2014-11-24 02:40:52

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 00/11] Multiplatform BMIPS kernel

This patch series REPLACES the following commits in Ralf's
mips-for-linux-next branch:

ab3e5d0647e3 Documentation: DT: Add entries for BCM3384 and its peripherals
1251d9964de5 MIPS: bcm3384: Initial commit of bcm3384 platform support
aff366c68e5c MAINTAINERS: Add entry for BCM33xx cable chips

(Ralf, if you just want to drop the above commits and target the new
platform for 3.20+, that's fine.)


V2->V3:

- Omit the BMIPS updates that have already been accepted into Ralf's tree.
They are still needed, but not reposted.

- Make USB endian swap options conditional on "if CPU_BIG_ENDIAN".

- Remove board listing from Documentation/devicetree/bindings/mips/brcm/soc.txt

- Remove legacy device autodetection and chip ID decoding. Legacy
boards/bootloaders will be supported by selecting a single DTB file
to compile into the kernel.

- Refactor quirks code to match against DT "compatible" strings, not chip IDs.

- Fix CPU1 boot (missing DT node) on 6329.

- Remove @0 / addressing properties on non-reg nodes.

- Remove bogus "brcm,bmips" bus registration.

- Move UBUS peripherals onto a "simple-bus" and set DMA ranges for this
bus on bcm3384_zephyr.

- Fix base addresses on 6328/6368 for "periph_intc@10000020".

- Change the MIPS_L1_CACHE_SHIFT calculation so as to minimize the impact
on other builds (like bcm63xx).


This series is based on mips-for-linux-next, minus the three 3384 patches
listed above, plus these non-MIPS patches:

http://patchwork.linux-mips.org/bundle/cernekee/bmips-multi-v3-deps/?state=%2a
http://marc.info/?l=linux-usb&m=141305106215886&w=2 (all 3/3)

These are queued for tty-next / irqchip-next / usb-next.


Re: irqchip patches in this series

These apply cleanly on top of earlier bcm7120/brcmstb commits currently
in irqchip-next. The BMIPS commit in this series depends on both the
irqchip-next updates, and the irqchip updates in this series.


Re: syscon/reset

I have some patches ready for the brcmstb syscon/reset drivers, but will
submit them separately so we can get the basic platform support stuff
nailed down first.

I don't have a patch ready for gisb-arb support yet, but I have prototyped
the change.

These patches will also have interdependencies between the
arch/mips/boot/dts changes and the drivers/ changes.


Re: external (non-MIPS) timers:

I left this problem for a future submission. There are a couple of
elements to consider:

- Do we want to completely eliminate CSRC_R4K and CEVT_R4K in favor of an
external timer, and leave mips_hpt_frequency unset?

- If so, do all platforms have a suitable timer, and is it hooked up to an
IRQ? On STB we saw conflicts with other software when taking over one
of the UPG timers; the alternative (WKTMR) doesn't have a suitable
alarm/IRQ.

- Or do we want to use another timer to calibrate mips_hpt_frequency? In
this case we may need to add part of that timer's driver under
arch/mips/bmips instead of under drivers/, so it is available early in the
boot process. Unfortunately that might cause problems or redundancy
sharing the code with ARM platforms.

- And if we do wind up using CSRC_R4K / CEVT_R4K, we'll need a way to
handle the complications caused by frequency scaling. The brcmstb
kernel sources posted on github do this, but it did require changes to
other files under arch/mips/kernel/.


Re: dma-ranges

dma.c implements a minimal remapping scheme just for the current UBUS
peripherals. The remapping is global, and it isn't the same mapping
needed for PCI(e). A more comprehensive solution will be needed before
PCI support can be added.

On chips OTHER than 3384, remapping is only required on PCI (not UBUS or
"rdb"). Notably, BCM7445, an ARM platform currently supported upstream,
doesn't require dma-ranges for non-PCI devices.

I am hoping we can piggyback on top of the ARM dma-ranges code once it
is merged. This will allow for eliminating my dma.c.


Brian Norris (1):
irqchip: brcmstb-l2: don't clear wakeable interrupts at init time

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

Kevin Cernekee (8):
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: Let __dt_register_buses accept a single bus type
MIPS: Fall back to the generic restart notifier
MIPS: Reorder MIPS_L1_CACHE_SHIFT priorities
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 | 12 +
arch/mips/Kbuild.platforms | 1 +
arch/mips/Kconfig | 42 ++-
arch/mips/bmips/Kconfig | 50 +++
arch/mips/bmips/Makefile | 1 +
arch/mips/bmips/Platform | 7 +
arch/mips/bmips/dma.c | 141 +++++++++
arch/mips/bmips/irq.c | 38 +++
arch/mips/bmips/setup.c | 195 ++++++++++++
arch/mips/boot/dts/Makefile | 9 +
arch/mips/boot/dts/bcm3384_viper.dtsi | 108 +++++++
arch/mips/boot/dts/bcm3384_zephyr.dtsi | 126 ++++++++
arch/mips/boot/dts/bcm6328.dtsi | 87 ++++++
arch/mips/boot/dts/bcm6368.dtsi | 94 ++++++
arch/mips/boot/dts/bcm7125.dtsi | 107 +++++++
arch/mips/boot/dts/bcm7346.dtsi | 192 ++++++++++++
arch/mips/boot/dts/bcm7360.dtsi | 129 ++++++++
arch/mips/boot/dts/bcm7420.dtsi | 151 ++++++++++
arch/mips/boot/dts/bcm7425.dtsi | 191 ++++++++++++
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 | 45 +++
arch/mips/boot/dts/bcm97425svmb.dts | 60 ++++
arch/mips/boot/dts/bcm9ejtagprb.dts | 22 ++
arch/mips/configs/bmips_be_defconfig | 86 ++++++
arch/mips/configs/bmips_stb_defconfig | 86 ++++++
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/kernel/prom.c | 5 +-
arch/mips/kernel/reset.c | 2 +
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 | 13 +-
44 files changed, 2768 insertions(+), 36 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/Kconfig
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_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


2014-11-24 02:40:57

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 02/11] irqchip: brcmstb-l2: don't clear wakeable interrupts at init time

From: Brian Norris <[email protected]>

Wakeable interrupts might be pending at boot/init time, because wakeup
interrupts might have triggered a resume from S5. So don't clear such
wakeups.

This means that any driver which requests a wakeable interrupt bit
should be prepared to handle an interrupt as soon as they call
request_irq(). (This is technically already the correct development
practice, but some drivers probably expect not to receive interrupts
until they have performed some I/O.)

Signed-off-by: Brian Norris <[email protected]>
Signed-off-by: Kevin Cernekee <[email protected]>
---
drivers/irqchip/irq-brcmstb-l2.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c
index 4aa653a0ac72..4edd27c486c4 100644
--- a/drivers/irqchip/irq-brcmstb-l2.c
+++ b/drivers/irqchip/irq-brcmstb-l2.c
@@ -136,7 +136,11 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,

/* Disable all interrupts by default */
writel(0xffffffff, data->base + CPU_MASK_SET);
- writel(0xffffffff, data->base + CPU_CLEAR);
+
+ /* Wakeup interrupts may be retained from S5 (cold boot) */
+ data->can_wake = of_property_read_bool(np, "brcm,irq-can-wake");
+ if (!data->can_wake)
+ writel(0xffffffff, data->base + CPU_CLEAR);

