kernel: b53: add Register Access Bridge Registers (SRAB) interface
authorHauke Mehrtens <hauke@hauke-m.de>
Wed, 25 Sep 2013 21:44:28 +0000 (21:44 +0000)
committerHauke Mehrtens <hauke@hauke-m.de>
Wed, 25 Sep 2013 21:44:28 +0000 (21:44 +0000)
The SRAB interface is used on BCM4707 and BCM5301X SoCs.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
SVN-Revision: 38198

target/linux/bcm53xx/config-3.10
target/linux/brcm47xx/config-3.10
target/linux/brcm63xx/config-3.10
target/linux/generic/files/drivers/net/phy/b53/Kconfig
target/linux/generic/files/drivers/net/phy/b53/Makefile
target/linux/generic/files/drivers/net/phy/b53/b53_srab.c [new file with mode: 0644]

index 325d884dd418c80d442f33e42c24fba28f43d1b6..b8ac7d3e652082905b4c6dda01b6eab4c9f28900 100644 (file)
@@ -38,8 +38,8 @@ CONFIG_ATAGS=y
 CONFIG_AUTO_ZRELADDR=y
 CONFIG_B53=y
 # CONFIG_B53_MMAP_DRIVER is not set
-CONFIG_B53_PHY_DRIVER=y
-CONFIG_B53_PHY_FIXUP=y
+# CONFIG_B53_PHY_DRIVER is not set
+CONFIG_B53_SRAB_DRIVER=y
 CONFIG_BCMA=y
 CONFIG_BCMA_BLOCKIO=y
 CONFIG_BCMA_DEBUG=y
@@ -98,7 +98,6 @@ CONFIG_HAS_DMA=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 # CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
-CONFIG_HAVE_AOUT=y
 CONFIG_HAVE_ARCH_JUMP_LABEL=y
 CONFIG_HAVE_ARCH_KGDB=y
 CONFIG_HAVE_ARCH_PFN_VALID=y
index 9d4f503d07364e3f787b1a623d4611c8a45f4b5c..7518bb80d0738b8b1d718d2a49102c773bf25cb8 100644 (file)
@@ -11,6 +11,7 @@ CONFIG_B53=y
 # CONFIG_B53_MMAP_DRIVER is not set
 CONFIG_B53_PHY_DRIVER=y
 CONFIG_B53_PHY_FIXUP=y
+# CONFIG_B53_SRAB_DRIVER is not set
 CONFIG_BCM47XX=y
 CONFIG_BCM47XX_BCMA=y
 CONFIG_BCM47XX_SSB=y
index f54a471cc7fac557797c396db4f10ccec3a5cf43..e47a22ad55ff25200ddebff0522be990467a90e4 100644 (file)
@@ -13,6 +13,7 @@ CONFIG_B53_MMAP_DRIVER=y
 CONFIG_B53_PHY_DRIVER=y
 CONFIG_B53_PHY_FIXUP=y
 CONFIG_B53_SPI_DRIVER=y
+# CONFIG_B53_SRAB_DRIVER is not set
 CONFIG_BCM63XX=y
 CONFIG_BCM63XX_CPU_3368=y
 CONFIG_BCM63XX_CPU_6328=y
index 3b514fb62269d140f482924ab32d9bdec64e4f2c..67e053ea0f51c657aeb8693f51635a527232b49c 100644 (file)
@@ -26,5 +26,12 @@ config B53_MMAP_DRIVER
          Select to enable support for memory-mapped switches like the BCM63XX
          integrated switches.
 
+config B53_SRAB_DRIVER
+       tristate "B53 SRAB connected switch driver"
+       depends on B53
+       help
+         Select to enable support for memory-mapped Switch Register Access
+         Bridge Registers (SRAB) like it is found on the BCM53010
+
 config B53_PHY_FIXUP
        bool
index 146196e088bdf709e31f80417a32ceb19b59425e..7cc39c7628fb3d137b765b2ebc79686f7ecb1efc 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_B53)               += b53_common.o
 obj-$(CONFIG_B53_PHY_FIXUP)    += b53_phy_fixup.o
 
 obj-$(CONFIG_B53_MMAP_DRIVER)  += b53_mmap.o
