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 16 static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset) 17 { 18 return readb(core->io_addr + offset); 19 } 20 21 static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset) 22 { 23 return readw(core->io_addr + offset); 24 } 25 26 static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset) 27 { 28 return readl(core->io_addr + offset); 29 } 30 31 static void bcma_host_soc_write8(struct bcma_device *core, u16 offset, 32 u8 value) 33 { 34 writeb(value, core->io_addr + offset); 35 } 36 37 static void bcma_host_soc_write16(struct bcma_device *core, u16 offset, 38 u16 value) 39 { 40 writew(value, core->io_addr + offset); 41 } 42 43 static 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 50 static 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 93 static 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 138 static 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 145 static 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 153 static 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 168 int __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 183 /* Initialize struct, detect chip */ 184 bcma_init_bus(bus); 185 186 return 0; 187 } 188 189 int __init bcma_host_soc_init(struct bcma_soc *soc) 190 { 191 struct bcma_bus *bus = &soc->bus; 192 int err; 193 194 /* Scan bus and initialize it */ 195 err = bcma_bus_early_register(bus); 196 if (err) 197 iounmap(bus->mmio); 198 199 return err; 200 } 201 202 #ifdef CONFIG_OF 203 static int bcma_host_soc_probe(struct platform_device *pdev) 204 { 205 struct device *dev = &pdev->dev; 206 struct device_node *np = dev->of_node; 207 struct bcma_bus *bus; 208 int err; 209 210 /* Alloc */ 211 bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL); 212 if (!bus) 213 return -ENOMEM; 214 215 bus->dev = dev; 216 217 /* Map MMIO */ 218 bus->mmio = of_iomap(np, 0); 219 if (!bus->mmio) 220 return -ENOMEM; 221 222 /* Host specific */ 223 bus->hosttype = BCMA_HOSTTYPE_SOC; 224 bus->ops = &bcma_host_soc_ops; 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 238 err_unmap_mmio: 239 iounmap(bus->mmio); 240 return err; 241 } 242 243 static 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 254 static const struct of_device_id bcma_host_soc_of_match[] = { 255 { .compatible = "brcm,bus-axi", }, 256 {}, 257 }; 258 MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match); 259 260 static 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 269 int __init bcma_host_soc_register_driver(void) 270 { 271 return platform_driver_register(&bcma_host_soc_driver); 272 } 273 274 void __exit bcma_host_soc_unregister_driver(void) 275 { 276 platform_driver_unregister(&bcma_host_soc_driver); 277 } 278 #endif /* CONFIG_OF */ 279