ipq806x: add support for 4.0 kernel
authorJohn Crispin <john@openwrt.org>
Wed, 1 Apr 2015 08:32:03 +0000 (08:32 +0000)
committerJohn Crispin <john@openwrt.org>
Wed, 1 Apr 2015 08:32:03 +0000 (08:32 +0000)
Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
SVN-Revision: 45210

target/linux/ipq806x/config-4.0 [new file with mode: 0644]
target/linux/ipq806x/patches-4.0/001-spi-qup-Add-DMA-capabilities.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.0/002-v3-spi-qup-Fix-incorrect-block-transfers.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.0/003-spi-qup-Ensure-done-detection.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.0/011-watchdog-qcom-use-timer-devicetree-binding.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.0/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.0/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.0/020-add-ap148-bootargs.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.0/021-add-ap148-partitions.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.0/700-add-gmac-dts-suport.patch [new file with mode: 0644]

diff --git a/target/linux/ipq806x/config-4.0 b/target/linux/ipq806x/config-4.0
new file mode 100644 (file)
index 0000000..5ce4644
--- /dev/null
@@ -0,0 +1,389 @@
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_AMBA_PL08X is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_APQ_GCC_8084=y
+CONFIG_APQ_MMCC_8084=y
+CONFIG_AR8216_PHY=y
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MSM8960=y
+CONFIG_ARCH_MSM8974=y
+CONFIG_ARCH_MSM8X60=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+CONFIG_ARCH_MULTI_V6_V7=y
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_QCOM=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+# CONFIG_ARM_LPAE is not set
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+# CONFIG_ARM_SMMU is not set
+# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_AUTO_ZRELADDR=y
+# CONFIG_BATTERY_GAUGE_LTC2941 is not set
+CONFIG_BCMA_DRIVER_PCI=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_BOUNCE=y
+CONFIG_BUILD_BIN2C=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CLEANCACHE=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_QCOM=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_COMMON_CLK=y
+CONFIG_COMMON_CLK_QCOM=y
+CONFIG_COMPACTION=y
+CONFIG_COREDUMP=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+# CONFIG_CRC32_SARWATE is not set
+CONFIG_CRC32_SLICEBY8=y
+CONFIG_CROSS_MEMORY_ATTACH=y
+# CONFIG_CRYPTO_SHA1_ARM_NEON is not set
+# CONFIG_CRYPTO_SHA512_ARM_NEON is not set
+CONFIG_CRYPTO_XZ=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DEVMEM=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DTC=y
+# CONFIG_DW_DMAC_CORE is not set
+# CONFIG_DW_DMAC_PCI is not set
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_ETHERNET_PACKET_MANGLE=y
+CONFIG_FREEZER=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_MSI_IRQ=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_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_DEVRES=y
+# CONFIG_GPIO_MSM_V2 is not set
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_HZ_FIXED=0
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_QUP=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IOMMU_HELPER=y
+# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
+CONFIG_IOMMU_SUPPORT=y
+CONFIG_IPQ_GCC_806X=y
+# CONFIG_IPQ_LCC_806X is not set
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+# CONFIG_LEDS_REGULATOR is not set
+CONFIG_LIBFDT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+# CONFIG_LZ4_COMPRESS is not set
+# CONFIG_LZ4_DECOMPRESS is not set
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MDIO_GPIO=y
+# CONFIG_MFD_DA9150 is not set
+# CONFIG_MFD_QCOM_RPM is not set
+# CONFIG_MFD_RT5033 is not set
+# CONFIG_MFD_SPMI_PMIC is not set
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_MIGRATION=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MPLS is not set
+CONFIG_MSM_GCC_8660=y
+CONFIG_MSM_GCC_8960=y
+CONFIG_MSM_GCC_8974=y
+# CONFIG_MSM_LCC_8960 is not set
+CONFIG_MSM_MMCC_8960=y
+CONFIG_MSM_MMCC_8974=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_FIT_FW=y
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEON=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_VENDOR_WIZNET=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_ADDRESS_PCI=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PCI=y
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+CONFIG_PCI_MSI=y
+CONFIG_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PHYLIB=y
+# CONFIG_PHY_QCOM_APQ8064_SATA is not set
+CONFIG_PHY_QCOM_IPQ806X_SATA=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_APQ8064=y
+# CONFIG_PINCTRL_APQ8084 is not set
+CONFIG_PINCTRL_IPQ8064=y
+CONFIG_PINCTRL_MSM=y
+# CONFIG_PINCTRL_MSM8916 is not set
+# CONFIG_PINCTRL_MSM8960 is not set
+CONFIG_PINCTRL_MSM8X74=y
+# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set
+# CONFIG_PL330_DMA is not set
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_POWER_RESET=y
+# CONFIG_POWER_RESET_BRCMSTB is not set
+# CONFIG_POWER_RESET_GPIO is not set
+# CONFIG_POWER_RESET_GPIO_RESTART is not set
+# CONFIG_POWER_RESET_LTC2952 is not set
+CONFIG_POWER_RESET_MSM=y
+# CONFIG_POWER_RESET_SYSCON is not set
+CONFIG_POWER_SUPPLY=y
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_COUNT=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_RCU=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_QCOM_BAM_DMA=y
+CONFIG_QCOM_GSBI=y
+CONFIG_QCOM_SCM=y
+CONFIG_QCOM_WDT=y
+# CONFIG_RCU_BOOST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RD_GZIP=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_CMOS is not set
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_AMBA_PL010 is not set
+# CONFIG_SERIAL_AMBA_PL011 is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_CPU_PARTIAL=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_QUP=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_SRCU=y
+CONFIG_STOP_MACHINE=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_SWCONFIG=y
+CONFIG_SWIOTLB=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_TEGRA_AHB is not set
+CONFIG_THERMAL=y
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_EMULATION is not set
+# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
+CONFIG_THERMAL_GOV_STEP_WISE=y
+# CONFIG_THERMAL_GOV_USER_SPACE is not set
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_OF=y
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_STATS=y
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_UID16=y
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WATCHDOG_CORE=y
+# CONFIG_WIZNET_W5100 is not set
+# CONFIG_WIZNET_W5300 is not set
+# CONFIG_WL_TI is not set
+# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+# CONFIG_XEN is not set
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/ipq806x/patches-4.0/001-spi-qup-Add-DMA-capabilities.patch b/target/linux/ipq806x/patches-4.0/001-spi-qup-Add-DMA-capabilities.patch
new file mode 100644 (file)
index 0000000..62badd5
--- /dev/null
@@ -0,0 +1,522 @@
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: spi: qup: Add DMA capabilities
+From: Andy Gross <agross@codeaurora.org>
+X-Patchwork-Id: 4432401
+Message-Id: <1403816781-31008-1-git-send-email-agross@codeaurora.org>
+To: Mark Brown <broonie@kernel.org>
+Cc: linux-spi@vger.kernel.org, Sagar Dharia <sdharia@codeaurora.org>,
+       Daniel Sneddon <dsneddon@codeaurora.org>,
+       Bjorn Andersson <bjorn.andersson@sonymobile.com>,
+       "Ivan T. Ivanov" <iivanov@mm-sol.com>,
+       linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
+       linux-arm-msm@vger.kernel.org, Andy Gross <agross@codeaurora.org>
+Date: Thu, 26 Jun 2014 16:06:21 -0500
+
+This patch adds DMA capabilities to the spi-qup driver.  If DMA channels are
+present, the QUP will use DMA instead of block mode for transfers to/from SPI
+peripherals for transactions larger than the length of a block.
+
+Signed-off-by: Andy Gross <agross@codeaurora.org>
+
+---
+.../devicetree/bindings/spi/qcom,spi-qup.txt       |   10 +
+ drivers/spi/spi-qup.c                              |  361 ++++++++++++++++++--
+ 2 files changed, 350 insertions(+), 21 deletions(-)
+
+--- a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
++++ b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
+@@ -27,6 +27,11 @@ Optional properties:
+ - spi-max-frequency: Specifies maximum SPI clock frequency,
+                      Units - Hz. Definition as per
+                      Documentation/devicetree/bindings/spi/spi-bus.txt
++- dmas :             Two DMA channel specifiers following the convention outlined
++                     in bindings/dma/dma.txt
++- dma-names:         Names for the dma channels, if present. There must be at
++                     least one channel named "tx" for transmit and named "rx" for
++                     receive.
+ - num-cs:     total number of chipselects
+ - cs-gpios:   should specify GPIOs used for chipselects.
+               The gpios will be referred to as reg = <index> in the SPI child
+@@ -51,6 +56,10 @@ Example:
+               clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
+               clock-names = "core", "iface";
++              dmas = <&blsp2_bam 2>,
++                      <&blsp2_bam 3>;
++              dma-names = "rx", "tx";
++
+               pinctrl-names = "default";
+               pinctrl-0 = <&spi8_default>;
+--- a/drivers/spi/spi-qup.c
++++ b/drivers/spi/spi-qup.c
+@@ -22,6 +22,8 @@
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/spi/spi.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
+ #define QUP_CONFIG                    0x0000
+ #define QUP_STATE                     0x0004
+@@ -116,6 +118,8 @@
+ #define SPI_NUM_CHIPSELECTS           4
++#define SPI_MAX_XFER                  (SZ_64K - 64)
++
+ /* high speed mode is when bus rate is greater then 26MHz */
+ #define SPI_HS_MIN_RATE                       26000000
+ #define SPI_MAX_RATE                  50000000
+@@ -143,6 +147,17 @@ struct spi_qup {
+       int                     tx_bytes;
+       int                     rx_bytes;
+       int                     qup_v1;
++
++      int                     use_dma;
++
++      struct dma_chan         *rx_chan;
++      struct dma_slave_config rx_conf;
++      struct dma_chan         *tx_chan;
++      struct dma_slave_config tx_conf;
++      dma_addr_t              rx_dma;
++      dma_addr_t              tx_dma;
++      void                    *dummy;
++      atomic_t                dma_outstanding;
+ };
+@@ -266,6 +281,221 @@ static void spi_qup_fifo_write(struct sp
+       }
+ }
++static void qup_dma_callback(void *data)
++{
++      struct spi_qup *controller = data;
++
++      if (atomic_dec_and_test(&controller->dma_outstanding))
++              complete(&controller->done);
++}
++
++static int spi_qup_do_dma(struct spi_qup *controller, struct spi_transfer *xfer)
++{
++      struct dma_async_tx_descriptor *rxd, *txd;
++      dma_cookie_t rx_cookie, tx_cookie;
++      u32 xfer_len, rx_align = 0, tx_align = 0, n_words;
++      struct scatterlist tx_sg[2], rx_sg[2];
++      int ret = 0;
++      u32 bytes_to_xfer = xfer->len;
++      u32 offset = 0;
++      u32 rx_nents = 0, tx_nents = 0;
++      dma_addr_t rx_dma = 0, tx_dma = 0, rx_dummy_dma = 0, tx_dummy_dma = 0;
++
++
++      if (xfer->rx_buf) {
++              rx_dma = dma_map_single(controller->dev, xfer->rx_buf,
++                      xfer->len, DMA_FROM_DEVICE);
++
++              if (dma_mapping_error(controller->dev, rx_dma)) {
++                      ret = -ENOMEM;
++                      return ret;
++              }
++
++              /* check to see if we need dummy buffer for leftover bytes */
++              rx_align = xfer->len % controller->in_blk_sz;
++              if (rx_align) {
++                      rx_dummy_dma = dma_map_single(controller->dev,
++                              controller->dummy, controller->in_fifo_sz,
++                              DMA_FROM_DEVICE);
++
++                      if (dma_mapping_error(controller->dev, rx_dummy_dma)) {
++                              ret = -ENOMEM;
++                              goto err_map_rx_dummy;
++                      }
++              }
++      }
++
++      if (xfer->tx_buf) {
++              tx_dma = dma_map_single(controller->dev,
++                      (void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE);
++
++              if (dma_mapping_error(controller->dev, tx_dma)) {
++                      ret = -ENOMEM;
++                      goto err_map_tx;
++              }
++
++              /* check to see if we need dummy buffer for leftover bytes */
++              tx_align = xfer->len % controller->out_blk_sz;
++              if (tx_align) {
++                      memcpy(controller->dummy + SZ_1K,
++                              xfer->tx_buf + xfer->len - tx_align,
++                              tx_align);
++                      memset(controller->dummy + SZ_1K + tx_align, 0,
++                              controller->out_blk_sz - tx_align);
++
++                      tx_dummy_dma = dma_map_single(controller->dev,
++                              controller->dummy + SZ_1K,
++                              controller->out_blk_sz, DMA_TO_DEVICE);
++
++                      if (dma_mapping_error(controller->dev, tx_dummy_dma)) {
++                              ret = -ENOMEM;
++                              goto err_map_tx_dummy;
++                      }
++              }
++      }
++
++      atomic_set(&controller->dma_outstanding, 0);
++
++      while (bytes_to_xfer > 0) {
++              xfer_len = min_t(u32, bytes_to_xfer, SPI_MAX_XFER);
++              n_words = DIV_ROUND_UP(xfer_len, controller->w_size);
++
++              /* write out current word count to controller */
++              writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
++              writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
++
++              reinit_completion(&controller->done);
++
++              if (xfer->tx_buf) {
++                      /* recalc align for each transaction */
++                      tx_align = xfer_len % controller->out_blk_sz;
++
++                      if (tx_align)
++                              tx_nents = 2;
++                      else
++                              tx_nents = 1;
++
++                      /* initialize scatterlists */
++                      sg_init_table(tx_sg, tx_nents);
++                      sg_dma_len(&tx_sg[0]) = xfer_len - tx_align;
++                      sg_dma_address(&tx_sg[0]) = tx_dma + offset;
++
++                      /* account for non block size transfer */
++                      if (tx_align) {
++                              sg_dma_len(&tx_sg[1]) = controller->out_blk_sz;
++                              sg_dma_address(&tx_sg[1]) = tx_dummy_dma;
++                      }
++
++                      txd = dmaengine_prep_slave_sg(controller->tx_chan,
++                                      tx_sg, tx_nents, DMA_MEM_TO_DEV, 0);
++                      if (!txd) {
++                              ret = -ENOMEM;
++                              goto err_unmap;
++                      }
++
++                      atomic_inc(&controller->dma_outstanding);
++
++                      txd->callback = qup_dma_callback;
++                      txd->callback_param = controller;
++
++                      tx_cookie = dmaengine_submit(txd);
++
++                      dma_async_issue_pending(controller->tx_chan);
++              }
++
++              if (xfer->rx_buf) {
++                      /* recalc align for each transaction */
++                      rx_align = xfer_len % controller->in_blk_sz;
++
++                      if (rx_align)
++                              rx_nents = 2;
++                      else
++                              rx_nents = 1;
++
++                      /* initialize scatterlists */
++                      sg_init_table(rx_sg, rx_nents);
++                      sg_dma_address(&rx_sg[0]) = rx_dma + offset;
++                      sg_dma_len(&rx_sg[0]) = xfer_len - rx_align;
++
++                      /* account for non block size transfer */
++                      if (rx_align) {
++                              sg_dma_len(&rx_sg[1]) = controller->in_blk_sz;
++                              sg_dma_address(&rx_sg[1]) = rx_dummy_dma;
++                      }
++
++                      rxd = dmaengine_prep_slave_sg(controller->rx_chan,
++                                      rx_sg, rx_nents, DMA_DEV_TO_MEM, 0);
++                      if (!rxd) {
++                              ret = -ENOMEM;
++                              goto err_unmap;
++                      }
++
++                      atomic_inc(&controller->dma_outstanding);
++
++                      rxd->callback = qup_dma_callback;
++                      rxd->callback_param = controller;
++
++                      rx_cookie = dmaengine_submit(rxd);
++
++                      dma_async_issue_pending(controller->rx_chan);
++              }
++
++              if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
++                      dev_warn(controller->dev, "cannot set EXECUTE state\n");
++                      goto err_unmap;
++              }
++
++              if (!wait_for_completion_timeout(&controller->done,
++                      msecs_to_jiffies(1000))) {
++                      ret = -ETIMEDOUT;
++
++                      /* clear out all the DMA transactions */
++                      if (xfer->tx_buf)
++                              dmaengine_terminate_all(controller->tx_chan);
++                      if (xfer->rx_buf)
++                              dmaengine_terminate_all(controller->rx_chan);
++
++                      goto err_unmap;
++              }
++
++              if (rx_align)
++                      memcpy(xfer->rx_buf + offset + xfer->len - rx_align,
++                              controller->dummy, rx_align);
++
++              /* adjust remaining bytes to transfer */
++              bytes_to_xfer -= xfer_len;
++              offset += xfer_len;
++
++
++              /* reset mini-core state so we can program next transaction */
++              if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
++                      dev_err(controller->dev, "cannot set RESET state\n");
++                      goto err_unmap;
++              }
++      }
++
++      ret = 0;
++
++err_unmap:
++      if (tx_align)
++              dma_unmap_single(controller->dev, tx_dummy_dma,
++                      controller->out_fifo_sz, DMA_TO_DEVICE);
++err_map_tx_dummy:
++      if (xfer->tx_buf)
++              dma_unmap_single(controller->dev, tx_dma, xfer->len,
++                      DMA_TO_DEVICE);
++err_map_tx:
++      if (rx_align)
++              dma_unmap_single(controller->dev, rx_dummy_dma,
++                      controller->in_fifo_sz, DMA_FROM_DEVICE);
++err_map_rx_dummy:
++      if (xfer->rx_buf)
++              dma_unmap_single(controller->dev, rx_dma, xfer->len,
++                      DMA_FROM_DEVICE);
++
++      return ret;
++}
++
+ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
+ {
+       struct spi_qup *controller = dev_id;
+@@ -315,11 +545,13 @@ static irqreturn_t spi_qup_qup_irq(int i
+               error = -EIO;
+       }
+-      if (opflags & QUP_OP_IN_SERVICE_FLAG)
+-              spi_qup_fifo_read(controller, xfer);
++      if (!controller->use_dma) {
++              if (opflags & QUP_OP_IN_SERVICE_FLAG)
++                      spi_qup_fifo_read(controller, xfer);
+-      if (opflags & QUP_OP_OUT_SERVICE_FLAG)
+-              spi_qup_fifo_write(controller, xfer);
++              if (opflags & QUP_OP_OUT_SERVICE_FLAG)
++                      spi_qup_fifo_write(controller, xfer);
++      }
+       spin_lock_irqsave(&controller->lock, flags);
+       controller->error = error;
+@@ -339,6 +571,8 @@ static int spi_qup_io_config(struct spi_
+       struct spi_qup *controller = spi_master_get_devdata(spi->master);
+       u32 config, iomode, mode;
+       int ret, n_words, w_size;
++      size_t dma_align = dma_get_cache_alignment();
++      u32 dma_available = 0;
+       if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
+               dev_err(controller->dev, "too big size for loopback %d > %d\n",
+@@ -367,6 +601,11 @@ static int spi_qup_io_config(struct spi_
+       n_words = xfer->len / w_size;
+       controller->w_size = w_size;
++      if (controller->rx_chan &&
++              IS_ALIGNED((size_t)xfer->tx_buf, dma_align) &&
++              IS_ALIGNED((size_t)xfer->rx_buf, dma_align))
++              dma_available = 1;
++
+       if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
+               mode = QUP_IO_M_MODE_FIFO;
+               writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
+@@ -374,19 +613,31 @@ static int spi_qup_io_config(struct spi_
+               /* must be zero for FIFO */
+               writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
+               writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
+-      } else {
++              controller->use_dma = 0;
++      } else if (!dma_available) {
+               mode = QUP_IO_M_MODE_BLOCK;
+               writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+               writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+               /* must be zero for BLOCK and BAM */
+               writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+               writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
++              controller->use_dma = 0;
++      } else {
++              mode = QUP_IO_M_MODE_DMOV;
++              writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
++              writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
++              controller->use_dma = 1;
+       }
+       iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
+       /* Set input and output transfer mode */
+       iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
+-      iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
++
++      if (!controller->use_dma)
++              iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
++      else
++              iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
++
+       iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+       iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+@@ -419,6 +670,14 @@ static int spi_qup_io_config(struct spi_
+       config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
+       config |= xfer->bits_per_word - 1;
+       config |= QUP_CONFIG_SPI_MODE;
++
++      if (controller->use_dma) {
++              if (!xfer->tx_buf)
++                      config |= QUP_CONFIG_NO_OUTPUT;
++              if (!xfer->rx_buf)
++                      config |= QUP_CONFIG_NO_INPUT;
++      }
++
+       writel_relaxed(config, controller->base + QUP_CONFIG);
+       /* only write to OPERATIONAL_MASK when register is present */
+@@ -452,25 +711,29 @@ static int spi_qup_transfer_one(struct s
+       controller->tx_bytes = 0;
+       spin_unlock_irqrestore(&controller->lock, flags);
+-      if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+-              dev_warn(controller->dev, "cannot set RUN state\n");
+-              goto exit;
+-      }
++      if (controller->use_dma) {
++              ret = spi_qup_do_dma(controller, xfer);
++      } else {
++              if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
++                      dev_warn(controller->dev, "cannot set RUN state\n");
++                      goto exit;
++              }
+-      if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
+-              dev_warn(controller->dev, "cannot set PAUSE state\n");
+-              goto exit;
+-      }
++              if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
++                      dev_warn(controller->dev, "cannot set PAUSE state\n");
++                      goto exit;
++              }
+-      spi_qup_fifo_write(controller, xfer);
++              spi_qup_fifo_write(controller, xfer);
+-      if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+-              dev_warn(controller->dev, "cannot set EXECUTE state\n");
+-              goto exit;
+-      }
++              if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
++                      dev_warn(controller->dev, "cannot set EXECUTE state\n");
++                      goto exit;
++              }
+-      if (!wait_for_completion_timeout(&controller->done, timeout))
+-              ret = -ETIMEDOUT;
++              if (!wait_for_completion_timeout(&controller->done, timeout))
++                      ret = -ETIMEDOUT;
++      }
+ exit:
+       spi_qup_set_state(controller, QUP_STATE_RESET);
+       spin_lock_irqsave(&controller->lock, flags);
+@@ -553,6 +816,7 @@ static int spi_qup_probe(struct platform
+       master->transfer_one = spi_qup_transfer_one;
+       master->dev.of_node = pdev->dev.of_node;
+       master->auto_runtime_pm = true;
++      master->dma_alignment = dma_get_cache_alignment();
+       platform_set_drvdata(pdev, master);
+@@ -618,6 +882,56 @@ static int spi_qup_probe(struct platform
+                       QUP_ERROR_INPUT_UNDER_RUN | QUP_ERROR_OUTPUT_UNDER_RUN,
+                       base + QUP_ERROR_FLAGS_EN);
++      /* allocate dma resources, if available */
++      controller->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");
++      if (controller->rx_chan) {
++              controller->tx_chan =
++                      dma_request_slave_channel(&pdev->dev, "tx");
++
++              if (!controller->tx_chan) {
++                      dev_err(&pdev->dev, "Failed to allocate dma tx chan");
++                      dma_release_channel(controller->rx_chan);
++              }
++
++              /* set DMA parameters */
++              controller->rx_conf.device_fc = 1;
++              controller->rx_conf.src_addr = res->start + QUP_INPUT_FIFO;
++              controller->rx_conf.src_maxburst = controller->in_blk_sz;
++
++              controller->tx_conf.device_fc = 1;
++              controller->tx_conf.dst_addr = res->start + QUP_OUTPUT_FIFO;
++              controller->tx_conf.dst_maxburst = controller->out_blk_sz;
++
++              if (dmaengine_slave_config(controller->rx_chan,
++                              &controller->rx_conf)) {
++                      dev_err(&pdev->dev, "failed to configure RX channel\n");
++
++                      dma_release_channel(controller->rx_chan);
++                      dma_release_channel(controller->tx_chan);
++                      controller->tx_chan = NULL;
++                      controller->rx_chan = NULL;
++              } else if (dmaengine_slave_config(controller->tx_chan,
++                              &controller->tx_conf)) {
++                      dev_err(&pdev->dev, "failed to configure TX channel\n");
++
++                      dma_release_channel(controller->rx_chan);
++                      dma_release_channel(controller->tx_chan);
++                      controller->tx_chan = NULL;
++                      controller->rx_chan = NULL;
++              }
++
++              controller->dummy = devm_kmalloc(controller->dev, PAGE_SIZE,
++                      GFP_KERNEL);
++
++              if (!controller->dummy) {
++                      dma_release_channel(controller->rx_chan);
++                      dma_release_channel(controller->tx_chan);
++                      controller->tx_chan = NULL;
++                      controller->rx_chan = NULL;
++              }
++      }
++
++
+       writel_relaxed(0, base + SPI_CONFIG);
+       writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL);
+@@ -730,6 +1044,11 @@ static int spi_qup_remove(struct platfor
+       if (ret)
+               return ret;
++      if (controller->rx_chan)
++              dma_release_channel(controller->rx_chan);
++      if (controller->tx_chan)
++              dma_release_channel(controller->tx_chan);
++
+       clk_disable_unprepare(controller->cclk);
+       clk_disable_unprepare(controller->iclk);
diff --git a/target/linux/ipq806x/patches-4.0/002-v3-spi-qup-Fix-incorrect-block-transfers.patch b/target/linux/ipq806x/patches-4.0/002-v3-spi-qup-Fix-incorrect-block-transfers.patch
new file mode 100644 (file)
index 0000000..c8c6e4f
--- /dev/null
@@ -0,0 +1,376 @@
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v3] spi: qup: Fix incorrect block transfers
+From: Andy Gross <agross@codeaurora.org>
+X-Patchwork-Id: 5007321
+Message-Id: <1412112088-25928-1-git-send-email-agross@codeaurora.org>
+To: Mark Brown <broonie@kernel.org>
+Cc: linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org,
+       linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org,
+       "Ivan T. Ivanov" <iivanov@mm-sol.com>,
+       Bjorn Andersson <bjorn.andersson@sonymobile.com>,
+       Kumar Gala <galak@codeaurora.org>, Andy Gross <agross@codeaurora.org>
+Date: Tue, 30 Sep 2014 16:21:28 -0500
+
+This patch fixes a number of errors with the QUP block transfer mode.  Errors
+manifested themselves as input underruns, output overruns, and timed out
+transactions.
+
+The block mode does not require the priming that occurs in FIFO mode.  At the
+moment that the QUP is placed into the RUN state, the QUP will immediately raise
+an interrupt if the request is a write.  Therefore, there is no need to prime
+the pump.
+
+In addition, the block transfers require that whole blocks of data are
+read/written at a time.  The last block of data that completes a transaction may
+contain less than a full blocks worth of data.
+
+Each block of data results in an input/output service interrupt accompanied with
+a input/output block flag set.  Additional block reads/writes require clearing
+of the service flag.  It is ok to check for additional blocks of data in the
+ISR, but you have to ack every block you transfer.  Imbalanced acks result in
+early return from complete transactions with pending interrupts that still have
+to be ack'd.  The next transaction can be affected by these interrupts.
+Transactions are deemed complete when the MAX_INPUT or MAX_OUTPUT flag are set.
+
+Changes from v2:
+- Added in additional completion check so that transaction done is not
+  prematurely signaled.
+- Fixed various review comments.
+
+Changes from v1:
+- Split out read/write block function.
+- Removed extraneous checks for transfer length
+
+Signed-off-by: Andy Gross <agross@codeaurora.org>
+
+---
+drivers/spi/spi-qup.c |  201 ++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 148 insertions(+), 53 deletions(-)
+
+--- a/drivers/spi/spi-qup.c
++++ b/drivers/spi/spi-qup.c
+@@ -82,6 +82,8 @@
+ #define QUP_IO_M_MODE_BAM             3
+ /* QUP_OPERATIONAL fields */
++#define QUP_OP_IN_BLOCK_READ_REQ      BIT(13)
++#define QUP_OP_OUT_BLOCK_WRITE_REQ    BIT(12)
+ #define QUP_OP_MAX_INPUT_DONE_FLAG    BIT(11)
+ #define QUP_OP_MAX_OUTPUT_DONE_FLAG   BIT(10)
+ #define QUP_OP_IN_SERVICE_FLAG                BIT(9)
+@@ -147,6 +149,7 @@ struct spi_qup {
+       int                     tx_bytes;
+       int                     rx_bytes;
+       int                     qup_v1;
++      int                     mode;
+       int                     use_dma;
+@@ -213,30 +216,14 @@ static int spi_qup_set_state(struct spi_
+       return 0;
+ }
+-
+-static void spi_qup_fifo_read(struct spi_qup *controller,
+-                          struct spi_transfer *xfer)
++static void spi_qup_fill_read_buffer(struct spi_qup *controller,
++      struct spi_transfer *xfer, u32 data)
+ {
+       u8 *rx_buf = xfer->rx_buf;
+-      u32 word, state;
+-      int idx, shift, w_size;
+-
+-      w_size = controller->w_size;
+-
+-      while (controller->rx_bytes < xfer->len) {
+-
+-              state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+-              if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
+-                      break;
+-
+-              word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+-
+-              if (!rx_buf) {
+-                      controller->rx_bytes += w_size;
+-                      continue;
+-              }
++      int idx, shift;
+-              for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
++      if (rx_buf)
++              for (idx = 0; idx < controller->w_size; idx++) {
+                       /*
+                        * The data format depends on bytes per SPI word:
+                        *  4 bytes: 0x12345678
+@@ -244,41 +231,139 @@ static void spi_qup_fifo_read(struct spi
+                        *  1 byte : 0x00000012
+                        */
+                       shift = BITS_PER_BYTE;
+-                      shift *= (w_size - idx - 1);
+-                      rx_buf[controller->rx_bytes] = word >> shift;
++                      shift *= (controller->w_size - idx - 1);
++                      rx_buf[controller->rx_bytes + idx] = data >> shift;
++              }
++
++      controller->rx_bytes += controller->w_size;
++}
++
++static void spi_qup_prepare_write_data(struct spi_qup *controller,
++      struct spi_transfer *xfer, u32 *data)
++{
++      const u8 *tx_buf = xfer->tx_buf;
++      u32 val;
++      int idx;
++
++      *data = 0;
++
++      if (tx_buf)
++              for (idx = 0; idx < controller->w_size; idx++) {
++                      val = tx_buf[controller->tx_bytes + idx];
++                      *data |= val << (BITS_PER_BYTE * (3 - idx));
+               }
++
++      controller->tx_bytes += controller->w_size;
++}
++
++static void spi_qup_fifo_read(struct spi_qup *controller,
++                          struct spi_transfer *xfer)
++{
++      u32 data;
++
++      /* clear service request */
++      writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
++                      controller->base + QUP_OPERATIONAL);
++
++      while (controller->rx_bytes < xfer->len) {
++              if (!(readl_relaxed(controller->base + QUP_OPERATIONAL) &
++                  QUP_OP_IN_FIFO_NOT_EMPTY))
++                      break;
++
++              data = readl_relaxed(controller->base + QUP_INPUT_FIFO);
++
++              spi_qup_fill_read_buffer(controller, xfer, data);
+       }
+ }
+ static void spi_qup_fifo_write(struct spi_qup *controller,
+-                          struct spi_transfer *xfer)
++      struct spi_transfer *xfer)
+ {
+-      const u8 *tx_buf = xfer->tx_buf;
+-      u32 word, state, data;
+-      int idx, w_size;
++      u32 data;
+-      w_size = controller->w_size;
++      /* clear service request */
++      writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
++              controller->base + QUP_OPERATIONAL);
+       while (controller->tx_bytes < xfer->len) {
+-              state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+-              if (state & QUP_OP_OUT_FIFO_FULL)
++              if (readl_relaxed(controller->base + QUP_OPERATIONAL) &
++                              QUP_OP_OUT_FIFO_FULL)
+                       break;
+-              word = 0;
+-              for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
++              spi_qup_prepare_write_data(controller, xfer, &data);
++              writel_relaxed(data, controller->base + QUP_OUTPUT_FIFO);
+-                      if (!tx_buf) {
+-                              controller->tx_bytes += w_size;
+-                              break;
+-                      }
++      }
++}
+-                      data = tx_buf[controller->tx_bytes];
+-                      word |= data << (BITS_PER_BYTE * (3 - idx));
+-              }
++static void spi_qup_block_read(struct spi_qup *controller,
++      struct spi_transfer *xfer)
++{
++      u32 data;
++      u32 reads_per_blk = controller->in_blk_sz >> 2;
++      u32 num_words = (xfer->len - controller->rx_bytes) / controller->w_size;
++      int i;
++
++      do {
++              /* ACK by clearing service flag */
++              writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
++                      controller->base + QUP_OPERATIONAL);
++
++              /* transfer up to a block size of data in a single pass */
++              for (i = 0; num_words && i < reads_per_blk; i++, num_words--) {
++
++                      /* read data and fill up rx buffer */
++                      data = readl_relaxed(controller->base + QUP_INPUT_FIFO);
++                      spi_qup_fill_read_buffer(controller, xfer, data);
++              }
++
++              /* check to see if next block is ready */
++              if (!(readl_relaxed(controller->base + QUP_OPERATIONAL) &
++                      QUP_OP_IN_BLOCK_READ_REQ))
++                      break;
+-              writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
+-      }
++      } while (num_words);
++
++      /*
++       * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
++       * reads, it has to be cleared again at the very end
++       */
++      if (readl_relaxed(controller->base + QUP_OPERATIONAL) &
++              QUP_OP_MAX_INPUT_DONE_FLAG)
++              writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
++                      controller->base + QUP_OPERATIONAL);
++
++}
++
++static void spi_qup_block_write(struct spi_qup *controller,
++      struct spi_transfer *xfer)
++{
++      u32 data;
++      u32 writes_per_blk = controller->out_blk_sz >> 2;
++      u32 num_words = (xfer->len - controller->tx_bytes) / controller->w_size;
++      int i;
++
++      do {
++              /* ACK by clearing service flag */
++              writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
++                      controller->base + QUP_OPERATIONAL);
++
++              /* transfer up to a block size of data in a single pass */
++              for (i = 0; num_words && i < writes_per_blk; i++, num_words--) {
++
++                      /* swizzle the bytes for output and write out */
++                      spi_qup_prepare_write_data(controller, xfer, &data);
++                      writel_relaxed(data,
++                              controller->base + QUP_OUTPUT_FIFO);
++              }
++
++              /* check to see if next block is ready */
++              if (!(readl_relaxed(controller->base + QUP_OPERATIONAL) &
++                      QUP_OP_OUT_BLOCK_WRITE_REQ))
++                      break;
++
++      } while (num_words);
+ }
+ static void qup_dma_callback(void *data)
+@@ -515,9 +600,9 @@ static irqreturn_t spi_qup_qup_irq(int i
+       writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
+       writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
+-      writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
+       if (!xfer) {
++              writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
+               dev_err_ratelimited(controller->dev, "unexpected irq %08x %08x %08x\n",
+                                   qup_err, spi_err, opflags);
+               return IRQ_HANDLED;
+@@ -546,11 +631,19 @@ static irqreturn_t spi_qup_qup_irq(int i
+       }
+       if (!controller->use_dma) {
+-              if (opflags & QUP_OP_IN_SERVICE_FLAG)
+-                      spi_qup_fifo_read(controller, xfer);
++              if (opflags & QUP_OP_IN_SERVICE_FLAG) {
++                      if (opflags & QUP_OP_IN_BLOCK_READ_REQ)
++                              spi_qup_block_read(controller, xfer);
++                      else
++                              spi_qup_fifo_read(controller, xfer);
++              }
+-              if (opflags & QUP_OP_OUT_SERVICE_FLAG)
+-                      spi_qup_fifo_write(controller, xfer);
++              if (opflags & QUP_OP_OUT_SERVICE_FLAG) {
++                      if (opflags & QUP_OP_OUT_BLOCK_WRITE_REQ)
++                              spi_qup_block_write(controller, xfer);
++                      else
++                              spi_qup_fifo_write(controller, xfer);
++              }
+       }
+       spin_lock_irqsave(&controller->lock, flags);
+@@ -558,7 +651,8 @@ static irqreturn_t spi_qup_qup_irq(int i
+       controller->xfer = xfer;
+       spin_unlock_irqrestore(&controller->lock, flags);
+-      if (controller->rx_bytes == xfer->len || error)
++      if ((controller->rx_bytes == xfer->len &&
++              (opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) || error)
+               complete(&controller->done);
+       return IRQ_HANDLED;
+@@ -569,7 +663,7 @@ static irqreturn_t spi_qup_qup_irq(int i
+ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
+ {
+       struct spi_qup *controller = spi_master_get_devdata(spi->master);
+-      u32 config, iomode, mode, control;
++      u32 config, iomode, control;
+       int ret, n_words, w_size;
+       size_t dma_align = dma_get_cache_alignment();
+       u32 dma_available = 0;
+@@ -607,7 +701,7 @@ static int spi_qup_io_config(struct spi_
+               dma_available = 1;
+       if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
+-              mode = QUP_IO_M_MODE_FIFO;
++              controller->mode = QUP_IO_M_MODE_FIFO;
+               writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
+               writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
+               /* must be zero for FIFO */
+@@ -615,7 +709,7 @@ static int spi_qup_io_config(struct spi_
+               writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
+               controller->use_dma = 0;
+       } else if (!dma_available) {
+-              mode = QUP_IO_M_MODE_BLOCK;
++              controller->mode = QUP_IO_M_MODE_BLOCK;
+               writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+               writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+               /* must be zero for BLOCK and BAM */
+@@ -623,7 +717,7 @@ static int spi_qup_io_config(struct spi_
+               writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+               controller->use_dma = 0;
+       } else {
+-              mode = QUP_IO_M_MODE_DMOV;
++              controller->mode = QUP_IO_M_MODE_DMOV;
+               writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+               writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+               controller->use_dma = 1;
+@@ -638,8 +732,8 @@ static int spi_qup_io_config(struct spi_
+       else
+               iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
+-      iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+-      iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
++      iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
++      iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+       writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
+@@ -733,7 +827,8 @@ static int spi_qup_transfer_one(struct s
+                       goto exit;
+               }
+-              spi_qup_fifo_write(controller, xfer);
++              if (controller->mode == QUP_IO_M_MODE_FIFO)
++                      spi_qup_fifo_write(controller, xfer);
+               if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+                       dev_warn(controller->dev, "cannot set EXECUTE state\n");
+@@ -750,6 +845,7 @@ exit:
+       if (!ret)
+               ret = controller->error;
+       spin_unlock_irqrestore(&controller->lock, flags);
++
+       return ret;
+ }
diff --git a/target/linux/ipq806x/patches-4.0/003-spi-qup-Ensure-done-detection.patch b/target/linux/ipq806x/patches-4.0/003-spi-qup-Ensure-done-detection.patch
new file mode 100644 (file)
index 0000000..7052227
--- /dev/null
@@ -0,0 +1,56 @@
+From 4faba89e3ffbb1c5f6232651375b9b3212b50f02 Mon Sep 17 00:00:00 2001
+From: Andy Gross <agross@codeaurora.org>
+Date: Thu, 15 Jan 2015 17:56:02 -0800
+Subject: [PATCH] spi: qup: Ensure done detection
+
+This patch fixes an issue where a SPI transaction has completed, but the done
+condition is missed.  This occurs because at the time of interrupt the
+MAX_INPUT_DONE_FLAG is not asserted.  However, in the process of reading blocks
+of data from the FIFO, the last portion of data comes in.
+
+The opflags read at the beginning of the irq handler no longer matches the
+current opflag state.  To get around this condition, the block read function
+should update the opflags so that done detection is correct after the return.
+
+Change-Id: If109e0eeb432f96000d765c4b34dbb2269f8093f
+Signed-off-by: Andy Gross <agross@codeaurora.org>
+---
+ drivers/spi/spi-qup.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/drivers/spi/spi-qup.c
++++ b/drivers/spi/spi-qup.c
+@@ -298,7 +298,7 @@ static void spi_qup_fifo_write(struct sp
+ }
+ static void spi_qup_block_read(struct spi_qup *controller,
+-      struct spi_transfer *xfer)
++      struct spi_transfer *xfer, u32 *opflags)
+ {
+       u32 data;
+       u32 reads_per_blk = controller->in_blk_sz >> 2;
+@@ -327,10 +327,12 @@ static void spi_qup_block_read(struct sp
+       /*
+        * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
+-       * reads, it has to be cleared again at the very end
++       * reads, it has to be cleared again at the very end.  However, be sure
++       * to refresh opflags value because MAX_INPUT_DONE_FLAG may now be
++       * present and this is used to determine if transaction is complete
+        */
+-      if (readl_relaxed(controller->base + QUP_OPERATIONAL) &
+-              QUP_OP_MAX_INPUT_DONE_FLAG)
++      *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
++      if (*opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
+               writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+                       controller->base + QUP_OPERATIONAL);
+@@ -633,7 +635,7 @@ static irqreturn_t spi_qup_qup_irq(int i
+       if (!controller->use_dma) {
+               if (opflags & QUP_OP_IN_SERVICE_FLAG) {
+                       if (opflags & QUP_OP_IN_BLOCK_READ_REQ)
+-                              spi_qup_block_read(controller, xfer);
++                              spi_qup_block_read(controller, xfer, &opflags);
+                       else
+                               spi_qup_fifo_read(controller, xfer);
+               }
diff --git a/target/linux/ipq806x/patches-4.0/011-watchdog-qcom-use-timer-devicetree-binding.patch b/target/linux/ipq806x/patches-4.0/011-watchdog-qcom-use-timer-devicetree-binding.patch
new file mode 100644 (file)
index 0000000..0cd7da1
--- /dev/null
@@ -0,0 +1,72 @@
+From fded70251b1b58f68de1d3757ece9965f0b75452 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu@codeaurora.org>
+Date: Thu, 19 Feb 2015 20:19:30 -0800
+Subject: [PATCH 1/3] watchdog: qcom: use timer devicetree binding
+
+MSM watchdog configuration happens in the same register block as the
+timer, so we'll use the same binding as the existing timer.
+
+The qcom-wdt will now be probed when devicetree has an entry compatible
+with "qcom,kpss-timer" or "qcom-scss-timer".
+
+Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+---
+ drivers/watchdog/qcom-wdt.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c
+index aa85618..aa03ca8 100644
+--- a/drivers/watchdog/qcom-wdt.c
++++ b/drivers/watchdog/qcom-wdt.c
+@@ -20,9 +20,9 @@
+ #include <linux/reboot.h>
+ #include <linux/watchdog.h>
+-#define WDT_RST               0x0
+-#define WDT_EN                0x8
+-#define WDT_BITE_TIME 0x24
++#define WDT_RST               0x38
++#define WDT_EN                0x40
++#define WDT_BITE_TIME 0x5C
+ struct qcom_wdt {
+       struct watchdog_device  wdd;
+@@ -117,6 +117,8 @@ static int qcom_wdt_probe(struct platform_device *pdev)
+ {
+       struct qcom_wdt *wdt;
+       struct resource *res;
++      struct device_node *np = pdev->dev.of_node;
++      u32 percpu_offset;
+       int ret;
+       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+@@ -124,6 +126,14 @@ static int qcom_wdt_probe(struct platform_device *pdev)
+               return -ENOMEM;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++      /* We use CPU0's DGT for the watchdog */
++      if (of_property_read_u32(np, "cpu-offset", &percpu_offset))
++              percpu_offset = 0;
++
++      res->start += percpu_offset;
++      res->end += percpu_offset;
++
+       wdt->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(wdt->base))
+               return PTR_ERR(wdt->base);
+@@ -203,9 +213,8 @@ static int qcom_wdt_remove(struct platform_device *pdev)
+ }
+ static const struct of_device_id qcom_wdt_of_table[] = {
+-      { .compatible = "qcom,kpss-wdt-msm8960", },
+-      { .compatible = "qcom,kpss-wdt-apq8064", },
+-      { .compatible = "qcom,kpss-wdt-ipq8064", },
++      { .compatible = "qcom,kpss-timer" },
++      { .compatible = "qcom,scss-timer" },
+       { },
+ };
+ MODULE_DEVICE_TABLE(of, qcom_wdt_of_table);
+-- 
+1.9.1
+
diff --git a/target/linux/ipq806x/patches-4.0/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch b/target/linux/ipq806x/patches-4.0/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch
new file mode 100644 (file)
index 0000000..24a093a
--- /dev/null
@@ -0,0 +1,53 @@
+From 297cf8136ecd6a56520888fd28948393766b8ee7 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu@codeaurora.org>
+Date: Thu, 19 Feb 2015 20:27:39 -0800
+Subject: [PATCH 2/3] ARM: qcom: add description of KPSS WDT for IPQ8064
+
+Add the watchdog related entries to the Krait Processor Sub-system
+(KPSS) timer IPQ8064 devicetree section. Also, add a fixed-clock
+description of SLEEP_CLK, which will do for now.
+
+Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
+Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+---
+ arch/arm/boot/dts/qcom-ipq8064.dtsi | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi
+index cb225da..d01f618 100644
+--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
+@@ -60,6 +60,14 @@
+               };
+       };
++      clocks {
++              sleep_clk: sleep_clk {
++                      compatible = "fixed-clock";
++                      clock-frequency = <32768>;
++                      #clock-cells = <0>;
++              };
++      };
++
+       soc: soc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+@@ -89,10 +97,14 @@
+                       compatible = "qcom,kpss-timer", "qcom,msm-timer";
+                       interrupts = <1 1 0x301>,
+                                    <1 2 0x301>,
+-                                   <1 3 0x301>;
++                                   <1 3 0x301>,
++                                   <1 4 0x301>,
++                                   <1 5 0x301>;
+                       reg = <0x0200a000 0x100>;
+                       clock-frequency = <25000000>,
+                                         <32768>;
++                      clocks = <&sleep_clk>;
++                      clock-names = "sleep";
+                       cpu-offset = <0x80000>;
+               };
+-- 
+1.9.1
+
diff --git a/target/linux/ipq806x/patches-4.0/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch b/target/linux/ipq806x/patches-4.0/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch
new file mode 100644 (file)
index 0000000..e775f12
--- /dev/null
@@ -0,0 +1,50 @@
+From e535f01dffb6dd9e09934fa219be52af3437a8f6 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu@codeaurora.org>
+Date: Thu, 19 Feb 2015 20:36:27 -0800
+Subject: [PATCH 3/3] ARM: msm: add watchdog entries to DT timer binding doc
+
+The watchdog has been reworked to use the same DT node as the timer.
+This change is updating the device tree doc accordingly.
+
+Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+---
+ Documentation/devicetree/bindings/arm/msm/timer.txt | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+--- a/Documentation/devicetree/bindings/arm/msm/timer.txt
++++ b/Documentation/devicetree/bindings/arm/msm/timer.txt
+@@ -9,11 +9,17 @@ Properties:
+                "qcom,scss-timer" - scorpion subsystem
+ - interrupts : Interrupts for the debug timer, the first general purpose
+-               timer, and optionally a second general purpose timer in that
+-               order.
++               timer, and optionally a second general purpose timer, and
++               optionally as well, 2 watchdog interrupts, in that order.
+ - reg : Specifies the base address of the timer registers.
++- clocks: Reference to the parent clocks, one per output clock. The parents
++          must appear in the same order as the clock names.
++
++- clock-names: The name of the clocks as free-form strings. They should be in
++               the same order as the clocks.
++
+ - clock-frequency : The frequency of the debug timer and the general purpose
+                     timer(s) in Hz in that order.
+@@ -29,9 +35,13 @@ Example:
+                compatible = "qcom,scss-timer", "qcom,msm-timer";
+                interrupts = <1 1 0x301>,
+                             <1 2 0x301>,
+-                            <1 3 0x301>;
++                            <1 3 0x301>,
++                            <1 4 0x301>,
++                            <1 5 0x301>;
+                reg = <0x0200a000 0x100>;
+                clock-frequency = <19200000>,
+                                  <32768>;
++               clocks = <&sleep_clk>;
++               clock-names = "sleep";
+                cpu-offset = <0x40000>;
+        };
diff --git a/target/linux/ipq806x/patches-4.0/020-add-ap148-bootargs.patch b/target/linux/ipq806x/patches-4.0/020-add-ap148-bootargs.patch
new file mode 100644 (file)
index 0000000..a61481e
--- /dev/null
@@ -0,0 +1,46 @@
+--- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
++++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
+@@ -14,6 +14,14 @@
+               };
+       };
++      alias {
++              serial0 = &uart4;
++      };
++
++      chosen {
++              linux,stdout-path = "serial0:115200n8";
++      };
++
+       soc {
+               pinmux@800000 {
+                       i2c4_pins: i2c4_pinmux {
+--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
+@@ -140,7 +140,7 @@
+                       ranges;
+                       status = "disabled";
+-                      serial@12490000 {
++                      uart2: serial@12490000 {
+                               compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+                               reg = <0x12490000 0x1000>,
+                                     <0x12480000 0x1000>;
+@@ -175,7 +175,7 @@
+                       ranges;
+                       status = "disabled";
+-                      serial@16340000 {
++                      uart4: serial@16340000 {
+                               compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+                               reg = <0x16340000 0x1000>,
+                                     <0x16300000 0x1000>;
+@@ -209,7 +209,7 @@
+                       ranges;
+                       status = "disabled";
+-                      serial@1a240000 {
++                      uart5: serial@1a240000 {
+                               compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+                               reg = <0x1a240000 0x1000>,
+                                     <0x1a200000 0x1000>;
diff --git a/target/linux/ipq806x/patches-4.0/021-add-ap148-partitions.patch b/target/linux/ipq806x/patches-4.0/021-add-ap148-partitions.patch
new file mode 100644 (file)
index 0000000..34eb9c0
--- /dev/null
@@ -0,0 +1,35 @@
+--- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
++++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
+@@ -78,13 +78,28 @@
+                                       reg = <0>;
+                                       partition@0 {
+-                                              label = "rootfs";
+-                                              reg = <0x0 0x1000000>;
++                                              label = "lowlevel_init";
++                                              reg = <0x0 0x1b0000>;
+                                       };
+                                       partition@1 {
+-                                              label = "scratch";
+-                                              reg = <0x1000000 0x1000000>;
++                                              label = "u-boot";
++                                              reg = <0x1b0000 0x80000>;
++                                      };
++
++                                      partition@2 {
++                                              label = "u-boot-env";
++                                              reg = <0x230000 0x40000>;
++                                      };
++
++                                      partition@3 {
++                                              label = "caldata";
++                                              reg = <0x270000 0x40000>;
++                                      };
++
++                                      partition@4 {
++                                              label = "firmware";
++                                              reg = <0x2b0000 0x1d50000>;
+                                       };
+                               };
+                       };
diff --git a/target/linux/ipq806x/patches-4.0/700-add-gmac-dts-suport.patch b/target/linux/ipq806x/patches-4.0/700-add-gmac-dts-suport.patch
new file mode 100644 (file)
index 0000000..89ebe66
--- /dev/null
@@ -0,0 +1,172 @@
+--- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
++++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
+@@ -18,8 +18,15 @@
+               bootargs = "console=ttyMSM0,115200 root=/dev/mtdblock12 rootfstype=squashfs,jffs2";
+       };
++      aliases {
++              mdio-gpio0 = &mdio0;
++      };
++
+       soc {
+               pinmux@800000 {
++                      pinctrl-0 = <&mdio0_pins &rgmii2_pins>;
++                      pinctrl-names = "default";
++
+                       i2c4_pins: i2c4_pinmux {
+                               pins = "gpio12", "gpio13";
+                               function = "gsbi4";
+@@ -34,6 +41,25 @@
+                                       bias-none;
+                               };
+                       };
++
++                      mdio0_pins: mdio0_pins {
++                              mux {
++                                      pins = "gpio0", "gpio1";
++                                      function = "gpio";
++                                      drive-strength = <8>;
++                                      bias-disable;
++                              };
++                      };
++
++                      rgmii2_pins: rgmii2_pins {
++                              mux {
++                                      pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
++                                             "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
++                                      function = "rgmii2";
++                                      drive-strength = <8>;
++                                      bias-disable;
++                              };
++                      };
+               };
+               gsbi@16300000 {
+@@ -72,6 +98,7 @@
+                                       #size-cells = <1>;
+                                       spi-max-frequency = <50000000>;
+                                       reg = <0>;
++                                      m25p,fast-read;
+                                       partition@0 {
+                                               label = "0:SBL1";
+@@ -148,5 +175,66 @@
+               sata@29000000 {
+                       status = "ok";
+               };
++
++              mdio0: mdio {
++                      compatible = "virtual,mdio-gpio";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>;
++
++                      phy0: ethernet-phy@0 {
++                              device_type = "ethernet-phy";
++                              reg = <0>;
++                              qca,ar8327-initvals = <
++                                      0x00004 0x7600000   /* PAD0_MODE */
++                                      0x00008 0x1000000   /* PAD5_MODE */
++                                      0x0000c 0x80        /* PAD6_MODE */
++                                      0x000e4 0xaa545     /* MAC_POWER_SEL */
++                                      0x000e0 0xc74164de  /* SGMII_CTRL */
++                                      0x0007c 0x4e        /* PORT0_STATUS */
++                                      0x00094 0x4e        /* PORT6_STATUS */
++                              >;
++                      };
++
++                      phy4: ethernet-phy@4 {
++                              device_type = "ethernet-phy";
++                              reg = <4>;
++                      };
++              };
++
++              nss-gmac-common {
++                      reg = <0x03000000 0x0000FFFF 0x1bb00000 0x0000FFFF 0x00900000 0x00004000>;
++                      reg-names = "nss_reg_base" , "qsgmii_reg_base", "clk_ctl_base";
++              };
++
++              gmac1: ethernet@37200000 {
++                      status = "ok";
++                      phy-mode = "rgmii";
++                      qcom,id = <1>;
++                      qcom,phy_mdio_addr = <4>;
++                      qcom,poll_required = <1>;
++                      qcom,rgmii_delay = <0>;
++                      qcom,emulation = <0>;
++                      qcom,forced_speed = <1000>;
++                      qcom,forced_duplex = <1>;
++                      qcom,socver = <0>;
++                      local-mac-address = [000000000000];
++                      mdiobus = <&mdio0>;
++              };
++
++              gmac2: ethernet@37400000 {
++                      status = "ok";
++                      phy-mode = "sgmii";
++                      qcom,id = <2>;
++                      qcom,phy_mdio_addr = <0>;
++                      qcom,poll_required = <0>;
++                      qcom,rgmii_delay = <0>;
++                      qcom,emulation = <0>;
++                      qcom,forced_speed = <1000>;
++                      qcom,forced_duplex = <1>;
++                      qcom,socver = <0>;
++                      local-mac-address = [000000000000];
++                      mdiobus = <&mdio0>;
++              };
+       };
+ };
+--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
+@@ -3,6 +3,7 @@
+ #include "skeleton.dtsi"
+ #include <dt-bindings/clock/qcom,gcc-ipq806x.h>
+ #include <dt-bindings/soc/qcom,gsbi.h>
++#include <dt-bindings/interrupt-controller/arm-gic.h>
+ / {
+       model = "Qualcomm IPQ8064";
+@@ -279,5 +280,42 @@
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+               };
++
++              nss-gmac-common {
++                      reg = <0x03000000 0x0000FFFF 0x1bb00000 0x0000FFFF 0x00900000 0x00004000>;
++                      reg-names = "nss_reg_base" , "qsgmii_reg_base", "clk_ctl_base";
++              };
++
++              gmac0: ethernet@37000000 {
++                      device_type = "network";
++                      compatible = "qcom,nss-gmac";
++                      reg = <0x37000000 0x200000>;
++                      interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              gmac1: ethernet@37200000 {
++                      device_type = "network";
++                      compatible = "qcom,nss-gmac";
++                      reg = <0x37200000 0x200000>;
++                      interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              gmac2: ethernet@37400000 {
++                      device_type = "network";
++                      compatible = "qcom,nss-gmac";
++                      reg = <0x37400000 0x200000>;
++                      interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              gmac3: ethernet@37600000 {
++                      device_type = "network";
++                      compatible = "qcom,nss-gmac";
++                      reg = <0x37600000 0x200000>;
++                      interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
+       };
+ };