cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy-exynos5250-sata.c (6959B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Samsung SATA SerDes(PHY) driver
      4 *
      5 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
      6 * Authors: Girish K S <ks.giri@samsung.com>
      7 *         Yuvaraj Kumar C D <yuvaraj.cd@samsung.com>
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/delay.h>
     12#include <linux/io.h>
     13#include <linux/i2c.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/of.h>
     17#include <linux/of_address.h>
     18#include <linux/phy/phy.h>
     19#include <linux/platform_device.h>
     20#include <linux/regmap.h>
     21#include <linux/spinlock.h>
     22#include <linux/mfd/syscon.h>
     23
     24#define SATAPHY_CONTROL_OFFSET		0x0724
     25#define EXYNOS5_SATAPHY_PMU_ENABLE	BIT(0)
     26#define EXYNOS5_SATA_RESET		0x4
     27#define RESET_GLOBAL_RST_N		BIT(0)
     28#define RESET_CMN_RST_N			BIT(1)
     29#define RESET_CMN_BLOCK_RST_N		BIT(2)
     30#define RESET_CMN_I2C_RST_N		BIT(3)
     31#define RESET_TX_RX_PIPE_RST_N		BIT(4)
     32#define RESET_TX_RX_BLOCK_RST_N		BIT(5)
     33#define RESET_TX_RX_I2C_RST_N		(BIT(6) | BIT(7))
     34#define LINK_RESET			0xf0000
     35#define EXYNOS5_SATA_MODE0		0x10
     36#define SATA_SPD_GEN3			BIT(1)
     37#define EXYNOS5_SATA_CTRL0		0x14
     38#define CTRL0_P0_PHY_CALIBRATED_SEL	BIT(9)
     39#define CTRL0_P0_PHY_CALIBRATED		BIT(8)
     40#define EXYNOS5_SATA_PHSATA_CTRLM	0xe0
     41#define PHCTRLM_REF_RATE		BIT(1)
     42#define PHCTRLM_HIGH_SPEED		BIT(0)
     43#define EXYNOS5_SATA_PHSATA_STATM	0xf0
     44#define PHSTATM_PLL_LOCKED		BIT(0)
     45
     46#define PHY_PLL_TIMEOUT (usecs_to_jiffies(1000))
     47
     48struct exynos_sata_phy {
     49	struct phy *phy;
     50	struct clk *phyclk;
     51	void __iomem *regs;
     52	struct regmap *pmureg;
     53	struct i2c_client *client;
     54};
     55
     56static int wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit,
     57				u32 status)
     58{
     59	unsigned long timeout = jiffies + PHY_PLL_TIMEOUT;
     60
     61	while (time_before(jiffies, timeout)) {
     62		if ((readl(base + reg) & checkbit) == status)
     63			return 0;
     64	}
     65
     66	return -EFAULT;
     67}
     68
     69static int exynos_sata_phy_power_on(struct phy *phy)
     70{
     71	struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
     72
     73	return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
     74			EXYNOS5_SATAPHY_PMU_ENABLE, true);
     75
     76}
     77
     78static int exynos_sata_phy_power_off(struct phy *phy)
     79{
     80	struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
     81
     82	return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
     83			EXYNOS5_SATAPHY_PMU_ENABLE, false);
     84
     85}
     86
     87static int exynos_sata_phy_init(struct phy *phy)
     88{
     89	u32 val = 0;
     90	int ret = 0;
     91	u8 buf[] = { 0x3a, 0x0b };
     92	struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
     93
     94	ret = regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
     95			EXYNOS5_SATAPHY_PMU_ENABLE, true);
     96	if (ret != 0)
     97		dev_err(&sata_phy->phy->dev, "phy init failed\n");
     98
     99	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
    100
    101	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
    102	val |= RESET_GLOBAL_RST_N | RESET_CMN_RST_N | RESET_CMN_BLOCK_RST_N
    103		| RESET_CMN_I2C_RST_N | RESET_TX_RX_PIPE_RST_N
    104		| RESET_TX_RX_BLOCK_RST_N | RESET_TX_RX_I2C_RST_N;
    105	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
    106
    107	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
    108	val |= LINK_RESET;
    109	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
    110
    111	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
    112	val |= RESET_CMN_RST_N;
    113	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
    114
    115	val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
    116	val &= ~PHCTRLM_REF_RATE;
    117	writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
    118
    119	/* High speed enable for Gen3 */
    120	val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
    121	val |= PHCTRLM_HIGH_SPEED;
    122	writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
    123
    124	val = readl(sata_phy->regs + EXYNOS5_SATA_CTRL0);
    125	val |= CTRL0_P0_PHY_CALIBRATED_SEL | CTRL0_P0_PHY_CALIBRATED;
    126	writel(val, sata_phy->regs + EXYNOS5_SATA_CTRL0);
    127
    128	val = readl(sata_phy->regs + EXYNOS5_SATA_MODE0);
    129	val |= SATA_SPD_GEN3;
    130	writel(val, sata_phy->regs + EXYNOS5_SATA_MODE0);
    131
    132	ret = i2c_master_send(sata_phy->client, buf, sizeof(buf));
    133	if (ret < 0)
    134		return ret;
    135
    136	/* release cmu reset */
    137	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
    138	val &= ~RESET_CMN_RST_N;
    139	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
    140
    141	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
    142	val |= RESET_CMN_RST_N;
    143	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
    144
    145	ret = wait_for_reg_status(sata_phy->regs,
    146				EXYNOS5_SATA_PHSATA_STATM,
    147				PHSTATM_PLL_LOCKED, 1);
    148	if (ret < 0)
    149		dev_err(&sata_phy->phy->dev,
    150			"PHY PLL locking failed\n");
    151	return ret;
    152}
    153
    154static const struct phy_ops exynos_sata_phy_ops = {
    155	.init		= exynos_sata_phy_init,
    156	.power_on	= exynos_sata_phy_power_on,
    157	.power_off	= exynos_sata_phy_power_off,
    158	.owner		= THIS_MODULE,
    159};
    160
    161static int exynos_sata_phy_probe(struct platform_device *pdev)
    162{
    163	struct exynos_sata_phy *sata_phy;
    164	struct device *dev = &pdev->dev;
    165	struct phy_provider *phy_provider;
    166	struct device_node *node;
    167	int ret = 0;
    168
    169	sata_phy = devm_kzalloc(dev, sizeof(*sata_phy), GFP_KERNEL);
    170	if (!sata_phy)
    171		return -ENOMEM;
    172
    173	sata_phy->regs = devm_platform_ioremap_resource(pdev, 0);
    174	if (IS_ERR(sata_phy->regs))
    175		return PTR_ERR(sata_phy->regs);
    176
    177	sata_phy->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
    178					"samsung,syscon-phandle");
    179	if (IS_ERR(sata_phy->pmureg)) {
    180		dev_err(dev, "syscon regmap lookup failed.\n");
    181		return PTR_ERR(sata_phy->pmureg);
    182	}
    183
    184	node = of_parse_phandle(dev->of_node,
    185			"samsung,exynos-sataphy-i2c-phandle", 0);
    186	if (!node)
    187		return -EINVAL;
    188
    189	sata_phy->client = of_find_i2c_device_by_node(node);
    190	of_node_put(node);
    191	if (!sata_phy->client)
    192		return -EPROBE_DEFER;
    193
    194	dev_set_drvdata(dev, sata_phy);
    195
    196	sata_phy->phyclk = devm_clk_get(dev, "sata_phyctrl");
    197	if (IS_ERR(sata_phy->phyclk)) {
    198		dev_err(dev, "failed to get clk for PHY\n");
    199		ret = PTR_ERR(sata_phy->phyclk);
    200		goto put_dev;
    201	}
    202
    203	ret = clk_prepare_enable(sata_phy->phyclk);
    204	if (ret < 0) {
    205		dev_err(dev, "failed to enable source clk\n");
    206		goto put_dev;
    207	}
    208
    209	sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops);
    210	if (IS_ERR(sata_phy->phy)) {
    211		dev_err(dev, "failed to create PHY\n");
    212		ret = PTR_ERR(sata_phy->phy);
    213		goto clk_disable;
    214	}
    215
    216	phy_set_drvdata(sata_phy->phy, sata_phy);
    217
    218	phy_provider = devm_of_phy_provider_register(dev,
    219					of_phy_simple_xlate);
    220	if (IS_ERR(phy_provider)) {
    221		ret = PTR_ERR(phy_provider);
    222		goto clk_disable;
    223	}
    224
    225	return 0;
    226
    227clk_disable:
    228	clk_disable_unprepare(sata_phy->phyclk);
    229put_dev:
    230	put_device(&sata_phy->client->dev);
    231
    232	return ret;
    233}
    234
    235static const struct of_device_id exynos_sata_phy_of_match[] = {
    236	{ .compatible = "samsung,exynos5250-sata-phy" },
    237	{ },
    238};
    239MODULE_DEVICE_TABLE(of, exynos_sata_phy_of_match);
    240
    241static struct platform_driver exynos_sata_phy_driver = {
    242	.probe	= exynos_sata_phy_probe,
    243	.driver = {
    244		.of_match_table	= exynos_sata_phy_of_match,
    245		.name  = "samsung,sata-phy",
    246		.suppress_bind_attrs = true,
    247	}
    248};
    249module_platform_driver(exynos_sata_phy_driver);
    250
    251MODULE_DESCRIPTION("Samsung SerDes PHY driver");
    252MODULE_LICENSE("GPL v2");
    253MODULE_AUTHOR("Girish K S <ks.giri@samsung.com>");
    254MODULE_AUTHOR("Yuvaraj C D <yuvaraj.cd@samsung.com>");