data->parent_irq = irq_of_parse_and_map(np, 0);
if (data->parent_irq < 0) {
@@ -188,8 +192,7 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
ct->chip.irq_suspend = brcmstb_l2_intc_suspend;
ct->chip.irq_resume = brcmstb_l2_intc_resume;

- if (of_property_read_bool(np, "brcm,irq-can-wake")) {
- data->can_wake = true;
+ if (data->can_wake) {
/* This IRQ chip can wake the system, set all child interrupts
* in wake_enabled mask
*/
--
2.1.1

2014-11-24 02:41:05

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 04/11] irqchip: bcm7120-l2: fix error handling of irq_of_parse_and_map

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 e7c6155b23b8..8eec8e1201d9 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

2014-11-24 02:41:08

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 08/11] MIPS: Let __dt_register_buses accept a single bus type

Some machines only have one bus type to register (e.g. "simple-bus").

Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/kernel/prom.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
index 452d4350ce42..e303cb1ef2f4 100644
--- a/arch/mips/kernel/prom.c
+++ b/arch/mips/kernel/prom.c
@@ -64,7 +64,10 @@ int __init __dt_register_buses(const char *bus0, const char *bus1)
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 (bus1) {
+ 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");
--
2.1.1

2014-11-24 02:41:13

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 10/11] MIPS: Reorder MIPS_L1_CACHE_SHIFT priorities

Enabling support for more than one BMIPS CPU in the same build may
result in different L1_CACHE_SHIFT values, e.g.

CPU_BMIPS5000 selects MIPS_L1_CACHE_SHIFT_7
CPU_BMIPS4380 selects MIPS_L1_CACHE_SHIFT_6
anything else defaults to MIPS_L1_CACHE_SHIFT_5

Ensure that if more than one MIPS_L1_CACHE_SHIFT_x option is selected,
Kconfig sets CONFIG_MIPS_L1_CACHE_SHIFT to the highest value.

Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/Kconfig | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index ae8ae77b2ecd..9c09a5a43f87 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1167,10 +1167,10 @@ config MIPS_L1_CACHE_SHIFT_7

config MIPS_L1_CACHE_SHIFT
int
- default "4" if MIPS_L1_CACHE_SHIFT_4
- default "5" if MIPS_L1_CACHE_SHIFT_5
- default "6" if MIPS_L1_CACHE_SHIFT_6
default "7" if MIPS_L1_CACHE_SHIFT_7
+ default "6" if MIPS_L1_CACHE_SHIFT_6
+ default "5" if MIPS_L1_CACHE_SHIFT_5
+ default "4" if MIPS_L1_CACHE_SHIFT_4
default "5"

config HAVE_STD_PC_SERIAL_PORT
--
2.1.1

2014-11-24 02:41:34

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

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, so they will need to select an appropriate builtin DTB at
compile time until the bootloader is updated.

Signed-off-by: Kevin Cernekee <[email protected]>
---
.../devicetree/bindings/mips/brcm/bmips.txt | 8 +
.../devicetree/bindings/mips/brcm/soc.txt | 12 ++
arch/mips/Kbuild.platforms | 1 +
arch/mips/Kconfig | 36 ++++
arch/mips/bmips/Kconfig | 50 ++++++
arch/mips/bmips/Makefile | 1 +
arch/mips/bmips/Platform | 7 +
arch/mips/bmips/dma.c | 141 +++++++++++++++
arch/mips/bmips/irq.c | 38 ++++
arch/mips/bmips/setup.c | 195 +++++++++++++++++++++
arch/mips/boot/dts/Makefile | 9 +
arch/mips/boot/dts/bcm3384_viper.dtsi | 108 ++++++++++++
arch/mips/boot/dts/bcm3384_zephyr.dtsi | 126 +++++++++++++
arch/mips/boot/dts/bcm6328.dtsi | 87 +++++++++
arch/mips/boot/dts/bcm6368.dtsi | 94 ++++++++++
arch/mips/boot/dts/bcm7125.dtsi | 107 +++++++++++
arch/mips/boot/dts/bcm7346.dtsi | 192 ++++++++++++++++++++
arch/mips/boot/dts/bcm7360.dtsi | 129 ++++++++++++++
arch/mips/boot/dts/bcm7420.dtsi | 151 ++++++++++++++++
arch/mips/boot/dts/bcm7425.dtsi | 191 ++++++++++++++++++++
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 | 45 +++++
arch/mips/boot/dts/bcm97425svmb.dts | 60 +++++++
arch/mips/boot/dts/bcm9ejtagprb.dts | 22 +++
arch/mips/configs/bmips_be_defconfig | 86 +++++++++
arch/mips/configs/bmips_stb_defconfig | 86 +++++++++
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, 2272 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/Kconfig
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_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 000000000000..4a8cd8f4d41a
--- /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 000000000000..f011443eb9d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/brcm/soc.txt
@@ -0,0 +1,12 @@
+* Broadcom cable/DSL/settop platforms
+
+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"
+
+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 1780c74ed0da..a4d1e4f2ebb6 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -6,6 +6,7 @@ platforms += ath25
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 9c09a5a43f87..36ac0e2f9d99 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -130,6 +130,41 @@ 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 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 if CPU_BIG_ENDIAN
+ select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
+ 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
@@ -858,6 +893,7 @@ source "arch/mips/ath25/Kconfig"
source "arch/mips/ath79/Kconfig"
source "arch/mips/bcm47xx/Kconfig"
source "arch/mips/bcm63xx/Kconfig"
+source "arch/mips/bmips/Kconfig"
source "arch/mips/jazz/Kconfig"
source "arch/mips/jz4740/Kconfig"
source "arch/mips/lantiq/Kconfig"
diff --git a/arch/mips/bmips/Kconfig b/arch/mips/bmips/Kconfig
new file mode 100644
index 000000000000..dced2cdc3d85
--- /dev/null
+++ b/arch/mips/bmips/Kconfig
@@ -0,0 +1,50 @@
+choice
+ prompt "Built-in device tree"
+ help
+ Legacy bootloaders do not pass a DTB pointer to the kernel, so
+ if a "wrapper" is not being used, the kernel will need to include
+ a device tree that matches the target board.
+
+ The builtin DTB will only be used if the firmware does not supply
+ a valid DTB.
+
+config DT_NONE
+ bool "None"
+
+config DT_BCM93384WVG
+ bool "BCM93384WVG Zephyr CPU"
+ select BUILTIN_DTB
+
+config DT_BCM93384WVG_VIPER
+ bool "BCM93384WVG Viper CPU (EXPERIMENTAL)"
+ select BUILTIN_DTB
+
+config DT_BCM96368MVWG
+ bool "BCM96368MVWG"
+ select BUILTIN_DTB
+
+config DT_BCM9EJTAGPRB
+ bool "BCM9EJTAGPRB"
+ select BUILTIN_DTB
+
+config DT_BCM97125CBMB
+ bool "BCM97125CBMB"
+ select BUILTIN_DTB
+
+config DT_BCM97346DBSMB
+ bool "BCM97346DBSMB"
+ select BUILTIN_DTB
+
+config DT_BCM97360SVMB
+ bool "BCM97360SVMB"
+ select BUILTIN_DTB
+
+config DT_BCM97420C
+ bool "BCM97420C"
+ select BUILTIN_DTB
+
+config DT_BCM97425SVMB
+ bool "BCM97425SVMB"
+ select BUILTIN_DTB
+
+endchoice
diff --git a/arch/mips/bmips/Makefile b/arch/mips/bmips/Makefile
new file mode 100644
index 000000000000..a393955cba08
--- /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 000000000000..bb2716225f76
--- /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 000000000000..9453c688dcfa
--- /dev/null
+++ b/arch/mips/bmips/dma.c
@@ -0,0 +1,141 @@
+/*
+ * 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]>
+ */
+
+#define pr_fmt(fmt) "bmips-dma: " fmt
+
+#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/printk.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 the "brcm,ubus" node has a "dma-ranges" property we will enable this
+ * translation globally using the provided information. This implements a
+ * very limited subset of "dma-ranges" support and it will probably be
+ * replaced by a more generic version later.
+ */
+
+struct bmips_dma_range {
+ u32 child_addr;
+ u32 parent_addr;
+ u32 size;
+};
+
+static struct bmips_dma_range *bmips_dma_ranges;
+
+#define FLUSH_RAC 0x100
+
+static dma_addr_t bmips_phys_to_dma(struct device *dev, phys_addr_t pa)
+{
+ struct bmips_dma_range *r;
+
+ for (r = bmips_dma_ranges; r && r->size; r++) {
+ if (pa >= r->child_addr &&
+ pa < (r->child_addr + r->size))
+ return pa - r->child_addr + r->parent_addr;
+ }
+ 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)
+{
+ struct bmips_dma_range *r;
+
+ for (r = bmips_dma_ranges; r && r->size; r++) {
+ if (dma_addr >= r->parent_addr &&
+ dma_addr < (r->parent_addr + r->size))
+ return dma_addr - r->parent_addr + r->child_addr;
+ }
+ return dma_addr;
+}
+
+static int __init bmips_init_dma_ranges(void)
+{
+ struct device_node *np =
+ of_find_compatible_node(NULL, NULL, "brcm,ubus");
+ const __be32 *data;
+ struct bmips_dma_range *r;
+ int len;
+
+ if (!np)
+ return 0;
+
+ data = of_get_property(np, "dma-ranges", &len);
+ if (!data)
+ goto out_good;
+
+ len /= sizeof(*data) * 3;
+ if (!len)
+ goto out_bad;
+
+ /* add a dummy (zero) entry at the end as a sentinel */
+ bmips_dma_ranges = kzalloc(sizeof(struct bmips_dma_range) * (len + 1),
+ GFP_KERNEL);
+ if (!bmips_dma_ranges)
+ goto out_bad;
+
+ for (r = bmips_dma_ranges; len; len--, r++) {
+ r->child_addr = be32_to_cpup(data++);
+ r->parent_addr = be32_to_cpup(data++);
+ r->size = be32_to_cpup(data++);
+ }
+
+out_good:
+ of_node_put(np);
+ return 0;
+
+out_bad:
+ pr_err("error parsing dma-ranges property\n");
+ of_node_put(np);
+ return -EINVAL;
+}
+arch_initcall(bmips_init_dma_ranges);
+
+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 000000000000..14552e58ff7e
--- /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 000000000000..f1474f682b22
--- /dev/null
+++ b/arch/mips/bmips/setup.c
@@ -0,0 +1,195 @@
+/*
+ * 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 RELO_NORMAL_VEC BIT(18)
+
+#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_quirk {
+ const char *compatible;
+ void (*quirk_fn)(void);
+};
+
+static void kbase_setup(void)
+{
+ __raw_writel(kbase | RELO_NORMAL_VEC,
+ BMIPS_GET_CBR() + BMIPS_RELO_VECTOR_CONTROL_1);
+ ebase = kbase;
+}
+
+static void bcm3384_viper_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.
+ */
+ board_ebase_setup = &kbase_setup;
+ bmips_smp_enabled = 0;
+}
+
+static void bcm63xx_fixup_cpu1(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 void bcm6328_quirks(void)
+{
+ /* Check CPU1 status in OTP (it is usually disabled) */
+ if (__raw_readl(REG_BCM6328_OTP) & BCM6328_TP1_DISABLED)
+ bmips_smp_enabled = 0;
+ else
+ bcm63xx_fixup_cpu1();
+}
+
+static void bcm6368_quirks(void)
+{
+ bcm63xx_fixup_cpu1();
+}
+
+static const struct bmips_quirk bmips_quirk_list[] = {
+ { "brcm,bcm3384-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm33843-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm6328", &bcm6328_quirks },
+ { "brcm,bcm6368", &bcm6368_quirks },
+ { },
+};
+
+void __init prom_init(void)
+{
+ register_bmips_smp_ops();
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init plat_mem_setup(void)
+{
+ void *dtb;
+ const struct bmips_quirk *q;
+
+ set_io_port_base(0);
+ ioport_resource.start = 0;
+ ioport_resource.end = ~0;
+
+ /* Intended to somewhat resemble ARM; see Documentation/arm/Booting */
+ if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
+ dtb = phys_to_virt(fw_arg2);
+ else if (__dtb_start != __dtb_end)
+ dtb = (void *)__dtb_start;
+ else
+ panic("no dtb found");
+
+ __dt_setup_arch(dtb);
+ strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+
+ for (q = bmips_quirk_list; q->quirk_fn; q++) {
+ if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
+ q->compatible)) {
+ q->quirk_fn();
+ }
+ }
+}
+
+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);
+}
+
+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;
+}
+
+int __init plat_of_setup(void)
+{
+ return __dt_register_buses("simple-bus", NULL);
+}
+
+arch_initcall(plat_of_setup);
+
+static int __init plat_dev_init(void)
+{
+ of_clk_init(NULL);
+ return 0;
+}
+
+device_initcall(plat_dev_init);
+
+const char *get_system_type(void)
+{
+ return "BMIPS multiplatform kernel";
+}
diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile
index ca9c90e2cabf..153d04489c46 100644
--- a/arch/mips/boot/dts/Makefile
+++ b/arch/mips/boot/dts/Makefile
@@ -1,4 +1,13 @@
dtb-$(CONFIG_CAVIUM_OCTEON_SOC) += octeon_3xxx.dtb octeon_68xx.dtb
+dtb-$(CONFIG_DT_BCM93384WVG) += bcm93384wvg.dtb
+dtb-$(CONFIG_DT_BCM93384WVG_VIPER) += bcm93384wvg_viper.dtb
+dtb-$(CONFIG_DT_BCM96368MVWG) += bcm96368mvwg.dtb
+dtb-$(CONFIG_DT_BCM9EJTAGPRB) += bcm9ejtagprb.dtb
+dtb-$(CONFIG_DT_BCM97125CBMB) += bcm97125cbmb.dtb
+dtb-$(CONFIG_DT_BCM97346DBSMB) += bcm97346dbsmb.dtb
+dtb-$(CONFIG_DT_BCM97360SVMB) += bcm97360svmb.dtb
+dtb-$(CONFIG_DT_BCM97420C) += bcm97420c.dtb
+dtb-$(CONFIG_DT_BCM97425SVMB) += bcm97425svmb.dtb
dtb-$(CONFIG_DT_EASY50712) += easy50712.dtb
dtb-$(CONFIG_DT_XLP_EVP) += xlp_evp.dtb
dtb-$(CONFIG_DT_XLP_SVP) += xlp_svp.dtb
diff --git a/arch/mips/boot/dts/bcm3384_viper.dtsi b/arch/mips/boot/dts/bcm3384_viper.dtsi
new file mode 100644
index 000000000000..8f803de68ac7
--- /dev/null
+++ b/arch/mips/boot/dts/bcm3384_viper.dtsi
@@ -0,0 +1,108 @@
+/ {
+ #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. */
+ 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 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <54000000>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "brcm,ubus", "simple-bus";
+ ranges;
+ /* No dma-ranges on Viper. */
+
+ 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>;
+ };
+
+ 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_zephyr.dtsi b/arch/mips/boot/dts/bcm3384_zephyr.dtsi
new file mode 100644
index 000000000000..37f46f41e527
--- /dev/null
+++ b/arch/mips/boot/dts/bcm3384_zephyr.dtsi
@@ -0,0 +1,126 @@
+/ {
+ #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>;
+ };
+
+ 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 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <54000000>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "brcm,ubus", "simple-bus";
+ ranges;
+ dma-ranges = <0x00000000 0x08000000 0x08000000>,
+ <0x08000000 0x00000000 0x08000000>;
+
+ 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>;
+ };
+
+ 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/bcm6328.dtsi b/arch/mips/boot/dts/bcm6328.dtsi
new file mode 100644
index 000000000000..648e8594145c
--- /dev/null
+++ b/arch/mips/boot/dts/bcm6328.dtsi
@@ -0,0 +1,87 @@
+/ {
+ #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>;
+ };
+
+ cpu@1 {
+ compatible = "brcm,bmips4350";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ periph_intc: periph_intc@10000020 {
+ 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";
+ };
+
+ timer: timer@10000040 {
+ compatible = "syscon";
+ reg = <0x10000040 0x2c>;
+ little-endian;
+ };
+
+ reboot {
+ compatible = "syscon-reboot";
+ regmap = <&timer>;
+ offset = <0x28>;
+ mask = <0x1>;
+ };
+ };
+};
diff --git a/arch/mips/boot/dts/bcm6368.dtsi b/arch/mips/boot/dts/bcm6368.dtsi
new file mode 100644
index 000000000000..dd11853a6ecb
--- /dev/null
+++ b/arch/mips/boot/dts/bcm6368.dtsi
@@ -0,0 +1,94 @@
+/ {
+ #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 {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ aliases {
+ uart0 = &uart0;
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ periph_intc: periph_intc@10000020 {
+ 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 000000000000..292ef0cf29ef
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7125.dtsi
@@ -0,0 +1,107 @@
+/ {
+ #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 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ clocks {
+ uart_clk: uart_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ rdb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges = <0 0x10000000 0x01000000>;
+
+ periph_intc: periph_intc@441400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x441400 0x30>, <0x441600 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@406780 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x406780 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <18>;
+ };
+
+ uart0: serial@406b00 {
+ compatible = "ns16550a";
+ reg = <0x406b00 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <21>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ ehci0: usb@488300 {
+ compatible = "brcm,bcm7125-ehci", "generic-ehci";
+ reg = <0x488300 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <60>;
+ status = "disabled";
+ };
+
+ ohci0: usb@488400 {
+ compatible = "brcm,bcm7125-ohci", "generic-ohci";
+ reg = <0x488400 0x100>;
+ native-endian;
+ 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 000000000000..ba2a91a4b111
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7346.dtsi
@@ -0,0 +1,192 @@
+/ {
+ #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 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ clocks {
+ uart_clk: uart_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ rdb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges = <0 0x10000000 0x01000000>;
+
+ periph_intc: periph_intc@411400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x411400 0x30>, <0x411600 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@406780 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x406780 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <59>;
+ };
+
+ uart0: serial@406900 {
+ compatible = "ns16550a";
+ reg = <0x406900 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <64>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ enet0: ethernet@430000 {
+ 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 = <0x430000 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@480300 {
+ compatible = "brcm,bcm7346-ehci", "generic-ehci";
+ reg = <0x480300 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <68>;
+ status = "disabled";
+ };
+
+ ohci0: usb@480400 {
+ compatible = "brcm,bcm7346-ohci", "generic-ohci";
+ reg = <0x480400 0x100>;
+ native-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <70>;
+ status = "disabled";
+ };
+
+ ehci1: usb@480500 {
+ compatible = "brcm,bcm7346-ehci", "generic-ehci";
+ reg = <0x480500 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <69>;
+ status = "disabled";
+ };
+
+ ohci1: usb@480600 {
+ compatible = "brcm,bcm7346-ohci", "generic-ohci";
+ reg = <0x480600 0x100>;
+ native-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <71>;
+ status = "disabled";
+ };
+
+ ehci2: usb@490300 {
+ compatible = "brcm,bcm7346-ehci", "generic-ehci";
+ reg = <0x490300 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <73>;
+ status = "disabled";
+ };
+
+ ohci2: usb@490400 {
+ compatible = "brcm,bcm7346-ohci", "generic-ohci";
+ reg = <0x490400 0x100>;
+ native-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <75>;
+ status = "disabled";
+ };
+
+ ehci3: usb@490500 {
+ compatible = "brcm,bcm7346-ehci", "generic-ehci";
+ reg = <0x490500 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <74>;
+ status = "disabled";
+ };
+
+ ohci3: usb@490600 {
+ compatible = "brcm,bcm7346-ohci", "generic-ohci";
+ reg = <0x490600 0x100>;
+ native-endian;
+ no-big-frame-no;
+ 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 000000000000..33fa02df0767
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7360.dtsi
@@ -0,0 +1,129 @@
+/ {
+ #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 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ clocks {
+ uart_clk: uart_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ rdb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges = <0 0x10000000 0x01000000>;
+
+ periph_intc: periph_intc@411400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x411400 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@406600 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x406600 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <56>;
+ };
+
+ uart0: serial@406800 {
+ compatible = "ns16550a";
+ reg = <0x406800 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <61>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ enet0: ethernet@430000 {
+ 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 = <0x430000 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@480300 {
+ compatible = "brcm,bcm7360-ehci", "generic-ehci";
+ reg = <0x480300 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <65>;
+ status = "disabled";
+ };
+
+ ohci0: usb@480400 {
+ compatible = "brcm,bcm7360-ohci", "generic-ohci";
+ reg = <0x480400 0x100>;
+ native-endian;
+ 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 000000000000..e100da00f93b
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7420.dtsi
@@ -0,0 +1,151 @@
+/ {
+ #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 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ clocks {
+ uart_clk: uart_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ rdb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges = <0 0x10000000 0x01000000>;
+
+ periph_intc: periph_intc@441400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x441400 0x30>, <0x441600 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@406780 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x406780 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <18>;
+ };
+
+ uart0: serial@406b00 {
+ compatible = "ns16550a";
+ reg = <0x406b00 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <21>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ enet0: ethernet@468000 {
+ 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 = <0x468000 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@488300 {
+ compatible = "brcm,bcm7420-ehci", "generic-ehci";
+ reg = <0x488300 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <60>;
+ status = "disabled";
+ };
+
+ ohci0: usb@488400 {
+ compatible = "brcm,bcm7420-ohci", "generic-ohci";
+ reg = <0x488400 0x100>;
+ native-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <61>;
+ status = "disabled";
+ };
+
+ ehci1: usb@488500 {
+ compatible = "brcm,bcm7420-ehci", "generic-ehci";
+ reg = <0x488500 0x100>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <55>;
+ status = "disabled";
+ };
+
+ ohci1: usb@488600 {
+ compatible = "brcm,bcm7420-ohci", "generic-ohci";
+ reg = <0x488600 0x100>;
+ native-endian;
+ no-big-frame-no;
+ 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 000000000000..6ea448a13879
--- /dev/null
+++ b/arch/mips/boot/dts/bcm7425.dtsi
@@ -0,0 +1,191 @@
+/ {
+ #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 {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ clocks {
+ uart_clk: uart_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <81000000>;
+ };
+ };
+
+ rdb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges = <0 0x10000000 0x01000000>;
+
+ periph_intc: periph_intc@41a400 {
+ compatible = "brcm,bcm7038-l1-intc";
+ reg = <0x41a400 0x30>, <0x41a600 0x30>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ upg_irq0_intc: upg_irq0_intc@406780 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x406780 0x8>;
+
+ brcm,int-map-mask = <0x44>;
+ brcm,int-fwd-mask = <0x70000>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <55>;
+ };
+
+ uart0: serial@406b00 {
+ compatible = "ns16550a";
+ reg = <0x406b00 0x20>;
+ reg-io-width = <0x4>;
+ reg-shift = <0x2>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <61>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ enet0: ethernet@b80000 {
+ 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 = <0xb80000 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@480300 {
+ compatible = "brcm,bcm7425-ehci", "generic-ehci";
+ reg = <0x480300 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <65>;
+ status = "disabled";
+ };
+
+ ohci0: usb@480400 {
+ compatible = "brcm,bcm7425-ohci", "generic-ohci";
+ reg = <0x480400 0x100>;
+ native-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <67>;
+ status = "disabled";
+ };
+
+ ehci1: usb@480500 {
+ compatible = "brcm,bcm7425-ehci", "generic-ehci";
+ reg = <0x480500 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <66>;
+ status = "disabled";
+ };
+
+ ohci1: usb@480600 {
+ compatible = "brcm,bcm7425-ohci", "generic-ohci";
+ reg = <0x480600 0x100>;
+ native-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <68>;
+ status = "disabled";
+ };
+
+ ehci2: usb@490300 {
+ compatible = "brcm,bcm7425-ehci", "generic-ehci";
+ reg = <0x490300 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <70>;
+ status = "disabled";
+ };
+
+ ohci2: usb@490400 {
+ compatible = "brcm,bcm7425-ohci", "generic-ohci";
+ reg = <0x490400 0x100>;
+ native-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <72>;
+ status = "disabled";
+ };
+
+ ehci3: usb@490500 {
+ compatible = "brcm,bcm7425-ehci", "generic-ehci";
+ reg = <0x490500 0x100>;
+ native-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <71>;
+ status = "disabled";
+ };
+
+ ohci3: usb@490600 {
+ compatible = "brcm,bcm7425-ohci", "generic-ohci";
+ reg = <0x490600 0x100>;
+ native-endian;
+ no-big-frame-no;
+ 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 000000000000..d1e44a17d41a
--- /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 000000000000..1ecb2696aca8
--- /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 000000000000..0e890c28fe5c
--- /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 000000000000..e046b1109eab
--- /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 000000000000..70f196d89d26
--- /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 000000000000..4fe515500102
--- /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 000000000000..67fe1f3a3891
--- /dev/null
+++ b/arch/mips/boot/dts/bcm97420c.dts
@@ -0,0 +1,45 @@
+/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 000000000000..689c68a4f9c8
--- /dev/null
+++ b/arch/mips/boot/dts/bcm97425svmb.dts
@@ -0,0 +1,60 @@
+/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 000000000000..1da4608680aa
--- /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 000000000000..7ab31664dcb1
--- /dev/null
+++ b/arch/mips/configs/bmips_be_defconfig
@@ -0,0 +1,86 @@
+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_POWER_SUPPLY=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+# 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 000000000000..c119d678f362
--- /dev/null
+++ b/arch/mips/configs/bmips_stb_defconfig
@@ -0,0 +1,86 @@
+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_POWER_SUPPLY=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+# 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 000000000000..5481a4d1bbbf
--- /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 000000000000..1f7bc6cb6160
--- /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 000000000000..65af1096cd6f
--- /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

2014-11-24 02:42:03

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 07/11] irqchip: Add new driver for BCM7038-style level 1 interrupt controllers

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 000000000000..cc217b22dccd
--- /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 018f884aa3b0..89ee92b8b94c 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 4954a314c31e..446ae7a98f7a 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 000000000000..d3b8c8be15f6
--- /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

2014-11-24 02:42:01

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 09/11] MIPS: Fall back to the generic restart notifier

If the machine doesn't set its own _machine_restart callback, call the
common do_kernel_restart() instead. This allows arch-independent reset
drivers from drivers/power/reset/ to be used to reboot the machine.

Signed-off-by: Kevin Cernekee <[email protected]>
---
arch/mips/kernel/reset.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/mips/kernel/reset.c b/arch/mips/kernel/reset.c
index 07fc5244aed4..cf23ab520701 100644
--- a/arch/mips/kernel/reset.c
+++ b/arch/mips/kernel/reset.c
@@ -29,6 +29,8 @@ void machine_restart(char *command)
{
if (_machine_restart)
_machine_restart(command);
+ else
+ do_kernel_restart(command);
}

void machine_halt(void)
--
2.1.1

2014-11-24 02:42:46

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 06/11] irqchip: bcm7120-l2: Change DT binding to allow non-contiguous IRQEN/IRQSTAT

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 bae1f2187226..e3b0cba9489a 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 e8441ee7454c..576a92b34372 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

2014-11-24 02:41:01

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 05/11] irqchip: bcm7120-l2: Refactor driver for arbitrary IRQEN/IRQSTAT offsets

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 8eec8e1201d9..e8441ee7454c 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

2014-11-24 02:43:36

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 03/11] irqchip: brcmstb-l2: fix error handling of irq_of_parse_and_map

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 4edd27c486c4..d6bcc6be0777 100644
--- a/drivers/irqchip/irq-brcmstb-l2.c
+++ b/drivers/irqchip/irq-brcmstb-l2.c
@@ -143,9 +143,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

2014-11-24 02:44:05

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V3 01/11] irqchip: Update docs regarding irq_domain_add_tree()

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 8a8b82c9ca53..0ccd7b7f6043 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

2014-11-24 13:34:59

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH V3 00/11] Multiplatform BMIPS kernel

On Sunday 23 November 2014 18:40:35 Kevin Cernekee wrote:

> V2->V3:
>
> - Omit the BMIPS updates that have already been accepted into Ralf's tree.
> They are still needed, but not reposted.
>
> - Make USB endian swap options conditional on "if CPU_BIG_ENDIAN".
>
> - Remove board listing from Documentation/devicetree/bindings/mips/brcm/soc.txt
>
> - Remove legacy device autodetection and chip ID decoding. Legacy
> boards/bootloaders will be supported by selecting a single DTB file
> to compile into the kernel.
>
> - Refactor quirks code to match against DT "compatible" strings, not chip IDs.
>
> - Fix CPU1 boot (missing DT node) on 6329.
>
> - Remove @0 / addressing properties on non-reg nodes.
>
> - Remove bogus "brcm,bmips" bus registration.
>
> - Move UBUS peripherals onto a "simple-bus" and set DMA ranges for this
> bus on bcm3384_zephyr.
>
> - Fix base addresses on 6328/6368 for "periph_intc@10000020".
>
> - Change the MIPS_L1_CACHE_SHIFT calculation so as to minimize the impact
> on other builds (like bcm63xx).

Looks nice to me overall, with the new way of handling the dtb passing,
this seems much more flexible, and I guess it can be turned into an
actual multiplatform build if there is ever a desire to do that.

> Re: dma-ranges
>
> dma.c implements a minimal remapping scheme just for the current UBUS
> peripherals. The remapping is global, and it isn't the same mapping
> needed for PCI(e). A more comprehensive solution will be needed before
> PCI support can be added.
>
> On chips OTHER than 3384, remapping is only required on PCI (not UBUS or
> "rdb"). Notably, BCM7445, an ARM platform currently supported upstream,
> doesn't require dma-ranges for non-PCI devices.
>
> I am hoping we can piggyback on top of the ARM dma-ranges code once it
> is merged. This will allow for eliminating my dma.c.

Sounds good.

Arnd

2014-11-24 14:00:40

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

On Sunday 23 November 2014 18:40:46 Kevin Cernekee 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
> - 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, so they will need to select an appropriate builtin DTB at
> compile time until the bootloader is updated.
>
> Signed-off-by: Kevin Cernekee <[email protected]>

It mihgt be good to split this into multiple patches


> ---
> .../devicetree/bindings/mips/brcm/bmips.txt | 8 +
> .../devicetree/bindings/mips/brcm/soc.txt | 12 ++
> arch/mips/Kbuild.platforms | 1 +
> arch/mips/Kconfig | 36 ++++
> arch/mips/bmips/Kconfig | 50 ++++++
> arch/mips/bmips/Makefile | 1 +
> arch/mips/bmips/Platform | 7 +
> arch/mips/bmips/dma.c | 141 +++++++++++++++
> arch/mips/bmips/irq.c | 38 ++++
> arch/mips/bmips/setup.c | 195 +++++++++++++++++++++
> arch/mips/boot/dts/Makefile | 9 +
> arch/mips/boot/dts/bcm3384_viper.dtsi | 108 ++++++++++++
> arch/mips/boot/dts/bcm3384_zephyr.dtsi | 126 +++++++++++++
> arch/mips/boot/dts/bcm6328.dtsi | 87 +++++++++
> arch/mips/boot/dts/bcm6368.dtsi | 94 ++++++++++
> arch/mips/boot/dts/bcm7125.dtsi | 107 +++++++++++
> arch/mips/boot/dts/bcm7346.dtsi | 192 ++++++++++++++++++++
> arch/mips/boot/dts/bcm7360.dtsi | 129 ++++++++++++++
> arch/mips/boot/dts/bcm7420.dtsi | 151 ++++++++++++++++
> arch/mips/boot/dts/bcm7425.dtsi | 191 ++++++++++++++++++++

I hadn't noticed before that the dts files are now all in one
directory on MIPS, apparently after a patch from Andrew Brewsticker.
We should really coordinate these things better, we have just merged
an arm64 patch to split out the files into multiple directories.

> --- /dev/null
> +++ b/arch/mips/bmips/Kconfig
> @@ -0,0 +1,50 @@
> +choice
> + prompt "Built-in device tree"
> + help
> + Legacy bootloaders do not pass a DTB pointer to the kernel, so
> + if a "wrapper" is not being used, the kernel will need to include
> + a device tree that matches the target board.
> +
> + The builtin DTB will only be used if the firmware does not supply
> + a valid DTB.
> +
> +config DT_NONE
> + bool "None"
> +
> +config DT_BCM93384WVG
> + bool "BCM93384WVG Zephyr CPU"
> + select BUILTIN_DTB
> +
> +config DT_BCM93384WVG_VIPER
> + bool "BCM93384WVG Viper CPU (EXPERIMENTAL)"
> + select BUILTIN_DTB

Why do you have to pick just one? I liked the suggestion of just
appending the dtb to the zImage as we do on ARM, so you can build
a combined kernel and then run it on multiple machines.

> diff --git a/arch/mips/bmips/irq.c b/arch/mips/bmips/irq.c
> new file mode 100644
> index 000000000000..14552e58ff7e
> --- /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;
> +}

Could this just become a function pointer instead of a global
variable?

> +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);

OF_DECLARE_2 really wasn't meant to be used directly. Can you move this
code into drivers/irqchip and make it use IRQCHIP_DECLARE()?

> +
> +static const struct bmips_quirk bmips_quirk_list[] = {
> + { "brcm,bcm3384-viper", &bcm3384_viper_quirks },
> + { "brcm,bcm33843-viper", &bcm3384_viper_quirks },
> + { "brcm,bcm6328", &bcm6328_quirks },
> + { "brcm,bcm6368", &bcm6368_quirks },
> + { },
> +};
> +
> +void __init prom_init(void)
> +{
> + register_bmips_smp_ops();
> +}

This seems to be the wrong place for calling this function.

> +void __init prom_free_prom_memory(void)
> +{
> +}

This in turn could live outside of the platform codefor anything
that is "multiplatform".

> +void __init plat_mem_setup(void)
> +{
> + void *dtb;
> + const struct bmips_quirk *q;
> +
> + set_io_port_base(0);
> + ioport_resource.start = 0;
> + ioport_resource.end = ~0;

ioport_resource must not extend beyond IO_SPACE_LIMIT, which is
0xffff on MIPS. setting the I/O port base to zero is probably
not what you want. What are you trying to do here?

Maybe defer this until you have PCI support? The new generic PCI
handling should make this really easy to get right.

> + /* Intended to somewhat resemble ARM; see Documentation/arm/Booting */
> + if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
> + dtb = phys_to_virt(fw_arg2);
> + else if (__dtb_start != __dtb_end)
> + dtb = (void *)__dtb_start;
> + else
> + panic("no dtb found");
> +
> + __dt_setup_arch(dtb);
> + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);

Is this intended to become a generic MIPS boot interface? Better
document it in Documentation/mips/

> + for (q = bmips_quirk_list; q->quirk_fn; q++) {
> + if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
> + q->compatible)) {
> + q->quirk_fn();
> + }
> + }
> +}
> +

nice

> +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);
> +}

this looks also like it should be in platform
independent code

> +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;
> +}

