diff options
Diffstat (limited to 'drivers/bcma/host_soc.c')
-rw-r--r-- | drivers/bcma/host_soc.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c new file mode 100644 index 000000000000..3c381fb8f9c4 --- /dev/null +++ b/drivers/bcma/host_soc.c @@ -0,0 +1,183 @@ +/* + * Broadcom specific AMBA + * System on Chip (SoC) Host + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include "scan.h" +#include <linux/bcma/bcma.h> +#include <linux/bcma/bcma_soc.h> + +static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset) +{ + return readb(core->io_addr + offset); +} + +static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset) +{ + return readw(core->io_addr + offset); +} + +static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset) +{ + return readl(core->io_addr + offset); +} + +static void bcma_host_soc_write8(struct bcma_device *core, u16 offset, + u8 value) +{ + writeb(value, core->io_addr + offset); +} + +static void bcma_host_soc_write16(struct bcma_device *core, u16 offset, + u16 value) +{ + writew(value, core->io_addr + offset); +} + +static void bcma_host_soc_write32(struct bcma_device *core, u16 offset, + u32 value) +{ + writel(value, core->io_addr + offset); +} + +#ifdef CONFIG_BCMA_BLOCKIO +static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + void __iomem *addr = core->io_addr + offset; + + switch (reg_width) { + case sizeof(u8): { + u8 *buf = buffer; + + while (count) { + *buf = __raw_readb(addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + __le16 *buf = buffer; + + WARN_ON(count & 1); + while (count) { + *buf = (__force __le16)__raw_readw(addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + __le32 *buf = buffer; + + WARN_ON(count & 3); + while (count) { + *buf = (__force __le32)__raw_readl(addr); + buf++; + count -= 4; + } + break; + } + default: + WARN_ON(1); + } +} + +static void bcma_host_soc_block_write(struct bcma_device *core, + const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + void __iomem *addr = core->io_addr + offset; + + switch (reg_width) { + case sizeof(u8): { + const u8 *buf = buffer; + + while (count) { + __raw_writeb(*buf, addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + const __le16 *buf = buffer; + + WARN_ON(count & 1); + while (count) { + __raw_writew((__force u16)(*buf), addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + const __le32 *buf = buffer; + + WARN_ON(count & 3); + while (count) { + __raw_writel((__force u32)(*buf), addr); + buf++; + count -= 4; + } + break; + } + default: + WARN_ON(1); + } +} +#endif /* CONFIG_BCMA_BLOCKIO */ + +static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset) +{ + return readl(core->io_wrap + offset); +} + +static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset, + u32 value) +{ + writel(value, core->io_wrap + offset); +} + +const struct bcma_host_ops bcma_host_soc_ops = { + .read8 = bcma_host_soc_read8, + .read16 = bcma_host_soc_read16, + .read32 = bcma_host_soc_read32, + .write8 = bcma_host_soc_write8, + .write16 = bcma_host_soc_write16, + .write32 = bcma_host_soc_write32, +#ifdef CONFIG_BCMA_BLOCKIO + .block_read = bcma_host_soc_block_read, + .block_write = bcma_host_soc_block_write, +#endif + .aread32 = bcma_host_soc_aread32, + .awrite32 = bcma_host_soc_awrite32, +}; + +int __init bcma_host_soc_register(struct bcma_soc *soc) +{ + struct bcma_bus *bus = &soc->bus; + int err; + + /* iomap only first core. We have to read some register on this core + * to scan the bus. + */ + bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1); + if (!bus->mmio) + return -ENOMEM; + + /* Host specific */ + bus->hosttype = BCMA_HOSTTYPE_SOC; + bus->ops = &bcma_host_soc_ops; + + /* Register */ + err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips); + if (err) + iounmap(bus->mmio); + + return err; +} |