brcm47xx: update bcma and ssb to master-2011-07-21

* add new patches for bcm4716 SoC
* add support for serial flash on bcma bus

SVN-Revision: 27723
lede-17.01
Hauke Mehrtens 2011-07-22 16:30:42 +00:00
parent 39f491e479
commit b988168906
42 changed files with 3314 additions and 767 deletions

View File

@ -18,6 +18,7 @@ CONFIG_BCM47XX_BCMA=y
CONFIG_BCM47XX_SSB=y CONFIG_BCM47XX_SSB=y
CONFIG_BCM47XX_WDT=y CONFIG_BCM47XX_WDT=y
CONFIG_BCMA=y CONFIG_BCMA=y
CONFIG_BCMA_BLOCKIO=y
CONFIG_BCMA_DEBUG=y CONFIG_BCMA_DEBUG=y
CONFIG_BCMA_DRIVER_MIPS=y CONFIG_BCMA_DRIVER_MIPS=y
CONFIG_BCMA_DRIVER_PCI_HOSTMODE=y CONFIG_BCMA_DRIVER_PCI_HOSTMODE=y
@ -25,6 +26,7 @@ CONFIG_BCMA_HOST_PCI=y
CONFIG_BCMA_HOST_PCI_POSSIBLE=y CONFIG_BCMA_HOST_PCI_POSSIBLE=y
CONFIG_BCMA_HOST_SOC=y CONFIG_BCMA_HOST_SOC=y
CONFIG_BCMA_POSSIBLE=y CONFIG_BCMA_POSSIBLE=y
CONFIG_BCMA_SFLASH=y
# CONFIG_BRCMUTIL is not set # CONFIG_BRCMUTIL is not set
# CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_BUG is not set # CONFIG_BUG is not set
@ -93,7 +95,9 @@ CONFIG_MIPS=y
CONFIG_MIPS_L1_CACHE_SHIFT=5 CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set # CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_MT_DISABLED=y CONFIG_MIPS_MT_DISABLED=y
CONFIG_MTD_BCM47XX=y CONFIG_MTD_BCM47XX_PARTS=y
CONFIG_MTD_BCM47XX_PFLASH=y
CONFIG_MTD_BCM47XX_SFLASH=y
CONFIG_NEED_DMA_MAP_STATE=y CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y CONFIG_NEED_PER_CPU_KM=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y

View File