Could this be part of a drivers/clocksource driver?

> +
> +int __init plat_of_setup(void)
> +{
> + return __dt_register_buses("simple-bus", NULL);
> +}
> +
> +arch_initcall(plat_of_setup);
> +
> +static int __init plat_dev_init(void)
> +{
> + of_clk_init(NULL);
> + return 0;
> +}
> +
> +device_initcall(plat_dev_init);
> +
> +const char *get_system_type(void)
> +{
> + return "BMIPS multiplatform kernel";
> +}

You could set the string from bmips_quirk_list and make this generic
as well.

> 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 000000000000..5481a4d1bbbf
> --- /dev/null
> +++ b/arch/mips/include/asm/mach-bmips/dma-coherence.h
> @@ -0,0 +1,45 @@
> +#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);

I think you could just add these to
arch/mips/include/asm/mach-generic/dma-coherence.h and get rid of the
header file, after adding a Kconfig symbol.

> 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 000000000000..1f7bc6cb6160
> --- /dev/null
> +++ b/arch/mips/include/asm/mach-bmips/spaces.h
> @@ -0,0 +1,17 @@
> +#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 */

Why does this platform need a special FIXADDR_TOP value? Would either
this value or the 0xfffe0000 from
arch/mips/include/asm/mach-generic/spaces.h would everywhere?

