1/* 2 * Broadcom specific AMBA 3 * System on Chip (SoC) Host 4 * 5 * Licensed under the GNU/GPL. See COPYING for details. 6 */ 7 8#include "bcma_private.h" 9#include "scan.h" 10#include <linux/slab.h> 11#include <linux/module.h> 12#include <linux/of_address.h> 13#include <linux/bcma/bcma.h> 14#include <linux/bcma/bcma_soc.h> 15 16static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset) 17{ 18 return readb(core->io_addr + offset); 19} 20 21static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset) 22{ 23 return readw(core->io_addr + offset); 24} 25 26static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset) 27{ 28 return readl(core->io_addr + offset); 29} 30 31static void bcma_host_soc_write8(struct bcma_device *core, u16 offset, 32 u8 value) 33{ 34 writeb(value, core->io_addr + offset); 35} 36 37static void bcma_host_soc_write16(struct bcma_device *core, u16 offset, 38 u16 value) 39{ 40 writew(value, core->io_addr + offset); 41} 42 43static void bcma_host_soc_write32(struct bcma_device *core, u16 offset, 44 u32 value) 45{ 46 writel(value, core->io_addr + offset); 47} 48 49#ifdef CONFIG_BCMA_BLOCKIO 50static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer, 51 size_t count, u16 offset, u8 reg_width) 52{ 53 void __iomem *addr = core->io_addr + offset; 54 55 switch (reg_width) { 56 case sizeof(u8): { 57 u8 *buf = buffer; 58 59 while (count) { 60 *buf = __raw_readb(addr); 61 buf++; 62 count--; 63 } 64 break; 65 } 66 case sizeof(u16): { 67 __le16 *buf = buffer; 68 69 WARN_ON(count & 1); 70 while (count) { 71 *buf = (__force __le16)__raw_readw(addr); 72 buf++; 73 count -= 2; 74 } 75 break; 76 } 77 case sizeof(u32): { 78 __le32 *buf = buffer; 79 80 WARN_ON(count & 3); 81 while (count) { 82 *buf = (__force __le32)__raw_readl(addr); 83 buf++; 84 count -= 4; 85 } 86 break; 87 } 88 default: 89 WARN_ON(1); 90 } 91} 92 93static void bcma_host_soc_block_write(struct bcma_device *core, 94 const void *buffer, 95 size_t count, u16 offset, u8 reg_width) 96{ 97 void __iomem *addr = core->io_addr + offset; 98 99 switch (reg_width) { 100 case sizeof(u8): { 101 const u8 *buf = buffer; 102 103 while (count) { 104 __raw_writeb(*buf, addr); 105 buf++; 106 count--; 107 } 108 break; 109 } 110 case sizeof(u16): { 111 const __le16 *buf = buffer; 112 113 WARN_ON(count & 1); 114 while (count) { 115 __raw_writew((__force u16)(*buf), addr); 116 buf++; 117 count -= 2; 118 } 119 break; 120 } 121 case sizeof(u32): { 122 const __le32 *buf = buffer; 123 124 WARN_ON(count & 3); 125 while (count) { 126 __raw_writel((__force u32)(*buf), addr); 127 buf++; 128 count -= 4; 129 } 130 break; 131 } 132 default: 133 WARN_ON(1); 134 } 135} 136#endif /* CONFIG_BCMA_BLOCKIO */ 137 138static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset) 139{ 140 if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n")) 141 return ~0; 142 return readl(core->io_wrap + offset); 143} 144 145static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset, 146 u32 value) 147{ 148 if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n")) 149 return; 150 writel(value, core->io_wrap + offset); 151} 152 153static const struct bcma_host_ops bcma_host_soc_ops = { 154 .read8 = bcma_host_soc_read8, 155 .read16 = bcma_host_soc_read16, 156 .read32 = bcma_host_soc_read32, 157 .write8 = bcma_host_soc_write8, 158 .write16 = bcma_host_soc_write16, 159 .write32 = bcma_host_soc_write32, 160#ifdef CONFIG_BCMA_BLOCKIO 161 .block_read = bcma_host_soc_block_read, 162 .block_write = bcma_host_soc_block_write, 163#endif 164 .aread32 = bcma_host_soc_aread32, 165 .awrite32 = bcma_host_soc_awrite32, 166}; 167 168int __init bcma_host_soc_register(struct bcma_soc *soc) 169{ 170 struct bcma_bus *bus = &soc->bus; 171 172 /* iomap only first core. We have to read some register on this core 173 * to scan the bus. 174 */ 175 bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1); 176 if (!bus->mmio) 177 return -ENOMEM; 178 179 /* Host specific */ 180 bus->hosttype = BCMA_HOSTTYPE_SOC; 181 bus->ops = &bcma_host_soc_ops; 182 bus->host_pdev = NULL; 183 184 /* Initialize struct, detect chip */ 185 bcma_init_bus(bus); 186 187 return 0; 188} 189 190int __init bcma_host_soc_init(struct bcma_soc *soc) 191{ 192 struct bcma_bus *bus = &soc->bus; 193 int err; 194 195 /* Scan bus and initialize it */ 196 err = bcma_bus_early_register(bus); 197 if (err) 198 iounmap(bus->mmio); 199 200 return err; 201} 202 203#ifdef CONFIG_OF 204static int bcma_host_soc_probe(struct platform_device *pdev) 205{ 206 struct device *dev = &pdev->dev; 207 struct device_node *np = dev->of_node; 208 struct bcma_bus *bus; 209 int err; 210 211 /* Alloc */ 212 bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL); 213 if (!bus) 214 return -ENOMEM; 215 216 /* Map MMIO */ 217 bus->mmio = of_iomap(np, 0); 218 if (!bus->mmio) 219 return -ENOMEM; 220 221 /* Host specific */ 222 bus->hosttype = BCMA_HOSTTYPE_SOC; 223 bus->ops = &bcma_host_soc_ops; 224 bus->host_pdev = pdev; 225 226 /* Initialize struct, detect chip */ 227 bcma_init_bus(bus); 228 229 /* Register */ 230 err = bcma_bus_register(bus); 231 if (err) 232 goto err_unmap_mmio; 233 234 platform_set_drvdata(pdev, bus); 235 236 return err; 237 238err_unmap_mmio: 239 iounmap(bus->mmio); 240 return err; 241} 242 243static int bcma_host_soc_remove(struct platform_device *pdev) 244{ 245 struct bcma_bus *bus = platform_get_drvdata(pdev); 246 247 bcma_bus_unregister(bus); 248 iounmap(bus->mmio); 249 platform_set_drvdata(pdev, NULL); 250 251 return 0; 252} 253 254static const struct of_device_id bcma_host_soc_of_match[] = { 255 { .compatible = "brcm,bus-axi", }, 256 {}, 257}; 258MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match); 259 260static struct platform_driver bcma_host_soc_driver = { 261 .driver = { 262 .name = "bcma-host-soc", 263 .of_match_table = bcma_host_soc_of_match, 264 }, 265 .probe = bcma_host_soc_probe, 266 .remove = bcma_host_soc_remove, 267}; 268 269int __init bcma_host_soc_register_driver(void) 270{ 271 return platform_driver_register(&bcma_host_soc_driver); 272} 273 274void __exit bcma_host_soc_unregister_driver(void) 275{ 276 platform_driver_unregister(&bcma_host_soc_driver); 277} 278#endif /* CONFIG_OF */ 279