Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Broadcom specific AMBA
0003  * Bus scanning
0004  *
0005  * Licensed under the GNU/GPL. See COPYING for details.
0006  */
0007 
0008 #include "scan.h"
0009 #include "bcma_private.h"
0010 
0011 #include <linux/bcma/bcma.h>
0012 #include <linux/bcma/bcma_regs.h>
0013 #include <linux/pci.h>
0014 #include <linux/io.h>
0015 #include <linux/dma-mapping.h>
0016 #include <linux/slab.h>
0017 
0018 struct bcma_device_id_name {
0019     u16 id;
0020     const char *name;
0021 };
0022 
0023 static const struct bcma_device_id_name bcma_arm_device_names[] = {
0024     { BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" },
0025     { BCMA_CORE_ARM_1176, "ARM 1176" },
0026     { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
0027     { BCMA_CORE_ARM_CM3, "ARM CM3" },
0028 };
0029 
0030 static const struct bcma_device_id_name bcma_bcm_device_names[] = {
0031     { BCMA_CORE_OOB_ROUTER, "OOB Router" },
0032     { BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" },
0033     { BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" },
0034     { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" },
0035     { BCMA_CORE_NS_PCIEG2, "PCIe Gen 2" },
0036     { BCMA_CORE_NS_DMA, "DMA" },
0037     { BCMA_CORE_NS_SDIO3, "SDIO3" },
0038     { BCMA_CORE_NS_USB20, "USB 2.0" },
0039     { BCMA_CORE_NS_USB30, "USB 3.0" },
0040     { BCMA_CORE_NS_A9JTAG, "ARM Cortex A9 JTAG" },
0041     { BCMA_CORE_NS_DDR23, "Denali DDR2/DDR3 memory controller" },
0042     { BCMA_CORE_NS_ROM, "ROM" },
0043     { BCMA_CORE_NS_NAND, "NAND flash controller" },
0044     { BCMA_CORE_NS_QSPI, "SPI flash controller" },
0045     { BCMA_CORE_NS_CHIPCOMMON_B, "Chipcommon B" },
0046     { BCMA_CORE_ARMCA9, "ARM Cortex A9 core (ihost)" },
0047     { BCMA_CORE_AMEMC, "AMEMC (DDR)" },
0048     { BCMA_CORE_ALTA, "ALTA (I2S)" },
0049     { BCMA_CORE_INVALID, "Invalid" },
0050     { BCMA_CORE_CHIPCOMMON, "ChipCommon" },
0051     { BCMA_CORE_ILINE20, "ILine 20" },
0052     { BCMA_CORE_SRAM, "SRAM" },
0053     { BCMA_CORE_SDRAM, "SDRAM" },
0054     { BCMA_CORE_PCI, "PCI" },
0055     { BCMA_CORE_ETHERNET, "Fast Ethernet" },
0056     { BCMA_CORE_V90, "V90" },
0057     { BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
0058     { BCMA_CORE_ADSL, "ADSL" },
0059     { BCMA_CORE_ILINE100, "ILine 100" },
0060     { BCMA_CORE_IPSEC, "IPSEC" },
0061     { BCMA_CORE_UTOPIA, "UTOPIA" },
0062     { BCMA_CORE_PCMCIA, "PCMCIA" },
0063     { BCMA_CORE_INTERNAL_MEM, "Internal Memory" },
0064     { BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" },
0065     { BCMA_CORE_OFDM, "OFDM" },
0066     { BCMA_CORE_EXTIF, "EXTIF" },
0067     { BCMA_CORE_80211, "IEEE 802.11" },
0068     { BCMA_CORE_PHY_A, "PHY A" },
0069     { BCMA_CORE_PHY_B, "PHY B" },
0070     { BCMA_CORE_PHY_G, "PHY G" },
0071     { BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
0072     { BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
0073     { BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
0074     { BCMA_CORE_USB20_DEV, "USB 2.0 Device" },
0075     { BCMA_CORE_SDIO_HOST, "SDIO Host" },
0076     { BCMA_CORE_ROBOSWITCH, "Roboswitch" },
0077     { BCMA_CORE_PARA_ATA, "PATA" },
0078     { BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" },
0079     { BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" },
0080     { BCMA_CORE_PCIE, "PCIe" },
0081     { BCMA_CORE_PHY_N, "PHY N" },
0082     { BCMA_CORE_SRAM_CTL, "SRAM Controller" },
0083     { BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
0084     { BCMA_CORE_PHY_LP, "PHY LP" },
0085     { BCMA_CORE_PMU, "PMU" },
0086     { BCMA_CORE_PHY_SSN, "PHY SSN" },
0087     { BCMA_CORE_SDIO_DEV, "SDIO Device" },
0088     { BCMA_CORE_PHY_HT, "PHY HT" },
0089     { BCMA_CORE_MAC_GBIT, "GBit MAC" },
0090     { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
0091     { BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
0092     { BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" },
0093     { BCMA_CORE_SHARED_COMMON, "Common Shared" },
0094     { BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" },
0095     { BCMA_CORE_SPI_HOST, "SPI Host" },
0096     { BCMA_CORE_I2S, "I2S" },
0097     { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
0098     { BCMA_CORE_SHIM, "SHIM" },
0099     { BCMA_CORE_PCIE2, "PCIe Gen2" },
0100     { BCMA_CORE_ARM_CR4, "ARM CR4" },
0101     { BCMA_CORE_GCI, "GCI" },
0102     { BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
0103     { BCMA_CORE_ARM_CA7, "ARM CA7" },
0104     { BCMA_CORE_DEFAULT, "Default" },
0105 };
0106 
0107 static const struct bcma_device_id_name bcma_mips_device_names[] = {
0108     { BCMA_CORE_MIPS, "MIPS" },
0109     { BCMA_CORE_MIPS_3302, "MIPS 3302" },
0110     { BCMA_CORE_MIPS_74K, "MIPS 74K" },
0111 };
0112 
0113 static const char *bcma_device_name(const struct bcma_device_id *id)
0114 {
0115     const struct bcma_device_id_name *names;
0116     int size, i;
0117 
0118     /* search manufacturer specific names */
0119     switch (id->manuf) {
0120     case BCMA_MANUF_ARM:
0121         names = bcma_arm_device_names;
0122         size = ARRAY_SIZE(bcma_arm_device_names);
0123         break;
0124     case BCMA_MANUF_BCM:
0125         names = bcma_bcm_device_names;
0126         size = ARRAY_SIZE(bcma_bcm_device_names);
0127         break;
0128     case BCMA_MANUF_MIPS:
0129         names = bcma_mips_device_names;
0130         size = ARRAY_SIZE(bcma_mips_device_names);
0131         break;
0132     default:
0133         return "UNKNOWN";
0134     }
0135 
0136     for (i = 0; i < size; i++) {
0137         if (names[i].id == id->id)
0138             return names[i].name;
0139     }
0140 
0141     return "UNKNOWN";
0142 }
0143 
0144 static u32 bcma_scan_read32(struct bcma_bus *bus, u16 offset)
0145 {
0146     return readl(bus->mmio + offset);
0147 }
0148 
0149 static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
0150 {
0151     if (bus->hosttype == BCMA_HOSTTYPE_PCI)
0152         pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN,
0153                        addr);
0154 }
0155 
0156 static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 __iomem **eromptr)
0157 {
0158     u32 ent = readl(*eromptr);
0159     (*eromptr)++;
0160     return ent;
0161 }
0162 
0163 static void bcma_erom_push_ent(u32 __iomem **eromptr)
0164 {
0165     (*eromptr)--;
0166 }
0167 
0168 static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 __iomem **eromptr)
0169 {
0170     u32 ent = bcma_erom_get_ent(bus, eromptr);
0171     if (!(ent & SCAN_ER_VALID))
0172         return -ENOENT;
0173     if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI)
0174         return -ENOENT;
0175     return ent;
0176 }
0177 
0178 static bool bcma_erom_is_end(struct bcma_bus *bus, u32 __iomem **eromptr)
0179 {
0180     u32 ent = bcma_erom_get_ent(bus, eromptr);
0181     bcma_erom_push_ent(eromptr);
0182     return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
0183 }
0184 
0185 static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 __iomem **eromptr)
0186 {
0187     u32 ent = bcma_erom_get_ent(bus, eromptr);
0188     bcma_erom_push_ent(eromptr);
0189     return (((ent & SCAN_ER_VALID)) &&
0190         ((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) &&
0191         ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
0192 }
0193 
0194 static void bcma_erom_skip_component(struct bcma_bus *bus, u32 __iomem **eromptr)
0195 {
0196     u32 ent;
0197     while (1) {
0198         ent = bcma_erom_get_ent(bus, eromptr);
0199         if ((ent & SCAN_ER_VALID) &&
0200             ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI))
0201             break;
0202         if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID))
0203             break;
0204     }
0205     bcma_erom_push_ent(eromptr);
0206 }
0207 
0208 static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
0209 {
0210     u32 ent = bcma_erom_get_ent(bus, eromptr);
0211     if (!(ent & SCAN_ER_VALID))
0212         return -ENOENT;
0213     if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP)
0214         return -ENOENT;
0215     return ent;
0216 }
0217 
0218 static u32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
0219                   u32 type, u8 port)
0220 {
0221     u32 addrl;
0222     u32 size;
0223 
0224     u32 ent = bcma_erom_get_ent(bus, eromptr);
0225     if ((!(ent & SCAN_ER_VALID)) ||
0226         ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) ||
0227         ((ent & SCAN_ADDR_TYPE) != type) ||
0228         (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
0229         bcma_erom_push_ent(eromptr);
0230         return (u32)-EINVAL;
0231     }
0232 
0233     addrl = ent & SCAN_ADDR_ADDR;
0234     if (ent & SCAN_ADDR_AG32)
0235         bcma_erom_get_ent(bus, eromptr);
0236 
0237     if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) {
0238         size = bcma_erom_get_ent(bus, eromptr);
0239         if (size & SCAN_SIZE_SG32)
0240             bcma_erom_get_ent(bus, eromptr);
0241     }
0242 
0243     return addrl;
0244 }
0245 
0246 static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
0247                            u16 index)
0248 {
0249     struct bcma_device *core;
0250 
0251     list_for_each_entry(core, &bus->cores, list) {
0252         if (core->core_index == index)
0253             return core;
0254     }
0255     return NULL;
0256 }
0257 
0258 static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 coreid)
0259 {
0260     struct bcma_device *core;
0261 
0262     list_for_each_entry_reverse(core, &bus->cores, list) {
0263         if (core->id.id == coreid)
0264             return core;
0265     }
0266     return NULL;
0267 }
0268 
0269 #define IS_ERR_VALUE_U32(x) ((x) >= (u32)-MAX_ERRNO)
0270 
0271 static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
0272                   struct bcma_device_id *match, int core_num,
0273                   struct bcma_device *core)
0274 {
0275     u32 tmp;
0276     u8 i, j, k;
0277     s32 cia, cib;
0278     u8 ports[2], wrappers[2];
0279 
0280     /* get CIs */
0281     cia = bcma_erom_get_ci(bus, eromptr);
0282     if (cia < 0) {
0283         bcma_erom_push_ent(eromptr);
0284         if (bcma_erom_is_end(bus, eromptr))
0285             return -ESPIPE;
0286         return -EILSEQ;
0287     }
0288     cib = bcma_erom_get_ci(bus, eromptr);
0289     if (cib < 0)
0290         return -EILSEQ;
0291 
0292     /* parse CIs */
0293     core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
0294     core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
0295     core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
0296     ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
0297     ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
0298     wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
0299     wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
0300     core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
0301 
0302     if (((core->id.manuf == BCMA_MANUF_ARM) &&
0303          (core->id.id == 0xFFF)) ||
0304         (ports[1] == 0)) {
0305         bcma_erom_skip_component(bus, eromptr);
0306         return -ENXIO;
0307     }
0308 
0309     /* check if component is a core at all */
0310     if (wrappers[0] + wrappers[1] == 0) {
0311         /* Some specific cores don't need wrappers */
0312         switch (core->id.id) {
0313         case BCMA_CORE_4706_MAC_GBIT_COMMON:
0314         case BCMA_CORE_NS_CHIPCOMMON_B:
0315         case BCMA_CORE_PMU:
0316         case BCMA_CORE_GCI:
0317         /* Not used yet: case BCMA_CORE_OOB_ROUTER: */
0318             break;
0319         default:
0320             bcma_erom_skip_component(bus, eromptr);
0321             return -ENXIO;
0322         }
0323     }
0324 
0325     if (bcma_erom_is_bridge(bus, eromptr)) {
0326         bcma_erom_skip_component(bus, eromptr);
0327         return -ENXIO;
0328     }
0329 
0330     if (bcma_find_core_by_index(bus, core_num)) {
0331         bcma_erom_skip_component(bus, eromptr);
0332         return -ENODEV;
0333     }
0334 
0335     if (match && ((match->manuf != BCMA_ANY_MANUF &&
0336           match->manuf != core->id.manuf) ||
0337          (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
0338          (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
0339          (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
0340         )) {
0341         bcma_erom_skip_component(bus, eromptr);
0342         return -ENODEV;
0343     }
0344 
0345     /* get & parse master ports */
0346     for (i = 0; i < ports[0]; i++) {
0347         s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
0348         if (mst_port_d < 0)
0349             return -EILSEQ;
0350     }
0351 
0352     /* First Slave Address Descriptor should be port 0:
0353      * the main register space for the core
0354      */
0355     tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
0356     if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
0357         /* Try again to see if it is a bridge */
0358         tmp = bcma_erom_get_addr_desc(bus, eromptr,
0359                           SCAN_ADDR_TYPE_BRIDGE, 0);
0360         if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
0361             return -EILSEQ;
0362         } else {
0363             bcma_info(bus, "Bridge found\n");
0364             return -ENXIO;
0365         }
0366     }
0367     core->addr = tmp;
0368 
0369     /* get & parse slave ports */
0370     k = 0;
0371     for (i = 0; i < ports[1]; i++) {
0372         for (j = 0; ; j++) {
0373             tmp = bcma_erom_get_addr_desc(bus, eromptr,
0374                 SCAN_ADDR_TYPE_SLAVE, i);
0375             if (IS_ERR_VALUE_U32(tmp)) {
0376                 /* no more entries for port _i_ */
0377                 /* pr_debug("erom: slave port %d "
0378                  * "has %d descriptors\n", i, j); */
0379                 break;
0380             } else if (k < ARRAY_SIZE(core->addr_s)) {
0381                 core->addr_s[k] = tmp;
0382                 k++;
0383             }
0384         }
0385     }
0386 
0387     /* get & parse master wrappers */
0388     for (i = 0; i < wrappers[0]; i++) {
0389         for (j = 0; ; j++) {
0390             tmp = bcma_erom_get_addr_desc(bus, eromptr,
0391                 SCAN_ADDR_TYPE_MWRAP, i);
0392             if (IS_ERR_VALUE_U32(tmp)) {
0393                 /* no more entries for port _i_ */
0394                 /* pr_debug("erom: master wrapper %d "
0395                  * "has %d descriptors\n", i, j); */
0396                 break;
0397             } else {
0398                 if (i == 0 && j == 0)
0399                     core->wrap = tmp;
0400             }
0401         }
0402     }
0403 
0404     /* get & parse slave wrappers */
0405     for (i = 0; i < wrappers[1]; i++) {
0406         u8 hack = (ports[1] == 1) ? 0 : 1;
0407         for (j = 0; ; j++) {
0408             tmp = bcma_erom_get_addr_desc(bus, eromptr,
0409                 SCAN_ADDR_TYPE_SWRAP, i + hack);
0410             if (IS_ERR_VALUE_U32(tmp)) {
0411                 /* no more entries for port _i_ */
0412                 /* pr_debug("erom: master wrapper %d "
0413                  * has %d descriptors\n", i, j); */
0414                 break;
0415             } else {
0416                 if (wrappers[0] == 0 && !i && !j)
0417                     core->wrap = tmp;
0418             }
0419         }
0420     }
0421     if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
0422         core->io_addr = ioremap(core->addr, BCMA_CORE_SIZE);
0423         if (!core->io_addr)
0424             return -ENOMEM;
0425         if (core->wrap) {
0426             core->io_wrap = ioremap(core->wrap,
0427                             BCMA_CORE_SIZE);
0428             if (!core->io_wrap) {
0429                 iounmap(core->io_addr);
0430                 return -ENOMEM;
0431             }
0432         }
0433     }
0434     return 0;
0435 }
0436 
0437 void bcma_detect_chip(struct bcma_bus *bus)
0438 {
0439     s32 tmp;
0440     struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
0441     char chip_id[8];
0442 
0443     bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
0444 
0445     tmp = bcma_scan_read32(bus, BCMA_CC_ID);
0446     chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
0447     chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
0448     chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
0449 
0450     snprintf(chip_id, ARRAY_SIZE(chip_id),
0451          (chipinfo->id > 0x9999) ? "%d" : "0x%04X", chipinfo->id);
0452     bcma_info(bus, "Found chip with id %s, rev 0x%02X and package 0x%02X\n",
0453           chip_id, chipinfo->rev, chipinfo->pkg);
0454 }
0455 
0456 int bcma_bus_scan(struct bcma_bus *bus)
0457 {
0458     u32 erombase;
0459     u32 __iomem *eromptr, *eromend;
0460 
0461     int err, core_num = 0;
0462 
0463     /* Skip if bus was already scanned (e.g. during early register) */
0464     if (bus->nr_cores)
0465         return 0;
0466 
0467     erombase = bcma_scan_read32(bus, BCMA_CC_EROM);
0468     if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
0469         eromptr = ioremap(erombase, BCMA_CORE_SIZE);
0470         if (!eromptr)
0471             return -ENOMEM;
0472     } else {
0473         eromptr = bus->mmio;
0474     }
0475 
0476     eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
0477 
0478     bcma_scan_switch_core(bus, erombase);
0479 
0480     while (eromptr < eromend) {
0481         struct bcma_device *other_core;
0482         struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
0483         if (!core) {
0484             err = -ENOMEM;
0485             goto out;
0486         }
0487         INIT_LIST_HEAD(&core->list);
0488         core->bus = bus;
0489 
0490         err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
0491         if (err < 0) {
0492             kfree(core);
0493             if (err == -ENODEV) {
0494                 core_num++;
0495                 continue;
0496             } else if (err == -ENXIO) {
0497                 continue;
0498             } else if (err == -ESPIPE) {
0499                 break;
0500             }
0501             goto out;
0502         }
0503 
0504         core->core_index = core_num++;
0505         bus->nr_cores++;
0506         other_core = bcma_find_core_reverse(bus, core->id.id);
0507         core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
0508         bcma_prepare_core(bus, core);
0509 
0510         bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
0511               core->core_index, bcma_device_name(&core->id),
0512               core->id.manuf, core->id.id, core->id.rev,
0513               core->id.class);
0514 
0515         list_add_tail(&core->list, &bus->cores);
0516     }
0517 
0518     err = 0;
0519 out:
0520     if (bus->hosttype == BCMA_HOSTTYPE_SOC)
0521         iounmap(eromptr);
0522 
0523     return err;
0524 }