> 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 000000000000..65af1096cd6f
> --- /dev/null
> +++ b/arch/mips/include/asm/mach-bmips/war.h
> @@ -0,0 +1,24 @@
> +#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
> ...

As mentioned before, it seems like you are simply defining these all to zero,
like most other platforms do too. Why not add this file as
arch/mips/include/asm/mach-generic/war.h and delete all identical copies?

Arnd

2014-11-24 14:32:17

by Jonas Gorski

[permalink] [raw]
Subject: Re: [PATCH V3 06/11] irqchip: bcm7120-l2: Change DT binding to allow non-contiguous IRQEN/IRQSTAT

On Mon, Nov 24, 2014 at 3:40 AM, Kevin Cernekee <[email protected]> wrote:
> 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]>

Hmm ... the more I think about this, the less I like it.

Using the amount and size of the reg-properties to infer a certain
layout seems rather hackish and dirty to me. Maybe we should just use
different compatible match ids for that? E.g. brcm,bm7120-l2-intc for
the 32-bit en/stat pairs, and e.g. brcm,bcm6368-l2-intc for the 64-bit
wide one. Or maybe make the bcm63xx one a separate driver and let it
share code with the bcm7120-l2-intc driver.

This would avoid having to specify a lot of regs (let's assume we also
add support for affinity), and cause a lot of io(re)map calls - the
bcm63268 one would currently look like:

reg = <0x1000002c 0x4 0x1000003c 0x4>, /* irq 0..31 -> mips irq 2 */
<0x10000028 0x4 0x10000038 0x4>, /* irq 32..63 -> mips irq 2 */
<0x10000024 0x4 0x10000034 0x4>, /* irq 64 .. 95 -> mips irq 2 */
<0x10000020 0x4 0x10000030 0x4>, /* irq 96 .. 127 ->
mips irq 2 */
<0x1000004c 0x4 0x1000005c 0x4>, /* irq 0.. 31 -> mips irq 3 */
<0x10000048 0x4 0x10000058 0x4>, /* irq 32 .. 63 -> mips irq 3 */
<0x10000044 0x4 0x10000054 0x4>, /* irq 64 ... 95 ->
mips irq 3 */
<0x10000040 0x4 0x10000050 0x4>; /* irq 96 ... 127 ->
mips irq 3 */

where as with a different match id, we could rather allow something like

reg = <0x10000020 0x20>, /* irq 0..127 -> mips irq 2 */
<0x10000040 0x20>; /* irq 0..127 -> mips irq 3 */


This would make the dts(i) files quite a bit more readable IMHO, and
make it more likely that newer dts(i) files work with older kernels,
e.g. where the mips irq3 routed registers were added - in the current
style, the kernel would interpret these as additional irq banks. Not
that I think this is expected/required to work, but it wouldn't hurt
having at least a bit of backward compatibility for bisecting on a
device that provides a newer dtb through the bootloader.


Jonas

2014-11-24 18:34:18

by Andrew Bresticker

[permalink] [raw]
Subject: Re: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

Hi,

On Mon, Nov 24, 2014 at 6:00 AM, Arnd Bergmann <[email protected]> wrote:
>> ---
>> .../devicetree/bindings/mips/brcm/bmips.txt | 8 +
>> .../devicetree/bindings/mips/brcm/soc.txt | 12 ++
>> arch/mips/Kbuild.platforms | 1 +
>> arch/mips/Kconfig | 36 ++++
>> arch/mips/bmips/Kconfig | 50 ++++++
>> arch/mips/bmips/Makefile | 1 +
>> arch/mips/bmips/Platform | 7 +
>> arch/mips/bmips/dma.c | 141 +++++++++++++++
>> arch/mips/bmips/irq.c | 38 ++++
>> arch/mips/bmips/setup.c | 195 +++++++++++++++++++++
>> arch/mips/boot/dts/Makefile | 9 +
>> arch/mips/boot/dts/bcm3384_viper.dtsi | 108 ++++++++++++
>> arch/mips/boot/dts/bcm3384_zephyr.dtsi | 126 +++++++++++++
>> arch/mips/boot/dts/bcm6328.dtsi | 87 +++++++++
>> arch/mips/boot/dts/bcm6368.dtsi | 94 ++++++++++
>> arch/mips/boot/dts/bcm7125.dtsi | 107 +++++++++++
>> arch/mips/boot/dts/bcm7346.dtsi | 192 ++++++++++++++++++++
>> arch/mips/boot/dts/bcm7360.dtsi | 129 ++++++++++++++
>> arch/mips/boot/dts/bcm7420.dtsi | 151 ++++++++++++++++
>> arch/mips/boot/dts/bcm7425.dtsi | 191 ++++++++++++++++++++
>
> I hadn't noticed before that the dts files are now all in one
> directory on MIPS, apparently after a patch from Andrew Brewsticker.
> We should really coordinate these things better, we have just merged
> an arm64 patch to split out the files into multiple directories.

FWIW, I'm planning on sending a patch once 3.19-rc1 is released to
move the DTs into per-vendor sub-directories. I was expecting to do
it for 3.19, but Robert Richter's series which added kbuild support
for the vendor sub-directories did not end up landing in 3.18.

2014-11-24 19:29:43

by Andrew Bresticker

[permalink] [raw]
Subject: Re: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

> diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c

> +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;
> +}

Could you use common clock framework for this? Isn't the HPT just a
fixed factor of the CPU clock? I'm planning on doing something very
similar for ImgTec MIPS SoCs, so perhaps this could go in a common
place, like the r4k clocksource driver?

2014-11-24 19:57:31

by Kevin Cernekee

[permalink] [raw]
Subject: Re: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

On Mon, Nov 24, 2014 at 11:29 AM, Andrew Bresticker <[email protected]> wrote:
>> diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c
>
>> +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;
>> +}
>
> Could you use common clock framework for this? Isn't the HPT just a
> fixed factor of the CPU clock? I'm planning on doing something very
> similar for ImgTec MIPS SoCs, so perhaps this could go in a common
> place, like the r4k clocksource driver?

Jonas and I had tossed some ideas around earlier, and I included a few
random thoughts in the cover letter.

One concern is that this currently has to be set pretty early in the
boot process (prior to jiffies calibration IIRC), so it might still
need to be handled as a special case.

Regarding the "fixed factor" question: that is true on all of the
chips I've seen, with a few additional caveats:

- Most MIPS cores use cpu_clk/2, but BMIPS5000 uses cpu_clk/8.

- Some MIPS cores scale the CP0 counter frequency when the cpu_clk is
changed, but others do not. Sometimes this depends on the core rev
(e.g. 65nm BMIPS438x cores do scale, but 40nm BMIPS438x cores do not).

- We might not necessarily have a good way to determine cpu_clk on
every platform, either.

2014-11-24 21:08:10

by Kevin Cernekee

[permalink] [raw]
Subject: Re: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

On Mon, Nov 24, 2014 at 6:00 AM, Arnd Bergmann <[email protected]> wrote:
> It mihgt be good to split this into multiple patches

OK. For V4 I could submit the arch/mips/bmips code changes in one
patch, and then add the DTS files in the next patch?

>> --- /dev/null
>> +++ b/arch/mips/bmips/Kconfig
>> @@ -0,0 +1,50 @@
>> +choice
>> + prompt "Built-in device tree"
>> + help
>> + Legacy bootloaders do not pass a DTB pointer to the kernel, so
>> + if a "wrapper" is not being used, the kernel will need to include
>> + a device tree that matches the target board.
>> +
>> + The builtin DTB will only be used if the firmware does not supply
>> + a valid DTB.
>> +
>> +config DT_NONE
>> + bool "None"
>> +
>> +config DT_BCM93384WVG
>> + bool "BCM93384WVG Zephyr CPU"
>> + select BUILTIN_DTB
>> +
>> +config DT_BCM93384WVG_VIPER
>> + bool "BCM93384WVG Viper CPU (EXPERIMENTAL)"
>> + select BUILTIN_DTB
>
> Why do you have to pick just one? I liked the suggestion of just
> appending the dtb to the zImage as we do on ARM, so you can build
> a combined kernel and then run it on multiple machines.

I'm not sure this exists yet on MIPS. Perhaps we can discuss it as a
possible future enhancement to the general arch/mips code?

One possible complication is that we're mostly using ELF images on
MIPS, not zImage. Is it easy to calculate the end address of an ELF
file?

If there is no PT_LOAD segment for the blob, will the bootloader even
copy it into memory?

>> +unsigned int get_c0_compare_int(void)
>> +{
>> + return CP0_LEGACY_COMPARE_IRQ;
>> +}
>
> Could this just become a function pointer instead of a global
> variable?

>> +void __init prom_free_prom_memory(void)
>> +{
>> +}
>
> This in turn could live outside of the platform codefor anything
> that is "multiplatform".

>> +#define R4600_V1_INDEX_ICACHEOP_WAR 0
>> +#define R4600_V1_HIT_CACHEOP_WAR 0
>> +#define R4600_V2_HIT_CACHEOP_WAR 0
>> ...
>
> As mentioned before, it seems like you are simply defining these all to zero,
> like most other platforms do too. Why not add this file as
> arch/mips/include/asm/mach-generic/war.h and delete all identical copies?

Likewise - currently every existing MIPS machine type implements it this way.

Perhaps a future patch series can generalize the way these definitions
are handled on MIPS?

>> +OF_DECLARE_2(irqchip, mips_cpu_intc, "mti,cpu-interrupt-controller",
>> + mips_cpu_irq_of_init);
>
> OF_DECLARE_2 really wasn't meant to be used directly. Can you move this
> code into drivers/irqchip and make it use IRQCHIP_DECLARE()?

Perhaps arch/mips/kernel/irq_cpu.c could be moved under
drivers/irqchip in a future commit? We'll probably have to change the
way arch/mips/ralink invokes it too.

Also, as a side note, it would be nice if irq_cpu.c let me cascade
child IRQ controllers on a specific CPU. For instance, some of our
hardware looks like:

