From: hauke Date: Wed, 14 Mar 2012 21:48:23 +0000 (+0000) Subject: brcm47xx: move and rename the patches X-Git-Url: https://git.rohieb.name/openwrt.git/commitdiff_plain/40687c51624402412a0b6734bfb57609113f7f1d brcm47xx: move and rename the patches The patches are now grouped by the part what they are doing and are using three digest numbers. This does not remove or adds anything git-svn-id: svn://svn.openwrt.org/openwrt/trunk@30942 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- diff --git a/target/linux/brcm47xx/patches-3.2/000-pci-backport.patch b/target/linux/brcm47xx/patches-3.2/000-pci-backport.patch new file mode 100644 index 000000000..b1eed44d6 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/000-pci-backport.patch @@ -0,0 +1,2210 @@ +--- 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 ++ ++---------------------------- ++ ++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 +--- 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 : ""); + +- /* 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 : ""); + ++ /* 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 + #include + #include ++#include + + #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); diff --git a/target/linux/brcm47xx/patches-3.2/0000-pci-backport.patch b/target/linux/brcm47xx/patches-3.2/0000-pci-backport.patch deleted file mode 100644 index b1eed44d6..000000000 --- a/target/linux/brcm47xx/patches-3.2/0000-pci-backport.patch +++ /dev/null @@ -1,2210 +0,0 @@ ---- 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 -+ -+---------------------------- -+ -+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 ---- 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 : ""); - -- /* 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 : ""); - -+ /* 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 - #include - #include -+#include - - #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); diff --git a/target/linux/brcm47xx/patches-3.2/0012-bcma-move-parallel-flash-into-a-union.patch b/target/linux/brcm47xx/patches-3.2/0012-bcma-move-parallel-flash-into-a-union.patch deleted file mode 100644 index 11855b449..000000000 --- a/target/linux/brcm47xx/patches-3.2/0012-bcma-move-parallel-flash-into-a-union.patch +++ /dev/null @@ -1,142 +0,0 @@ -From b7d9f9cd6a8e463c1061ea29ed3e614403625024 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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]; diff --git a/target/linux/brcm47xx/patches-3.2/0013-bcma-add-serial-flash-support-to-bcma.patch b/target/linux/brcm47xx/patches-3.2/0013-bcma-add-serial-flash-support-to-bcma.patch deleted file mode 100644 index e78f3c457..000000000 --- a/target/linux/brcm47xx/patches-3.2/0013-bcma-add-serial-flash-support-to-bcma.patch +++ /dev/null @@ -1,681 +0,0 @@ -From a62940e988526c881966a8c72cc28c95fca89f3c Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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 -+ * Copyright 2010, Broadcom Corporation -+ * -+ * Licensed under the GNU/GPL. See COPYING for details. -+ */ -+ -+#include -+#include -+#include -+ -+#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_ */ diff --git a/target/linux/brcm47xx/patches-3.2/0014-ssb-move-flash-to-chipcommon.patch b/target/linux/brcm47xx/patches-3.2/0014-ssb-move-flash-to-chipcommon.patch deleted file mode 100644 index 91d8acb26..000000000 --- a/target/linux/brcm47xx/patches-3.2/0014-ssb-move-flash-to-chipcommon.patch +++ /dev/null @@ -1,149 +0,0 @@ -From e8afde87ecf56beff67c7d5371cabaa4fc018541 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Sat, 23 Jul 2011 23:57:06 +0200 -Subject: [PATCH 14/26] ssb: move flash to chipcommon - - -Signed-off-by: Hauke Mehrtens ---- - 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); diff --git a/target/linux/brcm47xx/patches-3.2/0015-ssb-add-serial-flash-support.patch b/target/linux/brcm47xx/patches-3.2/0015-ssb-add-serial-flash-support.patch deleted file mode 100644 index e91c2a44f..000000000 --- a/target/linux/brcm47xx/patches-3.2/0015-ssb-add-serial-flash-support.patch +++ /dev/null @@ -1,697 +0,0 @@ -From 980da78179592a3f5f99168bc5af415835aa8c13 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Sun, 24 Jul 2011 20:20:36 +0200 -Subject: [PATCH 15/26] ssb: add serial flash support - - -Signed-off-by: Hauke Mehrtens ---- - 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 -+ * Copyright 2010, Broadcom Corporation -+ * -+ * Licensed under the GNU/GPL. See COPYING for details. -+ */ -+ -+#include -+#include -+#include -+ -+#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); - diff --git a/target/linux/brcm47xx/patches-3.2/0016-brcm47xx-add-common-interface-for-sflash.patch b/target/linux/brcm47xx/patches-3.2/0016-brcm47xx-add-common-interface-for-sflash.patch deleted file mode 100644 index 6caa9180d..000000000 --- a/target/linux/brcm47xx/patches-3.2/0016-brcm47xx-add-common-interface-for-sflash.patch +++ /dev/null @@ -1,193 +0,0 @@ -From 4f314ac9edbc80897f158fdb4e1b1de8a2d0d432 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Sun, 24 Jul 2011 21:10:49 +0200 -Subject: [PATCH 16/26] brcm47xx: add common interface for sflash - - -Signed-off-by: Hauke Mehrtens ---- - 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 -+ * -+ * 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 -+ -+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 -+ * -+ * 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 -+#include -+#include -+ -+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; diff --git a/target/linux/brcm47xx/patches-3.2/0017-mtd-bcm47xx-add-bcm47xx-part-parser.patch b/target/linux/brcm47xx/patches-3.2/0017-mtd-bcm47xx-add-bcm47xx-part-parser.patch deleted file mode 100644 index 1c41827f9..000000000 --- a/target/linux/brcm47xx/patches-3.2/0017-mtd-bcm47xx-add-bcm47xx-part-parser.patch +++ /dev/null @@ -1,585 +0,0 @@ -From d50d2d8e3ab5446f791deff0cb78820989ed93e7 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Sun, 17 Jul 2011 14:54:11 +0200 -Subject: [PATCH 06/19] mtd: bcm47xx: add bcm47xx part parser - - -Signed-off-by: Hauke Mehrtens ---- - 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 -+ * Copyright (C) 2005 Waldemar Brodkorb -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#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"); diff --git a/target/linux/brcm47xx/patches-3.2/0018-mtd-bcm47xx-add-parallel-flash-driver.patch b/target/linux/brcm47xx/patches-3.2/0018-mtd-bcm47xx-add-parallel-flash-driver.patch deleted file mode 100644 index 613dc8914..000000000 --- a/target/linux/brcm47xx/patches-3.2/0018-mtd-bcm47xx-add-parallel-flash-driver.patch +++ /dev/null @@ -1,230 +0,0 @@ -From 36f8b899174a445a98fe02ed8d1db177525f0c52 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Sun, 17 Jul 2011 14:55:18 +0200 -Subject: [PATCH 07/15] mtd: bcm47xx: add parallel flash driver - - -Signed-off-by: Hauke Mehrtens ---- - 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 -+ * Copyright (C) 2005 Waldemar Brodkorb -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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"); diff --git a/target/linux/brcm47xx/patches-3.2/0019-mtd-bcm47xx-add-serial-flash-driver.patch b/target/linux/brcm47xx/patches-3.2/0019-mtd-bcm47xx-add-serial-flash-driver.patch deleted file mode 100644 index 1b5dafabd..000000000 --- a/target/linux/brcm47xx/patches-3.2/0019-mtd-bcm47xx-add-serial-flash-driver.patch +++ /dev/null @@ -1,315 +0,0 @@ -From 2e2951220bf63e05449c03a95453680da1029e44 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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 - #include -+#include - #include - - 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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"); diff --git a/target/linux/brcm47xx/patches-3.2/0020-bcm47xx-register-flash-drivers.patch b/target/linux/brcm47xx/patches-3.2/0020-bcm47xx-register-flash-drivers.patch deleted file mode 100644 index f8978b0b8..000000000 --- a/target/linux/brcm47xx/patches-3.2/0020-bcm47xx-register-flash-drivers.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 64f3d068654589d6114048ac5933cd4498706cfc Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Sun, 17 Jul 2011 15:02:10 +0200 -Subject: [PATCH 20/26] bcm47xx: register flash drivers - - -Signed-off-by: Hauke Mehrtens ---- - 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 - #include - #include -+#include - #include - #include - #include - #include -+#include - #include - - 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); diff --git a/target/linux/brcm47xx/patches-3.2/0025-bcm47xx-read-nvram-from-sflash.patch b/target/linux/brcm47xx/patches-3.2/0025-bcm47xx-read-nvram-from-sflash.patch deleted file mode 100644 index d3781b8fe..000000000 --- a/target/linux/brcm47xx/patches-3.2/0025-bcm47xx-read-nvram-from-sflash.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 1d693b2c9d5943cbe938f879041b837cd004737f Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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 - #include - #include -+#include - - 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) diff --git a/target/linux/brcm47xx/patches-3.2/0026-bcma-export-needed-gpio-functions.patch b/target/linux/brcm47xx/patches-3.2/0026-bcma-export-needed-gpio-functions.patch deleted file mode 100644 index 7d172d4c9..000000000 --- a/target/linux/brcm47xx/patches-3.2/0026-bcma-export-needed-gpio-functions.patch +++ /dev/null @@ -1,47 +0,0 @@ -From f6e41db3ee7ead99e1398def222c14893fc265de Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Thu, 4 Aug 2011 21:09:48 +0200 -Subject: [PATCH 26/26] bcma: export needed gpio functions - - -Signed-off-by: Hauke Mehrtens ---- - 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) diff --git a/target/linux/brcm47xx/patches-3.2/0036-bcma-add-the-core-unit-number.patch b/target/linux/brcm47xx/patches-3.2/0036-bcma-add-the-core-unit-number.patch deleted file mode 100644 index cba9a6398..000000000 --- a/target/linux/brcm47xx/patches-3.2/0036-bcma-add-the-core-unit-number.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 7b9116eeaf44c0d368b5eeaa06eb101465284596 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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; diff --git a/target/linux/brcm47xx/patches-3.2/0037-bcma-constants-for-PCI-and-use-them.patch b/target/linux/brcm47xx/patches-3.2/0037-bcma-constants-for-PCI-and-use-them.patch deleted file mode 100644 index ab5f48198..000000000 --- a/target/linux/brcm47xx/patches-3.2/0037-bcma-constants-for-PCI-and-use-them.patch +++ /dev/null @@ -1,334 +0,0 @@ -From 300efafa8e1381a208c723bb9d03d46bf29f1ec0 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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 -+ * Copyright 2011, 2012, Hauke Mehrtens - * - * 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 */ - diff --git a/target/linux/brcm47xx/patches-3.2/0038-bcma-export-bcma_pcie_read.patch b/target/linux/brcm47xx/patches-3.2/0038-bcma-export-bcma_pcie_read.patch deleted file mode 100644 index 70bb497bf..000000000 --- a/target/linux/brcm47xx/patches-3.2/0038-bcma-export-bcma_pcie_read.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 01d8709c311858c37e02c96464ea4dc954334210 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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); diff --git a/target/linux/brcm47xx/patches-3.2/0039-bcma-make-some-functions-__devinit.patch b/target/linux/brcm47xx/patches-3.2/0039-bcma-make-some-functions-__devinit.patch deleted file mode 100644 index 2534a3a6b..000000000 --- a/target/linux/brcm47xx/patches-3.2/0039-bcma-make-some-functions-__devinit.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 3cd3138f2ef77e18abc99737c6740f35d61dbbb3 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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 - --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); - diff --git a/target/linux/brcm47xx/patches-3.2/0040-bcma-add-PCIe-host-controller.patch b/target/linux/brcm47xx/patches-3.2/0040-bcma-add-PCIe-host-controller.patch deleted file mode 100644 index 2afd09aee..000000000 --- a/target/linux/brcm47xx/patches-3.2/0040-bcma-add-PCIe-host-controller.patch +++ /dev/null @@ -1,845 +0,0 @@ -From 47d0e8c2743729b4248585d33b55b6aaeac008d5 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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 - #include - #include -+#include - #include - - 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 - * Copyright 2011, 2012, Hauke Mehrtens - * -@@ -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 -+ * Copyright 2011, 2012, Hauke Mehrtens -+ * - * Licensed under the GNU/GPL. See COPYING for details. - */ - - #include "bcma_private.h" -+#include - #include -+#include -+ -+/* 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_ */ diff --git a/target/linux/brcm47xx/patches-3.2/0041-bcma-add-bus-num-counter.patch b/target/linux/brcm47xx/patches-3.2/0041-bcma-add-bus-num-counter.patch deleted file mode 100644 index 14d112746..000000000 --- a/target/linux/brcm47xx/patches-3.2/0041-bcma-add-bus-num-counter.patch +++ /dev/null @@ -1,59 +0,0 @@ -From eecd733c14952b074d7488934a4f3dc83c9c426b Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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; diff --git a/target/linux/brcm47xx/patches-3.2/0042-bcma-add-new-PCI-ID.patch b/target/linux/brcm47xx/patches-3.2/0042-bcma-add-new-PCI-ID.patch deleted file mode 100644 index 72463d454..000000000 --- a/target/linux/brcm47xx/patches-3.2/0042-bcma-add-new-PCI-ID.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 699c57a18b40ffbe1763915acdc1a3e4fb539d01 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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); diff --git a/target/linux/brcm47xx/patches-3.2/0043-bcma-add-extra-sprom-check.patch b/target/linux/brcm47xx/patches-3.2/0043-bcma-add-extra-sprom-check.patch deleted file mode 100644 index 3ae571153..000000000 --- a/target/linux/brcm47xx/patches-3.2/0043-bcma-add-extra-sprom-check.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 1cd3d0de72e42161fe0df355c5429459265aeef0 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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 diff --git a/target/linux/brcm47xx/patches-3.2/0045-ssb-fix-cardbus-in-hostmode.patch b/target/linux/brcm47xx/patches-3.2/0045-ssb-fix-cardbus-in-hostmode.patch deleted file mode 100644 index d26807f3e..000000000 --- a/target/linux/brcm47xx/patches-3.2/0045-ssb-fix-cardbus-in-hostmode.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 7b90e7040b9783b91a4e2baf72ac32d3a00f9f2d Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Sat, 21 Jan 2012 11:18:25 +0100 -Subject: [PATCH 31/34] ssb: fix cardbus in hostmode - - -Signed-off-by: Hauke Mehrtens ---- - 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) { diff --git a/target/linux/brcm47xx/patches-3.2/0046-bcma-complete-workaround-for-BCMA43224.patch b/target/linux/brcm47xx/patches-3.2/0046-bcma-complete-workaround-for-BCMA43224.patch deleted file mode 100644 index 97e3f9c34..000000000 --- a/target/linux/brcm47xx/patches-3.2/0046-bcma-complete-workaround-for-BCMA43224.patch +++ /dev/null @@ -1,52 +0,0 @@ -From efe89df0326b777563d197b8cf1c25209a31ceb0 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Sat, 21 Jan 2012 18:47:42 +0100 -Subject: [PATCH 32/34] bcma: complete workaround for BCMA43224 - - -Signed-off-by: Hauke Mehrtens ---- - 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 */ diff --git a/target/linux/brcm47xx/patches-3.2/0047-bcma-log-the-id-rev-and-pkg-of-the-chip-found.patch b/target/linux/brcm47xx/patches-3.2/0047-bcma-log-the-id-rev-and-pkg-of-the-chip-found.patch deleted file mode 100644 index ce16cac3c..000000000 --- a/target/linux/brcm47xx/patches-3.2/0047-bcma-log-the-id-rev-and-pkg-of-the-chip-found.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 293fcc92dae1284c35a3bb51e7f9eb13b52e58fe Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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; - } - diff --git a/target/linux/brcm47xx/patches-3.2/0048-ssb-log-the-id-rev-and-pkg-of-the-chip-found.patch b/target/linux/brcm47xx/patches-3.2/0048-ssb-log-the-id-rev-and-pkg-of-the-chip-found.patch deleted file mode 100644 index a5a8bc4c7..000000000 --- a/target/linux/brcm47xx/patches-3.2/0048-ssb-log-the-id-rev-and-pkg-of-the-chip-found.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 7ddcc963030bbc82add2efbd49e696ae8aff3ae6 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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)) { diff --git a/target/linux/brcm47xx/patches-3.2/014-MIPS-BCM47xx-Setup-and-register-serial-early.patch b/target/linux/brcm47xx/patches-3.2/014-MIPS-BCM47xx-Setup-and-register-serial-early.patch deleted file mode 100644 index 12028c4a4..000000000 --- a/target/linux/brcm47xx/patches-3.2/014-MIPS-BCM47xx-Setup-and-register-serial-early.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 9be402f069cc259ad5795b77567d66c4e7f6bef6 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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 - #include - #include -+#include -+#include - #include - #include - #include -@@ -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 - diff --git a/target/linux/brcm47xx/patches-3.2/016-MIPS-BCM47xx-Remove-CFE-console.patch b/target/linux/brcm47xx/patches-3.2/016-MIPS-BCM47xx-Remove-CFE-console.patch deleted file mode 100644 index 1ae09d86e..000000000 --- a/target/linux/brcm47xx/patches-3.2/016-MIPS-BCM47xx-Remove-CFE-console.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 5219981646071abb6731634bf47781a53e248764 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -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 ---- - 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 - #include - --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(); - } - diff --git a/target/linux/brcm47xx/patches-3.2/019-fix-boot.patch b/target/linux/brcm47xx/patches-3.2/019-fix-boot.patch deleted file mode 100644 index dc57933b9..000000000 --- a/target/linux/brcm47xx/patches-3.2/019-fix-boot.patch +++ /dev/null @@ -1,42 +0,0 @@ ---- 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 diff --git a/target/linux/brcm47xx/patches-3.2/020-bcma-move-parallel-flash-into-a-union.patch b/target/linux/brcm47xx/patches-3.2/020-bcma-move-parallel-flash-into-a-union.patch new file mode 100644 index 000000000..11855b449 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/020-bcma-move-parallel-flash-into-a-union.patch @@ -0,0 +1,142 @@ +From b7d9f9cd6a8e463c1061ea29ed3e614403625024 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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]; diff --git a/target/linux/brcm47xx/patches-3.2/021-bcma-add-serial-flash-support-to-bcma.patch b/target/linux/brcm47xx/patches-3.2/021-bcma-add-serial-flash-support-to-bcma.patch new file mode 100644 index 000000000..e78f3c457 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/021-bcma-add-serial-flash-support-to-bcma.patch @@ -0,0 +1,681 @@ +From a62940e988526c881966a8c72cc28c95fca89f3c Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 ++ * Copyright 2010, Broadcom Corporation ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++ ++#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_ */ diff --git a/target/linux/brcm47xx/patches-3.2/022-ssb-move-flash-to-chipcommon.patch b/target/linux/brcm47xx/patches-3.2/022-ssb-move-flash-to-chipcommon.patch new file mode 100644 index 000000000..91d8acb26 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/022-ssb-move-flash-to-chipcommon.patch @@ -0,0 +1,149 @@ +From e8afde87ecf56beff67c7d5371cabaa4fc018541 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sat, 23 Jul 2011 23:57:06 +0200 +Subject: [PATCH 14/26] ssb: move flash to chipcommon + + +Signed-off-by: Hauke Mehrtens +--- + 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); diff --git a/target/linux/brcm47xx/patches-3.2/023-ssb-add-serial-flash-support.patch b/target/linux/brcm47xx/patches-3.2/023-ssb-add-serial-flash-support.patch new file mode 100644 index 000000000..e91c2a44f --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/023-ssb-add-serial-flash-support.patch @@ -0,0 +1,697 @@ +From 980da78179592a3f5f99168bc5af415835aa8c13 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 24 Jul 2011 20:20:36 +0200 +Subject: [PATCH 15/26] ssb: add serial flash support + + +Signed-off-by: Hauke Mehrtens +--- + 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 ++ * Copyright 2010, Broadcom Corporation ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++ ++#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); + diff --git a/target/linux/brcm47xx/patches-3.2/024-brcm47xx-add-common-interface-for-sflash.patch b/target/linux/brcm47xx/patches-3.2/024-brcm47xx-add-common-interface-for-sflash.patch new file mode 100644 index 000000000..6caa9180d --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/024-brcm47xx-add-common-interface-for-sflash.patch @@ -0,0 +1,193 @@ +From 4f314ac9edbc80897f158fdb4e1b1de8a2d0d432 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 24 Jul 2011 21:10:49 +0200 +Subject: [PATCH 16/26] brcm47xx: add common interface for sflash + + +Signed-off-by: Hauke Mehrtens +--- + 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 ++ * ++ * 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 ++ ++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 ++ * ++ * 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 ++#include ++#include ++ ++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; diff --git a/target/linux/brcm47xx/patches-3.2/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch b/target/linux/brcm47xx/patches-3.2/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch new file mode 100644 index 000000000..1c41827f9 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch @@ -0,0 +1,585 @@ +From d50d2d8e3ab5446f791deff0cb78820989ed93e7 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 17 Jul 2011 14:54:11 +0200 +Subject: [PATCH 06/19] mtd: bcm47xx: add bcm47xx part parser + + +Signed-off-by: Hauke Mehrtens +--- + 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 ++ * Copyright (C) 2005 Waldemar Brodkorb ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#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"); diff --git a/target/linux/brcm47xx/patches-3.2/026-mtd-bcm47xx-add-parallel-flash-driver.patch b/target/linux/brcm47xx/patches-3.2/026-mtd-bcm47xx-add-parallel-flash-driver.patch new file mode 100644 index 000000000..613dc8914 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/026-mtd-bcm47xx-add-parallel-flash-driver.patch @@ -0,0 +1,230 @@ +From 36f8b899174a445a98fe02ed8d1db177525f0c52 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 17 Jul 2011 14:55:18 +0200 +Subject: [PATCH 07/15] mtd: bcm47xx: add parallel flash driver + + +Signed-off-by: Hauke Mehrtens +--- + 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 ++ * Copyright (C) 2005 Waldemar Brodkorb ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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"); diff --git a/target/linux/brcm47xx/patches-3.2/027-mtd-bcm47xx-add-serial-flash-driver.patch b/target/linux/brcm47xx/patches-3.2/027-mtd-bcm47xx-add-serial-flash-driver.patch new file mode 100644 index 000000000..1b5dafabd --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/027-mtd-bcm47xx-add-serial-flash-driver.patch @@ -0,0 +1,315 @@ +From 2e2951220bf63e05449c03a95453680da1029e44 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 + #include ++#include + #include + + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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"); diff --git a/target/linux/brcm47xx/patches-3.2/028-bcm47xx-register-flash-drivers.patch b/target/linux/brcm47xx/patches-3.2/028-bcm47xx-register-flash-drivers.patch new file mode 100644 index 000000000..f8978b0b8 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/028-bcm47xx-register-flash-drivers.patch @@ -0,0 +1,100 @@ +From 64f3d068654589d6114048ac5933cd4498706cfc Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 17 Jul 2011 15:02:10 +0200 +Subject: [PATCH 20/26] bcm47xx: register flash drivers + + +Signed-off-by: Hauke Mehrtens +--- + 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 + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + + 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); diff --git a/target/linux/brcm47xx/patches-3.2/029-bcm47xx-read-nvram-from-sflash.patch b/target/linux/brcm47xx/patches-3.2/029-bcm47xx-read-nvram-from-sflash.patch new file mode 100644 index 000000000..d3781b8fe --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/029-bcm47xx-read-nvram-from-sflash.patch @@ -0,0 +1,118 @@ +From 1d693b2c9d5943cbe938f879041b837cd004737f Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 + #include + #include ++#include + + 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) diff --git a/target/linux/brcm47xx/patches-3.2/040-bcm47xx-add-gpio_set_debounce.patch b/target/linux/brcm47xx/patches-3.2/040-bcm47xx-add-gpio_set_debounce.patch deleted file mode 100644 index c37bb13d1..000000000 --- a/target/linux/brcm47xx/patches-3.2/040-bcm47xx-add-gpio_set_debounce.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- 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 */ diff --git a/target/linux/brcm47xx/patches-3.2/040-bcma-add-the-core-unit-number.patch b/target/linux/brcm47xx/patches-3.2/040-bcma-add-the-core-unit-number.patch new file mode 100644 index 000000000..cba9a6398 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/040-bcma-add-the-core-unit-number.patch @@ -0,0 +1,61 @@ +From 7b9116eeaf44c0d368b5eeaa06eb101465284596 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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; diff --git a/target/linux/brcm47xx/patches-3.2/041-bcma-constants-for-PCI-and-use-them.patch b/target/linux/brcm47xx/patches-3.2/041-bcma-constants-for-PCI-and-use-them.patch new file mode 100644 index 000000000..ab5f48198 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/041-bcma-constants-for-PCI-and-use-them.patch @@ -0,0 +1,334 @@ +From 300efafa8e1381a208c723bb9d03d46bf29f1ec0 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 ++ * Copyright 2011, 2012, Hauke Mehrtens + * + * 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 */ + diff --git a/target/linux/brcm47xx/patches-3.2/042-bcma-export-bcma_pcie_read.patch b/target/linux/brcm47xx/patches-3.2/042-bcma-export-bcma_pcie_read.patch new file mode 100644 index 000000000..70bb497bf --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/042-bcma-export-bcma_pcie_read.patch @@ -0,0 +1,35 @@ +From 01d8709c311858c37e02c96464ea4dc954334210 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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); diff --git a/target/linux/brcm47xx/patches-3.2/043-bcma-make-some-functions-__devinit.patch b/target/linux/brcm47xx/patches-3.2/043-bcma-make-some-functions-__devinit.patch new file mode 100644 index 000000000..2534a3a6b --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/043-bcma-make-some-functions-__devinit.patch @@ -0,0 +1,111 @@ +From 3cd3138f2ef77e18abc99737c6740f35d61dbbb3 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 + +-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); + diff --git a/target/linux/brcm47xx/patches-3.2/044-bcma-add-PCIe-host-controller.patch b/target/linux/brcm47xx/patches-3.2/044-bcma-add-PCIe-host-controller.patch new file mode 100644 index 000000000..2afd09aee --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/044-bcma-add-PCIe-host-controller.patch @@ -0,0 +1,845 @@ +From 47d0e8c2743729b4248585d33b55b6aaeac008d5 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 + #include + #include ++#include + #include + + 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 + * Copyright 2011, 2012, Hauke Mehrtens + * +@@ -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 ++ * Copyright 2011, 2012, Hauke Mehrtens ++ * + * Licensed under the GNU/GPL. See COPYING for details. + */ + + #include "bcma_private.h" ++#include + #include ++#include ++ ++/* 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_ */ diff --git a/target/linux/brcm47xx/patches-3.2/045-bcma-add-bus-num-counter.patch b/target/linux/brcm47xx/patches-3.2/045-bcma-add-bus-num-counter.patch new file mode 100644 index 000000000..14d112746 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/045-bcma-add-bus-num-counter.patch @@ -0,0 +1,59 @@ +From eecd733c14952b074d7488934a4f3dc83c9c426b Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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; diff --git a/target/linux/brcm47xx/patches-3.2/046-bcma-add-extra-sprom-check.patch b/target/linux/brcm47xx/patches-3.2/046-bcma-add-extra-sprom-check.patch new file mode 100644 index 000000000..3ae571153 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/046-bcma-add-extra-sprom-check.patch @@ -0,0 +1,62 @@ +From 1cd3d0de72e42161fe0df355c5429459265aeef0 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 diff --git a/target/linux/brcm47xx/patches-3.2/047-bcma-add-new-PCI-ID.patch b/target/linux/brcm47xx/patches-3.2/047-bcma-add-new-PCI-ID.patch new file mode 100644 index 000000000..72463d454 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/047-bcma-add-new-PCI-ID.patch @@ -0,0 +1,24 @@ +From 699c57a18b40ffbe1763915acdc1a3e4fb539d01 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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); diff --git a/target/linux/brcm47xx/patches-3.2/050-bcma-export-needed-gpio-functions.patch b/target/linux/brcm47xx/patches-3.2/050-bcma-export-needed-gpio-functions.patch new file mode 100644 index 000000000..7d172d4c9 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/050-bcma-export-needed-gpio-functions.patch @@ -0,0 +1,47 @@ +From f6e41db3ee7ead99e1398def222c14893fc265de Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Thu, 4 Aug 2011 21:09:48 +0200 +Subject: [PATCH 26/26] bcma: export needed gpio functions + + +Signed-off-by: Hauke Mehrtens +--- + 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) diff --git a/target/linux/brcm47xx/patches-3.2/051-ssb-fix-cardbus-in-hostmode.patch b/target/linux/brcm47xx/patches-3.2/051-ssb-fix-cardbus-in-hostmode.patch new file mode 100644 index 000000000..d26807f3e --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/051-ssb-fix-cardbus-in-hostmode.patch @@ -0,0 +1,22 @@ +From 7b90e7040b9783b91a4e2baf72ac32d3a00f9f2d Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sat, 21 Jan 2012 11:18:25 +0100 +Subject: [PATCH 31/34] ssb: fix cardbus in hostmode + + +Signed-off-by: Hauke Mehrtens +--- + 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) { diff --git a/target/linux/brcm47xx/patches-3.2/052-bcma-complete-workaround-for-BCMA43224.patch b/target/linux/brcm47xx/patches-3.2/052-bcma-complete-workaround-for-BCMA43224.patch new file mode 100644 index 000000000..97e3f9c34 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/052-bcma-complete-workaround-for-BCMA43224.patch @@ -0,0 +1,52 @@ +From efe89df0326b777563d197b8cf1c25209a31ceb0 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sat, 21 Jan 2012 18:47:42 +0100 +Subject: [PATCH 32/34] bcma: complete workaround for BCMA43224 + + +Signed-off-by: Hauke Mehrtens +--- + 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 */ diff --git a/target/linux/brcm47xx/patches-3.2/053-bcma-log-the-id-rev-and-pkg-of-the-chip-found.patch b/target/linux/brcm47xx/patches-3.2/053-bcma-log-the-id-rev-and-pkg-of-the-chip-found.patch new file mode 100644 index 000000000..ce16cac3c --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/053-bcma-log-the-id-rev-and-pkg-of-the-chip-found.patch @@ -0,0 +1,39 @@ +From 293fcc92dae1284c35a3bb51e7f9eb13b52e58fe Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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; + } + diff --git a/target/linux/brcm47xx/patches-3.2/054-ssb-log-the-id-rev-and-pkg-of-the-chip-found.patch b/target/linux/brcm47xx/patches-3.2/054-ssb-log-the-id-rev-and-pkg-of-the-chip-found.patch new file mode 100644 index 000000000..a5a8bc4c7 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/054-ssb-log-the-id-rev-and-pkg-of-the-chip-found.patch @@ -0,0 +1,25 @@ +From 7ddcc963030bbc82add2efbd49e696ae8aff3ae6 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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)) { diff --git a/target/linux/brcm47xx/patches-3.2/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch b/target/linux/brcm47xx/patches-3.2/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch new file mode 100644 index 000000000..12028c4a4 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch @@ -0,0 +1,69 @@ +From 9be402f069cc259ad5795b77567d66c4e7f6bef6 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 + #include + #include ++#include ++#include + #include + #include + #include +@@ -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 + diff --git a/target/linux/brcm47xx/patches-3.2/116-MIPS-BCM47xx-Remove-CFE-console.patch b/target/linux/brcm47xx/patches-3.2/116-MIPS-BCM47xx-Remove-CFE-console.patch new file mode 100644 index 000000000..1ae09d86e --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/116-MIPS-BCM47xx-Remove-CFE-console.patch @@ -0,0 +1,141 @@ +From 5219981646071abb6731634bf47781a53e248764 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 + #include + +-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(); + } + diff --git a/target/linux/brcm47xx/patches-3.2/119-fix-boot.patch b/target/linux/brcm47xx/patches-3.2/119-fix-boot.patch new file mode 100644 index 000000000..dc57933b9 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/119-fix-boot.patch @@ -0,0 +1,42 @@ +--- 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 diff --git a/target/linux/brcm47xx/patches-3.2/140-bcm47xx-add-gpio_set_debounce.patch b/target/linux/brcm47xx/patches-3.2/140-bcm47xx-add-gpio_set_debounce.patch new file mode 100644 index 000000000..c37bb13d1 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.2/140-bcm47xx-add-gpio_set_debounce.patch @@ -0,0 +1,12 @@ +--- 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 */