@ -1,28 +0,0 @@
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -412,16 +412,6 @@ static int __devinit pcicore_is_in_hostm
* Workarounds.
**************************************************/
-static void __devinit ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc)
-{
- u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0));
- if (((tmp & 0xF000) >> 12) != pc->dev->core_index) {
- tmp &= ~0xF000;
- tmp |= (pc->dev->core_index << 12);
- pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp);
- }
-}
-
static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc)
{
return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
@@ -529,8 +519,6 @@ void __devinit ssb_pcicore_init(struct s
if (!ssb_device_is_enabled(dev))
ssb_device_enable(dev, 0);
- ssb_pcicore_fix_sprom_core_index(pc);
-
#ifdef CONFIG_SSB_PCICORE_HOSTMODE
pc->hostmode = pcicore_is_in_hostmode(pc);
if (pc->hostmode)

View File

@ -25,7 +25,7 @@
ssb_printk(KERN_ERR PFX ssb_printk(KERN_ERR PFX
--- a/include/linux/ssb/ssb.h --- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h
@@ -155,9 +155,16 @@ struct ssb_bus_ops { @@ -157,9 +157,16 @@ struct ssb_bus_ops {
#define SSB_DEV_MINI_MACPHY 0x823 #define SSB_DEV_MINI_MACPHY 0x823
#define SSB_DEV_ARM_1176 0x824 #define SSB_DEV_ARM_1176 0x824
#define SSB_DEV_ARM_7TDMI 0x825 #define SSB_DEV_ARM_7TDMI 0x825

View File

@ -1,12 +1,16 @@
From c4fb5adbe45b3a1cfc509a64bb92429ab0d6fc37 Mon Sep 17 00:00:00 2001 From e6defe46ea936ebb309c9cab4f7fd14bdc0c5416 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sat, 11 Jun 2011 16:47:38 +0200 Date: Sat, 11 Jun 2011 16:47:38 +0200
Subject: [PATCH 01/14] bcma: move parsing of EEPROM into own function. Subject: [PATCH 01/22] bcma: move parsing of EEPROM into own function.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Move the parsing of the EEPROM data in scan function for one core into Move the parsing of the EEPROM data in scan function for one core into
an own function. Now we are able to use it in some other scan function an own function. Now we are able to use it in some other scan function
as well. as well.
Acked-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- ---
drivers/bcma/scan.c | 230 ++++++++++++++++++++++++++------------------------- drivers/bcma/scan.c | 230 ++++++++++++++++++++++++++-------------------------

View File

@ -1,10 +1,14 @@
From dd6cbe9b9e2ae563659b34184f4cd9d905dc90d5 Mon Sep 17 00:00:00 2001 From 47b0447e18f72724caf57ba7e4573e309fb2bfae Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sat, 18 Jun 2011 11:55:47 +0200 Date: Sat, 18 Jun 2011 11:55:47 +0200
Subject: [PATCH 02/14] bcma: move initializing of struct bcma_bus to own function. Subject: [PATCH 02/22] bcma: move initializing of struct bcma_bus to own function.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This makes it possible to use this code in some other method. This makes it possible to use this code in some other method.
Acked-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- ---
drivers/bcma/scan.c | 17 +++++++++++------ drivers/bcma/scan.c | 17 +++++++++++------

View File

@ -1,7 +1,10 @@
From 9a920f4d8eed485f7b73e9b13dab0e49c64d3ff8 Mon Sep 17 00:00:00 2001 From beb36a1a49227ca6c5778a667aefc8cd3fd56a4f Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sat, 18 Jun 2011 14:30:55 +0200 Date: Sat, 18 Jun 2011 14:30:55 +0200
Subject: [PATCH 03/14] bcma: add functions to scan cores needed on SoCs Subject: [PATCH 03/22] bcma: add functions to scan cores needed on SoCs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The chip common and mips core have to be setup early in the boot The chip common and mips core have to be setup early in the boot
process to get the cpu clock. process to get the cpu clock.
@ -10,17 +13,19 @@ data and searches for the chip common and mips core and initializes
chip common. After that was done and the kernel is out of early boot we chip common. After that was done and the kernel is out of early boot we
just have to run bcma_bus_register() and it will search for the other just have to run bcma_bus_register() and it will search for the other
cores, initialize and register them. cores, initialize and register them.
The cores are getting the same numbers as before.
Acked-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- ---
drivers/bcma/bcma_private.h | 7 ++ drivers/bcma/bcma_private.h | 7 ++
drivers/bcma/driver_chipcommon.c | 5 ++ drivers/bcma/driver_chipcommon.c | 5 ++
drivers/bcma/driver_pci.c | 3 + drivers/bcma/driver_pci.c | 5 ++
drivers/bcma/main.c | 45 +++++++++++++ drivers/bcma/main.c | 46 +++++++++++++
drivers/bcma/scan.c | 95 +++++++++++++++++++++++++-- drivers/bcma/scan.c | 95 +++++++++++++++++++++++++--
include/linux/bcma/bcma.h | 1 + include/linux/bcma/bcma.h | 1 +
include/linux/bcma/bcma_driver_chipcommon.h | 1 + include/linux/bcma/bcma_driver_chipcommon.h | 1 +
7 files changed, 151 insertions(+), 6 deletions(-) 7 files changed, 154 insertions(+), 6 deletions(-)
--- a/drivers/bcma/bcma_private.h --- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h
@ -43,20 +48,20 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
int bcma_sprom_get(struct bcma_bus *bus); int bcma_sprom_get(struct bcma_bus *bus);
--- a/drivers/bcma/driver_chipcommon.c --- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c
@@ -23,6 +23,9 @@ static inline u32 bcma_cc_write32_masked @@ -26,6 +26,9 @@ void bcma_core_chipcommon_init(struct bc
u32 leddc_on = 10;
u32 leddc_off = 90;
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
{
+ if (cc->setup_done) + if (cc->setup_done)
+ return; + return;
+ +
if (cc->core->id.rev >= 11) if (cc->core->id.rev >= 11)
cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
@@ -38,6 +41,8 @@ void bcma_core_chipcommon_init(struct bc @@ -52,6 +55,8 @@ void bcma_core_chipcommon_init(struct bc
bcma_pmu_init(cc); ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
if (cc->capabilities & BCMA_CC_CAP_PCTL) (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
pr_err("Power control not implemented!\n"); }
+ +
+ cc->setup_done = true; + cc->setup_done = true;
} }
@ -64,20 +69,28 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
--- a/drivers/bcma/driver_pci.c --- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c
@@ -159,7 +159,10 @@ static void bcma_pcicore_serdes_workarou @@ -187,6 +187,9 @@ static bool bcma_core_pci_is_in_hostmode
void bcma_core_pci_init(struct bcma_drv_pci *pc) void bcma_core_pci_init(struct bcma_drv_pci *pc)
{ {
+ if (pc->setup_done) + if (pc->setup_done)
+ return; + return;
bcma_pcicore_serdes_workaround(pc); +
if (bcma_core_pci_is_in_hostmode(pc)) {
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
bcma_core_pci_hostmode_init(pc);
@@ -196,6 +199,8 @@ void bcma_core_pci_init(struct bcma_drv_
} else {
bcma_core_pci_clientmode_init(pc);
}
+
+ pc->setup_done = true; + pc->setup_done = true;
} }
int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
--- a/drivers/bcma/main.c --- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c +++ b/drivers/bcma/main.c
@@ -167,6 +167,51 @@ void bcma_bus_unregister(struct bcma_bus @@ -169,6 +169,52 @@ void bcma_bus_unregister(struct bcma_bus
bcma_unregister_cores(bus); bcma_unregister_cores(bus);
} }
@ -96,7 +109,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ match.class = BCMA_CL_SIM; + match.class = BCMA_CL_SIM;
+ match.rev = BCMA_ANY_REV; + match.rev = BCMA_ANY_REV;
+ +
+ /* Scan for devices (cores) */ + /* Scan for chip common core */
+ err = bcma_bus_scan_early(bus, &match, core_cc); + err = bcma_bus_scan_early(bus, &match, core_cc);
+ if (err) { + if (err) {
+ pr_err("Failed to scan for common core: %d\n", err); + pr_err("Failed to scan for common core: %d\n", err);
@ -108,6 +121,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ match.class = BCMA_CL_SIM; + match.class = BCMA_CL_SIM;
+ match.rev = BCMA_ANY_REV; + match.rev = BCMA_ANY_REV;
+ +
+ /* Scan for mips core */
+ err = bcma_bus_scan_early(bus, &match, core_mips); + err = bcma_bus_scan_early(bus, &match, core_mips);
+ if (err) { + if (err) {
+ pr_err("Failed to scan for mips core: %d\n", err); + pr_err("Failed to scan for mips core: %d\n", err);
@ -287,7 +301,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+} +}
--- a/include/linux/bcma/bcma.h --- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h
@@ -185,6 +185,7 @@ struct bcma_bus { @@ -190,6 +190,7 @@ struct bcma_bus {
struct bcma_device *mapped_core; struct bcma_device *mapped_core;
struct list_head cores; struct list_head cores;
u8 nr_cores; u8 nr_cores;
@ -297,7 +311,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
struct bcma_drv_pci drv_pci; struct bcma_drv_pci drv_pci;
--- a/include/linux/bcma/bcma_driver_chipcommon.h --- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -259,6 +259,7 @@ struct bcma_drv_cc { @@ -252,6 +252,7 @@ struct bcma_drv_cc {
u32 status; u32 status;
u32 capabilities; u32 capabilities;
u32 capabilities_ext; u32 capabilities_ext;

View File

@ -1,44 +1,50 @@
From a807b2fb233af60028ed38ba237953bcffdf33e9 Mon Sep 17 00:00:00 2001 From 22573303ad477fa07c948a9944e9c18fea9af724 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sat, 18 Jun 2011 14:31:53 +0200 Date: Sat, 18 Jun 2011 14:31:53 +0200
Subject: [PATCH 04/14] bcma: add SOC bus Subject: [PATCH 04/22] bcma: add SOC bus
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch adds support for using bcma on an embedded bus. An embedded This patch adds support for using bcma on a Broadcom SoC as the system
system like the bcm4716 could register this bus and it searches for the bus. An SoC like the bcm4716 could register this bus and use it to
bcma cores then. searches for the bcma cores and register the devices on this bus.
BCMA_HOSTTYPE_NONE was intended for SoCs at first but BCMA_HOSTTYPE_SOC
is a better name.
Acked-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- ---
drivers/bcma/Kconfig | 5 + drivers/bcma/Kconfig | 4 +
drivers/bcma/Makefile | 1 + drivers/bcma/Makefile | 1 +
drivers/bcma/host_soc.c | 178 +++++++++++++++++++++++++++++++++++++++++ drivers/bcma/host_soc.c | 183 +++++++++++++++++++++++++++++++++++++++++
drivers/bcma/main.c | 1 + drivers/bcma/main.c | 6 +-
drivers/bcma/scan.c | 24 +++++- drivers/bcma/scan.c | 42 ++++++++-
include/linux/bcma/bcma.h | 4 + include/linux/bcma/bcma.h | 5 +-
include/linux/bcma/bcma_soc.h | 16 ++++ include/linux/bcma/bcma_soc.h | 16 ++++
7 files changed, 227 insertions(+), 2 deletions(-) 7 files changed, 250 insertions(+), 7 deletions(-)
create mode 100644 drivers/bcma/host_soc.c create mode 100644 drivers/bcma/host_soc.c
create mode 100644 include/linux/bcma/bcma_soc.h create mode 100644 include/linux/bcma/bcma_soc.h
--- a/drivers/bcma/Kconfig --- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig
@@ -27,6 +27,11 @@ config BCMA_HOST_PCI @@ -34,6 +34,10 @@ config BCMA_DRIVER_PCI_HOSTMODE
bool "Support for BCMA on PCI-host bus" help
depends on BCMA_HOST_PCI_POSSIBLE PCI core hostmode operation (external PCI bus).
+config BCMA_HOST_SOC +config BCMA_HOST_SOC
+ bool + bool
+ depends on BCMA && MIPS + depends on BCMA && MIPS
+ default n
+ +
config BCMA_DEBUG config BCMA_DEBUG
bool "BCMA debugging" bool "BCMA debugging"
depends on BCMA depends on BCMA
--- a/drivers/bcma/Makefile --- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile
@@ -2,6 +2,7 @@ bcma-y += main.o scan.o core.o sprom @@ -3,6 +3,7 @@ bcma-y += driver_chipcommon.o driver
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_pci.o bcma-y += driver_pci.o
bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
+bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o +bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o
obj-$(CONFIG_BCMA) += bcma.o obj-$(CONFIG_BCMA) += bcma.o
@ -46,7 +52,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG
--- /dev/null --- /dev/null
+++ b/drivers/bcma/host_soc.c +++ b/drivers/bcma/host_soc.c
@@ -0,0 +1,178 @@ @@ -0,0 +1,183 @@
+/* +/*
+ * Broadcom specific AMBA + * Broadcom specific AMBA
+ * System on Chip (SoC) Host + * System on Chip (SoC) Host
@ -210,11 +216,12 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+int __init bcma_host_soc_register(struct bcma_soc *soc) +int __init bcma_host_soc_register(struct bcma_soc *soc)
+{ +{
+ struct bcma_bus *bus = &soc->bus; + struct bcma_bus *bus = &soc->bus;
+ int err;
+ +
+ /* iomap only first core. We have to read some register on this core + /* iomap only first core. We have to read some register on this core
+ * to scan the bus. + * to scan the bus.
+ */ + */
+ bus->mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1); + bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
+ if (!bus->mmio) + if (!bus->mmio)
+ return -ENOMEM; + return -ENOMEM;
+ +
@ -223,13 +230,30 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ bus->ops = &bcma_host_soc_ops; + bus->ops = &bcma_host_soc_ops;
+ +
+ /* Register */ + /* Register */
+ return bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips); + err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
+ if (err)
+ iounmap(bus->mmio);
+
+ return err;
+} +}
--- a/drivers/bcma/main.c --- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c +++ b/drivers/bcma/main.c
@@ -95,6 +95,7 @@ static int bcma_register_cores(struct bc @@ -66,6 +66,10 @@ static struct bcma_device *bcma_find_cor
static void bcma_release_core_dev(struct device *dev)
{
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ if (core->io_addr)
+ iounmap(core->io_addr);
+ if (core->io_wrap)
+ iounmap(core->io_wrap);
kfree(core);
}
@@ -93,8 +97,8 @@ static int bcma_register_cores(struct bc
core->dma_dev = &bus->host_pci->dev;
core->irq = bus->host_pci->irq;
break; break;
case BCMA_HOSTTYPE_NONE: - case BCMA_HOSTTYPE_NONE:
case BCMA_HOSTTYPE_SDIO: case BCMA_HOSTTYPE_SDIO:
+ case BCMA_HOSTTYPE_SOC: + case BCMA_HOSTTYPE_SOC:
break; break;
@ -237,62 +261,99 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- a/drivers/bcma/scan.c --- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c
@@ -337,6 +337,14 @@ static int bcma_get_next_core(struct bcm @@ -337,6 +337,16 @@ static int bcma_get_next_core(struct bcm
} }
} }
} }
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+ core->io_addr = ioremap(core->addr, BCMA_CORE_SIZE); + core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
+ if (!core->io_addr) + if (!core->io_addr)
+ return -ENOMEM; + return -ENOMEM;
+ core->io_wrap = ioremap(core->wrap, BCMA_CORE_SIZE); + core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
+ if (!core->io_wrap) + if (!core->io_wrap) {
+ iounmap(core->io_addr);
+ return -ENOMEM; + return -ENOMEM;
+ }
+ } + }
return 0; return 0;
} }
@@ -369,7 +377,13 @@ int bcma_bus_scan(struct bcma_bus *bus) @@ -369,7 +379,14 @@ int bcma_bus_scan(struct bcma_bus *bus)
bcma_init_bus(bus); bcma_init_bus(bus);
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
- eromptr = bus->mmio; - eromptr = bus->mmio;
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+ eromptr = ioremap(erombase, BCMA_CORE_SIZE); + eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+ if (!eromptr) + if (!eromptr)
+ return -ENOMEM; + return -ENOMEM;
+ } else + } else {
+ eromptr = bus->mmio; + eromptr = bus->mmio;
+ }
+ +
eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
bcma_scan_switch_core(bus, erombase); bcma_scan_switch_core(bus, erombase);
@@ -417,7 +431,13 @@ int __init bcma_bus_scan_early(struct bc @@ -404,6 +421,9 @@ int bcma_bus_scan(struct bcma_bus *bus)
int err, core_num = 0; list_add(&core->list, &bus->cores);
}
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ iounmap(eromptr);
+
return 0;
}
@@ -414,10 +434,18 @@ int __init bcma_bus_scan_early(struct bc
u32 erombase;
u32 __iomem *eromptr, *eromend;
- int err, core_num = 0;
+ int err = -ENODEV;
+ int core_num = 0;
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
- eromptr = bus->mmio; - eromptr = bus->mmio;
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+ eromptr = ioremap(erombase, BCMA_CORE_SIZE); + eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+ if (!eromptr) + if (!eromptr)
+ return -ENOMEM; + return -ENOMEM;
+ } else + } else {
+ eromptr = bus->mmio; + eromptr = bus->mmio;
+ }
+ +
eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
bcma_scan_switch_core(bus, erombase); bcma_scan_switch_core(bus, erombase);
@@ -447,8 +475,12 @@ int __init bcma_bus_scan_early(struct bc
core->id.class);
list_add(&core->list, &bus->cores);
- return 0;
+ err = 0;
+ break;
}
- return -ENODEV;
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ iounmap(eromptr);
+
+ return err;
}
--- a/include/linux/bcma/bcma.h --- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h
@@ -17,6 +17,7 @@ enum bcma_hosttype { @@ -14,9 +14,9 @@ struct bcma_device;
BCMA_HOSTTYPE_NONE, struct bcma_bus;
enum bcma_hosttype {
- BCMA_HOSTTYPE_NONE,
BCMA_HOSTTYPE_PCI, BCMA_HOSTTYPE_PCI,
BCMA_HOSTTYPE_SDIO, BCMA_HOSTTYPE_SDIO,
+ BCMA_HOSTTYPE_SOC, + BCMA_HOSTTYPE_SOC,
}; };
struct bcma_chipinfo { struct bcma_chipinfo {
@@ -133,6 +134,9 @@ struct bcma_device { @@ -138,6 +138,9 @@ struct bcma_device {
u32 addr; u32 addr;
u32 wrap; u32 wrap;

View File

@ -1,7 +1,7 @@
From 0a1a5fd8aab864e7b531ab88fd317ff7278d884d Mon Sep 17 00:00:00 2001 From 5961a1401605cd1941d5260a03b1dc2e8ae80619 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 6 Jun 2011 00:07:32 +0200 Date: Mon, 6 Jun 2011 00:07:32 +0200
Subject: [PATCH 05/14] bcma: add mips driver Subject: [PATCH 05/22] bcma: add mips driver
This adds a mips driver to bcma. This is only found on embedded This adds a mips driver to bcma. This is only found on embedded
devices. For now the driver just initializes the irqs used on this devices. For now the driver just initializes the irqs used on this
@ -9,51 +9,49 @@ system.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- ---
drivers/bcma/Kconfig | 11 ++- drivers/bcma/Kconfig | 9 +
drivers/bcma/Makefile | 1 + drivers/bcma/Makefile | 1 +
drivers/bcma/driver_mips.c | 234 +++++++++++++++++++++++++++++++++ drivers/bcma/driver_mips.c | 243 +++++++++++++++++++++++++++
drivers/bcma/main.c | 19 +++ drivers/bcma/main.c | 15 ++
include/linux/bcma/bcma.h | 2 + include/linux/bcma/bcma.h | 3 +
include/linux/bcma/bcma_driver_mips.h | 49 +++++++ include/linux/bcma/bcma_driver_chipcommon.h | 13 ++
6 files changed, 315 insertions(+), 1 deletions(-) include/linux/bcma/bcma_driver_mips.h | 49 ++++++
7 files changed, 333 insertions(+), 0 deletions(-)
create mode 100644 drivers/bcma/driver_mips.c create mode 100644 drivers/bcma/driver_mips.c
create mode 100644 include/linux/bcma/bcma_driver_mips.h create mode 100644 include/linux/bcma/bcma_driver_mips.h
--- a/drivers/bcma/Kconfig --- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig
@@ -29,9 +29,18 @@ config BCMA_HOST_PCI @@ -36,7 +36,16 @@ config BCMA_DRIVER_PCI_HOSTMODE
config BCMA_HOST_SOC config BCMA_HOST_SOC
bool bool
- depends on BCMA && MIPS
+ depends on BCMA_DRIVER_MIPS + depends on BCMA_DRIVER_MIPS
default n +
+config BCMA_DRIVER_MIPS +config BCMA_DRIVER_MIPS
+ bool "BCMA Broadcom MIPS core driver" + bool "BCMA Broadcom MIPS core driver"
+ depends on BCMA && MIPS depends on BCMA && MIPS
+ help + help
+ Driver for the Broadcom MIPS core attached to Broadcom specific + Driver for the Broadcom MIPS core attached to Broadcom specific
+ Advanced Microcontroller Bus. + Advanced Microcontroller Bus.
+ +
+ If unsure, say N + If unsure, say N
+
config BCMA_DEBUG config BCMA_DEBUG
bool "BCMA debugging" bool "BCMA debugging"
depends on BCMA
--- a/drivers/bcma/Makefile --- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile
@@ -1,6 +1,7 @@ @@ -2,6 +2,7 @@ bcma-y += main.o scan.o core.o sprom
bcma-y += main.o scan.o core.o sprom.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_pci.o bcma-y += driver_pci.o
bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
+bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o +bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o
obj-$(CONFIG_BCMA) += bcma.o obj-$(CONFIG_BCMA) += bcma.o
--- /dev/null --- /dev/null
+++ b/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c
@@ -0,0 +1,234 @@ @@ -0,0 +1,243 @@
+/* +/*
+ * Broadcom specific AMBA + * Broadcom specific AMBA
+ * Broadcom MIPS32 74K core driver + * Broadcom MIPS32 74K core driver
@ -75,13 +73,22 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+#include <linux/serial_reg.h> +#include <linux/serial_reg.h>
+#include <linux/time.h> +#include <linux/time.h>
+ +
+/* The 47162a0 hangs when reading its registers */ +/* The 47162a0 hangs when reading MIPS DMP registers registers */
+static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) +static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+{ +{
+ return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 && + return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
+ dev->id.id == BCMA_CORE_MIPS_74K; + dev->id.id == BCMA_CORE_MIPS_74K;
+} +}
+ +
+/* The 5357b0 hangs when reading USB20H DMP registers */
+static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
+{
+ return (dev->bus->chipinfo.id == 0x5357 ||
+ dev->bus->chipinfo.id == 0x4749) &&
+ dev->bus->chipinfo.pkg == 11 &&
+ dev->id.id == BCMA_CORE_USB20_HOST;
+}
+
+static inline u32 mips_read32(struct bcma_drv_mips *mcore, +static inline u32 mips_read32(struct bcma_drv_mips *mcore,
+ u16 offset) + u16 offset)
+{ +{
@ -117,15 +124,15 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ +
+ if (bcma_core_mips_bcm47162a0_quirk(dev)) + if (bcma_core_mips_bcm47162a0_quirk(dev))
+ return dev->core_index; + return dev->core_index;
+ if (bcma_core_mips_bcm5357b0_quirk(dev))
+ return dev->core_index;
+ flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30); + flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
+ +
+ return flag & 0x1F; + return flag & 0x1F;
+} +}
+ +
+
+/* Get the MIPS IRQ assignment for a specified device. +/* Get the MIPS IRQ assignment for a specified device.
+ * If unassigned, 0 is returned. + * If unassigned, 0 is returned.
+ * If disabled, 5 is returned.
+ */ + */
+unsigned int bcma_core_mips_irq(struct bcma_device *dev) +unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+{ +{
@ -217,24 +224,24 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+{ +{
+ struct bcma_bus *bus = mcore->core->bus; + struct bcma_bus *bus = mcore->core->bus;
+ +
+ mcore->flash_buswidth = 2; + switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
+ if (bus->drv_cc.core) { + case BCMA_CC_FLASHT_STSER:
+ mcore->flash_window = 0x1c000000; + case BCMA_CC_FLASHT_ATSER:
+ mcore->flash_window_size = 0x02000000; + pr_err("Serial flash not supported.\n");
+ switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { + break;
+ case BCMA_CC_FLASHT_STSER: + case BCMA_CC_FLASHT_PARA:
+ case BCMA_CC_FLASHT_ATSER: + pr_info("found parallel flash.\n");
+ pr_err("Serial flash not supported.\n"); + bus->drv_cc.pflash.window = 0x1c000000;
+ break; + bus->drv_cc.pflash.window_size = 0x02000000;
+ case BCMA_CC_FLASHT_PARA: +
+ if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) & + if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
+ BCMA_CC_OTPS) == 0) + BCMA_CC_FLASH_CFG_DS) == 0)
+ mcore->flash_buswidth = 1; + bus->drv_cc.pflash.buswidth = 1;
+ break; + else
+ } + bus->drv_cc.pflash.buswidth = 2;
+ } else { + break;
+ mcore->flash_window = 0x1fc00000; + default:
+ mcore->flash_window_size = 0x00400000; + pr_err("flash not supported.\n");
+ } + }
+} +}
+ +
@ -290,7 +297,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+} +}
--- a/drivers/bcma/main.c --- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c +++ b/drivers/bcma/main.c
@@ -80,6 +80,7 @@ static int bcma_register_cores(struct bc @@ -84,6 +84,7 @@ static int bcma_register_cores(struct bc
case BCMA_CORE_CHIPCOMMON: case BCMA_CORE_CHIPCOMMON:
case BCMA_CORE_PCI: case BCMA_CORE_PCI:
case BCMA_CORE_PCIE: case BCMA_CORE_PCIE:
@ -298,34 +305,30 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
continue; continue;
} }
@@ -141,6 +142,15 @@ int bcma_bus_register(struct bcma_bus *b @@ -144,6 +145,13 @@ int bcma_bus_register(struct bcma_bus *b
bcma_core_chipcommon_init(&bus->drv_cc); bcma_core_chipcommon_init(&bus->drv_cc);
} }
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ /* Init MIPS core */ + /* Init MIPS core */
+ core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); + core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+ if (core) { + if (core) {
+ bus->drv_mips.core = core; + bus->drv_mips.core = core;
+ bcma_core_mips_init(&bus->drv_mips); + bcma_core_mips_init(&bus->drv_mips);
+ } + }
+#endif
+ +
/* Init PCIE core */ /* Init PCIE core */
core = bcma_find_core(bus, BCMA_CORE_PCIE); core = bcma_find_core(bus, BCMA_CORE_PCIE);
if (core) { if (core) {
@@ -208,6 +218,15 @@ int __init bcma_bus_early_register(struc @@ -214,6 +222,13 @@ int __init bcma_bus_early_register(struc
bcma_core_chipcommon_init(&bus->drv_cc); bcma_core_chipcommon_init(&bus->drv_cc);
} }
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ /* Init MIPS core */ + /* Init MIPS core */
+ core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); + core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+ if (core) { + if (core) {
+ bus->drv_mips.core = core; + bus->drv_mips.core = core;
+ bcma_core_mips_init(&bus->drv_mips); + bcma_core_mips_init(&bus->drv_mips);
+ } + }
+#endif
+ +
pr_info("Early bus registered\n"); pr_info("Early bus registered\n");
@ -340,7 +343,15 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
#include <linux/ssb/ssb.h> /* SPROM sharing */ #include <linux/ssb/ssb.h> /* SPROM sharing */
#include "bcma_regs.h" #include "bcma_regs.h"
@@ -193,6 +194,7 @@ struct bcma_bus { @@ -130,6 +131,7 @@ struct bcma_device {
struct device dev;
struct device *dma_dev;
+
unsigned int irq;
bool dev_registered;
@@ -197,6 +199,7 @@ struct bcma_bus {
struct bcma_drv_cc drv_cc; struct bcma_drv_cc drv_cc;
struct bcma_drv_pci drv_pci; struct bcma_drv_pci drv_pci;
@ -348,6 +359,49 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
/* We decided to share SPROM struct with SSB as long as we do not need /* We decided to share SPROM struct with SSB as long as we do not need
* any hacks for BCMA. This simplifies drivers code. */ * any hacks for BCMA. This simplifies drivers code. */
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -24,6 +24,7 @@
#define BCMA_CC_FLASHT_NONE 0x00000000 /* No flash */
#define BCMA_CC_FLASHT_STSER 0x00000100 /* ST serial flash */
#define BCMA_CC_FLASHT_ATSER 0x00000200 /* Atmel serial flash */
+#define BCMA_CC_FLASHT_NFLASH 0x00000200
#define BCMA_CC_FLASHT_PARA 0x00000700 /* Parallel flash */
#define BCMA_CC_CAP_PLLT 0x00038000 /* PLL Type */
#define BCMA_PLLTYPE_NONE 0x00000000
@@ -178,6 +179,7 @@
#define BCMA_CC_PROG_CFG 0x0120
#define BCMA_CC_PROG_WAITCNT 0x0124
#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
/* 0x1E0 is defined as shared BCMA_CLKCTLST */
#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
@@ -247,6 +249,14 @@ struct bcma_chipcommon_pmu {
u32 crystalfreq; /* The active crystal frequency (in kHz) */
};
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+struct bcma_pflash {
+ u8 buswidth;
+ u32 window;
+ u32 window_size;
+};
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+
struct bcma_drv_cc {
struct bcma_device *core;
u32 status;
@@ -256,6 +266,9 @@ struct bcma_drv_cc {
/* Fast Powerup Delay constant */
u16 fast_pwrup_delay;
struct bcma_chipcommon_pmu pmu;
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_pflash pflash;
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
};
/* Register access */
--- /dev/null --- /dev/null
+++ b/include/linux/bcma/bcma_driver_mips.h +++ b/include/linux/bcma/bcma_driver_mips.h
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
@ -356,17 +410,17 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ +
+#define BCMA_MIPS_IPSFLAG 0x0F08 +#define BCMA_MIPS_IPSFLAG 0x0F08
+/* which sbflags get routed to mips interrupt 1 */ +/* which sbflags get routed to mips interrupt 1 */
+#define BCMA_MIPS_IPSFLAG_IRQ1 0x0000003F +#define BCMA_MIPS_IPSFLAG_IRQ1 0x0000003F
+#define BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0 +#define BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
+/* which sbflags get routed to mips interrupt 2 */ +/* which sbflags get routed to mips interrupt 2 */
+#define BCMA_MIPS_IPSFLAG_IRQ2 0x00003F00 +#define BCMA_MIPS_IPSFLAG_IRQ2 0x00003F00
+#define BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8 +#define BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
+/* which sbflags get routed to mips interrupt 3 */ +/* which sbflags get routed to mips interrupt 3 */
+#define BCMA_MIPS_IPSFLAG_IRQ3 0x003F0000 +#define BCMA_MIPS_IPSFLAG_IRQ3 0x003F0000
+#define BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16 +#define BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
+/* which sbflags get routed to mips interrupt 4 */ +/* which sbflags get routed to mips interrupt 4 */
+#define BCMA_MIPS_IPSFLAG_IRQ4 0x3F000000 +#define BCMA_MIPS_IPSFLAG_IRQ4 0x3F000000
+#define BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24 +#define BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
+ +
+/* MIPS 74K core registers */ +/* MIPS 74K core registers */
+#define BCMA_MIPS_MIPS74K_CORECTL 0x0000 +#define BCMA_MIPS_MIPS74K_CORECTL 0x0000
@ -389,13 +443,13 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ struct bcma_device *core; + struct bcma_device *core;
+ u8 setup_done:1; + u8 setup_done:1;
+ unsigned int assigned_irqs; + unsigned int assigned_irqs;
+
+ u8 flash_buswidth;
+ u32 flash_window;
+ u32 flash_window_size;
+}; +};
+ +
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+extern void bcma_core_mips_init(struct bcma_drv_mips *mcore); +extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+#else
+static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
+#endif
+ +
+extern unsigned int bcma_core_mips_irq(struct bcma_device *dev); +extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+ +

View File

@ -1,63 +1,55 @@
From b7c100827012ba588089807475affe0c69a3f817 Mon Sep 17 00:00:00 2001 From 5088e81ecc5c953df7de84eeedd0817326bc4be4 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 6 Jun 2011 00:07:33 +0200 Date: Mon, 6 Jun 2011 00:07:33 +0200
Subject: [PATCH 06/14] bcma: add serial console support Subject: [PATCH 06/22] bcma: add serial console support
This adds support for serial console to bcma, when operating on an This adds support for serial console to bcma, when operating on an SoC.
embedded device.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- ---
drivers/bcma/bcma_private.h | 6 +++ drivers/bcma/bcma_private.h | 8 ++++
drivers/bcma/driver_chipcommon.c | 64 +++++++++++++++++++++++++++++++++ drivers/bcma/driver_chipcommon.c | 48 +++++++++++++++++++++++++++
drivers/bcma/driver_mips.c | 9 +++++ drivers/bcma/driver_chipcommon_pmu.c | 26 ++++++++++++++
include/linux/bcma/bcma_driver_mips.h | 11 ++++++ drivers/bcma/driver_mips.c | 1 +
4 files changed, 90 insertions(+), 0 deletions(-) include/linux/bcma/bcma_driver_chipcommon.h | 14 ++++++++
5 files changed, 97 insertions(+), 0 deletions(-)
--- a/drivers/bcma/bcma_private.h --- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h
@@ -29,6 +29,12 @@ void bcma_init_bus(struct bcma_bus *bus) @@ -29,6 +29,14 @@ void bcma_init_bus(struct bcma_bus *bus)
/* sprom.c */ /* sprom.c */
int bcma_sprom_get(struct bcma_bus *bus); int bcma_sprom_get(struct bcma_bus *bus);
+/* driver_chipcommon.c */ +/* driver_chipcommon.c */
+#ifdef CONFIG_BCMA_DRIVER_MIPS +#ifdef CONFIG_BCMA_DRIVER_MIPS
+extern int bcma_chipco_serial_init(struct bcma_drv_cc *cc, +void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+ struct bcma_drv_mips_serial_port *ports);
+#endif /* CONFIG_BCMA_DRIVER_MIPS */ +#endif /* CONFIG_BCMA_DRIVER_MIPS */
+
+/* driver_chipcommon_pmu.c */
+u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
+ +
#ifdef CONFIG_BCMA_HOST_PCI #ifdef CONFIG_BCMA_HOST_PCI
/* host_pci.c */ /* host_pci.c */
extern int __init bcma_host_pci_init(void); extern int __init bcma_host_pci_init(void);
--- a/drivers/bcma/driver_chipcommon.c --- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c
@@ -92,3 +92,67 @@ u32 bcma_chipco_gpio_polarity(struct bcm @@ -106,3 +106,51 @@ u32 bcma_chipco_gpio_polarity(struct bcm
{ {
return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
} }
+ +
+#ifdef CONFIG_BCMA_DRIVER_MIPS +#ifdef CONFIG_BCMA_DRIVER_MIPS
+int bcma_chipco_serial_init(struct bcma_drv_cc *cc, +void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+ struct bcma_drv_mips_serial_port *ports)
+{ +{
+ int nr_ports = 0;
+ u32 plltype;
+ unsigned int irq; + unsigned int irq;
+ u32 baud_base, div; + u32 baud_base;
+ u32 i, n; + u32 i;
+ unsigned int ccrev = cc->core->id.rev; + unsigned int ccrev = cc->core->id.rev;
+ struct bcma_serial_port *ports = cc->serial_ports;
+ +
+ plltype = (cc->capabilities & BCMA_CC_CAP_PLLT); + if (ccrev >= 11 && ccrev != 15) {
+ irq = bcma_core_mips_irq(cc->core);
+
+ if ((ccrev >= 11) && (ccrev != 15) && (ccrev != 20)) {
+ /* Fixed ALP clock */ + /* Fixed ALP clock */
+ baud_base = 20000000; + baud_base = bcma_pmu_alp_clock(cc);
+ if (cc->capabilities & BCMA_CC_CAP_PMU) {
+ /* FIXME: baud_base is different for devices with a PMU */
+ WARN_ON(1);
+ }
+ div = 1;
+ if (ccrev >= 21) { + if (ccrev >= 21) {
+ /* Turn off UART clock before switching clocksource. */ + /* Turn off UART clock before switching clocksource. */
+ bcma_cc_write32(cc, BCMA_CC_CORECTL, + bcma_cc_write32(cc, BCMA_CC_CORECTL,
@ -74,78 +66,101 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ bcma_cc_read32(cc, BCMA_CC_CORECTL) + bcma_cc_read32(cc, BCMA_CC_CORECTL)
+ | BCMA_CC_CORECTL_UARTCLKEN); + | BCMA_CC_CORECTL_UARTCLKEN);
+ } + }
+ } else + } else {
+ pr_err("serial not supported on this device ccrev: 0x%x\n", + pr_err("serial not supported on this device ccrev: 0x%x\n",
+ ccrev); + ccrev);
+ return;
+ }
+
+ irq = bcma_core_mips_irq(cc->core);
+ +
+ /* Determine the registers of the UARTs */ + /* Determine the registers of the UARTs */
+ n = (cc->capabilities & BCMA_CC_CAP_NRUART); + cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
+ for (i = 0; i < n; i++) { + for (i = 0; i < cc->nr_serial_ports; i++) {
+ void __iomem *cc_mmio; + ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
+ void __iomem *uart_regs; + (i * 256);
+
+ cc_mmio = cc->core->bus->mmio +
+ (cc->core->core_index * BCMA_CORE_SIZE);
+ uart_regs = cc_mmio + BCMA_CC_UART0_DATA;
+ uart_regs += (i * 256);
+
+ nr_ports++;
+ ports[i].regs = uart_regs;
+ ports[i].irq = irq; + ports[i].irq = irq;
+ ports[i].baud_base = baud_base; + ports[i].baud_base = baud_base;
+ ports[i].reg_shift = 0; + ports[i].reg_shift = 0;
+ } + }
+
+ return nr_ports;
+} +}
+#endif /* CONFIG_BCMA_DRIVER_MIPS */ +#endif /* CONFIG_BCMA_DRIVER_MIPS */
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -136,3 +136,29 @@ void bcma_pmu_init(struct bcma_drv_cc *c
bcma_pmu_swreg_init(cc);
bcma_pmu_workarounds(cc);
}
+
+u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4716:
+ case 0x4748:
+ case 47162:
+ case 0x4313:
+ case 0x5357:
+ case 0x4749:
+ case 53572:
+ /* always 20Mhz */
+ return 20000 * 1000;
+ case 0x5356:
+ case 0x5300:
+ /* always 25Mhz */
+ return 25000 * 1000;
+ default:
+ pr_warn("No ALP clock specified for %04X device, "
+ "pmu rev. %d, using default %d Hz\n",
+ bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
+ }
+ return BCMA_CC_PMU_ALP_CLOCK;
+}
--- a/drivers/bcma/driver_mips.c --- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c
@@ -157,6 +157,14 @@ static void bcma_core_mips_dump_irq(stru @@ -238,6 +238,7 @@ void bcma_core_mips_init(struct bcma_drv
}
}
+static void bcma_core_mips_serial_init(struct bcma_drv_mips *mcore)
+{
+ struct bcma_bus *bus = mcore->core->bus;
+
+ mcore->nr_serial_ports = bcma_chipco_serial_init(&bus->drv_cc,
+ mcore->serial_ports);
+}
+
static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus = mcore->core->bus;
@@ -229,6 +237,7 @@ void bcma_core_mips_init(struct bcma_drv
if (mcore->setup_done) if (mcore->setup_done)
return; return;
+ bcma_core_mips_serial_init(mcore); + bcma_chipco_serial_init(&bus->drv_cc);
bcma_core_mips_flash_detect(mcore); bcma_core_mips_flash_detect(mcore);
mcore->setup_done = true; mcore->setup_done = true;
} }
--- a/include/linux/bcma/bcma_driver_mips.h --- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_mips.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -32,11 +32,22 @@ @@ -241,6 +241,9 @@
#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
struct bcma_device; +/* ALP clock on pre-PMU chips */
+#define BCMA_CC_PMU_ALP_CLOCK 20000000
+struct bcma_drv_mips_serial_port { +
/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
*/
@@ -255,6 +258,14 @@ struct bcma_pflash {
u32 window;
u32 window_size;
};
+
+struct bcma_serial_port {
+ void *regs; + void *regs;
+ unsigned long clockspeed; + unsigned long clockspeed;
+ unsigned int irq; + unsigned int irq;
+ unsigned int baud_base; + unsigned int baud_base;
+ unsigned int reg_shift; + unsigned int reg_shift;
+}; +};
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
struct bcma_drv_mips {
struct bcma_device *core;
u8 setup_done:1;
unsigned int assigned_irqs;
+ int nr_serial_ports; struct bcma_drv_cc {
+ struct bcma_drv_mips_serial_port serial_ports[4]; @@ -268,6 +279,9 @@ struct bcma_drv_cc {
struct bcma_chipcommon_pmu pmu;
#ifdef CONFIG_BCMA_DRIVER_MIPS
struct bcma_pflash pflash;
+ +
u8 flash_buswidth; + int nr_serial_ports;
u32 flash_window; + struct bcma_serial_port serial_ports[4];
u32 flash_window_size; #endif /* CONFIG_BCMA_DRIVER_MIPS */
};

View File

@ -1,32 +1,30 @@
From 257d5fe12600f08df764cac0abc17bef7b6fae9b Mon Sep 17 00:00:00 2001 From e993e8342e660f29a048be872522eedabaa177e1 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 19 Jun 2011 17:51:30 +0200 Date: Sat, 16 Jul 2011 15:19:38 +0200
Subject: [PATCH 07/14] bcma: get CPU clock Subject: [PATCH 07/22] bcma: get CPU clock
Add method to return the clock of the CPU. This is needed by the arch Add method to return the clock of the CPU. This is needed by the arch
code to calculate the mips_hpt_frequency. code to calculate the mips_hpt_frequency.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- ---
drivers/bcma/bcma_private.h | 3 + drivers/bcma/bcma_private.h | 1 +
drivers/bcma/driver_chipcommon_pmu.c | 87 +++++++++++++++++++++++++++ drivers/bcma/driver_chipcommon_pmu.c | 107 +++++++++++++++++++++++++++
drivers/bcma/driver_mips.c | 12 ++++ drivers/bcma/driver_mips.c | 12 +++
include/linux/bcma/bcma_driver_chipcommon.h | 35 +++++++++++ include/linux/bcma/bcma_driver_chipcommon.h | 39 ++++++++++
include/linux/bcma/bcma_driver_mips.h | 1 + include/linux/bcma/bcma_driver_mips.h | 2 +
5 files changed, 138 insertions(+), 0 deletions(-) 5 files changed, 161 insertions(+), 0 deletions(-)
--- a/drivers/bcma/bcma_private.h --- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h
@@ -29,6 +29,9 @@ void bcma_init_bus(struct bcma_bus *bus) @@ -36,6 +36,7 @@ void bcma_chipco_serial_init(struct bcma
/* sprom.c */
int bcma_sprom_get(struct bcma_bus *bus);
+/* driver_chipcommon_pmu.c */ /* driver_chipcommon_pmu.c */
+extern u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc); u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
+ +u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
/* driver_chipcommon.c */
#ifdef CONFIG_BCMA_DRIVER_MIPS #ifdef CONFIG_BCMA_HOST_PCI
extern int bcma_chipco_serial_init(struct bcma_drv_cc *cc, /* host_pci.c */
--- a/drivers/bcma/driver_chipcommon_pmu.c --- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -11,6 +11,13 @@ @@ -11,6 +11,13 @@
@ -43,39 +41,29 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
u32 offset, u32 mask, u32 set) u32 offset, u32 mask, u32 set)
{ {
@@ -136,3 +143,83 @@ void bcma_pmu_init(struct bcma_drv_cc *c @@ -162,3 +169,103 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
bcma_pmu_swreg_init(cc); }
bcma_pmu_workarounds(cc); return BCMA_CC_PMU_ALP_CLOCK;
} }
+ +
+static u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4716:
+ case 0x4748:
+ case 47162:
+ /* always 20Mhz */
+ return 20000 * 1000;
+ default:
+ pr_warn("No ALP clock specified for %04X device, "
+ "pmu rev. %d, using default %d Hz\n",
+ bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
+ }
+ return BCMA_CC_PMU_ALP_CLOCK;
+}
+
+/* Find the output of the "m" pll divider given pll controls that start with +/* Find the output of the "m" pll divider given pll controls that start with
+ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc. + * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
+ */ + */
+static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) +static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
+{ +{
+ u32 tmp, div, ndiv, p1, p2, fc; + u32 tmp, div, ndiv, p1, p2, fc;
+ struct bcma_bus *bus = cc->core->bus;
+
+ BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
+ +
+ BUG_ON(!m || m > 4); + BUG_ON(!m || m > 4);
+ +
+ BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0)); + if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
+ /* Detect failure in clock setting */
+ tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
+ if (tmp & 0x40000)
+ return 133 * 1000000;
+ }
+ +
+ tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF); + tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
+ p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT; + p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
@ -107,6 +95,18 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ case 47162: + case 47162:
+ return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, + return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB); + BCMA_CC_PMU5_MAINPLL_SSB);
+ case 0x5356:
+ return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
+ case 0x5357:
+ case 0x4749:
+ return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
+ case 0x5300:
+ return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
+ case 53572:
+ return 75000000;
+ default: + default:
+ pr_warn("No backplane clock specified for %04X device, " + pr_warn("No backplane clock specified for %04X device, "
+ "pmu rev. %d, using default %d Hz\n", + "pmu rev. %d, using default %d Hz\n",
@ -120,16 +120,34 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+{ +{
+ struct bcma_bus *bus = cc->core->bus; + struct bcma_bus *bus = cc->core->bus;
+ +
+ if ((cc->pmu.rev == 5 || cc->pmu.rev == 6 || cc->pmu.rev == 7) && + if (bus->chipinfo.id == 53572)
+ (bus->chipinfo.id != 0x4319)) + return 300000000;
+ return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, +
+ BCMA_CC_PMU5_MAINPLL_CPU); + if (cc->pmu.rev >= 5) {
+ u32 pll;
+ switch (bus->chipinfo.id) {
+ case 0x5356:
+ pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
+ break;
+ case 0x5357:
+ case 0x4749:
+ pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
+ break;
+ default:
+ pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
+ break;
+ }
+
+ /* TODO: if (bus->chipinfo.id == 0x5300)
+ return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
+ return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
+ }
+ +
+ return bcma_pmu_get_clockcontrol(cc); + return bcma_pmu_get_clockcontrol(cc);
+} +}
--- a/drivers/bcma/driver_mips.c --- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c
@@ -157,6 +157,18 @@ static void bcma_core_mips_dump_irq(stru @@ -166,6 +166,18 @@ static void bcma_core_mips_dump_irq(stru
} }
} }
@ -145,14 +163,14 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+} +}
+EXPORT_SYMBOL(bcma_cpu_clock); +EXPORT_SYMBOL(bcma_cpu_clock);
+ +
static void bcma_core_mips_serial_init(struct bcma_drv_mips *mcore) static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
{ {
struct bcma_bus *bus = mcore->core->bus; struct bcma_bus *bus = mcore->core->bus;
--- a/include/linux/bcma/bcma_driver_chipcommon.h --- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -246,6 +246,41 @@ @@ -241,8 +241,47 @@
#define BCMA_CC_PLLCTL_DATA 0x0664 #define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
#define BCMA_CC_SPROM 0x0830 /* SPROM beginning */ #define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
+/* Divider allocation in 4716/47162/5356 */ +/* Divider allocation in 4716/47162/5356 */
+#define BCMA_CC_PMU5_MAINPLL_CPU 1 +#define BCMA_CC_PMU5_MAINPLL_CPU 1
@ -162,43 +180,50 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+/* PLL usage in 4716/47162 */ +/* PLL usage in 4716/47162 */
+#define BCMA_CC_PMU4716_MAINPLL_PLL0 12 +#define BCMA_CC_PMU4716_MAINPLL_PLL0 12
+ +
+/* ALP clock on pre-PMU chips */ +/* PLL usage in 5356/5357 */
+#define BCMA_CC_PMU_ALP_CLOCK 20000000 +#define BCMA_CC_PMU5356_MAINPLL_PLL0 0
+#define BCMA_CC_PMU5357_MAINPLL_PLL0 0
+
+/* 4706 PMU */
+#define BCMA_CC_PMU4706_MAINPLL_PLL0 0
+
/* ALP clock on pre-PMU chips */
#define BCMA_CC_PMU_ALP_CLOCK 20000000
+/* HT clock for systems with PMU-enabled chipcommon */ +/* HT clock for systems with PMU-enabled chipcommon */
+#define BCMA_CC_PMU_HT_CLOCK 80000000 +#define BCMA_CC_PMU_HT_CLOCK 80000000
+ +
+/* PMU rev 5 (& 6) */ +/* PMU rev 5 (& 6) */
+#define BCMA_CC_PPL_P1P2_OFF 0 +#define BCMA_CC_PPL_P1P2_OFF 0
+#define BCMA_CC_PPL_P1_MASK 0x0f000000 +#define BCMA_CC_PPL_P1_MASK 0x0f000000
+#define BCMA_CC_PPL_P1_SHIFT 24 +#define BCMA_CC_PPL_P1_SHIFT 24
+#define BCMA_CC_PPL_P2_MASK 0x00f00000 +#define BCMA_CC_PPL_P2_MASK 0x00f00000
+#define BCMA_CC_PPL_P2_SHIFT 20 +#define BCMA_CC_PPL_P2_SHIFT 20
+#define BCMA_CC_PPL_M14_OFF 1 +#define BCMA_CC_PPL_M14_OFF 1
+#define BCMA_CC_PPL_MDIV_MASK 0x000000ff +#define BCMA_CC_PPL_MDIV_MASK 0x000000ff
+#define BCMA_CC_PPL_MDIV_WIDTH 8 +#define BCMA_CC_PPL_MDIV_WIDTH 8
+#define BCMA_CC_PPL_NM5_OFF 2 +#define BCMA_CC_PPL_NM5_OFF 2
+#define BCMA_CC_PPL_NDIV_MASK 0xfff00000 +#define BCMA_CC_PPL_NDIV_MASK 0xfff00000
+#define BCMA_CC_PPL_NDIV_SHIFT 20 +#define BCMA_CC_PPL_NDIV_SHIFT 20
+#define BCMA_CC_PPL_FMAB_OFF 3 +#define BCMA_CC_PPL_FMAB_OFF 3
+#define BCMA_CC_PPL_MRAT_MASK 0xf0000000 +#define BCMA_CC_PPL_MRAT_MASK 0xf0000000
+#define BCMA_CC_PPL_MRAT_SHIFT 28 +#define BCMA_CC_PPL_MRAT_SHIFT 28
+#define BCMA_CC_PPL_ABRAT_MASK 0x08000000 +#define BCMA_CC_PPL_ABRAT_MASK 0x08000000
+#define BCMA_CC_PPL_ABRAT_SHIFT 27 +#define BCMA_CC_PPL_ABRAT_SHIFT 27
+#define BCMA_CC_PPL_FDIV_MASK 0x07ffffff +#define BCMA_CC_PPL_FDIV_MASK 0x07ffffff
+#define BCMA_CC_PPL_PLLCTL_OFF 4 +#define BCMA_CC_PPL_PLLCTL_OFF 4
+#define BCMA_CC_PPL_PCHI_OFF 5 +#define BCMA_CC_PPL_PCHI_OFF 5
+#define BCMA_CC_PPL_PCHI_MASK 0x0000003f +#define BCMA_CC_PPL_PCHI_MASK 0x0000003f
+
/* Data for the PMU, if available. /* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU) * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
*/
--- a/include/linux/bcma/bcma_driver_mips.h --- a/include/linux/bcma/bcma_driver_mips.h
+++ b/include/linux/bcma/bcma_driver_mips.h +++ b/include/linux/bcma/bcma_driver_mips.h
@@ -54,6 +54,7 @@ struct bcma_drv_mips { @@ -44,6 +44,8 @@ extern void bcma_core_mips_init(struct b
}; static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
#endif
extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore); +extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
+
extern unsigned int bcma_core_mips_irq(struct bcma_device *dev); extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */

View File

@ -1,24 +1,26 @@
From c0886db6357de20fba4f7c0602eceefba3ad343b Mon Sep 17 00:00:00 2001 From 1db44bc4e7d5abb2966154ac57d1f035dc3e4ec1 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 6 Jun 2011 00:07:36 +0200 Date: Mon, 6 Jun 2011 00:07:36 +0200
Subject: [PATCH 10/14] bcm47xx: prepare to support different buses Subject: [PATCH 08/22] bcm47xx: prepare to support different buses
The ssb bus is not hod directly any more. there is now a union which Prepare bcm47xx to support different System buses. Before adding
contains all the supported buses, now just ssb. As just one system bus support for bcma it should be possible to build bcm47xx without the
can be used at a time the union does not cause any problems. need of ssb. With this patch bcm47xx does not directly contain a
ssb_bus, but a union contain all the supported system buses. As a SoC
just uses one system bus a union is a good choice.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- ---
arch/mips/bcm47xx/gpio.c | 56 ++++++++++++++++---------- arch/mips/bcm47xx/gpio.c | 56 ++++++++++++++++----------
arch/mips/bcm47xx/nvram.c | 15 +++++-- arch/mips/bcm47xx/nvram.c | 15 +++++--
arch/mips/bcm47xx/serial.c | 13 +++++- arch/mips/bcm47xx/serial.c | 13 +++++-
arch/mips/bcm47xx/setup.c | 32 +++++++++++--- arch/mips/bcm47xx/setup.c | 33 ++++++++++++---
arch/mips/bcm47xx/time.c | 9 +++- arch/mips/bcm47xx/time.c | 9 +++-
arch/mips/bcm47xx/wgt634u.c | 13 ++++-- arch/mips/bcm47xx/wgt634u.c | 14 ++++--
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 14 ++++++- arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 14 ++++++-
arch/mips/include/asm/mach-bcm47xx/gpio.h | 55 ++++++++++++++++++------- arch/mips/include/asm/mach-bcm47xx/gpio.h | 55 ++++++++++++++++++-------
drivers/watchdog/bcm47xx_wdt.c | 12 +++++- drivers/watchdog/bcm47xx_wdt.c | 12 +++++-
9 files changed, 158 insertions(+), 61 deletions(-) 9 files changed, 160 insertions(+), 61 deletions(-)
--- a/arch/mips/bcm47xx/gpio.c --- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c +++ b/arch/mips/bcm47xx/gpio.c
@ -277,15 +279,17 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
SSB_CHIPCO_IRQ_GPIO)) SSB_CHIPCO_IRQ_GPIO))
return IRQ_NONE; return IRQ_NONE;
@@ -133,21 +133,24 @@ static int __init wgt634u_init(void) @@ -132,22 +132,26 @@ static int __init wgt634u_init(void)
* machine. Use the MAC address as an heuristic. Netgear Inc. has
* been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx. * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
*/ */
+ u8 *et0mac;
- u8 *et0mac = ssb_bcm47xx.sprom.et0mac; - u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
+ if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB) + if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
+ return -ENODEV; + return -ENODEV;
+ +
+ u8 *et0mac = bcm47xx_bus.ssb.sprom.et0mac; + et0mac = bcm47xx_bus.ssb.sprom.et0mac;
if (et0mac[0] == 0x00 && if (et0mac[0] == 0x00 &&
((et0mac[1] == 0x09 && et0mac[2] == 0x5b) || ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||

View File

@ -1,140 +0,0 @@
From f93062e72447b4a4a51afbe33ea086ce8c922587 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 19 Jun 2011 17:52:09 +0200
Subject: [PATCH 08/14] bcma: add pci(e) host mode
This adds some stub for a pci(e) host controller. This controller is
found on some embedded devices to attach other chips.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/Kconfig | 6 ++++
drivers/bcma/Makefile | 1 +
drivers/bcma/bcma_private.h | 6 ++++
drivers/bcma/driver_pci.c | 14 ++++++++++-
drivers/bcma/driver_pci_host.c | 43 ++++++++++++++++++++++++++++++++++
include/linux/bcma/bcma_driver_pci.h | 1 +
6 files changed, 70 insertions(+), 1 deletions(-)
create mode 100644 drivers/bcma/driver_pci_host.c
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -32,6 +32,12 @@ config BCMA_HOST_SOC
depends on BCMA_DRIVER_MIPS
default n
+config BCMA_DRIVER_PCI_HOSTMODE
+ bool "Hostmode support for BCMA PCI core"
+ depends on BCMA_DRIVER_MIPS
+ help
+ PCIcore hostmode operation (external PCI bus).
+
config BCMA_DRIVER_MIPS
bool "BCMA Broadcom MIPS core driver"
depends on BCMA && MIPS
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -1,6 +1,7 @@
bcma-y += main.o scan.o core.o sprom.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_pci.o
+bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -38,6 +38,12 @@ extern int bcma_chipco_serial_init(struc
struct bcma_drv_mips_serial_port *ports);
#endif /* CONFIG_BCMA_DRIVER_MIPS */
+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+/* driver_pci_host.c */
+int bcma_core_pci_in_hostmode(struct bcma_drv_pci *pc);
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+
#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
@@ -159,9 +159,21 @@ static void bcma_pcicore_serdes_workarou
void bcma_core_pci_init(struct bcma_drv_pci *pc)
{
+ struct bcma_device *core = pc->core;
+
if (pc->setup_done)
return;
- bcma_pcicore_serdes_workaround(pc);
+
+ if (!bcma_core_is_enabled(core))
+ bcma_core_enable(core, 0);
+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+ pc->hostmode = bcma_core_pci_in_hostmode(pc);
+ if (pc->hostmode)
+ bcma_core_pci_hostmode_init(pc);
+#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+ if (!pc->hostmode)
+ bcma_pcicore_serdes_workaround(pc);
+
pc->setup_done = true;
}
--- /dev/null
+++ b/drivers/bcma/driver_pci_host.c
@@ -0,0 +1,43 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Host mode
+ *
+ * Copyright 2005, Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+#include <asm/paccess.h>
+/* Probe a 32bit value on the bus and catch bus exceptions.
+ * Returns nonzero on a bus exception.
+ * This is MIPS specific */
+#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
+
+
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+{
+ /* TODO: implement PCI host mode */
+}
+
+int bcma_core_pci_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 0;
+
+/* TODO: add when sprom is available
+ * if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+ * return 0;
+ */
+
+ return !mips_busprobe32(tmp, (bus->mmio + (pc->core->core_index *
+ BCMA_CORE_SIZE)));
+}
--- a/include/linux/bcma/bcma_driver_pci.h
+++ b/include/linux/bcma/bcma_driver_pci.h
@@ -78,6 +78,7 @@ struct pci_dev;
struct bcma_drv_pci {
struct bcma_device *core;
u8 setup_done:1;
+ u8 hostmode:1;
};
/* Register access */

View File

@ -1,7 +1,7 @@
From 82d03f33ba3e41511e56bd6ae5ae93b3b1bd0b63 Mon Sep 17 00:00:00 2001 From 1f25ff1b0bb5a8deae3aba2ea9c58f9b83f367bb Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Wed, 22 Jun 2011 22:16:35 +0200 Date: Wed, 22 Jun 2011 22:16:35 +0200
Subject: [PATCH 11/14] bcm47xx: make it possible to build bcm47xx without ssb. Subject: [PATCH 09/22] bcm47xx: make it possible to build bcm47xx without ssb.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
@ -63,9 +63,9 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ select SSB_PCICORE_HOSTMODE if PCI + select SSB_PCICORE_HOSTMODE if PCI
+ default y + default y
+ help + help
+ Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support bus. + Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
+ +
+ This will generate an image with support for SSB and MIPS32 R2 instruction set. + This will generate an image with support for SSB and MIPS32 R1 instruction set.
+ +
+endif +endif
--- a/arch/mips/bcm47xx/Makefile --- a/arch/mips/bcm47xx/Makefile

View File

@ -1,37 +0,0 @@
From 5972feafaa3c71c1497b4ef4101b3c6855b7b64e Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 19 Jun 2011 19:14:11 +0200
Subject: [PATCH 09/14] bcma: add check if sprom is available before accessing it.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/main.c | 4 +++-
drivers/bcma/sprom.c | 3 +++
2 files changed, 6 insertions(+), 1 deletions(-)
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -160,7 +160,9 @@ int bcma_bus_register(struct bcma_bus *b
/* Try to get SPROM */
err = bcma_sprom_get(bus);
- if (err) {
+ if (err == -ENOENT) {
+ pr_err("No SPROM available\n");
+ } else if (err) {
pr_err("Failed to get SPROM: %d\n", err);
return -ENOENT;
}
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -143,6 +143,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
if (!bus->drv_cc.core)
return -EOPNOTSUPP;
+ if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
+ return -ENOENT;
+
sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
GFP_KERNEL);
if (!sprom)

View File

@ -1,7 +1,7 @@
From 0b7b4817579b5b283e48b96de24b7b2c1a861644 Mon Sep 17 00:00:00 2001 From 27aa4f76cfe54b6ce3bf98f4d5fd70ab1f60071f Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 6 Jun 2011 00:07:37 +0200 Date: Mon, 6 Jun 2011 00:07:37 +0200
Subject: [PATCH 12/14] bcm47xx: add support for bcma bus Subject: [PATCH 10/22] bcm47xx: add support for bcma bus
This patch add support for the bcma bus. Broadcom uses only Mips 74K This patch add support for the bcma bus. Broadcom uses only Mips 74K
CPUs on the new SoC and on the old ons using ssb bus there are no Mips CPUs on the new SoC and on the old ons using ssb bus there are no Mips
@ -24,10 +24,10 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+++ b/arch/mips/bcm47xx/Kconfig +++ b/arch/mips/bcm47xx/Kconfig
@@ -15,4 +15,17 @@ config BCM47XX_SSB @@ -15,4 +15,17 @@ config BCM47XX_SSB
This will generate an image with support for SSB and MIPS32 R2 instruction set. This will generate an image with support for SSB and MIPS32 R1 instruction set.
+config BCM47XX_BCMA +config BCM47XX_BCMA
+ bool "SSB Support for Broadcom BCM47XX" + bool "BCMA Support for Broadcom BCM47XX"
+ select SYS_HAS_CPU_MIPS32_R2 + select SYS_HAS_CPU_MIPS32_R2
+ select BCMA + select BCMA
+ select BCMA_HOST_SOC + select BCMA_HOST_SOC
@ -48,7 +48,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
#endif #endif
+#ifdef CONFIG_BCM47XX_BCMA +#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA: + case BCM47XX_BUS_TYPE_BCMA:
+ if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES) + if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+ return -EINVAL; + return -EINVAL;
+ +
+ if (test_and_set_bit(gpio, gpio_in_use)) + if (test_and_set_bit(gpio, gpio_in_use))
@ -65,7 +65,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
#endif #endif
+#ifdef CONFIG_BCM47XX_BCMA +#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA: + case BCM47XX_BUS_TYPE_BCMA:
+ if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES) + if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+ return; + return;
+ +
+ clear_bit(gpio, gpio_in_use); + clear_bit(gpio, gpio_in_use);
@ -92,7 +92,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
struct ssb_mipscore *mcore_ssb; struct ssb_mipscore *mcore_ssb;
#endif #endif
+#ifdef CONFIG_BCM47XX_BCMA +#ifdef CONFIG_BCM47XX_BCMA
+ struct bcma_drv_mips *mcore_bcma; + struct bcma_drv_cc *bcma_cc;
+#endif +#endif
struct nvram_header *header; struct nvram_header *header;
int i; int i;
@ -103,9 +103,9 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
#endif #endif
+#ifdef CONFIG_BCM47XX_BCMA +#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA: + case BCM47XX_BUS_TYPE_BCMA:
+ mcore_bcma = &bcm47xx_bus.bcma.bus.drv_mips; + bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
+ base = mcore_bcma->flash_window; + base = bcma_cc->pflash.window;
+ lim = mcore_bcma->flash_window_size; + lim = bcma_cc->pflash.window_size;
+ break; + break;
+#endif +#endif
} }
@ -121,14 +121,14 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+static int __init uart8250_init_bcma(void) +static int __init uart8250_init_bcma(void)
+{ +{
+ int i; + int i;
+ struct bcma_drv_mips *mcore = &(bcm47xx_bus.bcma.bus.drv_mips); + struct bcma_drv_cc *cc = &(bcm47xx_bus.bcma.bus.drv_cc);
+ +
+ memset(&uart8250_data, 0, sizeof(uart8250_data)); + memset(&uart8250_data, 0, sizeof(uart8250_data));
+ +
+ for (i = 0; i < mcore->nr_serial_ports; i++) { + for (i = 0; i < cc->nr_serial_ports; i++) {
+ struct plat_serial8250_port *p = &(uart8250_data[i]); + struct plat_serial8250_port *p = &(uart8250_data[i]);
+ struct bcma_drv_mips_serial_port *bcma_port; + struct bcma_serial_port *bcma_port;
+ bcma_port = &(mcore->serial_ports[i]); + bcma_port = &(cc->serial_ports[i]);
+ +
+ p->mapbase = (unsigned int) bcma_port->regs; + p->mapbase = (unsigned int) bcma_port->regs;
+ p->membase = (void *) bcma_port->regs; + p->membase = (void *) bcma_port->regs;

View File

@ -1,7 +1,7 @@
From 360eb82fd303ac24590a1b99ad1866162f6b0171 Mon Sep 17 00:00:00 2001 From a277b0b02837a167a5766c048dedef8dfc2fb707 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de> From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 6 Jun 2011 00:07:38 +0200 Date: Mon, 6 Jun 2011 00:07:38 +0200
Subject: [PATCH 13/14] bcm47xx: fix irq assignment for new SoCs. Subject: [PATCH 11/22] bcm47xx: fix irq assignment for new SoCs.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- ---

View File

@ -0,0 +1,166 @@
From a1d9c96a6c9b37b26dc1149706f3061b57a62b50 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 17 Jul 2011 14:51:47 +0200
Subject: [PATCH 12/22] bcma: move parallel flash into a union
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
arch/mips/bcm47xx/nvram.c | 7 ++-
drivers/bcma/driver_mips.c | 9 ++--
include/linux/bcma/bcma_driver_chipcommon.h | 75 ++++++++++++++++++++++++++-
3 files changed, 84 insertions(+), 7 deletions(-)
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -50,8 +50,11 @@ static void early_nvram_init(void)
#ifdef CONFIG_BCM47XX_BCMA
case BCM47XX_BUS_TYPE_BCMA:
bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
- base = bcma_cc->pflash.window;
- lim = bcma_cc->pflash.window_size;
+ if (bcma_cc->flash_type != BCMA_PFLASH)
+ return;
+
+ base = bcma_cc->flash.pflash.window;
+ lim = bcma_cc->flash.pflash.window_size;
break;
#endif
}
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -189,14 +189,15 @@ static void bcma_core_mips_flash_detect(
break;
case BCMA_CC_FLASHT_PARA:
pr_info("found parallel flash.\n");
- bus->drv_cc.pflash.window = 0x1c000000;
- bus->drv_cc.pflash.window_size = 0x02000000;
+ bus->drv_cc.flash_type = BCMA_PFLASH;
+ bus->drv_cc.flash.pflash.window = 0x1c000000;
+ bus->drv_cc.flash.pflash.window_size = 0x02000000;
if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
BCMA_CC_FLASH_CFG_DS) == 0)
- bus->drv_cc.pflash.buswidth = 1;
+ bus->drv_cc.flash.pflash.buswidth = 1;
else
- bus->drv_cc.pflash.buswidth = 2;
+ bus->drv_cc.flash.pflash.buswidth = 2;
break;
default:
pr_err("flash not supported.\n");
--- 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 */
@@ -283,6 +341,12 @@
#define BCMA_CC_PPL_PCHI_OFF 5
#define BCMA_CC_PPL_PCHI_MASK 0x0000003f
+#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)
*/
@@ -292,12 +356,20 @@ struct bcma_chipcommon_pmu {
};
#ifdef CONFIG_BCMA_DRIVER_MIPS
+enum bcma_flash_type {
+ BCMA_PFLASH,
+};
+
struct bcma_pflash {
u8 buswidth;
u32 window;
u32 window_size;
};
+union bcma_flash {
+ struct bcma_pflash pflash;
+};
+
struct bcma_serial_port {
void *regs;
unsigned long clockspeed;
@@ -317,7 +389,8 @@ 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 bcma_flash flash;
int nr_serial_ports;
struct bcma_serial_port serial_ports[4];

View File

@ -0,0 +1,675 @@
From b5be6e3037650ff5615cb869f1972dea5a49bcb6 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 17 Jul 2011 14:53:07 +0200
Subject: [PATCH 13/22] bcma: add serial flash support to bcma
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/Kconfig | 5 +
drivers/bcma/Makefile | 1 +
drivers/bcma/bcma_private.h | 5 +
drivers/bcma/driver_chipcommon_sflash.c | 554 +++++++++++++++++++++++++++
drivers/bcma/driver_mips.c | 8 +-
include/linux/bcma/bcma_driver_chipcommon.h | 24 ++
6 files changed, 596 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
@@ -38,6 +38,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,554 @@
+/*
+ * Broadcom SiliconBackplane chipcommon serial flash interface
+ *
+ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
+ * Copyright 2010, Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_driver_chipcommon.h>
+#include <linux/delay.h>
+
+#include "bcma_private.h"
+
+#define NUM_RETRIES 3
+
+
+/* Issue a serial flash command */
+static inline void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
+{
+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
+ BCMA_CC_FLASHCTL_START | opcode);
+ while (bcma_cc_read32(cc, BCMA_CC_FLASHCTL)
+ & BCMA_CC_FLASHCTL_BUSY);
+}
+
+
+static inline void bcma_sflash_write_u8(struct bcma_drv_cc *cc,
+ u32 offset, u8 byte)
+{
+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
+ bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
+}
+
+/* Initialize serial flash access */
+int bcma_sflash_init(struct bcma_drv_cc *cc)
+{
+ u32 id, id2;
+
+ memset(&cc->flash.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->flash.sflash.blocksize = 64 * 1024;
+ switch (id) {
+ case 0x11:
+ /* ST M25P20 2 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 4;
+ break;
+ case 0x12:
+ /* ST M25P40 4 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 8;
+ break;
+ case 0x13:
+ /* ST M25P80 8 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 16;
+ break;
+ case 0x14:
+ /* ST M25P16 16 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 32;
+ break;
+ case 0x15:
+ /* ST M25P32 32 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 64;
+ break;
+ case 0x16:
+ /* ST M25P64 64 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 128;
+ break;
+ case 0x17:
+ /* ST M25FL128 128 Mbit Serial Flash */
+ cc->flash.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->flash.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->flash.sflash.numblocks = 16;
+ break;
+ case 2:
+ /* SST25WF010 1 Mbit Serial Flash */
+ case 0x49:
+ /* SST25VF010 1 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 32;
+ break;
+ case 3:
+ /* SST25WF020 2 Mbit Serial Flash */
+ case 0x43:
+ /* SST25VF020 2 Mbit Serial Flash */
+ cc->flash.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->flash.sflash.numblocks = 128;
+ break;
+ case 5:
+ /* SST25WF080 8 Mbit Serial Flash */
+ case 0x8e:
+ /* SST25VF080B 8 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 256;
+ break;
+ case 0x41:
+ /* SST25VF016 16 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 512;
+ break;
+ case 0x4a:
+ /* SST25VF032 32 Mbit Serial Flash */
+ cc->flash.sflash.numblocks = 1024;
+ break;
+ case 0x4b:
+ /* SST25VF064 64 Mbit Serial Flash */
+ cc->flash.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->flash.sflash.blocksize = 256;
+ cc->flash.sflash.numblocks = 512;
+ break;
+ case 0x14:
+ /* Atmel AT45DB021 2Mbit Serial Flash */
+ cc->flash.sflash.blocksize = 256;
+ cc->flash.sflash.numblocks = 1024;
+ break;
+ case 0x1c:
+ /* Atmel AT45DB041 4Mbit Serial Flash */
+ cc->flash.sflash.blocksize = 256;
+ cc->flash.sflash.numblocks = 2048;
+ break;
+ case 0x24:
+ /* Atmel AT45DB081 8Mbit Serial Flash */
+ cc->flash.sflash.blocksize = 256;
+ cc->flash.sflash.numblocks = 4096;
+ break;
+ case 0x2c:
+ /* Atmel AT45DB161 16Mbit Serial Flash */
+ cc->flash.sflash.blocksize = 512;
+ cc->flash.sflash.numblocks = 4096;
+ break;
+ case 0x34:
+ /* Atmel AT45DB321 32Mbit Serial Flash */
+ cc->flash.sflash.blocksize = 512;
+ cc->flash.sflash.numblocks = 8192;
+ break;
+ case 0x3c:
+ /* Atmel AT45DB642 64Mbit Serial Flash */
+ cc->flash.sflash.blocksize = 1024;
+ cc->flash.sflash.numblocks = 8192;
+ break;
+ }
+ break;
+ }
+
+ cc->flash.sflash.size = cc->flash.sflash.blocksize * cc->flash.sflash.numblocks;
+
+ return cc->flash.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->flash.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->flash.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->flash.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->flash.sflash.size)
+ return -EINVAL;
+
+ sfl = &cc->flash.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->flash.sflash.size)
+ return -EINVAL;
+
+ sfl = &cc->flash.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->flash.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
@@ -358,6 +358,7 @@ struct bcma_chipcommon_pmu {
#ifdef CONFIG_BCMA_DRIVER_MIPS
enum bcma_flash_type {
BCMA_PFLASH,
+ BCMA_SFLASH,
};
struct bcma_pflash {
@@ -366,8 +367,19 @@ 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 */
+
union bcma_flash {
struct bcma_pflash pflash;
+#ifdef CONFIG_BCMA_SFLASH
+ struct bcma_sflash sflash;
+#endif /* CONFIG_BCMA_SFLASH */
};
struct bcma_serial_port {
@@ -433,4 +445,16 @@ u32 bcma_chipco_gpio_polarity(struct bcm
/* PMU support */
extern void bcma_pmu_init(struct bcma_drv_cc *cc);
+#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_ */

View File

@ -0,0 +1,579 @@
From 4b449ce15d74e5973cde18381c2a3fa0616b2b3d Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 17 Jul 2011 14:54:11 +0200
Subject: [PATCH 14/18] mtd: bcm47xx: add bcm47xx part parser
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/mtd/Kconfig | 7 +
drivers/mtd/Makefile | 1 +
drivers/mtd/bcm47xxpart.c | 536 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 544 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/bcm47xxpart.c
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -173,6 +173,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,536 @@
+/*
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
+ *
+ * original functions for finding root filesystem from Mike Baker
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Copyright 2001-2003, Broadcom Corporation
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * Flash mapping for BCM947XX boards
+ */
+
+#define pr_fmt(fmt) "bcm47xx_part: " fmt
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/crc32.h>
+#include <asm/io.h>
+#include <asm/mach-bcm47xx/nvram.h>
+#include <asm/mach-bcm47xx/bcm47xx.h>
+#include <asm/fw/cfe/cfe_api.h>
+
+
+#define TRX_MAGIC 0x30524448 /* "HDR0" */
+#define TRX_VERSION 1
+#define TRX_MAX_LEN 0x3A0000
+#define TRX_NO_HEADER 1 /* Do not write TRX header */
+#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
+#define TRX_MAX_OFFSET 3
+
+struct trx_header {
+ u32 magic; /* "HDR0" */
+ u32 len; /* Length of file including header */
+ u32 crc32; /* 32-bit CRC from flag_version to end of file */
+ u32 flag_version; /* 0:15 flags, 16:31 version */
+ u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
+};
+
+/* for Edimax Print servers which use an additional header
+ * then the firmware on flash looks like :
+ * EDIMAX HEADER | TRX HEADER
+ * As this header is 12 bytes long we have to handle it
+ * and skip it to find the TRX header
+ */
+#define EDIMAX_PS_HEADER_MAGIC 0x36315350 /* "PS16" */
+#define EDIMAX_PS_HEADER_LEN 0xc /* 12 bytes long for edimax header */
+
+#define NVRAM_SPACE 0x8000
+
+#define ROUTER_NETGEAR_WGR614L 1
+#define ROUTER_NETGEAR_WNR834B 2
+#define ROUTER_NETGEAR_WNDR3300 3
+#define ROUTER_NETGEAR_WNR3500L 4
+#define ROUTER_SIMPLETECH_SIMPLESHARE 5
+
+static struct mtd_partition bcm47xx_parts[] = {
+ { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
+ { name: "linux", offset: 0, size: 0, },
+ { name: "rootfs", offset: 0, size: 0, },
+ { name: "nvram", offset: 0, size: 0, },
+ { name: NULL, }, /* Used to create custom partitons with the function get_router() */
+ { name: NULL, },
+};
+
+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 (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)
+ unsigned long 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;
+
+ if ((cfe_size = find_cfe_size(mtd)) < 0)
+ return 0;
+
+ /* boot loader */
+ 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:
+ /* 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");

View File

@ -0,0 +1,238 @@
From 941c7a12af5d985c9dabc6813db3b75908bd619c Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 17 Jul 2011 14:55:18 +0200
Subject: [PATCH 15/22] mtd: bcm47xx: add parallel flash driver
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/mtd/maps/Kconfig | 9 ++
drivers/mtd/maps/Makefile | 1 +
drivers/mtd/maps/bcm47xx-pflash.c | 196 +++++++++++++++++++++++++++++++++++++
3 files changed, 206 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/maps/bcm47xx-pflash.c
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -264,6 +264,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
@@ -60,3 +60,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,196 @@
+/*
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
+ *
+ * original functions for finding root filesystem from Mike Baker
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Copyright 2001-2003, Broadcom Corporation
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * Flash mapping for BCM947XX boards
+ */
+
+#define pr_fmt(fmt) "bcm47xx_pflash: " fmt
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/mach-bcm47xx/bcm47xx.h>
+#include <linux/platform_device.h>
+
+#define WINDOW_ADDR 0x1fc00000
+#define WINDOW_SIZE 0x400000
+#define BUSWIDTH 2
+
+static struct mtd_info *bcm47xx_mtd;
+
+static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ if (len==1) {
+ memcpy_fromio(to, map->virt + from, len);
+ } else {
+ int i;
+ u16 *dest = (u16 *) to;
+ u16 *src = (u16 *) (map->virt + from);
+ for (i = 0; i < (len / 2); i++) {
+ dest[i] = src[i];
+ }
+ if (len & 1)
+ *((u8 *)dest+len-1) = src[i] & 0xff;
+ }
+}
+
+static struct map_info bcm47xx_map = {
+ name: "Physically mapped flash",
+ size: WINDOW_SIZE,
+ bankwidth: BUSWIDTH,
+ phys: WINDOW_ADDR,
+};
+
+static const char *probes[] = { "bcm47xx", NULL };
+
+static int bcm47xx_mtd_probe(struct platform_device *pdev)
+{
+#ifdef CONFIG_BCM47XX_SSB
+ struct ssb_mipscore *mcore_ssb;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ struct bcma_drv_cc *bcma_cc;
+#endif
+ int ret = 0;
+ struct mtd_partition *partitions = NULL;
+ int num_partitions = 0;
+
+ switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+ bcm47xx_map.phys = mcore_ssb->flash_window;
+ bcm47xx_map.size = mcore_ssb->flash_window_size;
+ bcm47xx_map.bankwidth = mcore_ssb->flash_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->flash.pflash.window;
+ bcm47xx_map.size = bcma_cc->flash.pflash.window_size;
+ bcm47xx_map.bankwidth = bcma_cc->flash.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);
+
+ num_partitions = parse_mtd_partitions(bcm47xx_mtd, probes, &partitions, 0);
+ if (num_partitions < 0) {
+ ret = num_partitions;
+ goto err_unmap;
+ }
+
+ ret = mtd_device_register(bcm47xx_mtd, partitions, num_partitions);
+
+// ret = mtd_device_parse_register(bcm47xx_mtd, "bcm47xx", 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");

View File

@ -0,0 +1,312 @@
From 8a6398687998886c451c6df381c2320b6dddb3fe Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 17 Jul 2011 14:55:45 +0200
Subject: [PATCH 16/22] mtd: bcm47xx: add serial flash driver
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/mtd/maps/Kconfig | 9 ++
drivers/mtd/maps/Makefile | 1 +
drivers/mtd/maps/bcm47xx-sflash.c | 270 +++++++++++++++++++++++++++++++++++++
3 files changed, 280 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/maps/bcm47xx-sflash.c
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -273,6 +273,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
@@ -61,3 +61,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,270 @@
+/*
+ * Broadcom SiliconBackplane chipcommon serial flash interface
+ *
+ * Copyright 2006, Broadcom Corporation
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#define pr_fmt(fmt) "bcm47xx_sflash: " fmt
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <bcm47xx.h>
+
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_driver_chipcommon.h>
+#include <linux/platform_device.h>
+
+struct sflash_mtd {
+ struct bcma_drv_cc *cc;
+ struct mtd_info mtd;
+ struct mtd_erase_region_info region;
+};
+
+static struct sflash_mtd *sflash;
+
+static int
+sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout)
+{
+ unsigned long now = jiffies;
+ int ret = 0;
+
+ for (;;) {
+ if (!bcma_sflash_poll(sflash->cc, 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 sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
+
+ /* Check address range */
+ if (!len)
+ return 0;
+
+ if ((from + len) > mtd->size)
+ return -EINVAL;
+
+ *retlen = 0;
+
+ while (len) {
+ int ret = bcma_sflash_read(sflash->cc, 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 sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
+
+ /* Check address range */
+ if (!len)
+ return 0;
+
+ if ((to + len) > mtd->size)
+ return -EINVAL;
+
+ *retlen = 0;
+ while (len) {
+ int bytes;
+ int ret = bcma_sflash_write(sflash->cc, 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 sflash_mtd *sflash = (struct sflash_mtd *) 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) {
+ if ((ret = bcma_sflash_erase(sflash->cc, addr)) < 0)
+ break;
+ if ((ret = sflash_mtd_poll(sflash, addr, 10 * HZ)))
+ 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)
+{
+ int ret = 0;
+
+ struct mtd_partition *parts;
+ int num_partitions = 0;
+
+ sflash = kzalloc(sizeof(struct sflash_mtd), GFP_KERNEL);
+ if (!sflash)
+ return -ENOMEM;
+
+ sflash->cc = &bcm47xx_bus.bcma.bus.drv_cc;
+ if (sflash->cc->flash_type != BCMA_SFLASH)
+ return -ENODEV;
+
+ pr_info("found serial flash: blocksize=%dKB, numblocks=%d, size=%dKB\n",
+ sflash->cc->flash.sflash.blocksize/1024,
+ sflash->cc->flash.sflash.numblocks,
+ sflash->cc->flash.sflash.size/1024);
+
+ /* Setup region info */
+ sflash->region.offset = 0;
+ sflash->region.erasesize = sflash->cc->flash.sflash.blocksize;
+ sflash->region.numblocks = sflash->cc->flash.sflash.numblocks;
+ if (sflash->region.erasesize > sflash->mtd.erasesize)
+ sflash->mtd.erasesize = sflash->region.erasesize;
+ sflash->mtd.size = sflash->cc->flash.sflash.size;
+ sflash->mtd.numeraseregions = 1;
+
+ /* Register with MTD */
+ sflash->mtd.name = "bcm47xx-sflash";
+ sflash->mtd.type = MTD_NORFLASH;
+ sflash->mtd.flags = MTD_CAP_NORFLASH;
+ sflash->mtd.eraseregions = &sflash->region;
+ sflash->mtd.erase = sflash_mtd_erase;
+ sflash->mtd.read = sflash_mtd_read;
+ sflash->mtd.write = sflash_mtd_write;
+ sflash->mtd.writesize = 1;
+ sflash->mtd.priv = sflash;
+ sflash->mtd.owner = THIS_MODULE;
+
+ num_partitions = parse_mtd_partitions(&sflash->mtd, probes, &parts, 0);
+ if (num_partitions < 0) {
+ ret = num_partitions;
+ goto err_destroy;
+ }
+
+ ret = mtd_device_register(&sflash->mtd, parts, num_partitions);
+
+// ret = mtd_device_parse_register(bcm47xx_mtd, "bcm47xx", NULL, NULL, 0);
+
+ if (ret) {
+ pr_err("mtd_device_register failed\n");
+ return ret;
+ }
+ return 0;
+
+err_destroy:
+ map_destroy(&sflash->mtd);
+ return ret;
+}
+
+static int __devexit bcm47xx_sflash_remove(struct platform_device *pdev)
+{
+ if (sflash) {
+ mtd_device_unregister(&sflash->mtd);
+ map_destroy(&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");

View File

@ -0,0 +1,74 @@
From 89b904335338c86ef2c40e7cc51e19673feb62c1 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 17 Jul 2011 15:02:10 +0200
Subject: [PATCH 17/22] bcm47xx: register flash drivers
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
arch/mips/bcm47xx/setup.c | 50 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 50 insertions(+), 0 deletions(-)
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -30,6 +30,7 @@
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_embedded.h>
#include <linux/bcma/bcma_soc.h>
+#include <linux/platform_device.h>
#include <asm/bootinfo.h>
#include <asm/reboot.h>
#include <asm/time.h>
@@ -357,3 +358,52 @@ static int __init bcm47xx_register_bus_c
return 0;
}
device_initcall(bcm47xx_register_bus_complete);
+
+static struct resource bcm47xx_pflash_resource = {
+ .name = "para",
+ .start = 0,
+ .end = 0,
+ .flags = 0,
+};
+
+static struct platform_device bcm47xx_pflash = {
+ .name = "bcm47xx_pflash",
+ .resource = &bcm47xx_pflash_resource,
+ .num_resources = 1,
+};
+
+static struct resource bcm47xx_sflash_resource = {
+ .name = "serial",
+ .start = 0,
+ .end = 0,
+ .flags = 0,
+};
+
+static struct platform_device bcm47xx_sflash = {
+ .name = "bcm47xx_sflash",
+ .resource = &bcm47xx_sflash_resource,
+ .num_resources = 1,
+};
+
+static int __init bcm47xx_register_flash(void)
+{
+ switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ return platform_device_register(&bcm47xx_pflash);
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_PFLASH) {
+ return platform_device_register(&bcm47xx_pflash);
+ } else if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_SFLASH) {
+ return platform_device_register(&bcm47xx_sflash);
+ } else {
+ printk(KERN_ERR "No flash device found\n");
+ return -1;
+ }
+#endif
+ }
+ return 0;
+}
+fs_initcall(bcm47xx_register_flash);

View File

@ -0,0 +1,29 @@
From 1b23f310d4a7d24efe5dffbbde6b2b84252e2d7b Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Fri, 22 Jul 2011 14:18:21 +0200
Subject: [PATCH 19/22] bcma: to not route irqs on non pci devices
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/driver_pci.c | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -208,7 +208,14 @@ int bcma_core_pci_irq_ctl(struct bcma_dr
{
struct pci_dev *pdev = pc->core->bus->host_pci;
u32 coremask, tmp;
- int err;
+ int err = 0;
+
+ if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
+ /* This bcma device is not on a PCI host-bus. So the IRQs are
+ * not routed through the PCI core.
+ * So we must not enable routing through the PCI core. */
+ goto out;
+ }
err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
if (err)

View File

@ -0,0 +1,37 @@
From f3007275d7706afb1381adb0003f3ba69d359c8f Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Fri, 22 Jul 2011 17:09:36 +0200
Subject: [PATCH 20/22] bcma: small fixes needed to get b43 up with SoC
When using an SoC these small cahnges are neede to get it up
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/core.c | 2 ++
drivers/bcma/main.c | 3 +++
2 files changed, 5 insertions(+), 0 deletions(-)
--- a/drivers/bcma/core.c
+++ b/drivers/bcma/core.c
@@ -110,6 +110,8 @@ EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
u32 bcma_core_dma_translation(struct bcma_device *core)
{
switch (core->bus->hosttype) {
+ case BCMA_HOSTTYPE_SOC:
+ return 0;
case BCMA_HOSTTYPE_PCI:
if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
return BCMA_DMA_TRANSLATION_DMA64_CMT;
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -99,7 +99,10 @@ static int bcma_register_cores(struct bc
core->irq = bus->host_pci->irq;
break;
case BCMA_HOSTTYPE_SDIO:
+ break;
case BCMA_HOSTTYPE_SOC:
+ core->dev.dma_mask = &core->dev.coherent_dma_mask;
+ core->dma_dev = &core->dev;
break;
}

View File

@ -0,0 +1,33 @@
From 6dd27601bee9b3c26cdb67246b6da51dd696ac34 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Fri, 22 Jul 2011 17:11:51 +0200
Subject: [PATCH 22/22] bcma: use randoom mac address as long as reading it out does not work
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/sprom.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/etherdevice.h>
#define SPOFF(offset) ((offset) / sizeof(u16))
@@ -144,8 +145,10 @@ int bcma_sprom_get(struct bcma_bus *bus)
if (!bus->drv_cc.core)
return -EOPNOTSUPP;
- if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
+ if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM)) {
+ random_ether_addr(bus->sprom.il0mac);
return -ENOENT;
+ }
sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
GFP_KERNEL);

View File

@ -15,16 +15,16 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- a/arch/mips/bcm47xx/setup.c --- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c
@@ -30,6 +30,8 @@ @@ -31,6 +31,8 @@
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_embedded.h> #include <linux/ssb/ssb_embedded.h>
#include <linux/bcma/bcma_soc.h> #include <linux/bcma/bcma_soc.h>
#include <linux/platform_device.h>
+#include <linux/serial.h> +#include <linux/serial.h>
+#include <linux/serial_8250.h> +#include <linux/serial_8250.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/reboot.h> #include <asm/reboot.h>
#include <asm/time.h> #include <asm/time.h>
@@ -274,6 +276,31 @@ static int bcm47xx_get_invariants(struct @@ -275,6 +277,31 @@ static int bcm47xx_get_invariants(struct
return 0; return 0;
} }
@ -56,7 +56,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
static void __init bcm47xx_register_ssb(void) static void __init bcm47xx_register_ssb(void)
{ {
int err; int err;
@@ -303,6 +330,10 @@ static void __init bcm47xx_register_ssb( @@ -304,6 +331,10 @@ static void __init bcm47xx_register_ssb(
memcpy(&mcore->serial_ports[1], &port, sizeof(port)); memcpy(&mcore->serial_ports[1], &port, sizeof(port));
} }
} }

View File

@ -1,25 +0,0 @@
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -332,6 +332,12 @@ config MTD_CFI_FLAGADM
Mapping for the Flaga digital module. If you don't have one, ignore
this setting.
+config MTD_BCM47XX
+ tristate "BCM47xx flash device"
+ depends on MIPS && MTD_CFI && BCM47XX
+ help
+ Support for the flash chips on the BCM947xx board.
+
config MTD_SOLUTIONENGINE
tristate "CFI Flash device mapped on Hitachi SolutionEngine"
depends on SUPERH && SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcms
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
+obj-$(CONFIG_MTD_BCM47XX) += bcm47xx-flash.o
obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o

View File

@ -1,68 +0,0 @@
--- a/drivers/mtd/maps/bcm47xx-flash.c
+++ b/drivers/mtd/maps/bcm47xx-flash.c
@@ -44,9 +44,7 @@
#include <linux/wait.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
-#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/partitions.h>
-#endif
#include <linux/crc32.h>
#ifdef CONFIG_SSB
#include <linux/ssb/ssb.h>
@@ -120,7 +118,6 @@ static struct map_info bcm47xx_map = {
phys: WINDOW_ADDR,
};
-#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition bcm47xx_parts[] = {
{ name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
@@ -552,7 +549,6 @@ init_mtd_partitions(struct mtd_info *mtd
return bcm47xx_parts;
}
-#endif
int __init init_bcm47xx_map(void)
{
@@ -561,10 +557,8 @@ int __init init_bcm47xx_map(void)
#endif
size_t size;
int ret = 0;
-#ifdef CONFIG_MTD_PARTITIONS
struct mtd_partition *parts;
int i;
-#endif
#ifdef CONFIG_SSB
u32 window = mcore->flash_window;
@@ -602,15 +596,13 @@ int __init init_bcm47xx_map(void)
printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR);
-#ifdef CONFIG_MTD_PARTITIONS
parts = init_mtd_partitions(bcm47xx_mtd, size);
for (i = 0; parts[i].name; i++);
- ret = add_mtd_partitions(bcm47xx_mtd, parts, i);
+ ret = mtd_device_register(bcm47xx_mtd, parts, i);
if (ret) {
- printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
+ printk(KERN_ERR "Flash: mtd_device_register failed\n");
goto fail;
}
-#endif
return 0;
fail:
@@ -624,9 +616,7 @@ int __init init_bcm47xx_map(void)
void __exit cleanup_bcm47xx_map(void)
{
-#ifdef CONFIG_MTD_PARTITIONS
- del_mtd_partitions(bcm47xx_mtd);
-#endif
+ mtd_device_unregister(bcm47xx_mtd);
map_destroy(bcm47xx_mtd);
iounmap((void *)bcm47xx_map.virt);
}

View File

@ -1,78 +0,0 @@
--- a/drivers/mtd/maps/bcm47xx-flash.c
+++ b/drivers/mtd/maps/bcm47xx-flash.c
@@ -46,11 +46,9 @@
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/crc32.h>
-#ifdef CONFIG_SSB
-#include <linux/ssb/ssb.h>
-#endif
#include <asm/io.h>
#include <asm/mach-bcm47xx/nvram.h>
+#include <asm/mach-bcm47xx/bcm47xx.h>
#include <asm/fw/cfe/cfe_api.h>
@@ -90,9 +88,6 @@ struct trx_header {
#define ROUTER_NETGEAR_WNR3500L 4
#define ROUTER_SIMPLETECH_SIMPLESHARE 5
-#ifdef CONFIG_SSB
-extern struct ssb_bus ssb_bcm47xx;
-#endif
static struct mtd_info *bcm47xx_mtd;
static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
@@ -552,27 +547,42 @@ init_mtd_partitions(struct mtd_info *mtd
int __init init_bcm47xx_map(void)
{
-#ifdef CONFIG_SSB
- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+#ifdef CONFIG_BCM47XX_SSB
+ struct ssb_mipscore *mcore_ssb;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ struct bcma_drv_mips *mcore_bcma;
#endif
size_t size;
int ret = 0;
+ u32 window = 0;
+ u32 window_size = 0;
struct mtd_partition *parts;
int i;
-#ifdef CONFIG_SSB
- u32 window = mcore->flash_window;
- u32 window_size = mcore->flash_window_size;
+ switch (bcm47xx_active_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+ window = mcore_ssb->flash_window;
+ window_size = mcore_ssb->flash_window_size;
+ bcm47xx_map.bankwidth = mcore_ssb->flash_buswidth;
+ break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ mcore_bcma = &bcm47xx_bus.bcma.bus.drv_mips;
+ window = mcore_bcma->flash_window;
+ window_size = mcore_bcma->flash_window_size;
+ bcm47xx_map.bankwidth = mcore_bcma->flash_buswidth;
+ break;
+#endif
+ }
printk("flash init: 0x%08x 0x%08x\n", window, window_size);
bcm47xx_map.phys = window;
bcm47xx_map.size = window_size;
- bcm47xx_map.bankwidth = mcore->flash_buswidth;
bcm47xx_map.virt = ioremap_nocache(window, window_size);
-#else
- printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE);
- bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
-#endif
if (!bcm47xx_map.virt) {
printk("Failed to ioremap\n");

View File

@ -1,6 +1,6 @@
--- a/arch/mips/bcm47xx/nvram.c --- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c
@@ -114,3 +114,30 @@ int nvram_getenv(char *name, char *val, @@ -117,3 +117,30 @@ int nvram_getenv(char *name, char *val,
return NVRAM_ERR_ENVNOTFOUND; return NVRAM_ERR_ENVNOTFOUND;
} }
EXPORT_SYMBOL(nvram_getenv); EXPORT_SYMBOL(nvram_getenv);
@ -33,10 +33,10 @@
+EXPORT_SYMBOL(nvram_get); +EXPORT_SYMBOL(nvram_get);
--- a/arch/mips/bcm47xx/setup.c --- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c
@@ -388,3 +388,20 @@ static int __init bcm47xx_register_bus_c @@ -438,3 +438,20 @@ static int __init bcm47xx_register_flash
return 0; return 0;
} }
device_initcall(bcm47xx_register_bus_complete); fs_initcall(bcm47xx_register_flash);
+ +
+static int __init bcm47xx_register_gpiodev(void) +static int __init bcm47xx_register_gpiodev(void)
+{ +{

View File

@ -7,7 +7,7 @@
-obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o -obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
--- a/arch/mips/bcm47xx/wgt634u.c --- a/arch/mips/bcm47xx/wgt634u.c
+++ /dev/null +++ /dev/null
@@ -1,169 +0,0 @@ @@ -1,170 +0,0 @@
-/* -/*
- * This file is subject to the terms and conditions of the GNU General Public - * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive - * License. See the file "COPYING" in the main directory of this archive
@ -142,11 +142,12 @@
- * machine. Use the MAC address as an heuristic. Netgear Inc. has - * machine. Use the MAC address as an heuristic. Netgear Inc. has
- * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx. - * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
- */ - */
- u8 *et0mac;
- -
- if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB) - if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
- return -ENODEV; - return -ENODEV;
- -
- u8 *et0mac = bcm47xx_bus.ssb.sprom.et0mac; - et0mac = bcm47xx_bus.ssb.sprom.et0mac;
- -
- if (et0mac[0] == 0x00 && - if (et0mac[0] == 0x00 &&
- ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) || - ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||

View File

@ -254,7 +254,7 @@ out the configuration than the in kernel cfe config reader.
/* Probe for NVRAM header */ /* Probe for NVRAM header */
static void early_nvram_init(void) static void early_nvram_init(void)
@@ -55,6 +57,25 @@ static void early_nvram_init(void) @@ -58,6 +60,25 @@ static void early_nvram_init(void)
break; break;
#endif #endif
} }
@ -280,7 +280,7 @@ out the configuration than the in kernel cfe config reader.
off = FLASH_MIN; off = FLASH_MIN;
while (off <= lim) { while (off <= lim) {
@@ -96,6 +117,12 @@ int nvram_getenv(char *name, char *val, @@ -99,6 +120,12 @@ int nvram_getenv(char *name, char *val,
if (!nvram_buf[0]) if (!nvram_buf[0])
early_nvram_init(); early_nvram_init();
@ -293,7 +293,7 @@ out the configuration than the in kernel cfe config reader.
/* Look for name=value and return value */ /* Look for name=value and return value */
var = &nvram_buf[sizeof(struct nvram_header)]; var = &nvram_buf[sizeof(struct nvram_header)];
end = nvram_buf + sizeof(nvram_buf) - 2; end = nvram_buf + sizeof(nvram_buf) - 2;
@@ -125,6 +152,9 @@ char *nvram_get(const char *name) @@ -128,6 +155,9 @@ char *nvram_get(const char *name)
if (!nvram_buf[0]) if (!nvram_buf[0])
early_nvram_init(); early_nvram_init();

View File

@ -25,7 +25,7 @@
ssb_printk(KERN_ERR PFX ssb_printk(KERN_ERR PFX
--- a/include/linux/ssb/ssb.h --- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h
@@ -155,9 +155,16 @@ struct ssb_bus_ops { @@ -157,9 +157,16 @@ struct ssb_bus_ops {
#define SSB_DEV_MINI_MACPHY 0x823 #define SSB_DEV_MINI_MACPHY 0x823
#define SSB_DEV_ARM_1176 0x824 #define SSB_DEV_ARM_1176 0x824
#define SSB_DEV_ARM_7TDMI 0x825 #define SSB_DEV_ARM_7TDMI 0x825

View File

@ -1,6 +1,6 @@
--- a/arch/mips/bcm47xx/setup.c --- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c
@@ -273,6 +273,10 @@ static int bcm47xx_get_invariants(struct @@ -274,6 +274,10 @@ static int bcm47xx_get_invariants(struct
if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);

View File

@ -185,7 +185,7 @@
{ {
struct ssb_bus *bus = pc->dev->bus; struct ssb_bus *bus = pc->dev->bus;
u16 chipid_top; u16 chipid_top;
@@ -403,28 +408,129 @@ static int pcicore_is_in_hostmode(struct @@ -403,25 +408,133 @@ static int pcicore_is_in_hostmode(struct
} }
#endif /* CONFIG_SSB_PCICORE_HOSTMODE */ #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
@ -298,8 +298,17 @@
-static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
+static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
{ {
+ ssb_pcicore_fix_sprom_core_index(pc);
+
/* Disable PCI interrupts. */ /* Disable PCI interrupts. */
ssb_write32(pc->dev, SSB_INTVEC, 0); ssb_write32(pc->dev, SSB_INTVEC, 0);
+
+ /* Additional PCIe always once-executed workarounds */
+ if (pc->dev->id.coreid == SSB_DEV_PCIE) {
+ ssb_pcicore_serdes_workaround(pc);
+ /* TODO: ASPM */
+ /* TODO: Clock Request Update */
+ }
} }
-void ssb_pcicore_init(struct ssb_pcicore *pc) -void ssb_pcicore_init(struct ssb_pcicore *pc)
@ -314,25 +323,6 @@
if (!ssb_device_is_enabled(dev)) if (!ssb_device_is_enabled(dev))
ssb_device_enable(dev, 0); ssb_device_enable(dev, 0);
+ ssb_pcicore_fix_sprom_core_index(pc);
+
#ifdef CONFIG_SSB_PCICORE_HOSTMODE
pc->hostmode = pcicore_is_in_hostmode(pc);
if (pc->hostmode)
@@ -432,6 +538,13 @@ void ssb_pcicore_init(struct ssb_pcicore
#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
if (!pc->hostmode)
ssb_pcicore_init_clientmode(pc);
+
+ /* Additional PCIe always once-executed workarounds */
+ if (dev->id.coreid == SSB_DEV_PCIE) {
+ ssb_pcicore_serdes_workaround(pc);
+ /* TODO: ASPM */
+ /* TODO: Clock Request Update */
+ }
}
static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
@@ -446,11 +559,35 @@ static void ssb_pcie_write(struct ssb_pc @@ -446,11 +559,35 @@ static void ssb_pcie_write(struct ssb_pc
pcicore_write32(pc, 0x134, data); pcicore_write32(pc, 0x134, data);
} }
@ -629,7 +619,19 @@
} }
int ssb_device_is_enabled(struct ssb_device *dev) int ssb_device_is_enabled(struct ssb_device *dev)
@@ -1309,20 +1309,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown); @@ -1266,7 +1266,10 @@ u32 ssb_dma_translation(struct ssb_devic
case SSB_BUSTYPE_SSB:
return 0;
case SSB_BUSTYPE_PCI:
- return SSB_PCI_DMA;
+ if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
+ return SSB_PCIE_DMA_H32;
+ else
+ return SSB_PCI_DMA;
default:
__ssb_dma_not_implemented(dev);
}
@@ -1309,20 +1312,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
{ {
@ -654,7 +656,7 @@
return 0; return 0;
error: error:
ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
@@ -1330,6 +1330,37 @@ error: @@ -1330,6 +1333,37 @@ error:
} }
EXPORT_SYMBOL(ssb_bus_powerup); EXPORT_SYMBOL(ssb_bus_powerup);
@ -724,6 +726,22 @@
err = 0; err = 0;
goto out_free; goto out_free;
} }
@@ -728,12 +734,9 @@ out_free:
static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
struct ssb_boardinfo *bi)
{
- pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
- &bi->vendor);
- pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
- &bi->type);
- pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
- &bi->rev);
+ bi->vendor = bus->host_pci->subsystem_vendor;
+ bi->type = bus->host_pci->subsystem_device;
+ bi->rev = bus->host_pci->revision;
}
int ssb_pci_get_invariants(struct ssb_bus *bus,
--- a/drivers/ssb/pcihost_wrapper.c --- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c
@@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci @@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci
@ -856,7 +874,25 @@
/* core.c */ /* core.c */
--- a/include/linux/ssb/ssb.h --- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h
@@ -308,7 +308,7 @@ struct ssb_bus { @@ -27,6 +27,8 @@ struct ssb_sprom {
u8 et1mdcport; /* MDIO for enet1 */
u8 board_rev; /* Board revision number from SPROM. */
u8 country_code; /* Country Code */
+ u16 leddc_on_time; /* LED Powersave Duty Cycle On Count */
+ u16 leddc_off_time; /* LED Powersave Duty Cycle Off Count */
u8 ant_available_a; /* 2GHz antenna available bits (up to 4) */
u8 ant_available_bg; /* 5GHz antenna available bits (up to 4) */
u16 pa0b0;
@@ -99,7 +101,7 @@ struct ssb_sprom {
struct ssb_boardinfo {
u16 vendor;
u16 type;
- u16 rev;
+ u8 rev;
};
@@ -308,7 +310,7 @@ struct ssb_bus {
/* ID information about the Chip. */ /* ID information about the Chip. */
u16 chip_id; u16 chip_id;
@ -865,7 +901,7 @@
u16 sprom_offset; u16 sprom_offset;
u16 sprom_size; /* number of words in sprom */ u16 sprom_size; /* number of words in sprom */
u8 chip_package; u8 chip_package;
@@ -404,7 +404,9 @@ extern bool ssb_is_sprom_available(struc @@ -404,7 +406,9 @@ extern bool ssb_is_sprom_available(struc
/* Set a fallback SPROM. /* Set a fallback SPROM.
* See kdoc at the function definition for complete documentation. */ * See kdoc at the function definition for complete documentation. */
@ -876,7 +912,7 @@
/* Suspend a SSB bus. /* Suspend a SSB bus.
* Call this from the parent bus suspend routine. */ * Call this from the parent bus suspend routine. */
@@ -518,6 +520,7 @@ extern int ssb_bus_may_powerdown(struct @@ -518,6 +522,7 @@ extern int ssb_bus_may_powerdown(struct
* Otherwise static always-on powercontrol will be used. */ * Otherwise static always-on powercontrol will be used. */
extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl); extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);

View File

@ -71,7 +71,7 @@
obj-$(CONFIG_STAGING) += staging/ obj-$(CONFIG_STAGING) += staging/
--- /dev/null --- /dev/null
+++ b/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig
@@ -0,0 +1,38 @@ @@ -0,0 +1,44 @@
+config BCMA_POSSIBLE +config BCMA_POSSIBLE
+ bool + bool
+ depends on HAS_IOMEM && HAS_DMA + depends on HAS_IOMEM && HAS_DMA
@ -101,6 +101,12 @@
+ bool "Support for BCMA on PCI-host bus" + bool "Support for BCMA on PCI-host bus"
+ depends on BCMA_HOST_PCI_POSSIBLE + depends on BCMA_HOST_PCI_POSSIBLE
+ +
+config BCMA_DRIVER_PCI_HOSTMODE
+ bool "Driver for PCI core working in hostmode"
+ depends on BCMA && MIPS
+ help
+ PCI core hostmode operation (external PCI bus).
+
+config BCMA_DEBUG +config BCMA_DEBUG
+ bool "BCMA debugging" + bool "BCMA debugging"
+ depends on BCMA + depends on BCMA
@ -112,10 +118,11 @@
+endmenu +endmenu
--- /dev/null --- /dev/null
+++ b/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile
@@ -0,0 +1,7 @@ @@ -0,0 +1,8 @@
+bcma-y += main.o scan.o core.o sprom.o +bcma-y += main.o scan.o core.o sprom.o
+bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o +bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
+bcma-y += driver_pci.o +bcma-y += driver_pci.o
+bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
+bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o +bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
+obj-$(CONFIG_BCMA) += bcma.o +obj-$(CONFIG_BCMA) += bcma.o
+ +
@ -150,7 +157,7 @@
+- Create kernel Documentation (use info from README) +- Create kernel Documentation (use info from README)
--- /dev/null --- /dev/null
+++ b/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h
@@ -0,0 +1,31 @@ @@ -0,0 +1,35 @@
+#ifndef LINUX_BCMA_PRIVATE_H_ +#ifndef LINUX_BCMA_PRIVATE_H_
+#define LINUX_BCMA_PRIVATE_H_ +#define LINUX_BCMA_PRIVATE_H_
+ +
@ -181,10 +188,14 @@
+extern void __exit bcma_host_pci_exit(void); +extern void __exit bcma_host_pci_exit(void);
+#endif /* CONFIG_BCMA_HOST_PCI */ +#endif /* CONFIG_BCMA_HOST_PCI */
+ +
+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+
+#endif +#endif
--- /dev/null --- /dev/null
+++ b/drivers/bcma/core.c +++ b/drivers/bcma/core.c
@@ -0,0 +1,52 @@ @@ -0,0 +1,124 @@
+/* +/*
+ * Broadcom specific AMBA + * Broadcom specific AMBA
+ * Core ops + * Core ops
@ -237,9 +248,81 @@
+ return 0; + return 0;
+} +}
+EXPORT_SYMBOL_GPL(bcma_core_enable); +EXPORT_SYMBOL_GPL(bcma_core_enable);
+
+void bcma_core_set_clockmode(struct bcma_device *core,
+ enum bcma_clkmode clkmode)
+{
+ u16 i;
+
+ WARN_ON(core->id.id != BCMA_CORE_CHIPCOMMON &&
+ core->id.id != BCMA_CORE_PCIE &&
+ core->id.id != BCMA_CORE_80211);
+
+ switch (clkmode) {
+ case BCMA_CLKMODE_FAST:
+ bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+ udelay(64);
+ for (i = 0; i < 1500; i++) {
+ if (bcma_read32(core, BCMA_CLKCTLST) &
+ BCMA_CLKCTLST_HAVEHT) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ pr_err("HT force timeout\n");
+ break;
+ case BCMA_CLKMODE_DYNAMIC:
+ pr_warn("Dynamic clockmode not supported yet!\n");
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(bcma_core_set_clockmode);
+
+void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on)
+{
+ u16 i;
+
+ WARN_ON(req & ~BCMA_CLKCTLST_EXTRESREQ);
+ WARN_ON(status & ~BCMA_CLKCTLST_EXTRESST);
+
+ if (on) {
+ bcma_set32(core, BCMA_CLKCTLST, req);
+ for (i = 0; i < 10000; i++) {
+ if ((bcma_read32(core, BCMA_CLKCTLST) & status) ==
+ status) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ pr_err("PLL enable timeout\n");
+ } else {
+ pr_warn("Disabling PLL not supported yet!\n");
+ }
+}
+EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
+
+u32 bcma_core_dma_translation(struct bcma_device *core)
+{
+ switch (core->bus->hosttype) {
+ case BCMA_HOSTTYPE_PCI:
+ if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
+ return BCMA_DMA_TRANSLATION_DMA64_CMT;
+ else
+ return BCMA_DMA_TRANSLATION_DMA32_CMT;
+ default:
+ pr_err("DMA translation unknown for host %d\n",
+ core->bus->hosttype);
+ }
+ return BCMA_DMA_TRANSLATION_NONE;
+}
+EXPORT_SYMBOL(bcma_core_dma_translation);
--- /dev/null --- /dev/null
+++ b/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c
@@ -0,0 +1,89 @@ @@ -0,0 +1,103 @@
+/* +/*
+ * Broadcom specific AMBA + * Broadcom specific AMBA
+ * ChipCommon core driver + * ChipCommon core driver
@ -265,6 +348,9 @@
+ +
+void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) +void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
+{ +{
+ u32 leddc_on = 10;
+ u32 leddc_off = 90;
+
+ if (cc->core->id.rev >= 11) + if (cc->core->id.rev >= 11)
+ cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); + cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
+ cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); + cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
@ -280,6 +366,17 @@
+ bcma_pmu_init(cc); + bcma_pmu_init(cc);
+ if (cc->capabilities & BCMA_CC_CAP_PCTL) + if (cc->capabilities & BCMA_CC_CAP_PCTL)
+ pr_err("Power control not implemented!\n"); + pr_err("Power control not implemented!\n");
+
+ if (cc->core->id.rev >= 16) {
+ if (cc->core->bus->sprom.leddc_on_time &&
+ cc->core->bus->sprom.leddc_off_time) {
+ leddc_on = cc->core->bus->sprom.leddc_on_time;
+ leddc_off = cc->core->bus->sprom.leddc_off_time;
+ }
+ bcma_cc_write32(cc, BCMA_CC_GPIOTIMER,
+ ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
+ (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
+ }
+} +}
+ +
+/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
@ -472,7 +569,7 @@
+} +}
--- /dev/null --- /dev/null
+++ b/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c
@@ -0,0 +1,187 @@ @@ -0,0 +1,223 @@
+/* +/*
+ * Broadcom specific AMBA + * Broadcom specific AMBA
+ * PCI Core + * PCI Core
@ -632,11 +729,47 @@
+ * Init. + * Init.
+ **************************************************/ + **************************************************/
+ +
+void bcma_core_pci_init(struct bcma_drv_pci *pc) +static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
+{ +{
+ bcma_pcicore_serdes_workaround(pc); + bcma_pcicore_serdes_workaround(pc);
+} +}
+ +
+static bool 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;
+
+ if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+ return false;
+
+#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 bcma_core_pci_init(struct bcma_drv_pci *pc)
+{
+ if (bcma_core_pci_is_in_hostmode(pc)) {
+#ifdef CONFIG_BCMA_DRIVER_PCI_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);
+ }
+}
+
+int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
+ bool enable) + bool enable)
+{ +{
@ -916,7 +1049,7 @@
+} +}
--- /dev/null --- /dev/null
+++ b/drivers/bcma/main.c +++ b/drivers/bcma/main.c
@@ -0,0 +1,255 @@ @@ -0,0 +1,257 @@
+/* +/*
+ * Broadcom specific AMBA + * Broadcom specific AMBA
+ * Bus subsystem + * Bus subsystem
@ -1068,7 +1201,9 @@
+ +
+ /* Try to get SPROM */ + /* Try to get SPROM */
+ err = bcma_sprom_get(bus); + err = bcma_sprom_get(bus);
+ if (err) { + if (err == -ENOENT) {
+ pr_err("No SPROM available\n");
+ } else if (err) {
+ pr_err("Failed to get SPROM: %d\n", err); + pr_err("Failed to get SPROM: %d\n", err);
+ return -ENOENT; + return -ENOENT;
+ } + }
@ -1596,7 +1731,7 @@
+#endif /* BCMA_SCAN_H_ */ +#endif /* BCMA_SCAN_H_ */
--- /dev/null --- /dev/null
+++ b/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h
@@ -0,0 +1,250 @@ @@ -0,0 +1,271 @@
+#ifndef LINUX_BCMA_H_ +#ifndef LINUX_BCMA_H_
+#define LINUX_BCMA_H_ +#define LINUX_BCMA_H_
+ +
@ -1624,6 +1759,11 @@
+ u8 pkg; + u8 pkg;
+}; +};
+ +
+enum bcma_clkmode {
+ BCMA_CLKMODE_FAST,
+ BCMA_CLKMODE_DYNAMIC,
+};
+
+struct bcma_host_ops { +struct bcma_host_ops {
+ u8 (*read8)(struct bcma_device *core, u16 offset); + u8 (*read8)(struct bcma_device *core, u16 offset);
+ u16 (*read16)(struct bcma_device *core, u16 offset); + u16 (*read16)(struct bcma_device *core, u16 offset);
@ -1842,14 +1982,30 @@
+ core->bus->ops->awrite32(core, offset, value); + core->bus->ops->awrite32(core, offset, value);
+} +}
+ +
+#define bcma_mask32(cc, offset, mask) \
+ bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
+#define bcma_set32(cc, offset, set) \
+ bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
+#define bcma_maskset32(cc, offset, mask, set) \
+ bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
+
+extern bool bcma_core_is_enabled(struct bcma_device *core); +extern bool bcma_core_is_enabled(struct bcma_device *core);
+extern void bcma_core_disable(struct bcma_device *core, u32 flags); +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
+extern int bcma_core_enable(struct bcma_device *core, u32 flags); +extern int bcma_core_enable(struct bcma_device *core, u32 flags);
+extern void bcma_core_set_clockmode(struct bcma_device *core,
+ enum bcma_clkmode clkmode);
+extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status,
+ bool on);
+#define BCMA_DMA_TRANSLATION_MASK 0xC0000000
+#define BCMA_DMA_TRANSLATION_NONE 0x00000000
+#define BCMA_DMA_TRANSLATION_DMA32_CMT 0x40000000 /* Client Mode Translation for 32-bit DMA */
+#define BCMA_DMA_TRANSLATION_DMA64_CMT 0x80000000 /* Client Mode Translation for 64-bit DMA */
+extern u32 bcma_core_dma_translation(struct bcma_device *core);
+ +
+#endif /* LINUX_BCMA_H_ */ +#endif /* LINUX_BCMA_H_ */
--- /dev/null --- /dev/null
+++ b/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -0,0 +1,303 @@ @@ -0,0 +1,296 @@
+#ifndef LINUX_BCMA_DRIVER_CC_H_ +#ifndef LINUX_BCMA_DRIVER_CC_H_
+#define LINUX_BCMA_DRIVER_CC_H_ +#define LINUX_BCMA_DRIVER_CC_H_
+ +
@ -2031,15 +2187,7 @@
+#define BCMA_CC_PROG_WAITCNT 0x0124 +#define BCMA_CC_PROG_WAITCNT 0x0124
+#define BCMA_CC_FLASH_CFG 0x0128 +#define BCMA_CC_FLASH_CFG 0x0128
+#define BCMA_CC_FLASH_WAITCNT 0x012C +#define BCMA_CC_FLASH_WAITCNT 0x012C
+#define BCMA_CC_CLKCTLST 0x01E0 /* Clock control and status (rev >= 20) */ +/* 0x1E0 is defined as shared BCMA_CLKCTLST */
+#define BCMA_CC_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */
+#define BCMA_CC_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */
+#define BCMA_CC_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */
+#define BCMA_CC_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */
+#define BCMA_CC_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
+#define BCMA_CC_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
+#define BCMA_CC_CLKCTLST_HAVEHT 0x00010000 /* HT available */
+#define BCMA_CC_CLKCTLST_HAVEALP 0x00020000 /* APL available */
+#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */ +#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
+#define BCMA_CC_UART0_DATA 0x0300 +#define BCMA_CC_UART0_DATA 0x0300
+#define BCMA_CC_UART0_IMR 0x0304 +#define BCMA_CC_UART0_IMR 0x0304
@ -2096,7 +2244,8 @@
+#define BCMA_CC_REGCTL_DATA 0x065C +#define BCMA_CC_REGCTL_DATA 0x065C
+#define BCMA_CC_PLLCTL_ADDR 0x0660 +#define BCMA_CC_PLLCTL_ADDR 0x0660
+#define BCMA_CC_PLLCTL_DATA 0x0664 +#define BCMA_CC_PLLCTL_DATA 0x0664
+#define BCMA_CC_SPROM 0x0830 /* SPROM beginning */ +#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
+#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
+ +
+/* Data for the PMU, if available. +/* Data for the PMU, if available.
+ * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU) + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
@ -2249,17 +2398,42 @@
+#endif /* LINUX_BCMA_DRIVER_PCI_H_ */ +#endif /* LINUX_BCMA_DRIVER_PCI_H_ */
--- /dev/null --- /dev/null
+++ b/include/linux/bcma/bcma_regs.h +++ b/include/linux/bcma/bcma_regs.h
@@ -0,0 +1,34 @@ @@ -0,0 +1,59 @@
+#ifndef LINUX_BCMA_REGS_H_ +#ifndef LINUX_BCMA_REGS_H_
+#define LINUX_BCMA_REGS_H_ +#define LINUX_BCMA_REGS_H_
+ +
+/* Some single registers are shared between many cores */
+/* BCMA_CLKCTLST: ChipCommon (rev >= 20), PCIe, 80211 */
+#define BCMA_CLKCTLST 0x01E0 /* Clock control and status */
+#define BCMA_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */
+#define BCMA_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */
+#define BCMA_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */
+#define BCMA_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */
+#define BCMA_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
+#define BCMA_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
+#define BCMA_CLKCTLST_EXTRESREQ 0x00000700 /* Mask of external resource requests */
+#define BCMA_CLKCTLST_HAVEALP 0x00010000 /* ALP available */
+#define BCMA_CLKCTLST_HAVEHT 0x00020000 /* HT available */
+#define BCMA_CLKCTLST_BP_ON_ALP 0x00040000 /* RO: running on ALP clock */
+#define BCMA_CLKCTLST_BP_ON_HT 0x00080000 /* RO: running on HT clock */
+#define BCMA_CLKCTLST_EXTRESST 0x07000000 /* Mask of external resource status */
+/* Is there any BCM4328 on BCMA bus? */
+#define BCMA_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */
+#define BCMA_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */
+
+/* Agent registers (common for every core) */ +/* Agent registers (common for every core) */
+#define BCMA_IOCTL 0x0408 +#define BCMA_IOCTL 0x0408 /* IO control */
+#define BCMA_IOCTL_CLK 0x0001 +#define BCMA_IOCTL_CLK 0x0001
+#define BCMA_IOCTL_FGC 0x0002 +#define BCMA_IOCTL_FGC 0x0002
+#define BCMA_IOCTL_CORE_BITS 0x3FFC +#define BCMA_IOCTL_CORE_BITS 0x3FFC
+#define BCMA_IOCTL_PME_EN 0x4000 +#define BCMA_IOCTL_PME_EN 0x4000
+#define BCMA_IOCTL_BIST_EN 0x8000 +#define BCMA_IOCTL_BIST_EN 0x8000
+#define BCMA_IOST 0x0500 /* IO status */
+#define BCMA_IOST_CORE_BITS 0x0FFF
+#define BCMA_IOST_DMA64 0x1000
+#define BCMA_IOST_GATED_CLK 0x2000
+#define BCMA_IOST_BIST_ERROR 0x4000
+#define BCMA_IOST_BIST_DONE 0x8000
+#define BCMA_RESET_CTL 0x0800 +#define BCMA_RESET_CTL 0x0800
+#define BCMA_RESET_CTL_RESET 0x0001 +#define BCMA_RESET_CTL_RESET 0x0001
+ +
@ -2350,7 +2524,7 @@
sizeof(struct virtio_device_id), "virtio", sizeof(struct virtio_device_id), "virtio",
--- /dev/null --- /dev/null
+++ b/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c
@@ -0,0 +1,162 @@ @@ -0,0 +1,171 @@
+/* +/*
+ * Broadcom specific AMBA + * Broadcom specific AMBA
+ * SPROM reading + * SPROM reading
@ -2373,12 +2547,12 @@
+ * R/W ops. + * R/W ops.
+ **************************************************/ + **************************************************/
+ +
+static void bcma_sprom_read(struct bcma_bus *bus, u16 *sprom) +static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
+{ +{
+ int i; + int i;
+ for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++) + for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
+ sprom[i] = bcma_read16(bus->drv_cc.core, + sprom[i] = bcma_read16(bus->drv_cc.core,
+ BCMA_CC_SPROM + (i * 2)); + offset + (i * 2));
+} +}
+ +
+/************************************************** +/**************************************************
@ -2465,7 +2639,7 @@
+ return err; + return err;
+ +
+ revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV; + revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
+ if (revision != 8) { + if (revision != 8 && revision != 9) {
+ pr_err("Unsupported SPROM revision: %d\n", revision); + pr_err("Unsupported SPROM revision: %d\n", revision);
+ return -ENOENT; + return -ENOENT;
+ } + }
@ -2490,18 +2664,27 @@
+ +
+int bcma_sprom_get(struct bcma_bus *bus) +int bcma_sprom_get(struct bcma_bus *bus)
+{ +{
+ u16 offset;
+ u16 *sprom; + u16 *sprom;
+ int err = 0; + int err = 0;
+ +
+ if (!bus->drv_cc.core) + if (!bus->drv_cc.core)
+ return -EOPNOTSUPP; + return -EOPNOTSUPP;
+ +
+ if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
+ return -ENOENT;
+
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), + sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ GFP_KERNEL); + GFP_KERNEL);
+ if (!sprom) + if (!sprom)
+ return -ENOMEM; + return -ENOMEM;
+ +
+ bcma_sprom_read(bus, sprom); + /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
+ * According to brcm80211 this applies to cards with PCIe rev >= 6
+ * TODO: understand this condition and use it */
+ offset = (bus->chipinfo.id == 0x4331) ? BCMA_CC_SPROM :
+ BCMA_CC_SPROM_PCIE6;
+ bcma_sprom_read(bus, offset, sprom);
+ +
+ err = bcma_sprom_valid(sprom); + err = bcma_sprom_valid(sprom);
+ if (err) + if (err)
@ -2513,3 +2696,20 @@
+ kfree(sprom); + kfree(sprom);
+ return err; + return err;
+} +}
--- /dev/null
+++ b/drivers/bcma/driver_pci_host.c
@@ -0,0 +1,14 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Core in hostmode
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+{
+ pr_err("No support for PCI core in hostmode yet\n");
+}

View File

@ -409,7 +409,7 @@
static struct dentry *shmem_get_parent(struct dentry *child) static struct dentry *shmem_get_parent(struct dentry *child)
{ {
@@ -2402,8 +2606,10 @@ int shmem_fill_super(struct super_block @@ -2402,8 +2606,10 @@ int shmem_fill_super(struct super_block
sb->s_magic = TMPFS_MAGIC; sb->s_magic = TMPFS_MAGIC;
sb->s_op = &shmem_ops; sb->s_op = &shmem_ops;
sb->s_time_gran = 1; sb->s_time_gran = 1;

View File

@ -17,3 +17,13 @@
config SSB_PCMCIAHOST_POSSIBLE config SSB_PCMCIAHOST_POSSIBLE
bool bool
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -17,6 +17,7 @@ config BCMA
config BCMA_BLOCKIO
bool
depends on BCMA
+ default y
config BCMA_HOST_PCI_POSSIBLE
bool

View File

@ -8,7 +8,7 @@
endif # BLOCK endif # BLOCK
@@ -177,6 +176,10 @@ source "fs/hfsplus/Kconfig" @@ -193,6 +192,10 @@ source "fs/hfsplus/Kconfig"
source "fs/befs/Kconfig" source "fs/befs/Kconfig"
source "fs/bfs/Kconfig" source "fs/bfs/Kconfig"
source "fs/efs/Kconfig" source "fs/efs/Kconfig"

View File

@ -179,6 +179,36 @@
case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
@@ -1265,7 +1266,10 @@ u32 ssb_dma_translation(struct ssb_devic
case SSB_BUSTYPE_SSB:
return 0;
case SSB_BUSTYPE_PCI:
- return SSB_PCI_DMA;
+ if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
+ return SSB_PCIE_DMA_H32;
+ else
+ return SSB_PCI_DMA;
default:
__ssb_dma_not_implemented(dev);
}
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -734,12 +734,9 @@ out_free:
static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
struct ssb_boardinfo *bi)
{
- pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
- &bi->vendor);
- pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
- &bi->type);
- pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
- &bi->rev);
+ bi->vendor = bus->host_pci->subsystem_vendor;
+ bi->type = bus->host_pci->subsystem_device;
+ bi->rev = bus->host_pci->revision;
}
int ssb_pci_get_invariants(struct ssb_bus *bus,
--- a/drivers/ssb/pcihost_wrapper.c --- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c
@@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci @@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci
@ -213,3 +243,23 @@
bus->chip_package = 0; bus->chip_package = 0;
} else { } else {
bus->chip_id = 0x4710; bus->chip_id = 0x4710;
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -27,6 +27,8 @@ struct ssb_sprom {
u8 et1mdcport; /* MDIO for enet1 */
u8 board_rev; /* Board revision number from SPROM. */
u8 country_code; /* Country Code */
+ u16 leddc_on_time; /* LED Powersave Duty Cycle On Count */
+ u16 leddc_off_time; /* LED Powersave Duty Cycle Off Count */
u8 ant_available_a; /* 2GHz antenna available bits (up to 4) */
u8 ant_available_bg; /* 5GHz antenna available bits (up to 4) */
u16 pa0b0;
@@ -99,7 +101,7 @@ struct ssb_sprom {
struct ssb_boardinfo {
u16 vendor;
u16 type;
- u16 rev;
+ u8 rev;
};

View File

@ -12,17 +12,33 @@
config BCMA_HOST_PCI_POSSIBLE config BCMA_HOST_PCI_POSSIBLE
bool bool
depends on BCMA && PCI = y depends on BCMA && PCI = y
@@ -22,6 +27,12 @@ config BCMA_HOST_PCI
bool "Support for BCMA on PCI-host bus"
depends on BCMA_HOST_PCI_POSSIBLE
+config BCMA_DRIVER_PCI_HOSTMODE
+ bool "Driver for PCI core working in hostmode"
+ depends on BCMA && MIPS
+ help
+ PCI core hostmode operation (external PCI bus).
+
config BCMA_DEBUG
bool "BCMA debugging"
depends on BCMA
--- a/drivers/bcma/Makefile --- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile
@@ -1,4 +1,4 @@ @@ -1,6 +1,7 @@
-bcma-y += main.o scan.o core.o -bcma-y += main.o scan.o core.o
+bcma-y += main.o scan.o core.o sprom.o +bcma-y += main.o scan.o core.o sprom.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_pci.o bcma-y += driver_pci.o
+bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
obj-$(CONFIG_BCMA) += bcma.o
--- a/drivers/bcma/bcma_private.h --- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h
@@ -13,12 +13,15 @@ @@ -13,16 +13,23 @@
struct bcma_bus; struct bcma_bus;
/* main.c */ /* main.c */
@ -40,6 +56,14 @@
#ifdef CONFIG_BCMA_HOST_PCI #ifdef CONFIG_BCMA_HOST_PCI
/* host_pci.c */ /* host_pci.c */
extern int __init bcma_host_pci_init(void); extern int __init bcma_host_pci_init(void);
extern void __exit bcma_host_pci_exit(void);
#endif /* CONFIG_BCMA_HOST_PCI */
+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+
#endif
--- a/drivers/bcma/core.c --- a/drivers/bcma/core.c
+++ b/drivers/bcma/core.c +++ b/drivers/bcma/core.c
@@ -19,7 +19,7 @@ bool bcma_core_is_enabled(struct bcma_de @@ -19,7 +19,7 @@ bool bcma_core_is_enabled(struct bcma_de
@ -59,6 +83,82 @@
int bcma_core_enable(struct bcma_device *core, u32 flags) int bcma_core_enable(struct bcma_device *core, u32 flags)
{ {
@@ -49,3 +50,75 @@ int bcma_core_enable(struct bcma_device
return 0;
}
EXPORT_SYMBOL_GPL(bcma_core_enable);
+
+void bcma_core_set_clockmode(struct bcma_device *core,
+ enum bcma_clkmode clkmode)
+{
+ u16 i;
+
+ WARN_ON(core->id.id != BCMA_CORE_CHIPCOMMON &&
+ core->id.id != BCMA_CORE_PCIE &&
+ core->id.id != BCMA_CORE_80211);
+
+ switch (clkmode) {
+ case BCMA_CLKMODE_FAST:
+ bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+ udelay(64);
+ for (i = 0; i < 1500; i++) {
+ if (bcma_read32(core, BCMA_CLKCTLST) &
+ BCMA_CLKCTLST_HAVEHT) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ pr_err("HT force timeout\n");
+ break;
+ case BCMA_CLKMODE_DYNAMIC:
+ pr_warn("Dynamic clockmode not supported yet!\n");
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(bcma_core_set_clockmode);
+
+void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on)
+{
+ u16 i;
+
+ WARN_ON(req & ~BCMA_CLKCTLST_EXTRESREQ);
+ WARN_ON(status & ~BCMA_CLKCTLST_EXTRESST);
+
+ if (on) {
+ bcma_set32(core, BCMA_CLKCTLST, req);
+ for (i = 0; i < 10000; i++) {
+ if ((bcma_read32(core, BCMA_CLKCTLST) & status) ==
+ status) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ pr_err("PLL enable timeout\n");
+ } else {
+ pr_warn("Disabling PLL not supported yet!\n");
+ }
+}
+EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
+
+u32 bcma_core_dma_translation(struct bcma_device *core)
+{
+ switch (core->bus->hosttype) {
+ case BCMA_HOSTTYPE_PCI:
+ if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
+ return BCMA_DMA_TRANSLATION_DMA64_CMT;
+ else
+ return BCMA_DMA_TRANSLATION_DMA32_CMT;
+ default:
+ pr_err("DMA translation unknown for host %d\n",
+ core->bus->hosttype);
+ }
+ return BCMA_DMA_TRANSLATION_NONE;
+}
+EXPORT_SYMBOL(bcma_core_dma_translation);
--- a/drivers/bcma/driver_chipcommon_pmu.c --- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -53,6 +53,7 @@ static void bcma_pmu_resources_init(stru @@ -53,6 +53,7 @@ static void bcma_pmu_resources_init(stru
@ -94,11 +194,52 @@
bus->chipinfo.id); bus->chipinfo.id);
--- a/drivers/bcma/driver_pci.c --- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c
@@ -161,3 +161,27 @@ void bcma_core_pci_init(struct bcma_drv_ @@ -157,7 +157,67 @@ static void bcma_pcicore_serdes_workarou
* Init.
**************************************************/
-void bcma_core_pci_init(struct bcma_drv_pci *pc)
+static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
{ {
bcma_pcicore_serdes_workaround(pc); bcma_pcicore_serdes_workaround(pc);
} }
+ +
+static bool 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;
+
+ if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+ return false;
+
+#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 bcma_core_pci_init(struct bcma_drv_pci *pc)
+{
+ if (bcma_core_pci_is_in_hostmode(pc)) {
+#ifdef CONFIG_BCMA_DRIVER_PCI_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);
+ }
+}
+
+int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
+ bool enable) + bool enable)
+{ +{
@ -217,13 +358,15 @@
break; break;
case BCMA_HOSTTYPE_NONE: case BCMA_HOSTTYPE_NONE:
case BCMA_HOSTTYPE_SDIO: case BCMA_HOSTTYPE_SDIO:
@@ -144,6 +147,13 @@ int bcma_bus_register(struct bcma_bus *b @@ -144,6 +147,15 @@ int bcma_bus_register(struct bcma_bus *b
bcma_core_pci_init(&bus->drv_pci); bcma_core_pci_init(&bus->drv_pci);
} }
+ /* Try to get SPROM */ + /* Try to get SPROM */
+ err = bcma_sprom_get(bus); + err = bcma_sprom_get(bus);
+ if (err) { + if (err == -ENOENT) {
+ pr_err("No SPROM available\n");
+ } else if (err) {
+ pr_err("Failed to get SPROM: %d\n", err); + pr_err("Failed to get SPROM: %d\n", err);
+ return -ENOENT; + return -ENOENT;
+ } + }
@ -231,7 +374,7 @@
/* Register found cores */ /* Register found cores */
bcma_register_cores(bus); bcma_register_cores(bus);
@@ -151,13 +161,11 @@ int bcma_bus_register(struct bcma_bus *b @@ -151,13 +163,11 @@ int bcma_bus_register(struct bcma_bus *b
return 0; return 0;
} }
@ -247,7 +390,7 @@
{ {
--- /dev/null --- /dev/null
+++ b/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c
@@ -0,0 +1,162 @@ @@ -0,0 +1,171 @@
+/* +/*
+ * Broadcom specific AMBA + * Broadcom specific AMBA
+ * SPROM reading + * SPROM reading
@ -270,12 +413,12 @@
+ * R/W ops. + * R/W ops.
+ **************************************************/ + **************************************************/
+ +
+static void bcma_sprom_read(struct bcma_bus *bus, u16 *sprom) +static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
+{ +{
+ int i; + int i;
+ for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++) + for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
+ sprom[i] = bcma_read16(bus->drv_cc.core, + sprom[i] = bcma_read16(bus->drv_cc.core,
+ BCMA_CC_SPROM + (i * 2)); + offset + (i * 2));
+} +}
+ +
+/************************************************** +/**************************************************
@ -362,7 +505,7 @@
+ return err; + return err;
+ +
+ revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV; + revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
+ if (revision != 8) { + if (revision != 8 && revision != 9) {
+ pr_err("Unsupported SPROM revision: %d\n", revision); + pr_err("Unsupported SPROM revision: %d\n", revision);
+ return -ENOENT; + return -ENOENT;
+ } + }
@ -387,18 +530,27 @@
+ +
+int bcma_sprom_get(struct bcma_bus *bus) +int bcma_sprom_get(struct bcma_bus *bus)
+{ +{
+ u16 offset;
+ u16 *sprom; + u16 *sprom;
+ int err = 0; + int err = 0;
+ +
+ if (!bus->drv_cc.core) + if (!bus->drv_cc.core)
+ return -EOPNOTSUPP; + return -EOPNOTSUPP;
+ +
+ if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
+ return -ENOENT;
+
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), + sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ GFP_KERNEL); + GFP_KERNEL);
+ if (!sprom) + if (!sprom)
+ return -ENOMEM; + return -ENOMEM;
+ +
+ bcma_sprom_read(bus, sprom); + /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
+ * According to brcm80211 this applies to cards with PCIe rev >= 6
+ * TODO: understand this condition and use it */
+ offset = (bus->chipinfo.id == 0x4331) ? BCMA_CC_SPROM :
+ BCMA_CC_SPROM_PCIE6;
+ bcma_sprom_read(bus, offset, sprom);
+ +
+ err = bcma_sprom_valid(sprom); + err = bcma_sprom_valid(sprom);
+ if (err) + if (err)
@ -420,7 +572,19 @@
#include "bcma_regs.h" #include "bcma_regs.h"
@@ -31,6 +32,12 @@ struct bcma_host_ops { @@ -24,6 +25,11 @@ struct bcma_chipinfo {
u8 pkg;
};
+enum bcma_clkmode {
+ BCMA_CLKMODE_FAST,
+ BCMA_CLKMODE_DYNAMIC,
+};
+
struct bcma_host_ops {
u8 (*read8)(struct bcma_device *core, u16 offset);
u16 (*read16)(struct bcma_device *core, u16 offset);
@@ -31,6 +37,12 @@ struct bcma_host_ops {
void (*write8)(struct bcma_device *core, u16 offset, u8 value); void (*write8)(struct bcma_device *core, u16 offset, u8 value);
void (*write16)(struct bcma_device *core, u16 offset, u16 value); void (*write16)(struct bcma_device *core, u16 offset, u16 value);
void (*write32)(struct bcma_device *core, u16 offset, u32 value); void (*write32)(struct bcma_device *core, u16 offset, u32 value);
@ -433,7 +597,7 @@
/* Agent ops */ /* Agent ops */
u32 (*aread32)(struct bcma_device *core, u16 offset); u32 (*aread32)(struct bcma_device *core, u16 offset);
void (*awrite32)(struct bcma_device *core, u16 offset, u32 value); void (*awrite32)(struct bcma_device *core, u16 offset, u32 value);
@@ -117,6 +124,8 @@ struct bcma_device { @@ -117,6 +129,8 @@ struct bcma_device {
struct bcma_device_id id; struct bcma_device_id id;
struct device dev; struct device dev;
@ -442,7 +606,7 @@
bool dev_registered; bool dev_registered;
u8 core_index; u8 core_index;
@@ -179,6 +188,10 @@ struct bcma_bus { @@ -179,6 +193,10 @@ struct bcma_bus {
struct bcma_drv_cc drv_cc; struct bcma_drv_cc drv_cc;
struct bcma_drv_pci drv_pci; struct bcma_drv_pci drv_pci;
@ -453,7 +617,7 @@
}; };
extern inline u32 bcma_read8(struct bcma_device *core, u16 offset) extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
@@ -208,6 +221,18 @@ void bcma_write32(struct bcma_device *co @@ -208,6 +226,18 @@ void bcma_write32(struct bcma_device *co
{ {
core->bus->ops->write32(core, offset, value); core->bus->ops->write32(core, offset, value);
} }
@ -472,21 +636,56 @@
extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset) extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
{ {
return core->bus->ops->aread32(core, offset); return core->bus->ops->aread32(core, offset);
@@ -219,6 +244,7 @@ void bcma_awrite32(struct bcma_device *c @@ -218,7 +248,24 @@ void bcma_awrite32(struct bcma_device *c
core->bus->ops->awrite32(core, offset, value);
} }
+#define bcma_mask32(cc, offset, mask) \
+ bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
+#define bcma_set32(cc, offset, set) \
+ bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
+#define bcma_maskset32(cc, offset, mask, set) \
+ bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
+
extern bool bcma_core_is_enabled(struct bcma_device *core); extern bool bcma_core_is_enabled(struct bcma_device *core);
+extern void bcma_core_disable(struct bcma_device *core, u32 flags); +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
extern int bcma_core_enable(struct bcma_device *core, u32 flags); extern int bcma_core_enable(struct bcma_device *core, u32 flags);
+extern void bcma_core_set_clockmode(struct bcma_device *core,
+ enum bcma_clkmode clkmode);
+extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status,
+ bool on);
+#define BCMA_DMA_TRANSLATION_MASK 0xC0000000
+#define BCMA_DMA_TRANSLATION_NONE 0x00000000
+#define BCMA_DMA_TRANSLATION_DMA32_CMT 0x40000000 /* Client Mode Translation for 32-bit DMA */
+#define BCMA_DMA_TRANSLATION_DMA64_CMT 0x80000000 /* Client Mode Translation for 64-bit DMA */
+extern u32 bcma_core_dma_translation(struct bcma_device *core);
#endif /* LINUX_BCMA_H_ */ #endif /* LINUX_BCMA_H_ */
--- a/include/linux/bcma/bcma_driver_chipcommon.h --- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -244,6 +244,7 @@ @@ -179,15 +179,7 @@
#define BCMA_CC_PROG_WAITCNT 0x0124
#define BCMA_CC_FLASH_CFG 0x0128
#define BCMA_CC_FLASH_WAITCNT 0x012C
-#define BCMA_CC_CLKCTLST 0x01E0 /* Clock control and status (rev >= 20) */
-#define BCMA_CC_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */
-#define BCMA_CC_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */
-#define BCMA_CC_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */
-#define BCMA_CC_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */
-#define BCMA_CC_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
-#define BCMA_CC_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
-#define BCMA_CC_CLKCTLST_HAVEHT 0x00010000 /* HT available */
-#define BCMA_CC_CLKCTLST_HAVEALP 0x00020000 /* APL available */
+/* 0x1E0 is defined as shared BCMA_CLKCTLST */
#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
#define BCMA_CC_UART0_DATA 0x0300
#define BCMA_CC_UART0_IMR 0x0304
@@ -244,6 +236,8 @@
#define BCMA_CC_REGCTL_DATA 0x065C #define BCMA_CC_REGCTL_DATA 0x065C
#define BCMA_CC_PLLCTL_ADDR 0x0660 #define BCMA_CC_PLLCTL_ADDR 0x0660
#define BCMA_CC_PLLCTL_DATA 0x0664 #define BCMA_CC_PLLCTL_DATA 0x0664
+#define BCMA_CC_SPROM 0x0830 /* SPROM beginning */ +#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
+#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
/* Data for the PMU, if available. /* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU) * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
@ -500,3 +699,92 @@
+ struct bcma_device *core, bool enable); + struct bcma_device *core, bool enable);
#endif /* LINUX_BCMA_DRIVER_PCI_H_ */ #endif /* LINUX_BCMA_DRIVER_PCI_H_ */
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -23,6 +23,9 @@ static inline u32 bcma_cc_write32_masked
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
{
+ u32 leddc_on = 10;
+ u32 leddc_off = 90;
+
if (cc->core->id.rev >= 11)
cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
@@ -38,6 +41,17 @@ void bcma_core_chipcommon_init(struct bc
bcma_pmu_init(cc);
if (cc->capabilities & BCMA_CC_CAP_PCTL)
pr_err("Power control not implemented!\n");
+
+ if (cc->core->id.rev >= 16) {
+ if (cc->core->bus->sprom.leddc_on_time &&
+ cc->core->bus->sprom.leddc_off_time) {
+ leddc_on = cc->core->bus->sprom.leddc_on_time;
+ leddc_off = cc->core->bus->sprom.leddc_off_time;
+ }
+ bcma_cc_write32(cc, BCMA_CC_GPIOTIMER,
+ ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
+ (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
+ }
}
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
--- /dev/null
+++ b/drivers/bcma/driver_pci_host.c
@@ -0,0 +1,14 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Core in hostmode
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+{
+ pr_err("No support for PCI core in hostmode yet\n");
+}
--- a/include/linux/bcma/bcma_regs.h
+++ b/include/linux/bcma/bcma_regs.h
@@ -1,13 +1,38 @@
#ifndef LINUX_BCMA_REGS_H_
#define LINUX_BCMA_REGS_H_
+/* Some single registers are shared between many cores */
+/* BCMA_CLKCTLST: ChipCommon (rev >= 20), PCIe, 80211 */
+#define BCMA_CLKCTLST 0x01E0 /* Clock control and status */
+#define BCMA_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */
+#define BCMA_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */
+#define BCMA_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */
+#define BCMA_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */
+#define BCMA_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
+#define BCMA_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
+#define BCMA_CLKCTLST_EXTRESREQ 0x00000700 /* Mask of external resource requests */
+#define BCMA_CLKCTLST_HAVEALP 0x00010000 /* ALP available */
+#define BCMA_CLKCTLST_HAVEHT 0x00020000 /* HT available */
+#define BCMA_CLKCTLST_BP_ON_ALP 0x00040000 /* RO: running on ALP clock */
+#define BCMA_CLKCTLST_BP_ON_HT 0x00080000 /* RO: running on HT clock */
+#define BCMA_CLKCTLST_EXTRESST 0x07000000 /* Mask of external resource status */
+/* Is there any BCM4328 on BCMA bus? */
+#define BCMA_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */
+#define BCMA_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */
+
/* Agent registers (common for every core) */
-#define BCMA_IOCTL 0x0408
+#define BCMA_IOCTL 0x0408 /* IO control */
#define BCMA_IOCTL_CLK 0x0001
#define BCMA_IOCTL_FGC 0x0002
#define BCMA_IOCTL_CORE_BITS 0x3FFC
#define BCMA_IOCTL_PME_EN 0x4000
#define BCMA_IOCTL_BIST_EN 0x8000
+#define BCMA_IOST 0x0500 /* IO status */
+#define BCMA_IOST_CORE_BITS 0x0FFF
+#define BCMA_IOST_DMA64 0x1000
+#define BCMA_IOST_GATED_CLK 0x2000
+#define BCMA_IOST_BIST_ERROR 0x4000
+#define BCMA_IOST_BIST_DONE 0x8000
#define BCMA_RESET_CTL 0x0800
#define BCMA_RESET_CTL_RESET 0x0001

View File

@ -17,3 +17,13 @@
config SSB_PCMCIAHOST_POSSIBLE config SSB_PCMCIAHOST_POSSIBLE
bool bool
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -17,6 +17,7 @@ config BCMA
config BCMA_BLOCKIO
bool
depends on BCMA
+ default y
config BCMA_HOST_PCI_POSSIBLE
bool