Linux Audio

Check our new training course

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