ipq806x: add support for 4.0 kernel
Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org> SVN-Revision: 45210
This commit is contained in:
parent
2d74104b52
commit
d3a9fc4586
10 changed files with 1771 additions and 0 deletions
389
target/linux/ipq806x/config-4.0
Normal file
389
target/linux/ipq806x/config-4.0
Normal file
|
@ -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
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
172
target/linux/ipq806x/patches-4.0/700-add-gmac-dts-suport.patch
Normal file
172
target/linux/ipq806x/patches-4.0/700-add-gmac-dts-suport.patch
Normal file
|
@ -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";
|
||||
+ };
|
||||
};
|
||||
};
|
Loading…
Reference in a new issue