From: Hauke Mehrtens Date: Wed, 25 Sep 2013 21:44:28 +0000 (+0000) Subject: kernel: b53: add Register Access Bridge Registers (SRAB) interface X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=c75a970337175d123c3989f473052f4919b5fd91;p=openwrt%2Fstaging%2Fnbd.git kernel: b53: add Register Access Bridge Registers (SRAB) interface The SRAB interface is used on BCM4707 and BCM5301X SoCs. Signed-off-by: Hauke Mehrtens SVN-Revision: 38198 --- diff --git a/target/linux/bcm53xx/config-3.10 b/target/linux/bcm53xx/config-3.10 index 325d884dd4..b8ac7d3e65 100644 --- a/target/linux/bcm53xx/config-3.10 +++ b/target/linux/bcm53xx/config-3.10 @@ -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 diff --git a/target/linux/brcm47xx/config-3.10 b/target/linux/brcm47xx/config-3.10 index 9d4f503d07..7518bb80d0 100644 --- a/target/linux/brcm47xx/config-3.10 +++ b/target/linux/brcm47xx/config-3.10 @@ -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 diff --git a/target/linux/brcm63xx/config-3.10 b/target/linux/brcm63xx/config-3.10 index f54a471cc7..e47a22ad55 100644 --- a/target/linux/brcm63xx/config-3.10 +++ b/target/linux/brcm63xx/config-3.10 @@ -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 diff --git a/target/linux/generic/files/drivers/net/phy/b53/Kconfig b/target/linux/generic/files/drivers/net/phy/b53/Kconfig index 3b514fb622..67e053ea0f 100644 --- a/target/linux/generic/files/drivers/net/phy/b53/Kconfig +++ b/target/linux/generic/files/drivers/net/phy/b53/Kconfig @@ -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 diff --git a/target/linux/generic/files/drivers/net/phy/b53/Makefile b/target/linux/generic/files/drivers/net/phy/b53/Makefile index 146196e088..7cc39c7628 100644 --- a/target/linux/generic/files/drivers/net/phy/b53/Makefile +++ b/target/linux/generic/files/drivers/net/phy/b53/Makefile @@ -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 index 0000000000..f0743b7017 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c @@ -0,0 +1,380 @@ +/* + * B53 register access through Switch Register Access Bridge Registers + * + * Copyright (C) 2013 Hauke Mehrtens + * + * 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 +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver"); +MODULE_LICENSE("Dual BSD/GPL");