diff options
21 files changed, 3823 insertions, 0 deletions
diff --git a/target/linux/pistachio/config-4.9 b/target/linux/pistachio/config-4.9 new file mode 100644 index 0000000000..00af5875b2 --- /dev/null +++ b/target/linux/pistachio/config-4.9 @@ -0,0 +1,340 @@ +CONFIG_ARCH_BINFMT_ELF_STATE=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_DISCARD_MEMBLOCK=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set +# CONFIG_ARCH_HAS_SG_CHAIN is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_SD=y +CONFIG_BOARD_SCACHE=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1 +CONFIG_BOOT_ELF32=y +CONFIG_CEVT_R4K=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MIPS_GIC=y +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_PISTACHIO=y +CONFIG_CLKSRC_PROBE=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_CONNECTOR=y +CONFIG_CPU_GENERIC_DUMP_TLB=y +CONFIG_CPU_HAS_PREFETCH=y +CONFIG_CPU_HAS_RIXI=y +CONFIG_CPU_HAS_SYNC=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPS32_R2=y +CONFIG_CPU_MIPSR2=y +CONFIG_CPU_MIPSR2_IRQ_EI=y +CONFIG_CPU_MIPSR2_IRQ_VI=y +CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y +CONFIG_CPU_PM=y +CONFIG_CPU_R4K_CACHE_TLB=y +CONFIG_CPU_R4K_FPU=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_CPU_SUPPORTS_MSA=y +CONFIG_CRC16=y +CONFIG_CRC_CCITT=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CSRC_R4K=y +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_DMA_OF=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DTC=y +CONFIG_DWMAC_GENERIC=y +CONFIG_EARLY_PRINTK=y +CONFIG_EARLY_PRINTK_8250=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FIXED_PHY=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ATOMIC64=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_GENERIC_IRQ_IPI=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_SYSFS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDWARE_WATCHPOINTS=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +# CONFIG_HAVE_ARCH_BITREVERSE is not set +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_CBPF_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_DEBUG_STACKOVERFLOW=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_KVM=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HOTPLUG_CPU=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_IMG=y +CONFIG_IMGPDC_WDT=y +CONFIG_IMG_MDC_DMA=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_MIPS_CPU=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_LEDS_PWM=y +CONFIG_LIBFDT=y +CONFIG_LKDTM=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MACH_PISTACHIO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0 +CONFIG_MDIO_BOARDINFO=y +# CONFIG_MFD_MAX77620 is not set +CONFIG_MFD_SYSCON=y +CONFIG_MICREL_PHY=y +CONFIG_MIPS=y +CONFIG_MIPS_ASID_BITS=8 +CONFIG_MIPS_ASID_SHIFT=0 +CONFIG_MIPS_CLOCK_VSYSCALL=y +CONFIG_MIPS_CM=y +# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set +CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_MIPS_CMDLINE_FROM_DTB is not set +CONFIG_MIPS_CPC=y +CONFIG_MIPS_CPS=y +# CONFIG_MIPS_CPS_CPUIDLE is not set +# CONFIG_MIPS_CPS_NS16550 is not set +CONFIG_MIPS_CPS_PM=y +CONFIG_MIPS_CPU_SCACHE=y +# CONFIG_MIPS_ELF_APPENDED_DTB is not set +CONFIG_MIPS_EXTERNAL_TIMER=y +CONFIG_MIPS_FPU_EMULATOR=y +CONFIG_MIPS_GIC=y +# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set +CONFIG_MIPS_L1_CACHE_SHIFT=5 +# CONFIG_MIPS_MACHINE is not set +CONFIG_MIPS_MT=y +CONFIG_MIPS_MT_FPAFF=y +CONFIG_MIPS_MT_SMP=y +CONFIG_MIPS_NO_APPENDED_DTB=y +CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y +# CONFIG_MIPS_RAW_APPENDED_DTB is not set +CONFIG_MIPS_SPRAM=y +# CONFIG_MIPS_VPE_LOADER is not set +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_DW=y +# CONFIG_MMC_DW_EXYNOS is not set +# CONFIG_MMC_DW_K3 is not set +CONFIG_MMC_DW_PLTFM=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set +CONFIG_MTD_SPI_NAND=y +CONFIG_MTD_SPI_NAND_DEVICES=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +CONFIG_MTD_UBI_FASTMAP=y +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_NAMESPACES=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_NS=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NLS=y +CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_IOPORT_MAP is not set +CONFIG_NR_CPUS=4 +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_PADATA=y +CONFIG_PCI_DRIVERS_LEGACY=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +# CONFIG_PGTABLE_MAPPING is not set +CONFIG_PHYLIB=y +CONFIG_PHY_PISTACHIO_USB=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_PISTACHIO=y +CONFIG_PISTACHIO_GPTIMER_CLKSRC=y +CONFIG_POWER_SUPPLY=y +CONFIG_PPS=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_EVENTS=y +CONFIG_PROFILING=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PWM=y +CONFIG_PWM_IMG=y +CONFIG_PWM_SYSFS=y +CONFIG_RATIONAL=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_PISTACHIO=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_HRTICK=y +CONFIG_SCHED_INFO=y +CONFIG_SCSI=y +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_FSL is not set +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SMP=y +CONFIG_SMP_UP=y +CONFIG_SPI=y +CONFIG_SPI_IMG_SPFI=y +CONFIG_SPI_MASTER=y +CONFIG_SRAM=y +CONFIG_SRCU=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +CONFIG_SWPHY=y +CONFIG_SYNC_R4K=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_SYS_HAS_CPU_MIPS32_R2=y +CONFIG_SYS_HAS_EARLY_PRINTK=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_MIPS_CPS=y +CONFIG_SYS_SUPPORTS_MULTITHREADING=y +CONFIG_SYS_SUPPORTS_RELOCATABLE=y +CONFIG_SYS_SUPPORTS_SCHED_SMT=y +CONFIG_SYS_SUPPORTS_SMP=y +CONFIG_SYS_SUPPORTS_ZBOOT=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_STATS=y +CONFIG_TMPFS_POSIX_ACL=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_ZLIB=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWC2=y +CONFIG_USB_DWC2_DUAL_ROLE=y +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_ETH is not set +CONFIG_USB_GADGET=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USER_NS=y +CONFIG_USE_GENERIC_EARLY_PRINTK_8250=y +CONFIG_USE_OF=y +CONFIG_WATCHDOG_CORE=y +CONFIG_WEAK_ORDERING=y +CONFIG_XPS=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set diff --git a/target/linux/pistachio/patches-4.9/001-MIPS-DTS-Add-base-device-tree-for-Pistachio-SoC.patch b/target/linux/pistachio/patches-4.9/001-MIPS-DTS-Add-base-device-tree-for-Pistachio-SoC.patch new file mode 100644 index 0000000000..54d7f86f67 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/001-MIPS-DTS-Add-base-device-tree-for-Pistachio-SoC.patch @@ -0,0 +1,991 @@ +From 8efda11baddf344cbfab01dc016a8fef9bb64641 Mon Sep 17 00:00:00 2001 +From: Rahul Bedarkar <rahul.bedarkar@imgtec.com> +Date: Fri, 14 Oct 2016 11:25:54 +0530 +Subject: MIPS: DTS: Add base device tree for Pistachio SoC + +Add support for the base Device Tree for Imagination Technologies' +Pistachio SoC. + +This commit supports the following peripherals: + + * Clocks + * Pinctrl and GPIO + * UART + * SPI + * I2C + * PWM + * ADC + * Watchdog + * Ethernet + * MMC + * DMA engine + * Crypto + * I2S + * SPDIF + * Internal DAC + * Timer + * USB + * IR + * Interrupt Controller + +Signed-off-by: Rahul Bedarkar <rahul.bedarkar@imgtec.com> +Acked-by: James Hartley <james.hartley@imgtec.com> +Cc: Rob Herring <robh+dt@kernel.org> +Cc: Mark Rutland <mark.rutland@arm.com> +Cc: linux-mips@linux-mips.org +Cc: devicetree@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Patchwork: https://patchwork.linux-mips.org/patch/14393/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + MAINTAINERS | 2 +- + arch/mips/boot/dts/img/pistachio.dtsi | 924 ++++++++++++++++++++++++++++++++++ + 2 files changed, 925 insertions(+), 1 deletion(-) + create mode 100644 arch/mips/boot/dts/img/pistachio.dtsi + +diff --git a/MAINTAINERS b/MAINTAINERS +index 63cefa6..f0037c7 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -9569,7 +9569,7 @@ L: linux-mips@linux-mips.org + S: Maintained + F: arch/mips/pistachio/ + F: arch/mips/include/asm/mach-pistachio/ +-F: arch/mips/boot/dts/pistachio/ ++F: arch/mips/boot/dts/img/pistachio* + F: arch/mips/configs/pistachio*_defconfig + + PKTCDVD DRIVER +diff --git a/arch/mips/boot/dts/img/pistachio.dtsi b/arch/mips/boot/dts/img/pistachio.dtsi +new file mode 100644 +index 0000000..57809f6 +--- /dev/null ++++ b/arch/mips/boot/dts/img/pistachio.dtsi +@@ -0,0 +1,924 @@ ++/* ++ * Copyright (C) 2015, 2016 Imagination Technologies Ltd. ++ * Copyright (C) 2015 Google, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <dt-bindings/clock/pistachio-clk.h> ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/interrupt-controller/irq.h> ++#include <dt-bindings/interrupt-controller/mips-gic.h> ++#include <dt-bindings/reset/pistachio-resets.h> ++ ++/ { ++ compatible = "img,pistachio"; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ interrupt-parent = <&gic>; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "mti,interaptiv"; ++ reg = <0>; ++ clocks = <&clk_core CLK_MIPS_PLL>; ++ clock-names = "cpu"; ++ clock-latency = <1000>; ++ operating-points = < ++ /* kHz uV(dummy) */ ++ 546000 1150000 ++ 520000 1100000 ++ 494000 1000000 ++ 468000 950000 ++ 442000 900000 ++ 416000 800000 ++ >; ++ }; ++ }; ++ ++ i2c0: i2c@18100000 { ++ compatible = "img,scb-i2c"; ++ reg = <0x18100000 0x200>; ++ interrupts = <GIC_SHARED 2 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_periph PERIPH_CLK_I2C0>, ++ <&cr_periph SYS_CLK_I2C0>; ++ clock-names = "scb", "sys"; ++ assigned-clocks = <&clk_periph PERIPH_CLK_I2C0_PRE_DIV>, ++ <&clk_periph PERIPH_CLK_I2C0_DIV>; ++ assigned-clock-rates = <100000000>, <33333334>; ++ status = "disabled"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ i2c1: i2c@18100200 { ++ compatible = "img,scb-i2c"; ++ reg = <0x18100200 0x200>; ++ interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_periph PERIPH_CLK_I2C1>, ++ <&cr_periph SYS_CLK_I2C1>; ++ clock-names = "scb", "sys"; ++ assigned-clocks = <&clk_periph PERIPH_CLK_I2C1_PRE_DIV>, ++ <&clk_periph PERIPH_CLK_I2C1_DIV>; ++ assigned-clock-rates = <100000000>, <33333334>; ++ status = "disabled"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ i2c2: i2c@18100400 { ++ compatible = "img,scb-i2c"; ++ reg = <0x18100400 0x200>; ++ interrupts = <GIC_SHARED 4 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_periph PERIPH_CLK_I2C2>, ++ <&cr_periph SYS_CLK_I2C2>; ++ clock-names = "scb", "sys"; ++ assigned-clocks = <&clk_periph PERIPH_CLK_I2C2_PRE_DIV>, ++ <&clk_periph PERIPH_CLK_I2C2_DIV>; ++ assigned-clock-rates = <100000000>, <33333334>; ++ status = "disabled"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ i2c3: i2c@18100600 { ++ compatible = "img,scb-i2c"; ++ reg = <0x18100600 0x200>; ++ interrupts = <GIC_SHARED 5 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_periph PERIPH_CLK_I2C3>, ++ <&cr_periph SYS_CLK_I2C3>; ++ clock-names = "scb", "sys"; ++ assigned-clocks = <&clk_periph PERIPH_CLK_I2C3_PRE_DIV>, ++ <&clk_periph PERIPH_CLK_I2C3_DIV>; ++ assigned-clock-rates = <100000000>, <33333334>; ++ status = "disabled"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c3_pins>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ i2s_in: i2s-in@18100800 { ++ compatible = "img,i2s-in"; ++ reg = <0x18100800 0x200>; ++ interrupts = <GIC_SHARED 7 IRQ_TYPE_LEVEL_HIGH>; ++ dmas = <&mdc 30 0xffffffff 0>; ++ dma-names = "rx"; ++ clocks = <&cr_periph SYS_CLK_I2S_IN>; ++ clock-names = "sys"; ++ img,i2s-channels = <6>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2s_in_pins>; ++ status = "disabled"; ++ ++ #sound-dai-cells = <0>; ++ }; ++ ++ i2s_out: i2s-out@18100a00 { ++ compatible = "img,i2s-out"; ++ reg = <0x18100a00 0x200>; ++ interrupts = <GIC_SHARED 13 IRQ_TYPE_LEVEL_HIGH>; ++ dmas = <&mdc 23 0xffffffff 0>; ++ dma-names = "tx"; ++ clocks = <&cr_periph SYS_CLK_I2S_OUT>, ++ <&clk_core CLK_I2S>; ++ clock-names = "sys", "ref"; ++ assigned-clocks = <&clk_core CLK_I2S_DIV>; ++ assigned-clock-rates = <12288000>; ++ img,i2s-channels = <6>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2s_out_pins>; ++ status = "disabled"; ++ resets = <&pistachio_reset PISTACHIO_RESET_I2S_OUT>; ++ reset-names = "rst"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ parallel_out: parallel-audio-out@18100c00 { ++ compatible = "img,parallel-out"; ++ reg = <0x18100c00 0x100>; ++ interrupts = <GIC_SHARED 19 IRQ_TYPE_LEVEL_HIGH>; ++ dmas = <&mdc 16 0xffffffff 0>; ++ dma-names = "tx"; ++ clocks = <&cr_periph SYS_CLK_PAUD_OUT>, ++ <&clk_core CLK_AUDIO_DAC>; ++ clock-names = "sys", "ref"; ++ assigned-clocks = <&clk_core CLK_AUDIO_DAC_DIV>; ++ assigned-clock-rates = <12288000>; ++ status = "disabled"; ++ resets = <&pistachio_reset PISTACHIO_RESET_PRL_OUT>; ++ reset-names = "rst"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ spdif_out: spdif-out@18100d00 { ++ compatible = "img,spdif-out"; ++ reg = <0x18100d00 0x100>; ++ interrupts = <GIC_SHARED 21 IRQ_TYPE_LEVEL_HIGH>; ++ dmas = <&mdc 14 0xffffffff 0>; ++ dma-names = "tx"; ++ clocks = <&cr_periph SYS_CLK_SPDIF_OUT>, ++ <&clk_core CLK_SPDIF>; ++ clock-names = "sys", "ref"; ++ assigned-clocks = <&clk_core CLK_SPDIF_DIV>; ++ assigned-clock-rates = <12288000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spdif_out_pin>; ++ status = "disabled"; ++ resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>; ++ reset-names = "rst"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ spdif_in: spdif-in@18100e00 { ++ compatible = "img,spdif-in"; ++ reg = <0x18100e00 0x100>; ++ interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>; ++ dmas = <&mdc 15 0xffffffff 0>; ++ dma-names = "rx"; ++ clocks = <&cr_periph SYS_CLK_SPDIF_IN>; ++ clock-names = "sys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spdif_in_pin>; ++ status = "disabled"; ++ ++ #sound-dai-cells = <0>; ++ }; ++ ++ internal_dac: internal-dac { ++ compatible = "img,pistachio-internal-dac"; ++ img,cr-top = <&cr_top>; ++ img,voltage-select = <1>; ++ ++ #sound-dai-cells = <0>; ++ }; ++ ++ spfi0: spi@18100f00 { ++ compatible = "img,spfi"; ++ reg = <0x18100f00 0x100>; ++ interrupts = <GIC_SHARED 22 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_core CLK_SPI0>, <&cr_periph SYS_CLK_SPI0_MASTER>; ++ clock-names = "sys", "spfi"; ++ dmas = <&mdc 9 0xffffffff 0>, <&mdc 10 0xffffffff 0>; ++ dma-names = "rx", "tx"; ++ spfi-max-frequency = <50000000>; ++ status = "disabled"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ spfi1: spi@18101000 { ++ compatible = "img,spfi"; ++ reg = <0x18101000 0x100>; ++ interrupts = <GIC_SHARED 26 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_core CLK_SPI1>, <&cr_periph SYS_CLK_SPI1>; ++ clock-names = "sys", "spfi"; ++ dmas = <&mdc 1 0xffffffff 0>, <&mdc 2 0xffffffff 0>; ++ dma-names = "rx", "tx"; ++ img,supports-quad-mode; ++ spfi-max-frequency = <50000000>; ++ status = "disabled"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ pwm: pwm@18101300 { ++ compatible = "img,pistachio-pwm"; ++ reg = <0x18101300 0x100>; ++ clocks = <&clk_periph PERIPH_CLK_PWM>, ++ <&cr_periph SYS_CLK_PWM>; ++ clock-names = "pwm", "sys"; ++ img,cr-periph = <&cr_periph>; ++ #pwm-cells = <2>; ++ status = "disabled"; ++ }; ++ ++ uart0: uart@18101400 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x18101400 0x100>; ++ interrupts = <GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_core CLK_UART0>, <&cr_periph SYS_CLK_UART0>; ++ clock-names = "baudclk", "apb_pclk"; ++ assigned-clocks = <&clk_core CLK_UART0_INTERNAL_DIV>, ++ <&clk_core CLK_UART0_DIV>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ pinctrl-0 = <&uart0_pins>, <&uart0_rts_cts_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ ++ uart1: uart@18101500 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x18101500 0x100>; ++ interrupts = <GIC_SHARED 25 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_core CLK_UART1>, <&cr_periph SYS_CLK_UART1>; ++ clock-names = "baudclk", "apb_pclk"; ++ assigned-clocks = <&clk_core CLK_UART1_INTERNAL_DIV>, ++ <&clk_core CLK_UART1_DIV>; ++ assigned-clock-rates = <114278400>, <1843200>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ pinctrl-0 = <&uart1_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ ++ adc: adc@18101600 { ++ compatible = "cosmic,10001-adc"; ++ reg = <0x18101600 0x24>; ++ adc-reserved-channels = <0x30>; ++ clocks = <&clk_core CLK_AUX_ADC>; ++ clock-names = "adc"; ++ assigned-clocks = <&clk_core CLK_AUX_ADC_INTERNAL_DIV>, ++ <&clk_core CLK_AUX_ADC_DIV>; ++ assigned-clock-rates = <100000000>, <1000000>; ++ status = "disabled"; ++ ++ #io-channel-cells = <1>; ++ }; ++ ++ pinctrl: pinctrl@18101c00 { ++ compatible = "img,pistachio-system-pinctrl"; ++ reg = <0x18101c00 0x400>; ++ ++ gpio0: gpio0 { ++ interrupts = <GIC_SHARED 71 IRQ_TYPE_LEVEL_HIGH>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 0 16>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio1: gpio1 { ++ interrupts = <GIC_SHARED 72 IRQ_TYPE_LEVEL_HIGH>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 16 16>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio2: gpio2 { ++ interrupts = <GIC_SHARED 73 IRQ_TYPE_LEVEL_HIGH>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 32 16>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio3: gpio3 { ++ interrupts = <GIC_SHARED 74 IRQ_TYPE_LEVEL_HIGH>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 48 16>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio4: gpio4 { ++ interrupts = <GIC_SHARED 75 IRQ_TYPE_LEVEL_HIGH>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 64 16>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio5: gpio5 { ++ interrupts = <GIC_SHARED 76 IRQ_TYPE_LEVEL_HIGH>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 80 10>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ i2c0_pins: i2c0-pins { ++ pin_i2c0: i2c0 { ++ pins = "mfio28", "mfio29"; ++ function = "i2c0"; ++ drive-strength = <4>; ++ }; ++ }; ++ ++ i2c1_pins: i2c1-pins { ++ pin_i2c1: i2c1 { ++ pins = "mfio30", "mfio31"; ++ function = "i2c1"; ++ drive-strength = <4>; ++ }; ++ }; ++ ++ i2c2_pins: i2c2-pins { ++ pin_i2c2: i2c2 { ++ pins = "mfio32", "mfio33"; ++ function = "i2c2"; ++ drive-strength = <4>; ++ }; ++ }; ++ ++ i2c3_pins: i2c3-pins { ++ pin_i2c3: i2c3 { ++ pins = "mfio34", "mfio35"; ++ function = "i2c3"; ++ drive-strength = <4>; ++ }; ++ }; ++ ++ spim0_pins: spim0-pins { ++ pin_spim0: spim0 { ++ pins = "mfio9", "mfio10"; ++ function = "spim0"; ++ drive-strength = <4>; ++ }; ++ spim0_clk: spim0-clk { ++ pins = "mfio8"; ++ function = "spim0"; ++ drive-strength = <4>; ++ }; ++ }; ++ ++ spim0_cs0_alt_pin: spim0-cs0-alt-pin { ++ spim0-cs0 { ++ pins = "mfio2"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim0_cs1_pin: spim0-cs1-pin { ++ spim0-cs1 { ++ pins = "mfio1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim0_cs2_pin: spim0-cs2-pin { ++ spim0-cs2 { ++ pins = "mfio55"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim0_cs2_alt_pin: spim0-cs2-alt-pin { ++ spim0-cs2 { ++ pins = "mfio28"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim0_cs3_pin: spim0-cs3-pin { ++ spim0-cs3 { ++ pins = "mfio56"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim0_cs3_alt_pin: spim0-cs3-alt-pin { ++ spim0-cs3 { ++ pins = "mfio29"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim0_cs4_pin: spim0-cs4-pin { ++ spim0-cs4 { ++ pins = "mfio57"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim0_cs4_alt_pin: spim0-cs4-alt-pin { ++ spim0-cs4 { ++ pins = "mfio30"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_pins: spim1-pins { ++ spim1 { ++ pins = "mfio3", "mfio4", "mfio5"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_quad_pins: spim1-quad-pins { ++ spim1-quad { ++ pins = "mfio6", "mfio7"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_cs0_pin: spim1-cs0-pins { ++ spim1-cs0 { ++ pins = "mfio0"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_cs1_pin: spim1-cs1-pin { ++ spim1-cs1 { ++ pins = "mfio1"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_cs1_alt_pin: spim1-cs1-alt-pin { ++ spim1-cs1 { ++ pins = "mfio58"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_cs2_pin: spim1-cs2-pin { ++ spim1-cs2 { ++ pins = "mfio2"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_cs2_alt0_pin: spim1-cs2-alt0-pin { ++ spim1-cs2 { ++ pins = "mfio31"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_cs2_alt1_pin: spim1-cs2-alt1-pin { ++ spim1-cs2 { ++ pins = "mfio55"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_cs3_pin: spim1-cs3-pin { ++ spim1-cs3 { ++ pins = "mfio56"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spim1_cs4_pin: spim1-cs4-pin { ++ spim1-cs4 { ++ pins = "mfio57"; ++ function = "spim1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ uart0_pins: uart0-pins { ++ uart0 { ++ pins = "mfio55", "mfio56"; ++ function = "uart0"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ uart0_rts_cts_pins: uart0-rts-cts-pins { ++ uart0-rts-cts { ++ pins = "mfio57", "mfio58"; ++ function = "uart0"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ uart1_pins: uart1-pins { ++ uart1 { ++ pins = "mfio59", "mfio60"; ++ function = "uart1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ uart1_rts_cts_pins: uart1-rts-cts-pins { ++ uart1-rts-cts { ++ pins = "mfio1", "mfio2"; ++ function = "uart1"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ enet_pins: enet-pins { ++ pin_enet: enet { ++ pins = "mfio63", "mfio64", "mfio65", "mfio66", ++ "mfio67", "mfio68", "mfio69", "mfio70"; ++ function = "eth"; ++ slew-rate = <1>; ++ drive-strength = <4>; ++ }; ++ pin_enet_phy_clk: enet-phy-clk { ++ pins = "mfio71"; ++ function = "eth"; ++ slew-rate = <1>; ++ drive-strength = <8>; ++ }; ++ }; ++ ++ sdhost_pins: sdhost-pins { ++ pin_sdhost_clk: sdhost-clk { ++ pins = "mfio15"; ++ function = "sdhost"; ++ slew-rate = <1>; ++ drive-strength = <4>; ++ }; ++ pin_sdhost_cmd: sdhost-cmd { ++ pins = "mfio16"; ++ function = "sdhost"; ++ slew-rate = <1>; ++ drive-strength = <4>; ++ }; ++ pin_sdhost_data: sdhost-data { ++ pins = "mfio17", "mfio18", "mfio19", "mfio20", ++ "mfio21", "mfio22", "mfio23", "mfio24"; ++ function = "sdhost"; ++ slew-rate = <1>; ++ drive-strength = <4>; ++ }; ++ pin_sdhost_power_select: sdhost-power-select { ++ pins = "mfio25"; ++ function = "sdhost"; ++ slew-rate = <1>; ++ drive-strength = <2>; ++ }; ++ pin_sdhost_card_detect: sdhost-card-detect { ++ pins = "mfio26"; ++ function = "sdhost"; ++ drive-strength = <2>; ++ }; ++ pin_sdhost_write_protect: sdhost-write-protect { ++ pins = "mfio27"; ++ function = "sdhost"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ ir_pin: ir-pin { ++ ir-data { ++ pins = "mfio72"; ++ function = "ir"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ pwmpdm0_pin: pwmpdm0-pin { ++ pwmpdm0 { ++ pins = "mfio73"; ++ function = "pwmpdm"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ pwmpdm1_pin: pwmpdm1-pin { ++ pwmpdm1 { ++ pins = "mfio74"; ++ function = "pwmpdm"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ pwmpdm2_pin: pwmpdm2-pin { ++ pwmpdm2 { ++ pins = "mfio75"; ++ function = "pwmpdm"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ pwmpdm3_pin: pwmpdm3-pin { ++ pwmpdm3 { ++ pins = "mfio76"; ++ function = "pwmpdm"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ dac_clk_pin: dac-clk-pin { ++ pin_dac_clk: dac-clk { ++ pins = "mfio45"; ++ function = "i2s_dac_clk"; ++ drive-strength = <4>; ++ }; ++ }; ++ ++ i2s_mclk_pin: i2s-mclk-pin { ++ pin_i2s_mclk: i2s-mclk { ++ pins = "mfio36"; ++ function = "i2s_out"; ++ drive-strength = <4>; ++ }; ++ }; ++ ++ spdif_out_pin: spdif-out-pin { ++ spdif-out { ++ pins = "mfio61"; ++ function = "spdif_out"; ++ slew-rate = <1>; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ spdif_in_pin: spdif-in-pin { ++ spdif-in { ++ pins = "mfio62"; ++ function = "spdif_in"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ i2s_out_pins: i2s-out-pins { ++ pins_i2s_out_clk: i2s-out-clk { ++ pins = "mfio37", "mfio38"; ++ function = "i2s_out"; ++ drive-strength = <4>; ++ }; ++ pins_i2s_out: i2s-out { ++ pins = "mfio39", "mfio40", ++ "mfio41", "mfio42", ++ "mfio43", "mfio44"; ++ function = "i2s_out"; ++ drive-strength = <2>; ++ }; ++ }; ++ ++ i2s_in_pins: i2s-in-pins { ++ i2s-in { ++ pins = "mfio47", "mfio48", "mfio49", ++ "mfio50", "mfio51", "mfio52", ++ "mfio53", "mfio54"; ++ function = "i2s_in"; ++ drive-strength = <2>; ++ }; ++ }; ++ }; ++ ++ timer: timer@18102000 { ++ compatible = "img,pistachio-gptimer"; ++ reg = <0x18102000 0x100>; ++ interrupts = <GIC_SHARED 60 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_periph PERIPH_CLK_COUNTER_FAST>, ++ <&cr_periph SYS_CLK_TIMER>; ++ clock-names = "fast", "sys"; ++ img,cr-periph = <&cr_periph>; ++ }; ++ ++ wdt: watchdog@18102100 { ++ compatible = "img,pdc-wdt"; ++ reg = <0x18102100 0x100>; ++ interrupts = <GIC_SHARED 52 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_periph PERIPH_CLK_WD>, <&cr_periph SYS_CLK_WD>; ++ clock-names = "wdt", "sys"; ++ assigned-clocks = <&clk_periph PERIPH_CLK_WD_PRE_DIV>, ++ <&clk_periph PERIPH_CLK_WD_DIV>; ++ assigned-clock-rates = <4000000>, <32768>; ++ }; ++ ++ ir: ir@18102200 { ++ compatible = "img,ir-rev1"; ++ reg = <0x18102200 0x100>; ++ interrupts = <GIC_SHARED 51 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_periph PERIPH_CLK_IR>, <&cr_periph SYS_CLK_IR>; ++ clock-names = "core", "sys"; ++ assigned-clocks = <&clk_periph PERIPH_CLK_IR_PRE_DIV>, ++ <&clk_periph PERIPH_CLK_IR_DIV>; ++ assigned-clock-rates = <4000000>, <32768>; ++ pinctrl-0 = <&ir_pin>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ ++ usb: usb@18120000 { ++ compatible = "snps,dwc2"; ++ reg = <0x18120000 0x1c000>; ++ interrupts = <GIC_SHARED 49 IRQ_TYPE_LEVEL_HIGH>; ++ phys = <&usb_phy>; ++ phy-names = "usb2-phy"; ++ g-tx-fifo-size = <256 256 256 256>; ++ status = "disabled"; ++ }; ++ ++ enet: ethernet@18140000 { ++ compatible = "snps,dwmac"; ++ reg = <0x18140000 0x2000>; ++ interrupts = <GIC_SHARED 50 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "macirq"; ++ clocks = <&clk_core CLK_ENET>, <&cr_periph SYS_CLK_ENET>; ++ clock-names = "stmmaceth", "pclk"; ++ assigned-clocks = <&clk_core CLK_ENET_MUX>, ++ <&clk_core CLK_ENET_DIV>; ++ assigned-clock-parents = <&clk_core CLK_SYS_INTERNAL_DIV>; ++ assigned-clock-rates = <0>, <50000000>; ++ pinctrl-0 = <&enet_pins>; ++ pinctrl-names = "default"; ++ phy-mode = "rmii"; ++ status = "disabled"; ++ }; ++ ++ sdhost: mmc@18142000 { ++ compatible = "img,pistachio-dw-mshc"; ++ reg = <0x18142000 0x400>; ++ interrupts = <GIC_SHARED 39 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clk_core CLK_SD_HOST>, <&cr_periph SYS_CLK_SD_HOST>; ++ clock-names = "ciu", "biu"; ++ pinctrl-0 = <&sdhost_pins>; ++ pinctrl-names = "default"; ++ fifo-depth = <0x20>; ++ num-slots = <1>; ++ clock-frequency = <50000000>; ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ cap-sd-highspeed; ++ status = "disabled"; ++ }; ++ ++ sram: sram@1b000000 { ++ compatible = "mmio-sram"; ++ reg = <0x1b000000 0x10000>; ++ }; ++ ++ mdc: dma-controller@18143000 { ++ compatible = "img,pistachio-mdc-dma"; ++ reg = <0x18143000 0x1000>; ++ interrupts = <GIC_SHARED 27 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 28 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 29 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 30 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 31 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 32 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 33 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 34 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 35 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 36 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 37 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SHARED 38 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&cr_periph SYS_CLK_MDC>; ++ clock-names = "sys"; ++ ++ img,max-burst-multiplier = <16>; ++ img,cr-periph = <&cr_periph>; ++ ++ #dma-cells = <3>; ++ }; ++ ++ clk_core: clk@18144000 { ++ compatible = "img,pistachio-clk", "syscon"; ++ clocks = <&xtal>, <&cr_top EXT_CLK_AUDIO_IN>, ++ <&cr_top EXT_CLK_ENET_IN>; ++ clock-names = "xtal", "audio_refclk_ext_gate", ++ "ext_enet_in_gate"; ++ reg = <0x18144000 0x800>; ++ #clock-cells = <1>; ++ }; ++ ++ clk_periph: clk@18144800 { ++ compatible = "img,pistachio-clk-periph"; ++ reg = <0x18144800 0x1000>; ++ clocks = <&clk_core CLK_PERIPH_SYS>; ++ clock-names = "periph_sys_core"; ++ #clock-cells = <1>; ++ }; ++ ++ cr_periph: clk@18148000 { ++ compatible = "img,pistachio-cr-periph", "syscon", "simple-bus"; ++ reg = <0x18148000 0x1000>; ++ clocks = <&clk_periph PERIPH_CLK_SYS>; ++ clock-names = "sys"; ++ #clock-cells = <1>; ++ ++ pistachio_reset: reset-controller { ++ compatible = "img,pistachio-reset"; ++ #reset-cells = <1>; ++ }; ++ }; ++ ++ cr_top: clk@18149000 { ++ compatible = "img,pistachio-cr-top", "syscon"; ++ reg = <0x18149000 0x200>; ++ #clock-cells = <1>; ++ }; ++ ++ hash: hash@18149600 { ++ compatible = "img,hash-accelerator"; ++ reg = <0x18149600 0x100>, <0x18101100 0x4>; ++ interrupts = <GIC_SHARED 59 IRQ_TYPE_LEVEL_HIGH>; ++ dmas = <&mdc 8 0xffffffff 0>; ++ dma-names = "tx"; ++ clocks = <&cr_periph SYS_CLK_HASH>, ++ <&clk_periph PERIPH_CLK_ROM>; ++ clock-names = "sys", "hash"; ++ }; ++ ++ gic: interrupt-controller@1bdc0000 { ++ compatible = "mti,gic"; ++ reg = <0x1bdc0000 0x20000>; ++ ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ++ timer { ++ compatible = "mti,gic-timer"; ++ interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>; ++ clocks = <&clk_core CLK_MIPS>; ++ }; ++ }; ++ ++ usb_phy: usb-phy { ++ compatible = "img,pistachio-usb-phy"; ++ clocks = <&clk_core CLK_USB_PHY>; ++ clock-names = "usb_phy"; ++ assigned-clocks = <&clk_core CLK_USB_PHY_DIV>; ++ assigned-clock-rates = <50000000>; ++ img,refclk = <0x2>; ++ img,cr-top = <&cr_top>; ++ #phy-cells = <0>; ++ }; ++ ++ xtal: xtal { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <52000000>; ++ clock-output-names = "xtal"; ++ }; ++}; +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/002-MIPS-DTS-img-add-device-tree-for-Marduk-board.patch b/target/linux/pistachio/patches-4.9/002-MIPS-DTS-img-add-device-tree-for-Marduk-board.patch new file mode 100644 index 0000000000..2682ac2d3d --- /dev/null +++ b/target/linux/pistachio/patches-4.9/002-MIPS-DTS-img-add-device-tree-for-Marduk-board.patch @@ -0,0 +1,242 @@ +From a189771546b304250cf18b26748edfefb857adbf Mon Sep 17 00:00:00 2001 +From: Rahul Bedarkar <rahul.bedarkar@imgtec.com> +Date: Fri, 14 Oct 2016 11:25:55 +0530 +Subject: MIPS: DTS: img: add device tree for Marduk board + +Add support for Imagination Technologies' Marduk board which is based +on Pistachio SoC. It is also known as Creator Ci40. Marduk is legacy +name and will be there for decades. + +Documentation for this board can be found on +https://docs.creatordev.io/ci40/ + +This patch adds initial support for board with following peripherals: + +* PWM based heartbeat LED +* GPIO based buttons +* SPI NOR flash on SPI1 +* UART0 and UART1 +* SD card +* Ethernet +* USB +* PWM +* ADC +* I2C + +(apply from https://patchwork.linux-mips.org/project/linux-mips/list/?submitter=7165) + +Signed-off-by: Rahul Bedarkar <rahul.bedarkar@imgtec.com> +Acked-by: Rob Herring <robh@kernel.org> +Acked-by: James Hartley <james.hartley@imgtec.com> +--- + .../bindings/mips/img/pistachio-marduk.txt | 10 ++ + arch/mips/boot/dts/img/Makefile | 9 ++ + arch/mips/boot/dts/img/pistachio_marduk.dts | 163 +++++++++++++++++++++ + 3 files changed, 182 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt + create mode 100644 arch/mips/boot/dts/img/Makefile + create mode 100644 arch/mips/boot/dts/img/pistachio_marduk.dts + +diff --git a/Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt b/Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt +new file mode 100644 +index 0000000..2d5126d +--- /dev/null ++++ b/Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt +@@ -0,0 +1,10 @@ ++Imagination Technologies' Pistachio SoC based Marduk Board ++========================================================== ++ ++Compatible string must be "img,pistachio-marduk", "img,pistachio" ++ ++Hardware and other related documentation is available at ++https://docs.creatordev.io/ci40/ ++ ++It is also known as Creator Ci40. Marduk is legacy name and will ++be there for decades. +diff --git a/arch/mips/boot/dts/img/Makefile b/arch/mips/boot/dts/img/Makefile +new file mode 100644 +index 0000000..69a65f0 +--- /dev/null ++++ b/arch/mips/boot/dts/img/Makefile +@@ -0,0 +1,9 @@ ++dtb-$(CONFIG_MACH_PISTACHIO) += pistachio_marduk.dtb ++ ++obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y)) ++ ++# Force kbuild to make empty built-in.o if necessary ++obj- += dummy.o ++ ++always := $(dtb-y) ++clean-files := *.dtb *.dtb.S +diff --git a/arch/mips/boot/dts/img/pistachio_marduk.dts b/arch/mips/boot/dts/img/pistachio_marduk.dts +new file mode 100644 +index 0000000..cf9cebd +--- /dev/null ++++ b/arch/mips/boot/dts/img/pistachio_marduk.dts +@@ -0,0 +1,163 @@ ++/* ++ * Copyright (C) 2015, 2016 Imagination Technologies Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * IMG Marduk board is also known as Creator Ci40. ++ */ ++ ++/dts-v1/; ++ ++#include "pistachio.dtsi" ++ ++/ { ++ model = "IMG Marduk (Creator Ci40)"; ++ compatible = "img,pistachio-marduk", "img,pistachio"; ++ ++ aliases { ++ serial0 = &uart0; ++ serial1 = &uart1; ++ ethernet0 = &enet; ++ spi0 = &spfi0; ++ spi1 = &spfi1; ++ }; ++ ++ chosen { ++ bootargs = "root=/dev/sda1 rootwait ro lpj=723968"; ++ stdout-path = "serial1:115200"; ++ }; ++ ++ memory { ++ device_type = "memory"; ++ reg = <0x00000000 0x10000000>; ++ }; ++ ++ reg_1v8: fixed-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "aux_adc_vref"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ }; ++ ++ internal_dac_supply: internal-dac-supply { ++ compatible = "regulator-fixed"; ++ regulator-name = "internal_dac_supply"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ leds { ++ compatible = "pwm-leds"; ++ heartbeat { ++ label = "marduk:red:heartbeat"; ++ pwms = <&pwm 3 300000>; ++ max-brightness = <255>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++ ++ keys { ++ compatible = "gpio-keys"; ++ button@1 { ++ label = "Button 1"; ++ linux,code = <0x101>; /* BTN_1 */ ++ gpios = <&gpio3 6 GPIO_ACTIVE_LOW>; ++ }; ++ button@2 { ++ label = "Button 2"; ++ linux,code = <0x102>; /* BTN_2 */ ++ gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++}; ++ ++&internal_dac { ++ VDD-supply = <&internal_dac_supply>; ++}; ++ ++&spfi1 { ++ status = "okay"; ++ ++ pinctrl-0 = <&spim1_pins>, <&spim1_quad_pins>, <&spim1_cs0_pin>, ++ <&spim1_cs1_pin>; ++ pinctrl-names = "default"; ++ cs-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio0 1 GPIO_ACTIVE_HIGH>; ++ ++ flash@0 { ++ compatible = "spansion,s25fl016k", "jedec,spi-nor"; ++ reg = <0>; ++ spi-max-frequency = <50000000>; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++ assigned-clock-rates = <114278400>, <1843200>; ++}; ++ ++&uart1 { ++ status = "okay"; ++}; ++ ++&usb { ++ status = "okay"; ++}; ++ ++&enet { ++ status = "okay"; ++}; ++ ++&pin_enet { ++ drive-strength = <2>; ++}; ++ ++&pin_enet_phy_clk { ++ drive-strength = <2>; ++}; ++ ++&sdhost { ++ status = "okay"; ++ bus-width = <4>; ++ disable-wp; ++}; ++ ++&pin_sdhost_cmd { ++ drive-strength = <2>; ++}; ++ ++&pin_sdhost_data { ++ drive-strength = <2>; ++}; ++ ++&pwm { ++ status = "okay"; ++ ++ pinctrl-0 = <&pwmpdm0_pin>, <&pwmpdm1_pin>, <&pwmpdm2_pin>, ++ <&pwmpdm3_pin>; ++ pinctrl-names = "default"; ++}; ++ ++&adc { ++ status = "okay"; ++ vref-supply = <®_1v8>; ++ adc-reserved-channels = <0x10>; ++}; ++ ++&i2c2 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ tpm@20 { ++ compatible = "infineon,slb9645tt"; ++ reg = <0x20>; ++ }; ++ ++}; ++ ++&i2c3 { ++ status = "okay"; ++ clock-frequency = <400000>; ++}; +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/003-MIPS-DTS-add-img-directory-to-Makefile.patch b/target/linux/pistachio/patches-4.9/003-MIPS-DTS-add-img-directory-to-Makefile.patch new file mode 100644 index 0000000000..7d06f6f1c9 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/003-MIPS-DTS-add-img-directory-to-Makefile.patch @@ -0,0 +1,27 @@ +From a907fdeb3f057e4c4b3960ca864b460dc1fa687a Mon Sep 17 00:00:00 2001 +From: Ian Pozella <Ian.Pozella@imgtec.com> +Date: Thu, 16 Feb 2017 10:42:22 +0000 +Subject: MIPS: DTS: add img directory to Makefile + +An img directory exists for the Pistchio Soc but the directory +itself isn't in the dts Makefile meaning the dtbs never get built. + +Signed-off-by: Ian Pozella <Ian.Pozella@imgtec.com> +--- + arch/mips/boot/dts/Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile +index fc7a0a9..b9db492 100644 +--- a/arch/mips/boot/dts/Makefile ++++ b/arch/mips/boot/dts/Makefile +@@ -1,5 +1,6 @@ + dts-dirs += brcm + dts-dirs += cavium-octeon ++dts-dirs += img + dts-dirs += ingenic + dts-dirs += lantiq + dts-dirs += mti +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/101-dmaengine-img-mdc-Handle-early-status-read.patch b/target/linux/pistachio/patches-4.9/101-dmaengine-img-mdc-Handle-early-status-read.patch new file mode 100644 index 0000000000..8d62699270 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/101-dmaengine-img-mdc-Handle-early-status-read.patch @@ -0,0 +1,73 @@ +From a2dd154377c9aa6ddda00d39b8c7c334e4fa16ff Mon Sep 17 00:00:00 2001 +From: Damien Horsley <damien.horsley@imgtec.com> +Date: Tue, 22 Mar 2016 12:46:09 +0000 +Subject: dmaengine: img-mdc: Handle early status read + +It is possible that mdc_tx_status may be called before the first +node has been read from memory. + +In this case, the residue value stored in the register is undefined. +Return the transfer size instead. + +Signed-off-by: Damien Horsley <damien.horsley@imgtec.com> +--- + drivers/dma/img-mdc-dma.c | 40 ++++++++++++++++++++++++---------------- + 1 file changed, 24 insertions(+), 16 deletions(-) + +diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c +index 624f1e1..0216e2c 100644 +--- a/drivers/dma/img-mdc-dma.c ++++ b/drivers/dma/img-mdc-dma.c +@@ -623,25 +623,33 @@ static enum dma_status mdc_tx_status(struct dma_chan *chan, + (MDC_CMDS_PROCESSED_CMDS_DONE_MASK + 1); + + /* +- * If the command loaded event hasn't been processed yet, then +- * the difference above includes an extra command. ++ * If the first node has not yet been read from memory, ++ * the residue register value is undefined + */ +- if (!mdesc->cmd_loaded) +- cmds--; +- else +- cmds += mdesc->list_cmds_done; +- +- bytes = mdesc->list_xfer_size; +- ldesc = mdesc->list; +- for (i = 0; i < cmds; i++) { +- bytes -= ldesc->xfer_size + 1; +- ldesc = ldesc->next_desc; +- } +- if (ldesc) { +- if (residue != MDC_TRANSFER_SIZE_MASK) +- bytes -= ldesc->xfer_size - residue; ++ if (!mdesc->cmd_loaded && !cmds) { ++ bytes = mdesc->list_xfer_size; ++ } else { ++ /* ++ * If the command loaded event hasn't been processed yet, then ++ * the difference above includes an extra command. ++ */ ++ if (!mdesc->cmd_loaded) ++ cmds--; + else ++ cmds += mdesc->list_cmds_done; ++ ++ bytes = mdesc->list_xfer_size; ++ ldesc = mdesc->list; ++ for (i = 0; i < cmds; i++) { + bytes -= ldesc->xfer_size + 1; ++ ldesc = ldesc->next_desc; ++ } ++ if (ldesc) { ++ if (residue != MDC_TRANSFER_SIZE_MASK) ++ bytes -= ldesc->xfer_size - residue; ++ else ++ bytes -= ldesc->xfer_size + 1; ++ } + } + } + spin_unlock_irqrestore(&mchan->vc.lock, flags); +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/102-spi-img-spfi-Implement-dual-and-quad-mode.patch b/target/linux/pistachio/patches-4.9/102-spi-img-spfi-Implement-dual-and-quad-mode.patch new file mode 100644 index 0000000000..ee768c4623 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/102-spi-img-spfi-Implement-dual-and-quad-mode.patch @@ -0,0 +1,203 @@ +From cd2a6af51553d38072cd31699b58d16ca6176ef5 Mon Sep 17 00:00:00 2001 +From: Ionela Voinescu <ionela.voinescu@imgtec.com> +Date: Thu, 2 Feb 2017 16:46:14 +0000 +Subject: spi: img-spfi: Implement dual and quad mode + +For dual and quad modes to work the SPFI controller needs +to have information about command/address/dummy bytes in the +transaction register. This information is not relevant for +single mode, and therefore it can have any value in the +allowed range. Therefore, for any read or write transfers of less +than 8 bytes (cmd = 1 byte, addr up to 7 bytes), SPFI will be +configured, but not enabled (unless it is the last transfer in +the queue). The transfer will be enabled by the subsequent tranfer. +A pending transfer is determined by the content of the transaction +register: if command part is set and tsize is not. + +This way we ensure that for dual and quad transactions +the command request size will apear in the command/address part +of the transaction register, while the data size will be in +tsize, all data being sent/received in the same transaction (as +set up in the transaction register). + +Signed-off-by: Ionela Voinescu <ionela.voinescu@imgtec.com> +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@imgtec.com> +--- + drivers/spi/spi-img-spfi.c | 96 ++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 85 insertions(+), 11 deletions(-) + +diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c +index 7a37090..c845a50 100644 +--- a/drivers/spi/spi-img-spfi.c ++++ b/drivers/spi/spi-img-spfi.c +@@ -40,7 +40,8 @@ + #define SPFI_CONTROL_SOFT_RESET BIT(11) + #define SPFI_CONTROL_SEND_DMA BIT(10) + #define SPFI_CONTROL_GET_DMA BIT(9) +-#define SPFI_CONTROL_SE BIT(8) ++#define SPFI_CONTROL_SE BIT(8) ++#define SPFI_CONTROL_TX_RX BIT(1) + #define SPFI_CONTROL_TMODE_SHIFT 5 + #define SPFI_CONTROL_TMODE_MASK 0x7 + #define SPFI_CONTROL_TMODE_SINGLE 0 +@@ -51,6 +52,10 @@ + #define SPFI_TRANSACTION 0x18 + #define SPFI_TRANSACTION_TSIZE_SHIFT 16 + #define SPFI_TRANSACTION_TSIZE_MASK 0xffff ++#define SPFI_TRANSACTION_CMD_SHIFT 13 ++#define SPFI_TRANSACTION_CMD_MASK 0x7 ++#define SPFI_TRANSACTION_ADDR_SHIFT 10 ++#define SPFI_TRANSACTION_ADDR_MASK 0x7 + + #define SPFI_PORT_STATE 0x1c + #define SPFI_PORT_STATE_DEV_SEL_SHIFT 20 +@@ -87,6 +92,7 @@ + */ + #define SPFI_32BIT_FIFO_SIZE 64 + #define SPFI_8BIT_FIFO_SIZE 16 ++#define SPFI_DATA_REQUEST_MAX_SIZE 8 + + struct img_spfi { + struct device *dev; +@@ -103,6 +109,8 @@ struct img_spfi { + struct dma_chan *tx_ch; + bool tx_dma_busy; + bool rx_dma_busy; ++ ++ bool complete; + }; + + struct img_spfi_device_data { +@@ -123,9 +131,11 @@ static inline void spfi_start(struct img_spfi *spfi) + { + u32 val; + +- val = spfi_readl(spfi, SPFI_CONTROL); +- val |= SPFI_CONTROL_SPFI_EN; +- spfi_writel(spfi, val, SPFI_CONTROL); ++ if (spfi->complete) { ++ val = spfi_readl(spfi, SPFI_CONTROL); ++ val |= SPFI_CONTROL_SPFI_EN; ++ spfi_writel(spfi, val, SPFI_CONTROL); ++ } + } + + static inline void spfi_reset(struct img_spfi *spfi) +@@ -138,12 +148,21 @@ static int spfi_wait_all_done(struct img_spfi *spfi) + { + unsigned long timeout = jiffies + msecs_to_jiffies(50); + ++ if (!(spfi->complete)) ++ return 0; ++ + while (time_before(jiffies, timeout)) { + u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); + + if (status & SPFI_INTERRUPT_ALLDONETRIG) { + spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG, + SPFI_INTERRUPT_CLEAR); ++ /* ++ * Disable SPFI for it not to interfere with ++ * pending transactions ++ */ ++ spfi_writel(spfi, spfi_readl(spfi, SPFI_CONTROL) ++ & ~SPFI_CONTROL_SPFI_EN, SPFI_CONTROL); + return 0; + } + cpu_relax(); +@@ -494,9 +513,32 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) + { + struct img_spfi *spfi = spi_master_get_devdata(spi->master); +- u32 val, div; ++ u32 val, div, transact; ++ bool is_pending; + + /* ++ * For read or write transfers of less than 8 bytes (cmd = 1 byte, ++ * addr up to 7 bytes), SPFI will be configured, but not enabled ++ * (unless it is the last transfer in the queue).The transfer will ++ * be enabled by the subsequent transfer. ++ * A pending transfer is determined by the content of the ++ * transaction register: if command part is set and tsize ++ * is not ++ */ ++ transact = spfi_readl(spfi, SPFI_TRANSACTION); ++ is_pending = ((transact >> SPFI_TRANSACTION_CMD_SHIFT) & ++ SPFI_TRANSACTION_CMD_MASK) && ++ (!((transact >> SPFI_TRANSACTION_TSIZE_SHIFT) & ++ SPFI_TRANSACTION_TSIZE_MASK)); ++ ++ /* If there are no pending transactions it's OK to soft reset */ ++ if (!is_pending) { ++ /* Start the transaction from a known (reset) state */ ++ spfi_reset(spfi); ++ } ++ ++ /* ++ * Before anything else, set up parameters. + * output = spfi_clk * (BITCLK / 512), where BITCLK must be a + * power of 2 up to 128 + */ +@@ -509,20 +551,52 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi, + val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT; + spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select)); + +- spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT, +- SPFI_TRANSACTION); ++ if (!list_is_last(&xfer->transfer_list, &master->cur_msg->transfers) && ++ /* ++ * For duplex mode (both the tx and rx buffers are !NULL) the ++ * CMD, ADDR, and DUMMY byte parts of the transaction register ++ * should always be 0 and therefore the pending transfer ++ * technique cannot be used. ++ */ ++ (xfer->tx_buf) && (!xfer->rx_buf) && ++ (xfer->len <= SPFI_DATA_REQUEST_MAX_SIZE) && !is_pending) { ++ transact = (1 & SPFI_TRANSACTION_CMD_MASK) << ++ SPFI_TRANSACTION_CMD_SHIFT; ++ transact |= ((xfer->len - 1) & SPFI_TRANSACTION_ADDR_MASK) << ++ SPFI_TRANSACTION_ADDR_SHIFT; ++ spfi->complete = false; ++ } else { ++ spfi->complete = true; ++ if (is_pending) { ++ /* Keep setup from pending transfer */ ++ transact |= ((xfer->len & SPFI_TRANSACTION_TSIZE_MASK) << ++ SPFI_TRANSACTION_TSIZE_SHIFT); ++ } else { ++ transact = ((xfer->len & SPFI_TRANSACTION_TSIZE_MASK) << ++ SPFI_TRANSACTION_TSIZE_SHIFT); ++ } ++ } ++ spfi_writel(spfi, transact, SPFI_TRANSACTION); + + val = spfi_readl(spfi, SPFI_CONTROL); + val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA); +- if (xfer->tx_buf) ++ /* ++ * We set up send DMA for pending transfers also, as ++ * those are always send transfers ++ */ ++ if ((xfer->tx_buf) || is_pending) + val |= SPFI_CONTROL_SEND_DMA; +- if (xfer->rx_buf) ++ if (xfer->tx_buf) ++ val |= SPFI_CONTROL_TX_RX; ++ if (xfer->rx_buf) { + val |= SPFI_CONTROL_GET_DMA; ++ val &= ~SPFI_CONTROL_TX_RX; ++ } + val &= ~(SPFI_CONTROL_TMODE_MASK << SPFI_CONTROL_TMODE_SHIFT); +- if (xfer->tx_nbits == SPI_NBITS_DUAL && ++ if (xfer->tx_nbits == SPI_NBITS_DUAL || + xfer->rx_nbits == SPI_NBITS_DUAL) + val |= SPFI_CONTROL_TMODE_DUAL << SPFI_CONTROL_TMODE_SHIFT; +- else if (xfer->tx_nbits == SPI_NBITS_QUAD && ++ else if (xfer->tx_nbits == SPI_NBITS_QUAD || + xfer->rx_nbits == SPI_NBITS_QUAD) + val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT; + val |= SPFI_CONTROL_SE; +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/103-spi-img-spfi-set-device-select-bits-for-SPFI-port-st.patch b/target/linux/pistachio/patches-4.9/103-spi-img-spfi-set-device-select-bits-for-SPFI-port-st.patch new file mode 100644 index 0000000000..d5bf309b4e --- /dev/null +++ b/target/linux/pistachio/patches-4.9/103-spi-img-spfi-set-device-select-bits-for-SPFI-port-st.patch @@ -0,0 +1,32 @@ +From 145f5369510b86cd55c659388a26a0cc267f8874 Mon Sep 17 00:00:00 2001 +From: Ionela Voinescu <ionela.voinescu@imgtec.com> +Date: Mon, 1 Feb 2016 10:58:08 +0000 +Subject: spi: img-spfi: set device select bits for SPFI port state + +Even if the chip select line is not controlled by the SPFI +hardware, the device select bits need to be set to specify +the chip select line in use for the hardware to know what +parameters to use for the current transfer. + +Signed-off-by: Ionela Voinescu <ionela.voinescu@imgtec.com> +--- + drivers/spi/spi-img-spfi.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c +index c845a50..0d73d31 100644 +--- a/drivers/spi/spi-img-spfi.c ++++ b/drivers/spi/spi-img-spfi.c +@@ -438,6 +438,9 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg) + u32 val; + + val = spfi_readl(spfi, SPFI_PORT_STATE); ++ val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << ++ SPFI_PORT_STATE_DEV_SEL_SHIFT); ++ val |= msg->spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT; + if (msg->spi->mode & SPI_CPHA) + val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select); + else +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/104-spi-img-spfi-use-device-0-configuration-for-all-devi.patch b/target/linux/pistachio/patches-4.9/104-spi-img-spfi-use-device-0-configuration-for-all-devi.patch new file mode 100644 index 0000000000..01143e2c3b --- /dev/null +++ b/target/linux/pistachio/patches-4.9/104-spi-img-spfi-use-device-0-configuration-for-all-devi.patch @@ -0,0 +1,69 @@ +From 905ee06a9966113fe51d6bad1819759cb30fd0bd Mon Sep 17 00:00:00 2001 +From: Ionela Voinescu <ionela.voinescu@imgtec.com> +Date: Tue, 9 Feb 2016 10:18:31 +0000 +Subject: spi: img-spfi: use device 0 configuration for all devices + +Given that we control the chip select line externally +we can use only one parameter register (device 0 parameter +register) and one set of configuration bits (port configuration +bits for device 0) for all devices (all chip select lines). + +Signed-off-by: Ionela Voinescu <ionela.voinescu@imgtec.com> +--- + drivers/spi/spi-img-spfi.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c +index 0d73d31..231b59c 100644 +--- a/drivers/spi/spi-img-spfi.c ++++ b/drivers/spi/spi-img-spfi.c +@@ -437,18 +437,23 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg) + struct img_spfi *spfi = spi_master_get_devdata(master); + u32 val; + ++ /* ++ * The chip select line is controlled externally so ++ * we can use the CS0 configuration for all devices ++ */ + val = spfi_readl(spfi, SPFI_PORT_STATE); ++ ++ /* 0 for device selection */ + val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << + SPFI_PORT_STATE_DEV_SEL_SHIFT); +- val |= msg->spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT; + if (msg->spi->mode & SPI_CPHA) +- val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select); ++ val |= SPFI_PORT_STATE_CK_PHASE(0); + else +- val &= ~SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select); ++ val &= ~SPFI_PORT_STATE_CK_PHASE(0); + if (msg->spi->mode & SPI_CPOL) +- val |= SPFI_PORT_STATE_CK_POL(msg->spi->chip_select); ++ val |= SPFI_PORT_STATE_CK_POL(0); + else +- val &= ~SPFI_PORT_STATE_CK_POL(msg->spi->chip_select); ++ val &= ~SPFI_PORT_STATE_CK_POL(0); + spfi_writel(spfi, val, SPFI_PORT_STATE); + + return 0; +@@ -548,11 +553,15 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi, + div = DIV_ROUND_UP(clk_get_rate(spfi->spfi_clk), xfer->speed_hz); + div = clamp(512 / (1 << get_count_order(div)), 1, 128); + +- val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(spi->chip_select)); ++ /* ++ * The chip select line is controlled externally so ++ * we can use the CS0 parameters for all devices ++ */ ++ val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(0)); + val &= ~(SPFI_DEVICE_PARAMETER_BITCLK_MASK << + SPFI_DEVICE_PARAMETER_BITCLK_SHIFT); + val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT; +- spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select)); ++ spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(0)); + + if (!list_is_last(&xfer->transfer_list, &master->cur_msg->transfers) && + /* +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/105-spi-img-spfi-RX-maximum-burst-size-for-DMA-is-8.patch b/target/linux/pistachio/patches-4.9/105-spi-img-spfi-RX-maximum-burst-size-for-DMA-is-8.patch new file mode 100644 index 0000000000..47fcf3c0ba --- /dev/null +++ b/target/linux/pistachio/patches-4.9/105-spi-img-spfi-RX-maximum-burst-size-for-DMA-is-8.patch @@ -0,0 +1,64 @@ +From 56466f505f58f44b69feb7eaed3b506842800456 Mon Sep 17 00:00:00 2001 +From: Ionela Voinescu <ionela.voinescu@imgtec.com> +Date: Tue, 1 Mar 2016 17:49:45 +0000 +Subject: spi: img-spfi: RX maximum burst size for DMA is 8 + +The depth of the FIFOs is 16 bytes. The DMA request line is tied +to the half full/empty (depending on the use of the TX or RX FIFO) +threshold. For the TX FIFO, if you set a burst size of 8 (equal to +half the depth) the first burst goes into FIFO without any issues, +but due the latency involved (the time the data leaves the DMA +engine to the time it arrives at the FIFO), the DMA might trigger +another burst of 8. But given that there is no space for 2 additonal +bursts of 8, this would result in a failure. Therefore, we have to +keep the burst size for TX to 4 to accomodate for an extra burst. + +For the read (RX) scenario, the DMA request line goes high when +there is at least 8 entries in the FIFO (half full), and we can +program the burst size to be 8 because the risk of accidental burst +does not exist. The DMA engine will not trigger another read until +the read data for all the burst it has sent out has been received. + +While here, move the burst size setting outside of the if/else branches +as they have the same value for both 8 and 32 bit data widths. + +Signed-off-by: Ionela Voinescu <ionela.voinescu@imgtec.com> +--- + drivers/spi/spi-img-spfi.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c +index 231b59c..8ad6c75 100644 +--- a/drivers/spi/spi-img-spfi.c ++++ b/drivers/spi/spi-img-spfi.c +@@ -346,12 +346,11 @@ static int img_spfi_start_dma(struct spi_master *master, + if (xfer->len % 4 == 0) { + rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA; + rxconf.src_addr_width = 4; +- rxconf.src_maxburst = 4; + } else { + rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA; + rxconf.src_addr_width = 1; +- rxconf.src_maxburst = 4; + } ++ rxconf.src_maxburst = 8; + dmaengine_slave_config(spfi->rx_ch, &rxconf); + + rxdesc = dmaengine_prep_slave_sg(spfi->rx_ch, xfer->rx_sg.sgl, +@@ -370,12 +369,11 @@ static int img_spfi_start_dma(struct spi_master *master, + if (xfer->len % 4 == 0) { + txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA; + txconf.dst_addr_width = 4; +- txconf.dst_maxburst = 4; + } else { + txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA; + txconf.dst_addr_width = 1; +- txconf.dst_maxburst = 4; + } ++ txconf.dst_maxburst = 4; + dmaengine_slave_config(spfi->tx_ch, &txconf); + + txdesc = dmaengine_prep_slave_sg(spfi->tx_ch, xfer->tx_sg.sgl, +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/106-spi-img-spfi-finish-every-transfer-cleanly.patch b/target/linux/pistachio/patches-4.9/106-spi-img-spfi-finish-every-transfer-cleanly.patch new file mode 100644 index 0000000000..f75f0fbc57 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/106-spi-img-spfi-finish-every-transfer-cleanly.patch @@ -0,0 +1,125 @@ +From 5fcca3fd4b621d7b5bdeca18d36dfc6ca6cfe383 Mon Sep 17 00:00:00 2001 +From: Ionela Voinescu <ionela.voinescu@imgtec.com> +Date: Wed, 10 Aug 2016 11:42:26 +0100 +Subject: spi: img-spfi: finish every transfer cleanly + +Before this change, the interrupt status bit that signaled +the end of a tranfers was cleared in the wait_all_done +function. That functionality triggered issues for DMA +duplex transactions where the wait function was called +twice, in both the TX and RX callbacks. + +In order to fix the issue, clear all interrupt data bits +at the end of a PIO transfer or at the end of both TX and RX +duplex transfers, if the transfer is not a pending tranfer +(command waiting for data). After that, the status register +is checked for new incoming data or new data requests to be +signaled. If SPFI finished cleanly, no new interrupt data +bits should be set. + +Signed-off-by: Ionela Voinescu <ionela.voinescu@imgtec.com> +--- + drivers/spi/spi-img-spfi.c | 49 +++++++++++++++++++++++++++++++++------------- + 1 file changed, 35 insertions(+), 14 deletions(-) + +diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c +index 8ad6c75..a124423 100644 +--- a/drivers/spi/spi-img-spfi.c ++++ b/drivers/spi/spi-img-spfi.c +@@ -83,6 +83,14 @@ + #define SPFI_INTERRUPT_SDE BIT(1) + #define SPFI_INTERRUPT_SDTRIG BIT(0) + ++#define SPFI_INTERRUPT_DATA_BITS (SPFI_INTERRUPT_SDHF |\ ++ SPFI_INTERRUPT_SDFUL |\ ++ SPFI_INTERRUPT_GDEX32BIT |\ ++ SPFI_INTERRUPT_GDHF |\ ++ SPFI_INTERRUPT_GDFUL |\ ++ SPFI_INTERRUPT_ALLDONETRIG |\ ++ SPFI_INTERRUPT_GDEX8BIT) ++ + /* + * There are four parallel FIFOs of 16 bytes each. The word buffer + * (*_32BIT_VALID_DATA) accesses all four FIFOs at once, resulting in an +@@ -144,6 +152,23 @@ static inline void spfi_reset(struct img_spfi *spfi) + spfi_writel(spfi, 0, SPFI_CONTROL); + } + ++static inline void spfi_finish(struct img_spfi *spfi) ++{ ++ if (!(spfi->complete)) ++ return; ++ ++ /* Clear data bits as all transfers(TX and RX) have finished */ ++ spfi_writel(spfi, SPFI_INTERRUPT_DATA_BITS, SPFI_INTERRUPT_CLEAR); ++ if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & SPFI_INTERRUPT_DATA_BITS) { ++ dev_err(spfi->dev, "SPFI did not finish transfer cleanly.\n"); ++ spfi_reset(spfi); ++ } ++ /* Disable SPFI for it not to interfere with pending transactions */ ++ spfi_writel(spfi, ++ spfi_readl(spfi, SPFI_CONTROL) & ~SPFI_CONTROL_SPFI_EN, ++ SPFI_CONTROL); ++} ++ + static int spfi_wait_all_done(struct img_spfi *spfi) + { + unsigned long timeout = jiffies + msecs_to_jiffies(50); +@@ -152,19 +177,9 @@ static int spfi_wait_all_done(struct img_spfi *spfi) + return 0; + + while (time_before(jiffies, timeout)) { +- u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); +- +- if (status & SPFI_INTERRUPT_ALLDONETRIG) { +- spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG, +- SPFI_INTERRUPT_CLEAR); +- /* +- * Disable SPFI for it not to interfere with +- * pending transactions +- */ +- spfi_writel(spfi, spfi_readl(spfi, SPFI_CONTROL) +- & ~SPFI_CONTROL_SPFI_EN, SPFI_CONTROL); ++ if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & ++ SPFI_INTERRUPT_ALLDONETRIG) + return 0; +- } + cpu_relax(); + } + +@@ -296,6 +311,8 @@ static int img_spfi_start_pio(struct spi_master *master, + } + + ret = spfi_wait_all_done(spfi); ++ spfi_finish(spfi); ++ + if (ret < 0) + return ret; + +@@ -311,8 +328,10 @@ static void img_spfi_dma_rx_cb(void *data) + + spin_lock_irqsave(&spfi->lock, flags); + spfi->rx_dma_busy = false; +- if (!spfi->tx_dma_busy) ++ if (!spfi->tx_dma_busy) { ++ spfi_finish(spfi); + spi_finalize_current_transfer(spfi->master); ++ } + spin_unlock_irqrestore(&spfi->lock, flags); + } + +@@ -325,8 +344,10 @@ static void img_spfi_dma_tx_cb(void *data) + + spin_lock_irqsave(&spfi->lock, flags); + spfi->tx_dma_busy = false; +- if (!spfi->rx_dma_busy) ++ if (!spfi->rx_dma_busy) { ++ spfi_finish(spfi); + spi_finalize_current_transfer(spfi->master); ++ } + spin_unlock_irqrestore(&spfi->lock, flags); + } + +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/107-clockevents-Retry-programming-min-delta-up-to-10-tim.patch b/target/linux/pistachio/patches-4.9/107-clockevents-Retry-programming-min-delta-up-to-10-tim.patch new file mode 100644 index 0000000000..613584e33c --- /dev/null +++ b/target/linux/pistachio/patches-4.9/107-clockevents-Retry-programming-min-delta-up-to-10-tim.patch @@ -0,0 +1,71 @@ +From b46f8c74afdd30cd52bfdcc2231470a0bab04416 Mon Sep 17 00:00:00 2001 +From: James Hogan <james.hogan@imgtec.com> +Date: Fri, 22 Apr 2016 18:22:45 +0100 +Subject: clockevents: Retry programming min delta up to 10 times + +Under virtualisation it is possible to get unexpected latency during a +clockevent device's set_next_event() callback which can make it return +-ETIME even for a delta based on min_delta_ns. + +The clockevents_program_min_delta() implementation for +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=n doesn't handle retries when this +happens, nor does clockevents_program_event() or its callers when force +is true (for example hrtimer_reprogram()). This can result in hangs +until the clock event device does a full period. + +It isn't appropriate to use MIN_ADJUST in this case as occasional +hypervisor induced high latency will cause min_delta_ns to quickly +increase to the maximum. +Instead, borrow the retry pattern from the MIN_ADJUST case, but without +making adjustments. We retry up to 10 times before giving up. + +(picked https://patchwork.kernel.org/patch/8909491/) + +Signed-off-by: James Hogan <james.hogan@imgtec.com> +--- + kernel/time/clockevents.c | 26 +++++++++++++++++++------- + 1 file changed, 19 insertions(+), 7 deletions(-) + +diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c +index 2c5bc77..ddd7e82 100644 +--- a/kernel/time/clockevents.c ++++ b/kernel/time/clockevents.c +@@ -281,16 +281,28 @@ static int clockevents_program_min_delta(struct clock_event_device *dev) + { + unsigned long long clc; + int64_t delta; ++ int i; + +- delta = dev->min_delta_ns; +- dev->next_event = ktime_add_ns(ktime_get(), delta); ++ for (i = 0;;) { ++ delta = dev->min_delta_ns; ++ dev->next_event = ktime_add_ns(ktime_get(), delta); + +- if (clockevent_state_shutdown(dev)) +- return 0; ++ if (clockevent_state_shutdown(dev)) ++ return 0; + +- dev->retries++; +- clc = ((unsigned long long) delta * dev->mult) >> dev->shift; +- return dev->set_next_event((unsigned long) clc, dev); ++ dev->retries++; ++ clc = ((unsigned long long) delta * dev->mult) >> dev->shift; ++ if (dev->set_next_event((unsigned long) clc, dev) == 0) ++ return 0; ++ ++ if (++i > 9) { ++ /* ++ * We tried 10 times to program the device with the ++ * given min_delta_ns. Get out of here. ++ */ ++ return -ETIME; ++ } ++ } + } + + #endif /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */ +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/108-clk-pistachio-Fix-wrong-SDHost-card-speed.patch b/target/linux/pistachio/patches-4.9/108-clk-pistachio-Fix-wrong-SDHost-card-speed.patch new file mode 100644 index 0000000000..da2a873e61 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/108-clk-pistachio-Fix-wrong-SDHost-card-speed.patch @@ -0,0 +1,56 @@ +From 3642843a06025ec333d7e92580cf52cb8db2a652 Mon Sep 17 00:00:00 2001 +From: Govindraj Raja <Govindraj.Raja@imgtec.com> +Date: Fri, 8 Jan 2016 16:36:07 +0000 +Subject: clk: pistachio: Fix wrong SDHost card speed + +The SDHost currently clocks the card 4x slower than it +should do, because there is fixed divide by 4 in the +sdhost wrapper that is not present in the clock tree. +To model this add a fixed divide by 4 clock node in +the SDHost clock path. + +This will ensure the right clock frequency is selected when +the mmc driver tries to configure frequency on card insert. + +Signed-off-by: Govindraj Raja <Govindraj.Raja@imgtec.com> +--- + drivers/clk/pistachio/clk-pistachio.c | 3 ++- + include/dt-bindings/clock/pistachio-clk.h | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c +index c4ceb5e..1c968d9 100644 +--- a/drivers/clk/pistachio/clk-pistachio.c ++++ b/drivers/clk/pistachio/clk-pistachio.c +@@ -44,7 +44,7 @@ static struct pistachio_gate pistachio_gates[] __initdata = { + GATE(CLK_AUX_ADC_INTERNAL, "aux_adc_internal", "sys_internal_div", + 0x104, 22), + GATE(CLK_AUX_ADC, "aux_adc", "aux_adc_div", 0x104, 23), +- GATE(CLK_SD_HOST, "sd_host", "sd_host_div", 0x104, 24), ++ GATE(CLK_SD_HOST, "sd_host", "sd_host_div4", 0x104, 24), + GATE(CLK_BT, "bt", "bt_div", 0x104, 25), + GATE(CLK_BT_DIV4, "bt_div4", "bt_div4_div", 0x104, 26), + GATE(CLK_BT_DIV8, "bt_div8", "bt_div8_div", 0x104, 27), +@@ -54,6 +54,7 @@ static struct pistachio_gate pistachio_gates[] __initdata = { + static struct pistachio_fixed_factor pistachio_ffs[] __initdata = { + FIXED_FACTOR(CLK_WIFI_DIV4, "wifi_div4", "wifi_pll", 4), + FIXED_FACTOR(CLK_WIFI_DIV8, "wifi_div8", "wifi_pll", 8), ++ FIXED_FACTOR(CLK_SDHOST_DIV4, "sd_host_div4", "sd_host_div", 4), + }; + + static struct pistachio_div pistachio_divs[] __initdata = { +diff --git a/include/dt-bindings/clock/pistachio-clk.h b/include/dt-bindings/clock/pistachio-clk.h +index 039f83f..77b92ae 100644 +--- a/include/dt-bindings/clock/pistachio-clk.h ++++ b/include/dt-bindings/clock/pistachio-clk.h +@@ -21,6 +21,7 @@ + /* Fixed-factor clocks */ + #define CLK_WIFI_DIV4 16 + #define CLK_WIFI_DIV8 17 ++#define CLK_SDHOST_DIV4 18 + + /* Gate clocks */ + #define CLK_MIPS 32 +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/109-MIPS-DTS-img-marduk-switch-mmc-to-1-bit-mode.patch b/target/linux/pistachio/patches-4.9/109-MIPS-DTS-img-marduk-switch-mmc-to-1-bit-mode.patch new file mode 100644 index 0000000000..141e401fcb --- /dev/null +++ b/target/linux/pistachio/patches-4.9/109-MIPS-DTS-img-marduk-switch-mmc-to-1-bit-mode.patch @@ -0,0 +1,52 @@ +From 981c1d416af45eff207227aec106381ac23aac99 Mon Sep 17 00:00:00 2001 +From: Ian Pozella <Ian.Pozella@imgtec.com> +Date: Mon, 20 Feb 2017 10:00:52 +0000 +Subject: MIPS: DTS: img: marduk: switch mmc to 1 bit mode + +The mmc block in Pistachio allows 1 to 8 data bits to be used. +Marduk uses 4 bits allowing the upper 4 bits to be allocated +to the Mikrobus ports. However these bits are still connected +internally meaning the mmc block recieves signals on all data lines +and seems the internal HW CRC checks get corrupted by this erroneous +data. + +We cannot control what data is sent on these lines because they go +to external ports. 1 bit mode does not exhibit the issue hence the +safe default is to use this. If a user knows that in their use case +they will not use the upper bits then they can set to 4 bit mode in +order to improve performance. + +Also make sure that the upper 4 bits don't get allocated to the mmc +driver (the default is to assign all 8 pins) so they can be allocated +to other drivers. Allocating all 4 despite setting 1 bit mode as this +matches what is there in hardware. + +Signed-off-by: Ian Pozella <Ian.Pozella@imgtec.com> +--- + arch/mips/boot/dts/img/pistachio_marduk.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/mips/boot/dts/img/pistachio_marduk.dts b/arch/mips/boot/dts/img/pistachio_marduk.dts +index cf9cebd..7708815 100644 +--- a/arch/mips/boot/dts/img/pistachio_marduk.dts ++++ b/arch/mips/boot/dts/img/pistachio_marduk.dts +@@ -120,7 +120,7 @@ + + &sdhost { + status = "okay"; +- bus-width = <4>; ++ bus-width = <1>; + disable-wp; + }; + +@@ -130,6 +130,7 @@ + + &pin_sdhost_data { + drive-strength = <2>; ++ pins = "mfio17", "mfio18", "mfio19", "mfio20"; + }; + + &pwm { +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/401-mtd-nor-support-mtd-name-from-device-tree.patch b/target/linux/pistachio/patches-4.9/401-mtd-nor-support-mtd-name-from-device-tree.patch new file mode 100644 index 0000000000..0ae92f3c86 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/401-mtd-nor-support-mtd-name-from-device-tree.patch @@ -0,0 +1,39 @@ +From f32bc2aa01edcba2f2ed5db151cf183eac9ef919 Mon Sep 17 00:00:00 2001 +From: Abhimanyu Vishwakarma <Abhimanyu.Vishwakarma@imgtec.com> +Date: Sat, 25 Feb 2017 16:42:50 +0000 +Subject: mtd: nor: support mtd name from device tree + +Signed-off-by: Abhimanyu Vishwakarma <Abhimanyu.Vishwakarma@imgtec.com> +--- + drivers/mtd/spi-nor/spi-nor.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c +index d0fc165..fcee697 100644 +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -1306,6 +1306,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) + struct device *dev = nor->dev; + struct mtd_info *mtd = &nor->mtd; + struct device_node *np = spi_nor_get_flash_node(nor); ++ const char __maybe_unused *of_mtd_name = NULL; + int ret; + int i; + +@@ -1361,7 +1362,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) + spi_nor_wait_till_ready(nor); + } + +- if (!mtd->name) ++#ifdef CONFIG_MTD_OF_PARTS ++ of_property_read_string(np, "linux,mtd-name", &of_mtd_name); ++#endif ++ if (of_mtd_name) ++ mtd->name = of_mtd_name; ++ else if (!mtd->name) + mtd->name = dev_name(dev); + mtd->priv = nor; + mtd->type = MTD_NORFLASH; +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/411-mtd-nand-Check-length-of-ID-before-reading-bits-per-.patch b/target/linux/pistachio/patches-4.9/411-mtd-nand-Check-length-of-ID-before-reading-bits-per-.patch new file mode 100644 index 0000000000..cd2f8bb123 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/411-mtd-nand-Check-length-of-ID-before-reading-bits-per-.patch @@ -0,0 +1,38 @@ +From 42ebff638003be18fab503b37de4ad7853244e95 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@imgtec.com> +Date: Sat, 25 Feb 2017 15:58:22 +0000 +Subject: mtd: nand: Check length of ID before reading bits per cell + +The table-based NAND identification currently reads the number +of bits per cell from the 3rd byte of the extended ID. This is done +for the so-called 'full ID' devices; i.e. devices that have a known +length ID. + +However, if the ID length is shorter than three, there's no 3rd byte, +and so it's wrong to read the bits per cell from there. Fix this by +adding a check for the ID length. + +(picked from http://lists.infradead.org/pipermail/linux-mtd/2014-December/056764.html) + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@imgtec.com> +--- + drivers/mtd/nand/nand_base.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c +index 3bde96a..69b5cac 100644 +--- a/drivers/mtd/nand/nand_base.c ++++ b/drivers/mtd/nand/nand_base.c +@@ -3964,7 +3964,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, + mtd->erasesize = type->erasesize; + mtd->oobsize = type->oobsize; + +- chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); ++ if (type->id_len > 2) ++ chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); + chip->chipsize = (uint64_t)type->chipsize << 20; + chip->options |= type->options; + chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/412-mtd-nand-Add-JEDEC-manufacturer-ID-for-Gigadevice.patch b/target/linux/pistachio/patches-4.9/412-mtd-nand-Add-JEDEC-manufacturer-ID-for-Gigadevice.patch new file mode 100644 index 0000000000..f8ebac5a1d --- /dev/null +++ b/target/linux/pistachio/patches-4.9/412-mtd-nand-Add-JEDEC-manufacturer-ID-for-Gigadevice.patch @@ -0,0 +1,42 @@ +From a4bc33b205fd9b1db862f1e45173dba57b0fa57f Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@imgtec.com> +Date: Sat, 25 Feb 2017 15:43:09 +0000 +Subject: mtd: nand: Add JEDEC manufacturer ID for Gigadevice + +This commit adds Gigadevice to the list of manufacturer ID and name strings. + +(picked from http://lists.infradead.org/pipermail/linux-mtd/2014-December/056765.html) + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@imgtec.com> +--- + drivers/mtd/nand/nand_ids.c | 1 + + include/linux/mtd/nand.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c +index 2af9869..dc80fcd 100644 +--- a/drivers/mtd/nand/nand_ids.c ++++ b/drivers/mtd/nand/nand_ids.c +@@ -182,6 +182,7 @@ struct nand_manufacturers nand_manuf_ids[] = { + {NAND_MFR_SANDISK, "SanDisk"}, + {NAND_MFR_INTEL, "Intel"}, + {NAND_MFR_ATO, "ATO"}, ++ {NAND_MFR_GIGADEVICE, "Gigadevice"}, + {0x0, "Unknown"} + }; + +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index d8905a2..3a00df7 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -928,6 +928,7 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) + #define NAND_MFR_SANDISK 0x45 + #define NAND_MFR_INTEL 0x89 + #define NAND_MFR_ATO 0x9b ++#define NAND_MFR_GIGADEVICE 0xc8 + + /* The maximum expected count of bytes in the NAND ID sequence */ + #define NAND_MAX_ID_LEN 8 +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/413-mtd-Introduce-SPI-NAND-framework.patch b/target/linux/pistachio/patches-4.9/413-mtd-Introduce-SPI-NAND-framework.patch new file mode 100644 index 0000000000..d8b268164e --- /dev/null +++ b/target/linux/pistachio/patches-4.9/413-mtd-Introduce-SPI-NAND-framework.patch @@ -0,0 +1,725 @@ +From 082a89a78e29b15008284df90441747cb742f149 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@imgtec.com> +Date: Tue, 2 Dec 2014 09:58:52 -0300 +Subject: mtd: Introduce SPI NAND framework + +Add a new framework, to support SPI NAND devices. The framework registers +a NAND chip and handles the generic SPI NAND protocol, calling device-specific +hooks for each SPI NAND command. + +The following is the stack design, from userspace to hardware. This commit +adds the "SPI NAND core" layer. + + Userspace + ------------------ + MTD + ------------------ + NAND core + ------------------ + SPI NAND core + ------------------ + SPI NAND device + ------------------ + SPI core + ------------------ + SPI master + ------------------ + Hardware + +(based on http://lists.infradead.org/pipermail/linux-mtd/2014-December/056763.html) + +Signed-off-by: Ionela Voinescu <ionela.voinescu@imgtec.com> +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@imgtec.com> +Signed-off-by: Ian Pozella <Ian.Pozella@imgtec.com> +--- + drivers/mtd/Kconfig | 2 + + drivers/mtd/Makefile | 1 + + drivers/mtd/spi-nand/Kconfig | 7 + + drivers/mtd/spi-nand/Makefile | 1 + + drivers/mtd/spi-nand/spi-nand-base.c | 566 +++++++++++++++++++++++++++++++++++ + include/linux/mtd/spi-nand.h | 54 ++++ + 6 files changed, 631 insertions(+) + create mode 100644 drivers/mtd/spi-nand/Kconfig + create mode 100644 drivers/mtd/spi-nand/Makefile + create mode 100644 drivers/mtd/spi-nand/spi-nand-base.c + create mode 100644 include/linux/mtd/spi-nand.h + +diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig +index e83a279..9163d7f 100644 +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -334,6 +334,8 @@ source "drivers/mtd/onenand/Kconfig" + + source "drivers/mtd/lpddr/Kconfig" + ++source "drivers/mtd/spi-nand/Kconfig" ++ + source "drivers/mtd/spi-nor/Kconfig" + + source "drivers/mtd/ubi/Kconfig" +diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile +index 99bb9a1..38a4756 100644 +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -32,5 +32,6 @@ inftl-objs := inftlcore.o inftlmount.o + + obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/ + ++obj-$(CONFIG_MTD_SPI_NAND) += spi-nand/ + obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ + obj-$(CONFIG_MTD_UBI) += ubi/ +diff --git a/drivers/mtd/spi-nand/Kconfig b/drivers/mtd/spi-nand/Kconfig +new file mode 100644 +index 0000000..17b31e1 +--- /dev/null ++++ b/drivers/mtd/spi-nand/Kconfig +@@ -0,0 +1,7 @@ ++menuconfig MTD_SPI_NAND ++ tristate "SPI NAND device support" ++ depends on MTD ++ select MTD_NAND ++ help ++ This is the framework for the SPI NAND. ++ +diff --git a/drivers/mtd/spi-nand/Makefile b/drivers/mtd/spi-nand/Makefile +new file mode 100644 +index 0000000..d454c52 +--- /dev/null ++++ b/drivers/mtd/spi-nand/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_MTD_SPI_NAND) += spi-nand-base.o +diff --git a/drivers/mtd/spi-nand/spi-nand-base.c b/drivers/mtd/spi-nand/spi-nand-base.c +new file mode 100644 +index 0000000..5d79f85 +--- /dev/null ++++ b/drivers/mtd/spi-nand/spi-nand-base.c +@@ -0,0 +1,566 @@ ++/* ++ * Copyright (C) 2014 Imagination Technologies Ltd. ++ * ++ * 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 of the License. ++ * ++ * Notes: ++ * 1. Erase and program operations need to call write_enable() first, ++ * to clear the enable bit. This bit is cleared automatically after ++ * the erase or program operation. ++ * ++ */ ++ ++#include <linux/device.h> ++#include <linux/err.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/mtd/nand.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/mtd/spi-nand.h> ++#include <linux/of.h> ++#include <linux/slab.h> ++ ++/* Registers common to all devices */ ++#define SPI_NAND_LOCK_REG 0xa0 ++#define SPI_NAND_PROT_UNLOCK_ALL 0x0 ++ ++#define SPI_NAND_FEATURE_REG 0xb0 ++#define SPI_NAND_ECC_EN BIT(4) ++#define SPI_NAND_QUAD_EN BIT(0) ++ ++#define SPI_NAND_STATUS_REG 0xc0 ++#define SPI_NAND_STATUS_REG_ECC_MASK 0x3 ++#define SPI_NAND_STATUS_REG_ECC_SHIFT 4 ++#define SPI_NAND_STATUS_REG_PROG_FAIL BIT(3) ++#define SPI_NAND_STATUS_REG_ERASE_FAIL BIT(2) ++#define SPI_NAND_STATUS_REG_WREN BIT(1) ++#define SPI_NAND_STATUS_REG_BUSY BIT(0) ++ ++#define SPI_NAND_CMD_BUF_LEN 8 ++ ++/* Rewind and fill the buffer with 0xff */ ++static void spi_nand_clear_buffer(struct spi_nand *snand) ++{ ++ snand->buf_start = 0; ++ memset(snand->data_buf, 0xff, snand->buf_size); ++} ++ ++static int spi_nand_enable_ecc(struct spi_nand *snand) ++{ ++ int ret; ++ ++ ret = snand->read_reg(snand, SPI_NAND_FEATURE_REG, snand->buf); ++ if (ret) ++ return ret; ++ ++ snand->buf[0] |= SPI_NAND_ECC_EN; ++ ret = snand->write_reg(snand, SPI_NAND_FEATURE_REG, snand->buf); ++ if (ret) ++ return ret; ++ snand->ecc = true; ++ ++ return 0; ++} ++ ++static int spi_nand_disable_ecc(struct spi_nand *snand) ++{ ++ int ret; ++ ++ ret = snand->read_reg(snand, SPI_NAND_FEATURE_REG, snand->buf); ++ if (ret) ++ return ret; ++ ++ snand->buf[0] &= ~SPI_NAND_ECC_EN; ++ ret = snand->write_reg(snand, SPI_NAND_FEATURE_REG, snand->buf); ++ if (ret) ++ return ret; ++ snand->ecc = false; ++ ++ return 0; ++} ++ ++static int spi_nand_enable_quad(struct spi_nand *snand) ++{ ++ int ret; ++ ++ ret = snand->read_reg(snand, SPI_NAND_FEATURE_REG, snand->buf); ++ if (ret) ++ return ret; ++ ++ snand->buf[0] |= SPI_NAND_QUAD_EN; ++ ret = snand->write_reg(snand, SPI_NAND_FEATURE_REG, snand->buf); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++/* ++ * Wait until the status register busy bit is cleared. ++ * Returns a negatie errno on error or time out, and a non-negative status ++ * value if the device is ready. ++ */ ++static int spi_nand_wait_till_ready(struct spi_nand *snand) ++{ ++ unsigned long deadline = jiffies + msecs_to_jiffies(100); ++ bool timeout = false; ++ int ret; ++ ++ /* ++ * Perhaps we should set a different timeout for each ++ * operation (reset, read, write, erase). ++ */ ++ while (!timeout) { ++ if (time_after_eq(jiffies, deadline)) ++ timeout = true; ++ ++ ret = snand->read_reg(snand, SPI_NAND_STATUS_REG, snand->buf); ++ if (ret < 0) { ++ dev_err(snand->dev, "error reading status register\n"); ++ return ret; ++ } else if (!(snand->buf[0] & SPI_NAND_STATUS_REG_BUSY)) { ++ return snand->buf[0]; ++ } ++ ++ cond_resched(); ++ } ++ ++ dev_err(snand->dev, "operation timed out\n"); ++ ++ return -ETIMEDOUT; ++} ++ ++static int spi_nand_reset(struct spi_nand *snand) ++{ ++ int ret; ++ ++ ret = snand->reset(snand); ++ if (ret < 0) { ++ dev_err(snand->dev, "reset command failed\n"); ++ return ret; ++ } ++ ++ /* ++ * The NAND core won't wait after a device reset, so we need ++ * to do that here. ++ */ ++ ret = spi_nand_wait_till_ready(snand); ++ if (ret < 0) ++ return ret; ++ return 0; ++} ++ ++static int spi_nand_status(struct spi_nand *snand) ++{ ++ int ret, status; ++ ++ ret = snand->read_reg(snand, SPI_NAND_STATUS_REG, snand->buf); ++ if (ret < 0) { ++ dev_err(snand->dev, "error reading status register\n"); ++ return ret; ++ } ++ status = snand->buf[0]; ++ ++ /* Convert this into standard NAND_STATUS values */ ++ if (status & SPI_NAND_STATUS_REG_BUSY) ++ snand->buf[0] = 0; ++ else ++ snand->buf[0] = NAND_STATUS_READY; ++ ++ if (status & SPI_NAND_STATUS_REG_PROG_FAIL || ++ status & SPI_NAND_STATUS_REG_ERASE_FAIL) ++ snand->buf[0] |= NAND_STATUS_FAIL; ++ ++ /* ++ * Since we unlock the entire device at initialization, unconditionally ++ * set the WP bit to indicate it's not protected. ++ */ ++ snand->buf[0] |= NAND_STATUS_WP; ++ return 0; ++} ++ ++static int spi_nand_erase(struct spi_nand *snand, int page_addr) ++{ ++ int ret; ++ ++ ret = snand->write_enable(snand); ++ if (ret < 0) { ++ dev_err(snand->dev, "write enable command failed\n"); ++ return ret; ++ } ++ ++ ret = snand->block_erase(snand, page_addr); ++ if (ret < 0) { ++ dev_err(snand->dev, "block erase command failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int spi_nand_write(struct spi_nand *snand) ++{ ++ int ret; ++ ++ /* Enable quad mode */ ++ ret = spi_nand_enable_quad(snand); ++ if (ret) { ++ dev_err(snand->dev, "error %d enabling quad mode\n", ret); ++ return ret; ++ } ++ /* Store the page to cache */ ++ ret = snand->store_cache(snand, 0, snand->buf_size, snand->data_buf); ++ if (ret < 0) { ++ dev_err(snand->dev, "error %d storing page 0x%x to cache\n", ++ ret, snand->page_addr); ++ return ret; ++ } ++ ++ ret = snand->write_enable(snand); ++ if (ret < 0) { ++ dev_err(snand->dev, "write enable command failed\n"); ++ return ret; ++ } ++ ++ /* Get page from the device cache into our internal buffer */ ++ ret = snand->write_page(snand, snand->page_addr); ++ if (ret < 0) { ++ dev_err(snand->dev, "error %d reading page 0x%x from cache\n", ++ ret, snand->page_addr); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int spi_nand_read_id(struct spi_nand *snand) ++{ ++ int ret; ++ ++ ret = snand->read_id(snand, snand->data_buf); ++ if (ret < 0) { ++ dev_err(snand->dev, "error %d reading ID\n", ret); ++ return ret; ++ } ++ return 0; ++} ++ ++static int spi_nand_read_page(struct spi_nand *snand, unsigned int page_addr, ++ unsigned int page_offset, size_t length) ++{ ++ unsigned int corrected = 0, ecc_error = 0; ++ int ret; ++ ++ /* Load a page into the cache register */ ++ ret = snand->load_page(snand, page_addr); ++ if (ret < 0) { ++ dev_err(snand->dev, "error %d loading page 0x%x to cache\n", ++ ret, page_addr); ++ return ret; ++ } ++ ++ ret = spi_nand_wait_till_ready(snand); ++ if (ret < 0) ++ return ret; ++ ++ if (snand->ecc) { ++ snand->get_ecc_status(ret, &corrected, &ecc_error); ++ snand->bitflips = corrected; ++ ++ /* ++ * If there's an ECC error, print a message and notify MTD ++ * about it. Then complete the read, to load actual data on ++ * the buffer (instead of the status result). ++ */ ++ if (ecc_error) { ++ dev_err(snand->dev, ++ "internal ECC error reading page 0x%x\n", ++ page_addr); ++ snand->nand_chip.mtd.ecc_stats.failed++; ++ } else { ++ snand->nand_chip.mtd.ecc_stats.corrected += corrected; ++ } ++ } ++ ++ /* Enable quad mode */ ++ ret = spi_nand_enable_quad(snand); ++ if (ret) { ++ dev_err(snand->dev, "error %d enabling quad mode\n", ret); ++ return ret; ++ } ++ /* Get page from the device cache into our internal buffer */ ++ ret = snand->read_cache(snand, page_offset, length, snand->data_buf); ++ if (ret < 0) { ++ dev_err(snand->dev, "error %d reading page 0x%x from cache\n", ++ ret, page_addr); ++ return ret; ++ } ++ return 0; ++} ++ ++static u8 spi_nand_read_byte(struct mtd_info *mtd) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct spi_nand *snand = nand_get_controller_data(chip); ++ char val = 0xff; ++ ++ if (snand->buf_start < snand->buf_size) ++ val = snand->data_buf[snand->buf_start++]; ++ return val; ++} ++ ++static void spi_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct spi_nand *snand = nand_get_controller_data(chip); ++ size_t n = min_t(size_t, len, snand->buf_size - snand->buf_start); ++ ++ memcpy(snand->data_buf + snand->buf_start, buf, n); ++ snand->buf_start += n; ++} ++ ++static void spi_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct spi_nand *snand = nand_get_controller_data(chip); ++ size_t n = min_t(size_t, len, snand->buf_size - snand->buf_start); ++ ++ memcpy(buf, snand->data_buf + snand->buf_start, n); ++ snand->buf_start += n; ++} ++ ++static int spi_nand_write_page_hwecc(struct mtd_info *mtd, ++ struct nand_chip *chip, const uint8_t *buf, int oob_required, ++ int page) ++{ ++ chip->write_buf(mtd, buf, mtd->writesize); ++ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); ++ ++ return 0; ++} ++ ++static int spi_nand_read_page_hwecc(struct mtd_info *mtd, ++ struct nand_chip *chip, uint8_t *buf, int oob_required, ++ int page) ++{ ++ struct spi_nand *snand = nand_get_controller_data(chip); ++ ++ chip->read_buf(mtd, buf, mtd->writesize); ++ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); ++ ++ return snand->bitflips; ++} ++ ++static int spi_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) ++{ ++ struct spi_nand *snand = nand_get_controller_data(chip); ++ int ret; ++ ++ ret = spi_nand_wait_till_ready(snand); ++ ++ if (ret < 0) { ++ return NAND_STATUS_FAIL; ++ } else if (ret & SPI_NAND_STATUS_REG_PROG_FAIL) { ++ dev_err(snand->dev, "page program failed\n"); ++ return NAND_STATUS_FAIL; ++ } else if (ret & SPI_NAND_STATUS_REG_ERASE_FAIL) { ++ dev_err(snand->dev, "block erase failed\n"); ++ return NAND_STATUS_FAIL; ++ } ++ ++ return NAND_STATUS_READY; ++} ++ ++static void spi_nand_cmdfunc(struct mtd_info *mtd, unsigned int command, ++ int column, int page_addr) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct spi_nand *snand = nand_get_controller_data(chip); ++ ++ /* ++ * In case there's any unsupported command, let's make sure ++ * we don't keep garbage around in the buffer. ++ */ ++ if (command != NAND_CMD_PAGEPROG) { ++ spi_nand_clear_buffer(snand); ++ snand->page_addr = 0; ++ } ++ ++ switch (command) { ++ case NAND_CMD_READ0: ++ spi_nand_read_page(snand, page_addr, 0, mtd->writesize); ++ break; ++ case NAND_CMD_READOOB: ++ spi_nand_disable_ecc(snand); ++ spi_nand_read_page(snand, page_addr, mtd->writesize, ++ mtd->oobsize); ++ spi_nand_enable_ecc(snand); ++ break; ++ case NAND_CMD_READID: ++ spi_nand_read_id(snand); ++ break; ++ case NAND_CMD_ERASE1: ++ spi_nand_erase(snand, page_addr); ++ break; ++ case NAND_CMD_ERASE2: ++ /* There's nothing to do here, as the erase is one-step */ ++ break; ++ case NAND_CMD_SEQIN: ++ snand->buf_start = column; ++ snand->page_addr = page_addr; ++ break; ++ case NAND_CMD_PAGEPROG: ++ spi_nand_write(snand); ++ break; ++ case NAND_CMD_STATUS: ++ spi_nand_status(snand); ++ break; ++ case NAND_CMD_RESET: ++ spi_nand_reset(snand); ++ break; ++ default: ++ dev_err(&mtd->dev, "unknown command 0x%x\n", command); ++ } ++} ++ ++static void spi_nand_select_chip(struct mtd_info *mtd, int chip) ++{ ++ /* We need this to override the default */ ++} ++ ++int spi_nand_check(struct spi_nand *snand) ++{ ++ if (!snand->dev) ++ return -ENODEV; ++ if (!snand->read_cache) ++ return -ENODEV; ++ if (!snand->load_page) ++ return -ENODEV; ++ if (!snand->store_cache) ++ return -ENODEV; ++ if (!snand->write_page) ++ return -ENODEV; ++ if (!snand->write_reg) ++ return -ENODEV; ++ if (!snand->read_reg) ++ return -ENODEV; ++ if (!snand->block_erase) ++ return -ENODEV; ++ if (!snand->reset) ++ return -ENODEV; ++ if (!snand->write_enable) ++ return -ENODEV; ++ if (!snand->write_disable) ++ return -ENODEV; ++ if (!snand->get_ecc_status) ++ return -ENODEV; ++ return 0; ++} ++ ++int spi_nand_register(struct spi_nand *snand, struct nand_flash_dev *flash_ids) ++{ ++ struct nand_chip *chip = &snand->nand_chip; ++ struct mtd_info *mtd = nand_to_mtd(chip); ++ struct device_node *np = snand->dev->of_node; ++ const char __maybe_unused *of_mtd_name = NULL; ++ int ret; ++ ++ /* Let's check all the hooks are in-place so we don't panic later */ ++ ret = spi_nand_check(snand); ++ if (ret) ++ return ret; ++ ++ nand_set_controller_data(chip, snand); ++ nand_set_flash_node(chip, np); ++ chip->read_buf = spi_nand_read_buf; ++ chip->write_buf = spi_nand_write_buf; ++ chip->read_byte = spi_nand_read_byte; ++ chip->cmdfunc = spi_nand_cmdfunc; ++ chip->waitfunc = spi_nand_waitfunc; ++ chip->select_chip = spi_nand_select_chip; ++ chip->options |= NAND_NO_SUBPAGE_WRITE; ++ chip->bits_per_cell = 1; ++ ++ mtd_set_ooblayout(mtd, snand->ooblayout); ++ chip->ecc.read_page = spi_nand_read_page_hwecc; ++ chip->ecc.write_page = spi_nand_write_page_hwecc; ++ chip->ecc.mode = NAND_ECC_HW; ++ ++ if (of_property_read_bool(np, "nand-on-flash-bbt")) ++ chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; ++ ++#ifdef CONFIG_MTD_OF_PARTS ++ of_property_read_string(np, "linux,mtd-name", &of_mtd_name); ++#endif ++ if (of_mtd_name) ++ mtd->name = of_mtd_name; ++ else ++ mtd->name = snand->name; ++ mtd->owner = THIS_MODULE; ++ ++ /* Allocate buffer to be used to read/write the internal registers */ ++ snand->buf = kmalloc(SPI_NAND_CMD_BUF_LEN, GFP_KERNEL); ++ if (!snand->buf) ++ return -ENOMEM; ++ ++ /* This is enabled at device power up but we'd better make sure */ ++ ret = spi_nand_enable_ecc(snand); ++ if (ret) ++ return ret; ++ ++ /* Preallocate buffer for flash identification (NAND_CMD_READID) */ ++ snand->buf_size = SPI_NAND_CMD_BUF_LEN; ++ snand->data_buf = kmalloc(snand->buf_size, GFP_KERNEL); ++ ++ ret = nand_scan_ident(mtd, 1, flash_ids); ++ if (ret) ++ return ret; ++ ++ /* ++ * SPI NAND has on-die ECC, which means we can correct as much as ++ * we are required to. This must be done after identification of ++ * the device. ++ */ ++ chip->ecc.strength = chip->ecc_strength_ds; ++ chip->ecc.size = chip->ecc_step_ds; ++ ++ /* ++ * Unlock all the device before calling nand_scan_tail. This is needed ++ * in case the in-flash bad block table needs to be created. ++ * We could override __nand_unlock(), but since it's not currently used ++ * by the NAND core we call this explicitly. ++ */ ++ snand->buf[0] = SPI_NAND_PROT_UNLOCK_ALL; ++ ret = snand->write_reg(snand, SPI_NAND_LOCK_REG, snand->buf); ++ if (ret) ++ return ret; ++ ++ /* Free the buffer and allocate a good one, to fit a page plus OOB */ ++ kfree(snand->data_buf); ++ ++ snand->buf_size = mtd->writesize + mtd->oobsize; ++ snand->data_buf = kmalloc(snand->buf_size, GFP_KERNEL); ++ if (!snand->data_buf) ++ return -ENOMEM; ++ ++ ret = nand_scan_tail(mtd); ++ if (ret) ++ return ret; ++ ++ return mtd_device_register(mtd, NULL, 0); ++} ++EXPORT_SYMBOL_GPL(spi_nand_register); ++ ++void spi_nand_unregister(struct spi_nand *snand) ++{ ++ kfree(snand->buf); ++ kfree(snand->data_buf); ++} ++EXPORT_SYMBOL_GPL(spi_nand_unregister); ++ ++MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@imgtec.com>"); ++MODULE_DESCRIPTION("Framework for SPI NAND"); ++MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/mtd/spi-nand.h b/include/linux/mtd/spi-nand.h +new file mode 100644 +index 0000000..b5cc99f +--- /dev/null ++++ b/include/linux/mtd/spi-nand.h +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (C) 2014 Imagination Technologies Ltd. ++ * ++ * 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 of the License. ++ */ ++ ++#ifndef __LINUX_MTD_SPI_NAND_H ++#define __LINUX_MTD_SPI_NAND_H ++ ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/nand.h> ++ ++struct spi_nand { ++ struct nand_chip nand_chip; ++ struct device *dev; ++ const char *name; ++ ++ u8 *buf, *data_buf; ++ size_t buf_size; ++ off_t buf_start; ++ unsigned int page_addr; ++ unsigned int bitflips; ++ bool ecc; ++ struct mtd_ooblayout_ops *ooblayout; ++ ++ int (*reset)(struct spi_nand *snand); ++ int (*read_id)(struct spi_nand *snand, u8 *buf); ++ ++ int (*write_disable)(struct spi_nand *snand); ++ int (*write_enable)(struct spi_nand *snand); ++ ++ int (*read_reg)(struct spi_nand *snand, u8 opcode, u8 *buf); ++ int (*write_reg)(struct spi_nand *snand, u8 opcode, u8 *buf); ++ void (*get_ecc_status)(unsigned int status, ++ unsigned int *corrected, ++ unsigned int *ecc_errors); ++ ++ int (*store_cache)(struct spi_nand *snand, unsigned int page_offset, ++ size_t length, u8 *write_buf); ++ int (*write_page)(struct spi_nand *snand, unsigned int page_addr); ++ int (*load_page)(struct spi_nand *snand, unsigned int page_addr); ++ int (*read_cache)(struct spi_nand *snand, unsigned int page_offset, ++ size_t length, u8 *read_buf); ++ int (*block_erase)(struct spi_nand *snand, unsigned int page_addr); ++ ++ void *priv; ++}; ++ ++int spi_nand_register(struct spi_nand *snand, struct nand_flash_dev *flash_ids); ++void spi_nand_unregister(struct spi_nand *snand); ++ ++#endif +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/414-mtd-spi-nand-Support-Gigadevice-GD5F.patch b/target/linux/pistachio/patches-4.9/414-mtd-spi-nand-Support-Gigadevice-GD5F.patch new file mode 100644 index 0000000000..34d2aab12b --- /dev/null +++ b/target/linux/pistachio/patches-4.9/414-mtd-spi-nand-Support-Gigadevice-GD5F.patch @@ -0,0 +1,534 @@ +From 7723e59d483a883578115a73eb87eb7fff0ff724 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@imgtec.com> +Date: Tue, 28 Feb 2017 10:37:24 +0000 +Subject: mtd: spi-nand: Support Gigadevice GD5F + +This commit uses the recently introduced SPI NAND framework to support +the Gigadevice GD5F serial NAND device. + +The current support includes: + + * Page read and page program operations (using on-die ECC) + * Page out-of-band read + * Erase + * Reset + * Device status retrieval + * Device ID retrieval + +(based on http://lists.infradead.org/pipermail/linux-mtd/2014-December/056769.html) + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@imgtec.com> +Signed-off-by: Ian Pozella <Ian.Pozella@imgtec.com> +--- + drivers/mtd/spi-nand/Kconfig | 10 + + drivers/mtd/spi-nand/Makefile | 1 + + drivers/mtd/spi-nand/spi-nand-device.c | 472 +++++++++++++++++++++++++++++++++ + 3 files changed, 483 insertions(+) + create mode 100644 drivers/mtd/spi-nand/spi-nand-device.c + +diff --git a/drivers/mtd/spi-nand/Kconfig b/drivers/mtd/spi-nand/Kconfig +index 17b31e1..ab6bb6c 100644 +--- a/drivers/mtd/spi-nand/Kconfig ++++ b/drivers/mtd/spi-nand/Kconfig +@@ -5,3 +5,13 @@ menuconfig MTD_SPI_NAND + help + This is the framework for the SPI NAND. + ++if MTD_SPI_NAND ++ ++config MTD_SPI_NAND_DEVICES ++ tristate "Support for SPI NAND devices" ++ default y ++ depends on MTD_SPI_NAND ++ help ++ Select this option if you require support for SPI NAND devices. ++ ++endif # MTD_SPI_NAND +diff --git a/drivers/mtd/spi-nand/Makefile b/drivers/mtd/spi-nand/Makefile +index d454c52..6e460d1 100644 +--- a/drivers/mtd/spi-nand/Makefile ++++ b/drivers/mtd/spi-nand/Makefile +@@ -1 +1,2 @@ + obj-$(CONFIG_MTD_SPI_NAND) += spi-nand-base.o ++obj-$(CONFIG_MTD_SPI_NAND_DEVICES) += spi-nand-device.o +diff --git a/drivers/mtd/spi-nand/spi-nand-device.c b/drivers/mtd/spi-nand/spi-nand-device.c +new file mode 100644 +index 0000000..95db20b +--- /dev/null ++++ b/drivers/mtd/spi-nand/spi-nand-device.c +@@ -0,0 +1,472 @@ ++/* ++ * Copyright (C) 2014 Imagination Technologies Ltd. ++ * ++ * 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 of the License. ++ * ++ * Notes: ++ * 1. We avoid using a stack-allocated buffer for SPI messages. Using ++ * a kmalloced buffer is probably better, given we shouldn't assume ++ * any particular usage by SPI core. ++ */ ++ ++#include <linux/device.h> ++#include <linux/err.h> ++#include <linux/errno.h> ++#include <linux/module.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/mtd/spi-nand.h> ++#include <linux/sizes.h> ++#include <linux/spi/spi.h> ++ ++/* SPI NAND commands */ ++#define SPI_NAND_WRITE_ENABLE 0x06 ++#define SPI_NAND_WRITE_DISABLE 0x04 ++#define SPI_NAND_GET_FEATURE 0x0f ++#define SPI_NAND_SET_FEATURE 0x1f ++#define SPI_NAND_PAGE_READ 0x13 ++#define SPI_NAND_READ_CACHE 0x03 ++#define SPI_NAND_FAST_READ_CACHE 0x0b ++#define SPI_NAND_READ_CACHE_X2 0x3b ++#define SPI_NAND_READ_CACHE_X4 0x6b ++#define SPI_NAND_READ_CACHE_DUAL_IO 0xbb ++#define SPI_NAND_READ_CACHE_QUAD_IO 0xeb ++#define SPI_NAND_READ_ID 0x9f ++#define SPI_NAND_PROGRAM_LOAD 0x02 ++#define SPI_NAND_PROGRAM_LOAD4 0x32 ++#define SPI_NAND_PROGRAM_EXEC 0x10 ++#define SPI_NAND_PROGRAM_LOAD_RANDOM 0x84 ++#define SPI_NAND_PROGRAM_LOAD_RANDOM4 0xc4 ++#define SPI_NAND_BLOCK_ERASE 0xd8 ++#define SPI_NAND_RESET 0xff ++ ++#define SPI_NAND_GD5F_READID_LEN 2 ++ ++#define SPI_NAND_GD5F_ECC_MASK (BIT(0) | BIT(1) | BIT(2)) ++#define SPI_NAND_GD5F_ECC_UNCORR (BIT(0) | BIT(1) | BIT(2)) ++#define SPI_NAND_GD5F_ECC_SHIFT 4 ++ ++static int spi_nand_gd5f_ooblayout_256_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ if (section) ++ return -ERANGE; ++ ++ oobregion->offset = 128; ++ oobregion->length = 128; ++ ++ return 0; ++} ++ ++static int spi_nand_gd5f_ooblayout_256_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ if (section) ++ return -ERANGE; ++ ++ oobregion->offset = 1; ++ oobregion->length = 127; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops spi_nand_gd5f_oob_256_ops = { ++ .ecc = spi_nand_gd5f_ooblayout_256_ecc, ++ .free = spi_nand_gd5f_ooblayout_256_free, ++}; ++ ++static struct nand_flash_dev spi_nand_flash_ids[] = { ++ { ++ .name = "SPI NAND 512MiB 3,3V", ++ .id = { NAND_MFR_GIGADEVICE, 0xb4 }, ++ .chipsize = 512, ++ .pagesize = SZ_4K, ++ .erasesize = SZ_256K, ++ .id_len = 2, ++ .oobsize = 256, ++ .ecc.strength_ds = 8, ++ .ecc.step_ds = 512, ++ }, ++ { ++ .name = "SPI NAND 512MiB 1,8V", ++ .id = { NAND_MFR_GIGADEVICE, 0xa4 }, ++ .chipsize = 512, ++ .pagesize = SZ_4K, ++ .erasesize = SZ_256K, ++ .id_len = 2, ++ .oobsize = 256, ++ .ecc.strength_ds = 8, ++ .ecc.step_ds = 512, ++ }, ++}; ++ ++enum spi_nand_device_variant { ++ SPI_NAND_GENERIC, ++ SPI_NAND_GD5F, ++}; ++ ++struct spi_nand_device_cmd { ++ ++ /* ++ * Command and address. I/O errors have been observed if a ++ * separate spi_transfer is used for command and address, ++ * so keep them together. ++ */ ++ u32 n_cmd; ++ u8 cmd[5]; ++ ++ /* Tx data */ ++ u32 n_tx; ++ u8 *tx_buf; ++ ++ /* Rx data */ ++ u32 n_rx; ++ u8 *rx_buf; ++ u8 rx_nbits; ++ u8 tx_nbits; ++}; ++ ++struct spi_nand_device { ++ struct spi_nand spi_nand; ++ struct spi_device *spi; ++ ++ struct spi_nand_device_cmd cmd; ++}; ++ ++static int spi_nand_send_command(struct spi_device *spi, ++ struct spi_nand_device_cmd *cmd) ++{ ++ struct spi_message message; ++ struct spi_transfer x[2]; ++ ++ if (!cmd->n_cmd) { ++ dev_err(&spi->dev, "cannot send an empty command\n"); ++ return -EINVAL; ++ } ++ ++ if (cmd->n_tx && cmd->n_rx) { ++ dev_err(&spi->dev, "cannot send and receive data at the same time\n"); ++ return -EINVAL; ++ } ++ ++ spi_message_init(&message); ++ memset(x, 0, sizeof(x)); ++ ++ /* Command and address */ ++ x[0].len = cmd->n_cmd; ++ x[0].tx_buf = cmd->cmd; ++ x[0].tx_nbits = cmd->tx_nbits; ++ spi_message_add_tail(&x[0], &message); ++ ++ /* Data to be transmitted */ ++ if (cmd->n_tx) { ++ x[1].len = cmd->n_tx; ++ x[1].tx_buf = cmd->tx_buf; ++ x[1].tx_nbits = cmd->tx_nbits; ++ spi_message_add_tail(&x[1], &message); ++ } ++ ++ /* Data to be received */ ++ if (cmd->n_rx) { ++ x[1].len = cmd->n_rx; ++ x[1].rx_buf = cmd->rx_buf; ++ x[1].rx_nbits = cmd->rx_nbits; ++ spi_message_add_tail(&x[1], &message); ++ } ++ ++ return spi_sync(spi, &message); ++} ++ ++static int spi_nand_device_reset(struct spi_nand *snand) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 1; ++ cmd->cmd[0] = SPI_NAND_RESET; ++ ++ dev_dbg(snand->dev, "%s\n", __func__); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_device_read_reg(struct spi_nand *snand, u8 opcode, u8 *buf) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 2; ++ cmd->cmd[0] = SPI_NAND_GET_FEATURE; ++ cmd->cmd[1] = opcode; ++ cmd->n_rx = 1; ++ cmd->rx_buf = buf; ++ ++ dev_dbg(snand->dev, "%s: reg 0%x\n", __func__, opcode); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_device_write_reg(struct spi_nand *snand, u8 opcode, u8 *buf) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 2; ++ cmd->cmd[0] = SPI_NAND_SET_FEATURE; ++ cmd->cmd[1] = opcode; ++ cmd->n_tx = 1; ++ cmd->tx_buf = buf; ++ ++ dev_dbg(snand->dev, "%s: reg 0%x\n", __func__, opcode); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_device_write_enable(struct spi_nand *snand) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 1; ++ cmd->cmd[0] = SPI_NAND_WRITE_ENABLE; ++ ++ dev_dbg(snand->dev, "%s\n", __func__); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_device_write_disable(struct spi_nand *snand) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 1; ++ cmd->cmd[0] = SPI_NAND_WRITE_DISABLE; ++ ++ dev_dbg(snand->dev, "%s\n", __func__); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_device_write_page(struct spi_nand *snand, ++ unsigned int page_addr) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 4; ++ cmd->cmd[0] = SPI_NAND_PROGRAM_EXEC; ++ cmd->cmd[1] = (u8)((page_addr & 0xff0000) >> 16); ++ cmd->cmd[2] = (u8)((page_addr & 0xff00) >> 8); ++ cmd->cmd[3] = (u8)(page_addr & 0xff); ++ ++ dev_dbg(snand->dev, "%s: page 0x%x\n", __func__, page_addr); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_device_store_cache(struct spi_nand *snand, ++ unsigned int page_offset, size_t length, ++ u8 *write_buf) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ struct spi_device *spi = snand_dev->spi; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 3; ++ cmd->cmd[0] = spi->mode & SPI_TX_QUAD ? SPI_NAND_PROGRAM_LOAD4 : ++ SPI_NAND_PROGRAM_LOAD; ++ cmd->cmd[1] = (u8)((page_offset & 0xff00) >> 8); ++ cmd->cmd[2] = (u8)(page_offset & 0xff); ++ cmd->n_tx = length; ++ cmd->tx_buf = write_buf; ++ cmd->tx_nbits = spi->mode & SPI_TX_QUAD ? 4 : 1; ++ ++ dev_dbg(snand->dev, "%s: offset 0x%x\n", __func__, page_offset); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_device_load_page(struct spi_nand *snand, ++ unsigned int page_addr) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 4; ++ cmd->cmd[0] = SPI_NAND_PAGE_READ; ++ cmd->cmd[1] = (u8)((page_addr & 0xff0000) >> 16); ++ cmd->cmd[2] = (u8)((page_addr & 0xff00) >> 8); ++ cmd->cmd[3] = (u8)(page_addr & 0xff); ++ ++ dev_dbg(snand->dev, "%s: page 0x%x\n", __func__, page_addr); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_device_read_cache(struct spi_nand *snand, ++ unsigned int page_offset, size_t length, ++ u8 *read_buf) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ struct spi_device *spi = snand_dev->spi; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ if ((spi->mode & SPI_RX_DUAL) || (spi->mode & SPI_RX_QUAD)) ++ cmd->n_cmd = 5; ++ else ++ cmd->n_cmd = 4; ++ cmd->cmd[0] = (spi->mode & SPI_RX_QUAD) ? SPI_NAND_READ_CACHE_X4 : ++ ((spi->mode & SPI_RX_DUAL) ? SPI_NAND_READ_CACHE_X2 : ++ SPI_NAND_READ_CACHE); ++ cmd->cmd[1] = 0; /* dummy byte */ ++ cmd->cmd[2] = (u8)((page_offset & 0xff00) >> 8); ++ cmd->cmd[3] = (u8)(page_offset & 0xff); ++ cmd->cmd[4] = 0; /* dummy byte */ ++ cmd->n_rx = length; ++ cmd->rx_buf = read_buf; ++ cmd->rx_nbits = (spi->mode & SPI_RX_QUAD) ? 4 : ++ ((spi->mode & SPI_RX_DUAL) ? 2 : 1); ++ ++ dev_dbg(snand->dev, "%s: offset 0x%x\n", __func__, page_offset); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_device_block_erase(struct spi_nand *snand, ++ unsigned int page_addr) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 4; ++ cmd->cmd[0] = SPI_NAND_BLOCK_ERASE; ++ cmd->cmd[1] = (u8)((page_addr & 0xff0000) >> 16); ++ cmd->cmd[2] = (u8)((page_addr & 0xff00) >> 8); ++ cmd->cmd[3] = (u8)(page_addr & 0xff); ++ ++ dev_dbg(snand->dev, "%s: block 0x%x\n", __func__, page_addr); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static int spi_nand_gd5f_read_id(struct spi_nand *snand, u8 *buf) ++{ ++ struct spi_nand_device *snand_dev = snand->priv; ++ struct spi_nand_device_cmd *cmd = &snand_dev->cmd; ++ ++ memset(cmd, 0, sizeof(struct spi_nand_device_cmd)); ++ cmd->n_cmd = 1; ++ cmd->cmd[0] = SPI_NAND_READ_ID; ++ cmd->n_rx = SPI_NAND_GD5F_READID_LEN; ++ cmd->rx_buf = buf; ++ ++ dev_dbg(snand->dev, "%s\n", __func__); ++ ++ return spi_nand_send_command(snand_dev->spi, cmd); ++} ++ ++static void spi_nand_gd5f_ecc_status(unsigned int status, ++ unsigned int *corrected, ++ unsigned int *ecc_error) ++{ ++ unsigned int ecc_status = (status >> SPI_NAND_GD5F_ECC_SHIFT) & ++ SPI_NAND_GD5F_ECC_MASK; ++ ++ *ecc_error = (ecc_status == SPI_NAND_GD5F_ECC_UNCORR) ? 1 : 0; ++ if (*ecc_error == 0) ++ *corrected = (ecc_status > 1) ? (2 + ecc_status) : 0; ++} ++ ++static int spi_nand_device_probe(struct spi_device *spi) ++{ ++ enum spi_nand_device_variant variant; ++ struct spi_nand_device *priv; ++ struct spi_nand *snand; ++ int ret; ++ ++ priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ snand = &priv->spi_nand; ++ ++ snand->read_cache = spi_nand_device_read_cache; ++ snand->load_page = spi_nand_device_load_page; ++ snand->store_cache = spi_nand_device_store_cache; ++ snand->write_page = spi_nand_device_write_page; ++ snand->write_reg = spi_nand_device_write_reg; ++ snand->read_reg = spi_nand_device_read_reg; ++ snand->block_erase = spi_nand_device_block_erase; ++ snand->reset = spi_nand_device_reset; ++ snand->write_enable = spi_nand_device_write_enable; ++ snand->write_disable = spi_nand_device_write_disable; ++ snand->dev = &spi->dev; ++ snand->priv = priv; ++ ++ /* This'll mean we won't need to specify any specific compatible string ++ * for a given device, and instead just support spi-nand. ++ */ ++ variant = spi_get_device_id(spi)->driver_data; ++ switch (variant) { ++ case SPI_NAND_GD5F: ++ snand->read_id = spi_nand_gd5f_read_id; ++ snand->get_ecc_status = spi_nand_gd5f_ecc_status; ++ snand->ooblayout = &spi_nand_gd5f_oob_256_ops; ++ break; ++ default: ++ dev_err(snand->dev, "unknown device\n"); ++ return -ENODEV; ++ } ++ ++ spi_set_drvdata(spi, snand); ++ priv->spi = spi; ++ ++ ret = spi_nand_register(snand, spi_nand_flash_ids); ++ if (ret) ++ return ret; ++ return 0; ++} ++ ++static int spi_nand_device_remove(struct spi_device *spi) ++{ ++ struct spi_nand *snand = spi_get_drvdata(spi); ++ ++ spi_nand_unregister(snand); ++ ++ return 0; ++} ++ ++const struct spi_device_id spi_nand_id_table[] = { ++ { "spi-nand", SPI_NAND_GENERIC }, ++ { "gd5f", SPI_NAND_GD5F }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(spi, spi_nand_id_table); ++ ++static struct spi_driver spi_nand_device_driver = { ++ .driver = { ++ .name = "spi_nand_device", ++ .owner = THIS_MODULE, ++ }, ++ .id_table = spi_nand_id_table, ++ .probe = spi_nand_device_probe, ++ .remove = spi_nand_device_remove, ++}; ++module_spi_driver(spi_nand_device_driver); ++ ++MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@imgtec.com>"); ++MODULE_DESCRIPTION("SPI NAND device support"); ++MODULE_LICENSE("GPL v2"); +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/701-net-micrel-Disable-PME.patch b/target/linux/pistachio/patches-4.9/701-net-micrel-Disable-PME.patch new file mode 100644 index 0000000000..4274a353e2 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/701-net-micrel-Disable-PME.patch @@ -0,0 +1,40 @@ +From 5e84aec87108e0481af7495a1e9a9953d8590d70 Mon Sep 17 00:00:00 2001 +From: Xue Liu <liuxuenetmail@gmail.com> +Date: Mon, 6 Feb 2017 17:43:19 +0000 +Subject: net: micrel: Disable PME + +Disable PME for Micrel phy driver allowing the Ethernet ports LED +driver to work on marduk platform. + +Signed-off-by: Xue Liu <liuxuenetmail@gmail.com> +--- + drivers/net/phy/micrel.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c +index ea92d52..73401fb 100644 +--- a/drivers/net/phy/micrel.c ++++ b/drivers/net/phy/micrel.c +@@ -273,6 +273,7 @@ static int kszphy_config_init(struct phy_device *phydev) + struct kszphy_priv *priv = phydev->priv; + const struct kszphy_type *type; + int ret; ++ int temp = 0; + + if (!priv) + return 0; +@@ -308,6 +309,11 @@ static int kszphy_config_init(struct phy_device *phydev) + return ret; + } + ++ /* disable PME */ ++ temp = phy_read(phydev, 0x16); ++ temp &= ~(1 << 15); ++ phy_write(phydev, 0x16, temp); ++ + return 0; + } + +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/901-MIPS-DTS-img-marduk-add-nor-partition-name.patch b/target/linux/pistachio/patches-4.9/901-MIPS-DTS-img-marduk-add-nor-partition-name.patch new file mode 100644 index 0000000000..e2ccd7af94 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/901-MIPS-DTS-img-marduk-add-nor-partition-name.patch @@ -0,0 +1,25 @@ +From b5f49b448cd3c7ab930f1a53c88f739a86071df8 Mon Sep 17 00:00:00 2001 +From: Ian Pozella <Ian.Pozella@imgtec.com> +Date: Mon, 20 Feb 2017 10:38:07 +0000 +Subject: MIPS: DTS: img: marduk: add nor partition name + +Signed-off-by: Ian Pozella <Ian.Pozella@imgtec.com> +--- + arch/mips/boot/dts/img/pistachio_marduk.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/mips/boot/dts/img/pistachio_marduk.dts b/arch/mips/boot/dts/img/pistachio_marduk.dts +index 7708815..b18aa26 100644 +--- a/arch/mips/boot/dts/img/pistachio_marduk.dts ++++ b/arch/mips/boot/dts/img/pistachio_marduk.dts +@@ -90,6 +90,7 @@ + compatible = "spansion,s25fl016k", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; ++ linux,mtd-name = "spi-nor"; + }; + }; + +-- +2.7.4 + diff --git a/target/linux/pistachio/patches-4.9/902-MIPS-DTS-img-marduk-add-nand-device-support.patch b/target/linux/pistachio/patches-4.9/902-MIPS-DTS-img-marduk-add-nand-device-support.patch new file mode 100644 index 0000000000..cb96753875 --- /dev/null +++ b/target/linux/pistachio/patches-4.9/902-MIPS-DTS-img-marduk-add-nand-device-support.patch @@ -0,0 +1,35 @@ +From c13cfb3a49cf1578bb85f19a7066f262503a39ba Mon Sep 17 00:00:00 2001 +From: Abhimanyu Vishwakarma <Abhimanyu.Vishwakarma@imgtec.com> +Date: Thu, 24 Nov 2016 19:26:46 +0530 +Subject: MIPS: DTS: img: marduk: add nand device support + +Signed-off-by: Abhimanyu Vishwakarma <Abhimanyu.Vishwakarma@imgtec.com> +--- + arch/mips/boot/dts/img/pistachio_marduk.dts | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/mips/boot/dts/img/pistachio_marduk.dts b/arch/mips/boot/dts/img/pistachio_marduk.dts +index b18aa26..ed92462 100644 +--- a/arch/mips/boot/dts/img/pistachio_marduk.dts ++++ b/arch/mips/boot/dts/img/pistachio_marduk.dts +@@ -92,6 +92,17 @@ + spi-max-frequency = <50000000>; + linux,mtd-name = "spi-nor"; + }; ++ flash@1 { ++ compatible = "gigadevice,gd5f"; ++ reg = <1>; ++ spi-max-frequency = <50000000>; ++ nand-on-flash-bbt; ++ spi-rx-bus-width = <2>; ++ spi-tx-bus-width = <4>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ linux,mtd-name = "spi-nand"; ++ }; + }; + + &uart0 { +-- +2.7.4 + |