CPU0 MIPS IRQ 2 -> bcm7038 L1 instance #0
CPU1 MIPS IRQ 3 -> bcm7038 L1 instance #1
CPU2 MIPS IRQ 2 -> bcm7038 L1 instance #2
CPU3 MIPS IRQ 3 -> bcm7038 L1 instance #3

These would be handled by a single "brcm,bcm7038-l1-intc" DT node
which lists the 4 parent IRQs individually. We'll need this
capability to support IRQ affinity with 4-way SMP on BCM7435.

>> +void __init prom_init(void)
>> +{
>> + register_bmips_smp_ops();
>> +}
>
> This seems to be the wrong place for calling this function.

Hmm, looking around the tree:

cavium-octeon, ip27, loongson, netlogic xlr, paravirt, and sibyte call
register_smp_ops() from prom_init().

netlogic xlp calls it from plat_mem_setup().

>> +void __init plat_mem_setup(void)
>> +{
>> + void *dtb;
>> + const struct bmips_quirk *q;
>> +
>> + set_io_port_base(0);
>> + ioport_resource.start = 0;
>> + ioport_resource.end = ~0;
>
> ioport_resource must not extend beyond IO_SPACE_LIMIT, which is
> 0xffff on MIPS. setting the I/O port base to zero is probably
> not what you want. What are you trying to do here?

Blindly plagiarize the bcm63xx/netlogic/pnx833x implementations ;-)

> Maybe defer this until you have PCI support? The new generic PCI
> handling should make this really easy to get right.

OK, I'll drop this code in V4 if nothing breaks.

>> + /* Intended to somewhat resemble ARM; see Documentation/arm/Booting */
>> + if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
>> + dtb = phys_to_virt(fw_arg2);
>> + else if (__dtb_start != __dtb_end)
>> + dtb = (void *)__dtb_start;
>> + else
>> + panic("no dtb found");
>> +
>> + __dt_setup_arch(dtb);
>> + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
>
> Is this intended to become a generic MIPS boot interface? Better
> document it in Documentation/mips/

Not sure yet. It's currently limited to BCM3384.

For V4 I can add an "Entry point for arch/mips/bmips" or even an
"Entry point for arch/mips" section to
Documentation/devicetree/booting-without-of.txt. Any preferences?

>> +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);
>> +}
>
> this looks also like it should be in platform
> independent code

Hmm. Do we want to add some logic to kernel/smp.c or kernel/cpu.c
that says something like: if there is a "cpus" node, clear
cpu_possible_mask and then set the corresponding bit for each cpu@N
listed in the DT?

Unfortunately, if enabled by default, this could impact a lot of other
systems too.

Another option is to make a generic helper function that individual
platforms can call to say "populate my CPU bitmap from DT," maybe
something like of_set_possible_cpus().

>> +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;
>> +}
>
> Could this be part of a drivers/clocksource driver?

See earlier replies / cover letter

>> +const char *get_system_type(void)
>> +{
>> + return "BMIPS multiplatform kernel";
>> +}
>
> You could set the string from bmips_quirk_list and make this generic
> as well.

The way it currently looks is:

# cat /proc/cpuinfo
system type : BMIPS multiplatform kernel
machine : Broadcom BCM97425SVMB
processor : 0
cpu model : Broadcom BMIPS5000 V1.1 FPU V0.1
BogoMIPS : 866.30
wait instruction : yes
microsecond timers : yes
tlb_entries : 64
extra interrupt vector : yes
hardware watchpoint : no
isa : mips1 mips2 mips32r1
[...]

So this indicates:

system type: the kernel build
machine: the board name from DT
cpu model: the detected CPU type

I would rather not tie quirks to the system identity, as sane
legacy-free systems (such as bcm3384-zephyr) probably shouldn't have
quirks.

>> 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 000000000000..5481a4d1bbbf
>> --- /dev/null
>> +++ b/arch/mips/include/asm/mach-bmips/dma-coherence.h
>> @@ -0,0 +1,45 @@
>> +#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);
>
> I think you could just add these to
> arch/mips/include/asm/mach-generic/dma-coherence.h and get rid of the
> header file, after adding a Kconfig symbol.

Some platforms mix and match inline definitions versus externs in this file.

Maybe Ralf can comment on whether we should move to an "all or nothing" model?

>> 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 000000000000..1f7bc6cb6160
>> --- /dev/null
>> +++ b/arch/mips/include/asm/mach-bmips/spaces.h
>> @@ -0,0 +1,17 @@
>> +#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 */
>
> Why does this platform need a special FIXADDR_TOP value?

I thought I documented this somewhere but I can't find it now. I'll
add a comment in V4. BMIPS does need a special value as there are
registers in this range.

> Would either
> this value or the 0xfffe0000 from
> arch/mips/include/asm/mach-generic/spaces.h would everywhere?

I would have to defer to the other MIPS guys...

The other question is what "everywhere" means in this context. Maybe
we want to just use 0xff00_0000 for a multiplatform kernel, and any
system that is too obscure or too "weird" would continue using its own
build.

2014-11-24 21:39:43

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

On Monday 24 November 2014 13:07:46 Kevin Cernekee wrote:
> On Mon, Nov 24, 2014 at 6:00 AM, Arnd Bergmann <[email protected]> wrote:
> > It mihgt be good to split this into multiple patches
>
> OK. For V4 I could submit the arch/mips/bmips code changes in one
> patch, and then add the DTS files in the next patch?

Sounds good.

> >> --- /dev/null
> >> +++ b/arch/mips/bmips/Kconfig
> >> @@ -0,0 +1,50 @@
> >> +choice
> >> + prompt "Built-in device tree"
> >> + help
> >> + Legacy bootloaders do not pass a DTB pointer to the kernel, so
> >> + if a "wrapper" is not being used, the kernel will need to include
> >> + a device tree that matches the target board.
> >> +
> >> + The builtin DTB will only be used if the firmware does not supply
> >> + a valid DTB.
> >> +
> >> +config DT_NONE
> >> + bool "None"
> >> +
> >> +config DT_BCM93384WVG
> >> + bool "BCM93384WVG Zephyr CPU"
> >> + select BUILTIN_DTB
> >> +
> >> +config DT_BCM93384WVG_VIPER
> >> + bool "BCM93384WVG Viper CPU (EXPERIMENTAL)"
> >> + select BUILTIN_DTB
> >
> > Why do you have to pick just one? I liked the suggestion of just
> > appending the dtb to the zImage as we do on ARM, so you can build
> > a combined kernel and then run it on multiple machines.
>
> I'm not sure this exists yet on MIPS. Perhaps we can discuss it as a
> possible future enhancement to the general arch/mips code?

I don't remember who said it, but someone commented on v2 that they
had a patch for this.

> One possible complication is that we're mostly using ELF images on
> MIPS, not zImage. Is it easy to calculate the end address of an ELF
> file?
>
> If there is no PT_LOAD segment for the blob, will the bootloader even
> copy it into memory?

Don't know

> >> +unsigned int get_c0_compare_int(void)
> >> +{
> >> + return CP0_LEGACY_COMPARE_IRQ;
> >> +}
> >
> > Could this just become a function pointer instead of a global
> > variable?
>
> >> +void __init prom_free_prom_memory(void)
> >> +{
> >> +}
> >
> > This in turn could live outside of the platform codefor anything
> > that is "multiplatform".
>
> >> +#define R4600_V1_INDEX_ICACHEOP_WAR 0
> >> +#define R4600_V1_HIT_CACHEOP_WAR 0
> >> +#define R4600_V2_HIT_CACHEOP_WAR 0
> >> ...
> >
> > As mentioned before, it seems like you are simply defining these all to zero,
> > like most other platforms do too. Why not add this file as
> > arch/mips/include/asm/mach-generic/war.h and delete all identical copies?
>
> Likewise - currently every existing MIPS machine type implements it this way.
>
> Perhaps a future patch series can generalize the way these definitions
> are handled on MIPS?

I'd like to hear what Ralf thinks about it, it's really his decision.
What I was pointing out here are things that are still in the way of
a real "multiplatform" implementation. None of these are really hard
to do, but I don't know where you are heading with MIPS.

I think in case of the last one, it's really just a matter of moving the
file, you could delete the other copies later.


> >> +OF_DECLARE_2(irqchip, mips_cpu_intc, "mti,cpu-interrupt-controller",
> >> + mips_cpu_irq_of_init);
> >
> > OF_DECLARE_2 really wasn't meant to be used directly. Can you move this
> > code into drivers/irqchip and make it use IRQCHIP_DECLARE()?
>
> Perhaps arch/mips/kernel/irq_cpu.c could be moved under
> drivers/irqchip in a future commit? We'll probably have to change the
> way arch/mips/ralink invokes it too.

Possibly, but that seems unrelated. Moving this file is required
in order to use IRQCHIP_DECLARE, which is defined in
drivers/irqchip/irqchip.h.

> >> +void __init prom_init(void)
> >> +{
> >> + register_bmips_smp_ops();
> >> +}
> >
> > This seems to be the wrong place for calling this function.
>
> Hmm, looking around the tree:
>
> cavium-octeon, ip27, loongson, netlogic xlr, paravirt, and sibyte call
> register_smp_ops() from prom_init().
>
> netlogic xlp calls it from plat_mem_setup().

I guess prom_init() doesn't do what I expected it to on MIPS then.
On powerpc, this is where we call into Open Firmware. No point changing
it now I guess.

For a real multiplatform kernel, the function would likely have to
be matched up with a root DT compatible property like your fixups.

> >> + /* Intended to somewhat resemble ARM; see Documentation/arm/Booting */
> >> + if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
> >> + dtb = phys_to_virt(fw_arg2);
> >> + else if (__dtb_start != __dtb_end)
> >> + dtb = (void *)__dtb_start;
> >> + else
> >> + panic("no dtb found");
> >> +
> >> + __dt_setup_arch(dtb);
> >> + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
> >
> > Is this intended to become a generic MIPS boot interface? Better
> > document it in Documentation/mips/
>
> Not sure yet. It's currently limited to BCM3384.
>
> For V4 I can add an "Entry point for arch/mips/bmips" or even an
> "Entry point for arch/mips" section to
> Documentation/devicetree/booting-without-of.txt. Any preferences?

If the goal is being able to have a multiplatform kernel
that can cover more than just BMIPS, I think this would have
to be documented as the only way for MIPS multiplatform.

If that isn't possible, most of my other comments here are
moot, but then you shouldn't call it "multiplatform" but just
"generic BMIPS" or something like that.

> >> +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);
> >> +}
> >
> > this looks also like it should be in platform
> > independent code
>
> Hmm. Do we want to add some logic to kernel/smp.c or kernel/cpu.c
> that says something like: if there is a "cpus" node, clear
> cpu_possible_mask and then set the corresponding bit for each cpu@N
> listed in the DT?
>
> Unfortunately, if enabled by default, this could impact a lot of other
> systems too.
>
> Another option is to make a generic helper function that individual
> platforms can call to say "populate my CPU bitmap from DT," maybe
> something like of_set_possible_cpus().

I would do it for all "multiplatform" implementations, i.e. BMIPS
for now and then any other platform that is ready to convert to that.

The existing platforms already provide their own device_tree_init()
function already.

> >> +const char *get_system_type(void)
> >> +{
> >> + return "BMIPS multiplatform kernel";
> >> +}
> >
> > You could set the string from bmips_quirk_list and make this generic
> > as well.
>
> The way it currently looks is:
>
> # cat /proc/cpuinfo
> system type : BMIPS multiplatform kernel
> machine : Broadcom BCM97425SVMB
> processor : 0
> cpu model : Broadcom BMIPS5000 V1.1 FPU V0.1
> BogoMIPS : 866.30
> wait instruction : yes
> microsecond timers : yes
> tlb_entries : 64
> extra interrupt vector : yes
> hardware watchpoint : no
> isa : mips1 mips2 mips32r1
> [...]
>
> So this indicates:
>
> system type: the kernel build
> machine: the board name from DT
> cpu model: the detected CPU type
>
> I would rather not tie quirks to the system identity, as sane
> legacy-free systems (such as bcm3384-zephyr) probably shouldn't have
> quirks.

Ok, got it. So in a multiplatform kernel, this would be another function
pointer I guess, but it would always return this string for any BMIPS
system.

> >> 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 000000000000..5481a4d1bbbf
> >> --- /dev/null
> >> +++ b/arch/mips/include/asm/mach-bmips/dma-coherence.h
> >> @@ -0,0 +1,45 @@
> >> +#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);
> >
> > I think you could just add these to
> > arch/mips/include/asm/mach-generic/dma-coherence.h and get rid of the
> > header file, after adding a Kconfig symbol.
>
> Some platforms mix and match inline definitions versus externs in this file.
>
> Maybe Ralf can comment on whether we should move to an "all or nothing" model?

To clarify where I was getting to here: In a generic multiplatform kernel,
you would probably want to always look at the dma-ranges properties here,
at least if there are one or more platforms built into the kernel that
don't just have a flat mapping that the current mach-generic header
provides.

> > Would either
> > this value or the 0xfffe0000 from
> > arch/mips/include/asm/mach-generic/spaces.h would everywhere?
>
> I would have to defer to the other MIPS guys...
>
> The other question is what "everywhere" means in this context. Maybe
> we want to just use 0xff00_0000 for a multiplatform kernel, and any
> system that is too obscure or too "weird" would continue using its own
> build.

I mean every system that today uses the plain mach-generic/spaces.h.

Arnd

2014-11-26 05:19:08

by Kevin Cernekee

