Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.18-rc3 283 lines 6.9 kB view raw
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 PHY_BASE 0x200 34 35/* register 0x01 */ 36#define REF_FREF_SEL_25 BIT(0) 37#define PHY_MODE_SATA (0x0 << 5) 38 39/* register 0x02 */ 40#define USE_MAX_PLL_RATE BIT(12) 41 42/* register 0x23 */ 43#define DATA_BIT_WIDTH_10 (0x0 << 10) 44#define DATA_BIT_WIDTH_20 (0x1 << 10) 45#define DATA_BIT_WIDTH_40 (0x2 << 10) 46 47/* register 0x25 */ 48#define PHY_GEN_MAX_1_5 (0x0 << 10) 49#define PHY_GEN_MAX_3_0 (0x1 << 10) 50#define PHY_GEN_MAX_6_0 (0x2 << 10) 51 52struct phy_berlin_desc { 53 struct phy *phy; 54 u32 power_bit; 55 unsigned index; 56}; 57 58struct phy_berlin_priv { 59 void __iomem *base; 60 spinlock_t lock; 61 struct clk *clk; 62 struct phy_berlin_desc **phys; 63 unsigned nphys; 64}; 65 66static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg, u32 reg, 67 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 int ret = 0; 87 u32 regval; 88 89 clk_prepare_enable(priv->clk); 90 91 spin_lock(&priv->lock); 92 93 /* Power on PHY */ 94 writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR); 95 regval = readl(priv->base + HOST_VSA_DATA); 96 regval &= ~desc->power_bit; 97 writel(regval, priv->base + HOST_VSA_DATA); 98 99 /* Configure MBus */ 100 writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR); 101 regval = readl(priv->base + HOST_VSA_DATA); 102 regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128; 103 writel(regval, priv->base + HOST_VSA_DATA); 104 105 /* set PHY mode and ref freq to 25 MHz */ 106 phy_berlin_sata_reg_setbits(ctrl_reg, 0x1, 0xff, 107 REF_FREF_SEL_25 | PHY_MODE_SATA); 108 109 /* set PHY up to 6 Gbps */ 110 phy_berlin_sata_reg_setbits(ctrl_reg, 0x25, 0xc00, PHY_GEN_MAX_6_0); 111 112 /* set 40 bits width */ 113 phy_berlin_sata_reg_setbits(ctrl_reg, 0x23, 0xc00, DATA_BIT_WIDTH_40); 114 115 /* use max pll rate */ 116 phy_berlin_sata_reg_setbits(ctrl_reg, 0x2, 0x0, USE_MAX_PLL_RATE); 117 118 /* set Gen3 controller speed */ 119 regval = readl(ctrl_reg + PORT_SCR_CTL); 120 regval &= ~GENMASK(7, 4); 121 regval |= 0x30; 122 writel(regval, ctrl_reg + PORT_SCR_CTL); 123 124 spin_unlock(&priv->lock); 125 126 clk_disable_unprepare(priv->clk); 127 128 return ret; 129} 130 131static int phy_berlin_sata_power_off(struct phy *phy) 132{ 133 struct phy_berlin_desc *desc = phy_get_drvdata(phy); 134 struct phy_berlin_priv *priv = dev_get_drvdata(phy->dev.parent); 135 u32 regval; 136 137 clk_prepare_enable(priv->clk); 138 139 spin_lock(&priv->lock); 140 141 /* Power down PHY */ 142 writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR); 143 regval = readl(priv->base + HOST_VSA_DATA); 144 regval |= desc->power_bit; 145 writel(regval, priv->base + HOST_VSA_DATA); 146 147 spin_unlock(&priv->lock); 148 149 clk_disable_unprepare(priv->clk); 150 151 return 0; 152} 153 154static struct phy *phy_berlin_sata_phy_xlate(struct device *dev, 155 struct of_phandle_args *args) 156{ 157 struct phy_berlin_priv *priv = dev_get_drvdata(dev); 158 int i; 159 160 if (WARN_ON(args->args[0] >= priv->nphys)) 161 return ERR_PTR(-ENODEV); 162 163 for (i = 0; i < priv->nphys; i++) { 164 if (priv->phys[i]->index == args->args[0]) 165 break; 166 } 167 168 if (i == priv->nphys) 169 return ERR_PTR(-ENODEV); 170 171 return priv->phys[i]->phy; 172} 173 174static struct phy_ops phy_berlin_sata_ops = { 175 .power_on = phy_berlin_sata_power_on, 176 .power_off = phy_berlin_sata_power_off, 177 .owner = THIS_MODULE, 178}; 179 180static u32 phy_berlin_power_down_bits[] = { 181 POWER_DOWN_PHY0, 182 POWER_DOWN_PHY1, 183}; 184 185static int phy_berlin_sata_probe(struct platform_device *pdev) 186{ 187 struct device *dev = &pdev->dev; 188 struct device_node *child; 189 struct phy *phy; 190 struct phy_provider *phy_provider; 191 struct phy_berlin_priv *priv; 192 struct resource *res; 193 int i = 0; 194 u32 phy_id; 195 196 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 197 if (!priv) 198 return -ENOMEM; 199 200 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 201 if (!res) 202 return -EINVAL; 203 204 priv->base = devm_ioremap(dev, res->start, resource_size(res)); 205 if (!priv->base) 206 return -ENOMEM; 207 208 priv->clk = devm_clk_get(dev, NULL); 209 if (IS_ERR(priv->clk)) 210 return PTR_ERR(priv->clk); 211 212 priv->nphys = of_get_child_count(dev->of_node); 213 if (priv->nphys == 0) 214 return -ENODEV; 215 216 priv->phys = devm_kzalloc(dev, priv->nphys * sizeof(*priv->phys), 217 GFP_KERNEL); 218 if (!priv->phys) 219 return -ENOMEM; 220 221 dev_set_drvdata(dev, priv); 222 spin_lock_init(&priv->lock); 223 224 for_each_available_child_of_node(dev->of_node, child) { 225 struct phy_berlin_desc *phy_desc; 226 227 if (of_property_read_u32(child, "reg", &phy_id)) { 228 dev_err(dev, "missing reg property in node %s\n", 229 child->name); 230 return -EINVAL; 231 } 232 233 if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) { 234 dev_err(dev, "invalid reg in node %s\n", child->name); 235 return -EINVAL; 236 } 237 238 phy_desc = devm_kzalloc(dev, sizeof(*phy_desc), GFP_KERNEL); 239 if (!phy_desc) 240 return -ENOMEM; 241 242 phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops, NULL); 243 if (IS_ERR(phy)) { 244 dev_err(dev, "failed to create PHY %d\n", phy_id); 245 return PTR_ERR(phy); 246 } 247 248 phy_desc->phy = phy; 249 phy_desc->power_bit = phy_berlin_power_down_bits[phy_id]; 250 phy_desc->index = phy_id; 251 phy_set_drvdata(phy, phy_desc); 252 253 priv->phys[i++] = phy_desc; 254 255 /* Make sure the PHY is off */ 256 phy_berlin_sata_power_off(phy); 257 } 258 259 phy_provider = 260 devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate); 261 if (IS_ERR(phy_provider)) 262 return PTR_ERR(phy_provider); 263 264 return 0; 265} 266 267static const struct of_device_id phy_berlin_sata_of_match[] = { 268 { .compatible = "marvell,berlin2q-sata-phy" }, 269 { }, 270}; 271 272static struct platform_driver phy_berlin_sata_driver = { 273 .probe = phy_berlin_sata_probe, 274 .driver = { 275 .name = "phy-berlin-sata", 276 .of_match_table = phy_berlin_sata_of_match, 277 }, 278}; 279module_platform_driver(phy_berlin_sata_driver); 280 281MODULE_DESCRIPTION("Marvell Berlin SATA PHY driver"); 282MODULE_AUTHOR("Antoine Ténart <antoine.tenart@free-electrons.com>"); 283MODULE_LICENSE("GPL v2");