This patch series implements a multiplatform target that runs on a
variety of different Broadcom chipsets based on the BMIPS CPUs. It
evolved out of the "BMIPS updates and BCM3384 platform support"
RFC posted earlier.
V1->V2:
- Add several more DTS files so the same kernel can boot on multiple
chips: BCM6328, BCM6368, BCM7125, BCM7346, BCM7360, BCM7420, BCM7425,
and as a very special bonus, the BCM3384 Viper CPU.
- Add irq-bcm7038-l1.c to support the BCM7xxx chipsets.
- Rename target from "bcm3384" to "bmips".
- Change L1_CACHE_SHIFT fix so it works correctly when multiple BMIPS
CPU types are selected.
- Drop dependency on rejected EARLYCON_FORCE changes.
- Delete most of my new irq.c, in favor of using the refactored
irq-bcm7120-l2.c.
- Add flush for BMIPS3300/BMIPS43xx readahead caches, to avoid
non-coherency after DMA_FROM_DEVICE operations.
- Utilize the new MIPS IRQ APIs from mips-for-linux-next.
- Tweak docs/copyrights/maintainership.
This series is based on 3.18-rc4, plus:
http://patchwork.linux-mips.org/bundle/cernekee/bmips-multi-v2-deps/?state=*
http://marc.info/?l=linux-usb&m=141305106215886&w=2 (all 3/3)
These are all queued for tty-next / irqchip-next / usb-next. Notably,
the proposed serial/pxa/ttyBCM coexistence changes are not required at
this time.
A couple of sample boot logs are posted here:
https://gist.github.com/cernekee/e53a6ff05292c3a78a94
checkpatch status:
The checkpatch warnings fall into two categories:
- Undocumented DT bindings. These SoCs use mostly-standard-looking
peripherals (OHCI/EHCI controllers, ethernet PHYs), but it may be
necessary to add extra code in the future to compensate for
hardware quirks. So the compatible string in the DTS file lists
both the generic device name (documented) and a more specific
identifier for the hardware present on the chip (undocumented).
- extern declarations for the __dtb_* symbols.
Known issues:
If the lockdep checks are enabled, I see a weird IRQ state mismatch
returning from e.g. sys_execve(). CP0 STATUS shows IE disabled, but
current->hardirqs_enabled == 1. Not sure if this is a problem with
my new code or something more general. It only shows up on
SMP && !PREEMPT builds.
Booting a HIGHMEM MIPS kernel on a system with cache aliases may fail
if the system has >256MB of memory. AFAICT this is a general problem
with the fallback logic in arch/mips/mm/init.c.
Many of the BCM63xx bootloaders impose severe restrictions on the kernel
size. This tends to cause a lot of trouble booting images that include
an initramfs (because we're still missing MTD support). One workaround
is to set CONFIG_PHYSICAL_START to a higher value, like 0x8100_0000.
Future work:
Many BCM7xxx boards can be freely switched between big endian and little
endian modes, with the latter being the default. It would be nice if we
could use identical DTS files for both configurations, since the LE/BE
setting mostly doesn't affect how the peripherals work. But currently a
few assumptions are hardcoded in there ("big-endian" USB register
properties and a hack to get the 16550 register addresses correct). I
submitted a patch to the DT/serial lists which adds a "native-endian"
property; if this is accepted and utilized by the drivers in question, it
will go a long way toward solving this problem.
Lots of peripherals are still missing, especially flash and bcm63xx_enet.
The lack of a reboot handler is annoying; syscon-reboot probably won't work
on STB (because it requires two writes). Some peripherals, like USB on
certain boards, need more work (possibly PHY drivers) and were left
disabled.
There are ways to retrieve other information from the legacy non-DT
bootloaders, but they're pretty hacky. The flash configuration is among
the worst of the bunch, because these chips can have up to 4 different
flash controllers, more than one can be active at a time, and the
bootloader just passes "hints" rather than explicit partition maps. For
specific boards it is sometimes OK to hardcode the map into the DTS file,
although most of the supported boards are user-reconfigurable and the
flash layouts may change from one bootloader version to the next.
There is currently no way to distinguish between different bcm63xx
board types (i.e. we can only identify the SoC, not the board). There
is a way to distinguish different bcm7xxx board types, although in
practice the data source is somewhat unreliable and doesn't always convey
all of the information needed to distinguish boards with different
capabilities.
The kernel makes a few assumptions about how the bootloader has set up
Broadcom-specific registers for e.g. USB. If/when power management
features are added, these registers will revert to their default settings
on resume, and somehow need to be set up again by Linux.
irq-bcm7120-l2.c is getting a little bloated and I'm not entirely happy
with the latest round of changes. In particular it would be really nice
if the probe function could use the devm_ APIs and not have to worry
about so many error paths. And I'm not sure if the generic-chip helpers
are making the code any simpler.
Dmitry Torokhov (2):
irqchip: brcmstb-l2: fix error handling of irq_of_parse_and_map
irqchip: bcm7120-l2: fix error handling of irq_of_parse_and_map
Jon Fraser (2):
MIPS: BMIPS: Allow BMIPS3300 to utilize SMP ebase relocation code
MIPS: BMIPS: Mask off timer IRQs when hot-unplugging a CPU
Kevin Cernekee (18):
irqchip: Update docs regarding irq_domain_add_tree()
irqchip: bcm7120-l2: Refactor driver for arbitrary IRQEN/IRQSTAT
offsets
irqchip: bcm7120-l2: Change DT binding to allow non-contiguous
IRQEN/IRQSTAT
irqchip: Add new driver for BCM7038-style level 1 interrupt
controllers
MIPS: BMIPS: Fix ".previous without corresponding .section" warnings
MIPS: BMIPS: Align secondary boot sequence with latest firmware
releases
MIPS: BMIPS: Introduce helper function to change the reset vector
MIPS: BMIPS: Explicitly configure reset vectors prior to secondary
boot
MIPS: Allow MIPS_CPU_SCACHE to be used with different line sizes
MIPS: BMIPS: Fix L1_CACHE_SHIFT when BMIPS5000 is selected
MIPS: BMIPS: Let each platform customize the CPU1 IRQ mask
MIPS: BMIPS: Add special cache handling in c-r4k.c
MIPS: BMIPS: Add PRId for BMIPS5200 (Whirlwind)
MIPS: Create a helper function for DT setup
Documentation: DT: Add "mti" vendor prefix
MAINTAINERS: Add entry for bcm63xx/bcm33xx UDC gadget driver
MAINTAINERS: Add entry for BMIPS multiplatform kernel
MIPS: Add multiplatform BMIPS target
Documentation/IRQ-domain.txt | 3 +-
.../interrupt-controller/brcm,bcm7038-l1-intc.txt | 52 ++++
.../interrupt-controller/brcm,bcm7120-l2-intc.txt | 5 +-
.../devicetree/bindings/mips/brcm/bmips.txt | 8 +
.../devicetree/bindings/mips/brcm/soc.txt | 21 ++
.../devicetree/bindings/vendor-prefixes.txt | 1 +
MAINTAINERS | 18 ++
arch/mips/Kbuild.platforms | 1 +
arch/mips/Kconfig | 40 ++-
arch/mips/bmips/Makefile | 1 +
arch/mips/bmips/Platform | 7 +
arch/mips/bmips/dma.c | 109 +++++++
arch/mips/bmips/irq.c | 38 +++
arch/mips/bmips/setup.c | 249 +++++++++++++++
arch/mips/boot/dts/Makefile | 9 +
arch/mips/boot/dts/bcm3384_common.dtsi | 44 +++
arch/mips/boot/dts/bcm3384_viper.dtsi | 63 ++++
arch/mips/boot/dts/bcm3384_zephyr.dtsi | 82 +++++
arch/mips/boot/dts/bcm6328.dtsi | 63 ++++
arch/mips/boot/dts/bcm6368.dtsi | 89 ++++++
arch/mips/boot/dts/bcm7125.dtsi | 99 ++++++
arch/mips/boot/dts/bcm7346.dtsi | 174 +++++++++++
arch/mips/boot/dts/bcm7360.dtsi | 121 ++++++++
arch/mips/boot/dts/bcm7420.dtsi | 142 +++++++++
arch/mips/boot/dts/bcm7425.dtsi | 174 +++++++++++
arch/mips/boot/dts/bcm93384wvg.dts | 25 ++
arch/mips/boot/dts/bcm93384wvg_viper.dts | 25 ++
arch/mips/boot/dts/bcm96368mvwg.dts | 31 ++
arch/mips/boot/dts/bcm97125cbmb.dts | 31 ++
arch/mips/boot/dts/bcm97346dbsmb.dts | 58 ++++
arch/mips/boot/dts/bcm97360svmb.dts | 34 +++
arch/mips/boot/dts/bcm97420c.dts | 44 +++
arch/mips/boot/dts/bcm97425svmb.dts | 59 ++++
arch/mips/boot/dts/bcm9ejtagprb.dts | 22 ++
arch/mips/configs/bmips_be_defconfig | 83 +++++
arch/mips/configs/bmips_stb_defconfig | 83 +++++
arch/mips/include/asm/bmips.h | 1 +
arch/mips/include/asm/cpu.h | 1 +
arch/mips/include/asm/mach-bmips/dma-coherence.h | 45 +++
arch/mips/include/asm/mach-bmips/spaces.h | 17 ++
arch/mips/include/asm/mach-bmips/war.h | 24 ++
arch/mips/include/asm/prom.h | 1 +
arch/mips/kernel/bmips_vec.S | 3 -
arch/mips/kernel/cpu-probe.c | 1 +
arch/mips/kernel/prom.c | 18 ++
arch/mips/kernel/smp-bmips.c | 114 ++++---
arch/mips/lantiq/prom.c | 11 +-
arch/mips/mm/c-r4k.c | 43 +++
arch/mips/ralink/of.c | 14 +-
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-bcm7038-l1.c | 335 +++++++++++++++++++++
drivers/irqchip/irq-bcm7120-l2.c | 105 +++++--
drivers/irqchip/irq-brcmstb-l2.c | 4 +-
54 files changed, 2755 insertions(+), 96 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt
create mode 100644 Documentation/devicetree/bindings/mips/brcm/bmips.txt
create mode 100644 Documentation/devicetree/bindings/mips/brcm/soc.txt
create mode 100644 arch/mips/bmips/Makefile
create mode 100644 arch/mips/bmips/Platform
create mode 100644 arch/mips/bmips/dma.c
create mode 100644 arch/mips/bmips/irq.c
create mode 100644 arch/mips/bmips/setup.c
create mode 100644 arch/mips/boot/dts/bcm3384_common.dtsi
create mode 100644 arch/mips/boot/dts/bcm3384_viper.dtsi
create mode 100644 arch/mips/boot/dts/bcm3384_zephyr.dtsi
create mode 100644 arch/mips/boot/dts/bcm6328.dtsi
create mode 100644 arch/mips/boot/dts/bcm6368.dtsi
create mode 100644 arch/mips/boot/dts/bcm7125.dtsi
create mode 100644 arch/mips/boot/dts/bcm7346.dtsi
create mode 100644 arch/mips/boot/dts/bcm7360.dtsi
create mode 100644 arch/mips/boot/dts/bcm7420.dtsi
create mode 100644 arch/mips/boot/dts/bcm7425.dtsi
create mode 100644 arch/mips/boot/dts/bcm93384wvg.dts
create mode 100644 arch/mips/boot/dts/bcm93384wvg_viper.dts
create mode 100644 arch/mips/boot/dts/bcm96368mvwg.dts
create mode 100644 arch/mips/boot/dts/bcm97125cbmb.dts
create mode 100644 arch/mips/boot/dts/bcm97346dbsmb.dts
create mode 100644 arch/mips/boot/dts/bcm97360svmb.dts
create mode 100644 arch/mips/boot/dts/bcm97420c.dts
create mode 100644 arch/mips/boot/dts/bcm97425svmb.dts
create mode 100644 arch/mips/boot/dts/bcm9ejtagprb.dts
create mode 100644 arch/mips/configs/bmips_be_defconfig
create mode 100644 arch/mips/configs/bmips_stb_defconfig
create mode 100644 arch/mips/include/asm/mach-bmips/dma-coherence.h
create mode 100644 arch/mips/include/asm/mach-bmips/spaces.h
create mode 100644 arch/mips/include/asm/mach-bmips/war.h
create mode 100644 drivers/irqchip/irq-bcm7038-l1.c
--
2.1.1
Several drivers now use this API, including the ARM GIC driver, so remove
the outdated comment.
Signed-off-by: Kevin Cernekee <[email protected]>
---
Documentation/IRQ-domain.txt | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt
index 8a8b82c..0ccd7b7 100644
--- a/Documentation/IRQ-domain.txt
+++ b/Documentation/IRQ-domain.txt
@@ -95,8 +95,7 @@ since it doesn't need to allocate a table as large as the largest
hwirq number. The disadvantage is that hwirq to IRQ number lookup is
dependent on how many entries are in the table.
-Very few drivers should need this mapping. At the moment, powerpc
-iseries is the only user.
+Very few drivers should need this mapping.
==== No Map ===-
irq_domain_add_nomap()
--
2.1.1
Currently the driver assumes that REG_BASE+0x00 is the IRQ enable mask,
and REG_BASE+0x04 is the IRQ status mask. This is true on BCM3384 and
BCM7xxx, but it is not true for some of the controllers found on BCM63xx
chips. So we will change a couple of key assumptions:
- Don't assume that both the IRQEN and IRQSTAT registers will be
covered by a single ioremap() operation.
- Don't assume any particular ordering (IRQSTAT might show up before
IRQEN on some chips).
- For an L2 controller with >=64 IRQs, don't assume that every
IRQEN/IRQSTAT pair will use the same register spacing.
This patch changes the "plumbing" but doesn't yet provide a way for users
to instantiate a controller with arbitrary IRQEN/IRQSTAT offsets.
Signed-off-by: Kevin Cernekee <[email protected]>
---
drivers/irqchip/irq-bcm7120-l2.c | 41 +++++++++++++++++++++++++++-------------
1 file changed, 28 insertions(+), 13 deletions(-)
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
index 8eec8e1..e8441ee 100644
--- a/drivers/irqchip/irq-bcm7120-l2.c
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -34,11 +34,15 @@
#define IRQSTAT 0x04
#define MAX_WORDS 4
+#define MAX_MAPPINGS MAX_WORDS
#define IRQS_PER_WORD 32
struct bcm7120_l2_intc_data {
unsigned int n_words;
- void __iomem *base[MAX_WORDS];
+ void __iomem *map_base[MAX_MAPPINGS];
+ void __iomem *pair_base[MAX_WORDS];
+ int en_offset[MAX_WORDS];
+ int stat_offset[MAX_WORDS];
struct irq_domain *domain;
bool can_wake;
u32 irq_fwd_mask[MAX_WORDS];
@@ -61,7 +65,8 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
int hwirq;
irq_gc_lock(gc);
- pending = irq_reg_readl(gc, IRQSTAT) & gc->mask_cache;
+ pending = irq_reg_readl(gc, b->stat_offset[idx]) &
+ gc->mask_cache;
irq_gc_unlock(gc);
for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
@@ -76,21 +81,24 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
static void bcm7120_l2_intc_suspend(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
struct bcm7120_l2_intc_data *b = gc->private;
irq_gc_lock(gc);
if (b->can_wake)
- irq_reg_writel(gc, gc->mask_cache | gc->wake_active, IRQEN);
+ irq_reg_writel(gc, gc->mask_cache | gc->wake_active,
+ ct->regs.mask);
irq_gc_unlock(gc);
}
static void bcm7120_l2_intc_resume(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
/* Restore the saved mask */
irq_gc_lock(gc);
- irq_reg_writel(gc, gc->mask_cache, IRQEN);
+ irq_reg_writel(gc, gc->mask_cache, ct->regs.mask);
irq_gc_unlock(gc);
}
@@ -137,9 +145,14 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
return -ENOMEM;
for (idx = 0; idx < MAX_WORDS; idx++) {
- data->base[idx] = of_iomap(dn, idx);
- if (!data->base[idx])
+ data->map_base[idx] = of_iomap(dn, idx);
+ if (!data->map_base[idx])
break;
+
+ data->pair_base[idx] = data->map_base[idx];
+ data->en_offset[idx] = IRQEN;
+ data->stat_offset[idx] = IRQSTAT;
+
data->n_words = idx + 1;
}
if (!data->n_words) {
@@ -157,7 +170,8 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
if (ret == 0 || ret == -EINVAL) {
for (idx = 0; idx < data->n_words; idx++)
__raw_writel(data->irq_fwd_mask[idx],
- data->base[idx] + IRQEN);
+ data->pair_base[idx] +
+ data->en_offset[idx]);
} else {
/* property exists but has the wrong number of words */
pr_err("invalid int-fwd-mask property\n");
@@ -215,11 +229,12 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
gc = irq_get_domain_generic_chip(data->domain, irq);
gc->unused = 0xffffffff & ~data->irq_map_mask[idx];
- gc->reg_base = data->base[idx];
gc->private = data;
ct = gc->chip_types;
- ct->regs.mask = IRQEN;
+ gc->reg_base = data->pair_base[idx];
+ ct->regs.mask = data->en_offset[idx];
+
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->chip.irq_ack = irq_gc_noop;
@@ -237,16 +252,16 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
}
pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n",
- data->base[0], num_parent_irqs);
+ data->map_base[0], num_parent_irqs);
return 0;
out_free_domain:
irq_domain_remove(data->domain);
out_unmap:
- for (idx = 0; idx < MAX_WORDS; idx++) {
- if (data->base[idx])
- iounmap(data->base[idx]);
+ for (idx = 0; idx < MAX_MAPPINGS; idx++) {
+ if (data->map_base[idx])
+ iounmap(data->map_base[idx]);
}
kfree(data);
return ret;
--
2.1.1
The secondary CPU's reset vector needs to be set to KSEG1 for a cold
boot (release from reset), or KSEG0 for a warm restart. On a cold boot
KSEG0 may be unavailable (BMIPS4380), and on a warm restart KSEG1 may
be unavailable (XKS01 mode on 4380 or 5000).
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/kernel/smp-bmips.c | 29 ++++++++---------------------
1 file changed, 8 insertions(+), 21 deletions(-)
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index f7b1bee..162391d 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -47,6 +47,8 @@ cpumask_t bmips_booted_mask;
#define RESET_FROM_KSEG0 0x80080800
#define RESET_FROM_KSEG1 0xa0080800
+static void bmips_set_reset_vec(int cpu, u32 val);
+
#ifdef CONFIG_SMP
/* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */
@@ -198,6 +200,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
pr_info("SMP: Booting CPU%d...\n", cpu);
if (cpumask_test_cpu(cpu, &bmips_booted_mask)) {
+ /* kseg1 might not exist if this CPU enabled XKS01 */
+ bmips_set_reset_vec(cpu, RESET_FROM_KSEG0);
+
switch (current_cpu_type()) {
case CPU_BMIPS4350:
case CPU_BMIPS4380:
@@ -207,8 +212,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
bmips5000_send_ipi_single(cpu, 0);
break;
}
- }
- else {
+ } else {
+ bmips_set_reset_vec(cpu, RESET_FROM_KSEG1);
+
switch (current_cpu_type()) {
case CPU_BMIPS4350:
case CPU_BMIPS4380:
@@ -229,31 +235,12 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
*/
static void bmips_init_secondary(void)
{
- /* move NMI vector to kseg0, in case XKS01 is enabled */
-
- void __iomem *cbr;
- unsigned long old_vec;
- unsigned long relo_vector;
- int boot_cpu;
-
switch (current_cpu_type()) {
case CPU_BMIPS4350:
case CPU_BMIPS4380:
- cbr = BMIPS_GET_CBR();
-
- boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
- relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 :
- BMIPS_RELO_VECTOR_CONTROL_1;
-
- old_vec = __raw_readl(cbr + relo_vector);
- __raw_writel(old_vec & ~0x20000000, cbr + relo_vector);
-
clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0);
break;
case CPU_BMIPS5000:
- write_c0_brcm_bootvec(read_c0_brcm_bootvec() &
- (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000));
-
write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0));
break;
}
--
2.1.1
We have a bunch of platforms using "mti,cpu-interrupt-controller" but
the "mti" prefix isn't documented. Fix this.
Signed-off-by: Kevin Cernekee <[email protected]>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 723999d..b2114de 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -96,6 +96,7 @@ mitsubishi Mitsubishi Electric Corporation
mosaixtech Mosaix Technologies, Inc.
moxa Moxa
mpl MPL AG
+mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.)
mundoreader Mundo Reader S.L.
murata Murata Manufacturing Co., Ltd.
mxicy Macronix International Co., Ltd.
--
2.1.1
This is a dual core (quad thread) BMIPS5000. It needs a little extra
code to boot the second core (CPU2/CPU3), but for now we can treat it the
same as a single core BMIPS5000.
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/include/asm/cpu.h | 1 +
arch/mips/kernel/cpu-probe.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index dfdc77e..de9ca43 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -142,6 +142,7 @@
#define PRID_IMP_BMIPS3300_BUG 0x0000
#define PRID_IMP_BMIPS43XX 0xa000
#define PRID_IMP_BMIPS5000 0x5a00
+#define PRID_IMP_BMIPS5200 0x5b00
#define PRID_REV_BMIPS4380_LO 0x0040
#define PRID_REV_BMIPS4380_HI 0x006f
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 94c4a0c..5477d91 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -1024,6 +1024,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
break;
}
case PRID_IMP_BMIPS5000:
+ case PRID_IMP_BMIPS5200:
c->cputype = CPU_BMIPS5000;
__cpu_name[cpu] = "Broadcom BMIPS5000";
set_elf_platform(cpu, "bmips5000");
--
2.1.1
bmips_be_defconfig supports Linux running on the following CM and DSL
SoCs:
- BCM3384 (BMIPS5000) cable modem application processor, BE, SMP
- BCM3384 (BMIPS4355) cable modem "spare CPU"*, BE
- BCM6328 (BMIPS4355) ADSL chip, BE
- BCM6368 (BMIPS4350) ADSL chip, BE, SMP
*experimental; most configurations will require changing CONFIG_PHYSICAL_START
bmips_stb_defconfig supports Linux running on the (nominally LE) STB
chipsets:
- BCM7125 (BMIPS4380) set-top box chip, LE, SMP
- BCM7346 (BMIPS5000) set-top box chip, LE, SMP
- BCM7360 (BMIPS3300) set-top box chip, LE
- BCM7420 (BMIPS5000) set-top box chip, LE, SMP
- BCM7425 (BMIPS5000) set-top box chip, LE, SMP
serial8250 and bcm63xx_uart do not currently coexist. If/when this is
fixed, it will be also possible to boot the BE image on any supported STB
board configured for BE. For now, each defconfig can only pick one UART
driver, and the BE defconfig enables bcm63xx_uart.
On these MIPS systems, endianness cannot be reconfigured at runtime. On
STB it is sometimes offered as a board jumper or 0-ohm resistor, and
sometimes hardwired to LE only. The CM and DSL systems always run BE.
Device Tree is used to configure the following items:
- UART, USB, GENET peripherals
- IRQ controllers
- Early console base address (bcm63xx_uart only)
- SMP or UP mode
- MIPS counter frequency
- Memory size / regions
- DMA remappings
- Kernel command line
The DT-enabled bootloader and build instructions for 3384 are posted at
https://github.com/Broadcom/aeolus . The other chips use legacy non-DT
bootloaders, and so the kernel employs autodetection heuristics to select
a builtin DTB.
Signed-off-by: Kevin Cernekee <[email protected]>
---
.../devicetree/bindings/mips/brcm/bmips.txt | 8 +
.../devicetree/bindings/mips/brcm/soc.txt | 21 ++
arch/mips/Kbuild.platforms | 1 +
arch/mips/Kconfig | 37 +++
arch/mips/bmips/Makefile | 1 +
arch/mips/bmips/Platform | 7 +
arch/mips/bmips/dma.c | 109 +++++++++
arch/mips/bmips/irq.c | 38 ++++
arch/mips/bmips/setup.c | 249 +++++++++++++++++++++
arch/mips/boot/dts/Makefile | 9 +
arch/mips/boot/dts/bcm3384_common.dtsi | 44 ++++
arch/mips/boot/dts/bcm3384_viper.dtsi | 63 ++++++
arch/mips/boot/dts/bcm3384_zephyr.dtsi | 82 +++++++
arch/mips/boot/dts/bcm6328.dtsi | 63 ++++++
arch/mips/boot/dts/bcm6368.dtsi | 89 ++++++++
arch/mips/boot/dts/bcm7125.dtsi | 99 ++++++++
arch/mips/boot/dts/bcm7346.dtsi | 174 ++++++++++++++
arch/mips/boot/dts/bcm7360.dtsi | 121 ++++++++++
arch/mips/boot/dts/bcm7420.dtsi | 142 ++++++++++++
arch/mips/boot/dts/bcm7425.dtsi | 174 ++++++++++++++
arch/mips/boot/dts/bcm93384wvg.dts | 25 +++
arch/mips/boot/dts/bcm93384wvg_viper.dts | 25 +++
arch/mips/boot/dts/bcm96368mvwg.dts | 31 +++
arch/mips/boot/dts/bcm97125cbmb.dts | 31 +++
arch/mips/boot/dts/bcm97346dbsmb.dts | 58 +++++
arch/mips/boot/dts/bcm97360svmb.dts | 34 +++
arch/mips/boot/dts/bcm97420c.dts | 44 ++++
arch/mips/boot/dts/bcm97425svmb.dts | 59 +++++
arch/mips/boot/dts/bcm9ejtagprb.dts | 22 ++
arch/mips/configs/bmips_be_defconfig | 83 +++++++
arch/mips/configs/bmips_stb_defconfig | 83 +++++++
arch/mips/include/asm/mach-bmips/dma-coherence.h | 45 ++++
arch/mips/include/asm/mach-bmips/spaces.h | 17 ++
arch/mips/include/asm/mach-bmips/war.h | 24 ++
34 files changed, 2112 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mips/brcm/bmips.txt
create mode 100644 Documentation/devicetree/bindings/mips/brcm/soc.txt
create mode 100644 arch/mips/bmips/Makefile
create mode 100644 arch/mips/bmips/Platform
create mode 100644 arch/mips/bmips/dma.c
create mode 100644 arch/mips/bmips/irq.c
create mode 100644 arch/mips/bmips/setup.c
create mode 100644 arch/mips/boot/dts/bcm3384_common.dtsi
create mode 100644 arch/mips/boot/dts/bcm3384_viper.dtsi
create mode 100644 arch/mips/boot/dts/bcm3384_zephyr.dtsi
create mode 100644 arch/mips/boot/dts/bcm6328.dtsi
create mode 100644 arch/mips/boot/dts/bcm6368.dtsi
create mode 100644 arch/mips/boot/dts/bcm7125.dtsi
create mode 100644 arch/mips/boot/dts/bcm7346.dtsi
create mode 100644 arch/mips/boot/dts/bcm7360.dtsi
create mode 100644 arch/mips/boot/dts/bcm7420.dtsi
create mode 100644 arch/mips/boot/dts/bcm7425.dtsi
create mode 100644 arch/mips/boot/dts/bcm93384wvg.dts
create mode 100644 arch/mips/boot/dts/bcm93384wvg_viper.dts
create mode 100644 arch/mips/boot/dts/bcm96368mvwg.dts
create mode 100644 arch/mips/boot/dts/bcm97125cbmb.dts
create mode 100644 arch/mips/boot/dts/bcm97346dbsmb.dts
create mode 100644 arch/mips/boot/dts/bcm97360svmb.dts
create mode 100644 arch/mips/boot/dts/bcm97420c.dts
create mode 100644 arch/mips/boot/dts/bcm97425svmb.dts
create mode 100644 arch/mips/boot/dts/bcm9ejtagprb.dts
create mode 100644 arch/mips/configs/bmips_be_defconfig
create mode 100644 arch/mips/configs/bmips_stb_defconfig
create mode 100644 arch/mips/include/asm/mach-bmips/dma-coherence.h
create mode 100644 arch/mips/include/asm/mach-bmips/spaces.h
create mode 100644 arch/mips/include/asm/mach-bmips/war.h
diff --git a/Documentation/devicetree/bindings/mips/brcm/bmips.txt b/Documentation/devicetree/bindings/mips/brcm/bmips.txt
new file mode 100644
index 0000000..4a8cd8f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/brcm/bmips.txt
@@ -0,0 +1,8 @@
+* Broadcom MIPS (BMIPS) CPUs
+
+Required properties:
+- compatible: "brcm,bmips3300", "brcm,bmips4350", "brcm,bmips4380"
+ "brcm,bmips5000"
+
+- mips-hpt-frequency: This is common to all CPUs in the system so it lives
+ under the "cpus" node.
diff --git a/Documentation/devicetree/bindings/mips/brcm/soc.txt b/Documentation/devicetree/bindings/mips/brcm/soc.txt
new file mode 100644
index 0000000..1eedcb8
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/brcm/soc.txt
@@ -0,0 +1,21 @@
+* Broadcom cable/DSL/settop platforms
+
+SoCs:
+
+Required properties:
+- compatible: "brcm,bcm3384", "brcm,bcm33843"
+ "brcm,bcm3384-viper", "brcm,bcm33843-viper"
+ "brcm,bcm6328", "brcm,bcm6368",
+ "brcm,bcm7125", "brcm,bcm7346", "brcm,bcm7360",
+ "brcm,bcm7420", "brcm,bcm7425"
+
+Boards:
+
+Required properties:
+- compatible: "brcm,bcm93384wvg", "brcm,bcm93384wvg-viper"
+ "brcm,bcm9ejtagprb", "brcm,bcm96368mvwg",
+ "brcm,bcm97125cbmb", "brcm,bcm97346dbsmb", "brcm,bcm97360svmb",
+ "brcm,bcm97420c", "brcm,bcm97425svmb"
+
+The experimental -viper variants are for running Linux on the 3384's
+BMIPS4355 cable modem CPU instead of the BMIPS5000 application processor.
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index f5e18bf..e61b77a 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -5,6 +5,7 @@ platforms += ar7
platforms += ath79
platforms += bcm47xx
platforms += bcm63xx
+platforms += bmips
platforms += cavium-octeon
platforms += cobalt
platforms += dec
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index c0130ec..6c8fd86 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -115,6 +115,43 @@ config ATH79
help
Support for the Atheros AR71XX/AR724X/AR913X SoCs.
+config BMIPS_MULTIPLATFORM
+ bool "Broadcom BCM33xx/BCM63xx/BCM7xxx multiplatform kernel"
+ select BOOT_RAW
+ select NO_EXCEPT_FILL
+ select USE_OF
+ select BUILTIN_DTB
+ select FW_CFE
+ select CEVT_R4K
+ select CSRC_R4K
+ select SYNC_R4K
+ select COMMON_CLK
+ select BCM7038_L1_IRQ
+ select BCM7120_L2_IRQ
+ select BRCMSTB_L2_IRQ
+ select IRQ_CPU
+ select RAW_IRQ_ACCESSORS
+ select DMA_NONCOHERENT
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_HIGHMEM
+ select SYS_HAS_CPU_BMIPS3300
+ select SYS_HAS_CPU_BMIPS4350
+ select SYS_HAS_CPU_BMIPS4380
+ select SYS_HAS_CPU_BMIPS5000
+ select SWAP_IO_SPACE
+ select USB_EHCI_BIG_ENDIAN_DESC
+ select USB_EHCI_BIG_ENDIAN_MMIO
+ select USB_OHCI_BIG_ENDIAN_DESC
+ select USB_OHCI_BIG_ENDIAN_MMIO
+ help
+ Build a multiplatform DT-based kernel image that boots on select
+ BCM33xx cable modem chips, BCM63xx DSL chips, and BCM7xxx set-top
+ box chips. Note that CONFIG_CPU_BIG_ENDIAN/CONFIG_CPU_LITTLE_ENDIAN
+ must be set appropriately for your board, and the dts/dtsi files may
+ require changes based on the system endianness.
+
config BCM47XX
bool "Broadcom BCM47XX based boards"
select ARCH_WANT_OPTIONAL_GPIOLIB
diff --git a/arch/mips/bmips/Makefile b/arch/mips/bmips/Makefile
new file mode 100644
index 0000000..a393955
--- /dev/null
+++ b/arch/mips/bmips/Makefile
@@ -0,0 +1 @@
+obj-y += setup.o irq.o dma.o
diff --git a/arch/mips/bmips/Platform b/arch/mips/bmips/Platform
new file mode 100644
index 0000000..bb27162
--- /dev/null
+++ b/arch/mips/bmips/Platform
@@ -0,0 +1,7 @@
+#
+# Broadcom BMIPS multiplatform kernel
+#
+platform-$(CONFIG_BMIPS_MULTIPLATFORM) += bmips/
+cflags-$(CONFIG_BMIPS_MULTIPLATFORM) += \
+ -I$(srctree)/arch/mips/include/asm/mach-bmips/
+load-$(CONFIG_BMIPS_MULTIPLATFORM) := 0xffffffff80010000
diff --git a/arch/mips/bmips/dma.c b/arch/mips/bmips/dma.c
new file mode 100644
index 0000000..85474ee0
--- /dev/null
+++ b/arch/mips/bmips/dma.c
@@ -0,0 +1,109 @@
+/*
+ * 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
+ * for more details.
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ * Author: Kevin Cernekee <[email protected]>
+ */
+
+#include <linux/device.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <asm/bmips.h>
+#include <asm/cpu-type.h>
+#include <dma-coherence.h>
+
+/*
+ * BCM338x has configurable address translation windows which allow the
+ * peripherals' DMA addresses to be different from the Zephyr-visible
+ * physical addresses. e.g. usb_dma_addr = zephyr_pa ^ 0x08000000
+ *
+ * If our DT "memory" node has a "dma-xor-mask" property we will enable this
+ * translation using the provided offset.
+ */
+static u32 bcm338x_dma_xor_mask;
+static u32 bcm338x_dma_xor_limit = 0xffffffff;
+
+/*
+ * PCI collapses the memory hole at 0x10000000 - 0x1fffffff on all
+ * supported BMIPS based systems.
+ *
+ * On systems with a dma-xor-mask, this range is guaranteed to live above
+ * the dma-xor-limit.
+ */
+#define BMIPS_MEM_HOLE_PA 0x10000000
+#define BMIPS_MEM_HOLE_SIZE 0x10000000
+
+#define FLUSH_RAC 0x100
+
+static dma_addr_t bmips_phys_to_dma(struct device *dev, phys_addr_t pa)
+{
+ if (dev && dev_is_pci(dev) &&
+ pa >= (BMIPS_MEM_HOLE_PA + BMIPS_MEM_HOLE_SIZE))
+ return pa - BMIPS_MEM_HOLE_SIZE;
+ if (pa <= bcm338x_dma_xor_limit)
+ return pa ^ bcm338x_dma_xor_mask;
+ return pa;
+}
+
+dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
+{
+ return bmips_phys_to_dma(dev, virt_to_phys(addr));
+}
+
+dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
+{
+ return bmips_phys_to_dma(dev, page_to_phys(page));
+}
+
+unsigned long plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr)
+{
+ if (dev && dev_is_pci(dev) &&
+ dma_addr >= BMIPS_MEM_HOLE_PA)
+ return dma_addr + BMIPS_MEM_HOLE_SIZE;
+ if ((dma_addr ^ bcm338x_dma_xor_mask) <= bcm338x_dma_xor_limit)
+ return dma_addr ^ bcm338x_dma_xor_mask;
+ return dma_addr;
+}
+
+static int __init bcm338x_init_dma_xor(void)
+{
+ struct device_node *np = of_find_node_by_type(NULL, "memory");
+
+ if (!np)
+ return 0;
+
+ of_property_read_u32(np, "dma-xor-mask", &bcm338x_dma_xor_mask);
+ of_property_read_u32(np, "dma-xor-limit", &bcm338x_dma_xor_limit);
+
+ of_node_put(np);
+ return 0;
+}
+arch_initcall(bcm338x_init_dma_xor);
+
+void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction dir)
+{
+ if (dir == DMA_TO_DEVICE)
+ return;
+
+ switch (current_cpu_type()) {
+ case CPU_BMIPS3300:
+ case CPU_BMIPS4350:
+ case CPU_BMIPS4380: {
+ void __iomem *cbr = BMIPS_GET_CBR();
+
+ /* Flush stale data out of the readahead cache */
+ __raw_writel(FLUSH_RAC, cbr + BMIPS_RAC_CONFIG);
+ __raw_readl(cbr + BMIPS_RAC_CONFIG);
+ break;
+ }
+ }
+}
diff --git a/arch/mips/bmips/irq.c b/arch/mips/bmips/irq.c
new file mode 100644
index 0000000..14552e5
--- /dev/null
+++ b/arch/mips/bmips/irq.c
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ * Author: Kevin Cernekee <[email protected]>
+ */
+
+#include <linux/of.h>
+#include <linux/irqchip.h>
+
+#include <asm/bmips.h>
+#include <asm/irq.h>
+#include <asm/irq_cpu.h>
+#include <asm/time.h>
+
+unsigned int get_c0_compare_int(void)
+{
+ return CP0_LEGACY_COMPARE_IRQ;
+}
+
+void __init arch_init_irq(void)
+{
+ struct device_node *dn;
+
+ /* Only the STB (bcm7038) controller supports SMP IRQ affinity */
+ dn = of_find_compatible_node(NULL, NULL, "brcm,bcm7038-l1-intc");
+ if (dn)
+ of_node_put(dn);
+ else
+ bmips_tp1_irqs = 0;
+
+ irqchip_init();
+}
+
+OF_DECLARE_2(irqchip, mips_cpu_intc, "mti,cpu-interrupt-controller",
+ mips_cpu_irq_of_init);
diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c
new file mode 100644
index 0000000..c34601d
--- /dev/null
+++ b/arch/mips/bmips/setup.c
@@ -0,0 +1,249 @@
+/*
+ * 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
+ * for more details.
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ * Author: Kevin Cernekee <[email protected]>
+ */
+
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/bootmem.h>
+#include <linux/clk-provider.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/smp.h>
+#include <asm/addrspace.h>
+#include <asm/bmips.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu-type.h>
+#include <asm/mipsregs.h>
+#include <asm/prom.h>
+#include <asm/smp-ops.h>
+#include <asm/time.h>
+#include <asm/traps.h>
+#include <asm/fw/cfe/cfe_api.h>
+
+#define CMT_LOCAL_TPID BIT(31)
+#define RELO_NORMAL_VEC BIT(18)
+
+#define REG_DSL_CHIP_ID ((void __iomem *)CKSEG1ADDR(0x10000000))
+#define REG_STB_CHIP_ID ((void __iomem *)CKSEG1ADDR(0x10404000))
+
+#define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c))
+#define BCM6328_TP1_DISABLED BIT(9)
+
+static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000;
+
+struct bmips_board_list {
+ void *dtb;
+ u32 chip_id;
+ const char *boardname;
+ void (*quirk_fn)(void);
+};
+
+extern char __dtb_bcm9ejtagprb_begin;
+extern char __dtb_bcm96368mvwg_begin;
+extern char __dtb_bcm97125cbmb_begin;
+extern char __dtb_bcm97346dbsmb_begin;
+extern char __dtb_bcm97360svmb_begin;
+extern char __dtb_bcm97420c_begin;
+extern char __dtb_bcm97425svmb_begin;
+
+static void kbase_setup(void)
+{
+ __raw_writel(kbase | RELO_NORMAL_VEC,
+ BMIPS_GET_CBR() + BMIPS_RELO_VECTOR_CONTROL_1);
+ ebase = kbase;
+}
+
+static void bcm3384_quirks(void)
+{
+ /*
+ * Some experimental CM boxes are set up to let CM own the Viper TP0
+ * and let Linux own TP1. This requires moving the kernel
+ * load address to a non-conflicting region (e.g. via
+ * CONFIG_PHYSICAL_START) and supplying an alternate DTB.
+ * If we detect this condition, we need to move the MIPS exception
+ * vectors up to an area that we own.
+ *
+ * This is distinct from the OTHER special case mentioned in
+ * smp-bmips.c (boot on TP1, but enable SMP, then TP0 becomes our
+ * logical CPU#1). For the Viper TP1 case, SMP is off limits.
+ *
+ * Also note that many BMIPS435x CPUs do not have a
+ * BMIPS_RELO_VECTOR_CONTROL_1 register, so it isn't safe to just
+ * write VMLINUX_LOAD_ADDRESS into that register on every SoC.
+ */
+ if (current_cpu_type() == CPU_BMIPS4350 &&
+ kbase != CKSEG0 &&
+ read_c0_brcm_cmt_local() & CMT_LOCAL_TPID) {
+ board_ebase_setup = &kbase_setup;
+ bmips_smp_enabled = 0;
+ }
+}
+
+static void bcm6328_quirks(void)
+{
+ /* Check OTP to see if CPU1 is enabled (it usually isn't) */
+ if (__raw_readl(REG_BCM6328_OTP) & BCM6328_TP1_DISABLED)
+ bmips_smp_enabled = 0;
+}
+
+static void bcm6368_quirks(void)
+{
+ /*
+ * The bootloader has set up the CPU1 reset vector at
+ * 0xa000_0200.
+ * This conflicts with the special interrupt vector (IV).
+ * The bootloader has also set up CPU1 to respond to the wrong
+ * IPI interrupt.
+ * Here we will start up CPU1 in the background and ask it to
+ * reconfigure itself then go back to sleep.
+ */
+ memcpy((void *)0xa0000200, &bmips_smp_movevec, 0x20);
+ __sync();
+ set_c0_cause(C_SW0);
+ cpumask_set_cpu(1, &bmips_booted_mask);
+}
+
+static const struct bmips_board_list bmips_board_list[] = {
+ { &__dtb_bcm9ejtagprb_begin, 0x6328, NULL, &bcm6328_quirks },
+ { &__dtb_bcm96368mvwg_begin, 0x6368, NULL, &bcm6368_quirks },
+ { &__dtb_bcm97125cbmb_begin, 0x7125, "BCM97125C0" },
+ { &__dtb_bcm97346dbsmb_begin, 0x7346, "BCM97346DBSMB" },
+ { &__dtb_bcm97360svmb_begin, 0x7360, "BCM97360SVMB" },
+ { &__dtb_bcm97420c_begin, 0x7420, "BCM97420C_DDR3" },
+ { &__dtb_bcm97425svmb_begin, 0x7425, "BCM97425SVMB" },
+ { },
+};
+
+void __init prom_init(void)
+{
+ register_bmips_smp_ops();
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+const char *get_system_type(void)
+{
+ return "BMIPS multiplatform kernel";
+}
+
+void __init plat_time_init(void)
+{
+ struct device_node *np;
+ u32 freq;
+
+ np = of_find_node_by_name(NULL, "cpus");
+ if (!np)
+ panic("missing 'cpus' DT node");
+ if (of_property_read_u32(np, "mips-hpt-frequency", &freq) < 0)
+ panic("missing 'mips-hpt-frequency' property");
+ of_node_put(np);
+
+ mips_hpt_frequency = freq;
+}
+
+static void __init *find_dtb(void)
+{
+ u32 chip_id;
+ char boardname[64] = "";
+ const struct bmips_board_list *b;
+
+ /* Intended to somewhat resemble ARM; see Documentation/arm/Booting */
+ if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
+ return phys_to_virt(fw_arg2);
+
+ if (fw_arg1 != 0 || fw_arg3 != CFE_EPTSEAL ||
+ (fw_arg2 & 0xf0000000) != CKSEG0)
+ panic("cannot identify chip");
+
+ /*
+ * Unfortunately the CFE API doesn't seem to provide chip
+ * identification, but we can check the entry point to see whether
+ * the current platform is a DSL chip or STB chip. On STB,
+ * CAE_STKSIZE = _regidx(13) = 13*8 = 104, so the first instruction is:
+ * 0: 23bdff98 addi sp,sp,-104
+ */
+ if (__raw_readl((void *)fw_arg2) == 0x23bdff98) {
+ chip_id = __raw_readl(REG_STB_CHIP_ID);
+ cfe_init(fw_arg0, fw_arg2);
+ cfe_getenv("CFE_BOARDNAME", boardname, sizeof(boardname));
+ } else {
+ /*
+ * This works on most modern chips, but will break on older
+ * ones like 6358
+ */
+ chip_id = __raw_readl(REG_DSL_CHIP_ID);
+ }
+
+ /* 4-digit parts use bits [31:16]; 5-digit parts use [27:8] */
+ if (chip_id & 0xf0000000)
+ chip_id >>= 16;
+ else
+ chip_id >>= 8;
+
+ for (b = bmips_board_list; b->dtb; b++) {
+ if (b->chip_id != chip_id)
+ continue;
+ if (b->boardname && strcmp(b->boardname, boardname))
+ continue;
+ if (b->quirk_fn)
+ b->quirk_fn();
+ return b->dtb;
+ }
+
+ panic("no dtb found for current board");
+}
+
+void __init plat_mem_setup(void)
+{
+ set_io_port_base(0);
+ ioport_resource.start = 0;
+ ioport_resource.end = ~0;
+
+ __dt_setup_arch(find_dtb());
+ strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+
+ /* BCM3384 DTB comes from the bootloader, not from bmips_board_list */
+ if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
+ "brcm,bcm3384-viper")) {
+ bcm3384_quirks();
+ }
+}
+
+void __init device_tree_init(void)
+{
+ struct device_node *np;
+
+ unflatten_and_copy_device_tree();
+
+ /* Disable SMP boot unless both CPUs are listed in DT and !disabled */
+ np = of_find_node_by_name(NULL, "cpus");
+ if (np && of_get_available_child_count(np) <= 1)
+ bmips_smp_enabled = 0;
+ of_node_put(np);
+}
+
+int __init plat_of_setup(void)
+{
+ return __dt_register_buses("brcm,bmips", "simple-bus");
+}
+
+arch_initcall(plat_of_setup);
+
+static int __init plat_dev_init(void)
+{
+ of_clk_init(NULL);
+ return 0;
+}
+
+device_initcall(plat_dev_init);
diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile
index ca9c90e..ffae96b 100644
--- a/arch/mips/boot/dts/Makefile
+++ b/arch/mips/boot/dts/Makefile
@@ -1,3 +1,12 @@
+dtb-$(CONFIG_BMIPS_MULTIPLATFORM) += bcm93384wvg.dtb \
+ bcm93384wvg_viper.dtb \
+ bcm96368mvwg.dtb \
+ bcm9ejtagprb.dtb \
+ bcm97125cbmb.dtb \
+ bcm97346dbsmb.dtb \
+ bcm97360svmb.dtb \
+ bcm97420c.dtb \
+ bcm97425svmb.dtb
dtb-$(CONFIG_CAVIUM_OCTEON_SOC) += octeon_3xxx.dtb octeon_68xx.dtb
dtb-$(CONFIG_DT_EASY50712) += easy50712.dtb
dtb-$(CONFIG_DT_XLP_EVP) += xlp_evp.dtb
diff --git a/arch/mips/boot/dts/bcm3384_common.dtsi b/arch/mips/boot/dts/bcm3384_common.dtsi
new file mode 100644
index 0000000..448cb5b
--- /dev/null
+++ b/arch/mips/boot/dts/bcm3384_common.dtsi
@@ -0,0 +1,44 @@
+/ {
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ periph_clk: periph_clk@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <54000000>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ uart0: serial@14e00520 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x14e00520 0x18>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <2>;
+ clocks = <&periph_clk>;
+ status = "disabled";
+ };
+
+ ehci0: usb@15400300 {
+ compatible = "brcm,bcm3384-ehci", "generic-ehci";
+ reg = <0x15400300 0x100>;
+ big-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <41>;
+ status = "disabled";
+ };
+
+ ohci0: usb@15400400 {
+ compatible = "brcm,bcm3384-ohci", "generic-ohci";
+ reg = <0x15400400 0x100>;
+ big-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <40>;
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/boot/dts/bcm3384_viper.dtsi b/arch/mips/boot/dts/bcm3384_viper.dtsi
new file mode 100644
index 0000000..b5dba67
--- /dev/null
+++ b/arch/mips/boot/dts/bcm3384_viper.dtsi
@@ -0,0 +1,63 @@
+/include/ "bcm3384_common.dtsi"
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm3384-viper", "brcm,bcm33843-viper";
+
+ memory@0 {
+ device_type = "memory";
+
+ /*
+ * Typical ranges. The bootloader should fill these in.
+ * Note: no DMA translation on Viper (UBUS).
+ */
+ reg = <0x06000000 0x02000000 0x0e000000 0x02000000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* 1/2 of the CPU core clock (standard MIPS behavior) */
+ mips-hpt-frequency = <300000000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips4350";
+ device_type = "cpu";
+ reg = <0>;
+ };
+ };
+
+ cpu_intc: cpu_intc@0 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ periph_intc: periph_intc@14e00048 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x14e00048 0x8 0x14e00350 0x8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <4>;
+ brcm,int-map-mask = <0xffffffff 0xffffffff>;
+ };
+
+ cmips_intc: cmips_intc@151f8048 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x151f8048 0x8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <30>;
+ brcm,int-map-mask = <0xffffffff>;
+ };
+};
diff --git a/arch/mips/boot/dts/bcm3384_zephyr.dtsi b/arch/mips/boot/dts/bcm3384_zephyr.dtsi
new file mode 100644
index 0000000..bbbfe6e
--- /dev/null
+++ b/arch/mips/boot/dts/bcm3384_zephyr.dtsi
@@ -0,0 +1,82 @@
+/include/ "bcm3384_common.dtsi"
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm3384", "brcm,bcm33843";
+
+ memory@0 {
+ device_type = "memory";
+
+ /* Typical range. The bootloader should fill this in. */
+ reg = <0x0 0x08000000>;
+
+ /* Inverted mapping in low 256MB; 1:1 mapping above that. */
+ dma-xor-mask = <0x08000000>;
+ dma-xor-limit = <0x0fffffff>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* On BMIPS5000 this is 1/8th of the CPU core clock */
+ mips-hpt-frequency = <100000000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips5000";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "brcm,bmips5000";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ cpu_intc: cpu_intc@0 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ periph_intc: periph_intc@14e00038 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x14e00038 0x8 0x14e00340 0x8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <4>;
+ brcm,int-map-mask = <0xffffffff 0xffffffff>;
+ };
+
+ zmips_intc: zmips_intc@104b0060 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x104b0060 0x8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <29>;
+ brcm,int-map-mask = <0xffffffff>;
+ };
+
+ iop_intc: iop_intc@14e00058 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x14e00058 0x8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <6>;
+ brcm,int-map-mask = <0xffffffff>;
+ };
+};
diff --git a/arch/mips/boot/dts/bcm6328.dtsi b/arch/mips/boot/dts/bcm6328.dtsi
new file mode 100644
index 0000000..a7e397f
--- /dev/null
+++ b/arch/mips/boot/dts/bcm6328.dtsi
@@ -0,0 +1,63 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6328";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <160000000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips4350";
+ device_type = "cpu";
+ reg = <0>;
+ };
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ periph_clk: periph_clk@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ cpu_intc: cpu_intc@0 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ periph_intc: periph_intc@10000024 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x10000024 0x4 0x1000002c 0x4
+ 0x10000020 0x4 0x10000028 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ brcm,int-map-mask = <0xffffffff 0xffffffff>;
+ };
+
+ uart0: serial@10000100 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000100 0x18>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <28>;
+ clocks = <&periph_clk>;
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/boot/dts/bcm6368.dtsi b/arch/mips/boot/dts/bcm6368.dtsi
new file mode 100644
index 0000000..c8c6249
--- /dev/null
+++ b/arch/mips/boot/dts/bcm6368.dtsi
@@ -0,0 +1,89 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6368";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <200000000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips4350";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "brcm,bmips4350";
+ device_type = "cpu";
+ reg = <1>;
+ };
+
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ periph_clk: periph_clk@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ cpu_intc: cpu_intc@0 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ periph_intc: periph_intc@10000024 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x10000024 0x4 0x1000002c 0x4
+ 0x10000020 0x4 0x10000028 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ brcm,int-map-mask = <0xffffffff 0xffffffff>;
+ };
+
+ uart0: serial@10000100 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000100 0x18>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <2>;
+ clocks = <&periph_clk>;
+ status = "disabled";
+ };
+
+ ehci0: usb@10001500 {
+ compatible = "brcm,bcm6368-ehci", "generic-ehci";
+ reg = <0x10001500 0x100>;
+ big-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <7>;
+ status = "disabled";
+ };
+
+ ohci0: usb@10001600 {
+ compatible = "brcm,bcm6368-ohci", "generic-ohci";
+ reg = <0x10001600 0x100>;
+ big-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <5>;
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/boot/dts/bcm7125.dtsi b/arch/mips/boot/dts/bcm7125.dtsi
new file mode 100644
index 0000000..2031590
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7125.dtsi
@@ -0,0 +1,99 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm7125";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <202500000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips4380";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "brcm,bmips4380";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ cpu_intc: cpu_intc@0 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ periph_intc: periph_intc@10441400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x10441400 0x30 0x10441600 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@10406780 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x10406780 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <18>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ uart_clk: uart_clk@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ uart0: serial@10406b00 {
+ compatible = "ns16550a";
+ reg = <0x10406b00 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <21>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ ehci0: usb@10488300 {
+ compatible = "brcm,bcm7125-ehci", "generic-ehci";
+ reg = <0x10488300 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <60>;
+ status = "disabled";
+ };
+
+ ohci0: usb@10488400 {
+ compatible = "brcm,bcm7125-ohci", "generic-ohci";
+ reg = <0x10488400 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <61>;
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/boot/dts/bcm7346.dtsi b/arch/mips/boot/dts/bcm7346.dtsi
new file mode 100644
index 0000000..a4ee332
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7346.dtsi
@@ -0,0 +1,174 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm7346";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <163125000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips5000";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "brcm,bmips5000";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ cpu_intc: cpu_intc@0 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ periph_intc: periph_intc@10411400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x10411400 0x30 0x10411600 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@10406780 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x10406780 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <59>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ uart_clk: uart_clk@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ uart0: serial@10406900 {
+ compatible = "ns16550a";
+ reg = <0x10406900 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <64>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ enet0: ethernet@10430000 {
+ phy-mode = "internal";
+ phy-handle = <&phy1>;
+ mac-address = [ 00 10 18 36 23 1a ];
+ compatible = "brcm,genet-v2";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0x10430000 0x4c8c>;
+ interrupts = <24>, <25>;
+ interrupt-parent = <&periph_intc>;
+ status = "disabled";
+
+ mdio@e14 {
+ compatible = "brcm,genet-mdio-v2";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+
+ phy1: ethernet-phy@1 {
+ max-speed = <100>;
+ reg = <0x1>;
+ compatible = "brcm,40nm-ephy",
+ "ethernet-phy-ieee802.3-c22";
+ };
+ };
+ };
+
+ ehci0: usb@10480300 {
+ compatible = "brcm,bcm7346-ehci", "generic-ehci";
+ reg = <0x10480300 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <68>;
+ status = "disabled";
+ };
+
+ ohci0: usb@10480400 {
+ compatible = "brcm,bcm7346-ohci", "generic-ohci";
+ reg = <0x10480400 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <70>;
+ status = "disabled";
+ };
+
+ ehci1: usb@10480500 {
+ compatible = "brcm,bcm7346-ehci", "generic-ehci";
+ reg = <0x10480500 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <69>;
+ status = "disabled";
+ };
+
+ ohci1: usb@10480600 {
+ compatible = "brcm,bcm7346-ohci", "generic-ohci";
+ reg = <0x10480600 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <71>;
+ status = "disabled";
+ };
+
+ ehci2: usb@10490300 {
+ compatible = "brcm,bcm7346-ehci", "generic-ehci";
+ reg = <0x10490300 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <73>;
+ status = "disabled";
+ };
+
+ ohci2: usb@10490400 {
+ compatible = "brcm,bcm7346-ohci", "generic-ohci";
+ reg = <0x10490400 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <75>;
+ status = "disabled";
+ };
+
+ ehci3: usb@10490500 {
+ compatible = "brcm,bcm7346-ehci", "generic-ehci";
+ reg = <0x10490500 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <74>;
+ status = "disabled";
+ };
+
+ ohci3: usb@10490600 {
+ compatible = "brcm,bcm7346-ohci", "generic-ohci";
+ reg = <0x10490600 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <76>;
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/boot/dts/bcm7360.dtsi b/arch/mips/boot/dts/bcm7360.dtsi
new file mode 100644
index 0000000..d689a73
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7360.dtsi
@@ -0,0 +1,121 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm7360";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <375000000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips3300";
+ device_type = "cpu";
+ reg = <0>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ cpu_intc: cpu_intc@0 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ periph_intc: periph_intc@10411400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x10411400 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@10406600 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x10406600 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <56>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ uart_clk: uart_clk@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ uart0: serial@10406800 {
+ compatible = "ns16550a";
+ reg = <0x10406800 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <61>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ enet0: ethernet@10430000 {
+ phy-mode = "internal";
+ phy-handle = <&phy1>;
+ mac-address = [ 00 10 18 36 23 1a ];
+ compatible = "brcm,genet-v2";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0x10430000 0x4c8c>;
+ interrupts = <24>, <25>;
+ interrupt-parent = <&periph_intc>;
+ status = "disabled";
+
+ mdio@e14 {
+ compatible = "brcm,genet-mdio-v2";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+
+ phy1: ethernet-phy@1 {
+ max-speed = <100>;
+ reg = <0x1>;
+ compatible = "brcm,40nm-ephy",
+ "ethernet-phy-ieee802.3-c22";
+ };
+ };
+ };
+
+ ehci0: usb@10480300 {
+ compatible = "brcm,bcm7360-ehci", "generic-ehci";
+ reg = <0x10480300 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <65>;
+ status = "disabled";
+ };
+
+ ohci0: usb@10480400 {
+ compatible = "brcm,bcm7360-ohci", "generic-ohci";
+ reg = <0x10480400 0x100>;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <66>;
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/boot/dts/bcm7420.dtsi b/arch/mips/boot/dts/bcm7420.dtsi
new file mode 100644
index 0000000..e299dcb
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7420.dtsi
@@ -0,0 +1,142 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm7420";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <93750000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips5000";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "brcm,bmips5000";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ cpu_intc: cpu_intc@0 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ periph_intc: periph_intc@10441400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x10441400 0x30 0x10441600 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@10406780 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x10406780 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <18>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ uart_clk: uart_clk@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ uart0: serial@10406b00 {
+ compatible = "ns16550a";
+ reg = <0x10406b00 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <21>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ enet0: ethernet@10468000 {
+ phy-mode = "internal";
+ phy-handle = <&phy1>;
+ mac-address = [ 00 10 18 36 23 1a ];
+ compatible = "brcm,genet-v1";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0x10468000 0x3c8c>;
+ interrupts = <69>, <79>;
+ interrupt-parent = <&periph_intc>;
+ status = "disabled";
+
+ mdio@e14 {
+ compatible = "brcm,genet-mdio-v1";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+
+ phy1: ethernet-phy@1 {
+ max-speed = <100>;
+ reg = <0x1>;
+ compatible = "brcm,65nm-ephy",
+ "ethernet-phy-ieee802.3-c22";
+ };
+ };
+ };
+
+ ehci0: usb@10488300 {
+ compatible = "brcm,bcm7420-ehci", "generic-ehci";
+ reg = <0x10488300 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <60>;
+ status = "disabled";
+ };
+
+ ohci0: usb@10488400 {
+ compatible = "brcm,bcm7420-ohci", "generic-ohci";
+ reg = <0x10488400 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <61>;
+ status = "disabled";
+ };
+
+ ehci1: usb@10488500 {
+ compatible = "brcm,bcm7420-ehci", "generic-ehci";
+ reg = <0x10488500 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <55>;
+ status = "disabled";
+ };
+
+ ohci1: usb@10488600 {
+ compatible = "brcm,bcm7420-ohci", "generic-ohci";
+ reg = <0x10488600 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <62>;
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/boot/dts/bcm7425.dtsi b/arch/mips/boot/dts/bcm7425.dtsi
new file mode 100644
index 0000000..b7bd4dd
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7425.dtsi
@@ -0,0 +1,174 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm7425";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <163125000>;
+
+ cpu@0 {
+ compatible = "brcm,bmips5000";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "brcm,bmips5000";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ cpu_intc: cpu_intc@0 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ periph_intc: periph_intc@1041a400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x1041a400 0x30 0x1041a600 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@10406780 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x10406780 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <55>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ uart_clk: uart_clk@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ uart0: serial@10406b00 {
+ compatible = "ns16550a";
+ reg = <0x10406b00 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <61>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ enet0: ethernet@10b80000 {
+ phy-mode = "internal";
+ phy-handle = <&phy1>;
+ mac-address = [ 00 10 18 36 23 1a ];
+ compatible = "brcm,genet-v3";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0x10b80000 0x11c88>;
+ interrupts = <17>, <18>;
+ interrupt-parent = <&periph_intc>;
+ status = "disabled";
+
+ mdio@e14 {
+ compatible = "brcm,genet-mdio-v3";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+
+ phy1: ethernet-phy@1 {
+ max-speed = <100>;
+ reg = <0x1>;
+ compatible = "brcm,40nm-ephy",
+ "ethernet-phy-ieee802.3-c22";
+ };
+ };
+ };
+
+ ehci0: usb@10480300 {
+ compatible = "brcm,bcm7425-ehci", "generic-ehci";
+ reg = <0x10480300 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <65>;
+ status = "disabled";
+ };
+
+ ohci0: usb@10480400 {
+ compatible = "brcm,bcm7425-ohci", "generic-ohci";
+ reg = <0x10480400 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <67>;
+ status = "disabled";
+ };
+
+ ehci1: usb@10480500 {
+ compatible = "brcm,bcm7425-ehci", "generic-ehci";
+ reg = <0x10480500 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <66>;
+ status = "disabled";
+ };
+
+ ohci1: usb@10480600 {
+ compatible = "brcm,bcm7425-ohci", "generic-ohci";
+ reg = <0x10480600 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <68>;
+ status = "disabled";
+ };
+
+ ehci2: usb@10490300 {
+ compatible = "brcm,bcm7425-ehci", "generic-ehci";
+ reg = <0x10490300 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <70>;
+ status = "disabled";
+ };
+
+ ohci2: usb@10490400 {
+ compatible = "brcm,bcm7425-ohci", "generic-ohci";
+ reg = <0x10490400 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <72>;
+ status = "disabled";
+ };
+
+ ehci3: usb@10490500 {
+ compatible = "brcm,bcm7425-ehci", "generic-ehci";
+ reg = <0x10490500 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <71>;
+ status = "disabled";
+ };
+
+ ohci3: usb@10490600 {
+ compatible = "brcm,bcm7425-ohci", "generic-ohci";
+ reg = <0x10490600 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <73>;
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/boot/dts/bcm93384wvg.dts b/arch/mips/boot/dts/bcm93384wvg.dts
new file mode 100644
index 0000000..d1e44a1
--- /dev/null
+++ b/arch/mips/boot/dts/bcm93384wvg.dts
@@ -0,0 +1,25 @@
+/dts-v1/;
+
+/include/ "bcm3384_zephyr.dtsi"
+
+/ {
+ compatible = "brcm,bcm93384wvg", "brcm,bcm3384";
+ model = "Broadcom BCM93384WVG";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
diff --git a/arch/mips/boot/dts/bcm93384wvg_viper.dts b/arch/mips/boot/dts/bcm93384wvg_viper.dts
new file mode 100644
index 0000000..1ecb269
--- /dev/null
+++ b/arch/mips/boot/dts/bcm93384wvg_viper.dts
@@ -0,0 +1,25 @@
+/dts-v1/;
+
+/include/ "bcm3384_viper.dtsi"
+
+/ {
+ compatible = "brcm,bcm93384wvg-viper", "brcm,bcm3384-viper";
+ model = "Broadcom BCM93384WVG-viper";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
diff --git a/arch/mips/boot/dts/bcm96368mvwg.dts b/arch/mips/boot/dts/bcm96368mvwg.dts
new file mode 100644
index 0000000..0e890c2
--- /dev/null
+++ b/arch/mips/boot/dts/bcm96368mvwg.dts
@@ -0,0 +1,31 @@
+/dts-v1/;
+
+/include/ "bcm6368.dtsi"
+
+/ {
+ compatible = "brcm,bcm96368mvwg", "brcm,bcm6368";
+ model = "Broadcom BCM96368MVWG";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+/* FIXME: need to set up USB_CTRL registers first */
+&ehci0 {
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "disabled";
+};
diff --git a/arch/mips/boot/dts/bcm97125cbmb.dts b/arch/mips/boot/dts/bcm97125cbmb.dts
new file mode 100644
index 0000000..e046b11
--- /dev/null
+++ b/arch/mips/boot/dts/bcm97125cbmb.dts
@@ -0,0 +1,31 @@
+/dts-v1/;
+
+/include/ "bcm7125.dtsi"
+
+/ {
+ compatible = "brcm,bcm97125cbmb", "brcm,bcm7125";
+ model = "Broadcom BCM97125CBMB";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+/* FIXME: USB is wonky; disable it for now */
+&ehci0 {
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "disabled";
+};
diff --git a/arch/mips/boot/dts/bcm97346dbsmb.dts b/arch/mips/boot/dts/bcm97346dbsmb.dts
new file mode 100644
index 0000000..3095f7b
--- /dev/null
+++ b/arch/mips/boot/dts/bcm97346dbsmb.dts
@@ -0,0 +1,58 @@
+/dts-v1/;
+
+/include/ "bcm7346.dtsi"
+
+/ {
+ compatible = "brcm,bcm97346dbsmb", "brcm,bcm7346";
+ model = "Broadcom BCM97346DBSMB";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000 0x20000000 0x30000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&enet0 {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
diff --git a/arch/mips/boot/dts/bcm97360svmb.dts b/arch/mips/boot/dts/bcm97360svmb.dts
new file mode 100644
index 0000000..4fe5155
--- /dev/null
+++ b/arch/mips/boot/dts/bcm97360svmb.dts
@@ -0,0 +1,34 @@
+/dts-v1/;
+
+/include/ "bcm7360.dtsi"
+
+/ {
+ compatible = "brcm,bcm97360svmb", "brcm,bcm7360";
+ model = "Broadcom BCM97360SVMB";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&enet0 {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
diff --git a/arch/mips/boot/dts/bcm97420c.dts b/arch/mips/boot/dts/bcm97420c.dts
new file mode 100644
index 0000000..15bb8a0
--- /dev/null
+++ b/arch/mips/boot/dts/bcm97420c.dts
@@ -0,0 +1,44 @@
+/dts-v1/;
+
+/include/ "bcm7420.dtsi"
+
+/ {
+ compatible = "brcm,bcm97420c", "brcm,bcm7420";
+ model = "Broadcom BCM97420C";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000 0x20000000 0x30000000
+ 0x60000000 0x10000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+/* FIXME: MAC driver comes up but cannot attach to PHY */
+&enet0 {
+ status = "disabled";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
diff --git a/arch/mips/boot/dts/bcm97425svmb.dts b/arch/mips/boot/dts/bcm97425svmb.dts
new file mode 100644
index 0000000..077f266
--- /dev/null
+++ b/arch/mips/boot/dts/bcm97425svmb.dts
@@ -0,0 +1,59 @@
+/dts-v1/;
+
+/include/ "bcm7425.dtsi"
+
+/ {
+ compatible = "brcm,bcm97425svmb", "brcm,bcm7425";
+ model = "Broadcom BCM97425SVMB";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000 0x20000000 0x30000000
+ 0x90000000 0x40000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&enet0 {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
diff --git a/arch/mips/boot/dts/bcm9ejtagprb.dts b/arch/mips/boot/dts/bcm9ejtagprb.dts
new file mode 100644
index 0000000..1da4608
--- /dev/null
+++ b/arch/mips/boot/dts/bcm9ejtagprb.dts
@@ -0,0 +1,22 @@
+/dts-v1/;
+
+/include/ "bcm6328.dtsi"
+
+/ {
+ compatible = "brcm,bcm9ejtagprb", "brcm,bcm6328";
+ model = "Broadcom BCM9EJTAGPRB";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/mips/configs/bmips_be_defconfig b/arch/mips/configs/bmips_be_defconfig
new file mode 100644
index 0000000..2490d7a2
--- /dev/null
+++ b/arch/mips/configs/bmips_be_defconfig
@@ -0,0 +1,83 @@
+CONFIG_BMIPS_MULTIPLATFORM=y
+CONFIG_HIGHMEM=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+# CONFIG_SECCOMP is not set
+CONFIG_MIPS_O32_FP64_SUPPORT=y
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_NO_HZ=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_GZIP is not set
+CONFIG_EXPERT=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_MAC80211=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_MTD=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_BLK_DEV is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_BCMGENET=y
+CONFIG_USB_USBNET=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_BCM63XX=y
+CONFIG_SERIAL_BCM63XX_CONSOLE=y
+# CONFIG_SERIAL_BCM63XX_TTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_CIFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="earlycon"
+# CONFIG_CRYPTO_HW is not set
diff --git a/arch/mips/configs/bmips_stb_defconfig b/arch/mips/configs/bmips_stb_defconfig
new file mode 100644
index 0000000..e9313b0
--- /dev/null
+++ b/arch/mips/configs/bmips_stb_defconfig
@@ -0,0 +1,83 @@
+CONFIG_BMIPS_MULTIPLATFORM=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_HIGHMEM=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+# CONFIG_SECCOMP is not set
+CONFIG_MIPS_O32_FP64_SUPPORT=y
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_NO_HZ=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_GZIP is not set
+CONFIG_EXPERT=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_MAC80211=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_MTD=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_BLK_DEV is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_BCMGENET=y
+CONFIG_USB_USBNET=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_CIFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="earlycon"
+# CONFIG_CRYPTO_HW is not set
diff --git a/arch/mips/include/asm/mach-bmips/dma-coherence.h b/arch/mips/include/asm/mach-bmips/dma-coherence.h
new file mode 100644
index 0000000..5481a4d
--- /dev/null
+++ b/arch/mips/include/asm/mach-bmips/dma-coherence.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006 Ralf Baechle <[email protected]>
+ * Copyright (C) 2009-2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_MACH_BMIPS_DMA_COHERENCE_H
+#define __ASM_MACH_BMIPS_DMA_COHERENCE_H
+
+struct device;
+
+extern dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size);
+extern dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page);
+extern unsigned long plat_dma_addr_to_phys(struct device *dev,
+ dma_addr_t dma_addr);
+extern void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction direction);
+
+static inline int plat_dma_supported(struct device *dev, u64 mask)
+{
+ /*
+ * we fall back to GFP_DMA when the mask isn't all 1s,
+ * so we can't guarantee allocations that must be
+ * within a tighter range than GFP_DMA..
+ */
+ if (mask < DMA_BIT_MASK(24))
+ return 0;
+
+ return 1;
+}
+
+static inline int plat_device_is_coherent(struct device *dev)
+{
+ return 0;
+}
+
+#endif /* __ASM_MACH_BMIPS_DMA_COHERENCE_H */
diff --git a/arch/mips/include/asm/mach-bmips/spaces.h b/arch/mips/include/asm/mach-bmips/spaces.h
new file mode 100644
index 0000000..1f7bc6c
--- /dev/null
+++ b/arch/mips/include/asm/mach-bmips/spaces.h
@@ -0,0 +1,17 @@
+/*
+ * 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
+ * for more details.
+ *
+ * Copyright (C) 1994 - 1999, 2000, 03, 04 Ralf Baechle
+ * Copyright (C) 2000, 2002 Maciej W. Rozycki
+ * Copyright (C) 1990, 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_BMIPS_SPACES_H
+#define _ASM_BMIPS_SPACES_H
+
+#define FIXADDR_TOP ((unsigned long)(long)(int)0xff000000)
+
+#include <asm/mach-generic/spaces.h>
+
+#endif /* __ASM_BMIPS_SPACES_H */
diff --git a/arch/mips/include/asm/mach-bmips/war.h b/arch/mips/include/asm/mach-bmips/war.h
new file mode 100644
index 0000000..65af109
--- /dev/null
+++ b/arch/mips/include/asm/mach-bmips/war.h
@@ -0,0 +1,24 @@
+/*
+ * 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
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <[email protected]>
+ */
+#ifndef __ASM_MIPS_MACH_BMIPS_WAR_H
+#define __ASM_MIPS_MACH_BMIPS_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif /* __ASM_MIPS_MACH_BMIPS_WAR_H */
--
2.1.1
On some chips like bcm3384, "other stuff" gets wired up to CPU1's IE_IRQ1
input, generating spurious IRQs. In this case we want the platform code
to be able to mask it off.
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/include/asm/bmips.h | 1 +
arch/mips/kernel/smp-bmips.c | 6 ++++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/mips/include/asm/bmips.h b/arch/mips/include/asm/bmips.h
index cbacceb..30939b0 100644
--- a/arch/mips/include/asm/bmips.h
+++ b/arch/mips/include/asm/bmips.h
@@ -84,6 +84,7 @@ extern char bmips_smp_int_vec_end;
extern int bmips_smp_enabled;
extern int bmips_cpu_offset;
extern cpumask_t bmips_booted_mask;
+extern unsigned long bmips_tp1_irqs;
extern void bmips_ebase_setup(void);
extern asmlinkage void plat_wired_tlb_setup(void);
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 162391d..b8bd934 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -43,6 +43,7 @@ static int __maybe_unused max_cpus = 1;
int bmips_smp_enabled = 1;
int bmips_cpu_offset;
cpumask_t bmips_booted_mask;
+unsigned long bmips_tp1_irqs = IE_IRQ1;
#define RESET_FROM_KSEG0 0x80080800
#define RESET_FROM_KSEG1 0xa0080800
@@ -257,7 +258,7 @@ static void bmips_smp_finish(void)
write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
irq_enable_hazard();
- set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE);
+ set_c0_status(IE_SW0 | IE_SW1 | bmips_tp1_irqs | IE_IRQ5 | ST0_IE);
irq_enable_hazard();
}
@@ -387,7 +388,8 @@ void __ref play_dead(void)
* IRQ handlers; this clears ST0_IE and returns immediately.
*/
clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1);
- change_c0_status(IE_IRQ5 | IE_IRQ1 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV,
+ change_c0_status(
+ IE_IRQ5 | bmips_tp1_irqs | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV,
IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV);
irq_disable_hazard();
--
2.1.1
Add myself as a maintainer for the new BMIPS target.
Signed-off-by: Kevin Cernekee <[email protected]>
---
MAINTAINERS | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 6ab20b4..e96b4ae 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2108,6 +2108,18 @@ S: Maintained
F: arch/arm/mach-bcm/*brcmstb*
F: arch/arm/boot/dts/bcm7*.dts*
+BROADCOM BMIPS MIPS ARCHITECTURE
+M: Kevin Cernekee <[email protected]>
+M: Florian Fainelli <[email protected]>
+L: [email protected]
+S: Maintained
+F: arch/mips/bmips/*
+F: arch/mips/include/asm/mach-bmips/*
+F: arch/mips/kernel/*bmips*
+F: arch/mips/boot/dts/bcm*.dts*
+F: drivers/irqchip/irq-bcm7*
+F: drivers/irqchip/irq-brcmstb*
+
BROADCOM TG3 GIGABIT ETHERNET DRIVER
M: Prashant Sreedharan <[email protected]>
M: Michael Chan <[email protected]>
--
2.1.1
This hardware shows up on the newly-supported BCM3384 cable chip, as well
as several old BCM63xx DSL chips.
Signed-off-by: Kevin Cernekee <[email protected]>
---
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index e5e8a55..6ab20b4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2094,6 +2094,12 @@ S: Maintained
F: arch/arm/mach-bcm/bcm63xx.c
F: arch/arm/include/debug/bcm63xx.S
+BROADCOM BCM63XX/BCM33XX UDC DRIVER
+M: Kevin Cernekee <[email protected]>
+L: [email protected]
+S: Maintained
+F: drivers/usb/gadget/udc/bcm63xx_udc.*
+
BROADCOM BCM7XXX ARM ARCHITECTURE
M: Marc Carino <[email protected]>
M: Brian Norris <[email protected]>
--
2.1.1
BMIPS435x and BMIPS438x have a single shared L1 D$ and load/store unit,
so it isn't necessary to raise IPIs to keep both CPUs coherent.
BMIPS5000 has VIPT L1 caches that handle aliases in hardware, and its I$
fills from D$. But a special sequence with 2 SYNCs and 32 NOPs is needed
to ensure coherency.
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/mm/c-r4k.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index fbcd867..dd261df 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -917,6 +917,18 @@ static inline void alias_74k_erratum(struct cpuinfo_mips *c)
}
}
+static void b5k_instruction_hazard(void)
+{
+ __sync();
+ __sync();
+ __asm__ __volatile__(
+ " nop; nop; nop; nop; nop; nop; nop; nop\n"
+ " nop; nop; nop; nop; nop; nop; nop; nop\n"
+ " nop; nop; nop; nop; nop; nop; nop; nop\n"
+ " nop; nop; nop; nop; nop; nop; nop; nop\n"
+ : : : "memory");
+}
+
static char *way_string[] = { NULL, "direct mapped", "2-way",
"3-way", "4-way", "5-way", "6-way", "7-way", "8-way"
};
@@ -1683,6 +1695,37 @@ void r4k_cache_init(void)
coherency_setup();
board_cache_error_setup = r4k_cache_error_setup;
+
+ /*
+ * Per-CPU overrides
+ */
+ switch (current_cpu_type()) {
+ case CPU_BMIPS4350:
+ case CPU_BMIPS4380:
+ /* No IPI is needed because all CPUs share the same D$ */
+ flush_data_cache_page = r4k_blast_dcache_page;
+ break;
+ case CPU_BMIPS5000:
+ /* We lose our superpowers if L2 is disabled */
+ if (c->scache.flags & MIPS_CACHE_NOT_PRESENT)
+ break;
+
+ /* I$ fills from D$ just by emptying the write buffers */
+ flush_cache_page = (void *)b5k_instruction_hazard;
+ flush_cache_range = (void *)b5k_instruction_hazard;
+ flush_cache_sigtramp = (void *)b5k_instruction_hazard;
+ local_flush_data_cache_page = (void *)b5k_instruction_hazard;
+ flush_data_cache_page = (void *)b5k_instruction_hazard;
+ flush_icache_range = (void *)b5k_instruction_hazard;
+ local_flush_icache_range = (void *)b5k_instruction_hazard;
+
+ /* Cache aliases are handled in hardware; allow HIGHMEM */
+ current_cpu_data.dcache.flags &= ~MIPS_CACHE_ALIASES;
+
+ /* Optimization: an L2 flush implicitly flushes the L1 */
+ current_cpu_data.options |= MIPS_CPU_INCLUSIVE_CACHES;
+ break;
+ }
}
static int r4k_cache_pm_notifier(struct notifier_block *self, unsigned long cmd,
--
2.1.1
A couple of platforms register two buses and call of_platform_populate().
Move this into a common function to reduce duplication.
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/include/asm/prom.h | 1 +
arch/mips/kernel/prom.c | 18 ++++++++++++++++++
arch/mips/lantiq/prom.c | 11 +----------
arch/mips/ralink/of.c | 14 ++------------
4 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/arch/mips/include/asm/prom.h b/arch/mips/include/asm/prom.h
index a9494c0..eaa2627 100644
--- a/arch/mips/include/asm/prom.h
+++ b/arch/mips/include/asm/prom.h
@@ -22,6 +22,7 @@ extern void device_tree_init(void);
struct boot_param_header;
extern void __dt_setup_arch(void *bph);
+extern int __dt_register_buses(const char *bus0, const char *bus1);
#define dt_setup_arch(sym) \
({ \
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
index 5d39bb8..452d435 100644
--- a/arch/mips/kernel/prom.c
+++ b/arch/mips/kernel/prom.c
@@ -16,6 +16,7 @@
#include <linux/debugfs.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
#include <asm/page.h>
#include <asm/prom.h>
@@ -54,4 +55,21 @@ void __init __dt_setup_arch(void *bph)
mips_set_machine_name(of_flat_dt_get_machine_name());
}
+
+int __init __dt_register_buses(const char *bus0, const char *bus1)
+{
+ static struct of_device_id of_ids[3];
+
+ if (!of_have_populated_dt())
+ panic("device tree not present");
+
+ strlcpy(of_ids[0].compatible, bus0, sizeof(of_ids[0].compatible));
+ strlcpy(of_ids[1].compatible, bus1, sizeof(of_ids[1].compatible));
+
+ if (of_platform_populate(NULL, of_ids, NULL, NULL))
+ panic("failed to populate DT");
+
+ return 0;
+}
+
#endif
diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
index 7447d32..758970e 100644
--- a/arch/mips/lantiq/prom.c
+++ b/arch/mips/lantiq/prom.c
@@ -97,16 +97,7 @@ void __init prom_init(void)
int __init plat_of_setup(void)
{
- static struct of_device_id of_ids[3];
-
- if (!of_have_populated_dt())
- panic("device tree not present");
-
- strlcpy(of_ids[0].compatible, soc_info.compatible,
- sizeof(of_ids[0].compatible));
- strncpy(of_ids[1].compatible, "simple-bus",
- sizeof(of_ids[1].compatible));
- return of_platform_populate(NULL, of_ids, NULL, NULL);
+ return __dt_register_buses(soc_info.compatible, "simple-bus");
}
arch_initcall(plat_of_setup);
diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c
index 7c4598c..f68115f 100644
--- a/arch/mips/ralink/of.c
+++ b/arch/mips/ralink/of.c
@@ -74,19 +74,9 @@ void __init plat_mem_setup(void)
static int __init plat_of_setup(void)
{
- static struct of_device_id of_ids[3];
- int len = sizeof(of_ids[0].compatible);
+ __dt_register_buses(soc_info.compatible, "palmbus");
- if (!of_have_populated_dt())
- panic("device tree not present");
-
- strlcpy(of_ids[0].compatible, soc_info.compatible, len);
- strlcpy(of_ids[1].compatible, "palmbus", len);
-
- if (of_platform_populate(NULL, of_ids, NULL, NULL))
- panic("failed to populate DT");
-
- /* make sure ithat the reset controller is setup early */
+ /* make sure that the reset controller is setup early */
ralink_rst_init();
return 0;
--
2.1.1
BMIPS platforms can select multiple CPUs, in which case we'll need to
use the greatest common denominator (= 1 << 7 = 128 bytes, for the
BMIPS5000 L2).
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3d56928..c0130ec 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1473,6 +1473,7 @@ config CPU_BMIPS
select WEAK_ORDERING
select CPU_SUPPORTS_HIGHMEM
select CPU_HAS_PREFETCH
+ select MIPS_L1_CACHE_SHIFT_7
help
Support for BMIPS32/3300/4350/4380 and BMIPS5000 processors.
--
2.1.1
CONFIG_MIPS_CPU_SCACHE determines whether to build sc-mips.c. However,
it is currently hardwired to use an L1_SHIFT of 6 (64 bytes). Move the
L1_SHIFT selection into the CPU or SoC section so that other SoCs can
select different values.
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 92033b7..3d56928 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -326,6 +326,7 @@ config MIPS_MALTA
select I8259
select MIPS_BONITO64
select MIPS_CPU_SCACHE
+ select MIPS_L1_CACHE_SHIFT_6
select PCI_GT64XXX_PCI0
select MIPS_MSC
select SWAP_IO_SPACE
@@ -1909,7 +1910,6 @@ config IP22_CPU_SCACHE
config MIPS_CPU_SCACHE
bool
select BOARD_SCACHE
- select MIPS_L1_CACHE_SHIFT_6
config R5000_CPU_SCACHE
bool
--
2.1.1
From: Jon Fraser <[email protected]>
CPU interrupts need to be disabled on a cpu being taken down.
When a cpu is hot-plugged out of the system the following sequence occurs.
On the CPU where the hotplug sequence was initiated:
cpu_down
_cpu_down {
__cpu_notify(CPU_DOWN_PREPARE
__stop_machine(take_cpu_down
wait for cpu to run disable code.
__cpu_die
}
On the CPU being disabled:
take_cpu_down
__cpu_disable {
mp_ops->cpu_disable
bmips_cpu_disable
clear_c0_status(IE_IRQ5) (added)
cpu_notify(CPU_DYING...
}
Before the cpu_notifier is called with CPU_DYING, all interrupts on the
dying cpu must be disabled. This guarantees that before tick_notify is
called with the CPU_DYING event and sets the clock device pointer to
NULL, there can not be any more clock interrupts.
When this wasn't done, an unfortunately-timed timer interrupt sometimes
caused hangs immediately prior to system suspend:
Debug PM is not enabled. To enable partial suspend, rebuild kernel with CONFIG_PM_DEBUG
Pass 1 out of 1,PM: Syncing filesystems ... mode=none, tp1=done.
1, flags=5, cycle_tp=, sleep=
Freezing user space processes ... (elapsed 0.01 seconds) done.
Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.
PM: suspend of devices complete after 54.199 msecs
PM: late suspend of devices complete after 0.172 msecs
Disabling non-boot CPUs ...
SMP: CPU1 is offline
INFO: rcu_sched detected stalls on CPUs/tasks: { 3} (detected by 0, t=62537 jiffies)
Call Trace:
[<804baa78>] dump_stack+0x8/0x34
[<8008a2d8>] __rcu_pending+0x4b8/0x55c
[<8008adf4>] rcu_check_callbacks+0x78/0x180
[<80037830>] update_process_times+0x40/0x6c
[<80072fe4>] tick_sched_timer+0x74/0xe4
[<80050180>] __run_hrtimer.clone.30+0x64/0x140
[<80051150>] hrtimer_interrupt+0x19c/0x4bc
[<8000cdb8>] c0_compare_interrupt+0x50/0x88
[<80081b18>] handle_irq_event_percpu+0x5c/0x2f4
[<80086490>] handle_percpu_irq+0x8c/0xc0
[<800811b4>] generic_handle_irq+0x34/0x54
[<800067dc>] do_IRQ+0x18/0x2c
[<8000375c>] plat_irq_dispatch+0xd0/0x128
[<80004a04>] ret_from_irq+0x0/0x4
[<80004c40>] r4k_wait+0x20/0x40
[<80006b6c>] cpu_idle+0x98/0xf0
[<805d3988>] start_kernel+0x424/0x440
Signed-off-by: Jon Fraser <[email protected]>
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/kernel/smp-bmips.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 887c3ea..f7b1bee 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -375,6 +375,7 @@ static int bmips_cpu_disable(void)
set_cpu_online(cpu, false);
cpu_clear(cpu, cpu_callin_map);
+ clear_c0_status(IE_IRQ5);
local_flush_tlb_all();
local_flush_icache_range(0, ~0);
--
2.1.1
This will need to be called from a few different places, and the logic
is starting to get a bit hairy (with the need for IPIs, CPU bug
workarounds, and hazards).
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/kernel/smp-bmips.c | 65 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 58 insertions(+), 7 deletions(-)
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 4e56911..8383fa4 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -35,6 +35,7 @@
#include <asm/bmips.h>
#include <asm/traps.h>
#include <asm/barrier.h>
+#include <asm/cpu-features.h>
static int __maybe_unused max_cpus = 1;
@@ -43,6 +44,9 @@ int bmips_smp_enabled = 1;
int bmips_cpu_offset;
cpumask_t bmips_booted_mask;
+#define RESET_FROM_KSEG0 0x80080800
+#define RESET_FROM_KSEG1 0xa0080800
+
#ifdef CONFIG_SMP
/* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */
@@ -463,10 +467,61 @@ static inline void bmips_nmi_handler_setup(void)
&bmips_smp_int_vec_end);
}
+struct reset_vec_info {
+ int cpu;
+ u32 val;
+};
+
+static void bmips_set_reset_vec_remote(void *vinfo)
+{
+ struct reset_vec_info *info = vinfo;
+ int shift = info->cpu & 0x01 ? 16 : 0;
+ u32 mask = ~(0xffff << shift), val = info->val >> 16;
+
+ preempt_disable();
+ if (smp_processor_id() > 0) {
+ smp_call_function_single(0, &bmips_set_reset_vec_remote,
+ info, 1);
+ } else {
+ if (info->cpu & 0x02) {
+ /* BMIPS5200 "should" use mask/shift, but it's buggy */
+ bmips_write_zscm_reg(0xa0, (val << 16) | val);
+ bmips_read_zscm_reg(0xa0);
+ } else {
+ write_c0_brcm_bootvec((read_c0_brcm_bootvec() & mask) |
+ (val << shift));
+ }
+ }
+ preempt_enable();
+}
+
+static void bmips_set_reset_vec(int cpu, u32 val)
+{
+ struct reset_vec_info info;
+
+ if (current_cpu_type() == CPU_BMIPS5000) {
+ /* this needs to run from CPU0 (which is always online) */
+ info.cpu = cpu;
+ info.val = val;
+ bmips_set_reset_vec_remote(&info);
+ } else {
+ void __iomem *cbr = BMIPS_GET_CBR();
+
+ if (cpu == 0)
+ __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
+ else {
+ if (current_cpu_type() != CPU_BMIPS4380)
+ return;
+ __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
+ }
+ }
+ __sync();
+ back_to_back_c0_hazard();
+}
+
void bmips_ebase_setup(void)
{
unsigned long new_ebase = ebase;
- void __iomem __maybe_unused *cbr;
BUG_ON(ebase != CKSEG0);
@@ -492,9 +547,7 @@ void bmips_ebase_setup(void)
* 0x8000_0400: normal vectors
*/
new_ebase = 0x80000400;
- cbr = BMIPS_GET_CBR();
- __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
- __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
+ bmips_set_reset_vec(0, RESET_FROM_KSEG0);
break;
case CPU_BMIPS5000:
/*
@@ -502,10 +555,8 @@ void bmips_ebase_setup(void)
* 0x8000_1000: normal vectors
*/
new_ebase = 0x80001000;
- write_c0_brcm_bootvec(0xa0088008);
+ bmips_set_reset_vec(0, RESET_FROM_KSEG0);
write_c0_ebase(new_ebase);
- if (max_cpus > 2)
- bmips_write_zscm_reg(0xa0, 0xa008a008);
break;
default:
return;
--
2.1.1
From: Jon Fraser <[email protected]>
BMIPS3300 processors do not have the hardware to support SMP, but with a
small tweak, the SMP ebase relocation code allows BMIPS3300-based
platforms to reuse the S2/S3 power management code from BMIPS4380-based
chips. Normally this is as simple as adding one line to prom_init():
board_ebase_setup = &bmips_ebase_setup;
Signed-off-by: Jon Fraser <[email protected]>
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/kernel/smp-bmips.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 8383fa4..887c3ea 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -541,6 +541,7 @@ void bmips_ebase_setup(void)
&bmips_smp_int_vec, 0x80);
__sync();
return;
+ case CPU_BMIPS3300:
case CPU_BMIPS4380:
/*
* 0x8000_0000: reset/NMI (initially in kseg1)
--
2.1.1
On some older BMIPS5200 (dual core / quad thread) platforms, the
PROM code set up CPU2/CPU3 so they would be started through an NMI
instead of through the ACTION register. But this was incompatible with
some power management features that were later added, so the scheme was
changed so that Linux is fully responsible for booting CPU2/CPU3.
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/kernel/smp-bmips.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 06bb5ed..4e56911 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -213,17 +213,7 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
set_c0_brcm_cmt_ctrl(0x01);
break;
case CPU_BMIPS5000:
- if (cpu & 0x01)
- write_c0_brcm_action(ACTION_BOOT_THREAD(cpu));
- else {
- /*
- * core N thread 0 was already booted; just
- * pulse the NMI line
- */
- bmips_write_zscm_reg(0x210, 0xc0000000);
- udelay(10);
- bmips_write_zscm_reg(0x210, 0x00);
- }
+ write_c0_brcm_action(ACTION_BOOT_THREAD(cpu));
break;
}
cpumask_set_cpu(cpu, &bmips_booted_mask);
--
2.1.1
Commit 078a55fc824c1 ("Delete __cpuinit/__CPUINIT usage from MIPS code")
removed our __CPUINIT directives, so now the ".previous" directives
are superfluous. Remove them.
Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/kernel/bmips_vec.S | 3 ---
1 file changed, 3 deletions(-)
diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S
index 290c23b..8649507 100644
--- a/arch/mips/kernel/bmips_vec.S
+++ b/arch/mips/kernel/bmips_vec.S
@@ -208,7 +208,6 @@ bmips_reset_nmi_vec_end:
END(bmips_reset_nmi_vec)
.set pop
- .previous
/***********************************************************************
* CPU1 warm restart vector (used for second and subsequent boots).
@@ -281,5 +280,3 @@ LEAF(bmips_enable_xks01)
jr ra
END(bmips_enable_xks01)
-
- .previous
--
2.1.1
This is the main peripheral IRQ controller on the BCM7xxx MIPS chips;
it has the following characteristics:
- 64 to 160+ level IRQs
- Atomic set/clear registers
- Reasonably predictable register layout (N status words, then N
mask status words, then N mask set words, then N mask clear words)
- SMP affinity supported on most systems
- Typically connected to MIPS IRQ 2,3,2,3 on CPUs 0,1,2,3
This driver registers one IRQ domain and one IRQ chip to cover all
instances of the block. Up to 4 instances of the block may appear, as
it supports 4-way IRQ affinity on BCM7435.
The same block exists on the ARM BCM7xxx chips, but typically the ARM GIC
is used instead. So this driver is primarily intended for MIPS STB chips.
Signed-off-by: Kevin Cernekee <[email protected]>
---
.../interrupt-controller/brcm,bcm7038-l1-intc.txt | 52 ++++
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-bcm7038-l1.c | 335 +++++++++++++++++++++
4 files changed, 393 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt
create mode 100644 drivers/irqchip/irq-bcm7038-l1.c
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt
new file mode 100644
index 0000000..cc217b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt
@@ -0,0 +1,52 @@
+Broadcom BCM7038-style Level 1 interrupt controller
+
+This block is a first level interrupt controller that is typically connected
+directly to one of the HW INT lines on each CPU. Every BCM7xxx set-top chip
+since BCM7038 has contained this hardware.
+
+Key elements of the hardware design include:
+
+- 64, 96, 128, or 160 incoming level IRQ lines
+
+- Most onchip peripherals are wired directly to an L1 input
+
+- A separate instance of the register set for each CPU, allowing individual
+ peripheral IRQs to be routed to any CPU
+
+- Atomic mask/unmask operations
+
+- No polarity/level/edge settings
+
+- No FIFO or priority encoder logic; software is expected to read all
+ 2-5 status words to determine which IRQs are pending
+
+Required properties:
+
+- compatible: should be "brcm,bcm7038-l1-intc"
+- reg: specifies the base physical address and size of the registers;
+ the number of supported IRQs is inferred from the size argument
+- interrupt-controller: identifies the node as an interrupt controller
+- #interrupt-cells: specifies the number of cells needed to encode an interrupt
+ source, should be 1.
+- interrupt-parent: specifies the phandle to the parent interrupt controller(s)
+ this one is cascaded from
+- interrupts: specifies the interrupt line(s) in the interrupt-parent controller
+ node; valid values depend on the type of parent interrupt controller
+
+If multiple reg ranges and interrupt-parent entries are present on an SMP
+system, the driver will allow IRQ SMP affinity to be set up through the
+/proc/irq/ interface. In the simplest possible configuration, only one
+reg range and one interrupt-parent is needed.
+
+Example:
+
+periph_intc: periph_intc@1041a400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x1041a400 0x30 0x1041a600 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+};
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index afdc1f3..84070c9 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -48,6 +48,11 @@ config ATMEL_AIC5_IRQ
select MULTI_IRQ_HANDLER
select SPARSE_IRQ
+config BCM7038_L1_IRQ
+ bool
+ select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+
config BCM7120_L2_IRQ
bool
select GENERIC_IRQ_CHIP
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index f0909d0..fca4af9 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
+obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o
obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o
obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o
diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c
new file mode 100644
index 0000000..d3b8c8b
--- /dev/null
+++ b/drivers/irqchip/irq-bcm7038-l1.c
@@ -0,0 +1,335 @@
+/*
+ * Broadcom BCM7038 style Level 1 interrupt controller driver
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ * Author: Kevin Cernekee
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/kconfig.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+#include <linux/irqchip/chained_irq.h>
+
+#include "irqchip.h"
+
+#define IRQS_PER_WORD 32
+#define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4)
+#define MAX_WORDS 8
+
+struct bcm7038_l1_cpu;
+
+struct bcm7038_l1_chip {
+ raw_spinlock_t lock;
+ unsigned int n_words;
+ struct irq_domain *domain;
+ struct bcm7038_l1_cpu *cpus[NR_CPUS];
+ u8 affinity[MAX_WORDS * IRQS_PER_WORD];
+};
+
+struct bcm7038_l1_cpu {
+ void __iomem *map_base;
+ u32 mask_cache[0];
+};
+
+/*
+ * STATUS/MASK_STATUS/MASK_SET/MASK_CLEAR are packed one right after another:
+ *
+ * 7038:
+ * 0x1000_1400: W0_STATUS
+ * 0x1000_1404: W1_STATUS
+ * 0x1000_1408: W0_MASK_STATUS
+ * 0x1000_140c: W1_MASK_STATUS
+ * 0x1000_1410: W0_MASK_SET
+ * 0x1000_1414: W1_MASK_SET
+ * 0x1000_1418: W0_MASK_CLEAR
+ * 0x1000_141c: W1_MASK_CLEAR
+ *
+ * 7445:
+ * 0xf03e_1500: W0_STATUS
+ * 0xf03e_1504: W1_STATUS
+ * 0xf03e_1508: W2_STATUS
+ * 0xf03e_150c: W3_STATUS
+ * 0xf03e_1510: W4_STATUS
+ * 0xf03e_1514: W0_MASK_STATUS
+ * 0xf03e_1518: W1_MASK_STATUS
+ * [...]
+ */
+
+static inline unsigned int reg_status(struct bcm7038_l1_chip *intc,
+ unsigned int word)
+{
+ return (0 * intc->n_words + word) * sizeof(u32);
+}
+
+static inline unsigned int reg_mask_status(struct bcm7038_l1_chip *intc,
+ unsigned int word)
+{
+ return (1 * intc->n_words + word) * sizeof(u32);
+}
+
+static inline unsigned int reg_mask_set(struct bcm7038_l1_chip *intc,
+ unsigned int word)
+{
+ return (2 * intc->n_words + word) * sizeof(u32);
+}
+
+static inline unsigned int reg_mask_clr(struct bcm7038_l1_chip *intc,
+ unsigned int word)
+{
+ return (3 * intc->n_words + word) * sizeof(u32);
+}
+
+static inline u32 l1_readl(void __iomem *reg)
+{
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ return ioread32be(reg);
+ else
+ return readl(reg);
+}
+
+static inline void l1_writel(u32 val, void __iomem *reg)
+{
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ iowrite32be(val, reg);
+ else
+ writel(val, reg);
+}
+
+static void bcm7038_l1_irq_handle(unsigned int irq, struct irq_desc *desc)
+{
+ struct bcm7038_l1_chip *intc = irq_desc_get_handler_data(desc);
+ struct bcm7038_l1_cpu *cpu;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned int idx;
+
+#ifdef CONFIG_SMP
+ cpu = intc->cpus[cpu_logical_map(smp_processor_id())];
+#else
+ cpu = intc->cpus[0];
+#endif
+
+ chained_irq_enter(chip, desc);
+
+ for (idx = 0; idx < intc->n_words; idx++) {
+ int base = idx * IRQS_PER_WORD;
+ unsigned long pending, flags;
+ int hwirq;
+
+ raw_spin_lock_irqsave(&intc->lock, flags);
+ pending = l1_readl(cpu->map_base + reg_status(intc, idx)) &
+ ~cpu->mask_cache[idx];
+ raw_spin_unlock_irqrestore(&intc->lock, flags);
+
+ for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
+ generic_handle_irq(irq_find_mapping(intc->domain,
+ base + hwirq));
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void __bcm7038_l1_unmask(struct irq_data *d, unsigned int cpu_idx)
+{
+ struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ u32 word = d->hwirq / IRQS_PER_WORD;
+ u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
+
+ intc->cpus[cpu_idx]->mask_cache[word] &= ~mask;
+ l1_writel(mask, intc->cpus[cpu_idx]->map_base +
+ reg_mask_clr(intc, word));
+}
+
+static void __bcm7038_l1_mask(struct irq_data *d, unsigned int cpu_idx)
+{
+ struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ u32 word = d->hwirq / IRQS_PER_WORD;
+ u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
+
+ intc->cpus[cpu_idx]->mask_cache[word] |= mask;
+ l1_writel(mask, intc->cpus[cpu_idx]->map_base +
+ reg_mask_set(intc, word));
+}
+
+static void bcm7038_l1_unmask(struct irq_data *d)
+{
+ struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&intc->lock, flags);
+ __bcm7038_l1_unmask(d, intc->affinity[d->hwirq]);
+ raw_spin_unlock_irqrestore(&intc->lock, flags);
+}
+
+static void bcm7038_l1_mask(struct irq_data *d)
+{
+ struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&intc->lock, flags);
+ __bcm7038_l1_mask(d, intc->affinity[d->hwirq]);
+ raw_spin_unlock_irqrestore(&intc->lock, flags);
+}
+
+static int bcm7038_l1_set_affinity(struct irq_data *d,
+ const struct cpumask *dest,
+ bool force)
+{
+ struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+ irq_hw_number_t hw = d->hwirq;
+ u32 word = hw / IRQS_PER_WORD;
+ u32 mask = BIT(hw % IRQS_PER_WORD);
+ unsigned int first_cpu = cpumask_any_and(dest, cpu_online_mask);
+ bool was_disabled;
+
+ raw_spin_lock_irqsave(&intc->lock, flags);
+
+ was_disabled = !!(intc->cpus[intc->affinity[hw]]->mask_cache[word] &
+ mask);
+ __bcm7038_l1_mask(d, intc->affinity[hw]);
+ intc->affinity[hw] = first_cpu;
+ if (!was_disabled)
+ __bcm7038_l1_unmask(d, first_cpu);
+
+ raw_spin_unlock_irqrestore(&intc->lock, flags);
+ return 0;
+}
+
+static int __init bcm7038_l1_init_one(struct device_node *dn,
+ unsigned int idx,
+ struct bcm7038_l1_chip *intc)
+{
+ struct resource res;
+ resource_size_t sz;
+ struct bcm7038_l1_cpu *cpu;
+ unsigned int i, n_words, parent_irq;
+
+ if (of_address_to_resource(dn, idx, &res))
+ return -EINVAL;
+ sz = resource_size(&res);
+ n_words = sz / REG_BYTES_PER_IRQ_WORD;
+
+ if (n_words > MAX_WORDS)
+ return -EINVAL;
+ else if (!intc->n_words)
+ intc->n_words = n_words;
+ else if (intc->n_words != n_words)
+ return -EINVAL;
+
+ cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32),
+ GFP_KERNEL);
+ if (!cpu)
+ return -ENOMEM;
+
+ cpu->map_base = ioremap(res.start, sz);
+ if (!cpu->map_base)
+ return -ENOMEM;
+
+ for (i = 0; i < n_words; i++) {
+ l1_writel(0xffffffff, cpu->map_base + reg_mask_set(intc, i));
+ cpu->mask_cache[i] = 0xffffffff;
+ }
+
+ parent_irq = irq_of_parse_and_map(dn, idx);
+ if (!parent_irq) {
+ pr_err("failed to map parent interrupt %d\n", parent_irq);
+ return -EINVAL;
+ }
+ irq_set_handler_data(parent_irq, intc);
+ irq_set_chained_handler(parent_irq, bcm7038_l1_irq_handle);
+
+ return 0;
+}
+
+static struct irq_chip bcm7038_l1_irq_chip = {
+ .name = "bcm7038-l1",
+ .irq_mask = bcm7038_l1_mask,
+ .irq_unmask = bcm7038_l1_unmask,
+ .irq_set_affinity = bcm7038_l1_set_affinity,
+};
+
+static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw_irq)
+{
+ irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq);
+ irq_set_chip_data(virq, d->host_data);
+ return 0;
+}
+
+static const struct irq_domain_ops bcm7038_l1_domain_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = bcm7038_l1_map,
+};
+
+int __init bcm7038_l1_of_init(struct device_node *dn,
+ struct device_node *parent)
+{
+ struct bcm7038_l1_chip *intc;
+ int idx, ret;
+
+ intc = kzalloc(sizeof(*intc), GFP_KERNEL);
+ if (!intc)
+ return -ENOMEM;
+
+ raw_spin_lock_init(&intc->lock);
+ for_each_possible_cpu(idx) {
+ ret = bcm7038_l1_init_one(dn, idx, intc);
+ if (ret < 0) {
+ if (idx)
+ break;
+ pr_err("failed to remap intc L1 registers\n");
+ goto out_free;
+ }
+ }
+
+ intc->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * intc->n_words,
+ &bcm7038_l1_domain_ops,
+ intc);
+ if (!intc->domain) {
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+
+ pr_info("registered BCM7038 L1 intc (mem: 0x%p, IRQs: %d)\n",
+ intc->cpus[0]->map_base, IRQS_PER_WORD * intc->n_words);
+
+ return 0;
+
+out_unmap:
+ for_each_possible_cpu(idx) {
+ struct bcm7038_l1_cpu *cpu = intc->cpus[idx];
+
+ if (cpu) {
+ if (cpu->map_base)
+ iounmap(cpu->map_base);
+ kfree(cpu);
+ }
+ }
+out_free:
+ kfree(intc);
+ return ret;
+}
+
+IRQCHIP_DECLARE(bcm7038_l1, "brcm,bcm7038-l1-intc", bcm7038_l1_of_init);
--
2.1.1
From: Dmitry Torokhov <[email protected]>
Return value of irq_of_parse_and_map() is unsigned int, with 0
indicating failure, so testing for negative result never works.
Signed-off-by: Dmitry Torokhov <[email protected]>
Acked-by: Florian Fainelli <[email protected]>
Tested-by: Kevin Cernekee <[email protected]>
---
drivers/irqchip/irq-bcm7120-l2.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
index e7c6155..8eec8e1 100644
--- a/drivers/irqchip/irq-bcm7120-l2.c
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -102,9 +102,9 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
unsigned int idx;
parent_irq = irq_of_parse_and_map(dn, irq);
- if (parent_irq < 0) {
+ if (!parent_irq) {
pr_err("failed to map interrupt %d\n", irq);
- return parent_irq;
+ return -EINVAL;
}
/* For multiple parent IRQs with multiple words, this looks like:
--
2.1.1
To date, all supported controllers have had the IRQEN register at offset
0x00 and the IRQSTAT register at 0x04. So in DT we would typically see
something like:
reg = <0xf0406800 0x8>;
We still want to support this format, but we also need to support cases
where IRQEN and IRQSTAT aren't adjacent. So, we will amend the driver to
accept an alternate format that looks like this:
reg = <0xf0406800 0x4 0xf0406804 0x4>;
i.e. if the first resource_size() == 4, assume that the first resource
points to IRQEN and that the next resource points to IRQSTAT. If the
first resource_size() == 8, retain the current behavior.
Signed-off-by: Kevin Cernekee <[email protected]>
---
.../interrupt-controller/brcm,bcm7120-l2-intc.txt | 5 +-
drivers/irqchip/irq-bcm7120-l2.c | 76 +++++++++++++++++-----
2 files changed, 63 insertions(+), 18 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
index bae1f21..e3b0cba 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
@@ -55,7 +55,10 @@ Required properties:
- compatible: should be "brcm,bcm7120-l2-intc"
- reg: specifies the base physical address and size of the registers;
multiple pairs may be specified, with the first pair handling IRQ offsets
- 0..31 and the second pair handling 32..63
+ 0..31 and the second pair handling 32..63. A register pair may be
+ specified as either <base 0x8>, where IRQEN lives at base+0x00 and
+ IRQSTAT lives at base+0x04, or <enreg 0x4 statreg 0x4>, where the
+ address of each register is listed independently.
- interrupt-controller: identifies the node as an interrupt controller
- #interrupt-cells: specifies the number of cells needed to encode an interrupt
source, should be 1.
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
index e8441ee..576a92b 100644
--- a/drivers/irqchip/irq-bcm7120-l2.c
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kconfig.h>
+#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -22,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/ioport.h>
#include <linux/irqdomain.h>
#include <linux/reboot.h>
#include <linux/bitops.h>
@@ -29,12 +31,8 @@
#include "irqchip.h"
-/* Register offset in the L2 interrupt controller */
-#define IRQEN 0x00
-#define IRQSTAT 0x04
-
#define MAX_WORDS 4
-#define MAX_MAPPINGS MAX_WORDS
+#define MAX_MAPPINGS (MAX_WORDS * 2)
#define IRQS_PER_WORD 32
struct bcm7120_l2_intc_data {
@@ -128,6 +126,61 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
return 0;
}
+static int __init bcm7120_l2_intc_map_regs(struct device_node *dn,
+ struct bcm7120_l2_intc_data *data)
+{
+ unsigned int idx, n_regs = 0, gc_idx = 0;
+ void __iomem *en_reg = NULL, *stat_reg = NULL;
+
+ for (idx = 0; n_regs < MAX_WORDS * 2; idx++) {
+ struct resource res;
+ resource_size_t sz;
+ void __iomem *map_base;
+
+ if (of_address_to_resource(dn, idx, &res))
+ break;
+ sz = resource_size(&res);
+ map_base = data->map_base[idx] = ioremap(res.start, sz);
+ if (!map_base)
+ return -EINVAL;
+
+ if (n_regs % 2 == 0) {
+ /* Accept either enable + status, or just enable:
+ * reg = <0x10000024 0x8>;
+ * reg = <0x10000024 0x4 0x1000002c 0x4>;
+ */
+ en_reg = map_base;
+ if (sz == 8) {
+ stat_reg = map_base + 0x04;
+ n_regs += 2;
+ } else if (sz == 4) {
+ n_regs += 1;
+ continue;
+ } else {
+ return -EINVAL;
+ }
+ } else {
+ /* If the last register was enable, we're looking
+ * for its corresponding status register
+ */
+ if (sz == 4) {
+ stat_reg = map_base;
+ n_regs += 1;
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ data->pair_base[gc_idx] = min(en_reg, stat_reg);
+ data->en_offset[gc_idx] = en_reg - data->pair_base[gc_idx];
+ data->stat_offset[gc_idx] = stat_reg - data->pair_base[gc_idx];
+ gc_idx++;
+ }
+
+ data->n_words = gc_idx;
+ return gc_idx ? 0 : -ENOENT;
+}
+
int __init bcm7120_l2_intc_of_init(struct device_node *dn,
struct device_node *parent)
{
@@ -144,18 +197,7 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
if (!data)
return -ENOMEM;
- for (idx = 0; idx < MAX_WORDS; idx++) {
- data->map_base[idx] = of_iomap(dn, idx);
- if (!data->map_base[idx])
- break;
-
- data->pair_base[idx] = data->map_base[idx];
- data->en_offset[idx] = IRQEN;
- data->stat_offset[idx] = IRQSTAT;
-
- data->n_words = idx + 1;
- }
- if (!data->n_words) {
+ if (bcm7120_l2_intc_map_regs(dn, data) < 0) {
pr_err("failed to remap intc L2 registers\n");
ret = -ENOMEM;
goto out_unmap;
--
2.1.1
From: Dmitry Torokhov <[email protected]>
Return value of irq_of_parse_and_map() is unsigned int, with 0
indicating failure, so testing for negative result never works.
Signed-off-by: Dmitry Torokhov <[email protected]>
Acked-by: Florian Fainelli <[email protected]>
Tested-by: Kevin Cernekee <[email protected]>
---
drivers/irqchip/irq-brcmstb-l2.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c
index 4aa653a..313c2c6 100644
--- a/drivers/irqchip/irq-brcmstb-l2.c
+++ b/drivers/irqchip/irq-brcmstb-l2.c
@@ -139,9 +139,9 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
writel(0xffffffff, data->base + CPU_CLEAR);
data->parent_irq = irq_of_parse_and_map(np, 0);
- if (data->parent_irq < 0) {
+ if (!data->parent_irq) {
pr_err("failed to find parent interrupt\n");
- ret = data->parent_irq;
+ ret = -EINVAL;
goto out_unmap;
}
--
2.1.1
On Saturday 15 November 2014 16:17:46 Kevin Cernekee wrote:
> +config BMIPS_MULTIPLATFORM
> + bool "Broadcom BCM33xx/BCM63xx/BCM7xxx multiplatform kernel"
> + select BOOT_RAW
> + select NO_EXCEPT_FILL
> + select USE_OF
> + select BUILTIN_DTB
> + select FW_CFE
> + select CEVT_R4K
> + select CSRC_R4K
> + select SYNC_R4K
> + select COMMON_CLK
> + select BCM7038_L1_IRQ
> + select BCM7120_L2_IRQ
> + select BRCMSTB_L2_IRQ
> + select IRQ_CPU
> + select RAW_IRQ_ACCESSORS
> + select DMA_NONCOHERENT
> + select SYS_SUPPORTS_32BIT_KERNEL
> + select SYS_SUPPORTS_LITTLE_ENDIAN
> + select SYS_SUPPORTS_BIG_ENDIAN
> + select SYS_SUPPORTS_HIGHMEM
> + select SYS_HAS_CPU_BMIPS3300
> + select SYS_HAS_CPU_BMIPS4350
> + select SYS_HAS_CPU_BMIPS4380
> + select SYS_HAS_CPU_BMIPS5000
> + select SWAP_IO_SPACE
> + select USB_EHCI_BIG_ENDIAN_DESC
> + select USB_EHCI_BIG_ENDIAN_MMIO
> + select USB_OHCI_BIG_ENDIAN_DESC
> + select USB_OHCI_BIG_ENDIAN_MMIO
You mentioned in another thread that all MMIO is byteswapped based on the
jumper setting. Should the USB options have an 'if CPU_BIG_ENDIAN'
behind them? I think it will still work in the current way, but when you
know that you have little-endian registers, it is more efficient
not to set these.
> + help
> + Build a multiplatform DT-based kernel image that boots on select
> + BCM33xx cable modem chips, BCM63xx DSL chips, and BCM7xxx set-top
> + box chips. Note that CONFIG_CPU_BIG_ENDIAN/CONFIG_CPU_LITTLE_ENDIAN
> + must be set appropriately for your board, and the dts/dtsi files may
> + require changes based on the system endianness.
>
Can you clarify the meaning of "multiplatform" here? I suspect you
mean that this is one platform that includes multiple SoCs that
are all made by the same manufacturer and based on the same CPU
core family, but it is still incompatible with other Vendor's SoCs
and with Broadcom MIPS SoCs that are based on 74K or other cores, right?
It's probably not a wrong description here, but for anybody reading this
who also works on ARM, it seems rather confusing because there,
"multiplatform" implies that the particular SoC can be built into a
generic kernel image that supports SoCs from any vendor whose platform
is also marked as "multiplatform", as long as the CPU architecture level
(v4/v5, or v6/v7, or v8) is the same.
Arnd
On Sun, Nov 16, 2014 at 1:24 PM, Arnd Bergmann <[email protected]> wrote:
> On Saturday 15 November 2014 16:17:46 Kevin Cernekee wrote:
>> +config BMIPS_MULTIPLATFORM
>> + bool "Broadcom BCM33xx/BCM63xx/BCM7xxx multiplatform kernel"
>> + select BOOT_RAW
>> + select NO_EXCEPT_FILL
>> + select USE_OF
>> + select BUILTIN_DTB
>> + select FW_CFE
>> + select CEVT_R4K
>> + select CSRC_R4K
>> + select SYNC_R4K
>> + select COMMON_CLK
>> + select BCM7038_L1_IRQ
>> + select BCM7120_L2_IRQ
>> + select BRCMSTB_L2_IRQ
>> + select IRQ_CPU
>> + select RAW_IRQ_ACCESSORS
>> + select DMA_NONCOHERENT
>> + select SYS_SUPPORTS_32BIT_KERNEL
>> + select SYS_SUPPORTS_LITTLE_ENDIAN
>> + select SYS_SUPPORTS_BIG_ENDIAN
>> + select SYS_SUPPORTS_HIGHMEM
>> + select SYS_HAS_CPU_BMIPS3300
>> + select SYS_HAS_CPU_BMIPS4350
>> + select SYS_HAS_CPU_BMIPS4380
>> + select SYS_HAS_CPU_BMIPS5000
>> + select SWAP_IO_SPACE
>> + select USB_EHCI_BIG_ENDIAN_DESC
>> + select USB_EHCI_BIG_ENDIAN_MMIO
>> + select USB_OHCI_BIG_ENDIAN_DESC
>> + select USB_OHCI_BIG_ENDIAN_MMIO
>
> You mentioned in another thread that all MMIO is byteswapped based on the
> jumper setting. Should the USB options have an 'if CPU_BIG_ENDIAN'
> behind them? I think it will still work in the current way, but when you
> know that you have little-endian registers, it is more efficient
> not to set these.
Right, it works OK this way because the USB_*_BIG_ENDIAN_* options
just allow the USB drivers to accept the "big-endian" DT property.
They don't actually force any endian swaps on their own.
I can add the extra condition if warranted. On an LE build it saves
about 19kB = 0.3% in .text:
$ size vmlinux vmlinux.orig
text data bss dec hex filename
5945044 6227964 263936 12436944 bdc5d0 vmlinux
5963924 6227964 263936 12455824 be0f90 vmlinux.orig
("data" includes an initramfs so it's huge, but removing it doesn't
impact the "text" column.)
At some point I'd also like to get the of_device_is_big_endian() patch
merged, and then use it to harmonize the way endian swapping works
across serial8250, libahci, and maybe USB. Depending on the
size/complexity impact and the level of passion surrounding the topic,
this might also involve getting rid of the compile-time optimizations,
or at least simplifying them down to a single option instead of 6.
>> + help
>> + Build a multiplatform DT-based kernel image that boots on select
>> + BCM33xx cable modem chips, BCM63xx DSL chips, and BCM7xxx set-top
>> + box chips. Note that CONFIG_CPU_BIG_ENDIAN/CONFIG_CPU_LITTLE_ENDIAN
>> + must be set appropriately for your board, and the dts/dtsi files may
>> + require changes based on the system endianness.
>>
>
> Can you clarify the meaning of "multiplatform" here? I suspect you
> mean that this is one platform that includes multiple SoCs that
> are all made by the same manufacturer and based on the same CPU
> core family, but it is still incompatible with other Vendor's SoCs
> and with Broadcom MIPS SoCs that are based on 74K or other cores, right?
Correct
> It's probably not a wrong description here, but for anybody reading this
> who also works on ARM, it seems rather confusing because there,
> "multiplatform" implies that the particular SoC can be built into a
> generic kernel image that supports SoCs from any vendor whose platform
> is also marked as "multiplatform", as long as the CPU architecture level
> (v4/v5, or v6/v7, or v8) is the same.
The BMIPS multiplatform kernel is intended to support any SoC based on
a 65nm/40nm/28nm BMIPS CPU. Strictly speaking, "BMIPS" isn't an
architecture level defined by imgtec, nor is it something that other
silicon vendors can currently offer. But the BMIPS CPUs do have their
own unique CP0 registers, DSP instruction set, errata, and ways of
handling SMP / cache maintenance / performance counters.
Outside of the CPU, the BCM63xx/BCM33xx/BCM7xxx register maps and
peripherals look pretty different, and the arch/mips/bmips code makes
almost zero assumptions about the rest of the chip if a DTB is passed
in from the bootloader. In this sense you can see the parallels to
CONFIG_ARCH_MULTI_Vx.
Prior to this work, these product lines have never been able to share
a common kernel image.
On Sunday 16 November 2014 14:12:44 Kevin Cernekee wrote:
> On Sun, Nov 16, 2014 at 1:24 PM, Arnd Bergmann <[email protected]> wrote:
> > On Saturday 15 November 2014 16:17:46 Kevin Cernekee wrote:
> >> +config BMIPS_MULTIPLATFORM
> >> + bool "Broadcom BCM33xx/BCM63xx/BCM7xxx multiplatform kernel"
> >> + select BOOT_RAW
> >> + select NO_EXCEPT_FILL
> >> + select USE_OF
> >> + select BUILTIN_DTB
> >> + select FW_CFE
> >> + select CEVT_R4K
> >> + select CSRC_R4K
> >> + select SYNC_R4K
> >> + select COMMON_CLK
> >> + select BCM7038_L1_IRQ
> >> + select BCM7120_L2_IRQ
> >> + select BRCMSTB_L2_IRQ
> >> + select IRQ_CPU
> >> + select RAW_IRQ_ACCESSORS
> >> + select DMA_NONCOHERENT
> >> + select SYS_SUPPORTS_32BIT_KERNEL
> >> + select SYS_SUPPORTS_LITTLE_ENDIAN
> >> + select SYS_SUPPORTS_BIG_ENDIAN
> >> + select SYS_SUPPORTS_HIGHMEM
> >> + select SYS_HAS_CPU_BMIPS3300
> >> + select SYS_HAS_CPU_BMIPS4350
> >> + select SYS_HAS_CPU_BMIPS4380
> >> + select SYS_HAS_CPU_BMIPS5000
> >> + select SWAP_IO_SPACE
> >> + select USB_EHCI_BIG_ENDIAN_DESC
> >> + select USB_EHCI_BIG_ENDIAN_MMIO
> >> + select USB_OHCI_BIG_ENDIAN_DESC
> >> + select USB_OHCI_BIG_ENDIAN_MMIO
> >
> > You mentioned in another thread that all MMIO is byteswapped based on the
> > jumper setting. Should the USB options have an 'if CPU_BIG_ENDIAN'
> > behind them? I think it will still work in the current way, but when you
> > know that you have little-endian registers, it is more efficient
> > not to set these.
>
> Right, it works OK this way because the USB_*_BIG_ENDIAN_* options
> just allow the USB drivers to accept the "big-endian" DT property.
> They don't actually force any endian swaps on their own.
>
> I can add the extra condition if warranted. On an LE build it saves
> about 19kB = 0.3% in .text:
>
> $ size vmlinux vmlinux.orig
> text data bss dec hex filename
> 5945044 6227964 263936 12436944 bdc5d0 vmlinux
> 5963924 6227964 263936 12455824 be0f90 vmlinux.orig
>
> ("data" includes an initramfs so it's huge, but removing it doesn't
> impact the "text" column.)
I think 19kb is worth it, though I was actually more interested in the
runtime overhead.
> At some point I'd also like to get the of_device_is_big_endian() patch
> merged, and then use it to harmonize the way endian swapping works
> across serial8250, libahci, and maybe USB. Depending on the
> size/complexity impact and the level of passion surrounding the topic,
> this might also involve getting rid of the compile-time optimizations,
> or at least simplifying them down to a single option instead of 6.
Yes, good idea.
> > It's probably not a wrong description here, but for anybody reading this
> > who also works on ARM, it seems rather confusing because there,
> > "multiplatform" implies that the particular SoC can be built into a
> > generic kernel image that supports SoCs from any vendor whose platform
> > is also marked as "multiplatform", as long as the CPU architecture level
> > (v4/v5, or v6/v7, or v8) is the same.
>
> The BMIPS multiplatform kernel is intended to support any SoC based on
> a 65nm/40nm/28nm BMIPS CPU. Strictly speaking, "BMIPS" isn't an
> architecture level defined by imgtec, nor is it something that other
> silicon vendors can currently offer. But the BMIPS CPUs do have their
> own unique CP0 registers, DSP instruction set, errata, and ways of
> handling SMP / cache maintenance / performance counters.
Ok, I see. It looks like you can have a combined kernel that runs on
BMIPS BCM47xx and MIPS32r2 74K BCM47xx already, right?
So it's not fundamentally incompatible with the other platforms?
> Outside of the CPU, the BCM63xx/BCM33xx/BCM7xxx register maps and
> peripherals look pretty different, and the arch/mips/bmips code makes
> almost zero assumptions about the rest of the chip if a DTB is passed
> in from the bootloader. In this sense you can see the parallels to
> CONFIG_ARCH_MULTI_Vx.
>
> Prior to this work, these product lines have never been able to share
> a common kernel image.
I still think this is different in the sense that ARM multiplatform
support is about combining platforms from separate mach-* directories,
while your approach was to rewrite multiple mach-* directories into
a single new one that remains separate from the others. While this is
a great improvement, it doesn't get you any closer to having a
combined BMIPS+RALINK+JZ4740+ATH79 kernel for instance. I don't know
if such a kernel is something that anybody wants, or if it's even
technically possible.
If you wanted to do that however, starting with BMIPS you'd have
to make it possible to define a new platform without the
arch/mips/include/asm/mach-bmips/ directory (this should be possible
already, so the hardest part is done), replace all global function
calls (arch_init_irq, prom_init, get_system_type, ...) with generic
platform-independent implementations or wrappers around per-platform
callbacks, and move the Kconfig section for CONFIG_BMIPS_MULTIPLATFORM
outside of the "System type" choice statement.
Until you do that, your platform isn't "more multipliplatform" than
the others really, it just abstracts the differences between some
SoCs nicer than most.
Arnd
Hi,
On Sun, Nov 16, 2014 at 1:17 AM, Kevin Cernekee <[email protected]> wrote:
> bmips_be_defconfig supports Linux running on the following CM and DSL
> SoCs:
>
> - BCM3384 (BMIPS5000) cable modem application processor, BE, SMP
> - BCM3384 (BMIPS4355) cable modem "spare CPU"*, BE
> - BCM6328 (BMIPS4355) ADSL chip, BE
Is BMIPS435*5* intentional? I would have assumed at least 6328 is also
MIPS4350 like BCM6368.
> - BCM6368 (BMIPS4350) ADSL chip, BE, SMP
>
> *experimental; most configurations will require changing CONFIG_PHYSICAL_START
>
> bmips_stb_defconfig supports Linux running on the (nominally LE) STB
> chipsets:
>
> - BCM7125 (BMIPS4380) set-top box chip, LE, SMP
> - BCM7346 (BMIPS5000) set-top box chip, LE, SMP
> - BCM7360 (BMIPS3300) set-top box chip, LE
> - BCM7420 (BMIPS5000) set-top box chip, LE, SMP
> - BCM7425 (BMIPS5000) set-top box chip, LE, SMP
>
> serial8250 and bcm63xx_uart do not currently coexist. If/when this is
> fixed, it will be also possible to boot the BE image on any supported STB
> board configured for BE. For now, each defconfig can only pick one UART
> driver, and the BE defconfig enables bcm63xx_uart.
>
> On these MIPS systems, endianness cannot be reconfigured at runtime. On
> STB it is sometimes offered as a board jumper or 0-ohm resistor, and
> sometimes hardwired to LE only. The CM and DSL systems always run BE.
>
> Device Tree is used to configure the following items:
>
> - UART, USB, GENET peripherals
> - IRQ controllers
> - Early console base address (bcm63xx_uart only)
> - SMP or UP mode
> - MIPS counter frequency
> - Memory size / regions
> - DMA remappings
> - Kernel command line
>
> The DT-enabled bootloader and build instructions for 3384 are posted at
> https://github.com/Broadcom/aeolus . The other chips use legacy non-DT
> bootloaders, and so the kernel employs autodetection heuristics to select
> a builtin DTB.
>
> Signed-off-by: Kevin Cernekee <[email protected]>
This looks nice, and I think I agree with a new target instead of
trying to retrofit all the dtb/SoC support into bcm63xx.
Some individual comments here because I'm too lazy to search for the
introducing patches (more meant as general commentary than nitpicks).
(snip)
> diff --git a/Documentation/devicetree/bindings/mips/brcm/bmips.txt b/Documentation/devicetree/bindings/mips/brcm/bmips.txt
> new file mode 100644
> index 0000000..4a8cd8f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mips/brcm/bmips.txt
> @@ -0,0 +1,8 @@
> +* Broadcom MIPS (BMIPS) CPUs
> +
> +Required properties:
> +- compatible: "brcm,bmips3300", "brcm,bmips4350", "brcm,bmips4380"
> + "brcm,bmips5000"
> +
> +- mips-hpt-frequency: This is common to all CPUs in the system so it lives
> + under the "cpus" node.
Is it a good idea to hardcode this? Some SoC CPUs allow running with
different frequencies, which will directly affect this. Also I would
assume this would break once we add support for runtime clock changes
for BMIPS; at least on the DSL platform you can change the clock
between 1/4 (IIRC) and 1/1 for power saving.
> diff --git a/Documentation/devicetree/bindings/mips/brcm/soc.txt b/Documentation/devicetree/bindings/mips/brcm/soc.txt
> new file mode 100644
> index 0000000..1eedcb8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mips/brcm/soc.txt
> @@ -0,0 +1,21 @@
> +* Broadcom cable/DSL/settop platforms
> +
> +SoCs:
> +
> +Required properties:
> +- compatible: "brcm,bcm3384", "brcm,bcm33843"
> + "brcm,bcm3384-viper", "brcm,bcm33843-viper"
> + "brcm,bcm6328", "brcm,bcm6368",
> + "brcm,bcm7125", "brcm,bcm7346", "brcm,bcm7360",
> + "brcm,bcm7420", "brcm,bcm7425"
> +
> +Boards:
> +
> +Required properties:
> +- compatible: "brcm,bcm93384wvg", "brcm,bcm93384wvg-viper"
> + "brcm,bcm9ejtagprb", "brcm,bcm96368mvwg",
> + "brcm,bcm97125cbmb", "brcm,bcm97346dbsmb", "brcm,bcm97360svmb",
> + "brcm,bcm97420c", "brcm,bcm97425svmb"
Should the list of supported boards really be hardcoded here/in the
kernel? It doesn't match what the code does, as it (as far as I can
tell) accepts dtbs without any of the board compatible ids when passed
from bootloader.
> +
> +The experimental -viper variants are for running Linux on the 3384's
> +BMIPS4355 cable modem CPU instead of the BMIPS5000 application processor.
(snip)
> diff --git a/arch/mips/bmips/irq.c b/arch/mips/bmips/irq.c
> new file mode 100644
> index 0000000..14552e5
> --- /dev/null
> +++ b/arch/mips/bmips/irq.c
> @@ -0,0 +1,38 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation.
> + *
> + * Copyright (C) 2014 Broadcom Corporation
> + * Author: Kevin Cernekee <[email protected]>
> + */
> +
> +#include <linux/of.h>
> +#include <linux/irqchip.h>
> +
> +#include <asm/bmips.h>
> +#include <asm/irq.h>
> +#include <asm/irq_cpu.h>
> +#include <asm/time.h>
> +
> +unsigned int get_c0_compare_int(void)
> +{
> + return CP0_LEGACY_COMPARE_IRQ;
> +}
> +
> +void __init arch_init_irq(void)
> +{
> + struct device_node *dn;
> +
> + /* Only the STB (bcm7038) controller supports SMP IRQ affinity */
> + dn = of_find_compatible_node(NULL, NULL, "brcm,bcm7038-l1-intc");
> + if (dn)
> + of_node_put(dn);
> + else
> + bmips_tp1_irqs = 0;
> +
> + irqchip_init();
> +}
> +
> +OF_DECLARE_2(irqchip, mips_cpu_intc, "mti,cpu-interrupt-controller",
> + mips_cpu_irq_of_init);
> diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c
> new file mode 100644
> index 0000000..c34601d
> --- /dev/null
> +++ b/arch/mips/bmips/setup.c
> @@ -0,0 +1,249 @@
> +/*
> + * 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
> + * for more details.
> + *
> + * Copyright (C) 2014 Broadcom Corporation
> + * Author: Kevin Cernekee <[email protected]>
> + */
> +
> +#include <linux/init.h>
> +#include <linux/bitops.h>
> +#include <linux/bootmem.h>
> +#include <linux/clk-provider.h>
> +#include <linux/ioport.h>
> +#include <linux/kernel.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/of_platform.h>
> +#include <linux/smp.h>
> +#include <asm/addrspace.h>
> +#include <asm/bmips.h>
> +#include <asm/bootinfo.h>
> +#include <asm/cpu-type.h>
> +#include <asm/mipsregs.h>
> +#include <asm/prom.h>
> +#include <asm/smp-ops.h>
> +#include <asm/time.h>
> +#include <asm/traps.h>
> +#include <asm/fw/cfe/cfe_api.h>
> +
> +#define CMT_LOCAL_TPID BIT(31)
> +#define RELO_NORMAL_VEC BIT(18)
> +
> +#define REG_DSL_CHIP_ID ((void __iomem *)CKSEG1ADDR(0x10000000))
> +#define REG_STB_CHIP_ID ((void __iomem *)CKSEG1ADDR(0x10404000))
> +
> +#define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c))
> +#define BCM6328_TP1_DISABLED BIT(9)
> +
> +static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000;
> +
> +struct bmips_board_list {
> + void *dtb;
> + u32 chip_id;
> + const char *boardname;
> + void (*quirk_fn)(void);
> +};
> +
> +extern char __dtb_bcm9ejtagprb_begin;
> +extern char __dtb_bcm96368mvwg_begin;
> +extern char __dtb_bcm97125cbmb_begin;
> +extern char __dtb_bcm97346dbsmb_begin;
> +extern char __dtb_bcm97360svmb_begin;
> +extern char __dtb_bcm97420c_begin;
> +extern char __dtb_bcm97425svmb_begin;
I think it would be a good idea to have the embedded dtbs optional,
especially if you already provide an interface for passing a dtb
pointer.
> +
> +static void kbase_setup(void)
> +{
> + __raw_writel(kbase | RELO_NORMAL_VEC,
> + BMIPS_GET_CBR() + BMIPS_RELO_VECTOR_CONTROL_1);
> + ebase = kbase;
> +}
> +
> +static void bcm3384_quirks(void)
> +{
> + /*
> + * Some experimental CM boxes are set up to let CM own the Viper TP0
> + * and let Linux own TP1. This requires moving the kernel
> + * load address to a non-conflicting region (e.g. via
> + * CONFIG_PHYSICAL_START) and supplying an alternate DTB.
> + * If we detect this condition, we need to move the MIPS exception
> + * vectors up to an area that we own.
> + *
> + * This is distinct from the OTHER special case mentioned in
> + * smp-bmips.c (boot on TP1, but enable SMP, then TP0 becomes our
> + * logical CPU#1). For the Viper TP1 case, SMP is off limits.
> + *
> + * Also note that many BMIPS435x CPUs do not have a
> + * BMIPS_RELO_VECTOR_CONTROL_1 register, so it isn't safe to just
> + * write VMLINUX_LOAD_ADDRESS into that register on every SoC.
> + */
> + if (current_cpu_type() == CPU_BMIPS4350 &&
> + kbase != CKSEG0 &&
> + read_c0_brcm_cmt_local() & CMT_LOCAL_TPID) {
> + board_ebase_setup = &kbase_setup;
> + bmips_smp_enabled = 0;
> + }
> +}
> +
> +static void bcm6328_quirks(void)
> +{
> + /* Check OTP to see if CPU1 is enabled (it usually isn't) */
> + if (__raw_readl(REG_BCM6328_OTP) & BCM6328_TP1_DISABLED)
> + bmips_smp_enabled = 0;
> +}
> +
> +static void bcm6368_quirks(void)
> +{
> + /*
> + * The bootloader has set up the CPU1 reset vector at
> + * 0xa000_0200.
> + * This conflicts with the special interrupt vector (IV).
> + * The bootloader has also set up CPU1 to respond to the wrong
> + * IPI interrupt.
> + * Here we will start up CPU1 in the background and ask it to
> + * reconfigure itself then go back to sleep.
> + */
> + memcpy((void *)0xa0000200, &bmips_smp_movevec, 0x20);
> + __sync();
> + set_c0_cause(C_SW0);
> + cpumask_set_cpu(1, &bmips_booted_mask);
> +}
> +
> +static const struct bmips_board_list bmips_board_list[] = {
> + { &__dtb_bcm9ejtagprb_begin, 0x6328, NULL, &bcm6328_quirks },
> + { &__dtb_bcm96368mvwg_begin, 0x6368, NULL, &bcm6368_quirks },
> + { &__dtb_bcm97125cbmb_begin, 0x7125, "BCM97125C0" },
> + { &__dtb_bcm97346dbsmb_begin, 0x7346, "BCM97346DBSMB" },
> + { &__dtb_bcm97360svmb_begin, 0x7360, "BCM97360SVMB" },
> + { &__dtb_bcm97420c_begin, 0x7420, "BCM97420C_DDR3" },
> + { &__dtb_bcm97425svmb_begin, 0x7425, "BCM97425SVMB" },
> + { },
> +};
> +
> +void __init prom_init(void)
> +{
> + register_bmips_smp_ops();
> +}
> +
> +void __init prom_free_prom_memory(void)
> +{
> +}
> +
> +const char *get_system_type(void)
> +{
> + return "BMIPS multiplatform kernel";
> +}
> +
> +void __init plat_time_init(void)
> +{
> + struct device_node *np;
> + u32 freq;
> +
> + np = of_find_node_by_name(NULL, "cpus");
> + if (!np)
> + panic("missing 'cpus' DT node");
> + if (of_property_read_u32(np, "mips-hpt-frequency", &freq) < 0)
> + panic("missing 'mips-hpt-frequency' property");
> + of_node_put(np);
> +
> + mips_hpt_frequency = freq;
> +}
> +
> +static void __init *find_dtb(void)
> +{
> + u32 chip_id;
> + char boardname[64] = "";
> + const struct bmips_board_list *b;
> +
> + /* Intended to somewhat resemble ARM; see Documentation/arm/Booting */
> + if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
> + return phys_to_virt(fw_arg2);
I know a bit late, but how about using the OF_DT_MAGIC (0xd00dfeed)
for indicating that there is a device tree in arg2?
> +
> + if (fw_arg1 != 0 || fw_arg3 != CFE_EPTSEAL ||
> + (fw_arg2 & 0xf0000000) != CKSEG0)
> + panic("cannot identify chip");
> +
> + /*
> + * Unfortunately the CFE API doesn't seem to provide chip
> + * identification, but we can check the entry point to see whether
> + * the current platform is a DSL chip or STB chip. On STB,
> + * CAE_STKSIZE = _regidx(13) = 13*8 = 104, so the first instruction is:
> + * 0: 23bdff98 addi sp,sp,-104
> + */
> + if (__raw_readl((void *)fw_arg2) == 0x23bdff98) {
> + chip_id = __raw_readl(REG_STB_CHIP_ID);
> + cfe_init(fw_arg0, fw_arg2);
> + cfe_getenv("CFE_BOARDNAME", boardname, sizeof(boardname));
> + } else {
> + /*
> + * This works on most modern chips, but will break on older
> + * ones like 6358
> + */
> + chip_id = __raw_readl(REG_DSL_CHIP_ID);
Unfortunately I don't know any good way to discriminate between the
"old" and the "new" chips except by looking a the PRID and REV
(BMIPS3300 <= 3.2 || BMIPS4350 <= 1.0 => 0xfff00000, BMIPS3300 >= 3.3
|| BMIPS4350 >= 3.0 => 0xb0000000).
> + }
> +
> + /* 4-digit parts use bits [31:16]; 5-digit parts use [27:8] */
This might be true for the STB chips, but the DSL 5-digit parts use
[31:12]. And to add insult to insury, some 4-digit parts use [15:12]
for the chip variant, so you can't just check [15:12] for 0 or != 0
either (I would assume 63381 and 6328 (variant 63281) will have both 1
at [15:12].
> + if (chip_id & 0xf0000000)
> + chip_id >>= 16;
> + else
> + chip_id >>= 8;
> +
> + for (b = bmips_board_list; b->dtb; b++) {
> + if (b->chip_id != chip_id)
> + continue;
> + if (b->boardname && strcmp(b->boardname, boardname))
> + continue;
> + if (b->quirk_fn)
> + b->quirk_fn();
Hmm, maybe move running the quirk out of here and into
plat_mem_setup()? Currently e.g. a BCM6328 with a bootloader passed
dtb won't have its quirk run.
> + return b->dtb;
> + }
> +
> + panic("no dtb found for current board");
> +}
> +
> +void __init plat_mem_setup(void)
> +{
> + set_io_port_base(0);
> + ioport_resource.start = 0;
> + ioport_resource.end = ~0;
> +
> + __dt_setup_arch(find_dtb());
> + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
> +
> + /* BCM3384 DTB comes from the bootloader, not from bmips_board_list */
> + if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
> + "brcm,bcm3384-viper")) {
> + bcm3384_quirks();
> + }
> +}
> +
> +void __init device_tree_init(void)
> +{
> + struct device_node *np;
> +
> + unflatten_and_copy_device_tree();
> +
> + /* Disable SMP boot unless both CPUs are listed in DT and !disabled */
> + np = of_find_node_by_name(NULL, "cpus");
> + if (np && of_get_available_child_count(np) <= 1)
> + bmips_smp_enabled = 0;
> + of_node_put(np);
> +}
> +
> +int __init plat_of_setup(void)
> +{
> + return __dt_register_buses("brcm,bmips", "simple-bus");
Huh, "brcm,bmips" does not appear anywhere else. How does this work?
Should this be a required compatible?
(OT: "buses" irks me because in my native tongue the plural uses "ss",
but I accept that using one "s" is also a valid spelling in english
:P)
> +}
> +
> +arch_initcall(plat_of_setup);
> +
> +static int __init plat_dev_init(void)
> +{
> + of_clk_init(NULL);
> + return 0;
> +}
> +
> +device_initcall(plat_dev_init);
> diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile
> index ca9c90e..ffae96b 100644
> --- a/arch/mips/boot/dts/Makefile
> +++ b/arch/mips/boot/dts/Makefile
> @@ -1,3 +1,12 @@
> +dtb-$(CONFIG_BMIPS_MULTIPLATFORM) += bcm93384wvg.dtb \
Minor stilistic nitpick: I would use
dtb-$(CONFIG_BMIPS_MULTIPLATFORM) += \
bcm93384wvg.dtb \
so that adding a board before bcm963384wvg would only require an
insert, not also a modification.
> + bcm93384wvg_viper.dtb \
> + bcm96368mvwg.dtb \
> + bcm9ejtagprb.dtb \
> + bcm97125cbmb.dtb \
> + bcm97346dbsmb.dtb \
> + bcm97360svmb.dtb \
> + bcm97420c.dtb \
> + bcm97425svmb.dtb
> dtb-$(CONFIG_CAVIUM_OCTEON_SOC) += octeon_3xxx.dtb octeon_68xx.dtb
> dtb-$(CONFIG_DT_EASY50712) += easy50712.dtb
> dtb-$(CONFIG_DT_XLP_EVP) += xlp_evp.dtb
> diff --git a/arch/mips/boot/dts/bcm3384_common.dtsi b/arch/mips/boot/dts/bcm3384_common.dtsi
> new file mode 100644
> index 0000000..448cb5b
> --- /dev/null
> +++ b/arch/mips/boot/dts/bcm3384_common.dtsi
> @@ -0,0 +1,44 @@
> +/ {
> + clocks {
> + #address-cells = <1>;
This does not really make sense, as there is no address used at all
for the periph_clk.
> + #size-cells = <0>;
> +
> + periph_clk: periph_clk@0 {
Same for the @0 - there is no appropriate reg = <0>, so using an
address here does not make sense.
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <54000000>;
> + };
> + };
> +
> + aliases {
> + uart0 = &uart0;
> + };
> +
> + uart0: serial@14e00520 {
> + compatible = "brcm,bcm6345-uart";
> + reg = <0x14e00520 0x18>;
> + interrupt-parent = <&periph_intc>;
> + interrupts = <2>;
> + clocks = <&periph_clk>;
> + status = "disabled";
> + };
> +
> + ehci0: usb@15400300 {
> + compatible = "brcm,bcm3384-ehci", "generic-ehci";
> + reg = <0x15400300 0x100>;
> + big-endian;
> + interrupt-parent = <&periph_intc>;
> + interrupts = <41>;
> + status = "disabled";
> + };
> +
> + ohci0: usb@15400400 {
> + compatible = "brcm,bcm3384-ohci", "generic-ohci";
> + reg = <0x15400400 0x100>;
> + big-endian;
> + no-big-frame-no;
> + interrupt-parent = <&periph_intc>;
> + interrupts = <40>;
> + status = "disabled";
> + };
> +};
(snip)
> diff --git a/arch/mips/boot/dts/bcm6328.dtsi b/arch/mips/boot/dts/bcm6328.dtsi
> new file mode 100644
> index 0000000..a7e397f
> --- /dev/null
> +++ b/arch/mips/boot/dts/bcm6328.dtsi
> @@ -0,0 +1,63 @@
> +/ {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "brcm,bcm6328";
> +
> + cpus {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + mips-hpt-frequency = <160000000>;
> +
> + cpu@0 {
> + compatible = "brcm,bmips4350";
> + device_type = "cpu";
> + reg = <0>;
> + };
Since there are SMP-enabled variants, maybe it should have its second
thread documented here (but defaulting to "disabled")?
> + };
> +
> + clocks {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + periph_clk: periph_clk@0 {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <50000000>;
> + };
> + };
> +
> + aliases {
> + uart0 = &uart0;
> + };
> +
> + cpu_intc: cpu_intc@0 {
It does not have an address, so it should not have @0 in the node name I think.
> + #address-cells = <0>;
> + compatible = "mti,cpu-interrupt-controller";
> +
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> +
> + periph_intc: periph_intc@10000024 {
> + compatible = "brcm,bcm7120-l2-intc";
> + reg = <0x10000024 0x4 0x1000002c 0x4
> + 0x10000020 0x4 0x10000028 0x4>;
The "lowest" register address you use is 0x10000020, so the name
should arguably be periph_intc@10000020, not periph_intc@10000024. I
guess the second cpu block (10000030 - 1000003c) wired to hw irq 3 can
be added later.
This will easily translate to a lot of io(re)map calls in case of
63268/6318 when describing both cpu blocks ( a total of 16 "reg"s).
Also I wonder how you properly describe the intc of 63381, where it
has separate mask registers, but a shared status register.
> +
> + interrupt-controller;
> + #interrupt-cells = <1>;
> +
> + interrupt-parent = <&cpu_intc>;
> + interrupts = <2>;
> + brcm,int-map-mask = <0xffffffff 0xffffffff>;
> + };
> +
> + uart0: serial@10000100 {
> + compatible = "brcm,bcm6345-uart";
> + reg = <0x10000100 0x18>;
> + interrupt-parent = <&periph_intc>;
> + interrupts = <28>;
> + clocks = <&periph_clk>;
> + status = "disabled";
> + };
> +};
(snip)
Jonas
On Mon, Nov 17, 2014 at 1:16 PM, Arnd Bergmann <[email protected]> wrote:
> I still think this is different in the sense that ARM multiplatform
> support is about combining platforms from separate mach-* directories,
> while your approach was to rewrite multiple mach-* directories into
> a single new one that remains separate from the others. While this is
> a great improvement, it doesn't get you any closer to having a
> combined BMIPS+RALINK+JZ4740+ATH79 kernel for instance. I don't know
> if such a kernel is something that anybody wants, or if it's even
> technically possible.
>
> If you wanted to do that however, starting with BMIPS you'd have
> to make it possible to define a new platform without the
> arch/mips/include/asm/mach-bmips/ directory (this should be possible
> already, so the hardest part is done), replace all global function
> calls (arch_init_irq, prom_init, get_system_type, ...) with generic
> platform-independent implementations or wrappers around per-platform
> callbacks, and move the Kconfig section for CONFIG_BMIPS_MULTIPLATFORM
> outside of the "System type" choice statement.
> Until you do that, your platform isn't "more multipliplatform" than
> the others really, it just abstracts the differences between some
> SoCs nicer than most.
I guess a big blocker for such a real mips multiplatform kernel is
that there is still no defined (standard) interface for passing a
device tree to the kernel from the bootlader on mips, unlike on arm
(at least I'm not aware of any). And unless there is one, having a
multiplatform kernel does not make much sense, as there is no sane way
to tell apart different platforms on boot. But maybe we should just
define a way, and require new platforms to use it ;-)
Jonas
On Monday 17 November 2014 15:52:15 Jonas Gorski wrote:
> On Mon, Nov 17, 2014 at 1:16 PM, Arnd Bergmann <[email protected]> wrote:
> > I still think this is different in the sense that ARM multiplatform
> > support is about combining platforms from separate mach-* directories,
> > while your approach was to rewrite multiple mach-* directories into
> > a single new one that remains separate from the others. While this is
> > a great improvement, it doesn't get you any closer to having a
> > combined BMIPS+RALINK+JZ4740+ATH79 kernel for instance. I don't know
> > if such a kernel is something that anybody wants, or if it's even
> > technically possible.
> >
> > If you wanted to do that however, starting with BMIPS you'd have
> > to make it possible to define a new platform without the
> > arch/mips/include/asm/mach-bmips/ directory (this should be possible
> > already, so the hardest part is done), replace all global function
> > calls (arch_init_irq, prom_init, get_system_type, ...) with generic
> > platform-independent implementations or wrappers around per-platform
> > callbacks, and move the Kconfig section for CONFIG_BMIPS_MULTIPLATFORM
> > outside of the "System type" choice statement.
> > Until you do that, your platform isn't "more multipliplatform" than
> > the others really, it just abstracts the differences between some
> > SoCs nicer than most.
>
> I guess a big blocker for such a real mips multiplatform kernel is
> that there is still no defined (standard) interface for passing a
> device tree to the kernel from the bootlader on mips, unlike on arm
> (at least I'm not aware of any).
There are a few things to be worked out, I don't think this one is
particularly hard. Looking through the list of public symbols:
* arch/mips/bmips/dma.c,
arch/mips/include/asm/mach-bmips/dma-coherence.h:
plat_map_dma_mem
plat_map_dma_mem_page
plat_dma_addr_to_phys
plat_unmap_dma_mem
This should really be done in a generic way: What Kevin's patch
does here is to hardcode a mapping of DMA addresses. We have a way
to express this in DT in a generic manner, using the dma-ranges
property (currently not parsed completely on ARM yet, working on
it, but we don't have that many special cases on modern platforms).
Once you have the correct dma-ranges set and the code parses them
properly, the bmips specific code could just go away, and someone
has to do this already to support the ARM based bcm platforms I
suspect.
*arch/mips/bmips/irq.c:
get_c0_compare_int
arch_init_irq
I don't completely understand this code, but I think once the irqchips
all use irqdomains correctly and the code is moved to drivers/irqchip,
this can also go away. There is already code to override
get_c0_compare_int().
* arch/mips/include/asm/mach-bmips/war.h
Very few platforms actually set any of the workarounds, so I guess the
file setting them all to zero could just be moved to
arch/mips/include/asm/mach-generic/.
prom_init
prom_free_prom_memory
get_system_type
plat_time_init
find_dtb
plat_mem_setup
device_tree_init
plat_of_setup
plat_dev_init
This is not just DT, it's actually an implementation of a boot
interface. The situation here seems much more to what we had on
PowerPC a long time ago than what we had on ARM before the DT
conversion. I think the best approach here would be to move the
platform specific bits into the decompressor code, and allow
multiple implementations of that. This way you can have the
generic vmlinux file that has a common DT parser, and you wrap
that into one decompressor per platform, some of which can have
their own board detection logic or pre-boot setup where necessary.
To be honest, I think having multiple DT files linked into the
kernel is a really bad idea, because it doesn't solve the
scalability problem at all. What we did on ARM was to force those
hacks out into external projects such as the PXA impedence
matcher [https://github.com/zonque/pxa-impedance-matcher]. This
can handle all weird boot protocol and adapt them to the normal
well-defined interfaces we have in the kernel.
> And unless there is one, having a
> multiplatform kernel does not make much sense, as there is no sane way
> to tell apart different platforms on boot.
How do you normally tell boards apart on MIPS when you don't use DT?
Arnd
On Mon, Nov 17, 2014 at 4:16 AM, Arnd Bergmann <[email protected]> wrote:
>> > It's probably not a wrong description here, but for anybody reading this
>> > who also works on ARM, it seems rather confusing because there,
>> > "multiplatform" implies that the particular SoC can be built into a
>> > generic kernel image that supports SoCs from any vendor whose platform
>> > is also marked as "multiplatform", as long as the CPU architecture level
>> > (v4/v5, or v6/v7, or v8) is the same.
>>
>> The BMIPS multiplatform kernel is intended to support any SoC based on
>> a 65nm/40nm/28nm BMIPS CPU. Strictly speaking, "BMIPS" isn't an
>> architecture level defined by imgtec, nor is it something that other
>> silicon vendors can currently offer. But the BMIPS CPUs do have their
>> own unique CP0 registers, DSP instruction set, errata, and ways of
>> handling SMP / cache maintenance / performance counters.
>
> Ok, I see. It looks like you can have a combined kernel that runs on
> BMIPS BCM47xx and MIPS32r2 74K BCM47xx already, right?
Under arch/mips/bcm47xx I see a single mach type, but different builds
for BMIPS3300 (R1/SSB) versus MIPS 74K (R2/BCMA).
> So it's not fundamentally incompatible with the other platforms?
Relative to BMIPS43xx/BMIPS5x00, the BMIPS3300 CPU found in the older
BCM47xx chips requires fewer quirks and can be treated more like a
standard R4K by the OS:
- No SMP boot/IPI helpers are needed
- Cache maintenance is pretty straightforward (but some chips do have the RAC)
- No L2 or HW cache de-aliasing logic or weird instruction barriers
- No XI/ROR support
- Don't know about errata (BCM47xx uses the old 130nm/180nm cores)
OTOH, performance counters and DSP instructions are totally different
from the imgtec cores. Older BMIPS3300 instances have system
registers squatting in the middle of the default FIXMAP region.
Many of the early BMIPS3300 Linux ports just selected
CONFIG_CPU_MIPS32_R1 and gradually hacked in support for
BMIPS-specific features.
But I haven't seen precedent for a kernel supporting
BMIPS43xx/BMIPS5000 + other non-BMIPS CPUs in the same build. Maybe
it's possible; we would want to look at the current and future cases
where BMIPS gets special treatment. grepping through the tree I see
hazard barriers, exception vectors (most of which are figured out at
runtime now), and performance events. Also, things like FIXADDR_TOP
and <war.h> are compile-time options.
Historically, the "XKS01" kseg0/kseg1 remapping feature has also been
tricky, and might not be supportable at all in a multiplatform build.
>> Outside of the CPU, the BCM63xx/BCM33xx/BCM7xxx register maps and
>> peripherals look pretty different, and the arch/mips/bmips code makes
>> almost zero assumptions about the rest of the chip if a DTB is passed
>> in from the bootloader. In this sense you can see the parallels to
>> CONFIG_ARCH_MULTI_Vx.
>>
>> Prior to this work, these product lines have never been able to share
>> a common kernel image.
>
> I still think this is different in the sense that ARM multiplatform
> support is about combining platforms from separate mach-* directories,
> while your approach was to rewrite multiple mach-* directories into
> a single new one that remains separate from the others.
There is at least one out-of-tree kernel for each of:
arch/mips/bcm9338x
arch/mips/bcm963xx (which predates arch/mips/bcm63xx)
arch/mips/brcmstb
each of which was implementing and maintaining the same
CPU/SMP/cache/IRQ support a little bit differently.
The femtocell chips (BCM61xxx) may or may not have their own tree as
well - need to check. Plus, here in mainline, we currently have an
arch/mips/bcm63xx tree supporting a different (usually older) subset
of BCM63xx chipsets.
It would be nice if we could identify the BMIPS chips that are still
actively used, and support them all with one mach type instead of 4+.
There might still be a few special cases but I suspect that several of
the extra mach directories can be eliminated.
> While this is
> a great improvement, it doesn't get you any closer to having a
> combined BMIPS+RALINK+JZ4740+ATH79 kernel for instance. I don't know
> if such a kernel is something that anybody wants, or if it's even
> technically possible.
Correct, that isn't the goal for now.
Given the differences between BMIPS and imgtec MIPS, it is possible
that making such a multiplatform kernel would be the equivalent of
making a single image that runs on ARMv5 + ARMv7. We may want to
assess the tradeoffs at some point.
It is possible that a multiplatform BMIPS kernel may run fine on
reasonably simple non-BMIPS hardware, but that other hardware (e.g.
supporting SMP, system PM states, or more complicated caches) would
require a dedicated build.
> If you wanted to do that however, starting with BMIPS you'd have
> to make it possible to define a new platform without the
> arch/mips/include/asm/mach-bmips/ directory (this should be possible
> already, so the hardest part is done), replace all global function
> calls (arch_init_irq, prom_init, get_system_type, ...) with generic
> platform-independent implementations or wrappers around per-platform
> callbacks, and move the Kconfig section for CONFIG_BMIPS_MULTIPLATFORM
> outside of the "System type" choice statement.
Right. The other question is how much support for legacy non-DT
bootloaders really belongs in a true multiplatform kernel, as this
stuff gets hairy fast.
On Mon, Nov 17, 2014 at 8:13 AM, Arnd Bergmann <[email protected]> wrote:
> This is not just DT, it's actually an implementation of a boot
> interface. The situation here seems much more to what we had on
> PowerPC a long time ago than what we had on ARM before the DT
> conversion. I think the best approach here would be to move the
> platform specific bits into the decompressor code, and allow
> multiple implementations of that. This way you can have the
> generic vmlinux file that has a common DT parser, and you wrap
> that into one decompressor per platform, some of which can have
> their own board detection logic or pre-boot setup where necessary.
>
> To be honest, I think having multiple DT files linked into the
> kernel is a really bad idea, because it doesn't solve the
> scalability problem at all. What we did on ARM was to force those
> hacks out into external projects such as the PXA impedence
> matcher [https://github.com/zonque/pxa-impedance-matcher]. This
> can handle all weird boot protocol and adapt them to the normal
> well-defined interfaces we have in the kernel.
To some extent this is how BCM3384 was done[1].
There is a tradeoff here: to add support for the older platforms it is
easy to build a new DTB file into the kernel image, but it is a lot of
trouble to write a new 3rd stage bootloader. Do we want to maximize
our list of supported boards, or are we shooting for a super clean
kernel implementation right off the bat?
>> And unless there is one, having a
>> multiplatform kernel does not make much sense, as there is no sane way
>> to tell apart different platforms on boot.
>
> How do you normally tell boards apart on MIPS when you don't use DT?
On BCM7xxx (STB) kernels, we could assume the chip ID was in a known
register, and also we could call back into the bootloader to get a
somewhat-accurate board name.
On BCM63xx there is logic in arch/mips/bcm63xx/cpu.c to try to guess
the chip identity from the CPU type/revision (because the latter can
be read directly from CP0).
These systems were never really designed to support multiplatform
kernels. The ARM BCM7xxx variants, by contrast, were.
[1] https://github.com/Broadcom/aeolus
On Monday 17 November 2014 09:01:02 Kevin Cernekee wrote:
> On Mon, Nov 17, 2014 at 4:16 AM, Arnd Bergmann <[email protected]> wrote:
> Under arch/mips/bcm47xx I see a single mach type, but different builds
> for BMIPS3300 (R1/SSB) versus MIPS 74K (R2/BCMA).
At least in Kconfig, the two are not mutually exclusive, so I assumed
you could enable them both at the same time.
> >> Outside of the CPU, the BCM63xx/BCM33xx/BCM7xxx register maps and
> >> peripherals look pretty different, and the arch/mips/bmips code makes
> >> almost zero assumptions about the rest of the chip if a DTB is passed
> >> in from the bootloader. In this sense you can see the parallels to
> >> CONFIG_ARCH_MULTI_Vx.
> >>
> >> Prior to this work, these product lines have never been able to share
> >> a common kernel image.
> >
> > I still think this is different in the sense that ARM multiplatform
> > support is about combining platforms from separate mach-* directories,
> > while your approach was to rewrite multiple mach-* directories into
> > a single new one that remains separate from the others.
>
> There is at least one out-of-tree kernel for each of:
>
> arch/mips/bcm9338x
> arch/mips/bcm963xx (which predates arch/mips/bcm63xx)
> arch/mips/brcmstb
>
> each of which was implementing and maintaining the same
> CPU/SMP/cache/IRQ support a little bit differently.
>
> The femtocell chips (BCM61xxx) may or may not have their own tree as
> well - need to check. Plus, here in mainline, we currently have an
> arch/mips/bcm63xx tree supporting a different (usually older) subset
> of BCM63xx chipsets.
>
> It would be nice if we could identify the BMIPS chips that are still
> actively used, and support them all with one mach type instead of 4+.
> There might still be a few special cases but I suspect that several of
> the extra mach directories can be eliminated.
Absolutely agreed.
> > While this is
> > a great improvement, it doesn't get you any closer to having a
> > combined BMIPS+RALINK+JZ4740+ATH79 kernel for instance. I don't know
> > if such a kernel is something that anybody wants, or if it's even
> > technically possible.
>
> Correct, that isn't the goal for now.
>
> Given the differences between BMIPS and imgtec MIPS, it is possible
> that making such a multiplatform kernel would be the equivalent of
> making a single image that runs on ARMv5 + ARMv7. We may want to
> assess the tradeoffs at some point.
>
> It is possible that a multiplatform BMIPS kernel may run fine on
> reasonably simple non-BMIPS hardware, but that other hardware (e.g.
> supporting SMP, system PM states, or more complicated caches) would
> require a dedicated build.
I see.
> > If you wanted to do that however, starting with BMIPS you'd have
> > to make it possible to define a new platform without the
> > arch/mips/include/asm/mach-bmips/ directory (this should be possible
> > already, so the hardest part is done), replace all global function
> > calls (arch_init_irq, prom_init, get_system_type, ...) with generic
> > platform-independent implementations or wrappers around per-platform
> > callbacks, and move the Kconfig section for CONFIG_BMIPS_MULTIPLATFORM
> > outside of the "System type" choice statement.
>
> Right. The other question is how much support for legacy non-DT
> bootloaders really belongs in a true multiplatform kernel, as this
> stuff gets hairy fast.
Yes, that's why I suggested following PowerPC rather than ARM in this
regard. If you move the boot loader abstraction into the decompressor
instead of the platform code, you can avoid a lot of the problems.
Arnd
On Monday 17 November 2014 09:19:17 Kevin Cernekee wrote:
> On Mon, Nov 17, 2014 at 8:13 AM, Arnd Bergmann <[email protected]> wrote:
> > This is not just DT, it's actually an implementation of a boot
> > interface. The situation here seems much more to what we had on
> > PowerPC a long time ago than what we had on ARM before the DT
> > conversion. I think the best approach here would be to move the
> > platform specific bits into the decompressor code, and allow
> > multiple implementations of that. This way you can have the
> > generic vmlinux file that has a common DT parser, and you wrap
> > that into one decompressor per platform, some of which can have
> > their own board detection logic or pre-boot setup where necessary.
> >
> > To be honest, I think having multiple DT files linked into the
> > kernel is a really bad idea, because it doesn't solve the
> > scalability problem at all. What we did on ARM was to force those
> > hacks out into external projects such as the PXA impedence
> > matcher [https://github.com/zonque/pxa-impedance-matcher]. This
> > can handle all weird boot protocol and adapt them to the normal
> > well-defined interfaces we have in the kernel.
>
> To some extent this is how BCM3384 was done[1].
>
> There is a tradeoff here: to add support for the older platforms it is
> easy to build a new DTB file into the kernel image, but it is a lot of
> trouble to write a new 3rd stage bootloader. Do we want to maximize
> our list of supported boards, or are we shooting for a super clean
> kernel implementation right off the bat?
Right, when the norm is that you can't detect the board, having
the wrapper in the kernel is the better approach, as PowerPC, which
has a few dozen ways of linking the compressed kernel, while the
vmlinux file uses a common method and passes everything in DT.
That way you can have the best of both.
> >> And unless there is one, having a
> >> multiplatform kernel does not make much sense, as there is no sane way
> >> to tell apart different platforms on boot.
> >
> > How do you normally tell boards apart on MIPS when you don't use DT?
>
> On BCM7xxx (STB) kernels, we could assume the chip ID was in a known
> register, and also we could call back into the bootloader to get a
> somewhat-accurate board name.
>
> On BCM63xx there is logic in arch/mips/bcm63xx/cpu.c to try to guess
> the chip identity from the CPU type/revision (because the latter can
> be read directly from CP0).
>
> These systems were never really designed to support multiplatform
> kernels. The ARM BCM7xxx variants, by contrast, were.
Guessing the chip doesn't really help you all that much of course
as long as you don't know the board, and once you know that,
the chip is implied.
Arnd
On Mon, Nov 17, 2014 at 10:46 AM, Arnd Bergmann <[email protected]> wrote:
> On Monday 17 November 2014 09:01:02 Kevin Cernekee wrote:
>> On Mon, Nov 17, 2014 at 4:16 AM, Arnd Bergmann <[email protected]> wrote:
>> Under arch/mips/bcm47xx I see a single mach type, but different builds
>> for BMIPS3300 (R1/SSB) versus MIPS 74K (R2/BCMA).
>
> At least in Kconfig, the two are not mutually exclusive, so I assumed
> you could enable them both at the same time.
Ah right, bcm47xx_defconfig doesn't actually enable
CONFIG_CPU_MIPS32_R2. So it will still run on R1 CPUs like BMIPS3300.
On R2 systems it may lose a few optimizations/features.
I suspect that BCM47xx could use the BMIPS multiplatform kernel, if
somebody was willing to figure out how to convert board.c, leds.c,
etc.
>> > If you wanted to do that however, starting with BMIPS you'd have
>> > to make it possible to define a new platform without the
>> > arch/mips/include/asm/mach-bmips/ directory (this should be possible
>> > already, so the hardest part is done), replace all global function
>> > calls (arch_init_irq, prom_init, get_system_type, ...) with generic
>> > platform-independent implementations or wrappers around per-platform
>> > callbacks, and move the Kconfig section for CONFIG_BMIPS_MULTIPLATFORM
>> > outside of the "System type" choice statement.
>>
>> Right. The other question is how much support for legacy non-DT
>> bootloaders really belongs in a true multiplatform kernel, as this
>> stuff gets hairy fast.
>
> Yes, that's why I suggested following PowerPC rather than ARM in this
> regard. If you move the boot loader abstraction into the decompressor
> instead of the platform code, you can avoid a lot of the problems.
One possible complication: for BCM63xx/BCM7xxx (MIPS) there is no
decompressor in the kernel. The firmware loads an ELF image into
memory and jumps directly to kernel_entry.
On Mon, Nov 17, 2014 at 10:55 AM, Arnd Bergmann <[email protected]> wrote:
>> >> And unless there is one, having a
>> >> multiplatform kernel does not make much sense, as there is no sane way
>> >> to tell apart different platforms on boot.
>> >
>> > How do you normally tell boards apart on MIPS when you don't use DT?
>>
>> On BCM7xxx (STB) kernels, we could assume the chip ID was in a known
>> register, and also we could call back into the bootloader to get a
>> somewhat-accurate board name.
>>
>> On BCM63xx there is logic in arch/mips/bcm63xx/cpu.c to try to guess
>> the chip identity from the CPU type/revision (because the latter can
>> be read directly from CP0).
>>
>> These systems were never really designed to support multiplatform
>> kernels. The ARM BCM7xxx variants, by contrast, were.
>
> Guessing the chip doesn't really help you all that much of course
> as long as you don't know the board, and once you know that,
> the chip is implied.
This mostly depends on the desired feature set, and the delta from one
board to the next. Many of the reference board sections are largely
copied from a working design, but sometimes there are changes that
affect us. Other times there are tweaks that can be autodetected,
like a different flash chip.
The analog interfaces like SATA/USB/Ethernet don't tend to vary all
that much (although some may be missing ports on the board, or
disabled on the chip).
The pin muxing situation leaves a lot of room for board differences,
and on these platforms it isn't really handled in a central place.
This gets even more challenging when combined with some of the power
management requirements.
The peripherals that I added in my patch submission are among the
easiest / safest of the bunch.
On Monday 17 November 2014 11:47:12 Kevin Cernekee wrote:
> On Mon, Nov 17, 2014 at 10:55 AM, Arnd Bergmann <[email protected]> wrote:
> >> >> And unless there is one, having a
> >> >> multiplatform kernel does not make much sense, as there is no sane way
> >> >> to tell apart different platforms on boot.
> >> >
> >> > How do you normally tell boards apart on MIPS when you don't use DT?
> >>
> >> On BCM7xxx (STB) kernels, we could assume the chip ID was in a known
> >> register, and also we could call back into the bootloader to get a
> >> somewhat-accurate board name.
> >>
> >> On BCM63xx there is logic in arch/mips/bcm63xx/cpu.c to try to guess
> >> the chip identity from the CPU type/revision (because the latter can
> >> be read directly from CP0).
> >>
> >> These systems were never really designed to support multiplatform
> >> kernels. The ARM BCM7xxx variants, by contrast, were.
> >
> > Guessing the chip doesn't really help you all that much of course
> > as long as you don't know the board, and once you know that,
> > the chip is implied.
>
> This mostly depends on the desired feature set, and the delta from one
> board to the next. Many of the reference board sections are largely
> copied from a working design, but sometimes there are changes that
> affect us. Other times there are tweaks that can be autodetected,
> like a different flash chip.
>
> The analog interfaces like SATA/USB/Ethernet don't tend to vary all
> that much (although some may be missing ports on the board, or
> disabled on the chip).
>
> The pin muxing situation leaves a lot of room for board differences,
> and on these platforms it isn't really handled in a central place.
> This gets even more challenging when combined with some of the power
> management requirements.
>
> The peripherals that I added in my patch submission are among the
> easiest / safest of the bunch.
Right, that is exactly the danger: it's easy to get the basics working
like this, but the differences between SoCs are not what we need DT
for anyway, those are easily abstracted in kernel code if necessary,
hardcoded by some soc version identifier.
What you end up with in your approach is a kernel that can support
multiple SoCs but only some boards per SoC, and otherwise you still
depend on compile-time configuration. Aside from pin configuration,
you have to have a per-board dtb file if you have any i2c or spi
connected components, PCI devices with custom interrupt lines,
LEDs, GPIO buttons, or anything else on a nondiscoverable bus.
Arnd
On Mon, Nov 17, 2014 at 6:44 AM, Jonas Gorski <[email protected]> wrote:
> On Sun, Nov 16, 2014 at 1:17 AM, Kevin Cernekee <[email protected]> wrote:
>> bmips_be_defconfig supports Linux running on the following CM and DSL
>> SoCs:
>>
>> - BCM3384 (BMIPS5000) cable modem application processor, BE, SMP
>> - BCM3384 (BMIPS4355) cable modem "spare CPU"*, BE
>> - BCM6328 (BMIPS4355) ADSL chip, BE
>
> Is BMIPS435*5* intentional? I would have assumed at least 6328 is also
> MIPS4350 like BCM6368.
Welcome back Jonas - and thanks for reviewing :-)
According to my cheat sheet, BCM6328 has the newer BMIPS4355 core,
which includes the "DMA" features used for prefetching packet data.
BCM6368 has the old BMIPS4350.
>> diff --git a/Documentation/devicetree/bindings/mips/brcm/bmips.txt b/Documentation/devicetree/bindings/mips/brcm/bmips.txt
>> new file mode 100644
>> index 0000000..4a8cd8f
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mips/brcm/bmips.txt
>> @@ -0,0 +1,8 @@
>> +* Broadcom MIPS (BMIPS) CPUs
>> +
>> +Required properties:
>> +- compatible: "brcm,bmips3300", "brcm,bmips4350", "brcm,bmips4380"
>> + "brcm,bmips5000"
>> +
>> +- mips-hpt-frequency: This is common to all CPUs in the system so it lives
>> + under the "cpus" node.
>
> Is it a good idea to hardcode this? Some SoC CPUs allow running with
> different frequencies, which will directly affect this.
On some of the BCM7xxx kernels there is a timer peripheral that always
runs at 27 MHz. It is used to derive the CPU frequency at runtime, so
no hardcoding is necessary:
https://github.com/BlackPole/vuplus-kernel/blob/master/arch/mips/brcmstb/time.c#L119
On a generic BMIPS kernel it might be harder to rely on an external timer.
Is there a better solution (or should we implement some sort of
fallback if the mips-hpt-frequency property is missing)?
> Also I would
> assume this would break once we add support for runtime clock changes
> for BMIPS; at least on the DSL platform you can change the clock
> between 1/4 (IIRC) and 1/1 for power saving.
I don't know the 435x's very well, but I believe all BMIPS CPUs allow
selecting between 1:1, 1:2, 1:4, and 1:8. BMIPS5000 also allows 1:16.
FWIW, this feature is unstable on several of the 40nm chips.
Also, some older versions of the core (65nm, 130nm) scaled down the
MIPS CP0 counter frequency when the base clock changed. The newer
BMIPS438x cores, and all BMIPS5000 cores, do not. CP0 $22,0 bit 6 on
BMIPS438x should be '1' if the counter frequency is fixed. Not sure
about BMIPS435x.
We will have to put some thought into implementing cpufreq in a generic way...
>> +SoCs:
>> +
>> +Required properties:
>> +- compatible: "brcm,bcm3384", "brcm,bcm33843"
>> + "brcm,bcm3384-viper", "brcm,bcm33843-viper"
>> + "brcm,bcm6328", "brcm,bcm6368",
>> + "brcm,bcm7125", "brcm,bcm7346", "brcm,bcm7360",
>> + "brcm,bcm7420", "brcm,bcm7425"
>> +
>> +Boards:
>> +
>> +Required properties:
>> +- compatible: "brcm,bcm93384wvg", "brcm,bcm93384wvg-viper"
>> + "brcm,bcm9ejtagprb", "brcm,bcm96368mvwg",
>> + "brcm,bcm97125cbmb", "brcm,bcm97346dbsmb", "brcm,bcm97360svmb",
>> + "brcm,bcm97420c", "brcm,bcm97425svmb"
>
> Should the list of supported boards really be hardcoded here/in the
> kernel? It doesn't match what the code does, as it (as far as I can
> tell) accepts dtbs without any of the board compatible ids when passed
> from bootloader.
Honestly I'd prefer to nuke them from the bindings doc. But
checkpatch was complaining that they were undocumented.
Any opinions?
>> +extern char __dtb_bcm9ejtagprb_begin;
>> +extern char __dtb_bcm96368mvwg_begin;
>> +extern char __dtb_bcm97125cbmb_begin;
>> +extern char __dtb_bcm97346dbsmb_begin;
>> +extern char __dtb_bcm97360svmb_begin;
>> +extern char __dtb_bcm97420c_begin;
>> +extern char __dtb_bcm97425svmb_begin;
>
> I think it would be a good idea to have the embedded dtbs optional,
> especially if you already provide an interface for passing a dtb
> pointer.
So, our options include:
1) Use a bool option for each one; leave the setup.c heuristic logic
in place. Multiplatform kernels still work with existing bootloaders.
Need a bunch of new #ifdefs in this section of code.
2) Use a choice option to allow one DTS file (or no DTS file) to be compiled in.
3) Forbid compiling in DTS files; make people use a sensible
bootloader or wrapper.
4) Leave everything as-is.
The short term plan can be different from the long term plan.
What does everyone prefer?
>> +static void __init *find_dtb(void)
>> +{
>> + u32 chip_id;
>> + char boardname[64] = "";
>> + const struct bmips_board_list *b;
>> +
>> + /* Intended to somewhat resemble ARM; see Documentation/arm/Booting */
>> + if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
>> + return phys_to_virt(fw_arg2);
>
> I know a bit late, but how about using the OF_DT_MAGIC (0xd00dfeed)
> for indicating that there is a device tree in arg2?
No preference either way. Should we stick with the ARM convention, or
use a more unique magic number?
>> + /*
>> + * Unfortunately the CFE API doesn't seem to provide chip
>> + * identification, but we can check the entry point to see whether
>> + * the current platform is a DSL chip or STB chip. On STB,
>> + * CAE_STKSIZE = _regidx(13) = 13*8 = 104, so the first instruction is:
>> + * 0: 23bdff98 addi sp,sp,-104
>> + */
>> + if (__raw_readl((void *)fw_arg2) == 0x23bdff98) {
>> + chip_id = __raw_readl(REG_STB_CHIP_ID);
>> + cfe_init(fw_arg0, fw_arg2);
>> + cfe_getenv("CFE_BOARDNAME", boardname, sizeof(boardname));
>> + } else {
>> + /*
>> + * This works on most modern chips, but will break on older
>> + * ones like 6358
>> + */
>> + chip_id = __raw_readl(REG_DSL_CHIP_ID);
>
> Unfortunately I don't know any good way to discriminate between the
> "old" and the "new" chips except by looking a the PRID and REV
> (BMIPS3300 <= 3.2 || BMIPS4350 <= 1.0 => 0xfff00000, BMIPS3300 >= 3.3
> || BMIPS4350 >= 3.0 => 0xb0000000).
I suspect that if somebody is motivated to support the older chips in
arch/mips/bmips, our setup.c will start borrowing the existing bcm63xx
logic.
OTOH this could also be an opportunity to drop obsolete platforms that
have a small number of users or a large number of hacks.
>
>> + }
>> +
>> + /* 4-digit parts use bits [31:16]; 5-digit parts use [27:8] */
>
> This might be true for the STB chips, but the DSL 5-digit parts use
> [31:12]. And to add insult to insury, some 4-digit parts use [15:12]
> for the chip variant, so you can't just check [15:12] for 0 or != 0
> either (I would assume 63381 and 6328 (variant 63281) will have both 1
> at [15:12].
How unfortunate. A lot of effort/persuasion went into standardizing
this format on STB.
I can change this to use a value/mask test for non-STB?
My 6328 says:
# devmem 0x10000000
0x632830B0
Will need to double check our 6329's (I think their upper halfword is
still 0x6328).
>> + if (chip_id & 0xf0000000)
>> + chip_id >>= 16;
>> + else
>> + chip_id >>= 8;
>> +
>> + for (b = bmips_board_list; b->dtb; b++) {
>> + if (b->chip_id != chip_id)
>> + continue;
>> + if (b->boardname && strcmp(b->boardname, boardname))
>> + continue;
>> + if (b->quirk_fn)
>> + b->quirk_fn();
>
> Hmm, maybe move running the quirk out of here and into
> plat_mem_setup()? Currently e.g. a BCM6328 with a bootloader passed
> dtb won't have its quirk run.
Good idea. My current line of thinking is to restructure quirks into
its own table, indexed by the compatible string.
>> +int __init plat_of_setup(void)
>> +{
>> + return __dt_register_buses("brcm,bmips", "simple-bus");
>
> Huh, "brcm,bmips" does not appear anywhere else. How does this work?
> Should this be a required compatible?
I saw other platforms passing in strings like "lantiq,falcon" and did
likewise...
I can experiment with removing that bus registration entirely to see
what happens.
> Minor stilistic nitpick: I would use
>
> dtb-$(CONFIG_BMIPS_MULTIPLATFORM) += \
> bcm93384wvg.dtb \
>
> so that adding a board before bcm963384wvg would only require an
> insert, not also a modification.
OK
>> diff --git a/arch/mips/boot/dts/bcm3384_common.dtsi b/arch/mips/boot/dts/bcm3384_common.dtsi
>> new file mode 100644
>> index 0000000..448cb5b
>> --- /dev/null
>> +++ b/arch/mips/boot/dts/bcm3384_common.dtsi
>> @@ -0,0 +1,44 @@
>> +/ {
>> + clocks {
>> + #address-cells = <1>;
>
> This does not really make sense, as there is no address used at all
> for the periph_clk.
>
>> + #size-cells = <0>;
>> +
>> + periph_clk: periph_clk@0 {
>
> Same for the @0 - there is no appropriate reg = <0>, so using an
> address here does not make sense.
OK
>> diff --git a/arch/mips/boot/dts/bcm6328.dtsi b/arch/mips/boot/dts/bcm6328.dtsi
>> new file mode 100644
>> index 0000000..a7e397f
>> --- /dev/null
>> +++ b/arch/mips/boot/dts/bcm6328.dtsi
>> @@ -0,0 +1,63 @@
>> +/ {
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + compatible = "brcm,bcm6328";
>> +
>> + cpus {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + mips-hpt-frequency = <160000000>;
>> +
>> + cpu@0 {
>> + compatible = "brcm,bmips4350";
>> + device_type = "cpu";
>> + reg = <0>;
>> + };
>
> Since there are SMP-enabled variants, maybe it should have its second
> thread documented here (but defaulting to "disabled")?
That looks like a goof. There is code in setup.c that knows whether
to enable/disable CPU1 on 6328 based on OTP. Will fix.
>> + cpu_intc: cpu_intc@0 {
>
> It does not have an address, so it should not have @0 in the node name I think.
I have no preference either way, but
Documentation/devicetree/bindings/mips/cpu_irq.txt has the "@0".
>
>> + #address-cells = <0>;
>> + compatible = "mti,cpu-interrupt-controller";
>> +
>> + interrupt-controller;
>> + #interrupt-cells = <1>;
>> + };
>> +
>> + periph_intc: periph_intc@10000024 {
>> + compatible = "brcm,bcm7120-l2-intc";
>> + reg = <0x10000024 0x4 0x1000002c 0x4
>> + 0x10000020 0x4 0x10000028 0x4>;
>
> The "lowest" register address you use is 0x10000020, so the name
> should arguably be periph_intc@10000020, not periph_intc@10000024. I
> guess the second cpu block (10000030 - 1000003c) wired to hw irq 3 can
> be added later.
OK
> This will easily translate to a lot of io(re)map calls in case of
> 63268/6318 when describing both cpu blocks ( a total of 16 "reg"s).
>
> Also I wonder how you properly describe the intc of 63381, where it
> has separate mask registers, but a shared status register.
If you aren't putting any IRQs on CPU1 you can probably get away with
only mentioning the status register once, for now.
irq-bcm7120-l2.c will need some additional work before it can handle
multiple CPUs.
On Monday 17 November 2014 11:39:02 Kevin Cernekee wrote:
> On Mon, Nov 17, 2014 at 10:46 AM, Arnd Bergmann <[email protected]> wrote:
> > On Monday 17 November 2014 09:01:02 Kevin Cernekee wrote:
> >> > If you wanted to do that however, starting with BMIPS you'd have
> >> > to make it possible to define a new platform without the
> >> > arch/mips/include/asm/mach-bmips/ directory (this should be possible
> >> > already, so the hardest part is done), replace all global function
> >> > calls (arch_init_irq, prom_init, get_system_type, ...) with generic
> >> > platform-independent implementations or wrappers around per-platform
> >> > callbacks, and move the Kconfig section for CONFIG_BMIPS_MULTIPLATFORM
> >> > outside of the "System type" choice statement.
> >>
> >> Right. The other question is how much support for legacy non-DT
> >> bootloaders really belongs in a true multiplatform kernel, as this
> >> stuff gets hairy fast.
> >
> > Yes, that's why I suggested following PowerPC rather than ARM in this
> > regard. If you move the boot loader abstraction into the decompressor
> > instead of the platform code, you can avoid a lot of the problems.
>
> One possible complication: for BCM63xx/BCM7xxx (MIPS) there is no
> decompressor in the kernel. The firmware loads an ELF image into
> memory and jumps directly to kernel_entry.
>
Right, that complicates it a bit, but is there a reason why a decompressor
would be hard to do, or would be considered a bad thing?
There is already generic decompressor code in arch/mips/boot/compressed/
that I would assume you could use without firmware changes. Are you
worried about boot time overhead?
Arnd
On Mon, Nov 17, 2014 at 12:40 PM, Arnd Bergmann <[email protected]> wrote:
>> One possible complication: for BCM63xx/BCM7xxx (MIPS) there is no
>> decompressor in the kernel. The firmware loads an ELF image into
>> memory and jumps directly to kernel_entry.
>>
>
> Right, that complicates it a bit, but is there a reason why a decompressor
> would be hard to do, or would be considered a bad thing?
> There is already generic decompressor code in arch/mips/boot/compressed/
> that I would assume you could use without firmware changes. Are you
> worried about boot time overhead?
Currently the bootloader is responsible for decompressing the image.
On STB the bootloader typically loads a gzipped ELF file; on DSL/CM
the bootloader unpacks a custom image format containing an
LZMA-compressed kernel in some form. So we would be
double-compressing the same kernel in this scheme.
STB/DSL should be able to boot the arch/mips/boot/compressed "vmlinuz"
ELF file; I tested STB. CM might be questionable, but doesn't need
decompressor mods because the bootloader is DT-aware.
Also, the decompressor may need to be modified so that it recognizes /
passes / doesn't overwrite DTB blobs coming from the bootloader. And
to make sure it doesn't stomp on any of the code or data that our
bootloaders use for their callback mechanisms.
So, one possibility is to submit a V3 patch which allows 0 or 1 DTB
files to be compiled in statically (similar to
CONFIG_ARM_APPENDED_DTB) and requires a DT-aware bootloader or
decompressor for anything else. Any opinions?
On Mon, Nov 17, 2014 at 12:33 PM, Arnd Bergmann <[email protected]> wrote:
>> This mostly depends on the desired feature set, and the delta from one
>> board to the next. Many of the reference board sections are largely
>> copied from a working design, but sometimes there are changes that
>> affect us. Other times there are tweaks that can be autodetected,
>> like a different flash chip.
>>
>> The analog interfaces like SATA/USB/Ethernet don't tend to vary all
>> that much (although some may be missing ports on the board, or
>> disabled on the chip).
>>
>> The pin muxing situation leaves a lot of room for board differences,
>> and on these platforms it isn't really handled in a central place.
>> This gets even more challenging when combined with some of the power
>> management requirements.
>>
>> The peripherals that I added in my patch submission are among the
>> easiest / safest of the bunch.
>
> Right, that is exactly the danger: it's easy to get the basics working
> like this, but the differences between SoCs are not what we need DT
> for anyway, those are easily abstracted in kernel code if necessary,
> hardcoded by some soc version identifier.
That depends on how many SoC's we're talking about...
On MIPS we have literally dozens. Most of the "building blocks" are
pretty similar, but the MMIO addresses, IRQ mappings, and
quantity/revision of each peripheral vary. DT is ideal for
representing these differences and for rapidly bringing up a new
system.
> What you end up with in your approach is a kernel that can support
> multiple SoCs but only some boards per SoC, and otherwise you still
> depend on compile-time configuration.
Agreed, but for legacy platforms this is somewhat inevitable. These
systems are already in production so there is no manpower available to
go back and test every single one-off board. It is most likely that a
small subset of "interesting" boards will receive the best support.
For instance, I see an arch/arm/boot/dts/bcm2835-rpi-b.dts, but that's
hardly the only BCM2835-based platform found in the wild.
The limited board support doesn't negate the value of having a generic
BMIPS kernel available upstream; this build still eliminates
duplicated efforts on many of the basic items (CPU/SMP/caching, IRQ
controllers, UART). It also allows easy reuse of DT-ready peripherals
that are common to the CM/DSL/STB MIPS and ARM chips, which was the
original goal of the BCM3384 port.
Going forward I would expect that with this build available in
mainline, it will open up new opportunities for modernizing the
bootloaders on each product line.
> Aside from pin configuration,
> you have to have a per-board dtb file if you have any i2c or spi
> connected components, PCI devices with custom interrupt lines,
> LEDs, GPIO buttons, or anything else on a nondiscoverable bus.
Correct.
For better or for worse, most of these don't use Linux kernel drivers on STB.
On Mon, Nov 17, 2014 at 9:35 PM, Kevin Cernekee <[email protected]> wrote:
> On Mon, Nov 17, 2014 at 6:44 AM, Jonas Gorski <[email protected]> wrote:
>> On Sun, Nov 16, 2014 at 1:17 AM, Kevin Cernekee <[email protected]> wrote:
>>> bmips_be_defconfig supports Linux running on the following CM and DSL
>>> SoCs:
>>>
>>> - BCM3384 (BMIPS5000) cable modem application processor, BE, SMP
>>> - BCM3384 (BMIPS4355) cable modem "spare CPU"*, BE
>>> - BCM6328 (BMIPS4355) ADSL chip, BE
>>
>> Is BMIPS435*5* intentional? I would have assumed at least 6328 is also
>> MIPS4350 like BCM6368.
>
> Welcome back Jonas - and thanks for reviewing :-)
>
> According to my cheat sheet, BCM6328 has the newer BMIPS4355 core,
> which includes the "DMA" features used for prefetching packet data.
> BCM6368 has the old BMIPS4350.
Ah, interesting tidbit. So I guess BCM6362, BCM63268 and BCM63381 also
have BMIPS4355.
>>> diff --git a/Documentation/devicetree/bindings/mips/brcm/bmips.txt b/Documentation/devicetree/bindings/mips/brcm/bmips.txt
>>> new file mode 100644
>>> index 0000000..4a8cd8f
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/mips/brcm/bmips.txt
>>> @@ -0,0 +1,8 @@
>>> +* Broadcom MIPS (BMIPS) CPUs
>>> +
>>> +Required properties:
>>> +- compatible: "brcm,bmips3300", "brcm,bmips4350", "brcm,bmips4380"
>>> + "brcm,bmips5000"
>>> +
>>> +- mips-hpt-frequency: This is common to all CPUs in the system so it lives
>>> + under the "cpus" node.
>>
>> Is it a good idea to hardcode this? Some SoC CPUs allow running with
>> different frequencies, which will directly affect this.
>
> On some of the BCM7xxx kernels there is a timer peripheral that always
> runs at 27 MHz. It is used to derive the CPU frequency at runtime, so
> no hardcoding is necessary:
AFAIK all BCM63xx chips have a timer peripheral with 4 or 5 timers
running at 50 MHz, used as the HPT when using the BMIPS frequency
scaling.
> https://github.com/BlackPole/vuplus-kernel/blob/master/arch/mips/brcmstb/time.c#L119
>
> On a generic BMIPS kernel it might be harder to rely on an external timer.
>
> Is there a better solution (or should we implement some sort of
> fallback if the mips-hpt-frequency property is missing)?
I guess that is the dtb's job to point out the correct system timer.
>> Also I would
>> assume this would break once we add support for runtime clock changes
>> for BMIPS; at least on the DSL platform you can change the clock
>> between 1/4 (IIRC) and 1/1 for power saving.
>
> I don't know the 435x's very well, but I believe all BMIPS CPUs allow
> selecting between 1:1, 1:2, 1:4, and 1:8. BMIPS5000 also allows 1:16.
>
> FWIW, this feature is unstable on several of the 40nm chips.
>
> Also, some older versions of the core (65nm, 130nm) scaled down the
> MIPS CP0 counter frequency when the base clock changed. The newer
> BMIPS438x cores, and all BMIPS5000 cores, do not. CP0 $22,0 bit 6 on
> BMIPS438x should be '1' if the counter frequency is fixed. Not sure
> about BMIPS435x.
According to pwrmngtclk.c,the bcm63xx bmipses might not have a fixed
cp0 counter frequency and might scale with the cpu frequency. This
also includes the BMIPS3300 in 6318. This isn't very clear; the code
for snycing the cp0 count is enabled through a Kconfig symbol, but I
don't see anything selecting it. So dunno.
> We will have to put some thought into implementing cpufreq in a generic way...
>
>>> +SoCs:
>>> +
>>> +Required properties:
>>> +- compatible: "brcm,bcm3384", "brcm,bcm33843"
>>> + "brcm,bcm3384-viper", "brcm,bcm33843-viper"
>>> + "brcm,bcm6328", "brcm,bcm6368",
>>> + "brcm,bcm7125", "brcm,bcm7346", "brcm,bcm7360",
>>> + "brcm,bcm7420", "brcm,bcm7425"
>>> +
>>> +Boards:
>>> +
>>> +Required properties:
>>> +- compatible: "brcm,bcm93384wvg", "brcm,bcm93384wvg-viper"
>>> + "brcm,bcm9ejtagprb", "brcm,bcm96368mvwg",
>>> + "brcm,bcm97125cbmb", "brcm,bcm97346dbsmb", "brcm,bcm97360svmb",
>>> + "brcm,bcm97420c", "brcm,bcm97425svmb"
>>
>> Should the list of supported boards really be hardcoded here/in the
>> kernel? It doesn't match what the code does, as it (as far as I can
>> tell) accepts dtbs without any of the board compatible ids when passed
>> from bootloader.
>
> Honestly I'd prefer to nuke them from the bindings doc. But
> checkpatch was complaining that they were undocumented.
>
> Any opinions?
I don't think they should be there either. And checkpatch does not
always need to be followed, it is ultimately only a suggestion
(although a very strong one ;-)
>>> +extern char __dtb_bcm9ejtagprb_begin;
>>> +extern char __dtb_bcm96368mvwg_begin;
>>> +extern char __dtb_bcm97125cbmb_begin;
>>> +extern char __dtb_bcm97346dbsmb_begin;
>>> +extern char __dtb_bcm97360svmb_begin;
>>> +extern char __dtb_bcm97420c_begin;
>>> +extern char __dtb_bcm97425svmb_begin;
>>
>> I think it would be a good idea to have the embedded dtbs optional,
>> especially if you already provide an interface for passing a dtb
>> pointer.
>
> So, our options include:
>
> 1) Use a bool option for each one; leave the setup.c heuristic logic
> in place. Multiplatform kernels still work with existing bootloaders.
> Need a bunch of new #ifdefs in this section of code.
>
> 2) Use a choice option to allow one DTS file (or no DTS file) to be compiled in.
>
> 3) Forbid compiling in DTS files; make people use a sensible
> bootloader or wrapper.
>
> 4) Leave everything as-is.
>
> The short term plan can be different from the long term plan.
>
> What does everyone prefer?
I'd go with
5) Include legacy board dtbs in the kernel (Y/n)
which then selects BUILTIN_DTB.
>>> +static void __init *find_dtb(void)
>>> +{
>>> + u32 chip_id;
>>> + char boardname[64] = "";
>>> + const struct bmips_board_list *b;
>>> +
>>> + /* Intended to somewhat resemble ARM; see Documentation/arm/Booting */
>>> + if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
>>> + return phys_to_virt(fw_arg2);
>>
>> I know a bit late, but how about using the OF_DT_MAGIC (0xd00dfeed)
>> for indicating that there is a device tree in arg2?
>
> No preference either way. Should we stick with the ARM convention, or
> use a more unique magic number?
I don't see anything wrong in reusing conventions, quite the contrary.
>>> + /*
>>> + * Unfortunately the CFE API doesn't seem to provide chip
>>> + * identification, but we can check the entry point to see whether
>>> + * the current platform is a DSL chip or STB chip. On STB,
>>> + * CAE_STKSIZE = _regidx(13) = 13*8 = 104, so the first instruction is:
>>> + * 0: 23bdff98 addi sp,sp,-104
>>> + */
>>> + if (__raw_readl((void *)fw_arg2) == 0x23bdff98) {
>>> + chip_id = __raw_readl(REG_STB_CHIP_ID);
>>> + cfe_init(fw_arg0, fw_arg2);
>>> + cfe_getenv("CFE_BOARDNAME", boardname, sizeof(boardname));
>>> + } else {
>>> + /*
>>> + * This works on most modern chips, but will break on older
>>> + * ones like 6358
>>> + */
>>> + chip_id = __raw_readl(REG_DSL_CHIP_ID);
>>
>> Unfortunately I don't know any good way to discriminate between the
>> "old" and the "new" chips except by looking a the PRID and REV
>> (BMIPS3300 <= 3.2 || BMIPS4350 <= 1.0 => 0xfff00000, BMIPS3300 >= 3.3
>> || BMIPS4350 >= 3.0 => 0xb0000000).
>
> I suspect that if somebody is motivated to support the older chips in
> arch/mips/bmips, our setup.c will start borrowing the existing bcm63xx
> logic.
I wonder who that could be *whistle*
> OTOH this could also be an opportunity to drop obsolete platforms that
> have a small number of users or a large number of hacks.
BCM6345/6338/6348 might be streching it a bit, but I think 6358 is
still used in semi-recent devices. At least Broadcom still mentions it
on their website [1]. Surprisingly it also mentions 6338, so I wonder
if these are still produced. Also they seem to have dropped the 6328.
>>> + }
>>> +
>>> + /* 4-digit parts use bits [31:16]; 5-digit parts use [27:8] */
>>
>> This might be true for the STB chips, but the DSL 5-digit parts use
>> [31:12]. And to add insult to insury, some 4-digit parts use [15:12]
>> for the chip variant, so you can't just check [15:12] for 0 or != 0
>> either (I would assume 63381 and 6328 (variant 63281) will have both 1
>> at [15:12].
>
> How unfortunate. A lot of effort/persuasion went into standardizing
> this format on STB.
>
> I can change this to use a value/mask test for non-STB?
Assuming we add the PRID/REV matching to chipid reg location from
bcm63xx, we can use it at the same time for the width/offset of the
chip name part.
>
> My 6328 says:
>
> # devmem 0x10000000
> 0x632830B0
Assuming this is the ejtag thingy, this is expected, as it uses a
BCM63283 (no idea what the difference is to the 63281. Maybe some VoIP
related stuff or so). I also have an actual BCM63281, but I'm too lazy
to find an unused ttl-serial, so I'll just pretend it says 0x632810B0.
> Will need to double check our 6329's (I think their upper halfword is
> still 0x6328).
That would be interesting, as 6369, 63169 and 63269 actually uses a
...9 chip id. According to broadcom code, same for 6319.
There's also the mess of the 68xx gpon socs: 6818 and 6828 seem to use
the "standard" upper 16 bit of the chipid register, but encode a
variety of variants in their chipid:
/* Force BCM681x variants to be BCM6816 or BCM6818 correctly) */
if( (r & 0xfff0) == 0x6810 )
{
if ((r == 0x6811) || (r == 0x6815) || (r == 0x6817)) {
r = 0x6818;
} else {
r = 0x6816;
t = (int) (PERF->RevID & REV_ID_MASK);
if ((t & 0xf0) == 0xA0)
{
r = 0x6818;
}
}
}
/* Force 6821 and 6822 to be BCM6828 */
if ((r == 0x6821) || (r == 0x6822))
r = 0x6828;
6838 seems to use only a nibble [7:4] for the chip id and the second
one for the variant id [3:0]. WTF. Let's pretend it doesn't exist.
Actually let's pretend bcm68xx does not exist at all for now.
>>> + if (chip_id & 0xf0000000)
>>> + chip_id >>= 16;
>>> + else
>>> + chip_id >>= 8;
>>> +
>>> + for (b = bmips_board_list; b->dtb; b++) {
>>> + if (b->chip_id != chip_id)
>>> + continue;
>>> + if (b->boardname && strcmp(b->boardname, boardname))
>>> + continue;
>>> + if (b->quirk_fn)
>>> + b->quirk_fn();
>>
>> Hmm, maybe move running the quirk out of here and into
>> plat_mem_setup()? Currently e.g. a BCM6328 with a bootloader passed
>> dtb won't have its quirk run.
>
> Good idea. My current line of thinking is to restructure quirks into
> its own table, indexed by the compatible string.
>
>>> +int __init plat_of_setup(void)
>>> +{
>>> + return __dt_register_buses("brcm,bmips", "simple-bus");
>>
>> Huh, "brcm,bmips" does not appear anywhere else. How does this work?
>> Should this be a required compatible?
>
> I saw other platforms passing in strings like "lantiq,falcon" and did
> likewise...
IIRC all the dtb files then also use "vendor,boardname",
"lantiq,falcon"; as the compatible strings.
I can think of three options/variants:
1) Use a generic "brcm,bmips". Tthis is similar to e.g.
"marvell,kirkwood", but probably a bit too generic, and might imply
compatibilty for future chips where there is none.
2) Construct "brcm,bcm%x", where x == chipid. This is what I am
currently doing in [2].
3) Similar to 2), but use of_flat_dt_is_compatible() to find out the
SoC the dtb is written for, then use that as the expected chipid. It's
a bit of a tautology, but code could work something like this:
struct chipid_reg {
char compatible[128];
u32 chipid;
unsigned long reg;
int shift;
};
struct chipid_reg supported_chips[] = {
{ "brcm,bcm6328", 6328, KSEG1(0x1000000), 16 },
{ "brcm,bcm6358", 6358, 0xfff00000, 16 },
{ "brcm,bcm6368", 6368, KSEG1(0x1000000), 16 },
{ "brcm,bcm63628", 63628, KSEG1(0x1000000), 12 },
};
...
unsigned long dt_root = of_get_flat_dt_root();
for (i = 0; i < ARRAY_SIZE(supported_chips); i++) {
if (of_flat_dt_is_compatible(dt_root,
supported_chips[i].compatible)) {
u32 val = __raw_readl((void __iomem *)supported_chips[i].reg);
if ((val >> supported_chips[i].shift) !=
supported_chips[i].chipid)
panic("unexpected chipid!");
return true; /* or setup the board compatible to it
or whatever */
}
}
return false;
This is probably the closest to a "generic" multiplatform kernel, as
it will completely disregard the prid/whatever and just blindly follow
the dtb.
> I can experiment with removing that bus registration entirely to see
> what happens.
I'm rather surprised that it actually registered anything. I would
have expected for the code to be like "ugh, the registered dtb does
not have "brcm,bmips" as one of the compatible strings, so I'll ignore
it and don't register any platform devices".
>
>> Minor stilistic nitpick: I would use
>>
>> dtb-$(CONFIG_BMIPS_MULTIPLATFORM) += \
>> bcm93384wvg.dtb \
>>
>> so that adding a board before bcm963384wvg would only require an
>> insert, not also a modification.
>
> OK
>
>>> diff --git a/arch/mips/boot/dts/bcm3384_common.dtsi b/arch/mips/boot/dts/bcm3384_common.dtsi
>>> new file mode 100644
>>> index 0000000..448cb5b
>>> --- /dev/null
>>> +++ b/arch/mips/boot/dts/bcm3384_common.dtsi
>>> @@ -0,0 +1,44 @@
>>> +/ {
>>> + clocks {
>>> + #address-cells = <1>;
>>
>> This does not really make sense, as there is no address used at all
>> for the periph_clk.
>>
>>> + #size-cells = <0>;
>>> +
>>> + periph_clk: periph_clk@0 {
>>
>> Same for the @0 - there is no appropriate reg = <0>, so using an
>> address here does not make sense.
>
> OK
>
>>> diff --git a/arch/mips/boot/dts/bcm6328.dtsi b/arch/mips/boot/dts/bcm6328.dtsi
>>> new file mode 100644
>>> index 0000000..a7e397f
>>> --- /dev/null
>>> +++ b/arch/mips/boot/dts/bcm6328.dtsi
>>> @@ -0,0 +1,63 @@
>>> +/ {
>>> + #address-cells = <1>;
>>> + #size-cells = <1>;
>>> + compatible = "brcm,bcm6328";
>>> +
>>> + cpus {
>>> + #address-cells = <1>;
>>> + #size-cells = <0>;
>>> +
>>> + mips-hpt-frequency = <160000000>;
>>> +
>>> + cpu@0 {
>>> + compatible = "brcm,bmips4350";
>>> + device_type = "cpu";
>>> + reg = <0>;
>>> + };
>>
>> Since there are SMP-enabled variants, maybe it should have its second
>> thread documented here (but defaulting to "disabled")?
>
> That looks like a goof. There is code in setup.c that knows whether
> to enable/disable CPU1 on 6328 based on OTP. Will fix.
>
>>> + cpu_intc: cpu_intc@0 {
>>
>> It does not have an address, so it should not have @0 in the node name I think.
>
> I have no preference either way, but
> Documentation/devicetree/bindings/mips/cpu_irq.txt has the "@0".
Still looks wrong. Maybe the device-tree folks could throw in their two cents.
>>
>>> + #address-cells = <0>;
>>> + compatible = "mti,cpu-interrupt-controller";
>>> +
>>> + interrupt-controller;
>>> + #interrupt-cells = <1>;
>>> + };
>>> +
>>> + periph_intc: periph_intc@10000024 {
>>> + compatible = "brcm,bcm7120-l2-intc";
>>> + reg = <0x10000024 0x4 0x1000002c 0x4
>>> + 0x10000020 0x4 0x10000028 0x4>;
>>
>> The "lowest" register address you use is 0x10000020, so the name
>> should arguably be periph_intc@10000020, not periph_intc@10000024. I
>> guess the second cpu block (10000030 - 1000003c) wired to hw irq 3 can
>> be added later.
>
> OK
>
>> This will easily translate to a lot of io(re)map calls in case of
>> 63268/6318 when describing both cpu blocks ( a total of 16 "reg"s).
>>
>> Also I wonder how you properly describe the intc of 63381, where it
>> has separate mask registers, but a shared status register.
>
> If you aren't putting any IRQs on CPU1 you can probably get away with
> only mentioning the status register once, for now.
>
> irq-bcm7120-l2.c will need some additional work before it can handle
> multiple CPUs.
I expected that, and supposedly the performance suffers anyway if you
don't fix the irqs to one of the cpus, so I'm fine with having only
one of the cpu blocks documented for now.
Jonas
[1] http://www.broadcom.com/products/Broadband-Carrier-Access/xDSL-CPE-Solutions
[2] http://git.openwrt.org/?p=openwrt.git;a=blob;f=target/linux/brcm63xx/patches-3.14/367-MIPS-BCM63XX-add-support-for-loading-DTB.patch;h=577df55d0ebf4a9f7977a37d993d3e4c2abe3461;hb=HEAD
On Mon, Nov 17, 2014 at 10:21 PM, Kevin Cernekee <[email protected]> wrote:
> Currently the bootloader is responsible for decompressing the image.
> On STB the bootloader typically loads a gzipped ELF file; on DSL/CM
> the bootloader unpacks a custom image format containing an
> LZMA-compressed kernel in some form. So we would be
> double-compressing the same kernel in this scheme.
For the latter I use a patch[1] for mips head.S that detects if
there's a dtb appended to the vmlinux.bin, which would be trivial to
adapt to what the well-defined (b)mips interface expects. Of course
then there is no board detection at all, but I think that's an
acceptable trade off.
Jonas
[1] http://git.openwrt.org/?p=openwrt.git;a=blob;f=target/linux/brcm63xx/patches-3.14/366-MIPS-add-support-for-vmlinux.bin-appended-DTB.patch;h=344e78b5b41e03bff5f3d1f9cce1e8e2cb1a9368;hb=HEAD
On Monday 17 November 2014 13:57:07 Kevin Cernekee wrote:
> On Mon, Nov 17, 2014 at 12:33 PM, Arnd Bergmann <[email protected]> wrote:
> >> This mostly depends on the desired feature set, and the delta from one
> >> board to the next. Many of the reference board sections are largely
> >> copied from a working design, but sometimes there are changes that
> >> affect us. Other times there are tweaks that can be autodetected,
> >> like a different flash chip.
> >>
> >> The analog interfaces like SATA/USB/Ethernet don't tend to vary all
> >> that much (although some may be missing ports on the board, or
> >> disabled on the chip).
> >>
> >> The pin muxing situation leaves a lot of room for board differences,
> >> and on these platforms it isn't really handled in a central place.
> >> This gets even more challenging when combined with some of the power
> >> management requirements.
> >>
> >> The peripherals that I added in my patch submission are among the
> >> easiest / safest of the bunch.
> >
> > Right, that is exactly the danger: it's easy to get the basics working
> > like this, but the differences between SoCs are not what we need DT
> > for anyway, those are easily abstracted in kernel code if necessary,
> > hardcoded by some soc version identifier.
>
> That depends on how many SoC's we're talking about...
>
> On MIPS we have literally dozens. Most of the "building blocks" are
> pretty similar, but the MMIO addresses, IRQ mappings, and
> quantity/revision of each peripheral vary. DT is ideal for
> representing these differences and for rapidly bringing up a new
> system.
Of course you can abstract SoCs using DT, and we do that all the time
now on a lot of architectures. My point is that it's possible to abstract
a board using DT without also describing the SoC in detail, but you
cannot do the reverse.
> > What you end up with in your approach is a kernel that can support
> > multiple SoCs but only some boards per SoC, and otherwise you still
> > depend on compile-time configuration.
>
> Agreed, but for legacy platforms this is somewhat inevitable. These
> systems are already in production so there is no manpower available to
> go back and test every single one-off board. It is most likely that a
> small subset of "interesting" boards will receive the best support.
> For instance, I see an arch/arm/boot/dts/bcm2835-rpi-b.dts, but that's
> hardly the only BCM2835-based platform found in the wild.
It's absolutely ok to not have the dts files for each board, and to
not test all combinations, those can always come later if anyone is
interested in it.
The one thing I believe you shouldn't do is hardwire a dtb file to
an SoC specific identifier, because that makes it impossible to
support other boards that need additional DT nodes using the same
boot method. Using a single appended dtb file instead of the built-in
lookup table would solve this well enough.
> The limited board support doesn't negate the value of having a generic
> BMIPS kernel available upstream; this build still eliminates
> duplicated efforts on many of the basic items (CPU/SMP/caching, IRQ
> controllers, UART). It also allows easy reuse of DT-ready peripherals
> that are common to the CM/DSL/STB MIPS and ARM chips, which was the
> original goal of the BCM3384 port.
>
> Going forward I would expect that with this build available in
> mainline, it will open up new opportunities for modernizing the
> bootloaders on each product line.
Yes, this is all good.
Arnd
On Monday 17 November 2014 13:21:45 Kevin Cernekee wrote:
> On Mon, Nov 17, 2014 at 12:40 PM, Arnd Bergmann <[email protected]> wrote:
> >> One possible complication: for BCM63xx/BCM7xxx (MIPS) there is no
> >> decompressor in the kernel. The firmware loads an ELF image into
> >> memory and jumps directly to kernel_entry.
> >>
> >
> > Right, that complicates it a bit, but is there a reason why a decompressor
> > would be hard to do, or would be considered a bad thing?
> > There is already generic decompressor code in arch/mips/boot/compressed/
> > that I would assume you could use without firmware changes. Are you
> > worried about boot time overhead?
>
> Currently the bootloader is responsible for decompressing the image.
> On STB the bootloader typically loads a gzipped ELF file; on DSL/CM
> the bootloader unpacks a custom image format containing an
> LZMA-compressed kernel in some form. So we would be
> double-compressing the same kernel in this scheme.
>
> STB/DSL should be able to boot the arch/mips/boot/compressed "vmlinuz"
> ELF file; I tested STB. CM might be questionable, but doesn't need
> decompressor mods because the bootloader is DT-aware.
>
> Also, the decompressor may need to be modified so that it recognizes /
> passes / doesn't overwrite DTB blobs coming from the bootloader. And
> to make sure it doesn't stomp on any of the code or data that our
> bootloaders use for their callback mechanisms.
>
> So, one possibility is to submit a V3 patch which allows 0 or 1 DTB
> files to be compiled in statically (similar to
> CONFIG_ARM_APPENDED_DTB) and requires a DT-aware bootloader or
> decompressor for anything else. Any opinions?
That sounds like a good approach, in particular with the patch that
Jonas linked to. With that, most or all of your arch/mips/bmips/setup.c
should become completely generic, and I would think the rest can
be handled through a function that is called after looking up the
root "compatible" property in DT.
Arnd
On Sat, Nov 15, 2014 at 04:17:24PM -0800, Kevin Cernekee wrote:
> The lack of a reboot handler is annoying; syscon-reboot probably won't work
> on STB (because it requires two writes).
Can't you reuse drivers/power/reset/brcmstb-reboot.c ?
Brian
On Wed, Nov 19, 2014 at 7:04 PM, Brian Norris
<[email protected]> wrote:
> On Sat, Nov 15, 2014 at 04:17:24PM -0800, Kevin Cernekee wrote:
>> The lack of a reboot handler is annoying; syscon-reboot probably won't work
>> on STB (because it requires two writes).
>
> Can't you reuse drivers/power/reset/brcmstb-reboot.c ?
Oops, I ran a quick check earlier by grepping for "sun-top-ctrl" and
looking under drivers/reset, but assumed this driver wasn't merged yet
when nothing came up in the code. Thanks for the pointer.
It looks like the current driver will work for 40nm, but 65nm uses
different bit positions: RESET_CTRL bit 3 to arm, and SW_RESET bit 31
to trigger. I'll add a new "brcm,brcmstb-reboot-65nm" compatible
string to make this work.
Also, we'll need to take Guenter Roeck's register_restart_handler()
patch in order to build on MIPS.
On 11/19/2014 07:55 PM, Kevin Cernekee wrote:
> On Wed, Nov 19, 2014 at 7:04 PM, Brian Norris
> <[email protected]> wrote:
>> On Sat, Nov 15, 2014 at 04:17:24PM -0800, Kevin Cernekee wrote:
>>> The lack of a reboot handler is annoying; syscon-reboot probably won't work
>>> on STB (because it requires two writes).
>>
>> Can't you reuse drivers/power/reset/brcmstb-reboot.c ?
>
> Oops, I ran a quick check earlier by grepping for "sun-top-ctrl" and
> looking under drivers/reset, but assumed this driver wasn't merged yet
> when nothing came up in the code. Thanks for the pointer.
>
> It looks like the current driver will work for 40nm, but 65nm uses
> different bit positions: RESET_CTRL bit 3 to arm, and SW_RESET bit 31
> to trigger. I'll add a new "brcm,brcmstb-reboot-65nm" compatible
> string to make this work.
>
> Also, we'll need to take Guenter Roeck's register_restart_handler()
> patch in order to build on MIPS.
Slightly unrelated, did you also try to use drivers/bus/brcmstb_gisb.c
on these MIPS platforms?
Its usefulness is probably lower on MIPS since we typically get accurate
bus errors to be decoded by the CPU and printed through the exception
handler, but I'd be curious if it works just fine as well.
Thanks!
--
Florian
On Thu, Nov 20, 2014 at 10:09 AM, Florian Fainelli <[email protected]> wrote:
> Slightly unrelated, did you also try to use drivers/bus/brcmstb_gisb.c
> on these MIPS platforms?
>
> Its usefulness is probably lower on MIPS since we typically get accurate
> bus errors to be decoded by the CPU and printed through the exception
> handler, but I'd be curious if it works just fine as well.
Unfortunately ERR_CAP_CLR (the first register) starts at offset 0x7e4
on 28nm, and offset 0x0c8 on 40nm/65nm.
Just for fun I tried setting the base address to (0x104000c8 - 0x7e4)
= 0x103ff8e4 on 7420, and then noticed that the CAP_HI_ADDR register
only exists on the new chips with 40-bit addressing. This prevents
the driver from reading the valid bit from the correct location, so
the error handler exits prematurely. After manually hacking the code
to renumber the registers, it worked again:
# devmem 0x103ffffc
Data bus error, epc == 0040a21c, ra == 0040a1a0
brcmstb_gisb_arb_decode_addr: timeout at 0x103ffffc [R timeout], core: cpu_0
Bus error
# devmem 0x103ffffc 32 0x5678
brcmstb_gisb_arb_decode_addr: timeout at 0x103ffffc [W timeout], core: cpu_0
#
Last night I fixed up the brcmstb reset driver to work with the old
chips. I'm wondering if it makes sense to just split this work into a
new patch series, since several of the BCM7xxx ARM drivers will need
changes (both code and DT) to run on MIPS.
On Sat, Nov 15, 2014 at 04:17:34PM -0800, Kevin Cernekee wrote:
And if this one v1 is also queued for 3.19.
Ralf