diff options
36 files changed, 4925 insertions, 0 deletions
diff --git a/target/linux/bcm53xx/config-4.4 b/target/linux/bcm53xx/config-4.4 new file mode 100644 index 0000000..337c598 --- /dev/null +++ b/target/linux/bcm53xx/config-4.4 @@ -0,0 +1,314 @@ +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_BCM=y +# CONFIG_ARCH_BCM_21664 is not set +# CONFIG_ARCH_BCM_281XX is not set +CONFIG_ARCH_BCM_5301X=y +# CONFIG_ARCH_BCM_63XX is not set +# CONFIG_ARCH_BCM_CYGNUS is not set +CONFIG_ARCH_BCM_IPROC=y +# CONFIG_ARCH_BRCMSTB is not set +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_REQUIRE_GPIOLIB=y +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_APPENDED_DTB=y +# CONFIG_ARM_ATAG_DTB_COMPAT is not set +# CONFIG_ARM_CPU_SUSPEND is not set +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_ERRATA_775420=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GLOBAL_TIMER=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_HEAVY_MB=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +# CONFIG_ARM_LPAE is not set +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_ATAGS=y +CONFIG_AUTO_ZRELADDR=y +CONFIG_B53=y +# CONFIG_B53_MMAP_DRIVER is not set +# CONFIG_B53_PHY_DRIVER is not set +CONFIG_B53_SRAB_DRIVER=y +CONFIG_BCM47XX_NVRAM=y +CONFIG_BCM47XX_SPROM=y +CONFIG_BCM47XX_WDT=y +CONFIG_BCMA=y +CONFIG_BCMA_BLOCKIO=y +CONFIG_BCMA_DEBUG=y +CONFIG_BCMA_DRIVER_GMAC_CMN=y +CONFIG_BCMA_DRIVER_GPIO=y +CONFIG_BCMA_DRIVER_PCI=y +CONFIG_BCMA_HOST_PCI=y +CONFIG_BCMA_HOST_PCI_POSSIBLE=y +CONFIG_BCMA_HOST_SOC=y +CONFIG_BGMAC=y +CONFIG_BOUNCE=y +CONFIG_CACHE_L2X0=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLKSRC_OF=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_IPROC=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_XZ=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_BCM_5301X=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_INCLUDE="debug/8250.S" +CONFIG_DEBUG_UART_8250=y +# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set +CONFIG_DEBUG_UART_8250_SHIFT=0 +CONFIG_DEBUG_UART_PHYS=0x18000300 +CONFIG_DEBUG_UART_VIRT=0xf1000300 +CONFIG_DEBUG_UNCOMPRESS=y +CONFIG_DEBUG_USER=y +CONFIG_DTC=y +CONFIG_EARLY_PRINTK=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FRAME_POINTER=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_74X164=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIO_SYSFS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDIRQS_SW_RESEND=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_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_SCU=y +CONFIG_HAVE_ARM_TWD=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_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=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_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HZ_FIXED=0 +CONFIG_HZ_PERIODIC=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_IOMMU_HELPER=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_LIBFDT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MDIO_BOARDINFO=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MTD_BCM47XX_PARTS=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_BRCMNAND=y +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_PHYSMAP_OF is not set +CONFIG_MTD_SPI_BCM53XXSPIFLASH=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MULTI_IRQ_HANDLER=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NO_BOOTMEM=y +CONFIG_NR_CPUS=2 +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_OF_RESERVED_MEM=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PCI=y +CONFIG_PCIE_IPROC=y +CONFIG_PCIE_IPROC_BCMA=y +# CONFIG_PCIE_IPROC_PLATFORM is not set +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PINCTRL=y +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_PL310_ERRATA_769419 is not set +CONFIG_RCU_STALL_COMMON=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_SCHED_HRTICK=y +# CONFIG_SCHED_INFO is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_SG_SPLIT is not set +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_BCM53XX=y +CONFIG_SPI_BITBANG=y +CONFIG_SPI_GPIO=y +CONFIG_SPI_MASTER=y +CONFIG_SRCU=y +CONFIG_STOP_MACHINE=y +# CONFIG_SUNXI_SRAM is not set +CONFIG_SWCONFIG=y +CONFIG_SWIOTLB=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TREE_RCU=y +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_XZ=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_USB_SUPPORT=y +CONFIG_USE_OF=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_VFP is not set +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/bcm53xx/patches-4.4/020-ARM-BCM5310X-activate-erratas-needed-for-SoC.patch b/target/linux/bcm53xx/patches-4.4/020-ARM-BCM5310X-activate-erratas-needed-for-SoC.patch new file mode 100644 index 0000000..8169da9 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/020-ARM-BCM5310X-activate-erratas-needed-for-SoC.patch @@ -0,0 +1,31 @@ +From f4ce7effe2253a325f8ba182903cbdf0d8698593 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens <hauke@hauke-m.de> +Date: Sat, 21 Nov 2015 15:29:47 +0100 +Subject: [PATCH] ARM: BCM5310X: activate erratas needed for SoC + +The BCM4708 I have, which is probably the first generation which got +to the consumer market, is using a ARM Cortex-A9 rev r3p0 and a +L2C-310 rev r3p2 L2 cache controller. There are 3 workarounds for known +erratas in the Linux kernel which could be activated and will be in +this patch. There are currently no workarounds which have to be +activated for the L2C-310 rev r3p2 in Linux. + +Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> +Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> +--- + arch/arm/mach-bcm/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/mach-bcm/Kconfig ++++ b/arch/arm/mach-bcm/Kconfig +@@ -52,6 +52,10 @@ config ARCH_BCM_NSP + config ARCH_BCM_5301X + bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 + select ARCH_BCM_IPROC ++ select ARM_ERRATA_754322 ++ select ARM_ERRATA_775420 ++ select ARM_ERRATA_764369 if SMP ++ + help + Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. + diff --git a/target/linux/bcm53xx/patches-4.4/050-ARM-dts-enable-clock-support-for-BCM5301X.patch b/target/linux/bcm53xx/patches-4.4/050-ARM-dts-enable-clock-support-for-BCM5301X.patch new file mode 100644 index 0000000..a9a5246 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/050-ARM-dts-enable-clock-support-for-BCM5301X.patch @@ -0,0 +1,153 @@ +From e96ef422d0095fe9ae39b03c0805a0db8ff7e382 Mon Sep 17 00:00:00 2001 +From: Jon Mason <jonmason@broadcom.com> +Date: Tue, 13 Oct 2015 17:22:25 -0400 +Subject: [PATCH 50/50] ARM: dts: enable clock support for BCM5301X + +Replace current device tree dummy clocks with real clock support for +Broadcom Northstar SoCs. + +Signed-off-by: Jon Mason <jonmason@broadcom.com> +--- + arch/arm/boot/dts/bcm5301x.dtsi | 88 ++++++++++++++++++++++++++++++++--------- + 1 file changed, 69 insertions(+), 19 deletions(-) + +--- a/arch/arm/boot/dts/bcm5301x.dtsi ++++ b/arch/arm/boot/dts/bcm5301x.dtsi +@@ -8,6 +8,7 @@ + * Licensed under the GNU/GPL. See COPYING for details. + */ + ++#include <dt-bindings/clock/bcm-nsp.h> + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/input/input.h> + #include <dt-bindings/interrupt-controller/irq.h> +@@ -42,41 +43,48 @@ + + mpcore { + compatible = "simple-bus"; +- ranges = <0x00000000 0x19020000 0x00003000>; ++ ranges = <0x00000000 0x19000000 0x00023000>; + #address-cells = <1>; + #size-cells = <1>; + +- scu@0000 { ++ a9pll: arm_clk@00000 { ++ #clock-cells = <0>; ++ compatible = "brcm,nsp-armpll"; ++ clocks = <&osc>; ++ reg = <0x00000 0x1000>; ++ }; ++ ++ scu@20000 { + compatible = "arm,cortex-a9-scu"; +- reg = <0x0000 0x100>; ++ reg = <0x20000 0x100>; + }; + +- timer@0200 { ++ timer@20200 { + compatible = "arm,cortex-a9-global-timer"; +- reg = <0x0200 0x100>; ++ reg = <0x20200 0x100>; + interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&clk_periph>; ++ clocks = <&periph_clk>; + }; + +- local-timer@0600 { ++ local-timer@20600 { + compatible = "arm,cortex-a9-twd-timer"; +- reg = <0x0600 0x100>; ++ reg = <0x20600 0x100>; + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&clk_periph>; ++ clocks = <&periph_clk>; + }; + +- gic: interrupt-controller@1000 { ++ gic: interrupt-controller@21000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; +- reg = <0x1000 0x1000>, +- <0x0100 0x100>; ++ reg = <0x21000 0x1000>, ++ <0x20100 0x100>; + }; + +- L2: cache-controller@2000 { ++ L2: cache-controller@22000 { + compatible = "arm,pl310-cache"; +- reg = <0x2000 0x1000>; ++ reg = <0x22000 0x1000>; + cache-unified; + arm,shared-override; + prefetch-data = <1>; +@@ -94,14 +102,37 @@ + + clocks { + #address-cells = <1>; +- #size-cells = <0>; ++ #size-cells = <1>; ++ ranges; + +- /* As long as we do not have a real clock driver us this +- * fixed clock */ +- clk_periph: periph { ++ osc: oscillator { ++ #clock-cells = <0>; + compatible = "fixed-clock"; ++ clock-frequency = <25000000>; ++ }; ++ ++ iprocmed: iprocmed { + #clock-cells = <0>; +- clock-frequency = <400000000>; ++ compatible = "fixed-factor-clock"; ++ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>; ++ clock-div = <2>; ++ clock-mult = <1>; ++ }; ++ ++ iprocslow: iprocslow { ++ #clock-cells = <0>; ++ compatible = "fixed-factor-clock"; ++ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>; ++ clock-div = <4>; ++ clock-mult = <1>; ++ }; ++ ++ periph_clk: periph_clk { ++ #clock-cells = <0>; ++ compatible = "fixed-factor-clock"; ++ clocks = <&a9pll>; ++ clock-div = <2>; ++ clock-mult = <1>; + }; + }; + +@@ -189,4 +220,23 @@ + + brcm,nand-has-wp; + }; ++ ++ lcpll0: lcpll0@1800c100 { ++ #clock-cells = <1>; ++ compatible = "brcm,nsp-lcpll0"; ++ reg = <0x1800c100 0x14>; ++ clocks = <&osc>; ++ clock-output-names = "lcpll0", "pcie_phy", "sdio", ++ "ddr_phy"; ++ }; ++ ++ genpll: genpll@1800c140 { ++ #clock-cells = <1>; ++ compatible = "brcm,nsp-genpll"; ++ reg = <0x1800c140 0x24>; ++ clocks = <&osc>; ++ clock-output-names = "genpll", "phy", "ethernetclk", ++ "usbclk", "iprocfast", "sata1", ++ "sata2"; ++ }; + }; diff --git a/target/linux/bcm53xx/patches-4.4/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch b/target/linux/bcm53xx/patches-4.4/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch new file mode 100644 index 0000000..cd22e19 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch @@ -0,0 +1,218 @@ +From a0aef7fbab0d8b5a0d445c74990e5233beda246e Mon Sep 17 00:00:00 2001 +From: Jon Mason <jonmason@broadcom.com> +Date: Wed, 21 Oct 2015 18:46:04 -0400 +Subject: [PATCH] ARM: dts: bcm5301x: Add BCM SVK DT files + +Add device tree files for Broadcom Northstar based SVKs. Since the +bcm5301x.dtsi already exists, all that is necessary is the dts files to +enable the UARTs. With these files, the SVKs are able to boot to shell. + +Signed-off-by: Jon Mason <jonmason@broadcom.com> +--- + arch/arm/boot/dts/Makefile | 5 +++- + arch/arm/boot/dts/bcm94708.dts | 56 +++++++++++++++++++++++++++++++++++ + arch/arm/boot/dts/bcm94709.dts | 56 +++++++++++++++++++++++++++++++++++ + arch/arm/boot/dts/bcm953012k.dts | 63 ++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 179 insertions(+), 1 deletion(-) + create mode 100644 arch/arm/boot/dts/bcm94708.dts + create mode 100644 arch/arm/boot/dts/bcm94709.dts + create mode 100644 arch/arm/boot/dts/bcm953012k.dts + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -75,7 +75,10 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \ + bcm4709-asus-rt-ac87u.dtb \ + bcm4709-buffalo-wxr-1900dhp.dtb \ + bcm4709-netgear-r7000.dtb \ +- bcm4709-netgear-r8000.dtb ++ bcm4709-netgear-r8000.dtb \ ++ bcm94708.dtb \ ++ bcm94709.dtb \ ++ bcm953012k.dtb + dtb-$(CONFIG_ARCH_BCM_63XX) += \ + bcm963138dvt.dtb + dtb-$(CONFIG_ARCH_BCM_CYGNUS) += \ +--- /dev/null ++++ b/arch/arm/boot/dts/bcm94708.dts +@@ -0,0 +1,56 @@ ++/* ++ * BSD LICENSE ++ * ++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Broadcom Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/dts-v1/; ++ ++#include "bcm4708.dtsi" ++ ++/ { ++ model = "NorthStar SVK (BCM94708)"; ++ compatible = "brcm,bcm94708", "brcm,bcm4708"; ++ ++ aliases { ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory { ++ reg = <0x00000000 0x08000000>; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/bcm94709.dts +@@ -0,0 +1,56 @@ ++/* ++ * BSD LICENSE ++ * ++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Broadcom Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/dts-v1/; ++ ++#include "bcm4708.dtsi" ++ ++/ { ++ model = "NorthStar SVK (BCM94709)"; ++ compatible = "brcm,bcm94709", "brcm,bcm4709", "brcm,bcm4708"; ++ ++ aliases { ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory { ++ reg = <0x00000000 0x08000000>; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/bcm953012k.dts +@@ -0,0 +1,63 @@ ++/* ++ * BSD LICENSE ++ * ++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Broadcom Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/dts-v1/; ++ ++#include "bcm4708.dtsi" ++ ++/ { ++ model = "NorthStar SVK (BCM953012K)"; ++ compatible = "brcm,bcm953012k", "brcm,brcm53012", "brcm,bcm4708"; ++ ++ aliases { ++ serial0 = &uart0; ++ serial1 = &uart1; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory { ++ reg = <0x00000000 0x10000000>; ++ }; ++}; ++ ++&uart0 { ++ clock-frequency = <62499840>; ++ status = "okay"; ++}; ++ ++&uart1 { ++ clock-frequency = <62499840>; ++ status = "okay"; ++}; diff --git a/target/linux/bcm53xx/patches-4.4/101-use-part-parser.patch b/target/linux/bcm53xx/patches-4.4/101-use-part-parser.patch new file mode 100644 index 0000000..8d48673 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/101-use-part-parser.patch @@ -0,0 +1,11 @@ +--- a/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi ++++ b/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi +@@ -19,6 +19,8 @@ + + nand-ecc-strength = <8>; + nand-ecc-step-size = <512>; ++ ++ linux,part-probe = "ofpart", "bcm47xxpart"; + }; + }; + }; diff --git a/target/linux/bcm53xx/patches-4.4/112-bcm53xx-sprom-add-sprom-driver.patch b/target/linux/bcm53xx/patches-4.4/112-bcm53xx-sprom-add-sprom-driver.patch new file mode 100644 index 0000000..70ab039 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/112-bcm53xx-sprom-add-sprom-driver.patch @@ -0,0 +1,69 @@ +From 4e0ab3269a6d260a41a3673157753147f5f71341 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens <hauke@hauke-m.de> +Date: Sun, 4 May 2014 13:19:20 +0200 +Subject: [PATCH 03/17] bcm47xx-sprom: add Broadcom sprom parser driver + +This driver needs an nvram driver and fetches the sprom values from the +nvram and provides it to any other driver. The calibration data for the +wifi chip the mac address and some more board description data is +stores in the sprom. + +This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to +make the bcm47xx MIPS SoCs also use this driver some time later. + +Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> +--- + .../devicetree/bindings/misc/bcm47xx-sprom.txt | 16 + + drivers/misc/Kconfig | 11 + + drivers/misc/Makefile | 1 + + drivers/misc/bcm47xx-sprom.c | 690 +++++++++++++++++++++ + 4 files changed, 718 insertions(+) + create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt + create mode 100644 drivers/misc/bcm47xx-sprom.c + +--- /dev/null ++++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt +@@ -0,0 +1,16 @@ ++Broadcom bcm47xx/bcm53xx sprom converter ++ ++This driver provbides an sprom based on a given nvram. ++ ++Required properties: ++ ++- compatible : brcm,bcm47xx-sprom ++ ++- nvram : reference to a nvram driver, e.g. bcm47xx-nvram ++ ++Example: ++ ++sprom0: sprom@0 { ++ compatible = "brcm,bcm47xx-sprom"; ++ nvram = <&nvram0>; ++}; +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -525,6 +525,17 @@ config VEXPRESS_SYSCFG + bus. System Configuration interface is one of the possible means + of generating transactions on this bus. + ++config BCM47XX_SPROM ++ tristate "BCM47XX sprom driver" ++ help ++ This driver parses the sprom from a given nvram which is found on ++ Broadcom bcm47xx and bcm53xx SoCs. ++ ++ The sprom contains board configuration data like the ++ calibration data fro the wifi chips, the mac addresses used ++ by the board and many other board configuration data. This ++ driver will provide the sprom to bcma. ++ + source "drivers/misc/c2port/Kconfig" + source "drivers/misc/eeprom/Kconfig" + source "drivers/misc/cb710/Kconfig" +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE) += genwqe/ + obj-$(CONFIG_ECHO) += echo/ + obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o + obj-$(CONFIG_CXL_BASE) += cxl/ ++obj-$(CONFIG_BCM47XX_SPROM) += bcm47xx-sprom.o diff --git a/target/linux/bcm53xx/patches-4.4/130-dt-bindings-add-SMP-enable-method-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.4/130-dt-bindings-add-SMP-enable-method-for-Broadcom-NSP.patch new file mode 100644 index 0000000..1de37b0 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/130-dt-bindings-add-SMP-enable-method-for-Broadcom-NSP.patch @@ -0,0 +1,69 @@ +From 204b9dbd7c4bd5a223fd104b9cba56c12fe04add Mon Sep 17 00:00:00 2001 +From: Kapil Hali <kapilh@broadcom.com> +Date: Wed, 19 Aug 2015 13:42:23 -0400 +Subject: [PATCH 130/134] dt-bindings: add SMP enable-method for Broadcom NSP + +Add a compatible string "brcm,bcm-nsp-smp" for Broadcom's +Northstar Plus CPU to the 32-bit ARM CPU device tree binding +documentation file and create a new binding documentation for +Northstar Plus CPU. + +Signed-off-by: Kapil Hali <kapilh@broadcom.com> +--- + .../bindings/arm/bcm/brcm,nsp-cpu-method.txt | 39 ++++++++++++++++++++++ + Documentation/devicetree/bindings/arm/cpus.txt | 1 + + 2 files changed, 40 insertions(+) + create mode 100644 Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt +@@ -0,0 +1,39 @@ ++Broadcom Northstar Plus SoC CPU Enable Method ++--------------------------------------------- ++This binding defines the enable method used for starting secondary ++CPUs in the following Broadcom SoCs: ++ BCM58522, BCM58525, BCM58535, BCM58622, BCM58623, BCM58625, BCM88312 ++ ++The enable method is specified by defining the following required ++properties in the "cpus" device tree node: ++ - enable-method = "brcm,bcm-nsp-smp"; ++ - secondary-boot-reg = <...>; ++ ++The secondary-boot-reg property is a u32 value that specifies the ++physical address of the register which should hold the common ++entry point for a secondary CPU. This entry is cpu node specific ++and should be added per cpu. E.g., in case of NSP (BCM58625) which ++is a dual core CPU SoC, this entry should be added to cpu1 node. ++ ++ ++Example: ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ enable-method = "brcm,bcm-nsp-smp"; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ next-level-cache = <&L2>; ++ reg = <0>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ next-level-cache = <&L2>; ++ reg = <1>; ++ secondary-boot-reg = <0xffff042c>; ++ }; ++ }; +--- a/Documentation/devicetree/bindings/arm/cpus.txt ++++ b/Documentation/devicetree/bindings/arm/cpus.txt +@@ -190,6 +190,7 @@ nodes to be present and contain the prop + "allwinner,sun6i-a31" + "allwinner,sun8i-a23" + "arm,psci" ++ "brcm,bcm-nsp-smp" + "brcm,brahma-b15" + "marvell,armada-375-smp" + "marvell,armada-380-smp" diff --git a/target/linux/bcm53xx/patches-4.4/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch b/target/linux/bcm53xx/patches-4.4/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch new file mode 100644 index 0000000..7a48a13 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch @@ -0,0 +1,206 @@ +From 8622d6da5d95293d474c156612fd819fdaf542ec Mon Sep 17 00:00:00 2001 +From: Kapil Hali <kapilh@broadcom.com> +Date: Wed, 25 Nov 2015 08:58:53 -0500 +Subject: [PATCH 131/134] ARM: BCM: Clean up SMP support for Broadcom Kona + +These changes cleans up SMP implementaion for Broadcom's +Kona SoC which are required for handling SMP for iProc +family of SoCs at a single place for BCM NSP and BCM Kona. + +Signed-off-by: Kapil Hali <kapilh@broadcom.com> +--- + arch/arm/boot/dts/bcm11351.dtsi | 2 +- + arch/arm/boot/dts/bcm21664.dtsi | 2 +- + arch/arm/mach-bcm/kona_smp.c | 82 +++++++++++++++++++++++++++-------------- + 3 files changed, 56 insertions(+), 30 deletions(-) + +--- a/arch/arm/boot/dts/bcm11351.dtsi ++++ b/arch/arm/boot/dts/bcm11351.dtsi +@@ -31,7 +31,6 @@ + #address-cells = <1>; + #size-cells = <0>; + enable-method = "brcm,bcm11351-cpu-method"; +- secondary-boot-reg = <0x3500417c>; + + cpu0: cpu@0 { + device_type = "cpu"; +@@ -42,6 +41,7 @@ + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; ++ secondary-boot-reg = <0x3500417c>; + reg = <1>; + }; + }; +--- a/arch/arm/boot/dts/bcm21664.dtsi ++++ b/arch/arm/boot/dts/bcm21664.dtsi +@@ -31,7 +31,6 @@ + #address-cells = <1>; + #size-cells = <0>; + enable-method = "brcm,bcm11351-cpu-method"; +- secondary-boot-reg = <0x35004178>; + + cpu0: cpu@0 { + device_type = "cpu"; +@@ -42,6 +41,7 @@ + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; ++ secondary-boot-reg = <0x35004178>; + reg = <1>; + }; + }; +--- a/arch/arm/mach-bcm/kona_smp.c ++++ b/arch/arm/mach-bcm/kona_smp.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2014 Broadcom Corporation ++ * Copyright (C) 2014-2015 Broadcom Corporation + * Copyright 2014 Linaro Limited + * + * This program is free software; you can redistribute it and/or +@@ -30,9 +30,10 @@ + + /* Name of device node property defining secondary boot register location */ + #define OF_SECONDARY_BOOT "secondary-boot-reg" ++#define MPIDR_CPUID_BITMASK 0x3 + + /* I/O address of register used to coordinate secondary core startup */ +-static u32 secondary_boot; ++static u32 secondary_boot_addr; + + /* + * Enable the Cortex A9 Snoop Control Unit +@@ -78,44 +79,68 @@ static int __init scu_a9_enable(void) + static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) + { + static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; +- struct device_node *node; ++ struct device_node *cpus_node = NULL; ++ struct device_node *cpu_node = NULL; + int ret; + +- BUG_ON(secondary_boot); /* We're called only once */ +- + /* + * This function is only called via smp_ops->smp_prepare_cpu(). + * That only happens if a "/cpus" device tree node exists + * and has an "enable-method" property that selects the SMP + * operations defined herein. + */ +- node = of_find_node_by_path("/cpus"); +- BUG_ON(!node); +- +- /* +- * Our secondary enable method requires a "secondary-boot-reg" +- * property to specify a register address used to request the +- * ROM code boot a secondary code. If we have any trouble +- * getting this we fall back to uniprocessor mode. +- */ +- if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { +- pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", +- node->name); +- ret = -ENOENT; /* Arrange to disable SMP */ +- goto out; ++ cpus_node = of_find_node_by_path("/cpus"); ++ if (!cpus_node) ++ return; ++ ++ for_each_child_of_node(cpus_node, cpu_node) { ++ u32 cpuid; ++ ++ if (of_node_cmp(cpu_node->type, "cpu")) ++ continue; ++ ++ if (of_property_read_u32(cpu_node, "reg", &cpuid)) { ++ pr_debug("%s: missing reg property\n", ++ cpu_node->full_name); ++ ret = -ENOENT; ++ goto out; ++ } ++ ++ /* ++ * "secondary-boot-reg" property should be defined only ++ * for secondary cpu ++ */ ++ if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { ++ /* ++ * Our secondary enable method requires a ++ * "secondary-boot-reg" property to specify a register ++ * address used to request the ROM code boot a secondary ++ * core. If we have any trouble getting this we fall ++ * back to uniprocessor mode. ++ */ ++ if (of_property_read_u32(cpu_node, ++ OF_SECONDARY_BOOT, ++ &secondary_boot_addr)) { ++ pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", ++ cpu_node->name); ++ ret = -ENOENT; ++ goto out; ++ } ++ } + } + + /* +- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is ++ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is + * returned, the SoC reported a uniprocessor configuration. + * We bail on any other error. + */ + ret = scu_a9_enable(); + out: +- of_node_put(node); ++ of_node_put(cpu_node); ++ of_node_put(cpus_node); ++ + if (ret) { + /* Update the CPU present map to reflect uniprocessor mode */ +- BUG_ON(ret != -ENOENT); + pr_warn("disabling SMP\n"); + init_cpu_present(&only_cpu_0); + } +@@ -139,7 +164,7 @@ out: + * - Wait for the secondary boot register to be re-written, which + * indicates the secondary core has started. + */ +-static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) ++static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) + { + void __iomem *boot_reg; + phys_addr_t boot_func; +@@ -154,15 +179,16 @@ static int bcm_boot_secondary(unsigned i + return -EINVAL; + } + +- if (!secondary_boot) { ++ if (!secondary_boot_addr) { + pr_err("required secondary boot register not specified\n"); + return -EINVAL; + } + +- boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); ++ boot_reg = ioremap_nocache( ++ (phys_addr_t)secondary_boot_addr, sizeof(u32)); + if (!boot_reg) { + pr_err("unable to map boot register for cpu %u\n", cpu_id); +- return -ENOSYS; ++ return -ENOMEM; + } + + /* +@@ -191,12 +217,12 @@ static int bcm_boot_secondary(unsigned i + + pr_err("timeout waiting for cpu %u to start\n", cpu_id); + +- return -ENOSYS; ++ return -ENXIO; + } + + static struct smp_operations bcm_smp_ops __initdata = { + .smp_prepare_cpus = bcm_smp_prepare_cpus, +- .smp_boot_secondary = bcm_boot_secondary, ++ .smp_boot_secondary = kona_boot_secondary, + }; + CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", + &bcm_smp_ops); diff --git a/target/linux/bcm53xx/patches-4.4/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.4/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch new file mode 100644 index 0000000..75db188 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch @@ -0,0 +1,560 @@ +From e99fb6d01cddf38cffc11655aba4a96a981d604e Mon Sep 17 00:00:00 2001 +From: Kapil Hali <kapilh@broadcom.com> +Date: Wed, 25 Nov 2015 13:25:55 -0500 +Subject: [PATCH 133/134] ARM: BCM: Add SMP support for Broadcom NSP + +Add SMP support for Broadcom's Northstar Plus SoC +cpu enable method. This changes also consolidates +iProc family's - BCM NSP and BCM Kona, platform +SMP handling in a common file. + +Northstar Plus SoC is based on ARM Cortex-A9 +revision r3p0 which requires configuration for ARM +Errata 764369 for SMP. This change adds the needed +configuration option. + +Signed-off-by: Kapil Hali <kapilh@broadcom.com> +--- + arch/arm/mach-bcm/Kconfig | 2 + + arch/arm/mach-bcm/Makefile | 8 +- + arch/arm/mach-bcm/kona_smp.c | 228 ---------------------------------- + arch/arm/mach-bcm/platsmp.c | 290 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 298 insertions(+), 230 deletions(-) + delete mode 100644 arch/arm/mach-bcm/kona_smp.c + create mode 100644 arch/arm/mach-bcm/platsmp.c + +--- a/arch/arm/mach-bcm/Makefile ++++ b/arch/arm/mach-bcm/Makefile +@@ -23,7 +23,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc + obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o + + # BCM281XX and BCM21664 SMP support +-obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o ++obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o + + # BCM281XX and BCM21664 L2 cache control + obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o +--- a/arch/arm/mach-bcm/kona_smp.c ++++ /dev/null +@@ -1,228 +0,0 @@ +-/* +- * Copyright (C) 2014-2015 Broadcom Corporation +- * Copyright 2014 Linaro Limited +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation version 2. +- * +- * This program is distributed "as is" WITHOUT ANY WARRANTY of any +- * kind, whether express or implied; without even the implied warranty +- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- */ +- +-#include <linux/init.h> +-#include <linux/errno.h> +-#include <linux/io.h> +-#include <linux/of.h> +-#include <linux/sched.h> +- +-#include <asm/smp.h> +-#include <asm/smp_plat.h> +-#include <asm/smp_scu.h> +- +-/* Size of mapped Cortex A9 SCU address space */ +-#define CORTEX_A9_SCU_SIZE 0x58 +- +-#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ +-#define BOOT_ADDR_CPUID_MASK 0x3 +- +-/* Name of device node property defining secondary boot register location */ +-#define OF_SECONDARY_BOOT "secondary-boot-reg" +-#define MPIDR_CPUID_BITMASK 0x3 +- +-/* I/O address of register used to coordinate secondary core startup */ +-static u32 secondary_boot_addr; +- +-/* +- * Enable the Cortex A9 Snoop Control Unit +- * +- * By the time this is called we already know there are multiple +- * cores present. We assume we're running on a Cortex A9 processor, +- * so any trouble getting the base address register or getting the +- * SCU base is a problem. +- * +- * Return 0 if successful or an error code otherwise. +- */ +-static int __init scu_a9_enable(void) +-{ +- unsigned long config_base; +- void __iomem *scu_base; +- +- if (!scu_a9_has_base()) { +- pr_err("no configuration base address register!\n"); +- return -ENXIO; +- } +- +- /* Config base address register value is zero for uniprocessor */ +- config_base = scu_a9_get_base(); +- if (!config_base) { +- pr_err("hardware reports only one core\n"); +- return -ENOENT; +- } +- +- scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); +- if (!scu_base) { +- pr_err("failed to remap config base (%lu/%u) for SCU\n", +- config_base, CORTEX_A9_SCU_SIZE); +- return -ENOMEM; +- } +- +- scu_enable(scu_base); +- +- iounmap(scu_base); /* That's the last we'll need of this */ +- +- return 0; +-} +- +-static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) +-{ +- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; +- struct device_node *cpus_node = NULL; +- struct device_node *cpu_node = NULL; +- int ret; +- +- /* +- * This function is only called via smp_ops->smp_prepare_cpu(). +- * That only happens if a "/cpus" device tree node exists +- * and has an "enable-method" property that selects the SMP +- * operations defined herein. +- */ +- cpus_node = of_find_node_by_path("/cpus"); +- if (!cpus_node) +- return; +- +- for_each_child_of_node(cpus_node, cpu_node) { +- u32 cpuid; +- +- if (of_node_cmp(cpu_node->type, "cpu")) +- continue; +- +- if (of_property_read_u32(cpu_node, "reg", &cpuid)) { +- pr_debug("%s: missing reg property\n", +- cpu_node->full_name); +- ret = -ENOENT; +- goto out; +- } +- +- /* +- * "secondary-boot-reg" property should be defined only +- * for secondary cpu +- */ +- if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { +- /* +- * Our secondary enable method requires a +- * "secondary-boot-reg" property to specify a register +- * address used to request the ROM code boot a secondary +- * core. If we have any trouble getting this we fall +- * back to uniprocessor mode. +- */ +- if (of_property_read_u32(cpu_node, +- OF_SECONDARY_BOOT, +- &secondary_boot_addr)) { +- pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", +- cpu_node->name); +- ret = -ENOENT; +- goto out; +- } +- } +- } +- +- /* +- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is +- * returned, the SoC reported a uniprocessor configuration. +- * We bail on any other error. +- */ +- ret = scu_a9_enable(); +-out: +- of_node_put(cpu_node); +- of_node_put(cpus_node); +- +- if (ret) { +- /* Update the CPU present map to reflect uniprocessor mode */ +- pr_warn("disabling SMP\n"); +- init_cpu_present(&only_cpu_0); +- } +-} +- +-/* +- * The ROM code has the secondary cores looping, waiting for an event. +- * When an event occurs each core examines the bottom two bits of the +- * secondary boot register. When a core finds those bits contain its +- * own core id, it performs initialization, including computing its boot +- * address by clearing the boot register value's bottom two bits. The +- * core signals that it is beginning its execution by writing its boot +- * address back to the secondary boot register, and finally jumps to +- * that address. +- * +- * So to start a core executing we need to: +- * - Encode the (hardware) CPU id with the bottom bits of the secondary +- * start address. +- * - Write that value into the secondary boot register. +- * - Generate an event to wake up the secondary CPU(s). +- * - Wait for the secondary boot register to be re-written, which +- * indicates the secondary core has started. +- */ +-static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) +-{ +- void __iomem *boot_reg; +- phys_addr_t boot_func; +- u64 start_clock; +- u32 cpu_id; +- u32 boot_val; +- bool timeout = false; +- +- cpu_id = cpu_logical_map(cpu); +- if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { +- pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); +- return -EINVAL; +- } +- +- if (!secondary_boot_addr) { +- pr_err("required secondary boot register not specified\n"); +- return -EINVAL; +- } +- +- boot_reg = ioremap_nocache( +- (phys_addr_t)secondary_boot_addr, sizeof(u32)); +- if (!boot_reg) { +- pr_err("unable to map boot register for cpu %u\n", cpu_id); +- return -ENOMEM; +- } +- +- /* +- * Secondary cores will start in secondary_startup(), +- * defined in "arch/arm/kernel/head.S" +- */ +- boot_func = virt_to_phys(secondary_startup); +- BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); +- BUG_ON(boot_func > (phys_addr_t)U32_MAX); +- +- /* The core to start is encoded in the low bits */ +- boot_val = (u32)boot_func | cpu_id; +- writel_relaxed(boot_val, boot_reg); +- +- sev(); +- +- /* The low bits will be cleared once the core has started */ +- start_clock = local_clock(); +- while (!timeout && readl_relaxed(boot_reg) == boot_val) +- timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; +- +- iounmap(boot_reg); +- +- if (!timeout) +- return 0; +- +- pr_err("timeout waiting for cpu %u to start\n", cpu_id); +- +- return -ENXIO; +-} +- +-static struct smp_operations bcm_smp_ops __initdata = { +- .smp_prepare_cpus = bcm_smp_prepare_cpus, +- .smp_boot_secondary = kona_boot_secondary, +-}; +-CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", +- &bcm_smp_ops); +--- /dev/null ++++ b/arch/arm/mach-bcm/platsmp.c +@@ -0,0 +1,290 @@ ++/* ++ * Copyright (C) 2014-2015 Broadcom Corporation ++ * Copyright 2014 Linaro Limited ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/cpumask.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/jiffies.h> ++#include <linux/of.h> ++#include <linux/sched.h> ++#include <linux/smp.h> ++ ++#include <asm/cacheflush.h> ++#include <asm/smp.h> ++#include <asm/smp_plat.h> ++#include <asm/smp_scu.h> ++ ++/* Size of mapped Cortex A9 SCU address space */ ++#define CORTEX_A9_SCU_SIZE 0x58 ++ ++#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ ++#define BOOT_ADDR_CPUID_MASK 0x3 ++ ++/* Name of device node property defining secondary boot register location */ ++#define OF_SECONDARY_BOOT "secondary-boot-reg" ++#define MPIDR_CPUID_BITMASK 0x3 ++ ++/* I/O address of register used to coordinate secondary core startup */ ++static u32 secondary_boot_addr; ++ ++/* ++ * Enable the Cortex A9 Snoop Control Unit ++ * ++ * By the time this is called we already know there are multiple ++ * cores present. We assume we're running on a Cortex A9 processor, ++ * so any trouble getting the base address register or getting the ++ * SCU base is a problem. ++ * ++ * Return 0 if successful or an error code otherwise. ++ */ ++static int __init scu_a9_enable(void) ++{ ++ unsigned long config_base; ++ void __iomem *scu_base; ++ ++ if (!scu_a9_has_base()) { ++ pr_err("no configuration base address register!\n"); ++ return -ENXIO; ++ } ++ ++ /* Config base address register value is zero for uniprocessor */ ++ config_base = scu_a9_get_base(); ++ if (!config_base) { ++ pr_err("hardware reports only one core\n"); ++ return -ENOENT; ++ } ++ ++ scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); ++ if (!scu_base) { ++ pr_err("failed to remap config base (%lu/%u) for SCU\n", ++ config_base, CORTEX_A9_SCU_SIZE); ++ return -ENOMEM; ++ } ++ ++ scu_enable(scu_base); ++ ++ iounmap(scu_base); /* That's the last we'll need of this */ ++ ++ return 0; ++} ++ ++static int nsp_write_lut(void) ++{ ++ void __iomem *sku_rom_lut; ++ phys_addr_t secondary_startup_phy; ++ ++ if (!secondary_boot_addr) { ++ pr_warn("required secondary boot register not specified\n"); ++ return -EINVAL; ++ } ++ ++ sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot_addr, ++ sizeof(secondary_boot_addr)); ++ if (!sku_rom_lut) { ++ pr_warn("unable to ioremap SKU-ROM LUT register\n"); ++ return -ENOMEM; ++ } ++ ++ secondary_startup_phy = virt_to_phys(secondary_startup); ++ BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX); ++ ++ writel_relaxed(secondary_startup_phy, sku_rom_lut); ++ ++ /* Ensure the write is visible to the secondary core */ ++ smp_wmb(); ++ ++ iounmap(sku_rom_lut); ++ ++ return 0; ++} ++ ++static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) ++{ ++ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; ++ struct device_node *cpus_node = NULL; ++ struct device_node *cpu_node = NULL; ++ int ret; ++ ++ /* ++ * This function is only called via smp_ops->smp_prepare_cpu(). ++ * That only happens if a "/cpus" device tree node exists ++ * and has an "enable-method" property that selects the SMP ++ * operations defined herein. ++ */ ++ cpus_node = of_find_node_by_path("/cpus"); ++ if (!cpus_node) ++ return; ++ ++ for_each_child_of_node(cpus_node, cpu_node) { ++ u32 cpuid; ++ ++ if (of_node_cmp(cpu_node->type, "cpu")) ++ continue; ++ ++ if (of_property_read_u32(cpu_node, "reg", &cpuid)) { ++ pr_debug("%s: missing reg property\n", ++ cpu_node->full_name); ++ ret = -ENOENT; ++ goto out; ++ } ++ ++ /* ++ * "secondary-boot-reg" property should be defined only ++ * for secondary cpu ++ */ ++ if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { ++ /* ++ * Our secondary enable method requires a ++ * "secondary-boot-reg" property to specify a register ++ * address used to request the ROM code boot a secondary ++ * core. If we have any trouble getting this we fall ++ * back to uniprocessor mode. ++ */ ++ if (of_property_read_u32(cpu_node, ++ OF_SECONDARY_BOOT, ++ &secondary_boot_addr)) { ++ pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", ++ cpu_node->name); ++ ret = -ENOENT; ++ goto out; ++ } ++ } ++ } ++ ++ /* ++ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is ++ * returned, the SoC reported a uniprocessor configuration. ++ * We bail on any other error. ++ */ ++ ret = scu_a9_enable(); ++out: ++ of_node_put(cpu_node); ++ of_node_put(cpus_node); ++ ++ if (ret) { ++ /* Update the CPU present map to reflect uniprocessor mode */ ++ pr_warn("disabling SMP\n"); ++ init_cpu_present(&only_cpu_0); ++ } ++} ++ ++/* ++ * The ROM code has the secondary cores looping, waiting for an event. ++ * When an event occurs each core examines the bottom two bits of the ++ * secondary boot register. When a core finds those bits contain its ++ * own core id, it performs initialization, including computing its boot ++ * address by clearing the boot register value's bottom two bits. The ++ * core signals that it is beginning its execution by writing its boot ++ * address back to the secondary boot register, and finally jumps to ++ * that address. ++ * ++ * So to start a core executing we need to: ++ * - Encode the (hardware) CPU id with the bottom bits of the secondary ++ * start address. ++ * - Write that value into the secondary boot register. ++ * - Generate an event to wake up the secondary CPU(s). ++ * - Wait for the secondary boot register to be re-written, which ++ * indicates the secondary core has started. ++ */ ++static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) ++{ ++ void __iomem *boot_reg; ++ phys_addr_t boot_func; ++ u64 start_clock; ++ u32 cpu_id; ++ u32 boot_val; ++ bool timeout = false; ++ ++ cpu_id = cpu_logical_map(cpu); ++ if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { ++ pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); ++ return -EINVAL; ++ } ++ ++ if (!secondary_boot_addr) { ++ pr_err("required secondary boot register not specified\n"); ++ return -EINVAL; ++ } ++ ++ boot_reg = ioremap_nocache( ++ (phys_addr_t)secondary_boot_addr, sizeof(u32)); ++ if (!boot_reg) { ++ pr_err("unable to map boot register for cpu %u\n", cpu_id); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Secondary cores will start in secondary_startup(), ++ * defined in "arch/arm/kernel/head.S" ++ */ ++ boot_func = virt_to_phys(secondary_startup); ++ BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); ++ BUG_ON(boot_func > (phys_addr_t)U32_MAX); ++ ++ /* The core to start is encoded in the low bits */ ++ boot_val = (u32)boot_func | cpu_id; ++ writel_relaxed(boot_val, boot_reg); ++ ++ sev(); ++ ++ /* The low bits will be cleared once the core has started */ ++ start_clock = local_clock(); ++ while (!timeout && readl_relaxed(boot_reg) == boot_val) ++ timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; ++ ++ iounmap(boot_reg); ++ ++ if (!timeout) ++ return 0; ++ ++ pr_err("timeout waiting for cpu %u to start\n", cpu_id); ++ ++ return -ENXIO; ++} ++ ++static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle) ++{ ++ int ret; ++ ++ /* ++ * After wake up, secondary core branches to the startup ++ * address programmed at SKU ROM LUT location. ++ */ ++ ret = nsp_write_lut(); ++ if (ret) { ++ pr_err("unable to write startup addr to SKU ROM LUT\n"); ++ goto out; ++ } ++ ++ /* Send a CPU wakeup interrupt to the secondary core */ ++ arch_send_wakeup_ipi_mask(cpumask_of(cpu)); ++ ++out: ++ return ret; ++} ++ ++static struct smp_operations bcm_smp_ops __initdata = { ++ .smp_prepare_cpus = bcm_smp_prepare_cpus, ++ .smp_boot_secondary = kona_boot_secondary, ++}; ++CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", ++ &bcm_smp_ops); ++ ++struct smp_operations nsp_smp_ops __initdata = { ++ .smp_prepare_cpus = bcm_smp_prepare_cpus, ++ .smp_boot_secondary = nsp_boot_secondary, ++}; ++CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops); diff --git a/target/linux/bcm53xx/patches-4.4/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch b/target/linux/bcm53xx/patches-4.4/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch new file mode 100644 index 0000000..3c8aed0 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch @@ -0,0 +1,57 @@ +From 16e1bf7dde22ee22a331aabf824cc31a6794a4cb Mon Sep 17 00:00:00 2001 +From: Jon Mason <jonmason@broadcom.com> +Date: Thu, 15 Oct 2015 14:09:10 -0400 +Subject: [PATCH 134/134] ARM: BCM: Add SMP support for Broadcom 4708 + +Add SMP support for Broadcom's 4708 SoCs. + +Signed-off-by: Jon Mason <jonmason@broadcom.com> +Acked-by: Hauke Mehrtens <hauke@hauke-m.de> +Tested-by: Hauke Mehrtens <hauke@hauke-m.de> +Signed-off-by: Kapil Hali <kapilh@broadcom.com> +--- + arch/arm/boot/dts/bcm4708.dtsi | 2 ++ + arch/arm/mach-bcm/Kconfig | 1 + + arch/arm/mach-bcm/Makefile | 3 +++ + 3 files changed, 6 insertions(+) + +--- a/arch/arm/boot/dts/bcm4708.dtsi ++++ b/arch/arm/boot/dts/bcm4708.dtsi +@@ -15,6 +15,7 @@ + cpus { + #address-cells = <1>; + #size-cells = <0>; ++ enable-method = "brcm,bcm-nsp-smp"; + + cpu@0 { + device_type = "cpu"; +@@ -27,6 +28,7 @@ + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; ++ secondary-boot-reg = <0xffff0400>; + reg = <0x1>; + }; + }; +--- a/arch/arm/mach-bcm/Kconfig ++++ b/arch/arm/mach-bcm/Kconfig +@@ -55,6 +55,7 @@ config ARCH_BCM_5301X + select ARM_ERRATA_754322 + select ARM_ERRATA_775420 + select ARM_ERRATA_764369 if SMP ++ select HAVE_SMP + + help + Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. +--- a/arch/arm/mach-bcm/Makefile ++++ b/arch/arm/mach-bcm/Makefile +@@ -39,6 +39,9 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2 + + # BCM5301X + obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o ++ifeq ($(CONFIG_ARCH_BCM_5301X),y) ++obj-$(CONFIG_SMP) += platsmp.o ++endif + + # BCM63XXx + ifeq ($(CONFIG_ARCH_BCM_63XX),y) diff --git a/target/linux/bcm53xx/patches-4.4/150-PCI-iproc-Update-iProc-PCIe-device-tree-binding.patch b/target/linux/bcm53xx/patches-4.4/150-PCI-iproc-Update-iProc-PCIe-device-tree-binding.patch new file mode 100644 index 0000000..7d6949f --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/150-PCI-iproc-Update-iProc-PCIe-device-tree-binding.patch @@ -0,0 +1,29 @@ +From d85a955118c8d8679d4f746fe2189c172d7c365f Mon Sep 17 00:00:00 2001 +From: Ray Jui <rjui@broadcom.com> +Date: Mon, 16 Nov 2015 17:18:05 -0800 +Subject: [PATCH 150/154] PCI: iproc: Update iProc PCIe device tree binding + +Add a new compatible string "brcm,iproc-pcie-paxc", for PAXC based iProc +PCIe root complex. A PAXC based PCIe root complex is connected to +emulated endpoint devices internal to the ASIC + +Signed-off-by: Ray Jui <rjui@broadcom.com> +Reviewed-by: Scott Branden <sbranden@broadcom.com> +--- + Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt ++++ b/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt +@@ -1,7 +1,10 @@ + * Broadcom iProc PCIe controller with the platform bus interface + + Required properties: +-- compatible: Must be "brcm,iproc-pcie" ++- compatible: Must be "brcm,iproc-pcie" for PAXB, or "brcm,iproc-pcie-paxc" ++ for PAXC. PAXB based root complex is used for external endpoint devices. ++ PAXC based root complex is connected to emulated endpoint devices ++ internal to the ASIC + - reg: base address and length of the PCIe controller I/O register space + - #interrupt-cells: set to <1> + - interrupt-map-mask and interrupt-map, standard PCI properties to define the diff --git a/target/linux/bcm53xx/patches-4.4/151-PCI-iproc-Add-PAXC-interface-support.patch b/target/linux/bcm53xx/patches-4.4/151-PCI-iproc-Add-PAXC-interface-support.patch new file mode 100644 index 0000000..9b7b762 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/151-PCI-iproc-Add-PAXC-interface-support.patch @@ -0,0 +1,428 @@ +From a13fc4733b25d6dad6ec1826f09225c69ee21e3a Mon Sep 17 00:00:00 2001 +From: Ray Jui <rjui@broadcom.com> +Date: Mon, 16 Nov 2015 17:41:43 -0800 +Subject: [PATCH 151/154] PCI: iproc: Add PAXC interface support + +Traditionally, all iProc PCIe root complexes use PAXB based wrapper, +with an integrated on-chip Serdes to support external endpoint devices. +On newer iProc platforms, a PAXC based wrapper is introduced, for +connection with internally emulated PCIe endpoint devices in the ASIC + +This patch adds support for PAXC based iProc PCIe root complex in the +iProc PCIe core driver. This change fators out common logic between +PAXB and PAXC, and use tables to store register offsets that are +different between PAXB and PAXC. This allows the driver to be scaled to +support subsequent PAXC revisions in the future + +Signed-off-by: Ray Jui <rjui@broadcom.com> +Reviewed-by: Scott Branden <sbranden@broadcom.com> +--- + drivers/pci/host/pcie-iproc-platform.c | 24 +++- + drivers/pci/host/pcie-iproc.c | 202 +++++++++++++++++++++++++++------ + drivers/pci/host/pcie-iproc.h | 19 ++++ + 3 files changed, 205 insertions(+), 40 deletions(-) + +--- a/drivers/pci/host/pcie-iproc-platform.c ++++ b/drivers/pci/host/pcie-iproc-platform.c +@@ -26,8 +26,21 @@ + + #include "pcie-iproc.h" + ++static const struct of_device_id iproc_pcie_of_match_table[] = { ++ { ++ .compatible = "brcm,iproc-pcie", ++ .data = (int *)IPROC_PCIE_PAXB, ++ }, { ++ .compatible = "brcm,iproc-pcie-paxc", ++ .data = (int *)IPROC_PCIE_PAXC, ++ }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, iproc_pcie_of_match_table); ++ + static int iproc_pcie_pltfm_probe(struct platform_device *pdev) + { ++ const struct of_device_id *of_id; + struct iproc_pcie *pcie; + struct device_node *np = pdev->dev.of_node; + struct resource reg; +@@ -35,11 +48,16 @@ static int iproc_pcie_pltfm_probe(struct + LIST_HEAD(res); + int ret; + ++ of_id = of_match_device(iproc_pcie_of_match_table, &pdev->dev); ++ if (!of_id) ++ return -EINVAL; ++ + pcie = devm_kzalloc(&pdev->dev, sizeof(struct iproc_pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->dev = &pdev->dev; ++ pcie->type = (enum iproc_pcie_type)of_id->data; + platform_set_drvdata(pdev, pcie); + + ret = of_address_to_resource(np, 0, ®); +@@ -114,12 +132,6 @@ static int iproc_pcie_pltfm_remove(struc + return iproc_pcie_remove(pcie); + } + +-static const struct of_device_id iproc_pcie_of_match_table[] = { +- { .compatible = "brcm,iproc-pcie", }, +- { /* sentinel */ } +-}; +-MODULE_DEVICE_TABLE(of, iproc_pcie_of_match_table); +- + static struct platform_driver iproc_pcie_pltfm_driver = { + .driver = { + .name = "iproc-pcie", +--- a/drivers/pci/host/pcie-iproc.c ++++ b/drivers/pci/host/pcie-iproc.c +@@ -30,20 +30,16 @@ + + #include "pcie-iproc.h" + +-#define CLK_CONTROL_OFFSET 0x000 + #define EP_PERST_SOURCE_SELECT_SHIFT 2 + #define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT) + #define EP_MODE_SURVIVE_PERST_SHIFT 1 + #define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT) + #define RC_PCIE_RST_OUTPUT_SHIFT 0 + #define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT) ++#define PAXC_RESET_MASK 0x7f + +-#define CFG_IND_ADDR_OFFSET 0x120 + #define CFG_IND_ADDR_MASK 0x00001ffc + +-#define CFG_IND_DATA_OFFSET 0x124 +- +-#define CFG_ADDR_OFFSET 0x1f8 + #define CFG_ADDR_BUS_NUM_SHIFT 20 + #define CFG_ADDR_BUS_NUM_MASK 0x0ff00000 + #define CFG_ADDR_DEV_NUM_SHIFT 15 +@@ -55,12 +51,8 @@ + #define CFG_ADDR_CFG_TYPE_SHIFT 0 + #define CFG_ADDR_CFG_TYPE_MASK 0x00000003 + +-#define CFG_DATA_OFFSET 0x1fc +- +-#define SYS_RC_INTX_EN 0x330 + #define SYS_RC_INTX_MASK 0xf + +-#define PCIE_LINK_STATUS_OFFSET 0xf0c + #define PCIE_PHYLINKUP_SHIFT 3 + #define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT) + #define PCIE_DL_ACTIVE_SHIFT 2 +@@ -71,12 +63,54 @@ + #define OARR_SIZE_CFG_SHIFT 1 + #define OARR_SIZE_CFG BIT(OARR_SIZE_CFG_SHIFT) + +-#define OARR_LO(window) (0xd20 + (window) * 8) +-#define OARR_HI(window) (0xd24 + (window) * 8) +-#define OMAP_LO(window) (0xd40 + (window) * 8) +-#define OMAP_HI(window) (0xd44 + (window) * 8) +- + #define MAX_NUM_OB_WINDOWS 2 ++#define MAX_NUM_PAXC_PF 4 ++ ++#define IPROC_PCIE_REG_INVALID 0xffff ++ ++enum iproc_pcie_reg { ++ IPROC_PCIE_CLK_CTRL = 0, ++ IPROC_PCIE_CFG_IND_ADDR, ++ IPROC_PCIE_CFG_IND_DATA, ++ IPROC_PCIE_CFG_ADDR, ++ IPROC_PCIE_CFG_DATA, ++ IPROC_PCIE_INTX_EN, ++ IPROC_PCIE_OARR_LO, ++ IPROC_PCIE_OARR_HI, ++ IPROC_PCIE_OMAP_LO, ++ IPROC_PCIE_OMAP_HI, ++ IPROC_PCIE_LINK_STATUS, ++}; ++ ++/* iProc PCIe PAXB registers */ ++static const u16 iproc_pcie_reg_paxb[] = { ++ [IPROC_PCIE_CLK_CTRL] = 0x000, ++ [IPROC_PCIE_CFG_IND_ADDR] = 0x120, ++ [IPROC_PCIE_CFG_IND_DATA] = 0x124, ++ [IPROC_PCIE_CFG_ADDR] = 0x1f8, ++ [IPROC_PCIE_CFG_DATA] = 0x1fc, ++ [IPROC_PCIE_INTX_EN] = 0x330, ++ [IPROC_PCIE_OARR_LO] = 0xd20, ++ [IPROC_PCIE_OARR_HI] = 0xd24, ++ [IPROC_PCIE_OMAP_LO] = 0xd40, ++ [IPROC_PCIE_OMAP_HI] = 0xd44, ++ [IPROC_PCIE_LINK_STATUS] = 0xf0c, ++}; ++ ++/* iProc PCIe PAXC v1 registers */ ++static const u16 iproc_pcie_reg_paxc[] = { ++ [IPROC_PCIE_CLK_CTRL] = 0x000, ++ [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0, ++ [IPROC_PCIE_CFG_IND_DATA] = 0x1f4, ++ [IPROC_PCIE_CFG_ADDR] = 0x1f8, ++ [IPROC_PCIE_CFG_DATA] = 0x1fc, ++ [IPROC_PCIE_INTX_EN] = IPROC_PCIE_REG_INVALID, ++ [IPROC_PCIE_OARR_LO] = IPROC_PCIE_REG_INVALID, ++ [IPROC_PCIE_OARR_HI] = IPROC_PCIE_REG_INVALID, ++ [IPROC_PCIE_OMAP_LO] = IPROC_PCIE_REG_INVALID, ++ [IPROC_PCIE_OMAP_HI] = IPROC_PCIE_REG_INVALID, ++ [IPROC_PCIE_LINK_STATUS] = IPROC_PCIE_REG_INVALID, ++}; + + static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) + { +@@ -91,6 +125,65 @@ static inline struct iproc_pcie *iproc_d + return pcie; + } + ++static inline bool iproc_pcie_reg_is_invalid(u16 reg_offset) ++{ ++ return !!(reg_offset == IPROC_PCIE_REG_INVALID); ++} ++ ++static inline u16 iproc_pcie_reg_offset(struct iproc_pcie *pcie, ++ enum iproc_pcie_reg reg) ++{ ++ return pcie->reg_offsets[reg]; ++} ++ ++static inline u32 iproc_pcie_read_reg(struct iproc_pcie *pcie, ++ enum iproc_pcie_reg reg) ++{ ++ u16 offset = iproc_pcie_reg_offset(pcie, reg); ++ ++ if (iproc_pcie_reg_is_invalid(offset)) ++ return 0; ++ ++ return readl(pcie->base + offset); ++} ++ ++static inline void iproc_pcie_write_reg(struct iproc_pcie *pcie, ++ enum iproc_pcie_reg reg, u32 val) ++{ ++ u16 offset = iproc_pcie_reg_offset(pcie, reg); ++ ++ if (iproc_pcie_reg_is_invalid(offset)) ++ return; ++ ++ writel(val, pcie->base + offset); ++} ++ ++static inline void iproc_pcie_ob_write(struct iproc_pcie *pcie, ++ enum iproc_pcie_reg reg, ++ unsigned window, u32 val) ++{ ++ u16 offset = iproc_pcie_reg_offset(pcie, reg); ++ ++ if (iproc_pcie_reg_is_invalid(offset)) ++ return; ++ ++ writel(val, pcie->base + offset + (window * 8)); ++} ++ ++static inline bool iproc_pcie_device_is_valid(struct iproc_pcie *pcie, ++ unsigned int slot, ++ unsigned int fn) ++{ ++ if (slot > 0) ++ return false; ++ ++ /* PAXC can only support limited number of functions */ ++ if (pcie->type == IPROC_PCIE_PAXC && fn >= MAX_NUM_PAXC_PF) ++ return false; ++ ++ return true; ++} ++ + /** + * Note access to the configuration registers are protected at the higher layer + * by 'pci_lock' in drivers/pci/access.c +@@ -104,28 +197,34 @@ static void __iomem *iproc_pcie_map_cfg_ + unsigned fn = PCI_FUNC(devfn); + unsigned busno = bus->number; + u32 val; ++ u16 offset; ++ ++ if (!iproc_pcie_device_is_valid(pcie, slot, fn)) ++ return NULL; + + /* root complex access */ + if (busno == 0) { +- if (slot >= 1) ++ iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR, ++ where & CFG_IND_ADDR_MASK); ++ offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_IND_DATA); ++ if (iproc_pcie_reg_is_invalid(offset)) + return NULL; +- writel(where & CFG_IND_ADDR_MASK, +- pcie->base + CFG_IND_ADDR_OFFSET); +- return (pcie->base + CFG_IND_DATA_OFFSET); ++ else ++ return (pcie->base + offset); + } + +- if (fn > 1) +- return NULL; +- + /* EP device access */ + val = (busno << CFG_ADDR_BUS_NUM_SHIFT) | + (slot << CFG_ADDR_DEV_NUM_SHIFT) | + (fn << CFG_ADDR_FUNC_NUM_SHIFT) | + (where & CFG_ADDR_REG_NUM_MASK) | + (1 & CFG_ADDR_CFG_TYPE_MASK); +- writel(val, pcie->base + CFG_ADDR_OFFSET); +- +- return (pcie->base + CFG_DATA_OFFSET); ++ iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_ADDR, val); ++ offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA); ++ if (iproc_pcie_reg_is_invalid(offset)) ++ return NULL; ++ else ++ return (pcie->base + offset); + } + + static struct pci_ops iproc_pcie_ops = { +@@ -138,18 +237,29 @@ static void iproc_pcie_reset(struct ipro + { + u32 val; + ++ if (pcie->type == IPROC_PCIE_PAXC) { ++ val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); ++ val &= ~PAXC_RESET_MASK; ++ iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); ++ udelay(100); ++ val |= PAXC_RESET_MASK; ++ iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); ++ udelay(100); ++ return; ++ } ++ + /* + * Select perst_b signal as reset source. Put the device into reset, + * and then bring it out of reset + */ +- val = readl(pcie->base + CLK_CONTROL_OFFSET); ++ val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); + val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST & + ~RC_PCIE_RST_OUTPUT; +- writel(val, pcie->base + CLK_CONTROL_OFFSET); ++ iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); + udelay(250); + + val |= RC_PCIE_RST_OUTPUT; +- writel(val, pcie->base + CLK_CONTROL_OFFSET); ++ iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); + msleep(100); + } + +@@ -160,7 +270,14 @@ static int iproc_pcie_check_link(struct + u16 pos, link_status; + bool link_is_active = false; + +- val = readl(pcie->base + PCIE_LINK_STATUS_OFFSET); ++ /* ++ * PAXC connects to emulated endpoint devices directly and does not ++ * have a Serdes. Therefore skip the link detection logic here ++ */ ++ if (pcie->type == IPROC_PCIE_PAXC) ++ return 0; ++ ++ val = iproc_pcie_read_reg(pcie, IPROC_PCIE_LINK_STATUS); + if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) { + dev_err(pcie->dev, "PHY or data link is INACTIVE!\n"); + return -ENODEV; +@@ -221,7 +338,7 @@ static int iproc_pcie_check_link(struct + + static void iproc_pcie_enable(struct iproc_pcie *pcie) + { +- writel(SYS_RC_INTX_MASK, pcie->base + SYS_RC_INTX_EN); ++ iproc_pcie_write_reg(pcie, IPROC_PCIE_INTX_EN, SYS_RC_INTX_MASK); + } + + /** +@@ -272,11 +389,15 @@ static int iproc_pcie_setup_ob(struct ip + axi_addr -= ob->axi_offset; + + for (i = 0; i < MAX_NUM_OB_WINDOWS; i++) { +- writel(lower_32_bits(axi_addr) | OARR_VALID | +- (ob->set_oarr_size ? 1 : 0), pcie->base + OARR_LO(i)); +- writel(upper_32_bits(axi_addr), pcie->base + OARR_HI(i)); +- writel(lower_32_bits(pci_addr), pcie->base + OMAP_LO(i)); +- writel(upper_32_bits(pci_addr), pcie->base + OMAP_HI(i)); ++ iproc_pcie_ob_write(pcie, IPROC_PCIE_OARR_LO, i, ++ lower_32_bits(axi_addr) | OARR_VALID | ++ (ob->set_oarr_size ? 1 : 0)); ++ iproc_pcie_ob_write(pcie, IPROC_PCIE_OARR_HI, i, ++ upper_32_bits(axi_addr)); ++ iproc_pcie_ob_write(pcie, IPROC_PCIE_OMAP_LO, i, ++ lower_32_bits(pci_addr)); ++ iproc_pcie_ob_write(pcie, IPROC_PCIE_OMAP_HI, i, ++ upper_32_bits(pci_addr)); + + size -= ob->window_size; + if (size == 0) +@@ -340,6 +461,19 @@ int iproc_pcie_setup(struct iproc_pcie * + goto err_exit_phy; + } + ++ switch (pcie->type) { ++ case IPROC_PCIE_PAXB: ++ pcie->reg_offsets = iproc_pcie_reg_paxb; ++ break; ++ case IPROC_PCIE_PAXC: ++ pcie->reg_offsets = iproc_pcie_reg_paxc; ++ break; ++ default: ++ dev_err(pcie->dev, "incompatible iProc PCIe interface\n"); ++ ret = -EINVAL; ++ goto err_power_off_phy; ++ } ++ + iproc_pcie_reset(pcie); + + if (pcie->need_ob_cfg) { +--- a/drivers/pci/host/pcie-iproc.h ++++ b/drivers/pci/host/pcie-iproc.h +@@ -15,6 +15,20 @@ + #define _PCIE_IPROC_H + + /** ++ * iProc PCIe interface type ++ * ++ * PAXB is the wrapper used in root complex that can be connected to an ++ * external endpoint device ++ * ++ * PAXC is the wrapper used in root complex dedicated for internal emulated ++ * endpoint devices ++ */ ++enum iproc_pcie_type { ++ IPROC_PCIE_PAXB = 0, ++ IPROC_PCIE_PAXC, ++}; ++ ++/** + * iProc PCIe outbound mapping + * @set_oarr_size: indicates the OARR size bit needs to be set + * @axi_offset: offset from the AXI address to the internal address used by +@@ -29,7 +43,10 @@ struct iproc_pcie_ob { + + /** + * iProc PCIe device ++ * + * @dev: pointer to device data structure ++ * @type: iProc PCIe interface type ++ * @reg_offsets: register offsets + * @base: PCIe host controller I/O register base + * @sysdata: Per PCI controller data (ARM-specific) + * @root_bus: pointer to root bus +@@ -41,6 +58,8 @@ struct iproc_pcie_ob { + */ + struct iproc_pcie { + struct device *dev; ++ enum iproc_pcie_type type; ++ const u16 *reg_offsets; + void __iomem *base; + #ifdef CONFIG_ARM + struct pci_sys_data sysdata; diff --git a/target/linux/bcm53xx/patches-4.4/152-PCI-iproc-Add-iProc-PCIe-MSI-device-tree-binding.patch b/target/linux/bcm53xx/patches-4.4/152-PCI-iproc-Add-iProc-PCIe-MSI-device-tree-binding.patch new file mode 100644 index 0000000..f0b0031 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/152-PCI-iproc-Add-iProc-PCIe-MSI-device-tree-binding.patch @@ -0,0 +1,67 @@ +From 96b40de5e36ec479dabb88500f1830a87818a809 Mon Sep 17 00:00:00 2001 +From: Ray Jui <rjui@broadcom.com> +Date: Mon, 16 Nov 2015 17:57:33 -0800 +Subject: [PATCH 152/154] PCI: iproc: Add iProc PCIe MSI device tree binding + +This patch updates the iProc PCIe device tree bindings with added +binding information for MSI + +Signed-off-by: Ray Jui <rjui@broadcom.com> +Reviewed-by: Anup Patel <anup.patel@broadcom.com> +Reviewed-by: Vikram Prakash <vikramp@broadcom.com> +Reviewed-by: Scott Branden <sbranden@broadcom.com> +--- + .../devicetree/bindings/pci/brcm,iproc-pcie.txt | 35 ++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +--- a/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt ++++ b/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt +@@ -35,6 +35,28 @@ Optional: + - brcm,pcie-ob-oarr-size: Some iProc SoCs need the OARR size bit to be set to + increase the outbound window size + ++MSI support (optional): ++ ++For older platforms without MSI integrated in the GIC, iProc PCIe core provides ++an event queue based MSI support. The iProc MSI uses host memories to store ++MSI posted writes in the event queues ++ ++- msi-parent: Link to the device node of the MSI controller. On newer iProc ++platforms, the MSI controller may be gicv2m or gicv3-its. On older iProc ++platforms without MSI support in its interrupt controller, one may use the ++event queue based MSI support integrated within the iProc PCIe core ++ ++When the iProc event queue based MSI is used, one needs to define the ++following properties in the MSI device node: ++- compatible: Must be "brcm,iproc-msi" ++- msi-controller: claims itself as an MSI controller ++- interrupt-parent: Link to its parent interrupt device ++- interrupts: List of interrupt IDs from its parent interrupt device ++ ++Optional properties: ++- brcm,pcie-msi-inten: Needs to be present for some older iProc platforms that ++require the interrupt enable registers to be set explicitly to enable MSI ++ + Example: + pcie0: pcie@18012000 { + compatible = "brcm,iproc-pcie"; +@@ -61,6 +83,19 @@ Example: + brcm,pcie-ob-oarr-size; + brcm,pcie-ob-axi-offset = <0x00000000>; + brcm,pcie-ob-window-size = <256>; ++ ++ msi-parent = <&msi0>; ++ ++ /* iProc event queue based MSI */ ++ msi0: msi@18012000 { ++ compatible = "brcm,iproc-msi"; ++ msi-controller; ++ interrupt-parent = <&gic>; ++ interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>, ++ <GIC_SPI 97 IRQ_TYPE_NONE>, ++ <GIC_SPI 98 IRQ_TYPE_NONE>, ++ <GIC_SPI 99 IRQ_TYPE_NONE>, ++ }; + }; + + pcie1: pcie@18013000 { diff --git a/target/linux/bcm53xx/patches-4.4/153-PCI-iproc-Add-iProc-PCIe-MSI-support.patch b/target/linux/bcm53xx/patches-4.4/153-PCI-iproc-Add-iProc-PCIe-MSI-support.patch new file mode 100644 index 0000000..d52e557 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/153-PCI-iproc-Add-iProc-PCIe-MSI-support.patch @@ -0,0 +1,887 @@ +From c81922174d61127ff5baad6059ae148794c72276 Mon Sep 17 00:00:00 2001 +From: Ray Jui <rjui@broadcom.com> +Date: Tue, 17 Nov 2015 13:14:37 -0800 +Subject: [PATCH 153/154] PCI: iproc: Add iProc PCIe MSI support + +This patch adds PCIe MSI support for both PAXB and PAXC interfaces on +all iProc based platforms + +The iProc PCIe MSI support deploys an event queue based implementation. +Each event queue is serviced by a GIC interrupt and can support up to 64 +MSI vectors. Host memory is allocated for the event queues, and each event +queue consists of 64 word-sized entries. MSI data is written to the +lower 16-bit of each entry, whereas the upper 16-bit of the entry is +reserved for the controller for internal processing + +Each event queue is tracked by a head pointer and tail pointer. Head +pointer indicates the next entry in the event queue to be processed by +the driver and is updated by the driver after processing is done. +The controller uses the tail pointer as the next MSI data insertion +point. The controller ensures MSI data is flushed to host memory before +updating the tail pointer and then triggering the interrupt + +MSI IRQ affinity is supported by evenly distributing the interrupts to +each CPU core. MSI vector is moved from one GIC interrupt to another in +order to steer to the target CPU + +Therefore, the actual number of supported MSI vectors is: + +M * 64 / N + +where M denotes the number of GIC interrupts (event queues), and N +denotes the number of CPU cores + +This iProc event queue based MSI support should not be used with newer +platforms with integrated MSI support in the GIC (e.g., giv2m or +gicv3-its) + +Signed-off-by: Ray Jui <rjui@broadcom.com> +Reviewed-by: Anup Patel <anup.patel@broadcom.com> +Reviewed-by: Vikram Prakash <vikramp@broadcom.com> +Reviewed-by: Scott Branden <sbranden@broadcom.com> +--- + drivers/pci/host/Kconfig | 9 + + drivers/pci/host/Makefile | 1 + + drivers/pci/host/pcie-iproc-bcma.c | 1 + + drivers/pci/host/pcie-iproc-msi.c | 675 +++++++++++++++++++++++++++++++++ + drivers/pci/host/pcie-iproc-platform.c | 1 + + drivers/pci/host/pcie-iproc.c | 26 ++ + drivers/pci/host/pcie-iproc.h | 23 +- + 7 files changed, 734 insertions(+), 2 deletions(-) + create mode 100644 drivers/pci/host/pcie-iproc-msi.c + +--- a/drivers/pci/host/Kconfig ++++ b/drivers/pci/host/Kconfig +@@ -126,6 +126,15 @@ config PCIE_IPROC + iProc family of SoCs. An appropriate bus interface driver also needs + to be enabled + ++config PCIE_IPROC_MSI ++ bool "Broadcom iProc PCIe MSI support" ++ depends on ARCH_BCM_IPROC && PCI_MSI ++ select PCI_MSI_IRQ_DOMAIN ++ default ARCH_BCM_IPROC ++ help ++ Say Y here if you want to enable MSI support for Broadcom's iProc ++ PCIe controller ++ + config PCIE_IPROC_PLATFORM + tristate "Broadcom iProc PCIe platform bus driver" + depends on ARCH_BCM_IPROC || (ARM && COMPILE_TEST) +--- a/drivers/pci/host/Makefile ++++ b/drivers/pci/host/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene + obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o + obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o + obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o ++obj-$(CONFIG_PCIE_IPROC_MSI) += pcie-iproc-msi.o + obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o + obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o + obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o +--- a/drivers/pci/host/pcie-iproc-bcma.c ++++ b/drivers/pci/host/pcie-iproc-bcma.c +@@ -55,6 +55,7 @@ static int iproc_pcie_bcma_probe(struct + bcma_set_drvdata(bdev, pcie); + + pcie->base = bdev->io_addr; ++ pcie->base_addr = bdev->addr; + + res_mem.start = bdev->addr_s[0]; + res_mem.end = bdev->addr_s[0] + SZ_128M - 1; +--- /dev/null ++++ b/drivers/pci/host/pcie-iproc-msi.c +@@ -0,0 +1,675 @@ ++/* ++ * Copyright (C) 2015 Broadcom Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/interrupt.h> ++#include <linux/irqchip/chained_irq.h> ++#include <linux/irqdomain.h> ++#include <linux/msi.h> ++#include <linux/of_irq.h> ++#include <linux/of_pci.h> ++#include <linux/pci.h> ++ ++#include "pcie-iproc.h" ++ ++#define IPROC_MSI_INTR_EN_SHIFT 11 ++#define IPROC_MSI_INTR_EN BIT(IPROC_MSI_INTR_EN_SHIFT) ++#define IPROC_MSI_INT_N_EVENT_SHIFT 1 ++#define IPROC_MSI_INT_N_EVENT BIT(IPROC_MSI_INT_N_EVENT_SHIFT) ++#define IPROC_MSI_EQ_EN_SHIFT 0 ++#define IPROC_MSI_EQ_EN BIT(IPROC_MSI_EQ_EN_SHIFT) ++ ++#define IPROC_MSI_EQ_MASK 0x3f ++ ++/* max number of GIC interrupts */ ++#define NR_HW_IRQS 6 ++ ++/* number of entries in each event queue */ ++#define EQ_LEN 64 ++ ++/* size of each event queue memory region */ ++#define EQ_MEM_REGION_SIZE SZ_4K ++ ++/* size of each MSI address region */ ++#define MSI_MEM_REGION_SIZE SZ_4K ++ ++enum iproc_msi_reg { ++ IPROC_MSI_EQ_PAGE = 0, ++ IPROC_MSI_EQ_PAGE_UPPER, ++ IPROC_MSI_PAGE, ++ IPROC_MSI_PAGE_UPPER, ++ IPROC_MSI_CTRL, ++ IPROC_MSI_EQ_HEAD, ++ IPROC_MSI_EQ_TAIL, ++ IPROC_MSI_INTS_EN, ++ IPROC_MSI_REG_SIZE, ++}; ++ ++struct iproc_msi; ++ ++/** ++ * iProc MSI group ++ * ++ * One MSI group is allocated per GIC interrupt, serviced by one iProc MSI ++ * event queue ++ * ++ * @msi: pointer to iProc MSI data ++ * @gic_irq: GIC interrupt ++ * @eq: Event queue number ++ */ ++struct iproc_msi_grp { ++ struct iproc_msi *msi; ++ int gic_irq; ++ unsigned int eq; ++}; ++ ++/** ++ * iProc event queue based MSI ++ * ++ * Only meant to be used on platforms without MSI support integrated into the ++ * GIC ++ * ++ * @pcie: pointer to iProc PCIe data ++ * @reg_offsets: MSI register offsets ++ * @grps: MSI groups ++ * @nr_irqs: number of total interrupts connected to GIC ++ * @nr_cpus: number of toal CPUs ++ * @has_inten_reg: indicates the MSI interrupt enable register needs to be ++ * set explicitly (required for some legacy platforms) ++ * @bitmap: MSI vector bitmap ++ * @bitmap_lock: lock to protect access to the MSI bitmap ++ * @nr_msi_vecs: total number of MSI vectors ++ * @inner_domain: inner IRQ domain ++ * @msi_domain: MSI IRQ domain ++ * @nr_eq_region: required number of 4K aligned memory region for MSI event ++ * queues ++ * @nr_msi_region: required number of 4K aligned address region for MSI posted ++ * writes ++ * @eq_cpu: pointer to allocated memory region for MSI event queues ++ * @eq_dma: DMA address of MSI event queues ++ * @msi_addr: MSI address ++ */ ++struct iproc_msi { ++ struct iproc_pcie *pcie; ++ const u16 (*reg_offsets)[IPROC_MSI_REG_SIZE]; ++ struct iproc_msi_grp *grps; ++ int nr_irqs; ++ int nr_cpus; ++ bool has_inten_reg; ++ unsigned long *bitmap; ++ struct mutex bitmap_lock; ++ unsigned int nr_msi_vecs; ++ struct irq_domain *inner_domain; ++ struct irq_domain *msi_domain; ++ unsigned int nr_eq_region; ++ unsigned int nr_msi_region; ++ void *eq_cpu; ++ dma_addr_t eq_dma; ++ phys_addr_t msi_addr; ++}; ++ ++static const u16 iproc_msi_reg_paxb[NR_HW_IRQS][IPROC_MSI_REG_SIZE] = { ++ { 0x200, 0x2c0, 0x204, 0x2c4, 0x210, 0x250, 0x254, 0x208 }, ++ { 0x200, 0x2c0, 0x204, 0x2c4, 0x214, 0x258, 0x25c, 0x208 }, ++ { 0x200, 0x2c0, 0x204, 0x2c4, 0x218, 0x260, 0x264, 0x208 }, ++ { 0x200, 0x2c0, 0x204, 0x2c4, 0x21c, 0x268, 0x26c, 0x208 }, ++ { 0x200, 0x2c0, 0x204, 0x2c4, 0x220, 0x270, 0x274, 0x208 }, ++ { 0x200, 0x2c0, 0x204, 0x2c4, 0x224, 0x278, 0x27c, 0x208 }, ++}; ++ ++static const u16 iproc_msi_reg_paxc[NR_HW_IRQS][IPROC_MSI_REG_SIZE] = { ++ { 0xc00, 0xc04, 0xc08, 0xc0c, 0xc40, 0xc50, 0xc60 }, ++ { 0xc10, 0xc14, 0xc18, 0xc1c, 0xc44, 0xc54, 0xc64 }, ++ { 0xc20, 0xc24, 0xc28, 0xc2c, 0xc48, 0xc58, 0xc68 }, ++ { 0xc30, 0xc34, 0xc38, 0xc3c, 0xc4c, 0xc5c, 0xc6c }, ++}; ++ ++static inline u32 iproc_msi_read_reg(struct iproc_msi *msi, ++ enum iproc_msi_reg reg, ++ unsigned int eq) ++{ ++ struct iproc_pcie *pcie = msi->pcie; ++ ++ return readl_relaxed(pcie->base + msi->reg_offsets[eq][reg]); ++} ++ ++static inline void iproc_msi_write_reg(struct iproc_msi *msi, ++ enum iproc_msi_reg reg, ++ int eq, u32 val) ++{ ++ struct iproc_pcie *pcie = msi->pcie; ++ ++ writel_relaxed(val, pcie->base + msi->reg_offsets[eq][reg]); ++} ++ ++static inline u32 hwirq_to_group(struct iproc_msi *msi, unsigned long hwirq) ++{ ++ return (hwirq % msi->nr_irqs); ++} ++ ++static inline unsigned int iproc_msi_addr_offset(struct iproc_msi *msi, ++ unsigned long hwirq) ++{ ++ if (msi->nr_msi_region > 1) ++ return hwirq_to_group(msi, hwirq) * MSI_MEM_REGION_SIZE; ++ else ++ return hwirq_to_group(msi, hwirq) * sizeof(u32); ++} ++ ++static inline unsigned int iproc_msi_eq_offset(struct iproc_msi *msi, u32 eq) ++{ ++ if (msi->nr_eq_region > 1) ++ return eq * EQ_MEM_REGION_SIZE; ++ else ++ return eq * EQ_LEN * sizeof(u32); ++} ++ ++static struct irq_chip iproc_msi_irq_chip = { ++ .name = "iProc-MSI", ++}; ++ ++static struct msi_domain_info iproc_msi_domain_info = { ++ .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | ++ MSI_FLAG_PCI_MSIX, ++ .chip = &iproc_msi_irq_chip, ++}; ++ ++/* ++ * In iProc PCIe core, each MSI group is serviced by a GIC interrupt and a ++ * dedicated event queue. Each MSI group can support up to 64 MSI vectors ++ * ++ * The number of MSI groups varies between different iProc SoCs. The total ++ * number of CPU cores also varies. To support MSI IRQ affinity, we ++ * distribute GIC interrupts across all available CPUs. MSI vector is moved ++ * from one GIC interrupt to another to steer to the target CPU ++ * ++ * Assuming: ++ * - the number of MSI groups is M ++ * - the number of CPU cores is N ++ * - M is always a multiple of N ++ * ++ * Total number of raw MSI vectors = M * 64 ++ * Total number of supported MSI vectors = (M * 64) / N ++ */ ++static inline int hwirq_to_cpu(struct iproc_msi *msi, unsigned long hwirq) ++{ ++ return (hwirq % msi->nr_cpus); ++} ++ ++static inline unsigned long hwirq_to_canonical_hwirq(struct iproc_msi *msi, ++ unsigned long hwirq) ++{ ++ return (hwirq - hwirq_to_cpu(msi, hwirq)); ++} ++ ++static int iproc_msi_irq_set_affinity(struct irq_data *data, ++ const struct cpumask *mask, bool force) ++{ ++ struct iproc_msi *msi = irq_data_get_irq_chip_data(data); ++ int target_cpu = cpumask_first(mask); ++ int curr_cpu; ++ ++ curr_cpu = hwirq_to_cpu(msi, data->hwirq); ++ if (curr_cpu == target_cpu) ++ return IRQ_SET_MASK_OK_DONE; ++ ++ /* steer MSI to the target CPU */ ++ data->hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq) + target_cpu; ++ ++ return IRQ_SET_MASK_OK; ++} ++ ++static void iproc_msi_irq_compose_msi_msg(struct irq_data *data, ++ struct msi_msg *msg) ++{ ++ struct iproc_msi *msi = irq_data_get_irq_chip_data(data); ++ dma_addr_t addr; ++ ++ addr = msi->msi_addr + iproc_msi_addr_offset(msi, data->hwirq); ++ msg->address_lo = lower_32_bits(addr); ++ msg->address_hi = upper_32_bits(addr); ++ msg->data = data->hwirq; ++} ++ ++static struct irq_chip iproc_msi_bottom_irq_chip = { ++ .name = "MSI", ++ .irq_set_affinity = iproc_msi_irq_set_affinity, ++ .irq_compose_msi_msg = iproc_msi_irq_compose_msi_msg, ++}; ++ ++static int iproc_msi_irq_domain_alloc(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs, ++ void *args) ++{ ++ struct iproc_msi *msi = domain->host_data; ++ int hwirq; ++ ++ mutex_lock(&msi->bitmap_lock); ++ ++ /* allocate 'nr_cpus' number of MSI vectors each time */ ++ hwirq = bitmap_find_next_zero_area(msi->bitmap, msi->nr_msi_vecs, 0, ++ msi->nr_cpus, 0); ++ if (hwirq < msi->nr_msi_vecs) { ++ bitmap_set(msi->bitmap, hwirq, msi->nr_cpus); ++ } else { ++ mutex_unlock(&msi->bitmap_lock); ++ return -ENOSPC; ++ } ++ ++ mutex_unlock(&msi->bitmap_lock); ++ ++ irq_domain_set_info(domain, virq, hwirq, &iproc_msi_bottom_irq_chip, ++ domain->host_data, handle_simple_irq, NULL, NULL); ++ ++ return 0; ++} ++ ++static void iproc_msi_irq_domain_free(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs) ++{ ++ struct irq_data *data = irq_domain_get_irq_data(domain, virq); ++ struct iproc_msi *msi = irq_data_get_irq_chip_data(data); ++ unsigned int hwirq; ++ ++ mutex_lock(&msi->bitmap_lock); ++ ++ hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq); ++ bitmap_clear(msi->bitmap, hwirq, msi->nr_cpus); ++ ++ mutex_unlock(&msi->bitmap_lock); ++ ++ irq_domain_free_irqs_parent(domain, virq, nr_irqs); ++} ++ ++static const struct irq_domain_ops msi_domain_ops = { ++ .alloc = iproc_msi_irq_domain_alloc, ++ .free = iproc_msi_irq_domain_free, ++}; ++ ++static inline u32 decode_msi_hwirq(struct iproc_msi *msi, u32 eq, u32 head) ++{ ++ u32 *msg, hwirq; ++ unsigned int offs; ++ ++ offs = iproc_msi_eq_offset(msi, eq) + head * sizeof(u32); ++ msg = (u32 *)(msi->eq_cpu + offs); ++ hwirq = *msg & IPROC_MSI_EQ_MASK; ++ ++ /* ++ * Since we have multiple hwirq mapped to a single MSI vector, ++ * now we need to derive the hwirq at CPU0. It can then be used to ++ * mapped back to virq ++ */ ++ return hwirq_to_canonical_hwirq(msi, hwirq); ++} ++ ++static void iproc_msi_handler(struct irq_desc *desc) ++{ ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ struct iproc_msi_grp *grp; ++ struct iproc_msi *msi; ++ struct iproc_pcie *pcie; ++ u32 eq, head, tail, nr_events; ++ unsigned long hwirq; ++ int virq; ++ ++ chained_irq_enter(chip, desc); ++ ++ grp = irq_desc_get_handler_data(desc); ++ msi = grp->msi; ++ pcie = msi->pcie; ++ eq = grp->eq; ++ ++ /* ++ * iProc MSI event queue is tracked by head and tail pointers. Head ++ * pointer indicates the next entry (MSI data) to be consumed by SW in ++ * the queue and needs to be updated by SW. iProc MSI core uses the ++ * tail pointer as the next data insertion point ++ * ++ * Entries between head and tail pointers contain valid MSI data. MSI ++ * data is guaranteed to be in the event queue memory before the tail ++ * pointer is updated by the iProc MSI core ++ */ ++ head = iproc_msi_read_reg(msi, IPROC_MSI_EQ_HEAD, ++ eq) & IPROC_MSI_EQ_MASK; ++ do { ++ tail = iproc_msi_read_reg(msi, IPROC_MSI_EQ_TAIL, ++ eq) & IPROC_MSI_EQ_MASK; ++ ++ /* ++ * Figure out total number of events (MSI data) to be ++ * processed ++ */ ++ nr_events = (tail < head) ? ++ (EQ_LEN - (head - tail)) : (tail - head); ++ if (!nr_events) ++ break; ++ ++ /* process all outstanding events */ ++ while (nr_events--) { ++ hwirq = decode_msi_hwirq(msi, eq, head); ++ virq = irq_find_mapping(msi->inner_domain, hwirq); ++ generic_handle_irq(virq); ++ ++ head++; ++ head %= EQ_LEN; ++ } ++ ++ /* ++ * Now all outstanding events have been processed. Update the ++ * head pointer ++ */ ++ iproc_msi_write_reg(msi, IPROC_MSI_EQ_HEAD, eq, head); ++ ++ /* ++ * Now go read the tail pointer again to see if there are new ++ * oustanding events that came in during the above window ++ */ ++ } while (true); ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static void iproc_msi_enable(struct iproc_msi *msi) ++{ ++ int i, eq; ++ u32 val; ++ ++ /* program memory region for each event queue */ ++ for (i = 0; i < msi->nr_eq_region; i++) { ++ dma_addr_t addr = msi->eq_dma + (i * EQ_MEM_REGION_SIZE); ++ ++ iproc_msi_write_reg(msi, IPROC_MSI_EQ_PAGE, i, ++ lower_32_bits(addr)); ++ iproc_msi_write_reg(msi, IPROC_MSI_EQ_PAGE_UPPER, i, ++ upper_32_bits(addr)); ++ } ++ ++ /* program address region for MSI posted writes */ ++ for (i = 0; i < msi->nr_msi_region; i++) { ++ phys_addr_t addr = msi->msi_addr + (i * MSI_MEM_REGION_SIZE); ++ ++ iproc_msi_write_reg(msi, IPROC_MSI_PAGE, i, ++ lower_32_bits(addr)); ++ iproc_msi_write_reg(msi, IPROC_MSI_PAGE_UPPER, i, ++ upper_32_bits(addr)); ++ } ++ ++ for (eq = 0; eq < msi->nr_irqs; eq++) { ++ /* enable MSI event queue */ ++ val = IPROC_MSI_INTR_EN | IPROC_MSI_INT_N_EVENT | ++ IPROC_MSI_EQ_EN; ++ iproc_msi_write_reg(msi, IPROC_MSI_CTRL, eq, val); ++ ++ /* ++ * Some legacy platforms require the MSI interrupt enable ++ * register to be set explicitly ++ */ ++ if (msi->has_inten_reg) { ++ val = iproc_msi_read_reg(msi, IPROC_MSI_INTS_EN, eq); ++ val |= BIT(eq); ++ iproc_msi_write_reg(msi, IPROC_MSI_INTS_EN, eq, val); ++ } ++ } ++} ++ ++static void iproc_msi_disable(struct iproc_msi *msi) ++{ ++ u32 eq, val; ++ ++ for (eq = 0; eq < msi->nr_irqs; eq++) { ++ if (msi->has_inten_reg) { ++ val = iproc_msi_read_reg(msi, IPROC_MSI_INTS_EN, eq); ++ val &= ~BIT(eq); ++ iproc_msi_write_reg(msi, IPROC_MSI_INTS_EN, eq, val); ++ } ++ ++ val = iproc_msi_read_reg(msi, IPROC_MSI_CTRL, eq); ++ val &= ~(IPROC_MSI_INTR_EN | IPROC_MSI_INT_N_EVENT | ++ IPROC_MSI_EQ_EN); ++ iproc_msi_write_reg(msi, IPROC_MSI_CTRL, eq, val); ++ } ++} ++ ++static int iproc_msi_alloc_domains(struct device_node *node, ++ struct iproc_msi *msi) ++{ ++ msi->inner_domain = irq_domain_add_linear(NULL, msi->nr_msi_vecs, ++ &msi_domain_ops, msi); ++ if (!msi->inner_domain) ++ return -ENOMEM; ++ ++ msi->msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node), ++ &iproc_msi_domain_info, ++ msi->inner_domain); ++ if (!msi->msi_domain) { ++ irq_domain_remove(msi->inner_domain); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void iproc_msi_free_domains(struct iproc_msi *msi) ++{ ++ if (msi->msi_domain) ++ irq_domain_remove(msi->msi_domain); ++ ++ if (msi->inner_domain) ++ irq_domain_remove(msi->inner_domain); ++} ++ ++static void iproc_msi_irq_free(struct iproc_msi *msi, unsigned int cpu) ++{ ++ int i; ++ ++ for (i = cpu; i < msi->nr_irqs; i += msi->nr_cpus) { ++ irq_set_chained_handler_and_data(msi->grps[i].gic_irq, ++ NULL, NULL); ++ } ++} ++ ++static int iproc_msi_irq_setup(struct iproc_msi *msi, unsigned int cpu) ++{ ++ int i, ret; ++ cpumask_var_t mask; ++ struct iproc_pcie *pcie = msi->pcie; ++ ++ for (i = cpu; i < msi->nr_irqs; i += msi->nr_cpus) { ++ irq_set_chained_handler_and_data(msi->grps[i].gic_irq, ++ iproc_msi_handler, ++ &msi->grps[i]); ++ /* dedicate GIC interrupt to each CPU core */ ++ if (alloc_cpumask_var(&mask, GFP_KERNEL)) { ++ cpumask_clear(mask); ++ cpumask_set_cpu(cpu, mask); ++ ret = irq_set_affinity(msi->grps[i].gic_irq, mask); ++ if (ret) ++ dev_err(pcie->dev, ++ "failed to set affinity for IRQ%d\n", ++ msi->grps[i].gic_irq); ++ free_cpumask_var(mask); ++ } else { ++ dev_err(pcie->dev, "failed to alloc CPU mask\n"); ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ /* free all configured/unconfigured irqs */ ++ iproc_msi_irq_free(msi, cpu); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node) ++{ ++ struct iproc_msi *msi; ++ int i, ret; ++ unsigned int cpu; ++ ++ if (!of_device_is_compatible(node, "brcm,iproc-msi")) ++ return -ENODEV; ++ ++ if (!of_find_property(node, "msi-controller", NULL)) ++ return -ENODEV; ++ ++ if (pcie->msi) ++ return -EBUSY; ++ ++ msi = devm_kzalloc(pcie->dev, sizeof(*msi), GFP_KERNEL); ++ if (!msi) ++ return -ENOMEM; ++ ++ msi->pcie = pcie; ++ pcie->msi = msi; ++ msi->msi_addr = pcie->base_addr; ++ mutex_init(&msi->bitmap_lock); ++ msi->nr_cpus = num_possible_cpus(); ++ ++ msi->nr_irqs = of_irq_count(node); ++ if (!msi->nr_irqs) { ++ dev_err(pcie->dev, "found no MSI GIC interrupt\n"); ++ return -ENODEV; ++ } ++ ++ if (msi->nr_irqs > NR_HW_IRQS) { ++ dev_warn(pcie->dev, "too many MSI GIC interrupts defined %d\n", ++ msi->nr_irqs); ++ msi->nr_irqs = NR_HW_IRQS; ++ } ++ ++ if (msi->nr_irqs < msi->nr_cpus) { ++ dev_err(pcie->dev, ++ "not enough GIC interrupts for MSI affinity\n"); ++ return -EINVAL; ++ } ++ ++ if (msi->nr_irqs % msi->nr_cpus != 0) { ++ msi->nr_irqs -= msi->nr_irqs % msi->nr_cpus; ++ dev_warn(pcie->dev, "Reducing number of interrupts to %d\n", ++ msi->nr_irqs); ++ } ++ ++ switch (pcie->type) { ++ case IPROC_PCIE_PAXB: ++ msi->reg_offsets = iproc_msi_reg_paxb; ++ msi->nr_eq_region = 1; ++ msi->nr_msi_region = 1; ++ break; ++ case IPROC_PCIE_PAXC: ++ msi->reg_offsets = iproc_msi_reg_paxc; ++ msi->nr_eq_region = msi->nr_irqs; ++ msi->nr_msi_region = msi->nr_irqs; ++ break; ++ default: ++ dev_err(pcie->dev, "incompatible iProc PCIe interface\n"); ++ return -EINVAL; ++ } ++ ++ if (of_find_property(node, "brcm,pcie-msi-inten", NULL)) ++ msi->has_inten_reg = true; ++ ++ msi->nr_msi_vecs = msi->nr_irqs * EQ_LEN; ++ msi->bitmap = devm_kcalloc(pcie->dev, BITS_TO_LONGS(msi->nr_msi_vecs), ++ sizeof(*msi->bitmap), GFP_KERNEL); ++ if (!msi->bitmap) ++ return -ENOMEM; ++ ++ msi->grps = devm_kcalloc(pcie->dev, msi->nr_irqs, sizeof(*msi->grps), ++ GFP_KERNEL); ++ if (!msi->grps) ++ return -ENOMEM; ++ ++ for (i = 0; i < msi->nr_irqs; i++) { ++ unsigned int irq = irq_of_parse_and_map(node, i); ++ ++ if (!irq) { ++ dev_err(pcie->dev, "unable to parse/map interrupt\n"); ++ ret = -ENODEV; ++ goto free_irqs; ++ } ++ msi->grps[i].gic_irq = irq; ++ msi->grps[i].msi = msi; ++ msi->grps[i].eq = i; ++ } ++ ++ /* reserve memory for event queue and make sure memories are zeroed */ ++ msi->eq_cpu = dma_zalloc_coherent(pcie->dev, ++ msi->nr_eq_region * EQ_MEM_REGION_SIZE, ++ &msi->eq_dma, GFP_KERNEL); ++ if (!msi->eq_cpu) { ++ ret = -ENOMEM; ++ goto free_irqs; ++ } ++ ++ ret = iproc_msi_alloc_domains(node, msi); ++ if (ret) { ++ dev_err(pcie->dev, "failed to create MSI domains\n"); ++ goto free_eq_dma; ++ } ++ ++ for_each_online_cpu(cpu) { ++ ret = iproc_msi_irq_setup(msi, cpu); ++ if (ret) ++ goto free_msi_irq; ++ } ++ ++ iproc_msi_enable(msi); ++ ++ return 0; ++ ++free_msi_irq: ++ for_each_online_cpu(cpu) ++ iproc_msi_irq_free(msi, cpu); ++ iproc_msi_free_domains(msi); ++ ++free_eq_dma: ++ dma_free_coherent(pcie->dev, msi->nr_eq_region * EQ_MEM_REGION_SIZE, ++ msi->eq_cpu, msi->eq_dma); ++ ++free_irqs: ++ for (i = 0; i < msi->nr_irqs; i++) { ++ if (msi->grps[i].gic_irq) ++ irq_dispose_mapping(msi->grps[i].gic_irq); ++ } ++ pcie->msi = NULL; ++ return ret; ++} ++EXPORT_SYMBOL(iproc_msi_init); ++ ++void iproc_msi_exit(struct iproc_pcie *pcie) ++{ ++ struct iproc_msi *msi = pcie->msi; ++ unsigned int i, cpu; ++ ++ if (!msi) ++ return; ++ ++ iproc_msi_disable(msi); ++ ++ for_each_online_cpu(cpu) ++ iproc_msi_irq_free(msi, cpu); ++ ++ iproc_msi_free_domains(msi); ++ ++ dma_free_coherent(pcie->dev, msi->nr_eq_region * EQ_MEM_REGION_SIZE, ++ msi->eq_cpu, msi->eq_dma); ++ ++ for (i = 0; i < msi->nr_irqs; i++) { ++ if (msi->grps[i].gic_irq) ++ irq_dispose_mapping(msi->grps[i].gic_irq); ++ } ++} ++EXPORT_SYMBOL(iproc_msi_exit); +--- a/drivers/pci/host/pcie-iproc-platform.c ++++ b/drivers/pci/host/pcie-iproc-platform.c +@@ -71,6 +71,7 @@ static int iproc_pcie_pltfm_probe(struct + dev_err(pcie->dev, "unable to map controller registers\n"); + return -ENOMEM; + } ++ pcie->base_addr = reg.start; + + if (of_property_read_bool(np, "brcm,pcie-ob")) { + u32 val; +--- a/drivers/pci/host/pcie-iproc.c ++++ b/drivers/pci/host/pcie-iproc.c +@@ -440,6 +440,26 @@ static int iproc_pcie_map_ranges(struct + return 0; + } + ++static int iproc_pcie_msi_enable(struct iproc_pcie *pcie) ++{ ++ struct device_node *msi_node; ++ ++ msi_node = of_parse_phandle(pcie->dev->of_node, "msi-parent", 0); ++ if (!msi_node) ++ return -ENODEV; ++ ++ /* ++ * If another MSI controller is being used, the call below should fail ++ * but that is okay ++ */ ++ return iproc_msi_init(pcie, msi_node); ++} ++ ++static void iproc_pcie_msi_disable(struct iproc_pcie *pcie) ++{ ++ iproc_msi_exit(pcie); ++} ++ + int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) + { + int ret; +@@ -507,6 +527,10 @@ int iproc_pcie_setup(struct iproc_pcie * + + iproc_pcie_enable(pcie); + ++ if (IS_ENABLED(CONFIG_PCI_MSI)) ++ if (iproc_pcie_msi_enable(pcie)) ++ dev_info(pcie->dev, "not using iProc MSI\n"); ++ + pci_scan_child_bus(bus); + pci_assign_unassigned_bus_resources(bus); + pci_fixup_irqs(pci_common_swizzle, pcie->map_irq); +@@ -531,6 +555,8 @@ int iproc_pcie_remove(struct iproc_pcie + pci_stop_root_bus(pcie->root_bus); + pci_remove_root_bus(pcie->root_bus); + ++ iproc_pcie_msi_disable(pcie); ++ + phy_power_off(pcie->phy); + phy_exit(pcie->phy); + +--- a/drivers/pci/host/pcie-iproc.h ++++ b/drivers/pci/host/pcie-iproc.h +@@ -41,6 +41,8 @@ struct iproc_pcie_ob { + resource_size_t window_size; + }; + ++struct iproc_msi; ++ + /** + * iProc PCIe device + * +@@ -48,19 +50,21 @@ struct iproc_pcie_ob { + * @type: iProc PCIe interface type + * @reg_offsets: register offsets + * @base: PCIe host controller I/O register base ++ * @base_addr: PCIe host controller register base physical address + * @sysdata: Per PCI controller data (ARM-specific) + * @root_bus: pointer to root bus + * @phy: optional PHY device that controls the Serdes +- * @irqs: interrupt IDs + * @map_irq: function callback to map interrupts +- * @need_ob_cfg: indidates SW needs to configure the outbound mapping window ++ * @need_ob_cfg: indicates SW needs to configure the outbound mapping window + * @ob: outbound mapping parameters ++ * @msi: MSI data + */ + struct iproc_pcie { + struct device *dev; + enum iproc_pcie_type type; + const u16 *reg_offsets; + void __iomem *base; ++ phys_addr_t base_addr; + #ifdef CONFIG_ARM + struct pci_sys_data sysdata; + #endif +@@ -69,9 +73,24 @@ struct iproc_pcie { + int (*map_irq)(const struct pci_dev *, u8, u8); + bool need_ob_cfg; + struct iproc_pcie_ob ob; ++ struct iproc_msi *msi; + }; + + int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res); + int iproc_pcie_remove(struct iproc_pcie *pcie); + ++#ifdef CONFIG_PCI_MSI ++int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node); ++void iproc_msi_exit(struct iproc_pcie *pcie); ++#else ++static inline int iproc_msi_init(struct iproc_pcie *pcie, ++ struct device_node *node) ++{ ++ return -ENODEV; ++} ++static void iproc_msi_exit(struct iproc_pcie *pcie) ++{ ++} ++#endif ++ + #endif /* _PCIE_IPROC_H */ diff --git a/target/linux/bcm53xx/patches-4.4/170-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch b/target/linux/bcm53xx/patches-4.4/170-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch new file mode 100644 index 0000000..60fba13 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/170-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch @@ -0,0 +1,52 @@ +From b58682598541262f967ecd6db04bacac38026d3c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Fri, 30 Oct 2015 15:29:52 +0100 +Subject: [PATCH] ARM: BCM5301X: Add missing Netgear R8000 LEDs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + arch/arm/boot/dts/bcm4709-netgear-r8000.dts | 30 +++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts ++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts +@@ -50,6 +50,36 @@ + gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>; + linux,default-trigger = "default-off"; + }; ++ ++ wireless { ++ label = "bcm53xx:white:wireless"; ++ gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "default-off"; ++ }; ++ ++ wps { ++ label = "bcm53xx:white:wps"; ++ gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "default-off"; ++ }; ++ ++ 5ghz-2 { ++ label = "bcm53xx:white:5ghz-2"; ++ gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>; ++ linux,default-trigger = "default-off"; ++ }; ++ ++ usb3 { ++ label = "bcm53xx:white:usb3"; ++ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>; ++ linux,default-trigger = "default-off"; ++ }; ++ ++ usb2 { ++ label = "bcm53xx:white:usb2"; ++ gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>; ++ linux,default-trigger = "default-off"; ++ }; + }; + + gpio-keys { diff --git a/target/linux/bcm53xx/patches-4.4/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch b/target/linux/bcm53xx/patches-4.4/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch new file mode 100644 index 0000000..f1995d1 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch @@ -0,0 +1,73 @@ +From 0cb136f9882e4649ad6160bb7b48955ff728888c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Sun, 1 Nov 2015 08:17:21 +0100 +Subject: [PATCH V2] USB: bcma: switch to GPIO descriptor for power control +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So far we were using simple (legacy) GPIO functions & some poor logic to +control power. It got many drawbacks: we were ignoring OF flags +(GPIO_ACTIVE_LOW), we were not setting direction to output and we were +assuming gpio_request success all the time. +Fix it by switching to gpiod functions and adding appropriate checks. + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + drivers/usb/host/bcma-hcd.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +--- a/drivers/usb/host/bcma-hcd.c ++++ b/drivers/usb/host/bcma-hcd.c +@@ -21,6 +21,7 @@ + */ + #include <linux/bcma/bcma.h> + #include <linux/delay.h> ++#include <linux/gpio/consumer.h> + #include <linux/platform_device.h> + #include <linux/module.h> + #include <linux/slab.h> +@@ -36,6 +37,7 @@ MODULE_LICENSE("GPL"); + struct bcma_hcd_device { + struct platform_device *ehci_dev; + struct platform_device *ohci_dev; ++ struct gpio_desc *gpio_desc; + }; + + /* Wait for bitmask in a register to get set or cleared. +@@ -228,19 +230,12 @@ static void bcma_hcd_init_chip_arm(struc + + static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val) + { +- int gpio; ++ struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev); + +- gpio = of_get_named_gpio(dev->dev.of_node, "vcc-gpio", 0); +- if (!gpio_is_valid(gpio)) ++ if (IS_ERR_OR_NULL(usb_dev->gpio_desc)) + return; + +- if (val) { +- gpio_request(gpio, "bcma-hcd-gpio"); +- gpio_set_value(gpio, 1); +- } else { +- gpio_set_value(gpio, 0); +- gpio_free(gpio); +- } ++ gpiod_set_value(usb_dev->gpio_desc, val); + } + + static const struct usb_ehci_pdata ehci_pdata = { +@@ -314,7 +309,11 @@ static int bcma_hcd_probe(struct bcma_de + if (!usb_dev) + return -ENOMEM; + +- bcma_hci_platform_power_gpio(dev, true); ++ if (dev->dev.of_node) ++ usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc", ++ &dev->dev.of_node->fwnode); ++ if (!IS_ERR_OR_NULL(usb_dev->gpio_desc)) ++ gpiod_direction_output(usb_dev->gpio_desc, 1); + + switch (dev->id.id) { + case BCMA_CORE_NS_USB20: diff --git a/target/linux/bcm53xx/patches-4.4/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch b/target/linux/bcm53xx/patches-4.4/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch new file mode 100644 index 0000000..c120829 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch @@ -0,0 +1,63 @@ +From 1420e53fc88673683f8990aa5342e7b2640ce165 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens <hauke@hauke-m.de> +Date: Sun, 18 Oct 2015 19:13:27 +0200 +Subject: [PATCH v3 1/6] usb: xhci: plat: fix adding usb3-lpm-capable quirk + +The xhci->quirks member is overwritten in xhci_gen_setup() with the +quirks given through the module load parameter. Without this patch the +usb3-lpm-capable quirk will be over written before it gets used. This +patch moves the quirks code to the xhci_plat_quirks() callback function +which gets called directly after the quirks member variable is +overwritten with the module load parameter. + +I do not have any hardware which is using usb3-lpm-capabls so I can not +test this on real hardware. + +Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> +--- + drivers/usb/host/xhci-plat.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/usb/host/xhci-plat.c ++++ b/drivers/usb/host/xhci-plat.c +@@ -38,12 +38,20 @@ static const struct xhci_driver_override + + static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) + { ++ struct platform_device *pdev = to_platform_device(dev); ++ struct device_node *node = pdev->dev.of_node; ++ struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev); ++ + /* + * As of now platform drivers don't provide MSI support so we ensure + * here that the generic code does not try to make a pci_dev from our + * dev struct in order to setup MSI + */ + xhci->quirks |= XHCI_PLAT; ++ ++ if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || ++ (pdata && pdata->usb3_lpm_capable)) ++ xhci->quirks |= XHCI_LPM_SUPPORT; + } + + /* called during probe() after chip reset completes */ +@@ -75,8 +83,6 @@ static int xhci_plat_start(struct usb_hc + + static int xhci_plat_probe(struct platform_device *pdev) + { +- struct device_node *node = pdev->dev.of_node; +- struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev); + const struct hc_driver *driver; + struct xhci_hcd *xhci; + struct resource *res; +@@ -155,10 +161,6 @@ static int xhci_plat_probe(struct platfo + goto disable_clk; + } + +- if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || +- (pdata && pdata->usb3_lpm_capable)) +- xhci->quirks |= XHCI_LPM_SUPPORT; +- + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) + xhci->shared_hcd->can_do_streams = 1; + diff --git a/target/linux/bcm53xx/patches-4.4/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch b/target/linux/bcm53xx/patches-4.4/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch new file mode 100644 index 0000000..c54cecb --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch @@ -0,0 +1,135 @@ +From dd0e5f9a6a4aed849bdb80641c2a2350476cede7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Sun, 21 Jun 2015 11:10:49 +0200 +Subject: [PATCH v3 2/6] usb: xhci: add Broadcom specific fake doorbell +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes problem with controller seeing devices only in some small +percentage of cold boots. +This quirk is also added to the platform data so we can activate it +when we register our platform driver. + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> +--- + drivers/usb/host/xhci-plat.c | 3 +++ + drivers/usb/host/xhci.c | 57 +++++++++++++++++++++++++++++++++++++--- + drivers/usb/host/xhci.h | 1 + + include/linux/usb/xhci_pdriver.h | 1 + + 4 files changed, 59 insertions(+), 3 deletions(-) + +--- a/drivers/usb/host/xhci-plat.c ++++ b/drivers/usb/host/xhci-plat.c +@@ -52,6 +52,9 @@ static void xhci_plat_quirks(struct devi + if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || + (pdata && pdata->usb3_lpm_capable)) + xhci->quirks |= XHCI_LPM_SUPPORT; ++ ++ if (pdata && pdata->usb3_fake_doorbell) ++ xhci->quirks |= XHCI_FAKE_DOORBELL; + } + + /* called during probe() after chip reset completes */ +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -121,6 +121,39 @@ int xhci_halt(struct xhci_hcd *xhci) + return ret; + } + ++static int xhci_fake_doorbell(struct xhci_hcd *xhci, int slot_id) ++{ ++ u32 temp; ++ ++ /* alloc a virt device for slot */ ++ if (!xhci_alloc_virt_device(xhci, slot_id, NULL, GFP_NOIO)) { ++ xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n"); ++ return -ENOMEM; ++ } ++ ++ /* ring fake doorbell for slot_id ep 0 */ ++ xhci_ring_ep_doorbell(xhci, slot_id, 0, 0); ++ usleep_range(1000, 1500); ++ ++ /* read the status register to check if HSE is set or not? */ ++ temp = readl(&xhci->op_regs->status); ++ ++ /* clear HSE if set */ ++ if (temp & STS_FATAL) { ++ xhci_dbg(xhci, "HSE problem detected, status: 0x%x\n", temp); ++ temp &= ~(0x1fff); ++ temp |= STS_FATAL; ++ writel(temp, &xhci->op_regs->status); ++ usleep_range(1000, 1500); ++ readl(&xhci->op_regs->status); ++ } ++ ++ /* Free virt device */ ++ xhci_free_virt_device(xhci, slot_id); ++ ++ return 0; ++} ++ + /* + * Set the run bit and wait for the host to be running. + */ +@@ -567,10 +600,25 @@ int xhci_init(struct usb_hcd *hcd) + + static int xhci_run_finished(struct xhci_hcd *xhci) + { +- if (xhci_start(xhci)) { +- xhci_halt(xhci); +- return -ENODEV; ++ int err; ++ ++ err = xhci_start(xhci); ++ if (err) { ++ err = -ENODEV; ++ goto out_err; ++ } ++ if (xhci->quirks & XHCI_FAKE_DOORBELL) { ++ err = xhci_fake_doorbell(xhci, 1); ++ if (err) ++ goto out_err; ++ ++ err = xhci_start(xhci); ++ if (err) { ++ err = -ENODEV; ++ goto out_err; ++ } + } ++ + xhci->shared_hcd->state = HC_STATE_RUNNING; + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; + +@@ -580,6 +628,9 @@ static int xhci_run_finished(struct xhci + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Finished xhci_run for USB3 roothub"); + return 0; ++out_err: ++ xhci_halt(xhci); ++ return err; + } + + /* +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1630,6 +1630,7 @@ struct xhci_hcd { + /* For controllers with a broken beyond repair streams implementation */ + #define XHCI_BROKEN_STREAMS (1 << 19) + #define XHCI_PME_STUCK_QUIRK (1 << 20) ++#define XHCI_FAKE_DOORBELL (1 << 21) + unsigned int num_active_eps; + unsigned int limit_active_eps; + /* There are two roothubs to keep track of bus suspend info for */ +--- a/include/linux/usb/xhci_pdriver.h ++++ b/include/linux/usb/xhci_pdriver.h +@@ -22,6 +22,7 @@ + */ + struct usb_xhci_pdata { + unsigned usb3_lpm_capable:1; ++ unsigned usb3_fake_doorbell:1; + }; + + #endif /* __USB_CORE_XHCI_PDRIVER_H */ diff --git a/target/linux/bcm53xx/patches-4.4/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch b/target/linux/bcm53xx/patches-4.4/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch new file mode 100644 index 0000000..17a9260 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch @@ -0,0 +1,75 @@ +From c7c7bf7fcbacadac7781783de25fe1e13e2a2c35 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Tue, 16 Jun 2015 12:33:46 +0200 +Subject: [PATCH v3 3/6] usb: bcma: make helper creating platform dev more + generic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Having "bool ohci" argument bounded us to two cases only and didn't +allow re-using this code for XHCI. + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> +--- + drivers/usb/host/bcma-hcd.c | 24 +++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +--- a/drivers/usb/host/bcma-hcd.c ++++ b/drivers/usb/host/bcma-hcd.c +@@ -244,7 +244,10 @@ static const struct usb_ehci_pdata ehci_ + static const struct usb_ohci_pdata ohci_pdata = { + }; + +-static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr) ++static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, ++ const char *name, u32 addr, ++ const void *data, ++ size_t size) + { + struct platform_device *hci_dev; + struct resource hci_res[2]; +@@ -259,8 +262,7 @@ static struct platform_device *bcma_hcd_ + hci_res[1].start = dev->irq; + hci_res[1].flags = IORESOURCE_IRQ; + +- hci_dev = platform_device_alloc(ohci ? "ohci-platform" : +- "ehci-platform" , 0); ++ hci_dev = platform_device_alloc(name, 0); + if (!hci_dev) + return ERR_PTR(-ENOMEM); + +@@ -271,12 +273,8 @@ static struct platform_device *bcma_hcd_ + ARRAY_SIZE(hci_res)); + if (ret) + goto err_alloc; +- if (ohci) +- ret = platform_device_add_data(hci_dev, &ohci_pdata, +- sizeof(ohci_pdata)); +- else +- ret = platform_device_add_data(hci_dev, &ehci_pdata, +- sizeof(ehci_pdata)); ++ if (data) ++ ret = platform_device_add_data(hci_dev, data, size); + if (ret) + goto err_alloc; + ret = platform_device_add(hci_dev); +@@ -333,11 +331,15 @@ static int bcma_hcd_probe(struct bcma_de + && chipinfo->rev == 0) + ohci_addr = 0x18009000; + +- usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr); ++ usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, "ohci-platform", ++ ohci_addr, &ohci_pdata, ++ sizeof(ohci_pdata)); + if (IS_ERR(usb_dev->ohci_dev)) + return PTR_ERR(usb_dev->ohci_dev); + +- usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr); ++ usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, "ehci-platform", ++ dev->addr, &ehci_pdata, ++ sizeof(ehci_pdata)); + if (IS_ERR(usb_dev->ehci_dev)) { + err = PTR_ERR(usb_dev->ehci_dev); + goto err_unregister_ohci_dev; diff --git a/target/linux/bcm53xx/patches-4.4/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch b/target/linux/bcm53xx/patches-4.4/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch new file mode 100644 index 0000000..262192b --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch @@ -0,0 +1,112 @@ +From fa5622c2fadae573dd6b0f5bffe436b230b411f6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Tue, 16 Jun 2015 12:52:07 +0200 +Subject: [PATCH v3 4/6] usb: bcma: use separated function for USB 2.0 + initialization +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This will allow adding USB 3.0 (XHCI) support cleanly. + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> +--- + drivers/usb/host/bcma-hcd.c | 51 +++++++++++++++++++++++++++++++-------------- + 1 file changed, 35 insertions(+), 16 deletions(-) + +--- a/drivers/usb/host/bcma-hcd.c ++++ b/drivers/usb/host/bcma-hcd.c +@@ -35,6 +35,7 @@ MODULE_DESCRIPTION("Common USB driver fo + MODULE_LICENSE("GPL"); + + struct bcma_hcd_device { ++ struct bcma_device *core; + struct platform_device *ehci_dev; + struct platform_device *ohci_dev; + struct gpio_desc *gpio_desc; +@@ -288,31 +289,16 @@ err_alloc: + return ERR_PTR(ret); + } + +-static int bcma_hcd_probe(struct bcma_device *dev) ++static int bcma_hcd_usb20_init(struct bcma_hcd_device *usb_dev) + { +- int err; ++ struct bcma_device *dev = usb_dev->core; ++ struct bcma_chipinfo *chipinfo = &dev->bus->chipinfo; + u32 ohci_addr; +- struct bcma_hcd_device *usb_dev; +- struct bcma_chipinfo *chipinfo; +- +- chipinfo = &dev->bus->chipinfo; +- +- /* TODO: Probably need checks here; is the core connected? */ ++ int err; + + if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32))) + return -EOPNOTSUPP; + +- usb_dev = devm_kzalloc(&dev->dev, sizeof(struct bcma_hcd_device), +- GFP_KERNEL); +- if (!usb_dev) +- return -ENOMEM; +- +- if (dev->dev.of_node) +- usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc", +- &dev->dev.of_node->fwnode); +- if (!IS_ERR_OR_NULL(usb_dev->gpio_desc)) +- gpiod_direction_output(usb_dev->gpio_desc, 1); +- + switch (dev->id.id) { + case BCMA_CORE_NS_USB20: + bcma_hcd_init_chip_arm(dev); +@@ -345,7 +331,6 @@ static int bcma_hcd_probe(struct bcma_de + goto err_unregister_ohci_dev; + } + +- bcma_set_drvdata(dev, usb_dev); + return 0; + + err_unregister_ohci_dev: +@@ -353,6 +338,40 @@ err_unregister_ohci_dev: + return err; + } + ++static int bcma_hcd_probe(struct bcma_device *dev) ++{ ++ int err; ++ struct bcma_hcd_device *usb_dev; ++ ++ /* TODO: Probably need checks here; is the core connected? */ ++ ++ usb_dev = devm_kzalloc(&dev->dev, sizeof(struct bcma_hcd_device), ++ GFP_KERNEL); ++ if (!usb_dev) ++ return -ENOMEM; ++ usb_dev->core = dev; ++ ++ if (dev->dev.of_node) ++ usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc", ++ &dev->dev.of_node->fwnode); ++ if (!IS_ERR_OR_NULL(usb_dev->gpio_desc)) ++ gpiod_direction_output(usb_dev->gpio_desc, 1); ++ ++ switch (dev->id.id) { ++ case BCMA_CORE_USB20_HOST: ++ case BCMA_CORE_NS_USB20: ++ err = bcma_hcd_usb20_init(usb_dev); ++ if (err) ++ return err; ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ bcma_set_drvdata(dev, usb_dev); ++ return 0; ++} ++ + static void bcma_hcd_remove(struct bcma_device *dev) + { + struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev); diff --git a/target/linux/bcm53xx/patches-4.4/197-USB-bcma-add-USB-3.0-support.patch b/target/linux/bcm53xx/patches-4.4/197-USB-bcma-add-USB-3.0-support.patch new file mode 100644 index 0000000..34ab858 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/197-USB-bcma-add-USB-3.0-support.patch @@ -0,0 +1,295 @@ +From 121ec6539abedbc0e975cf35f48ee044b323e4c3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Tue, 16 Jun 2015 17:14:26 +0200 +Subject: [PATCH v3 5/6] usb: bcma: add USB 3.0 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> +--- + drivers/usb/host/bcma-hcd.c | 225 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 225 insertions(+) + +--- a/drivers/usb/host/bcma-hcd.c ++++ b/drivers/usb/host/bcma-hcd.c +@@ -29,6 +29,7 @@ + #include <linux/of_gpio.h> + #include <linux/usb/ehci_pdriver.h> + #include <linux/usb/ohci_pdriver.h> ++#include <linux/usb/xhci_pdriver.h> + + MODULE_AUTHOR("Hauke Mehrtens"); + MODULE_DESCRIPTION("Common USB driver for BCMA Bus"); +@@ -38,6 +39,7 @@ struct bcma_hcd_device { + struct bcma_device *core; + struct platform_device *ehci_dev; + struct platform_device *ohci_dev; ++ struct platform_device *xhci_dev; + struct gpio_desc *gpio_desc; + }; + +@@ -245,6 +247,10 @@ static const struct usb_ehci_pdata ehci_ + static const struct usb_ohci_pdata ohci_pdata = { + }; + ++static const struct usb_xhci_pdata xhci_pdata = { ++ .usb3_fake_doorbell = 1 ++}; ++ + static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, + const char *name, u32 addr, + const void *data, +@@ -338,6 +344,216 @@ err_unregister_ohci_dev: + return err; + } + ++static bool bcma_wait_reg(struct bcma_bus *bus, void __iomem *addr, u32 mask, ++ u32 value, int timeout) ++{ ++ unsigned long deadline = jiffies + timeout; ++ u32 val; ++ ++ do { ++ val = readl(addr); ++ if ((val & mask) == value) ++ return true; ++ cpu_relax(); ++ udelay(10); ++ } while (!time_after_eq(jiffies, deadline)); ++ ++ pr_err("Timeout waiting for register %p\n", addr); ++ ++ return false; ++} ++ ++static void bcma_hcd_usb30_phy_init(struct bcma_hcd_device *bcma_hcd) ++{ ++ struct bcma_device *core = bcma_hcd->core; ++ struct bcma_bus *bus = core->bus; ++ struct bcma_chipinfo *chipinfo = &bus->chipinfo; ++ struct bcma_drv_cc_b *ccb = &bus->drv_cc_b; ++ struct bcma_device *arm_core; ++ void __iomem *dmu = NULL; ++ u32 cru_straps_ctrl; ++ ++ if (chipinfo->id != BCMA_CHIP_ID_BCM4707 && ++ chipinfo->id != BCMA_CHIP_ID_BCM53018) ++ return; ++ ++ arm_core = bcma_find_core(bus, BCMA_CORE_ARMCA9); ++ if (!arm_core) ++ return; ++ ++ dmu = ioremap_nocache(arm_core->addr_s[0], 0x1000); ++ if (!dmu) ++ goto out; ++ ++ /* Check strapping of PCIE/USB3 SEL */ ++ cru_straps_ctrl = ioread32(dmu + 0x2a0); ++ if ((cru_straps_ctrl & 0x10) == 0) ++ goto out; ++ ++ /* Perform USB3 system soft reset */ ++ bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); ++ ++ /* Enable MDIO. Setting MDCDIV as 26 */ ++ iowrite32(0x0000009a, ccb->mii + 0x000); ++ udelay(2); ++ ++ switch (chipinfo->id) { ++ case BCMA_CHIP_ID_BCM4707: ++ if (chipinfo->rev == 4) { ++ /* For NS-B0, USB3 PLL Block */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x587e8000, ccb->mii + 0x004); ++ ++ /* Clear ana_pllSeqStart */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x58061000, ccb->mii + 0x004); ++ ++ /* CMOS Divider ratio to 25 */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x582a6400, ccb->mii + 0x004); ++ ++ /* Asserting PLL Reset */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x582ec000, ccb->mii + 0x004); ++ ++ /* Deaaserting PLL Reset */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x582e8000, ccb->mii + 0x004); ++ ++ /* Deasserting USB3 system reset */ ++ bcma_awrite32(core, BCMA_RESET_CTL, 0); ++ ++ /* Set ana_pllSeqStart */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x58069000, ccb->mii + 0x004); ++ ++ /* RXPMD block */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x587e8020, ccb->mii + 0x004); ++ ++ /* CDR int loop locking BW to 1 */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x58120049, ccb->mii + 0x004); ++ ++ /* CDR int loop acquisition BW to 1 */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x580e0049, ccb->mii + 0x004); ++ ++ /* CDR prop loop BW to 1 */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x580a005c, ccb->mii + 0x004); ++ ++ /* Waiting MII Mgt interface idle */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ } else { ++ /* PLL30 block */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x587e8000, ccb->mii + 0x004); ++ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x582a6400, ccb->mii + 0x004); ++ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x587e80e0, ccb->mii + 0x004); ++ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x580a009c, ccb->mii + 0x004); ++ ++ /* Enable SSC */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x587e8040, ccb->mii + 0x004); ++ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x580a21d3, ccb->mii + 0x004); ++ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x58061003, ccb->mii + 0x004); ++ ++ /* Waiting MII Mgt interface idle */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ ++ /* Deasserting USB3 system reset */ ++ bcma_awrite32(core, BCMA_RESET_CTL, 0); ++ } ++ break; ++ case BCMA_CHIP_ID_BCM53018: ++ /* USB3 PLL Block */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x587e8000, ccb->mii + 0x004); ++ ++ /* Assert Ana_Pllseq start */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x58061000, ccb->mii + 0x004); ++ ++ /* Assert CML Divider ratio to 26 */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x582a6400, ccb->mii + 0x004); ++ ++ /* Asserting PLL Reset */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x582ec000, ccb->mii + 0x004); ++ ++ /* Deaaserting PLL Reset */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x582e8000, ccb->mii + 0x004); ++ ++ /* Waiting MII Mgt interface idle */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ ++ /* Deasserting USB3 system reset */ ++ bcma_awrite32(core, BCMA_RESET_CTL, 0); ++ ++ /* PLL frequency monitor enable */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x58069000, ccb->mii + 0x004); ++ ++ /* PIPE Block */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x587e8060, ccb->mii + 0x004); ++ ++ /* CMPMAX & CMPMINTH setting */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x580af30d, ccb->mii + 0x004); ++ ++ /* DEGLITCH MIN & MAX setting */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x580e6302, ccb->mii + 0x004); ++ ++ /* TXPMD block */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x587e8040, ccb->mii + 0x004); ++ ++ /* Enabling SSC */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ iowrite32(0x58061003, ccb->mii + 0x004); ++ ++ /* Waiting MII Mgt interface idle */ ++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000); ++ ++ break; ++ } ++out: ++ if (dmu) ++ iounmap(dmu); ++} ++ ++static int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd) ++{ ++ struct bcma_device *core = bcma_hcd->core; ++ ++ bcma_core_enable(core, 0); ++ ++ bcma_hcd_usb30_phy_init(bcma_hcd); ++ ++ bcma_hcd->xhci_dev = bcma_hcd_create_pdev(core, "xhci-hcd", core->addr, ++ &xhci_pdata, ++ sizeof(xhci_pdata)); ++ if (IS_ERR(bcma_hcd->ohci_dev)) ++ return PTR_ERR(bcma_hcd->ohci_dev); ++ ++ return 0; ++} ++ + static int bcma_hcd_probe(struct bcma_device *dev) + { + int err; +@@ -364,6 +580,11 @@ static int bcma_hcd_probe(struct bcma_de + if (err) + return err; + break; ++ case BCMA_CORE_NS_USB30: ++ err = bcma_hcd_usb30_init(usb_dev); ++ if (err) ++ return err; ++ break; + default: + return -ENODEV; + } +@@ -377,11 +598,14 @@ static void bcma_hcd_remove(struct bcma_ + struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev); + struct platform_device *ohci_dev = usb_dev->ohci_dev; + struct platform_device *ehci_dev = usb_dev->ehci_dev; ++ struct platform_device *xhci_dev = usb_dev->xhci_dev; + + if (ohci_dev) + platform_device_unregister(ohci_dev); + if (ehci_dev) + platform_device_unregister(ehci_dev); ++ if (xhci_dev) ++ platform_device_unregister(xhci_dev); + + bcma_core_disable(dev, 0); + } +@@ -418,6 +642,7 @@ static int bcma_hcd_resume(struct bcma_d + static const struct bcma_device_id bcma_hcd_table[] = { + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS), ++ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB30, BCMA_ANY_REV, BCMA_ANY_CLASS), + {}, + }; + MODULE_DEVICE_TABLE(bcma, bcma_hcd_table); diff --git a/target/linux/bcm53xx/patches-4.4/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch b/target/linux/bcm53xx/patches-4.4/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch new file mode 100644 index 0000000..62bda2e --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch @@ -0,0 +1,86 @@ +From: Florian Fainelli <f.fainelli@gmail.com> +Subject: [PATCH] ARM: BCM5301x: Disable MMU and Dcache during decompression +Date: Tue, 14 Jul 2015 16:12:08 -0700 + +Use the existing __armv7_mmu_cache_flush() to perform the cache flush +since this does what we are after. + +Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> +--- + arch/arm/boot/compressed/Makefile | 4 +++ + arch/arm/boot/compressed/head-bcm_5301x-mpcore.S | 37 ++++++++++++++++++++++++ + arch/arm/boot/compressed/head.S | 2 ++ + 3 files changed, 43 insertions(+) + create mode 100644 arch/arm/boot/compressed/head-bcm_5301x-mpcore.S + +--- a/arch/arm/boot/compressed/Makefile ++++ b/arch/arm/boot/compressed/Makefile +@@ -31,6 +31,10 @@ ifeq ($(CONFIG_ARCH_ACORN),y) + OBJS += ll_char_wr.o font.o + endif + ++ifeq ($(CONFIG_ARCH_BCM_5301X),y) ++OBJS += head-bcm_5301x-mpcore.o ++endif ++ + ifeq ($(CONFIG_ARCH_SA1100),y) + OBJS += head-sa1100.o + endif +--- /dev/null ++++ b/arch/arm/boot/compressed/head-bcm_5301x-mpcore.S +@@ -0,0 +1,37 @@ ++/* ++ * ++ * Platform specific tweaks. This is merged into head.S by the linker. ++ * ++ */ ++ ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++#include <asm/cp15.h> ++ ++ .section ".start", "ax" ++ ++/* ++ * This code section is spliced into the head code by the linker ++ */ ++ ++__plat_uncompress_start: ++ ++ @ Preserve r8/r7 i.e. kernel entry values ++ mov r12, r8 ++ ++ @ Clear MMU enable and Dcache enable bits ++ mrc p15, 0, r0, c1, c0, 0 @ Read SCTLR ++ bic r0, #CR_C|CR_M ++ mcr p15, 0, r0, c1, c0, 0 @ Write SCTLR ++ nop ++ ++ @ Call the cache invalidation routine ++ bl __armv7_mmu_cache_flush_fn ++ nop ++ mov r0,#0 ++ ldr r3, =0x19022000 @ L2 cache controller, control reg ++ str r0, [r3, #0x100] @ Disable L2 cache ++ nop ++ ++ @ Restore ++ mov r8, r12 +--- a/arch/arm/boot/compressed/head.S ++++ b/arch/arm/boot/compressed/head.S +@@ -1152,6 +1152,7 @@ __armv7_mmu_cache_flush: + hierarchical: + mcr p15, 0, r10, c7, c10, 5 @ DMB + stmfd sp!, {r0-r7, r9-r11} ++ENTRY(__armv7_mmu_cache_flush_fn) + mrc p15, 1, r0, c0, c0, 1 @ read clidr + ands r3, r0, #0x7000000 @ extract loc from clidr + mov r3, r3, lsr #23 @ left align loc bit field +@@ -1201,6 +1202,7 @@ iflush: + mcr p15, 0, r10, c7, c10, 4 @ DSB + mcr p15, 0, r10, c7, c5, 4 @ ISB + mov pc, lr ++ENDPROC(__armv7_mmu_cache_flush_fn) + + __armv5tej_mmu_cache_flush: + tst r4, #1 diff --git a/target/linux/bcm53xx/patches-4.4/301-ARM-BCM5301X-Add-SPROM.patch b/target/linux/bcm53xx/patches-4.4/301-ARM-BCM5301X-Add-SPROM.patch new file mode 100644 index 0000000..ed6cc73 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/301-ARM-BCM5301X-Add-SPROM.patch @@ -0,0 +1,26 @@ +From d404e0b22356078a51719fa911f6e09cb1a72d80 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Sun, 7 Jun 2015 16:18:18 +0200 +Subject: [PATCH] ARM: BCM5301X: Add SPROM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + arch/arm/boot/dts/bcm5301x.dtsi | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/bcm5301x.dtsi ++++ b/arch/arm/boot/dts/bcm5301x.dtsi +@@ -136,6 +136,10 @@ + }; + }; + ++ sprom0: sprom@0 { ++ compatible = "brcm,bcm47xx-sprom"; ++ }; ++ + axi@18000000 { + compatible = "brcm,bus-axi"; + reg = <0x18000000 0x1000>; diff --git a/target/linux/bcm53xx/patches-4.4/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch b/target/linux/bcm53xx/patches-4.4/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch new file mode 100644 index 0000000..ff02cd7 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch @@ -0,0 +1,69 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Subject: [PATCH] ARM: BCM5301X: Add DT for Linksys EA6300 V1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -65,6 +65,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \ + bcm4708-asus-rt-ac56u.dtb \ + bcm4708-asus-rt-ac68u.dtb \ + bcm4708-buffalo-wzr-1750dhp.dtb \ ++ bcm4708-linksys-ea6300-v1.dtb \ + bcm4708-luxul-xwc-1000.dtb \ + bcm4708-netgear-r6250.dtb \ + bcm4708-netgear-r6300-v2.dtb \ +--- /dev/null ++++ b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts +@@ -0,0 +1,48 @@ ++/* ++ * Broadcom BCM470X / BCM5301X ARM platform code. ++ * DTS for Linksys EA6300 V1 ++ * ++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com> ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++/dts-v1/; ++ ++#include "bcm4708.dtsi" ++#include "bcm5301x-nand-cs0-bch8.dtsi" ++ ++/ { ++ compatible = "linksys,ea6300v1", "brcm,bcm4708"; ++ model = "Linksys EA6300 V1"; ++ ++ chosen { ++ bootargs = "console=ttyS0,115200"; ++ }; ++ ++ memory { ++ reg = <0x00000000 0x08000000>; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ wps { ++ label = "WPS"; ++ linux,code = <KEY_WPS_BUTTON>; ++ gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>; ++ }; ++ ++ restart { ++ label = "Reset"; ++ linux,code = <KEY_RESTART>; ++ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; diff --git a/target/linux/bcm53xx/patches-4.4/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch b/target/linux/bcm53xx/patches-4.4/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch new file mode 100644 index 0000000..802188d --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch @@ -0,0 +1,41 @@ +From 504dba5b073a9009ae1e3f2fc53ea9c3aa10c38a Mon Sep 17 00:00:00 2001 +From: Felix Fietkau <nbd@openwrt.org> +Date: Wed, 13 May 2015 20:56:38 +0200 +Subject: [PATCH] ARM: BCM5301X: Add Buffalo WXR-1900DHP clock and USB power + control +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts ++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts +@@ -24,6 +24,23 @@ + reg = <0x00000000 0x08000000>; + }; + ++ clocks { ++ clk_periph: periph { ++ clock-frequency = <500000000>; ++ }; ++ }; ++ ++ axi@18000000 { ++ usb2@21000 { ++ reg = <0x00021000 0x1000>; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ vcc-gpio = <&chipcommon 13 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ + leds { + compatible = "gpio-leds"; + diff --git a/target/linux/bcm53xx/patches-4.4/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch b/target/linux/bcm53xx/patches-4.4/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch new file mode 100644 index 0000000..e9b1b32 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch @@ -0,0 +1,66 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Subject: [PATCH] ARM: BCM5301X: Set vcc-gpio for USB controllers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- +--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts ++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts +@@ -24,6 +24,26 @@ + reg = <0x00000000 0x08000000>; + }; + ++ axi@18000000 { ++ usb2@21000 { ++ reg = <0x00021000 0x1000>; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ vcc-gpio = <&chipcommon 9 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ usb3@23000 { ++ reg = <0x00023000 0x1000>; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ vcc-gpio = <&chipcommon 10 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ + spi { + compatible = "spi-gpio"; + num-chipselects = <1>; +--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts ++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts +@@ -24,6 +24,26 @@ + reg = <0x00000000 0x08000000>; + }; + ++ axi@18000000 { ++ usb2@21000 { ++ reg = <0x00021000 0x1000>; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ usb3@23000 { ++ reg = <0x00023000 0x1000>; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ + leds { + compatible = "gpio-leds"; + diff --git a/target/linux/bcm53xx/patches-4.4/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch b/target/linux/bcm53xx/patches-4.4/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch new file mode 100644 index 0000000..4e25647 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch @@ -0,0 +1,170 @@ +From eb1075cc48d3c315c7403822c33da9588ab76492 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Wed, 14 Jan 2015 08:33:25 +0100 +Subject: [PATCH] ARM: BCM5310X: Enable earlyprintk on tested devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 2 +- + arch/arm/boot/dts/bcm4708-netgear-r6250.dts | 2 +- + arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts | 2 +- + arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts ++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts +@@ -17,7 +17,7 @@ + model = "Buffalo WZR-1750DHP (BCM4708)"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts ++++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts +@@ -17,7 +17,7 @@ + model = "Netgear R6250 V1 (BCM4708)"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts ++++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts +@@ -17,7 +17,7 @@ + model = "Asus RT-N18U (BCM47081)"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts ++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts +@@ -17,7 +17,7 @@ + model = "Buffalo WZR-600DHP2 (BCM47081)"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts ++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts +@@ -17,7 +17,7 @@ + model = "Buffalo WZR-900DHP (BCM47081)"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts ++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts +@@ -17,7 +17,7 @@ + model = "Netgear R8000 (BCM4709)"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts ++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts +@@ -17,7 +17,7 @@ + model = "Asus RT-AC56U (BCM4708)"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts ++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts +@@ -17,7 +17,7 @@ + model = "Asus RT-AC68U (BCM4708)"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts ++++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts +@@ -17,7 +17,7 @@ + model = "Luxul XWC-1000 (BCM4708)"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts ++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts +@@ -17,7 +17,7 @@ + model = "Buffalo WXR-1900DHP"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts ++++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts +@@ -17,7 +17,7 @@ + model = "SmartRG SR400ac"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts ++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts +@@ -17,7 +17,7 @@ + model = "Asus RT-AC87U"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts ++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts +@@ -17,7 +17,7 @@ + model = "Netgear R7000"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { +--- a/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts ++++ b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts +@@ -17,7 +17,7 @@ + model = "Linksys EA6300 V1"; + + chosen { +- bootargs = "console=ttyS0,115200"; ++ bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { diff --git a/target/linux/bcm53xx/patches-4.4/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch b/target/linux/bcm53xx/patches-4.4/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch new file mode 100644 index 0000000..b53c57f --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch @@ -0,0 +1,173 @@ +From 36b2fbb3badf0e32b371e1f7579a95d4fe25c0e1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Wed, 14 Jan 2015 09:13:58 +0100 +Subject: [PATCH] ARM: BCM5301X: Specify RAM on devices by including HIGHMEM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 3 ++- + arch/arm/boot/dts/bcm4708-netgear-r6250.dts | 3 ++- + arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts | 3 ++- + arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts | 3 ++- + arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts | 3 ++- + 5 files changed, 10 insertions(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts ++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x18000000>; + }; + + axi@18000000 { +--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts ++++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + axi@18000000 { +--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts ++++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + leds { +--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts ++++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + leds { +--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts ++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + spi { +--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts ++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + gpio-keys { +--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts ++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + axi@18000000 { +--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts ++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + leds { +--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts ++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + leds { +--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts ++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x18000000>; + }; + + clocks { +--- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts ++++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + leds { +--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts ++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + leds { +--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts ++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts +@@ -21,7 +21,8 @@ + }; + + memory { +- reg = <0x00000000 0x08000000>; ++ reg = <0x00000000 0x08000000 ++ 0x88000000 0x08000000>; + }; + + leds { diff --git a/target/linux/bcm53xx/patches-4.4/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch b/target/linux/bcm53xx/patches-4.4/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch new file mode 100644 index 0000000..f9ca7eb --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch @@ -0,0 +1,20 @@ +From: Felix Fietkau <nbd@openwrt.org> +Subject: [PATCH] ARM: BCM5301X: Add power button for Buffalo WZR-1750DHP + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- +--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts ++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts +@@ -123,6 +123,12 @@ + #address-cells = <1>; + #size-cells = <0>; + ++ power { ++ label = "Power"; ++ linux,code = <KEY_POWER>; ++ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>; ++ }; ++ + restart { + label = "Reset"; + linux,code = <KEY_RESTART>; diff --git a/target/linux/bcm53xx/patches-4.4/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch b/target/linux/bcm53xx/patches-4.4/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch new file mode 100644 index 0000000..dad4f8a --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch @@ -0,0 +1,111 @@ +From b49d7bb4825654f81bcee8e219028712811515a5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Mon, 29 Jun 2015 08:11:36 +0200 +Subject: [PATCH] ARM: BCM5301X: Enable ChipCommon UART on untested devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts | 4 ++++ + arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts | 4 ++++ + arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts | 4 ++++ + arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts | 4 ++++ + arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts | 4 ++++ + arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts | 5 +++++ + arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts | 5 +++++ + arch/arm/boot/dts/bcm4709-netgear-r8000.dts | 5 +++++ + 8 files changed, 35 insertions(+) + +--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts ++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts +@@ -96,3 +96,7 @@ + }; + }; + }; ++ ++&uart0 { ++ status = "okay"; ++}; +--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts ++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts +@@ -83,3 +83,7 @@ + }; + }; + }; ++ ++&uart0 { ++ status = "okay"; ++}; +--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts ++++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts +@@ -83,3 +83,7 @@ + }; + }; + }; ++ ++&uart0 { ++ status = "okay"; ++}; +--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts ++++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts +@@ -77,3 +77,7 @@ + }; + }; + }; ++ ++&uart0 { ++ status = "okay"; ++}; +--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts ++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts +@@ -37,3 +37,7 @@ + }; + }; + }; ++ ++&uart0 { ++ status = "okay"; ++}; +--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts ++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts +@@ -65,3 +65,8 @@ + }; + }; + }; ++ ++&uart0 { ++ status = "okay"; ++ clock-frequency = <125000000>; ++}; +--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts ++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts +@@ -144,3 +144,8 @@ + }; + }; + }; ++ ++&uart0 { ++ status = "okay"; ++ clock-frequency = <125000000>; ++}; +--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts ++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts +@@ -127,3 +127,8 @@ + }; + }; + }; ++ ++&uart0 { ++ status = "okay"; ++ clock-frequency = <125000000>; ++}; +--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts ++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts +@@ -104,4 +104,5 @@ + + &uart0 { + status = "okay"; ++ clock-frequency = <125000000>; + }; diff --git a/target/linux/bcm53xx/patches-4.4/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch b/target/linux/bcm53xx/patches-4.4/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch new file mode 100644 index 0000000..ccdb28b --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch @@ -0,0 +1,31 @@ +From d658c21d6697293a928434fd6ac19264b5a8948d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Fri, 30 Jan 2015 08:25:54 +0100 +Subject: [PATCH] mtd: bcm47xxpart: scan whole flash on ARCH_BCM_5301X +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + drivers/mtd/bcm47xxpart.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -120,9 +120,15 @@ static int bcm47xxpart_parse(struct mtd_ + /* Parse block by block looking for magics */ + for (offset = 0; offset <= master->size - blocksize; + offset += blocksize) { ++#ifndef CONFIG_ARCH_BCM_5301X ++ /* ++ * ARM routers may have partitions in higher memory. E.g. ++ * Netgear R8000 has board_data at 0x2600000. ++ */ + /* Nothing more in higher memory */ + if (offset >= 0x2000000) + break; ++#endif + + if (curr_part >= BCM47XXPART_MAX_PARTS) { + pr_warn("Reached maximum number of partitions, scanning stopped!\n"); diff --git a/target/linux/bcm53xx/patches-4.4/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch b/target/linux/bcm53xx/patches-4.4/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch new file mode 100644 index 0000000..487e64f --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch @@ -0,0 +1,20 @@ +--- a/drivers/mtd/spi-nor/Kconfig ++++ b/drivers/mtd/spi-nor/Kconfig +@@ -41,4 +41,10 @@ config SPI_NXP_SPIFI + Flash. Enable this option if you have a device with a SPIFI + controller and want to access the Flash as a mtd device. + ++config MTD_SPI_BCM53XXSPIFLASH ++ tristate "SPI-NOR flashes connected to the Broadcom ARM SoC" ++ depends on MTD_SPI_NOR ++ help ++ SPI driver for flashes used on Broadcom ARM SoCs. ++ + endif # MTD_SPI_NOR +--- a/drivers/mtd/spi-nor/Makefile ++++ b/drivers/mtd/spi-nor/Makefile +@@ -1,3 +1,4 @@ + obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o + obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o ++obj-$(CONFIG_MTD_SPI_BCM53XXSPIFLASH) += bcm53xxspiflash.o + obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o diff --git a/target/linux/bcm53xx/patches-4.4/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch b/target/linux/bcm53xx/patches-4.4/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch new file mode 100644 index 0000000..11bd956 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch @@ -0,0 +1,59 @@ +From 2a2af518266a29323cf30c3f9ba9ef2ceb1dd84b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Thu, 16 Oct 2014 20:52:16 +0200 +Subject: [PATCH] UBI: Detect EOF mark and erase all remaining blocks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + drivers/mtd/ubi/attach.c | 5 +++++ + drivers/mtd/ubi/io.c | 4 ++++ + drivers/mtd/ubi/ubi.h | 1 + + 3 files changed, 10 insertions(+) + +--- a/drivers/mtd/ubi/attach.c ++++ b/drivers/mtd/ubi/attach.c +@@ -95,6 +95,9 @@ static int self_check_ai(struct ubi_devi + static struct ubi_ec_hdr *ech; + static struct ubi_vid_hdr *vidh; + ++/* Set on finding block with 0xdeadc0de, indicates erasing all blocks behind */ ++bool erase_all_next; ++ + /** + * add_to_list - add physical eraseblock to a list. + * @ai: attaching information +@@ -1425,6 +1428,8 @@ int ubi_attach(struct ubi_device *ubi, i + if (!ai) + return -ENOMEM; + ++ erase_all_next = false; ++ + #ifdef CONFIG_MTD_UBI_FASTMAP + /* On small flash devices we disable fastmap in any case. */ + if ((int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd) <= UBI_FM_MAX_START) { +--- a/drivers/mtd/ubi/io.c ++++ b/drivers/mtd/ubi/io.c +@@ -755,6 +755,10 @@ int ubi_io_read_ec_hdr(struct ubi_device + } + + magic = be32_to_cpu(ec_hdr->magic); ++ if (magic == 0xdeadc0de) ++ erase_all_next = true; ++ if (erase_all_next) ++ return read_err ? UBI_IO_FF_BITFLIPS : UBI_IO_FF; + if (magic != UBI_EC_HDR_MAGIC) { + if (mtd_is_eccerr(read_err)) + return UBI_IO_BAD_HDR_EBADMSG; +--- a/drivers/mtd/ubi/ubi.h ++++ b/drivers/mtd/ubi/ubi.h +@@ -781,6 +781,7 @@ extern struct mutex ubi_devices_mutex; + extern struct blocking_notifier_head ubi_notifiers; + + /* attach.c */ ++extern bool erase_all_next; + int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, + int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips); + struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai, diff --git a/target/linux/bcm53xx/patches-4.4/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch b/target/linux/bcm53xx/patches-4.4/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch new file mode 100644 index 0000000..dfc422e --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch @@ -0,0 +1,42 @@ +From 4abdde3ad6bc0b3b157c4bf6ec0bf139d11d07e8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Wed, 13 May 2015 14:13:28 +0200 +Subject: [PATCH] b53: add hacky CPU port fixes for devices not using port 5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + drivers/net/phy/b53/b53_common.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/phy/b53/b53_common.c ++++ b/drivers/net/phy/b53/b53_common.c +@@ -25,6 +25,7 @@ + #include <linux/module.h> + #include <linux/switch.h> + #include <linux/platform_data/b53.h> ++#include <linux/of.h> + + #include "b53_regs.h" + #include "b53_priv.h" +@@ -1313,6 +1314,18 @@ static int b53_switch_init(struct b53_de + sw_dev->cpu_port = 5; + } + ++ if (of_machine_is_compatible("asus,rt-ac87u")) ++ sw_dev->cpu_port = 7; ++ else if (of_machine_is_compatible("netgear,r8000")) ++ sw_dev->cpu_port = 8; ++ ++ /* ++ * Workaround for devices using port 8 (connected to the 3rd iface). ++ * For some reason it doesn't work (no packets on eth2). ++ */ ++ if (of_machine_is_compatible("netgear,r8000")) ++ sw_dev->cpu_port = 5; ++ + /* cpu port is always last */ + sw_dev->ports = sw_dev->cpu_port + 1; + dev->enabled_ports |= BIT(sw_dev->cpu_port); diff --git a/target/linux/bcm53xx/patches-4.4/800-bcma-use-two-different-initcalls-if-built-in.patch b/target/linux/bcm53xx/patches-4.4/800-bcma-use-two-different-initcalls-if-built-in.patch new file mode 100644 index 0000000..eb9ab2f --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/800-bcma-use-two-different-initcalls-if-built-in.patch @@ -0,0 +1,65 @@ +From 666bdfc027cde41a171862dc698987a378c8b66a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Mon, 9 Feb 2015 18:00:42 +0100 +Subject: [PATCH RFC] bcma: use two different initcalls if built-in +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is needed as we can't initialize bus during fs_initcall. +Initialization requires SPROM which depends on NVRAM which depends on +mtd. Since mtd, spi, nand, spi-nor use standard module_init, we have to +do the same in bcma. +Without this we'll try to initialize SPROM without having a ready SPROM +proviver registered using bcma_arch_register_fallback_sprom. + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- +While this patch seems to work and I can compile bcma as built-in and +module, I'm not too proud of it. I don't really like these #if(n)def +tricks and I'm afraid bcma_modinit may be called even if +bcma_modinit_early failed. + +Do you see any better idea of solving this? +--- + drivers/bcma/main.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -668,13 +668,25 @@ static int bcma_device_uevent(struct dev + core->id.rev, core->id.class); + } + ++/* Bus has to be registered early, before any bcma driver */ ++static int __init bcma_modinit_early(void) ++{ ++ return bus_register(&bcma_bus_type); ++} ++#ifndef MODULE ++fs_initcall(bcma_modinit_early); ++#endif ++ ++/* Initialization has to be done later with SPI/mtd/NAND/SPROM available */ + static int __init bcma_modinit(void) + { + int err; + +- err = bus_register(&bcma_bus_type); ++#ifdef MODULE ++ err = bcma_modinit_early(); + if (err) + return err; ++#endif + + err = bcma_host_soc_register_driver(); + if (err) { +@@ -691,7 +703,7 @@ static int __init bcma_modinit(void) + + return err; + } +-fs_initcall(bcma_modinit); ++module_init(bcma_modinit); + + static void __exit bcma_modexit(void) + { diff --git a/target/linux/bcm53xx/patches-4.4/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch b/target/linux/bcm53xx/patches-4.4/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch new file mode 100644 index 0000000..c1dfa92 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch @@ -0,0 +1,42 @@ +From 21500872c1dba33848ddcf6bea97d58772675d36 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Sun, 17 May 2015 14:00:52 +0200 +Subject: [PATCH] mtd: bcm47xxpart: workaround for Asus RT-AC87U "asus" + partition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +--- + drivers/mtd/bcm47xxpart.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -14,6 +14,7 @@ + #include <linux/slab.h> + #include <linux/mtd/mtd.h> + #include <linux/mtd/partitions.h> ++#include <linux/of.h> + + #include <uapi/linux/magic.h> + +@@ -135,6 +136,17 @@ static int bcm47xxpart_parse(struct mtd_ + break; + } + ++ /* ++ * Ugly workaround for Asus RT-AC87U and its "asus" partition. ++ * It uses JFFS2 which we don't (want to) detect. We should ++ * probably use DT to define partitions but we need a working ++ * TRX firmware splitter first. ++ */ ++ if (of_machine_is_compatible("asus,rt-ac87u") && offset == 0x7ec0000) { ++ bcm47xxpart_add_part(&parts[curr_part++], "asus", offset, MTD_WRITEABLE); ++ continue; ++ } ++ + /* Read beginning of the block */ + if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ, + &bytes_read, (uint8_t *)buf) < 0) { |