--- /dev/null
+--- a/Documentation/feature-removal-schedule.txt
++++ b/Documentation/feature-removal-schedule.txt
+@@ -551,3 +551,15 @@ When: 3.5
+ Why: The iwlagn module has been renamed iwlwifi. The alias will be around
+ for backward compatibility for several cycles and then dropped.
+ Who: Don Fry <donald.h.fry@intel.com>
++
++----------------------------
++
++What: pci_scan_bus_parented()
++When: 3.5
++Why: The pci_scan_bus_parented() interface creates a new root bus. The
++ bus is created with default resources (ioport_resource and
++ iomem_resource) that are always wrong, so we rely on arch code to
++ correct them later. Callers of pci_scan_bus_parented() should
++ convert to using pci_scan_root_bus() so they can supply a list of
++ bus resources when the bus is created.
++Who: Bjorn Helgaas <bhelgaas@google.com>
+--- a/arch/alpha/kernel/pci.c
++++ b/arch/alpha/kernel/pci.c
+@@ -281,27 +281,9 @@ pcibios_fixup_device_resources(struct pc
+ void __devinit
+ pcibios_fixup_bus(struct pci_bus *bus)
+ {
+- /* Propagate hose info into the subordinate devices. */
+-
+- struct pci_controller *hose = bus->sysdata;
+ struct pci_dev *dev = bus->self;
+
+- if (!dev) {
+- /* Root bus. */
+- u32 pci_mem_end;
+- u32 sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;
+- unsigned long end;
+-
+- bus->resource[0] = hose->io_space;
+- bus->resource[1] = hose->mem_space;
+-
+- /* Adjust hose mem_space limit to prevent PCI allocations
+- in the iommu windows. */
+- pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
+- end = hose->mem_space->start + pci_mem_end;
+- if (hose->mem_space->end > end)
+- hose->mem_space->end = end;
+- } else if (pci_probe_only &&
++ if (pci_probe_only && dev &&
+ (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ pci_read_bridge_bases(bus);
+ pcibios_fixup_device_resources(dev, bus);
+@@ -414,13 +396,31 @@ void __init
+ common_init_pci(void)
+ {
+ struct pci_controller *hose;
++ struct list_head resources;
+ struct pci_bus *bus;
+ int next_busno;
+ int need_domain_info = 0;
++ u32 pci_mem_end;
++ u32 sg_base;
++ unsigned long end;
+
+ /* Scan all of the recorded PCI controllers. */
+ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
+- bus = pci_scan_bus(next_busno, alpha_mv.pci_ops, hose);
++ sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;
++
++ /* Adjust hose mem_space limit to prevent PCI allocations
++ in the iommu windows. */
++ pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
++ end = hose->mem_space->start + pci_mem_end;
++ if (hose->mem_space->end > end)
++ hose->mem_space->end = end;
++
++ INIT_LIST_HEAD(&resources);
++ pci_add_resource(&resources, hose->io_space);
++ pci_add_resource(&resources, hose->mem_space);
++
++ bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
++ hose, &resources);
+ hose->bus = bus;
+ hose->need_domain_info = need_domain_info;
+ next_busno = bus->subordinate + 1;
+--- a/arch/arm/common/it8152.c
++++ b/arch/arm/common/it8152.c
+@@ -299,8 +299,8 @@ int __init it8152_pci_setup(int nr, stru
+ goto err1;
+ }
+
+- sys->resource[0] = &it8152_io;
+- sys->resource[1] = &it8152_mem;
++ pci_add_resource(&sys->resources, &it8152_io);
++ pci_add_resource(&sys->resources, &it8152_mem);
+
+ if (platform_notify || platform_notify_remove) {
+ printk(KERN_ERR "PCI: Can't use platform_notify\n");
+@@ -352,7 +352,7 @@ void pcibios_set_master(struct pci_dev *
+
+ struct pci_bus * __init it8152_pci_scan_bus(int nr, struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(nr, &it8152_ops, sys);
++ return pci_scan_root_bus(NULL, nr, &it8152_ops, sys, &sys->resources);
+ }
+
+ EXPORT_SYMBOL(dma_set_coherent_mask);
+--- a/arch/arm/common/via82c505.c
++++ b/arch/arm/common/via82c505.c
+@@ -86,7 +86,8 @@ int __init via82c505_setup(int nr, struc
+ struct pci_bus * __init via82c505_scan_bus(int nr, struct pci_sys_data *sysdata)
+ {
+ if (nr == 0)
+- return pci_scan_bus(0, &via82c505_ops, sysdata);
++ return pci_scan_root_bus(NULL, 0, &via82c505_ops, sysdata,
++ &sysdata->resources);
+
+ return NULL;
+ }
+--- a/arch/arm/include/asm/mach/pci.h
++++ b/arch/arm/include/asm/mach/pci.h
+@@ -40,7 +40,7 @@ struct pci_sys_data {
+ u64 mem_offset; /* bus->cpu memory mapping offset */
+ unsigned long io_offset; /* bus->cpu IO mapping offset */
+ struct pci_bus *bus; /* PCI bus */
+- struct resource *resource[3]; /* Primary PCI bus resources */
++ struct list_head resources; /* root bus resources (apertures) */
+ /* Bridge swizzling */
+ u8 (*swizzle)(struct pci_dev *, u8 *);
+ /* IRQ mapping */
+--- a/arch/arm/kernel/bios32.c
++++ b/arch/arm/kernel/bios32.c
+@@ -316,21 +316,6 @@ pdev_fixup_device_resources(struct pci_s
+ }
+ }
+
+-static void __devinit
+-pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root)
+-{
+- struct pci_dev *dev = bus->self;
+- int i;
+-
+- if (!dev) {
+- /*
+- * Assign root bus resources.
+- */
+- for (i = 0; i < 3; i++)
+- bus->resource[i] = root->resource[i];
+- }
+-}
+-
+ /*
+ * pcibios_fixup_bus - Called after each bus is probed,
+ * but before its children are examined.
+@@ -341,8 +326,6 @@ void pcibios_fixup_bus(struct pci_bus *b
+ struct pci_dev *dev;
+ u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK;
+
+- pbus_assign_bus_resources(bus, root);
+-
+ /*
+ * Walk the devices on this bus, working out what we can
+ * and can't support.
+@@ -508,12 +491,18 @@ static void __init pcibios_init_hw(struc
+ sys->busnr = busnr;
+ sys->swizzle = hw->swizzle;
+ sys->map_irq = hw->map_irq;
+- sys->resource[0] = &ioport_resource;
+- sys->resource[1] = &iomem_resource;
++ INIT_LIST_HEAD(&sys->resources);
+
+ ret = hw->setup(nr, sys);
+
+ if (ret > 0) {
++ if (list_empty(&sys->resources)) {
++ pci_add_resource(&sys->resources,
++ &ioport_resource);
++ pci_add_resource(&sys->resources,
++ &iomem_resource);
++ }
++
+ sys->bus = hw->scan(nr, sys);
+
+ if (!sys->bus)
+--- a/arch/arm/mach-cns3xxx/pcie.c
++++ b/arch/arm/mach-cns3xxx/pcie.c
+@@ -151,13 +151,12 @@ static int cns3xxx_pci_setup(int nr, str
+ struct cns3xxx_pcie *cnspci = sysdata_to_cnspci(sys);
+ struct resource *res_io = &cnspci->res_io;
+ struct resource *res_mem = &cnspci->res_mem;
+- struct resource **sysres = sys->resource;
+
+ BUG_ON(request_resource(&iomem_resource, res_io) ||
+ request_resource(&iomem_resource, res_mem));
+
+- sysres[0] = res_io;
+- sysres[1] = res_mem;
++ pci_add_resource(&sys->resources, res_io);
++ pci_add_resource(&sys->resources, res_mem);
+
+ return 1;
+ }
+@@ -169,7 +168,8 @@ static struct pci_ops cns3xxx_pcie_ops =
+
+ static struct pci_bus *cns3xxx_pci_scan_bus(int nr, struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(sys->busnr, &cns3xxx_pcie_ops, sys);
++ return pci_scan_root_bus(NULL, sys->busnr, &cns3xxx_pcie_ops, sys,
++ &sys->resources);
+ }
+
+ static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+--- a/arch/arm/mach-dove/pcie.c
++++ b/arch/arm/mach-dove/pcie.c
+@@ -69,7 +69,7 @@ static int __init dove_pcie_setup(int nr
+ pp->res[0].flags = IORESOURCE_IO;
+ if (request_resource(&ioport_resource, &pp->res[0]))
+ panic("Request PCIe IO resource failed\n");
+- sys->resource[0] = &pp->res[0];
++ pci_add_resource(&sys->resources, &pp->res[0]);
+
+ /*
+ * IORESOURCE_MEM
+@@ -88,9 +88,7 @@ static int __init dove_pcie_setup(int nr
+ pp->res[1].flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource, &pp->res[1]))
+ panic("Request PCIe Memory resource failed\n");
+- sys->resource[1] = &pp->res[1];
+-
+- sys->resource[2] = NULL;
++ pci_add_resource(&sys->resources, &pp->res[1]);
+
+ return 1;
+ }
+@@ -184,7 +182,8 @@ dove_pcie_scan_bus(int nr, struct pci_sy
+ struct pci_bus *bus;
+
+ if (nr < num_pcie_ports) {
+- bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
++ bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
++ &sys->resources);
+ } else {
+ bus = NULL;
+ BUG();
+--- a/arch/arm/mach-footbridge/dc21285.c
++++ b/arch/arm/mach-footbridge/dc21285.c
+@@ -275,9 +275,9 @@ int __init dc21285_setup(int nr, struct
+ allocate_resource(&iomem_resource, &res[0], 0x40000000,
+ 0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
+
+- sys->resource[0] = &ioport_resource;
+- sys->resource[1] = &res[0];
+- sys->resource[2] = &res[1];
++ pci_add_resource(&sys->resources, &ioport_resource);
++ pci_add_resource(&sys->resources, &res[0]);
++ pci_add_resource(&sys->resources, &res[1]);
+ sys->mem_offset = DC21285_PCI_MEM;
+
+ return 1;
+@@ -285,7 +285,7 @@ int __init dc21285_setup(int nr, struct
+
+ struct pci_bus * __init dc21285_scan_bus(int nr, struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(0, &dc21285_ops, sys);
++ return pci_scan_root_bus(NULL, 0, &dc21285_ops, sys, &sys->resources);
+ }
+
+ #define dc21285_request_irq(_a, _b, _c, _d, _e) \
+--- a/arch/arm/mach-integrator/pci_v3.c
++++ b/arch/arm/mach-integrator/pci_v3.c
+@@ -359,7 +359,7 @@ static struct resource pre_mem = {
+ .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH,
+ };
+
+-static int __init pci_v3_setup_resources(struct resource **resource)
++static int __init pci_v3_setup_resources(struct pci_sys_data *sys)
+ {
+ if (request_resource(&iomem_resource, &non_mem)) {
+ printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
+@@ -374,13 +374,13 @@ static int __init pci_v3_setup_resources
+ }
+
+ /*
+- * bus->resource[0] is the IO resource for this bus
+- * bus->resource[1] is the mem resource for this bus
+- * bus->resource[2] is the prefetch mem resource for this bus
++ * the IO resource for this bus
++ * the mem resource for this bus
++ * the prefetch mem resource for this bus
+ */
+- resource[0] = &ioport_resource;
+- resource[1] = &non_mem;
+- resource[2] = &pre_mem;
++ pci_add_resource(&sys->resources, &ioport_resource);
++ pci_add_resource(&sys->resources, &non_mem);
++ pci_add_resource(&sys->resources, &pre_mem);
+
+ return 1;
+ }
+@@ -481,7 +481,7 @@ int __init pci_v3_setup(int nr, struct p
+
+ if (nr == 0) {
+ sys->mem_offset = PHYS_PCI_MEM_BASE;
+- ret = pci_v3_setup_resources(sys->resource);
++ ret = pci_v3_setup_resources(sys);
+ }
+
+ return ret;
+@@ -489,7 +489,8 @@ int __init pci_v3_setup(int nr, struct p
+
+ struct pci_bus * __init pci_v3_scan_bus(int nr, struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(sys->busnr, &pci_v3_ops, sys);
++ return pci_scan_root_bus(NULL, sys->busnr, &pci_v3_ops, sys,
++ &sys->resources);
+ }
+
+ /*
+--- a/arch/arm/mach-iop13xx/pci.c
++++ b/arch/arm/mach-iop13xx/pci.c
+@@ -537,14 +537,14 @@ struct pci_bus *iop13xx_scan_bus(int nr,
+ while(time_before(jiffies, atux_trhfa_timeout))
+ udelay(100);
+
+- bus = pci_bus_atux = pci_scan_bus(sys->busnr,
+- &iop13xx_atux_ops,
+- sys);
++ bus = pci_bus_atux = pci_scan_root_bus(NULL, sys->busnr,
++ &iop13xx_atux_ops,
++ sys, &sys->resources);
+ break;
+ case IOP13XX_INIT_ATU_ATUE:
+- bus = pci_bus_atue = pci_scan_bus(sys->busnr,
+- &iop13xx_atue_ops,
+- sys);
++ bus = pci_bus_atue = pci_scan_root_bus(NULL, sys->busnr,
++ &iop13xx_atue_ops,
++ sys, &sys->resources);
+ break;
+ }
+
+@@ -1084,9 +1084,8 @@ int iop13xx_pci_setup(int nr, struct pci
+ request_resource(&ioport_resource, &res[0]);
+ request_resource(&iomem_resource, &res[1]);
+
+- sys->resource[0] = &res[0];
+- sys->resource[1] = &res[1];
+- sys->resource[2] = NULL;
++ pci_add_resource(&sys->resources, &res[0]);
++ pci_add_resource(&sys->resources, &res[1]);
+
+ return 1;
+ }
+--- a/arch/arm/mach-ixp2000/enp2611.c
++++ b/arch/arm/mach-ixp2000/enp2611.c
+@@ -145,7 +145,8 @@ static struct pci_ops enp2611_pci_ops =
+ static struct pci_bus * __init enp2611_pci_scan_bus(int nr,
+ struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(sys->busnr, &enp2611_pci_ops, sys);
++ return pci_scan_root_bus(NULL, sys->busnr, &enp2611_pci_ops, sys,
++ &sys->resources);
+ }
+
+ static int __init enp2611_pci_map_irq(const struct pci_dev *dev, u8 slot,
+--- a/arch/arm/mach-ixp2000/pci.c
++++ b/arch/arm/mach-ixp2000/pci.c
+@@ -132,7 +132,8 @@ static struct pci_ops ixp2000_pci_ops =
+
+ struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
+ {
+- return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata);
++ return pci_scan_root_bus(NULL, sysdata->busnr, &ixp2000_pci_ops,
++ sysdata, &sysdata->resources);
+ }
+
+
+@@ -242,9 +243,8 @@ int ixp2000_pci_setup(int nr, struct pci
+ if (nr >= 1)
+ return 0;
+
+- sys->resource[0] = &ixp2000_pci_io_space;
+- sys->resource[1] = &ixp2000_pci_mem_space;
+- sys->resource[2] = NULL;
++ pci_add_resource(&sys->resources, &ixp2000_pci_io_space);
++ pci_add_resource(&sys->resources, &ixp2000_pci_mem_space);
+
+ return 1;
+ }
+--- a/arch/arm/mach-ixp23xx/pci.c
++++ b/arch/arm/mach-ixp23xx/pci.c
+@@ -143,7 +143,8 @@ struct pci_ops ixp23xx_pci_ops = {
+
+ struct pci_bus *ixp23xx_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
+ {
+- return pci_scan_bus(sysdata->busnr, &ixp23xx_pci_ops, sysdata);
++ return pci_scan_root_bus(NULL, sysdata->busnr, &ixp23xx_pci_ops,
++ sysdata, &sysdata->resources);
+ }
+
+ int ixp23xx_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+@@ -280,9 +281,8 @@ int ixp23xx_pci_setup(int nr, struct pci
+ if (nr >= 1)
+ return 0;
+
+- sys->resource[0] = &ixp23xx_pci_io_space;
+- sys->resource[1] = &ixp23xx_pci_mem_space;
+- sys->resource[2] = NULL;
++ pci_add_resource(&sys->resources, &ixp23xx_pci_io_space);
++ pci_add_resource(&sys->resources, &ixp23xx_pci_mem_space);
+
+ return 1;
+ }
+--- a/arch/arm/mach-ixp4xx/common-pci.c
++++ b/arch/arm/mach-ixp4xx/common-pci.c
+@@ -472,9 +472,8 @@ int ixp4xx_setup(int nr, struct pci_sys_
+ request_resource(&ioport_resource, &res[0]);
+ request_resource(&iomem_resource, &res[1]);
+
+- sys->resource[0] = &res[0];
+- sys->resource[1] = &res[1];
+- sys->resource[2] = NULL;
++ pci_add_resource(&sys->resources, &res[0]);
++ pci_add_resource(&sys->resources, &res[1]);
+
+ platform_notify = ixp4xx_pci_platform_notify;
+ platform_notify_remove = ixp4xx_pci_platform_notify_remove;
+@@ -484,7 +483,8 @@ int ixp4xx_setup(int nr, struct pci_sys_
+
+ struct pci_bus * __devinit ixp4xx_scan_bus(int nr, struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(sys->busnr, &ixp4xx_ops, sys);
++ return pci_scan_root_bus(NULL, sys->busnr, &ixp4xx_ops, sys,
++ &sys->resources);
+ }
+
+ int dma_set_coherent_mask(struct device *dev, u64 mask)
+--- a/arch/arm/mach-kirkwood/pcie.c
++++ b/arch/arm/mach-kirkwood/pcie.c
+@@ -198,9 +198,8 @@ static int __init kirkwood_pcie_setup(in
+ if (request_resource(&iomem_resource, &pp->res[1]))
+ panic("Request PCIe%d Memory resource failed\n", index);
+
+- sys->resource[0] = &pp->res[0];
+- sys->resource[1] = &pp->res[1];
+- sys->resource[2] = NULL;
++ pci_add_resource(&sys->resources, &pp->res[0]);
++ pci_add_resource(&sys->resources, &pp->res[1]);
+ sys->io_offset = 0;
+
+ /*
+@@ -236,7 +235,8 @@ kirkwood_pcie_scan_bus(int nr, struct pc
+ struct pci_bus *bus;
+
+ if (nr < num_pcie_ports) {
+- bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
++ bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
++ &sys->resources);
+ } else {
+ bus = NULL;
+ BUG();
+--- a/arch/arm/mach-ks8695/pci.c
++++ b/arch/arm/mach-ks8695/pci.c
+@@ -143,7 +143,8 @@ static struct pci_ops ks8695_pci_ops = {
+
+ static struct pci_bus* __init ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(sys->busnr, &ks8695_pci_ops, sys);
++ return pci_scan_root_bus(NULL, sys->busnr, &ks8695_pci_ops, sys,
++ &sys->resources);
+ }
+
+ static struct resource pci_mem = {
+@@ -168,9 +169,8 @@ static int __init ks8695_pci_setup(int n
+ request_resource(&iomem_resource, &pci_mem);
+ request_resource(&ioport_resource, &pci_io);
+
+- sys->resource[0] = &pci_io;
+- sys->resource[1] = &pci_mem;
+- sys->resource[2] = NULL;
++ pci_add_resource(&sys->resources, &pci_io);
++ pci_add_resource(&sys->resources, &pci_mem);
+
+ /* Assign and enable processor bridge */
+ ks8695_local_writeconfig(PCI_BASE_ADDRESS_0, KS8695_PCIMEM_PA);
+--- a/arch/arm/mach-mv78xx0/pcie.c
++++ b/arch/arm/mach-mv78xx0/pcie.c
+@@ -155,9 +155,8 @@ static int __init mv78xx0_pcie_setup(int
+ orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
+ orion_pcie_setup(pp->base, &mv78xx0_mbus_dram_info);
+
+- sys->resource[0] = &pp->res[0];
+- sys->resource[1] = &pp->res[1];
+- sys->resource[2] = NULL;
++ pci_add_resource(&sys->resources, &pp->res[0]);
++ pci_add_resource(&sys->resources, &pp->res[1]);
+
+ return 1;
+ }
+@@ -251,7 +250,8 @@ mv78xx0_pcie_scan_bus(int nr, struct pci
+ struct pci_bus *bus;
+
+ if (nr < num_pcie_ports) {
+- bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
++ bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
++ &sys->resources);
+ } else {
+ bus = NULL;
+ BUG();
+--- a/arch/arm/mach-orion5x/pci.c
++++ b/arch/arm/mach-orion5x/pci.c
+@@ -176,7 +176,7 @@ static int __init pcie_setup(struct pci_
+ res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1;
+ if (request_resource(&ioport_resource, &res[0]))
+ panic("Request PCIe IO resource failed\n");
+- sys->resource[0] = &res[0];
++ pci_add_resource(&sys->resources, &res[0]);
+
+ /*
+ * IORESOURCE_MEM
+@@ -187,9 +187,8 @@ static int __init pcie_setup(struct pci_
+ res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1;
+ if (request_resource(&iomem_resource, &res[1]))
+ panic("Request PCIe Memory resource failed\n");
+- sys->resource[1] = &res[1];
++ pci_add_resource(&sys->resources, &res[1]);
+
+- sys->resource[2] = NULL;
+ sys->io_offset = 0;
+
+ return 1;
+@@ -505,7 +504,7 @@ static int __init pci_setup(struct pci_s
+ res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1;
+ if (request_resource(&ioport_resource, &res[0]))
+ panic("Request PCI IO resource failed\n");
+- sys->resource[0] = &res[0];
++ pci_add_resource(&sys->resources, &res[0]);
+
+ /*
+ * IORESOURCE_MEM
+@@ -516,9 +515,8 @@ static int __init pci_setup(struct pci_s
+ res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1;
+ if (request_resource(&iomem_resource, &res[1]))
+ panic("Request PCI Memory resource failed\n");
+- sys->resource[1] = &res[1];
++ pci_add_resource(&sys->resources, &res[1]);
+
+- sys->resource[2] = NULL;
+ sys->io_offset = 0;
+
+ return 1;
+@@ -579,9 +577,11 @@ struct pci_bus __init *orion5x_pci_sys_s
+ struct pci_bus *bus;
+
+ if (nr == 0) {
+- bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
++ bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
++ &sys->resources);
+ } else if (nr == 1 && !orion5x_pci_disabled) {
+- bus = pci_scan_bus(sys->busnr, &pci_ops, sys);
++ bus = pci_scan_root_bus(NULL, sys->busnr, &pci_ops, sys,
++ &sys->resources);
+ } else {
+ bus = NULL;
+ BUG();
+--- a/arch/arm/mach-sa1100/pci-nanoengine.c
++++ b/arch/arm/mach-sa1100/pci-nanoengine.c
+@@ -131,7 +131,8 @@ static int __init pci_nanoengine_map_irq
+
+ struct pci_bus * __init pci_nanoengine_scan_bus(int nr, struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(sys->busnr, &pci_nano_ops, sys);
++ return pci_scan_root_bus(NULL, sys->busnr, &pci_nano_ops, sys,
++ &sys->resources);
+ }
+
+ static struct resource pci_io_ports = {
+@@ -226,7 +227,7 @@ static struct resource pci_prefetchable_
+ .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH,
+ };
+
+-static int __init pci_nanoengine_setup_resources(struct resource **resource)
++static int __init pci_nanoengine_setup_resources(struct pci_sys_data *sys)
+ {
+ if (request_resource(&ioport_resource, &pci_io_ports)) {
+ printk(KERN_ERR "PCI: unable to allocate io port region\n");
+@@ -243,9 +244,9 @@ static int __init pci_nanoengine_setup_r
+ printk(KERN_ERR "PCI: unable to allocate prefetchable\n");
+ return -EBUSY;
+ }
+- resource[0] = &pci_io_ports;
+- resource[1] = &pci_non_prefetchable_memory;
+- resource[2] = &pci_prefetchable_memory;
++ pci_add_resource(&sys->resources, &pci_io_ports);
++ pci_add_resource(&sys->resources, &pci_non_prefetchable_memory);
++ pci_add_resource(&sys->resources, &pci_prefetchable_memory);
+
+ return 1;
+ }
+@@ -260,7 +261,7 @@ int __init pci_nanoengine_setup(int nr,
+ if (nr == 0) {
+ sys->mem_offset = NANO_PCI_MEM_RW_PHYS;
+ sys->io_offset = 0x400;
+- ret = pci_nanoengine_setup_resources(sys->resource);
++ ret = pci_nanoengine_setup_resources(sys);
+ /* Enable alternate memory bus master mode, see
+ * "Intel StrongARM SA1110 Developer's Manual",
+ * section 10.8, "Alternate Memory Bus Master Mode". */
+--- a/arch/arm/mach-tegra/pcie.c
++++ b/arch/arm/mach-tegra/pcie.c
+@@ -409,7 +409,7 @@ static int tegra_pcie_setup(int nr, stru
+ pp->res[0].flags = IORESOURCE_IO;
+ if (request_resource(&ioport_resource, &pp->res[0]))
+ panic("Request PCIe IO resource failed\n");
+- sys->resource[0] = &pp->res[0];
++ pci_add_resource(&sys->resources, &pp->res[0]);
+
+ /*
+ * IORESOURCE_MEM
+@@ -428,7 +428,7 @@ static int tegra_pcie_setup(int nr, stru
+ pp->res[1].flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource, &pp->res[1]))
+ panic("Request PCIe Memory resource failed\n");
+- sys->resource[1] = &pp->res[1];
++ pci_add_resource(&sys->resources, &pp->res[1]);
+
+ /*
+ * IORESOURCE_MEM | IORESOURCE_PREFETCH
+@@ -447,7 +447,7 @@ static int tegra_pcie_setup(int nr, stru
+ pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+ if (request_resource(&iomem_resource, &pp->res[2]))
+ panic("Request PCIe Prefetch Memory resource failed\n");
+- sys->resource[2] = &pp->res[2];
++ pci_add_resource(&sys->resources, &pp->res[2]);
+
+ return 1;
+ }
+@@ -468,7 +468,8 @@ static struct pci_bus __init *tegra_pcie
+ pp = tegra_pcie.port + nr;
+ pp->root_bus_nr = sys->busnr;
+
+- return pci_scan_bus(sys->busnr, &tegra_pcie_ops, sys);
++ return pci_scan_root_bus(NULL, sys->busnr, &tegra_pcie_ops, sys,
++ &sys->resources);
+ }
+
+ static struct hw_pci tegra_pcie_hw __initdata = {
+--- a/arch/arm/mach-versatile/pci.c
++++ b/arch/arm/mach-versatile/pci.c
+@@ -191,7 +191,7 @@ static struct resource pre_mem = {
+ .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH,
+ };
+
+-static int __init pci_versatile_setup_resources(struct resource **resource)
++static int __init pci_versatile_setup_resources(struct list_head *resources)
+ {
+ int ret = 0;
+
+@@ -215,13 +215,13 @@ static int __init pci_versatile_setup_re
+ }
+
+ /*
+- * bus->resource[0] is the IO resource for this bus
+- * bus->resource[1] is the mem resource for this bus
+- * bus->resource[2] is the prefetch mem resource for this bus
++ * the IO resource for this bus
++ * the mem resource for this bus
++ * the prefetch mem resource for this bus
+ */
+- resource[0] = &io_mem;
+- resource[1] = &non_mem;
+- resource[2] = &pre_mem;
++ pci_add_resource(resources, &io_mem);
++ pci_add_resource(resources, &non_mem);
++ pci_add_resource(resources, &pre_mem);
+
+ goto out;
+
+@@ -250,7 +250,7 @@ int __init pci_versatile_setup(int nr, s
+
+ if (nr == 0) {
+ sys->mem_offset = 0;
+- ret = pci_versatile_setup_resources(sys->resource);
++ ret = pci_versatile_setup_resources(&sys->resources);
+ if (ret < 0) {
+ printk("pci_versatile_setup: resources... oops?\n");
+ goto out;
+@@ -306,7 +306,8 @@ int __init pci_versatile_setup(int nr, s
+
+ struct pci_bus * __init pci_versatile_scan_bus(int nr, struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys);
++ return pci_scan_root_bus(NULL, sys->busnr, &pci_versatile_ops, sys,
++ &sys->resources);
+ }
+
+ void __init pci_versatile_preinit(void)
+--- a/arch/arm/plat-iop/pci.c
++++ b/arch/arm/plat-iop/pci.c
+@@ -215,16 +215,16 @@ int iop3xx_pci_setup(int nr, struct pci_
+ sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
+ sys->io_offset = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR;
+
+- sys->resource[0] = &res[0];
+- sys->resource[1] = &res[1];
+- sys->resource[2] = NULL;
++ pci_add_resource(&sys->resources, &res[0]);
++ pci_add_resource(&sys->resources, &res[1]);
+
+ return 1;
+ }
+
+ struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys)
+ {
+- return pci_scan_bus(sys->busnr, &iop3xx_ops, sys);
++ return pci_scan_root_bus(NULL, sys->busnr, &iop3xx_ops, sys,
++ &sys->resources);
+ }
+
+ void __init iop3xx_atu_setup(void)
+--- a/arch/frv/mb93090-mb00/pci-vdk.c
++++ b/arch/frv/mb93090-mb00/pci-vdk.c
+@@ -327,11 +327,6 @@ void __init pcibios_fixup_bus(struct pci
+ printk("### PCIBIOS_FIXUP_BUS(%d)\n",bus->number);
+ #endif
+
+- if (bus->number == 0) {
+- bus->resource[0] = &pci_ioport_resource;
+- bus->resource[1] = &pci_iomem_resource;
+- }
+-
+ pci_read_bridge_bases(bus);
+
+ if (bus->number == 0) {
+@@ -357,6 +352,7 @@ void __init pcibios_fixup_bus(struct pci
+ int __init pcibios_init(void)
+ {
+ struct pci_ops *dir = NULL;
++ LIST_HEAD(resources);
+
+ if (!mb93090_mb00_detected)
+ return -ENXIO;
+@@ -420,7 +416,10 @@ int __init pcibios_init(void)
+ }
+
+ printk("PCI: Probing PCI hardware\n");
+- pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
++ pci_add_resource(&resources, &pci_ioport_resource);
++ pci_add_resource(&resources, &pci_iomem_resource);
++ pci_root_bus = pci_scan_root_bus(NULL, 0, pci_root_ops, NULL,
++ &resources);
+
+ pcibios_irq_init();
+ pcibios_fixup_peer_bridges();
+--- a/arch/ia64/pci/pci.c
++++ b/arch/ia64/pci/pci.c
+@@ -134,6 +134,7 @@ alloc_pci_controller (int seg)
+ struct pci_root_info {
+ struct acpi_device *bridge;
+ struct pci_controller *controller;
++ struct list_head resources;
+ char *name;
+ };
+
+@@ -315,24 +316,13 @@ static __devinit acpi_status add_window(
+ &window->resource);
+ }
+
+- return AE_OK;
+-}
++ /* HP's firmware has a hack to work around a Windows bug.
++ * Ignore these tiny memory ranges */
++ if (!((window->resource.flags & IORESOURCE_MEM) &&
++ (window->resource.end - window->resource.start < 16)))
++ pci_add_resource(&info->resources, &window->resource);
+
+-static void __devinit
+-pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
+-{
+- int i;
+-
+- pci_bus_remove_resources(bus);
+- for (i = 0; i < ctrl->windows; i++) {
+- struct resource *res = &ctrl->window[i].resource;
+- /* HP's firmware has a hack to work around a Windows bug.
+- * Ignore these tiny memory ranges */
+- if ((res->flags & IORESOURCE_MEM) &&
+- (res->end - res->start < 16))
+- continue;
+- pci_bus_add_resource(bus, res, 0);
+- }
++ return AE_OK;
+ }
+
+ struct pci_bus * __devinit
+@@ -343,6 +333,7 @@ pci_acpi_scan_root(struct acpi_pci_root
+ int bus = root->secondary.start;
+ struct pci_controller *controller;
+ unsigned int windows = 0;
++ struct pci_root_info info;
+ struct pci_bus *pbus;
+ char *name;
+ int pxm;
+@@ -359,11 +350,10 @@ pci_acpi_scan_root(struct acpi_pci_root
+ controller->node = pxm_to_node(pxm);
+ #endif
+
++ INIT_LIST_HEAD(&info.resources);
+ acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
+ &windows);
+ if (windows) {
+- struct pci_root_info info;
+-
+ controller->window =
+ kmalloc_node(sizeof(*controller->window) * windows,
+ GFP_KERNEL, controller->node);
+@@ -387,8 +377,14 @@ pci_acpi_scan_root(struct acpi_pci_root
+ * should handle the case here, but it appears that IA64 hasn't
+ * such quirk. So we just ignore the case now.
+ */
+- pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
++ pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller,
++ &info.resources);
++ if (!pbus) {
++ pci_free_resource_list(&info.resources);
++ return NULL;
++ }
+
++ pbus->subordinate = pci_scan_child_bus(pbus);
+ return pbus;
+
+ out3:
+@@ -504,14 +500,10 @@ pcibios_fixup_bus (struct pci_bus *b)
+ if (b->self) {
+ pci_read_bridge_bases(b);
+ pcibios_fixup_bridge_resources(b->self);
+- } else {
+- pcibios_setup_root_windows(b, b->sysdata);
+ }
+ list_for_each_entry(dev, &b->devices, bus_list)
+ pcibios_fixup_device_resources(dev);
+ platform_pci_fixup_bus(b);
+-
+- return;
+ }
+
+ void __devinit
+--- a/arch/microblaze/include/asm/pci-bridge.h
++++ b/arch/microblaze/include/asm/pci-bridge.h
+@@ -140,7 +140,6 @@ extern void pci_process_bridge_OF_ranges
+ /* Allocate & free a PCI host bridge structure */
+ extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
+ extern void pcibios_free_controller(struct pci_controller *phb);
+-extern void pcibios_setup_phb_resources(struct pci_controller *hose);
+
+ #endif /* __KERNEL__ */
+ #endif /* _ASM_MICROBLAZE_PCI_BRIDGE_H */
+--- a/arch/microblaze/pci/pci-common.c
++++ b/arch/microblaze/pci/pci-common.c
+@@ -1019,7 +1019,6 @@ static void __devinit pcibios_fixup_brid
+ struct pci_dev *dev = bus->self;
+
+ pci_bus_for_each_resource(bus, res, i) {
+- res = bus->resource[i];
+ if (!res)
+ continue;
+ if (!res->flags)
+@@ -1219,7 +1218,6 @@ void pcibios_allocate_bus_resources(stru
+ pci_domain_nr(bus), bus->number);
+
+ pci_bus_for_each_resource(bus, res, i) {
+- res = bus->resource[i];
+ if (!res || !res->flags
+ || res->start > res->end || res->parent)
+ continue;
+@@ -1510,14 +1508,18 @@ int pcibios_enable_device(struct pci_dev
+ return pci_enable_resources(dev, mask);
+ }
+
+-void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
++static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
+ {
+- struct pci_bus *bus = hose->bus;
+ struct resource *res;
+ int i;
+
+ /* Hookup PHB IO resource */
+- bus->resource[0] = res = &hose->io_resource;
++ res = &hose->io_resource;
++
++ /* Fixup IO space offset */
++ io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
++ res->start = (res->start + io_offset) & 0xffffffffu;
++ res->end = (res->end + io_offset) & 0xffffffffu;
+
+ if (!res->flags) {
+ printk(KERN_WARNING "PCI: I/O resource not set for host"
+@@ -1528,6 +1530,7 @@ void __devinit pcibios_setup_phb_resourc
+ res->end = res->start + IO_SPACE_LIMIT;
+ res->flags = IORESOURCE_IO;
+ }
++ pci_add_resource(resources, res);
+
+ pr_debug("PCI: PHB IO resource = %016llx-%016llx [%lx]\n",
+ (unsigned long long)res->start,
+@@ -1550,7 +1553,7 @@ void __devinit pcibios_setup_phb_resourc
+ res->flags = IORESOURCE_MEM;
+
+ }
+- bus->resource[i+1] = res;
++ pci_add_resource(resources, res);
+
+ pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n",
+ i, (unsigned long long)res->start,
+@@ -1573,34 +1576,27 @@ struct device_node *pcibios_get_phb_of_n
+
+ static void __devinit pcibios_scan_phb(struct pci_controller *hose)
+ {
++ LIST_HEAD(resources);
+ struct pci_bus *bus;
+ struct device_node *node = hose->dn;
+- unsigned long io_offset;
+- struct resource *res = &hose->io_resource;
+
+ pr_debug("PCI: Scanning PHB %s\n",
+ node ? node->full_name : "<NO NAME>");
+
+- /* Create an empty bus for the toplevel */
+- bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
++ pcibios_setup_phb_resources(hose, &resources);
++
++ bus = pci_scan_root_bus(hose->parent, hose->first_busno,
++ hose->ops, hose, &resources);
+ if (bus == NULL) {
+ printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
+ hose->global_number);
++ pci_free_resource_list(&resources);
+ return;
+ }
+ bus->secondary = hose->first_busno;
+ hose->bus = bus;
+
+- /* Fixup IO space offset */
+- io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
+- res->start = (res->start + io_offset) & 0xffffffffu;
+- res->end = (res->end + io_offset) & 0xffffffffu;
+-
+- /* Wire up PHB bus resources */
+- pcibios_setup_phb_resources(hose);
+-
+- /* Scan children */
+- hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
++ hose->last_busno = bus->subordinate;
+ }
+
+ static int __init pcibios_init(void)
+@@ -1614,8 +1610,6 @@ static int __init pcibios_init(void)
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+ hose->last_busno = 0xff;
+ pcibios_scan_phb(hose);
+- printk(KERN_INFO "calling pci_bus_add_devices()\n");
+- pci_bus_add_devices(hose->bus);
+ if (next_busno <= hose->last_busno)
+ next_busno = hose->last_busno + 1;
+ }
+--- a/arch/mips/pci/pci.c
++++ b/arch/mips/pci/pci.c
+@@ -81,6 +81,7 @@ static void __devinit pcibios_scanbus(st
+ {
+ static int next_busno;
+ static int need_domain_info;
++ LIST_HEAD(resources);
+ struct pci_bus *bus;
+
+ if (!hose->iommu)
+@@ -89,7 +90,13 @@ static void __devinit pcibios_scanbus(st
+ if (hose->get_busno && pci_probe_only)
+ next_busno = (*hose->get_busno)();
+
+- bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
++ pci_add_resource(&resources, hose->mem_resource);
++ pci_add_resource(&resources, hose->io_resource);
++ bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
++ &resources);
++ if (!bus)
++ pci_free_resource_list(&resources);
++
+ hose->bus = bus;
+
+ need_domain_info = need_domain_info || hose->index;
+@@ -266,15 +273,11 @@ void __devinit pcibios_fixup_bus(struct
+ {
+ /* Propagate hose info into the subordinate devices. */
+
+- struct pci_controller *hose = bus->sysdata;
+ struct list_head *ln;
+ struct pci_dev *dev = bus->self;
+
+- if (!dev) {
+- bus->resource[0] = hose->io_resource;
+- bus->resource[1] = hose->mem_resource;
+- } else if (pci_probe_only &&
+- (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
++ if (pci_probe_only && dev &&
++ (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ pci_read_bridge_bases(bus);
+ pcibios_fixup_device_resources(dev, bus);
+ }
+--- a/arch/mn10300/unit-asb2305/pci.c
++++ b/arch/mn10300/unit-asb2305/pci.c
+@@ -380,11 +380,6 @@ void __devinit pcibios_fixup_bus(struct
+ {
+ struct pci_dev *dev;
+
+- if (bus->number == 0) {
+- bus->resource[0] = &pci_ioport_resource;
+- bus->resource[1] = &pci_iomem_resource;
+- }
+-
+ if (bus->self) {
+ pci_read_bridge_bases(bus);
+ pcibios_fixup_device_resources(bus->self);
+@@ -402,6 +397,8 @@ void __devinit pcibios_fixup_bus(struct
+ */
+ static int __init pcibios_init(void)
+ {
++ LIST_HEAD(resources);
++
+ ioport_resource.start = 0xA0000000;
+ ioport_resource.end = 0xDFFFFFFF;
+ iomem_resource.start = 0xA0000000;
+@@ -423,7 +420,10 @@ static int __init pcibios_init(void)
+ printk(KERN_INFO "PCI: Probing PCI hardware [mempage %08x]\n",
+ MEM_PAGING_REG);
+
+- pci_root_bus = pci_scan_bus(0, &pci_direct_ampci, NULL);
++ pci_add_resource(&resources, &pci_ioport_resource);
++ pci_add_resource(&resources, &pci_iomem_resource);
++ pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL,
++ &resources);
+
+ pcibios_irq_init();
+ pcibios_fixup_irqs();
+--- a/arch/powerpc/include/asm/pci-bridge.h
++++ b/arch/powerpc/include/asm/pci-bridge.h
+@@ -222,7 +222,6 @@ extern void pci_process_bridge_OF_ranges
+ /* Allocate & free a PCI host bridge structure */
+ extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
+ extern void pcibios_free_controller(struct pci_controller *phb);
+-extern void pcibios_setup_phb_resources(struct pci_controller *hose);
+
+ #ifdef CONFIG_PCI
+ extern int pcibios_vaddr_is_ioport(void __iomem *address);
+--- a/arch/powerpc/kernel/pci-common.c
++++ b/arch/powerpc/kernel/pci-common.c
+@@ -1555,14 +1555,13 @@ int pcibios_enable_device(struct pci_dev
+ return pci_enable_resources(dev, mask);
+ }
+
+-void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
++static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
+ {
+- struct pci_bus *bus = hose->bus;
+ struct resource *res;
+ int i;
+
+ /* Hookup PHB IO resource */
+- bus->resource[0] = res = &hose->io_resource;
++ res = &hose->io_resource;
+
+ if (!res->flags) {
+ printk(KERN_WARNING "PCI: I/O resource not set for host"
+@@ -1580,6 +1579,7 @@ void __devinit pcibios_setup_phb_resourc
+ (unsigned long long)res->start,
+ (unsigned long long)res->end,
+ (unsigned long)res->flags);
++ pci_add_resource(resources, res);
+
+ /* Hookup PHB Memory resources */
+ for (i = 0; i < 3; ++i) {
+@@ -1597,12 +1597,12 @@ void __devinit pcibios_setup_phb_resourc
+ res->flags = IORESOURCE_MEM;
+ #endif /* CONFIG_PPC32 */
+ }
+- bus->resource[i+1] = res;
+
+ pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i,
+ (unsigned long long)res->start,
+ (unsigned long long)res->end,
+ (unsigned long)res->flags);
++ pci_add_resource(resources, res);
+ }
+
+ pr_debug("PCI: PHB MEM offset = %016llx\n",
+@@ -1696,6 +1696,7 @@ struct device_node *pcibios_get_phb_of_n
+ */
+ void __devinit pcibios_scan_phb(struct pci_controller *hose)
+ {
++ LIST_HEAD(resources);
+ struct pci_bus *bus;
+ struct device_node *node = hose->dn;
+ int mode;
+@@ -1703,22 +1704,24 @@ void __devinit pcibios_scan_phb(struct p
+ pr_debug("PCI: Scanning PHB %s\n",
+ node ? node->full_name : "<NO NAME>");
+
++ /* Get some IO space for the new PHB */
++ pcibios_setup_phb_io_space(hose);
++
++ /* Wire up PHB bus resources */
++ pcibios_setup_phb_resources(hose, &resources);
++
+ /* Create an empty bus for the toplevel */
+- bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
++ bus = pci_create_root_bus(hose->parent, hose->first_busno,
++ hose->ops, hose, &resources);
+ if (bus == NULL) {
+ pr_err("Failed to create bus for PCI domain %04x\n",
+ hose->global_number);
++ pci_free_resource_list(&resources);
+ return;
+ }
+ bus->secondary = hose->first_busno;
+ hose->bus = bus;
+
+- /* Get some IO space for the new PHB */
+- pcibios_setup_phb_io_space(hose);
+-
+- /* Wire up PHB bus resources */
+- pcibios_setup_phb_resources(hose);
+-
+ /* Get probe mode and perform scan */
+ mode = PCI_PROBE_NORMAL;
+ if (node && ppc_md.pci_probe_mode)
+--- a/arch/powerpc/kernel/pci_64.c
++++ b/arch/powerpc/kernel/pci_64.c
+@@ -131,30 +131,13 @@ EXPORT_SYMBOL_GPL(pcibios_unmap_io_space
+
+ #endif /* CONFIG_HOTPLUG */
+
+-int __devinit pcibios_map_io_space(struct pci_bus *bus)
++static int __devinit pcibios_map_phb_io_space(struct pci_controller *hose)
+ {
+ struct vm_struct *area;
+ unsigned long phys_page;
+ unsigned long size_page;
+ unsigned long io_virt_offset;
+- struct pci_controller *hose;
+-
+- WARN_ON(bus == NULL);
+
+- /* If this not a PHB, nothing to do, page tables still exist and
+- * thus HPTEs will be faulted in when needed
+- */
+- if (bus->self) {
+- pr_debug("IO mapping for PCI-PCI bridge %s\n",
+- pci_name(bus->self));
+- pr_debug(" virt=0x%016llx...0x%016llx\n",
+- bus->resource[0]->start + _IO_BASE,
+- bus->resource[0]->end + _IO_BASE);
+- return 0;
+- }
+-
+- /* Get the host bridge */
+- hose = pci_bus_to_host(bus);
+ phys_page = _ALIGN_DOWN(hose->io_base_phys, PAGE_SIZE);
+ size_page = _ALIGN_UP(hose->pci_io_size, PAGE_SIZE);
+
+@@ -198,11 +181,30 @@ int __devinit pcibios_map_io_space(struc
+
+ return 0;
+ }
++
++int __devinit pcibios_map_io_space(struct pci_bus *bus)
++{
++ WARN_ON(bus == NULL);
++
++ /* If this not a PHB, nothing to do, page tables still exist and
++ * thus HPTEs will be faulted in when needed
++ */
++ if (bus->self) {
++ pr_debug("IO mapping for PCI-PCI bridge %s\n",
++ pci_name(bus->self));
++ pr_debug(" virt=0x%016llx...0x%016llx\n",
++ bus->resource[0]->start + _IO_BASE,
++ bus->resource[0]->end + _IO_BASE);
++ return 0;
++ }
++
++ return pcibios_map_phb_io_space(pci_bus_to_host(bus));
++}
+ EXPORT_SYMBOL_GPL(pcibios_map_io_space);
+
+ void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
+ {
+- pcibios_map_io_space(hose->bus);
++ pcibios_map_phb_io_space(hose);
+ }
+
+ #define IOBASE_BRIDGE_NUMBER 0
+--- a/arch/sh/drivers/pci/pci.c
++++ b/arch/sh/drivers/pci/pci.c
+@@ -36,9 +36,15 @@ static void __devinit pcibios_scanbus(st
+ {
+ static int next_busno;
+ static int need_domain_info;
++ LIST_HEAD(resources);
++ int i;
+ struct pci_bus *bus;
+
+- bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
++ for (i = 0; i < hose->nr_resources; i++)
++ pci_add_resource(&resources, hose->resources + i);
++
++ bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
++ &resources);
+ hose->bus = bus;
+
+ need_domain_info = need_domain_info || hose->index;
+@@ -55,6 +61,8 @@ static void __devinit pcibios_scanbus(st
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
+ pci_enable_bridges(bus);
++ } else {
++ pci_free_resource_list(&resources);
+ }
+ }
+
+@@ -162,16 +170,8 @@ static void pcibios_fixup_device_resourc
+ */
+ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+ {
+- struct pci_dev *dev = bus->self;
++ struct pci_dev *dev;
+ struct list_head *ln;
+- struct pci_channel *hose = bus->sysdata;
+-
+- if (!dev) {
+- int i;
+-
+- for (i = 0; i < hose->nr_resources; i++)
+- bus->resource[i] = hose->resources + i;
+- }
+
+ for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+ dev = pci_dev_b(ln);
+--- a/arch/sparc/kernel/leon_pci.c
++++ b/arch/sparc/kernel/leon_pci.c
+@@ -19,22 +19,22 @@
+ */
+ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
+ {
++ LIST_HEAD(resources);
+ struct pci_bus *root_bus;
+
+- root_bus = pci_scan_bus_parented(&ofdev->dev, 0, info->ops, info);
+- if (root_bus) {
+- root_bus->resource[0] = &info->io_space;
+- root_bus->resource[1] = &info->mem_space;
+- root_bus->resource[2] = NULL;
+-
+- /* Init all PCI devices into PCI tree */
+- pci_bus_add_devices(root_bus);
++ pci_add_resource(&resources, &info->io_space);
++ pci_add_resource(&resources, &info->mem_space);
+
++ root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
++ &resources);
++ if (root_bus) {
+ /* Setup IRQs of all devices using custom routines */
+ pci_fixup_irqs(pci_common_swizzle, info->map_irq);
+
+ /* Assign devices with resources */
+ pci_assign_unassigned_resources();
++ } else {
++ pci_free_resource_list(&resources);
+ }
+ }
+
+@@ -83,15 +83,6 @@ void __devinit pcibios_fixup_bus(struct
+ int i, has_io, has_mem;
+ u16 cmd;
+
+- /* Generic PCI bus probing sets these to point at
+- * &io{port,mem}_resouce which is wrong for us.
+- */
+- if (pbus->self == NULL) {
+- pbus->resource[0] = &info->io_space;
+- pbus->resource[1] = &info->mem_space;
+- pbus->resource[2] = NULL;
+- }
+-
+ list_for_each_entry(dev, &pbus->devices, bus_list) {
+ /*
+ * We can not rely on that the bootloader has enabled I/O
+--- a/arch/sparc/kernel/pci.c
++++ b/arch/sparc/kernel/pci.c
+@@ -685,23 +685,25 @@ static void __devinit pci_bus_register_o
+ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
+ struct device *parent)
+ {
++ LIST_HEAD(resources);
+ struct device_node *node = pbm->op->dev.of_node;
+ struct pci_bus *bus;
+
+ printk("PCI: Scanning PBM %s\n", node->full_name);
+
+- bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm);
++ pci_add_resource(&resources, &pbm->io_space);
++ pci_add_resource(&resources, &pbm->mem_space);
++ bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
++ pbm, &resources);
+ if (!bus) {
+ printk(KERN_ERR "Failed to create bus for %s\n",
+ node->full_name);
++ pci_free_resource_list(&resources);
+ return NULL;
+ }
+ bus->secondary = pbm->pci_first_busno;
+ bus->subordinate = pbm->pci_last_busno;
+
+- bus->resource[0] = &pbm->io_space;
+- bus->resource[1] = &pbm->mem_space;
+-
+ pci_of_scan_bus(pbm, node, bus);
+ pci_bus_add_devices(bus);
+ pci_bus_register_of_sysfs(bus);
+@@ -711,13 +713,6 @@ struct pci_bus * __devinit pci_scan_one_
+
+ void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
+ {
+- struct pci_pbm_info *pbm = pbus->sysdata;
+-
+- /* Generic PCI bus probing sets these to point at
+- * &io{port,mem}_resouce which is wrong for us.
+- */
+- pbus->resource[0] = &pbm->io_space;
+- pbus->resource[1] = &pbm->mem_space;
+ }
+
+ void pcibios_update_irq(struct pci_dev *pdev, int irq)
+--- a/arch/x86/include/asm/topology.h
++++ b/arch/x86/include/asm/topology.h
+@@ -174,7 +174,7 @@ static inline void arch_fix_phys_package
+ }
+
+ struct pci_bus;
+-void x86_pci_root_bus_res_quirks(struct pci_bus *b);
++void x86_pci_root_bus_resources(int bus, struct list_head *resources);
+
+ #ifdef CONFIG_SMP
+ #define mc_capable() ((boot_cpu_data.x86_max_cores > 1) && \
+--- a/arch/x86/pci/acpi.c
++++ b/arch/x86/pci/acpi.c
+@@ -12,7 +12,7 @@ struct pci_root_info {
+ char *name;
+ unsigned int res_num;
+ struct resource *res;
+- struct pci_bus *bus;
++ struct list_head *resources;
+ int busnum;
+ };
+
+@@ -275,23 +275,20 @@ static void add_resources(struct pci_roo
+ "ignoring host bridge window %pR (conflicts with %s %pR)\n",
+ res, conflict->name, conflict);
+ else
+- pci_bus_add_resource(info->bus, res, 0);
++ pci_add_resource(info->resources, res);
+ }
+ }
+
+ static void
+ get_current_resources(struct acpi_device *device, int busnum,
+- int domain, struct pci_bus *bus)
++ int domain, struct list_head *resources)
+ {
+ struct pci_root_info info;
+ size_t size;
+
+- if (pci_use_crs)
+- pci_bus_remove_resources(bus);
+-
+ info.bridge = device;
+- info.bus = bus;
+ info.res_num = 0;
++ info.resources = resources;
+ acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
+ &info);
+ if (!info.res_num)
+@@ -300,7 +297,7 @@ get_current_resources(struct acpi_device
+ size = sizeof(*info.res) * info.res_num;
+ info.res = kmalloc(size, GFP_KERNEL);
+ if (!info.res)
+- goto res_alloc_fail;
++ return;
+
+ info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum);
+ if (!info.name)
+@@ -315,8 +312,6 @@ get_current_resources(struct acpi_device
+
+ name_alloc_fail:
+ kfree(info.res);
+-res_alloc_fail:
+- return;
+ }
+
+ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
+@@ -324,6 +319,7 @@ struct pci_bus * __devinit pci_acpi_scan
+ struct acpi_device *device = root->device;
+ int domain = root->segment;
+ int busnum = root->secondary.start;
++ LIST_HEAD(resources);
+ struct pci_bus *bus;
+ struct pci_sysdata *sd;
+ int node;
+@@ -378,11 +374,15 @@ struct pci_bus * __devinit pci_acpi_scan
+ memcpy(bus->sysdata, sd, sizeof(*sd));
+ kfree(sd);
+ } else {
+- bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd);
+- if (bus) {
+- get_current_resources(device, busnum, domain, bus);
++ get_current_resources(device, busnum, domain, &resources);
++ if (list_empty(&resources))
++ x86_pci_root_bus_resources(busnum, &resources);
++ bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
++ &resources);
++ if (bus)
+ bus->subordinate = pci_scan_child_bus(bus);
+- }
++ else
++ pci_free_resource_list(&resources);
+ }
+
+ /* After the PCI-E bus has been walked and all devices discovered,
+--- a/arch/x86/pci/broadcom_bus.c
++++ b/arch/x86/pci/broadcom_bus.c
+@@ -15,10 +15,11 @@
+ #include <linux/pci.h>
+ #include <linux/init.h>
+ #include <asm/pci_x86.h>
++#include <asm/pci-direct.h>
+
+ #include "bus_numa.h"
+
+-static void __devinit cnb20le_res(struct pci_dev *dev)
++static void __init cnb20le_res(u8 bus, u8 slot, u8 func)
+ {
+ struct pci_root_info *info;
+ struct resource res;
+@@ -26,21 +27,12 @@ static void __devinit cnb20le_res(struct
+ u8 fbus, lbus;
+ int i;
+
+-#ifdef CONFIG_ACPI
+- /*
+- * We should get host bridge information from ACPI unless the BIOS
+- * doesn't support it.
+- */
+- if (acpi_os_get_root_pointer())
+- return;
+-#endif
+-
+ info = &pci_root_info[pci_root_num];
+ pci_root_num++;
+
+ /* read the PCI bus numbers */
+- pci_read_config_byte(dev, 0x44, &fbus);
+- pci_read_config_byte(dev, 0x45, &lbus);
++ fbus = read_pci_config_byte(bus, slot, func, 0x44);
++ lbus = read_pci_config_byte(bus, slot, func, 0x45);
+ info->bus_min = fbus;
+ info->bus_max = lbus;
+
+@@ -59,8 +51,8 @@ static void __devinit cnb20le_res(struct
+ }
+
+ /* read the non-prefetchable memory window */
+- pci_read_config_word(dev, 0xc0, &word1);
+- pci_read_config_word(dev, 0xc2, &word2);
++ word1 = read_pci_config_16(bus, slot, func, 0xc0);
++ word2 = read_pci_config_16(bus, slot, func, 0xc2);
+ if (word1 != word2) {
+ res.start = (word1 << 16) | 0x0000;
+ res.end = (word2 << 16) | 0xffff;
+@@ -69,8 +61,8 @@ static void __devinit cnb20le_res(struct
+ }
+
+ /* read the prefetchable memory window */
+- pci_read_config_word(dev, 0xc4, &word1);
+- pci_read_config_word(dev, 0xc6, &word2);
++ word1 = read_pci_config_16(bus, slot, func, 0xc4);
++ word2 = read_pci_config_16(bus, slot, func, 0xc6);
+ if (word1 != word2) {
+ res.start = (word1 << 16) | 0x0000;
+ res.end = (word2 << 16) | 0xffff;
+@@ -79,8 +71,8 @@ static void __devinit cnb20le_res(struct
+ }
+
+ /* read the IO port window */
+- pci_read_config_word(dev, 0xd0, &word1);
+- pci_read_config_word(dev, 0xd2, &word2);
++ word1 = read_pci_config_16(bus, slot, func, 0xd0);
++ word2 = read_pci_config_16(bus, slot, func, 0xd2);
+ if (word1 != word2) {
+ res.start = word1;
+ res.end = word2;
+@@ -92,13 +84,37 @@ static void __devinit cnb20le_res(struct
+ res.start = fbus;
+ res.end = lbus;
+ res.flags = IORESOURCE_BUS;
+- dev_info(&dev->dev, "CNB20LE PCI Host Bridge (domain %04x %pR)\n",
+- pci_domain_nr(dev->bus), &res);
++ printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res);
+
+ for (i = 0; i < info->res_num; i++)
+- dev_info(&dev->dev, "host bridge window %pR\n", &info->res[i]);
++ printk(KERN_INFO "host bridge window %pR\n", &info->res[i]);
+ }
+
+-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
+- cnb20le_res);
++static int __init broadcom_postcore_init(void)
++{
++ u8 bus = 0, slot = 0;
++ u32 id;
++ u16 vendor, device;
++
++#ifdef CONFIG_ACPI
++ /*
++ * We should get host bridge information from ACPI unless the BIOS
++ * doesn't support it.
++ */
++ if (acpi_os_get_root_pointer())
++ return 0;
++#endif
++
++ id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
++ vendor = id & 0xffff;
++ device = (id >> 16) & 0xffff;
++
++ if (vendor == PCI_VENDOR_ID_SERVERWORKS &&
++ device == PCI_DEVICE_ID_SERVERWORKS_LE) {
++ cnb20le_res(bus, slot, 0);
++ cnb20le_res(bus, slot, 1);
++ }
++ return 0;
++}
+
++postcore_initcall(broadcom_postcore_init);
+--- a/arch/x86/pci/bus_numa.c
++++ b/arch/x86/pci/bus_numa.c
+@@ -7,45 +7,50 @@
+ int pci_root_num;
+ struct pci_root_info pci_root_info[PCI_ROOT_NR];
+
+-void x86_pci_root_bus_res_quirks(struct pci_bus *b)
++void x86_pci_root_bus_resources(int bus, struct list_head *resources)
+ {
+ int i;
+ int j;
+ struct pci_root_info *info;
+
+- /* don't go for it if _CRS is used already */
+- if (b->resource[0] != &ioport_resource ||
+- b->resource[1] != &iomem_resource)
+- return;
+-
+ if (!pci_root_num)
+- return;
++ goto default_resources;
+
+ for (i = 0; i < pci_root_num; i++) {
+- if (pci_root_info[i].bus_min == b->number)
++ if (pci_root_info[i].bus_min == bus)
+ break;
+ }
+
+ if (i == pci_root_num)
+- return;
++ goto default_resources;
+
+- printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
+- b->number);
++ printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n",
++ bus);
+
+- pci_bus_remove_resources(b);
+ info = &pci_root_info[i];
+ for (j = 0; j < info->res_num; j++) {
+ struct resource *res;
+ struct resource *root;
+
+ res = &info->res[j];
+- pci_bus_add_resource(b, res, 0);
++ pci_add_resource(resources, res);
+ if (res->flags & IORESOURCE_IO)
+ root = &ioport_resource;
+ else
+ root = &iomem_resource;
+ insert_resource(root, res);
+ }
++ return;
++
++default_resources:
++ /*
++ * We don't have any host bridge aperture information from the
++ * "native host bridge drivers," e.g., amd_bus or broadcom_bus,
++ * so fall back to the defaults historically used by pci_create_bus().
++ */
++ printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus);
++ pci_add_resource(resources, &ioport_resource);
++ pci_add_resource(resources, &iomem_resource);
+ }
+
+ void __devinit update_res(struct pci_root_info *info, resource_size_t start,
+--- a/arch/x86/pci/common.c
++++ b/arch/x86/pci/common.c
+@@ -164,9 +164,6 @@ void __devinit pcibios_fixup_bus(struct
+ {
+ struct pci_dev *dev;
+
+- /* root bus? */
+- if (!b->parent)
+- x86_pci_root_bus_res_quirks(b);
+ pci_read_bridge_bases(b);
+ list_for_each_entry(dev, &b->devices, bus_list)
+ pcibios_fixup_device_resources(dev);
+@@ -433,6 +430,7 @@ void __init dmi_check_pciprobe(void)
+
+ struct pci_bus * __devinit pcibios_scan_root(int busnum)
+ {
++ LIST_HEAD(resources);
+ struct pci_bus *bus = NULL;
+ struct pci_sysdata *sd;
+
+@@ -456,9 +454,12 @@ struct pci_bus * __devinit pcibios_scan_
+ sd->node = get_mp_bus_to_node(busnum);
+
+ printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
+- bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+- if (!bus)
++ x86_pci_root_bus_resources(busnum, &resources);
++ bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
++ if (!bus) {
++ pci_free_resource_list(&resources);
+ kfree(sd);
++ }
+
+ return bus;
+ }
+@@ -639,6 +640,7 @@ int pci_ext_cfg_avail(struct pci_dev *de
+
+ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
+ {
++ LIST_HEAD(resources);
+ struct pci_bus *bus = NULL;
+ struct pci_sysdata *sd;
+
+@@ -653,9 +655,12 @@ struct pci_bus * __devinit pci_scan_bus_
+ return NULL;
+ }
+ sd->node = node;
+- bus = pci_scan_bus(busno, ops, sd);
+- if (!bus)
++ x86_pci_root_bus_resources(busno, &resources);
++ bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
++ if (!bus) {
++ pci_free_resource_list(&resources);
+ kfree(sd);
++ }
+
+ return bus;
+ }
+--- a/arch/x86/pci/legacy.c
++++ b/arch/x86/pci/legacy.c
+@@ -31,9 +31,6 @@ int __init pci_legacy_init(void)
+
+ printk("PCI: Probing PCI hardware\n");
+ pci_root_bus = pcibios_scan_root(0);
+- if (pci_root_bus)
+- pci_bus_add_devices(pci_root_bus);
+-
+ return 0;
+ }
+
+--- a/arch/x86/pci/numaq_32.c
++++ b/arch/x86/pci/numaq_32.c
+@@ -153,8 +153,6 @@ int __init pci_numaq_init(void)
+ raw_pci_ops = &pci_direct_conf1_mq;
+
+ pci_root_bus = pcibios_scan_root(0);
+- if (pci_root_bus)
+- pci_bus_add_devices(pci_root_bus);
+ if (num_online_nodes() > 1)
+ for_each_online_node(quad) {
+ if (quad == 0)
+--- a/arch/xtensa/kernel/pci.c
++++ b/arch/xtensa/kernel/pci.c
+@@ -134,9 +134,46 @@ struct pci_controller * __init pcibios_a
+ return pci_ctrl;
+ }
+
++static void __init pci_controller_apertures(struct pci_controller *pci_ctrl,
++ struct list_head *resources)
++{
++ struct resource *res;
++ unsigned long io_offset;
++ int i;
++
++ io_offset = (unsigned long)pci_ctrl->io_space.base;
++ res = &pci_ctrl->io_resource;
++ if (!res->flags) {
++ if (io_offset)
++ printk (KERN_ERR "I/O resource not set for host"
++ " bridge %d\n", pci_ctrl->index);
++ res->start = 0;
++ res->end = IO_SPACE_LIMIT;
++ res->flags = IORESOURCE_IO;
++ }
++ res->start += io_offset;
++ res->end += io_offset;
++ pci_add_resource(resources, res);
++
++ for (i = 0; i < 3; i++) {
++ res = &pci_ctrl->mem_resources[i];
++ if (!res->flags) {
++ if (i > 0)
++ continue;
++ printk(KERN_ERR "Memory resource not set for "
++ "host bridge %d\n", pci_ctrl->index);
++ res->start = 0;
++ res->end = ~0U;
++ res->flags = IORESOURCE_MEM;
++ }
++ pci_add_resource(resources, res);
++ }
++}
++
+ static int __init pcibios_init(void)
+ {
+ struct pci_controller *pci_ctrl;
++ struct list_head resources;
+ struct pci_bus *bus;
+ int next_busno = 0, i;
+
+@@ -145,19 +182,10 @@ static int __init pcibios_init(void)
+ /* Scan all of the recorded PCI controllers. */
+ for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) {
+ pci_ctrl->last_busno = 0xff;
+- bus = pci_scan_bus(pci_ctrl->first_busno, pci_ctrl->ops,
+- pci_ctrl);
+- if (pci_ctrl->io_resource.flags) {
+- unsigned long offs;
+-
+- offs = (unsigned long)pci_ctrl->io_space.base;
+- pci_ctrl->io_resource.start += offs;
+- pci_ctrl->io_resource.end += offs;
+- bus->resource[0] = &pci_ctrl->io_resource;
+- }
+- for (i = 0; i < 3; ++i)
+- if (pci_ctrl->mem_resources[i].flags)
+- bus->resource[i+1] =&pci_ctrl->mem_resources[i];
++ INIT_LIST_HEAD(&resources);
++ pci_controller_apertures(pci_ctrl, &resources);
++ bus = pci_scan_root_bus(NULL, pci_ctrl->first_busno,
++ pci_ctrl->ops, pci_ctrl, &resources);
+ pci_ctrl->bus = bus;
+ pci_ctrl->last_busno = bus->subordinate;
+ if (next_busno <= pci_ctrl->last_busno)
+@@ -178,36 +206,7 @@ void __init pcibios_fixup_bus(struct pci
+ int i;
+
+ io_offset = (unsigned long)pci_ctrl->io_space.base;
+- if (bus->parent == NULL) {
+- /* this is a host bridge - fill in its resources */
+- pci_ctrl->bus = bus;
+-
+- bus->resource[0] = res = &pci_ctrl->io_resource;
+- if (!res->flags) {
+- if (io_offset)
+- printk (KERN_ERR "I/O resource not set for host"
+- " bridge %d\n", pci_ctrl->index);
+- res->start = 0;
+- res->end = IO_SPACE_LIMIT;
+- res->flags = IORESOURCE_IO;
+- }
+- res->start += io_offset;
+- res->end += io_offset;
+-
+- for (i = 0; i < 3; i++) {
+- res = &pci_ctrl->mem_resources[i];
+- if (!res->flags) {
+- if (i > 0)
+- continue;
+- printk(KERN_ERR "Memory resource not set for "
+- "host bridge %d\n", pci_ctrl->index);
+- res->start = 0;
+- res->end = ~0U;
+- res->flags = IORESOURCE_MEM;
+- }
+- bus->resource[i+1] = res;
+- }
+- } else {
++ if (bus->parent) {
+ /* This is a subordinate bridge */
+ pci_read_bridge_bases(bus);
+
+--- a/drivers/parisc/dino.c
++++ b/drivers/parisc/dino.c
+@@ -562,19 +562,6 @@ dino_fixup_bus(struct pci_bus *bus)
+ /* Firmware doesn't set up card-mode dino, so we have to */
+ if (is_card_dino(&dino_dev->hba.dev->id)) {
+ dino_card_setup(bus, dino_dev->hba.base_addr);
+- } else if(bus->parent == NULL) {
+- /* must have a dino above it, reparent the resources
+- * into the dino window */
+- int i;
+- struct resource *res = &dino_dev->hba.lmmio_space;
+-
+- bus->resource[0] = &(dino_dev->hba.io_space);
+- for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) {
+- if(res[i].flags == 0)
+- break;
+- bus->resource[i+1] = &res[i];
+- }
+-
+ } else if (bus->parent) {
+ int i;
+
+@@ -927,6 +914,7 @@ static int __init dino_probe(struct pari
+ const char *version = "unknown";
+ char *name;
+ int is_cujo = 0;
++ LIST_HEAD(resources);
+ struct pci_bus *bus;
+ unsigned long hpa = dev->hpa.start;
+
+@@ -1003,26 +991,37 @@ static int __init dino_probe(struct pari
+
+ dev->dev.platform_data = dino_dev;
+
++ pci_add_resource(&resources, &dino_dev->hba.io_space);
++ if (dino_dev->hba.lmmio_space.flags)
++ pci_add_resource(&resources, &dino_dev->hba.lmmio_space);
++ if (dino_dev->hba.elmmio_space.flags)
++ pci_add_resource(&resources, &dino_dev->hba.elmmio_space);
++ if (dino_dev->hba.gmmio_space.flags)
++ pci_add_resource(&resources, &dino_dev->hba.gmmio_space);
++
+ /*
+ ** It's not used to avoid chicken/egg problems
+ ** with configuration accessor functions.
+ */
+- dino_dev->hba.hba_bus = bus = pci_scan_bus_parented(&dev->dev,
+- dino_current_bus, &dino_cfg_ops, NULL);
+-
+- if(bus) {
+- /* This code *depends* on scanning being single threaded
+- * if it isn't, this global bus number count will fail
+- */
+- dino_current_bus = bus->subordinate + 1;
+- pci_bus_assign_resources(bus);
+- pci_bus_add_devices(bus);
+- } else {
++ dino_dev->hba.hba_bus = bus = pci_create_root_bus(&dev->dev,
++ dino_current_bus, &dino_cfg_ops, NULL, &resources);
++ if (!bus) {
+ printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
+ dev_name(&dev->dev), dino_current_bus);
++ pci_free_resource_list(&resources);
+ /* increment the bus number in case of duplicates */
+ dino_current_bus++;
++ return 0;
+ }
++
++ bus->subordinate = pci_scan_child_bus(bus);
++
++ /* This code *depends* on scanning being single threaded
++ * if it isn't, this global bus number count will fail
++ */
++ dino_current_bus = bus->subordinate + 1;
++ pci_bus_assign_resources(bus);
++ pci_bus_add_devices(bus);
+ return 0;
+ }
+
+--- a/drivers/parisc/lba_pci.c
++++ b/drivers/parisc/lba_pci.c
+@@ -653,7 +653,7 @@ lba_fixup_bus(struct pci_bus *bus)
+ }
+ } else {
+ /* Host-PCI Bridge */
+- int err, i;
++ int err;
+
+ DBG("lba_fixup_bus() %s [%lx/%lx]/%lx\n",
+ ldev->hba.io_space.name,
+@@ -669,9 +669,6 @@ lba_fixup_bus(struct pci_bus *bus)
+ lba_dump_res(&ioport_resource, 2);
+ BUG();
+ }
+- /* advertize Host bridge resources to PCI bus */
+- bus->resource[0] = &(ldev->hba.io_space);
+- i = 1;
+
+ if (ldev->hba.elmmio_space.start) {
+ err = request_resource(&iomem_resource,
+@@ -685,35 +682,17 @@ lba_fixup_bus(struct pci_bus *bus)
+
+ /* lba_dump_res(&iomem_resource, 2); */
+ /* BUG(); */
+- } else
+- bus->resource[i++] = &(ldev->hba.elmmio_space);
++ }
+ }
+
+-
+- /* Overlaps with elmmio can (and should) fail here.
+- * We will prune (or ignore) the distributed range.
+- *
+- * FIXME: SBA code should register all elmmio ranges first.
+- * that would take care of elmmio ranges routed
+- * to a different rope (already discovered) from
+- * getting registered *after* LBA code has already
+- * registered it's distributed lmmio range.
+- */
+- if (truncate_pat_collision(&iomem_resource,
+- &(ldev->hba.lmmio_space))) {
+-
+- printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n",
+- (long)ldev->hba.lmmio_space.start,
+- (long)ldev->hba.lmmio_space.end);
+- } else {
++ if (ldev->hba.lmmio_space.flags) {
+ err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
+ if (err < 0) {
+ printk(KERN_ERR "FAILED: lba_fixup_bus() request for "
+ "lmmio_space [%lx/%lx]\n",
+ (long)ldev->hba.lmmio_space.start,
+ (long)ldev->hba.lmmio_space.end);
+- } else
+- bus->resource[i++] = &(ldev->hba.lmmio_space);
++ }
+ }
+
+ #ifdef CONFIG_64BIT
+@@ -728,7 +707,6 @@ lba_fixup_bus(struct pci_bus *bus)
+ lba_dump_res(&iomem_resource, 2);
+ BUG();
+ }
+- bus->resource[i++] = &(ldev->hba.gmmio_space);
+ }
+ #endif
+
+@@ -1404,6 +1382,7 @@ static int __init
+ lba_driver_probe(struct parisc_device *dev)
+ {
+ struct lba_device *lba_dev;
++ LIST_HEAD(resources);
+ struct pci_bus *lba_bus;
+ struct pci_ops *cfg_ops;
+ u32 func_class;
+@@ -1518,10 +1497,41 @@ lba_driver_probe(struct parisc_device *d
+ if (lba_dev->hba.bus_num.start < lba_next_bus)
+ lba_dev->hba.bus_num.start = lba_next_bus;
+
++ /* Overlaps with elmmio can (and should) fail here.
++ * We will prune (or ignore) the distributed range.
++ *
++ * FIXME: SBA code should register all elmmio ranges first.
++ * that would take care of elmmio ranges routed
++ * to a different rope (already discovered) from
++ * getting registered *after* LBA code has already
++ * registered it's distributed lmmio range.
++ */
++ if (truncate_pat_collision(&iomem_resource,
++ &(lba_dev->hba.lmmio_space))) {
++ printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n",
++ (long)lba_dev->hba.lmmio_space.start,
++ (long)lba_dev->hba.lmmio_space.end);
++ lba_dev->hba.lmmio_space.flags = 0;
++ }
++
++ pci_add_resource(&resources, &lba_dev->hba.io_space);
++ if (lba_dev->hba.elmmio_space.start)
++ pci_add_resource(&resources, &lba_dev->hba.elmmio_space);
++ if (lba_dev->hba.lmmio_space.flags)
++ pci_add_resource(&resources, &lba_dev->hba.lmmio_space);
++ if (lba_dev->hba.gmmio_space.flags)
++ pci_add_resource(&resources, &lba_dev->hba.gmmio_space);
++
+ dev->dev.platform_data = lba_dev;
+ lba_bus = lba_dev->hba.hba_bus =
+- pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
+- cfg_ops, NULL);
++ pci_create_root_bus(&dev->dev, lba_dev->hba.bus_num.start,
++ cfg_ops, NULL, &resources);
++ if (!lba_bus) {
++ pci_free_resource_list(&resources);
++ return 0;
++ }
++
++ lba_bus->subordinate = pci_scan_child_bus(lba_bus);
+
+ /* This is in lieu of calling pci_assign_unassigned_resources() */
+ if (is_pdc_pat()) {
+@@ -1551,10 +1561,8 @@ lba_driver_probe(struct parisc_device *d
+ lba_dev->flags |= LBA_FLAG_SKIP_PROBE;
+ }
+
+- if (lba_bus) {
+- lba_next_bus = lba_bus->subordinate + 1;
+- pci_bus_add_devices(lba_bus);
+- }
++ lba_next_bus = lba_bus->subordinate + 1;
++ pci_bus_add_devices(lba_bus);
+
+ /* Whew! Finally done! Tell services we got this one covered. */
+ return 0;
+--- a/drivers/pci/bus.c
++++ b/drivers/pci/bus.c
+@@ -18,6 +18,32 @@
+
+ #include "pci.h"
+
++void pci_add_resource(struct list_head *resources, struct resource *res)
++{
++ struct pci_bus_resource *bus_res;
++
++ bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
++ if (!bus_res) {
++ printk(KERN_ERR "PCI: can't add bus resource %pR\n", res);
++ return;
++ }
++
++ bus_res->res = res;
++ list_add_tail(&bus_res->list, resources);
++}
++EXPORT_SYMBOL(pci_add_resource);
++
++void pci_free_resource_list(struct list_head *resources)
++{
++ struct pci_bus_resource *bus_res, *tmp;
++
++ list_for_each_entry_safe(bus_res, tmp, resources, list) {
++ list_del(&bus_res->list);
++ kfree(bus_res);
++ }
++}
++EXPORT_SYMBOL(pci_free_resource_list);
++
+ void pci_bus_add_resource(struct pci_bus *bus, struct resource *res,
+ unsigned int flags)
+ {
+@@ -52,16 +78,12 @@ EXPORT_SYMBOL_GPL(pci_bus_resource_n);
+
+ void pci_bus_remove_resources(struct pci_bus *bus)
+ {
+- struct pci_bus_resource *bus_res, *tmp;
+ int i;
+
+ for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
+ bus->resource[i] = NULL;
+
+- list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
+- list_del(&bus_res->list);
+- kfree(bus_res);
+- }
++ pci_free_resource_list(&bus->resources);
+ }
+
+ /**
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -1527,12 +1527,14 @@ unsigned int __devinit pci_scan_child_bu
+ return max;
+ }
+
+-struct pci_bus * pci_create_bus(struct device *parent,
+- int bus, struct pci_ops *ops, void *sysdata)
++struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
++ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+ {
+- int error;
++ int error, i;
+ struct pci_bus *b, *b2;
+ struct device *dev;
++ struct pci_bus_resource *bus_res, *n;
++ struct resource *res;
+
+ b = pci_alloc_bus();
+ if (!b)
+@@ -1582,8 +1584,20 @@ struct pci_bus * pci_create_bus(struct d
+ pci_create_legacy_files(b);
+
+ b->number = b->secondary = bus;
+- b->resource[0] = &ioport_resource;
+- b->resource[1] = &iomem_resource;
++
++ /* Add initial resources to the bus */
++ list_for_each_entry_safe(bus_res, n, resources, list)
++ list_move_tail(&bus_res->list, &b->resources);
++
++ if (parent)
++ dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
++ else
++ printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
++
++ pci_bus_for_each_resource(b, res, i) {
++ if (res)
++ dev_info(&b->dev, "root bus resource %pR\n", res);
++ }
+
+ return b;
+
+@@ -1599,18 +1613,58 @@ err_out:
+ return NULL;
+ }
+
++struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
++ struct pci_ops *ops, void *sysdata, struct list_head *resources)
++{
++ struct pci_bus *b;
++
++ b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
++ if (!b)
++ return NULL;
++
++ b->subordinate = pci_scan_child_bus(b);
++ pci_bus_add_devices(b);
++ return b;
++}
++EXPORT_SYMBOL(pci_scan_root_bus);
++
++/* Deprecated; use pci_scan_root_bus() instead */
+ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
+ int bus, struct pci_ops *ops, void *sysdata)
+ {
++ LIST_HEAD(resources);
+ struct pci_bus *b;
+
+- b = pci_create_bus(parent, bus, ops, sysdata);
++ pci_add_resource(&resources, &ioport_resource);
++ pci_add_resource(&resources, &iomem_resource);
++ b = pci_create_root_bus(parent, bus, ops, sysdata, &resources);
+ if (b)
+ b->subordinate = pci_scan_child_bus(b);
++ else
++ pci_free_resource_list(&resources);
+ return b;
+ }
+ EXPORT_SYMBOL(pci_scan_bus_parented);
+
++struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
++ void *sysdata)
++{
++ LIST_HEAD(resources);
++ struct pci_bus *b;
++
++ pci_add_resource(&resources, &ioport_resource);
++ pci_add_resource(&resources, &iomem_resource);
++ b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
++ if (b) {
++ b->subordinate = pci_scan_child_bus(b);
++ pci_bus_add_devices(b);
++ } else {
++ pci_free_resource_list(&resources);
++ }
++ return b;
++}
++EXPORT_SYMBOL(pci_scan_bus);
++
+ #ifdef CONFIG_HOTPLUG
+ /**
+ * pci_rescan_bus - scan a PCI bus for devices.
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -660,17 +660,13 @@ extern struct pci_bus *pci_find_bus(int
+ void pci_bus_add_devices(const struct pci_bus *bus);
+ struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata);
+-static inline struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
+- void *sysdata)
+-{
+- struct pci_bus *root_bus;
+- root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
+- if (root_bus)
+- pci_bus_add_devices(root_bus);
+- return root_bus;
+-}
+-struct pci_bus *pci_create_bus(struct device *parent, int bus,
+- struct pci_ops *ops, void *sysdata);
++struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
++struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
++ struct pci_ops *ops, void *sysdata,
++ struct list_head *resources);
++struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
++ struct pci_ops *ops, void *sysdata,
++ struct list_head *resources);
+ struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
+ int busnr);
+ void pcie_update_link_speed(struct pci_bus *bus, u16 link_status);
+@@ -910,6 +906,8 @@ int pci_request_selected_regions_exclusi
+ void pci_release_selected_regions(struct pci_dev *, int);
+
+ /* drivers/pci/bus.c */
++void pci_add_resource(struct list_head *resources, struct resource *res);
++void pci_free_resource_list(struct list_head *resources);
+ void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
+ struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n);
+ void pci_bus_remove_resources(struct pci_bus *bus);
+++ /dev/null
---- a/Documentation/feature-removal-schedule.txt
-+++ b/Documentation/feature-removal-schedule.txt
-@@ -551,3 +551,15 @@ When: 3.5
- Why: The iwlagn module has been renamed iwlwifi. The alias will be around
- for backward compatibility for several cycles and then dropped.
- Who: Don Fry <donald.h.fry@intel.com>
-+
-+----------------------------
-+
-+What: pci_scan_bus_parented()
-+When: 3.5
-+Why: The pci_scan_bus_parented() interface creates a new root bus. The
-+ bus is created with default resources (ioport_resource and
-+ iomem_resource) that are always wrong, so we rely on arch code to
-+ correct them later. Callers of pci_scan_bus_parented() should
-+ convert to using pci_scan_root_bus() so they can supply a list of
-+ bus resources when the bus is created.
-+Who: Bjorn Helgaas <bhelgaas@google.com>
---- a/arch/alpha/kernel/pci.c
-+++ b/arch/alpha/kernel/pci.c
-@@ -281,27 +281,9 @@ pcibios_fixup_device_resources(struct pc
- void __devinit
- pcibios_fixup_bus(struct pci_bus *bus)
- {
-- /* Propagate hose info into the subordinate devices. */
--
-- struct pci_controller *hose = bus->sysdata;
- struct pci_dev *dev = bus->self;
-
-- if (!dev) {
-- /* Root bus. */
-- u32 pci_mem_end;
-- u32 sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;
-- unsigned long end;
--
-- bus->resource[0] = hose->io_space;
-- bus->resource[1] = hose->mem_space;
--
-- /* Adjust hose mem_space limit to prevent PCI allocations
-- in the iommu windows. */
-- pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
-- end = hose->mem_space->start + pci_mem_end;
-- if (hose->mem_space->end > end)
-- hose->mem_space->end = end;
-- } else if (pci_probe_only &&
-+ if (pci_probe_only && dev &&
- (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
- pci_read_bridge_bases(bus);
- pcibios_fixup_device_resources(dev, bus);
-@@ -414,13 +396,31 @@ void __init
- common_init_pci(void)
- {
- struct pci_controller *hose;
-+ struct list_head resources;
- struct pci_bus *bus;
- int next_busno;
- int need_domain_info = 0;
-+ u32 pci_mem_end;
-+ u32 sg_base;
-+ unsigned long end;
-
- /* Scan all of the recorded PCI controllers. */
- for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
-- bus = pci_scan_bus(next_busno, alpha_mv.pci_ops, hose);
-+ sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;
-+
-+ /* Adjust hose mem_space limit to prevent PCI allocations
-+ in the iommu windows. */
-+ pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
-+ end = hose->mem_space->start + pci_mem_end;
-+ if (hose->mem_space->end > end)
-+ hose->mem_space->end = end;
-+
-+ INIT_LIST_HEAD(&resources);
-+ pci_add_resource(&resources, hose->io_space);
-+ pci_add_resource(&resources, hose->mem_space);
-+
-+ bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
-+ hose, &resources);
- hose->bus = bus;
- hose->need_domain_info = need_domain_info;
- next_busno = bus->subordinate + 1;
---- a/arch/arm/common/it8152.c
-+++ b/arch/arm/common/it8152.c
-@@ -299,8 +299,8 @@ int __init it8152_pci_setup(int nr, stru
- goto err1;
- }
-
-- sys->resource[0] = &it8152_io;
-- sys->resource[1] = &it8152_mem;
-+ pci_add_resource(&sys->resources, &it8152_io);
-+ pci_add_resource(&sys->resources, &it8152_mem);
-
- if (platform_notify || platform_notify_remove) {
- printk(KERN_ERR "PCI: Can't use platform_notify\n");
-@@ -352,7 +352,7 @@ void pcibios_set_master(struct pci_dev *
-
- struct pci_bus * __init it8152_pci_scan_bus(int nr, struct pci_sys_data *sys)
- {
-- return pci_scan_bus(nr, &it8152_ops, sys);
-+ return pci_scan_root_bus(NULL, nr, &it8152_ops, sys, &sys->resources);
- }
-
- EXPORT_SYMBOL(dma_set_coherent_mask);
---- a/arch/arm/common/via82c505.c
-+++ b/arch/arm/common/via82c505.c
-@@ -86,7 +86,8 @@ int __init via82c505_setup(int nr, struc
- struct pci_bus * __init via82c505_scan_bus(int nr, struct pci_sys_data *sysdata)
- {
- if (nr == 0)
-- return pci_scan_bus(0, &via82c505_ops, sysdata);
-+ return pci_scan_root_bus(NULL, 0, &via82c505_ops, sysdata,
-+ &sysdata->resources);
-
- return NULL;
- }
---- a/arch/arm/include/asm/mach/pci.h
-+++ b/arch/arm/include/asm/mach/pci.h
-@@ -40,7 +40,7 @@ struct pci_sys_data {
- u64 mem_offset; /* bus->cpu memory mapping offset */
- unsigned long io_offset; /* bus->cpu IO mapping offset */
- struct pci_bus *bus; /* PCI bus */
-- struct resource *resource[3]; /* Primary PCI bus resources */
-+ struct list_head resources; /* root bus resources (apertures) */
- /* Bridge swizzling */
- u8 (*swizzle)(struct pci_dev *, u8 *);
- /* IRQ mapping */
---- a/arch/arm/kernel/bios32.c
-+++ b/arch/arm/kernel/bios32.c
-@@ -316,21 +316,6 @@ pdev_fixup_device_resources(struct pci_s
- }
- }
-
--static void __devinit
--pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root)
--{
-- struct pci_dev *dev = bus->self;
-- int i;
--
-- if (!dev) {
-- /*
-- * Assign root bus resources.
-- */
-- for (i = 0; i < 3; i++)
-- bus->resource[i] = root->resource[i];
-- }
--}
--
- /*
- * pcibios_fixup_bus - Called after each bus is probed,
- * but before its children are examined.
-@@ -341,8 +326,6 @@ void pcibios_fixup_bus(struct pci_bus *b
- struct pci_dev *dev;
- u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK;
-
-- pbus_assign_bus_resources(bus, root);
--
- /*
- * Walk the devices on this bus, working out what we can
- * and can't support.
-@@ -508,12 +491,18 @@ static void __init pcibios_init_hw(struc
- sys->busnr = busnr;
- sys->swizzle = hw->swizzle;
- sys->map_irq = hw->map_irq;
-- sys->resource[0] = &ioport_resource;
-- sys->resource[1] = &iomem_resource;
-+ INIT_LIST_HEAD(&sys->resources);
-
- ret = hw->setup(nr, sys);
-
- if (ret > 0) {
-+ if (list_empty(&sys->resources)) {
-+ pci_add_resource(&sys->resources,
-+ &ioport_resource);
-+ pci_add_resource(&sys->resources,
-+ &iomem_resource);
-+ }
-+
- sys->bus = hw->scan(nr, sys);
-
- if (!sys->bus)
---- a/arch/arm/mach-cns3xxx/pcie.c
-+++ b/arch/arm/mach-cns3xxx/pcie.c
-@@ -151,13 +151,12 @@ static int cns3xxx_pci_setup(int nr, str
- struct cns3xxx_pcie *cnspci = sysdata_to_cnspci(sys);
- struct resource *res_io = &cnspci->res_io;
- struct resource *res_mem = &cnspci->res_mem;
-- struct resource **sysres = sys->resource;
-
- BUG_ON(request_resource(&iomem_resource, res_io) ||
- request_resource(&iomem_resource, res_mem));
-
-- sysres[0] = res_io;
-- sysres[1] = res_mem;
-+ pci_add_resource(&sys->resources, res_io);
-+ pci_add_resource(&sys->resources, res_mem);
-
- return 1;
- }
-@@ -169,7 +168,8 @@ static struct pci_ops cns3xxx_pcie_ops =
-
- static struct pci_bus *cns3xxx_pci_scan_bus(int nr, struct pci_sys_data *sys)
- {
-- return pci_scan_bus(sys->busnr, &cns3xxx_pcie_ops, sys);
-+ return pci_scan_root_bus(NULL, sys->busnr, &cns3xxx_pcie_ops, sys,
-+ &sys->resources);
- }
-
- static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
---- a/arch/arm/mach-dove/pcie.c
-+++ b/arch/arm/mach-dove/pcie.c
-@@ -69,7 +69,7 @@ static int __init dove_pcie_setup(int nr
- pp->res[0].flags = IORESOURCE_IO;
- if (request_resource(&ioport_resource, &pp->res[0]))
- panic("Request PCIe IO resource failed\n");
-- sys->resource[0] = &pp->res[0];
-+ pci_add_resource(&sys->resources, &pp->res[0]);
-
- /*
- * IORESOURCE_MEM
-@@ -88,9 +88,7 @@ static int __init dove_pcie_setup(int nr
- pp->res[1].flags = IORESOURCE_MEM;
- if (request_resource(&iomem_resource, &pp->res[1]))
- panic("Request PCIe Memory resource failed\n");
-- sys->resource[1] = &pp->res[1];
--
-- sys->resource[2] = NULL;
-+ pci_add_resource(&sys->resources, &pp->res[1]);
-
- return 1;
- }
-@@ -184,7 +182,8 @@ dove_pcie_scan_bus(int nr, struct pci_sy
- struct pci_bus *bus;
-
- if (nr < num_pcie_ports) {
-- bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
-+ bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
-+ &sys->resources);
- } else {
- bus = NULL;
- BUG();
---- a/arch/arm/mach-footbridge/dc21285.c
-+++ b/arch/arm/mach-footbridge/dc21285.c
-@@ -275,9 +275,9 @@ int __init dc21285_setup(int nr, struct
- allocate_resource(&iomem_resource, &res[0], 0x40000000,
- 0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
-
-- sys->resource[0] = &ioport_resource;
-- sys->resource[1] = &res[0];
-- sys->resource[2] = &res[1];
-+ pci_add_resource(&sys->resources, &ioport_resource);
-+ pci_add_resource(&sys->resources, &res[0]);
-+ pci_add_resource(&sys->resources, &res[1]);
- sys->mem_offset = DC21285_PCI_MEM;
-
- return 1;
-@@ -285,7 +285,7 @@ int __init dc21285_setup(int nr, struct
-
- struct pci_bus * __init dc21285_scan_bus(int nr, struct pci_sys_data *sys)
- {
-- return pci_scan_bus(0, &dc21285_ops, sys);
-+ return pci_scan_root_bus(NULL, 0, &dc21285_ops, sys, &sys->resources);
- }
-
- #define dc21285_request_irq(_a, _b, _c, _d, _e) \
---- a/arch/arm/mach-integrator/pci_v3.c
-+++ b/arch/arm/mach-integrator/pci_v3.c
-@@ -359,7 +359,7 @@ static struct resource pre_mem = {
- .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH,
- };
-
--static int __init pci_v3_setup_resources(struct resource **resource)
-+static int __init pci_v3_setup_resources(struct pci_sys_data *sys)
- {
- if (request_resource(&iomem_resource, &non_mem)) {
- printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
-@@ -374,13 +374,13 @@ static int __init pci_v3_setup_resources
- }
-
- /*
-- * bus->resource[0] is the IO resource for this bus
-- * bus->resource[1] is the mem resource for this bus
-- * bus->resource[2] is the prefetch mem resource for this bus
-+ * the IO resource for this bus
-+ * the mem resource for this bus
-+ * the prefetch mem resource for this bus
- */
-- resource[0] = &ioport_resource;
-- resource[1] = &non_mem;
-- resource[2] = &pre_mem;
-+ pci_add_resource(&sys->resources, &ioport_resource);
-+ pci_add_resource(&sys->resources, &non_mem);
-+ pci_add_resource(&sys->resources, &pre_mem);
-
- return 1;
- }
-@@ -481,7 +481,7 @@ int __init pci_v3_setup(int nr, struct p
-
- if (nr == 0) {
- sys->mem_offset = PHYS_PCI_MEM_BASE;
-- ret = pci_v3_setup_resources(sys->resource);
-+ ret = pci_v3_setup_resources(sys);
- }
-
- return ret;
-@@ -489,7 +489,8 @@ int __init pci_v3_setup(int nr, struct p
-
- struct pci_bus * __init pci_v3_scan_bus(int nr, struct pci_sys_data *sys)
- {
-- return pci_scan_bus(sys->busnr, &pci_v3_ops, sys);
-+ return pci_scan_root_bus(NULL, sys->busnr, &pci_v3_ops, sys,
-+ &sys->resources);
- }
-
- /*
---- a/arch/arm/mach-iop13xx/pci.c
-+++ b/arch/arm/mach-iop13xx/pci.c
-@@ -537,14 +537,14 @@ struct pci_bus *iop13xx_scan_bus(int nr,
- while(time_before(jiffies, atux_trhfa_timeout))
- udelay(100);
-
-- bus = pci_bus_atux = pci_scan_bus(sys->busnr,
-- &iop13xx_atux_ops,
-- sys);
-+ bus = pci_bus_atux = pci_scan_root_bus(NULL, sys->busnr,
-+ &iop13xx_atux_ops,
-+ sys, &sys->resources);
- break;
- case IOP13XX_INIT_ATU_ATUE:
-- bus = pci_bus_atue = pci_scan_bus(sys->busnr,
-- &iop13xx_atue_ops,
-- sys);
-+ bus = pci_bus_atue = pci_scan_root_bus(NULL, sys->busnr,
-+ &iop13xx_atue_ops,
-+ sys, &sys->resources);
- break;
- }
-
-@@ -1084,9 +1084,8 @@ int iop13xx_pci_setup(int nr, struct pci
- request_resource(&ioport_resource, &res[0]);
- request_resource(&iomem_resource, &res[1]);
-
-- sys->resource[0] = &res[0];
-- sys->resource[1] = &res[1];
-- sys->resource[2] = NULL;
-+ pci_add_resource(&sys->resources, &res[0]);
-+ pci_add_resource(&sys->resources, &res[1]);
-
- return 1;
- }
---- a/arch/arm/mach-ixp2000/enp2611.c
-+++ b/arch/arm/mach-ixp2000/enp2611.c
-@@ -145,7 +145,8 @@ static struct pci_ops enp2611_pci_ops =
- static struct pci_bus * __init enp2611_pci_scan_bus(int nr,
- struct pci_sys_data *sys)
- {
-- return pci_scan_bus(sys->busnr, &enp2611_pci_ops, sys);
-+ return pci_scan_root_bus(NULL, sys->busnr, &enp2611_pci_ops, sys,
-+ &sys->resources);
- }
-
- static int __init enp2611_pci_map_irq(const struct pci_dev *dev, u8 slot,
---- a/arch/arm/mach-ixp2000/pci.c
-+++ b/arch/arm/mach-ixp2000/pci.c
-@@ -132,7 +132,8 @@ static struct pci_ops ixp2000_pci_ops =
-
- struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
- {
-- return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata);
-+ return pci_scan_root_bus(NULL, sysdata->busnr, &ixp2000_pci_ops,
-+ sysdata, &sysdata->resources);
- }
-
-
-@@ -242,9 +243,8 @@ int ixp2000_pci_setup(int nr, struct pci
- if (nr >= 1)
- return 0;
-
-- sys->resource[0] = &ixp2000_pci_io_space;
-- sys->resource[1] = &ixp2000_pci_mem_space;
-- sys->resource[2] = NULL;
-+ pci_add_resource(&sys->resources, &ixp2000_pci_io_space);
-+ pci_add_resource(&sys->resources, &ixp2000_pci_mem_space);
-
- return 1;
- }
---- a/arch/arm/mach-ixp23xx/pci.c
-+++ b/arch/arm/mach-ixp23xx/pci.c
-@@ -143,7 +143,8 @@ struct pci_ops ixp23xx_pci_ops = {
-
- struct pci_bus *ixp23xx_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
- {
-- return pci_scan_bus(sysdata->busnr, &ixp23xx_pci_ops, sysdata);
-+ return pci_scan_root_bus(NULL, sysdata->busnr, &ixp23xx_pci_ops,
-+ sysdata, &sysdata->resources);
- }
-
- int ixp23xx_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
-@@ -280,9 +281,8 @@ int ixp23xx_pci_setup(int nr, struct pci
- if (nr >= 1)
- return 0;
-
-- sys->resource[0] = &ixp23xx_pci_io_space;
-- sys->resource[1] = &ixp23xx_pci_mem_space;
-- sys->resource[2] = NULL;
-+ pci_add_resource(&sys->resources, &ixp23xx_pci_io_space);
-+ pci_add_resource(&sys->resources, &ixp23xx_pci_mem_space);
-
- return 1;
- }
---- a/arch/arm/mach-ixp4xx/common-pci.c
-+++ b/arch/arm/mach-ixp4xx/common-pci.c
-@@ -472,9 +472,8 @@ int ixp4xx_setup(int nr, struct pci_sys_
- request_resource(&ioport_resource, &res[0]);
- request_resource(&iomem_resource, &res[1]);
-
-- sys->resource[0] = &res[0];
-- sys->resource[1] = &res[1];
-- sys->resource[2] = NULL;
-+ pci_add_resource(&sys->resources, &res[0]);
-+ pci_add_resource(&sys->resources, &res[1]);
-
- platform_notify = ixp4xx_pci_platform_notify;
- platform_notify_remove = ixp4xx_pci_platform_notify_remove;
-@@ -484,7 +483,8 @@ int ixp4xx_setup(int nr, struct pci_sys_
-
- struct pci_bus * __devinit ixp4xx_scan_bus(int nr, struct pci_sys_data *sys)
- {
-- return pci_scan_bus(sys->busnr, &ixp4xx_ops, sys);
-+ return pci_scan_root_bus(NULL, sys->busnr, &ixp4xx_ops, sys,
-+ &sys->resources);
- }
-
- int dma_set_coherent_mask(struct device *dev, u64 mask)
---- a/arch/arm/mach-kirkwood/pcie.c
-+++ b/arch/arm/mach-kirkwood/pcie.c
-@@ -198,9 +198,8 @@ static int __init kirkwood_pcie_setup(in
- if (request_resource(&iomem_resource, &pp->res[1]))
- panic("Request PCIe%d Memory resource failed\n", index);
-
-- sys->resource[0] = &pp->res[0];
-- sys->resource[1] = &pp->res[1];
-- sys->resource[2] = NULL;
-+ pci_add_resource(&sys->resources, &pp->res[0]);
-+ pci_add_resource(&sys->resources, &pp->res[1]);
- sys->io_offset = 0;
-
- /*
-@@ -236,7 +235,8 @@ kirkwood_pcie_scan_bus(int nr, struct pc
- struct pci_bus *bus;
-
- if (nr < num_pcie_ports) {
-- bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
-+ bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
-+ &sys->resources);
- } else {
- bus = NULL;
- BUG();
---- a/arch/arm/mach-ks8695/pci.c
-+++ b/arch/arm/mach-ks8695/pci.c
-@@ -143,7 +143,8 @@ static struct pci_ops ks8695_pci_ops = {
-
- static struct pci_bus* __init ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys)
- {
-- return pci_scan_bus(sys->busnr, &ks8695_pci_ops, sys);
-+ return pci_scan_root_bus(NULL, sys->busnr, &ks8695_pci_ops, sys,
-+ &sys->resources);
- }
-
- static struct resource pci_mem = {
-@@ -168,9 +169,8 @@ static int __init ks8695_pci_setup(int n
- request_resource(&iomem_resource, &pci_mem);
- request_resource(&ioport_resource, &pci_io);
-
-- sys->resource[0] = &pci_io;
-- sys->resource[1] = &pci_mem;
-- sys->resource[2] = NULL;
-+ pci_add_resource(&sys->resources, &pci_io);
-+ pci_add_resource(&sys->resources, &pci_mem);
-
- /* Assign and enable processor bridge */
- ks8695_local_writeconfig(PCI_BASE_ADDRESS_0, KS8695_PCIMEM_PA);
---- a/arch/arm/mach-mv78xx0/pcie.c
-+++ b/arch/arm/mach-mv78xx0/pcie.c
-@@ -155,9 +155,8 @@ static int __init mv78xx0_pcie_setup(int
- orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
- orion_pcie_setup(pp->base, &mv78xx0_mbus_dram_info);
-
-- sys->resource[0] = &pp->res[0];
-- sys->resource[1] = &pp->res[1];
-- sys->resource[2] = NULL;
-+ pci_add_resource(&sys->resources, &pp->res[0]);
-+ pci_add_resource(&sys->resources, &pp->res[1]);
-
- return 1;
- }
-@@ -251,7 +250,8 @@ mv78xx0_pcie_scan_bus(int nr, struct pci
- struct pci_bus *bus;
-
- if (nr < num_pcie_ports) {
-- bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
-+ bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
-+ &sys->resources);
- } else {
- bus = NULL;
- BUG();
---- a/arch/arm/mach-orion5x/pci.c
-+++ b/arch/arm/mach-orion5x/pci.c
-@@ -176,7 +176,7 @@ static int __init pcie_setup(struct pci_
- res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1;
- if (request_resource(&ioport_resource, &res[0]))
- panic("Request PCIe IO resource failed\n");
-- sys->resource[0] = &res[0];
-+ pci_add_resource(&sys->resources, &res[0]);
-
- /*
- * IORESOURCE_MEM
-@@ -187,9 +187,8 @@ static int __init pcie_setup(struct pci_
- res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1;
- if (request_resource(&iomem_resource, &res[1]))
- panic("Request PCIe Memory resource failed\n");
-- sys->resource[1] = &res[1];
-+ pci_add_resource(&sys->resources, &res[1]);
-
-- sys->resource[2] = NULL;
- sys->io_offset = 0;
-
- return 1;
-@@ -505,7 +504,7 @@ static int __init pci_setup(struct pci_s
- res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1;
- if (request_resource(&ioport_resource, &res[0]))
- panic("Request PCI IO resource failed\n");
-- sys->resource[0] = &res[0];
-+ pci_add_resource(&sys->resources, &res[0]);
-
- /*
- * IORESOURCE_MEM
-@@ -516,9 +515,8 @@ static int __init pci_setup(struct pci_s
- res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1;
- if (request_resource(&iomem_resource, &res[1]))
- panic("Request PCI Memory resource failed\n");
-- sys->resource[1] = &res[1];
-+ pci_add_resource(&sys->resources, &res[1]);
-
-- sys->resource[2] = NULL;
- sys->io_offset = 0;
-
- return 1;
-@@ -579,9 +577,11 @@ struct pci_bus __init *orion5x_pci_sys_s
- struct pci_bus *bus;
-
- if (nr == 0) {
-- bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
-+ bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
-+ &sys->resources);
- } else if (nr == 1 && !orion5x_pci_disabled) {
-- bus = pci_scan_bus(sys->busnr, &pci_ops, sys);
-+ bus = pci_scan_root_bus(NULL, sys->busnr, &pci_ops, sys,
-+ &sys->resources);
- } else {
- bus = NULL;
- BUG();
---- a/arch/arm/mach-sa1100/pci-nanoengine.c
-+++ b/arch/arm/mach-sa1100/pci-nanoengine.c
-@@ -131,7 +131,8 @@ static int __init pci_nanoengine_map_irq
-
- struct pci_bus * __init pci_nanoengine_scan_bus(int nr, struct pci_sys_data *sys)
- {
-- return pci_scan_bus(sys->busnr, &pci_nano_ops, sys);
-+ return pci_scan_root_bus(NULL, sys->busnr, &pci_nano_ops, sys,
-+ &sys->resources);
- }
-
- static struct resource pci_io_ports = {
-@@ -226,7 +227,7 @@ static struct resource pci_prefetchable_
- .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH,
- };
-
--static int __init pci_nanoengine_setup_resources(struct resource **resource)
-+static int __init pci_nanoengine_setup_resources(struct pci_sys_data *sys)
- {
- if (request_resource(&ioport_resource, &pci_io_ports)) {
- printk(KERN_ERR "PCI: unable to allocate io port region\n");
-@@ -243,9 +244,9 @@ static int __init pci_nanoengine_setup_r
- printk(KERN_ERR "PCI: unable to allocate prefetchable\n");
- return -EBUSY;
- }
-- resource[0] = &pci_io_ports;
-- resource[1] = &pci_non_prefetchable_memory;
-- resource[2] = &pci_prefetchable_memory;
-+ pci_add_resource(&sys->resources, &pci_io_ports);
-+ pci_add_resource(&sys->resources, &pci_non_prefetchable_memory);
-+ pci_add_resource(&sys->resources, &pci_prefetchable_memory);
-
- return 1;
- }
-@@ -260,7 +261,7 @@ int __init pci_nanoengine_setup(int nr,
- if (nr == 0) {
- sys->mem_offset = NANO_PCI_MEM_RW_PHYS;
- sys->io_offset = 0x400;
-- ret = pci_nanoengine_setup_resources(sys->resource);
-+ ret = pci_nanoengine_setup_resources(sys);
- /* Enable alternate memory bus master mode, see
- * "Intel StrongARM SA1110 Developer's Manual",
- * section 10.8, "Alternate Memory Bus Master Mode". */
---- a/arch/arm/mach-tegra/pcie.c
-+++ b/arch/arm/mach-tegra/pcie.c
-@@ -409,7 +409,7 @@ static int tegra_pcie_setup(int nr, stru
- pp->res[0].flags = IORESOURCE_IO;
- if (request_resource(&ioport_resource, &pp->res[0]))
- panic("Request PCIe IO resource failed\n");
-- sys->resource[0] = &pp->res[0];
-+ pci_add_resource(&sys->resources, &pp->res[0]);
-
- /*
- * IORESOURCE_MEM
-@@ -428,7 +428,7 @@ static int tegra_pcie_setup(int nr, stru
- pp->res[1].flags = IORESOURCE_MEM;
- if (request_resource(&iomem_resource, &pp->res[1]))
- panic("Request PCIe Memory resource failed\n");
-- sys->resource[1] = &pp->res[1];
-+ pci_add_resource(&sys->resources, &pp->res[1]);
-
- /*
- * IORESOURCE_MEM | IORESOURCE_PREFETCH
-@@ -447,7 +447,7 @@ static int tegra_pcie_setup(int nr, stru
- pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
- if (request_resource(&iomem_resource, &pp->res[2]))
- panic("Request PCIe Prefetch Memory resource failed\n");
-- sys->resource[2] = &pp->res[2];
-+ pci_add_resource(&sys->resources, &pp->res[2]);
-
- return 1;
- }
-@@ -468,7 +468,8 @@ static struct pci_bus __init *tegra_pcie
- pp = tegra_pcie.port + nr;
- pp->root_bus_nr = sys->busnr;
-
-- return pci_scan_bus(sys->busnr, &tegra_pcie_ops, sys);
-+ return pci_scan_root_bus(NULL, sys->busnr, &tegra_pcie_ops, sys,
-+ &sys->resources);
- }
-
- static struct hw_pci tegra_pcie_hw __initdata = {
---- a/arch/arm/mach-versatile/pci.c
-+++ b/arch/arm/mach-versatile/pci.c
-@@ -191,7 +191,7 @@ static struct resource pre_mem = {
- .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH,
- };
-
--static int __init pci_versatile_setup_resources(struct resource **resource)
-+static int __init pci_versatile_setup_resources(struct list_head *resources)
- {
- int ret = 0;
-
-@@ -215,13 +215,13 @@ static int __init pci_versatile_setup_re
- }
-
- /*
-- * bus->resource[0] is the IO resource for this bus
-- * bus->resource[1] is the mem resource for this bus
-- * bus->resource[2] is the prefetch mem resource for this bus
-+ * the IO resource for this bus
-+ * the mem resource for this bus
-+ * the prefetch mem resource for this bus
- */
-- resource[0] = &io_mem;
-- resource[1] = &non_mem;
-- resource[2] = &pre_mem;
-+ pci_add_resource(resources, &io_mem);
-+ pci_add_resource(resources, &non_mem);
-+ pci_add_resource(resources, &pre_mem);
-
- goto out;
-
-@@ -250,7 +250,7 @@ int __init pci_versatile_setup(int nr, s
-
- if (nr == 0) {
- sys->mem_offset = 0;
-- ret = pci_versatile_setup_resources(sys->resource);
-+ ret = pci_versatile_setup_resources(&sys->resources);
- if (ret < 0) {
- printk("pci_versatile_setup: resources... oops?\n");
- goto out;
-@@ -306,7 +306,8 @@ int __init pci_versatile_setup(int nr, s
-
- struct pci_bus * __init pci_versatile_scan_bus(int nr, struct pci_sys_data *sys)
- {
-- return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys);
-+ return pci_scan_root_bus(NULL, sys->busnr, &pci_versatile_ops, sys,
-+ &sys->resources);
- }
-
- void __init pci_versatile_preinit(void)
---- a/arch/arm/plat-iop/pci.c
-+++ b/arch/arm/plat-iop/pci.c
-@@ -215,16 +215,16 @@ int iop3xx_pci_setup(int nr, struct pci_
- sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
- sys->io_offset = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR;
-
-- sys->resource[0] = &res[0];
-- sys->resource[1] = &res[1];
-- sys->resource[2] = NULL;
-+ pci_add_resource(&sys->resources, &res[0]);
-+ pci_add_resource(&sys->resources, &res[1]);
-
- return 1;
- }
-
- struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys)
- {
-- return pci_scan_bus(sys->busnr, &iop3xx_ops, sys);
-+ return pci_scan_root_bus(NULL, sys->busnr, &iop3xx_ops, sys,
-+ &sys->resources);
- }
-
- void __init iop3xx_atu_setup(void)
---- a/arch/frv/mb93090-mb00/pci-vdk.c
-+++ b/arch/frv/mb93090-mb00/pci-vdk.c
-@@ -327,11 +327,6 @@ void __init pcibios_fixup_bus(struct pci
- printk("### PCIBIOS_FIXUP_BUS(%d)\n",bus->number);
- #endif
-
-- if (bus->number == 0) {
-- bus->resource[0] = &pci_ioport_resource;
-- bus->resource[1] = &pci_iomem_resource;
-- }
--
- pci_read_bridge_bases(bus);
-
- if (bus->number == 0) {
-@@ -357,6 +352,7 @@ void __init pcibios_fixup_bus(struct pci
- int __init pcibios_init(void)
- {
- struct pci_ops *dir = NULL;
-+ LIST_HEAD(resources);
-
- if (!mb93090_mb00_detected)
- return -ENXIO;
-@@ -420,7 +416,10 @@ int __init pcibios_init(void)
- }
-
- printk("PCI: Probing PCI hardware\n");
-- pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
-+ pci_add_resource(&resources, &pci_ioport_resource);
-+ pci_add_resource(&resources, &pci_iomem_resource);
-+ pci_root_bus = pci_scan_root_bus(NULL, 0, pci_root_ops, NULL,
-+ &resources);
-
- pcibios_irq_init();
- pcibios_fixup_peer_bridges();
---- a/arch/ia64/pci/pci.c
-+++ b/arch/ia64/pci/pci.c
-@@ -134,6 +134,7 @@ alloc_pci_controller (int seg)
- struct pci_root_info {
- struct acpi_device *bridge;
- struct pci_controller *controller;
-+ struct list_head resources;
- char *name;
- };
-
-@@ -315,24 +316,13 @@ static __devinit acpi_status add_window(
- &window->resource);
- }
-
-- return AE_OK;
--}
-+ /* HP's firmware has a hack to work around a Windows bug.
-+ * Ignore these tiny memory ranges */
-+ if (!((window->resource.flags & IORESOURCE_MEM) &&
-+ (window->resource.end - window->resource.start < 16)))
-+ pci_add_resource(&info->resources, &window->resource);
-
--static void __devinit
--pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
--{
-- int i;
--
-- pci_bus_remove_resources(bus);
-- for (i = 0; i < ctrl->windows; i++) {
-- struct resource *res = &ctrl->window[i].resource;
-- /* HP's firmware has a hack to work around a Windows bug.
-- * Ignore these tiny memory ranges */
-- if ((res->flags & IORESOURCE_MEM) &&
-- (res->end - res->start < 16))
-- continue;
-- pci_bus_add_resource(bus, res, 0);
-- }
-+ return AE_OK;
- }
-
- struct pci_bus * __devinit
-@@ -343,6 +333,7 @@ pci_acpi_scan_root(struct acpi_pci_root
- int bus = root->secondary.start;
- struct pci_controller *controller;
- unsigned int windows = 0;
-+ struct pci_root_info info;
- struct pci_bus *pbus;
- char *name;
- int pxm;
-@@ -359,11 +350,10 @@ pci_acpi_scan_root(struct acpi_pci_root
- controller->node = pxm_to_node(pxm);
- #endif
-
-+ INIT_LIST_HEAD(&info.resources);
- acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
- &windows);
- if (windows) {
-- struct pci_root_info info;
--
- controller->window =
- kmalloc_node(sizeof(*controller->window) * windows,
- GFP_KERNEL, controller->node);
-@@ -387,8 +377,14 @@ pci_acpi_scan_root(struct acpi_pci_root
- * should handle the case here, but it appears that IA64 hasn't
- * such quirk. So we just ignore the case now.
- */
-- pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
-+ pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller,
-+ &info.resources);
-+ if (!pbus) {
-+ pci_free_resource_list(&info.resources);
-+ return NULL;
-+ }
-
-+ pbus->subordinate = pci_scan_child_bus(pbus);
- return pbus;
-
- out3:
-@@ -504,14 +500,10 @@ pcibios_fixup_bus (struct pci_bus *b)
- if (b->self) {
- pci_read_bridge_bases(b);
- pcibios_fixup_bridge_resources(b->self);
-- } else {
-- pcibios_setup_root_windows(b, b->sysdata);
- }
- list_for_each_entry(dev, &b->devices, bus_list)
- pcibios_fixup_device_resources(dev);
- platform_pci_fixup_bus(b);
--
-- return;
- }
-
- void __devinit
---- a/arch/microblaze/include/asm/pci-bridge.h
-+++ b/arch/microblaze/include/asm/pci-bridge.h
-@@ -140,7 +140,6 @@ extern void pci_process_bridge_OF_ranges
- /* Allocate & free a PCI host bridge structure */
- extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
- extern void pcibios_free_controller(struct pci_controller *phb);
--extern void pcibios_setup_phb_resources(struct pci_controller *hose);
-
- #endif /* __KERNEL__ */
- #endif /* _ASM_MICROBLAZE_PCI_BRIDGE_H */
---- a/arch/microblaze/pci/pci-common.c
-+++ b/arch/microblaze/pci/pci-common.c
-@@ -1019,7 +1019,6 @@ static void __devinit pcibios_fixup_brid
- struct pci_dev *dev = bus->self;
-
- pci_bus_for_each_resource(bus, res, i) {
-- res = bus->resource[i];
- if (!res)
- continue;
- if (!res->flags)
-@@ -1219,7 +1218,6 @@ void pcibios_allocate_bus_resources(stru
- pci_domain_nr(bus), bus->number);
-
- pci_bus_for_each_resource(bus, res, i) {
-- res = bus->resource[i];
- if (!res || !res->flags
- || res->start > res->end || res->parent)
- continue;
-@@ -1510,14 +1508,18 @@ int pcibios_enable_device(struct pci_dev
- return pci_enable_resources(dev, mask);
- }
-
--void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
-+static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
- {
-- struct pci_bus *bus = hose->bus;
- struct resource *res;
- int i;
-
- /* Hookup PHB IO resource */
-- bus->resource[0] = res = &hose->io_resource;
-+ res = &hose->io_resource;
-+
-+ /* Fixup IO space offset */
-+ io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-+ res->start = (res->start + io_offset) & 0xffffffffu;
-+ res->end = (res->end + io_offset) & 0xffffffffu;
-
- if (!res->flags) {
- printk(KERN_WARNING "PCI: I/O resource not set for host"
-@@ -1528,6 +1530,7 @@ void __devinit pcibios_setup_phb_resourc
- res->end = res->start + IO_SPACE_LIMIT;
- res->flags = IORESOURCE_IO;
- }
-+ pci_add_resource(resources, res);
-
- pr_debug("PCI: PHB IO resource = %016llx-%016llx [%lx]\n",
- (unsigned long long)res->start,
-@@ -1550,7 +1553,7 @@ void __devinit pcibios_setup_phb_resourc
- res->flags = IORESOURCE_MEM;
-
- }
-- bus->resource[i+1] = res;
-+ pci_add_resource(resources, res);
-
- pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n",
- i, (unsigned long long)res->start,
-@@ -1573,34 +1576,27 @@ struct device_node *pcibios_get_phb_of_n
-
- static void __devinit pcibios_scan_phb(struct pci_controller *hose)
- {
-+ LIST_HEAD(resources);
- struct pci_bus *bus;
- struct device_node *node = hose->dn;
-- unsigned long io_offset;
-- struct resource *res = &hose->io_resource;
-
- pr_debug("PCI: Scanning PHB %s\n",
- node ? node->full_name : "<NO NAME>");
-
-- /* Create an empty bus for the toplevel */
-- bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
-+ pcibios_setup_phb_resources(hose, &resources);
-+
-+ bus = pci_scan_root_bus(hose->parent, hose->first_busno,
-+ hose->ops, hose, &resources);
- if (bus == NULL) {
- printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
- hose->global_number);
-+ pci_free_resource_list(&resources);
- return;
- }
- bus->secondary = hose->first_busno;
- hose->bus = bus;
-
-- /* Fixup IO space offset */
-- io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-- res->start = (res->start + io_offset) & 0xffffffffu;
-- res->end = (res->end + io_offset) & 0xffffffffu;
--
-- /* Wire up PHB bus resources */
-- pcibios_setup_phb_resources(hose);
--
-- /* Scan children */
-- hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
-+ hose->last_busno = bus->subordinate;
- }
-
- static int __init pcibios_init(void)
-@@ -1614,8 +1610,6 @@ static int __init pcibios_init(void)
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- hose->last_busno = 0xff;
- pcibios_scan_phb(hose);
-- printk(KERN_INFO "calling pci_bus_add_devices()\n");
-- pci_bus_add_devices(hose->bus);
- if (next_busno <= hose->last_busno)
- next_busno = hose->last_busno + 1;
- }
---- a/arch/mips/pci/pci.c
-+++ b/arch/mips/pci/pci.c
-@@ -81,6 +81,7 @@ static void __devinit pcibios_scanbus(st
- {
- static int next_busno;
- static int need_domain_info;
-+ LIST_HEAD(resources);
- struct pci_bus *bus;
-
- if (!hose->iommu)
-@@ -89,7 +90,13 @@ static void __devinit pcibios_scanbus(st
- if (hose->get_busno && pci_probe_only)
- next_busno = (*hose->get_busno)();
-
-- bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
-+ pci_add_resource(&resources, hose->mem_resource);
-+ pci_add_resource(&resources, hose->io_resource);
-+ bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
-+ &resources);
-+ if (!bus)
-+ pci_free_resource_list(&resources);
-+
- hose->bus = bus;
-
- need_domain_info = need_domain_info || hose->index;
-@@ -266,15 +273,11 @@ void __devinit pcibios_fixup_bus(struct
- {
- /* Propagate hose info into the subordinate devices. */
-
-- struct pci_controller *hose = bus->sysdata;
- struct list_head *ln;
- struct pci_dev *dev = bus->self;
-
-- if (!dev) {
-- bus->resource[0] = hose->io_resource;
-- bus->resource[1] = hose->mem_resource;
-- } else if (pci_probe_only &&
-- (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
-+ if (pci_probe_only && dev &&
-+ (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
- pci_read_bridge_bases(bus);
- pcibios_fixup_device_resources(dev, bus);
- }
---- a/arch/mn10300/unit-asb2305/pci.c
-+++ b/arch/mn10300/unit-asb2305/pci.c
-@@ -380,11 +380,6 @@ void __devinit pcibios_fixup_bus(struct
- {
- struct pci_dev *dev;
-
-- if (bus->number == 0) {
-- bus->resource[0] = &pci_ioport_resource;
-- bus->resource[1] = &pci_iomem_resource;
-- }
--
- if (bus->self) {
- pci_read_bridge_bases(bus);
- pcibios_fixup_device_resources(bus->self);
-@@ -402,6 +397,8 @@ void __devinit pcibios_fixup_bus(struct
- */
- static int __init pcibios_init(void)
- {
-+ LIST_HEAD(resources);
-+
- ioport_resource.start = 0xA0000000;
- ioport_resource.end = 0xDFFFFFFF;
- iomem_resource.start = 0xA0000000;
-@@ -423,7 +420,10 @@ static int __init pcibios_init(void)
- printk(KERN_INFO "PCI: Probing PCI hardware [mempage %08x]\n",
- MEM_PAGING_REG);
-
-- pci_root_bus = pci_scan_bus(0, &pci_direct_ampci, NULL);
-+ pci_add_resource(&resources, &pci_ioport_resource);
-+ pci_add_resource(&resources, &pci_iomem_resource);
-+ pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL,
-+ &resources);
-
- pcibios_irq_init();
- pcibios_fixup_irqs();
---- a/arch/powerpc/include/asm/pci-bridge.h
-+++ b/arch/powerpc/include/asm/pci-bridge.h
-@@ -222,7 +222,6 @@ extern void pci_process_bridge_OF_ranges
- /* Allocate & free a PCI host bridge structure */
- extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
- extern void pcibios_free_controller(struct pci_controller *phb);
--extern void pcibios_setup_phb_resources(struct pci_controller *hose);
-
- #ifdef CONFIG_PCI
- extern int pcibios_vaddr_is_ioport(void __iomem *address);
---- a/arch/powerpc/kernel/pci-common.c
-+++ b/arch/powerpc/kernel/pci-common.c
-@@ -1555,14 +1555,13 @@ int pcibios_enable_device(struct pci_dev
- return pci_enable_resources(dev, mask);
- }
-
--void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
-+static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
- {
-- struct pci_bus *bus = hose->bus;
- struct resource *res;
- int i;
-
- /* Hookup PHB IO resource */
-- bus->resource[0] = res = &hose->io_resource;
-+ res = &hose->io_resource;
-
- if (!res->flags) {
- printk(KERN_WARNING "PCI: I/O resource not set for host"
-@@ -1580,6 +1579,7 @@ void __devinit pcibios_setup_phb_resourc
- (unsigned long long)res->start,
- (unsigned long long)res->end,
- (unsigned long)res->flags);
-+ pci_add_resource(resources, res);
-
- /* Hookup PHB Memory resources */
- for (i = 0; i < 3; ++i) {
-@@ -1597,12 +1597,12 @@ void __devinit pcibios_setup_phb_resourc
- res->flags = IORESOURCE_MEM;
- #endif /* CONFIG_PPC32 */
- }
-- bus->resource[i+1] = res;
-
- pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i,
- (unsigned long long)res->start,
- (unsigned long long)res->end,
- (unsigned long)res->flags);
-+ pci_add_resource(resources, res);
- }
-
- pr_debug("PCI: PHB MEM offset = %016llx\n",
-@@ -1696,6 +1696,7 @@ struct device_node *pcibios_get_phb_of_n
- */
- void __devinit pcibios_scan_phb(struct pci_controller *hose)
- {
-+ LIST_HEAD(resources);
- struct pci_bus *bus;
- struct device_node *node = hose->dn;
- int mode;
-@@ -1703,22 +1704,24 @@ void __devinit pcibios_scan_phb(struct p
- pr_debug("PCI: Scanning PHB %s\n",
- node ? node->full_name : "<NO NAME>");
-
-+ /* Get some IO space for the new PHB */
-+ pcibios_setup_phb_io_space(hose);
-+
-+ /* Wire up PHB bus resources */
-+ pcibios_setup_phb_resources(hose, &resources);
-+
- /* Create an empty bus for the toplevel */
-- bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
-+ bus = pci_create_root_bus(hose->parent, hose->first_busno,
-+ hose->ops, hose, &resources);
- if (bus == NULL) {
- pr_err("Failed to create bus for PCI domain %04x\n",
- hose->global_number);
-+ pci_free_resource_list(&resources);
- return;
- }
- bus->secondary = hose->first_busno;
- hose->bus = bus;
-
-- /* Get some IO space for the new PHB */
-- pcibios_setup_phb_io_space(hose);
--
-- /* Wire up PHB bus resources */
-- pcibios_setup_phb_resources(hose);
--
- /* Get probe mode and perform scan */
- mode = PCI_PROBE_NORMAL;
- if (node && ppc_md.pci_probe_mode)
---- a/arch/powerpc/kernel/pci_64.c
-+++ b/arch/powerpc/kernel/pci_64.c
-@@ -131,30 +131,13 @@ EXPORT_SYMBOL_GPL(pcibios_unmap_io_space
-
- #endif /* CONFIG_HOTPLUG */
-
--int __devinit pcibios_map_io_space(struct pci_bus *bus)
-+static int __devinit pcibios_map_phb_io_space(struct pci_controller *hose)
- {
- struct vm_struct *area;
- unsigned long phys_page;
- unsigned long size_page;
- unsigned long io_virt_offset;
-- struct pci_controller *hose;
--
-- WARN_ON(bus == NULL);
-
-- /* If this not a PHB, nothing to do, page tables still exist and
-- * thus HPTEs will be faulted in when needed
-- */
-- if (bus->self) {
-- pr_debug("IO mapping for PCI-PCI bridge %s\n",
-- pci_name(bus->self));
-- pr_debug(" virt=0x%016llx...0x%016llx\n",
-- bus->resource[0]->start + _IO_BASE,
-- bus->resource[0]->end + _IO_BASE);
-- return 0;
-- }
--
-- /* Get the host bridge */
-- hose = pci_bus_to_host(bus);
- phys_page = _ALIGN_DOWN(hose->io_base_phys, PAGE_SIZE);
- size_page = _ALIGN_UP(hose->pci_io_size, PAGE_SIZE);
-
-@@ -198,11 +181,30 @@ int __devinit pcibios_map_io_space(struc
-
- return 0;
- }
-+
-+int __devinit pcibios_map_io_space(struct pci_bus *bus)
-+{
-+ WARN_ON(bus == NULL);
-+
-+ /* If this not a PHB, nothing to do, page tables still exist and
-+ * thus HPTEs will be faulted in when needed
-+ */
-+ if (bus->self) {
-+ pr_debug("IO mapping for PCI-PCI bridge %s\n",
-+ pci_name(bus->self));
-+ pr_debug(" virt=0x%016llx...0x%016llx\n",
-+ bus->resource[0]->start + _IO_BASE,
-+ bus->resource[0]->end + _IO_BASE);
-+ return 0;
-+ }
-+
-+ return pcibios_map_phb_io_space(pci_bus_to_host(bus));
-+}
- EXPORT_SYMBOL_GPL(pcibios_map_io_space);
-
- void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
- {
-- pcibios_map_io_space(hose->bus);
-+ pcibios_map_phb_io_space(hose);
- }
-
- #define IOBASE_BRIDGE_NUMBER 0
---- a/arch/sh/drivers/pci/pci.c
-+++ b/arch/sh/drivers/pci/pci.c
-@@ -36,9 +36,15 @@ static void __devinit pcibios_scanbus(st
- {
- static int next_busno;
- static int need_domain_info;
-+ LIST_HEAD(resources);
-+ int i;
- struct pci_bus *bus;
-
-- bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
-+ for (i = 0; i < hose->nr_resources; i++)
-+ pci_add_resource(&resources, hose->resources + i);
-+
-+ bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
-+ &resources);
- hose->bus = bus;
-
- need_domain_info = need_domain_info || hose->index;
-@@ -55,6 +61,8 @@ static void __devinit pcibios_scanbus(st
- pci_bus_size_bridges(bus);
- pci_bus_assign_resources(bus);
- pci_enable_bridges(bus);
-+ } else {
-+ pci_free_resource_list(&resources);
- }
- }
-
-@@ -162,16 +170,8 @@ static void pcibios_fixup_device_resourc
- */
- void __devinit pcibios_fixup_bus(struct pci_bus *bus)
- {
-- struct pci_dev *dev = bus->self;
-+ struct pci_dev *dev;
- struct list_head *ln;
-- struct pci_channel *hose = bus->sysdata;
--
-- if (!dev) {
-- int i;
--
-- for (i = 0; i < hose->nr_resources; i++)
-- bus->resource[i] = hose->resources + i;
-- }
-
- for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
- dev = pci_dev_b(ln);
---- a/arch/sparc/kernel/leon_pci.c
-+++ b/arch/sparc/kernel/leon_pci.c
-@@ -19,22 +19,22 @@
- */
- void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
- {
-+ LIST_HEAD(resources);
- struct pci_bus *root_bus;
-
-- root_bus = pci_scan_bus_parented(&ofdev->dev, 0, info->ops, info);
-- if (root_bus) {
-- root_bus->resource[0] = &info->io_space;
-- root_bus->resource[1] = &info->mem_space;
-- root_bus->resource[2] = NULL;
--
-- /* Init all PCI devices into PCI tree */
-- pci_bus_add_devices(root_bus);
-+ pci_add_resource(&resources, &info->io_space);
-+ pci_add_resource(&resources, &info->mem_space);
-
-+ root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
-+ &resources);
-+ if (root_bus) {
- /* Setup IRQs of all devices using custom routines */
- pci_fixup_irqs(pci_common_swizzle, info->map_irq);
-
- /* Assign devices with resources */
- pci_assign_unassigned_resources();
-+ } else {
-+ pci_free_resource_list(&resources);
- }
- }
-
-@@ -83,15 +83,6 @@ void __devinit pcibios_fixup_bus(struct
- int i, has_io, has_mem;
- u16 cmd;
-
-- /* Generic PCI bus probing sets these to point at
-- * &io{port,mem}_resouce which is wrong for us.
-- */
-- if (pbus->self == NULL) {
-- pbus->resource[0] = &info->io_space;
-- pbus->resource[1] = &info->mem_space;
-- pbus->resource[2] = NULL;
-- }
--
- list_for_each_entry(dev, &pbus->devices, bus_list) {
- /*
- * We can not rely on that the bootloader has enabled I/O
---- a/arch/sparc/kernel/pci.c
-+++ b/arch/sparc/kernel/pci.c
-@@ -685,23 +685,25 @@ static void __devinit pci_bus_register_o
- struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
- struct device *parent)
- {
-+ LIST_HEAD(resources);
- struct device_node *node = pbm->op->dev.of_node;
- struct pci_bus *bus;
-
- printk("PCI: Scanning PBM %s\n", node->full_name);
-
-- bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm);
-+ pci_add_resource(&resources, &pbm->io_space);
-+ pci_add_resource(&resources, &pbm->mem_space);
-+ bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
-+ pbm, &resources);
- if (!bus) {
- printk(KERN_ERR "Failed to create bus for %s\n",
- node->full_name);
-+ pci_free_resource_list(&resources);
- return NULL;
- }
- bus->secondary = pbm->pci_first_busno;
- bus->subordinate = pbm->pci_last_busno;
-
-- bus->resource[0] = &pbm->io_space;
-- bus->resource[1] = &pbm->mem_space;
--
- pci_of_scan_bus(pbm, node, bus);
- pci_bus_add_devices(bus);
- pci_bus_register_of_sysfs(bus);
-@@ -711,13 +713,6 @@ struct pci_bus * __devinit pci_scan_one_
-
- void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
- {
-- struct pci_pbm_info *pbm = pbus->sysdata;
--
-- /* Generic PCI bus probing sets these to point at
-- * &io{port,mem}_resouce which is wrong for us.
-- */
-- pbus->resource[0] = &pbm->io_space;
-- pbus->resource[1] = &pbm->mem_space;
- }
-
- void pcibios_update_irq(struct pci_dev *pdev, int irq)
---- a/arch/x86/include/asm/topology.h
-+++ b/arch/x86/include/asm/topology.h
-@@ -174,7 +174,7 @@ static inline void arch_fix_phys_package
- }
-
- struct pci_bus;
--void x86_pci_root_bus_res_quirks(struct pci_bus *b);
-+void x86_pci_root_bus_resources(int bus, struct list_head *resources);
-
- #ifdef CONFIG_SMP
- #define mc_capable() ((boot_cpu_data.x86_max_cores > 1) && \
---- a/arch/x86/pci/acpi.c
-+++ b/arch/x86/pci/acpi.c
-@@ -12,7 +12,7 @@ struct pci_root_info {
- char *name;
- unsigned int res_num;
- struct resource *res;
-- struct pci_bus *bus;
-+ struct list_head *resources;
- int busnum;
- };
-
-@@ -275,23 +275,20 @@ static void add_resources(struct pci_roo
- "ignoring host bridge window %pR (conflicts with %s %pR)\n",
- res, conflict->name, conflict);
- else
-- pci_bus_add_resource(info->bus, res, 0);
-+ pci_add_resource(info->resources, res);
- }
- }
-
- static void
- get_current_resources(struct acpi_device *device, int busnum,
-- int domain, struct pci_bus *bus)
-+ int domain, struct list_head *resources)
- {
- struct pci_root_info info;
- size_t size;
-
-- if (pci_use_crs)
-- pci_bus_remove_resources(bus);
--
- info.bridge = device;
-- info.bus = bus;
- info.res_num = 0;
-+ info.resources = resources;
- acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
- &info);
- if (!info.res_num)
-@@ -300,7 +297,7 @@ get_current_resources(struct acpi_device
- size = sizeof(*info.res) * info.res_num;
- info.res = kmalloc(size, GFP_KERNEL);
- if (!info.res)
-- goto res_alloc_fail;
-+ return;
-
- info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum);
- if (!info.name)
-@@ -315,8 +312,6 @@ get_current_resources(struct acpi_device
-
- name_alloc_fail:
- kfree(info.res);
--res_alloc_fail:
-- return;
- }
-
- struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
-@@ -324,6 +319,7 @@ struct pci_bus * __devinit pci_acpi_scan
- struct acpi_device *device = root->device;
- int domain = root->segment;
- int busnum = root->secondary.start;
-+ LIST_HEAD(resources);
- struct pci_bus *bus;
- struct pci_sysdata *sd;
- int node;
-@@ -378,11 +374,15 @@ struct pci_bus * __devinit pci_acpi_scan
- memcpy(bus->sysdata, sd, sizeof(*sd));
- kfree(sd);
- } else {
-- bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd);
-- if (bus) {
-- get_current_resources(device, busnum, domain, bus);
-+ get_current_resources(device, busnum, domain, &resources);
-+ if (list_empty(&resources))
-+ x86_pci_root_bus_resources(busnum, &resources);
-+ bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
-+ &resources);
-+ if (bus)
- bus->subordinate = pci_scan_child_bus(bus);
-- }
-+ else
-+ pci_free_resource_list(&resources);
- }
-
- /* After the PCI-E bus has been walked and all devices discovered,
---- a/arch/x86/pci/broadcom_bus.c
-+++ b/arch/x86/pci/broadcom_bus.c
-@@ -15,10 +15,11 @@
- #include <linux/pci.h>
- #include <linux/init.h>
- #include <asm/pci_x86.h>
-+#include <asm/pci-direct.h>
-
- #include "bus_numa.h"
-
--static void __devinit cnb20le_res(struct pci_dev *dev)
-+static void __init cnb20le_res(u8 bus, u8 slot, u8 func)
- {
- struct pci_root_info *info;
- struct resource res;
-@@ -26,21 +27,12 @@ static void __devinit cnb20le_res(struct
- u8 fbus, lbus;
- int i;
-
--#ifdef CONFIG_ACPI
-- /*
-- * We should get host bridge information from ACPI unless the BIOS
-- * doesn't support it.
-- */
-- if (acpi_os_get_root_pointer())
-- return;
--#endif
--
- info = &pci_root_info[pci_root_num];
- pci_root_num++;
-
- /* read the PCI bus numbers */
-- pci_read_config_byte(dev, 0x44, &fbus);
-- pci_read_config_byte(dev, 0x45, &lbus);
-+ fbus = read_pci_config_byte(bus, slot, func, 0x44);
-+ lbus = read_pci_config_byte(bus, slot, func, 0x45);
- info->bus_min = fbus;
- info->bus_max = lbus;
-
-@@ -59,8 +51,8 @@ static void __devinit cnb20le_res(struct
- }
-
- /* read the non-prefetchable memory window */
-- pci_read_config_word(dev, 0xc0, &word1);
-- pci_read_config_word(dev, 0xc2, &word2);
-+ word1 = read_pci_config_16(bus, slot, func, 0xc0);
-+ word2 = read_pci_config_16(bus, slot, func, 0xc2);
- if (word1 != word2) {
- res.start = (word1 << 16) | 0x0000;
- res.end = (word2 << 16) | 0xffff;
-@@ -69,8 +61,8 @@ static void __devinit cnb20le_res(struct
- }
-
- /* read the prefetchable memory window */
-- pci_read_config_word(dev, 0xc4, &word1);
-- pci_read_config_word(dev, 0xc6, &word2);
-+ word1 = read_pci_config_16(bus, slot, func, 0xc4);
-+ word2 = read_pci_config_16(bus, slot, func, 0xc6);
- if (word1 != word2) {
- res.start = (word1 << 16) | 0x0000;
- res.end = (word2 << 16) | 0xffff;
-@@ -79,8 +71,8 @@ static void __devinit cnb20le_res(struct
- }
-
- /* read the IO port window */
-- pci_read_config_word(dev, 0xd0, &word1);
-- pci_read_config_word(dev, 0xd2, &word2);
-+ word1 = read_pci_config_16(bus, slot, func, 0xd0);
-+ word2 = read_pci_config_16(bus, slot, func, 0xd2);
- if (word1 != word2) {
- res.start = word1;
- res.end = word2;
-@@ -92,13 +84,37 @@ static void __devinit cnb20le_res(struct
- res.start = fbus;
- res.end = lbus;
- res.flags = IORESOURCE_BUS;
-- dev_info(&dev->dev, "CNB20LE PCI Host Bridge (domain %04x %pR)\n",
-- pci_domain_nr(dev->bus), &res);
-+ printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res);
-
- for (i = 0; i < info->res_num; i++)
-- dev_info(&dev->dev, "host bridge window %pR\n", &info->res[i]);
-+ printk(KERN_INFO "host bridge window %pR\n", &info->res[i]);
- }
-
--DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
-- cnb20le_res);
-+static int __init broadcom_postcore_init(void)
-+{
-+ u8 bus = 0, slot = 0;
-+ u32 id;
-+ u16 vendor, device;
-+
-+#ifdef CONFIG_ACPI
-+ /*
-+ * We should get host bridge information from ACPI unless the BIOS
-+ * doesn't support it.
-+ */
-+ if (acpi_os_get_root_pointer())
-+ return 0;
-+#endif
-+
-+ id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
-+ vendor = id & 0xffff;
-+ device = (id >> 16) & 0xffff;
-+
-+ if (vendor == PCI_VENDOR_ID_SERVERWORKS &&
-+ device == PCI_DEVICE_ID_SERVERWORKS_LE) {
-+ cnb20le_res(bus, slot, 0);
-+ cnb20le_res(bus, slot, 1);
-+ }
-+ return 0;
-+}
-
-+postcore_initcall(broadcom_postcore_init);
---- a/arch/x86/pci/bus_numa.c
-+++ b/arch/x86/pci/bus_numa.c
-@@ -7,45 +7,50 @@
- int pci_root_num;
- struct pci_root_info pci_root_info[PCI_ROOT_NR];
-
--void x86_pci_root_bus_res_quirks(struct pci_bus *b)
-+void x86_pci_root_bus_resources(int bus, struct list_head *resources)
- {
- int i;
- int j;
- struct pci_root_info *info;
-
-- /* don't go for it if _CRS is used already */
-- if (b->resource[0] != &ioport_resource ||
-- b->resource[1] != &iomem_resource)
-- return;
--
- if (!pci_root_num)
-- return;
-+ goto default_resources;
-
- for (i = 0; i < pci_root_num; i++) {
-- if (pci_root_info[i].bus_min == b->number)
-+ if (pci_root_info[i].bus_min == bus)
- break;
- }
-
- if (i == pci_root_num)
-- return;
-+ goto default_resources;
-
-- printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
-- b->number);
-+ printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n",
-+ bus);
-
-- pci_bus_remove_resources(b);
- info = &pci_root_info[i];
- for (j = 0; j < info->res_num; j++) {
- struct resource *res;
- struct resource *root;
-
- res = &info->res[j];
-- pci_bus_add_resource(b, res, 0);
-+ pci_add_resource(resources, res);
- if (res->flags & IORESOURCE_IO)
- root = &ioport_resource;
- else
- root = &iomem_resource;
- insert_resource(root, res);
- }
-+ return;
-+
-+default_resources:
-+ /*
-+ * We don't have any host bridge aperture information from the
-+ * "native host bridge drivers," e.g., amd_bus or broadcom_bus,
-+ * so fall back to the defaults historically used by pci_create_bus().
-+ */
-+ printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus);
-+ pci_add_resource(resources, &ioport_resource);
-+ pci_add_resource(resources, &iomem_resource);
- }
-
- void __devinit update_res(struct pci_root_info *info, resource_size_t start,
---- a/arch/x86/pci/common.c
-+++ b/arch/x86/pci/common.c
-@@ -164,9 +164,6 @@ void __devinit pcibios_fixup_bus(struct
- {
- struct pci_dev *dev;
-
-- /* root bus? */
-- if (!b->parent)
-- x86_pci_root_bus_res_quirks(b);
- pci_read_bridge_bases(b);
- list_for_each_entry(dev, &b->devices, bus_list)
- pcibios_fixup_device_resources(dev);
-@@ -433,6 +430,7 @@ void __init dmi_check_pciprobe(void)
-
- struct pci_bus * __devinit pcibios_scan_root(int busnum)
- {
-+ LIST_HEAD(resources);
- struct pci_bus *bus = NULL;
- struct pci_sysdata *sd;
-
-@@ -456,9 +454,12 @@ struct pci_bus * __devinit pcibios_scan_
- sd->node = get_mp_bus_to_node(busnum);
-
- printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
-- bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
-- if (!bus)
-+ x86_pci_root_bus_resources(busnum, &resources);
-+ bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
-+ if (!bus) {
-+ pci_free_resource_list(&resources);
- kfree(sd);
-+ }
-
- return bus;
- }
-@@ -639,6 +640,7 @@ int pci_ext_cfg_avail(struct pci_dev *de
-
- struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
- {
-+ LIST_HEAD(resources);
- struct pci_bus *bus = NULL;
- struct pci_sysdata *sd;
-
-@@ -653,9 +655,12 @@ struct pci_bus * __devinit pci_scan_bus_
- return NULL;
- }
- sd->node = node;
-- bus = pci_scan_bus(busno, ops, sd);
-- if (!bus)
-+ x86_pci_root_bus_resources(busno, &resources);
-+ bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
-+ if (!bus) {
-+ pci_free_resource_list(&resources);
- kfree(sd);
-+ }
-
- return bus;
- }
---- a/arch/x86/pci/legacy.c
-+++ b/arch/x86/pci/legacy.c
-@@ -31,9 +31,6 @@ int __init pci_legacy_init(void)
-
- printk("PCI: Probing PCI hardware\n");
- pci_root_bus = pcibios_scan_root(0);
-- if (pci_root_bus)
-- pci_bus_add_devices(pci_root_bus);
--
- return 0;
- }
-
---- a/arch/x86/pci/numaq_32.c
-+++ b/arch/x86/pci/numaq_32.c
-@@ -153,8 +153,6 @@ int __init pci_numaq_init(void)
- raw_pci_ops = &pci_direct_conf1_mq;
-
- pci_root_bus = pcibios_scan_root(0);
-- if (pci_root_bus)
-- pci_bus_add_devices(pci_root_bus);
- if (num_online_nodes() > 1)
- for_each_online_node(quad) {
- if (quad == 0)
---- a/arch/xtensa/kernel/pci.c
-+++ b/arch/xtensa/kernel/pci.c
-@@ -134,9 +134,46 @@ struct pci_controller * __init pcibios_a
- return pci_ctrl;
- }
-
-+static void __init pci_controller_apertures(struct pci_controller *pci_ctrl,
-+ struct list_head *resources)
-+{
-+ struct resource *res;
-+ unsigned long io_offset;
-+ int i;
-+
-+ io_offset = (unsigned long)pci_ctrl->io_space.base;
-+ res = &pci_ctrl->io_resource;
-+ if (!res->flags) {
-+ if (io_offset)
-+ printk (KERN_ERR "I/O resource not set for host"
-+ " bridge %d\n", pci_ctrl->index);
-+ res->start = 0;
-+ res->end = IO_SPACE_LIMIT;
-+ res->flags = IORESOURCE_IO;
-+ }
-+ res->start += io_offset;
-+ res->end += io_offset;
-+ pci_add_resource(resources, res);
-+
-+ for (i = 0; i < 3; i++) {
-+ res = &pci_ctrl->mem_resources[i];
-+ if (!res->flags) {
-+ if (i > 0)
-+ continue;
-+ printk(KERN_ERR "Memory resource not set for "
-+ "host bridge %d\n", pci_ctrl->index);
-+ res->start = 0;
-+ res->end = ~0U;
-+ res->flags = IORESOURCE_MEM;
-+ }
-+ pci_add_resource(resources, res);
-+ }
-+}
-+
- static int __init pcibios_init(void)
- {
- struct pci_controller *pci_ctrl;
-+ struct list_head resources;
- struct pci_bus *bus;
- int next_busno = 0, i;
-
-@@ -145,19 +182,10 @@ static int __init pcibios_init(void)
- /* Scan all of the recorded PCI controllers. */
- for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) {
- pci_ctrl->last_busno = 0xff;
-- bus = pci_scan_bus(pci_ctrl->first_busno, pci_ctrl->ops,
-- pci_ctrl);
-- if (pci_ctrl->io_resource.flags) {
-- unsigned long offs;
--
-- offs = (unsigned long)pci_ctrl->io_space.base;
-- pci_ctrl->io_resource.start += offs;
-- pci_ctrl->io_resource.end += offs;
-- bus->resource[0] = &pci_ctrl->io_resource;
-- }
-- for (i = 0; i < 3; ++i)
-- if (pci_ctrl->mem_resources[i].flags)
-- bus->resource[i+1] =&pci_ctrl->mem_resources[i];
-+ INIT_LIST_HEAD(&resources);
-+ pci_controller_apertures(pci_ctrl, &resources);
-+ bus = pci_scan_root_bus(NULL, pci_ctrl->first_busno,
-+ pci_ctrl->ops, pci_ctrl, &resources);
- pci_ctrl->bus = bus;
- pci_ctrl->last_busno = bus->subordinate;
- if (next_busno <= pci_ctrl->last_busno)
-@@ -178,36 +206,7 @@ void __init pcibios_fixup_bus(struct pci
- int i;
-
- io_offset = (unsigned long)pci_ctrl->io_space.base;
-- if (bus->parent == NULL) {
-- /* this is a host bridge - fill in its resources */
-- pci_ctrl->bus = bus;
--
-- bus->resource[0] = res = &pci_ctrl->io_resource;
-- if (!res->flags) {
-- if (io_offset)
-- printk (KERN_ERR "I/O resource not set for host"
-- " bridge %d\n", pci_ctrl->index);
-- res->start = 0;
-- res->end = IO_SPACE_LIMIT;
-- res->flags = IORESOURCE_IO;
-- }
-- res->start += io_offset;
-- res->end += io_offset;
--
-- for (i = 0; i < 3; i++) {
-- res = &pci_ctrl->mem_resources[i];
-- if (!res->flags) {
-- if (i > 0)
-- continue;
-- printk(KERN_ERR "Memory resource not set for "
-- "host bridge %d\n", pci_ctrl->index);
-- res->start = 0;
-- res->end = ~0U;
-- res->flags = IORESOURCE_MEM;
-- }
-- bus->resource[i+1] = res;
-- }
-- } else {
-+ if (bus->parent) {
- /* This is a subordinate bridge */
- pci_read_bridge_bases(bus);
-
---- a/drivers/parisc/dino.c
-+++ b/drivers/parisc/dino.c
-@@ -562,19 +562,6 @@ dino_fixup_bus(struct pci_bus *bus)
- /* Firmware doesn't set up card-mode dino, so we have to */
- if (is_card_dino(&dino_dev->hba.dev->id)) {
- dino_card_setup(bus, dino_dev->hba.base_addr);
-- } else if(bus->parent == NULL) {
-- /* must have a dino above it, reparent the resources
-- * into the dino window */
-- int i;
-- struct resource *res = &dino_dev->hba.lmmio_space;
--
-- bus->resource[0] = &(dino_dev->hba.io_space);
-- for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) {
-- if(res[i].flags == 0)
-- break;
-- bus->resource[i+1] = &res[i];
-- }
--
- } else if (bus->parent) {
- int i;
-
-@@ -927,6 +914,7 @@ static int __init dino_probe(struct pari
- const char *version = "unknown";
- char *name;
- int is_cujo = 0;
-+ LIST_HEAD(resources);
- struct pci_bus *bus;
- unsigned long hpa = dev->hpa.start;
-
-@@ -1003,26 +991,37 @@ static int __init dino_probe(struct pari
-
- dev->dev.platform_data = dino_dev;
-
-+ pci_add_resource(&resources, &dino_dev->hba.io_space);
-+ if (dino_dev->hba.lmmio_space.flags)
-+ pci_add_resource(&resources, &dino_dev->hba.lmmio_space);
-+ if (dino_dev->hba.elmmio_space.flags)
-+ pci_add_resource(&resources, &dino_dev->hba.elmmio_space);
-+ if (dino_dev->hba.gmmio_space.flags)
-+ pci_add_resource(&resources, &dino_dev->hba.gmmio_space);
-+
- /*
- ** It's not used to avoid chicken/egg problems
- ** with configuration accessor functions.
- */
-- dino_dev->hba.hba_bus = bus = pci_scan_bus_parented(&dev->dev,
-- dino_current_bus, &dino_cfg_ops, NULL);
--
-- if(bus) {
-- /* This code *depends* on scanning being single threaded
-- * if it isn't, this global bus number count will fail
-- */
-- dino_current_bus = bus->subordinate + 1;
-- pci_bus_assign_resources(bus);
-- pci_bus_add_devices(bus);
-- } else {
-+ dino_dev->hba.hba_bus = bus = pci_create_root_bus(&dev->dev,
-+ dino_current_bus, &dino_cfg_ops, NULL, &resources);
-+ if (!bus) {
- printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
- dev_name(&dev->dev), dino_current_bus);
-+ pci_free_resource_list(&resources);
- /* increment the bus number in case of duplicates */
- dino_current_bus++;
-+ return 0;
- }
-+
-+ bus->subordinate = pci_scan_child_bus(bus);
-+
-+ /* This code *depends* on scanning being single threaded
-+ * if it isn't, this global bus number count will fail
-+ */
-+ dino_current_bus = bus->subordinate + 1;
-+ pci_bus_assign_resources(bus);
-+ pci_bus_add_devices(bus);
- return 0;
- }
-
---- a/drivers/parisc/lba_pci.c
-+++ b/drivers/parisc/lba_pci.c
-@@ -653,7 +653,7 @@ lba_fixup_bus(struct pci_bus *bus)
- }
- } else {
- /* Host-PCI Bridge */
-- int err, i;
-+ int err;
-
- DBG("lba_fixup_bus() %s [%lx/%lx]/%lx\n",
- ldev->hba.io_space.name,
-@@ -669,9 +669,6 @@ lba_fixup_bus(struct pci_bus *bus)
- lba_dump_res(&ioport_resource, 2);
- BUG();
- }
-- /* advertize Host bridge resources to PCI bus */
-- bus->resource[0] = &(ldev->hba.io_space);
-- i = 1;
-
- if (ldev->hba.elmmio_space.start) {
- err = request_resource(&iomem_resource,
-@@ -685,35 +682,17 @@ lba_fixup_bus(struct pci_bus *bus)
-
- /* lba_dump_res(&iomem_resource, 2); */
- /* BUG(); */
-- } else
-- bus->resource[i++] = &(ldev->hba.elmmio_space);
-+ }
- }
-
--
-- /* Overlaps with elmmio can (and should) fail here.
-- * We will prune (or ignore) the distributed range.
-- *
-- * FIXME: SBA code should register all elmmio ranges first.
-- * that would take care of elmmio ranges routed
-- * to a different rope (already discovered) from
-- * getting registered *after* LBA code has already
-- * registered it's distributed lmmio range.
-- */
-- if (truncate_pat_collision(&iomem_resource,
-- &(ldev->hba.lmmio_space))) {
--
-- printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n",
-- (long)ldev->hba.lmmio_space.start,
-- (long)ldev->hba.lmmio_space.end);
-- } else {
-+ if (ldev->hba.lmmio_space.flags) {
- err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
- if (err < 0) {
- printk(KERN_ERR "FAILED: lba_fixup_bus() request for "
- "lmmio_space [%lx/%lx]\n",
- (long)ldev->hba.lmmio_space.start,
- (long)ldev->hba.lmmio_space.end);
-- } else
-- bus->resource[i++] = &(ldev->hba.lmmio_space);
-+ }
- }
-
- #ifdef CONFIG_64BIT
-@@ -728,7 +707,6 @@ lba_fixup_bus(struct pci_bus *bus)
- lba_dump_res(&iomem_resource, 2);
- BUG();
- }
-- bus->resource[i++] = &(ldev->hba.gmmio_space);
- }
- #endif
-
-@@ -1404,6 +1382,7 @@ static int __init
- lba_driver_probe(struct parisc_device *dev)
- {
- struct lba_device *lba_dev;
-+ LIST_HEAD(resources);
- struct pci_bus *lba_bus;
- struct pci_ops *cfg_ops;
- u32 func_class;
-@@ -1518,10 +1497,41 @@ lba_driver_probe(struct parisc_device *d
- if (lba_dev->hba.bus_num.start < lba_next_bus)
- lba_dev->hba.bus_num.start = lba_next_bus;
-
-+ /* Overlaps with elmmio can (and should) fail here.
-+ * We will prune (or ignore) the distributed range.
-+ *
-+ * FIXME: SBA code should register all elmmio ranges first.
-+ * that would take care of elmmio ranges routed
-+ * to a different rope (already discovered) from
-+ * getting registered *after* LBA code has already
-+ * registered it's distributed lmmio range.
-+ */
-+ if (truncate_pat_collision(&iomem_resource,
-+ &(lba_dev->hba.lmmio_space))) {
-+ printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n",
-+ (long)lba_dev->hba.lmmio_space.start,
-+ (long)lba_dev->hba.lmmio_space.end);
-+ lba_dev->hba.lmmio_space.flags = 0;
-+ }
-+
-+ pci_add_resource(&resources, &lba_dev->hba.io_space);
-+ if (lba_dev->hba.elmmio_space.start)
-+ pci_add_resource(&resources, &lba_dev->hba.elmmio_space);
-+ if (lba_dev->hba.lmmio_space.flags)
-+ pci_add_resource(&resources, &lba_dev->hba.lmmio_space);
-+ if (lba_dev->hba.gmmio_space.flags)
-+ pci_add_resource(&resources, &lba_dev->hba.gmmio_space);
-+
- dev->dev.platform_data = lba_dev;
- lba_bus = lba_dev->hba.hba_bus =
-- pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
-- cfg_ops, NULL);
-+ pci_create_root_bus(&dev->dev, lba_dev->hba.bus_num.start,
-+ cfg_ops, NULL, &resources);
-+ if (!lba_bus) {
-+ pci_free_resource_list(&resources);
-+ return 0;
-+ }
-+
-+ lba_bus->subordinate = pci_scan_child_bus(lba_bus);
-
- /* This is in lieu of calling pci_assign_unassigned_resources() */
- if (is_pdc_pat()) {
-@@ -1551,10 +1561,8 @@ lba_driver_probe(struct parisc_device *d
- lba_dev->flags |= LBA_FLAG_SKIP_PROBE;
- }
-
-- if (lba_bus) {
-- lba_next_bus = lba_bus->subordinate + 1;
-- pci_bus_add_devices(lba_bus);
-- }
-+ lba_next_bus = lba_bus->subordinate + 1;
-+ pci_bus_add_devices(lba_bus);
-
- /* Whew! Finally done! Tell services we got this one covered. */
- return 0;
---- a/drivers/pci/bus.c
-+++ b/drivers/pci/bus.c
-@@ -18,6 +18,32 @@
-
- #include "pci.h"
-
-+void pci_add_resource(struct list_head *resources, struct resource *res)
-+{
-+ struct pci_bus_resource *bus_res;
-+
-+ bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
-+ if (!bus_res) {
-+ printk(KERN_ERR "PCI: can't add bus resource %pR\n", res);
-+ return;
-+ }
-+
-+ bus_res->res = res;
-+ list_add_tail(&bus_res->list, resources);
-+}
-+EXPORT_SYMBOL(pci_add_resource);
-+
-+void pci_free_resource_list(struct list_head *resources)
-+{
-+ struct pci_bus_resource *bus_res, *tmp;
-+
-+ list_for_each_entry_safe(bus_res, tmp, resources, list) {
-+ list_del(&bus_res->list);
-+ kfree(bus_res);
-+ }
-+}
-+EXPORT_SYMBOL(pci_free_resource_list);
-+
- void pci_bus_add_resource(struct pci_bus *bus, struct resource *res,
- unsigned int flags)
- {
-@@ -52,16 +78,12 @@ EXPORT_SYMBOL_GPL(pci_bus_resource_n);
-
- void pci_bus_remove_resources(struct pci_bus *bus)
- {
-- struct pci_bus_resource *bus_res, *tmp;
- int i;
-
- for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
- bus->resource[i] = NULL;
-
-- list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
-- list_del(&bus_res->list);
-- kfree(bus_res);
-- }
-+ pci_free_resource_list(&bus->resources);
- }
-
- /**
---- a/drivers/pci/probe.c
-+++ b/drivers/pci/probe.c
-@@ -1527,12 +1527,14 @@ unsigned int __devinit pci_scan_child_bu
- return max;
- }
-
--struct pci_bus * pci_create_bus(struct device *parent,
-- int bus, struct pci_ops *ops, void *sysdata)
-+struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
-+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
- {
-- int error;
-+ int error, i;
- struct pci_bus *b, *b2;
- struct device *dev;
-+ struct pci_bus_resource *bus_res, *n;
-+ struct resource *res;
-
- b = pci_alloc_bus();
- if (!b)
-@@ -1582,8 +1584,20 @@ struct pci_bus * pci_create_bus(struct d
- pci_create_legacy_files(b);
-
- b->number = b->secondary = bus;
-- b->resource[0] = &ioport_resource;
-- b->resource[1] = &iomem_resource;
-+
-+ /* Add initial resources to the bus */
-+ list_for_each_entry_safe(bus_res, n, resources, list)
-+ list_move_tail(&bus_res->list, &b->resources);
-+
-+ if (parent)
-+ dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
-+ else
-+ printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
-+
-+ pci_bus_for_each_resource(b, res, i) {
-+ if (res)
-+ dev_info(&b->dev, "root bus resource %pR\n", res);
-+ }
-
- return b;
-
-@@ -1599,18 +1613,58 @@ err_out:
- return NULL;
- }
-
-+struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
-+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
-+{
-+ struct pci_bus *b;
-+
-+ b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
-+ if (!b)
-+ return NULL;
-+
-+ b->subordinate = pci_scan_child_bus(b);
-+ pci_bus_add_devices(b);
-+ return b;
-+}
-+EXPORT_SYMBOL(pci_scan_root_bus);
-+
-+/* Deprecated; use pci_scan_root_bus() instead */
- struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
- int bus, struct pci_ops *ops, void *sysdata)
- {
-+ LIST_HEAD(resources);
- struct pci_bus *b;
-
-- b = pci_create_bus(parent, bus, ops, sysdata);
-+ pci_add_resource(&resources, &ioport_resource);
-+ pci_add_resource(&resources, &iomem_resource);
-+ b = pci_create_root_bus(parent, bus, ops, sysdata, &resources);
- if (b)
- b->subordinate = pci_scan_child_bus(b);
-+ else
-+ pci_free_resource_list(&resources);
- return b;
- }
- EXPORT_SYMBOL(pci_scan_bus_parented);
-
-+struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
-+ void *sysdata)
-+{
-+ LIST_HEAD(resources);
-+ struct pci_bus *b;
-+
-+ pci_add_resource(&resources, &ioport_resource);
-+ pci_add_resource(&resources, &iomem_resource);
-+ b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
-+ if (b) {
-+ b->subordinate = pci_scan_child_bus(b);
-+ pci_bus_add_devices(b);
-+ } else {
-+ pci_free_resource_list(&resources);
-+ }
-+ return b;
-+}
-+EXPORT_SYMBOL(pci_scan_bus);
-+
- #ifdef CONFIG_HOTPLUG
- /**
- * pci_rescan_bus - scan a PCI bus for devices.
---- a/include/linux/pci.h
-+++ b/include/linux/pci.h
-@@ -660,17 +660,13 @@ extern struct pci_bus *pci_find_bus(int
- void pci_bus_add_devices(const struct pci_bus *bus);
- struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata);
--static inline struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
-- void *sysdata)
--{
-- struct pci_bus *root_bus;
-- root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
-- if (root_bus)
-- pci_bus_add_devices(root_bus);
-- return root_bus;
--}
--struct pci_bus *pci_create_bus(struct device *parent, int bus,
-- struct pci_ops *ops, void *sysdata);
-+struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
-+struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
-+ struct pci_ops *ops, void *sysdata,
-+ struct list_head *resources);
-+struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
-+ struct pci_ops *ops, void *sysdata,
-+ struct list_head *resources);
- struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
- int busnr);
- void pcie_update_link_speed(struct pci_bus *bus, u16 link_status);
-@@ -910,6 +906,8 @@ int pci_request_selected_regions_exclusi
- void pci_release_selected_regions(struct pci_dev *, int);
-
- /* drivers/pci/bus.c */
-+void pci_add_resource(struct list_head *resources, struct resource *res);
-+void pci_free_resource_list(struct list_head *resources);
- void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
- struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n);
- void pci_bus_remove_resources(struct pci_bus *bus);
+++ /dev/null
-From b7d9f9cd6a8e463c1061ea29ed3e614403625024 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 17 Jul 2011 14:51:47 +0200
-Subject: [PATCH 12/26] bcma: move parallel flash into a union
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/bcm47xx/nvram.c | 3 +
- drivers/bcma/driver_mips.c | 1 +
- include/linux/bcma/bcma_driver_chipcommon.h | 73 ++++++++++++++++++++++++++-
- 3 files changed, 76 insertions(+), 1 deletions(-)
-
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -50,6 +50,9 @@ static void early_nvram_init(void)
- #ifdef CONFIG_BCM47XX_BCMA
- case BCM47XX_BUS_TYPE_BCMA:
- bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
-+ if (bcma_cc->flash_type != BCMA_PFLASH)
-+ return;
-+
- base = bcma_cc->pflash.window;
- lim = bcma_cc->pflash.window_size;
- break;
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -189,6 +189,7 @@ static void bcma_core_mips_flash_detect(
- break;
- case BCMA_CC_FLASHT_PARA:
- pr_info("found parallel flash.\n");
-+ bus->drv_cc.flash_type = BCMA_PFLASH;
- bus->drv_cc.pflash.window = 0x1c000000;
- bus->drv_cc.pflash.window_size = 0x02000000;
-
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -108,10 +108,68 @@
- #define BCMA_CC_JCTL_EXT_EN 2 /* Enable external targets */
- #define BCMA_CC_JCTL_EN 1 /* Enable Jtag master */
- #define BCMA_CC_FLASHCTL 0x0040
-+
-+/* Start/busy bit in flashcontrol */
-+#define BCMA_CC_FLASHCTL_OPCODE 0x000000ff
-+#define BCMA_CC_FLASHCTL_ACTION 0x00000700
-+#define BCMA_CC_FLASHCTL_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */
- #define BCMA_CC_FLASHCTL_START 0x80000000
- #define BCMA_CC_FLASHCTL_BUSY BCMA_CC_FLASHCTL_START
-+
-+/* flashcontrol action+opcodes for ST flashes */
-+#define BCMA_CC_FLASHCTL_ST_WREN 0x0006 /* Write Enable */
-+#define BCMA_CC_FLASHCTL_ST_WRDIS 0x0004 /* Write Disable */
-+#define BCMA_CC_FLASHCTL_ST_RDSR 0x0105 /* Read Status Register */
-+#define BCMA_CC_FLASHCTL_ST_WRSR 0x0101 /* Write Status Register */
-+#define BCMA_CC_FLASHCTL_ST_READ 0x0303 /* Read Data Bytes */
-+#define BCMA_CC_FLASHCTL_ST_PP 0x0302 /* Page Program */
-+#define BCMA_CC_FLASHCTL_ST_SE 0x02d8 /* Sector Erase */
-+#define BCMA_CC_FLASHCTL_ST_BE 0x00c7 /* Bulk Erase */
-+#define BCMA_CC_FLASHCTL_ST_DP 0x00b9 /* Deep Power-down */
-+#define BCMA_CC_FLASHCTL_ST_RES 0x03ab /* Read Electronic Signature */
-+#define BCMA_CC_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
-+#define BCMA_CC_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
-+
-+
-+/* flashcontrol action+opcodes for Atmel flashes */
-+#define BCMA_CC_FLASHCTL_AT_READ 0x07e8
-+#define BCMA_CC_FLASHCTL_AT_PAGE_READ 0x07d2
-+#define BCMA_CC_FLASHCTL_AT_BUF1_READ
-+#define BCMA_CC_FLASHCTL_AT_BUF2_READ
-+#define BCMA_CC_FLASHCTL_AT_STATUS 0x01d7
-+#define BCMA_CC_FLASHCTL_AT_BUF1_WRITE 0x0384
-+#define BCMA_CC_FLASHCTL_AT_BUF2_WRITE 0x0387
-+#define BCMA_CC_FLASHCTL_AT_BUF1_ERASE_PROGRAM 0x0283
-+#define BCMA_CC_FLASHCTL_AT_BUF2_ERASE_PROGRAM 0x0286
-+#define BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM 0x0288
-+#define BCMA_CC_FLASHCTL_AT_BUF2_PROGRAM 0x0289
-+#define BCMA_CC_FLASHCTL_AT_PAGE_ERASE 0x0281
-+#define BCMA_CC_FLASHCTL_AT_BLOCK_ERASE 0x0250
-+#define BCMA_CC_FLASHCTL_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
-+#define BCMA_CC_FLASHCTL_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
-+#define BCMA_CC_FLASHCTL_AT_BUF1_LOAD 0x0253
-+#define BCMA_CC_FLASHCTL_AT_BUF2_LOAD 0x0255
-+#define BCMA_CC_FLASHCTL_AT_BUF1_COMPARE 0x0260
-+#define BCMA_CC_FLASHCTL_AT_BUF2_COMPARE 0x0261
-+#define BCMA_CC_FLASHCTL_AT_BUF1_REPROGRAM 0x0258
-+#define BCMA_CC_FLASHCTL_AT_BUF2_REPROGRAM 0x0259
-+
- #define BCMA_CC_FLASHADDR 0x0044
- #define BCMA_CC_FLASHDATA 0x0048
-+
-+/* Status register bits for ST flashes */
-+#define BCMA_CC_FLASHDATA_ST_WIP 0x01 /* Write In Progress */
-+#define BCMA_CC_FLASHDATA_ST_WEL 0x02 /* Write Enable Latch */
-+#define BCMA_CC_FLASHDATA_ST_BP_MASK 0x1c /* Block Protect */
-+#define BCMA_CC_FLASHDATA_ST_BP_SHIFT 2
-+#define BCMA_CC_FLASHDATA_ST_SRWD 0x80 /* Status Register Write Disable */
-+
-+/* Status register bits for Atmel flashes */
-+#define BCMA_CC_FLASHDATA_AT_READY 0x80
-+#define BCMA_CC_FLASHDATA_AT_MISMATCH 0x40
-+#define BCMA_CC_FLASHDATA_AT_ID_MASK 0x38
-+#define BCMA_CC_FLASHDATA_AT_ID_SHIFT 3
-+
- #define BCMA_CC_BCAST_ADDR 0x0050
- #define BCMA_CC_BCAST_DATA 0x0054
- #define BCMA_CC_GPIOPULLUP 0x0058 /* Rev >= 20 only */
-@@ -300,6 +358,12 @@
- #define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4 BIT(16) /* enable bt_shd0 at gpio4 */
- #define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5 BIT(17) /* enable bt_shd1 at gpio5 */
-
-+#define BCMA_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
-+#define BCMA_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
-+#define BCMA_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
-+#define BCMA_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */
-+
-+
- /* Data for the PMU, if available.
- * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
- */
-@@ -309,6 +373,10 @@ struct bcma_chipcommon_pmu {
- };
-
- #ifdef CONFIG_BCMA_DRIVER_MIPS
-+enum bcma_flash_type {
-+ BCMA_PFLASH,
-+};
-+
- struct bcma_pflash {
- u8 buswidth;
- u32 window;
-@@ -334,7 +402,10 @@ struct bcma_drv_cc {
- u16 fast_pwrup_delay;
- struct bcma_chipcommon_pmu pmu;
- #ifdef CONFIG_BCMA_DRIVER_MIPS
-- struct bcma_pflash pflash;
-+ enum bcma_flash_type flash_type;
-+ union {
-+ struct bcma_pflash pflash;
-+ };
-
- int nr_serial_ports;
- struct bcma_serial_port serial_ports[4];
+++ /dev/null
-From a62940e988526c881966a8c72cc28c95fca89f3c Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 17 Jul 2011 14:53:07 +0200
-Subject: [PATCH 13/26] bcma: add serial flash support to bcma
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/Kconfig | 5 +
- drivers/bcma/Makefile | 1 +
- drivers/bcma/bcma_private.h | 5 +
- drivers/bcma/driver_chipcommon_sflash.c | 555 +++++++++++++++++++++++++++
- drivers/bcma/driver_mips.c | 8 +-
- include/linux/bcma/bcma_driver_chipcommon.h | 24 ++
- 6 files changed, 597 insertions(+), 1 deletions(-)
- create mode 100644 drivers/bcma/driver_chipcommon_sflash.c
-
---- a/drivers/bcma/Kconfig
-+++ b/drivers/bcma/Kconfig
-@@ -38,6 +38,11 @@ config BCMA_HOST_SOC
- bool
- depends on BCMA_DRIVER_MIPS
-
-+config BCMA_SFLASH
-+ bool
-+ depends on BCMA_DRIVER_MIPS
-+ default y
-+
- config BCMA_DRIVER_MIPS
- bool "BCMA Broadcom MIPS core driver"
- depends on BCMA && MIPS
---- a/drivers/bcma/Makefile
-+++ b/drivers/bcma/Makefile
-@@ -1,5 +1,6 @@
- bcma-y += main.o scan.o core.o sprom.o
- bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
-+bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
- bcma-y += driver_pci.o
- bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
- bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
---- a/drivers/bcma/bcma_private.h
-+++ b/drivers/bcma/bcma_private.h
-@@ -41,6 +41,11 @@ void bcma_chipco_serial_init(struct bcma
- u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
- u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
-
-+#ifdef CONFIG_BCMA_SFLASH
-+/* driver_chipcommon_sflash.c */
-+int bcma_sflash_init(struct bcma_drv_cc *cc);
-+#endif /* CONFIG_BCMA_SFLASH */
-+
- #ifdef CONFIG_BCMA_HOST_PCI
- /* host_pci.c */
- extern int __init bcma_host_pci_init(void);
---- /dev/null
-+++ b/drivers/bcma/driver_chipcommon_sflash.c
-@@ -0,0 +1,555 @@
-+/*
-+ * Broadcom SiliconBackplane chipcommon serial flash interface
-+ *
-+ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
-+ * Copyright 2010, Broadcom Corporation
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+
-+#include <linux/bcma/bcma.h>
-+#include <linux/bcma/bcma_driver_chipcommon.h>
-+#include <linux/delay.h>
-+
-+#include "bcma_private.h"
-+
-+#define NUM_RETRIES 3
-+
-+
-+/* Issue a serial flash command */
-+static inline void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
-+{
-+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
-+ BCMA_CC_FLASHCTL_START | opcode);
-+ while (bcma_cc_read32(cc, BCMA_CC_FLASHCTL) & BCMA_CC_FLASHCTL_BUSY)
-+ ;
-+}
-+
-+
-+static inline void bcma_sflash_write_u8(struct bcma_drv_cc *cc,
-+ u32 offset, u8 byte)
-+{
-+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
-+ bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
-+}
-+
-+/* Initialize serial flash access */
-+int bcma_sflash_init(struct bcma_drv_cc *cc)
-+{
-+ u32 id, id2;
-+
-+ memset(&cc->sflash, 0, sizeof(struct bcma_sflash));
-+
-+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
-+ case BCMA_CC_FLASHT_STSER:
-+ /* Probe for ST chips */
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP);
-+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0);
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
-+ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
-+ cc->sflash.blocksize = 64 * 1024;
-+ switch (id) {
-+ case 0x11:
-+ /* ST M25P20 2 Mbit Serial Flash */
-+ cc->sflash.numblocks = 4;
-+ break;
-+ case 0x12:
-+ /* ST M25P40 4 Mbit Serial Flash */
-+ cc->sflash.numblocks = 8;
-+ break;
-+ case 0x13:
-+ /* ST M25P80 8 Mbit Serial Flash */
-+ cc->sflash.numblocks = 16;
-+ break;
-+ case 0x14:
-+ /* ST M25P16 16 Mbit Serial Flash */
-+ cc->sflash.numblocks = 32;
-+ break;
-+ case 0x15:
-+ /* ST M25P32 32 Mbit Serial Flash */
-+ cc->sflash.numblocks = 64;
-+ break;
-+ case 0x16:
-+ /* ST M25P64 64 Mbit Serial Flash */
-+ cc->sflash.numblocks = 128;
-+ break;
-+ case 0x17:
-+ /* ST M25FL128 128 Mbit Serial Flash */
-+ cc->sflash.numblocks = 256;
-+ break;
-+ case 0xbf:
-+ /* All of the following flashes are SST with
-+ * 4KB subsectors. Others should be added but
-+ * We'll have to revamp the way we identify them
-+ * since RES is not eough to disambiguate them.
-+ */
-+ cc->sflash.blocksize = 4 * 1024;
-+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1);
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
-+ id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
-+ switch (id2) {
-+ case 1:
-+ /* SST25WF512 512 Kbit Serial Flash */
-+ case 0x48:
-+ /* SST25VF512 512 Kbit Serial Flash */
-+ cc->sflash.numblocks = 16;
-+ break;
-+ case 2:
-+ /* SST25WF010 1 Mbit Serial Flash */
-+ case 0x49:
-+ /* SST25VF010 1 Mbit Serial Flash */
-+ cc->sflash.numblocks = 32;
-+ break;
-+ case 3:
-+ /* SST25WF020 2 Mbit Serial Flash */
-+ case 0x43:
-+ /* SST25VF020 2 Mbit Serial Flash */
-+ cc->sflash.numblocks = 64;
-+ break;
-+ case 4:
-+ /* SST25WF040 4 Mbit Serial Flash */
-+ case 0x44:
-+ /* SST25VF040 4 Mbit Serial Flash */
-+ case 0x8d:
-+ /* SST25VF040B 4 Mbit Serial Flash */
-+ cc->sflash.numblocks = 128;
-+ break;
-+ case 5:
-+ /* SST25WF080 8 Mbit Serial Flash */
-+ case 0x8e:
-+ /* SST25VF080B 8 Mbit Serial Flash */
-+ cc->sflash.numblocks = 256;
-+ break;
-+ case 0x41:
-+ /* SST25VF016 16 Mbit Serial Flash */
-+ cc->sflash.numblocks = 512;
-+ break;
-+ case 0x4a:
-+ /* SST25VF032 32 Mbit Serial Flash */
-+ cc->sflash.numblocks = 1024;
-+ break;
-+ case 0x4b:
-+ /* SST25VF064 64 Mbit Serial Flash */
-+ cc->sflash.numblocks = 2048;
-+ break;
-+ }
-+ break;
-+ }
-+ break;
-+
-+ case BCMA_CC_FLASHT_ATSER:
-+ /* Probe for Atmel chips */
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
-+ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c;
-+ switch (id) {
-+ case 0xc:
-+ /* Atmel AT45DB011 1Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 512;
-+ break;
-+ case 0x14:
-+ /* Atmel AT45DB021 2Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 1024;
-+ break;
-+ case 0x1c:
-+ /* Atmel AT45DB041 4Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 2048;
-+ break;
-+ case 0x24:
-+ /* Atmel AT45DB081 8Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 4096;
-+ break;
-+ case 0x2c:
-+ /* Atmel AT45DB161 16Mbit Serial Flash */
-+ cc->sflash.blocksize = 512;
-+ cc->sflash.numblocks = 4096;
-+ break;
-+ case 0x34:
-+ /* Atmel AT45DB321 32Mbit Serial Flash */
-+ cc->sflash.blocksize = 512;
-+ cc->sflash.numblocks = 8192;
-+ break;
-+ case 0x3c:
-+ /* Atmel AT45DB642 64Mbit Serial Flash */
-+ cc->sflash.blocksize = 1024;
-+ cc->sflash.numblocks = 8192;
-+ break;
-+ }
-+ break;
-+ }
-+
-+ cc->sflash.size = cc->sflash.blocksize * cc->sflash.numblocks;
-+
-+ return cc->sflash.size ? 0 : -ENODEV;
-+}
-+
-+/* Read len bytes starting at offset into buf. Returns number of bytes read. */
-+int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ u8 *buf)
-+{
-+ u8 *from, *to;
-+ u32 cnt, i;
-+
-+ if (!len)
-+ return 0;
-+
-+ if ((offset + len) > cc->sflash.size)
-+ return -EINVAL;
-+
-+ if ((len >= 4) && (offset & 3))
-+ cnt = 4 - (offset & 3);
-+ else if ((len >= 4) && ((u32)buf & 3))
-+ cnt = 4 - ((u32)buf & 3);
-+ else
-+ cnt = len;
-+
-+
-+ if (cc->core->id.rev == 12)
-+ from = (u8 *)KSEG1ADDR(BCMA_FLASH2 + offset);
-+ else
-+ from = (u8 *)KSEG0ADDR(BCMA_FLASH2 + offset);
-+
-+ to = (u8 *)buf;
-+
-+ if (cnt < 4) {
-+ for (i = 0; i < cnt; i++) {
-+ *to = readb(from);
-+ from++;
-+ to++;
-+ }
-+ return cnt;
-+ }
-+
-+ while (cnt >= 4) {
-+ *(u32 *)to = readl(from);
-+ from += 4;
-+ to += 4;
-+ cnt -= 4;
-+ }
-+
-+ return len - cnt;
-+}
-+
-+/* Poll for command completion. Returns zero when complete. */
-+int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset)
-+{
-+ if (offset >= cc->sflash.size)
-+ return -22;
-+
-+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
-+ case BCMA_CC_FLASHT_STSER:
-+ /* Check for ST Write In Progress bit */
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RDSR);
-+ return bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
-+ & BCMA_CC_FLASHDATA_ST_WIP;
-+ case BCMA_CC_FLASHT_ATSER:
-+ /* Check for Atmel Ready bit */
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
-+ return !(bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
-+ & BCMA_CC_FLASHDATA_AT_READY);
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static int sflash_st_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct bcma_bus *bus = cc->core->bus;
-+ int ret = 0;
-+ bool is4712b0 = (bus->chipinfo.id == 0x4712) && (bus->chipinfo.rev == 3);
-+ u32 mask;
-+
-+
-+ /* Enable writes */
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
-+ if (is4712b0) {
-+ mask = 1 << 14;
-+ bcma_sflash_write_u8(cc, offset, *buf++);
-+ /* Set chip select */
-+ bcma_cc_set32(cc, BCMA_CC_GPIOOUT, mask);
-+ /* Issue a page program with the first byte */
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_PP);
-+ ret = 1;
-+ offset++;
-+ len--;
-+ while (len > 0) {
-+ if ((offset & 255) == 0) {
-+ /* Page boundary, drop cs and return */
-+ bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
-+ udelay(1);
-+ if (!bcma_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ return ret;
-+ } else {
-+ /* Write single byte */
-+ bcma_sflash_cmd(cc, *buf++);
-+ }
-+ ret++;
-+ offset++;
-+ len--;
-+ }
-+ /* All done, drop cs */
-+ bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
-+ udelay(1);
-+ if (!bcma_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ } else if (cc->core->id.rev >= 20) {
-+ bcma_sflash_write_u8(cc, offset, *buf++);
-+ /* Issue a page program with CSA bit set */
-+ bcma_sflash_cmd(cc,
-+ BCMA_CC_FLASHCTL_ST_CSA |
-+ BCMA_CC_FLASHCTL_ST_PP);
-+ ret = 1;
-+ offset++;
-+ len--;
-+ while (len > 0) {
-+ if ((offset & 255) == 0) {
-+ /* Page boundary, poll droping cs and return */
-+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
-+ udelay(1);
-+ if (!bcma_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ return ret;
-+ } else {
-+ /* Write single byte */
-+ bcma_sflash_cmd(cc,
-+ BCMA_CC_FLASHCTL_ST_CSA |
-+ *buf++);
-+ }
-+ ret++;
-+ offset++;
-+ len--;
-+ }
-+ /* All done, drop cs & poll */
-+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
-+ udelay(1);
-+ if (!bcma_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ } else {
-+ ret = 1;
-+ bcma_sflash_write_u8(cc, offset, *buf);
-+ /* Page program */
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_PP);
-+ }
-+ return ret;
-+}
-+
-+static int sflash_at_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct bcma_sflash *sfl = &cc->sflash;
-+ u32 page, byte, mask;
-+ int ret = 0;
-+ mask = sfl->blocksize - 1;
-+ page = (offset & ~mask) << 1;
-+ byte = offset & mask;
-+ /* Read main memory page into buffer 1 */
-+ if (byte || (len < sfl->blocksize)) {
-+ int i = 100;
-+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_LOAD);
-+ /* 250 us for AT45DB321B */
-+ while (i > 0 && bcma_sflash_poll(cc, offset)) {
-+ udelay(10);
-+ i--;
-+ }
-+ BUG_ON(!bcma_sflash_poll(cc, offset));
-+ }
-+ /* Write into buffer 1 */
-+ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
-+ bcma_sflash_write_u8(cc, byte++, *buf++);
-+ bcma_sflash_cmd(cc,
-+ BCMA_CC_FLASHCTL_AT_BUF1_WRITE);
-+ }
-+ /* Write buffer 1 into main memory page */
-+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM);
-+
-+ return ret;
-+}
-+
-+/* Write len bytes starting at offset into buf. Returns number of bytes
-+ * written. Caller should poll for completion.
-+ */
-+int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct bcma_sflash *sfl;
-+ int ret = 0, tries = NUM_RETRIES;
-+
-+ if (!len)
-+ return 0;
-+
-+ if ((offset + len) > cc->sflash.size)
-+ return -EINVAL;
-+
-+ sfl = &cc->sflash;
-+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
-+ case BCMA_CC_FLASHT_STSER:
-+ do {
-+ ret = sflash_st_write(cc, offset, len, buf);
-+ tries--;
-+ } while (ret == -EAGAIN && tries > 0);
-+
-+ if (ret == -EAGAIN && tries == 0) {
-+ pr_info("ST Flash rejected write\n");
-+ ret = -EIO;
-+ }
-+ break;
-+ case BCMA_CC_FLASHT_ATSER:
-+ ret = sflash_at_write(cc, offset, len, buf);
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+/* Erase a region. Returns number of bytes scheduled for erasure.
-+ * Caller should poll for completion.
-+ */
-+int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset)
-+{
-+ struct bcma_sflash *sfl;
-+
-+ if (offset >= cc->sflash.size)
-+ return -EINVAL;
-+
-+ sfl = &cc->sflash;
-+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
-+ case BCMA_CC_FLASHT_STSER:
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
-+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
-+ /* Newer flashes have "sub-sectors" which can be erased independently
-+ * with a new command: ST_SSE. The ST_SE command erases 64KB just as
-+ * before.
-+ */
-+ bcma_sflash_cmd(cc, (sfl->blocksize < (64 * 1024)) ? BCMA_CC_FLASHCTL_ST_SSE : BCMA_CC_FLASHCTL_ST_SE);
-+ return sfl->blocksize;
-+ case BCMA_CC_FLASHT_ATSER:
-+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset << 1);
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_PAGE_ERASE);
-+ return sfl->blocksize;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * writes the appropriate range of flash, a NULL buf simply erases
-+ * the region of flash
-+ */
-+int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct bcma_sflash *sfl;
-+ u8 *block = NULL, *cur_ptr, *blk_ptr;
-+ u32 blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
-+ u32 blk_offset, blk_len, copied;
-+ int bytes, ret = 0;
-+
-+ /* Check address range */
-+ if (len <= 0)
-+ return 0;
-+
-+ sfl = &cc->sflash;
-+ if ((offset + len) > sfl->size)
-+ return -EINVAL;
-+
-+ blocksize = sfl->blocksize;
-+ mask = blocksize - 1;
-+
-+ /* Allocate a block of mem */
-+ block = kmalloc(blocksize, GFP_KERNEL);
-+ if (!block)
-+ return -ENOMEM;
-+
-+ while (len) {
-+ /* Align offset */
-+ cur_offset = offset & ~mask;
-+ cur_length = blocksize;
-+ cur_ptr = block;
-+
-+ remainder = blocksize - (offset & mask);
-+ if (len < remainder)
-+ cur_retlen = len;
-+ else
-+ cur_retlen = remainder;
-+
-+ /* buf == NULL means erase only */
-+ if (buf) {
-+ /* Copy existing data into holding block if necessary */
-+ if ((offset & mask) || (len < blocksize)) {
-+ blk_offset = cur_offset;
-+ blk_len = cur_length;
-+ blk_ptr = cur_ptr;
-+
-+ /* Copy entire block */
-+ while (blk_len) {
-+ copied = bcma_sflash_read(cc,
-+ blk_offset,
-+ blk_len, blk_ptr);
-+ blk_offset += copied;
-+ blk_len -= copied;
-+ blk_ptr += copied;
-+ }
-+ }
-+
-+ /* Copy input data into holding block */
-+ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
-+ }
-+
-+ /* Erase block */
-+ ret = bcma_sflash_erase(cc, cur_offset);
-+ if (ret < 0)
-+ goto done;
-+
-+ while (bcma_sflash_poll(cc, cur_offset));
-+
-+ /* buf == NULL means erase only */
-+ if (!buf) {
-+ offset += cur_retlen;
-+ len -= cur_retlen;
-+ continue;
-+ }
-+
-+ /* Write holding block */
-+ while (cur_length > 0) {
-+ bytes = bcma_sflash_write(cc, cur_offset,
-+ cur_length, cur_ptr);
-+
-+ if (bytes < 0) {
-+ ret = bytes;
-+ goto done;
-+ }
-+
-+ while (bcma_sflash_poll(cc, cur_offset))
-+ ;
-+
-+ cur_offset += bytes;
-+ cur_length -= bytes;
-+ cur_ptr += bytes;
-+ }
-+
-+ offset += cur_retlen;
-+ len -= cur_retlen;
-+ buf += cur_retlen;
-+ }
-+
-+ ret = len;
-+done:
-+ kfree(block);
-+ return ret;
-+}
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -185,7 +185,13 @@ static void bcma_core_mips_flash_detect(
- switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
- case BCMA_CC_FLASHT_STSER:
- case BCMA_CC_FLASHT_ATSER:
-- pr_err("Serial flash not supported.\n");
-+#ifdef CONFIG_BCMA_SFLASH
-+ pr_info("found serial flash.\n");
-+ bus->drv_cc.flash_type = BCMA_SFLASH;
-+ bcma_sflash_init(&bus->drv_cc);
-+#else
-+ pr_info("serial flash not supported.\n");
-+#endif /* CONFIG_BCMA_SFLASH */
- break;
- case BCMA_CC_FLASHT_PARA:
- pr_info("found parallel flash.\n");
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -375,6 +375,7 @@ struct bcma_chipcommon_pmu {
- #ifdef CONFIG_BCMA_DRIVER_MIPS
- enum bcma_flash_type {
- BCMA_PFLASH,
-+ BCMA_SFLASH,
- };
-
- struct bcma_pflash {
-@@ -383,6 +384,14 @@ struct bcma_pflash {
- u32 window_size;
- };
-
-+#ifdef CONFIG_BCMA_SFLASH
-+struct bcma_sflash {
-+ u32 blocksize; /* Block size */
-+ u32 numblocks; /* Number of blocks */
-+ u32 size; /* Total size in bytes */
-+};
-+#endif /* CONFIG_BCMA_SFLASH */
-+
- struct bcma_serial_port {
- void *regs;
- unsigned long clockspeed;
-@@ -405,6 +414,9 @@ struct bcma_drv_cc {
- enum bcma_flash_type flash_type;
- union {
- struct bcma_pflash pflash;
-+#ifdef CONFIG_BCMA_SFLASH
-+ struct bcma_sflash sflash;
-+#endif /* CONFIG_BCMA_SFLASH */
- };
-
- int nr_serial_ports;
-@@ -459,4 +471,16 @@ extern void bcma_chipco_chipctl_maskset(
- extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
- u32 offset, u32 mask, u32 set);
-
-+#ifdef CONFIG_BCMA_SFLASH
-+/* Chipcommon sflash support. */
-+int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ u8 *buf);
-+int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset);
-+int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ const u8 *buf);
-+int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset);
-+int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ const u8 *buf);
-+#endif /* CONFIG_BCMA_SFLASH */
-+
- #endif /* LINUX_BCMA_DRIVER_CC_H_ */
+++ /dev/null
-From e8afde87ecf56beff67c7d5371cabaa4fc018541 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 23 Jul 2011 23:57:06 +0200
-Subject: [PATCH 14/26] ssb: move flash to chipcommon
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/bcm47xx/nvram.c | 8 +++---
- arch/mips/bcm47xx/wgt634u.c | 8 +++---
- drivers/ssb/driver_mipscore.c | 36 +++++++++++++++++++++-------
- include/linux/ssb/ssb_driver_chipcommon.h | 18 ++++++++++++++
- include/linux/ssb/ssb_driver_mips.h | 4 ---
- 5 files changed, 53 insertions(+), 21 deletions(-)
-
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -27,7 +27,7 @@ static char nvram_buf[NVRAM_SPACE];
- static void early_nvram_init(void)
- {
- #ifdef CONFIG_BCM47XX_SSB
-- struct ssb_mipscore *mcore_ssb;
-+ struct ssb_chipcommon *ssb_cc;
- #endif
- #ifdef CONFIG_BCM47XX_BCMA
- struct bcma_drv_cc *bcma_cc;
-@@ -42,9 +42,9 @@ static void early_nvram_init(void)
- switch (bcm47xx_bus_type) {
- #ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
-- mcore_ssb = &bcm47xx_bus.ssb.mipscore;
-- base = mcore_ssb->flash_window;
-- lim = mcore_ssb->flash_window_size;
-+ ssb_cc = &bcm47xx_bus.ssb.chipco;
-+ base = ssb_cc->pflash.window;
-+ lim = ssb_cc->pflash.window_size;
- break;
- #endif
- #ifdef CONFIG_BCM47XX_BCMA
---- a/arch/mips/bcm47xx/wgt634u.c
-+++ b/arch/mips/bcm47xx/wgt634u.c
-@@ -156,10 +156,10 @@ static int __init wgt634u_init(void)
- SSB_CHIPCO_IRQ_GPIO);
- }
-
-- wgt634u_flash_data.width = mcore->flash_buswidth;
-- wgt634u_flash_resource.start = mcore->flash_window;
-- wgt634u_flash_resource.end = mcore->flash_window
-- + mcore->flash_window_size
-+ wgt634u_flash_data.width = mcore->pflash.buswidth;
-+ wgt634u_flash_resource.start = mcore->pflash.window;
-+ wgt634u_flash_resource.end = mcore->pflash.window
-+ + mcore->pflash.window_size
- - 1;
- return platform_add_devices(wgt634u_devices,
- ARRAY_SIZE(wgt634u_devices));
---- a/drivers/ssb/driver_mipscore.c
-+++ b/drivers/ssb/driver_mipscore.c
-@@ -190,16 +190,34 @@ static void ssb_mips_flash_detect(struct
- {
- struct ssb_bus *bus = mcore->dev->bus;
-
-- mcore->flash_buswidth = 2;
-- if (bus->chipco.dev) {
-- mcore->flash_window = 0x1c000000;
-- mcore->flash_window_size = 0x02000000;
-+ /* When there is no chipcommon on the bus there is 4MB flash */
-+ if (!bus->chipco.dev) {
-+ pr_info("found parallel flash.\n");
-+ bus->chipco.flash_type = SSB_PFLASH;
-+ bus->chipco.pflash.window = SSB_FLASH1;
-+ bus->chipco.pflash.window_size = SSB_FLASH1_SZ;
-+ bus->chipco.pflash.buswidth = 2;
-+ return;
-+ }
-+
-+ switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_FLASHT_STSER:
-+ case SSB_CHIPCO_FLASHT_ATSER:
-+ pr_info("serial flash not supported.\n");
-+ break;
-+ case SSB_CHIPCO_FLASHT_PARA:
-+ pr_info("found parallel flash.\n");
-+ bus->chipco.flash_type = SSB_PFLASH;
-+ bus->chipco.pflash.window = SSB_FLASH2;
-+ bus->chipco.pflash.window_size = SSB_FLASH2_SZ;
- if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
-- & SSB_CHIPCO_CFG_DS16) == 0)
-- mcore->flash_buswidth = 1;
-- } else {
-- mcore->flash_window = 0x1fc00000;
-- mcore->flash_window_size = 0x00400000;
-+ & SSB_CHIPCO_CFG_DS16) == 0)
-+ bus->chipco.pflash.buswidth = 1;
-+ else
-+ bus->chipco.pflash.buswidth = 2;
-+ break;
-+ default:
-+ pr_err("flash not supported.\n");
- }
- }
-
---- a/include/linux/ssb/ssb_driver_chipcommon.h
-+++ b/include/linux/ssb/ssb_driver_chipcommon.h
-@@ -582,6 +582,18 @@ struct ssb_chipcommon_pmu {
- u32 crystalfreq; /* The active crystal frequency (in kHz) */
- };
-
-+#ifdef CONFIG_SSB_DRIVER_MIPS
-+enum ssb_flash_type {
-+ SSB_PFLASH,
-+};
-+
-+struct ssb_pflash {
-+ u8 buswidth;
-+ u32 window;
-+ u32 window_size;
-+};
-+#endif /* CONFIG_SSB_DRIVER_MIPS */
-+
- struct ssb_chipcommon {
- struct ssb_device *dev;
- u32 capabilities;
-@@ -589,6 +601,12 @@ struct ssb_chipcommon {
- /* Fast Powerup Delay constant */
- u16 fast_pwrup_delay;
- struct ssb_chipcommon_pmu pmu;
-+#ifdef CONFIG_SSB_DRIVER_MIPS
-+ enum ssb_flash_type flash_type;
-+ union {
-+ struct ssb_pflash pflash;
-+ };
-+#endif /* CONFIG_SSB_DRIVER_MIPS */
- };
-
- static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)
---- a/include/linux/ssb/ssb_driver_mips.h
-+++ b/include/linux/ssb/ssb_driver_mips.h
-@@ -19,10 +19,6 @@ struct ssb_mipscore {
-
- int nr_serial_ports;
- struct ssb_serial_port serial_ports[4];
--
-- u8 flash_buswidth;
-- u32 flash_window;
-- u32 flash_window_size;
- };
-
- extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
+++ /dev/null
-From 980da78179592a3f5f99168bc5af415835aa8c13 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 24 Jul 2011 20:20:36 +0200
-Subject: [PATCH 15/26] ssb: add serial flash support
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/ssb/Kconfig | 6 +
- drivers/ssb/Makefile | 1 +
- drivers/ssb/driver_chipcommon_sflash.c | 556 +++++++++++++++++++++++++++++
- drivers/ssb/driver_mipscore.c | 6 +
- drivers/ssb/ssb_private.h | 4 +
- include/linux/ssb/ssb_driver_chipcommon.h | 30 ++-
- 6 files changed, 601 insertions(+), 2 deletions(-)
- create mode 100644 drivers/ssb/driver_chipcommon_sflash.c
-
---- a/drivers/ssb/Kconfig
-+++ b/drivers/ssb/Kconfig
-@@ -137,6 +137,12 @@ config SSB_DRIVER_MIPS
-
- If unsure, say N
-
-+config SSB_SFLASH
-+ bool
-+ depends on SSB_DRIVER_MIPS
-+ default y
-+
-+
- # Assumption: We are on embedded, if we compile the MIPS core.
- config SSB_EMBEDDED
- bool
---- a/drivers/ssb/Makefile
-+++ b/drivers/ssb/Makefile
-@@ -11,6 +11,7 @@ ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o
- # built-in drivers
- ssb-y += driver_chipcommon.o
- ssb-y += driver_chipcommon_pmu.o
-+ssb-$(CONFIG_SSB_SFLASH) += driver_chipcommon_sflash.o
- ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
- ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
- ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
---- /dev/null
-+++ b/drivers/ssb/driver_chipcommon_sflash.c
-@@ -0,0 +1,556 @@
-+/*
-+ * Broadcom SiliconBackplane chipcommon serial flash interface
-+ *
-+ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
-+ * Copyright 2010, Broadcom Corporation
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+
-+#include <linux/ssb/ssb.h>
-+#include <linux/ssb/ssb_driver_chipcommon.h>
-+#include <linux/delay.h>
-+
-+#include "ssb_private.h"
-+
-+#define NUM_RETRIES 3
-+
-+
-+/* Issue a serial flash command */
-+static inline void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
-+{
-+ chipco_write32(cc, SSB_CHIPCO_FLASHCTL,
-+ SSB_CHIPCO_FLASHCTL_START | opcode);
-+ while (chipco_read32(cc, SSB_CHIPCO_FLASHCTL)
-+ & SSB_CHIPCO_FLASHCTL_BUSY)
-+ ;
-+}
-+
-+
-+static inline void ssb_sflash_write_u8(struct ssb_chipcommon *cc,
-+ u32 offset, u8 byte)
-+{
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, offset);
-+ chipco_write32(cc, SSB_CHIPCO_FLASHDATA, byte);
-+}
-+
-+/* Initialize serial flash access */
-+int ssb_sflash_init(struct ssb_chipcommon *cc)
-+{
-+ u32 id, id2;
-+
-+ memset(&cc->sflash, 0, sizeof(struct ssb_sflash));
-+
-+ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_FLASHT_STSER:
-+ /* Probe for ST chips */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_DP);
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 0);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
-+ id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
-+ cc->sflash.blocksize = 64 * 1024;
-+ switch (id) {
-+ case 0x11:
-+ /* ST M25P20 2 Mbit Serial Flash */
-+ cc->sflash.numblocks = 4;
-+ break;
-+ case 0x12:
-+ /* ST M25P40 4 Mbit Serial Flash */
-+ cc->sflash.numblocks = 8;
-+ break;
-+ case 0x13:
-+ /* ST M25P80 8 Mbit Serial Flash */
-+ cc->sflash.numblocks = 16;
-+ break;
-+ case 0x14:
-+ /* ST M25P16 16 Mbit Serial Flash */
-+ cc->sflash.numblocks = 32;
-+ break;
-+ case 0x15:
-+ /* ST M25P32 32 Mbit Serial Flash */
-+ cc->sflash.numblocks = 64;
-+ break;
-+ case 0x16:
-+ /* ST M25P64 64 Mbit Serial Flash */
-+ cc->sflash.numblocks = 128;
-+ break;
-+ case 0x17:
-+ /* ST M25FL128 128 Mbit Serial Flash */
-+ cc->sflash.numblocks = 256;
-+ break;
-+ case 0xbf:
-+ /* All of the following flashes are SST with
-+ * 4KB subsectors. Others should be added but
-+ * We'll have to revamp the way we identify them
-+ * since RES is not eough to disambiguate them.
-+ */
-+ cc->sflash.blocksize = 4 * 1024;
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 1);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
-+ id2 = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
-+ switch (id2) {
-+ case 1:
-+ /* SST25WF512 512 Kbit Serial Flash */
-+ case 0x48:
-+ /* SST25VF512 512 Kbit Serial Flash */
-+ cc->sflash.numblocks = 16;
-+ break;
-+ case 2:
-+ /* SST25WF010 1 Mbit Serial Flash */
-+ case 0x49:
-+ /* SST25VF010 1 Mbit Serial Flash */
-+ cc->sflash.numblocks = 32;
-+ break;
-+ case 3:
-+ /* SST25WF020 2 Mbit Serial Flash */
-+ case 0x43:
-+ /* SST25VF020 2 Mbit Serial Flash */
-+ cc->sflash.numblocks = 64;
-+ break;
-+ case 4:
-+ /* SST25WF040 4 Mbit Serial Flash */
-+ case 0x44:
-+ /* SST25VF040 4 Mbit Serial Flash */
-+ case 0x8d:
-+ /* SST25VF040B 4 Mbit Serial Flash */
-+ cc->sflash.numblocks = 128;
-+ break;
-+ case 5:
-+ /* SST25WF080 8 Mbit Serial Flash */
-+ case 0x8e:
-+ /* SST25VF080B 8 Mbit Serial Flash */
-+ cc->sflash.numblocks = 256;
-+ break;
-+ case 0x41:
-+ /* SST25VF016 16 Mbit Serial Flash */
-+ cc->sflash.numblocks = 512;
-+ break;
-+ case 0x4a:
-+ /* SST25VF032 32 Mbit Serial Flash */
-+ cc->sflash.numblocks = 1024;
-+ break;
-+ case 0x4b:
-+ /* SST25VF064 64 Mbit Serial Flash */
-+ cc->sflash.numblocks = 2048;
-+ break;
-+ }
-+ break;
-+ }
-+ break;
-+
-+ case SSB_CHIPCO_FLASHT_ATSER:
-+ /* Probe for Atmel chips */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
-+ id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA) & 0x3c;
-+ switch (id) {
-+ case 0xc:
-+ /* Atmel AT45DB011 1Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 512;
-+ break;
-+ case 0x14:
-+ /* Atmel AT45DB021 2Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 1024;
-+ break;
-+ case 0x1c:
-+ /* Atmel AT45DB041 4Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 2048;
-+ break;
-+ case 0x24:
-+ /* Atmel AT45DB081 8Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 4096;
-+ break;
-+ case 0x2c:
-+ /* Atmel AT45DB161 16Mbit Serial Flash */
-+ cc->sflash.blocksize = 512;
-+ cc->sflash.numblocks = 4096;
-+ break;
-+ case 0x34:
-+ /* Atmel AT45DB321 32Mbit Serial Flash */
-+ cc->sflash.blocksize = 512;
-+ cc->sflash.numblocks = 8192;
-+ break;
-+ case 0x3c:
-+ /* Atmel AT45DB642 64Mbit Serial Flash */
-+ cc->sflash.blocksize = 1024;
-+ cc->sflash.numblocks = 8192;
-+ break;
-+ }
-+ break;
-+ }
-+
-+ cc->sflash.size = cc->sflash.blocksize * cc->sflash.numblocks;
-+
-+ return cc->sflash.size ? 0 : -ENODEV;
-+}
-+
-+/* Read len bytes starting at offset into buf. Returns number of bytes read. */
-+int ssb_sflash_read(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ u8 *buf)
-+{
-+ u8 *from, *to;
-+ u32 cnt, i;
-+
-+ if (!len)
-+ return 0;
-+
-+ if ((offset + len) > cc->sflash.size)
-+ return -EINVAL;
-+
-+ if ((len >= 4) && (offset & 3))
-+ cnt = 4 - (offset & 3);
-+ else if ((len >= 4) && ((u32)buf & 3))
-+ cnt = 4 - ((u32)buf & 3);
-+ else
-+ cnt = len;
-+
-+
-+ if (cc->dev->id.revision == 12)
-+ from = (u8 *)KSEG1ADDR(SSB_FLASH2 + offset);
-+ else
-+ from = (u8 *)KSEG0ADDR(SSB_FLASH2 + offset);
-+
-+ to = (u8 *)buf;
-+
-+ if (cnt < 4) {
-+ for (i = 0; i < cnt; i++) {
-+ *to = readb(from);
-+ from++;
-+ to++;
-+ }
-+ return cnt;
-+ }
-+
-+ while (cnt >= 4) {
-+ *(u32 *)to = readl(from);
-+ from += 4;
-+ to += 4;
-+ cnt -= 4;
-+ }
-+
-+ return len - cnt;
-+}
-+
-+/* Poll for command completion. Returns zero when complete. */
-+int ssb_sflash_poll(struct ssb_chipcommon *cc, u32 offset)
-+{
-+ if (offset >= cc->sflash.size)
-+ return -22;
-+
-+ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_FLASHT_STSER:
-+ /* Check for ST Write In Progress bit */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RDSR);
-+ return chipco_read32(cc, SSB_CHIPCO_FLASHDATA)
-+ & SSB_CHIPCO_FLASHSTA_ST_WIP;
-+ case SSB_CHIPCO_FLASHT_ATSER:
-+ /* Check for Atmel Ready bit */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
-+ return !(chipco_read32(cc, SSB_CHIPCO_FLASHDATA)
-+ & SSB_CHIPCO_FLASHSTA_AT_READY);
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static int sflash_st_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct ssb_bus *bus = cc->dev->bus;
-+ int ret = 0;
-+ bool is4712b0 = (bus->chip_id == 0x4712) && (bus->chip_rev == 3);
-+ u32 mask;
-+
-+
-+ /* Enable writes */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_WREN);
-+ if (is4712b0) {
-+ mask = 1 << 14;
-+ ssb_sflash_write_u8(cc, offset, *buf++);
-+ /* Set chip select */
-+ chipco_set32(cc, SSB_CHIPCO_GPIOOUT, mask);
-+ /* Issue a page program with the first byte */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_PP);
-+ ret = 1;
-+ offset++;
-+ len--;
-+ while (len > 0) {
-+ if ((offset & 255) == 0) {
-+ /* Page boundary, drop cs and return */
-+ chipco_mask32(cc, SSB_CHIPCO_GPIOOUT, ~mask);
-+ udelay(1);
-+ if (!ssb_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ return ret;
-+ } else {
-+ /* Write single byte */
-+ ssb_sflash_cmd(cc, *buf++);
-+ }
-+ ret++;
-+ offset++;
-+ len--;
-+ }
-+ /* All done, drop cs */
-+ chipco_mask32(cc, SSB_CHIPCO_GPIOOUT, ~mask);
-+ udelay(1);
-+ if (!ssb_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ } else if (cc->dev->id.revision >= 20) {
-+ ssb_sflash_write_u8(cc, offset, *buf++);
-+ /* Issue a page program with CSA bit set */
-+ ssb_sflash_cmd(cc,
-+ SSB_CHIPCO_FLASHCTL_ST_CSA |
-+ SSB_CHIPCO_FLASHCTL_ST_PP);
-+ ret = 1;
-+ offset++;
-+ len--;
-+ while (len > 0) {
-+ if ((offset & 255) == 0) {
-+ /* Page boundary, poll droping cs and return */
-+ chipco_write32(cc, SSB_CHIPCO_FLASHCTL, 0);
-+ udelay(1);
-+ if (!ssb_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ return ret;
-+ } else {
-+ /* Write single byte */
-+ ssb_sflash_cmd(cc,
-+ SSB_CHIPCO_FLASHCTL_ST_CSA |
-+ *buf++);
-+ }
-+ ret++;
-+ offset++;
-+ len--;
-+ }
-+ /* All done, drop cs & poll */
-+ chipco_write32(cc, SSB_CHIPCO_FLASHCTL, 0);
-+ udelay(1);
-+ if (!ssb_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ } else {
-+ ret = 1;
-+ ssb_sflash_write_u8(cc, offset, *buf);
-+ /* Page program */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_PP);
-+ }
-+ return ret;
-+}
-+
-+static int sflash_at_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct ssb_sflash *sfl = &cc->sflash;
-+ u32 page, byte, mask;
-+ int ret = 0;
-+ mask = sfl->blocksize - 1;
-+ page = (offset & ~mask) << 1;
-+ byte = offset & mask;
-+ /* Read main memory page into buffer 1 */
-+ if (byte || (len < sfl->blocksize)) {
-+ int i = 100;
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, page);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD);
-+ /* 250 us for AT45DB321B */
-+ while (i > 0 && ssb_sflash_poll(cc, offset)) {
-+ udelay(10);
-+ i--;
-+ }
-+ BUG_ON(!ssb_sflash_poll(cc, offset));
-+ }
-+ /* Write into buffer 1 */
-+ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
-+ ssb_sflash_write_u8(cc, byte++, *buf++);
-+ ssb_sflash_cmd(cc,
-+ SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE);
-+ }
-+ /* Write buffer 1 into main memory page */
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, page);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_BUF1_PROGRAM);
-+
-+ return ret;
-+}
-+
-+/* Write len bytes starting at offset into buf. Returns number of bytes
-+ * written. Caller should poll for completion.
-+ */
-+int ssb_sflash_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct ssb_sflash *sfl;
-+ int ret = 0, tries = NUM_RETRIES;
-+
-+ if (!len)
-+ return 0;
-+
-+ if ((offset + len) > cc->sflash.size)
-+ return -EINVAL;
-+
-+ sfl = &cc->sflash;
-+ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_FLASHT_STSER:
-+ do {
-+ ret = sflash_st_write(cc, offset, len, buf);
-+ tries--;
-+ } while (ret == -EAGAIN && tries > 0);
-+
-+ if (ret == -EAGAIN && tries == 0) {
-+ pr_info("ST Flash rejected write\n");
-+ ret = -EIO;
-+ }
-+ break;
-+ case SSB_CHIPCO_FLASHT_ATSER:
-+ ret = sflash_at_write(cc, offset, len, buf);
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+/* Erase a region. Returns number of bytes scheduled for erasure.
-+ * Caller should poll for completion.
-+ */
-+int ssb_sflash_erase(struct ssb_chipcommon *cc, u32 offset)
-+{
-+ struct ssb_sflash *sfl;
-+
-+ if (offset >= cc->sflash.size)
-+ return -EINVAL;
-+
-+ sfl = &cc->sflash;
-+ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_FLASHT_STSER:
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_WREN);
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, offset);
-+ /* Newer flashes have "sub-sectors" which can be erased independently
-+ * with a new command: ST_SSE. The ST_SE command erases 64KB just as
-+ * before.
-+ */
-+ ssb_sflash_cmd(cc, (sfl->blocksize < (64 * 1024)) ? SSB_CHIPCO_FLASHCTL_ST_SSE : SSB_CHIPCO_FLASHCTL_ST_SE);
-+ return sfl->blocksize;
-+ case SSB_CHIPCO_FLASHT_ATSER:
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, offset << 1);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE);
-+ return sfl->blocksize;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * writes the appropriate range of flash, a NULL buf simply erases
-+ * the region of flash
-+ */
-+int ssb_sflash_commit(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct ssb_sflash *sfl;
-+ u8 *block = NULL, *cur_ptr, *blk_ptr;
-+ u32 blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
-+ u32 blk_offset, blk_len, copied;
-+ int bytes, ret = 0;
-+
-+ /* Check address range */
-+ if (len <= 0)
-+ return 0;
-+
-+ sfl = &cc->sflash;
-+ if ((offset + len) > sfl->size)
-+ return -EINVAL;
-+
-+ blocksize = sfl->blocksize;
-+ mask = blocksize - 1;
-+
-+ /* Allocate a block of mem */
-+ block = kmalloc(blocksize, GFP_KERNEL);
-+ if (!block)
-+ return -ENOMEM;
-+
-+ while (len) {
-+ /* Align offset */
-+ cur_offset = offset & ~mask;
-+ cur_length = blocksize;
-+ cur_ptr = block;
-+
-+ remainder = blocksize - (offset & mask);
-+ if (len < remainder)
-+ cur_retlen = len;
-+ else
-+ cur_retlen = remainder;
-+
-+ /* buf == NULL means erase only */
-+ if (buf) {
-+ /* Copy existing data into holding block if necessary */
-+ if ((offset & mask) || (len < blocksize)) {
-+ blk_offset = cur_offset;
-+ blk_len = cur_length;
-+ blk_ptr = cur_ptr;
-+
-+ /* Copy entire block */
-+ while (blk_len) {
-+ copied = ssb_sflash_read(cc,
-+ blk_offset,
-+ blk_len, blk_ptr);
-+ blk_offset += copied;
-+ blk_len -= copied;
-+ blk_ptr += copied;
-+ }
-+ }
-+
-+ /* Copy input data into holding block */
-+ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
-+ }
-+
-+ /* Erase block */
-+ ret = ssb_sflash_erase(cc, cur_offset);
-+ if (ret < 0)
-+ goto done;
-+
-+ while (ssb_sflash_poll(cc, cur_offset));
-+
-+ /* buf == NULL means erase only */
-+ if (!buf) {
-+ offset += cur_retlen;
-+ len -= cur_retlen;
-+ continue;
-+ }
-+
-+ /* Write holding block */
-+ while (cur_length > 0) {
-+ bytes = ssb_sflash_write(cc, cur_offset,
-+ cur_length, cur_ptr);
-+
-+ if (bytes < 0) {
-+ ret = bytes;
-+ goto done;
-+ }
-+
-+ while (ssb_sflash_poll(cc, cur_offset))
-+ ;
-+
-+ cur_offset += bytes;
-+ cur_length -= bytes;
-+ cur_ptr += bytes;
-+ }
-+
-+ offset += cur_retlen;
-+ len -= cur_retlen;
-+ buf += cur_retlen;
-+ }
-+
-+ ret = len;
-+done:
-+ kfree(block);
-+ return ret;
-+}
---- a/drivers/ssb/driver_mipscore.c
-+++ b/drivers/ssb/driver_mipscore.c
-@@ -203,7 +203,13 @@ static void ssb_mips_flash_detect(struct
- switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
- case SSB_CHIPCO_FLASHT_STSER:
- case SSB_CHIPCO_FLASHT_ATSER:
-+#ifdef CONFIG_SSB_SFLASH
-+ pr_info("found serial flash.\n");
-+ bus->chipco.flash_type = SSB_SFLASH;
-+ ssb_sflash_init(&bus->chipco);
-+#else
- pr_info("serial flash not supported.\n");
-+#endif /* CONFIG_SSB_SFLASH */
- break;
- case SSB_CHIPCO_FLASHT_PARA:
- pr_info("found parallel flash.\n");
---- a/drivers/ssb/ssb_private.h
-+++ b/drivers/ssb/ssb_private.h
-@@ -192,6 +192,10 @@ extern int ssb_devices_freeze(struct ssb
- extern int ssb_devices_thaw(struct ssb_freeze_context *ctx);
-
-
-+#ifdef CONFIG_SSB_SFLASH
-+/* driver_chipcommon_sflash.c */
-+int ssb_sflash_init(struct ssb_chipcommon *cc);
-+#endif /* CONFIG_SSB_SFLASH */
-
- /* b43_pci_bridge.c */
- #ifdef CONFIG_SSB_B43_PCI_BRIDGE
---- a/include/linux/ssb/ssb_driver_chipcommon.h
-+++ b/include/linux/ssb/ssb_driver_chipcommon.h
-@@ -503,8 +503,10 @@
- #define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */
- #define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
- #define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
--#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
--#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */
-+#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00D9 /* Deep Power-down */
-+#define SSB_CHIPCO_FLASHCTL_ST_RES 0x03AB /* Read Electronic Signature */
-+#define SSB_CHIPCO_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
-+#define SSB_CHIPCO_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
-
- /* Status register bits for ST flashes */
- #define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */
-@@ -585,6 +587,7 @@ struct ssb_chipcommon_pmu {
- #ifdef CONFIG_SSB_DRIVER_MIPS
- enum ssb_flash_type {
- SSB_PFLASH,
-+ SSB_SFLASH,
- };
-
- struct ssb_pflash {
-@@ -592,6 +595,14 @@ struct ssb_pflash {
- u32 window;
- u32 window_size;
- };
-+
-+#ifdef CONFIG_SSB_SFLASH
-+struct ssb_sflash {
-+ u32 blocksize; /* Block size */
-+ u32 numblocks; /* Number of blocks */
-+ u32 size; /* Total size in bytes */
-+};
-+#endif /* CONFIG_SSB_SFLASH */
- #endif /* CONFIG_SSB_DRIVER_MIPS */
-
- struct ssb_chipcommon {
-@@ -605,6 +616,9 @@ struct ssb_chipcommon {
- enum ssb_flash_type flash_type;
- union {
- struct ssb_pflash pflash;
-+#ifdef CONFIG_SSB_SFLASH
-+ struct ssb_sflash sflash;
-+#endif /* CONFIG_SSB_SFLASH */
- };
- #endif /* CONFIG_SSB_DRIVER_MIPS */
- };
-@@ -666,6 +680,18 @@ extern int ssb_chipco_serial_init(struct
- struct ssb_serial_port *ports);
- #endif /* CONFIG_SSB_SERIAL */
-
-+#ifdef CONFIG_SSB_SFLASH
-+/* Chipcommon sflash support. */
-+int ssb_sflash_read(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ u8 *buf);
-+int ssb_sflash_poll(struct ssb_chipcommon *cc, u32 offset);
-+int ssb_sflash_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf);
-+int ssb_sflash_erase(struct ssb_chipcommon *cc, u32 offset);
-+int ssb_sflash_commit(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf);
-+#endif /* CONFIG_SSB_SFLASH */
-+
- /* PMU support */
- extern void ssb_pmu_init(struct ssb_chipcommon *cc);
-
+++ /dev/null
-From 4f314ac9edbc80897f158fdb4e1b1de8a2d0d432 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 24 Jul 2011 21:10:49 +0200
-Subject: [PATCH 16/26] brcm47xx: add common interface for sflash
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/bcm47xx/Makefile | 2 +-
- arch/mips/bcm47xx/bus.c | 94 ++++++++++++++++++++++++++++++
- arch/mips/bcm47xx/setup.c | 8 +++
- arch/mips/include/asm/mach-bcm47xx/bus.h | 37 ++++++++++++
- 4 files changed, 140 insertions(+), 1 deletions(-)
- create mode 100644 arch/mips/bcm47xx/bus.c
- create mode 100644 arch/mips/include/asm/mach-bcm47xx/bus.h
-
---- a/arch/mips/bcm47xx/Makefile
-+++ b/arch/mips/bcm47xx/Makefile
-@@ -3,5 +3,5 @@
- # under Linux.
- #
-
--obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
-+obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o bus.o
- obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
---- /dev/null
-+++ b/arch/mips/bcm47xx/bus.c
-@@ -0,0 +1,94 @@
-+/*
-+ * BCM947xx nvram variable access
-+ *
-+ * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <bus.h>
-+
-+static int bcm47xx_sflash_bcma_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
-+{
-+ return bcma_sflash_read(dev->bcc, offset, len, buf);
-+}
-+
-+static int bcm47xx_sflash_bcma_poll(struct bcm47xx_sflash *dev, u32 offset)
-+{
-+ return bcma_sflash_poll(dev->bcc, offset);
-+}
-+
-+static int bcm47xx_sflash_bcma_write(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
-+{
-+ return bcma_sflash_write(dev->bcc, offset, len, buf);
-+}
-+
-+static int bcm47xx_sflash_bcma_erase(struct bcm47xx_sflash *dev, u32 offset)
-+{
-+ return bcma_sflash_erase(dev->bcc, offset);
-+}
-+
-+static int bcm47xx_sflash_bcma_commit(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
-+{
-+ return bcma_sflash_commit(dev->bcc, offset, len, buf);
-+}
-+
-+void bcm47xx_sflash_struct_bcma_init(struct bcm47xx_sflash *sflash, struct bcma_drv_cc *bcc)
-+{
-+ sflash->sflash_type = BCM47XX_BUS_TYPE_BCMA;
-+ sflash->bcc = bcc;
-+
-+ sflash->read = bcm47xx_sflash_bcma_read;
-+ sflash->poll = bcm47xx_sflash_bcma_poll;
-+ sflash->write = bcm47xx_sflash_bcma_write;
-+ sflash->erase = bcm47xx_sflash_bcma_erase;
-+ sflash->commit = bcm47xx_sflash_bcma_commit;
-+
-+ sflash->blocksize = bcc->sflash.blocksize;
-+ sflash->numblocks = bcc->sflash.numblocks;
-+ sflash->size = bcc->sflash.size;
-+}
-+
-+static int bcm47xx_sflash_ssb_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
-+{
-+ return ssb_sflash_read(dev->scc, offset, len, buf);
-+}
-+
-+static int bcm47xx_sflash_ssb_poll(struct bcm47xx_sflash *dev, u32 offset)
-+{
-+ return ssb_sflash_poll(dev->scc, offset);
-+}
-+
-+static int bcm47xx_sflash_ssb_write(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
-+{
-+ return ssb_sflash_write(dev->scc, offset, len, buf);
-+}
-+
-+static int bcm47xx_sflash_ssb_erase(struct bcm47xx_sflash *dev, u32 offset)
-+{
-+ return ssb_sflash_erase(dev->scc, offset);
-+}
-+
-+static int bcm47xx_sflash_ssb_commit(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
-+{
-+ return ssb_sflash_commit(dev->scc, offset, len, buf);
-+}
-+
-+void bcm47xx_sflash_struct_ssb_init(struct bcm47xx_sflash *sflash, struct ssb_chipcommon *scc)
-+{
-+ sflash->sflash_type = BCM47XX_BUS_TYPE_SSB;
-+ sflash->scc = scc;
-+
-+ sflash->read = bcm47xx_sflash_ssb_read;
-+ sflash->poll = bcm47xx_sflash_ssb_poll;
-+ sflash->write = bcm47xx_sflash_ssb_write;
-+ sflash->erase = bcm47xx_sflash_ssb_erase;
-+ sflash->commit = bcm47xx_sflash_ssb_commit;
-+
-+ sflash->blocksize = scc->sflash.blocksize;
-+ sflash->numblocks = scc->sflash.numblocks;
-+ sflash->size = scc->sflash.size;
-+}
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -43,6 +43,8 @@ EXPORT_SYMBOL(bcm47xx_bus);
- enum bcm47xx_bus_type bcm47xx_bus_type;
- EXPORT_SYMBOL(bcm47xx_bus_type);
-
-+struct bcm47xx_sflash bcm47xx_sflash;
-+
- static void bcm47xx_machine_restart(char *command)
- {
- printk(KERN_ALERT "Please stand by while rebooting the system...\n");
-@@ -291,6 +293,9 @@ static void __init bcm47xx_register_ssb(
- if (err)
- panic("Failed to initialize SSB bus (err %d)\n", err);
-
-+ if (bcm47xx_bus.ssb.chipco.flash_type == SSB_SFLASH)
-+ bcm47xx_sflash_struct_ssb_init(&bcm47xx_sflash, &bcm47xx_bus.ssb.chipco);
-+
- mcore = &bcm47xx_bus.ssb.mipscore;
- if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
- if (strstr(buf, "console=ttyS1")) {
-@@ -315,6 +320,9 @@ static void __init bcm47xx_register_bcma
- err = bcma_host_soc_register(&bcm47xx_bus.bcma);
- if (err)
- panic("Failed to initialize BCMA bus (err %d)\n", err);
-+
-+ if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_SFLASH)
-+ bcm47xx_sflash_struct_bcma_init(&bcm47xx_sflash, &bcm47xx_bus.bcma.bus.drv_cc);
- }
- #endif
-
---- /dev/null
-+++ b/arch/mips/include/asm/mach-bcm47xx/bus.h
-@@ -0,0 +1,37 @@
-+/*
-+ * BCM947xx nvram variable access
-+ *
-+ * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/ssb/ssb.h>
-+#include <linux/bcma/bcma.h>
-+#include <bcm47xx.h>
-+
-+struct bcm47xx_sflash {
-+ enum bcm47xx_bus_type sflash_type;
-+ union {
-+ struct ssb_chipcommon *scc;
-+ struct bcma_drv_cc *bcc;
-+ };
-+
-+ int (*read)(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf);
-+ int (*poll)(struct bcm47xx_sflash *dev, u32 offset);
-+ int (*write)(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf);
-+ int (*erase)(struct bcm47xx_sflash *dev, u32 offset);
-+ int (*commit)(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf);
-+
-+ u32 blocksize; /* Block size */
-+ u32 numblocks; /* Number of blocks */
-+ u32 size; /* Total size in bytes */
-+};
-+
-+void bcm47xx_sflash_struct_bcma_init(struct bcm47xx_sflash *sflash, struct bcma_drv_cc *bcc);
-+void bcm47xx_sflash_struct_ssb_init(struct bcm47xx_sflash *sflash, struct ssb_chipcommon *scc);
-+
-+extern struct bcm47xx_sflash bcm47xx_sflash;
+++ /dev/null
-From d50d2d8e3ab5446f791deff0cb78820989ed93e7 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 17 Jul 2011 14:54:11 +0200
-Subject: [PATCH 06/19] mtd: bcm47xx: add bcm47xx part parser
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/mtd/Kconfig | 7 +
- drivers/mtd/Makefile | 1 +
- drivers/mtd/bcm47xxpart.c | 542 +++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 550 insertions(+), 0 deletions(-)
- create mode 100644 drivers/mtd/bcm47xxpart.c
-
---- a/drivers/mtd/Kconfig
-+++ b/drivers/mtd/Kconfig
-@@ -164,6 +164,13 @@ config MTD_MYLOADER_PARTS
- You will still need the parsing functions to be called by the driver
- for your particular device. It won't happen automatically.
-
-+config MTD_BCM47XX_PARTS
-+ tristate "BCM47XX partitioning support"
-+ default y
-+ depends on BCM47XX
-+ ---help---
-+ bcm47XX partitioning support
-+
- comment "User Modules And Translation Layers"
-
- config MTD_CHAR
---- a/drivers/mtd/Makefile
-+++ b/drivers/mtd/Makefile
-@@ -12,6 +12,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdli
- obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
- obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
- obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
-+obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
-
- # 'Users' - code which presents functionality to userspace.
- obj-$(CONFIG_MTD_CHAR) += mtdchar.o
---- /dev/null
-+++ b/drivers/mtd/bcm47xxpart.c
-@@ -0,0 +1,542 @@
-+/*
-+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
-+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
-+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
-+ *
-+ * original functions for finding root filesystem from Mike Baker
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this program; if not, write to the Free Software Foundation, Inc.,
-+ * 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ * Copyright 2001-2003, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * Flash mapping for BCM947XX boards
-+ */
-+
-+#define pr_fmt(fmt) "bcm47xx_part: " fmt
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/wait.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/crc32.h>
-+#include <linux/io.h>
-+#include <asm/mach-bcm47xx/nvram.h>
-+#include <asm/mach-bcm47xx/bcm47xx.h>
-+#include <asm/fw/cfe/cfe_api.h>
-+
-+
-+#define TRX_MAGIC 0x30524448 /* "HDR0" */
-+#define TRX_VERSION 1
-+#define TRX_MAX_LEN 0x3A0000
-+#define TRX_NO_HEADER 1 /* Do not write TRX header */
-+#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
-+#define TRX_MAX_OFFSET 3
-+
-+struct trx_header {
-+ u32 magic; /* "HDR0" */
-+ u32 len; /* Length of file including header */
-+ u32 crc32; /* 32-bit CRC from flag_version to end of file */
-+ u32 flag_version; /* 0:15 flags, 16:31 version */
-+ u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
-+};
-+
-+/* for Edimax Print servers which use an additional header
-+ * then the firmware on flash looks like :
-+ * EDIMAX HEADER | TRX HEADER
-+ * As this header is 12 bytes long we have to handle it
-+ * and skip it to find the TRX header
-+ */
-+#define EDIMAX_PS_HEADER_MAGIC 0x36315350 /* "PS16" */
-+#define EDIMAX_PS_HEADER_LEN 0xc /* 12 bytes long for edimax header */
-+
-+#define NVRAM_SPACE 0x8000
-+
-+#define ROUTER_NETGEAR_WGR614L 1
-+#define ROUTER_NETGEAR_WNR834B 2
-+#define ROUTER_NETGEAR_WNDR3300 3
-+#define ROUTER_NETGEAR_WNR3500L 4
-+#define ROUTER_SIMPLETECH_SIMPLESHARE 5
-+#define ROUTER_NETGEAR_WNDR3400 6
-+
-+static int
-+find_cfe_size(struct mtd_info *mtd)
-+{
-+ struct trx_header *trx;
-+ unsigned char buf[512];
-+ int off;
-+ size_t len;
-+ int blocksize;
-+
-+ trx = (struct trx_header *) buf;
-+
-+ blocksize = mtd->erasesize;
-+ if (blocksize < 0x10000)
-+ blocksize = 0x10000;
-+
-+ for (off = (128*1024); off < mtd->size; off += blocksize) {
-+ memset(buf, 0xe5, sizeof(buf));
-+
-+ /*
-+ * Read into buffer
-+ */
-+ if (mtd->read(mtd, off, sizeof(buf), &len, buf) ||
-+ len != sizeof(buf))
-+ continue;
-+
-+ if (le32_to_cpu(trx->magic) == EDIMAX_PS_HEADER_MAGIC) {
-+ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN,
-+ sizeof(buf), &len, buf) || len != sizeof(buf)) {
-+ continue;
-+ } else {
-+ pr_notice("Found edimax header\n");
-+ }
-+ }
-+
-+ /* found a TRX header */
-+ if (le32_to_cpu(trx->magic) == TRX_MAGIC)
-+ goto found;
-+ }
-+
-+ pr_notice("%s: Couldn't find bootloader size\n", mtd->name);
-+ return -1;
-+
-+ found:
-+ pr_notice("bootloader size: %d\n", off);
-+ return off;
-+
-+}
-+
-+/*
-+ * Copied from mtdblock.c
-+ *
-+ * Cache stuff...
-+ *
-+ * Since typical flash erasable sectors are much larger than what Linux's
-+ * buffer cache can handle, we must implement read-modify-write on flash
-+ * sectors for each block write requests. To avoid over-erasing flash sectors
-+ * and to speed things up, we locally cache a whole flash sector while it is
-+ * being written to until a different sector is required.
-+ */
-+
-+static void erase_callback(struct erase_info *done)
-+{
-+ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
-+ wake_up(wait_q);
-+}
-+
-+static int erase_write(struct mtd_info *mtd, unsigned long pos,
-+ int len, const char *buf)
-+{
-+ struct erase_info erase;
-+ DECLARE_WAITQUEUE(wait, current);
-+ wait_queue_head_t wait_q;
-+ size_t retlen;
-+ int ret;
-+
-+ /*
-+ * First, let's erase the flash block.
-+ */
-+
-+ init_waitqueue_head(&wait_q);
-+ erase.mtd = mtd;
-+ erase.callback = erase_callback;
-+ erase.addr = pos;
-+ erase.len = len;
-+ erase.priv = (u_long)&wait_q;
-+
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ add_wait_queue(&wait_q, &wait);
-+
-+ ret = mtd->erase(mtd, &erase);
-+ if (ret) {
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&wait_q, &wait);
-+ pr_warn("erase of region [0x%lx, 0x%x] on \"%s\" failed\n",
-+ pos, len, mtd->name);
-+ return ret;
-+ }
-+
-+ schedule(); /* Wait for erase to finish. */
-+ remove_wait_queue(&wait_q, &wait);
-+
-+ /*
-+ * Next, write data to flash.
-+ */
-+
-+ ret = mtd->write(mtd, pos, len, &retlen, buf);
-+ if (ret)
-+ return ret;
-+ if (retlen != len)
-+ return -EIO;
-+ return 0;
-+}
-+
-+
-+static int
-+find_dual_image_off(struct mtd_info *mtd)
-+{
-+ struct trx_header trx;
-+ int off, blocksize;
-+ size_t len;
-+
-+ blocksize = mtd->erasesize;
-+ if (blocksize < 0x10000)
-+ blocksize = 0x10000;
-+
-+ for (off = (128*1024); off < mtd->size; off += blocksize) {
-+ memset(&trx, 0xe5, sizeof(trx));
-+ /*
-+ * Read into buffer
-+ */
-+ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
-+ len != sizeof(trx))
-+ continue;
-+ /* found last TRX header */
-+ if (le32_to_cpu(trx.magic) == TRX_MAGIC) {
-+ if (le32_to_cpu(trx.flag_version >> 16) == 2) {
-+ pr_notice("dual image TRX header found\n");
-+ return mtd->size / 2;
-+ } else {
-+ return 0;
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+static int
-+find_root(struct mtd_info *mtd, struct mtd_partition *part)
-+{
-+ struct trx_header trx, *trx2;
-+ unsigned char buf[512], *block;
-+ int off, blocksize, trxoff = 0;
-+ u32 i, crc = ~0;
-+ size_t len;
-+ bool edimax = false;
-+
-+ blocksize = mtd->erasesize;
-+ if (blocksize < 0x10000)
-+ blocksize = 0x10000;
-+
-+ for (off = (128*1024); off < mtd->size; off += blocksize) {
-+ memset(&trx, 0xe5, sizeof(trx));
-+
-+ /*
-+ * Read into buffer
-+ */
-+ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
-+ len != sizeof(trx))
-+ continue;
-+
-+ /* found an edimax header */
-+ if (le32_to_cpu(trx.magic) == EDIMAX_PS_HEADER_MAGIC) {
-+ /* read the correct trx header */
-+ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN,
-+ sizeof(trx), &len, (char *) &trx) ||
-+ len != sizeof(trx)) {
-+ continue;
-+ } else {
-+ pr_notice("Found an edimax ps header\n");
-+ edimax = true;
-+ }
-+ }
-+
-+ /* found a TRX header */
-+ if (le32_to_cpu(trx.magic) == TRX_MAGIC) {
-+ part->offset = le32_to_cpu(trx.offsets[2]) ? :
-+ le32_to_cpu(trx.offsets[1]);
-+ part->size = le32_to_cpu(trx.len);
-+
-+ part->size -= part->offset;
-+ part->offset += off;
-+ if (edimax) {
-+ off += EDIMAX_PS_HEADER_LEN;
-+ trxoff = EDIMAX_PS_HEADER_LEN;
-+ }
-+
-+ goto found;
-+ }
-+ }
-+
-+ pr_warn("%s: Couldn't find root filesystem\n",
-+ mtd->name);
-+ return -1;
-+
-+ found:
-+ pr_notice("TRX offset : %x\n", trxoff);
-+ if (part->size == 0)
-+ return 0;
-+
-+ if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf))
-+ return 0;
-+
-+ /* Move the fs outside of the trx */
-+ part->size = 0;
-+
-+ if (trx.len != part->offset + part->size - off) {
-+ /* Update the trx offsets and length */
-+ trx.len = part->offset + part->size - off;
-+
-+ /* Update the trx crc32 */
-+ for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
-+ if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf))
-+ return 0;
-+ crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
-+ }
-+ trx.crc32 = crc;
-+
-+ /* read first eraseblock from the trx */
-+ block = kmalloc(mtd->erasesize, GFP_KERNEL);
-+ trx2 = (struct trx_header *) block;
-+ if (mtd->read(mtd, off - trxoff, mtd->erasesize, &len, block) || len != mtd->erasesize) {
-+ pr_err("Error accessing the first trx eraseblock\n");
-+ return 0;
-+ }
-+
-+ pr_notice("Updating TRX offsets and length:\n");
-+ pr_notice("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32);
-+ pr_notice("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32);
-+
-+ /* Write updated trx header to the flash */
-+ memcpy(block + trxoff, &trx, sizeof(trx));
-+ if (mtd->unlock)
-+ mtd->unlock(mtd, off - trxoff, mtd->erasesize);
-+ erase_write(mtd, off - trxoff, mtd->erasesize, block);
-+ if (mtd->sync)
-+ mtd->sync(mtd);
-+ kfree(block);
-+ pr_notice("Done\n");
-+ }
-+
-+ return part->size;
-+}
-+
-+static int get_router(void)
-+{
-+ char buf[20];
-+ u32 boardnum = 0;
-+ u16 boardtype = 0;
-+ u16 boardrev = 0;
-+ u32 boardflags = 0;
-+ u16 sdram_init = 0;
-+ u16 cardbus = 0;
-+ u16 strev = 0;
-+
-+ if (nvram_getenv("boardnum", buf, sizeof(buf)) >= 0)
-+ boardnum = simple_strtoul(buf, NULL, 0);
-+ if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
-+ boardtype = simple_strtoul(buf, NULL, 0);
-+ if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
-+ boardrev = simple_strtoul(buf, NULL, 0);
-+ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0)
-+ boardflags = simple_strtoul(buf, NULL, 0);
-+ if (nvram_getenv("sdram_init", buf, sizeof(buf)) >= 0)
-+ sdram_init = simple_strtoul(buf, NULL, 0);
-+ if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
-+ cardbus = simple_strtoul(buf, NULL, 0);
-+ if (nvram_getenv("st_rev", buf, sizeof(buf)) >= 0)
-+ strev = simple_strtoul(buf, NULL, 0);
-+
-+ if ((boardnum == 8 || boardnum == 01)
-+ && boardtype == 0x0472 && cardbus == 1) {
-+ /* Netgear WNR834B, Netgear WNR834Bv2 */
-+ return ROUTER_NETGEAR_WNR834B;
-+ }
-+
-+ if (boardnum == 01 && boardtype == 0x0472 && boardrev == 0x23) {
-+ /* Netgear WNDR-3300 */
-+ return ROUTER_NETGEAR_WNDR3300;
-+ }
-+
-+ if ((boardnum == 83258 || boardnum == 01)
-+ && boardtype == 0x048e
-+ && (boardrev == 0x11 || boardrev == 0x10)
-+ && boardflags == 0x750
-+ && sdram_init == 0x000A) {
-+ /* Netgear WGR614v8/L/WW 16MB ram, cfe v1.3 or v1.5 */
-+ return ROUTER_NETGEAR_WGR614L;
-+ }
-+
-+ if ((boardnum == 1 || boardnum == 3500)
-+ && boardtype == 0x04CF
-+ && (boardrev == 0x1213 || boardrev == 02)) {
-+ /* Netgear WNR3500v2/U/L */
-+ return ROUTER_NETGEAR_WNR3500L;
-+ }
-+
-+ if (boardnum == 1 && boardtype == 0xb4cf && boardrev == 0x1100) {
-+ /* Netgear WNDR3400 */
-+ return ROUTER_NETGEAR_WNDR3400;
-+ }
-+
-+ if (boardtype == 0x042f
-+ && boardrev == 0x10
-+ && boardflags == 0
-+ && strev == 0x11) {
-+ /* Simpletech Simpleshare */
-+ return ROUTER_SIMPLETECH_SIMPLESHARE;
-+ }
-+
-+ return 0;
-+}
-+
-+static int parse_bcm47xx_partitions(struct mtd_info *mtd,
-+ struct mtd_partition **pparts,
-+ struct mtd_part_parser_data *data)
-+{
-+ int cfe_size;
-+ int dual_image_offset = 0;
-+ /* e.g Netgear 0x003e0000-0x003f0000 : "board_data", we exclude this
-+ * part from our mapping to prevent overwriting len/checksum on e.g.
-+ * Netgear WGR614v8/L/WW
-+ */
-+ int custom_data_size = 0;
-+ struct mtd_partition *bcm47xx_parts;
-+
-+ cfe_size = find_cfe_size(mtd);
-+ if (cfe_size < 0)
-+ return 0;
-+
-+ bcm47xx_parts = kzalloc(sizeof(struct mtd_partition) * 6, GFP_KERNEL);
-+
-+ bcm47xx_parts[0].name = "cfe";
-+ bcm47xx_parts[1].name = "linux";
-+ bcm47xx_parts[2].name = "rootfs";
-+ bcm47xx_parts[3].name = "nvram";
-+
-+ /* boot loader */
-+ bcm47xx_parts[0].mask_flags = MTD_WRITEABLE;
-+ bcm47xx_parts[0].offset = 0;
-+ bcm47xx_parts[0].size = cfe_size;
-+
-+ /* nvram */
-+ if (cfe_size != 384 * 1024) {
-+
-+ switch (get_router()) {
-+ case ROUTER_NETGEAR_WGR614L:
-+ case ROUTER_NETGEAR_WNR834B:
-+ case ROUTER_NETGEAR_WNDR3300:
-+ case ROUTER_NETGEAR_WNR3500L:
-+ case ROUTER_NETGEAR_WNDR3400:
-+ /* Netgear: checksum is @ 0x003AFFF8 for 4M flash or checksum
-+ * is @ 0x007AFFF8 for 8M flash
-+ */
-+ custom_data_size = mtd->erasesize;
-+
-+ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize);
-+ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
-+
-+ /* Place CFE board_data into a partition */
-+ bcm47xx_parts[4].name = "board_data";
-+ bcm47xx_parts[4].offset = bcm47xx_parts[3].offset - custom_data_size;
-+ bcm47xx_parts[4].size = custom_data_size;
-+ break;
-+
-+ case ROUTER_SIMPLETECH_SIMPLESHARE:
-+ /* Fixup Simpletech Simple share nvram */
-+
-+ pr_notice("Setting up simpletech nvram\n");
-+ custom_data_size = mtd->erasesize;
-+
-+ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize) * 2;
-+ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
-+
-+ /* Place backup nvram into a partition */
-+ bcm47xx_parts[4].name = "nvram_copy";
-+ bcm47xx_parts[4].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize);
-+ bcm47xx_parts[4].size = roundup(NVRAM_SPACE, mtd->erasesize);
-+ break;
-+
-+ default:
-+ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize);
-+ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
-+ }
-+
-+ } else {
-+ /* nvram (old 128kb config partition on netgear wgt634u) */
-+ bcm47xx_parts[3].offset = bcm47xx_parts[0].size;
-+ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
-+ }
-+
-+ /* dual image offset*/
-+ pr_notice("Looking for dual image\n");
-+ dual_image_offset = find_dual_image_off(mtd);
-+ /* linux (kernel and rootfs) */
-+ if (cfe_size != 384 * 1024) {
-+ if (get_router() == ROUTER_SIMPLETECH_SIMPLESHARE) {
-+ bcm47xx_parts[1].offset = bcm47xx_parts[0].size;
-+ bcm47xx_parts[1].size = bcm47xx_parts[4].offset - dual_image_offset -
-+ bcm47xx_parts[1].offset - custom_data_size;
-+ } else {
-+ bcm47xx_parts[1].offset = bcm47xx_parts[0].size;
-+ bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset -
-+ bcm47xx_parts[1].offset - custom_data_size;
-+ }
-+ } else {
-+ /* do not count the elf loader, which is on one block */
-+ bcm47xx_parts[1].offset = bcm47xx_parts[0].size +
-+ bcm47xx_parts[3].size + mtd->erasesize;
-+ bcm47xx_parts[1].size = mtd->size -
-+ bcm47xx_parts[0].size -
-+ (2*bcm47xx_parts[3].size) -
-+ mtd->erasesize - custom_data_size;
-+ }
-+
-+ /* find and size rootfs */
-+ find_root(mtd, &bcm47xx_parts[2]);
-+ bcm47xx_parts[2].size = mtd->size - dual_image_offset -
-+ bcm47xx_parts[2].offset -
-+ bcm47xx_parts[3].size - custom_data_size;
-+ *pparts = bcm47xx_parts;
-+ return bcm47xx_parts[4].name == NULL ? 4 : 5;
-+}
-+
-+static struct mtd_part_parser bcm47xx_parser = {
-+ .owner = THIS_MODULE,
-+ .parse_fn = parse_bcm47xx_partitions,
-+ .name = "bcm47xx",
-+};
-+
-+static int __init bcm47xx_parser_init(void)
-+{
-+ return register_mtd_parser(&bcm47xx_parser);
-+}
-+
-+static void __exit bcm47xx_parser_exit(void)
-+{
-+ deregister_mtd_parser(&bcm47xx_parser);
-+}
-+
-+module_init(bcm47xx_parser_init);
-+module_exit(bcm47xx_parser_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Parsing code for flash partitions on bcm47xx SoCs");
+++ /dev/null
-From 36f8b899174a445a98fe02ed8d1db177525f0c52 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 17 Jul 2011 14:55:18 +0200
-Subject: [PATCH 07/15] mtd: bcm47xx: add parallel flash driver
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/mtd/maps/Kconfig | 9 ++
- drivers/mtd/maps/Makefile | 1 +
- drivers/mtd/maps/bcm47xx-pflash.c | 188 +++++++++++++++++++++++++++++++++++++
- 3 files changed, 198 insertions(+), 0 deletions(-)
- create mode 100644 drivers/mtd/maps/bcm47xx-pflash.c
-
---- a/drivers/mtd/maps/Kconfig
-+++ b/drivers/mtd/maps/Kconfig
-@@ -257,6 +257,15 @@ config MTD_LANTIQ
- help
- Support for NOR flash attached to the Lantiq SoC's External Bus Unit.
-
-+config MTD_BCM47XX_PFLASH
-+ tristate "bcm47xx parallel flash support"
-+ default y
-+ depends on BCM47XX
-+ select MTD_PARTITIONS
-+ select MTD_BCM47XX_PARTS
-+ help
-+ Support for bcm47xx parallel flash
-+
- config MTD_DILNETPC
- tristate "CFI Flash device mapped on DIL/Net PC"
- depends on X86 && MTD_CFI_INTELEXT && BROKEN
---- a/drivers/mtd/maps/Makefile
-+++ b/drivers/mtd/maps/Makefile
-@@ -58,3 +58,4 @@ obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr
- obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
- obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
- obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
-+obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o
---- /dev/null
-+++ b/drivers/mtd/maps/bcm47xx-pflash.c
-@@ -0,0 +1,188 @@
-+/*
-+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
-+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
-+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
-+ *
-+ * original functions for finding root filesystem from Mike Baker
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this program; if not, write to the Free Software Foundation, Inc.,
-+ * 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ * Copyright 2001-2003, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * Flash mapping for BCM947XX boards
-+ */
-+
-+#define pr_fmt(fmt) "bcm47xx_pflash: " fmt
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/io.h>
-+#include <asm/mach-bcm47xx/bcm47xx.h>
-+#include <linux/platform_device.h>
-+
-+#define WINDOW_ADDR 0x1fc00000
-+#define WINDOW_SIZE 0x400000
-+#define BUSWIDTH 2
-+
-+static struct mtd_info *bcm47xx_mtd;
-+
-+static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+{
-+ if (len == 1) {
-+ memcpy_fromio(to, map->virt + from, len);
-+ } else {
-+ int i;
-+ u16 *dest = (u16 *) to;
-+ u16 *src = (u16 *) (map->virt + from);
-+ for (i = 0; i < (len / 2); i++)
-+ dest[i] = src[i];
-+ if (len & 1)
-+ *((u8 *)dest+len-1) = src[i] & 0xff;
-+ }
-+}
-+
-+static struct map_info bcm47xx_map = {
-+ name: "Physically mapped flash",
-+ size : WINDOW_SIZE,
-+ bankwidth : BUSWIDTH,
-+ phys : WINDOW_ADDR,
-+};
-+
-+static const char *probes[] = { "bcm47xx", NULL };
-+
-+static int bcm47xx_mtd_probe(struct platform_device *pdev)
-+{
-+#ifdef CONFIG_BCM47XX_SSB
-+ struct ssb_chipcommon *ssb_cc;
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ struct bcma_drv_cc *bcma_cc;
-+#endif
-+ int ret = 0;
-+
-+ switch (bcm47xx_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
-+ case BCM47XX_BUS_TYPE_SSB:
-+ ssb_cc = &bcm47xx_bus.ssb.chipco;
-+ if (ssb_cc->flash_type != SSB_PFLASH)
-+ return -ENODEV;
-+
-+ bcm47xx_map.phys = ssb_cc->pflash.window;
-+ bcm47xx_map.size = ssb_cc->pflash.window_size;
-+ bcm47xx_map.bankwidth = ssb_cc->pflash.buswidth;
-+ break;
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
-+ if (bcma_cc->flash_type != BCMA_PFLASH)
-+ return -ENODEV;
-+
-+ bcm47xx_map.phys = bcma_cc->pflash.window;
-+ bcm47xx_map.size = bcma_cc->pflash.window_size;
-+ bcm47xx_map.bankwidth = bcma_cc->pflash.buswidth;
-+ break;
-+#endif
-+ }
-+
-+ pr_notice("flash init: 0x%08x 0x%08lx\n", bcm47xx_map.phys, bcm47xx_map.size);
-+ bcm47xx_map.virt = ioremap_nocache(bcm47xx_map.phys, bcm47xx_map.size);
-+
-+ if (!bcm47xx_map.virt) {
-+ pr_err("Failed to ioremap\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&bcm47xx_map);
-+ /* override copy_from routine */
-+ bcm47xx_map.copy_from = bcm47xx_map_copy_from;
-+
-+ bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map);
-+ if (!bcm47xx_mtd) {
-+ pr_err("Failed to do_map_probe\n");
-+ ret = -ENXIO;
-+ goto err_unmap;
-+ }
-+ bcm47xx_mtd->owner = THIS_MODULE;
-+
-+ pr_notice("Flash device: 0x%lx at 0x%x\n", bcm47xx_map.size, WINDOW_ADDR);
-+
-+ ret = mtd_device_parse_register(bcm47xx_mtd, probes, NULL, NULL, 0);
-+
-+ if (ret) {
-+ pr_err("Flash: mtd_device_register failed\n");
-+ goto err_destroy;
-+ }
-+ return 0;
-+
-+err_destroy:
-+ map_destroy(bcm47xx_mtd);
-+err_unmap:
-+ iounmap(bcm47xx_map.virt);
-+ return ret;
-+}
-+
-+static int __devexit bcm47xx_mtd_remove(struct platform_device *pdev)
-+{
-+ mtd_device_unregister(bcm47xx_mtd);
-+ map_destroy(bcm47xx_mtd);
-+ iounmap(bcm47xx_map.virt);
-+ return 0;
-+}
-+
-+static struct platform_driver bcm47xx_mtd_driver = {
-+ .remove = __devexit_p(bcm47xx_mtd_remove),
-+ .driver = {
-+ .name = "bcm47xx_pflash",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init init_bcm47xx_mtd(void)
-+{
-+ int ret = platform_driver_probe(&bcm47xx_mtd_driver, bcm47xx_mtd_probe);
-+
-+ if (ret)
-+ pr_err("error registering platform driver: %i\n", ret);
-+ return ret;
-+}
-+
-+static void __exit exit_bcm47xx_mtd(void)
-+{
-+ platform_driver_unregister(&bcm47xx_mtd_driver);
-+}
-+
-+module_init(init_bcm47xx_mtd);
-+module_exit(exit_bcm47xx_mtd);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("BCM47XX parallel flash driver");
+++ /dev/null
-From 2e2951220bf63e05449c03a95453680da1029e44 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 17 Jul 2011 14:55:45 +0200
-Subject: [PATCH 08/15] mtd: bcm47xx: add serial flash driver
-
-sflash get the sflash ops from platform device
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/include/asm/mach-bcm47xx/bus.h | 3 +
- drivers/mtd/maps/Kconfig | 9 +
- drivers/mtd/maps/Makefile | 1 +
- drivers/mtd/maps/bcm47xx-sflash.c | 252 ++++++++++++++++++++++++++++++
- 4 files changed, 265 insertions(+), 0 deletions(-)
- create mode 100644 drivers/mtd/maps/bcm47xx-sflash.c
-
---- a/arch/mips/include/asm/mach-bcm47xx/bus.h
-+++ b/arch/mips/include/asm/mach-bcm47xx/bus.h
-@@ -11,6 +11,7 @@
-
- #include <linux/ssb/ssb.h>
- #include <linux/bcma/bcma.h>
-+#include <linux/mtd/mtd.h>
- #include <bcm47xx.h>
-
- struct bcm47xx_sflash {
-@@ -29,6 +30,8 @@ struct bcm47xx_sflash {
- u32 blocksize; /* Block size */
- u32 numblocks; /* Number of blocks */
- u32 size; /* Total size in bytes */
-+
-+ struct mtd_info *mtd;
- };
-
- void bcm47xx_sflash_struct_bcma_init(struct bcm47xx_sflash *sflash, struct bcma_drv_cc *bcc);
---- a/drivers/mtd/maps/Kconfig
-+++ b/drivers/mtd/maps/Kconfig
-@@ -266,6 +266,15 @@ config MTD_BCM47XX_PFLASH
- help
- Support for bcm47xx parallel flash
-
-+config MTD_BCM47XX_SFLASH
-+ tristate "bcm47xx serial flash support"
-+ default y
-+ depends on BCM47XX
-+ select MTD_PARTITIONS
-+ select MTD_BCM47XX_PARTS
-+ help
-+ Support for bcm47xx parallel flash
-+
- config MTD_DILNETPC
- tristate "CFI Flash device mapped on DIL/Net PC"
- depends on X86 && MTD_CFI_INTELEXT && BROKEN
---- a/drivers/mtd/maps/Makefile
-+++ b/drivers/mtd/maps/Makefile
-@@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-f
- obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
- obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
- obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o
-+obj-$(CONFIG_MTD_BCM47XX_SFLASH)+= bcm47xx-sflash.o
---- /dev/null
-+++ b/drivers/mtd/maps/bcm47xx-sflash.c
-@@ -0,0 +1,252 @@
-+/*
-+ * Broadcom SiliconBackplane chipcommon serial flash interface
-+ *
-+ * Copyright 2006, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id$
-+ */
-+
-+#define pr_fmt(fmt) "bcm47xx_sflash: " fmt
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/sched.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/errno.h>
-+#include <linux/delay.h>
-+#include <linux/platform_device.h>
-+#include <bcm47xx.h>
-+#include <bus.h>
-+
-+static int
-+sflash_mtd_poll(struct bcm47xx_sflash *sflash, unsigned int offset, int timeout)
-+{
-+ unsigned long now = jiffies;
-+ int ret = 0;
-+
-+ for (;;) {
-+ if (!sflash->poll(sflash, offset)) {
-+ ret = 0;
-+ break;
-+ }
-+ if (time_after(jiffies, now + timeout)) {
-+ pr_err("timeout while polling\n");
-+ ret = -ETIMEDOUT;
-+ break;
-+ }
-+ udelay(1);
-+ }
-+
-+ return ret;
-+}
-+
-+static int
-+sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-+{
-+ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *) mtd->priv;
-+
-+ /* Check address range */
-+ if (!len)
-+ return 0;
-+
-+ if ((from + len) > mtd->size)
-+ return -EINVAL;
-+
-+ *retlen = 0;
-+
-+ while (len) {
-+ int ret = sflash->read(sflash, from, len, buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ from += (loff_t) ret;
-+ len -= ret;
-+ buf += ret;
-+ *retlen += ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-+{
-+ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *) mtd->priv;
-+
-+ /* Check address range */
-+ if (!len)
-+ return 0;
-+
-+ if ((to + len) > mtd->size)
-+ return -EINVAL;
-+
-+ *retlen = 0;
-+ while (len) {
-+ int bytes;
-+ int ret = sflash->write(sflash, to, len, buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ bytes = ret;
-+
-+ ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10);
-+ if (ret)
-+ return ret;
-+
-+ to += (loff_t) bytes;
-+ len -= bytes;
-+ buf += bytes;
-+ *retlen += bytes;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
-+{
-+ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *) mtd->priv;
-+ int i, j, ret = 0;
-+ unsigned int addr, len;
-+
-+ /* Check address range */
-+ if (!erase->len)
-+ return 0;
-+ if ((erase->addr + erase->len) > mtd->size)
-+ return -EINVAL;
-+
-+ addr = erase->addr;
-+ len = erase->len;
-+
-+ /* Ensure that requested regions are aligned */
-+ for (i = 0; i < mtd->numeraseregions; i++) {
-+ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
-+ if (addr == mtd->eraseregions[i].offset +
-+ mtd->eraseregions[i].erasesize * j &&
-+ len >= mtd->eraseregions[i].erasesize) {
-+ ret = sflash->erase(sflash, addr);
-+ if (ret < 0)
-+ break;
-+ ret = sflash_mtd_poll(sflash, addr, 10 * HZ);
-+ if (ret)
-+ break;
-+ addr += mtd->eraseregions[i].erasesize;
-+ len -= mtd->eraseregions[i].erasesize;
-+ }
-+ }
-+ if (ret)
-+ break;
-+ }
-+
-+ /* Set erase status */
-+ if (ret)
-+ erase->state = MTD_ERASE_FAILED;
-+ else
-+ erase->state = MTD_ERASE_DONE;
-+
-+ /* Call erase callback */
-+ if (erase->callback)
-+ erase->callback(erase);
-+
-+ return ret;
-+}
-+
-+static const char *probes[] = { "bcm47xx", NULL };
-+
-+static int bcm47xx_sflash_probe(struct platform_device *pdev)
-+{
-+ struct bcm47xx_sflash *sflash = dev_get_platdata(&pdev->dev);
-+ struct mtd_info *mtd;
-+ struct mtd_erase_region_info *regions;
-+ int ret = 0;
-+
-+ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
-+ if (!mtd)
-+ return -ENOMEM;
-+
-+ regions = kzalloc(sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-+ if (!mtd)
-+ return -ENOMEM;
-+
-+ pr_info("found serial flash: blocksize=%dKB, numblocks=%d, size=%dKB\n",
-+ sflash->blocksize/1024, sflash->numblocks, sflash->size / 1024);
-+
-+ /* Setup region info */
-+ regions->offset = 0;
-+ regions->erasesize = sflash->blocksize;
-+ regions->numblocks = sflash->numblocks;
-+ if (regions->erasesize > mtd->erasesize)
-+ mtd->erasesize = regions->erasesize;
-+ mtd->size = sflash->size;
-+ mtd->numeraseregions = 1;
-+
-+ /* Register with MTD */
-+ mtd->name = "bcm47xx-sflash";
-+ mtd->type = MTD_NORFLASH;
-+ mtd->flags = MTD_CAP_NORFLASH;
-+ mtd->eraseregions = regions;
-+ mtd->erase = sflash_mtd_erase;
-+ mtd->read = sflash_mtd_read;
-+ mtd->write = sflash_mtd_write;
-+ mtd->writesize = 1;
-+ mtd->priv = sflash;
-+ mtd->owner = THIS_MODULE;
-+
-+ ret = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
-+
-+ if (ret) {
-+ pr_err("mtd_device_register failed\n");
-+ return ret;
-+ }
-+ sflash->mtd = mtd;
-+ return 0;
-+}
-+
-+static int __devexit bcm47xx_sflash_remove(struct platform_device *pdev)
-+{
-+ struct bcm47xx_sflash *sflash = dev_get_platdata(&pdev->dev);
-+
-+ if (sflash) {
-+ mtd_device_unregister(sflash->mtd);
-+ map_destroy(sflash->mtd);
-+ kfree(sflash->mtd->eraseregions);
-+ kfree(sflash->mtd);
-+ }
-+ return 0;
-+}
-+
-+static struct platform_driver bcm47xx_sflash_driver = {
-+ .remove = __devexit_p(bcm47xx_sflash_remove),
-+ .driver = {
-+ .name = "bcm47xx_sflash",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init init_bcm47xx_sflash(void)
-+{
-+ int ret = platform_driver_probe(&bcm47xx_sflash_driver, bcm47xx_sflash_probe);
-+
-+ if (ret)
-+ pr_err("error registering platform driver: %i\n", ret);
-+ return ret;
-+}
-+
-+static void __exit exit_bcm47xx_sflash(void)
-+{
-+ platform_driver_unregister(&bcm47xx_sflash_driver);
-+}
-+
-+module_init(init_bcm47xx_sflash);
-+module_exit(exit_bcm47xx_sflash);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("BCM47XX parallel flash driver");
+++ /dev/null
-From 64f3d068654589d6114048ac5933cd4498706cfc Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 17 Jul 2011 15:02:10 +0200
-Subject: [PATCH 20/26] bcm47xx: register flash drivers
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/bcm47xx/setup.c | 72 +++++++++++++++++++++++++++++++++++++++++++++
- 1 files changed, 72 insertions(+), 0 deletions(-)
-
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -31,10 +31,12 @@
- #include <linux/ssb/ssb.h>
- #include <linux/ssb/ssb_embedded.h>
- #include <linux/bcma/bcma_soc.h>
-+#include <linux/platform_device.h>
- #include <asm/bootinfo.h>
- #include <asm/reboot.h>
- #include <asm/time.h>
- #include <bcm47xx.h>
-+#include <bus.h>
- #include <asm/mach-bcm47xx/nvram.h>
-
- union bcm47xx_bus bcm47xx_bus;
-@@ -366,3 +368,73 @@ static int __init bcm47xx_register_bus_c
- return 0;
- }
- device_initcall(bcm47xx_register_bus_complete);
-+
-+static struct resource bcm47xx_pflash_resource = {
-+ .name = "bcm47xx_pflash",
-+ .start = 0,
-+ .end = 0,
-+ .flags = 0,
-+};
-+
-+static struct platform_device bcm47xx_pflash_dev = {
-+ .name = "bcm47xx_pflash",
-+ .resource = &bcm47xx_pflash_resource,
-+ .num_resources = 1,
-+};
-+
-+static struct resource bcm47xx_sflash_resource = {
-+ .name = "bcm47xx_sflash",
-+ .start = 0,
-+ .end = 0,
-+ .flags = 0,
-+};
-+
-+static struct platform_device bcm47xx_sflash_dev = {
-+ .name = "bcm47xx_sflash",
-+ .resource = &bcm47xx_sflash_resource,
-+ .num_resources = 1,
-+};
-+
-+static int __init bcm47xx_register_flash(void)
-+{
-+#ifdef CONFIG_BCM47XX_SSB
-+ struct ssb_chipcommon *chipco;
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ struct bcma_drv_cc *drv_cc;
-+#endif
-+ switch (bcm47xx_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
-+ case BCM47XX_BUS_TYPE_SSB:
-+ chipco = &bcm47xx_bus.ssb.chipco;
-+ if (chipco->flash_type == SSB_PFLASH) {
-+ bcm47xx_pflash_resource.start = chipco->pflash.window;
-+ bcm47xx_pflash_resource.end = chipco->pflash.window + chipco->pflash.window_size;
-+ return platform_device_register(&bcm47xx_pflash_dev);
-+ } else if (chipco->flash_type == SSB_SFLASH) {
-+ bcm47xx_sflash_dev.dev.platform_data = &bcm47xx_sflash;
-+ return platform_device_register(&bcm47xx_sflash_dev);
-+ } else {
-+ printk(KERN_ERR "No flash device found\n");
-+ return -1;
-+ }
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ drv_cc = &bcm47xx_bus.bcma.bus.drv_cc;
-+ if (drv_cc->flash_type == BCMA_PFLASH) {
-+ bcm47xx_pflash_resource.start = drv_cc->pflash.window;
-+ bcm47xx_pflash_resource.end = drv_cc->pflash.window + drv_cc->pflash.window_size;
-+ return platform_device_register(&bcm47xx_pflash_dev);
-+ } else if (drv_cc->flash_type == BCMA_SFLASH) {
-+ bcm47xx_sflash_dev.dev.platform_data = &bcm47xx_sflash;
-+ return platform_device_register(&bcm47xx_sflash_dev);
-+ } else {
-+ printk(KERN_ERR "No flash device found\n");
-+ return -1;
-+ }
-+#endif
-+ }
-+ return -1;
-+}
-+fs_initcall(bcm47xx_register_flash);
+++ /dev/null
-From 1d693b2c9d5943cbe938f879041b837cd004737f Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 23 Jul 2011 18:29:38 +0200
-Subject: [PATCH 25/26] bcm47xx: read nvram from sflash
-
-bcm47xx: add sflash support to nvram
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/bcm47xx/nvram.c | 86 +++++++++++++++++++++++++++++++++++++++++++-
- 1 files changed, 84 insertions(+), 2 deletions(-)
-
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -20,11 +20,12 @@
- #include <asm/addrspace.h>
- #include <asm/mach-bcm47xx/nvram.h>
- #include <asm/mach-bcm47xx/bcm47xx.h>
-+#include <asm/mach-bcm47xx/bus.h>
-
- static char nvram_buf[NVRAM_SPACE];
-
- /* Probe for NVRAM header */
--static void early_nvram_init(void)
-+static void early_nvram_init_pflash(void)
- {
- #ifdef CONFIG_BCM47XX_SSB
- struct ssb_chipcommon *ssb_cc;
-@@ -86,7 +87,88 @@ found:
- for (i = 0; i < sizeof(struct nvram_header); i += 4)
- *dst++ = *src++;
- for (; i < header->len && i < NVRAM_SPACE; i += 4)
-- *dst++ = le32_to_cpu(*src++);
-+ *dst++ = *src++;
-+}
-+
-+static int early_nvram_init_sflash(void)
-+{
-+ struct nvram_header header;
-+ u32 off;
-+ int ret;
-+ char *dst;
-+ int len;
-+
-+ /* check if the struct is already initilized */
-+ if (!bcm47xx_sflash.size)
-+ return -1;
-+
-+ off = FLASH_MIN;
-+ while (off <= bcm47xx_sflash.size) {
-+ ret = bcm47xx_sflash.read(&bcm47xx_sflash, off - NVRAM_SPACE, sizeof(header), (u8 *)&header);
-+ if (ret != sizeof(header))
-+ return ret;
-+ if (header.magic == NVRAM_HEADER)
-+ goto found;
-+ off <<= 1;
-+ }
-+
-+ off = FLASH_MIN;
-+ while (off <= bcm47xx_sflash.size) {
-+ ret = bcm47xx_sflash.read(&bcm47xx_sflash, off - (2 * NVRAM_SPACE), sizeof(header), (u8 *)&header);
-+ if (ret != sizeof(header))
-+ return ret;
-+ if (header.magic == NVRAM_HEADER)
-+ goto found;
-+ off <<= 1;
-+ }
-+ return -1;
-+
-+found:
-+ len = NVRAM_SPACE;
-+ dst = nvram_buf;
-+ while (len) {
-+ ret = bcm47xx_sflash.read(&bcm47xx_sflash, off - (2 * NVRAM_SPACE), len, dst);
-+ if (ret < 0)
-+ return ret;
-+ off += ret;
-+ len -= ret;
-+ dst += ret;
-+ }
-+ return 0;
-+}
-+
-+static void early_nvram_init(void)
-+{
-+ int err = 0;
-+
-+ switch (bcm47xx_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
-+ case BCM47XX_BUS_TYPE_SSB:
-+ if (bcm47xx_bus.ssb.chipco.flash_type == SSB_PFLASH) {
-+ early_nvram_init_pflash();
-+ } else if (bcm47xx_bus.ssb.chipco.flash_type == SSB_SFLASH) {
-+ err = early_nvram_init_sflash();
-+ if (err < 0)
-+ printk(KERN_WARNING "can not read from flash: %i\n", err);
-+ } else {
-+ printk(KERN_WARNING "unknow flash type\n");
-+ }
-+ break;
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_PFLASH) {
-+ early_nvram_init_pflash();
-+ } else if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_SFLASH) {
-+ err = early_nvram_init_sflash();
-+ if (err < 0)
-+ printk(KERN_WARNING "can not read from flash: %i\n", err);
-+ } else {
-+ printk(KERN_WARNING "unknow flash type\n");
-+ }
-+ break;
-+#endif
-+ }
- }
-
- int nvram_getenv(char *name, char *val, size_t val_len)
+++ /dev/null
-From f6e41db3ee7ead99e1398def222c14893fc265de Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Thu, 4 Aug 2011 21:09:48 +0200
-Subject: [PATCH 26/26] bcma: export needed gpio functions
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/driver_chipcommon.c | 5 +++++
- 1 files changed, 5 insertions(+), 0 deletions(-)
-
---- a/drivers/bcma/driver_chipcommon.c
-+++ b/drivers/bcma/driver_chipcommon.c
-@@ -81,16 +81,19 @@ u32 bcma_chipco_gpio_in(struct bcma_drv_
- {
- return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask;
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_in);
-
- u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
- {
- return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_out);
-
- u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
- {
- return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen);
-
- u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
- {
-@@ -102,11 +105,13 @@ u32 bcma_chipco_gpio_intmask(struct bcma
- {
- return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_intmask);
-
- u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
- {
- return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_polarity);
-
- #ifdef CONFIG_BCMA_DRIVER_MIPS
- void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+++ /dev/null
-From 7b9116eeaf44c0d368b5eeaa06eb101465284596 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Wed, 11 Jan 2012 15:26:11 +0100
-Subject: [PATCH 23/31] bcma: add the core unit number
-
-Some SoCs have two pcie or gmac cores and we need to know the number of
-the specific core on the bus. This is the case for the BCM4706.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/scan.c | 14 ++++++++++++++
- include/linux/bcma/bcma.h | 1 +
- 2 files changed, 15 insertions(+), 0 deletions(-)
-
---- a/drivers/bcma/scan.c
-+++ b/drivers/bcma/scan.c
-@@ -212,6 +212,17 @@ static struct bcma_device *bcma_find_cor
- return NULL;
- }
-
-+static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 coreid)
-+{
-+ struct bcma_device *core;
-+
-+ list_for_each_entry_reverse(core, &bus->cores, list) {
-+ if (core->id.id == coreid)
-+ 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)
-@@ -392,6 +403,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
- bcma_scan_switch_core(bus, erombase);
-
- while (eromptr < eromend) {
-+ struct bcma_device *other_core;
- struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
- if (!core)
- return -ENOMEM;
-@@ -411,6 +423,8 @@ int bcma_bus_scan(struct bcma_bus *bus)
-
- core->core_index = core_num++;
- bus->nr_cores++;
-+ other_core = bcma_find_core_reverse(bus, core->id.id);
-+ core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
-
- pr_info("Core %d found: %s "
- "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
---- a/include/linux/bcma/bcma.h
-+++ b/include/linux/bcma/bcma.h
-@@ -136,6 +136,7 @@ struct bcma_device {
- bool dev_registered;
-
- u8 core_index;
-+ u8 core_unit;
-
- u32 addr;
- u32 wrap;
+++ /dev/null
-From 300efafa8e1381a208c723bb9d03d46bf29f1ec0 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 14 Jan 2012 20:02:15 +0100
-Subject: [PATCH 24/31] bcma: constants for PCI and use them
-
-There are loots of magic numbers used in the PCIe code. These constants
-are from the Broadcom SDK and will also used in the host controller.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/driver_pci.c | 124 +++++++++++++++++++---------------
- include/linux/bcma/bcma_driver_pci.h | 85 +++++++++++++++++++++++
- 2 files changed, 155 insertions(+), 54 deletions(-)
-
---- a/drivers/bcma/driver_pci.c
-+++ b/drivers/bcma/driver_pci.c
-@@ -4,6 +4,7 @@
- *
- * Copyright 2005, Broadcom Corporation
- * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
-+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
- *
- * Licensed under the GNU/GPL. See COPYING for details.
- */
-@@ -18,38 +19,39 @@
-
- static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
- {
-- pcicore_write32(pc, 0x130, address);
-- pcicore_read32(pc, 0x130);
-- return pcicore_read32(pc, 0x134);
-+ pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
-+ pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
-+ return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA);
- }
-
- #if 0
- static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
- {
-- pcicore_write32(pc, 0x130, address);
-- pcicore_read32(pc, 0x130);
-- pcicore_write32(pc, 0x134, data);
-+ pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
-+ pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
-+ pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data);
- }
- #endif
-
- static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
- {
-- const u16 mdio_control = 0x128;
-- const u16 mdio_data = 0x12C;
- u32 v;
- int i;
-
-- v = (1 << 30); /* Start of Transaction */
-- v |= (1 << 28); /* Write Transaction */
-- v |= (1 << 17); /* Turnaround */
-- v |= (0x1F << 18);
-+ v = BCMA_CORE_PCI_MDIODATA_START;
-+ v |= BCMA_CORE_PCI_MDIODATA_WRITE;
-+ v |= (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
-+ BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
-+ v |= (BCMA_CORE_PCI_MDIODATA_BLK_ADDR <<
-+ BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
-+ v |= BCMA_CORE_PCI_MDIODATA_TA;
- v |= (phy << 4);
-- pcicore_write32(pc, mdio_data, v);
-+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
-
- udelay(10);
- for (i = 0; i < 200; i++) {
-- v = pcicore_read32(pc, mdio_control);
-- if (v & 0x100 /* Trans complete */)
-+ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
-+ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
- break;
- msleep(1);
- }
-@@ -57,79 +59,84 @@ static void bcma_pcie_mdio_set_phy(struc
-
- static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
- {
-- const u16 mdio_control = 0x128;
-- const u16 mdio_data = 0x12C;
- int max_retries = 10;
- u16 ret = 0;
- u32 v;
- int i;
-
-- v = 0x80; /* Enable Preamble Sequence */
-- v |= 0x2; /* MDIO Clock Divisor */
-- pcicore_write32(pc, mdio_control, v);
-+ /* enable mdio access to SERDES */
-+ v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
-+ v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
-+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
-
- if (pc->core->id.rev >= 10) {
- max_retries = 200;
- bcma_pcie_mdio_set_phy(pc, device);
-+ v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
-+ BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
-+ v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
-+ } else {
-+ v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
-+ v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
- }
-
-- v = (1 << 30); /* Start of Transaction */
-- v |= (1 << 29); /* Read Transaction */
-- v |= (1 << 17); /* Turnaround */
-- if (pc->core->id.rev < 10)
-- v |= (u32)device << 22;
-- v |= (u32)address << 18;
-- pcicore_write32(pc, mdio_data, v);
-+ v = BCMA_CORE_PCI_MDIODATA_START;
-+ v |= BCMA_CORE_PCI_MDIODATA_READ;
-+ v |= BCMA_CORE_PCI_MDIODATA_TA;
-+
-+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
- /* Wait for the device to complete the transaction */
- udelay(10);
- for (i = 0; i < max_retries; i++) {
-- v = pcicore_read32(pc, mdio_control);
-- if (v & 0x100 /* Trans complete */) {
-+ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
-+ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE) {
- udelay(10);
-- ret = pcicore_read32(pc, mdio_data);
-+ ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA);
- break;
- }
- msleep(1);
- }
-- pcicore_write32(pc, mdio_control, 0);
-+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
- return ret;
- }
-
- static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
- u8 address, u16 data)
- {
-- const u16 mdio_control = 0x128;
-- const u16 mdio_data = 0x12C;
- int max_retries = 10;
- u32 v;
- int i;
-
-- v = 0x80; /* Enable Preamble Sequence */
-- v |= 0x2; /* MDIO Clock Divisor */
-- pcicore_write32(pc, mdio_control, v);
-+ /* enable mdio access to SERDES */
-+ v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
-+ v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
-+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
-
- if (pc->core->id.rev >= 10) {
- max_retries = 200;
- bcma_pcie_mdio_set_phy(pc, device);
-+ v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
-+ BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
-+ v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
-+ } else {
-+ v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
-+ v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
- }
-
-- v = (1 << 30); /* Start of Transaction */
-- v |= (1 << 28); /* Write Transaction */
-- v |= (1 << 17); /* Turnaround */
-- if (pc->core->id.rev < 10)
-- v |= (u32)device << 22;
-- v |= (u32)address << 18;
-+ v = BCMA_CORE_PCI_MDIODATA_START;
-+ v |= BCMA_CORE_PCI_MDIODATA_WRITE;
-+ v |= BCMA_CORE_PCI_MDIODATA_TA;
- v |= data;
-- pcicore_write32(pc, mdio_data, v);
-+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
- /* Wait for the device to complete the transaction */
- udelay(10);
- for (i = 0; i < max_retries; i++) {
-- v = pcicore_read32(pc, mdio_control);
-- if (v & 0x100 /* Trans complete */)
-+ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
-+ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
- break;
- msleep(1);
- }
-- pcicore_write32(pc, mdio_control, 0);
-+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
- }
-
- /**************************************************
-@@ -138,20 +145,29 @@ static void bcma_pcie_mdio_write(struct
-
- static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc)
- {
-- return (bcma_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
-+ u32 tmp;
-+
-+ tmp = bcma_pcie_read(pc, BCMA_CORE_PCI_PLP_STATUSREG);
-+ if (tmp & BCMA_CORE_PCI_PLP_POLARITYINV_STAT)
-+ return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE |
-+ BCMA_CORE_PCI_SERDES_RX_CTRL_POLARITY;
-+ else
-+ return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE;
- }
-
- static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
- {
-- const u8 serdes_pll_device = 0x1D;
-- const u8 serdes_rx_device = 0x1F;
- u16 tmp;
-
-- bcma_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
-- bcma_pcicore_polarity_workaround(pc));
-- tmp = bcma_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
-- if (tmp & 0x4000)
-- bcma_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
-+ bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_RX,
-+ BCMA_CORE_PCI_SERDES_RX_CTRL,
-+ bcma_pcicore_polarity_workaround(pc));
-+ tmp = bcma_pcie_mdio_read(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
-+ BCMA_CORE_PCI_SERDES_PLL_CTRL);
-+ if (tmp & BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN)
-+ bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
-+ BCMA_CORE_PCI_SERDES_PLL_CTRL,
-+ tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
- }
-
- /**************************************************
---- a/include/linux/bcma/bcma_driver_pci.h
-+++ b/include/linux/bcma/bcma_driver_pci.h
-@@ -53,6 +53,35 @@ struct pci_dev;
- #define BCMA_CORE_PCI_SBTOPCI1_MASK 0xFC000000
- #define BCMA_CORE_PCI_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */
- #define BCMA_CORE_PCI_SBTOPCI2_MASK 0xC0000000
-+#define BCMA_CORE_PCI_CONFIG_ADDR 0x0120 /* pcie config space access */
-+#define BCMA_CORE_PCI_CONFIG_DATA 0x0124 /* pcie config space access */
-+#define BCMA_CORE_PCI_MDIO_CONTROL 0x0128 /* controls the mdio access */
-+#define BCMA_CORE_PCI_MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */
-+#define BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL 0x2
-+#define BCMA_CORE_PCI_MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */
-+#define BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE 0x100 /* Tranaction complete */
-+#define BCMA_CORE_PCI_MDIO_DATA 0x012c /* Data to the mdio access */
-+#define BCMA_CORE_PCI_MDIODATA_MASK 0x0000ffff /* data 2 bytes */
-+#define BCMA_CORE_PCI_MDIODATA_TA 0x00020000 /* Turnaround */
-+#define BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift (rev < 10) */
-+#define BCMA_CORE_PCI_MDIODATA_REGADDR_MASK_OLD 0x003c0000 /* Regaddr Mask (rev < 10) */
-+#define BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift (rev < 10) */
-+#define BCMA_CORE_PCI_MDIODATA_DEVADDR_MASK_OLD 0x0fc00000 /* Physmedia devaddr Mask (rev < 10) */
-+#define BCMA_CORE_PCI_MDIODATA_REGADDR_SHF 18 /* Regaddr shift */
-+#define BCMA_CORE_PCI_MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */
-+#define BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */
-+#define BCMA_CORE_PCI_MDIODATA_DEVADDR_MASK 0x0f800000 /* Physmedia devaddr Mask */
-+#define BCMA_CORE_PCI_MDIODATA_WRITE 0x10000000 /* write Transaction */
-+#define BCMA_CORE_PCI_MDIODATA_READ 0x20000000 /* Read Transaction */
-+#define BCMA_CORE_PCI_MDIODATA_START 0x40000000 /* start of Transaction */
-+#define BCMA_CORE_PCI_MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */
-+#define BCMA_CORE_PCI_MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */
-+#define BCMA_CORE_PCI_MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */
-+#define BCMA_CORE_PCI_MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */
-+#define BCMA_CORE_PCI_MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */
-+#define BCMA_CORE_PCI_PCIEIND_ADDR 0x0130 /* indirect access to the internal register */
-+#define BCMA_CORE_PCI_PCIEIND_DATA 0x0134 /* Data to/from the internal regsiter */
-+#define BCMA_CORE_PCI_CLKREQENCTRL 0x0138 /* >= rev 6, Clkreq rdma control */
- #define BCMA_CORE_PCI_PCICFG0 0x0400 /* PCI config space 0 (rev >= 8) */
- #define BCMA_CORE_PCI_PCICFG1 0x0500 /* PCI config space 1 (rev >= 8) */
- #define BCMA_CORE_PCI_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */
-@@ -72,6 +101,62 @@ struct pci_dev;
- #define BCMA_CORE_PCI_SBTOPCI_RC_READL 0x00000010 /* Memory read line */
- #define BCMA_CORE_PCI_SBTOPCI_RC_READM 0x00000020 /* Memory read multiple */
-
-+/* PCIE protocol PHY diagnostic registers */
-+#define BCMA_CORE_PCI_PLP_MODEREG 0x200 /* Mode */
-+#define BCMA_CORE_PCI_PLP_STATUSREG 0x204 /* Status */
-+#define BCMA_CORE_PCI_PLP_POLARITYINV_STAT 0x10 /* Status reg PCIE_PLP_STATUSREG */
-+#define BCMA_CORE_PCI_PLP_LTSSMCTRLREG 0x208 /* LTSSM control */
-+#define BCMA_CORE_PCI_PLP_LTLINKNUMREG 0x20c /* Link Training Link number */
-+#define BCMA_CORE_PCI_PLP_LTLANENUMREG 0x210 /* Link Training Lane number */
-+#define BCMA_CORE_PCI_PLP_LTNFTSREG 0x214 /* Link Training N_FTS */
-+#define BCMA_CORE_PCI_PLP_ATTNREG 0x218 /* Attention */
-+#define BCMA_CORE_PCI_PLP_ATTNMASKREG 0x21C /* Attention Mask */
-+#define BCMA_CORE_PCI_PLP_RXERRCTR 0x220 /* Rx Error */
-+#define BCMA_CORE_PCI_PLP_RXFRMERRCTR 0x224 /* Rx Framing Error */
-+#define BCMA_CORE_PCI_PLP_RXERRTHRESHREG 0x228 /* Rx Error threshold */
-+#define BCMA_CORE_PCI_PLP_TESTCTRLREG 0x22C /* Test Control reg */
-+#define BCMA_CORE_PCI_PLP_SERDESCTRLOVRDREG 0x230 /* SERDES Control Override */
-+#define BCMA_CORE_PCI_PLP_TIMINGOVRDREG 0x234 /* Timing param override */
-+#define BCMA_CORE_PCI_PLP_RXTXSMDIAGREG 0x238 /* RXTX State Machine Diag */
-+#define BCMA_CORE_PCI_PLP_LTSSMDIAGREG 0x23C /* LTSSM State Machine Diag */
-+
-+/* PCIE protocol DLLP diagnostic registers */
-+#define BCMA_CORE_PCI_DLLP_LCREG 0x100 /* Link Control */
-+#define BCMA_CORE_PCI_DLLP_LSREG 0x104 /* Link Status */
-+#define BCMA_CORE_PCI_DLLP_LAREG 0x108 /* Link Attention */
-+#define BCMA_CORE_PCI_DLLP_LSREG_LINKUP (1 << 16)
-+#define BCMA_CORE_PCI_DLLP_LAMASKREG 0x10C /* Link Attention Mask */
-+#define BCMA_CORE_PCI_DLLP_NEXTTXSEQNUMREG 0x110 /* Next Tx Seq Num */
-+#define BCMA_CORE_PCI_DLLP_ACKEDTXSEQNUMREG 0x114 /* Acked Tx Seq Num */
-+#define BCMA_CORE_PCI_DLLP_PURGEDTXSEQNUMREG 0x118 /* Purged Tx Seq Num */
-+#define BCMA_CORE_PCI_DLLP_RXSEQNUMREG 0x11C /* Rx Sequence Number */
-+#define BCMA_CORE_PCI_DLLP_LRREG 0x120 /* Link Replay */
-+#define BCMA_CORE_PCI_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */
-+#define BCMA_CORE_PCI_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
-+#define BCMA_CORE_PCI_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */
-+#define BCMA_CORE_PCI_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */
-+#define BCMA_CORE_PCI_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */
-+#define BCMA_CORE_PCI_DLLP_RTRRWREG 0x138 /* Retry buffer Read/Write */
-+#define BCMA_CORE_PCI_DLLP_ECTHRESHREG 0x13C /* Error Count Threshold */
-+#define BCMA_CORE_PCI_DLLP_TLPERRCTRREG 0x140 /* TLP Error Counter */
-+#define BCMA_CORE_PCI_DLLP_ERRCTRREG 0x144 /* Error Counter */
-+#define BCMA_CORE_PCI_DLLP_NAKRXCTRREG 0x148 /* NAK Received Counter */
-+#define BCMA_CORE_PCI_DLLP_TESTREG 0x14C /* Test */
-+#define BCMA_CORE_PCI_DLLP_PKTBIST 0x150 /* Packet BIST */
-+#define BCMA_CORE_PCI_DLLP_PCIE11 0x154 /* DLLP PCIE 1.1 reg */
-+
-+/* SERDES RX registers */
-+#define BCMA_CORE_PCI_SERDES_RX_CTRL 1 /* Rx cntrl */
-+#define BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */
-+#define BCMA_CORE_PCI_SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */
-+#define BCMA_CORE_PCI_SERDES_RX_TIMER1 2 /* Rx Timer1 */
-+#define BCMA_CORE_PCI_SERDES_RX_CDR 6 /* CDR */
-+#define BCMA_CORE_PCI_SERDES_RX_CDRBW 7 /* CDR BW */
-+
-+/* SERDES PLL registers */
-+#define BCMA_CORE_PCI_SERDES_PLL_CTRL 1 /* PLL control reg */
-+#define BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */
-+
- /* PCIcore specific boardflags */
- #define BCMA_CORE_PCI_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
-
+++ /dev/null
-From 01d8709c311858c37e02c96464ea4dc954334210 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 14 Jan 2012 20:03:09 +0100
-Subject: [PATCH 25/31] bcma: export bcma_pcie_read()
-
-This will be needed by the host controller.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/bcma_private.h | 2 ++
- drivers/bcma/driver_pci.c | 2 +-
- 2 files changed, 3 insertions(+), 1 deletions(-)
-
---- a/drivers/bcma/bcma_private.h
-+++ b/drivers/bcma/bcma_private.h
-@@ -46,6 +46,8 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
- int bcma_sflash_init(struct bcma_drv_cc *cc);
- #endif /* CONFIG_BCMA_SFLASH */
-
-+u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
-+
- #ifdef CONFIG_BCMA_HOST_PCI
- /* host_pci.c */
- extern int __init bcma_host_pci_init(void);
---- a/drivers/bcma/driver_pci.c
-+++ b/drivers/bcma/driver_pci.c
-@@ -17,7 +17,7 @@
- * R/W ops.
- **************************************************/
-
--static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
-+u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
- {
- pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
- pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
+++ /dev/null
-From 3cd3138f2ef77e18abc99737c6740f35d61dbbb3 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 15 Jan 2012 23:05:05 +0100
-Subject: [PATCH 26/32] bcma: make some functions __devinit
-
-bcma_core_pci_hostmode_init() has to be in __devinit as it will call a
-function in that section and so all functions calling it also have to
-be in __devinit.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/bcma_private.h | 4 ++--
- drivers/bcma/driver_pci.c | 6 +++---
- drivers/bcma/driver_pci_host.c | 2 +-
- drivers/bcma/host_pci.c | 4 ++--
- drivers/bcma/main.c | 2 +-
- include/linux/bcma/bcma_driver_pci.h | 2 +-
- 6 files changed, 10 insertions(+), 10 deletions(-)
-
---- a/drivers/bcma/bcma_private.h
-+++ b/drivers/bcma/bcma_private.h
-@@ -13,7 +13,7 @@
- struct bcma_bus;
-
- /* main.c */
--int bcma_bus_register(struct bcma_bus *bus);
-+int __devinit 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,
-@@ -55,7 +55,7 @@ extern void __exit bcma_host_pci_exit(vo
- #endif /* CONFIG_BCMA_HOST_PCI */
-
- #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
--void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
-+void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
- #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
-
- #endif
---- a/drivers/bcma/driver_pci.c
-+++ b/drivers/bcma/driver_pci.c
-@@ -174,12 +174,12 @@ static void bcma_pcicore_serdes_workarou
- * Init.
- **************************************************/
-
--static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
-+static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
- {
- bcma_pcicore_serdes_workaround(pc);
- }
-
--static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
-+static bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
- {
- struct bcma_bus *bus = pc->core->bus;
- u16 chipid_top;
-@@ -204,7 +204,7 @@ static bool bcma_core_pci_is_in_hostmode
- return true;
- }
-
--void bcma_core_pci_init(struct bcma_drv_pci *pc)
-+void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc)
- {
- if (pc->setup_done)
- return;
---- a/drivers/bcma/driver_pci_host.c
-+++ b/drivers/bcma/driver_pci_host.c
-@@ -8,7 +8,7 @@
- #include "bcma_private.h"
- #include <linux/bcma/bcma.h>
-
--void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
-+void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
- {
- pr_err("No support for PCI core in hostmode yet\n");
- }
---- a/drivers/bcma/host_pci.c
-+++ b/drivers/bcma/host_pci.c
-@@ -154,8 +154,8 @@ const struct bcma_host_ops bcma_host_pci
- .awrite32 = bcma_host_pci_awrite32,
- };
-
--static int bcma_host_pci_probe(struct pci_dev *dev,
-- const struct pci_device_id *id)
-+static int __devinit bcma_host_pci_probe(struct pci_dev *dev,
-+ const struct pci_device_id *id)
- {
- struct bcma_bus *bus;
- int err = -ENOMEM;
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -132,7 +132,7 @@ static void bcma_unregister_cores(struct
- }
- }
-
--int bcma_bus_register(struct bcma_bus *bus)
-+int __devinit bcma_bus_register(struct bcma_bus *bus)
- {
- int err;
- struct bcma_device *core;
---- a/include/linux/bcma/bcma_driver_pci.h
-+++ b/include/linux/bcma/bcma_driver_pci.h
-@@ -169,7 +169,7 @@ struct bcma_drv_pci {
- #define pcicore_read32(pc, offset) bcma_read32((pc)->core, offset)
- #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val)
-
--extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
-+extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc);
- extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
- struct bcma_device *core, bool enable);
-
+++ /dev/null
-From 47d0e8c2743729b4248585d33b55b6aaeac008d5 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 8 Jan 2012 16:53:15 +0100
-Subject: [PATCH 25/34] bcma: add PCIe host controller
-
-Some SoCs have a PCIe host controller to make it possible to attach
-some other devices to it, like an other Wifi card.
-This code was tested with an Netgear WNDR3400 (bcm4716 based), but
-should work with all bcma based SoCs.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/pci/pci-bcm47xx.c | 49 +++-
- drivers/bcma/bcma_private.h | 1 +
- drivers/bcma/driver_pci.c | 38 +--
- drivers/bcma/driver_pci_host.c | 576 +++++++++++++++++++++++++++++++++-
- include/linux/bcma/bcma_driver_pci.h | 34 ++
- include/linux/bcma/bcma_regs.h | 27 ++
- 6 files changed, 686 insertions(+), 39 deletions(-)
-
---- a/arch/mips/pci/pci-bcm47xx.c
-+++ b/arch/mips/pci/pci-bcm47xx.c
-@@ -25,6 +25,7 @@
- #include <linux/types.h>
- #include <linux/pci.h>
- #include <linux/ssb/ssb.h>
-+#include <linux/bcma/bcma.h>
- #include <bcm47xx.h>
-
- int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-@@ -32,15 +33,12 @@ int __init pcibios_map_irq(const struct
- return 0;
- }
-
--int pcibios_plat_dev_init(struct pci_dev *dev)
--{
- #ifdef CONFIG_BCM47XX_SSB
-+static int bcm47xx_pcibios_plat_dev_init_ssb(struct pci_dev *dev)
-+{
- int res;
- u8 slot, pin;
-
-- if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
-- return 0;
--
- res = ssb_pcibios_plat_dev_init(dev);
- if (res < 0) {
- printk(KERN_ALERT "PCI: Failed to init device %s\n",
-@@ -60,6 +58,47 @@ int pcibios_plat_dev_init(struct pci_dev
- }
-
- dev->irq = res;
-+ return 0;
-+}
- #endif
-+
-+#ifdef CONFIG_BCM47XX_BCMA
-+static int bcm47xx_pcibios_plat_dev_init_bcma(struct pci_dev *dev)
-+{
-+ int res;
-+
-+ res = bcma_core_pci_plat_dev_init(dev);
-+ if (res < 0) {
-+ printk(KERN_ALERT "PCI: Failed to init device %s\n",
-+ pci_name(dev));
-+ return res;
-+ }
-+
-+ res = bcma_core_pci_pcibios_map_irq(dev);
-+
-+ /* IRQ-0 and IRQ-1 are software interrupts. */
-+ if (res < 2) {
-+ printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n",
-+ pci_name(dev));
-+ return res;
-+ }
-+
-+ dev->irq = res;
- return 0;
- }
-+#endif
-+
-+int pcibios_plat_dev_init(struct pci_dev *dev)
-+{
-+#ifdef CONFIG_BCM47XX_SSB
-+ if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_SSB)
-+ return bcm47xx_pcibios_plat_dev_init_ssb(dev);
-+ else
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA)
-+ return bcm47xx_pcibios_plat_dev_init_bcma(dev);
-+ else
-+#endif
-+ return 0;
-+}
---- a/drivers/bcma/bcma_private.h
-+++ b/drivers/bcma/bcma_private.h
-@@ -55,6 +55,7 @@ extern void __exit bcma_host_pci_exit(vo
- #endif /* CONFIG_BCMA_HOST_PCI */
-
- #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
-+bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
- void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
- #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
-
---- a/drivers/bcma/driver_pci.c
-+++ b/drivers/bcma/driver_pci.c
-@@ -2,7 +2,7 @@
- * Broadcom specific AMBA
- * PCI Core
- *
-- * Copyright 2005, Broadcom Corporation
-+ * Copyright 2005, 2011, Broadcom Corporation
- * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
- * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
- *
-@@ -179,47 +179,19 @@ static void __devinit bcma_core_pci_clie
- bcma_pcicore_serdes_workaround(pc);
- }
-
--static bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
--{
-- struct bcma_bus *bus = pc->core->bus;
-- u16 chipid_top;
--
-- chipid_top = (bus->chipinfo.id & 0xFF00);
-- if (chipid_top != 0x4700 &&
-- chipid_top != 0x5300)
-- return false;
--
--#ifdef CONFIG_SSB_DRIVER_PCICORE
-- if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
-- return false;
--#endif /* CONFIG_SSB_DRIVER_PCICORE */
--
--#if 0
-- /* TODO: on BCMA we use address from EROM instead of magic formula */
-- u32 tmp;
-- return !mips_busprobe32(tmp, (bus->mmio +
-- (pc->core->core_index * BCMA_CORE_SIZE)));
--#endif
--
-- return true;
--}
--
- void __devinit 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
-+ pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
-+ if (pc->hostmode)
- bcma_core_pci_hostmode_init(pc);
--#else
-- pr_err("Driver compiled without support for hostmode PCI\n");
- #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
-- } else {
-- bcma_core_pci_clientmode_init(pc);
-- }
-
-- pc->setup_done = true;
-+ if (!pc->hostmode)
-+ bcma_core_pci_clientmode_init(pc);
- }
-
- int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
---- a/drivers/bcma/driver_pci_host.c
-+++ b/drivers/bcma/driver_pci_host.c
-@@ -2,13 +2,587 @@
- * Broadcom specific AMBA
- * PCI Core in hostmode
- *
-+ * Copyright 2005 - 2011, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
-+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
-+ *
- * Licensed under the GNU/GPL. See COPYING for details.
- */
-
- #include "bcma_private.h"
-+#include <linux/export.h>
- #include <linux/bcma/bcma.h>
-+#include <asm/paccess.h>
-+
-+/* Probe a 32bit value on the bus and catch bus exceptions.
-+ * Returns nonzero on a bus exception.
-+ * This is MIPS specific */
-+#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
-+
-+/* Assume one-hot slot wiring */
-+#define BCMA_PCI_SLOT_MAX 16
-+#define PCI_CONFIG_SPACE_SIZE 256
-+
-+bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
-+{
-+ struct bcma_bus *bus = pc->core->bus;
-+ u16 chipid_top;
-+ u32 tmp;
-+
-+ chipid_top = (bus->chipinfo.id & 0xFF00);
-+ if (chipid_top != 0x4700 &&
-+ chipid_top != 0x5300)
-+ return false;
-+
-+ if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
-+ pr_info("This PCI core is disabled and not working\n");
-+ return false;
-+ }
-+
-+ bcma_core_enable(pc->core, 0);
-+
-+ return !mips_busprobe32(tmp, pc->core->io_addr);
-+}
-+
-+static u32 bcma_pcie_read_config(struct bcma_drv_pci *pc, u32 address)
-+{
-+ pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
-+ pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
-+ return pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_DATA);
-+}
-+
-+static void bcma_pcie_write_config(struct bcma_drv_pci *pc, u32 address,
-+ u32 data)
-+{
-+ pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
-+ pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
-+ pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_DATA, data);
-+}
-+
-+static u32 bcma_get_cfgspace_addr(struct bcma_drv_pci *pc, unsigned int dev,
-+ unsigned int func, unsigned int off)
-+{
-+ u32 addr = 0;
-+
-+ /* Issue config commands only when the data link is up (atleast
-+ * one external pcie device is present).
-+ */
-+ if (dev >= 2 || !(bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_LSREG)
-+ & BCMA_CORE_PCI_DLLP_LSREG_LINKUP))
-+ goto out;
-+
-+ /* Type 0 transaction */
-+ /* Slide the PCI window to the appropriate slot */
-+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI1, BCMA_CORE_PCI_SBTOPCI_CFG0);
-+ /* Calculate the address */
-+ addr = pc->host_controller->host_cfg_addr;
-+ addr |= (dev << BCMA_CORE_PCI_CFG_SLOT_SHIFT);
-+ addr |= (func << BCMA_CORE_PCI_CFG_FUN_SHIFT);
-+ addr |= (off & ~3);
-+
-+out:
-+ return addr;
-+}
-+
-+static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
-+ unsigned int func, unsigned int off,
-+ void *buf, int len)
-+{
-+ int err = -EINVAL;
-+ u32 addr, val;
-+ void __iomem *mmio = 0;
-+
-+ WARN_ON(!pc->hostmode);
-+ if (unlikely(len != 1 && len != 2 && len != 4))
-+ goto out;
-+ if (dev == 0) {
-+ /* we support only two functions on device 0 */
-+ if (func > 1)
-+ return -EINVAL;
-+
-+ /* accesses to config registers with offsets >= 256
-+ * requires indirect access.
-+ */
-+ if (off >= PCI_CONFIG_SPACE_SIZE) {
-+ addr = (func << 12);
-+ addr |= (off & 0x0FFF);
-+ val = bcma_pcie_read_config(pc, addr);
-+ } else {
-+ addr = BCMA_CORE_PCI_PCICFG0;
-+ addr |= (func << 8);
-+ addr |= (off & 0xfc);
-+ val = pcicore_read32(pc, addr);
-+ }
-+ } else {
-+ addr = bcma_get_cfgspace_addr(pc, dev, func, off);
-+ if (unlikely(!addr))
-+ goto out;
-+ err = -ENOMEM;
-+ mmio = ioremap_nocache(addr, len);
-+ if (!mmio)
-+ goto out;
-+
-+ if (mips_busprobe32(val, mmio)) {
-+ val = 0xffffffff;
-+ goto unmap;
-+ }
-+
-+ val = readl(mmio);
-+ }
-+ val >>= (8 * (off & 3));
-+
-+ switch (len) {
-+ case 1:
-+ *((u8 *)buf) = (u8)val;
-+ break;
-+ case 2:
-+ *((u16 *)buf) = (u16)val;
-+ break;
-+ case 4:
-+ *((u32 *)buf) = (u32)val;
-+ break;
-+ }
-+ err = 0;
-+unmap:
-+ if (mmio)
-+ iounmap(mmio);
-+out:
-+ return err;
-+}
-+
-+static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
-+ unsigned int func, unsigned int off,
-+ const void *buf, int len)
-+{
-+ int err = -EINVAL;
-+ u32 addr = 0, val = 0;
-+ void __iomem *mmio = 0;
-+ u16 chipid = pc->core->bus->chipinfo.id;
-+
-+ WARN_ON(!pc->hostmode);
-+ if (unlikely(len != 1 && len != 2 && len != 4))
-+ goto out;
-+ if (dev == 0) {
-+ /* accesses to config registers with offsets >= 256
-+ * requires indirect access.
-+ */
-+ if (off < PCI_CONFIG_SPACE_SIZE) {
-+ addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
-+ addr |= (func << 8);
-+ addr |= (off & 0xfc);
-+ mmio = ioremap_nocache(addr, len);
-+ if (!mmio)
-+ goto out;
-+ }
-+ } else {
-+ addr = bcma_get_cfgspace_addr(pc, dev, func, off);
-+ if (unlikely(!addr))
-+ goto out;
-+ err = -ENOMEM;
-+ mmio = ioremap_nocache(addr, len);
-+ if (!mmio)
-+ goto out;
-+
-+ if (mips_busprobe32(val, mmio)) {
-+ val = 0xffffffff;
-+ goto unmap;
-+ }
-+ }
-+
-+ switch (len) {
-+ case 1:
-+ val = readl(mmio);
-+ val &= ~(0xFF << (8 * (off & 3)));
-+ val |= *((const u8 *)buf) << (8 * (off & 3));
-+ break;
-+ case 2:
-+ val = readl(mmio);
-+ val &= ~(0xFFFF << (8 * (off & 3)));
-+ val |= *((const u16 *)buf) << (8 * (off & 3));
-+ break;
-+ case 4:
-+ val = *((const u32 *)buf);
-+ break;
-+ }
-+ if (dev == 0 && !addr) {
-+ /* accesses to config registers with offsets >= 256
-+ * requires indirect access.
-+ */
-+ addr = (func << 12);
-+ addr |= (off & 0x0FFF);
-+ bcma_pcie_write_config(pc, addr, val);
-+ } else {
-+ writel(val, mmio);
-+
-+ if (chipid == 0x4716 || chipid == 0x4748)
-+ readl(mmio);
-+ }
-+
-+ err = 0;
-+unmap:
-+ if (mmio)
-+ iounmap(mmio);
-+out:
-+ return err;
-+}
-+
-+static int bcma_core_pci_hostmode_read_config(struct pci_bus *bus,
-+ unsigned int devfn,
-+ int reg, int size, u32 *val)
-+{
-+ unsigned long flags;
-+ int err;
-+ struct bcma_drv_pci *pc;
-+ struct bcma_drv_pci_host *pc_host;
-+
-+ pc_host = container_of(bus->ops, struct bcma_drv_pci_host, pci_ops);
-+ pc = pc_host->pdev;
-+
-+ spin_lock_irqsave(&pc_host->cfgspace_lock, flags);
-+ err = bcma_extpci_read_config(pc, PCI_SLOT(devfn),
-+ PCI_FUNC(devfn), reg, val, size);
-+ spin_unlock_irqrestore(&pc_host->cfgspace_lock, flags);
-+
-+ return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+static int bcma_core_pci_hostmode_write_config(struct pci_bus *bus,
-+ unsigned int devfn,
-+ int reg, int size, u32 val)
-+{
-+ unsigned long flags;
-+ int err;
-+ struct bcma_drv_pci *pc;
-+ struct bcma_drv_pci_host *pc_host;
-+
-+ pc_host = container_of(bus->ops, struct bcma_drv_pci_host, pci_ops);
-+ pc = pc_host->pdev;
-+
-+ spin_lock_irqsave(&pc_host->cfgspace_lock, flags);
-+ err = bcma_extpci_write_config(pc, PCI_SLOT(devfn),
-+ PCI_FUNC(devfn), reg, &val, size);
-+ spin_unlock_irqrestore(&pc_host->cfgspace_lock, flags);
-+
-+ return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+/* return cap_offset if requested capability exists in the PCI config space */
-+static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc,
-+ unsigned int dev,
-+ unsigned int func, u8 req_cap_id,
-+ unsigned char *buf, u32 *buflen)
-+{
-+ u8 cap_id;
-+ u8 cap_ptr = 0;
-+ u32 bufsize;
-+ u8 byte_val;
-+
-+ /* check for Header type 0 */
-+ bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val,
-+ sizeof(u8));
-+ if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
-+ return cap_ptr;
-+
-+ /* check if the capability pointer field exists */
-+ bcma_extpci_read_config(pc, dev, func, PCI_STATUS, &byte_val,
-+ sizeof(u8));
-+ if (!(byte_val & PCI_STATUS_CAP_LIST))
-+ return cap_ptr;
-+
-+ /* check if the capability pointer is 0x00 */
-+ bcma_extpci_read_config(pc, dev, func, PCI_CAPABILITY_LIST, &cap_ptr,
-+ sizeof(u8));
-+ if (cap_ptr == 0x00)
-+ return cap_ptr;
-+
-+ /* loop thr'u the capability list and see if the requested capabilty
-+ * exists */
-+ bcma_extpci_read_config(pc, dev, func, cap_ptr, &cap_id, sizeof(u8));
-+ while (cap_id != req_cap_id) {
-+ bcma_extpci_read_config(pc, dev, func, cap_ptr + 1, &cap_ptr,
-+ sizeof(u8));
-+ if (cap_ptr == 0x00)
-+ return cap_ptr;
-+ bcma_extpci_read_config(pc, dev, func, cap_ptr, &cap_id,
-+ sizeof(u8));
-+ }
-+
-+ /* found the caller requested capability */
-+ if ((buf != NULL) && (buflen != NULL)) {
-+ u8 cap_data;
-+
-+ bufsize = *buflen;
-+ if (!bufsize)
-+ return cap_ptr;
-+
-+ *buflen = 0;
-+
-+ /* copy the cpability data excluding cap ID and next ptr */
-+ cap_data = cap_ptr + 2;
-+ if ((bufsize + cap_data) > PCI_CONFIG_SPACE_SIZE)
-+ bufsize = PCI_CONFIG_SPACE_SIZE - cap_data;
-+ *buflen = bufsize;
-+ while (bufsize--) {
-+ bcma_extpci_read_config(pc, dev, func, cap_data, buf,
-+ sizeof(u8));
-+ cap_data++;
-+ buf++;
-+ }
-+ }
-+
-+ return cap_ptr;
-+}
-+
-+/* If the root port is capable of returning Config Request
-+ * Retry Status (CRS) Completion Status to software then
-+ * enable the feature.
-+ */
-+static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc)
-+{
-+ u8 cap_ptr, root_ctrl, root_cap, dev;
-+ u16 val16;
-+ int i;
-+
-+ cap_ptr = bcma_find_pci_capability(pc, 0, 0, PCI_CAP_ID_EXP, NULL,
-+ NULL);
-+ root_cap = cap_ptr + PCI_EXP_RTCAP;
-+ bcma_extpci_read_config(pc, 0, 0, root_cap, &val16, sizeof(u16));
-+ if (val16 & BCMA_CORE_PCI_RC_CRS_VISIBILITY) {
-+ /* Enable CRS software visibility */
-+ root_ctrl = cap_ptr + PCI_EXP_RTCTL;
-+ val16 = PCI_EXP_RTCTL_CRSSVE;
-+ bcma_extpci_read_config(pc, 0, 0, root_ctrl, &val16,
-+ sizeof(u16));
-+
-+ /* Initiate a configuration request to read the vendor id
-+ * field of the device function's config space header after
-+ * 100 ms wait time from the end of Reset. If the device is
-+ * not done with its internal initialization, it must at
-+ * least return a completion TLP, with a completion status
-+ * of "Configuration Request Retry Status (CRS)". The root
-+ * complex must complete the request to the host by returning
-+ * a read-data value of 0001h for the Vendor ID field and
-+ * all 1s for any additional bytes included in the request.
-+ * Poll using the config reads for max wait time of 1 sec or
-+ * until we receive the successful completion status. Repeat
-+ * the procedure for all the devices.
-+ */
-+ for (dev = 1; dev < BCMA_PCI_SLOT_MAX; dev++) {
-+ for (i = 0; i < 100000; i++) {
-+ bcma_extpci_read_config(pc, dev, 0,
-+ PCI_VENDOR_ID, &val16,
-+ sizeof(val16));
-+ if (val16 != 0x1)
-+ break;
-+ udelay(10);
-+ }
-+ if (val16 == 0x1)
-+ pr_err("PCI: Broken device in slot %d\n", dev);
-+ }
-+ }
-+}
-
- void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
- {
-- pr_err("No support for PCI core in hostmode yet\n");
-+ struct bcma_bus *bus = pc->core->bus;
-+ struct bcma_drv_pci_host *pc_host;
-+ u32 tmp;
-+ u32 pci_membase_1G;
-+ unsigned long io_map_base;
-+
-+ pr_info("PCIEcore in host mode found\n");
-+
-+ pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
-+ if (!pc_host) {
-+ pr_err("can not allocate memory");
-+ return;
-+ }
-+
-+ pc->host_controller = pc_host;
-+ pc_host->pci_controller.io_resource = &pc_host->io_resource;
-+ pc_host->pci_controller.mem_resource = &pc_host->mem_resource;
-+ pc_host->pci_controller.pci_ops = &pc_host->pci_ops;
-+ pc_host->pdev = pc;
-+
-+ pci_membase_1G = BCMA_SOC_PCI_DMA;
-+ pc_host->host_cfg_addr = BCMA_SOC_PCI_CFG;
-+
-+ pc_host->pci_ops.read = bcma_core_pci_hostmode_read_config;
-+ pc_host->pci_ops.write = bcma_core_pci_hostmode_write_config;
-+
-+ pc_host->mem_resource.name = "BCMA PCIcore external memory",
-+ pc_host->mem_resource.start = BCMA_SOC_PCI_DMA;
-+ pc_host->mem_resource.end = BCMA_SOC_PCI_DMA + BCMA_SOC_PCI_DMA_SZ - 1;
-+ pc_host->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
-+
-+ pc_host->io_resource.name = "BCMA PCIcore external I/O",
-+ pc_host->io_resource.start = 0x100;
-+ pc_host->io_resource.end = 0x7FF;
-+ pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
-+
-+ /* Reset RC */
-+ udelay(3000);
-+ pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
-+ udelay(1000);
-+ pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
-+ BCMA_CORE_PCI_CTL_RST_OE);
-+
-+ /* 64 MB I/O access window. On 4716, use
-+ * sbtopcie0 to access the device registers. We
-+ * can't use address match 2 (1 GB window) region
-+ * as mips can't generate 64-bit address on the
-+ * backplane.
-+ */
-+ if (bus->chipinfo.id == 0x4716 || bus->chipinfo.id == 0x4748) {
-+ pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
-+ pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
-+ BCMA_SOC_PCI_MEM_SZ - 1;
-+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
-+ BCMA_CORE_PCI_SBTOPCI_MEM | BCMA_SOC_PCI_MEM);
-+ } else if (bus->chipinfo.id == 0x5300) {
-+ tmp = BCMA_CORE_PCI_SBTOPCI_MEM;
-+ tmp |= BCMA_CORE_PCI_SBTOPCI_PREF;
-+ tmp |= BCMA_CORE_PCI_SBTOPCI_BURST;
-+ if (pc->core->core_unit == 0) {
-+ pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
-+ pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
-+ BCMA_SOC_PCI_MEM_SZ - 1;
-+ pci_membase_1G = BCMA_SOC_PCIE_DMA_H32;
-+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
-+ tmp | BCMA_SOC_PCI_MEM);
-+ } else if (pc->core->core_unit == 1) {
-+ pc_host->mem_resource.start = BCMA_SOC_PCI1_MEM;
-+ pc_host->mem_resource.end = BCMA_SOC_PCI1_MEM +
-+ BCMA_SOC_PCI_MEM_SZ - 1;
-+ pci_membase_1G = BCMA_SOC_PCIE1_DMA_H32;
-+ pc_host->host_cfg_addr = BCMA_SOC_PCI1_CFG;
-+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
-+ tmp | BCMA_SOC_PCI1_MEM);
-+ }
-+ } else
-+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
-+ BCMA_CORE_PCI_SBTOPCI_IO);
-+
-+ /* 64 MB configuration access window */
-+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI1, BCMA_CORE_PCI_SBTOPCI_CFG0);
-+
-+ /* 1 GB memory access window */
-+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI2,
-+ BCMA_CORE_PCI_SBTOPCI_MEM | pci_membase_1G);
-+
-+
-+ /* As per PCI Express Base Spec 1.1 we need to wait for
-+ * at least 100 ms from the end of a reset (cold/warm/hot)
-+ * before issuing configuration requests to PCI Express
-+ * devices.
-+ */
-+ udelay(100000);
-+
-+ bcma_core_pci_enable_crs(pc);
-+
-+ /* Enable PCI bridge BAR0 memory & master access */
-+ tmp = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
-+ bcma_extpci_write_config(pc, 0, 0, PCI_COMMAND, &tmp, sizeof(tmp));
-+
-+ /* Enable PCI interrupts */
-+ pcicore_write32(pc, BCMA_CORE_PCI_IMASK, BCMA_CORE_PCI_IMASK_INTA);
-+
-+ /* Ok, ready to run, register it to the system.
-+ * The following needs change, if we want to port hostmode
-+ * to non-MIPS platform. */
-+ io_map_base = (unsigned long)ioremap_nocache(BCMA_SOC_PCI_MEM,
-+ 0x04000000);
-+ pc_host->pci_controller.io_map_base = io_map_base;
-+ set_io_port_base(pc_host->pci_controller.io_map_base);
-+ /* Give some time to the PCI controller to configure itself with the new
-+ * values. Not waiting at this point causes crashes of the machine. */
-+ mdelay(10);
-+ register_pci_controller(&pc_host->pci_controller);
-+ return;
-+}
-+
-+/* Early PCI fixup for a device on the PCI-core bridge. */
-+static void bcma_core_pci_fixup_pcibridge(struct pci_dev *dev)
-+{
-+ if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
-+ /* This is not a device on the PCI-core bridge. */
-+ return;
-+ }
-+ if (PCI_SLOT(dev->devfn) != 0)
-+ return;
-+
-+ pr_info("PCI: Fixing up bridge %s\n", pci_name(dev));
-+
-+ /* Enable PCI bridge bus mastering and memory space */
-+ pci_set_master(dev);
-+ if (pcibios_enable_device(dev, ~0) < 0) {
-+ pr_err("PCI: BCMA bridge enable failed\n");
-+ return;
-+ }
-+
-+ /* Enable PCI bridge BAR1 prefetch and burst */
-+ pci_write_config_dword(dev, BCMA_PCI_BAR1_CONTROL, 3);
-+}
-+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_pcibridge);
-+
-+/* Early PCI fixup for all PCI-cores to set the correct memory address. */
-+static void bcma_core_pci_fixup_addresses(struct pci_dev *dev)
-+{
-+ struct resource *res;
-+ int pos;
-+
-+ if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
-+ /* This is not a device on the PCI-core bridge. */
-+ return;
-+ }
-+ if (PCI_SLOT(dev->devfn) == 0)
-+ return;
-+
-+ pr_info("PCI: Fixing up addresses %s\n", pci_name(dev));
-+
-+ for (pos = 0; pos < 6; pos++) {
-+ res = &dev->resource[pos];
-+ if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM))
-+ pci_assign_resource(dev, pos);
-+ }
-+}
-+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_addresses);
-+
-+/* This function is called when doing a pci_enable_device().
-+ * We must first check if the device is a device on the PCI-core bridge. */
-+int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
-+{
-+ struct bcma_drv_pci_host *pc_host;
-+
-+ if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
-+ /* This is not a device on the PCI-core bridge. */
-+ return -ENODEV;
-+ }
-+ pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
-+ pci_ops);
-+
-+ pr_info("PCI: Fixing up device %s\n", pci_name(dev));
-+
-+ /* Fix up interrupt lines */
-+ dev->irq = bcma_core_mips_irq(pc_host->pdev->core) + 2;
-+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(bcma_core_pci_plat_dev_init);
-+
-+/* PCI device IRQ mapping. */
-+int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
-+{
-+ struct bcma_drv_pci_host *pc_host;
-+
-+ if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
-+ /* This is not a device on the PCI-core bridge. */
-+ return -ENODEV;
-+ }
-+
-+ pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
-+ pci_ops);
-+ return bcma_core_mips_irq(pc_host->pdev->core) + 2;
- }
-+EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
---- a/include/linux/bcma/bcma_driver_pci.h
-+++ b/include/linux/bcma/bcma_driver_pci.h
-@@ -160,9 +160,40 @@ struct pci_dev;
- /* PCIcore specific boardflags */
- #define BCMA_CORE_PCI_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
-
-+/* PCIE Config space accessing MACROS */
-+#define BCMA_CORE_PCI_CFG_BUS_SHIFT 24 /* Bus shift */
-+#define BCMA_CORE_PCI_CFG_SLOT_SHIFT 19 /* Slot/Device shift */
-+#define BCMA_CORE_PCI_CFG_FUN_SHIFT 16 /* Function shift */
-+#define BCMA_CORE_PCI_CFG_OFF_SHIFT 0 /* Register shift */
-+
-+#define BCMA_CORE_PCI_CFG_BUS_MASK 0xff /* Bus mask */
-+#define BCMA_CORE_PCI_CFG_SLOT_MASK 0x1f /* Slot/Device mask */
-+#define BCMA_CORE_PCI_CFG_FUN_MASK 7 /* Function mask */
-+#define BCMA_CORE_PCI_CFG_OFF_MASK 0xfff /* Register mask */
-+
-+/* PCIE Root Capability Register bits (Host mode only) */
-+#define BCMA_CORE_PCI_RC_CRS_VISIBILITY 0x0001
-+
-+struct bcma_drv_pci;
-+
-+struct bcma_drv_pci_host {
-+ struct bcma_drv_pci *pdev;
-+
-+ u32 host_cfg_addr;
-+ spinlock_t cfgspace_lock;
-+
-+ struct pci_controller pci_controller;
-+ struct pci_ops pci_ops;
-+ struct resource mem_resource;
-+ struct resource io_resource;
-+};
-+
- struct bcma_drv_pci {
- struct bcma_device *core;
- u8 setup_done:1;
-+ u8 hostmode:1;
-+
-+ struct bcma_drv_pci_host *host_controller;
- };
-
- /* Register access */
-@@ -173,4 +204,7 @@ extern void __devinit bcma_core_pci_init
- extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
- struct bcma_device *core, bool enable);
-
-+extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
-+extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
-+
- #endif /* LINUX_BCMA_DRIVER_PCI_H_ */
---- a/include/linux/bcma/bcma_regs.h
-+++ b/include/linux/bcma/bcma_regs.h
-@@ -56,4 +56,31 @@
- #define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
- #define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
-
-+/* SiliconBackplane Address Map.
-+ * All regions may not exist on all chips.
-+ */
-+#define BCMA_SOC_SDRAM_BASE 0x00000000U /* Physical SDRAM */
-+#define BCMA_SOC_PCI_MEM 0x08000000U /* Host Mode sb2pcitranslation0 (64 MB) */
-+#define BCMA_SOC_PCI_MEM_SZ (64 * 1024 * 1024)
-+#define BCMA_SOC_PCI_CFG 0x0c000000U /* Host Mode sb2pcitranslation1 (64 MB) */
-+#define BCMA_SOC_SDRAM_SWAPPED 0x10000000U /* Byteswapped Physical SDRAM */
-+#define BCMA_SOC_SDRAM_R2 0x80000000U /* Region 2 for sdram (512 MB) */
-+
-+
-+#define BCMA_SOC_PCI_DMA 0x40000000U /* Client Mode sb2pcitranslation2 (1 GB) */
-+#define BCMA_SOC_PCI_DMA2 0x80000000U /* Client Mode sb2pcitranslation2 (1 GB) */
-+#define BCMA_SOC_PCI_DMA_SZ 0x40000000U /* Client Mode sb2pcitranslation2 size in bytes */
-+#define BCMA_SOC_PCIE_DMA_L32 0x00000000U /* PCIE Client Mode sb2pcitranslation2
-+ * (2 ZettaBytes), low 32 bits
-+ */
-+#define BCMA_SOC_PCIE_DMA_H32 0x80000000U /* PCIE Client Mode sb2pcitranslation2
-+ * (2 ZettaBytes), high 32 bits
-+ */
-+
-+#define BCMA_SOC_PCI1_MEM 0x40000000U /* Host Mode sb2pcitranslation0 (64 MB) */
-+#define BCMA_SOC_PCI1_CFG 0x44000000U /* Host Mode sb2pcitranslation1 (64 MB) */
-+#define BCMA_SOC_PCIE1_DMA_H32 0xc0000000U /* PCIE Client Mode sb2pcitranslation2
-+ * (2 ZettaBytes), high 32 bits
-+ */
-+
- #endif /* LINUX_BCMA_REGS_H_ */
+++ /dev/null
-From eecd733c14952b074d7488934a4f3dc83c9c426b Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 14 Jan 2012 16:29:51 +0100
-Subject: [PATCH 28/32] bcma: add bus num counter
-
-If we have two bcma buses on one computer the second will not work
-without this patch. Now each bus gets an own number.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/main.c | 12 +++++++++++-
- include/linux/bcma/bcma.h | 1 +
- 2 files changed, 12 insertions(+), 1 deletions(-)
-
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -13,6 +13,12 @@
- MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
- MODULE_LICENSE("GPL");
-
-+/* contains the number the next bus should get. */
-+static unsigned int bcma_bus_next_num = 0;
-+
-+/* bcma_buses_mutex locks the bcma_bus_next_num */
-+static DEFINE_MUTEX(bcma_buses_mutex);
-+
- static int bcma_bus_match(struct device *dev, struct device_driver *drv);
- static int bcma_device_probe(struct device *dev);
- static int bcma_device_remove(struct device *dev);
-@@ -93,7 +99,7 @@ static int bcma_register_cores(struct bc
-
- core->dev.release = bcma_release_core_dev;
- core->dev.bus = &bcma_bus_type;
-- dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
-+ dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
-
- switch (bus->hosttype) {
- case BCMA_HOSTTYPE_PCI:
-@@ -137,6 +143,10 @@ int __devinit bcma_bus_register(struct b
- int err;
- struct bcma_device *core;
-
-+ mutex_lock(&bcma_buses_mutex);
-+ bus->num = bcma_bus_next_num++;
-+ mutex_unlock(&bcma_buses_mutex);
-+
- /* Scan for devices (cores) */
- err = bcma_bus_scan(bus);
- if (err) {
---- a/include/linux/bcma/bcma.h
-+++ b/include/linux/bcma/bcma.h
-@@ -196,6 +196,7 @@ struct bcma_bus {
- struct list_head cores;
- u8 nr_cores;
- u8 init_done:1;
-+ u8 num;
-
- struct bcma_drv_cc drv_cc;
- struct bcma_drv_pci drv_pci;
+++ /dev/null
-From 699c57a18b40ffbe1763915acdc1a3e4fb539d01 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Fri, 13 Jan 2012 17:42:15 +0100
-Subject: [PATCH 29/32] bcma: add new PCI ID
-
-This ID was found on the PCIe wireless card on the board of a Netgear
-WNDR3400 using a bcm4716. The device with this ID is identified by b43
-as "Broadcom 43224 WLAN".
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/host_pci.c | 1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
-
---- a/drivers/bcma/host_pci.c
-+++ b/drivers/bcma/host_pci.c
-@@ -278,6 +278,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_
- { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
- { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
- { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0xa8d8) },
- { 0, },
- };
- MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
+++ /dev/null
-From 1cd3d0de72e42161fe0df355c5429459265aeef0 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 14 Jan 2012 16:11:17 +0100
-Subject: [PATCH 30/32] bcma: add extra sprom check
-
-This check is needed on the BCM43224 device as it says in the
-capabilities it has an sprom but is extra check says it has not.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/sprom.c | 8 ++++++++
- include/linux/bcma/bcma_driver_chipcommon.h | 16 ++++++++++++++++
- 2 files changed, 24 insertions(+), 0 deletions(-)
-
---- a/drivers/bcma/sprom.c
-+++ b/drivers/bcma/sprom.c
-@@ -209,6 +209,7 @@ int bcma_sprom_get(struct bcma_bus *bus)
- {
- u16 offset;
- u16 *sprom;
-+ u32 sromctrl;
- int err = 0;
-
- if (!bus->drv_cc.core)
-@@ -217,6 +218,12 @@ int bcma_sprom_get(struct bcma_bus *bus)
- if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
- return -ENOENT;
-
-+ if (bus->drv_cc.core->id.rev >= 32) {
-+ sromctrl = bcma_read32(bus->drv_cc.core, BCMA_CC_SROM_CONTROL);
-+ if (!(sromctrl & BCMA_CC_SROM_CONTROL_PRESENT))
-+ return -ENOENT;
-+ }
-+
- sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
- GFP_KERNEL);
- if (!sprom)
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -239,6 +239,22 @@
- #define BCMA_CC_FLASH_CFG 0x0128
- #define BCMA_CC_FLASH_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */
- #define BCMA_CC_FLASH_WAITCNT 0x012C
-+#define BCMA_CC_SROM_CONTROL 0x0190
-+#define BCMA_CC_SROM_CONTROL_START 0x80000000
-+#define BCMA_CC_SROM_CONTROL_BUSY 0x80000000
-+#define BCMA_CC_SROM_CONTROL_OPCODE 0x60000000
-+#define BCMA_CC_SROM_CONTROL_OP_READ 0x00000000
-+#define BCMA_CC_SROM_CONTROL_OP_WRITE 0x20000000
-+#define BCMA_CC_SROM_CONTROL_OP_WRDIS 0x40000000
-+#define BCMA_CC_SROM_CONTROL_OP_WREN 0x60000000
-+#define BCMA_CC_SROM_CONTROL_OTPSEL 0x00000010
-+#define BCMA_CC_SROM_CONTROL_LOCK 0x00000008
-+#define BCMA_CC_SROM_CONTROL_SIZE_MASK 0x00000006
-+#define BCMA_CC_SROM_CONTROL_SIZE_1K 0x00000000
-+#define BCMA_CC_SROM_CONTROL_SIZE_4K 0x00000002
-+#define BCMA_CC_SROM_CONTROL_SIZE_16K 0x00000004
-+#define BCMA_CC_SROM_CONTROL_SIZE_SHIFT 1
-+#define BCMA_CC_SROM_CONTROL_PRESENT 0x00000001
- /* 0x1E0 is defined as shared BCMA_CLKCTLST */
- #define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
- #define BCMA_CC_UART0_DATA 0x0300
+++ /dev/null
-From 7b90e7040b9783b91a4e2baf72ac32d3a00f9f2d Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 21 Jan 2012 11:18:25 +0100
-Subject: [PATCH 31/34] ssb: fix cardbus in hostmode
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/ssb/driver_pcicore.c | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
---- a/drivers/ssb/driver_pcicore.c
-+++ b/drivers/ssb/driver_pcicore.c
-@@ -75,7 +75,7 @@ static u32 get_cfgspace_addr(struct ssb_
- u32 tmp;
-
- /* We do only have one cardbus device behind the bridge. */
-- if (pc->cardbusmode && (dev >= 1))
-+ if (pc->cardbusmode && (dev > 1))
- goto out;
-
- if (bus == 0) {
+++ /dev/null
-From efe89df0326b777563d197b8cf1c25209a31ceb0 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 21 Jan 2012 18:47:42 +0100
-Subject: [PATCH 32/34] bcma: complete workaround for BCMA43224
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/driver_chipcommon_pmu.c | 15 +++++++++++----
- include/linux/bcma/bcma_driver_chipcommon.h | 5 +++++
- 2 files changed, 16 insertions(+), 4 deletions(-)
-
---- a/drivers/bcma/driver_chipcommon_pmu.c
-+++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -141,12 +141,19 @@ void bcma_pmu_workarounds(struct bcma_dr
- /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
- break;
- case 43224:
-+ case 43421:
-+ /* enable 12 mA drive strenth for 43224 and set chipControl register bit 15 */
- if (bus->chipinfo.rev == 0) {
-- pr_err("Workarounds for 43224 rev 0 not fully "
-- "implemented\n");
-- bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x00F000F0);
-+ bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL,
-+ BCMA_CCTRL_43224_GPIO_TOGGLE,
-+ BCMA_CCTRL_43224_GPIO_TOGGLE);
-+ bcma_chipco_chipctl_maskset(cc, 0,
-+ BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
-+ BCMA_CCTRL_43224A0_12MA_LED_DRIVE);
- } else {
-- bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
-+ bcma_chipco_chipctl_maskset(cc, 0,
-+ BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
-+ BCMA_CCTRL_43224B0_12MA_LED_DRIVE);
- }
- break;
- case 43225:
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -374,6 +374,11 @@
- #define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4 BIT(16) /* enable bt_shd0 at gpio4 */
- #define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5 BIT(17) /* enable bt_shd1 at gpio5 */
-
-+/* 43224 chip-specific ChipControl register bits */
-+#define BCMA_CCTRL_43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */
-+#define BCMA_CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */
-+#define BCMA_CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */
-+
- #define BCMA_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
- #define BCMA_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
- #define BCMA_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
+++ /dev/null
-From 293fcc92dae1284c35a3bb51e7f9eb13b52e58fe Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Tue, 31 Jan 2012 23:36:44 +0100
-Subject: [PATCH 2/4] bcma: log the id, rev and pkg of the chip found
-
-This makes us see what type of hardware someone uses by the dmesg
-output.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/scan.c | 10 +++++++---
- 1 files changed, 7 insertions(+), 3 deletions(-)
-
---- a/drivers/bcma/scan.c
-+++ b/drivers/bcma/scan.c
-@@ -364,6 +364,7 @@ static int bcma_get_next_core(struct bcm
- void bcma_init_bus(struct bcma_bus *bus)
- {
- s32 tmp;
-+ struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
-
- if (bus->init_done)
- return;
-@@ -374,9 +375,12 @@ void bcma_init_bus(struct bcma_bus *bus)
- bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
-
- tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
-- 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;
-+ chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
-+ chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
-+ chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
-+ pr_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
-+ chipinfo->id, chipinfo->rev, chipinfo->pkg);
-+
- bus->init_done = true;
- }
-
+++ /dev/null
-From 7ddcc963030bbc82add2efbd49e696ae8aff3ae6 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Tue, 31 Jan 2012 23:38:36 +0100
-Subject: [PATCH 3/4] ssb: log the id, rev and pkg of the chip found
-
-This makes us see what type of hardware someone uses by the dmesg
-output.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/ssb/scan.c | 3 +++
- 1 files changed, 3 insertions(+), 0 deletions(-)
-
---- a/drivers/ssb/scan.c
-+++ b/drivers/ssb/scan.c
-@@ -318,6 +318,9 @@ int ssb_bus_scan(struct ssb_bus *bus,
- bus->chip_package = 0;
- }
- }
-+ ssb_printk(KERN_INFO PFX "Found chip with id 0x%04X, rev 0x%02X and "
-+ "package 0x%02X\n", bus->chip_id, bus->chip_rev,
-+ bus->chip_package);
- if (!bus->nr_devices)
- bus->nr_devices = chipid_to_nrcores(bus->chip_id);
- if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
+++ /dev/null
-From 9be402f069cc259ad5795b77567d66c4e7f6bef6 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 18 Jul 2010 14:59:24 +0200
-Subject: [PATCH 4/6] MIPS: BCM47xx: Setup and register serial early
-
-Swap the first and second serial if console=ttyS1 was set.
-Set it up and register it for early serial support.
-
-This patch has been in OpenWRT for a long time.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/bcm47xx/setup.c | 39 ++++++++++++++++++++++++++++++++++++++-
- 1 files changed, 38 insertions(+), 1 deletions(-)
-
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -32,6 +32,8 @@
- #include <linux/ssb/ssb_embedded.h>
- #include <linux/bcma/bcma_soc.h>
- #include <linux/platform_device.h>
-+#include <linux/serial.h>
-+#include <linux/serial_8250.h>
- #include <asm/bootinfo.h>
- #include <asm/reboot.h>
- #include <asm/time.h>
-@@ -279,6 +281,31 @@ static int bcm47xx_get_invariants(struct
- return 0;
- }
-
-+#ifdef CONFIG_SERIAL_8250
-+static void __init bcm47xx_early_serial_setup(struct ssb_mipscore *mcore)
-+{
-+ int i;
-+
-+ for (i = 0; i < mcore->nr_serial_ports; i++) {
-+ struct ssb_serial_port *port = &(mcore->serial_ports[i]);
-+ struct uart_port s;
-+
-+ memset(&s, 0, sizeof(s));
-+ s.line = i;
-+ s.mapbase = (unsigned int) port->regs;
-+ s.membase = port->regs;
-+ s.irq = port->irq + 2;
-+ s.uartclk = port->baud_base;
-+ s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
-+ s.iotype = SERIAL_IO_MEM;
-+ s.regshift = port->reg_shift;
-+
-+ early_serial_setup(&s);
-+ }
-+ printk(KERN_DEBUG "Serial init done.\n");
-+}
-+#endif
-+
- static void __init bcm47xx_register_ssb(void)
- {
- int err;
-@@ -311,6 +338,10 @@ static void __init bcm47xx_register_ssb(
- memcpy(&mcore->serial_ports[1], &port, sizeof(port));
- }
- }
-+
-+#ifdef CONFIG_SERIAL_8250
-+ bcm47xx_early_serial_setup(mcore);
-+#endif
- }
- #endif
-
+++ /dev/null
-From 5219981646071abb6731634bf47781a53e248764 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 18 Jul 2010 15:11:26 +0200
-Subject: [PATCH 6/6] MIPS: BCM47xx: Remove CFE console
-
-Do not use the CFE console. It causes hangs on some devices like the
-Buffalo WHR-HP-G54.
-This was reported in https://dev.openwrt.org/ticket/4061 and
-https://forum.openwrt.org/viewtopic.php?id=17063
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/Kconfig | 1 -
- arch/mips/bcm47xx/prom.c | 82 +++------------------------------------------
- 2 files changed, 6 insertions(+), 77 deletions(-)
-
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -97,7 +97,6 @@ config BCM47XX
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_LITTLE_ENDIAN
- select GENERIC_GPIO
-- select SYS_HAS_EARLY_PRINTK
- select CFE
- help
- Support for BCM47XX based boards
---- a/arch/mips/bcm47xx/prom.c
-+++ b/arch/mips/bcm47xx/prom.c
-@@ -31,96 +31,28 @@
- #include <asm/fw/cfe/cfe_api.h>
- #include <asm/fw/cfe/cfe_error.h>
-
--static int cfe_cons_handle;
--
- const char *get_system_type(void)
- {
- return "Broadcom BCM47XX";
- }
-
--void prom_putchar(char c)
--{
-- while (cfe_write(cfe_cons_handle, &c, 1) == 0)
-- ;
--}
--
--static __init void prom_init_cfe(void)
-+static __init int prom_init_cfe(void)
- {
- uint32_t cfe_ept;
- uint32_t cfe_handle;
- uint32_t cfe_eptseal;
-- int argc = fw_arg0;
-- char **envp = (char **) fw_arg2;
-- int *prom_vec = (int *) fw_arg3;
--
-- /*
-- * Check if a loader was used; if NOT, the 4 arguments are
-- * what CFE gives us (handle, 0, EPT and EPTSEAL)
-- */
-- if (argc < 0) {
-- cfe_handle = (uint32_t)argc;
-- cfe_ept = (uint32_t)envp;
-- cfe_eptseal = (uint32_t)prom_vec;
-- } else {
-- if ((int)prom_vec < 0) {
-- /*
-- * Old loader; all it gives us is the handle,
-- * so use the "known" entrypoint and assume
-- * the seal.
-- */
-- cfe_handle = (uint32_t)prom_vec;
-- cfe_ept = 0xBFC00500;
-- cfe_eptseal = CFE_EPTSEAL;
-- } else {
-- /*
-- * Newer loaders bundle the handle/ept/eptseal
-- * Note: prom_vec is in the loader's useg
-- * which is still alive in the TLB.
-- */
-- cfe_handle = prom_vec[0];
-- cfe_ept = prom_vec[2];
-- cfe_eptseal = prom_vec[3];
-- }
-- }
-+
-+ cfe_eptseal = (uint32_t) fw_arg3;
-+ cfe_handle = (uint32_t) fw_arg0;
-+ cfe_ept = (uint32_t) fw_arg2;
-
- if (cfe_eptseal != CFE_EPTSEAL) {
-- /* too early for panic to do any good */
- printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
-- while (1) ;
-+ return -1;
- }
-
- cfe_init(cfe_handle, cfe_ept);
--}
--
--static __init void prom_init_console(void)
--{
-- /* Initialize CFE console */
-- cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
--}
--
--static __init void prom_init_cmdline(void)
--{
-- static char buf[COMMAND_LINE_SIZE] __initdata;
--
-- /* Get the kernel command line from CFE */
-- if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) {
-- buf[COMMAND_LINE_SIZE - 1] = 0;
-- strcpy(arcs_cmdline, buf);
-- }
--
-- /* Force a console handover by adding a console= argument if needed,
-- * as CFE is not available anymore later in the boot process. */
-- if ((strstr(arcs_cmdline, "console=")) == NULL) {
-- /* Try to read the default serial port used by CFE */
-- if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0)
-- || (strncmp("uart", buf, 4)))
-- /* Default to uart0 */
-- strcpy(buf, "uart0");
--
-- /* Compute the new command line */
-- snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200",
-- arcs_cmdline, buf[4]);
-- }
-+ return 0;
- }
-
- static __init void prom_init_mem(void)
-@@ -161,8 +93,6 @@ static __init void prom_init_mem(void)
- void __init prom_init(void)
- {
- prom_init_cfe();
-- prom_init_console();
-- prom_init_cmdline();
- prom_init_mem();
- }
-
+++ /dev/null
---- a/arch/mips/kernel/head.S
-+++ b/arch/mips/kernel/head.S
-@@ -121,14 +121,6 @@
- #endif
- .endm
-
--#ifndef CONFIG_NO_EXCEPT_FILL
-- /*
-- * Reserved space for exception handlers.
-- * Necessary for machines which link their kernels at KSEG0.
-- */
-- .fill 0x400
--#endif
--
- EXPORT(_stext)
-
- #ifdef CONFIG_BOOT_RAW
-@@ -141,6 +133,14 @@ FEXPORT(__kernel_entry)
- j kernel_entry
- #endif
-
-+#ifndef CONFIG_NO_EXCEPT_FILL
-+ /*
-+ * Reserved space for exception handlers.
-+ * Necessary for machines which link their kernels at KSEG0.
-+ */
-+ .fill 0x400
-+#endif
-+
- #ifdef CONFIG_IMAGE_CMDLINE_HACK
- .ascii "CMDLINE:"
- EXPORT(__image_cmdline)
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -89,6 +89,7 @@ config ATH79
-
- config BCM47XX
- bool "Broadcom BCM47XX based boards"
-+ select BOOT_RAW
- select CEVT_R4K
- select CSRC_R4K
- select DMA_NONCOHERENT
--- /dev/null
+From b7d9f9cd6a8e463c1061ea29ed3e614403625024 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:51:47 +0200
+Subject: [PATCH 12/26] bcma: move parallel flash into a union
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/nvram.c | 3 +
+ drivers/bcma/driver_mips.c | 1 +
+ include/linux/bcma/bcma_driver_chipcommon.h | 73 ++++++++++++++++++++++++++-
+ 3 files changed, 76 insertions(+), 1 deletions(-)
+
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -50,6 +50,9 @@ static void early_nvram_init(void)
+ #ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
++ if (bcma_cc->flash_type != BCMA_PFLASH)
++ return;
++
+ base = bcma_cc->pflash.window;
+ lim = bcma_cc->pflash.window_size;
+ break;
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -189,6 +189,7 @@ static void bcma_core_mips_flash_detect(
+ break;
+ case BCMA_CC_FLASHT_PARA:
+ pr_info("found parallel flash.\n");
++ bus->drv_cc.flash_type = BCMA_PFLASH;
+ bus->drv_cc.pflash.window = 0x1c000000;
+ bus->drv_cc.pflash.window_size = 0x02000000;
+
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -108,10 +108,68 @@
+ #define BCMA_CC_JCTL_EXT_EN 2 /* Enable external targets */
+ #define BCMA_CC_JCTL_EN 1 /* Enable Jtag master */
+ #define BCMA_CC_FLASHCTL 0x0040
++
++/* Start/busy bit in flashcontrol */
++#define BCMA_CC_FLASHCTL_OPCODE 0x000000ff
++#define BCMA_CC_FLASHCTL_ACTION 0x00000700
++#define BCMA_CC_FLASHCTL_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */
+ #define BCMA_CC_FLASHCTL_START 0x80000000
+ #define BCMA_CC_FLASHCTL_BUSY BCMA_CC_FLASHCTL_START
++
++/* flashcontrol action+opcodes for ST flashes */
++#define BCMA_CC_FLASHCTL_ST_WREN 0x0006 /* Write Enable */
++#define BCMA_CC_FLASHCTL_ST_WRDIS 0x0004 /* Write Disable */
++#define BCMA_CC_FLASHCTL_ST_RDSR 0x0105 /* Read Status Register */
++#define BCMA_CC_FLASHCTL_ST_WRSR 0x0101 /* Write Status Register */
++#define BCMA_CC_FLASHCTL_ST_READ 0x0303 /* Read Data Bytes */
++#define BCMA_CC_FLASHCTL_ST_PP 0x0302 /* Page Program */
++#define BCMA_CC_FLASHCTL_ST_SE 0x02d8 /* Sector Erase */
++#define BCMA_CC_FLASHCTL_ST_BE 0x00c7 /* Bulk Erase */
++#define BCMA_CC_FLASHCTL_ST_DP 0x00b9 /* Deep Power-down */
++#define BCMA_CC_FLASHCTL_ST_RES 0x03ab /* Read Electronic Signature */
++#define BCMA_CC_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
++#define BCMA_CC_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
++
++
++/* flashcontrol action+opcodes for Atmel flashes */
++#define BCMA_CC_FLASHCTL_AT_READ 0x07e8
++#define BCMA_CC_FLASHCTL_AT_PAGE_READ 0x07d2
++#define BCMA_CC_FLASHCTL_AT_BUF1_READ
++#define BCMA_CC_FLASHCTL_AT_BUF2_READ
++#define BCMA_CC_FLASHCTL_AT_STATUS 0x01d7
++#define BCMA_CC_FLASHCTL_AT_BUF1_WRITE 0x0384
++#define BCMA_CC_FLASHCTL_AT_BUF2_WRITE 0x0387
++#define BCMA_CC_FLASHCTL_AT_BUF1_ERASE_PROGRAM 0x0283
++#define BCMA_CC_FLASHCTL_AT_BUF2_ERASE_PROGRAM 0x0286
++#define BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM 0x0288
++#define BCMA_CC_FLASHCTL_AT_BUF2_PROGRAM 0x0289
++#define BCMA_CC_FLASHCTL_AT_PAGE_ERASE 0x0281
++#define BCMA_CC_FLASHCTL_AT_BLOCK_ERASE 0x0250
++#define BCMA_CC_FLASHCTL_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
++#define BCMA_CC_FLASHCTL_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
++#define BCMA_CC_FLASHCTL_AT_BUF1_LOAD 0x0253
++#define BCMA_CC_FLASHCTL_AT_BUF2_LOAD 0x0255
++#define BCMA_CC_FLASHCTL_AT_BUF1_COMPARE 0x0260
++#define BCMA_CC_FLASHCTL_AT_BUF2_COMPARE 0x0261
++#define BCMA_CC_FLASHCTL_AT_BUF1_REPROGRAM 0x0258
++#define BCMA_CC_FLASHCTL_AT_BUF2_REPROGRAM 0x0259
++
+ #define BCMA_CC_FLASHADDR 0x0044
+ #define BCMA_CC_FLASHDATA 0x0048
++
++/* Status register bits for ST flashes */
++#define BCMA_CC_FLASHDATA_ST_WIP 0x01 /* Write In Progress */
++#define BCMA_CC_FLASHDATA_ST_WEL 0x02 /* Write Enable Latch */
++#define BCMA_CC_FLASHDATA_ST_BP_MASK 0x1c /* Block Protect */
++#define BCMA_CC_FLASHDATA_ST_BP_SHIFT 2
++#define BCMA_CC_FLASHDATA_ST_SRWD 0x80 /* Status Register Write Disable */
++
++/* Status register bits for Atmel flashes */
++#define BCMA_CC_FLASHDATA_AT_READY 0x80
++#define BCMA_CC_FLASHDATA_AT_MISMATCH 0x40
++#define BCMA_CC_FLASHDATA_AT_ID_MASK 0x38
++#define BCMA_CC_FLASHDATA_AT_ID_SHIFT 3
++
+ #define BCMA_CC_BCAST_ADDR 0x0050
+ #define BCMA_CC_BCAST_DATA 0x0054
+ #define BCMA_CC_GPIOPULLUP 0x0058 /* Rev >= 20 only */
+@@ -300,6 +358,12 @@
+ #define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4 BIT(16) /* enable bt_shd0 at gpio4 */
+ #define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5 BIT(17) /* enable bt_shd1 at gpio5 */
+
++#define BCMA_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
++#define BCMA_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
++#define BCMA_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
++#define BCMA_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */
++
++
+ /* Data for the PMU, if available.
+ * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+ */
+@@ -309,6 +373,10 @@ struct bcma_chipcommon_pmu {
+ };
+
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
++enum bcma_flash_type {
++ BCMA_PFLASH,
++};
++
+ struct bcma_pflash {
+ u8 buswidth;
+ u32 window;
+@@ -334,7 +402,10 @@ struct bcma_drv_cc {
+ u16 fast_pwrup_delay;
+ struct bcma_chipcommon_pmu pmu;
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+- struct bcma_pflash pflash;
++ enum bcma_flash_type flash_type;
++ union {
++ struct bcma_pflash pflash;
++ };
+
+ int nr_serial_ports;
+ struct bcma_serial_port serial_ports[4];
--- /dev/null
+From a62940e988526c881966a8c72cc28c95fca89f3c Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:53:07 +0200
+Subject: [PATCH 13/26] bcma: add serial flash support to bcma
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/Kconfig | 5 +
+ drivers/bcma/Makefile | 1 +
+ drivers/bcma/bcma_private.h | 5 +
+ drivers/bcma/driver_chipcommon_sflash.c | 555 +++++++++++++++++++++++++++
+ drivers/bcma/driver_mips.c | 8 +-
+ include/linux/bcma/bcma_driver_chipcommon.h | 24 ++
+ 6 files changed, 597 insertions(+), 1 deletions(-)
+ create mode 100644 drivers/bcma/driver_chipcommon_sflash.c
+
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -38,6 +38,11 @@ config BCMA_HOST_SOC
+ bool
+ depends on BCMA_DRIVER_MIPS
+
++config BCMA_SFLASH
++ bool
++ depends on BCMA_DRIVER_MIPS
++ default y
++
+ config BCMA_DRIVER_MIPS
+ bool "BCMA Broadcom MIPS core driver"
+ depends on BCMA && MIPS
+--- a/drivers/bcma/Makefile
++++ b/drivers/bcma/Makefile
+@@ -1,5 +1,6 @@
+ bcma-y += main.o scan.o core.o sprom.o
+ bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
++bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
+ bcma-y += driver_pci.o
+ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
+ bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -41,6 +41,11 @@ void bcma_chipco_serial_init(struct bcma
+ u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
+ u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
+
++#ifdef CONFIG_BCMA_SFLASH
++/* driver_chipcommon_sflash.c */
++int bcma_sflash_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_SFLASH */
++
+ #ifdef CONFIG_BCMA_HOST_PCI
+ /* host_pci.c */
+ extern int __init bcma_host_pci_init(void);
+--- /dev/null
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -0,0 +1,555 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
++ * Copyright 2010, Broadcom Corporation
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_driver_chipcommon.h>
++#include <linux/delay.h>
++
++#include "bcma_private.h"
++
++#define NUM_RETRIES 3
++
++
++/* Issue a serial flash command */
++static inline void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
++{
++ bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
++ BCMA_CC_FLASHCTL_START | opcode);
++ while (bcma_cc_read32(cc, BCMA_CC_FLASHCTL) & BCMA_CC_FLASHCTL_BUSY)
++ ;
++}
++
++
++static inline void bcma_sflash_write_u8(struct bcma_drv_cc *cc,
++ u32 offset, u8 byte)
++{
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
++ bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
++}
++
++/* Initialize serial flash access */
++int bcma_sflash_init(struct bcma_drv_cc *cc)
++{
++ u32 id, id2;
++
++ memset(&cc->sflash, 0, sizeof(struct bcma_sflash));
++
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ /* Probe for ST chips */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP);
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
++ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
++ cc->sflash.blocksize = 64 * 1024;
++ switch (id) {
++ case 0x11:
++ /* ST M25P20 2 Mbit Serial Flash */
++ cc->sflash.numblocks = 4;
++ break;
++ case 0x12:
++ /* ST M25P40 4 Mbit Serial Flash */
++ cc->sflash.numblocks = 8;
++ break;
++ case 0x13:
++ /* ST M25P80 8 Mbit Serial Flash */
++ cc->sflash.numblocks = 16;
++ break;
++ case 0x14:
++ /* ST M25P16 16 Mbit Serial Flash */
++ cc->sflash.numblocks = 32;
++ break;
++ case 0x15:
++ /* ST M25P32 32 Mbit Serial Flash */
++ cc->sflash.numblocks = 64;
++ break;
++ case 0x16:
++ /* ST M25P64 64 Mbit Serial Flash */
++ cc->sflash.numblocks = 128;
++ break;
++ case 0x17:
++ /* ST M25FL128 128 Mbit Serial Flash */
++ cc->sflash.numblocks = 256;
++ break;
++ case 0xbf:
++ /* All of the following flashes are SST with
++ * 4KB subsectors. Others should be added but
++ * We'll have to revamp the way we identify them
++ * since RES is not eough to disambiguate them.
++ */
++ cc->sflash.blocksize = 4 * 1024;
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
++ id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
++ switch (id2) {
++ case 1:
++ /* SST25WF512 512 Kbit Serial Flash */
++ case 0x48:
++ /* SST25VF512 512 Kbit Serial Flash */
++ cc->sflash.numblocks = 16;
++ break;
++ case 2:
++ /* SST25WF010 1 Mbit Serial Flash */
++ case 0x49:
++ /* SST25VF010 1 Mbit Serial Flash */
++ cc->sflash.numblocks = 32;
++ break;
++ case 3:
++ /* SST25WF020 2 Mbit Serial Flash */
++ case 0x43:
++ /* SST25VF020 2 Mbit Serial Flash */
++ cc->sflash.numblocks = 64;
++ break;
++ case 4:
++ /* SST25WF040 4 Mbit Serial Flash */
++ case 0x44:
++ /* SST25VF040 4 Mbit Serial Flash */
++ case 0x8d:
++ /* SST25VF040B 4 Mbit Serial Flash */
++ cc->sflash.numblocks = 128;
++ break;
++ case 5:
++ /* SST25WF080 8 Mbit Serial Flash */
++ case 0x8e:
++ /* SST25VF080B 8 Mbit Serial Flash */
++ cc->sflash.numblocks = 256;
++ break;
++ case 0x41:
++ /* SST25VF016 16 Mbit Serial Flash */
++ cc->sflash.numblocks = 512;
++ break;
++ case 0x4a:
++ /* SST25VF032 32 Mbit Serial Flash */
++ cc->sflash.numblocks = 1024;
++ break;
++ case 0x4b:
++ /* SST25VF064 64 Mbit Serial Flash */
++ cc->sflash.numblocks = 2048;
++ break;
++ }
++ break;
++ }
++ break;
++
++ case BCMA_CC_FLASHT_ATSER:
++ /* Probe for Atmel chips */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
++ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c;
++ switch (id) {
++ case 0xc:
++ /* Atmel AT45DB011 1Mbit Serial Flash */
++ cc->sflash.blocksize = 256;
++ cc->sflash.numblocks = 512;
++ break;
++ case 0x14:
++ /* Atmel AT45DB021 2Mbit Serial Flash */
++ cc->sflash.blocksize = 256;
++ cc->sflash.numblocks = 1024;
++ break;
++ case 0x1c:
++ /* Atmel AT45DB041 4Mbit Serial Flash */
++ cc->sflash.blocksize = 256;
++ cc->sflash.numblocks = 2048;
++ break;
++ case 0x24:
++ /* Atmel AT45DB081 8Mbit Serial Flash */
++ cc->sflash.blocksize = 256;
++ cc->sflash.numblocks = 4096;
++ break;
++ case 0x2c:
++ /* Atmel AT45DB161 16Mbit Serial Flash */
++ cc->sflash.blocksize = 512;
++ cc->sflash.numblocks = 4096;
++ break;
++ case 0x34:
++ /* Atmel AT45DB321 32Mbit Serial Flash */
++ cc->sflash.blocksize = 512;
++ cc->sflash.numblocks = 8192;
++ break;
++ case 0x3c:
++ /* Atmel AT45DB642 64Mbit Serial Flash */
++ cc->sflash.blocksize = 1024;
++ cc->sflash.numblocks = 8192;
++ break;
++ }
++ break;
++ }
++
++ cc->sflash.size = cc->sflash.blocksize * cc->sflash.numblocks;
++
++ return cc->sflash.size ? 0 : -ENODEV;
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ u8 *buf)
++{
++ u8 *from, *to;
++ u32 cnt, i;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > cc->sflash.size)
++ return -EINVAL;
++
++ if ((len >= 4) && (offset & 3))
++ cnt = 4 - (offset & 3);
++ else if ((len >= 4) && ((u32)buf & 3))
++ cnt = 4 - ((u32)buf & 3);
++ else
++ cnt = len;
++
++
++ if (cc->core->id.rev == 12)
++ from = (u8 *)KSEG1ADDR(BCMA_FLASH2 + offset);
++ else
++ from = (u8 *)KSEG0ADDR(BCMA_FLASH2 + offset);
++
++ to = (u8 *)buf;
++
++ if (cnt < 4) {
++ for (i = 0; i < cnt; i++) {
++ *to = readb(from);
++ from++;
++ to++;
++ }
++ return cnt;
++ }
++
++ while (cnt >= 4) {
++ *(u32 *)to = readl(from);
++ from += 4;
++ to += 4;
++ cnt -= 4;
++ }
++
++ return len - cnt;
++}
++
++/* Poll for command completion. Returns zero when complete. */
++int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset)
++{
++ if (offset >= cc->sflash.size)
++ return -22;
++
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ /* Check for ST Write In Progress bit */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RDSR);
++ return bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
++ & BCMA_CC_FLASHDATA_ST_WIP;
++ case BCMA_CC_FLASHT_ATSER:
++ /* Check for Atmel Ready bit */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
++ return !(bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
++ & BCMA_CC_FLASHDATA_AT_READY);
++ }
++
++ return 0;
++}
++
++
++static int sflash_st_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct bcma_bus *bus = cc->core->bus;
++ int ret = 0;
++ bool is4712b0 = (bus->chipinfo.id == 0x4712) && (bus->chipinfo.rev == 3);
++ u32 mask;
++
++
++ /* Enable writes */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
++ if (is4712b0) {
++ mask = 1 << 14;
++ bcma_sflash_write_u8(cc, offset, *buf++);
++ /* Set chip select */
++ bcma_cc_set32(cc, BCMA_CC_GPIOOUT, mask);
++ /* Issue a page program with the first byte */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_PP);
++ ret = 1;
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, drop cs and return */
++ bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
++ udelay(1);
++ if (!bcma_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return ret;
++ } else {
++ /* Write single byte */
++ bcma_sflash_cmd(cc, *buf++);
++ }
++ ret++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs */
++ bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
++ udelay(1);
++ if (!bcma_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ } else if (cc->core->id.rev >= 20) {
++ bcma_sflash_write_u8(cc, offset, *buf++);
++ /* Issue a page program with CSA bit set */
++ bcma_sflash_cmd(cc,
++ BCMA_CC_FLASHCTL_ST_CSA |
++ BCMA_CC_FLASHCTL_ST_PP);
++ ret = 1;
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, poll droping cs and return */
++ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
++ udelay(1);
++ if (!bcma_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return ret;
++ } else {
++ /* Write single byte */
++ bcma_sflash_cmd(cc,
++ BCMA_CC_FLASHCTL_ST_CSA |
++ *buf++);
++ }
++ ret++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs & poll */
++ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
++ udelay(1);
++ if (!bcma_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ } else {
++ ret = 1;
++ bcma_sflash_write_u8(cc, offset, *buf);
++ /* Page program */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_PP);
++ }
++ return ret;
++}
++
++static int sflash_at_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct bcma_sflash *sfl = &cc->sflash;
++ u32 page, byte, mask;
++ int ret = 0;
++ mask = sfl->blocksize - 1;
++ page = (offset & ~mask) << 1;
++ byte = offset & mask;
++ /* Read main memory page into buffer 1 */
++ if (byte || (len < sfl->blocksize)) {
++ int i = 100;
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_LOAD);
++ /* 250 us for AT45DB321B */
++ while (i > 0 && bcma_sflash_poll(cc, offset)) {
++ udelay(10);
++ i--;
++ }
++ BUG_ON(!bcma_sflash_poll(cc, offset));
++ }
++ /* Write into buffer 1 */
++ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
++ bcma_sflash_write_u8(cc, byte++, *buf++);
++ bcma_sflash_cmd(cc,
++ BCMA_CC_FLASHCTL_AT_BUF1_WRITE);
++ }
++ /* Write buffer 1 into main memory page */
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM);
++
++ return ret;
++}
++
++/* Write len bytes starting at offset into buf. Returns number of bytes
++ * written. Caller should poll for completion.
++ */
++int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct bcma_sflash *sfl;
++ int ret = 0, tries = NUM_RETRIES;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > cc->sflash.size)
++ return -EINVAL;
++
++ sfl = &cc->sflash;
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ do {
++ ret = sflash_st_write(cc, offset, len, buf);
++ tries--;
++ } while (ret == -EAGAIN && tries > 0);
++
++ if (ret == -EAGAIN && tries == 0) {
++ pr_info("ST Flash rejected write\n");
++ ret = -EIO;
++ }
++ break;
++ case BCMA_CC_FLASHT_ATSER:
++ ret = sflash_at_write(cc, offset, len, buf);
++ break;
++ }
++
++ return ret;
++}
++
++/* Erase a region. Returns number of bytes scheduled for erasure.
++ * Caller should poll for completion.
++ */
++int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset)
++{
++ struct bcma_sflash *sfl;
++
++ if (offset >= cc->sflash.size)
++ return -EINVAL;
++
++ sfl = &cc->sflash;
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
++ /* Newer flashes have "sub-sectors" which can be erased independently
++ * with a new command: ST_SSE. The ST_SE command erases 64KB just as
++ * before.
++ */
++ bcma_sflash_cmd(cc, (sfl->blocksize < (64 * 1024)) ? BCMA_CC_FLASHCTL_ST_SSE : BCMA_CC_FLASHCTL_ST_SE);
++ return sfl->blocksize;
++ case BCMA_CC_FLASHT_ATSER:
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset << 1);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_PAGE_ERASE);
++ return sfl->blocksize;
++ }
++
++ return 0;
++}
++
++/*
++ * writes the appropriate range of flash, a NULL buf simply erases
++ * the region of flash
++ */
++int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct bcma_sflash *sfl;
++ u8 *block = NULL, *cur_ptr, *blk_ptr;
++ u32 blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
++ u32 blk_offset, blk_len, copied;
++ int bytes, ret = 0;
++
++ /* Check address range */
++ if (len <= 0)
++ return 0;
++
++ sfl = &cc->sflash;
++ if ((offset + len) > sfl->size)
++ return -EINVAL;
++
++ blocksize = sfl->blocksize;
++ mask = blocksize - 1;
++
++ /* Allocate a block of mem */
++ block = kmalloc(blocksize, GFP_KERNEL);
++ if (!block)
++ return -ENOMEM;
++
++ while (len) {
++ /* Align offset */
++ cur_offset = offset & ~mask;
++ cur_length = blocksize;
++ cur_ptr = block;
++
++ remainder = blocksize - (offset & mask);
++ if (len < remainder)
++ cur_retlen = len;
++ else
++ cur_retlen = remainder;
++
++ /* buf == NULL means erase only */
++ if (buf) {
++ /* Copy existing data into holding block if necessary */
++ if ((offset & mask) || (len < blocksize)) {
++ blk_offset = cur_offset;
++ blk_len = cur_length;
++ blk_ptr = cur_ptr;
++
++ /* Copy entire block */
++ while (blk_len) {
++ copied = bcma_sflash_read(cc,
++ blk_offset,
++ blk_len, blk_ptr);
++ blk_offset += copied;
++ blk_len -= copied;
++ blk_ptr += copied;
++ }
++ }
++
++ /* Copy input data into holding block */
++ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
++ }
++
++ /* Erase block */
++ ret = bcma_sflash_erase(cc, cur_offset);
++ if (ret < 0)
++ goto done;
++
++ while (bcma_sflash_poll(cc, cur_offset));
++
++ /* buf == NULL means erase only */
++ if (!buf) {
++ offset += cur_retlen;
++ len -= cur_retlen;
++ continue;
++ }
++
++ /* Write holding block */
++ while (cur_length > 0) {
++ bytes = bcma_sflash_write(cc, cur_offset,
++ cur_length, cur_ptr);
++
++ if (bytes < 0) {
++ ret = bytes;
++ goto done;
++ }
++
++ while (bcma_sflash_poll(cc, cur_offset))
++ ;
++
++ cur_offset += bytes;
++ cur_length -= bytes;
++ cur_ptr += bytes;
++ }
++
++ offset += cur_retlen;
++ len -= cur_retlen;
++ buf += cur_retlen;
++ }
++
++ ret = len;
++done:
++ kfree(block);
++ return ret;
++}
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -185,7 +185,13 @@ static void bcma_core_mips_flash_detect(
+ switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
+ case BCMA_CC_FLASHT_STSER:
+ case BCMA_CC_FLASHT_ATSER:
+- pr_err("Serial flash not supported.\n");
++#ifdef CONFIG_BCMA_SFLASH
++ pr_info("found serial flash.\n");
++ bus->drv_cc.flash_type = BCMA_SFLASH;
++ bcma_sflash_init(&bus->drv_cc);
++#else
++ pr_info("serial flash not supported.\n");
++#endif /* CONFIG_BCMA_SFLASH */
+ break;
+ case BCMA_CC_FLASHT_PARA:
+ pr_info("found parallel flash.\n");
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -375,6 +375,7 @@ struct bcma_chipcommon_pmu {
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ enum bcma_flash_type {
+ BCMA_PFLASH,
++ BCMA_SFLASH,
+ };
+
+ struct bcma_pflash {
+@@ -383,6 +384,14 @@ struct bcma_pflash {
+ u32 window_size;
+ };
+
++#ifdef CONFIG_BCMA_SFLASH
++struct bcma_sflash {
++ u32 blocksize; /* Block size */
++ u32 numblocks; /* Number of blocks */
++ u32 size; /* Total size in bytes */
++};
++#endif /* CONFIG_BCMA_SFLASH */
++
+ struct bcma_serial_port {
+ void *regs;
+ unsigned long clockspeed;
+@@ -405,6 +414,9 @@ struct bcma_drv_cc {
+ enum bcma_flash_type flash_type;
+ union {
+ struct bcma_pflash pflash;
++#ifdef CONFIG_BCMA_SFLASH
++ struct bcma_sflash sflash;
++#endif /* CONFIG_BCMA_SFLASH */
+ };
+
+ int nr_serial_ports;
+@@ -459,4 +471,16 @@ extern void bcma_chipco_chipctl_maskset(
+ extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
+ u32 offset, u32 mask, u32 set);
+
++#ifdef CONFIG_BCMA_SFLASH
++/* Chipcommon sflash support. */
++int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ u8 *buf);
++int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset);
++int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf);
++int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset);
++int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf);
++#endif /* CONFIG_BCMA_SFLASH */
++
+ #endif /* LINUX_BCMA_DRIVER_CC_H_ */
--- /dev/null
+From e8afde87ecf56beff67c7d5371cabaa4fc018541 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 23 Jul 2011 23:57:06 +0200
+Subject: [PATCH 14/26] ssb: move flash to chipcommon
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/nvram.c | 8 +++---
+ arch/mips/bcm47xx/wgt634u.c | 8 +++---
+ drivers/ssb/driver_mipscore.c | 36 +++++++++++++++++++++-------
+ include/linux/ssb/ssb_driver_chipcommon.h | 18 ++++++++++++++
+ include/linux/ssb/ssb_driver_mips.h | 4 ---
+ 5 files changed, 53 insertions(+), 21 deletions(-)
+
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -27,7 +27,7 @@ static char nvram_buf[NVRAM_SPACE];
+ static void early_nvram_init(void)
+ {
+ #ifdef CONFIG_BCM47XX_SSB
+- struct ssb_mipscore *mcore_ssb;
++ struct ssb_chipcommon *ssb_cc;
+ #endif
+ #ifdef CONFIG_BCM47XX_BCMA
+ struct bcma_drv_cc *bcma_cc;
+@@ -42,9 +42,9 @@ static void early_nvram_init(void)
+ switch (bcm47xx_bus_type) {
+ #ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+- mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+- base = mcore_ssb->flash_window;
+- lim = mcore_ssb->flash_window_size;
++ ssb_cc = &bcm47xx_bus.ssb.chipco;
++ base = ssb_cc->pflash.window;
++ lim = ssb_cc->pflash.window_size;
+ break;
+ #endif
+ #ifdef CONFIG_BCM47XX_BCMA
+--- a/arch/mips/bcm47xx/wgt634u.c
++++ b/arch/mips/bcm47xx/wgt634u.c
+@@ -156,10 +156,10 @@ static int __init wgt634u_init(void)
+ SSB_CHIPCO_IRQ_GPIO);
+ }
+
+- wgt634u_flash_data.width = mcore->flash_buswidth;
+- wgt634u_flash_resource.start = mcore->flash_window;
+- wgt634u_flash_resource.end = mcore->flash_window
+- + mcore->flash_window_size
++ wgt634u_flash_data.width = mcore->pflash.buswidth;
++ wgt634u_flash_resource.start = mcore->pflash.window;
++ wgt634u_flash_resource.end = mcore->pflash.window
++ + mcore->pflash.window_size
+ - 1;
+ return platform_add_devices(wgt634u_devices,
+ ARRAY_SIZE(wgt634u_devices));
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -190,16 +190,34 @@ static void ssb_mips_flash_detect(struct
+ {
+ struct ssb_bus *bus = mcore->dev->bus;
+
+- mcore->flash_buswidth = 2;
+- if (bus->chipco.dev) {
+- mcore->flash_window = 0x1c000000;
+- mcore->flash_window_size = 0x02000000;
++ /* When there is no chipcommon on the bus there is 4MB flash */
++ if (!bus->chipco.dev) {
++ pr_info("found parallel flash.\n");
++ bus->chipco.flash_type = SSB_PFLASH;
++ bus->chipco.pflash.window = SSB_FLASH1;
++ bus->chipco.pflash.window_size = SSB_FLASH1_SZ;
++ bus->chipco.pflash.buswidth = 2;
++ return;
++ }
++
++ switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ case SSB_CHIPCO_FLASHT_ATSER:
++ pr_info("serial flash not supported.\n");
++ break;
++ case SSB_CHIPCO_FLASHT_PARA:
++ pr_info("found parallel flash.\n");
++ bus->chipco.flash_type = SSB_PFLASH;
++ bus->chipco.pflash.window = SSB_FLASH2;
++ bus->chipco.pflash.window_size = SSB_FLASH2_SZ;
+ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
+- & SSB_CHIPCO_CFG_DS16) == 0)
+- mcore->flash_buswidth = 1;
+- } else {
+- mcore->flash_window = 0x1fc00000;
+- mcore->flash_window_size = 0x00400000;
++ & SSB_CHIPCO_CFG_DS16) == 0)
++ bus->chipco.pflash.buswidth = 1;
++ else
++ bus->chipco.pflash.buswidth = 2;
++ break;
++ default:
++ pr_err("flash not supported.\n");
+ }
+ }
+
+--- a/include/linux/ssb/ssb_driver_chipcommon.h
++++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -582,6 +582,18 @@ struct ssb_chipcommon_pmu {
+ u32 crystalfreq; /* The active crystal frequency (in kHz) */
+ };
+
++#ifdef CONFIG_SSB_DRIVER_MIPS
++enum ssb_flash_type {
++ SSB_PFLASH,
++};
++
++struct ssb_pflash {
++ u8 buswidth;
++ u32 window;
++ u32 window_size;
++};
++#endif /* CONFIG_SSB_DRIVER_MIPS */
++
+ struct ssb_chipcommon {
+ struct ssb_device *dev;
+ u32 capabilities;
+@@ -589,6 +601,12 @@ struct ssb_chipcommon {
+ /* Fast Powerup Delay constant */
+ u16 fast_pwrup_delay;
+ struct ssb_chipcommon_pmu pmu;
++#ifdef CONFIG_SSB_DRIVER_MIPS
++ enum ssb_flash_type flash_type;
++ union {
++ struct ssb_pflash pflash;
++ };
++#endif /* CONFIG_SSB_DRIVER_MIPS */
+ };
+
+ static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)
+--- a/include/linux/ssb/ssb_driver_mips.h
++++ b/include/linux/ssb/ssb_driver_mips.h
+@@ -19,10 +19,6 @@ struct ssb_mipscore {
+
+ int nr_serial_ports;
+ struct ssb_serial_port serial_ports[4];
+-
+- u8 flash_buswidth;
+- u32 flash_window;
+- u32 flash_window_size;
+ };
+
+ extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
--- /dev/null
+From 980da78179592a3f5f99168bc5af415835aa8c13 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 24 Jul 2011 20:20:36 +0200
+Subject: [PATCH 15/26] ssb: add serial flash support
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/ssb/Kconfig | 6 +
+ drivers/ssb/Makefile | 1 +
+ drivers/ssb/driver_chipcommon_sflash.c | 556 +++++++++++++++++++++++++++++
+ drivers/ssb/driver_mipscore.c | 6 +
+ drivers/ssb/ssb_private.h | 4 +
+ include/linux/ssb/ssb_driver_chipcommon.h | 30 ++-
+ 6 files changed, 601 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/ssb/driver_chipcommon_sflash.c
+
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -137,6 +137,12 @@ config SSB_DRIVER_MIPS
+
+ If unsure, say N
+
++config SSB_SFLASH
++ bool
++ depends on SSB_DRIVER_MIPS
++ default y
++
++
+ # Assumption: We are on embedded, if we compile the MIPS core.
+ config SSB_EMBEDDED
+ bool
+--- a/drivers/ssb/Makefile
++++ b/drivers/ssb/Makefile
+@@ -11,6 +11,7 @@ ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o
+ # built-in drivers
+ ssb-y += driver_chipcommon.o
+ ssb-y += driver_chipcommon_pmu.o
++ssb-$(CONFIG_SSB_SFLASH) += driver_chipcommon_sflash.o
+ ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
+ ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
+ ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
+--- /dev/null
++++ b/drivers/ssb/driver_chipcommon_sflash.c
+@@ -0,0 +1,556 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
++ * Copyright 2010, Broadcom Corporation
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/ssb/ssb.h>
++#include <linux/ssb/ssb_driver_chipcommon.h>
++#include <linux/delay.h>
++
++#include "ssb_private.h"
++
++#define NUM_RETRIES 3
++
++
++/* Issue a serial flash command */
++static inline void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
++{
++ chipco_write32(cc, SSB_CHIPCO_FLASHCTL,
++ SSB_CHIPCO_FLASHCTL_START | opcode);
++ while (chipco_read32(cc, SSB_CHIPCO_FLASHCTL)
++ & SSB_CHIPCO_FLASHCTL_BUSY)
++ ;
++}
++
++
++static inline void ssb_sflash_write_u8(struct ssb_chipcommon *cc,
++ u32 offset, u8 byte)
++{
++ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, offset);
++ chipco_write32(cc, SSB_CHIPCO_FLASHDATA, byte);
++}
++
++/* Initialize serial flash access */
++int ssb_sflash_init(struct ssb_chipcommon *cc)
++{
++ u32 id, id2;
++
++ memset(&cc->sflash, 0, sizeof(struct ssb_sflash));
++
++ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ /* Probe for ST chips */
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_DP);
++ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 0);
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
++ id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
++ cc->sflash.blocksize = 64 * 1024;
++ switch (id) {
++ case 0x11:
++ /* ST M25P20 2 Mbit Serial Flash */
++ cc->sflash.numblocks = 4;
++ break;
++ case 0x12:
++ /* ST M25P40 4 Mbit Serial Flash */
++ cc->sflash.numblocks = 8;
++ break;
++ case 0x13:
++ /* ST M25P80 8 Mbit Serial Flash */
++ cc->sflash.numblocks = 16;
++ break;
++ case 0x14:
++ /* ST M25P16 16 Mbit Serial Flash */
++ cc->sflash.numblocks = 32;
++ break;
++ case 0x15:
++ /* ST M25P32 32 Mbit Serial Flash */
++ cc->sflash.numblocks = 64;
++ break;
++ case 0x16:
++ /* ST M25P64 64 Mbit Serial Flash */
++ cc->sflash.numblocks = 128;
++ break;
++ case 0x17:
++ /* ST M25FL128 128 Mbit Serial Flash */
++ cc->sflash.numblocks = 256;
++ break;
++ case 0xbf:
++ /* All of the following flashes are SST with
++ * 4KB subsectors. Others should be added but
++ * We'll have to revamp the way we identify them
++ * since RES is not eough to disambiguate them.
++ */
++ cc->sflash.blocksize = 4 * 1024;
++ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 1);
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
++ id2 = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
++ switch (id2) {
++ case 1:
++ /* SST25WF512 512 Kbit Serial Flash */
++ case 0x48:
++ /* SST25VF512 512 Kbit Serial Flash */
++ cc->sflash.numblocks = 16;
++ break;
++ case 2:
++ /* SST25WF010 1 Mbit Serial Flash */
++ case 0x49:
++ /* SST25VF010 1 Mbit Serial Flash */
++ cc->sflash.numblocks = 32;
++ break;
++ case 3:
++ /* SST25WF020 2 Mbit Serial Flash */
++ case 0x43:
++ /* SST25VF020 2 Mbit Serial Flash */
++ cc->sflash.numblocks = 64;
++ break;
++ case 4:
++ /* SST25WF040 4 Mbit Serial Flash */
++ case 0x44:
++ /* SST25VF040 4 Mbit Serial Flash */
++ case 0x8d:
++ /* SST25VF040B 4 Mbit Serial Flash */
++ cc->sflash.numblocks = 128;
++ break;
++ case 5:
++ /* SST25WF080 8 Mbit Serial Flash */
++ case 0x8e:
++ /* SST25VF080B 8 Mbit Serial Flash */
++ cc->sflash.numblocks = 256;
++ break;
++ case 0x41:
++ /* SST25VF016 16 Mbit Serial Flash */
++ cc->sflash.numblocks = 512;
++ break;
++ case 0x4a:
++ /* SST25VF032 32 Mbit Serial Flash */
++ cc->sflash.numblocks = 1024;
++ break;
++ case 0x4b:
++ /* SST25VF064 64 Mbit Serial Flash */
++ cc->sflash.numblocks = 2048;
++ break;
++ }
++ break;
++ }
++ break;
++
++ case SSB_CHIPCO_FLASHT_ATSER:
++ /* Probe for Atmel chips */
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
++ id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA) & 0x3c;
++ switch (id) {
++ case 0xc:
++ /* Atmel AT45DB011 1Mbit Serial Flash */
++ cc->sflash.blocksize = 256;
++ cc->sflash.numblocks = 512;
++ break;
++ case 0x14:
++ /* Atmel AT45DB021 2Mbit Serial Flash */
++ cc->sflash.blocksize = 256;
++ cc->sflash.numblocks = 1024;
++ break;
++ case 0x1c:
++ /* Atmel AT45DB041 4Mbit Serial Flash */
++ cc->sflash.blocksize = 256;
++ cc->sflash.numblocks = 2048;
++ break;
++ case 0x24:
++ /* Atmel AT45DB081 8Mbit Serial Flash */
++ cc->sflash.blocksize = 256;
++ cc->sflash.numblocks = 4096;
++ break;
++ case 0x2c:
++ /* Atmel AT45DB161 16Mbit Serial Flash */
++ cc->sflash.blocksize = 512;
++ cc->sflash.numblocks = 4096;
++ break;
++ case 0x34:
++ /* Atmel AT45DB321 32Mbit Serial Flash */
++ cc->sflash.blocksize = 512;
++ cc->sflash.numblocks = 8192;
++ break;
++ case 0x3c:
++ /* Atmel AT45DB642 64Mbit Serial Flash */
++ cc->sflash.blocksize = 1024;
++ cc->sflash.numblocks = 8192;
++ break;
++ }
++ break;
++ }
++
++ cc->sflash.size = cc->sflash.blocksize * cc->sflash.numblocks;
++
++ return cc->sflash.size ? 0 : -ENODEV;
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++int ssb_sflash_read(struct ssb_chipcommon *cc, u32 offset, u32 len,
++ u8 *buf)
++{
++ u8 *from, *to;
++ u32 cnt, i;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > cc->sflash.size)
++ return -EINVAL;
++
++ if ((len >= 4) && (offset & 3))
++ cnt = 4 - (offset & 3);
++ else if ((len >= 4) && ((u32)buf & 3))
++ cnt = 4 - ((u32)buf & 3);
++ else
++ cnt = len;
++
++
++ if (cc->dev->id.revision == 12)
++ from = (u8 *)KSEG1ADDR(SSB_FLASH2 + offset);
++ else
++ from = (u8 *)KSEG0ADDR(SSB_FLASH2 + offset);
++
++ to = (u8 *)buf;
++
++ if (cnt < 4) {
++ for (i = 0; i < cnt; i++) {
++ *to = readb(from);
++ from++;
++ to++;
++ }
++ return cnt;
++ }
++
++ while (cnt >= 4) {
++ *(u32 *)to = readl(from);
++ from += 4;
++ to += 4;
++ cnt -= 4;
++ }
++
++ return len - cnt;
++}
++
++/* Poll for command completion. Returns zero when complete. */
++int ssb_sflash_poll(struct ssb_chipcommon *cc, u32 offset)
++{
++ if (offset >= cc->sflash.size)
++ return -22;
++
++ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ /* Check for ST Write In Progress bit */
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RDSR);
++ return chipco_read32(cc, SSB_CHIPCO_FLASHDATA)
++ & SSB_CHIPCO_FLASHSTA_ST_WIP;
++ case SSB_CHIPCO_FLASHT_ATSER:
++ /* Check for Atmel Ready bit */
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
++ return !(chipco_read32(cc, SSB_CHIPCO_FLASHDATA)
++ & SSB_CHIPCO_FLASHSTA_AT_READY);
++ }
++
++ return 0;
++}
++
++
++static int sflash_st_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct ssb_bus *bus = cc->dev->bus;
++ int ret = 0;
++ bool is4712b0 = (bus->chip_id == 0x4712) && (bus->chip_rev == 3);
++ u32 mask;
++
++
++ /* Enable writes */
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_WREN);
++ if (is4712b0) {
++ mask = 1 << 14;
++ ssb_sflash_write_u8(cc, offset, *buf++);
++ /* Set chip select */
++ chipco_set32(cc, SSB_CHIPCO_GPIOOUT, mask);
++ /* Issue a page program with the first byte */
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_PP);
++ ret = 1;
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, drop cs and return */
++ chipco_mask32(cc, SSB_CHIPCO_GPIOOUT, ~mask);
++ udelay(1);
++ if (!ssb_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return ret;
++ } else {
++ /* Write single byte */
++ ssb_sflash_cmd(cc, *buf++);
++ }
++ ret++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs */
++ chipco_mask32(cc, SSB_CHIPCO_GPIOOUT, ~mask);
++ udelay(1);
++ if (!ssb_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ } else if (cc->dev->id.revision >= 20) {
++ ssb_sflash_write_u8(cc, offset, *buf++);
++ /* Issue a page program with CSA bit set */
++ ssb_sflash_cmd(cc,
++ SSB_CHIPCO_FLASHCTL_ST_CSA |
++ SSB_CHIPCO_FLASHCTL_ST_PP);
++ ret = 1;
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, poll droping cs and return */
++ chipco_write32(cc, SSB_CHIPCO_FLASHCTL, 0);
++ udelay(1);
++ if (!ssb_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return ret;
++ } else {
++ /* Write single byte */
++ ssb_sflash_cmd(cc,
++ SSB_CHIPCO_FLASHCTL_ST_CSA |
++ *buf++);
++ }
++ ret++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs & poll */
++ chipco_write32(cc, SSB_CHIPCO_FLASHCTL, 0);
++ udelay(1);
++ if (!ssb_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ } else {
++ ret = 1;
++ ssb_sflash_write_u8(cc, offset, *buf);
++ /* Page program */
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_PP);
++ }
++ return ret;
++}
++
++static int sflash_at_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct ssb_sflash *sfl = &cc->sflash;
++ u32 page, byte, mask;
++ int ret = 0;
++ mask = sfl->blocksize - 1;
++ page = (offset & ~mask) << 1;
++ byte = offset & mask;
++ /* Read main memory page into buffer 1 */
++ if (byte || (len < sfl->blocksize)) {
++ int i = 100;
++ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, page);
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD);
++ /* 250 us for AT45DB321B */
++ while (i > 0 && ssb_sflash_poll(cc, offset)) {
++ udelay(10);
++ i--;
++ }
++ BUG_ON(!ssb_sflash_poll(cc, offset));
++ }
++ /* Write into buffer 1 */
++ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
++ ssb_sflash_write_u8(cc, byte++, *buf++);
++ ssb_sflash_cmd(cc,
++ SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE);
++ }
++ /* Write buffer 1 into main memory page */
++ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, page);
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_BUF1_PROGRAM);
++
++ return ret;
++}
++
++/* Write len bytes starting at offset into buf. Returns number of bytes
++ * written. Caller should poll for completion.
++ */
++int ssb_sflash_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct ssb_sflash *sfl;
++ int ret = 0, tries = NUM_RETRIES;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > cc->sflash.size)
++ return -EINVAL;
++
++ sfl = &cc->sflash;
++ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ do {
++ ret = sflash_st_write(cc, offset, len, buf);
++ tries--;
++ } while (ret == -EAGAIN && tries > 0);
++
++ if (ret == -EAGAIN && tries == 0) {
++ pr_info("ST Flash rejected write\n");
++ ret = -EIO;
++ }
++ break;
++ case SSB_CHIPCO_FLASHT_ATSER:
++ ret = sflash_at_write(cc, offset, len, buf);
++ break;
++ }
++
++ return ret;
++}
++
++/* Erase a region. Returns number of bytes scheduled for erasure.
++ * Caller should poll for completion.
++ */
++int ssb_sflash_erase(struct ssb_chipcommon *cc, u32 offset)
++{
++ struct ssb_sflash *sfl;
++
++ if (offset >= cc->sflash.size)
++ return -EINVAL;
++
++ sfl = &cc->sflash;
++ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_WREN);
++ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, offset);
++ /* Newer flashes have "sub-sectors" which can be erased independently
++ * with a new command: ST_SSE. The ST_SE command erases 64KB just as
++ * before.
++ */
++ ssb_sflash_cmd(cc, (sfl->blocksize < (64 * 1024)) ? SSB_CHIPCO_FLASHCTL_ST_SSE : SSB_CHIPCO_FLASHCTL_ST_SE);
++ return sfl->blocksize;
++ case SSB_CHIPCO_FLASHT_ATSER:
++ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, offset << 1);
++ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE);
++ return sfl->blocksize;
++ }
++
++ return 0;
++}
++
++/*
++ * writes the appropriate range of flash, a NULL buf simply erases
++ * the region of flash
++ */
++int ssb_sflash_commit(struct ssb_chipcommon *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct ssb_sflash *sfl;
++ u8 *block = NULL, *cur_ptr, *blk_ptr;
++ u32 blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
++ u32 blk_offset, blk_len, copied;
++ int bytes, ret = 0;
++
++ /* Check address range */
++ if (len <= 0)
++ return 0;
++
++ sfl = &cc->sflash;
++ if ((offset + len) > sfl->size)
++ return -EINVAL;
++
++ blocksize = sfl->blocksize;
++ mask = blocksize - 1;
++
++ /* Allocate a block of mem */
++ block = kmalloc(blocksize, GFP_KERNEL);
++ if (!block)
++ return -ENOMEM;
++
++ while (len) {
++ /* Align offset */
++ cur_offset = offset & ~mask;
++ cur_length = blocksize;
++ cur_ptr = block;
++
++ remainder = blocksize - (offset & mask);
++ if (len < remainder)
++ cur_retlen = len;
++ else
++ cur_retlen = remainder;
++
++ /* buf == NULL means erase only */
++ if (buf) {
++ /* Copy existing data into holding block if necessary */
++ if ((offset & mask) || (len < blocksize)) {
++ blk_offset = cur_offset;
++ blk_len = cur_length;
++ blk_ptr = cur_ptr;
++
++ /* Copy entire block */
++ while (blk_len) {
++ copied = ssb_sflash_read(cc,
++ blk_offset,
++ blk_len, blk_ptr);
++ blk_offset += copied;
++ blk_len -= copied;
++ blk_ptr += copied;
++ }
++ }
++
++ /* Copy input data into holding block */
++ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
++ }
++
++ /* Erase block */
++ ret = ssb_sflash_erase(cc, cur_offset);
++ if (ret < 0)
++ goto done;
++
++ while (ssb_sflash_poll(cc, cur_offset));
++
++ /* buf == NULL means erase only */
++ if (!buf) {
++ offset += cur_retlen;
++ len -= cur_retlen;
++ continue;
++ }
++
++ /* Write holding block */
++ while (cur_length > 0) {
++ bytes = ssb_sflash_write(cc, cur_offset,
++ cur_length, cur_ptr);
++
++ if (bytes < 0) {
++ ret = bytes;
++ goto done;
++ }
++
++ while (ssb_sflash_poll(cc, cur_offset))
++ ;
++
++ cur_offset += bytes;
++ cur_length -= bytes;
++ cur_ptr += bytes;
++ }
++
++ offset += cur_retlen;
++ len -= cur_retlen;
++ buf += cur_retlen;
++ }
++
++ ret = len;
++done:
++ kfree(block);
++ return ret;
++}
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -203,7 +203,13 @@ static void ssb_mips_flash_detect(struct
+ switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
+ case SSB_CHIPCO_FLASHT_STSER:
+ case SSB_CHIPCO_FLASHT_ATSER:
++#ifdef CONFIG_SSB_SFLASH
++ pr_info("found serial flash.\n");
++ bus->chipco.flash_type = SSB_SFLASH;
++ ssb_sflash_init(&bus->chipco);
++#else
+ pr_info("serial flash not supported.\n");
++#endif /* CONFIG_SSB_SFLASH */
+ break;
+ case SSB_CHIPCO_FLASHT_PARA:
+ pr_info("found parallel flash.\n");
+--- a/drivers/ssb/ssb_private.h
++++ b/drivers/ssb/ssb_private.h
+@@ -192,6 +192,10 @@ extern int ssb_devices_freeze(struct ssb
+ extern int ssb_devices_thaw(struct ssb_freeze_context *ctx);
+
+
++#ifdef CONFIG_SSB_SFLASH
++/* driver_chipcommon_sflash.c */
++int ssb_sflash_init(struct ssb_chipcommon *cc);
++#endif /* CONFIG_SSB_SFLASH */
+
+ /* b43_pci_bridge.c */
+ #ifdef CONFIG_SSB_B43_PCI_BRIDGE
+--- a/include/linux/ssb/ssb_driver_chipcommon.h
++++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -503,8 +503,10 @@
+ #define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */
+ #define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
+ #define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
+-#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
+-#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */
++#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00D9 /* Deep Power-down */
++#define SSB_CHIPCO_FLASHCTL_ST_RES 0x03AB /* Read Electronic Signature */
++#define SSB_CHIPCO_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
++#define SSB_CHIPCO_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
+
+ /* Status register bits for ST flashes */
+ #define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */
+@@ -585,6 +587,7 @@ struct ssb_chipcommon_pmu {
+ #ifdef CONFIG_SSB_DRIVER_MIPS
+ enum ssb_flash_type {
+ SSB_PFLASH,
++ SSB_SFLASH,
+ };
+
+ struct ssb_pflash {
+@@ -592,6 +595,14 @@ struct ssb_pflash {
+ u32 window;
+ u32 window_size;
+ };
++
++#ifdef CONFIG_SSB_SFLASH
++struct ssb_sflash {
++ u32 blocksize; /* Block size */
++ u32 numblocks; /* Number of blocks */
++ u32 size; /* Total size in bytes */
++};
++#endif /* CONFIG_SSB_SFLASH */
+ #endif /* CONFIG_SSB_DRIVER_MIPS */
+
+ struct ssb_chipcommon {
+@@ -605,6 +616,9 @@ struct ssb_chipcommon {
+ enum ssb_flash_type flash_type;
+ union {
+ struct ssb_pflash pflash;
++#ifdef CONFIG_SSB_SFLASH
++ struct ssb_sflash sflash;
++#endif /* CONFIG_SSB_SFLASH */
+ };
+ #endif /* CONFIG_SSB_DRIVER_MIPS */
+ };
+@@ -666,6 +680,18 @@ extern int ssb_chipco_serial_init(struct
+ struct ssb_serial_port *ports);
+ #endif /* CONFIG_SSB_SERIAL */
+
++#ifdef CONFIG_SSB_SFLASH
++/* Chipcommon sflash support. */
++int ssb_sflash_read(struct ssb_chipcommon *cc, u32 offset, u32 len,
++ u8 *buf);
++int ssb_sflash_poll(struct ssb_chipcommon *cc, u32 offset);
++int ssb_sflash_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
++ const u8 *buf);
++int ssb_sflash_erase(struct ssb_chipcommon *cc, u32 offset);
++int ssb_sflash_commit(struct ssb_chipcommon *cc, u32 offset, u32 len,
++ const u8 *buf);
++#endif /* CONFIG_SSB_SFLASH */
++
+ /* PMU support */
+ extern void ssb_pmu_init(struct ssb_chipcommon *cc);
+
--- /dev/null
+From 4f314ac9edbc80897f158fdb4e1b1de8a2d0d432 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 24 Jul 2011 21:10:49 +0200
+Subject: [PATCH 16/26] brcm47xx: add common interface for sflash
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/Makefile | 2 +-
+ arch/mips/bcm47xx/bus.c | 94 ++++++++++++++++++++++++++++++
+ arch/mips/bcm47xx/setup.c | 8 +++
+ arch/mips/include/asm/mach-bcm47xx/bus.h | 37 ++++++++++++
+ 4 files changed, 140 insertions(+), 1 deletions(-)
+ create mode 100644 arch/mips/bcm47xx/bus.c
+ create mode 100644 arch/mips/include/asm/mach-bcm47xx/bus.h
+
+--- a/arch/mips/bcm47xx/Makefile
++++ b/arch/mips/bcm47xx/Makefile
+@@ -3,5 +3,5 @@
+ # under Linux.
+ #
+
+-obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
++obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o bus.o
+ obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
+--- /dev/null
++++ b/arch/mips/bcm47xx/bus.c
+@@ -0,0 +1,94 @@
++/*
++ * BCM947xx nvram variable access
++ *
++ * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <bus.h>
++
++static int bcm47xx_sflash_bcma_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
++{
++ return bcma_sflash_read(dev->bcc, offset, len, buf);
++}
++
++static int bcm47xx_sflash_bcma_poll(struct bcm47xx_sflash *dev, u32 offset)
++{
++ return bcma_sflash_poll(dev->bcc, offset);
++}
++
++static int bcm47xx_sflash_bcma_write(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
++{
++ return bcma_sflash_write(dev->bcc, offset, len, buf);
++}
++
++static int bcm47xx_sflash_bcma_erase(struct bcm47xx_sflash *dev, u32 offset)
++{
++ return bcma_sflash_erase(dev->bcc, offset);
++}
++
++static int bcm47xx_sflash_bcma_commit(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
++{
++ return bcma_sflash_commit(dev->bcc, offset, len, buf);
++}
++
++void bcm47xx_sflash_struct_bcma_init(struct bcm47xx_sflash *sflash, struct bcma_drv_cc *bcc)
++{
++ sflash->sflash_type = BCM47XX_BUS_TYPE_BCMA;
++ sflash->bcc = bcc;
++
++ sflash->read = bcm47xx_sflash_bcma_read;
++ sflash->poll = bcm47xx_sflash_bcma_poll;
++ sflash->write = bcm47xx_sflash_bcma_write;
++ sflash->erase = bcm47xx_sflash_bcma_erase;
++ sflash->commit = bcm47xx_sflash_bcma_commit;
++
++ sflash->blocksize = bcc->sflash.blocksize;
++ sflash->numblocks = bcc->sflash.numblocks;
++ sflash->size = bcc->sflash.size;
++}
++
++static int bcm47xx_sflash_ssb_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
++{
++ return ssb_sflash_read(dev->scc, offset, len, buf);
++}
++
++static int bcm47xx_sflash_ssb_poll(struct bcm47xx_sflash *dev, u32 offset)
++{
++ return ssb_sflash_poll(dev->scc, offset);
++}
++
++static int bcm47xx_sflash_ssb_write(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
++{
++ return ssb_sflash_write(dev->scc, offset, len, buf);
++}
++
++static int bcm47xx_sflash_ssb_erase(struct bcm47xx_sflash *dev, u32 offset)
++{
++ return ssb_sflash_erase(dev->scc, offset);
++}
++
++static int bcm47xx_sflash_ssb_commit(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
++{
++ return ssb_sflash_commit(dev->scc, offset, len, buf);
++}
++
++void bcm47xx_sflash_struct_ssb_init(struct bcm47xx_sflash *sflash, struct ssb_chipcommon *scc)
++{
++ sflash->sflash_type = BCM47XX_BUS_TYPE_SSB;
++ sflash->scc = scc;
++
++ sflash->read = bcm47xx_sflash_ssb_read;
++ sflash->poll = bcm47xx_sflash_ssb_poll;
++ sflash->write = bcm47xx_sflash_ssb_write;
++ sflash->erase = bcm47xx_sflash_ssb_erase;
++ sflash->commit = bcm47xx_sflash_ssb_commit;
++
++ sflash->blocksize = scc->sflash.blocksize;
++ sflash->numblocks = scc->sflash.numblocks;
++ sflash->size = scc->sflash.size;
++}
+--- a/arch/mips/bcm47xx/setup.c
++++ b/arch/mips/bcm47xx/setup.c
+@@ -43,6 +43,8 @@ EXPORT_SYMBOL(bcm47xx_bus);
+ enum bcm47xx_bus_type bcm47xx_bus_type;
+ EXPORT_SYMBOL(bcm47xx_bus_type);
+
++struct bcm47xx_sflash bcm47xx_sflash;
++
+ static void bcm47xx_machine_restart(char *command)
+ {
+ printk(KERN_ALERT "Please stand by while rebooting the system...\n");
+@@ -291,6 +293,9 @@ static void __init bcm47xx_register_ssb(
+ if (err)
+ panic("Failed to initialize SSB bus (err %d)\n", err);
+
++ if (bcm47xx_bus.ssb.chipco.flash_type == SSB_SFLASH)
++ bcm47xx_sflash_struct_ssb_init(&bcm47xx_sflash, &bcm47xx_bus.ssb.chipco);
++
+ mcore = &bcm47xx_bus.ssb.mipscore;
+ if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
+ if (strstr(buf, "console=ttyS1")) {
+@@ -315,6 +320,9 @@ static void __init bcm47xx_register_bcma
+ err = bcma_host_soc_register(&bcm47xx_bus.bcma);
+ if (err)
+ panic("Failed to initialize BCMA bus (err %d)\n", err);
++
++ if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_SFLASH)
++ bcm47xx_sflash_struct_bcma_init(&bcm47xx_sflash, &bcm47xx_bus.bcma.bus.drv_cc);
+ }
+ #endif
+
+--- /dev/null
++++ b/arch/mips/include/asm/mach-bcm47xx/bus.h
+@@ -0,0 +1,37 @@
++/*
++ * BCM947xx nvram variable access
++ *
++ * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/ssb/ssb.h>
++#include <linux/bcma/bcma.h>
++#include <bcm47xx.h>
++
++struct bcm47xx_sflash {
++ enum bcm47xx_bus_type sflash_type;
++ union {
++ struct ssb_chipcommon *scc;
++ struct bcma_drv_cc *bcc;
++ };
++
++ int (*read)(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf);
++ int (*poll)(struct bcm47xx_sflash *dev, u32 offset);
++ int (*write)(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf);
++ int (*erase)(struct bcm47xx_sflash *dev, u32 offset);
++ int (*commit)(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf);
++
++ u32 blocksize; /* Block size */
++ u32 numblocks; /* Number of blocks */
++ u32 size; /* Total size in bytes */
++};
++
++void bcm47xx_sflash_struct_bcma_init(struct bcm47xx_sflash *sflash, struct bcma_drv_cc *bcc);
++void bcm47xx_sflash_struct_ssb_init(struct bcm47xx_sflash *sflash, struct ssb_chipcommon *scc);
++
++extern struct bcm47xx_sflash bcm47xx_sflash;
--- /dev/null
+From d50d2d8e3ab5446f791deff0cb78820989ed93e7 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:54:11 +0200
+Subject: [PATCH 06/19] mtd: bcm47xx: add bcm47xx part parser
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/mtd/Kconfig | 7 +
+ drivers/mtd/Makefile | 1 +
+ drivers/mtd/bcm47xxpart.c | 542 +++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 550 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mtd/bcm47xxpart.c
+
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -164,6 +164,13 @@ config MTD_MYLOADER_PARTS
+ You will still need the parsing functions to be called by the driver
+ for your particular device. It won't happen automatically.
+
++config MTD_BCM47XX_PARTS
++ tristate "BCM47XX partitioning support"
++ default y
++ depends on BCM47XX
++ ---help---
++ bcm47XX partitioning support
++
+ comment "User Modules And Translation Layers"
+
+ config MTD_CHAR
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdli
+ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
+ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
+ obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
++obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
+
+ # 'Users' - code which presents functionality to userspace.
+ obj-$(CONFIG_MTD_CHAR) += mtdchar.o
+--- /dev/null
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -0,0 +1,542 @@
++/*
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ *
++ * original functions for finding root filesystem from Mike Baker
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Copyright 2001-2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * Flash mapping for BCM947XX boards
++ */
++
++#define pr_fmt(fmt) "bcm47xx_part: " fmt
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/crc32.h>
++#include <linux/io.h>
++#include <asm/mach-bcm47xx/nvram.h>
++#include <asm/mach-bcm47xx/bcm47xx.h>
++#include <asm/fw/cfe/cfe_api.h>
++
++
++#define TRX_MAGIC 0x30524448 /* "HDR0" */
++#define TRX_VERSION 1
++#define TRX_MAX_LEN 0x3A0000
++#define TRX_NO_HEADER 1 /* Do not write TRX header */
++#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
++#define TRX_MAX_OFFSET 3
++
++struct trx_header {
++ u32 magic; /* "HDR0" */
++ u32 len; /* Length of file including header */
++ u32 crc32; /* 32-bit CRC from flag_version to end of file */
++ u32 flag_version; /* 0:15 flags, 16:31 version */
++ u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
++};
++
++/* for Edimax Print servers which use an additional header
++ * then the firmware on flash looks like :
++ * EDIMAX HEADER | TRX HEADER
++ * As this header is 12 bytes long we have to handle it
++ * and skip it to find the TRX header
++ */
++#define EDIMAX_PS_HEADER_MAGIC 0x36315350 /* "PS16" */
++#define EDIMAX_PS_HEADER_LEN 0xc /* 12 bytes long for edimax header */
++
++#define NVRAM_SPACE 0x8000
++
++#define ROUTER_NETGEAR_WGR614L 1
++#define ROUTER_NETGEAR_WNR834B 2
++#define ROUTER_NETGEAR_WNDR3300 3
++#define ROUTER_NETGEAR_WNR3500L 4
++#define ROUTER_SIMPLETECH_SIMPLESHARE 5
++#define ROUTER_NETGEAR_WNDR3400 6
++
++static int
++find_cfe_size(struct mtd_info *mtd)
++{
++ struct trx_header *trx;
++ unsigned char buf[512];
++ int off;
++ size_t len;
++ int blocksize;
++
++ trx = (struct trx_header *) buf;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < mtd->size; off += blocksize) {
++ memset(buf, 0xe5, sizeof(buf));
++
++ /*
++ * Read into buffer
++ */
++ if (mtd->read(mtd, off, sizeof(buf), &len, buf) ||
++ len != sizeof(buf))
++ continue;
++
++ if (le32_to_cpu(trx->magic) == EDIMAX_PS_HEADER_MAGIC) {
++ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN,
++ sizeof(buf), &len, buf) || len != sizeof(buf)) {
++ continue;
++ } else {
++ pr_notice("Found edimax header\n");
++ }
++ }
++
++ /* found a TRX header */
++ if (le32_to_cpu(trx->magic) == TRX_MAGIC)
++ goto found;
++ }
++
++ pr_notice("%s: Couldn't find bootloader size\n", mtd->name);
++ return -1;
++
++ found:
++ pr_notice("bootloader size: %d\n", off);
++ return off;
++
++}
++
++/*
++ * Copied from mtdblock.c
++ *
++ * Cache stuff...
++ *
++ * Since typical flash erasable sectors are much larger than what Linux's
++ * buffer cache can handle, we must implement read-modify-write on flash
++ * sectors for each block write requests. To avoid over-erasing flash sectors
++ * and to speed things up, we locally cache a whole flash sector while it is
++ * being written to until a different sector is required.
++ */
++
++static void erase_callback(struct erase_info *done)
++{
++ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
++ wake_up(wait_q);
++}
++
++static int erase_write(struct mtd_info *mtd, unsigned long pos,
++ int len, const char *buf)
++{
++ struct erase_info erase;
++ DECLARE_WAITQUEUE(wait, current);
++ wait_queue_head_t wait_q;
++ size_t retlen;
++ int ret;
++
++ /*
++ * First, let's erase the flash block.
++ */
++
++ init_waitqueue_head(&wait_q);
++ erase.mtd = mtd;
++ erase.callback = erase_callback;
++ erase.addr = pos;
++ erase.len = len;
++ erase.priv = (u_long)&wait_q;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&wait_q, &wait);
++
++ ret = mtd->erase(mtd, &erase);
++ if (ret) {
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&wait_q, &wait);
++ pr_warn("erase of region [0x%lx, 0x%x] on \"%s\" failed\n",
++ pos, len, mtd->name);
++ return ret;
++ }
++
++ schedule(); /* Wait for erase to finish. */
++ remove_wait_queue(&wait_q, &wait);
++
++ /*
++ * Next, write data to flash.
++ */
++
++ ret = mtd->write(mtd, pos, len, &retlen, buf);
++ if (ret)
++ return ret;
++ if (retlen != len)
++ return -EIO;
++ return 0;
++}
++
++
++static int
++find_dual_image_off(struct mtd_info *mtd)
++{
++ struct trx_header trx;
++ int off, blocksize;
++ size_t len;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < mtd->size; off += blocksize) {
++ memset(&trx, 0xe5, sizeof(trx));
++ /*
++ * Read into buffer
++ */
++ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
++ len != sizeof(trx))
++ continue;
++ /* found last TRX header */
++ if (le32_to_cpu(trx.magic) == TRX_MAGIC) {
++ if (le32_to_cpu(trx.flag_version >> 16) == 2) {
++ pr_notice("dual image TRX header found\n");
++ return mtd->size / 2;
++ } else {
++ return 0;
++ }
++ }
++ }
++ return 0;
++}
++
++
++static int
++find_root(struct mtd_info *mtd, struct mtd_partition *part)
++{
++ struct trx_header trx, *trx2;
++ unsigned char buf[512], *block;
++ int off, blocksize, trxoff = 0;
++ u32 i, crc = ~0;
++ size_t len;
++ bool edimax = false;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < mtd->size; off += blocksize) {
++ memset(&trx, 0xe5, sizeof(trx));
++
++ /*
++ * Read into buffer
++ */
++ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
++ len != sizeof(trx))
++ continue;
++
++ /* found an edimax header */
++ if (le32_to_cpu(trx.magic) == EDIMAX_PS_HEADER_MAGIC) {
++ /* read the correct trx header */
++ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN,
++ sizeof(trx), &len, (char *) &trx) ||
++ len != sizeof(trx)) {
++ continue;
++ } else {
++ pr_notice("Found an edimax ps header\n");
++ edimax = true;
++ }
++ }
++
++ /* found a TRX header */
++ if (le32_to_cpu(trx.magic) == TRX_MAGIC) {
++ part->offset = le32_to_cpu(trx.offsets[2]) ? :
++ le32_to_cpu(trx.offsets[1]);
++ part->size = le32_to_cpu(trx.len);
++
++ part->size -= part->offset;
++ part->offset += off;
++ if (edimax) {
++ off += EDIMAX_PS_HEADER_LEN;
++ trxoff = EDIMAX_PS_HEADER_LEN;
++ }
++
++ goto found;
++ }
++ }
++
++ pr_warn("%s: Couldn't find root filesystem\n",
++ mtd->name);
++ return -1;
++
++ found:
++ pr_notice("TRX offset : %x\n", trxoff);
++ if (part->size == 0)
++ return 0;
++
++ if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf))
++ return 0;
++
++ /* Move the fs outside of the trx */
++ part->size = 0;
++
++ if (trx.len != part->offset + part->size - off) {
++ /* Update the trx offsets and length */
++ trx.len = part->offset + part->size - off;
++
++ /* Update the trx crc32 */
++ for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
++ if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf))
++ return 0;
++ crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
++ }
++ trx.crc32 = crc;
++
++ /* read first eraseblock from the trx */
++ block = kmalloc(mtd->erasesize, GFP_KERNEL);
++ trx2 = (struct trx_header *) block;
++ if (mtd->read(mtd, off - trxoff, mtd->erasesize, &len, block) || len != mtd->erasesize) {
++ pr_err("Error accessing the first trx eraseblock\n");
++ return 0;
++ }
++
++ pr_notice("Updating TRX offsets and length:\n");
++ pr_notice("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32);
++ pr_notice("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32);
++
++ /* Write updated trx header to the flash */
++ memcpy(block + trxoff, &trx, sizeof(trx));
++ if (mtd->unlock)
++ mtd->unlock(mtd, off - trxoff, mtd->erasesize);
++ erase_write(mtd, off - trxoff, mtd->erasesize, block);
++ if (mtd->sync)
++ mtd->sync(mtd);
++ kfree(block);
++ pr_notice("Done\n");
++ }
++
++ return part->size;
++}
++
++static int get_router(void)
++{
++ char buf[20];
++ u32 boardnum = 0;
++ u16 boardtype = 0;
++ u16 boardrev = 0;
++ u32 boardflags = 0;
++ u16 sdram_init = 0;
++ u16 cardbus = 0;
++ u16 strev = 0;
++
++ if (nvram_getenv("boardnum", buf, sizeof(buf)) >= 0)
++ boardnum = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
++ boardtype = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
++ boardrev = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0)
++ boardflags = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("sdram_init", buf, sizeof(buf)) >= 0)
++ sdram_init = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
++ cardbus = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("st_rev", buf, sizeof(buf)) >= 0)
++ strev = simple_strtoul(buf, NULL, 0);
++
++ if ((boardnum == 8 || boardnum == 01)
++ && boardtype == 0x0472 && cardbus == 1) {
++ /* Netgear WNR834B, Netgear WNR834Bv2 */
++ return ROUTER_NETGEAR_WNR834B;
++ }
++
++ if (boardnum == 01 && boardtype == 0x0472 && boardrev == 0x23) {
++ /* Netgear WNDR-3300 */
++ return ROUTER_NETGEAR_WNDR3300;
++ }
++
++ if ((boardnum == 83258 || boardnum == 01)
++ && boardtype == 0x048e
++ && (boardrev == 0x11 || boardrev == 0x10)
++ && boardflags == 0x750
++ && sdram_init == 0x000A) {
++ /* Netgear WGR614v8/L/WW 16MB ram, cfe v1.3 or v1.5 */
++ return ROUTER_NETGEAR_WGR614L;
++ }
++
++ if ((boardnum == 1 || boardnum == 3500)
++ && boardtype == 0x04CF
++ && (boardrev == 0x1213 || boardrev == 02)) {
++ /* Netgear WNR3500v2/U/L */
++ return ROUTER_NETGEAR_WNR3500L;
++ }
++
++ if (boardnum == 1 && boardtype == 0xb4cf && boardrev == 0x1100) {
++ /* Netgear WNDR3400 */
++ return ROUTER_NETGEAR_WNDR3400;
++ }
++
++ if (boardtype == 0x042f
++ && boardrev == 0x10
++ && boardflags == 0
++ && strev == 0x11) {
++ /* Simpletech Simpleshare */
++ return ROUTER_SIMPLETECH_SIMPLESHARE;
++ }
++
++ return 0;
++}
++
++static int parse_bcm47xx_partitions(struct mtd_info *mtd,
++ struct mtd_partition **pparts,
++ struct mtd_part_parser_data *data)
++{
++ int cfe_size;
++ int dual_image_offset = 0;
++ /* e.g Netgear 0x003e0000-0x003f0000 : "board_data", we exclude this
++ * part from our mapping to prevent overwriting len/checksum on e.g.
++ * Netgear WGR614v8/L/WW
++ */
++ int custom_data_size = 0;
++ struct mtd_partition *bcm47xx_parts;
++
++ cfe_size = find_cfe_size(mtd);
++ if (cfe_size < 0)
++ return 0;
++
++ bcm47xx_parts = kzalloc(sizeof(struct mtd_partition) * 6, GFP_KERNEL);
++
++ bcm47xx_parts[0].name = "cfe";
++ bcm47xx_parts[1].name = "linux";
++ bcm47xx_parts[2].name = "rootfs";
++ bcm47xx_parts[3].name = "nvram";
++
++ /* boot loader */
++ bcm47xx_parts[0].mask_flags = MTD_WRITEABLE;
++ bcm47xx_parts[0].offset = 0;
++ bcm47xx_parts[0].size = cfe_size;
++
++ /* nvram */
++ if (cfe_size != 384 * 1024) {
++
++ switch (get_router()) {
++ case ROUTER_NETGEAR_WGR614L:
++ case ROUTER_NETGEAR_WNR834B:
++ case ROUTER_NETGEAR_WNDR3300:
++ case ROUTER_NETGEAR_WNR3500L:
++ case ROUTER_NETGEAR_WNDR3400:
++ /* Netgear: checksum is @ 0x003AFFF8 for 4M flash or checksum
++ * is @ 0x007AFFF8 for 8M flash
++ */
++ custom_data_size = mtd->erasesize;
++
++ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize);
++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
++
++ /* Place CFE board_data into a partition */
++ bcm47xx_parts[4].name = "board_data";
++ bcm47xx_parts[4].offset = bcm47xx_parts[3].offset - custom_data_size;
++ bcm47xx_parts[4].size = custom_data_size;
++ break;
++
++ case ROUTER_SIMPLETECH_SIMPLESHARE:
++ /* Fixup Simpletech Simple share nvram */
++
++ pr_notice("Setting up simpletech nvram\n");
++ custom_data_size = mtd->erasesize;
++
++ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize) * 2;
++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
++
++ /* Place backup nvram into a partition */
++ bcm47xx_parts[4].name = "nvram_copy";
++ bcm47xx_parts[4].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize);
++ bcm47xx_parts[4].size = roundup(NVRAM_SPACE, mtd->erasesize);
++ break;
++
++ default:
++ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize);
++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
++ }
++
++ } else {
++ /* nvram (old 128kb config partition on netgear wgt634u) */
++ bcm47xx_parts[3].offset = bcm47xx_parts[0].size;
++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
++ }
++
++ /* dual image offset*/
++ pr_notice("Looking for dual image\n");
++ dual_image_offset = find_dual_image_off(mtd);
++ /* linux (kernel and rootfs) */
++ if (cfe_size != 384 * 1024) {
++ if (get_router() == ROUTER_SIMPLETECH_SIMPLESHARE) {
++ bcm47xx_parts[1].offset = bcm47xx_parts[0].size;
++ bcm47xx_parts[1].size = bcm47xx_parts[4].offset - dual_image_offset -
++ bcm47xx_parts[1].offset - custom_data_size;
++ } else {
++ bcm47xx_parts[1].offset = bcm47xx_parts[0].size;
++ bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset -
++ bcm47xx_parts[1].offset - custom_data_size;
++ }
++ } else {
++ /* do not count the elf loader, which is on one block */
++ bcm47xx_parts[1].offset = bcm47xx_parts[0].size +
++ bcm47xx_parts[3].size + mtd->erasesize;
++ bcm47xx_parts[1].size = mtd->size -
++ bcm47xx_parts[0].size -
++ (2*bcm47xx_parts[3].size) -
++ mtd->erasesize - custom_data_size;
++ }
++
++ /* find and size rootfs */
++ find_root(mtd, &bcm47xx_parts[2]);
++ bcm47xx_parts[2].size = mtd->size - dual_image_offset -
++ bcm47xx_parts[2].offset -
++ bcm47xx_parts[3].size - custom_data_size;
++ *pparts = bcm47xx_parts;
++ return bcm47xx_parts[4].name == NULL ? 4 : 5;
++}
++
++static struct mtd_part_parser bcm47xx_parser = {
++ .owner = THIS_MODULE,
++ .parse_fn = parse_bcm47xx_partitions,
++ .name = "bcm47xx",
++};
++
++static int __init bcm47xx_parser_init(void)
++{
++ return register_mtd_parser(&bcm47xx_parser);
++}
++
++static void __exit bcm47xx_parser_exit(void)
++{
++ deregister_mtd_parser(&bcm47xx_parser);
++}
++
++module_init(bcm47xx_parser_init);
++module_exit(bcm47xx_parser_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Parsing code for flash partitions on bcm47xx SoCs");
--- /dev/null
+From 36f8b899174a445a98fe02ed8d1db177525f0c52 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:55:18 +0200
+Subject: [PATCH 07/15] mtd: bcm47xx: add parallel flash driver
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/mtd/maps/Kconfig | 9 ++
+ drivers/mtd/maps/Makefile | 1 +
+ drivers/mtd/maps/bcm47xx-pflash.c | 188 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 198 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mtd/maps/bcm47xx-pflash.c
+
+--- a/drivers/mtd/maps/Kconfig
++++ b/drivers/mtd/maps/Kconfig
+@@ -257,6 +257,15 @@ config MTD_LANTIQ
+ help
+ Support for NOR flash attached to the Lantiq SoC's External Bus Unit.
+
++config MTD_BCM47XX_PFLASH
++ tristate "bcm47xx parallel flash support"
++ default y
++ depends on BCM47XX
++ select MTD_PARTITIONS
++ select MTD_BCM47XX_PARTS
++ help
++ Support for bcm47xx parallel flash
++
+ config MTD_DILNETPC
+ tristate "CFI Flash device mapped on DIL/Net PC"
+ depends on X86 && MTD_CFI_INTELEXT && BROKEN
+--- a/drivers/mtd/maps/Makefile
++++ b/drivers/mtd/maps/Makefile
+@@ -58,3 +58,4 @@ obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr
+ obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
+ obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
+ obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
++obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o
+--- /dev/null
++++ b/drivers/mtd/maps/bcm47xx-pflash.c
+@@ -0,0 +1,188 @@
++/*
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ *
++ * original functions for finding root filesystem from Mike Baker
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Copyright 2001-2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * Flash mapping for BCM947XX boards
++ */
++
++#define pr_fmt(fmt) "bcm47xx_pflash: " fmt
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <linux/io.h>
++#include <asm/mach-bcm47xx/bcm47xx.h>
++#include <linux/platform_device.h>
++
++#define WINDOW_ADDR 0x1fc00000
++#define WINDOW_SIZE 0x400000
++#define BUSWIDTH 2
++
++static struct mtd_info *bcm47xx_mtd;
++
++static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ if (len == 1) {
++ memcpy_fromio(to, map->virt + from, len);
++ } else {
++ int i;
++ u16 *dest = (u16 *) to;
++ u16 *src = (u16 *) (map->virt + from);
++ for (i = 0; i < (len / 2); i++)
++ dest[i] = src[i];
++ if (len & 1)
++ *((u8 *)dest+len-1) = src[i] & 0xff;
++ }
++}
++
++static struct map_info bcm47xx_map = {
++ name: "Physically mapped flash",
++ size : WINDOW_SIZE,
++ bankwidth : BUSWIDTH,
++ phys : WINDOW_ADDR,
++};
++
++static const char *probes[] = { "bcm47xx", NULL };
++
++static int bcm47xx_mtd_probe(struct platform_device *pdev)
++{
++#ifdef CONFIG_BCM47XX_SSB
++ struct ssb_chipcommon *ssb_cc;
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ struct bcma_drv_cc *bcma_cc;
++#endif
++ int ret = 0;
++
++ switch (bcm47xx_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
++ case BCM47XX_BUS_TYPE_SSB:
++ ssb_cc = &bcm47xx_bus.ssb.chipco;
++ if (ssb_cc->flash_type != SSB_PFLASH)
++ return -ENODEV;
++
++ bcm47xx_map.phys = ssb_cc->pflash.window;
++ bcm47xx_map.size = ssb_cc->pflash.window_size;
++ bcm47xx_map.bankwidth = ssb_cc->pflash.buswidth;
++ break;
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
++ if (bcma_cc->flash_type != BCMA_PFLASH)
++ return -ENODEV;
++
++ bcm47xx_map.phys = bcma_cc->pflash.window;
++ bcm47xx_map.size = bcma_cc->pflash.window_size;
++ bcm47xx_map.bankwidth = bcma_cc->pflash.buswidth;
++ break;
++#endif
++ }
++
++ pr_notice("flash init: 0x%08x 0x%08lx\n", bcm47xx_map.phys, bcm47xx_map.size);
++ bcm47xx_map.virt = ioremap_nocache(bcm47xx_map.phys, bcm47xx_map.size);
++
++ if (!bcm47xx_map.virt) {
++ pr_err("Failed to ioremap\n");
++ return -EIO;
++ }
++
++ simple_map_init(&bcm47xx_map);
++ /* override copy_from routine */
++ bcm47xx_map.copy_from = bcm47xx_map_copy_from;
++
++ bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map);
++ if (!bcm47xx_mtd) {
++ pr_err("Failed to do_map_probe\n");
++ ret = -ENXIO;
++ goto err_unmap;
++ }
++ bcm47xx_mtd->owner = THIS_MODULE;
++
++ pr_notice("Flash device: 0x%lx at 0x%x\n", bcm47xx_map.size, WINDOW_ADDR);
++
++ ret = mtd_device_parse_register(bcm47xx_mtd, probes, NULL, NULL, 0);
++
++ if (ret) {
++ pr_err("Flash: mtd_device_register failed\n");
++ goto err_destroy;
++ }
++ return 0;
++
++err_destroy:
++ map_destroy(bcm47xx_mtd);
++err_unmap:
++ iounmap(bcm47xx_map.virt);
++ return ret;
++}
++
++static int __devexit bcm47xx_mtd_remove(struct platform_device *pdev)
++{
++ mtd_device_unregister(bcm47xx_mtd);
++ map_destroy(bcm47xx_mtd);
++ iounmap(bcm47xx_map.virt);
++ return 0;
++}
++
++static struct platform_driver bcm47xx_mtd_driver = {
++ .remove = __devexit_p(bcm47xx_mtd_remove),
++ .driver = {
++ .name = "bcm47xx_pflash",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init init_bcm47xx_mtd(void)
++{
++ int ret = platform_driver_probe(&bcm47xx_mtd_driver, bcm47xx_mtd_probe);
++
++ if (ret)
++ pr_err("error registering platform driver: %i\n", ret);
++ return ret;
++}
++
++static void __exit exit_bcm47xx_mtd(void)
++{
++ platform_driver_unregister(&bcm47xx_mtd_driver);
++}
++
++module_init(init_bcm47xx_mtd);
++module_exit(exit_bcm47xx_mtd);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("BCM47XX parallel flash driver");
--- /dev/null
+From 2e2951220bf63e05449c03a95453680da1029e44 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:55:45 +0200
+Subject: [PATCH 08/15] mtd: bcm47xx: add serial flash driver
+
+sflash get the sflash ops from platform device
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/include/asm/mach-bcm47xx/bus.h | 3 +
+ drivers/mtd/maps/Kconfig | 9 +
+ drivers/mtd/maps/Makefile | 1 +
+ drivers/mtd/maps/bcm47xx-sflash.c | 252 ++++++++++++++++++++++++++++++
+ 4 files changed, 265 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mtd/maps/bcm47xx-sflash.c
+
+--- a/arch/mips/include/asm/mach-bcm47xx/bus.h
++++ b/arch/mips/include/asm/mach-bcm47xx/bus.h
+@@ -11,6 +11,7 @@
+
+ #include <linux/ssb/ssb.h>
+ #include <linux/bcma/bcma.h>
++#include <linux/mtd/mtd.h>
+ #include <bcm47xx.h>
+
+ struct bcm47xx_sflash {
+@@ -29,6 +30,8 @@ struct bcm47xx_sflash {
+ u32 blocksize; /* Block size */
+ u32 numblocks; /* Number of blocks */
+ u32 size; /* Total size in bytes */
++
++ struct mtd_info *mtd;
+ };
+
+ void bcm47xx_sflash_struct_bcma_init(struct bcm47xx_sflash *sflash, struct bcma_drv_cc *bcc);
+--- a/drivers/mtd/maps/Kconfig
++++ b/drivers/mtd/maps/Kconfig
+@@ -266,6 +266,15 @@ config MTD_BCM47XX_PFLASH
+ help
+ Support for bcm47xx parallel flash
+
++config MTD_BCM47XX_SFLASH
++ tristate "bcm47xx serial flash support"
++ default y
++ depends on BCM47XX
++ select MTD_PARTITIONS
++ select MTD_BCM47XX_PARTS
++ help
++ Support for bcm47xx parallel flash
++
+ config MTD_DILNETPC
+ tristate "CFI Flash device mapped on DIL/Net PC"
+ depends on X86 && MTD_CFI_INTELEXT && BROKEN
+--- a/drivers/mtd/maps/Makefile
++++ b/drivers/mtd/maps/Makefile
+@@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-f
+ obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
+ obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
+ obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o
++obj-$(CONFIG_MTD_BCM47XX_SFLASH)+= bcm47xx-sflash.o
+--- /dev/null
++++ b/drivers/mtd/maps/bcm47xx-sflash.c
+@@ -0,0 +1,252 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#define pr_fmt(fmt) "bcm47xx_sflash: " fmt
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <bcm47xx.h>
++#include <bus.h>
++
++static int
++sflash_mtd_poll(struct bcm47xx_sflash *sflash, unsigned int offset, int timeout)
++{
++ unsigned long now = jiffies;
++ int ret = 0;
++
++ for (;;) {
++ if (!sflash->poll(sflash, offset)) {
++ ret = 0;
++ break;
++ }
++ if (time_after(jiffies, now + timeout)) {
++ pr_err("timeout while polling\n");
++ ret = -ETIMEDOUT;
++ break;
++ }
++ udelay(1);
++ }
++
++ return ret;
++}
++
++static int
++sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
++{
++ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *) mtd->priv;
++
++ /* Check address range */
++ if (!len)
++ return 0;
++
++ if ((from + len) > mtd->size)
++ return -EINVAL;
++
++ *retlen = 0;
++
++ while (len) {
++ int ret = sflash->read(sflash, from, len, buf);
++ if (ret < 0)
++ return ret;
++
++ from += (loff_t) ret;
++ len -= ret;
++ buf += ret;
++ *retlen += ret;
++ }
++
++ return 0;
++}
++
++static int
++sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
++{
++ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *) mtd->priv;
++
++ /* Check address range */
++ if (!len)
++ return 0;
++
++ if ((to + len) > mtd->size)
++ return -EINVAL;
++
++ *retlen = 0;
++ while (len) {
++ int bytes;
++ int ret = sflash->write(sflash, to, len, buf);
++ if (ret < 0)
++ return ret;
++
++ bytes = ret;
++
++ ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10);
++ if (ret)
++ return ret;
++
++ to += (loff_t) bytes;
++ len -= bytes;
++ buf += bytes;
++ *retlen += bytes;
++ }
++
++ return 0;
++}
++
++static int
++sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
++{
++ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *) mtd->priv;
++ int i, j, ret = 0;
++ unsigned int addr, len;
++
++ /* Check address range */
++ if (!erase->len)
++ return 0;
++ if ((erase->addr + erase->len) > mtd->size)
++ return -EINVAL;
++
++ addr = erase->addr;
++ len = erase->len;
++
++ /* Ensure that requested regions are aligned */
++ for (i = 0; i < mtd->numeraseregions; i++) {
++ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
++ if (addr == mtd->eraseregions[i].offset +
++ mtd->eraseregions[i].erasesize * j &&
++ len >= mtd->eraseregions[i].erasesize) {
++ ret = sflash->erase(sflash, addr);
++ if (ret < 0)
++ break;
++ ret = sflash_mtd_poll(sflash, addr, 10 * HZ);
++ if (ret)
++ break;
++ addr += mtd->eraseregions[i].erasesize;
++ len -= mtd->eraseregions[i].erasesize;
++ }
++ }
++ if (ret)
++ break;
++ }
++
++ /* Set erase status */
++ if (ret)
++ erase->state = MTD_ERASE_FAILED;
++ else
++ erase->state = MTD_ERASE_DONE;
++
++ /* Call erase callback */
++ if (erase->callback)
++ erase->callback(erase);
++
++ return ret;
++}
++
++static const char *probes[] = { "bcm47xx", NULL };
++
++static int bcm47xx_sflash_probe(struct platform_device *pdev)
++{
++ struct bcm47xx_sflash *sflash = dev_get_platdata(&pdev->dev);
++ struct mtd_info *mtd;
++ struct mtd_erase_region_info *regions;
++ int ret = 0;
++
++ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
++ if (!mtd)
++ return -ENOMEM;
++
++ regions = kzalloc(sizeof(struct mtd_erase_region_info), GFP_KERNEL);
++ if (!mtd)
++ return -ENOMEM;
++
++ pr_info("found serial flash: blocksize=%dKB, numblocks=%d, size=%dKB\n",
++ sflash->blocksize/1024, sflash->numblocks, sflash->size / 1024);
++
++ /* Setup region info */
++ regions->offset = 0;
++ regions->erasesize = sflash->blocksize;
++ regions->numblocks = sflash->numblocks;
++ if (regions->erasesize > mtd->erasesize)
++ mtd->erasesize = regions->erasesize;
++ mtd->size = sflash->size;
++ mtd->numeraseregions = 1;
++
++ /* Register with MTD */
++ mtd->name = "bcm47xx-sflash";
++ mtd->type = MTD_NORFLASH;
++ mtd->flags = MTD_CAP_NORFLASH;
++ mtd->eraseregions = regions;
++ mtd->erase = sflash_mtd_erase;
++ mtd->read = sflash_mtd_read;
++ mtd->write = sflash_mtd_write;
++ mtd->writesize = 1;
++ mtd->priv = sflash;
++ mtd->owner = THIS_MODULE;
++
++ ret = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
++
++ if (ret) {
++ pr_err("mtd_device_register failed\n");
++ return ret;
++ }
++ sflash->mtd = mtd;
++ return 0;
++}
++
++static int __devexit bcm47xx_sflash_remove(struct platform_device *pdev)
++{
++ struct bcm47xx_sflash *sflash = dev_get_platdata(&pdev->dev);
++
++ if (sflash) {
++ mtd_device_unregister(sflash->mtd);
++ map_destroy(sflash->mtd);
++ kfree(sflash->mtd->eraseregions);
++ kfree(sflash->mtd);
++ }
++ return 0;
++}
++
++static struct platform_driver bcm47xx_sflash_driver = {
++ .remove = __devexit_p(bcm47xx_sflash_remove),
++ .driver = {
++ .name = "bcm47xx_sflash",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init init_bcm47xx_sflash(void)
++{
++ int ret = platform_driver_probe(&bcm47xx_sflash_driver, bcm47xx_sflash_probe);
++
++ if (ret)
++ pr_err("error registering platform driver: %i\n", ret);
++ return ret;
++}
++
++static void __exit exit_bcm47xx_sflash(void)
++{
++ platform_driver_unregister(&bcm47xx_sflash_driver);
++}
++
++module_init(init_bcm47xx_sflash);
++module_exit(exit_bcm47xx_sflash);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("BCM47XX parallel flash driver");
--- /dev/null
+From 64f3d068654589d6114048ac5933cd4498706cfc Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 15:02:10 +0200
+Subject: [PATCH 20/26] bcm47xx: register flash drivers
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/setup.c | 72 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 72 insertions(+), 0 deletions(-)
+
+--- a/arch/mips/bcm47xx/setup.c
++++ b/arch/mips/bcm47xx/setup.c
+@@ -31,10 +31,12 @@
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_embedded.h>
+ #include <linux/bcma/bcma_soc.h>
++#include <linux/platform_device.h>
+ #include <asm/bootinfo.h>
+ #include <asm/reboot.h>
+ #include <asm/time.h>
+ #include <bcm47xx.h>
++#include <bus.h>
+ #include <asm/mach-bcm47xx/nvram.h>
+
+ union bcm47xx_bus bcm47xx_bus;
+@@ -366,3 +368,73 @@ static int __init bcm47xx_register_bus_c
+ return 0;
+ }
+ device_initcall(bcm47xx_register_bus_complete);
++
++static struct resource bcm47xx_pflash_resource = {
++ .name = "bcm47xx_pflash",
++ .start = 0,
++ .end = 0,
++ .flags = 0,
++};
++
++static struct platform_device bcm47xx_pflash_dev = {
++ .name = "bcm47xx_pflash",
++ .resource = &bcm47xx_pflash_resource,
++ .num_resources = 1,
++};
++
++static struct resource bcm47xx_sflash_resource = {
++ .name = "bcm47xx_sflash",
++ .start = 0,
++ .end = 0,
++ .flags = 0,
++};
++
++static struct platform_device bcm47xx_sflash_dev = {
++ .name = "bcm47xx_sflash",
++ .resource = &bcm47xx_sflash_resource,
++ .num_resources = 1,
++};
++
++static int __init bcm47xx_register_flash(void)
++{
++#ifdef CONFIG_BCM47XX_SSB
++ struct ssb_chipcommon *chipco;
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ struct bcma_drv_cc *drv_cc;
++#endif
++ switch (bcm47xx_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
++ case BCM47XX_BUS_TYPE_SSB:
++ chipco = &bcm47xx_bus.ssb.chipco;
++ if (chipco->flash_type == SSB_PFLASH) {
++ bcm47xx_pflash_resource.start = chipco->pflash.window;
++ bcm47xx_pflash_resource.end = chipco->pflash.window + chipco->pflash.window_size;
++ return platform_device_register(&bcm47xx_pflash_dev);
++ } else if (chipco->flash_type == SSB_SFLASH) {
++ bcm47xx_sflash_dev.dev.platform_data = &bcm47xx_sflash;
++ return platform_device_register(&bcm47xx_sflash_dev);
++ } else {
++ printk(KERN_ERR "No flash device found\n");
++ return -1;
++ }
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ drv_cc = &bcm47xx_bus.bcma.bus.drv_cc;
++ if (drv_cc->flash_type == BCMA_PFLASH) {
++ bcm47xx_pflash_resource.start = drv_cc->pflash.window;
++ bcm47xx_pflash_resource.end = drv_cc->pflash.window + drv_cc->pflash.window_size;
++ return platform_device_register(&bcm47xx_pflash_dev);
++ } else if (drv_cc->flash_type == BCMA_SFLASH) {
++ bcm47xx_sflash_dev.dev.platform_data = &bcm47xx_sflash;
++ return platform_device_register(&bcm47xx_sflash_dev);
++ } else {
++ printk(KERN_ERR "No flash device found\n");
++ return -1;
++ }
++#endif
++ }
++ return -1;
++}
++fs_initcall(bcm47xx_register_flash);
--- /dev/null
+From 1d693b2c9d5943cbe938f879041b837cd004737f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 23 Jul 2011 18:29:38 +0200
+Subject: [PATCH 25/26] bcm47xx: read nvram from sflash
+
+bcm47xx: add sflash support to nvram
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/nvram.c | 86 +++++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 84 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -20,11 +20,12 @@
+ #include <asm/addrspace.h>
+ #include <asm/mach-bcm47xx/nvram.h>
+ #include <asm/mach-bcm47xx/bcm47xx.h>
++#include <asm/mach-bcm47xx/bus.h>
+
+ static char nvram_buf[NVRAM_SPACE];
+
+ /* Probe for NVRAM header */
+-static void early_nvram_init(void)
++static void early_nvram_init_pflash(void)
+ {
+ #ifdef CONFIG_BCM47XX_SSB
+ struct ssb_chipcommon *ssb_cc;
+@@ -86,7 +87,88 @@ found:
+ for (i = 0; i < sizeof(struct nvram_header); i += 4)
+ *dst++ = *src++;
+ for (; i < header->len && i < NVRAM_SPACE; i += 4)
+- *dst++ = le32_to_cpu(*src++);
++ *dst++ = *src++;
++}
++
++static int early_nvram_init_sflash(void)
++{
++ struct nvram_header header;
++ u32 off;
++ int ret;
++ char *dst;
++ int len;
++
++ /* check if the struct is already initilized */
++ if (!bcm47xx_sflash.size)
++ return -1;
++
++ off = FLASH_MIN;
++ while (off <= bcm47xx_sflash.size) {
++ ret = bcm47xx_sflash.read(&bcm47xx_sflash, off - NVRAM_SPACE, sizeof(header), (u8 *)&header);
++ if (ret != sizeof(header))
++ return ret;
++ if (header.magic == NVRAM_HEADER)
++ goto found;
++ off <<= 1;
++ }
++
++ off = FLASH_MIN;
++ while (off <= bcm47xx_sflash.size) {
++ ret = bcm47xx_sflash.read(&bcm47xx_sflash, off - (2 * NVRAM_SPACE), sizeof(header), (u8 *)&header);
++ if (ret != sizeof(header))
++ return ret;
++ if (header.magic == NVRAM_HEADER)
++ goto found;
++ off <<= 1;
++ }
++ return -1;
++
++found:
++ len = NVRAM_SPACE;
++ dst = nvram_buf;
++ while (len) {
++ ret = bcm47xx_sflash.read(&bcm47xx_sflash, off - (2 * NVRAM_SPACE), len, dst);
++ if (ret < 0)
++ return ret;
++ off += ret;
++ len -= ret;
++ dst += ret;
++ }
++ return 0;
++}
++
++static void early_nvram_init(void)
++{
++ int err = 0;
++
++ switch (bcm47xx_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
++ case BCM47XX_BUS_TYPE_SSB:
++ if (bcm47xx_bus.ssb.chipco.flash_type == SSB_PFLASH) {
++ early_nvram_init_pflash();
++ } else if (bcm47xx_bus.ssb.chipco.flash_type == SSB_SFLASH) {
++ err = early_nvram_init_sflash();
++ if (err < 0)
++ printk(KERN_WARNING "can not read from flash: %i\n", err);
++ } else {
++ printk(KERN_WARNING "unknow flash type\n");
++ }
++ break;
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_PFLASH) {
++ early_nvram_init_pflash();
++ } else if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_SFLASH) {
++ err = early_nvram_init_sflash();
++ if (err < 0)
++ printk(KERN_WARNING "can not read from flash: %i\n", err);
++ } else {
++ printk(KERN_WARNING "unknow flash type\n");
++ }
++ break;
++#endif
++ }
+ }
+
+ int nvram_getenv(char *name, char *val, size_t val_len)
+++ /dev/null
---- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
-+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
-@@ -151,5 +151,9 @@ static inline int gpio_polarity(unsigned
- return -EINVAL;
- }
-
-+static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
-+{
-+ return -ENOSYS;
-+}
-
- #endif /* __BCM47XX_GPIO_H */
--- /dev/null
+From 7b9116eeaf44c0d368b5eeaa06eb101465284596 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Wed, 11 Jan 2012 15:26:11 +0100
+Subject: [PATCH 23/31] bcma: add the core unit number
+
+Some SoCs have two pcie or gmac cores and we need to know the number of
+the specific core on the bus. This is the case for the BCM4706.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/scan.c | 14 ++++++++++++++
+ include/linux/bcma/bcma.h | 1 +
+ 2 files changed, 15 insertions(+), 0 deletions(-)
+
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -212,6 +212,17 @@ static struct bcma_device *bcma_find_cor
+ return NULL;
+ }
+
++static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 coreid)
++{
++ struct bcma_device *core;
++
++ list_for_each_entry_reverse(core, &bus->cores, list) {
++ if (core->id.id == coreid)
++ 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)
+@@ -392,6 +403,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
+ bcma_scan_switch_core(bus, erombase);
+
+ while (eromptr < eromend) {
++ struct bcma_device *other_core;
+ struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (!core)
+ return -ENOMEM;
+@@ -411,6 +423,8 @@ int bcma_bus_scan(struct bcma_bus *bus)
+
+ core->core_index = core_num++;
+ bus->nr_cores++;
++ other_core = bcma_find_core_reverse(bus, core->id.id);
++ core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
+
+ pr_info("Core %d found: %s "
+ "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -136,6 +136,7 @@ struct bcma_device {
+ bool dev_registered;
+
+ u8 core_index;
++ u8 core_unit;
+
+ u32 addr;
+ u32 wrap;
--- /dev/null
+From 300efafa8e1381a208c723bb9d03d46bf29f1ec0 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 14 Jan 2012 20:02:15 +0100
+Subject: [PATCH 24/31] bcma: constants for PCI and use them
+
+There are loots of magic numbers used in the PCIe code. These constants
+are from the Broadcom SDK and will also used in the host controller.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/driver_pci.c | 124 +++++++++++++++++++---------------
+ include/linux/bcma/bcma_driver_pci.h | 85 +++++++++++++++++++++++
+ 2 files changed, 155 insertions(+), 54 deletions(-)
+
+--- a/drivers/bcma/driver_pci.c
++++ b/drivers/bcma/driver_pci.c
+@@ -4,6 +4,7 @@
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
++ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+@@ -18,38 +19,39 @@
+
+ static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
+ {
+- pcicore_write32(pc, 0x130, address);
+- pcicore_read32(pc, 0x130);
+- return pcicore_read32(pc, 0x134);
++ pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
++ pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
++ return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA);
+ }
+
+ #if 0
+ static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
+ {
+- pcicore_write32(pc, 0x130, address);
+- pcicore_read32(pc, 0x130);
+- pcicore_write32(pc, 0x134, data);
++ pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
++ pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
++ pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data);
+ }
+ #endif
+
+ static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
+ {
+- const u16 mdio_control = 0x128;
+- const u16 mdio_data = 0x12C;
+ u32 v;
+ int i;
+
+- v = (1 << 30); /* Start of Transaction */
+- v |= (1 << 28); /* Write Transaction */
+- v |= (1 << 17); /* Turnaround */
+- v |= (0x1F << 18);
++ v = BCMA_CORE_PCI_MDIODATA_START;
++ v |= BCMA_CORE_PCI_MDIODATA_WRITE;
++ v |= (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
++ BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
++ v |= (BCMA_CORE_PCI_MDIODATA_BLK_ADDR <<
++ BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
++ v |= BCMA_CORE_PCI_MDIODATA_TA;
+ v |= (phy << 4);
+- pcicore_write32(pc, mdio_data, v);
++ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
+
+ udelay(10);
+ for (i = 0; i < 200; i++) {
+- v = pcicore_read32(pc, mdio_control);
+- if (v & 0x100 /* Trans complete */)
++ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
++ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
+ break;
+ msleep(1);
+ }
+@@ -57,79 +59,84 @@ static void bcma_pcie_mdio_set_phy(struc
+
+ static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
+ {
+- const u16 mdio_control = 0x128;
+- const u16 mdio_data = 0x12C;
+ int max_retries = 10;
+ u16 ret = 0;
+ u32 v;
+ int i;
+
+- v = 0x80; /* Enable Preamble Sequence */
+- v |= 0x2; /* MDIO Clock Divisor */
+- pcicore_write32(pc, mdio_control, v);
++ /* enable mdio access to SERDES */
++ v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
++ v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
++ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
+
+ if (pc->core->id.rev >= 10) {
+ max_retries = 200;
+ bcma_pcie_mdio_set_phy(pc, device);
++ v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
++ BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
++ v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
++ } else {
++ v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
++ v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
+ }
+
+- v = (1 << 30); /* Start of Transaction */
+- v |= (1 << 29); /* Read Transaction */
+- v |= (1 << 17); /* Turnaround */
+- if (pc->core->id.rev < 10)
+- v |= (u32)device << 22;
+- v |= (u32)address << 18;
+- pcicore_write32(pc, mdio_data, v);
++ v = BCMA_CORE_PCI_MDIODATA_START;
++ v |= BCMA_CORE_PCI_MDIODATA_READ;
++ v |= BCMA_CORE_PCI_MDIODATA_TA;
++
++ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
+ /* Wait for the device to complete the transaction */
+ udelay(10);
+ for (i = 0; i < max_retries; i++) {
+- v = pcicore_read32(pc, mdio_control);
+- if (v & 0x100 /* Trans complete */) {
++ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
++ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE) {
+ udelay(10);
+- ret = pcicore_read32(pc, mdio_data);
++ ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA);
+ break;
+ }
+ msleep(1);
+ }
+- pcicore_write32(pc, mdio_control, 0);
++ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
+ return ret;
+ }
+
+ static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
+ u8 address, u16 data)
+ {
+- const u16 mdio_control = 0x128;
+- const u16 mdio_data = 0x12C;
+ int max_retries = 10;
+ u32 v;
+ int i;
+
+- v = 0x80; /* Enable Preamble Sequence */
+- v |= 0x2; /* MDIO Clock Divisor */
+- pcicore_write32(pc, mdio_control, v);
++ /* enable mdio access to SERDES */
++ v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
++ v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
++ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
+
+ if (pc->core->id.rev >= 10) {
+ max_retries = 200;
+ bcma_pcie_mdio_set_phy(pc, device);
++ v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
++ BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
++ v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
++ } else {
++ v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
++ v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
+ }
+
+- v = (1 << 30); /* Start of Transaction */
+- v |= (1 << 28); /* Write Transaction */
+- v |= (1 << 17); /* Turnaround */
+- if (pc->core->id.rev < 10)
+- v |= (u32)device << 22;
+- v |= (u32)address << 18;
++ v = BCMA_CORE_PCI_MDIODATA_START;
++ v |= BCMA_CORE_PCI_MDIODATA_WRITE;
++ v |= BCMA_CORE_PCI_MDIODATA_TA;
+ v |= data;
+- pcicore_write32(pc, mdio_data, v);
++ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
+ /* Wait for the device to complete the transaction */
+ udelay(10);
+ for (i = 0; i < max_retries; i++) {
+- v = pcicore_read32(pc, mdio_control);
+- if (v & 0x100 /* Trans complete */)
++ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
++ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
+ break;
+ msleep(1);
+ }
+- pcicore_write32(pc, mdio_control, 0);
++ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
+ }
+
+ /**************************************************
+@@ -138,20 +145,29 @@ static void bcma_pcie_mdio_write(struct
+
+ static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc)
+ {
+- return (bcma_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
++ u32 tmp;
++
++ tmp = bcma_pcie_read(pc, BCMA_CORE_PCI_PLP_STATUSREG);
++ if (tmp & BCMA_CORE_PCI_PLP_POLARITYINV_STAT)
++ return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE |
++ BCMA_CORE_PCI_SERDES_RX_CTRL_POLARITY;
++ else
++ return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE;
+ }
+
+ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
+ {
+- const u8 serdes_pll_device = 0x1D;
+- const u8 serdes_rx_device = 0x1F;
+ u16 tmp;
+
+- bcma_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
+- bcma_pcicore_polarity_workaround(pc));
+- tmp = bcma_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
+- if (tmp & 0x4000)
+- bcma_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
++ bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_RX,
++ BCMA_CORE_PCI_SERDES_RX_CTRL,
++ bcma_pcicore_polarity_workaround(pc));
++ tmp = bcma_pcie_mdio_read(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
++ BCMA_CORE_PCI_SERDES_PLL_CTRL);
++ if (tmp & BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN)
++ bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
++ BCMA_CORE_PCI_SERDES_PLL_CTRL,
++ tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
+ }
+
+ /**************************************************
+--- a/include/linux/bcma/bcma_driver_pci.h
++++ b/include/linux/bcma/bcma_driver_pci.h
+@@ -53,6 +53,35 @@ struct pci_dev;
+ #define BCMA_CORE_PCI_SBTOPCI1_MASK 0xFC000000
+ #define BCMA_CORE_PCI_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */
+ #define BCMA_CORE_PCI_SBTOPCI2_MASK 0xC0000000
++#define BCMA_CORE_PCI_CONFIG_ADDR 0x0120 /* pcie config space access */
++#define BCMA_CORE_PCI_CONFIG_DATA 0x0124 /* pcie config space access */
++#define BCMA_CORE_PCI_MDIO_CONTROL 0x0128 /* controls the mdio access */
++#define BCMA_CORE_PCI_MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */
++#define BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL 0x2
++#define BCMA_CORE_PCI_MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */
++#define BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE 0x100 /* Tranaction complete */
++#define BCMA_CORE_PCI_MDIO_DATA 0x012c /* Data to the mdio access */
++#define BCMA_CORE_PCI_MDIODATA_MASK 0x0000ffff /* data 2 bytes */
++#define BCMA_CORE_PCI_MDIODATA_TA 0x00020000 /* Turnaround */
++#define BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift (rev < 10) */
++#define BCMA_CORE_PCI_MDIODATA_REGADDR_MASK_OLD 0x003c0000 /* Regaddr Mask (rev < 10) */
++#define BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift (rev < 10) */
++#define BCMA_CORE_PCI_MDIODATA_DEVADDR_MASK_OLD 0x0fc00000 /* Physmedia devaddr Mask (rev < 10) */
++#define BCMA_CORE_PCI_MDIODATA_REGADDR_SHF 18 /* Regaddr shift */
++#define BCMA_CORE_PCI_MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */
++#define BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */
++#define BCMA_CORE_PCI_MDIODATA_DEVADDR_MASK 0x0f800000 /* Physmedia devaddr Mask */
++#define BCMA_CORE_PCI_MDIODATA_WRITE 0x10000000 /* write Transaction */
++#define BCMA_CORE_PCI_MDIODATA_READ 0x20000000 /* Read Transaction */
++#define BCMA_CORE_PCI_MDIODATA_START 0x40000000 /* start of Transaction */
++#define BCMA_CORE_PCI_MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */
++#define BCMA_CORE_PCI_MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */
++#define BCMA_CORE_PCI_MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */
++#define BCMA_CORE_PCI_MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */
++#define BCMA_CORE_PCI_MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */
++#define BCMA_CORE_PCI_PCIEIND_ADDR 0x0130 /* indirect access to the internal register */
++#define BCMA_CORE_PCI_PCIEIND_DATA 0x0134 /* Data to/from the internal regsiter */
++#define BCMA_CORE_PCI_CLKREQENCTRL 0x0138 /* >= rev 6, Clkreq rdma control */
+ #define BCMA_CORE_PCI_PCICFG0 0x0400 /* PCI config space 0 (rev >= 8) */
+ #define BCMA_CORE_PCI_PCICFG1 0x0500 /* PCI config space 1 (rev >= 8) */
+ #define BCMA_CORE_PCI_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */
+@@ -72,6 +101,62 @@ struct pci_dev;
+ #define BCMA_CORE_PCI_SBTOPCI_RC_READL 0x00000010 /* Memory read line */
+ #define BCMA_CORE_PCI_SBTOPCI_RC_READM 0x00000020 /* Memory read multiple */
+
++/* PCIE protocol PHY diagnostic registers */
++#define BCMA_CORE_PCI_PLP_MODEREG 0x200 /* Mode */
++#define BCMA_CORE_PCI_PLP_STATUSREG 0x204 /* Status */
++#define BCMA_CORE_PCI_PLP_POLARITYINV_STAT 0x10 /* Status reg PCIE_PLP_STATUSREG */
++#define BCMA_CORE_PCI_PLP_LTSSMCTRLREG 0x208 /* LTSSM control */
++#define BCMA_CORE_PCI_PLP_LTLINKNUMREG 0x20c /* Link Training Link number */
++#define BCMA_CORE_PCI_PLP_LTLANENUMREG 0x210 /* Link Training Lane number */
++#define BCMA_CORE_PCI_PLP_LTNFTSREG 0x214 /* Link Training N_FTS */
++#define BCMA_CORE_PCI_PLP_ATTNREG 0x218 /* Attention */
++#define BCMA_CORE_PCI_PLP_ATTNMASKREG 0x21C /* Attention Mask */
++#define BCMA_CORE_PCI_PLP_RXERRCTR 0x220 /* Rx Error */
++#define BCMA_CORE_PCI_PLP_RXFRMERRCTR 0x224 /* Rx Framing Error */
++#define BCMA_CORE_PCI_PLP_RXERRTHRESHREG 0x228 /* Rx Error threshold */
++#define BCMA_CORE_PCI_PLP_TESTCTRLREG 0x22C /* Test Control reg */
++#define BCMA_CORE_PCI_PLP_SERDESCTRLOVRDREG 0x230 /* SERDES Control Override */
++#define BCMA_CORE_PCI_PLP_TIMINGOVRDREG 0x234 /* Timing param override */
++#define BCMA_CORE_PCI_PLP_RXTXSMDIAGREG 0x238 /* RXTX State Machine Diag */
++#define BCMA_CORE_PCI_PLP_LTSSMDIAGREG 0x23C /* LTSSM State Machine Diag */
++
++/* PCIE protocol DLLP diagnostic registers */
++#define BCMA_CORE_PCI_DLLP_LCREG 0x100 /* Link Control */
++#define BCMA_CORE_PCI_DLLP_LSREG 0x104 /* Link Status */
++#define BCMA_CORE_PCI_DLLP_LAREG 0x108 /* Link Attention */
++#define BCMA_CORE_PCI_DLLP_LSREG_LINKUP (1 << 16)
++#define BCMA_CORE_PCI_DLLP_LAMASKREG 0x10C /* Link Attention Mask */
++#define BCMA_CORE_PCI_DLLP_NEXTTXSEQNUMREG 0x110 /* Next Tx Seq Num */
++#define BCMA_CORE_PCI_DLLP_ACKEDTXSEQNUMREG 0x114 /* Acked Tx Seq Num */
++#define BCMA_CORE_PCI_DLLP_PURGEDTXSEQNUMREG 0x118 /* Purged Tx Seq Num */
++#define BCMA_CORE_PCI_DLLP_RXSEQNUMREG 0x11C /* Rx Sequence Number */
++#define BCMA_CORE_PCI_DLLP_LRREG 0x120 /* Link Replay */
++#define BCMA_CORE_PCI_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */
++#define BCMA_CORE_PCI_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
++#define BCMA_CORE_PCI_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */
++#define BCMA_CORE_PCI_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */
++#define BCMA_CORE_PCI_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */
++#define BCMA_CORE_PCI_DLLP_RTRRWREG 0x138 /* Retry buffer Read/Write */
++#define BCMA_CORE_PCI_DLLP_ECTHRESHREG 0x13C /* Error Count Threshold */
++#define BCMA_CORE_PCI_DLLP_TLPERRCTRREG 0x140 /* TLP Error Counter */
++#define BCMA_CORE_PCI_DLLP_ERRCTRREG 0x144 /* Error Counter */
++#define BCMA_CORE_PCI_DLLP_NAKRXCTRREG 0x148 /* NAK Received Counter */
++#define BCMA_CORE_PCI_DLLP_TESTREG 0x14C /* Test */
++#define BCMA_CORE_PCI_DLLP_PKTBIST 0x150 /* Packet BIST */
++#define BCMA_CORE_PCI_DLLP_PCIE11 0x154 /* DLLP PCIE 1.1 reg */
++
++/* SERDES RX registers */
++#define BCMA_CORE_PCI_SERDES_RX_CTRL 1 /* Rx cntrl */
++#define BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */
++#define BCMA_CORE_PCI_SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */
++#define BCMA_CORE_PCI_SERDES_RX_TIMER1 2 /* Rx Timer1 */
++#define BCMA_CORE_PCI_SERDES_RX_CDR 6 /* CDR */
++#define BCMA_CORE_PCI_SERDES_RX_CDRBW 7 /* CDR BW */
++
++/* SERDES PLL registers */
++#define BCMA_CORE_PCI_SERDES_PLL_CTRL 1 /* PLL control reg */
++#define BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */
++
+ /* PCIcore specific boardflags */
+ #define BCMA_CORE_PCI_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
+
--- /dev/null
+From 01d8709c311858c37e02c96464ea4dc954334210 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 14 Jan 2012 20:03:09 +0100
+Subject: [PATCH 25/31] bcma: export bcma_pcie_read()
+
+This will be needed by the host controller.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/bcma_private.h | 2 ++
+ drivers/bcma/driver_pci.c | 2 +-
+ 2 files changed, 3 insertions(+), 1 deletions(-)
+
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -46,6 +46,8 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
+ int bcma_sflash_init(struct bcma_drv_cc *cc);
+ #endif /* CONFIG_BCMA_SFLASH */
+
++u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
++
+ #ifdef CONFIG_BCMA_HOST_PCI
+ /* host_pci.c */
+ extern int __init bcma_host_pci_init(void);
+--- a/drivers/bcma/driver_pci.c
++++ b/drivers/bcma/driver_pci.c
+@@ -17,7 +17,7 @@
+ * R/W ops.
+ **************************************************/
+
+-static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
++u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
+ {
+ pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
+ pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
--- /dev/null
+From 3cd3138f2ef77e18abc99737c6740f35d61dbbb3 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 15 Jan 2012 23:05:05 +0100
+Subject: [PATCH 26/32] bcma: make some functions __devinit
+
+bcma_core_pci_hostmode_init() has to be in __devinit as it will call a
+function in that section and so all functions calling it also have to
+be in __devinit.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/bcma_private.h | 4 ++--
+ drivers/bcma/driver_pci.c | 6 +++---
+ drivers/bcma/driver_pci_host.c | 2 +-
+ drivers/bcma/host_pci.c | 4 ++--
+ drivers/bcma/main.c | 2 +-
+ include/linux/bcma/bcma_driver_pci.h | 2 +-
+ 6 files changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -13,7 +13,7 @@
+ struct bcma_bus;
+
+ /* main.c */
+-int bcma_bus_register(struct bcma_bus *bus);
++int __devinit 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,
+@@ -55,7 +55,7 @@ extern void __exit bcma_host_pci_exit(vo
+ #endif /* CONFIG_BCMA_HOST_PCI */
+
+ #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+-void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
++void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+ #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+
+ #endif
+--- a/drivers/bcma/driver_pci.c
++++ b/drivers/bcma/driver_pci.c
+@@ -174,12 +174,12 @@ static void bcma_pcicore_serdes_workarou
+ * Init.
+ **************************************************/
+
+-static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
++static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
+ {
+ bcma_pcicore_serdes_workaround(pc);
+ }
+
+-static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
++static bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
+ {
+ struct bcma_bus *bus = pc->core->bus;
+ u16 chipid_top;
+@@ -204,7 +204,7 @@ static bool bcma_core_pci_is_in_hostmode
+ return true;
+ }
+
+-void bcma_core_pci_init(struct bcma_drv_pci *pc)
++void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc)
+ {
+ if (pc->setup_done)
+ return;
+--- a/drivers/bcma/driver_pci_host.c
++++ b/drivers/bcma/driver_pci_host.c
+@@ -8,7 +8,7 @@
+ #include "bcma_private.h"
+ #include <linux/bcma/bcma.h>
+
+-void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
++void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+ {
+ pr_err("No support for PCI core in hostmode yet\n");
+ }
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -154,8 +154,8 @@ const struct bcma_host_ops bcma_host_pci
+ .awrite32 = bcma_host_pci_awrite32,
+ };
+
+-static int bcma_host_pci_probe(struct pci_dev *dev,
+- const struct pci_device_id *id)
++static int __devinit bcma_host_pci_probe(struct pci_dev *dev,
++ const struct pci_device_id *id)
+ {
+ struct bcma_bus *bus;
+ int err = -ENOMEM;
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -132,7 +132,7 @@ static void bcma_unregister_cores(struct
+ }
+ }
+
+-int bcma_bus_register(struct bcma_bus *bus)
++int __devinit bcma_bus_register(struct bcma_bus *bus)
+ {
+ int err;
+ struct bcma_device *core;
+--- a/include/linux/bcma/bcma_driver_pci.h
++++ b/include/linux/bcma/bcma_driver_pci.h
+@@ -169,7 +169,7 @@ struct bcma_drv_pci {
+ #define pcicore_read32(pc, offset) bcma_read32((pc)->core, offset)
+ #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val)
+
+-extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
++extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc);
+ extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
+ struct bcma_device *core, bool enable);
+
--- /dev/null
+From 47d0e8c2743729b4248585d33b55b6aaeac008d5 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 8 Jan 2012 16:53:15 +0100
+Subject: [PATCH 25/34] bcma: add PCIe host controller
+
+Some SoCs have a PCIe host controller to make it possible to attach
+some other devices to it, like an other Wifi card.
+This code was tested with an Netgear WNDR3400 (bcm4716 based), but
+should work with all bcma based SoCs.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/pci/pci-bcm47xx.c | 49 +++-
+ drivers/bcma/bcma_private.h | 1 +
+ drivers/bcma/driver_pci.c | 38 +--
+ drivers/bcma/driver_pci_host.c | 576 +++++++++++++++++++++++++++++++++-
+ include/linux/bcma/bcma_driver_pci.h | 34 ++
+ include/linux/bcma/bcma_regs.h | 27 ++
+ 6 files changed, 686 insertions(+), 39 deletions(-)
+
+--- a/arch/mips/pci/pci-bcm47xx.c
++++ b/arch/mips/pci/pci-bcm47xx.c
+@@ -25,6 +25,7 @@
+ #include <linux/types.h>
+ #include <linux/pci.h>
+ #include <linux/ssb/ssb.h>
++#include <linux/bcma/bcma.h>
+ #include <bcm47xx.h>
+
+ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+@@ -32,15 +33,12 @@ int __init pcibios_map_irq(const struct
+ return 0;
+ }
+
+-int pcibios_plat_dev_init(struct pci_dev *dev)
+-{
+ #ifdef CONFIG_BCM47XX_SSB
++static int bcm47xx_pcibios_plat_dev_init_ssb(struct pci_dev *dev)
++{
+ int res;
+ u8 slot, pin;
+
+- if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
+- return 0;
+-
+ res = ssb_pcibios_plat_dev_init(dev);
+ if (res < 0) {
+ printk(KERN_ALERT "PCI: Failed to init device %s\n",
+@@ -60,6 +58,47 @@ int pcibios_plat_dev_init(struct pci_dev
+ }
+
+ dev->irq = res;
++ return 0;
++}
+ #endif
++
++#ifdef CONFIG_BCM47XX_BCMA
++static int bcm47xx_pcibios_plat_dev_init_bcma(struct pci_dev *dev)
++{
++ int res;
++
++ res = bcma_core_pci_plat_dev_init(dev);
++ if (res < 0) {
++ printk(KERN_ALERT "PCI: Failed to init device %s\n",
++ pci_name(dev));
++ return res;
++ }
++
++ res = bcma_core_pci_pcibios_map_irq(dev);
++
++ /* IRQ-0 and IRQ-1 are software interrupts. */
++ if (res < 2) {
++ printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n",
++ pci_name(dev));
++ return res;
++ }
++
++ dev->irq = res;
+ return 0;
+ }
++#endif
++
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++#ifdef CONFIG_BCM47XX_SSB
++ if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_SSB)
++ return bcm47xx_pcibios_plat_dev_init_ssb(dev);
++ else
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA)
++ return bcm47xx_pcibios_plat_dev_init_bcma(dev);
++ else
++#endif
++ return 0;
++}
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -55,6 +55,7 @@ extern void __exit bcma_host_pci_exit(vo
+ #endif /* CONFIG_BCMA_HOST_PCI */
+
+ #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
++bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
+ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+ #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+
+--- a/drivers/bcma/driver_pci.c
++++ b/drivers/bcma/driver_pci.c
+@@ -2,7 +2,7 @@
+ * Broadcom specific AMBA
+ * PCI Core
+ *
+- * Copyright 2005, Broadcom Corporation
++ * Copyright 2005, 2011, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
+ *
+@@ -179,47 +179,19 @@ static void __devinit bcma_core_pci_clie
+ bcma_pcicore_serdes_workaround(pc);
+ }
+
+-static bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
+-{
+- struct bcma_bus *bus = pc->core->bus;
+- u16 chipid_top;
+-
+- chipid_top = (bus->chipinfo.id & 0xFF00);
+- if (chipid_top != 0x4700 &&
+- chipid_top != 0x5300)
+- return false;
+-
+-#ifdef CONFIG_SSB_DRIVER_PCICORE
+- if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
+- return false;
+-#endif /* CONFIG_SSB_DRIVER_PCICORE */
+-
+-#if 0
+- /* TODO: on BCMA we use address from EROM instead of magic formula */
+- u32 tmp;
+- return !mips_busprobe32(tmp, (bus->mmio +
+- (pc->core->core_index * BCMA_CORE_SIZE)));
+-#endif
+-
+- return true;
+-}
+-
+ void __devinit 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
++ pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
++ if (pc->hostmode)
+ bcma_core_pci_hostmode_init(pc);
+-#else
+- pr_err("Driver compiled without support for hostmode PCI\n");
+ #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+- } else {
+- bcma_core_pci_clientmode_init(pc);
+- }
+
+- pc->setup_done = true;
++ if (!pc->hostmode)
++ bcma_core_pci_clientmode_init(pc);
+ }
+
+ int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
+--- a/drivers/bcma/driver_pci_host.c
++++ b/drivers/bcma/driver_pci_host.c
+@@ -2,13 +2,587 @@
+ * Broadcom specific AMBA
+ * PCI Core in hostmode
+ *
++ * Copyright 2005 - 2011, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
++ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
++ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+ #include "bcma_private.h"
++#include <linux/export.h>
+ #include <linux/bcma/bcma.h>
++#include <asm/paccess.h>
++
++/* Probe a 32bit value on the bus and catch bus exceptions.
++ * Returns nonzero on a bus exception.
++ * This is MIPS specific */
++#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
++
++/* Assume one-hot slot wiring */
++#define BCMA_PCI_SLOT_MAX 16
++#define PCI_CONFIG_SPACE_SIZE 256
++
++bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
++{
++ struct bcma_bus *bus = pc->core->bus;
++ u16 chipid_top;
++ u32 tmp;
++
++ chipid_top = (bus->chipinfo.id & 0xFF00);
++ if (chipid_top != 0x4700 &&
++ chipid_top != 0x5300)
++ return false;
++
++ if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
++ pr_info("This PCI core is disabled and not working\n");
++ return false;
++ }
++
++ bcma_core_enable(pc->core, 0);
++
++ return !mips_busprobe32(tmp, pc->core->io_addr);
++}
++
++static u32 bcma_pcie_read_config(struct bcma_drv_pci *pc, u32 address)
++{
++ pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
++ pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
++ return pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_DATA);
++}
++
++static void bcma_pcie_write_config(struct bcma_drv_pci *pc, u32 address,
++ u32 data)
++{
++ pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
++ pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
++ pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_DATA, data);
++}
++
++static u32 bcma_get_cfgspace_addr(struct bcma_drv_pci *pc, unsigned int dev,
++ unsigned int func, unsigned int off)
++{
++ u32 addr = 0;
++
++ /* Issue config commands only when the data link is up (atleast
++ * one external pcie device is present).
++ */
++ if (dev >= 2 || !(bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_LSREG)
++ & BCMA_CORE_PCI_DLLP_LSREG_LINKUP))
++ goto out;
++
++ /* Type 0 transaction */
++ /* Slide the PCI window to the appropriate slot */
++ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI1, BCMA_CORE_PCI_SBTOPCI_CFG0);
++ /* Calculate the address */
++ addr = pc->host_controller->host_cfg_addr;
++ addr |= (dev << BCMA_CORE_PCI_CFG_SLOT_SHIFT);
++ addr |= (func << BCMA_CORE_PCI_CFG_FUN_SHIFT);
++ addr |= (off & ~3);
++
++out:
++ return addr;
++}
++
++static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
++ unsigned int func, unsigned int off,
++ void *buf, int len)
++{
++ int err = -EINVAL;
++ u32 addr, val;
++ void __iomem *mmio = 0;
++
++ WARN_ON(!pc->hostmode);
++ if (unlikely(len != 1 && len != 2 && len != 4))
++ goto out;
++ if (dev == 0) {
++ /* we support only two functions on device 0 */
++ if (func > 1)
++ return -EINVAL;
++
++ /* accesses to config registers with offsets >= 256
++ * requires indirect access.
++ */
++ if (off >= PCI_CONFIG_SPACE_SIZE) {
++ addr = (func << 12);
++ addr |= (off & 0x0FFF);
++ val = bcma_pcie_read_config(pc, addr);
++ } else {
++ addr = BCMA_CORE_PCI_PCICFG0;
++ addr |= (func << 8);
++ addr |= (off & 0xfc);
++ val = pcicore_read32(pc, addr);
++ }
++ } else {
++ addr = bcma_get_cfgspace_addr(pc, dev, func, off);
++ if (unlikely(!addr))
++ goto out;
++ err = -ENOMEM;
++ mmio = ioremap_nocache(addr, len);
++ if (!mmio)
++ goto out;
++
++ if (mips_busprobe32(val, mmio)) {
++ val = 0xffffffff;
++ goto unmap;
++ }
++
++ val = readl(mmio);
++ }
++ val >>= (8 * (off & 3));
++
++ switch (len) {
++ case 1:
++ *((u8 *)buf) = (u8)val;
++ break;
++ case 2:
++ *((u16 *)buf) = (u16)val;
++ break;
++ case 4:
++ *((u32 *)buf) = (u32)val;
++ break;
++ }
++ err = 0;
++unmap:
++ if (mmio)
++ iounmap(mmio);
++out:
++ return err;
++}
++
++static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
++ unsigned int func, unsigned int off,
++ const void *buf, int len)
++{
++ int err = -EINVAL;
++ u32 addr = 0, val = 0;
++ void __iomem *mmio = 0;
++ u16 chipid = pc->core->bus->chipinfo.id;
++
++ WARN_ON(!pc->hostmode);
++ if (unlikely(len != 1 && len != 2 && len != 4))
++ goto out;
++ if (dev == 0) {
++ /* accesses to config registers with offsets >= 256
++ * requires indirect access.
++ */
++ if (off < PCI_CONFIG_SPACE_SIZE) {
++ addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
++ addr |= (func << 8);
++ addr |= (off & 0xfc);
++ mmio = ioremap_nocache(addr, len);
++ if (!mmio)
++ goto out;
++ }
++ } else {
++ addr = bcma_get_cfgspace_addr(pc, dev, func, off);
++ if (unlikely(!addr))
++ goto out;
++ err = -ENOMEM;
++ mmio = ioremap_nocache(addr, len);
++ if (!mmio)
++ goto out;
++
++ if (mips_busprobe32(val, mmio)) {
++ val = 0xffffffff;
++ goto unmap;
++ }
++ }
++
++ switch (len) {
++ case 1:
++ val = readl(mmio);
++ val &= ~(0xFF << (8 * (off & 3)));
++ val |= *((const u8 *)buf) << (8 * (off & 3));
++ break;
++ case 2:
++ val = readl(mmio);
++ val &= ~(0xFFFF << (8 * (off & 3)));
++ val |= *((const u16 *)buf) << (8 * (off & 3));
++ break;
++ case 4:
++ val = *((const u32 *)buf);
++ break;
++ }
++ if (dev == 0 && !addr) {
++ /* accesses to config registers with offsets >= 256
++ * requires indirect access.
++ */
++ addr = (func << 12);
++ addr |= (off & 0x0FFF);
++ bcma_pcie_write_config(pc, addr, val);
++ } else {
++ writel(val, mmio);
++
++ if (chipid == 0x4716 || chipid == 0x4748)
++ readl(mmio);
++ }
++
++ err = 0;
++unmap:
++ if (mmio)
++ iounmap(mmio);
++out:
++ return err;
++}
++
++static int bcma_core_pci_hostmode_read_config(struct pci_bus *bus,
++ unsigned int devfn,
++ int reg, int size, u32 *val)
++{
++ unsigned long flags;
++ int err;
++ struct bcma_drv_pci *pc;
++ struct bcma_drv_pci_host *pc_host;
++
++ pc_host = container_of(bus->ops, struct bcma_drv_pci_host, pci_ops);
++ pc = pc_host->pdev;
++
++ spin_lock_irqsave(&pc_host->cfgspace_lock, flags);
++ err = bcma_extpci_read_config(pc, PCI_SLOT(devfn),
++ PCI_FUNC(devfn), reg, val, size);
++ spin_unlock_irqrestore(&pc_host->cfgspace_lock, flags);
++
++ return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static int bcma_core_pci_hostmode_write_config(struct pci_bus *bus,
++ unsigned int devfn,
++ int reg, int size, u32 val)
++{
++ unsigned long flags;
++ int err;
++ struct bcma_drv_pci *pc;
++ struct bcma_drv_pci_host *pc_host;
++
++ pc_host = container_of(bus->ops, struct bcma_drv_pci_host, pci_ops);
++ pc = pc_host->pdev;
++
++ spin_lock_irqsave(&pc_host->cfgspace_lock, flags);
++ err = bcma_extpci_write_config(pc, PCI_SLOT(devfn),
++ PCI_FUNC(devfn), reg, &val, size);
++ spin_unlock_irqrestore(&pc_host->cfgspace_lock, flags);
++
++ return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++/* return cap_offset if requested capability exists in the PCI config space */
++static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc,
++ unsigned int dev,
++ unsigned int func, u8 req_cap_id,
++ unsigned char *buf, u32 *buflen)
++{
++ u8 cap_id;
++ u8 cap_ptr = 0;
++ u32 bufsize;
++ u8 byte_val;
++
++ /* check for Header type 0 */
++ bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val,
++ sizeof(u8));
++ if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
++ return cap_ptr;
++
++ /* check if the capability pointer field exists */
++ bcma_extpci_read_config(pc, dev, func, PCI_STATUS, &byte_val,
++ sizeof(u8));
++ if (!(byte_val & PCI_STATUS_CAP_LIST))
++ return cap_ptr;
++
++ /* check if the capability pointer is 0x00 */
++ bcma_extpci_read_config(pc, dev, func, PCI_CAPABILITY_LIST, &cap_ptr,
++ sizeof(u8));
++ if (cap_ptr == 0x00)
++ return cap_ptr;
++
++ /* loop thr'u the capability list and see if the requested capabilty
++ * exists */
++ bcma_extpci_read_config(pc, dev, func, cap_ptr, &cap_id, sizeof(u8));
++ while (cap_id != req_cap_id) {
++ bcma_extpci_read_config(pc, dev, func, cap_ptr + 1, &cap_ptr,
++ sizeof(u8));
++ if (cap_ptr == 0x00)
++ return cap_ptr;
++ bcma_extpci_read_config(pc, dev, func, cap_ptr, &cap_id,
++ sizeof(u8));
++ }
++
++ /* found the caller requested capability */
++ if ((buf != NULL) && (buflen != NULL)) {
++ u8 cap_data;
++
++ bufsize = *buflen;
++ if (!bufsize)
++ return cap_ptr;
++
++ *buflen = 0;
++
++ /* copy the cpability data excluding cap ID and next ptr */
++ cap_data = cap_ptr + 2;
++ if ((bufsize + cap_data) > PCI_CONFIG_SPACE_SIZE)
++ bufsize = PCI_CONFIG_SPACE_SIZE - cap_data;
++ *buflen = bufsize;
++ while (bufsize--) {
++ bcma_extpci_read_config(pc, dev, func, cap_data, buf,
++ sizeof(u8));
++ cap_data++;
++ buf++;
++ }
++ }
++
++ return cap_ptr;
++}
++
++/* If the root port is capable of returning Config Request
++ * Retry Status (CRS) Completion Status to software then
++ * enable the feature.
++ */
++static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc)
++{
++ u8 cap_ptr, root_ctrl, root_cap, dev;
++ u16 val16;
++ int i;
++
++ cap_ptr = bcma_find_pci_capability(pc, 0, 0, PCI_CAP_ID_EXP, NULL,
++ NULL);
++ root_cap = cap_ptr + PCI_EXP_RTCAP;
++ bcma_extpci_read_config(pc, 0, 0, root_cap, &val16, sizeof(u16));
++ if (val16 & BCMA_CORE_PCI_RC_CRS_VISIBILITY) {
++ /* Enable CRS software visibility */
++ root_ctrl = cap_ptr + PCI_EXP_RTCTL;
++ val16 = PCI_EXP_RTCTL_CRSSVE;
++ bcma_extpci_read_config(pc, 0, 0, root_ctrl, &val16,
++ sizeof(u16));
++
++ /* Initiate a configuration request to read the vendor id
++ * field of the device function's config space header after
++ * 100 ms wait time from the end of Reset. If the device is
++ * not done with its internal initialization, it must at
++ * least return a completion TLP, with a completion status
++ * of "Configuration Request Retry Status (CRS)". The root
++ * complex must complete the request to the host by returning
++ * a read-data value of 0001h for the Vendor ID field and
++ * all 1s for any additional bytes included in the request.
++ * Poll using the config reads for max wait time of 1 sec or
++ * until we receive the successful completion status. Repeat
++ * the procedure for all the devices.
++ */
++ for (dev = 1; dev < BCMA_PCI_SLOT_MAX; dev++) {
++ for (i = 0; i < 100000; i++) {
++ bcma_extpci_read_config(pc, dev, 0,
++ PCI_VENDOR_ID, &val16,
++ sizeof(val16));
++ if (val16 != 0x1)
++ break;
++ udelay(10);
++ }
++ if (val16 == 0x1)
++ pr_err("PCI: Broken device in slot %d\n", dev);
++ }
++ }
++}
+
+ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+ {
+- pr_err("No support for PCI core in hostmode yet\n");
++ struct bcma_bus *bus = pc->core->bus;
++ struct bcma_drv_pci_host *pc_host;
++ u32 tmp;
++ u32 pci_membase_1G;
++ unsigned long io_map_base;
++
++ pr_info("PCIEcore in host mode found\n");
++
++ pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
++ if (!pc_host) {
++ pr_err("can not allocate memory");
++ return;
++ }
++
++ pc->host_controller = pc_host;
++ pc_host->pci_controller.io_resource = &pc_host->io_resource;
++ pc_host->pci_controller.mem_resource = &pc_host->mem_resource;
++ pc_host->pci_controller.pci_ops = &pc_host->pci_ops;
++ pc_host->pdev = pc;
++
++ pci_membase_1G = BCMA_SOC_PCI_DMA;
++ pc_host->host_cfg_addr = BCMA_SOC_PCI_CFG;
++
++ pc_host->pci_ops.read = bcma_core_pci_hostmode_read_config;
++ pc_host->pci_ops.write = bcma_core_pci_hostmode_write_config;
++
++ pc_host->mem_resource.name = "BCMA PCIcore external memory",
++ pc_host->mem_resource.start = BCMA_SOC_PCI_DMA;
++ pc_host->mem_resource.end = BCMA_SOC_PCI_DMA + BCMA_SOC_PCI_DMA_SZ - 1;
++ pc_host->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
++
++ pc_host->io_resource.name = "BCMA PCIcore external I/O",
++ pc_host->io_resource.start = 0x100;
++ pc_host->io_resource.end = 0x7FF;
++ pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
++
++ /* Reset RC */
++ udelay(3000);
++ pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
++ udelay(1000);
++ pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
++ BCMA_CORE_PCI_CTL_RST_OE);
++
++ /* 64 MB I/O access window. On 4716, use
++ * sbtopcie0 to access the device registers. We
++ * can't use address match 2 (1 GB window) region
++ * as mips can't generate 64-bit address on the
++ * backplane.
++ */
++ if (bus->chipinfo.id == 0x4716 || bus->chipinfo.id == 0x4748) {
++ pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
++ pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
++ BCMA_SOC_PCI_MEM_SZ - 1;
++ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
++ BCMA_CORE_PCI_SBTOPCI_MEM | BCMA_SOC_PCI_MEM);
++ } else if (bus->chipinfo.id == 0x5300) {
++ tmp = BCMA_CORE_PCI_SBTOPCI_MEM;
++ tmp |= BCMA_CORE_PCI_SBTOPCI_PREF;
++ tmp |= BCMA_CORE_PCI_SBTOPCI_BURST;
++ if (pc->core->core_unit == 0) {
++ pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
++ pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
++ BCMA_SOC_PCI_MEM_SZ - 1;
++ pci_membase_1G = BCMA_SOC_PCIE_DMA_H32;
++ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
++ tmp | BCMA_SOC_PCI_MEM);
++ } else if (pc->core->core_unit == 1) {
++ pc_host->mem_resource.start = BCMA_SOC_PCI1_MEM;
++ pc_host->mem_resource.end = BCMA_SOC_PCI1_MEM +
++ BCMA_SOC_PCI_MEM_SZ - 1;
++ pci_membase_1G = BCMA_SOC_PCIE1_DMA_H32;
++ pc_host->host_cfg_addr = BCMA_SOC_PCI1_CFG;
++ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
++ tmp | BCMA_SOC_PCI1_MEM);
++ }
++ } else
++ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
++ BCMA_CORE_PCI_SBTOPCI_IO);
++
++ /* 64 MB configuration access window */
++ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI1, BCMA_CORE_PCI_SBTOPCI_CFG0);
++
++ /* 1 GB memory access window */
++ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI2,
++ BCMA_CORE_PCI_SBTOPCI_MEM | pci_membase_1G);
++
++
++ /* As per PCI Express Base Spec 1.1 we need to wait for
++ * at least 100 ms from the end of a reset (cold/warm/hot)
++ * before issuing configuration requests to PCI Express
++ * devices.
++ */
++ udelay(100000);
++
++ bcma_core_pci_enable_crs(pc);
++
++ /* Enable PCI bridge BAR0 memory & master access */
++ tmp = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
++ bcma_extpci_write_config(pc, 0, 0, PCI_COMMAND, &tmp, sizeof(tmp));
++
++ /* Enable PCI interrupts */
++ pcicore_write32(pc, BCMA_CORE_PCI_IMASK, BCMA_CORE_PCI_IMASK_INTA);
++
++ /* Ok, ready to run, register it to the system.
++ * The following needs change, if we want to port hostmode
++ * to non-MIPS platform. */
++ io_map_base = (unsigned long)ioremap_nocache(BCMA_SOC_PCI_MEM,
++ 0x04000000);
++ pc_host->pci_controller.io_map_base = io_map_base;
++ set_io_port_base(pc_host->pci_controller.io_map_base);
++ /* Give some time to the PCI controller to configure itself with the new
++ * values. Not waiting at this point causes crashes of the machine. */
++ mdelay(10);
++ register_pci_controller(&pc_host->pci_controller);
++ return;
++}
++
++/* Early PCI fixup for a device on the PCI-core bridge. */
++static void bcma_core_pci_fixup_pcibridge(struct pci_dev *dev)
++{
++ if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
++ /* This is not a device on the PCI-core bridge. */
++ return;
++ }
++ if (PCI_SLOT(dev->devfn) != 0)
++ return;
++
++ pr_info("PCI: Fixing up bridge %s\n", pci_name(dev));
++
++ /* Enable PCI bridge bus mastering and memory space */
++ pci_set_master(dev);
++ if (pcibios_enable_device(dev, ~0) < 0) {
++ pr_err("PCI: BCMA bridge enable failed\n");
++ return;
++ }
++
++ /* Enable PCI bridge BAR1 prefetch and burst */
++ pci_write_config_dword(dev, BCMA_PCI_BAR1_CONTROL, 3);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_pcibridge);
++
++/* Early PCI fixup for all PCI-cores to set the correct memory address. */
++static void bcma_core_pci_fixup_addresses(struct pci_dev *dev)
++{
++ struct resource *res;
++ int pos;
++
++ if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
++ /* This is not a device on the PCI-core bridge. */
++ return;
++ }
++ if (PCI_SLOT(dev->devfn) == 0)
++ return;
++
++ pr_info("PCI: Fixing up addresses %s\n", pci_name(dev));
++
++ for (pos = 0; pos < 6; pos++) {
++ res = &dev->resource[pos];
++ if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM))
++ pci_assign_resource(dev, pos);
++ }
++}
++DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_addresses);
++
++/* This function is called when doing a pci_enable_device().
++ * We must first check if the device is a device on the PCI-core bridge. */
++int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
++{
++ struct bcma_drv_pci_host *pc_host;
++
++ if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
++ /* This is not a device on the PCI-core bridge. */
++ return -ENODEV;
++ }
++ pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
++ pci_ops);
++
++ pr_info("PCI: Fixing up device %s\n", pci_name(dev));
++
++ /* Fix up interrupt lines */
++ dev->irq = bcma_core_mips_irq(pc_host->pdev->core) + 2;
++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
++
++ return 0;
++}
++EXPORT_SYMBOL(bcma_core_pci_plat_dev_init);
++
++/* PCI device IRQ mapping. */
++int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
++{
++ struct bcma_drv_pci_host *pc_host;
++
++ if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
++ /* This is not a device on the PCI-core bridge. */
++ return -ENODEV;
++ }
++
++ pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
++ pci_ops);
++ return bcma_core_mips_irq(pc_host->pdev->core) + 2;
+ }
++EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
+--- a/include/linux/bcma/bcma_driver_pci.h
++++ b/include/linux/bcma/bcma_driver_pci.h
+@@ -160,9 +160,40 @@ struct pci_dev;
+ /* PCIcore specific boardflags */
+ #define BCMA_CORE_PCI_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
+
++/* PCIE Config space accessing MACROS */
++#define BCMA_CORE_PCI_CFG_BUS_SHIFT 24 /* Bus shift */
++#define BCMA_CORE_PCI_CFG_SLOT_SHIFT 19 /* Slot/Device shift */
++#define BCMA_CORE_PCI_CFG_FUN_SHIFT 16 /* Function shift */
++#define BCMA_CORE_PCI_CFG_OFF_SHIFT 0 /* Register shift */
++
++#define BCMA_CORE_PCI_CFG_BUS_MASK 0xff /* Bus mask */
++#define BCMA_CORE_PCI_CFG_SLOT_MASK 0x1f /* Slot/Device mask */
++#define BCMA_CORE_PCI_CFG_FUN_MASK 7 /* Function mask */
++#define BCMA_CORE_PCI_CFG_OFF_MASK 0xfff /* Register mask */
++
++/* PCIE Root Capability Register bits (Host mode only) */
++#define BCMA_CORE_PCI_RC_CRS_VISIBILITY 0x0001
++
++struct bcma_drv_pci;
++
++struct bcma_drv_pci_host {
++ struct bcma_drv_pci *pdev;
++
++ u32 host_cfg_addr;
++ spinlock_t cfgspace_lock;
++
++ struct pci_controller pci_controller;
++ struct pci_ops pci_ops;
++ struct resource mem_resource;
++ struct resource io_resource;
++};
++
+ struct bcma_drv_pci {
+ struct bcma_device *core;
+ u8 setup_done:1;
++ u8 hostmode:1;
++
++ struct bcma_drv_pci_host *host_controller;
+ };
+
+ /* Register access */
+@@ -173,4 +204,7 @@ extern void __devinit bcma_core_pci_init
+ extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
+ struct bcma_device *core, bool enable);
+
++extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
++extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
++
+ #endif /* LINUX_BCMA_DRIVER_PCI_H_ */
+--- a/include/linux/bcma/bcma_regs.h
++++ b/include/linux/bcma/bcma_regs.h
+@@ -56,4 +56,31 @@
+ #define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
+ #define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
+
++/* SiliconBackplane Address Map.
++ * All regions may not exist on all chips.
++ */
++#define BCMA_SOC_SDRAM_BASE 0x00000000U /* Physical SDRAM */
++#define BCMA_SOC_PCI_MEM 0x08000000U /* Host Mode sb2pcitranslation0 (64 MB) */
++#define BCMA_SOC_PCI_MEM_SZ (64 * 1024 * 1024)
++#define BCMA_SOC_PCI_CFG 0x0c000000U /* Host Mode sb2pcitranslation1 (64 MB) */
++#define BCMA_SOC_SDRAM_SWAPPED 0x10000000U /* Byteswapped Physical SDRAM */
++#define BCMA_SOC_SDRAM_R2 0x80000000U /* Region 2 for sdram (512 MB) */
++
++
++#define BCMA_SOC_PCI_DMA 0x40000000U /* Client Mode sb2pcitranslation2 (1 GB) */
++#define BCMA_SOC_PCI_DMA2 0x80000000U /* Client Mode sb2pcitranslation2 (1 GB) */
++#define BCMA_SOC_PCI_DMA_SZ 0x40000000U /* Client Mode sb2pcitranslation2 size in bytes */
++#define BCMA_SOC_PCIE_DMA_L32 0x00000000U /* PCIE Client Mode sb2pcitranslation2
++ * (2 ZettaBytes), low 32 bits
++ */
++#define BCMA_SOC_PCIE_DMA_H32 0x80000000U /* PCIE Client Mode sb2pcitranslation2
++ * (2 ZettaBytes), high 32 bits
++ */
++
++#define BCMA_SOC_PCI1_MEM 0x40000000U /* Host Mode sb2pcitranslation0 (64 MB) */
++#define BCMA_SOC_PCI1_CFG 0x44000000U /* Host Mode sb2pcitranslation1 (64 MB) */
++#define BCMA_SOC_PCIE1_DMA_H32 0xc0000000U /* PCIE Client Mode sb2pcitranslation2
++ * (2 ZettaBytes), high 32 bits
++ */
++
+ #endif /* LINUX_BCMA_REGS_H_ */
--- /dev/null
+From eecd733c14952b074d7488934a4f3dc83c9c426b Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 14 Jan 2012 16:29:51 +0100
+Subject: [PATCH 28/32] bcma: add bus num counter
+
+If we have two bcma buses on one computer the second will not work
+without this patch. Now each bus gets an own number.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/main.c | 12 +++++++++++-
+ include/linux/bcma/bcma.h | 1 +
+ 2 files changed, 12 insertions(+), 1 deletions(-)
+
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -13,6 +13,12 @@
+ MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
+ MODULE_LICENSE("GPL");
+
++/* contains the number the next bus should get. */
++static unsigned int bcma_bus_next_num = 0;
++
++/* bcma_buses_mutex locks the bcma_bus_next_num */
++static DEFINE_MUTEX(bcma_buses_mutex);
++
+ static int bcma_bus_match(struct device *dev, struct device_driver *drv);
+ static int bcma_device_probe(struct device *dev);
+ static int bcma_device_remove(struct device *dev);
+@@ -93,7 +99,7 @@ static int bcma_register_cores(struct bc
+
+ core->dev.release = bcma_release_core_dev;
+ core->dev.bus = &bcma_bus_type;
+- dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
++ dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
+
+ switch (bus->hosttype) {
+ case BCMA_HOSTTYPE_PCI:
+@@ -137,6 +143,10 @@ int __devinit bcma_bus_register(struct b
+ int err;
+ struct bcma_device *core;
+
++ mutex_lock(&bcma_buses_mutex);
++ bus->num = bcma_bus_next_num++;
++ mutex_unlock(&bcma_buses_mutex);
++
+ /* Scan for devices (cores) */
+ err = bcma_bus_scan(bus);
+ if (err) {
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -196,6 +196,7 @@ struct bcma_bus {
+ struct list_head cores;
+ u8 nr_cores;
+ u8 init_done:1;
++ u8 num;
+
+ struct bcma_drv_cc drv_cc;
+ struct bcma_drv_pci drv_pci;
--- /dev/null
+From 1cd3d0de72e42161fe0df355c5429459265aeef0 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 14 Jan 2012 16:11:17 +0100
+Subject: [PATCH 30/32] bcma: add extra sprom check
+
+This check is needed on the BCM43224 device as it says in the
+capabilities it has an sprom but is extra check says it has not.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/sprom.c | 8 ++++++++
+ include/linux/bcma/bcma_driver_chipcommon.h | 16 ++++++++++++++++
+ 2 files changed, 24 insertions(+), 0 deletions(-)
+
+--- a/drivers/bcma/sprom.c
++++ b/drivers/bcma/sprom.c
+@@ -209,6 +209,7 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ {
+ u16 offset;
+ u16 *sprom;
++ u32 sromctrl;
+ int err = 0;
+
+ if (!bus->drv_cc.core)
+@@ -217,6 +218,12 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
+ return -ENOENT;
+
++ if (bus->drv_cc.core->id.rev >= 32) {
++ sromctrl = bcma_read32(bus->drv_cc.core, BCMA_CC_SROM_CONTROL);
++ if (!(sromctrl & BCMA_CC_SROM_CONTROL_PRESENT))
++ return -ENOENT;
++ }
++
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ GFP_KERNEL);
+ if (!sprom)
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -239,6 +239,22 @@
+ #define BCMA_CC_FLASH_CFG 0x0128
+ #define BCMA_CC_FLASH_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */
+ #define BCMA_CC_FLASH_WAITCNT 0x012C
++#define BCMA_CC_SROM_CONTROL 0x0190
++#define BCMA_CC_SROM_CONTROL_START 0x80000000
++#define BCMA_CC_SROM_CONTROL_BUSY 0x80000000
++#define BCMA_CC_SROM_CONTROL_OPCODE 0x60000000
++#define BCMA_CC_SROM_CONTROL_OP_READ 0x00000000
++#define BCMA_CC_SROM_CONTROL_OP_WRITE 0x20000000
++#define BCMA_CC_SROM_CONTROL_OP_WRDIS 0x40000000
++#define BCMA_CC_SROM_CONTROL_OP_WREN 0x60000000
++#define BCMA_CC_SROM_CONTROL_OTPSEL 0x00000010
++#define BCMA_CC_SROM_CONTROL_LOCK 0x00000008
++#define BCMA_CC_SROM_CONTROL_SIZE_MASK 0x00000006
++#define BCMA_CC_SROM_CONTROL_SIZE_1K 0x00000000
++#define BCMA_CC_SROM_CONTROL_SIZE_4K 0x00000002
++#define BCMA_CC_SROM_CONTROL_SIZE_16K 0x00000004
++#define BCMA_CC_SROM_CONTROL_SIZE_SHIFT 1
++#define BCMA_CC_SROM_CONTROL_PRESENT 0x00000001
+ /* 0x1E0 is defined as shared BCMA_CLKCTLST */
+ #define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
+ #define BCMA_CC_UART0_DATA 0x0300
--- /dev/null
+From 699c57a18b40ffbe1763915acdc1a3e4fb539d01 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri, 13 Jan 2012 17:42:15 +0100
+Subject: [PATCH 29/32] bcma: add new PCI ID
+
+This ID was found on the PCIe wireless card on the board of a Netgear
+WNDR3400 using a bcm4716. The device with this ID is identified by b43
+as "Broadcom 43224 WLAN".
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/host_pci.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -278,6 +278,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0xa8d8) },
+ { 0, },
+ };
+ MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
--- /dev/null
+From f6e41db3ee7ead99e1398def222c14893fc265de Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 4 Aug 2011 21:09:48 +0200
+Subject: [PATCH 26/26] bcma: export needed gpio functions
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/driver_chipcommon.c | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -81,16 +81,19 @@ u32 bcma_chipco_gpio_in(struct bcma_drv_
+ {
+ return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask;
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_gpio_in);
+
+ u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
+ {
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_gpio_out);
+
+ u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
+ {
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen);
+
+ u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
+ {
+@@ -102,11 +105,13 @@ u32 bcma_chipco_gpio_intmask(struct bcma
+ {
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_gpio_intmask);
+
+ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
+ {
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_gpio_polarity);
+
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
--- /dev/null
+From 7b90e7040b9783b91a4e2baf72ac32d3a00f9f2d Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 21 Jan 2012 11:18:25 +0100
+Subject: [PATCH 31/34] ssb: fix cardbus in hostmode
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/ssb/driver_pcicore.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+--- a/drivers/ssb/driver_pcicore.c
++++ b/drivers/ssb/driver_pcicore.c
+@@ -75,7 +75,7 @@ static u32 get_cfgspace_addr(struct ssb_
+ u32 tmp;
+
+ /* We do only have one cardbus device behind the bridge. */
+- if (pc->cardbusmode && (dev >= 1))
++ if (pc->cardbusmode && (dev > 1))
+ goto out;
+
+ if (bus == 0) {
--- /dev/null
+From efe89df0326b777563d197b8cf1c25209a31ceb0 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 21 Jan 2012 18:47:42 +0100
+Subject: [PATCH 32/34] bcma: complete workaround for BCMA43224
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/driver_chipcommon_pmu.c | 15 +++++++++++----
+ include/linux/bcma/bcma_driver_chipcommon.h | 5 +++++
+ 2 files changed, 16 insertions(+), 4 deletions(-)
+
+--- a/drivers/bcma/driver_chipcommon_pmu.c
++++ b/drivers/bcma/driver_chipcommon_pmu.c
+@@ -141,12 +141,19 @@ void bcma_pmu_workarounds(struct bcma_dr
+ /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
+ break;
+ case 43224:
++ case 43421:
++ /* enable 12 mA drive strenth for 43224 and set chipControl register bit 15 */
+ if (bus->chipinfo.rev == 0) {
+- pr_err("Workarounds for 43224 rev 0 not fully "
+- "implemented\n");
+- bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x00F000F0);
++ bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL,
++ BCMA_CCTRL_43224_GPIO_TOGGLE,
++ BCMA_CCTRL_43224_GPIO_TOGGLE);
++ bcma_chipco_chipctl_maskset(cc, 0,
++ BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
++ BCMA_CCTRL_43224A0_12MA_LED_DRIVE);
+ } else {
+- bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
++ bcma_chipco_chipctl_maskset(cc, 0,
++ BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
++ BCMA_CCTRL_43224B0_12MA_LED_DRIVE);
+ }
+ break;
+ case 43225:
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -374,6 +374,11 @@
+ #define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4 BIT(16) /* enable bt_shd0 at gpio4 */
+ #define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5 BIT(17) /* enable bt_shd1 at gpio5 */
+
++/* 43224 chip-specific ChipControl register bits */
++#define BCMA_CCTRL_43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */
++#define BCMA_CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */
++#define BCMA_CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */
++
+ #define BCMA_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
+ #define BCMA_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
+ #define BCMA_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
--- /dev/null
+From 293fcc92dae1284c35a3bb51e7f9eb13b52e58fe Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Tue, 31 Jan 2012 23:36:44 +0100
+Subject: [PATCH 2/4] bcma: log the id, rev and pkg of the chip found
+
+This makes us see what type of hardware someone uses by the dmesg
+output.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/scan.c | 10 +++++++---
+ 1 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -364,6 +364,7 @@ static int bcma_get_next_core(struct bcm
+ void bcma_init_bus(struct bcma_bus *bus)
+ {
+ s32 tmp;
++ struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
+
+ if (bus->init_done)
+ return;
+@@ -374,9 +375,12 @@ void bcma_init_bus(struct bcma_bus *bus)
+ bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
+
+ tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
+- 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;
++ chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
++ chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
++ chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++ pr_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
++ chipinfo->id, chipinfo->rev, chipinfo->pkg);
++
+ bus->init_done = true;
+ }
+
--- /dev/null
+From 7ddcc963030bbc82add2efbd49e696ae8aff3ae6 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Tue, 31 Jan 2012 23:38:36 +0100
+Subject: [PATCH 3/4] ssb: log the id, rev and pkg of the chip found
+
+This makes us see what type of hardware someone uses by the dmesg
+output.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/ssb/scan.c | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+--- a/drivers/ssb/scan.c
++++ b/drivers/ssb/scan.c
+@@ -318,6 +318,9 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ bus->chip_package = 0;
+ }
+ }
++ ssb_printk(KERN_INFO PFX "Found chip with id 0x%04X, rev 0x%02X and "
++ "package 0x%02X\n", bus->chip_id, bus->chip_rev,
++ bus->chip_package);
+ if (!bus->nr_devices)
+ bus->nr_devices = chipid_to_nrcores(bus->chip_id);
+ if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
--- /dev/null
+From 9be402f069cc259ad5795b77567d66c4e7f6bef6 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 18 Jul 2010 14:59:24 +0200
+Subject: [PATCH 4/6] MIPS: BCM47xx: Setup and register serial early
+
+Swap the first and second serial if console=ttyS1 was set.
+Set it up and register it for early serial support.
+
+This patch has been in OpenWRT for a long time.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/setup.c | 39 ++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 38 insertions(+), 1 deletions(-)
+
+--- a/arch/mips/bcm47xx/setup.c
++++ b/arch/mips/bcm47xx/setup.c
+@@ -32,6 +32,8 @@
+ #include <linux/ssb/ssb_embedded.h>
+ #include <linux/bcma/bcma_soc.h>
+ #include <linux/platform_device.h>
++#include <linux/serial.h>
++#include <linux/serial_8250.h>
+ #include <asm/bootinfo.h>
+ #include <asm/reboot.h>
+ #include <asm/time.h>
+@@ -279,6 +281,31 @@ static int bcm47xx_get_invariants(struct
+ return 0;
+ }
+
++#ifdef CONFIG_SERIAL_8250
++static void __init bcm47xx_early_serial_setup(struct ssb_mipscore *mcore)
++{
++ int i;
++
++ for (i = 0; i < mcore->nr_serial_ports; i++) {
++ struct ssb_serial_port *port = &(mcore->serial_ports[i]);
++ struct uart_port s;
++
++ memset(&s, 0, sizeof(s));
++ s.line = i;
++ s.mapbase = (unsigned int) port->regs;
++ s.membase = port->regs;
++ s.irq = port->irq + 2;
++ s.uartclk = port->baud_base;
++ s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
++ s.iotype = SERIAL_IO_MEM;
++ s.regshift = port->reg_shift;
++
++ early_serial_setup(&s);
++ }
++ printk(KERN_DEBUG "Serial init done.\n");
++}
++#endif
++
+ static void __init bcm47xx_register_ssb(void)
+ {
+ int err;
+@@ -311,6 +338,10 @@ static void __init bcm47xx_register_ssb(
+ memcpy(&mcore->serial_ports[1], &port, sizeof(port));
+ }
+ }
++
++#ifdef CONFIG_SERIAL_8250
++ bcm47xx_early_serial_setup(mcore);
++#endif
+ }
+ #endif
+
--- /dev/null
+From 5219981646071abb6731634bf47781a53e248764 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 18 Jul 2010 15:11:26 +0200
+Subject: [PATCH 6/6] MIPS: BCM47xx: Remove CFE console
+
+Do not use the CFE console. It causes hangs on some devices like the
+Buffalo WHR-HP-G54.
+This was reported in https://dev.openwrt.org/ticket/4061 and
+https://forum.openwrt.org/viewtopic.php?id=17063
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/Kconfig | 1 -
+ arch/mips/bcm47xx/prom.c | 82 +++------------------------------------------
+ 2 files changed, 6 insertions(+), 77 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -97,7 +97,6 @@ config BCM47XX
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select GENERIC_GPIO
+- select SYS_HAS_EARLY_PRINTK
+ select CFE
+ help
+ Support for BCM47XX based boards
+--- a/arch/mips/bcm47xx/prom.c
++++ b/arch/mips/bcm47xx/prom.c
+@@ -31,96 +31,28 @@
+ #include <asm/fw/cfe/cfe_api.h>
+ #include <asm/fw/cfe/cfe_error.h>
+
+-static int cfe_cons_handle;
+-
+ const char *get_system_type(void)
+ {
+ return "Broadcom BCM47XX";
+ }
+
+-void prom_putchar(char c)
+-{
+- while (cfe_write(cfe_cons_handle, &c, 1) == 0)
+- ;
+-}
+-
+-static __init void prom_init_cfe(void)
++static __init int prom_init_cfe(void)
+ {
+ uint32_t cfe_ept;
+ uint32_t cfe_handle;
+ uint32_t cfe_eptseal;
+- int argc = fw_arg0;
+- char **envp = (char **) fw_arg2;
+- int *prom_vec = (int *) fw_arg3;
+-
+- /*
+- * Check if a loader was used; if NOT, the 4 arguments are
+- * what CFE gives us (handle, 0, EPT and EPTSEAL)
+- */
+- if (argc < 0) {
+- cfe_handle = (uint32_t)argc;
+- cfe_ept = (uint32_t)envp;
+- cfe_eptseal = (uint32_t)prom_vec;
+- } else {
+- if ((int)prom_vec < 0) {
+- /*
+- * Old loader; all it gives us is the handle,
+- * so use the "known" entrypoint and assume
+- * the seal.
+- */
+- cfe_handle = (uint32_t)prom_vec;
+- cfe_ept = 0xBFC00500;
+- cfe_eptseal = CFE_EPTSEAL;
+- } else {
+- /*
+- * Newer loaders bundle the handle/ept/eptseal
+- * Note: prom_vec is in the loader's useg
+- * which is still alive in the TLB.
+- */
+- cfe_handle = prom_vec[0];
+- cfe_ept = prom_vec[2];
+- cfe_eptseal = prom_vec[3];
+- }
+- }
++
++ cfe_eptseal = (uint32_t) fw_arg3;
++ cfe_handle = (uint32_t) fw_arg0;
++ cfe_ept = (uint32_t) fw_arg2;
+
+ if (cfe_eptseal != CFE_EPTSEAL) {
+- /* too early for panic to do any good */
+ printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
+- while (1) ;
++ return -1;
+ }
+
+ cfe_init(cfe_handle, cfe_ept);
+-}
+-
+-static __init void prom_init_console(void)
+-{
+- /* Initialize CFE console */
+- cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
+-}
+-
+-static __init void prom_init_cmdline(void)
+-{
+- static char buf[COMMAND_LINE_SIZE] __initdata;
+-
+- /* Get the kernel command line from CFE */
+- if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) {
+- buf[COMMAND_LINE_SIZE - 1] = 0;
+- strcpy(arcs_cmdline, buf);
+- }
+-
+- /* Force a console handover by adding a console= argument if needed,
+- * as CFE is not available anymore later in the boot process. */
+- if ((strstr(arcs_cmdline, "console=")) == NULL) {
+- /* Try to read the default serial port used by CFE */
+- if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0)
+- || (strncmp("uart", buf, 4)))
+- /* Default to uart0 */
+- strcpy(buf, "uart0");
+-
+- /* Compute the new command line */
+- snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200",
+- arcs_cmdline, buf[4]);
+- }
++ return 0;
+ }
+
+ static __init void prom_init_mem(void)
+@@ -161,8 +93,6 @@ static __init void prom_init_mem(void)
+ void __init prom_init(void)
+ {
+ prom_init_cfe();
+- prom_init_console();
+- prom_init_cmdline();
+ prom_init_mem();
+ }
+
--- /dev/null
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -121,14 +121,6 @@
+ #endif
+ .endm
+
+-#ifndef CONFIG_NO_EXCEPT_FILL
+- /*
+- * Reserved space for exception handlers.
+- * Necessary for machines which link their kernels at KSEG0.
+- */
+- .fill 0x400
+-#endif
+-
+ EXPORT(_stext)
+
+ #ifdef CONFIG_BOOT_RAW
+@@ -141,6 +133,14 @@ FEXPORT(__kernel_entry)
+ j kernel_entry
+ #endif
+
++#ifndef CONFIG_NO_EXCEPT_FILL
++ /*
++ * Reserved space for exception handlers.
++ * Necessary for machines which link their kernels at KSEG0.
++ */
++ .fill 0x400
++#endif
++
+ #ifdef CONFIG_IMAGE_CMDLINE_HACK
+ .ascii "CMDLINE:"
+ EXPORT(__image_cmdline)
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -89,6 +89,7 @@ config ATH79
+
+ config BCM47XX
+ bool "Broadcom BCM47XX based boards"
++ select BOOT_RAW
+ select CEVT_R4K
+ select CSRC_R4K
+ select DMA_NONCOHERENT
--- /dev/null
+--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
++++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
+@@ -151,5 +151,9 @@ static inline int gpio_polarity(unsigned
+ return -EINVAL;
+ }
+
++static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
++{
++ return -ENOSYS;
++}
+
+ #endif /* __BCM47XX_GPIO_H */