18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Broadcom specific AMBA 38c2ecf20Sopenharmony_ci * System on Chip (SoC) Host 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "bcma_private.h" 98c2ecf20Sopenharmony_ci#include "scan.h" 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of_address.h> 138c2ecf20Sopenharmony_ci#include <linux/bcma/bcma.h> 148c2ecf20Sopenharmony_ci#include <linux/bcma/bcma_soc.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci return readb(core->io_addr + offset); 198c2ecf20Sopenharmony_ci} 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci return readw(core->io_addr + offset); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci return readl(core->io_addr + offset); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void bcma_host_soc_write8(struct bcma_device *core, u16 offset, 328c2ecf20Sopenharmony_ci u8 value) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci writeb(value, core->io_addr + offset); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void bcma_host_soc_write16(struct bcma_device *core, u16 offset, 388c2ecf20Sopenharmony_ci u16 value) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci writew(value, core->io_addr + offset); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void bcma_host_soc_write32(struct bcma_device *core, u16 offset, 448c2ecf20Sopenharmony_ci u32 value) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci writel(value, core->io_addr + offset); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#ifdef CONFIG_BCMA_BLOCKIO 508c2ecf20Sopenharmony_cistatic void bcma_host_soc_block_read(struct bcma_device *core, void *buffer, 518c2ecf20Sopenharmony_ci size_t count, u16 offset, u8 reg_width) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci void __iomem *addr = core->io_addr + offset; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci switch (reg_width) { 568c2ecf20Sopenharmony_ci case sizeof(u8): { 578c2ecf20Sopenharmony_ci u8 *buf = buffer; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci while (count) { 608c2ecf20Sopenharmony_ci *buf = __raw_readb(addr); 618c2ecf20Sopenharmony_ci buf++; 628c2ecf20Sopenharmony_ci count--; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci case sizeof(u16): { 678c2ecf20Sopenharmony_ci __le16 *buf = buffer; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci WARN_ON(count & 1); 708c2ecf20Sopenharmony_ci while (count) { 718c2ecf20Sopenharmony_ci *buf = (__force __le16)__raw_readw(addr); 728c2ecf20Sopenharmony_ci buf++; 738c2ecf20Sopenharmony_ci count -= 2; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci case sizeof(u32): { 788c2ecf20Sopenharmony_ci __le32 *buf = buffer; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci WARN_ON(count & 3); 818c2ecf20Sopenharmony_ci while (count) { 828c2ecf20Sopenharmony_ci *buf = (__force __le32)__raw_readl(addr); 838c2ecf20Sopenharmony_ci buf++; 848c2ecf20Sopenharmony_ci count -= 4; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci default: 898c2ecf20Sopenharmony_ci WARN_ON(1); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void bcma_host_soc_block_write(struct bcma_device *core, 948c2ecf20Sopenharmony_ci const void *buffer, 958c2ecf20Sopenharmony_ci size_t count, u16 offset, u8 reg_width) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci void __iomem *addr = core->io_addr + offset; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci switch (reg_width) { 1008c2ecf20Sopenharmony_ci case sizeof(u8): { 1018c2ecf20Sopenharmony_ci const u8 *buf = buffer; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci while (count) { 1048c2ecf20Sopenharmony_ci __raw_writeb(*buf, addr); 1058c2ecf20Sopenharmony_ci buf++; 1068c2ecf20Sopenharmony_ci count--; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci case sizeof(u16): { 1118c2ecf20Sopenharmony_ci const __le16 *buf = buffer; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci WARN_ON(count & 1); 1148c2ecf20Sopenharmony_ci while (count) { 1158c2ecf20Sopenharmony_ci __raw_writew((__force u16)(*buf), addr); 1168c2ecf20Sopenharmony_ci buf++; 1178c2ecf20Sopenharmony_ci count -= 2; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci case sizeof(u32): { 1228c2ecf20Sopenharmony_ci const __le32 *buf = buffer; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci WARN_ON(count & 3); 1258c2ecf20Sopenharmony_ci while (count) { 1268c2ecf20Sopenharmony_ci __raw_writel((__force u32)(*buf), addr); 1278c2ecf20Sopenharmony_ci buf++; 1288c2ecf20Sopenharmony_ci count -= 4; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci default: 1338c2ecf20Sopenharmony_ci WARN_ON(1); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci#endif /* CONFIG_BCMA_BLOCKIO */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n")) 1418c2ecf20Sopenharmony_ci return ~0; 1428c2ecf20Sopenharmony_ci return readl(core->io_wrap + offset); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset, 1468c2ecf20Sopenharmony_ci u32 value) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n")) 1498c2ecf20Sopenharmony_ci return; 1508c2ecf20Sopenharmony_ci writel(value, core->io_wrap + offset); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic const struct bcma_host_ops bcma_host_soc_ops = { 1548c2ecf20Sopenharmony_ci .read8 = bcma_host_soc_read8, 1558c2ecf20Sopenharmony_ci .read16 = bcma_host_soc_read16, 1568c2ecf20Sopenharmony_ci .read32 = bcma_host_soc_read32, 1578c2ecf20Sopenharmony_ci .write8 = bcma_host_soc_write8, 1588c2ecf20Sopenharmony_ci .write16 = bcma_host_soc_write16, 1598c2ecf20Sopenharmony_ci .write32 = bcma_host_soc_write32, 1608c2ecf20Sopenharmony_ci#ifdef CONFIG_BCMA_BLOCKIO 1618c2ecf20Sopenharmony_ci .block_read = bcma_host_soc_block_read, 1628c2ecf20Sopenharmony_ci .block_write = bcma_host_soc_block_write, 1638c2ecf20Sopenharmony_ci#endif 1648c2ecf20Sopenharmony_ci .aread32 = bcma_host_soc_aread32, 1658c2ecf20Sopenharmony_ci .awrite32 = bcma_host_soc_awrite32, 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ciint __init bcma_host_soc_register(struct bcma_soc *soc) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct bcma_bus *bus = &soc->bus; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* iomap only first core. We have to read some register on this core 1738c2ecf20Sopenharmony_ci * to scan the bus. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci bus->mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1); 1768c2ecf20Sopenharmony_ci if (!bus->mmio) 1778c2ecf20Sopenharmony_ci return -ENOMEM; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Host specific */ 1808c2ecf20Sopenharmony_ci bus->hosttype = BCMA_HOSTTYPE_SOC; 1818c2ecf20Sopenharmony_ci bus->ops = &bcma_host_soc_ops; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* Initialize struct, detect chip */ 1848c2ecf20Sopenharmony_ci bcma_init_bus(bus); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ciint __init bcma_host_soc_init(struct bcma_soc *soc) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct bcma_bus *bus = &soc->bus; 1928c2ecf20Sopenharmony_ci int err; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* Scan bus and initialize it */ 1958c2ecf20Sopenharmony_ci err = bcma_bus_early_register(bus); 1968c2ecf20Sopenharmony_ci if (err) 1978c2ecf20Sopenharmony_ci iounmap(bus->mmio); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return err; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 2038c2ecf20Sopenharmony_cistatic int bcma_host_soc_probe(struct platform_device *pdev) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2068c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 2078c2ecf20Sopenharmony_ci struct bcma_bus *bus; 2088c2ecf20Sopenharmony_ci int err; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Alloc */ 2118c2ecf20Sopenharmony_ci bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL); 2128c2ecf20Sopenharmony_ci if (!bus) 2138c2ecf20Sopenharmony_ci return -ENOMEM; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci bus->dev = dev; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* Map MMIO */ 2188c2ecf20Sopenharmony_ci bus->mmio = of_iomap(np, 0); 2198c2ecf20Sopenharmony_ci if (!bus->mmio) 2208c2ecf20Sopenharmony_ci return -ENOMEM; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* Host specific */ 2238c2ecf20Sopenharmony_ci bus->hosttype = BCMA_HOSTTYPE_SOC; 2248c2ecf20Sopenharmony_ci bus->ops = &bcma_host_soc_ops; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Initialize struct, detect chip */ 2278c2ecf20Sopenharmony_ci bcma_init_bus(bus); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Register */ 2308c2ecf20Sopenharmony_ci err = bcma_bus_register(bus); 2318c2ecf20Sopenharmony_ci if (err) 2328c2ecf20Sopenharmony_ci goto err_unmap_mmio; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, bus); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return err; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cierr_unmap_mmio: 2398c2ecf20Sopenharmony_ci iounmap(bus->mmio); 2408c2ecf20Sopenharmony_ci return err; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int bcma_host_soc_remove(struct platform_device *pdev) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct bcma_bus *bus = platform_get_drvdata(pdev); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci bcma_bus_unregister(bus); 2488c2ecf20Sopenharmony_ci iounmap(bus->mmio); 2498c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, NULL); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic const struct of_device_id bcma_host_soc_of_match[] = { 2558c2ecf20Sopenharmony_ci { .compatible = "brcm,bus-axi", }, 2568c2ecf20Sopenharmony_ci {}, 2578c2ecf20Sopenharmony_ci}; 2588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bcma_host_soc_of_match); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic struct platform_driver bcma_host_soc_driver = { 2618c2ecf20Sopenharmony_ci .driver = { 2628c2ecf20Sopenharmony_ci .name = "bcma-host-soc", 2638c2ecf20Sopenharmony_ci .of_match_table = bcma_host_soc_of_match, 2648c2ecf20Sopenharmony_ci }, 2658c2ecf20Sopenharmony_ci .probe = bcma_host_soc_probe, 2668c2ecf20Sopenharmony_ci .remove = bcma_host_soc_remove, 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ciint __init bcma_host_soc_register_driver(void) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci return platform_driver_register(&bcma_host_soc_driver); 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_civoid __exit bcma_host_soc_unregister_driver(void) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci platform_driver_unregister(&bcma_host_soc_driver); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci#endif /* CONFIG_OF */ 279