[permalink] [raw]
Subject: Re: [PATCH V3 06/11] irqchip: bcm7120-l2: Change DT binding to allow non-contiguous IRQEN/IRQSTAT

On Mon, Nov 24, 2014 at 6:31 AM, Jonas Gorski <[email protected]> wrote:
> On Mon, Nov 24, 2014 at 3:40 AM, Kevin Cernekee <[email protected]> wrote:
>> 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]>
>
> Hmm ... the more I think about this, the less I like it.
>
> Using the amount and size of the reg-properties to infer a certain
> layout seems rather hackish and dirty to me. Maybe we should just use
> different compatible match ids for that? E.g. brcm,bm7120-l2-intc for
> the 32-bit en/stat pairs, and e.g. brcm,bcm6368-l2-intc for the 64-bit
> wide one. Or maybe make the bcm63xx one a separate driver and let it
> share code with the bcm7120-l2-intc driver.

In my current proposal, it is easy to specify an arbitrary number of
enable/status pairs located in any order and spread across different
parts of the register space. Even register indices (0,2,4,...) are
enable registers, and odd register indices are status registers.

If I'm interpreting your post correctly, you don't agree that we need
this level of flexibility. But looking over the register listings,
here are the cases we need to cover:


6828,6318: 4x mask(exthi,extlo,hi,lo),status(exthi,extlo,hi,lo)

TP0ExtIrqMaskHi
TP0ExtIrqMaskLo
TP0IrqMaskHi
TP0IrqMaskLo
TP0ExtIrqStatusHi
TP0ExtIrqStatusLo
TP0IrqStatusHi
TP0IrqStatusLo

TP1ExtIrqMaskHi
TP1ExtIrqMaskLo
...


6816,6362,6328: 2x extmask,mask,extstatus,status

ExtraChipIrqMask
ChipIrqMask
ExtraChipIrqStatus
ChipIrqStatus
ExtraChipIrqMask1 [1=TP1]
ChipIrqMask1
ExtraChipIrqStatus1
ChipIrqStatus1


6368: similar to above, but with yet another naming convention:

IRQMASK_MIPS0_Hi
IRQMASK_MIPS0_Lo
IRQSTATUS_MIPS0_Hi
IRQSTATUS_MIPS0_Lo
IRQMASK_MIPS1_Hi
IRQMASK_MIPS1_Lo
IRQSTATUS_MIPS1_Hi
IRQSTATUS_MIPS1_Lo



6838,3384: interleaved "mystery meat" mask/status (same IRQ source
names, with the output of each bcm7120-l2 routed to several different
processors/threads):

PeriphIRQMASK0
PeriphIRQSTATUS0
PeriphIRQMASK1 <- mine, if running on Zephyr
PeriphIRQSTATUS1 <- mine, if running on Zephyr
PeriphIRQMASK2
PeriphIRQSTATUS2
PeriphIRQMASK3 <- mine, if running on Viper
PeriphIRQSTATUS3 <- mine, if running on Viper

But wait, there's more! There wasn't enough space in this block for
>32 IRQ bits, so the upper bits spilled over into a separate
"INT_EXT_PER" block that lives elsewhere in the register space:

PeriphIRQMASK0_2
PeriphIRQSTATUS0_2
PeriphIRQMASK1_2 <- mine, if running on Zephyr
PeriphIRQSTATUS1_2 <- mine, if running on Zephyr
PeriphIRQMASK2_2
PeriphIRQSTATUS2_2
PeriphIRQMASK3_2 <- mine, if running on Viper
PeriphIRQSTATUS3_2 <- mine, if running on Viper

The "INT_PER" and "INT_EXT_PER" outputs are ORed into the same MIPS
IRQ lines, so we need to treat them as two sides of a single
controller. AFAICT, unlike a shared device IRQ, there is no way to
share a MIPS IRQ line between two controller instances.

Additionally, we have a few other random MASK/STATUS pairs scattered
around (ZMIPS, CMIPS blocks), and then we also have DQM IRQs with
multiple mask registers + single status register:

CMIPS_NOT_EMPTY_IRQ_MSK
CMIPS1_NOT_EMPTY_IRQ_MSK <- mine, if running on Viper
ZMIPS_NOT_EMPTY_IRQ_MSK <- mine, if running on Zephyr
PMC_NOT_EMPTY_IRQ_MSK
DFAP_NOT_EMPTY_IRQ_MSK
NOT_EMPTY_IRQ_STS

I suppose another alternative is to ioremap() a range large enough to
cover enable + status, and then specify the offset of each one in
another property. This does run the risk of overlapping mappings.


> This would avoid having to specify a lot of regs (let's assume we also
> add support for affinity)

I concede that I have no idea how affinity should be handled here.
AFAICT it is completely off limits on BCM3384 because we just don't
have enough L2 outputs to offer proper masking for all of the
threads/CPUs in the system.

Perhaps we could write a simple, SMP-capable driver for the
saner/newer SoCs, and use the flexible-but-non-SMP version for the
complicated ones.


> and cause a lot of io(re)map calls

Is the ioremap() call really that big of a deal?

On MIPS it's basically computing CKSEG1ADDR(phys_addr). On ARM, the
top level (with 64 to 128+ IRQs) goes through the GIC. On both,
ioremap() is a one-time cost at startup.

2014-11-26 09:46:09

by Jonas Gorski

[permalink] [raw]
Subject: Re: [PATCH V3 06/11] irqchip: bcm7120-l2: Change DT binding to allow non-contiguous IRQEN/IRQSTAT

On Wed, Nov 26, 2014 at 6:18 AM, Kevin Cernekee <[email protected]> wrote:
> On Mon, Nov 24, 2014 at 6:31 AM, Jonas Gorski <[email protected]> wrote:
>> On Mon, Nov 24, 2014 at 3:40 AM, Kevin Cernekee <[email protected]> wrote:
>>> 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]>
>>
>> Hmm ... the more I think about this, the less I like it.
>>
>> Using the amount and size of the reg-properties to infer a certain
>> layout seems rather hackish and dirty to me. Maybe we should just use
>> different compatible match ids for that? E.g. brcm,bm7120-l2-intc for
>> the 32-bit en/stat pairs, and e.g. brcm,bcm6368-l2-intc for the 64-bit
>> wide one. Or maybe make the bcm63xx one a separate driver and let it
>> share code with the bcm7120-l2-intc driver.
>
> In my current proposal, it is easy to specify an arbitrary number of
> enable/status pairs located in any order and spread across different
> parts of the register space. Even register indices (0,2,4,...) are
> enable registers, and odd register indices are status registers.
>
> If I'm interpreting your post correctly, you don't agree that we need
> this level of flexibility. But looking over the register listings,
> here are the cases we need to cover:
>
>
> 6828,6318: 4x mask(exthi,extlo,hi,lo),status(exthi,extlo,hi,lo)
>
> TP0ExtIrqMaskHi
> TP0ExtIrqMaskLo
> TP0IrqMaskHi
> TP0IrqMaskLo
> TP0ExtIrqStatusHi
> TP0ExtIrqStatusLo
> TP0IrqStatusHi
> TP0IrqStatusLo
>
> TP1ExtIrqMaskHi
> TP1ExtIrqMaskLo
> ...
>
>
> 6816,6362,6328: 2x extmask,mask,extstatus,status
>
> ExtraChipIrqMask
> ChipIrqMask
> ExtraChipIrqStatus
> ChipIrqStatus
> ExtraChipIrqMask1 [1=TP1]
> ChipIrqMask1
> ExtraChipIrqStatus1
> ChipIrqStatus1
>
>
> 6368: similar to above, but with yet another naming convention:
>
> IRQMASK_MIPS0_Hi
> IRQMASK_MIPS0_Lo
> IRQSTATUS_MIPS0_Hi
> IRQSTATUS_MIPS0_Lo
> IRQMASK_MIPS1_Hi
> IRQMASK_MIPS1_Lo
> IRQSTATUS_MIPS1_Hi
> IRQSTATUS_MIPS1_Lo
>
> 6838,3384: interleaved "mystery meat" mask/status (same IRQ source
> names, with the output of each bcm7120-l2 routed to several different
> processors/threads):
>
> PeriphIRQMASK0
> PeriphIRQSTATUS0
> PeriphIRQMASK1 <- mine, if running on Zephyr
> PeriphIRQSTATUS1 <- mine, if running on Zephyr
> PeriphIRQMASK2
> PeriphIRQSTATUS2
> PeriphIRQMASK3 <- mine, if running on Viper
> PeriphIRQSTATUS3 <- mine, if running on Viper
>
> But wait, there's more! There wasn't enough space in this block for
>>32 IRQ bits, so the upper bits spilled over into a separate
> "INT_EXT_PER" block that lives elsewhere in the register space:
>
> PeriphIRQMASK0_2
> PeriphIRQSTATUS0_2
> PeriphIRQMASK1_2 <- mine, if running on Zephyr
> PeriphIRQSTATUS1_2 <- mine, if running on Zephyr
> PeriphIRQMASK2_2
> PeriphIRQSTATUS2_2
> PeriphIRQMASK3_2 <- mine, if running on Viper
> PeriphIRQSTATUS3_2 <- mine, if running on Viper
>
> The "INT_PER" and "INT_EXT_PER" outputs are ORed into the same MIPS
> IRQ lines, so we need to treat them as two sides of a single
> controller. AFAICT, unlike a shared device IRQ, there is no way to
> share a MIPS IRQ line between two controller instances.
>
> Additionally, we have a few other random MASK/STATUS pairs scattered
> around (ZMIPS, CMIPS blocks), and then we also have DQM IRQs with
> multiple mask registers + single status register:
>
> CMIPS_NOT_EMPTY_IRQ_MSK
> CMIPS1_NOT_EMPTY_IRQ_MSK <- mine, if running on Viper
> ZMIPS_NOT_EMPTY_IRQ_MSK <- mine, if running on Zephyr
> PMC_NOT_EMPTY_IRQ_MSK
> DFAP_NOT_EMPTY_IRQ_MSK
> NOT_EMPTY_IRQ_STS

There are also 63268 and 6828, which follow the 6318/6328 layout;
6818, which follows the 6368 layout, as well as 6358 (Yes I know, very
unlikely to ever get SMP support due to its stupid shared TLB design):

IrqMask
IrqStatus
(several unrelated registers)
IrqMask1
IrqStatus1

and 63381:

IrqStatusHi
IrqStatusLo
ExtIrqStatusHi
ExtIrqStatusLo
IrqMask0Hi
IrqMask0Lo
ExtIrqMask0Hi
ExtIrqMask0Lo
IrqMask1Hi
IrqMask1Lo
ExtIrqMask1Hi
ExtIrqMask1Lo

I see also a 60333, which has three 32bit Mask/Status pairs per
thread, also none of the higher irqs seem to be used according to
_intr.h).

> I suppose another alternative is to ioremap() a range large enough to
> cover enable + status, and then specify the offset of each one in
> another property. This does run the risk of overlapping mappings.
>
>> This would avoid having to specify a lot of regs (let's assume we also
>> add support for affinity)
>
> I concede that I have no idea how affinity should be handled here.
> AFAICT it is completely off limits on BCM3384 because we just don't
> have enough L2 outputs to offer proper masking for all of the
> threads/CPUs in the system.

Affinity support is "easy"; expect one set of registers for each
output irq specified, and if there is only one, then we don't support
it / fill the affinity pointers.

> Perhaps we could write a simple, SMP-capable driver for the
> saner/newer SoCs, and use the flexible-but-non-SMP version for the
> complicated ones.

As far as I can see, we have three distinct layouts here:

a) An arbitrary number of 32-bit Mask/Status-pairs (3384/6838). No per
thread support (well, not sure about 60333).

b) An arbitrary length (32 to 128 bit) Mask register, followed by a
same length Status register (63xx except 63381, 6818, 6828); repeated
for each thread.

c) A single arbitrary length (currently only 128 bit) Status register,
followed by per thread same length Mask registers (63381).

On a first glance this could translate to three distinct
drivers/compatible properties, where each expects different reg = <>;
contents.

For a), it should be enough to expand the current 7120-l2 driver to
accept/use more than one 0x8 length register, which should simplify
the register map setup.

For b) we could add a a new compatible name (maybe bcm6358-l2, because
that was AFAICT the first one with blocks) that will use the 8 to 32
byte length regs (one for each block). For now we could ignore the SMP
capability of it and make it a variant of the 7120-l2 driver, and when
we add SMP support, split it into a second different driver if we want
to avoid having all the spinlock for register accesses even for a).

We could then even easily document/add the extra block registers /
interrrupts in documentation / the dtsi files before actually
supporting them, because we only have a fixed amount of regs/irqs to
expect in the !SMP case and can easily ignore the extra
registers/interrupts.

For c) we could add a a third compatible name (bcm63381-l2), also with
its own setup routine. I would guess it doesn't matter if both
thread's irqstatus register pointers point to the same region.

>> and cause a lot of io(re)map calls
>
> Is the ioremap() call really that big of a deal?
>
> On MIPS it's basically computing CKSEG1ADDR(phys_addr). On ARM, the
> top level (with 64 to 128+ IRQs) goes through the GIC. On both,
> ioremap() is a one-time cost at startup.

For a single driver it probably doesn't hurt that much, but AFAIK
these are also stored in a table, so if all drivers did this, the
table easily becomes huge. This isn't a very strong argument, just
more a smaller nitpick.


Jonas

2014-11-26 10:25:52

by Jonas Gorski

[permalink] [raw]
Subject: Re: [PATCH V3 06/11] irqchip: bcm7120-l2: Change DT binding to allow non-contiguous IRQEN/IRQSTAT

