bcma: add functions to scan cores needed on SoCs
authorHauke Mehrtens <hauke@hauke-m.de>
Fri, 22 Jul 2011 23:20:07 +0000 (01:20 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 8 Aug 2011 18:29:24 +0000 (14:29 -0400)
The chip common and mips core have to be setup early in the boot
process to get the cpu clock.
bcma_bus_early_register() gets pointers to some space to store the core
data and searches for the chip common and mips core and initializes
chip common. After that was done and the kernel is out of early boot we
just have to run bcma_bus_register() and it will search for the other
cores, initialize and register them.
The cores are getting the same numbers as before.

Acked-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Acked-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/bcma/bcma_private.h
drivers/bcma/driver_chipcommon.c
drivers/bcma/driver_pci.c
drivers/bcma/main.c
drivers/bcma/scan.c
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_chipcommon.h

index e02ff21835c90b960722ab6419fed6039f47c828..b97633d0d237ee4a5b7adcb4d3ed692d3b1abe0d 100644 (file)
@@ -15,9 +15,16 @@ struct bcma_bus;
 /* main.c */
 int bcma_bus_register(struct bcma_bus *bus);
 void bcma_bus_unregister(struct bcma_bus *bus);
+int __init bcma_bus_early_register(struct bcma_bus *bus,
+                                  struct bcma_device *core_cc,
+                                  struct bcma_device *core_mips);
 
 /* scan.c */
 int bcma_bus_scan(struct bcma_bus *bus);
+int __init bcma_bus_scan_early(struct bcma_bus *bus,
+                              struct bcma_device_id *match,
+                              struct bcma_device *core);
+void bcma_init_bus(struct bcma_bus *bus);
 
 /* sprom.c */
 int bcma_sprom_get(struct bcma_bus *bus);
index 851e05bc948afea6740d5b590e26c1320654c6a8..acca327db3de3df334575ec4c30e48e6edd7ea80 100644 (file)
@@ -26,6 +26,9 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
        u32 leddc_on = 10;
        u32 leddc_off = 90;
 
+       if (cc->setup_done)
+               return;
+
        if (cc->core->id.rev >= 11)
                cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
        cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
@@ -52,6 +55,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
                        ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
                         (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
        }
+
+       cc->setup_done = true;
 }
 
 /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
index 25f3ddf33823122433edfb6c1464598cc832acc5..4e082100fa9b3dbf005f553d1a15081d07ae6f31 100644 (file)
@@ -189,6 +189,9 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
 
 void bcma_core_pci_init(struct bcma_drv_pci *pc)
 {
+       if (pc->setup_done)
+               return;
+
        if (bcma_core_pci_is_in_hostmode(pc)) {
 #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
                bcma_core_pci_hostmode_init(pc);
@@ -198,6 +201,8 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc)
        } else {
                bcma_core_pci_clientmode_init(pc);
        }
+
+       pc->setup_done = true;
 }
 
 int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
index 873e2e4ac55f01795a3b174b103ce0960c484bc2..360a289738fcbc29c6765f7a1b2c8f4751749516 100644 (file)
@@ -169,6 +169,52 @@ void bcma_bus_unregister(struct bcma_bus *bus)
        bcma_unregister_cores(bus);
 }
 
+int __init bcma_bus_early_register(struct bcma_bus *bus,
+                                  struct bcma_device *core_cc,
+                                  struct bcma_device *core_mips)
+{
+       int err;
+       struct bcma_device *core;
+       struct bcma_device_id match;
+
+       bcma_init_bus(bus);
+
+       match.manuf = BCMA_MANUF_BCM;
+       match.id = BCMA_CORE_CHIPCOMMON;
+       match.class = BCMA_CL_SIM;
+       match.rev = BCMA_ANY_REV;
+
+       /* Scan for chip common core */
+       err = bcma_bus_scan_early(bus, &match, core_cc);
+       if (err) {
+               pr_err("Failed to scan for common core: %d\n", err);
+               return -1;
+       }
+
+       match.manuf = BCMA_MANUF_MIPS;
+       match.id = BCMA_CORE_MIPS_74K;
+       match.class = BCMA_CL_SIM;
+       match.rev = BCMA_ANY_REV;
+
+       /* Scan for mips core */
+       err = bcma_bus_scan_early(bus, &match, core_mips);
+       if (err) {
+               pr_err("Failed to scan for mips core: %d\n", err);
+               return -1;
+       }
+
+       /* Init CC core */
+       core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
+       if (core) {
+               bus->drv_cc.core = core;
+               bcma_core_chipcommon_init(&bus->drv_cc);
+       }
+
+       pr_info("Early bus registered\n");
+
+       return 0;
+}
+
 int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 {
        drv->drv.name = drv->name;
index 79705534217ee8fa8a354f1c56d35dd36f43426b..bf9f80652773a41f68ff429d5d9a784fd36fa492 100644 (file)
@@ -200,7 +200,20 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
        return addrl;
 }
 
