Only netboot tested. Flash at your own risk.
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
SVN-Revision: 47702
--- /dev/null
+CONFIG_ARCH_BINFMT_ELF_STATE=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_B53=y
+CONFIG_B53_MMAP_DRIVER=y
+CONFIG_B53_PHY_DRIVER=y
+CONFIG_B53_PHY_FIXUP=y
+CONFIG_B53_SPI_DRIVER=y
+# CONFIG_B53_SRAB_DRIVER is not set
+CONFIG_BCM6345_EXT_IRQ=y
+CONFIG_BCM6345_PERIPH_IRQ=y
+CONFIG_BCM63XX=y
+CONFIG_BCM63XX_CPU_3368=y
+CONFIG_BCM63XX_CPU_6318=y
+CONFIG_BCM63XX_CPU_63268=y
+CONFIG_BCM63XX_CPU_6328=y
+CONFIG_BCM63XX_CPU_6338=y
+CONFIG_BCM63XX_CPU_6345=y
+CONFIG_BCM63XX_CPU_6348=y
+CONFIG_BCM63XX_CPU_6358=y
+CONFIG_BCM63XX_CPU_6362=y
+CONFIG_BCM63XX_CPU_6368=y
+CONFIG_BCM63XX_EHCI=y
+CONFIG_BCM63XX_ENET=y
+CONFIG_BCM63XX_OHCI=y
+CONFIG_BCM63XX_PHY=y
+CONFIG_BCM63XX_WDT=y
+CONFIG_BCMA=y
+CONFIG_BCMA_BLOCKIO=y
+# CONFIG_BCMA_DEBUG is not set
+# CONFIG_BCMA_DRIVER_GMAC_CMN is not set
+# CONFIG_BCMA_DRIVER_MIPS is not set
+CONFIG_BCMA_DRIVER_PCI=y
+# CONFIG_BCMA_DRIVER_PCI_HOSTMODE is not set
+CONFIG_BCMA_HOST_PCI=y
+CONFIG_BCMA_HOST_PCI_POSSIBLE=y
+# CONFIG_BCMA_HOST_SOC is not set
+CONFIG_BOARD_BCM63XX_DT=y
+CONFIG_BOARD_BCM963XX=y
+CONFIG_BOARD_LIVEBOX=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CEVT_R4K=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,jffs2 noinitrd console=ttyS0,115200"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_BMIPS=y
+CONFIG_CPU_BMIPS32_3300=y
+CONFIG_CPU_BMIPS4350=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_R4K_FPU=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CSRC_R4K=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_74X164=y
+CONFIG_GPIO_BCM63XX=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_GENERIC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HW_HAS_PCI=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_BCM63XX=y
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_CPU=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_KEXEC=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LIBFDT=y
+# CONFIG_LZ4_COMPRESS is not set
+# CONFIG_LZ4_DECOMPRESS is not set
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MIPS=y
+# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=4
+CONFIG_MIPS_L1_CACHE_SHIFT_4=y
+# CONFIG_MIPS_MACHINE is not set
+# CONFIG_MIPS_ELF_APPENDED_DTB is not set
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MTD_BCM63XX_PARTS=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_BE_BYTE_SWAP=y
+# CONFIG_MTD_CFI_GEOMETRY is not set
+# CONFIG_MTD_CFI_NOSWAP is not set
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
+# CONFIG_NO_IOPORT_MAP is not set
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_ADDRESS_PCI=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PCI=y
+# CONFIG_PCIEAER is not set
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_RELAY=y
+CONFIG_RTL8366_SMI=y
+CONFIG_RTL8367_PHY=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_BCM63XX=y
+CONFIG_SERIAL_BCM63XX_CONSOLE=y
+CONFIG_SPI=y
+CONFIG_SPI_BCM63XX=y
+CONFIG_SPI_BCM63XX_HSSPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_MASTER=y
+CONFIG_SQUASHFS_EMBEDDED=y
+CONFIG_SRCU=y
+CONFIG_SSB=y
+CONFIG_SSB_B43_PCI_BRIDGE=y
+CONFIG_SSB_BLOCKIO=y
+# CONFIG_SSB_DRIVER_MIPS is not set
+CONFIG_SSB_DRIVER_PCICORE=y
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
+CONFIG_SSB_PCIHOST=y
+CONFIG_SSB_PCIHOST_POSSIBLE=y
+CONFIG_SSB_SPROM=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_SWCONFIG=y
+CONFIG_SYNC_R4K=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_BMIPS=y
+CONFIG_SYS_HAS_CPU_BMIPS32_3300=y
+CONFIG_SYS_HAS_CPU_BMIPS4350=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_ZONE_DMA_FLAG=0
--- /dev/null
+From 80a2f983e9f44dbc3e01ae31c62d877846a7f791 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:19 +0100
+Subject: [PATCH 01/11] MIPS: BCM63XX: add USB host clock enable delay
+
+Knowledge of the clock setup delay should remain at the clock level (so
+it can be clock specific and CPU specific). Add the 100 milliseconds
+required clock delay for the USB host clock when it gets enabled.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/clk.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/arch/mips/bcm63xx/clk.c
++++ b/arch/mips/bcm63xx/clk.c
+@@ -177,6 +177,11 @@ static void usbh_set(struct clk *clk, in
+ bcm_hwclock_set(CKCTL_6362_USBH_EN, enable);
+ else if (BCMCPU_IS_6368())
+ bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
++ else
++ return;
++
++ if (enable)
++ msleep(100);
+ }
+
+ static struct clk clk_usbh = {
--- /dev/null
+From 8e9bf528a122741f0171b89c297b63041116d704 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:20 +0100
+Subject: [PATCH 02/11] MIPS: BCM63XX: add USB device clock enable delay to
+ clock code
+
+This patch adds the required 10 micro seconds delay to the USB device
+clock enable operation. Put this where the correct clock knowledege is,
+which is in the clock code, and remove this delay from the bcm63xx_udc
+gadget driver where it was before.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/clk.c | 5 +++++
+ drivers/usb/gadget/bcm63xx_udc.c | 1 -
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+--- a/arch/mips/bcm63xx/clk.c
++++ b/arch/mips/bcm63xx/clk.c
+@@ -199,6 +199,11 @@ static void usbd_set(struct clk *clk, in
+ bcm_hwclock_set(CKCTL_6362_USBD_EN, enable);
+ else if (BCMCPU_IS_6368())
+ bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
++ else
++ return;
++
++ if (enable)
++ udelay(10);
+ }
+
+ static struct clk clk_usbd = {
+--- a/drivers/usb/gadget/udc/bcm63xx_udc.c
++++ b/drivers/usb/gadget/udc/bcm63xx_udc.c
+@@ -411,7 +411,6 @@ static inline void set_clocks(struct bcm
+ if (is_enabled) {
+ clk_enable(udc->usbh_clk);
+ clk_enable(udc->usbd_clk);
+- udelay(10);
+ } else {
+ clk_disable(udc->usbd_clk);
+ clk_disable(udc->usbh_clk);
--- /dev/null
+From ac9b0b574d54be28b300bf99ffe092a2c589484f Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:21 +0100
+Subject: [PATCH 03/11] MIPS: BCM63XX: move code touching the USB private
+ register
+
+This patch moves the code touching the USB private register in the
+bcm63xx USB gadget driver to arch/mips/bcm63xx/usb-common.c in
+preparation for adding support for OHCI and EHCI host controllers which
+will also touch the USB private register.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/Makefile | 2 +-
+ arch/mips/bcm63xx/usb-common.c | 53 ++++++++++++++++++++
+ .../include/asm/mach-bcm63xx/bcm63xx_usb_priv.h | 9 ++++
+ drivers/usb/gadget/bcm63xx_udc.c | 27 ++--------
+ 4 files changed, 67 insertions(+), 24 deletions(-)
+ create mode 100644 arch/mips/bcm63xx/usb-common.c
+ create mode 100644 arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
+
+--- a/arch/mips/bcm63xx/Makefile
++++ b/arch/mips/bcm63xx/Makefile
+@@ -1,7 +1,7 @@
+ obj-y += clk.o cpu.o cs.o gpio.o irq.o nvram.o prom.o reset.o \
+ setup.o timer.o dev-dsp.o dev-enet.o dev-flash.o \
+ dev-pcmcia.o dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o \
+- dev-wdt.o dev-usb-usbd.o
++ dev-wdt.o dev-usb-usbd.o usb-common.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+ obj-y += boards/
+--- /dev/null
++++ b/arch/mips/bcm63xx/usb-common.c
+@@ -0,0 +1,53 @@
++/*
++ * Broadcom BCM63xx common USB device configuration code
++ *
++ * 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) 2012 Kevin Cernekee <cernekee@gmail.com>
++ * Copyright (C) 2012 Broadcom Corporation
++ *
++ */
++#include <linux/export.h>
++
++#include <bcm63xx_cpu.h>
++#include <bcm63xx_regs.h>
++#include <bcm63xx_io.h>
++#include <bcm63xx_usb_priv.h>
++
++void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device)
++{
++ u32 val;
++
++ val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
++ if (is_device) {
++ val |= (portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT);
++ val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
++ } else {
++ val &= ~(portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT);
++ val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
++ }
++ bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
++
++ val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
++ if (is_device)
++ val |= USBH_PRIV_SWAP_USBD_MASK;
++ else
++ val &= ~USBH_PRIV_SWAP_USBD_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG);
++}
++EXPORT_SYMBOL(bcm63xx_usb_priv_select_phy_mode);
++
++void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on)
++{
++ u32 val;
++
++ val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
++ if (is_on)
++ val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
++ else
++ val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
++ bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
++}
++EXPORT_SYMBOL(bcm63xx_usb_priv_select_pullup);
+--- /dev/null
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
+@@ -0,0 +1,9 @@
++#ifndef BCM63XX_USB_PRIV_H_
++#define BCM63XX_USB_PRIV_H_
++
++#include <linux/types.h>
++
++void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device);
++void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on);
++
++#endif /* BCM63XX_USB_PRIV_H_ */
+--- a/drivers/usb/gadget/udc/bcm63xx_udc.c
++++ b/drivers/usb/gadget/udc/bcm63xx_udc.c
+@@ -40,6 +40,7 @@
+ #include <bcm63xx_dev_usb_usbd.h>
+ #include <bcm63xx_io.h>
+ #include <bcm63xx_regs.h>
++#include <bcm63xx_usb_priv.h>
+
+ #define DRV_MODULE_NAME "bcm63xx_udc"
+
+@@ -888,22 +889,7 @@ static void bcm63xx_select_phy_mode(stru
+ bcm_gpio_writel(val, GPIO_PINMUX_OTHR_REG);
+ }
+
+- val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
+- if (is_device) {
+- val |= (portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT);
+- val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+- } else {
+- val &= ~(portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT);
+- val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+- }
+- bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
+-
+- val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
+- if (is_device)
+- val |= USBH_PRIV_SWAP_USBD_MASK;
+- else
+- val &= ~USBH_PRIV_SWAP_USBD_MASK;
+- bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG);
++ bcm63xx_usb_priv_select_phy_mode(portmask, is_device);
+ }
+
+ /**
+@@ -917,14 +903,9 @@ static void bcm63xx_select_phy_mode(stru
+ */
+ static void bcm63xx_select_pullup(struct bcm63xx_udc *udc, bool is_on)
+ {
+- u32 val, portmask = BIT(udc->pd->port_no);
++ u32 portmask = BIT(udc->pd->port_no);
+
+- val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
+- if (is_on)
+- val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+- else
+- val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+- bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
++ bcm63xx_usb_priv_select_pullup(portmask, is_on);
+ }
+
+ /**
--- /dev/null
+From 28758a9da77954ed323f86123ef448c6a563c037 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:22 +0100
+Subject: [PATCH 04/11] MIPS: BCM63XX: add OHCI/EHCI configuration bits to
+ common USB code
+
+This patch updates the common USB code touching the USB private
+registers with the specific bits to properly enable OHCI and EHCI
+controllers on BCM63xx SoCs. As a result we now need to protect access
+to Read Modify Write sequences using a spinlock because we cannot
+guarantee that any of the exposed helper will not be called
+concurrently.
+
+Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/usb-common.c | 97 ++++++++++++++++++++
+ .../include/asm/mach-bcm63xx/bcm63xx_usb_priv.h | 2 +
+ 2 files changed, 99 insertions(+)
+
+--- a/arch/mips/bcm63xx/usb-common.c
++++ b/arch/mips/bcm63xx/usb-common.c
+@@ -5,10 +5,12 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
++ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com>
+ * Copyright (C) 2012 Broadcom Corporation
+ *
+ */
++#include <linux/spinlock.h>
+ #include <linux/export.h>
+
+ #include <bcm63xx_cpu.h>
+@@ -16,9 +18,14 @@
+ #include <bcm63xx_io.h>
+ #include <bcm63xx_usb_priv.h>
+
++static DEFINE_SPINLOCK(usb_priv_reg_lock);
++
+ void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device)
+ {
+ u32 val;
++ unsigned long flags;
++
++ spin_lock_irqsave(&usb_priv_reg_lock, flags);
+
+ val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
+ if (is_device) {
+@@ -36,12 +43,17 @@ void bcm63xx_usb_priv_select_phy_mode(u3
+ else
+ val &= ~USBH_PRIV_SWAP_USBD_MASK;
+ bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG);
++
++ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
+ }
+ EXPORT_SYMBOL(bcm63xx_usb_priv_select_phy_mode);
+
+ void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on)
+ {
+ u32 val;
++ unsigned long flags;
++
++ spin_lock_irqsave(&usb_priv_reg_lock, flags);
+
+ val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
+ if (is_on)
+@@ -49,5 +61,90 @@ void bcm63xx_usb_priv_select_pullup(u32
+ else
+ val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+ bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
++
++ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
+ }
+ EXPORT_SYMBOL(bcm63xx_usb_priv_select_pullup);
++
++/* The following array represents the meaning of the DESC/DATA
++ * endian swapping with respect to the CPU configured endianness
++ *
++ * DATA ENDN mmio descriptor
++ * 0 0 BE invalid
++ * 0 1 BE LE
++ * 1 0 BE BE
++ * 1 1 BE invalid
++ *
++ * Since BCM63XX SoCs are configured to be in big-endian mode
++ * we want configuration at line 3.
++ */
++void bcm63xx_usb_priv_ohci_cfg_set(void)
++{
++ u32 reg;
++ unsigned long flags;
++
++ spin_lock_irqsave(&usb_priv_reg_lock, flags);
++
++ if (BCMCPU_IS_6348())
++ bcm_rset_writel(RSET_OHCI_PRIV, 0, OHCI_PRIV_REG);
++ else if (BCMCPU_IS_6358()) {
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
++ reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
++ reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
++ /*
++ * The magic value comes for the original vendor BSP
++ * and is needed for USB to work. Datasheet does not
++ * help, so the magic value is used as-is.
++ */
++ bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
++ USBH_PRIV_TEST_6358_REG);
++
++ } else if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) {
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
++ reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
++ reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
++ reg |= USBH_PRIV_SETUP_IOC_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
++ }
++
++ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
++}
++
++void bcm63xx_usb_priv_ehci_cfg_set(void)
++{
++ u32 reg;
++ unsigned long flags;
++
++ spin_lock_irqsave(&usb_priv_reg_lock, flags);
++
++ if (BCMCPU_IS_6358()) {
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
++ reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
++ reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
++
++ /*
++ * The magic value comes for the original vendor BSP
++ * and is needed for USB to work. Datasheet does not
++ * help, so the magic value is used as-is.
++ */
++ bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
++ USBH_PRIV_TEST_6358_REG);
++
++ } else if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) {
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
++ reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
++ reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
++ reg |= USBH_PRIV_SETUP_IOC_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
++ }
++
++ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
++}
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
+@@ -5,5 +5,7 @@
+
+ void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device);
+ void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on);
++void bcm63xx_usb_priv_ohci_cfg_set(void);
++void bcm63xx_usb_priv_ehci_cfg_set(void);
+
+ #endif /* BCM63XX_USB_PRIV_H_ */
--- /dev/null
+From 94ec618bd1a6b07fafbbfc9bcc54e7f9360ff9a0 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:23 +0100
+Subject: [PATCH 05/11] MIPS: BCM63XX: introduce BCM63XX_OHCI configuration
+ symbol
+
+This configuration symbol can be used by CPUs supporting the on-chip
+OHCI controller, and ensures that all relevant OHCI-related
+configuration options are correctly selected. So far, OHCI support is
+available for the 6328, 6348, 6358 and 6358 SoCs.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/Kconfig | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+--- a/arch/mips/bcm63xx/Kconfig
++++ b/arch/mips/bcm63xx/Kconfig
+@@ -6,10 +6,17 @@ config BCM63XX_CPU_3368
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
+
++config BCM63XX_OHCI
++ bool
++ select USB_ARCH_HAS_OHCI
++ select USB_OHCI_BIG_ENDIAN_DESC if USB_OHCI_HCD
++ select USB_OHCI_BIG_ENDIAN_MMIO if USB_OHCI_HCD
++
+ config BCM63XX_CPU_6328
+ bool "support 6328 CPU"
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
++ select BCM63XX_OHCI
+
+ config BCM63XX_CPU_6338
+ bool "support 6338 CPU"
+@@ -24,21 +31,25 @@ config BCM63XX_CPU_6348
+ bool "support 6348 CPU"
+ select SYS_HAS_CPU_BMIPS32_3300
+ select HW_HAS_PCI
++ select BCM63XX_OHCI
+
+ config BCM63XX_CPU_6358
+ bool "support 6358 CPU"
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
++ select BCM63XX_OHCI
+
+ config BCM63XX_CPU_6362
+ bool "support 6362 CPU"
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
++ select BCM63XX_OHCI
+
+ config BCM63XX_CPU_6368
+ bool "support 6368 CPU"
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
++ select BCM63XX_OHCI
+ endmenu
+
+ source "arch/mips/bcm63xx/boards/Kconfig"
--- /dev/null
+From 30d22baef255c99a12c4858ce4ab0d45f0d8c9ae Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:24 +0100
+Subject: [PATCH 06/11] MIPS: BCM63XX: add support for the on-chip OHCI
+ controller
+
+Broadcom BCM63XX SoCs include an on-chip OHCI controller which can be
+driven by the ohci-platform generic driver by using specific power
+on/off/suspend callback to manage clocks and hardware specific
+configuration.
+
+Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/Makefile | 2 +-
+ arch/mips/bcm63xx/dev-usb-ohci.c | 94 ++++++++++++++++++++
+ .../asm/mach-bcm63xx/bcm63xx_dev_usb_ohci.h | 6 ++
+ 3 files changed, 101 insertions(+), 1 deletion(-)
+ create mode 100644 arch/mips/bcm63xx/dev-usb-ohci.c
+ create mode 100644 arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ohci.h
+
+--- a/arch/mips/bcm63xx/Makefile
++++ b/arch/mips/bcm63xx/Makefile
+@@ -1,7 +1,7 @@
+ obj-y += clk.o cpu.o cs.o gpio.o irq.o nvram.o prom.o reset.o \
+ setup.o timer.o dev-dsp.o dev-enet.o dev-flash.o \
+ dev-pcmcia.o dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o \
+- dev-wdt.o dev-usb-usbd.o usb-common.o
++ dev-wdt.o dev-usb-ohci.o dev-usb-usbd.o usb-common.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+ obj-y += boards/
+--- /dev/null
++++ b/arch/mips/bcm63xx/dev-usb-ohci.c
+@@ -0,0 +1,94 @@
++/*
++ * 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) 2008 Maxime Bizon <mbizon@freebox.fr>
++ * Copyright (C) 2013 Florian Fainelli <florian@openwrt.org>
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/usb/ohci_pdriver.h>
++#include <linux/dma-mapping.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++
++#include <bcm63xx_cpu.h>
++#include <bcm63xx_regs.h>
++#include <bcm63xx_io.h>
++#include <bcm63xx_usb_priv.h>
++#include <bcm63xx_dev_usb_ohci.h>
++
++static struct resource ohci_resources[] = {
++ {
++ .start = -1, /* filled at runtime */
++ .end = -1, /* filled at runtime */
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = -1, /* filled at runtime */
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static u64 ohci_dmamask = DMA_BIT_MASK(32);
++
++static struct clk *usb_host_clock;
++
++static int bcm63xx_ohci_power_on(struct platform_device *pdev)
++{
++ usb_host_clock = clk_get(&pdev->dev, "usbh");
++ if (IS_ERR_OR_NULL(usb_host_clock))
++ return -ENODEV;
++
++ clk_prepare_enable(usb_host_clock);
++
++ bcm63xx_usb_priv_ohci_cfg_set();
++
++ return 0;
++}
++
++static void bcm63xx_ohci_power_off(struct platform_device *pdev)
++{
++ if (!IS_ERR_OR_NULL(usb_host_clock)) {
++ clk_disable_unprepare(usb_host_clock);
++ clk_put(usb_host_clock);
++ }
++}
++
++static struct usb_ohci_pdata bcm63xx_ohci_pdata = {
++ .big_endian_desc = 1,
++ .big_endian_mmio = 1,
++ .no_big_frame_no = 1,
++ .num_ports = 1,
++ .power_on = bcm63xx_ohci_power_on,
++ .power_off = bcm63xx_ohci_power_off,
++ .power_suspend = bcm63xx_ohci_power_off,
++};
++
++static struct platform_device bcm63xx_ohci_device = {
++ .name = "ohci-platform",
++ .id = -1,
++ .num_resources = ARRAY_SIZE(ohci_resources),
++ .resource = ohci_resources,
++ .dev = {
++ .platform_data = &bcm63xx_ohci_pdata,
++ .dma_mask = &ohci_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ },
++};
++
++int __init bcm63xx_ohci_register(void)
++{
++ if (BCMCPU_IS_6345() || BCMCPU_IS_6338())
++ return -ENODEV;
++
++ ohci_resources[0].start = bcm63xx_regset_address(RSET_OHCI0);
++ ohci_resources[0].end = ohci_resources[0].start;
++ ohci_resources[0].end += RSET_OHCI_SIZE - 1;
++ ohci_resources[1].start = bcm63xx_get_irq_number(IRQ_OHCI0);
++
++ return platform_device_register(&bcm63xx_ohci_device);
++}
+--- /dev/null
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ohci.h
+@@ -0,0 +1,6 @@
++#ifndef BCM63XX_DEV_USB_OHCI_H_
++#define BCM63XX_DEV_USB_OHCI_H_
++
++int bcm63xx_ohci_register(void);
++
++#endif /* BCM63XX_DEV_USB_OHCI_H_ */
--- /dev/null
+From 33ef960aed15f9a98a2c51d8d794cd72418e0be4 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:25 +0100
+Subject: [PATCH 07/11] MIPS: BCM63XX: register OHCI controller if board
+ enables it
+
+BCM63XX-based boards can control the registration of the OHCI controller
+by setting their has_ohci0 flag to 1. Handle this in the generic
+code dealing with board registration and call the actual helper to
+register the OHCI controller.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/boards/board_bcm963xx.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -28,6 +28,7 @@
+ #include <bcm63xx_dev_hsspi.h>
+ #include <bcm63xx_dev_pcmcia.h>
+ #include <bcm63xx_dev_spi.h>
++#include <bcm63xx_dev_usb_ohci.h>
+ #include <bcm63xx_dev_usb_usbd.h>
+ #include <board_bcm963xx.h>
+
+@@ -898,6 +899,9 @@ int __init board_register_devices(void)
+ if (board.has_usbd)
+ bcm63xx_usbd_register(&board.usbd);
+
++ if (board.has_ohci0)
++ bcm63xx_ohci_register();
++
+ if (board.has_dsp)
+ bcm63xx_dsp_register(&board.dsp);
+
--- /dev/null
+From 00da1683364e58c6430a4577123d01037f8faddc Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:26 +0100
+Subject: [PATCH 08/11] MIPS: BCM63XX: introduce BCM63XX_EHCI configuration
+ symbol
+
+This configuration symbol can be used by CPUs supporting the on-chip
+EHCI controller, and ensures that all relevant EHCI-related
+configuration options are selected. So far BCM6328, BCM6358 and BCM6368
+have an EHCI controller and do select this symbol. Update
+drivers/usb/host/Kconfig with BCM63XX to update direct unmet
+dependencies.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/Kconfig | 9 +++++++++
+ drivers/usb/host/Kconfig | 5 +++--
+ 2 files changed, 12 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/bcm63xx/Kconfig
++++ b/arch/mips/bcm63xx/Kconfig
+@@ -12,11 +12,18 @@ config BCM63XX_OHCI
+ select USB_OHCI_BIG_ENDIAN_DESC if USB_OHCI_HCD
+ select USB_OHCI_BIG_ENDIAN_MMIO if USB_OHCI_HCD
+
++config BCM63XX_EHCI
++ bool
++ select USB_ARCH_HAS_EHCI
++ select USB_EHCI_BIG_ENDIAN_DESC if USB_EHCI_HCD
++ select USB_EHCI_BIG_ENDIAN_MMIO if USB_EHCI_HCD
++
+ config BCM63XX_CPU_6328
+ bool "support 6328 CPU"
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
+ select BCM63XX_OHCI
++ select BCM63XX_EHCI
+
+ config BCM63XX_CPU_6338
+ bool "support 6338 CPU"
+@@ -38,18 +45,21 @@ config BCM63XX_CPU_6358
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
+ select BCM63XX_OHCI
++ select BCM63XX_EHCI
+
+ config BCM63XX_CPU_6362
+ bool "support 6362 CPU"
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
+ select BCM63XX_OHCI
++ select BCM63XX_EHCI
+
+ config BCM63XX_CPU_6368
+ bool "support 6368 CPU"
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
+ select BCM63XX_OHCI
++ select BCM63XX_EHCI
+ endmenu
+
+ source "arch/mips/bcm63xx/boards/Kconfig"
--- /dev/null
+From e38f13bd6408769c0b565bb1079024f496eee121 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:27 +0100
+Subject: [PATCH 09/11] MIPS: BCM63XX: add support for the on-chip EHCI
+ controller
+
+Broadcom BCM63XX SoCs include an on-chip EHCI controller which can be
+driven by the generic ehci-platform driver by using specific power
+on/off/suspend callbacks to manage clocks and hardware specific
+configuration.
+
+Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/Makefile | 2 +-
+ arch/mips/bcm63xx/dev-usb-ehci.c | 92 ++++++++++++++++++++
+ .../asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h | 6 ++
+ 3 files changed, 99 insertions(+), 1 deletion(-)
+ create mode 100644 arch/mips/bcm63xx/dev-usb-ehci.c
+ create mode 100644 arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h
+
+--- a/arch/mips/bcm63xx/Makefile
++++ b/arch/mips/bcm63xx/Makefile
+@@ -1,7 +1,8 @@
+ obj-y += clk.o cpu.o cs.o gpio.o irq.o nvram.o prom.o reset.o \
+ setup.o timer.o dev-dsp.o dev-enet.o dev-flash.o \
+ dev-pcmcia.o dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o \
+- dev-wdt.o dev-usb-ohci.o dev-usb-usbd.o usb-common.o
++ dev-wdt.o dev-usb-ehci.o dev-usb-ohci.o dev-usb-usbd.o \
++ usb-common.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+ obj-y += boards/
+--- /dev/null
++++ b/arch/mips/bcm63xx/dev-usb-ehci.c
+@@ -0,0 +1,92 @@
++/*
++ * 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) 2008 Maxime Bizon <mbizon@freebox.fr>
++ * Copyright (C) 2013 Florian Fainelli <florian@openwrt.org>
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/usb/ehci_pdriver.h>
++#include <linux/dma-mapping.h>
++
++#include <bcm63xx_cpu.h>
++#include <bcm63xx_regs.h>
++#include <bcm63xx_io.h>
++#include <bcm63xx_usb_priv.h>
++#include <bcm63xx_dev_usb_ehci.h>
++
++static struct resource ehci_resources[] = {
++ {
++ .start = -1, /* filled at runtime */
++ .end = -1, /* filled at runtime */
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = -1, /* filled at runtime */
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static u64 ehci_dmamask = DMA_BIT_MASK(32);
++
++static struct clk *usb_host_clock;
++
++static int bcm63xx_ehci_power_on(struct platform_device *pdev)
++{
++ usb_host_clock = clk_get(&pdev->dev, "usbh");
++ if (IS_ERR_OR_NULL(usb_host_clock))
++ return -ENODEV;
++
++ clk_prepare_enable(usb_host_clock);
++
++ bcm63xx_usb_priv_ehci_cfg_set();
++
++ return 0;
++}
++
++static void bcm63xx_ehci_power_off(struct platform_device *pdev)
++{
++ if (!IS_ERR_OR_NULL(usb_host_clock)) {
++ clk_disable_unprepare(usb_host_clock);
++ clk_put(usb_host_clock);
++ }
++}
++
++static struct usb_ehci_pdata bcm63xx_ehci_pdata = {
++ .big_endian_desc = 1,
++ .big_endian_mmio = 1,
++ .power_on = bcm63xx_ehci_power_on,
++ .power_off = bcm63xx_ehci_power_off,
++ .power_suspend = bcm63xx_ehci_power_off,
++};
++
++static struct platform_device bcm63xx_ehci_device = {
++ .name = "ehci-platform",
++ .id = -1,
++ .num_resources = ARRAY_SIZE(ehci_resources),
++ .resource = ehci_resources,
++ .dev = {
++ .platform_data = &bcm63xx_ehci_pdata,
++ .dma_mask = &ehci_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ },
++};
++
++int __init bcm63xx_ehci_register(void)
++{
++ if (!BCMCPU_IS_6328() && !BCMCPU_IS_6358() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
++ return 0;
++
++ ehci_resources[0].start = bcm63xx_regset_address(RSET_EHCI0);
++ ehci_resources[0].end = ehci_resources[0].start;
++ ehci_resources[0].end += RSET_EHCI_SIZE - 1;
++ ehci_resources[1].start = bcm63xx_get_irq_number(IRQ_EHCI0);
++
++ return platform_device_register(&bcm63xx_ehci_device);
++}
+--- /dev/null
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h
+@@ -0,0 +1,6 @@
++#ifndef BCM63XX_DEV_USB_EHCI_H_
++#define BCM63XX_DEV_USB_EHCI_H_
++
++int bcm63xx_ehci_register(void);
++
++#endif /* BCM63XX_DEV_USB_EHCI_H_ */
--- /dev/null
+From 709ef2034f5ba06da35f89856ad7baf2b7a41287 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:28 +0100
+Subject: [PATCH 10/11] MIPS: BCM63XX: register EHCI controller if board
+ enables it
+
+BCM63XX-based board can control the registration of the EHCI controller
+by setting their has_ehci0 flag to 1. Handle this in the generic
+code dealing with board registration and call the actual helper to register
+the EHCI controller.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/boards/board_bcm963xx.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -28,6 +28,7 @@
+ #include <bcm63xx_dev_hsspi.h>
+ #include <bcm63xx_dev_pcmcia.h>
+ #include <bcm63xx_dev_spi.h>
++#include <bcm63xx_dev_usb_ehci.h>
+ #include <bcm63xx_dev_usb_ohci.h>
+ #include <bcm63xx_dev_usb_usbd.h>
+ #include <board_bcm963xx.h>
+@@ -899,6 +900,9 @@ int __init board_register_devices(void)
+ if (board.has_usbd)
+ bcm63xx_usbd_register(&board.usbd);
+
++ if (board.has_ehci0)
++ bcm63xx_ehci_register();
++
+ if (board.has_ohci0)
+ bcm63xx_ohci_register();
+
--- /dev/null
+From 111bbd770441ab34f9da5bb1d85767a9b75227b4 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:30 +0100
+Subject: [PATCH 12/12] MIPS: BCM63XX: EHCI controller does not support
+ overcurrent
+
+This patch sets the ignore_oc flag for the BCM63XX EHCI controller as it
+does not support proper overcurrent reporting.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ arch/mips/bcm63xx/dev-usb-ehci.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/mips/bcm63xx/dev-usb-ehci.c
++++ b/arch/mips/bcm63xx/dev-usb-ehci.c
+@@ -61,6 +61,7 @@ static void bcm63xx_ehci_power_off(struc
+ static struct usb_ehci_pdata bcm63xx_ehci_pdata = {
+ .big_endian_desc = 1,
+ .big_endian_mmio = 1,
++ .ignore_oc = 1,
+ .power_on = bcm63xx_ehci_power_on,
+ .power_off = bcm63xx_ehci_power_off,
+ .power_suspend = bcm63xx_ehci_power_off,
--- /dev/null
+From 3f650fc30aa0badf9d02842ce396cea3eef2eeaa Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jonas.gorski@gmail.com>
+Date: Fri, 1 Jul 2011 23:16:47 +0200
+Subject: [PATCH 49/79] SPI: Allow specifying the parsers for SPI flash
+
+Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
+---
+ include/linux/spi/flash.h | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/include/linux/spi/flash.h
++++ b/include/linux/spi/flash.h
+@@ -2,7 +2,7 @@
+ #define LINUX_SPI_FLASH_H
+
+ struct mtd_partition;
+-
++struct mtd_part_parser_data;
+ /**
+ * struct flash_platform_data: board-specific flash data
+ * @name: optional flash device name (eg, as used with mtdparts=)
+@@ -10,6 +10,8 @@ struct mtd_partition;
+ * @nr_parts: number of mtd_partitions for static partitoning
+ * @type: optional flash device type (e.g. m25p80 vs m25p64), for use
+ * with chips that can't be queried for JEDEC or other IDs
++ * @part_probe_types: optional list of MTD parser names to use for
++ * partitioning
+ *
+ * Board init code (in arch/.../mach-xxx/board-yyy.c files) can
+ * provide information about SPI flash parts (such as DataFlash) to
+@@ -25,6 +27,7 @@ struct flash_platform_data {
+
+ char *type;
+
++ const char **part_probe_types;
+ /* we'll likely add more ... use JEDEC IDs, etc */
+ };
+
--- /dev/null
+From c7c3c338cb25d7f55ddb3f6bfbf3572758ca3896 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jonas.gorski@gmail.com>
+Date: Thu, 10 Nov 2011 16:53:08 +0100
+Subject: [PATCH 50/79] MTD: DEVICES: m25p80: use parsers if provided in flash
+ platform data
+
+Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
+---
+ drivers/mtd/devices/m25p80.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -229,7 +229,8 @@ static int m25p_probe(struct spi_device
+
+ ppdata.of_node = spi->dev.of_node;
+
+- return mtd_device_parse_register(&nor->mtd, NULL, &ppdata,
++ return mtd_device_parse_register(&nor->mtd,
++ data ? data->part_probe_types : NULL, &ppdata,
+ data ? data->parts : NULL,
+ data ? data->nr_parts : 0);
+ }
--- /dev/null
+From 5fb4e8d7287ac8fcb33aae8b1e9e22c5a3c392bd Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jonas.gorski@gmail.com>
+Date: Thu, 10 Nov 2011 17:33:40 +0100
+Subject: [PATCH 51/79] MTD: DEVICES: m25p80: add support for limiting reads
+
+Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
+---
+ drivers/mtd/devices/m25p80.c | 29 +++++++++++++++++++++++++++--
+ include/linux/spi/flash.h | 4 ++++
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -31,6 +31,7 @@
+ struct m25p {
+ struct spi_device *spi;
+ struct spi_nor spi_nor;
++ int max_transfer_len;
+ u8 command[MAX_CMD_SIZE];
+ };
+
+@@ -119,7 +120,7 @@ static inline unsigned int m25p80_rx_nbi
+ * Read an address range from the nor chip. The address range
+ * may be any size provided it is within the physical boundaries.
+ */
+-static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
++static int __m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+ {
+ struct m25p *flash = nor->priv;
+@@ -152,6 +153,29 @@ static int m25p80_read(struct spi_nor *n
+ return 0;
+ }
+
++static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
++ size_t *retlen, u_char *buf)
++{
++ struct m25p *flash = nor->priv;
++ size_t off;
++ size_t read_len = flash->max_transfer_len;
++ size_t part_len;
++ int ret = 0;
++
++ if (!read_len)
++ return __m25p80_read(nor, from, len, retlen, buf);
++
++ *retlen = 0;
++
++ for (off = 0; off < len && !ret; off += read_len) {
++ ret = __m25p80_read(nor, from + off, min(len - off, read_len),
++ &part_len, buf + off);
++ *retlen += part_len;
++ }
++
++ return ret;
++}
++
+ static int m25p80_erase(struct spi_nor *nor, loff_t offset)
+ {
+ struct m25p *flash = nor->priv;
+@@ -223,6 +247,9 @@ static int m25p_probe(struct spi_device
+ else
+ flash_name = spi->modalias;
+
++ if (data)
++ flash->max_transfer_len = data->max_transfer_len;
++
+ ret = spi_nor_scan(nor, flash_name, mode);
+ if (ret)
+ return ret;
+--- a/include/linux/spi/flash.h
++++ b/include/linux/spi/flash.h
+@@ -13,6 +13,8 @@ struct mtd_part_parser_data;
+ * @part_probe_types: optional list of MTD parser names to use for
+ * partitioning
+ *
++ * @max_transfer_len: option maximum read/write length limitation for
++ * SPI controllers not able to transfer any length commands.
+ * Board init code (in arch/.../mach-xxx/board-yyy.c files) can
+ * provide information about SPI flash parts (such as DataFlash) to
+ * help set up the device and its appropriate default partitioning.
+@@ -28,6 +30,8 @@ struct flash_platform_data {
+ char *type;
+
+ const char **part_probe_types;
++
++ unsigned int max_transfer_len;
+ /* we'll likely add more ... use JEDEC IDs, etc */
+ };
+
--- /dev/null
+From 6ac09efa8f0e189ffe7dd7b0889289de56ee44cc Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 19 Jan 2014 12:18:03 +0100
+Subject: [PATCH] USB: EHCI: allow limiting ports for ehci-platform
+
+In the same way as the ohci platform driver allows limiting ports,
+enable the same for ehci. This prevents a mismatch in the available
+ports between ehci/ohci on USB 2.0 controllers.
+
+This is needed if the USB host controller always reports the maximum
+number of ports regardless of the number of available ports (because
+one might be set to be usb device).
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ drivers/usb/host/ehci-hcd.c | 4 ++++
+ drivers/usb/host/ehci-platform.c | 2 ++
+ drivers/usb/host/ehci.h | 1 +
+ include/linux/usb/ehci_pdriver.h | 1 +
+ 4 files changed, 8 insertions(+)
+
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -666,6 +666,10 @@ int ehci_setup(struct usb_hcd *hcd)
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++ if (ehci->num_ports) {
++ ehci->hcs_params &= ~0xf; /* bits 3:0, ports on HC */
++ ehci->hcs_params |= ehci->num_ports;
++ }
+
+ ehci->sbrn = HCD_USB2;
+
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -60,6 +60,9 @@ static int ehci_platform_reset(struct us
+
+ ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
+
++ if (pdata->num_ports && pdata->num_ports <= 15)
++ ehci->num_ports = pdata->num_ports;
++
+ if (pdata->pre_setup) {
+ retval = pdata->pre_setup(hcd);
+ if (retval < 0)
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -213,6 +213,7 @@ struct ehci_hcd { /* one per controlle
+ u32 command;
+
+ /* SILICON QUIRKS */
++ unsigned int num_ports;
+ unsigned no_selective_suspend:1;
+ unsigned has_fsl_port_bug:1; /* FreeScale */
+ unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
+--- a/include/linux/usb/ehci_pdriver.h
++++ b/include/linux/usb/ehci_pdriver.h
+@@ -42,6 +42,7 @@ struct usb_hcd;
+ */
+ struct usb_ehci_pdata {
+ int caps_offset;
++ unsigned int num_ports;
+ unsigned has_tt:1;
+ unsigned has_synopsys_hc_bug:1;
+ unsigned big_endian_desc:1;
--- /dev/null
+From 5a50cb0d53344a2429831b00925d6183d4d332e1 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 9 Mar 2014 03:54:05 +0100
+Subject: [PATCH 40/44] MIPS: BCM63XX: move device registration code into its
+ own file
+
+Move device registration code into its own file to allow sharing it
+between board implementations.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/boards/Makefile | 1 +
+ arch/mips/bcm63xx/boards/board_bcm963xx.c | 188 +-------------------------
+ arch/mips/bcm63xx/boards/board_common.c | 215 ++++++++++++++++++++++++++++++
+ arch/mips/bcm63xx/boards/board_common.h | 8 ++
+ 4 files changed, 223 insertions(+), 183 deletions(-)
+ create mode 100644 arch/mips/bcm63xx/boards/board_common.c
+ create mode 100644 arch/mips/bcm63xx/boards/board_common.h
+
+--- a/arch/mips/bcm63xx/boards/Makefile
++++ b/arch/mips/bcm63xx/boards/Makefile
+@@ -1 +1,2 @@
++obj-y += board_common.o
+ obj-$(CONFIG_BOARD_BCM963XX) += board_bcm963xx.o
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -12,34 +12,21 @@
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+ #include <linux/string.h>
+-#include <linux/platform_device.h>
+-#include <linux/ssb/ssb.h>
+ #include <asm/addrspace.h>
+ #include <bcm63xx_board.h>
+ #include <bcm63xx_cpu.h>
+-#include <bcm63xx_dev_uart.h>
+ #include <bcm63xx_regs.h>
+ #include <bcm63xx_io.h>
+ #include <bcm63xx_nvram.h>
+-#include <bcm63xx_dev_pci.h>
+-#include <bcm63xx_dev_enet.h>
+-#include <bcm63xx_dev_dsp.h>
+-#include <bcm63xx_dev_flash.h>
+-#include <bcm63xx_dev_hsspi.h>
+-#include <bcm63xx_dev_pcmcia.h>
+-#include <bcm63xx_dev_spi.h>
+-#include <bcm63xx_dev_usb_ehci.h>
+-#include <bcm63xx_dev_usb_ohci.h>
+-#include <bcm63xx_dev_usb_usbd.h>
+ #include <board_bcm963xx.h>
+
++#include "board_common.h"
++
+ #include <uapi/linux/bcm933xx_hcs.h>
+
+
+ #define HCS_OFFSET_128K 0x20000
+
+-static struct board_info board;
+-
+ /*
+ * known 3368 boards
+ */
+@@ -712,52 +699,6 @@ static const struct board_info __initcon
+ };
+
+ /*
+- * Register a sane SPROMv2 to make the on-board
+- * bcm4318 WLAN work
+- */
+-#ifdef CONFIG_SSB_PCIHOST
+-static struct ssb_sprom bcm63xx_sprom = {
+- .revision = 0x02,
+- .board_rev = 0x17,
+- .country_code = 0x0,
+- .ant_available_bg = 0x3,
+- .pa0b0 = 0x15ae,
+- .pa0b1 = 0xfa85,
+- .pa0b2 = 0xfe8d,
+- .pa1b0 = 0xffff,
+- .pa1b1 = 0xffff,
+- .pa1b2 = 0xffff,
+- .gpio0 = 0xff,
+- .gpio1 = 0xff,
+- .gpio2 = 0xff,
+- .gpio3 = 0xff,
+- .maxpwr_bg = 0x004c,
+- .itssi_bg = 0x00,
+- .boardflags_lo = 0x2848,
+- .boardflags_hi = 0x0000,
+-};
+-
+-int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+-{
+- if (bus->bustype == SSB_BUSTYPE_PCI) {
+- memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
+- return 0;
+- } else {
+- pr_err("unable to fill SPROM for given bustype\n");
+- return -EINVAL;
+- }
+-}
+-#endif
+-
+-/*
+- * return board name for /proc/cpuinfo
+- */
+-const char *board_get_name(void)
+-{
+- return board.name;
+-}
+-
+-/*
+ * early init callback, read nvram data from flash and checksum it
+ */
+ void __init board_prom_init(void)
+@@ -802,140 +743,15 @@ void __init board_prom_init(void)
+ if (strncmp(board_name, bcm963xx_boards[i]->name, 16))
+ continue;
+ /* copy, board desc array is marked initdata */
+- memcpy(&board, bcm963xx_boards[i], sizeof(board));
++ board_early_setup(bcm963xx_boards[i]);
+ break;
+ }
+
+- /* bail out if board is not found, will complain later */
+- if (!board.name[0]) {
++ /* warn if board is not found, will complain later */
++ if (i == ARRAY_SIZE(bcm963xx_boards)) {
+ char name[17];
+ memcpy(name, board_name, 16);
+ name[16] = 0;
+ pr_err("unknown bcm963xx board: %s\n", name);
+- return;
+- }
+-
+- /* setup pin multiplexing depending on board enabled device,
+- * this has to be done this early since PCI init is done
+- * inside arch_initcall */
+- val = 0;
+-
+-#ifdef CONFIG_PCI
+- if (board.has_pci) {
+- bcm63xx_pci_enabled = 1;
+- if (BCMCPU_IS_6348())
+- val |= GPIO_MODE_6348_G2_PCI;
+- }
+-#endif
+-
+- if (board.has_pccard) {
+- if (BCMCPU_IS_6348())
+- val |= GPIO_MODE_6348_G1_MII_PCCARD;
+- }
+-
+- if (board.has_enet0 && !board.enet0.use_internal_phy) {
+- if (BCMCPU_IS_6348())
+- val |= GPIO_MODE_6348_G3_EXT_MII |
+- GPIO_MODE_6348_G0_EXT_MII;
+- }
+-
+- if (board.has_enet1 && !board.enet1.use_internal_phy) {
+- if (BCMCPU_IS_6348())
+- val |= GPIO_MODE_6348_G3_EXT_MII |
+- GPIO_MODE_6348_G0_EXT_MII;
+- }
+-
+- bcm_gpio_writel(val, GPIO_MODE_REG);
+-}
+-
+-/*
+- * second stage init callback, good time to panic if we couldn't
+- * identify on which board we're running since early printk is working
+- */
+-void __init board_setup(void)
+-{
+- if (!board.name[0])
+- panic("unable to detect bcm963xx board");
+- pr_info("board name: %s\n", board.name);
+-
+- /* make sure we're running on expected cpu */
+- if (bcm63xx_get_cpu_id() != board.expected_cpu_id)
+- panic("unexpected CPU for bcm963xx board");
+-}
+-
+-static struct gpio_led_platform_data bcm63xx_led_data;
+-
+-static struct platform_device bcm63xx_gpio_leds = {
+- .name = "leds-gpio",
+- .id = 0,
+- .dev.platform_data = &bcm63xx_led_data,
+-};
+-
+-/*
+- * third stage init callback, register all board devices.
+- */
+-int __init board_register_devices(void)
+-{
+- if (board.has_uart0)
+- bcm63xx_uart_register(0);
+-
+- if (board.has_uart1)
+- bcm63xx_uart_register(1);
+-
+- if (board.has_pccard)
+- bcm63xx_pcmcia_register();
+-
+- if (board.has_enet0 &&
+- !bcm63xx_nvram_get_mac_address(board.enet0.mac_addr))
+- bcm63xx_enet_register(0, &board.enet0);
+-
+- if (board.has_enet1 &&
+- !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))
+- bcm63xx_enet_register(1, &board.enet1);
+-
+- if (board.has_enetsw &&
+- !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr))
+- bcm63xx_enetsw_register(&board.enetsw);
+-
+- if (board.has_usbd)
+- bcm63xx_usbd_register(&board.usbd);
+-
+- if (board.has_ehci0)
+- bcm63xx_ehci_register();
+-
+- if (board.has_ohci0)
+- bcm63xx_ohci_register();
+-
+- if (board.has_dsp)
+- bcm63xx_dsp_register(&board.dsp);
+-
+- /* Generate MAC address for WLAN and register our SPROM,
+- * do this after registering enet devices
+- */
+-#ifdef CONFIG_SSB_PCIHOST
+- if (!bcm63xx_nvram_get_mac_address(bcm63xx_sprom.il0mac)) {
+- memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
+- memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
+- if (ssb_arch_register_fallback_sprom(
+- &bcm63xx_get_fallback_sprom) < 0)
+- pr_err("failed to register fallback SPROM\n");
+ }
+-#endif
+-
+- bcm63xx_spi_register();
+-
+- bcm63xx_hsspi_register();
+-
+- bcm63xx_flash_register();
+-
+- bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
+- bcm63xx_led_data.leds = board.leds;
+-
+- platform_device_register(&bcm63xx_gpio_leds);
+-
+- if (board.ephy_reset_gpio && board.ephy_reset_gpio_flags)
+- gpio_request_one(board.ephy_reset_gpio,
+- board.ephy_reset_gpio_flags, "ephy-reset");
+-
+- return 0;
+ }
+--- /dev/null
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -0,0 +1,218 @@
++/*
++ * 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) 2008 Maxime Bizon <mbizon@freebox.fr>
++ * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/platform_device.h>
++#include <linux/ssb/ssb.h>
++#include <asm/addrspace.h>
++#include <bcm63xx_board.h>
++#include <bcm63xx_cpu.h>
++#include <bcm63xx_dev_uart.h>
++#include <bcm63xx_regs.h>
++#include <bcm63xx_io.h>
++#include <bcm63xx_nvram.h>
++#include <bcm63xx_gpio.h>
++#include <bcm63xx_dev_pci.h>
++#include <bcm63xx_dev_enet.h>
++#include <bcm63xx_dev_dsp.h>
++#include <bcm63xx_dev_flash.h>
++#include <bcm63xx_dev_hsspi.h>
++#include <bcm63xx_dev_pcmcia.h>
++#include <bcm63xx_dev_spi.h>
++#include <bcm63xx_dev_usb_ehci.h>
++#include <bcm63xx_dev_usb_ohci.h>
++#include <bcm63xx_dev_usb_usbd.h>
++#include <board_bcm963xx.h>
++
++#define PFX "board: "
++
++static struct board_info board;
++
++/*
++ * Register a sane SPROMv2 to make the on-board
++ * bcm4318 WLAN work
++ */
++#ifdef CONFIG_SSB_PCIHOST
++static struct ssb_sprom bcm63xx_sprom = {
++ .revision = 0x02,
++ .board_rev = 0x17,
++ .country_code = 0x0,
++ .ant_available_bg = 0x3,
++ .pa0b0 = 0x15ae,
++ .pa0b1 = 0xfa85,
++ .pa0b2 = 0xfe8d,
++ .pa1b0 = 0xffff,
++ .pa1b1 = 0xffff,
++ .pa1b2 = 0xffff,
++ .gpio0 = 0xff,
++ .gpio1 = 0xff,
++ .gpio2 = 0xff,
++ .gpio3 = 0xff,
++ .maxpwr_bg = 0x004c,
++ .itssi_bg = 0x00,
++ .boardflags_lo = 0x2848,
++ .boardflags_hi = 0x0000,
++};
++
++int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
++{
++ if (bus->bustype == SSB_BUSTYPE_PCI) {
++ memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
++ return 0;
++ } else {
++ printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n");
++ return -EINVAL;
++ }
++}
++#endif
++
++/*
++ * return board name for /proc/cpuinfo
++ */
++const char *board_get_name(void)
++{
++ return board.name;
++}
++
++/*
++ * setup board for device registration
++ */
++void __init board_early_setup(const struct board_info *target)
++{
++ u32 val;
++
++ memcpy(&board, target, sizeof(board));
++
++ /* setup pin multiplexing depending on board enabled device,
++ * this has to be done this early since PCI init is done
++ * inside arch_initcall */
++ val = 0;
++
++#ifdef CONFIG_PCI
++ if (board.has_pci) {
++ bcm63xx_pci_enabled = 1;
++ if (BCMCPU_IS_6348())
++ val |= GPIO_MODE_6348_G2_PCI;
++ }
++#endif
++
++ if (board.has_pccard) {
++ if (BCMCPU_IS_6348())
++ val |= GPIO_MODE_6348_G1_MII_PCCARD;
++ }
++
++ if (board.has_enet0 && !board.enet0.use_internal_phy) {
++ if (BCMCPU_IS_6348())
++ val |= GPIO_MODE_6348_G3_EXT_MII |
++ GPIO_MODE_6348_G0_EXT_MII;
++ }
++
++ if (board.has_enet1 && !board.enet1.use_internal_phy) {
++ if (BCMCPU_IS_6348())
++ val |= GPIO_MODE_6348_G3_EXT_MII |
++ GPIO_MODE_6348_G0_EXT_MII;
++ }
++
++ bcm_gpio_writel(val, GPIO_MODE_REG);
++}
++
++
++/*
++ * second stage init callback, good time to panic if we couldn't
++ * identify on which board we're running since early printk is working
++ */
++void __init board_setup(void)
++{
++ if (!board.name[0])
++ panic("unable to detect bcm963xx board");
++ printk(KERN_INFO PFX "board name: %s\n", board.name);
++
++ /* make sure we're running on expected cpu */
++ if (bcm63xx_get_cpu_id() != board.expected_cpu_id)
++ panic("unexpected CPU for bcm963xx board");
++}
++
++static struct gpio_led_platform_data bcm63xx_led_data;
++
++static struct platform_device bcm63xx_gpio_leds = {
++ .name = "leds-gpio",
++ .id = 0,
++ .dev.platform_data = &bcm63xx_led_data,
++};
++
++/*
++ * third stage init callback, register all board devices.
++ */
++int __init board_register_devices(void)
++{
++ if (board.has_uart0)
++ bcm63xx_uart_register(0);
++
++ if (board.has_uart1)
++ bcm63xx_uart_register(1);
++
++ if (board.has_pccard)
++ bcm63xx_pcmcia_register();
++
++ if (board.has_enet0 &&
++ !bcm63xx_nvram_get_mac_address(board.enet0.mac_addr))
++ bcm63xx_enet_register(0, &board.enet0);
++
++ if (board.has_enet1 &&
++ !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))
++ bcm63xx_enet_register(1, &board.enet1);
++
++ if (board.has_enetsw &&
++ !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr))
++ bcm63xx_enetsw_register(&board.enetsw);
++
++ if (board.has_usbd)
++ bcm63xx_usbd_register(&board.usbd);
++
++ if (board.has_ehci0)
++ bcm63xx_ehci_register();
++
++ if (board.has_ohci0)
++ bcm63xx_ohci_register();
++
++ if (board.has_dsp)
++ bcm63xx_dsp_register(&board.dsp);
++
++ /* Generate MAC address for WLAN and register our SPROM,
++ * do this after registering enet devices
++ */
++#ifdef CONFIG_SSB_PCIHOST
++ if (!bcm63xx_nvram_get_mac_address(bcm63xx_sprom.il0mac)) {
++ memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
++ memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
++ if (ssb_arch_register_fallback_sprom(
++ &bcm63xx_get_fallback_sprom) < 0)
++ pr_err(PFX "failed to register fallback SPROM\n");
++ }
++#endif
++
++ bcm63xx_spi_register();
++
++ bcm63xx_hsspi_register();
++
++ bcm63xx_flash_register();
++
++ bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
++ bcm63xx_led_data.leds = board.leds;
++
++ platform_device_register(&bcm63xx_gpio_leds);
++
++ if (board.ephy_reset_gpio && board.ephy_reset_gpio_flags)
++ gpio_request_one(board.ephy_reset_gpio,
++ board.ephy_reset_gpio_flags, "ephy-reset");
++
++ return 0;
++}
+--- /dev/null
++++ b/arch/mips/bcm63xx/boards/board_common.h
+@@ -0,0 +1,8 @@
++#ifndef __BOARD_COMMON_H
++#define __BOARD_COMMON_H
++
++#include <board_bcm963xx.h>
++
++void board_early_setup(const struct board_info *board);
++
++#endif /* __BOARD_COMMON_H */
--- /dev/null
+From 4e9c34a37bd3442b286ba55441bfe22c1ac5b65f Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 9 Mar 2014 04:08:06 +0100
+Subject: [PATCH 41/44] MIPS: BCM63XX: pass a mac addresss allocator to board
+ setup
+
+Pass a mac address allocator to board setup code to allow board
+implementations to work with third party bootloaders not using nvram
+for configuration storage.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/boards/board_bcm963xx.c | 3 ++-
+ arch/mips/bcm63xx/boards/board_common.c | 16 ++++++++++------
+ arch/mips/bcm63xx/boards/board_common.h | 3 ++-
+ 3 files changed, 14 insertions(+), 8 deletions(-)
+
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -743,7 +743,8 @@ void __init board_prom_init(void)
+ if (strncmp(board_name, bcm963xx_boards[i]->name, 16))
+ continue;
+ /* copy, board desc array is marked initdata */
+- board_early_setup(bcm963xx_boards[i]);
++ board_early_setup(bcm963xx_boards[i],
++ bcm63xx_nvram_get_mac_address);
+ break;
+ }
+
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -18,7 +18,6 @@
+ #include <bcm63xx_dev_uart.h>
+ #include <bcm63xx_regs.h>
+ #include <bcm63xx_io.h>
+-#include <bcm63xx_nvram.h>
+ #include <bcm63xx_gpio.h>
+ #include <bcm63xx_dev_pci.h>
+ #include <bcm63xx_dev_enet.h>
+@@ -82,15 +81,20 @@ const char *board_get_name(void)
+ return board.name;
+ }
+
++static int (*board_get_mac_address)(u8 mac[ETH_ALEN]);
++
+ /*
+ * setup board for device registration
+ */
+-void __init board_early_setup(const struct board_info *target)
++void __init board_early_setup(const struct board_info *target,
++ int (*get_mac_address)(u8 mac[ETH_ALEN]))
+ {
+ u32 val;
+
+ memcpy(&board, target, sizeof(board));
+
++ board_get_mac_address = get_mac_address;
++
+ /* setup pin multiplexing depending on board enabled device,
+ * this has to be done this early since PCI init is done
+ * inside arch_initcall */
+@@ -163,15 +167,15 @@ int __init board_register_devices(void)
+ bcm63xx_pcmcia_register();
+
+ if (board.has_enet0 &&
+- !bcm63xx_nvram_get_mac_address(board.enet0.mac_addr))
++ !board_get_mac_address(board.enet0.mac_addr))
+ bcm63xx_enet_register(0, &board.enet0);
+
+ if (board.has_enet1 &&
+- !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))
++ !board_get_mac_address(board.enet1.mac_addr))
+ bcm63xx_enet_register(1, &board.enet1);
+
+ if (board.has_enetsw &&
+- !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr))
++ !board_get_mac_address(board.enetsw.mac_addr))
+ bcm63xx_enetsw_register(&board.enetsw);
+
+ if (board.has_usbd)
+@@ -190,7 +194,7 @@ int __init board_register_devices(void)
+ * do this after registering enet devices
+ */
+ #ifdef CONFIG_SSB_PCIHOST
+- if (!bcm63xx_nvram_get_mac_address(bcm63xx_sprom.il0mac)) {
++ if (!board_get_mac_address(bcm63xx_sprom.il0mac)) {
+ memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
+ memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
+ if (ssb_arch_register_fallback_sprom(
+--- a/arch/mips/bcm63xx/boards/board_common.h
++++ b/arch/mips/bcm63xx/boards/board_common.h
+@@ -3,6 +3,7 @@
+
+ #include <board_bcm963xx.h>
+
+-void board_early_setup(const struct board_info *board);
++void board_early_setup(const struct board_info *board,
++ int (*get_mac_address)(u8 mac[ETH_ALEN]));
+
+ #endif /* __BOARD_COMMON_H */
--- /dev/null
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -207,6 +207,9 @@ int __init board_register_devices(void)
+
+ bcm63xx_hsspi_register();
+
++ if (board.num_devs)
++ platform_add_devices(board.devs, board.num_devs);
++
+ bcm63xx_flash_register();
+
+ bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
+--- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
++++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
+@@ -53,6 +53,10 @@ struct board_info {
+
+ /* External PHY reset GPIO flags from gpio.h */
+ unsigned long ephy_reset_gpio_flags;
++
++ /* Additional platform devices */
++ struct platform_device **devs;
++ unsigned int num_devs;
+ };
+
+ #endif /* ! BOARD_BCM963XX_H_ */
--- /dev/null
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -12,6 +12,7 @@
+ #include <linux/string.h>
+ #include <linux/platform_device.h>
+ #include <linux/ssb/ssb.h>
++#include <linux/spi/spi.h>
+ #include <asm/addrspace.h>
+ #include <bcm63xx_board.h>
+ #include <bcm63xx_cpu.h>
+@@ -210,6 +211,9 @@ int __init board_register_devices(void)
+ if (board.num_devs)
+ platform_add_devices(board.devs, board.num_devs);
+
++ if (board.num_spis)
++ spi_register_board_info(board.spis, board.num_spis);
++
+ bcm63xx_flash_register();
+
+ bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
+--- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
++++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
+@@ -57,6 +57,10 @@ struct board_info {
+ /* Additional platform devices */
+ struct platform_device **devs;
+ unsigned int num_devs;
++
++ /* Additional platform devices */
++ struct spi_board_info *spis;
++ unsigned int num_spis;
+ };
+
+ #endif /* ! BOARD_BCM963XX_H_ */
--- /dev/null
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -723,10 +723,20 @@ void __init board_prom_init(void)
+
+ /* dump cfe version */
+ cfe = boot_addr + BCM963XX_CFE_VERSION_OFFSET;
+- if (!memcmp(cfe, "cfe-v", 5))
+- snprintf(cfe_version, sizeof(cfe_version), "%u.%u.%u-%u.%u",
+- cfe[5], cfe[6], cfe[7], cfe[8], cfe[9]);
+- else
++ if (strstarts(cfe, "cfe-")) {
++ if(cfe[4] == 'v') {
++ if(cfe[5] == 'd')
++ snprintf(cfe_version, 11, "%s", (char *) &cfe[5]);
++ else if (cfe[10] > 0)
++ snprintf(cfe_version, sizeof(cfe_version), "%u.%u.%u-%u.%u-%u",
++ cfe[5], cfe[6], cfe[7], cfe[8], cfe[9], cfe[10]);
++ else
++ snprintf(cfe_version, sizeof(cfe_version), "%u.%u.%u-%u.%u",
++ cfe[5], cfe[6], cfe[7], cfe[8], cfe[9]);
++ } else {
++ snprintf(cfe_version, 12, "%s", (char *) &cfe[4]);
++ }
++ } else
+ strcpy(cfe_version, "unknown");
+ pr_info("CFE version: %s\n", cfe_version);
+
--- /dev/null
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_board.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_board.h
+@@ -1,6 +1,8 @@
+ #ifndef BCM63XX_BOARD_H_
+ #define BCM63XX_BOARD_H_
+
++#include <asm/bootinfo.h>
++
+ const char *board_get_name(void);
+
+ void board_prom_init(void);
+@@ -9,4 +11,8 @@ void board_setup(void);
+
+ int board_register_devices(void);
+
++static inline bool bcm63xx_is_cfe_present(void) {
++ return fw_arg3 == 0x43464531;
++}
++
+ #endif /* ! BCM63XX_BOARD_H_ */
--- /dev/null
+--- a/drivers/mtd/bcm63xxpart.c
++++ b/drivers/mtd/bcm63xxpart.c
+@@ -35,7 +35,7 @@
+
+ #include <asm/mach-bcm63xx/bcm63xx_nvram.h>
+ #include <asm/mach-bcm63xx/bcm963xx_tag.h>
+-#include <asm/mach-bcm63xx/board_bcm963xx.h>
++#include <asm/mach-bcm63xx/bcm63xx_board.h>
+
+ #define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */
+
+@@ -43,30 +43,6 @@
+
+ #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
+
+-static int bcm63xx_detect_cfe(struct mtd_info *master)
+-{
+- char buf[9];
+- int ret;
+- size_t retlen;
+-
+- ret = mtd_read(master, BCM963XX_CFE_VERSION_OFFSET, 5, &retlen,
+- (void *)buf);
+- buf[retlen] = 0;
+-
+- if (ret)
+- return ret;
+-
+- if (strncmp("cfe-v", buf, 5) == 0)
+- return 0;
+-
+- /* very old CFE's do not have the cfe-v string, so check for magic */
+- ret = mtd_read(master, BCM63XX_CFE_MAGIC_OFFSET, 8, &retlen,
+- (void *)buf);
+- buf[retlen] = 0;
+-
+- return strncmp("CFE1CFE1", buf, 8);
+-}
+-
+ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+@@ -85,7 +61,7 @@ static int bcm63xx_parse_cfe_partitions(
+ u32 computed_crc;
+ bool rootfs_first = false;
+
+- if (bcm63xx_detect_cfe(master))
++ if (!bcm63xx_is_cfe_present())
+ return -EINVAL;
+
+ cfe_erasesize = max_t(uint32_t, master->erasesize,
--- /dev/null
+From 301744ecbeece89ab3a9d6beef7802fa22598f00 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 30 Nov 2014 14:53:12 +0100
+Subject: [PATCH 1/5] irqchip: add support for bcm6345-style periphery irq
+ controller
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ .../brcm,bcm6345-periph-intc.txt | 50 +++
+ drivers/irqchip/Kconfig | 4 +
+ drivers/irqchip/Makefile | 1 +
+ drivers/irqchip/irq-bcm6345-periph.c | 339 ++++++++++++++++++++
+ include/linux/irqchip/irq-bcm6345-periph.h | 16 +
+ 5 files changed, 410 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-periph-intc.txt
+ create mode 100644 drivers/irqchip/irq-bcm6345-periph.c
+ create mode 100644 include/linux/irqchip/irq-bcm6345-periph.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-periph-intc.txt
+@@ -0,0 +1,50 @@
++Broadcom BCM6345 Level 1 periphery interrupt controller
++
++This block is a interrupt controller that is typically connected directly
++to one of the HW INT lines on each CPU. Every BCM63XX xDSL chip since
++BCM6345 has contained this hardware.
++
++Key elements of the hardware design include:
++
++- 32, 64, or 128 incoming level IRQ lines
++
++- All onchip peripherals are wired directly to an L2 input
++
++- A separate instance of the register set for each CPU, allowing individual
++ peripheral IRQs to be routed to any CPU
++
++- No atomic mask/unmask operations
++
++- No polarity/level/edge settings
++
++- No FIFO or priority encoder logic; software is expected to read all
++ 1-4 status words to determine which IRQs are pending
++
++Required properties:
++
++- compatible: Should be "brcm,bcm6345-periph-intc".
++- reg: Specifies the base physical address and size of the registers.
++ Multiple register addresses may be specified, and must match the amount of
++ parent interrupts.
++- 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
++ 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.
++ Multiple lines are used to route interrupts to different cpus, with the first
++ assumed to be for the boot CPU.
++
++Example:
++
++periph_intc: interrupt-controller@f0406800 {
++ compatible = "brcm,bcm6345-periph-intc";
++ reg = <0x10000020 0x10>, <0x10000030 0x10>;
++
++ interrupt-controller;
++ #interrupt-cells = <1>;
++
++ interrupt-parent = <&cpu_intc>;
++ interrupts = <2>, <3>;
++};
+--- a/drivers/irqchip/Kconfig
++++ b/drivers/irqchip/Kconfig
+@@ -80,6 +80,10 @@ config BRCMSTB_L2_IRQ
+ select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+
++config BCM6345_PERIPH_IRQ
++ bool
++ select IRQ_DOMAIN
++
+ config DW_APB_ICTL
+ bool
+ select GENERIC_IRQ_CHIP
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_ARCH_MVEBU) += irq-armada-
+ obj-$(CONFIG_IRQ_MXS) += irq-mxs.o
+ obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o
+ obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
++obj-$(CONFIG_BCM6345_PERIPH_IRQ) += irq-bcm6345-periph.o
+ obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o
+ obj-$(CONFIG_METAG) += irq-metag-ext.o
+ obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
+--- /dev/null
++++ b/drivers/irqchip/irq-bcm6345-periph.c
+@@ -0,0 +1,339 @@
++/*
++ * 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 Jonas Gorski <jogo@openwrt.org>
++ */
++
++#include <linux/ioport.h>
++#include <linux/irq.h>
++#include <linux/irqchip.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqchip/irq-bcm6345-periph.h>
++#include <linux/kernel.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++
++#ifdef CONFIG_BCM63XX
++#include <asm/mach-bcm63xx/bcm63xx_irq.h>
++
++#define VIRQ_BASE IRQ_INTERNAL_BASE
++#else
++#define VIRQ_BASE 0
++#endif
++
++#define MAX_WORDS 4
++#define MAX_PARENT_IRQS 2
++#define IRQS_PER_WORD 32
++
++struct intc_block {
++ int parent_irq;
++ void __iomem *base;
++ void __iomem *en_reg[MAX_WORDS];
++ void __iomem *status_reg[MAX_WORDS];
++ u32 mask_cache[MAX_WORDS];
++};
++
++struct intc_data {
++ struct irq_chip chip;
++ struct intc_block block[MAX_PARENT_IRQS];
++
++ int num_words;
++
++ struct irq_domain *domain;
++ raw_spinlock_t lock;
++};
++
++static void bcm6345_periph_irq_handle(struct irq_desc *desc)
++{
++ struct intc_data *data = irq_desc_get_handler_data(desc);
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ struct intc_block *block;
++ unsigned int irq = irq_desc_get_irq(desc);
++ unsigned int idx;
++
++ chained_irq_enter(chip, desc);
++
++ for (idx = 0; idx < MAX_PARENT_IRQS; idx++)
++ if (irq == data->block[idx].parent_irq)
++ block = &data->block[idx];
++
++ for (idx = 0; idx < data->num_words; idx++) {
++ int base = idx * IRQS_PER_WORD;
++ unsigned long pending;
++ int hw_irq;
++
++ raw_spin_lock(&data->lock);
++ pending = __raw_readl(block->en_reg[idx]) &
++ __raw_readl(block->status_reg[idx]);
++ raw_spin_unlock(&data->lock);
++
++ for_each_set_bit(hw_irq, &pending, IRQS_PER_WORD) {
++ int virq;
++
++ virq = irq_find_mapping(data->domain, base + hw_irq);
++ generic_handle_irq(virq);
++ }
++ }
++
++ chained_irq_exit(chip, desc);
++}
++
++static void __bcm6345_periph_enable(struct intc_block *block, int reg, int bit,
++ bool enable)
++{
++ u32 val;
++
++ val = __raw_readl(block->en_reg[reg]);
++ if (enable)
++ val |= BIT(bit);
++ else
++ val &= ~BIT(bit);
++ __raw_writel(val, block->en_reg[reg]);
++}
++
++static void bcm6345_periph_irq_mask(struct irq_data *data)
++{
++ unsigned int i, reg, bit;
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++
++ reg = hwirq / IRQS_PER_WORD;
++ bit = hwirq % IRQS_PER_WORD;
++
++ raw_spin_lock(&priv->lock);
++ for (i = 0; i < MAX_PARENT_IRQS; i++) {
++ struct intc_block *block = &priv->block[i];
++
++ if (!block->parent_irq)
++ break;
++
++ __bcm6345_periph_enable(block, reg, bit, false);
++ }
++ raw_spin_unlock(&priv->lock);
++}
++
++static void bcm6345_periph_irq_unmask(struct irq_data *data)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ unsigned int i, reg, bit;
++
++ reg = hwirq / IRQS_PER_WORD;
++ bit = hwirq % IRQS_PER_WORD;
++
++ raw_spin_lock(&priv->lock);
++ for (i = 0; i < MAX_PARENT_IRQS; i++) {
++ struct intc_block *block = &priv->block[i];
++
++ if (!block->parent_irq)
++ break;
++
++ if (block->mask_cache[reg] & BIT(bit))
++ __bcm6345_periph_enable(block, reg, bit, true);
++ else
++ __bcm6345_periph_enable(block, reg, bit, false);
++ }
++ raw_spin_unlock(&priv->lock);
++}
++
++#ifdef CONFIG_SMP
++static int bcm6345_periph_set_affinity(struct irq_data *data,
++ const struct cpumask *mask, bool force)
++{
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ struct intc_data *priv = data->domain->host_data;
++ unsigned int i, reg, bit;
++ unsigned long flags;
++ bool enabled;
++ int cpu;
++
++ reg = hwirq / IRQS_PER_WORD;
++ bit = hwirq % IRQS_PER_WORD;
++
++ /* we could route to more than one cpu, but performance
++ suffers, so fix it to one.
++ */
++ cpu = cpumask_any_and(mask, cpu_online_mask);
++ if (cpu >= nr_cpu_ids)
++ return -EINVAL;
++
++ if (cpu >= MAX_PARENT_IRQS)
++ return -EINVAL;
++
++ if (!priv->block[cpu].parent_irq)
++ return -EINVAL;
++
++ raw_spin_lock_irqsave(&priv->lock, flags);
++ enabled = !irqd_irq_masked(data);
++ for (i = 0; i < MAX_PARENT_IRQS; i++) {
++ struct intc_block *block = &priv->block[i];
++
++ if (!block->parent_irq)
++ break;
++
++ if (i == cpu) {
++ block->mask_cache[reg] |= BIT(bit);
++ __bcm6345_periph_enable(block, reg, bit, enabled);
++ } else {
++ block->mask_cache[reg] &= ~BIT(bit);
++ __bcm6345_periph_enable(block, reg, bit, false);
++ }
++ }
++ raw_spin_unlock_irqrestore(&priv->lock, flags);
++
++ return 0;
++}
++#endif
++
++static int bcm6345_periph_map(struct irq_domain *d, unsigned int irq,
++ irq_hw_number_t hw)
++{
++ struct intc_data *priv = d->host_data;
++
++ irq_set_chip_and_handler(irq, &priv->chip, handle_level_irq);
++
++ return 0;
++}
++
++static const struct irq_domain_ops bcm6345_periph_domain_ops = {
++ .xlate = irq_domain_xlate_onecell,
++ .map = bcm6345_periph_map,
++};
++
++static int __init __bcm6345_periph_intc_init(struct device_node *node,
++ int num_blocks, int *irq,
++ void __iomem **base, int num_words)
++{
++ struct intc_data *data;
++ unsigned int i, w, status_offset;
++
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ raw_spin_lock_init(&data->lock);
++
++ status_offset = num_words * sizeof(u32);
++
++ for (i = 0; i < num_blocks; i++) {
++ struct intc_block *block = &data->block[i];
++
++ block->parent_irq = irq[i];
++ block->base = base[i];
++
++ for (w = 0; w < num_words; w++) {
++ int word_offset = sizeof(u32) * ((num_words - w) - 1);
++
++ block->en_reg[w] = base[i] + word_offset;
++ block->status_reg[w] = base[i] + status_offset;
++ block->status_reg[w] += word_offset;
++
++ /* route all interrupts to line 0 by default */
++ if (i == 0)
++ block->mask_cache[w] = 0xffffffff;
++ }
++
++ irq_set_handler_data(block->parent_irq, data);
++ irq_set_chained_handler(block->parent_irq,
++ bcm6345_periph_irq_handle);
++ }
++
++ data->num_words = num_words;
++
++ data->chip.name = "bcm6345-periph-intc";
++ data->chip.irq_mask = bcm6345_periph_irq_mask;
++ data->chip.irq_unmask = bcm6345_periph_irq_unmask;
++
++#ifdef CONFIG_SMP
++ if (num_blocks > 1)
++ data->chip.irq_set_affinity = bcm6345_periph_set_affinity;
++#endif
++
++ data->domain = irq_domain_add_simple(node, IRQS_PER_WORD * num_words,
++ VIRQ_BASE,
++ &bcm6345_periph_domain_ops, data);
++ if (!data->domain) {
++ kfree(data);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++void __init bcm6345_periph_intc_init(int num_blocks, int *irq,
++ void __iomem **base, int num_words)
++{
++ __bcm6345_periph_intc_init(NULL, num_blocks, irq, base, num_words);
++}
++
++#ifdef CONFIG_OF
++static int __init bcm6345_periph_of_init(struct device_node *node,
++ struct device_node *parent)
++{
++ struct resource res;
++ int num_irqs, ret = -EINVAL;
++ int irqs[MAX_PARENT_IRQS] = { 0 };
++ void __iomem *bases[MAX_PARENT_IRQS] = { NULL };
++ int words = 0;
++ int i;
++
++ num_irqs = of_irq_count(node);
++
++ if (num_irqs < 1 || num_irqs > MAX_PARENT_IRQS)
++ return -EINVAL;
++
++ for (i = 0; i < num_irqs; i++) {
++ resource_size_t size;
++
++ irqs[i] = irq_of_parse_and_map(node, i);
++ if (!irqs[i])
++ goto out_unmap;
++
++ if (of_address_to_resource(node, i, &res))
++ goto out_unmap;
++
++ size = resource_size(&res);
++ switch (size) {
++ case 8:
++ case 16:
++ case 32:
++ size = size / 8;
++ break;
++ default:
++ goto out_unmap;
++ }
++
++ if (words && words != size) {
++ ret = -EINVAL;
++ goto out_unmap;
++ }
++ words = size;
++
++ bases[i] = of_iomap(node, i);
++ if (!bases[i]) {
++ ret = -ENOMEM;
++ goto out_unmap;
++ }
++ }
++
++ ret = __bcm6345_periph_intc_init(node, num_irqs, irqs, bases, words);
++ if (!ret)
++ return 0;
++
++out_unmap:
++ for (i = 0; i < num_irqs; i++) {
++ iounmap(bases[i]);
++ irq_dispose_mapping(irqs[i]);
++ }
++
++ return ret;
++}
++
++IRQCHIP_DECLARE(bcm6345_periph_intc, "brcm,bcm6345-periph-intc",
++ bcm6345_periph_of_init);
++#endif
+--- /dev/null
++++ b/include/linux/irqchip/irq-bcm6345-periph.h
+@@ -0,0 +1,16 @@
++/*
++ * 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) 2008 Maxime Bizon <mbizon@freebox.fr>
++ * Copyright (C) 2008 Nicolas Schichan <nschichan@freebox.fr>
++ */
++
++#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_PERIPH_H
++#define __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_PERIPH_H
++
++void bcm6345_periph_intc_init(int num_blocks, int *irq, void __iomem **base,
++ int num_words);
++
++#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_PERIPH_H */
--- /dev/null
+From cf908990d4a8ccdb73ee4484aa8cadad379ca314 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 30 Nov 2014 14:54:27 +0100
+Subject: [PATCH 2/5] irqchip: add support for bcm6345-style external
+ interrupt controller
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ .../interrupt-controller/brcm,bcm6345-ext-intc.txt | 29 ++
+ drivers/irqchip/Kconfig | 4 +
+ drivers/irqchip/Makefile | 1 +
+ drivers/irqchip/irq-bcm6345-ext.c | 287 ++++++++++++++++++++
+ include/linux/irqchip/irq-bcm6345-ext.h | 14 +
+ 5 files changed, 335 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-ext-intc.txt
+ create mode 100644 drivers/irqchip/irq-bcm6345-ext.c
+ create mode 100644 include/linux/irqchip/irq-bcm6345-ext.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-ext-intc.txt
+@@ -0,0 +1,29 @@
++Broadcom BCM6345-style external interrupt controller
++
++Required properties:
++
++- compatible: Should be "brcm,bcm6345-ext-intc".
++- reg: Specifies the base physical addresses and size of the registers.
++- interrupt-controller: identifies the node as an interrupt controller.
++- #interrupt-cells: Specifies the number of cells needed to encode an interrupt
++ source, Should be 2.
++- interrupt-parent: Specifies the phandle to the parent interrupt controller
++ 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.
++
++Optional properties:
++
++- brcm,field-width: Size of each field (mask, clear, sense, ...) in bits in the
++ register. Defaults to 4.
++
++Example:
++
++ext_intc: interrupt-controller@10000018 {
++ compatible = "brcm,bcm6345-ext-intc";
++ interrupt-parent = <&periph_intc>;
++ #interrupt-cells = <2>;
++ reg = <0x10000018 0x4>;
++ interrupt-controller;
++ interrupts = <24>, <25>, <26>, <27>;
++};
+--- a/drivers/irqchip/Kconfig
++++ b/drivers/irqchip/Kconfig
+@@ -80,6 +80,10 @@ config BRCMSTB_L2_IRQ
+ select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+
++config BCM6345_EXT_IRQ
++ bool
++ select IRQ_DOMAIN
++
+ config BCM6345_PERIPH_IRQ
+ bool
+ select IRQ_DOMAIN
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_ARCH_MVEBU) += irq-armada-
+ obj-$(CONFIG_IRQ_MXS) += irq-mxs.o
+ obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o
+ obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
++obj-$(CONFIG_BCM6345_EXT_IRQ) += irq-bcm6345-ext.o
+ obj-$(CONFIG_BCM6345_PERIPH_IRQ) += irq-bcm6345-periph.o
+ obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o
+ obj-$(CONFIG_METAG) += irq-metag-ext.o
+--- /dev/null
++++ b/drivers/irqchip/irq-bcm6345-ext.c
+@@ -0,0 +1,288 @@
++/*
++ * 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 Jonas Gorski <jogo@openwrt.org>
++ */
++
++#include <linux/ioport.h>
++#include <linux/irq.h>
++#include <linux/irqchip.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqchip/irq-bcm6345-ext.h>
++#include <linux/kernel.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++
++#ifdef CONFIG_BCM63XX
++#include <asm/mach-bcm63xx/bcm63xx_irq.h>
++
++#define VIRQ_BASE IRQ_EXTERNAL_BASE
++#else
++#define VIRQ_BASE 0
++#endif
++
++#define MAX_IRQS 4
++
++#define EXTIRQ_CFG_SENSE 0
++#define EXTIRQ_CFG_STAT 1
++#define EXTIRQ_CFG_CLEAR 2
++#define EXTIRQ_CFG_MASK 3
++#define EXTIRQ_CFG_BOTHEDGE 4
++#define EXTIRQ_CFG_LEVELSENSE 5
++
++struct intc_data {
++ struct irq_chip chip;
++ struct irq_domain *domain;
++ raw_spinlock_t lock;
++
++ int parent_irq[MAX_IRQS];
++ void __iomem *reg;
++ int shift;
++};
++
++static void bcm6345_ext_intc_irq_handle(struct irq_desc *desc)
++{
++ struct intc_data *data = irq_desc_get_handler_data(desc);
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ unsigned int irq = irq_desc_get_irq(desc);
++ unsigned int idx;
++
++ chained_irq_enter(chip, desc);
++
++ for (idx = 0; idx < MAX_IRQS; idx++) {
++ if (data->parent_irq[idx] != irq)
++ continue;
++
++ generic_handle_irq(irq_find_mapping(data->domain, idx));
++ }
++
++ chained_irq_exit(chip, desc);
++}
++
++static void bcm6345_ext_intc_irq_ack(struct irq_data *data)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ u32 reg;
++
++ raw_spin_lock(&priv->lock);
++ reg = __raw_readl(priv->reg);
++ reg |= hwirq << (EXTIRQ_CFG_CLEAR * priv->shift);
++ __raw_writel(reg, priv->reg);
++ raw_spin_unlock(&priv->lock);
++}
++
++static void bcm6345_ext_intc_irq_mask(struct irq_data *data)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ u32 reg;
++
++ raw_spin_lock(&priv->lock);
++ reg = __raw_readl(priv->reg);
++ reg &= ~(hwirq << (EXTIRQ_CFG_MASK * priv->shift));
++ __raw_writel(reg, priv->reg);
++ raw_spin_unlock(&priv->lock);
++}
++
++static void bcm6345_ext_intc_irq_unmask(struct irq_data *data)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ u32 reg;
++
++ raw_spin_lock(&priv->lock);
++ reg = __raw_readl(priv->reg);
++ reg |= hwirq << (EXTIRQ_CFG_MASK * priv->shift);
++ __raw_writel(reg, priv->reg);
++ raw_spin_unlock(&priv->lock);
++}
++
++static int bcm6345_ext_intc_set_type(struct irq_data *data,
++ unsigned int flow_type)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ bool levelsense = 0, sense = 0, bothedge = 0;
++ u32 reg;
++
++ flow_type &= IRQ_TYPE_SENSE_MASK;
++
++ if (flow_type == IRQ_TYPE_NONE)
++ flow_type = IRQ_TYPE_LEVEL_LOW;
++
++ switch (flow_type) {
++ case IRQ_TYPE_EDGE_BOTH:
++ bothedge = 1;
++ break;
++
++ case IRQ_TYPE_EDGE_RISING:
++ break;
++
++ case IRQ_TYPE_EDGE_FALLING:
++ sense = 1;
++ break;
++
++ case IRQ_TYPE_LEVEL_HIGH:
++ levelsense = 1;
++ sense = 1;
++ break;
++
++ case IRQ_TYPE_LEVEL_LOW:
++ levelsense = 1;
++ break;
++
++ default:
++ pr_err("bogus flow type combination given!\n");
++ return -EINVAL;
++ }
++
++ raw_spin_lock(&priv->lock);
++ reg = __raw_readl(priv->reg);
++
++ if (levelsense)
++ reg |= hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift);
++ else
++ reg &= ~(hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift));
++ if (sense)
++ reg |= hwirq << (EXTIRQ_CFG_SENSE * priv->shift);
++ else
++ reg &= ~(hwirq << (EXTIRQ_CFG_SENSE * priv->shift));
++ if (bothedge)
++ reg |= hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift);
++ else
++ reg &= ~(hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift));
++
++ __raw_writel(reg, priv->reg);
++ raw_spin_unlock(&priv->lock);
++
++ irqd_set_trigger_type(data, flow_type);
++ if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
++ irq_set_handler_locked(data, handle_level_irq);
++ else
++ irq_set_handler_locked(data, handle_edge_irq);
++
++ return 0;
++}
++
++static int bcm6345_ext_intc_map(struct irq_domain *d, unsigned int irq,
++ irq_hw_number_t hw)
++{
++ struct intc_data *priv = d->host_data;
++
++ irq_set_chip_and_handler(irq, &priv->chip, handle_level_irq);
++
++ return 0;
++}
++
++static const struct irq_domain_ops bcm6345_ext_domain_ops = {
++ .xlate = irq_domain_xlate_twocell,
++ .map = bcm6345_ext_intc_map,
++};
++
++static int __init __bcm6345_ext_intc_init(struct device_node *node,
++ int num_irqs, int *irqs,
++ void __iomem *reg, int shift)
++{
++ struct intc_data *data;
++ unsigned int i;
++ int start = VIRQ_BASE;
++
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ raw_spin_lock_init(&data->lock);
++
++ for (i = 0; i < num_irqs; i++) {
++ data->parent_irq[i] = irqs[i];
++
++ irq_set_handler_data(irqs[i], data);
++ irq_set_chained_handler(irqs[i], bcm6345_ext_intc_irq_handle);
++ }
++
++ data->reg = reg;
++ data->shift = shift;
++
++ data->chip.name = "bcm6345-ext-intc";
++ data->chip.irq_ack = bcm6345_ext_intc_irq_ack;
++ data->chip.irq_mask = bcm6345_ext_intc_irq_mask;
++ data->chip.irq_unmask = bcm6345_ext_intc_irq_unmask;
++ data->chip.irq_set_type = bcm6345_ext_intc_set_type;
++
++ /*
++ * If we have less than 4 irqs, this is the second controller on
++ * bcm63xx. So increase the VIRQ start to not overlap with the first
++ * one, but only do so if we actually use a non-zero start.
++ *
++ * This can be removed when bcm63xx has no legacy users anymore.
++ */
++ if (start && num_irqs < 4)
++ start += 4;
++
++ data->domain = irq_domain_add_simple(node, num_irqs, start,
++ &bcm6345_ext_domain_ops, data);
++ if (!data->domain) {
++ kfree(data);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++void __init bcm6345_ext_intc_init(int num_irqs, int *irqs, void __iomem *reg,
++ int shift)
++{
++ __bcm6345_ext_intc_init(NULL, num_irqs, irqs, reg, shift);
++}
++
++#ifdef CONFIG_OF
++static int __init bcm6345_ext_intc_of_init(struct device_node *node,
++ struct device_node *parent)
++{
++ int num_irqs, ret = -EINVAL;
++ unsigned i;
++ void __iomem *base;
++ int irqs[MAX_IRQS] = { 0 };
++ u32 shift;
++
++ num_irqs = of_irq_count(node);
++
++ if (!num_irqs || num_irqs > MAX_IRQS)
++ return -EINVAL;
++
++ if (of_property_read_u32(node, "brcm,field-width", &shift))
++ shift = 4;
++
++ for (i = 0; i < num_irqs; i++) {
++ irqs[i] = irq_of_parse_and_map(node, i);
++ if (!irqs[i]) {
++ ret = -ENOMEM;
++ goto out_unmap;
++ }
++ }
++
++ base = of_iomap(node, 0);
++ if (!base)
++ goto out_unmap;
++
++ ret = __bcm6345_ext_intc_init(node, num_irqs, irqs, base, shift);
++ if (!ret)
++ return 0;
++out_unmap:
++ iounmap(base);
++
++ for (i = 0; i < num_irqs; i++)
++ irq_dispose_mapping(irqs[i]);
++
++ return ret;
++}
++
++IRQCHIP_DECLARE(bcm6345_ext_intc, "brcm,bcm6345-ext-intc",
++ bcm6345_ext_intc_of_init);
++#endif
+--- /dev/null
++++ b/include/linux/irqchip/irq-bcm6345-ext.h
+@@ -0,0 +1,14 @@
++/*
++ * 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 Jonas Gorski <jogo@openwrt.org>
++ */
++
++#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_EXT_H
++#define __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_EXT_H
++
++void bcm6345_ext_intc_init(int n_irqs, int *irqs, void __iomem *reg, int shift);
++
++#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_EXT_H */
--- /dev/null
+From d2d2489e0a4b740abd980e9d1cad952d15bc2d9e Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 30 Nov 2014 14:55:02 +0100
+Subject: [PATCH] MIPS: BCM63XX: switch to IRQ_DOMAIN
+
+Now that we have working IRQ_DOMAIN drivers for both interrupt controllers,
+switch to using them.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/Kconfig | 3 +
+ arch/mips/bcm63xx/irq.c | 612 +++++++++---------------------------------------
+ 2 files changed, 108 insertions(+), 507 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -206,6 +206,9 @@ config BCM63XX
+ select SYNC_R4K
+ select DMA_NONCOHERENT
+ select IRQ_MIPS_CPU
++ select BCM6345_EXT_IRQ
++ select BCM6345_PERIPH_IRQ
++ select IRQ_DOMAIN
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_HAS_EARLY_PRINTK
+--- a/arch/mips/bcm63xx/irq.c
++++ b/arch/mips/bcm63xx/irq.c
+@@ -12,7 +12,9 @@
+ #include <linux/interrupt.h>
+ #include <linux/module.h>
+ #include <linux/irq.h>
+-#include <linux/spinlock.h>
++#include <linux/irqchip.h>
++#include <linux/irqchip/irq-bcm6345-ext.h>
++#include <linux/irqchip/irq-bcm6345-periph.h>
+ #include <asm/irq_cpu.h>
+ #include <asm/mipsregs.h>
+ #include <bcm63xx_cpu.h>
+@@ -20,544 +22,140 @@
+ #include <bcm63xx_io.h>
+ #include <bcm63xx_irq.h>
+
+-
+-static DEFINE_SPINLOCK(ipic_lock);
+-static DEFINE_SPINLOCK(epic_lock);
+-
+-static u32 irq_stat_addr[2];
+-static u32 irq_mask_addr[2];
+-static void (*dispatch_internal)(int cpu);
+-static int is_ext_irq_cascaded;
+-static unsigned int ext_irq_count;
+-static unsigned int ext_irq_start, ext_irq_end;
+-static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2;
+-static void (*internal_irq_mask)(struct irq_data *d);
+-static void (*internal_irq_unmask)(struct irq_data *d, const struct cpumask *m);
+-
+-
+-static inline u32 get_ext_irq_perf_reg(int irq)
+-{
+- if (irq < 4)
+- return ext_irq_cfg_reg1;
+- return ext_irq_cfg_reg2;
+-}
+-
+-static inline void handle_internal(int intbit)
+-{
+- if (is_ext_irq_cascaded &&
+- intbit >= ext_irq_start && intbit <= ext_irq_end)
+- do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE);
+- else
+- do_IRQ(intbit + IRQ_INTERNAL_BASE);
+-}
+-
+-static inline int enable_irq_for_cpu(int cpu, struct irq_data *d,
+- const struct cpumask *m)
+-{
+- bool enable = cpu_online(cpu);
+-
+-#ifdef CONFIG_SMP
+- if (m)
+- enable &= cpumask_test_cpu(cpu, m);
+- else if (irqd_affinity_was_set(d))
+- enable &= cpumask_test_cpu(cpu, irq_data_get_affinity_mask(d));
+-#endif
+- return enable;
+-}
+-
+-/*
+- * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
+- * prioritize any interrupt relatively to another. the static counter
+- * will resume the loop where it ended the last time we left this
+- * function.
+- */
+-
+-#define BUILD_IPIC_INTERNAL(width) \
+-void __dispatch_internal_##width(int cpu) \
+-{ \
+- u32 pending[width / 32]; \
+- unsigned int src, tgt; \
+- bool irqs_pending = false; \
+- static unsigned int i[2]; \
+- unsigned int *next = &i[cpu]; \
+- unsigned long flags; \
+- \
+- /* read registers in reverse order */ \
+- spin_lock_irqsave(&ipic_lock, flags); \
+- for (src = 0, tgt = (width / 32); src < (width / 32); src++) { \
+- u32 val; \
+- \
+- val = bcm_readl(irq_stat_addr[cpu] + src * sizeof(u32)); \
+- val &= bcm_readl(irq_mask_addr[cpu] + src * sizeof(u32)); \
+- pending[--tgt] = val; \
+- \
+- if (val) \
+- irqs_pending = true; \
+- } \
+- spin_unlock_irqrestore(&ipic_lock, flags); \
+- \
+- if (!irqs_pending) \
+- return; \
+- \
+- while (1) { \
+- unsigned int to_call = *next; \
+- \
+- *next = (*next + 1) & (width - 1); \
+- if (pending[to_call / 32] & (1 << (to_call & 0x1f))) { \
+- handle_internal(to_call); \
+- break; \
+- } \
+- } \
+-} \
+- \
+-static void __internal_irq_mask_##width(struct irq_data *d) \
+-{ \
+- u32 val; \
+- unsigned irq = d->irq - IRQ_INTERNAL_BASE; \
+- unsigned reg = (irq / 32) ^ (width/32 - 1); \
+- unsigned bit = irq & 0x1f; \
+- unsigned long flags; \
+- int cpu; \
+- \
+- spin_lock_irqsave(&ipic_lock, flags); \
+- for_each_present_cpu(cpu) { \
+- if (!irq_mask_addr[cpu]) \
+- break; \
+- \
+- val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
+- val &= ~(1 << bit); \
+- bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
+- } \
+- spin_unlock_irqrestore(&ipic_lock, flags); \
+-} \
+- \
+-static void __internal_irq_unmask_##width(struct irq_data *d, \
+- const struct cpumask *m) \
+-{ \
+- u32 val; \
+- unsigned irq = d->irq - IRQ_INTERNAL_BASE; \
+- unsigned reg = (irq / 32) ^ (width/32 - 1); \
+- unsigned bit = irq & 0x1f; \
+- unsigned long flags; \
+- int cpu; \
+- \
+- spin_lock_irqsave(&ipic_lock, flags); \
+- for_each_present_cpu(cpu) { \
+- if (!irq_mask_addr[cpu]) \
+- break; \
+- \
+- val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
+- if (enable_irq_for_cpu(cpu, d, m)) \
+- val |= (1 << bit); \
+- else \
+- val &= ~(1 << bit); \
+- bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
+- } \
+- spin_unlock_irqrestore(&ipic_lock, flags); \
+-}
+-
+-BUILD_IPIC_INTERNAL(32);
+-BUILD_IPIC_INTERNAL(64);
+-
+-asmlinkage void plat_irq_dispatch(void)
+-{
+- u32 cause;
+-
+- do {
+- cause = read_c0_cause() & read_c0_status() & ST0_IM;
+-
+- if (!cause)
+- break;
+-
+- if (cause & CAUSEF_IP7)
+- do_IRQ(7);
+- if (cause & CAUSEF_IP0)
+- do_IRQ(0);
+- if (cause & CAUSEF_IP1)
+- do_IRQ(1);
+- if (cause & CAUSEF_IP2)
+- dispatch_internal(0);
+- if (is_ext_irq_cascaded) {
+- if (cause & CAUSEF_IP3)
+- dispatch_internal(1);
+- } else {
+- if (cause & CAUSEF_IP3)
+- do_IRQ(IRQ_EXT_0);
+- if (cause & CAUSEF_IP4)
+- do_IRQ(IRQ_EXT_1);
+- if (cause & CAUSEF_IP5)
+- do_IRQ(IRQ_EXT_2);
+- if (cause & CAUSEF_IP6)
+- do_IRQ(IRQ_EXT_3);
+- }
+- } while (1);
+-}
+-
+-/*
+- * internal IRQs operations: only mask/unmask on PERF irq mask
+- * register.
+- */
+-static void bcm63xx_internal_irq_mask(struct irq_data *d)
+-{
+- internal_irq_mask(d);
+-}
+-
+-static void bcm63xx_internal_irq_unmask(struct irq_data *d)
+-{
+- internal_irq_unmask(d, NULL);
+-}
+-
+-/*
+- * external IRQs operations: mask/unmask and clear on PERF external
+- * irq control register.
+- */
+-static void bcm63xx_external_irq_mask(struct irq_data *d)
+-{
+- unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
+- u32 reg, regaddr;
+- unsigned long flags;
+-
+- regaddr = get_ext_irq_perf_reg(irq);
+- spin_lock_irqsave(&epic_lock, flags);
+- reg = bcm_perf_readl(regaddr);
+-
+- if (BCMCPU_IS_6348())
+- reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4);
+- else
+- reg &= ~EXTIRQ_CFG_MASK(irq % 4);
+-
+- bcm_perf_writel(reg, regaddr);
+- spin_unlock_irqrestore(&epic_lock, flags);
+-
+- if (is_ext_irq_cascaded)
+- internal_irq_mask(irq_get_irq_data(irq + ext_irq_start));
+-}
+-
+-static void bcm63xx_external_irq_unmask(struct irq_data *d)
+-{
+- unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
+- u32 reg, regaddr;
+- unsigned long flags;
+-
+- regaddr = get_ext_irq_perf_reg(irq);
+- spin_lock_irqsave(&epic_lock, flags);
+- reg = bcm_perf_readl(regaddr);
+-
+- if (BCMCPU_IS_6348())
+- reg |= EXTIRQ_CFG_MASK_6348(irq % 4);
+- else
+- reg |= EXTIRQ_CFG_MASK(irq % 4);
+-
+- bcm_perf_writel(reg, regaddr);
+- spin_unlock_irqrestore(&epic_lock, flags);
+-
+- if (is_ext_irq_cascaded)
+- internal_irq_unmask(irq_get_irq_data(irq + ext_irq_start),
+- NULL);
+-}
+-
+-static void bcm63xx_external_irq_clear(struct irq_data *d)
+-{
+- unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
+- u32 reg, regaddr;
+- unsigned long flags;
+-
+- regaddr = get_ext_irq_perf_reg(irq);
+- spin_lock_irqsave(&epic_lock, flags);
+- reg = bcm_perf_readl(regaddr);
+-
+- if (BCMCPU_IS_6348())
+- reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4);
+- else
+- reg |= EXTIRQ_CFG_CLEAR(irq % 4);
+-
+- bcm_perf_writel(reg, regaddr);
+- spin_unlock_irqrestore(&epic_lock, flags);
+-}
+-
+-static int bcm63xx_external_irq_set_type(struct irq_data *d,
+- unsigned int flow_type)
+-{
+- unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
+- u32 reg, regaddr;
+- int levelsense, sense, bothedge;
+- unsigned long flags;
+-
+- flow_type &= IRQ_TYPE_SENSE_MASK;
+-
+- if (flow_type == IRQ_TYPE_NONE)
+- flow_type = IRQ_TYPE_LEVEL_LOW;
+-
+- levelsense = sense = bothedge = 0;
+- switch (flow_type) {
+- case IRQ_TYPE_EDGE_BOTH:
+- bothedge = 1;
+- break;
+-
+- case IRQ_TYPE_EDGE_RISING:
+- sense = 1;
+- break;
+-
+- case IRQ_TYPE_EDGE_FALLING:
+- break;
+-
+- case IRQ_TYPE_LEVEL_HIGH:
+- levelsense = 1;
+- sense = 1;
+- break;
+-
+- case IRQ_TYPE_LEVEL_LOW:
+- levelsense = 1;
+- break;
+-
+- default:
+- pr_err("bogus flow type combination given !\n");
+- return -EINVAL;
+- }
+-
+- regaddr = get_ext_irq_perf_reg(irq);
+- spin_lock_irqsave(&epic_lock, flags);
+- reg = bcm_perf_readl(regaddr);
+- irq %= 4;
+-
+- switch (bcm63xx_get_cpu_id()) {
+- case BCM6348_CPU_ID:
+- if (levelsense)
+- reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq);
+- else
+- reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq);
+- if (sense)
+- reg |= EXTIRQ_CFG_SENSE_6348(irq);
+- else
+- reg &= ~EXTIRQ_CFG_SENSE_6348(irq);
+- if (bothedge)
+- reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq);
+- else
+- reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
+- break;
+-
+- case BCM3368_CPU_ID:
+- case BCM6328_CPU_ID:
+- case BCM6338_CPU_ID:
+- case BCM6345_CPU_ID:
+- case BCM6358_CPU_ID:
+- case BCM6362_CPU_ID:
+- case BCM6368_CPU_ID:
+- if (levelsense)
+- reg |= EXTIRQ_CFG_LEVELSENSE(irq);
+- else
+- reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
+- if (sense)
+- reg |= EXTIRQ_CFG_SENSE(irq);
+- else
+- reg &= ~EXTIRQ_CFG_SENSE(irq);
+- if (bothedge)
+- reg |= EXTIRQ_CFG_BOTHEDGE(irq);
+- else
+- reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
+- break;
+- default:
+- BUG();
+- }
+-
+- bcm_perf_writel(reg, regaddr);
+- spin_unlock_irqrestore(&epic_lock, flags);
+-
+- irqd_set_trigger_type(d, flow_type);
+- if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+- irq_set_handler_locked(d, handle_level_irq);
+- else
+- irq_set_handler_locked(d, handle_edge_irq);
+-
+- return IRQ_SET_MASK_OK_NOCOPY;
+-}
+-
+-#ifdef CONFIG_SMP
+-static int bcm63xx_internal_set_affinity(struct irq_data *data,
+- const struct cpumask *dest,
+- bool force)
+-{
+- if (!irqd_irq_disabled(data))
+- internal_irq_unmask(data, dest);
+-
+- return 0;
+-}
+-#endif
+-
+-static struct irq_chip bcm63xx_internal_irq_chip = {
+- .name = "bcm63xx_ipic",
+- .irq_mask = bcm63xx_internal_irq_mask,
+- .irq_unmask = bcm63xx_internal_irq_unmask,
+-};
+-
+-static struct irq_chip bcm63xx_external_irq_chip = {
+- .name = "bcm63xx_epic",
+- .irq_ack = bcm63xx_external_irq_clear,
+-
+- .irq_mask = bcm63xx_external_irq_mask,
+- .irq_unmask = bcm63xx_external_irq_unmask,
+-
+- .irq_set_type = bcm63xx_external_irq_set_type,
+-};
+-
+-static struct irqaction cpu_ip2_cascade_action = {
+- .handler = no_action,
+- .name = "cascade_ip2",
+- .flags = IRQF_NO_THREAD,
+-};
+-
+-#ifdef CONFIG_SMP
+-static struct irqaction cpu_ip3_cascade_action = {
+- .handler = no_action,
+- .name = "cascade_ip3",
+- .flags = IRQF_NO_THREAD,
+-};
+-#endif
+-
+-static struct irqaction cpu_ext_cascade_action = {
+- .handler = no_action,
+- .name = "cascade_extirq",
+- .flags = IRQF_NO_THREAD,
+-};
+-
+-static void bcm63xx_init_irq(void)
++void __init arch_init_irq(void)
+ {
+- int irq_bits;
+-
+- irq_stat_addr[0] = bcm63xx_regset_address(RSET_PERF);
+- irq_mask_addr[0] = bcm63xx_regset_address(RSET_PERF);
+- irq_stat_addr[1] = bcm63xx_regset_address(RSET_PERF);
+- irq_mask_addr[1] = bcm63xx_regset_address(RSET_PERF);
++ void __iomem *periph_bases[2];
++ void __iomem *ext_intc_bases[2];
++ int periph_irq_count, periph_width, ext_irq_count, ext_shift;
++ int periph_irqs[2] = { 2, 3 };
++ int ext_irqs[6];
++
++ periph_bases[0] = (void __iomem *)bcm63xx_regset_address(RSET_PERF);
++ periph_bases[1] = (void __iomem *)bcm63xx_regset_address(RSET_PERF);
++ ext_intc_bases[0] = (void __iomem *)bcm63xx_regset_address(RSET_PERF);
++ ext_intc_bases[1] = (void __iomem *)bcm63xx_regset_address(RSET_PERF);
+
+ switch (bcm63xx_get_cpu_id()) {
+ case BCM3368_CPU_ID:
+- irq_stat_addr[0] += PERF_IRQSTAT_3368_REG;
+- irq_mask_addr[0] += PERF_IRQMASK_3368_REG;
+- irq_stat_addr[1] = 0;
+- irq_mask_addr[1] = 0;
+- irq_bits = 32;
+- ext_irq_count = 4;
+- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368;
++ periph_bases[0] += PERF_IRQMASK_3368_REG;
++ periph_irq_count = 1;
++ periph_width = 1;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_3368;
++ ext_irq_count = 4;
++ ext_irqs[0] = BCM_3368_EXT_IRQ0;
++ ext_irqs[1] = BCM_3368_EXT_IRQ1;
++ ext_irqs[2] = BCM_3368_EXT_IRQ2;
++ ext_irqs[3] = BCM_3368_EXT_IRQ3;
++ ext_shift = 4;
+ break;
+ case BCM6328_CPU_ID:
+- irq_stat_addr[0] += PERF_IRQSTAT_6328_REG(0);
+- irq_mask_addr[0] += PERF_IRQMASK_6328_REG(0);
+- irq_stat_addr[1] += PERF_IRQSTAT_6328_REG(1);
+- irq_mask_addr[1] += PERF_IRQMASK_6328_REG(1);
+- irq_bits = 64;
+- ext_irq_count = 4;
+- is_ext_irq_cascaded = 1;
+- ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+- ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
++ periph_bases[0] += PERF_IRQMASK_6328_REG(0);
++ periph_bases[1] += PERF_IRQMASK_6328_REG(1);
++ periph_irq_count = 2;
++ periph_width = 2;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6328;
++ ext_irq_count = 4;
++ ext_irqs[0] = BCM_6328_EXT_IRQ0;
++ ext_irqs[1] = BCM_6328_EXT_IRQ1;
++ ext_irqs[2] = BCM_6328_EXT_IRQ2;
++ ext_irqs[3] = BCM_6328_EXT_IRQ3;
++ ext_shift = 4;
+ break;
+ case BCM6338_CPU_ID:
+- irq_stat_addr[0] += PERF_IRQSTAT_6338_REG;
+- irq_mask_addr[0] += PERF_IRQMASK_6338_REG;
+- irq_stat_addr[1] = 0;
+- irq_mask_addr[1] = 0;
+- irq_bits = 32;
+- ext_irq_count = 4;
+- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338;
++ periph_bases[0] += PERF_IRQMASK_6338_REG;
++ periph_irq_count = 1;
++ periph_width = 1;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6338;
++ ext_irq_count = 4;
++ ext_irqs[0] = 3;
++ ext_irqs[1] = 4;
++ ext_irqs[2] = 5;
++ ext_irqs[3] = 6;
++ ext_shift = 4;
+ break;
+ case BCM6345_CPU_ID:
+- irq_stat_addr[0] += PERF_IRQSTAT_6345_REG;
+- irq_mask_addr[0] += PERF_IRQMASK_6345_REG;
+- irq_stat_addr[1] = 0;
+- irq_mask_addr[1] = 0;
+- irq_bits = 32;
+- ext_irq_count = 4;
+- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345;
++ periph_bases[0] += PERF_IRQMASK_6345_REG;
++ periph_irq_count = 1;
++ periph_width = 1;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6345;
++ ext_irq_count = 4;
++ ext_irqs[0] = 3;
++ ext_irqs[1] = 4;
++ ext_irqs[2] = 5;
++ ext_irqs[3] = 6;
++ ext_shift = 4;
+ break;
+ case BCM6348_CPU_ID:
+- irq_stat_addr[0] += PERF_IRQSTAT_6348_REG;
+- irq_mask_addr[0] += PERF_IRQMASK_6348_REG;
+- irq_stat_addr[1] = 0;
+- irq_mask_addr[1] = 0;
+- irq_bits = 32;
+- ext_irq_count = 4;
+- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348;
++ periph_bases[0] += PERF_IRQMASK_6348_REG;
++ periph_irq_count = 1;
++ periph_width = 1;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6348;
++ ext_irq_count = 4;
++ ext_irqs[0] = 3;
++ ext_irqs[1] = 4;
++ ext_irqs[2] = 5;
++ ext_irqs[3] = 6;
++ ext_shift = 5;
+ break;
+ case BCM6358_CPU_ID:
+- irq_stat_addr[0] += PERF_IRQSTAT_6358_REG(0);
+- irq_mask_addr[0] += PERF_IRQMASK_6358_REG(0);
+- irq_stat_addr[1] += PERF_IRQSTAT_6358_REG(1);
+- irq_mask_addr[1] += PERF_IRQMASK_6358_REG(1);
+- irq_bits = 32;
+- ext_irq_count = 4;
+- is_ext_irq_cascaded = 1;
+- ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+- ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358;
++ periph_bases[0] += PERF_IRQMASK_6358_REG(0);
++ periph_bases[1] += PERF_IRQMASK_6358_REG(1);
++ periph_irq_count = 2;
++ periph_width = 1;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6358;
++ ext_irq_count = 4;
++ ext_irqs[0] = BCM_6358_EXT_IRQ0;
++ ext_irqs[1] = BCM_6358_EXT_IRQ1;
++ ext_irqs[2] = BCM_6358_EXT_IRQ2;
++ ext_irqs[3] = BCM_6358_EXT_IRQ3;
++ ext_shift = 4;
+ break;
+ case BCM6362_CPU_ID:
+- irq_stat_addr[0] += PERF_IRQSTAT_6362_REG(0);
+- irq_mask_addr[0] += PERF_IRQMASK_6362_REG(0);
+- irq_stat_addr[1] += PERF_IRQSTAT_6362_REG(1);
+- irq_mask_addr[1] += PERF_IRQMASK_6362_REG(1);
+- irq_bits = 64;
+- ext_irq_count = 4;
+- is_ext_irq_cascaded = 1;
+- ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+- ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362;
++ periph_bases[0] += PERF_IRQMASK_6362_REG(0);
++ periph_bases[1] += PERF_IRQMASK_6362_REG(1);
++ periph_irq_count = 2;
++ periph_width = 2;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6362;
++ ext_irq_count = 4;
++ ext_irqs[0] = BCM_6362_EXT_IRQ0;
++ ext_irqs[1] = BCM_6362_EXT_IRQ1;
++ ext_irqs[2] = BCM_6362_EXT_IRQ2;
++ ext_irqs[3] = BCM_6362_EXT_IRQ3;
++ ext_shift = 4;
+ break;
+ case BCM6368_CPU_ID:
+- irq_stat_addr[0] += PERF_IRQSTAT_6368_REG(0);
+- irq_mask_addr[0] += PERF_IRQMASK_6368_REG(0);
+- irq_stat_addr[1] += PERF_IRQSTAT_6368_REG(1);
+- irq_mask_addr[1] += PERF_IRQMASK_6368_REG(1);
+- irq_bits = 64;
++ periph_bases[0] += PERF_IRQMASK_6368_REG(0);
++ periph_bases[1] += PERF_IRQMASK_6368_REG(1);
++ periph_irq_count = 2;
++ periph_width = 2;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6368;
++ ext_intc_bases[1] += PERF_EXTIRQ_CFG_REG2_6368;
+ ext_irq_count = 6;
+- is_ext_irq_cascaded = 1;
+- ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+- ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
+- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
+- ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
++ ext_irqs[0] = BCM_6368_EXT_IRQ0;
++ ext_irqs[1] = BCM_6368_EXT_IRQ1;
++ ext_irqs[2] = BCM_6368_EXT_IRQ2;
++ ext_irqs[3] = BCM_6368_EXT_IRQ3;
++ ext_irqs[4] = BCM_6368_EXT_IRQ4;
++ ext_irqs[5] = BCM_6368_EXT_IRQ5;
++ ext_shift = 4;
+ break;
+ default:
+ BUG();
+ }
+
+- if (irq_bits == 32) {
+- dispatch_internal = __dispatch_internal_32;
+- internal_irq_mask = __internal_irq_mask_32;
+- internal_irq_unmask = __internal_irq_unmask_32;
+- } else {
+- dispatch_internal = __dispatch_internal_64;
+- internal_irq_mask = __internal_irq_mask_64;
+- internal_irq_unmask = __internal_irq_unmask_64;
+- }
+-}
+-
+-void __init arch_init_irq(void)
+-{
+- int i;
+-
+- bcm63xx_init_irq();
+ mips_cpu_irq_init();
+- for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
+- irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,
+- handle_level_irq);
+-
+- for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i)
+- irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,
+- handle_edge_irq);
+-
+- if (!is_ext_irq_cascaded) {
+- for (i = 3; i < 3 + ext_irq_count; ++i)
+- setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action);
+- }
+-
+- setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action);
+-#ifdef CONFIG_SMP
+- if (is_ext_irq_cascaded) {
+- setup_irq(MIPS_CPU_IRQ_BASE + 3, &cpu_ip3_cascade_action);
+- bcm63xx_internal_irq_chip.irq_set_affinity =
+- bcm63xx_internal_set_affinity;
+-
+- cpumask_clear(irq_default_affinity);
+- cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
+- }
+-#endif
++ bcm6345_periph_intc_init(periph_irq_count, periph_irqs, periph_bases,
++ periph_width);
++ bcm6345_ext_intc_init(4, ext_irqs, ext_intc_bases[0], ext_shift);
++ if (ext_irq_count > 4)
++ bcm6345_ext_intc_init(2, &ext_irqs[4], ext_intc_bases[1],
++ ext_shift);
+ }
--- /dev/null
+From 4fd286c3e5a5bebab0391cf1937695b3ed6721a3 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 30 Nov 2014 20:20:30 +0100
+Subject: [PATCH 4/5] MIPS: BCM63XX: wire up BCM6358's external interrupts 4
+ and 5
+
+Due to the external interrupts being non consecutive, the previous
+implementation did not support them. Now that we treat both registers
+as separate irq controllers, there is no such limitation anymore and
+we can expose them for drivers to use.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/irq.c | 5 ++++-
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 2 ++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 1 +
+ 3 files changed, 7 insertions(+), 1 deletion(-)
+
+--- a/arch/mips/bcm63xx/irq.c
++++ b/arch/mips/bcm63xx/irq.c
+@@ -109,11 +109,14 @@ void __init arch_init_irq(void)
+ periph_width = 1;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6358;
+- ext_irq_count = 4;
++ ext_intc_bases[1] += PERF_EXTIRQ_CFG_REG2_6358;
++ ext_irq_count = 6;
+ ext_irqs[0] = BCM_6358_EXT_IRQ0;
+ ext_irqs[1] = BCM_6358_EXT_IRQ1;
+ ext_irqs[2] = BCM_6358_EXT_IRQ2;
+ ext_irqs[3] = BCM_6358_EXT_IRQ3;
++ ext_irqs[4] = BCM_6358_EXT_IRQ4;
++ ext_irqs[5] = BCM_6358_EXT_IRQ5;
+ ext_shift = 4;
+ break;
+ case BCM6362_CPU_ID:
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+@@ -895,6 +895,8 @@ enum bcm63xx_irq {
+ #define BCM_6358_EXT_IRQ1 (IRQ_INTERNAL_BASE + 26)
+ #define BCM_6358_EXT_IRQ2 (IRQ_INTERNAL_BASE + 27)
+ #define BCM_6358_EXT_IRQ3 (IRQ_INTERNAL_BASE + 28)
++#define BCM_6358_EXT_IRQ4 (IRQ_INTERNAL_BASE + 20)
++#define BCM_6358_EXT_IRQ5 (IRQ_INTERNAL_BASE + 21)
+
+ /*
+ * 6362 irqs
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+@@ -243,6 +243,7 @@
+ #define PERF_EXTIRQ_CFG_REG_6362 0x18
+ #define PERF_EXTIRQ_CFG_REG_6368 0x18
+
++#define PERF_EXTIRQ_CFG_REG2_6358 0x1c
+ #define PERF_EXTIRQ_CFG_REG2_6368 0x1c
+
+ /* for 6348 only */
--- /dev/null
+From c50acd37b425a8a907a6f7f93aa2e658256e79ce Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sat, 7 Dec 2013 14:08:36 +0100
+Subject: [PATCH 40/53] MIPS: BCM63XX: add a new cpu variant helper
+
+---
+ arch/mips/bcm63xx/cpu.c | 10 ++++++++++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 18 ++++++++++++++++++
+ 2 files changed, 28 insertions(+)
+
+--- a/arch/mips/bcm63xx/cpu.c
++++ b/arch/mips/bcm63xx/cpu.c
+@@ -27,6 +27,8 @@ EXPORT_SYMBOL(bcm63xx_irqs);
+ u16 bcm63xx_cpu_id __read_mostly;
+ EXPORT_SYMBOL(bcm63xx_cpu_id);
+
++static u32 bcm63xx_cpu_variant __read_mostly;
++
+ static u8 bcm63xx_cpu_rev;
+ static unsigned int bcm63xx_cpu_freq;
+ static unsigned int bcm63xx_memory_size;
+@@ -99,6 +101,13 @@ static const int bcm6368_irqs[] = {
+
+ };
+
++u32 bcm63xx_get_cpu_variant(void)
++{
++ return bcm63xx_cpu_variant;
++}
++
++EXPORT_SYMBOL(bcm63xx_get_cpu_variant);
++
+ u8 bcm63xx_get_cpu_rev(void)
+ {
+ return bcm63xx_cpu_rev;
+@@ -333,6 +342,7 @@ void __init bcm63xx_cpu_init(void)
+ /* read out CPU type */
+ tmp = bcm_readl(chipid_reg);
+ bcm63xx_cpu_id = (tmp & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT;
++ bcm63xx_cpu_variant = bcm63xx_cpu_id;
+ bcm63xx_cpu_rev = (tmp & REV_REVID_MASK) >> REV_REVID_SHIFT;
+
+ switch (bcm63xx_cpu_id) {
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+@@ -19,6 +19,7 @@
+ #define BCM6368_CPU_ID 0x6368
+
+ void __init bcm63xx_cpu_init(void);
++u32 bcm63xx_get_cpu_variant(void);
+ u8 bcm63xx_get_cpu_rev(void);
+ unsigned int bcm63xx_get_cpu_freq(void);
+
+@@ -82,6 +83,23 @@ static inline u16 __pure bcm63xx_get_cpu
+ #define BCMCPU_IS_6362() (bcm63xx_get_cpu_id() == BCM6362_CPU_ID)
+ #define BCMCPU_IS_6368() (bcm63xx_get_cpu_id() == BCM6368_CPU_ID)
+
++#define BCMCPU_VARIANT_IS_3368() \
++ (bcm63xx_get_cpu_variant() == BCM3368_CPU_ID)
++#define BCMCPU_VARIANT_IS_6328() \
++ (bcm63xx_get_cpu_variant() == BCM6328_CPU_ID)
++#define BCMCPU_VARIANT_IS_6338() \
++ (bcm63xx_get_cpu_variant() == BCM6338_CPU_ID)
++#define BCMCPU_VARIANT_IS_6345() \
++ (bcm63xx_get_cpu_variant() == BCM6345_CPU_ID)
++#define BCMCPU_VARIANT_IS_6348() \
++ (bcm63xx_get_cpu_variant() == BCM6348_CPU_ID)
++#define BCMCPU_VARIANT_IS_6358() \
++ (bcm63xx_get_cpu_cariant() == BCM6358_CPU_ID)
++#define BCMCPU_VARIANT_IS_6362() \
++ (bcm63xx_get_cpu_variant() == BCM6362_CPU_ID)
++#define BCMCPU_VARIANT_IS_6368() \
++ (bcm63xx_get_cpu_variant() == BCM6368_CPU_ID)
++
+ /*
+ * While registers sets are (mostly) the same across 63xx CPU, base
+ * address of these sets do change.
--- /dev/null
+From 3bd8e2535265f06f79ed9c0ad788405441e091dc Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sat, 7 Dec 2013 14:22:41 +0100
+Subject: [PATCH 21/45] MIPS: BCM63XX: define variant id field
+
+Some SoC have a variant id field in the chip id register.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+@@ -9,6 +9,8 @@
+ #define PERF_REV_REG 0x0
+ #define REV_CHIPID_SHIFT 16
+ #define REV_CHIPID_MASK (0xffff << REV_CHIPID_SHIFT)
++#define REV_VARID_SHIFT 12
++#define REV_VARID_MASK (0xf << REV_VARID_SHIFT)
+ #define REV_REVID_SHIFT 0
+ #define REV_REVID_MASK (0xff << REV_REVID_SHIFT)
+
--- /dev/null
+From d59120f23279ef62a48d9f94847254b061d0a8b6 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sat, 7 Dec 2013 14:30:59 +0100
+Subject: [PATCH 22/45] MIPS: BCM63XX: detect BCM6328 variants
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/cpu.c | 10 ++++++++++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 8 ++++++--
+ 2 files changed, 16 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/bcm63xx/cpu.c
++++ b/arch/mips/bcm63xx/cpu.c
+@@ -305,6 +305,7 @@ void __init bcm63xx_cpu_init(void)
+ unsigned int tmp;
+ unsigned int cpu = smp_processor_id();
+ u32 chipid_reg;
++ u8 __maybe_unused varid = 0;
+
+ /* soc registers location depends on cpu type */
+ chipid_reg = 0;
+@@ -344,6 +345,7 @@ void __init bcm63xx_cpu_init(void)
+ bcm63xx_cpu_id = (tmp & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT;
+ bcm63xx_cpu_variant = bcm63xx_cpu_id;
+ bcm63xx_cpu_rev = (tmp & REV_REVID_MASK) >> REV_REVID_SHIFT;
++ varid = (tmp & REV_VARID_MASK) >> REV_VARID_SHIFT;
+
+ switch (bcm63xx_cpu_id) {
+ case BCM3368_CPU_ID:
+@@ -353,6 +355,14 @@ void __init bcm63xx_cpu_init(void)
+ case BCM6328_CPU_ID:
+ bcm63xx_regs_base = bcm6328_regs_base;
+ bcm63xx_irqs = bcm6328_irqs;
++
++ if (varid == 1)
++ bcm63xx_cpu_variant = BCM63281_CPU_ID;
++ else if (varid == 3)
++ bcm63xx_cpu_variant = BCM63283_CPU_ID;
++ else
++ pr_warn("unknown BCM6328 variant: %x\n", varid);
++
+ break;
+ case BCM6338_CPU_ID:
+ bcm63xx_regs_base = bcm6338_regs_base;
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+@@ -11,6 +11,8 @@
+ */
+ #define BCM3368_CPU_ID 0x3368
+ #define BCM6328_CPU_ID 0x6328
++#define BCM63281_CPU_ID 0x63281
++#define BCM63283_CPU_ID 0x63283
+ #define BCM6338_CPU_ID 0x6338
+ #define BCM6345_CPU_ID 0x6345
+ #define BCM6348_CPU_ID 0x6348
+@@ -85,8 +87,10 @@ static inline u16 __pure bcm63xx_get_cpu
+
+ #define BCMCPU_VARIANT_IS_3368() \
+ (bcm63xx_get_cpu_variant() == BCM3368_CPU_ID)
+-#define BCMCPU_VARIANT_IS_6328() \
+- (bcm63xx_get_cpu_variant() == BCM6328_CPU_ID)
++#define BCMCPU_VARIANT_IS_63281() \
++ (bcm63xx_get_cpu_variant() == BCM63281_CPU_ID)
++#define BCMCPU_VARIANT_IS_63283() \
++ (bcm63xx_get_cpu_variant() == BCM63283_CPU_ID)
+ #define BCMCPU_VARIANT_IS_6338() \
+ (bcm63xx_get_cpu_variant() == BCM6338_CPU_ID)
+ #define BCMCPU_VARIANT_IS_6345() \
--- /dev/null
+From 04458c3db8eb79da21ecde40ab36a1dde52bef06 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sat, 7 Dec 2013 14:33:28 +0100
+Subject: [PATCH 23/45] MIPS: BCM63XX: detect BCM6362 variants
+
+---
+ arch/mips/bcm63xx/cpu.c | 8 ++++++++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 3 +++
+ 2 files changed, 11 insertions(+)
+
+--- a/arch/mips/bcm63xx/cpu.c
++++ b/arch/mips/bcm63xx/cpu.c
+@@ -383,6 +383,14 @@ void __init bcm63xx_cpu_init(void)
+ case BCM6362_CPU_ID:
+ bcm63xx_regs_base = bcm6362_regs_base;
+ bcm63xx_irqs = bcm6362_irqs;
++
++ if (varid == 1)
++ bcm63xx_cpu_variant = BCM6362_CPU_ID;
++ else if (varid == 2)
++ bcm63xx_cpu_variant = BCM6361_CPU_ID;
++ else
++ pr_warn("unknown BCM6362 variant: %x\n", varid);
++
+ break;
+ case BCM6368_CPU_ID:
+ bcm63xx_regs_base = bcm6368_regs_base;
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+@@ -17,6 +17,7 @@
+ #define BCM6345_CPU_ID 0x6345
+ #define BCM6348_CPU_ID 0x6348
+ #define BCM6358_CPU_ID 0x6358
++#define BCM6361_CPU_ID 0x6361
+ #define BCM6362_CPU_ID 0x6362
+ #define BCM6368_CPU_ID 0x6368
+
+@@ -99,6 +100,8 @@ static inline u16 __pure bcm63xx_get_cpu
+ (bcm63xx_get_cpu_variant() == BCM6348_CPU_ID)
+ #define BCMCPU_VARIANT_IS_6358() \
+ (bcm63xx_get_cpu_cariant() == BCM6358_CPU_ID)
++#define BCMCPU_VARIANT_IS_6361() \
++ (bcm63xx_get_cpu_variant() == BCM6361_CPU_ID)
+ #define BCMCPU_VARIANT_IS_6362() \
+ (bcm63xx_get_cpu_variant() == BCM6362_CPU_ID)
+ #define BCMCPU_VARIANT_IS_6368() \
--- /dev/null
+From 825cc67e56b5e624a05f6850a86d91508b786848 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sat, 7 Dec 2013 14:36:56 +0100
+Subject: [PATCH 24/44] MIPS: BCM63XX: detect BCM6368 variants
+
+The DSL-less BCM6368 variant BCM6367 uses a different chip id. Apart
+from missing DSL, there is no difference to BCM6368, so treat it such.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/cpu.c | 4 ++++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 3 +++
+ 2 files changed, 7 insertions(+)
+
+--- a/arch/mips/bcm63xx/cpu.c
++++ b/arch/mips/bcm63xx/cpu.c
+@@ -393,8 +393,12 @@ void __init bcm63xx_cpu_init(void)
+
+ break;
+ case BCM6368_CPU_ID:
++ case BCM6369_CPU_ID:
+ bcm63xx_regs_base = bcm6368_regs_base;
+ bcm63xx_irqs = bcm6368_irqs;
++
++ /* BCM6369 is a BCM6368 without xDSL, so treat it the same */
++ bcm63xx_cpu_id = BCM6368_CPU_ID;
+ break;
+ default:
+ panic("unsupported broadcom CPU %x", bcm63xx_cpu_id);
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+@@ -20,6 +20,7 @@
+ #define BCM6361_CPU_ID 0x6361
+ #define BCM6362_CPU_ID 0x6362
+ #define BCM6368_CPU_ID 0x6368
++#define BCM6369_CPU_ID 0x6369
+
+ void __init bcm63xx_cpu_init(void);
+ u32 bcm63xx_get_cpu_variant(void);
+@@ -106,6 +107,8 @@ static inline u16 __pure bcm63xx_get_cpu
+ (bcm63xx_get_cpu_variant() == BCM6362_CPU_ID)
+ #define BCMCPU_VARIANT_IS_6368() \
+ (bcm63xx_get_cpu_variant() == BCM6368_CPU_ID)
++#define BCMCPU_VARIANT_IS_6369() \
++ (bcm63xx_get_cpu_variant() == BCM6369_CPU_ID)
+
+ /*
+ * While registers sets are (mostly) the same across 63xx CPU, base
--- /dev/null
+From f67f8134b4537c8bbafe7e1975edfe808b813997 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 8 Dec 2013 03:05:54 +0100
+Subject: [PATCH 45/53] MIPS: BCM63XX: fix PCIe memory window size
+
+---
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
+@@ -41,7 +41,7 @@
+ BCM_CB_MEM_SIZE - 1)
+
+ #define BCM_PCIE_MEM_BASE_PA 0x10f00000
+-#define BCM_PCIE_MEM_SIZE (16 * 1024 * 1024)
++#define BCM_PCIE_MEM_SIZE (1 * 1024 * 1024)
+ #define BCM_PCIE_MEM_END_PA (BCM_PCIE_MEM_BASE_PA + \
+ BCM_PCIE_MEM_SIZE - 1)
+
--- /dev/null
+From aa05464973bc176478af462ca7c53a9239c651d4 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 8 Dec 2013 03:13:06 +0100
+Subject: [PATCH 46/53] MIPS: BCM63XX: dynamically set the pcie memory windows
+
+Different SoCs use different memory windows (and sizes), so don't
+hardcode it.
+---
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h | 8 ++++----
+ arch/mips/pci/pci-bcm63xx.c | 15 ++++++++++-----
+ 2 files changed, 14 insertions(+), 9 deletions(-)
+
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
+@@ -40,10 +40,10 @@
+ #define BCM_CB_MEM_END_PA (BCM_CB_MEM_BASE_PA + \
+ BCM_CB_MEM_SIZE - 1)
+
+-#define BCM_PCIE_MEM_BASE_PA 0x10f00000
+-#define BCM_PCIE_MEM_SIZE (1 * 1024 * 1024)
+-#define BCM_PCIE_MEM_END_PA (BCM_PCIE_MEM_BASE_PA + \
+- BCM_PCIE_MEM_SIZE - 1)
++#define BCM_PCIE_MEM_BASE_PA_6328 0x10f00000
++#define BCM_PCIE_MEM_SIZE_6328 (1 * 1024 * 1024)
++#define BCM_PCIE_MEM_END_PA_6328 (BCM_PCIE_MEM_BASE_PA_6328 + \
++ BCM_PCIE_MEM_SIZE_6328 - 1)
+
+ /*
+ * Internal registers are accessed through KSEG3
+--- a/arch/mips/pci/pci-bcm63xx.c
++++ b/arch/mips/pci/pci-bcm63xx.c
+@@ -77,8 +77,8 @@ struct pci_controller bcm63xx_cb_control
+
+ static struct resource bcm_pcie_mem_resource = {
+ .name = "bcm63xx PCIe memory space",
+- .start = BCM_PCIE_MEM_BASE_PA,
+- .end = BCM_PCIE_MEM_END_PA,
++ .start = 0,
++ .end = 0,
+ .flags = IORESOURCE_MEM,
+ };
+
+@@ -195,12 +195,12 @@ static int __init bcm63xx_register_pcie(
+ bcm_pcie_writel(val, PCIE_CONFIG2_REG);
+
+ /* set bar0 to little endian */
+- val = (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_BASE_SHIFT;
+- val |= (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_MASK_SHIFT;
++ val = (bcm_pcie_mem_resource.start >> 20) << BASEMASK_BASE_SHIFT;
++ val |= (bcm_pcie_mem_resource.end >> 20) << BASEMASK_MASK_SHIFT;
+ val |= BASEMASK_REMAP_EN;
+ bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG);
+
+- val = (BCM_PCIE_MEM_BASE_PA >> 20) << REBASE_ADDR_BASE_SHIFT;
++ val = (bcm_pcie_mem_resource.start >> 20) << REBASE_ADDR_BASE_SHIFT;
+ bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG);
+
+ register_pci_controller(&bcm63xx_pcie_controller);
+@@ -334,6 +334,11 @@ static int __init bcm63xx_pci_init(void)
+ if (!bcm63xx_pci_enabled)
+ return -ENODEV;
+
++ if (BCMCPU_IS_6328() || BCMCPU_IS_6362()) {
++ bcm_pcie_mem_resource.start = BCM_PCIE_MEM_BASE_PA_6328;
++ bcm_pcie_mem_resource.end = BCM_PCIE_MEM_END_PA_6328;
++ }
++
+ switch (bcm63xx_get_cpu_id()) {
+ case BCM6328_CPU_ID:
+ case BCM6362_CPU_ID:
--- /dev/null
+From f1477f6e3551fd6beecfee5368fed1325dcd421f Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sat, 7 Dec 2013 14:54:51 +0100
+Subject: [PATCH 47/53] MIPS: BCM63XX: widen cpuid field
+
+---
+ arch/mips/bcm63xx/cpu.c | 2 +-
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 8 ++++----
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/mips/bcm63xx/cpu.c
++++ b/arch/mips/bcm63xx/cpu.c
+@@ -24,7 +24,7 @@ EXPORT_SYMBOL(bcm63xx_regs_base);
+ const int *bcm63xx_irqs;
+ EXPORT_SYMBOL(bcm63xx_irqs);
+
+-u16 bcm63xx_cpu_id __read_mostly;
++u32 bcm63xx_cpu_id __read_mostly;
+ EXPORT_SYMBOL(bcm63xx_cpu_id);
+
+ static u32 bcm63xx_cpu_variant __read_mostly;
+@@ -127,7 +127,7 @@ unsigned int bcm63xx_get_memory_size(voi
+
+ static unsigned int detect_cpu_clock(void)
+ {
+- u16 cpu_id = bcm63xx_get_cpu_id();
++ u32 cpu_id = bcm63xx_get_cpu_id();
+
+ switch (cpu_id) {
+ case BCM3368_CPU_ID:
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+@@ -27,7 +27,7 @@ u32 bcm63xx_get_cpu_variant(void);
+ u8 bcm63xx_get_cpu_rev(void);
+ unsigned int bcm63xx_get_cpu_freq(void);
+
+-static inline u16 __pure __bcm63xx_get_cpu_id(const u16 cpu_id)
++static inline u32 __pure __bcm63xx_get_cpu_id(const u32 cpu_id)
+ {
+ switch (cpu_id) {
+ #ifdef CONFIG_BCM63XX_CPU_3368
+@@ -69,11 +69,11 @@ static inline u16 __pure __bcm63xx_get_c
+ return cpu_id;
+ }
+
+-extern u16 bcm63xx_cpu_id;
++extern u32 bcm63xx_cpu_id;
+
+-static inline u16 __pure bcm63xx_get_cpu_id(void)
++static inline u32 __pure bcm63xx_get_cpu_id(void)
+ {
+- const u16 cpu_id = bcm63xx_cpu_id;
++ const u32 cpu_id = bcm63xx_cpu_id;
+
+ return __bcm63xx_get_cpu_id(cpu_id);
+ }
--- /dev/null
+From 6f5658c845cf1f79213b1d20423a04967259fdaa Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 15 Dec 2013 20:46:26 +0100
+Subject: [PATCH 48/53] MIPS: BCM63XX: increase number of IRQs
+
+Newer SoCs have 128 bit wide irq registers, thus 128 available internal
+interupts.
+---
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_irq.h | 4 +++-
+ arch/mips/include/asm/mach-bcm63xx/irq.h | 2 +-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_irq.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_irq.h
+@@ -1,10 +1,12 @@
+ #ifndef BCM63XX_IRQ_H_
+ #define BCM63XX_IRQ_H_
+
++#include <irq.h>
+ #include <bcm63xx_cpu.h>
+
+ #define IRQ_INTERNAL_BASE 8
+-#define IRQ_EXTERNAL_BASE 100
++#define NR_INTERNAL_IRQS 128
++#define IRQ_EXTERNAL_BASE (IRQ_INTERNAL_BASE + NR_INTERNAL_IRQS)
+ #define IRQ_EXT_0 (IRQ_EXTERNAL_BASE + 0)
+ #define IRQ_EXT_1 (IRQ_EXTERNAL_BASE + 1)
+ #define IRQ_EXT_2 (IRQ_EXTERNAL_BASE + 2)
+--- a/arch/mips/include/asm/mach-bcm63xx/irq.h
++++ b/arch/mips/include/asm/mach-bcm63xx/irq.h
+@@ -1,7 +1,7 @@
+ #ifndef __ASM_MACH_BCM63XX_IRQ_H
+ #define __ASM_MACH_BCM63XX_IRQ_H
+
+-#define NR_IRQS 128
++#define NR_IRQS 256
+ #define MIPS_CPU_IRQ_BASE 0
+
+ #endif
--- /dev/null
+From 98f63141190ac02c58b78d58f771bd263c61d756 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sat, 7 Dec 2013 17:14:17 +0100
+Subject: [PATCH 48/56] MIPS: BCM63XX: add support for BCM63268
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/Kconfig | 5 +
+ arch/mips/bcm63xx/boards/board_bcm963xx.c | 2 +-
+ arch/mips/bcm63xx/clk.c | 25 ++++-
+ arch/mips/bcm63xx/cpu.c | 59 +++++++++-
+ arch/mips/bcm63xx/dev-flash.c | 6 +
+ arch/mips/bcm63xx/dev-spi.c | 4 +-
+ arch/mips/bcm63xx/irq.c | 20 +++-
+ arch/mips/bcm63xx/reset.c | 21 ++++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 130 ++++++++++++++++++++++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h | 2 +
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 79 +++++++++++++
+ arch/mips/include/asm/mach-bcm63xx/ioremap.h | 1 +
+ 12 files changed, 342 insertions(+), 12 deletions(-)
+
+--- a/arch/mips/bcm63xx/Kconfig
++++ b/arch/mips/bcm63xx/Kconfig
+@@ -60,6 +60,11 @@ config BCM63XX_CPU_6368
+ select HW_HAS_PCI
+ select BCM63XX_OHCI
+ select BCM63XX_EHCI
++
++config BCM63XX_CPU_63268
++ bool "support 63268 CPU"
++ select SYS_HAS_CPU_BMIPS4350
++ select HW_HAS_PCI
+ endmenu
+
+ source "arch/mips/bcm63xx/boards/Kconfig"
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -713,7 +713,7 @@ void __init board_prom_init(void)
+ /* read base address of boot chip select (0)
+ * 6328/6362 do not have MPI but boot from a fixed address
+ */
+- if (BCMCPU_IS_6328() || BCMCPU_IS_6362()) {
++ if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_63268()) {
+ val = 0x18000000;
+ } else {
+ val = bcm_mpi_readl(MPI_CSBASE_REG(0));
+--- a/arch/mips/bcm63xx/clk.c
++++ b/arch/mips/bcm63xx/clk.c
+@@ -133,6 +133,8 @@ static void enetsw_set(struct clk *clk,
+ CKCTL_6368_SWPKT_USB_EN |
+ CKCTL_6368_SWPKT_SAR_EN,
+ enable);
++ else if (BCMCPU_IS_63268())
++ bcm_hwclock_set(CKCTL_63268_ROBOSW_EN, enable);
+ else
+ return;
+
+@@ -177,6 +179,8 @@ static void usbh_set(struct clk *clk, in
+ bcm_hwclock_set(CKCTL_6362_USBH_EN, enable);
+ else if (BCMCPU_IS_6368())
+ bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
++ else if (BCMCPU_IS_63268())
++ bcm_hwclock_set(CKCTL_63268_USBH_EN, enable);
+ else
+ return;
+
+@@ -199,6 +203,8 @@ static void usbd_set(struct clk *clk, in
+ bcm_hwclock_set(CKCTL_6362_USBD_EN, enable);
+ else if (BCMCPU_IS_6368())
+ bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
++ else if (BCMCPU_IS_63268())
++ bcm_hwclock_set(CKCTL_63268_USBD_EN, enable);
+ else
+ return;
+
+@@ -225,9 +231,13 @@ static void spi_set(struct clk *clk, int
+ mask = CKCTL_6358_SPI_EN;
+ else if (BCMCPU_IS_6362())
+ mask = CKCTL_6362_SPI_EN;
+- else
+- /* BCMCPU_IS_6368 */
++ else if (BCMCPU_IS_6368())
+ mask = CKCTL_6368_SPI_EN;
++ else if (BCMCPU_IS_63268())
++ mask = CKCTL_63268_SPI_EN;
++ else
++ return;
++
+ bcm_hwclock_set(mask, enable);
+ }
+
+@@ -246,6 +256,8 @@ static void hsspi_set(struct clk *clk, i
+ mask = CKCTL_6328_HSSPI_EN;
+ else if (BCMCPU_IS_6362())
+ mask = CKCTL_6362_HSSPI_EN;
++ else if (BCMCPU_IS_63268())
++ mask = CKCTL_63268_HSSPI_EN;
+ else
+ return;
+
+@@ -307,6 +319,8 @@ static void pcie_set(struct clk *clk, in
+ bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
+ else if (BCMCPU_IS_6362())
+ bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable);
++ else if (BCMCPU_IS_63268())
++ bcm_hwclock_set(CKCTL_63268_PCIE_EN, enable);
+ }
+
+ static struct clk clk_pcie = {
+@@ -386,9 +400,11 @@ struct clk *clk_get(struct device *dev,
+ return &clk_periph;
+ if ((BCMCPU_IS_3368() || BCMCPU_IS_6358()) && !strcmp(id, "pcm"))
+ return &clk_pcm;
+- if ((BCMCPU_IS_6362() || BCMCPU_IS_6368()) && !strcmp(id, "ipsec"))
++ if ((BCMCPU_IS_6362() || BCMCPU_IS_6368() || BCMCPU_IS_63268()) &&
++ !strcmp(id, "ipsec"))
+ return &clk_ipsec;
+- if ((BCMCPU_IS_6328() || BCMCPU_IS_6362()) && !strcmp(id, "pcie"))
++ if ((BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_63268()) &&
++ !strcmp(id, "pcie"))
+ return &clk_pcie;
+ return ERR_PTR(-ENOENT);
+ }
+@@ -411,6 +427,7 @@ static int __init bcm63xx_clk_init(void)
+ clk_hsspi.rate = HSSPI_PLL_HZ_6328;
+ break;
+ case BCM6362_CPU_ID:
++ case BCM63268_CPU_ID:
+ clk_hsspi.rate = HSSPI_PLL_HZ_6362;
+ break;
+ }
+--- a/arch/mips/bcm63xx/cpu.c
++++ b/arch/mips/bcm63xx/cpu.c
+@@ -101,6 +101,15 @@ static const int bcm6368_irqs[] = {
+
+ };
+
++static const unsigned long bcm63268_regs_base[] = {
++ __GEN_CPU_REGS_TABLE(63268)
++};
++
++static const int bcm63268_irqs[] = {
++ __GEN_CPU_IRQ_TABLE(63268)
++
++};
++
+ u32 bcm63xx_get_cpu_variant(void)
+ {
+ return bcm63xx_cpu_variant;
+@@ -253,6 +262,27 @@ static unsigned int detect_cpu_clock(voi
+
+ return (((64 * 1000000) / p1) * p2 * ndiv) / m1;
+ }
++ case BCM63268_CPU_ID:
++ {
++ unsigned int tmp, mips_pll_fcvo;
++
++ tmp = bcm_misc_readl(MISC_STRAPBUS_63268_REG);
++ mips_pll_fcvo = (tmp & STRAPBUS_63268_FCVO_MASK) >>
++ STRAPBUS_63268_FCVO_SHIFT;
++ switch (mips_pll_fcvo) {
++ case 0x3:
++ case 0xe:
++ return 320000000;
++ case 0xa:
++ return 333000000;
++ case 0x2:
++ case 0xb:
++ case 0xf:
++ return 400000000;
++ default:
++ return 0;
++ }
++ }
+
+ default:
+ panic("Failed to detect clock for CPU with id=%04X\n", cpu_id);
+@@ -267,7 +297,7 @@ static unsigned int detect_memory_size(v
+ unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0;
+ u32 val;
+
+- if (BCMCPU_IS_6328() || BCMCPU_IS_6362())
++ if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_63268())
+ return bcm_ddr_readl(DDR_CSEND_REG) << 24;
+
+ if (BCMCPU_IS_6345()) {
+@@ -305,6 +335,7 @@ void __init bcm63xx_cpu_init(void)
+ unsigned int tmp;
+ unsigned int cpu = smp_processor_id();
+ u32 chipid_reg;
++ bool long_chipid = false;
+ u8 __maybe_unused varid = 0;
+
+ /* soc registers location depends on cpu type */
+@@ -326,6 +357,9 @@ void __init bcm63xx_cpu_init(void)
+ case 0x10:
+ chipid_reg = BCM_6345_PERF_BASE;
+ break;
++ case 0x80:
++ long_chipid = true;
++ /* fall-through */
+ default:
+ chipid_reg = BCM_6368_PERF_BASE;
+ break;
+@@ -333,6 +367,7 @@ void __init bcm63xx_cpu_init(void)
+ break;
+ }
+
++
+ /*
+ * really early to panic, but delaying panic would not help since we
+ * will never get any working console
+@@ -342,10 +377,17 @@ void __init bcm63xx_cpu_init(void)
+
+ /* read out CPU type */
+ tmp = bcm_readl(chipid_reg);
+- bcm63xx_cpu_id = (tmp & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT;
+- bcm63xx_cpu_variant = bcm63xx_cpu_id;
++
++ if (long_chipid) {
++ bcm63xx_cpu_id = tmp & REV_LONG_CHIPID_MASK;
++ bcm63xx_cpu_id >>= REV_LONG_CHIPID_SHIFT;
++ } else {
++ bcm63xx_cpu_id = (tmp & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT;
++ varid = (tmp & REV_VARID_MASK) >> REV_VARID_SHIFT;
++ }
++
+ bcm63xx_cpu_rev = (tmp & REV_REVID_MASK) >> REV_REVID_SHIFT;
+- varid = (tmp & REV_VARID_MASK) >> REV_VARID_SHIFT;
++ bcm63xx_cpu_variant = bcm63xx_cpu_id;
+
+ switch (bcm63xx_cpu_id) {
+ case BCM3368_CPU_ID:
+@@ -400,6 +442,15 @@ void __init bcm63xx_cpu_init(void)
+ /* BCM6369 is a BCM6368 without xDSL, so treat it the same */
+ bcm63xx_cpu_id = BCM6368_CPU_ID;
+ break;
++ case BCM63168_CPU_ID:
++ case BCM63169_CPU_ID:
++ case BCM63268_CPU_ID:
++ case BCM63269_CPU_ID:
++ bcm63xx_regs_base = bcm63268_regs_base;
++ bcm63xx_irqs = bcm63268_irqs;
++
++ bcm63xx_cpu_id = BCM63268_CPU_ID;
++ break;
+ default:
+ panic("unsupported broadcom CPU %x", bcm63xx_cpu_id);
+ break;
+--- a/arch/mips/bcm63xx/dev-flash.c
++++ b/arch/mips/bcm63xx/dev-flash.c
+@@ -94,6 +94,12 @@ static int __init bcm63xx_detect_flash_t
+ case STRAPBUS_6368_BOOT_SEL_PARALLEL:
+ return BCM63XX_FLASH_TYPE_PARALLEL;
+ }
++ case BCM63268_CPU_ID:
++ val = bcm_misc_readl(MISC_STRAPBUS_63268_REG);
++ if (val & STRAPBUS_63268_BOOT_SEL_SERIAL)
++ return BCM63XX_FLASH_TYPE_SERIAL;
++ else
++ return BCM63XX_FLASH_TYPE_NAND;
+ default:
+ return -EINVAL;
+ }
+--- a/arch/mips/bcm63xx/dev-spi.c
++++ b/arch/mips/bcm63xx/dev-spi.c
+@@ -51,7 +51,7 @@ int __init bcm63xx_spi_register(void)
+ }
+
+ if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6362() ||
+- BCMCPU_IS_6368()) {
++ BCMCPU_IS_6368() || BCMCPU_IS_63268()) {
+ bcm63xx_spi_device.name = "bcm6358-spi",
+ spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
+ }
+--- a/arch/mips/bcm63xx/irq.c
++++ b/arch/mips/bcm63xx/irq.c
+@@ -150,6 +150,20 @@ void __init arch_init_irq(void)
+ ext_irqs[5] = BCM_6368_EXT_IRQ5;
+ ext_shift = 4;
+ break;
++ case BCM63268_CPU_ID:
++ periph_bases[0] += PERF_IRQMASK_63268_REG(0);
++ periph_bases[1] += PERF_IRQMASK_63268_REG(1);
++ periph_irq_count = 2;
++ periph_width = 4;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_63268;
++ ext_irq_count = 4;
++ ext_irqs[0] = BCM_63268_EXT_IRQ0;
++ ext_irqs[1] = BCM_63268_EXT_IRQ1;
++ ext_irqs[2] = BCM_63268_EXT_IRQ2;
++ ext_irqs[3] = BCM_63268_EXT_IRQ3;
++ ext_shift = 4;
++ break;
+ default:
+ BUG();
+ }
+--- a/arch/mips/bcm63xx/reset.c
++++ b/arch/mips/bcm63xx/reset.c
+@@ -125,6 +125,20 @@
+ #define BCM6368_RESET_PCIE 0
+ #define BCM6368_RESET_PCIE_EXT 0
+
++#define BCM63268_RESET_SPI SOFTRESET_63268_SPI_MASK
++#define BCM63268_RESET_ENET 0
++#define BCM63268_RESET_USBH SOFTRESET_63268_USBH_MASK
++#define BCM63268_RESET_USBD SOFTRESET_63268_USBS_MASK
++#define BCM63268_RESET_DSL 0
++#define BCM63268_RESET_SAR SOFTRESET_63268_SAR_MASK
++#define BCM63268_RESET_EPHY 0
++#define BCM63268_RESET_ENETSW SOFTRESET_63268_ENETSW_MASK
++#define BCM63268_RESET_PCM SOFTRESET_63268_PCM_MASK
++#define BCM63268_RESET_MPI 0
++#define BCM63268_RESET_PCIE (SOFTRESET_63268_PCIE_MASK | \
++ SOFTRESET_63268_PCIE_CORE_MASK)
++#define BCM63268_RESET_PCIE_EXT SOFTRESET_63268_PCIE_EXT_MASK
++
+ /*
+ * core reset bits
+ */
+@@ -156,6 +170,10 @@ static const u32 bcm6368_reset_bits[] =
+ __GEN_RESET_BITS_TABLE(6368)
+ };
+
++static const u32 bcm63268_reset_bits[] = {
++ __GEN_RESET_BITS_TABLE(63268)
++};
++
+ const u32 *bcm63xx_reset_bits;
+ static int reset_reg;
+
+@@ -182,6 +200,9 @@ static int __init bcm63xx_reset_bits_ini
+ } else if (BCMCPU_IS_6368()) {
+ reset_reg = PERF_SOFTRESET_6368_REG;
+ bcm63xx_reset_bits = bcm6368_reset_bits;
++ } else if (BCMCPU_IS_63268()) {
++ reset_reg = PERF_SOFTRESET_63268_REG;
++ bcm63xx_reset_bits = bcm63268_reset_bits;
+ }
+
+ return 0;
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+@@ -21,6 +21,10 @@
+ #define BCM6362_CPU_ID 0x6362
+ #define BCM6368_CPU_ID 0x6368
+ #define BCM6369_CPU_ID 0x6369
++#define BCM63168_CPU_ID 0x63168
++#define BCM63169_CPU_ID 0x63169
++#define BCM63268_CPU_ID 0x63268
++#define BCM63269_CPU_ID 0x63269
+
+ void __init bcm63xx_cpu_init(void);
+ u32 bcm63xx_get_cpu_variant(void);
+@@ -61,6 +65,10 @@ static inline u32 __pure __bcm63xx_get_c
+ #ifdef CONFIG_BCM63XX_CPU_6368
+ case BCM6368_CPU_ID:
+ #endif
++
++#ifdef CONFIG_BCM63XX_CPU_63268
++ case BCM63268_CPU_ID:
++#endif
+ break;
+ default:
+ unreachable();
+@@ -86,6 +94,7 @@ static inline u32 __pure bcm63xx_get_cpu
+ #define BCMCPU_IS_6358() (bcm63xx_get_cpu_id() == BCM6358_CPU_ID)
+ #define BCMCPU_IS_6362() (bcm63xx_get_cpu_id() == BCM6362_CPU_ID)
+ #define BCMCPU_IS_6368() (bcm63xx_get_cpu_id() == BCM6368_CPU_ID)
++#define BCMCPU_IS_63268() (bcm63xx_get_cpu_id() == BCM63268_CPU_ID)
+
+ #define BCMCPU_VARIANT_IS_3368() \
+ (bcm63xx_get_cpu_variant() == BCM3368_CPU_ID)
+@@ -109,6 +118,14 @@ static inline u32 __pure bcm63xx_get_cpu
+ (bcm63xx_get_cpu_variant() == BCM6368_CPU_ID)
+ #define BCMCPU_VARIANT_IS_6369() \
+ (bcm63xx_get_cpu_variant() == BCM6369_CPU_ID)
++#define BCMCPU_VARIANT_IS_63168() \
++ (bcm63xx_get_cpu_variant() == BCM63168_CPU_ID)
++#define BCMCPU_VARIANT_IS_63169() \
++ (bcm63xx_get_cpu_variant() == BCM63169_CPU_ID)
++#define BCMCPU_VARIANT_IS_63268() \
++ (bcm63xx_get_cpu_variant() == BCM63268_CPU_ID)
++#define BCMCPU_VARIANT_IS_63269() \
++ (bcm63xx_get_cpu_variant() == BCM63269_CPU_ID)
+
+ /*
+ * While registers sets are (mostly) the same across 63xx CPU, base
+@@ -573,6 +590,52 @@ enum bcm63xx_regs_set {
+ #define BCM_6368_RNG_BASE (0xb0004180)
+ #define BCM_6368_MISC_BASE (0xdeadbeef)
+
++/*
++ * 63268 register sets base address
++ */
++#define BCM_63268_DSL_LMEM_BASE (0xdeadbeef)
++#define BCM_63268_PERF_BASE (0xb0000000)
++#define BCM_63268_TIMER_BASE (0xb0000080)
++#define BCM_63268_WDT_BASE (0xb000009c)
++#define BCM_63268_UART0_BASE (0xb0000180)
++#define BCM_63268_UART1_BASE (0xb00001a0)
++#define BCM_63268_GPIO_BASE (0xb00000c0)
++#define BCM_63268_SPI_BASE (0xb0000800)
++#define BCM_63268_HSSPI_BASE (0xb0001000)
++#define BCM_63268_UDC0_BASE (0xdeadbeef)
++#define BCM_63268_USBDMA_BASE (0xb000c800)
++#define BCM_63268_OHCI0_BASE (0xb0002600)
++#define BCM_63268_OHCI_PRIV_BASE (0xdeadbeef)
++#define BCM_63268_USBH_PRIV_BASE (0xb0002700)
++#define BCM_63268_USBD_BASE (0xb0002400)
++#define BCM_63268_MPI_BASE (0xdeadbeef)
++#define BCM_63268_PCMCIA_BASE (0xdeadbeef)
++#define BCM_63268_PCIE_BASE (0xb06e0000)
++#define BCM_63268_SDRAM_REGS_BASE (0xdeadbeef)
++#define BCM_63268_DSL_BASE (0xdeadbeef)
++#define BCM_63268_UBUS_BASE (0xdeadbeef)
++#define BCM_63268_ENET0_BASE (0xdeadbeef)
++#define BCM_63268_ENET1_BASE (0xdeadbeef)
++#define BCM_63268_ENETDMA_BASE (0xb000d800)
++#define BCM_63268_ENETDMAC_BASE (0xb000da00)
++#define BCM_63268_ENETDMAS_BASE (0xb000dc00)
++#define BCM_63268_ENETSW_BASE (0xb0700000)
++#define BCM_63268_EHCI0_BASE (0xb0002500)
++#define BCM_63268_SDRAM_BASE (0xdeadbeef)
++#define BCM_63268_MEMC_BASE (0xdeadbeef)
++#define BCM_63268_DDR_BASE (0xb0003000)
++#define BCM_63268_M2M_BASE (0xdeadbeef)
++#define BCM_63268_ATM_BASE (0xdeadbeef)
++#define BCM_63268_XTM_BASE (0xb0007000)
++#define BCM_63268_XTMDMA_BASE (0xb000b800)
++#define BCM_63268_XTMDMAC_BASE (0xdeadbeef)
++#define BCM_63268_XTMDMAS_BASE (0xdeadbeef)
++#define BCM_63268_PCM_BASE (0xb000b000)
++#define BCM_63268_PCMDMA_BASE (0xb000b800)
++#define BCM_63268_PCMDMAC_BASE (0xdeadbeef)
++#define BCM_63268_PCMDMAS_BASE (0xdeadbeef)
++#define BCM_63268_RNG_BASE (0xdeadbeef)
++#define BCM_63268_MISC_BASE (0xb0001800)
+
+ extern const unsigned long *bcm63xx_regs_base;
+
+@@ -1041,6 +1104,73 @@ enum bcm63xx_irq {
+ #define BCM_6368_EXT_IRQ4 (IRQ_INTERNAL_BASE + 24)
+ #define BCM_6368_EXT_IRQ5 (IRQ_INTERNAL_BASE + 25)
+
++/*
++ * 63268 irqs
++ */
++#define BCM_63268_HIGH_IRQ_BASE (IRQ_INTERNAL_BASE + 32)
++#define BCM_63268_VERY_HIGH_IRQ_BASE (BCM_63268_HIGH_IRQ_BASE + 32)
++
++#define BCM_63268_TIMER_IRQ (IRQ_INTERNAL_BASE + 0)
++#define BCM_63268_SPI_IRQ (BCM_63268_VERY_HIGH_IRQ_BASE + 16)
++#define BCM_63268_UART0_IRQ (IRQ_INTERNAL_BASE + 5)
++#define BCM_63268_UART1_IRQ (BCM_63268_HIGH_IRQ_BASE + 2)
++#define BCM_63268_DSL_IRQ (IRQ_INTERNAL_BASE + 23)
++#define BCM_63268_UDC0_IRQ 0
++#define BCM_63268_ENET0_IRQ 0
++#define BCM_63268_ENET1_IRQ 0
++#define BCM_63268_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 13)
++#define BCM_63268_HSSPI_IRQ (IRQ_INTERNAL_BASE + 6)
++#define BCM_63268_OHCI0_IRQ (IRQ_INTERNAL_BASE + 9)
++#define BCM_63268_EHCI0_IRQ (IRQ_INTERNAL_BASE + 10)
++#define BCM_63268_USBD_IRQ (IRQ_INTERNAL_BASE + 11)
++#define BCM_63268_USBD_RXDMA0_IRQ (IRQ_INTERNAL_BASE + 19)
++#define BCM_63268_USBD_TXDMA0_IRQ (BCM_63268_HIGH_IRQ_BASE + 4)
++#define BCM_63268_USBD_RXDMA1_IRQ (IRQ_INTERNAL_BASE + 20)
++#define BCM_63268_USBD_TXDMA1_IRQ (BCM_63268_HIGH_IRQ_BASE + 5)
++#define BCM_63268_USBD_RXDMA2_IRQ (IRQ_INTERNAL_BASE + 21)
++#define BCM_63268_USBD_TXDMA2_IRQ (BCM_63268_HIGH_IRQ_BASE + 6)
++#define BCM_63268_PCMCIA_IRQ 0
++#define BCM_63268_ENET0_RXDMA_IRQ 0
++#define BCM_63268_ENET0_TXDMA_IRQ 0
++#define BCM_63268_ENET1_RXDMA_IRQ 0
++#define BCM_63268_ENET1_TXDMA_IRQ 0
++#define BCM_63268_PCI_IRQ (BCM_63268_HIGH_IRQ_BASE + 8)
++#define BCM_63268_ATM_IRQ 0
++#define BCM_63268_ENETSW_RXDMA0_IRQ (IRQ_INTERNAL_BASE + 1)
++#define BCM_63268_ENETSW_RXDMA1_IRQ (IRQ_INTERNAL_BASE + 2)
++#define BCM_63268_ENETSW_RXDMA2_IRQ (IRQ_INTERNAL_BASE + 3)
++#define BCM_63268_ENETSW_RXDMA3_IRQ (IRQ_INTERNAL_BASE + 4)
++#define BCM_63268_ENETSW_TXDMA0_IRQ (BCM_63268_VERY_HIGH_IRQ_BASE + 0)
++#define BCM_63268_ENETSW_TXDMA1_IRQ (BCM_63268_VERY_HIGH_IRQ_BASE + 1)
++#define BCM_63268_ENETSW_TXDMA2_IRQ (BCM_63268_VERY_HIGH_IRQ_BASE + 2)
++#define BCM_63268_ENETSW_TXDMA3_IRQ (BCM_63268_VERY_HIGH_IRQ_BASE + 3)
++#define BCM_63268_XTM_IRQ (BCM_63268_HIGH_IRQ_BASE + 17)
++#define BCM_63268_XTM_DMA0_IRQ (IRQ_INTERNAL_BASE + 26)
++
++#define BCM_63268_RING_OSC_IRQ (BCM_63268_HIGH_IRQ_BASE + 20)
++#define BCM_63268_WLAN_GPIO_IRQ (BCM_63268_HIGH_IRQ_BASE + 3)
++#define BCM_63268_WLAN_IRQ (IRQ_INTERNAL_BASE + 7)
++#define BCM_63268_IPSEC_IRQ (IRQ_INTERNAL_BASE + 8)
++#define BCM_63268_NAND_IRQ (BCM_63268_HIGH_IRQ_BASE + 18)
++#define BCM_63268_PCM_IRQ (IRQ_INTERNAL_BASE + 13)
++#define BCM_63268_DG_IRQ (IRQ_INTERNAL_BASE + 15)
++#define BCM_63268_EPHY_ENERGY0_IRQ (IRQ_INTERNAL_BASE + 16)
++#define BCM_63268_EPHY_ENERGY1_IRQ (IRQ_INTERNAL_BASE + 17)
++#define BCM_63268_EPHY_ENERGY2_IRQ (IRQ_INTERNAL_BASE + 18)
++#define BCM_63268_EPHY_ENERGY3_IRQ (IRQ_INTERNAL_BASE + 19)
++#define BCM_63268_IPSEC_DMA0_IRQ (IRQ_INTERNAL_BASE + 22)
++#define BCM_63268_IPSEC_DMA1_IRQ (BCM_63268_HIGH_IRQ_BASE + 7)
++#define BCM_63268_FAP0_IRQ (IRQ_INTERNAL_BASE + 24)
++#define BCM_63268_FAP1_IRQ (IRQ_INTERNAL_BASE + 25)
++#define BCM_63268_PCM_DMA0_IRQ (BCM_63268_HIGH_IRQ_BASE + 10)
++#define BCM_63268_PCM_DMA1_IRQ (BCM_63268_HIGH_IRQ_BASE + 11)
++#define BCM_63268_DECT0_IRQ (BCM_63268_HIGH_IRQ_BASE + 0)
++#define BCM_63268_DECT1_IRQ (BCM_63268_HIGH_IRQ_BASE + 1)
++#define BCM_63268_EXT_IRQ0 (BCM_63268_HIGH_IRQ_BASE + 12)
++#define BCM_63268_EXT_IRQ1 (BCM_63268_HIGH_IRQ_BASE + 13)
++#define BCM_63268_EXT_IRQ2 (BCM_63268_HIGH_IRQ_BASE + 14)
++#define BCM_63268_EXT_IRQ3 (BCM_63268_HIGH_IRQ_BASE + 15)
++
+ extern const int *bcm63xx_irqs;
+
+ #define __GEN_CPU_IRQ_TABLE(__cpu) \
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
+@@ -22,6 +22,8 @@ static inline unsigned long bcm63xx_gpio
+ return 48;
+ case BCM6368_CPU_ID:
+ return 38;
++ case BCM63268_CPU_ID:
++ return 52;
+ case BCM6348_CPU_ID:
+ default:
+ return 37;
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+@@ -9,6 +9,8 @@
+ #define PERF_REV_REG 0x0
+ #define REV_CHIPID_SHIFT 16
+ #define REV_CHIPID_MASK (0xffff << REV_CHIPID_SHIFT)
++#define REV_LONG_CHIPID_SHIFT 12
++#define REV_LONG_CHIPID_MASK (0xfffff << REV_LONG_CHIPID_SHIFT)
+ #define REV_VARID_SHIFT 12
+ #define REV_VARID_MASK (0xf << REV_VARID_SHIFT)
+ #define REV_REVID_SHIFT 0
+@@ -211,6 +213,52 @@
+ CKCTL_6368_NAND_EN | \
+ CKCTL_6368_IPSEC_EN)
+
++#define CKCTL_63268_DISABLE_GLESS (1 << 0)
++#define CKCTL_63268_VDSL_QPROC_EN (1 << 1)
++#define CKCTL_63268_VDSL_AFE_EN (1 << 2)
++#define CKCTL_63268_VDSL_EN (1 << 3)
++#define CKCTL_63268_MIPS_EN (1 << 4)
++#define CKCTL_63268_WLAN_OCP_EN (1 << 5)
++#define CKCTL_63268_DECT_EN (1 << 6)
++#define CKCTL_63268_FAP0_EN (1 << 7)
++#define CKCTL_63268_FAP1_EN (1 << 8)
++#define CKCTL_63268_SAR_EN (1 << 9)
++#define CKCTL_63268_ROBOSW_EN (1 << 10)
++#define CKCTL_63268_PCM_EN (1 << 11)
++#define CKCTL_63268_USBD_EN (1 << 12)
++#define CKCTL_63268_USBH_EN (1 << 13)
++#define CKCTL_63268_IPSEC_EN (1 << 14)
++#define CKCTL_63268_SPI_EN (1 << 15)
++#define CKCTL_63268_HSSPI_EN (1 << 16)
++#define CKCTL_63268_PCIE_EN (1 << 17)
++#define CKCTL_63268_PHYMIPS_EN (1 << 18)
++#define CKCTL_63268_GMAC_EN (1 << 19)
++#define CKCTL_63268_NAND_EN (1 << 20)
++#define CKCTL_63268_TBUS_EN (1 << 27)
++#define CKCTL_63268_ROBOSW250_EN (1 << 31)
++
++#define CKCTL_63268_ALL_SAFE_EN (CKCTL_63268_VDSL_QPROC_EN | \
++ CKCTL_63268_VDSL_AFE_EN | \
++ CKCTL_63268_VDSL_EN | \
++ CKCTL_63268_WLAN_OCP_EN | \
++ CKCTL_63268_DECT_EN | \
++ CKCTL_63268_FAP0_EN | \
++ CKCTL_63268_FAP1_EN | \
++ CKCTL_63268_SAR_EN | \
++ CKCTL_63268_ROBOSW_EN | \
++ CKCTL_63268_PCM_EN | \
++ CKCTL_63268_USBD_EN | \
++ CKCTL_63268_USBH_EN | \
++ CKCTL_63268_IPSEC_EN | \
++ CKCTL_63268_SPI_EN | \
++ CKCTL_63268_HSSPI_EN | \
++ CKCTL_63268_PCIE_EN | \
++ CKCTL_63268_PHYMIPS_EN | \
++ CKCTL_63268_GMAC_EN | \
++ CKCTL_63268_NAND_EN | \
++ CKCTL_63268_TBUS_EN | \
++ CKCTL_63268_ROBOSW250_EN)
++
+ /* System PLL Control register */
+ #define PERF_SYS_PLL_CTL_REG 0x8
+ #define SYS_PLL_SOFT_RESET 0x1
+@@ -224,6 +272,7 @@
+ #define PERF_IRQMASK_6358_REG(x) (0xc + (x) * 0x2c)
+ #define PERF_IRQMASK_6362_REG(x) (0x20 + (x) * 0x10)
+ #define PERF_IRQMASK_6368_REG(x) (0x20 + (x) * 0x10)
++#define PERF_IRQMASK_63268_REG(x) (0x20 + (x) * 0x20)
+
+ /* Interrupt Status register */
+ #define PERF_IRQSTAT_3368_REG 0x10
+@@ -234,6 +283,7 @@
+ #define PERF_IRQSTAT_6358_REG(x) (0x10 + (x) * 0x2c)
+ #define PERF_IRQSTAT_6362_REG(x) (0x28 + (x) * 0x10)
+ #define PERF_IRQSTAT_6368_REG(x) (0x28 + (x) * 0x10)
++#define PERF_IRQSTAT_63268_REG(x) (0x30 + (x) * 0x20)
+
+ /* External Interrupt Configuration register */
+ #define PERF_EXTIRQ_CFG_REG_3368 0x14
+@@ -244,6 +294,7 @@
+ #define PERF_EXTIRQ_CFG_REG_6358 0x14
+ #define PERF_EXTIRQ_CFG_REG_6362 0x18
+ #define PERF_EXTIRQ_CFG_REG_6368 0x18
++#define PERF_EXTIRQ_CFG_REG_63268 0x18
+
+ #define PERF_EXTIRQ_CFG_REG2_6358 0x1c
+ #define PERF_EXTIRQ_CFG_REG2_6368 0x1c
+@@ -274,6 +325,7 @@
+ #define PERF_SOFTRESET_6358_REG 0x34
+ #define PERF_SOFTRESET_6362_REG 0x10
+ #define PERF_SOFTRESET_6368_REG 0x10
++#define PERF_SOFTRESET_63268_REG 0x10
+
+ #define SOFTRESET_3368_SPI_MASK (1 << 0)
+ #define SOFTRESET_3368_ENET_MASK (1 << 2)
+@@ -367,6 +419,26 @@
+ #define SOFTRESET_6368_USBH_MASK (1 << 12)
+ #define SOFTRESET_6368_PCM_MASK (1 << 13)
+
++#define SOFTRESET_63268_SPI_MASK (1 << 0)
++#define SOFTRESET_63268_IPSEC_MASK (1 << 1)
++#define SOFTRESET_63268_EPHY_MASK (1 << 2)
++#define SOFTRESET_63268_SAR_MASK (1 << 3)
++#define SOFTRESET_63268_ENETSW_MASK (1 << 4)
++#define SOFTRESET_63268_USBS_MASK (1 << 5)
++#define SOFTRESET_63268_USBH_MASK (1 << 6)
++#define SOFTRESET_63268_PCM_MASK (1 << 7)
++#define SOFTRESET_63268_PCIE_CORE_MASK (1 << 8)
++#define SOFTRESET_63268_PCIE_MASK (1 << 9)
++#define SOFTRESET_63268_PCIE_EXT_MASK (1 << 10)
++#define SOFTRESET_63268_WLAN_SHIM_MASK (1 << 11)
++#define SOFTRESET_63268_DDR_PHY_MASK (1 << 12)
++#define SOFTRESET_63268_FAP0_MASK (1 << 13)
++#define SOFTRESET_63268_WLAN_UBUS_MASK (1 << 14)
++#define SOFTRESET_63268_DECT_MASK (1 << 15)
++#define SOFTRESET_63268_FAP1_MASK (1 << 16)
++#define SOFTRESET_63268_PCIE_HARD_MASK (1 << 17)
++#define SOFTRESET_63268_GPHY_MASK (1 << 18)
++
+ /* MIPS PLL control register */
+ #define PERF_MIPSPLLCTL_REG 0x34
+ #define MIPSPLLCTL_N1_SHIFT 20
+@@ -1366,6 +1438,13 @@
+ #define STRAPBUS_6362_BOOT_SEL_SERIAL (1 << 15)
+ #define STRAPBUS_6362_BOOT_SEL_NAND (0 << 15)
+
++#define MISC_STRAPBUS_63268_REG 0x14
++#define STRAPBUS_63268_HSSPI_CLK_FAST (1 << 9)
++#define STRAPBUS_63268_BOOT_SEL_SERIAL (1 << 11)
++#define STRAPBUS_63268_BOOT_SEL_NAND (0 << 11)
++#define STRAPBUS_63268_FCVO_SHIFT 21
++#define STRAPBUS_63268_FCVO_MASK (0xf << STRAPBUS_63268_FCVO_SHIFT)
++
+ #define MISC_STRAPBUS_6328_REG 0x240
+ #define STRAPBUS_6328_FCVO_SHIFT 7
+ #define STRAPBUS_6328_FCVO_MASK (0x1f << STRAPBUS_6328_FCVO_SHIFT)
+--- a/arch/mips/include/asm/mach-bcm63xx/ioremap.h
++++ b/arch/mips/include/asm/mach-bcm63xx/ioremap.h
+@@ -25,6 +25,7 @@ static inline int is_bcm63xx_internal_re
+ case BCM6328_CPU_ID:
+ case BCM6362_CPU_ID:
+ case BCM6368_CPU_ID:
++ case BCM63268_CPU_ID:
+ if (offset >= 0xb0000000 && offset < 0xb1000000)
+ return 1;
+ break;
+--- a/arch/mips/bcm63xx/dev-hsspi.c
++++ b/arch/mips/bcm63xx/dev-hsspi.c
+@@ -35,7 +35,7 @@ static struct platform_device bcm63xx_hs
+
+ int __init bcm63xx_hsspi_register(void)
+ {
+- if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362())
++ if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_63268())
+ return -ENODEV;
+
+ spi_resources[0].start = bcm63xx_regset_address(RSET_HSSPI);
+--- a/arch/mips/bcm63xx/dev-enet.c
++++ b/arch/mips/bcm63xx/dev-enet.c
+@@ -176,7 +176,8 @@ static int __init register_shared(void)
+ else
+ shared_res[0].end += (RSET_ENETDMA_SIZE) - 1;
+
+- if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368())
++ if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368() ||
++ BCMCPU_IS_63268())
+ chan_count = 32;
+ else if (BCMCPU_IS_6345())
+ chan_count = 8;
+@@ -276,7 +277,8 @@ bcm63xx_enetsw_register(const struct bcm
+ {
+ int ret;
+
+- if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
++ if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368() &&
++ !BCMCPU_IS_63268())
+ return -ENODEV;
+
+ ret = register_shared();
+@@ -297,6 +299,8 @@ bcm63xx_enetsw_register(const struct bcm
+ enetsw_pd.num_ports = ENETSW_PORTS_6328;
+ else if (BCMCPU_IS_6362() || BCMCPU_IS_6368())
+ enetsw_pd.num_ports = ENETSW_PORTS_6368;
++ else if (BCMCPU_IS_63268())
++ enetsw_pd.num_ports = ENETSW_PORTS_63268;
+
+ enetsw_pd.dma_has_sram = true;
+ enetsw_pd.dma_chan_width = ENETDMA_CHAN_WIDTH;
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h
+@@ -62,6 +62,7 @@ struct bcm63xx_enet_platform_data {
+ #define ENETSW_MAX_PORT 8
+ #define ENETSW_PORTS_6328 5 /* 4 FE PHY + 1 RGMII */
+ #define ENETSW_PORTS_6368 6 /* 4 FE PHY + 2 RGMII */
++#define ENETSW_PORTS_63268 8 /* 3 FE PHY + 1 GE PHY + 4 RGMII */
+
+ #define ENETSW_RGMII_PORT0 4
+
--- /dev/null
+From 5c290c81dbdb4433600593fe80c88eb4af86e791 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 8 Dec 2013 03:22:40 +0100
+Subject: [PATCH 50/53] MIPS: BCM63XX: add pcie support for BCM63268
+
+---
+ arch/mips/bcm63xx/reset.c | 3 ++-
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h | 5 +++++
+ arch/mips/pci/pci-bcm63xx.c | 4 ++++
+ 3 files changed, 11 insertions(+), 1 deletion(-)
+
+--- a/arch/mips/bcm63xx/reset.c
++++ b/arch/mips/bcm63xx/reset.c
+@@ -136,7 +136,8 @@
+ #define BCM63268_RESET_PCM SOFTRESET_63268_PCM_MASK
+ #define BCM63268_RESET_MPI 0
+ #define BCM63268_RESET_PCIE (SOFTRESET_63268_PCIE_MASK | \
+- SOFTRESET_63268_PCIE_CORE_MASK)
++ SOFTRESET_63268_PCIE_CORE_MASK | \
++ SOFTRESET_63268_PCIE_HARD_MASK)
+ #define BCM63268_RESET_PCIE_EXT SOFTRESET_63268_PCIE_EXT_MASK
+
+ /*
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
+@@ -45,6 +45,11 @@
+ #define BCM_PCIE_MEM_END_PA_6328 (BCM_PCIE_MEM_BASE_PA_6328 + \
+ BCM_PCIE_MEM_SIZE_6328 - 1)
+
++#define BCM_PCIE_MEM_BASE_PA_63268 0x11000000
++#define BCM_PCIE_MEM_SIZE_63268 (15 * 1024 * 1024)
++#define BCM_PCIE_MEM_END_PA_63268 (BCM_PCIE_MEM_BASE_PA_63268 + \
++ BCM_PCIE_MEM_SIZE_63268 - 1)
++
+ /*
+ * Internal registers are accessed through KSEG3
+ */
+--- a/arch/mips/pci/pci-bcm63xx.c
++++ b/arch/mips/pci/pci-bcm63xx.c
+@@ -337,11 +337,15 @@ static int __init bcm63xx_pci_init(void)
+ if (BCMCPU_IS_6328() || BCMCPU_IS_6362()) {
+ bcm_pcie_mem_resource.start = BCM_PCIE_MEM_BASE_PA_6328;
+ bcm_pcie_mem_resource.end = BCM_PCIE_MEM_END_PA_6328;
++ } else if (BCMCPU_IS_63268()) {
++ bcm_pcie_mem_resource.start = BCM_PCIE_MEM_BASE_PA_63268;
++ bcm_pcie_mem_resource.end = BCM_PCIE_MEM_END_PA_63268;
+ }
+
+ switch (bcm63xx_get_cpu_id()) {
+ case BCM6328_CPU_ID:
+ case BCM6362_CPU_ID:
++ case BCM63268_CPU_ID:
+ return bcm63xx_register_pcie();
+ case BCM3368_CPU_ID:
+ case BCM6348_CPU_ID:
--- /dev/null
+From 60c29522a8c77d96145d965589c56befda7d4c3d Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 8 Dec 2013 01:24:09 +0100
+Subject: [PATCH 51/53] MIPS: BCM63XX: add support for BCM6318
+
+---
+ arch/mips/bcm63xx/Kconfig | 5 +
+ arch/mips/bcm63xx/boards/board_bcm963xx.c | 2 +-
+ arch/mips/bcm63xx/clk.c | 8 +-
+ arch/mips/bcm63xx/cpu.c | 53 +++++++++++
+ arch/mips/bcm63xx/dev-flash.c | 3 +
+ arch/mips/bcm63xx/dev-spi.c | 2 +-
+ arch/mips/bcm63xx/irq.c | 10 ++
+ arch/mips/bcm63xx/prom.c | 2 +-
+ arch/mips/bcm63xx/reset.c | 24 +++++
+ arch/mips/bcm63xx/setup.c | 5 +-
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 107 ++++++++++++++++++++++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 75 ++++++++++++++-
+ arch/mips/include/asm/mach-bcm63xx/ioremap.h | 1 +
+ 13 files changed, 291 insertions(+), 6 deletions(-)
+
+--- a/arch/mips/bcm63xx/Kconfig
++++ b/arch/mips/bcm63xx/Kconfig
+@@ -18,6 +18,11 @@ config BCM63XX_EHCI
+ select USB_EHCI_BIG_ENDIAN_DESC if USB_EHCI_HCD
+ select USB_EHCI_BIG_ENDIAN_MMIO if USB_EHCI_HCD
+
++config BCM63XX_CPU_6318
++ bool "support 6318 CPU"
++ select SYS_HAS_CPU_BMIPS32_3300
++ select HW_HAS_PCI
++
+ config BCM63XX_CPU_6328
+ bool "support 6328 CPU"
+ select SYS_HAS_CPU_BMIPS4350
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -713,7 +713,7 @@ void __init board_prom_init(void)
+ /* read base address of boot chip select (0)
+ * 6328/6362 do not have MPI but boot from a fixed address
+ */
+- if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_63268()) {
++ if (BCMCPU_IS_6318() || BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_63268()) {
+ val = 0x18000000;
+ } else {
+ val = bcm_mpi_readl(MPI_CSBASE_REG(0));
+--- a/arch/mips/bcm63xx/clk.c
++++ b/arch/mips/bcm63xx/clk.c
+@@ -252,7 +252,9 @@ static void hsspi_set(struct clk *clk, i
+ {
+ u32 mask;
+
+- if (BCMCPU_IS_6328())
++ if (BCMCPU_IS_6318())
++ mask = CKCTL_6318_HSSPI_EN;
++ else if (BCMCPU_IS_6328())
+ mask = CKCTL_6328_HSSPI_EN;
+ else if (BCMCPU_IS_6362())
+ mask = CKCTL_6362_HSSPI_EN;
+@@ -417,12 +419,16 @@ void clk_put(struct clk *clk)
+
+ EXPORT_SYMBOL(clk_put);
+
++#define HSSPI_PLL_HZ_6318 250000000
+ #define HSSPI_PLL_HZ_6328 133333333
+ #define HSSPI_PLL_HZ_6362 400000000
+
+ static int __init bcm63xx_clk_init(void)
+ {
+ switch (bcm63xx_get_cpu_id()) {
++ case BCM6318_CPU_ID:
++ clk_hsspi.rate = HSSPI_PLL_HZ_6318;
++ break;
+ case BCM6328_CPU_ID:
+ clk_hsspi.rate = HSSPI_PLL_HZ_6328;
+ break;
+--- a/arch/mips/bcm63xx/cpu.c
++++ b/arch/mips/bcm63xx/cpu.c
+@@ -41,6 +41,14 @@ static const int bcm3368_irqs[] = {
+ __GEN_CPU_IRQ_TABLE(3368)
+ };
+
++static const unsigned long bcm6318_regs_base[] = {
++ __GEN_CPU_REGS_TABLE(6318)
++};
++
++static const int bcm6318_irqs[] = {
++ __GEN_CPU_IRQ_TABLE(6318)
++};
++
+ static const unsigned long bcm6328_regs_base[] = {
+ __GEN_CPU_REGS_TABLE(6328)
+ };
+@@ -134,6 +142,10 @@ unsigned int bcm63xx_get_memory_size(voi
+ return bcm63xx_memory_size;
+ }
+
++#define STRAP_OVERRIDE_BUS_REG 0x0
++#define OVERRIDE_BUS_MIPS_FREQ_SHIFT 23
++#define OVERRIDE_BUS_MIPS_FREQ_MASK (0x3 << OVERRIDE_BUS_MIPS_FREQ_SHIFT)
++
+ static unsigned int detect_cpu_clock(void)
+ {
+ u32 cpu_id = bcm63xx_get_cpu_id();
+@@ -142,6 +154,28 @@ static unsigned int detect_cpu_clock(voi
+ case BCM3368_CPU_ID:
+ return 300000000;
+
++ case BCM6318_CPU_ID:
++ {
++ unsigned int tmp, mips_pll_fcvo;
++
++ tmp = bcm_readl(BCM_6318_STRAP_BASE + STRAP_OVERRIDE_BUS_REG);
++
++ pr_info("strap_override_bus = %08x\n", tmp);
++
++ mips_pll_fcvo = (tmp & OVERRIDE_BUS_MIPS_FREQ_MASK)
++ >> OVERRIDE_BUS_MIPS_FREQ_SHIFT;
++
++ switch (mips_pll_fcvo) {
++ case 0:
++ return 166000000;
++ case 1:
++ return 400000000;
++ case 2:
++ return 250000000;
++ case 3:
++ return 333000000;
++ };
++ }
+ case BCM6328_CPU_ID:
+ {
+ unsigned int tmp, mips_pll_fcvo;
+@@ -297,6 +331,13 @@ static unsigned int detect_memory_size(v
+ unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0;
+ u32 val;
+
++ if (BCMCPU_IS_6318()) {
++ val = bcm_sdram_readl(SDRAM_CFG_REG);
++ val = val & SDRAM_CFG_6318_SPACE_MASK;
++ val >>= SDRAM_CFG_6318_SPACE_SHIFT;
++ return 1 << (val + 20);
++ }
++
+ if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_63268())
+ return bcm_ddr_readl(DDR_CSEND_REG) << 24;
+
+@@ -343,6 +384,12 @@ void __init bcm63xx_cpu_init(void)
+
+ switch (current_cpu_type()) {
+ case CPU_BMIPS3300:
++ if ((read_c0_prid() & 0xff) >= 0x33) {
++ /* BCM6318 */
++ chipid_reg = BCM_6368_PERF_BASE;
++ break;
++ }
++
+ if ((read_c0_prid() & PRID_IMP_MASK) != PRID_IMP_BMIPS3300_ALT)
+ __cpu_name[cpu] = "Broadcom BCM6338";
+ /* fall-through */
+@@ -390,6 +437,10 @@ void __init bcm63xx_cpu_init(void)
+ bcm63xx_cpu_variant = bcm63xx_cpu_id;
+
+ switch (bcm63xx_cpu_id) {
++ case BCM6318_CPU_ID:
++ bcm63xx_regs_base = bcm6318_regs_base;
++ bcm63xx_irqs = bcm6318_irqs;
++ break;
+ case BCM3368_CPU_ID:
+ bcm63xx_regs_base = bcm3368_regs_base;
+ bcm63xx_irqs = bcm3368_irqs;
+--- a/arch/mips/bcm63xx/dev-flash.c
++++ b/arch/mips/bcm63xx/dev-flash.c
+@@ -60,6 +60,9 @@ static int __init bcm63xx_detect_flash_t
+ u32 val;
+
+ switch (bcm63xx_get_cpu_id()) {
++ case BCM6318_CPU_ID:
++ /* only support serial flash */
++ return BCM63XX_FLASH_TYPE_SERIAL;
+ case BCM6328_CPU_ID:
+ val = bcm_misc_readl(MISC_STRAPBUS_6328_REG);
+ if (val & STRAPBUS_6328_BOOT_SEL_SERIAL)
+--- a/arch/mips/bcm63xx/dev-spi.c
++++ b/arch/mips/bcm63xx/dev-spi.c
+@@ -38,7 +38,7 @@ static struct platform_device bcm63xx_sp
+
+ int __init bcm63xx_spi_register(void)
+ {
+- if (BCMCPU_IS_6328() || BCMCPU_IS_6345())
++ if (BCMCPU_IS_6318() || BCMCPU_IS_6328() || BCMCPU_IS_6345())
+ return -ENODEV;
+
+ spi_resources[0].start = bcm63xx_regset_address(RSET_SPI);
+--- a/arch/mips/bcm63xx/irq.c
++++ b/arch/mips/bcm63xx/irq.c
+@@ -49,6 +49,19 @@ void __init arch_init_irq(void)
+ ext_irqs[3] = BCM_3368_EXT_IRQ3;
+ ext_shift = 4;
+ break;
++ case BCM6318_CPU_ID:
++ periph_bases[0] += PERF_IRQMASK_6318_REG;
++ periph_irq_count = 1;
++ periph_width = 4;
++
++ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6318;
++ ext_irq_count = 4;
++ ext_irqs[0] = BCM_6318_EXT_IRQ0;
++ ext_irqs[1] = BCM_6318_EXT_IRQ0;
++ ext_irqs[2] = BCM_6318_EXT_IRQ0;
++ ext_irqs[3] = BCM_6318_EXT_IRQ0;
++ ext_shift = 4;
++ break;
+ case BCM6328_CPU_ID:
+ periph_bases[0] += PERF_IRQMASK_6328_REG(0);
+ periph_bases[1] += PERF_IRQMASK_6328_REG(1);
+--- a/arch/mips/bcm63xx/prom.c
++++ b/arch/mips/bcm63xx/prom.c
+@@ -68,7 +68,7 @@ void __init prom_init(void)
+
+ if (reg & OTP_6328_REG3_TP1_DISABLED)
+ bmips_smp_enabled = 0;
+- } else if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) {
++ } else if (BCMCPU_IS_6318() || BCMCPU_IS_3368() || BCMCPU_IS_6358()) {
+ bmips_smp_enabled = 0;
+ }
+
+--- a/arch/mips/bcm63xx/reset.c
++++ b/arch/mips/bcm63xx/reset.c
+@@ -43,6 +43,23 @@
+ #define BCM3368_RESET_PCIE 0
+ #define BCM3368_RESET_PCIE_EXT 0
+
++
++#define BCM6318_RESET_SPI SOFTRESET_6318_SPI_MASK
++#define BCM6318_RESET_ENET 0
++#define BCM6318_RESET_USBH SOFTRESET_6318_USBH_MASK
++#define BCM6318_RESET_USBD SOFTRESET_6318_USBS_MASK
++#define BCM6318_RESET_DSL 0
++#define BCM6318_RESET_SAR SOFTRESET_6318_SAR_MASK
++#define BCM6318_RESET_EPHY SOFTRESET_6318_EPHY_MASK
++#define BCM6318_RESET_ENETSW SOFTRESET_6318_ENETSW_MASK
++#define BCM6318_RESET_PCM 0
++#define BCM6318_RESET_MPI 0
++#define BCM6318_RESET_PCIE \
++ (SOFTRESET_6318_PCIE_MASK | \
++ SOFTRESET_6318_PCIE_CORE_MASK | \
++ SOFTRESET_6318_PCIE_HARD_MASK)
++#define BCM6318_RESET_PCIE_EXT SOFTRESET_6318_PCIE_EXT_MASK
++
+ #define BCM6328_RESET_SPI SOFTRESET_6328_SPI_MASK
+ #define BCM6328_RESET_ENET 0
+ #define BCM6328_RESET_USBH SOFTRESET_6328_USBH_MASK
+@@ -147,6 +164,10 @@ static const u32 bcm3368_reset_bits[] =
+ __GEN_RESET_BITS_TABLE(3368)
+ };
+
++static const u32 bcm6318_reset_bits[] = {
++ __GEN_RESET_BITS_TABLE(6318)
++};
++
+ static const u32 bcm6328_reset_bits[] = {
+ __GEN_RESET_BITS_TABLE(6328)
+ };
+@@ -183,6 +204,9 @@ static int __init bcm63xx_reset_bits_ini
+ if (BCMCPU_IS_3368()) {
+ reset_reg = PERF_SOFTRESET_6358_REG;
+ bcm63xx_reset_bits = bcm3368_reset_bits;
++ } else if (BCMCPU_IS_6318()) {
++ reset_reg = PERF_SOFTRESET_6318_REG;
++ bcm63xx_reset_bits = bcm6318_reset_bits;
+ } else if (BCMCPU_IS_6328()) {
+ reset_reg = PERF_SOFTRESET_6328_REG;
+ bcm63xx_reset_bits = bcm6328_reset_bits;
+--- a/arch/mips/bcm63xx/setup.c
++++ b/arch/mips/bcm63xx/setup.c
+@@ -72,6 +72,9 @@ void bcm63xx_machine_reboot(void)
+ case BCM3368_CPU_ID:
+ perf_regs[0] = PERF_EXTIRQ_CFG_REG_3368;
+ break;
++ case BCM6318_CPU_ID:
++ perf_regs[0] = PERF_EXTIRQ_CFG_REG_6318;
++ break;
+ case BCM6328_CPU_ID:
+ perf_regs[0] = PERF_EXTIRQ_CFG_REG_6328;
+ break;
+@@ -111,7 +114,7 @@ void bcm63xx_machine_reboot(void)
+ bcm6348_a1_reboot();
+
+ pr_info("triggering watchdog soft-reset...\n");
+- if (BCMCPU_IS_6328()) {
++ if (BCMCPU_IS_6318() || BCMCPU_IS_6328()) {
+ bcm_wdt_writel(1, WDT_SOFTRESET_REG);
+ } else {
+ reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG);
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+@@ -10,6 +10,7 @@
+ * arm mach-types)
+ */
+ #define BCM3368_CPU_ID 0x3368
++#define BCM6318_CPU_ID 0x6318
+ #define BCM6328_CPU_ID 0x6328
+ #define BCM63281_CPU_ID 0x63281
+ #define BCM63283_CPU_ID 0x63283
+@@ -38,6 +39,10 @@ static inline u32 __pure __bcm63xx_get_c
+ case BCM3368_CPU_ID:
+ #endif
+
++#ifdef CONFIG_BCM63XX_CPU_6318
++ case BCM6318_CPU_ID:
++#endif
++
+ #ifdef CONFIG_BCM63XX_CPU_6328
+ case BCM6328_CPU_ID:
+ #endif
+@@ -87,6 +92,7 @@ static inline u32 __pure bcm63xx_get_cpu
+ }
+
+ #define BCMCPU_IS_3368() (bcm63xx_get_cpu_id() == BCM3368_CPU_ID)
++#define BCMCPU_IS_6318() (bcm63xx_get_cpu_id() == BCM6318_CPU_ID)
+ #define BCMCPU_IS_6328() (bcm63xx_get_cpu_id() == BCM6328_CPU_ID)
+ #define BCMCPU_IS_6338() (bcm63xx_get_cpu_id() == BCM6338_CPU_ID)
+ #define BCMCPU_IS_6345() (bcm63xx_get_cpu_id() == BCM6345_CPU_ID)
+@@ -98,6 +104,8 @@ static inline u32 __pure bcm63xx_get_cpu
+
+ #define BCMCPU_VARIANT_IS_3368() \
+ (bcm63xx_get_cpu_variant() == BCM3368_CPU_ID)
++#define BCMCPU_VARIANT_IS_6318() \
++ (bcm63xx_get_cpu_variant() == BCM6318_CPU_ID)
+ #define BCMCPU_VARIANT_IS_63281() \
+ (bcm63xx_get_cpu_variant() == BCM63281_CPU_ID)
+ #define BCMCPU_VARIANT_IS_63283() \
+@@ -252,6 +260,56 @@ enum bcm63xx_regs_set {
+ #define BCM_3368_MISC_BASE (0xdeadbeef)
+
+ /*
++ * 6318 register sets base address
++ */
++#define BCM_6318_DSL_LMEM_BASE (0xdeadbeef)
++#define BCM_6318_PERF_BASE (0xb0000000)
++#define BCM_6318_TIMER_BASE (0xb0000040)
++#define BCM_6318_WDT_BASE (0xb0000068)
++#define BCM_6318_UART0_BASE (0xb0000100)
++#define BCM_6318_UART1_BASE (0xdeadbeef)
++#define BCM_6318_GPIO_BASE (0xb0000080)
++#define BCM_6318_SPI_BASE (0xdeadbeef)
++#define BCM_6318_HSSPI_BASE (0xb0003000)
++#define BCM_6318_UDC0_BASE (0xdeadbeef)
++#define BCM_6318_USBDMA_BASE (0xb0006800)
++#define BCM_6318_OHCI0_BASE (0xb0005100)
++#define BCM_6318_OHCI_PRIV_BASE (0xdeadbeef)
++#define BCM_6318_USBH_PRIV_BASE (0xb0005200)
++#define BCM_6318_USBD_BASE (0xb0006000)
++#define BCM_6318_MPI_BASE (0xdeadbeef)
++#define BCM_6318_PCMCIA_BASE (0xdeadbeef)
++#define BCM_6318_PCIE_BASE (0xb0010000)
++#define BCM_6318_SDRAM_REGS_BASE (0xdeadbeef)
++#define BCM_6318_DSL_BASE (0xdeadbeef)
++#define BCM_6318_UBUS_BASE (0xdeadbeef)
++#define BCM_6318_ENET0_BASE (0xdeadbeef)
++#define BCM_6318_ENET1_BASE (0xdeadbeef)
++#define BCM_6318_ENETDMA_BASE (0xb0088000)
++#define BCM_6318_ENETDMAC_BASE (0xb0088200)
++#define BCM_6318_ENETDMAS_BASE (0xb0088400)
++#define BCM_6318_ENETSW_BASE (0xb0080000)
++#define BCM_6318_EHCI0_BASE (0xb0005000)
++#define BCM_6318_SDRAM_BASE (0xb0004000)
++#define BCM_6318_MEMC_BASE (0xdeadbeef)
++#define BCM_6318_DDR_BASE (0xdeadbeef)
++#define BCM_6318_M2M_BASE (0xdeadbeef)
++#define BCM_6318_ATM_BASE (0xdeadbeef)
++#define BCM_6318_XTM_BASE (0xdeadbeef)
++#define BCM_6318_XTMDMA_BASE (0xb000c000)
++#define BCM_6318_XTMDMAC_BASE (0xdeadbeef)
++#define BCM_6318_XTMDMAS_BASE (0xdeadbeef)
++#define BCM_6318_PCM_BASE (0xdeadbeef)
++#define BCM_6318_PCMDMA_BASE (0xdeadbeef)
++#define BCM_6318_PCMDMAC_BASE (0xdeadbeef)
++#define BCM_6318_PCMDMAS_BASE (0xdeadbeef)
++#define BCM_6318_RNG_BASE (0xdeadbeef)
++#define BCM_6318_MISC_BASE (0xb0000280)
++#define BCM_6318_OTP_BASE (0xdeadbeef)
++
++#define BCM_6318_STRAP_BASE (0xb0000900)
++
++/*
+ * 6328 register sets base address
+ */
+ #define BCM_6328_DSL_LMEM_BASE (0xdeadbeef)
+@@ -774,6 +832,55 @@ enum bcm63xx_irq {
+ #define BCM_3368_EXT_IRQ2 (IRQ_INTERNAL_BASE + 27)
+ #define BCM_3368_EXT_IRQ3 (IRQ_INTERNAL_BASE + 28)
+
++/*
++ * 6318 irqs
++ */
++#define BCM_6318_HIGH_IRQ_BASE (IRQ_INTERNAL_BASE + 32)
++#define BCM_6318_VERY_HIGH_IRQ_BASE (BCM_6318_HIGH_IRQ_BASE + 32)
++
++#define BCM_6318_TIMER_IRQ (IRQ_INTERNAL_BASE + 31)
++#define BCM_6318_SPI_IRQ 0
++#define BCM_6318_UART0_IRQ (IRQ_INTERNAL_BASE + 28)
++#define BCM_6318_UART1_IRQ 0
++#define BCM_6318_DSL_IRQ (IRQ_INTERNAL_BASE + 21)
++#define BCM_6318_UDC0_IRQ 0
++#define BCM_6318_ENET0_IRQ 0
++#define BCM_6318_ENET1_IRQ 0
++#define BCM_6318_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 12)
++#define BCM_6318_HSSPI_IRQ (IRQ_INTERNAL_BASE + 29)
++#define BCM_6318_OHCI0_IRQ (BCM_6318_HIGH_IRQ_BASE + 9)
++#define BCM_6318_EHCI0_IRQ (BCM_6318_HIGH_IRQ_BASE + 10)
++#define BCM_6318_USBD_IRQ (IRQ_INTERNAL_BASE + 4)
++#define BCM_6318_USBD_RXDMA0_IRQ (IRQ_INTERNAL_BASE + 5)
++#define BCM_6318_USBD_TXDMA0_IRQ (IRQ_INTERNAL_BASE + 6)
++#define BCM_6318_USBD_RXDMA1_IRQ (IRQ_INTERNAL_BASE + 7)
++#define BCM_6318_USBD_TXDMA1_IRQ (IRQ_INTERNAL_BASE + 8)
++#define BCM_6318_USBD_RXDMA2_IRQ (IRQ_INTERNAL_BASE + 9)
++#define BCM_6318_USBD_TXDMA2_IRQ (IRQ_INTERNAL_BASE + 10)
++#define BCM_6318_PCMCIA_IRQ 0
++#define BCM_6318_ENET0_RXDMA_IRQ 0
++#define BCM_6318_ENET0_TXDMA_IRQ 0
++#define BCM_6318_ENET1_RXDMA_IRQ 0
++#define BCM_6318_ENET1_TXDMA_IRQ 0
++#define BCM_6318_PCI_IRQ (IRQ_INTERNAL_BASE + 23)
++#define BCM_6318_ATM_IRQ 0
++#define BCM_6318_ENETSW_RXDMA0_IRQ (BCM_6318_HIGH_IRQ_BASE + 0)
++#define BCM_6318_ENETSW_RXDMA1_IRQ (BCM_6318_HIGH_IRQ_BASE + 1)
++#define BCM_6318_ENETSW_RXDMA2_IRQ (BCM_6318_HIGH_IRQ_BASE + 2)
++#define BCM_6318_ENETSW_RXDMA3_IRQ (BCM_6318_HIGH_IRQ_BASE + 3)
++#define BCM_6318_ENETSW_TXDMA0_IRQ (BCM_6318_VERY_HIGH_IRQ_BASE + 10)
++#define BCM_6318_ENETSW_TXDMA1_IRQ (BCM_6318_VERY_HIGH_IRQ_BASE + 11)
++#define BCM_6318_ENETSW_TXDMA2_IRQ (BCM_6318_VERY_HIGH_IRQ_BASE + 12)
++#define BCM_6318_ENETSW_TXDMA3_IRQ (BCM_6318_VERY_HIGH_IRQ_BASE + 13)
++#define BCM_6318_XTM_IRQ (BCM_6318_HIGH_IRQ_BASE + 31)
++#define BCM_6318_XTM_DMA0_IRQ (BCM_6318_HIGH_IRQ_BASE + 11)
++
++#define BCM_6318_PCM_DMA0_IRQ (IRQ_INTERNAL_BASE + 2)
++#define BCM_6318_PCM_DMA1_IRQ (IRQ_INTERNAL_BASE + 3)
++#define BCM_6318_EXT_IRQ0 (IRQ_INTERNAL_BASE + 24)
++#define BCM_6318_EXT_IRQ1 (IRQ_INTERNAL_BASE + 25)
++#define BCM_6318_EXT_IRQ2 (IRQ_INTERNAL_BASE + 26)
++#define BCM_6318_EXT_IRQ3 (IRQ_INTERNAL_BASE + 27)
+
+ /*
+ * 6328 irqs
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+@@ -52,6 +52,39 @@
+ CKCTL_3368_EMUSB_EN | \
+ CKCTL_3368_USBU_EN)
+
++#define CKCTL_6318_ADSL_ASB_EN (1 << 0)
++#define CKCTL_6318_USB_ASB_EN (1 << 1)
++#define CKCTL_6318_MIPS_ASB_EN (1 << 2)
++#define CKCTL_6318_PCIE_ASB_EN (1 << 3)
++#define CKCTL_6318_PHYMIPS_ASB_EN (1 << 4)
++#define CKCTL_6318_ROBOSW_ASB_EN (1 << 5)
++#define CKCTL_6318_SAR_ASB_EN (1 << 6)
++#define CKCTL_6318_SDR_ASB_EN (1 << 7)
++#define CKCTL_6318_SWREG_ASB_EN (1 << 8)
++#define CKCTL_6318_PERIPH_ASB_EN (1 << 9)
++#define CKCTL_6318_CPUBUS160_EN (1 << 10)
++#define CKCTL_6318_ADSL_EN (1 << 11)
++#define CKCTL_6318_SAR125_EN (1 << 12)
++#define CKCTL_6318_MIPS_EN (1 << 13)
++#define CKCTL_6318_PCIE_EN (1 << 14)
++#define CKCTL_6318_ROBOSW250_EN (1 << 16)
++#define CKCTL_6318_ROBOSW025_EN (1 << 17)
++#define CKCTL_6318_SDR_EN (1 << 19)
++#define CKCTL_6318_USB_EN (1 << 20) /* both device and host */
++#define CKCTL_6318_HSSPI_EN (1 << 25)
++#define CKCTL_6318_PCIE25_EN (1 << 27)
++#define CKCTL_6318_PHYMIPS_EN (1 << 28)
++#define CKCTL_6318_ADSL_AFE_EN (1 << 29)
++#define CKCTL_6318_ADSL_QPROC_EN (1 << 30)
++
++#define CKCTL_6318_ALL_SAFE_EN (CKCTL_6318_PHYMIPS_EN | \
++ CKCTL_6318_ADSL_QPROC_EN | \
++ CKCTL_6318_ADSL_AFE_EN | \
++ CKCTL_6318_ADSL_EN | \
++ CKCTL_6318_SAR_EN | \
++ CKCTL_6318_USB_EN | \
++ CKCTL_6318_PCIE_EN)
++
+ #define CKCTL_6328_PHYMIPS_EN (1 << 0)
+ #define CKCTL_6328_ADSL_QPROC_EN (1 << 1)
+ #define CKCTL_6328_ADSL_AFE_EN (1 << 2)
+@@ -259,12 +292,27 @@
+ CKCTL_63268_TBUS_EN | \
+ CKCTL_63268_ROBOSW250_EN)
+
++/* UBUS Clock Control register */
++#define PERF_UB_CKCTL_REG 0x10
++
++#define UB_CKCTL_6318_ADSL_EN (1 << 0)
++#define UB_CKCTL_6318_ARB_EN (1 << 1)
++#define UB_CKCTL_6318_MIPS_EN (1 << 2)
++#define UB_CKCTL_6318_PCIE_EN (1 << 3)
++#define UB_CKCTL_6318_PERIPH_EN (1 << 4)
++#define UB_CKCTL_6318_PHYMIPS_EN (1 << 5)
++#define UB_CKCTL_6318_ROBOSW_EN (1 << 6)
++#define UB_CKCTL_6318_SAR_EN (1 << 7)
++#define UB_CKCTL_6318_SDR_EN (1 << 8)
++#define UB_CKCTL_6318_USB_EN (1 << 9)
++
+ /* System PLL Control register */
+ #define PERF_SYS_PLL_CTL_REG 0x8
+ #define SYS_PLL_SOFT_RESET 0x1
+
+ /* Interrupt Mask register */
+ #define PERF_IRQMASK_3368_REG 0xc
++#define PERF_IRQMASK_6318_REG 0x20
+ #define PERF_IRQMASK_6328_REG(x) (0x20 + (x) * 0x10)
+ #define PERF_IRQMASK_6338_REG 0xc
+ #define PERF_IRQMASK_6345_REG 0xc
+@@ -276,6 +324,7 @@
+
+ /* Interrupt Status register */
+ #define PERF_IRQSTAT_3368_REG 0x10
++#define PERF_IRQSTAT_6318_REG 0x30
+ #define PERF_IRQSTAT_6328_REG(x) (0x28 + (x) * 0x10)
+ #define PERF_IRQSTAT_6338_REG 0x10
+ #define PERF_IRQSTAT_6345_REG 0x10
+@@ -287,6 +336,7 @@
+
+ /* External Interrupt Configuration register */
+ #define PERF_EXTIRQ_CFG_REG_3368 0x14
++#define PERF_EXTIRQ_CFG_REG_6318 0x18
+ #define PERF_EXTIRQ_CFG_REG_6328 0x18
+ #define PERF_EXTIRQ_CFG_REG_6338 0x14
+ #define PERF_EXTIRQ_CFG_REG_6345 0x14
+@@ -321,6 +371,7 @@
+
+ /* Soft Reset register */
+ #define PERF_SOFTRESET_REG 0x28
++#define PERF_SOFTRESET_6318_REG 0x10
+ #define PERF_SOFTRESET_6328_REG 0x10
+ #define PERF_SOFTRESET_6358_REG 0x34
+ #define PERF_SOFTRESET_6362_REG 0x10
+@@ -334,6 +385,18 @@
+ #define SOFTRESET_3368_USBS_MASK (1 << 11)
+ #define SOFTRESET_3368_PCM_MASK (1 << 13)
+
++#define SOFTRESET_6318_SPI_MASK (1 << 0)
++#define SOFTRESET_6318_EPHY_MASK (1 << 1)
++#define SOFTRESET_6318_SAR_MASK (1 << 2)
++#define SOFTRESET_6318_ENETSW_MASK (1 << 3)
++#define SOFTRESET_6318_USBS_MASK (1 << 4)
++#define SOFTRESET_6318_USBH_MASK (1 << 5)
++#define SOFTRESET_6318_PCIE_CORE_MASK (1 << 6)
++#define SOFTRESET_6318_PCIE_MASK (1 << 7)
++#define SOFTRESET_6318_PCIE_EXT_MASK (1 << 8)
++#define SOFTRESET_6318_PCIE_HARD_MASK (1 << 9)
++#define SOFTRESET_6318_ADSL_MASK (1 << 10)
++
+ #define SOFTRESET_6328_SPI_MASK (1 << 0)
+ #define SOFTRESET_6328_EPHY_MASK (1 << 1)
+ #define SOFTRESET_6328_SAR_MASK (1 << 2)
+@@ -505,8 +568,17 @@
+ #define TIMER_IRQSTAT_TIMER1_IR_EN (1 << 9)
+ #define TIMER_IRQSTAT_TIMER2_IR_EN (1 << 10)
+
++#define TIMER_IRQMASK_6318_REG 0x0
++#define TIMER_IRQSTAT_6318_REG 0x4
++#define IRQSTATMASK_TIMER0 (1 << 0)
++#define IRQSTATMASK_TIMER1 (1 << 1)
++#define IRQSTATMASK_TIMER2 (1 << 2)
++#define IRQSTATMASK_TIMER3 (1 << 3)
++#define IRQSTATMASK_WDT (1 << 4)
++
+ /* Timer control register */
+ #define TIMER_CTLx_REG(x) (0x4 + (x * 4))
++#define TIMER_CTRx_6318_REG(x) (0x8 + (x * 4))
+ #define TIMER_CTL0_REG 0x4
+ #define TIMER_CTL1_REG 0x8
+ #define TIMER_CTL2_REG 0xC
+@@ -1253,6 +1325,8 @@
+ #define SDRAM_CFG_32B_MASK (1 << SDRAM_CFG_32B_SHIFT)
+ #define SDRAM_CFG_BANK_SHIFT 13
+ #define SDRAM_CFG_BANK_MASK (1 << SDRAM_CFG_BANK_SHIFT)
++#define SDRAM_CFG_6318_SPACE_SHIFT 4
++#define SDRAM_CFG_6318_SPACE_MASK (0xf << SDRAM_CFG_6318_SPACE_SHIFT)
+
+ #define SDRAM_MBASE_REG 0xc
+
+--- a/arch/mips/include/asm/mach-bcm63xx/ioremap.h
++++ b/arch/mips/include/asm/mach-bcm63xx/ioremap.h
+@@ -22,6 +22,7 @@ static inline int is_bcm63xx_internal_re
+ if (offset >= 0xfff00000)
+ return 1;
+ break;
++ case BCM6318_CPU_ID:
+ case BCM6328_CPU_ID:
+ case BCM6362_CPU_ID:
+ case BCM6368_CPU_ID:
+--- a/arch/mips/bcm63xx/dev-hsspi.c
++++ b/arch/mips/bcm63xx/dev-hsspi.c
+@@ -35,7 +35,8 @@ static struct platform_device bcm63xx_hs
+
+ int __init bcm63xx_hsspi_register(void)
+ {
+- if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_63268())
++ if (!BCMCPU_IS_6318() && !BCMCPU_IS_6328() && !BCMCPU_IS_6362() &&
++ !BCMCPU_IS_63268())
+ return -ENODEV;
+
+ spi_resources[0].start = bcm63xx_regset_address(RSET_HSSPI);
+--- a/arch/mips/bcm63xx/dev-usb-usbd.c
++++ b/arch/mips/bcm63xx/dev-usb-usbd.c
+@@ -41,7 +41,7 @@ int __init bcm63xx_usbd_register(const s
+ IRQ_USBD_RXDMA2, IRQ_USBD_TXDMA2 };
+ int i;
+
+- if (!BCMCPU_IS_6328() && !BCMCPU_IS_6368())
++ if (!BCMCPU_IS_6318() && !BCMCPU_IS_6328() && !BCMCPU_IS_6368())
+ return 0;
+
+ usbd_resources[0].start = bcm63xx_regset_address(RSET_USBD);
+--- a/arch/mips/bcm63xx/dev-enet.c
++++ b/arch/mips/bcm63xx/dev-enet.c
+@@ -176,8 +176,8 @@ static int __init register_shared(void)
+ else
+ shared_res[0].end += (RSET_ENETDMA_SIZE) - 1;
+
+- if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368() ||
+- BCMCPU_IS_63268())
++ if (BCMCPU_IS_6318() || BCMCPU_IS_6328() || BCMCPU_IS_6362() ||
++ BCMCPU_IS_6368() || BCMCPU_IS_63268())
+ chan_count = 32;
+ else if (BCMCPU_IS_6345())
+ chan_count = 8;
+@@ -277,8 +277,8 @@ bcm63xx_enetsw_register(const struct bcm
+ {
+ int ret;
+
+- if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368() &&
+- !BCMCPU_IS_63268())
++ if (!BCMCPU_IS_6318() && !BCMCPU_IS_6328() && !BCMCPU_IS_6362() &&
++ !BCMCPU_IS_6368() && !BCMCPU_IS_63268())
+ return -ENODEV;
+
+ ret = register_shared();
+@@ -295,7 +295,7 @@ bcm63xx_enetsw_register(const struct bcm
+
+ memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd));
+
+- if (BCMCPU_IS_6328())
++ if (BCMCPU_IS_6318() || BCMCPU_IS_6328())
+ enetsw_pd.num_ports = ENETSW_PORTS_6328;
+ else if (BCMCPU_IS_6362() || BCMCPU_IS_6368())
+ enetsw_pd.num_ports = ENETSW_PORTS_6368;
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
+@@ -9,6 +9,8 @@ int __init bcm63xx_gpio_init(void);
+ static inline unsigned long bcm63xx_gpio_count(void)
+ {
+ switch (bcm63xx_get_cpu_id()) {
++ case BCM6318_CPU_ID:
++ return 50;
+ case BCM6328_CPU_ID:
+ return 32;
+ case BCM3368_CPU_ID:
+--- a/arch/mips/bcm63xx/dev-usb-ehci.c
++++ b/arch/mips/bcm63xx/dev-usb-ehci.c
+@@ -81,7 +81,8 @@ static struct platform_device bcm63xx_eh
+
+ int __init bcm63xx_ehci_register(void)
+ {
+- if (!BCMCPU_IS_6328() && !BCMCPU_IS_6358() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
++ if (!BCMCPU_IS_6318() && !BCMCPU_IS_6328() && !BCMCPU_IS_6358() &&
++ !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
+ return 0;
+
+ ehci_resources[0].start = bcm63xx_regset_address(RSET_EHCI0);
--- /dev/null
+From 4bdfacdeaf3c988c4f3256c88118893eac640b03 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 8 Dec 2013 14:17:50 +0100
+Subject: [PATCH 52/53] MIPS: BCM63XX: split PCIE reset signals
+
+---
+ arch/mips/bcm63xx/reset.c | 39 ++++++++++++++--------
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_reset.h | 2 ++
+ arch/mips/pci/pci-bcm63xx.c | 7 ++++
+ 3 files changed, 34 insertions(+), 14 deletions(-)
+
+--- a/arch/mips/bcm63xx/reset.c
++++ b/arch/mips/bcm63xx/reset.c
+@@ -28,7 +28,9 @@
+ [BCM63XX_RESET_PCM] = BCM## __cpu ##_RESET_PCM, \
+ [BCM63XX_RESET_MPI] = BCM## __cpu ##_RESET_MPI, \
+ [BCM63XX_RESET_PCIE] = BCM## __cpu ##_RESET_PCIE, \
+- [BCM63XX_RESET_PCIE_EXT] = BCM## __cpu ##_RESET_PCIE_EXT,
++ [BCM63XX_RESET_PCIE_EXT] = BCM## __cpu ##_RESET_PCIE_EXT, \
++ [BCM63XX_RESET_PCIE_CORE] = BCM## __cpu ##_RESET_PCIE_CORE, \
++ [BCM63XX_RESET_PCIE_HARD] = BCM## __cpu ##_RESET_PCIE_HARD,
+
+ #define BCM3368_RESET_SPI SOFTRESET_3368_SPI_MASK
+ #define BCM3368_RESET_ENET SOFTRESET_3368_ENET_MASK
+@@ -42,6 +44,8 @@
+ #define BCM3368_RESET_MPI SOFTRESET_3368_MPI_MASK
+ #define BCM3368_RESET_PCIE 0
+ #define BCM3368_RESET_PCIE_EXT 0
++#define BCM3368_RESET_PCIE_CORE 0
++#define BCM3368_RESET_PCIE_HARD 0
+
+
+ #define BCM6318_RESET_SPI SOFTRESET_6318_SPI_MASK
+@@ -54,11 +58,10 @@
+ #define BCM6318_RESET_ENETSW SOFTRESET_6318_ENETSW_MASK
+ #define BCM6318_RESET_PCM 0
+ #define BCM6318_RESET_MPI 0
+-#define BCM6318_RESET_PCIE \
+- (SOFTRESET_6318_PCIE_MASK | \
+- SOFTRESET_6318_PCIE_CORE_MASK | \
+- SOFTRESET_6318_PCIE_HARD_MASK)
++#define BCM6318_RESET_PCIE SOFTRESET_6318_PCIE_MASK
+ #define BCM6318_RESET_PCIE_EXT SOFTRESET_6318_PCIE_EXT_MASK
++#define BCM6318_RESET_PCIE_CORE SOFTRESET_6318_PCIE_CORE_MASK
++#define BCM6318_RESET_PCIE_HARD SOFTRESET_6318_PCIE_HARD_MASK
+
+ #define BCM6328_RESET_SPI SOFTRESET_6328_SPI_MASK
+ #define BCM6328_RESET_ENET 0
+@@ -70,11 +73,10 @@
+ #define BCM6328_RESET_ENETSW SOFTRESET_6328_ENETSW_MASK
+ #define BCM6328_RESET_PCM SOFTRESET_6328_PCM_MASK
+ #define BCM6328_RESET_MPI 0
+-#define BCM6328_RESET_PCIE \
+- (SOFTRESET_6328_PCIE_MASK | \
+- SOFTRESET_6328_PCIE_CORE_MASK | \
+- SOFTRESET_6328_PCIE_HARD_MASK)
++#define BCM6328_RESET_PCIE SOFTRESET_6328_PCIE_MASK
+ #define BCM6328_RESET_PCIE_EXT SOFTRESET_6328_PCIE_EXT_MASK
++#define BCM6328_RESET_PCIE_CORE SOFTRESET_6328_PCIE_CORE_MASK
++#define BCM6328_RESET_PCIE_HARD SOFTRESET_6328_PCIE_HARD_MASK
+
+ #define BCM6338_RESET_SPI SOFTRESET_6338_SPI_MASK
+ #define BCM6338_RESET_ENET SOFTRESET_6338_ENET_MASK
+@@ -88,6 +90,8 @@
+ #define BCM6338_RESET_MPI 0
+ #define BCM6338_RESET_PCIE 0
+ #define BCM6338_RESET_PCIE_EXT 0
++#define BCM6338_RESET_PCIE_CORE 0
++#define BCM6338_RESET_PCIE_HARD 0
+
+ #define BCM6348_RESET_SPI SOFTRESET_6348_SPI_MASK
+ #define BCM6348_RESET_ENET SOFTRESET_6348_ENET_MASK
+@@ -101,6 +105,8 @@
+ #define BCM6348_RESET_MPI 0
+ #define BCM6348_RESET_PCIE 0
+ #define BCM6348_RESET_PCIE_EXT 0
++#define BCM6348_RESET_PCIE_CORE 0
++#define BCM6348_RESET_PCIE_HARD 0
+
+ #define BCM6358_RESET_SPI SOFTRESET_6358_SPI_MASK
+ #define BCM6358_RESET_ENET SOFTRESET_6358_ENET_MASK
+@@ -114,6 +120,8 @@
+ #define BCM6358_RESET_MPI SOFTRESET_6358_MPI_MASK
+ #define BCM6358_RESET_PCIE 0
+ #define BCM6358_RESET_PCIE_EXT 0
++#define BCM6358_RESET_PCIE_CORE 0
++#define BCM6358_RESET_PCIE_HARD 0
+
+ #define BCM6362_RESET_SPI SOFTRESET_6362_SPI_MASK
+ #define BCM6362_RESET_ENET 0
+@@ -125,9 +133,10 @@
+ #define BCM6362_RESET_ENETSW SOFTRESET_6362_ENETSW_MASK
+ #define BCM6362_RESET_PCM SOFTRESET_6362_PCM_MASK
+ #define BCM6362_RESET_MPI 0
+-#define BCM6362_RESET_PCIE (SOFTRESET_6362_PCIE_MASK | \
+- SOFTRESET_6362_PCIE_CORE_MASK)
++#define BCM6362_RESET_PCIE SOFTRESET_6362_PCIE_MASK
+ #define BCM6362_RESET_PCIE_EXT SOFTRESET_6362_PCIE_EXT_MASK
++#define BCM6362_RESET_PCIE_CORE SOFTRESET_6362_PCIE_CORE_MASK
++#define BCM6362_RESET_PCIE_HARD 0
+
+ #define BCM6368_RESET_SPI SOFTRESET_6368_SPI_MASK
+ #define BCM6368_RESET_ENET 0
+@@ -141,6 +150,8 @@
+ #define BCM6368_RESET_MPI SOFTRESET_6368_MPI_MASK
+ #define BCM6368_RESET_PCIE 0
+ #define BCM6368_RESET_PCIE_EXT 0
++#define BCM6368_RESET_PCIE_CORE 0
++#define BCM6368_RESET_PCIE_HARD 0
+
+ #define BCM63268_RESET_SPI SOFTRESET_63268_SPI_MASK
+ #define BCM63268_RESET_ENET 0
+@@ -152,10 +163,10 @@
+ #define BCM63268_RESET_ENETSW SOFTRESET_63268_ENETSW_MASK
+ #define BCM63268_RESET_PCM SOFTRESET_63268_PCM_MASK
+ #define BCM63268_RESET_MPI 0
+-#define BCM63268_RESET_PCIE (SOFTRESET_63268_PCIE_MASK | \
+- SOFTRESET_63268_PCIE_CORE_MASK | \
+- SOFTRESET_63268_PCIE_HARD_MASK)
++#define BCM63268_RESET_PCIE SOFTRESET_63268_PCIE_MASK
+ #define BCM63268_RESET_PCIE_EXT SOFTRESET_63268_PCIE_EXT_MASK
++#define BCM63268_RESET_PCIE_CORE SOFTRESET_63268_PCIE_CORE_MASK
++#define BCM63268_RESET_PCIE_HARD SOFTRESET_63268_PCIE_HARD_MASK
+
+ /*
+ * core reset bits
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_reset.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_reset.h
+@@ -14,6 +14,8 @@ enum bcm63xx_core_reset {
+ BCM63XX_RESET_MPI,
+ BCM63XX_RESET_PCIE,
+ BCM63XX_RESET_PCIE_EXT,
++ BCM63XX_RESET_PCIE_CORE,
++ BCM63XX_RESET_PCIE_HARD,
+ };
+
+ void bcm63xx_core_set_reset(enum bcm63xx_core_reset, int reset);
+--- a/arch/mips/pci/pci-bcm63xx.c
++++ b/arch/mips/pci/pci-bcm63xx.c
+@@ -135,9 +135,16 @@ static void __init bcm63xx_reset_pcie(vo
+
+ /* reset the PCIe core */
+ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE, 1);
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_CORE, 1);
+ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_EXT, 1);
++ if (BCMCPU_IS_6328() || BCMCPU_IS_63268()) {
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_HARD, 1);
++ mdelay(10);
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_HARD, 0);
++ }
+ mdelay(10);
+
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_CORE, 0);
+ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE, 0);
+ mdelay(10);
+
--- /dev/null
+From 11a8ab8dac4ef5d0d70199843043927edce1d4db Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 15 Dec 2013 20:47:34 +0100
+Subject: [PATCH 53/53] MIPS: BCM63XX: add PCIe support for BCM6318
+
+---
+ arch/mips/bcm63xx/clk.c | 25 ++++-
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h | 6 ++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 60 +++++++++++-
+ arch/mips/pci/ops-bcm63xx.c | 16 +++-
+ arch/mips/pci/pci-bcm63xx.c | 106 ++++++++++++++++++----
+ 5 files changed, 184 insertions(+), 29 deletions(-)
+
+--- a/arch/mips/bcm63xx/clk.c
++++ b/arch/mips/bcm63xx/clk.c
+@@ -50,6 +50,18 @@ static void bcm_hwclock_set(u32 mask, in
+ bcm_perf_writel(reg, PERF_CKCTL_REG);
+ }
+
++static void bcm_ub_hwclock_set(u32 mask, int enable)
++{
++ u32 reg;
++
++ reg = bcm_perf_readl(PERF_UB_CKCTL_REG);
++ if (enable)
++ reg |= mask;
++ else
++ reg &= ~mask;
++ bcm_perf_writel(reg, PERF_UB_CKCTL_REG);
++}
++
+ /*
+ * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
+ */
+@@ -317,12 +329,17 @@ static struct clk clk_ipsec = {
+
+ static void pcie_set(struct clk *clk, int enable)
+ {
+- if (BCMCPU_IS_6328())
++ if (BCMCPU_IS_6318()) {
++ bcm_hwclock_set(CKCTL_6318_PCIE_EN, enable);
++ bcm_hwclock_set(CKCTL_6318_PCIE25_EN, enable);
++ bcm_ub_hwclock_set(UB_CKCTL_6318_PCIE_EN, enable);
++ } else if (BCMCPU_IS_6328()) {
+ bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
+- else if (BCMCPU_IS_6362())
++ } else if (BCMCPU_IS_6362()) {
+ bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable);
+- else if (BCMCPU_IS_63268())
++ } else if (BCMCPU_IS_63268()) {
+ bcm_hwclock_set(CKCTL_63268_PCIE_EN, enable);
++ }
+ }
+
+ static struct clk clk_pcie = {
+@@ -405,7 +422,7 @@ struct clk *clk_get(struct device *dev,
+ if ((BCMCPU_IS_6362() || BCMCPU_IS_6368() || BCMCPU_IS_63268()) &&
+ !strcmp(id, "ipsec"))
+ return &clk_ipsec;
+- if ((BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_63268()) &&
++ if ((BCMCPU_IS_6318() || BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_63268()) &&
+ !strcmp(id, "pcie"))
+ return &clk_pcie;
+ return ERR_PTR(-ENOENT);
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
+@@ -40,6 +40,12 @@
+ #define BCM_CB_MEM_END_PA (BCM_CB_MEM_BASE_PA + \
+ BCM_CB_MEM_SIZE - 1)
+
++#define BCM_PCIE_MEM_BASE_PA_6318 0x10200000
++#define BCM_PCIE_MEM_SIZE_6318 (1 * 1024 * 1024)
++#define BCM_PCIE_MEM_END_PA_6318 (BCM_PCIE_MEM_BASE_PA_6318 + \
++ BCM_PCIE_MEM_SIZE_6318 - 1)
++
++
+ #define BCM_PCIE_MEM_BASE_PA_6328 0x10f00000
+ #define BCM_PCIE_MEM_SIZE_6328 (1 * 1024 * 1024)
+ #define BCM_PCIE_MEM_END_PA_6328 (BCM_PCIE_MEM_BASE_PA_6328 + \
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+@@ -1529,6 +1529,17 @@
+ * _REG relative to RSET_PCIE
+ *************************************************************************/
+
++#define PCIE_SPECIFIC_REG 0x188
++#define SPECIFIC_ENDIAN_MODE_BAR1_SHIFT 0
++#define SPECIFIC_ENDIAN_MODE_BAR1_MASK (0x3 << SPECIFIC_ENDIAN_MODE_BAR1_SHIFT)
++#define SPECIFIC_ENDIAN_MODE_BAR2_SHIFT 2
++#define SPECIFIC_ENDIAN_MODE_BAR2_MASK (0x3 << SPECIFIC_ENDIAN_MODE_BAR1_SHIFT)
++#define SPECIFIC_ENDIAN_MODE_BAR3_SHIFT 4
++#define SPECIFIC_ENDIAN_MODE_BAR3_MASK (0x3 << SPECIFIC_ENDIAN_MODE_BAR1_SHIFT)
++#define SPECIFIC_ENDIAN_MODE_WORD_ALIGN 0
++#define SPECIFIC_ENDIAN_MODE_HALFWORD_ALIGN 1
++#define SPECIFIC_ENDIAN_MODE_BYTE_ALIGN 2
++
+ #define PCIE_CONFIG2_REG 0x408
+ #define CONFIG2_BAR1_SIZE_EN 1
+ #define CONFIG2_BAR1_SIZE_MASK 0xf
+@@ -1574,7 +1585,54 @@
+ #define PCIE_RC_INT_C (1 << 2)
+ #define PCIE_RC_INT_D (1 << 3)
+
+-#define PCIE_DEVICE_OFFSET 0x8000
++#define PCIE_CPU_2_PCIE_MEM_WIN0_LO_REG 0x400c
++#define C2P_MEM_WIN_ENDIAN_MODE_MASK 0x3
++#define C2P_MEM_WIN_ENDIAN_NO_SWAP 0
++#define C2P_MEM_WIN_ENDIAN_HALF_WORD_SWAP 1
++#define C2P_MEM_WIN_ENDIAN_HALF_BYTE_SWAP 2
++#define C2P_MEM_WIN_BASE_ADDR_SHIFT 20
++#define C2P_MEM_WIN_BASE_ADDR_MASK (0xfff << C2P_MEM_WIN_BASE_ADDR_SHIFT)
++
++#define PCIE_RC_BAR1_CONFIG_LO_REG 0x402c
++#define RC_BAR_CFG_LO_SIZE_256MB 0xd
++#define RC_BAR_CFG_LO_MATCH_ADDR_SHIFT 20
++#define RC_BAR_CFG_LO_MATCH_ADDR_MASK (0xfff << RC_BAR_CFG_LO_MATCH_ADDR_SHIFT)
++
++#define PCIE_CPU_2_PCIE_MEM_WIN0_BASELIMIT_REG 0x4070
++#define C2P_BASELIMIT_LIMIT_SHIFT 20
++#define C2P_BASELIMIT_LIMIT_MASK (0xfff << C2P_BASELIMIT_LIMIT_SHIFT)
++#define C2P_BASELIMIT_BASE_SHIFT 4
++#define C2P_BASELIMIT_BASE_MASK (0xfff << C2P_BASELIMIT_BASE_SHIFT)
++
++#define PCIE_UBUS_BAR1_CFG_REMAP_REG 0x4088
++#define BAR1_CFG_REMAP_OFFSET_SHIFT 20
++#define BAR1_CFG_REMAP_OFFSET_MASK (0xfff << BAR1_CFG_REMAP_OFFSET_SHIFT)
++#define BAR1_CFG_REMAP_ACCESS_EN 1
++
++#define PCIE_HARD_DEBUG_REG 0x4204
++#define HARD_DEBUG_SERDES_IDDQ (1 << 23)
++
++#define PCIE_CPU_INT1_MASK_CLEAR_REG 0x830c
++#define CPU_INT_PCIE_ERR_ATTN_CPU (1 << 0)
++#define CPU_INT_PCIE_INTA (1 << 1)
++#define CPU_INT_PCIE_INTB (1 << 2)
++#define CPU_INT_PCIE_INTC (1 << 3)
++#define CPU_INT_PCIE_INTD (1 << 4)
++#define CPU_INT_PCIE_INTR (1 << 5)
++#define CPU_INT_PCIE_NMI (1 << 6)
++#define CPU_INT_PCIE_UBUS (1 << 7)
++#define CPU_INT_IPI (1 << 8)
++
++#define PCIE_EXT_CFG_INDEX_REG 0x8400
++#define EXT_CFG_FUNC_NUM_SHIFT 12
++#define EXT_CFG_FUNC_NUM_MASK (0x7 << EXT_CFG_FUNC_NUM_SHIFT)
++#define EXT_CFG_DEV_NUM_SHIFT 15
++#define EXT_CFG_DEV_NUM_MASK (0xf << EXT_CFG_DEV_NUM_SHIFT)
++#define EXT_CFG_BUS_NUM_SHIFT 20
++#define EXT_CFG_BUS_NUM_MASK (0xff << EXT_CFG_BUS_NUM_SHIFT)
++
++#define PCIE_DEVICE_OFFSET_6318 0x9000
++#define PCIE_DEVICE_OFFSET_6328 0x8000
+
+ /*************************************************************************
+ * _REG relative to RSET_OTP
+--- a/arch/mips/pci/ops-bcm63xx.c
++++ b/arch/mips/pci/ops-bcm63xx.c
+@@ -488,8 +488,12 @@ static int bcm63xx_pcie_read(struct pci_
+ if (!bcm63xx_pcie_can_access(bus, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+- if (bus->number == PCIE_BUS_DEVICE)
+- reg += PCIE_DEVICE_OFFSET;
++ if (bus->number == PCIE_BUS_DEVICE) {
++ if (BCMCPU_IS_6318())
++ reg += PCIE_DEVICE_OFFSET_6318;
++ else
++ reg += PCIE_DEVICE_OFFSET_6328;
++ }
+
+ data = bcm_pcie_readl(reg);
+
+@@ -508,8 +512,12 @@ static int bcm63xx_pcie_write(struct pci
+ if (!bcm63xx_pcie_can_access(bus, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+- if (bus->number == PCIE_BUS_DEVICE)
+- reg += PCIE_DEVICE_OFFSET;
++ if (bus->number == PCIE_BUS_DEVICE) {
++ if (BCMCPU_IS_6318())
++ reg += PCIE_DEVICE_OFFSET_6318;
++ else
++ reg += PCIE_DEVICE_OFFSET_6328;
++ }
+
+
+ data = bcm_pcie_readl(reg);
+--- a/arch/mips/pci/pci-bcm63xx.c
++++ b/arch/mips/pci/pci-bcm63xx.c
+@@ -118,7 +118,7 @@ static void bcm63xx_int_cfg_writel(u32 v
+
+ void __iomem *pci_iospace_start;
+
+-static void __init bcm63xx_reset_pcie(void)
++static void __init bcm63xx_reset_pcie_gen1(void)
+ {
+ u32 val;
+ u32 reg;
+@@ -152,20 +152,32 @@ static void __init bcm63xx_reset_pcie(vo
+ mdelay(200);
+ }
+
+-static struct clk *pcie_clk;
+-
+-static int __init bcm63xx_register_pcie(void)
++static void __init bcm63xx_reset_pcie_gen2(void)
+ {
+ u32 val;
+
+- /* enable clock */
+- pcie_clk = clk_get(NULL, "pcie");
+- if (IS_ERR_OR_NULL(pcie_clk))
+- return -ENODEV;
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_HARD, 0);
+
+- clk_prepare_enable(pcie_clk);
++ /* reset the PCIe core */
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE, 1);
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_EXT, 1);
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_CORE, 1);
++ mdelay(10);
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_EXT, 0);
++ mdelay(10);
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE, 0);
++ mdelay(10);
++ val = bcm_pcie_readl(PCIE_HARD_DEBUG_REG);
++ val &= ~HARD_DEBUG_SERDES_IDDQ;
++ bcm_pcie_writel(val, PCIE_HARD_DEBUG_REG);
++ mdelay(10);
++ bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_CORE, 0);
++ mdelay(200);
++}
+
+- bcm63xx_reset_pcie();
++static void __init bcm63xx_init_pcie_gen1(void)
++{
++ u32 val;
+
+ /* configure the PCIe bridge */
+ val = bcm_pcie_readl(PCIE_BRIDGE_OPT1_REG);
+@@ -190,6 +202,65 @@ static int __init bcm63xx_register_pcie(
+ val |= OPT2_CFG_TYPE1_BD_SEL;
+ bcm_pcie_writel(val, PCIE_BRIDGE_OPT2_REG);
+
++ /* set bar0 to little endian */
++ val = (bcm_pcie_mem_resource.start >> 20) << BASEMASK_BASE_SHIFT;
++ val |= (bcm_pcie_mem_resource.end >> 20) << BASEMASK_MASK_SHIFT;
++ val |= BASEMASK_REMAP_EN;
++ bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG);
++
++ val = (bcm_pcie_mem_resource.start >> 20) << REBASE_ADDR_BASE_SHIFT;
++ bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG);
++}
++
++static void __init bcm63xx_init_pcie_gen2(void)
++{
++ u32 val;
++
++ bcm_pcie_writel(CPU_INT_PCIE_INTA | CPU_INT_PCIE_INTB |
++ CPU_INT_PCIE_INTC | CPU_INT_PCIE_INTD,
++ PCIE_CPU_INT1_MASK_CLEAR_REG);
++
++ val = bcm_pcie_mem_resource.end & C2P_BASELIMIT_LIMIT_MASK;
++ val |= (bcm_pcie_mem_resource.start >> C2P_BASELIMIT_LIMIT_SHIFT) <<
++ C2P_BASELIMIT_BASE_SHIFT;
++
++ bcm_pcie_writel(val, PCIE_CPU_2_PCIE_MEM_WIN0_BASELIMIT_REG);
++
++ /* set bar0 to little endian */
++ val = bcm_pcie_readl(PCIE_CPU_2_PCIE_MEM_WIN0_LO_REG);
++ val |= bcm_pcie_mem_resource.start & C2P_MEM_WIN_BASE_ADDR_MASK;
++ val |= C2P_MEM_WIN_ENDIAN_HALF_BYTE_SWAP;
++ bcm_pcie_writel(val, PCIE_CPU_2_PCIE_MEM_WIN0_LO_REG);
++
++ bcm_pcie_writel(SPECIFIC_ENDIAN_MODE_BYTE_ALIGN, PCIE_SPECIFIC_REG);
++ bcm_pcie_writel(RC_BAR_CFG_LO_SIZE_256MB, PCIE_RC_BAR1_CONFIG_LO_REG);
++ bcm_pcie_writel(BAR1_CFG_REMAP_ACCESS_EN, PCIE_UBUS_BAR1_CFG_REMAP_REG);
++
++ bcm_pcie_writel(PCIE_BUS_DEVICE << EXT_CFG_BUS_NUM_SHIFT,
++ PCIE_EXT_CFG_INDEX_REG);
++}
++
++static struct clk *pcie_clk;
++
++static int __init bcm63xx_register_pcie(void)
++{
++ u32 val;
++
++ /* enable clock */
++ pcie_clk = clk_get(NULL, "pcie");
++ if (IS_ERR_OR_NULL(pcie_clk))
++ return -ENODEV;
++
++ clk_prepare_enable(pcie_clk);
++
++ if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_63268()) {
++ bcm63xx_reset_pcie_gen1();
++ bcm63xx_init_pcie_gen1();
++ } else {
++ bcm63xx_reset_pcie_gen2();
++ bcm63xx_init_pcie_gen2();
++ }
++
+ /* setup class code as bridge */
+ val = bcm_pcie_readl(PCIE_IDVAL3_REG);
+ val &= ~IDVAL3_CLASS_CODE_MASK;
+@@ -201,15 +272,6 @@ static int __init bcm63xx_register_pcie(
+ val &= ~CONFIG2_BAR1_SIZE_MASK;
+ bcm_pcie_writel(val, PCIE_CONFIG2_REG);
+
+- /* set bar0 to little endian */
+- val = (bcm_pcie_mem_resource.start >> 20) << BASEMASK_BASE_SHIFT;
+- val |= (bcm_pcie_mem_resource.end >> 20) << BASEMASK_MASK_SHIFT;
+- val |= BASEMASK_REMAP_EN;
+- bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG);
+-
+- val = (bcm_pcie_mem_resource.start >> 20) << REBASE_ADDR_BASE_SHIFT;
+- bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG);
+-
+ register_pci_controller(&bcm63xx_pcie_controller);
+
+ return 0;
+@@ -341,7 +403,10 @@ static int __init bcm63xx_pci_init(void)
+ if (!bcm63xx_pci_enabled)
+ return -ENODEV;
+
+- if (BCMCPU_IS_6328() || BCMCPU_IS_6362()) {
++ if (BCMCPU_IS_6318()) {
++ bcm_pcie_mem_resource.start = BCM_PCIE_MEM_BASE_PA_6318;
++ bcm_pcie_mem_resource.end = BCM_PCIE_MEM_END_PA_6318;
++ } if (BCMCPU_IS_6328() || BCMCPU_IS_6362()) {
+ bcm_pcie_mem_resource.start = BCM_PCIE_MEM_BASE_PA_6328;
+ bcm_pcie_mem_resource.end = BCM_PCIE_MEM_END_PA_6328;
+ } else if (BCMCPU_IS_63268()) {
+@@ -350,6 +415,7 @@ static int __init bcm63xx_pci_init(void)
+ }
+
+ switch (bcm63xx_get_cpu_id()) {
++ case BCM6318_CPU_ID:
+ case BCM6328_CPU_ID:
+ case BCM6362_CPU_ID:
+ case BCM63268_CPU_ID:
--- /dev/null
+From 9a97177b907330971aa7bf41855fafc2602e1c18 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 22 Dec 2013 12:26:57 +0100
+Subject: [PATCH 51/56] MIPS: BCM63XX: detect flash type early and store the
+ result
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/dev-flash.c | 10 +++++++---
+ arch/mips/bcm63xx/prom.c | 4 ++++
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h | 2 ++
+ 3 files changed, 13 insertions(+), 3 deletions(-)
+
+--- a/arch/mips/bcm63xx/dev-flash.c
++++ b/arch/mips/bcm63xx/dev-flash.c
+@@ -22,6 +22,8 @@
+ #include <bcm63xx_regs.h>
+ #include <bcm63xx_io.h>
+
++static int flash_type;
++
+ static struct mtd_partition mtd_partitions[] = {
+ {
+ .name = "cfe",
+@@ -108,13 +110,15 @@ static int __init bcm63xx_detect_flash_t
+ }
+ }
+
++void __init bcm63xx_flash_detect(void)
++{
++ flash_type = bcm63xx_detect_flash_type();
++}
++
+ int __init bcm63xx_flash_register(void)
+ {
+- int flash_type;
+ u32 val;
+
+- flash_type = bcm63xx_detect_flash_type();
+-
+ switch (flash_type) {
+ case BCM63XX_FLASH_TYPE_PARALLEL:
+ /* read base address of boot chip select (0) */
+--- a/arch/mips/bcm63xx/prom.c
++++ b/arch/mips/bcm63xx/prom.c
+@@ -17,6 +17,7 @@
+ #include <bcm63xx_cpu.h>
+ #include <bcm63xx_io.h>
+ #include <bcm63xx_regs.h>
++#include <bcm63xx_dev_flash.h>
+
+ void __init prom_init(void)
+ {
+@@ -52,6 +53,9 @@ void __init prom_init(void)
+ reg &= ~mask;
+ bcm_perf_writel(reg, PERF_CKCTL_REG);
+
++ /* detect and setup flash access */
++ bcm63xx_flash_detect();
++
+ /* do low level board init */
+ board_prom_init();
+
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h
+@@ -7,6 +7,8 @@ enum {
+ BCM63XX_FLASH_TYPE_NAND,
+ };
+
++void bcm63xx_flash_detect(void);
++
+ int __init bcm63xx_flash_register(void);
+
+ #endif /* __BCM63XX_FLASH_H */
--- /dev/null
+From 1cacd0f7b0d35f8e3d3f8a69ecb3b5e436d6b9e8 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 22 Dec 2013 13:25:25 +0100
+Subject: [PATCH 52/56] MIPS: BCM63XX: fixup mapped SPI flash access on boot
+
+Some bootloaders leave the flash access in an invalid state with dual
+read enabled; fix it by disabling it and falling back to simple fast
+reads.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/dev-flash.c | 51 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 51 insertions(+)
+
+--- a/arch/mips/bcm63xx/dev-flash.c
++++ b/arch/mips/bcm63xx/dev-flash.c
+@@ -16,6 +16,7 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/mtd/physmap.h>
++#include <linux/mtd/spi-nor.h>
+
+ #include <bcm63xx_cpu.h>
+ #include <bcm63xx_dev_flash.h>
+@@ -110,9 +111,59 @@ static int __init bcm63xx_detect_flash_t
+ }
+ }
+
++#define HSSPI_FLASH_CTRL_REG 0x14
++#define FLASH_CTRL_READ_OPCODE_MASK 0xff
++#define FLASH_CTRL_ADDR_BYTES_MASK (0x3 << 8)
++#define FLASH_CTRL_ADDR_BYTES_2 (0 << 8)
++#define FLASH_CTRL_ADDR_BYTES_3 (1 << 8)
++#define FLASH_CTRL_ADDR_BYTES_4 (2 << 8)
++#define FLASH_CTRL_DUMMY_BYTES_SHIFT 10
++#define FLASH_CTRL_DUMMY_BYTES_MASK (0x3 << FLASH_CTRL_DUMMY_BYTES_SHIFT)
++#define FLASH_CTRL_MB_EN (1 << 23)
++
+ void __init bcm63xx_flash_detect(void)
+ {
+ flash_type = bcm63xx_detect_flash_type();
++
++ /* ensure flash mapping has sane values */
++ if (flash_type == BCM63XX_FLASH_TYPE_SERIAL &&
++ (BCMCPU_IS_6318() || BCMCPU_IS_6328() || BCMCPU_IS_6362() ||
++ BCMCPU_IS_63268())) {
++ u32 val = bcm_rset_readl(RSET_HSSPI, HSSPI_FLASH_CTRL_REG);
++
++ if (val & FLASH_CTRL_MB_EN) {
++ /* cfe might configure non working dual-io mode */
++ val &= ~FLASH_CTRL_MB_EN;
++ val &= ~FLASH_CTRL_READ_OPCODE_MASK;
++ val &= ~FLASH_CTRL_DUMMY_BYTES_MASK;
++ val |= 1 << FLASH_CTRL_DUMMY_BYTES_SHIFT;
++
++ switch (val & FLASH_CTRL_ADDR_BYTES_MASK) {
++ case FLASH_CTRL_ADDR_BYTES_3:
++ val |= SPINOR_OP_READ_FAST;
++ break;
++ case FLASH_CTRL_ADDR_BYTES_4:
++ val |= SPINOR_OP_READ4_FAST;
++ break;
++ case FLASH_CTRL_ADDR_BYTES_2:
++ default:
++ pr_warn("unsupported address byte mode (%x), not fixing up\n",
++ val & FLASH_CTRL_ADDR_BYTES_MASK);
++ return;
++ }
++ } else {
++ /* ensure dummy bytes is set to 1 for _FAST reads */
++ u8 cmd = val & FLASH_CTRL_READ_OPCODE_MASK;
++
++ if (cmd != SPINOR_OP_READ_FAST && cmd != SPINOR_OP_READ4_FAST)
++ return;
++
++ val &= ~FLASH_CTRL_DUMMY_BYTES_MASK;
++ val |= 1 << FLASH_CTRL_DUMMY_BYTES_SHIFT;
++ }
++
++ bcm_rset_writel(RSET_HSSPI, val, HSSPI_FLASH_CTRL_REG);
++ }
+ }
+
+ int __init bcm63xx_flash_register(void)
--- /dev/null
+--- a/arch/mips/bcm63xx/clk.c
++++ b/arch/mips/bcm63xx/clk.c
+@@ -136,7 +136,11 @@ static struct clk clk_ephy = {
+ */
+ static void enetsw_set(struct clk *clk, int enable)
+ {
+- if (BCMCPU_IS_6328())
++ if (BCMCPU_IS_6318()) {
++ bcm_hwclock_set(CKCTL_6318_ROBOSW250_EN |
++ CKCTL_6318_ROBOSW025_EN, enable);
++ bcm_ub_hwclock_set(UB_CKCTL_6318_ROBOSW_EN, enable);
++ } else if (BCMCPU_IS_6328())
+ bcm_hwclock_set(CKCTL_6328_ROBOSW_EN, enable);
+ else if (BCMCPU_IS_6362())
+ bcm_hwclock_set(CKCTL_6362_ROBOSW_EN, enable);
+@@ -183,18 +187,22 @@ static struct clk clk_pcm = {
+ */
+ static void usbh_set(struct clk *clk, int enable)
+ {
+- if (BCMCPU_IS_6328())
++ if (BCMCPU_IS_6318()) {
++ bcm_hwclock_set(CKCTL_6318_USB_EN, enable);
++ bcm_ub_hwclock_set(UB_CKCTL_6318_USB_EN, enable);
++ } else if (BCMCPU_IS_6328()) {
+ bcm_hwclock_set(CKCTL_6328_USBH_EN, enable);
+- else if (BCMCPU_IS_6348())
++ } else if (BCMCPU_IS_6348()) {
+ bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
+- else if (BCMCPU_IS_6362())
++ } else if (BCMCPU_IS_6362()) {
+ bcm_hwclock_set(CKCTL_6362_USBH_EN, enable);
+- else if (BCMCPU_IS_6368())
++ } else if (BCMCPU_IS_6368()) {
+ bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
+- else if (BCMCPU_IS_63268())
++ } else if (BCMCPU_IS_63268()) {
+ bcm_hwclock_set(CKCTL_63268_USBH_EN, enable);
+- else
++ } else {
+ return;
++ }
+
+ if (enable)
+ msleep(100);
+@@ -405,9 +413,9 @@ struct clk *clk_get(struct device *dev,
+ return &clk_enetsw;
+ if (!strcmp(id, "ephy"))
+ return &clk_ephy;
+- if (!strcmp(id, "usbh"))
++ if (!strcmp(id, "usbh") || (BCMCPU_IS_6318() && !strcmp(id, "usbd")))
+ return &clk_usbh;
+- if (!strcmp(id, "usbd"))
++ if (!strcmp(id, "usbd") && !BCMCPU_IS_6318())
+ return &clk_usbd;
+ if (!strcmp(id, "spi"))
+ return &clk_spi;
--- /dev/null
+--- a/arch/mips/bcm63xx/usb-common.c
++++ b/arch/mips/bcm63xx/usb-common.c
+@@ -109,6 +109,27 @@ void bcm63xx_usb_priv_ohci_cfg_set(void)
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
+ reg |= USBH_PRIV_SETUP_IOC_MASK;
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
++ } else if (BCMCPU_IS_6318()) {
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6318_REG);
++ reg |= USBH_PRIV_PLL_CTRL1_SUSP_EN;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6318_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6318_REG);
++ reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
++ reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6318_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6318_REG);
++ reg |= USBH_PRIV_SETUP_IOC_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6318_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6318_REG);
++ reg &= ~USBH_PRIV_PLL_CTRL1_IDDQ_PWRDN;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6318_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SIM_CTRL_6318_REG);
++ reg |= USBH_PRIV_SIM_CTRL_LADDR_SEL;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SIM_CTRL_6318_REG);
+ }
+
+ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
+@@ -144,6 +165,27 @@ void bcm63xx_usb_priv_ehci_cfg_set(void)
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
+ reg |= USBH_PRIV_SETUP_IOC_MASK;
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
++ } else if (BCMCPU_IS_6318()) {
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6318_REG);
++ reg |= USBH_PRIV_PLL_CTRL1_SUSP_EN;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6318_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6318_REG);
++ reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
++ reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6318_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6318_REG);
++ reg |= USBH_PRIV_SETUP_IOC_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6318_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6318_REG);
++ reg &= ~USBH_PRIV_PLL_CTRL1_IDDQ_PWRDN;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6318_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SIM_CTRL_6318_REG);
++ reg |= USBH_PRIV_SIM_CTRL_LADDR_SEL;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SIM_CTRL_6318_REG);
+ }
+
+ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+@@ -681,6 +681,12 @@
+ #define GPIO_MODE_6368_SPI_SSN4 (1 << 30)
+ #define GPIO_MODE_6368_SPI_SSN5 (1 << 31)
+
++#define GPIO_PINMUX_SEL0_6318 0x1c
++#define GPIO_PINMUX_SEL0_GPIO13_SHIFT 26
++#define GPIO_PINMUX_SEL0_GPIO13_MASK (0x3 << GPIO_PINMUX_SEL0_GPIO13_SHIFT)
++#define GPIO_PINMUX_SEL0_GPIO13_PWRON (1 << GPIO_PINMUX_SEL0_GPIO13_SHIFT)
++#define GPIO_PINMUX_SEL0_GPIO13_LED (2 << GPIO_PINMUX_SEL0_GPIO13_SHIFT)
++#define GPIO_PINMUX_SEL0_GPIO13_GPIO (3 << GPIO_PINMUX_SEL0_GPIO13_SHIFT)
+
+ #define GPIO_PINMUX_OTHR_REG 0x24
+ #define GPIO_PINMUX_OTHR_6328_USB_SHIFT 12
+@@ -999,6 +1005,7 @@
+
+ #define USBH_PRIV_SWAP_6358_REG 0x0
+ #define USBH_PRIV_SWAP_6368_REG 0x1c
++#define USBH_PRIV_SWAP_6318_REG 0x0c
+
+ #define USBH_PRIV_SWAP_USBD_SHIFT 6
+ #define USBH_PRIV_SWAP_USBD_MASK (1 << USBH_PRIV_SWAP_USBD_SHIFT)
+@@ -1024,6 +1031,13 @@
+ #define USBH_PRIV_SETUP_IOC_SHIFT 4
+ #define USBH_PRIV_SETUP_IOC_MASK (1 << USBH_PRIV_SETUP_IOC_SHIFT)
+
++#define USBH_PRIV_SETUP_6318_REG 0x00
++#define USBH_PRIV_PLL_CTRL1_6318_REG 0x04
++#define USBH_PRIV_PLL_CTRL1_SUSP_EN (1 << 27)
++#define USBH_PRIV_PLL_CTRL1_IDDQ_PWRDN (1 << 31)
++#define USBH_PRIV_SIM_CTRL_6318_REG 0x20
++#define USBH_PRIV_SIM_CTRL_LADDR_SEL (1 << 5)
++
+
+ /*************************************************************************
+ * _REG relative to RSET_USBD
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -127,6 +127,15 @@ void __init board_early_setup(const stru
+ }
+
+ bcm_gpio_writel(val, GPIO_MODE_REG);
++
++#if IS_ENABLED(CONFIG_USB)
++ if (BCMCPU_IS_6318() && (board.has_ehci0 || board.has_ohci0)) {
++ val = bcm_gpio_readl(GPIO_PINMUX_SEL0_6318);
++ val &= ~GPIO_PINMUX_SEL0_GPIO13_MASK;
++ val |= GPIO_PINMUX_SEL0_GPIO13_PWRON;
++ bcm_gpio_writel(val, GPIO_PINMUX_SEL0_6318);
++ }
++#endif
+ }
+
+
+--- a/arch/mips/bcm63xx/Kconfig
++++ b/arch/mips/bcm63xx/Kconfig
+@@ -22,6 +22,8 @@ config BCM63XX_CPU_6318
+ bool "support 6318 CPU"
+ select SYS_HAS_CPU_BMIPS32_3300
+ select HW_HAS_PCI
++ select BCM63XX_OHCI
++ select BCM63XX_EHCI
+
+ config BCM63XX_CPU_6328
+ bool "support 6328 CPU"
--- /dev/null
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+@@ -586,6 +586,9 @@
+ #define TIMER_CTL_MONOTONIC_MASK (1 << 30)
+ #define TIMER_CTL_ENABLE_MASK (1 << 31)
+
++/* Clock reset control (63268 only) */
++#define TIMER_CLK_RST_CTL_REG 0x2c
++#define CLK_RST_CTL_USB_REF_CLK_EN (1 << 18)
+
+ /*************************************************************************
+ * _REG relative to RSET_WDT
+@@ -1533,6 +1536,11 @@
+ #define STRAPBUS_63268_FCVO_SHIFT 21
+ #define STRAPBUS_63268_FCVO_MASK (0xf << STRAPBUS_63268_FCVO_SHIFT)
+
++#define MISC_IDDQ_CTRL_6328_REG 0x48
++#define MISC_IDDQ_CTRL_63268_REG 0x4c
++
++#define IDDQ_CTRL_63268_USBH (1 << 4)
++
+ #define MISC_STRAPBUS_6328_REG 0x240
+ #define STRAPBUS_6328_FCVO_SHIFT 7
+ #define STRAPBUS_6328_FCVO_MASK (0x1f << STRAPBUS_6328_FCVO_SHIFT)
+--- a/arch/mips/bcm63xx/clk.c
++++ b/arch/mips/bcm63xx/clk.c
+@@ -62,6 +62,26 @@ static void bcm_ub_hwclock_set(u32 mask,
+ bcm_perf_writel(reg, PERF_UB_CKCTL_REG);
+ }
+
++static void bcm_misc_iddq_set(u32 mask, int enable)
++{
++ u32 offset;
++ u32 reg;
++
++ if (BCMCPU_IS_6328() || BCMCPU_IS_6362())
++ offset = MISC_IDDQ_CTRL_6328_REG;
++ else if (BCMCPU_IS_63268())
++ offset = MISC_IDDQ_CTRL_63268_REG;
++ else
++ return;
++
++ reg = bcm_misc_readl(offset);
++ if (enable)
++ reg &= ~mask;
++ else
++ reg |= mask;
++ bcm_misc_writel(reg, offset);
++}
++
+ /*
+ * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
+ */
+@@ -199,7 +219,17 @@ static void usbh_set(struct clk *clk, in
+ } else if (BCMCPU_IS_6368()) {
+ bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
+ } else if (BCMCPU_IS_63268()) {
++ u32 reg;
++
+ bcm_hwclock_set(CKCTL_63268_USBH_EN, enable);
++ bcm_misc_iddq_set(IDDQ_CTRL_63268_USBH, enable);
++ bcm63xx_core_set_reset(BCM63XX_RESET_USBH, !enable);
++ reg = bcm_timer_readl(TIMER_CLK_RST_CTL_REG);
++ if (enable)
++ reg |= CLK_RST_CTL_USB_REF_CLK_EN;
++ else
++ reg &= ~CLK_RST_CTL_USB_REF_CLK_EN;
++ bcm_timer_writel(reg, TIMER_CLK_RST_CTL_REG);
+ } else {
+ return;
+ }
--- /dev/null
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+@@ -1033,11 +1033,18 @@
+ #define USBH_PRIV_SETUP_6368_REG 0x28
+ #define USBH_PRIV_SETUP_IOC_SHIFT 4
+ #define USBH_PRIV_SETUP_IOC_MASK (1 << USBH_PRIV_SETUP_IOC_SHIFT)
++#define USBH_PRIV_SETUP_IPP_SHIFT 5
++#define USBH_PRIV_SETUP_IPP_MASK (1 << USBH_PRIV_SETUP_IPP_SHIFT)
+
+ #define USBH_PRIV_SETUP_6318_REG 0x00
++#define USBH_PRIV_PLL_CTRL1_6368_REG 0x18
+ #define USBH_PRIV_PLL_CTRL1_6318_REG 0x04
+-#define USBH_PRIV_PLL_CTRL1_SUSP_EN (1 << 27)
+-#define USBH_PRIV_PLL_CTRL1_IDDQ_PWRDN (1 << 31)
++
++#define USBH_PRIV_PLL_CTRL1_6318_SUSP_EN (1 << 27)
++#define USBH_PRIV_PLL_CTRL1_6318_IDDQ_PWRDN (1 << 31)
++#define USBH_PRIV_PLL_CTRL1_63268_IDDQ_PWRDN (1 << 9)
++#define USBH_PRIV_PLL_CTRL1_63268_PWRDN_DELAY (1 << 10)
++
+ #define USBH_PRIV_SIM_CTRL_6318_REG 0x20
+ #define USBH_PRIV_SIM_CTRL_LADDR_SEL (1 << 5)
+
+--- a/arch/mips/bcm63xx/Kconfig
++++ b/arch/mips/bcm63xx/Kconfig
+@@ -72,6 +72,8 @@ config BCM63XX_CPU_63268
+ bool "support 63268 CPU"
+ select SYS_HAS_CPU_BMIPS4350
+ select HW_HAS_PCI
++ select BCM63XX_OHCI
++ select BCM63XX_EHCI
+ endmenu
+
+ source "arch/mips/bcm63xx/boards/Kconfig"
+--- a/arch/mips/bcm63xx/dev-usb-ehci.c
++++ b/arch/mips/bcm63xx/dev-usb-ehci.c
+@@ -82,7 +82,7 @@ static struct platform_device bcm63xx_eh
+ int __init bcm63xx_ehci_register(void)
+ {
+ if (!BCMCPU_IS_6318() && !BCMCPU_IS_6328() && !BCMCPU_IS_6358() &&
+- !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
++ !BCMCPU_IS_6362() && !BCMCPU_IS_6368() && !BCMCPU_IS_63268())
+ return 0;
+
+ ehci_resources[0].start = bcm63xx_regset_address(RSET_EHCI0);
+--- a/arch/mips/bcm63xx/usb-common.c
++++ b/arch/mips/bcm63xx/usb-common.c
+@@ -109,9 +109,24 @@ void bcm63xx_usb_priv_ohci_cfg_set(void)
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
+ reg |= USBH_PRIV_SETUP_IOC_MASK;
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
++ } else if (BCMCPU_IS_63268()) {
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
++ reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
++ reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
++ reg |= USBH_PRIV_SETUP_IOC_MASK;
++ reg &= ~USBH_PRIV_SETUP_IPP_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6368_REG);
++ reg &= ~(USBH_PRIV_PLL_CTRL1_63268_IDDQ_PWRDN |
++ USBH_PRIV_PLL_CTRL1_63268_PWRDN_DELAY);
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6368_REG);
+ } else if (BCMCPU_IS_6318()) {
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6318_REG);
+- reg |= USBH_PRIV_PLL_CTRL1_SUSP_EN;
++ reg |= USBH_PRIV_PLL_CTRL1_6318_SUSP_EN;
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6318_REG);
+
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6318_REG);
+@@ -124,7 +139,7 @@ void bcm63xx_usb_priv_ohci_cfg_set(void)
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6318_REG);
+
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6318_REG);
+- reg &= ~USBH_PRIV_PLL_CTRL1_IDDQ_PWRDN;
++ reg &= ~USBH_PRIV_PLL_CTRL1_6318_IDDQ_PWRDN;
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6318_REG);
+
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SIM_CTRL_6318_REG);
+@@ -165,9 +180,24 @@ void bcm63xx_usb_priv_ehci_cfg_set(void)
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
+ reg |= USBH_PRIV_SETUP_IOC_MASK;
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
++ } else if (BCMCPU_IS_63268()) {
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
++ reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
++ reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
++ reg |= USBH_PRIV_SETUP_IOC_MASK;
++ reg &= ~USBH_PRIV_SETUP_IPP_MASK;
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
++
++ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6368_REG);
++ reg &= ~(USBH_PRIV_PLL_CTRL1_63268_IDDQ_PWRDN |
++ USBH_PRIV_PLL_CTRL1_63268_PWRDN_DELAY);
++ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6368_REG);
+ } else if (BCMCPU_IS_6318()) {
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6318_REG);
+- reg |= USBH_PRIV_PLL_CTRL1_SUSP_EN;
++ reg |= USBH_PRIV_PLL_CTRL1_6318_SUSP_EN;
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6318_REG);
+
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6318_REG);
+@@ -180,7 +210,7 @@ void bcm63xx_usb_priv_ehci_cfg_set(void)
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6318_REG);
+
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_PLL_CTRL1_6318_REG);
+- reg &= ~USBH_PRIV_PLL_CTRL1_IDDQ_PWRDN;
++ reg &= ~USBH_PRIV_PLL_CTRL1_6318_IDDQ_PWRDN;
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_PLL_CTRL1_6318_REG);
+
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SIM_CTRL_6318_REG);
--- /dev/null
+--- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
++++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
+@@ -41,6 +41,7 @@ struct board_info {
+
+ /* USB config */
+ struct bcm63xx_usbd_platform_data usbd;
++ unsigned int num_usbh_ports:2;
+
+ /* DSP config */
+ struct bcm63xx_dsp_platform_data dsp;
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h
+@@ -1,6 +1,6 @@
+ #ifndef BCM63XX_DEV_USB_EHCI_H_
+ #define BCM63XX_DEV_USB_EHCI_H_
+
+-int bcm63xx_ehci_register(void);
++int bcm63xx_ehci_register(unsigned int num_ports);
+
+ #endif /* BCM63XX_DEV_USB_EHCI_H_ */
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ohci.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ohci.h
+@@ -1,6 +1,6 @@
+ #ifndef BCM63XX_DEV_USB_OHCI_H_
+ #define BCM63XX_DEV_USB_OHCI_H_
+
+-int bcm63xx_ohci_register(void);
++int bcm63xx_ohci_register(unsigned int num_ports);
+
+ #endif /* BCM63XX_DEV_USB_OHCI_H_ */
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -167,6 +167,8 @@ static struct platform_device bcm63xx_gp
+ */
+ int __init board_register_devices(void)
+ {
++ int usbh_ports = 0;
++
+ if (board.has_uart0)
+ bcm63xx_uart_register(0);
+
+@@ -188,14 +190,21 @@ int __init board_register_devices(void)
+ !board_get_mac_address(board.enetsw.mac_addr))
+ bcm63xx_enetsw_register(&board.enetsw);
+
++ if ((board.has_ohci0 || board.has_ehci0)) {
++ usbh_ports = board.num_usbh_ports;
++
++ if (!usbh_ports || WARN_ON(usbh_ports > 1 && board.has_usbd))
++ usbh_ports = 1;
++ }
++
+ if (board.has_usbd)
+ bcm63xx_usbd_register(&board.usbd);
+
+ if (board.has_ehci0)
+- bcm63xx_ehci_register();
++ bcm63xx_ehci_register(usbh_ports);
+
+ if (board.has_ohci0)
+- bcm63xx_ohci_register();
++ bcm63xx_ohci_register(usbh_ports);
+
+ if (board.has_dsp)
+ bcm63xx_dsp_register(&board.dsp);
+--- a/arch/mips/bcm63xx/dev-usb-ehci.c
++++ b/arch/mips/bcm63xx/dev-usb-ehci.c
+@@ -79,12 +79,14 @@ static struct platform_device bcm63xx_eh
+ },
+ };
+
+-int __init bcm63xx_ehci_register(void)
++int __init bcm63xx_ehci_register(unsigned int num_ports)
+ {
+ if (!BCMCPU_IS_6318() && !BCMCPU_IS_6328() && !BCMCPU_IS_6358() &&
+ !BCMCPU_IS_6362() && !BCMCPU_IS_6368() && !BCMCPU_IS_63268())
+ return 0;
+
++ bcm63xx_ehci_pdata.num_ports = num_ports;
++
+ ehci_resources[0].start = bcm63xx_regset_address(RSET_EHCI0);
+ ehci_resources[0].end = ehci_resources[0].start;
+ ehci_resources[0].end += RSET_EHCI_SIZE - 1;
+--- a/arch/mips/bcm63xx/dev-usb-ohci.c
++++ b/arch/mips/bcm63xx/dev-usb-ohci.c
+@@ -62,7 +62,6 @@ static struct usb_ohci_pdata bcm63xx_ohc
+ .big_endian_desc = 1,
+ .big_endian_mmio = 1,
+ .no_big_frame_no = 1,
+- .num_ports = 1,
+ .power_on = bcm63xx_ohci_power_on,
+ .power_off = bcm63xx_ohci_power_off,
+ .power_suspend = bcm63xx_ohci_power_off,
+@@ -80,11 +79,13 @@ static struct platform_device bcm63xx_oh
+ },
+ };
+
+-int __init bcm63xx_ohci_register(void)
++int __init bcm63xx_ohci_register(unsigned int num_ports)
+ {
+ if (BCMCPU_IS_6345() || BCMCPU_IS_6338())
+ return -ENODEV;
+
++ bcm63xx_ohci_pdata.num_ports = num_ports;
++
+ ohci_resources[0].start = bcm63xx_regset_address(RSET_OHCI0);
+ ohci_resources[0].end = ohci_resources[0].start;
+ ohci_resources[0].end += RSET_OHCI_SIZE - 1;
--- /dev/null
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -592,6 +592,7 @@ static struct board_info __initdata boar
+ .has_ohci0 = 1,
+ .has_pccard = 1,
+ .has_ehci0 = 1,
++ .num_usbh_ports = 2,
+
+ .leds = {
+ {
--- /dev/null
+From 0daf361ea799fba0af5a232036d0f06cea85ad24 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sat, 21 Jun 2014 12:47:49 +0200
+Subject: [PATCH 42/44] MIPS: BCM63XX: allow building support for more than one
+ board type
+
+Use the arguments passed to the kernel to detect being booted with
+CFE as the indicator for bcm963xx board support, allowing the
+non presence of CFE_EPTSEAL to assume a different board type.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/boards/Kconfig | 7 +++----
+ arch/mips/bcm63xx/boards/board_bcm963xx.c | 2 +-
+ arch/mips/bcm63xx/boards/board_common.c | 13 +++++++++++++
+ arch/mips/bcm63xx/boards/board_common.h | 6 ++++++
+ 4 files changed, 23 insertions(+), 5 deletions(-)
+
+--- a/arch/mips/bcm63xx/boards/Kconfig
++++ b/arch/mips/bcm63xx/boards/Kconfig
+@@ -1,11 +1,10 @@
+-choice
+- prompt "Board support"
++menu "Board support"
+ depends on BCM63XX
+- default BOARD_BCM963XX
+
+ config BOARD_BCM963XX
+ bool "Generic Broadcom 963xx boards"
+ select SSB
++ default y
+ help
+
+-endchoice
++endmenu
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -702,7 +702,7 @@ static const struct board_info __initcon
+ /*
+ * early init callback, read nvram data from flash and checksum it
+ */
+-void __init board_prom_init(void)
++void __init board_bcm963xx_init(void)
+ {
+ unsigned int i;
+ u8 *boot_addr, *cfe;
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -14,6 +14,8 @@
+ #include <linux/ssb/ssb.h>
+ #include <linux/spi/spi.h>
+ #include <asm/addrspace.h>
++#include <asm/bootinfo.h>
++#include <asm/fw/cfe/cfe_api.h>
+ #include <bcm63xx_board.h>
+ #include <bcm63xx_cpu.h>
+ #include <bcm63xx_dev_uart.h>
+@@ -32,6 +34,8 @@
+ #include <bcm63xx_dev_usb_usbd.h>
+ #include <board_bcm963xx.h>
+
++#include "board_common.h"
++
+ #define PFX "board: "
+
+ static struct board_info board;
+@@ -82,6 +86,15 @@ const char *board_get_name(void)
+ return board.name;
+ }
+
++void __init board_prom_init(void)
++{
++ /* detect bootloader */
++ if (fw_arg3 == CFE_EPTSEAL)
++ board_bcm963xx_init();
++ else
++ panic("unsupported bootloader detected");
++}
++
+ static int (*board_get_mac_address)(u8 mac[ETH_ALEN]);
+
+ /*
+--- a/arch/mips/bcm63xx/boards/board_common.h
++++ b/arch/mips/bcm63xx/boards/board_common.h
+@@ -6,4 +6,10 @@
+ void board_early_setup(const struct board_info *board,
+ int (*get_mac_address)(u8 mac[ETH_ALEN]));
+
++#if defined(CONFIG_BOARD_BCM963XX)
++void board_bcm963xx_init(void);
++#else
++static inline void board_bcm963xx_init(void) { }
++#endif
++
+ #endif /* __BOARD_COMMON_H */
--- /dev/null
+From 8a30097a899b975709f728666d5ad20c8b832d21 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 9 Mar 2014 04:28:14 +0100
+Subject: [PATCH 43/44] MIPS: BCM63XX: allow board implementations to force
+ flash address
+
+Allow board implementations to force the physmap address.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/dev-flash.c | 19 ++++++++++++++-----
+ .../mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h | 2 ++
+ 2 files changed, 16 insertions(+), 5 deletions(-)
+
+--- a/arch/mips/bcm63xx/dev-flash.c
++++ b/arch/mips/bcm63xx/dev-flash.c
+@@ -58,6 +58,12 @@ static struct platform_device mtd_dev =
+ },
+ };
+
++void __init bcm63xx_flash_force_phys_base_address(u32 start, u32 end)
++{
++ mtd_resources[0].start = start;
++ mtd_resources[0].end = end;
++}
++
+ static int __init bcm63xx_detect_flash_type(void)
+ {
+ u32 val;
+@@ -172,12 +178,15 @@ int __init bcm63xx_flash_register(void)
+
+ switch (flash_type) {
+ case BCM63XX_FLASH_TYPE_PARALLEL:
+- /* read base address of boot chip select (0) */
+- val = bcm_mpi_readl(MPI_CSBASE_REG(0));
+- val &= MPI_CSBASE_BASE_MASK;
+
+- mtd_resources[0].start = val;
+- mtd_resources[0].end = 0x1FFFFFFF;
++ if (!mtd_resources[0].start) {
++ /* read base address of boot chip select (0) */
++ val = bcm_mpi_readl(MPI_CSBASE_REG(0));
++ val &= MPI_CSBASE_BASE_MASK;
++
++ mtd_resources[0].start = val;
++ mtd_resources[0].end = 0x1FFFFFFF;
++ }
+
+ return platform_device_register(&mtd_dev);
+ case BCM63XX_FLASH_TYPE_SERIAL:
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h
+@@ -9,6 +9,8 @@ enum {
+
+ void bcm63xx_flash_detect(void);
+
++void bcm63xx_flash_force_phys_base_address(u32 start, u32 end);
++
+ int __init bcm63xx_flash_register(void);
+
+ #endif /* __BCM63XX_FLASH_H */
--- /dev/null
+From cc025e749a1fece61a6cc0d64bbe7b12472259cc Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Tue, 29 Jul 2014 21:31:12 +0200
+Subject: [PATCH 01/10] MIPS: BCM63XX: move fallback sprom support into its own
+ unit
+
+In preparation for enhancing it, move it into its own file. Require a
+mac address to be passed as the argument to always "reserve" the mac
+regardless of the inclusion state of SSB.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/Makefile | 2 +-
+ arch/mips/bcm63xx/boards/board_common.c | 53 ++--------------
+ arch/mips/bcm63xx/sprom.c | 70 ++++++++++++++++++++++
+ .../asm/mach-bcm63xx/bcm63xx_fallback_sprom.h | 6 ++
+ 4 files changed, 83 insertions(+), 48 deletions(-)
+ create mode 100644 arch/mips/bcm63xx/sprom.c
+ create mode 100644 arch/mips/include/asm/mach-bcm63xx/bcm63xx_fallback_sprom.h
+
+--- a/arch/mips/bcm63xx/Makefile
++++ b/arch/mips/bcm63xx/Makefile
+@@ -2,7 +2,7 @@ obj-y += clk.o cpu.o cs.o gpio.o irq.o
+ setup.o timer.o dev-dsp.o dev-enet.o dev-flash.o \
+ dev-pcmcia.o dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o \
+ dev-wdt.o dev-usb-ehci.o dev-usb-ohci.o dev-usb-usbd.o \
+- usb-common.o
++ usb-common.o sprom.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+ obj-y += boards/
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -41,44 +41,6 @@
+ static struct board_info board;
+
+ /*
+- * Register a sane SPROMv2 to make the on-board
+- * bcm4318 WLAN work
+- */
+-#ifdef CONFIG_SSB_PCIHOST
+-static struct ssb_sprom bcm63xx_sprom = {
+- .revision = 0x02,
+- .board_rev = 0x17,
+- .country_code = 0x0,
+- .ant_available_bg = 0x3,
+- .pa0b0 = 0x15ae,
+- .pa0b1 = 0xfa85,
+- .pa0b2 = 0xfe8d,
+- .pa1b0 = 0xffff,
+- .pa1b1 = 0xffff,
+- .pa1b2 = 0xffff,
+- .gpio0 = 0xff,
+- .gpio1 = 0xff,
+- .gpio2 = 0xff,
+- .gpio3 = 0xff,
+- .maxpwr_bg = 0x004c,
+- .itssi_bg = 0x00,
+- .boardflags_lo = 0x2848,
+- .boardflags_hi = 0x0000,
+-};
+-
+-int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+-{
+- if (bus->bustype == SSB_BUSTYPE_PCI) {
+- memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
+- return 0;
+- } else {
+- printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n");
+- return -EINVAL;
+- }
+-}
+-#endif
+-
+-/*
+ * return board name for /proc/cpuinfo
+ */
+ const char *board_get_name(void)
+@@ -181,6 +143,7 @@ static struct platform_device bcm63xx_gp
+ int __init board_register_devices(void)
+ {
+ int usbh_ports = 0;
++ u8 mac[ETH_ALEN];
+
+ if (board.has_uart0)
+ bcm63xx_uart_register(0);
+@@ -225,15 +188,10 @@ int __init board_register_devices(void)
+ /* Generate MAC address for WLAN and register our SPROM,
+ * do this after registering enet devices
+ */
+-#ifdef CONFIG_SSB_PCIHOST
+- if (!board_get_mac_address(bcm63xx_sprom.il0mac)) {
+- memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
+- memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
+- if (ssb_arch_register_fallback_sprom(
+- &bcm63xx_get_fallback_sprom) < 0)
+- pr_err(PFX "failed to register fallback SPROM\n");
+- }
+-#endif
++
++ if (board_get_mac_address(mac) ||
++ bcm63xx_register_fallback_sprom(mac))
++ pr_err(PFX "failed to register fallback SPROM\n");
+
+ bcm63xx_spi_register();
+
+--- /dev/null
++++ b/arch/mips/bcm63xx/sprom.c
+@@ -0,0 +1,70 @@
++/*
++ * 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) 2008 Maxime Bizon <mbizon@freebox.fr>
++ * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/platform_device.h>
++#include <linux/ssb/ssb.h>
++#include <bcm63xx_fallback_sprom.h>
++#include <board_bcm963xx.h>
++
++#define PFX "sprom: "
++
++/*
++ * Register a sane SPROMv2 to make the on-board
++ * bcm4318 WLAN work
++ */
++#ifdef CONFIG_SSB_PCIHOST
++static struct ssb_sprom bcm63xx_sprom = {
++ .revision = 0x02,
++ .board_rev = 0x17,
++ .country_code = 0x0,
++ .ant_available_bg = 0x3,
++ .pa0b0 = 0x15ae,
++ .pa0b1 = 0xfa85,
++ .pa0b2 = 0xfe8d,
++ .pa1b0 = 0xffff,
++ .pa1b1 = 0xffff,
++ .pa1b2 = 0xffff,
++ .gpio0 = 0xff,
++ .gpio1 = 0xff,
++ .gpio2 = 0xff,
++ .gpio3 = 0xff,
++ .maxpwr_bg = 0x004c,
++ .itssi_bg = 0x00,
++ .boardflags_lo = 0x2848,
++ .boardflags_hi = 0x0000,
++};
++
++int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
++{
++ if (bus->bustype == SSB_BUSTYPE_PCI) {
++ memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
++ return 0;
++ } else {
++ printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n");
++ return -EINVAL;
++ }
++}
++#endif
++
++int __init bcm63xx_register_fallback_sprom(u8 *mac)
++{
++ int ret = 0;
++
++#ifdef CONFIG_SSB_PCIHOST
++ memcpy(bcm63xx_sprom.il0mac, mac, ETH_ALEN);
++ memcpy(bcm63xx_sprom.et0mac, mac, ETH_ALEN);
++ memcpy(bcm63xx_sprom.et1mac, mac, ETH_ALEN);
++
++ ret = ssb_arch_register_fallback_sprom(&bcm63xx_get_fallback_sprom);
++#endif
++ return ret;
++}
+--- /dev/null
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_fallback_sprom.h
+@@ -0,0 +1,6 @@
++#ifndef __BCM63XX_FALLBACK_SPROM
++#define __BCM63XX_FALLBACK_SPROM
++
++int bcm63xx_register_fallback_sprom(u8 *mac);
++
++#endif
--- /dev/null
+From 9912a8b3c240a9b0af01ff496b7e8ed9e4cc5b82 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Tue, 29 Jul 2014 21:43:49 +0200
+Subject: [PATCH 02/10] MIPS: BCM63XX: use platform data for the sprom
+
+Similar to ethernet setup, use a platform data struct for passing
+the mac. This eliminates the requirement to allocate an array on
+stack for the mac passed.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/boards/board_common.c | 6 ++----
+ arch/mips/bcm63xx/sprom.c | 8 ++++----
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_fallback_sprom.h | 8 +++++++-
+ arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h | 4 ++++
+ 4 files changed, 17 insertions(+), 9 deletions(-)
+
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -143,7 +143,6 @@ static struct platform_device bcm63xx_gp
+ int __init board_register_devices(void)
+ {
+ int usbh_ports = 0;
+- u8 mac[ETH_ALEN];
+
+ if (board.has_uart0)
+ bcm63xx_uart_register(0);
+@@ -189,8 +188,8 @@ int __init board_register_devices(void)
+ * do this after registering enet devices
+ */
+
+- if (board_get_mac_address(mac) ||
+- bcm63xx_register_fallback_sprom(mac))
++ if (board_get_mac_address(board.fallback_sprom.mac_addr) ||
++ bcm63xx_register_fallback_sprom(&board.fallback_sprom))
+ pr_err(PFX "failed to register fallback SPROM\n");
+
+ bcm63xx_spi_register();
+--- a/arch/mips/bcm63xx/sprom.c
++++ b/arch/mips/bcm63xx/sprom.c
+@@ -55,14 +55,14 @@ int bcm63xx_get_fallback_sprom(struct ss
+ }
+ #endif
+
+-int __init bcm63xx_register_fallback_sprom(u8 *mac)
++int __init bcm63xx_register_fallback_sprom(struct fallback_sprom_data *data)
+ {
+ int ret = 0;
+
+ #ifdef CONFIG_SSB_PCIHOST
+- memcpy(bcm63xx_sprom.il0mac, mac, ETH_ALEN);
+- memcpy(bcm63xx_sprom.et0mac, mac, ETH_ALEN);
+- memcpy(bcm63xx_sprom.et1mac, mac, ETH_ALEN);
++ memcpy(bcm63xx_sprom.il0mac, data->mac_addr, ETH_ALEN);
++ memcpy(bcm63xx_sprom.et0mac, data->mac_addr, ETH_ALEN);
++ memcpy(bcm63xx_sprom.et1mac, data->mac_addr, ETH_ALEN);
+
+ ret = ssb_arch_register_fallback_sprom(&bcm63xx_get_fallback_sprom);
+ #endif
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_fallback_sprom.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_fallback_sprom.h
+@@ -1,6 +1,12 @@
+ #ifndef __BCM63XX_FALLBACK_SPROM
+ #define __BCM63XX_FALLBACK_SPROM
+
+-int bcm63xx_register_fallback_sprom(u8 *mac);
++#include <linux/if_ether.h>
++
++struct fallback_sprom_data {
++ u8 mac_addr[ETH_ALEN];
++};
++
++int bcm63xx_register_fallback_sprom(struct fallback_sprom_data *data);
+
+ #endif
+--- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
++++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
+@@ -7,6 +7,7 @@
+ #include <bcm63xx_dev_enet.h>
+ #include <bcm63xx_dev_usb_usbd.h>
+ #include <bcm63xx_dev_dsp.h>
++#include <bcm63xx_fallback_sprom.h>
+
+ /*
+ * flash mapping
+@@ -55,6 +56,9 @@ struct board_info {
+ /* External PHY reset GPIO flags from gpio.h */
+ unsigned long ephy_reset_gpio_flags;
+
++ /* fallback sprom config */
++ struct fallback_sprom_data fallback_sprom;
++
+ /* Additional platform devices */
+ struct platform_device **devs;
+ unsigned int num_devs;
--- /dev/null
+From 83131acbfb59760a19f3711c09526e191c8aad54 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Tue, 29 Jul 2014 21:52:56 +0200
+Subject: [PATCH 03/10] MIPS: BCM63XX: make fallback sprom optional
+
+Some devices do not provide enough mac addresses to populate wifi in
+addition to ethernet.
+
+Use having pci enabled as a rough heuristic which boards should have it
+enabled.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/boards/board_bcm963xx.c | 12 ++++++++++++
+ arch/mips/bcm63xx/boards/board_common.c | 5 +++--
+ arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h | 1 +
+ 3 files changed, 16 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
+@@ -70,6 +70,7 @@ static struct board_info __initdata boar
+ .has_uart0 = 1,
+ .has_pci = 1,
+ .has_usbd = 0,
++ .use_fallback_sprom = 1,
+
+ .usbd = {
+ .use_fullspeed = 0,
+@@ -219,6 +220,7 @@ static struct board_info __initdata boar
+ .has_uart0 = 1,
+ .has_enet0 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+@@ -264,6 +266,7 @@ static struct board_info __initdata boar
+ .has_enet0 = 1,
+ .has_enet1 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+@@ -324,6 +327,7 @@ static struct board_info __initdata boar
+ .has_enet0 = 1,
+ .has_enet1 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+@@ -378,6 +382,7 @@ static struct board_info __initdata boar
+ .has_enet0 = 1,
+ .has_enet1 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+@@ -436,6 +441,7 @@ static struct board_info __initdata boar
+ .has_enet0 = 1,
+ .has_enet1 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+@@ -459,6 +465,7 @@ static struct board_info __initdata boar
+ .has_enet0 = 1,
+ .has_enet1 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+@@ -477,6 +484,7 @@ static struct board_info __initdata boar
+
+ .has_uart0 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+ .has_ohci0 = 1,
+
+ .has_enet0 = 1,
+@@ -499,6 +507,7 @@ static struct board_info __initdata boar
+ .has_enet0 = 1,
+ .has_enet1 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+@@ -525,6 +534,7 @@ static struct board_info __initdata boar
+ .has_enet0 = 1,
+ .has_enet1 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+@@ -577,6 +587,7 @@ static struct board_info __initdata boar
+ .has_enet0 = 1,
+ .has_enet1 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+@@ -648,6 +659,7 @@ static struct board_info __initdata boar
+ .has_enet0 = 1,
+ .has_enet1 = 1,
+ .has_pci = 1,
++ .use_fallback_sprom = 1,
+
+ .enet0 = {
+ .has_phy = 1,
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -188,8 +188,9 @@ int __init board_register_devices(void)
+ * do this after registering enet devices
+ */
+
+- if (board_get_mac_address(board.fallback_sprom.mac_addr) ||
+- bcm63xx_register_fallback_sprom(&board.fallback_sprom))
++ if (board.use_fallback_sprom &&
++ (board_get_mac_address(board.fallback_sprom.mac_addr) ||
++ bcm63xx_register_fallback_sprom(&board.fallback_sprom)))
+ pr_err(PFX "failed to register fallback SPROM\n");
+
+ bcm63xx_spi_register();
+--- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
++++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
+@@ -34,6 +34,7 @@ struct board_info {
+ unsigned int has_dsp:1;
+ unsigned int has_uart0:1;
+ unsigned int has_uart1:1;
++ unsigned int use_fallback_sprom:1;
+
+ /* ethernet config */
+ struct bcm63xx_enet_platform_data enet0;
--- /dev/null
+From 1cece9f7aca1f0c193edce201f77a87008c5a405 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Tue, 29 Jul 2014 21:58:38 +0200
+Subject: [PATCH 04/10] MIPS: BCM63XX: allow different types of sprom
+
+Different chips require different sprom contents, so prepare for
+supplying the appropriate sprom type.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/sprom.c | 13 ++++++++++++-
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_fallback_sprom.h | 5 +++++
+ 2 files changed, 17 insertions(+), 1 deletion(-)
+
+--- a/arch/mips/bcm63xx/sprom.c
++++ b/arch/mips/bcm63xx/sprom.c
+@@ -22,7 +22,7 @@
+ * bcm4318 WLAN work
+ */
+ #ifdef CONFIG_SSB_PCIHOST
+-static struct ssb_sprom bcm63xx_sprom = {
++static __initconst struct ssb_sprom bcm63xx_default_sprom = {
+ .revision = 0x02,
+ .board_rev = 0x17,
+ .country_code = 0x0,
+@@ -43,6 +43,8 @@ static struct ssb_sprom bcm63xx_sprom =
+ .boardflags_hi = 0x0000,
+ };
+
++static struct ssb_sprom bcm63xx_sprom;
++
+ int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+ {
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+@@ -60,6 +62,15 @@ int __init bcm63xx_register_fallback_spr
+ int ret = 0;
+
+ #ifdef CONFIG_SSB_PCIHOST
++ switch (data->type) {
++ case SPROM_DEFAULT:
++ memcpy(&bcm63xx_sprom, &bcm63xx_default_sprom,
++ sizeof(bcm63xx_sprom));
++ break;
++ default:
++ return -EINVAL;
++ }
++
+ memcpy(bcm63xx_sprom.il0mac, data->mac_addr, ETH_ALEN);
+ memcpy(bcm63xx_sprom.et0mac, data->mac_addr, ETH_ALEN);
+ memcpy(bcm63xx_sprom.et1mac, data->mac_addr, ETH_ALEN);
+--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_fallback_sprom.h
++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_fallback_sprom.h
+@@ -3,8 +3,13 @@
+
+ #include <linux/if_ether.h>
+
++enum sprom_type {
++ SPROM_DEFAULT, /* default fallback sprom */
++};
++
+ struct fallback_sprom_data {
+ u8 mac_addr[ETH_ALEN];
++ enum sprom_type type;
+ };
+
+ int bcm63xx_register_fallback_sprom(struct fallback_sprom_data *data);
--- /dev/null
+From cedee63bc73f8b7d45b8c0cba1236986812c1f83 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Tue, 29 Jul 2014 22:16:36 +0200
+Subject: [PATCH 05/10] MIPS: BCM63XX: add support for "raw" sproms
+
+Allow using raw sprom content as templates.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/mips/bcm63xx/sprom.c | 482 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 482 insertions(+)
+
+--- a/arch/mips/bcm63xx/sprom.c
++++ b/arch/mips/bcm63xx/sprom.c
+@@ -55,13 +55,492 @@ int bcm63xx_get_fallback_sprom(struct ss
+ return -EINVAL;
+ }
+ }
++
++/* FIXME: use lib_sprom after submission upstream */
++
++/* Get the word-offset for a SSB_SPROM_XXX define. */
++#define SPOFF(offset) ((offset) / sizeof(u16))
++/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
++#define SPEX16(_outvar, _offset, _mask, _shift) \
++ out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
++#define SPEX32(_outvar, _offset, _mask, _shift) \
++ out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \
++ in[SPOFF(_offset)]) & (_mask)) >> (_shift))
++#define SPEX(_outvar, _offset, _mask, _shift) \
++ SPEX16(_outvar, _offset, _mask, _shift)
++
++#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
++ do { \
++ SPEX(_field[0], _offset + 0, _mask, _shift); \
++ SPEX(_field[1], _offset + 2, _mask, _shift); \
++ SPEX(_field[2], _offset + 4, _mask, _shift); \
++ SPEX(_field[3], _offset + 6, _mask, _shift); \
++ SPEX(_field[4], _offset + 8, _mask, _shift); \
++ SPEX(_field[5], _offset + 10, _mask, _shift); \
++ SPEX(_field[6], _offset + 12, _mask, _shift); \
++ SPEX(_field[7], _offset + 14, _mask, _shift); \
++ } while (0)
++
++
++static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
++ u16 mask, u16 shift)
++{
++ u16 v;
++ u8 gain;
++
++ v = in[SPOFF(SSB_SPROM1_AGAIN)];
++ gain = (v & mask) >> shift;
++ if (gain == 0xFF)
++ gain = 2; /* If unset use 2dBm */
++ if (sprom_revision == 1) {
++ /* Convert to Q5.2 */
++ gain <<= 2;
++ } else {
++ /* Q5.2 Fractional part is stored in 0xC0 */
++ gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
++ }
++
++ return (s8)gain;
++}
++
++static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in)
++{
++ SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
++ SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
++ SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
++ SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
++ SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
++ SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
++ SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
++ SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
++ SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
++ SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
++ SSB_SPROM2_MAXP_A_LO_SHIFT);
++}
++
++static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
++{
++ u16 loc[3];
++
++ if (out->revision == 3) /* rev 3 moved MAC */
++ loc[0] = SSB_SPROM3_IL0MAC;
++ else {
++ loc[0] = SSB_SPROM1_IL0MAC;
++ loc[1] = SSB_SPROM1_ET0MAC;
++ loc[2] = SSB_SPROM1_ET1MAC;
++ }
++
++ SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
++ SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
++ SSB_SPROM1_ETHPHY_ET1A_SHIFT);
++ SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
++ SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
++ SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
++ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
++ if (out->revision == 1)
++ SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
++ SSB_SPROM1_BINF_CCODE_SHIFT);
++ SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
++ SSB_SPROM1_BINF_ANTA_SHIFT);
++ SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
++ SSB_SPROM1_BINF_ANTBG_SHIFT);
++ SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
++ SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
++ SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
++ SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
++ SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
++ SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
++ SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
++ SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
++ SSB_SPROM1_GPIOA_P1_SHIFT);
++ SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
++ SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
++ SSB_SPROM1_GPIOB_P3_SHIFT);
++ SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
++ SSB_SPROM1_MAXPWR_A_SHIFT);
++ SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
++ SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
++ SSB_SPROM1_ITSSI_A_SHIFT);
++ SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
++ SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
++
++ SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
++ SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
++
++ /* Extract the antenna gain values. */
++ out->antenna_gain.a0 = r123_extract_antgain(out->revision, in,
++ SSB_SPROM1_AGAIN_BG,
++ SSB_SPROM1_AGAIN_BG_SHIFT);
++ out->antenna_gain.a1 = r123_extract_antgain(out->revision, in,
++ SSB_SPROM1_AGAIN_A,
++ SSB_SPROM1_AGAIN_A_SHIFT);
++ if (out->revision >= 2)
++ sprom_extract_r23(out, in);
++}
++
++/* Revs 4 5 and 8 have partially shared layout */
++static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
++{
++ SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
++ SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
++ SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
++ SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
++ SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
++ SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
++ SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
++ SSB_SPROM4_TXPID2G3, SSB_SP