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