1 /* 2 * B53 register access through Switch Register Access Bridge Registers 3 * 4 * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de> 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/kernel.h> 20 #include <linux/module.h> 21 #include <linux/delay.h> 22 #include <linux/platform_device.h> 23 #include <linux/platform_data/b53.h> 24 #include <linux/of.h> 25 26 #include "b53_priv.h" 27 28 /* command and status register of the SRAB */ 29 #define B53_SRAB_CMDSTAT 0x2c 30 #define B53_SRAB_CMDSTAT_RST BIT(2) 31 #define B53_SRAB_CMDSTAT_WRITE BIT(1) 32 #define B53_SRAB_CMDSTAT_GORDYN BIT(0) 33 #define B53_SRAB_CMDSTAT_PAGE 24 34 #define B53_SRAB_CMDSTAT_REG 16 35 36 /* high order word of write data to switch registe */ 37 #define B53_SRAB_WD_H 0x30 38 39 /* low order word of write data to switch registe */ 40 #define B53_SRAB_WD_L 0x34 41 42 /* high order word of read data from switch register */ 43 #define B53_SRAB_RD_H 0x38 44 45 /* low order word of read data from switch register */ 46 #define B53_SRAB_RD_L 0x3c 47 48 /* command and status register of the SRAB */ 49 #define B53_SRAB_CTRLS 0x40 50 #define B53_SRAB_CTRLS_RCAREQ BIT(3) 51 #define B53_SRAB_CTRLS_RCAGNT BIT(4) 52 #define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6) 53 54 /* the register captures interrupt pulses from the switch */ 55 #define B53_SRAB_INTR 0x44 56 #define B53_SRAB_INTR_P(x) BIT(x) 57 #define B53_SRAB_SWITCH_PHY BIT(8) 58 #define B53_SRAB_1588_SYNC BIT(9) 59 #define B53_SRAB_IMP1_SLEEP_TIMER BIT(10) 60 #define B53_SRAB_P7_SLEEP_TIMER BIT(11) 61 #define B53_SRAB_IMP0_SLEEP_TIMER BIT(12) 62 63 struct b53_srab_priv { 64 void __iomem *regs; 65 }; 66 67 static int b53_srab_request_grant(struct b53_device *dev) 68 { 69 struct b53_srab_priv *priv = dev->priv; 70 u8 __iomem *regs = priv->regs; 71 u32 ctrls; 72 int i; 73 74 ctrls = readl(regs + B53_SRAB_CTRLS); 75 ctrls |= B53_SRAB_CTRLS_RCAREQ; 76 writel(ctrls, regs + B53_SRAB_CTRLS); 77 78 for (i = 0; i < 20; i++) { 79 ctrls = readl(regs + B53_SRAB_CTRLS); 80 if (ctrls & B53_SRAB_CTRLS_RCAGNT) 81 break; 82 usleep_range(10, 100); 83 } 84 if (WARN_ON(i == 5)) 85 return -EIO; 86 87 return 0; 88 } 89 90 static void b53_srab_release_grant(struct b53_device *dev) 91 { 92 struct b53_srab_priv *priv = dev->priv; 93 u8 __iomem *regs = priv->regs; 94 u32 ctrls; 95 96 ctrls = readl(regs + B53_SRAB_CTRLS); 97 ctrls &= ~B53_SRAB_CTRLS_RCAREQ; 98 writel(ctrls, regs + B53_SRAB_CTRLS); 99 } 100 101 static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op) 102 { 103 struct b53_srab_priv *priv = dev->priv; 104 u8 __iomem *regs = priv->regs; 105 int i; 106 u32 cmdstat; 107 108 /* set register address */ 109 cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) | 110 (reg << B53_SRAB_CMDSTAT_REG) | 111 B53_SRAB_CMDSTAT_GORDYN | 112 op; 113 writel(cmdstat, regs + B53_SRAB_CMDSTAT); 114 115 /* check if operation completed */ 116 for (i = 0; i < 5; ++i) { 117 cmdstat = readl(regs + B53_SRAB_CMDSTAT); 118 if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN)) 119 break; 120 usleep_range(10, 100); 121 } 122 123 if (WARN_ON(i == 5)) 124 return -EIO; 125 126 return 0; 127 } 128 129 static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) 130 { 131 struct b53_srab_priv *priv = dev->priv; 132 u8 __iomem *regs = priv->regs; 133 int ret = 0; 134 135 ret = b53_srab_request_grant(dev); 136 if (ret) 137 goto err; 138 139 ret = b53_srab_op(dev, page, reg, 0); 140 if (ret) 141 goto err; 142 143 *val = readl(regs + B53_SRAB_RD_L) & 0xff; 144 145 err: 146 b53_srab_release_grant(dev); 147 148 return ret; 149 } 150 151 static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) 152 { 153 struct b53_srab_priv *priv = dev->priv; 154 u8 __iomem *regs = priv->regs; 155 int ret = 0; 156 157 ret = b53_srab_request_grant(dev); 158 if (ret) 159 goto err; 160 161 ret = b53_srab_op(dev, page, reg, 0); 162 if (ret) 163 goto err; 164 165 *val = readl(regs + B53_SRAB_RD_L) & 0xffff; 166 167 err: 168 b53_srab_release_grant(dev); 169 170 return ret; 171 } 172 173 static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) 174 { 175 struct b53_srab_priv *priv = dev->priv; 176 u8 __iomem *regs = priv->regs; 177 int ret = 0; 178 179 ret = b53_srab_request_grant(dev); 180 if (ret) 181 goto err; 182 183 ret = b53_srab_op(dev, page, reg, 0); 184 if (ret) 185 goto err; 186 187 *val = readl(regs + B53_SRAB_RD_L); 188 189 err: 190 b53_srab_release_grant(dev); 191 192 return ret; 193 } 194 195 static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) 196 { 197 struct b53_srab_priv *priv = dev->priv; 198 u8 __iomem *regs = priv->regs; 199 int ret = 0; 200 201 ret = b53_srab_request_grant(dev); 202 if (ret) 203 goto err; 204 205 ret = b53_srab_op(dev, page, reg, 0); 206 if (ret) 207 goto err; 208 209 *val = readl(regs + B53_SRAB_RD_L); 210 *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32; 211 212 err: 213 b53_srab_release_grant(dev); 214 215 return ret; 216 } 217 218 static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) 219 { 220 struct b53_srab_priv *priv = dev->priv; 221 u8 __iomem *regs = priv->regs; 222 int ret = 0; 223 224 ret = b53_srab_request_grant(dev); 225 if (ret) 226 goto err; 227 228 ret = b53_srab_op(dev, page, reg, 0); 229 if (ret) 230 goto err; 231 232 *val = readl(regs + B53_SRAB_RD_L); 233 *val += (u64)readl(regs + B53_SRAB_RD_H) << 32; 234 235 err: 236 b53_srab_release_grant(dev); 237 238 return ret; 239 } 240 241 static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) 242 { 243 struct b53_srab_priv *priv = dev->priv; 244 u8 __iomem *regs = priv->regs; 245 int ret = 0; 246 247 ret = b53_srab_request_grant(dev); 248 if (ret) 249 goto err; 250 251 writel(value, regs + B53_SRAB_WD_L); 252 253 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 254 255 err: 256 b53_srab_release_grant(dev); 257 258 return ret; 259 } 260 261 static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg, 262 u16 value) 263 { 264 struct b53_srab_priv *priv = dev->priv; 265 u8 __iomem *regs = priv->regs; 266 int ret = 0; 267 268 ret = b53_srab_request_grant(dev); 269 if (ret) 270 goto err; 271 272 writel(value, regs + B53_SRAB_WD_L); 273 274 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 275 276 err: 277 b53_srab_release_grant(dev); 278 279 return ret; 280 } 281 282 static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg, 283 u32 value) 284 { 285 struct b53_srab_priv *priv = dev->priv; 286 u8 __iomem *regs = priv->regs; 287 int ret = 0; 288 289 ret = b53_srab_request_grant(dev); 290 if (ret) 291 goto err; 292 293 writel(value, regs + B53_SRAB_WD_L); 294 295 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 296 297 err: 298 b53_srab_release_grant(dev); 299 300 return ret; 301 } 302 303 static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg, 304 u64 value) 305 { 306 struct b53_srab_priv *priv = dev->priv; 307 u8 __iomem *regs = priv->regs; 308 int ret = 0; 309 310 ret = b53_srab_request_grant(dev); 311 if (ret) 312 goto err; 313 314 writel((u32)value, regs + B53_SRAB_WD_L); 315 writel((u16)(value >> 32), regs + B53_SRAB_WD_H); 316 317 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 318 319 err: 320 b53_srab_release_grant(dev); 321 322 return ret; 323 } 324 325 static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg, 326 u64 value) 327 { 328 struct b53_srab_priv *priv = dev->priv; 329 u8 __iomem *regs = priv->regs; 330 int ret = 0; 331 332 ret = b53_srab_request_grant(dev); 333 if (ret) 334 goto err; 335 336 writel((u32)value, regs + B53_SRAB_WD_L); 337 writel((u32)(value >> 32), regs + B53_SRAB_WD_H); 338 339 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 340 341 err: 342 b53_srab_release_grant(dev); 343 344 return ret; 345 } 346 347 static const struct b53_io_ops b53_srab_ops = { 348 .read8 = b53_srab_read8, 349 .read16 = b53_srab_read16, 350 .read32 = b53_srab_read32, 351 .read48 = b53_srab_read48, 352 .read64 = b53_srab_read64, 353 .write8 = b53_srab_write8, 354 .write16 = b53_srab_write16, 355 .write32 = b53_srab_write32, 356 .write48 = b53_srab_write48, 357 .write64 = b53_srab_write64, 358 }; 359 360 static const struct of_device_id b53_srab_of_match[] = { 361 { .compatible = "brcm,bcm53010-srab" }, 362 { .compatible = "brcm,bcm53011-srab" }, 363 { .compatible = "brcm,bcm53012-srab" }, 364 { .compatible = "brcm,bcm53018-srab" }, 365 { .compatible = "brcm,bcm53019-srab" }, 366 { .compatible = "brcm,bcm5301x-srab" }, 367 { .compatible = "brcm,bcm11360-srab", .data = (void *)BCM583XX_DEVICE_ID }, 368 { .compatible = "brcm,bcm58522-srab", .data = (void *)BCM58XX_DEVICE_ID }, 369 { .compatible = "brcm,bcm58525-srab", .data = (void *)BCM58XX_DEVICE_ID }, 370 { .compatible = "brcm,bcm58535-srab", .data = (void *)BCM58XX_DEVICE_ID }, 371 { .compatible = "brcm,bcm58622-srab", .data = (void *)BCM58XX_DEVICE_ID }, 372 { .compatible = "brcm,bcm58623-srab", .data = (void *)BCM58XX_DEVICE_ID }, 373 { .compatible = "brcm,bcm58625-srab", .data = (void *)BCM58XX_DEVICE_ID }, 374 { .compatible = "brcm,bcm88312-srab", .data = (void *)BCM58XX_DEVICE_ID }, 375 { .compatible = "brcm,cygnus-srab", .data = (void *)BCM583XX_DEVICE_ID }, 376 { .compatible = "brcm,nsp-srab", .data = (void *)BCM58XX_DEVICE_ID }, 377 { .compatible = "brcm,omega-srab", .data = (void *)BCM583XX_DEVICE_ID }, 378 { /* sentinel */ }, 379 }; 380 MODULE_DEVICE_TABLE(of, b53_srab_of_match); 381 382 static int b53_srab_probe(struct platform_device *pdev) 383 { 384 struct b53_platform_data *pdata = pdev->dev.platform_data; 385 struct device_node *dn = pdev->dev.of_node; 386 const struct of_device_id *of_id = NULL; 387 struct b53_srab_priv *priv; 388 struct b53_device *dev; 389 struct resource *r; 390 391 if (dn) 392 of_id = of_match_node(b53_srab_of_match, dn); 393 394 if (of_id) { 395 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 396 if (!pdata) 397 return -ENOMEM; 398 399 pdata->chip_id = (u32)(unsigned long)of_id->data; 400 } 401 402 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 403 if (!priv) 404 return -ENOMEM; 405 406 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 407 priv->regs = devm_ioremap_resource(&pdev->dev, r); 408 if (IS_ERR(priv->regs)) 409 return -ENOMEM; 410 411 dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv); 412 if (!dev) 413 return -ENOMEM; 414 415 if (pdata) 416 dev->pdata = pdata; 417 418 platform_set_drvdata(pdev, dev); 419 420 return b53_switch_register(dev); 421 } 422 423 static int b53_srab_remove(struct platform_device *pdev) 424 { 425 struct b53_device *dev = platform_get_drvdata(pdev); 426 427 if (dev) 428 b53_switch_remove(dev); 429 430 return 0; 431 } 432 433 static struct platform_driver b53_srab_driver = { 434 .probe = b53_srab_probe, 435 .remove = b53_srab_remove, 436 .driver = { 437 .name = "b53-srab-switch", 438 .of_match_table = b53_srab_of_match, 439 }, 440 }; 441 442 module_platform_driver(b53_srab_driver); 443 MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>"); 444 MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver"); 445 MODULE_LICENSE("Dual BSD/GPL"); 446