+static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
+                                                  u16 index)
+{
+       struct bcma_device *core;
+
+       list_for_each_entry(core, &bus->cores, list) {
+               if (core->core_index == index)
+                       return core;
+       }
+       return NULL;
+}
+
 static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
+                             struct bcma_device_id *match, int core_num,
                              struct bcma_device *core)
 {
        s32 tmp;
@@ -251,6 +264,21 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                return -ENXIO;
        }
 
+       if (bcma_find_core_by_index(bus, core_num)) {
+               bcma_erom_skip_component(bus, eromptr);
+               return -ENODEV;
+       }
+
+       if (match && ((match->manuf != BCMA_ANY_MANUF &&
+             match->manuf != core->id.manuf) ||
+            (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
+            (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
+            (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
+           )) {
+               bcma_erom_skip_component(bus, eromptr);
+               return -ENODEV;
+       }
+
        /* get & parse master ports */
        for (i = 0; i < ports[0]; i++) {
                u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
@@ -312,10 +340,13 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
        return 0;
 }
 
-static void bcma_init_bus(struct bcma_bus *bus)
+void bcma_init_bus(struct bcma_bus *bus)
 {
        s32 tmp;
 
+       if (bus->init_done)
+               return;
+
        INIT_LIST_HEAD(&bus->cores);
        bus->nr_cores = 0;
 
@@ -325,6 +356,7 @@ static void bcma_init_bus(struct bcma_bus *bus)
        bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
        bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
        bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+       bus->init_done = true;
 }
 
 int bcma_bus_scan(struct bcma_bus *bus)
@@ -332,7 +364,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
        u32 erombase;
        u32 __iomem *eromptr, *eromend;
 
-       int err;
+       int err, core_num = 0;
 
        bcma_init_bus(bus);
 
@@ -349,23 +381,74 @@ int bcma_bus_scan(struct bcma_bus *bus)
                INIT_LIST_HEAD(&core->list);
                core->bus = bus;
 
-               err = bcma_get_next_core(bus, &eromptr, core);
-               if (err == -ENXIO)
+               err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
+               if (err == -ENODEV) {
+                       core_num++;
+                       continue;
+               } else if (err == -ENXIO)
                        continue;
                else if (err == -ESPIPE)
                        break;
                else if (err < 0)
                        return err;
 
+               core->core_index = core_num++;
+               bus->nr_cores++;
+
                pr_info("Core %d found: %s "
                        "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-                       bus->nr_cores, bcma_device_name(&core->id),
+                       core->core_index, bcma_device_name(&core->id),
                        core->id.manuf, core->id.id, core->id.rev,
                        core->id.class);
 
-               core->core_index = bus->nr_cores++;
                list_add(&core->list, &bus->cores);
        }
 
        return 0;
 }
+
+int __init bcma_bus_scan_early(struct bcma_bus *bus,
+                              struct bcma_device_id *match,
+                              struct bcma_device *core)
+{
+       u32 erombase;
+       u32 __iomem *eromptr, *eromend;
+
+       int err, core_num = 0;
+
+       erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+       eromptr = bus->mmio;
+       eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
+
+       bcma_scan_switch_core(bus, erombase);
+
+       while (eromptr < eromend) {
+               memset(core, 0, sizeof(*core));
+               INIT_LIST_HEAD(&core->list);
+               core->bus = bus;
+
+               err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
+               if (err == -ENODEV) {
+                       core_num++;
+                       continue;
+               } else if (err == -ENXIO)
+                       continue;
+               else if (err == -ESPIPE)
+                       break;
+               else if (err < 0)
+                       return err;
+
+               core->core_index = core_num++;
+               bus->nr_cores++;
+               pr_info("Core %d found: %s "
+                       "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+                       core->core_index, bcma_device_name(&core->id),
+                       core->id.manuf, core->id.id, core->id.rev,
+                       core->id.class);
+
+               list_add(&core->list, &bus->cores);
+               return 0;
+       }
+
+       return -ENODEV;
+}
index 8c96654bef16bb8cba98267f2f0e1a42e13e47bc..e31c9b46222138582ffc8797c3e2395905a970bb 100644 (file)
@@ -190,6 +190,7 @@ struct bcma_bus {
        struct bcma_device *mapped_core;
        struct list_head cores;
        u8 nr_cores;
+       u8 init_done:1;
 
        struct bcma_drv_cc drv_cc;
        struct bcma_drv_pci drv_pci;
index a0f684615ae561a6c1cc241808512655533ee420..c8b4cf7f9faef045f9730ea235652fb4f6bd8241 100644 (file)
@@ -252,6 +252,7 @@ struct bcma_drv_cc {
        u32 status;
        u32 capabilities;
        u32 capabilities_ext;
+       u8 setup_done:1;
        /* Fast Powerup Delay constant */
        u16 fast_pwrup_delay;
        struct bcma_chipcommon_pmu pmu;