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