1 /* 2 * B53 register access through memory mapped registers 3 * 4 * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <linux/bits.h> 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <linux/of.h> 23 #include <linux/io.h> 24 #include <linux/mfd/syscon.h> 25 #include <linux/platform_device.h> 26 #include <linux/platform_data/b53.h> 27 #include <linux/regmap.h> 28 29 #include "b53_priv.h" 30 31 #define BCM63XX_EPHY_REG 0x3C 32 #define BCM63268_GPHY_REG 0x54 33 34 #define GPHY_CTRL_LOW_PWR BIT(3) 35 #define GPHY_CTRL_IDDQ_BIAS BIT(0) 36 37 struct b53_phy_info { 38 u32 gphy_port_mask; 39 u32 ephy_enable_mask; 40 u32 ephy_port_mask; 41 u32 ephy_bias_bit; 42 const u32 *ephy_offset; 43 }; 44 45 struct b53_mmap_priv { 46 void __iomem *regs; 47 struct regmap *gpio_ctrl; 48 const struct b53_phy_info *phy_info; 49 u32 phys_enabled; 50 }; 51 52 static const u32 bcm6318_ephy_offsets[] = {4, 5, 6, 7}; 53 54 static const struct b53_phy_info bcm6318_ephy_info = { 55 .ephy_enable_mask = BIT(0) | BIT(4) | BIT(8) | BIT(12) | BIT(16), 56 .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm6318_ephy_offsets) - 1), 0), 57 .ephy_bias_bit = 24, 58 .ephy_offset = bcm6318_ephy_offsets, 59 }; 60 61 static const u32 bcm6368_ephy_offsets[] = {2, 3, 4, 5}; 62 63 static const struct b53_phy_info bcm6368_ephy_info = { 64 .ephy_enable_mask = BIT(0), 65 .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm6368_ephy_offsets) - 1), 0), 66 .ephy_bias_bit = 0, 67 .ephy_offset = bcm6368_ephy_offsets, 68 }; 69 70 static const u32 bcm63268_ephy_offsets[] = {4, 9, 14}; 71 72 static const struct b53_phy_info bcm63268_ephy_info = { 73 .gphy_port_mask = BIT(3), 74 .ephy_enable_mask = GENMASK(4, 0), 75 .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm63268_ephy_offsets) - 1), 0), 76 .ephy_bias_bit = 24, 77 .ephy_offset = bcm63268_ephy_offsets, 78 }; 79 80 static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) 81 { 82 struct b53_mmap_priv *priv = dev->priv; 83 void __iomem *regs = priv->regs; 84 85 *val = readb(regs + (page << 8) + reg); 86 87 return 0; 88 } 89 90 static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) 91 { 92 struct b53_mmap_priv *priv = dev->priv; 93 void __iomem *regs = priv->regs; 94 95 if (WARN_ON(reg % 2)) 96 return -EINVAL; 97 98 if (dev->pdata && dev->pdata->big_endian) 99 *val = ioread16be(regs + (page << 8) + reg); 100 else 101 *val = readw(regs + (page << 8) + reg); 102 103 return 0; 104 } 105 106 static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) 107 { 108 struct b53_mmap_priv *priv = dev->priv; 109 void __iomem *regs = priv->regs; 110 111 if (WARN_ON(reg % 4)) 112 return -EINVAL; 113 114 if (dev->pdata && dev->pdata->big_endian) 115 *val = ioread32be(regs + (page << 8) + reg); 116 else 117 *val = readl(regs + (page << 8) + reg); 118 119 return 0; 120 } 121 122 static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) 123 { 124 struct b53_mmap_priv *priv = dev->priv; 125 void __iomem *regs = priv->regs; 126 127 if (WARN_ON(reg % 2)) 128 return -EINVAL; 129 130 if (reg % 4) { 131 u16 lo; 132 u32 hi; 133 134 if (dev->pdata && dev->pdata->big_endian) { 135 lo = ioread16be(regs + (page << 8) + reg); 136 hi = ioread32be(regs + (page << 8) + reg + 2); 137 } else { 138 lo = readw(regs + (page << 8) + reg); 139 hi = readl(regs + (page << 8) + reg + 2); 140 } 141 142 *val = ((u64)hi << 16) | lo; 143 } else { 144 u32 lo; 145 u16 hi; 146 147 if (dev->pdata && dev->pdata->big_endian) { 148 lo = ioread32be(regs + (page << 8) + reg); 149 hi = ioread16be(regs + (page << 8) + reg + 4); 150 } else { 151 lo = readl(regs + (page << 8) + reg); 152 hi = readw(regs + (page << 8) + reg + 4); 153 } 154 155 *val = ((u64)hi << 32) | lo; 156 } 157 158 return 0; 159 } 160 161 static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) 162 { 163 struct b53_mmap_priv *priv = dev->priv; 164 void __iomem *regs = priv->regs; 165 u32 hi, lo; 166 167 if (WARN_ON(reg % 4)) 168 return -EINVAL; 169 170 if (dev->pdata && dev->pdata->big_endian) { 171 lo = ioread32be(regs + (page << 8) + reg); 172 hi = ioread32be(regs + (page << 8) + reg + 4); 173 } else { 174 lo = readl(regs + (page << 8) + reg); 175 hi = readl(regs + (page << 8) + reg + 4); 176 } 177 178 *val = ((u64)hi << 32) | lo; 179 180 return 0; 181 } 182 183 static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) 184 { 185 struct b53_mmap_priv *priv = dev->priv; 186 void __iomem *regs = priv->regs; 187 188 writeb(value, regs + (page << 8) + reg); 189 190 return 0; 191 } 192 193 static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg, 194 u16 value) 195 { 196 struct b53_mmap_priv *priv = dev->priv; 197 void __iomem *regs = priv->regs; 198 199 if (WARN_ON(reg % 2)) 200 return -EINVAL; 201 202 if (dev->pdata && dev->pdata->big_endian) 203 iowrite16be(value, regs + (page << 8) + reg); 204 else 205 writew(value, regs + (page << 8) + reg); 206 207 return 0; 208 } 209 210 static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg, 211 u32 value) 212 { 213 struct b53_mmap_priv *priv = dev->priv; 214 void __iomem *regs = priv->regs; 215 216 if (WARN_ON(reg % 4)) 217 return -EINVAL; 218 219 if (dev->pdata && dev->pdata->big_endian) 220 iowrite32be(value, regs + (page << 8) + reg); 221 else 222 writel(value, regs + (page << 8) + reg); 223 224 return 0; 225 } 226 227 static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg, 228 u64 value) 229 { 230 if (WARN_ON(reg % 2)) 231 return -EINVAL; 232 233 if (reg % 4) { 234 u32 hi = (u32)(value >> 16); 235 u16 lo = (u16)value; 236 237 b53_mmap_write16(dev, page, reg, lo); 238 b53_mmap_write32(dev, page, reg + 2, hi); 239 } else { 240 u16 hi = (u16)(value >> 32); 241 u32 lo = (u32)value; 242 243 b53_mmap_write32(dev, page, reg, lo); 244 b53_mmap_write16(dev, page, reg + 4, hi); 245 } 246 247 return 0; 248 } 249 250 static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg, 251 u64 value) 252 { 253 u32 hi, lo; 254 255 hi = upper_32_bits(value); 256 lo = lower_32_bits(value); 257 258 if (WARN_ON(reg % 4)) 259 return -EINVAL; 260 261 b53_mmap_write32(dev, page, reg, lo); 262 b53_mmap_write32(dev, page, reg + 4, hi); 263 264 return 0; 265 } 266 267 static int b53_mmap_phy_read16(struct b53_device *dev, int addr, int reg, 268 u16 *value) 269 { 270 return -EIO; 271 } 272 273 static int b53_mmap_phy_write16(struct b53_device *dev, int addr, int reg, 274 u16 value) 275 { 276 return -EIO; 277 } 278 279 static int bcm63xx_ephy_set(struct b53_device *dev, int port, bool enable) 280 { 281 struct b53_mmap_priv *priv = dev->priv; 282 const struct b53_phy_info *info = priv->phy_info; 283 struct regmap *gpio_ctrl = priv->gpio_ctrl; 284 u32 mask, val; 285 286 if (enable) { 287 mask = (info->ephy_enable_mask << info->ephy_offset[port]) 288 | BIT(info->ephy_bias_bit); 289 val = 0; 290 } else { 291 mask = (info->ephy_enable_mask << info->ephy_offset[port]); 292 if (!((priv->phys_enabled & ~BIT(port)) & info->ephy_port_mask)) 293 mask |= BIT(info->ephy_bias_bit); 294 val = mask; 295 } 296 return regmap_update_bits(gpio_ctrl, BCM63XX_EPHY_REG, mask, val); 297 } 298 299 static int bcm63268_gphy_set(struct b53_device *dev, bool enable) 300 { 301 struct b53_mmap_priv *priv = dev->priv; 302 struct regmap *gpio_ctrl = priv->gpio_ctrl; 303 u32 mask = GPHY_CTRL_IDDQ_BIAS | GPHY_CTRL_LOW_PWR; 304 u32 val = 0; 305 306 if (!enable) 307 val = mask; 308 309 return regmap_update_bits(gpio_ctrl, BCM63268_GPHY_REG, mask, val); 310 } 311 312 static void b53_mmap_phy_enable(struct b53_device *dev, int port) 313 { 314 struct b53_mmap_priv *priv = dev->priv; 315 int ret = 0; 316 317 if (priv->phy_info) { 318 if (BIT(port) & priv->phy_info->ephy_port_mask) 319 ret = bcm63xx_ephy_set(dev, port, true); 320 else if (BIT(port) & priv->phy_info->gphy_port_mask) 321 ret = bcm63268_gphy_set(dev, true); 322 } 323 324 if (!ret) 325 priv->phys_enabled |= BIT(port); 326 } 327 328 static void b53_mmap_phy_disable(struct b53_device *dev, int port) 329 { 330 struct b53_mmap_priv *priv = dev->priv; 331 int ret = 0; 332 333 if (priv->phy_info) { 334 if (BIT(port) & priv->phy_info->ephy_port_mask) 335 ret = bcm63xx_ephy_set(dev, port, false); 336 else if (BIT(port) & priv->phy_info->gphy_port_mask) 337 ret = bcm63268_gphy_set(dev, false); 338 } 339 340 if (!ret) 341 priv->phys_enabled &= ~BIT(port); 342 } 343 344 static const struct b53_io_ops b53_mmap_ops = { 345 .read8 = b53_mmap_read8, 346 .read16 = b53_mmap_read16, 347 .read32 = b53_mmap_read32, 348 .read48 = b53_mmap_read48, 349 .read64 = b53_mmap_read64, 350 .write8 = b53_mmap_write8, 351 .write16 = b53_mmap_write16, 352 .write32 = b53_mmap_write32, 353 .write48 = b53_mmap_write48, 354 .write64 = b53_mmap_write64, 355 .phy_read16 = b53_mmap_phy_read16, 356 .phy_write16 = b53_mmap_phy_write16, 357 .phy_enable = b53_mmap_phy_enable, 358 .phy_disable = b53_mmap_phy_disable, 359 }; 360 361 static int b53_mmap_probe_of(struct platform_device *pdev, 362 struct b53_platform_data **ppdata) 363 { 364 struct device_node *np = pdev->dev.of_node; 365 struct device_node *of_ports, *of_port; 366 struct device *dev = &pdev->dev; 367 struct b53_platform_data *pdata; 368 void __iomem *mem; 369 370 mem = devm_platform_ioremap_resource(pdev, 0); 371 if (IS_ERR(mem)) 372 return PTR_ERR(mem); 373 374 pdata = devm_kzalloc(dev, sizeof(struct b53_platform_data), 375 GFP_KERNEL); 376 if (!pdata) 377 return -ENOMEM; 378 379 pdata->regs = mem; 380 pdata->chip_id = (u32)(unsigned long)device_get_match_data(dev); 381 pdata->big_endian = of_property_read_bool(np, "big-endian"); 382 383 of_ports = of_get_child_by_name(np, "ports"); 384 if (!of_ports) { 385 dev_err(dev, "no ports child node found\n"); 386 return -EINVAL; 387 } 388 389 for_each_available_child_of_node(of_ports, of_port) { 390 u32 reg; 391 392 if (of_property_read_u32(of_port, "reg", ®)) 393 continue; 394 395 if (reg < B53_N_PORTS) 396 pdata->enabled_ports |= BIT(reg); 397 } 398 399 of_node_put(of_ports); 400 *ppdata = pdata; 401 402 return 0; 403 } 404 405 static int b53_mmap_probe(struct platform_device *pdev) 406 { 407 struct device_node *np = pdev->dev.of_node; 408 struct b53_platform_data *pdata = pdev->dev.platform_data; 409 struct b53_mmap_priv *priv; 410 struct b53_device *dev; 411 int ret; 412 413 if (!pdata && np) { 414 ret = b53_mmap_probe_of(pdev, &pdata); 415 if (ret) { 416 dev_err(&pdev->dev, "OF probe error\n"); 417 return ret; 418 } 419 } 420 421 if (!pdata) 422 return -EINVAL; 423 424 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 425 if (!priv) 426 return -ENOMEM; 427 428 priv->regs = pdata->regs; 429 430 priv->gpio_ctrl = syscon_regmap_lookup_by_phandle(np, "brcm,gpio-ctrl"); 431 if (!IS_ERR(priv->gpio_ctrl)) { 432 if (pdata->chip_id == BCM6318_DEVICE_ID || 433 pdata->chip_id == BCM6328_DEVICE_ID || 434 pdata->chip_id == BCM6362_DEVICE_ID) 435 priv->phy_info = &bcm6318_ephy_info; 436 else if (pdata->chip_id == BCM6368_DEVICE_ID) 437 priv->phy_info = &bcm6368_ephy_info; 438 else if (pdata->chip_id == BCM63268_DEVICE_ID) 439 priv->phy_info = &bcm63268_ephy_info; 440 } 441 442 dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, priv); 443 if (!dev) 444 return -ENOMEM; 445 446 dev->pdata = pdata; 447 448 platform_set_drvdata(pdev, dev); 449 450 return b53_switch_register(dev); 451 } 452 453 static void b53_mmap_remove(struct platform_device *pdev) 454 { 455 struct b53_device *dev = platform_get_drvdata(pdev); 456 457 if (dev) 458 b53_switch_remove(dev); 459 } 460 461 static void b53_mmap_shutdown(struct platform_device *pdev) 462 { 463 struct b53_device *dev = platform_get_drvdata(pdev); 464 465 if (dev) 466 b53_switch_shutdown(dev); 467 468 platform_set_drvdata(pdev, NULL); 469 } 470 471 static const struct of_device_id b53_mmap_of_table[] = { 472 { 473 .compatible = "brcm,bcm3384-switch", 474 .data = (void *)BCM63XX_DEVICE_ID, 475 }, { 476 .compatible = "brcm,bcm6318-switch", 477 .data = (void *)BCM6318_DEVICE_ID, 478 }, { 479 .compatible = "brcm,bcm6328-switch", 480 .data = (void *)BCM6328_DEVICE_ID, 481 }, { 482 .compatible = "brcm,bcm6362-switch", 483 .data = (void *)BCM6362_DEVICE_ID, 484 }, { 485 .compatible = "brcm,bcm6368-switch", 486 .data = (void *)BCM6368_DEVICE_ID, 487 }, { 488 .compatible = "brcm,bcm63268-switch", 489 .data = (void *)BCM63268_DEVICE_ID, 490 }, { 491 .compatible = "brcm,bcm63xx-switch", 492 .data = (void *)BCM63XX_DEVICE_ID, 493 }, { /* sentinel */ } 494 }; 495 MODULE_DEVICE_TABLE(of, b53_mmap_of_table); 496 497 static struct platform_driver b53_mmap_driver = { 498 .probe = b53_mmap_probe, 499 .remove = b53_mmap_remove, 500 .shutdown = b53_mmap_shutdown, 501 .driver = { 502 .name = "b53-switch", 503 .of_match_table = b53_mmap_of_table, 504 }, 505 }; 506 507 module_platform_driver(b53_mmap_driver); 508 MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>"); 509 MODULE_DESCRIPTION("B53 MMAP access driver"); 510 MODULE_LICENSE("Dual BSD/GPL"); 511