brintos

brintos / linux-shallow public Read only

0
0
Text · 7.1 KiB · c90e286 Raw
299 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Marvell Berlin SATA PHY driver4 *5 * Copyright (C) 2014 Marvell Technology Group Ltd.6 *7 * Antoine Ténart <antoine.tenart@free-electrons.com>8 */9 10#include <linux/clk.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/phy/phy.h>14#include <linux/io.h>15#include <linux/platform_device.h>16 17#define HOST_VSA_ADDR		0x018#define HOST_VSA_DATA		0x419#define PORT_SCR_CTL		0x2c20#define PORT_VSR_ADDR		0x7821#define PORT_VSR_DATA		0x7c22 23#define CONTROL_REGISTER	0x024#define MBUS_SIZE_CONTROL	0x425 26#define POWER_DOWN_PHY0			BIT(6)27#define POWER_DOWN_PHY1			BIT(14)28#define MBUS_WRITE_REQUEST_SIZE_128	(BIT(2) << 16)29#define MBUS_READ_REQUEST_SIZE_128	(BIT(2) << 19)30 31#define BG2_PHY_BASE		0x08032#define BG2Q_PHY_BASE		0x20033 34/* register 0x01 */35#define REF_FREF_SEL_25		BIT(0)36#define PHY_BERLIN_MODE_SATA	(0x0 << 5)37 38/* register 0x02 */39#define USE_MAX_PLL_RATE	BIT(12)40 41/* register 0x23 */42#define DATA_BIT_WIDTH_10	(0x0 << 10)43#define DATA_BIT_WIDTH_20	(0x1 << 10)44#define DATA_BIT_WIDTH_40	(0x2 << 10)45 46/* register 0x25 */47#define PHY_GEN_MAX_1_5		(0x0 << 10)48#define PHY_GEN_MAX_3_0		(0x1 << 10)49#define PHY_GEN_MAX_6_0		(0x2 << 10)50 51struct phy_berlin_desc {52	struct phy	*phy;53	u32		power_bit;54	unsigned	index;55};56 57struct phy_berlin_priv {58	void __iomem		*base;59	spinlock_t		lock;60	struct clk		*clk;61	struct phy_berlin_desc	**phys;62	unsigned		nphys;63	u32			phy_base;64};65 66static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg,67			       u32 phy_base, u32 reg, u32 mask, u32 val)68{69	u32 regval;70 71	/* select register */72	writel(phy_base + reg, ctrl_reg + PORT_VSR_ADDR);73 74	/* set bits */75	regval = readl(ctrl_reg + PORT_VSR_DATA);76	regval &= ~mask;77	regval |= val;78	writel(regval, ctrl_reg + PORT_VSR_DATA);79}80 81static int phy_berlin_sata_power_on(struct phy *phy)82{83	struct phy_berlin_desc *desc = phy_get_drvdata(phy);84	struct phy_berlin_priv *priv = dev_get_drvdata(phy->dev.parent);85	void __iomem *ctrl_reg = priv->base + 0x60 + (desc->index * 0x80);86	u32 regval;87 88	clk_prepare_enable(priv->clk);89 90	spin_lock(&priv->lock);91 92	/* Power on PHY */93	writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);94	regval = readl(priv->base + HOST_VSA_DATA);95	regval &= ~desc->power_bit;96	writel(regval, priv->base + HOST_VSA_DATA);97 98	/* Configure MBus */99	writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR);100	regval = readl(priv->base + HOST_VSA_DATA);101	regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128;102	writel(regval, priv->base + HOST_VSA_DATA);103 104	/* set PHY mode and ref freq to 25 MHz */105	phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x01,106				    0x00ff,107				    REF_FREF_SEL_25 | PHY_BERLIN_MODE_SATA);108 109	/* set PHY up to 6 Gbps */110	phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x25,111				    0x0c00, PHY_GEN_MAX_6_0);112 113	/* set 40 bits width */114	phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x23,115				    0x0c00, DATA_BIT_WIDTH_40);116 117	/* use max pll rate */118	phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x02,119				    0x0000, USE_MAX_PLL_RATE);120 121	/* set Gen3 controller speed */122	regval = readl(ctrl_reg + PORT_SCR_CTL);123	regval &= ~GENMASK(7, 4);124	regval |= 0x30;125	writel(regval, ctrl_reg + PORT_SCR_CTL);126 127	spin_unlock(&priv->lock);128 129	clk_disable_unprepare(priv->clk);130 131	return 0;132}133 134static int phy_berlin_sata_power_off(struct phy *phy)135{136	struct phy_berlin_desc *desc = phy_get_drvdata(phy);137	struct phy_berlin_priv *priv = dev_get_drvdata(phy->dev.parent);138	u32 regval;139 140	clk_prepare_enable(priv->clk);141 142	spin_lock(&priv->lock);143 144	/* Power down PHY */145	writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);146	regval = readl(priv->base + HOST_VSA_DATA);147	regval |= desc->power_bit;148	writel(regval, priv->base + HOST_VSA_DATA);149 150	spin_unlock(&priv->lock);151 152	clk_disable_unprepare(priv->clk);153 154	return 0;155}156 157static struct phy *phy_berlin_sata_phy_xlate(struct device *dev,158					     const struct of_phandle_args *args)159{160	struct phy_berlin_priv *priv = dev_get_drvdata(dev);161	int i;162 163	if (WARN_ON(args->args[0] >= priv->nphys))164		return ERR_PTR(-ENODEV);165 166	for (i = 0; i < priv->nphys; i++) {167		if (priv->phys[i]->index == args->args[0])168			break;169	}170 171	if (i == priv->nphys)172		return ERR_PTR(-ENODEV);173 174	return priv->phys[i]->phy;175}176 177static const struct phy_ops phy_berlin_sata_ops = {178	.power_on	= phy_berlin_sata_power_on,179	.power_off	= phy_berlin_sata_power_off,180	.owner		= THIS_MODULE,181};182 183static u32 phy_berlin_power_down_bits[] = {184	POWER_DOWN_PHY0,185	POWER_DOWN_PHY1,186};187 188static int phy_berlin_sata_probe(struct platform_device *pdev)189{190	struct device *dev = &pdev->dev;191	struct device_node *child;192	struct phy *phy;193	struct phy_provider *phy_provider;194	struct phy_berlin_priv *priv;195	struct resource *res;196	int ret, i = 0;197	u32 phy_id;198 199	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);200	if (!priv)201		return -ENOMEM;202 203	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);204	if (!res)205		return -EINVAL;206 207	priv->base = devm_ioremap(dev, res->start, resource_size(res));208	if (!priv->base)209		return -ENOMEM;210 211	priv->clk = devm_clk_get(dev, NULL);212	if (IS_ERR(priv->clk))213		return PTR_ERR(priv->clk);214 215	priv->nphys = of_get_child_count(dev->of_node);216	if (priv->nphys == 0)217		return -ENODEV;218 219	priv->phys = devm_kcalloc(dev, priv->nphys, sizeof(*priv->phys),220				  GFP_KERNEL);221	if (!priv->phys)222		return -ENOMEM;223 224	if (of_device_is_compatible(dev->of_node, "marvell,berlin2-sata-phy"))225		priv->phy_base = BG2_PHY_BASE;226	else227		priv->phy_base = BG2Q_PHY_BASE;228 229	dev_set_drvdata(dev, priv);230	spin_lock_init(&priv->lock);231 232	for_each_available_child_of_node(dev->of_node, child) {233		struct phy_berlin_desc *phy_desc;234 235		if (of_property_read_u32(child, "reg", &phy_id)) {236			dev_err(dev, "missing reg property in node %pOFn\n",237				child);238			ret = -EINVAL;239			goto put_child;240		}241 242		if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) {243			dev_err(dev, "invalid reg in node %pOFn\n", child);244			ret = -EINVAL;245			goto put_child;246		}247 248		phy_desc = devm_kzalloc(dev, sizeof(*phy_desc), GFP_KERNEL);249		if (!phy_desc) {250			ret = -ENOMEM;251			goto put_child;252		}253 254		phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops);255		if (IS_ERR(phy)) {256			dev_err(dev, "failed to create PHY %d\n", phy_id);257			ret = PTR_ERR(phy);258			goto put_child;259		}260 261		phy_desc->phy = phy;262		phy_desc->power_bit = phy_berlin_power_down_bits[phy_id];263		phy_desc->index = phy_id;264		phy_set_drvdata(phy, phy_desc);265 266		priv->phys[i++] = phy_desc;267 268		/* Make sure the PHY is off */269		phy_berlin_sata_power_off(phy);270	}271 272	phy_provider =273		devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate);274	return PTR_ERR_OR_ZERO(phy_provider);275put_child:276	of_node_put(child);277	return ret;278}279 280static const struct of_device_id phy_berlin_sata_of_match[] = {281	{ .compatible = "marvell,berlin2-sata-phy" },282	{ .compatible = "marvell,berlin2q-sata-phy" },283	{ },284};285MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match);286 287static struct platform_driver phy_berlin_sata_driver = {288	.probe	= phy_berlin_sata_probe,289	.driver	= {290		.name		= "phy-berlin-sata",291		.of_match_table	= phy_berlin_sata_of_match,292	},293};294module_platform_driver(phy_berlin_sata_driver);295 296MODULE_DESCRIPTION("Marvell Berlin SATA PHY driver");297MODULE_AUTHOR("Antoine Ténart <antoine.tenart@free-electrons.com>");298MODULE_LICENSE("GPL v2");299