From b8df41f8032016fd91da40dd1aa4a06d38e569be Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 18 May 2016 00:12:26 +0200 Subject: [PATCH 01/37] ar7: update to v4.4 Signed-off-by: John Crispin --- .../patches-D7.04.03.00/250-4.1_fixes.patch | 20 -- .../250-compile_fixes.patch | 236 ++++++++++++++ target/linux/ar7/Makefile | 2 +- target/linux/ar7/config-3.18 | 130 -------- target/linux/ar7/{config-4.1 => config-4.4} | 20 +- .../linux/ar7/files/drivers/char/ar7_gpio.c | 6 +- .../001-mips-ar7-fix-serial.patch | 23 -- .../ar7/patches-3.18/120-gpio_chrdev.patch | 28 -- .../patches-3.18/300-add-ac49x-platform.patch | 85 ----- .../320-ac49x-mtd-partitions.patch | 35 -- .../ar7/patches-3.18/500-serial_kludge.patch | 28 -- .../ar7/patches-3.18/925-actiontec_leds.patch | 95 ------ .../patches-4.1/100-fix-highmem-offset.patch | 11 - target/linux/ar7/patches-4.1/110-flash.patch | 22 -- .../160-vlynq_try_remote_first.patch | 300 ------------------ .../200-free-mem-below-kernel-offset.patch | 15 - .../patches-4.1/310-ac49x-prom-support.patch | 20 -- .../ar7/patches-4.1/500-serial_kludge.patch | 28 -- .../linux/ar7/patches-4.1/920-ar7part.patch | 118 ------- .../ar7/patches-4.1/950-cpmac_titan.patch | 52 --- .../001-mips-ar7-fix-serial.patch | 0 .../100-fix-highmem-offset.patch | 0 .../110-flash.patch | 0 .../120-gpio_chrdev.patch | 0 .../160-vlynq_try_remote_first.patch | 0 .../200-free-mem-below-kernel-offset.patch | 0 .../300-add-ac49x-platform.patch | 0 .../310-ac49x-prom-support.patch | 0 .../320-ac49x-mtd-partitions.patch | 0 .../ar7/patches-4.4/500-serial_kludge.patch | 14 + .../920-ar7part.patch | 0 .../925-actiontec_leds.patch | 0 .../950-cpmac_titan.patch | 0 33 files changed, 270 insertions(+), 1018 deletions(-) delete mode 100644 package/kernel/ar7-atm/patches-D7.04.03.00/250-4.1_fixes.patch create mode 100644 package/kernel/ar7-atm/patches-D7.04.03.00/250-compile_fixes.patch delete mode 100644 target/linux/ar7/config-3.18 rename target/linux/ar7/{config-4.1 => config-4.4} (90%) delete mode 100644 target/linux/ar7/patches-3.18/001-mips-ar7-fix-serial.patch delete mode 100644 target/linux/ar7/patches-3.18/120-gpio_chrdev.patch delete mode 100644 target/linux/ar7/patches-3.18/300-add-ac49x-platform.patch delete mode 100644 target/linux/ar7/patches-3.18/320-ac49x-mtd-partitions.patch delete mode 100644 target/linux/ar7/patches-3.18/500-serial_kludge.patch delete mode 100644 target/linux/ar7/patches-3.18/925-actiontec_leds.patch delete mode 100644 target/linux/ar7/patches-4.1/100-fix-highmem-offset.patch delete mode 100644 target/linux/ar7/patches-4.1/110-flash.patch delete mode 100644 target/linux/ar7/patches-4.1/160-vlynq_try_remote_first.patch delete mode 100644 target/linux/ar7/patches-4.1/200-free-mem-below-kernel-offset.patch delete mode 100644 target/linux/ar7/patches-4.1/310-ac49x-prom-support.patch delete mode 100644 target/linux/ar7/patches-4.1/500-serial_kludge.patch delete mode 100644 target/linux/ar7/patches-4.1/920-ar7part.patch delete mode 100644 target/linux/ar7/patches-4.1/950-cpmac_titan.patch rename target/linux/ar7/{patches-4.1 => patches-4.4}/001-mips-ar7-fix-serial.patch (100%) rename target/linux/ar7/{patches-3.18 => patches-4.4}/100-fix-highmem-offset.patch (100%) rename target/linux/ar7/{patches-3.18 => patches-4.4}/110-flash.patch (100%) rename target/linux/ar7/{patches-4.1 => patches-4.4}/120-gpio_chrdev.patch (100%) rename target/linux/ar7/{patches-3.18 => patches-4.4}/160-vlynq_try_remote_first.patch (100%) rename target/linux/ar7/{patches-3.18 => patches-4.4}/200-free-mem-below-kernel-offset.patch (100%) rename target/linux/ar7/{patches-4.1 => patches-4.4}/300-add-ac49x-platform.patch (100%) rename target/linux/ar7/{patches-3.18 => patches-4.4}/310-ac49x-prom-support.patch (100%) rename target/linux/ar7/{patches-4.1 => patches-4.4}/320-ac49x-mtd-partitions.patch (100%) create mode 100644 target/linux/ar7/patches-4.4/500-serial_kludge.patch rename target/linux/ar7/{patches-3.18 => patches-4.4}/920-ar7part.patch (100%) rename target/linux/ar7/{patches-4.1 => patches-4.4}/925-actiontec_leds.patch (100%) rename target/linux/ar7/{patches-3.18 => patches-4.4}/950-cpmac_titan.patch (100%) diff --git a/package/kernel/ar7-atm/patches-D7.04.03.00/250-4.1_fixes.patch b/package/kernel/ar7-atm/patches-D7.04.03.00/250-4.1_fixes.patch deleted file mode 100644 index 97a26cb417f3..000000000000 --- a/package/kernel/ar7-atm/patches-D7.04.03.00/250-4.1_fixes.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/tn7atm.c -+++ b/tn7atm.c -@@ -788,7 +788,7 @@ static int __init tn7atm_irq_request (st - * Register SAR interrupt - */ - priv->sar_irq = LNXINTNUM (ATM_SAR_INT); /* Interrupt line # */ -- if (request_irq (priv->sar_irq, tn7atm_sar_irq, IRQF_DISABLED, "SAR ", dev)) -+ if (request_irq (priv->sar_irq, tn7atm_sar_irq, 0, "SAR ", dev)) - printk ("Could not register tn7atm_sar_irq\n"); - - /* -@@ -806,7 +806,7 @@ static int __init tn7atm_irq_request (st - * Reigster Receive interrupt A - */ - priv->dsl_irq = LNXINTNUM (ATM_DSL_INT); /* Interrupt line # */ -- if (request_irq (priv->dsl_irq, tn7atm_dsl_irq, IRQF_DISABLED, "DSL ", dev)) -+ if (request_irq (priv->dsl_irq, tn7atm_dsl_irq, 0, "DSL ", dev)) - printk ("Could not register tn7atm_dsl_irq\n"); - - /***** VRB Tasklet Mode ****/ diff --git a/package/kernel/ar7-atm/patches-D7.04.03.00/250-compile_fixes.patch b/package/kernel/ar7-atm/patches-D7.04.03.00/250-compile_fixes.patch new file mode 100644 index 000000000000..6f72677df8b1 --- /dev/null +++ b/package/kernel/ar7-atm/patches-D7.04.03.00/250-compile_fixes.patch @@ -0,0 +1,236 @@ +--- a/tn7atm.c ++++ b/tn7atm.c +@@ -788,7 +788,7 @@ + * Register SAR interrupt + */ + priv->sar_irq = LNXINTNUM (ATM_SAR_INT); /* Interrupt line # */ +- if (request_irq (priv->sar_irq, tn7atm_sar_irq, IRQF_DISABLED, "SAR ", dev)) ++ if (request_irq (priv->sar_irq, tn7atm_sar_irq, 0, "SAR ", dev)) + printk ("Could not register tn7atm_sar_irq\n"); + + /* +@@ -806,7 +806,7 @@ + * Reigster Receive interrupt A + */ + priv->dsl_irq = LNXINTNUM (ATM_DSL_INT); /* Interrupt line # */ +- if (request_irq (priv->dsl_irq, tn7atm_dsl_irq, IRQF_DISABLED, "DSL ", dev)) ++ if (request_irq (priv->dsl_irq, tn7atm_dsl_irq, 0, "DSL ", dev)) + printk ("Could not register tn7atm_dsl_irq\n"); + + /***** VRB Tasklet Mode ****/ +@@ -1160,7 +1160,7 @@ + Tn7AtmPrivate *priv; + int dmachan; + spinlock_t closeLock; +- unsigned int closeFlag; ++ unsigned long closeFlag; + int rc; + + priv = (Tn7AtmPrivate *) vcc->dev->dev_data; +--- a/tn7sar.c ++++ b/tn7sar.c +@@ -1214,7 +1214,7 @@ + HAL_FUNCTIONS *pHalFunc; + HAL_DEVICE *pHalDev; + int rc; +- int flags; ++ unsigned long flags; + + //dgprintf(4, "tn7sar_deactivate_vc\n"); + //printk("tn7sar_deactivate_vc entered\n"); +@@ -1467,7 +1467,7 @@ + { + struct atm_dev *dev; + Tn7AtmPrivate *priv; +- int i, j, k; ++ int i, j; + int stat_len; + char statString[32]; + unsigned int *pStateBase, *pSarStat; +@@ -1486,7 +1486,6 @@ + if(priv->lut[i].inuse) + { + seq_printf(m, "\nChannel %d:\n",priv->lut[i].chanid); +- k=0; + for(j=0;j<4;j++) + { + stat_len =sprintf(statString, "Stats;%d;%d", j,priv->lut[i].chanid); +@@ -1499,16 +1498,11 @@ + if((char *)*pSarStat == NULL) + break; + +- k += seq_printf(m, "%s: ",(char *) *pSarStat); ++ seq_printf(m, "%s: ",(char *) *pSarStat); + pSarStat++; +- k += seq_printf(m, "%s; \n",(char *) *pSarStat); ++ seq_printf(m, "%s; \n",(char *) *pSarStat); + pSarStat++; + +- if(k > 60) +- { +- k=0; +- seq_printf(m, "\n"); +- } + } + + kfree(pStateBase); +--- a/cpswhal_cpaal5.h ++++ b/cpswhal_cpaal5.h +@@ -430,10 +430,10 @@ + int (*DeviceFindInfo)(int Inst, const char *DeviceName, void *DeviceInfo); + int (*DeviceFindParmUint)(void *DeviceInfo, const char *Parm, bit32u *Value); + int (*DeviceFindParmValue)(void *DeviceInfo, const char *Parm, void *Value); +- void (*Free)(void *MemPtr); ++ void (*Free)(const void *MemPtr); + void (*FreeRxBuffer)(OS_RECEIVEINFO *OsReceiveInfo, void *MemPtr); +- void (*FreeDev)(void *MemPtr); +- void (*FreeDmaXfer)(void *MemPtr); ++ void (*FreeDev)(const void *MemPtr); ++ void (*FreeDmaXfer)(const void *MemPtr); + void (*IsrRegister)(OS_DEVICE *OsDev, int (*halISR)(HAL_DEVICE*, int*), int InterruptBit); + void (*IsrUnRegister)(OS_DEVICE *OsDev, int InterruptBit); + void* (*Malloc)(bit32u size); +--- a/cpswhal_cpsar.h ++++ b/cpswhal_cpsar.h +@@ -430,10 +430,10 @@ + int (*DeviceFindInfo)(int Inst, const char *DeviceName, void *DeviceInfo); + int (*DeviceFindParmUint)(void *DeviceInfo, const char *Parm, bit32u *Value); + int (*DeviceFindParmValue)(void *DeviceInfo, const char *Parm, void *Value); +- void (*Free)(void *MemPtr); ++ void (*Free)(const void *MemPtr); + void (*FreeRxBuffer)(OS_RECEIVEINFO *OsReceiveInfo, void *MemPtr); +- void (*FreeDev)(void *MemPtr); +- void (*FreeDmaXfer)(void *MemPtr); ++ void (*FreeDev)(const void *MemPtr); ++ void (*FreeDmaXfer)(const void *MemPtr); + void (*IsrRegister)(OS_DEVICE *OsDev, int (*halISR)(HAL_DEVICE*, int*), int InterruptBit); + void (*IsrUnRegister)(OS_DEVICE *OsDev, int InterruptBit); + void* (*Malloc)(bit32u size); +--- a/tn7dsl.c ++++ b/tn7dsl.c +@@ -637,7 +637,7 @@ + return jiffies; + } + +-int flags; ++unsigned long flags; + spinlock_t shimLock; + + void shim_osCriticalEnter(void) +--- a/dsl_hal_support.c ++++ b/dsl_hal_support.c +@@ -1665,7 +1665,7 @@ + unsigned char * image; + char *tmp = (char *)DEV_HOST_DSP_OAM_POINTER_LOCATION; + DEV_HOST_dspVersionDef_t dspVersion; +-#if SWTC ++#ifdef SWTC + DEV_HOST_tcHostCommDef_t TCHostCommDef; + #endif + DEV_HOST_oamWrNegoParaDef_t OamWrNegoParaDef; +@@ -1675,7 +1675,7 @@ + #ifndef NO_ACT + DEV_HOST_consBufDef_t constDisp; + #endif +-#if CO_PROFILES ++#ifdef CO_PROFILES + DEV_HOST_coData_t coData; + #endif + DEV_HOST_olayDpPageDef_t olayDpPageDef[32]; +@@ -2152,7 +2152,7 @@ + } + + /* table_dsp info */ +-#if SWTC ++#ifdef SWTC + dspOamSharedInterface.tcHostComm_p = (DEV_HOST_tcHostCommDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.tcHostComm_p); + rc = dslhal_support_blockRead(&pdspOamSharedInterface->tcHostComm_p, + &pTCHostCommDef, 4); +@@ -2252,7 +2252,7 @@ + } + + /* Co Profile Test */ +-#if CO_PROFILES ++#ifdef CO_PROFILES + dspOamSharedInterface.profileList_p = (DEV_HOST_profileBase_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.profileList_p); + /* Access the profileList Structure */ + rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.profileList_p,&profileList, sizeof(DEV_HOST_profileBase_t)); +--- a/dsl_hal_api.c ++++ b/dsl_hal_api.c +@@ -958,7 +958,7 @@ + + /*char *tmp;*/ + DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface; +-#if SWTC ++#ifdef SWTC + DEV_HOST_tcHostCommDef_t TCHostCommDef; + #endif + +@@ -971,7 +971,7 @@ + dgprintf(1,"dslhal_support_blockRead failed\n"); + return DSLHAL_ERROR_BLOCK_READ; + } +-#if SWTC ++#ifdef SWTC + dspOamSharedInterface.tcHostComm_p =(DEV_HOST_tcHostCommDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.tcHostComm_p); + + rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.tcHostComm_p, +@@ -1025,7 +1025,7 @@ + + /*char *tmp;*/ + DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface; +-#if SWTC ++#ifdef SWTC + DEV_HOST_tcHostCommDef_t TCHostCommDef; + #endif + dgprintf(6,"dslhal_api_handleTrainingInterrupt\n"); +@@ -1037,7 +1037,7 @@ + dgprintf(1,"dslhal_support_blockRead failed\n"); + return DSLHAL_ERROR_BLOCK_READ; + } +-#if SWTC ++#ifdef SWTC + dspOamSharedInterface.tcHostComm_p =(DEV_HOST_tcHostCommDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.tcHostComm_p); + + rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.tcHostComm_p, +@@ -1705,12 +1705,12 @@ + /* Get ATM Stats for both US and DS for Channel 0*/ + ptidsl->AppData.usAtm_count[0] = dslhal_support_byteSwap32(usAtmStats0.goodCount); + ptidsl->AppData.usIdle_count[0] = dslhal_support_byteSwap32(usAtmStats0.idleCount); +-#if SWTC ++#ifdef SWTC + ptidsl->AppData.usPdu_count[0] = dslhal_support_byteSwap32(usAtmStats0.pduCount); + #endif + ptidsl->AppData.dsGood_count[0] = dslhal_support_byteSwap32(dsAtmStats0.goodCount); + ptidsl->AppData.dsIdle_count[0] = dslhal_support_byteSwap32(dsAtmStats0.idleCount); +-#if SWTC ++#ifdef SWTC + ptidsl->AppData.dsPdu_count[0] = dslhal_support_byteSwap32(dsAtmStats0.pduCount); + #endif + ptidsl->AppData.dsBadHec_count[0] = dslhal_support_byteSwap32((dsAtmStats0.badHecCount)); +@@ -1718,12 +1718,12 @@ + /* Get ATM Stats for both US and DS for Channel 1*/ + ptidsl->AppData.usAtm_count[1] = dslhal_support_byteSwap32(usAtmStats1.goodCount); + ptidsl->AppData.usIdle_count[1] = dslhal_support_byteSwap32(usAtmStats1.idleCount); +-#if SWTC ++#ifdef SWTC + ptidsl->AppData.usPdu_count[1] = dslhal_support_byteSwap32(usAtmStats1.pduCount); + #endif + ptidsl->AppData.dsGood_count[1] = dslhal_support_byteSwap32(dsAtmStats1.goodCount); + ptidsl->AppData.dsIdle_count[1] = dslhal_support_byteSwap32(dsAtmStats1.idleCount); +-#if SWTC ++#ifdef SWTC + ptidsl->AppData.dsPdu_count[1] = dslhal_support_byteSwap32(dsAtmStats1.pduCount); + #endif + ptidsl->AppData.dsBadHec_count[1] = dslhal_support_byteSwap32((dsAtmStats1.badHecCount)); +--- a/dev_host_interface.h ++++ b/dev_host_interface.h +@@ -1288,7 +1288,7 @@ + + SINT16 devCodecRxdf4Coeff[12] ; // (BOTH) IIR Coefficients + SINT16 devCodecTxdf2aCoeff[64] ; // (BOTH) FIR filter coefficients +-#if OHIO_SUPPORT ++#ifdef OHIO_SUPPORT + SINT16 devCodecTxdf2bCoeff[84] ; // (BOTH) FIR filter coefficients + #else + SINT16 devCodecTxdf2bCoeff[64] ; // (BOTH) FIR filter coefficients diff --git a/target/linux/ar7/Makefile b/target/linux/ar7/Makefile index 1832e7b5e077..a9ea3103140a 100644 --- a/target/linux/ar7/Makefile +++ b/target/linux/ar7/Makefile @@ -13,7 +13,7 @@ FEATURES:=squashfs atm low_mem MAINTAINER:=Florian Fainelli SUBTARGETS:=generic ac49x -KERNEL_PATCHVER:=3.18 +KERNEL_PATCHVER:=4.4 include $(INCLUDE_DIR)/target.mk diff --git a/target/linux/ar7/config-3.18 b/target/linux/ar7/config-3.18 deleted file mode 100644 index 21c86db65f97..000000000000 --- a/target/linux/ar7/config-3.18 +++ /dev/null @@ -1,130 +0,0 @@ -CONFIG_ADM6996_PHY=y -CONFIG_AR7=y -CONFIG_AR7_GPIO=y -CONFIG_AR7_TI=y -# CONFIG_AR7_TYPE_AC49X is not set -CONFIG_AR7_TYPE_TI=y -CONFIG_AR7_WDT=y -CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y -CONFIG_ARCH_DISCARD_MEMBLOCK=y -CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y -CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y -CONFIG_ARCH_HIBERNATION_POSSIBLE=y -CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y -CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y -CONFIG_ARCH_REQUIRE_GPIOLIB=y -CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y -CONFIG_BOOT_ELF32=y -CONFIG_CEVT_R4K=y -CONFIG_CLONE_BACKWARDS=y -CONFIG_CMDLINE="rootfstype=squashfs,jffs2" -CONFIG_CMDLINE_BOOL=y -# CONFIG_CMDLINE_OVERRIDE is not set -CONFIG_CPMAC=y -CONFIG_CPU_GENERIC_DUMP_TLB=y -CONFIG_CPU_HAS_PREFETCH=y -CONFIG_CPU_HAS_SYNC=y -CONFIG_CPU_LITTLE_ENDIAN=y -CONFIG_CPU_MIPS32=y -CONFIG_CPU_MIPS32_R1=y -CONFIG_CPU_MIPSR1=y -CONFIG_CPU_R4K_CACHE_TLB=y -CONFIG_CPU_R4K_FPU=y -CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_HIGHMEM=y -CONFIG_CSRC_R4K=y -CONFIG_DMA_NONCOHERENT=y -CONFIG_EARLY_PRINTK=y -CONFIG_ETHERNET_PACKET_MANGLE=y -CONFIG_FIXED_PHY=y -CONFIG_GENERIC_ATOMIC64=y -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -CONFIG_GENERIC_CMOS_UPDATE=y -CONFIG_GENERIC_IO=y -CONFIG_GENERIC_IRQ_SHOW=y -CONFIG_GENERIC_PCI_IOMAP=y -CONFIG_GENERIC_SMP_IDLE_THREAD=y -CONFIG_GPIOLIB=y -CONFIG_GPIO_DEVRES=y -CONFIG_HARDWARE_WATCHPOINTS=y -CONFIG_HAS_DMA=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y -# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set -CONFIG_HAVE_CC_STACKPROTECTOR=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_CONTEXT_TRACKING=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DEBUG_KMEMLEAK=y -CONFIG_HAVE_DEBUG_STACKOVERFLOW=y -CONFIG_HAVE_DMA_API_DEBUG=y -CONFIG_HAVE_DMA_ATTRS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y -CONFIG_HAVE_GENERIC_DMA_COHERENT=y -CONFIG_HAVE_IDE=y -CONFIG_HAVE_KERNEL_BZIP2=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_MEMBLOCK_NODE_MAP=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_HAVE_NET_DSA=y -CONFIG_HAVE_OPROFILE=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HW_RANDOM=y -CONFIG_HZ_PERIODIC=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_IP17XX_PHY=y -CONFIG_IRQ_CPU=y -CONFIG_IRQ_FORCED_THREADING=y -CONFIG_IRQ_WORK=y -CONFIG_KALLSYMS=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_MDIO_BOARDINFO=y -CONFIG_MIPS=y -# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set -CONFIG_MIPS_L1_CACHE_SHIFT=5 -# CONFIG_MIPS_MACHINE is not set -CONFIG_MIPS_MT_DISABLED=y -CONFIG_MODULES_USE_ELF_REL=y -# CONFIG_MTD_AC49X_PARTS is not set -CONFIG_MTD_CFI_STAA=y -CONFIG_MTD_PHYSMAP=y -CONFIG_MVSWITCH_PHY=y -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_NEED_PER_CPU_KM=y -CONFIG_NO_EXCEPT_FILL=y -CONFIG_PAGEFLAGS_EXTENDED=y -CONFIG_PERF_USE_VMALLOC=y -CONFIG_PHYLIB=y -# CONFIG_PREEMPT_RCU is not set -# CONFIG_RCU_STALL_COMMON is not set -# CONFIG_SCSI_DMA is not set -CONFIG_SWAP_IO_SPACE=y -CONFIG_SWCONFIG=y -CONFIG_SYS_HAS_CPU_MIPS32_R1=y -CONFIG_SYS_HAS_EARLY_PRINTK=y -CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -CONFIG_SYS_SUPPORTS_ZBOOT=y -CONFIG_SYS_SUPPORTS_ZBOOT_UART16550=y -CONFIG_TICK_CPU_ACCOUNTING=y -CONFIG_VLYNQ=y -# CONFIG_VLYNQ_DEBUG is not set -CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/ar7/config-4.1 b/target/linux/ar7/config-4.4 similarity index 90% rename from target/linux/ar7/config-4.1 rename to target/linux/ar7/config-4.4 index 7463d5b751c5..3cfbea1671c2 100644 --- a/target/linux/ar7/config-4.1 +++ b/target/linux/ar7/config-4.4 @@ -6,17 +6,19 @@ CONFIG_AR7_TI=y CONFIG_AR7_TYPE_TI=y CONFIG_AR7_WDT=y CONFIG_ARCH_BINFMT_ELF_STATE=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_ARCH_DISCARD_MEMBLOCK=y CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y CONFIG_ARCH_HAS_ELF_RANDOMIZE=y # CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set # CONFIG_ARCH_HAS_SG_CHAIN is not set -CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_BOOT_ELF32=y CONFIG_CEVT_R4K=y @@ -37,6 +39,8 @@ CONFIG_CPU_R4K_CACHE_TLB=y CONFIG_CPU_R4K_FPU=y CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_WORKQUEUE=y CONFIG_CSRC_R4K=y CONFIG_DMA_NONCOHERENT=y CONFIG_EARLY_PRINTK=y @@ -46,10 +50,12 @@ CONFIG_GENERIC_ATOMIC64=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_CHIP=y CONFIG_GENERIC_IRQ_SHOW=y CONFIG_GENERIC_PCI_IOMAP=y CONFIG_GENERIC_SCHED_CLOCK=y CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GPIOLIB=y CONFIG_GPIO_DEVRES=y CONFIG_HARDWARE_WATCHPOINTS=y @@ -86,6 +92,7 @@ CONFIG_HAVE_KERNEL_LZ4=y CONFIG_HAVE_KERNEL_LZMA=y CONFIG_HAVE_KERNEL_LZO=y CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y CONFIG_HAVE_MEMBLOCK=y CONFIG_HAVE_MEMBLOCK_NODE_MAP=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y @@ -98,17 +105,17 @@ CONFIG_HW_RANDOM=y CONFIG_HZ_PERIODIC=y CONFIG_INITRAMFS_SOURCE="" CONFIG_IP17XX_PHY=y -CONFIG_IRQ_CPU=y CONFIG_IRQ_DOMAIN=y CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_MIPS_CPU=y CONFIG_IRQ_WORK=y CONFIG_KALLSYMS=y CONFIG_LEDS_GPIO=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y -# CONFIG_LZ4_COMPRESS is not set -# CONFIG_LZ4_DECOMPRESS is not set CONFIG_MDIO_BOARDINFO=y CONFIG_MIPS=y +CONFIG_MIPS_CLOCK_VSYSCALL=y +CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER=y # CONFIG_MIPS_HUGE_TLB_SUPPORT is not set CONFIG_MIPS_L1_CACHE_SHIFT=5 # CONFIG_MIPS_MACHINE is not set @@ -121,14 +128,15 @@ CONFIG_NEED_DMA_MAP_STATE=y CONFIG_NEED_PER_CPU_KM=y CONFIG_NO_EXCEPT_FILL=y # CONFIG_NO_IOPORT_MAP is not set -CONFIG_PAGEFLAGS_EXTENDED=y +# CONFIG_OF is not set CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y -# CONFIG_RCU_EXPEDITE_BOOT is not set # CONFIG_RCU_STALL_COMMON is not set CONFIG_SCHED_HRTICK=y +# CONFIG_SCHED_INFO is not set # CONFIG_SCSI_DMA is not set +# CONFIG_SERIAL_8250_FSL is not set CONFIG_SRCU=y CONFIG_SWAP_IO_SPACE=y CONFIG_SWCONFIG=y diff --git a/target/linux/ar7/files/drivers/char/ar7_gpio.c b/target/linux/ar7/files/drivers/char/ar7_gpio.c index 71310fa75147..d5e263c2fb35 100644 --- a/target/linux/ar7/files/drivers/char/ar7_gpio.c +++ b/target/linux/ar7/files/drivers/char/ar7_gpio.c @@ -27,7 +27,11 @@ #include #include #include -#include +#include +#include + +#define AR7_GPIO_MAX 32 +#define TITAN_GPIO_MAX 51 #define DRVNAME "ar7_gpio" #define LONGNAME "TI AR7 GPIOs Driver" diff --git a/target/linux/ar7/patches-3.18/001-mips-ar7-fix-serial.patch b/target/linux/ar7/patches-3.18/001-mips-ar7-fix-serial.patch deleted file mode 100644 index 68963522662c..000000000000 --- a/target/linux/ar7/patches-3.18/001-mips-ar7-fix-serial.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 443ab715a40881d6c9ba11b027ba154bac904cb0 Mon Sep 17 00:00:00 2001 -From: Oswald Buddenhagen -Date: Sat, 10 May 2014 23:19:08 +0200 -Subject: [PATCH] MIPS/AR7: ensure that serial ports are properly set up - -without UPF_FIXED_TYPE, the data from the PORT_AR7 uart_config entry is -never copied, resulting in a dead port. - -Signed-off-by: Oswald Buddenhagen ---- - arch/mips/ar7/platform.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/arch/mips/ar7/platform.c -+++ b/arch/mips/ar7/platform.c -@@ -581,6 +581,7 @@ static int __init ar7_register_uarts(voi - uart_port.type = PORT_AR7; - uart_port.uartclk = clk_get_rate(bus_clk) / 2; - uart_port.iotype = UPIO_MEM32; -+ uart_port.flags = UPF_FIXED_TYPE; - uart_port.regshift = 2; - - uart_port.line = 0; diff --git a/target/linux/ar7/patches-3.18/120-gpio_chrdev.patch b/target/linux/ar7/patches-3.18/120-gpio_chrdev.patch deleted file mode 100644 index beb0052ca138..000000000000 --- a/target/linux/ar7/patches-3.18/120-gpio_chrdev.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -452,6 +452,15 @@ config MWAVE - To compile this driver as a module, choose M here: the - module will be called mwave. - -+config AR7_GPIO -+ tristate "TI AR7 GPIO Support" -+ depends on AR7 -+ help -+ Give userspace access to the GPIO pins on the Texas Instruments AR7 -+ processors. -+ -+ If compiled as a module, it will be called ar7_gpio. -+ - config SCx200_GPIO - tristate "NatSemi SCx200 GPIO Support" - depends on SCx200 ---- a/drivers/char/Makefile -+++ b/drivers/char/Makefile -@@ -42,6 +42,7 @@ obj-$(CONFIG_HW_RANDOM) += hw_random/ - obj-$(CONFIG_PPDEV) += ppdev.o - obj-$(CONFIG_NWBUTTON) += nwbutton.o - obj-$(CONFIG_NWFLASH) += nwflash.o -+obj-$(CONFIG_AR7_GPIO) += ar7_gpio.o - obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o - obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o - obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o diff --git a/target/linux/ar7/patches-3.18/300-add-ac49x-platform.patch b/target/linux/ar7/patches-3.18/300-add-ac49x-platform.patch deleted file mode 100644 index ccdc84d309c9..000000000000 --- a/target/linux/ar7/patches-3.18/300-add-ac49x-platform.patch +++ /dev/null @@ -1,85 +0,0 @@ ---- a/arch/mips/ar7/Platform -+++ b/arch/mips/ar7/Platform -@@ -3,4 +3,9 @@ - # - platform-$(CONFIG_AR7) += ar7/ - cflags-$(CONFIG_AR7) += -I$(srctree)/arch/mips/include/asm/mach-ar7 --load-$(CONFIG_AR7) += 0xffffffff94100000 -+load-$(CONFIG_AR7_TI) += 0xffffffff94100000 -+ -+# -+# AudioCodes AC49x -+# -+load-$(CONFIG_AR7_AC49X) += 0xffffffff945ca000 ---- a/arch/mips/ar7/setup.c -+++ b/arch/mips/ar7/setup.c -@@ -69,6 +69,10 @@ const char *get_system_type(void) - return "TI AR7 (TNETV1056)"; - case TITAN_CHIP_1060: - return "TI AR7 (TNETV1060)"; -+ case TITAN_CHIP_AC495: -+ return "AudioCodes AC495"; -+ case TITAN_CHIP_AC496: -+ return "AudioCodes AC496"; - } - default: - return "TI AR7 (unknown)"; ---- a/arch/mips/include/asm/mach-ar7/ar7.h -+++ b/arch/mips/include/asm/mach-ar7/ar7.h -@@ -92,6 +92,8 @@ - #define TITAN_CHIP_1055 0x0e - #define TITAN_CHIP_1056 0x0d - #define TITAN_CHIP_1060 0x07 -+#define TITAN_CHIP_AC495 0x00 -+#define TITAN_CHIP_AC496 0x02 - - /* Interrupts */ - #define AR7_IRQ_UART0 15 ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -94,7 +94,7 @@ config AR7 - select HAVE_CLK - help - Support for the Texas Instruments AR7 System-on-a-Chip -- family: TNETD7100, 7200 and 7300. -+ family: TI TNETD7100, 7200, 7300 and AudioCodes AC49x. - - config ATH79 - bool "Atheros AR71XX/AR724X/AR913X based boards" -@@ -835,6 +835,7 @@ config MIPS_PARAVIRT - endchoice - - source "arch/mips/alchemy/Kconfig" -+source "arch/mips/ar7/Kconfig" - source "arch/mips/ath79/Kconfig" - source "arch/mips/bcm47xx/Kconfig" - source "arch/mips/bcm63xx/Kconfig" ---- /dev/null -+++ b/arch/mips/ar7/Kconfig -@@ -0,0 +1,26 @@ -+if AR7 -+ -+config AR7_TI -+ bool -+ -+config AR7_AC49X -+ bool -+ -+choice -+ prompt "AR7 SoC family selection" -+ default AR7_TYPE_TI -+ depends on AR7 -+ help -+ Select AR7 MIPS SoC implementation. -+ -+ config AR7_TYPE_TI -+ bool "Texas Instruments AR7" -+ select AR7_TI -+ -+ config AR7_TYPE_AC49X -+ bool "AudioCodes AC49X" -+ select AR7_AC49X -+ -+endchoice -+ -+endif diff --git a/target/linux/ar7/patches-3.18/320-ac49x-mtd-partitions.patch b/target/linux/ar7/patches-3.18/320-ac49x-mtd-partitions.patch deleted file mode 100644 index 53ac07273a8f..000000000000 --- a/target/linux/ar7/patches-3.18/320-ac49x-mtd-partitions.patch +++ /dev/null @@ -1,35 +0,0 @@ ---- a/drivers/mtd/Kconfig -+++ b/drivers/mtd/Kconfig -@@ -164,6 +164,11 @@ config MTD_OF_PARTS - the partition map from the children of the flash node, - as described in Documentation/devicetree/booting-without-of.txt. - -+config MTD_AC49X_PARTS -+ tristate "AudioCodes AC49X partitioning support" -+ ---help--- -+ AudioCodes AC49X partitioning support -+ - config MTD_AR7_PARTS - tristate "TI AR7 partitioning support" - ---help--- ---- a/drivers/mtd/Makefile -+++ b/drivers/mtd/Makefile -@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_SPLIT) += mtdsplit/ - obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o - obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o -+obj-$(CONFIG_MTD_AC49X_PARTS) += ac49xpart.o - obj-$(CONFIG_MTD_AFS_PARTS) += afs.o - obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o titanpart.o - obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o ---- a/arch/mips/ar7/platform.c -+++ b/arch/mips/ar7/platform.c -@@ -202,7 +202,7 @@ static struct resource physmap_flash_res - .end = 0x11ffffff, - }; - --static const char *ar7_probe_types[] = { "ar7part", NULL }; -+static const char *ar7_probe_types[] = { "ac49xpart", "ar7part", NULL }; - - static struct physmap_flash_data physmap_flash_data = { - .width = 2, diff --git a/target/linux/ar7/patches-3.18/500-serial_kludge.patch b/target/linux/ar7/patches-3.18/500-serial_kludge.patch deleted file mode 100644 index 08bd6a6f2d66..000000000000 --- a/target/linux/ar7/patches-3.18/500-serial_kludge.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- a/drivers/tty/serial/8250/8250_core.c -+++ b/drivers/tty/serial/8250/8250_core.c -@@ -329,6 +329,13 @@ static const struct serial8250_config ua - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, -+ [PORT_AR7] = { -+ .name = "TI-AR7", -+ .fifo_size = 16, -+ .tx_loadsz = 16, -+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, -+ .flags = UART_CAP_FIFO | UART_CAP_AFE, -+ }, - }; - - /* Uart divisor latch read */ -@@ -3174,7 +3181,11 @@ static void serial8250_console_putchar(s - { - struct uart_8250_port *up = up_to_u8250p(port); - -+#ifdef CONFIG_AR7 -+ wait_for_xmitr(up, BOTH_EMPTY); -+#else - wait_for_xmitr(up, UART_LSR_THRE); -+#endif - serial_port_out(port, UART_TX, ch); - } - diff --git a/target/linux/ar7/patches-3.18/925-actiontec_leds.patch b/target/linux/ar7/patches-3.18/925-actiontec_leds.patch deleted file mode 100644 index 41af2cb54fb4..000000000000 --- a/target/linux/ar7/patches-3.18/925-actiontec_leds.patch +++ /dev/null @@ -1,95 +0,0 @@ ---- a/arch/mips/ar7/platform.c -+++ b/arch/mips/ar7/platform.c -@@ -465,31 +465,22 @@ static struct gpio_led fb_fon_leds[] = { - }, - }; - --static struct gpio_led gt701_leds[] = { -+static struct gpio_led actiontec_leds[] = { - { - .name = "inet:green", - .gpio = 13, -- .active_low = 1, -- }, -- { -- .name = "usb", -- .gpio = 12, -- .active_low = 1, - }, - { - .name = "inet:red", - .gpio = 9, -- .active_low = 1, - }, - { -- .name = "power:red", -+ .name = "power:green", - .gpio = 7, -- .active_low = 1, - }, - { -- .name = "power:green", -+ .name = "power:red", - .gpio = 8, -- .active_low = 1, - .default_trigger = "default-on", - }, - { -@@ -497,6 +488,44 @@ static struct gpio_led gt701_leds[] = { - .gpio = 10, - .active_low = 1, - }, -+ { -+ .name = "wifi", -+ .gpio = 6, -+ .active_low = 1, -+ }, -+ { -+ .name = "wifi:red", -+ .gpio = 3, -+ }, -+ { -+ .name = "standby", -+ .gpio = 4, -+ }, -+ { -+ .name = "wps", -+ .gpio = 16, -+ .active_low = 1, -+ }, -+ { -+ .name = "usb", -+ .gpio = 12, -+ .active_low = 1, -+ }, -+ { -+ .name = "voip", -+ .gpio = 15, -+ .active_low = 1, -+ }, -+ { -+ .name = "line1", -+ .gpio = 23, -+ .active_low = 1, -+ }, -+ { -+ .name = "line2", -+ .gpio = 25, -+ .active_low = 1, -+ }, - }; - - static struct gpio_led_platform_data ar7_led_data; -@@ -540,9 +569,9 @@ static void __init detect_leds(void) - } else if (strstr(prid, "CYWM") || strstr(prid, "CYWL")) { - ar7_led_data.num_leds = ARRAY_SIZE(titan_leds); - ar7_led_data.leds = titan_leds; -- } else if (strstr(prid, "GT701")) { -- ar7_led_data.num_leds = ARRAY_SIZE(gt701_leds); -- ar7_led_data.leds = gt701_leds; -+ } else if (strstr(prid, "GT7") || strstr(prid, "PK5000")) { -+ ar7_led_data.num_leds = ARRAY_SIZE(actiontec_leds); -+ ar7_led_data.leds = actiontec_leds; - } - } - diff --git a/target/linux/ar7/patches-4.1/100-fix-highmem-offset.patch b/target/linux/ar7/patches-4.1/100-fix-highmem-offset.patch deleted file mode 100644 index f1a754978699..000000000000 --- a/target/linux/ar7/patches-4.1/100-fix-highmem-offset.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/arch/mips/include/asm/mach-ar7/spaces.h -+++ b/arch/mips/include/asm/mach-ar7/spaces.h -@@ -20,6 +20,8 @@ - #define UNCAC_BASE _AC(0xb4000000, UL) /* 0xa0000000 + PHYS_OFFSET */ - #define IO_BASE UNCAC_BASE - -+#define HIGHMEM_START _AC(0x20000000, UL) -+ - #include - - #endif /* __ASM_AR7_SPACES_H */ diff --git a/target/linux/ar7/patches-4.1/110-flash.patch b/target/linux/ar7/patches-4.1/110-flash.patch deleted file mode 100644 index e4aeffd3e2d8..000000000000 --- a/target/linux/ar7/patches-4.1/110-flash.patch +++ /dev/null @@ -1,22 +0,0 @@ ---- a/drivers/mtd/Makefile -+++ b/drivers/mtd/Makefile -@@ -12,7 +12,7 @@ obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o - obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o - obj-$(CONFIG_MTD_AFS_PARTS) += afs.o --obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o -+obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o titanpart.o - obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o - obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o - obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o ---- a/arch/mips/ar7/platform.c -+++ b/arch/mips/ar7/platform.c -@@ -199,7 +199,7 @@ static struct resource physmap_flash_res - .name = "mem", - .flags = IORESOURCE_MEM, - .start = 0x10000000, -- .end = 0x107fffff, -+ .end = 0x11ffffff, - }; - - static const char *ar7_probe_types[] = { "ar7part", NULL }; diff --git a/target/linux/ar7/patches-4.1/160-vlynq_try_remote_first.patch b/target/linux/ar7/patches-4.1/160-vlynq_try_remote_first.patch deleted file mode 100644 index 1d1310d82eb0..000000000000 --- a/target/linux/ar7/patches-4.1/160-vlynq_try_remote_first.patch +++ /dev/null @@ -1,300 +0,0 @@ ---- a/drivers/vlynq/vlynq.c -+++ b/drivers/vlynq/vlynq.c -@@ -119,20 +119,40 @@ static int vlynq_linked(struct vlynq_dev - return 0; - } - -+static volatile int vlynq_delay_value_new = 0; -+ -+static void vlynq_delay_wait(u32 count) -+{ -+ /* Code adopted from original vlynq driver */ -+ int i = 0; -+ volatile int *ptr = &vlynq_delay_value_new; -+ *ptr = 0; -+ -+ /* We are assuming that the each cycle takes about -+ * 23 assembly instructions. */ -+ for(i = 0; i < (count + 23)/23; i++) -+ *ptr = *ptr + 1; -+} -+ - static void vlynq_reset(struct vlynq_device *dev) - { -+ u32 rtm = readl(&dev->local->revision); -+ -+ rtm = rtm < 0x00010205 || readl(&dev->local->status) & 0x800 == 0 ? -+ 0 : 0x600000; -+ - writel(readl(&dev->local->control) | VLYNQ_CTRL_RESET, - &dev->local->control); - - /* Wait for the devices to finish resetting */ -- msleep(5); -+ vlynq_delay_wait(0xffffff); - - /* Remove reset bit */ -- writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET, -+ writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET | rtm, - &dev->local->control); - - /* Give some time for the devices to settle */ -- msleep(5); -+ vlynq_delay_wait(0xffffff); - } - - static void vlynq_irq_unmask(struct irq_data *d) -@@ -379,6 +399,61 @@ void vlynq_unregister_driver(struct vlyn - } - EXPORT_SYMBOL(vlynq_unregister_driver); - -+enum vlynq_clk_src { -+ vlynq_clk_external, -+ vlynq_clk_local, -+ vlynq_clk_remote, -+ vlynq_clk_invalid, -+}; -+ -+static int __vlynq_set_clocks(struct vlynq_device *dev, -+ enum vlynq_clk_src clk_dir, -+ int lclk_div, int rclk_div) -+{ -+ u32 reg; -+ -+ if (clk_dir == vlynq_clk_invalid) { -+ printk(KERN_ERR "%s: attempt to set invalid clocking\n", -+ dev_name(&dev->dev)); -+ return -EINVAL; -+ } -+ -+ reg = readl(&dev->local->control); -+ if (readl(&dev->local->revision) < 0x00010205) { -+ if (clk_dir & vlynq_clk_local) -+ reg |= VLYNQ_CTRL_CLOCK_INT; -+ else -+ reg &= ~VLYNQ_CTRL_CLOCK_INT; -+ } -+ reg &= ~VLYNQ_CTRL_CLOCK_MASK; -+ reg |= VLYNQ_CTRL_CLOCK_DIV(lclk_div); -+ writel(reg, &dev->local->control); -+ -+ if (!vlynq_linked(dev)) -+ return -ENODEV; -+ -+ printk(KERN_INFO "%s: local VLYNQ protocol rev. is 0x%08x\n", -+ dev_name(&dev->dev), readl(&dev->local->revision)); -+ printk(KERN_INFO "%s: remote VLYNQ protocol rev. is 0x%08x\n", -+ dev_name(&dev->dev), readl(&dev->remote->revision)); -+ -+ reg = readl(&dev->remote->control); -+ if (readl(&dev->remote->revision) < 0x00010205) { -+ if (clk_dir & vlynq_clk_remote) -+ reg |= VLYNQ_CTRL_CLOCK_INT; -+ else -+ reg &= ~VLYNQ_CTRL_CLOCK_INT; -+ } -+ reg &= ~VLYNQ_CTRL_CLOCK_MASK; -+ reg |= VLYNQ_CTRL_CLOCK_DIV(rclk_div); -+ writel(reg, &dev->remote->control); -+ -+ if (!vlynq_linked(dev)) -+ return -ENODEV; -+ -+ return 0; -+} -+ - /* - * A VLYNQ remote device can clock the VLYNQ bus master - * using a dedicated clock line. In that case, both the -@@ -392,29 +467,16 @@ static int __vlynq_try_remote(struct vly - int i; - - vlynq_reset(dev); -- for (i = dev->dev_id ? vlynq_rdiv2 : vlynq_rdiv8; dev->dev_id ? -- i <= vlynq_rdiv8 : i >= vlynq_rdiv2; -- dev->dev_id ? i++ : i--) { -+ for (i = 0; i <= 7; i++) { - - if (!vlynq_linked(dev)) - break; - -- writel((readl(&dev->remote->control) & -- ~VLYNQ_CTRL_CLOCK_MASK) | -- VLYNQ_CTRL_CLOCK_INT | -- VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1), -- &dev->remote->control); -- writel((readl(&dev->local->control) -- & ~(VLYNQ_CTRL_CLOCK_INT | -- VLYNQ_CTRL_CLOCK_MASK)) | -- VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1), -- &dev->local->control); -- -- if (vlynq_linked(dev)) { -- printk(KERN_DEBUG -- "%s: using remote clock divisor %d\n", -- dev_name(&dev->dev), i - vlynq_rdiv1 + 1); -- dev->divisor = i; -+ if (!__vlynq_set_clocks(dev, vlynq_clk_remote, i, i)) { -+ printk(KERN_INFO -+ "%s: using remote clock divisor %d\n", -+ dev_name(&dev->dev), i + 1); -+ dev->divisor = i + vlynq_rdiv1; - return 0; - } else { - vlynq_reset(dev); -@@ -433,25 +495,17 @@ static int __vlynq_try_remote(struct vly - */ - static int __vlynq_try_local(struct vlynq_device *dev) - { -- int i; -+ int i, dir = !dev->dev_id; - - vlynq_reset(dev); - -- for (i = dev->dev_id ? vlynq_ldiv2 : vlynq_ldiv8; dev->dev_id ? -- i <= vlynq_ldiv8 : i >= vlynq_ldiv2; -- dev->dev_id ? i++ : i--) { -- -- writel((readl(&dev->local->control) & -- ~VLYNQ_CTRL_CLOCK_MASK) | -- VLYNQ_CTRL_CLOCK_INT | -- VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1), -- &dev->local->control); -- -- if (vlynq_linked(dev)) { -- printk(KERN_DEBUG -- "%s: using local clock divisor %d\n", -- dev_name(&dev->dev), i - vlynq_ldiv1 + 1); -- dev->divisor = i; -+ for (i = dir ? 7 : 0; dir ? i >= 0 : i <= 7; dir ? i-- : i++) { -+ -+ if (!__vlynq_set_clocks(dev, vlynq_clk_local, i, 0)) { -+ printk(KERN_INFO -+ "%s: using local clock divisor %d\n", -+ dev_name(&dev->dev), i + 1); -+ dev->divisor = i + vlynq_ldiv1; - return 0; - } else { - vlynq_reset(dev); -@@ -473,18 +527,10 @@ static int __vlynq_try_external(struct v - if (!vlynq_linked(dev)) - return -ENODEV; - -- writel((readl(&dev->remote->control) & -- ~VLYNQ_CTRL_CLOCK_INT), -- &dev->remote->control); -- -- writel((readl(&dev->local->control) & -- ~VLYNQ_CTRL_CLOCK_INT), -- &dev->local->control); -- -- if (vlynq_linked(dev)) { -- printk(KERN_DEBUG "%s: using external clock\n", -- dev_name(&dev->dev)); -- dev->divisor = vlynq_div_external; -+ if (!__vlynq_set_clocks(dev, vlynq_clk_external, 0, 0)) { -+ printk(KERN_INFO "%s: using external clock\n", -+ dev_name(&dev->dev)); -+ dev->divisor = vlynq_div_external; - return 0; - } - -@@ -501,24 +547,16 @@ static int __vlynq_enable_device(struct - return result; - - switch (dev->divisor) { -- case vlynq_div_external: - case vlynq_div_auto: - /* When the device is brought from reset it should have clock - * generation negotiated by hardware. - * Check which device is generating clocks and perform setup - * accordingly */ -- if (vlynq_linked(dev) && readl(&dev->remote->control) & -- VLYNQ_CTRL_CLOCK_INT) { -- if (!__vlynq_try_remote(dev) || -- !__vlynq_try_local(dev) || -- !__vlynq_try_external(dev)) -- return 0; -- } else { -- if (!__vlynq_try_external(dev) || -- !__vlynq_try_local(dev) || -- !__vlynq_try_remote(dev)) -- return 0; -- } -+ if (!__vlynq_try_remote(dev) || !__vlynq_try_local(dev)) -+ return 0; -+ case vlynq_div_external: -+ if (!__vlynq_try_external(dev)) -+ return 0; - break; - case vlynq_ldiv1: - case vlynq_ldiv2: -@@ -528,15 +566,12 @@ static int __vlynq_enable_device(struct - case vlynq_ldiv6: - case vlynq_ldiv7: - case vlynq_ldiv8: -- writel(VLYNQ_CTRL_CLOCK_INT | -- VLYNQ_CTRL_CLOCK_DIV(dev->divisor - -- vlynq_ldiv1), &dev->local->control); -- writel(0, &dev->remote->control); -- if (vlynq_linked(dev)) { -- printk(KERN_DEBUG -- "%s: using local clock divisor %d\n", -- dev_name(&dev->dev), -- dev->divisor - vlynq_ldiv1 + 1); -+ if (!__vlynq_set_clocks(dev, vlynq_clk_local, dev->divisor - -+ vlynq_ldiv1, 0)) { -+ printk(KERN_INFO -+ "%s: using local clock divisor %d\n", -+ dev_name(&dev->dev), -+ dev->divisor - vlynq_ldiv1 + 1); - return 0; - } - break; -@@ -548,20 +583,17 @@ static int __vlynq_enable_device(struct - case vlynq_rdiv6: - case vlynq_rdiv7: - case vlynq_rdiv8: -- writel(0, &dev->local->control); -- writel(VLYNQ_CTRL_CLOCK_INT | -- VLYNQ_CTRL_CLOCK_DIV(dev->divisor - -- vlynq_rdiv1), &dev->remote->control); -- if (vlynq_linked(dev)) { -- printk(KERN_DEBUG -- "%s: using remote clock divisor %d\n", -- dev_name(&dev->dev), -- dev->divisor - vlynq_rdiv1 + 1); -+ if (!__vlynq_set_clocks(dev, vlynq_clk_remote, 0, -+ dev->divisor - vlynq_rdiv1)) { -+ printk(KERN_INFO -+ "%s: using remote clock divisor %d\n", -+ dev_name(&dev->dev), -+ dev->divisor - vlynq_rdiv1 + 1); - return 0; - } - break; - } -- -+ vlynq_reset(dev); - ops->off(dev); - return -ENODEV; - } -@@ -732,14 +764,14 @@ static int vlynq_probe(struct platform_d - platform_set_drvdata(pdev, dev); - - printk(KERN_INFO "%s: regs 0x%p, irq %d, mem 0x%p\n", -- dev_name(&dev->dev), (void *)dev->regs_start, dev->irq, -- (void *)dev->mem_start); -+ dev_name(&dev->dev), (void *)dev->regs_start, -+ dev->irq, (void *)dev->mem_start); - - dev->dev_id = 0; - dev->divisor = vlynq_div_auto; -- result = __vlynq_enable_device(dev); -- if (result == 0) { -+ if (!__vlynq_enable_device(dev)) { - dev->dev_id = readl(&dev->remote->chip); -+ vlynq_reset(dev); - ((struct plat_vlynq_ops *)(dev->dev.platform_data))->off(dev); - } - if (dev->dev_id) diff --git a/target/linux/ar7/patches-4.1/200-free-mem-below-kernel-offset.patch b/target/linux/ar7/patches-4.1/200-free-mem-below-kernel-offset.patch deleted file mode 100644 index 4011942d793e..000000000000 --- a/target/linux/ar7/patches-4.1/200-free-mem-below-kernel-offset.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- a/arch/mips/ar7/memory.c -+++ b/arch/mips/ar7/memory.c -@@ -66,5 +66,11 @@ void __init prom_meminit(void) - - void __init prom_free_prom_memory(void) - { -- /* Nothing to free */ -+ /* adapted from arch/mips/txx9/generic/setup.c */ -+ unsigned long saddr = PHYS_OFFSET + PAGE_SIZE; -+ unsigned long eaddr = __pa_symbol(&_text); -+ -+ /* free memory between prom-record and kernel _text base */ -+ if (saddr < eaddr) -+ free_init_pages("prom memory", saddr, eaddr); - } diff --git a/target/linux/ar7/patches-4.1/310-ac49x-prom-support.patch b/target/linux/ar7/patches-4.1/310-ac49x-prom-support.patch deleted file mode 100644 index dddf22106af1..000000000000 --- a/target/linux/ar7/patches-4.1/310-ac49x-prom-support.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/arch/mips/ar7/prom.c -+++ b/arch/mips/ar7/prom.c -@@ -70,6 +70,7 @@ struct psbl_rec { - }; - - static const char psp_env_version[] __initconst = "TIENV0.8"; -+static const char psp_env_version_ac49x[] __initconst = "MaxENV0.2"; - - struct psp_env_chunk { - u8 num; -@@ -186,7 +187,8 @@ static void __init ar7_init_env(struct e - struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300)); - void *psp_env = (void *)KSEG1ADDR(psbl->env_base); - -- if (strcmp(psp_env, psp_env_version) == 0) { -+ if (strcmp(psp_env, psp_env_version) == 0 || -+ strcmp(psp_env, psp_env_version_ac49x) == 0) { - parse_psp_env(psp_env); - } else { - for (i = 0; i < MAX_ENTRY; i++, env++) diff --git a/target/linux/ar7/patches-4.1/500-serial_kludge.patch b/target/linux/ar7/patches-4.1/500-serial_kludge.patch deleted file mode 100644 index 23214491a127..000000000000 --- a/target/linux/ar7/patches-4.1/500-serial_kludge.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- a/drivers/tty/serial/8250/8250_core.c -+++ b/drivers/tty/serial/8250/8250_core.c -@@ -347,6 +347,13 @@ configured less than Maximum supported f - .rxtrig_bytes = {1, 4, 8, 14}, - .flags = UART_CAP_FIFO, - }, -+ [PORT_AR7] = { -+ .name = "TI-AR7", -+ .fifo_size = 16, -+ .tx_loadsz = 16, -+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, -+ .flags = UART_CAP_FIFO | UART_CAP_AFE, -+ }, - }; - - /* Uart divisor latch read */ -@@ -3348,7 +3355,11 @@ static void serial8250_console_putchar(s - { - struct uart_8250_port *up = up_to_u8250p(port); - -+#ifdef CONFIG_AR7 -+ wait_for_xmitr(up, BOTH_EMPTY); -+#else - wait_for_xmitr(up, UART_LSR_THRE); -+#endif - serial_port_out(port, UART_TX, ch); - } - diff --git a/target/linux/ar7/patches-4.1/920-ar7part.patch b/target/linux/ar7/patches-4.1/920-ar7part.patch deleted file mode 100644 index 9948858d054b..000000000000 --- a/target/linux/ar7/patches-4.1/920-ar7part.patch +++ /dev/null @@ -1,118 +0,0 @@ ---- a/drivers/mtd/ar7part.c -+++ b/drivers/mtd/ar7part.c -@@ -30,11 +30,14 @@ - - #include - -+#include -+ - #define AR7_PARTS 4 - #define ROOT_OFFSET 0xe0000 - - #define LOADER_MAGIC1 le32_to_cpu(0xfeedfa42) - #define LOADER_MAGIC2 le32_to_cpu(0xfeed1281) -+#define LOADER_MAGIC3 le32_to_cpu(0x434d4d4c) - - struct ar7_bin_rec { - unsigned int checksum; -@@ -42,12 +45,16 @@ struct ar7_bin_rec { - unsigned int address; - }; - -+int create_titan_partitions(struct mtd_info *master, -+ struct mtd_partition **pparts, -+ struct mtd_part_parser_data *data); -+ - static int create_mtd_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data) - { - struct ar7_bin_rec header; -- unsigned int offset; -+ unsigned int offset, mtd_start, mtd_end; - size_t len; - unsigned int pre_size = master->erasesize, post_size = 0; - unsigned int root_offset = ROOT_OFFSET; -@@ -55,6 +62,16 @@ static int create_mtd_partitions(struct - int retries = 10; - struct mtd_partition *ar7_parts; - -+ const char *prom_str = prom_getenv("ProductID"); -+ char mtd_name[] = "mtd1"; -+ if(prom_str && -+ (strcmp(prom_str, "CYWL")==0 || -+ strcmp(prom_str, "CYWM")==0 || -+ strcmp(prom_str, "CYLM")==0 || -+ strcmp(prom_str, "CYLL")==0)){ -+ return create_titan_partitions(master, pparts, data); -+ } -+ - ar7_parts = kzalloc(sizeof(*ar7_parts) * AR7_PARTS, GFP_KERNEL); - if (!ar7_parts) - return -ENOMEM; -@@ -83,34 +100,39 @@ static int create_mtd_partitions(struct - - pre_size = offset; - -- if (!ar7_parts[1].offset) { -- ar7_parts[1].offset = master->size - master->erasesize; -- post_size = master->erasesize; -- } -- - switch (header.checksum) { -- case LOADER_MAGIC1: -- while (header.length) { -- offset += sizeof(header) + header.length; -- mtd_read(master, offset, sizeof(header), &len, -- (uint8_t *)&header); -- } -- root_offset = offset + sizeof(header) + 4; -- break; - case LOADER_MAGIC2: -+ for (retries = 0; retries <= 9; retries++) { -+ mtd_name[3] = '0' + retries; -+ prom_str = prom_getenv(mtd_name); -+ if (prom_str == NULL) -+ continue; -+ sscanf(prom_str, "%i,%i", &mtd_start, &mtd_end); -+ if (pre_size == (mtd_start & 0x1ffffff)) { -+ ar7_parts[1].offset = mtd_end &= 0x1ffffff; -+ ar7_parts[1].size = post_size = master->size - mtd_end; -+ break; -+ } -+ } -+ case LOADER_MAGIC1: -+ root_offset = (header.checksum == LOADER_MAGIC1) ? 4 : 0; - while (header.length) { - offset += sizeof(header) + header.length; - mtd_read(master, offset, sizeof(header), &len, - (uint8_t *)&header); - } -- root_offset = offset + sizeof(header) + 4 + 0xff; -- root_offset &= ~(uint32_t)0xff; -+ root_offset += offset + sizeof(header); - break; - default: - printk(KERN_WARNING "Unknown magic: %08x\n", header.checksum); - break; - } - -+ if (!ar7_parts[1].offset) { -+ post_size = master->erasesize; -+ ar7_parts[1].offset = master->size - post_size; -+ } -+ - mtd_read(master, root_offset, sizeof(header), &len, (u8 *)&header); - if (header.checksum != SQUASHFS_MAGIC) { - root_offset += master->erasesize - 1; ---- a/drivers/mtd/titanpart.c -+++ b/drivers/mtd/titanpart.c -@@ -149,7 +149,7 @@ static void titan_add_partition(char * e - } - int create_titan_partitions(struct mtd_info *master, - struct mtd_partition **pparts, -- unsigned long origin) -+ struct mtd_part_parser_data *data) - { - struct nsp_img_hdr_head hdr; - struct nsp_img_hdr_section_info sect_info; diff --git a/target/linux/ar7/patches-4.1/950-cpmac_titan.patch b/target/linux/ar7/patches-4.1/950-cpmac_titan.patch deleted file mode 100644 index f1d432cc4c83..000000000000 --- a/target/linux/ar7/patches-4.1/950-cpmac_titan.patch +++ /dev/null @@ -1,52 +0,0 @@ ---- a/drivers/net/ethernet/ti/cpmac.c -+++ b/drivers/net/ethernet/ti/cpmac.c -@@ -1146,6 +1146,8 @@ static int cpmac_probe(struct platform_d - goto out; - } - -+ ar7_device_reset(pdata->reset_bit); -+ - dev->irq = platform_get_irq_byname(pdev, "irq"); - - dev->netdev_ops = &cpmac_netdev_ops; -@@ -1227,7 +1229,7 @@ int cpmac_init(void) - cpmac_mii->reset = cpmac_mdio_reset; - cpmac_mii->irq = mii_irqs; - -- cpmac_mii->priv = ioremap(AR7_REGS_MDIO, 256); -+ cpmac_mii->priv = ioremap(ar7_is_titan() ? TITAN_REGS_MDIO : AR7_REGS_MDIO, 256); - - if (!cpmac_mii->priv) { - pr_err("Can't ioremap mdio registers\n"); -@@ -1238,10 +1240,16 @@ int cpmac_init(void) - #warning FIXME: unhardcode gpio&reset bits - ar7_gpio_disable(26); - ar7_gpio_disable(27); -- ar7_device_reset(AR7_RESET_BIT_CPMAC_LO); -- ar7_device_reset(AR7_RESET_BIT_CPMAC_HI); -+ -+ if (!ar7_is_titan()) { -+ ar7_device_reset(AR7_RESET_BIT_CPMAC_LO); -+ ar7_device_reset(AR7_RESET_BIT_CPMAC_HI); -+ } - ar7_device_reset(AR7_RESET_BIT_EPHY); - -+ if (ar7_is_titan()) -+ ar7_device_reset(TITAN_RESET_BIT_EPHY1); -+ - cpmac_mii->reset(cpmac_mii); - - for (i = 0; i < 300; i++) { -@@ -1258,7 +1266,11 @@ int cpmac_init(void) - mask = 0; - } - -- cpmac_mii->phy_mask = ~(mask | 0x80000000); -+ if (ar7_is_titan()) -+ cpmac_mii->phy_mask = ~(mask | 0x80000000 | 0x40000000); -+ else -+ cpmac_mii->phy_mask = ~(mask | 0x80000000); -+ - snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "cpmac-1"); - - res = mdiobus_register(cpmac_mii); diff --git a/target/linux/ar7/patches-4.1/001-mips-ar7-fix-serial.patch b/target/linux/ar7/patches-4.4/001-mips-ar7-fix-serial.patch similarity index 100% rename from target/linux/ar7/patches-4.1/001-mips-ar7-fix-serial.patch rename to target/linux/ar7/patches-4.4/001-mips-ar7-fix-serial.patch diff --git a/target/linux/ar7/patches-3.18/100-fix-highmem-offset.patch b/target/linux/ar7/patches-4.4/100-fix-highmem-offset.patch similarity index 100% rename from target/linux/ar7/patches-3.18/100-fix-highmem-offset.patch rename to target/linux/ar7/patches-4.4/100-fix-highmem-offset.patch diff --git a/target/linux/ar7/patches-3.18/110-flash.patch b/target/linux/ar7/patches-4.4/110-flash.patch similarity index 100% rename from target/linux/ar7/patches-3.18/110-flash.patch rename to target/linux/ar7/patches-4.4/110-flash.patch diff --git a/target/linux/ar7/patches-4.1/120-gpio_chrdev.patch b/target/linux/ar7/patches-4.4/120-gpio_chrdev.patch similarity index 100% rename from target/linux/ar7/patches-4.1/120-gpio_chrdev.patch rename to target/linux/ar7/patches-4.4/120-gpio_chrdev.patch diff --git a/target/linux/ar7/patches-3.18/160-vlynq_try_remote_first.patch b/target/linux/ar7/patches-4.4/160-vlynq_try_remote_first.patch similarity index 100% rename from target/linux/ar7/patches-3.18/160-vlynq_try_remote_first.patch rename to target/linux/ar7/patches-4.4/160-vlynq_try_remote_first.patch diff --git a/target/linux/ar7/patches-3.18/200-free-mem-below-kernel-offset.patch b/target/linux/ar7/patches-4.4/200-free-mem-below-kernel-offset.patch similarity index 100% rename from target/linux/ar7/patches-3.18/200-free-mem-below-kernel-offset.patch rename to target/linux/ar7/patches-4.4/200-free-mem-below-kernel-offset.patch diff --git a/target/linux/ar7/patches-4.1/300-add-ac49x-platform.patch b/target/linux/ar7/patches-4.4/300-add-ac49x-platform.patch similarity index 100% rename from target/linux/ar7/patches-4.1/300-add-ac49x-platform.patch rename to target/linux/ar7/patches-4.4/300-add-ac49x-platform.patch diff --git a/target/linux/ar7/patches-3.18/310-ac49x-prom-support.patch b/target/linux/ar7/patches-4.4/310-ac49x-prom-support.patch similarity index 100% rename from target/linux/ar7/patches-3.18/310-ac49x-prom-support.patch rename to target/linux/ar7/patches-4.4/310-ac49x-prom-support.patch diff --git a/target/linux/ar7/patches-4.1/320-ac49x-mtd-partitions.patch b/target/linux/ar7/patches-4.4/320-ac49x-mtd-partitions.patch similarity index 100% rename from target/linux/ar7/patches-4.1/320-ac49x-mtd-partitions.patch rename to target/linux/ar7/patches-4.4/320-ac49x-mtd-partitions.patch diff --git a/target/linux/ar7/patches-4.4/500-serial_kludge.patch b/target/linux/ar7/patches-4.4/500-serial_kludge.patch new file mode 100644 index 000000000000..db78e747aebf --- /dev/null +++ b/target/linux/ar7/patches-4.4/500-serial_kludge.patch @@ -0,0 +1,14 @@ +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -3348,7 +3355,11 @@ static void serial8250_console_putchar(s + { + struct uart_8250_port *up = up_to_u8250p(port); + ++#ifdef CONFIG_AR7 ++ wait_for_xmitr(up, BOTH_EMPTY); ++#else + wait_for_xmitr(up, UART_LSR_THRE); ++#endif + serial_port_out(port, UART_TX, ch); + } + diff --git a/target/linux/ar7/patches-3.18/920-ar7part.patch b/target/linux/ar7/patches-4.4/920-ar7part.patch similarity index 100% rename from target/linux/ar7/patches-3.18/920-ar7part.patch rename to target/linux/ar7/patches-4.4/920-ar7part.patch diff --git a/target/linux/ar7/patches-4.1/925-actiontec_leds.patch b/target/linux/ar7/patches-4.4/925-actiontec_leds.patch similarity index 100% rename from target/linux/ar7/patches-4.1/925-actiontec_leds.patch rename to target/linux/ar7/patches-4.4/925-actiontec_leds.patch diff --git a/target/linux/ar7/patches-3.18/950-cpmac_titan.patch b/target/linux/ar7/patches-4.4/950-cpmac_titan.patch similarity index 100% rename from target/linux/ar7/patches-3.18/950-cpmac_titan.patch rename to target/linux/ar7/patches-4.4/950-cpmac_titan.patch From f997940ebd704c240a8442aa63577d5a0a286207 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 15 May 2016 15:30:16 +0200 Subject: [PATCH 02/37] au1000: bump to v4.4 Signed-off-by: John Crispin --- target/linux/au1000/Makefile | 2 +- .../linux/au1000/{config-3.18 => config-4.4} | 57 +++++++++++++------ 2 files changed, 42 insertions(+), 17 deletions(-) rename target/linux/au1000/{config-3.18 => config-4.4} (74%) diff --git a/target/linux/au1000/Makefile b/target/linux/au1000/Makefile index 7438e9b6df1c..f3a79d3cae1e 100644 --- a/target/linux/au1000/Makefile +++ b/target/linux/au1000/Makefile @@ -13,7 +13,7 @@ FEATURES:=squashfs usb pci SUBTARGETS=au1500 au1550 MAINTAINER:=Florian Fainelli -KERNEL_PATCHVER:=3.18 +KERNEL_PATCHVER:=4.4 include $(INCLUDE_DIR)/target.mk DEFAULT_PACKAGES += wpad-mini yamonenv diff --git a/target/linux/au1000/config-3.18 b/target/linux/au1000/config-4.4 similarity index 74% rename from target/linux/au1000/config-3.18 rename to target/linux/au1000/config-4.4 index cb2eee20ebdc..3ebfb94a502b 100644 --- a/target/linux/au1000/config-3.18 +++ b/target/linux/au1000/config-4.4 @@ -1,23 +1,27 @@ -CONFIG_64BIT_PHYS_ADDR=y -CONFIG_ALCHEMY_GPIOINT_AU1000=y -CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_ARCH_BINFMT_ELF_STATE=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_ARCH_DISCARD_MEMBLOCK=y CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y -CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set +# CONFIG_ARCH_HAS_SG_CHAIN is not set CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y CONFIG_ARCH_PHYS_ADDR_T_64BIT=y CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_CEVT_R4K=y +CONFIG_CLKDEV_LOOKUP=y CONFIG_CLONE_BACKWARDS=y CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/mtdblock0 rootfstype=squashfs,jffs2" CONFIG_CMDLINE_BOOL=y # CONFIG_CMDLINE_OVERRIDE is not set -# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_COMMON_CLK=y CONFIG_CPU_GENERIC_DUMP_TLB=y CONFIG_CPU_HAS_PREFETCH=y CONFIG_CPU_HAS_SYNC=y @@ -25,53 +29,66 @@ CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_CPU_MIPS32=y CONFIG_CPU_MIPS32_R1=y CONFIG_CPU_MIPSR1=y +CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y CONFIG_CPU_R4K_CACHE_TLB=y CONFIG_CPU_R4K_FPU=y CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y CONFIG_CPU_SUPPORTS_HIGHMEM=y CONFIG_CRC16=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_WORKQUEUE=y CONFIG_CSRC_R4K=y +CONFIG_DMA_MAYBE_COHERENT=y CONFIG_DMA_NONCOHERENT=y CONFIG_EARLY_PRINTK=y CONFIG_GENERIC_ATOMIC64=y CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_CHIP=y CONFIG_GENERIC_IRQ_SHOW=y CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_SCHED_CLOCK=y CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GPIOLIB=y CONFIG_GPIO_DEVRES=y CONFIG_HARDWARE_WATCHPOINTS=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y +CONFIG_HAS_IOPORT_MAP=y # CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +# CONFIG_HAVE_ARCH_BITREVERSE is not set CONFIG_HAVE_ARCH_JUMP_LABEL=y CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_HAVE_ARCH_TRACEHOOK=y # CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_BPF_JIT=y CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y CONFIG_HAVE_CONTEXT_TRACKING=y CONFIG_HAVE_C_RECORDMCOUNT=y CONFIG_HAVE_DEBUG_KMEMLEAK=y CONFIG_HAVE_DEBUG_STACKOVERFLOW=y CONFIG_HAVE_DMA_API_DEBUG=y CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_KERNEL_BZIP2=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_LATENCYTOP_SUPPORT=y CONFIG_HAVE_MEMBLOCK=y CONFIG_HAVE_MEMBLOCK_NODE_MAP=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y @@ -79,6 +96,7 @@ CONFIG_HAVE_NET_DSA=y CONFIG_HAVE_OPROFILE=y CONFIG_HAVE_PERF_EVENTS=y CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HW_HAS_PCI=y CONFIG_HW_RANDOM=y CONFIG_HZ=250 @@ -86,25 +104,26 @@ CONFIG_HZ=250 CONFIG_HZ_250=y CONFIG_HZ_PERIODIC=y CONFIG_INITRAMFS_SOURCE="" -CONFIG_IRQ_CPU=y +CONFIG_IRQ_DOMAIN=y CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_MIPS_CPU=y CONFIG_IRQ_WORK=y CONFIG_KEXEC=y +CONFIG_KEXEC_CORE=y CONFIG_LEDS_GPIO=y CONFIG_MAGIC_SYSRQ=y CONFIG_MDIO_BOARDINFO=y CONFIG_MIPS=y CONFIG_MIPS_ALCHEMY=y CONFIG_MIPS_AU1X00_ENET=y -CONFIG_MIPS_DB1000=y -# CONFIG_MIPS_DB1XXX is not set -# CONFIG_MIPS_DB1235 is not set +CONFIG_MIPS_CLOCK_VSYSCALL=y +CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER=y +CONFIG_MIPS_DB1XXX=y # CONFIG_MIPS_GPR is not set # CONFIG_MIPS_HUGE_TLB_SUPPORT is not set CONFIG_MIPS_L1_CACHE_SHIFT=5 # CONFIG_MIPS_MACHINE is not set # CONFIG_MIPS_MTX1 is not set -CONFIG_MIPS_MT_DISABLED=y # CONFIG_MIPS_XXS1500 is not set CONFIG_MODULES_USE_ELF_REL=y CONFIG_MODULE_FORCE_UNLOAD=y @@ -114,25 +133,31 @@ CONFIG_MTD_PHYSMAP=y CONFIG_NEED_DMA_MAP_STATE=y CONFIG_NEED_PER_CPU_KM=y CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y -CONFIG_PAGEFLAGS_EXTENDED=y +# CONFIG_NO_IOPORT_MAP is not set +# CONFIG_OF is not set CONFIG_PCI=y CONFIG_PCI_DOMAINS=y CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y CONFIG_PHYS_ADDR_T_64BIT=y -# CONFIG_PREEMPT_RCU is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_RATIONAL=y # CONFIG_RCU_STALL_COMMON is not set +CONFIG_SCHED_HRTICK=y +# CONFIG_SCHED_INFO is not set # CONFIG_SCSI_DMA is not set +# CONFIG_SERIAL_8250_FSL is not set CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SRCU=y # CONFIG_STANDALONE is not set +CONFIG_SYSCTL_EXCEPTION_TRACE=y CONFIG_SYS_HAS_CPU_MIPS32_R1=y CONFIG_SYS_HAS_EARLY_PRINTK=y CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y CONFIG_SYS_SUPPORTS_ZBOOT=y CONFIG_TICK_CPU_ACCOUNTING=y From a1a54cfb42de306db6c9a388cbbccd0d02a3693a Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 15 May 2016 20:42:36 +0200 Subject: [PATCH 03/37] at91: update to new image building code Signed-off-by: John Crispin --- target/linux/at91/image/Makefile | 186 ++++++++++++------ .../linux/at91/legacy/profiles/00-default.mk | 1 + target/linux/at91/legacy/profiles/atmel.mk | 86 -------- target/linux/at91/legacy/profiles/calamp.mk | 23 --- target/linux/at91/sama5d3/profiles/atmel.mk | 14 -- 5 files changed, 130 insertions(+), 180 deletions(-) delete mode 100644 target/linux/at91/legacy/profiles/atmel.mk delete mode 100644 target/linux/at91/legacy/profiles/calamp.mk delete mode 100644 target/linux/at91/sama5d3/profiles/atmel.mk diff --git a/target/linux/at91/image/Makefile b/target/linux/at91/image/Makefile index 767255ca3ff4..b80358debbb0 100644 --- a/target/linux/at91/image/Makefile +++ b/target/linux/at91/image/Makefile @@ -13,26 +13,23 @@ UBI_OPTS = -m 2048 -p 128KiB -s 512 AT91SAMA5D3XPLAINED_UBIFS_OPTS = -m 2048 -e 124KiB -c 2048 AT91SAMA5D3XPLAINED_UBI_OPTS = -m 2048 -p 128KiB -s 2048 -define Build/Clean - $(MAKE) -C u-boot clean -endef +DEVICE_VARS += KERNEL_PREFIX DTS -define Build/Compile - if [ $(CONFIG_AT91_UBOOT) ]; then \ - $(MAKE) -C u-boot compile; \ - fi -endef +KERNEL_LOADADDR := 0x20008000 -define Image/Prepare - cp $(LINUX_DIR)/arch/arm/boot/Image $(KDIR)/Image - cp $(LINUX_DIR)/arch/arm/boot/zImage $(KDIR)/zImage +define Device/Default + PROFILES = Default $$(DEVICE_NAME) + KERNEL_NAME := zImage2 + KERNEL_INITRAMFS_NAME := vmlinux-initramfs + KERNEL := append-dtb + DEVICE_TITLE := $$(DEVICE_NAME) + FILESYSTEMS := squashfs + IMAGES := uImage + IMAGE/uImage := append-kernel | uImage none endef -define MkuImageDtb - cat $(KDIR)/zImage $(DTS_DIR)/$(2).dtb > $(KDIR)/zImage-$(1) - mkimage -A arm -T kernel -C none -a 0x20008000 -e 0x20008000 \ - -n "OpenWrt ARM $(LINUX_VERSION)" \ - -d $(KDIR)/zImage-$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1)-uImage +define Build/append-dtb + cat $(KDIR)/zImage $(DTS_DIR)/$(DTS).dtb > $@ endef define MkOftree @@ -40,52 +37,113 @@ define MkOftree cp $(DTS_DIR)/$(2).dtb $(BIN_DIR)/$(IMG_PREFIX)-$(1)-oftree.dtb endef +ifeq ($(SUBTARGET),legacy) # Atmel -Image/Build/Kernel/AT91SAM9263EK=$(call MkuImageDtb,9263ek,at91sam9263ek) -Image/Build/Kernel/AT91SAM9G15EK=$(call MkuImageDtb,9g15ek,at91sam9g15ek) -Image/Build/Kernel/AT91SAM9G20EK=$(call MkOftree,9g20ek,at91sam9g20ek) -Image/Build/Kernel/AT91SAM9G20EK-2MMC=$(call MkOftree,9g20ek_2mmc,at91sam9g20ek_2mmc) -Image/Build/Kernel/AT91SAM9G25EK=$(call MkuImageDtb,9g25ek,at91sam9g25ek) -Image/Build/Kernel/AT91SAM9G35EK=$(call MkuImageDtb,9g35ek,at91sam9g35ek) -Image/Build/Kernel/AT91SAM9M10G45EK=$(call MkuImageDtb,9m10g45ek,at91sam9m10g45ek) -Image/Build/Kernel/AT91SAM9X25EK=$(call MkuImageDtb,9x25ek,at91sam9x25ek) -Image/Build/Kernel/AT91SAM9X35EK=$(call MkuImageDtb,9x35ek,at91sam9x35ek) -Image/Build/Kernel/AT91SAMA5D3XPLAINED=$(call MkuImageDtb,sama5,at91-sama5d3_xplained) +define Device/AT91SAM9263EK + DTS := at91sam9263ek +endef +TARGET_DEVICES += AT91SAM9263EK + +define Device/AT91SAM9G15EK + DTS := at91sam9g15ek +endef +TARGET_DEVICES += AT91SAM9G15EK + +define Device/AT91SAM9G20EK + DTS := at91sam9g20ek +endef +TARGET_DEVICES += AT91SAM9G20EK + +define Device/AT91SAM9G20EK-2MMC + DTS := at91sam9g20ek_2mmc +endef +TARGET_DEVICES += AT91SAM9G20EK-2MMC + +define Device/AT91SAM9G25EK + DTS := at91sam9g25ek +endef +TARGET_DEVICES += AT91SAM9G25EK + +define Device/AT91SAM9G35EK + DTS := at91sam9g35ek +endef +TARGET_DEVICES += AT91SAM9G35EK + +define Device/AT91SAM9M10G45EK + DTS := at91sam9m10g45ek +endef +TARGET_DEVICES += AT91SAM9M10G45EK + +define Device/AT91SAM9X25EK + DTS := at91sam9x25ek +endef +TARGET_DEVICES += AT91SAM9X25EK + +define Device/AT91SAM9X35EK + DTS := at91sam9x35ek +endef +TARGET_DEVICES += AT91SAM9X35EK + # CalAmp -Image/Build/Kernel/LMU5000=$(call MkuImageDtb,lmu5000,lmu5000) +define Device/LMU5000 + DTS := lmu5000 +endef +TARGET_DEVICES += LMU5000 + # Calao -Image/Build/Kernel/TNYA9260=$(call MkuImageDtb,tny_a9260,tny_a9260) -Image/Build/Kernel/TNYA9263=$(call MkuImageDtb,tny_a9263,tny_a9263) -Image/Build/Kernel/TNYA9G20=$(call MkuImageDtb,tny_a9g20,tny_a9g20) -Image/Build/Kernel/USBA9260=$(call MkuImageDtb,usb_a9260,usb_a9260) -Image/Build/Kernel/USBA9263=$(call MkuImageDtb,usb_a9263,usb_a9263) -Image/Build/Kernel/USBA9G20=$(call MkuImageDtb,usb_a9g20,usb_a9g20) +define Device/TNYA9260 + DTS := tny_a9260 +endef +TARGET_DEVICES += TNYA9260 + +define Device/TNYA9263 + DTS := tny_a9263 +endef +TARGET_DEVICES += TNYA9263 + +define Device/TNYA9G20 + DTS := tny_a9g20 +endef +TARGET_DEVICES += TNYA9G20 + +define Device/USBA9260 + DTS := usb_a9260 +endef +TARGET_DEVICES += USBA9260 + +define Device/USBA9263 + DTS := usb_a9263 +endef +TARGET_DEVICES += USBA9263 + +define Device/USBA9G20 + DTS := usb_a9g20 +endef +TARGET_DEVICES += USBA9G20 + # Ethernut -Image/Build/Kernel/ETHERNUT5=$(call MkuImageDtb,ethernut5,ethernut5) +define Device/ETHERNUT5 + DTS := ethernut5 +endef +TARGET_DEVICES += ETHERNUT5 + # Exegin -Image/Build/Kernel/Q5XR5=$(call MkOftree,q5xr5,at91-q5xr5) - - -define Image/Build/Kernel/Default - $(call Image/Build/Kernel/AT91SAM9263EK) - $(call Image/Build/Kernel/AT91SAM9G15EK) - $(call Image/Build/Kernel/AT91SAM9G20EK) - $(call Image/Build/Kernel/AT91SAM9G20EK-2MMC) - $(call Image/Build/Kernel/AT91SAM9G25EK) - $(call Image/Build/Kernel/AT91SAM9G35EK) - $(call Image/Build/Kernel/AT91SAM9M10G45EK) - $(call Image/Build/Kernel/AT91SAM9X25EK) - $(call Image/Build/Kernel/AT91SAM9X35EK) - $(call Image/Build/Kernel/LMU5000) - $(call Image/Build/Kernel/TNYA9260) - $(call Image/Build/Kernel/TNYA9263) - $(call Image/Build/Kernel/TNYA9G20) - $(call Image/Build/Kernel/USBA9260) - $(call Image/Build/Kernel/USBA9263) - $(call Image/Build/Kernel/USBA9G20) - $(call Image/Build/Kernel/ETHERNUT5) - $(call Image/Build/Kernel/Q5XR5) +define Device/Q5XR5 + DTS := at91-q5xr5 +endef +TARGET_DEVICES += Q5XR5 + +endif + +ifeq ($(SUBTARGET),sama5d3) + +define Device/AT91SAMA5D3XPLAINED + DTS := at91-sama5d3_xplained endef +TARGET_DEVICES += AT91SAMA5D3XPLAINED + +endif + define Image/BuildKernel mkimage -A arm -T kernel -C none -a 0x20008000 -e 0x20008000 -n linux-2.6 \ @@ -93,7 +151,21 @@ define Image/BuildKernel if [ $(CONFIG_FLEXIBITY_ROOT) ]; then \ $(INSTALL_BIN) $(BIN_DIR)/$(IMG_PREFIX)-uImage $(TARGET_DIR)/uImage ; \ fi - $(call Image/Build/Kernel/$(PROFILE)) +endef + +define Build/Clean + $(MAKE) -C u-boot clean +endef + +define Build/Compile + if [ $(CONFIG_AT91_UBOOT) ]; then \ + $(MAKE) -C u-boot compile; \ + fi +endef + +define Image/Prepare + cp $(LINUX_DIR)/arch/arm/boot/Image $(KDIR)/Image + cp $(LINUX_DIR)/arch/arm/boot/zImage $(KDIR)/zImage endef define Image/Build diff --git a/target/linux/at91/legacy/profiles/00-default.mk b/target/linux/at91/legacy/profiles/00-default.mk index 3ff040d2e48c..b85094e7adae 100644 --- a/target/linux/at91/legacy/profiles/00-default.mk +++ b/target/linux/at91/legacy/profiles/00-default.mk @@ -7,6 +7,7 @@ define Profile/Default NAME:=Default Profile + PRIORITY:=1 endef define Profile/Default/Description diff --git a/target/linux/at91/legacy/profiles/atmel.mk b/target/linux/at91/legacy/profiles/atmel.mk deleted file mode 100644 index 4b14f939eea0..000000000000 --- a/target/linux/at91/legacy/profiles/atmel.mk +++ /dev/null @@ -1,86 +0,0 @@ -# -# Copyright (C) 2013 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -define Profile/AT91SAM9263EK - NAME:=Atmel AT91SAM9263-EK -endef -define Profile/AT91SAM9263EK/Description - Atmel AT91SAM9263-EK eval board -endef -$(eval $(call Profile,AT91SAM9263EK)) - - -define Profile/AT91SAM9G15EK - NAME:=Atmel AT91SAM9G15-EK -endef -define Profile/AT91SAM9G15EK/Description - Atmel AT91SAM9G15-EK eval board -endef -$(eval $(call Profile,AT91SAM9G15EK)) - - -define Profile/AT91SAM9G20EK - NAME:=Atmel AT91SAM9G20-EK -endef -define Profile/AT91SAM9G20EK/Description - Atmel AT91SAM9G20-EK eval board -endef -$(eval $(call Profile,AT91SAM9G20EK)) - - -define Profile/AT91SAM9G20EK-2MMC - NAME:=Atmel AT91SAM9G20-EK 2MMC -endef -define Profile/AT91SAM9G20EK-2MMC/Description - Atmel AT91SAM9G20-EK eval board with 2 MMC -endef -$(eval $(call Profile,AT91SAM9G20EK-2MMC)) - - -define Profile/AT91SAM9G25EK - NAME:=Atmel AT91SAM9G25-EK -endef -define Profile/AT91SAM9G25EK/Description - Atmel AT91SAM9G25-EK eval board -endef -$(eval $(call Profile,AT91SAM9G25EK)) - - -define Profile/AT91SAM9G35EK - NAME:=Atmel AT91SAM9G35-EK -endef -define Profile/AT91SAM9G35EK/Description - Atmel AT91SAM9G35-EK eval board -endef -$(eval $(call Profile,AT91SAM9G35EK)) - - -define Profile/AT91SAM9M10G45EK - NAME:=Atmel AT91SAM9M10G45-EK -endef -define Profile/AT91SAM9M10G45EK/Description - Atmel AT91SAM9M10G45-EK eval board -endef -$(eval $(call Profile,AT91SAM9M10G45EK)) - - -define Profile/AT91SAM9X25EK - NAME:=Atmel AT91SAM9X25-EK -endef -define Profile/AT91SAM9X25EK/Description - Atmel AT91SAM9X25-EK eval board -endef -$(eval $(call Profile,AT91SAM9X25EK)) - - -define Profile/AT91SAM9X35EK - NAME:=Atmel AT91SAM9X35-EK -endef -define Profile/AT91SAM9X35EK/Description - Atmel AT91SAM9X35-EK eval board -endef -$(eval $(call Profile,AT91SAM9X35EK)) diff --git a/target/linux/at91/legacy/profiles/calamp.mk b/target/linux/at91/legacy/profiles/calamp.mk deleted file mode 100644 index 33f78e17ac1c..000000000000 --- a/target/linux/at91/legacy/profiles/calamp.mk +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (C) 2013 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -define Profile/LMU5000 - NAME:=CalAmp LMU5000 - PACKAGES:= \ - kmod-rtc-pcf2123 \ - kmod-usb-acm \ - kmod-usb-serial \ - kmod-usb-serial-option \ - kmod-usb-serial-sierrawireless \ - kmod-gpio-mcp23s08 -endef - -define Profile/LMU5000/Description - CalAmp LMU5000 -endef - -$(eval $(call Profile,LMU5000)) diff --git a/target/linux/at91/sama5d3/profiles/atmel.mk b/target/linux/at91/sama5d3/profiles/atmel.mk deleted file mode 100644 index 8a9b1ef2721c..000000000000 --- a/target/linux/at91/sama5d3/profiles/atmel.mk +++ /dev/null @@ -1,14 +0,0 @@ -# -# Copyright (C) 2014 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -define Profile/AT91SAMA5D3XPLAINED - NAME:=Atmel AT91SAMA5D3XPLAINED -endef -define Profile/AT91SAMA5D3XPLAINED/Description - Atmel AT91SAMA5D3EXPLAINED eval board -endef -$(eval $(call Profile,AT91SAMA5D3XPLAINED)) From 63973840eb79849f9b1fa4bbdfde6d4528c2631d Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 15 May 2016 09:44:34 +0200 Subject: [PATCH 04/37] octeon: convert to new image building code Signed-off-by: John Crispin --- target/linux/octeon/image/Makefile | 79 +++++++++------------ target/linux/octeon/profiles/000-Generic.mk | 12 ++-- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/target/linux/octeon/image/Makefile b/target/linux/octeon/image/Makefile index e74b06dd4b88..46c94ecacb5a 100644 --- a/target/linux/octeon/image/Makefile +++ b/target/linux/octeon/image/Makefile @@ -7,59 +7,50 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/image.mk -define Image/Prepare - # Workaround pre-SDK-1.9.0 u-boot versions not handling the .notes section - $(TARGET_CROSS)strip -R .notes $(KDIR)/vmlinux.elf -o $(KDIR)/vmlinux.elf.stripped +DEVICE_VARS += KERNEL_PREFIX + +define Device/Default + PROFILES = Default $$(DEVICE_NAME) + KERNEL_NAME := vmlinux.elf + KERNEL_INITRAMFS_NAME := vmlinux-initramfs.elf + KERNEL := kernel-bin | strip-kernel | patch-cmdline + IMAGES := sysupgrade.tar + FILESYSTEMS := squashfs + IMAGE/sysupgrade.tar := tar-file $$(FILESYSTEMS) +endef + +define Build/tar-file + mkdir -p $(KDIR)/sysupgrade-$(KERNEL_PREFIX)/ + echo "BOARD=$(KERNEL_PREFIX)" > $(KDIR)/sysupgrade-$(KERNEL_PREFIX)/CONTROL + $(CP) $(KDIR)/$(KERNEL_IMAGE) $(KDIR)/sysupgrade-$(KERNEL_PREFIX)/kernel + $(CP) $(KDIR)/root.$(1) $(KDIR)/sysupgrade-$(KERNEL_PREFIX)/root + (cd $(KDIR); $(TAR) cvf \ + $@ sysupgrade-$(KERNEL_PREFIX)) endef -define Image/BuildKernel/Template - $(CP) $(KDIR)/vmlinux.elf.stripped $(BIN_DIR)/$(IMG_PREFIX)-$(1)-vmlinux.64 - $(STAGING_DIR_HOST)/bin/patch-cmdline $(BIN_DIR)/$(IMG_PREFIX)-$(1)-vmlinux.64 '$(strip $(2))' - md5sum $(BIN_DIR)/$(IMG_PREFIX)-$(1)-vmlinux.64 | cut -d " " -f 1 | tee $(BIN_DIR)/$(IMG_PREFIX)-$(1)-vmlinux.64.md5 +define Build/strip-kernel + # Workaround pre-SDK-1.9.0 u-boot versions not handling the .notes section + $(TARGET_CROSS)strip -R .notes $@ -o $@.stripped && mv $@.stripped $@ endef -define Image/BuildKernel/Initramfs/Template - $(TARGET_CROSS)strip -R .notes $(KDIR)/vmlinux-initramfs.elf -o $(BIN_DIR)/$(IMG_PREFIX)-$(1)-vmlinux-initramfs.elf - $(STAGING_DIR_HOST)/bin/patch-cmdline $(BIN_DIR)/$(IMG_PREFIX)-$(1)-vmlinux-initramfs.elf '$(strip $(2))' +define Device/generic + FILESYSTEMS := ext4 + DEVICE_TITLE := Generic endef +TARGET_DEVICES += generic ER_CMDLINE:=-mtdparts=phys_mapped_flash:640k(boot0)ro,640k(boot1)ro,64k(eeprom)ro block2mtd.block2mtd=/dev/mmcblk0p2,65536,rootfs,5 root=/dev/mtdblock3 rootfstype=squashfs rootwait -ERLITE_CMDLINE:=-mtdparts=phys_mapped_flash:512k(boot0),512k(boot1),64k@1024k(eeprom) block2mtd.block2mtd=/dev/sda2,65536,rootfs,5 root=/dev/mtdblock3 rootfstype=squashfs rootwait - -define Image/BuildKernel - $(call Image/BuildKernel/Template,generic,) - $(call Image/BuildKernel/Template,er,$(ER_CMDLINE)) - $(call Image/BuildKernel/Template,erlite,$(ERLITE_CMDLINE)) -endef - -define Image/BuildKernel/Initramfs - $(call Image/BuildKernel/Initramfs/Template,generic,) - $(call Image/BuildKernel/Initramfs/Template,er,$(ER_CMDLINE)) - $(call Image/BuildKernel/Initramfs/Template,erlite,$(ERLITE_CMDLINE)) +define Device/er + CMDLINE := $(ER_CMDLINE) + DEVICE_TITLE := Ubiquiti EdgeRouter endef +TARGET_DEVICES += er -define Image/Build/sysupgrade - mkdir -p $(KDIR)/sysupgrade-$(1)/ - echo "BOARD=$(1)" > $(KDIR)/sysupgrade-$(1)/CONTROL - $(CP) $(BIN_DIR)/$(IMG_PREFIX)-$(2)-vmlinux.64 $(KDIR)/sysupgrade-$(1)/kernel - $(CP) $(KDIR)/root.$(3) $(KDIR)/sysupgrade-$(1)/root - (cd $(KDIR); $(TAR) cvf \ - $(BIN_DIR)/$(IMG_PREFIX)-$(1)-$(3)-sysupgrade.tar sysupgrade-$(1)) -endef - -define Image/Build/ext4 - $(call Image/Build/sysupgrade,erlite,generic,ext4) -endef - -define Image/Build/squashfs - $(call prepare_generic_squashfs,$(KDIR)/root.squashfs) - $(call Image/Build/sysupgrade,er,er,squashfs) - $(call Image/Build/sysupgrade,erlite,erlite,squashfs) -endef - -define Image/Build - $(call Image/Build/$(1)) - dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync +ERLITE_CMDLINE:=-mtdparts=phys_mapped_flash:512k(boot0),512k(boot1),64k@1024k(eeprom) block2mtd.block2mtd=/dev/sda2,65536,rootfs,5 root=/dev/mtdblock3 rootfstype=squashfs rootwait +define Device/erlite + CMDLINE := $(ERLITE_CMDLINE) + DEVICE_TITLE := Ubiquiti EdgeRouter Lite endef +TARGET_DEVICES += erlite $(eval $(call BuildImage)) diff --git a/target/linux/octeon/profiles/000-Generic.mk b/target/linux/octeon/profiles/000-Generic.mk index cf9a0137ba8c..d4c57675779d 100644 --- a/target/linux/octeon/profiles/000-Generic.mk +++ b/target/linux/octeon/profiles/000-Generic.mk @@ -5,13 +5,13 @@ # See /LICENSE for more information. # -define Profile/generic - NAME:=Generic Octeon board - PACKAGES:= +define Profile/Default + NAME:=Default Profile + PRIORITY:=1 endef -define Profile/generic/Description - Base packages for Octeon boards. +define Profile/Default/Description + Base packages for Octeon boards. endef -$(eval $(call Profile,generic)) +$(eval $(call Profile,Default)) From ccb2bd6154ca994b6f6b86a95c38ee3da7741ac5 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 3 Jun 2016 13:13:55 +0200 Subject: [PATCH 05/37] lantiq: fix io_space_limit this broke uhci pci support on some arv units Signed-off-by: John Crispin --- ...42-arch-mips-increase-io_space_limit.patch | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 target/linux/lantiq/patches-4.4/0042-arch-mips-increase-io_space_limit.patch diff --git a/target/linux/lantiq/patches-4.4/0042-arch-mips-increase-io_space_limit.patch b/target/linux/lantiq/patches-4.4/0042-arch-mips-increase-io_space_limit.patch new file mode 100644 index 000000000000..3bc2a62306da --- /dev/null +++ b/target/linux/lantiq/patches-4.4/0042-arch-mips-increase-io_space_limit.patch @@ -0,0 +1,28 @@ +From 9807eb80a1b3bad7a4a89aa6566497bb1cadd6ef Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 3 Jun 2016 13:12:20 +0200 +Subject: [PATCH] arch: mips: increase io_space_limit + +this value comes from x86 and breaks some pci devices + +Signed-off-by: John Crispin +--- + arch/mips/include/asm/io.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h +index d10fd80..d42eac9 100644 +--- a/arch/mips/include/asm/io.h ++++ b/arch/mips/include/asm/io.h +@@ -50,7 +50,7 @@ + + /* ioswab[bwlq], __mem_ioswab[bwlq] are defined in mangle-port.h */ + +-#define IO_SPACE_LIMIT 0xffff ++#define IO_SPACE_LIMIT 0x200000 + + /* + * On MIPS I/O ports are memory mapped, so we access them using normal +-- +1.7.10.4 + From 4bc438be7f7bfcb5ddf32e2e35643ddc49a20019 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 6 Jun 2016 21:16:47 +0200 Subject: [PATCH 06/37] package/*: update git urls for project repos Signed-off-by: John Crispin --- package/libs/librpc/Makefile | 2 +- package/libs/libubox/Makefile | 2 +- package/libs/uclient/Makefile | 2 +- package/libs/ustream-ssl/Makefile | 2 +- package/network/config/firewall/Makefile | 2 +- package/network/config/netifd/Makefile | 2 +- package/network/services/mdns/Makefile | 2 +- package/network/services/relayd/Makefile | 2 +- package/network/services/uhttpd/Makefile | 2 +- package/network/utils/iwinfo/Makefile | 2 +- package/network/utils/umbim/Makefile | 2 +- package/network/utils/uqmi/Makefile | 2 +- package/system/fstools/Makefile | 2 +- package/system/mountd/Makefile | 2 +- package/system/procd/Makefile | 2 +- package/system/rpcd/Makefile | 2 +- package/system/ubox/Makefile | 2 +- package/system/ubus/Makefile | 2 +- package/system/uci/Makefile | 2 +- package/system/usign/Makefile | 2 +- package/utils/jsonfilter/Makefile | 2 +- package/utils/ugps/Makefile | 2 +- package/utils/usbmode/Makefile | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/package/libs/librpc/Makefile b/package/libs/librpc/Makefile index d24cdd95d6a8..e1f7ad414d0e 100644 --- a/package/libs/librpc/Makefile +++ b/package/libs/librpc/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2015-11-04 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/librpc-uclibc.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/librpc-uclibc.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=a921e3ded051746f9f7cd5e5a312fb6771716aac PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/libs/libubox/Makefile b/package/libs/libubox/Makefile index 97cac7bf5e8c..8b0e1d8c82fc 100644 --- a/package/libs/libubox/Makefile +++ b/package/libs/libubox/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2016-05-19 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/libubox.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/libubox.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=1257a38a6e64511207bb3b077ca7e8e1a3338fc1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/libs/uclient/Makefile b/package/libs/uclient/Makefile index 58734aa18da3..895dab58c40b 100644 --- a/package/libs/uclient/Makefile +++ b/package/libs/uclient/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2016-01-28 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/uclient.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/uclient.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=2e0918c7e0612449024caaaa8d44fb2d7a33f5f3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/libs/ustream-ssl/Makefile b/package/libs/ustream-ssl/Makefile index 1729e82a816a..6719cd3ff756 100644 --- a/package/libs/ustream-ssl/Makefile +++ b/package/libs/ustream-ssl/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2016-06-07 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/ustream-ssl.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/ustream-ssl.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=17085b7abc0cd09c64ccace6f8d16ddee5729678 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/network/config/firewall/Makefile b/package/network/config/firewall/Makefile index ffce0c37bfa0..c379219d5823 100644 --- a/package/network/config/firewall/Makefile +++ b/package/network/config/firewall/Makefile @@ -13,7 +13,7 @@ PKG_VERSION:=2016-05-02 PKG_RELEASE:=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/firewall3.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/firewall3.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=6cccf1ba7f0c3eb34ef4a7adc6af501376bfa875 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/network/config/netifd/Makefile b/package/network/config/netifd/Makefile index 82fcb3e48e83..d9c63eb8de6b 100644 --- a/package/network/config/netifd/Makefile +++ b/package/network/config/netifd/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2016-06-06 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/netifd.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/netifd.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=99e6dc68bbac5a57a0ebca810a9dc36e38667821 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/network/services/mdns/Makefile b/package/network/services/mdns/Makefile index 6d026c3f80d1..624ada30fd24 100644 --- a/package/network/services/mdns/Makefile +++ b/package/network/services/mdns/Makefile @@ -13,7 +13,7 @@ PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/mdnsd.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/mdnsd.git PKG_SOURCE_PROTO:=git PKG_SOURCE_VERSION:=8a70b2b47dd328f8180e5ecaa7bdc817f574a81b diff --git a/package/network/services/relayd/Makefile b/package/network/services/relayd/Makefile index 937b98165e1c..6559770d0049 100644 --- a/package/network/services/relayd/Makefile +++ b/package/network/services/relayd/Makefile @@ -13,7 +13,7 @@ PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/relayd.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/relayd.git PKG_SOURCE_PROTO:=git PKG_SOURCE_VERSION:=ad0b25ad74345d367c62311e14b279f5ccb8ef13 diff --git a/package/network/services/uhttpd/Makefile b/package/network/services/uhttpd/Makefile index 3408c940187e..fa4af5be01d1 100644 --- a/package/network/services/uhttpd/Makefile +++ b/package/network/services/uhttpd/Makefile @@ -12,7 +12,7 @@ PKG_VERSION:=2015-11-08 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/uhttpd.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/uhttpd.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=fe01ef3f52adae9da38ef47926cd50974af5d6b7 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/network/utils/iwinfo/Makefile b/package/network/utils/iwinfo/Makefile index 4e442c37fab5..d9922b1cbcf5 100644 --- a/package/network/utils/iwinfo/Makefile +++ b/package/network/utils/iwinfo/Makefile @@ -11,7 +11,7 @@ PKG_VERSION:=2016-01-25 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/iwinfo.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/iwinfo.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=e4aca3910dff532ed878d0ceaf1ab6e8ad7719bf PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/network/utils/umbim/Makefile b/package/network/utils/umbim/Makefile index 54152fe4618e..fbd70d04211a 100644 --- a/package/network/utils/umbim/Makefile +++ b/package/network/utils/umbim/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2015-04-09 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/umbim.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/umbim.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=af9c293c1f1d8a97fbd8adf9c6070ead4920ca84 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/network/utils/uqmi/Makefile b/package/network/utils/uqmi/Makefile index f8423608f228..59821e572793 100644 --- a/package/network/utils/uqmi/Makefile +++ b/package/network/utils/uqmi/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2015-09-17 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/uqmi.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/uqmi.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=8a97586e9445a60e355dea13aa87885ab3dcb277 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile index 3d3c6a13eb0e..b4e8ded35e98 100644 --- a/package/system/fstools/Makefile +++ b/package/system/fstools/Makefile @@ -13,7 +13,7 @@ PKG_VERSION:=2016-05-23 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/fstools.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/fstools.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=0453f48e509077c83129b8aaceecb4e4430c8309 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/system/mountd/Makefile b/package/system/mountd/Makefile index d27b572f5fbf..32eb1e00cc21 100644 --- a/package/system/mountd/Makefile +++ b/package/system/mountd/Makefile @@ -9,7 +9,7 @@ PKG_VERSION:=2015-11-22 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/mountd.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/mountd.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=8476a03b25d457e99f59e6372b8d9faebe2266f8 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile index a02061c87df7..04771cd487dc 100644 --- a/package/system/procd/Makefile +++ b/package/system/procd/Makefile @@ -13,7 +13,7 @@ PKG_VERSION:=2016-06-03 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/procd.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/procd.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=b8eb07c22fc5f3dea04d9843e8fd6d2eac6e61fa PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/system/rpcd/Makefile b/package/system/rpcd/Makefile index 6545c0db9119..ac90f56ab6df 100644 --- a/package/system/rpcd/Makefile +++ b/package/system/rpcd/Makefile @@ -12,7 +12,7 @@ PKG_VERSION:=2016-04-13 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/rpcd.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/rpcd.git PKG_SOURCE_SUBDIR:=$(PKG_NAME) PKG_SOURCE_VERSION:=73aea9b8b621a1ce034bc6ee00c9d058a40c8a3d PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/system/ubox/Makefile b/package/system/ubox/Makefile index d9e8ce338fd5..61a465300275 100644 --- a/package/system/ubox/Makefile +++ b/package/system/ubox/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2016-06-08 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/ubox.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/ubox.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=fd4bb41ee7ab136d25609c2a917beea5d52b723b PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/system/ubus/Makefile b/package/system/ubus/Makefile index 51356706ac6c..284c5cd66779 100644 --- a/package/system/ubus/Makefile +++ b/package/system/ubus/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2016-06-01 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/ubus.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/ubus.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=96ab0b3032f5caf443162f38073403a372b3e1c1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/system/uci/Makefile b/package/system/uci/Makefile index ae6104fac429..2d2c0a179f8e 100644 --- a/package/system/uci/Makefile +++ b/package/system/uci/Makefile @@ -17,7 +17,7 @@ PKG_RELEASE:=1 PKG_REV:=ec96e1f93d6d0faa3f3c40f6bcbc0006550281a8 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/uci.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/uci.git PKG_SOURCE_SUBDIR:=uci-$(PKG_VERSION) PKG_SOURCE_VERSION:=$(PKG_REV) PKG_SOURCE_PROTO:=git diff --git a/package/system/usign/Makefile b/package/system/usign/Makefile index 5b40ce9630fb..77db61f06e03 100644 --- a/package/system/usign/Makefile +++ b/package/system/usign/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2015-05-08 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/usign.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/usign.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=cf8dcdb8a4e874c77f3e9a8e9b643e8c17b19131 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/utils/jsonfilter/Makefile b/package/utils/jsonfilter/Makefile index 79cc3854f546..4a98a4b1dd3c 100644 --- a/package/utils/jsonfilter/Makefile +++ b/package/utils/jsonfilter/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2016-06-01 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/jsonpath.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/jsonpath.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=7151885df6ac2554c07cc6047dde7c4eb253ce87 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz diff --git a/package/utils/ugps/Makefile b/package/utils/ugps/Makefile index bee1fdad1b74..6f139d0dc1b6 100644 --- a/package/utils/ugps/Makefile +++ b/package/utils/ugps/Makefile @@ -12,7 +12,7 @@ PKG_VERSION:=2015-08-17 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/ugps.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/ugps.git PKG_SOURCE_PROTO:=git PKG_SOURCE_VERSION:=971e6703eb9bed936cc62cd335105bd2acca14ef PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.bz2 diff --git a/package/utils/usbmode/Makefile b/package/utils/usbmode/Makefile index b4e41a252ce0..4b481126b3b1 100644 --- a/package/utils/usbmode/Makefile +++ b/package/utils/usbmode/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2014-08-26 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(OPENWRT_GIT)/project/usbmode.git +PKG_SOURCE_URL=$(LEDE_GIT)/project/usbmode.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=993a9a542791953c4804f7ddbb3a07756738e37a PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz From f43899532f78bdc1530eb3e0169c866577000f39 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 7 Jun 2016 18:59:26 +0200 Subject: [PATCH 07/37] lantiq: add default lan setup to board.d script Signed-off-by: John Crispin --- target/linux/lantiq/base-files/etc/board.d/02_network | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/linux/lantiq/base-files/etc/board.d/02_network b/target/linux/lantiq/base-files/etc/board.d/02_network index a3dc80c54b16..f254d9cd678a 100755 --- a/target/linux/lantiq/base-files/etc/board.d/02_network +++ b/target/linux/lantiq/base-files/etc/board.d/02_network @@ -145,6 +145,9 @@ VGV7510KW22) ucidef_add_switch "switch0" \ "2:lan:1" "3:lan:2" "4:lan:3" "5:lan:4" "6t@eth0" ;; +*) + ucidef_set_interface_lan 'eth0' + ;; esac From 04e1f324703d9fd9128123c30053919a71d8c906 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 7 Jun 2016 18:56:51 +0200 Subject: [PATCH 08/37] lantiq: fix a regression in the eiu irq loading code this worked in 3.18 but broke at some point. the old code that loaded a irq table was incorrewct anyhow as it mapped the irqs int he domain which should really be done when the driver using them loads them and not the irq driver itself. Signed-off-by: John Crispin --- .../lantiq/patches-4.4/0047-irq-fixes.patch | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 target/linux/lantiq/patches-4.4/0047-irq-fixes.patch diff --git a/target/linux/lantiq/patches-4.4/0047-irq-fixes.patch b/target/linux/lantiq/patches-4.4/0047-irq-fixes.patch new file mode 100644 index 000000000000..f11e057a80ae --- /dev/null +++ b/target/linux/lantiq/patches-4.4/0047-irq-fixes.patch @@ -0,0 +1,78 @@ +--- a/arch/mips/lantiq/irq.c ++++ b/arch/mips/lantiq/irq.c +@@ -67,7 +67,7 @@ + #endif + + static int exin_avail; +-static struct resource ltq_eiu_irq[MAX_EIU]; ++static u32 ltq_eiu_irq[MAX_EIU]; + static void __iomem *ltq_icu_membase[MAX_IM]; + static void __iomem *ltq_eiu_membase; + static struct irq_domain *ltq_domain; +@@ -76,7 +76,7 @@ + int ltq_eiu_get_irq(int exin) + { + if (exin < exin_avail) +- return ltq_eiu_irq[exin].start; ++ return ltq_eiu_irq[exin]; + return -1; + } + +@@ -128,7 +128,7 @@ + int i; + + for (i = 0; i < MAX_EIU; i++) { +- if (d->hwirq == ltq_eiu_irq[i].start) { ++ if (d->hwirq == ltq_eiu_irq[i]) { + int val = 0; + int edge = 0; + +@@ -176,7 +176,7 @@ + + ltq_enable_irq(d); + for (i = 0; i < MAX_EIU; i++) { +- if (d->hwirq == ltq_eiu_irq[i].start) { ++ if (d->hwirq == ltq_eiu_irq[i]) { + /* by default we are low level triggered */ + ltq_eiu_settype(d, IRQF_TRIGGER_LOW); + /* clear all pending */ +@@ -198,7 +198,7 @@ + + ltq_disable_irq(d); + for (i = 0; i < MAX_EIU; i++) { +- if (d->hwirq == ltq_eiu_irq[i].start) { ++ if (d->hwirq == ltq_eiu_irq[i]) { + /* disable */ + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i), + LTQ_EIU_EXIN_INEN); +@@ -343,10 +343,10 @@ + return 0; + + for (i = 0; i < exin_avail; i++) +- if (hw == ltq_eiu_irq[i].start) ++ if (hw == ltq_eiu_irq[i]) + chip = <q_eiu_type; + +- irq_set_chip_and_handler(hw, chip, handle_level_irq); ++ irq_set_chip_and_handler(irq, chip, handle_level_irq); + + return 0; + } +@@ -441,14 +441,14 @@ + eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway"); + if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { + /* find out how many external irq sources we have */ +- exin_avail = of_irq_count(eiu_node); ++ exin_avail = of_property_count_u32_elems(eiu_node, "lantiq,eiu-irqs"); + + if (exin_avail > MAX_EIU) + exin_avail = MAX_EIU; + +- ret = of_irq_to_resource_table(eiu_node, ++ ret = of_property_read_u32_array(eiu_node, "lantiq,eiu-irqs", + ltq_eiu_irq, exin_avail); +- if (ret != exin_avail) ++ if (ret) + panic("failed to load external irq resources"); + + if (!request_mem_region(res.start, resource_size(&res), From d01f91fe4f25c5c682cee443aeeb9d672d68a29a Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 7 Jun 2016 18:59:52 +0200 Subject: [PATCH 09/37] lantiq: use new property name for eiu irqs Signed-off-by: John Crispin --- target/linux/lantiq/dts/amazonse.dtsi | 2 +- target/linux/lantiq/dts/ar9.dtsi | 2 +- target/linux/lantiq/dts/danube.dtsi | 2 +- target/linux/lantiq/dts/vr9.dtsi | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/linux/lantiq/dts/amazonse.dtsi b/target/linux/lantiq/dts/amazonse.dtsi index c0bba436d1c3..c58610635931 100644 --- a/target/linux/lantiq/dts/amazonse.dtsi +++ b/target/linux/lantiq/dts/amazonse.dtsi @@ -45,7 +45,7 @@ compatible = "lantiq,eiu-xway"; reg = <0x101000 0x1000>; interrupt-parent = <&icu0>; - interrupts = <29 30 31>; + lantiq,eiu-irqs = <29 30 31>; }; pmu0: pmu@102000 { diff --git a/target/linux/lantiq/dts/ar9.dtsi b/target/linux/lantiq/dts/ar9.dtsi index 9feb8a0e512e..e67bcc2a1038 100644 --- a/target/linux/lantiq/dts/ar9.dtsi +++ b/target/linux/lantiq/dts/ar9.dtsi @@ -50,7 +50,7 @@ compatible = "lantiq,eiu-xway"; reg = <0x101000 0x1000>; interrupt-parent = <&icu0>; - interrupts = <166 135 66 40 41 42>; + lantiq,eiu-irqs = <166 135 66 40 41 42>; }; pmu0: pmu@102000 { diff --git a/target/linux/lantiq/dts/danube.dtsi b/target/linux/lantiq/dts/danube.dtsi index 0a75fd9d45ca..a785af42660f 100644 --- a/target/linux/lantiq/dts/danube.dtsi +++ b/target/linux/lantiq/dts/danube.dtsi @@ -54,7 +54,7 @@ compatible = "lantiq,eiu-xway"; reg = <0x101000 0x1000>; interrupt-parent = <&icu0>; - interrupts = <166 135 66>; + lantiq,eiu-irqs = <166 135 66>; }; pmu0: pmu@102000 { diff --git a/target/linux/lantiq/dts/vr9.dtsi b/target/linux/lantiq/dts/vr9.dtsi index aa34a5f3e7a5..15d73a50be05 100644 --- a/target/linux/lantiq/dts/vr9.dtsi +++ b/target/linux/lantiq/dts/vr9.dtsi @@ -50,7 +50,7 @@ compatible = "lantiq,eiu-xway"; reg = <0x101000 0x1000>; interrupt-parent = <&icu0>; - interrupts = <166 135 66 40 41 42>; + lantiq,eiu-irqs = <166 135 66 40 41 42>; }; pmu0: pmu@102000 { From 21ec7114529a38be2e30640893ec637038b6a1e3 Mon Sep 17 00:00:00 2001 From: Adrian Panella Date: Mon, 16 May 2016 02:10:56 -0500 Subject: [PATCH 10/37] mac80211: ath10k fix otp check patch Fix patch to match new updated package version Signed-off-by: Adrian Panella --- package/kernel/mac80211/patches/936-ath10k_skip_otp_check.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/kernel/mac80211/patches/936-ath10k_skip_otp_check.patch b/package/kernel/mac80211/patches/936-ath10k_skip_otp_check.patch index 39aba41df4d2..1f967b073fb1 100644 --- a/package/kernel/mac80211/patches/936-ath10k_skip_otp_check.patch +++ b/package/kernel/mac80211/patches/936-ath10k_skip_otp_check.patch @@ -35,7 +35,7 @@ + if (ret && ret != -EOPNOTSUPP) { + ath10k_err(ar, "failed to get board id from otp: %d\n", + ret); -+ return ret; ++ goto err_free_firmware_files; + } } From f7223c8d40bde6162c541de3c8acf7bfd6180db5 Mon Sep 17 00:00:00 2001 From: Adrian Panella Date: Thu, 19 May 2016 09:45:38 -0500 Subject: [PATCH 11/37] mtd: add linksys_bootcount for ipq806x Reset bc is needed for Linksys EA8500's dual boot. Signed-off-by: Adrian Panella --- package/system/mtd/src/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/package/system/mtd/src/Makefile b/package/system/mtd/src/Makefile index 94a2a1a3ac4b..70c61e58ae1f 100644 --- a/package/system/mtd/src/Makefile +++ b/package/system/mtd/src/Makefile @@ -12,6 +12,7 @@ obj.brcm63xx = imagetag.o obj.ramips = $(obj.seama) obj.mvebu = linksys_bootcount.o obj.kirkwood = linksys_bootcount.o +obj.ipq806x = linksys_bootcount.o ifdef FIS_SUPPORT obj += fis.o From 11b057e0eea980691d8ce2eb8f557150e05fd768 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 7 Jun 2016 19:19:01 +0200 Subject: [PATCH 12/37] uboot-envtools: add ipq806x support Signed-off-by: Adrian Panella --- package/boot/uboot-envtools/Makefile | 4 ++++ package/boot/uboot-envtools/files/ipq | 26 ++++++++++++++++++++++++++ target/linux/ipq806x/Makefile | 3 ++- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100755 package/boot/uboot-envtools/files/ipq diff --git a/package/boot/uboot-envtools/Makefile b/package/boot/uboot-envtools/Makefile index a5b0f923101e..fd41005aac70 100644 --- a/package/boot/uboot-envtools/Makefile +++ b/package/boot/uboot-envtools/Makefile @@ -85,6 +85,10 @@ ifneq ($(CONFIG_TARGET_imx6),) $(INSTALL_DIR) $(1)/etc/uci-defaults $(INSTALL_DATA) ./files/imx6 $(1)/etc/uci-defaults/30_uboot-envtools endif +ifneq ($(CONFIG_TARGET_ipq806x),) + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_DATA) ./files/ipq $(1)/etc/uci-defaults/30_uboot-envtools +endif ifneq ($(CONFIG_TARGET_kirkwood),) $(INSTALL_DIR) $(1)/etc/uci-defaults $(INSTALL_DATA) ./files/kirkwood $(1)/etc/uci-defaults/30_uboot-envtools diff --git a/package/boot/uboot-envtools/files/ipq b/package/boot/uboot-envtools/files/ipq new file mode 100755 index 000000000000..8cf0ddbb061c --- /dev/null +++ b/package/boot/uboot-envtools/files/ipq @@ -0,0 +1,26 @@ +#!/bin/sh +# +# Copyright (C) 2016 LEDE +# + +[ -e /etc/config/ubootenv ] && exit 0 + +touch /etc/config/ubootenv + +. /lib/ipq806x.sh +. /lib/uboot-envtools.sh +. /lib/functions.sh + +board=$(ipq806x_board_name) + + +case "$board" in +"ea8500") + ubootenv_add_uci_config "/dev/mtd10" "0x0" "0x20000" "0x20000" + ;; +esac + +config_load ubootenv +config_foreach ubootenv_add_app_config ubootenv + +exit 0 diff --git a/target/linux/ipq806x/Makefile b/target/linux/ipq806x/Makefile index 50e9467c5d97..a4d2bff59e6b 100644 --- a/target/linux/ipq806x/Makefile +++ b/target/linux/ipq806x/Makefile @@ -20,6 +20,7 @@ DEFAULT_PACKAGES += \ kmod-ata-core kmod-ata-ahci kmod-ata-ahci-platform \ kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-ledtrig-usbdev \ kmod-usb3 kmod-usb-dwc3-qcom kmod-usb-phy-qcom-dwc3 \ - kmod-ath10k ath10k-firmware-qca99x0 wpad-mini + kmod-ath10k ath10k-firmware-qca99x0 wpad-mini \ + uboot-envtools $(eval $(call BuildTarget)) From 2909d4549be2e1bfa46db5ce78eae5a24ef9f691 Mon Sep 17 00:00:00 2001 From: Adrian Panella Date: Mon, 30 May 2016 14:56:50 -0500 Subject: [PATCH 13/37] ipq806x: qcom rpm fix support for smb208 In commit "regulator: qcom: Rework to single platform device" the smb208 regulator used in IPQ8064 was left out. Add it to that new framework and update Docs and DT accordingly. Signed-off-by: Adrian Panella --- ...-ARM-qcom_rpm_fix_support_for_smb208.patch | 50 +++++++++++++ .../168-ARM-qcom-add-smb208-DT.patch | 74 +++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 target/linux/ipq806x/patches-4.4/167-ARM-qcom_rpm_fix_support_for_smb208.patch create mode 100644 target/linux/ipq806x/patches-4.4/168-ARM-qcom-add-smb208-DT.patch diff --git a/target/linux/ipq806x/patches-4.4/167-ARM-qcom_rpm_fix_support_for_smb208.patch b/target/linux/ipq806x/patches-4.4/167-ARM-qcom_rpm_fix_support_for_smb208.patch new file mode 100644 index 000000000000..8da70340def1 --- /dev/null +++ b/target/linux/ipq806x/patches-4.4/167-ARM-qcom_rpm_fix_support_for_smb208.patch @@ -0,0 +1,50 @@ + +In commit "regulator: qcom: Rework to single platform device" the smb208 regulator +used in IPQ8064 was left out. + +Add it to that new framework and update Docs accordingly. + +Signed-off-by: Adrian Panella + +--- a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt ++++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt +@@ -59,6 +59,7 @@ Regulator nodes are identified by their + "qcom,rpm-pm8058-regulators" + "qcom,rpm-pm8901-regulators" + "qcom,rpm-pm8921-regulators" ++ "qcom,rpm-smb208-regulators" + + - vdd_l0_l1_lvs-supply: + - vdd_l2_l11_l12-supply: +@@ -156,6 +157,9 @@ pm8921: + l29, lvs1, lvs2, lvs3, lvs4, lvs5, lvs6, lvs7, usb-switch, hdmi-switch, + ncp + ++smb208: ++ s1a, s1b, s2a, s2b ++ + The content of each sub-node is defined by the standard binding for regulators - + see regulator.txt - with additional custom properties described below: + +--- a/drivers/regulator/qcom_rpm-regulator.c ++++ b/drivers/regulator/qcom_rpm-regulator.c +@@ -869,10 +869,19 @@ static const struct rpm_regulator_data r + { } + }; + ++static const struct rpm_regulator_data rpm_smb208_regulators[] = { ++ { "s1a", QCOM_RPM_SMB208_S1a, &smb208_smps, "vin_s1a" }, ++ { "s1b", QCOM_RPM_SMB208_S1b, &smb208_smps, "vin_s1b" }, ++ { "s2a", QCOM_RPM_SMB208_S2a, &smb208_smps, "vin_s2a" }, ++ { "s2b", QCOM_RPM_SMB208_S2b, &smb208_smps, "vin_s2b" }, ++ { } ++}; ++ + static const struct of_device_id rpm_of_match[] = { + { .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators }, + { .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators }, + { .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators }, ++ { .compatible = "qcom,rpm-smb208-regulators", .data = &rpm_smb208_regulators }, + { } + }; + MODULE_DEVICE_TABLE(of, rpm_of_match); diff --git a/target/linux/ipq806x/patches-4.4/168-ARM-qcom-add-smb208-DT.patch b/target/linux/ipq806x/patches-4.4/168-ARM-qcom-add-smb208-DT.patch new file mode 100644 index 000000000000..503654d98880 --- /dev/null +++ b/target/linux/ipq806x/patches-4.4/168-ARM-qcom-add-smb208-DT.patch @@ -0,0 +1,74 @@ +Change DT to use new smb208 regulator driver. + +Signed-off-by: Adrian Panella + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -167,45 +167,37 @@ + #address-cells = <1>; + #size-cells = <0>; + +- smb208_s1a: smb208-s1a { +- compatible = "qcom,rpm-smb208"; +- reg = ; +- +- regulator-min-microvolt = <1050000>; +- regulator-max-microvolt = <1150000>; ++ regulators { ++ compatible = "qcom,rpm-smb208-regulators"; + +- qcom,switch-mode-frequency = <1200000>; +- +- }; ++ smb208_s1a: s1a { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; + +- smb208_s1b: smb208-s1b { +- compatible = "qcom,rpm-smb208"; +- reg = ; ++ qcom,switch-mode-frequency = <1200000>; + +- regulator-min-microvolt = <1050000>; +- regulator-max-microvolt = <1150000>; +- +- qcom,switch-mode-frequency = <1200000>; +- }; ++ }; + +- smb208_s2a: smb208-s2a { +- compatible = "qcom,rpm-smb208"; +- reg = ; ++ smb208_s1b: s1b { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; + +- regulator-min-microvolt = < 800000>; +- regulator-max-microvolt = <1250000>; ++ qcom,switch-mode-frequency = <1200000>; ++ }; + +- qcom,switch-mode-frequency = <1200000>; +- }; ++ smb208_s2a: s2a { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; + +- smb208_s2b: smb208-s2b { +- compatible = "qcom,rpm-smb208"; +- reg = ; ++ qcom,switch-mode-frequency = <1200000>; ++ }; + +- regulator-min-microvolt = < 800000>; +- regulator-max-microvolt = <1250000>; ++ smb208_s2b: s2b { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; + +- qcom,switch-mode-frequency = <1200000>; ++ qcom,switch-mode-frequency = <1200000>; ++ }; + }; + }; + From f22d5656f7faa3ac0f215ae20ddf3311b81b8ac7 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 7 Jun 2016 19:29:10 +0200 Subject: [PATCH 14/37] ipq806x: build Linksys EA8500 images Signed-off-by: Adrian Panella --- target/linux/ipq806x/image/Makefile | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/target/linux/ipq806x/image/Makefile b/target/linux/ipq806x/image/Makefile index 77391d043fc0..455ea1eb72ce 100644 --- a/target/linux/ipq806x/image/Makefile +++ b/target/linux/ipq806x/image/Makefile @@ -149,6 +149,23 @@ define Device/DB149 DEVICE_TITLE := Qualcom DB149 endef +define Device/EA8500 + $(call Device/LegacyImage) + DEVICE_DTS := qcom-ipq8064-ea8500 + PAGESIZE := 2048 + BLOCKSIZE := 128KiB + KERNEL_SIZE := 3145728 + FILESYSTEMS := squashfs + KERNEL = kernel-bin | append-dtb | uImage none | append-file $(KDIR)/root.dummy + PROFILES += $$(DEVICE_NAME) + BOARD_NAME := ea8500 + IMAGES := factory.bin sysupgrade.tar + IMAGE/factory.bin := append-kernel 3145728 | append-ubi + IMAGE/sysupgrade.tar := sysupgrade-nand + DEVICE_VARS += DEVICE_DTS KERNEL_SIZE PAGESIZE BLOCKSIZE SUBPAGESIZE + DEVICE_TITLE := Linksys EA8500 +endef + define Device/R7500 $(call Device/DniImage) DEVICE_DTS := qcom-ipq8064-r7500 @@ -161,6 +178,6 @@ define Device/R7500 DEVICE_TITLE := Netgear Nighthawk X4 R7500 endef -TARGET_DEVICES += AP148 AP148-legacy C2600 D7800 DB149 R7500 +TARGET_DEVICES += AP148 AP148-legacy C2600 D7800 DB149 EA8500 R7500 $(eval $(call BuildImage)) From e656fd1bcfadf9aa2c4f4c3e29e00f5801f778db Mon Sep 17 00:00:00 2001 From: Adrian Panella Date: Fri, 13 May 2016 01:13:15 -0500 Subject: [PATCH 15/37] ipq806x: base-files: add support for Linksys EA8500 Signed-off-by: Adrian Panella --- .../ipq806x/base-files/etc/board.d/01_leds | 4 + .../ipq806x/base-files/etc/board.d/02_network | 9 ++ target/linux/ipq806x/base-files/etc/diag.sh | 3 + .../etc/hotplug.d/firmware/11-ath10k-caldata | 8 ++ .../base-files/etc/init.d/linksys_recovery | 20 +++++ .../linux/ipq806x/base-files/lib/ipq806x.sh | 3 + .../ipq806x/base-files/lib/upgrade/linksys.sh | 88 +++++++++++++++++++ .../base-files/lib/upgrade/platform.sh | 7 ++ 8 files changed, 142 insertions(+) create mode 100755 target/linux/ipq806x/base-files/etc/init.d/linksys_recovery create mode 100644 target/linux/ipq806x/base-files/lib/upgrade/linksys.sh diff --git a/target/linux/ipq806x/base-files/etc/board.d/01_leds b/target/linux/ipq806x/base-files/etc/board.d/01_leds index 392dc8b5e7d8..568b4827b764 100755 --- a/target/linux/ipq806x/base-files/etc/board.d/01_leds +++ b/target/linux/ipq806x/base-files/etc/board.d/01_leds @@ -27,6 +27,10 @@ r7500) ucidef_set_led_default "wps" "WPS" "r7500:white:wps" "0" ucidef_set_led_default "rfkill" "rfkill" "r7500:white:rfkill" "0" ;; +ea8500) + ucidef_set_led_wlan "wifi" "WIFI" "ea8500:green:wifi" "phy0radio" + ucidef_set_led_default "wps" "WPS" "ea8500:green:wps" "0" + ;; *) ;; esac diff --git a/target/linux/ipq806x/base-files/etc/board.d/02_network b/target/linux/ipq806x/base-files/etc/board.d/02_network index e3c9137a5a2d..67969669f1a5 100755 --- a/target/linux/ipq806x/base-files/etc/board.d/02_network +++ b/target/linux/ipq806x/base-files/etc/board.d/02_network @@ -6,6 +6,7 @@ . /lib/functions/uci-defaults.sh . /lib/ipq806x.sh +. /lib/functions/system.sh board_config_update @@ -24,6 +25,14 @@ db149) ucidef_add_switch "switch0" \ "1:lan" "2:lan" "3:lan" "4:lan" "6@eth1" "5:wan" "0@eth0" ;; +ea8500) + + hw_mac_addr=$(mtd_get_mac_ascii devinfo hw_mac_addr) + ucidef_add_switch "switch0" \ + "1:lan" "2:lan" "3:lan" "4:lan" "0t@eth0" "5:wan" "0t@eth0" + ucidef_set_interface_macaddr "lan" "$hw_mac_addr" + ucidef_set_interface_macaddr "wan" "$hw_mac_addr" + ;; *) echo "Unsupported hardware. Network interfaces not intialized" ;; diff --git a/target/linux/ipq806x/base-files/etc/diag.sh b/target/linux/ipq806x/base-files/etc/diag.sh index b19012c4e53e..6b3622dc580c 100755 --- a/target/linux/ipq806x/base-files/etc/diag.sh +++ b/target/linux/ipq806x/base-files/etc/diag.sh @@ -8,6 +8,9 @@ get_status_led() { c2600) status_led="status:blue" ;; + ea8500) + status_led="ea8500:white:power" + ;; esac } diff --git a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata index 5f604e1a264a..24da5500b551 100644 --- a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +++ b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -52,6 +52,10 @@ case "$FIRMWARE" in ath10kcal_extract "radio" 4096 12064 # ath10kcal_patch_mac $(macaddr_add $(mtd_get_mac_binary default-mac 8) -1) ;; + ea8500) + hw_mac_addr=$(mtd_get_mac_ascii devinfo hw_mac_addr) + ath10kcal_extract "art" 4096 12064 + ;; esac ;; "ath10k/cal-pci-0001:01:00.0.bin") @@ -60,6 +64,10 @@ case "$FIRMWARE" in ath10kcal_extract "radio" 20480 12064 # ath10kcal_patch_mac $(macaddr_add $(mtd_get_mac_binary default-mac 8) -2) ;; + ea8500) + hw_mac_addr=$(mtd_get_mac_ascii devinfo hw_mac_addr) + ath10kcal_extract "art" 20480 12064 + ;; esac ;; *) diff --git a/target/linux/ipq806x/base-files/etc/init.d/linksys_recovery b/target/linux/ipq806x/base-files/etc/init.d/linksys_recovery new file mode 100755 index 000000000000..b9ea00420714 --- /dev/null +++ b/target/linux/ipq806x/base-files/etc/init.d/linksys_recovery @@ -0,0 +1,20 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2015 OpenWrt.org + +START=97 +boot() { +. /lib/functions.sh +. /lib/ipq806x.sh + +case $(ipq806x_board_name) in + ea8500) + # make sure auto_recovery in uboot is always on + AUTO_RECOVERY_ENA="`fw_printenv -n auto_recovery`" + if [ "$AUTO_RECOVERY_ENA" != "yes" ] ; then + fw_setenv auto_recovery yes + fi + # reset the boot counter + mtd resetbc s_env + ;; +esac +} diff --git a/target/linux/ipq806x/base-files/lib/ipq806x.sh b/target/linux/ipq806x/base-files/lib/ipq806x.sh index 73202c0b8814..8157e6afac6e 100644 --- a/target/linux/ipq806x/base-files/lib/ipq806x.sh +++ b/target/linux/ipq806x/base-files/lib/ipq806x.sh @@ -29,6 +29,9 @@ ipq806x_board_detect() { *"R7500") name="r7500" ;; + *"Linksys EA8500"*) + name="ea8500" + ;; esac [ -z "$name" ] && name="unknown" diff --git a/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh b/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh new file mode 100644 index 000000000000..ca5161a61b9a --- /dev/null +++ b/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh @@ -0,0 +1,88 @@ +# +# Copyright (C) 2014-2015 OpenWrt.org +# + +linksys_get_target_firmware() { + cur_boot_part=`/usr/sbin/fw_printenv -n boot_part` + target_firmware="" + if [ "$cur_boot_part" = "1" ] + then + # current primary boot - update alt boot + target_firmware="kernel2" + fw_setenv boot_part 2 + #In EA8500 bootcmd is always "bootipq", so don't change + #fw_setenv bootcmd "run altnandboot" + elif [ "$cur_boot_part" = "2" ] + then + # current alt boot - update primary boot + target_firmware="kernel1" + fw_setenv boot_part 1 + #In EA8500 bootcmd is always "bootipq", so don't change + #fw_setenv bootcmd "run nandboot" + fi + + # re-enable recovery so we get back if the new firmware is broken + fw_setenv auto_recovery yes + + echo "$target_firmware" +} + +linksys_get_root_magic() { + (get_image "$@" | dd skip=786432 bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2>/dev/null +} + +platform_do_upgrade_linksys() { + local magic_long="$(get_magic_long "$1")" + + mkdir -p /var/lock + local part_label="$(linksys_get_target_firmware)" + touch /var/lock/fw_printenv.lock + + if [ ! -n "$part_label" ] + then + echo "cannot find target partition" + exit 1 + fi + + local target_mtd=$(find_mtd_part $part_label) + + [ "$magic_long" = "73797375" ] && { + CI_KERNPART="$part_label" + if [ "$part_label" = "kernel1" ] + then + CI_UBIPART="rootfs1" + else + CI_UBIPART="rootfs2" + fi + + nand_upgrade_tar "$1" + } + [ "$magic_long" = "27051956" ] && { + # check firmwares' rootfs types + local target_mtd=$(find_mtd_part $part_label) + local oldroot="$(linksys_get_root_magic $target_mtd)" + local newroot="$(linksys_get_root_magic "$1")" + + if [ "$newroot" = "55424923" -a "$oldroot" = "55424923" ] + # we're upgrading from a firmware with UBI to one with UBI + then + # erase everything to be safe + mtd erase $part_label + get_image "$1" | mtd -n write - $part_label + else + get_image "$1" | mtd write - $part_label + fi + } +} + +linksys_preupgrade() { + export RAMFS_COPY_BIN="${RAMFS_COPY_BIN} /usr/sbin/fw_printenv /usr/sbin/fw_setenv" + export RAMFS_COPY_BIN="${RAMFS_COPY_BIN} /bin/mkdir /bin/touch" + export RAMFS_COPY_DATA="${RAMFS_COPY_DATA} /etc/fw_env.config /var/lock/fw_printenv.lock" + + [ -f /tmp/sysupgrade.tgz ] && { + cp /tmp/sysupgrade.tgz /tmp/syscfg/sysupgrade.tgz + } +} + +append sysupgrade_pre_upgrade linksys_preupgrade diff --git a/target/linux/ipq806x/base-files/lib/upgrade/platform.sh b/target/linux/ipq806x/base-files/lib/upgrade/platform.sh index a181f13b43a2..2b6f61d7be15 100644 --- a/target/linux/ipq806x/base-files/lib/upgrade/platform.sh +++ b/target/linux/ipq806x/base-files/lib/upgrade/platform.sh @@ -8,6 +8,7 @@ platform_check_image() { case "$board" in ap148 |\ d7800 |\ + ea8500 |\ r7500) nand_do_platform_check $board $1 return $?; @@ -34,6 +35,9 @@ platform_pre_upgrade() { r7500) nand_do_upgrade "$1" ;; + ea8500) + linksys_preupgrade "$1" + ;; esac } @@ -46,5 +50,8 @@ platform_do_upgrade() { MTD_CONFIG_ARGS="-s 0x200000" default_do_upgrade "$ARGV" ;; + ea8500) + platform_do_upgrade_linksys "$ARGV" + ;; esac } From b5c826898596f02ae985570ea4a79187de72edca Mon Sep 17 00:00:00 2001 From: Adrian Panella Date: Wed, 25 May 2016 14:06:54 -0500 Subject: [PATCH 16/37] ipq806x: add mangle bootargs options in config-4.4 Add config options to manage dual boot partitions, using MANGLE BOOTARGS Signed-off-by: Adrian Panella --- target/linux/ipq806x/config-4.4 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target/linux/ipq806x/config-4.4 b/target/linux/ipq806x/config-4.4 index 408fc6d3e9b1..430f1f709f3a 100644 --- a/target/linux/ipq806x/config-4.4 +++ b/target/linux/ipq806x/config-4.4 @@ -37,11 +37,13 @@ CONFIG_ARM_AMBA=y CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ARCH_TIMER=y CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y -# CONFIG_ARM_ATAG_DTB_COMPAT is not set CONFIG_ARM_CCI=y CONFIG_ARM_CCI400_COMMON=y CONFIG_ARM_CCI400_PMU=y CONFIG_ARM_CCI_PMU=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set CONFIG_ARM_CPU_SUSPEND=y CONFIG_ARM_GIC=y CONFIG_ARM_HAS_SG_CHAIN=y @@ -249,6 +251,7 @@ CONFIG_LOCKUP_DETECTOR=y CONFIG_LOCK_SPIN_ON_OWNER=y CONFIG_LZO_COMPRESS=y CONFIG_LZO_DECOMPRESS=y +CONFIG_MANGLE_BOOTARGS=y CONFIG_MDIO_BITBANG=y CONFIG_MDIO_BOARDINFO=y CONFIG_MDIO_GPIO=y From c8d7a9f610298f73cd2e41318321e23ada933307 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 7 Jun 2016 20:33:35 +0200 Subject: [PATCH 17/37] ipg806x: set v4.4 as default Signed-off-by: John Crispin --- target/linux/ipq806x/Makefile | 2 +- target/linux/ipq806x/config-3.18 | 452 -- .../001-spi-qup-Add-DMA-capabilities.patch | 522 -- ...pi-qup-Fix-incorrect-block-transfers.patch | 376 -- .../003-spi-qup-Ensure-done-detection.patch | 56 - ...og-qcom-use-timer-devicetree-binding.patch | 67 - ...-description-of-KPSS-WDT-for-IPQ8064.patch | 48 - ...hdog-entries-to-DT-timer-binding-doc.patch | 50 - .../patches-3.18/020-add-ap148-bootargs.patch | 46 - .../021-add-ap148-partitions.patch | 19 - .../patches-3.18/022-add-db149-dts.patch | 160 - ...-ipq806x-Disable-i2c-device-on-gsbi4.patch | 53 - .../024-ap148-add-memory-node.patch | 14 - ...pinlock-core-add-device-tree-support.patch | 167 - ...Add-support-for-Qualcomm-HW-Mutex-bl.patch | 234 - ...ock-qcom-Correct-msb-in-regmap_field.patch | 26 - ...M-qcom-add-SFPB-nodes-to-IPQ806x-dts.patch | 34 - ...com-Add-device-tree-binding-for-SMEM.patch | 82 - ...com-Add-Shared-Memory-Manager-driver.patch | 841 ---- ...-add-SMEM-device-node-to-IPQ806x-dts.patch | 36 - ...d-add-SMEM-parser-for-QCOM-platforms.patch | 277 -- ...-Add-Qualcomm-DWC3-HS-SS-PHY-drivers.patch | 511 -- ...-qcom-add-USB-nodes-to-ipq806x-ap148.patch | 126 - ...gsbi-Add-support-for-ADM-CRCI-muxing.patch | 249 - .../103-ARM-DT-ipq8064-Add-TCSR-support.patch | 65 - ...om-Document-PCIe-devicetree-bindings.patch | 263 - ...-Add-Qualcomm-PCIe-controller-driver.patch | 753 --- ...-add-pcie-nodes-to-ipq806x-platforms.patch | 244 - ...ically-select-PCI_DOMAINS-if-PCI-is-.patch | 29 - .../patches-3.18/114-pcie-add-ctlr-init.patch | 311 -- .../115-add-pcie-aux-clk-dts.patch | 80 - ...qcom-rpm-Driver-for-the-Qualcomm-RPM.patch | 654 --- ...mfd-qcom_rpm-Add-support-for-IPQ8064.patch | 71 - ...bindings-Add-Qualcomm-RPM-DT-binding.patch | 247 - ...-qcom_rpm-Document-IPQ8064-resources.patch | 42 - ...dd-support-for-RPM-controller-SMB208.patch | 58 - ...pm-Add-missing-state-flag-in-call-to.patch | 25 - .../126-add-rpm-to-ipq8064-dts.patch | 87 - ...parent-doing-the-wrong-thing-when-IN.patch | 55 - ...Add-__clk_mux_determine_rate_closest.patch | 120 - ...gister_-divider-gate-mux-to-close-me.patch | 115 - ...Krait-L2-register-accessor-functions.patch | 144 - ...lit-out-register-accessors-for-reuse.patch | 192 - ...to-downstream-clocks-during-set_rate.patch | 129 - .../136-clk-Add-safe-switch-hook.patch | 170 - ...pport-for-High-Frequency-PLLs-HFPLLs.patch | 351 -- .../138-clk-qcom-Add-HFPLL-driver.patch | 206 - .../139-clk-qcom-Add-IPQ806X-s-HFPLLs.patch | 127 - ...lk-qcom-Add-support-for-Krait-clocks.patch | 271 -- ...141-clk-qcom-Add-KPSS-ACC-GCC-driver.patch | 205 - ...om-Add-Krait-clock-controller-driver.patch | 435 -- ...le-to-register-cpufreq-on-Krait-CPUs.patch | 304 -- ...-necessary-DT-data-for-Krait-cpufreq.patch | 100 - ...-Add-a-cpufreq-krait-based-on-cpufre.patch | 461 -- .../150-dmaengine-Rework-dma_chan_get.patch | 70 - ...e-the-need-to-declare-device_control.patch | 27 - ...hannel-allocation-callbacks-optional.patch | 62 - ...e-Introduce-a-device_config-callback.patch | 51 - ...ne-Add-device_terminate_all-callback.patch | 47 - ...ings-qcom_adm-Fix-channel-specifiers.patch | 76 - .../156-dmaengine-Add-ADM-driver.patch | 958 ---- ...7-ARM-DT-ipq8064-Add-ADM-device-node.patch | 42 - ...clk-qcom-Add-EBI2-clocks-for-IPQ806x.patch | 74 - ...access-bad-block-markers-in-raw-mode.patch | 84 - ...nand-Qualcomm-NAND-controller-driver.patch | 2024 -------- ...-bindings-qcom_nandc-Add-DT-bindings.patch | 82 - ...Add-NAND-controller-node-for-ipq806x.patch | 51 - ...-NAND-node-on-IPQ8064-AP148-platform.patch | 79 - ...m-dts-enable-qcom-smem-on-AP148-NAND.patch | 11 - ...arch-arm-force-ZRELADDR-on-arch-qcom.patch | 62 - ...tgear-Nighthawk-X4-R7500-device-tree.patch | 367 -- .../302-mtd-qcom-smem-rename-rootfs-ubi.patch | 13 - ...pport-for-NSS-GMAC-clocks-and-resets.patch | 733 --- .../701-stmmac_update_to_4.3.patch | 4258 ----------------- ...s-qcom-add-mdio-nodes-to-ap148-db149.patch | 146 - ...-add-gmac-nodes-to-ipq806x-platforms.patch | 216 - ...dd-support-for-retreiving-mac-from-m.patch | 31 - ...stmmac-fix-ipq806x-DMA-configuration.patch | 117 - ...tgear-Nighthawk-X4-D7800-device-tree.patch | 381 -- ...RM-qcom-add-TPLink-C2600-device-tree.patch | 425 -- 80 files changed, 1 insertion(+), 21248 deletions(-) delete mode 100644 target/linux/ipq806x/config-3.18 delete mode 100644 target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch delete mode 100644 target/linux/ipq806x/patches-3.18/002-v3-spi-qup-Fix-incorrect-block-transfers.patch delete mode 100644 target/linux/ipq806x/patches-3.18/003-spi-qup-Ensure-done-detection.patch delete mode 100644 target/linux/ipq806x/patches-3.18/011-watchdog-qcom-use-timer-devicetree-binding.patch delete mode 100644 target/linux/ipq806x/patches-3.18/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch delete mode 100644 target/linux/ipq806x/patches-3.18/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch delete mode 100644 target/linux/ipq806x/patches-3.18/020-add-ap148-bootargs.patch delete mode 100644 target/linux/ipq806x/patches-3.18/021-add-ap148-partitions.patch delete mode 100644 target/linux/ipq806x/patches-3.18/022-add-db149-dts.patch delete mode 100644 target/linux/ipq806x/patches-3.18/023-ARM-dts-ipq806x-Disable-i2c-device-on-gsbi4.patch delete mode 100644 target/linux/ipq806x/patches-3.18/024-ap148-add-memory-node.patch delete mode 100644 target/linux/ipq806x/patches-3.18/030-hwspinlock-core-add-device-tree-support.patch delete mode 100644 target/linux/ipq806x/patches-3.18/031-hwspinlock-qcom-Add-support-for-Qualcomm-HW-Mutex-bl.patch delete mode 100644 target/linux/ipq806x/patches-3.18/032-hwspinlock-qcom-Correct-msb-in-regmap_field.patch delete mode 100644 target/linux/ipq806x/patches-3.18/033-ARM-qcom-add-SFPB-nodes-to-IPQ806x-dts.patch delete mode 100644 target/linux/ipq806x/patches-3.18/034-soc-qcom-Add-device-tree-binding-for-SMEM.patch delete mode 100644 target/linux/ipq806x/patches-3.18/035-soc-qcom-Add-Shared-Memory-Manager-driver.patch delete mode 100644 target/linux/ipq806x/patches-3.18/036-ARM-qcom-add-SMEM-device-node-to-IPQ806x-dts.patch delete mode 100644 target/linux/ipq806x/patches-3.18/037-mtd-add-SMEM-parser-for-QCOM-platforms.patch delete mode 100644 target/linux/ipq806x/patches-3.18/100-usb-phy-Add-Qualcomm-DWC3-HS-SS-PHY-drivers.patch delete mode 100644 target/linux/ipq806x/patches-3.18/101-ARM-qcom-add-USB-nodes-to-ipq806x-ap148.patch delete mode 100644 target/linux/ipq806x/patches-3.18/102-soc-qcom-gsbi-Add-support-for-ADM-CRCI-muxing.patch delete mode 100644 target/linux/ipq806x/patches-3.18/103-ARM-DT-ipq8064-Add-TCSR-support.patch delete mode 100644 target/linux/ipq806x/patches-3.18/110-DT-PCI-qcom-Document-PCIe-devicetree-bindings.patch delete mode 100644 target/linux/ipq806x/patches-3.18/111-PCI-qcom-Add-Qualcomm-PCIe-controller-driver.patch delete mode 100644 target/linux/ipq806x/patches-3.18/112-ARM-dts-qcom-add-pcie-nodes-to-ipq806x-platforms.patch delete mode 100644 target/linux/ipq806x/patches-3.18/113-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch delete mode 100644 target/linux/ipq806x/patches-3.18/114-pcie-add-ctlr-init.patch delete mode 100644 target/linux/ipq806x/patches-3.18/115-add-pcie-aux-clk-dts.patch delete mode 100644 target/linux/ipq806x/patches-3.18/120-mfd-qcom-rpm-Driver-for-the-Qualcomm-RPM.patch delete mode 100644 target/linux/ipq806x/patches-3.18/121-mfd-qcom_rpm-Add-support-for-IPQ8064.patch delete mode 100644 target/linux/ipq806x/patches-3.18/122-mfd-devicetree-bindings-Add-Qualcomm-RPM-DT-binding.patch delete mode 100644 target/linux/ipq806x/patches-3.18/123-mfd-devicetree-qcom_rpm-Document-IPQ8064-resources.patch delete mode 100644 target/linux/ipq806x/patches-3.18/124-regulator-rpm-add-support-for-RPM-controller-SMB208.patch delete mode 100644 target/linux/ipq806x/patches-3.18/125-regulator-qcom-rpm-Add-missing-state-flag-in-call-to.patch delete mode 100644 target/linux/ipq806x/patches-3.18/126-add-rpm-to-ipq8064-dts.patch delete mode 100644 target/linux/ipq806x/patches-3.18/130-clk_mux-Fix-set_parent-doing-the-wrong-thing-when-IN.patch delete mode 100644 target/linux/ipq806x/patches-3.18/131-clk-Add-__clk_mux_determine_rate_closest.patch delete mode 100644 target/linux/ipq806x/patches-3.18/132-clk-Add-clk_unregister_-divider-gate-mux-to-close-me.patch delete mode 100644 target/linux/ipq806x/patches-3.18/133-ARM-Add-Krait-L2-register-accessor-functions.patch delete mode 100644 target/linux/ipq806x/patches-3.18/134-clk-mux-Split-out-register-accessors-for-reuse.patch delete mode 100644 target/linux/ipq806x/patches-3.18/135-clk-Avoid-sending-high-rates-to-downstream-clocks-during-set_rate.patch delete mode 100644 target/linux/ipq806x/patches-3.18/136-clk-Add-safe-switch-hook.patch delete mode 100644 target/linux/ipq806x/patches-3.18/137-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch delete mode 100644 target/linux/ipq806x/patches-3.18/138-clk-qcom-Add-HFPLL-driver.patch delete mode 100644 target/linux/ipq806x/patches-3.18/139-clk-qcom-Add-IPQ806X-s-HFPLLs.patch delete mode 100644 target/linux/ipq806x/patches-3.18/140-clk-qcom-Add-support-for-Krait-clocks.patch delete mode 100644 target/linux/ipq806x/patches-3.18/141-clk-qcom-Add-KPSS-ACC-GCC-driver.patch delete mode 100644 target/linux/ipq806x/patches-3.18/142-clk-qcom-Add-Krait-clock-controller-driver.patch delete mode 100644 target/linux/ipq806x/patches-3.18/143-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch delete mode 100644 target/linux/ipq806x/patches-3.18/144-ARM-dts-qcom-Add-necessary-DT-data-for-Krait-cpufreq.patch delete mode 100644 target/linux/ipq806x/patches-3.18/145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch delete mode 100644 target/linux/ipq806x/patches-3.18/150-dmaengine-Rework-dma_chan_get.patch delete mode 100644 target/linux/ipq806x/patches-3.18/151-dmaengine-Remove-the-need-to-declare-device_control.patch delete mode 100644 target/linux/ipq806x/patches-3.18/152-dmaengine-Make-channel-allocation-callbacks-optional.patch delete mode 100644 target/linux/ipq806x/patches-3.18/153-dmaengine-Introduce-a-device_config-callback.patch delete mode 100644 target/linux/ipq806x/patches-3.18/154-dmaengine-Add-device_terminate_all-callback.patch delete mode 100644 target/linux/ipq806x/patches-3.18/155-dt-bindings-qcom_adm-Fix-channel-specifiers.patch delete mode 100644 target/linux/ipq806x/patches-3.18/156-dmaengine-Add-ADM-driver.patch delete mode 100644 target/linux/ipq806x/patches-3.18/157-ARM-DT-ipq8064-Add-ADM-device-node.patch delete mode 100644 target/linux/ipq806x/patches-3.18/160-clk-qcom-Add-EBI2-clocks-for-IPQ806x.patch delete mode 100644 target/linux/ipq806x/patches-3.18/161-mtd-nand-Create-a-BBT-flag-to-access-bad-block-markers-in-raw-mode.patch delete mode 100644 target/linux/ipq806x/patches-3.18/162-mtd-nand-Qualcomm-NAND-controller-driver.patch delete mode 100644 target/linux/ipq806x/patches-3.18/163-dt-bindings-qcom_nandc-Add-DT-bindings.patch delete mode 100644 target/linux/ipq806x/patches-3.18/164-arm-qcom-dts-Add-NAND-controller-node-for-ipq806x.patch delete mode 100644 target/linux/ipq806x/patches-3.18/165-arm-qcom-dts-Enable-NAND-node-on-IPQ8064-AP148-platform.patch delete mode 100644 target/linux/ipq806x/patches-3.18/166-arch-qcom-dts-enable-qcom-smem-on-AP148-NAND.patch delete mode 100644 target/linux/ipq806x/patches-3.18/300-arch-arm-force-ZRELADDR-on-arch-qcom.patch delete mode 100644 target/linux/ipq806x/patches-3.18/301-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch delete mode 100644 target/linux/ipq806x/patches-3.18/302-mtd-qcom-smem-rename-rootfs-ubi.patch delete mode 100644 target/linux/ipq806x/patches-3.18/700-clk-qcom-Add-support-for-NSS-GMAC-clocks-and-resets.patch delete mode 100644 target/linux/ipq806x/patches-3.18/701-stmmac_update_to_4.3.patch delete mode 100644 target/linux/ipq806x/patches-3.18/707-ARM-dts-qcom-add-mdio-nodes-to-ap148-db149.patch delete mode 100644 target/linux/ipq806x/patches-3.18/708-ARM-dts-qcom-add-gmac-nodes-to-ipq806x-platforms.patch delete mode 100644 target/linux/ipq806x/patches-3.18/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch delete mode 100644 target/linux/ipq806x/patches-3.18/710-stmmac-fix-ipq806x-DMA-configuration.patch delete mode 100644 target/linux/ipq806x/patches-3.18/801-ARM-qcom-add-Netgear-Nighthawk-X4-D7800-device-tree.patch delete mode 100644 target/linux/ipq806x/patches-3.18/802-ARM-qcom-add-TPLink-C2600-device-tree.patch diff --git a/target/linux/ipq806x/Makefile b/target/linux/ipq806x/Makefile index a4d2bff59e6b..d070b05e0086 100644 --- a/target/linux/ipq806x/Makefile +++ b/target/linux/ipq806x/Makefile @@ -10,7 +10,7 @@ CPU_TYPE:=cortex-a9 CPU_SUBTYPE:=neon-vfpv4 MAINTAINER:=John Crispin -KERNEL_PATCHVER:=3.18 +KERNEL_PATCHVER:=4.4 KERNELNAME:=zImage Image dtbs diff --git a/target/linux/ipq806x/config-3.18 b/target/linux/ipq806x/config-3.18 deleted file mode 100644 index 68a8933748d3..000000000000 --- a/target/linux/ipq806x/config-3.18 +++ /dev/null @@ -1,452 +0,0 @@ -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_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_REQUIRE_GPIOLIB=y -# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set -# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_ARCH_SUPPORTS_UPROBES=y -CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USE_BUILTIN_BSWAP=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_WANT_GENERAL_HUGETLB=y -CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y -CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y -CONFIG_ARM=y -CONFIG_ARM_AMBA=y -CONFIG_ARM_APPENDED_DTB=y -CONFIG_ARM_ARCH_TIMER=y -CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y -# CONFIG_ARM_ATAG_DTB_COMPAT is not set -CONFIG_ARM_CPU_SUSPEND=y -CONFIG_ARM_GIC=y -CONFIG_ARM_HAS_SG_CHAIN=y -# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set -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_QCOM_CPUFREQ=y -# 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_AT803X_PHY=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_CPUFREQ_DT is not set -CONFIG_CPU_32v6K=y -CONFIG_CPU_32v7=y -CONFIG_CPU_ABRT_EV7=y -# CONFIG_CPU_BPREDICT_DISABLE is not set -CONFIG_CPU_CACHE_V7=y -CONFIG_CPU_CACHE_VIPT=y -CONFIG_CPU_COPY_V6=y -CONFIG_CPU_CP15=y -CONFIG_CPU_CP15_MMU=y -CONFIG_CPU_FREQ=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -# CONFIG_CPU_FREQ_GOV_USERSPACE is not set -CONFIG_CPU_FREQ_STAT=y -# CONFIG_CPU_FREQ_STAT_DETAILS is not set -CONFIG_CPU_HAS_ASID=y -# CONFIG_CPU_ICACHE_DISABLE is not set -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_GOV_LADDER=y -CONFIG_CPU_IDLE_GOV_MENU=y -CONFIG_CPU_PABRT_V7=y -CONFIG_CPU_PM=y -CONFIG_CPU_RMAP=y -# CONFIG_CPU_THERMAL is not set -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_DEFLATE=y -CONFIG_CRYPTO_LZO=y -CONFIG_CRYPTO_RNG2=y -# CONFIG_CRYPTO_SHA1_ARM_NEON is not set -# CONFIG_CRYPTO_SHA512_ARM_NEON is not set -CONFIG_CRYPTO_WORKQUEUE=y -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_UART_PL01X is not set -# CONFIG_DEBUG_USER is not set -CONFIG_DECOMPRESS_GZIP=y -CONFIG_DMADEVICES=y -CONFIG_DMA_ENGINE=y -CONFIG_DMA_OF=y -CONFIG_DMA_VIRTUAL_CHANNELS=y -CONFIG_DTC=y -# CONFIG_DWMAC_GENERIC is not set -CONFIG_DWMAC_IPQ806X=y -# CONFIG_DWMAC_LPC18XX is not set -# CONFIG_DWMAC_MESON is not set -# CONFIG_DWMAC_ROCKCHIP is not set -# CONFIG_DWMAC_SOCFPGA is not set -# CONFIG_DWMAC_STI is not set -# CONFIG_DWMAC_SUNXI is not set -# CONFIG_DW_DMAC_CORE is not set -# CONFIG_DW_DMAC_PCI is not set -CONFIG_DYNAMIC_DEBUG=y -CONFIG_ETHERNET_PACKET_MANGLE=y -CONFIG_FIXED_PHY=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_CPUFREQ_KRAIT=y -CONFIG_GENERIC_IDLE_POLL_SETUP=y -CONFIG_GENERIC_IO=y -CONFIG_GENERIC_IRQ_SHOW=y -CONFIG_GENERIC_PCI_IOMAP=y -CONFIG_GENERIC_PHY=y -CONFIG_GENERIC_PINCONF=y -CONFIG_GENERIC_SCHED_CLOCK=y -CONFIG_GENERIC_SMP_IDLE_THREAD=y -CONFIG_GENERIC_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_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_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_HWSPINLOCK=y -CONFIG_HWSPINLOCK_QCOM=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_API=y -CONFIG_IOMMU_HELPER=y -CONFIG_IOMMU_PGTABLES_L2=y -CONFIG_IOMMU_SUPPORT=y -CONFIG_IPQ_GCC_806X=y -CONFIG_IRQCHIP=y -CONFIG_IRQ_DOMAIN=y -CONFIG_IRQ_FORCED_THREADING=y -CONFIG_IRQ_WORK=y -CONFIG_KPSS_XCC=y -CONFIG_KRAITCC=y -CONFIG_KRAIT_CLOCKS=y -CONFIG_KRAIT_L2_ACCESSORS=y -# CONFIG_LEDS_REGULATOR is not set -CONFIG_LIBFDT=y -CONFIG_LOCKUP_DETECTOR=y -CONFIG_LZO_COMPRESS=y -CONFIG_LZO_DECOMPRESS=y -CONFIG_MDIO_BITBANG=y -CONFIG_MDIO_BOARDINFO=y -CONFIG_MDIO_GPIO=y -CONFIG_MFD_QCOM_RPM=y -# CONFIG_MFD_SPMI_PMIC is not set -CONFIG_MFD_SYSCON=y -CONFIG_MIGHT_HAVE_CACHE_L2X0=y -CONFIG_MIGHT_HAVE_PCI=y -CONFIG_MIGRATION=y -CONFIG_MODULES_USE_ELF_REL=y -CONFIG_MSM_GCC_8660=y -CONFIG_MSM_GCC_8960=y -CONFIG_MSM_GCC_8974=y -CONFIG_MSM_IOMMU=y -CONFIG_MSM_MMCC_8960=y -CONFIG_MSM_MMCC_8974=y -CONFIG_MTD_CMDLINE_PARTS=y -# CONFIG_MTD_IMPA7 is not set -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_ECC=y -CONFIG_MTD_NAND_QCOM=y -CONFIG_MTD_QCOM_SMEM_PARTS=y -CONFIG_MTD_SPI_NOR=y -CONFIG_MTD_SPLIT_FIRMWARE=y -CONFIG_MTD_SPLIT_FIT_FW=y -CONFIG_MTD_UBI=y -CONFIG_MTD_UBI_BEB_LIMIT=20 -CONFIG_MTD_UBI_BLOCK=y -# CONFIG_MTD_UBI_FASTMAP is not set -# CONFIG_MTD_UBI_GLUEBI is not set -CONFIG_MTD_UBI_WL_THRESHOLD=4096 -CONFIG_MULTI_IRQ_HANDLER=y -CONFIG_MUTEX_SPIN_ON_OWNER=y -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_NEON=y -CONFIG_NET_FLOW_LIMIT=y -CONFIG_NET_PTP_CLASSIFY=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_IOMMU=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_PCIEAER=y -CONFIG_PCIEPORTBUS=y -CONFIG_PCIE_DW=y -CONFIG_PCIE_PME=y -CONFIG_PCIE_QCOM=y -CONFIG_PCI_DOMAINS=y -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_MSM8960 is not set -CONFIG_PINCTRL_MSM8X74=y -# CONFIG_PL330_DMA is not set -CONFIG_PM=y -CONFIG_PM_CLK=y -# CONFIG_PM_DEBUG is not set -CONFIG_PM_OPP=y -CONFIG_PM_RUNTIME=y -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_PPS=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_PTP_1588_CLOCK=y -CONFIG_QCOM_ADM=y -CONFIG_QCOM_BAM_DMA=y -CONFIG_QCOM_GSBI=y -CONFIG_QCOM_HFPLL=y -CONFIG_QCOM_SCM=y -CONFIG_QCOM_SMEM=y -CONFIG_QCOM_WDT=y -CONFIG_RAS=y -# CONFIG_RCU_BOOST is not set -CONFIG_RCU_CPU_STALL_TIMEOUT=21 -CONFIG_RCU_CPU_STALL_VERBOSE=y -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_QCOM_RPM=y -# 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_STMMAC_ETH=y -CONFIG_STMMAC_PLATFORM=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_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_TREE_PREEMPT_RCU=y -CONFIG_UBIFS_FS=y -# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -CONFIG_UBIFS_FS_LZO=y -CONFIG_UBIFS_FS_XZ=y -CONFIG_UBIFS_FS_ZLIB=y -CONFIG_UEVENT_HELPER_PATH="" -CONFIG_UID16=y -CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" -CONFIG_UNINLINE_SPIN_UNLOCK=y -CONFIG_USB_SUPPORT=y -CONFIG_USE_OF=y -CONFIG_VECTORS_BASE=0xffff0000 -# CONFIG_VFIO is not set -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_XPS=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_BCJ=y -CONFIG_ZBOOT_ROM_BSS=0 -CONFIG_ZBOOT_ROM_TEXT=0 -CONFIG_ZLIB_DEFLATE=y -CONFIG_ZLIB_INFLATE=y -CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch b/target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch deleted file mode 100644 index e110bf726cb6..000000000000 --- a/target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch +++ /dev/null @@ -1,522 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: spi: qup: Add DMA capabilities -From: Andy Gross -X-Patchwork-Id: 4432401 -Message-Id: <1403816781-31008-1-git-send-email-agross@codeaurora.org> -To: Mark Brown -Cc: linux-spi@vger.kernel.org, Sagar Dharia , - Daniel Sneddon , - Bjorn Andersson , - "Ivan T. Ivanov" , - linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - linux-arm-msm@vger.kernel.org, Andy Gross -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 - ---- -.../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 = 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 - #include - #include -+#include -+#include - - #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); -@@ -554,6 +817,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); - -@@ -619,6 +883,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); - -@@ -731,6 +1045,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-3.18/002-v3-spi-qup-Fix-incorrect-block-transfers.patch b/target/linux/ipq806x/patches-3.18/002-v3-spi-qup-Fix-incorrect-block-transfers.patch deleted file mode 100644 index 62ee5b4fad09..000000000000 --- a/target/linux/ipq806x/patches-3.18/002-v3-spi-qup-Fix-incorrect-block-transfers.patch +++ /dev/null @@ -1,376 +0,0 @@ -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 -X-Patchwork-Id: 5007321 -Message-Id: <1412112088-25928-1-git-send-email-agross@codeaurora.org> -To: Mark Brown -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" , - Bjorn Andersson , - Kumar Gala , Andy Gross -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 - ---- -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; -+ u32 config, iomode; - 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); - -@@ -724,7 +818,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"); -@@ -741,6 +836,7 @@ exit: - if (!ret) - ret = controller->error; - spin_unlock_irqrestore(&controller->lock, flags); -+ - return ret; - } - diff --git a/target/linux/ipq806x/patches-3.18/003-spi-qup-Ensure-done-detection.patch b/target/linux/ipq806x/patches-3.18/003-spi-qup-Ensure-done-detection.patch deleted file mode 100644 index 70522278103c..000000000000 --- a/target/linux/ipq806x/patches-3.18/003-spi-qup-Ensure-done-detection.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 4faba89e3ffbb1c5f6232651375b9b3212b50f02 Mon Sep 17 00:00:00 2001 -From: Andy Gross -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 ---- - 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-3.18/011-watchdog-qcom-use-timer-devicetree-binding.patch b/target/linux/ipq806x/patches-3.18/011-watchdog-qcom-use-timer-devicetree-binding.patch deleted file mode 100644 index 68489a83b5b5..000000000000 --- a/target/linux/ipq806x/patches-3.18/011-watchdog-qcom-use-timer-devicetree-binding.patch +++ /dev/null @@ -1,67 +0,0 @@ -From fded70251b1b58f68de1d3757ece9965f0b75452 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -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 ---- - drivers/watchdog/qcom-wdt.c | 21 +++++++++++++++------ - 1 file changed, 15 insertions(+), 6 deletions(-) - ---- a/drivers/watchdog/qcom-wdt.c -+++ b/drivers/watchdog/qcom-wdt.c -@@ -20,9 +20,9 @@ - #include - #include - --#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 platfor - { - 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 platfor - 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 platfo - } - - 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); diff --git a/target/linux/ipq806x/patches-3.18/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch b/target/linux/ipq806x/patches-3.18/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch deleted file mode 100644 index ae9677656e06..000000000000 --- a/target/linux/ipq806x/patches-3.18/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 297cf8136ecd6a56520888fd28948393766b8ee7 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -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 -Signed-off-by: Mathieu Olivari ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - ---- 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>; - }; - diff --git a/target/linux/ipq806x/patches-3.18/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch b/target/linux/ipq806x/patches-3.18/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch deleted file mode 100644 index 6876768962d7..000000000000 --- a/target/linux/ipq806x/patches-3.18/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch +++ /dev/null @@ -1,50 +0,0 @@ -From e535f01dffb6dd9e09934fa219be52af3437a8f6 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -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 ---- - 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 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-3.18/020-add-ap148-bootargs.patch b/target/linux/ipq806x/patches-3.18/020-add-ap148-bootargs.patch deleted file mode 100644 index a61481e65238..000000000000 --- a/target/linux/ipq806x/patches-3.18/020-add-ap148-bootargs.patch +++ /dev/null @@ -1,46 +0,0 @@ ---- 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-3.18/021-add-ap148-partitions.patch b/target/linux/ipq806x/patches-3.18/021-add-ap148-partitions.patch deleted file mode 100644 index bfdb30fe14a3..000000000000 --- a/target/linux/ipq806x/patches-3.18/021-add-ap148-partitions.patch +++ /dev/null @@ -1,19 +0,0 @@ ---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -@@ -77,15 +77,7 @@ - spi-max-frequency = <50000000>; - reg = <0>; - -- partition@0 { -- label = "rootfs"; -- reg = <0x0 0x1000000>; -- }; -- -- partition@1 { -- label = "scratch"; -- reg = <0x1000000 0x1000000>; -- }; -+ linux,part-probe = "qcom-smem"; - }; - }; - }; diff --git a/target/linux/ipq806x/patches-3.18/022-add-db149-dts.patch b/target/linux/ipq806x/patches-3.18/022-add-db149-dts.patch deleted file mode 100644 index bd6ec1e94f38..000000000000 --- a/target/linux/ipq806x/patches-3.18/022-add-db149-dts.patch +++ /dev/null @@ -1,160 +0,0 @@ -From a32d6e7c8fca6371a2614924b89981bc912b6378 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Tue, 7 Apr 2015 19:58:58 -0700 -Subject: [PATCH] ARM: dts: qcom: add initial DB149 device-tree - -Add basic DB149 (IPQ806x based platform) device-tree. It supports UART, -SATA, USB2, USB3 and NOR flash. - -Signed-off-by: Mathieu Olivari ---- - arch/arm/boot/dts/Makefile | 1 + - arch/arm/boot/dts/qcom-ipq8064-db149.dts | 257 +++++++++++++++++++++++++++++++ - 2 files changed, 258 insertions(+) - create mode 100644 arch/arm/boot/dts/qcom-ipq8064-db149.dts - ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -360,6 +360,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ - qcom-apq8084-ifc6540.dtb \ - qcom-apq8084-mtp.dtb \ - qcom-ipq8064-ap148.dtb \ -+ qcom-ipq8064-db149.dtb \ - qcom-msm8660-surf.dtb \ - qcom-msm8960-cdp.dtb \ - qcom-msm8974-sony-xperia-honami.dtb ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-db149.dts -@@ -0,0 +1,132 @@ -+#include "qcom-ipq8064-v1.0.dtsi" -+ -+/ { -+ model = "Qualcomm IPQ8064/DB149"; -+ compatible = "qcom,ipq8064-db149", "qcom,ipq8064"; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ rsvd@41200000 { -+ reg = <0x41200000 0x300000>; -+ no-map; -+ }; -+ }; -+ -+ alias { -+ serial0 = &uart2; -+ }; -+ -+ chosen { -+ linux,stdout-path = "serial0:115200n8"; -+ }; -+ -+ soc { -+ pinmux@800000 { -+ i2c4_pins: i2c4_pinmux { -+ pins = "gpio12", "gpio13"; -+ function = "gsbi4"; -+ bias-disable; -+ }; -+ -+ spi_pins: spi_pins { -+ mux { -+ pins = "gpio18", "gpio19", "gpio21"; -+ function = "gsbi5"; -+ drive-strength = <10>; -+ bias-none; -+ }; -+ }; -+ }; -+ -+ gsbi2: gsbi@12480000 { -+ qcom,mode = ; -+ status = "ok"; -+ uart2: serial@12490000 { -+ status = "ok"; -+ }; -+ }; -+ -+ gsbi5: gsbi@1a200000 { -+ qcom,mode = ; -+ status = "ok"; -+ -+ spi4: spi@1a280000 { -+ status = "ok"; -+ spi-max-frequency = <50000000>; -+ -+ pinctrl-0 = <&spi_pins>; -+ pinctrl-names = "default"; -+ -+ cs-gpios = <&qcom_pinmux 20 0>; -+ -+ flash: m25p80@0 { -+ compatible = "s25fl256s1"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ spi-max-frequency = <50000000>; -+ reg = <0>; -+ m25p,fast-read; -+ -+ partition@0 { -+ label = "lowlevel_init"; -+ reg = <0x0 0x1b0000>; -+ }; -+ -+ partition@1 { -+ 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>; -+ }; -+ }; -+ }; -+ }; -+ -+ sata-phy@1b400000 { -+ status = "ok"; -+ }; -+ -+ sata@29000000 { -+ status = "ok"; -+ }; -+ -+ phy@100f8800 { /* USB3 port 1 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@100f8830 { /* USB3 port 1 SS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8800 { /* USB3 port 0 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8830 { /* USB3 port 0 SS phy */ -+ status = "ok"; -+ }; -+ -+ usb30@0 { -+ status = "ok"; -+ }; -+ -+ usb30@1 { -+ status = "ok"; -+ }; -+ }; -+}; diff --git a/target/linux/ipq806x/patches-3.18/023-ARM-dts-ipq806x-Disable-i2c-device-on-gsbi4.patch b/target/linux/ipq806x/patches-3.18/023-ARM-dts-ipq806x-Disable-i2c-device-on-gsbi4.patch deleted file mode 100644 index 319859b109c0..000000000000 --- a/target/linux/ipq806x/patches-3.18/023-ARM-dts-ipq806x-Disable-i2c-device-on-gsbi4.patch +++ /dev/null @@ -1,53 +0,0 @@ ---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -@@ -46,15 +46,12 @@ - serial@16340000 { - status = "ok"; - }; -- -- i2c4: i2c@16380000 { -- status = "ok"; -- -- clock-frequency = <200000>; -- -- pinctrl-0 = <&i2c4_pins>; -- pinctrl-names = "default"; -- }; -+ /* -+ * The i2c device on gsbi4 should not be enabled. -+ * On ipq806x designs gsbi4 i2c is meant for exclusive -+ * RPM usage. Turning this on in kernel manifests as -+ * i2c failure for the RPM. -+ */ - }; - - gsbi5: gsbi@1a200000 { ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -794,7 +794,7 @@ static struct clk_rcg gsbi7_qup_src = { - .parent_names = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, -- .flags = CLK_SET_PARENT_GATE, -+ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, - }, - }, - }; -@@ -810,7 +810,7 @@ static struct clk_branch gsbi7_qup_clk = - .parent_names = (const char *[]){ "gsbi7_qup_src" }, - .num_parents = 1, - .ops = &clk_branch_ops, -- .flags = CLK_SET_RATE_PARENT, -+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, - }, - }, - }; -@@ -858,7 +858,7 @@ static struct clk_branch gsbi4_h_clk = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi4_h_clk", - .ops = &clk_branch_ops, -- .flags = CLK_IS_ROOT, -+ .flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED, - }, - }, - }; diff --git a/target/linux/ipq806x/patches-3.18/024-ap148-add-memory-node.patch b/target/linux/ipq806x/patches-3.18/024-ap148-add-memory-node.patch deleted file mode 100644 index f026ed93941f..000000000000 --- a/target/linux/ipq806x/patches-3.18/024-ap148-add-memory-node.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -@@ -4,6 +4,11 @@ - model = "Qualcomm IPQ8064/AP148"; - compatible = "qcom,ipq8064-ap148", "qcom,ipq8064"; - -+ memory@0 { -+ reg = <0x42000000 0x1e000000>; -+ device_type = "memory"; -+ }; -+ - reserved-memory { - #address-cells = <1>; - #size-cells = <1>; diff --git a/target/linux/ipq806x/patches-3.18/030-hwspinlock-core-add-device-tree-support.patch b/target/linux/ipq806x/patches-3.18/030-hwspinlock-core-add-device-tree-support.patch deleted file mode 100644 index 04f35b7ec759..000000000000 --- a/target/linux/ipq806x/patches-3.18/030-hwspinlock-core-add-device-tree-support.patch +++ /dev/null @@ -1,167 +0,0 @@ -From fb7737e949e31d8a71acee6bbb670f32dbd2a2c0 Mon Sep 17 00:00:00 2001 -From: Suman Anna -Date: Wed, 4 Mar 2015 20:01:14 -0600 -Subject: [PATCH] hwspinlock/core: add device tree support - -This patch adds a new OF-friendly API of_hwspin_lock_get_id() -for hwspinlock clients to use/request locks from a hwspinlock -device instantiated through a device-tree blob. This new API -can be used by hwspinlock clients to get the id for a specific -lock using the phandle + args specifier, so that it can be -requested using the available hwspin_lock_request_specific() -API. - -Signed-off-by: Suman Anna -Reviewed-by: Bjorn Andersson -[small comment clarification] -Signed-off-by: Ohad Ben-Cohen ---- - Documentation/hwspinlock.txt | 10 +++++ - drivers/hwspinlock/hwspinlock_core.c | 79 ++++++++++++++++++++++++++++++++++++ - include/linux/hwspinlock.h | 7 ++++ - 3 files changed, 96 insertions(+) - ---- a/Documentation/hwspinlock.txt -+++ b/Documentation/hwspinlock.txt -@@ -48,6 +48,16 @@ independent, drivers. - ids for predefined purposes. - Should be called from a process context (might sleep). - -+ int of_hwspin_lock_get_id(struct device_node *np, int index); -+ - retrieve the global lock id for an OF phandle-based specific lock. -+ This function provides a means for DT users of a hwspinlock module -+ to get the global lock id of a specific hwspinlock, so that it can -+ be requested using the normal hwspin_lock_request_specific() API. -+ The function returns a lock id number on success, -EPROBE_DEFER if -+ the hwspinlock device is not yet registered with the core, or other -+ error values. -+ Should be called from a process context (might sleep). -+ - int hwspin_lock_free(struct hwspinlock *hwlock); - - free a previously-assigned hwspinlock; returns 0 on success, or an - appropriate error code on failure (e.g. -EINVAL if the hwspinlock ---- a/drivers/hwspinlock/hwspinlock_core.c -+++ b/drivers/hwspinlock/hwspinlock_core.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #include "hwspinlock_internal.h" - -@@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock * - } - EXPORT_SYMBOL_GPL(__hwspin_unlock); - -+/** -+ * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id -+ * @bank: the hwspinlock device bank -+ * @hwlock_spec: hwlock specifier as found in the device tree -+ * -+ * This is a simple translation function, suitable for hwspinlock platform -+ * drivers that only has a lock specifier length of 1. -+ * -+ * Returns a relative index of the lock within a specified bank on success, -+ * or -EINVAL on invalid specifier cell count. -+ */ -+static inline int -+of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec) -+{ -+ if (WARN_ON(hwlock_spec->args_count != 1)) -+ return -EINVAL; -+ -+ return hwlock_spec->args[0]; -+} -+ -+/** -+ * of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock -+ * @np: device node from which to request the specific hwlock -+ * @index: index of the hwlock in the list of values -+ * -+ * This function provides a means for DT users of the hwspinlock module to -+ * get the global lock id of a specific hwspinlock using the phandle of the -+ * hwspinlock device, so that it can be requested using the normal -+ * hwspin_lock_request_specific() API. -+ * -+ * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock -+ * device is not yet registered, -EINVAL on invalid args specifier value or an -+ * appropriate error as returned from the OF parsing of the DT client node. -+ */ -+int of_hwspin_lock_get_id(struct device_node *np, int index) -+{ -+ struct of_phandle_args args; -+ struct hwspinlock *hwlock; -+ struct radix_tree_iter iter; -+ void **slot; -+ int id; -+ int ret; -+ -+ ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index, -+ &args); -+ if (ret) -+ return ret; -+ -+ /* Find the hwspinlock device: we need its base_id */ -+ ret = -EPROBE_DEFER; -+ rcu_read_lock(); -+ radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) { -+ hwlock = radix_tree_deref_slot(slot); -+ if (unlikely(!hwlock)) -+ continue; -+ -+ if (hwlock->bank->dev->of_node == args.np) { -+ ret = 0; -+ break; -+ } -+ } -+ rcu_read_unlock(); -+ if (ret < 0) -+ goto out; -+ -+ id = of_hwspin_lock_simple_xlate(&args); -+ if (id < 0 || id >= hwlock->bank->num_locks) { -+ ret = -EINVAL; -+ goto out; -+ } -+ id += hwlock->bank->base_id; -+ -+out: -+ of_node_put(args.np); -+ return ret ? ret : id; -+} -+EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id); -+ - static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) - { - struct hwspinlock *tmp; ---- a/include/linux/hwspinlock.h -+++ b/include/linux/hwspinlock.h -@@ -26,6 +26,7 @@ - #define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */ - - struct device; -+struct device_node; - struct hwspinlock; - struct hwspinlock_device; - struct hwspinlock_ops; -@@ -66,6 +67,7 @@ int hwspin_lock_unregister(struct hwspin - struct hwspinlock *hwspin_lock_request(void); - struct hwspinlock *hwspin_lock_request_specific(unsigned int id); - int hwspin_lock_free(struct hwspinlock *hwlock); -+int of_hwspin_lock_get_id(struct device_node *np, int index); - int hwspin_lock_get_id(struct hwspinlock *hwlock); - int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int, - unsigned long *); -@@ -120,6 +122,11 @@ void __hwspin_unlock(struct hwspinlock * - { - } - -+static inline int of_hwspin_lock_get_id(struct device_node *np, int index) -+{ -+ return 0; -+} -+ - static inline int hwspin_lock_get_id(struct hwspinlock *hwlock) - { - return 0; diff --git a/target/linux/ipq806x/patches-3.18/031-hwspinlock-qcom-Add-support-for-Qualcomm-HW-Mutex-bl.patch b/target/linux/ipq806x/patches-3.18/031-hwspinlock-qcom-Add-support-for-Qualcomm-HW-Mutex-bl.patch deleted file mode 100644 index 581b199d7ff8..000000000000 --- a/target/linux/ipq806x/patches-3.18/031-hwspinlock-qcom-Add-support-for-Qualcomm-HW-Mutex-bl.patch +++ /dev/null @@ -1,234 +0,0 @@ -From 19a0f61224d2d91860fa8291ab63cb104ee86bdd Mon Sep 17 00:00:00 2001 -From: Bjorn Andersson -Date: Tue, 24 Mar 2015 10:11:05 -0700 -Subject: [PATCH] hwspinlock: qcom: Add support for Qualcomm HW Mutex block - -Add driver for Qualcomm Hardware Mutex block found in many Qualcomm -SoCs. - -Based on initial effort by Kumar Gala - -Signed-off-by: Bjorn Andersson -Reviewed-by: Andy Gross -Reviewed-by: Jeffrey Hugo -Signed-off-by: Ohad Ben-Cohen ---- - drivers/hwspinlock/Kconfig | 12 +++ - drivers/hwspinlock/Makefile | 1 + - drivers/hwspinlock/qcom_hwspinlock.c | 181 +++++++++++++++++++++++++++++++++++ - 3 files changed, 194 insertions(+) - create mode 100644 drivers/hwspinlock/qcom_hwspinlock.c - ---- a/drivers/hwspinlock/Kconfig -+++ b/drivers/hwspinlock/Kconfig -@@ -18,6 +18,18 @@ config HWSPINLOCK_OMAP - - If unsure, say N. - -+config HWSPINLOCK_QCOM -+ tristate "Qualcomm Hardware Spinlock device" -+ depends on ARCH_QCOM -+ select HWSPINLOCK -+ select MFD_SYSCON -+ help -+ Say y here to support the Qualcomm Hardware Mutex functionality, which -+ provides a synchronisation mechanism for the various processors on -+ the SoC. -+ -+ If unsure, say N. -+ - config HSEM_U8500 - tristate "STE Hardware Semaphore functionality" - depends on ARCH_U8500 ---- a/drivers/hwspinlock/Makefile -+++ b/drivers/hwspinlock/Makefile -@@ -4,4 +4,5 @@ - - obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o - obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o -+obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o - obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o ---- /dev/null -+++ b/drivers/hwspinlock/qcom_hwspinlock.c -@@ -0,0 +1,181 @@ -+/* -+ * Copyright (c) 2013, The Linux Foundation. All rights reserved. -+ * Copyright (c) 2015, Sony Mobile Communications AB -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "hwspinlock_internal.h" -+ -+#define QCOM_MUTEX_APPS_PROC_ID 1 -+#define QCOM_MUTEX_NUM_LOCKS 32 -+ -+static int qcom_hwspinlock_trylock(struct hwspinlock *lock) -+{ -+ struct regmap_field *field = lock->priv; -+ u32 lock_owner; -+ int ret; -+ -+ ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID); -+ if (ret) -+ return ret; -+ -+ ret = regmap_field_read(field, &lock_owner); -+ if (ret) -+ return ret; -+ -+ return lock_owner == QCOM_MUTEX_APPS_PROC_ID; -+} -+ -+static void qcom_hwspinlock_unlock(struct hwspinlock *lock) -+{ -+ struct regmap_field *field = lock->priv; -+ u32 lock_owner; -+ int ret; -+ -+ ret = regmap_field_read(field, &lock_owner); -+ if (ret) { -+ pr_err("%s: unable to query spinlock owner\n", __func__); -+ return; -+ } -+ -+ if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) { -+ pr_err("%s: spinlock not owned by us (actual owner is %d)\n", -+ __func__, lock_owner); -+ } -+ -+ ret = regmap_field_write(field, 0); -+ if (ret) -+ pr_err("%s: failed to unlock spinlock\n", __func__); -+} -+ -+static const struct hwspinlock_ops qcom_hwspinlock_ops = { -+ .trylock = qcom_hwspinlock_trylock, -+ .unlock = qcom_hwspinlock_unlock, -+}; -+ -+static const struct of_device_id qcom_hwspinlock_of_match[] = { -+ { .compatible = "qcom,sfpb-mutex" }, -+ { .compatible = "qcom,tcsr-mutex" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match); -+ -+static int qcom_hwspinlock_probe(struct platform_device *pdev) -+{ -+ struct hwspinlock_device *bank; -+ struct device_node *syscon; -+ struct reg_field field; -+ struct regmap *regmap; -+ size_t array_size; -+ u32 stride; -+ u32 base; -+ int ret; -+ int i; -+ -+ syscon = of_parse_phandle(pdev->dev.of_node, "syscon", 0); -+ if (!syscon) { -+ dev_err(&pdev->dev, "no syscon property\n"); -+ return -ENODEV; -+ } -+ -+ regmap = syscon_node_to_regmap(syscon); -+ if (IS_ERR(regmap)) -+ return PTR_ERR(regmap); -+ -+ ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, &base); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "no offset in syscon\n"); -+ return -EINVAL; -+ } -+ -+ ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 2, &stride); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "no stride syscon\n"); -+ return -EINVAL; -+ } -+ -+ array_size = QCOM_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock); -+ bank = devm_kzalloc(&pdev->dev, sizeof(*bank) + array_size, GFP_KERNEL); -+ if (!bank) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, bank); -+ -+ for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) { -+ field.reg = base + i * stride; -+ field.lsb = 0; -+ field.msb = 32; -+ -+ bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev, -+ regmap, field); -+ } -+ -+ pm_runtime_enable(&pdev->dev); -+ -+ ret = hwspin_lock_register(bank, &pdev->dev, &qcom_hwspinlock_ops, -+ 0, QCOM_MUTEX_NUM_LOCKS); -+ if (ret) -+ pm_runtime_disable(&pdev->dev); -+ -+ return ret; -+} -+ -+static int qcom_hwspinlock_remove(struct platform_device *pdev) -+{ -+ struct hwspinlock_device *bank = platform_get_drvdata(pdev); -+ int ret; -+ -+ ret = hwspin_lock_unregister(bank); -+ if (ret) { -+ dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); -+ return ret; -+ } -+ -+ pm_runtime_disable(&pdev->dev); -+ -+ return 0; -+} -+ -+static struct platform_driver qcom_hwspinlock_driver = { -+ .probe = qcom_hwspinlock_probe, -+ .remove = qcom_hwspinlock_remove, -+ .driver = { -+ .name = "qcom_hwspinlock", -+ .of_match_table = qcom_hwspinlock_of_match, -+ }, -+}; -+ -+static int __init qcom_hwspinlock_init(void) -+{ -+ return platform_driver_register(&qcom_hwspinlock_driver); -+} -+/* board init code might need to reserve hwspinlocks for predefined purposes */ -+postcore_initcall(qcom_hwspinlock_init); -+ -+static void __exit qcom_hwspinlock_exit(void) -+{ -+ platform_driver_unregister(&qcom_hwspinlock_driver); -+} -+module_exit(qcom_hwspinlock_exit); -+ -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION("Hardware spinlock driver for Qualcomm SoCs"); diff --git a/target/linux/ipq806x/patches-3.18/032-hwspinlock-qcom-Correct-msb-in-regmap_field.patch b/target/linux/ipq806x/patches-3.18/032-hwspinlock-qcom-Correct-msb-in-regmap_field.patch deleted file mode 100644 index 70d5a58248d9..000000000000 --- a/target/linux/ipq806x/patches-3.18/032-hwspinlock-qcom-Correct-msb-in-regmap_field.patch +++ /dev/null @@ -1,26 +0,0 @@ -From bd5717a4632cdecafe82d03de7dcb3b1876e2828 Mon Sep 17 00:00:00 2001 -From: Bjorn Andersson -Date: Fri, 26 Jun 2015 14:47:21 -0700 -Subject: [PATCH] hwspinlock: qcom: Correct msb in regmap_field - -msb of the regmap_field was mistakenly given the value 32, to set all bits -in the regmap update mask; although incorrect this worked until 921cc294, -where the mask calculation was corrected. - -Signed-off-by: Bjorn Andersson -Signed-off-by: Ohad Ben-Cohen ---- - drivers/hwspinlock/qcom_hwspinlock.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/hwspinlock/qcom_hwspinlock.c -+++ b/drivers/hwspinlock/qcom_hwspinlock.c -@@ -123,7 +123,7 @@ static int qcom_hwspinlock_probe(struct - for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) { - field.reg = base + i * stride; - field.lsb = 0; -- field.msb = 32; -+ field.msb = 31; - - bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev, - regmap, field); diff --git a/target/linux/ipq806x/patches-3.18/033-ARM-qcom-add-SFPB-nodes-to-IPQ806x-dts.patch b/target/linux/ipq806x/patches-3.18/033-ARM-qcom-add-SFPB-nodes-to-IPQ806x-dts.patch deleted file mode 100644 index 4a353254bfec..000000000000 --- a/target/linux/ipq806x/patches-3.18/033-ARM-qcom-add-SFPB-nodes-to-IPQ806x-dts.patch +++ /dev/null @@ -1,34 +0,0 @@ -From c7c482da19a5e4ba7101198c21c2434056b0b2da Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Thu, 13 Aug 2015 09:45:26 -0700 -Subject: [PATCH 1/3] ARM: qcom: add SFPB nodes to IPQ806x dts - -Add one new node to the ipq806x.dtsi file to declare & register the -hardware spinlock devices. This mechanism is required to be used by -other drivers such as SMEM. - -Signed-off-by: Mathieu Olivari ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 11 +++++++++++ - 1 file changed, 11 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -291,5 +291,17 @@ - #clock-cells = <1>; - #reset-cells = <1>; - }; -+ -+ sfpb_mutex_block: syscon@1200600 { -+ compatible = "syscon"; -+ reg = <0x01200600 0x100>; -+ }; - }; -+ -+ sfpb_mutex: sfpb-mutex { -+ compatible = "qcom,sfpb-mutex"; -+ syscon = <&sfpb_mutex_block 4 4>; -+ -+ #hwlock-cells = <1>; -+ }; - }; diff --git a/target/linux/ipq806x/patches-3.18/034-soc-qcom-Add-device-tree-binding-for-SMEM.patch b/target/linux/ipq806x/patches-3.18/034-soc-qcom-Add-device-tree-binding-for-SMEM.patch deleted file mode 100644 index d22db2226eda..000000000000 --- a/target/linux/ipq806x/patches-3.18/034-soc-qcom-Add-device-tree-binding-for-SMEM.patch +++ /dev/null @@ -1,82 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v2,1/2] soc: qcom: Add device tree binding for SMEM -From: Bjorn Andersson -X-Patchwork-Id: 6202201 -Message-Id: <1428795178-24312-1-git-send-email-bjorn.andersson@sonymobile.com> -To: Rob Herring , Pawel Moll , - Mark Rutland , - Ian Campbell , - Kumar Gala , Jeffrey Hugo , - Andry Gross -Cc: , - linux-arm-msm , - -Date: Sat, 11 Apr 2015 16:32:57 -0700 - -Add device tree binding documentation for the Qualcom Shared Memory -manager. - -Signed-off-by: Bjorn Andersson - ---- -Changes since v1: -- None - - .../devicetree/bindings/soc/qcom/qcom,smem.txt | 49 ++++++++++++++++++++++ - 1 file changed, 49 insertions(+) - create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,smem.txt - ---- /dev/null -+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smem.txt -@@ -0,0 +1,49 @@ -+Qualcomm Shared Memory binding -+ -+This binding describes the Qualcomm Shared Memory, used to share data between -+various subsystems and OSes in Qualcomm platforms. -+ -+- compatible: -+ Usage: required -+ Value type: -+ Definition: must be: -+ "qcom,smem" -+ -+- memory-region: -+ Usage: required -+ Value type: -+ Definition: handle to memory reservation for main smem memory region. -+ -+- reg: -+ Usage: optional -+ Value type: -+ Definition: base address and size pair for any additional memory areas -+ of the shared memory. -+ -+- hwspinlocks: -+ Usage: required -+ Value type: -+ Definition: reference to a hwspinlock used to protect allocations from -+ the shared memory -+ -+= EXAMPLE -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ -+ smem_region: smem@fa00000 { -+ reg = <0xfa00000 0x200000>; -+ no-map; -+ }; -+ }; -+ -+ smem@fa00000 { -+ compatible = "qcom,smem"; -+ -+ memory-region = <&smem_region>; -+ reg = <0xfc428000 0x4000>; -+ -+ hwlocks = <&tcsr_mutex 3>; -+ }; diff --git a/target/linux/ipq806x/patches-3.18/035-soc-qcom-Add-Shared-Memory-Manager-driver.patch b/target/linux/ipq806x/patches-3.18/035-soc-qcom-Add-Shared-Memory-Manager-driver.patch deleted file mode 100644 index c8cff1a2887e..000000000000 --- a/target/linux/ipq806x/patches-3.18/035-soc-qcom-Add-Shared-Memory-Manager-driver.patch +++ /dev/null @@ -1,841 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v2,2/2] soc: qcom: Add Shared Memory Manager driver -From: Bjorn Andersson -X-Patchwork-Id: 6202211 -Message-Id: <1428795178-24312-2-git-send-email-bjorn.andersson@sonymobile.com> -To: Kumar Gala , Andy Gross , - David Brown , Jeffrey Hugo -Cc: , , - -Date: Sat, 11 Apr 2015 16:32:58 -0700 - -The Shared Memory Manager driver implements an interface for allocating -and accessing items in the memory area shared among all of the -processors in a Qualcomm platform. - -Signed-off-by: Bjorn Andersson -Reviewed-by: Andy Gross -Tested-by: Andy Gross - ---- -Changes since v1: -- ioremapping the regions nocache -- improved documentation of the two regions of partitions -- corrected free space check in private allocator - - drivers/soc/qcom/Kconfig | 7 + - drivers/soc/qcom/Makefile | 1 + - drivers/soc/qcom/smem.c | 768 ++++++++++++++++++++++++++++++++++++++++++ - include/linux/soc/qcom/smem.h | 14 + - 4 files changed, 790 insertions(+) - create mode 100644 drivers/soc/qcom/smem.c - create mode 100644 include/linux/soc/qcom/smem.h - ---- a/drivers/soc/qcom/Kconfig -+++ b/drivers/soc/qcom/Kconfig -@@ -9,3 +9,10 @@ config QCOM_GSBI - functions for connecting the underlying serial UART, SPI, and I2C - devices to the output pins. - -+config QCOM_SMEM -+ tristate "Qualcomm Shared Memory Manager (SMEM)" -+ depends on ARCH_QCOM -+ help -+ Say y here to enable support for the Qualcomm Shared Memory Manager. -+ The driver provides an interface to items in a heap shared among all -+ processors in a Qualcomm platform. ---- a/drivers/soc/qcom/Makefile -+++ b/drivers/soc/qcom/Makefile -@@ -1 +1,2 @@ - obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o -+obj-$(CONFIG_QCOM_SMEM) += smem.o ---- /dev/null -+++ b/drivers/soc/qcom/smem.c -@@ -0,0 +1,768 @@ -+/* -+ * Copyright (c) 2015, Sony Mobile Communications AB. -+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * The Qualcomm shared memory system is a allocate only heap structure that -+ * consists of one of more memory areas that can be accessed by the processors -+ * in the SoC. -+ * -+ * All systems contains a global heap, accessible by all processors in the SoC, -+ * with a table of contents data structure (@smem_header) at the beginning of -+ * the main shared memory block. -+ * -+ * The global header contains metadata for allocations as well as a fixed list -+ * of 512 entries (@smem_global_entry) that can be initialized to reference -+ * parts of the shared memory space. -+ * -+ * -+ * In addition to this global heap a set of "private" heaps can be set up at -+ * boot time with access restrictions so that only certain processor pairs can -+ * access the data. -+ * -+ * These partitions are referenced from an optional partition table -+ * (@smem_ptable), that is found 4kB from the end of the main smem region. The -+ * partition table entries (@smem_ptable_entry) lists the involved processors -+ * (or hosts) and their location in the main shared memory region. -+ * -+ * Each partition starts with a header (@smem_partition_header) that identifies -+ * the partition and holds properties for the two internal memory regions. The -+ * two regions are cached and non-cached memory respectively. Each region -+ * contain a link list of allocation headers (@smem_private_entry) followed by -+ * their data. -+ * -+ * Items in the non-cached region are allocated from the start of the partition -+ * while items in the cached region are allocated from the end. The free area -+ * is hence the region between the cached and non-cached offsets. -+ * -+ * -+ * To synchronize allocations in the shared memory heaps a remote spinlock must -+ * be held - currently lock number 3 of the sfpb or tcsr is used for this on all -+ * platforms. -+ * -+ */ -+ -+/** -+ * struct smem_proc_comm - proc_comm communication struct (legacy) -+ * @command: current command to be executed -+ * @status: status of the currently requested command -+ * @params: parameters to the command -+ */ -+struct smem_proc_comm { -+ u32 command; -+ u32 status; -+ u32 params[2]; -+}; -+ -+/** -+ * struct smem_global_entry - entry to reference smem items on the heap -+ * @allocated: boolean to indicate if this entry is used -+ * @offset: offset to the allocated space -+ * @size: size of the allocated space, 8 byte aligned -+ * @aux_base: base address for the memory region used by this unit, or 0 for -+ * the default region. bits 0,1 are reserved -+ */ -+struct smem_global_entry { -+ u32 allocated; -+ u32 offset; -+ u32 size; -+ u32 aux_base; /* bits 1:0 reserved */ -+}; -+#define AUX_BASE_MASK 0xfffffffc -+ -+/** -+ * struct smem_header - header found in beginning of primary smem region -+ * @proc_comm: proc_comm communication interface (legacy) -+ * @version: array of versions for the various subsystems -+ * @initialized: boolean to indicate that smem is initialized -+ * @free_offset: index of the first unallocated byte in smem -+ * @available: number of bytes available for allocation -+ * @reserved: reserved field, must be 0 -+ * toc: array of references to items -+ */ -+struct smem_header { -+ struct smem_proc_comm proc_comm[4]; -+ u32 version[32]; -+ u32 initialized; -+ u32 free_offset; -+ u32 available; -+ u32 reserved; -+ struct smem_global_entry toc[]; -+}; -+ -+/** -+ * struct smem_ptable_entry - one entry in the @smem_ptable list -+ * @offset: offset, within the main shared memory region, of the partition -+ * @size: size of the partition -+ * @flags: flags for the partition (currently unused) -+ * @host0: first processor/host with access to this partition -+ * @host1: second processor/host with access to this partition -+ * @reserved: reserved entries for later use -+ */ -+struct smem_ptable_entry { -+ u32 offset; -+ u32 size; -+ u32 flags; -+ u16 host0; -+ u16 host1; -+ u32 reserved[8]; -+}; -+ -+/** -+ * struct smem_ptable - partition table for the private partitions -+ * @magic: magic number, must be SMEM_PTABLE_MAGIC -+ * @version: version of the partition table -+ * @num_entries: number of partitions in the table -+ * @reserved: for now reserved entries -+ * @entry: list of @smem_ptable_entry for the @num_entries partitions -+ */ -+struct smem_ptable { -+ u32 magic; -+ u32 version; -+ u32 num_entries; -+ u32 reserved[5]; -+ struct smem_ptable_entry entry[]; -+}; -+#define SMEM_PTABLE_MAGIC 0x434f5424 /* "$TOC" */ -+ -+/** -+ * struct smem_partition_header - header of the partitions -+ * @magic: magic number, must be SMEM_PART_MAGIC -+ * @host0: first processor/host with access to this partition -+ * @host1: second processor/host with access to this partition -+ * @size: size of the partition -+ * @offset_free_uncached: offset to the first free byte of uncached memory in -+ * this partition -+ * @offset_free_cached: offset to the first free byte of cached memory in this -+ * partition -+ * @reserved: for now reserved entries -+ */ -+struct smem_partition_header { -+ u32 magic; -+ u16 host0; -+ u16 host1; -+ u32 size; -+ u32 offset_free_uncached; -+ u32 offset_free_cached; -+ u32 reserved[3]; -+}; -+#define SMEM_PART_MAGIC 0x54525024 /* "$PRT" */ -+ -+/** -+ * struct smem_private_entry - header of each item in the private partition -+ * @canary: magic number, must be SMEM_PRIVATE_CANARY -+ * @item: identifying number of the smem item -+ * @size: size of the data, including padding bytes -+ * @padding_data: number of bytes of padding of data -+ * @padding_hdr: number of bytes of padding between the header and the data -+ * @reserved: for now reserved entry -+ */ -+struct smem_private_entry { -+ u16 canary; -+ u16 item; -+ u32 size; /* includes padding bytes */ -+ u16 padding_data; -+ u16 padding_hdr; -+ u32 reserved; -+}; -+#define SMEM_PRIVATE_CANARY 0xa5a5 -+ -+/* -+ * Item 3 of the global heap contains an array of versions for the various -+ * software components in the SoC. We verify that the boot loader version is -+ * what the expected version (SMEM_EXPECTED_VERSION) as a sanity check. -+ */ -+#define SMEM_ITEM_VERSION 3 -+#define SMEM_MASTER_SBL_VERSION_INDEX 7 -+#define SMEM_EXPECTED_VERSION 11 -+ -+/* -+ * The first 8 items are only to be allocated by the boot loader while -+ * initializing the heap. -+ */ -+#define SMEM_ITEM_LAST_FIXED 8 -+ -+/* Highest accepted item number, for both global and private heaps */ -+#define SMEM_ITEM_LAST 512 -+ -+/* Processor/host identifier for the application processor */ -+#define SMEM_HOST_APPS 0 -+ -+/* Max number of processors/hosts in a system */ -+#define SMEM_HOST_COUNT 7 -+ -+/** -+ * struct smem_region - representation of a chunk of memory used for smem -+ * @aux_base: identifier of aux_mem base -+ * @virt_base: virtual base address of memory with this aux_mem identifier -+ * @size: size of the memory region -+ */ -+struct smem_region { -+ u32 aux_base; -+ void __iomem *virt_base; -+ size_t size; -+}; -+ -+/** -+ * struct qcom_smem - device data for the smem device -+ * @dev: device pointer -+ * @hwlock: reference to a hwspinlock -+ * @partitions: list of pointers to partitions affecting the current -+ * processor/host -+ * @num_regions: number of @regions -+ * @regions: list of the memory regions defining the shared memory -+ */ -+struct qcom_smem { -+ struct device *dev; -+ -+ struct hwspinlock *hwlock; -+ -+ struct smem_partition_header *partitions[SMEM_HOST_COUNT]; -+ -+ unsigned num_regions; -+ struct smem_region regions[0]; -+}; -+ -+/* Pointer to the one and only smem handle */ -+static struct qcom_smem *__smem; -+ -+/* Timeout (ms) for the trylock of remote spinlocks */ -+#define HWSPINLOCK_TIMEOUT 1000 -+ -+static int qcom_smem_alloc_private(struct qcom_smem *smem, -+ unsigned host, -+ unsigned item, -+ size_t size) -+{ -+ struct smem_partition_header *phdr; -+ struct smem_private_entry *hdr; -+ size_t alloc_size; -+ void *p; -+ -+ /* We're not going to find it if there's no matching partition */ -+ if (host >= SMEM_HOST_COUNT || !smem->partitions[host]) -+ return -ENOENT; -+ -+ phdr = smem->partitions[host]; -+ -+ p = (void *)phdr + sizeof(*phdr); -+ while (p < (void *)phdr + phdr->offset_free_uncached) { -+ hdr = p; -+ -+ if (hdr->canary != SMEM_PRIVATE_CANARY) { -+ dev_err(smem->dev, -+ "Found invalid canary in host %d partition\n", -+ host); -+ return -EINVAL; -+ } -+ -+ if (hdr->item == item) -+ return -EEXIST; -+ -+ p += sizeof(*hdr) + hdr->padding_hdr + hdr->size; -+ } -+ -+ /* Check that we don't grow into the cached region */ -+ alloc_size = sizeof(*hdr) + ALIGN(size, 8); -+ if (p + alloc_size >= (void *)phdr + phdr->offset_free_cached) { -+ dev_err(smem->dev, "Out of memory\n"); -+ return -ENOSPC; -+ } -+ -+ hdr = p; -+ hdr->canary = SMEM_PRIVATE_CANARY; -+ hdr->item = item; -+ hdr->size = ALIGN(size, 8); -+ hdr->padding_data = hdr->size - size; -+ hdr->padding_hdr = 0; -+ -+ /* -+ * Ensure the header is written before we advance the free offset, so -+ * that remote processors that does not take the remote spinlock still -+ * gets a consistent view of the linked list. -+ */ -+ wmb(); -+ phdr->offset_free_uncached += alloc_size; -+ -+ return 0; -+} -+ -+static int qcom_smem_alloc_global(struct qcom_smem *smem, -+ unsigned item, -+ size_t size) -+{ -+ struct smem_header *header; -+ struct smem_global_entry *entry; -+ -+ if (WARN_ON(item >= SMEM_ITEM_LAST)) -+ return -EINVAL; -+ -+ header = smem->regions[0].virt_base; -+ entry = &header->toc[item]; -+ if (entry->allocated) -+ return -EEXIST; -+ -+ size = ALIGN(size, 8); -+ if (WARN_ON(size > header->available)) -+ return -ENOMEM; -+ -+ entry->offset = header->free_offset; -+ entry->size = size; -+ -+ /* -+ * Ensure the header is consistent before we mark the item allocated, -+ * so that remote processors will get a consistent view of the item -+ * even though they do not take the spinlock on read. -+ */ -+ wmb(); -+ entry->allocated = 1; -+ -+ header->free_offset += size; -+ header->available -= size; -+ -+ return 0; -+} -+ -+/** -+ * qcom_smem_alloc - allocate space for a smem item -+ * @host: remote processor id, or -1 -+ * @item: smem item handle -+ * @size: number of bytes to be allocated -+ * -+ * Allocate space for a given smem item of size @size, given that the item is -+ * not yet allocated. -+ */ -+int qcom_smem_alloc(unsigned host, unsigned item, size_t size) -+{ -+ unsigned long flags; -+ int ret; -+ -+ if (!__smem) -+ return -EPROBE_DEFER; -+ -+ if (item < SMEM_ITEM_LAST_FIXED) { -+ dev_err(__smem->dev, -+ "Rejecting allocation of static entry %d\n", item); -+ return -EINVAL; -+ } -+ -+ ret = hwspin_lock_timeout_irqsave(__smem->hwlock, -+ HWSPINLOCK_TIMEOUT, -+ &flags); -+ if (ret) -+ return ret; -+ -+ ret = qcom_smem_alloc_private(__smem, host, item, size); -+ if (ret == -ENOENT) -+ ret = qcom_smem_alloc_global(__smem, item, size); -+ -+ hwspin_unlock_irqrestore(__smem->hwlock, &flags); -+ -+ return ret; -+} -+EXPORT_SYMBOL(qcom_smem_alloc); -+ -+static int qcom_smem_get_global(struct qcom_smem *smem, -+ unsigned item, -+ void **ptr, -+ size_t *size) -+{ -+ struct smem_header *header; -+ struct smem_region *area; -+ struct smem_global_entry *entry; -+ u32 aux_base; -+ unsigned i; -+ -+ if (WARN_ON(item >= SMEM_ITEM_LAST)) -+ return -EINVAL; -+ -+ header = smem->regions[0].virt_base; -+ entry = &header->toc[item]; -+ if (!entry->allocated) -+ return -ENXIO; -+ -+ if (ptr != NULL) { -+ aux_base = entry->aux_base & AUX_BASE_MASK; -+ -+ for (i = 0; i < smem->num_regions; i++) { -+ area = &smem->regions[i]; -+ -+ if (area->aux_base == aux_base || !aux_base) { -+ *ptr = area->virt_base + entry->offset; -+ break; -+ } -+ } -+ } -+ if (size != NULL) -+ *size = entry->size; -+ -+ return 0; -+} -+ -+static int qcom_smem_get_private(struct qcom_smem *smem, -+ unsigned host, -+ unsigned item, -+ void **ptr, -+ size_t *size) -+{ -+ struct smem_partition_header *phdr; -+ struct smem_private_entry *hdr; -+ void *p; -+ -+ /* We're not going to find it if there's no matching partition */ -+ if (host >= SMEM_HOST_COUNT || !smem->partitions[host]) -+ return -ENOENT; -+ -+ phdr = smem->partitions[host]; -+ -+ p = (void *)phdr + sizeof(*phdr); -+ while (p < (void *)phdr + phdr->offset_free_uncached) { -+ hdr = p; -+ -+ if (hdr->canary != SMEM_PRIVATE_CANARY) { -+ dev_err(smem->dev, -+ "Found invalid canary in host %d partition\n", -+ host); -+ return -EINVAL; -+ } -+ -+ if (hdr->item == item) { -+ if (ptr != NULL) -+ *ptr = p + sizeof(*hdr) + hdr->padding_hdr; -+ -+ if (size != NULL) -+ *size = hdr->size - hdr->padding_data; -+ -+ return 0; -+ } -+ -+ p += sizeof(*hdr) + hdr->padding_hdr + hdr->size; -+ } -+ -+ return -ENOENT; -+} -+ -+/** -+ * qcom_smem_get - resolve ptr of size of a smem item -+ * @host: the remote processor, or -1 -+ * @item: smem item handle -+ * @ptr: pointer to be filled out with address of the item -+ * @size: pointer to be filled out with size of the item -+ * -+ * Looks up pointer and size of a smem item. -+ */ -+int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size) -+{ -+ unsigned long flags; -+ int ret; -+ -+ if (!__smem) -+ return -EPROBE_DEFER; -+ -+ ret = hwspin_lock_timeout_irqsave(__smem->hwlock, -+ HWSPINLOCK_TIMEOUT, -+ &flags); -+ if (ret) -+ return ret; -+ -+ ret = qcom_smem_get_private(__smem, host, item, ptr, size); -+ if (ret == -ENOENT) -+ ret = qcom_smem_get_global(__smem, item, ptr, size); -+ -+ hwspin_unlock_irqrestore(__smem->hwlock, &flags); -+ return ret; -+ -+} -+EXPORT_SYMBOL(qcom_smem_get); -+ -+/** -+ * qcom_smem_get_free_space - retrieve amont of free space in a partition -+ * @host: the remote processor identifing a partition, or -1 -+ * -+ * To be used by smem clients as a quick way to determine if any new -+ * allocations has been made. -+ */ -+int qcom_smem_get_free_space(unsigned host) -+{ -+ struct smem_partition_header *phdr; -+ struct smem_header *header; -+ unsigned ret; -+ -+ if (!__smem) -+ return -EPROBE_DEFER; -+ -+ if (host < SMEM_HOST_COUNT && __smem->partitions[host]) { -+ phdr = __smem->partitions[host]; -+ ret = phdr->offset_free_uncached; -+ } else { -+ header = __smem->regions[0].virt_base; -+ ret = header->available; -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL(qcom_smem_get_free_space); -+ -+static int qcom_smem_get_sbl_version(struct qcom_smem *smem) -+{ -+ unsigned *versions; -+ size_t size; -+ int ret; -+ -+ ret = qcom_smem_get_global(smem, SMEM_ITEM_VERSION, -+ (void **)&versions, &size); -+ if (ret < 0) { -+ dev_err(smem->dev, "Unable to read the version item\n"); -+ return -ENOENT; -+ } -+ -+ if (size < sizeof(unsigned) * SMEM_MASTER_SBL_VERSION_INDEX) { -+ dev_err(smem->dev, "Version item is too small\n"); -+ return -EINVAL; -+ } -+ -+ return versions[SMEM_MASTER_SBL_VERSION_INDEX]; -+} -+ -+static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, -+ unsigned local_host) -+{ -+ struct smem_partition_header *header; -+ struct smem_ptable_entry *entry; -+ struct smem_ptable *ptable; -+ unsigned remote_host; -+ int i; -+ -+ ptable = smem->regions[0].virt_base + smem->regions[0].size - 4 * 1024; -+ if (ptable->magic != SMEM_PTABLE_MAGIC) -+ return 0; -+ -+ if (ptable->version != 1) { -+ dev_err(smem->dev, -+ "Unsupported partition header version %d\n", -+ ptable->version); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < ptable->num_entries; i++) { -+ entry = &ptable->entry[i]; -+ -+ if (entry->host0 != local_host && entry->host1 != local_host) -+ continue; -+ -+ if (!entry->offset) -+ continue; -+ -+ if (!entry->size) -+ continue; -+ -+ if (entry->host0 == local_host) -+ remote_host = entry->host1; -+ else -+ remote_host = entry->host0; -+ -+ if (smem->partitions[remote_host]) { -+ dev_err(smem->dev, -+ "Already found a partition for host %d\n", -+ remote_host); -+ return -EINVAL; -+ } -+ -+ header = smem->regions[0].virt_base + entry->offset; -+ -+ if (header->magic != SMEM_PART_MAGIC) { -+ dev_err(smem->dev, -+ "Partition %d has invalid magic\n", i); -+ return -EINVAL; -+ } -+ -+ if (header->host0 != local_host && header->host1 != local_host) { -+ dev_err(smem->dev, -+ "Partition %d hosts are invalid\n", i); -+ return -EINVAL; -+ } -+ -+ if (header->host0 != remote_host && header->host1 != remote_host) { -+ dev_err(smem->dev, -+ "Partition %d hosts are invalid\n", i); -+ return -EINVAL; -+ } -+ -+ if (header->size != entry->size) { -+ dev_err(smem->dev, -+ "Partition %d has invalid size\n", i); -+ return -EINVAL; -+ } -+ -+ if (header->offset_free_uncached > header->size) { -+ dev_err(smem->dev, -+ "Partition %d has invalid free pointer\n", i); -+ return -EINVAL; -+ } -+ -+ smem->partitions[remote_host] = header; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_count_mem_regions(struct platform_device *pdev) -+{ -+ struct resource *res; -+ int num_regions = 0; -+ int i; -+ -+ for (i = 0; i < pdev->num_resources; i++) { -+ res = &pdev->resource[i]; -+ -+ if (resource_type(res) == IORESOURCE_MEM) -+ num_regions++; -+ } -+ -+ return num_regions; -+} -+ -+static int qcom_smem_probe(struct platform_device *pdev) -+{ -+ struct smem_header *header; -+ struct device_node *np; -+ struct qcom_smem *smem; -+ struct resource *res; -+ struct resource r; -+ size_t array_size; -+ int num_regions = 0; -+ int hwlock_id; -+ u32 version; -+ int ret; -+ int i; -+ -+ num_regions = qcom_smem_count_mem_regions(pdev) + 1; -+ -+ array_size = num_regions * sizeof(struct smem_region); -+ smem = devm_kzalloc(&pdev->dev, sizeof(*smem) + array_size, GFP_KERNEL); -+ if (!smem) -+ return -ENOMEM; -+ -+ smem->dev = &pdev->dev; -+ smem->num_regions = num_regions; -+ -+ np = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); -+ if (!np) { -+ dev_err(&pdev->dev, "No memory-region specified\n"); -+ return -EINVAL; -+ } -+ -+ ret = of_address_to_resource(np, 0, &r); -+ of_node_put(np); -+ if (ret) -+ return ret; -+ -+ smem->regions[0].aux_base = (u32)r.start; -+ smem->regions[0].size = resource_size(&r); -+ smem->regions[0].virt_base = devm_ioremap_nocache(&pdev->dev, -+ r.start, -+ resource_size(&r)); -+ if (!smem->regions[0].virt_base) -+ return -ENOMEM; -+ -+ for (i = 1; i < num_regions; i++) { -+ res = platform_get_resource(pdev, IORESOURCE_MEM, i - 1); -+ -+ smem->regions[i].aux_base = (u32)res->start; -+ smem->regions[i].size = resource_size(res); -+ smem->regions[i].virt_base = devm_ioremap_nocache(&pdev->dev, -+ res->start, -+ resource_size(res)); -+ if (!smem->regions[i].virt_base) -+ return -ENOMEM; -+ } -+ -+ header = smem->regions[0].virt_base; -+ if (header->initialized != 1 || header->reserved) { -+ dev_err(&pdev->dev, "SMEM is not initilized by SBL\n"); -+ return -EINVAL; -+ } -+ -+ version = qcom_smem_get_sbl_version(smem); -+ if (version >> 16 != SMEM_EXPECTED_VERSION) { -+ dev_err(&pdev->dev, "Unsupported smem version 0x%x\n", version); -+ return -EINVAL; -+ } -+ -+ ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); -+ if (ret < 0) -+ return ret; -+ -+ hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); -+ if (hwlock_id < 0) { -+ dev_err(&pdev->dev, "failed to retrieve hwlock\n"); -+ return hwlock_id; -+ } -+ -+ smem->hwlock = hwspin_lock_request_specific(hwlock_id); -+ if (!smem->hwlock) -+ return -ENXIO; -+ -+ __smem = smem; -+ -+ return 0; -+} -+ -+static int qcom_smem_remove(struct platform_device *pdev) -+{ -+ hwspin_lock_free(__smem->hwlock); -+ __smem = NULL; -+ -+ return 0; -+} -+ -+static const struct of_device_id qcom_smem_of_match[] = { -+ { .compatible = "qcom,smem" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, qcom_smem_of_match); -+ -+static struct platform_driver qcom_smem_driver = { -+ .probe = qcom_smem_probe, -+ .remove = qcom_smem_remove, -+ .driver = { -+ .name = "qcom_smem", -+ .of_match_table = qcom_smem_of_match, -+ .suppress_bind_attrs = true, -+ }, -+}; -+ -+static int __init qcom_smem_init(void) -+{ -+ return platform_driver_register(&qcom_smem_driver); -+} -+arch_initcall(qcom_smem_init); -+ -+static void __exit qcom_smem_exit(void) -+{ -+ platform_driver_unregister(&qcom_smem_driver); -+} -+module_exit(qcom_smem_exit) -+ -+MODULE_AUTHOR("Bjorn Andersson "); -+MODULE_DESCRIPTION("Qualcomm Shared Memory Manager"); -+MODULE_LICENSE("GPLv2"); ---- /dev/null -+++ b/include/linux/soc/qcom/smem.h -@@ -0,0 +1,14 @@ -+#ifndef __QCOM_SMEM_H__ -+#define __QCOM_SMEM_H__ -+ -+struct device_node; -+struct qcom_smem; -+ -+#define QCOM_SMEM_HOST_ANY -1 -+ -+int qcom_smem_alloc(unsigned host, unsigned item, size_t size); -+int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size); -+ -+int qcom_smem_get_free_space(unsigned host); -+ -+#endif diff --git a/target/linux/ipq806x/patches-3.18/036-ARM-qcom-add-SMEM-device-node-to-IPQ806x-dts.patch b/target/linux/ipq806x/patches-3.18/036-ARM-qcom-add-SMEM-device-node-to-IPQ806x-dts.patch deleted file mode 100644 index b2b9a749c34c..000000000000 --- a/target/linux/ipq806x/patches-3.18/036-ARM-qcom-add-SMEM-device-node-to-IPQ806x-dts.patch +++ /dev/null @@ -1,36 +0,0 @@ -From f212be3a6134db8dd7c5f6f0987536a669401fae Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Fri, 14 Aug 2015 11:17:20 -0700 -Subject: [PATCH 2/3] ARM: qcom: add SMEM device node to IPQ806x dts - -SMEM is used on IPQ806x to store various board related information such -as boot device and flash partition layout. We'll declare it as a device -so we can make use of it thanks to the new SMEM soc driver. - -Signed-off-by: Mathieu Olivari ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -54,7 +54,7 @@ - no-map; - }; - -- smem@41000000 { -+ smem: smem@41000000 { - reg = <0x41000000 0x200000>; - no-map; - }; -@@ -304,4 +304,10 @@ - - #hwlock-cells = <1>; - }; -+ -+ smem { -+ compatible = "qcom,smem"; -+ memory-region = <&smem>; -+ hwlocks = <&sfpb_mutex 3>; -+ }; - }; diff --git a/target/linux/ipq806x/patches-3.18/037-mtd-add-SMEM-parser-for-QCOM-platforms.patch b/target/linux/ipq806x/patches-3.18/037-mtd-add-SMEM-parser-for-QCOM-platforms.patch deleted file mode 100644 index b2c8cd5c53a3..000000000000 --- a/target/linux/ipq806x/patches-3.18/037-mtd-add-SMEM-parser-for-QCOM-platforms.patch +++ /dev/null @@ -1,277 +0,0 @@ -From 0501f76b138cf1dc11a313bb7a094da524b79337 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Thu, 13 Aug 2015 09:53:14 -0700 -Subject: [PATCH 3/3] mtd: add SMEM parser for QCOM platforms - -On QCOM platforms using MTD devices storage (such as IPQ806x), SMEM is -used to store partition layout. This new parser can now be used to read -SMEM and use it to register an MTD layout according to its content. - -Signed-off-by: Mathieu Olivari ---- - drivers/mtd/Kconfig | 7 ++ - drivers/mtd/Makefile | 1 + - drivers/mtd/qcom_smem_part.c | 231 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 239 insertions(+) - create mode 100644 drivers/mtd/qcom_smem_part.c - ---- a/drivers/mtd/Kconfig -+++ b/drivers/mtd/Kconfig -@@ -200,6 +200,13 @@ config MTD_MYLOADER_PARTS - You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. - -+config MTD_QCOM_SMEM_PARTS -+ tristate "QCOM SMEM partitioning support" -+ depends on QCOM_SMEM -+ help -+ This provides partitions parser for QCOM devices using SMEM -+ such as IPQ806x. -+ - comment "User Modules And Translation Layers" - - # ---- /dev/null -+++ b/drivers/mtd/qcom_smem_part.c -@@ -0,0 +1,231 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* Processor/host identifier for the application processor */ -+#define SMEM_HOST_APPS 0 -+ -+/* SMEM items index */ -+#define SMEM_AARM_PARTITION_TABLE 9 -+#define SMEM_BOOT_FLASH_TYPE 421 -+#define SMEM_BOOT_FLASH_BLOCK_SIZE 424 -+ -+/* SMEM Flash types */ -+#define SMEM_FLASH_NAND 2 -+#define SMEM_FLASH_SPI 6 -+ -+#define SMEM_PART_NAME_SZ 16 -+#define SMEM_PARTS_MAX 32 -+ -+struct smem_partition { -+ char name[SMEM_PART_NAME_SZ]; -+ __le32 start; -+ __le32 size; -+ __le32 attr; -+}; -+ -+struct smem_partition_table { -+ u8 magic[8]; -+ __le32 version; -+ __le32 len; -+ struct smem_partition parts[SMEM_PARTS_MAX]; -+}; -+ -+/* SMEM Magic values in partition table */ -+static const u8 SMEM_PTABLE_MAGIC[] = { -+ 0xaa, 0x73, 0xee, 0x55, -+ 0xdb, 0xbd, 0x5e, 0xe3, -+}; -+ -+static int qcom_smem_get_flash_blksz(u64 **smem_blksz) -+{ -+ int ret; -+ size_t size; -+ -+ ret = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_BLOCK_SIZE, -+ (void **) smem_blksz, &size); -+ -+ if (ret < 0) { -+ pr_err("Unable to read flash blksz from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_blksz)) { -+ pr_err("Invalid flash blksz size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_type(u64 **smem_flash_type) -+{ -+ int ret; -+ size_t size; -+ -+ ret = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_TYPE, -+ (void **) smem_flash_type, &size); -+ -+ if (ret < 0) { -+ pr_err("Unable to read flash type from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_flash_type)) { -+ pr_err("Invalid flash type size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_partitions(struct smem_partition_table **pparts) -+{ -+ int ret; -+ size_t size; -+ -+ ret = qcom_smem_get(SMEM_HOST_APPS, SMEM_AARM_PARTITION_TABLE, -+ (void **) pparts, &size); -+ -+ if (ret < 0) { -+ pr_err("Unable to read partition table from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ return 0; -+} -+ -+static int of_dev_node_match(struct device *dev, void *data) -+{ -+ return dev->of_node == data; -+} -+ -+static bool is_spi_device(struct device_node *np) -+{ -+ struct device *dev; -+ -+ dev = bus_find_device(&spi_bus_type, NULL, np, of_dev_node_match); -+ if (!dev) -+ return false; -+ -+ put_device(dev); -+ return true; -+} -+ -+static int parse_qcom_smem_partitions(struct mtd_info *master, -+ struct mtd_partition **pparts, -+ struct mtd_part_parser_data *data) -+{ -+ struct smem_partition_table *smem_parts; -+ u64 *smem_flash_type, *smem_blksz; -+ struct mtd_partition *mtd_parts; -+ struct device_node *of_node = data->of_node; -+ int i, ret; -+ -+ /* -+ * SMEM will only store the partition table of the boot device. -+ * If this is not the boot device, do not return any partition. -+ */ -+ ret = qcom_smem_get_flash_type(&smem_flash_type); -+ if (ret < 0) -+ return ret; -+ -+ if ((*smem_flash_type == SMEM_FLASH_NAND && !mtd_type_is_nand(master)) -+ || (*smem_flash_type == SMEM_FLASH_SPI && !is_spi_device(of_node))) -+ return 0; -+ -+ /* -+ * Just for sanity purpose, make sure the block size in SMEM matches the -+ * block size of the MTD device -+ */ -+ ret = qcom_smem_get_flash_blksz(&smem_blksz); -+ if (ret < 0) -+ return ret; -+ -+ if (*smem_blksz != master->erasesize) { -+ pr_err("SMEM block size differs from MTD block size\n"); -+ return -EINVAL; -+ } -+ -+ /* Get partition pointer from SMEM */ -+ ret = qcom_smem_get_flash_partitions(&smem_parts); -+ if (ret < 0) -+ return ret; -+ -+ if (memcmp(SMEM_PTABLE_MAGIC, smem_parts->magic, -+ sizeof(SMEM_PTABLE_MAGIC))) { -+ pr_err("SMEM partition magic invalid\n"); -+ return -EINVAL; -+ } -+ -+ /* Allocate and populate the mtd structures */ -+ mtd_parts = kcalloc(le32_to_cpu(smem_parts->len), sizeof(*mtd_parts), -+ GFP_KERNEL); -+ if (!mtd_parts) -+ return -ENOMEM; -+ -+ for (i = 0; i < smem_parts->len; i++) { -+ struct smem_partition *s_part = &smem_parts->parts[i]; -+ struct mtd_partition *m_part = &mtd_parts[i]; -+ -+ m_part->name = s_part->name; -+ m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); -+ m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); -+ -+ /* -+ * The last SMEM partition may have its size marked as -+ * something like 0xffffffff, which means "until the end of the -+ * flash device". In this case, truncate it. -+ */ -+ if (m_part->offset + m_part->size > master->size) -+ m_part->size = master->size - m_part->offset; -+ } -+ -+ *pparts = mtd_parts; -+ -+ return smem_parts->len; -+} -+ -+static struct mtd_part_parser qcom_smem_parser = { -+ .owner = THIS_MODULE, -+ .parse_fn = parse_qcom_smem_partitions, -+ .name = "qcom-smem", -+}; -+ -+static int __init qcom_smem_parser_init(void) -+{ -+ register_mtd_parser(&qcom_smem_parser); -+ return 0; -+} -+ -+static void __exit qcom_smem_parser_exit(void) -+{ -+ deregister_mtd_parser(&qcom_smem_parser); -+} -+ -+module_init(qcom_smem_parser_init); -+module_exit(qcom_smem_parser_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Mathieu Olivari "); -+MODULE_DESCRIPTION("Parsing code for SMEM based partition tables"); ---- a/drivers/mtd/Makefile -+++ b/drivers/mtd/Makefile -@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o - obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o - obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o - obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o -+obj-$(CONFIG_MTD_QCOM_SMEM_PARTS) += qcom_smem_part.o - - # 'Users' - code which presents functionality to userspace. - obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o diff --git a/target/linux/ipq806x/patches-3.18/100-usb-phy-Add-Qualcomm-DWC3-HS-SS-PHY-drivers.patch b/target/linux/ipq806x/patches-3.18/100-usb-phy-Add-Qualcomm-DWC3-HS-SS-PHY-drivers.patch deleted file mode 100644 index 25803b88ebee..000000000000 --- a/target/linux/ipq806x/patches-3.18/100-usb-phy-Add-Qualcomm-DWC3-HS-SS-PHY-drivers.patch +++ /dev/null @@ -1,511 +0,0 @@ ---- a/drivers/phy/Kconfig -+++ b/drivers/phy/Kconfig -@@ -256,4 +256,15 @@ config PHY_STIH41X_USB - Enable this to support the USB transceiver that is part of - STMicroelectronics STiH41x SoC series. - -+config PHY_QCOM_DWC3 -+ tristate "QCOM DWC3 USB PHY support" -+ depends on ARCH_QCOM -+ depends on HAS_IOMEM -+ depends on OF -+ select GENERIC_PHY -+ help -+ This option enables support for the Synopsis PHYs present inside the -+ Qualcomm USB3.0 DWC3 controller. This driver supports both HS and SS -+ PHY controllers. -+ - endmenu ---- a/drivers/phy/Makefile -+++ b/drivers/phy/Makefile -@@ -31,3 +31,4 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += - obj-$(CONFIG_PHY_XGENE) += phy-xgene.o - obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o - obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o -+obj-$(CONFIG_PHY_QCOM_DWC3) += phy-qcom-dwc3.o ---- /dev/null -+++ b/drivers/phy/phy-qcom-dwc3.c -@@ -0,0 +1,483 @@ -+/* Copyright (c) 2013-2014, Code Aurora Forum. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/** -+ * USB QSCRATCH Hardware registers -+ */ -+#define QSCRATCH_GENERAL_CFG (0x08) -+#define HSUSB_PHY_CTRL_REG (0x10) -+ -+/* PHY_CTRL_REG */ -+#define HSUSB_CTRL_DMSEHV_CLAMP BIT(24) -+#define HSUSB_CTRL_USB2_SUSPEND BIT(23) -+#define HSUSB_CTRL_UTMI_CLK_EN BIT(21) -+#define HSUSB_CTRL_UTMI_OTG_VBUS_VALID BIT(20) -+#define HSUSB_CTRL_USE_CLKCORE BIT(18) -+#define HSUSB_CTRL_DPSEHV_CLAMP BIT(17) -+#define HSUSB_CTRL_COMMONONN BIT(11) -+#define HSUSB_CTRL_ID_HV_CLAMP BIT(9) -+#define HSUSB_CTRL_OTGSESSVLD_CLAMP BIT(8) -+#define HSUSB_CTRL_CLAMP_EN BIT(7) -+#define HSUSB_CTRL_RETENABLEN BIT(1) -+#define HSUSB_CTRL_POR BIT(0) -+ -+/* QSCRATCH_GENERAL_CFG */ -+#define HSUSB_GCFG_XHCI_REV BIT(2) -+ -+/** -+ * USB QSCRATCH Hardware registers -+ */ -+#define SSUSB_PHY_CTRL_REG (0x00) -+#define SSUSB_PHY_PARAM_CTRL_1 (0x04) -+#define SSUSB_PHY_PARAM_CTRL_2 (0x08) -+#define CR_PROTOCOL_DATA_IN_REG (0x0c) -+#define CR_PROTOCOL_DATA_OUT_REG (0x10) -+#define CR_PROTOCOL_CAP_ADDR_REG (0x14) -+#define CR_PROTOCOL_CAP_DATA_REG (0x18) -+#define CR_PROTOCOL_READ_REG (0x1c) -+#define CR_PROTOCOL_WRITE_REG (0x20) -+ -+/* PHY_CTRL_REG */ -+#define SSUSB_CTRL_REF_USE_PAD BIT(28) -+#define SSUSB_CTRL_TEST_POWERDOWN BIT(27) -+#define SSUSB_CTRL_LANE0_PWR_PRESENT BIT(24) -+#define SSUSB_CTRL_SS_PHY_EN BIT(8) -+#define SSUSB_CTRL_SS_PHY_RESET BIT(7) -+ -+/* SSPHY control registers */ -+#define SSPHY_CTRL_RX_OVRD_IN_HI(lane) (0x1006 + 0x100 * lane) -+#define SSPHY_CTRL_TX_OVRD_DRV_LO(lane) (0x1002 + 0x100 * lane) -+ -+/* RX OVRD IN HI bits */ -+#define RX_OVRD_IN_HI_RX_RESET_OVRD BIT(13) -+#define RX_OVRD_IN_HI_RX_RX_RESET BIT(12) -+#define RX_OVRD_IN_HI_RX_EQ_OVRD BIT(11) -+#define RX_OVRD_IN_HI_RX_EQ_MASK 0x0700 -+#define RX_OVRD_IN_HI_RX_EQ_SHIFT 8 -+#define RX_OVRD_IN_HI_RX_EQ_EN_OVRD BIT(7) -+#define RX_OVRD_IN_HI_RX_EQ_EN BIT(6) -+#define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD BIT(5) -+#define RX_OVRD_IN_HI_RX_LOS_FILTER_MASK 0x0018 -+#define RX_OVRD_IN_HI_RX_RATE_OVRD BIT(2) -+#define RX_OVRD_IN_HI_RX_RATE_MASK 0x0003 -+ -+/* TX OVRD DRV LO register bits */ -+#define TX_OVRD_DRV_LO_AMPLITUDE_MASK 0x007F -+#define TX_OVRD_DRV_LO_PREEMPH_MASK 0x3F80 -+#define TX_OVRD_DRV_LO_PREEMPH_SHIFT 7 -+#define TX_OVRD_DRV_LO_EN BIT(14) -+ -+struct qcom_dwc3_usb_phy { -+ void __iomem *base; -+ struct device *dev; -+ struct phy *phy; -+ -+ int (*phy_init)(struct qcom_dwc3_usb_phy *phy_dwc3); -+ int (*phy_exit)(struct qcom_dwc3_usb_phy *phy_dwc3); -+ -+ struct clk *xo_clk; -+ struct clk *ref_clk; -+}; -+ -+/** -+ * Write register and read back masked value to confirm it is written -+ * -+ * @base - QCOM DWC3 PHY base virtual address. -+ * @offset - register offset. -+ * @mask - register bitmask specifying what should be updated -+ * @val - value to write. -+ */ -+static inline void qcom_dwc3_phy_write_readback( -+ struct qcom_dwc3_usb_phy *phy_dwc3, u32 offset, -+ const u32 mask, u32 val) -+{ -+ u32 write_val, tmp = readl(phy_dwc3->base + offset); -+ -+ tmp &= ~mask; /* retain other bits */ -+ write_val = tmp | val; -+ -+ writel(write_val, phy_dwc3->base + offset); -+ -+ /* Read back to see if val was written */ -+ tmp = readl(phy_dwc3->base + offset); -+ tmp &= mask; /* clear other bits */ -+ -+ if (tmp != val) -+ dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n", -+ val, offset); -+} -+ -+static int wait_for_latch(void __iomem *addr) -+{ -+ u32 retry = 10; -+ -+ while (true) { -+ if (!readl(addr)) -+ break; -+ -+ if (--retry == 0) -+ return -ETIMEDOUT; -+ -+ usleep_range(10, 20); -+ } -+ -+ return 0; -+} -+ -+/** -+ * Write SSPHY register -+ * -+ * @base - QCOM DWC3 PHY base virtual address. -+ * @addr - SSPHY address to write. -+ * @val - value to write. -+ */ -+static int qcom_dwc3_ss_write_phycreg(void __iomem *base, u32 addr, u32 val) -+{ -+ int ret; -+ -+ writel(addr, base + CR_PROTOCOL_DATA_IN_REG); -+ writel(0x1, base + CR_PROTOCOL_CAP_ADDR_REG); -+ -+ ret = wait_for_latch(base + CR_PROTOCOL_CAP_ADDR_REG); -+ if (ret) -+ goto err_wait; -+ -+ writel(val, base + CR_PROTOCOL_DATA_IN_REG); -+ writel(0x1, base + CR_PROTOCOL_CAP_DATA_REG); -+ -+ ret = wait_for_latch(base + CR_PROTOCOL_CAP_DATA_REG); -+ if (ret) -+ goto err_wait; -+ -+ writel(0x1, base + CR_PROTOCOL_WRITE_REG); -+ -+ ret = wait_for_latch(base + CR_PROTOCOL_WRITE_REG); -+ -+err_wait: -+ return ret; -+} -+ -+/** -+ * Read SSPHY register. -+ * -+ * @base - QCOM DWC3 PHY base virtual address. -+ * @addr - SSPHY address to read. -+ */ -+static int qcom_dwc3_ss_read_phycreg(void __iomem *base, u32 addr, u32 *val) -+{ -+ int ret; -+ bool first_read = true; -+ -+ writel(addr, base + CR_PROTOCOL_DATA_IN_REG); -+ writel(0x1, base + CR_PROTOCOL_CAP_ADDR_REG); -+ -+ ret = wait_for_latch(base + CR_PROTOCOL_CAP_ADDR_REG); -+ if (ret) -+ goto err_wait; -+ -+ /* -+ * Due to hardware bug, first read of SSPHY register might be -+ * incorrect. Hence as workaround, SW should perform SSPHY register -+ * read twice, but use only second read and ignore first read. -+ */ -+retry: -+ writel(0x1, base + CR_PROTOCOL_READ_REG); -+ -+ ret = wait_for_latch(base + CR_PROTOCOL_READ_REG); -+ if (ret) -+ goto err_wait; -+ -+ if (first_read) { -+ readl(base + CR_PROTOCOL_DATA_OUT_REG); -+ first_read = false; -+ goto retry; -+ } -+ -+ *val = readl(base + CR_PROTOCOL_DATA_OUT_REG); -+ -+err_wait: -+ return ret; -+} -+ -+static int qcom_dwc3_phy_power_on(struct phy *phy) -+{ -+ int ret; -+ struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy); -+ -+ ret = clk_prepare_enable(phy_dwc3->xo_clk); -+ if (ret) -+ return ret; -+ -+ ret = clk_prepare_enable(phy_dwc3->ref_clk); -+ if (ret) -+ clk_disable_unprepare(phy_dwc3->xo_clk); -+ -+ return ret; -+} -+ -+static int qcom_dwc3_phy_power_off(struct phy *phy) -+{ -+ struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy); -+ -+ clk_disable_unprepare(phy_dwc3->ref_clk); -+ clk_disable_unprepare(phy_dwc3->xo_clk); -+ -+ return 0; -+} -+ -+static int qcom_dwc3_hs_phy_init(struct qcom_dwc3_usb_phy *phy_dwc3) -+{ -+ u32 val; -+ -+ /* -+ * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel -+ * enable clamping, and disable RETENTION (power-on default is ENABLED) -+ */ -+ val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP | -+ HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN | -+ HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP | -+ HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID | -+ HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70; -+ -+ /* use core clock if external reference is not present */ -+ if (!phy_dwc3->xo_clk) -+ val |= HSUSB_CTRL_USE_CLKCORE; -+ -+ writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG); -+ usleep_range(2000, 2200); -+ -+ /* Disable (bypass) VBUS and ID filters */ -+ writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG); -+ -+ return 0; -+} -+ -+static int qcom_dwc3_ss_phy_init(struct qcom_dwc3_usb_phy *phy_dwc3) -+{ -+ int ret; -+ u32 data = 0; -+ -+ /* reset phy */ -+ data = readl_relaxed(phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ writel_relaxed(data | SSUSB_CTRL_SS_PHY_RESET, -+ phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ usleep_range(2000, 2200); -+ writel_relaxed(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ -+ /* clear REF_PAD if we don't have XO clk */ -+ if (!phy_dwc3->xo_clk) -+ data &= ~SSUSB_CTRL_REF_USE_PAD; -+ else -+ data |= SSUSB_CTRL_REF_USE_PAD; -+ -+ writel_relaxed(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ msleep(30); -+ -+ data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT; -+ writel_relaxed(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ -+ /* -+ * Fix RX Equalization setting as follows -+ * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 -+ * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 -+ * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3 -+ * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 -+ */ -+ ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base, -+ SSPHY_CTRL_RX_OVRD_IN_HI(0), &data); -+ if (ret) -+ goto err_phy_trans; -+ -+ data &= ~RX_OVRD_IN_HI_RX_EQ_EN; -+ data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD; -+ data &= ~RX_OVRD_IN_HI_RX_EQ_MASK; -+ data |= 0x3 << RX_OVRD_IN_HI_RX_EQ_SHIFT; -+ data |= RX_OVRD_IN_HI_RX_EQ_OVRD; -+ ret = qcom_dwc3_ss_write_phycreg(phy_dwc3->base, -+ SSPHY_CTRL_RX_OVRD_IN_HI(0), data); -+ if (ret) -+ goto err_phy_trans; -+ -+ /* -+ * Set EQ and TX launch amplitudes as follows -+ * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22 -+ * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127 -+ * LANE0.TX_OVRD_DRV_LO.EN set to 1. -+ */ -+ ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base, -+ SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data); -+ if (ret) -+ goto err_phy_trans; -+ -+ data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK; -+ data |= 0x16 << TX_OVRD_DRV_LO_PREEMPH_SHIFT; -+ data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK; -+ data |= 0x7f; -+ data |= TX_OVRD_DRV_LO_EN; -+ ret = qcom_dwc3_ss_write_phycreg(phy_dwc3->base, -+ SSPHY_CTRL_TX_OVRD_DRV_LO(0), data); -+ if (ret) -+ goto err_phy_trans; -+ -+ /* -+ * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows -+ * TX_FULL_SWING [26:20] amplitude to 127 -+ * TX_DEEMPH_3_5DB [13:8] to 22 -+ * LOS_BIAS [2:0] to 0x5 -+ */ -+ qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1, -+ 0x07f03f07, 0x07f01605); -+ -+err_phy_trans: -+ return ret; -+} -+ -+static int qcom_dwc3_ss_phy_exit(struct qcom_dwc3_usb_phy *phy_dwc3) -+{ -+ /* Sequence to put SSPHY in low power state: -+ * 1. Clear REF_PHY_EN in PHY_CTRL_REG -+ * 2. Clear REF_USE_PAD in PHY_CTRL_REG -+ * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention -+ * 4. Disable SSPHY ref clk -+ */ -+ qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, -+ SSUSB_CTRL_SS_PHY_EN, 0x0); -+ qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, -+ SSUSB_CTRL_REF_USE_PAD, 0x0); -+ qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, -+ 0x0, SSUSB_CTRL_TEST_POWERDOWN); -+ -+ return 0; -+} -+ -+static int qcom_dwc3_phy_init(struct phy *phy) -+{ -+ struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy); -+ -+ if (phy_dwc3->phy_init) -+ return phy_dwc3->phy_init(phy_dwc3); -+ -+ return 0; -+} -+ -+static int qcom_dwc3_phy_exit(struct phy *phy) -+{ -+ struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy); -+ -+ if (phy_dwc3->phy_exit) -+ return qcom_dwc3_ss_phy_exit(phy_dwc3); -+ -+ return 0; -+} -+ -+static struct phy_ops qcom_dwc3_phy_ops = { -+ .init = qcom_dwc3_phy_init, -+ .exit = qcom_dwc3_phy_exit, -+ .power_on = qcom_dwc3_phy_power_on, -+ .power_off = qcom_dwc3_phy_power_off, -+ .owner = THIS_MODULE, -+}; -+ -+static const struct of_device_id qcom_dwc3_phy_table[] = { -+ { .compatible = "qcom,dwc3-hs-usb-phy", }, -+ { .compatible = "qcom,dwc3-ss-usb-phy", }, -+ { /* Sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, qcom_dwc3_phy_table); -+ -+static int qcom_dwc3_phy_probe(struct platform_device *pdev) -+{ -+ struct qcom_dwc3_usb_phy *phy_dwc3; -+ struct phy_provider *phy_provider; -+ struct resource *res; -+ -+ phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL); -+ if (!phy_dwc3) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, phy_dwc3); -+ -+ phy_dwc3->dev = &pdev->dev; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ phy_dwc3->base = devm_ioremap_resource(phy_dwc3->dev, res); -+ if (IS_ERR(phy_dwc3->base)) -+ return PTR_ERR(phy_dwc3->base); -+ -+ phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref"); -+ if (IS_ERR(phy_dwc3->ref_clk)) { -+ dev_dbg(phy_dwc3->dev, "cannot get reference clock\n"); -+ return PTR_ERR(phy_dwc3->ref_clk); -+ } -+ -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "qcom,dwc3-hs-usb-phy")) { -+ clk_set_rate(phy_dwc3->ref_clk, 60000000); -+ phy_dwc3->phy_init = qcom_dwc3_hs_phy_init; -+ } else if (of_device_is_compatible(pdev->dev.of_node, -+ "qcom,dwc3-ss-usb-phy")) { -+ phy_dwc3->phy_init = qcom_dwc3_ss_phy_init; -+ phy_dwc3->phy_exit = qcom_dwc3_ss_phy_exit; -+ clk_set_rate(phy_dwc3->ref_clk, 125000000); -+ } else { -+ dev_err(phy_dwc3->dev, "Unknown phy\n"); -+ return -EINVAL; -+ } -+ -+ phy_dwc3->xo_clk = devm_clk_get(phy_dwc3->dev, "xo"); -+ if (IS_ERR(phy_dwc3->xo_clk)) { -+ dev_dbg(phy_dwc3->dev, "cannot get TCXO clock\n"); -+ phy_dwc3->xo_clk = NULL; -+ } -+ -+ phy_dwc3->phy = devm_phy_create(phy_dwc3->dev, NULL, &qcom_dwc3_phy_ops, -+ NULL); -+ -+ if (IS_ERR(phy_dwc3->phy)) -+ return PTR_ERR(phy_dwc3->phy); -+ -+ phy_set_drvdata(phy_dwc3->phy, phy_dwc3); -+ -+ phy_provider = devm_of_phy_provider_register(phy_dwc3->dev, -+ of_phy_simple_xlate); -+ -+ if (IS_ERR(phy_provider)) -+ return PTR_ERR(phy_provider); -+ -+ return 0; -+} -+ -+static struct platform_driver qcom_dwc3_phy_driver = { -+ .probe = qcom_dwc3_phy_probe, -+ .driver = { -+ .name = "qcom-dwc3-usb-phy", -+ .owner = THIS_MODULE, -+ .of_match_table = qcom_dwc3_phy_table, -+ }, -+}; -+ -+module_platform_driver(qcom_dwc3_phy_driver); -+ -+MODULE_ALIAS("platform:phy-qcom-dwc3"); -+MODULE_LICENSE("GPL v2"); -+MODULE_AUTHOR("Andy Gross "); -+MODULE_AUTHOR("Ivan T. Ivanov "); -+MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver"); diff --git a/target/linux/ipq806x/patches-3.18/101-ARM-qcom-add-USB-nodes-to-ipq806x-ap148.patch b/target/linux/ipq806x/patches-3.18/101-ARM-qcom-add-USB-nodes-to-ipq806x-ap148.patch deleted file mode 100644 index e2d03d4ffd26..000000000000 --- a/target/linux/ipq806x/patches-3.18/101-ARM-qcom-add-USB-nodes-to-ipq806x-ap148.patch +++ /dev/null @@ -1,126 +0,0 @@ ---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -@@ -91,5 +91,29 @@ - sata@29000000 { - status = "ok"; - }; -+ -+ phy@100f8800 { /* USB3 port 1 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@100f8830 { /* USB3 port 1 SS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8800 { /* USB3 port 0 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8830 { /* USB3 port 0 SS phy */ -+ status = "ok"; -+ }; -+ -+ usb30@0 { -+ status = "ok"; -+ }; -+ -+ usb30@1 { -+ status = "ok"; -+ }; - }; - }; ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -296,6 +296,91 @@ - compatible = "syscon"; - reg = <0x01200600 0x100>; - }; -+ -+ hs_phy_1: phy@100f8800 { -+ compatible = "qcom,dwc3-hs-usb-phy"; -+ reg = <0x100f8800 0x30>; -+ clocks = <&gcc USB30_1_UTMI_CLK>; -+ clock-names = "ref"; -+ #phy-cells = <0>; -+ -+ status = "disabled"; -+ }; -+ -+ ss_phy_1: phy@100f8830 { -+ compatible = "qcom,dwc3-ss-usb-phy"; -+ reg = <0x100f8830 0x30>; -+ clocks = <&gcc USB30_1_MASTER_CLK>; -+ clock-names = "ref"; -+ #phy-cells = <0>; -+ -+ status = "disabled"; -+ }; -+ -+ hs_phy_0: phy@110f8800 { -+ compatible = "qcom,dwc3-hs-usb-phy"; -+ reg = <0x110f8800 0x30>; -+ clocks = <&gcc USB30_0_UTMI_CLK>; -+ clock-names = "ref"; -+ #phy-cells = <0>; -+ -+ status = "disabled"; -+ }; -+ -+ ss_phy_0: phy@110f8830 { -+ compatible = "qcom,dwc3-ss-usb-phy"; -+ reg = <0x110f8830 0x30>; -+ clocks = <&gcc USB30_0_MASTER_CLK>; -+ clock-names = "ref"; -+ #phy-cells = <0>; -+ -+ status = "disabled"; -+ }; -+ -+ usb3_0: usb30@0 { -+ compatible = "qcom,dwc3"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ clocks = <&gcc USB30_0_MASTER_CLK>; -+ clock-names = "core"; -+ -+ ranges; -+ -+ status = "disabled"; -+ -+ dwc3@11000000 { -+ compatible = "snps,dwc3"; -+ reg = <0x11000000 0xcd00>; -+ interrupts = <0 110 0x4>; -+ phys = <&hs_phy_0>, <&ss_phy_0>; -+ phy-names = "usb2-phy", "usb3-phy"; -+ tx-fifo-resize; -+ dr_mode = "host"; -+ }; -+ }; -+ -+ usb3_1: usb30@1 { -+ compatible = "qcom,dwc3"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ clocks = <&gcc USB30_1_MASTER_CLK>; -+ clock-names = "core"; -+ -+ ranges; -+ -+ status = "disabled"; -+ -+ dwc3@10000000 { -+ compatible = "snps,dwc3"; -+ reg = <0x10000000 0xcd00>; -+ interrupts = <0 205 0x4>; -+ phys = <&hs_phy_1>, <&ss_phy_1>; -+ phy-names = "usb2-phy", "usb3-phy"; -+ tx-fifo-resize; -+ dr_mode = "host"; -+ }; -+ }; -+ - }; - - sfpb_mutex: sfpb-mutex { diff --git a/target/linux/ipq806x/patches-3.18/102-soc-qcom-gsbi-Add-support-for-ADM-CRCI-muxing.patch b/target/linux/ipq806x/patches-3.18/102-soc-qcom-gsbi-Add-support-for-ADM-CRCI-muxing.patch deleted file mode 100644 index 752f3f74d5a4..000000000000 --- a/target/linux/ipq806x/patches-3.18/102-soc-qcom-gsbi-Add-support-for-ADM-CRCI-muxing.patch +++ /dev/null @@ -1,249 +0,0 @@ ---- a/Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt -+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt -@@ -6,7 +6,8 @@ configuration settings. The mode settin - the 4 GSBI IOs. - - Required properties: --- compatible: must contain "qcom,gsbi-v1.0.0" for APQ8064/IPQ8064 -+- compatible: Should contain "qcom,gsbi-v1.0.0" -+- cell-index: Should contain the GSBI index - - reg: Address range for GSBI registers - - clocks: required clock - - clock-names: must contain "iface" entry -@@ -16,6 +17,8 @@ Required properties: - Optional properties: - - qcom,crci : indicates CRCI MUX value for QUP CRCI ports. Please reference - dt-bindings/soc/qcom,gsbi.h for valid CRCI mux values. -+- syscon-tcsr: indicates phandle of TCSR syscon node. Required if child uses -+ dma. - - Required properties if child node exists: - - #address-cells: Must be 1 -@@ -39,6 +42,7 @@ Example for APQ8064: - - gsbi4@16300000 { - compatible = "qcom,gsbi-v1.0.0"; -+ cell-index = <4>; - reg = <0x16300000 0x100>; - clocks = <&gcc GSBI4_H_CLK>; - clock-names = "iface"; -@@ -48,6 +52,8 @@ Example for APQ8064: - qcom,mode = ; - qcom,crci = ; - -+ syscon-tcsr = <&tcsr>; -+ - /* child nodes go under here */ - - i2c_qup4: i2c@16380000 { -@@ -76,3 +82,9 @@ Example for APQ8064: - }; - }; - -+ tcsr: syscon@1a400000 { -+ compatible = "qcom,apq8064-tcsr", "syscon"; -+ reg = <0x1a400000 0x100>; -+ }; -+ -+ ---- a/drivers/soc/qcom/Kconfig -+++ b/drivers/soc/qcom/Kconfig -@@ -4,6 +4,7 @@ - config QCOM_GSBI - tristate "QCOM General Serial Bus Interface" - depends on ARCH_QCOM -+ select MFD_SYSCON - help - Say y here to enable GSBI support. The GSBI provides control - functions for connecting the underlying serial UART, SPI, and I2C ---- a/drivers/soc/qcom/qcom_gsbi.c -+++ b/drivers/soc/qcom/qcom_gsbi.c -@@ -18,22 +18,129 @@ - #include - #include - #include -+#include -+#include -+#include - - #define GSBI_CTRL_REG 0x0000 - #define GSBI_PROTOCOL_SHIFT 4 -+#define MAX_GSBI 12 -+ -+#define TCSR_ADM_CRCI_BASE 0x70 -+ -+struct crci_config { -+ u32 num_rows; -+ const u32 (*array)[MAX_GSBI]; -+}; -+ -+static const u32 crci_ipq8064[][MAX_GSBI] = { -+ { -+ 0x000003, 0x00000c, 0x000030, 0x0000c0, -+ 0x000300, 0x000c00, 0x003000, 0x00c000, -+ 0x030000, 0x0c0000, 0x300000, 0xc00000 -+ }, -+ { -+ 0x000003, 0x00000c, 0x000030, 0x0000c0, -+ 0x000300, 0x000c00, 0x003000, 0x00c000, -+ 0x030000, 0x0c0000, 0x300000, 0xc00000 -+ }, -+}; -+ -+static const struct crci_config config_ipq8064 = { -+ .num_rows = ARRAY_SIZE(crci_ipq8064), -+ .array = crci_ipq8064, -+}; -+ -+static const unsigned int crci_apq8064[][MAX_GSBI] = { -+ { -+ 0x001800, 0x006000, 0x000030, 0x0000c0, -+ 0x000300, 0x000400, 0x000000, 0x000000, -+ 0x000000, 0x000000, 0x000000, 0x000000 -+ }, -+ { -+ 0x000000, 0x000000, 0x000000, 0x000000, -+ 0x000000, 0x000020, 0x0000c0, 0x000000, -+ 0x000000, 0x000000, 0x000000, 0x000000 -+ }, -+}; -+ -+static const struct crci_config config_apq8064 = { -+ .num_rows = ARRAY_SIZE(crci_apq8064), -+ .array = crci_apq8064, -+}; -+ -+static const unsigned int crci_msm8960[][MAX_GSBI] = { -+ { -+ 0x000003, 0x00000c, 0x000030, 0x0000c0, -+ 0x000300, 0x000400, 0x000000, 0x000000, -+ 0x000000, 0x000000, 0x000000, 0x000000 -+ }, -+ { -+ 0x000000, 0x000000, 0x000000, 0x000000, -+ 0x000000, 0x000020, 0x0000c0, 0x000300, -+ 0x001800, 0x006000, 0x000000, 0x000000 -+ }, -+}; -+ -+static const struct crci_config config_msm8960 = { -+ .num_rows = ARRAY_SIZE(crci_msm8960), -+ .array = crci_msm8960, -+}; -+ -+static const unsigned int crci_msm8660[][MAX_GSBI] = { -+ { /* ADM 0 - B */ -+ 0x000003, 0x00000c, 0x000030, 0x0000c0, -+ 0x000300, 0x000c00, 0x003000, 0x00c000, -+ 0x030000, 0x0c0000, 0x300000, 0xc00000 -+ }, -+ { /* ADM 0 - B */ -+ 0x000003, 0x00000c, 0x000030, 0x0000c0, -+ 0x000300, 0x000c00, 0x003000, 0x00c000, -+ 0x030000, 0x0c0000, 0x300000, 0xc00000 -+ }, -+ { /* ADM 1 - A */ -+ 0x000003, 0x00000c, 0x000030, 0x0000c0, -+ 0x000300, 0x000c00, 0x003000, 0x00c000, -+ 0x030000, 0x0c0000, 0x300000, 0xc00000 -+ }, -+ { /* ADM 1 - B */ -+ 0x000003, 0x00000c, 0x000030, 0x0000c0, -+ 0x000300, 0x000c00, 0x003000, 0x00c000, -+ 0x030000, 0x0c0000, 0x300000, 0xc00000 -+ }, -+}; -+ -+static const struct crci_config config_msm8660 = { -+ .num_rows = ARRAY_SIZE(crci_msm8660), -+ .array = crci_msm8660, -+}; - - struct gsbi_info { - struct clk *hclk; - u32 mode; - u32 crci; -+ struct regmap *tcsr; -+}; -+ -+static const struct of_device_id tcsr_dt_match[] = { -+ { .compatible = "qcom,tcsr-ipq8064", .data = &config_ipq8064}, -+ { .compatible = "qcom,tcsr-apq8064", .data = &config_apq8064}, -+ { .compatible = "qcom,tcsr-msm8960", .data = &config_msm8960}, -+ { .compatible = "qcom,tcsr-msm8660", .data = &config_msm8660}, -+ { }, - }; - - static int gsbi_probe(struct platform_device *pdev) - { - struct device_node *node = pdev->dev.of_node; -+ struct device_node *tcsr_node; -+ const struct of_device_id *match; - struct resource *res; - void __iomem *base; - struct gsbi_info *gsbi; -+ int i; -+ u32 mask, gsbi_num; -+ const struct crci_config *config = NULL; - - gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL); - -@@ -45,6 +152,32 @@ static int gsbi_probe(struct platform_de - if (IS_ERR(base)) - return PTR_ERR(base); - -+ /* get the tcsr node and setup the config and regmap */ -+ gsbi->tcsr = syscon_regmap_lookup_by_phandle(node, "syscon-tcsr"); -+ -+ if (!IS_ERR(gsbi->tcsr)) { -+ tcsr_node = of_parse_phandle(node, "syscon-tcsr", 0); -+ if (tcsr_node) { -+ match = of_match_node(tcsr_dt_match, tcsr_node); -+ if (match) -+ config = match->data; -+ else -+ dev_warn(&pdev->dev, "no matching TCSR\n"); -+ -+ of_node_put(tcsr_node); -+ } -+ } -+ -+ if (of_property_read_u32(node, "cell-index", &gsbi_num)) { -+ dev_err(&pdev->dev, "missing cell-index\n"); -+ return -EINVAL; -+ } -+ -+ if (gsbi_num < 1 || gsbi_num > MAX_GSBI) { -+ dev_err(&pdev->dev, "invalid cell-index\n"); -+ return -EINVAL; -+ } -+ - if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) { - dev_err(&pdev->dev, "missing mode configuration\n"); - return -EINVAL; -@@ -64,6 +197,25 @@ static int gsbi_probe(struct platform_de - writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci, - base + GSBI_CTRL_REG); - -+ /* -+ * modify tcsr to reflect mode and ADM CRCI mux -+ * Each gsbi contains a pair of bits, one for RX and one for TX -+ * SPI mode requires both bits cleared, otherwise they are set -+ */ -+ if (config) { -+ for (i = 0; i < config->num_rows; i++) { -+ mask = config->array[i][gsbi_num - 1]; -+ -+ if (gsbi->mode == GSBI_PROT_SPI) -+ regmap_update_bits(gsbi->tcsr, -+ TCSR_ADM_CRCI_BASE + 4 * i, mask, 0); -+ else -+ regmap_update_bits(gsbi->tcsr, -+ TCSR_ADM_CRCI_BASE + 4 * i, mask, mask); -+ -+ } -+ } -+ - /* make sure the gsbi control write is not reordered */ - wmb(); - diff --git a/target/linux/ipq806x/patches-3.18/103-ARM-DT-ipq8064-Add-TCSR-support.patch b/target/linux/ipq806x/patches-3.18/103-ARM-DT-ipq8064-Add-TCSR-support.patch deleted file mode 100644 index 322e1d923735..000000000000 --- a/target/linux/ipq806x/patches-3.18/103-ARM-DT-ipq8064-Add-TCSR-support.patch +++ /dev/null @@ -1,65 +0,0 @@ ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -132,6 +132,7 @@ - - gsbi2: gsbi@12480000 { - compatible = "qcom,gsbi-v1.0.0"; -+ cell-index = <2>; - reg = <0x12480000 0x100>; - clocks = <&gcc GSBI2_H_CLK>; - clock-names = "iface"; -@@ -140,6 +141,8 @@ - ranges; - status = "disabled"; - -+ syscon-tcsr = <&tcsr>; -+ - uart2: serial@12490000 { - compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; - reg = <0x12490000 0x1000>, -@@ -167,6 +170,7 @@ - - gsbi4: gsbi@16300000 { - compatible = "qcom,gsbi-v1.0.0"; -+ cell-index = <4>; - reg = <0x16300000 0x100>; - clocks = <&gcc GSBI4_H_CLK>; - clock-names = "iface"; -@@ -175,6 +179,8 @@ - ranges; - status = "disabled"; - -+ syscon-tcsr = <&tcsr>; -+ - uart4: serial@16340000 { - compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; - reg = <0x16340000 0x1000>, -@@ -201,6 +207,7 @@ - - gsbi5: gsbi@1a200000 { - compatible = "qcom,gsbi-v1.0.0"; -+ cell-index = <5>; - reg = <0x1a200000 0x100>; - clocks = <&gcc GSBI5_H_CLK>; - clock-names = "iface"; -@@ -209,6 +216,8 @@ - ranges; - status = "disabled"; - -+ syscon-tcsr = <&tcsr>; -+ - uart5: serial@1a240000 { - compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; - reg = <0x1a240000 0x1000>, -@@ -279,6 +288,11 @@ - status = "disabled"; - }; - -+ tcsr: syscon@1a400000 { -+ compatible = "qcom,tcsr-ipq8064", "syscon"; -+ reg = <0x1a400000 0x100>; -+ }; -+ - qcom,ssbi@500000 { - compatible = "qcom,ssbi"; - reg = <0x00500000 0x1000>; diff --git a/target/linux/ipq806x/patches-3.18/110-DT-PCI-qcom-Document-PCIe-devicetree-bindings.patch b/target/linux/ipq806x/patches-3.18/110-DT-PCI-qcom-Document-PCIe-devicetree-bindings.patch deleted file mode 100644 index 41f91fae7c47..000000000000 --- a/target/linux/ipq806x/patches-3.18/110-DT-PCI-qcom-Document-PCIe-devicetree-bindings.patch +++ /dev/null @@ -1,263 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v2,3/5] DT: PCI: qcom: Document PCIe devicetree bindings -From: Stanimir Varbanov -X-Patchwork-Id: 6326181 -Message-Id: <1430743338-10441-4-git-send-email-svarbanov@mm-sol.com> -To: Rob Herring , Kumar Gala , - Mark Rutland , - Grant Likely , - Bjorn Helgaas , - Kishon Vijay Abraham I , - Russell King , Arnd Bergmann -Cc: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, - linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, - linux-pci@vger.kernel.org, Mathieu Olivari , - Srinivas Kandagatla , - Stanimir Varbanov -Date: Mon, 4 May 2015 15:42:16 +0300 - -Document Qualcomm PCIe driver devicetree bindings. - -Signed-off-by: Stanimir Varbanov - ---- -.../devicetree/bindings/pci/qcom,pcie.txt | 231 ++++++++++++++++++++ - 1 files changed, 231 insertions(+), 0 deletions(-) - create mode 100644 Documentation/devicetree/bindings/pci/qcom,pcie.txt - ---- /dev/null -+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt -@@ -0,0 +1,231 @@ -+* Qualcomm PCI express root complex -+ -+- compatible: -+ Usage: required -+ Value type: -+ Definition: Value shall include -+ - "qcom,pcie-v0" for apq/ipq8064 -+ - "qcom,pcie-v1" for apq8084 -+ -+- reg: -+ Usage: required -+ Value type: -+ Definition: Register ranges as listed in the reg-names property -+ -+- reg-names: -+ Usage: required -+ Value type: -+ Definition: Must include the following entries -+ - "parf" Qualcomm specific registers -+ - "dbi" Designware PCIe registers -+ - "elbi" External local bus interface registers -+ - "config" PCIe configuration space -+ -+- device_type: -+ Usage: required -+ Value type: -+ Definition: Should be "pci". As specified in designware-pcie.txt -+ -+- #address-cells: -+ Usage: required -+ Value type: -+ Definition: Should be set to 3. As specified in designware-pcie.txt -+ -+- #size-cells: -+ Usage: required -+ Value type: -+ Definition: Should be set 2. As specified in designware-pcie.txt -+ -+- ranges: -+ Usage: required -+ Value type: -+ Definition: As specified in designware-pcie.txt -+ -+- interrupts: -+ Usage: required -+ Value type: -+ Definition: MSI interrupt -+ -+- interrupt-names: -+ Usage: required -+ Value type: -+ Definition: Should contain "msi" -+ -+- #interrupt-cells: -+ Usage: required -+ Value type: -+ Definition: Should be 1. As specified in designware-pcie.txt -+ -+- interrupt-map-mask: -+ Usage: required -+ Value type: -+ Definition: As specified in designware-pcie.txt -+ -+- interrupt-map: -+ Usage: required -+ Value type: -+ Definition: As specified in designware-pcie.txt -+ -+- clocks: -+ Usage: required -+ Value type: -+ Definition: List of phandle and clock specifier pairs as listed -+ in clock-names property -+ -+- clock-names: -+ Usage: required -+ Value type: -+ Definition: Should contain the following entries -+ * should be populated for v0 and v1 -+ - "iface" Configuration AHB clock -+ -+ * should be populated for v0 -+ - "core" Clocks the pcie hw block -+ - "phy" Clocks the pcie PHY block -+ -+ * should be populated for v1 -+ - "aux" Auxiliary (AUX) clock -+ - "bus_master" Master AXI clock -+ - "bus_slave" Slave AXI clock -+ -+- resets: -+ Usage: required -+ Value type: -+ Definition: List of phandle and reset specifier pairs as listed -+ in reset-names property -+ -+- reset-names: -+ Usage: required -+ Value type: -+ Definition: Should contain the following entries -+ * should be populated for v0 -+ - "axi" AXI reset -+ - "ahb" AHB reset -+ - "por" POR reset -+ - "pci" PCI reset -+ - "phy" PHY reset -+ -+ * should be populated for v1 -+ - "core" Core reset -+ -+- power-domains: -+ Usage: required (for v1 only) -+ Value type: -+ Definition: A phandle and power domain specifier pair to the -+ power domain which is responsible for collapsing -+ and restoring power to the peripheral -+ -+- -supply: -+ Usage: required -+ Value type: -+ Definition: List of phandles to the power supply regulator(s) -+ * should be populated for v0 and v1 -+ - "vdda" core analog power supply -+ -+ * should be populated for v0 -+ - "vdda_phy" analog power supply for PHY -+ - "vdda_refclk" analog power supply for IC which generate -+ reference clock -+ -+- phys: -+ Usage: required (for v1 only) -+ Value type: -+ Definition: List of phandle(s) as listed in phy-names property -+ -+- phy-names: -+ Usage: required (for v1 only) -+ Value type: -+ Definition: Should contain "pciephy" -+ -+- -gpio: -+ Usage: optional -+ Value type: -+ Definition: List of phandle and gpio specifier pairs. Should contain -+ - "perst" PCIe endpoint reset signal line -+ - "pewake" PCIe endpoint wake signal line -+ -+- pinctrl-0: -+ Usage: required -+ Value type: -+ Definition: List of phandles pointing at a pin(s) configuration -+ -+- pinctrl-names -+ Usage: required -+ Value type: -+ Definition: List of names of pinctrl-0 state -+ -+* Example for v0 -+ pcie0: pci@1b500000 { -+ compatible = "qcom,pcie-v0"; -+ reg = <0x1b500000 0x1000 -+ 0x1b502000 0x80 -+ 0x1b600000 0x100 -+ 0x0ff00000 0x100000>; -+ reg-names = "dbi", "elbi", "parf", "config"; -+ device_type = "pci"; -+ linux,pci-domain = <0>; -+ bus-range = <0x00 0xff>; -+ num-lanes = <1>; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ ranges = <0x81000000 0 0 0x0fe00000 0 0x00100000 /* I/O */ -+ 0x82000000 0 0x00000000 0x08000000 0 0x07e00000>; /* memory */ -+ interrupts = ; -+ interrupt-names = "msi"; -+ #interrupt-cells = <1>; -+ interrupt-map-mask = <0 0 0 0x7>; -+ interrupt-map = <0 0 0 1 &intc 0 36 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ -+ <0 0 0 2 &intc 0 37 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ -+ <0 0 0 3 &intc 0 38 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ -+ <0 0 0 4 &intc 0 39 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ -+ clocks = <&gcc PCIE_A_CLK>, -+ <&gcc PCIE_H_CLK>, -+ <&gcc PCIE_PHY_CLK>; -+ clock-names = "core", "iface", "phy"; -+ resets = <&gcc PCIE_ACLK_RESET>, -+ <&gcc PCIE_HCLK_RESET>, -+ <&gcc PCIE_POR_RESET>, -+ <&gcc PCIE_PCI_RESET>, -+ <&gcc PCIE_PHY_RESET>; -+ reset-names = "axi", "ahb", "por", "pci", "phy"; -+ }; -+ -+* Example for v1 -+ pcie0@fc520000 { -+ compatible = "qcom,pcie-v1"; -+ reg = <0xfc520000 0x2000>, -+ <0xff000000 0x1000>, -+ <0xff001000 0x1000>, -+ <0xff002000 0x2000>; -+ reg-names = "parf", "dbi", "elbi", "config"; -+ device_type = "pci"; -+ linux,pci-domain = <0>; -+ bus-range = <0x00 0xff>; -+ num-lanes = <1>; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ ranges = <0x81000000 0 0 0xff200000 0 0x00100000 /* I/O */ -+ 0x82000000 0 0x00300000 0xff300000 0 0x00d00000>; /* memory */ -+ interrupts = ; -+ interrupt-names = "msi"; -+ #interrupt-cells = <1>; -+ interrupt-map-mask = <0 0 0 0x7>; -+ interrupt-map = <0 0 0 1 &intc 0 244 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ -+ <0 0 0 2 &intc 0 245 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ -+ <0 0 0 3 &intc 0 247 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ -+ <0 0 0 4 &intc 0 248 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ -+ clocks = <&gcc GCC_PCIE_0_CFG_AHB_CLK>, -+ <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, -+ <&gcc GCC_PCIE_0_SLV_AXI_CLK>, -+ <&gcc GCC_PCIE_0_AUX_CLK>; -+ clock-names = "iface", "master_bus", "slave_bus", "aux"; -+ resets = <&gcc GCC_PCIE_0_BCR>; -+ reset-names = "core"; -+ power-domains = <&gcc PCIE0_GDSC>; -+ vdda-supply = <&pma8084_l3>; -+ phys = <&pciephy0>; -+ phy-names = "pciephy"; -+ perst-gpio = <&tlmm 70 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&pcie0_pins_default>; -+ pinctrl-names = "default"; -+ }; diff --git a/target/linux/ipq806x/patches-3.18/111-PCI-qcom-Add-Qualcomm-PCIe-controller-driver.patch b/target/linux/ipq806x/patches-3.18/111-PCI-qcom-Add-Qualcomm-PCIe-controller-driver.patch deleted file mode 100644 index a0c9c7c36ed3..000000000000 --- a/target/linux/ipq806x/patches-3.18/111-PCI-qcom-Add-Qualcomm-PCIe-controller-driver.patch +++ /dev/null @@ -1,753 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v2,4/5] PCI: qcom: Add Qualcomm PCIe controller driver -From: Stanimir Varbanov -X-Patchwork-Id: 6326161 -Message-Id: <1430743338-10441-5-git-send-email-svarbanov@mm-sol.com> -To: Rob Herring , Kumar Gala , - Mark Rutland , - Grant Likely , - Bjorn Helgaas , - Kishon Vijay Abraham I , - Russell King , Arnd Bergmann -Cc: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, - linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, - linux-pci@vger.kernel.org, Mathieu Olivari , - Srinivas Kandagatla , - Stanimir Varbanov -Date: Mon, 4 May 2015 15:42:17 +0300 - -The PCIe driver reuse the Designware common code for host -and MSI initialization, and also program the Qualcomm -application specific registers. - -Signed-off-by: Stanimir Varbanov - ---- -MAINTAINERS | 7 + - drivers/pci/host/Kconfig | 9 + - drivers/pci/host/Makefile | 1 + - drivers/pci/host/pcie-qcom.c | 677 ++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 694 insertions(+), 0 deletions(-) - create mode 100644 drivers/pci/host/pcie-qcom.c - ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -7127,6 +7127,13 @@ L: linux-pci@vger.kernel.org - S: Maintained - F: drivers/pci/host/*spear* - -+PCIE DRIVER FOR QUALCOMM MSM -+M: Stanimir Varbanov -+L: linux-pci@vger.kernel.org -+L: linux-arm-msm@vger.kernel.org -+S: Maintained -+F: drivers/pci/host/*qcom* -+ - PCMCIA SUBSYSTEM - P: Linux PCMCIA Team - L: linux-pcmcia@lists.infradead.org ---- a/drivers/pci/host/Kconfig -+++ b/drivers/pci/host/Kconfig -@@ -91,4 +91,13 @@ config PCI_XGENE - There are 5 internal PCIe ports available. Each port is GEN3 capable - and have varied lanes from x1 to x8. - -+config PCIE_QCOM -+ bool "Qualcomm PCIe controller" -+ depends on ARCH_QCOM && OF || (ARM && COMPILE_TEST) -+ select PCIE_DW -+ select PCIEPORTBUS -+ help -+ Say Y here to enable PCIe controller support on Qualcomm SoCs. The -+ PCIe controller use Designware core plus Qualcomm specific hardware -+ wrappers. - endmenu ---- /dev/null -+++ b/drivers/pci/host/pcie-qcom.c -@@ -0,0 +1,677 @@ -+/* -+ * Copyright (c) 2014, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pcie-designware.h" -+ -+#define PCIE20_PARF_PHY_CTRL 0x40 -+#define PCIE20_PARF_PHY_REFCLK 0x4C -+#define PCIE20_PARF_DBI_BASE_ADDR 0x168 -+#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16c -+#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x178 -+ -+#define PCIE20_ELBI_SYS_CTRL 0x04 -+#define PCIE20_ELBI_SYS_STTS 0x08 -+#define XMLH_LINK_UP BIT(10) -+ -+#define PCIE20_CAP 0x70 -+#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10) -+ -+#define PERST_DELAY_MIN_US 1000 -+#define PERST_DELAY_MAX_US 1005 -+ -+#define LINKUP_DELAY_MIN_US 5000 -+#define LINKUP_DELAY_MAX_US 5100 -+#define LINKUP_RETRIES_COUNT 20 -+ -+#define PCIE_V0 0 /* apq8064 */ -+#define PCIE_V1 1 /* apq8084 */ -+ -+struct qcom_pcie_resources_v0 { -+ struct clk *iface_clk; -+ struct clk *core_clk; -+ struct clk *phy_clk; -+ struct reset_control *pci_reset; -+ struct reset_control *axi_reset; -+ struct reset_control *ahb_reset; -+ struct reset_control *por_reset; -+ struct reset_control *phy_reset; -+ struct regulator *vdda; -+ struct regulator *vdda_phy; -+ struct regulator *vdda_refclk; -+}; -+ -+struct qcom_pcie_resources_v1 { -+ struct clk *iface; -+ struct clk *aux; -+ struct clk *master_bus; -+ struct clk *slave_bus; -+ struct reset_control *core; -+ struct regulator *vdda; -+}; -+ -+union pcie_resources { -+ struct qcom_pcie_resources_v0 v0; -+ struct qcom_pcie_resources_v1 v1; -+}; -+ -+struct qcom_pcie { -+ struct pcie_port pp; -+ struct device *dev; -+ union pcie_resources res; -+ void __iomem *parf; -+ void __iomem *dbi; -+ void __iomem *elbi; -+ struct phy *phy; -+ struct gpio_desc *reset; -+ unsigned int version; -+}; -+ -+#define to_qcom_pcie(x) container_of(x, struct qcom_pcie, pp) -+ -+static inline void -+writel_masked(void __iomem *addr, u32 clear_mask, u32 set_mask) -+{ -+ u32 val = readl(addr); -+ -+ val &= ~clear_mask; -+ val |= set_mask; -+ writel(val, addr); -+} -+ -+static void qcom_ep_reset_assert_deassert(struct qcom_pcie *pcie, int assert) -+{ -+ int val, active_low; -+ -+ if (IS_ERR_OR_NULL(pcie->reset)) -+ return; -+ -+ active_low = gpiod_is_active_low(pcie->reset); -+ -+ if (assert) -+ val = !!active_low; -+ else -+ val = !active_low; -+ -+ gpiod_set_value(pcie->reset, val); -+ -+ usleep_range(PERST_DELAY_MIN_US, PERST_DELAY_MAX_US); -+} -+ -+static void qcom_ep_reset_assert(struct qcom_pcie *pcie) -+{ -+ qcom_ep_reset_assert_deassert(pcie, 1); -+} -+ -+static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) -+{ -+ qcom_ep_reset_assert_deassert(pcie, 0); -+} -+ -+static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg) -+{ -+ struct pcie_port *pp = arg; -+ -+ return dw_handle_msi_irq(pp); -+} -+ -+static int qcom_pcie_link_up(struct pcie_port *pp) -+{ -+ struct qcom_pcie *pcie = to_qcom_pcie(pp); -+ u32 val = readl(pcie->dbi + PCIE20_CAP_LINKCTRLSTATUS); -+ -+ return val & BIT(29) ? 1 : 0; -+} -+ -+static void qcom_pcie_disable_resources_v0(struct qcom_pcie *pcie) -+{ -+ struct qcom_pcie_resources_v0 *res = &pcie->res.v0; -+ -+ reset_control_assert(res->pci_reset); -+ reset_control_assert(res->axi_reset); -+ reset_control_assert(res->ahb_reset); -+ reset_control_assert(res->por_reset); -+ reset_control_assert(res->pci_reset); -+ clk_disable_unprepare(res->iface_clk); -+ clk_disable_unprepare(res->core_clk); -+ clk_disable_unprepare(res->phy_clk); -+ regulator_disable(res->vdda); -+ regulator_disable(res->vdda_phy); -+ regulator_disable(res->vdda_refclk); -+} -+ -+static void qcom_pcie_disable_resources_v1(struct qcom_pcie *pcie) -+{ -+ struct qcom_pcie_resources_v1 *res = &pcie->res.v1; -+ -+ reset_control_assert(res->core); -+ clk_disable_unprepare(res->slave_bus); -+ clk_disable_unprepare(res->master_bus); -+ clk_disable_unprepare(res->iface); -+ clk_disable_unprepare(res->aux); -+ regulator_disable(res->vdda); -+} -+ -+static int qcom_pcie_enable_resources_v0(struct qcom_pcie *pcie) -+{ -+ struct qcom_pcie_resources_v0 *res = &pcie->res.v0; -+ struct device *dev = pcie->dev; -+ int ret; -+ -+ ret = regulator_enable(res->vdda); -+ if (ret) { -+ dev_err(dev, "cannot enable vdda regulator\n"); -+ return ret; -+ } -+ -+ ret = regulator_enable(res->vdda_refclk); -+ if (ret) { -+ dev_err(dev, "cannot enable vdda_refclk regulator\n"); -+ goto err_refclk; -+ } -+ -+ ret = regulator_enable(res->vdda_phy); -+ if (ret) { -+ dev_err(dev, "cannot enable vdda_phy regulator\n"); -+ goto err_vdda_phy; -+ } -+ -+ ret = clk_prepare_enable(res->iface_clk); -+ if (ret) { -+ dev_err(dev, "cannot prepare/enable iface clock\n"); -+ goto err_iface; -+ } -+ -+ ret = clk_prepare_enable(res->core_clk); -+ if (ret) { -+ dev_err(dev, "cannot prepare/enable core clock\n"); -+ goto err_clk_core; -+ } -+ -+ ret = clk_prepare_enable(res->phy_clk); -+ if (ret) { -+ dev_err(dev, "cannot prepare/enable phy clock\n"); -+ goto err_clk_phy; -+ } -+ -+ ret = reset_control_deassert(res->ahb_reset); -+ if (ret) { -+ dev_err(dev, "cannot deassert ahb reset\n"); -+ goto err_reset_ahb; -+ } -+ -+ return 0; -+ -+err_reset_ahb: -+ clk_disable_unprepare(res->phy_clk); -+err_clk_phy: -+ clk_disable_unprepare(res->core_clk); -+err_clk_core: -+ clk_disable_unprepare(res->iface_clk); -+err_iface: -+ regulator_disable(res->vdda_phy); -+err_vdda_phy: -+ regulator_disable(res->vdda_refclk); -+err_refclk: -+ regulator_disable(res->vdda); -+ return ret; -+} -+ -+static int qcom_pcie_enable_resources_v1(struct qcom_pcie *pcie) -+{ -+ struct qcom_pcie_resources_v1 *res = &pcie->res.v1; -+ struct device *dev = pcie->dev; -+ int ret; -+ -+ ret = reset_control_deassert(res->core); -+ if (ret) { -+ dev_err(dev, "cannot deassert core reset\n"); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(res->aux); -+ if (ret) { -+ dev_err(dev, "cannot prepare/enable aux clock\n"); -+ goto err_res; -+ } -+ -+ ret = clk_prepare_enable(res->iface); -+ if (ret) { -+ dev_err(dev, "cannot prepare/enable iface clock\n"); -+ goto err_aux; -+ } -+ -+ ret = clk_prepare_enable(res->master_bus); -+ if (ret) { -+ dev_err(dev, "cannot prepare/enable master_bus clock\n"); -+ goto err_iface; -+ } -+ -+ ret = clk_prepare_enable(res->slave_bus); -+ if (ret) { -+ dev_err(dev, "cannot prepare/enable slave_bus clock\n"); -+ goto err_master; -+ } -+ -+ ret = regulator_enable(res->vdda); -+ if (ret) { -+ dev_err(dev, "cannot enable vdda regulator\n"); -+ goto err_slave; -+ } -+ -+ return 0; -+ -+err_slave: -+ clk_disable_unprepare(res->slave_bus); -+err_master: -+ clk_disable_unprepare(res->master_bus); -+err_iface: -+ clk_disable_unprepare(res->iface); -+err_aux: -+ clk_disable_unprepare(res->aux); -+err_res: -+ reset_control_assert(res->core); -+ -+ return ret; -+} -+ -+static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie) -+{ -+ struct qcom_pcie_resources_v0 *res = &pcie->res.v0; -+ struct device *dev = pcie->dev; -+ -+ res->vdda = devm_regulator_get(dev, "vdda"); -+ if (IS_ERR(res->vdda)) -+ return PTR_ERR(res->vdda); -+ -+ res->vdda_phy = devm_regulator_get(dev, "vdda_phy"); -+ if (IS_ERR(res->vdda_phy)) -+ return PTR_ERR(res->vdda_phy); -+ -+ res->vdda_refclk = devm_regulator_get(dev, "vdda_refclk"); -+ if (IS_ERR(res->vdda_refclk)) -+ return PTR_ERR(res->vdda_refclk); -+ -+ res->iface_clk = devm_clk_get(dev, "iface"); -+ if (IS_ERR(res->iface_clk)) -+ return PTR_ERR(res->iface_clk); -+ -+ res->core_clk = devm_clk_get(dev, "core"); -+ if (IS_ERR(res->core_clk)) -+ return PTR_ERR(res->core_clk); -+ -+ res->phy_clk = devm_clk_get(dev, "phy"); -+ if (IS_ERR(res->phy_clk)) -+ return PTR_ERR(res->phy_clk); -+ -+ res->pci_reset = devm_reset_control_get(dev, "pci"); -+ if (IS_ERR(res->pci_reset)) -+ return PTR_ERR(res->pci_reset); -+ -+ res->axi_reset = devm_reset_control_get(dev, "axi"); -+ if (IS_ERR(res->axi_reset)) -+ return PTR_ERR(res->axi_reset); -+ -+ res->ahb_reset = devm_reset_control_get(dev, "ahb"); -+ if (IS_ERR(res->ahb_reset)) -+ return PTR_ERR(res->ahb_reset); -+ -+ res->por_reset = devm_reset_control_get(dev, "por"); -+ if (IS_ERR(res->por_reset)) -+ return PTR_ERR(res->por_reset); -+ -+ res->phy_reset = devm_reset_control_get(dev, "phy"); -+ if (IS_ERR(res->phy_reset)) -+ return PTR_ERR(res->phy_reset); -+ -+ return 0; -+} -+ -+static int qcom_pcie_get_resources_v1(struct qcom_pcie *pcie) -+{ -+ struct qcom_pcie_resources_v1 *res = &pcie->res.v1; -+ struct device *dev = pcie->dev; -+ -+ res->vdda = devm_regulator_get(dev, "vdda"); -+ if (IS_ERR(res->vdda)) -+ return PTR_ERR(res->vdda); -+ -+ res->iface = devm_clk_get(dev, "iface"); -+ if (IS_ERR(res->iface)) -+ return PTR_ERR(res->iface); -+ -+ res->aux = devm_clk_get(dev, "aux"); -+ if (IS_ERR(res->aux) && PTR_ERR(res->aux) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ else if (IS_ERR(res->aux)) -+ res->aux = NULL; -+ -+ res->master_bus = devm_clk_get(dev, "master_bus"); -+ if (IS_ERR(res->master_bus)) -+ return PTR_ERR(res->master_bus); -+ -+ res->slave_bus = devm_clk_get(dev, "slave_bus"); -+ if (IS_ERR(res->slave_bus)) -+ return PTR_ERR(res->slave_bus); -+ -+ res->core = devm_reset_control_get(dev, "core"); -+ if (IS_ERR(res->core)) -+ return PTR_ERR(res->core); -+ -+ return 0; -+} -+ -+static int qcom_pcie_enable_link_training(struct pcie_port *pp) -+{ -+ struct qcom_pcie *pcie = to_qcom_pcie(pp); -+ struct device *dev = pp->dev; -+ int retries; -+ u32 val; -+ -+ /* enable link training */ -+ writel_masked(pcie->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0)); -+ -+ /* wait for up to 100ms for the link to come up */ -+ retries = LINKUP_RETRIES_COUNT; -+ do { -+ val = readl(pcie->elbi + PCIE20_ELBI_SYS_STTS); -+ if (val & XMLH_LINK_UP) -+ break; -+ usleep_range(LINKUP_DELAY_MIN_US, LINKUP_DELAY_MAX_US); -+ } while (retries--); -+ -+ if (retries < 0 || !dw_pcie_link_up(pp)) { -+ dev_err(dev, "link initialization failed\n"); -+ return -ENXIO; -+ } -+ -+ return 0; -+} -+ -+static void qcom_pcie_host_init_v1(struct pcie_port *pp) -+{ -+ struct qcom_pcie *pcie = to_qcom_pcie(pp); -+ int ret; -+ -+ qcom_ep_reset_assert(pcie); -+ -+ ret = qcom_pcie_enable_resources_v1(pcie); -+ if (ret) -+ return; -+ -+ /* change DBI base address */ -+ writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR); -+ -+ if (IS_ENABLED(CONFIG_PCI_MSI)) -+ writel_masked(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT, -+ 0, BIT(31)); -+ -+ ret = phy_init(pcie->phy); -+ if (ret) -+ goto err_res; -+ -+ ret = phy_power_on(pcie->phy); -+ if (ret) -+ goto err_phy; -+ -+ dw_pcie_setup_rc(pp); -+ -+ if (IS_ENABLED(CONFIG_PCI_MSI)) -+ dw_pcie_msi_init(pp); -+ -+ qcom_ep_reset_deassert(pcie); -+ -+ ret = qcom_pcie_enable_link_training(pp); -+ if (ret) -+ goto err; -+ -+ return; -+ -+err: -+ qcom_ep_reset_assert(pcie); -+ phy_power_off(pcie->phy); -+err_phy: -+ phy_exit(pcie->phy); -+err_res: -+ qcom_pcie_disable_resources_v1(pcie); -+} -+ -+static void qcom_pcie_host_init_v0(struct pcie_port *pp) -+{ -+ struct qcom_pcie *pcie = to_qcom_pcie(pp); -+ struct qcom_pcie_resources_v0 *res = &pcie->res.v0; -+ struct device *dev = pcie->dev; -+ int ret; -+ -+ qcom_ep_reset_assert(pcie); -+ -+ ret = qcom_pcie_enable_resources_v0(pcie); -+ if (ret) -+ return; -+ -+ writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0); -+ -+ /* enable external reference clock */ -+ writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16)); -+ -+ ret = reset_control_deassert(res->phy_reset); -+ if (ret) { -+ dev_err(dev, "cannot deassert phy reset\n"); -+ return; -+ } -+ -+ ret = reset_control_deassert(res->pci_reset); -+ if (ret) { -+ dev_err(dev, "cannot deassert pci reset\n"); -+ return; -+ } -+ -+ ret = reset_control_deassert(res->por_reset); -+ if (ret) { -+ dev_err(dev, "cannot deassert por reset\n"); -+ return; -+ } -+ -+ ret = reset_control_deassert(res->axi_reset); -+ if (ret) { -+ dev_err(dev, "cannot deassert axi reset\n"); -+ return; -+ } -+ -+ /* wait 150ms for clock acquisition */ -+ usleep_range(10000, 15000); -+ -+ dw_pcie_setup_rc(pp); -+ -+ if (IS_ENABLED(CONFIG_PCI_MSI)) -+ dw_pcie_msi_init(pp); -+ -+ qcom_ep_reset_deassert(pcie); -+ -+ ret = qcom_pcie_enable_link_training(pp); -+ if (ret) -+ goto err; -+ -+ return; -+err: -+ qcom_ep_reset_assert(pcie); -+ qcom_pcie_disable_resources_v0(pcie); -+} -+ -+static void qcom_pcie_host_init(struct pcie_port *pp) -+{ -+ struct qcom_pcie *pcie = to_qcom_pcie(pp); -+ -+ if (pcie->version == PCIE_V0) -+ return qcom_pcie_host_init_v0(pp); -+ else -+ return qcom_pcie_host_init_v1(pp); -+} -+ -+static int -+qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val) -+{ -+ /* the device class is not reported correctly from the register */ -+ if (where == PCI_CLASS_REVISION && size == 4) { -+ *val = readl(pp->dbi_base + PCI_CLASS_REVISION); -+ *val &= ~(0xffff << 16); -+ *val |= PCI_CLASS_BRIDGE_PCI << 16; -+ return PCIBIOS_SUCCESSFUL; -+ } -+ -+ return dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, -+ size, val); -+} -+ -+static struct pcie_host_ops qcom_pcie_ops = { -+ .link_up = qcom_pcie_link_up, -+ .host_init = qcom_pcie_host_init, -+ .rd_own_conf = qcom_pcie_rd_own_conf, -+}; -+ -+static const struct of_device_id qcom_pcie_match[] = { -+ { .compatible = "qcom,pcie-v0", .data = (void *)PCIE_V0 }, -+ { .compatible = "qcom,pcie-v1", .data = (void *)PCIE_V1 }, -+ { } -+}; -+ -+static int qcom_pcie_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ const struct of_device_id *match; -+ struct resource *res; -+ struct qcom_pcie *pcie; -+ struct pcie_port *pp; -+ int ret; -+ -+ match = of_match_node(qcom_pcie_match, dev->of_node); -+ if (!match) -+ return -ENXIO; -+ -+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); -+ if (!pcie) -+ return -ENOMEM; -+ -+ pcie->version = (unsigned int)match->data; -+ -+ pcie->reset = devm_gpiod_get_optional(dev, "perst"); -+ if (IS_ERR(pcie->reset) && PTR_ERR(pcie->reset) == -EPROBE_DEFER) -+ return PTR_ERR(pcie->reset); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf"); -+ pcie->parf = devm_ioremap_resource(dev, res); -+ if (IS_ERR(pcie->parf)) -+ return PTR_ERR(pcie->parf); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); -+ pcie->dbi = devm_ioremap_resource(dev, res); -+ if (IS_ERR(pcie->dbi)) -+ return PTR_ERR(pcie->dbi); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi"); -+ pcie->elbi = devm_ioremap_resource(dev, res); -+ if (IS_ERR(pcie->elbi)) -+ return PTR_ERR(pcie->elbi); -+ -+ pcie->phy = devm_phy_optional_get(dev, "pciephy"); -+ if (IS_ERR(pcie->phy)) -+ return PTR_ERR(pcie->phy); -+ -+ pcie->dev = dev; -+ -+ if (pcie->version == PCIE_V0) -+ ret = qcom_pcie_get_resources_v0(pcie); -+ else -+ ret = qcom_pcie_get_resources_v1(pcie); -+ -+ if (ret) -+ return ret; -+ -+ pp = &pcie->pp; -+ pp->dev = dev; -+ pp->dbi_base = pcie->dbi; -+ pp->root_bus_nr = -1; -+ pp->ops = &qcom_pcie_ops; -+ -+ if (IS_ENABLED(CONFIG_PCI_MSI)) { -+ pp->msi_irq = platform_get_irq_byname(pdev, "msi"); -+ if (pp->msi_irq < 0) { -+ dev_err(dev, "cannot get msi irq\n"); -+ return pp->msi_irq; -+ } -+ -+ ret = devm_request_irq(dev, pp->msi_irq, -+ qcom_pcie_msi_irq_handler, -+ IRQF_SHARED, "qcom-pcie-msi", pp); -+ if (ret) { -+ dev_err(dev, "cannot request msi irq\n"); -+ return ret; -+ } -+ } -+ -+ ret = dw_pcie_host_init(pp); -+ if (ret) { -+ dev_err(dev, "cannot initialize host\n"); -+ return ret; -+ } -+ -+ platform_set_drvdata(pdev, pcie); -+ -+ return 0; -+} -+ -+static int qcom_pcie_remove(struct platform_device *pdev) -+{ -+ struct qcom_pcie *pcie = platform_get_drvdata(pdev); -+ -+ qcom_ep_reset_assert(pcie); -+ phy_power_off(pcie->phy); -+ phy_exit(pcie->phy); -+ if (pcie->version == PCIE_V0) -+ qcom_pcie_disable_resources_v0(pcie); -+ else -+ qcom_pcie_disable_resources_v1(pcie); -+ -+ return 0; -+} -+ -+static struct platform_driver qcom_pcie_driver = { -+ .probe = qcom_pcie_probe, -+ .remove = qcom_pcie_remove, -+ .driver = { -+ .name = "qcom-pcie", -+ .of_match_table = qcom_pcie_match, -+ }, -+}; -+ -+module_platform_driver(qcom_pcie_driver); -+ -+MODULE_AUTHOR("Stanimir Varbanov "); -+MODULE_DESCRIPTION("Qualcomm PCIe root complex driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:qcom-pcie"); ---- a/drivers/pci/host/Makefile -+++ b/drivers/pci/host/Makefile -@@ -11,3 +11,4 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spe - obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o - obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o - obj-$(CONFIG_PCI_XGENE) += pci-xgene.o -+obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o diff --git a/target/linux/ipq806x/patches-3.18/112-ARM-dts-qcom-add-pcie-nodes-to-ipq806x-platforms.patch b/target/linux/ipq806x/patches-3.18/112-ARM-dts-qcom-add-pcie-nodes-to-ipq806x-platforms.patch deleted file mode 100644 index a57de6c4751e..000000000000 --- a/target/linux/ipq806x/patches-3.18/112-ARM-dts-qcom-add-pcie-nodes-to-ipq806x-platforms.patch +++ /dev/null @@ -1,244 +0,0 @@ -From 5b40516b2f5fb9b2a7d6d3e2e924f12ec9d183a8 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Tue, 21 Apr 2015 19:01:42 -0700 -Subject: [PATCH 8/9] ARM: dts: qcom: add pcie nodes to ipq806x platforms - -qcom-pcie driver now supports version 0 of the controller. This change -adds the corresponding entries to the IPQ806x dtsi file and -corresponding platform (AP148). - -Signed-off-by: Mathieu Olivari ---- - arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 30 ++++++++ - arch/arm/boot/dts/qcom-ipq8064.dtsi | 124 +++++++++++++++++++++++++++++++ - 2 files changed, 154 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -@@ -115,5 +115,15 @@ - usb30@1 { - status = "ok"; - }; -+ -+ pcie0: pci@1b500000 { -+ status = "ok"; -+ phy-tx0-term-offset = <7>; -+ }; -+ -+ pcie1: pci@1b700000 { -+ status = "ok"; -+ phy-tx0-term-offset = <7>; -+ }; - }; - }; ---- a/arch/arm/boot/dts/qcom-ipq8064-db149.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-db149.dts -@@ -128,5 +128,17 @@ - usb30@1 { - status = "ok"; - }; -+ -+ pcie0: pci@1b500000 { -+ status = "ok"; -+ }; -+ -+ pcie1: pci@1b700000 { -+ status = "ok"; -+ }; -+ -+ pcie2: pci@1b900000 { -+ status = "ok"; -+ }; - }; - }; ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -3,6 +3,9 @@ - #include "skeleton.dtsi" - #include - #include -+#include -+#include -+#include - - / { - model = "Qualcomm IPQ8064"; -@@ -83,6 +86,33 @@ - interrupt-controller; - #interrupt-cells = <2>; - interrupts = <0 32 0x4>; -+ -+ pcie0_pins: pcie0_pinmux { -+ mux { -+ pins = "gpio3"; -+ function = "pcie1_rst"; -+ drive-strength = <12>; -+ bias-disable; -+ }; -+ }; -+ -+ pcie1_pins: pcie1_pinmux { -+ mux { -+ pins = "gpio48"; -+ function = "pcie2_rst"; -+ drive-strength = <12>; -+ bias-disable; -+ }; -+ }; -+ -+ pcie2_pins: pcie2_pinmux { -+ mux { -+ pins = "gpio63"; -+ function = "pcie3_rst"; -+ drive-strength = <12>; -+ bias-disable; -+ }; -+ }; - }; - - intc: interrupt-controller@2000000 { -@@ -311,6 +341,144 @@ - reg = <0x01200600 0x100>; - }; - -+ pcie0: pci@1b500000 { -+ compatible = "qcom,pcie-v0"; -+ reg = <0x1b500000 0x1000 -+ 0x1b502000 0x80 -+ 0x1b600000 0x100 -+ 0x0ff00000 0x100000>; -+ reg-names = "dbi", "elbi", "parf", "config"; -+ device_type = "pci"; -+ linux,pci-domain = <0>; -+ bus-range = <0x00 0xff>; -+ num-lanes = <1>; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00100000 /* downstream I/O */ -+ 0x82000000 0 0x08000000 0x08000000 0 0x07e00000>; /* non-prefetchable memory */ -+ -+ interrupts = ; -+ interrupt-names = "msi"; -+ #interrupt-cells = <1>; -+ interrupt-map-mask = <0 0 0 0x7>; -+ interrupt-map = <0 0 0 1 &intc 0 36 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ -+ <0 0 0 2 &intc 0 37 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ -+ <0 0 0 3 &intc 0 38 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ -+ <0 0 0 4 &intc 0 39 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ -+ -+ clocks = <&gcc PCIE_A_CLK>, -+ <&gcc PCIE_H_CLK>, -+ <&gcc PCIE_PHY_CLK>; -+ clock-names = "core", "iface", "phy"; -+ -+ resets = <&gcc PCIE_ACLK_RESET>, -+ <&gcc PCIE_HCLK_RESET>, -+ <&gcc PCIE_POR_RESET>, -+ <&gcc PCIE_PCI_RESET>, -+ <&gcc PCIE_PHY_RESET>; -+ reset-names = "axi", "ahb", "por", "pci", "phy"; -+ -+ pinctrl-0 = <&pcie0_pins>; -+ pinctrl-names = "default"; -+ -+ perst-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>; -+ -+ status = "disabled"; -+ }; -+ -+ pcie1: pci@1b700000 { -+ compatible = "qcom,pcie-v0"; -+ reg = <0x1b700000 0x1000 -+ 0x1b702000 0x80 -+ 0x1b800000 0x100 -+ 0x31f00000 0x100000>; -+ reg-names = "dbi", "elbi", "parf", "config"; -+ device_type = "pci"; -+ linux,pci-domain = <1>; -+ bus-range = <0x00 0xff>; -+ num-lanes = <1>; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00100000 /* downstream I/O */ -+ 0x82000000 0 0x2e000000 0x2e000000 0 0x03e00000>; /* non-prefetchable memory */ -+ -+ interrupts = ; -+ interrupt-names = "msi"; -+ #interrupt-cells = <1>; -+ interrupt-map-mask = <0 0 0 0x7>; -+ interrupt-map = <0 0 0 1 &intc 0 58 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ -+ <0 0 0 2 &intc 0 59 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ -+ <0 0 0 3 &intc 0 60 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ -+ <0 0 0 4 &intc 0 61 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ -+ -+ clocks = <&gcc PCIE_1_A_CLK>, -+ <&gcc PCIE_1_H_CLK>, -+ <&gcc PCIE_1_PHY_CLK>; -+ clock-names = "core", "iface", "phy"; -+ -+ resets = <&gcc PCIE_1_ACLK_RESET>, -+ <&gcc PCIE_1_HCLK_RESET>, -+ <&gcc PCIE_1_POR_RESET>, -+ <&gcc PCIE_1_PCI_RESET>, -+ <&gcc PCIE_1_PHY_RESET>; -+ reset-names = "axi", "ahb", "por", "pci", "phy"; -+ -+ pinctrl-0 = <&pcie1_pins>; -+ pinctrl-names = "default"; -+ -+ perst-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>; -+ -+ status = "disabled"; -+ }; -+ -+ pcie2: pci@1b900000 { -+ compatible = "qcom,pcie-v0"; -+ reg = <0x1b900000 0x1000 -+ 0x1b902000 0x80 -+ 0x1ba00000 0x100 -+ 0x35f00000 0x100000>; -+ reg-names = "dbi", "elbi", "parf", "config"; -+ device_type = "pci"; -+ linux,pci-domain = <2>; -+ bus-range = <0x00 0xff>; -+ num-lanes = <1>; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00100000 /* downstream I/O */ -+ 0x82000000 0 0x32000000 0x32000000 0 0x03e00000>; /* non-prefetchable memory */ -+ -+ interrupts = ; -+ interrupt-names = "msi"; -+ #interrupt-cells = <1>; -+ interrupt-map-mask = <0 0 0 0x7>; -+ interrupt-map = <0 0 0 1 &intc 0 72 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ -+ <0 0 0 2 &intc 0 73 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ -+ <0 0 0 3 &intc 0 74 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ -+ <0 0 0 4 &intc 0 75 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ -+ -+ clocks = <&gcc PCIE_2_A_CLK>, -+ <&gcc PCIE_2_H_CLK>, -+ <&gcc PCIE_2_PHY_CLK>; -+ clock-names = "core", "iface", "phy"; -+ -+ resets = <&gcc PCIE_2_ACLK_RESET>, -+ <&gcc PCIE_2_HCLK_RESET>, -+ <&gcc PCIE_2_POR_RESET>, -+ <&gcc PCIE_2_PCI_RESET>, -+ <&gcc PCIE_2_PHY_RESET>; -+ reset-names = "axi", "ahb", "por", "pci", "phy"; -+ -+ pinctrl-0 = <&pcie2_pins>; -+ pinctrl-names = "default"; -+ -+ perst-gpio = <&qcom_pinmux 63 GPIO_ACTIVE_LOW>; -+ -+ status = "disabled"; -+ }; -+ - hs_phy_1: phy@100f8800 { - compatible = "qcom,dwc3-hs-usb-phy"; - reg = <0x100f8800 0x30>; diff --git a/target/linux/ipq806x/patches-3.18/113-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch b/target/linux/ipq806x/patches-3.18/113-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch deleted file mode 100644 index 4f0e45f656d1..000000000000 --- a/target/linux/ipq806x/patches-3.18/113-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch +++ /dev/null @@ -1,29 +0,0 @@ -From f004aa1dec6e2e206be025de15b115d60f2b21e3 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Tue, 21 Apr 2015 19:09:07 -0700 -Subject: [PATCH 9/9] ARM: qcom: automatically select PCI_DOMAINS if PCI is - enabled - -If multiple PCIe devices are present in the system, the kernel will -panic at boot time when trying to scan the PCI buses. This happens on -IPQ806x based platforms, which has 3 PCIe ports. - -Enabling this option allows the kernel to assign the pci-domains -according to the device-tree content. This allows multiple PCIe -controllers to coexist in the system. - -Signed-off-by: Mathieu Olivari ---- - arch/arm/mach-qcom/Kconfig | 1 + - 1 file changed, 1 insertion(+) - ---- a/arch/arm/mach-qcom/Kconfig -+++ b/arch/arm/mach-qcom/Kconfig -@@ -6,6 +6,7 @@ menuconfig ARCH_QCOM - select CLKSRC_OF - select PINCTRL - select QCOM_SCM if SMP -+ select PCI_DOMAINS if PCI - help - Support for Qualcomm's devicetree based systems. - diff --git a/target/linux/ipq806x/patches-3.18/114-pcie-add-ctlr-init.patch b/target/linux/ipq806x/patches-3.18/114-pcie-add-ctlr-init.patch deleted file mode 100644 index c00abca75377..000000000000 --- a/target/linux/ipq806x/patches-3.18/114-pcie-add-ctlr-init.patch +++ /dev/null @@ -1,311 +0,0 @@ ---- a/drivers/pci/host/pcie-qcom.c -+++ b/drivers/pci/host/pcie-qcom.c -@@ -29,8 +29,53 @@ - - #include "pcie-designware.h" - -+/* DBI registers */ -+#define PCIE20_CAP 0x70 -+#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10) -+ -+#define PCIE20_AXI_MSTR_RESP_COMP_CTRL0 0x818 -+#define PCIE20_AXI_MSTR_RESP_COMP_CTRL1 0x81c -+ -+#define PCIE20_PLR_IATU_VIEWPORT 0x900 -+#define PCIE20_PLR_IATU_REGION_OUTBOUND (0x0 << 31) -+#define PCIE20_PLR_IATU_REGION_INDEX(x) (x << 0) -+ -+#define PCIE20_PLR_IATU_CTRL1 0x904 -+#define PCIE20_PLR_IATU_TYPE_CFG0 (0x4 << 0) -+#define PCIE20_PLR_IATU_TYPE_MEM (0x0 << 0) -+ -+#define PCIE20_PLR_IATU_CTRL2 0x908 -+#define PCIE20_PLR_IATU_ENABLE BIT(31) -+ -+#define PCIE20_PLR_IATU_LBAR 0x90C -+#define PCIE20_PLR_IATU_UBAR 0x910 -+#define PCIE20_PLR_IATU_LAR 0x914 -+#define PCIE20_PLR_IATU_LTAR 0x918 -+#define PCIE20_PLR_IATU_UTAR 0x91c -+ -+#define MSM_PCIE_DEV_CFG_ADDR 0x01000000 -+ -+/* PARF registers */ -+#define PCIE20_PARF_PCS_DEEMPH 0x34 -+#define PCS_DEEMPH_TX_DEEMPH_GEN1(x) (x << 16) -+#define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x) (x << 8) -+#define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x) (x << 0) -+ -+#define PCIE20_PARF_PCS_SWING 0x38 -+#define PCS_SWING_TX_SWING_FULL(x) (x << 8) -+#define PCS_SWING_TX_SWING_LOW(x) (x << 0) -+ - #define PCIE20_PARF_PHY_CTRL 0x40 -+#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK (0x1f << 16) -+#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x) (x << 16) -+ - #define PCIE20_PARF_PHY_REFCLK 0x4C -+#define REF_SSP_EN BIT(16) -+#define REF_USE_PAD BIT(12) -+ -+#define PCIE20_PARF_CONFIG_BITS 0x50 -+#define PHY_RX0_EQ(x) (x << 24) -+ - #define PCIE20_PARF_DBI_BASE_ADDR 0x168 - #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16c - #define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x178 -@@ -39,9 +84,6 @@ - #define PCIE20_ELBI_SYS_STTS 0x08 - #define XMLH_LINK_UP BIT(10) - --#define PCIE20_CAP 0x70 --#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10) -- - #define PERST_DELAY_MIN_US 1000 - #define PERST_DELAY_MAX_US 1005 - -@@ -56,14 +98,18 @@ struct qcom_pcie_resources_v0 { - struct clk *iface_clk; - struct clk *core_clk; - struct clk *phy_clk; -+ struct clk *aux_clk; -+ struct clk *ref_clk; - struct reset_control *pci_reset; - struct reset_control *axi_reset; - struct reset_control *ahb_reset; - struct reset_control *por_reset; - struct reset_control *phy_reset; -+ struct reset_control *ext_reset; - struct regulator *vdda; - struct regulator *vdda_phy; - struct regulator *vdda_refclk; -+ uint8_t phy_tx0_term_offset; - }; - - struct qcom_pcie_resources_v1 { -@@ -106,20 +152,10 @@ writel_masked(void __iomem *addr, u32 cl - - static void qcom_ep_reset_assert_deassert(struct qcom_pcie *pcie, int assert) - { -- int val, active_low; -- - if (IS_ERR_OR_NULL(pcie->reset)) - return; - -- active_low = gpiod_is_active_low(pcie->reset); -- -- if (assert) -- val = !!active_low; -- else -- val = !active_low; -- -- gpiod_set_value(pcie->reset, val); -- -+ gpiod_set_value(pcie->reset, assert); - usleep_range(PERST_DELAY_MIN_US, PERST_DELAY_MAX_US); - } - -@@ -156,10 +192,13 @@ static void qcom_pcie_disable_resources_ - reset_control_assert(res->axi_reset); - reset_control_assert(res->ahb_reset); - reset_control_assert(res->por_reset); -- reset_control_assert(res->pci_reset); -+ reset_control_assert(res->phy_reset); -+ reset_control_assert(res->ext_reset); - clk_disable_unprepare(res->iface_clk); - clk_disable_unprepare(res->core_clk); - clk_disable_unprepare(res->phy_clk); -+ clk_disable_unprepare(res->aux_clk); -+ clk_disable_unprepare(res->ref_clk); - regulator_disable(res->vdda); - regulator_disable(res->vdda_phy); - regulator_disable(res->vdda_refclk); -@@ -201,6 +240,12 @@ static int qcom_pcie_enable_resources_v0 - goto err_vdda_phy; - } - -+ ret = reset_control_deassert(res->ext_reset); -+ if (ret) { -+ dev_err(dev, "cannot assert ext reset\n"); -+ goto err_reset_ext; -+ } -+ - ret = clk_prepare_enable(res->iface_clk); - if (ret) { - dev_err(dev, "cannot prepare/enable iface clock\n"); -@@ -219,21 +264,40 @@ static int qcom_pcie_enable_resources_v0 - goto err_clk_phy; - } - -+ ret = clk_prepare_enable(res->aux_clk); -+ if (ret) { -+ dev_err(dev, "cannot prepare/enable aux clock\n"); -+ goto err_clk_aux; -+ } -+ -+ ret = clk_prepare_enable(res->ref_clk); -+ if (ret) { -+ dev_err(dev, "cannot prepare/enable ref clock\n"); -+ goto err_clk_ref; -+ } -+ - ret = reset_control_deassert(res->ahb_reset); - if (ret) { - dev_err(dev, "cannot deassert ahb reset\n"); - goto err_reset_ahb; - } -+ udelay(1); - - return 0; - - err_reset_ahb: -+ clk_disable_unprepare(res->ref_clk); -+err_clk_ref: -+ clk_disable_unprepare(res->aux_clk); -+err_clk_aux: - clk_disable_unprepare(res->phy_clk); - err_clk_phy: - clk_disable_unprepare(res->core_clk); - err_clk_core: - clk_disable_unprepare(res->iface_clk); - err_iface: -+ reset_control_assert(res->ext_reset); -+err_reset_ext: - regulator_disable(res->vdda_phy); - err_vdda_phy: - regulator_disable(res->vdda_refclk); -@@ -329,6 +393,14 @@ static int qcom_pcie_get_resources_v0(st - if (IS_ERR(res->phy_clk)) - return PTR_ERR(res->phy_clk); - -+ res->aux_clk = devm_clk_get(dev, "aux"); -+ if (IS_ERR(res->aux_clk)) -+ return PTR_ERR(res->aux_clk); -+ -+ res->ref_clk = devm_clk_get(dev, "ref"); -+ if (IS_ERR(res->ref_clk)) -+ return PTR_ERR(res->ref_clk); -+ - res->pci_reset = devm_reset_control_get(dev, "pci"); - if (IS_ERR(res->pci_reset)) - return PTR_ERR(res->pci_reset); -@@ -349,6 +421,14 @@ static int qcom_pcie_get_resources_v0(st - if (IS_ERR(res->phy_reset)) - return PTR_ERR(res->phy_reset); - -+ res->ext_reset = devm_reset_control_get(dev, "ext"); -+ if (IS_ERR(res->ext_reset)) -+ return PTR_ERR(res->ext_reset); -+ -+ if (of_property_read_u8(dev->of_node, "phy-tx0-term-offset", -+ &res->phy_tx0_term_offset)) -+ res->phy_tx0_term_offset = 0; -+ - return 0; - } - -@@ -461,6 +541,57 @@ err_res: - qcom_pcie_disable_resources_v1(pcie); - } - -+static void qcom_pcie_prog_viewport_cfg0(struct qcom_pcie *pcie, u32 busdev) -+{ -+ struct pcie_port *pp = &pcie->pp; -+ -+ /* -+ * program and enable address translation region 0 (device config -+ * address space); region type config; -+ * axi config address range to device config address range -+ */ -+ writel(PCIE20_PLR_IATU_REGION_OUTBOUND | -+ PCIE20_PLR_IATU_REGION_INDEX(0), -+ pcie->dbi + PCIE20_PLR_IATU_VIEWPORT); -+ -+ writel(PCIE20_PLR_IATU_TYPE_CFG0, pcie->dbi + PCIE20_PLR_IATU_CTRL1); -+ writel(PCIE20_PLR_IATU_ENABLE, pcie->dbi + PCIE20_PLR_IATU_CTRL2); -+ writel(pp->cfg0_mod_base, pcie->dbi + PCIE20_PLR_IATU_LBAR); -+ writel((pp->cfg0_mod_base >> 32), pcie->dbi + PCIE20_PLR_IATU_UBAR); -+ writel((pp->cfg0_mod_base + pp->cfg0_size - 1), -+ pcie->dbi + PCIE20_PLR_IATU_LAR); -+ writel(busdev, pcie->dbi + PCIE20_PLR_IATU_LTAR); -+ writel(0, pcie->dbi + PCIE20_PLR_IATU_UTAR); -+} -+ -+static void qcom_pcie_prog_viewport_mem2_outbound(struct qcom_pcie *pcie) -+{ -+ struct pcie_port *pp = &pcie->pp; -+ -+ /* -+ * program and enable address translation region 2 (device resource -+ * address space); region type memory; -+ * axi device bar address range to device bar address range -+ */ -+ writel(PCIE20_PLR_IATU_REGION_OUTBOUND | -+ PCIE20_PLR_IATU_REGION_INDEX(2), -+ pcie->dbi + PCIE20_PLR_IATU_VIEWPORT); -+ -+ writel(PCIE20_PLR_IATU_TYPE_MEM, pcie->dbi + PCIE20_PLR_IATU_CTRL1); -+ writel(PCIE20_PLR_IATU_ENABLE, pcie->dbi + PCIE20_PLR_IATU_CTRL2); -+ writel(pp->mem_mod_base, pcie->dbi + PCIE20_PLR_IATU_LBAR); -+ writel((pp->mem_mod_base >> 32), pcie->dbi + PCIE20_PLR_IATU_UBAR); -+ writel(pp->mem_mod_base + pp->mem_size - 1, -+ pcie->dbi + PCIE20_PLR_IATU_LAR); -+ writel(pp->mem_bus_addr, pcie->dbi + PCIE20_PLR_IATU_LTAR); -+ writel(upper_32_bits(pp->mem_bus_addr), -+ pcie->dbi + PCIE20_PLR_IATU_UTAR); -+ -+ /* 256B PCIE buffer setting */ -+ writel(0x1, pcie->dbi + PCIE20_AXI_MSTR_RESP_COMP_CTRL0); -+ writel(0x1, pcie->dbi + PCIE20_AXI_MSTR_RESP_COMP_CTRL1); -+} -+ - static void qcom_pcie_host_init_v0(struct pcie_port *pp) - { - struct qcom_pcie *pcie = to_qcom_pcie(pp); -@@ -470,15 +601,34 @@ static void qcom_pcie_host_init_v0(struc - - qcom_ep_reset_assert(pcie); - -+ reset_control_assert(res->ahb_reset); -+ - ret = qcom_pcie_enable_resources_v0(pcie); - if (ret) - return; - - writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0); - -- /* enable external reference clock */ -- writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16)); -+ /* Set Tx termination offset */ -+ writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL, -+ PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK, -+ PHY_CTRL_PHY_TX0_TERM_OFFSET(res->phy_tx0_term_offset)); -+ -+ /* PARF programming */ -+ writel(PCS_DEEMPH_TX_DEEMPH_GEN1(0x18) | -+ PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(0x18) | -+ PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(0x22), -+ pcie->parf + PCIE20_PARF_PCS_DEEMPH); -+ writel(PCS_SWING_TX_SWING_FULL(0x78) | -+ PCS_SWING_TX_SWING_LOW(0x78), -+ pcie->parf + PCIE20_PARF_PCS_SWING); -+ writel(PHY_RX0_EQ(0x4), pcie->parf + PCIE20_PARF_CONFIG_BITS); -+ -+ /* Enable reference clock */ -+ writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK, -+ REF_USE_PAD, REF_SSP_EN); - -+ /* De-assert PHY, PCIe, POR and AXI resets */ - ret = reset_control_deassert(res->phy_reset); - if (ret) { - dev_err(dev, "cannot deassert phy reset\n"); -@@ -517,6 +667,9 @@ static void qcom_pcie_host_init_v0(struc - if (ret) - goto err; - -+ qcom_pcie_prog_viewport_cfg0(pcie, MSM_PCIE_DEV_CFG_ADDR); -+ qcom_pcie_prog_viewport_mem2_outbound(pcie); -+ - return; - err: - qcom_ep_reset_assert(pcie); diff --git a/target/linux/ipq806x/patches-3.18/115-add-pcie-aux-clk-dts.patch b/target/linux/ipq806x/patches-3.18/115-add-pcie-aux-clk-dts.patch deleted file mode 100644 index 9f32e8fbc217..000000000000 --- a/target/linux/ipq806x/patches-3.18/115-add-pcie-aux-clk-dts.patch +++ /dev/null @@ -1,80 +0,0 @@ ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -369,15 +369,21 @@ - - clocks = <&gcc PCIE_A_CLK>, - <&gcc PCIE_H_CLK>, -- <&gcc PCIE_PHY_CLK>; -- clock-names = "core", "iface", "phy"; -+ <&gcc PCIE_PHY_CLK>, -+ <&gcc PCIE_AUX_CLK>, -+ <&gcc PCIE_ALT_REF_CLK>; -+ clock-names = "core", "iface", "phy", "aux", "ref"; -+ -+ assigned-clocks = <&gcc PCIE_ALT_REF_CLK>; -+ assigned-clock-rates = <100000000>; - - resets = <&gcc PCIE_ACLK_RESET>, - <&gcc PCIE_HCLK_RESET>, - <&gcc PCIE_POR_RESET>, - <&gcc PCIE_PCI_RESET>, -- <&gcc PCIE_PHY_RESET>; -- reset-names = "axi", "ahb", "por", "pci", "phy"; -+ <&gcc PCIE_PHY_RESET>, -+ <&gcc PCIE_EXT_RESET>; -+ reset-names = "axi", "ahb", "por", "pci", "phy", "ext"; - - pinctrl-0 = <&pcie0_pins>; - pinctrl-names = "default"; -@@ -415,15 +421,21 @@ - - clocks = <&gcc PCIE_1_A_CLK>, - <&gcc PCIE_1_H_CLK>, -- <&gcc PCIE_1_PHY_CLK>; -- clock-names = "core", "iface", "phy"; -+ <&gcc PCIE_1_PHY_CLK>, -+ <&gcc PCIE_1_AUX_CLK>, -+ <&gcc PCIE_1_ALT_REF_CLK>; -+ clock-names = "core", "iface", "phy", "aux", "ref"; -+ -+ assigned-clocks = <&gcc PCIE_1_ALT_REF_CLK>; -+ assigned-clock-rates = <100000000>; - - resets = <&gcc PCIE_1_ACLK_RESET>, - <&gcc PCIE_1_HCLK_RESET>, - <&gcc PCIE_1_POR_RESET>, - <&gcc PCIE_1_PCI_RESET>, -- <&gcc PCIE_1_PHY_RESET>; -- reset-names = "axi", "ahb", "por", "pci", "phy"; -+ <&gcc PCIE_1_PHY_RESET>, -+ <&gcc PCIE_1_EXT_RESET>; -+ reset-names = "axi", "ahb", "por", "pci", "phy", "ext"; - - pinctrl-0 = <&pcie1_pins>; - pinctrl-names = "default"; -@@ -461,15 +473,21 @@ - - clocks = <&gcc PCIE_2_A_CLK>, - <&gcc PCIE_2_H_CLK>, -- <&gcc PCIE_2_PHY_CLK>; -- clock-names = "core", "iface", "phy"; -+ <&gcc PCIE_2_PHY_CLK>, -+ <&gcc PCIE_2_AUX_CLK>, -+ <&gcc PCIE_2_ALT_REF_CLK>; -+ clock-names = "core", "iface", "phy", "aux", "ref"; -+ -+ assigned-clocks = <&gcc PCIE_2_ALT_REF_CLK>; -+ assigned-clock-rates = <100000000>; - - resets = <&gcc PCIE_2_ACLK_RESET>, - <&gcc PCIE_2_HCLK_RESET>, - <&gcc PCIE_2_POR_RESET>, - <&gcc PCIE_2_PCI_RESET>, -- <&gcc PCIE_2_PHY_RESET>; -- reset-names = "axi", "ahb", "por", "pci", "phy"; -+ <&gcc PCIE_2_PHY_RESET>, -+ <&gcc PCIE_2_EXT_RESET>; -+ reset-names = "axi", "ahb", "por", "pci", "phy", "ext"; - - pinctrl-0 = <&pcie2_pins>; - pinctrl-names = "default"; diff --git a/target/linux/ipq806x/patches-3.18/120-mfd-qcom-rpm-Driver-for-the-Qualcomm-RPM.patch b/target/linux/ipq806x/patches-3.18/120-mfd-qcom-rpm-Driver-for-the-Qualcomm-RPM.patch deleted file mode 100644 index d8191422c4f1..000000000000 --- a/target/linux/ipq806x/patches-3.18/120-mfd-qcom-rpm-Driver-for-the-Qualcomm-RPM.patch +++ /dev/null @@ -1,654 +0,0 @@ -From 58e214382bdd1eb48c5a3519182bddcb26edabad Mon Sep 17 00:00:00 2001 -From: Bjorn Andersson -Date: Wed, 26 Nov 2014 13:51:00 -0800 -Subject: [PATCH] mfd: qcom-rpm: Driver for the Qualcomm RPM - -Driver for the Resource Power Manager (RPM) found in Qualcomm 8660, 8960 -and 8064 based devices. The driver exposes resources that child drivers -can operate on; to implementing regulator, clock and bus frequency -drivers. - -Signed-off-by: Bjorn Andersson -Signed-off-by: Lee Jones ---- - drivers/mfd/Kconfig | 14 ++ - drivers/mfd/Makefile | 1 + - drivers/mfd/qcom_rpm.c | 581 +++++++++++++++++++++++++++++++++++++++++++ - include/linux/mfd/qcom_rpm.h | 13 + - 4 files changed, 609 insertions(+) - create mode 100644 drivers/mfd/qcom_rpm.c - create mode 100644 include/linux/mfd/qcom_rpm.h - ---- a/drivers/mfd/Kconfig -+++ b/drivers/mfd/Kconfig -@@ -567,6 +567,20 @@ config MFD_PM8921_CORE - Say M here if you want to include support for PM8921 chip as a module. - This will build a module called "pm8921-core". - -+config MFD_QCOM_RPM -+ tristate "Qualcomm Resource Power Manager (RPM)" -+ depends on ARCH_QCOM && OF -+ help -+ If you say yes to this option, support will be included for the -+ Resource Power Manager system found in the Qualcomm 8660, 8960 and -+ 8064 based devices. -+ -+ This is required to access many regulators, clocks and bus -+ frequencies controlled by the RPM on these devices. -+ -+ Say M here if you want to include support for the Qualcomm RPM as a -+ module. This will build a module called "qcom_rpm". -+ - config MFD_SPMI_PMIC - tristate "Qualcomm SPMI PMICs" - depends on ARCH_QCOM || COMPILE_TEST ---- a/drivers/mfd/Makefile -+++ b/drivers/mfd/Makefile -@@ -153,6 +153,7 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x- - obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o - obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o - obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o -+obj-$(CONFIG_MFD_QCOM_RPM) += qcom_rpm.o - obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o - obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o - obj-$(CONFIG_MFD_TPS65090) += tps65090.o ---- /dev/null -+++ b/drivers/mfd/qcom_rpm.c -@@ -0,0 +1,581 @@ -+/* -+ * Copyright (c) 2014, Sony Mobile Communications AB. -+ * Copyright (c) 2013, The Linux Foundation. All rights reserved. -+ * Author: Bjorn Andersson -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+struct qcom_rpm_resource { -+ unsigned target_id; -+ unsigned status_id; -+ unsigned select_id; -+ unsigned size; -+}; -+ -+struct qcom_rpm_data { -+ u32 version; -+ const struct qcom_rpm_resource *resource_table; -+ unsigned n_resources; -+}; -+ -+struct qcom_rpm { -+ struct device *dev; -+ struct regmap *ipc_regmap; -+ unsigned ipc_offset; -+ unsigned ipc_bit; -+ -+ struct completion ack; -+ struct mutex lock; -+ -+ void __iomem *status_regs; -+ void __iomem *ctrl_regs; -+ void __iomem *req_regs; -+ -+ u32 ack_status; -+ -+ const struct qcom_rpm_data *data; -+}; -+ -+#define RPM_STATUS_REG(rpm, i) ((rpm)->status_regs + (i) * 4) -+#define RPM_CTRL_REG(rpm, i) ((rpm)->ctrl_regs + (i) * 4) -+#define RPM_REQ_REG(rpm, i) ((rpm)->req_regs + (i) * 4) -+ -+#define RPM_REQUEST_TIMEOUT (5 * HZ) -+ -+#define RPM_REQUEST_CONTEXT 3 -+#define RPM_REQ_SELECT 11 -+#define RPM_ACK_CONTEXT 15 -+#define RPM_ACK_SELECTOR 23 -+#define RPM_SELECT_SIZE 7 -+ -+#define RPM_NOTIFICATION BIT(30) -+#define RPM_REJECTED BIT(31) -+ -+#define RPM_SIGNAL BIT(2) -+ -+static const struct qcom_rpm_resource apq8064_rpm_resource_table[] = { -+ [QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 }, -+ [QCOM_RPM_PXO_CLK] = { 26, 10, 6, 1 }, -+ [QCOM_RPM_APPS_FABRIC_CLK] = { 27, 11, 8, 1 }, -+ [QCOM_RPM_SYS_FABRIC_CLK] = { 28, 12, 9, 1 }, -+ [QCOM_RPM_MM_FABRIC_CLK] = { 29, 13, 10, 1 }, -+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 30, 14, 11, 1 }, -+ [QCOM_RPM_SFPB_CLK] = { 31, 15, 12, 1 }, -+ [QCOM_RPM_CFPB_CLK] = { 32, 16, 13, 1 }, -+ [QCOM_RPM_MMFPB_CLK] = { 33, 17, 14, 1 }, -+ [QCOM_RPM_EBI1_CLK] = { 34, 18, 16, 1 }, -+ [QCOM_RPM_APPS_FABRIC_HALT] = { 35, 19, 18, 1 }, -+ [QCOM_RPM_APPS_FABRIC_MODE] = { 37, 20, 19, 1 }, -+ [QCOM_RPM_APPS_FABRIC_IOCTL] = { 40, 21, 20, 1 }, -+ [QCOM_RPM_APPS_FABRIC_ARB] = { 41, 22, 21, 12 }, -+ [QCOM_RPM_SYS_FABRIC_HALT] = { 53, 23, 22, 1 }, -+ [QCOM_RPM_SYS_FABRIC_MODE] = { 55, 24, 23, 1 }, -+ [QCOM_RPM_SYS_FABRIC_IOCTL] = { 58, 25, 24, 1 }, -+ [QCOM_RPM_SYS_FABRIC_ARB] = { 59, 26, 25, 30 }, -+ [QCOM_RPM_MM_FABRIC_HALT] = { 89, 27, 26, 1 }, -+ [QCOM_RPM_MM_FABRIC_MODE] = { 91, 28, 27, 1 }, -+ [QCOM_RPM_MM_FABRIC_IOCTL] = { 94, 29, 28, 1 }, -+ [QCOM_RPM_MM_FABRIC_ARB] = { 95, 30, 29, 21 }, -+ [QCOM_RPM_PM8921_SMPS1] = { 116, 31, 30, 2 }, -+ [QCOM_RPM_PM8921_SMPS2] = { 118, 33, 31, 2 }, -+ [QCOM_RPM_PM8921_SMPS3] = { 120, 35, 32, 2 }, -+ [QCOM_RPM_PM8921_SMPS4] = { 122, 37, 33, 2 }, -+ [QCOM_RPM_PM8921_SMPS5] = { 124, 39, 34, 2 }, -+ [QCOM_RPM_PM8921_SMPS6] = { 126, 41, 35, 2 }, -+ [QCOM_RPM_PM8921_SMPS7] = { 128, 43, 36, 2 }, -+ [QCOM_RPM_PM8921_SMPS8] = { 130, 45, 37, 2 }, -+ [QCOM_RPM_PM8921_LDO1] = { 132, 47, 38, 2 }, -+ [QCOM_RPM_PM8921_LDO2] = { 134, 49, 39, 2 }, -+ [QCOM_RPM_PM8921_LDO3] = { 136, 51, 40, 2 }, -+ [QCOM_RPM_PM8921_LDO4] = { 138, 53, 41, 2 }, -+ [QCOM_RPM_PM8921_LDO5] = { 140, 55, 42, 2 }, -+ [QCOM_RPM_PM8921_LDO6] = { 142, 57, 43, 2 }, -+ [QCOM_RPM_PM8921_LDO7] = { 144, 59, 44, 2 }, -+ [QCOM_RPM_PM8921_LDO8] = { 146, 61, 45, 2 }, -+ [QCOM_RPM_PM8921_LDO9] = { 148, 63, 46, 2 }, -+ [QCOM_RPM_PM8921_LDO10] = { 150, 65, 47, 2 }, -+ [QCOM_RPM_PM8921_LDO11] = { 152, 67, 48, 2 }, -+ [QCOM_RPM_PM8921_LDO12] = { 154, 69, 49, 2 }, -+ [QCOM_RPM_PM8921_LDO13] = { 156, 71, 50, 2 }, -+ [QCOM_RPM_PM8921_LDO14] = { 158, 73, 51, 2 }, -+ [QCOM_RPM_PM8921_LDO15] = { 160, 75, 52, 2 }, -+ [QCOM_RPM_PM8921_LDO16] = { 162, 77, 53, 2 }, -+ [QCOM_RPM_PM8921_LDO17] = { 164, 79, 54, 2 }, -+ [QCOM_RPM_PM8921_LDO18] = { 166, 81, 55, 2 }, -+ [QCOM_RPM_PM8921_LDO19] = { 168, 83, 56, 2 }, -+ [QCOM_RPM_PM8921_LDO20] = { 170, 85, 57, 2 }, -+ [QCOM_RPM_PM8921_LDO21] = { 172, 87, 58, 2 }, -+ [QCOM_RPM_PM8921_LDO22] = { 174, 89, 59, 2 }, -+ [QCOM_RPM_PM8921_LDO23] = { 176, 91, 60, 2 }, -+ [QCOM_RPM_PM8921_LDO24] = { 178, 93, 61, 2 }, -+ [QCOM_RPM_PM8921_LDO25] = { 180, 95, 62, 2 }, -+ [QCOM_RPM_PM8921_LDO26] = { 182, 97, 63, 2 }, -+ [QCOM_RPM_PM8921_LDO27] = { 184, 99, 64, 2 }, -+ [QCOM_RPM_PM8921_LDO28] = { 186, 101, 65, 2 }, -+ [QCOM_RPM_PM8921_LDO29] = { 188, 103, 66, 2 }, -+ [QCOM_RPM_PM8921_CLK1] = { 190, 105, 67, 2 }, -+ [QCOM_RPM_PM8921_CLK2] = { 192, 107, 68, 2 }, -+ [QCOM_RPM_PM8921_LVS1] = { 194, 109, 69, 1 }, -+ [QCOM_RPM_PM8921_LVS2] = { 195, 110, 70, 1 }, -+ [QCOM_RPM_PM8921_LVS3] = { 196, 111, 71, 1 }, -+ [QCOM_RPM_PM8921_LVS4] = { 197, 112, 72, 1 }, -+ [QCOM_RPM_PM8921_LVS5] = { 198, 113, 73, 1 }, -+ [QCOM_RPM_PM8921_LVS6] = { 199, 114, 74, 1 }, -+ [QCOM_RPM_PM8921_LVS7] = { 200, 115, 75, 1 }, -+ [QCOM_RPM_PM8821_SMPS1] = { 201, 116, 76, 2 }, -+ [QCOM_RPM_PM8821_SMPS2] = { 203, 118, 77, 2 }, -+ [QCOM_RPM_PM8821_LDO1] = { 205, 120, 78, 2 }, -+ [QCOM_RPM_PM8921_NCP] = { 207, 122, 80, 2 }, -+ [QCOM_RPM_CXO_BUFFERS] = { 209, 124, 81, 1 }, -+ [QCOM_RPM_USB_OTG_SWITCH] = { 210, 125, 82, 1 }, -+ [QCOM_RPM_HDMI_SWITCH] = { 211, 126, 83, 1 }, -+ [QCOM_RPM_DDR_DMM] = { 212, 127, 84, 2 }, -+ [QCOM_RPM_VDDMIN_GPIO] = { 215, 131, 89, 1 }, -+}; -+ -+static const struct qcom_rpm_data apq8064_template = { -+ .version = 3, -+ .resource_table = apq8064_rpm_resource_table, -+ .n_resources = ARRAY_SIZE(apq8064_rpm_resource_table), -+}; -+ -+static const struct qcom_rpm_resource msm8660_rpm_resource_table[] = { -+ [QCOM_RPM_CXO_CLK] = { 32, 12, 5, 1 }, -+ [QCOM_RPM_PXO_CLK] = { 33, 13, 6, 1 }, -+ [QCOM_RPM_PLL_4] = { 34, 14, 7, 1 }, -+ [QCOM_RPM_APPS_FABRIC_CLK] = { 35, 15, 8, 1 }, -+ [QCOM_RPM_SYS_FABRIC_CLK] = { 36, 16, 9, 1 }, -+ [QCOM_RPM_MM_FABRIC_CLK] = { 37, 17, 10, 1 }, -+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 38, 18, 11, 1 }, -+ [QCOM_RPM_SFPB_CLK] = { 39, 19, 12, 1 }, -+ [QCOM_RPM_CFPB_CLK] = { 40, 20, 13, 1 }, -+ [QCOM_RPM_MMFPB_CLK] = { 41, 21, 14, 1 }, -+ [QCOM_RPM_SMI_CLK] = { 42, 22, 15, 1 }, -+ [QCOM_RPM_EBI1_CLK] = { 43, 23, 16, 1 }, -+ [QCOM_RPM_APPS_L2_CACHE_CTL] = { 44, 24, 17, 1 }, -+ [QCOM_RPM_APPS_FABRIC_HALT] = { 45, 25, 18, 2 }, -+ [QCOM_RPM_APPS_FABRIC_MODE] = { 47, 26, 19, 3 }, -+ [QCOM_RPM_APPS_FABRIC_ARB] = { 51, 28, 21, 6 }, -+ [QCOM_RPM_SYS_FABRIC_HALT] = { 63, 29, 22, 2 }, -+ [QCOM_RPM_SYS_FABRIC_MODE] = { 65, 30, 23, 3 }, -+ [QCOM_RPM_SYS_FABRIC_ARB] = { 69, 32, 25, 22 }, -+ [QCOM_RPM_MM_FABRIC_HALT] = { 105, 33, 26, 2 }, -+ [QCOM_RPM_MM_FABRIC_MODE] = { 107, 34, 27, 3 }, -+ [QCOM_RPM_MM_FABRIC_ARB] = { 111, 36, 29, 23 }, -+ [QCOM_RPM_PM8901_SMPS0] = { 134, 37, 30, 2 }, -+ [QCOM_RPM_PM8901_SMPS1] = { 136, 39, 31, 2 }, -+ [QCOM_RPM_PM8901_SMPS2] = { 138, 41, 32, 2 }, -+ [QCOM_RPM_PM8901_SMPS3] = { 140, 43, 33, 2 }, -+ [QCOM_RPM_PM8901_SMPS4] = { 142, 45, 34, 2 }, -+ [QCOM_RPM_PM8901_LDO0] = { 144, 47, 35, 2 }, -+ [QCOM_RPM_PM8901_LDO1] = { 146, 49, 36, 2 }, -+ [QCOM_RPM_PM8901_LDO2] = { 148, 51, 37, 2 }, -+ [QCOM_RPM_PM8901_LDO3] = { 150, 53, 38, 2 }, -+ [QCOM_RPM_PM8901_LDO4] = { 152, 55, 39, 2 }, -+ [QCOM_RPM_PM8901_LDO5] = { 154, 57, 40, 2 }, -+ [QCOM_RPM_PM8901_LDO6] = { 156, 59, 41, 2 }, -+ [QCOM_RPM_PM8901_LVS0] = { 158, 61, 42, 1 }, -+ [QCOM_RPM_PM8901_LVS1] = { 159, 62, 43, 1 }, -+ [QCOM_RPM_PM8901_LVS2] = { 160, 63, 44, 1 }, -+ [QCOM_RPM_PM8901_LVS3] = { 161, 64, 45, 1 }, -+ [QCOM_RPM_PM8901_MVS] = { 162, 65, 46, 1 }, -+ [QCOM_RPM_PM8058_SMPS0] = { 163, 66, 47, 2 }, -+ [QCOM_RPM_PM8058_SMPS1] = { 165, 68, 48, 2 }, -+ [QCOM_RPM_PM8058_SMPS2] = { 167, 70, 49, 2 }, -+ [QCOM_RPM_PM8058_SMPS3] = { 169, 72, 50, 2 }, -+ [QCOM_RPM_PM8058_SMPS4] = { 171, 74, 51, 2 }, -+ [QCOM_RPM_PM8058_LDO0] = { 173, 76, 52, 2 }, -+ [QCOM_RPM_PM8058_LDO1] = { 175, 78, 53, 2 }, -+ [QCOM_RPM_PM8058_LDO2] = { 177, 80, 54, 2 }, -+ [QCOM_RPM_PM8058_LDO3] = { 179, 82, 55, 2 }, -+ [QCOM_RPM_PM8058_LDO4] = { 181, 84, 56, 2 }, -+ [QCOM_RPM_PM8058_LDO5] = { 183, 86, 57, 2 }, -+ [QCOM_RPM_PM8058_LDO6] = { 185, 88, 58, 2 }, -+ [QCOM_RPM_PM8058_LDO7] = { 187, 90, 59, 2 }, -+ [QCOM_RPM_PM8058_LDO8] = { 189, 92, 60, 2 }, -+ [QCOM_RPM_PM8058_LDO9] = { 191, 94, 61, 2 }, -+ [QCOM_RPM_PM8058_LDO10] = { 193, 96, 62, 2 }, -+ [QCOM_RPM_PM8058_LDO11] = { 195, 98, 63, 2 }, -+ [QCOM_RPM_PM8058_LDO12] = { 197, 100, 64, 2 }, -+ [QCOM_RPM_PM8058_LDO13] = { 199, 102, 65, 2 }, -+ [QCOM_RPM_PM8058_LDO14] = { 201, 104, 66, 2 }, -+ [QCOM_RPM_PM8058_LDO15] = { 203, 106, 67, 2 }, -+ [QCOM_RPM_PM8058_LDO16] = { 205, 108, 68, 2 }, -+ [QCOM_RPM_PM8058_LDO17] = { 207, 110, 69, 2 }, -+ [QCOM_RPM_PM8058_LDO18] = { 209, 112, 70, 2 }, -+ [QCOM_RPM_PM8058_LDO19] = { 211, 114, 71, 2 }, -+ [QCOM_RPM_PM8058_LDO20] = { 213, 116, 72, 2 }, -+ [QCOM_RPM_PM8058_LDO21] = { 215, 118, 73, 2 }, -+ [QCOM_RPM_PM8058_LDO22] = { 217, 120, 74, 2 }, -+ [QCOM_RPM_PM8058_LDO23] = { 219, 122, 75, 2 }, -+ [QCOM_RPM_PM8058_LDO24] = { 221, 124, 76, 2 }, -+ [QCOM_RPM_PM8058_LDO25] = { 223, 126, 77, 2 }, -+ [QCOM_RPM_PM8058_LVS0] = { 225, 128, 78, 1 }, -+ [QCOM_RPM_PM8058_LVS1] = { 226, 129, 79, 1 }, -+ [QCOM_RPM_PM8058_NCP] = { 227, 130, 80, 2 }, -+ [QCOM_RPM_CXO_BUFFERS] = { 229, 132, 81, 1 }, -+}; -+ -+static const struct qcom_rpm_data msm8660_template = { -+ .version = 2, -+ .resource_table = msm8660_rpm_resource_table, -+ .n_resources = ARRAY_SIZE(msm8660_rpm_resource_table), -+}; -+ -+static const struct qcom_rpm_resource msm8960_rpm_resource_table[] = { -+ [QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 }, -+ [QCOM_RPM_PXO_CLK] = { 26, 10, 6, 1 }, -+ [QCOM_RPM_APPS_FABRIC_CLK] = { 27, 11, 8, 1 }, -+ [QCOM_RPM_SYS_FABRIC_CLK] = { 28, 12, 9, 1 }, -+ [QCOM_RPM_MM_FABRIC_CLK] = { 29, 13, 10, 1 }, -+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 30, 14, 11, 1 }, -+ [QCOM_RPM_SFPB_CLK] = { 31, 15, 12, 1 }, -+ [QCOM_RPM_CFPB_CLK] = { 32, 16, 13, 1 }, -+ [QCOM_RPM_MMFPB_CLK] = { 33, 17, 14, 1 }, -+ [QCOM_RPM_EBI1_CLK] = { 34, 18, 16, 1 }, -+ [QCOM_RPM_APPS_FABRIC_HALT] = { 35, 19, 18, 1 }, -+ [QCOM_RPM_APPS_FABRIC_MODE] = { 37, 20, 19, 1 }, -+ [QCOM_RPM_APPS_FABRIC_IOCTL] = { 40, 21, 20, 1 }, -+ [QCOM_RPM_APPS_FABRIC_ARB] = { 41, 22, 21, 12 }, -+ [QCOM_RPM_SYS_FABRIC_HALT] = { 53, 23, 22, 1 }, -+ [QCOM_RPM_SYS_FABRIC_MODE] = { 55, 24, 23, 1 }, -+ [QCOM_RPM_SYS_FABRIC_IOCTL] = { 58, 25, 24, 1 }, -+ [QCOM_RPM_SYS_FABRIC_ARB] = { 59, 26, 25, 29 }, -+ [QCOM_RPM_MM_FABRIC_HALT] = { 88, 27, 26, 1 }, -+ [QCOM_RPM_MM_FABRIC_MODE] = { 90, 28, 27, 1 }, -+ [QCOM_RPM_MM_FABRIC_IOCTL] = { 93, 29, 28, 1 }, -+ [QCOM_RPM_MM_FABRIC_ARB] = { 94, 30, 29, 23 }, -+ [QCOM_RPM_PM8921_SMPS1] = { 117, 31, 30, 2 }, -+ [QCOM_RPM_PM8921_SMPS2] = { 119, 33, 31, 2 }, -+ [QCOM_RPM_PM8921_SMPS3] = { 121, 35, 32, 2 }, -+ [QCOM_RPM_PM8921_SMPS4] = { 123, 37, 33, 2 }, -+ [QCOM_RPM_PM8921_SMPS5] = { 125, 39, 34, 2 }, -+ [QCOM_RPM_PM8921_SMPS6] = { 127, 41, 35, 2 }, -+ [QCOM_RPM_PM8921_SMPS7] = { 129, 43, 36, 2 }, -+ [QCOM_RPM_PM8921_SMPS8] = { 131, 45, 37, 2 }, -+ [QCOM_RPM_PM8921_LDO1] = { 133, 47, 38, 2 }, -+ [QCOM_RPM_PM8921_LDO2] = { 135, 49, 39, 2 }, -+ [QCOM_RPM_PM8921_LDO3] = { 137, 51, 40, 2 }, -+ [QCOM_RPM_PM8921_LDO4] = { 139, 53, 41, 2 }, -+ [QCOM_RPM_PM8921_LDO5] = { 141, 55, 42, 2 }, -+ [QCOM_RPM_PM8921_LDO6] = { 143, 57, 43, 2 }, -+ [QCOM_RPM_PM8921_LDO7] = { 145, 59, 44, 2 }, -+ [QCOM_RPM_PM8921_LDO8] = { 147, 61, 45, 2 }, -+ [QCOM_RPM_PM8921_LDO9] = { 149, 63, 46, 2 }, -+ [QCOM_RPM_PM8921_LDO10] = { 151, 65, 47, 2 }, -+ [QCOM_RPM_PM8921_LDO11] = { 153, 67, 48, 2 }, -+ [QCOM_RPM_PM8921_LDO12] = { 155, 69, 49, 2 }, -+ [QCOM_RPM_PM8921_LDO13] = { 157, 71, 50, 2 }, -+ [QCOM_RPM_PM8921_LDO14] = { 159, 73, 51, 2 }, -+ [QCOM_RPM_PM8921_LDO15] = { 161, 75, 52, 2 }, -+ [QCOM_RPM_PM8921_LDO16] = { 163, 77, 53, 2 }, -+ [QCOM_RPM_PM8921_LDO17] = { 165, 79, 54, 2 }, -+ [QCOM_RPM_PM8921_LDO18] = { 167, 81, 55, 2 }, -+ [QCOM_RPM_PM8921_LDO19] = { 169, 83, 56, 2 }, -+ [QCOM_RPM_PM8921_LDO20] = { 171, 85, 57, 2 }, -+ [QCOM_RPM_PM8921_LDO21] = { 173, 87, 58, 2 }, -+ [QCOM_RPM_PM8921_LDO22] = { 175, 89, 59, 2 }, -+ [QCOM_RPM_PM8921_LDO23] = { 177, 91, 60, 2 }, -+ [QCOM_RPM_PM8921_LDO24] = { 179, 93, 61, 2 }, -+ [QCOM_RPM_PM8921_LDO25] = { 181, 95, 62, 2 }, -+ [QCOM_RPM_PM8921_LDO26] = { 183, 97, 63, 2 }, -+ [QCOM_RPM_PM8921_LDO27] = { 185, 99, 64, 2 }, -+ [QCOM_RPM_PM8921_LDO28] = { 187, 101, 65, 2 }, -+ [QCOM_RPM_PM8921_LDO29] = { 189, 103, 66, 2 }, -+ [QCOM_RPM_PM8921_CLK1] = { 191, 105, 67, 2 }, -+ [QCOM_RPM_PM8921_CLK2] = { 193, 107, 68, 2 }, -+ [QCOM_RPM_PM8921_LVS1] = { 195, 109, 69, 1 }, -+ [QCOM_RPM_PM8921_LVS2] = { 196, 110, 70, 1 }, -+ [QCOM_RPM_PM8921_LVS3] = { 197, 111, 71, 1 }, -+ [QCOM_RPM_PM8921_LVS4] = { 198, 112, 72, 1 }, -+ [QCOM_RPM_PM8921_LVS5] = { 199, 113, 73, 1 }, -+ [QCOM_RPM_PM8921_LVS6] = { 200, 114, 74, 1 }, -+ [QCOM_RPM_PM8921_LVS7] = { 201, 115, 75, 1 }, -+ [QCOM_RPM_PM8921_NCP] = { 202, 116, 80, 2 }, -+ [QCOM_RPM_CXO_BUFFERS] = { 204, 118, 81, 1 }, -+ [QCOM_RPM_USB_OTG_SWITCH] = { 205, 119, 82, 1 }, -+ [QCOM_RPM_HDMI_SWITCH] = { 206, 120, 83, 1 }, -+ [QCOM_RPM_DDR_DMM] = { 207, 121, 84, 2 }, -+}; -+ -+static const struct qcom_rpm_data msm8960_template = { -+ .version = 3, -+ .resource_table = msm8960_rpm_resource_table, -+ .n_resources = ARRAY_SIZE(msm8960_rpm_resource_table), -+}; -+ -+static const struct of_device_id qcom_rpm_of_match[] = { -+ { .compatible = "qcom,rpm-apq8064", .data = &apq8064_template }, -+ { .compatible = "qcom,rpm-msm8660", .data = &msm8660_template }, -+ { .compatible = "qcom,rpm-msm8960", .data = &msm8960_template }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, qcom_rpm_of_match); -+ -+int qcom_rpm_write(struct qcom_rpm *rpm, -+ int state, -+ int resource, -+ u32 *buf, size_t count) -+{ -+ const struct qcom_rpm_resource *res; -+ const struct qcom_rpm_data *data = rpm->data; -+ u32 sel_mask[RPM_SELECT_SIZE] = { 0 }; -+ int left; -+ int ret = 0; -+ int i; -+ -+ if (WARN_ON(resource < 0 || resource >= data->n_resources)) -+ return -EINVAL; -+ -+ res = &data->resource_table[resource]; -+ if (WARN_ON(res->size != count)) -+ return -EINVAL; -+ -+ mutex_lock(&rpm->lock); -+ -+ for (i = 0; i < res->size; i++) -+ writel_relaxed(buf[i], RPM_REQ_REG(rpm, res->target_id + i)); -+ -+ bitmap_set((unsigned long *)sel_mask, res->select_id, 1); -+ for (i = 0; i < ARRAY_SIZE(sel_mask); i++) { -+ writel_relaxed(sel_mask[i], -+ RPM_CTRL_REG(rpm, RPM_REQ_SELECT + i)); -+ } -+ -+ writel_relaxed(BIT(state), RPM_CTRL_REG(rpm, RPM_REQUEST_CONTEXT)); -+ -+ reinit_completion(&rpm->ack); -+ regmap_write(rpm->ipc_regmap, rpm->ipc_offset, BIT(rpm->ipc_bit)); -+ -+ left = wait_for_completion_timeout(&rpm->ack, RPM_REQUEST_TIMEOUT); -+ if (!left) -+ ret = -ETIMEDOUT; -+ else if (rpm->ack_status & RPM_REJECTED) -+ ret = -EIO; -+ -+ mutex_unlock(&rpm->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(qcom_rpm_write); -+ -+static irqreturn_t qcom_rpm_ack_interrupt(int irq, void *dev) -+{ -+ struct qcom_rpm *rpm = dev; -+ u32 ack; -+ int i; -+ -+ ack = readl_relaxed(RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT)); -+ for (i = 0; i < RPM_SELECT_SIZE; i++) -+ writel_relaxed(0, RPM_CTRL_REG(rpm, RPM_ACK_SELECTOR + i)); -+ writel(0, RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT)); -+ -+ if (ack & RPM_NOTIFICATION) { -+ dev_warn(rpm->dev, "ignoring notification!\n"); -+ } else { -+ rpm->ack_status = ack; -+ complete(&rpm->ack); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t qcom_rpm_err_interrupt(int irq, void *dev) -+{ -+ struct qcom_rpm *rpm = dev; -+ -+ regmap_write(rpm->ipc_regmap, rpm->ipc_offset, BIT(rpm->ipc_bit)); -+ dev_err(rpm->dev, "RPM triggered fatal error\n"); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t qcom_rpm_wakeup_interrupt(int irq, void *dev) -+{ -+ return IRQ_HANDLED; -+} -+ -+static int qcom_rpm_probe(struct platform_device *pdev) -+{ -+ const struct of_device_id *match; -+ struct device_node *syscon_np; -+ struct resource *res; -+ struct qcom_rpm *rpm; -+ u32 fw_version[3]; -+ int irq_wakeup; -+ int irq_ack; -+ int irq_err; -+ int ret; -+ -+ rpm = devm_kzalloc(&pdev->dev, sizeof(*rpm), GFP_KERNEL); -+ if (!rpm) -+ return -ENOMEM; -+ -+ rpm->dev = &pdev->dev; -+ mutex_init(&rpm->lock); -+ init_completion(&rpm->ack); -+ -+ irq_ack = platform_get_irq_byname(pdev, "ack"); -+ if (irq_ack < 0) { -+ dev_err(&pdev->dev, "required ack interrupt missing\n"); -+ return irq_ack; -+ } -+ -+ irq_err = platform_get_irq_byname(pdev, "err"); -+ if (irq_err < 0) { -+ dev_err(&pdev->dev, "required err interrupt missing\n"); -+ return irq_err; -+ } -+ -+ irq_wakeup = platform_get_irq_byname(pdev, "wakeup"); -+ if (irq_wakeup < 0) { -+ dev_err(&pdev->dev, "required wakeup interrupt missing\n"); -+ return irq_wakeup; -+ } -+ -+ match = of_match_device(qcom_rpm_of_match, &pdev->dev); -+ rpm->data = match->data; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ rpm->status_regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(rpm->status_regs)) -+ return PTR_ERR(rpm->status_regs); -+ rpm->ctrl_regs = rpm->status_regs + 0x400; -+ rpm->req_regs = rpm->status_regs + 0x600; -+ -+ syscon_np = of_parse_phandle(pdev->dev.of_node, "qcom,ipc", 0); -+ if (!syscon_np) { -+ dev_err(&pdev->dev, "no qcom,ipc node\n"); -+ return -ENODEV; -+ } -+ -+ rpm->ipc_regmap = syscon_node_to_regmap(syscon_np); -+ if (IS_ERR(rpm->ipc_regmap)) -+ return PTR_ERR(rpm->ipc_regmap); -+ -+ ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,ipc", 1, -+ &rpm->ipc_offset); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "no offset in qcom,ipc\n"); -+ return -EINVAL; -+ } -+ -+ ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,ipc", 2, -+ &rpm->ipc_bit); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "no bit in qcom,ipc\n"); -+ return -EINVAL; -+ } -+ -+ dev_set_drvdata(&pdev->dev, rpm); -+ -+ fw_version[0] = readl(RPM_STATUS_REG(rpm, 0)); -+ fw_version[1] = readl(RPM_STATUS_REG(rpm, 1)); -+ fw_version[2] = readl(RPM_STATUS_REG(rpm, 2)); -+ if (fw_version[0] != rpm->data->version) { -+ dev_err(&pdev->dev, -+ "RPM version %u.%u.%u incompatible with driver version %u", -+ fw_version[0], -+ fw_version[1], -+ fw_version[2], -+ rpm->data->version); -+ return -EFAULT; -+ } -+ -+ dev_info(&pdev->dev, "RPM firmware %u.%u.%u\n", fw_version[0], -+ fw_version[1], -+ fw_version[2]); -+ -+ ret = devm_request_irq(&pdev->dev, -+ irq_ack, -+ qcom_rpm_ack_interrupt, -+ IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, -+ "qcom_rpm_ack", -+ rpm); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to request ack interrupt\n"); -+ return ret; -+ } -+ -+ ret = irq_set_irq_wake(irq_ack, 1); -+ if (ret) -+ dev_warn(&pdev->dev, "failed to mark ack irq as wakeup\n"); -+ -+ ret = devm_request_irq(&pdev->dev, -+ irq_err, -+ qcom_rpm_err_interrupt, -+ IRQF_TRIGGER_RISING, -+ "qcom_rpm_err", -+ rpm); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to request err interrupt\n"); -+ return ret; -+ } -+ -+ ret = devm_request_irq(&pdev->dev, -+ irq_wakeup, -+ qcom_rpm_wakeup_interrupt, -+ IRQF_TRIGGER_RISING, -+ "qcom_rpm_wakeup", -+ rpm); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to request wakeup interrupt\n"); -+ return ret; -+ } -+ -+ ret = irq_set_irq_wake(irq_wakeup, 1); -+ if (ret) -+ dev_warn(&pdev->dev, "failed to mark wakeup irq as wakeup\n"); -+ -+ return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); -+} -+ -+static int qcom_rpm_remove(struct platform_device *pdev) -+{ -+ of_platform_depopulate(&pdev->dev); -+ return 0; -+} -+ -+static struct platform_driver qcom_rpm_driver = { -+ .probe = qcom_rpm_probe, -+ .remove = qcom_rpm_remove, -+ .driver = { -+ .name = "qcom_rpm", -+ .of_match_table = qcom_rpm_of_match, -+ }, -+}; -+ -+static int __init qcom_rpm_init(void) -+{ -+ return platform_driver_register(&qcom_rpm_driver); -+} -+arch_initcall(qcom_rpm_init); -+ -+static void __exit qcom_rpm_exit(void) -+{ -+ platform_driver_unregister(&qcom_rpm_driver); -+} -+module_exit(qcom_rpm_exit) -+ -+MODULE_DESCRIPTION("Qualcomm Resource Power Manager driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_AUTHOR("Bjorn Andersson "); ---- /dev/null -+++ b/include/linux/mfd/qcom_rpm.h -@@ -0,0 +1,13 @@ -+#ifndef __QCOM_RPM_H__ -+#define __QCOM_RPM_H__ -+ -+#include -+ -+struct qcom_rpm; -+ -+#define QCOM_RPM_ACTIVE_STATE 0 -+#define QCOM_RPM_SLEEP_STATE 1 -+ -+int qcom_rpm_write(struct qcom_rpm *rpm, int state, int resource, u32 *buf, size_t count); -+ -+#endif diff --git a/target/linux/ipq806x/patches-3.18/121-mfd-qcom_rpm-Add-support-for-IPQ8064.patch b/target/linux/ipq806x/patches-3.18/121-mfd-qcom_rpm-Add-support-for-IPQ8064.patch deleted file mode 100644 index e5e9e4e6ccee..000000000000 --- a/target/linux/ipq806x/patches-3.18/121-mfd-qcom_rpm-Add-support-for-IPQ8064.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 4d54b0adfa67476e6509bc8646b9dbac642e8a29 Mon Sep 17 00:00:00 2001 -From: Josh Cartwright -Date: Thu, 26 Mar 2015 11:29:26 -0700 -Subject: [PATCH] mfd: qcom_rpm: Add support for IPQ8064 - -The IPQ8064 also includes an RPM following the same message structure as -other chips. In addition, it supports a few new resource types to -support the NSS fabric clocks and the SMB208/SMB209 regulators found on -the reference boards. - -Signed-off-by: Josh Cartwright -Signed-off-by: Stephen Boyd -Signed-off-by: Lee Jones ---- - drivers/mfd/qcom_rpm.c | 41 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 41 insertions(+) - ---- a/drivers/mfd/qcom_rpm.c -+++ b/drivers/mfd/qcom_rpm.c -@@ -323,10 +323,51 @@ static const struct qcom_rpm_data msm896 - .n_resources = ARRAY_SIZE(msm8960_rpm_resource_table), - }; - -+static const struct qcom_rpm_resource ipq806x_rpm_resource_table[] = { -+ [QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 }, -+ [QCOM_RPM_PXO_CLK] = { 26, 10, 6, 1 }, -+ [QCOM_RPM_APPS_FABRIC_CLK] = { 27, 11, 8, 1 }, -+ [QCOM_RPM_SYS_FABRIC_CLK] = { 28, 12, 9, 1 }, -+ [QCOM_RPM_NSS_FABRIC_0_CLK] = { 29, 13, 10, 1 }, -+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 30, 14, 11, 1 }, -+ [QCOM_RPM_SFPB_CLK] = { 31, 15, 12, 1 }, -+ [QCOM_RPM_CFPB_CLK] = { 32, 16, 13, 1 }, -+ [QCOM_RPM_NSS_FABRIC_1_CLK] = { 33, 17, 14, 1 }, -+ [QCOM_RPM_EBI1_CLK] = { 34, 18, 16, 1 }, -+ [QCOM_RPM_APPS_FABRIC_HALT] = { 35, 19, 18, 2 }, -+ [QCOM_RPM_APPS_FABRIC_MODE] = { 37, 20, 19, 3 }, -+ [QCOM_RPM_APPS_FABRIC_IOCTL] = { 40, 21, 20, 1 }, -+ [QCOM_RPM_APPS_FABRIC_ARB] = { 41, 22, 21, 12 }, -+ [QCOM_RPM_SYS_FABRIC_HALT] = { 53, 23, 22, 2 }, -+ [QCOM_RPM_SYS_FABRIC_MODE] = { 55, 24, 23, 3 }, -+ [QCOM_RPM_SYS_FABRIC_IOCTL] = { 58, 25, 24, 1 }, -+ [QCOM_RPM_SYS_FABRIC_ARB] = { 59, 26, 25, 30 }, -+ [QCOM_RPM_MM_FABRIC_HALT] = { 89, 27, 26, 2 }, -+ [QCOM_RPM_MM_FABRIC_MODE] = { 91, 28, 27, 3 }, -+ [QCOM_RPM_MM_FABRIC_IOCTL] = { 94, 29, 28, 1 }, -+ [QCOM_RPM_MM_FABRIC_ARB] = { 95, 30, 29, 2 }, -+ [QCOM_RPM_CXO_BUFFERS] = { 209, 33, 31, 1 }, -+ [QCOM_RPM_USB_OTG_SWITCH] = { 210, 34, 32, 1 }, -+ [QCOM_RPM_HDMI_SWITCH] = { 211, 35, 33, 1 }, -+ [QCOM_RPM_DDR_DMM] = { 212, 36, 34, 2 }, -+ [QCOM_RPM_VDDMIN_GPIO] = { 215, 40, 39, 1 }, -+ [QCOM_RPM_SMB208_S1a] = { 216, 41, 90, 2 }, -+ [QCOM_RPM_SMB208_S1b] = { 218, 43, 91, 2 }, -+ [QCOM_RPM_SMB208_S2a] = { 220, 45, 92, 2 }, -+ [QCOM_RPM_SMB208_S2b] = { 222, 47, 93, 2 }, -+}; -+ -+static const struct qcom_rpm_data ipq806x_template = { -+ .version = 3, -+ .resource_table = ipq806x_rpm_resource_table, -+ .n_resources = ARRAY_SIZE(ipq806x_rpm_resource_table), -+}; -+ - static const struct of_device_id qcom_rpm_of_match[] = { - { .compatible = "qcom,rpm-apq8064", .data = &apq8064_template }, - { .compatible = "qcom,rpm-msm8660", .data = &msm8660_template }, - { .compatible = "qcom,rpm-msm8960", .data = &msm8960_template }, -+ { .compatible = "qcom,rpm-ipq8064", .data = &ipq806x_template }, - { } - }; - MODULE_DEVICE_TABLE(of, qcom_rpm_of_match); diff --git a/target/linux/ipq806x/patches-3.18/122-mfd-devicetree-bindings-Add-Qualcomm-RPM-DT-binding.patch b/target/linux/ipq806x/patches-3.18/122-mfd-devicetree-bindings-Add-Qualcomm-RPM-DT-binding.patch deleted file mode 100644 index a65d2c51318c..000000000000 --- a/target/linux/ipq806x/patches-3.18/122-mfd-devicetree-bindings-Add-Qualcomm-RPM-DT-binding.patch +++ /dev/null @@ -1,247 +0,0 @@ -From aa0c4b815045420ea54d5ae5362f5a0190609d46 Mon Sep 17 00:00:00 2001 -From: Bjorn Andersson -Date: Wed, 26 Nov 2014 13:50:59 -0800 -Subject: [PATCH] mfd: devicetree: bindings: Add Qualcomm RPM DT binding - -Add binding for the Qualcomm Resource Power Manager (RPM) found in 8660, -8960 and 8064 based devices. - -Signed-off-by: Bjorn Andersson -Signed-off-by: Lee Jones ---- - Documentation/devicetree/bindings/mfd/qcom-rpm.txt | 70 ++++++++++ - include/dt-bindings/mfd/qcom-rpm.h | 154 +++++++++++++++++++++ - 2 files changed, 224 insertions(+) - create mode 100644 Documentation/devicetree/bindings/mfd/qcom-rpm.txt - create mode 100644 include/dt-bindings/mfd/qcom-rpm.h - ---- /dev/null -+++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt -@@ -0,0 +1,70 @@ -+Qualcomm Resource Power Manager (RPM) -+ -+This driver is used to interface with the Resource Power Manager (RPM) found in -+various Qualcomm platforms. The RPM allows each component in the system to vote -+for state of the system resources, such as clocks, regulators and bus -+frequencies. -+ -+- compatible: -+ Usage: required -+ Value type: -+ Definition: must be one of: -+ "qcom,rpm-apq8064" -+ "qcom,rpm-msm8660" -+ "qcom,rpm-msm8960" -+ -+- reg: -+ Usage: required -+ Value type: -+ Definition: base address and size of the RPM's message ram -+ -+- interrupts: -+ Usage: required -+ Value type: -+ Definition: three entries specifying the RPM's: -+ 1. acknowledgement interrupt -+ 2. error interrupt -+ 3. wakeup interrupt -+ -+- interrupt-names: -+ Usage: required -+ Value type: -+ Definition: must be the three strings "ack", "err" and "wakeup", in order -+ -+- #address-cells: -+ Usage: required -+ Value type: -+ Definition: must be 1 -+ -+- #size-cells: -+ Usage: required -+ Value type: -+ Definition: must be 0 -+ -+- qcom,ipc: -+ Usage: required -+ Value type: -+ -+ Definition: three entries specifying the outgoing ipc bit used for -+ signaling the RPM: -+ - phandle to a syscon node representing the apcs registers -+ - u32 representing offset to the register within the syscon -+ - u32 representing the ipc bit within the register -+ -+ -+= EXAMPLE -+ -+ #include -+ -+ rpm@108000 { -+ compatible = "qcom,rpm-msm8960"; -+ reg = <0x108000 0x1000>; -+ qcom,ipc = <&apcs 0x8 2>; -+ -+ interrupts = <0 19 0>, <0 21 0>, <0 22 0>; -+ interrupt-names = "ack", "err", "wakeup"; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ ---- /dev/null -+++ b/include/dt-bindings/mfd/qcom-rpm.h -@@ -0,0 +1,154 @@ -+/* -+ * This header provides constants for the Qualcomm RPM bindings. -+ */ -+ -+#ifndef _DT_BINDINGS_MFD_QCOM_RPM_H -+#define _DT_BINDINGS_MFD_QCOM_RPM_H -+ -+/* -+ * Constants use to identify individual resources in the RPM. -+ */ -+#define QCOM_RPM_APPS_FABRIC_ARB 1 -+#define QCOM_RPM_APPS_FABRIC_CLK 2 -+#define QCOM_RPM_APPS_FABRIC_HALT 3 -+#define QCOM_RPM_APPS_FABRIC_IOCTL 4 -+#define QCOM_RPM_APPS_FABRIC_MODE 5 -+#define QCOM_RPM_APPS_L2_CACHE_CTL 6 -+#define QCOM_RPM_CFPB_CLK 7 -+#define QCOM_RPM_CXO_BUFFERS 8 -+#define QCOM_RPM_CXO_CLK 9 -+#define QCOM_RPM_DAYTONA_FABRIC_CLK 10 -+#define QCOM_RPM_DDR_DMM 11 -+#define QCOM_RPM_EBI1_CLK 12 -+#define QCOM_RPM_HDMI_SWITCH 13 -+#define QCOM_RPM_MMFPB_CLK 14 -+#define QCOM_RPM_MM_FABRIC_ARB 15 -+#define QCOM_RPM_MM_FABRIC_CLK 16 -+#define QCOM_RPM_MM_FABRIC_HALT 17 -+#define QCOM_RPM_MM_FABRIC_IOCTL 18 -+#define QCOM_RPM_MM_FABRIC_MODE 19 -+#define QCOM_RPM_PLL_4 20 -+#define QCOM_RPM_PM8058_LDO0 21 -+#define QCOM_RPM_PM8058_LDO1 22 -+#define QCOM_RPM_PM8058_LDO2 23 -+#define QCOM_RPM_PM8058_LDO3 24 -+#define QCOM_RPM_PM8058_LDO4 25 -+#define QCOM_RPM_PM8058_LDO5 26 -+#define QCOM_RPM_PM8058_LDO6 27 -+#define QCOM_RPM_PM8058_LDO7 28 -+#define QCOM_RPM_PM8058_LDO8 29 -+#define QCOM_RPM_PM8058_LDO9 30 -+#define QCOM_RPM_PM8058_LDO10 31 -+#define QCOM_RPM_PM8058_LDO11 32 -+#define QCOM_RPM_PM8058_LDO12 33 -+#define QCOM_RPM_PM8058_LDO13 34 -+#define QCOM_RPM_PM8058_LDO14 35 -+#define QCOM_RPM_PM8058_LDO15 36 -+#define QCOM_RPM_PM8058_LDO16 37 -+#define QCOM_RPM_PM8058_LDO17 38 -+#define QCOM_RPM_PM8058_LDO18 39 -+#define QCOM_RPM_PM8058_LDO19 40 -+#define QCOM_RPM_PM8058_LDO20 41 -+#define QCOM_RPM_PM8058_LDO21 42 -+#define QCOM_RPM_PM8058_LDO22 43 -+#define QCOM_RPM_PM8058_LDO23 44 -+#define QCOM_RPM_PM8058_LDO24 45 -+#define QCOM_RPM_PM8058_LDO25 46 -+#define QCOM_RPM_PM8058_LVS0 47 -+#define QCOM_RPM_PM8058_LVS1 48 -+#define QCOM_RPM_PM8058_NCP 49 -+#define QCOM_RPM_PM8058_SMPS0 50 -+#define QCOM_RPM_PM8058_SMPS1 51 -+#define QCOM_RPM_PM8058_SMPS2 52 -+#define QCOM_RPM_PM8058_SMPS3 53 -+#define QCOM_RPM_PM8058_SMPS4 54 -+#define QCOM_RPM_PM8821_LDO1 55 -+#define QCOM_RPM_PM8821_SMPS1 56 -+#define QCOM_RPM_PM8821_SMPS2 57 -+#define QCOM_RPM_PM8901_LDO0 58 -+#define QCOM_RPM_PM8901_LDO1 59 -+#define QCOM_RPM_PM8901_LDO2 60 -+#define QCOM_RPM_PM8901_LDO3 61 -+#define QCOM_RPM_PM8901_LDO4 62 -+#define QCOM_RPM_PM8901_LDO5 63 -+#define QCOM_RPM_PM8901_LDO6 64 -+#define QCOM_RPM_PM8901_LVS0 65 -+#define QCOM_RPM_PM8901_LVS1 66 -+#define QCOM_RPM_PM8901_LVS2 67 -+#define QCOM_RPM_PM8901_LVS3 68 -+#define QCOM_RPM_PM8901_MVS 69 -+#define QCOM_RPM_PM8901_SMPS0 70 -+#define QCOM_RPM_PM8901_SMPS1 71 -+#define QCOM_RPM_PM8901_SMPS2 72 -+#define QCOM_RPM_PM8901_SMPS3 73 -+#define QCOM_RPM_PM8901_SMPS4 74 -+#define QCOM_RPM_PM8921_CLK1 75 -+#define QCOM_RPM_PM8921_CLK2 76 -+#define QCOM_RPM_PM8921_LDO1 77 -+#define QCOM_RPM_PM8921_LDO2 78 -+#define QCOM_RPM_PM8921_LDO3 79 -+#define QCOM_RPM_PM8921_LDO4 80 -+#define QCOM_RPM_PM8921_LDO5 81 -+#define QCOM_RPM_PM8921_LDO6 82 -+#define QCOM_RPM_PM8921_LDO7 83 -+#define QCOM_RPM_PM8921_LDO8 84 -+#define QCOM_RPM_PM8921_LDO9 85 -+#define QCOM_RPM_PM8921_LDO10 86 -+#define QCOM_RPM_PM8921_LDO11 87 -+#define QCOM_RPM_PM8921_LDO12 88 -+#define QCOM_RPM_PM8921_LDO13 89 -+#define QCOM_RPM_PM8921_LDO14 90 -+#define QCOM_RPM_PM8921_LDO15 91 -+#define QCOM_RPM_PM8921_LDO16 92 -+#define QCOM_RPM_PM8921_LDO17 93 -+#define QCOM_RPM_PM8921_LDO18 94 -+#define QCOM_RPM_PM8921_LDO19 95 -+#define QCOM_RPM_PM8921_LDO20 96 -+#define QCOM_RPM_PM8921_LDO21 97 -+#define QCOM_RPM_PM8921_LDO22 98 -+#define QCOM_RPM_PM8921_LDO23 99 -+#define QCOM_RPM_PM8921_LDO24 100 -+#define QCOM_RPM_PM8921_LDO25 101 -+#define QCOM_RPM_PM8921_LDO26 102 -+#define QCOM_RPM_PM8921_LDO27 103 -+#define QCOM_RPM_PM8921_LDO28 104 -+#define QCOM_RPM_PM8921_LDO29 105 -+#define QCOM_RPM_PM8921_LVS1 106 -+#define QCOM_RPM_PM8921_LVS2 107 -+#define QCOM_RPM_PM8921_LVS3 108 -+#define QCOM_RPM_PM8921_LVS4 109 -+#define QCOM_RPM_PM8921_LVS5 110 -+#define QCOM_RPM_PM8921_LVS6 111 -+#define QCOM_RPM_PM8921_LVS7 112 -+#define QCOM_RPM_PM8921_MVS 113 -+#define QCOM_RPM_PM8921_NCP 114 -+#define QCOM_RPM_PM8921_SMPS1 115 -+#define QCOM_RPM_PM8921_SMPS2 116 -+#define QCOM_RPM_PM8921_SMPS3 117 -+#define QCOM_RPM_PM8921_SMPS4 118 -+#define QCOM_RPM_PM8921_SMPS5 119 -+#define QCOM_RPM_PM8921_SMPS6 120 -+#define QCOM_RPM_PM8921_SMPS7 121 -+#define QCOM_RPM_PM8921_SMPS8 122 -+#define QCOM_RPM_PXO_CLK 123 -+#define QCOM_RPM_QDSS_CLK 124 -+#define QCOM_RPM_SFPB_CLK 125 -+#define QCOM_RPM_SMI_CLK 126 -+#define QCOM_RPM_SYS_FABRIC_ARB 127 -+#define QCOM_RPM_SYS_FABRIC_CLK 128 -+#define QCOM_RPM_SYS_FABRIC_HALT 129 -+#define QCOM_RPM_SYS_FABRIC_IOCTL 130 -+#define QCOM_RPM_SYS_FABRIC_MODE 131 -+#define QCOM_RPM_USB_OTG_SWITCH 132 -+#define QCOM_RPM_VDDMIN_GPIO 133 -+ -+/* -+ * Constants used to select force mode for regulators. -+ */ -+#define QCOM_RPM_FORCE_MODE_NONE 0 -+#define QCOM_RPM_FORCE_MODE_LPM 1 -+#define QCOM_RPM_FORCE_MODE_HPM 2 -+#define QCOM_RPM_FORCE_MODE_AUTO 3 -+#define QCOM_RPM_FORCE_MODE_BYPASS 4 -+ -+#endif diff --git a/target/linux/ipq806x/patches-3.18/123-mfd-devicetree-qcom_rpm-Document-IPQ8064-resources.patch b/target/linux/ipq806x/patches-3.18/123-mfd-devicetree-qcom_rpm-Document-IPQ8064-resources.patch deleted file mode 100644 index c8a9f3f5d085..000000000000 --- a/target/linux/ipq806x/patches-3.18/123-mfd-devicetree-qcom_rpm-Document-IPQ8064-resources.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 30bc3aa5c4ed3072bdff7d915772df1b91307ed4 Mon Sep 17 00:00:00 2001 -From: Josh Cartwright -Date: Thu, 26 Mar 2015 11:29:25 -0700 -Subject: [PATCH] mfd: devicetree: qcom_rpm: Document IPQ8064 resources - -The IPQ8064 SoC has several RPM-controlled resources, an NSS fabrick -clock and four regulator resources. Provide definitions for them. - -Signed-off-by: Josh Cartwright -[sboyd@codeaurora.org: Drop regulator part of binding] -Signed-off-by: Stephen Boyd -Signed-off-by: Lee Jones ---- - Documentation/devicetree/bindings/mfd/qcom-rpm.txt | 1 + - include/dt-bindings/mfd/qcom-rpm.h | 6 ++++++ - 2 files changed, 7 insertions(+) - ---- a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt -+++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt -@@ -12,6 +12,7 @@ frequencies. - "qcom,rpm-apq8064" - "qcom,rpm-msm8660" - "qcom,rpm-msm8960" -+ "qcom,rpm-ipq8064" - - - reg: - Usage: required ---- a/include/dt-bindings/mfd/qcom-rpm.h -+++ b/include/dt-bindings/mfd/qcom-rpm.h -@@ -141,6 +141,12 @@ - #define QCOM_RPM_SYS_FABRIC_MODE 131 - #define QCOM_RPM_USB_OTG_SWITCH 132 - #define QCOM_RPM_VDDMIN_GPIO 133 -+#define QCOM_RPM_NSS_FABRIC_0_CLK 134 -+#define QCOM_RPM_NSS_FABRIC_1_CLK 135 -+#define QCOM_RPM_SMB208_S1a 136 -+#define QCOM_RPM_SMB208_S1b 137 -+#define QCOM_RPM_SMB208_S2a 138 -+#define QCOM_RPM_SMB208_S2b 139 - - /* - * Constants used to select force mode for regulators. diff --git a/target/linux/ipq806x/patches-3.18/124-regulator-rpm-add-support-for-RPM-controller-SMB208.patch b/target/linux/ipq806x/patches-3.18/124-regulator-rpm-add-support-for-RPM-controller-SMB208.patch deleted file mode 100644 index e4f094c2132c..000000000000 --- a/target/linux/ipq806x/patches-3.18/124-regulator-rpm-add-support-for-RPM-controller-SMB208.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0f5bb5b5de3b18877373f746bdb85d8ea0efeedf Mon Sep 17 00:00:00 2001 -From: Josh Cartwright -Date: Thu, 20 Nov 2014 13:41:25 -0600 -Subject: [PATCH] regulator: rpm: add support for RPM-controller SMB208 - -The IPQ8064 reference boards make use of SMB208 regulators which are -controlled by RPM. Implement support for these regulators in the RPM -regulator driver. - -Signed-off-by: Josh Cartwright -Acked-by: Bjorn Andersson -Signed-off-by: Mark Brown ---- - drivers/regulator/qcom_rpm-regulator.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - ---- a/drivers/regulator/qcom_rpm-regulator.c -+++ b/drivers/regulator/qcom_rpm-regulator.c -@@ -183,6 +183,13 @@ static const struct regulator_linear_ran - REGULATOR_LINEAR_RANGE(1500000, 64, 100, 50000), - }; - -+static const struct regulator_linear_range smb208_ranges[] = { -+ REGULATOR_LINEAR_RANGE( 375000, 0, 29, 12500), -+ REGULATOR_LINEAR_RANGE( 750000, 30, 89, 12500), -+ REGULATOR_LINEAR_RANGE(1500000, 90, 153, 25000), -+ REGULATOR_LINEAR_RANGE(3100000, 154, 234, 25000), -+}; -+ - static const struct regulator_linear_range ncp_ranges[] = { - REGULATOR_LINEAR_RANGE(1500000, 0, 31, 50000), - }; -@@ -559,6 +566,16 @@ static const struct qcom_rpm_reg pm8921_ - .parts = &rpm8960_switch_parts, - }; - -+static const struct qcom_rpm_reg smb208_smps = { -+ .desc.linear_ranges = smb208_ranges, -+ .desc.n_linear_ranges = ARRAY_SIZE(smb208_ranges), -+ .desc.n_voltages = 235, -+ .desc.ops = &uV_ops, -+ .parts = &rpm8960_smps_parts, -+ .supports_force_mode_auto = false, -+ .supports_force_mode_bypass = false, -+}; -+ - static const struct of_device_id rpm_of_match[] = { - { .compatible = "qcom,rpm-pm8058-pldo", .data = &pm8058_pldo }, - { .compatible = "qcom,rpm-pm8058-nldo", .data = &pm8058_nldo }, -@@ -578,6 +595,8 @@ static const struct of_device_id rpm_of_ - { .compatible = "qcom,rpm-pm8921-ftsmps", .data = &pm8921_ftsmps }, - { .compatible = "qcom,rpm-pm8921-ncp", .data = &pm8921_ncp }, - { .compatible = "qcom,rpm-pm8921-switch", .data = &pm8921_switch }, -+ -+ { .compatible = "qcom,rpm-smb208", .data = &smb208_smps }, - { } - }; - MODULE_DEVICE_TABLE(of, rpm_of_match); diff --git a/target/linux/ipq806x/patches-3.18/125-regulator-qcom-rpm-Add-missing-state-flag-in-call-to.patch b/target/linux/ipq806x/patches-3.18/125-regulator-qcom-rpm-Add-missing-state-flag-in-call-to.patch deleted file mode 100644 index 48921a842912..000000000000 --- a/target/linux/ipq806x/patches-3.18/125-regulator-qcom-rpm-Add-missing-state-flag-in-call-to.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 803926825fa4db007437f76654e3e63bafb9b906 Mon Sep 17 00:00:00 2001 -From: Bjorn Andersson -Date: Wed, 26 Nov 2014 13:51:01 -0800 -Subject: [PATCH] regulator: qcom-rpm: Add missing state flag in call to RPM - -This adds the missing state parameter to the call down to the RPM. This -is currently hard coded to the active state, as that's all we're -supporting at this moment. - -Signed-off-by: Bjorn Andersson -Signed-off-by: Lee Jones ---- - drivers/regulator/qcom_rpm-regulator.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/regulator/qcom_rpm-regulator.c -+++ b/drivers/regulator/qcom_rpm-regulator.c -@@ -205,6 +205,7 @@ static int rpm_reg_write(struct qcom_rpm - vreg->val[req->word] |= value << req->shift; - - return qcom_rpm_write(vreg->rpm, -+ QCOM_RPM_ACTIVE_STATE, - vreg->resource, - vreg->val, - vreg->parts->request_len); diff --git a/target/linux/ipq806x/patches-3.18/126-add-rpm-to-ipq8064-dts.patch b/target/linux/ipq806x/patches-3.18/126-add-rpm-to-ipq8064-dts.patch deleted file mode 100644 index a40738edb1f0..000000000000 --- a/target/linux/ipq806x/patches-3.18/126-add-rpm-to-ipq8064-dts.patch +++ /dev/null @@ -1,87 +0,0 @@ ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -2,6 +2,7 @@ - - #include "skeleton.dtsi" - #include -+#include - #include - #include - #include -@@ -77,6 +78,63 @@ - ranges; - compatible = "simple-bus"; - -+ rpm@108000 { -+ compatible = "qcom,rpm-ipq8064"; -+ reg = <0x108000 0x1000>; -+ qcom,ipc = <&l2cc 0x8 2>; -+ -+ interrupts = <0 19 0>, -+ <0 21 0>, -+ <0 22 0>; -+ interrupt-names = "ack", -+ "err", -+ "wakeup"; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ smb208_s1a: smb208-s1a { -+ compatible = "qcom,rpm-smb208"; -+ reg = ; -+ -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ -+ }; -+ -+ smb208_s1b: smb208-s1b { -+ compatible = "qcom,rpm-smb208"; -+ reg = ; -+ -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2a: smb208-s2a { -+ compatible = "qcom,rpm-smb208"; -+ reg = ; -+ -+ regulator-min-microvolt = < 800000>; -+ regulator-max-microvolt = <1250000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2b: smb208-s2b { -+ compatible = "qcom,rpm-smb208"; -+ reg = ; -+ -+ regulator-min-microvolt = < 800000>; -+ regulator-max-microvolt = <1250000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ }; -+ - qcom_pinmux: pinmux@800000 { - compatible = "qcom,ipq8064-pinctrl"; - reg = <0x800000 0x4000>; -@@ -148,6 +206,12 @@ - reg = <0x02098000 0x1000>, <0x02008000 0x1000>; - }; - -+ l2cc: clock-controller@2011000 { -+ compatible = "qcom,kpss-gcc", "syscon"; -+ reg = <0x2011000 0x1000>; -+ clock-output-names = "acpu_l2_aux"; -+ }; -+ - saw0: regulator@2089000 { - compatible = "qcom,saw2"; - reg = <0x02089000 0x1000>, <0x02009000 0x1000>; diff --git a/target/linux/ipq806x/patches-3.18/130-clk_mux-Fix-set_parent-doing-the-wrong-thing-when-IN.patch b/target/linux/ipq806x/patches-3.18/130-clk_mux-Fix-set_parent-doing-the-wrong-thing-when-IN.patch deleted file mode 100644 index 29f74b760d35..000000000000 --- a/target/linux/ipq806x/patches-3.18/130-clk_mux-Fix-set_parent-doing-the-wrong-thing-when-IN.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 6793b3cd5da817c4be218bd8632f07cf4d2b0d26 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 19 Nov 2014 14:48:59 +0100 -Subject: [PATCH] clk_mux: Fix set_parent doing the wrong thing when INDEX_BIT - && index >= 3 - -If CLK_MUX_INDEX_BIT is set, then each bit turns on / off a single parent, -so theoretically multiple parents could be enabled at the same time, but in -practice only one bit should ever be 1. So to select parent 0, set -the register (*) to 0x01, to select parent 1 set it 0x02, parent 2, 0x04, -parent 3, 0x08, etc. - -But the current code does: - - if (mux->flags & CLK_MUX_INDEX_BIT) - index = (1 << ffs(index)); - -Which means that: - -For an input index of 0, ffs returns 0, so we set the register -to 0x01, ok. - -For an input index of 1, ffs returns 1, so we set the register -to 0x02, ok. - -For an input index of 2, ffs returns 2, so we set the register -to 0x04, ok. - -For an input index of 3, ffs returns 1, so we set the register -to 0x02, not good! - -The code should simply be: - - if (mux->flags & CLK_MUX_INDEX_BIT) - index = 1 << index; - -Which always does the right thing, this commit fixes this. - -Signed-off-by: Hans de Goede -Signed-off-by: Michael Turquette ---- - drivers/clk/clk-mux.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/clk/clk-mux.c -+++ b/drivers/clk/clk-mux.c -@@ -77,7 +77,7 @@ static int clk_mux_set_parent(struct clk - - else { - if (mux->flags & CLK_MUX_INDEX_BIT) -- index = (1 << ffs(index)); -+ index = 1 << index; - - if (mux->flags & CLK_MUX_INDEX_ONE) - index++; diff --git a/target/linux/ipq806x/patches-3.18/131-clk-Add-__clk_mux_determine_rate_closest.patch b/target/linux/ipq806x/patches-3.18/131-clk-Add-__clk_mux_determine_rate_closest.patch deleted file mode 100644 index 18972f353791..000000000000 --- a/target/linux/ipq806x/patches-3.18/131-clk-Add-__clk_mux_determine_rate_closest.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 15a02c1f6dd7c2bb150c61d00ffb33f584ff2288 Mon Sep 17 00:00:00 2001 -From: Stephen Boyd -Date: Mon, 19 Jan 2015 18:05:28 -0800 -Subject: [PATCH] clk: Add __clk_mux_determine_rate_closest - -Some clock drivers want to find the closest rate on the input of -a mux instead of a rate that's less than or equal to the desired -rate. Add a generic mux function to support this. - -Signed-off-by: Stephen Boyd -Tested-by: Kenneth Westfield -Signed-off-by: Michael Turquette ---- - drivers/clk/clk.c | 47 +++++++++++++++++++++++++++++++++++--------- - include/linux/clk-provider.h | 8 +++++++- - 2 files changed, 45 insertions(+), 10 deletions(-) - ---- a/drivers/clk/clk.c -+++ b/drivers/clk/clk.c -@@ -695,14 +695,20 @@ struct clk *__clk_lookup(const char *nam - return NULL; - } - --/* -- * Helper for finding best parent to provide a given frequency. This can be used -- * directly as a determine_rate callback (e.g. for a mux), or from a more -- * complex clock that may combine a mux with other operations. -- */ --long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, -- unsigned long *best_parent_rate, -- struct clk **best_parent_p) -+static bool mux_is_better_rate(unsigned long rate, unsigned long now, -+ unsigned long best, unsigned long flags) -+{ -+ if (flags & CLK_MUX_ROUND_CLOSEST) -+ return abs(now - rate) < abs(best - rate); -+ -+ return now <= rate && now > best; -+} -+ -+static long -+clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, -+ unsigned long *best_parent_rate, -+ struct clk **best_parent_p, -+ unsigned long flags) - { - struct clk *clk = hw->clk, *parent, *best_parent = NULL; - int i, num_parents; -@@ -730,7 +736,7 @@ long __clk_mux_determine_rate(struct clk - parent_rate = __clk_round_rate(parent, rate); - else - parent_rate = __clk_get_rate(parent); -- if (parent_rate <= rate && parent_rate > best) { -+ if (mux_is_better_rate(rate, parent_rate, best, flags)) { - best_parent = parent; - best = parent_rate; - } -@@ -743,8 +749,31 @@ out: - - return best; - } -+ -+/* -+ * Helper for finding best parent to provide a given frequency. This can be used -+ * directly as a determine_rate callback (e.g. for a mux), or from a more -+ * complex clock that may combine a mux with other operations. -+ */ -+long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *best_parent_rate, -+ struct clk **best_parent_p) -+{ -+ return clk_mux_determine_rate_flags(hw, rate, best_parent_rate, -+ best_parent_p, 0); -+} - EXPORT_SYMBOL_GPL(__clk_mux_determine_rate); - -+long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, -+ unsigned long *best_parent_rate, -+ struct clk **best_parent_p) -+{ -+ return clk_mux_determine_rate_flags(hw, rate, best_parent_rate, -+ best_parent_p, -+ CLK_MUX_ROUND_CLOSEST); -+} -+EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest); -+ - /*** clk api ***/ - - void __clk_unprepare(struct clk *clk) ---- a/include/linux/clk-provider.h -+++ b/include/linux/clk-provider.h -@@ -382,6 +382,8 @@ struct clk *clk_register_divider_table(s - * register, and mask of mux bits are in higher 16-bit of this register. - * While setting the mux bits, higher 16-bit should also be updated to - * indicate changing mux bits. -+ * CLK_MUX_ROUND_CLOSEST - Use the parent rate that is closest to the desired -+ * frequency. - */ - struct clk_mux { - struct clk_hw hw; -@@ -396,7 +398,8 @@ struct clk_mux { - #define CLK_MUX_INDEX_ONE BIT(0) - #define CLK_MUX_INDEX_BIT BIT(1) - #define CLK_MUX_HIWORD_MASK BIT(2) --#define CLK_MUX_READ_ONLY BIT(3) /* mux setting cannot be changed */ -+#define CLK_MUX_READ_ONLY BIT(3) /* mux can't be changed */ -+#define CLK_MUX_ROUND_CLOSEST BIT(4) - - extern const struct clk_ops clk_mux_ops; - extern const struct clk_ops clk_mux_ro_ops; -@@ -554,6 +557,9 @@ struct clk *__clk_lookup(const char *nam - long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *best_parent_rate, - struct clk **best_parent_p); -+long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, -+ unsigned long *best_parent_rate, -+ struct clk **best_parent_p); - - /* - * FIXME clock api without lock protection diff --git a/target/linux/ipq806x/patches-3.18/132-clk-Add-clk_unregister_-divider-gate-mux-to-close-me.patch b/target/linux/ipq806x/patches-3.18/132-clk-Add-clk_unregister_-divider-gate-mux-to-close-me.patch deleted file mode 100644 index 790f25d28db2..000000000000 --- a/target/linux/ipq806x/patches-3.18/132-clk-Add-clk_unregister_-divider-gate-mux-to-close-me.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 4e3c021fb995bcbb5d1f814d00584cb80eb904a8 Mon Sep 17 00:00:00 2001 -From: Krzysztof Kozlowski -Date: Mon, 5 Jan 2015 10:52:40 +0100 -Subject: [PATCH] clk: Add clk_unregister_{divider, gate, mux} to close memory - leak - -The common clk_register_{divider,gate,mux} functions allocated memory -for internal data which wasn't freed anywhere. Drivers using these -helpers could only unregister clocks but the memory would still leak. - -Add corresponding unregister functions which will release all resources. - -Signed-off-by: Krzysztof Kozlowski -Reviewed-by: Stephen Boyd -Signed-off-by: Michael Turquette ---- - drivers/clk/clk-divider.c | 16 ++++++++++++++++ - drivers/clk/clk-gate.c | 16 ++++++++++++++++ - drivers/clk/clk-mux.c | 16 ++++++++++++++++ - include/linux/clk-provider.h | 4 ++++ - 4 files changed, 52 insertions(+) - ---- a/drivers/clk/clk-divider.c -+++ b/drivers/clk/clk-divider.c -@@ -461,3 +461,19 @@ struct clk *clk_register_divider_table(s - width, clk_divider_flags, table, lock); - } - EXPORT_SYMBOL_GPL(clk_register_divider_table); -+ -+void clk_unregister_divider(struct clk *clk) -+{ -+ struct clk_divider *div; -+ struct clk_hw *hw; -+ -+ hw = __clk_get_hw(clk); -+ if (!hw) -+ return; -+ -+ div = to_clk_divider(hw); -+ -+ clk_unregister(clk); -+ kfree(div); -+} -+EXPORT_SYMBOL_GPL(clk_unregister_divider); ---- a/drivers/clk/clk-gate.c -+++ b/drivers/clk/clk-gate.c -@@ -162,3 +162,19 @@ struct clk *clk_register_gate(struct dev - return clk; - } - EXPORT_SYMBOL_GPL(clk_register_gate); -+ -+void clk_unregister_gate(struct clk *clk) -+{ -+ struct clk_gate *gate; -+ struct clk_hw *hw; -+ -+ hw = __clk_get_hw(clk); -+ if (!hw) -+ return; -+ -+ gate = to_clk_gate(hw); -+ -+ clk_unregister(clk); -+ kfree(gate); -+} -+EXPORT_SYMBOL_GPL(clk_unregister_gate); ---- a/drivers/clk/clk-mux.c -+++ b/drivers/clk/clk-mux.c -@@ -177,3 +177,19 @@ struct clk *clk_register_mux(struct devi - NULL, lock); - } - EXPORT_SYMBOL_GPL(clk_register_mux); -+ -+void clk_unregister_mux(struct clk *clk) -+{ -+ struct clk_mux *mux; -+ struct clk_hw *hw; -+ -+ hw = __clk_get_hw(clk); -+ if (!hw) -+ return; -+ -+ mux = to_clk_mux(hw); -+ -+ clk_unregister(clk); -+ kfree(mux); -+} -+EXPORT_SYMBOL_GPL(clk_unregister_mux); ---- a/include/linux/clk-provider.h -+++ b/include/linux/clk-provider.h -@@ -294,6 +294,7 @@ struct clk *clk_register_gate(struct dev - const char *parent_name, unsigned long flags, - void __iomem *reg, u8 bit_idx, - u8 clk_gate_flags, spinlock_t *lock); -+void clk_unregister_gate(struct clk *clk); - - struct clk_div_table { - unsigned int val; -@@ -361,6 +362,7 @@ struct clk *clk_register_divider_table(s - void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags, const struct clk_div_table *table, - spinlock_t *lock); -+void clk_unregister_divider(struct clk *clk); - - /** - * struct clk_mux - multiplexer clock -@@ -414,6 +416,8 @@ struct clk *clk_register_mux_table(struc - void __iomem *reg, u8 shift, u32 mask, - u8 clk_mux_flags, u32 *table, spinlock_t *lock); - -+void clk_unregister_mux(struct clk *clk); -+ - void of_fixed_factor_clk_setup(struct device_node *node); - - /** diff --git a/target/linux/ipq806x/patches-3.18/133-ARM-Add-Krait-L2-register-accessor-functions.patch b/target/linux/ipq806x/patches-3.18/133-ARM-Add-Krait-L2-register-accessor-functions.patch deleted file mode 100644 index 36a92c858aeb..000000000000 --- a/target/linux/ipq806x/patches-3.18/133-ARM-Add-Krait-L2-register-accessor-functions.patch +++ /dev/null @@ -1,144 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,01/13] ARM: Add Krait L2 register accessor functions -From: Stephen Boyd -X-Patchwork-Id: 6063051 -Message-Id: <1426920332-9340-2-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar , - Mark Rutland , Russell King , - Courtney Cavin -Date: Fri, 20 Mar 2015 23:45:20 -0700 - -Krait CPUs have a handful of L2 cache controller registers that -live behind a cp15 based indirection register. First you program -the indirection register (l2cpselr) to point the L2 'window' -register (l2cpdr) at what you want to read/write. Then you -read/write the 'window' register to do what you want. The -l2cpselr register is not banked per-cpu so we must lock around -accesses to it to prevent other CPUs from re-pointing l2cpdr -underneath us. - -Cc: Mark Rutland -Cc: Russell King -Cc: Courtney Cavin -Signed-off-by: Stephen Boyd - ---- -arch/arm/common/Kconfig | 3 ++ - arch/arm/common/Makefile | 1 + - arch/arm/common/krait-l2-accessors.c | 58 +++++++++++++++++++++++++++++++ - arch/arm/include/asm/krait-l2-accessors.h | 20 +++++++++++ - 4 files changed, 82 insertions(+) - create mode 100644 arch/arm/common/krait-l2-accessors.c - create mode 100644 arch/arm/include/asm/krait-l2-accessors.h - ---- a/arch/arm/common/Kconfig -+++ b/arch/arm/common/Kconfig -@@ -9,6 +9,9 @@ config DMABOUNCE - bool - select ZONE_DMA - -+config KRAIT_L2_ACCESSORS -+ bool -+ - config SHARP_LOCOMO - bool - ---- a/arch/arm/common/Makefile -+++ b/arch/arm/common/Makefile -@@ -7,6 +7,7 @@ obj-y += firmware.o - obj-$(CONFIG_ICST) += icst.o - obj-$(CONFIG_SA1111) += sa1111.o - obj-$(CONFIG_DMABOUNCE) += dmabounce.o -+obj-$(CONFIG_KRAIT_L2_ACCESSORS) += krait-l2-accessors.o - obj-$(CONFIG_SHARP_LOCOMO) += locomo.o - obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o - obj-$(CONFIG_SHARP_SCOOP) += scoop.o ---- /dev/null -+++ b/arch/arm/common/krait-l2-accessors.c -@@ -0,0 +1,58 @@ -+/* -+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+ -+static DEFINE_RAW_SPINLOCK(krait_l2_lock); -+ -+void krait_set_l2_indirect_reg(u32 addr, u32 val) -+{ -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&krait_l2_lock, flags); -+ /* -+ * Select the L2 window by poking l2cpselr, then write to the window -+ * via l2cpdr. -+ */ -+ asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr)); -+ isb(); -+ asm volatile ("mcr p15, 3, %0, c15, c0, 7 @ l2cpdr" : : "r" (val)); -+ isb(); -+ -+ raw_spin_unlock_irqrestore(&krait_l2_lock, flags); -+} -+EXPORT_SYMBOL(krait_set_l2_indirect_reg); -+ -+u32 krait_get_l2_indirect_reg(u32 addr) -+{ -+ u32 val; -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&krait_l2_lock, flags); -+ /* -+ * Select the L2 window by poking l2cpselr, then read from the window -+ * via l2cpdr. -+ */ -+ asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr)); -+ isb(); -+ asm volatile ("mrc p15, 3, %0, c15, c0, 7 @ l2cpdr" : "=r" (val)); -+ -+ raw_spin_unlock_irqrestore(&krait_l2_lock, flags); -+ -+ return val; -+} -+EXPORT_SYMBOL(krait_get_l2_indirect_reg); ---- /dev/null -+++ b/arch/arm/include/asm/krait-l2-accessors.h -@@ -0,0 +1,20 @@ -+/* -+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#ifndef __ASMARM_KRAIT_L2_ACCESSORS_H -+#define __ASMARM_KRAIT_L2_ACCESSORS_H -+ -+extern void krait_set_l2_indirect_reg(u32 addr, u32 val); -+extern u32 krait_get_l2_indirect_reg(u32 addr); -+ -+#endif diff --git a/target/linux/ipq806x/patches-3.18/134-clk-mux-Split-out-register-accessors-for-reuse.patch b/target/linux/ipq806x/patches-3.18/134-clk-mux-Split-out-register-accessors-for-reuse.patch deleted file mode 100644 index 50022e6107db..000000000000 --- a/target/linux/ipq806x/patches-3.18/134-clk-mux-Split-out-register-accessors-for-reuse.patch +++ /dev/null @@ -1,192 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,02/13] clk: mux: Split out register accessors for reuse -From: Stephen Boyd -X-Patchwork-Id: 6063111 -Message-Id: <1426920332-9340-3-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar -Date: Fri, 20 Mar 2015 23:45:21 -0700 - -We want to reuse the logic in clk-mux.c for other clock drivers -that don't use readl as register accessors. Fortunately, there -really isn't much to the mux code besides the table indirection -and quirk flags if you assume any bit shifting and masking has -been done already. Pull that logic out into reusable functions -that operate on an optional table and some flags so that other -drivers can use the same logic. - -Signed-off-by: Stephen Boyd - ---- -drivers/clk/clk-mux.c | 76 +++++++++++++++++++++++++++----------------- - include/linux/clk-provider.h | 9 ++++-- - 2 files changed, 54 insertions(+), 31 deletions(-) - ---- a/drivers/clk/clk-mux.c -+++ b/drivers/clk/clk-mux.c -@@ -29,35 +29,24 @@ - - #define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) - --static u8 clk_mux_get_parent(struct clk_hw *hw) -+unsigned int clk_mux_get_parent(struct clk_hw *hw, unsigned int val, -+ unsigned int *table, unsigned long flags) - { -- struct clk_mux *mux = to_clk_mux(hw); - int num_parents = __clk_get_num_parents(hw->clk); -- u32 val; - -- /* -- * FIXME need a mux-specific flag to determine if val is bitwise or numeric -- * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 -- * to 0x7 (index starts at one) -- * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so -- * val = 0x4 really means "bit 2, index starts at bit 0" -- */ -- val = clk_readl(mux->reg) >> mux->shift; -- val &= mux->mask; -- -- if (mux->table) { -+ if (table) { - int i; - - for (i = 0; i < num_parents; i++) -- if (mux->table[i] == val) -+ if (table[i] == val) - return i; - return -EINVAL; - } - -- if (val && (mux->flags & CLK_MUX_INDEX_BIT)) -+ if (val && (flags & CLK_MUX_INDEX_BIT)) - val = ffs(val) - 1; - -- if (val && (mux->flags & CLK_MUX_INDEX_ONE)) -+ if (val && (flags & CLK_MUX_INDEX_ONE)) - val--; - - if (val >= num_parents) -@@ -65,24 +54,53 @@ static u8 clk_mux_get_parent(struct clk_ - - return val; - } -+EXPORT_SYMBOL_GPL(clk_mux_get_parent); - --static int clk_mux_set_parent(struct clk_hw *hw, u8 index) -+static u8 _clk_mux_get_parent(struct clk_hw *hw) - { - struct clk_mux *mux = to_clk_mux(hw); - u32 val; -- unsigned long flags = 0; - -- if (mux->table) -- index = mux->table[index]; -+ /* -+ * FIXME need a mux-specific flag to determine if val is bitwise or numeric -+ * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 -+ * to 0x7 (index starts at one) -+ * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so -+ * val = 0x4 really means "bit 2, index starts at bit 0" -+ */ -+ val = clk_readl(mux->reg) >> mux->shift; -+ val &= mux->mask; -+ -+ return clk_mux_get_parent(hw, val, mux->table, mux->flags); -+} - -- else { -- if (mux->flags & CLK_MUX_INDEX_BIT) -- index = 1 << index; -+unsigned int clk_mux_reindex(u8 index, unsigned int *table, -+ unsigned long flags) -+{ -+ unsigned int val = index; - -- if (mux->flags & CLK_MUX_INDEX_ONE) -- index++; -+ if (table) { -+ val = table[val]; -+ } else { -+ if (flags & CLK_MUX_INDEX_BIT) -+ val = 1 << index; -+ -+ if (flags & CLK_MUX_INDEX_ONE) -+ val++; - } - -+ return val; -+} -+EXPORT_SYMBOL_GPL(clk_mux_reindex); -+ -+static int clk_mux_set_parent(struct clk_hw *hw, u8 index) -+{ -+ struct clk_mux *mux = to_clk_mux(hw); -+ u32 val; -+ unsigned long flags = 0; -+ -+ index = clk_mux_reindex(index, mux->table, mux->flags); -+ - if (mux->lock) - spin_lock_irqsave(mux->lock, flags); - -@@ -102,21 +120,21 @@ static int clk_mux_set_parent(struct clk - } - - const struct clk_ops clk_mux_ops = { -- .get_parent = clk_mux_get_parent, -+ .get_parent = _clk_mux_get_parent, - .set_parent = clk_mux_set_parent, - .determine_rate = __clk_mux_determine_rate, - }; - EXPORT_SYMBOL_GPL(clk_mux_ops); - - const struct clk_ops clk_mux_ro_ops = { -- .get_parent = clk_mux_get_parent, -+ .get_parent = _clk_mux_get_parent, - }; - EXPORT_SYMBOL_GPL(clk_mux_ro_ops); - - struct clk *clk_register_mux_table(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned long flags, - void __iomem *reg, u8 shift, u32 mask, -- u8 clk_mux_flags, u32 *table, spinlock_t *lock) -+ u8 clk_mux_flags, unsigned int *table, spinlock_t *lock) - { - struct clk_mux *mux; - struct clk *clk; ---- a/include/linux/clk-provider.h -+++ b/include/linux/clk-provider.h -@@ -390,7 +390,7 @@ void clk_unregister_divider(struct clk * - struct clk_mux { - struct clk_hw hw; - void __iomem *reg; -- u32 *table; -+ unsigned int *table; - u32 mask; - u8 shift; - u8 flags; -@@ -406,6 +406,11 @@ struct clk_mux { - extern const struct clk_ops clk_mux_ops; - extern const struct clk_ops clk_mux_ro_ops; - -+unsigned int clk_mux_get_parent(struct clk_hw *hw, unsigned int val, -+ unsigned int *table, unsigned long flags); -+unsigned int clk_mux_reindex(u8 index, unsigned int *table, -+ unsigned long flags); -+ - struct clk *clk_register_mux(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, -@@ -414,7 +419,7 @@ struct clk *clk_register_mux(struct devi - struct clk *clk_register_mux_table(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned long flags, - void __iomem *reg, u8 shift, u32 mask, -- u8 clk_mux_flags, u32 *table, spinlock_t *lock); -+ u8 clk_mux_flags, unsigned int *table, spinlock_t *lock); - - void clk_unregister_mux(struct clk *clk); - diff --git a/target/linux/ipq806x/patches-3.18/135-clk-Avoid-sending-high-rates-to-downstream-clocks-during-set_rate.patch b/target/linux/ipq806x/patches-3.18/135-clk-Avoid-sending-high-rates-to-downstream-clocks-during-set_rate.patch deleted file mode 100644 index 02d96ad08af3..000000000000 --- a/target/linux/ipq806x/patches-3.18/135-clk-Avoid-sending-high-rates-to-downstream-clocks-during-set_rate.patch +++ /dev/null @@ -1,129 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3, 03/13] clk: Avoid sending high rates to downstream clocks during - set_rate -From: Stephen Boyd -X-Patchwork-Id: 6063271 -Message-Id: <1426920332-9340-4-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar -Date: Fri, 20 Mar 2015 23:45:22 -0700 - -If a clock is on and we call clk_set_rate() on it we may get into -a situation where the clock temporarily increases in rate -dramatically while we walk the tree and call .set_rate() ops. For -example, consider a case where a PLL feeds into a divider. -Initially the divider is set to divide by 1 and the PLL is -running fairly slow (100MHz). The downstream consumer of the -divider output can only handle rates =< 400 MHz, but the divider -can only choose between divisors of 1 and 4. - - +-----+ +----------------+ - | PLL |-->| div 1 or div 4 |---> consumer device - +-----+ +----------------+ - -To achieve a rate of 400MHz on the output of the divider, we -would have to set the rate of the PLL to 1.6 GHz and then divide -it by 4. The current code would set the PLL to 1.6GHz first while -the divider is still set to 1, thus causing the downstream -consumer of the clock to receive a few clock cycles of 1.6GHz -clock (far beyond it's maximum acceptable rate). We should be -changing the divider first before increasing the PLL rate to -avoid this problem. - -Therefore, set the rate of any child clocks that are increasing -in rate from their current rate so that they can increase their -dividers if necessary. We assume that there isn't such a thing as -minimum rate requirements. - -Signed-off-by: Stephen Boyd - ---- -drivers/clk/clk.c | 34 ++++++++++++++++++++++------------ - 1 file changed, 22 insertions(+), 12 deletions(-) - ---- a/drivers/clk/clk.c -+++ b/drivers/clk/clk.c -@@ -1476,21 +1476,23 @@ static struct clk *clk_propagate_rate_ch - * walk down a subtree and set the new rates notifying the rate - * change on the way - */ --static void clk_change_rate(struct clk *clk) -+static void clk_change_rate(struct clk *clk, unsigned long best_parent_rate) - { - struct clk *child; - struct hlist_node *tmp; - unsigned long old_rate; -- unsigned long best_parent_rate = 0; - bool skip_set_rate = false; - struct clk *old_parent; - -- old_rate = clk->rate; -+ hlist_for_each_entry(child, &clk->children, child_node) { -+ /* Skip children who will be reparented to another clock */ -+ if (child->new_parent && child->new_parent != clk) -+ continue; -+ if (child->new_rate > child->rate) -+ clk_change_rate(child, clk->new_rate); -+ } - -- if (clk->new_parent) -- best_parent_rate = clk->new_parent->rate; -- else if (clk->parent) -- best_parent_rate = clk->parent->rate; -+ old_rate = clk->rate; - - if (clk->new_parent && clk->new_parent != clk->parent) { - old_parent = __clk_set_parent_before(clk, clk->new_parent); -@@ -1510,7 +1512,7 @@ static void clk_change_rate(struct clk * - if (!skip_set_rate && clk->ops->set_rate) - clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); - -- clk->rate = clk_recalc(clk, best_parent_rate); -+ clk->rate = clk->new_rate; - - if (clk->notifier_count && old_rate != clk->rate) - __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); -@@ -1523,12 +1525,13 @@ static void clk_change_rate(struct clk * - /* Skip children who will be reparented to another clock */ - if (child->new_parent && child->new_parent != clk) - continue; -- clk_change_rate(child); -+ if (child->new_rate != child->rate) -+ clk_change_rate(child, clk->new_rate); - } - - /* handle the new child who might not be in clk->children yet */ -- if (clk->new_child) -- clk_change_rate(clk->new_child); -+ if (clk->new_child && clk->new_child->new_rate != clk->new_child->rate) -+ clk_change_rate(clk->new_child, clk->new_rate); - } - - /** -@@ -1556,6 +1559,7 @@ int clk_set_rate(struct clk *clk, unsign - { - struct clk *top, *fail_clk; - int ret = 0; -+ unsigned long parent_rate; - - if (!clk) - return 0; -@@ -1589,8 +1593,13 @@ int clk_set_rate(struct clk *clk, unsign - goto out; - } - -+ if (top->parent) -+ parent_rate = top->parent->rate; -+ else -+ parent_rate = 0; -+ - /* change the rates */ -- clk_change_rate(top); -+ clk_change_rate(top, parent_rate); - - out: - clk_prepare_unlock(); diff --git a/target/linux/ipq806x/patches-3.18/136-clk-Add-safe-switch-hook.patch b/target/linux/ipq806x/patches-3.18/136-clk-Add-safe-switch-hook.patch deleted file mode 100644 index 227f8cea05c1..000000000000 --- a/target/linux/ipq806x/patches-3.18/136-clk-Add-safe-switch-hook.patch +++ /dev/null @@ -1,170 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,04/13] clk: Add safe switch hook -From: Stephen Boyd -X-Patchwork-Id: 6063211 -Message-Id: <1426920332-9340-5-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar -Date: Fri, 20 Mar 2015 23:45:23 -0700 - -Sometimes clocks can't accept their parent source turning off -while the source is reprogrammed to a different rate. Most -notably CPU clocks require a way to switch away from the current -PLL they're running on, reprogram that PLL to a new rate, and -then switch back to the PLL with the new rate once they're done. -Add a hook that drivers can implement allowing them to return a -'safe parent' that they can switch their parent to while the -upstream source is reprogrammed to support this. - -Signed-off-by: Stephen Boyd - ---- -This patch is good enough for Krait, but soon I'll need to -support a "safe rate" where we ask a clock what rate it needs to be running -at to be sure it's within voltage constraints. Right now safe parent -handles that problem on Krait, but on other platforms it won't work. - - drivers/clk/clk.c | 61 ++++++++++++++++++++++++++++++++++++++------ - include/linux/clk-provider.h | 1 + - 2 files changed, 54 insertions(+), 8 deletions(-) - ---- a/drivers/clk/clk.c -+++ b/drivers/clk/clk.c -@@ -1350,7 +1350,8 @@ out: - static void clk_calc_subtree(struct clk *clk, unsigned long new_rate, - struct clk *new_parent, u8 p_index) - { -- struct clk *child; -+ struct clk *child, *parent; -+ struct clk_hw *parent_hw; - - clk->new_rate = new_rate; - clk->new_parent = new_parent; -@@ -1360,6 +1361,18 @@ static void clk_calc_subtree(struct clk - if (new_parent && new_parent != clk->parent) - new_parent->new_child = clk; - -+ if (clk->ops->get_safe_parent) { -+ parent_hw = clk->ops->get_safe_parent(clk->hw); -+ if (parent_hw) { -+ parent = parent_hw->clk; -+ p_index = clk_fetch_parent_index(clk, parent); -+ clk->safe_parent_index = p_index; -+ clk->safe_parent = parent; -+ } -+ } else { -+ clk->safe_parent = NULL; -+ } -+ - hlist_for_each_entry(child, &clk->children, child_node) { - child->new_rate = clk_recalc(child, new_rate); - clk_calc_subtree(child, child->new_rate, NULL, 0); -@@ -1439,17 +1452,47 @@ out: - * so that in case of an error we can walk down the whole tree again and - * abort the change. - */ --static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event) -+static struct clk *clk_propagate_rate_change(struct clk *clk, -+ unsigned long event) - { - struct clk *child, *tmp_clk, *fail_clk = NULL; -+ struct clk *old_parent; - int ret = NOTIFY_DONE; - -- if (clk->rate == clk->new_rate) -+ if (clk->rate == clk->new_rate && event != POST_RATE_CHANGE) - return NULL; - -+ switch (event) { -+ case PRE_RATE_CHANGE: -+ if (clk->safe_parent) -+ clk->ops->set_parent(clk->hw, clk->safe_parent_index); -+ clk->old_rate = clk->rate; -+ break; -+ case POST_RATE_CHANGE: -+ if (clk->safe_parent) { -+ old_parent = __clk_set_parent_before(clk, -+ clk->new_parent); -+ if (clk->ops->set_rate_and_parent) { -+ clk->ops->set_rate_and_parent(clk->hw, -+ clk->new_rate, -+ clk->new_parent ? -+ clk->new_parent->rate : 0, -+ clk->new_parent_index); -+ } else if (clk->ops->set_parent) { -+ clk->ops->set_parent(clk->hw, -+ clk->new_parent_index); -+ } -+ __clk_set_parent_after(clk, clk->new_parent, -+ old_parent); -+ } -+ break; -+ } -+ - if (clk->notifier_count) { -- ret = __clk_notify(clk, event, clk->rate, clk->new_rate); -- if (ret & NOTIFY_STOP_MASK) -+ if (event != POST_RATE_CHANGE || clk->old_rate != clk->rate) -+ ret = __clk_notify(clk, event, clk->old_rate, -+ clk->new_rate); -+ if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE) - fail_clk = clk; - } - -@@ -1494,7 +1537,8 @@ static void clk_change_rate(struct clk * - - old_rate = clk->rate; - -- if (clk->new_parent && clk->new_parent != clk->parent) { -+ if (clk->new_parent && clk->new_parent != clk->parent && -+ !clk->safe_parent) { - old_parent = __clk_set_parent_before(clk, clk->new_parent); - - if (clk->ops->set_rate_and_parent) { -@@ -1514,9 +1558,6 @@ static void clk_change_rate(struct clk * - - clk->rate = clk->new_rate; - -- if (clk->notifier_count && old_rate != clk->rate) -- __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); -- - /* - * Use safe iteration, as change_rate can actually swap parents - * for certain clock types. -@@ -1601,6 +1642,8 @@ int clk_set_rate(struct clk *clk, unsign - /* change the rates */ - clk_change_rate(top, parent_rate); - -+ clk_propagate_rate_change(top, POST_RATE_CHANGE); -+ - out: - clk_prepare_unlock(); - ---- a/include/linux/clk-provider.h -+++ b/include/linux/clk-provider.h -@@ -179,6 +179,7 @@ struct clk_ops { - struct clk **best_parent_clk); - int (*set_parent)(struct clk_hw *hw, u8 index); - u8 (*get_parent)(struct clk_hw *hw); -+ struct clk_hw *(*get_safe_parent)(struct clk_hw *hw); - int (*set_rate)(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); - int (*set_rate_and_parent)(struct clk_hw *hw, ---- a/include/linux/clk-private.h -+++ b/include/linux/clk-private.h -@@ -38,8 +38,11 @@ struct clk { - struct clk **parents; - u8 num_parents; - u8 new_parent_index; -+ u8 safe_parent_index; - unsigned long rate; -+ unsigned long old_rate; - unsigned long new_rate; -+ struct clk *safe_parent; - struct clk *new_parent; - struct clk *new_child; - unsigned long flags; diff --git a/target/linux/ipq806x/patches-3.18/137-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch b/target/linux/ipq806x/patches-3.18/137-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch deleted file mode 100644 index 701d5e704609..000000000000 --- a/target/linux/ipq806x/patches-3.18/137-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch +++ /dev/null @@ -1,351 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,05/13] clk: qcom: Add support for High-Frequency PLLs (HFPLLs) -From: Stephen Boyd -X-Patchwork-Id: 6063261 -Message-Id: <1426920332-9340-6-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar -Date: Fri, 20 Mar 2015 23:45:24 -0700 - -HFPLLs are the main frequency source for Krait CPU clocks. Add -support for changing the rate of these PLLs. - -Signed-off-by: Stephen Boyd - ---- -I'd really like to get rid of __clk_hfpll_init_once() if possible... - - drivers/clk/qcom/Makefile | 1 + - drivers/clk/qcom/clk-hfpll.c | 253 +++++++++++++++++++++++++++++++++++++++++++ - drivers/clk/qcom/clk-hfpll.h | 54 +++++++++ - 3 files changed, 308 insertions(+) - create mode 100644 drivers/clk/qcom/clk-hfpll.c - create mode 100644 drivers/clk/qcom/clk-hfpll.h - ---- a/drivers/clk/qcom/Makefile -+++ b/drivers/clk/qcom/Makefile -@@ -6,6 +6,7 @@ clk-qcom-y += clk-pll.o - clk-qcom-y += clk-rcg.o - clk-qcom-y += clk-rcg2.o - clk-qcom-y += clk-branch.o -+clk-qcom-y += clk-hfpll.o - clk-qcom-y += reset.o - - obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o ---- /dev/null -+++ b/drivers/clk/qcom/clk-hfpll.c -@@ -0,0 +1,253 @@ -+/* -+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "clk-regmap.h" -+#include "clk-hfpll.h" -+ -+#define PLL_OUTCTRL BIT(0) -+#define PLL_BYPASSNL BIT(1) -+#define PLL_RESET_N BIT(2) -+ -+/* Initialize a HFPLL at a given rate and enable it. */ -+static void __clk_hfpll_init_once(struct clk_hw *hw) -+{ -+ struct clk_hfpll *h = to_clk_hfpll(hw); -+ struct hfpll_data const *hd = h->d; -+ struct regmap *regmap = h->clkr.regmap; -+ -+ if (likely(h->init_done)) -+ return; -+ -+ /* Configure PLL parameters for integer mode. */ -+ if (hd->config_val) -+ regmap_write(regmap, hd->config_reg, hd->config_val); -+ regmap_write(regmap, hd->m_reg, 0); -+ regmap_write(regmap, hd->n_reg, 1); -+ -+ if (hd->user_reg) { -+ u32 regval = hd->user_val; -+ unsigned long rate; -+ -+ rate = __clk_get_rate(hw->clk); -+ -+ /* Pick the right VCO. */ -+ if (hd->user_vco_mask && rate > hd->low_vco_max_rate) -+ regval |= hd->user_vco_mask; -+ regmap_write(regmap, hd->user_reg, regval); -+ } -+ -+ if (hd->droop_reg) -+ regmap_write(regmap, hd->droop_reg, hd->droop_val); -+ -+ h->init_done = true; -+} -+ -+static void __clk_hfpll_enable(struct clk_hw *hw) -+{ -+ struct clk_hfpll *h = to_clk_hfpll(hw); -+ struct hfpll_data const *hd = h->d; -+ struct regmap *regmap = h->clkr.regmap; -+ u32 val; -+ -+ __clk_hfpll_init_once(hw); -+ -+ /* Disable PLL bypass mode. */ -+ regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL); -+ -+ /* -+ * H/W requires a 5us delay between disabling the bypass and -+ * de-asserting the reset. Delay 10us just to be safe. -+ */ -+ udelay(10); -+ -+ /* De-assert active-low PLL reset. */ -+ regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N); -+ -+ /* Wait for PLL to lock. */ -+ if (hd->status_reg) { -+ do { -+ regmap_read(regmap, hd->status_reg, &val); -+ } while (!(val & BIT(hd->lock_bit))); -+ } else { -+ udelay(60); -+ } -+ -+ /* Enable PLL output. */ -+ regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL); -+} -+ -+/* Enable an already-configured HFPLL. */ -+static int clk_hfpll_enable(struct clk_hw *hw) -+{ -+ unsigned long flags; -+ struct clk_hfpll *h = to_clk_hfpll(hw); -+ struct hfpll_data const *hd = h->d; -+ struct regmap *regmap = h->clkr.regmap; -+ u32 mode; -+ -+ spin_lock_irqsave(&h->lock, flags); -+ regmap_read(regmap, hd->mode_reg, &mode); -+ if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL))) -+ __clk_hfpll_enable(hw); -+ spin_unlock_irqrestore(&h->lock, flags); -+ -+ return 0; -+} -+ -+static void __clk_hfpll_disable(struct clk_hfpll *h) -+{ -+ struct hfpll_data const *hd = h->d; -+ struct regmap *regmap = h->clkr.regmap; -+ -+ /* -+ * Disable the PLL output, disable test mode, enable the bypass mode, -+ * and assert the reset. -+ */ -+ regmap_update_bits(regmap, hd->mode_reg, -+ PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0); -+} -+ -+static void clk_hfpll_disable(struct clk_hw *hw) -+{ -+ struct clk_hfpll *h = to_clk_hfpll(hw); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&h->lock, flags); -+ __clk_hfpll_disable(h); -+ spin_unlock_irqrestore(&h->lock, flags); -+} -+ -+static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *parent_rate) -+{ -+ struct clk_hfpll *h = to_clk_hfpll(hw); -+ struct hfpll_data const *hd = h->d; -+ unsigned long rrate; -+ -+ rate = clamp(rate, hd->min_rate, hd->max_rate); -+ -+ rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate; -+ if (rrate > hd->max_rate) -+ rrate -= *parent_rate; -+ -+ return rrate; -+} -+ -+/* -+ * For optimization reasons, assumes no downstream clocks are actively using -+ * it. -+ */ -+static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct clk_hfpll *h = to_clk_hfpll(hw); -+ struct hfpll_data const *hd = h->d; -+ struct regmap *regmap = h->clkr.regmap; -+ unsigned long flags; -+ u32 l_val, val; -+ bool enabled; -+ -+ l_val = rate / parent_rate; -+ -+ spin_lock_irqsave(&h->lock, flags); -+ -+ enabled = __clk_is_enabled(hw->clk); -+ if (enabled) -+ __clk_hfpll_disable(h); -+ -+ /* Pick the right VCO. */ -+ if (hd->user_reg && hd->user_vco_mask) { -+ regmap_read(regmap, hd->user_reg, &val); -+ if (rate <= hd->low_vco_max_rate) -+ val &= ~hd->user_vco_mask; -+ else -+ val |= hd->user_vco_mask; -+ regmap_write(regmap, hd->user_reg, val); -+ } -+ -+ regmap_write(regmap, hd->l_reg, l_val); -+ -+ if (enabled) -+ __clk_hfpll_enable(hw); -+ -+ spin_unlock_irqrestore(&h->lock, flags); -+ -+ return 0; -+} -+ -+static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct clk_hfpll *h = to_clk_hfpll(hw); -+ struct hfpll_data const *hd = h->d; -+ struct regmap *regmap = h->clkr.regmap; -+ u32 l_val; -+ -+ regmap_read(regmap, hd->l_reg, &l_val); -+ -+ return l_val * parent_rate; -+} -+ -+static void clk_hfpll_init(struct clk_hw *hw) -+{ -+ struct clk_hfpll *h = to_clk_hfpll(hw); -+ struct hfpll_data const *hd = h->d; -+ struct regmap *regmap = h->clkr.regmap; -+ u32 mode, status; -+ -+ regmap_read(regmap, hd->mode_reg, &mode); -+ if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) { -+ __clk_hfpll_init_once(hw); -+ return; -+ } -+ -+ if (hd->status_reg) { -+ regmap_read(regmap, hd->status_reg, &status); -+ if (!(status & BIT(hd->lock_bit))) { -+ WARN(1, "HFPLL %s is ON, but not locked!\n", -+ __clk_get_name(hw->clk)); -+ clk_hfpll_disable(hw); -+ __clk_hfpll_init_once(hw); -+ } -+ } -+} -+ -+static int hfpll_is_enabled(struct clk_hw *hw) -+{ -+ struct clk_hfpll *h = to_clk_hfpll(hw); -+ struct hfpll_data const *hd = h->d; -+ struct regmap *regmap = h->clkr.regmap; -+ u32 mode; -+ -+ regmap_read(regmap, hd->mode_reg, &mode); -+ mode &= 0x7; -+ return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL); -+} -+ -+const struct clk_ops clk_ops_hfpll = { -+ .enable = clk_hfpll_enable, -+ .disable = clk_hfpll_disable, -+ .is_enabled = hfpll_is_enabled, -+ .round_rate = clk_hfpll_round_rate, -+ .set_rate = clk_hfpll_set_rate, -+ .recalc_rate = clk_hfpll_recalc_rate, -+ .init = clk_hfpll_init, -+}; -+EXPORT_SYMBOL_GPL(clk_ops_hfpll); ---- /dev/null -+++ b/drivers/clk/qcom/clk-hfpll.h -@@ -0,0 +1,54 @@ -+/* -+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+#ifndef __QCOM_CLK_HFPLL_H__ -+#define __QCOM_CLK_HFPLL_H__ -+ -+#include -+#include -+#include "clk-regmap.h" -+ -+struct hfpll_data { -+ u32 mode_reg; -+ u32 l_reg; -+ u32 m_reg; -+ u32 n_reg; -+ u32 user_reg; -+ u32 droop_reg; -+ u32 config_reg; -+ u32 status_reg; -+ u8 lock_bit; -+ -+ u32 droop_val; -+ u32 config_val; -+ u32 user_val; -+ u32 user_vco_mask; -+ unsigned long low_vco_max_rate; -+ -+ unsigned long min_rate; -+ unsigned long max_rate; -+}; -+ -+struct clk_hfpll { -+ struct hfpll_data const *d; -+ int init_done; -+ -+ struct clk_regmap clkr; -+ spinlock_t lock; -+}; -+ -+#define to_clk_hfpll(_hw) \ -+ container_of(to_clk_regmap(_hw), struct clk_hfpll, clkr) -+ -+extern const struct clk_ops clk_ops_hfpll; -+ -+#endif diff --git a/target/linux/ipq806x/patches-3.18/138-clk-qcom-Add-HFPLL-driver.patch b/target/linux/ipq806x/patches-3.18/138-clk-qcom-Add-HFPLL-driver.patch deleted file mode 100644 index a0b1d64dc613..000000000000 --- a/target/linux/ipq806x/patches-3.18/138-clk-qcom-Add-HFPLL-driver.patch +++ /dev/null @@ -1,206 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,06/13] clk: qcom: Add HFPLL driver -From: Stephen Boyd -X-Patchwork-Id: 6063231 -Message-Id: <1426920332-9340-7-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar , -Date: Fri, 20 Mar 2015 23:45:25 -0700 - -On some devices (MSM8974 for example), the HFPLLs are -instantiated within the Krait processor subsystem as separate -register regions. Add a driver for these PLLs so that we can -provide HFPLL clocks for use by the system. - -Cc: -Signed-off-by: Stephen Boyd - ---- -.../devicetree/bindings/clock/qcom,hfpll.txt | 40 ++++++++ - drivers/clk/qcom/Kconfig | 8 ++ - drivers/clk/qcom/Makefile | 1 + - drivers/clk/qcom/hfpll.c | 109 +++++++++++++++++++++ - 4 files changed, 158 insertions(+) - create mode 100644 Documentation/devicetree/bindings/clock/qcom,hfpll.txt - create mode 100644 drivers/clk/qcom/hfpll.c - ---- /dev/null -+++ b/Documentation/devicetree/bindings/clock/qcom,hfpll.txt -@@ -0,0 +1,40 @@ -+High-Frequency PLL (HFPLL) -+ -+PROPERTIES -+ -+- compatible: -+ Usage: required -+ Value type: -+ Definition: must be "qcom,hfpll" -+ -+- reg: -+ Usage: required -+ Value type: -+ Definition: address and size of HPLL registers. An optional second -+ element specifies the address and size of the alias -+ register region. -+ -+- clock-output-names: -+ Usage: required -+ Value type: -+ Definition: Name of the PLL. Typically hfpllX where X is a CPU number -+ starting at 0. Otherwise hfpll_Y where Y is more specific -+ such as "l2". -+ -+Example: -+ -+1) An HFPLL for the L2 cache. -+ -+ clock-controller@f9016000 { -+ compatible = "qcom,hfpll"; -+ reg = <0xf9016000 0x30>; -+ clock-output-names = "hfpll_l2"; -+ }; -+ -+2) An HFPLL for CPU0. This HFPLL has the alias register region. -+ -+ clock-controller@f908a000 { -+ compatible = "qcom,hfpll"; -+ reg = <0xf908a000 0x30>, <0xf900a000 0x30>; -+ clock-output-names = "hfpll0"; -+ }; ---- a/drivers/clk/qcom/Kconfig -+++ b/drivers/clk/qcom/Kconfig -@@ -70,3 +70,11 @@ config MSM_MMCC_8974 - Support for the multimedia clock controller on msm8974 devices. - Say Y if you want to support multimedia devices such as display, - graphics, video encode/decode, camera, etc. -+ -+config QCOM_HFPLL -+ tristate "High-Frequency PLL (HFPLL) Clock Controller" -+ depends on COMMON_CLK_QCOM -+ help -+ Support for the high-frequency PLLs present on Qualcomm devices. -+ Say Y if you want to support CPU frequency scaling on devices -+ such as MSM8974, APQ8084, etc. ---- a/drivers/clk/qcom/Makefile -+++ b/drivers/clk/qcom/Makefile -@@ -17,3 +17,4 @@ obj-$(CONFIG_MSM_GCC_8960) += gcc-msm896 - obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o - obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o - obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o -+obj-$(CONFIG_QCOM_HFPLL) += hfpll.o ---- /dev/null -+++ b/drivers/clk/qcom/hfpll.c -@@ -0,0 +1,109 @@ -+/* -+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "clk-regmap.h" -+#include "clk-hfpll.h" -+ -+static const struct hfpll_data hdata = { -+ .mode_reg = 0x00, -+ .l_reg = 0x04, -+ .m_reg = 0x08, -+ .n_reg = 0x0c, -+ .user_reg = 0x10, -+ .config_reg = 0x14, -+ .config_val = 0x430405d, -+ .status_reg = 0x1c, -+ .lock_bit = 16, -+ -+ .user_val = 0x8, -+ .user_vco_mask = 0x100000, -+ .low_vco_max_rate = 1248000000, -+ .min_rate = 537600000UL, -+ .max_rate = 2900000000UL, -+}; -+ -+static const struct of_device_id qcom_hfpll_match_table[] = { -+ { .compatible = "qcom,hfpll" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table); -+ -+static const struct regmap_config hfpll_regmap_config = { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .max_register = 0x30, -+ .fast_io = true, -+}; -+ -+static int qcom_hfpll_probe(struct platform_device *pdev) -+{ -+ struct clk *clk; -+ struct resource *res; -+ struct device *dev = &pdev->dev; -+ void __iomem *base; -+ struct regmap *regmap; -+ struct clk_hfpll *h; -+ struct clk_init_data init = { -+ .parent_names = (const char *[]){ "xo" }, -+ .num_parents = 1, -+ .ops = &clk_ops_hfpll, -+ }; -+ -+ h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL); -+ if (!h) -+ return -ENOMEM; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ regmap = devm_regmap_init_mmio(&pdev->dev, base, &hfpll_regmap_config); -+ if (IS_ERR(regmap)) -+ return PTR_ERR(regmap); -+ -+ if (of_property_read_string_index(dev->of_node, "clock-output-names", -+ 0, &init.name)) -+ return -ENODEV; -+ -+ h->d = &hdata; -+ h->clkr.hw.init = &init; -+ spin_lock_init(&h->lock); -+ -+ clk = devm_clk_register_regmap(&pdev->dev, &h->clkr); -+ -+ return PTR_ERR_OR_ZERO(clk); -+} -+ -+static struct platform_driver qcom_hfpll_driver = { -+ .probe = qcom_hfpll_probe, -+ .driver = { -+ .name = "qcom-hfpll", -+ .of_match_table = qcom_hfpll_match_table, -+ }, -+}; -+module_platform_driver(qcom_hfpll_driver); -+ -+MODULE_DESCRIPTION("QCOM HFPLL Clock Driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:qcom-hfpll"); diff --git a/target/linux/ipq806x/patches-3.18/139-clk-qcom-Add-IPQ806X-s-HFPLLs.patch b/target/linux/ipq806x/patches-3.18/139-clk-qcom-Add-IPQ806X-s-HFPLLs.patch deleted file mode 100644 index 7fd53d1d9c18..000000000000 --- a/target/linux/ipq806x/patches-3.18/139-clk-qcom-Add-IPQ806X-s-HFPLLs.patch +++ /dev/null @@ -1,127 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,08/13] clk: qcom: Add IPQ806X's HFPLLs -From: Stephen Boyd -X-Patchwork-Id: 6063241 -Message-Id: <1426920332-9340-9-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar -Date: Fri, 20 Mar 2015 23:45:27 -0700 - -Describe the HFPLLs present on IPQ806X devices. - -Signed-off-by: Stephen Boyd - ---- -drivers/clk/qcom/gcc-ipq806x.c | 83 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 83 insertions(+) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -30,6 +30,7 @@ - #include "clk-pll.h" - #include "clk-rcg.h" - #include "clk-branch.h" -+#include "clk-hfpll.h" - #include "reset.h" - - static struct clk_pll pll0 = { -@@ -102,6 +103,85 @@ static struct clk_regmap pll8_vote = { - }, - }; - -+static struct hfpll_data hfpll0_data = { -+ .mode_reg = 0x3200, -+ .l_reg = 0x3208, -+ .m_reg = 0x320c, -+ .n_reg = 0x3210, -+ .config_reg = 0x3204, -+ .status_reg = 0x321c, -+ .config_val = 0x7845c665, -+ .droop_reg = 0x3214, -+ .droop_val = 0x0108c000, -+ .min_rate = 600000000UL, -+ .max_rate = 1800000000UL, -+}; -+ -+static struct clk_hfpll hfpll0 = { -+ .d = &hfpll0_data, -+ .clkr.hw.init = &(struct clk_init_data){ -+ .parent_names = (const char *[]){ "pxo" }, -+ .num_parents = 1, -+ .name = "hfpll0", -+ .ops = &clk_ops_hfpll, -+ .flags = CLK_IGNORE_UNUSED, -+ }, -+ .lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock), -+}; -+ -+static struct hfpll_data hfpll1_data = { -+ .mode_reg = 0x3240, -+ .l_reg = 0x3248, -+ .m_reg = 0x324c, -+ .n_reg = 0x3250, -+ .config_reg = 0x3244, -+ .status_reg = 0x325c, -+ .config_val = 0x7845c665, -+ .droop_reg = 0x3314, -+ .droop_val = 0x0108c000, -+ .min_rate = 600000000UL, -+ .max_rate = 1800000000UL, -+}; -+ -+static struct clk_hfpll hfpll1 = { -+ .d = &hfpll1_data, -+ .clkr.hw.init = &(struct clk_init_data){ -+ .parent_names = (const char *[]){ "pxo" }, -+ .num_parents = 1, -+ .name = "hfpll1", -+ .ops = &clk_ops_hfpll, -+ .flags = CLK_IGNORE_UNUSED, -+ }, -+ .lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock), -+}; -+ -+static struct hfpll_data hfpll_l2_data = { -+ .mode_reg = 0x3300, -+ .l_reg = 0x3308, -+ .m_reg = 0x330c, -+ .n_reg = 0x3310, -+ .config_reg = 0x3304, -+ .status_reg = 0x331c, -+ .config_val = 0x7845c665, -+ .droop_reg = 0x3314, -+ .droop_val = 0x0108c000, -+ .min_rate = 600000000UL, -+ .max_rate = 1800000000UL, -+}; -+ -+static struct clk_hfpll hfpll_l2 = { -+ .d = &hfpll_l2_data, -+ .clkr.hw.init = &(struct clk_init_data){ -+ .parent_names = (const char *[]){ "pxo" }, -+ .num_parents = 1, -+ .name = "hfpll_l2", -+ .ops = &clk_ops_hfpll, -+ .flags = CLK_IGNORE_UNUSED, -+ }, -+ .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock), -+}; -+ -+ - static struct clk_pll pll14 = { - .l_reg = 0x31c4, - .m_reg = 0x31c8, -@@ -2261,6 +2341,9 @@ static struct clk_regmap *gcc_ipq806x_cl - [USB_FS1_XCVR_SRC] = &usb_fs1_xcvr_clk_src.clkr, - [USB_FS1_XCVR_CLK] = &usb_fs1_xcvr_clk.clkr, - [USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr, -+ [PLL9] = &hfpll0.clkr, -+ [PLL10] = &hfpll1.clkr, -+ [PLL12] = &hfpll_l2.clkr, - }; - - static const struct qcom_reset_map gcc_ipq806x_resets[] = { diff --git a/target/linux/ipq806x/patches-3.18/140-clk-qcom-Add-support-for-Krait-clocks.patch b/target/linux/ipq806x/patches-3.18/140-clk-qcom-Add-support-for-Krait-clocks.patch deleted file mode 100644 index 63292e86114c..000000000000 --- a/target/linux/ipq806x/patches-3.18/140-clk-qcom-Add-support-for-Krait-clocks.patch +++ /dev/null @@ -1,271 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,09/13] clk: qcom: Add support for Krait clocks -From: Stephen Boyd -X-Patchwork-Id: 6063251 -Message-Id: <1426920332-9340-10-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar -Date: Fri, 20 Mar 2015 23:45:28 -0700 - -The Krait clocks are made up of a series of muxes and a divider -that choose between a fixed rate clock and dedicated HFPLLs for -each CPU. Instead of using mmio accesses to remux parents, the -Krait implementation exposes the remux control via cp15 -registers. Support these clocks. - -Signed-off-by: Stephen Boyd - ---- -drivers/clk/qcom/Kconfig | 4 ++ - drivers/clk/qcom/Makefile | 1 + - drivers/clk/qcom/clk-krait.c | 166 +++++++++++++++++++++++++++++++++++++++++++ - drivers/clk/qcom/clk-krait.h | 49 +++++++++++++ - 4 files changed, 220 insertions(+) - create mode 100644 drivers/clk/qcom/clk-krait.c - create mode 100644 drivers/clk/qcom/clk-krait.h - ---- a/drivers/clk/qcom/Kconfig -+++ b/drivers/clk/qcom/Kconfig -@@ -78,3 +78,7 @@ config QCOM_HFPLL - Support for the high-frequency PLLs present on Qualcomm devices. - Say Y if you want to support CPU frequency scaling on devices - such as MSM8974, APQ8084, etc. -+ -+config KRAIT_CLOCKS -+ bool -+ select KRAIT_L2_ACCESSORS ---- a/drivers/clk/qcom/Makefile -+++ b/drivers/clk/qcom/Makefile -@@ -6,6 +6,7 @@ clk-qcom-y += clk-pll.o - clk-qcom-y += clk-rcg.o - clk-qcom-y += clk-rcg2.o - clk-qcom-y += clk-branch.o -+clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o - clk-qcom-y += clk-hfpll.o - clk-qcom-y += reset.o - ---- /dev/null -+++ b/drivers/clk/qcom/clk-krait.c -@@ -0,0 +1,166 @@ -+/* -+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "clk-krait.h" -+ -+/* Secondary and primary muxes share the same cp15 register */ -+static DEFINE_SPINLOCK(krait_clock_reg_lock); -+ -+#define LPL_SHIFT 8 -+static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel) -+{ -+ unsigned long flags; -+ u32 regval; -+ -+ spin_lock_irqsave(&krait_clock_reg_lock, flags); -+ regval = krait_get_l2_indirect_reg(mux->offset); -+ regval &= ~(mux->mask << mux->shift); -+ regval |= (sel & mux->mask) << mux->shift; -+ if (mux->lpl) { -+ regval &= ~(mux->mask << (mux->shift + LPL_SHIFT)); -+ regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT); -+ } -+ krait_set_l2_indirect_reg(mux->offset, regval); -+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags); -+ -+ /* Wait for switch to complete. */ -+ mb(); -+ udelay(1); -+} -+ -+static int krait_mux_set_parent(struct clk_hw *hw, u8 index) -+{ -+ struct krait_mux_clk *mux = to_krait_mux_clk(hw); -+ u32 sel; -+ -+ sel = clk_mux_reindex(index, mux->parent_map, 0); -+ mux->en_mask = sel; -+ /* Don't touch mux if CPU is off as it won't work */ -+ if (__clk_is_enabled(hw->clk)) -+ __krait_mux_set_sel(mux, sel); -+ return 0; -+} -+ -+static u8 krait_mux_get_parent(struct clk_hw *hw) -+{ -+ struct krait_mux_clk *mux = to_krait_mux_clk(hw); -+ u32 sel; -+ -+ sel = krait_get_l2_indirect_reg(mux->offset); -+ sel >>= mux->shift; -+ sel &= mux->mask; -+ mux->en_mask = sel; -+ -+ return clk_mux_get_parent(hw, sel, mux->parent_map, 0); -+} -+ -+static struct clk_hw *krait_mux_get_safe_parent(struct clk_hw *hw) -+{ -+ int i; -+ struct krait_mux_clk *mux = to_krait_mux_clk(hw); -+ int num_parents = __clk_get_num_parents(hw->clk); -+ -+ i = mux->safe_sel; -+ for (i = 0; i < num_parents; i++) -+ if (mux->safe_sel == mux->parent_map[i]) -+ break; -+ -+ return __clk_get_hw(clk_get_parent_by_index(hw->clk, i)); -+} -+ -+static int krait_mux_enable(struct clk_hw *hw) -+{ -+ struct krait_mux_clk *mux = to_krait_mux_clk(hw); -+ -+ __krait_mux_set_sel(mux, mux->en_mask); -+ -+ return 0; -+} -+ -+static void krait_mux_disable(struct clk_hw *hw) -+{ -+ struct krait_mux_clk *mux = to_krait_mux_clk(hw); -+ -+ __krait_mux_set_sel(mux, mux->safe_sel); -+} -+ -+const struct clk_ops krait_mux_clk_ops = { -+ .enable = krait_mux_enable, -+ .disable = krait_mux_disable, -+ .set_parent = krait_mux_set_parent, -+ .get_parent = krait_mux_get_parent, -+ .determine_rate = __clk_mux_determine_rate_closest, -+ .get_safe_parent = krait_mux_get_safe_parent, -+}; -+EXPORT_SYMBOL_GPL(krait_mux_clk_ops); -+ -+/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */ -+static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *parent_rate) -+{ -+ *parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), rate * 2); -+ return DIV_ROUND_UP(*parent_rate, 2); -+} -+ -+static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct krait_div2_clk *d = to_krait_div2_clk(hw); -+ unsigned long flags; -+ u32 val; -+ u32 mask = BIT(d->width) - 1; -+ -+ if (d->lpl) -+ mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift; -+ -+ spin_lock_irqsave(&krait_clock_reg_lock, flags); -+ val = krait_get_l2_indirect_reg(d->offset); -+ val &= ~mask; -+ krait_set_l2_indirect_reg(d->offset, val); -+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags); -+ -+ return 0; -+} -+ -+static unsigned long -+krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) -+{ -+ struct krait_div2_clk *d = to_krait_div2_clk(hw); -+ u32 mask = BIT(d->width) - 1; -+ u32 div; -+ -+ div = krait_get_l2_indirect_reg(d->offset); -+ div >>= d->shift; -+ div &= mask; -+ div = (div + 1) * 2; -+ -+ return DIV_ROUND_UP(parent_rate, div); -+} -+ -+const struct clk_ops krait_div2_clk_ops = { -+ .round_rate = krait_div2_round_rate, -+ .set_rate = krait_div2_set_rate, -+ .recalc_rate = krait_div2_recalc_rate, -+}; -+EXPORT_SYMBOL_GPL(krait_div2_clk_ops); ---- /dev/null -+++ b/drivers/clk/qcom/clk-krait.h -@@ -0,0 +1,49 @@ -+/* -+ * Copyright (c) 2013, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#ifndef __QCOM_CLK_KRAIT_H -+#define __QCOM_CLK_KRAIT_H -+ -+#include -+ -+struct krait_mux_clk { -+ unsigned int *parent_map; -+ bool has_safe_parent; -+ u8 safe_sel; -+ u32 offset; -+ u32 mask; -+ u32 shift; -+ u32 en_mask; -+ bool lpl; -+ -+ struct clk_hw hw; -+}; -+ -+#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw) -+ -+extern const struct clk_ops krait_mux_clk_ops; -+ -+struct krait_div2_clk { -+ u32 offset; -+ u8 width; -+ u32 shift; -+ bool lpl; -+ -+ struct clk_hw hw; -+}; -+ -+#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw) -+ -+extern const struct clk_ops krait_div2_clk_ops; -+ -+#endif diff --git a/target/linux/ipq806x/patches-3.18/141-clk-qcom-Add-KPSS-ACC-GCC-driver.patch b/target/linux/ipq806x/patches-3.18/141-clk-qcom-Add-KPSS-ACC-GCC-driver.patch deleted file mode 100644 index 06b14d8b5332..000000000000 --- a/target/linux/ipq806x/patches-3.18/141-clk-qcom-Add-KPSS-ACC-GCC-driver.patch +++ /dev/null @@ -1,205 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,10/13] clk: qcom: Add KPSS ACC/GCC driver -From: Stephen Boyd -X-Patchwork-Id: 6063201 -Message-Id: <1426920332-9340-11-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar , -Date: Fri, 20 Mar 2015 23:45:29 -0700 - -The ACC and GCC regions present in KPSSv1 contain registers to -control clocks and power to each Krait CPU and L2. For CPUfreq -purposes probe these devices and expose a mux clock that chooses -between PXO and PLL8. - -Cc: -Signed-off-by: Stephen Boyd - ---- -.../devicetree/bindings/arm/msm/qcom,kpss-acc.txt | 7 ++ - .../devicetree/bindings/arm/msm/qcom,kpss-gcc.txt | 28 +++++++ - drivers/clk/qcom/Kconfig | 8 ++ - drivers/clk/qcom/Makefile | 1 + - drivers/clk/qcom/kpss-xcc.c | 95 ++++++++++++++++++++++ - 5 files changed, 139 insertions(+) - create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt - create mode 100644 drivers/clk/qcom/kpss-xcc.c - ---- a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt -+++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt -@@ -21,10 +21,17 @@ PROPERTIES - the register region. An optional second element specifies - the base address and size of the alias register region. - -+- clock-output-names: -+ Usage: optional -+ Value type: -+ Definition: Name of the output clock. Typically acpuX_aux where X is a -+ CPU number starting at 0. -+ - Example: - - clock-controller@2088000 { - compatible = "qcom,kpss-acc-v2"; - reg = <0x02088000 0x1000>, - <0x02008000 0x1000>; -+ clock-output-names = "acpu0_aux"; - }; ---- /dev/null -+++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt -@@ -0,0 +1,28 @@ -+Krait Processor Sub-system (KPSS) Global Clock Controller (GCC) -+ -+PROPERTIES -+ -+- compatible: -+ Usage: required -+ Value type: -+ Definition: should be one of: -+ "qcom,kpss-gcc" -+ -+- reg: -+ Usage: required -+ Value type: -+ Definition: base address and size of the register region -+ -+- clock-output-names: -+ Usage: required -+ Value type: -+ Definition: Name of the output clock. Typically acpu_l2_aux indicating -+ an L2 cache auxiliary clock. -+ -+Example: -+ -+ l2cc: clock-controller@2011000 { -+ compatible = "qcom,kpss-gcc"; -+ reg = <0x2011000 0x1000>; -+ clock-output-names = "acpu_l2_aux"; -+ }; ---- a/drivers/clk/qcom/Kconfig -+++ b/drivers/clk/qcom/Kconfig -@@ -79,6 +79,14 @@ config QCOM_HFPLL - Say Y if you want to support CPU frequency scaling on devices - such as MSM8974, APQ8084, etc. - -+config KPSS_XCC -+ tristate "KPSS Clock Controller" -+ depends on COMMON_CLK_QCOM -+ help -+ Support for the Krait ACC and GCC clock controllers. Say Y -+ if you want to support CPU frequency scaling on devices such -+ as MSM8960, APQ8064, etc. -+ - config KRAIT_CLOCKS - bool - select KRAIT_L2_ACCESSORS ---- a/drivers/clk/qcom/Makefile -+++ b/drivers/clk/qcom/Makefile -@@ -18,4 +18,5 @@ obj-$(CONFIG_MSM_GCC_8960) += gcc-msm896 - obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o - obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o - obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o -+obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o - obj-$(CONFIG_QCOM_HFPLL) += hfpll.o ---- /dev/null -+++ b/drivers/clk/qcom/kpss-xcc.c -@@ -0,0 +1,95 @@ -+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static const char *aux_parents[] = { -+ "pll8_vote", -+ "pxo", -+}; -+ -+static unsigned int aux_parent_map[] = { -+ 3, -+ 0, -+}; -+ -+static const struct of_device_id kpss_xcc_match_table[] = { -+ { .compatible = "qcom,kpss-acc-v1", .data = (void *)1UL }, -+ { .compatible = "qcom,kpss-gcc" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, kpss_xcc_match_table); -+ -+static int kpss_xcc_driver_probe(struct platform_device *pdev) -+{ -+ const struct of_device_id *id; -+ struct clk *clk; -+ struct resource *res; -+ void __iomem *base; -+ const char *name; -+ -+ id = of_match_device(kpss_xcc_match_table, &pdev->dev); -+ if (!id) -+ return -ENODEV; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ if (id->data) { -+ if (of_property_read_string_index(pdev->dev.of_node, -+ "clock-output-names", 0, &name)) -+ return -ENODEV; -+ base += 0x14; -+ } else { -+ name = "acpu_l2_aux"; -+ base += 0x28; -+ } -+ -+ clk = clk_register_mux_table(&pdev->dev, name, aux_parents, -+ ARRAY_SIZE(aux_parents), 0, base, 0, 0x3, -+ 0, aux_parent_map, NULL); -+ -+ platform_set_drvdata(pdev, clk); -+ -+ return PTR_ERR_OR_ZERO(clk); -+} -+ -+static int kpss_xcc_driver_remove(struct platform_device *pdev) -+{ -+ clk_unregister_mux(platform_get_drvdata(pdev)); -+ return 0; -+} -+ -+static struct platform_driver kpss_xcc_driver = { -+ .probe = kpss_xcc_driver_probe, -+ .remove = kpss_xcc_driver_remove, -+ .driver = { -+ .name = "kpss-xcc", -+ .of_match_table = kpss_xcc_match_table, -+ }, -+}; -+module_platform_driver(kpss_xcc_driver); -+ -+MODULE_DESCRIPTION("Krait Processor Sub System (KPSS) Clock Driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:kpss-xcc"); diff --git a/target/linux/ipq806x/patches-3.18/142-clk-qcom-Add-Krait-clock-controller-driver.patch b/target/linux/ipq806x/patches-3.18/142-clk-qcom-Add-Krait-clock-controller-driver.patch deleted file mode 100644 index 98a09ac08e45..000000000000 --- a/target/linux/ipq806x/patches-3.18/142-clk-qcom-Add-Krait-clock-controller-driver.patch +++ /dev/null @@ -1,435 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,11/13] clk: qcom: Add Krait clock controller driver -From: Stephen Boyd -X-Patchwork-Id: 6063121 -Message-Id: <1426920332-9340-12-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar , -Date: Fri, 20 Mar 2015 23:45:30 -0700 - -The Krait CPU clocks are made up of a primary mux and secondary -mux for each CPU and the L2, controlled via cp15 accessors. For -Kraits within KPSSv1 each secondary mux accepts a different aux -source, but on KPSSv2 each secondary mux accepts the same aux -source. - -Cc: -Signed-off-by: Stephen Boyd - ---- -.../devicetree/bindings/clock/qcom,krait-cc.txt | 22 ++ - drivers/clk/qcom/Kconfig | 8 + - drivers/clk/qcom/Makefile | 1 + - drivers/clk/qcom/krait-cc.c | 352 +++++++++++++++++++++ - 4 files changed, 383 insertions(+) - create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt - create mode 100644 drivers/clk/qcom/krait-cc.c - ---- /dev/null -+++ b/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt -@@ -0,0 +1,22 @@ -+Krait Clock Controller -+ -+PROPERTIES -+ -+- compatible: -+ Usage: required -+ Value type: -+ Definition: must be one of: -+ "qcom,krait-cc-v1" -+ "qcom,krait-cc-v2" -+ -+- #clock-cells: -+ Usage: required -+ Value type: -+ Definition: must be 1 -+ -+Example: -+ -+ kraitcc: clock-controller { -+ compatible = "qcom,krait-cc-v1"; -+ #clock-cells = <1>; -+ }; ---- a/drivers/clk/qcom/Kconfig -+++ b/drivers/clk/qcom/Kconfig -@@ -87,6 +87,14 @@ config KPSS_XCC - if you want to support CPU frequency scaling on devices such - as MSM8960, APQ8064, etc. - -+config KRAITCC -+ tristate "Krait Clock Controller" -+ depends on COMMON_CLK_QCOM && ARM -+ select KRAIT_CLOCKS -+ help -+ Support for the Krait CPU clocks on Qualcomm devices. -+ Say Y if you want to support CPU frequency scaling. -+ - config KRAIT_CLOCKS - bool - select KRAIT_L2_ACCESSORS ---- a/drivers/clk/qcom/Makefile -+++ b/drivers/clk/qcom/Makefile -@@ -20,3 +20,4 @@ obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8 - obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o - obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o - obj-$(CONFIG_QCOM_HFPLL) += hfpll.o -+obj-$(CONFIG_KRAITCC) += krait-cc.o ---- /dev/null -+++ b/drivers/clk/qcom/krait-cc.c -@@ -0,0 +1,352 @@ -+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "clk-krait.h" -+ -+static unsigned int sec_mux_map[] = { -+ 2, -+ 0, -+}; -+ -+static unsigned int pri_mux_map[] = { -+ 1, -+ 2, -+ 0, -+}; -+ -+static int -+krait_add_div(struct device *dev, int id, const char *s, unsigned offset) -+{ -+ struct krait_div2_clk *div; -+ struct clk_init_data init = { -+ .num_parents = 1, -+ .ops = &krait_div2_clk_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }; -+ const char *p_names[1]; -+ struct clk *clk; -+ -+ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); -+ if (!div) -+ return -ENOMEM; -+ -+ div->width = 2; -+ div->shift = 6; -+ div->lpl = id >= 0; -+ div->offset = offset; -+ div->hw.init = &init; -+ -+ init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s); -+ if (!init.name) -+ return -ENOMEM; -+ -+ init.parent_names = p_names; -+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s); -+ if (!p_names[0]) { -+ kfree(init.name); -+ return -ENOMEM; -+ } -+ -+ clk = devm_clk_register(dev, &div->hw); -+ kfree(p_names[0]); -+ kfree(init.name); -+ -+ return PTR_ERR_OR_ZERO(clk); -+} -+ -+static int -+krait_add_sec_mux(struct device *dev, int id, const char *s, unsigned offset, -+ bool unique_aux) -+{ -+ struct krait_mux_clk *mux; -+ static const char *sec_mux_list[] = { -+ "acpu_aux", -+ "qsb", -+ }; -+ struct clk_init_data init = { -+ .parent_names = sec_mux_list, -+ .num_parents = ARRAY_SIZE(sec_mux_list), -+ .ops = &krait_mux_clk_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }; -+ struct clk *clk; -+ -+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); -+ if (!mux) -+ return -ENOMEM; -+ -+ mux->offset = offset; -+ mux->lpl = id >= 0; -+ mux->has_safe_parent = true; -+ mux->safe_sel = 2; -+ mux->mask = 0x3; -+ mux->shift = 2; -+ mux->parent_map = sec_mux_map; -+ mux->hw.init = &init; -+ -+ init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); -+ if (!init.name) -+ return -ENOMEM; -+ -+ if (unique_aux) { -+ sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s); -+ if (!sec_mux_list[0]) { -+ clk = ERR_PTR(-ENOMEM); -+ goto err_aux; -+ } -+ } -+ -+ clk = devm_clk_register(dev, &mux->hw); -+ -+ if (unique_aux) -+ kfree(sec_mux_list[0]); -+err_aux: -+ kfree(init.name); -+ return PTR_ERR_OR_ZERO(clk); -+} -+ -+static struct clk * -+krait_add_pri_mux(struct device *dev, int id, const char *s, unsigned offset) -+{ -+ struct krait_mux_clk *mux; -+ const char *p_names[3]; -+ struct clk_init_data init = { -+ .parent_names = p_names, -+ .num_parents = ARRAY_SIZE(p_names), -+ .ops = &krait_mux_clk_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }; -+ struct clk *clk; -+ -+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); -+ if (!mux) -+ return ERR_PTR(-ENOMEM); -+ -+ mux->has_safe_parent = true; -+ mux->safe_sel = 0; -+ mux->mask = 0x3; -+ mux->shift = 0; -+ mux->offset = offset; -+ mux->lpl = id >= 0; -+ mux->parent_map = pri_mux_map; -+ mux->hw.init = &init; -+ -+ init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s); -+ if (!init.name) -+ return ERR_PTR(-ENOMEM); -+ -+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s); -+ if (!p_names[0]) { -+ clk = ERR_PTR(-ENOMEM); -+ goto err_p0; -+ } -+ -+ p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s); -+ if (!p_names[1]) { -+ clk = ERR_PTR(-ENOMEM); -+ goto err_p1; -+ } -+ -+ p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); -+ if (!p_names[2]) { -+ clk = ERR_PTR(-ENOMEM); -+ goto err_p2; -+ } -+ -+ clk = devm_clk_register(dev, &mux->hw); -+ -+ kfree(p_names[2]); -+err_p2: -+ kfree(p_names[1]); -+err_p1: -+ kfree(p_names[0]); -+err_p0: -+ kfree(init.name); -+ return clk; -+} -+ -+/* id < 0 for L2, otherwise id == physical CPU number */ -+static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux) -+{ -+ int ret; -+ unsigned offset; -+ void *p = NULL; -+ const char *s; -+ struct clk *clk; -+ -+ if (id >= 0) { -+ offset = 0x4501 + (0x1000 * id); -+ s = p = kasprintf(GFP_KERNEL, "%d", id); -+ if (!s) -+ return ERR_PTR(-ENOMEM); -+ } else { -+ offset = 0x500; -+ s = "_l2"; -+ } -+ -+ ret = krait_add_div(dev, id, s, offset); -+ if (ret) { -+ clk = ERR_PTR(ret); -+ goto err; -+ } -+ -+ ret = krait_add_sec_mux(dev, id, s, offset, unique_aux); -+ if (ret) { -+ clk = ERR_PTR(ret); -+ goto err; -+ } -+ -+ clk = krait_add_pri_mux(dev, id, s, offset); -+err: -+ kfree(p); -+ return clk; -+} -+ -+static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data) -+{ -+ unsigned int idx = clkspec->args[0]; -+ struct clk **clks = data; -+ -+ if (idx >= 5) { -+ pr_err("%s: invalid clock index %d\n", __func__, idx); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ return clks[idx] ? : ERR_PTR(-ENODEV); -+} -+ -+static const struct of_device_id krait_cc_match_table[] = { -+ { .compatible = "qcom,krait-cc-v1", (void *)1UL }, -+ { .compatible = "qcom,krait-cc-v2" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, krait_cc_match_table); -+ -+static int krait_cc_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ const struct of_device_id *id; -+ unsigned long cur_rate, aux_rate; -+ int cpu; -+ struct clk *clk; -+ struct clk **clks; -+ struct clk *l2_pri_mux_clk; -+ -+ id = of_match_device(krait_cc_match_table, dev); -+ if (!id) -+ return -ENODEV; -+ -+ /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */ -+ clk = clk_register_fixed_rate(dev, "qsb", NULL, CLK_IS_ROOT, 1); -+ if (IS_ERR(clk)) -+ return PTR_ERR(clk); -+ -+ if (!id->data) { -+ clk = clk_register_fixed_factor(dev, "acpu_aux", -+ "gpll0_vote", 0, 1, 2); -+ if (IS_ERR(clk)) -+ return PTR_ERR(clk); -+ } -+ -+ /* Krait configurations have at most 4 CPUs and one L2 */ -+ clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL); -+ if (!clks) -+ return -ENOMEM; -+ -+ for_each_possible_cpu(cpu) { -+ clk = krait_add_clks(dev, cpu, id->data); -+ if (IS_ERR(clk)) -+ return PTR_ERR(clk); -+ clks[cpu] = clk; -+ } -+ -+ l2_pri_mux_clk = krait_add_clks(dev, -1, id->data); -+ if (IS_ERR(l2_pri_mux_clk)) -+ return PTR_ERR(l2_pri_mux_clk); -+ clks[4] = l2_pri_mux_clk; -+ -+ /* -+ * We don't want the CPU or L2 clocks to be turned off at late init -+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the -+ * refcount of these clocks. Any cpufreq/hotplug manager can assume -+ * that the clocks have already been prepared and enabled by the time -+ * they take over. -+ */ -+ for_each_online_cpu(cpu) { -+ clk_prepare_enable(l2_pri_mux_clk); -+ WARN(clk_prepare_enable(clks[cpu]), -+ "Unable to turn on CPU%d clock", cpu); -+ } -+ -+ /* -+ * Force reinit of HFPLLs and muxes to overwrite any potential -+ * incorrect configuration of HFPLLs and muxes by the bootloader. -+ * While at it, also make sure the cores are running at known rates -+ * and print the current rate. -+ * -+ * The clocks are set to aux clock rate first to make sure the -+ * secondary mux is not sourcing off of QSB. The rate is then set to -+ * two different rates to force a HFPLL reinit under all -+ * circumstances. -+ */ -+ cur_rate = clk_get_rate(l2_pri_mux_clk); -+ aux_rate = 384000000; -+ if (cur_rate == 1) { -+ pr_info("L2 @ QSB rate. Forcing new rate.\n"); -+ cur_rate = aux_rate; -+ } -+ clk_set_rate(l2_pri_mux_clk, aux_rate); -+ clk_set_rate(l2_pri_mux_clk, 2); -+ clk_set_rate(l2_pri_mux_clk, cur_rate); -+ pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000); -+ for_each_possible_cpu(cpu) { -+ clk = clks[cpu]; -+ cur_rate = clk_get_rate(clk); -+ if (cur_rate == 1) { -+ pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu); -+ cur_rate = aux_rate; -+ } -+ clk_set_rate(clk, aux_rate); -+ clk_set_rate(clk, 2); -+ clk_set_rate(clk, cur_rate); -+ pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000); -+ } -+ -+ of_clk_add_provider(dev->of_node, krait_of_get, clks); -+ -+ return 0; -+} -+ -+static struct platform_driver krait_cc_driver = { -+ .probe = krait_cc_probe, -+ .driver = { -+ .name = "krait-cc", -+ .of_match_table = krait_cc_match_table, -+ }, -+}; -+module_platform_driver(krait_cc_driver); -+ -+MODULE_DESCRIPTION("Krait CPU Clock Driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:krait-cc"); diff --git a/target/linux/ipq806x/patches-3.18/143-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch b/target/linux/ipq806x/patches-3.18/143-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch deleted file mode 100644 index c3ca9b5f7049..000000000000 --- a/target/linux/ipq806x/patches-3.18/143-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch +++ /dev/null @@ -1,304 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,12/13] cpufreq: Add module to register cpufreq on Krait CPUs -From: Stephen Boyd -X-Patchwork-Id: 6063191 -Message-Id: <1426920332-9340-13-git-send-email-sboyd@codeaurora.org> -To: Mike Turquette , Stephen Boyd -Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - Viresh Kumar , -Date: Fri, 20 Mar 2015 23:45:31 -0700 - -Register a cpufreq-generic device whenever we detect that a -"qcom,krait" compatible CPU is present in DT. - -Cc: -Signed-off-by: Stephen Boyd - ---- -.../devicetree/bindings/arm/msm/qcom,pvs.txt | 38 ++++ - drivers/cpufreq/Kconfig.arm | 9 + - drivers/cpufreq/Makefile | 1 + - drivers/cpufreq/qcom-cpufreq.c | 204 +++++++++++++++++++++ - 4 files changed, 252 insertions(+) - create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt - create mode 100644 drivers/cpufreq/qcom-cpufreq.c - ---- /dev/null -+++ b/Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt -@@ -0,0 +1,38 @@ -+Qualcomm Process Voltage Scaling Tables -+ -+The node name is required to be "qcom,pvs". There shall only be one -+such node present in the root of the tree. -+ -+PROPERTIES -+ -+- qcom,pvs-format-a or qcom,pvs-format-b: -+ Usage: required -+ Value type: -+ Definition: Indicates the format of qcom,speedX-pvsY-bin-vZ properties. -+ If qcom,pvs-format-a is used the table is two columns -+ (frequency and voltage in that order). If qcom,pvs-format-b is used the table is three columns (frequency, voltage, -+ and current in that order). -+ -+- qcom,speedX-pvsY-bin-vZ: -+ Usage: required -+ Value type: -+ Definition: The PVS table corresponding to the speed bin X, pvs bin Y, -+ and version Z. -+Example: -+ -+ qcom,pvs { -+ qcom,pvs-format-a; -+ qcom,speed0-pvs0-bin-v0 = -+ < 384000000 950000 >, -+ < 486000000 975000 >, -+ < 594000000 1000000 >, -+ < 702000000 1025000 >, -+ < 810000000 1075000 >, -+ < 918000000 1100000 >, -+ < 1026000000 1125000 >, -+ < 1134000000 1175000 >, -+ < 1242000000 1200000 >, -+ < 1350000000 1225000 >, -+ < 1458000000 1237500 >, -+ < 1512000000 1250000 >; -+ }; ---- a/drivers/cpufreq/Kconfig.arm -+++ b/drivers/cpufreq/Kconfig.arm -@@ -129,6 +129,15 @@ config ARM_OMAP2PLUS_CPUFREQ - depends on ARCH_OMAP2PLUS - default ARCH_OMAP2PLUS - -+config ARM_QCOM_CPUFREQ -+ tristate "Qualcomm based" -+ depends on ARCH_QCOM -+ select PM_OPP -+ help -+ This adds the CPUFreq driver for Qualcomm SoC based boards. -+ -+ If in doubt, say N. -+ - config ARM_S3C_CPUFREQ - bool - help ---- a/drivers/cpufreq/Makefile -+++ b/drivers/cpufreq/Makefile -@@ -64,6 +64,7 @@ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += o - obj-$(CONFIG_PXA25x) += pxa2xx-cpufreq.o - obj-$(CONFIG_PXA27x) += pxa2xx-cpufreq.o - obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o -+obj-$(CONFIG_ARM_QCOM_CPUFREQ) += qcom-cpufreq.o - obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o - obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o - obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o ---- /dev/null -+++ b/drivers/cpufreq/qcom-cpufreq.c -@@ -0,0 +1,204 @@ -+/* Copyright (c) 2014, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static void __init get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver) -+{ -+ void __iomem *base; -+ u32 pte_efuse; -+ -+ *speed = *pvs = *pvs_ver = 0; -+ -+ base = ioremap(0x007000c0, 4); -+ if (!base) { -+ pr_warn("Unable to read efuse data. Defaulting to 0!\n"); -+ return; -+ } -+ -+ pte_efuse = readl_relaxed(base); -+ iounmap(base); -+ -+ *speed = pte_efuse & 0xf; -+ if (*speed == 0xf) -+ *speed = (pte_efuse >> 4) & 0xf; -+ -+ if (*speed == 0xf) { -+ *speed = 0; -+ pr_warn("Speed bin: Defaulting to %d\n", *speed); -+ } else { -+ pr_info("Speed bin: %d\n", *speed); -+ } -+ -+ *pvs = (pte_efuse >> 10) & 0x7; -+ if (*pvs == 0x7) -+ *pvs = (pte_efuse >> 13) & 0x7; -+ -+ if (*pvs == 0x7) { -+ *pvs = 0; -+ pr_warn("PVS bin: Defaulting to %d\n", *pvs); -+ } else { -+ pr_info("PVS bin: %d\n", *pvs); -+ } -+} -+ -+static void __init get_krait_bin_format_b(int *speed, int *pvs, int *pvs_ver) -+{ -+ u32 pte_efuse, redundant_sel; -+ void __iomem *base; -+ -+ *speed = 0; -+ *pvs = 0; -+ *pvs_ver = 0; -+ -+ base = ioremap(0xfc4b80b0, 8); -+ if (!base) { -+ pr_warn("Unable to read efuse data. Defaulting to 0!\n"); -+ return; -+ } -+ -+ pte_efuse = readl_relaxed(base); -+ redundant_sel = (pte_efuse >> 24) & 0x7; -+ *speed = pte_efuse & 0x7; -+ /* 4 bits of PVS are in efuse register bits 31, 8-6. */ -+ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7); -+ *pvs_ver = (pte_efuse >> 4) & 0x3; -+ -+ switch (redundant_sel) { -+ case 1: -+ *speed = (pte_efuse >> 27) & 0xf; -+ break; -+ case 2: -+ *pvs = (pte_efuse >> 27) & 0xf; -+ break; -+ } -+ -+ /* Check SPEED_BIN_BLOW_STATUS */ -+ if (pte_efuse & BIT(3)) { -+ pr_info("Speed bin: %d\n", *speed); -+ } else { -+ pr_warn("Speed bin not set. Defaulting to 0!\n"); -+ *speed = 0; -+ } -+ -+ /* Check PVS_BLOW_STATUS */ -+ pte_efuse = readl_relaxed(base + 0x4) & BIT(21); -+ if (pte_efuse) { -+ pr_info("PVS bin: %d\n", *pvs); -+ } else { -+ pr_warn("PVS bin not set. Defaulting to 0!\n"); -+ *pvs = 0; -+ } -+ -+ pr_info("PVS version: %d\n", *pvs_ver); -+ iounmap(base); -+} -+ -+static int __init qcom_cpufreq_populate_opps(void) -+{ -+ int len, rows, cols, i, k, speed, pvs, pvs_ver; -+ char table_name[] = "qcom,speedXX-pvsXX-bin-vXX"; -+ struct device_node *np; -+ struct device *dev; -+ int cpu = 0; -+ -+ np = of_find_node_by_name(NULL, "qcom,pvs"); -+ if (!np) -+ return -ENODEV; -+ -+ if (of_property_read_bool(np, "qcom,pvs-format-a")) { -+ get_krait_bin_format_a(&speed, &pvs, &pvs_ver); -+ cols = 2; -+ } else if (of_property_read_bool(np, "qcom,pvs-format-b")) { -+ get_krait_bin_format_b(&speed, &pvs, &pvs_ver); -+ cols = 3; -+ } else { -+ return -ENODEV; -+ } -+ -+ snprintf(table_name, sizeof(table_name), -+ "qcom,speed%d-pvs%d-bin-v%d", speed, pvs, pvs_ver); -+ -+ if (!of_find_property(np, table_name, &len)) -+ return -EINVAL; -+ -+ len /= sizeof(u32); -+ if (len % cols || len == 0) -+ return -EINVAL; -+ -+ rows = len / cols; -+ -+ for (i = 0, k = 0; i < rows; i++) { -+ u32 freq, volt; -+ -+ of_property_read_u32_index(np, table_name, k++, &freq); -+ of_property_read_u32_index(np, table_name, k++, &volt); -+ while (k % cols) -+ k++; /* Skip uA entries if present */ -+ for (cpu = 0; cpu < num_possible_cpus(); cpu++) { -+ dev = get_cpu_device(cpu); -+ if (!dev) -+ return -ENODEV; -+ if (dev_pm_opp_add(dev, freq, volt)) -+ pr_warn("failed to add OPP %u\n", freq); -+ } -+ } -+ -+ return 0; -+} -+ -+static int __init qcom_cpufreq_driver_init(void) -+{ -+ struct cpufreq_dt_platform_data pdata = { .independent_clocks = true }; -+ struct platform_device_info devinfo = { -+ .name = "cpufreq-dt", -+ .data = &pdata, -+ .size_data = sizeof(pdata), -+ }; -+ struct device *cpu_dev; -+ struct device_node *np; -+ int ret; -+ -+ cpu_dev = get_cpu_device(0); -+ if (!cpu_dev) -+ return -ENODEV; -+ -+ np = of_node_get(cpu_dev->of_node); -+ if (!np) -+ return -ENOENT; -+ -+ if (!of_device_is_compatible(np, "qcom,krait")) { -+ of_node_put(np); -+ return -ENODEV; -+ } -+ of_node_put(np); -+ -+ ret = qcom_cpufreq_populate_opps(); -+ if (ret) -+ return ret; -+ -+ return PTR_ERR_OR_ZERO(platform_device_register_full(&devinfo)); -+} -+module_init(qcom_cpufreq_driver_init); -+ -+MODULE_DESCRIPTION("Qualcomm CPUfreq driver"); -+MODULE_LICENSE("GPL v2"); diff --git a/target/linux/ipq806x/patches-3.18/144-ARM-dts-qcom-Add-necessary-DT-data-for-Krait-cpufreq.patch b/target/linux/ipq806x/patches-3.18/144-ARM-dts-qcom-Add-necessary-DT-data-for-Krait-cpufreq.patch deleted file mode 100644 index c398487ae599..000000000000 --- a/target/linux/ipq806x/patches-3.18/144-ARM-dts-qcom-Add-necessary-DT-data-for-Krait-cpufreq.patch +++ /dev/null @@ -1,100 +0,0 @@ ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -25,6 +25,11 @@ - next-level-cache = <&L2>; - qcom,acc = <&acc0>; - qcom,saw = <&saw0>; -+ clocks = <&kraitcc 0>; -+ clock-names = "cpu"; -+ clock-latency = <100000>; -+ core-supply = <&smb208_s2a>; -+ voltage-tolerance = <5>; - }; - - cpu@1 { -@@ -35,11 +40,24 @@ - next-level-cache = <&L2>; - qcom,acc = <&acc1>; - qcom,saw = <&saw1>; -+ clocks = <&kraitcc 1>; -+ clock-names = "cpu"; -+ clock-latency = <100000>; -+ core-supply = <&smb208_s2b>; - }; - - L2: l2-cache { - compatible = "cache"; - cache-level = <2>; -+ clocks = <&kraitcc 4>; -+ clock-names = "cache"; -+ cache-points-kHz = < -+ /* kHz uV CPU kHz */ -+ 1200000 1150000 1200000 -+ 1000000 1100000 600000 -+ 384000 1100000 384000 -+ >; -+ vdd_dig-supply = <&smb208_s1a>; - }; - }; - -@@ -72,6 +90,46 @@ - }; - }; - -+ kraitcc: clock-controller { -+ compatible = "qcom,krait-cc-v1"; -+ #clock-cells = <1>; -+ }; -+ -+ qcom,pvs { -+ qcom,pvs-format-a; -+ qcom,speed0-pvs0-bin-v0 = -+ < 1400000000 1250000 >, -+ < 1200000000 1200000 >, -+ < 1000000000 1150000 >, -+ < 800000000 1100000 >, -+ < 600000000 1050000 >, -+ < 384000000 1000000 >; -+ -+ qcom,speed0-pvs1-bin-v0 = -+ < 1400000000 1175000 >, -+ < 1200000000 1125000 >, -+ < 1000000000 1075000 >, -+ < 800000000 1025000 >, -+ < 600000000 975000 >, -+ < 384000000 925000 >; -+ -+ qcom,speed0-pvs2-bin-v0 = -+ < 1400000000 1125000 >, -+ < 1200000000 1075000 >, -+ < 1000000000 1025000 >, -+ < 800000000 995000 >, -+ < 600000000 925000 >, -+ < 384000000 875000 >; -+ -+ qcom,speed0-pvs3-bin-v0 = -+ < 1400000000 1050000 >, -+ < 1200000000 1000000 >, -+ < 1000000000 950000 >, -+ < 800000000 900000 >, -+ < 600000000 850000 >, -+ < 384000000 800000 >; -+ }; -+ - soc: soc { - #address-cells = <1>; - #size-cells = <1>; -@@ -199,11 +257,13 @@ - acc0: clock-controller@2088000 { - compatible = "qcom,kpss-acc-v1"; - reg = <0x02088000 0x1000>, <0x02008000 0x1000>; -+ clock-output-names = "acpu0_aux"; - }; - - acc1: clock-controller@2098000 { - compatible = "qcom,kpss-acc-v1"; - reg = <0x02098000 0x1000>, <0x02008000 0x1000>; -+ clock-output-names = "acpu1_aux"; - }; - - l2cc: clock-controller@2011000 { diff --git a/target/linux/ipq806x/patches-3.18/145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch b/target/linux/ipq806x/patches-3.18/145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch deleted file mode 100644 index 6052b417ac7a..000000000000 --- a/target/linux/ipq806x/patches-3.18/145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch +++ /dev/null @@ -1,461 +0,0 @@ -From dd77db4143290689d3a5e1ec61627233d0711b66 Mon Sep 17 00:00:00 2001 -From: Stephen Boyd -Date: Fri, 30 May 2014 16:36:11 -0700 -Subject: [PATCH] FROMLIST: cpufreq: Add a cpufreq-krait based on cpufreq-cpu0 - -Krait processors have individual clocks for each CPU that can -scale independently from one another. cpufreq-cpu0 is fairly -close to this, but assumes that there is only one clock for all -CPUs. Add a driver to support the Krait configuration. - -TODO: Merge into cpufreq-cpu0? Or make generic? - -Signed-off-by: Stephen Boyd - ---- - drivers/cpufreq/Kconfig | 13 +++ - drivers/cpufreq/Makefile | 1 + - drivers/cpufreq/cpufreq-krait.c | 190 ++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 204 insertions(+) - create mode 100644 drivers/cpufreq/cpufreq-krait.c - ---- a/drivers/cpufreq/Kconfig -+++ b/drivers/cpufreq/Kconfig -@@ -196,6 +196,19 @@ config CPUFREQ_DT - - If in doubt, say N. - -+config GENERIC_CPUFREQ_KRAIT -+ tristate "Krait cpufreq driver" -+ depends on HAVE_CLK && OF -+ # if CPU_THERMAL is on and THERMAL=m, CPU0 cannot be =y: -+ depends on !CPU_THERMAL || THERMAL -+ select PM_OPP -+ help -+ This adds a generic cpufreq driver for CPU0 frequency management. -+ It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) -+ systems which share clock and voltage across all CPUs. -+ -+ If in doubt, say N. -+ - menu "x86 CPU frequency scaling drivers" - depends on X86 - source "drivers/cpufreq/Kconfig.x86" ---- a/drivers/cpufreq/Makefile -+++ b/drivers/cpufreq/Makefile -@@ -14,6 +14,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) - obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o - - obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o -+obj-$(CONFIG_GENERIC_CPUFREQ_KRAIT) += cpufreq-krait.o - - ################################################################################## - # x86 drivers. ---- /dev/null -+++ b/drivers/cpufreq/cpufreq-krait.c -@@ -0,0 +1,390 @@ -+/* -+ * Copyright (C) 2012 Freescale Semiconductor, Inc. -+ * Copyright (c) 2014, The Linux Foundation. All rights reserved. -+ * -+ * The OPP code in function krait_set_target() is reused from -+ * drivers/cpufreq/omap-cpufreq.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static unsigned int transition_latency; -+static unsigned int voltage_tolerance; /* in percentage */ -+ -+static struct device *cpu_dev; -+static DEFINE_PER_CPU(struct clk *, krait_cpu_clks); -+static DEFINE_PER_CPU(struct regulator *, krait_supply_core); -+static struct cpufreq_frequency_table *freq_table; -+static struct thermal_cooling_device *cdev; -+ -+struct cache_points { -+ unsigned long cache_freq; -+ unsigned int cache_volt; -+ unsigned long cpu_freq; -+}; -+ -+static struct regulator *krait_l2_reg; -+static struct clk *krait_l2_clk; -+static struct cache_points *krait_l2_points; -+static int nr_krait_l2_points; -+ -+static int krait_parse_cache_points(struct device *dev, -+ struct device_node *of_node) -+{ -+ const struct property *prop; -+ const __be32 *val; -+ int nr, i; -+ -+ prop = of_find_property(of_node, "cache-points-kHz", NULL); -+ if (!prop) -+ return -ENODEV; -+ if (!prop->value) -+ return -ENODATA; -+ -+ /* -+ * Each OPP is a set of tuples consisting of frequency and -+ * cpu-frequency like . -+ */ -+ nr = prop->length / sizeof(u32); -+ if (nr % 3) { -+ dev_err(dev, "%s: Invalid cache points\n", __func__); -+ return -EINVAL; -+ } -+ nr /= 3; -+ -+ krait_l2_points = devm_kcalloc(dev, nr, sizeof(*krait_l2_points), -+ GFP_KERNEL); -+ if (!krait_l2_points) -+ return -ENOMEM; -+ nr_krait_l2_points = nr; -+ -+ for (i = 0, val = prop->value; i < nr; i++) { -+ unsigned long cache_freq = be32_to_cpup(val++) * 1000; -+ unsigned int cache_volt = be32_to_cpup(val++); -+ unsigned long cpu_freq = be32_to_cpup(val++) * 1000; -+ -+ krait_l2_points[i].cache_freq = cache_freq; -+ krait_l2_points[i].cache_volt = cache_volt; -+ krait_l2_points[i].cpu_freq = cpu_freq; -+ } -+ -+ return 0; -+} -+ -+static int krait_set_target(struct cpufreq_policy *policy, unsigned int index) -+{ -+ struct dev_pm_opp *opp; -+ unsigned long volt = 0, volt_old = 0, tol = 0; -+ unsigned long freq, max_cpu_freq = 0; -+ unsigned int old_freq, new_freq; -+ long freq_Hz, freq_exact; -+ int ret, i; -+ struct clk *cpu_clk; -+ struct regulator *core; -+ unsigned int cpu; -+ -+ cpu_clk = per_cpu(krait_cpu_clks, policy->cpu); -+ -+ freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); -+ if (freq_Hz <= 0) -+ freq_Hz = freq_table[index].frequency * 1000; -+ -+ freq_exact = freq_Hz; -+ new_freq = freq_Hz / 1000; -+ old_freq = clk_get_rate(cpu_clk) / 1000; -+ -+ core = per_cpu(krait_supply_core, policy->cpu); -+ -+ rcu_read_lock(); -+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz); -+ if (IS_ERR(opp)) { -+ rcu_read_unlock(); -+ pr_err("failed to find OPP for %ld\n", freq_Hz); -+ return PTR_ERR(opp); -+ } -+ volt = dev_pm_opp_get_voltage(opp); -+ rcu_read_unlock(); -+ tol = volt * voltage_tolerance / 100; -+ volt_old = regulator_get_voltage(core); -+ -+ pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n", -+ old_freq / 1000, volt_old ? volt_old / 1000 : -1, -+ new_freq / 1000, volt ? volt / 1000 : -1); -+ -+ /* scaling up? scale voltage before frequency */ -+ if (new_freq > old_freq) { -+ ret = regulator_set_voltage_tol(core, volt, tol); -+ if (ret) { -+ pr_err("failed to scale voltage up: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ ret = clk_set_rate(cpu_clk, freq_exact); -+ if (ret) { -+ pr_err("failed to set clock rate: %d\n", ret); -+ return ret; -+ } -+ -+ /* scaling down? scale voltage after frequency */ -+ if (new_freq < old_freq) { -+ ret = regulator_set_voltage_tol(core, volt, tol); -+ if (ret) { -+ pr_err("failed to scale voltage down: %d\n", ret); -+ clk_set_rate(cpu_clk, old_freq * 1000); -+ } -+ } -+ -+ for_each_possible_cpu(cpu) { -+ freq = clk_get_rate(per_cpu(krait_cpu_clks, cpu)); -+ max_cpu_freq = max(max_cpu_freq, freq); -+ } -+ -+ for (i = 0; i < nr_krait_l2_points; i++) { -+ if (max_cpu_freq >= krait_l2_points[i].cpu_freq) { -+ if (krait_l2_reg) { -+ ret = regulator_set_voltage_tol(krait_l2_reg, -+ krait_l2_points[i].cache_volt, -+ tol); -+ if (ret) { -+ pr_err("failed to scale l2 voltage: %d\n", -+ ret); -+ } -+ } -+ ret = clk_set_rate(krait_l2_clk, -+ krait_l2_points[i].cache_freq); -+ if (ret) -+ pr_err("failed to scale l2 clk: %d\n", ret); -+ break; -+ } -+ -+ } -+ -+ return ret; -+} -+ -+static int krait_cpufreq_init(struct cpufreq_policy *policy) -+{ -+ int ret; -+ -+ policy->clk = per_cpu(krait_cpu_clks, policy->cpu); -+ -+ ret = cpufreq_table_validate_and_show(policy, freq_table); -+ if (ret) { -+ pr_err("%s: invalid frequency table: %d\n", __func__, ret); -+ return ret; -+ } -+ -+ policy->cpuinfo.transition_latency = transition_latency; -+ -+ return 0; -+} -+ -+static struct cpufreq_driver krait_cpufreq_driver = { -+ .flags = CPUFREQ_STICKY, -+ .verify = cpufreq_generic_frequency_table_verify, -+ .target_index = krait_set_target, -+ .get = cpufreq_generic_get, -+ .init = krait_cpufreq_init, -+ .name = "generic_krait", -+ .attr = cpufreq_generic_attr, -+}; -+ -+static int krait_cpufreq_probe(struct platform_device *pdev) -+{ -+ struct device_node *np, *cache; -+ int ret, i; -+ unsigned int cpu; -+ struct device *dev; -+ struct clk *clk; -+ struct regulator *core; -+ unsigned long freq_Hz, freq, max_cpu_freq = 0; -+ struct dev_pm_opp *opp; -+ unsigned long volt, tol; -+ -+ cpu_dev = get_cpu_device(0); -+ if (!cpu_dev) { -+ pr_err("failed to get krait device\n"); -+ return -ENODEV; -+ } -+ -+ np = of_node_get(cpu_dev->of_node); -+ if (!np) { -+ pr_err("failed to find krait node\n"); -+ return -ENOENT; -+ } -+ -+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); -+ if (ret) { -+ pr_err("failed to init cpufreq table: %d\n", ret); -+ goto out_put_node; -+ } -+ -+ of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance); -+ -+ if (of_property_read_u32(np, "clock-latency", &transition_latency)) -+ transition_latency = CPUFREQ_ETERNAL; -+ -+ cache = of_find_next_cache_node(np); -+ if (cache) { -+ struct device_node *vdd; -+ -+ vdd = of_parse_phandle(cache, "vdd_dig-supply", 0); -+ if (vdd) { -+ krait_l2_reg = regulator_get(NULL, vdd->name); -+ if (IS_ERR(krait_l2_reg)) { -+ pr_warn("failed to get l2 vdd_dig supply\n"); -+ krait_l2_reg = NULL; -+ } -+ of_node_put(vdd); -+ } -+ -+ krait_l2_clk = of_clk_get(cache, 0); -+ if (!IS_ERR(krait_l2_clk)) { -+ ret = krait_parse_cache_points(&pdev->dev, cache); -+ if (ret) -+ clk_put(krait_l2_clk); -+ } -+ if (IS_ERR(krait_l2_clk) || ret) -+ krait_l2_clk = NULL; -+ } -+ -+ for_each_possible_cpu(cpu) { -+ dev = get_cpu_device(cpu); -+ if (!dev) { -+ pr_err("failed to get krait device\n"); -+ ret = -ENOENT; -+ goto out_free_table; -+ } -+ per_cpu(krait_cpu_clks, cpu) = clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(clk)) { -+ ret = PTR_ERR(clk); -+ goto out_free_table; -+ } -+ core = devm_regulator_get(dev, "core"); -+ if (IS_ERR(core)) { -+ pr_debug("failed to get core regulator\n"); -+ ret = PTR_ERR(core); -+ goto out_free_table; -+ } -+ per_cpu(krait_supply_core, cpu) = core; -+ -+ freq = freq_Hz = clk_get_rate(clk); -+ -+ rcu_read_lock(); -+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz); -+ if (IS_ERR(opp)) { -+ rcu_read_unlock(); -+ pr_err("failed to find OPP for %ld\n", freq_Hz); -+ ret = PTR_ERR(opp); -+ goto out_free_table; -+ } -+ volt = dev_pm_opp_get_voltage(opp); -+ rcu_read_unlock(); -+ -+ tol = volt * voltage_tolerance / 100; -+ ret = regulator_set_voltage_tol(core, volt, tol); -+ if (ret) { -+ pr_err("failed to scale voltage up: %d\n", ret); -+ goto out_free_table; -+ } -+ ret = regulator_enable(core); -+ if (ret) { -+ pr_err("failed to enable regulator: %d\n", ret); -+ goto out_free_table; -+ } -+ max_cpu_freq = max(max_cpu_freq, freq); -+ } -+ -+ for (i = 0; i < nr_krait_l2_points; i++) { -+ if (max_cpu_freq >= krait_l2_points[i].cpu_freq) { -+ if (krait_l2_reg) { -+ ret = regulator_set_voltage_tol(krait_l2_reg, -+ krait_l2_points[i].cache_volt, -+ tol); -+ if (ret) -+ pr_err("failed to scale l2 voltage: %d\n", -+ ret); -+ ret = regulator_enable(krait_l2_reg); -+ if (ret) -+ pr_err("failed to enable l2 voltage: %d\n", -+ ret); -+ } -+ break; -+ } -+ -+ } -+ -+ ret = cpufreq_register_driver(&krait_cpufreq_driver); -+ if (ret) { -+ pr_err("failed register driver: %d\n", ret); -+ goto out_free_table; -+ } -+ of_node_put(np); -+ -+ /* -+ * For now, just loading the cooling device; -+ * thermal DT code takes care of matching them. -+ */ -+ for_each_possible_cpu(cpu) { -+ dev = get_cpu_device(cpu); -+ np = of_node_get(dev->of_node); -+ if (of_find_property(np, "#cooling-cells", NULL)) { -+ cdev = of_cpufreq_cooling_register(np, cpumask_of(cpu)); -+ if (IS_ERR(cdev)) -+ pr_err("running cpufreq without cooling device: %ld\n", -+ PTR_ERR(cdev)); -+ } -+ of_node_put(np); -+ } -+ -+ return 0; -+ -+out_free_table: -+ regulator_put(krait_l2_reg); -+ clk_put(krait_l2_clk); -+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); -+out_put_node: -+ of_node_put(np); -+ return ret; -+} -+ -+static int krait_cpufreq_remove(struct platform_device *pdev) -+{ -+ cpufreq_cooling_unregister(cdev); -+ cpufreq_unregister_driver(&krait_cpufreq_driver); -+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); -+ clk_put(krait_l2_clk); -+ regulator_put(krait_l2_reg); -+ -+ return 0; -+} -+ -+static struct platform_driver krait_cpufreq_platdrv = { -+ .driver = { -+ .name = "cpufreq-krait", -+ .owner = THIS_MODULE, -+ }, -+ .probe = krait_cpufreq_probe, -+ .remove = krait_cpufreq_remove, -+}; -+module_platform_driver(krait_cpufreq_platdrv); -+ -+MODULE_DESCRIPTION("Krait CPUfreq driver"); -+MODULE_LICENSE("GPL v2"); ---- a/drivers/cpufreq/qcom-cpufreq.c -+++ b/drivers/cpufreq/qcom-cpufreq.c -@@ -168,11 +168,8 @@ static int __init qcom_cpufreq_populate_ - - static int __init qcom_cpufreq_driver_init(void) - { -- struct cpufreq_dt_platform_data pdata = { .independent_clocks = true }; - struct platform_device_info devinfo = { -- .name = "cpufreq-dt", -- .data = &pdata, -- .size_data = sizeof(pdata), -+ .name = "cpufreq-krait", - }; - struct device *cpu_dev; - struct device_node *np; diff --git a/target/linux/ipq806x/patches-3.18/150-dmaengine-Rework-dma_chan_get.patch b/target/linux/ipq806x/patches-3.18/150-dmaengine-Rework-dma_chan_get.patch deleted file mode 100644 index 880e67c46bf7..000000000000 --- a/target/linux/ipq806x/patches-3.18/150-dmaengine-Rework-dma_chan_get.patch +++ /dev/null @@ -1,70 +0,0 @@ -From d2f4f99db3e9ec8b063cf2e45704e2bb95428317 Mon Sep 17 00:00:00 2001 -From: Maxime Ripard -Date: Mon, 17 Nov 2014 14:41:58 +0100 -Subject: [PATCH] dmaengine: Rework dma_chan_get - -dma_chan_get uses a rather interesting error handling and code path. - -Change it to something more usual in the kernel. - -Signed-off-by: Maxime Ripard -Acked-by: Laurent Pinchart -Signed-off-by: Vinod Koul ---- - drivers/dma/dmaengine.c | 36 +++++++++++++++++++----------------- - 1 file changed, 19 insertions(+), 17 deletions(-) - ---- a/drivers/dma/dmaengine.c -+++ b/drivers/dma/dmaengine.c -@@ -222,31 +222,33 @@ static void balance_ref_count(struct dma - */ - static int dma_chan_get(struct dma_chan *chan) - { -- int err = -ENODEV; - struct module *owner = dma_chan_to_owner(chan); -+ int ret; - -+ /* The channel is already in use, update client count */ - if (chan->client_count) { - __module_get(owner); -- err = 0; -- } else if (try_module_get(owner)) -- err = 0; -+ goto out; -+ } - -- if (err == 0) -- chan->client_count++; -+ if (!try_module_get(owner)) -+ return -ENODEV; - - /* allocate upon first client reference */ -- if (chan->client_count == 1 && err == 0) { -- int desc_cnt = chan->device->device_alloc_chan_resources(chan); -- -- if (desc_cnt < 0) { -- err = desc_cnt; -- chan->client_count = 0; -- module_put(owner); -- } else if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) -- balance_ref_count(chan); -- } -- -- return err; -+ ret = chan->device->device_alloc_chan_resources(chan); -+ if (ret < 0) -+ goto err_out; -+ -+ if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) -+ balance_ref_count(chan); -+ -+out: -+ chan->client_count++; -+ return 0; -+ -+err_out: -+ module_put(owner); -+ return ret; - } - - /** diff --git a/target/linux/ipq806x/patches-3.18/151-dmaengine-Remove-the-need-to-declare-device_control.patch b/target/linux/ipq806x/patches-3.18/151-dmaengine-Remove-the-need-to-declare-device_control.patch deleted file mode 100644 index b24a10b9110f..000000000000 --- a/target/linux/ipq806x/patches-3.18/151-dmaengine-Remove-the-need-to-declare-device_control.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 4f8ef9f4140cc286d7d1cf9237da7a7439e4fc0b Mon Sep 17 00:00:00 2001 -From: Maxime Ripard -Date: Mon, 17 Nov 2014 14:42:03 +0100 -Subject: [PATCH] dmaengine: Remove the need to declare device_control - -In order to migrate the drivers without triggering a BUG_ON for the converted -drivers, which would cause bisectability issues, we need to remove that check -before removing the device_control function entirely. - -Signed-off-by: Maxime Ripard -Acked-by: Laurent Pinchart -Signed-off-by: Vinod Koul ---- - drivers/dma/dmaengine.c | 2 -- - 1 file changed, 2 deletions(-) - ---- a/drivers/dma/dmaengine.c -+++ b/drivers/dma/dmaengine.c -@@ -814,8 +814,6 @@ int dma_async_device_register(struct dma - !device->device_prep_dma_sg); - BUG_ON(dma_has_cap(DMA_CYCLIC, device->cap_mask) && - !device->device_prep_dma_cyclic); -- BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) && -- !device->device_control); - BUG_ON(dma_has_cap(DMA_INTERLEAVE, device->cap_mask) && - !device->device_prep_interleaved_dma); - diff --git a/target/linux/ipq806x/patches-3.18/152-dmaengine-Make-channel-allocation-callbacks-optional.patch b/target/linux/ipq806x/patches-3.18/152-dmaengine-Make-channel-allocation-callbacks-optional.patch deleted file mode 100644 index 63372594d8f9..000000000000 --- a/target/linux/ipq806x/patches-3.18/152-dmaengine-Make-channel-allocation-callbacks-optional.patch +++ /dev/null @@ -1,62 +0,0 @@ -From c4b54a648e682f678c338619df848233a6babc46 Mon Sep 17 00:00:00 2001 -From: Maxime Ripard -Date: Mon, 17 Nov 2014 14:41:59 +0100 -Subject: [PATCH] dmaengine: Make channel allocation callbacks optional - -Nowadays, some drivers don't have anything in there channel allocation -callbacks anymore. - -Remove the BUG_ON if those callbacks aren't implemented, in order to allow -drivers to not implement them. - -Signed-off-by: Maxime Ripard -Acked-by: Laurent Pinchart -Signed-off-by: Vinod Koul ---- - drivers/dma/dmaengine.c | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - ---- a/drivers/dma/dmaengine.c -+++ b/drivers/dma/dmaengine.c -@@ -235,9 +235,11 @@ static int dma_chan_get(struct dma_chan - return -ENODEV; - - /* allocate upon first client reference */ -- ret = chan->device->device_alloc_chan_resources(chan); -- if (ret < 0) -- goto err_out; -+ if (chan->device->device_alloc_chan_resources) { -+ ret = chan->device->device_alloc_chan_resources(chan); -+ if (ret < 0) -+ goto err_out; -+ } - - if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) - balance_ref_count(chan); -@@ -259,11 +261,15 @@ err_out: - */ - static void dma_chan_put(struct dma_chan *chan) - { -+ /* This channel is not in use, bail out */ - if (!chan->client_count) -- return; /* this channel failed alloc_chan_resources */ -+ return; -+ - chan->client_count--; - module_put(dma_chan_to_owner(chan)); -- if (chan->client_count == 0) -+ -+ /* This channel is not in use anymore, free it */ -+ if (!chan->client_count && chan->device->device_free_chan_resources) - chan->device->device_free_chan_resources(chan); - } - -@@ -817,8 +823,6 @@ int dma_async_device_register(struct dma - BUG_ON(dma_has_cap(DMA_INTERLEAVE, device->cap_mask) && - !device->device_prep_interleaved_dma); - -- BUG_ON(!device->device_alloc_chan_resources); -- BUG_ON(!device->device_free_chan_resources); - BUG_ON(!device->device_tx_status); - BUG_ON(!device->device_issue_pending); - BUG_ON(!device->dev); diff --git a/target/linux/ipq806x/patches-3.18/153-dmaengine-Introduce-a-device_config-callback.patch b/target/linux/ipq806x/patches-3.18/153-dmaengine-Introduce-a-device_config-callback.patch deleted file mode 100644 index ced452f8a075..000000000000 --- a/target/linux/ipq806x/patches-3.18/153-dmaengine-Introduce-a-device_config-callback.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 94a73e30dfe6722e9f4ef19f7892901d7d00eab1 Mon Sep 17 00:00:00 2001 -From: Maxime Ripard -Date: Mon, 17 Nov 2014 14:42:00 +0100 -Subject: [PATCH] dmaengine: Introduce a device_config callback - -The fact that the channel configuration is done in device_control is rather -misleading, since it's not really advertised as such, plus, the fact that the -framework exposes a function of its own makes it not really intuitive, while -we're losing the type checking whenever we pass that unsigned long argument. - -Add a device_config callback to dma_device, with a fallback on the old -behaviour for now for existing drivers to opt in. - -Signed-off-by: Maxime Ripard -Acked-by: Laurent Pinchart -Signed-off-by: Vinod Koul ---- - include/linux/dmaengine.h | 8 ++++++++ - 1 file changed, 8 insertions(+) - ---- a/include/linux/dmaengine.h -+++ b/include/linux/dmaengine.h -@@ -607,6 +607,8 @@ struct dma_tx_state { - * The function takes a buffer of size buf_len. The callback function will - * be called after period_len bytes have been transferred. - * @device_prep_interleaved_dma: Transfer expression in a generic way. -+ * @device_config: Pushes a new configuration to a channel, return 0 or an error -+ * code - * @device_control: manipulate all pending operations on a channel, returns - * zero or error code - * @device_tx_status: poll for transaction completion, the optional -@@ -673,6 +675,9 @@ struct dma_device { - struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)( - struct dma_chan *chan, struct dma_interleaved_template *xt, - unsigned long flags); -+ -+ int (*device_config)(struct dma_chan *chan, -+ struct dma_slave_config *config); - int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd, - unsigned long arg); - -@@ -696,6 +701,9 @@ static inline int dmaengine_device_contr - static inline int dmaengine_slave_config(struct dma_chan *chan, - struct dma_slave_config *config) - { -+ if (chan->device->device_config) -+ return chan->device->device_config(chan, config); -+ - return dmaengine_device_control(chan, DMA_SLAVE_CONFIG, - (unsigned long)config); - } diff --git a/target/linux/ipq806x/patches-3.18/154-dmaengine-Add-device_terminate_all-callback.patch b/target/linux/ipq806x/patches-3.18/154-dmaengine-Add-device_terminate_all-callback.patch deleted file mode 100644 index 422f7fbe4241..000000000000 --- a/target/linux/ipq806x/patches-3.18/154-dmaengine-Add-device_terminate_all-callback.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 7fa0cf462daa6f6121b332b87833d7f5bdb515c0 Mon Sep 17 00:00:00 2001 -From: Maxime Ripard -Date: Mon, 17 Nov 2014 14:42:02 +0100 -Subject: [PATCH] dmaengine: Add device_terminate_all callback - -Split out the terminate_all command from device_control to a dma_device -callback. In order to preserve backward capability, still rely on -device_control if no such callback has been implemented. - -Eventually, this will allow to create a generic dma_slave_caps callback. - -Signed-off-by: Maxime Ripard -Acked-by: Laurent Pinchart -Signed-off-by: Vinod Koul ---- - include/linux/dmaengine.h | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/include/linux/dmaengine.h -+++ b/include/linux/dmaengine.h -@@ -611,6 +611,8 @@ struct dma_tx_state { - * code - * @device_control: manipulate all pending operations on a channel, returns - * zero or error code -+ * @device_terminate_all: Aborts all transfers on a channel. Returns 0 -+ * or an error code - * @device_tx_status: poll for transaction completion, the optional - * txstate parameter can be supplied with a pointer to get a - * struct with auxiliary transfer status information, otherwise the call -@@ -680,6 +682,7 @@ struct dma_device { - struct dma_slave_config *config); - int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd, - unsigned long arg); -+ int (*device_terminate_all)(struct dma_chan *chan); - - enum dma_status (*device_tx_status)(struct dma_chan *chan, - dma_cookie_t cookie, -@@ -789,6 +792,9 @@ static inline int dma_get_slave_caps(str - - static inline int dmaengine_terminate_all(struct dma_chan *chan) - { -+ if (chan->device->device_terminate_all) -+ return chan->device->device_terminate_all(chan); -+ - return dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); - } - diff --git a/target/linux/ipq806x/patches-3.18/155-dt-bindings-qcom_adm-Fix-channel-specifiers.patch b/target/linux/ipq806x/patches-3.18/155-dt-bindings-qcom_adm-Fix-channel-specifiers.patch deleted file mode 100644 index 4f5c0efb7b05..000000000000 --- a/target/linux/ipq806x/patches-3.18/155-dt-bindings-qcom_adm-Fix-channel-specifiers.patch +++ /dev/null @@ -1,76 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v6,1/2] dt/bindings: qcom_adm: Fix channel specifiers -From: Andy Gross -X-Patchwork-Id: 6027361 -Message-Id: <1426571172-9711-2-git-send-email-agross@codeaurora.org> -To: Vinod Koul -Cc: devicetree@vger.kernel.org, dmaengine@vger.kernel.org, - linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, - linux-arm-kernel@lists.infradead.org, Kumar Gala , - Bjorn Andersson , - Andy Gross -Date: Tue, 17 Mar 2015 00:46:11 -0500 - -This patch removes the crci information from the dma channel property. At least -one client device requires using more than one CRCI value for a channel. This -does not match the current binding and the crci information needs to be removed. - -Instead, the client device will provide this information via other means. - -Signed-off-by: Andy Gross - ---- -Documentation/devicetree/bindings/dma/qcom_adm.txt | 16 ++++++---------- - 1 file changed, 6 insertions(+), 10 deletions(-) - ---- a/Documentation/devicetree/bindings/dma/qcom_adm.txt -+++ b/Documentation/devicetree/bindings/dma/qcom_adm.txt -@@ -4,8 +4,7 @@ Required properties: - - compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960 - - reg: Address range for DMA registers - - interrupts: Should contain one interrupt shared by all channels --- #dma-cells: must be <2>. First cell denotes the channel number. Second cell -- denotes CRCI (client rate control interface) flow control assignment. -+- #dma-cells: must be <1>. First cell denotes the channel number. - - clocks: Should contain the core clock and interface clock. - - clock-names: Must contain "core" for the core clock and "iface" for the - interface clock. -@@ -22,7 +21,7 @@ Example: - compatible = "qcom,adm"; - reg = <0x18300000 0x100000>; - interrupts = <0 170 0>; -- #dma-cells = <2>; -+ #dma-cells = <1>; - - clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; - clock-names = "core", "iface"; -@@ -35,15 +34,12 @@ Example: - qcom,ee = <0>; - }; - --DMA clients must use the format descripted in the dma.txt file, using a three -+DMA clients must use the format descripted in the dma.txt file, using a two - cell specifier for each channel. - --Each dmas request consists of 3 cells: -+Each dmas request consists of two cells: - 1. phandle pointing to the DMA controller - 2. channel number -- 3. CRCI assignment, if applicable. If no CRCI flow control is required, use 0. -- The CRCI is used for flow control. It identifies the peripheral device that -- is the source/destination for the transferred data. - - Example: - -@@ -56,7 +52,7 @@ Example: - - cs-gpios = <&qcom_pinmux 20 0>; - -- dmas = <&adm_dma 6 9>, -- <&adm_dma 5 10>; -+ dmas = <&adm_dma 6>, -+ <&adm_dma 5>; - dma-names = "rx", "tx"; - }; diff --git a/target/linux/ipq806x/patches-3.18/156-dmaengine-Add-ADM-driver.patch b/target/linux/ipq806x/patches-3.18/156-dmaengine-Add-ADM-driver.patch deleted file mode 100644 index 16d000e8a5be..000000000000 --- a/target/linux/ipq806x/patches-3.18/156-dmaengine-Add-ADM-driver.patch +++ /dev/null @@ -1,958 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v6,2/2] dmaengine: Add ADM driver -From: Andy Gross -X-Patchwork-Id: 6027351 -Message-Id: <1426571172-9711-3-git-send-email-agross@codeaurora.org> -To: Vinod Koul -Cc: devicetree@vger.kernel.org, dmaengine@vger.kernel.org, - linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, - linux-arm-kernel@lists.infradead.org, Kumar Gala , - Bjorn Andersson , - Andy Gross -Date: Tue, 17 Mar 2015 00:46:12 -0500 - -Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA -controller found in the MSM8x60 and IPQ/APQ8064 platforms. - -The ADM supports both memory to memory transactions and memory -to/from peripheral device transactions. The controller also provides flow -control capabilities for transactions to/from peripheral devices. - -The initial release of this driver supports slave transfers to/from peripherals -and also incorporates CRCI (client rate control interface) flow control. - -Signed-off-by: Andy Gross -Reviewed-by: sricharan - ---- -drivers/dma/Kconfig | 10 + - drivers/dma/Makefile | 1 + - drivers/dma/qcom_adm.c | 900 ++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 911 insertions(+) - create mode 100644 drivers/dma/qcom_adm.c - ---- a/drivers/dma/Kconfig -+++ b/drivers/dma/Kconfig -@@ -457,4 +457,14 @@ config QCOM_BAM_DMA - Enable support for the QCOM BAM DMA controller. This controller - provides DMA capabilities for a variety of on-chip devices. - -+config QCOM_ADM -+ tristate "Qualcomm ADM support" -+ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) -+ select DMA_ENGINE -+ select DMA_VIRTUAL_CHANNELS -+ ---help--- -+ Enable support for the Qualcomm ADM DMA controller. This controller -+ provides DMA capabilities for both general purpose and on-chip -+ peripheral devices. -+ - endif ---- /dev/null -+++ b/drivers/dma/qcom_adm.c -@@ -0,0 +1,896 @@ -+/* -+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "dmaengine.h" -+#include "virt-dma.h" -+ -+/* ADM registers - calculated from channel number and security domain */ -+#define ADM_CHAN_MULTI 0x4 -+#define ADM_CI_MULTI 0x4 -+#define ADM_CRCI_MULTI 0x4 -+#define ADM_EE_MULTI 0x800 -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) -+#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * ee) -+#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) -+#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) -+#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_CH_FLUSH_STATE0(chan, ee) (0x80 + ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_CH_STATUS_SD(chan, ee) (0x200 + ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) -+#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) -+#define ADM_CI_CONF(ci) (0x390 + ci * ADM_CI_MULTI) -+#define ADM_GP_CTL 0x3d8 -+#define ADM_CRCI_CTL(crci, ee) (0x400 + crci * ADM_CRCI_MULTI + \ -+ ADM_EE_OFFS(ee)) -+ -+/* channel status */ -+#define ADM_CH_STATUS_VALID BIT(1) -+ -+/* channel result */ -+#define ADM_CH_RSLT_VALID BIT(31) -+#define ADM_CH_RSLT_ERR BIT(3) -+#define ADM_CH_RSLT_FLUSH BIT(2) -+#define ADM_CH_RSLT_TPD BIT(1) -+ -+/* channel conf */ -+#define ADM_CH_CONF_SHADOW_EN BIT(12) -+#define ADM_CH_CONF_MPU_DISABLE BIT(11) -+#define ADM_CH_CONF_PERM_MPU_CONF BIT(9) -+#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) -+#define ADM_CH_CONF_SEC_DOMAIN(ee) (((ee & 0x3) << 4) | ((ee & 0x4) << 11)) -+ -+/* channel result conf */ -+#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) -+#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) -+ -+/* CRCI CTL */ -+#define ADM_CRCI_CTL_MUX_SEL BIT(18) -+#define ADM_CRCI_CTL_RST BIT(17) -+ -+/* CI configuration */ -+#define ADM_CI_RANGE_END(x) (x << 24) -+#define ADM_CI_RANGE_START(x) (x << 16) -+#define ADM_CI_BURST_4_WORDS BIT(2) -+#define ADM_CI_BURST_8_WORDS BIT(3) -+ -+/* GP CTL */ -+#define ADM_GP_CTL_LP_EN BIT(12) -+#define ADM_GP_CTL_LP_CNT(x) (x << 8) -+ -+/* Command pointer list entry */ -+#define ADM_CPLE_LP BIT(31) -+#define ADM_CPLE_CMD_PTR_LIST BIT(29) -+ -+/* Command list entry */ -+#define ADM_CMD_LC BIT(31) -+#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) -+#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) -+ -+#define ADM_CMD_TYPE_SINGLE 0x0 -+#define ADM_CMD_TYPE_BOX 0x3 -+ -+#define ADM_CRCI_MUX_SEL BIT(4) -+#define ADM_DESC_ALIGN 8 -+#define ADM_MAX_XFER (SZ_64K-1) -+#define ADM_MAX_ROWS (SZ_64K-1) -+#define ADM_MAX_CHANNELS 16 -+ -+struct adm_desc_hw_box { -+ u32 cmd; -+ u32 src_addr; -+ u32 dst_addr; -+ u32 row_len; -+ u32 num_rows; -+ u32 row_offset; -+}; -+ -+struct adm_desc_hw_single { -+ u32 cmd; -+ u32 src_addr; -+ u32 dst_addr; -+ u32 len; -+}; -+ -+struct adm_async_desc { -+ struct virt_dma_desc vd; -+ struct adm_device *adev; -+ -+ size_t length; -+ enum dma_transfer_direction dir; -+ dma_addr_t dma_addr; -+ size_t dma_len; -+ -+ void *cpl; -+ dma_addr_t cp_addr; -+ u32 crci; -+ u32 mux; -+ u32 blk_size; -+}; -+ -+struct adm_chan { -+ struct virt_dma_chan vc; -+ struct adm_device *adev; -+ -+ /* parsed from DT */ -+ u32 id; /* channel id */ -+ -+ struct adm_async_desc *curr_txd; -+ struct dma_slave_config slave; -+ struct list_head node; -+ -+ int error; -+ int initialized; -+}; -+ -+static inline struct adm_chan *to_adm_chan(struct dma_chan *common) -+{ -+ return container_of(common, struct adm_chan, vc.chan); -+} -+ -+struct adm_device { -+ void __iomem *regs; -+ struct device *dev; -+ struct dma_device common; -+ struct device_dma_parameters dma_parms; -+ struct adm_chan *channels; -+ -+ u32 ee; -+ -+ struct clk *core_clk; -+ struct clk *iface_clk; -+ -+ struct reset_control *clk_reset; -+ struct reset_control *c0_reset; -+ struct reset_control *c1_reset; -+ struct reset_control *c2_reset; -+ int irq; -+}; -+ -+/** -+ * adm_free_chan - Frees dma resources associated with the specific channel -+ * -+ * Free all allocated descriptors associated with this channel -+ * -+ */ -+static void adm_free_chan(struct dma_chan *chan) -+{ -+ /* free all queued descriptors */ -+ vchan_free_chan_resources(to_virt_chan(chan)); -+} -+ -+/** -+ * adm_get_blksize - Get block size from burst value -+ * -+ */ -+static int adm_get_blksize(unsigned int burst) -+{ -+ int ret; -+ -+ switch (burst) { -+ case 16: -+ case 32: -+ case 64: -+ case 128: -+ ret = ffs(burst>>4) - 1; -+ break; -+ case 192: -+ ret = 4; -+ break; -+ case 256: -+ ret = 5; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+/** -+ * adm_process_fc_descriptors - Process descriptors for flow controlled xfers -+ * -+ * @achan: ADM channel -+ * @desc: Descriptor memory pointer -+ * @sg: Scatterlist entry -+ * @crci: CRCI value -+ * @burst: Burst size of transaction -+ * @direction: DMA transfer direction -+ */ -+static void *adm_process_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, u32 crci, u32 burst, -+ enum dma_transfer_direction direction) -+{ -+ struct adm_desc_hw_box *box_desc = NULL; -+ struct adm_desc_hw_single *single_desc; -+ u32 remainder = sg_dma_len(sg); -+ u32 rows, row_offset, crci_cmd; -+ u32 mem_addr = sg_dma_address(sg); -+ u32 *incr_addr = &mem_addr; -+ u32 *src, *dst; -+ -+ if (direction == DMA_DEV_TO_MEM) { -+ crci_cmd = ADM_CMD_SRC_CRCI(crci); -+ row_offset = burst; -+ src = &achan->slave.src_addr; -+ dst = &mem_addr; -+ } else { -+ crci_cmd = ADM_CMD_DST_CRCI(crci); -+ row_offset = burst << 16; -+ src = &mem_addr; -+ dst = &achan->slave.dst_addr; -+ } -+ -+ while (remainder >= burst) { -+ box_desc = desc; -+ box_desc->cmd = ADM_CMD_TYPE_BOX | crci_cmd; -+ box_desc->row_offset = row_offset; -+ box_desc->src_addr = *src; -+ box_desc->dst_addr = *dst; -+ -+ rows = remainder / burst; -+ rows = min_t(u32, rows, ADM_MAX_ROWS); -+ box_desc->num_rows = rows << 16 | rows; -+ box_desc->row_len = burst << 16 | burst; -+ -+ *incr_addr += burst * rows; -+ remainder -= burst * rows; -+ desc += sizeof(*box_desc); -+ } -+ -+ /* if leftover bytes, do one single descriptor */ -+ if (remainder) { -+ single_desc = desc; -+ single_desc->cmd = ADM_CMD_TYPE_SINGLE | crci_cmd; -+ single_desc->len = remainder; -+ single_desc->src_addr = *src; -+ single_desc->dst_addr = *dst; -+ desc += sizeof(*single_desc); -+ -+ if (sg_is_last(sg)) -+ single_desc->cmd |= ADM_CMD_LC; -+ } else { -+ if (box_desc && sg_is_last(sg)) -+ box_desc->cmd |= ADM_CMD_LC; -+ } -+ -+ return desc; -+} -+ -+/** -+ * adm_process_non_fc_descriptors - Process descriptors for non-fc xfers -+ * -+ * @achan: ADM channel -+ * @desc: Descriptor memory pointer -+ * @sg: Scatterlist entry -+ * @direction: DMA transfer direction -+ */ -+static void *adm_process_non_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, -+ enum dma_transfer_direction direction) -+{ -+ struct adm_desc_hw_single *single_desc; -+ u32 remainder = sg_dma_len(sg); -+ u32 mem_addr = sg_dma_address(sg); -+ u32 *incr_addr = &mem_addr; -+ u32 *src, *dst; -+ -+ if (direction == DMA_DEV_TO_MEM) { -+ src = &achan->slave.src_addr; -+ dst = &mem_addr; -+ } else { -+ src = &mem_addr; -+ dst = &achan->slave.dst_addr; -+ } -+ -+ do { -+ single_desc = desc; -+ single_desc->cmd = ADM_CMD_TYPE_SINGLE; -+ single_desc->src_addr = *src; -+ single_desc->dst_addr = *dst; -+ single_desc->len = (remainder > ADM_MAX_XFER) ? -+ ADM_MAX_XFER : remainder; -+ -+ remainder -= single_desc->len; -+ *incr_addr += single_desc->len; -+ desc += sizeof(*single_desc); -+ } while (remainder); -+ -+ /* set last command if this is the end of the whole transaction */ -+ if (sg_is_last(sg)) -+ single_desc->cmd |= ADM_CMD_LC; -+ -+ return desc; -+} -+ -+/** -+ * adm_prep_slave_sg - Prep slave sg transaction -+ * -+ * @chan: dma channel -+ * @sgl: scatter gather list -+ * @sg_len: length of sg -+ * @direction: DMA transfer direction -+ * @flags: DMA flags -+ * @context: transfer context (unused) -+ */ -+static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, -+ struct scatterlist *sgl, unsigned int sg_len, -+ enum dma_transfer_direction direction, unsigned long flags, -+ void *context) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ struct adm_device *adev = achan->adev; -+ struct adm_async_desc *async_desc; -+ struct scatterlist *sg; -+ u32 i, burst; -+ u32 single_count = 0, box_count = 0, crci = 0; -+ void *desc; -+ u32 *cple; -+ int blk_size = 0; -+ -+ if (!is_slave_direction(direction)) { -+ dev_err(adev->dev, "invalid dma direction\n"); -+ return NULL; -+ } -+ -+ /* -+ * get burst value from slave configuration -+ */ -+ burst = (direction == DMA_MEM_TO_DEV) ? -+ achan->slave.dst_maxburst : -+ achan->slave.src_maxburst; -+ -+ /* if using flow control, validate burst and crci values */ -+ if (achan->slave.device_fc) { -+ -+ blk_size = adm_get_blksize(burst); -+ if (blk_size < 0) { -+ dev_err(adev->dev, "invalid burst value: %d\n", -+ burst); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ crci = achan->slave.slave_id & 0xf; -+ if (!crci || achan->slave.slave_id > 0x1f) { -+ dev_err(adev->dev, "invalid crci value\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ } -+ -+ /* iterate through sgs and compute allocation size of structures */ -+ for_each_sg(sgl, sg, sg_len, i) { -+ if (achan->slave.device_fc) { -+ box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst, -+ ADM_MAX_ROWS); -+ if (sg_dma_len(sg) % burst) -+ single_count++; -+ } else { -+ single_count += DIV_ROUND_UP(sg_dma_len(sg), -+ ADM_MAX_XFER); -+ } -+ } -+ -+ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); -+ if (!async_desc) -+ return ERR_PTR(-ENOMEM); -+ -+ if (crci) -+ async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ? -+ ADM_CRCI_CTL_MUX_SEL : 0; -+ async_desc->crci = crci; -+ async_desc->blk_size = blk_size; -+ async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) + -+ box_count * sizeof(struct adm_desc_hw_box) + -+ sizeof(*cple) + 2 * ADM_DESC_ALIGN; -+ -+ async_desc->cpl = dma_alloc_writecombine(adev->dev, async_desc->dma_len, -+ &async_desc->dma_addr, GFP_NOWAIT); -+ -+ if (!async_desc->cpl) { -+ kfree(async_desc); -+ return ERR_PTR(-ENOMEM); -+ } -+ -+ async_desc->adev = adev; -+ -+ /* both command list entry and descriptors must be 8 byte aligned */ -+ cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN); -+ desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN); -+ -+ /* init cmd list */ -+ *cple = ADM_CPLE_LP; -+ *cple |= (desc - async_desc->cpl + async_desc->dma_addr) >> 3; -+ -+ for_each_sg(sgl, sg, sg_len, i) { -+ async_desc->length += sg_dma_len(sg); -+ -+ if (achan->slave.device_fc) -+ desc = adm_process_fc_descriptors(achan, desc, sg, crci, -+ burst, direction); -+ else -+ desc = adm_process_non_fc_descriptors(achan, desc, sg, -+ direction); -+ } -+ -+ return vchan_tx_prep(&achan->vc, &async_desc->vd, flags); -+} -+ -+/** -+ * adm_terminate_all - terminate all transactions on a channel -+ * @achan: adm dma channel -+ * -+ * Dequeues and frees all transactions, aborts current transaction -+ * No callbacks are done -+ * -+ */ -+static int adm_terminate_all(struct dma_chan *chan) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ struct adm_device *adev = achan->adev; -+ unsigned long flags; -+ LIST_HEAD(head); -+ -+ spin_lock_irqsave(&achan->vc.lock, flags); -+ vchan_get_all_descriptors(&achan->vc, &head); -+ -+ /* send flush command to terminate current transaction */ -+ writel_relaxed(0x0, -+ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); -+ -+ spin_unlock_irqrestore(&achan->vc.lock, flags); -+ -+ vchan_dma_desc_free_list(&achan->vc, &head); -+ -+ return 0; -+} -+ -+static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ unsigned long flag; -+ -+ spin_lock_irqsave(&achan->vc.lock, flag); -+ memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config)); -+ spin_unlock_irqrestore(&achan->vc.lock, flag); -+ -+ return 0; -+} -+ -+/** -+ * adm_start_dma - start next transaction -+ * @achan - ADM dma channel -+ */ -+static void adm_start_dma(struct adm_chan *achan) -+{ -+ struct virt_dma_desc *vd = vchan_next_desc(&achan->vc); -+ struct adm_device *adev = achan->adev; -+ struct adm_async_desc *async_desc; -+ -+ lockdep_assert_held(&achan->vc.lock); -+ -+ if (!vd) -+ return; -+ -+ list_del(&vd->node); -+ -+ /* write next command list out to the CMD FIFO */ -+ async_desc = container_of(vd, struct adm_async_desc, vd); -+ achan->curr_txd = async_desc; -+ -+ /* reset channel error */ -+ achan->error = 0; -+ -+ if (!achan->initialized) { -+ /* enable interrupts */ -+ writel(ADM_CH_CONF_SHADOW_EN | -+ ADM_CH_CONF_PERM_MPU_CONF | -+ ADM_CH_CONF_MPU_DISABLE | -+ ADM_CH_CONF_SEC_DOMAIN(adev->ee), -+ adev->regs + ADM_CH_CONF(achan->id)); -+ -+ writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, -+ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); -+ -+ achan->initialized = 1; -+ } -+ -+ /* set the crci block size if this transaction requires CRCI */ -+ if (async_desc->crci) { -+ writel(async_desc->mux | async_desc->blk_size, -+ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); -+ } -+ -+ /* make sure IRQ enable doesn't get reordered */ -+ wmb(); -+ -+ /* write next command list out to the CMD FIFO */ -+ writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, -+ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); -+} -+ -+/** -+ * adm_dma_irq - irq handler for ADM controller -+ * @irq: IRQ of interrupt -+ * @data: callback data -+ * -+ * IRQ handler for the bam controller -+ */ -+static irqreturn_t adm_dma_irq(int irq, void *data) -+{ -+ struct adm_device *adev = data; -+ u32 srcs, i; -+ struct adm_async_desc *async_desc; -+ unsigned long flags; -+ -+ srcs = readl_relaxed(adev->regs + -+ ADM_SEC_DOMAIN_IRQ_STATUS(adev->ee)); -+ -+ for (i = 0; i < ADM_MAX_CHANNELS; i++) { -+ struct adm_chan *achan = &adev->channels[i]; -+ u32 status, result; -+ -+ if (srcs & BIT(i)) { -+ status = readl_relaxed(adev->regs + -+ ADM_CH_STATUS_SD(i, adev->ee)); -+ -+ /* if no result present, skip */ -+ if (!(status & ADM_CH_STATUS_VALID)) -+ continue; -+ -+ result = readl_relaxed(adev->regs + -+ ADM_CH_RSLT(i, adev->ee)); -+ -+ /* no valid results, skip */ -+ if (!(result & ADM_CH_RSLT_VALID)) -+ continue; -+ -+ /* flag error if transaction was flushed or failed */ -+ if (result & (ADM_CH_RSLT_ERR | ADM_CH_RSLT_FLUSH)) -+ achan->error = 1; -+ -+ spin_lock_irqsave(&achan->vc.lock, flags); -+ async_desc = achan->curr_txd; -+ -+ achan->curr_txd = NULL; -+ -+ if (async_desc) { -+ vchan_cookie_complete(&async_desc->vd); -+ -+ /* kick off next DMA */ -+ adm_start_dma(achan); -+ } -+ -+ spin_unlock_irqrestore(&achan->vc.lock, flags); -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+ * adm_tx_status - returns status of transaction -+ * @chan: dma channel -+ * @cookie: transaction cookie -+ * @txstate: DMA transaction state -+ * -+ * Return status of dma transaction -+ */ -+static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, -+ struct dma_tx_state *txstate) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ struct virt_dma_desc *vd; -+ enum dma_status ret; -+ unsigned long flags; -+ size_t residue = 0; -+ -+ ret = dma_cookie_status(chan, cookie, txstate); -+ if (ret == DMA_COMPLETE || !txstate) -+ return ret; -+ -+ spin_lock_irqsave(&achan->vc.lock, flags); -+ -+ vd = vchan_find_desc(&achan->vc, cookie); -+ if (vd) -+ residue = container_of(vd, struct adm_async_desc, vd)->length; -+ -+ spin_unlock_irqrestore(&achan->vc.lock, flags); -+ -+ /* -+ * residue is either the full length if it is in the issued list, or 0 -+ * if it is in progress. We have no reliable way of determining -+ * anything inbetween -+ */ -+ dma_set_residue(txstate, residue); -+ -+ if (achan->error) -+ return DMA_ERROR; -+ -+ return ret; -+} -+ -+/** -+ * adm_issue_pending - starts pending transactions -+ * @chan: dma channel -+ * -+ * Issues all pending transactions and starts DMA -+ */ -+static void adm_issue_pending(struct dma_chan *chan) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&achan->vc.lock, flags); -+ -+ if (vchan_issue_pending(&achan->vc) && !achan->curr_txd) -+ adm_start_dma(achan); -+ spin_unlock_irqrestore(&achan->vc.lock, flags); -+} -+ -+/** -+ * adm_dma_free_desc - free descriptor memory -+ * @vd: virtual descriptor -+ * -+ */ -+static void adm_dma_free_desc(struct virt_dma_desc *vd) -+{ -+ struct adm_async_desc *async_desc = container_of(vd, -+ struct adm_async_desc, vd); -+ -+ dma_free_writecombine(async_desc->adev->dev, async_desc->dma_len, -+ async_desc->cpl, async_desc->dma_addr); -+ kfree(async_desc); -+} -+ -+static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, -+ u32 index) -+{ -+ achan->id = index; -+ achan->adev = adev; -+ -+ vchan_init(&achan->vc, &adev->common); -+ achan->vc.desc_free = adm_dma_free_desc; -+} -+ -+static int adm_dma_probe(struct platform_device *pdev) -+{ -+ struct adm_device *adev; -+ struct resource *iores; -+ int ret; -+ u32 i; -+ -+ adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL); -+ if (!adev) -+ return -ENOMEM; -+ -+ adev->dev = &pdev->dev; -+ -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ adev->regs = devm_ioremap_resource(&pdev->dev, iores); -+ if (IS_ERR(adev->regs)) -+ return PTR_ERR(adev->regs); -+ -+ adev->irq = platform_get_irq(pdev, 0); -+ if (adev->irq < 0) -+ return adev->irq; -+ -+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &adev->ee); -+ if (ret) { -+ dev_err(adev->dev, "Execution environment unspecified\n"); -+ return ret; -+ } -+ -+ adev->core_clk = devm_clk_get(adev->dev, "core"); -+ if (IS_ERR(adev->core_clk)) -+ return PTR_ERR(adev->core_clk); -+ -+ ret = clk_prepare_enable(adev->core_clk); -+ if (ret) { -+ dev_err(adev->dev, "failed to prepare/enable core clock\n"); -+ return ret; -+ } -+ -+ adev->iface_clk = devm_clk_get(adev->dev, "iface"); -+ if (IS_ERR(adev->iface_clk)) { -+ ret = PTR_ERR(adev->iface_clk); -+ goto err_disable_core_clk; -+ } -+ -+ ret = clk_prepare_enable(adev->iface_clk); -+ if (ret) { -+ dev_err(adev->dev, "failed to prepare/enable iface clock\n"); -+ goto err_disable_core_clk; -+ } -+ -+ adev->clk_reset = devm_reset_control_get(&pdev->dev, "clk"); -+ if (IS_ERR(adev->clk_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 reset\n"); -+ ret = PTR_ERR(adev->clk_reset); -+ goto err_disable_clks; -+ } -+ -+ adev->c0_reset = devm_reset_control_get(&pdev->dev, "c0"); -+ if (IS_ERR(adev->c0_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); -+ ret = PTR_ERR(adev->c0_reset); -+ goto err_disable_clks; -+ } -+ -+ adev->c1_reset = devm_reset_control_get(&pdev->dev, "c1"); -+ if (IS_ERR(adev->c1_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); -+ ret = PTR_ERR(adev->c1_reset); -+ goto err_disable_clks; -+ } -+ -+ adev->c2_reset = devm_reset_control_get(&pdev->dev, "c2"); -+ if (IS_ERR(adev->c2_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); -+ ret = PTR_ERR(adev->c2_reset); -+ goto err_disable_clks; -+ } -+ -+ reset_control_assert(adev->clk_reset); -+ reset_control_assert(adev->c0_reset); -+ reset_control_assert(adev->c1_reset); -+ reset_control_assert(adev->c2_reset); -+ -+ reset_control_deassert(adev->clk_reset); -+ reset_control_deassert(adev->c0_reset); -+ reset_control_deassert(adev->c1_reset); -+ reset_control_deassert(adev->c2_reset); -+ -+ adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, -+ sizeof(*adev->channels), GFP_KERNEL); -+ -+ if (!adev->channels) { -+ ret = -ENOMEM; -+ goto err_disable_clks; -+ } -+ -+ /* allocate and initialize channels */ -+ INIT_LIST_HEAD(&adev->common.channels); -+ -+ for (i = 0; i < ADM_MAX_CHANNELS; i++) -+ adm_channel_init(adev, &adev->channels[i], i); -+ -+ /* reset CRCIs */ -+ for (i = 0; i < 16; i++) -+ writel(ADM_CRCI_CTL_RST, adev->regs + -+ ADM_CRCI_CTL(i, adev->ee)); -+ -+ /* configure client interfaces */ -+ writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); -+ writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); -+ writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); -+ writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), -+ adev->regs + ADM_GP_CTL); -+ -+ ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, -+ 0, "adm_dma", adev); -+ if (ret) -+ goto err_disable_clks; -+ -+ platform_set_drvdata(pdev, adev); -+ -+ adev->common.dev = adev->dev; -+ adev->common.dev->dma_parms = &adev->dma_parms; -+ -+ /* set capabilities */ -+ dma_cap_zero(adev->common.cap_mask); -+ dma_cap_set(DMA_SLAVE, adev->common.cap_mask); -+ dma_cap_set(DMA_PRIVATE, adev->common.cap_mask); -+ -+ /* initialize dmaengine apis */ -+ adev->common.device_free_chan_resources = adm_free_chan; -+ adev->common.device_prep_slave_sg = adm_prep_slave_sg; -+ adev->common.device_issue_pending = adm_issue_pending; -+ adev->common.device_tx_status = adm_tx_status; -+ adev->common.device_terminate_all = adm_terminate_all; -+ adev->common.device_config = adm_slave_config; -+ -+ ret = dma_async_device_register(&adev->common); -+ if (ret) { -+ dev_err(adev->dev, "failed to register dma async device\n"); -+ goto err_disable_clks; -+ } -+ -+ ret = of_dma_controller_register(pdev->dev.of_node, -+ of_dma_xlate_by_chan_id, -+ &adev->common); -+ if (ret) -+ goto err_unregister_dma; -+ -+ return 0; -+ -+err_unregister_dma: -+ dma_async_device_unregister(&adev->common); -+err_disable_clks: -+ clk_disable_unprepare(adev->iface_clk); -+err_disable_core_clk: -+ clk_disable_unprepare(adev->core_clk); -+ -+ return ret; -+} -+ -+static int adm_dma_remove(struct platform_device *pdev) -+{ -+ struct adm_device *adev = platform_get_drvdata(pdev); -+ struct adm_chan *achan; -+ u32 i; -+ -+ of_dma_controller_free(pdev->dev.of_node); -+ dma_async_device_unregister(&adev->common); -+ -+ for (i = 0; i < ADM_MAX_CHANNELS; i++) { -+ achan = &adev->channels[i]; -+ -+ /* mask IRQs for this channel/EE pair */ -+ writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); -+ -+ adm_terminate_all(&adev->channels[i].vc.chan); -+ } -+ -+ devm_free_irq(adev->dev, adev->irq, adev); -+ -+ clk_disable_unprepare(adev->core_clk); -+ clk_disable_unprepare(adev->iface_clk); -+ -+ return 0; -+} -+ -+static const struct of_device_id adm_of_match[] = { -+ { .compatible = "qcom,adm", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, adm_of_match); -+ -+static struct platform_driver adm_dma_driver = { -+ .probe = adm_dma_probe, -+ .remove = adm_dma_remove, -+ .driver = { -+ .name = "adm-dma-engine", -+ .of_match_table = adm_of_match, -+ }, -+}; -+ -+module_platform_driver(adm_dma_driver); -+ -+MODULE_AUTHOR("Andy Gross "); -+MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); -+MODULE_LICENSE("GPL v2"); ---- a/drivers/dma/Makefile -+++ b/drivers/dma/Makefile -@@ -49,3 +49,4 @@ obj-y += xilinx/ - obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o - obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o - obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o -+obj-$(CONFIG_QCOM_ADM) += qcom_adm.o diff --git a/target/linux/ipq806x/patches-3.18/157-ARM-DT-ipq8064-Add-ADM-device-node.patch b/target/linux/ipq806x/patches-3.18/157-ARM-DT-ipq8064-Add-ADM-device-node.patch deleted file mode 100644 index a6dc89764cd6..000000000000 --- a/target/linux/ipq806x/patches-3.18/157-ARM-DT-ipq8064-Add-ADM-device-node.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 1fb18acab2d71e7e4efd9c10492edb1baf84dcc0 Mon Sep 17 00:00:00 2001 -From: Andy Gross -Date: Wed, 20 May 2015 15:41:07 +0530 -Subject: [PATCH] ARM: DT: ipq8064: Add ADM device node - -This patch adds support for the ADM DMA on the IPQ8064 SOC - -Signed-off-by: Andy Gross ---- - arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 4 ++++ - arch/arm/boot/dts/qcom-ipq8064.dtsi | 21 +++++++++++++++++++++ - 2 files changed, 25 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -705,6 +705,26 @@ - }; - }; - -+ adm_dma: dma@18300000 { -+ compatible = "qcom,adm"; -+ reg = <0x18300000 0x100000>; -+ interrupts = <0 170 0>; -+ #dma-cells = <1>; -+ -+ clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; -+ clock-names = "core", "iface"; -+ -+ resets = <&gcc ADM0_RESET>, -+ <&gcc ADM0_PBUS_RESET>, -+ <&gcc ADM0_C0_RESET>, -+ <&gcc ADM0_C1_RESET>, -+ <&gcc ADM0_C2_RESET>; -+ reset-names = "clk", "pbus", "c0", "c1", "c2"; -+ qcom,ee = <0>; -+ -+ status = "disabled"; -+ }; -+ - }; - - sfpb_mutex: sfpb-mutex { diff --git a/target/linux/ipq806x/patches-3.18/160-clk-qcom-Add-EBI2-clocks-for-IPQ806x.patch b/target/linux/ipq806x/patches-3.18/160-clk-qcom-Add-EBI2-clocks-for-IPQ806x.patch deleted file mode 100644 index 77d29d8ac43b..000000000000 --- a/target/linux/ipq806x/patches-3.18/160-clk-qcom-Add-EBI2-clocks-for-IPQ806x.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 4c385b25fab119144bffb255ad77712fe586ac10 Mon Sep 17 00:00:00 2001 -From: Archit Taneja -Date: Thu, 2 Apr 2015 11:20:41 +0530 -Subject: [PATCH] clk: qcom: Add EBI2 clocks for IPQ806x - -The NAND controller within EBI2 requires EBI2_CLK and -EBI2_ALWAYS_ON_CLK clocks. Create structs for these clocks so -that they can be used by the NAND controller driver. Add an entry -for EBI2_AON_CLK in the gcc-ipq806x DT binding document. - -Signed-off-by: Archit Taneja -Signed-off-by: Stephen Boyd ---- - drivers/clk/qcom/gcc-ipq806x.c | 32 ++++++++++++++++++++++++++++ - include/dt-bindings/clock/qcom,gcc-ipq806x.h | 1 + - 2 files changed, 33 insertions(+) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -2239,6 +2239,36 @@ static struct clk_branch usb_fs1_h_clk = - }, - }; - -+static struct clk_branch ebi2_clk = { -+ .hwcg_reg = 0x3b00, -+ .hwcg_bit = 6, -+ .halt_reg = 0x2fcc, -+ .halt_bit = 1, -+ .clkr = { -+ .enable_reg = 0x3b00, -+ .enable_mask = BIT(4), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ebi2_clk", -+ .ops = &clk_branch_ops, -+ .flags = CLK_IS_ROOT, -+ }, -+ }, -+}; -+ -+static struct clk_branch ebi2_aon_clk = { -+ .halt_reg = 0x2fcc, -+ .halt_bit = 0, -+ .clkr = { -+ .enable_reg = 0x3b00, -+ .enable_mask = BIT(8), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ebi2_always_on_clk", -+ .ops = &clk_branch_ops, -+ .flags = CLK_IS_ROOT, -+ }, -+ }, -+}; -+ - static struct clk_regmap *gcc_ipq806x_clks[] = { - [PLL0] = &pll0.clkr, - [PLL0_VOTE] = &pll0_vote, -@@ -2341,6 +2371,8 @@ static struct clk_regmap *gcc_ipq806x_cl - [USB_FS1_XCVR_SRC] = &usb_fs1_xcvr_clk_src.clkr, - [USB_FS1_XCVR_CLK] = &usb_fs1_xcvr_clk.clkr, - [USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr, -+ [EBI2_CLK] = &ebi2_clk.clkr, -+ [EBI2_AON_CLK] = &ebi2_aon_clk.clkr, - [PLL9] = &hfpll0.clkr, - [PLL10] = &hfpll1.clkr, - [PLL12] = &hfpll_l2.clkr, ---- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h -+++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h -@@ -289,5 +289,6 @@ - #define UBI32_CORE2_CLK_SRC 278 - #define UBI32_CORE1_CLK 279 - #define UBI32_CORE2_CLK 280 -+#define EBI2_AON_CLK 281 - - #endif diff --git a/target/linux/ipq806x/patches-3.18/161-mtd-nand-Create-a-BBT-flag-to-access-bad-block-markers-in-raw-mode.patch b/target/linux/ipq806x/patches-3.18/161-mtd-nand-Create-a-BBT-flag-to-access-bad-block-markers-in-raw-mode.patch deleted file mode 100644 index 3fb47850fc48..000000000000 --- a/target/linux/ipq806x/patches-3.18/161-mtd-nand-Create-a-BBT-flag-to-access-bad-block-markers-in-raw-mode.patch +++ /dev/null @@ -1,84 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3, - 1/5] mtd: nand: Create a BBT flag to access bad block markers in raw - mode -From: Archit Taneja -X-Patchwork-Id: 6927081 -Message-Id: <1438578498-32254-2-git-send-email-architt@codeaurora.org> -To: linux-mtd@lists.infradead.org, dehrenberg@google.com, - cernekee@gmail.com, computersforpeace@gmail.com -Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org, - sboyd@codeaurora.org, linux-kernel@vger.kernel.org, - Archit Taneja -Date: Mon, 3 Aug 2015 10:38:14 +0530 - -Some controllers can access the factory bad block marker from OOB only -when they read it in raw mode. When ECC is enabled, these controllers -discard reading/writing bad block markers, preventing access to them -altogether. - -The bbt driver assumes MTD_OPS_PLACE_OOB when scanning for bad blocks. -This results in the nand driver's ecc->read_oob() op to be called, which -works with ECC enabled. - -Create a new BBT option flag that tells nand_bbt to force the mode to -MTD_OPS_RAW. This would result in the correct op being called for the -underlying nand controller driver. - -Reviewed-by: Andy Gross -Signed-off-by: Archit Taneja - ---- -drivers/mtd/nand/nand_base.c | 6 +++++- - drivers/mtd/nand/nand_bbt.c | 6 +++++- - include/linux/mtd/bbm.h | 7 +++++++ - 3 files changed, 17 insertions(+), 2 deletions(-) - ---- a/drivers/mtd/nand/nand_base.c -+++ b/drivers/mtd/nand/nand_base.c -@@ -396,7 +396,11 @@ static int nand_default_block_markbad(st - } else { - ops.len = ops.ooblen = 1; - } -- ops.mode = MTD_OPS_PLACE_OOB; -+ -+ if (unlikely(chip->bbt_options & NAND_BBT_ACCESS_BBM_RAW)) -+ ops.mode = MTD_OPS_RAW; -+ else -+ ops.mode = MTD_OPS_PLACE_OOB; - - /* Write to first/last page(s) if necessary */ - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ---- a/drivers/mtd/nand/nand_bbt.c -+++ b/drivers/mtd/nand/nand_bbt.c -@@ -423,7 +423,11 @@ static int scan_block_fast(struct mtd_in - ops.oobbuf = buf; - ops.ooboffs = 0; - ops.datbuf = NULL; -- ops.mode = MTD_OPS_PLACE_OOB; -+ -+ if (unlikely(bd->options & NAND_BBT_ACCESS_BBM_RAW)) -+ ops.mode = MTD_OPS_RAW; -+ else -+ ops.mode = MTD_OPS_PLACE_OOB; - - for (j = 0; j < numpages; j++) { - /* ---- a/include/linux/mtd/bbm.h -+++ b/include/linux/mtd/bbm.h -@@ -116,6 +116,13 @@ struct nand_bbt_descr { - #define NAND_BBT_NO_OOB_BBM 0x00080000 - - /* -+ * Force MTD_OPS_RAW mode when trying to access bad block markes from OOB. To -+ * be used by controllers which can access BBM only when ECC is disabled, i.e, -+ * when in RAW access mode -+ */ -+#define NAND_BBT_ACCESS_BBM_RAW 0x00100000 -+ -+/* - * Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr - * was allocated dynamicaly and must be freed in nand_release(). Has no meaning - * in nand_chip.bbt_options. diff --git a/target/linux/ipq806x/patches-3.18/162-mtd-nand-Qualcomm-NAND-controller-driver.patch b/target/linux/ipq806x/patches-3.18/162-mtd-nand-Qualcomm-NAND-controller-driver.patch deleted file mode 100644 index 6172f7dec8be..000000000000 --- a/target/linux/ipq806x/patches-3.18/162-mtd-nand-Qualcomm-NAND-controller-driver.patch +++ /dev/null @@ -1,2024 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,2/5] mtd: nand: Qualcomm NAND controller driver -From: Archit Taneja -X-Patchwork-Id: 6927101 -Message-Id: <1438578498-32254-3-git-send-email-architt@codeaurora.org> -To: linux-mtd@lists.infradead.org, dehrenberg@google.com, - cernekee@gmail.com, computersforpeace@gmail.com -Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org, - sboyd@codeaurora.org, linux-kernel@vger.kernel.org, - Archit Taneja -Date: Mon, 3 Aug 2015 10:38:15 +0530 - -The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx, -MDM9x15 series. - -It exists as a sub block inside the IPs EBI2 (External Bus Interface 2) -and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a -broader interface for external slow peripheral devices such as LCD and -NAND/NOR flash memory or SRAM like interfaces. - -We add support for the NAND controller found within EBI2. For the SoCs -of our interest, we only use the NAND controller within EBI2. Therefore, -it's safe for us to assume that the NAND controller is a standalone block -within the SoC. - -The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND -flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and -16 bit correction/step) and RS ECC(4 bit correction/step) that covers main -and spare data. The controller contains an internal 512 byte page buffer -to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA -for register read/write and data transfers. The controller performs page -reads and writes at a codeword/step level of 512 bytes. It can support up -to 2 external chips of different configurations. - -The driver prepares register read and write configuration descriptors for -each codeword, followed by data descriptors to read or write data from the -controller's internal buffer. It uses a single ADM DMA channel that we get -via dmaengine API. The controller requires 2 ADM CRCIs for command and -data flow control. These are passed via DT. - -The ecc layout used by the controller is syndrome like, but we can't use -the standard syndrome ecc ops because of several reasons. First, the amount -of data bytes covered by ecc isn't same in each step. Second, writing to -free oob space requires us writing to the entire step in which the oob -lies. This forces us to create our own ecc ops. - -One more difference is how the controller accesses the bad block marker. -The controller ignores reading the marker when ECC is enabled. ECC needs -to be explicity disabled to read or write to the bad block marker. For -this reason, we use the newly created flag NAND_BBT_ACCESS_BBM_RAW to -read the factory provided bad block markers. - -v3: -- Refactor dma functions for maximum reuse -- Use dma_slave_confing on stack -- optimize and clean upempty_page_fixup using memchr_inv -- ensure portability with dma register reads using le32_* funcs -- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves -- fix handling of return values of dmaengine funcs -- constify wherever possible -- Remove dependency on ADM DMA in Kconfig -- Misc fixes and clean ups - -v2: -- Use new BBT flag that allows us to read BBM in raw mode -- reduce memcpy-s in the driver -- some refactor and clean ups because of above changes - -Reviewed-by: Andy Gross -Signed-off-by: Archit Taneja - ---- -drivers/mtd/nand/Kconfig | 7 + - drivers/mtd/nand/Makefile | 1 + - drivers/mtd/nand/qcom_nandc.c | 1913 +++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 1921 insertions(+) - create mode 100644 drivers/mtd/nand/qcom_nandc.c - ---- a/drivers/mtd/nand/Kconfig -+++ b/drivers/mtd/nand/Kconfig -@@ -516,4 +516,11 @@ config MTD_NAND_XWAY - Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached - to the External Bus Unit (EBU). - -+config MTD_NAND_QCOM -+ tristate "Support for NAND on QCOM SoCs" -+ depends on ARCH_QCOM -+ help -+ Enables support for NAND flash chips on SoCs containing the EBI2 NAND -+ controller. This controller is found on IPQ806x SoC. -+ - endif # MTD_NAND ---- /dev/null -+++ b/drivers/mtd/nand/qcom_nandc.c -@@ -0,0 +1,1918 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* NANDc reg offsets */ -+#define NAND_FLASH_CMD 0x00 -+#define NAND_ADDR0 0x04 -+#define NAND_ADDR1 0x08 -+#define NAND_FLASH_CHIP_SELECT 0x0c -+#define NAND_EXEC_CMD 0x10 -+#define NAND_FLASH_STATUS 0x14 -+#define NAND_BUFFER_STATUS 0x18 -+#define NAND_DEV0_CFG0 0x20 -+#define NAND_DEV0_CFG1 0x24 -+#define NAND_DEV0_ECC_CFG 0x28 -+#define NAND_DEV1_ECC_CFG 0x2c -+#define NAND_DEV1_CFG0 0x30 -+#define NAND_DEV1_CFG1 0x34 -+#define NAND_READ_ID 0x40 -+#define NAND_READ_STATUS 0x44 -+#define NAND_DEV_CMD0 0xa0 -+#define NAND_DEV_CMD1 0xa4 -+#define NAND_DEV_CMD2 0xa8 -+#define NAND_DEV_CMD_VLD 0xac -+#define SFLASHC_BURST_CFG 0xe0 -+#define NAND_ERASED_CW_DETECT_CFG 0xe8 -+#define NAND_ERASED_CW_DETECT_STATUS 0xec -+#define NAND_EBI2_ECC_BUF_CFG 0xf0 -+#define FLASH_BUF_ACC 0x100 -+ -+#define NAND_CTRL 0xf00 -+#define NAND_VERSION 0xf08 -+#define NAND_READ_LOCATION_0 0xf20 -+#define NAND_READ_LOCATION_1 0xf24 -+ -+/* dummy register offsets, used by write_reg_dma */ -+#define NAND_DEV_CMD1_RESTORE 0xdead -+#define NAND_DEV_CMD_VLD_RESTORE 0xbeef -+ -+/* NAND_FLASH_CMD bits */ -+#define PAGE_ACC BIT(4) -+#define LAST_PAGE BIT(5) -+ -+/* NAND_FLASH_CHIP_SELECT bits */ -+#define NAND_DEV_SEL 0 -+#define DM_EN BIT(2) -+ -+/* NAND_FLASH_STATUS bits */ -+#define FS_OP_ERR BIT(4) -+#define FS_READY_BSY_N BIT(5) -+#define FS_MPU_ERR BIT(8) -+#define FS_DEVICE_STS_ERR BIT(16) -+#define FS_DEVICE_WP BIT(23) -+ -+/* NAND_BUFFER_STATUS bits */ -+#define BS_UNCORRECTABLE_BIT BIT(8) -+#define BS_CORRECTABLE_ERR_MSK 0x1f -+ -+/* NAND_DEVn_CFG0 bits */ -+#define DISABLE_STATUS_AFTER_WRITE 4 -+#define CW_PER_PAGE 6 -+#define UD_SIZE_BYTES 9 -+#define ECC_PARITY_SIZE_BYTES_RS 19 -+#define SPARE_SIZE_BYTES 23 -+#define NUM_ADDR_CYCLES 27 -+#define STATUS_BFR_READ 30 -+#define SET_RD_MODE_AFTER_STATUS 31 -+ -+/* NAND_DEVn_CFG0 bits */ -+#define DEV0_CFG1_ECC_DISABLE 0 -+#define WIDE_FLASH 1 -+#define NAND_RECOVERY_CYCLES 2 -+#define CS_ACTIVE_BSY 5 -+#define BAD_BLOCK_BYTE_NUM 6 -+#define BAD_BLOCK_IN_SPARE_AREA 16 -+#define WR_RD_BSY_GAP 17 -+#define ENABLE_BCH_ECC 27 -+ -+/* NAND_DEV0_ECC_CFG bits */ -+#define ECC_CFG_ECC_DISABLE 0 -+#define ECC_SW_RESET 1 -+#define ECC_MODE 4 -+#define ECC_PARITY_SIZE_BYTES_BCH 8 -+#define ECC_NUM_DATA_BYTES 16 -+#define ECC_FORCE_CLK_OPEN 30 -+ -+/* NAND_DEV_CMD1 bits */ -+#define READ_ADDR 0 -+ -+/* NAND_DEV_CMD_VLD bits */ -+#define READ_START_VLD 0 -+ -+/* NAND_EBI2_ECC_BUF_CFG bits */ -+#define NUM_STEPS 0 -+ -+/* NAND_ERASED_CW_DETECT_CFG bits */ -+#define ERASED_CW_ECC_MASK 1 -+#define AUTO_DETECT_RES 0 -+#define MASK_ECC (1 << ERASED_CW_ECC_MASK) -+#define RESET_ERASED_DET (1 << AUTO_DETECT_RES) -+#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) -+#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) -+#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) -+ -+/* NAND_ERASED_CW_DETECT_STATUS bits */ -+#define PAGE_ALL_ERASED BIT(7) -+#define CODEWORD_ALL_ERASED BIT(6) -+#define PAGE_ERASED BIT(5) -+#define CODEWORD_ERASED BIT(4) -+#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED) -+#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED) -+ -+/* Version Mask */ -+#define NAND_VERSION_MAJOR_MASK 0xf0000000 -+#define NAND_VERSION_MAJOR_SHIFT 28 -+#define NAND_VERSION_MINOR_MASK 0x0fff0000 -+#define NAND_VERSION_MINOR_SHIFT 16 -+ -+/* NAND OP_CMDs */ -+#define PAGE_READ 0x2 -+#define PAGE_READ_WITH_ECC 0x3 -+#define PAGE_READ_WITH_ECC_SPARE 0x4 -+#define PROGRAM_PAGE 0x6 -+#define PAGE_PROGRAM_WITH_ECC 0x7 -+#define PROGRAM_PAGE_SPARE 0x9 -+#define BLOCK_ERASE 0xa -+#define FETCH_ID 0xb -+#define RESET_DEVICE 0xd -+ -+/* -+ * the NAND controller performs reads/writes with ECC in 516 byte chunks. -+ * the driver calls the chunks 'step' or 'codeword' interchangeably -+ */ -+#define NANDC_STEP_SIZE 512 -+ -+/* -+ * the largest page size we support is 8K, this will have 16 steps/codewords -+ * of 512 bytes each -+ */ -+#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE) -+ -+/* we read at most 3 registers per codeword scan */ -+#define MAX_REG_RD (3 * MAX_NUM_STEPS) -+ -+/* ECC modes */ -+#define ECC_NONE BIT(0) -+#define ECC_RS_4BIT BIT(1) -+#define ECC_BCH_4BIT BIT(2) -+#define ECC_BCH_8BIT BIT(3) -+ -+struct desc_info { -+ struct list_head list; -+ -+ enum dma_transfer_direction dir; -+ struct scatterlist sgl; -+ struct dma_async_tx_descriptor *dma_desc; -+}; -+ -+/* -+ * holds the current register values that we want to write. acts as a contiguous -+ * chunk of memory which we use to write the controller registers through DMA. -+ */ -+struct nandc_regs { -+ u32 cmd; -+ u32 addr0; -+ u32 addr1; -+ u32 chip_sel; -+ u32 exec; -+ -+ u32 cfg0; -+ u32 cfg1; -+ u32 ecc_bch_cfg; -+ -+ u32 clrflashstatus; -+ u32 clrreadstatus; -+ -+ u32 cmd1; -+ u32 vld; -+ -+ u32 orig_cmd1; -+ u32 orig_vld; -+ -+ u32 ecc_buf_cfg; -+}; -+ -+/* -+ * @cmd_crci: ADM DMA CRCI for command flow control -+ * @data_crci: ADM DMA CRCI for data flow control -+ * @list: DMA descriptor list (list of desc_infos) -+ * @dma_done: completion param to denote end of last -+ * descriptor in the list -+ * @data_buffer: our local DMA buffer for page read/writes, -+ * used when we can't use the buffer provided -+ * by upper layers directly -+ * @buf_size/count/start: markers for chip->read_buf/write_buf functions -+ * @reg_read_buf: buffer for reading register data via DMA -+ * @reg_read_pos: marker for data read in reg_read_buf -+ * @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for -+ * ecc/non-ecc mode for the current nand flash -+ * device -+ * @regs: a contiguous chunk of memory for DMA register -+ * writes -+ * @ecc_strength: 4 bit or 8 bit ecc, received via DT -+ * @bus_width: 8 bit or 16 bit NAND bus width, received via DT -+ * @ecc_modes: supported ECC modes by the current controller, -+ * initialized via DT match data -+ * @cw_size: the number of bytes in a single step/codeword -+ * of a page, consisting of all data, ecc, spare -+ * and reserved bytes -+ * @cw_data: the number of bytes within a codeword protected -+ * by ECC -+ * @bch_enabled: flag to tell whether BCH or RS ECC mode is used -+ * @status: value to be returned if NAND_CMD_STATUS command -+ * is executed -+ */ -+struct qcom_nandc_data { -+ struct platform_device *pdev; -+ struct device *dev; -+ -+ void __iomem *base; -+ struct resource *res; -+ -+ struct clk *core_clk; -+ struct clk *aon_clk; -+ -+ /* DMA stuff */ -+ struct dma_chan *chan; -+ struct dma_slave_config slave_conf; -+ unsigned int cmd_crci; -+ unsigned int data_crci; -+ struct list_head list; -+ struct completion dma_done; -+ -+ /* MTD stuff */ -+ struct nand_chip chip; -+ struct mtd_info mtd; -+ -+ /* local data buffer and markers */ -+ u8 *data_buffer; -+ int buf_size; -+ int buf_count; -+ int buf_start; -+ -+ /* local buffer to read back registers */ -+ u32 *reg_read_buf; -+ int reg_read_pos; -+ -+ /* required configs */ -+ u32 cfg0, cfg1; -+ u32 cfg0_raw, cfg1_raw; -+ u32 ecc_buf_cfg; -+ u32 ecc_bch_cfg; -+ u32 clrflashstatus; -+ u32 clrreadstatus; -+ u32 sflashc_burst_cfg; -+ u32 cmd1, vld; -+ -+ /* register state */ -+ struct nandc_regs *regs; -+ -+ /* things we get from DT */ -+ int ecc_strength; -+ int bus_width; -+ -+ u32 ecc_modes; -+ -+ /* misc params */ -+ int cw_size; -+ int cw_data; -+ bool use_ecc; -+ bool bch_enabled; -+ u8 status; -+ int last_command; -+}; -+ -+static inline u32 nandc_read(struct qcom_nandc_data *this, int offset) -+{ -+ return ioread32(this->base + offset); -+} -+ -+static inline void nandc_write(struct qcom_nandc_data *this, int offset, -+ u32 val) -+{ -+ iowrite32(val, this->base + offset); -+} -+ -+/* helper to configure address register values */ -+static void set_address(struct qcom_nandc_data *this, u16 column, int page) -+{ -+ struct nand_chip *chip = &this->chip; -+ struct nandc_regs *regs = this->regs; -+ -+ if (chip->options & NAND_BUSWIDTH_16) -+ column >>= 1; -+ -+ regs->addr0 = page << 16 | column; -+ regs->addr1 = page >> 16 & 0xff; -+} -+ -+/* -+ * update_rw_regs: set up read/write register values, these will be -+ * written to the NAND controller registers via DMA -+ * -+ * @num_cw: number of steps for the read/write operation -+ * @read: read or write operation -+ */ -+static void update_rw_regs(struct qcom_nandc_data *this, int num_cw, bool read) -+{ -+ struct nandc_regs *regs = this->regs; -+ -+ if (read) { -+ if (this->use_ecc) -+ regs->cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE; -+ else -+ regs->cmd = PAGE_READ | PAGE_ACC | LAST_PAGE; -+ } else { -+ regs->cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE; -+ } -+ -+ if (this->use_ecc) { -+ regs->cfg0 = (this->cfg0 & ~(7U << CW_PER_PAGE)) | -+ (num_cw - 1) << CW_PER_PAGE; -+ -+ regs->cfg1 = this->cfg1; -+ regs->ecc_bch_cfg = this->ecc_bch_cfg; -+ } else { -+ regs->cfg0 = (this->cfg0_raw & ~(7U << CW_PER_PAGE)) | -+ (num_cw - 1) << CW_PER_PAGE; -+ -+ regs->cfg1 = this->cfg1_raw; -+ regs->ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; -+ } -+ -+ regs->ecc_buf_cfg = this->ecc_buf_cfg; -+ regs->clrflashstatus = this->clrflashstatus; -+ regs->clrreadstatus = this->clrreadstatus; -+ regs->exec = 1; -+} -+ -+static int prep_dma_desc(struct qcom_nandc_data *this, bool read, int reg_off, -+ const void *vaddr, int size, bool flow_control) -+{ -+ struct desc_info *desc; -+ struct dma_async_tx_descriptor *dma_desc; -+ struct scatterlist *sgl; -+ struct dma_slave_config slave_conf; -+ int r; -+ -+ desc = kzalloc(sizeof(*desc), GFP_KERNEL); -+ if (!desc) -+ return -ENOMEM; -+ -+ list_add_tail(&desc->list, &this->list); -+ -+ sgl = &desc->sgl; -+ -+ sg_init_one(sgl, vaddr, size); -+ -+ desc->dir = read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; -+ -+ r = dma_map_sg(this->dev, sgl, 1, desc->dir); -+ if (r == 0) { -+ r = -ENOMEM; -+ goto err; -+ } -+ -+ memset(&slave_conf, 0x00, sizeof(slave_conf)); -+ -+ slave_conf.device_fc = flow_control; -+ if (read) { -+ slave_conf.src_maxburst = 16; -+ slave_conf.src_addr = this->res->start + reg_off; -+ slave_conf.slave_id = this->data_crci; -+ } else { -+ slave_conf.dst_maxburst = 16; -+ slave_conf.dst_addr = this->res->start + reg_off; -+ slave_conf.slave_id = this->cmd_crci; -+ } -+ -+ r = dmaengine_slave_config(this->chan, &slave_conf); -+ if (r) { -+ dev_err(this->dev, "failed to configure dma channel\n"); -+ goto err; -+ } -+ -+ dma_desc = dmaengine_prep_slave_sg(this->chan, sgl, 1, desc->dir, 0); -+ if (!dma_desc) { -+ dev_err(this->dev, "failed to prepare desc\n"); -+ r = -EINVAL; -+ goto err; -+ } -+ -+ desc->dma_desc = dma_desc; -+ -+ return 0; -+err: -+ kfree(desc); -+ -+ return r; -+} -+ -+/* -+ * read_reg_dma: prepares a descriptor to read a given number of -+ * contiguous registers to the reg_read_buf pointer -+ * -+ * @first: offset of the first register in the contiguous block -+ * @num_regs: number of registers to read -+ */ -+static int read_reg_dma(struct qcom_nandc_data *this, int first, int num_regs) -+{ -+ bool flow_control = false; -+ void *vaddr; -+ int size; -+ -+ if (first == NAND_READ_ID || first == NAND_FLASH_STATUS) -+ flow_control = true; -+ -+ size = num_regs * sizeof(u32); -+ vaddr = this->reg_read_buf + this->reg_read_pos; -+ this->reg_read_pos += num_regs; -+ -+ return prep_dma_desc(this, true, first, vaddr, size, flow_control); -+} -+ -+/* -+ * write_reg_dma: prepares a descriptor to write a given number of -+ * contiguous registers -+ * -+ * @first: offset of the first register in the contiguous block -+ * @num_regs: number of registers to write -+ */ -+static int write_reg_dma(struct qcom_nandc_data *this, int first, int num_regs) -+{ -+ bool flow_control = false; -+ struct nandc_regs *regs = this->regs; -+ void *vaddr; -+ int size; -+ -+ switch (first) { -+ case NAND_FLASH_CMD: -+ vaddr = ®s->cmd; -+ flow_control = true; -+ break; -+ case NAND_EXEC_CMD: -+ vaddr = ®s->exec; -+ break; -+ case NAND_FLASH_STATUS: -+ vaddr = ®s->clrflashstatus; -+ break; -+ case NAND_DEV0_CFG0: -+ vaddr = ®s->cfg0; -+ break; -+ case NAND_READ_STATUS: -+ vaddr = ®s->clrreadstatus; -+ break; -+ case NAND_DEV_CMD1: -+ vaddr = ®s->cmd1; -+ break; -+ case NAND_DEV_CMD1_RESTORE: -+ first = NAND_DEV_CMD1; -+ vaddr = ®s->orig_cmd1; -+ break; -+ case NAND_DEV_CMD_VLD: -+ vaddr = ®s->vld; -+ break; -+ case NAND_DEV_CMD_VLD_RESTORE: -+ first = NAND_DEV_CMD_VLD; -+ vaddr = ®s->orig_vld; -+ break; -+ case NAND_EBI2_ECC_BUF_CFG: -+ vaddr = ®s->ecc_buf_cfg; -+ break; -+ default: -+ dev_err(this->dev, "invalid starting register\n"); -+ return -EINVAL; -+ } -+ -+ size = num_regs * sizeof(u32); -+ -+ return prep_dma_desc(this, false, first, vaddr, size, flow_control); -+} -+ -+/* -+ * read_data_dma: prepares a DMA descriptor to transfer data from the -+ * controller's internal buffer to the buffer 'vaddr' -+ * -+ * @reg_off: offset within the controller's data buffer -+ * @vaddr: virtual address of the buffer we want to write to -+ * @size: DMA transaction size in bytes -+ */ -+static int read_data_dma(struct qcom_nandc_data *this, int reg_off, -+ const u8 *vaddr, int size) -+{ -+ return prep_dma_desc(this, true, reg_off, vaddr, size, false); -+} -+ -+/* -+ * write_data_dma: prepares a DMA descriptor to transfer data from -+ * 'vaddr' to the controller's internal buffer -+ * -+ * @reg_off: offset within the controller's data buffer -+ * @vaddr: virtual address of the buffer we want to read from -+ * @size: DMA transaction size in bytes -+ */ -+static int write_data_dma(struct qcom_nandc_data *this, int reg_off, -+ const u8 *vaddr, int size) -+{ -+ return prep_dma_desc(this, false, reg_off, vaddr, size, false); -+} -+ -+/* -+ * helper to prepare dma descriptors to configure registers needed for reading a -+ * codeword/step in a page -+ */ -+static void config_cw_read(struct qcom_nandc_data *this) -+{ -+ write_reg_dma(this, NAND_FLASH_CMD, 3); -+ write_reg_dma(this, NAND_DEV0_CFG0, 3); -+ write_reg_dma(this, NAND_EBI2_ECC_BUF_CFG, 1); -+ -+ write_reg_dma(this, NAND_EXEC_CMD, 1); -+ -+ read_reg_dma(this, NAND_FLASH_STATUS, 2); -+ read_reg_dma(this, NAND_ERASED_CW_DETECT_STATUS, 1); -+} -+ -+/* -+ * helpers to prepare dma descriptors used to configure registers needed for -+ * writing a codeword/step in a page -+ */ -+static void config_cw_write_pre(struct qcom_nandc_data *this) -+{ -+ write_reg_dma(this, NAND_FLASH_CMD, 3); -+ write_reg_dma(this, NAND_DEV0_CFG0, 3); -+ write_reg_dma(this, NAND_EBI2_ECC_BUF_CFG, 1); -+} -+ -+static void config_cw_write_post(struct qcom_nandc_data *this) -+{ -+ write_reg_dma(this, NAND_EXEC_CMD, 1); -+ -+ read_reg_dma(this, NAND_FLASH_STATUS, 1); -+ -+ write_reg_dma(this, NAND_FLASH_STATUS, 1); -+ write_reg_dma(this, NAND_READ_STATUS, 1); -+} -+ -+/* -+ * the following functions are used within chip->cmdfunc() to perform different -+ * NAND_CMD_* commands -+ */ -+ -+/* sets up descriptors for NAND_CMD_PARAM */ -+static int nandc_param(struct qcom_nandc_data *this) -+{ -+ struct nandc_regs *regs = this->regs; -+ -+ /* -+ * NAND_CMD_PARAM is called before we know much about the FLASH chip -+ * in use. we configure the controller to perform a raw read of 512 -+ * bytes to read onfi params -+ */ -+ regs->cmd = PAGE_READ | PAGE_ACC | LAST_PAGE; -+ regs->addr0 = 0; -+ regs->addr1 = 0; -+ regs->cfg0 = 0 << CW_PER_PAGE -+ | 512 << UD_SIZE_BYTES -+ | 5 << NUM_ADDR_CYCLES -+ | 0 << SPARE_SIZE_BYTES; -+ -+ regs->cfg1 = 7 << NAND_RECOVERY_CYCLES -+ | 0 << CS_ACTIVE_BSY -+ | 17 << BAD_BLOCK_BYTE_NUM -+ | 1 << BAD_BLOCK_IN_SPARE_AREA -+ | 2 << WR_RD_BSY_GAP -+ | 0 << WIDE_FLASH -+ | 1 << DEV0_CFG1_ECC_DISABLE; -+ -+ regs->ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; -+ -+ /* configure CMD1 and VLD for ONFI param probing */ -+ regs->vld = (this->vld & ~(1 << READ_START_VLD)) -+ | 0 << READ_START_VLD; -+ -+ regs->cmd1 = (this->cmd1 & ~(0xFF << READ_ADDR)) -+ | NAND_CMD_PARAM << READ_ADDR; -+ -+ regs->exec = 1; -+ -+ regs->orig_cmd1 = this->cmd1; -+ regs->orig_vld = this->vld; -+ -+ write_reg_dma(this, NAND_DEV_CMD_VLD, 1); -+ write_reg_dma(this, NAND_DEV_CMD1, 1); -+ -+ this->buf_count = 512; -+ memset(this->data_buffer, 0xff, this->buf_count); -+ -+ config_cw_read(this); -+ -+ read_data_dma(this, FLASH_BUF_ACC, this->data_buffer, this->buf_count); -+ -+ /* restore CMD1 and VLD regs */ -+ write_reg_dma(this, NAND_DEV_CMD1_RESTORE, 1); -+ write_reg_dma(this, NAND_DEV_CMD_VLD_RESTORE, 1); -+ -+ return 0; -+} -+ -+/* sets up descriptors for NAND_CMD_ERASE1 */ -+static int erase_block(struct qcom_nandc_data *this, int page_addr) -+{ -+ struct nandc_regs *regs = this->regs; -+ -+ regs->cmd = BLOCK_ERASE | PAGE_ACC | LAST_PAGE; -+ regs->addr0 = page_addr; -+ regs->addr1 = 0; -+ regs->cfg0 = this->cfg0_raw & ~(7 << CW_PER_PAGE); -+ regs->cfg1 = this->cfg1_raw; -+ regs->exec = 1; -+ regs->clrflashstatus = this->clrflashstatus; -+ regs->clrreadstatus = this->clrreadstatus; -+ -+ write_reg_dma(this, NAND_FLASH_CMD, 3); -+ write_reg_dma(this, NAND_DEV0_CFG0, 2); -+ write_reg_dma(this, NAND_EXEC_CMD, 1); -+ -+ read_reg_dma(this, NAND_FLASH_STATUS, 1); -+ -+ write_reg_dma(this, NAND_FLASH_STATUS, 1); -+ write_reg_dma(this, NAND_READ_STATUS, 1); -+ -+ return 0; -+} -+ -+/* sets up descriptors for NAND_CMD_READID */ -+static int read_id(struct qcom_nandc_data *this, int column) -+{ -+ struct nandc_regs *regs = this->regs; -+ -+ if (column == -1) -+ return 0; -+ -+ regs->cmd = FETCH_ID; -+ regs->addr0 = column; -+ regs->addr1 = 0; -+ regs->chip_sel = DM_EN; -+ regs->exec = 1; -+ -+ write_reg_dma(this, NAND_FLASH_CMD, 4); -+ write_reg_dma(this, NAND_EXEC_CMD, 1); -+ -+ read_reg_dma(this, NAND_READ_ID, 1); -+ -+ return 0; -+} -+ -+/* sets up descriptors for NAND_CMD_RESET */ -+static int reset(struct qcom_nandc_data *this) -+{ -+ struct nandc_regs *regs = this->regs; -+ -+ regs->cmd = RESET_DEVICE; -+ regs->exec = 1; -+ -+ write_reg_dma(this, NAND_FLASH_CMD, 1); -+ write_reg_dma(this, NAND_EXEC_CMD, 1); -+ -+ read_reg_dma(this, NAND_FLASH_STATUS, 1); -+ -+ return 0; -+} -+ -+/* helpers to submit/free our list of dma descriptors */ -+static void dma_callback(void *param) -+{ -+ struct qcom_nandc_data *this = param; -+ struct completion *c = &this->dma_done; -+ -+ complete(c); -+} -+ -+static int submit_descs(struct qcom_nandc_data *this) -+{ -+ struct completion *c = &this->dma_done; -+ struct desc_info *desc; -+ int r; -+ -+ init_completion(c); -+ -+ list_for_each_entry(desc, &this->list, list) { -+ /* -+ * we add a callback to the last descriptor in our list to -+ * notify completion of command -+ */ -+ if (list_is_last(&desc->list, &this->list)) { -+ desc->dma_desc->callback = dma_callback; -+ desc->dma_desc->callback_param = this; -+ } -+ -+ dmaengine_submit(desc->dma_desc); -+ } -+ -+ dma_async_issue_pending(this->chan); -+ -+ r = wait_for_completion_timeout(c, msecs_to_jiffies(500)); -+ if (!r) -+ return -ETIMEDOUT; -+ -+ return 0; -+} -+ -+static void free_descs(struct qcom_nandc_data *this) -+{ -+ struct desc_info *desc, *n; -+ -+ list_for_each_entry_safe(desc, n, &this->list, list) { -+ list_del(&desc->list); -+ dma_unmap_sg(this->dev, &desc->sgl, 1, desc->dir); -+ kfree(desc); -+ } -+} -+ -+/* reset the register read buffer for next NAND operation */ -+static void clear_read_regs(struct qcom_nandc_data *this) -+{ -+ this->reg_read_pos = 0; -+ memset(this->reg_read_buf, 0, MAX_REG_RD * sizeof(*this->reg_read_buf)); -+} -+ -+static void pre_command(struct qcom_nandc_data *this, int command) -+{ -+ this->buf_count = 0; -+ this->buf_start = 0; -+ this->use_ecc = false; -+ this->last_command = command; -+ -+ clear_read_regs(this); -+} -+ -+/* -+ * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our -+ * privately maintained status byte, this status byte can be read after -+ * NAND_CMD_STATUS is called -+ */ -+static void parse_erase_write_errors(struct qcom_nandc_data *this, int command) -+{ -+ struct nand_chip *chip = &this->chip; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ int num_cw; -+ int i; -+ -+ num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1; -+ -+ for (i = 0; i < num_cw; i++) { -+ __le32 flash_status = le32_to_cpu(this->reg_read_buf[i]); -+ -+ if (flash_status & FS_MPU_ERR) -+ this->status &= ~NAND_STATUS_WP; -+ -+ if (flash_status & FS_OP_ERR || (i == (num_cw - 1) && -+ (flash_status & FS_DEVICE_STS_ERR))) -+ this->status |= NAND_STATUS_FAIL; -+ } -+} -+ -+static void post_command(struct qcom_nandc_data *this, int command) -+{ -+ switch (command) { -+ case NAND_CMD_READID: -+ memcpy(this->data_buffer, this->reg_read_buf, this->buf_count); -+ break; -+ case NAND_CMD_PAGEPROG: -+ case NAND_CMD_ERASE1: -+ parse_erase_write_errors(this, command); -+ break; -+ default: -+ break; -+ } -+} -+ -+/* -+ * Implements chip->cmdfunc. It's only used for a limited set of commands. -+ * The rest of the commands wouldn't be called by upper layers. For example, -+ * NAND_CMD_READOOB would never be called because we have our own versions -+ * of read_oob ops for nand_ecc_ctrl. -+ */ -+static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command, -+ int column, int page_addr) -+{ -+ struct nand_chip *chip = mtd->priv; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ struct qcom_nandc_data *this = chip->priv; -+ bool wait = false; -+ int r = 0; -+ -+ pre_command(this, command); -+ -+ switch (command) { -+ case NAND_CMD_RESET: -+ r = reset(this); -+ wait = true; -+ break; -+ -+ case NAND_CMD_READID: -+ this->buf_count = 4; -+ r = read_id(this, column); -+ wait = true; -+ break; -+ -+ case NAND_CMD_PARAM: -+ r = nandc_param(this); -+ wait = true; -+ break; -+ -+ case NAND_CMD_ERASE1: -+ r = erase_block(this, page_addr); -+ wait = true; -+ break; -+ -+ case NAND_CMD_READ0: -+ /* we read the entire page for now */ -+ WARN_ON(column != 0); -+ -+ this->use_ecc = true; -+ set_address(this, 0, page_addr); -+ update_rw_regs(this, ecc->steps, true); -+ break; -+ -+ case NAND_CMD_SEQIN: -+ WARN_ON(column != 0); -+ set_address(this, 0, page_addr); -+ break; -+ -+ case NAND_CMD_PAGEPROG: -+ case NAND_CMD_STATUS: -+ case NAND_CMD_NONE: -+ default: -+ break; -+ } -+ -+ if (r) { -+ dev_err(this->dev, "failure executing command %d\n", -+ command); -+ free_descs(this); -+ return; -+ } -+ -+ if (wait) { -+ r = submit_descs(this); -+ if (r) -+ dev_err(this->dev, -+ "failure submitting descs for command %d\n", -+ command); -+ } -+ -+ free_descs(this); -+ -+ post_command(this, command); -+} -+ -+/* -+ * when using RS ECC, the NAND controller flags an error when reading an -+ * erased page. however, there are special characters at certain offsets when -+ * we read the erased page. we check here if the page is really empty. if so, -+ * we replace the magic characters with 0xffs -+ */ -+static bool empty_page_fixup(struct qcom_nandc_data *this, u8 *data_buf) -+{ -+ struct mtd_info *mtd = &this->mtd; -+ struct nand_chip *chip = &this->chip; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ int cwperpage = ecc->steps; -+ u8 orig1[MAX_NUM_STEPS], orig2[MAX_NUM_STEPS]; -+ int i, j; -+ -+ /* if BCH is enabled, HW will take care of detecting erased pages */ -+ if (this->bch_enabled || !this->use_ecc) -+ return false; -+ -+ for (i = 0; i < cwperpage; i++) { -+ u8 *empty1, *empty2; -+ __le32 flash_status = le32_to_cpu(this->reg_read_buf[3 * i]); -+ -+ /* -+ * an erased page flags an error in NAND_FLASH_STATUS, check if -+ * the page is erased by looking for 0x54s at offsets 3 and 175 -+ * from the beginning of each codeword -+ */ -+ if (!(flash_status & FS_OP_ERR)) -+ break; -+ -+ empty1 = &data_buf[3 + i * this->cw_data]; -+ empty2 = &data_buf[175 + i * this->cw_data]; -+ -+ /* -+ * if the error wasn't because of an erased page, bail out and -+ * and let someone else do the error checking -+ */ -+ if ((*empty1 == 0x54 && *empty2 == 0xff) || -+ (*empty1 == 0xff && *empty2 == 0x54)) { -+ orig1[i] = *empty1; -+ orig2[i] = *empty2; -+ -+ *empty1 = 0xff; -+ *empty2 = 0xff; -+ } else { -+ break; -+ } -+ } -+ -+ if (i < cwperpage || memchr_inv(data_buf, 0xff, mtd->writesize)) -+ goto not_empty; -+ -+ /* -+ * tell the caller that the page was empty and is fixed up, so that -+ * parse_read_errors() doesn't think it's an error -+ */ -+ return true; -+ -+not_empty: -+ /* restore original values if not empty*/ -+ for (j = 0; j < i; j++) { -+ data_buf[3 + j * this->cw_data] = orig1[j]; -+ data_buf[175 + j * this->cw_data] = orig2[j]; -+ } -+ -+ return false; -+} -+ -+struct read_stats { -+ __le32 flash; -+ __le32 buffer; -+ __le32 erased_cw; -+}; -+ -+/* -+ * reads back status registers set by the controller to notify page read -+ * errors. this is equivalent to what 'ecc->correct()' would do. -+ */ -+static int parse_read_errors(struct qcom_nandc_data *this, bool erased_page) -+{ -+ struct mtd_info *mtd = &this->mtd; -+ struct nand_chip *chip = &this->chip; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ int cwperpage = ecc->steps; -+ unsigned int max_bitflips = 0; -+ int i; -+ -+ for (i = 0; i < cwperpage; i++) { -+ int stat; -+ struct read_stats *buf; -+ -+ buf = (struct read_stats *) (this->reg_read_buf + 3 * i); -+ -+ buf->flash = le32_to_cpu(buf->flash); -+ buf->buffer = le32_to_cpu(buf->buffer); -+ buf->erased_cw = le32_to_cpu(buf->erased_cw); -+ -+ if (buf->flash & (FS_OP_ERR | FS_MPU_ERR)) { -+ -+ /* ignore erased codeword errors */ -+ if (this->bch_enabled) { -+ if ((buf->erased_cw & ERASED_CW) == ERASED_CW) -+ continue; -+ } else if (erased_page) { -+ continue; -+ } -+ -+ if (buf->buffer & BS_UNCORRECTABLE_BIT) { -+ mtd->ecc_stats.failed++; -+ continue; -+ } -+ } -+ -+ stat = buf->buffer & BS_CORRECTABLE_ERR_MSK; -+ mtd->ecc_stats.corrected += stat; -+ -+ max_bitflips = max_t(unsigned int, max_bitflips, stat); -+ } -+ -+ return max_bitflips; -+} -+ -+/* -+ * helper to perform the actual page read operation, used by ecc->read_page() -+ * and ecc->read_oob() -+ */ -+static int read_page_low(struct qcom_nandc_data *this, u8 *data_buf, -+ u8 *oob_buf) -+{ -+ struct nand_chip *chip = &this->chip; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ int i, r; -+ -+ /* queue cmd descs for each codeword */ -+ for (i = 0; i < ecc->steps; i++) { -+ int data_size, oob_size; -+ -+ if (i == (ecc->steps - 1)) { -+ data_size = ecc->size - ((ecc->steps - 1) << 2); -+ oob_size = (ecc->steps << 2) + ecc->bytes; -+ } else { -+ data_size = this->cw_data; -+ oob_size = ecc->bytes; -+ } -+ -+ config_cw_read(this); -+ -+ if (data_buf) -+ read_data_dma(this, FLASH_BUF_ACC, data_buf, data_size); -+ -+ if (oob_buf) -+ read_data_dma(this, FLASH_BUF_ACC + data_size, oob_buf, -+ oob_size); -+ -+ if (data_buf) -+ data_buf += data_size; -+ if (oob_buf) -+ oob_buf += oob_size; -+ } -+ -+ r = submit_descs(this); -+ if (r) -+ dev_err(this->dev, "failure to read page/oob\n"); -+ -+ free_descs(this); -+ -+ return r; -+} -+ -+/* -+ * a helper that copies the last step/codeword of a page (containing free oob) -+ * into our local buffer -+ */ -+static int copy_last_cw(struct qcom_nandc_data *this, bool use_ecc, int page) -+{ -+ struct nand_chip *chip = &this->chip; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ int size; -+ int r; -+ -+ clear_read_regs(this); -+ -+ size = use_ecc ? this->cw_data : this->cw_size; -+ -+ /* prepare a clean read buffer */ -+ memset(this->data_buffer, 0xff, size); -+ -+ this->use_ecc = use_ecc; -+ set_address(this, this->cw_size * (ecc->steps - 1), page); -+ update_rw_regs(this, 1, true); -+ -+ config_cw_read(this); -+ -+ read_data_dma(this, FLASH_BUF_ACC, this->data_buffer, size); -+ -+ r = submit_descs(this); -+ if (r) -+ dev_err(this->dev, "failed to copy last codeword\n"); -+ -+ free_descs(this); -+ -+ return r; -+} -+ -+/* implements ecc->read_page() */ -+static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip, -+ uint8_t *buf, int oob_required, int page) -+{ -+ struct qcom_nandc_data *this = chip->priv; -+ u8 *data_buf, *oob_buf = NULL; -+ bool erased_page; -+ int r; -+ -+ data_buf = buf; -+ oob_buf = oob_required ? chip->oob_poi : NULL; -+ -+ r = read_page_low(this, data_buf, oob_buf); -+ if (r) { -+ dev_err(this->dev, "failure to read page\n"); -+ return r; -+ } -+ -+ erased_page = empty_page_fixup(this, data_buf); -+ -+ return parse_read_errors(this, erased_page); -+} -+ -+/* implements ecc->read_oob() */ -+static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, -+ int page) -+{ -+ struct qcom_nandc_data *this = chip->priv; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ int r; -+ -+ clear_read_regs(this); -+ -+ this->use_ecc = true; -+ set_address(this, 0, page); -+ update_rw_regs(this, ecc->steps, true); -+ -+ r = read_page_low(this, NULL, chip->oob_poi); -+ if (r) -+ dev_err(this->dev, "failure to read oob\n"); -+ -+ return r; -+} -+ -+/* implements ecc->read_oob_raw(), used to read the bad block marker flag */ -+static int qcom_nandc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, -+ int page) -+{ -+ struct qcom_nandc_data *this = chip->priv; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ uint8_t *oob = chip->oob_poi; -+ int start, length; -+ int r; -+ -+ /* -+ * configure registers for a raw page read, the address is set to the -+ * beginning of the last codeword, we don't care about reading ecc -+ * portion of oob, just the free stuff -+ */ -+ r = copy_last_cw(this, false, page); -+ if (r) -+ return r; -+ -+ /* -+ * reading raw oob has 2 parts, first the bad block byte, then the -+ * actual free oob region. perform a memcpy in two steps -+ */ -+ start = mtd->writesize - (this->cw_size * (ecc->steps - 1)); -+ length = chip->options & NAND_BUSWIDTH_16 ? 2 : 1; -+ -+ memcpy(oob, this->data_buffer + start, length); -+ -+ oob += length; -+ -+ start = this->cw_data - (ecc->steps << 2) + 1; -+ length = ecc->steps << 2; -+ -+ memcpy(oob, this->data_buffer + start, length); -+ -+ return 0; -+} -+ -+/* implements ecc->write_page() */ -+static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, -+ const uint8_t *buf, int oob_required) -+{ -+ struct qcom_nandc_data *this = chip->priv; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ u8 *data_buf, *oob_buf; -+ int i, r = 0; -+ -+ clear_read_regs(this); -+ -+ data_buf = (u8 *) buf; -+ oob_buf = chip->oob_poi; -+ -+ this->use_ecc = true; -+ update_rw_regs(this, ecc->steps, false); -+ -+ for (i = 0; i < ecc->steps; i++) { -+ int data_size, oob_size; -+ -+ if (i == (ecc->steps - 1)) { -+ data_size = ecc->size - ((ecc->steps - 1) << 2); -+ oob_size = (ecc->steps << 2) + ecc->bytes; -+ } else { -+ data_size = this->cw_data; -+ oob_size = ecc->bytes; -+ } -+ -+ config_cw_write_pre(this); -+ write_data_dma(this, FLASH_BUF_ACC, data_buf, data_size); -+ -+ /* -+ * we don't really need to write anything to oob for the -+ * first n - 1 codewords since these oob regions just -+ * contain ecc that's written by the controller itself -+ */ -+ if (i == (ecc->steps - 1)) -+ write_data_dma(this, FLASH_BUF_ACC + data_size, -+ oob_buf, oob_size); -+ config_cw_write_post(this); -+ -+ data_buf += data_size; -+ oob_buf += oob_size; -+ } -+ -+ r = submit_descs(this); -+ if (r) -+ dev_err(this->dev, "failure to write page\n"); -+ -+ free_descs(this); -+ -+ return r; -+} -+ -+/* -+ * implements ecc->write_oob() -+ * -+ * the NAND controller cannot write only data or only oob within a codeword, -+ * since ecc is calculated for the combined codeword. we first copy the -+ * entire contents for the last codeword(data + oob), replace the old oob -+ * with the new one in chip->oob_poi, and then write the entire codeword. -+ * this read-copy-write operation results in a slight perormance loss. -+ */ -+static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, -+ int page) -+{ -+ struct qcom_nandc_data *this = chip->priv; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ uint8_t *oob = chip->oob_poi; -+ int free_boff; -+ int data_size, oob_size; -+ int r, status = 0; -+ -+ r = copy_last_cw(this, true, page); -+ if (r) -+ return r; -+ -+ clear_read_regs(this); -+ -+ /* calculate the data and oob size for the last codeword/step */ -+ data_size = ecc->size - ((ecc->steps - 1) << 2); -+ oob_size = (ecc->steps << 2) + ecc->bytes; -+ -+ /* -+ * the location of spare data in the oob buffer, we could also use -+ * ecc->layout.oobfree here -+ */ -+ free_boff = ecc->bytes * (ecc->steps - 1); -+ -+ /* override new oob content to last codeword */ -+ memcpy(this->data_buffer + data_size, oob + free_boff, oob_size); -+ -+ this->use_ecc = true; -+ set_address(this, this->cw_size * (ecc->steps - 1), page); -+ update_rw_regs(this, 1, false); -+ -+ config_cw_write_pre(this); -+ write_data_dma(this, FLASH_BUF_ACC, this->data_buffer, -+ data_size + oob_size); -+ config_cw_write_post(this); -+ -+ r = submit_descs(this); -+ -+ free_descs(this); -+ -+ if (r) { -+ dev_err(this->dev, "failure to write oob\n"); -+ return -EIO; -+ } -+ -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+ -+ status = chip->waitfunc(mtd, chip); -+ -+ return status & NAND_STATUS_FAIL ? -EIO : 0; -+} -+ -+/* implements ecc->write_oob_raw(), used to write bad block marker flag */ -+static int qcom_nandc_write_oob_raw(struct mtd_info *mtd, -+ struct nand_chip *chip, int page) -+{ -+ struct qcom_nandc_data *this = chip->priv; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ uint8_t *oob = chip->oob_poi; -+ int start, length; -+ int r, status = 0; -+ -+ r = copy_last_cw(this, false, page); -+ if (r) -+ return r; -+ -+ clear_read_regs(this); -+ -+ /* -+ * writing raw oob has 2 parts, first the bad block region, then the -+ * actual free region -+ */ -+ start = mtd->writesize - (this->cw_size * (ecc->steps - 1)); -+ length = chip->options & NAND_BUSWIDTH_16 ? 2 : 1; -+ -+ memcpy(this->data_buffer + start, oob, length); -+ -+ oob += length; -+ -+ start = this->cw_data - (ecc->steps << 2) + 1; -+ length = ecc->steps << 2; -+ -+ memcpy(this->data_buffer + start, oob, length); -+ -+ /* prepare write */ -+ this->use_ecc = false; -+ set_address(this, this->cw_size * (ecc->steps - 1), page); -+ update_rw_regs(this, 1, false); -+ -+ config_cw_write_pre(this); -+ write_data_dma(this, FLASH_BUF_ACC, this->data_buffer, this->cw_size); -+ config_cw_write_post(this); -+ -+ r = submit_descs(this); -+ -+ free_descs(this); -+ -+ if (r) { -+ dev_err(this->dev, "failure to write updated oob\n"); -+ return -EIO; -+ } -+ -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+ -+ status = chip->waitfunc(mtd, chip); -+ -+ return status & NAND_STATUS_FAIL ? -EIO : 0; -+} -+ -+/* -+ * the three functions below implement chip->read_byte(), chip->read_buf() -+ * and chip->write_buf() respectively. these aren't used for -+ * reading/writing page data, they are used for smaller data like reading -+ * id, status etc -+ */ -+static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd) -+{ -+ struct nand_chip *chip = mtd->priv; -+ struct qcom_nandc_data *this = chip->priv; -+ uint8_t *buf = this->data_buffer; -+ uint8_t ret = 0x0; -+ -+ if (this->last_command == NAND_CMD_STATUS) { -+ ret = this->status; -+ -+ this->status = NAND_STATUS_READY | NAND_STATUS_WP; -+ -+ return ret; -+ } -+ -+ if (this->buf_start < this->buf_count) -+ ret = buf[this->buf_start++]; -+ -+ return ret; -+} -+ -+static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -+{ -+ struct nand_chip *chip = mtd->priv; -+ struct qcom_nandc_data *this = chip->priv; -+ int real_len = min_t(size_t, len, this->buf_count - this->buf_start); -+ -+ memcpy(buf, this->data_buffer + this->buf_start, real_len); -+ this->buf_start += real_len; -+} -+ -+static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf, -+ int len) -+{ -+ struct nand_chip *chip = mtd->priv; -+ struct qcom_nandc_data *this = chip->priv; -+ int real_len = min_t(size_t, len, this->buf_count - this->buf_start); -+ -+ memcpy(this->data_buffer + this->buf_start, buf, real_len); -+ -+ this->buf_start += real_len; -+} -+ -+/* we support only one external chip for now */ -+static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr) -+{ -+ struct nand_chip *chip = mtd->priv; -+ struct qcom_nandc_data *this = chip->priv; -+ -+ if (chipnr <= 0) -+ return; -+ -+ dev_warn(this->dev, "invalid chip select\n"); -+} -+ -+/* -+ * NAND controller page layout info -+ * -+ * |-----------------------| |---------------------------------| -+ * | xx.......xx| | *********xx.......xx| -+ * | DATA xx..ECC..xx| | DATA **SPARE**xx..ECC..xx| -+ * | (516) xx.......xx| | (516-n*4) **(n*4)**xx.......xx| -+ * | xx.......xx| | *********xx.......xx| -+ * |-----------------------| |---------------------------------| -+ * codeword 1,2..n-1 codeword n -+ * <---(528/532 Bytes)----> <-------(528/532 Bytes)----------> -+ * -+ * n = number of codewords in the page -+ * . = ECC bytes -+ * * = spare bytes -+ * x = unused/reserved bytes -+ * -+ * 2K page: n = 4, spare = 16 bytes -+ * 4K page: n = 8, spare = 32 bytes -+ * 8K page: n = 16, spare = 64 bytes -+ * -+ * the qcom nand controller operates at a sub page/codeword level. each -+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively. -+ * the number of ECC bytes vary based on the ECC strength and the bus width. -+ * -+ * the first n - 1 codewords contains 516 bytes of user data, the remaining -+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains -+ * both user data and spare(oobavail) bytes that sum up to 516 bytes. -+ * -+ * the layout described above is used by the controller when the ECC block is -+ * enabled. When we read a page with ECC enabled, the unused/reserved bytes are -+ * skipped and not copied to our internal buffer. therefore, the nand_ecclayout -+ * layouts defined below doesn't consider the positions occupied by the reserved -+ * bytes -+ * -+ * when the ECC block is disabled, one unused byte (or two for 16 bit bus width) -+ * in the last codeword is the position of bad block marker. the bad block -+ * marker cannot be accessed when ECC is enabled. -+ * -+ */ -+ -+/* -+ * Layouts for different page sizes and ecc modes. We skip the eccpos field -+ * since it isn't needed for this driver -+ */ -+ -+/* 2K page, 4 bit ECC */ -+static struct nand_ecclayout layout_oob_64 = { -+ .eccbytes = 40, -+ .oobfree = { -+ { 30, 16 }, -+ }, -+}; -+ -+/* 4K page, 4 bit ECC, 8/16 bit bus width */ -+static struct nand_ecclayout layout_oob_128 = { -+ .eccbytes = 80, -+ .oobfree = { -+ { 70, 32 }, -+ }, -+}; -+ -+/* 4K page, 8 bit ECC, 8 bit bus width */ -+static struct nand_ecclayout layout_oob_224_x8 = { -+ .eccbytes = 104, -+ .oobfree = { -+ { 91, 32 }, -+ }, -+}; -+ -+/* 4K page, 8 bit ECC, 16 bit bus width */ -+static struct nand_ecclayout layout_oob_224_x16 = { -+ .eccbytes = 112, -+ .oobfree = { -+ { 98, 32 }, -+ }, -+}; -+ -+/* 8K page, 4 bit ECC, 8/16 bit bus width */ -+static struct nand_ecclayout layout_oob_256 = { -+ .eccbytes = 160, -+ .oobfree = { -+ { 151, 64 }, -+ }, -+}; -+ -+/* -+ * this is called before scan_ident, we do some minimal configurations so -+ * that reading ID and ONFI params work -+ */ -+static void qcom_nandc_pre_init(struct qcom_nandc_data *this) -+{ -+ /* kill onenand */ -+ nandc_write(this, SFLASHC_BURST_CFG, 0); -+ -+ /* enable ADM DMA */ -+ nandc_write(this, NAND_FLASH_CHIP_SELECT, DM_EN); -+ -+ /* save the original values of these registers */ -+ this->cmd1 = nandc_read(this, NAND_DEV_CMD1); -+ this->vld = nandc_read(this, NAND_DEV_CMD_VLD); -+ -+ /* initial status value */ -+ this->status = NAND_STATUS_READY | NAND_STATUS_WP; -+} -+ -+static int qcom_nandc_ecc_init(struct qcom_nandc_data *this) -+{ -+ struct mtd_info *mtd = &this->mtd; -+ struct nand_chip *chip = &this->chip; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ int cwperpage; -+ bool wide_bus; -+ -+ /* the nand controller fetches codewords/chunks of 512 bytes */ -+ cwperpage = mtd->writesize >> 9; -+ -+ ecc->strength = this->ecc_strength; -+ -+ wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false; -+ -+ if (ecc->strength >= 8) { -+ /* 8 bit ECC defaults to BCH ECC on all platforms */ -+ ecc->bytes = wide_bus ? 14 : 13; -+ } else { -+ /* -+ * if the controller supports BCH for 4 bit ECC, the controller -+ * uses lesser bytes for ECC. If RS is used, the ECC bytes is -+ * always 10 bytes -+ */ -+ if (this->ecc_modes & ECC_BCH_4BIT) -+ ecc->bytes = wide_bus ? 8 : 7; -+ else -+ ecc->bytes = 10; -+ } -+ -+ /* each step consists of 512 bytes of data */ -+ ecc->size = NANDC_STEP_SIZE; -+ -+ ecc->read_page = qcom_nandc_read_page; -+ ecc->read_oob = qcom_nandc_read_oob; -+ ecc->write_page = qcom_nandc_write_page; -+ ecc->write_oob = qcom_nandc_write_oob; -+ -+ /* -+ * the bad block marker is readable only when we read the page with ECC -+ * disabled. all the ops above run with ECC enabled. We need raw read -+ * and write function for oob in order to access bad block marker. -+ */ -+ ecc->read_oob_raw = qcom_nandc_read_oob_raw; -+ ecc->write_oob_raw = qcom_nandc_write_oob_raw; -+ -+ switch (mtd->oobsize) { -+ case 64: -+ ecc->layout = &layout_oob_64; -+ break; -+ case 128: -+ ecc->layout = &layout_oob_128; -+ break; -+ case 224: -+ if (wide_bus) -+ ecc->layout = &layout_oob_224_x16; -+ else -+ ecc->layout = &layout_oob_224_x8; -+ break; -+ case 256: -+ ecc->layout = &layout_oob_256; -+ break; -+ default: -+ dev_err(this->dev, "unsupported NAND device, oobsize %d\n", -+ mtd->oobsize); -+ return -ENODEV; -+ } -+ -+ ecc->mode = NAND_ECC_HW; -+ -+ /* enable ecc by default */ -+ this->use_ecc = true; -+ -+ return 0; -+} -+ -+static void qcom_nandc_hw_post_init(struct qcom_nandc_data *this) -+{ -+ struct mtd_info *mtd = &this->mtd; -+ struct nand_chip *chip = &this->chip; -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ int cwperpage = mtd->writesize / ecc->size; -+ int spare_bytes, bad_block_byte; -+ bool wide_bus; -+ int ecc_mode = 0; -+ -+ wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false; -+ -+ if (ecc->strength >= 8) { -+ this->cw_size = 532; -+ -+ spare_bytes = wide_bus ? 0 : 2; -+ -+ this->bch_enabled = true; -+ ecc_mode = 1; -+ } else { -+ this->cw_size = 528; -+ -+ if (this->ecc_modes & ECC_BCH_4BIT) { -+ spare_bytes = wide_bus ? 2 : 4; -+ -+ this->bch_enabled = true; -+ ecc_mode = 0; -+ } else { -+ spare_bytes = wide_bus ? 0 : 1; -+ } -+ } -+ -+ /* -+ * DATA_UD_BYTES varies based on whether the read/write command protects -+ * spare data with ECC too. We protect spare data by default, so we set -+ * it to main + spare data, which are 512 and 4 bytes respectively. -+ */ -+ this->cw_data = 516; -+ -+ bad_block_byte = mtd->writesize - this->cw_size * (cwperpage - 1) + 1; -+ -+ this->cfg0 = (cwperpage - 1) << CW_PER_PAGE -+ | this->cw_data << UD_SIZE_BYTES -+ | 0 << DISABLE_STATUS_AFTER_WRITE -+ | 5 << NUM_ADDR_CYCLES -+ | ecc->bytes << ECC_PARITY_SIZE_BYTES_RS -+ | 0 << STATUS_BFR_READ -+ | 1 << SET_RD_MODE_AFTER_STATUS -+ | spare_bytes << SPARE_SIZE_BYTES; -+ -+ this->cfg1 = 7 << NAND_RECOVERY_CYCLES -+ | 0 << CS_ACTIVE_BSY -+ | bad_block_byte << BAD_BLOCK_BYTE_NUM -+ | 0 << BAD_BLOCK_IN_SPARE_AREA -+ | 2 << WR_RD_BSY_GAP -+ | wide_bus << WIDE_FLASH -+ | this->bch_enabled << ENABLE_BCH_ECC; -+ -+ this->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE -+ | this->cw_size << UD_SIZE_BYTES -+ | 5 << NUM_ADDR_CYCLES -+ | 0 << SPARE_SIZE_BYTES; -+ -+ this->cfg1_raw = 7 << NAND_RECOVERY_CYCLES -+ | 0 << CS_ACTIVE_BSY -+ | 17 << BAD_BLOCK_BYTE_NUM -+ | 1 << BAD_BLOCK_IN_SPARE_AREA -+ | 2 << WR_RD_BSY_GAP -+ | wide_bus << WIDE_FLASH -+ | 1 << DEV0_CFG1_ECC_DISABLE; -+ -+ this->ecc_bch_cfg = this->bch_enabled << ECC_CFG_ECC_DISABLE -+ | 0 << ECC_SW_RESET -+ | this->cw_data << ECC_NUM_DATA_BYTES -+ | 1 << ECC_FORCE_CLK_OPEN -+ | ecc_mode << ECC_MODE -+ | ecc->bytes << ECC_PARITY_SIZE_BYTES_BCH; -+ -+ this->ecc_buf_cfg = 0x203 << NUM_STEPS; -+ -+ this->clrflashstatus = FS_READY_BSY_N; -+ this->clrreadstatus = 0xc0; -+ -+ dev_dbg(this->dev, -+ "cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n", -+ this->cfg0, this->cfg1, this->ecc_buf_cfg, -+ this->ecc_bch_cfg, this->cw_size, this->cw_data, -+ ecc->strength, ecc->bytes, cwperpage); -+} -+ -+static int qcom_nandc_alloc(struct qcom_nandc_data *this) -+{ -+ int r; -+ -+ r = dma_set_coherent_mask(this->dev, DMA_BIT_MASK(32)); -+ if (r) { -+ dev_err(this->dev, "failed to set DMA mask\n"); -+ return r; -+ } -+ -+ /* -+ * we use the internal buffer for reading ONFI params, reading small -+ * data like ID and status, and preforming read-copy-write operations -+ * when writing to a codeword partially. 532 is the maximum possible -+ * size of a codeword for our nand controller -+ */ -+ this->buf_size = 532; -+ -+ this->data_buffer = devm_kzalloc(this->dev, this->buf_size, GFP_KERNEL); -+ if (!this->data_buffer) -+ return -ENOMEM; -+ -+ this->regs = devm_kzalloc(this->dev, sizeof(*this->regs), GFP_KERNEL); -+ if (!this->regs) -+ return -ENOMEM; -+ -+ this->reg_read_buf = devm_kzalloc(this->dev, -+ MAX_REG_RD * sizeof(*this->reg_read_buf), -+ GFP_KERNEL); -+ if (!this->reg_read_buf) -+ return -ENOMEM; -+ -+ INIT_LIST_HEAD(&this->list); -+ -+ this->chan = dma_request_slave_channel(this->dev, "rxtx"); -+ if (!this->chan) { -+ dev_err(this->dev, "failed to request slave channel\n"); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void qcom_nandc_unalloc(struct qcom_nandc_data *this) -+{ -+ dma_release_channel(this->chan); -+} -+ -+static int qcom_nandc_init(struct qcom_nandc_data *this) -+{ -+ struct mtd_info *mtd = &this->mtd; -+ struct nand_chip *chip = &this->chip; -+ struct device_node *np = this->dev->of_node; -+ struct mtd_part_parser_data ppdata = { .of_node = np }; -+ int r; -+ -+ mtd->priv = chip; -+ mtd->name = "qcom-nandc"; -+ mtd->owner = THIS_MODULE; -+ -+ chip->priv = this; -+ -+ chip->cmdfunc = qcom_nandc_command; -+ chip->select_chip = qcom_nandc_select_chip; -+ chip->read_byte = qcom_nandc_read_byte; -+ chip->read_buf = qcom_nandc_read_buf; -+ chip->write_buf = qcom_nandc_write_buf; -+ -+ chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER; -+ if (this->bus_width == 16) -+ chip->options |= NAND_BUSWIDTH_16; -+ -+ chip->bbt_options = NAND_BBT_ACCESS_BBM_RAW; -+ if (of_get_nand_on_flash_bbt(np)) -+ chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; -+ -+ qcom_nandc_pre_init(this); -+ -+ r = nand_scan_ident(mtd, 1, NULL); -+ if (r) -+ return r; -+ -+ r = qcom_nandc_ecc_init(this); -+ if (r) -+ return r; -+ -+ qcom_nandc_hw_post_init(this); -+ -+ r = nand_scan_tail(mtd); -+ if (r) -+ return r; -+ -+ return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); -+} -+ -+static int qcom_nandc_parse_dt(struct platform_device *pdev) -+{ -+ struct qcom_nandc_data *this = platform_get_drvdata(pdev); -+ struct device_node *np = this->dev->of_node; -+ int r; -+ -+ this->ecc_strength = of_get_nand_ecc_strength(np); -+ if (this->ecc_strength < 0) { -+ dev_warn(this->dev, -+ "incorrect ecc strength, setting to 4 bits/step\n"); -+ this->ecc_strength = 4; -+ } -+ -+ this->bus_width = of_get_nand_bus_width(np); -+ if (this->bus_width < 0) { -+ dev_warn(this->dev, "incorrect bus width, setting to 8\n"); -+ this->bus_width = 8; -+ } -+ -+ r = of_property_read_u32(np, "qcom,cmd-crci", &this->cmd_crci); -+ if (r) { -+ dev_err(this->dev, "command CRCI unspecified\n"); -+ return r; -+ } -+ -+ r = of_property_read_u32(np, "qcom,data-crci", &this->data_crci); -+ if (r) { -+ dev_err(this->dev, "data CRCI unspecified\n"); -+ return r; -+ } -+ -+ return 0; -+} -+ -+static int qcom_nandc_probe(struct platform_device *pdev) -+{ -+ struct qcom_nandc_data *this; -+ const struct of_device_id *match; -+ int r; -+ -+ this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL); -+ if (!this) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, this); -+ -+ this->pdev = pdev; -+ this->dev = &pdev->dev; -+ -+ match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); -+ if (!match) { -+ dev_err(&pdev->dev, "failed to match device\n"); -+ return -ENODEV; -+ } -+ -+ if (!match->data) { -+ dev_err(&pdev->dev, "failed to get device data\n"); -+ return -ENODEV; -+ } -+ -+ this->ecc_modes = (u32) match->data; -+ -+ this->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ this->base = devm_ioremap_resource(&pdev->dev, this->res); -+ if (IS_ERR(this->base)) -+ return PTR_ERR(this->base); -+ -+ this->core_clk = devm_clk_get(&pdev->dev, "core"); -+ if (IS_ERR(this->core_clk)) -+ return PTR_ERR(this->core_clk); -+ -+ this->aon_clk = devm_clk_get(&pdev->dev, "aon"); -+ if (IS_ERR(this->aon_clk)) -+ return PTR_ERR(this->aon_clk); -+ -+ r = qcom_nandc_parse_dt(pdev); -+ if (r) -+ return r; -+ -+ r = qcom_nandc_alloc(this); -+ if (r) -+ return r; -+ -+ r = clk_prepare_enable(this->core_clk); -+ if (r) -+ goto err_core_clk; -+ -+ r = clk_prepare_enable(this->aon_clk); -+ if (r) -+ goto err_aon_clk; -+ -+ r = qcom_nandc_init(this); -+ if (r) -+ goto err_init; -+ -+ return 0; -+ -+err_init: -+ clk_disable_unprepare(this->aon_clk); -+err_aon_clk: -+ clk_disable_unprepare(this->core_clk); -+err_core_clk: -+ qcom_nandc_unalloc(this); -+ -+ return r; -+} -+ -+static int qcom_nandc_remove(struct platform_device *pdev) -+{ -+ struct qcom_nandc_data *this = platform_get_drvdata(pdev); -+ -+ qcom_nandc_unalloc(this); -+ -+ clk_disable_unprepare(this->aon_clk); -+ clk_disable_unprepare(this->core_clk); -+ -+ return 0; -+} -+ -+#define EBI2_NANDC_ECC_MODES (ECC_RS_4BIT | ECC_BCH_8BIT) -+ -+/* -+ * data will hold a struct pointer containing more differences once we support -+ * more IPs -+ */ -+static const struct of_device_id qcom_nandc_of_match[] = { -+ { .compatible = "qcom,ebi2-nandc", -+ .data = (void *) EBI2_NANDC_ECC_MODES, -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, qcom_nandc_of_match); -+ -+static struct platform_driver qcom_nandc_driver = { -+ .driver = { -+ .name = "qcom-nandc", -+ .of_match_table = qcom_nandc_of_match, -+ }, -+ .probe = qcom_nandc_probe, -+ .remove = qcom_nandc_remove, -+}; -+module_platform_driver(qcom_nandc_driver); -+ -+MODULE_AUTHOR("Archit Taneja "); -+MODULE_DESCRIPTION("Qualcomm NAND Controller driver"); -+MODULE_LICENSE("GPL v2"); ---- a/drivers/mtd/nand/Makefile -+++ b/drivers/mtd/nand/Makefile -@@ -50,5 +50,6 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740 - obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ - obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o - obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ -+obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o - - nand-objs := nand_base.o nand_bbt.o nand_timings.o diff --git a/target/linux/ipq806x/patches-3.18/163-dt-bindings-qcom_nandc-Add-DT-bindings.patch b/target/linux/ipq806x/patches-3.18/163-dt-bindings-qcom_nandc-Add-DT-bindings.patch deleted file mode 100644 index 6530eb1c86b2..000000000000 --- a/target/linux/ipq806x/patches-3.18/163-dt-bindings-qcom_nandc-Add-DT-bindings.patch +++ /dev/null @@ -1,82 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,3/5] dt/bindings: qcom_nandc: Add DT bindings -From: Archit Taneja -X-Patchwork-Id: 6927141 -Message-Id: <1438578498-32254-4-git-send-email-architt@codeaurora.org> -To: linux-mtd@lists.infradead.org, dehrenberg@google.com, - cernekee@gmail.com, computersforpeace@gmail.com -Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org, - sboyd@codeaurora.org, linux-kernel@vger.kernel.org, - Archit Taneja , devicetree@vger.kernel.org -Date: Mon, 3 Aug 2015 10:38:16 +0530 - -Add DT bindings document for the Qualcomm NAND controller driver. - -Cc: devicetree@vger.kernel.org - -v3: -- Don't use '0x' when specifying nand controller address space -- Add optional property for on-flash bbt usage - -Acked-by: Andy Gross -Signed-off-by: Archit Taneja - ---- -.../devicetree/bindings/mtd/qcom_nandc.txt | 49 ++++++++++++++++++++++ - 1 file changed, 49 insertions(+) - create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt - ---- /dev/null -+++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt -@@ -0,0 +1,49 @@ -+* Qualcomm NAND controller -+ -+Required properties: -+- compatible: should be "qcom,ebi2-nand" for IPQ806x -+- reg: MMIO address range -+- clocks: must contain core clock and always on clock -+- clock-names: must contain "core" for the core clock and "aon" for the -+ always on clock -+- dmas: DMA specifier, consisting of a phandle to the ADM DMA -+ controller node and the channel number to be used for -+ NAND. Refer to dma.txt and qcom_adm.txt for more details -+- dma-names: must be "rxtx" -+- qcom,cmd-crci: must contain the ADM command type CRCI block instance -+ number specified for the NAND controller on the given -+ platform -+- qcom,data-crci: must contain the ADM data type CRCI block instance -+ number specified for the NAND controller on the given -+ platform -+ -+Optional properties: -+- nand-bus-width: bus width. Must be 8 or 16. If not present, 8 is chosen -+ as default -+ -+- nand-ecc-strength: number of bits to correct per ECC step. Must be 4 or 8 -+ bits. If not present, 4 is chosen as default -+- nand-on-flash-bbt: Create/use on-flash bad block table -+ -+The device tree may optionally contain sub-nodes describing partitions of the -+address space. See partition.txt for more detail. -+ -+Example: -+ -+nand@1ac00000 { -+ compatible = "qcom,ebi2-nandc"; -+ reg = <0x1ac00000 0x800>; -+ -+ clocks = <&gcc EBI2_CLK>, -+ <&gcc EBI2_AON_CLK>; -+ clock-names = "core", "aon"; -+ -+ dmas = <&adm_dma 3>; -+ dma-names = "rxtx"; -+ qcom,cmd-crci = <15>; -+ qcom,data-crci = <3>; -+ -+ partition@0 { -+ ... -+ }; -+}; diff --git a/target/linux/ipq806x/patches-3.18/164-arm-qcom-dts-Add-NAND-controller-node-for-ipq806x.patch b/target/linux/ipq806x/patches-3.18/164-arm-qcom-dts-Add-NAND-controller-node-for-ipq806x.patch deleted file mode 100644 index 6a8ec4ac4b62..000000000000 --- a/target/linux/ipq806x/patches-3.18/164-arm-qcom-dts-Add-NAND-controller-node-for-ipq806x.patch +++ /dev/null @@ -1,51 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,4/5] arm: qcom: dts: Add NAND controller node for ipq806x -From: Archit Taneja -X-Patchwork-Id: 6927121 -Message-Id: <1438578498-32254-5-git-send-email-architt@codeaurora.org> -To: linux-mtd@lists.infradead.org, dehrenberg@google.com, - cernekee@gmail.com, computersforpeace@gmail.com -Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org, - sboyd@codeaurora.org, linux-kernel@vger.kernel.org, - Archit Taneja , devicetree@vger.kernel.org -Date: Mon, 3 Aug 2015 10:38:17 +0530 - -The nand controller in IPQ806x is of the 'EBI2 type'. Use the corresponding -compatible string. - -Cc: devicetree@vger.kernel.org - -Reviewed-by: Andy Gross -Signed-off-by: Archit Taneja - ---- -arch/arm/boot/dts/qcom-ipq8064.dtsi | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -725,6 +725,22 @@ - status = "disabled"; - }; - -+ nand@1ac00000 { -+ compatible = "qcom,ebi2-nandc"; -+ reg = <0x1ac00000 0x800>; -+ -+ clocks = <&gcc EBI2_CLK>, -+ <&gcc EBI2_AON_CLK>; -+ clock-names = "core", "aon"; -+ -+ dmas = <&adm_dma 3>; -+ dma-names = "rxtx"; -+ qcom,cmd-crci = <15>; -+ qcom,data-crci = <3>; -+ -+ status = "disabled"; -+ }; -+ - }; - - sfpb_mutex: sfpb-mutex { diff --git a/target/linux/ipq806x/patches-3.18/165-arm-qcom-dts-Enable-NAND-node-on-IPQ8064-AP148-platform.patch b/target/linux/ipq806x/patches-3.18/165-arm-qcom-dts-Enable-NAND-node-on-IPQ8064-AP148-platform.patch deleted file mode 100644 index 9c7c3a3af016..000000000000 --- a/target/linux/ipq806x/patches-3.18/165-arm-qcom-dts-Enable-NAND-node-on-IPQ8064-AP148-platform.patch +++ /dev/null @@ -1,79 +0,0 @@ -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v3,5/5] arm: qcom: dts: Enable NAND node on IPQ8064 AP148 platform -From: Archit Taneja -X-Patchwork-Id: 6927091 -Message-Id: <1438578498-32254-6-git-send-email-architt@codeaurora.org> -To: linux-mtd@lists.infradead.org, dehrenberg@google.com, - cernekee@gmail.com, computersforpeace@gmail.com -Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org, - sboyd@codeaurora.org, linux-kernel@vger.kernel.org, - Archit Taneja , devicetree@vger.kernel.org -Date: Mon, 3 Aug 2015 10:38:18 +0530 - -Enable the NAND controller node on the AP148 platform. Provide pinmux -information. - -Cc: devicetree@vger.kernel.org - -Signed-off-by: Archit Taneja - ---- -arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 36 ++++++++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -@@ -43,6 +43,31 @@ - bias-none; - }; - }; -+ -+ nand_pins: nand_pins { -+ mux { -+ pins = "gpio34", "gpio35", "gpio36", -+ "gpio37", "gpio38", "gpio39", -+ "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ function = "nand"; -+ drive-strength = <10>; -+ bias-disable; -+ }; -+ -+ pullups { -+ pins = "gpio39"; -+ bias-pull-up; -+ }; -+ -+ hold { -+ pins = "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ bias-bus-hold; -+ }; -+ }; - }; - - gsbi@16300000 { -@@ -125,5 +150,19 @@ - status = "ok"; - phy-tx0-term-offset = <7>; - }; -+ -+ nand@1ac00000 { -+ status = "ok"; -+ -+ pinctrl-0 = <&nand_pins>; -+ pinctrl-names = "default"; -+ -+ nand-ecc-strength = <4>; -+ nand-bus-width = <8>; -+ }; - }; - }; -+ -+&adm_dma { -+ status = "ok"; -+}; diff --git a/target/linux/ipq806x/patches-3.18/166-arch-qcom-dts-enable-qcom-smem-on-AP148-NAND.patch b/target/linux/ipq806x/patches-3.18/166-arch-qcom-dts-enable-qcom-smem-on-AP148-NAND.patch deleted file mode 100644 index 1db21e4edcb1..000000000000 --- a/target/linux/ipq806x/patches-3.18/166-arch-qcom-dts-enable-qcom-smem-on-AP148-NAND.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -@@ -159,6 +159,8 @@ - - nand-ecc-strength = <4>; - nand-bus-width = <8>; -+ -+ linux,part-probe = "qcom-smem"; - }; - }; - }; diff --git a/target/linux/ipq806x/patches-3.18/300-arch-arm-force-ZRELADDR-on-arch-qcom.patch b/target/linux/ipq806x/patches-3.18/300-arch-arm-force-ZRELADDR-on-arch-qcom.patch deleted file mode 100644 index 8669b0257ca6..000000000000 --- a/target/linux/ipq806x/patches-3.18/300-arch-arm-force-ZRELADDR-on-arch-qcom.patch +++ /dev/null @@ -1,62 +0,0 @@ -From b12e230f09d4481424e6a5d7e2ae566b6954e83f Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Wed, 29 Apr 2015 15:21:46 -0700 -Subject: [PATCH] HACK: arch: arm: force ZRELADDR on arch-qcom - -ARCH_QCOM is using the ARCH_MULTIPLATFORM option, as now recommended -on most ARM architectures. This automatically calculate ZRELADDR by -masking PHYS_OFFSET with 0xf8000000. - -However, on IPQ806x, the first ~20MB of RAM is reserved for the hardware -network accelerators, and the bootloader removes this section from the -layout passed from the ATAGS (when used). - -For newer bootloader, when DT is used, this is not a problem, we just -reserve this memory in the device tree. But if the bootloader doesn't -have DT support, then ATAGS have to be used. In this case, the ARM -decompressor will position the kernel in this low mem, which will not be -in the RAM section mapped by the bootloader, which means the kernel will -freeze in the middle of the boot process trying to map the memory. - -As a work around, this patch allows disabling AUTO_ZRELADDR when -ARCH_QCOM is selected. It makes the zImage usage possible on bootloaders -which don't support device-tree, which is the case on certain early -IPQ806x based designs. - -Signed-off-by: Mathieu Olivari ---- - arch/arm/Kconfig | 2 +- - arch/arm/Makefile | 2 ++ - arch/arm/mach-qcom/Makefile.boot | 1 + - 3 files changed, 4 insertions(+), 1 deletion(-) - create mode 100644 arch/arm/mach-qcom/Makefile.boot - ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -311,7 +311,7 @@ config ARCH_MULTIPLATFORM - select ARCH_WANT_OPTIONAL_GPIOLIB - select ARM_HAS_SG_CHAIN - select ARM_PATCH_PHYS_VIRT -- select AUTO_ZRELADDR -+ select AUTO_ZRELADDR if !ARCH_QCOM - select CLKSRC_OF - select COMMON_CLK - select GENERIC_CLOCKEVENTS ---- a/arch/arm/Makefile -+++ b/arch/arm/Makefile -@@ -248,9 +248,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac - else - MACHINE := - endif -+ifeq ($(CONFIG_ARCH_QCOM),) - ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y) - MACHINE := - endif -+endif - - machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) - platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y))) ---- /dev/null -+++ b/arch/arm/mach-qcom/Makefile.boot -@@ -0,0 +1 @@ -+zreladdr-y+= 0x42208000 diff --git a/target/linux/ipq806x/patches-3.18/301-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch b/target/linux/ipq806x/patches-3.18/301-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch deleted file mode 100644 index abd7cf631de5..000000000000 --- a/target/linux/ipq806x/patches-3.18/301-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch +++ /dev/null @@ -1,367 +0,0 @@ -From 7e77aa188a7a7c4391856a9e5ef5ef58f769e679 Mon Sep 17 00:00:00 2001 -From: Jonas Gorski -Date: Sun, 9 Aug 2015 13:02:38 +0200 -Subject: [PATCH] ARM: qcom: add Netgear Nighthawk X4 R7500 device tree - -Signed-off-by: Jonas Gorski ---- - arch/arm/boot/dts/Makefile | 1 + - arch/arm/boot/dts/qcom-ipq8064-r7500.dts | 370 +++++++++++++++++++++++++++++++ - 2 files changed, 371 insertions(+) - create mode 100644 arch/arm/boot/dts/qcom-ipq8064-r7500.dts - ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -361,6 +361,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ - qcom-apq8084-mtp.dtb \ - qcom-ipq8064-ap148.dtb \ - qcom-ipq8064-db149.dtb \ -+ qcom-ipq8064-r7500.dtb \ - qcom-msm8660-surf.dtb \ - qcom-msm8960-cdp.dtb \ - qcom-msm8974-sony-xperia-honami.dtb ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-r7500.dts -@@ -0,0 +1,342 @@ -+#include "qcom-ipq8064-v1.0.dtsi" -+ -+#include -+ -+/ { -+ model = "Netgear Nighthawk X4 R7500"; -+ compatible = "netgear,r7500", "qcom,ipq8064"; -+ -+ memory@0 { -+ reg = <0x42000000 0xe000000>; -+ device_type = "memory"; -+ }; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ rsvd@41200000 { -+ reg = <0x41200000 0x300000>; -+ no-map; -+ }; -+ }; -+ -+ aliases { -+ serial0 = &uart4; -+ mdio-gpio0 = &mdio0; -+ }; -+ -+ chosen { -+ bootargs = "rootfstype=squashfs noinitrd"; -+ linux,stdout-path = "serial0:115200n8"; -+ }; -+ -+ soc { -+ pinmux@800000 { -+ i2c4_pins: i2c4_pinmux { -+ pins = "gpio12", "gpio13"; -+ function = "gsbi4"; -+ bias-disable; -+ }; -+ -+ nand_pins: nand_pins { -+ mux { -+ pins = "gpio34", "gpio35", "gpio36", -+ "gpio37", "gpio38", "gpio39", -+ "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ function = "nand"; -+ drive-strength = <10>; -+ bias-disable; -+ }; -+ pullups { -+ pins = "gpio39"; -+ bias-pull-up; -+ }; -+ hold { -+ pins = "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ bias-bus-hold; -+ }; -+ }; -+ -+ 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 { -+ qcom,mode = ; -+ status = "ok"; -+ serial@16340000 { -+ status = "ok"; -+ }; -+ /* -+ * The i2c device on gsbi4 should not be enabled. -+ * On ipq806x designs gsbi4 i2c is meant for exclusive -+ * RPM usage. Turning this on in kernel manifests as -+ * i2c failure for the RPM. -+ */ -+ }; -+ -+ sata-phy@1b400000 { -+ status = "ok"; -+ }; -+ -+ sata@29000000 { -+ status = "ok"; -+ }; -+ -+ phy@100f8800 { /* USB3 port 1 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@100f8830 { /* USB3 port 1 SS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8800 { /* USB3 port 0 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8830 { /* USB3 port 0 SS phy */ -+ status = "ok"; -+ }; -+ -+ usb30@0 { -+ status = "ok"; -+ }; -+ -+ usb30@1 { -+ status = "ok"; -+ }; -+ -+ pcie0: pci@1b500000 { -+ status = "ok"; -+ }; -+ -+ pcie1: pci@1b700000 { -+ status = "ok"; -+ }; -+ -+ nand@1ac00000 { -+ status = "ok"; -+ -+ pinctrl-0 = <&nand_pins>; -+ pinctrl-names = "default"; -+ -+ nand-ecc-strength = <4>; -+ nand-bus-width = <8>; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ qcadata@0 { -+ label = "qcadata"; -+ reg = <0x0000000 0x0c80000>; -+ read-only; -+ }; -+ -+ APPSBL@c80000 { -+ label = "APPSBL"; -+ reg = <0x0c80000 0x0500000>; -+ read-only; -+ }; -+ -+ APPSBLENV@1180000 { -+ label = "APPSBLENV"; -+ reg = <0x1180000 0x0080000>; -+ read-only; -+ }; -+ -+ art: art@1200000 { -+ label = "art"; -+ reg = <0x1200000 0x0140000>; -+ read-only; -+ }; -+ -+ kernel@1340000 { -+ label = "kernel"; -+ reg = <0x1340000 0x0200000>; -+ }; -+ -+ ubi@1540000 { -+ label = "ubi"; -+ reg = <0x1540000 0x1800000>; -+ }; -+ -+ netgear@2d40000 { -+ label = "netgear"; -+ reg = <0x2d40000 0x0c00000>; -+ read-only; -+ }; -+ -+ reserve@3940000 { -+ label = "reserve"; -+ reg = <0x3940000 0x46c0000>; -+ read-only; -+ }; -+ -+ firmware@1340000 { -+ label = "firmware"; -+ reg = <0x1340000 0x1a00000>; -+ }; -+ -+ }; -+ -+ mdio0: mdio { -+ compatible = "virtual,mdio-gpio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; -+ pinctrl-0 = <&mdio0_pins>; -+ pinctrl-names = "default"; -+ -+ 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>; -+ }; -+ }; -+ -+ gmac1: ethernet@37200000 { -+ status = "ok"; -+ phy-mode = "rgmii"; -+ qcom,id = <1>; -+ -+ pinctrl-0 = <&rgmii2_pins>; -+ pinctrl-names = "default"; -+ -+ mtd-mac-address = <&art 6>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <2>; -+ -+ mtd-mac-address = <&art 0>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ wifi { -+ label = "wifi"; -+ gpios = <&qcom_pinmux 6 1>; -+ linux,code = ; -+ }; -+ -+ reset { -+ label = "reset"; -+ gpios = <&qcom_pinmux 54 1>; -+ linux,code = ; -+ }; -+ -+ wps { -+ label = "wps"; -+ gpios = <&qcom_pinmux 65 1>; -+ linux,code = ; -+ }; -+ }; -+ -+ gpio-leds { -+ compatible = "gpio-leds"; -+ -+ usb1 { -+ label = "r7500:amber:usb1"; -+ gpios = <&qcom_pinmux 7 0>; -+ }; -+ -+ usb3 { -+ label = "r7500:amber:usb3"; -+ gpios = <&qcom_pinmux 8 0>; -+ }; -+ -+ status { -+ label = "r7500:amber:status"; -+ gpios = <&qcom_pinmux 9 0>; -+ }; -+ -+ internet { -+ label = "r7500:white:internet"; -+ gpios = <&qcom_pinmux 22 0>; -+ }; -+ -+ wan { -+ label = "r7500:white:wan"; -+ gpios = <&qcom_pinmux 23 0>; -+ }; -+ -+ wps { -+ label = "r7500:white:wps"; -+ gpios = <&qcom_pinmux 24 0>; -+ }; -+ -+ esata { -+ label = "r7500:white:esata"; -+ gpios = <&qcom_pinmux 26 0>; -+ }; -+ -+ power { -+ label = "r7500:white:power"; -+ gpios = <&qcom_pinmux 53 0>; -+ default-state = "on"; -+ }; -+ -+ rfkill { -+ label = "r7500:white:rfkill"; -+ gpios = <&qcom_pinmux 64 0>; -+ }; -+ -+ wifi5g { -+ label = "r7500:white:wifi5g"; -+ gpios = <&qcom_pinmux 67 0>; -+ }; -+ }; -+}; -+ -+&adm_dma { -+ status = "ok"; -+}; diff --git a/target/linux/ipq806x/patches-3.18/302-mtd-qcom-smem-rename-rootfs-ubi.patch b/target/linux/ipq806x/patches-3.18/302-mtd-qcom-smem-rename-rootfs-ubi.patch deleted file mode 100644 index 471a87ba6806..000000000000 --- a/target/linux/ipq806x/patches-3.18/302-mtd-qcom-smem-rename-rootfs-ubi.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- a/drivers/mtd/qcom_smem_part.c -+++ b/drivers/mtd/qcom_smem_part.c -@@ -192,6 +192,10 @@ static int parse_qcom_smem_partitions(st - m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); - m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); - -+ /* "rootfs" conflicts with OpenWrt auto mounting */ -+ if (mtd_type_is_nand(master) && !strcmp(m_part->name, "rootfs")) -+ m_part->name = "ubi"; -+ - /* - * The last SMEM partition may have its size marked as - * something like 0xffffffff, which means "until the end of the diff --git a/target/linux/ipq806x/patches-3.18/700-clk-qcom-Add-support-for-NSS-GMAC-clocks-and-resets.patch b/target/linux/ipq806x/patches-3.18/700-clk-qcom-Add-support-for-NSS-GMAC-clocks-and-resets.patch deleted file mode 100644 index 22d28ac63834..000000000000 --- a/target/linux/ipq806x/patches-3.18/700-clk-qcom-Add-support-for-NSS-GMAC-clocks-and-resets.patch +++ /dev/null @@ -1,733 +0,0 @@ -From 2fbb18f85826a9ba308fedb2cf90d3a661a39fd7 Mon Sep 17 00:00:00 2001 -From: Stephen Boyd -Date: Fri, 27 Mar 2015 00:16:14 -0700 -Subject: [PATCH] clk: qcom: Add support for NSS/GMAC clocks and resets - -Add the NSS/GMAC clocks and the TCM clock and NSS resets. - -Signed-off-by: Stephen Boyd ---- - drivers/clk/qcom/gcc-ipq806x.c | 594 ++++++++++++++++++++++++++- - drivers/clk/qcom/gcc-ipq806x.c.rej | 50 +++ - include/dt-bindings/clock/qcom,gcc-ipq806x.h | 2 + - include/dt-bindings/reset/qcom,gcc-ipq806x.h | 43 ++ - 4 files changed, 688 insertions(+), 1 deletion(-) - create mode 100644 drivers/clk/qcom/gcc-ipq806x.c.rej - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -209,11 +209,46 @@ static struct clk_regmap pll14_vote = { - }, - }; - -+#define NSS_PLL_RATE(f, _l, _m, _n, i) \ -+ { \ -+ .freq = f, \ -+ .l = _l, \ -+ .m = _m, \ -+ .n = _n, \ -+ .ibits = i, \ -+ } -+ -+static struct pll_freq_tbl pll18_freq_tbl[] = { -+ NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625), -+ NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625), -+}; -+ -+static struct clk_pll pll18 = { -+ .l_reg = 0x31a4, -+ .m_reg = 0x31a8, -+ .n_reg = 0x31ac, -+ .config_reg = 0x31b4, -+ .mode_reg = 0x31a0, -+ .status_reg = 0x31b8, -+ .status_bit = 16, -+ .post_div_shift = 16, -+ .post_div_width = 1, -+ .freq_tbl = pll18_freq_tbl, -+ .clkr.hw.init = &(struct clk_init_data){ -+ .name = "pll18", -+ .parent_names = (const char *[]){ "pxo" }, -+ .num_parents = 1, -+ .ops = &clk_pll_ops, -+ }, -+}; -+ - #define P_PXO 0 - #define P_PLL8 1 - #define P_PLL3 1 - #define P_PLL0 2 - #define P_CXO 2 -+#define P_PLL14 3 -+#define P_PLL18 4 - - static const u8 gcc_pxo_pll8_map[] = { - [P_PXO] = 0, -@@ -264,6 +299,22 @@ static const char *gcc_pxo_pll8_pll0_map - "pll0_vote", - }; - -+static const u8 gcc_pxo_pll8_pll14_pll18_pll0_map[] = { -+ [P_PXO] = 0 , -+ [P_PLL8] = 4, -+ [P_PLL0] = 2, -+ [P_PLL14] = 5, -+ [P_PLL18] = 1, -+}; -+ -+static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = { -+ "pxo", -+ "pll8_vote", -+ "pll0_vote", -+ "pll14", -+ "pll18", -+}; -+ - static struct freq_tbl clk_tbl_gsbi_uart[] = { - { 1843200, P_PLL8, 2, 6, 625 }, - { 3686400, P_PLL8, 2, 12, 625 }, -@@ -2269,6 +2320,472 @@ static struct clk_branch ebi2_aon_clk = - }, - }; - -+static const struct freq_tbl clk_tbl_gmac[] = { -+ { 133000000, P_PLL0, 1, 50, 301 }, -+ { 266000000, P_PLL0, 1, 127, 382 }, -+ { } -+}; -+ -+static struct clk_dyn_rcg gmac_core1_src = { -+ .ns_reg[0] = 0x3cac, -+ .ns_reg[1] = 0x3cb0, -+ .md_reg[0] = 0x3ca4, -+ .md_reg[1] = 0x3ca8, -+ .bank_reg = 0x3ca0, -+ .mn[0] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .mn[1] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_gmac, -+ .clkr = { -+ .enable_reg = 0x3ca0, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "gmac_core1_src", -+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .num_parents = 5, -+ .ops = &clk_dyn_rcg_ops, -+ }, -+ }, -+}; -+ -+static struct clk_branch gmac_core1_clk = { -+ .halt_reg = 0x3c20, -+ .halt_bit = 4, -+ .hwcg_reg = 0x3cb4, -+ .hwcg_bit = 6, -+ .clkr = { -+ .enable_reg = 0x3cb4, -+ .enable_mask = BIT(4), -+ .hw.init = &(struct clk_init_data){ -+ .name = "gmac_core1_clk", -+ .parent_names = (const char *[]){ -+ "gmac_core1_src", -+ }, -+ .num_parents = 1, -+ .ops = &clk_branch_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+ }, -+}; -+ -+static struct clk_dyn_rcg gmac_core2_src = { -+ .ns_reg[0] = 0x3ccc, -+ .ns_reg[1] = 0x3cd0, -+ .md_reg[0] = 0x3cc4, -+ .md_reg[1] = 0x3cc8, -+ .bank_reg = 0x3ca0, -+ .mn[0] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .mn[1] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_gmac, -+ .clkr = { -+ .enable_reg = 0x3cc0, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "gmac_core2_src", -+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .num_parents = 5, -+ .ops = &clk_dyn_rcg_ops, -+ }, -+ }, -+}; -+ -+static struct clk_branch gmac_core2_clk = { -+ .halt_reg = 0x3c20, -+ .halt_bit = 5, -+ .hwcg_reg = 0x3cd4, -+ .hwcg_bit = 6, -+ .clkr = { -+ .enable_reg = 0x3cd4, -+ .enable_mask = BIT(4), -+ .hw.init = &(struct clk_init_data){ -+ .name = "gmac_core2_clk", -+ .parent_names = (const char *[]){ -+ "gmac_core2_src", -+ }, -+ .num_parents = 1, -+ .ops = &clk_branch_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+ }, -+}; -+ -+static struct clk_dyn_rcg gmac_core3_src = { -+ .ns_reg[0] = 0x3cec, -+ .ns_reg[1] = 0x3cf0, -+ .md_reg[0] = 0x3ce4, -+ .md_reg[1] = 0x3ce8, -+ .bank_reg = 0x3ce0, -+ .mn[0] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .mn[1] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_gmac, -+ .clkr = { -+ .enable_reg = 0x3ce0, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "gmac_core3_src", -+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .num_parents = 5, -+ .ops = &clk_dyn_rcg_ops, -+ }, -+ }, -+}; -+ -+static struct clk_branch gmac_core3_clk = { -+ .halt_reg = 0x3c20, -+ .halt_bit = 6, -+ .hwcg_reg = 0x3cf4, -+ .hwcg_bit = 6, -+ .clkr = { -+ .enable_reg = 0x3cf4, -+ .enable_mask = BIT(4), -+ .hw.init = &(struct clk_init_data){ -+ .name = "gmac_core3_clk", -+ .parent_names = (const char *[]){ -+ "gmac_core3_src", -+ }, -+ .num_parents = 1, -+ .ops = &clk_branch_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+ }, -+}; -+ -+static struct clk_dyn_rcg gmac_core4_src = { -+ .ns_reg[0] = 0x3d0c, -+ .ns_reg[1] = 0x3d10, -+ .md_reg[0] = 0x3d04, -+ .md_reg[1] = 0x3d08, -+ .bank_reg = 0x3d00, -+ .mn[0] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .mn[1] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_gmac, -+ .clkr = { -+ .enable_reg = 0x3d00, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "gmac_core4_src", -+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .num_parents = 5, -+ .ops = &clk_dyn_rcg_ops, -+ }, -+ }, -+}; -+ -+static struct clk_branch gmac_core4_clk = { -+ .halt_reg = 0x3c20, -+ .halt_bit = 7, -+ .hwcg_reg = 0x3d14, -+ .hwcg_bit = 6, -+ .clkr = { -+ .enable_reg = 0x3d14, -+ .enable_mask = BIT(4), -+ .hw.init = &(struct clk_init_data){ -+ .name = "gmac_core4_clk", -+ .parent_names = (const char *[]){ -+ "gmac_core4_src", -+ }, -+ .num_parents = 1, -+ .ops = &clk_branch_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+ }, -+}; -+ -+static const struct freq_tbl clk_tbl_nss_tcm[] = { -+ { 266000000, P_PLL0, 3, 0, 0 }, -+ { 400000000, P_PLL0, 2, 0, 0 }, -+ { } -+}; -+ -+static struct clk_dyn_rcg nss_tcm_src = { -+ .ns_reg[0] = 0x3dc4, -+ .ns_reg[1] = 0x3dc8, -+ .bank_reg = 0x3dc0, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 4, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 4, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_nss_tcm, -+ .clkr = { -+ .enable_reg = 0x3dc0, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "nss_tcm_src", -+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .num_parents = 5, -+ .ops = &clk_dyn_rcg_ops, -+ }, -+ }, -+}; -+ -+static struct clk_branch nss_tcm_clk = { -+ .halt_reg = 0x3c20, -+ .halt_bit = 14, -+ .clkr = { -+ .enable_reg = 0x3dd0, -+ .enable_mask = BIT(6) | BIT(4), -+ .hw.init = &(struct clk_init_data){ -+ .name = "nss_tcm_clk", -+ .parent_names = (const char *[]){ -+ "nss_tcm_src", -+ }, -+ .num_parents = 1, -+ .ops = &clk_branch_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+ }, -+}; -+ -+static const struct freq_tbl clk_tbl_nss[] = { -+ { 110000000, P_PLL18, 1, 1, 5 }, -+ { 275000000, P_PLL18, 2, 0, 0 }, -+ { 550000000, P_PLL18, 1, 0, 0 }, -+ { 733000000, P_PLL18, 1, 0, 0 }, -+ { } -+}; -+ -+static struct clk_dyn_rcg ubi32_core1_src_clk = { -+ .ns_reg[0] = 0x3d2c, -+ .ns_reg[1] = 0x3d30, -+ .md_reg[0] = 0x3d24, -+ .md_reg[1] = 0x3d28, -+ .bank_reg = 0x3d20, -+ .mn[0] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .mn[1] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_nss, -+ .clkr = { -+ .enable_reg = 0x3d20, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ubi32_core1_src_clk", -+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .num_parents = 5, -+ .ops = &clk_dyn_rcg_ops, -+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, -+ }, -+ }, -+}; -+ -+static struct clk_dyn_rcg ubi32_core2_src_clk = { -+ .ns_reg[0] = 0x3d4c, -+ .ns_reg[1] = 0x3d50, -+ .md_reg[0] = 0x3d44, -+ .md_reg[1] = 0x3d48, -+ .bank_reg = 0x3d40, -+ .mn[0] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .mn[1] = { -+ .mnctr_en_bit = 8, -+ .mnctr_reset_bit = 7, -+ .mnctr_mode_shift = 5, -+ .n_val_shift = 16, -+ .m_val_shift = 16, -+ .width = 8, -+ }, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 2, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_nss, -+ .clkr = { -+ .enable_reg = 0x3d40, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ubi32_core2_src_clk", -+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .num_parents = 5, -+ .ops = &clk_dyn_rcg_ops, -+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, -+ }, -+ }, -+}; -+ - static struct clk_regmap *gcc_ipq806x_clks[] = { - [PLL0] = &pll0.clkr, - [PLL0_VOTE] = &pll0_vote, -@@ -2277,6 +2794,7 @@ static struct clk_regmap *gcc_ipq806x_cl - [PLL8_VOTE] = &pll8_vote, - [PLL14] = &pll14.clkr, - [PLL14_VOTE] = &pll14_vote, -+ [PLL18] = &pll18.clkr, - [GSBI1_UART_SRC] = &gsbi1_uart_src.clkr, - [GSBI1_UART_CLK] = &gsbi1_uart_clk.clkr, - [GSBI2_UART_SRC] = &gsbi2_uart_src.clkr, -@@ -2376,6 +2894,18 @@ static struct clk_regmap *gcc_ipq806x_cl - [PLL9] = &hfpll0.clkr, - [PLL10] = &hfpll1.clkr, - [PLL12] = &hfpll_l2.clkr, -+ [GMAC_CORE1_CLK_SRC] = &gmac_core1_src.clkr, -+ [GMAC_CORE1_CLK] = &gmac_core1_clk.clkr, -+ [GMAC_CORE2_CLK_SRC] = &gmac_core2_src.clkr, -+ [GMAC_CORE2_CLK] = &gmac_core2_clk.clkr, -+ [GMAC_CORE3_CLK_SRC] = &gmac_core3_src.clkr, -+ [GMAC_CORE3_CLK] = &gmac_core3_clk.clkr, -+ [GMAC_CORE4_CLK_SRC] = &gmac_core4_src.clkr, -+ [GMAC_CORE4_CLK] = &gmac_core4_clk.clkr, -+ [UBI32_CORE1_CLK_SRC] = &ubi32_core1_src_clk.clkr, -+ [UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr, -+ [NSSTCM_CLK_SRC] = &nss_tcm_src.clkr, -+ [NSSTCM_CLK] = &nss_tcm_clk.clkr, - }; - - static const struct qcom_reset_map gcc_ipq806x_resets[] = { -@@ -2494,6 +3024,48 @@ static const struct qcom_reset_map gcc_i - [USB30_1_PHY_RESET] = { 0x3b58, 0 }, - [NSSFB0_RESET] = { 0x3b60, 6 }, - [NSSFB1_RESET] = { 0x3b60, 7 }, -+ [UBI32_CORE1_CLKRST_CLAMP_RESET] = { 0x3d3c, 3}, -+ [UBI32_CORE1_CLAMP_RESET] = { 0x3d3c, 2 }, -+ [UBI32_CORE1_AHB_RESET] = { 0x3d3c, 1 }, -+ [UBI32_CORE1_AXI_RESET] = { 0x3d3c, 0 }, -+ [UBI32_CORE2_CLKRST_CLAMP_RESET] = { 0x3d5c, 3 }, -+ [UBI32_CORE2_CLAMP_RESET] = { 0x3d5c, 2 }, -+ [UBI32_CORE2_AHB_RESET] = { 0x3d5c, 1 }, -+ [UBI32_CORE2_AXI_RESET] = { 0x3d5c, 0 }, -+ [GMAC_CORE1_RESET] = { 0x3cbc, 0 }, -+ [GMAC_CORE2_RESET] = { 0x3cdc, 0 }, -+ [GMAC_CORE3_RESET] = { 0x3cfc, 0 }, -+ [GMAC_CORE4_RESET] = { 0x3d1c, 0 }, -+ [GMAC_AHB_RESET] = { 0x3e24, 0 }, -+ [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 }, -+ [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 }, -+ [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 }, -+ [NSS_CH0_HW_RST_RX_125M_N_RESET] = { 0x3b60, 3 }, -+ [NSS_CH0_RST_TX_125M_N_RESET] = { 0x3b60, 4 }, -+ [NSS_CH1_RST_RX_CLK_N_RESET] = { 0x3b60, 5 }, -+ [NSS_CH1_RST_TX_CLK_N_RESET] = { 0x3b60, 6 }, -+ [NSS_CH1_RST_RX_125M_N_RESET] = { 0x3b60, 7 }, -+ [NSS_CH1_HW_RST_RX_125M_N_RESET] = { 0x3b60, 8 }, -+ [NSS_CH1_RST_TX_125M_N_RESET] = { 0x3b60, 9 }, -+ [NSS_CH2_RST_RX_CLK_N_RESET] = { 0x3b60, 10 }, -+ [NSS_CH2_RST_TX_CLK_N_RESET] = { 0x3b60, 11 }, -+ [NSS_CH2_RST_RX_125M_N_RESET] = { 0x3b60, 12 }, -+ [NSS_CH2_HW_RST_RX_125M_N_RESET] = { 0x3b60, 13 }, -+ [NSS_CH2_RST_TX_125M_N_RESET] = { 0x3b60, 14 }, -+ [NSS_CH3_RST_RX_CLK_N_RESET] = { 0x3b60, 15 }, -+ [NSS_CH3_RST_TX_CLK_N_RESET] = { 0x3b60, 16 }, -+ [NSS_CH3_RST_RX_125M_N_RESET] = { 0x3b60, 17 }, -+ [NSS_CH3_HW_RST_RX_125M_N_RESET] = { 0x3b60, 18 }, -+ [NSS_CH3_RST_TX_125M_N_RESET] = { 0x3b60, 19 }, -+ [NSS_RST_RX_250M_125M_N_RESET] = { 0x3b60, 20 }, -+ [NSS_RST_TX_250M_125M_N_RESET] = { 0x3b60, 21 }, -+ [NSS_QSGMII_TXPI_RST_N_RESET] = { 0x3b60, 22 }, -+ [NSS_QSGMII_CDR_RST_N_RESET] = { 0x3b60, 23 }, -+ [NSS_SGMII2_CDR_RST_N_RESET] = { 0x3b60, 24 }, -+ [NSS_SGMII3_CDR_RST_N_RESET] = { 0x3b60, 25 }, -+ [NSS_CAL_PRBS_RST_N_RESET] = { 0x3b60, 26 }, -+ [NSS_LCKDT_RST_N_RESET] = { 0x3b60, 27 }, -+ [NSS_SRDS_N_RESET] = { 0x3b60, 28 }, - }; - - static const struct regmap_config gcc_ipq806x_regmap_config = { -@@ -2522,6 +3094,8 @@ static int gcc_ipq806x_probe(struct plat - { - struct clk *clk; - struct device *dev = &pdev->dev; -+ struct regmap *regmap; -+ int ret; - - /* Temporary until RPM clocks supported */ - clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 25000000); -@@ -2532,7 +3106,25 @@ static int gcc_ipq806x_probe(struct plat - if (IS_ERR(clk)) - return PTR_ERR(clk); - -- return qcom_cc_probe(pdev, &gcc_ipq806x_desc); -+ ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc); -+ if (ret) -+ return ret; -+ -+ regmap = dev_get_regmap(dev, NULL); -+ if (!regmap) -+ return -ENODEV; -+ -+ /* Setup PLL18 static bits */ -+ regmap_update_bits(regmap, 0x31a4, 0xffffffc0, 0x40000400); -+ regmap_write(regmap, 0x31b0, 0x3080); -+ -+ /* Set GMAC footswitch sleep/wakeup values */ -+ regmap_write(regmap, 0x3cb8, 8); -+ regmap_write(regmap, 0x3cd8, 8); -+ regmap_write(regmap, 0x3cf8, 8); -+ regmap_write(regmap, 0x3d18, 8); -+ -+ return 0; - } - - static int gcc_ipq806x_remove(struct platform_device *pdev) ---- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h -+++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h -@@ -290,5 +290,7 @@ - #define UBI32_CORE1_CLK 279 - #define UBI32_CORE2_CLK 280 - #define EBI2_AON_CLK 281 -+#define NSSTCM_CLK_SRC 282 -+#define NSSTCM_CLK 283 - - #endif ---- a/include/dt-bindings/reset/qcom,gcc-ipq806x.h -+++ b/include/dt-bindings/reset/qcom,gcc-ipq806x.h -@@ -129,4 +129,47 @@ - #define USB30_1_PHY_RESET 112 - #define NSSFB0_RESET 113 - #define NSSFB1_RESET 114 -+#define UBI32_CORE1_CLKRST_CLAMP_RESET 115 -+#define UBI32_CORE1_CLAMP_RESET 116 -+#define UBI32_CORE1_AHB_RESET 117 -+#define UBI32_CORE1_AXI_RESET 118 -+#define UBI32_CORE2_CLKRST_CLAMP_RESET 119 -+#define UBI32_CORE2_CLAMP_RESET 120 -+#define UBI32_CORE2_AHB_RESET 121 -+#define UBI32_CORE2_AXI_RESET 122 -+#define GMAC_CORE1_RESET 123 -+#define GMAC_CORE2_RESET 124 -+#define GMAC_CORE3_RESET 125 -+#define GMAC_CORE4_RESET 126 -+#define GMAC_AHB_RESET 127 -+#define NSS_CH0_RST_RX_CLK_N_RESET 128 -+#define NSS_CH0_RST_TX_CLK_N_RESET 129 -+#define NSS_CH0_RST_RX_125M_N_RESET 130 -+#define NSS_CH0_HW_RST_RX_125M_N_RESET 131 -+#define NSS_CH0_RST_TX_125M_N_RESET 132 -+#define NSS_CH1_RST_RX_CLK_N_RESET 133 -+#define NSS_CH1_RST_TX_CLK_N_RESET 134 -+#define NSS_CH1_RST_RX_125M_N_RESET 135 -+#define NSS_CH1_HW_RST_RX_125M_N_RESET 136 -+#define NSS_CH1_RST_TX_125M_N_RESET 137 -+#define NSS_CH2_RST_RX_CLK_N_RESET 138 -+#define NSS_CH2_RST_TX_CLK_N_RESET 139 -+#define NSS_CH2_RST_RX_125M_N_RESET 140 -+#define NSS_CH2_HW_RST_RX_125M_N_RESET 141 -+#define NSS_CH2_RST_TX_125M_N_RESET 142 -+#define NSS_CH3_RST_RX_CLK_N_RESET 143 -+#define NSS_CH3_RST_TX_CLK_N_RESET 144 -+#define NSS_CH3_RST_RX_125M_N_RESET 145 -+#define NSS_CH3_HW_RST_RX_125M_N_RESET 146 -+#define NSS_CH3_RST_TX_125M_N_RESET 147 -+#define NSS_RST_RX_250M_125M_N_RESET 148 -+#define NSS_RST_TX_250M_125M_N_RESET 149 -+#define NSS_QSGMII_TXPI_RST_N_RESET 150 -+#define NSS_QSGMII_CDR_RST_N_RESET 151 -+#define NSS_SGMII2_CDR_RST_N_RESET 152 -+#define NSS_SGMII3_CDR_RST_N_RESET 153 -+#define NSS_CAL_PRBS_RST_N_RESET 154 -+#define NSS_LCKDT_RST_N_RESET 155 -+#define NSS_SRDS_N_RESET 156 -+ - #endif diff --git a/target/linux/ipq806x/patches-3.18/701-stmmac_update_to_4.3.patch b/target/linux/ipq806x/patches-3.18/701-stmmac_update_to_4.3.patch deleted file mode 100644 index 539d1a1c4453..000000000000 --- a/target/linux/ipq806x/patches-3.18/701-stmmac_update_to_4.3.patch +++ /dev/null @@ -1,4258 +0,0 @@ ---- a/include/linux/stmmac.h -+++ b/include/linux/stmmac.h -@@ -99,6 +99,7 @@ struct plat_stmmacenet_data { - int phy_addr; - int interface; - struct stmmac_mdio_bus_data *mdio_bus_data; -+ struct device_node *phy_node; - struct stmmac_dma_cfg *dma_cfg; - int clk_csr; - int has_gmac; -@@ -114,32 +115,12 @@ struct plat_stmmacenet_data { - int maxmtu; - int multicast_filter_bins; - int unicast_filter_entries; -+ int tx_fifo_size; -+ int rx_fifo_size; - void (*fix_mac_speed)(void *priv, unsigned int speed); - void (*bus_setup)(void __iomem *ioaddr); -- void *(*setup)(struct platform_device *pdev); -- void (*free)(struct platform_device *pdev, void *priv); - int (*init)(struct platform_device *pdev, void *priv); - void (*exit)(struct platform_device *pdev, void *priv); -- void *custom_cfg; -- void *custom_data; - void *bsp_priv; - }; -- --/* of_data for SoC glue layer device tree bindings */ -- --struct stmmac_of_data { -- int has_gmac; -- int enh_desc; -- int tx_coe; -- int rx_coe; -- int bugged_jumbo; -- int pmt; -- int riwt_off; -- void (*fix_mac_speed)(void *priv, unsigned int speed); -- void (*bus_setup)(void __iomem *ioaddr); -- void *(*setup)(struct platform_device *pdev); -- void (*free)(struct platform_device *pdev, void *priv); -- int (*init)(struct platform_device *pdev, void *priv); -- void (*exit)(struct platform_device *pdev, void *priv); --}; - #endif ---- a/drivers/net/ethernet/stmicro/Kconfig -+++ b/drivers/net/ethernet/stmicro/Kconfig -@@ -7,9 +7,7 @@ config NET_VENDOR_STMICRO - default y - depends on HAS_IOMEM - ---help--- -- If you have a network (Ethernet) card belonging to this class, say Y -- and read the Ethernet-HOWTO, available from -- . -+ If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all ---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig -+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig -@@ -14,21 +14,54 @@ config STMMAC_ETH - if STMMAC_ETH - - config STMMAC_PLATFORM -- bool "STMMAC Platform bus support" -+ tristate "STMMAC Platform bus support" - depends on STMMAC_ETH -+ select MFD_SYSCON - default y - ---help--- -- This selects the platform specific bus support for -- the stmmac device driver. This is the driver used -- on many embedded STM platforms based on ARM and SuperH -- processors. -+ This selects the platform specific bus support for the stmmac driver. -+ This is the driver used on several SoCs: -+ STi, Allwinner, Amlogic Meson, Altera SOCFPGA. -+ - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -+if STMMAC_PLATFORM -+ -+config DWMAC_GENERIC -+ tristate "Generic driver for DWMAC" -+ default STMMAC_PLATFORM -+ ---help--- -+ Generic DWMAC driver for platforms that don't require any -+ platform specific code to function or is using platform -+ data for setup. -+ -+config DWMAC_IPQ806X -+ tristate "QCA IPQ806x DWMAC support" -+ default ARCH_QCOM -+ depends on OF -+ select MFD_SYSCON -+ help -+ Support for QCA IPQ806X DWMAC Ethernet. -+ -+ This selects the IPQ806x SoC glue layer support for the stmmac -+ device driver. This driver does not use any of the hardware -+ acceleration features available on this SoC. Network devices -+ will behave like standard non-accelerated ethernet interfaces. -+ -+config DWMAC_LPC18XX -+ tristate "NXP LPC18xx/43xx DWMAC support" -+ default ARCH_LPC18XX -+ depends on OF -+ select MFD_SYSCON -+ ---help--- -+ Support for NXP LPC18xx/43xx DWMAC Ethernet. -+ - config DWMAC_MESON -- bool "Amlogic Meson dwmac support" -- depends on STMMAC_PLATFORM && ARCH_MESON -+ tristate "Amlogic Meson dwmac support" -+ default ARCH_MESON -+ depends on OF - help - Support for Ethernet controller on Amlogic Meson SoCs. - -@@ -36,9 +69,22 @@ config DWMAC_MESON - the stmmac device driver. This driver is used for Meson6 and - Meson8 SoCs. - -+config DWMAC_ROCKCHIP -+ tristate "Rockchip dwmac support" -+ default ARCH_ROCKCHIP -+ depends on OF -+ select MFD_SYSCON -+ help -+ Support for Ethernet controller on Rockchip RK3288 SoC. -+ -+ This selects the Rockchip RK3288 SoC glue layer support for -+ the stmmac device driver. -+ - config DWMAC_SOCFPGA -- bool "SOCFPGA dwmac support" -- depends on STMMAC_PLATFORM && MFD_SYSCON && (ARCH_SOCFPGA || COMPILE_TEST) -+ tristate "SOCFPGA dwmac support" -+ default ARCH_SOCFPGA -+ depends on OF -+ select MFD_SYSCON - help - Support for ethernet controller on Altera SOCFPGA - -@@ -46,21 +92,11 @@ config DWMAC_SOCFPGA - for the stmmac device driver. This driver is used for - arria5 and cyclone5 FPGA SoCs. - --config DWMAC_SUNXI -- bool "Allwinner GMAC support" -- depends on STMMAC_PLATFORM && ARCH_SUNXI -- default y -- ---help--- -- Support for Allwinner A20/A31 GMAC ethernet controllers. -- -- This selects Allwinner SoC glue layer support for the -- stmmac device driver. This driver is used for A20/A31 -- GMAC ethernet controller. -- - config DWMAC_STI -- bool "STi GMAC support" -- depends on STMMAC_PLATFORM && ARCH_STI -- default y -+ tristate "STi GMAC support" -+ default ARCH_STI -+ depends on OF -+ select MFD_SYSCON - ---help--- - Support for ethernet controller on STi SOCs. - -@@ -68,8 +104,20 @@ config DWMAC_STI - device driver. This driver is used on for the STi series - SOCs GMAC ethernet controller. - -+config DWMAC_SUNXI -+ tristate "Allwinner GMAC support" -+ default ARCH_SUNXI -+ depends on OF -+ ---help--- -+ Support for Allwinner A20/A31 GMAC ethernet controllers. -+ -+ This selects Allwinner SoC glue layer support for the -+ stmmac device driver. This driver is used for A20/A31 -+ GMAC ethernet controller. -+endif -+ - config STMMAC_PCI -- bool "STMMAC PCI bus support" -+ tristate "STMMAC PCI bus support" - depends on STMMAC_ETH && PCI - ---help--- - This is to select the Synopsys DWMAC available on PCI devices, -@@ -79,22 +127,4 @@ config STMMAC_PCI - D1215994A VIRTEX FPGA board. - - If unsure, say N. -- --config STMMAC_DEBUG_FS -- bool "Enable monitoring via sysFS " -- default n -- depends on STMMAC_ETH && DEBUG_FS -- ---help--- -- The stmmac entry in /sys reports DMA TX/RX rings -- or (if supported) the HW cap register. -- --config STMMAC_DA -- bool "STMMAC DMA arbitration scheme" -- default n -- ---help--- -- Selecting this option, rx has priority over Tx (only for Giga -- Ethernet device). -- By default, the DMA arbitration scheme is based on Round-robin -- (rx:tx priority is 1:1). -- - endif ---- a/drivers/net/ethernet/stmicro/stmmac/Makefile -+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile -@@ -1,11 +1,20 @@ - obj-$(CONFIG_STMMAC_ETH) += stmmac.o --stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o --stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o --stmmac-$(CONFIG_DWMAC_MESON) += dwmac-meson.o --stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o --stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o --stmmac-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o - stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ -- chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ -- dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ -+ chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ -+ dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ - mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y) -+ -+# Ordering matters. Generic driver must be last. -+obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o -+obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o -+obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o -+obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o -+obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o -+obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o -+obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o -+obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o -+obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o -+stmmac-platform-objs:= stmmac_platform.o -+ -+obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o -+stmmac-pci-objs:= stmmac_pci.o ---- a/drivers/net/ethernet/stmicro/stmmac/common.h -+++ b/drivers/net/ethernet/stmicro/stmmac/common.h -@@ -44,6 +44,7 @@ - #undef FRAME_FILTER_DEBUG - /* #define FRAME_FILTER_DEBUG */ - -+/* Extra statistic and debug information exposed by ethtool */ - struct stmmac_extra_stats { - /* Transmit errors */ - unsigned long tx_underflow ____cacheline_aligned; -@@ -149,7 +150,7 @@ struct stmmac_extra_stats { - #define MAC_CSR_H_FRQ_MASK 0x20 - - #define HASH_TABLE_SIZE 64 --#define PAUSE_TIME 0x200 -+#define PAUSE_TIME 0xffff - - /* Flow Control defines */ - #define FLOW_OFF 0 -@@ -220,6 +221,7 @@ enum dma_irq_status { - handle_tx = 0x8, - }; - -+/* EEE and LPI defines */ - #define CORE_IRQ_TX_PATH_IN_LPI_MODE (1 << 0) - #define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 1) - #define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 2) -@@ -229,6 +231,7 @@ enum dma_irq_status { - #define CORE_PCS_LINK_STATUS (1 << 6) - #define CORE_RGMII_IRQ (1 << 7) - -+/* Physical Coding Sublayer */ - struct rgmii_adv { - unsigned int pause; - unsigned int duplex; -@@ -294,6 +297,7 @@ struct dma_features { - - #define JUMBO_LEN 9000 - -+/* Descriptors helpers */ - struct stmmac_desc_ops { - /* DMA RX descriptor ring initialization */ - void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode, -@@ -341,6 +345,10 @@ struct stmmac_desc_ops { - int (*get_rx_timestamp_status) (void *desc, u32 ats); - }; - -+extern const struct stmmac_desc_ops enh_desc_ops; -+extern const struct stmmac_desc_ops ndesc_ops; -+ -+/* Specific DMA helpers */ - struct stmmac_dma_ops { - /* DMA core initialization */ - int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb, -@@ -349,7 +357,8 @@ struct stmmac_dma_ops { - void (*dump_regs) (void __iomem *ioaddr); - /* Set tx/rx threshold in the csr6 register - * An invalid value enables the store-and-forward mode */ -- void (*dma_mode) (void __iomem *ioaddr, int txmode, int rxmode); -+ void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode, -+ int rxfifosz); - /* To track extra statistic (if supported) */ - void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x, - void __iomem *ioaddr); -@@ -370,6 +379,7 @@ struct stmmac_dma_ops { - - struct mac_device_info; - -+/* Helpers to program the MAC core */ - struct stmmac_ops { - /* MAC core initialization */ - void (*core_init)(struct mac_device_info *hw, int mtu); -@@ -400,6 +410,7 @@ struct stmmac_ops { - void (*get_adv)(struct mac_device_info *hw, struct rgmii_adv *adv); - }; - -+/* PTP and HW Timer helpers */ - struct stmmac_hwtimestamp { - void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data); - void (*config_sub_second_increment) (void __iomem *ioaddr); -@@ -410,6 +421,8 @@ struct stmmac_hwtimestamp { - u64(*get_systime) (void __iomem *ioaddr); - }; - -+extern const struct stmmac_hwtimestamp stmmac_ptp; -+ - struct mac_link { - int port; - int duplex; -@@ -421,6 +434,7 @@ struct mii_regs { - unsigned int data; /* MII Data */ - }; - -+/* Helpers to manage the descriptors for chain and ring modes */ - struct stmmac_mode_ops { - void (*init) (void *des, dma_addr_t phy_addr, unsigned int size, - unsigned int extend_desc); ---- /dev/null -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c -@@ -0,0 +1,81 @@ -+/* -+ * Generic DWMAC platform driver -+ * -+ * Copyright (C) 2007-2011 STMicroelectronics Ltd -+ * Copyright (C) 2015 Joachim Eastwood -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+ -+#include -+#include -+#include -+ -+#include "stmmac.h" -+#include "stmmac_platform.h" -+ -+static int dwmac_generic_probe(struct platform_device *pdev) -+{ -+ struct plat_stmmacenet_data *plat_dat; -+ struct stmmac_resources stmmac_res; -+ int ret; -+ -+ ret = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (ret) -+ return ret; -+ -+ if (pdev->dev.of_node) { -+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); -+ if (IS_ERR(plat_dat)) { -+ dev_err(&pdev->dev, "dt configuration failed\n"); -+ return PTR_ERR(plat_dat); -+ } -+ } else { -+ plat_dat = dev_get_platdata(&pdev->dev); -+ if (!plat_dat) { -+ dev_err(&pdev->dev, "no platform data provided\n"); -+ return -EINVAL; -+ } -+ -+ /* Set default value for multicast hash bins */ -+ plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; -+ -+ /* Set default value for unicast filter entries */ -+ plat_dat->unicast_filter_entries = 1; -+ } -+ -+ /* Custom initialisation (if needed) */ -+ if (plat_dat->init) { -+ ret = plat_dat->init(pdev, plat_dat->bsp_priv); -+ if (ret) -+ return ret; -+ } -+ -+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); -+} -+ -+static const struct of_device_id dwmac_generic_match[] = { -+ { .compatible = "st,spear600-gmac"}, -+ { .compatible = "snps,dwmac-3.610"}, -+ { .compatible = "snps,dwmac-3.70a"}, -+ { .compatible = "snps,dwmac-3.710"}, -+ { .compatible = "snps,dwmac"}, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, dwmac_generic_match); -+ -+static struct platform_driver dwmac_generic_driver = { -+ .probe = dwmac_generic_probe, -+ .remove = stmmac_pltfr_remove, -+ .driver = { -+ .name = STMMAC_RESOURCE_NAME, -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = of_match_ptr(dwmac_generic_match), -+ }, -+}; -+module_platform_driver(dwmac_generic_driver); -+ -+MODULE_DESCRIPTION("Generic dwmac driver"); -+MODULE_LICENSE("GPL v2"); ---- /dev/null -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -@@ -0,0 +1,373 @@ -+/* -+ * Qualcomm Atheros IPQ806x GMAC glue layer -+ * -+ * Copyright (C) 2015 The Linux Foundation -+ * -+ * Permission to use, copy, modify, and/or distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "stmmac_platform.h" -+ -+#define NSS_COMMON_CLK_GATE 0x8 -+#define NSS_COMMON_CLK_GATE_PTP_EN(x) BIT(0x10 + x) -+#define NSS_COMMON_CLK_GATE_RGMII_RX_EN(x) BIT(0x9 + (x * 2)) -+#define NSS_COMMON_CLK_GATE_RGMII_TX_EN(x) BIT(0x8 + (x * 2)) -+#define NSS_COMMON_CLK_GATE_GMII_RX_EN(x) BIT(0x4 + x) -+#define NSS_COMMON_CLK_GATE_GMII_TX_EN(x) BIT(0x0 + x) -+ -+#define NSS_COMMON_CLK_DIV0 0xC -+#define NSS_COMMON_CLK_DIV_OFFSET(x) (x * 8) -+#define NSS_COMMON_CLK_DIV_MASK 0x7f -+ -+#define NSS_COMMON_CLK_SRC_CTRL 0x14 -+#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (x) -+/* Mode is coded on 1 bit but is different depending on the MAC ID: -+ * MAC0: QSGMII=0 RGMII=1 -+ * MAC1: QSGMII=0 SGMII=0 RGMII=1 -+ * MAC2 & MAC3: QSGMII=0 SGMII=1 -+ */ -+#define NSS_COMMON_CLK_SRC_CTRL_RGMII(x) 1 -+#define NSS_COMMON_CLK_SRC_CTRL_SGMII(x) ((x >= 2) ? 1 : 0) -+ -+#define NSS_COMMON_MACSEC_CTL 0x28 -+#define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x) (1 << x) -+ -+#define NSS_COMMON_GMAC_CTL(x) (0x30 + (x * 4)) -+#define NSS_COMMON_GMAC_CTL_CSYS_REQ BIT(19) -+#define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL BIT(16) -+#define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET 8 -+#define NSS_COMMON_GMAC_CTL_IFG_OFFSET 0 -+#define NSS_COMMON_GMAC_CTL_IFG_MASK 0x3f -+ -+#define NSS_COMMON_CLK_DIV_RGMII_1000 1 -+#define NSS_COMMON_CLK_DIV_RGMII_100 9 -+#define NSS_COMMON_CLK_DIV_RGMII_10 99 -+#define NSS_COMMON_CLK_DIV_SGMII_1000 0 -+#define NSS_COMMON_CLK_DIV_SGMII_100 4 -+#define NSS_COMMON_CLK_DIV_SGMII_10 49 -+ -+#define QSGMII_PCS_MODE_CTL 0x68 -+#define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x) BIT((x * 8) + 7) -+ -+#define QSGMII_PCS_CAL_LCKDT_CTL 0x120 -+#define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19) -+ -+/* Only GMAC1/2/3 support SGMII and their CTL register are not contiguous */ -+#define QSGMII_PHY_SGMII_CTL(x) ((x == 1) ? 0x134 : \ -+ (0x13c + (4 * (x - 2)))) -+#define QSGMII_PHY_CDR_EN BIT(0) -+#define QSGMII_PHY_RX_FRONT_EN BIT(1) -+#define QSGMII_PHY_RX_SIGNAL_DETECT_EN BIT(2) -+#define QSGMII_PHY_TX_DRIVER_EN BIT(3) -+#define QSGMII_PHY_QSGMII_EN BIT(7) -+#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12 -+#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK 0x7 -+#define QSGMII_PHY_RX_DC_BIAS_OFFSET 18 -+#define QSGMII_PHY_RX_DC_BIAS_MASK 0x3 -+#define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20 -+#define QSGMII_PHY_RX_INPUT_EQU_MASK 0x3 -+#define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22 -+#define QSGMII_PHY_CDR_PI_SLEW_MASK 0x3 -+#define QSGMII_PHY_TX_DRV_AMP_OFFSET 28 -+#define QSGMII_PHY_TX_DRV_AMP_MASK 0xf -+ -+struct ipq806x_gmac { -+ struct platform_device *pdev; -+ struct regmap *nss_common; -+ struct regmap *qsgmii_csr; -+ uint32_t id; -+ struct clk *core_clk; -+ phy_interface_t phy_mode; -+}; -+ -+static int get_clk_div_sgmii(struct ipq806x_gmac *gmac, unsigned int speed) -+{ -+ struct device *dev = &gmac->pdev->dev; -+ int div; -+ -+ switch (speed) { -+ case SPEED_1000: -+ div = NSS_COMMON_CLK_DIV_SGMII_1000; -+ break; -+ -+ case SPEED_100: -+ div = NSS_COMMON_CLK_DIV_SGMII_100; -+ break; -+ -+ case SPEED_10: -+ div = NSS_COMMON_CLK_DIV_SGMII_10; -+ break; -+ -+ default: -+ dev_err(dev, "Speed %dMbps not supported in SGMII\n", speed); -+ return -EINVAL; -+ } -+ -+ return div; -+} -+ -+static int get_clk_div_rgmii(struct ipq806x_gmac *gmac, unsigned int speed) -+{ -+ struct device *dev = &gmac->pdev->dev; -+ int div; -+ -+ switch (speed) { -+ case SPEED_1000: -+ div = NSS_COMMON_CLK_DIV_RGMII_1000; -+ break; -+ -+ case SPEED_100: -+ div = NSS_COMMON_CLK_DIV_RGMII_100; -+ break; -+ -+ case SPEED_10: -+ div = NSS_COMMON_CLK_DIV_RGMII_10; -+ break; -+ -+ default: -+ dev_err(dev, "Speed %dMbps not supported in RGMII\n", speed); -+ return -EINVAL; -+ } -+ -+ return div; -+} -+ -+static int ipq806x_gmac_set_speed(struct ipq806x_gmac *gmac, unsigned int speed) -+{ -+ uint32_t clk_bits, val; -+ int div; -+ -+ switch (gmac->phy_mode) { -+ case PHY_INTERFACE_MODE_RGMII: -+ div = get_clk_div_rgmii(gmac, speed); -+ clk_bits = NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) | -+ NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id); -+ break; -+ -+ case PHY_INTERFACE_MODE_SGMII: -+ div = get_clk_div_sgmii(gmac, speed); -+ clk_bits = NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) | -+ NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id); -+ break; -+ -+ default: -+ dev_err(&gmac->pdev->dev, "Unsupported PHY mode: \"%s\"\n", -+ phy_modes(gmac->phy_mode)); -+ return -EINVAL; -+ } -+ -+ /* Disable the clocks */ -+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val); -+ val &= ~clk_bits; -+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val); -+ -+ /* Set the divider */ -+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_DIV0, &val); -+ val &= ~(NSS_COMMON_CLK_DIV_MASK -+ << NSS_COMMON_CLK_DIV_OFFSET(gmac->id)); -+ val |= div << NSS_COMMON_CLK_DIV_OFFSET(gmac->id); -+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_DIV0, val); -+ -+ /* Enable the clock back */ -+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val); -+ val |= clk_bits; -+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val); -+ -+ return 0; -+} -+ -+static void *ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac) -+{ -+ struct device *dev = &gmac->pdev->dev; -+ -+ gmac->phy_mode = of_get_phy_mode(dev->of_node); -+ if (gmac->phy_mode < 0) { -+ dev_err(dev, "missing phy mode property\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ if (of_property_read_u32(dev->of_node, "qcom,id", &gmac->id) < 0) { -+ dev_err(dev, "missing qcom id property\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ /* The GMACs are called 1 to 4 in the documentation, but to simplify the -+ * code and keep it consistent with the Linux convention, we'll number -+ * them from 0 to 3 here. -+ */ -+ if (gmac->id < 0 || gmac->id > 3) { -+ dev_err(dev, "invalid gmac id\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ gmac->core_clk = devm_clk_get(dev, "stmmaceth"); -+ if (IS_ERR(gmac->core_clk)) { -+ dev_err(dev, "missing stmmaceth clk property\n"); -+ return gmac->core_clk; -+ } -+ clk_set_rate(gmac->core_clk, 266000000); -+ -+ /* Setup the register map for the nss common registers */ -+ gmac->nss_common = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "qcom,nss-common"); -+ if (IS_ERR(gmac->nss_common)) { -+ dev_err(dev, "missing nss-common node\n"); -+ return gmac->nss_common; -+ } -+ -+ /* Setup the register map for the qsgmii csr registers */ -+ gmac->qsgmii_csr = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "qcom,qsgmii-csr"); -+ if (IS_ERR(gmac->qsgmii_csr)) { -+ dev_err(dev, "missing qsgmii-csr node\n"); -+ return gmac->qsgmii_csr; -+ } -+ -+ return NULL; -+} -+ -+static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed) -+{ -+ struct ipq806x_gmac *gmac = priv; -+ -+ ipq806x_gmac_set_speed(gmac, speed); -+} -+ -+static int ipq806x_gmac_probe(struct platform_device *pdev) -+{ -+ struct plat_stmmacenet_data *plat_dat; -+ struct stmmac_resources stmmac_res; -+ struct device *dev = &pdev->dev; -+ struct ipq806x_gmac *gmac; -+ int val; -+ void *err; -+ -+ val = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (val) -+ return val; -+ -+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); -+ if (IS_ERR(plat_dat)) -+ return PTR_ERR(plat_dat); -+ -+ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); -+ if (!gmac) -+ return -ENOMEM; -+ -+ gmac->pdev = pdev; -+ -+ err = ipq806x_gmac_of_parse(gmac); -+ if (IS_ERR(err)) { -+ dev_err(dev, "device tree parsing error\n"); -+ return PTR_ERR(err); -+ } -+ -+ regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL, -+ QSGMII_PCS_CAL_LCKDT_CTL_RST); -+ -+ /* Inter frame gap is set to 12 */ -+ val = 12 << NSS_COMMON_GMAC_CTL_IFG_OFFSET | -+ 12 << NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET; -+ /* We also initiate an AXI low power exit request */ -+ val |= NSS_COMMON_GMAC_CTL_CSYS_REQ; -+ switch (gmac->phy_mode) { -+ case PHY_INTERFACE_MODE_RGMII: -+ val |= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL; -+ break; -+ case PHY_INTERFACE_MODE_SGMII: -+ val &= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL; -+ break; -+ default: -+ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", -+ phy_modes(gmac->phy_mode)); -+ return -EINVAL; -+ } -+ regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val); -+ -+ /* Configure the clock src according to the mode */ -+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val); -+ val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id)); -+ switch (gmac->phy_mode) { -+ case PHY_INTERFACE_MODE_RGMII: -+ val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) << -+ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id); -+ break; -+ case PHY_INTERFACE_MODE_SGMII: -+ val |= NSS_COMMON_CLK_SRC_CTRL_SGMII(gmac->id) << -+ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id); -+ break; -+ default: -+ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", -+ phy_modes(gmac->phy_mode)); -+ return -EINVAL; -+ } -+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val); -+ -+ /* Enable PTP clock */ -+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val); -+ val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id); -+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val); -+ -+ if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) { -+ regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id), -+ QSGMII_PHY_CDR_EN | -+ QSGMII_PHY_RX_FRONT_EN | -+ QSGMII_PHY_RX_SIGNAL_DETECT_EN | -+ QSGMII_PHY_TX_DRIVER_EN | -+ QSGMII_PHY_QSGMII_EN | -+ 0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET | -+ 0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET | -+ 0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET | -+ 0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET | -+ 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET); -+ } -+ -+ plat_dat->has_gmac = true; -+ plat_dat->bsp_priv = gmac; -+ plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; -+ -+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); -+} -+ -+static const struct of_device_id ipq806x_gmac_dwmac_match[] = { -+ { .compatible = "qcom,ipq806x-gmac" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match); -+ -+static struct platform_driver ipq806x_gmac_dwmac_driver = { -+ .probe = ipq806x_gmac_probe, -+ .remove = stmmac_pltfr_remove, -+ .driver = { -+ .name = "ipq806x-gmac-dwmac", -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = ipq806x_gmac_dwmac_match, -+ }, -+}; -+module_platform_driver(ipq806x_gmac_dwmac_driver); -+ -+MODULE_AUTHOR("Mathieu Olivari "); -+MODULE_DESCRIPTION("Qualcomm Atheros IPQ806x DWMAC specific glue layer"); -+MODULE_LICENSE("Dual BSD/GPL"); ---- /dev/null -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c -@@ -0,0 +1,86 @@ -+/* -+ * DWMAC glue for NXP LPC18xx/LPC43xx Ethernet -+ * -+ * Copyright (C) 2015 Joachim Eastwood -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "stmmac_platform.h" -+ -+/* Register defines for CREG syscon */ -+#define LPC18XX_CREG_CREG6 0x12c -+# define LPC18XX_CREG_CREG6_ETHMODE_MASK 0x7 -+# define LPC18XX_CREG_CREG6_ETHMODE_MII 0x0 -+# define LPC18XX_CREG_CREG6_ETHMODE_RMII 0x4 -+ -+static int lpc18xx_dwmac_probe(struct platform_device *pdev) -+{ -+ struct plat_stmmacenet_data *plat_dat; -+ struct stmmac_resources stmmac_res; -+ struct regmap *reg; -+ u8 ethmode; -+ int ret; -+ -+ ret = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (ret) -+ return ret; -+ -+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); -+ if (IS_ERR(plat_dat)) -+ return PTR_ERR(plat_dat); -+ -+ plat_dat->has_gmac = true; -+ -+ reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); -+ if (IS_ERR(reg)) { -+ dev_err(&pdev->dev, "syscon lookup failed\n"); -+ return PTR_ERR(reg); -+ } -+ -+ if (plat_dat->interface == PHY_INTERFACE_MODE_MII) { -+ ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII; -+ } else if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) { -+ ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII; -+ } else { -+ dev_err(&pdev->dev, "Only MII and RMII mode supported\n"); -+ return -EINVAL; -+ } -+ -+ regmap_update_bits(reg, LPC18XX_CREG_CREG6, -+ LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode); -+ -+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); -+} -+ -+static const struct of_device_id lpc18xx_dwmac_match[] = { -+ { .compatible = "nxp,lpc1850-dwmac" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match); -+ -+static struct platform_driver lpc18xx_dwmac_driver = { -+ .probe = lpc18xx_dwmac_probe, -+ .remove = stmmac_pltfr_remove, -+ .driver = { -+ .name = "lpc18xx-dwmac", -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = lpc18xx_dwmac_match, -+ }, -+}; -+module_platform_driver(lpc18xx_dwmac_driver); -+ -+MODULE_AUTHOR("Joachim Eastwood "); -+MODULE_DESCRIPTION("DWMAC glue for LPC18xx/43xx Ethernet"); -+MODULE_LICENSE("GPL v2"); ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c -@@ -15,9 +15,12 @@ - #include - #include - #include -+#include - #include - #include - -+#include "stmmac_platform.h" -+ - #define ETHMAC_SPEED_100 BIT(1) - - struct meson_dwmac { -@@ -44,24 +47,54 @@ static void meson6_dwmac_fix_mac_speed(v - writel(val, dwmac->reg); - } - --static void *meson6_dwmac_setup(struct platform_device *pdev) -+static int meson6_dwmac_probe(struct platform_device *pdev) - { -+ struct plat_stmmacenet_data *plat_dat; -+ struct stmmac_resources stmmac_res; - struct meson_dwmac *dwmac; - struct resource *res; -+ int ret; -+ -+ ret = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (ret) -+ return ret; -+ -+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); -+ if (IS_ERR(plat_dat)) -+ return PTR_ERR(plat_dat); - - dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); - if (!dwmac) -- return ERR_PTR(-ENOMEM); -+ return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - dwmac->reg = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dwmac->reg)) -- return dwmac->reg; -+ return PTR_ERR(dwmac->reg); -+ -+ plat_dat->bsp_priv = dwmac; -+ plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed; - -- return dwmac; -+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); - } - --const struct stmmac_of_data meson6_dwmac_data = { -- .setup = meson6_dwmac_setup, -- .fix_mac_speed = meson6_dwmac_fix_mac_speed, -+static const struct of_device_id meson6_dwmac_match[] = { -+ { .compatible = "amlogic,meson6-dwmac" }, -+ { } - }; -+MODULE_DEVICE_TABLE(of, meson6_dwmac_match); -+ -+static struct platform_driver meson6_dwmac_driver = { -+ .probe = meson6_dwmac_probe, -+ .remove = stmmac_pltfr_remove, -+ .driver = { -+ .name = "meson6-dwmac", -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = meson6_dwmac_match, -+ }, -+}; -+module_platform_driver(meson6_dwmac_driver); -+ -+MODULE_AUTHOR("Beniamino Galvani "); -+MODULE_DESCRIPTION("Amlogic Meson DWMAC glue layer"); -+MODULE_LICENSE("GPL v2"); ---- /dev/null -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c -@@ -0,0 +1,626 @@ -+/** -+ * dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer -+ * -+ * Copyright (C) 2014 Chen-Zhi (Roger Chen) -+ * -+ * Chen-Zhi (Roger Chen) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "stmmac_platform.h" -+ -+struct rk_priv_data; -+struct rk_gmac_ops { -+ void (*set_to_rgmii)(struct rk_priv_data *bsp_priv, -+ int tx_delay, int rx_delay); -+ void (*set_to_rmii)(struct rk_priv_data *bsp_priv); -+ void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed); -+ void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed); -+}; -+ -+struct rk_priv_data { -+ struct platform_device *pdev; -+ int phy_iface; -+ struct regulator *regulator; -+ const struct rk_gmac_ops *ops; -+ -+ bool clk_enabled; -+ bool clock_input; -+ -+ struct clk *clk_mac; -+ struct clk *gmac_clkin; -+ struct clk *mac_clk_rx; -+ struct clk *mac_clk_tx; -+ struct clk *clk_mac_ref; -+ struct clk *clk_mac_refout; -+ struct clk *aclk_mac; -+ struct clk *pclk_mac; -+ -+ int tx_delay; -+ int rx_delay; -+ -+ struct regmap *grf; -+}; -+ -+#define HIWORD_UPDATE(val, mask, shift) \ -+ ((val) << (shift) | (mask) << ((shift) + 16)) -+ -+#define GRF_BIT(nr) (BIT(nr) | BIT(nr+16)) -+#define GRF_CLR_BIT(nr) (BIT(nr+16)) -+ -+#define RK3288_GRF_SOC_CON1 0x0248 -+#define RK3288_GRF_SOC_CON3 0x0250 -+ -+/*RK3288_GRF_SOC_CON1*/ -+#define RK3288_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | \ -+ GRF_CLR_BIT(8)) -+#define RK3288_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | \ -+ GRF_BIT(8)) -+#define RK3288_GMAC_FLOW_CTRL GRF_BIT(9) -+#define RK3288_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9) -+#define RK3288_GMAC_SPEED_10M GRF_CLR_BIT(10) -+#define RK3288_GMAC_SPEED_100M GRF_BIT(10) -+#define RK3288_GMAC_RMII_CLK_25M GRF_BIT(11) -+#define RK3288_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11) -+#define RK3288_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13)) -+#define RK3288_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13)) -+#define RK3288_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13)) -+#define RK3288_GMAC_RMII_MODE GRF_BIT(14) -+#define RK3288_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14) -+ -+/*RK3288_GRF_SOC_CON3*/ -+#define RK3288_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14) -+#define RK3288_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14) -+#define RK3288_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) -+#define RK3288_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) -+#define RK3288_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7) -+#define RK3288_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) -+ -+static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv, -+ int tx_delay, int rx_delay) -+{ -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (IS_ERR(bsp_priv->grf)) { -+ dev_err(dev, "Missing rockchip,grf property\n"); -+ return; -+ } -+ -+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, -+ RK3288_GMAC_PHY_INTF_SEL_RGMII | -+ RK3288_GMAC_RMII_MODE_CLR); -+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3, -+ RK3288_GMAC_RXCLK_DLY_ENABLE | -+ RK3288_GMAC_TXCLK_DLY_ENABLE | -+ RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) | -+ RK3288_GMAC_CLK_TX_DL_CFG(tx_delay)); -+} -+ -+static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv) -+{ -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (IS_ERR(bsp_priv->grf)) { -+ dev_err(dev, "Missing rockchip,grf property\n"); -+ return; -+ } -+ -+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, -+ RK3288_GMAC_PHY_INTF_SEL_RMII | RK3288_GMAC_RMII_MODE); -+} -+ -+static void rk3288_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -+{ -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (IS_ERR(bsp_priv->grf)) { -+ dev_err(dev, "Missing rockchip,grf property\n"); -+ return; -+ } -+ -+ if (speed == 10) -+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, -+ RK3288_GMAC_CLK_2_5M); -+ else if (speed == 100) -+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, -+ RK3288_GMAC_CLK_25M); -+ else if (speed == 1000) -+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, -+ RK3288_GMAC_CLK_125M); -+ else -+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); -+} -+ -+static void rk3288_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) -+{ -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (IS_ERR(bsp_priv->grf)) { -+ dev_err(dev, "Missing rockchip,grf property\n"); -+ return; -+ } -+ -+ if (speed == 10) { -+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, -+ RK3288_GMAC_RMII_CLK_2_5M | -+ RK3288_GMAC_SPEED_10M); -+ } else if (speed == 100) { -+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, -+ RK3288_GMAC_RMII_CLK_25M | -+ RK3288_GMAC_SPEED_100M); -+ } else { -+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed); -+ } -+} -+ -+static const struct rk_gmac_ops rk3288_ops = { -+ .set_to_rgmii = rk3288_set_to_rgmii, -+ .set_to_rmii = rk3288_set_to_rmii, -+ .set_rgmii_speed = rk3288_set_rgmii_speed, -+ .set_rmii_speed = rk3288_set_rmii_speed, -+}; -+ -+#define RK3368_GRF_SOC_CON15 0x043c -+#define RK3368_GRF_SOC_CON16 0x0440 -+ -+/* RK3368_GRF_SOC_CON15 */ -+#define RK3368_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \ -+ GRF_CLR_BIT(11)) -+#define RK3368_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \ -+ GRF_BIT(11)) -+#define RK3368_GMAC_FLOW_CTRL GRF_BIT(8) -+#define RK3368_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8) -+#define RK3368_GMAC_SPEED_10M GRF_CLR_BIT(7) -+#define RK3368_GMAC_SPEED_100M GRF_BIT(7) -+#define RK3368_GMAC_RMII_CLK_25M GRF_BIT(3) -+#define RK3368_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3) -+#define RK3368_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5)) -+#define RK3368_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5)) -+#define RK3368_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5)) -+#define RK3368_GMAC_RMII_MODE GRF_BIT(6) -+#define RK3368_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6) -+ -+/* RK3368_GRF_SOC_CON16 */ -+#define RK3368_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7) -+#define RK3368_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7) -+#define RK3368_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) -+#define RK3368_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) -+#define RK3368_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) -+#define RK3368_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) -+ -+static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv, -+ int tx_delay, int rx_delay) -+{ -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (IS_ERR(bsp_priv->grf)) { -+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); -+ return; -+ } -+ -+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, -+ RK3368_GMAC_PHY_INTF_SEL_RGMII | -+ RK3368_GMAC_RMII_MODE_CLR); -+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16, -+ RK3368_GMAC_RXCLK_DLY_ENABLE | -+ RK3368_GMAC_TXCLK_DLY_ENABLE | -+ RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) | -+ RK3368_GMAC_CLK_TX_DL_CFG(tx_delay)); -+} -+ -+static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv) -+{ -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (IS_ERR(bsp_priv->grf)) { -+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); -+ return; -+ } -+ -+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, -+ RK3368_GMAC_PHY_INTF_SEL_RMII | RK3368_GMAC_RMII_MODE); -+} -+ -+static void rk3368_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -+{ -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (IS_ERR(bsp_priv->grf)) { -+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); -+ return; -+ } -+ -+ if (speed == 10) -+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, -+ RK3368_GMAC_CLK_2_5M); -+ else if (speed == 100) -+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, -+ RK3368_GMAC_CLK_25M); -+ else if (speed == 1000) -+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, -+ RK3368_GMAC_CLK_125M); -+ else -+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); -+} -+ -+static void rk3368_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) -+{ -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (IS_ERR(bsp_priv->grf)) { -+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); -+ return; -+ } -+ -+ if (speed == 10) { -+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, -+ RK3368_GMAC_RMII_CLK_2_5M | -+ RK3368_GMAC_SPEED_10M); -+ } else if (speed == 100) { -+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, -+ RK3368_GMAC_RMII_CLK_25M | -+ RK3368_GMAC_SPEED_100M); -+ } else { -+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed); -+ } -+} -+ -+static const struct rk_gmac_ops rk3368_ops = { -+ .set_to_rgmii = rk3368_set_to_rgmii, -+ .set_to_rmii = rk3368_set_to_rmii, -+ .set_rgmii_speed = rk3368_set_rgmii_speed, -+ .set_rmii_speed = rk3368_set_rmii_speed, -+}; -+ -+static int gmac_clk_init(struct rk_priv_data *bsp_priv) -+{ -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ bsp_priv->clk_enabled = false; -+ -+ bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx"); -+ if (IS_ERR(bsp_priv->mac_clk_rx)) -+ dev_err(dev, "cannot get clock %s\n", -+ "mac_clk_rx"); -+ -+ bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx"); -+ if (IS_ERR(bsp_priv->mac_clk_tx)) -+ dev_err(dev, "cannot get clock %s\n", -+ "mac_clk_tx"); -+ -+ bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac"); -+ if (IS_ERR(bsp_priv->aclk_mac)) -+ dev_err(dev, "cannot get clock %s\n", -+ "aclk_mac"); -+ -+ bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac"); -+ if (IS_ERR(bsp_priv->pclk_mac)) -+ dev_err(dev, "cannot get clock %s\n", -+ "pclk_mac"); -+ -+ bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth"); -+ if (IS_ERR(bsp_priv->clk_mac)) -+ dev_err(dev, "cannot get clock %s\n", -+ "stmmaceth"); -+ -+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) { -+ bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref"); -+ if (IS_ERR(bsp_priv->clk_mac_ref)) -+ dev_err(dev, "cannot get clock %s\n", -+ "clk_mac_ref"); -+ -+ if (!bsp_priv->clock_input) { -+ bsp_priv->clk_mac_refout = -+ devm_clk_get(dev, "clk_mac_refout"); -+ if (IS_ERR(bsp_priv->clk_mac_refout)) -+ dev_err(dev, "cannot get clock %s\n", -+ "clk_mac_refout"); -+ } -+ } -+ -+ if (bsp_priv->clock_input) { -+ dev_info(dev, "clock input from PHY\n"); -+ } else { -+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) -+ clk_set_rate(bsp_priv->clk_mac, 50000000); -+ } -+ -+ return 0; -+} -+ -+static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable) -+{ -+ int phy_iface = phy_iface = bsp_priv->phy_iface; -+ -+ if (enable) { -+ if (!bsp_priv->clk_enabled) { -+ if (phy_iface == PHY_INTERFACE_MODE_RMII) { -+ if (!IS_ERR(bsp_priv->mac_clk_rx)) -+ clk_prepare_enable( -+ bsp_priv->mac_clk_rx); -+ -+ if (!IS_ERR(bsp_priv->clk_mac_ref)) -+ clk_prepare_enable( -+ bsp_priv->clk_mac_ref); -+ -+ if (!IS_ERR(bsp_priv->clk_mac_refout)) -+ clk_prepare_enable( -+ bsp_priv->clk_mac_refout); -+ } -+ -+ if (!IS_ERR(bsp_priv->aclk_mac)) -+ clk_prepare_enable(bsp_priv->aclk_mac); -+ -+ if (!IS_ERR(bsp_priv->pclk_mac)) -+ clk_prepare_enable(bsp_priv->pclk_mac); -+ -+ if (!IS_ERR(bsp_priv->mac_clk_tx)) -+ clk_prepare_enable(bsp_priv->mac_clk_tx); -+ -+ /** -+ * if (!IS_ERR(bsp_priv->clk_mac)) -+ * clk_prepare_enable(bsp_priv->clk_mac); -+ */ -+ mdelay(5); -+ bsp_priv->clk_enabled = true; -+ } -+ } else { -+ if (bsp_priv->clk_enabled) { -+ if (phy_iface == PHY_INTERFACE_MODE_RMII) { -+ if (!IS_ERR(bsp_priv->mac_clk_rx)) -+ clk_disable_unprepare( -+ bsp_priv->mac_clk_rx); -+ -+ if (!IS_ERR(bsp_priv->clk_mac_ref)) -+ clk_disable_unprepare( -+ bsp_priv->clk_mac_ref); -+ -+ if (!IS_ERR(bsp_priv->clk_mac_refout)) -+ clk_disable_unprepare( -+ bsp_priv->clk_mac_refout); -+ } -+ -+ if (!IS_ERR(bsp_priv->aclk_mac)) -+ clk_disable_unprepare(bsp_priv->aclk_mac); -+ -+ if (!IS_ERR(bsp_priv->pclk_mac)) -+ clk_disable_unprepare(bsp_priv->pclk_mac); -+ -+ if (!IS_ERR(bsp_priv->mac_clk_tx)) -+ clk_disable_unprepare(bsp_priv->mac_clk_tx); -+ /** -+ * if (!IS_ERR(bsp_priv->clk_mac)) -+ * clk_disable_unprepare(bsp_priv->clk_mac); -+ */ -+ bsp_priv->clk_enabled = false; -+ } -+ } -+ -+ return 0; -+} -+ -+static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable) -+{ -+ struct regulator *ldo = bsp_priv->regulator; -+ int ret; -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (!ldo) { -+ dev_err(dev, "no regulator found\n"); -+ return -1; -+ } -+ -+ if (enable) { -+ ret = regulator_enable(ldo); -+ if (ret) -+ dev_err(dev, "fail to enable phy-supply\n"); -+ } else { -+ ret = regulator_disable(ldo); -+ if (ret) -+ dev_err(dev, "fail to disable phy-supply\n"); -+ } -+ -+ return 0; -+} -+ -+static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev, -+ const struct rk_gmac_ops *ops) -+{ -+ struct rk_priv_data *bsp_priv; -+ struct device *dev = &pdev->dev; -+ int ret; -+ const char *strings = NULL; -+ int value; -+ -+ bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL); -+ if (!bsp_priv) -+ return ERR_PTR(-ENOMEM); -+ -+ bsp_priv->phy_iface = of_get_phy_mode(dev->of_node); -+ bsp_priv->ops = ops; -+ -+ bsp_priv->regulator = devm_regulator_get_optional(dev, "phy"); -+ if (IS_ERR(bsp_priv->regulator)) { -+ if (PTR_ERR(bsp_priv->regulator) == -EPROBE_DEFER) { -+ dev_err(dev, "phy regulator is not available yet, deferred probing\n"); -+ return ERR_PTR(-EPROBE_DEFER); -+ } -+ dev_err(dev, "no regulator found\n"); -+ bsp_priv->regulator = NULL; -+ } -+ -+ ret = of_property_read_string(dev->of_node, "clock_in_out", &strings); -+ if (ret) { -+ dev_err(dev, "Can not read property: clock_in_out.\n"); -+ bsp_priv->clock_input = true; -+ } else { -+ dev_info(dev, "clock input or output? (%s).\n", -+ strings); -+ if (!strcmp(strings, "input")) -+ bsp_priv->clock_input = true; -+ else -+ bsp_priv->clock_input = false; -+ } -+ -+ ret = of_property_read_u32(dev->of_node, "tx_delay", &value); -+ if (ret) { -+ bsp_priv->tx_delay = 0x30; -+ dev_err(dev, "Can not read property: tx_delay."); -+ dev_err(dev, "set tx_delay to 0x%x\n", -+ bsp_priv->tx_delay); -+ } else { -+ dev_info(dev, "TX delay(0x%x).\n", value); -+ bsp_priv->tx_delay = value; -+ } -+ -+ ret = of_property_read_u32(dev->of_node, "rx_delay", &value); -+ if (ret) { -+ bsp_priv->rx_delay = 0x10; -+ dev_err(dev, "Can not read property: rx_delay."); -+ dev_err(dev, "set rx_delay to 0x%x\n", -+ bsp_priv->rx_delay); -+ } else { -+ dev_info(dev, "RX delay(0x%x).\n", value); -+ bsp_priv->rx_delay = value; -+ } -+ -+ bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "rockchip,grf"); -+ bsp_priv->pdev = pdev; -+ -+ /*rmii or rgmii*/ -+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) { -+ dev_info(dev, "init for RGMII\n"); -+ bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay, -+ bsp_priv->rx_delay); -+ } else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) { -+ dev_info(dev, "init for RMII\n"); -+ bsp_priv->ops->set_to_rmii(bsp_priv); -+ } else { -+ dev_err(dev, "NO interface defined!\n"); -+ } -+ -+ gmac_clk_init(bsp_priv); -+ -+ return bsp_priv; -+} -+ -+static int rk_gmac_init(struct platform_device *pdev, void *priv) -+{ -+ struct rk_priv_data *bsp_priv = priv; -+ int ret; -+ -+ ret = phy_power_on(bsp_priv, true); -+ if (ret) -+ return ret; -+ -+ ret = gmac_clk_enable(bsp_priv, true); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static void rk_gmac_exit(struct platform_device *pdev, void *priv) -+{ -+ struct rk_priv_data *gmac = priv; -+ -+ phy_power_on(gmac, false); -+ gmac_clk_enable(gmac, false); -+} -+ -+static void rk_fix_speed(void *priv, unsigned int speed) -+{ -+ struct rk_priv_data *bsp_priv = priv; -+ struct device *dev = &bsp_priv->pdev->dev; -+ -+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) -+ bsp_priv->ops->set_rgmii_speed(bsp_priv, speed); -+ else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) -+ bsp_priv->ops->set_rmii_speed(bsp_priv, speed); -+ else -+ dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface); -+} -+ -+static int rk_gmac_probe(struct platform_device *pdev) -+{ -+ struct plat_stmmacenet_data *plat_dat; -+ struct stmmac_resources stmmac_res; -+ const struct rk_gmac_ops *data; -+ int ret; -+ -+ data = of_device_get_match_data(&pdev->dev); -+ if (!data) { -+ dev_err(&pdev->dev, "no of match data provided\n"); -+ return -EINVAL; -+ } -+ -+ ret = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (ret) -+ return ret; -+ -+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); -+ if (IS_ERR(plat_dat)) -+ return PTR_ERR(plat_dat); -+ -+ plat_dat->has_gmac = true; -+ plat_dat->init = rk_gmac_init; -+ plat_dat->exit = rk_gmac_exit; -+ plat_dat->fix_mac_speed = rk_fix_speed; -+ -+ plat_dat->bsp_priv = rk_gmac_setup(pdev, data); -+ if (IS_ERR(plat_dat->bsp_priv)) -+ return PTR_ERR(plat_dat->bsp_priv); -+ -+ ret = rk_gmac_init(pdev, plat_dat->bsp_priv); -+ if (ret) -+ return ret; -+ -+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); -+} -+ -+static const struct of_device_id rk_gmac_dwmac_match[] = { -+ { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops }, -+ { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match); -+ -+static struct platform_driver rk_gmac_dwmac_driver = { -+ .probe = rk_gmac_probe, -+ .remove = stmmac_pltfr_remove, -+ .driver = { -+ .name = "rk_gmac-dwmac", -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = rk_gmac_dwmac_match, -+ }, -+}; -+module_platform_driver(rk_gmac_dwmac_driver); -+ -+MODULE_AUTHOR("Chen-Zhi (Roger Chen) "); -+MODULE_DESCRIPTION("Rockchip RK3288 DWMAC specific glue layer"); -+MODULE_LICENSE("GPL"); ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c -@@ -23,7 +23,9 @@ - #include - #include - #include -+ - #include "stmmac.h" -+#include "stmmac_platform.h" - - #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 - #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 -@@ -89,7 +91,9 @@ static int socfpga_dwmac_parse_data(stru - STMMAC_RESOURCE_NAME); - if (IS_ERR(dwmac->stmmac_rst)) { - dev_info(dev, "Could not get reset control!\n"); -- return -EINVAL; -+ if (PTR_ERR(dwmac->stmmac_rst) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ dwmac->stmmac_rst = NULL; - } - - dwmac->interface = of_get_phy_mode(np); -@@ -171,31 +175,6 @@ static int socfpga_dwmac_setup(struct so - return 0; - } - --static void *socfpga_dwmac_probe(struct platform_device *pdev) --{ -- struct device *dev = &pdev->dev; -- int ret; -- struct socfpga_dwmac *dwmac; -- -- dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); -- if (!dwmac) -- return ERR_PTR(-ENOMEM); -- -- ret = socfpga_dwmac_parse_data(dwmac, dev); -- if (ret) { -- dev_err(dev, "Unable to parse OF data\n"); -- return ERR_PTR(ret); -- } -- -- ret = socfpga_dwmac_setup(dwmac); -- if (ret) { -- dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); -- return ERR_PTR(ret); -- } -- -- return dwmac; --} -- - static void socfpga_dwmac_exit(struct platform_device *pdev, void *priv) - { - struct socfpga_dwmac *dwmac = priv; -@@ -253,9 +232,65 @@ static int socfpga_dwmac_init(struct pla - return ret; - } - --const struct stmmac_of_data socfpga_gmac_data = { -- .setup = socfpga_dwmac_probe, -- .init = socfpga_dwmac_init, -- .exit = socfpga_dwmac_exit, -- .fix_mac_speed = socfpga_dwmac_fix_mac_speed, -+static int socfpga_dwmac_probe(struct platform_device *pdev) -+{ -+ struct plat_stmmacenet_data *plat_dat; -+ struct stmmac_resources stmmac_res; -+ struct device *dev = &pdev->dev; -+ int ret; -+ struct socfpga_dwmac *dwmac; -+ -+ ret = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (ret) -+ return ret; -+ -+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); -+ if (IS_ERR(plat_dat)) -+ return PTR_ERR(plat_dat); -+ -+ dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); -+ if (!dwmac) -+ return -ENOMEM; -+ -+ ret = socfpga_dwmac_parse_data(dwmac, dev); -+ if (ret) { -+ dev_err(dev, "Unable to parse OF data\n"); -+ return ret; -+ } -+ -+ ret = socfpga_dwmac_setup(dwmac); -+ if (ret) { -+ dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); -+ return ret; -+ } -+ -+ plat_dat->bsp_priv = dwmac; -+ plat_dat->init = socfpga_dwmac_init; -+ plat_dat->exit = socfpga_dwmac_exit; -+ plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; -+ -+ ret = socfpga_dwmac_init(pdev, plat_dat->bsp_priv); -+ if (ret) -+ return ret; -+ -+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); -+} -+ -+static const struct of_device_id socfpga_dwmac_match[] = { -+ { .compatible = "altr,socfpga-stmmac" }, -+ { } - }; -+MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); -+ -+static struct platform_driver socfpga_dwmac_driver = { -+ .probe = socfpga_dwmac_probe, -+ .remove = stmmac_pltfr_remove, -+ .driver = { -+ .name = "socfpga-dwmac", -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = socfpga_dwmac_match, -+ }, -+}; -+module_platform_driver(socfpga_dwmac_driver); -+ -+MODULE_LICENSE("GPL v2"); ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c -@@ -1,4 +1,4 @@ --/** -+/* - * dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer - * - * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited -@@ -17,11 +17,15 @@ - #include - #include - #include -+#include - #include - #include - #include -+#include - #include - -+#include "stmmac_platform.h" -+ - #define DWMAC_125MHZ 125000000 - #define DWMAC_50MHZ 50000000 - #define DWMAC_25MHZ 25000000 -@@ -35,9 +39,8 @@ - #define IS_PHY_IF_MODE_GBIT(iface) (IS_PHY_IF_MODE_RGMII(iface) || \ - iface == PHY_INTERFACE_MODE_GMII) - --/* STiH4xx register definitions (STiH415/STiH416/STiH407/STiH410 families) */ -- --/** -+/* STiH4xx register definitions (STiH415/STiH416/STiH407/STiH410 families) -+ * - * Below table summarizes the clock requirement and clock sources for - * supported phy interface modes with link speeds. - * ________________________________________________ -@@ -76,9 +79,7 @@ - #define STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK BIT(7) - #define STIH4XX_ETH_SEL_TXCLK_NOT_CLK125 BIT(6) - --/* STiD127 register definitions */ -- --/** -+/* STiD127 register definitions - *----------------------- - * src |BIT(6)| BIT(7)| - *----------------------- -@@ -104,13 +105,13 @@ - #define EN_MASK GENMASK(1, 1) - #define EN BIT(1) - --/** -+/* - * 3 bits [4:2] - * 000-GMII/MII - * 001-RGMII - * 010-SGMII - * 100-RMII --*/ -+ */ - #define MII_PHY_SEL_MASK GENMASK(4, 2) - #define ETH_PHY_SEL_RMII BIT(4) - #define ETH_PHY_SEL_SGMII BIT(3) -@@ -123,11 +124,16 @@ struct sti_dwmac { - bool ext_phyclk; /* Clock from external PHY */ - u32 tx_retime_src; /* TXCLK Retiming*/ - struct clk *clk; /* PHY clock */ -- int ctrl_reg; /* GMAC glue-logic control register */ -+ u32 ctrl_reg; /* GMAC glue-logic control register */ - int clk_sel_reg; /* GMAC ext clk selection register */ - struct device *dev; - struct regmap *regmap; - u32 speed; -+ void (*fix_retime_src)(void *priv, unsigned int speed); -+}; -+ -+struct sti_dwmac_of_data { -+ void (*fix_retime_src)(void *priv, unsigned int speed); - }; - - static u32 phy_intf_sels[] = { -@@ -222,8 +228,9 @@ static void stid127_fix_retime_src(void - regmap_update_bits(dwmac->regmap, reg, STID127_RETIME_SRC_MASK, val); - } - --static void sti_dwmac_ctrl_init(struct sti_dwmac *dwmac) -+static int sti_dwmac_init(struct platform_device *pdev, void *priv) - { -+ struct sti_dwmac *dwmac = priv; - struct regmap *regmap = dwmac->regmap; - int iface = dwmac->interface; - struct device *dev = dwmac->dev; -@@ -241,28 +248,8 @@ static void sti_dwmac_ctrl_init(struct s - - val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII; - regmap_update_bits(regmap, reg, ENMII_MASK, val); --} - --static int stix4xx_init(struct platform_device *pdev, void *priv) --{ -- struct sti_dwmac *dwmac = priv; -- u32 spd = dwmac->speed; -- -- sti_dwmac_ctrl_init(dwmac); -- -- stih4xx_fix_retime_src(priv, spd); -- -- return 0; --} -- --static int stid127_init(struct platform_device *pdev, void *priv) --{ -- struct sti_dwmac *dwmac = priv; -- u32 spd = dwmac->speed; -- -- sti_dwmac_ctrl_init(dwmac); -- -- stid127_fix_retime_src(priv, spd); -+ dwmac->fix_retime_src(priv, dwmac->speed); - - return 0; - } -@@ -286,11 +273,6 @@ static int sti_dwmac_parse_data(struct s - if (!np) - return -EINVAL; - -- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf"); -- if (!res) -- return -ENODATA; -- dwmac->ctrl_reg = res->start; -- - /* clk selection from extra syscfg register */ - dwmac->clk_sel_reg = -ENXIO; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-clkconf"); -@@ -301,6 +283,12 @@ static int sti_dwmac_parse_data(struct s - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - -+ err = of_property_read_u32_index(np, "st,syscon", 1, &dwmac->ctrl_reg); -+ if (err) { -+ dev_err(dev, "Can't get sysconfig ctrl offset (%d)\n", err); -+ return err; -+ } -+ - dwmac->dev = dev; - dwmac->interface = of_get_phy_mode(np); - dwmac->regmap = regmap; -@@ -310,16 +298,16 @@ static int sti_dwmac_parse_data(struct s - - if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) { - const char *rs; -- dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN; - - err = of_property_read_string(np, "st,tx-retime-src", &rs); -- if (err < 0) -+ if (err < 0) { - dev_warn(dev, "Use internal clock source\n"); -- -- if (!strcasecmp(rs, "clk_125")) -+ dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN; -+ } else if (!strcasecmp(rs, "clk_125")) { - dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125; -- else if (!strcasecmp(rs, "txclk")) -+ } else if (!strcasecmp(rs, "txclk")) { - dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK; -+ } - - dwmac->speed = SPEED_1000; - } -@@ -333,34 +321,80 @@ static int sti_dwmac_parse_data(struct s - return 0; - } - --static void *sti_dwmac_setup(struct platform_device *pdev) -+static int sti_dwmac_probe(struct platform_device *pdev) - { -+ struct plat_stmmacenet_data *plat_dat; -+ const struct sti_dwmac_of_data *data; -+ struct stmmac_resources stmmac_res; - struct sti_dwmac *dwmac; - int ret; - -+ data = of_device_get_match_data(&pdev->dev); -+ if (!data) { -+ dev_err(&pdev->dev, "No OF match data provided\n"); -+ return -EINVAL; -+ } -+ -+ ret = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (ret) -+ return ret; -+ -+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); -+ if (IS_ERR(plat_dat)) -+ return PTR_ERR(plat_dat); -+ - dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); - if (!dwmac) -- return ERR_PTR(-ENOMEM); -+ return -ENOMEM; - - ret = sti_dwmac_parse_data(dwmac, pdev); - if (ret) { - dev_err(&pdev->dev, "Unable to parse OF data\n"); -- return ERR_PTR(ret); -+ return ret; - } - -- return dwmac; -+ dwmac->fix_retime_src = data->fix_retime_src; -+ -+ plat_dat->bsp_priv = dwmac; -+ plat_dat->init = sti_dwmac_init; -+ plat_dat->exit = sti_dwmac_exit; -+ plat_dat->fix_mac_speed = data->fix_retime_src; -+ -+ ret = sti_dwmac_init(pdev, plat_dat->bsp_priv); -+ if (ret) -+ return ret; -+ -+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); - } - --const struct stmmac_of_data stih4xx_dwmac_data = { -- .fix_mac_speed = stih4xx_fix_retime_src, -- .setup = sti_dwmac_setup, -- .init = stix4xx_init, -- .exit = sti_dwmac_exit, -+static const struct sti_dwmac_of_data stih4xx_dwmac_data = { -+ .fix_retime_src = stih4xx_fix_retime_src, - }; - --const struct stmmac_of_data stid127_dwmac_data = { -- .fix_mac_speed = stid127_fix_retime_src, -- .setup = sti_dwmac_setup, -- .init = stid127_init, -- .exit = sti_dwmac_exit, -+static const struct sti_dwmac_of_data stid127_dwmac_data = { -+ .fix_retime_src = stid127_fix_retime_src, - }; -+ -+static const struct of_device_id sti_dwmac_match[] = { -+ { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data}, -+ { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data}, -+ { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data}, -+ { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data}, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, sti_dwmac_match); -+ -+static struct platform_driver sti_dwmac_driver = { -+ .probe = sti_dwmac_probe, -+ .remove = stmmac_pltfr_remove, -+ .driver = { -+ .name = "sti-dwmac", -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = sti_dwmac_match, -+ }, -+}; -+module_platform_driver(sti_dwmac_driver); -+ -+MODULE_AUTHOR("Srinivas Kandagatla "); -+MODULE_DESCRIPTION("STMicroelectronics DWMAC Specific Glue layer"); -+MODULE_LICENSE("GPL"); ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c -@@ -1,4 +1,4 @@ --/** -+/* - * dwmac-sunxi.c - Allwinner sunxi DWMAC specific glue layer - * - * Copyright (C) 2013 Chen-Yu Tsai -@@ -18,10 +18,14 @@ - - #include - #include -+#include - #include -+#include - #include - #include - -+#include "stmmac_platform.h" -+ - struct sunxi_priv_data { - int interface; - int clk_enabled; -@@ -29,35 +33,6 @@ struct sunxi_priv_data { - struct regulator *regulator; - }; - --static void *sun7i_gmac_setup(struct platform_device *pdev) --{ -- struct sunxi_priv_data *gmac; -- struct device *dev = &pdev->dev; -- -- gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); -- if (!gmac) -- return ERR_PTR(-ENOMEM); -- -- gmac->interface = of_get_phy_mode(dev->of_node); -- -- gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); -- if (IS_ERR(gmac->tx_clk)) { -- dev_err(dev, "could not get tx clock\n"); -- return gmac->tx_clk; -- } -- -- /* Optional regulator for PHY */ -- gmac->regulator = devm_regulator_get_optional(dev, "phy"); -- if (IS_ERR(gmac->regulator)) { -- if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) -- return ERR_PTR(-EPROBE_DEFER); -- dev_info(dev, "no regulator found\n"); -- gmac->regulator = NULL; -- } -- -- return gmac; --} -- - #define SUN7I_GMAC_GMII_RGMII_RATE 125000000 - #define SUN7I_GMAC_MII_RATE 25000000 - -@@ -128,13 +103,76 @@ static void sun7i_fix_speed(void *priv, - } - } - --/* of_data specifying hardware features and callbacks. -- * hardware features were copied from Allwinner drivers. */ --const struct stmmac_of_data sun7i_gmac_data = { -- .has_gmac = 1, -- .tx_coe = 1, -- .fix_mac_speed = sun7i_fix_speed, -- .setup = sun7i_gmac_setup, -- .init = sun7i_gmac_init, -- .exit = sun7i_gmac_exit, -+static int sun7i_gmac_probe(struct platform_device *pdev) -+{ -+ struct plat_stmmacenet_data *plat_dat; -+ struct stmmac_resources stmmac_res; -+ struct sunxi_priv_data *gmac; -+ struct device *dev = &pdev->dev; -+ int ret; -+ -+ ret = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (ret) -+ return ret; -+ -+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); -+ if (IS_ERR(plat_dat)) -+ return PTR_ERR(plat_dat); -+ -+ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); -+ if (!gmac) -+ return -ENOMEM; -+ -+ gmac->interface = of_get_phy_mode(dev->of_node); -+ -+ gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); -+ if (IS_ERR(gmac->tx_clk)) { -+ dev_err(dev, "could not get tx clock\n"); -+ return PTR_ERR(gmac->tx_clk); -+ } -+ -+ /* Optional regulator for PHY */ -+ gmac->regulator = devm_regulator_get_optional(dev, "phy"); -+ if (IS_ERR(gmac->regulator)) { -+ if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ dev_info(dev, "no regulator found\n"); -+ gmac->regulator = NULL; -+ } -+ -+ /* platform data specifying hardware features and callbacks. -+ * hardware features were copied from Allwinner drivers. */ -+ plat_dat->tx_coe = 1; -+ plat_dat->has_gmac = true; -+ plat_dat->bsp_priv = gmac; -+ plat_dat->init = sun7i_gmac_init; -+ plat_dat->exit = sun7i_gmac_exit; -+ plat_dat->fix_mac_speed = sun7i_fix_speed; -+ -+ ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv); -+ if (ret) -+ return ret; -+ -+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); -+} -+ -+static const struct of_device_id sun7i_dwmac_match[] = { -+ { .compatible = "allwinner,sun7i-a20-gmac" }, -+ { } - }; -+MODULE_DEVICE_TABLE(of, sun7i_dwmac_match); -+ -+static struct platform_driver sun7i_dwmac_driver = { -+ .probe = sun7i_gmac_probe, -+ .remove = stmmac_pltfr_remove, -+ .driver = { -+ .name = "sun7i-dwmac", -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = sun7i_dwmac_match, -+ }, -+}; -+module_platform_driver(sun7i_dwmac_driver); -+ -+MODULE_AUTHOR("Chen-Yu Tsai "); -+MODULE_DESCRIPTION("Allwinner sunxi DWMAC specific glue layer"); -+MODULE_LICENSE("GPL"); ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h -@@ -172,6 +172,7 @@ enum inter_frame_gap { - /* GMAC FLOW CTRL defines */ - #define GMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */ - #define GMAC_FLOW_CTRL_PT_SHIFT 16 -+#define GMAC_FLOW_CTRL_UP 0x00000008 /* Unicast pause frame enable */ - #define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */ - #define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */ - #define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */ -@@ -246,6 +247,56 @@ enum ttc_control { - #define DMA_CONTROL_FEF 0x00000080 - #define DMA_CONTROL_FUF 0x00000040 - -+/* Receive flow control activation field -+ * RFA field in DMA control register, bits 23,10:9 -+ */ -+#define DMA_CONTROL_RFA_MASK 0x00800600 -+ -+/* Receive flow control deactivation field -+ * RFD field in DMA control register, bits 22,12:11 -+ */ -+#define DMA_CONTROL_RFD_MASK 0x00401800 -+ -+/* RFD and RFA fields are encoded as follows -+ * -+ * Bit Field -+ * 0,00 - Full minus 1KB (only valid when rxfifo >= 4KB and EFC enabled) -+ * 0,01 - Full minus 2KB (only valid when rxfifo >= 4KB and EFC enabled) -+ * 0,10 - Full minus 3KB (only valid when rxfifo >= 4KB and EFC enabled) -+ * 0,11 - Full minus 4KB (only valid when rxfifo > 4KB and EFC enabled) -+ * 1,00 - Full minus 5KB (only valid when rxfifo > 8KB and EFC enabled) -+ * 1,01 - Full minus 6KB (only valid when rxfifo > 8KB and EFC enabled) -+ * 1,10 - Full minus 7KB (only valid when rxfifo > 8KB and EFC enabled) -+ * 1,11 - Reserved -+ * -+ * RFD should always be > RFA for a given FIFO size. RFD == RFA may work, -+ * but packet throughput performance may not be as expected. -+ * -+ * Be sure that bit 3 in GMAC Register 6 is set for Unicast Pause frame -+ * detection (IEEE Specification Requirement, Annex 31B, 31B.1, Pause -+ * Description). -+ * -+ * Be sure that DZPA (bit 7 in Flow Control Register, GMAC Register 6), -+ * is set to 0. This allows pause frames with a quanta of 0 to be sent -+ * as an XOFF message to the link peer. -+ */ -+ -+#define RFA_FULL_MINUS_1K 0x00000000 -+#define RFA_FULL_MINUS_2K 0x00000200 -+#define RFA_FULL_MINUS_3K 0x00000400 -+#define RFA_FULL_MINUS_4K 0x00000600 -+#define RFA_FULL_MINUS_5K 0x00800000 -+#define RFA_FULL_MINUS_6K 0x00800200 -+#define RFA_FULL_MINUS_7K 0x00800400 -+ -+#define RFD_FULL_MINUS_1K 0x00000000 -+#define RFD_FULL_MINUS_2K 0x00000800 -+#define RFD_FULL_MINUS_3K 0x00001000 -+#define RFD_FULL_MINUS_4K 0x00001800 -+#define RFD_FULL_MINUS_5K 0x00400000 -+#define RFD_FULL_MINUS_6K 0x00400800 -+#define RFD_FULL_MINUS_7K 0x00401000 -+ - enum rtc_control { - DMA_CONTROL_RTC_64 = 0x00000000, - DMA_CONTROL_RTC_32 = 0x00000008, ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c -@@ -201,7 +201,10 @@ static void dwmac1000_flow_ctrl(struct m - unsigned int fc, unsigned int pause_time) - { - void __iomem *ioaddr = hw->pcsr; -- unsigned int flow = 0; -+ /* Set flow such that DZPQ in Mac Register 6 is 0, -+ * and unicast pause detect is enabled. -+ */ -+ unsigned int flow = GMAC_FLOW_CTRL_UP; - - pr_debug("GMAC Flow-Control:\n"); - if (fc & FLOW_RX) { ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c -@@ -70,10 +70,6 @@ static int dwmac1000_dma_init(void __iom - if (mb) - value |= DMA_BUS_MODE_MB; - --#ifdef CONFIG_STMMAC_DA -- value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */ --#endif -- - if (atds) - value |= DMA_BUS_MODE_ATDS; - -@@ -110,8 +106,29 @@ static int dwmac1000_dma_init(void __iom - return 0; - } - -+static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz) -+{ -+ csr6 &= ~DMA_CONTROL_RFA_MASK; -+ csr6 &= ~DMA_CONTROL_RFD_MASK; -+ -+ /* Leave flow control disabled if receive fifo size is less than -+ * 4K or 0. Otherwise, send XOFF when fifo is 1K less than full, -+ * and send XON when 2K less than full. -+ */ -+ if (rxfifosz < 4096) { -+ csr6 &= ~DMA_CONTROL_EFC; -+ pr_debug("GMAC: disabling flow control, rxfifo too small(%d)\n", -+ rxfifosz); -+ } else { -+ csr6 |= DMA_CONTROL_EFC; -+ csr6 |= RFA_FULL_MINUS_1K; -+ csr6 |= RFD_FULL_MINUS_2K; -+ } -+ return csr6; -+} -+ - static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode, -- int rxmode) -+ int rxmode, int rxfifosz) - { - u32 csr6 = readl(ioaddr + DMA_CONTROL); - -@@ -157,6 +174,9 @@ static void dwmac1000_dma_operation_mode - csr6 |= DMA_CONTROL_RTC_128; - } - -+ /* Configure flow control based on rx fifo size */ -+ csr6 = dwmac1000_configure_fc(csr6, rxfifosz); -+ - writel(csr6, ioaddr + DMA_CONTROL); - } - ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c -@@ -72,7 +72,7 @@ static int dwmac100_dma_init(void __iome - * control register. - */ - static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode, -- int rxmode) -+ int rxmode, int rxfifosz) - { - u32 csr6 = readl(ioaddr + DMA_CONTROL); - ---- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c -+++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c -@@ -73,7 +73,7 @@ - #define MMC_RX_OCTETCOUNT_G 0x00000188 - #define MMC_RX_BROADCASTFRAME_G 0x0000018c - #define MMC_RX_MULTICASTFRAME_G 0x00000190 --#define MMC_RX_CRC_ERRROR 0x00000194 -+#define MMC_RX_CRC_ERROR 0x00000194 - #define MMC_RX_ALIGN_ERROR 0x00000198 - #define MMC_RX_RUN_ERROR 0x0000019C - #define MMC_RX_JABBER_ERROR 0x000001A0 -@@ -196,7 +196,7 @@ void dwmac_mmc_read(void __iomem *ioaddr - mmc->mmc_rx_octetcount_g += readl(ioaddr + MMC_RX_OCTETCOUNT_G); - mmc->mmc_rx_broadcastframe_g += readl(ioaddr + MMC_RX_BROADCASTFRAME_G); - mmc->mmc_rx_multicastframe_g += readl(ioaddr + MMC_RX_MULTICASTFRAME_G); -- mmc->mmc_rx_crc_error += readl(ioaddr + MMC_RX_CRC_ERRROR); -+ mmc->mmc_rx_crc_error += readl(ioaddr + MMC_RX_CRC_ERROR); - mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR); - mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR); - mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR); ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h -@@ -34,6 +34,14 @@ - #include - #include - -+struct stmmac_resources { -+ void __iomem *addr; -+ const char *mac; -+ int wol_irq; -+ int lpi_irq; -+ int irq; -+}; -+ - struct stmmac_tx_info { - dma_addr_t buf; - bool map_as_page; -@@ -97,6 +105,7 @@ struct stmmac_priv { - int wolopts; - int wol_irq; - struct clk *stmmac_clk; -+ struct clk *pclk; - struct reset_control *stmmac_rst; - int clk_csr; - struct timer_list eee_ctrl_timer; -@@ -116,97 +125,28 @@ struct stmmac_priv { - int use_riwt; - int irq_wake; - spinlock_t ptp_lock; -+ -+#ifdef CONFIG_DEBUG_FS -+ struct dentry *dbgfs_dir; -+ struct dentry *dbgfs_rings_status; -+ struct dentry *dbgfs_dma_cap; -+#endif - }; - - int stmmac_mdio_unregister(struct net_device *ndev); - int stmmac_mdio_register(struct net_device *ndev); - int stmmac_mdio_reset(struct mii_bus *mii); - void stmmac_set_ethtool_ops(struct net_device *netdev); --extern const struct stmmac_desc_ops enh_desc_ops; --extern const struct stmmac_desc_ops ndesc_ops; --extern const struct stmmac_hwtimestamp stmmac_ptp; -+ - int stmmac_ptp_register(struct stmmac_priv *priv); - void stmmac_ptp_unregister(struct stmmac_priv *priv); - int stmmac_resume(struct net_device *ndev); - int stmmac_suspend(struct net_device *ndev); - int stmmac_dvr_remove(struct net_device *ndev); --struct stmmac_priv *stmmac_dvr_probe(struct device *device, -- struct plat_stmmacenet_data *plat_dat, -- void __iomem *addr); -+int stmmac_dvr_probe(struct device *device, -+ struct plat_stmmacenet_data *plat_dat, -+ struct stmmac_resources *res); - void stmmac_disable_eee_mode(struct stmmac_priv *priv); - bool stmmac_eee_init(struct stmmac_priv *priv); - --#ifdef CONFIG_STMMAC_PLATFORM --#ifdef CONFIG_DWMAC_MESON --extern const struct stmmac_of_data meson6_dwmac_data; --#endif --#ifdef CONFIG_DWMAC_SUNXI --extern const struct stmmac_of_data sun7i_gmac_data; --#endif --#ifdef CONFIG_DWMAC_STI --extern const struct stmmac_of_data stih4xx_dwmac_data; --extern const struct stmmac_of_data stid127_dwmac_data; --#endif --#ifdef CONFIG_DWMAC_SOCFPGA --extern const struct stmmac_of_data socfpga_gmac_data; --#endif --extern struct platform_driver stmmac_pltfr_driver; --static inline int stmmac_register_platform(void) --{ -- int err; -- -- err = platform_driver_register(&stmmac_pltfr_driver); -- if (err) -- pr_err("stmmac: failed to register the platform driver\n"); -- -- return err; --} -- --static inline void stmmac_unregister_platform(void) --{ -- platform_driver_unregister(&stmmac_pltfr_driver); --} --#else --static inline int stmmac_register_platform(void) --{ -- pr_debug("stmmac: do not register the platf driver\n"); -- -- return 0; --} -- --static inline void stmmac_unregister_platform(void) --{ --} --#endif /* CONFIG_STMMAC_PLATFORM */ -- --#ifdef CONFIG_STMMAC_PCI --extern struct pci_driver stmmac_pci_driver; --static inline int stmmac_register_pci(void) --{ -- int err; -- -- err = pci_register_driver(&stmmac_pci_driver); -- if (err) -- pr_err("stmmac: failed to register the PCI driver\n"); -- -- return err; --} -- --static inline void stmmac_unregister_pci(void) --{ -- pci_unregister_driver(&stmmac_pci_driver); --} --#else --static inline int stmmac_register_pci(void) --{ -- pr_debug("stmmac: do not register the PCI driver\n"); -- -- return 0; --} -- --static inline void stmmac_unregister_pci(void) --{ --} --#endif /* CONFIG_STMMAC_PCI */ -- - #endif /* __STMMAC_H__ */ ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c -@@ -696,7 +696,7 @@ static int stmmac_set_coalesce(struct ne - (ec->tx_max_coalesced_frames == 0)) - return -EINVAL; - -- if ((ec->tx_coalesce_usecs > STMMAC_COAL_TX_TIMER) || -+ if ((ec->tx_coalesce_usecs > STMMAC_MAX_COAL_TX_TICK) || - (ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES)) - return -EINVAL; - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -44,14 +44,15 @@ - #include - #include - #include --#ifdef CONFIG_STMMAC_DEBUG_FS -+#ifdef CONFIG_DEBUG_FS - #include - #include --#endif /* CONFIG_STMMAC_DEBUG_FS */ -+#endif /* CONFIG_DEBUG_FS */ - #include - #include "stmmac_ptp.h" - #include "stmmac.h" - #include -+#include - - #define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) - -@@ -116,17 +117,17 @@ MODULE_PARM_DESC(chain_mode, "To use cha - - static irqreturn_t stmmac_interrupt(int irq, void *dev_id); - --#ifdef CONFIG_STMMAC_DEBUG_FS -+#ifdef CONFIG_DEBUG_FS - static int stmmac_init_fs(struct net_device *dev); --static void stmmac_exit_fs(void); -+static void stmmac_exit_fs(struct net_device *dev); - #endif - - #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x)) - - /** - * stmmac_verify_args - verify the driver parameters. -- * Description: it verifies if some wrong parameter is passed to the driver. -- * Note that wrong parameters are replaced with the default values. -+ * Description: it checks the driver parameters and set a default in case of -+ * errors. - */ - static void stmmac_verify_args(void) - { -@@ -191,14 +192,8 @@ static void stmmac_clk_csr_set(struct st - - static void print_pkt(unsigned char *buf, int len) - { -- int j; -- pr_debug("len = %d byte, buf addr: 0x%p", len, buf); -- for (j = 0; j < len; j++) { -- if ((j % 16) == 0) -- pr_debug("\n %03x:", j); -- pr_debug(" %02x", buf[j]); -- } -- pr_debug("\n"); -+ pr_debug("len = %d byte, buf addr: 0x%p\n", len, buf); -+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); - } - - /* minimum number of free TX descriptors required to wake up TX process */ -@@ -210,7 +205,7 @@ static inline u32 stmmac_tx_avail(struct - } - - /** -- * stmmac_hw_fix_mac_speed: callback for speed selection -+ * stmmac_hw_fix_mac_speed - callback for speed selection - * @priv: driver private structure - * Description: on some platforms (e.g. ST), some HW system configuraton - * registers have to be set according to the link speed negotiated. -@@ -224,9 +219,10 @@ static inline void stmmac_hw_fix_mac_spe - } - - /** -- * stmmac_enable_eee_mode: Check and enter in LPI mode -+ * stmmac_enable_eee_mode - check and enter in LPI mode - * @priv: driver private structure -- * Description: this function is to verify and enter in LPI mode for EEE. -+ * Description: this function is to verify and enter in LPI mode in case of -+ * EEE. - */ - static void stmmac_enable_eee_mode(struct stmmac_priv *priv) - { -@@ -237,7 +233,7 @@ static void stmmac_enable_eee_mode(struc - } - - /** -- * stmmac_disable_eee_mode: disable/exit from EEE -+ * stmmac_disable_eee_mode - disable and exit from LPI mode - * @priv: driver private structure - * Description: this function is to exit and disable EEE in case of - * LPI state is true. This is called by the xmit. -@@ -250,7 +246,7 @@ void stmmac_disable_eee_mode(struct stmm - } - - /** -- * stmmac_eee_ctrl_timer: EEE TX SW timer. -+ * stmmac_eee_ctrl_timer - EEE TX SW timer. - * @arg : data hook - * Description: - * if there is no data transfer and if we are not in LPI state, -@@ -265,13 +261,12 @@ static void stmmac_eee_ctrl_timer(unsign - } - - /** -- * stmmac_eee_init: init EEE -+ * stmmac_eee_init - init EEE - * @priv: driver private structure - * Description: -- * If the EEE support has been enabled while configuring the driver, -- * if the GMAC actually supports the EEE (from the HW cap reg) and the -- * phy can also manage EEE, so enable the LPI state and start the timer -- * to verify if the tx path can enter in LPI state. -+ * if the GMAC supports the EEE (from the HW cap reg) and the phy device -+ * can also manage EEE, this function enable the LPI state and start related -+ * timer. - */ - bool stmmac_eee_init(struct stmmac_priv *priv) - { -@@ -316,11 +311,11 @@ bool stmmac_eee_init(struct stmmac_priv - spin_lock_irqsave(&priv->lock, flags); - if (!priv->eee_active) { - priv->eee_active = 1; -- init_timer(&priv->eee_ctrl_timer); -- priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer; -- priv->eee_ctrl_timer.data = (unsigned long)priv; -- priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer); -- add_timer(&priv->eee_ctrl_timer); -+ setup_timer(&priv->eee_ctrl_timer, -+ stmmac_eee_ctrl_timer, -+ (unsigned long)priv); -+ mod_timer(&priv->eee_ctrl_timer, -+ STMMAC_LPI_T(eee_timer)); - - priv->hw->mac->set_eee_timer(priv->hw, - STMMAC_DEFAULT_LIT_LS, -@@ -338,7 +333,7 @@ out: - return ret; - } - --/* stmmac_get_tx_hwtstamp: get HW TX timestamps -+/* stmmac_get_tx_hwtstamp - get HW TX timestamps - * @priv: driver private structure - * @entry : descriptor index to be used. - * @skb : the socket buffer -@@ -380,7 +375,7 @@ static void stmmac_get_tx_hwtstamp(struc - return; - } - --/* stmmac_get_rx_hwtstamp: get HW RX timestamps -+/* stmmac_get_rx_hwtstamp - get HW RX timestamps - * @priv: driver private structure - * @entry : descriptor index to be used. - * @skb : the socket buffer -@@ -615,7 +610,7 @@ static int stmmac_hwtstamp_ioctl(struct - * where, freq_div_ratio = clk_ptp_ref_i/50MHz - * hence, addend = ((2^32) * 50MHz)/clk_ptp_ref_i; - * NOTE: clk_ptp_ref_i should be >= 50MHz to -- * achive 20ns accuracy. -+ * achieve 20ns accuracy. - * - * 2^x * y == (y << x), hence - * 2^32 * 50000000 ==> (50000000 << 32) -@@ -636,11 +631,11 @@ static int stmmac_hwtstamp_ioctl(struct - } - - /** -- * stmmac_init_ptp: init PTP -+ * stmmac_init_ptp - init PTP - * @priv: driver private structure -- * Description: this is to verify if the HW supports the PTPv1 or v2. -+ * Description: this is to verify if the HW supports the PTPv1 or PTPv2. - * This is done by looking at the HW cap. register. -- * Also it registers the ptp driver. -+ * This function also registers the ptp driver. - */ - static int stmmac_init_ptp(struct stmmac_priv *priv) - { -@@ -682,9 +677,13 @@ static void stmmac_release_ptp(struct st - } - - /** -- * stmmac_adjust_link -+ * stmmac_adjust_link - adjusts the link parameters - * @dev: net device structure -- * Description: it adjusts the link parameters. -+ * Description: this is the helper called by the physical abstraction layer -+ * drivers to communicate the phy link status. According the speed and duplex -+ * this driver can invoke registered glue-logic as well. -+ * It also invoke the eee initialization because it could happen when switch -+ * on different networks (that are eee capable). - */ - static void stmmac_adjust_link(struct net_device *dev) - { -@@ -774,7 +773,7 @@ static void stmmac_adjust_link(struct ne - } - - /** -- * stmmac_check_pcs_mode: verify if RGMII/SGMII is supported -+ * stmmac_check_pcs_mode - verify if RGMII/SGMII is supported - * @priv: driver private structure - * Description: this is to verify if the HW supports the PCS. - * Physical Coding Sublayer (PCS) interface that can be used when the MAC is -@@ -818,21 +817,31 @@ static int stmmac_init_phy(struct net_de - priv->speed = 0; - priv->oldduplex = -1; - -- if (priv->plat->phy_bus_name) -- snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", -- priv->plat->phy_bus_name, priv->plat->bus_id); -- else -- snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", -- priv->plat->bus_id); -+ if (priv->plat->phy_node) { -+ phydev = of_phy_connect(dev, priv->plat->phy_node, -+ &stmmac_adjust_link, 0, interface); -+ } else { -+ if (priv->plat->phy_bus_name) -+ snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", -+ priv->plat->phy_bus_name, priv->plat->bus_id); -+ else -+ snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", -+ priv->plat->bus_id); - -- snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, -- priv->plat->phy_addr); -- pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt); -+ snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, -+ priv->plat->phy_addr); -+ pr_debug("stmmac_init_phy: trying to attach to %s\n", -+ phy_id_fmt); - -- phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface); -+ phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, -+ interface); -+ } - -- if (IS_ERR(phydev)) { -+ if (IS_ERR_OR_NULL(phydev)) { - pr_err("%s: Could not attach to PHY\n", dev->name); -+ if (!phydev) -+ return -ENODEV; -+ - return PTR_ERR(phydev); - } - -@@ -850,7 +859,7 @@ static int stmmac_init_phy(struct net_de - * device as well. - * Note: phydev->phy_id is the result of reading the UID PHY registers. - */ -- if (phydev->phy_id == 0) { -+ if (!priv->plat->phy_node && phydev->phy_id == 0) { - phy_disconnect(phydev); - return -ENODEV; - } -@@ -863,7 +872,7 @@ static int stmmac_init_phy(struct net_de - } - - /** -- * stmmac_display_ring: display ring -+ * stmmac_display_ring - display ring - * @head: pointer to the head of the ring passed. - * @size: size of the ring. - * @extend_desc: to verify if extended descriptors are used. -@@ -931,7 +940,7 @@ static int stmmac_set_bfsize(int mtu, in - } - - /** -- * stmmac_clear_descriptors: clear descriptors -+ * stmmac_clear_descriptors - clear descriptors - * @priv: driver private structure - * Description: this function is called to clear the tx and rx descriptors - * in case of both basic and extended descriptors are used. -@@ -963,18 +972,25 @@ static void stmmac_clear_descriptors(str - (i == txsize - 1)); - } - -+/** -+ * stmmac_init_rx_buffers - init the RX descriptor buffer. -+ * @priv: driver private structure -+ * @p: descriptor pointer -+ * @i: descriptor index -+ * @flags: gfp flag. -+ * Description: this function is called to allocate a receive buffer, perform -+ * the DMA mapping and init the descriptor. -+ */ - static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, - int i, gfp_t flags) - { - struct sk_buff *skb; - -- skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN, -- flags); -+ skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags); - if (!skb) { - pr_err("%s: Rx init fails; skb is NULL\n", __func__); - return -ENOMEM; - } -- skb_reserve(skb, NET_IP_ALIGN); - priv->rx_skbuff[i] = skb; - priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, - priv->dma_buf_sz, -@@ -1007,7 +1023,8 @@ static void stmmac_free_rx_buffers(struc - /** - * init_dma_desc_rings - init the RX/TX descriptor rings - * @dev: net device structure -- * Description: this function initializes the DMA RX/TX descriptors -+ * @flags: gfp flag. -+ * Description: this function initializes the DMA RX/TX descriptors - * and allocates the socket buffers. It suppors the chained and ring - * modes. - */ -@@ -1089,6 +1106,7 @@ static int init_dma_desc_rings(struct ne - - priv->dirty_tx = 0; - priv->cur_tx = 0; -+ netdev_reset_queue(priv->dev); - - stmmac_clear_descriptors(priv); - -@@ -1144,6 +1162,14 @@ static void dma_free_tx_skbufs(struct st - } - } - -+/** -+ * alloc_dma_desc_resources - alloc TX/RX resources. -+ * @priv: private structure -+ * Description: according to which descriptor can be used (extend or basic) -+ * this function allocates the resources for TX and RX paths. In case of -+ * reception, for example, it pre-allocated the RX socket buffer in order to -+ * allow zero-copy mechanism. -+ */ - static int alloc_dma_desc_resources(struct stmmac_priv *priv) - { - unsigned int txsize = priv->dma_tx_size; -@@ -1255,13 +1281,15 @@ static void free_dma_desc_resources(stru - /** - * stmmac_dma_operation_mode - HW DMA operation mode - * @priv: driver private structure -- * Description: it sets the DMA operation mode: tx/rx DMA thresholds -- * or Store-And-Forward capability. -+ * Description: it is used for configuring the DMA operation mode register in -+ * order to program the tx/rx DMA thresholds or Store-And-Forward mode. - */ - static void stmmac_dma_operation_mode(struct stmmac_priv *priv) - { -+ int rxfifosz = priv->plat->rx_fifo_size; -+ - if (priv->plat->force_thresh_dma_mode) -- priv->hw->dma->dma_mode(priv->ioaddr, tc, tc); -+ priv->hw->dma->dma_mode(priv->ioaddr, tc, tc, rxfifosz); - else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) { - /* - * In case of GMAC, SF mode can be enabled -@@ -1270,20 +1298,23 @@ static void stmmac_dma_operation_mode(st - * 2) There is no bugged Jumbo frame support - * that needs to not insert csum in the TDES. - */ -- priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE); -- tc = SF_DMA_MODE; -+ priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE, -+ rxfifosz); -+ priv->xstats.threshold = SF_DMA_MODE; - } else -- priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); -+ priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE, -+ rxfifosz); - } - - /** -- * stmmac_tx_clean: -+ * stmmac_tx_clean - to manage the transmission completion - * @priv: driver private structure -- * Description: it reclaims resources after transmission completes. -+ * Description: it reclaims the transmit resources after transmission completes. - */ - static void stmmac_tx_clean(struct stmmac_priv *priv) - { - unsigned int txsize = priv->dma_tx_size; -+ unsigned int bytes_compl = 0, pkts_compl = 0; - - spin_lock(&priv->tx_lock); - -@@ -1340,6 +1371,8 @@ static void stmmac_tx_clean(struct stmma - priv->hw->mode->clean_desc3(priv, p); - - if (likely(skb != NULL)) { -+ pkts_compl++; -+ bytes_compl += skb->len; - dev_consume_skb_any(skb); - priv->tx_skbuff[entry] = NULL; - } -@@ -1348,6 +1381,9 @@ static void stmmac_tx_clean(struct stmma - - priv->dirty_tx++; - } -+ -+ netdev_completed_queue(priv->dev, pkts_compl, bytes_compl); -+ - if (unlikely(netif_queue_stopped(priv->dev) && - stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) { - netif_tx_lock(priv->dev); -@@ -1378,10 +1414,10 @@ static inline void stmmac_disable_dma_ir - } - - /** -- * stmmac_tx_err: irq tx error mng function -+ * stmmac_tx_err - to manage the tx error - * @priv: driver private structure - * Description: it cleans the descriptors and restarts the transmission -- * in case of errors. -+ * in case of transmission errors. - */ - static void stmmac_tx_err(struct stmmac_priv *priv) - { -@@ -1402,6 +1438,7 @@ static void stmmac_tx_err(struct stmmac_ - (i == txsize - 1)); - priv->dirty_tx = 0; - priv->cur_tx = 0; -+ netdev_reset_queue(priv->dev); - priv->hw->dma->start_tx(priv->ioaddr); - - priv->dev->stats.tx_errors++; -@@ -1409,16 +1446,16 @@ static void stmmac_tx_err(struct stmmac_ - } - - /** -- * stmmac_dma_interrupt: DMA ISR -+ * stmmac_dma_interrupt - DMA ISR - * @priv: driver private structure - * Description: this is the DMA ISR. It is called by the main ISR. -- * It calls the dwmac dma routine to understand which type of interrupt -- * happened. In case of there is a Normal interrupt and either TX or RX -- * interrupt happened so the NAPI is scheduled. -+ * It calls the dwmac dma routine and schedule poll method in case of some -+ * work can be done. - */ - static void stmmac_dma_interrupt(struct stmmac_priv *priv) - { - int status; -+ int rxfifosz = priv->plat->rx_fifo_size; - - status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats); - if (likely((status & handle_rx)) || (status & handle_tx)) { -@@ -1429,9 +1466,15 @@ static void stmmac_dma_interrupt(struct - } - if (unlikely(status & tx_hard_error_bump_tc)) { - /* Try to bump up the dma threshold on this failure */ -- if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { -+ if (unlikely(priv->xstats.threshold != SF_DMA_MODE) && -+ (tc <= 256)) { - tc += 64; -- priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); -+ if (priv->plat->force_thresh_dma_mode) -+ priv->hw->dma->dma_mode(priv->ioaddr, tc, tc, -+ rxfifosz); -+ else -+ priv->hw->dma->dma_mode(priv->ioaddr, tc, -+ SF_DMA_MODE, rxfifosz); - priv->xstats.threshold = tc; - } - } else if (unlikely(status == tx_hard_error)) -@@ -1457,6 +1500,12 @@ static void stmmac_mmc_setup(struct stmm - pr_info(" No MAC Management Counters available\n"); - } - -+/** -+ * stmmac_get_synopsys_id - return the SYINID. -+ * @priv: driver private structure -+ * Description: this simple function is to decode and return the SYINID -+ * starting from the HW core register. -+ */ - static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv) - { - u32 hwid = priv->hw->synopsys_uid; -@@ -1475,11 +1524,11 @@ static u32 stmmac_get_synopsys_id(struct - } - - /** -- * stmmac_selec_desc_mode: to select among: normal/alternate/extend descriptors -+ * stmmac_selec_desc_mode - to select among: normal/alternate/extend descriptors - * @priv: driver private structure - * Description: select the Enhanced/Alternate or Normal descriptors. -- * In case of Enhanced/Alternate, it looks at the extended descriptors are -- * supported by the HW cap. register. -+ * In case of Enhanced/Alternate, it checks if the extended descriptors are -+ * supported by the HW capability register. - */ - static void stmmac_selec_desc_mode(struct stmmac_priv *priv) - { -@@ -1501,7 +1550,7 @@ static void stmmac_selec_desc_mode(struc - } - - /** -- * stmmac_get_hw_features: get MAC capabilities from the HW cap. register. -+ * stmmac_get_hw_features - get MAC capabilities from the HW cap. register. - * @priv: driver private structure - * Description: - * new GMAC chip generations have a new register to indicate the -@@ -1559,7 +1608,7 @@ static int stmmac_get_hw_features(struct - } - - /** -- * stmmac_check_ether_addr: check if the MAC addr is valid -+ * stmmac_check_ether_addr - check if the MAC addr is valid - * @priv: driver private structure - * Description: - * it is to verify if the MAC address is valid, in case of failures it -@@ -1578,7 +1627,7 @@ static void stmmac_check_ether_addr(stru - } - - /** -- * stmmac_init_dma_engine: DMA init. -+ * stmmac_init_dma_engine - DMA init. - * @priv: driver private structure - * Description: - * It inits the DMA invoking the specific MAC/GMAC callback. -@@ -1607,7 +1656,7 @@ static int stmmac_init_dma_engine(struct - } - - /** -- * stmmac_tx_timer: mitigation sw timer for tx. -+ * stmmac_tx_timer - mitigation sw timer for tx. - * @data: data pointer - * Description: - * This is the timer handler to directly invoke the stmmac_tx_clean. -@@ -1620,7 +1669,7 @@ static void stmmac_tx_timer(unsigned lon - } - - /** -- * stmmac_init_tx_coalesce: init tx mitigation options. -+ * stmmac_init_tx_coalesce - init tx mitigation options. - * @priv: driver private structure - * Description: - * This inits the transmit coalesce parameters: i.e. timer rate, -@@ -1639,15 +1688,18 @@ static void stmmac_init_tx_coalesce(stru - } - - /** -- * stmmac_hw_setup: setup mac in a usable state. -+ * stmmac_hw_setup - setup mac in a usable state. - * @dev : pointer to the device structure. - * Description: -- * This function sets up the ip in a usable state. -+ * this is the main function to setup the HW in a usable state because the -+ * dma engine is reset, the core registers are configured (e.g. AXI, -+ * Checksum features, timers). The DMA is ready to start receiving and -+ * transmitting. - * Return value: - * 0 on success and an appropriate (-)ve integer as defined in errno.h - * file on failure. - */ --static int stmmac_hw_setup(struct net_device *dev) -+static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) - { - struct stmmac_priv *priv = netdev_priv(dev); - int ret; -@@ -1684,11 +1736,13 @@ static int stmmac_hw_setup(struct net_de - - stmmac_mmc_setup(priv); - -- ret = stmmac_init_ptp(priv); -- if (ret && ret != -EOPNOTSUPP) -- pr_warn("%s: failed PTP initialisation\n", __func__); -+ if (init_ptp) { -+ ret = stmmac_init_ptp(priv); -+ if (ret && ret != -EOPNOTSUPP) -+ pr_warn("%s: failed PTP initialisation\n", __func__); -+ } - --#ifdef CONFIG_STMMAC_DEBUG_FS -+#ifdef CONFIG_DEBUG_FS - ret = stmmac_init_fs(dev); - if (ret < 0) - pr_warn("%s: failed debugFS registration\n", __func__); -@@ -1763,7 +1817,7 @@ static int stmmac_open(struct net_device - goto init_error; - } - -- ret = stmmac_hw_setup(dev); -+ ret = stmmac_hw_setup(dev, true); - if (ret < 0) { - pr_err("%s: Hw setup failed\n", __func__); - goto init_error; -@@ -1870,8 +1924,8 @@ static int stmmac_release(struct net_dev - - netif_carrier_off(dev); - --#ifdef CONFIG_STMMAC_DEBUG_FS -- stmmac_exit_fs(); -+#ifdef CONFIG_DEBUG_FS -+ stmmac_exit_fs(dev); - #endif - - stmmac_release_ptp(priv); -@@ -1880,7 +1934,7 @@ static int stmmac_release(struct net_dev - } - - /** -- * stmmac_xmit: Tx entry point of the driver -+ * stmmac_xmit - Tx entry point of the driver - * @skb : the socket buffer - * @dev : device pointer - * Description : this is the tx entry point of the driver. -@@ -2024,6 +2078,7 @@ static netdev_tx_t stmmac_xmit(struct sk - if (!priv->hwts_tx_en) - skb_tx_timestamp(skb); - -+ netdev_sent_queue(dev, skb->len); - priv->hw->dma->enable_dma_transmission(priv->ioaddr); - - spin_unlock(&priv->tx_lock); -@@ -2055,7 +2110,7 @@ static void stmmac_rx_vlan(struct net_de - - - /** -- * stmmac_rx_refill: refill used skb preallocated buffers -+ * stmmac_rx_refill - refill used skb preallocated buffers - * @priv: driver private structure - * Description : this is to reallocate the skb for the reception process - * that is based on zero-copy. -@@ -2106,7 +2161,7 @@ static inline void stmmac_rx_refill(stru - } - - /** -- * stmmac_rx_refill: refill used skb preallocated buffers -+ * stmmac_rx - manage the receive process - * @priv: driver private structure - * @limit: napi bugget. - * Description : this the function called by the napi poll method. -@@ -2375,8 +2430,11 @@ static int stmmac_set_features(struct ne - * @irq: interrupt number. - * @dev_id: to pass the net device pointer. - * Description: this is the main driver interrupt service routine. -- * It calls the DMA ISR and also the core ISR to manage PMT, MMC, LPI -- * interrupts. -+ * It can call: -+ * o DMA service routine (to manage incoming frame reception and transmission -+ * status) -+ * o Core interrupts to manage: remote wake-up, management counter, LPI -+ * interrupts. - */ - static irqreturn_t stmmac_interrupt(int irq, void *dev_id) - { -@@ -2457,10 +2515,8 @@ static int stmmac_ioctl(struct net_devic - return ret; - } - --#ifdef CONFIG_STMMAC_DEBUG_FS -+#ifdef CONFIG_DEBUG_FS - static struct dentry *stmmac_fs_dir; --static struct dentry *stmmac_rings_status; --static struct dentry *stmmac_dma_cap; - - static void sysfs_display_ring(void *head, int size, int extend_desc, - struct seq_file *seq) -@@ -2599,36 +2655,39 @@ static const struct file_operations stmm - - static int stmmac_init_fs(struct net_device *dev) - { -- /* Create debugfs entries */ -- stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL); -+ struct stmmac_priv *priv = netdev_priv(dev); - -- if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) { -- pr_err("ERROR %s, debugfs create directory failed\n", -- STMMAC_RESOURCE_NAME); -+ /* Create per netdev entries */ -+ priv->dbgfs_dir = debugfs_create_dir(dev->name, stmmac_fs_dir); -+ -+ if (!priv->dbgfs_dir || IS_ERR(priv->dbgfs_dir)) { -+ pr_err("ERROR %s/%s, debugfs create directory failed\n", -+ STMMAC_RESOURCE_NAME, dev->name); - - return -ENOMEM; - } - - /* Entry to report DMA RX/TX rings */ -- stmmac_rings_status = debugfs_create_file("descriptors_status", -- S_IRUGO, stmmac_fs_dir, dev, -- &stmmac_rings_status_fops); -+ priv->dbgfs_rings_status = -+ debugfs_create_file("descriptors_status", S_IRUGO, -+ priv->dbgfs_dir, dev, -+ &stmmac_rings_status_fops); - -- if (!stmmac_rings_status || IS_ERR(stmmac_rings_status)) { -+ if (!priv->dbgfs_rings_status || IS_ERR(priv->dbgfs_rings_status)) { - pr_info("ERROR creating stmmac ring debugfs file\n"); -- debugfs_remove(stmmac_fs_dir); -+ debugfs_remove_recursive(priv->dbgfs_dir); - - return -ENOMEM; - } - - /* Entry to report the DMA HW features */ -- stmmac_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, stmmac_fs_dir, -- dev, &stmmac_dma_cap_fops); -+ priv->dbgfs_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, -+ priv->dbgfs_dir, -+ dev, &stmmac_dma_cap_fops); - -- if (!stmmac_dma_cap || IS_ERR(stmmac_dma_cap)) { -+ if (!priv->dbgfs_dma_cap || IS_ERR(priv->dbgfs_dma_cap)) { - pr_info("ERROR creating stmmac MMC debugfs file\n"); -- debugfs_remove(stmmac_rings_status); -- debugfs_remove(stmmac_fs_dir); -+ debugfs_remove_recursive(priv->dbgfs_dir); - - return -ENOMEM; - } -@@ -2636,13 +2695,13 @@ static int stmmac_init_fs(struct net_dev - return 0; - } - --static void stmmac_exit_fs(void) -+static void stmmac_exit_fs(struct net_device *dev) - { -- debugfs_remove(stmmac_rings_status); -- debugfs_remove(stmmac_dma_cap); -- debugfs_remove(stmmac_fs_dir); -+ struct stmmac_priv *priv = netdev_priv(dev); -+ -+ debugfs_remove_recursive(priv->dbgfs_dir); - } --#endif /* CONFIG_STMMAC_DEBUG_FS */ -+#endif /* CONFIG_DEBUG_FS */ - - static const struct net_device_ops stmmac_netdev_ops = { - .ndo_open = stmmac_open, -@@ -2663,11 +2722,10 @@ static const struct net_device_ops stmma - /** - * stmmac_hw_init - Init the MAC device - * @priv: driver private structure -- * Description: this function detects which MAC device -- * (GMAC/MAC10-100) has to attached, checks the HW capability -- * (if supported) and sets the driver's features (for example -- * to use the ring or chaine mode or support the normal/enh -- * descriptor structure). -+ * Description: this function is to configure the MAC device according to -+ * some platform parameters or the HW capability register. It prepares the -+ * driver to use either ring or chain modes and to setup either enhanced or -+ * normal descriptors. - */ - static int stmmac_hw_init(struct stmmac_priv *priv) - { -@@ -2714,7 +2772,11 @@ static int stmmac_hw_init(struct stmmac_ - priv->plat->enh_desc = priv->dma_cap.enh_desc; - priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up; - -- priv->plat->tx_coe = priv->dma_cap.tx_coe; -+ /* TXCOE doesn't work in thresh DMA mode */ -+ if (priv->plat->force_thresh_dma_mode) -+ priv->plat->tx_coe = 0; -+ else -+ priv->plat->tx_coe = priv->dma_cap.tx_coe; - - if (priv->dma_cap.rx_coe_type2) - priv->plat->rx_coe = STMMAC_RX_COE_TYPE2; -@@ -2747,13 +2809,15 @@ static int stmmac_hw_init(struct stmmac_ - * stmmac_dvr_probe - * @device: device pointer - * @plat_dat: platform data pointer -- * @addr: iobase memory address -+ * @res: stmmac resource pointer - * Description: this is the main probe function used to - * call the alloc_etherdev, allocate the priv structure. -+ * Return: -+ * returns 0 on success, otherwise errno. - */ --struct stmmac_priv *stmmac_dvr_probe(struct device *device, -- struct plat_stmmacenet_data *plat_dat, -- void __iomem *addr) -+int stmmac_dvr_probe(struct device *device, -+ struct plat_stmmacenet_data *plat_dat, -+ struct stmmac_resources *res) - { - int ret = 0; - struct net_device *ndev = NULL; -@@ -2761,7 +2825,7 @@ struct stmmac_priv *stmmac_dvr_probe(str - - ndev = alloc_etherdev(sizeof(struct stmmac_priv)); - if (!ndev) -- return NULL; -+ return -ENOMEM; - - SET_NETDEV_DEV(ndev, device); - -@@ -2772,8 +2836,17 @@ struct stmmac_priv *stmmac_dvr_probe(str - stmmac_set_ethtool_ops(ndev); - priv->pause = pause; - priv->plat = plat_dat; -- priv->ioaddr = addr; -- priv->dev->base_addr = (unsigned long)addr; -+ priv->ioaddr = res->addr; -+ priv->dev->base_addr = (unsigned long)res->addr; -+ -+ priv->dev->irq = res->irq; -+ priv->wol_irq = res->wol_irq; -+ priv->lpi_irq = res->lpi_irq; -+ -+ if (res->mac) -+ memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN); -+ -+ dev_set_drvdata(device, priv->dev); - - /* Verify driver arguments */ - stmmac_verify_args(); -@@ -2800,6 +2873,16 @@ struct stmmac_priv *stmmac_dvr_probe(str - } - clk_prepare_enable(priv->stmmac_clk); - -+ priv->pclk = devm_clk_get(priv->device, "pclk"); -+ if (IS_ERR(priv->pclk)) { -+ if (PTR_ERR(priv->pclk) == -EPROBE_DEFER) { -+ ret = -EPROBE_DEFER; -+ goto error_pclk_get; -+ } -+ priv->pclk = NULL; -+ } -+ clk_prepare_enable(priv->pclk); -+ - priv->stmmac_rst = devm_reset_control_get(priv->device, - STMMAC_RESOURCE_NAME); - if (IS_ERR(priv->stmmac_rst)) { -@@ -2878,19 +2961,22 @@ struct stmmac_priv *stmmac_dvr_probe(str - } - } - -- return priv; -+ return 0; - - error_mdio_register: - unregister_netdev(ndev); - error_netdev_register: - netif_napi_del(&priv->napi); - error_hw_init: -+ clk_disable_unprepare(priv->pclk); -+error_pclk_get: - clk_disable_unprepare(priv->stmmac_clk); - error_clk_get: - free_netdev(ndev); - -- return ERR_PTR(ret); -+ return ret; - } -+EXPORT_SYMBOL_GPL(stmmac_dvr_probe); - - /** - * stmmac_dvr_remove -@@ -2908,20 +2994,28 @@ int stmmac_dvr_remove(struct net_device - priv->hw->dma->stop_tx(priv->ioaddr); - - stmmac_set_mac(priv->ioaddr, false); -- if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && -- priv->pcs != STMMAC_PCS_RTBI) -- stmmac_mdio_unregister(ndev); - netif_carrier_off(ndev); - unregister_netdev(ndev); - if (priv->stmmac_rst) - reset_control_assert(priv->stmmac_rst); -+ clk_disable_unprepare(priv->pclk); - clk_disable_unprepare(priv->stmmac_clk); -+ if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && -+ priv->pcs != STMMAC_PCS_RTBI) -+ stmmac_mdio_unregister(ndev); - free_netdev(ndev); - - return 0; - } -+EXPORT_SYMBOL_GPL(stmmac_dvr_remove); - --#ifdef CONFIG_PM -+/** -+ * stmmac_suspend - suspend callback -+ * @ndev: net device pointer -+ * Description: this is the function to suspend the device and it is called -+ * by the platform driver to stop the network queue, release the resources, -+ * program the PMT register (for WoL), clean and release driver resources. -+ */ - int stmmac_suspend(struct net_device *ndev) - { - struct stmmac_priv *priv = netdev_priv(ndev); -@@ -2954,6 +3048,7 @@ int stmmac_suspend(struct net_device *nd - stmmac_set_mac(priv->ioaddr, false); - pinctrl_pm_select_sleep_state(priv->device); - /* Disable clock in case of PWM is off */ -+ clk_disable(priv->pclk); - clk_disable(priv->stmmac_clk); - } - spin_unlock_irqrestore(&priv->lock, flags); -@@ -2963,7 +3058,14 @@ int stmmac_suspend(struct net_device *nd - priv->oldduplex = -1; - return 0; - } -+EXPORT_SYMBOL_GPL(stmmac_suspend); - -+/** -+ * stmmac_resume - resume callback -+ * @ndev: net device pointer -+ * Description: when resume this function is invoked to setup the DMA and CORE -+ * in a usable state. -+ */ - int stmmac_resume(struct net_device *ndev) - { - struct stmmac_priv *priv = netdev_priv(ndev); -@@ -2987,6 +3089,7 @@ int stmmac_resume(struct net_device *nde - pinctrl_pm_select_default_state(priv->device); - /* enable the clk prevously disabled */ - clk_enable(priv->stmmac_clk); -+ clk_enable(priv->pclk); - /* reset the phy so that it's ready */ - if (priv->mii) - stmmac_mdio_reset(priv->mii); -@@ -2995,7 +3098,7 @@ int stmmac_resume(struct net_device *nde - netif_device_attach(ndev); - - init_dma_desc_rings(ndev, GFP_ATOMIC); -- stmmac_hw_setup(ndev); -+ stmmac_hw_setup(ndev, false); - stmmac_init_tx_coalesce(priv); - - napi_enable(&priv->napi); -@@ -3009,37 +3112,7 @@ int stmmac_resume(struct net_device *nde - - return 0; - } --#endif /* CONFIG_PM */ -- --/* Driver can be configured w/ and w/ both PCI and Platf drivers -- * depending on the configuration selected. -- */ --static int __init stmmac_init(void) --{ -- int ret; -- -- ret = stmmac_register_platform(); -- if (ret) -- goto err; -- ret = stmmac_register_pci(); -- if (ret) -- goto err_pci; -- return 0; --err_pci: -- stmmac_unregister_platform(); --err: -- pr_err("stmmac: driver registration failed\n"); -- return ret; --} -- --static void __exit stmmac_exit(void) --{ -- stmmac_unregister_platform(); -- stmmac_unregister_pci(); --} -- --module_init(stmmac_init); --module_exit(stmmac_exit); -+EXPORT_SYMBOL_GPL(stmmac_resume); - - #ifndef MODULE - static int __init stmmac_cmdline_opt(char *str) -@@ -3094,6 +3167,35 @@ err: - __setup("stmmaceth=", stmmac_cmdline_opt); - #endif /* MODULE */ - -+static int __init stmmac_init(void) -+{ -+#ifdef CONFIG_DEBUG_FS -+ /* Create debugfs main directory if it doesn't exist yet */ -+ if (!stmmac_fs_dir) { -+ stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL); -+ -+ if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) { -+ pr_err("ERROR %s, debugfs create directory failed\n", -+ STMMAC_RESOURCE_NAME); -+ -+ return -ENOMEM; -+ } -+ } -+#endif -+ -+ return 0; -+} -+ -+static void __exit stmmac_exit(void) -+{ -+#ifdef CONFIG_DEBUG_FS -+ debugfs_remove_recursive(stmmac_fs_dir); -+#endif -+} -+ -+module_init(stmmac_init) -+module_exit(stmmac_exit) -+ - MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet device driver"); - MODULE_AUTHOR("Giuseppe Cavallaro "); - MODULE_LICENSE("GPL"); ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c -@@ -161,11 +161,16 @@ int stmmac_mdio_reset(struct mii_bus *bu - - if (!gpio_request(reset_gpio, "mdio-reset")) { - gpio_direction_output(reset_gpio, active_low ? 1 : 0); -- udelay(data->delays[0]); -+ if (data->delays[0]) -+ msleep(DIV_ROUND_UP(data->delays[0], 1000)); -+ - gpio_set_value(reset_gpio, active_low ? 0 : 1); -- udelay(data->delays[1]); -+ if (data->delays[1]) -+ msleep(DIV_ROUND_UP(data->delays[1], 1000)); -+ - gpio_set_value(reset_gpio, active_low ? 1 : 0); -- udelay(data->delays[2]); -+ if (data->delays[2]) -+ msleep(DIV_ROUND_UP(data->delays[2], 1000)); - } - } - #endif ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c -@@ -24,38 +24,128 @@ - *******************************************************************************/ - - #include -+#include -+ - #include "stmmac.h" - --static struct plat_stmmacenet_data plat_dat; --static struct stmmac_mdio_bus_data mdio_data; --static struct stmmac_dma_cfg dma_cfg; -- --static void stmmac_default_data(void) --{ -- memset(&plat_dat, 0, sizeof(struct plat_stmmacenet_data)); -- -- plat_dat.bus_id = 1; -- plat_dat.phy_addr = 0; -- plat_dat.interface = PHY_INTERFACE_MODE_GMII; -- plat_dat.clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ -- plat_dat.has_gmac = 1; -- plat_dat.force_sf_dma_mode = 1; -- -- mdio_data.phy_reset = NULL; -- mdio_data.phy_mask = 0; -- plat_dat.mdio_bus_data = &mdio_data; -- -- dma_cfg.pbl = 32; -- dma_cfg.burst_len = DMA_AXI_BLEN_256; -- plat_dat.dma_cfg = &dma_cfg; -+/* -+ * This struct is used to associate PCI Function of MAC controller on a board, -+ * discovered via DMI, with the address of PHY connected to the MAC. The -+ * negative value of the address means that MAC controller is not connected -+ * with PHY. -+ */ -+struct stmmac_pci_dmi_data { -+ const char *name; -+ unsigned int func; -+ int phy_addr; -+}; -+ -+struct stmmac_pci_info { -+ struct pci_dev *pdev; -+ int (*setup)(struct plat_stmmacenet_data *plat, -+ struct stmmac_pci_info *info); -+ struct stmmac_pci_dmi_data *dmi; -+}; -+ -+static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info) -+{ -+ const char *name = dmi_get_system_info(DMI_BOARD_NAME); -+ unsigned int func = PCI_FUNC(info->pdev->devfn); -+ struct stmmac_pci_dmi_data *dmi; -+ -+ /* -+ * Galileo boards with old firmware don't support DMI. We always return -+ * 1 here, so at least first found MAC controller would be probed. -+ */ -+ if (!name) -+ return 1; -+ -+ for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) { -+ if (!strcmp(dmi->name, name) && dmi->func == func) -+ return dmi->phy_addr; -+ } -+ -+ return -ENODEV; -+} -+ -+static void stmmac_default_data(struct plat_stmmacenet_data *plat) -+{ -+ plat->bus_id = 1; -+ plat->phy_addr = 0; -+ plat->interface = PHY_INTERFACE_MODE_GMII; -+ plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ -+ plat->has_gmac = 1; -+ plat->force_sf_dma_mode = 1; -+ -+ plat->mdio_bus_data->phy_reset = NULL; -+ plat->mdio_bus_data->phy_mask = 0; -+ -+ plat->dma_cfg->pbl = 32; -+ plat->dma_cfg->burst_len = DMA_AXI_BLEN_256; -+ -+ /* Set default value for multicast hash bins */ -+ plat->multicast_filter_bins = HASH_TABLE_SIZE; -+ -+ /* Set default value for unicast filter entries */ -+ plat->unicast_filter_entries = 1; -+} -+ -+static int quark_default_data(struct plat_stmmacenet_data *plat, -+ struct stmmac_pci_info *info) -+{ -+ struct pci_dev *pdev = info->pdev; -+ int ret; -+ -+ /* -+ * Refuse to load the driver and register net device if MAC controller -+ * does not connect to any PHY interface. -+ */ -+ ret = stmmac_pci_find_phy_addr(info); -+ if (ret < 0) -+ return ret; -+ -+ plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn); -+ plat->phy_addr = ret; -+ plat->interface = PHY_INTERFACE_MODE_RMII; -+ plat->clk_csr = 2; -+ plat->has_gmac = 1; -+ plat->force_sf_dma_mode = 1; -+ -+ plat->mdio_bus_data->phy_reset = NULL; -+ plat->mdio_bus_data->phy_mask = 0; -+ -+ plat->dma_cfg->pbl = 16; -+ plat->dma_cfg->burst_len = DMA_AXI_BLEN_256; -+ plat->dma_cfg->fixed_burst = 1; - - /* Set default value for multicast hash bins */ -- plat_dat.multicast_filter_bins = HASH_TABLE_SIZE; -+ plat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ -- plat_dat.unicast_filter_entries = 1; -+ plat->unicast_filter_entries = 1; -+ -+ return 0; - } - -+static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = { -+ { -+ .name = "Galileo", -+ .func = 6, -+ .phy_addr = 1, -+ }, -+ { -+ .name = "GalileoGen2", -+ .func = 6, -+ .phy_addr = 1, -+ }, -+ {} -+}; -+ -+static struct stmmac_pci_info quark_pci_info = { -+ .setup = quark_default_data, -+ .dmi = quark_pci_dmi_data, -+}; -+ - /** - * stmmac_pci_probe - * -@@ -71,64 +161,65 @@ static void stmmac_default_data(void) - static int stmmac_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) - { -- int ret = 0; -- void __iomem *addr = NULL; -- struct stmmac_priv *priv = NULL; -+ struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data; -+ struct plat_stmmacenet_data *plat; -+ struct stmmac_resources res; - int i; -+ int ret; -+ -+ plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); -+ if (!plat) -+ return -ENOMEM; -+ -+ plat->mdio_bus_data = devm_kzalloc(&pdev->dev, -+ sizeof(*plat->mdio_bus_data), -+ GFP_KERNEL); -+ if (!plat->mdio_bus_data) -+ return -ENOMEM; -+ -+ plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg), -+ GFP_KERNEL); -+ if (!plat->dma_cfg) -+ return -ENOMEM; - - /* Enable pci device */ -- ret = pci_enable_device(pdev); -+ ret = pcim_enable_device(pdev); - if (ret) { -- pr_err("%s : ERROR: failed to enable %s device\n", __func__, -- pci_name(pdev)); -+ dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", -+ __func__); - return ret; - } -- if (pci_request_regions(pdev, STMMAC_RESOURCE_NAME)) { -- pr_err("%s: ERROR: failed to get PCI region\n", __func__); -- ret = -ENODEV; -- goto err_out_req_reg_failed; -- } - - /* Get the base address of device */ -- for (i = 0; i <= 5; i++) { -+ for (i = 0; i <= PCI_STD_RESOURCE_END; i++) { - if (pci_resource_len(pdev, i) == 0) - continue; -- addr = pci_iomap(pdev, i, 0); -- if (addr == NULL) { -- pr_err("%s: ERROR: cannot map register memory aborting", -- __func__); -- ret = -EIO; -- goto err_out_map_failed; -- } -+ ret = pcim_iomap_regions(pdev, BIT(i), pci_name(pdev)); -+ if (ret) -+ return ret; - break; - } -- pci_set_master(pdev); -- -- stmmac_default_data(); - -- priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr); -- if (IS_ERR(priv)) { -- pr_err("%s: main driver probe failed", __func__); -- ret = PTR_ERR(priv); -- goto err_out; -- } -- priv->dev->irq = pdev->irq; -- priv->wol_irq = pdev->irq; -- -- pci_set_drvdata(pdev, priv->dev); -+ pci_set_master(pdev); - -- pr_debug("STMMAC platform driver registration completed"); -+ if (info) { -+ info->pdev = pdev; -+ if (info->setup) { -+ ret = info->setup(plat, info); -+ if (ret) -+ return ret; -+ } -+ } else -+ stmmac_default_data(plat); - -- return 0; -+ pci_enable_msi(pdev); - --err_out: -- pci_clear_master(pdev); --err_out_map_failed: -- pci_release_regions(pdev); --err_out_req_reg_failed: -- pci_disable_device(pdev); -+ memset(&res, 0, sizeof(res)); -+ res.addr = pcim_iomap_table(pdev)[i]; -+ res.wol_irq = pdev->irq; -+ res.irq = pdev->irq; - -- return ret; -+ return stmmac_dvr_probe(&pdev->dev, plat, &res); - } - - /** -@@ -141,61 +232,55 @@ err_out_req_reg_failed: - static void stmmac_pci_remove(struct pci_dev *pdev) - { - struct net_device *ndev = pci_get_drvdata(pdev); -- struct stmmac_priv *priv = netdev_priv(ndev); - - stmmac_dvr_remove(ndev); -- -- pci_iounmap(pdev, priv->ioaddr); -- pci_release_regions(pdev); -- pci_disable_device(pdev); - } - --#ifdef CONFIG_PM --static int stmmac_pci_suspend(struct pci_dev *pdev, pm_message_t state) -+#ifdef CONFIG_PM_SLEEP -+static int stmmac_pci_suspend(struct device *dev) - { -+ struct pci_dev *pdev = to_pci_dev(dev); - struct net_device *ndev = pci_get_drvdata(pdev); -- int ret; -- -- ret = stmmac_suspend(ndev); -- pci_save_state(pdev); -- pci_set_power_state(pdev, pci_choose_state(pdev, state)); - -- return ret; -+ return stmmac_suspend(ndev); - } - --static int stmmac_pci_resume(struct pci_dev *pdev) -+static int stmmac_pci_resume(struct device *dev) - { -+ struct pci_dev *pdev = to_pci_dev(dev); - struct net_device *ndev = pci_get_drvdata(pdev); - -- pci_set_power_state(pdev, PCI_D0); -- pci_restore_state(pdev); -- - return stmmac_resume(ndev); - } - #endif - -+static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume); -+ - #define STMMAC_VENDOR_ID 0x700 -+#define STMMAC_QUARK_ID 0x0937 - #define STMMAC_DEVICE_ID 0x1108 - - static const struct pci_device_id stmmac_id_table[] = { - {PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)}, -+ {PCI_VDEVICE(INTEL, STMMAC_QUARK_ID), (kernel_ulong_t)&quark_pci_info}, - {} - }; - - MODULE_DEVICE_TABLE(pci, stmmac_id_table); - --struct pci_driver stmmac_pci_driver = { -+static struct pci_driver stmmac_pci_driver = { - .name = STMMAC_RESOURCE_NAME, - .id_table = stmmac_id_table, - .probe = stmmac_pci_probe, - .remove = stmmac_pci_remove, --#ifdef CONFIG_PM -- .suspend = stmmac_pci_suspend, -- .resume = stmmac_pci_resume, --#endif -+ .driver = { -+ .pm = &stmmac_pm_ops, -+ }, - }; - -+module_pci_driver(stmmac_pci_driver); -+ - MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver"); - MODULE_AUTHOR("Rayagond Kokatanur "); - MODULE_AUTHOR("Giuseppe Cavallaro "); ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -@@ -23,41 +23,23 @@ - *******************************************************************************/ - - #include -+#include - #include - #include - #include - #include --#include "stmmac.h" -+#include - --static const struct of_device_id stmmac_dt_ids[] = { --#ifdef CONFIG_DWMAC_MESON -- { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data}, --#endif --#ifdef CONFIG_DWMAC_SUNXI -- { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data}, --#endif --#ifdef CONFIG_DWMAC_STI -- { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data}, -- { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data}, -- { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data}, -- { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data}, --#endif --#ifdef CONFIG_DWMAC_SOCFPGA -- { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data }, --#endif -- /* SoC specific glue layers should come before generic bindings */ -- { .compatible = "st,spear600-gmac"}, -- { .compatible = "snps,dwmac-3.610"}, -- { .compatible = "snps,dwmac-3.70a"}, -- { .compatible = "snps,dwmac-3.710"}, -- { .compatible = "snps,dwmac"}, -- { /* sentinel */ } --}; --MODULE_DEVICE_TABLE(of, stmmac_dt_ids); -+#include "stmmac.h" -+#include "stmmac_platform.h" - - #ifdef CONFIG_OF - --/* This function validates the number of Multicast filtering bins specified -+/** -+ * dwmac1000_validate_mcast_bins - validates the number of Multicast filter bins -+ * @mcast_bins: Multicast filtering bins -+ * Description: -+ * this function validates the number of Multicast filtering bins specified - * by the configuration through the device tree. The Synopsys GMAC supports - * 64 bins, 128 bins, or 256 bins. "bins" refer to the division of CRC - * number space. 64 bins correspond to 6 bits of the CRC, 128 corresponds -@@ -83,7 +65,11 @@ static int dwmac1000_validate_mcast_bins - return x; - } - --/* This function validates the number of Unicast address entries supported -+/** -+ * dwmac1000_validate_ucast_entries - validate the Unicast address entries -+ * @ucast_entries: number of Unicast address entries -+ * Description: -+ * This function validates the number of Unicast address entries supported - * by a particular Synopsys 10/100/1000 controller. The Synopsys controller - * supports 1, 32, 64, or 128 Unicast filter entries for it's Unicast filter - * logic. This function validates a valid, supported configuration is -@@ -109,37 +95,25 @@ static int dwmac1000_validate_ucast_entr - return x; - } - --static int stmmac_probe_config_dt(struct platform_device *pdev, -- struct plat_stmmacenet_data *plat, -- const char **mac) -+/** -+ * stmmac_probe_config_dt - parse device-tree driver parameters -+ * @pdev: platform_device structure -+ * @plat: driver data platform structure -+ * @mac: MAC address to use -+ * Description: -+ * this function is to read the driver parameters from device-tree and -+ * set some private fields that will be used by the main at runtime. -+ */ -+struct plat_stmmacenet_data * -+stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) - { - struct device_node *np = pdev->dev.of_node; -+ struct plat_stmmacenet_data *plat; - struct stmmac_dma_cfg *dma_cfg; -- const struct of_device_id *device; - -- if (!np) -- return -ENODEV; -- -- device = of_match_device(stmmac_dt_ids, &pdev->dev); -- if (!device) -- return -ENODEV; -- -- if (device->data) { -- const struct stmmac_of_data *data = device->data; -- plat->has_gmac = data->has_gmac; -- plat->enh_desc = data->enh_desc; -- plat->tx_coe = data->tx_coe; -- plat->rx_coe = data->rx_coe; -- plat->bugged_jumbo = data->bugged_jumbo; -- plat->pmt = data->pmt; -- plat->riwt_off = data->riwt_off; -- plat->fix_mac_speed = data->fix_mac_speed; -- plat->bus_setup = data->bus_setup; -- plat->setup = data->setup; -- plat->free = data->free; -- plat->init = data->init; -- plat->exit = data->exit; -- } -+ plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); -+ if (!plat) -+ return ERR_PTR(-ENOMEM); - - *mac = of_get_mac_address(np); - plat->interface = of_get_phy_mode(np); -@@ -155,13 +129,24 @@ static int stmmac_probe_config_dt(struct - /* Default to phy auto-detection */ - plat->phy_addr = -1; - -+ /* If we find a phy-handle property, use it as the PHY */ -+ plat->phy_node = of_parse_phandle(np, "phy-handle", 0); -+ -+ /* If phy-handle is not specified, check if we have a fixed-phy */ -+ if (!plat->phy_node && of_phy_is_fixed_link(np)) { -+ if ((of_phy_register_fixed_link(np) < 0)) -+ return ERR_PTR(-ENODEV); -+ -+ plat->phy_node = of_node_get(np); -+ } -+ - /* "snps,phy-addr" is not a standard property. Mark it as deprecated - * and warn of its use. Remove this when phy node support is added. - */ - if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0) - dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n"); - -- if (plat->phy_bus_name) -+ if (plat->phy_node || plat->phy_bus_name) - plat->mdio_bus_data = NULL; - else - plat->mdio_bus_data = -@@ -169,6 +154,10 @@ static int stmmac_probe_config_dt(struct - sizeof(struct stmmac_mdio_bus_data), - GFP_KERNEL); - -+ of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size); -+ -+ of_property_read_u32(np, "rx-fifo-depth", &plat->rx_fifo_size); -+ - plat->force_sf_dma_mode = - of_property_read_bool(np, "snps,force_sf_dma_mode"); - -@@ -177,6 +166,12 @@ static int stmmac_probe_config_dt(struct - */ - plat->maxmtu = JUMBO_LEN; - -+ /* Set default value for multicast hash bins */ -+ plat->multicast_filter_bins = HASH_TABLE_SIZE; -+ -+ /* Set default value for unicast filter entries */ -+ plat->unicast_filter_entries = 1; -+ - /* - * Currently only the properties needed on SPEAr600 - * are provided. All other properties should be added -@@ -215,14 +210,19 @@ static int stmmac_probe_config_dt(struct - if (of_find_property(np, "snps,pbl", NULL)) { - dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), - GFP_KERNEL); -- if (!dma_cfg) -- return -ENOMEM; -+ if (!dma_cfg) { -+ of_node_put(np); -+ return ERR_PTR(-ENOMEM); -+ } - plat->dma_cfg = dma_cfg; - of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl); - dma_cfg->fixed_burst = - of_property_read_bool(np, "snps,fixed-burst"); - dma_cfg->mixed_burst = - of_property_read_bool(np, "snps,mixed-burst"); -+ of_property_read_u32(np, "snps,burst_len", &dma_cfg->burst_len); -+ if (dma_cfg->burst_len < 0 || dma_cfg->burst_len > 256) -+ dma_cfg->burst_len = 0; - } - plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode"); - if (plat->force_thresh_dma_mode) { -@@ -230,123 +230,60 @@ static int stmmac_probe_config_dt(struct - pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set."); - } - -- return 0; -+ return plat; - } - #else --static int stmmac_probe_config_dt(struct platform_device *pdev, -- struct plat_stmmacenet_data *plat, -- const char **mac) -+struct plat_stmmacenet_data * -+stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) - { -- return -ENOSYS; -+ return ERR_PTR(-ENOSYS); - } - #endif /* CONFIG_OF */ -+EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); - --/** -- * stmmac_pltfr_probe -- * @pdev: platform device pointer -- * Description: platform_device probe function. It allocates -- * the necessary resources and invokes the main to init -- * the net device, register the mdio bus etc. -- */ --static int stmmac_pltfr_probe(struct platform_device *pdev) -+int stmmac_get_platform_resources(struct platform_device *pdev, -+ struct stmmac_resources *stmmac_res) - { -- int ret = 0; - struct resource *res; -- struct device *dev = &pdev->dev; -- void __iomem *addr = NULL; -- struct stmmac_priv *priv = NULL; -- struct plat_stmmacenet_data *plat_dat = NULL; -- const char *mac = NULL; -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- addr = devm_ioremap_resource(dev, res); -- if (IS_ERR(addr)) -- return PTR_ERR(addr); -- -- plat_dat = dev_get_platdata(&pdev->dev); -- -- if (!plat_dat) -- plat_dat = devm_kzalloc(&pdev->dev, -- sizeof(struct plat_stmmacenet_data), -- GFP_KERNEL); -- if (!plat_dat) { -- pr_err("%s: ERROR: no memory", __func__); -- return -ENOMEM; -- } -- -- /* Set default value for multicast hash bins */ -- plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; -- -- /* Set default value for unicast filter entries */ -- plat_dat->unicast_filter_entries = 1; -- -- if (pdev->dev.of_node) { -- ret = stmmac_probe_config_dt(pdev, plat_dat, &mac); -- if (ret) { -- pr_err("%s: main dt probe failed", __func__); -- return ret; -- } -- } -- -- /* Custom setup (if needed) */ -- if (plat_dat->setup) { -- plat_dat->bsp_priv = plat_dat->setup(pdev); -- if (IS_ERR(plat_dat->bsp_priv)) -- return PTR_ERR(plat_dat->bsp_priv); -- } -- -- /* Custom initialisation (if needed)*/ -- if (plat_dat->init) { -- ret = plat_dat->init(pdev, plat_dat->bsp_priv); -- if (unlikely(ret)) -- return ret; -- } - -- priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr); -- if (IS_ERR(priv)) { -- pr_err("%s: main driver probe failed", __func__); -- return PTR_ERR(priv); -- } -+ memset(stmmac_res, 0, sizeof(*stmmac_res)); - -- /* Get MAC address if available (DT) */ -- if (mac) -- memcpy(priv->dev->dev_addr, mac, ETH_ALEN); -- -- /* Get the MAC information */ -- priv->dev->irq = platform_get_irq_byname(pdev, "macirq"); -- if (priv->dev->irq < 0) { -- if (priv->dev->irq != -EPROBE_DEFER) { -- netdev_err(priv->dev, -- "MAC IRQ configuration information not found\n"); -+ /* Get IRQ information early to have an ability to ask for deferred -+ * probe if needed before we went too far with resource allocation. -+ */ -+ stmmac_res->irq = platform_get_irq_byname(pdev, "macirq"); -+ if (stmmac_res->irq < 0) { -+ if (stmmac_res->irq != -EPROBE_DEFER) { -+ dev_err(&pdev->dev, -+ "MAC IRQ configuration information not found\n"); - } -- return priv->dev->irq; -+ return stmmac_res->irq; - } - -- /* -- * On some platforms e.g. SPEAr the wake up irq differs from the mac irq -+ /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq - * The external wake up irq can be passed through the platform code - * named as "eth_wake_irq" - * - * In case the wake up interrupt is not passed from the platform - * so the driver will continue to use the mac irq (ndev->irq) - */ -- priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); -- if (priv->wol_irq < 0) { -- if (priv->wol_irq == -EPROBE_DEFER) -+ stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); -+ if (stmmac_res->wol_irq < 0) { -+ if (stmmac_res->wol_irq == -EPROBE_DEFER) - return -EPROBE_DEFER; -- priv->wol_irq = priv->dev->irq; -+ stmmac_res->wol_irq = stmmac_res->irq; - } - -- priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); -- if (priv->lpi_irq == -EPROBE_DEFER) -+ stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); -+ if (stmmac_res->lpi_irq == -EPROBE_DEFER) - return -EPROBE_DEFER; - -- platform_set_drvdata(pdev, priv->dev); -- -- pr_debug("STMMAC platform driver registration completed"); -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res); - -- return 0; -+ return PTR_ERR_OR_ZERO(stmmac_res->addr); - } -+EXPORT_SYMBOL_GPL(stmmac_get_platform_resources); - - /** - * stmmac_pltfr_remove -@@ -354,7 +291,7 @@ static int stmmac_pltfr_probe(struct pla - * Description: this function calls the main to free the net resources - * and calls the platforms hook and release the resources (e.g. mem). - */ --static int stmmac_pltfr_remove(struct platform_device *pdev) -+int stmmac_pltfr_remove(struct platform_device *pdev) - { - struct net_device *ndev = platform_get_drvdata(pdev); - struct stmmac_priv *priv = netdev_priv(ndev); -@@ -363,13 +300,18 @@ static int stmmac_pltfr_remove(struct pl - if (priv->plat->exit) - priv->plat->exit(pdev, priv->plat->bsp_priv); - -- if (priv->plat->free) -- priv->plat->free(pdev, priv->plat->bsp_priv); -- - return ret; - } -+EXPORT_SYMBOL_GPL(stmmac_pltfr_remove); - --#ifdef CONFIG_PM -+#ifdef CONFIG_PM_SLEEP -+/** -+ * stmmac_pltfr_suspend -+ * @dev: device pointer -+ * Description: this function is invoked when suspend the driver and it direcly -+ * call the main suspend function and then, if required, on some platform, it -+ * can call an exit helper. -+ */ - static int stmmac_pltfr_suspend(struct device *dev) - { - int ret; -@@ -384,6 +326,13 @@ static int stmmac_pltfr_suspend(struct d - return ret; - } - -+/** -+ * stmmac_pltfr_resume -+ * @dev: device pointer -+ * Description: this function is invoked when resume the driver before calling -+ * the main resume function, on some platforms, it can call own init helper -+ * if required. -+ */ - static int stmmac_pltfr_resume(struct device *dev) - { - struct net_device *ndev = dev_get_drvdata(dev); -@@ -395,23 +344,12 @@ static int stmmac_pltfr_resume(struct de - - return stmmac_resume(ndev); - } -+#endif /* CONFIG_PM_SLEEP */ - --#endif /* CONFIG_PM */ -- --static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, -- stmmac_pltfr_suspend, stmmac_pltfr_resume); -- --struct platform_driver stmmac_pltfr_driver = { -- .probe = stmmac_pltfr_probe, -- .remove = stmmac_pltfr_remove, -- .driver = { -- .name = STMMAC_RESOURCE_NAME, -- .owner = THIS_MODULE, -- .pm = &stmmac_pltfr_pm_ops, -- .of_match_table = of_match_ptr(stmmac_dt_ids), -- }, --}; -+SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend, -+ stmmac_pltfr_resume); -+EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops); - --MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver"); -+MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support"); - MODULE_AUTHOR("Giuseppe Cavallaro "); - MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h -@@ -0,0 +1,33 @@ -+/******************************************************************************* -+ Copyright (C) 2007-2009 STMicroelectronics Ltd -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+ Author: Giuseppe Cavallaro -+*******************************************************************************/ -+ -+#ifndef __STMMAC_PLATFORM_H__ -+#define __STMMAC_PLATFORM_H__ -+ -+#include "stmmac.h" -+ -+struct plat_stmmacenet_data * -+stmmac_probe_config_dt(struct platform_device *pdev, const char **mac); -+ -+int stmmac_get_platform_resources(struct platform_device *pdev, -+ struct stmmac_resources *stmmac_res); -+ -+int stmmac_pltfr_remove(struct platform_device *pdev); -+extern const struct dev_pm_ops stmmac_pltfr_pm_ops; -+ -+#endif /* __STMMAC_PLATFORM_H__ */ diff --git a/target/linux/ipq806x/patches-3.18/707-ARM-dts-qcom-add-mdio-nodes-to-ap148-db149.patch b/target/linux/ipq806x/patches-3.18/707-ARM-dts-qcom-add-mdio-nodes-to-ap148-db149.patch deleted file mode 100644 index 0f2aebe5d4ca..000000000000 --- a/target/linux/ipq806x/patches-3.18/707-ARM-dts-qcom-add-mdio-nodes-to-ap148-db149.patch +++ /dev/null @@ -1,146 +0,0 @@ -From e81de9d28bd0421c236df322872e64edf4ee1852 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Mon, 11 May 2015 16:32:09 -0700 -Subject: [PATCH 7/8] ARM: dts: qcom: add mdio nodes to ap148 & db149 - -Signed-off-by: Mathieu Olivari ---- - arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 40 ++++++++++++++++++++++++++- - arch/arm/boot/dts/qcom-ipq8064-db149.dts | 46 ++++++++++++++++++++++++++++++++ - 2 files changed, 85 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -@@ -19,8 +19,9 @@ - }; - }; - -- alias { -+ aliases { - serial0 = &uart4; -+ mdio-gpio0 = &mdio0; - }; - - chosen { -@@ -68,6 +69,15 @@ - bias-bus-hold; - }; - }; -+ -+ mdio0_pins: mdio0_pins { -+ mux { -+ pins = "gpio0", "gpio1"; -+ function = "gpio"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ }; - }; - - gsbi@16300000 { -@@ -162,6 +172,34 @@ - - linux,part-probe = "qcom-smem"; - }; -+ -+ mdio0: mdio { -+ compatible = "virtual,mdio-gpio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; -+ pinctrl-0 = <&mdio0_pins>; -+ pinctrl-names = "default"; -+ -+ 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>; -+ }; -+ }; - }; - }; - ---- a/arch/arm/boot/dts/qcom-ipq8064-db149.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-db149.dts -@@ -16,6 +16,7 @@ - - alias { - serial0 = &uart2; -+ mdio-gpio0 = &mdio0; - }; - - chosen { -@@ -38,6 +39,15 @@ - bias-none; - }; - }; -+ -+ mdio0_pins: mdio0_pins { -+ mux { -+ pins = "gpio0", "gpio1"; -+ function = "gpio"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ }; - }; - - gsbi2: gsbi@12480000 { -@@ -140,5 +150,44 @@ - pcie2: pci@1b900000 { - status = "ok"; - }; -+ -+ mdio0: mdio { -+ compatible = "virtual,mdio-gpio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; -+ -+ pinctrl-0 = <&mdio0_pins>; -+ pinctrl-names = "default"; -+ -+ 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>; -+ }; -+ -+ phy6: ethernet-phy@6 { -+ device_type = "ethernet-phy"; -+ reg = <6>; -+ }; -+ -+ phy7: ethernet-phy@7 { -+ device_type = "ethernet-phy"; -+ reg = <7>; -+ }; -+ }; - }; - }; diff --git a/target/linux/ipq806x/patches-3.18/708-ARM-dts-qcom-add-gmac-nodes-to-ipq806x-platforms.patch b/target/linux/ipq806x/patches-3.18/708-ARM-dts-qcom-add-gmac-nodes-to-ipq806x-platforms.patch deleted file mode 100644 index 49203f1cea09..000000000000 --- a/target/linux/ipq806x/patches-3.18/708-ARM-dts-qcom-add-gmac-nodes-to-ipq806x-platforms.patch +++ /dev/null @@ -1,216 +0,0 @@ -From cab1f4720e82f2e17eaeed9a9ad9e4f07c742977 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Mon, 11 May 2015 12:29:18 -0700 -Subject: [PATCH 8/8] ARM: dts: qcom: add gmac nodes to ipq806x platforms - -Signed-off-by: Mathieu Olivari ---- - arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 31 ++++++++++++ - arch/arm/boot/dts/qcom-ipq8064-db149.dts | 43 ++++++++++++++++ - arch/arm/boot/dts/qcom-ipq8064.dtsi | 86 ++++++++++++++++++++++++++++++++ - 3 files changed, 160 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts -@@ -78,6 +78,16 @@ - 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 { -@@ -200,6 +210,31 @@ - reg = <4>; - }; - }; -+ -+ gmac1: ethernet@37200000 { -+ status = "ok"; -+ phy-mode = "rgmii"; -+ qcom,id = <1>; -+ -+ pinctrl-0 = <&rgmii2_pins>; -+ pinctrl-names = "default"; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <2>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; - }; - }; - ---- a/arch/arm/boot/dts/qcom-ipq8064-db149.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-db149.dts -@@ -48,6 +48,14 @@ - bias-disable; - }; - }; -+ -+ rgmii0_pins: rgmii0_pins { -+ mux { -+ pins = "gpio2", "gpio66"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ }; - }; - - gsbi2: gsbi@12480000 { -@@ -189,5 +197,40 @@ - reg = <7>; - }; - }; -+ -+ gmac0: ethernet@37000000 { -+ status = "ok"; -+ phy-mode = "rgmii"; -+ qcom,id = <0>; -+ phy-handle = <&phy4>; -+ -+ pinctrl-0 = <&rgmii0_pins>; -+ pinctrl-names = "default"; -+ }; -+ -+ gmac1: ethernet@37200000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <1>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <2>; -+ phy-handle = <&phy6>; -+ }; -+ -+ gmac3: ethernet@37600000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <3>; -+ phy-handle = <&phy7>; -+ }; - }; - }; ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -741,6 +741,92 @@ - status = "disabled"; - }; - -+ nss_common: syscon@03000000 { -+ compatible = "syscon"; -+ reg = <0x03000000 0x0000FFFF>; -+ }; -+ -+ qsgmii_csr: syscon@1bb00000 { -+ compatible = "syscon"; -+ reg = <0x1bb00000 0x000001FF>; -+ }; -+ -+ gmac0: ethernet@37000000 { -+ device_type = "network"; -+ compatible = "qcom,ipq806x-gmac"; -+ reg = <0x37000000 0x200000>; -+ interrupts = ; -+ interrupt-names = "macirq"; -+ -+ qcom,nss-common = <&nss_common>; -+ qcom,qsgmii-csr = <&qsgmii_csr>; -+ -+ clocks = <&gcc GMAC_CORE1_CLK>; -+ clock-names = "stmmaceth"; -+ -+ resets = <&gcc GMAC_CORE1_RESET>; -+ reset-names = "stmmaceth"; -+ -+ status = "disabled"; -+ }; -+ -+ gmac1: ethernet@37200000 { -+ device_type = "network"; -+ compatible = "qcom,ipq806x-gmac"; -+ reg = <0x37200000 0x200000>; -+ interrupts = ; -+ interrupt-names = "macirq"; -+ -+ qcom,nss-common = <&nss_common>; -+ qcom,qsgmii-csr = <&qsgmii_csr>; -+ -+ clocks = <&gcc GMAC_CORE2_CLK>; -+ clock-names = "stmmaceth"; -+ -+ resets = <&gcc GMAC_CORE2_RESET>; -+ reset-names = "stmmaceth"; -+ -+ status = "disabled"; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ device_type = "network"; -+ compatible = "qcom,ipq806x-gmac"; -+ reg = <0x37400000 0x200000>; -+ interrupts = ; -+ interrupt-names = "macirq"; -+ -+ qcom,nss-common = <&nss_common>; -+ qcom,qsgmii-csr = <&qsgmii_csr>; -+ -+ clocks = <&gcc GMAC_CORE3_CLK>; -+ clock-names = "stmmaceth"; -+ -+ resets = <&gcc GMAC_CORE3_RESET>; -+ reset-names = "stmmaceth"; -+ -+ status = "disabled"; -+ }; -+ -+ gmac3: ethernet@37600000 { -+ device_type = "network"; -+ compatible = "qcom,ipq806x-gmac"; -+ reg = <0x37600000 0x200000>; -+ interrupts = ; -+ interrupt-names = "macirq"; -+ -+ qcom,nss-common = <&nss_common>; -+ qcom,qsgmii-csr = <&qsgmii_csr>; -+ -+ clocks = <&gcc GMAC_CORE4_CLK>; -+ clock-names = "stmmaceth"; -+ -+ resets = <&gcc GMAC_CORE4_RESET>; -+ reset-names = "stmmaceth"; -+ -+ status = "disabled"; -+ }; -+ - }; - - sfpb_mutex: sfpb-mutex { diff --git a/target/linux/ipq806x/patches-3.18/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch b/target/linux/ipq806x/patches-3.18/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch deleted file mode 100644 index d385c9a36cc4..000000000000 --- a/target/linux/ipq806x/patches-3.18/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 5bf2dabde1fa3af0c9082b42b6847ef3fd198b13 Mon Sep 17 00:00:00 2001 -From: Jonas Gorski -Date: Sun, 9 Aug 2015 12:53:55 +0200 -Subject: [PATCH] stmac: platform: add support for retreiving mac from mtd - ---- - drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -@@ -116,6 +116,19 @@ stmmac_probe_config_dt(struct platform_d - return ERR_PTR(-ENOMEM); - - *mac = of_get_mac_address(np); -+ if (!*mac) { -+ u8 mtd_mac[ETH_ALEN]; -+ int ret; -+ -+ ret = of_get_mac_address_mtd(np, mtd_mac); -+ if (ret == -EPROBE_DEFER) -+ return ERR_PTR(ret); -+ -+ if (is_valid_ether_addr(mtd_mac)) -+ *mac = devm_kmemdup(&pdev->dev, mtd_mac, ETH_ALEN, -+ GFP_KERNEL); -+ } -+ - plat->interface = of_get_phy_mode(np); - - /* Get max speed of operation from device tree */ diff --git a/target/linux/ipq806x/patches-3.18/710-stmmac-fix-ipq806x-DMA-configuration.patch b/target/linux/ipq806x/patches-3.18/710-stmmac-fix-ipq806x-DMA-configuration.patch deleted file mode 100644 index c99f60768f28..000000000000 --- a/target/linux/ipq806x/patches-3.18/710-stmmac-fix-ipq806x-DMA-configuration.patch +++ /dev/null @@ -1,117 +0,0 @@ ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -@@ -259,6 +259,7 @@ static int ipq806x_gmac_probe(struct pla - { - struct plat_stmmacenet_data *plat_dat; - struct stmmac_resources stmmac_res; -+ struct stmmac_dma_cfg *dma_cfg; - struct device *dev = &pdev->dev; - struct ipq806x_gmac *gmac; - int val; -@@ -348,6 +349,17 @@ static int ipq806x_gmac_probe(struct pla - plat_dat->bsp_priv = gmac; - plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; - -+ dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), -+ GFP_KERNEL); -+ -+ dma_cfg->pbl = 32; -+ dma_cfg->aal = 1; -+ dma_cfg->burst_len = DMA_AXI_BLEN_16 | -+ (7 << DMA_AXI_RD_OSR_LMT_SHIFT) | -+ (7 << DMA_AXI_WR_OSR_LMT_SHIFT); -+ -+ plat_dat->dma_cfg = dma_cfg; -+ - return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); - } - ---- a/include/linux/stmmac.h -+++ b/include/linux/stmmac.h -@@ -73,6 +73,9 @@ - | DMA_AXI_BLEN_32 | DMA_AXI_BLEN_64 \ - | DMA_AXI_BLEN_128 | DMA_AXI_BLEN_256) - -+#define DMA_AXI_RD_OSR_LMT_SHIFT 16 -+#define DMA_AXI_WR_OSR_LMT_SHIFT 20 -+ - /* Platfrom data for platform device structure's platform_data field */ - - struct stmmac_mdio_bus_data { -@@ -88,6 +91,7 @@ struct stmmac_mdio_bus_data { - - struct stmmac_dma_cfg { - int pbl; -+ int aal; - int fixed_burst; - int mixed_burst; - int burst_len; ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c -@@ -31,7 +31,8 @@ - #include "dwmac_dma.h" - - static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb, -- int burst_len, u32 dma_tx, u32 dma_rx, int atds) -+ int burst_len, u32 dma_tx, u32 dma_rx, int atds, -+ int aal) - { - u32 value = readl(ioaddr + DMA_BUS_MODE); - int limit; -@@ -62,6 +63,10 @@ static int dwmac1000_dma_init(void __iom - value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) | - (pbl << DMA_BUS_MODE_RPBL_SHIFT)); - -+ /* Address Aligned Beats */ -+ if (aal) -+ value |= DMA_BUS_MODE_AAL; -+ - /* Set the Fixed burst mode */ - if (fb) - value |= DMA_BUS_MODE_FB; ---- a/drivers/net/ethernet/stmicro/stmmac/common.h -+++ b/drivers/net/ethernet/stmicro/stmmac/common.h -@@ -352,7 +352,7 @@ extern const struct stmmac_desc_ops ndes - struct stmmac_dma_ops { - /* DMA core initialization */ - int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb, -- int burst_len, u32 dma_tx, u32 dma_rx, int atds); -+ int burst_len, u32 dma_tx, u32 dma_rx, int atds, int aal); - /* Dump DMA registers */ - void (*dump_regs) (void __iomem *ioaddr); - /* Set tx/rx threshold in the csr6 register ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c -@@ -33,7 +33,8 @@ - #include "dwmac_dma.h" - - static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb, -- int burst_len, u32 dma_tx, u32 dma_rx, int atds) -+ int burst_len, u32 dma_tx, u32 dma_rx, int atds, -+ int aal) - { - u32 value = readl(ioaddr + DMA_BUS_MODE); - int limit; ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -1639,9 +1639,11 @@ static int stmmac_init_dma_engine(struct - int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_len = 0; - int mixed_burst = 0; - int atds = 0; -+ int aal = 0; - - if (priv->plat->dma_cfg) { - pbl = priv->plat->dma_cfg->pbl; -+ aal = priv->plat->dma_cfg->aal; - fixed_burst = priv->plat->dma_cfg->fixed_burst; - mixed_burst = priv->plat->dma_cfg->mixed_burst; - burst_len = priv->plat->dma_cfg->burst_len; -@@ -1652,7 +1654,7 @@ static int stmmac_init_dma_engine(struct - - return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst, - burst_len, priv->dma_tx_phy, -- priv->dma_rx_phy, atds); -+ priv->dma_rx_phy, atds, aal); - } - - /** diff --git a/target/linux/ipq806x/patches-3.18/801-ARM-qcom-add-Netgear-Nighthawk-X4-D7800-device-tree.patch b/target/linux/ipq806x/patches-3.18/801-ARM-qcom-add-Netgear-Nighthawk-X4-D7800-device-tree.patch deleted file mode 100644 index eaf037f57e78..000000000000 --- a/target/linux/ipq806x/patches-3.18/801-ARM-qcom-add-Netgear-Nighthawk-X4-D7800-device-tree.patch +++ /dev/null @@ -1,381 +0,0 @@ ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -362,6 +362,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ - qcom-ipq8064-ap148.dtb \ - qcom-ipq8064-db149.dtb \ - qcom-ipq8064-r7500.dtb \ -+ qcom-ipq8064-d7800.dtb \ - qcom-msm8660-surf.dtb \ - qcom-msm8960-cdp.dtb \ - qcom-msm8974-sony-xperia-honami.dtb ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-d7800.dts -@@ -0,0 +1,368 @@ -+#include "qcom-ipq8064-v1.0.dtsi" -+ -+#include -+ -+/ { -+ model = "Netgear Nighthawk X4 D7800"; -+ compatible = "netgear,d7800", "qcom,ipq8064"; -+ -+ memory@0 { -+ reg = <0x42000000 0xe000000>; -+ device_type = "memory"; -+ }; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ rsvd@41200000 { -+ reg = <0x41200000 0x300000>; -+ no-map; -+ }; -+ }; -+ -+ aliases { -+ serial0 = &uart4; -+ mdio-gpio0 = &mdio0; -+ }; -+ -+ chosen { -+ bootargs = "rootfstype=squashfs noinitrd"; -+ linux,stdout-path = "serial0:115200n8"; -+ }; -+ -+ soc { -+ pinmux@800000 { -+ i2c4_pins: i2c4_pinmux { -+ pins = "gpio12", "gpio13"; -+ function = "gsbi4"; -+ bias-disable; -+ }; -+ -+ pcie0_pins: pcie0_pinmux { -+ mux { -+ pins = "gpio3"; -+ function = "pcie1_rst"; -+ drive-strength = <12>; -+ bias-disable; -+ }; -+ }; -+ -+ pcie1_pins: pcie1_pinmux { -+ mux { -+ pins = "gpio48"; -+ function = "pcie2_rst"; -+ drive-strength = <12>; -+ bias-disable; -+ }; -+ }; -+ -+ nand_pins: nand_pins { -+ mux { -+ pins = "gpio34", "gpio35", "gpio36", -+ "gpio37", "gpio38", "gpio39", -+ "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ function = "nand"; -+ drive-strength = <10>; -+ bias-disable; -+ }; -+ pullups { -+ pins = "gpio39"; -+ bias-pull-up; -+ }; -+ hold { -+ pins = "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ bias-bus-hold; -+ }; -+ }; -+ -+ 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 { -+ qcom,mode = ; -+ status = "ok"; -+ serial@16340000 { -+ status = "ok"; -+ }; -+ /* -+ * The i2c device on gsbi4 should not be enabled. -+ * On ipq806x designs gsbi4 i2c is meant for exclusive -+ * RPM usage. Turning this on in kernel manifests as -+ * i2c failure for the RPM. -+ */ -+ }; -+ -+ sata-phy@1b400000 { -+ status = "ok"; -+ }; -+ -+ sata@29000000 { -+ status = "ok"; -+ }; -+ -+ phy@100f8800 { /* USB3 port 1 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@100f8830 { /* USB3 port 1 SS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8800 { /* USB3 port 0 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8830 { /* USB3 port 0 SS phy */ -+ status = "ok"; -+ }; -+ -+ usb30@0 { -+ status = "ok"; -+ }; -+ -+ usb30@1 { -+ status = "ok"; -+ }; -+ -+ pcie0: pci@1b500000 { -+ status = "ok"; -+ reset-gpio = <&qcom_pinmux 3 0>; -+ pinctrl-0 = <&pcie0_pins>; -+ pinctrl-names = "default"; -+ }; -+ -+ pcie1: pci@1b700000 { -+ status = "ok"; -+ reset-gpio = <&qcom_pinmux 48 0>; -+ pinctrl-0 = <&pcie1_pins>; -+ pinctrl-names = "default"; -+ }; -+ -+ nand@1ac00000 { -+ status = "ok"; -+ -+ pinctrl-0 = <&nand_pins>; -+ pinctrl-names = "default"; -+ -+ nand-ecc-strength = <4>; -+ nand-bus-width = <8>; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ qcadata@0 { -+ label = "qcadata"; -+ reg = <0x0000000 0x0c80000>; -+ read-only; -+ }; -+ -+ APPSBL@c80000 { -+ label = "APPSBL"; -+ reg = <0x0c80000 0x0500000>; -+ read-only; -+ }; -+ -+ APPSBLENV@1180000 { -+ label = "APPSBLENV"; -+ reg = <0x1180000 0x0080000>; -+ read-only; -+ }; -+ -+ art: art@1200000 { -+ label = "art"; -+ reg = <0x1200000 0x0140000>; -+ read-only; -+ }; -+ -+ artbak: art@1340000 { -+ label = "artbak"; -+ reg = <0x1340000 0x0140000>; -+ read-only; -+ }; -+ -+ kernel@1480000 { -+ label = "kernel"; -+ reg = <0x1480000 0x0200000>; -+ }; -+ -+ ubi@1680000 { -+ label = "ubi"; -+ reg = <0x1680000 0x1E00000>; -+ }; -+ -+ netgear@3480000 { -+ label = "netgear"; -+ reg = <0x3480000 0x4480000>; -+ read-only; -+ }; -+ -+ reserve@7900000 { -+ label = "reserve"; -+ reg = <0x7900000 0x0700000>; -+ read-only; -+ }; -+ -+ firmware@1480000 { -+ label = "firmware"; -+ reg = <0x1480000 0x2000000>; -+ }; -+ -+ }; -+ -+ mdio0: mdio { -+ compatible = "virtual,mdio-gpio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; -+ pinctrl-0 = <&mdio0_pins>; -+ pinctrl-names = "default"; -+ -+ 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>; -+ }; -+ }; -+ -+ gmac1: ethernet@37200000 { -+ status = "ok"; -+ phy-mode = "rgmii"; -+ phy-handle = <&phy4>; -+ qcom,id = <1>; -+ -+ pinctrl-0 = <&rgmii2_pins>; -+ pinctrl-names = "default"; -+ -+ mtd-mac-address = <&art 6>; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <2>; -+ -+ mtd-mac-address = <&art 0>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ wifi { -+ label = "wifi"; -+ gpios = <&qcom_pinmux 6 1>; -+ linux,code = ; -+ }; -+ -+ reset { -+ label = "reset"; -+ gpios = <&qcom_pinmux 54 1>; -+ linux,code = ; -+ }; -+ -+ wps { -+ label = "wps"; -+ gpios = <&qcom_pinmux 65 1>; -+ linux,code = ; -+ }; -+ }; -+ -+ gpio-leds { -+ compatible = "gpio-leds"; -+ -+ usb1 { -+ label = "d7800:amber:usb1"; -+ gpios = <&qcom_pinmux 7 0>; -+ }; -+ -+ usb3 { -+ label = "d7800:amber:usb3"; -+ gpios = <&qcom_pinmux 8 0>; -+ }; -+ -+ status { -+ label = "d7800:amber:status"; -+ gpios = <&qcom_pinmux 9 0>; -+ }; -+ -+ internet { -+ label = "d7800:white:internet"; -+ gpios = <&qcom_pinmux 22 0>; -+ }; -+ -+ wan { -+ label = "d7800:white:wan"; -+ gpios = <&qcom_pinmux 23 0>; -+ }; -+ -+ wps { -+ label = "d7800:white:wps"; -+ gpios = <&qcom_pinmux 24 0>; -+ }; -+ -+ esata { -+ label = "d7800:white:esata"; -+ gpios = <&qcom_pinmux 26 0>; -+ }; -+ -+ power { -+ label = "d7800:white:power"; -+ gpios = <&qcom_pinmux 53 0>; -+ default-state = "on"; -+ }; -+ -+ rfkill { -+ label = "d7800:white:rfkill"; -+ gpios = <&qcom_pinmux 64 0>; -+ }; -+ -+ wifi5g { -+ label = "d7800:white:wifi5g"; -+ gpios = <&qcom_pinmux 67 0>; -+ }; -+ }; -+}; -+ -+&adm_dma { -+ status = "ok"; -+}; diff --git a/target/linux/ipq806x/patches-3.18/802-ARM-qcom-add-TPLink-C2600-device-tree.patch b/target/linux/ipq806x/patches-3.18/802-ARM-qcom-add-TPLink-C2600-device-tree.patch deleted file mode 100644 index 8952f3339d9c..000000000000 --- a/target/linux/ipq806x/patches-3.18/802-ARM-qcom-add-TPLink-C2600-device-tree.patch +++ /dev/null @@ -1,425 +0,0 @@ ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -506,6 +506,7 @@ - qcom-apq8084-ifc6540.dtb \ - qcom-apq8084-mtp.dtb \ - qcom-ipq8064-ap148.dtb \ -+ qcom-ipq8064-c2600.dtb \ - qcom-ipq8064-db149.dtb \ - qcom-ipq8064-r7500.dtb \ - qcom-ipq8064-d7800.dtb \ ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-c2600.dts -@@ -0,0 +1,412 @@ -+#include "qcom-ipq8064-v1.0.dtsi" -+#include -+ -+/ { -+ model = "TP-Link Archer C2600"; -+ compatible = "tplink,c2600", "qcom,ipq8064"; -+ -+ memory@0 { -+ reg = <0x42000000 0x1e000000>; -+ device_type = "memory"; -+ }; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ rsvd@41200000 { -+ reg = <0x41200000 0x300000>; -+ no-map; -+ }; -+ }; -+ -+ aliases { -+ serial0 = &uart4; -+ mdio-gpio0 = &mdio0; -+ }; -+ -+ chosen { -+ linux,stdout-path = "serial0:115200n8"; -+ }; -+ -+ soc { -+ pinmux@800000 { -+ i2c4_pins: i2c4_pinmux { -+ pins = "gpio12", "gpio13"; -+ function = "gsbi4"; -+ bias-disable; -+ }; -+ -+ spi_pins: spi_pins { -+ mux { -+ pins = "gpio18", "gpio19", "gpio21"; -+ function = "gsbi5"; -+ drive-strength = <10>; -+ bias-none; -+ }; -+ }; -+ -+ nand_pins: nand_pins { -+ mux { -+ pins = "gpio34", "gpio35", "gpio36", -+ "gpio37", "gpio38", "gpio39", -+ "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ function = "nand"; -+ drive-strength = <10>; -+ bias-disable; -+ }; -+ -+ pullups { -+ pins = "gpio39"; -+ bias-pull-up; -+ }; -+ -+ hold { -+ pins = "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ bias-bus-hold; -+ }; -+ }; -+ -+ 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 { -+ qcom,mode = ; -+ status = "ok"; -+ serial@16340000 { -+ status = "ok"; -+ }; -+ /* -+ * The i2c device on gsbi4 should not be enabled. -+ * On ipq806x designs gsbi4 i2c is meant for exclusive -+ * RPM usage. Turning this on in kernel manifests as -+ * i2c failure for the RPM. -+ */ -+ }; -+ -+ gsbi5: gsbi@1a200000 { -+ qcom,mode = ; -+ status = "ok"; -+ -+ spi4: spi@1a280000 { -+ status = "ok"; -+ spi-max-frequency = <50000000>; -+ -+ pinctrl-0 = <&spi_pins>; -+ pinctrl-names = "default"; -+ -+ cs-gpios = <&qcom_pinmux 20 0>; -+ -+ flash: m25p80@0 { -+ compatible = "s25fl256s1"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ spi-max-frequency = <50000000>; -+ reg = <0>; -+ -+ SBL1@0 { -+ label = "SBL1"; -+ reg = <0x0 0x20000>; -+ read-only; -+ }; -+ MIBIB@20000 { -+ label = "MIBIB"; -+ reg = <0x20000 0x20000>; -+ read-only; -+ }; -+ SBL2@40000 { -+ label = "SBL2"; -+ reg = <0x40000 0x20000>; -+ read-only; -+ }; -+ SBL3@60000 { -+ label = "SBL3"; -+ reg = <0x60000 0x30000>; -+ read-only; -+ }; -+ DDRCONFIG@90000 { -+ label = "DDRCONFIG"; -+ reg = <0x90000 0x10000>; -+ read-only; -+ }; -+ SSD@a0000 { -+ label = "SSD"; -+ reg = <0xa0000 0x10000>; -+ read-only; -+ }; -+ TZ@b0000 { -+ label = "TZ"; -+ reg = <0xb0000 0x30000>; -+ read-only; -+ }; -+ RPM@e0000 { -+ label = "RPM"; -+ reg = <0xe0000 0x20000>; -+ read-only; -+ }; -+ fs-uboot@100000 { -+ label = "fs-uboot"; -+ reg = <0x100000 0x70000>; -+ read-only; -+ }; -+ uboot-env@170000 { -+ label = "uboot-env"; -+ reg = <0x170000 0x40000>; -+ read-only; -+ }; -+ radio@1b0000 { -+ label = "radio"; -+ reg = <0x1b0000 0x40000>; -+ read-only; -+ }; -+ os-image@1f0000 { -+ label = "os-image"; -+ reg = <0x1f0000 0x200000>; -+ }; -+ rootfs@3f0000 { -+ label = "rootfs"; -+ reg = <0x3f0000 0x1b00000>; -+ }; -+ defaultmac: default-mac@1ef0000 { -+ label = "default-mac"; -+ reg = <0x1ef0000 0x00200>; -+ read-only; -+ }; -+ pin@1ef0200 { -+ label = "pin"; -+ reg = <0x1ef0200 0x00200>; -+ read-only; -+ }; -+ product-info@1ef0400 { -+ label = "product-info"; -+ reg = <0x1ef0400 0x0fc00>; -+ read-only; -+ }; -+ partition-table@1f00000 { -+ label = "partition-table"; -+ reg = <0x1f00000 0x10000>; -+ read-only; -+ }; -+ soft-version@1f10000 { -+ label = "soft-version"; -+ reg = <0x1f10000 0x10000>; -+ read-only; -+ }; -+ support-list@1f20000 { -+ label = "support-list"; -+ reg = <0x1f20000 0x10000>; -+ read-only; -+ }; -+ profile@1f30000 { -+ label = "profile"; -+ reg = <0x1f30000 0x10000>; -+ read-only; -+ }; -+ default-config@1f40000 { -+ label = "default-config"; -+ reg = <0x1f40000 0x10000>; -+ read-only; -+ }; -+ user-config@1f50000 { -+ label = "user-config"; -+ reg = <0x1f50000 0x40000>; -+ read-only; -+ }; -+ qos-db@1f90000 { -+ label = "qos-db"; -+ reg = <0x1f90000 0x40000>; -+ read-only; -+ }; -+ usb-config@1fd0000 { -+ label = "usb-config"; -+ reg = <0x1fd0000 0x10000>; -+ read-only; -+ }; -+ log@1fe0000 { -+ label = "log"; -+ reg = <0x1fe0000 0x20000>; -+ read-only; -+ }; -+ }; -+ }; -+ }; -+ -+ phy@100f8800 { /* USB3 port 1 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@100f8830 { /* USB3 port 1 SS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8800 { /* USB3 port 0 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8830 { /* USB3 port 0 SS phy */ -+ status = "ok"; -+ }; -+ -+ usb30@0 { -+ status = "ok"; -+ }; -+ -+ usb30@1 { -+ status = "ok"; -+ }; -+ -+ pcie0: pci@1b500000 { -+ status = "ok"; -+ phy-tx0-term-offset = <7>; -+ }; -+ -+ pcie1: pci@1b700000 { -+ status = "ok"; -+ phy-tx0-term-offset = <7>; -+ }; -+ -+ mdio0: mdio { -+ compatible = "virtual,mdio-gpio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; -+ pinctrl-0 = <&mdio0_pins>; -+ pinctrl-names = "default"; -+ -+ 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>; -+ }; -+ }; -+ -+ gmac1: ethernet@37200000 { -+ status = "ok"; -+ phy-mode = "rgmii"; -+ qcom,id = <1>; -+ -+ pinctrl-0 = <&rgmii2_pins>; -+ pinctrl-names = "default"; -+ -+ mtd-mac-address = <&defaultmac 0x8>; -+ mtd-mac-address-increment = <1>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <2>; -+ -+ mtd-mac-address = <&defaultmac 0x8>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ wifi { -+ label = "wifi"; -+ gpios = <&qcom_pinmux 49 1>; -+ linux,code = ; -+ }; -+ -+ reset { -+ label = "reset"; -+ gpios = <&qcom_pinmux 64 1>; -+ linux,code = ; -+ }; -+ -+ wps { -+ label = "wps"; -+ gpios = <&qcom_pinmux 65 1>; -+ linux,code = ; -+ }; -+ ledgeneral { -+ label = "ledgeneral"; -+ gpios = <&qcom_pinmux 16 1>; -+ linux,code = ; -+ }; -+ }; -+ -+ gpio-leds { -+ compatible = "gpio-leds"; -+ -+ lan { -+ label = "lan:blue"; -+ gpios = <&qcom_pinmux 6 0>; -+ }; -+ usb4 { -+ label = "usb_4:blue"; -+ gpios = <&qcom_pinmux 7 0>; -+ }; -+ usb2 { -+ label = "usb_2:blue"; -+ gpios = <&qcom_pinmux 8 0>; -+ }; -+ wps { -+ label = "wps:blue"; -+ gpios = <&qcom_pinmux 9 0>; -+ }; -+ wan_blue { -+ label = "wan:blue"; -+ gpios = <&qcom_pinmux 33 1>; -+ }; -+ status { -+ label = "status:blue"; -+ gpios = <&qcom_pinmux 53 0>; -+ default-state = "on"; -+ }; -+ ledgnr { -+ label = "ledgnr:blue"; -+ gpios = <&qcom_pinmux 66 0>; -+ }; -+ }; -+}; -+ -+&adm_dma { -+ status = "ok"; -+}; From 6c5389de448540c926fb12e7a42b51c64b4bfa67 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 7 Jun 2016 21:00:28 +0200 Subject: [PATCH 18/37] ipq806x: move dts file to the files folder Signed-off-by: John Crispin --- .../arch/arm/boot/dts/qcom-ipq8064-c2600.dts | 412 +++++++++++++++++ .../arch/arm/boot/dts/qcom-ipq8064-d7800.dts | 368 +++++++++++++++ .../arch/arm/boot/dts/qcom-ipq8064-ea8500.dts | 380 ++++++++++++++++ .../arch/arm/boot/dts/qcom-ipq8064-r7500.dts | 342 ++++++++++++++ ...tgear-Nighthawk-X4-R7500-device-tree.patch | 367 --------------- .../ipq806x/patches-4.4/800-devicetree.patch | 26 ++ ...tgear-Nighthawk-X4-D7800-device-tree.patch | 381 ---------------- ...RM-qcom-add-TPLink-C2600-device-tree.patch | 425 ------------------ 8 files changed, 1528 insertions(+), 1173 deletions(-) create mode 100644 target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts create mode 100644 target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts create mode 100644 target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts create mode 100644 target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts delete mode 100644 target/linux/ipq806x/patches-4.4/800-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch create mode 100644 target/linux/ipq806x/patches-4.4/800-devicetree.patch delete mode 100644 target/linux/ipq806x/patches-4.4/801-ARM-qcom-add-Netgear-Nighthawk-X4-D7800-device-tree.patch delete mode 100644 target/linux/ipq806x/patches-4.4/802-ARM-qcom-add-TPLink-C2600-device-tree.patch diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts new file mode 100644 index 000000000000..fc136375020e --- /dev/null +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts @@ -0,0 +1,412 @@ +#include "qcom-ipq8064-v1.0.dtsi" +#include + +/ { + model = "TP-Link Archer C2600"; + compatible = "tplink,c2600", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + serial0 = &uart4; + mdio-gpio0 = &mdio0; + }; + + chosen { + linux,stdout-path = "serial0:115200n8"; + }; + + soc { + pinmux@800000 { + i2c4_pins: i2c4_pinmux { + pins = "gpio12", "gpio13"; + function = "gsbi4"; + bias-disable; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + drive-strength = <10>; + bias-none; + }; + }; + + nand_pins: nand_pins { + mux { + pins = "gpio34", "gpio35", "gpio36", + "gpio37", "gpio38", "gpio39", + "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + function = "nand"; + drive-strength = <10>; + bias-disable; + }; + + pullups { + pins = "gpio39"; + bias-pull-up; + }; + + hold { + pins = "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + bias-bus-hold; + }; + }; + + 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 { + qcom,mode = ; + status = "ok"; + serial@16340000 { + status = "ok"; + }; + /* + * The i2c device on gsbi4 should not be enabled. + * On ipq806x designs gsbi4 i2c is meant for exclusive + * RPM usage. Turning this on in kernel manifests as + * i2c failure for the RPM. + */ + }; + + gsbi5: gsbi@1a200000 { + qcom,mode = ; + status = "ok"; + + spi4: spi@1a280000 { + status = "ok"; + spi-max-frequency = <50000000>; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 0>; + + flash: m25p80@0 { + compatible = "s25fl256s1"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + SBL1@0 { + label = "SBL1"; + reg = <0x0 0x20000>; + read-only; + }; + MIBIB@20000 { + label = "MIBIB"; + reg = <0x20000 0x20000>; + read-only; + }; + SBL2@40000 { + label = "SBL2"; + reg = <0x40000 0x20000>; + read-only; + }; + SBL3@60000 { + label = "SBL3"; + reg = <0x60000 0x30000>; + read-only; + }; + DDRCONFIG@90000 { + label = "DDRCONFIG"; + reg = <0x90000 0x10000>; + read-only; + }; + SSD@a0000 { + label = "SSD"; + reg = <0xa0000 0x10000>; + read-only; + }; + TZ@b0000 { + label = "TZ"; + reg = <0xb0000 0x30000>; + read-only; + }; + RPM@e0000 { + label = "RPM"; + reg = <0xe0000 0x20000>; + read-only; + }; + fs-uboot@100000 { + label = "fs-uboot"; + reg = <0x100000 0x70000>; + read-only; + }; + uboot-env@170000 { + label = "uboot-env"; + reg = <0x170000 0x40000>; + read-only; + }; + radio@1b0000 { + label = "radio"; + reg = <0x1b0000 0x40000>; + read-only; + }; + os-image@1f0000 { + label = "os-image"; + reg = <0x1f0000 0x200000>; + }; + rootfs@3f0000 { + label = "rootfs"; + reg = <0x3f0000 0x1b00000>; + }; + defaultmac: default-mac@1ef0000 { + label = "default-mac"; + reg = <0x1ef0000 0x00200>; + read-only; + }; + pin@1ef0200 { + label = "pin"; + reg = <0x1ef0200 0x00200>; + read-only; + }; + product-info@1ef0400 { + label = "product-info"; + reg = <0x1ef0400 0x0fc00>; + read-only; + }; + partition-table@1f00000 { + label = "partition-table"; + reg = <0x1f00000 0x10000>; + read-only; + }; + soft-version@1f10000 { + label = "soft-version"; + reg = <0x1f10000 0x10000>; + read-only; + }; + support-list@1f20000 { + label = "support-list"; + reg = <0x1f20000 0x10000>; + read-only; + }; + profile@1f30000 { + label = "profile"; + reg = <0x1f30000 0x10000>; + read-only; + }; + default-config@1f40000 { + label = "default-config"; + reg = <0x1f40000 0x10000>; + read-only; + }; + user-config@1f50000 { + label = "user-config"; + reg = <0x1f50000 0x40000>; + read-only; + }; + qos-db@1f90000 { + label = "qos-db"; + reg = <0x1f90000 0x40000>; + read-only; + }; + usb-config@1fd0000 { + label = "usb-config"; + reg = <0x1fd0000 0x10000>; + read-only; + }; + log@1fe0000 { + label = "log"; + reg = <0x1fe0000 0x20000>; + read-only; + }; + }; + }; + }; + + phy@100f8800 { /* USB3 port 1 HS phy */ + status = "ok"; + }; + + phy@100f8830 { /* USB3 port 1 SS phy */ + status = "ok"; + }; + + phy@110f8800 { /* USB3 port 0 HS phy */ + status = "ok"; + }; + + phy@110f8830 { /* USB3 port 0 SS phy */ + status = "ok"; + }; + + usb30@0 { + status = "ok"; + }; + + usb30@1 { + status = "ok"; + }; + + pcie0: pci@1b500000 { + status = "ok"; + phy-tx0-term-offset = <7>; + }; + + pcie1: pci@1b700000 { + status = "ok"; + phy-tx0-term-offset = <7>; + }; + + mdio0: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + 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>; + }; + }; + + gmac1: ethernet@37200000 { + status = "ok"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + mtd-mac-address = <&defaultmac 0x8>; + mtd-mac-address-increment = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + gmac2: ethernet@37400000 { + status = "ok"; + phy-mode = "sgmii"; + qcom,id = <2>; + + mtd-mac-address = <&defaultmac 0x8>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 49 1>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 64 1>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 1>; + linux,code = ; + }; + ledgeneral { + label = "ledgeneral"; + gpios = <&qcom_pinmux 16 1>; + linux,code = ; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + lan { + label = "lan:blue"; + gpios = <&qcom_pinmux 6 0>; + }; + usb4 { + label = "usb_4:blue"; + gpios = <&qcom_pinmux 7 0>; + }; + usb2 { + label = "usb_2:blue"; + gpios = <&qcom_pinmux 8 0>; + }; + wps { + label = "wps:blue"; + gpios = <&qcom_pinmux 9 0>; + }; + wan_blue { + label = "wan:blue"; + gpios = <&qcom_pinmux 33 1>; + }; + status { + label = "status:blue"; + gpios = <&qcom_pinmux 53 0>; + default-state = "on"; + }; + ledgnr { + label = "ledgnr:blue"; + gpios = <&qcom_pinmux 66 0>; + }; + }; +}; + +&adm_dma { + status = "ok"; +}; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts new file mode 100644 index 000000000000..bd294c590e1c --- /dev/null +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts @@ -0,0 +1,368 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +#include + +/ { + model = "Netgear Nighthawk X4 D7800"; + compatible = "netgear,d7800", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0xe000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + serial0 = &uart4; + mdio-gpio0 = &mdio0; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + linux,stdout-path = "serial0:115200n8"; + }; + + soc { + pinmux@800000 { + i2c4_pins: i2c4_pinmux { + pins = "gpio12", "gpio13"; + function = "gsbi4"; + bias-disable; + }; + + pcie0_pins: pcie0_pinmux { + mux { + pins = "gpio3"; + function = "pcie1_rst"; + drive-strength = <12>; + bias-disable; + }; + }; + + pcie1_pins: pcie1_pinmux { + mux { + pins = "gpio48"; + function = "pcie2_rst"; + drive-strength = <12>; + bias-disable; + }; + }; + + nand_pins: nand_pins { + mux { + pins = "gpio34", "gpio35", "gpio36", + "gpio37", "gpio38", "gpio39", + "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + function = "nand"; + drive-strength = <10>; + bias-disable; + }; + pullups { + pins = "gpio39"; + bias-pull-up; + }; + hold { + pins = "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + bias-bus-hold; + }; + }; + + 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 { + qcom,mode = ; + status = "ok"; + serial@16340000 { + status = "ok"; + }; + /* + * The i2c device on gsbi4 should not be enabled. + * On ipq806x designs gsbi4 i2c is meant for exclusive + * RPM usage. Turning this on in kernel manifests as + * i2c failure for the RPM. + */ + }; + + sata-phy@1b400000 { + status = "ok"; + }; + + sata@29000000 { + status = "ok"; + }; + + phy@100f8800 { /* USB3 port 1 HS phy */ + status = "ok"; + }; + + phy@100f8830 { /* USB3 port 1 SS phy */ + status = "ok"; + }; + + phy@110f8800 { /* USB3 port 0 HS phy */ + status = "ok"; + }; + + phy@110f8830 { /* USB3 port 0 SS phy */ + status = "ok"; + }; + + usb30@0 { + status = "ok"; + }; + + usb30@1 { + status = "ok"; + }; + + pcie0: pci@1b500000 { + status = "ok"; + reset-gpio = <&qcom_pinmux 3 0>; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; + }; + + pcie1: pci@1b700000 { + status = "ok"; + reset-gpio = <&qcom_pinmux 48 0>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + }; + + nand@1ac00000 { + status = "ok"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + + #address-cells = <1>; + #size-cells = <1>; + + qcadata@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art: art@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + }; + + artbak: art@1340000 { + label = "artbak"; + reg = <0x1340000 0x0140000>; + read-only; + }; + + kernel@1480000 { + label = "kernel"; + reg = <0x1480000 0x0200000>; + }; + + ubi@1680000 { + label = "ubi"; + reg = <0x1680000 0x1E00000>; + }; + + netgear@3480000 { + label = "netgear"; + reg = <0x3480000 0x4480000>; + read-only; + }; + + reserve@7900000 { + label = "reserve"; + reg = <0x7900000 0x0700000>; + read-only; + }; + + firmware@1480000 { + label = "firmware"; + reg = <0x1480000 0x2000000>; + }; + + }; + + mdio0: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + 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>; + }; + }; + + gmac1: ethernet@37200000 { + status = "ok"; + phy-mode = "rgmii"; + phy-handle = <&phy4>; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + mtd-mac-address = <&art 6>; + }; + + gmac2: ethernet@37400000 { + status = "ok"; + phy-mode = "sgmii"; + qcom,id = <2>; + + mtd-mac-address = <&art 0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 1>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 1>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 1>; + linux,code = ; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + usb1 { + label = "d7800:amber:usb1"; + gpios = <&qcom_pinmux 7 0>; + }; + + usb3 { + label = "d7800:amber:usb3"; + gpios = <&qcom_pinmux 8 0>; + }; + + status { + label = "d7800:amber:status"; + gpios = <&qcom_pinmux 9 0>; + }; + + internet { + label = "d7800:white:internet"; + gpios = <&qcom_pinmux 22 0>; + }; + + wan { + label = "d7800:white:wan"; + gpios = <&qcom_pinmux 23 0>; + }; + + wps { + label = "d7800:white:wps"; + gpios = <&qcom_pinmux 24 0>; + }; + + esata { + label = "d7800:white:esata"; + gpios = <&qcom_pinmux 26 0>; + }; + + power { + label = "d7800:white:power"; + gpios = <&qcom_pinmux 53 0>; + default-state = "on"; + }; + + rfkill { + label = "d7800:white:rfkill"; + gpios = <&qcom_pinmux 64 0>; + }; + + wifi5g { + label = "d7800:white:wifi5g"; + gpios = <&qcom_pinmux 67 0>; + }; + }; +}; + +&adm_dma { + status = "ok"; +}; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts new file mode 100644 index 000000000000..2c5e1107a13b --- /dev/null +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts @@ -0,0 +1,380 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +#include + +/ { + model = "Linksys EA8500 WiFi Router"; + compatible = "linksys,ea8500", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + serial0 = &uart4; + mdio-gpio0 = &mdio0; + }; + + chosen { + bootargs = "console=ttyMSM0,115200n8"; + linux,stdout-path = "serial0:115200n8"; + }; + + soc { + pinmux@800000 { + i2c4_pins: i2c4_pinmux { + pins = "gpio12", "gpio13"; + function = "gsbi4"; + bias-disable; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + drive-strength = <10>; + bias-none; + }; + }; + nand_pins: nand_pins { + mux { + pins = "gpio34", "gpio35", "gpio36", + "gpio37", "gpio38", "gpio39", + "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + function = "nand"; + drive-strength = <10>; + bias-disable; + }; + pullups { + pins = "gpio39"; + bias-pull-up; + }; + hold { + pins = "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + bias-bus-hold; + }; + }; + + 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 { + qcom,mode = ; + status = "ok"; + serial@16340000 { + status = "ok"; + }; + /* + * The i2c device on gsbi4 should not be enabled. + * On ipq806x designs gsbi4 i2c is meant for exclusive + * RPM usage. Turning this on in kernel manifests as + * i2c failure for the RPM. + */ + }; + + sata-phy@1b400000 { + status = "ok"; + }; + + sata@29000000 { + status = "ok"; + }; + + phy@100f8800 { /* USB3 port 1 HS phy */ + status = "ok"; + }; + + phy@100f8830 { /* USB3 port 1 SS phy */ + status = "ok"; + }; + + phy@110f8800 { /* USB3 port 0 HS phy */ + status = "ok"; + }; + + phy@110f8830 { /* USB3 port 0 SS phy */ + status = "ok"; + }; + + usb30@0 { + status = "ok"; + }; + + usb30@1 { + status = "ok"; + }; + + pcie0: pci@1b500000 { + status = "ok"; + phy-tx0-term-offset = <7>; + }; + + pcie1: pci@1b700000 { + status = "ok"; + phy-tx0-term-offset = <7>; + }; + + pcie2: pci@1b900000 { + status = "ok"; + phy-tx0-term-offset = <7>; + }; + + nand@1ac00000 { + status = "ok"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + + #address-cells = <1>; + #size-cells = <1>; + + SBL1@0 { + label = "SBL1"; + reg = <0x0000000 0x0040000>; + read-only; + }; + + MIBIB@40000 { + label = "MIBIB"; + reg = <0x0040000 0x0140000>; + read-only; + }; + + SBL2@180000 { + label = "SBL2"; + reg = <0x0180000 0x0140000>; + read-only; + }; + + SBL3@2c0000 { + label = "SBL3"; + reg = <0x02c0000 0x0280000>; + read-only; + }; + + DDRCONFIG@540000 { + label = "DDRCONFIG"; + reg = <0x0540000 0x0120000>; + read-only; + }; + + SSD@660000 { + label = "SSD"; + reg = <0x0660000 0x0120000>; + read-only; + }; + + TZ@780000 { + label = "TZ"; + reg = <0x0780000 0x0280000>; + read-only; + }; + + RPM@a00000 { + label = "RPM"; + reg = <0x0a00000 0x0280000>; + read-only; + }; + + art: art@c80000 { + label = "art"; + reg = <0x0c80000 0x0140000>; + read-only; + }; + + APPSBL@dc0000 { + label = "APPSBL"; + reg = <0x0dc0000 0x0100000>; + read-only; + }; + + u_env@ec0000 { + label = "u_env"; + reg = <0x0ec0000 0x0040000>; + }; + + s_env@f00000 { + label = "s_env"; + reg = <0x0f00000 0x0040000>; + }; + + devinfo@f40000 { + label = "devinfo"; + reg = <0x0f40000 0x0040000>; + }; + + linux@f80000 { + label = "kernel1"; + reg = <0x0f80000 0x2800000>; /* 3 MB spill to rootfs*/ + }; + + rootfs@1280000 { + label = "rootfs1"; + reg = <0x1280000 0x2500000>; + }; + + linux2@3780000 { + label = "kernel2"; + reg = <0x3780000 0x2800000>; + }; + + rootfs2@3a80000 { + label = "rootfs2"; + reg = <0x3a80000 0x2500000>; + }; + + syscfg@5f80000 { + label = "syscfg"; + reg = <0x5f80000 0x2080000>; + }; + + }; + + mdio0: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + 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>; + }; + }; + + 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>; + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + //lan + gmac2: ethernet@37400000 { + status = "ok"; + phy-mode = "sgmii"; + qcom,id = <2>; + qcom,phy_mdio_addr = <0>; /* none */ + qcom,poll_required = <0>; /* no polling */ + qcom,rgmii_delay = <0>; + qcom,emulation = <0>; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + adm_dma: dma@18300000 { + status = "ok"; + }; + + }; + + gpio-keys { + compatible = "gpio-keys"; + + rfkill { + label = "rfkill"; /* WIFI on-off*/ + gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + }; + + gpio-leds { + compatible = "gpio-leds"; + + wps { + label = "ea8500:green:wps"; + gpios = <&qcom_pinmux 53 0>; + default-state = "off"; + }; + + power { + label = "ea8500:white:power"; + gpios = <&qcom_pinmux 6 1>; + default-state = "off"; + linux,default-trigger = "heartbeat"; + }; + + wifi { + label = "ea8500:green:wifi"; + gpios = <&qcom_pinmux 54 0>; + default-state = "off"; + }; + }; +}; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts new file mode 100644 index 000000000000..ca1f612844b9 --- /dev/null +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts @@ -0,0 +1,342 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +#include + +/ { + model = "Netgear Nighthawk X4 R7500"; + compatible = "netgear,r7500", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0xe000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + serial0 = &uart4; + mdio-gpio0 = &mdio0; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + linux,stdout-path = "serial0:115200n8"; + }; + + soc { + pinmux@800000 { + i2c4_pins: i2c4_pinmux { + pins = "gpio12", "gpio13"; + function = "gsbi4"; + bias-disable; + }; + + nand_pins: nand_pins { + mux { + pins = "gpio34", "gpio35", "gpio36", + "gpio37", "gpio38", "gpio39", + "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + function = "nand"; + drive-strength = <10>; + bias-disable; + }; + pullups { + pins = "gpio39"; + bias-pull-up; + }; + hold { + pins = "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + bias-bus-hold; + }; + }; + + 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 { + qcom,mode = ; + status = "ok"; + serial@16340000 { + status = "ok"; + }; + /* + * The i2c device on gsbi4 should not be enabled. + * On ipq806x designs gsbi4 i2c is meant for exclusive + * RPM usage. Turning this on in kernel manifests as + * i2c failure for the RPM. + */ + }; + + sata-phy@1b400000 { + status = "ok"; + }; + + sata@29000000 { + status = "ok"; + }; + + phy@100f8800 { /* USB3 port 1 HS phy */ + status = "ok"; + }; + + phy@100f8830 { /* USB3 port 1 SS phy */ + status = "ok"; + }; + + phy@110f8800 { /* USB3 port 0 HS phy */ + status = "ok"; + }; + + phy@110f8830 { /* USB3 port 0 SS phy */ + status = "ok"; + }; + + usb30@0 { + status = "ok"; + }; + + usb30@1 { + status = "ok"; + }; + + pcie0: pci@1b500000 { + status = "ok"; + }; + + pcie1: pci@1b700000 { + status = "ok"; + }; + + nand@1ac00000 { + status = "ok"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + + #address-cells = <1>; + #size-cells = <1>; + + qcadata@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art: art@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + }; + + kernel@1340000 { + label = "kernel"; + reg = <0x1340000 0x0200000>; + }; + + ubi@1540000 { + label = "ubi"; + reg = <0x1540000 0x1800000>; + }; + + netgear@2d40000 { + label = "netgear"; + reg = <0x2d40000 0x0c00000>; + read-only; + }; + + reserve@3940000 { + label = "reserve"; + reg = <0x3940000 0x46c0000>; + read-only; + }; + + firmware@1340000 { + label = "firmware"; + reg = <0x1340000 0x1a00000>; + }; + + }; + + mdio0: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + 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>; + }; + }; + + gmac1: ethernet@37200000 { + status = "ok"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + mtd-mac-address = <&art 6>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + gmac2: ethernet@37400000 { + status = "ok"; + phy-mode = "sgmii"; + qcom,id = <2>; + + mtd-mac-address = <&art 0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 1>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 1>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 1>; + linux,code = ; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + usb1 { + label = "r7500:amber:usb1"; + gpios = <&qcom_pinmux 7 0>; + }; + + usb3 { + label = "r7500:amber:usb3"; + gpios = <&qcom_pinmux 8 0>; + }; + + status { + label = "r7500:amber:status"; + gpios = <&qcom_pinmux 9 0>; + }; + + internet { + label = "r7500:white:internet"; + gpios = <&qcom_pinmux 22 0>; + }; + + wan { + label = "r7500:white:wan"; + gpios = <&qcom_pinmux 23 0>; + }; + + wps { + label = "r7500:white:wps"; + gpios = <&qcom_pinmux 24 0>; + }; + + esata { + label = "r7500:white:esata"; + gpios = <&qcom_pinmux 26 0>; + }; + + power { + label = "r7500:white:power"; + gpios = <&qcom_pinmux 53 0>; + default-state = "on"; + }; + + rfkill { + label = "r7500:white:rfkill"; + gpios = <&qcom_pinmux 64 0>; + }; + + wifi5g { + label = "r7500:white:wifi5g"; + gpios = <&qcom_pinmux 67 0>; + }; + }; +}; + +&adm_dma { + status = "ok"; +}; diff --git a/target/linux/ipq806x/patches-4.4/800-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch b/target/linux/ipq806x/patches-4.4/800-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch deleted file mode 100644 index 1f5eba8377d2..000000000000 --- a/target/linux/ipq806x/patches-4.4/800-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch +++ /dev/null @@ -1,367 +0,0 @@ -From 7e77aa188a7a7c4391856a9e5ef5ef58f769e679 Mon Sep 17 00:00:00 2001 -From: Jonas Gorski -Date: Sun, 9 Aug 2015 13:02:38 +0200 -Subject: [PATCH] ARM: qcom: add Netgear Nighthawk X4 R7500 device tree - -Signed-off-by: Jonas Gorski ---- - arch/arm/boot/dts/Makefile | 1 + - arch/arm/boot/dts/qcom-ipq8064-r7500.dts | 370 +++++++++++++++++++++++++++++++ - 2 files changed, 371 insertions(+) - create mode 100644 arch/arm/boot/dts/qcom-ipq8064-r7500.dts - ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -452,6 +452,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ - qcom-apq8084-mtp.dtb \ - qcom-ipq8064-ap148.dtb \ - qcom-ipq8064-db149.dtb \ -+ qcom-ipq8064-r7500.dtb \ - qcom-msm8660-surf.dtb \ - qcom-msm8960-cdp.dtb \ - qcom-msm8974-sony-xperia-honami.dtb ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-r7500.dts -@@ -0,0 +1,342 @@ -+#include "qcom-ipq8064-v1.0.dtsi" -+ -+#include -+ -+/ { -+ model = "Netgear Nighthawk X4 R7500"; -+ compatible = "netgear,r7500", "qcom,ipq8064"; -+ -+ memory@0 { -+ reg = <0x42000000 0xe000000>; -+ device_type = "memory"; -+ }; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ rsvd@41200000 { -+ reg = <0x41200000 0x300000>; -+ no-map; -+ }; -+ }; -+ -+ aliases { -+ serial0 = &uart4; -+ mdio-gpio0 = &mdio0; -+ }; -+ -+ chosen { -+ bootargs = "rootfstype=squashfs noinitrd"; -+ linux,stdout-path = "serial0:115200n8"; -+ }; -+ -+ soc { -+ pinmux@800000 { -+ i2c4_pins: i2c4_pinmux { -+ pins = "gpio12", "gpio13"; -+ function = "gsbi4"; -+ bias-disable; -+ }; -+ -+ nand_pins: nand_pins { -+ mux { -+ pins = "gpio34", "gpio35", "gpio36", -+ "gpio37", "gpio38", "gpio39", -+ "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ function = "nand"; -+ drive-strength = <10>; -+ bias-disable; -+ }; -+ pullups { -+ pins = "gpio39"; -+ bias-pull-up; -+ }; -+ hold { -+ pins = "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ bias-bus-hold; -+ }; -+ }; -+ -+ 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 { -+ qcom,mode = ; -+ status = "ok"; -+ serial@16340000 { -+ status = "ok"; -+ }; -+ /* -+ * The i2c device on gsbi4 should not be enabled. -+ * On ipq806x designs gsbi4 i2c is meant for exclusive -+ * RPM usage. Turning this on in kernel manifests as -+ * i2c failure for the RPM. -+ */ -+ }; -+ -+ sata-phy@1b400000 { -+ status = "ok"; -+ }; -+ -+ sata@29000000 { -+ status = "ok"; -+ }; -+ -+ phy@100f8800 { /* USB3 port 1 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@100f8830 { /* USB3 port 1 SS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8800 { /* USB3 port 0 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8830 { /* USB3 port 0 SS phy */ -+ status = "ok"; -+ }; -+ -+ usb30@0 { -+ status = "ok"; -+ }; -+ -+ usb30@1 { -+ status = "ok"; -+ }; -+ -+ pcie0: pci@1b500000 { -+ status = "ok"; -+ }; -+ -+ pcie1: pci@1b700000 { -+ status = "ok"; -+ }; -+ -+ nand@1ac00000 { -+ status = "ok"; -+ -+ pinctrl-0 = <&nand_pins>; -+ pinctrl-names = "default"; -+ -+ nand-ecc-strength = <4>; -+ nand-bus-width = <8>; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ qcadata@0 { -+ label = "qcadata"; -+ reg = <0x0000000 0x0c80000>; -+ read-only; -+ }; -+ -+ APPSBL@c80000 { -+ label = "APPSBL"; -+ reg = <0x0c80000 0x0500000>; -+ read-only; -+ }; -+ -+ APPSBLENV@1180000 { -+ label = "APPSBLENV"; -+ reg = <0x1180000 0x0080000>; -+ read-only; -+ }; -+ -+ art: art@1200000 { -+ label = "art"; -+ reg = <0x1200000 0x0140000>; -+ read-only; -+ }; -+ -+ kernel@1340000 { -+ label = "kernel"; -+ reg = <0x1340000 0x0200000>; -+ }; -+ -+ ubi@1540000 { -+ label = "ubi"; -+ reg = <0x1540000 0x1800000>; -+ }; -+ -+ netgear@2d40000 { -+ label = "netgear"; -+ reg = <0x2d40000 0x0c00000>; -+ read-only; -+ }; -+ -+ reserve@3940000 { -+ label = "reserve"; -+ reg = <0x3940000 0x46c0000>; -+ read-only; -+ }; -+ -+ firmware@1340000 { -+ label = "firmware"; -+ reg = <0x1340000 0x1a00000>; -+ }; -+ -+ }; -+ -+ mdio0: mdio { -+ compatible = "virtual,mdio-gpio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; -+ pinctrl-0 = <&mdio0_pins>; -+ pinctrl-names = "default"; -+ -+ 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>; -+ }; -+ }; -+ -+ gmac1: ethernet@37200000 { -+ status = "ok"; -+ phy-mode = "rgmii"; -+ qcom,id = <1>; -+ -+ pinctrl-0 = <&rgmii2_pins>; -+ pinctrl-names = "default"; -+ -+ mtd-mac-address = <&art 6>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <2>; -+ -+ mtd-mac-address = <&art 0>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ wifi { -+ label = "wifi"; -+ gpios = <&qcom_pinmux 6 1>; -+ linux,code = ; -+ }; -+ -+ reset { -+ label = "reset"; -+ gpios = <&qcom_pinmux 54 1>; -+ linux,code = ; -+ }; -+ -+ wps { -+ label = "wps"; -+ gpios = <&qcom_pinmux 65 1>; -+ linux,code = ; -+ }; -+ }; -+ -+ gpio-leds { -+ compatible = "gpio-leds"; -+ -+ usb1 { -+ label = "r7500:amber:usb1"; -+ gpios = <&qcom_pinmux 7 0>; -+ }; -+ -+ usb3 { -+ label = "r7500:amber:usb3"; -+ gpios = <&qcom_pinmux 8 0>; -+ }; -+ -+ status { -+ label = "r7500:amber:status"; -+ gpios = <&qcom_pinmux 9 0>; -+ }; -+ -+ internet { -+ label = "r7500:white:internet"; -+ gpios = <&qcom_pinmux 22 0>; -+ }; -+ -+ wan { -+ label = "r7500:white:wan"; -+ gpios = <&qcom_pinmux 23 0>; -+ }; -+ -+ wps { -+ label = "r7500:white:wps"; -+ gpios = <&qcom_pinmux 24 0>; -+ }; -+ -+ esata { -+ label = "r7500:white:esata"; -+ gpios = <&qcom_pinmux 26 0>; -+ }; -+ -+ power { -+ label = "r7500:white:power"; -+ gpios = <&qcom_pinmux 53 0>; -+ default-state = "on"; -+ }; -+ -+ rfkill { -+ label = "r7500:white:rfkill"; -+ gpios = <&qcom_pinmux 64 0>; -+ }; -+ -+ wifi5g { -+ label = "r7500:white:wifi5g"; -+ gpios = <&qcom_pinmux 67 0>; -+ }; -+ }; -+}; -+ -+&adm_dma { -+ status = "ok"; -+}; diff --git a/target/linux/ipq806x/patches-4.4/800-devicetree.patch b/target/linux/ipq806x/patches-4.4/800-devicetree.patch new file mode 100644 index 000000000000..fc59837f6655 --- /dev/null +++ b/target/linux/ipq806x/patches-4.4/800-devicetree.patch @@ -0,0 +1,26 @@ +From 7e77aa188a7a7c4391856a9e5ef5ef58f769e679 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sun, 9 Aug 2015 13:02:38 +0200 +Subject: [PATCH] ARM: qcom: add Netgear Nighthawk X4 R7500 device tree + +Signed-off-by: Jonas Gorski +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/qcom-ipq8064-r7500.dts | 370 +++++++++++++++++++++++++++++++ + 2 files changed, 371 insertions(+) + create mode 100644 arch/arm/boot/dts/qcom-ipq8064-r7500.dts + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -506,7 +506,11 @@ + qcom-apq8084-ifc6540.dtb \ + qcom-apq8084-mtp.dtb \ + qcom-ipq8064-ap148.dtb \ ++ qcom-ipq8064-c2600.dtb \ ++ qcom-ipq8064-d7800.dtb \ + qcom-ipq8064-db149.dtb \ ++ qcom-ipq8064-ea8500.dtb \ ++ qcom-ipq8064-r7500.dtb \ + qcom-msm8660-surf.dtb \ + qcom-msm8960-cdp.dtb \ + qcom-msm8974-sony-xperia-honami.dtb diff --git a/target/linux/ipq806x/patches-4.4/801-ARM-qcom-add-Netgear-Nighthawk-X4-D7800-device-tree.patch b/target/linux/ipq806x/patches-4.4/801-ARM-qcom-add-Netgear-Nighthawk-X4-D7800-device-tree.patch deleted file mode 100644 index eaf037f57e78..000000000000 --- a/target/linux/ipq806x/patches-4.4/801-ARM-qcom-add-Netgear-Nighthawk-X4-D7800-device-tree.patch +++ /dev/null @@ -1,381 +0,0 @@ ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -362,6 +362,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ - qcom-ipq8064-ap148.dtb \ - qcom-ipq8064-db149.dtb \ - qcom-ipq8064-r7500.dtb \ -+ qcom-ipq8064-d7800.dtb \ - qcom-msm8660-surf.dtb \ - qcom-msm8960-cdp.dtb \ - qcom-msm8974-sony-xperia-honami.dtb ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-d7800.dts -@@ -0,0 +1,368 @@ -+#include "qcom-ipq8064-v1.0.dtsi" -+ -+#include -+ -+/ { -+ model = "Netgear Nighthawk X4 D7800"; -+ compatible = "netgear,d7800", "qcom,ipq8064"; -+ -+ memory@0 { -+ reg = <0x42000000 0xe000000>; -+ device_type = "memory"; -+ }; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ rsvd@41200000 { -+ reg = <0x41200000 0x300000>; -+ no-map; -+ }; -+ }; -+ -+ aliases { -+ serial0 = &uart4; -+ mdio-gpio0 = &mdio0; -+ }; -+ -+ chosen { -+ bootargs = "rootfstype=squashfs noinitrd"; -+ linux,stdout-path = "serial0:115200n8"; -+ }; -+ -+ soc { -+ pinmux@800000 { -+ i2c4_pins: i2c4_pinmux { -+ pins = "gpio12", "gpio13"; -+ function = "gsbi4"; -+ bias-disable; -+ }; -+ -+ pcie0_pins: pcie0_pinmux { -+ mux { -+ pins = "gpio3"; -+ function = "pcie1_rst"; -+ drive-strength = <12>; -+ bias-disable; -+ }; -+ }; -+ -+ pcie1_pins: pcie1_pinmux { -+ mux { -+ pins = "gpio48"; -+ function = "pcie2_rst"; -+ drive-strength = <12>; -+ bias-disable; -+ }; -+ }; -+ -+ nand_pins: nand_pins { -+ mux { -+ pins = "gpio34", "gpio35", "gpio36", -+ "gpio37", "gpio38", "gpio39", -+ "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ function = "nand"; -+ drive-strength = <10>; -+ bias-disable; -+ }; -+ pullups { -+ pins = "gpio39"; -+ bias-pull-up; -+ }; -+ hold { -+ pins = "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ bias-bus-hold; -+ }; -+ }; -+ -+ 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 { -+ qcom,mode = ; -+ status = "ok"; -+ serial@16340000 { -+ status = "ok"; -+ }; -+ /* -+ * The i2c device on gsbi4 should not be enabled. -+ * On ipq806x designs gsbi4 i2c is meant for exclusive -+ * RPM usage. Turning this on in kernel manifests as -+ * i2c failure for the RPM. -+ */ -+ }; -+ -+ sata-phy@1b400000 { -+ status = "ok"; -+ }; -+ -+ sata@29000000 { -+ status = "ok"; -+ }; -+ -+ phy@100f8800 { /* USB3 port 1 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@100f8830 { /* USB3 port 1 SS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8800 { /* USB3 port 0 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8830 { /* USB3 port 0 SS phy */ -+ status = "ok"; -+ }; -+ -+ usb30@0 { -+ status = "ok"; -+ }; -+ -+ usb30@1 { -+ status = "ok"; -+ }; -+ -+ pcie0: pci@1b500000 { -+ status = "ok"; -+ reset-gpio = <&qcom_pinmux 3 0>; -+ pinctrl-0 = <&pcie0_pins>; -+ pinctrl-names = "default"; -+ }; -+ -+ pcie1: pci@1b700000 { -+ status = "ok"; -+ reset-gpio = <&qcom_pinmux 48 0>; -+ pinctrl-0 = <&pcie1_pins>; -+ pinctrl-names = "default"; -+ }; -+ -+ nand@1ac00000 { -+ status = "ok"; -+ -+ pinctrl-0 = <&nand_pins>; -+ pinctrl-names = "default"; -+ -+ nand-ecc-strength = <4>; -+ nand-bus-width = <8>; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ qcadata@0 { -+ label = "qcadata"; -+ reg = <0x0000000 0x0c80000>; -+ read-only; -+ }; -+ -+ APPSBL@c80000 { -+ label = "APPSBL"; -+ reg = <0x0c80000 0x0500000>; -+ read-only; -+ }; -+ -+ APPSBLENV@1180000 { -+ label = "APPSBLENV"; -+ reg = <0x1180000 0x0080000>; -+ read-only; -+ }; -+ -+ art: art@1200000 { -+ label = "art"; -+ reg = <0x1200000 0x0140000>; -+ read-only; -+ }; -+ -+ artbak: art@1340000 { -+ label = "artbak"; -+ reg = <0x1340000 0x0140000>; -+ read-only; -+ }; -+ -+ kernel@1480000 { -+ label = "kernel"; -+ reg = <0x1480000 0x0200000>; -+ }; -+ -+ ubi@1680000 { -+ label = "ubi"; -+ reg = <0x1680000 0x1E00000>; -+ }; -+ -+ netgear@3480000 { -+ label = "netgear"; -+ reg = <0x3480000 0x4480000>; -+ read-only; -+ }; -+ -+ reserve@7900000 { -+ label = "reserve"; -+ reg = <0x7900000 0x0700000>; -+ read-only; -+ }; -+ -+ firmware@1480000 { -+ label = "firmware"; -+ reg = <0x1480000 0x2000000>; -+ }; -+ -+ }; -+ -+ mdio0: mdio { -+ compatible = "virtual,mdio-gpio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; -+ pinctrl-0 = <&mdio0_pins>; -+ pinctrl-names = "default"; -+ -+ 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>; -+ }; -+ }; -+ -+ gmac1: ethernet@37200000 { -+ status = "ok"; -+ phy-mode = "rgmii"; -+ phy-handle = <&phy4>; -+ qcom,id = <1>; -+ -+ pinctrl-0 = <&rgmii2_pins>; -+ pinctrl-names = "default"; -+ -+ mtd-mac-address = <&art 6>; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <2>; -+ -+ mtd-mac-address = <&art 0>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ wifi { -+ label = "wifi"; -+ gpios = <&qcom_pinmux 6 1>; -+ linux,code = ; -+ }; -+ -+ reset { -+ label = "reset"; -+ gpios = <&qcom_pinmux 54 1>; -+ linux,code = ; -+ }; -+ -+ wps { -+ label = "wps"; -+ gpios = <&qcom_pinmux 65 1>; -+ linux,code = ; -+ }; -+ }; -+ -+ gpio-leds { -+ compatible = "gpio-leds"; -+ -+ usb1 { -+ label = "d7800:amber:usb1"; -+ gpios = <&qcom_pinmux 7 0>; -+ }; -+ -+ usb3 { -+ label = "d7800:amber:usb3"; -+ gpios = <&qcom_pinmux 8 0>; -+ }; -+ -+ status { -+ label = "d7800:amber:status"; -+ gpios = <&qcom_pinmux 9 0>; -+ }; -+ -+ internet { -+ label = "d7800:white:internet"; -+ gpios = <&qcom_pinmux 22 0>; -+ }; -+ -+ wan { -+ label = "d7800:white:wan"; -+ gpios = <&qcom_pinmux 23 0>; -+ }; -+ -+ wps { -+ label = "d7800:white:wps"; -+ gpios = <&qcom_pinmux 24 0>; -+ }; -+ -+ esata { -+ label = "d7800:white:esata"; -+ gpios = <&qcom_pinmux 26 0>; -+ }; -+ -+ power { -+ label = "d7800:white:power"; -+ gpios = <&qcom_pinmux 53 0>; -+ default-state = "on"; -+ }; -+ -+ rfkill { -+ label = "d7800:white:rfkill"; -+ gpios = <&qcom_pinmux 64 0>; -+ }; -+ -+ wifi5g { -+ label = "d7800:white:wifi5g"; -+ gpios = <&qcom_pinmux 67 0>; -+ }; -+ }; -+}; -+ -+&adm_dma { -+ status = "ok"; -+}; diff --git a/target/linux/ipq806x/patches-4.4/802-ARM-qcom-add-TPLink-C2600-device-tree.patch b/target/linux/ipq806x/patches-4.4/802-ARM-qcom-add-TPLink-C2600-device-tree.patch deleted file mode 100644 index 8952f3339d9c..000000000000 --- a/target/linux/ipq806x/patches-4.4/802-ARM-qcom-add-TPLink-C2600-device-tree.patch +++ /dev/null @@ -1,425 +0,0 @@ ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -506,6 +506,7 @@ - qcom-apq8084-ifc6540.dtb \ - qcom-apq8084-mtp.dtb \ - qcom-ipq8064-ap148.dtb \ -+ qcom-ipq8064-c2600.dtb \ - qcom-ipq8064-db149.dtb \ - qcom-ipq8064-r7500.dtb \ - qcom-ipq8064-d7800.dtb \ ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-c2600.dts -@@ -0,0 +1,412 @@ -+#include "qcom-ipq8064-v1.0.dtsi" -+#include -+ -+/ { -+ model = "TP-Link Archer C2600"; -+ compatible = "tplink,c2600", "qcom,ipq8064"; -+ -+ memory@0 { -+ reg = <0x42000000 0x1e000000>; -+ device_type = "memory"; -+ }; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ rsvd@41200000 { -+ reg = <0x41200000 0x300000>; -+ no-map; -+ }; -+ }; -+ -+ aliases { -+ serial0 = &uart4; -+ mdio-gpio0 = &mdio0; -+ }; -+ -+ chosen { -+ linux,stdout-path = "serial0:115200n8"; -+ }; -+ -+ soc { -+ pinmux@800000 { -+ i2c4_pins: i2c4_pinmux { -+ pins = "gpio12", "gpio13"; -+ function = "gsbi4"; -+ bias-disable; -+ }; -+ -+ spi_pins: spi_pins { -+ mux { -+ pins = "gpio18", "gpio19", "gpio21"; -+ function = "gsbi5"; -+ drive-strength = <10>; -+ bias-none; -+ }; -+ }; -+ -+ nand_pins: nand_pins { -+ mux { -+ pins = "gpio34", "gpio35", "gpio36", -+ "gpio37", "gpio38", "gpio39", -+ "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ function = "nand"; -+ drive-strength = <10>; -+ bias-disable; -+ }; -+ -+ pullups { -+ pins = "gpio39"; -+ bias-pull-up; -+ }; -+ -+ hold { -+ pins = "gpio40", "gpio41", "gpio42", -+ "gpio43", "gpio44", "gpio45", -+ "gpio46", "gpio47"; -+ bias-bus-hold; -+ }; -+ }; -+ -+ 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 { -+ qcom,mode = ; -+ status = "ok"; -+ serial@16340000 { -+ status = "ok"; -+ }; -+ /* -+ * The i2c device on gsbi4 should not be enabled. -+ * On ipq806x designs gsbi4 i2c is meant for exclusive -+ * RPM usage. Turning this on in kernel manifests as -+ * i2c failure for the RPM. -+ */ -+ }; -+ -+ gsbi5: gsbi@1a200000 { -+ qcom,mode = ; -+ status = "ok"; -+ -+ spi4: spi@1a280000 { -+ status = "ok"; -+ spi-max-frequency = <50000000>; -+ -+ pinctrl-0 = <&spi_pins>; -+ pinctrl-names = "default"; -+ -+ cs-gpios = <&qcom_pinmux 20 0>; -+ -+ flash: m25p80@0 { -+ compatible = "s25fl256s1"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ spi-max-frequency = <50000000>; -+ reg = <0>; -+ -+ SBL1@0 { -+ label = "SBL1"; -+ reg = <0x0 0x20000>; -+ read-only; -+ }; -+ MIBIB@20000 { -+ label = "MIBIB"; -+ reg = <0x20000 0x20000>; -+ read-only; -+ }; -+ SBL2@40000 { -+ label = "SBL2"; -+ reg = <0x40000 0x20000>; -+ read-only; -+ }; -+ SBL3@60000 { -+ label = "SBL3"; -+ reg = <0x60000 0x30000>; -+ read-only; -+ }; -+ DDRCONFIG@90000 { -+ label = "DDRCONFIG"; -+ reg = <0x90000 0x10000>; -+ read-only; -+ }; -+ SSD@a0000 { -+ label = "SSD"; -+ reg = <0xa0000 0x10000>; -+ read-only; -+ }; -+ TZ@b0000 { -+ label = "TZ"; -+ reg = <0xb0000 0x30000>; -+ read-only; -+ }; -+ RPM@e0000 { -+ label = "RPM"; -+ reg = <0xe0000 0x20000>; -+ read-only; -+ }; -+ fs-uboot@100000 { -+ label = "fs-uboot"; -+ reg = <0x100000 0x70000>; -+ read-only; -+ }; -+ uboot-env@170000 { -+ label = "uboot-env"; -+ reg = <0x170000 0x40000>; -+ read-only; -+ }; -+ radio@1b0000 { -+ label = "radio"; -+ reg = <0x1b0000 0x40000>; -+ read-only; -+ }; -+ os-image@1f0000 { -+ label = "os-image"; -+ reg = <0x1f0000 0x200000>; -+ }; -+ rootfs@3f0000 { -+ label = "rootfs"; -+ reg = <0x3f0000 0x1b00000>; -+ }; -+ defaultmac: default-mac@1ef0000 { -+ label = "default-mac"; -+ reg = <0x1ef0000 0x00200>; -+ read-only; -+ }; -+ pin@1ef0200 { -+ label = "pin"; -+ reg = <0x1ef0200 0x00200>; -+ read-only; -+ }; -+ product-info@1ef0400 { -+ label = "product-info"; -+ reg = <0x1ef0400 0x0fc00>; -+ read-only; -+ }; -+ partition-table@1f00000 { -+ label = "partition-table"; -+ reg = <0x1f00000 0x10000>; -+ read-only; -+ }; -+ soft-version@1f10000 { -+ label = "soft-version"; -+ reg = <0x1f10000 0x10000>; -+ read-only; -+ }; -+ support-list@1f20000 { -+ label = "support-list"; -+ reg = <0x1f20000 0x10000>; -+ read-only; -+ }; -+ profile@1f30000 { -+ label = "profile"; -+ reg = <0x1f30000 0x10000>; -+ read-only; -+ }; -+ default-config@1f40000 { -+ label = "default-config"; -+ reg = <0x1f40000 0x10000>; -+ read-only; -+ }; -+ user-config@1f50000 { -+ label = "user-config"; -+ reg = <0x1f50000 0x40000>; -+ read-only; -+ }; -+ qos-db@1f90000 { -+ label = "qos-db"; -+ reg = <0x1f90000 0x40000>; -+ read-only; -+ }; -+ usb-config@1fd0000 { -+ label = "usb-config"; -+ reg = <0x1fd0000 0x10000>; -+ read-only; -+ }; -+ log@1fe0000 { -+ label = "log"; -+ reg = <0x1fe0000 0x20000>; -+ read-only; -+ }; -+ }; -+ }; -+ }; -+ -+ phy@100f8800 { /* USB3 port 1 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@100f8830 { /* USB3 port 1 SS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8800 { /* USB3 port 0 HS phy */ -+ status = "ok"; -+ }; -+ -+ phy@110f8830 { /* USB3 port 0 SS phy */ -+ status = "ok"; -+ }; -+ -+ usb30@0 { -+ status = "ok"; -+ }; -+ -+ usb30@1 { -+ status = "ok"; -+ }; -+ -+ pcie0: pci@1b500000 { -+ status = "ok"; -+ phy-tx0-term-offset = <7>; -+ }; -+ -+ pcie1: pci@1b700000 { -+ status = "ok"; -+ phy-tx0-term-offset = <7>; -+ }; -+ -+ mdio0: mdio { -+ compatible = "virtual,mdio-gpio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>; -+ pinctrl-0 = <&mdio0_pins>; -+ pinctrl-names = "default"; -+ -+ 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>; -+ }; -+ }; -+ -+ gmac1: ethernet@37200000 { -+ status = "ok"; -+ phy-mode = "rgmii"; -+ qcom,id = <1>; -+ -+ pinctrl-0 = <&rgmii2_pins>; -+ pinctrl-names = "default"; -+ -+ mtd-mac-address = <&defaultmac 0x8>; -+ mtd-mac-address-increment = <1>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ status = "ok"; -+ phy-mode = "sgmii"; -+ qcom,id = <2>; -+ -+ mtd-mac-address = <&defaultmac 0x8>; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ -+ wifi { -+ label = "wifi"; -+ gpios = <&qcom_pinmux 49 1>; -+ linux,code = ; -+ }; -+ -+ reset { -+ label = "reset"; -+ gpios = <&qcom_pinmux 64 1>; -+ linux,code = ; -+ }; -+ -+ wps { -+ label = "wps"; -+ gpios = <&qcom_pinmux 65 1>; -+ linux,code = ; -+ }; -+ ledgeneral { -+ label = "ledgeneral"; -+ gpios = <&qcom_pinmux 16 1>; -+ linux,code = ; -+ }; -+ }; -+ -+ gpio-leds { -+ compatible = "gpio-leds"; -+ -+ lan { -+ label = "lan:blue"; -+ gpios = <&qcom_pinmux 6 0>; -+ }; -+ usb4 { -+ label = "usb_4:blue"; -+ gpios = <&qcom_pinmux 7 0>; -+ }; -+ usb2 { -+ label = "usb_2:blue"; -+ gpios = <&qcom_pinmux 8 0>; -+ }; -+ wps { -+ label = "wps:blue"; -+ gpios = <&qcom_pinmux 9 0>; -+ }; -+ wan_blue { -+ label = "wan:blue"; -+ gpios = <&qcom_pinmux 33 1>; -+ }; -+ status { -+ label = "status:blue"; -+ gpios = <&qcom_pinmux 53 0>; -+ default-state = "on"; -+ }; -+ ledgnr { -+ label = "ledgnr:blue"; -+ gpios = <&qcom_pinmux 66 0>; -+ }; -+ }; -+}; -+ -+&adm_dma { -+ status = "ok"; -+}; From 0e4f0de9ece39df4c44f25aea85a433977e5c1d4 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 9 Jun 2016 21:06:10 +0200 Subject: [PATCH 19/37] ipq806x: add boot mangle patches Signed-off-by: John Crispin --- .../patches-4.4/100-find_active_root.patch | 62 +++++++++++++++++++ .../patches-4.4/169-mangle-bootargs.patch | 39 ++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 target/linux/ipq806x/patches-4.4/100-find_active_root.patch create mode 100644 target/linux/ipq806x/patches-4.4/169-mangle-bootargs.patch diff --git a/target/linux/ipq806x/patches-4.4/100-find_active_root.patch b/target/linux/ipq806x/patches-4.4/100-find_active_root.patch new file mode 100644 index 000000000000..2eb6ba301a9d --- /dev/null +++ b/target/linux/ipq806x/patches-4.4/100-find_active_root.patch @@ -0,0 +1,62 @@ +The WRT1900AC among other Linksys routers uses a dual-firmware layout. +Dynamically rename the active partition to "ubi". + +Signed-off-by: Imre Kaloz + +--- a/drivers/mtd/ofpart.c ++++ b/drivers/mtd/ofpart.c +@@ -25,12 +25,15 @@ static bool node_has_compatible(struct d + return of_get_property(pp, "compatible", NULL); + } + ++static int mangled_rootblock; ++ + static int parse_ofpart_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) + { + struct device_node *mtd_node; + struct device_node *ofpart_node; ++ const char *owrtpart = "ubi"; + const char *partname; + struct device_node *pp; + int nr_parts, i, ret = 0; +@@ -110,9 +113,15 @@ static int parse_ofpart_partitions(struc + (*pparts)[i].offset = of_read_number(reg, a_cells); + (*pparts)[i].size = of_read_number(reg + a_cells, s_cells); + +- partname = of_get_property(pp, "label", &len); +- if (!partname) +- partname = of_get_property(pp, "name", &len); ++ if (mangled_rootblock && (i == mangled_rootblock)) { ++ partname = owrtpart; ++ } else { ++ partname = of_get_property(pp, "label", &len); ++ ++ if (!partname) ++ partname = of_get_property(pp, "name", &len); ++ } ++ + (*pparts)[i].name = partname; + + if (of_get_property(pp, "read-only", &len)) +@@ -215,6 +224,19 @@ static int __init ofpart_parser_init(voi + return 0; + } + ++static int __init active_root(char *str) ++{ ++ get_option(&str, &mangled_rootblock); ++ ++ if (!mangled_rootblock) ++ return 1; ++ ++ return 1; ++} ++ ++__setup("mangled_rootblock=", active_root); ++__setup_param("mglr=", active_root_mglr, active_root, 0); ++ + static void __exit ofpart_parser_exit(void) + { + deregister_mtd_parser(&ofpart_parser); diff --git a/target/linux/ipq806x/patches-4.4/169-mangle-bootargs.patch b/target/linux/ipq806x/patches-4.4/169-mangle-bootargs.patch new file mode 100644 index 000000000000..60e5e81cfcc1 --- /dev/null +++ b/target/linux/ipq806x/patches-4.4/169-mangle-bootargs.patch @@ -0,0 +1,39 @@ +--- a/init/main.c ++++ b/init/main.c +@@ -360,11 +360,36 @@ + { + char *rootdev; + char *rootfs; ++ char *end, *num; ++ int i; + + rootdev = strstr(command_line, "root=/dev/mtdblock"); + + if (rootdev) + strncpy(rootdev, "mangled_rootblock=", 18); ++ ++ else { //find partition number in cases with short format (root=/dev/mtdXX || yy:XX) ++ rootdev = strstr(command_line, "root="); ++ ++ if (rootdev) { ++ end = strchr(rootdev, ' '); ++ end = end ? (end-1) : (strchr(rootdev, 0)-1); ++ num = end; ++ for (i=0; num >= rootdev && *num >= '0' && *num <= '9' ; num--, i++); ++ num++; ++ ++ if (i>0) { ++ strncpy(rootdev, "mglr=", 5); ++ rootdev += 5; ++ memcpy(rootdev, num, i); ++ num += i; ++ while (num < end) { ++ *num = ' '; ++ num++; ++ } ++ } ++ } ++ } + + rootfs = strstr(command_line, "rootfstype"); + From 07f303fb1dd10c9769a988a5ea8966b75e31f2e2 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Wed, 8 Jun 2016 09:50:55 +0300 Subject: [PATCH 20/37] package/devel/gdb-arc: Add target GDB for ARC ARC port of GDB is not yet upstream so we need to use sources from Synopsys GitHub repo. Given Synopys' commitment to upstream ARC support in GDB in the nearest future it might be simpler to add a separate package for ARC GDB instead of patching generic GDB package. This way once ARC GDB stuff gets uptreamed we'll only need to remove that new "gdb-arc" package. Note 1 very minor change in generic gdb package was done - it now depends on !arc (while "gdb-arc" depends on "arc"). Signed-off-by: Alexey Brodkin --- package/devel/gdb-arc/Makefile | 94 +++++++++++++++++++ .../patches/100-no_extern_inline.patch | 32 +++++++ .../gdb-arc/patches/110-no_testsuite.patch | 21 +++++ .../120-fix-compile-flag-mismatch.patch | 11 +++ package/devel/gdb/Makefile | 2 +- 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 package/devel/gdb-arc/Makefile create mode 100644 package/devel/gdb-arc/patches/100-no_extern_inline.patch create mode 100644 package/devel/gdb-arc/patches/110-no_testsuite.patch create mode 100644 package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch diff --git a/package/devel/gdb-arc/Makefile b/package/devel/gdb-arc/Makefile new file mode 100644 index 000000000000..c42b10815089 --- /dev/null +++ b/package/devel/gdb-arc/Makefile @@ -0,0 +1,94 @@ +# +# Copyright (C) 2006-2016 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gdb-arc +PKG_VERSION:=arc-2016.03-gdb +PKG_RELEASE:=1 + +PKG_SOURCE:=gdb-arc-2016.03-gdb.tar.gz +PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/archive/$(PKG_VERSION) +PKG_MD5SUM:=775caaf6385c16f20b6f53c0a2b95f79 + +PKG_BUILD_DIR:=$(BUILD_DIR)/binutils-gdb-arc-2016.03-gdb + +PKG_BUILD_PARALLEL:=1 +PKG_INSTALL:=1 +PKG_LICENSE:=GPL-3.0+ + +include $(INCLUDE_DIR)/package.mk + +define Package/gdb-arc/Default + SECTION:=devel + CATEGORY:=Development + DEPENDS:=+!USE_MUSL:libthread-db +PACKAGE_zlib:zlib @arc + URL:=http://www.gnu.org/software/gdb/ +endef + +define Package/gdb-arc +$(call Package/gdb-arc/Default) + TITLE:=GNU Debugger for ARC + DEPENDS+=+libreadline +libncurses +zlib +endef + +define Package/gdb-arc/description +GDB, the GNU Project debugger, allows you to see what is going on `inside' +another program while it executes -- or what another program was doing at the +moment it crashed. +endef + +define Package/gdbserver-arc +$(call Package/gdb-arc/Default) + TITLE:=Remote server for GNU Debugger +endef + +define Package/gdbserver-arc/description +GDBSERVER is a program that allows you to run GDB on a different machine than the +one which is running the program being debugged. +endef + +# XXX: add --disable-werror to prevent build failure with arm +CONFIGURE_ARGS+= \ + --with-system-readline \ + --without-expat \ + --without-lzma \ + --disable-werror \ + --disable-binutils \ + --disable-ld \ + --disable-gas \ + --disable-sim + +CONFIGURE_VARS+= \ + ac_cv_search_tgetent="$(TARGET_LDFLAGS) -lncurses -lreadline" + +define Build/Compile + +$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \ + DESTDIR="$(PKG_INSTALL_DIR)" \ + CPPFLAGS="$(TARGET_CPPFLAGS)" \ + all +endef + +define Build/Install + $(MAKE) -C $(PKG_BUILD_DIR) \ + DESTDIR="$(PKG_INSTALL_DIR)" \ + CPPFLAGS="$(TARGET_CPPFLAGS)" \ + install-gdb +endef + +define Package/gdb-arc/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gdb $(1)/usr/bin/ +endef + +define Package/gdbserver-arc/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gdbserver $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,gdb-arc)) +$(eval $(call BuildPackage,gdbserver-arc)) diff --git a/package/devel/gdb-arc/patches/100-no_extern_inline.patch b/package/devel/gdb-arc/patches/100-no_extern_inline.patch new file mode 100644 index 000000000000..8c18c6e2e746 --- /dev/null +++ b/package/devel/gdb-arc/patches/100-no_extern_inline.patch @@ -0,0 +1,32 @@ +--- a/sim/common/sim-arange.c ++++ b/sim/common/sim-arange.c +@@ -280,11 +280,7 @@ sim_addr_range_delete (ADDR_RANGE *ar, a + build_search_tree (ar); + } + +-#endif /* DEFINE_NON_INLINE_P */ +- +-#if DEFINE_INLINE_P +- +-SIM_ARANGE_INLINE int ++int + sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr) + { + ADDR_RANGE_TREE *t = ar->range_tree; +@@ -301,4 +297,4 @@ sim_addr_range_hit_p (ADDR_RANGE *ar, ad + return 0; + } + +-#endif /* DEFINE_INLINE_P */ ++#endif /* DEFINE_NON_INLINE_P */ +--- a/sim/common/sim-arange.h ++++ b/sim/common/sim-arange.h +@@ -73,7 +73,7 @@ extern void sim_addr_range_delete (ADDR_ + + /* Return non-zero if ADDR is in range AR, traversing the entire tree. + If no range is specified, that is defined to mean "everything". */ +-SIM_ARANGE_INLINE int ++extern int + sim_addr_range_hit_p (ADDR_RANGE * /*ar*/, address_word /*addr*/); + #define ADDR_RANGE_HIT_P(ar, addr) \ + ((ar)->range_tree == NULL || sim_addr_range_hit_p ((ar), (addr))) diff --git a/package/devel/gdb-arc/patches/110-no_testsuite.patch b/package/devel/gdb-arc/patches/110-no_testsuite.patch new file mode 100644 index 000000000000..1b284ea7675a --- /dev/null +++ b/package/devel/gdb-arc/patches/110-no_testsuite.patch @@ -0,0 +1,21 @@ +--- a/gdb/configure ++++ b/gdb/configure +@@ -870,8 +870,7 @@ MAKEINFOFLAGS + YACC + YFLAGS + XMKMF' +-ac_subdirs_all='testsuite +-gdbtk ++ac_subdirs_all='gdbtk + multi-ice + gdbserver' + +@@ -5610,7 +5610,7 @@ $as_echo "$with_auto_load_safe_path" >&6 + + + +-subdirs="$subdirs testsuite" ++subdirs="$subdirs" + + + # Check whether to support alternative target configurations diff --git a/package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch b/package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch new file mode 100644 index 000000000000..c8b41f264a0c --- /dev/null +++ b/package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch @@ -0,0 +1,11 @@ +--- a/gdb/gdbserver/configure ++++ b/gdb/gdbserver/configure +@@ -2468,7 +2468,7 @@ $as_echo "$as_me: error: \`$ac_var' was + ac_cache_corrupted=: ;; + ,);; + *) +- if test "x$ac_old_val" != "x$ac_new_val"; then ++ if test "`echo x$ac_old_val`" != "`echo x$ac_new_val`"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` diff --git a/package/devel/gdb/Makefile b/package/devel/gdb/Makefile index f6d5fec2ff86..5678b5bb003d 100644 --- a/package/devel/gdb/Makefile +++ b/package/devel/gdb/Makefile @@ -24,7 +24,7 @@ include $(INCLUDE_DIR)/package.mk define Package/gdb/Default SECTION:=devel CATEGORY:=Development - DEPENDS:=+!USE_MUSL:libthread-db +PACKAGE_zlib:zlib + DEPENDS:=+!USE_MUSL:libthread-db +PACKAGE_zlib:zlib @!arc URL:=http://www.gnu.org/software/gdb/ endef From 214ce01065fcc9ba934980ff594626af5eb2c4cc Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Thu, 9 Jun 2016 12:38:34 +0300 Subject: [PATCH 21/37] toolchain/gdb: Use correct folder name for ARC patches Even though ARC tools were released as arc-2016.03 we have a little bit different version name for GDB. That's because both Binutils and GDB come from the same git repo but from different branches (and so different tags). Also removing an extra patch that made its way into release. Signed-off-by: Alexey Brodkin --- .../100-no_extern_inline.patch | 0 .../110-no_testsuite.patch | 0 .../120-fix-compile-flag-mismatch.patch | 0 .../arc-2016.03/200-arc-fix-target-mask.patch | 13 ------------- 4 files changed, 13 deletions(-) rename toolchain/gdb/patches/{arc-2016.03 => arc-2016.03-gdb}/100-no_extern_inline.patch (100%) rename toolchain/gdb/patches/{arc-2016.03 => arc-2016.03-gdb}/110-no_testsuite.patch (100%) rename toolchain/gdb/patches/{arc-2016.03 => arc-2016.03-gdb}/120-fix-compile-flag-mismatch.patch (100%) delete mode 100644 toolchain/gdb/patches/arc-2016.03/200-arc-fix-target-mask.patch diff --git a/toolchain/gdb/patches/arc-2016.03/100-no_extern_inline.patch b/toolchain/gdb/patches/arc-2016.03-gdb/100-no_extern_inline.patch similarity index 100% rename from toolchain/gdb/patches/arc-2016.03/100-no_extern_inline.patch rename to toolchain/gdb/patches/arc-2016.03-gdb/100-no_extern_inline.patch diff --git a/toolchain/gdb/patches/arc-2016.03/110-no_testsuite.patch b/toolchain/gdb/patches/arc-2016.03-gdb/110-no_testsuite.patch similarity index 100% rename from toolchain/gdb/patches/arc-2016.03/110-no_testsuite.patch rename to toolchain/gdb/patches/arc-2016.03-gdb/110-no_testsuite.patch diff --git a/toolchain/gdb/patches/arc-2016.03/120-fix-compile-flag-mismatch.patch b/toolchain/gdb/patches/arc-2016.03-gdb/120-fix-compile-flag-mismatch.patch similarity index 100% rename from toolchain/gdb/patches/arc-2016.03/120-fix-compile-flag-mismatch.patch rename to toolchain/gdb/patches/arc-2016.03-gdb/120-fix-compile-flag-mismatch.patch diff --git a/toolchain/gdb/patches/arc-2016.03/200-arc-fix-target-mask.patch b/toolchain/gdb/patches/arc-2016.03/200-arc-fix-target-mask.patch deleted file mode 100644 index 7e51d588ae22..000000000000 --- a/toolchain/gdb/patches/arc-2016.03/200-arc-fix-target-mask.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/bfd/config.bfd b/bfd/config.bfd -index 5145d4a..a9c9c99 100644 ---- a/bfd/config.bfd -+++ b/bfd/config.bfd -@@ -275,7 +275,7 @@ case "${targ}" in - targ_defvec=am33_elf32_linux_vec - ;; - -- arc*-*-elf* | arc*-*-linux-uclibc*) -+ arc*-*-elf* | arc*-*-linux-*) - targ_defvec=arc_elf32_le_vec - targ_selvecs=arc_elf32_be_vec - ;; From c26d00a9b1a6cb92a1d611e6ab6c52e692f868c0 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 8 Jun 2016 00:22:16 +0200 Subject: [PATCH 22/37] ubox: update to latest git HEAD this adds the new getrandom wrapper tool Signed-off-by: John Crispin --- package/system/ubox/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package/system/ubox/Makefile b/package/system/ubox/Makefile index 61a465300275..1ebcdce7441b 100644 --- a/package/system/ubox/Makefile +++ b/package/system/ubox/Makefile @@ -1,13 +1,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ubox -PKG_VERSION:=2016-06-08 +PKG_VERSION:=2016-06-09 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(LEDE_GIT)/project/ubox.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE_VERSION:=fd4bb41ee7ab136d25609c2a917beea5d52b723b +PKG_SOURCE_VERSION:=fdda69207d1509e0383e3da549f71666b194c40a PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz CMAKE_INSTALL:=1 @@ -36,9 +36,10 @@ define Package/logd endef define Package/ubox/install - $(INSTALL_DIR) $(1)/sbin $(1)/usr/sbin $(1)/lib/ + $(INSTALL_DIR) $(1)/sbin $(1)/usr/sbin $(1)/lib/ $(1)/usr/bin $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{kmodloader,validate_data} $(1)/sbin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/getrandom $(1)/usr/bin/ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libvalidate.so $(1)/lib $(LN) ../../sbin/kmodloader $(1)/usr/sbin/rmmod From 5eea1ddb33e7005308435c89afb19bc4067d477b Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 9 Jun 2016 17:39:05 +0200 Subject: [PATCH 23/37] feeds.conf.default: disable management feed looks like the upstream source packages were un-published. Signed-off-by: John Crispin --- feeds.conf.default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feeds.conf.default b/feeds.conf.default index bb08ab8b0e6e..db7756f73cc3 100644 --- a/feeds.conf.default +++ b/feeds.conf.default @@ -2,7 +2,7 @@ src-git packages https://github.com/openwrt/packages.git src-git luci https://github.com/openwrt/luci.git src-git routing https://github.com/openwrt-routing/packages.git src-git telephony https://github.com/openwrt/telephony.git -src-git management https://github.com/openwrt-management/packages.git src-git targets https://github.com/openwrt/targets.git +#src-git management https://github.com/openwrt-management/packages.git #src-git oldpackages http://git.openwrt.org/packages.git #src-link custom /usr/src/openwrt/custom-feed From 669376ed864a7498e2ecf01ef4d2778e8c52f0e9 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Wed, 2 Dec 2015 21:35:08 +0800 Subject: [PATCH 24/37] ramips: enhance dma engine support * fix compiler error. device_control operation not support now. * add old chips support 8 channels. new chips support 16 channels. * add mt7621 hsdma driver. data sheet says it has two channels. but after test only one channel support. * add memory to memory DMA support. i use dmatest kernel module to verify this function. on rt305x it will copy more data. on mt7621 only two channels can works at the same time. these two chips maybe have hardware bugs. because on other chips don't have these bugs. * use tasklet to handle remaining dma requests. Signed-off-by: Michael Lee --- ...047-DMA-ralink-add-rt2880-dma-engine.patch | 1550 ++++++++++++++--- 1 file changed, 1339 insertions(+), 211 deletions(-) diff --git a/target/linux/ramips/patches-4.4/0047-DMA-ralink-add-rt2880-dma-engine.patch b/target/linux/ramips/patches-4.4/0047-DMA-ralink-add-rt2880-dma-engine.patch index 3362d4b5fcbe..d100a082e772 100644 --- a/target/linux/ramips/patches-4.4/0047-DMA-ralink-add-rt2880-dma-engine.patch +++ b/target/linux/ramips/patches-4.4/0047-DMA-ralink-add-rt2880-dma-engine.patch @@ -14,13 +14,19 @@ Signed-off-by: John Crispin --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig -@@ -40,6 +40,12 @@ config ASYNC_TX_ENABLE_CHANNEL_SWITCH +@@ -40,6 +40,18 @@ config ASYNC_TX_ENABLE_CHANNEL_SWITCH config ARCH_HAS_ASYNC_TX_FIND_CHANNEL bool +config DMA_RALINK + tristate "RALINK DMA support" -+ depends on RALINK && SOC_MT7620 ++ depends on RALINK && !SOC_RT288X ++ select DMA_ENGINE ++ select DMA_VIRTUAL_CHANNELS ++ ++config MTK_HSDMA ++ tristate "MTK HSDMA support" ++ depends on RALINK && SOC_MT7621 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + @@ -29,16 +35,17 @@ Signed-off-by: John Crispin --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile -@@ -65,5 +65,6 @@ obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma- +@@ -65,5 +65,7 @@ obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma- obj-$(CONFIG_TI_EDMA) += edma.o obj-$(CONFIG_XGENE_DMA) += xgene-dma.o obj-$(CONFIG_ZX_DMA) += zx296702_dma.o +obj-$(CONFIG_DMA_RALINK) += ralink-gdma.o ++obj-$(CONFIG_MTK_HSDMA) += mtk-hsdma.o obj-y += xilinx/ --- /dev/null +++ b/drivers/dma/ralink-gdma.c -@@ -0,0 +1,577 @@ +@@ -0,0 +1,928 @@ +/* + * Copyright (C) 2013, Lars-Peter Clausen + * GDMA4740 DMAC support @@ -48,10 +55,6 @@ Signed-off-by: John Crispin + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ * + */ + +#include @@ -65,11 +68,11 @@ Signed-off-by: John Crispin +#include +#include +#include ++#include ++#include + +#include "virt-dma.h" + -+#define GDMA_NR_CHANS 16 -+ +#define GDMA_REG_SRC_ADDR(x) (0x00 + (x) * 0x10) +#define GDMA_REG_DST_ADDR(x) (0x04 + (x) * 0x10) + @@ -84,7 +87,7 @@ Signed-off-by: John Crispin +#define GDMA_REG_CTRL0_BURST_SHIFT 3 +#define GDMA_REG_CTRL0_DONE_INT BIT(2) +#define GDMA_REG_CTRL0_ENABLE BIT(1) -+#define GDMA_REG_CTRL0_HW_MODE 0 ++#define GDMA_REG_CTRL0_SW_MODE BIT(0) + +#define GDMA_REG_CTRL1(x) (0x0c + (x) * 0x10) +#define GDMA_REG_CTRL1_SEG_MASK 0xf @@ -109,16 +112,39 @@ Signed-off-by: John Crispin +#define GDMA_REG_GCT_VER_SHIFT 1 +#define GDMA_REG_GCT_ARBIT_RR BIT(0) + ++#define GDMA_REG_REQSTS 0x2a0 ++#define GDMA_REG_ACKSTS 0x2a4 ++#define GDMA_REG_FINSTS 0x2a8 ++ ++/* for RT305X gdma registers */ ++#define GDMA_RT305X_CTRL0_REQ_MASK 0xf ++#define GDMA_RT305X_CTRL0_SRC_REQ_SHIFT 12 ++#define GDMA_RT305X_CTRL0_DST_REQ_SHIFT 8 ++ ++#define GDMA_RT305X_CTRL1_FAIL BIT(4) ++#define GDMA_RT305X_CTRL1_NEXT_MASK 0x7 ++#define GDMA_RT305X_CTRL1_NEXT_SHIFT 1 ++ ++#define GDMA_RT305X_STATUS_INT 0x80 ++#define GDMA_RT305X_STATUS_SIGNAL 0x84 ++#define GDMA_RT305X_GCT 0x88 ++ ++/* for MT7621 gdma registers */ ++#define GDMA_REG_PERF_START(x) (0x230 + (x) * 0x8) ++#define GDMA_REG_PERF_END(x) (0x234 + (x) * 0x8) ++ +enum gdma_dma_transfer_size { + GDMA_TRANSFER_SIZE_4BYTE = 0, + GDMA_TRANSFER_SIZE_8BYTE = 1, + GDMA_TRANSFER_SIZE_16BYTE = 2, + GDMA_TRANSFER_SIZE_32BYTE = 3, ++ GDMA_TRANSFER_SIZE_64BYTE = 4, +}; + +struct gdma_dma_sg { -+ dma_addr_t addr; -+ unsigned int len; ++ dma_addr_t src_addr; ++ dma_addr_t dst_addr; ++ u32 len; +}; + +struct gdma_dma_desc { @@ -127,6 +153,7 @@ Signed-off-by: John Crispin + enum dma_transfer_direction direction; + bool cyclic; + ++ u32 residue; + unsigned int num_sgs; + struct gdma_dma_sg sg[]; +}; @@ -134,9 +161,10 @@ Signed-off-by: John Crispin +struct gdma_dmaengine_chan { + struct virt_dma_chan vchan; + unsigned int id; ++ unsigned int slave_id; + + dma_addr_t fifo_addr; -+ unsigned int transfer_shift; ++ enum gdma_dma_transfer_size burst_size; + + struct gdma_dma_desc *desc; + unsigned int next_sg; @@ -144,10 +172,22 @@ Signed-off-by: John Crispin + +struct gdma_dma_dev { + struct dma_device ddev; ++ struct device_dma_parameters dma_parms; ++ struct gdma_data *data; + void __iomem *base; -+ struct clk *clk; ++ struct tasklet_struct task; ++ volatile unsigned long chan_issued; ++ atomic_t cnt; ++ ++ struct gdma_dmaengine_chan chan[]; ++}; + -+ struct gdma_dmaengine_chan chan[GDMA_NR_CHANS]; ++struct gdma_data ++{ ++ int chancnt; ++ u32 done_int_reg; ++ void (*init)(struct gdma_dma_dev *dma_dev); ++ int (*start_transfer)(struct gdma_dmaengine_chan *chan); +}; + +static struct gdma_dma_dev *gdma_dma_chan_get_dev( @@ -176,21 +216,9 @@ Signed-off-by: John Crispin +static inline void gdma_dma_write(struct gdma_dma_dev *dma_dev, + unsigned reg, uint32_t val) +{ -+ //printk("gdma --> %p = 0x%08X\n", dma_dev->base + reg, val); + writel(val, dma_dev->base + reg); +} + -+static inline void gdma_dma_write_mask(struct gdma_dma_dev *dma_dev, -+ unsigned int reg, uint32_t val, uint32_t mask) -+{ -+ uint32_t tmp; -+ -+ tmp = gdma_dma_read(dma_dev, reg); -+ tmp &= ~mask; -+ tmp |= val; -+ gdma_dma_write(dma_dev, reg, tmp); -+} -+ +static struct gdma_dma_desc *gdma_dma_alloc_desc(unsigned int num_sgs) +{ + return kzalloc(sizeof(struct gdma_dma_desc) + @@ -199,58 +227,54 @@ Signed-off-by: John Crispin + +static enum gdma_dma_transfer_size gdma_dma_maxburst(u32 maxburst) +{ -+ if (maxburst <= 7) ++ if (maxburst < 2) + return GDMA_TRANSFER_SIZE_4BYTE; -+ else if (maxburst <= 15) ++ else if (maxburst < 4) + return GDMA_TRANSFER_SIZE_8BYTE; -+ else if (maxburst <= 31) ++ else if (maxburst < 8) + return GDMA_TRANSFER_SIZE_16BYTE; -+ -+ return GDMA_TRANSFER_SIZE_32BYTE; ++ else if (maxburst < 16) ++ return GDMA_TRANSFER_SIZE_32BYTE; ++ else ++ return GDMA_TRANSFER_SIZE_64BYTE; +} + -+static int gdma_dma_slave_config(struct dma_chan *c, -+ const struct dma_slave_config *config) ++static int gdma_dma_config(struct dma_chan *c, ++ struct dma_slave_config *config) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); -+ enum gdma_dma_transfer_size transfer_size; -+ uint32_t flags; -+ uint32_t ctrl0, ctrl1; ++ ++ if (config->device_fc) { ++ dev_err(dma_dev->ddev.dev, "not support flow controller\n"); ++ return -EINVAL; ++ } + + switch (config->direction) { + case DMA_MEM_TO_DEV: -+ ctrl1 = 32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT; -+ ctrl1 |= config->slave_id << GDMA_REG_CTRL1_DST_REQ_SHIFT; -+ flags = GDMA_REG_CTRL0_DST_ADDR_FIXED; -+ transfer_size = gdma_dma_maxburst(config->dst_maxburst); ++ if (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { ++ dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); ++ return -EINVAL; ++ } ++ chan->slave_id = config->slave_id; + chan->fifo_addr = config->dst_addr; ++ chan->burst_size = gdma_dma_maxburst(config->dst_maxburst); + break; -+ + case DMA_DEV_TO_MEM: -+ ctrl1 = config->slave_id << GDMA_REG_CTRL1_SRC_REQ_SHIFT; -+ ctrl1 |= 32 << GDMA_REG_CTRL1_DST_REQ_SHIFT; -+ flags = GDMA_REG_CTRL0_SRC_ADDR_FIXED; -+ transfer_size = gdma_dma_maxburst(config->src_maxburst); ++ if (config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { ++ dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); ++ return -EINVAL; ++ } ++ chan->slave_id = config->slave_id; + chan->fifo_addr = config->src_addr; ++ chan->burst_size = gdma_dma_maxburst(config->src_maxburst); + break; -+ + default: ++ dev_err(dma_dev->ddev.dev, "direction type %d error\n", ++ config->direction); + return -EINVAL; + } + -+ chan->transfer_shift = 1 + transfer_size; -+ -+ ctrl0 = flags | GDMA_REG_CTRL0_HW_MODE; -+ ctrl0 |= GDMA_REG_CTRL0_DONE_INT; -+ -+ ctrl1 &= ~(GDMA_REG_CTRL1_NEXT_MASK << GDMA_REG_CTRL1_NEXT_SHIFT); -+ ctrl1 |= chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; -+ ctrl1 |= GDMA_REG_CTRL1_FAIL; -+ ctrl1 &= ~GDMA_REG_CTRL1_CONTINOUS; -+ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); -+ gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); -+ + return 0; +} + @@ -258,108 +282,271 @@ Signed-off-by: John Crispin +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); -+ unsigned long flags; ++ unsigned long flags, timeout; + LIST_HEAD(head); ++ int i = 0; + + spin_lock_irqsave(&chan->vchan.lock, flags); -+ gdma_dma_write_mask(dma_dev, GDMA_REG_CTRL0(chan->id), 0, -+ GDMA_REG_CTRL0_ENABLE); + chan->desc = NULL; ++ clear_bit(chan->id, &dma_dev->chan_issued); + vchan_get_all_descriptors(&chan->vchan, &head); + spin_unlock_irqrestore(&chan->vchan.lock, flags); + + vchan_dma_desc_free_list(&chan->vchan, &head); + ++ /* wait dma transfer complete */ ++ timeout = jiffies + msecs_to_jiffies(5000); ++ while (gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)) & ++ GDMA_REG_CTRL0_ENABLE) { ++ if (time_after_eq(jiffies, timeout)) { ++ dev_err(dma_dev->ddev.dev, "chan %d wait timeout\n", ++ chan->id); ++ /* restore to init value */ ++ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), 0); ++ break; ++ } ++ cpu_relax(); ++ i++; ++ } ++ ++ if (i) ++ dev_dbg(dma_dev->ddev.dev, "terminate chan %d loops %d\n", ++ chan->id, i); ++ + return 0; +} + -+static int gdma_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, -+ unsigned long arg) ++static void rt305x_dump_reg(struct gdma_dma_dev *dma_dev, int id) +{ -+ struct dma_slave_config *config = (struct dma_slave_config *)arg; -+ -+ switch (cmd) { -+ case DMA_SLAVE_CONFIG: -+ return gdma_dma_slave_config(chan, config); -+ case DMA_TERMINATE_ALL: -+ return gdma_dma_terminate_all(chan); -+ default: -+ return -ENOSYS; -+ } ++ dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ ++ "ctr1 %08x, intr %08x, signal %08x\n", id, ++ gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), ++ gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), ++ gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), ++ gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), ++ gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_INT), ++ gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_SIGNAL)); +} + -+static int gdma_dma_start_transfer(struct gdma_dmaengine_chan *chan) ++static int rt305x_gdma_start_transfer(struct gdma_dmaengine_chan *chan) +{ + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + dma_addr_t src_addr, dst_addr; -+ struct virt_dma_desc *vdesc; + struct gdma_dma_sg *sg; ++ uint32_t ctrl0, ctrl1; + -+ gdma_dma_write_mask(dma_dev, GDMA_REG_CTRL0(chan->id), 0, -+ GDMA_REG_CTRL0_ENABLE); ++ /* verify chan is already stopped */ ++ ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); ++ if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { ++ dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", ++ chan->id, ctrl0); ++ rt305x_dump_reg(dma_dev, chan->id); ++ return -EINVAL; ++ } + -+ if (!chan->desc) { -+ vdesc = vchan_next_desc(&chan->vchan); -+ if (!vdesc) -+ return 0; -+ chan->desc = to_gdma_dma_desc(vdesc); -+ chan->next_sg = 0; ++ sg = &chan->desc->sg[chan->next_sg]; ++ if (chan->desc->direction == DMA_MEM_TO_DEV) { ++ src_addr = sg->src_addr; ++ dst_addr = chan->fifo_addr; ++ ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED | \ ++ (8 << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ ++ (chan->slave_id << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); ++ } else if (chan->desc->direction == DMA_DEV_TO_MEM) { ++ src_addr = chan->fifo_addr; ++ dst_addr = sg->dst_addr; ++ ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED | \ ++ (chan->slave_id << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ ++ (8 << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); ++ } else if (chan->desc->direction == DMA_MEM_TO_MEM) { ++ /* ++ * TODO: memcpy function have bugs. sometime it will copy ++ * more 8 bytes data when using dmatest verify. ++ */ ++ src_addr = sg->src_addr; ++ dst_addr = sg->dst_addr; ++ ctrl0 = GDMA_REG_CTRL0_SW_MODE | \ ++ (8 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ ++ (8 << GDMA_REG_CTRL1_DST_REQ_SHIFT); ++ } else { ++ dev_err(dma_dev->ddev.dev, "direction type %d error\n", ++ chan->desc->direction); ++ return -EINVAL; + } + -+ if (chan->next_sg == chan->desc->num_sgs) -+ chan->next_sg = 0; ++ ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ ++ (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ ++ GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; ++ ctrl1 = chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; + -+ sg = &chan->desc->sg[chan->next_sg]; ++ chan->next_sg++; ++ gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); ++ gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); ++ gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); ++ ++ /* make sure next_sg is update */ ++ wmb(); ++ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); + ++ return 0; ++} ++ ++static void rt3883_dump_reg(struct gdma_dma_dev *dma_dev, int id) ++{ ++ dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ ++ "ctr1 %08x, unmask %08x, done %08x, " \ ++ "req %08x, ack %08x, fin %08x\n", id, ++ gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), ++ gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), ++ gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), ++ gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), ++ gdma_dma_read(dma_dev, GDMA_REG_UNMASK_INT), ++ gdma_dma_read(dma_dev, GDMA_REG_DONE_INT), ++ gdma_dma_read(dma_dev, GDMA_REG_REQSTS), ++ gdma_dma_read(dma_dev, GDMA_REG_ACKSTS), ++ gdma_dma_read(dma_dev, GDMA_REG_FINSTS)); ++} ++ ++static int rt3883_gdma_start_transfer(struct gdma_dmaengine_chan *chan) ++{ ++ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); ++ dma_addr_t src_addr, dst_addr; ++ struct gdma_dma_sg *sg; ++ uint32_t ctrl0, ctrl1; ++ ++ /* verify chan is already stopped */ ++ ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); ++ if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { ++ dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", ++ chan->id, ctrl0); ++ rt3883_dump_reg(dma_dev, chan->id); ++ return -EINVAL; ++ } ++ ++ sg = &chan->desc->sg[chan->next_sg]; + if (chan->desc->direction == DMA_MEM_TO_DEV) { -+ src_addr = sg->addr; ++ src_addr = sg->src_addr; + dst_addr = chan->fifo_addr; -+ } else { ++ ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED; ++ ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ ++ (chan->slave_id << GDMA_REG_CTRL1_DST_REQ_SHIFT); ++ } else if (chan->desc->direction == DMA_DEV_TO_MEM) { + src_addr = chan->fifo_addr; -+ dst_addr = sg->addr; ++ dst_addr = sg->dst_addr; ++ ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED; ++ ctrl1 = (chan->slave_id << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ ++ (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ ++ GDMA_REG_CTRL1_COHERENT; ++ } else if (chan->desc->direction == DMA_MEM_TO_MEM) { ++ src_addr = sg->src_addr; ++ dst_addr = sg->dst_addr; ++ ctrl0 = GDMA_REG_CTRL0_SW_MODE; ++ ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ ++ (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ ++ GDMA_REG_CTRL1_COHERENT; ++ } else { ++ dev_err(dma_dev->ddev.dev, "direction type %d error\n", ++ chan->desc->direction); ++ return -EINVAL; + } ++ ++ ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ ++ (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ ++ GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; ++ ctrl1 |= chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; ++ ++ chan->next_sg++; + gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); + gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); -+ gdma_dma_write_mask(dma_dev, GDMA_REG_CTRL0(chan->id), -+ (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | GDMA_REG_CTRL0_ENABLE, -+ GDMA_REG_CTRL0_TX_MASK << GDMA_REG_CTRL0_TX_SHIFT); -+ chan->next_sg++; -+ gdma_dma_write_mask(dma_dev, GDMA_REG_CTRL1(chan->id), 0, GDMA_REG_CTRL1_MASK); ++ gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); ++ ++ /* make sure next_sg is update */ ++ wmb(); ++ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); + + return 0; +} + -+static void gdma_dma_chan_irq(struct gdma_dmaengine_chan *chan) ++static inline int gdma_start_transfer(struct gdma_dma_dev *dma_dev, ++ struct gdma_dmaengine_chan *chan) ++{ ++ return dma_dev->data->start_transfer(chan); ++} ++ ++static int gdma_next_desc(struct gdma_dmaengine_chan *chan) ++{ ++ struct virt_dma_desc *vdesc; ++ ++ vdesc = vchan_next_desc(&chan->vchan); ++ if (!vdesc) { ++ chan->desc = NULL; ++ return 0; ++ } ++ chan->desc = to_gdma_dma_desc(vdesc); ++ chan->next_sg = 0; ++ ++ return 1; ++} ++ ++static void gdma_dma_chan_irq(struct gdma_dma_dev *dma_dev, ++ struct gdma_dmaengine_chan *chan) +{ -+ spin_lock(&chan->vchan.lock); -+ if (chan->desc) { -+ if (chan->desc && chan->desc->cyclic) { -+ vchan_cyclic_callback(&chan->desc->vdesc); ++ struct gdma_dma_desc *desc; ++ unsigned long flags; ++ int chan_issued; ++ ++ chan_issued = 0; ++ spin_lock_irqsave(&chan->vchan.lock, flags); ++ desc = chan->desc; ++ if (desc) { ++ if (desc->cyclic) { ++ vchan_cyclic_callback(&desc->vdesc); ++ if (chan->next_sg == desc->num_sgs) ++ chan->next_sg = 0; ++ chan_issued = 1; + } else { -+ if (chan->next_sg == chan->desc->num_sgs) { -+ chan->desc = NULL; -+ vchan_cookie_complete(&chan->desc->vdesc); -+ } ++ desc->residue -= desc->sg[chan->next_sg - 1].len; ++ if (chan->next_sg == desc->num_sgs) { ++ list_del(&desc->vdesc.node); ++ vchan_cookie_complete(&desc->vdesc); ++ chan_issued = gdma_next_desc(chan); ++ } else ++ chan_issued = 1; + } -+ } -+ gdma_dma_start_transfer(chan); -+ spin_unlock(&chan->vchan.lock); ++ } else ++ dev_dbg(dma_dev->ddev.dev, "chan %d no desc to complete\n", ++ chan->id); ++ if (chan_issued) ++ set_bit(chan->id, &dma_dev->chan_issued); ++ spin_unlock_irqrestore(&chan->vchan.lock, flags); +} + +static irqreturn_t gdma_dma_irq(int irq, void *devid) +{ + struct gdma_dma_dev *dma_dev = devid; -+ uint32_t unmask, done; ++ u32 done, done_reg; + unsigned int i; + -+ unmask = gdma_dma_read(dma_dev, GDMA_REG_UNMASK_INT); -+ gdma_dma_write(dma_dev, GDMA_REG_UNMASK_INT, unmask); -+ done = gdma_dma_read(dma_dev, GDMA_REG_DONE_INT); ++ done_reg = dma_dev->data->done_int_reg; ++ done = gdma_dma_read(dma_dev, done_reg); ++ if (unlikely(!done)) ++ return IRQ_NONE; ++ ++ /* clean done bits */ ++ gdma_dma_write(dma_dev, done_reg, done); + -+ for (i = 0; i < GDMA_NR_CHANS; ++i) -+ if (done & BIT(i)) -+ gdma_dma_chan_irq(&dma_dev->chan[i]); -+ gdma_dma_write(dma_dev, GDMA_REG_DONE_INT, done); ++ i = 0; ++ while (done) { ++ if (done & 0x1) { ++ gdma_dma_chan_irq(dma_dev, &dma_dev->chan[i]); ++ atomic_dec(&dma_dev->cnt); ++ } ++ done >>= 1; ++ i++; ++ } ++ ++ /* start only have work to do */ ++ if (dma_dev->chan_issued) ++ tasklet_schedule(&dma_dev->task); + + return IRQ_HANDLED; +} @@ -367,18 +554,25 @@ Signed-off-by: John Crispin +static void gdma_dma_issue_pending(struct dma_chan *c) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); ++ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + unsigned long flags; + + spin_lock_irqsave(&chan->vchan.lock, flags); -+ if (vchan_issue_pending(&chan->vchan) && !chan->desc) -+ gdma_dma_start_transfer(chan); ++ if (vchan_issue_pending(&chan->vchan) && !chan->desc) { ++ if (gdma_next_desc(chan)) { ++ set_bit(chan->id, &dma_dev->chan_issued); ++ tasklet_schedule(&dma_dev->task); ++ } else ++ dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", ++ chan->id); ++ } + spin_unlock_irqrestore(&chan->vchan.lock, flags); +} + +static struct dma_async_tx_descriptor *gdma_dma_prep_slave_sg( -+ struct dma_chan *c, struct scatterlist *sgl, -+ unsigned int sg_len, enum dma_transfer_direction direction, -+ unsigned long flags, void *context) ++ struct dma_chan *c, struct scatterlist *sgl, ++ unsigned int sg_len, enum dma_transfer_direction direction, ++ unsigned long flags, void *context) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_desc *desc; @@ -386,12 +580,30 @@ Signed-off-by: John Crispin + unsigned int i; + + desc = gdma_dma_alloc_desc(sg_len); -+ if (!desc) ++ if (!desc) { ++ dev_err(c->device->dev, "alloc sg decs error\n"); + return NULL; ++ } ++ desc->residue = 0; + + for_each_sg(sgl, sg, sg_len, i) { -+ desc->sg[i].addr = sg_dma_address(sg); ++ if (direction == DMA_MEM_TO_DEV) ++ desc->sg[i].src_addr = sg_dma_address(sg); ++ else if (direction == DMA_DEV_TO_MEM) ++ desc->sg[i].dst_addr = sg_dma_address(sg); ++ else { ++ dev_err(c->device->dev, "direction type %d error\n", ++ direction); ++ goto free_desc; ++ } ++ ++ if (unlikely(sg_dma_len(sg) > GDMA_REG_CTRL0_TX_MASK)) { ++ dev_err(c->device->dev, "sg len too large %d\n", ++ sg_dma_len(sg)); ++ goto free_desc; ++ } + desc->sg[i].len = sg_dma_len(sg); ++ desc->residue += sg_dma_len(sg); + } + + desc->num_sgs = sg_len; @@ -399,12 +611,60 @@ Signed-off-by: John Crispin + desc->cyclic = false; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); ++ ++free_desc: ++ kfree(desc); ++ return NULL; ++} ++ ++static struct dma_async_tx_descriptor * gdma_dma_prep_dma_memcpy( ++ struct dma_chan *c, dma_addr_t dest, dma_addr_t src, ++ size_t len, unsigned long flags) ++{ ++ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); ++ struct gdma_dma_desc *desc; ++ unsigned int num_periods, i; ++ size_t xfer_count; ++ ++ if (len <= 0) ++ return NULL; ++ ++ chan->burst_size = gdma_dma_maxburst(len >> 2); ++ ++ xfer_count = GDMA_REG_CTRL0_TX_MASK; ++ num_periods = DIV_ROUND_UP(len, xfer_count); ++ ++ desc = gdma_dma_alloc_desc(num_periods); ++ if (!desc) { ++ dev_err(c->device->dev, "alloc memcpy decs error\n"); ++ return NULL; ++ } ++ desc->residue = len; ++ ++ for (i = 0; i < num_periods; i++) { ++ desc->sg[i].src_addr = src; ++ desc->sg[i].dst_addr = dest; ++ if (len > xfer_count) { ++ desc->sg[i].len = xfer_count; ++ } else { ++ desc->sg[i].len = len; ++ } ++ src += desc->sg[i].len; ++ dest += desc->sg[i].len; ++ len -= desc->sg[i].len; ++ } ++ ++ desc->num_sgs = num_periods; ++ desc->direction = DMA_MEM_TO_MEM; ++ desc->cyclic = false; ++ ++ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + +static struct dma_async_tx_descriptor *gdma_dma_prep_dma_cyclic( + struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, -+ unsigned long flags, void *context) ++ unsigned long flags) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_desc *desc; @@ -413,14 +673,30 @@ Signed-off-by: John Crispin + if (buf_len % period_len) + return NULL; + -+ num_periods = buf_len / period_len; ++ if (period_len > GDMA_REG_CTRL0_TX_MASK) { ++ dev_err(c->device->dev, "cyclic len too large %d\n", ++ period_len); ++ return NULL; ++ } + ++ num_periods = buf_len / period_len; + desc = gdma_dma_alloc_desc(num_periods); -+ if (!desc) ++ if (!desc) { ++ dev_err(c->device->dev, "alloc cyclic decs error\n"); + return NULL; ++ } ++ desc->residue = buf_len; + + for (i = 0; i < num_periods; i++) { -+ desc->sg[i].addr = buf_addr; ++ if (direction == DMA_MEM_TO_DEV) ++ desc->sg[i].src_addr = buf_addr; ++ else if (direction == DMA_DEV_TO_MEM) ++ desc->sg[i].dst_addr = buf_addr; ++ else { ++ dev_err(c->device->dev, "direction type %d error\n", ++ direction); ++ goto free_desc; ++ } + desc->sg[i].len = period_len; + buf_addr += period_len; + } @@ -430,28 +706,10 @@ Signed-off-by: John Crispin + desc->cyclic = true; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -+} + -+static size_t gdma_dma_desc_residue(struct gdma_dmaengine_chan *chan, -+ struct gdma_dma_desc *desc, unsigned int next_sg) -+{ -+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); -+ unsigned int residue, count; -+ unsigned int i; -+ -+ residue = 0; -+ -+ for (i = next_sg; i < desc->num_sgs; i++) -+ residue += desc->sg[i].len; -+ -+ if (next_sg != 0) { -+ count = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); -+ count >>= GDMA_REG_CTRL0_CURR_SHIFT; -+ count &= GDMA_REG_CTRL0_CURR_MASK; -+ residue += count << chan->transfer_shift; -+ } -+ -+ return residue; ++free_desc: ++ kfree(desc); ++ return NULL; +} + +static enum dma_status gdma_dma_tx_status(struct dma_chan *c, @@ -461,30 +719,32 @@ Signed-off-by: John Crispin + struct virt_dma_desc *vdesc; + enum dma_status status; + unsigned long flags; ++ struct gdma_dma_desc *desc; + + status = dma_cookie_status(c, cookie, state); -+ if (status == DMA_SUCCESS || !state) ++ if (status == DMA_COMPLETE || !state) + return status; + + spin_lock_irqsave(&chan->vchan.lock, flags); -+ vdesc = vchan_find_desc(&chan->vchan, cookie); -+ if (cookie == chan->desc->vdesc.tx.cookie) { -+ state->residue = gdma_dma_desc_residue(chan, chan->desc, -+ chan->next_sg); -+ } else if (vdesc) { -+ state->residue = gdma_dma_desc_residue(chan, -+ to_gdma_dma_desc(vdesc), 0); -+ } else { -+ state->residue = 0; -+ } ++ desc = chan->desc; ++ if (desc && (cookie == desc->vdesc.tx.cookie)) { ++ /* ++ * We never update edesc->residue in the cyclic case, so we ++ * can tell the remaining room to the end of the circular ++ * buffer. ++ */ ++ if (desc->cyclic) ++ state->residue = desc->residue - ++ ((chan->next_sg - 1) * desc->sg[0].len); ++ else ++ state->residue = desc->residue; ++ } else if ((vdesc = vchan_find_desc(&chan->vchan, cookie))) ++ state->residue = to_gdma_dma_desc(vdesc)->residue; + spin_unlock_irqrestore(&chan->vchan.lock, flags); + -+ return status; -+} ++ dev_dbg(c->device->dev, "tx residue %d bytes\n", state->residue); + -+static int gdma_dma_alloc_chan_resources(struct dma_chan *c) -+{ -+ return 0; ++ return status; +} + +static void gdma_dma_free_chan_resources(struct dma_chan *c) @@ -497,87 +757,192 @@ Signed-off-by: John Crispin + kfree(container_of(vdesc, struct gdma_dma_desc, vdesc)); +} + -+static struct dma_chan * -+of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec, -+ struct of_dma *ofdma) ++static void gdma_dma_tasklet(unsigned long arg) +{ -+ struct gdma_dma_dev *dma_dev = ofdma->of_dma_data; -+ unsigned int request = dma_spec->args[0]; ++ struct gdma_dma_dev *dma_dev = (struct gdma_dma_dev *)arg; ++ struct gdma_dmaengine_chan *chan; ++ static unsigned int last_chan; ++ unsigned int i, chan_mask; ++ ++ /* record last chan to round robin all chans */ ++ i = last_chan; ++ chan_mask = dma_dev->data->chancnt - 1; ++ do { ++ /* ++ * on mt7621. when verify with dmatest with all ++ * channel is enable. we need to limit only two ++ * channel is working at the same time. otherwise the ++ * data will have problem. ++ */ ++ if (atomic_read(&dma_dev->cnt) >= 2) { ++ last_chan = i; ++ break; ++ } + -+ if (request >= GDMA_NR_CHANS) -+ return NULL; ++ if (test_and_clear_bit(i, &dma_dev->chan_issued)) { ++ chan = &dma_dev->chan[i]; ++ if (chan->desc) { ++ atomic_inc(&dma_dev->cnt); ++ gdma_start_transfer(dma_dev, chan); ++ } else ++ dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", chan->id); ++ ++ if (!dma_dev->chan_issued) ++ break; ++ } ++ ++ i = (i + 1) & chan_mask; ++ } while (i != last_chan); ++} ++ ++static void rt305x_gdma_init(struct gdma_dma_dev *dma_dev) ++{ ++ uint32_t gct; ++ ++ /* all chans round robin */ ++ gdma_dma_write(dma_dev, GDMA_RT305X_GCT, GDMA_REG_GCT_ARBIT_RR); + -+ return dma_get_slave_channel(&(dma_dev->chan[request].vchan.chan)); ++ gct = gdma_dma_read(dma_dev, GDMA_RT305X_GCT); ++ dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", ++ (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, ++ 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & ++ GDMA_REG_GCT_CHAN_MASK)); +} + ++static void rt3883_gdma_init(struct gdma_dma_dev *dma_dev) ++{ ++ uint32_t gct; ++ ++ /* all chans round robin */ ++ gdma_dma_write(dma_dev, GDMA_REG_GCT, GDMA_REG_GCT_ARBIT_RR); ++ ++ gct = gdma_dma_read(dma_dev, GDMA_REG_GCT); ++ dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", ++ (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, ++ 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & ++ GDMA_REG_GCT_CHAN_MASK)); ++} ++ ++static struct gdma_data rt305x_gdma_data = { ++ .chancnt = 8, ++ .done_int_reg = GDMA_RT305X_STATUS_INT, ++ .init = rt305x_gdma_init, ++ .start_transfer = rt305x_gdma_start_transfer, ++}; ++ ++static struct gdma_data rt3883_gdma_data = { ++ .chancnt = 16, ++ .done_int_reg = GDMA_REG_DONE_INT, ++ .init = rt3883_gdma_init, ++ .start_transfer = rt3883_gdma_start_transfer, ++}; ++ ++static const struct of_device_id gdma_of_match_table[] = { ++ { .compatible = "ralink,rt305x-gdma", .data = &rt305x_gdma_data }, ++ { .compatible = "ralink,rt3883-gdma", .data = &rt3883_gdma_data }, ++ { }, ++}; ++ +static int gdma_dma_probe(struct platform_device *pdev) +{ ++ const struct of_device_id *match; + struct gdma_dmaengine_chan *chan; + struct gdma_dma_dev *dma_dev; + struct dma_device *dd; + unsigned int i; + struct resource *res; -+ uint32_t gct; + int ret; + int irq; ++ void __iomem *base; ++ struct gdma_data *data; + ++ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); ++ if (ret) ++ return ret; + -+ dma_dev = devm_kzalloc(&pdev->dev, sizeof(*dma_dev), GFP_KERNEL); -+ if (!dma_dev) ++ match = of_match_device(gdma_of_match_table, &pdev->dev); ++ if (!match) + return -EINVAL; ++ data = (struct gdma_data *) match->data; + -+ dd = &dma_dev->ddev; ++ dma_dev = devm_kzalloc(&pdev->dev, sizeof(*dma_dev) + ++ (sizeof(struct gdma_dmaengine_chan) * data->chancnt), ++ GFP_KERNEL); ++ if (!dma_dev) { ++ dev_err(&pdev->dev, "alloc dma device failed\n"); ++ return -EINVAL; ++ } ++ dma_dev->data = data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ dma_dev->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(dma_dev->base)) -+ return PTR_ERR(dma_dev->base); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ dma_dev->base = base; ++ tasklet_init(&dma_dev->task, gdma_dma_tasklet, (unsigned long)dma_dev); ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "failed to get irq\n"); ++ return -EINVAL; ++ } ++ ret = devm_request_irq(&pdev->dev, irq, gdma_dma_irq, ++ 0, dev_name(&pdev->dev), dma_dev); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request irq\n"); ++ return ret; ++ } ++ ++ device_reset(&pdev->dev); + ++ dd = &dma_dev->ddev; ++ dma_cap_set(DMA_MEMCPY, dd->cap_mask); + dma_cap_set(DMA_SLAVE, dd->cap_mask); + dma_cap_set(DMA_CYCLIC, dd->cap_mask); -+ dd->device_alloc_chan_resources = gdma_dma_alloc_chan_resources; + dd->device_free_chan_resources = gdma_dma_free_chan_resources; -+ dd->device_tx_status = gdma_dma_tx_status; -+ dd->device_issue_pending = gdma_dma_issue_pending; ++ dd->device_prep_dma_memcpy = gdma_dma_prep_dma_memcpy; + dd->device_prep_slave_sg = gdma_dma_prep_slave_sg; + dd->device_prep_dma_cyclic = gdma_dma_prep_dma_cyclic; -+ dd->device_control = gdma_dma_control; ++ dd->device_config = gdma_dma_config; ++ dd->device_terminate_all = gdma_dma_terminate_all; ++ dd->device_tx_status = gdma_dma_tx_status; ++ dd->device_issue_pending = gdma_dma_issue_pending; ++ ++ dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); ++ dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); ++ dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); ++ dd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; ++ + dd->dev = &pdev->dev; -+ dd->chancnt = GDMA_NR_CHANS; ++ dd->dev->dma_parms = &dma_dev->dma_parms; ++ dma_set_max_seg_size(dd->dev, GDMA_REG_CTRL0_TX_MASK); + INIT_LIST_HEAD(&dd->channels); + -+ for (i = 0; i < dd->chancnt; i++) { ++ for (i = 0; i < data->chancnt; i++) { + chan = &dma_dev->chan[i]; + chan->id = i; + chan->vchan.desc_free = gdma_dma_desc_free; + vchan_init(&chan->vchan, dd); + } + ++ /* init hardware */ ++ data->init(dma_dev); ++ + ret = dma_async_device_register(dd); -+ if (ret) ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register dma device\n"); + return ret; ++ } + + ret = of_dma_controller_register(pdev->dev.of_node, + of_dma_xlate_by_chan_id, dma_dev); -+ if (ret) -+ goto err_unregister; -+ -+ irq = platform_get_irq(pdev, 0); -+ ret = request_irq(irq, gdma_dma_irq, 0, dev_name(&pdev->dev), dma_dev); -+ if (ret) ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register of dma controller\n"); + goto err_unregister; ++ } + -+ gdma_dma_write(dma_dev, GDMA_REG_UNMASK_INT, 0); -+ gdma_dma_write(dma_dev, GDMA_REG_DONE_INT, BIT(dd->chancnt) - 1); -+ -+ gct = gdma_dma_read(dma_dev, GDMA_REG_GCT); -+ dev_info(&pdev->dev, "revision: %d, channels: %d\n", -+ (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, -+ 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & GDMA_REG_GCT_CHAN_MASK)); + platform_set_drvdata(pdev, dma_dev); + -+ gdma_dma_write(dma_dev, GDMA_REG_GCT, GDMA_REG_GCT_ARBIT_RR); -+ + return 0; + +err_unregister: @@ -588,34 +953,27 @@ Signed-off-by: John Crispin +static int gdma_dma_remove(struct platform_device *pdev) +{ + struct gdma_dma_dev *dma_dev = platform_get_drvdata(pdev); -+ int irq = platform_get_irq(pdev, 0); + -+ free_irq(irq, dma_dev); ++ tasklet_kill(&dma_dev->task); + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&dma_dev->ddev); + + return 0; +} + -+static const struct of_device_id gdma_of_match_table[] = { -+ { .compatible = "ralink,rt2880-gdma" }, -+ { }, -+}; -+ +static struct platform_driver gdma_dma_driver = { + .probe = gdma_dma_probe, + .remove = gdma_dma_remove, + .driver = { + .name = "gdma-rt2880", -+ .owner = THIS_MODULE, + .of_match_table = gdma_of_match_table, + }, +}; +module_platform_driver(gdma_dma_driver); + +MODULE_AUTHOR("Lars-Peter Clausen "); -+MODULE_DESCRIPTION("GDMA4740 DMA driver"); -+MODULE_LICENSE("GPLv2"); ++MODULE_DESCRIPTION("Ralink/MTK DMA driver"); ++MODULE_LICENSE("GPL v2"); --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -496,6 +496,7 @@ static inline void dma_set_unmap(struct @@ -626,3 +984,773 @@ Signed-off-by: John Crispin #else static inline void dma_set_unmap(struct dma_async_tx_descriptor *tx, struct dmaengine_unmap_data *unmap) +--- /dev/null ++++ b/drivers/dma/mtk-hsdma.c +@@ -0,0 +1,767 @@ ++/* ++ * Copyright (C) 2015, Michael Lee ++ * MTK HSDMA support ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "virt-dma.h" ++ ++#define HSDMA_BASE_OFFSET 0x800 ++ ++#define HSDMA_REG_TX_BASE 0x00 ++#define HSDMA_REG_TX_CNT 0x04 ++#define HSDMA_REG_TX_CTX 0x08 ++#define HSDMA_REG_TX_DTX 0x0c ++#define HSDMA_REG_RX_BASE 0x100 ++#define HSDMA_REG_RX_CNT 0x104 ++#define HSDMA_REG_RX_CRX 0x108 ++#define HSDMA_REG_RX_DRX 0x10c ++#define HSDMA_REG_INFO 0x200 ++#define HSDMA_REG_GLO_CFG 0x204 ++#define HSDMA_REG_RST_CFG 0x208 ++#define HSDMA_REG_DELAY_INT 0x20c ++#define HSDMA_REG_FREEQ_THRES 0x210 ++#define HSDMA_REG_INT_STATUS 0x220 ++#define HSDMA_REG_INT_MASK 0x228 ++#define HSDMA_REG_SCH_Q01 0x280 ++#define HSDMA_REG_SCH_Q23 0x284 ++ ++#define HSDMA_DESCS_MAX 0xfff ++#define HSDMA_DESCS_NUM 8 ++#define HSDMA_DESCS_MASK (HSDMA_DESCS_NUM - 1) ++#define HSDMA_NEXT_DESC(x) (((x) + 1) & HSDMA_DESCS_MASK) ++ ++/* HSDMA_REG_INFO */ ++#define HSDMA_INFO_INDEX_MASK 0xf ++#define HSDMA_INFO_INDEX_SHIFT 24 ++#define HSDMA_INFO_BASE_MASK 0xff ++#define HSDMA_INFO_BASE_SHIFT 16 ++#define HSDMA_INFO_RX_MASK 0xff ++#define HSDMA_INFO_RX_SHIFT 8 ++#define HSDMA_INFO_TX_MASK 0xff ++#define HSDMA_INFO_TX_SHIFT 0 ++ ++/* HSDMA_REG_GLO_CFG */ ++#define HSDMA_GLO_TX_2B_OFFSET BIT(31) ++#define HSDMA_GLO_CLK_GATE BIT(30) ++#define HSDMA_GLO_BYTE_SWAP BIT(29) ++#define HSDMA_GLO_MULTI_DMA BIT(10) ++#define HSDMA_GLO_TWO_BUF BIT(9) ++#define HSDMA_GLO_32B_DESC BIT(8) ++#define HSDMA_GLO_BIG_ENDIAN BIT(7) ++#define HSDMA_GLO_TX_DONE BIT(6) ++#define HSDMA_GLO_BT_MASK 0x3 ++#define HSDMA_GLO_BT_SHIFT 4 ++#define HSDMA_GLO_RX_BUSY BIT(3) ++#define HSDMA_GLO_RX_DMA BIT(2) ++#define HSDMA_GLO_TX_BUSY BIT(1) ++#define HSDMA_GLO_TX_DMA BIT(0) ++ ++#define HSDMA_BT_SIZE_16BYTES (0 << HSDMA_GLO_BT_SHIFT) ++#define HSDMA_BT_SIZE_32BYTES (1 << HSDMA_GLO_BT_SHIFT) ++#define HSDMA_BT_SIZE_64BYTES (2 << HSDMA_GLO_BT_SHIFT) ++#define HSDMA_BT_SIZE_128BYTES (3 << HSDMA_GLO_BT_SHIFT) ++ ++#define HSDMA_GLO_DEFAULT (HSDMA_GLO_MULTI_DMA | \ ++ HSDMA_GLO_RX_DMA | HSDMA_GLO_TX_DMA | HSDMA_BT_SIZE_32BYTES) ++ ++/* HSDMA_REG_RST_CFG */ ++#define HSDMA_RST_RX_SHIFT 16 ++#define HSDMA_RST_TX_SHIFT 0 ++ ++/* HSDMA_REG_DELAY_INT */ ++#define HSDMA_DELAY_INT_EN BIT(15) ++#define HSDMA_DELAY_PEND_OFFSET 8 ++#define HSDMA_DELAY_TIME_OFFSET 0 ++#define HSDMA_DELAY_TX_OFFSET 16 ++#define HSDMA_DELAY_RX_OFFSET 0 ++ ++#define HSDMA_DELAY_INIT(x) (HSDMA_DELAY_INT_EN | \ ++ ((x) << HSDMA_DELAY_PEND_OFFSET)) ++#define HSDMA_DELAY(x) ((HSDMA_DELAY_INIT(x) << \ ++ HSDMA_DELAY_TX_OFFSET) | HSDMA_DELAY_INIT(x)) ++ ++/* HSDMA_REG_INT_STATUS */ ++#define HSDMA_INT_DELAY_RX_COH BIT(31) ++#define HSDMA_INT_DELAY_RX_INT BIT(30) ++#define HSDMA_INT_DELAY_TX_COH BIT(29) ++#define HSDMA_INT_DELAY_TX_INT BIT(28) ++#define HSDMA_INT_RX_MASK 0x3 ++#define HSDMA_INT_RX_SHIFT 16 ++#define HSDMA_INT_RX_Q0 BIT(16) ++#define HSDMA_INT_TX_MASK 0xf ++#define HSDMA_INT_TX_SHIFT 0 ++#define HSDMA_INT_TX_Q0 BIT(0) ++ ++/* tx/rx dma desc flags */ ++#define HSDMA_PLEN_MASK 0x3fff ++#define HSDMA_DESC_DONE BIT(31) ++#define HSDMA_DESC_LS0 BIT(30) ++#define HSDMA_DESC_PLEN0(_x) (((_x) & HSDMA_PLEN_MASK) << 16) ++#define HSDMA_DESC_TAG BIT(15) ++#define HSDMA_DESC_LS1 BIT(14) ++#define HSDMA_DESC_PLEN1(_x) ((_x) & HSDMA_PLEN_MASK) ++ ++/* align 4 bytes */ ++#define HSDMA_ALIGN_SIZE 3 ++/* align size 128bytes */ ++#define HSDMA_MAX_PLEN 0x3f80 ++ ++struct hsdma_desc { ++ u32 addr0; ++ u32 flags; ++ u32 addr1; ++ u32 unused; ++}; ++ ++struct mtk_hsdma_sg { ++ dma_addr_t src_addr; ++ dma_addr_t dst_addr; ++ u32 len; ++}; ++ ++struct mtk_hsdma_desc { ++ struct virt_dma_desc vdesc; ++ unsigned int num_sgs; ++ struct mtk_hsdma_sg sg[1]; ++}; ++ ++struct mtk_hsdma_chan { ++ struct virt_dma_chan vchan; ++ unsigned int id; ++ dma_addr_t desc_addr; ++ int tx_idx; ++ int rx_idx; ++ struct hsdma_desc *tx_ring; ++ struct hsdma_desc *rx_ring; ++ struct mtk_hsdma_desc *desc; ++ unsigned int next_sg; ++}; ++ ++struct mtk_hsdam_engine { ++ struct dma_device ddev; ++ struct device_dma_parameters dma_parms; ++ void __iomem *base; ++ struct tasklet_struct task; ++ volatile unsigned long chan_issued; ++ ++ struct mtk_hsdma_chan chan[1]; ++}; ++ ++static inline struct mtk_hsdam_engine *mtk_hsdma_chan_get_dev( ++ struct mtk_hsdma_chan *chan) ++{ ++ return container_of(chan->vchan.chan.device, struct mtk_hsdam_engine, ++ ddev); ++} ++ ++static inline struct mtk_hsdma_chan *to_mtk_hsdma_chan(struct dma_chan *c) ++{ ++ return container_of(c, struct mtk_hsdma_chan, vchan.chan); ++} ++ ++static inline struct mtk_hsdma_desc *to_mtk_hsdma_desc( ++ struct virt_dma_desc *vdesc) ++{ ++ return container_of(vdesc, struct mtk_hsdma_desc, vdesc); ++} ++ ++static inline u32 mtk_hsdma_read(struct mtk_hsdam_engine *hsdma, u32 reg) ++{ ++ return readl(hsdma->base + reg); ++} ++ ++static inline void mtk_hsdma_write(struct mtk_hsdam_engine *hsdma, ++ unsigned reg, u32 val) ++{ ++ writel(val, hsdma->base + reg); ++} ++ ++static void mtk_hsdma_reset_chan(struct mtk_hsdam_engine *hsdma, ++ struct mtk_hsdma_chan *chan) ++{ ++ chan->tx_idx = 0; ++ chan->rx_idx = HSDMA_DESCS_NUM - 1; ++ ++ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CTX, chan->tx_idx); ++ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CRX, chan->rx_idx); ++ ++ mtk_hsdma_write(hsdma, HSDMA_REG_RST_CFG, ++ 0x1 << (chan->id + HSDMA_RST_TX_SHIFT)); ++ mtk_hsdma_write(hsdma, HSDMA_REG_RST_CFG, ++ 0x1 << (chan->id + HSDMA_RST_RX_SHIFT)); ++} ++ ++static void hsdma_dump_reg(struct mtk_hsdam_engine *hsdma) ++{ ++ dev_dbg(hsdma->ddev.dev, "tbase %08x, tcnt %08x, " \ ++ "tctx %08x, tdtx: %08x, rbase %08x, " \ ++ "rcnt %08x, rctx %08x, rdtx %08x\n", ++ mtk_hsdma_read(hsdma, HSDMA_REG_TX_BASE), ++ mtk_hsdma_read(hsdma, HSDMA_REG_TX_CNT), ++ mtk_hsdma_read(hsdma, HSDMA_REG_TX_CTX), ++ mtk_hsdma_read(hsdma, HSDMA_REG_TX_DTX), ++ mtk_hsdma_read(hsdma, HSDMA_REG_RX_BASE), ++ mtk_hsdma_read(hsdma, HSDMA_REG_RX_CNT), ++ mtk_hsdma_read(hsdma, HSDMA_REG_RX_CRX), ++ mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX)); ++ ++ dev_dbg(hsdma->ddev.dev, "info %08x, glo %08x, delay %08x, " \ ++ "intr_stat %08x, intr_mask %08x\n", ++ mtk_hsdma_read(hsdma, HSDMA_REG_INFO), ++ mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG), ++ mtk_hsdma_read(hsdma, HSDMA_REG_DELAY_INT), ++ mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS), ++ mtk_hsdma_read(hsdma, HSDMA_REG_INT_MASK)); ++} ++ ++static void hsdma_dump_desc(struct mtk_hsdam_engine *hsdma, ++ struct mtk_hsdma_chan *chan) ++{ ++ struct hsdma_desc *tx_desc; ++ struct hsdma_desc *rx_desc; ++ int i; ++ ++ dev_dbg(hsdma->ddev.dev, "tx idx: %d, rx idx: %d\n", ++ chan->tx_idx, chan->rx_idx); ++ ++ for (i = 0; i < HSDMA_DESCS_NUM; i++) { ++ tx_desc = &chan->tx_ring[i]; ++ rx_desc = &chan->rx_ring[i]; ++ ++ dev_dbg(hsdma->ddev.dev, "%d tx addr0: %08x, flags %08x, " \ ++ "tx addr1: %08x, rx addr0 %08x, flags %08x\n", ++ i, tx_desc->addr0, tx_desc->flags, \ ++ tx_desc->addr1, rx_desc->addr0, rx_desc->flags); ++ } ++} ++ ++static void mtk_hsdma_reset(struct mtk_hsdam_engine *hsdma, ++ struct mtk_hsdma_chan *chan) ++{ ++ int i; ++ ++ /* disable dma */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, 0); ++ ++ /* disable intr */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, 0); ++ ++ /* init desc value */ ++ for (i = 0; i < HSDMA_DESCS_NUM; i++) { ++ chan->tx_ring[i].addr0 = 0; ++ chan->tx_ring[i].flags = HSDMA_DESC_LS0 | ++ HSDMA_DESC_DONE; ++ } ++ for (i = 0; i < HSDMA_DESCS_NUM; i++) { ++ chan->rx_ring[i].addr0 = 0; ++ chan->rx_ring[i].flags = 0; ++ } ++ ++ /* reset */ ++ mtk_hsdma_reset_chan(hsdma, chan); ++ ++ /* enable intr */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, HSDMA_INT_RX_Q0); ++ ++ /* enable dma */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, HSDMA_GLO_DEFAULT); ++} ++ ++static int mtk_hsdma_terminate_all(struct dma_chan *c) ++{ ++ struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c); ++ struct mtk_hsdam_engine *hsdma = mtk_hsdma_chan_get_dev(chan); ++ unsigned long timeout; ++ LIST_HEAD(head); ++ ++ spin_lock_bh(&chan->vchan.lock); ++ chan->desc = NULL; ++ clear_bit(chan->id, &hsdma->chan_issued); ++ vchan_get_all_descriptors(&chan->vchan, &head); ++ spin_unlock_bh(&chan->vchan.lock); ++ ++ vchan_dma_desc_free_list(&chan->vchan, &head); ++ ++ /* wait dma transfer complete */ ++ timeout = jiffies + msecs_to_jiffies(2000); ++ while (mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG) & ++ (HSDMA_GLO_RX_BUSY | HSDMA_GLO_TX_BUSY)) { ++ if (time_after_eq(jiffies, timeout)) { ++ hsdma_dump_desc(hsdma, chan); ++ mtk_hsdma_reset(hsdma, chan); ++ dev_err(hsdma->ddev.dev, "timeout, reset it\n"); ++ break; ++ } ++ cpu_relax(); ++ } ++ ++ return 0; ++} ++ ++static int mtk_hsdma_start_transfer(struct mtk_hsdam_engine *hsdma, ++ struct mtk_hsdma_chan *chan) ++{ ++ dma_addr_t src, dst; ++ size_t len, tlen; ++ struct hsdma_desc *tx_desc, *rx_desc; ++ struct mtk_hsdma_sg *sg; ++ unsigned int i; ++ int rx_idx; ++ ++ sg = &chan->desc->sg[0]; ++ len = sg->len; ++ chan->desc->num_sgs = DIV_ROUND_UP(len, HSDMA_MAX_PLEN); ++ ++ /* tx desc */ ++ src = sg->src_addr; ++ for (i = 0; i < chan->desc->num_sgs; i++) { ++ if (len > HSDMA_MAX_PLEN) ++ tlen = HSDMA_MAX_PLEN; ++ else ++ tlen = len; ++ ++ if (i & 0x1) { ++ tx_desc->addr1 = src; ++ tx_desc->flags |= HSDMA_DESC_PLEN1(tlen); ++ } else { ++ tx_desc = &chan->tx_ring[chan->tx_idx]; ++ tx_desc->addr0 = src; ++ tx_desc->flags = HSDMA_DESC_PLEN0(tlen); ++ ++ /* update index */ ++ chan->tx_idx = HSDMA_NEXT_DESC(chan->tx_idx); ++ } ++ ++ src += tlen; ++ len -= tlen; ++ } ++ if (i & 0x1) ++ tx_desc->flags |= HSDMA_DESC_LS0; ++ else ++ tx_desc->flags |= HSDMA_DESC_LS1; ++ ++ /* rx desc */ ++ rx_idx = HSDMA_NEXT_DESC(chan->rx_idx); ++ len = sg->len; ++ dst = sg->dst_addr; ++ for (i = 0; i < chan->desc->num_sgs; i++) { ++ rx_desc = &chan->rx_ring[rx_idx]; ++ if (len > HSDMA_MAX_PLEN) ++ tlen = HSDMA_MAX_PLEN; ++ else ++ tlen = len; ++ ++ rx_desc->addr0 = dst; ++ rx_desc->flags = HSDMA_DESC_PLEN0(tlen); ++ ++ dst += tlen; ++ len -= tlen; ++ ++ /* update index */ ++ rx_idx = HSDMA_NEXT_DESC(rx_idx); ++ } ++ ++ /* make sure desc and index all up to date */ ++ wmb(); ++ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CTX, chan->tx_idx); ++ ++ return 0; ++} ++ ++static int gdma_next_desc(struct mtk_hsdma_chan *chan) ++{ ++ struct virt_dma_desc *vdesc; ++ ++ vdesc = vchan_next_desc(&chan->vchan); ++ if (!vdesc) { ++ chan->desc = NULL; ++ return 0; ++ } ++ chan->desc = to_mtk_hsdma_desc(vdesc); ++ chan->next_sg = 0; ++ ++ return 1; ++} ++ ++static void mtk_hsdma_chan_done(struct mtk_hsdam_engine *hsdma, ++ struct mtk_hsdma_chan *chan) ++{ ++ struct mtk_hsdma_desc *desc; ++ int chan_issued; ++ ++ chan_issued = 0; ++ spin_lock_bh(&chan->vchan.lock); ++ desc = chan->desc; ++ if (likely(desc)) { ++ if (chan->next_sg == desc->num_sgs) { ++ list_del(&desc->vdesc.node); ++ vchan_cookie_complete(&desc->vdesc); ++ chan_issued = gdma_next_desc(chan); ++ } ++ } else ++ dev_dbg(hsdma->ddev.dev, "no desc to complete\n"); ++ ++ if (chan_issued) ++ set_bit(chan->id, &hsdma->chan_issued); ++ spin_unlock_bh(&chan->vchan.lock); ++} ++ ++static irqreturn_t mtk_hsdma_irq(int irq, void *devid) ++{ ++ struct mtk_hsdam_engine *hsdma = devid; ++ u32 status; ++ ++ status = mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS); ++ if (unlikely(!status)) ++ return IRQ_NONE; ++ ++ if (likely(status & HSDMA_INT_RX_Q0)) ++ tasklet_schedule(&hsdma->task); ++ else ++ dev_dbg(hsdma->ddev.dev, "unhandle irq status %08x\n", ++ status); ++ /* clean intr bits */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_INT_STATUS, status); ++ ++ return IRQ_HANDLED; ++} ++ ++static void mtk_hsdma_issue_pending(struct dma_chan *c) ++{ ++ struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c); ++ struct mtk_hsdam_engine *hsdma = mtk_hsdma_chan_get_dev(chan); ++ ++ spin_lock_bh(&chan->vchan.lock); ++ if (vchan_issue_pending(&chan->vchan) && !chan->desc) { ++ if (gdma_next_desc(chan)) { ++ set_bit(chan->id, &hsdma->chan_issued); ++ tasklet_schedule(&hsdma->task); ++ } else ++ dev_dbg(hsdma->ddev.dev, "no desc to issue\n"); ++ } ++ spin_unlock_bh(&chan->vchan.lock); ++} ++ ++static struct dma_async_tx_descriptor * mtk_hsdma_prep_dma_memcpy( ++ struct dma_chan *c, dma_addr_t dest, dma_addr_t src, ++ size_t len, unsigned long flags) ++{ ++ struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c); ++ struct mtk_hsdma_desc *desc; ++ ++ if (len <= 0) ++ return NULL; ++ ++ desc = kzalloc(sizeof(struct mtk_hsdma_desc), GFP_ATOMIC); ++ if (!desc) { ++ dev_err(c->device->dev, "alloc memcpy decs error\n"); ++ return NULL; ++ } ++ ++ desc->sg[0].src_addr = src; ++ desc->sg[0].dst_addr = dest; ++ desc->sg[0].len = len; ++ ++ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); ++} ++ ++static enum dma_status mtk_hsdma_tx_status(struct dma_chan *c, ++ dma_cookie_t cookie, struct dma_tx_state *state) ++{ ++ return dma_cookie_status(c, cookie, state); ++} ++ ++static void mtk_hsdma_free_chan_resources(struct dma_chan *c) ++{ ++ vchan_free_chan_resources(to_virt_chan(c)); ++} ++ ++static void mtk_hsdma_desc_free(struct virt_dma_desc *vdesc) ++{ ++ kfree(container_of(vdesc, struct mtk_hsdma_desc, vdesc)); ++} ++ ++static void mtk_hsdma_tx(struct mtk_hsdam_engine *hsdma) ++{ ++ struct mtk_hsdma_chan *chan; ++ ++ if (test_and_clear_bit(0, &hsdma->chan_issued)) { ++ chan = &hsdma->chan[0]; ++ if (chan->desc) { ++ mtk_hsdma_start_transfer(hsdma, chan); ++ } else ++ dev_dbg(hsdma->ddev.dev,"chan 0 no desc to issue\n"); ++ } ++} ++ ++static void mtk_hsdma_rx(struct mtk_hsdam_engine *hsdma) ++{ ++ struct mtk_hsdma_chan *chan; ++ int next_idx, drx_idx, cnt; ++ ++ chan = &hsdma->chan[0]; ++ next_idx = HSDMA_NEXT_DESC(chan->rx_idx); ++ drx_idx = mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX); ++ ++ cnt = (drx_idx - next_idx) & HSDMA_DESCS_MASK; ++ if (!cnt) ++ return; ++ ++ chan->next_sg += cnt; ++ chan->rx_idx = (chan->rx_idx + cnt) & HSDMA_DESCS_MASK; ++ ++ /* update rx crx */ ++ wmb(); ++ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CRX, chan->rx_idx); ++ ++ mtk_hsdma_chan_done(hsdma, chan); ++} ++ ++static void mtk_hsdma_tasklet(unsigned long arg) ++{ ++ struct mtk_hsdam_engine *hsdma = (struct mtk_hsdam_engine *)arg; ++ ++ mtk_hsdma_rx(hsdma); ++ mtk_hsdma_tx(hsdma); ++} ++ ++static int mtk_hsdam_alloc_desc(struct mtk_hsdam_engine *hsdma, ++ struct mtk_hsdma_chan *chan) ++{ ++ int i; ++ ++ chan->tx_ring = dma_alloc_coherent(hsdma->ddev.dev, ++ 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring), ++ &chan->desc_addr, GFP_ATOMIC | __GFP_ZERO); ++ if (!chan->tx_ring) ++ goto no_mem; ++ ++ chan->rx_ring = &chan->tx_ring[HSDMA_DESCS_NUM]; ++ ++ /* init tx ring value */ ++ for (i = 0; i < HSDMA_DESCS_NUM; i++) ++ chan->tx_ring[i].flags = HSDMA_DESC_LS0 | HSDMA_DESC_DONE; ++ ++ return 0; ++no_mem: ++ return -ENOMEM; ++} ++ ++static void mtk_hsdam_free_desc(struct mtk_hsdam_engine *hsdma, ++ struct mtk_hsdma_chan *chan) ++{ ++ if (chan->tx_ring) { ++ dma_free_coherent(hsdma->ddev.dev, ++ 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring), ++ chan->tx_ring, chan->desc_addr); ++ chan->tx_ring = NULL; ++ chan->rx_ring = NULL; ++ } ++} ++ ++static int mtk_hsdma_init(struct mtk_hsdam_engine *hsdma) ++{ ++ struct mtk_hsdma_chan *chan; ++ int ret; ++ u32 reg; ++ ++ /* init desc */ ++ chan = &hsdma->chan[0]; ++ ret = mtk_hsdam_alloc_desc(hsdma, chan); ++ if (ret) ++ return ret; ++ ++ /* tx */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_TX_BASE, chan->desc_addr); ++ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CNT, HSDMA_DESCS_NUM); ++ /* rx */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_RX_BASE, chan->desc_addr + ++ (sizeof(struct hsdma_desc) * HSDMA_DESCS_NUM)); ++ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CNT, HSDMA_DESCS_NUM); ++ /* reset */ ++ mtk_hsdma_reset_chan(hsdma, chan); ++ ++ /* enable rx intr */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, HSDMA_INT_RX_Q0); ++ ++ /* enable dma */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, HSDMA_GLO_DEFAULT); ++ ++ /* hardware info */ ++ reg = mtk_hsdma_read(hsdma, HSDMA_REG_INFO); ++ dev_info(hsdma->ddev.dev, "rx: %d, tx: %d\n", ++ (reg >> HSDMA_INFO_RX_SHIFT) & HSDMA_INFO_RX_MASK, ++ (reg >> HSDMA_INFO_TX_SHIFT) & HSDMA_INFO_TX_MASK); ++ ++ hsdma_dump_reg(hsdma); ++ ++ return ret; ++} ++ ++static void mtk_hsdma_uninit(struct mtk_hsdam_engine *hsdma) ++{ ++ struct mtk_hsdma_chan *chan; ++ ++ /* disable dma */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, 0); ++ ++ /* disable intr */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, 0); ++ ++ /* free desc */ ++ chan = &hsdma->chan[0]; ++ mtk_hsdam_free_desc(hsdma, chan); ++ ++ /* tx */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_TX_BASE, 0); ++ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CNT, 0); ++ /* rx */ ++ mtk_hsdma_write(hsdma, HSDMA_REG_RX_BASE, 0); ++ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CNT, 0); ++ /* reset */ ++ mtk_hsdma_reset_chan(hsdma, chan); ++} ++ ++static const struct of_device_id mtk_hsdma_of_match[] = { ++ { .compatible = "mediatek,mt7621-hsdma" }, ++ { }, ++}; ++ ++static int mtk_hsdma_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *match; ++ struct mtk_hsdma_chan *chan; ++ struct mtk_hsdam_engine *hsdma; ++ struct dma_device *dd; ++ struct resource *res; ++ int ret; ++ int irq; ++ void __iomem *base; ++ ++ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); ++ if (ret) ++ return ret; ++ ++ match = of_match_device(mtk_hsdma_of_match, &pdev->dev); ++ if (!match) ++ return -EINVAL; ++ ++ hsdma = devm_kzalloc(&pdev->dev, sizeof(*hsdma), GFP_KERNEL); ++ if (!hsdma) { ++ dev_err(&pdev->dev, "alloc dma device failed\n"); ++ return -EINVAL; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ hsdma->base = base + HSDMA_BASE_OFFSET; ++ tasklet_init(&hsdma->task, mtk_hsdma_tasklet, (unsigned long)hsdma); ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "failed to get irq\n"); ++ return -EINVAL; ++ } ++ ret = devm_request_irq(&pdev->dev, irq, mtk_hsdma_irq, ++ 0, dev_name(&pdev->dev), hsdma); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request irq\n"); ++ return ret; ++ } ++ ++ device_reset(&pdev->dev); ++ ++ dd = &hsdma->ddev; ++ dma_cap_set(DMA_MEMCPY, dd->cap_mask); ++ dd->copy_align = HSDMA_ALIGN_SIZE; ++ dd->device_free_chan_resources = mtk_hsdma_free_chan_resources; ++ dd->device_prep_dma_memcpy = mtk_hsdma_prep_dma_memcpy; ++ dd->device_terminate_all = mtk_hsdma_terminate_all; ++ dd->device_tx_status = mtk_hsdma_tx_status; ++ dd->device_issue_pending = mtk_hsdma_issue_pending; ++ dd->dev = &pdev->dev; ++ dd->dev->dma_parms = &hsdma->dma_parms; ++ dma_set_max_seg_size(dd->dev, HSDMA_MAX_PLEN); ++ INIT_LIST_HEAD(&dd->channels); ++ ++ chan = &hsdma->chan[0]; ++ chan->id = 0; ++ chan->vchan.desc_free = mtk_hsdma_desc_free; ++ vchan_init(&chan->vchan, dd); ++ ++ /* init hardware */ ++ ret = mtk_hsdma_init(hsdma); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to alloc ring descs\n"); ++ return ret; ++ } ++ ++ ret = dma_async_device_register(dd); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register dma device\n"); ++ return ret; ++ } ++ ++ ret = of_dma_controller_register(pdev->dev.of_node, ++ of_dma_xlate_by_chan_id, hsdma); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register of dma controller\n"); ++ goto err_unregister; ++ } ++ ++ platform_set_drvdata(pdev, hsdma); ++ ++ return 0; ++ ++err_unregister: ++ dma_async_device_unregister(dd); ++ return ret; ++} ++ ++static int mtk_hsdma_remove(struct platform_device *pdev) ++{ ++ struct mtk_hsdam_engine *hsdma = platform_get_drvdata(pdev); ++ ++ mtk_hsdma_uninit(hsdma); ++ ++ of_dma_controller_free(pdev->dev.of_node); ++ dma_async_device_unregister(&hsdma->ddev); ++ ++ return 0; ++} ++ ++static struct platform_driver mtk_hsdma_driver = { ++ .probe = mtk_hsdma_probe, ++ .remove = mtk_hsdma_remove, ++ .driver = { ++ .name = "hsdma-mt7621", ++ .of_match_table = mtk_hsdma_of_match, ++ }, ++}; ++module_platform_driver(mtk_hsdma_driver); ++ ++MODULE_AUTHOR("Michael Lee "); ++MODULE_DESCRIPTION("MTK HSDMA driver"); ++MODULE_LICENSE("GPL v2"); From 816053d45ba98646cea6369d37195b5c57c69faa Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Wed, 2 Dec 2015 21:41:22 +0800 Subject: [PATCH 25/37] ramips: add gdma hsdma dts info Signed-off-by: Michael Lee --- target/linux/ramips/dts/mt7620a.dtsi | 2 +- target/linux/ramips/dts/mt7621.dtsi | 34 +++++++++++++++++++++++++++ target/linux/ramips/dts/mt7628an.dtsi | 2 +- target/linux/ramips/dts/rt3050.dtsi | 17 ++++++++++++++ target/linux/ramips/dts/rt3352.dtsi | 17 ++++++++++++++ target/linux/ramips/dts/rt3883.dtsi | 17 ++++++++++++++ target/linux/ramips/dts/rt5350.dtsi | 17 ++++++++++++++ 7 files changed, 104 insertions(+), 2 deletions(-) diff --git a/target/linux/ramips/dts/mt7620a.dtsi b/target/linux/ramips/dts/mt7620a.dtsi index 101cdac7ab2a..ccadbe40db7a 100644 --- a/target/linux/ramips/dts/mt7620a.dtsi +++ b/target/linux/ramips/dts/mt7620a.dtsi @@ -281,7 +281,7 @@ }; gdma: gdma@2800 { - compatible = "ralink,mt7620a-gdma", "ralink,rt2880-gdma"; + compatible = "ralink,mt7620a-gdma", "ralink,rt3883-gdma"; reg = <0x2800 0x800>; resets = <&rstctrl 14>; diff --git a/target/linux/ramips/dts/mt7621.dtsi b/target/linux/ramips/dts/mt7621.dtsi index 08343a5fd56d..7a9d79a88b93 100644 --- a/target/linux/ramips/dts/mt7621.dtsi +++ b/target/linux/ramips/dts/mt7621.dtsi @@ -144,6 +144,40 @@ m25p,chunked-io = <32>; }; }; + + gdma: gdma@2800 { + compatible = "ralink,rt3883-gdma"; + reg = <0x2800 0x800>; + + resets = <&rstctrl 14>; + reset-names = "dma"; + + interrupt-parent = <&gic>; + interrupts = <0 13 4>; + + #dma-cells = <1>; + #dma-channels = <16>; + #dma-requests = <16>; + + status = "disabled"; + }; + + hsdma: hsdma@7000 { + compatible = "mediatek,mt7621-hsdma"; + reg = <0x7000 0x1000>; + + resets = <&rstctrl 5>; + reset-names = "hsdma"; + + interrupt-parent = <&gic>; + interrupts = <0 11 4>; + + #dma-cells = <1>; + #dma-channels = <1>; + #dma-requests = <1>; + + status = "disabled"; + }; }; pinctrl: pinctrl { diff --git a/target/linux/ramips/dts/mt7628an.dtsi b/target/linux/ramips/dts/mt7628an.dtsi index 0b16a9f60d55..6d5ed95e4971 100644 --- a/target/linux/ramips/dts/mt7628an.dtsi +++ b/target/linux/ramips/dts/mt7628an.dtsi @@ -249,7 +249,7 @@ }; gdma: gdma@2800 { - compatible = "ralink,mt7620a-gdma", "ralink,rt2880-gdma"; + compatible = "ralink,rt3883-gdma"; reg = <0x2800 0x800>; resets = <&rstctrl 14>; diff --git a/target/linux/ramips/dts/rt3050.dtsi b/target/linux/ramips/dts/rt3050.dtsi index caf448bd160c..ed88ac12ec3b 100644 --- a/target/linux/ramips/dts/rt3050.dtsi +++ b/target/linux/ramips/dts/rt3050.dtsi @@ -149,6 +149,23 @@ status = "disabled"; }; + gdma: gdma@700 { + compatible = "ralink,rt305x-gdma"; + reg = <0x700 0x100>; + + resets = <&rstctrl 14>; + reset-names = "dma"; + + interrupt-parent = <&intc>; + interrupts = <7>; + + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <8>; + + status = "disabled"; + }; + spi0: spi@b00 { compatible = "ralink,rt3050-spi", "ralink,rt2880-spi"; reg = <0xb00 0x100>; diff --git a/target/linux/ramips/dts/rt3352.dtsi b/target/linux/ramips/dts/rt3352.dtsi index 0f64576b1eaf..0bb28ec83330 100644 --- a/target/linux/ramips/dts/rt3352.dtsi +++ b/target/linux/ramips/dts/rt3352.dtsi @@ -191,6 +191,23 @@ pinctrl-names = "default"; pinctrl-0 = <&uartlite_pins>; }; + + gdma: gdma@2800 { + compatible = "ralink,rt3883-gdma"; + reg = <0x2800 0x800>; + + resets = <&rstctrl 14>; + reset-names = "dma"; + + interrupt-parent = <&intc>; + interrupts = <7>; + + #dma-cells = <1>; + #dma-channels = <16>; + #dma-requests = <16>; + + status = "disabled"; + }; }; pinctrl: pinctrl { diff --git a/target/linux/ramips/dts/rt3883.dtsi b/target/linux/ramips/dts/rt3883.dtsi index d92cb65b7ad9..041b0633d3f4 100644 --- a/target/linux/ramips/dts/rt3883.dtsi +++ b/target/linux/ramips/dts/rt3883.dtsi @@ -211,6 +211,23 @@ pinctrl-names = "default"; pinctrl-0 = <&uartlite_pins>; }; + + gdma: gdma@2800 { + compatible = "ralink,rt3883-gdma"; + reg = <0x2800 0x800>; + + resets = <&rstctrl 14>; + reset-names = "dma"; + + interrupt-parent = <&intc>; + interrupts = <7>; + + #dma-cells = <1>; + #dma-channels = <16>; + #dma-requests = <16>; + + status = "disabled"; + }; }; pinctrl: pinctrl { diff --git a/target/linux/ramips/dts/rt5350.dtsi b/target/linux/ramips/dts/rt5350.dtsi index 05dce6d3e014..1027519c9826 100644 --- a/target/linux/ramips/dts/rt5350.dtsi +++ b/target/linux/ramips/dts/rt5350.dtsi @@ -208,6 +208,23 @@ interrupt-parent = <&cpuintc>; interrupts = <7>; }; + + gdma: gdma@2800 { + compatible = "ralink,rt3883-gdma"; + reg = <0x2800 0x800>; + + resets = <&rstctrl 14>; + reset-names = "dma"; + + interrupt-parent = <&intc>; + interrupts = <7>; + + #dma-cells = <1>; + #dma-channels = <16>; + #dma-requests = <16>; + + status = "disabled"; + }; }; pinctrl: pinctrl { From 4e1a8bc048e644b4ae34a3f70d964d8bc0a039fd Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 7 Jan 2016 21:50:24 +0800 Subject: [PATCH 26/37] ramips: update i2c drivers * add rt_i2c structure to store driver data * rewrite read/write check function and add i2c error status check. so we don't need to wait until time out. * add 10 bits address support. according to the data sheet i think it is possible. but i haven't verify it. * the most important is start transfer only need once. otherwise it cause I2C_STARTERR status. * add set i2c clock speed register by dts options "clock-frequency". not just hard code it. * add mt7621 i2c driver. i just copy i2c-ralink.c and change register names. and the hardware don't support error status. so i remove it. but the logic is the same. Signed-off-by: Michael Lee --- ...0044-i2c-MIPS-adds-ralink-I2C-driver.patch | 441 ++++++++------ .../0045-i2c-add-mt7621-driver.patch | 541 +++++++++++------- 2 files changed, 611 insertions(+), 371 deletions(-) diff --git a/target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch b/target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch index 31854eff4bce..21872082dd01 100644 --- a/target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch +++ b/target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch @@ -45,12 +45,13 @@ Signed-off-by: John Crispin +}; --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig -@@ -806,6 +806,10 @@ config I2C_RK3X +@@ -806,6 +806,11 @@ config I2C_RK3X This driver can also be built as a module. If so, the module will be called i2c-rk3x. +config I2C_RALINK + tristate "Ralink I2C Controller" ++ depends on RALINK && !SOC_MT7621 + select OF_I2C + config HAVE_S3C2410_I2C @@ -68,11 +69,12 @@ Signed-off-by: John Crispin obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o --- /dev/null +++ b/drivers/i2c/busses/i2c-ralink.c -@@ -0,0 +1,327 @@ +@@ -0,0 +1,435 @@ +/* + * drivers/i2c/busses/i2c-ralink.c + * + * Copyright (C) 2013 Steven Liu ++ * Copyright (C) 2016 Michael Lee + * + * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. + * (C) 2014 Sittisak @@ -101,8 +103,7 @@ Signed-off-by: John Crispin +#include +#include +#include -+ -+#include ++#include + +#define REG_CONFIG_REG 0x00 +#define REG_CLKDIV_REG 0x04 @@ -113,191 +114,250 @@ Signed-off-by: John Crispin +#define REG_STATUS_REG 0x18 +#define REG_STARTXFR_REG 0x1C +#define REG_BYTECNT_REG 0x20 -+#define REG_SM0CFG2 0x28 -+#define REG_SM0CTL0 0x40 + ++/* REG_CONFIG_REG */ ++#define I2C_ADDRLEN_OFFSET 5 ++#define I2C_DEVADLEN_OFFSET 2 ++#define I2C_ADDRLEN_MASK 0x3 ++#define I2C_ADDR_DIS BIT(1) ++#define I2C_DEVADDR_DIS BIT(0) ++#define I2C_ADDRLEN_8 (7 << I2C_ADDRLEN_OFFSET) ++#define I2C_DEVADLEN_7 (6 << I2C_DEVADLEN_OFFSET) ++#define I2C_CONF_DEFAULT (I2C_ADDRLEN_8 | I2C_DEVADLEN_7) ++ ++/* REG_CLKDIV_REG */ ++#define I2C_CLKDIV_MASK 0xffff ++ ++/* REG_DEVADDR_REG */ ++#define I2C_DEVADDR_MASK 0x7f ++ ++/* REG_ADDR_REG */ ++#define I2C_ADDR_MASK 0xff ++ ++/* REG_STATUS_REG */ +#define I2C_STARTERR BIT(4) +#define I2C_ACKERR BIT(3) +#define I2C_DATARDY BIT(2) +#define I2C_SDOEMPTY BIT(1) +#define I2C_BUSY BIT(0) + -+#define I2C_DEVADLEN_7 (6 << 2) -+#define I2C_ADDRDIS BIT(1) ++/* REG_STARTXFR_REG */ ++#define NOSTOP_CMD BIT(2) ++#define NODATA_CMD BIT(1) ++#define READ_CMD BIT(0) + -+#define CLKDIV_VALUE 200 // clock rate is 40M, 40M / (200*2) = 100k (standard i2c bus rate). -+//#define CLKDIV_VALUE 50 // clock rate is 40M, 40M / (50*2) = 400k (fast i2c bus rate). -+ -+#define READ_CMD 0x01 -+#define WRITE_CMD 0x00 -+#define READ_BLOCK 64 -+ -+#define SM0CTL0_OD BIT(31) -+#define SM0CTL0_VTRIG BIT(28) -+#define SM0CTL0_OUTHI BIT(6) -+#define SM0CTL0_STRETCH BIT(1) -+#define SM0CTL0_DEFAULT (SM0CTL0_OD | SM0CTL0_VTRIG | SM0CTL0_OUTHI | SM0CTL0_STRETCH) ++/* REG_BYTECNT_REG */ ++#define BYTECNT_MAX 64 ++#define SET_BYTECNT(x) (x - 1) + +/* timeout waiting for I2C devices to respond (clock streching) */ -+#define RT_I2C_TIMEOUT (msecs_to_jiffies(1000)) -+ -+enum { -+ I2C_TYPE_RALINK, -+ I2C_TYPE_MEDIATEK, ++#define TIMEOUT_MS 1000 ++#define DELAY_INTERVAL_US 100 ++ ++struct rt_i2c { ++ void __iomem *base; ++ struct clk *clk; ++ struct device *dev; ++ struct i2c_adapter adap; ++ u32 cur_clk; ++ u32 clk_div; ++ u32 flags; +}; + -+static void __iomem *membase; -+static struct i2c_adapter *adapter; -+static int hw_type; -+ -+static void rt_i2c_w32(u32 val, unsigned reg) ++static void rt_i2c_w32(struct rt_i2c *i2c, u32 val, unsigned reg) +{ -+ iowrite32(val, membase + reg); ++ iowrite32(val, i2c->base + reg); +} + -+static u32 rt_i2c_r32(unsigned reg) ++static u32 rt_i2c_r32(struct rt_i2c *i2c, unsigned reg) +{ -+ return ioread32(membase + reg); ++ return ioread32(i2c->base + reg); +} + -+static inline int rt_i2c_get_ack(void) ++static int poll_down_timeout(void __iomem *addr, u32 mask) +{ -+ return (rt_i2c_r32(REG_STATUS_REG) & I2C_ACKERR) ? -EIO : 0; -+} -+ -+static inline int rt_i2c_wait_rx_done(void) -+{ -+ unsigned long timeout; -+ -+ timeout = jiffies + RT_I2C_TIMEOUT; ++ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); + + do { -+ if (time_after(jiffies, timeout)) -+ return (-ETIMEDOUT); ++ if (!(readl_relaxed(addr) & mask)) ++ return 0; + -+ } while (!(rt_i2c_r32(REG_STATUS_REG) & I2C_DATARDY)); ++ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); ++ } while (time_before(jiffies, timeout)); + -+ return 0; ++ return (readl_relaxed(addr) & mask) ? -EAGAIN : 0; +} + -+static inline int rt_i2c_wait_idle(void) ++static int rt_i2c_wait_idle(struct rt_i2c *i2c) +{ -+ unsigned long timeout; ++ int ret; + -+ timeout = jiffies + RT_I2C_TIMEOUT; ++ ret = poll_down_timeout(i2c->base + REG_STATUS_REG, I2C_BUSY); ++ if (ret < 0) ++ dev_dbg(i2c->dev, "idle err(%d)\n", ret); + -+ do { -+ if (time_after(jiffies, timeout)) { -+ printk("i2c-read line busy\n"); -+ return 1; -+ } -+ } while (rt_i2c_r32(REG_STATUS_REG) & I2C_BUSY); -+ -+ return 0; ++ return ret; +} + -+static inline int rt_i2c_wait_tx_done(void) ++static int poll_up_timeout(void __iomem *addr, u32 mask) +{ -+ unsigned long timeout; -+ -+ timeout = jiffies + RT_I2C_TIMEOUT; ++ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); ++ u32 status; + + do { -+ if (time_after(jiffies, timeout)) -+ return (-ETIMEDOUT); ++ status = readl_relaxed(addr); + -+ } while (!(rt_i2c_r32(REG_STATUS_REG) & I2C_SDOEMPTY)); ++ /* check error status */ ++ if (status & I2C_STARTERR) ++ return -EAGAIN; ++ else if (status & I2C_ACKERR) ++ return -ENXIO; ++ else if (status & mask) ++ return 0; + -+ return 0; ++ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); ++ } while (time_before(jiffies, timeout)); ++ ++ return -ETIMEDOUT; +} + -+static int rt_i2c_handle_msg(struct i2c_adapter *a, struct i2c_msg* msg) ++static int rt_i2c_wait_rx_done(struct rt_i2c *i2c) +{ -+ int i = 0, j = 0, pos = 0; -+ int nblock = msg->len / READ_BLOCK; -+ int rem = msg->len % READ_BLOCK; -+ int ret = 0; -+ -+ if (msg->flags & I2C_M_TEN) { -+ printk("10 bits addr not supported\n"); -+ return -EINVAL; -+ } -+ -+ if (msg->flags & I2C_M_RD) { -+ for (i = 0; i < nblock; i++) { -+ if (rt_i2c_wait_idle()) -+ return -ETIMEDOUT; -+ rt_i2c_w32(READ_BLOCK - 1, REG_BYTECNT_REG); -+ rt_i2c_w32(READ_CMD, REG_STARTXFR_REG); -+ for (j = 0; j < READ_BLOCK; j++) { -+ if (rt_i2c_wait_rx_done() < 0) -+ ret = rt_i2c_wait_rx_done(); -+ if (rt_i2c_get_ack() < 0) -+ ret = rt_i2c_get_ack(); -+ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); -+ } -+ } -+ -+ if (rt_i2c_wait_idle()) -+ return -ETIMEDOUT; -+ if (rem) { -+ rt_i2c_w32(rem - 1, REG_BYTECNT_REG); -+ rt_i2c_w32(READ_CMD, REG_STARTXFR_REG); -+ } -+ for (i = 0; i < rem; i++) { -+ if (rt_i2c_wait_rx_done() < 0) -+ ret = rt_i2c_wait_rx_done(); -+ if (rt_i2c_get_ack() < 0) -+ ret = rt_i2c_get_ack(); ++ int ret; + -+ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); -+ } -+ } else { -+ if (rt_i2c_wait_idle()) -+ return -ETIMEDOUT; -+ rt_i2c_w32(msg->len - 1, REG_BYTECNT_REG); -+ for (i = 0; i < msg->len; i++) { -+ rt_i2c_w32(msg->buf[i], REG_DATAOUT_REG); -+ rt_i2c_w32(WRITE_CMD, REG_STARTXFR_REG); -+ -+ if (rt_i2c_wait_tx_done() < 0) -+ ret = rt_i2c_wait_tx_done(); -+ if (rt_i2c_get_ack() < 0) -+ ret = rt_i2c_get_ack(); -+ } -+ } ++ ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_DATARDY); ++ if (ret < 0) ++ dev_dbg(i2c->dev, "rx err(%d)\n", ret); + + return ret; +} + -+static int rt_i2c_master_xfer(struct i2c_adapter *a, struct i2c_msg *m, int n) ++static int rt_i2c_wait_tx_done(struct rt_i2c *i2c) +{ -+ int i = 0; -+ int ret = 0; ++ int ret; + -+ if (rt_i2c_wait_idle()) -+ return -ETIMEDOUT; ++ ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_SDOEMPTY); ++ if (ret < 0) ++ dev_dbg(i2c->dev, "tx err(%d)\n", ret); + -+ device_reset(a->dev.parent); ++ return ret; ++} + -+ rt_i2c_w32(m->addr, REG_DEVADDR_REG); -+ rt_i2c_w32(I2C_DEVADLEN_7 | I2C_ADDRDIS, REG_CONFIG_REG); -+ if (hw_type == I2C_TYPE_RALINK) { -+ rt_i2c_w32(CLKDIV_VALUE, REG_CLKDIV_REG); -+ } else { -+ rt_i2c_w32((CLKDIV_VALUE << 16) | SM0CTL0_DEFAULT, REG_SM0CTL0); -+ rt_i2c_w32(1, REG_SM0CFG2); -+ } ++static void rt_i2c_reset(struct rt_i2c *i2c) ++{ ++ device_reset(i2c->adap.dev.parent); ++ barrier(); ++ rt_i2c_w32(i2c, i2c->clk_div, REG_CLKDIV_REG); ++} ++ ++static void rt_i2c_dump_reg(struct rt_i2c *i2c) ++{ ++ dev_dbg(i2c->dev, "conf %08x, clkdiv %08x, devaddr %08x, " \ ++ "addr %08x, dataout %08x, datain %08x, " \ ++ "status %08x, startxfr %08x, bytecnt %08x\n", ++ rt_i2c_r32(i2c, REG_CONFIG_REG), ++ rt_i2c_r32(i2c, REG_CLKDIV_REG), ++ rt_i2c_r32(i2c, REG_DEVADDR_REG), ++ rt_i2c_r32(i2c, REG_ADDR_REG), ++ rt_i2c_r32(i2c, REG_DATAOUT_REG), ++ rt_i2c_r32(i2c, REG_DATAIN_REG), ++ rt_i2c_r32(i2c, REG_STATUS_REG), ++ rt_i2c_r32(i2c, REG_STARTXFR_REG), ++ rt_i2c_r32(i2c, REG_BYTECNT_REG)); ++} + -+ for (i = 0; i < n && !ret; i++) { -+ ret = rt_i2c_handle_msg(a, &m[i]); ++static int rt_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ++ int num) ++{ ++ struct rt_i2c *i2c; ++ struct i2c_msg *pmsg; ++ unsigned char addr; ++ int i, j, ret; ++ u32 cmd; ++ ++ i2c = i2c_get_adapdata(adap); ++ ++ for (i = 0; i < num; i++) { ++ pmsg = &msgs[i]; ++ if (i == (num - 1)) ++ cmd = 0; ++ else ++ cmd = NOSTOP_CMD; ++ ++ dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x, stop: %d\n", ++ pmsg->addr, pmsg->len, pmsg->flags, ++ (cmd == 0)? 1 : 0); ++ ++ /* wait hardware idle */ ++ if ((ret = rt_i2c_wait_idle(i2c))) ++ goto err_timeout; ++ ++ if (pmsg->flags & I2C_M_TEN) { ++ rt_i2c_w32(i2c, I2C_CONF_DEFAULT, REG_CONFIG_REG); ++ /* 10 bits address */ ++ addr = 0x78 | ((pmsg->addr >> 8) & 0x03); ++ rt_i2c_w32(i2c, addr & I2C_DEVADDR_MASK, ++ REG_DEVADDR_REG); ++ rt_i2c_w32(i2c, pmsg->addr & I2C_ADDR_MASK, ++ REG_ADDR_REG); ++ } else { ++ rt_i2c_w32(i2c, I2C_CONF_DEFAULT | I2C_ADDR_DIS, ++ REG_CONFIG_REG); ++ /* 7 bits address */ ++ rt_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK, ++ REG_DEVADDR_REG); ++ } + -+ if (ret < 0) { -+ return ret; ++ /* buffer length */ ++ if (pmsg->len == 0) ++ cmd |= NODATA_CMD; ++ else ++ rt_i2c_w32(i2c, SET_BYTECNT(pmsg->len), ++ REG_BYTECNT_REG); ++ ++ j = 0; ++ if (pmsg->flags & I2C_M_RD) { ++ cmd |= READ_CMD; ++ /* start transfer */ ++ barrier(); ++ rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG); ++ do { ++ /* wait */ ++ if ((ret = rt_i2c_wait_rx_done(i2c))) ++ goto err_timeout; ++ /* read data */ ++ if (pmsg->len) ++ pmsg->buf[j] = rt_i2c_r32(i2c, ++ REG_DATAIN_REG); ++ j++; ++ } while (j < pmsg->len); ++ } else { ++ do { ++ /* write data */ ++ if (pmsg->len) ++ rt_i2c_w32(i2c, pmsg->buf[j], ++ REG_DATAOUT_REG); ++ /* start transfer */ ++ if (j == 0) { ++ barrier(); ++ rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG); ++ } ++ /* wait */ ++ if ((ret = rt_i2c_wait_tx_done(i2c))) ++ goto err_timeout; ++ j++; ++ } while (j < pmsg->len); + } + } ++ /* the return value is number of executed messages */ ++ ret = i; ++ ++ return ret; + -+ return n; ++err_timeout: ++ rt_i2c_dump_reg(i2c); ++ rt_i2c_reset(i2c); ++ return ret; +} + +static u32 rt_i2c_func(struct i2c_adapter *a) @@ -311,60 +371,110 @@ Signed-off-by: John Crispin +}; + +static const struct of_device_id i2c_rt_dt_ids[] = { -+ { .compatible = "ralink,rt2880-i2c", .data = (void *) I2C_TYPE_RALINK }, -+ { .compatible = "mediatek,mt7628-i2c", .data = (void *) I2C_TYPE_MEDIATEK }, ++ { .compatible = "ralink,rt2880-i2c" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids); + ++static struct i2c_adapter_quirks rt_i2c_quirks = { ++ .max_write_len = BYTECNT_MAX, ++ .max_read_len = BYTECNT_MAX, ++}; ++ ++static int rt_i2c_init(struct rt_i2c *i2c) ++{ ++ u32 reg; ++ ++ /* i2c_sclk = periph_clk / ((2 * clk_div) + 5) */ ++ i2c->clk_div = (clk_get_rate(i2c->clk) - (5 * i2c->cur_clk)) / ++ (2 * i2c->cur_clk); ++ if (i2c->clk_div < 8) ++ i2c->clk_div = 8; ++ if (i2c->clk_div > I2C_CLKDIV_MASK) ++ i2c->clk_div = I2C_CLKDIV_MASK; ++ ++ /* check support combinde/repeated start message */ ++ rt_i2c_w32(i2c, NOSTOP_CMD, REG_STARTXFR_REG); ++ reg = rt_i2c_r32(i2c, REG_STARTXFR_REG) & NOSTOP_CMD; ++ ++ rt_i2c_reset(i2c); ++ ++ return reg; ++} ++ +static int rt_i2c_probe(struct platform_device *pdev) +{ -+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ struct resource *res; ++ struct rt_i2c *i2c; ++ struct i2c_adapter *adap; + const struct of_device_id *match; -+ int ret; ++ int ret, restart; + + match = of_match_device(i2c_rt_dt_ids, &pdev->dev); -+ hw_type = (int) match->data; + ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no memory resource found\n"); + return -ENODEV; + } + -+ adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter), GFP_KERNEL); -+ if (!adapter) { ++ i2c = devm_kzalloc(&pdev->dev, sizeof(struct rt_i2c), GFP_KERNEL); ++ if (!i2c) { + dev_err(&pdev->dev, "failed to allocate i2c_adapter\n"); + return -ENOMEM; + } + -+ membase = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(membase)) -+ return PTR_ERR(membase); -+ -+ strlcpy(adapter->name, dev_name(&pdev->dev), sizeof(adapter->name)); -+ adapter->owner = THIS_MODULE; -+ adapter->nr = pdev->id; -+ adapter->timeout = HZ; -+ adapter->algo = &rt_i2c_algo; -+ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ adapter->dev.parent = &pdev->dev; -+ adapter->dev.of_node = pdev->dev.of_node; -+ -+ ret = i2c_add_numbered_adapter(adapter); -+ if (ret) -+ return ret; ++ i2c->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(i2c->base)) ++ return PTR_ERR(i2c->base); + -+ platform_set_drvdata(pdev, adapter); ++ i2c->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(i2c->clk)) { ++ dev_err(&pdev->dev, "no clock defined\n"); ++ return -ENODEV; ++ } ++ clk_prepare_enable(i2c->clk); ++ i2c->dev = &pdev->dev; ++ ++ if (of_property_read_u32(pdev->dev.of_node, ++ "clock-frequency", &i2c->cur_clk)) ++ i2c->cur_clk = 100000; ++ ++ adap = &i2c->adap; ++ adap->owner = THIS_MODULE; ++ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; ++ adap->algo = &rt_i2c_algo; ++ adap->retries = 3; ++ adap->dev.parent = &pdev->dev; ++ i2c_set_adapdata(adap, i2c); ++ adap->dev.of_node = pdev->dev.of_node; ++ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); ++ adap->quirks = &rt_i2c_quirks; ++ ++ platform_set_drvdata(pdev, i2c); ++ ++ restart = rt_i2c_init(i2c); ++ ++ ret = i2c_add_adapter(adap); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to add adapter\n"); ++ clk_disable_unprepare(i2c->clk); ++ return ret; ++ } + -+ dev_info(&pdev->dev, "loaded\n"); ++ dev_info(&pdev->dev, "clock %uKHz, re-start %ssupport\n", ++ i2c->cur_clk/1000, restart ? "" : "not "); + -+ return 0; ++ return ret; +} + +static int rt_i2c_remove(struct platform_device *pdev) +{ -+ platform_set_drvdata(pdev, NULL); ++ struct rt_i2c *i2c = platform_get_drvdata(pdev); ++ ++ i2c_del_adapter(&i2c->adap); ++ clk_disable_unprepare(i2c->clk); + + return 0; +} @@ -389,8 +499,7 @@ Signed-off-by: John Crispin +{ + platform_driver_unregister(&rt_i2c_driver); +} -+ -+module_exit (i2c_rt_exit); ++module_exit(i2c_rt_exit); + +MODULE_AUTHOR("Steven Liu "); +MODULE_DESCRIPTION("Ralink I2c host driver"); diff --git a/target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch b/target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch index 044991594b5d..df8b3a443161 100644 --- a/target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch +++ b/target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch @@ -13,12 +13,13 @@ Signed-off-by: John Crispin --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig -@@ -810,6 +810,10 @@ config I2C_RALINK - tristate "Ralink I2C Controller" +@@ -811,6 +811,11 @@ config I2C_RALINK + depends on RALINK && !SOC_MT7621 select OF_I2C +config I2C_MT7621 -+ tristate "MT7621 I2C Controller" ++ tristate "MT7621/MT7628 I2C Controller" ++ depends on RALINK && (SOC_MT7620 || SOC_MT7621) + select OF_I2C + config HAVE_S3C2410_I2C @@ -36,11 +37,12 @@ Signed-off-by: John Crispin obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o --- /dev/null +++ b/drivers/i2c/busses/i2c-mt7621.c -@@ -0,0 +1,303 @@ +@@ -0,0 +1,433 @@ +/* + * drivers/i2c/busses/i2c-mt7621.c + * + * Copyright (C) 2013 Steven Liu ++ * Copyright (C) 2016 Michael Lee + * + * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. + * (C) 2014 Sittisak @@ -65,276 +67,405 @@ Signed-off-by: John Crispin +#include +#include +#include ++#include +#include +#include +#include ++#include ++ ++#define REG_SM0CFG0 0x08 ++#define REG_SM0DOUT 0x10 ++#define REG_SM0DIN 0x14 ++#define REG_SM0ST 0x18 ++#define REG_SM0AUTO 0x1C ++#define REG_SM0CFG1 0x20 ++#define REG_SM0CFG2 0x28 ++#define REG_SM0CTL0 0x40 ++#define REG_SM0CTL1 0x44 ++#define REG_SM0D0 0x50 ++#define REG_SM0D1 0x54 ++#define REG_PINTEN 0x5C ++#define REG_PINTST 0x60 ++#define REG_PINTCL 0x64 ++ ++/* REG_SM0CFG0 */ ++#define I2C_DEVADDR_MASK 0x7f ++ ++/* REG_SM0ST */ ++#define I2C_DATARDY BIT(2) ++#define I2C_SDOEMPTY BIT(1) ++#define I2C_BUSY BIT(0) ++ ++/* REG_SM0AUTO */ ++#define READ_CMD BIT(0) ++ ++/* REG_SM0CFG1 */ ++#define BYTECNT_MAX 64 ++#define SET_BYTECNT(x) (x - 1) ++ ++/* REG_SM0CFG2 */ ++#define AUTOMODE_EN BIT(0) ++ ++/* REG_SM0CTL0 */ ++#define ODRAIN_HIGH_SM0 BIT(31) ++#define VSYNC_SHIFT 28 ++#define VSYNC_MASK 0x3 ++#define VSYNC_PULSE (0x1 << VSYNC_SHIFT) ++#define VSYNC_RISING (0x2 << VSYNC_SHIFT) ++#define CLK_DIV_SHIFT 16 ++#define CLK_DIV_MASK 0xfff ++#define DEG_CNT_SHIFT 8 ++#define DEG_CNT_MASK 0xff ++#define WAIT_HIGH BIT(6) ++#define DEG_EN BIT(5) ++#define CS_STATUA BIT(4) ++#define SCL_STATUS BIT(3) ++#define SDA_STATUS BIT(2) ++#define SM0_EN BIT(1) ++#define SCL_STRECH BIT(0) ++ ++/* REG_SM0CTL1 */ ++#define ACK_SHIFT 16 ++#define ACK_MASK 0xff ++#define PGLEN_SHIFT 8 ++#define PGLEN_MASK 0x7 ++#define SM0_MODE_SHIFT 4 ++#define SM0_MODE_MASK 0x7 ++#define SM0_MODE_START 0x1 ++#define SM0_MODE_WRITE 0x2 ++#define SM0_MODE_STOP 0x3 ++#define SM0_MODE_READ_NACK 0x4 ++#define SM0_MODE_READ_ACK 0x5 ++#define SM0_TRI_BUSY BIT(0) ++ ++/* timeout waiting for I2C devices to respond (clock streching) */ ++#define TIMEOUT_MS 1000 ++#define DELAY_INTERVAL_US 100 ++ ++struct mtk_i2c { ++ void __iomem *base; ++ struct clk *clk; ++ struct device *dev; ++ struct i2c_adapter adap; ++ u32 cur_clk; ++ u32 clk_div; ++ u32 flags; ++}; + -+#include -+ -+#define REG_CONFIG_REG 0x00 -+#define REG_CLKDIV_REG 0x04 -+#define REG_DEVADDR_REG 0x08 -+#define REG_ADDR_REG 0x0C -+#define REG_DATAOUT_REG 0x10 -+#define REG_DATAIN_REG 0x14 -+#define REG_STATUS_REG 0x18 -+#define REG_STARTXFR_REG 0x1C -+#define REG_BYTECNT_REG 0x20 -+#define REG_SM0_IS_AUTOMODE 0x28 -+#define REG_SM0CTL0 0x40 -+ -+ -+#define I2C_STARTERR 0x10 -+#define I2C_ACKERR 0x08 -+#define I2C_DATARDY 0x04 -+#define I2C_SDOEMPTY 0x02 -+#define I2C_BUSY 0x01 -+ -+/* I2C_CFG register bit field */ -+#define I2C_CFG_ADDRLEN_8 (7<<5) /* 8 bits */ -+#define I2C_CFG_DEVADLEN_7 (6<<2) -+#define I2C_CFG_ADDRDIS BIT(1) -+#define I2C_CFG_DEVADDIS BIT(0) -+ -+#define I2C_CFG_DEFAULT (I2C_CFG_ADDRLEN_8 | \ -+ I2C_CFG_DEVADLEN_7 | \ -+ I2C_CFG_ADDRDIS) -+ -+#define I2C_RETRY 0x1000 -+ -+#define CLKDIV_VALUE 333 -+#define i2c_busy_loop (CLKDIV_VALUE*30) -+ -+#define READ_CMD 0x01 -+#define WRITE_CMD 0x00 -+#define READ_BLOCK 16 -+ -+#define SM0_ODRAIN BIT(31) -+#define SM0_VSYNC_MODE BIT(28) -+#define SM0_CLK_DIV (CLKDIV_VALUE << 16) -+#define SM0_WAIT_LEVEL BIT(6) -+#define SM0_EN BIT(1) -+ -+#define SM0_CFG_DEFUALT (SM0_ODRAIN | SM0_VSYNC_MODE | \ -+ SM0_CLK_DIV | SM0_WAIT_LEVEL | \ -+ SM0_EN) -+/***********************************************************/ -+ -+static void __iomem *membase; -+static struct i2c_adapter *adapter; -+ -+static void rt_i2c_w32(u32 val, unsigned reg) ++static void mtk_i2c_w32(struct mtk_i2c *i2c, u32 val, unsigned reg) +{ -+ iowrite32(val, membase + reg); ++ iowrite32(val, i2c->base + reg); +} + -+static u32 rt_i2c_r32(unsigned reg) ++static u32 mtk_i2c_r32(struct mtk_i2c *i2c, unsigned reg) +{ -+ return ioread32(membase + reg); ++ return ioread32(i2c->base + reg); +} + -+static void mt7621_i2c_reset(struct i2c_adapter *a) ++static int poll_down_timeout(void __iomem *addr, u32 mask) +{ -+ device_reset(a->dev.parent); ++ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); ++ ++ do { ++ if (!(readl_relaxed(addr) & mask)) ++ return 0; ++ ++ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); ++ } while (time_before(jiffies, timeout)); ++ ++ return (readl_relaxed(addr) & mask) ? -EAGAIN : 0; +} -+static void mt7621_i2c_enable(struct i2c_msg *msg) ++ ++static int mtk_i2c_wait_idle(struct mtk_i2c *i2c) +{ -+ rt_i2c_w32(msg->addr,REG_DEVADDR_REG); -+ rt_i2c_w32(0,REG_ADDR_REG); ++ int ret; ++ ++ ret = poll_down_timeout(i2c->base + REG_SM0ST, I2C_BUSY); ++ if (ret < 0) ++ dev_dbg(i2c->dev, "idle err(%d)\n", ret); ++ ++ return ret; +} + -+static void i2c_master_init(struct i2c_adapter *a) ++static int poll_up_timeout(void __iomem *addr, u32 mask) +{ -+ mt7621_i2c_reset(a); -+ rt_i2c_w32(I2C_CFG_DEFAULT,REG_CONFIG_REG); -+ rt_i2c_w32(SM0_CFG_DEFUALT,REG_SM0CTL0); -+ rt_i2c_w32(1,REG_SM0_IS_AUTOMODE);//auto mode -+} ++ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); ++ u32 status; + ++ do { ++ status = readl_relaxed(addr); ++ if (status & mask) ++ return 0; ++ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); ++ } while (time_before(jiffies, timeout)); + -+static inline int rt_i2c_wait_rx_done(void) -+{ -+ int i=0; -+ while((!(rt_i2c_r32(REG_STATUS_REG) & I2C_DATARDY)) && (i=i2c_busy_loop){ -+ pr_err("err,wait for idle timeout"); -+ return -ETIMEDOUT; -+ } -+ return 0; ++ return -ETIMEDOUT; +} + -+static inline int rt_i2c_wait_idle(void) ++static int mtk_i2c_wait_rx_done(struct mtk_i2c *i2c) +{ -+ int i=0; -+ while((rt_i2c_r32(REG_STATUS_REG) & I2C_BUSY) && (i=i2c_busy_loop){ -+ pr_err("err,wait for idle timeout"); -+ return -ETIMEDOUT; -+ } -+ return 0; ++ int ret; ++ ++ ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_DATARDY); ++ if (ret < 0) ++ dev_dbg(i2c->dev, "rx err(%d)\n", ret); ++ ++ return ret; +} + -+static inline int rt_i2c_wait_tx_done(void) ++static int mtk_i2c_wait_tx_done(struct mtk_i2c *i2c) +{ -+ int i=0; -+ while((!(rt_i2c_r32(REG_STATUS_REG) & I2C_SDOEMPTY)) && (i=i2c_busy_loop){ -+ pr_err("err,wait for idle timeout"); -+ return -ETIMEDOUT; -+ } -+ return 0; ++ int ret; ++ ++ ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_SDOEMPTY); ++ if (ret < 0) ++ dev_dbg(i2c->dev, "tx err(%d)\n", ret); ++ ++ return ret; +} + -+static int rt_i2c_handle_msg(struct i2c_adapter *a, struct i2c_msg* msg) ++static void mtk_i2c_reset(struct mtk_i2c *i2c) +{ -+ int i = 0, j = 0, pos = 0; -+ int nblock = msg->len / READ_BLOCK; -+ int rem = msg->len % READ_BLOCK; ++ u32 reg; ++ device_reset(i2c->adap.dev.parent); ++ barrier(); + -+ if (msg->flags & I2C_M_TEN) { -+ printk("10 bits addr not supported\n"); -+ return -EINVAL; -+ } ++ /* ctrl0 */ ++ reg = ODRAIN_HIGH_SM0 | VSYNC_PULSE | (i2c->clk_div << CLK_DIV_SHIFT) | ++ WAIT_HIGH | SM0_EN; ++ mtk_i2c_w32(i2c, reg, REG_SM0CTL0); + -+ if (msg->flags & I2C_M_RD) { -+ for (i = 0; i < nblock; i++) { -+ if (rt_i2c_wait_idle()) -+ goto err_timeout; -+ rt_i2c_w32(READ_BLOCK - 1, REG_BYTECNT_REG); -+ rt_i2c_w32(READ_CMD, REG_STARTXFR_REG); -+ for (j = 0; j < READ_BLOCK; j++) { -+ if (rt_i2c_wait_rx_done()) -+ goto err_timeout; -+ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); -+ } -+ } ++ /* auto mode */ ++ mtk_i2c_w32(i2c, AUTOMODE_EN, REG_SM0CFG2); ++} ++ ++static void mtk_i2c_dump_reg(struct mtk_i2c *i2c) ++{ ++ dev_dbg(i2c->dev, "cfg0 %08x, dout %08x, din %08x, " \ ++ "status %08x, auto %08x, cfg1 %08x, " \ ++ "cfg2 %08x, ctl0 %08x, ctl1 %08x\n", ++ mtk_i2c_r32(i2c, REG_SM0CFG0), ++ mtk_i2c_r32(i2c, REG_SM0DOUT), ++ mtk_i2c_r32(i2c, REG_SM0DIN), ++ mtk_i2c_r32(i2c, REG_SM0ST), ++ mtk_i2c_r32(i2c, REG_SM0AUTO), ++ mtk_i2c_r32(i2c, REG_SM0CFG1), ++ mtk_i2c_r32(i2c, REG_SM0CFG2), ++ mtk_i2c_r32(i2c, REG_SM0CTL0), ++ mtk_i2c_r32(i2c, REG_SM0CTL1)); ++} + -+ if (rt_i2c_wait_idle()) -+ goto err_timeout; -+ rt_i2c_w32(rem - 1, REG_BYTECNT_REG); -+ rt_i2c_w32(READ_CMD, REG_STARTXFR_REG); -+ -+ for (i = 0; i < rem; i++) { -+ if (rt_i2c_wait_rx_done()) -+ goto err_timeout; -+ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); ++static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ++ int num) ++{ ++ struct mtk_i2c *i2c; ++ struct i2c_msg *pmsg; ++ int i, j, ret; ++ u32 cmd; ++ ++ i2c = i2c_get_adapdata(adap); ++ ++ for (i = 0; i < num; i++) { ++ pmsg = &msgs[i]; ++ cmd = 0; ++ ++ dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x\n", ++ pmsg->addr, pmsg->len, pmsg->flags); ++ ++ /* wait hardware idle */ ++ if ((ret = mtk_i2c_wait_idle(i2c))) ++ goto err_timeout; ++ ++ if (pmsg->flags & I2C_M_TEN) { ++ dev_dbg(i2c->dev, "10 bits addr not supported\n"); ++ return -EINVAL; ++ } else { ++ /* 7 bits address */ ++ mtk_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK, ++ REG_SM0CFG0); + } -+ } else { -+ if (rt_i2c_wait_idle()) -+ goto err_timeout; -+ rt_i2c_w32(msg->len - 1, REG_BYTECNT_REG); -+ for (i = 0; i < msg->len; i++) { -+ rt_i2c_w32(msg->buf[i], REG_DATAOUT_REG); -+ if(i == 0) -+ rt_i2c_w32(WRITE_CMD, REG_STARTXFR_REG); -+ -+ if (rt_i2c_wait_tx_done()) -+ goto err_timeout; ++ ++ /* buffer length */ ++ if (pmsg->len == 0) { ++ dev_dbg(i2c->dev, "length is 0\n"); ++ return -EINVAL; ++ } else ++ mtk_i2c_w32(i2c, SET_BYTECNT(pmsg->len), ++ REG_SM0CFG1); ++ ++ j = 0; ++ if (pmsg->flags & I2C_M_RD) { ++ cmd |= READ_CMD; ++ /* start transfer */ ++ barrier(); ++ mtk_i2c_w32(i2c, cmd, REG_SM0AUTO); ++ do { ++ /* wait */ ++ if ((ret = mtk_i2c_wait_rx_done(i2c))) ++ goto err_timeout; ++ /* read data */ ++ if (pmsg->len) ++ pmsg->buf[j] = mtk_i2c_r32(i2c, ++ REG_SM0DIN); ++ j++; ++ } while (j < pmsg->len); ++ } else { ++ do { ++ /* write data */ ++ if (pmsg->len) ++ mtk_i2c_w32(i2c, pmsg->buf[j], ++ REG_SM0DOUT); ++ /* start transfer */ ++ if (j == 0) { ++ barrier(); ++ mtk_i2c_w32(i2c, cmd, REG_SM0AUTO); ++ } ++ /* wait */ ++ if ((ret = mtk_i2c_wait_tx_done(i2c))) ++ goto err_timeout; ++ j++; ++ } while (j < pmsg->len); + } + } ++ /* the return value is number of executed messages */ ++ ret = i; + -+ return 0; -+err_timeout: -+ return -ETIMEDOUT; -+} ++ return ret; + -+static int rt_i2c_master_xfer(struct i2c_adapter *a, struct i2c_msg *m, int n) -+{ -+ int i = 0; -+ int ret = 0; -+ i2c_master_init(a); -+ mt7621_i2c_enable(m); -+ -+ for (i = 0; i != n && ret==0; i++) { -+ ret = rt_i2c_handle_msg(a, &m[i]); -+ if (ret) -+ return ret; -+ } -+ return i; ++err_timeout: ++ mtk_i2c_dump_reg(i2c); ++ mtk_i2c_reset(i2c); ++ return ret; +} + -+static u32 rt_i2c_func(struct i2c_adapter *a) ++static u32 mtk_i2c_func(struct i2c_adapter *a) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + -+static const struct i2c_algorithm rt_i2c_algo = { -+ .master_xfer = rt_i2c_master_xfer, -+ .functionality = rt_i2c_func, ++static const struct i2c_algorithm mtk_i2c_algo = { ++ .master_xfer = mtk_i2c_master_xfer, ++ .functionality = mtk_i2c_func, +}; + -+static int rt_i2c_probe(struct platform_device *pdev) ++static const struct of_device_id i2c_mtk_dt_ids[] = { ++ { .compatible = "mediatek,mt7621-i2c" }, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(of, i2c_mtk_dt_ids); ++ ++static struct i2c_adapter_quirks mtk_i2c_quirks = { ++ .max_write_len = BYTECNT_MAX, ++ .max_read_len = BYTECNT_MAX, ++}; ++ ++static void mtk_i2c_init(struct mtk_i2c *i2c) ++{ ++ i2c->clk_div = clk_get_rate(i2c->clk) / i2c->cur_clk; ++ if (i2c->clk_div > CLK_DIV_MASK) ++ i2c->clk_div = CLK_DIV_MASK; ++ ++ mtk_i2c_reset(i2c); ++} ++ ++static int mtk_i2c_probe(struct platform_device *pdev) +{ -+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ struct resource *res; ++ struct mtk_i2c *i2c; ++ struct i2c_adapter *adap; ++ const struct of_device_id *match; + int ret; + -+ adapter = devm_kzalloc(&pdev->dev,sizeof(struct i2c_adapter), GFP_KERNEL); -+ if (!adapter) { ++ match = of_match_device(i2c_mtk_dt_ids, &pdev->dev); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "no memory resource found\n"); ++ return -ENODEV; ++ } ++ ++ i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL); ++ if (!i2c) { + dev_err(&pdev->dev, "failed to allocate i2c_adapter\n"); + return -ENOMEM; + } -+ membase = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(membase)) -+ return PTR_ERR(membase); -+ -+ strlcpy(adapter->name, dev_name(&pdev->dev), sizeof(adapter->name)); -+ -+ adapter->owner = THIS_MODULE; -+ adapter->nr = pdev->id; -+ adapter->timeout = HZ; -+ adapter->algo = &rt_i2c_algo; -+ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ adapter->dev.parent = &pdev->dev; -+ adapter->dev.of_node = pdev->dev.of_node; -+ -+ platform_set_drvdata(pdev, adapter); -+ -+ ret = i2c_add_numbered_adapter(adapter); -+ if (ret) ++ ++ i2c->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(i2c->base)) ++ return PTR_ERR(i2c->base); ++ ++ i2c->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(i2c->clk)) { ++ dev_err(&pdev->dev, "no clock defined\n"); ++ return -ENODEV; ++ } ++ clk_prepare_enable(i2c->clk); ++ i2c->dev = &pdev->dev; ++ ++ if (of_property_read_u32(pdev->dev.of_node, ++ "clock-frequency", &i2c->cur_clk)) ++ i2c->cur_clk = 100000; ++ ++ adap = &i2c->adap; ++ adap->owner = THIS_MODULE; ++ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; ++ adap->algo = &mtk_i2c_algo; ++ adap->retries = 3; ++ adap->dev.parent = &pdev->dev; ++ i2c_set_adapdata(adap, i2c); ++ adap->dev.of_node = pdev->dev.of_node; ++ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); ++ adap->quirks = &mtk_i2c_quirks; ++ ++ platform_set_drvdata(pdev, i2c); ++ ++ mtk_i2c_init(i2c); ++ ++ ret = i2c_add_adapter(adap); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to add adapter\n"); ++ clk_disable_unprepare(i2c->clk); + return ret; ++ } + -+ dev_info(&pdev->dev,"loaded"); ++ dev_info(&pdev->dev, "clock %uKHz, re-start not support\n", ++ i2c->cur_clk/1000); + -+ return 0; ++ return ret; +} + -+static int rt_i2c_remove(struct platform_device *pdev) ++static int mtk_i2c_remove(struct platform_device *pdev) +{ -+ platform_set_drvdata(pdev, NULL); -+ return 0; -+} ++ struct mtk_i2c *i2c = platform_get_drvdata(pdev); + -+static const struct of_device_id i2c_rt_dt_ids[] = { -+ { .compatible = "ralink,i2c-mt7621", }, -+ { /* sentinel */ } -+}; ++ i2c_del_adapter(&i2c->adap); ++ clk_disable_unprepare(i2c->clk); + -+MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids); ++ return 0; ++} + -+static struct platform_driver rt_i2c_driver = { -+ .probe = rt_i2c_probe, -+ .remove = rt_i2c_remove, ++static struct platform_driver mtk_i2c_driver = { ++ .probe = mtk_i2c_probe, ++ .remove = mtk_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = "i2c-mt7621", -+ .of_match_table = i2c_rt_dt_ids, ++ .of_match_table = i2c_mtk_dt_ids, + }, +}; + -+static int __init i2c_rt_init (void) ++static int __init i2c_mtk_init (void) +{ -+ return platform_driver_register(&rt_i2c_driver); ++ return platform_driver_register(&mtk_i2c_driver); +} ++subsys_initcall(i2c_mtk_init); + -+static void __exit i2c_rt_exit (void) ++static void __exit i2c_mtk_exit (void) +{ -+ platform_driver_unregister(&rt_i2c_driver); ++ platform_driver_unregister(&mtk_i2c_driver); +} -+module_init (i2c_rt_init); -+module_exit (i2c_rt_exit); ++module_exit(i2c_mtk_exit); + +MODULE_AUTHOR("Steven Liu "); +MODULE_DESCRIPTION("MT7621 I2c host driver"); From 32b8deeab5fecfe9fc7b68265c3e32c9736288f3 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 7 Jan 2016 22:27:45 +0800 Subject: [PATCH 27/37] ramips: update i2c dtsi files Signed-off-by: Michael Lee --- target/linux/ramips/dts/mt7620a.dtsi | 2 +- target/linux/ramips/dts/mt7621.dtsi | 32 +++++++++++++++++++++------ target/linux/ramips/dts/mt7628an.dtsi | 2 +- target/linux/ramips/dts/rt2880.dtsi | 23 +++++++++++++++++++ target/linux/ramips/dts/rt3050.dtsi | 23 +++++++++++++++++++ target/linux/ramips/dts/rt3352.dtsi | 23 +++++++++++++++++++ target/linux/ramips/dts/rt3883.dtsi | 23 +++++++++++++++++++ target/linux/ramips/dts/rt5350.dtsi | 16 +++++++------- 8 files changed, 127 insertions(+), 17 deletions(-) diff --git a/target/linux/ramips/dts/mt7620a.dtsi b/target/linux/ramips/dts/mt7620a.dtsi index ccadbe40db7a..1c957b7d2a71 100644 --- a/target/linux/ramips/dts/mt7620a.dtsi +++ b/target/linux/ramips/dts/mt7620a.dtsi @@ -176,7 +176,7 @@ }; i2c: i2c@900 { - compatible = "link,mt7620a-i2c", "ralink,rt2880-i2c"; + compatible = "ralink,rt2880-i2c"; reg = <0x900 0x100>; resets = <&rstctrl 16>; diff --git a/target/linux/ramips/dts/mt7621.dtsi b/target/linux/ramips/dts/mt7621.dtsi index 7a9d79a88b93..772f0aabfab9 100644 --- a/target/linux/ramips/dts/mt7621.dtsi +++ b/target/linux/ramips/dts/mt7621.dtsi @@ -89,6 +89,24 @@ }; }; + i2c: i2c@900 { + compatible = "mediatek,mt7621-i2c"; + reg = <0x900 0x100>; + + clocks = <&sysclock>; + + resets = <&rstctrl 16>; + reset-names = "i2c"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + }; + memc: memc@5000 { compatible = "mtk,mt7621-memc"; reg = <0x300 0x100>; @@ -188,13 +206,6 @@ state_default: pinctrl0 { }; - spi_pins: spi { - spi { - ralink,group = "spi"; - ralink,function = "spi"; - }; - }; - i2c_pins: i2c { i2c { ralink,group = "i2c"; @@ -202,6 +213,13 @@ }; }; + spi_pins: spi { + spi { + ralink,group = "spi"; + ralink,function = "spi"; + }; + }; + uart1_pins: uart1 { uart1 { ralink,group = "uart1"; diff --git a/target/linux/ramips/dts/mt7628an.dtsi b/target/linux/ramips/dts/mt7628an.dtsi index 6d5ed95e4971..860521999d4b 100644 --- a/target/linux/ramips/dts/mt7628an.dtsi +++ b/target/linux/ramips/dts/mt7628an.dtsi @@ -110,7 +110,7 @@ }; i2c: i2c@900 { - compatible = "mediatek,mt7628-i2c"; + compatible = "mediatek,mt7621-i2c"; reg = <0x900 0x100>; resets = <&rstctrl 16>; diff --git a/target/linux/ramips/dts/rt2880.dtsi b/target/linux/ramips/dts/rt2880.dtsi index ad882547f794..c2ead2c97555 100644 --- a/target/linux/ramips/dts/rt2880.dtsi +++ b/target/linux/ramips/dts/rt2880.dtsi @@ -114,6 +114,22 @@ status = "disabled"; }; + i2c: i2c@900 { + compatible = "ralink,rt2880-i2c"; + reg = <0x900 0x100>; + + resets = <&rstctrl 9>; + reset-names = "i2c"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + }; + uartlite: uartlite@c00 { compatible = "ralink,rt2880-uart", "ns16550a"; reg = <0xc00 0x100>; @@ -138,6 +154,13 @@ }; }; + i2c_pins: i2c { + i2c { + ralink,group = "i2c"; + ralink,function = "i2c"; + }; + }; + spi_pins: spi { spi { ralink,group = "spi"; diff --git a/target/linux/ramips/dts/rt3050.dtsi b/target/linux/ramips/dts/rt3050.dtsi index ed88ac12ec3b..ff1281b06416 100644 --- a/target/linux/ramips/dts/rt3050.dtsi +++ b/target/linux/ramips/dts/rt3050.dtsi @@ -166,6 +166,22 @@ status = "disabled"; }; + i2c@900 { + compatible = "ralink,rt2880-i2c"; + reg = <0x900 0x100>; + + resets = <&rstctrl 16>; + reset-names = "i2c"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + }; + spi0: spi@b00 { compatible = "ralink,rt3050-spi", "ralink,rt2880-spi"; reg = <0xb00 0x100>; @@ -212,6 +228,13 @@ }; }; + i2c_pins: i2c { + i2c { + ralink,group = "i2c"; + ralink,function = "i2c"; + }; + }; + spi_pins: spi { spi { ralink,group = "spi"; diff --git a/target/linux/ramips/dts/rt3352.dtsi b/target/linux/ramips/dts/rt3352.dtsi index 0bb28ec83330..d010de38a35a 100644 --- a/target/linux/ramips/dts/rt3352.dtsi +++ b/target/linux/ramips/dts/rt3352.dtsi @@ -146,6 +146,22 @@ status = "disabled"; }; + i2c@900 { + compatible = "ralink,rt2880-i2c"; + reg = <0x900 0x100>; + + resets = <&rstctrl 16>; + reset-names = "i2c"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + }; + spi0: spi@b00 { compatible = "ralink,rt3352-spi", "ralink,rt2880-spi"; reg = <0xb00 0x40>; @@ -219,6 +235,13 @@ state_default: pinctrl0 { }; + i2c_pins: i2c { + i2c { + ralink,group = "i2c"; + ralink,function = "i2c"; + }; + }; + spi_pins: spi { spi { ralink,group = "spi"; diff --git a/target/linux/ramips/dts/rt3883.dtsi b/target/linux/ramips/dts/rt3883.dtsi index 041b0633d3f4..975e86b1f632 100644 --- a/target/linux/ramips/dts/rt3883.dtsi +++ b/target/linux/ramips/dts/rt3883.dtsi @@ -166,6 +166,22 @@ status = "disabled"; }; + i2c@900 { + compatible = "ralink,rt2880-i2c"; + reg = <0x900 0x100>; + + resets = <&rstctrl 16>; + reset-names = "i2c"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + }; + spi0: spi@b00 { compatible = "ralink,rt3883-spi", "ralink,rt2880-spi"; reg = <0xb00 0x40>; @@ -239,6 +255,13 @@ state_default: pinctrl0 { }; + i2c_pins: i2c { + i2c { + ralink,group = "i2c"; + ralink,function = "i2c"; + }; + }; + spi_pins: spi { spi { ralink,group = "spi"; diff --git a/target/linux/ramips/dts/rt5350.dtsi b/target/linux/ramips/dts/rt5350.dtsi index 1027519c9826..f6a170756313 100644 --- a/target/linux/ramips/dts/rt5350.dtsi +++ b/target/linux/ramips/dts/rt5350.dtsi @@ -138,7 +138,7 @@ }; i2c: i2c@900 { - compatible = "link,rt5350-i2c", "ralink,rt2880-i2c"; + compatible = "ralink,rt2880-i2c"; reg = <0x900 0x100>; resets = <&rstctrl 16>; @@ -236,13 +236,6 @@ state_default: pinctrl0 { }; - spi_pins: spi { - spi { - ralink,group = "spi"; - ralink,function = "spi"; - }; - }; - i2c_pins: i2c { i2c { ralink,group = "i2c"; @@ -250,6 +243,13 @@ }; }; + spi_pins: spi { + spi { + ralink,group = "spi"; + ralink,function = "spi"; + }; + }; + phy_led_pins: phy_led { phy_led { ralink,group = "led"; From 2556e13e67501d6d8b532be24c3f3374cd7cce85 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Fri, 8 Jan 2016 21:15:27 +0800 Subject: [PATCH 28/37] ramips: add i2c clock Signed-off-by: Michael Lee --- ...0720-arch-mips-ralink-add-i2c-clocks.patch | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 target/linux/ramips/patches-4.4/0720-arch-mips-ralink-add-i2c-clocks.patch diff --git a/target/linux/ramips/patches-4.4/0720-arch-mips-ralink-add-i2c-clocks.patch b/target/linux/ramips/patches-4.4/0720-arch-mips-ralink-add-i2c-clocks.patch new file mode 100644 index 000000000000..395883686060 --- /dev/null +++ b/target/linux/ramips/patches-4.4/0720-arch-mips-ralink-add-i2c-clocks.patch @@ -0,0 +1,40 @@ +--- a/arch/mips/ralink/mt7620.c ++++ b/arch/mips/ralink/mt7620.c +@@ -446,6 +446,7 @@ void __init ralink_clk_init(void) + ralink_clk_add("cpu", cpu_rate); + ralink_clk_add("10000100.timer", periph_rate); + ralink_clk_add("10000120.watchdog", periph_rate); ++ ralink_clk_add("10000900.i2c", periph_rate); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000b40.spi", sys_rate); + ralink_clk_add("10000c00.uartlite", periph_rate); +--- a/arch/mips/ralink/rt288x.c ++++ b/arch/mips/ralink/rt288x.c +@@ -75,6 +75,7 @@ void __init ralink_clk_init(void) + ralink_clk_add("300100.timer", cpu_rate / 2); + ralink_clk_add("300120.watchdog", cpu_rate / 2); + ralink_clk_add("300500.uart", cpu_rate / 2); ++ ralink_clk_add("300900.i2c", cpu_rate / 2); + ralink_clk_add("300c00.uartlite", cpu_rate / 2); + ralink_clk_add("400000.ethernet", cpu_rate / 2); + ralink_clk_add("480000.wmac", wmac_rate); +--- a/arch/mips/ralink/rt305x.c ++++ b/arch/mips/ralink/rt305x.c +@@ -200,6 +200,7 @@ void __init ralink_clk_init(void) + + ralink_clk_add("cpu", cpu_rate); + ralink_clk_add("sys", sys_rate); ++ ralink_clk_add("10000900.i2c", uart_rate); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000b40.spi", sys_rate); + ralink_clk_add("10000100.timer", wdt_rate); +--- a/arch/mips/ralink/rt3883.c ++++ b/arch/mips/ralink/rt3883.c +@@ -108,6 +108,7 @@ void __init ralink_clk_init(void) + ralink_clk_add("10000100.timer", sys_rate); + ralink_clk_add("10000120.watchdog", sys_rate); + ralink_clk_add("10000500.uart", 40000000); ++ ralink_clk_add("10000900.i2c", 40000000); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000b40.spi", sys_rate); + ralink_clk_add("10000c00.uartlite", 40000000); From 0bc5b761ef5390fffe6b9955d7b4974571226a09 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Sun, 15 May 2016 22:59:25 +0800 Subject: [PATCH 29/37] ramips: improve i2s drivers * remove mt7620-wm8960.c use simple card and DTS to do it * add old chips support * add 12Mhz refclk setup. this is hard code. need use clock framework rewrite it * add interrupt error status support for debug. default disable it. because it cause to many interrupts * add setup bclk suport not hard code it * add 24 bits support for mt7628. not verified * use regmap api to control registers * add txdma-req/rxdma-req DTS params for DMA use Signed-off-by: Michael Lee --- .../0048-asoc-add-mt7620-support.patch | 1203 ++++++++++------- 1 file changed, 742 insertions(+), 461 deletions(-) diff --git a/target/linux/ramips/patches-4.4/0048-asoc-add-mt7620-support.patch b/target/linux/ramips/patches-4.4/0048-asoc-add-mt7620-support.patch index 41ef41c022ba..bc1800efe44d 100644 --- a/target/linux/ramips/patches-4.4/0048-asoc-add-mt7620-support.patch +++ b/target/linux/ramips/patches-4.4/0048-asoc-add-mt7620-support.patch @@ -58,41 +58,30 @@ Signed-off-by: John Crispin obj-$(CONFIG_SND_SOC) += sirf/ --- /dev/null +++ b/sound/soc/ralink/Kconfig -@@ -0,0 +1,15 @@ -+config SND_MT7620_SOC_I2S -+ depends on SOC_MT7620 && SND_SOC +@@ -0,0 +1,8 @@ ++config SND_RALINK_SOC_I2S ++ depends on RALINK && SND_SOC && !SOC_RT288X + select SND_SOC_GENERIC_DMAENGINE_PCM -+ tristate "SoC Audio (I2S protocol) for Ralink MT7620 SoC" ++ select REGMAP_MMIO ++ tristate "SoC Audio (I2S protocol) for Ralink SoC" + help -+ Say Y if you want to use I2S protocol and I2S codec on Ingenic MT7620 ++ Say Y if you want to use I2S protocol and I2S codec on Ralink/MediaTek + based boards. -+ -+config SND_MT7620_SOC_WM8960 -+ tristate "SoC Audio support for Ralink WM8960" -+ select SND_MT7620_SOC_I2S -+ select SND_SOC_WM8960 -+ help -+ Say Y if you want to add support for ASoC audio on the Qi LB60 board -+ a.k.a Qi Ben NanoNote. --- /dev/null +++ b/sound/soc/ralink/Makefile -@@ -0,0 +1,11 @@ +@@ -0,0 +1,6 @@ +# -+# Jz4740 Platform Support ++# Ralink/MediaTek Platform Support +# -+snd-soc-mt7620-i2s-objs := mt7620-i2s.o -+ -+obj-$(CONFIG_SND_MT7620_SOC_I2S) += snd-soc-mt7620-i2s.o -+ -+# Jz4740 Machine Support -+snd-soc-mt7620-wm8960-objs := mt7620-wm8960.o ++snd-soc-ralink-i2s-objs := ralink-i2s.o + -+obj-$(CONFIG_SND_MT7620_SOC_WM8960) += snd-soc-mt7620-wm8960.o ++obj-$(CONFIG_SND_RALINK_SOC_I2S) += snd-soc-ralink-i2s.o --- /dev/null -+++ b/sound/soc/ralink/mt7620-i2s.c -@@ -0,0 +1,436 @@ ++++ b/sound/soc/ralink/ralink-i2s.c +@@ -0,0 +1,965 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen ++ * Copyright (C) 2016 Michael Lee + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the @@ -105,27 +94,31 @@ Signed-off-by: John Crispin + * + */ + -+#include -+#include -+#include +#include +#include -+#include -+ -+#include -+ -+#include -+ -+#include -+#include ++#include ++#include ++#include ++#include ++#include +#include -+#include -+#include +#include + -+#include ++#include ++ ++#define DRV_NAME "ralink-i2s" + +#define I2S_REG_CFG0 0x00 ++#define I2S_REG_INT_STATUS 0x04 ++#define I2S_REG_INT_EN 0x08 ++#define I2S_REG_FF_STATUS 0x0c ++#define I2S_REG_WREG 0x10 ++#define I2S_REG_RREG 0x14 ++#define I2S_REG_CFG1 0x18 ++#define I2S_REG_DIVCMP 0x20 ++#define I2S_REG_DIVINT 0x24 ++ ++/* I2S_REG_CFG0 */ +#define I2S_REG_CFG0_EN BIT(31) +#define I2S_REG_CFG0_DMA_EN BIT(30) +#define I2S_REG_CFG0_BYTE_SWAP BIT(28) @@ -134,143 +127,235 @@ Signed-off-by: John Crispin +#define I2S_REG_CFG0_SLAVE BIT(16) +#define I2S_REG_CFG0_RX_THRES 12 +#define I2S_REG_CFG0_TX_THRES 4 ++#define I2S_REG_CFG0_THRES_MASK (0xf << I2S_REG_CFG0_RX_THRES) | \ ++ (4 << I2S_REG_CFG0_TX_THRES) +#define I2S_REG_CFG0_DFT_THRES (4 << I2S_REG_CFG0_RX_THRES) | \ -+ (4 << I2S_REG_CFG0_TX_THRES) -+ -+#define I2S_REG_INT_STATUS 0x04 -+#define I2S_REG_INT_EN 0x08 -+#define I2S_REG_FF_STATUS 0x0c -+#define I2S_REG_WREG 0x10 -+#define I2S_REG_RREG 0x14 -+#define I2S_REG_CFG1 0x18 -+ -+#define I2S_REG_DIVCMP 0x20 -+#define I2S_REG_DIVINT 0x24 -+#define I2S_REG_CLK_EN BIT(31) ++ (4 << I2S_REG_CFG0_TX_THRES) ++/* RT305x */ ++#define I2S_REG_CFG0_CLK_DIS BIT(8) ++#define I2S_REG_CFG0_TXCH_SWAP BIT(3) ++#define I2S_REG_CFG0_TXCH1_OFF BIT(2) ++#define I2S_REG_CFG0_TXCH0_OFF BIT(1) ++#define I2S_REG_CFG0_SLAVE_EN BIT(0) ++/* RT3883 */ ++#define I2S_REG_CFG0_RXCH_SWAP BIT(11) ++#define I2S_REG_CFG0_RXCH1_OFF BIT(10) ++#define I2S_REG_CFG0_RXCH0_OFF BIT(9) ++#define I2S_REG_CFG0_WS_INV BIT(0) ++/* MT7628 */ ++#define I2S_REG_CFG0_FMT_LE BIT(29) ++#define I2S_REG_CFG0_SYS_BE BIT(28) ++#define I2S_REG_CFG0_NORM_24 BIT(18) ++#define I2S_REG_CFG0_DATA_24 BIT(17) ++ ++/* I2S_REG_INT_STATUS */ ++#define I2S_REG_INT_RX_FAULT BIT(7) ++#define I2S_REG_INT_RX_OVRUN BIT(6) ++#define I2S_REG_INT_RX_UNRUN BIT(5) ++#define I2S_REG_INT_RX_THRES BIT(4) ++#define I2S_REG_INT_TX_FAULT BIT(3) ++#define I2S_REG_INT_TX_OVRUN BIT(2) ++#define I2S_REG_INT_TX_UNRUN BIT(1) ++#define I2S_REG_INT_TX_THRES BIT(0) ++#define I2S_REG_INT_TX_MASK 0xf ++#define I2S_REG_INT_RX_MASK 0xf0 ++ ++/* I2S_REG_INT_STATUS */ ++#define I2S_RX_AVCNT(x) ((x >> 4) & 0xf) ++#define I2S_TX_AVCNT(x) (x & 0xf) ++/* MT7628 */ ++#define MT7628_I2S_RX_AVCNT(x) ((x >> 8) & 0x1f) ++#define MT7628_I2S_TX_AVCNT(x) (x & 0x1f) ++ ++/* I2S_REG_CFG1 */ ++#define I2S_REG_CFG1_LBK BIT(31) ++#define I2S_REG_CFG1_EXTLBK BIT(30) ++/* RT3883 */ ++#define I2S_REG_CFG1_LEFT_J BIT(0) ++#define I2S_REG_CFG1_RIGHT_J BIT(1) ++#define I2S_REG_CFG1_FMT_MASK 0x3 ++ ++/* I2S_REG_DIVCMP */ ++#define I2S_REG_DIVCMP_CLKEN BIT(31) ++#define I2S_REG_DIVCMP_DIVCOMP_MASK 0x1ff ++ ++/* I2S_REG_DIVINT */ ++#define I2S_REG_DIVINT_MASK 0x3ff ++ ++/* BCLK dividers */ ++#define RALINK_I2S_DIVCMP 0 ++#define RALINK_I2S_DIVINT 1 ++ ++/* FIFO */ ++#define RALINK_I2S_FIFO_SIZE 32 ++ ++/* feature flags */ ++#define RALINK_FLAGS_TXONLY BIT(0) ++#define RALINK_FLAGS_LEFT_J BIT(1) ++#define RALINK_FLAGS_RIGHT_J BIT(2) ++#define RALINK_FLAGS_ENDIAN BIT(3) ++#define RALINK_FLAGS_24BIT BIT(4) ++ ++#define RALINK_I2S_INT_EN 0 ++ ++struct ralink_i2s_stats { ++ u32 dmafault; ++ u32 overrun; ++ u32 underrun; ++ u32 belowthres; ++}; + -+struct mt7620_i2s { -+ struct resource *mem; -+ void __iomem *base; -+ dma_addr_t phys_base; ++struct ralink_i2s { ++ struct device *dev; ++ void __iomem *regs; ++ struct clk *clk; ++ struct regmap *regmap; ++ u32 flags; ++ unsigned int fmt; ++ u16 txdma_req; ++ u16 rxdma_req; + + struct snd_dmaengine_dai_dma_data playback_dma_data; + struct snd_dmaengine_dai_dma_data capture_dma_data; ++ ++ struct dentry *dbg_dir; ++ struct dentry *dbg_stats; ++ struct ralink_i2s_stats txstats; ++ struct ralink_i2s_stats rxstats; +}; + -+static inline uint32_t mt7620_i2s_read(const struct mt7620_i2s *i2s, -+ unsigned int reg) ++static void ralink_i2s_dump_regs(struct ralink_i2s *i2s) +{ -+ return readl(i2s->base + reg); ++ u32 buf[10]; ++ int ret; ++ ++ ret = regmap_bulk_read(i2s->regmap, I2S_REG_CFG0, ++ buf, ARRAY_SIZE(buf)); ++ ++ dev_dbg(i2s->dev, "CFG0: %08x, INTSTAT: %08x, INTEN: %08x, " \ ++ "FFSTAT: %08x, WREG: %08x, RREG: %08x, " \ ++ "CFG1: %08x, DIVCMP: %08x, DIVINT: %08x\n", ++ buf[0], buf[1], buf[2], buf[3], buf[4], ++ buf[5], buf[6], buf[8], buf[9]); +} + -+static inline void mt7620_i2s_write(const struct mt7620_i2s *i2s, -+ unsigned int reg, uint32_t value) ++static int ralink_i2s_set_sysclk(struct snd_soc_dai *dai, ++ int clk_id, unsigned int freq, int dir) +{ -+ //printk("i2s --> %p = 0x%08X\n", i2s->base + reg, value); -+ writel(value, i2s->base + reg); ++ return 0; +} + -+static int mt7620_i2s_startup(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) ++static int ralink_i2s_set_sys_bclk(struct snd_soc_dai *dai, int width, int rate) +{ -+ struct mt7620_i2s *i2s = snd_soc_dai_get_drvdata(dai); -+ uint32_t cfg; ++ struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai); ++ unsigned long clk = clk_get_rate(i2s->clk); ++ int div; ++ uint32_t data; + -+ if (dai->active) ++ /* disable clock at slave mode */ ++ if ((i2s->fmt & SND_SOC_DAIFMT_MASTER_MASK) == ++ SND_SOC_DAIFMT_CBM_CFM) { ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_CLK_DIS, ++ I2S_REG_CFG0_CLK_DIS); + return 0; ++ } + -+ cfg = mt7620_i2s_read(i2s, I2S_REG_CFG0); -+ cfg |= I2S_REG_CFG0_EN; -+ mt7620_i2s_write(i2s, I2S_REG_CFG0, cfg); ++ /* FREQOUT = FREQIN / (I2S_CLK_DIV + 1) */ ++ div = (clk / rate ) - 1; + -+ return 0; -+} ++ data = rt_sysc_r32(0x30); ++ data &= (0xff << 8); ++ data |= (0x1 << 15) | (div << 8); ++ rt_sysc_w32(data, 0x30); + -+static void mt7620_i2s_shutdown(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct mt7620_i2s *i2s = snd_soc_dai_get_drvdata(dai); -+ uint32_t cfg; ++ /* enable clock */ ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, I2S_REG_CFG0_CLK_DIS, 0); + -+ if (dai->active) -+ return; ++ dev_dbg(i2s->dev, "clk: %lu, rate: %u, div: %d\n", ++ clk, rate, div); + -+ cfg = mt7620_i2s_read(i2s, I2S_REG_CFG0); -+ cfg &= ~I2S_REG_CFG0_EN; -+ mt7620_i2s_write(i2s, I2S_REG_CFG0, cfg); ++ return 0; +} + -+static int mt7620_i2s_trigger(struct snd_pcm_substream *substream, int cmd, -+ struct snd_soc_dai *dai) ++static int ralink_i2s_set_bclk(struct snd_soc_dai *dai, int width, int rate) +{ -+ struct mt7620_i2s *i2s = snd_soc_dai_get_drvdata(dai); -+ -+ uint32_t cfg; -+ uint32_t mask; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ mask = I2S_REG_CFG0_TX_EN; -+ else -+ mask = I2S_REG_CFG0_RX_EN; ++ struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai); ++ unsigned long clk = clk_get_rate(i2s->clk); ++ int divint, divcomp; ++ ++ /* disable clock at slave mode */ ++ if ((i2s->fmt & SND_SOC_DAIFMT_MASTER_MASK) == ++ SND_SOC_DAIFMT_CBM_CFM) { ++ regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP, ++ I2S_REG_DIVCMP_CLKEN, 0); ++ return 0; ++ } + -+ cfg = mt7620_i2s_read(i2s, I2S_REG_CFG0); ++ /* FREQOUT = FREQIN * (1/2) * (1/(DIVINT + DIVCOMP/512)) */ ++ clk = clk / (2 * 2 * width); ++ divint = clk / rate; ++ divcomp = ((clk % rate) * 512) / rate; + -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ cfg |= mask; -+ break; -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ cfg &= ~mask; -+ break; -+ default: ++ if ((divint > I2S_REG_DIVINT_MASK) || ++ (divcomp > I2S_REG_DIVCMP_DIVCOMP_MASK)) + return -EINVAL; -+ } + -+ if (cfg & (I2S_REG_CFG0_TX_EN | I2S_REG_CFG0_RX_EN)) -+ cfg |= I2S_REG_CFG0_DMA_EN; -+ else -+ cfg &= ~I2S_REG_CFG0_DMA_EN; ++ regmap_update_bits(i2s->regmap, I2S_REG_DIVINT, ++ I2S_REG_DIVINT_MASK, divint); ++ regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP, ++ I2S_REG_DIVCMP_DIVCOMP_MASK, divcomp); ++ ++ /* enable clock */ ++ regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP, I2S_REG_DIVCMP_CLKEN, ++ I2S_REG_DIVCMP_CLKEN); + -+ mt7620_i2s_write(i2s, I2S_REG_CFG0, cfg); ++ dev_dbg(i2s->dev, "clk: %lu, rate: %u, int: %d, comp: %d\n", ++ clk_get_rate(i2s->clk), rate, divint, divcomp); + + return 0; +} + -+static int mt7620_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++static int ralink_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ -+ struct mt7620_i2s *i2s = snd_soc_dai_get_drvdata(dai); -+ uint32_t cfg; -+ -+ cfg = mt7620_i2s_read(i2s, I2S_REG_CFG0); ++ struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai); ++ unsigned int cfg0 = 0, cfg1 = 0; + ++ /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { -+ case SND_SOC_DAIFMT_CBS_CFS: -+ cfg |= I2S_REG_CFG0_SLAVE; -+ break; + case SND_SOC_DAIFMT_CBM_CFM: -+ cfg &= ~I2S_REG_CFG0_SLAVE; ++ if (i2s->flags & RALINK_FLAGS_TXONLY) ++ cfg0 |= I2S_REG_CFG0_SLAVE_EN; ++ else ++ cfg0 |= I2S_REG_CFG0_SLAVE; ++ break; ++ case SND_SOC_DAIFMT_CBS_CFS: + break; -+ case SND_SOC_DAIFMT_CBM_CFS: + default: + return -EINVAL; + } + ++ /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: -+ case SND_SOC_DAIFMT_MSB: -+ cfg &= ~I2S_REG_CFG0_BYTE_SWAP; -+ break; -+ case SND_SOC_DAIFMT_LSB: -+ cfg |= I2S_REG_CFG0_BYTE_SWAP; + break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ if (i2s->flags & RALINK_FLAGS_RIGHT_J) { ++ cfg1 |= I2S_REG_CFG1_RIGHT_J; ++ break; ++ } ++ return -EINVAL; ++ case SND_SOC_DAIFMT_LEFT_J: ++ if (i2s->flags & RALINK_FLAGS_LEFT_J) { ++ cfg1 |= I2S_REG_CFG1_LEFT_J; ++ break; ++ } ++ return -EINVAL; + default: + return -EINVAL; + } + ++ /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; @@ -278,488 +363,684 @@ Signed-off-by: John Crispin + return -EINVAL; + } + -+ mt7620_i2s_write(i2s, I2S_REG_CFG0, cfg); ++ if (i2s->flags & RALINK_FLAGS_TXONLY) { ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_SLAVE_EN, cfg0); ++ } else { ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_SLAVE, cfg0); ++ } ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG1, ++ I2S_REG_CFG1_FMT_MASK, cfg1); ++ i2s->fmt = fmt; + + return 0; +} + -+static int mt7620_i2s_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) ++static int ralink_i2s_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) +{ ++ struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai); ++ ++ if (dai->active) ++ return 0; ++ ++ /* setup status interrupt */ ++#if (RALINK_I2S_INT_EN) ++ regmap_write(i2s->regmap, I2S_REG_INT_EN, 0xff); ++#else ++ regmap_write(i2s->regmap, I2S_REG_INT_EN, 0x0); ++#endif ++ ++ /* enable */ ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_EN | I2S_REG_CFG0_DMA_EN | ++ I2S_REG_CFG0_THRES_MASK, ++ I2S_REG_CFG0_EN | I2S_REG_CFG0_DMA_EN | ++ I2S_REG_CFG0_DFT_THRES); + + return 0; +} + -+unsigned long i2sMaster_inclk_int[11] = { -+ 78, 56, 52, 39, 28, 26, 19, 14, 13, 9, 6}; -+unsigned long i2sMaster_inclk_comp[11] = { -+ 64, 352, 42, 32, 176, 21, 272, 88, 10, 455, 261}; ++static void ralink_i2s_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai); ++ ++ /* If both streams are stopped, disable module and clock */ ++ if (dai->active) ++ return; + ++ /* ++ * datasheet mention when disable all control regs are cleared ++ * to initial values. need reinit at startup. ++ */ ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, I2S_REG_CFG0_EN, 0); ++} + -+static int mt7620_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, -+ unsigned int freq, int dir) ++static int ralink_i2s_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ -+ struct mt7620_i2s *i2s = snd_soc_dai_get_drvdata(dai); ++ struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai); ++ int width; ++ int ret; ++ ++ width = params_width(params); ++ switch (width) { ++ case 16: ++ if (i2s->flags & RALINK_FLAGS_24BIT) ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_DATA_24, 0); ++ break; ++ case 24: ++ if (i2s->flags & RALINK_FLAGS_24BIT) { ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_DATA_24, ++ I2S_REG_CFG0_DATA_24); ++ break; ++ } ++ return -EINVAL; ++ default: ++ return -EINVAL; ++ } + -+ printk("Internal REFCLK with fractional division\n"); ++ switch (params_channels(params)) { ++ case 2: ++ break; ++ default: ++ return -EINVAL; ++ } + -+ mt7620_i2s_write(i2s, I2S_REG_DIVINT, i2sMaster_inclk_int[7]); -+ mt7620_i2s_write(i2s, I2S_REG_DIVCMP, -+ i2sMaster_inclk_comp[7] | I2S_REG_CLK_EN); ++ if (i2s->flags & RALINK_FLAGS_ENDIAN) { ++ /* system endian */ ++#ifdef SNDRV_LITTLE_ENDIAN ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_SYS_BE, 0); ++#else ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_SYS_BE, ++ I2S_REG_CFG0_SYS_BE); ++#endif ++ ++ /* data endian */ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ case SNDRV_PCM_FORMAT_S24_LE: ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_FMT_LE, ++ I2S_REG_CFG0_FMT_LE); ++ break; ++ case SNDRV_PCM_FORMAT_S16_BE: ++ case SNDRV_PCM_FORMAT_S24_BE: ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, ++ I2S_REG_CFG0_FMT_LE, 0); ++ break; ++ default: ++ return -EINVAL; ++ } ++ } + -+/* struct mt7620_i2s *i2s = snd_soc_dai_get_drvdata(dai); -+ struct clk *parent; -+ int ret = 0; ++ /* setup bclk rate */ ++ if (i2s->flags & RALINK_FLAGS_TXONLY) ++ ret = ralink_i2s_set_sys_bclk(dai, width, params_rate(params)); ++ else ++ ret = ralink_i2s_set_bclk(dai, width, params_rate(params)); ++ ++ return ret; ++} ++ ++static int ralink_i2s_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai); ++ unsigned int mask, val; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ mask = I2S_REG_CFG0_TX_EN; ++ else ++ mask = I2S_REG_CFG0_RX_EN; + -+ switch (clk_id) { -+ case JZ4740_I2S_CLKSRC_EXT: -+ parent = clk_get(NULL, "ext"); -+ clk_set_parent(i2s->clk_i2s, parent); ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ val = mask; + break; -+ case JZ4740_I2S_CLKSRC_PLL: -+ parent = clk_get(NULL, "pll half"); -+ clk_set_parent(i2s->clk_i2s, parent); -+ ret = clk_set_rate(i2s->clk_i2s, freq); ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ val = 0; + break; + default: + return -EINVAL; + } -+ clk_put(parent); + -+ return ret;*/ ++ regmap_update_bits(i2s->regmap, I2S_REG_CFG0, mask, val); ++ + return 0; +} + -+static void mt7620_i2c_init_pcm_config(struct mt7620_i2s *i2s) ++static void ralink_i2s_init_dma_data(struct ralink_i2s *i2s, ++ struct resource *res) +{ + struct snd_dmaengine_dai_dma_data *dma_data; + + /* Playback */ + dma_data = &i2s->playback_dma_data; -+ dma_data->maxburst = 16; -+ dma_data->slave_id = 2; //JZ4740_DMA_TYPE_AIC_TRANSMIT; -+ dma_data->addr = i2s->phys_base + I2S_REG_WREG; ++ dma_data->addr = res->start + I2S_REG_WREG; ++ dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ dma_data->maxburst = 1; ++ dma_data->slave_id = i2s->txdma_req; ++ ++ if (i2s->flags & RALINK_FLAGS_TXONLY) ++ return; + + /* Capture */ + dma_data = &i2s->capture_dma_data; -+ dma_data->maxburst = 16; -+ dma_data->slave_id = 3; //JZ4740_DMA_TYPE_AIC_RECEIVE; -+ dma_data->addr = i2s->phys_base + I2S_REG_RREG; ++ dma_data->addr = res->start + I2S_REG_RREG; ++ dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ dma_data->maxburst = 1; ++ dma_data->slave_id = i2s->rxdma_req; +} + -+static int mt7620_i2s_dai_probe(struct snd_soc_dai *dai) ++static int ralink_i2s_dai_probe(struct snd_soc_dai *dai) +{ -+ struct mt7620_i2s *i2s = snd_soc_dai_get_drvdata(dai); -+ uint32_t data; -+ -+ mt7620_i2c_init_pcm_config(i2s); -+ dai->playback_dma_data = &i2s->playback_dma_data; -+ dai->capture_dma_data = &i2s->capture_dma_data; ++ struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai); + -+ /* set share pins to i2s/gpio mode and i2c mode */ -+ data = rt_sysc_r32(0x60); -+ data &= 0xFFFFFFE2; -+ data |= 0x00000018; -+ rt_sysc_w32(data, 0x60); -+ -+ printk("Internal REFCLK with fractional division\n"); -+ -+ mt7620_i2s_write(i2s, I2S_REG_CFG0, I2S_REG_CFG0_DFT_THRES); -+ mt7620_i2s_write(i2s, I2S_REG_CFG1, 0); -+ mt7620_i2s_write(i2s, I2S_REG_INT_EN, 0); -+ -+ mt7620_i2s_write(i2s, I2S_REG_DIVINT, i2sMaster_inclk_int[7]); -+ mt7620_i2s_write(i2s, I2S_REG_DIVCMP, -+ i2sMaster_inclk_comp[7] | I2S_REG_CLK_EN); ++ snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, ++ &i2s->capture_dma_data); + + return 0; +} + -+static int mt7620_i2s_dai_remove(struct snd_soc_dai *dai) ++static int ralink_i2s_dai_remove(struct snd_soc_dai *dai) +{ + return 0; +} + -+static const struct snd_soc_dai_ops mt7620_i2s_dai_ops = { -+ .startup = mt7620_i2s_startup, -+ .shutdown = mt7620_i2s_shutdown, -+ .trigger = mt7620_i2s_trigger, -+ .hw_params = mt7620_i2s_hw_params, -+ .set_fmt = mt7620_i2s_set_fmt, -+ .set_sysclk = mt7620_i2s_set_sysclk, ++static const struct snd_soc_dai_ops ralink_i2s_dai_ops = { ++ .set_sysclk = ralink_i2s_set_sysclk, ++ .set_fmt = ralink_i2s_set_fmt, ++ .startup = ralink_i2s_startup, ++ .shutdown = ralink_i2s_shutdown, ++ .hw_params = ralink_i2s_hw_params, ++ .trigger = ralink_i2s_trigger, +}; + -+#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ -+ SNDRV_PCM_FMTBIT_S24_LE) -+ -+static struct snd_soc_dai_driver mt7620_i2s_dai = { -+ .probe = mt7620_i2s_dai_probe, -+ .remove = mt7620_i2s_dai_remove, -+ .playback = { -+ .channels_min = 1, ++static struct snd_soc_dai_driver ralink_i2s_dai = { ++ .name = DRV_NAME, ++ .probe = ralink_i2s_dai_probe, ++ .remove = ralink_i2s_dai_remove, ++ .ops = &ralink_i2s_dai_ops, ++ .capture = { ++ .stream_name = "I2S Capture", ++ .channels_min = 2, + .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .formats = JZ4740_I2S_FMTS, ++ .rate_min = 5512, ++ .rate_max = 192000, ++ .rates = SNDRV_PCM_RATE_CONTINUOUS, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, -+ .capture = { ++ .playback = { ++ .stream_name = "I2S Playback", + .channels_min = 2, + .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .formats = JZ4740_I2S_FMTS, ++ .rate_min = 5512, ++ .rate_max = 192000, ++ .rates = SNDRV_PCM_RATE_CONTINUOUS, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .symmetric_rates = 1, -+ .ops = &mt7620_i2s_dai_ops, +}; + -+static const struct snd_pcm_hardware mt7620_pcm_hardware = { ++static struct snd_pcm_hardware ralink_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ .channels_min = 2, ++ .channels_max = 2, + .period_bytes_min = PAGE_SIZE, -+ .period_bytes_max = 64 * 1024, ++ .period_bytes_max = PAGE_SIZE * 2, + .periods_min = 2, + .periods_max = 128, + .buffer_bytes_max = 128 * 1024, -+ .fifo_size = 32, ++ .fifo_size = RALINK_I2S_FIFO_SIZE, +}; + -+static const struct snd_dmaengine_pcm_config mt7620_dmaengine_pcm_config = { ++static const struct snd_dmaengine_pcm_config ralink_dmaengine_pcm_config = { + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, -+ .pcm_hardware = &mt7620_pcm_hardware, ++ .pcm_hardware = &ralink_pcm_hardware, + .prealloc_buffer_size = 256 * PAGE_SIZE, +}; + -+static const struct snd_soc_component_driver mt7620_i2s_component = { -+ .name = "mt7620-i2s", ++static const struct snd_soc_component_driver ralink_i2s_component = { ++ .name = DRV_NAME, +}; + -+static int mt7620_i2s_dev_probe(struct platform_device *pdev) ++static bool ralink_i2s_readable_reg(struct device *dev, unsigned int reg) +{ -+ struct mt7620_i2s *i2s; -+ int ret; -+ -+ snd_dmaengine_pcm_register(&pdev->dev, -+ &mt7620_dmaengine_pcm_config, -+ SND_DMAENGINE_PCM_FLAG_COMPAT); -+ -+ i2s = kzalloc(sizeof(*i2s), GFP_KERNEL); -+ if (!i2s) -+ return -ENOMEM; -+ -+ i2s->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!i2s->mem) { -+ ret = -ENOENT; -+ goto err_free; -+ } ++ return true; ++} + -+ i2s->mem = request_mem_region(i2s->mem->start, resource_size(i2s->mem), -+ pdev->name); -+ if (!i2s->mem) { -+ ret = -EBUSY; -+ goto err_free; ++static bool ralink_i2s_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case I2S_REG_INT_STATUS: ++ case I2S_REG_FF_STATUS: ++ return true; + } ++ return false; ++} + -+ i2s->base = ioremap_nocache(i2s->mem->start, resource_size(i2s->mem)); -+ if (!i2s->base) { -+ ret = -EBUSY; -+ goto err_release_mem_region; ++static bool ralink_i2s_writeable_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case I2S_REG_FF_STATUS: ++ case I2S_REG_RREG: ++ return false; + } ++ return true; ++} + -+ i2s->phys_base = i2s->mem->start; -+ -+ platform_set_drvdata(pdev, i2s); -+ ret = snd_soc_register_component(&pdev->dev, &mt7620_i2s_component, -+ &mt7620_i2s_dai, 1); ++static const struct regmap_config ralink_i2s_regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .writeable_reg = ralink_i2s_writeable_reg, ++ .readable_reg = ralink_i2s_readable_reg, ++ .volatile_reg = ralink_i2s_volatile_reg, ++ .max_register = I2S_REG_DIVINT, ++}; + -+ if (!ret) { -+ dev_err(&pdev->dev, "loaded\n"); -+ return ret; ++#if (RALINK_I2S_INT_EN) ++static irqreturn_t ralink_i2s_irq(int irq, void *devid) ++{ ++ struct ralink_i2s *i2s = devid; ++ u32 status; ++ ++ regmap_read(i2s->regmap, I2S_REG_INT_STATUS, &status); ++ if (unlikely(!status)) ++ return IRQ_NONE; ++ ++ /* tx stats */ ++ if (status & I2S_REG_INT_TX_MASK) { ++ if (status & I2S_REG_INT_TX_THRES) ++ i2s->txstats.belowthres++; ++ if (status & I2S_REG_INT_TX_UNRUN) ++ i2s->txstats.underrun++; ++ if (status & I2S_REG_INT_TX_OVRUN) ++ i2s->txstats.overrun++; ++ if (status & I2S_REG_INT_TX_FAULT) ++ i2s->txstats.dmafault++; + } + -+ dev_err(&pdev->dev, "Failed to register DAI\n"); -+ iounmap(i2s->base); ++ /* rx stats */ ++ if (status & I2S_REG_INT_RX_MASK) { ++ if (status & I2S_REG_INT_RX_THRES) ++ i2s->rxstats.belowthres++; ++ if (status & I2S_REG_INT_RX_UNRUN) ++ i2s->rxstats.underrun++; ++ if (status & I2S_REG_INT_RX_OVRUN) ++ i2s->rxstats.overrun++; ++ if (status & I2S_REG_INT_RX_FAULT) ++ i2s->rxstats.dmafault++; ++ } + -+err_release_mem_region: -+ release_mem_region(i2s->mem->start, resource_size(i2s->mem)); -+err_free: -+ kfree(i2s); ++ /* clean status bits */ ++ regmap_write(i2s->regmap, I2S_REG_INT_STATUS, status); + -+ return ret; ++ return IRQ_HANDLED; +} ++#endif + -+static int mt7620_i2s_dev_remove(struct platform_device *pdev) ++#if IS_ENABLED(CONFIG_DEBUG_FS) ++static int ralink_i2s_stats_show(struct seq_file *s, void *unused) +{ -+ struct mt7620_i2s *i2s = platform_get_drvdata(pdev); ++ struct ralink_i2s *i2s = s->private; + -+ snd_soc_unregister_component(&pdev->dev); ++ seq_printf(s, "tx stats\n"); ++ seq_printf(s, "\tbelow threshold\t%u\n", i2s->txstats.belowthres); ++ seq_printf(s, "\tunder run\t%u\n", i2s->txstats.underrun); ++ seq_printf(s, "\tover run\t%u\n", i2s->txstats.overrun); ++ seq_printf(s, "\tdma fault\t%u\n", i2s->txstats.dmafault); + -+ iounmap(i2s->base); -+ release_mem_region(i2s->mem->start, resource_size(i2s->mem)); ++ seq_printf(s, "rx stats\n"); ++ seq_printf(s, "\tbelow threshold\t%u\n", i2s->rxstats.belowthres); ++ seq_printf(s, "\tunder run\t%u\n", i2s->rxstats.underrun); ++ seq_printf(s, "\tover run\t%u\n", i2s->rxstats.overrun); ++ seq_printf(s, "\tdma fault\t%u\n", i2s->rxstats.dmafault); + -+ kfree(i2s); -+ -+ snd_dmaengine_pcm_unregister(&pdev->dev); ++ ralink_i2s_dump_regs(i2s); + + return 0; +} + -+static const struct of_device_id mt7620_i2s_match[] = { -+ { .compatible = "ralink,mt7620a-i2s" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mt7620_i2s_match); ++static int ralink_i2s_stats_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, ralink_i2s_stats_show, inode->i_private); ++} + -+static struct platform_driver mt7620_i2s_driver = { -+ .probe = mt7620_i2s_dev_probe, -+ .remove = mt7620_i2s_dev_remove, -+ .driver = { -+ .name = "mt7620-i2s", -+ .owner = THIS_MODULE, -+ .of_match_table = mt7620_i2s_match, -+ }, ++static const struct file_operations ralink_i2s_stats_ops = { ++ .open = ralink_i2s_stats_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, +}; + -+module_platform_driver(mt7620_i2s_driver); ++static inline int ralink_i2s_debugfs_create(struct ralink_i2s *i2s) ++{ ++ i2s->dbg_dir = debugfs_create_dir(dev_name(i2s->dev), NULL); ++ if (!i2s->dbg_dir) ++ return -ENOMEM; ++ ++ i2s->dbg_stats = debugfs_create_file("stats", S_IRUGO, ++ i2s->dbg_dir, i2s, &ralink_i2s_stats_ops); ++ if (!i2s->dbg_stats) { ++ debugfs_remove(i2s->dbg_dir); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static inline void ralink_i2s_debugfs_remove(struct ralink_i2s *i2s) ++{ ++ debugfs_remove(i2s->dbg_stats); ++ debugfs_remove(i2s->dbg_dir); ++} ++#else ++static inline int ralink_i2s_debugfs_create(struct ralink_i2s *i2s) ++{ ++ return 0; ++} ++ ++static inline void ralink_i2s_debugfs_remove(struct fsl_ssi_dbg *ssi_dbg) ++{ ++} ++#endif + -+MODULE_AUTHOR("Lars-Peter Clausen, "); -+MODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:mt7620-i2s"); ---- /dev/null -+++ b/sound/soc/ralink/mt7620-wm8960.c -@@ -0,0 +1,233 @@ +/* -+ * Copyright 2013 Freescale Semiconductor, Inc. -+ * -+ * Based on mt7620-sgtl5000.c -+ * Copyright 2012 Freescale Semiconductor, Inc. -+ * Copyright 2012 Linaro Ltd. -+ * -+ * The code contained herein is licensed under the GNU General Public -+ * License. You may obtain a copy of the GNU General Public License -+ * Version 2 or later at the following locations: -+ * -+ * http://www.opensource.org/licenses/gpl-license.html -+ * http://www.gnu.org/copyleft/gpl.html ++ * TODO: these refclk setup functions should use ++ * clock framework instead. hardcode it now. + */ ++static void rt3350_refclk_setup(void) ++{ ++ uint32_t data; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ /* set refclk output 12Mhz clock */ ++ data = rt_sysc_r32(0x2c); ++ data |= (0x1 << 8); ++ rt_sysc_w32(data, 0x2c); ++} + -+#include "../codecs/wm8960.h" ++static void rt3883_refclk_setup(void) ++{ ++ uint32_t data; + -+#define DAI_NAME_SIZE 32 ++ /* set refclk output 12Mhz clock */ ++ data = rt_sysc_r32(0x2c); ++ data &= ~(0x3 << 13); ++ data |= (0x1 << 13); ++ rt_sysc_w32(data, 0x2c); ++} + -+struct mt7620_wm8960_data { -+ struct snd_soc_dai_link dai; -+ struct snd_soc_card card; -+ char codec_dai_name[DAI_NAME_SIZE]; -+ char platform_name[DAI_NAME_SIZE]; -+ unsigned int clk_frequency; -+}; ++static void rt3552_refclk_setup(void) ++{ ++ uint32_t data; + -+struct mt7620_priv { -+ struct platform_device *pdev; -+}; -+static struct mt7620_priv card_priv; ++ /* set refclk output 12Mhz clock */ ++ data = rt_sysc_r32(0x2c); ++ data &= ~(0xf << 8); ++ data |= (0x3 << 8); ++ rt_sysc_w32(data, 0x2c); ++} + -+static const struct snd_soc_dapm_widget mt7620_wm8960_dapm_widgets[] = { -+ SND_SOC_DAPM_HP("Headphone Jack", NULL), -+ SND_SOC_DAPM_SPK("Ext Spk", NULL), -+ SND_SOC_DAPM_MIC("AMIC", NULL), -+ SND_SOC_DAPM_MIC("DMIC", NULL), -+}; ++static void mt7620_refclk_setup(void) ++{ ++ uint32_t data; + -+static int sample_rate = 44100; -+static snd_pcm_format_t sample_format = SNDRV_PCM_FORMAT_S16_LE; ++ /* set refclk output 12Mhz clock */ ++ data = rt_sysc_r32(0x2c); ++ data &= ~(0x7 << 9); ++ data |= 0x1 << 9; ++ rt_sysc_w32(data, 0x2c); ++} + -+static int mt7620_hifi_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) ++static void mt7621_refclk_setup(void) +{ -+ sample_rate = params_rate(params); -+ sample_format = params_format(params); ++ uint32_t data; + -+ return 0; ++ /* set refclk output 12Mhz clock */ ++ data = rt_sysc_r32(0x2c); ++ data &= ~(0x1f << 18); ++ data |= (0x19 << 18); ++ data &= ~(0x1f << 12); ++ data |= (0x1 << 12); ++ data &= ~(0x7 << 9); ++ data |= (0x5 << 9); ++ rt_sysc_w32(data, 0x2c); +} + -+static struct snd_soc_ops mt7620_hifi_ops = { -+ .hw_params = mt7620_hifi_hw_params, ++static void mt7628_refclk_setup(void) ++{ ++ uint32_t data; ++ ++ /* set i2s and refclk digital pad */ ++ data = rt_sysc_r32(0x3c); ++ data |= 0x1f; ++ rt_sysc_w32(data, 0x3c); ++ ++ /* Adjust REFCLK0's driving strength */ ++ data = rt_sysc_r32(0x1354); ++ data &= ~(0x1 << 5); ++ rt_sysc_w32(data, 0x1354); ++ data = rt_sysc_r32(0x1364); ++ data |= ~(0x1 << 5); ++ rt_sysc_w32(data, 0x1364); ++ ++ /* set refclk output 12Mhz clock */ ++ data = rt_sysc_r32(0x2c); ++ data &= ~(0x7 << 9); ++ data |= 0x1 << 9; ++ rt_sysc_w32(data, 0x2c); ++} ++ ++struct rt_i2s_data { ++ u32 flags; ++ void (*refclk_setup)(void); ++}; ++ ++struct rt_i2s_data rt3050_i2s_data = { .flags = RALINK_FLAGS_TXONLY }; ++struct rt_i2s_data rt3350_i2s_data = { .flags = RALINK_FLAGS_TXONLY, ++ .refclk_setup = rt3350_refclk_setup }; ++struct rt_i2s_data rt3883_i2s_data = { ++ .flags = (RALINK_FLAGS_LEFT_J | RALINK_FLAGS_RIGHT_J), ++ .refclk_setup = rt3883_refclk_setup }; ++struct rt_i2s_data rt3352_i2s_data = { .refclk_setup = rt3552_refclk_setup}; ++struct rt_i2s_data mt7620_i2s_data = { .refclk_setup = mt7620_refclk_setup}; ++struct rt_i2s_data mt7621_i2s_data = { .refclk_setup = mt7621_refclk_setup}; ++struct rt_i2s_data mt7628_i2s_data = { ++ .flags = (RALINK_FLAGS_ENDIAN | RALINK_FLAGS_24BIT | ++ RALINK_FLAGS_LEFT_J), ++ .refclk_setup = mt7628_refclk_setup}; ++ ++static const struct of_device_id ralink_i2s_match_table[] = { ++ { .compatible = "ralink,rt3050-i2s", ++ .data = (void *)&rt3050_i2s_data }, ++ { .compatible = "ralink,rt3350-i2s", ++ .data = (void *)&rt3350_i2s_data }, ++ { .compatible = "ralink,rt3883-i2s", ++ .data = (void *)&rt3883_i2s_data }, ++ { .compatible = "ralink,rt3352-i2s", ++ .data = (void *)&rt3352_i2s_data }, ++ { .compatible = "mediatek,mt7620-i2s", ++ .data = (void *)&mt7620_i2s_data }, ++ { .compatible = "mediatek,mt7621-i2s", ++ .data = (void *)&mt7621_i2s_data }, ++ { .compatible = "mediatek,mt7628-i2s", ++ .data = (void *)&mt7628_i2s_data }, +}; ++MODULE_DEVICE_TABLE(of, ralink_i2s_match_table); + -+static int mt7620_wm8960_set_bias_level(struct snd_soc_card *card, -+ struct snd_soc_dapm_context *dapm, -+ enum snd_soc_bias_level level) ++static int ralink_i2s_probe(struct platform_device *pdev) +{ -+ struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; -+ struct mt7620_priv *priv = &card_priv; -+ struct mt7620_wm8960_data *data = snd_soc_card_get_drvdata(card); -+ struct device *dev = &priv->pdev->dev; -+ int ret; ++ const struct of_device_id *match; ++ struct device_node *np = pdev->dev.of_node; ++ struct ralink_i2s *i2s; ++ struct resource *res; ++ int irq, ret; ++ u32 dma_req; ++ struct rt_i2s_data *data; ++ ++ i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); ++ if (!i2s) ++ return -ENOMEM; + -+ if (dapm->dev != codec_dai->dev) -+ return 0; ++ platform_set_drvdata(pdev, i2s); ++ i2s->dev = &pdev->dev; + -+ switch (level) { -+ case SND_SOC_BIAS_PREPARE: -+ if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { ++ match = of_match_device(ralink_i2s_match_table, &pdev->dev); ++ if (!match) ++ return -EINVAL; ++ data = (struct rt_i2s_data *)match->data; ++ i2s->flags = data->flags; ++ /* setup out 12Mhz refclk to codec as mclk */ ++ if (data->refclk_setup) ++ data->refclk_setup(); ++ ++ if (of_property_read_u32(np, "txdma-req", &dma_req)) { ++ dev_err(&pdev->dev, "no txdma-req define\n"); ++ return -EINVAL; ++ } ++ i2s->txdma_req = (u16)dma_req; ++ if (!(i2s->flags & RALINK_FLAGS_TXONLY)) { ++ if (of_property_read_u32(np, "rxdma-req", &dma_req)) { ++ dev_err(&pdev->dev, "no rxdma-req define\n"); ++ return -EINVAL; + } -+ break; ++ i2s->rxdma_req = (u16)dma_req; ++ } + -+ case SND_SOC_BIAS_STANDBY: -+ if (dapm->bias_level == SND_SOC_BIAS_PREPARE) { -+ ret = snd_soc_dai_set_sysclk(codec_dai, -+ WM8960_SYSCLK_MCLK, data->clk_frequency, -+ SND_SOC_CLOCK_IN); -+ if (ret < 0) { -+ dev_err(dev, -+ "failed to switch away from FLL: %d\n", -+ ret); -+ return ret; -+ } -+ } -+ break; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ i2s->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(i2s->regs)) ++ return PTR_ERR(i2s->regs); + -+ default: -+ break; ++ i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs, ++ &ralink_i2s_regmap_config); ++ if (IS_ERR(i2s->regmap)) { ++ dev_err(&pdev->dev, "regmap init failed\n"); ++ return PTR_ERR(i2s->regmap); + } + -+ return 0; -+} ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "failed to get irq\n"); ++ return -EINVAL; ++ } + -+static int mt7620_wm8960_late_probe(struct snd_soc_card *card) -+{ -+ struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; -+ struct mt7620_priv *priv = &card_priv; -+ struct mt7620_wm8960_data *data = snd_soc_card_get_drvdata(card); -+ struct device *dev = &priv->pdev->dev; -+ int ret; ++#if (RALINK_I2S_INT_EN) ++ ret = devm_request_irq(&pdev->dev, irq, ralink_i2s_irq, ++ 0, dev_name(&pdev->dev), i2s); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request irq\n"); ++ return ret; ++ } ++#endif + -+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8960_SYSCLK_MCLK, -+ data->clk_frequency, SND_SOC_CLOCK_IN); -+ if (ret < 0) -+ dev_err(dev, "failed to set sysclk in %s\n", __func__); ++ i2s->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(i2s->clk)) { ++ dev_err(&pdev->dev, "no clock defined\n"); ++ return PTR_ERR(i2s->clk); ++ } + -+ return ret; -+} ++ ret = clk_prepare_enable(i2s->clk); ++ if (ret) ++ return ret; + -+static int mt7620_wm8960_probe(struct platform_device *pdev) -+{ -+ struct device_node *i2s_np, *codec_np; -+ struct platform_device *i2s_pdev; -+ struct mt7620_priv *priv = &card_priv; -+ struct i2c_client *codec_dev; -+ struct mt7620_wm8960_data *data; -+ int ret; ++ ralink_i2s_init_dma_data(i2s, res); + -+ priv->pdev = pdev; ++ device_reset(&pdev->dev); + -+ i2s_np = of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0); -+ codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0); -+ if (!i2s_np || !codec_np) { -+ dev_err(&pdev->dev, "phandle missing or invalid\n"); -+ ret = -EINVAL; -+ goto fail; ++ ret = ralink_i2s_debugfs_create(i2s); ++ if (ret) { ++ dev_err(&pdev->dev, "create debugfs failed\n"); ++ goto err_clk_disable; + } + -+ i2s_pdev = of_find_device_by_node(i2s_np); -+ if (!i2s_pdev) { -+ dev_err(&pdev->dev, "failed to find SSI platform device\n"); -+ ret = -EINVAL; -+ goto fail; -+ } -+ codec_dev = of_find_i2c_device_by_node(codec_np); -+ if (!codec_dev || !codec_dev->dev.driver) { -+ dev_err(&pdev->dev, "failed to find codec platform device\n"); -+ ret = -EINVAL; -+ goto fail; ++ /* enable 24bits support */ ++ if (i2s->flags & RALINK_FLAGS_24BIT) { ++ ralink_i2s_dai.capture.formats |= SNDRV_PCM_FMTBIT_S24_LE; ++ ralink_i2s_dai.playback.formats |= SNDRV_PCM_FMTBIT_S24_LE; + } + -+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); -+ if (!data) { -+ ret = -ENOMEM; -+ goto fail; ++ /* enable big endian support */ ++ if (i2s->flags & RALINK_FLAGS_ENDIAN) { ++ ralink_i2s_dai.capture.formats |= SNDRV_PCM_FMTBIT_S16_BE; ++ ralink_i2s_dai.playback.formats |= SNDRV_PCM_FMTBIT_S16_BE; ++ ralink_pcm_hardware.formats |= SNDRV_PCM_FMTBIT_S16_BE; ++ if (i2s->flags & RALINK_FLAGS_24BIT) { ++ ralink_i2s_dai.capture.formats |= ++ SNDRV_PCM_FMTBIT_S24_BE; ++ ralink_i2s_dai.playback.formats |= ++ SNDRV_PCM_FMTBIT_S24_BE; ++ ralink_pcm_hardware.formats |= ++ SNDRV_PCM_FMTBIT_S24_BE; ++ } + } + -+ data->clk_frequency = 12000000; -+ data->dai.name = "HiFi"; -+ data->dai.stream_name = "HiFi"; -+ data->dai.codec_dai_name = "wm8960-hifi"; -+ data->dai.codec_of_node = codec_np; -+ data->dai.cpu_dai_name = dev_name(&i2s_pdev->dev); -+ data->dai.platform_of_node = i2s_np; -+ data->dai.ops = &mt7620_hifi_ops; -+ data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBM_CFM; -+ -+ data->card.dev = &pdev->dev; -+ ret = snd_soc_of_parse_card_name(&data->card, "model"); ++ /* disable capture support */ ++ if (i2s->flags & RALINK_FLAGS_TXONLY) ++ memset(&ralink_i2s_dai.capture, sizeof(ralink_i2s_dai.capture), ++ 0); ++ ++ ret = devm_snd_soc_register_component(&pdev->dev, &ralink_i2s_component, ++ &ralink_i2s_dai, 1); + if (ret) -+ goto fail; -+ ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); ++ goto err_debugfs; ++ ++ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, ++ &ralink_dmaengine_pcm_config, ++ SND_DMAENGINE_PCM_FLAG_COMPAT); + if (ret) -+ goto fail; -+ data->card.num_links = 1; -+ data->card.dai_link = &data->dai; -+ data->card.dapm_widgets = mt7620_wm8960_dapm_widgets; -+ data->card.num_dapm_widgets = ARRAY_SIZE(mt7620_wm8960_dapm_widgets); ++ goto err_debugfs; + -+ data->card.late_probe = mt7620_wm8960_late_probe; -+ data->card.set_bias_level = mt7620_wm8960_set_bias_level; ++ dev_info(i2s->dev, "mclk %luKHz\n", clk_get_rate(i2s->clk) / 1000000); + -+ platform_set_drvdata(pdev, &data->card); -+ snd_soc_card_set_drvdata(&data->card, data); ++ return 0; + -+ ret = devm_snd_soc_register_card(&pdev->dev, &data->card); -+ if (ret) { -+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); -+ goto fail; -+ } ++err_debugfs: ++ ralink_i2s_debugfs_remove(i2s); + -+ of_node_put(i2s_np); -+ of_node_put(codec_np); -+ -+ return 0; -+fail: -+ if (i2s_np) -+ of_node_put(i2s_np); -+ if (codec_np) -+ of_node_put(codec_np); ++err_clk_disable: ++ clk_disable_unprepare(i2s->clk); + + return ret; +} + -+static int mt7620_wm8960_remove(struct platform_device *pdev) ++static int ralink_i2s_remove(struct platform_device *pdev) +{ ++ struct ralink_i2s *i2s = platform_get_drvdata(pdev); ++ ++ ralink_i2s_debugfs_remove(i2s); ++ clk_disable_unprepare(i2s->clk); ++ + return 0; +} + -+static const struct of_device_id mt7620_wm8960_dt_ids[] = { -+ { .compatible = "mediatek,mt7620-audio-wm8960", }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, mt7620_wm8960_dt_ids); -+ -+static struct platform_driver mt7620_wm8960_driver = { ++static struct platform_driver ralink_i2s_driver = { ++ .probe = ralink_i2s_probe, ++ .remove = ralink_i2s_remove, + .driver = { -+ .name = "mt7620-wm8960", -+ .owner = THIS_MODULE, -+ .pm = &snd_soc_pm_ops, -+ .of_match_table = mt7620_wm8960_dt_ids, ++ .name = DRV_NAME, ++ .of_match_table = ralink_i2s_match_table, + }, -+ .probe = mt7620_wm8960_probe, -+ .remove = mt7620_wm8960_remove, +}; -+module_platform_driver(mt7620_wm8960_driver); ++module_platform_driver(ralink_i2s_driver); + -+MODULE_AUTHOR("Freescale Semiconductor, Inc."); -+MODULE_DESCRIPTION("Freescale i.MX WM8962 ASoC machine driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:mt7620-wm8962"); ++MODULE_AUTHOR("Lars-Peter Clausen, "); ++MODULE_DESCRIPTION("Ralink/MediaTek I2S driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:" DRV_NAME); From d0b42850690d44de0028f30c1dd38e26a31b9749 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Mon, 22 Feb 2016 20:49:25 +0800 Subject: [PATCH 30/37] ramips: update i2s dtsi files Signed-off-by: Michael Lee --- target/linux/ramips/dts/mt7620a.dtsi | 7 +++++-- target/linux/ramips/dts/mt7621.dtsi | 22 ++++++++++++++++++++++ target/linux/ramips/dts/mt7628an.dtsi | 9 ++++++--- target/linux/ramips/dts/rt3050.dtsi | 18 ++++++++++++++++++ target/linux/ramips/dts/rt3352.dtsi | 20 ++++++++++++++++++++ target/linux/ramips/dts/rt3883.dtsi | 20 ++++++++++++++++++++ target/linux/ramips/dts/rt5350.dtsi | 20 ++++++++++++++++++++ 7 files changed, 111 insertions(+), 5 deletions(-) diff --git a/target/linux/ramips/dts/mt7620a.dtsi b/target/linux/ramips/dts/mt7620a.dtsi index 1c957b7d2a71..641d248e6063 100644 --- a/target/linux/ramips/dts/mt7620a.dtsi +++ b/target/linux/ramips/dts/mt7620a.dtsi @@ -192,7 +192,7 @@ }; i2s: i2s@a00 { - compatible = "ralink,mt7620a-i2s"; + compatible = "mediatek,mt7620-i2s"; reg = <0xa00 0x100>; resets = <&rstctrl 17>; @@ -201,8 +201,11 @@ interrupt-parent = <&intc>; interrupts = <10>; + txdma-req = <2>; + rxdma-req = <3>; + dmas = <&gdma 4>, - <&gdma 5>; + <&gdma 6>; dma-names = "tx", "rx"; status = "disabled"; diff --git a/target/linux/ramips/dts/mt7621.dtsi b/target/linux/ramips/dts/mt7621.dtsi index 772f0aabfab9..a8b98ed8c610 100644 --- a/target/linux/ramips/dts/mt7621.dtsi +++ b/target/linux/ramips/dts/mt7621.dtsi @@ -107,6 +107,28 @@ pinctrl-0 = <&i2c_pins>; }; + i2s: i2s@a00 { + compatible = "mediatek,mt7621-i2s"; + reg = <0xa00 0x100>; + + clocks = <&sysclock>; + + resets = <&rstctrl 17>; + reset-names = "i2s"; + + interrupt-parent = <&gic>; + interrupts = ; + + txdma-req = <2>; + rxdma-req = <3>; + + dmas = <&gdma 4>, + <&gdma 6>; + dma-names = "tx", "rx"; + + status = "disabled"; + }; + memc: memc@5000 { compatible = "mtk,mt7621-memc"; reg = <0x300 0x100>; diff --git a/target/linux/ramips/dts/mt7628an.dtsi b/target/linux/ramips/dts/mt7628an.dtsi index 860521999d4b..671aaef386d9 100644 --- a/target/linux/ramips/dts/mt7628an.dtsi +++ b/target/linux/ramips/dts/mt7628an.dtsi @@ -126,7 +126,7 @@ }; i2s: i2s@a00 { - compatible = "ralink,mt7620a-i2s"; + compatible = "mediatek,mt7628-i2s"; reg = <0xa00 0x100>; resets = <&rstctrl 17>; @@ -135,8 +135,11 @@ interrupt-parent = <&intc>; interrupts = <10>; - dmas = <&gdma 2>, - <&gdma 3>; + txdma-req = <2>; + rxdma-req = <3>; + + dmas = <&gdma 4>, + <&gdma 6>; dma-names = "tx", "rx"; status = "disabled"; diff --git a/target/linux/ramips/dts/rt3050.dtsi b/target/linux/ramips/dts/rt3050.dtsi index ff1281b06416..23da1c43ef6a 100644 --- a/target/linux/ramips/dts/rt3050.dtsi +++ b/target/linux/ramips/dts/rt3050.dtsi @@ -182,6 +182,24 @@ pinctrl-0 = <&i2c_pins>; }; + i2s@a00 { + compatible = "ralink,rt3050-i2s"; + reg = <0xa00 0x100>; + + resets = <&rstctrl 17>; + reset-names = "i2s"; + + interrupt-parent = <&intc>; + interrupts = <10>; + + txdma-req = <2>; + + dmas = <&gdma 4>; + dma-names = "tx"; + + status = "disabled"; + }; + spi0: spi@b00 { compatible = "ralink,rt3050-spi", "ralink,rt2880-spi"; reg = <0xb00 0x100>; diff --git a/target/linux/ramips/dts/rt3352.dtsi b/target/linux/ramips/dts/rt3352.dtsi index d010de38a35a..a617281b7510 100644 --- a/target/linux/ramips/dts/rt3352.dtsi +++ b/target/linux/ramips/dts/rt3352.dtsi @@ -162,6 +162,26 @@ pinctrl-0 = <&i2c_pins>; }; + i2s@a00 { + compatible = "ralink,rt3352-i2s"; + reg = <0xa00 0x100>; + + resets = <&rstctrl 17>; + reset-names = "i2s"; + + interrupt-parent = <&intc>; + interrupts = <10>; + + txdma-req = <2>; + rxdma-req = <3>; + + dmas = <&gdma 4>, + <&gdma 6>; + dma-names = "tx", "rx"; + + status = "disabled"; + }; + spi0: spi@b00 { compatible = "ralink,rt3352-spi", "ralink,rt2880-spi"; reg = <0xb00 0x40>; diff --git a/target/linux/ramips/dts/rt3883.dtsi b/target/linux/ramips/dts/rt3883.dtsi index 975e86b1f632..20fe7bfab929 100644 --- a/target/linux/ramips/dts/rt3883.dtsi +++ b/target/linux/ramips/dts/rt3883.dtsi @@ -182,6 +182,26 @@ pinctrl-0 = <&i2c_pins>; }; + i2s@a00 { + compatible = "ralink,rt3883-i2s"; + reg = <0xa00 0x100>; + + resets = <&rstctrl 17>; + reset-names = "i2s"; + + interrupt-parent = <&intc>; + interrupts = <10>; + + txdma-req = <2>; + rxdma-req = <3>; + + dmas = <&gdma 4>, + <&gdma 6>; + dma-names = "tx", "rx"; + + status = "disabled"; + }; + spi0: spi@b00 { compatible = "ralink,rt3883-spi", "ralink,rt2880-spi"; reg = <0xb00 0x40>; diff --git a/target/linux/ramips/dts/rt5350.dtsi b/target/linux/ramips/dts/rt5350.dtsi index f6a170756313..99959bfa359d 100644 --- a/target/linux/ramips/dts/rt5350.dtsi +++ b/target/linux/ramips/dts/rt5350.dtsi @@ -153,6 +153,26 @@ status = "disabled"; }; + i2s@a00 { + compatible = "ralink,rt3352-i2s"; + reg = <0xa00 0x100>; + + resets = <&rstctrl 17>; + reset-names = "i2s"; + + interrupt-parent = <&intc>; + interrupts = <10>; + + txdma-req = <2>; + rxdma-req = <3>; + + dmas = <&gdma 4>, + <&gdma 6>; + dma-names = "tx", "rx"; + + status = "disabled"; + }; + spi0: spi@b00 { compatible = "ralink,rt5350-spi", "ralink,rt2880-spi"; reg = <0xb00 0x40>; From b188d08e57e70c68bc79843aec85cb77920cc970 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Tue, 17 May 2016 21:13:35 +0800 Subject: [PATCH 31/37] ramips: add i2s clocks Signed-off-by: Michael Lee --- ...0720-arch-mips-ralink-add-i2c-clocks.patch | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/target/linux/ramips/patches-4.4/0720-arch-mips-ralink-add-i2c-clocks.patch b/target/linux/ramips/patches-4.4/0720-arch-mips-ralink-add-i2c-clocks.patch index 395883686060..ae262ac97daf 100644 --- a/target/linux/ramips/patches-4.4/0720-arch-mips-ralink-add-i2c-clocks.patch +++ b/target/linux/ramips/patches-4.4/0720-arch-mips-ralink-add-i2c-clocks.patch @@ -1,10 +1,35 @@ --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c -@@ -446,6 +446,7 @@ void __init ralink_clk_init(void) +@@ -389,6 +389,7 @@ void __init ralink_clk_init(void) + unsigned long sys_rate; + unsigned long dram_rate; + unsigned long periph_rate; ++ unsigned long pcmi2s_rate; + + xtal_rate = mt7620_get_xtal_rate(); + +@@ -403,6 +404,7 @@ void __init ralink_clk_init(void) + cpu_rate = MHZ(575); + dram_rate = sys_rate = cpu_rate / 3; + periph_rate = MHZ(40); ++ pcmi2s_rate = MHZ(480); + + ralink_clk_add("10000d00.uartlite", periph_rate); + ralink_clk_add("10000e00.uartlite", periph_rate); +@@ -414,6 +416,7 @@ void __init ralink_clk_init(void) + dram_rate = mt7620_get_dram_rate(pll_rate); + sys_rate = mt7620_get_sys_rate(cpu_rate); + periph_rate = mt7620_get_periph_rate(xtal_rate); ++ pcmi2s_rate = periph_rate; + + pr_debug(RFMT("XTAL") RFMT("CPU_PLL") RFMT("PLL"), + RINT(xtal_rate), RFRAC(xtal_rate), +@@ -435,6 +438,8 @@ void __init ralink_clk_init(void) ralink_clk_add("cpu", cpu_rate); ralink_clk_add("10000100.timer", periph_rate); ralink_clk_add("10000120.watchdog", periph_rate); + ralink_clk_add("10000900.i2c", periph_rate); ++ ralink_clk_add("10000a00.i2s", pcmi2s_rate); ralink_clk_add("10000b00.spi", sys_rate); ralink_clk_add("10000b40.spi", sys_rate); ralink_clk_add("10000c00.uartlite", periph_rate); @@ -20,21 +45,23 @@ ralink_clk_add("480000.wmac", wmac_rate); --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c -@@ -200,6 +200,7 @@ void __init ralink_clk_init(void) +@@ -200,6 +200,8 @@ void __init ralink_clk_init(void) ralink_clk_add("cpu", cpu_rate); ralink_clk_add("sys", sys_rate); + ralink_clk_add("10000900.i2c", uart_rate); ++ ralink_clk_add("10000a00.i2s", uart_rate); ralink_clk_add("10000b00.spi", sys_rate); ralink_clk_add("10000b40.spi", sys_rate); ralink_clk_add("10000100.timer", wdt_rate); --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c -@@ -108,6 +108,7 @@ void __init ralink_clk_init(void) +@@ -108,6 +108,8 @@ void __init ralink_clk_init(void) ralink_clk_add("10000100.timer", sys_rate); ralink_clk_add("10000120.watchdog", sys_rate); ralink_clk_add("10000500.uart", 40000000); + ralink_clk_add("10000900.i2c", 40000000); ++ ralink_clk_add("10000a00.i2s", 40000000); ralink_clk_add("10000b00.spi", sys_rate); ralink_clk_add("10000b40.spi", sys_rate); ralink_clk_add("10000c00.uartlite", 40000000); From af5a0fe5f3477693540d6eda7bbd1adfb3ba1bf2 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Sat, 21 May 2016 21:12:53 +0800 Subject: [PATCH 32/37] ramips: enable wm8960 kernel menuconfig select option Signed-off-by: Michael Lee --- .../patches-4.4/0721-asoc-enable-wm8960-kconfig.patch | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 target/linux/ramips/patches-4.4/0721-asoc-enable-wm8960-kconfig.patch diff --git a/target/linux/ramips/patches-4.4/0721-asoc-enable-wm8960-kconfig.patch b/target/linux/ramips/patches-4.4/0721-asoc-enable-wm8960-kconfig.patch new file mode 100644 index 000000000000..6272b71607ec --- /dev/null +++ b/target/linux/ramips/patches-4.4/0721-asoc-enable-wm8960-kconfig.patch @@ -0,0 +1,11 @@ +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -825,7 +825,7 @@ config SND_SOC_WM8955 + tristate + + config SND_SOC_WM8960 +- tristate ++ tristate "Wolfson Microelectronics WM8960 CODEC" + + config SND_SOC_WM8961 + tristate From 20fcd1be2b4e23b86ec2b843dd6f8eb194467565 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Sat, 28 May 2016 22:22:10 +0800 Subject: [PATCH 33/37] ramips: add support for DuZun DM06 DuZun DM06 is a develop board based on mt7628 64M RAM, 8M SPI Flash, 1 WAN, 1 LAN. wm8960 codec with line out, line in and speaker output. Signed-off-by: Michael Lee --- .../ramips/base-files/etc/board.d/02_network | 4 + target/linux/ramips/base-files/lib/ramips.sh | 3 + .../ramips/base-files/lib/upgrade/platform.sh | 1 + target/linux/ramips/dts/DUZUN-DM06.dts | 155 ++++++++++++++++++ target/linux/ramips/image/mt7628.mk | 8 + 5 files changed, 171 insertions(+) create mode 100644 target/linux/ramips/dts/DUZUN-DM06.dts diff --git a/target/linux/ramips/base-files/etc/board.d/02_network b/target/linux/ramips/base-files/etc/board.d/02_network index 4728c75312ee..6807eede319d 100755 --- a/target/linux/ramips/base-files/etc/board.d/02_network +++ b/target/linux/ramips/base-files/etc/board.d/02_network @@ -172,6 +172,10 @@ ramips_setup_interfaces() wrh-300cr) ucidef_set_interface_lan "eth0" ;; + duzun-dm06) + ucidef_add_switch "switch0" \ + "1:lan" "0:wan" "6@eth0" + ;; e1700|\ mt7620a_mt7530) ucidef_add_switch "switch1" \ diff --git a/target/linux/ramips/base-files/lib/ramips.sh b/target/linux/ramips/base-files/lib/ramips.sh index cbe455d77d58..567e5066f8dd 100755 --- a/target/linux/ramips/base-files/lib/ramips.sh +++ b/target/linux/ramips/base-files/lib/ramips.sh @@ -151,6 +151,9 @@ ramips_board_detect() { *"Dovado Tiny AC") name="tiny-ac" ;; + *"DuZun DM06") + name="duzun-dm06" + ;; *"E1700") name="e1700" ;; diff --git a/target/linux/ramips/base-files/lib/upgrade/platform.sh b/target/linux/ramips/base-files/lib/upgrade/platform.sh index 91c999799f10..c71fc6491758 100755 --- a/target/linux/ramips/base-files/lib/upgrade/platform.sh +++ b/target/linux/ramips/base-files/lib/upgrade/platform.sh @@ -50,6 +50,7 @@ platform_check_image() { dir-620-a1|\ dir-620-d1|\ dir-810l|\ + duzun-dm06|\ e1700|\ esr-9753|\ ex2700|\ diff --git a/target/linux/ramips/dts/DUZUN-DM06.dts b/target/linux/ramips/dts/DUZUN-DM06.dts new file mode 100644 index 000000000000..946a421c3a7a --- /dev/null +++ b/target/linux/ramips/dts/DUZUN-DM06.dts @@ -0,0 +1,155 @@ +/dts-v1/; + +/include/ "mt7628an.dtsi" + +/ { + compatible = "duzun,dm06-mt7628an", "mediatek,mt7628an-soc"; + model = "DuZun DM06"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x4000000>; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + reset { + label = "reset"; + gpios = <&gpio1 14 1>; + linux,code = <0x198>; + }; + + wps { + label = "wps"; + gpios = <&gpio1 6 1>; + linux,code = <0x211>; + }; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "Audio-I2S"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&dailink0_master>; + simple-audio-card,frame-master = <&dailink0_master>; + simple-audio-card,widgets = + "Headphone", "Headphones"; + simple-audio-card,routing = + "Headphones", "HP_L", + "Headphones", "HP_R"; + simple-audio-card,mclk-fs = <256>; + + simple-audio-card,cpu { + sound-dai = <&i2s>; + }; + + dailink0_master: simple-audio-card,codec { + sound-dai = <&codec>; + }; + }; +}; + +&pinctrl { + state_default: pinctrl0 { + gpio { + ralink,group = "wdt", "uart1"; + ralink,function = "gpio"; + }; + }; + + i2s_pins: i2s { + i2s { + ralink,group = "i2s"; + ralink,function = "i2s"; + }; + }; + + wm8960_mclk_pins: wm8960_mclk { + wm8960_mclk { + ralink,group = "refclk"; + ralink,function = "reclk"; + }; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c { + status = "okay"; + + codec: wm8960@1a { + #sound-dai-cells = <0>; + compatible = "wlf,wm8960"; + reg = <0x1a>; + + wlf,shared-lrclk; + }; +}; + +ðernet { + mtd-mac-address = <&factory 0x4>; +}; + +&esw { + mediatek,portmap = <0x3>; + mediatek,portdisable = <0x3c>; +}; + +&i2s { + #sound-dai-cells = <0>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s_pins>, <&wm8960_mclk_pins>; +}; + +&sdhci { + status = "okay"; +}; + +&gdma { + status = "okay"; +}; + +&spi0 { + status = "okay"; + + m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + linux,modalias = "m25p80"; + spi-max-frequency = <60000000>; + m25p,chunked-io = <32>; + m25p,fast-read; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x30000>; + read-only; + }; + + partition@30000 { + label = "u-boot-env"; + reg = <0x30000 0x10000>; + read-only; + }; + + factory: partition@40000 { + label = "factory"; + reg = <0x40000 0x10000>; + read-only; + }; + + partition@50000 { + label = "firmware"; + reg = <0x50000 0x7b0000>; + }; + }; +}; diff --git a/target/linux/ramips/image/mt7628.mk b/target/linux/ramips/image/mt7628.mk index 8274e11f1711..fa7d1e77f267 100644 --- a/target/linux/ramips/image/mt7628.mk +++ b/target/linux/ramips/image/mt7628.mk @@ -25,3 +25,11 @@ define Device/wrtnode2p DEVICE_PACKAGES := kmod-usb2 kmod-usb-ohci kmod-ledtrig-usbdev endef TARGET_DEVICES += wrtnode2p + +define Device/duzun-dm06 + DTS := DUZUN-DM06 + IMAGE_SIZE := $(ralink_default_fw_size_8M) + DEVICE_TITLE := DuZun DM06 + DEVICE_PACKAGES := kmod-usb2 kmod-usb-ohci kmod-ledtrig-usbdev +endef +TARGET_DEVICES += duzun-dm06 From 467fe76d697c7d7091999e26c8cf7ef964b0af62 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Thu, 9 Jun 2016 10:04:23 +0800 Subject: [PATCH 34/37] libunwind: initial version 1.1 The package Makefile was based on work at link [1] with the following changes 1. Disable minidebuginfo support thus no dependency on liblzma 2. Add 2 patches for building against musl-libc and building with mips16 enabled 3. Add LICENSE and DEPENDS info, etc. [1] https://github.com/rpi-openwrt/rpi-packages/tree/master/libs/libunwind Signed-off-by: Yousong Zhou --- package/libs/libunwind/Makefile | 53 +++++++++++++++++++ .../libunwind/patches/001-disable-tests.patch | 22 ++++++++ .../002-fix-building-getcontext_S.patch | 19 +++++++ ...03-fix-missing-ef_reg-defs-with-musl.patch | 47 ++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 package/libs/libunwind/Makefile create mode 100644 package/libs/libunwind/patches/001-disable-tests.patch create mode 100644 package/libs/libunwind/patches/002-fix-building-getcontext_S.patch create mode 100644 package/libs/libunwind/patches/003-fix-missing-ef_reg-defs-with-musl.patch diff --git a/package/libs/libunwind/Makefile b/package/libs/libunwind/Makefile new file mode 100644 index 000000000000..ec19656ec9e9 --- /dev/null +++ b/package/libs/libunwind/Makefile @@ -0,0 +1,53 @@ +# +# Copyright (C) 2008-2013 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=libunwind +PKG_VERSION:=1.1 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=http://download.savannah.gnu.org/releases/libunwind +PKG_MD5SUM:=fb4ea2f6fbbe45bf032cd36e586883ce +PKG_FIXUP:=autoreconf +PKG_INSTALL:=1 + +PKG_LICENSE:=X11 +PKG_LICENSE_FILES:=LICENSE + +PKG_MAINTAINER:=Yousong Zhou + +include $(INCLUDE_DIR)/package.mk + +define Package/libunwind + SECTION:=libs + CATEGORY:=Libraries + TITLE:=The libunwind project + URL:=http://www.nongnu.org/libunwind/ + DEPENDS:=@(mips||mipsel||powerpc||i386||x86_64) +endef + +define Package/libunwind/description + Libunwind defines a portable and efficient C programming interface (API) to determine the call-chain of a program. +endef + +CONFIGURE_ARGS += --enable-minidebuginfo=no + +define Package/libunwind/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libunwin*.so* $(1)/usr/lib/ +endef + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include $(1)/usr/lib/pkgconfig + $(CP) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libunwin*.so* $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/* $(1)/usr/lib/pkgconfig/ +endef + +$(eval $(call BuildPackage,libunwind)) diff --git a/package/libs/libunwind/patches/001-disable-tests.patch b/package/libs/libunwind/patches/001-disable-tests.patch new file mode 100644 index 000000000000..9700fea47763 --- /dev/null +++ b/package/libs/libunwind/patches/001-disable-tests.patch @@ -0,0 +1,22 @@ +--- a/Makefile.am ++++ b/Makefile.am +@@ -36,7 +36,7 @@ + + nodist_include_HEADERS = include/libunwind-common.h + +-SUBDIRS = src tests doc ++SUBDIRS = src doc + + noinst_HEADERS = include/dwarf.h include/dwarf_i.h include/dwarf-eh.h \ + include/compiler.h include/libunwind_i.h include/mempool.h \ +--- a/Makefile.in ++++ b/Makefile.in +@@ -313,7 +313,7 @@ + $(am__append_7) $(am__append_8) $(am__append_9) \ + $(am__append_10) + nodist_include_HEADERS = include/libunwind-common.h +-SUBDIRS = src tests doc ++SUBDIRS = src doc + noinst_HEADERS = include/dwarf.h include/dwarf_i.h include/dwarf-eh.h \ + include/compiler.h include/libunwind_i.h include/mempool.h \ + include/remote.h \ diff --git a/package/libs/libunwind/patches/002-fix-building-getcontext_S.patch b/package/libs/libunwind/patches/002-fix-building-getcontext_S.patch new file mode 100644 index 000000000000..10b1dd1d9098 --- /dev/null +++ b/package/libs/libunwind/patches/002-fix-building-getcontext_S.patch @@ -0,0 +1,19 @@ +diff -uprN a/src/mips/getcontext.S b/src/mips/getcontext.S +--- a/src/mips/getcontext.S 2012-10-06 12:54:38.000000000 +0800 ++++ b/src/mips/getcontext.S 2016-06-08 13:35:25.033051679 +0800 +@@ -24,12 +24,12 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + #include "offsets.h" +-#include + + .text ++ .set nomips16 + + #if _MIPS_SIM == _ABIO32 +-# if __BYTE_ORDER == __BIG_ENDIAN ++# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + # define OFFSET 4 + # else + # define OFFSET 0 + diff --git a/package/libs/libunwind/patches/003-fix-missing-ef_reg-defs-with-musl.patch b/package/libs/libunwind/patches/003-fix-missing-ef_reg-defs-with-musl.patch new file mode 100644 index 000000000000..465abb4ce0b8 --- /dev/null +++ b/package/libs/libunwind/patches/003-fix-missing-ef_reg-defs-with-musl.patch @@ -0,0 +1,47 @@ +diff -uprN a/include/libunwind-mips.h b/include/libunwind-mips.h +--- a/include/libunwind-mips.h 2012-10-06 12:54:38.000000000 +0800 ++++ b/include/libunwind-mips.h 2016-06-08 13:55:55.029436442 +0800 +@@ -111,6 +111,42 @@ typedef enum + } + mips_regnum_t; + ++#ifndef __GLIBC__ ++#include ++ ++/* musl as of 1.1.14 does not export these */ ++#define EF_REG0 6 ++#define EF_REG1 7 ++#define EF_REG2 8 ++#define EF_REG3 9 ++#define EF_REG4 10 ++#define EF_REG5 11 ++#define EF_REG6 12 ++#define EF_REG7 13 ++#define EF_REG8 14 ++#define EF_REG9 15 ++#define EF_REG10 16 ++#define EF_REG11 17 ++#define EF_REG12 18 ++#define EF_REG13 19 ++#define EF_REG14 20 ++#define EF_REG15 21 ++#define EF_REG16 22 ++#define EF_REG17 23 ++#define EF_REG18 24 ++#define EF_REG19 25 ++#define EF_REG20 26 ++#define EF_REG21 27 ++#define EF_REG22 28 ++#define EF_REG23 29 ++#define EF_REG24 30 ++#define EF_REG25 31 ++#define EF_REG28 34 ++#define EF_REG29 35 ++#define EF_REG30 36 ++#define EF_REG31 37 ++#endif ++ + typedef enum + { + UNW_MIPS_ABI_O32, + From 6d657f525ebe09ca0e29852f030e8840880817b1 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Thu, 9 Jun 2016 10:04:24 +0800 Subject: [PATCH 35/37] strace: add option for enabling stack trace support Signed-off-by: Yousong Zhou --- package/devel/strace/Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/package/devel/strace/Makefile b/package/devel/strace/Makefile index 8a0d2e8fb302..df560fd1b7aa 100644 --- a/package/devel/strace/Makefile +++ b/package/devel/strace/Makefile @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=strace PKG_VERSION:=4.11 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_MD5SUM:=a15d2555a7febb56d00c6e1a51c655dc PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz @@ -23,6 +23,7 @@ PKG_LICENSE_FILES:=COPYRIGHT PKG_MAINTAINER:=Felix Fietkau PKG_FIXUP:=autoreconf +PKG_CONFIG_DEPENDS:=CONFIG_PACKAGE_strace_libunwind PKG_INSTALL:=1 include $(INCLUDE_DIR)/package.mk @@ -39,6 +40,7 @@ define Package/strace SECTION:=utils CATEGORY:=Utilities TITLE:=System call tracer + DEPENDS:=+PACKAGE_strace_libunwind:libunwind URL:=http://strace.sourceforge.net/ endef @@ -47,6 +49,13 @@ A useful diagnostic, instructional, and debugging tool. Allows you to track what system calls a program makes while it is running. endef +define Package/strace/config +config PACKAGE_strace_libunwind + bool "Enable stack tracing support using libunwind (experimental)" + default n +endef + +CONFIGURE_ARGS += --with-libunwind=$(if $(CONFIG_PACKAGE_strace_libunwind),yes,no) MAKE_FLAGS := \ CCOPT="$(TARGET_CFLAGS)" From 21dcb0ac63b609a7039a12d67bfeb8e59a396cd6 Mon Sep 17 00:00:00 2001 From: Adrian Panella Date: Fri, 10 Jun 2016 19:10:15 -0500 Subject: [PATCH 36/37] generic: Mangle bootloader's kernel arguments The command-line arguments provided by the boot loader will be appended to a new device tree property: bootloader-args. If there is a property "append-rootblock" in DT under /chosen and a root= option in bootloaders command line it will be parsed and added to DT bootargs with the form: XX. Only command line ATAG will be processed, the rest of the ATAGs sent by bootloader will be ignored. This is usefull in dual boot systems, to get the current root partition without afecting the rest of the system. Signed-off-by: Adrian Panella --- .../996-ATAG_DTB_COMPAT_CMDLINE_MANGLE.patch | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 target/linux/generic/patches-4.4/996-ATAG_DTB_COMPAT_CMDLINE_MANGLE.patch diff --git a/target/linux/generic/patches-4.4/996-ATAG_DTB_COMPAT_CMDLINE_MANGLE.patch b/target/linux/generic/patches-4.4/996-ATAG_DTB_COMPAT_CMDLINE_MANGLE.patch new file mode 100644 index 000000000000..490886ee44da --- /dev/null +++ b/target/linux/generic/patches-4.4/996-ATAG_DTB_COMPAT_CMDLINE_MANGLE.patch @@ -0,0 +1,185 @@ +Author: Adrian Panella +Date: Fri Jun 10 19:10:15 2016 -0500 + +generic: Mangle bootloader's kernel arguments + +The command-line arguments provided by the boot loader will be +appended to a new device tree property: bootloader-args. +If there is a property "append-rootblock" in DT under /chosen +and a root= option in bootloaders command line it will be parsed +and added to DT bootargs with the form: XX. +Only command line ATAG will be processed, the rest of the ATAGs +sent by bootloader will be ignored. +This is usefull in dual boot systems, to get the current root partition +without afecting the rest of the system. + + +Signed-off-by: Adrian Panella + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1927,6 +1927,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN + The command-line arguments provided by the boot loader will be + appended to the the device tree bootargs property. + ++config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ bool "Append rootblock parsing bootloader's kernel arguments" ++ help ++ The command-line arguments provided by the boot loader will be ++ appended to a new device tree property: bootloader-args. ++ If there is a property "append-rootblock" in DT under /chosen ++ and a root= option in bootloaders command line it will be parsed ++ and added to DT bootargs with the form: XX. ++ Only command line ATAG will be processed, the rest of the ATAGs ++ sent by bootloader will be ignored. ++ + endchoice + + config CMDLINE +--- a/arch/arm/boot/compressed/atags_to_fdt.c ++++ b/arch/arm/boot/compressed/atags_to_fdt.c +@@ -3,6 +3,8 @@ + + #if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND) + #define do_extend_cmdline 1 ++#elif defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#define do_extend_cmdline 1 + #else + #define do_extend_cmdline 0 + #endif +@@ -66,6 +68,59 @@ static uint32_t get_cell_size(const void + return cell_size; + } + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ ++static char *append_rootblock(char *dest, const char *str, int len, void *fdt) ++{ ++ char *ptr, *end; ++ char *root="root="; ++ int i, l; ++ const char *rootblock; ++ ++ //ARM doesn't have __HAVE_ARCH_STRSTR, so search manually ++ ptr = str - 1; ++ ++ do { ++ ptr++; ++ //first find an 'r' at the begining or after a space ++ do { ++ ptr = strchr(ptr, 'r'); ++ if(!ptr) return dest; ++ ++ } while (ptr != str && *(ptr-1) != ' '); ++ ++ //then check for the rest ++ for(i = 1; i <= 4; i++) ++ if(*(ptr+i) != *(root+i)) break; ++ ++ } while (i != 5); ++ ++ end = strchr(ptr, ' '); ++ end = end ? (end - 1) : (strchr(ptr, 0) - 1); ++ ++ //find partition number (assumes format root=/dev/mtdXX | /dev/mtdblockXX | yy:XX ) ++ for( i = 0; end >= ptr && *end >= '0' && *end <= '9'; end--, i++); ++ ptr = end + 1; ++ ++ /* if append-rootblock property is set use it to append to command line */ ++ rootblock = getprop(fdt, "/chosen", "append-rootblock", &l); ++ if(rootblock != NULL) { ++ if(*dest != ' ') { ++ *dest = ' '; ++ dest++; ++ len++; ++ } ++ if (len + l + i <= COMMAND_LINE_SIZE) { ++ memcpy(dest, rootblock, l); ++ dest += l - 1; ++ memcpy(dest, ptr, i); ++ dest += i; ++ } ++ } ++ return dest; ++} ++#endif ++ + static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) + { + char cmdline[COMMAND_LINE_SIZE]; +@@ -85,12 +134,21 @@ static void merge_fdt_bootargs(void *fdt + + /* and append the ATAG_CMDLINE */ + if (fdt_cmdline) { ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //save original bootloader args ++ //and append ubi.mtd with root partition number to current cmdline ++ setprop_string(fdt, "/chosen", "bootloader-args", fdt_cmdline); ++ ptr = append_rootblock(ptr, fdt_cmdline, len, fdt); ++ ++#else + len = strlen(fdt_cmdline); + if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) { + *ptr++ = ' '; + memcpy(ptr, fdt_cmdline, len); + ptr += len; + } ++#endif + } + *ptr = '\0'; + +@@ -147,7 +205,9 @@ int atags_to_fdt(void *atag_list, void * + else + setprop_string(fdt, "/chosen", "bootargs", + atag->u.cmdline.cmdline); +- } else if (atag->hdr.tag == ATAG_MEM) { ++ } ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ else if (atag->hdr.tag == ATAG_MEM) { + if (memcount >= sizeof(mem_reg_property)/4) + continue; + if (!atag->u.mem.size) +@@ -186,6 +246,10 @@ int atags_to_fdt(void *atag_list, void * + setprop(fdt, "/memory", "reg", mem_reg_property, + 4 * memcount * memsize); + } ++#else ++ ++ } ++#endif + + return fdt_pack(fdt); + } +--- a/init/main.c ++++ b/init/main.c +@@ -88,6 +88,10 @@ + #include + #include + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#include ++#endif ++ + static int kernel_init(void *); + + extern void init_IRQ(void); +@@ -585,6 +589,18 @@ asmlinkage __visible void __init start_k + page_alloc_init(); + + pr_notice("Kernel command line: %s\n", boot_command_line); ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //Show bootloader's original command line for reference ++ if(of_chosen) { ++ const char *prop = of_get_property(of_chosen, "bootloader-args", NULL); ++ if(prop) ++ pr_notice("Bootloader command line (ignored): %s\n", prop); ++ else ++ pr_notice("Bootloader command line not present\n"); ++ } ++#endif ++ + parse_early_param(); + after_dashes = parse_args("Booting kernel", + static_command_line, __start___param, From 82d7239659be5857aaaad4465131fbdb996c12e4 Mon Sep 17 00:00:00 2001 From: Adrian Panella Date: Fri, 10 Jun 2016 19:10:50 -0500 Subject: [PATCH 37/37] ipq806x: activate ATAG DTB mangle and EA8500 rootblock in dts Signed-off-by: Adrian Panella --- target/linux/ipq806x/config-4.4 | 7 ++++--- .../files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/target/linux/ipq806x/config-4.4 b/target/linux/ipq806x/config-4.4 index 430f1f709f3a..e021ad181c1c 100644 --- a/target/linux/ipq806x/config-4.4 +++ b/target/linux/ipq806x/config-4.4 @@ -37,13 +37,14 @@ CONFIG_ARM_AMBA=y CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ARCH_TIMER=y CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE=y CONFIG_ARM_CCI=y CONFIG_ARM_CCI400_COMMON=y CONFIG_ARM_CCI400_PMU=y CONFIG_ARM_CCI_PMU=y -CONFIG_ARM_ATAG_DTB_COMPAT=y -CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND=y -# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set CONFIG_ARM_CPU_SUSPEND=y CONFIG_ARM_GIC=y CONFIG_ARM_HAS_SG_CHAIN=y diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts index 2c5e1107a13b..4576a715efdf 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts @@ -29,6 +29,7 @@ chosen { bootargs = "console=ttyMSM0,115200n8"; linux,stdout-path = "serial0:115200n8"; + append-rootblock = "ubi.mtd="; /* append to bootargs adding the root deviceblock nbr from bootloader */ }; soc {