+obj-$(CONFIG_B53_SRAB_DRIVER)  += b53_srab.o
 obj-$(CONFIG_B53_PHY_DRIVER)   += b53_mdio.o
 obj-$(CONFIG_B53_SPI_DRIVER)   += b53_spi.o
 
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c b/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c
new file mode 100644 (file)
index 0000000..f0743b7
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * B53 register access through Switch Register Access Bridge Registers
+ *
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/b53.h>
+
+#include "b53_priv.h"
+
+/* command and status register of the SRAB */
+#define B53_SRAB_CMDSTAT               0x2c
+#define  B53_SRAB_CMDSTAT_RST          BIT(2)
+#define  B53_SRAB_CMDSTAT_WRITE                BIT(1)
+#define  B53_SRAB_CMDSTAT_GORDYN       BIT(0)
+#define  B53_SRAB_CMDSTAT_PAGE         24
+#define  B53_SRAB_CMDSTAT_REG          16
+
+/* high order word of write data to switch registe */
+#define B53_SRAB_WD_H                  0x30
+
+/* low order word of write data to switch registe */
+#define B53_SRAB_WD_L                  0x34
+
+/* high order word of read data from switch register */
+#define B53_SRAB_RD_H                  0x38
+
+/* low order word of read data from switch register */
+#define B53_SRAB_RD_L                  0x3c
+
+/* command and status register of the SRAB */
+#define B53_SRAB_CTRLS                 0x40
+#define  B53_SRAB_CTRLS_RCAREQ         BIT(3)
+#define  B53_SRAB_CTRLS_RCAGNT         BIT(4)
+#define  B53_SRAB_CTRLS_SW_INIT_DONE   BIT(6)
+
+/* the register captures interrupt pulses from the switch */
+#define B53_SRAB_INTR                  0x44
+
+static int b53_srab_request_grant(struct b53_device *dev)
+{
+       u8 __iomem *regs = dev->priv;
+       u32 ctrls;
+       int i;
+
+       ctrls = readl(regs + B53_SRAB_CTRLS);
+       ctrls |= B53_SRAB_CTRLS_RCAREQ;
+       writel(ctrls, regs + B53_SRAB_CTRLS);
+
+       for (i = 0; i < 20; i++) {
+               ctrls = readl(regs + B53_SRAB_CTRLS);
+               if (ctrls & B53_SRAB_CTRLS_RCAGNT)
+                       break;
+               usleep_range(10, 100);
+       }
+       if (WARN_ON(i == 5))
+               return -EIO;
+
+       return 0;
+}
+
+static void b53_srab_release_grant(struct b53_device *dev)
+{
+       u8 __iomem *regs = dev->priv;
+       u32 ctrls;
+
+       ctrls = readl(regs + B53_SRAB_CTRLS);
+       ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
+       writel(ctrls, regs + B53_SRAB_CTRLS);
+}
+
+static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
+{
+       int i;
+       u32 cmdstat;
+       u8 __iomem *regs = dev->priv;
+
+       /* set register address */
+       cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
+                 (reg << B53_SRAB_CMDSTAT_REG) |
+                 B53_SRAB_CMDSTAT_GORDYN |
+                 op;
+       writel(cmdstat, regs + B53_SRAB_CMDSTAT);
+       
+       /* check if operation completed */
+       for (i = 0; i < 5; ++i) {
+               cmdstat = readl(regs + B53_SRAB_CMDSTAT);
+               if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
+                       break;
+               usleep_range(10, 100);
+       }
+
+       if (WARN_ON(i == 5))
+               return -EIO;
+
+       return 0;
+}
+
+static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       ret = b53_srab_op(dev, page, reg, 0);
+       if (ret)
+               goto err;
+
+       *val = readl(regs + B53_SRAB_RD_L) & 0xff;
+
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+}
+
+static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       ret = b53_srab_op(dev, page, reg, 0);
+       if (ret)
+               goto err;
+
+       *val = readl(regs + B53_SRAB_RD_L) & 0xffff;
+
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+}
+
+static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       ret = b53_srab_op(dev, page, reg, 0);
+       if (ret)
+               goto err;
+
+       *val = readl(regs + B53_SRAB_RD_L);
+
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+}
+
+static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       ret = b53_srab_op(dev, page, reg, 0);
+       if (ret)
+               goto err;
+
+       *val = readl(regs + B53_SRAB_RD_L);
+       *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
+       
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+}
+
+static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       ret = b53_srab_op(dev, page, reg, 0);
+       if (ret)
+               goto err;
+
+       *val = readl(regs + B53_SRAB_RD_L);
+       *val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
+
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+}
+
+static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       writel(value, regs + B53_SRAB_WD_L);
+
+       ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+}
+
+static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
+                            u16 value)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       writel(value, regs + B53_SRAB_WD_L);
+
+       ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+}
+
+static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
+                                   u32 value)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       writel(value, regs + B53_SRAB_WD_L);
+
+       ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+
+}
+
+static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
+                                   u64 value)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       writel((u32)value, regs + B53_SRAB_WD_L);
+       writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
+
+       ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+
+}
+
+static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
+                            u64 value)
+{
+       u8 __iomem *regs = dev->priv;
+       int ret = 0;
+
+       ret = b53_srab_request_grant(dev);
+       if (ret)
+               goto err;
+
+       writel((u32)value, regs + B53_SRAB_WD_L);
+       writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
+
+       ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+       b53_srab_release_grant(dev);
+
+       return ret;
+}
+
+static struct b53_io_ops b53_srab_ops = {
+       .read8 = b53_srab_read8,
+       .read16 = b53_srab_read16,
+       .read32 = b53_srab_read32,
+       .read48 = b53_srab_read48,
+       .read64 = b53_srab_read64,
+       .write8 = b53_srab_write8,
+       .write16 = b53_srab_write16,
+       .write32 = b53_srab_write32,
+       .write48 = b53_srab_write48,
+       .write64 = b53_srab_write64,
+};
+
+static int b53_srab_probe(struct platform_device *pdev)
+{
+       struct b53_platform_data *pdata = pdev->dev.platform_data;
+       struct b53_device *dev;
+
+       if (!pdata)
+               return -EINVAL;
+
+       dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs);
+       if (!dev)
+               return -ENOMEM;
+
+       if (pdata)
+               dev->pdata = pdata;
+
+       pdev->dev.platform_data = dev;
+
+       return b53_switch_register(dev);
+}
+
+static int b53_srab_remove(struct platform_device *pdev)
+{
+       struct b53_device *dev = pdev->dev.platform_data;
+
+       if (dev) {
+               pdev->dev.platform_data = dev->pdata;
+               b53_switch_remove(dev);
+       }
+
+       return 0;
+}
+
+static struct platform_driver b53_srab_driver = {
+       .probe = b53_srab_probe,
+       .remove = b53_srab_remove,
+       .driver = {
+               .name = "b53-srab-switch",
+       },
+};
+
+module_platform_driver(b53_srab_driver);
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
+MODULE_LICENSE("Dual BSD/GPL");