On Wed, Nov 26, 2014 at 10:45 AM, Jonas Gorski <[email protected]> wrote:
> As far as I can see, we have three distinct layouts here:
>
> a) An arbitrary number of 32-bit Mask/Status-pairs (3384/6838). No per
> thread support (well, not sure about 60333).
>
> b) An arbitrary length (32 to 128 bit) Mask register, followed by a
> same length Status register (63xx except 63381, 6818, 6828); repeated
> for each thread.
>
> c) A single arbitrary length (currently only 128 bit) Status register,
> followed by per thread same length Mask registers (63381).
>
> On a first glance this could translate to three distinct
> drivers/compatible properties, where each expects different reg = <>;
> contents.
>
> For a), it should be enough to expand the current 7120-l2 driver to
> accept/use more than one 0x8 length register, which should simplify
> the register map setup.
>
> For b) we could add a a new compatible name (maybe bcm6358-l2, because
> that was AFAICT the first one with blocks) that will use the 8 to 32
> byte length regs (one for each block). For now we could ignore the SMP
> capability of it and make it a variant of the 7120-l2 driver, and when
> we add SMP support, split it into a second different driver if we want
> to avoid having all the spinlock for register accesses even for a).
>
> We could then even easily document/add the extra block registers /
> interrrupts in documentation / the dtsi files before actually
> supporting them, because we only have a fixed amount of regs/irqs to
> expect in the !SMP case and can easily ignore the extra
> registers/interrupts.
>
> For c) we could add a a third compatible name (bcm63381-l2), also with
> its own setup routine. I would guess it doesn't matter if both
> thread's irqstatus register pointers point to the same region.

This split-up is especially tempting to me after I had a closer look
at the current 7120-l2 driver, which already accepts more than one
interrupt, but uses it in a different way. So even if we try to make
it very flexible with only one compatible property,

reg = <irqstatus0 irqmask0 irqstatus1 irqmask1>;
interrupts = <irq0>, <irq1>;

Could then mean either irq0 is for interrupts 0..31 (mask/status0) and
irq1 for interrupts 32 .. 64 (mask/status1), or irq0 is for interrupts
0..31 on cpu0, and irq1 is for interrupts 0..31 on cpu1, and then
would require an additional property to tell them apart, for which we
then also could just use a different compatible name, and have (IMHO)
a lot less headache. (I wonder why we couldn't just have had more
than one instance of 7120-l2 in the dts for the first case)


Jonas

2014-11-26 18:54:38

by Kevin Cernekee

[permalink] [raw]
Subject: Re: [PATCH V3 06/11] irqchip: bcm7120-l2: Change DT binding to allow non-contiguous IRQEN/IRQSTAT

On Wed, Nov 26, 2014 at 2:25 AM, Jonas Gorski <[email protected]> wrote:
> On Wed, Nov 26, 2014 at 10:45 AM, Jonas Gorski <[email protected]> wrote:
>> As far as I can see, we have three distinct layouts here:
>>
>> a) An arbitrary number of 32-bit Mask/Status-pairs (3384/6838). No per
>> thread support (well, not sure about 60333).
>>
>> b) An arbitrary length (32 to 128 bit) Mask register, followed by a
>> same length Status register (63xx except 63381, 6818, 6828); repeated
>> for each thread.
>>
>> c) A single arbitrary length (currently only 128 bit) Status register,
>> followed by per thread same length Mask registers (63381).
>>
>> On a first glance this could translate to three distinct
>> drivers/compatible properties, where each expects different reg = <>;
>> contents.
>>
>> For a), it should be enough to expand the current 7120-l2 driver to
>> accept/use more than one 0x8 length register, which should simplify
>> the register map setup.
>>
>> For b) we could add a a new compatible name (maybe bcm6358-l2, because
>> that was AFAICT the first one with blocks) that will use the 8 to 32
>> byte length regs (one for each block). For now we could ignore the SMP
>> capability of it and make it a variant of the 7120-l2 driver, and when
>> we add SMP support, split it into a second different driver if we want
>> to avoid having all the spinlock for register accesses even for a).
>>
>> We could then even easily document/add the extra block registers /
>> interrrupts in documentation / the dtsi files before actually
>> supporting them, because we only have a fixed amount of regs/irqs to
>> expect in the !SMP case and can easily ignore the extra
>> registers/interrupts.
>>
>> For c) we could add a a third compatible name (bcm63381-l2), also with
>> its own setup routine. I would guess it doesn't matter if both
>> thread's irqstatus register pointers point to the same region.
>
> This split-up is especially tempting to me after I had a closer look
> at the current 7120-l2 driver, which already accepts more than one
> interrupt, but uses it in a different way. So even if we try to make
> it very flexible with only one compatible property,
>
> reg = <irqstatus0 irqmask0 irqstatus1 irqmask1>;
> interrupts = <irq0>, <irq1>;
>
> Could then mean either irq0 is for interrupts 0..31 (mask/status0) and
> irq1 for interrupts 32 .. 64 (mask/status1), or irq0 is for interrupts
> 0..31 on cpu0, and irq1 is for interrupts 0..31 on cpu1, and then
> would require an additional property to tell them apart, for which we
> then also could just use a different compatible name, and have (IMHO)
> a lot less headache. (I wonder why we couldn't just have had more
> than one instance of 7120-l2 in the dts for the first case)

I don't think we've used this driver to implement the first case yet.

The initial use of the driver was for the BCM7xxx IRQ0 block, which is
wired up according to the ASCII art diagram in
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
. i.e. different sets of bits in a single irqstatus0/irqmask0 pair
map to different parent IRQs. The bits handled by each parent IRQ are
indicated in the brcm,int-map-mask property.

And now on BCM3384, of course, we're seeing the output from two 32-bit
irqstatus/irqmask words ORed together into a single parent IRQ, for
periph_intc. The other instances do have their own DT nodes.

2014-11-26 20:13:47

by Jonas Gorski

[permalink] [raw]
Subject: Re: [PATCH V3 06/11] irqchip: bcm7120-l2: Change DT binding to allow non-contiguous IRQEN/IRQSTAT

On Wed, Nov 26, 2014 at 7:54 PM, Kevin Cernekee <[email protected]> wrote:
> On Wed, Nov 26, 2014 at 2:25 AM, Jonas Gorski <[email protected]> wrote:
>> On Wed, Nov 26, 2014 at 10:45 AM, Jonas Gorski <[email protected]> wrote:
>>> As far as I can see, we have three distinct layouts here:
>>>
>>> a) An arbitrary number of 32-bit Mask/Status-pairs (3384/6838). No per
>>> thread support (well, not sure about 60333).
>>>
>>> b) An arbitrary length (32 to 128 bit) Mask register, followed by a
>>> same length Status register (63xx except 63381, 6818, 6828); repeated
>>> for each thread.
>>>
>>> c) A single arbitrary length (currently only 128 bit) Status register,
>>> followed by per thread same length Mask registers (63381).
>>>
>>> On a first glance this could translate to three distinct
>>> drivers/compatible properties, where each expects different reg = <>;
>>> contents.
>>>
>>> For a), it should be enough to expand the current 7120-l2 driver to
>>> accept/use more than one 0x8 length register, which should simplify
>>> the register map setup.
>>>
>>> For b) we could add a a new compatible name (maybe bcm6358-l2, because
>>> that was AFAICT the first one with blocks) that will use the 8 to 32
>>> byte length regs (one for each block). For now we could ignore the SMP
>>> capability of it and make it a variant of the 7120-l2 driver, and when
>>> we add SMP support, split it into a second different driver if we want
>>> to avoid having all the spinlock for register accesses even for a).
>>>
>>> We could then even easily document/add the extra block registers /
>>> interrrupts in documentation / the dtsi files before actually
>>> supporting them, because we only have a fixed amount of regs/irqs to
>>> expect in the !SMP case and can easily ignore the extra
>>> registers/interrupts.
>>>
>>> For c) we could add a a third compatible name (bcm63381-l2), also with
>>> its own setup routine. I would guess it doesn't matter if both
>>> thread's irqstatus register pointers point to the same region.
>>
>> This split-up is especially tempting to me after I had a closer look
>> at the current 7120-l2 driver, which already accepts more than one
>> interrupt, but uses it in a different way. So even if we try to make
>> it very flexible with only one compatible property,
>>
>> reg = <irqstatus0 irqmask0 irqstatus1 irqmask1>;
>> interrupts = <irq0>, <irq1>;
>>
>> Could then mean either irq0 is for interrupts 0..31 (mask/status0) and
>> irq1 for interrupts 32 .. 64 (mask/status1), or irq0 is for interrupts
>> 0..31 on cpu0, and irq1 is for interrupts 0..31 on cpu1, and then
>> would require an additional property to tell them apart, for which we
>> then also could just use a different compatible name, and have (IMHO)
>> a lot less headache. (I wonder why we couldn't just have had more
>> than one instance of 7120-l2 in the dts for the first case)
>
> I don't think we've used this driver to implement the first case yet.
>
> The initial use of the driver was for the BCM7xxx IRQ0 block, which is
> wired up according to the ASCII art diagram in
> Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
> . i.e. different sets of bits in a single irqstatus0/irqmask0 pair
> map to different parent IRQs. The bits handled by each parent IRQ are
> indicated in the brcm,int-map-mask property.
>
> And now on BCM3384, of course, we're seeing the output from two 32-bit
> irqstatus/irqmask words ORed together into a single parent IRQ, for
> periph_intc. The other instances do have their own DT nodes.

Ah indeed, I read it wrong. But it still the same "problem" of regs +
> 1 parent interrupts already having a different meaning for bcm7120
than what they will have for bcm63xx.

I just successfully* booted bcm63xx with my proposed changes to
bcm7120-l2-intc with a hacked together bcm6358-l2-intc probe routine,
and I now think even less that having these two in one driver merged
is a good idea. Especially if we want to support the affinity stuff.
There seems to be quite a bit that will need to be changed for it.


Jonas

* took me a while to find your OF_DECLARE_2() for the mips-intc - sneaky ;p.

P.S: I wonder how this patchset is supposed to go, as it depends on
earlier bcm7120/generic irqchip patches marked in patchwork as "other
subsystem".

2014-11-26 20:46:11

by Kevin Cernekee

[permalink] [raw]
Subject: Re: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

On Mon, Nov 24, 2014 at 1:39 PM, Arnd Bergmann <[email protected]> wrote:
>> > As mentioned before, it seems like you are simply defining these all to zero,
>> > like most other platforms do too. Why not add this file as
>> > arch/mips/include/asm/mach-generic/war.h and delete all identical copies?
>>
>> Likewise - currently every existing MIPS machine type implements it this way.
>>
>> Perhaps a future patch series can generalize the way these definitions
>> are handled on MIPS?
>
> I'd like to hear what Ralf thinks about it, it's really his decision.
> What I was pointing out here are things that are still in the way of
> a real "multiplatform" implementation. None of these are really hard
> to do, but I don't know where you are heading with MIPS.

That probably depends on what types of platforms were going to be
supported by the multiplatform kernel. For the case of war.h, about
2/3rds of arch/mips/include/asm/mach-*/war.h contain all zeroes...

> I think in case of the last one, it's really just a matter of moving the
> file, you could delete the other copies later.

...and so that's probably a good idea in general.

>> >> +OF_DECLARE_2(irqchip, mips_cpu_intc, "mti,cpu-interrupt-controller",
>> >> + mips_cpu_irq_of_init);
>> >
>> > OF_DECLARE_2 really wasn't meant to be used directly. Can you move this
>> > code into drivers/irqchip and make it use IRQCHIP_DECLARE()?
>>
>> Perhaps arch/mips/kernel/irq_cpu.c could be moved under
>> drivers/irqchip in a future commit? We'll probably have to change the
>> way arch/mips/ralink invokes it too.
>
> Possibly, but that seems unrelated. Moving this file is required
> in order to use IRQCHIP_DECLARE, which is defined in
> drivers/irqchip/irqchip.h.

arch/mips/kernel/irq_cpu.c is the actual irqchip driver containing
mips_cpu_irq_of_init(). It probably would not make sense to move
arch/mips/bmips/irq.c (platform IRQ stubs, not an irqchip driver)
under drivers/irqchip.

>> > Is this intended to become a generic MIPS boot interface? Better
>> > document it in Documentation/mips/
>>
>> Not sure yet. It's currently limited to BCM3384.
>>
>> For V4 I can add an "Entry point for arch/mips/bmips" or even an
>> "Entry point for arch/mips" section to
>> Documentation/devicetree/booting-without-of.txt. Any preferences?
>
> If the goal is being able to have a multiplatform kernel
> that can cover more than just BMIPS, I think this would have
> to be documented as the only way for MIPS multiplatform.
>
> If that isn't possible, most of my other comments here are
> moot, but then you shouldn't call it "multiplatform" but just
> "generic BMIPS" or something like that.

Currently my goal is to cover BMIPS only. Although it's possible that
someday somebody develops a more hardware-independent implementation
that runs on other MIPS processor variants.

So, I can go ahead and rename it to "Generic BMIPS" if that clarifies
the intent.

