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 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/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/toolchain/gdb/patches/arc-2016.03/100-no_extern_inline.patch b/package/devel/gdb-arc/patches/100-no_extern_inline.patch similarity index 100% rename from toolchain/gdb/patches/arc-2016.03/100-no_extern_inline.patch rename to package/devel/gdb-arc/patches/100-no_extern_inline.patch diff --git a/toolchain/gdb/patches/arc-2016.03/110-no_testsuite.patch b/package/devel/gdb-arc/patches/110-no_testsuite.patch similarity index 100% rename from toolchain/gdb/patches/arc-2016.03/110-no_testsuite.patch rename to package/devel/gdb-arc/patches/110-no_testsuite.patch diff --git a/toolchain/gdb/patches/arc-2016.03/120-fix-compile-flag-mismatch.patch b/package/devel/gdb-arc/patches/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 package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch 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 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)" 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/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; + } } 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/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, + 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/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 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..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=$(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_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 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 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 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)) 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 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, diff --git a/target/linux/ipq806x/Makefile b/target/linux/ipq806x/Makefile index 50e9467c5d97..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 @@ -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)) 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 } 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/config-4.4 b/target/linux/ipq806x/config-4.4 index 408fc6d3e9b1..e021ad181c1c 100644 --- a/target/linux/ipq806x/config-4.4 +++ b/target/linux/ipq806x/config-4.4 @@ -37,7 +37,10 @@ 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_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 @@ -249,6 +252,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 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..4576a715efdf --- /dev/null +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts @@ -0,0 +1,381 @@ +#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"; + append-rootblock = "ubi.mtd="; /* append to bootargs adding the root deviceblock nbr from bootloader */ + }; + + 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/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)) 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"; -+}; 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/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>; ++ }; + }; + }; + 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"); + 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"; -+}; 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 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 { 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 + 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), 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)) 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/dts/mt7620a.dtsi b/target/linux/ramips/dts/mt7620a.dtsi index 101cdac7ab2a..641d248e6063 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>; @@ -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"; @@ -281,7 +284,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..a8b98ed8c610 100644 --- a/target/linux/ramips/dts/mt7621.dtsi +++ b/target/linux/ramips/dts/mt7621.dtsi @@ -89,6 +89,46 @@ }; }; + 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>; + }; + + 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>; @@ -144,6 +184,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 { @@ -154,13 +228,6 @@ state_default: pinctrl0 { }; - spi_pins: spi { - spi { - ralink,group = "spi"; - ralink,function = "spi"; - }; - }; - i2c_pins: i2c { i2c { ralink,group = "i2c"; @@ -168,6 +235,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 0b16a9f60d55..671aaef386d9 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>; @@ -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"; @@ -249,7 +252,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/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 caf448bd160c..23da1c43ef6a 100644 --- a/target/linux/ramips/dts/rt3050.dtsi +++ b/target/linux/ramips/dts/rt3050.dtsi @@ -149,6 +149,57 @@ 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"; + }; + + 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>; + }; + + 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>; @@ -195,6 +246,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 0f64576b1eaf..a617281b7510 100644 --- a/target/linux/ramips/dts/rt3352.dtsi +++ b/target/linux/ramips/dts/rt3352.dtsi @@ -146,6 +146,42 @@ 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>; + }; + + 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>; @@ -191,6 +227,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 { @@ -202,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/rt3883.dtsi b/target/linux/ramips/dts/rt3883.dtsi index d92cb65b7ad9..20fe7bfab929 100644 --- a/target/linux/ramips/dts/rt3883.dtsi +++ b/target/linux/ramips/dts/rt3883.dtsi @@ -166,6 +166,42 @@ 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>; + }; + + 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>; @@ -211,6 +247,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 { @@ -222,6 +275,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 05dce6d3e014..99959bfa359d 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>; @@ -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>; @@ -208,6 +228,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 { @@ -219,13 +256,6 @@ state_default: pinctrl0 { }; - spi_pins: spi { - spi { - ralink,group = "spi"; - ralink,function = "spi"; - }; - }; - i2c_pins: i2c { i2c { ralink,group = "i2c"; @@ -233,6 +263,13 @@ }; }; + spi_pins: spi { + spi { + ralink,group = "spi"; + ralink,function = "spi"; + }; + }; + phy_led_pins: phy_led { phy_led { ralink,group = "led"; 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 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"); 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"); 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); 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..ae262ac97daf --- /dev/null +++ b/target/linux/ramips/patches-4.4/0720-arch-mips-ralink-add-i2c-clocks.patch @@ -0,0 +1,67 @@ +--- a/arch/mips/ralink/mt7620.c ++++ b/arch/mips/ralink/mt7620.c +@@ -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); +--- 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,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,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); 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 diff --git a/toolchain/gdb/patches/arc-2016.03-gdb/100-no_extern_inline.patch b/toolchain/gdb/patches/arc-2016.03-gdb/100-no_extern_inline.patch new file mode 100644 index 000000000000..8c18c6e2e746 --- /dev/null +++ b/toolchain/gdb/patches/arc-2016.03-gdb/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/toolchain/gdb/patches/arc-2016.03-gdb/110-no_testsuite.patch b/toolchain/gdb/patches/arc-2016.03-gdb/110-no_testsuite.patch new file mode 100644 index 000000000000..1b284ea7675a --- /dev/null +++ b/toolchain/gdb/patches/arc-2016.03-gdb/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/toolchain/gdb/patches/arc-2016.03-gdb/120-fix-compile-flag-mismatch.patch b/toolchain/gdb/patches/arc-2016.03-gdb/120-fix-compile-flag-mismatch.patch new file mode 100644 index 000000000000..c8b41f264a0c --- /dev/null +++ b/toolchain/gdb/patches/arc-2016.03-gdb/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/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 - ;;