>> >> 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 000000000000..5481a4d1bbbf
>> >> --- /dev/null
>> >> +++ b/arch/mips/include/asm/mach-bmips/dma-coherence.h
>> >> @@ -0,0 +1,45 @@
>> >> +#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);
>> >
>> > I think you could just add these to
>> > arch/mips/include/asm/mach-generic/dma-coherence.h and get rid of the
>> > header file, after adding a Kconfig symbol.
>>
>> Some platforms mix and match inline definitions versus externs in this file.
>>
>> Maybe Ralf can comment on whether we should move to an "all or nothing" model?
>
> To clarify where I was getting to here: In a generic multiplatform kernel,
> you would probably want to always look at the dma-ranges properties here,
> at least if there are one or more platforms built into the kernel that
> don't just have a flat mapping that the current mach-generic header
> provides.

For the BMIPS case:

plat_map_dma_mem* and plat_dma_addr_to_phys are just performing
remapping, so dma-ranges would work.

plat_unmap_dma_mem is used to perform an extra BMIPS-specific
cacheflush operation.


Not sure about something like this - I guess it would work with 4
ranges as long as bits 63:39 of daddr are 0:

phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
{
long nid;
#ifdef CONFIG_PHYS48_TO_HT40
/* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from
* Loongson-3's 48bit address space and embed it into 40bit */
nid = (daddr >> 37) & 0x3;
daddr = ((nid << 37) ^ daddr) | (nid << 44);
#endif
return daddr;
}

dma-octeon.c also has a few different cases to handle, but it looks
like they are range remappings selected based on the machine type;
that might still be suitable for DT.

The other tests in that file (coherency, per-device DMA masks) might
be better off as DT properties.

2014-11-26 21:06:55

by Kevin Cernekee

[permalink] [raw]
Subject: Re: [PATCH V3 06/11] irqchip: bcm7120-l2: Change DT binding to allow non-contiguous IRQEN/IRQSTAT

On Wed, Nov 26, 2014 at 12:13 PM, Jonas Gorski <[email protected]> wrote:
>>> Could then mean either irq0 is for interrupts 0..31 (mask/status0) and
>>> irq1 for interrupts 32 .. 64 (mask/status1), or irq0 is for interrupts
>>> 0..31 on cpu0, and irq1 is for interrupts 0..31 on cpu1, and then
>>> would require an additional property to tell them apart, for which we
>>> then also could just use a different compatible name, and have (IMHO)
>>> a lot less headache. (I wonder why we couldn't just have had more
>>> than one instance of 7120-l2 in the dts for the first case)
>>
>> I don't think we've used this driver to implement the first case yet.
>>
>> The initial use of the driver was for the BCM7xxx IRQ0 block, which is
>> wired up according to the ASCII art diagram in
>> Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
>> . i.e. different sets of bits in a single irqstatus0/irqmask0 pair
>> map to different parent IRQs. The bits handled by each parent IRQ are
>> indicated in the brcm,int-map-mask property.
>>
>> And now on BCM3384, of course, we're seeing the output from two 32-bit
>> irqstatus/irqmask words ORed together into a single parent IRQ, for
>> periph_intc. The other instances do have their own DT nodes.
>
> Ah indeed, I read it wrong. But it still the same "problem" of regs +
>> 1 parent interrupts already having a different meaning for bcm7120
> than what they will have for bcm63xx.
>
> I just successfully* booted bcm63xx with my proposed changes to
> bcm7120-l2-intc with a hacked together bcm6358-l2-intc probe routine,
> and I now think even less that having these two in one driver merged
> is a good idea. Especially if we want to support the affinity stuff.
> There seems to be quite a bit that will need to be changed for it.

My current line of thinking is:

compatible="bcm7120-l2-intc" will expect a STB IRQ device with
multiple outputs, and a brcm,int-map-mask property. IRQEN at 0x00,
IRQMASK at 0x04, single reg range: <addr 0x8>.

compatible="bcm3380-l2-intc" will expect one or more reg pairs of
<irqen_addr 0x4 irqstat_addr 0x4>, single output, no
brcm,int-map-mask, no brcm,int-fwd-mask. In the short term this can
be used to support bcm63xx controllers with one CPU. This can easily
be handled by irq-bcm7120-l2.c (I'll just split out the reg parsing
logic).

compatible="bcm6358-l1-intc", "bcm63381-l1-intc", etc. can be
supported by a separate driver at some future date. Similar to my new
"bcm7038-l1-intc" driver, this would eliminate many of the special
cases found in irq-bcm7120-l2.c, and it would add SMP affinity
support. reg ranges would look something like <cpu0_block 0x20
cpu1_block 0x20>. Each range corresponds to a single parent IRQ.
When this driver is ready, the DTS files can be upgraded to use the
new code. In the unlikely event that the old DTB gets baked into a
released bootloader image, that's still OK because we aren't changing
the "bcm3380-l2-intc" bindings.

IIRC there wasn't a nice way to implement SMP affinity with
kernel/irq/generic-chip.c either, which is why I dropped it from the
7038 driver.

> * took me a while to find your OF_DECLARE_2() for the mips-intc - sneaky ;p.

I'm not real happy about how that currently looks, but I didn't know
of another way to use mips_cpu_irq_of_init() in conjunction with
irqchip_init() (covering the L1/L2 drivers). We only want to call
of_irq_init() once, and it should be called with a list of all irqchip
drivers built into the kernel.

> P.S: I wonder how this patchset is supposed to go, as it depends on
> earlier bcm7120/generic irqchip patches marked in patchwork as "other
> subsystem".

Right, I noted this somewhere in the cover-letter...

2014-11-26 21:29:00

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

On Wednesday 26 November 2014 12:45:47 Kevin Cernekee wrote:
> On Mon, Nov 24, 2014 at 1:39 PM, Arnd Bergmann <[email protected]> wrote:
> >> >> +OF_DECLARE_2(irqchip, mips_cpu_intc, "mti,cpu-interrupt-controller",
> >> >> + mips_cpu_irq_of_init);
> >> >
> >> > OF_DECLARE_2 really wasn't meant to be used directly. Can you move this
> >> > code into drivers/irqchip and make it use IRQCHIP_DECLARE()?
> >>
> >> Perhaps arch/mips/kernel/irq_cpu.c could be moved under
> >> drivers/irqchip in a future commit? We'll probably have to change the
> >> way arch/mips/ralink invokes it too.
> >
> > Possibly, but that seems unrelated. Moving this file is required
> > in order to use IRQCHIP_DECLARE, which is defined in
> > drivers/irqchip/irqchip.h.
>
> arch/mips/kernel/irq_cpu.c is the actual irqchip driver containing
> mips_cpu_irq_of_init(). It probably would not make sense to move
> arch/mips/bmips/irq.c (platform IRQ stubs, not an irqchip driver)
> under drivers/irqchip.

I see. Makes sense.

> >> > Is this intended to become a generic MIPS boot interface? Better
> >> > document it in Documentation/mips/
> >>
> >> Not sure yet. It's currently limited to BCM3384.
> >>
> >> For V4 I can add an "Entry point for arch/mips/bmips" or even an
> >> "Entry point for arch/mips" section to
> >> Documentation/devicetree/booting-without-of.txt. Any preferences?
> >
> > If the goal is being able to have a multiplatform kernel
> > that can cover more than just BMIPS, I think this would have
> > to be documented as the only way for MIPS multiplatform.
> >
> > If that isn't possible, most of my other comments here are
> > moot, but then you shouldn't call it "multiplatform" but just
> > "generic BMIPS" or something like that.
>
> Currently my goal is to cover BMIPS only. Although it's possible that
> someday somebody develops a more hardware-independent implementation
> that runs on other MIPS processor variants.
>
> So, I can go ahead and rename it to "Generic BMIPS" if that clarifies
> the intent.

Ok. One more thought: With the powerpc-approach of having platform
specific boot wrappers (with or without uncompress code), the boot
protocol would no longer matter to the common multiplatform
implementation, and the specific BMIPS interface would become
part of arch/mips/boot/bmips.c or something like that. Looking at
the Makefile in there, MIPS already supports six different binary
formats that can all be generated from the same vmlinux, so at the
point when someone implements a full multiplatform implementation,
the bmips specifics can become another binary format that encapsulates
the vmlinux file and an optional dtb file and passes the dtb
into the common kernel entry point when calling the actual vmlinux
head.S.

> >> >> 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 000000000000..5481a4d1bbbf
> >> >> --- /dev/null
> >> >> +++ b/arch/mips/include/asm/mach-bmips/dma-coherence.h
> >> >> @@ -0,0 +1,45 @@
> >> >> +#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);
> >> >
> >> > I think you could just add these to
> >> > arch/mips/include/asm/mach-generic/dma-coherence.h and get rid of the
> >> > header file, after adding a Kconfig symbol.
> >>
> >> Some platforms mix and match inline definitions versus externs in this file.
> >>
> >> Maybe Ralf can comment on whether we should move to an "all or nothing" model?
> >
> > To clarify where I was getting to here: In a generic multiplatform kernel,
> > you would probably want to always look at the dma-ranges properties here,
> > at least if there are one or more platforms built into the kernel that
> > don't just have a flat mapping that the current mach-generic header
> > provides.
>
> For the BMIPS case:
>
> plat_map_dma_mem* and plat_dma_addr_to_phys are just performing
> remapping, so dma-ranges would work.
>
> plat_unmap_dma_mem is used to perform an extra BMIPS-specific
> cacheflush operation.

Yes, the cacheflush again would have to be abstracted. This is normally
done using either a platform-specific dma_map_ops struct, or using
a further abstraction with another function pointer.

I'm surprised that you need the special flush operation only
for 'unmap' and not for 'dma_sync_*_for_cpu'. Can you check that
you are actually doing the right thing for drivers that reuse
a DMA buffer with the streaming API?

> Not sure about something like this - I guess it would work with 4
> ranges as long as bits 63:39 of daddr are 0:
>
> phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
> {
> long nid;
> #ifdef CONFIG_PHYS48_TO_HT40
> /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from
> * Loongson-3's 48bit address space and embed it into 40bit */
> nid = (daddr >> 37) & 0x3;
> daddr = ((nid << 37) ^ daddr) | (nid << 44);
> #endif
> return daddr;
> }
>
> dma-octeon.c also has a few different cases to handle, but it looks
> like they are range remappings selected based on the machine type;
> that might still be suitable for DT.
>
> The other tests in that file (coherency, per-device DMA masks) might
> be better off as DT properties.

I guess a platform that doesn't fit the simple model could always
have its own dma_map_ops and not use the the dma-coherence.h interfaces.

Arnd

2014-11-26 22:55:13

by Kevin Cernekee

[permalink] [raw]
Subject: Re: [PATCH V3 11/11] MIPS: Add multiplatform BMIPS target

On Wed, Nov 26, 2014 at 1:28 PM, Arnd Bergmann <[email protected]> wrote:
>> For the BMIPS case:
>>
>> plat_map_dma_mem* and plat_dma_addr_to_phys are just performing
>> remapping, so dma-ranges would work.
>>
>> plat_unmap_dma_mem is used to perform an extra BMIPS-specific
>> cacheflush operation.
>
> Yes, the cacheflush again would have to be abstracted. This is normally
> done using either a platform-specific dma_map_ops struct, or using
> a further abstraction with another function pointer.
>
> I'm surprised that you need the special flush operation only
> for 'unmap' and not for 'dma_sync_*_for_cpu'. Can you check that
> you are actually doing the right thing for drivers that reuse
> a DMA buffer with the streaming API?

That's a fantastic question. I checked an older BCM7xxx kernel tree
and noticed that we used to implement plat_extra_sync_for_device()
locally to do this, but the API was "garbage collected" last year:

commit 4e7f72660c39a81cc5745d5c6f23f9500f80d8d8
Author: Felix Fietkau <[email protected]>
Date: Thu Aug 15 11:28:30 2013 +0200

MIPS: Remove unnecessary platform dma helper functions

The semantics stay the same - on Cavium Octeon the functions were dead
code (it overrides the MIPS DMA ops) - on other platforms they contained
no code at all.

Signed-off-by: Felix Fietkau <[email protected]>
Cc: [email protected]
Patchwork: https://patchwork.linux-mips.org/patch/5720/
Signed-off-by: Ralf Baechle <[email protected]>


If nobody objects, I can revert this change and then add the extra
flush to arch/mips/bmips/dma.c.

Or I can add some BMIPS-specific code to dma-default.c, similar to
cpu_needs_post_dma_flush(). Could even add it to that function
directly, although that is less intuitive:

diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
index af5f046..ee6d12c 100644
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -18,6 +18,7 @@
#include <linux/highmem.h>
#include <linux/dma-contiguous.h>

+#include <asm/bmips.h>
#include <asm/cache.h>
#include <asm/cpu-type.h>
#include <asm/io.h>
@@ -69,6 +70,18 @@ static inline struct page *dma_addr_to_page(struct
device *dev,
*/
static inline int cpu_needs_post_dma_flush(struct device *dev)
{
+ if (boot_cpu_type() == CPU_BMIPS3300 ||
+ boot_cpu_type() == CPU_BMIPS4350 ||
+ boot_cpu_type() == CPU_BMIPS4380) {
+ void __iomem *cbr = BMIPS_GET_CBR();
+
+ /* Flush stale data out of the readahead cache */
+ __raw_writel(0x100, cbr + BMIPS_RAC_CONFIG);
+ __raw_readl(cbr + BMIPS_RAC_CONFIG);
+
+ return 0;
+ }
+
return !plat_device_is_coherent(dev) &&
(boot_cpu_type() == CPU_R10000 ||
boot_cpu_type() == CPU_R12000 ||


This would allow for eliminating all flushes from
arch/mips/bmips/dma.c, so the entire file could go away when we switch
to the common dma-ranges code.

Any preferences?