1
0
Fork 0
mirror of https://git.openwrt.org/openwrt/openwrt.git synced 2024-05-06 07:36:26 +02:00

ipq40xx: drop 5.4 kernel

Since 5.10 is now default, no point in keeping
5.4 around.

Signed-off-by: Robert Marko <robert.marko@sartura.hr>
This commit is contained in:
Robert Marko 2021-10-19 20:27:37 +02:00 committed by Paul Spooren
parent 145d896e0e
commit b8ef54f5da
48 changed files with 0 additions and 7415 deletions

View File

@ -1,463 +0,0 @@
CONFIG_ALIGNMENT_TRAP=y
# CONFIG_APQ_GCC_8084 is not set
# CONFIG_APQ_MMCC_8084 is not set
CONFIG_AR40XX_PHY=y
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_IPQ40XX=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
# CONFIG_ARCH_MDM9615 is not set
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
# CONFIG_ARCH_MSM8960 is not set
# CONFIG_ARCH_MSM8974 is not set
# CONFIG_ARCH_MSM8X60 is not set
CONFIG_ARCH_MULTIPLATFORM=y
CONFIG_ARCH_MULTI_V6_V7=y
CONFIG_ARCH_MULTI_V7=y
CONFIG_ARCH_NR_GPIO=0
CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_SUSPEND_POSSIBLE=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_CPUIDLE=y
CONFIG_ARM_CPU_SUSPEND=y
# CONFIG_ARM_CPU_TOPOLOGY is not set
CONFIG_ARM_CRYPTO=y
CONFIG_ARM_GIC=y
CONFIG_ARM_HAS_SG_CHAIN=y
CONFIG_ARM_L1_CACHE_SHIFT=6
CONFIG_ARM_L1_CACHE_SHIFT_6=y
CONFIG_ARM_PATCH_IDIV=y
CONFIG_ARM_PATCH_PHYS_VIRT=y
# CONFIG_ARM_QCOM_CPUFREQ_HW is not set
# CONFIG_ARM_SMMU is not set
CONFIG_ARM_THUMB=y
CONFIG_ARM_UNWIND=y
CONFIG_ARM_VIRT_EXT=y
CONFIG_AT803X_PHY=y
CONFIG_AUTO_ZRELADDR=y
CONFIG_BCH=y
CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BOUNCE=y
# CONFIG_CACHE_L2X0 is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLKSRC_QCOM=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE_PARTITION=y
CONFIG_COMMON_CLK=y
CONFIG_COMMON_CLK_QCOM=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_CPUFREQ_DT=y
CONFIG_CPUFREQ_DT_PLATDEV=y
CONFIG_CPU_32v6K=y
CONFIG_CPU_32v7=y
CONFIG_CPU_ABRT_EV7=y
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_ONDEMAND=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
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_HAS_ASID=y
CONFIG_CPU_IDLE=y
CONFIG_CPU_IDLE_GOV_LADDER=y
CONFIG_CPU_IDLE_GOV_MENU=y
CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
CONFIG_CPU_PABRT_V7=y
CONFIG_CPU_PM=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_SPECTRE=y
CONFIG_CPU_THERMAL=y
CONFIG_CPU_THUMB_CAPABLE=y
CONFIG_CPU_TLB_V7=y
CONFIG_CPU_V7=y
CONFIG_CRC16=y
# CONFIG_CRC32_SARWATE is not set
CONFIG_CRC32_SLICEBY8=y
CONFIG_CRYPTO_ACOMP2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_AES_ARM=y
CONFIG_CRYPTO_AES_ARM_BS=y
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CRYPTD=y
CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_DEV_QCE=y
# CONFIG_CRYPTO_DEV_QCE_ENABLE_ALL is not set
# CONFIG_CRYPTO_DEV_QCE_ENABLE_SHA is not set
CONFIG_CRYPTO_DEV_QCE_ENABLE_SKCIPHER=y
CONFIG_CRYPTO_DEV_QCE_SKCIPHER=y
CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN=512
CONFIG_CRYPTO_DEV_QCOM_RNG=y
CONFIG_CRYPTO_DRBG=y
CONFIG_CRYPTO_DRBG_HMAC=y
CONFIG_CRYPTO_DRBG_MENU=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_HASH_INFO=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_JITTERENTROPY=y
CONFIG_CRYPTO_LIB_DES=y
CONFIG_CRYPTO_LIB_SHA256=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_NULL2=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_RNG_DEFAULT=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA256_ARM=y
CONFIG_CRYPTO_SIMD=y
CONFIG_CRYPTO_XTS=y
CONFIG_CRYPTO_ZSTD=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
CONFIG_DEBUG_MISC=y
CONFIG_DMADEVICES=y
CONFIG_DMA_ENGINE=y
CONFIG_DMA_OF=y
CONFIG_DMA_REMAP=y
CONFIG_DMA_SHARED_BUFFER=y
CONFIG_DMA_VIRTUAL_CHANNELS=y
CONFIG_DTC=y
CONFIG_DT_IDLE_STATES=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_EDAC_ATOMIC_SCRUB=y
CONFIG_EDAC_SUPPORT=y
CONFIG_EEPROM_AT24=y
CONFIG_ESSEDMA=y
CONFIG_EXTCON=y
CONFIG_FIXED_PHY=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_EARLY_IOREMAP=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_PINCONF=y
CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_74X164=y
CONFIG_GPIO_WATCHDOG=y
CONFIG_GPIO_WATCHDOG_ARCH_INITCALL=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAVE_SMP=y
CONFIG_HIGHMEM=y
# CONFIG_HIGHPTE is not set
CONFIG_HWSPINLOCK=y
CONFIG_HWSPINLOCK_QCOM=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_OPTEE=y
CONFIG_HZ_FIXED=0
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
CONFIG_I2C_QUP=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_IOMMU_DEBUGFS is not set
# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
CONFIG_IOMMU_SUPPORT=y
CONFIG_IO_URING=y
CONFIG_IPQ_GCC_4019=y
# CONFIG_IPQ_GCC_806X is not set
# CONFIG_IPQ_GCC_8074 is not set
# CONFIG_IPQ_LCC_806X is not set
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=y
# CONFIG_KPSS_XCC is not set
# CONFIG_KRAITCC is not set
CONFIG_LEDS_LP5523=y
CONFIG_LEDS_LP5562=y
CONFIG_LEDS_LP55XX_COMMON=y
CONFIG_LEDS_TLC591XX=y
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MDIO_BITBANG=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_GPIO=y
CONFIG_MDIO_IPQ4019=y
# CONFIG_MDM_GCC_9615 is not set
# CONFIG_MDM_LCC_9615 is not set
CONFIG_MEMFD_CREATE=y
# CONFIG_MFD_QCOM_RPM is not set
# CONFIG_MFD_SPMI_PMIC is not set
CONFIG_MFD_SYSCON=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_MIGRATION=y
CONFIG_MMC=y
CONFIG_MMC_BLOCK=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_IO_ACCESSORS=y
CONFIG_MMC_SDHCI_MSM=y
# CONFIG_MMC_SDHCI_PCI is not set
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MSM_GCC_8660 is not set
# CONFIG_MSM_GCC_8916 is not set
# CONFIG_MSM_GCC_8960 is not set
# CONFIG_MSM_GCC_8974 is not set
# CONFIG_MSM_GCC_8994 is not set
# CONFIG_MSM_GCC_8996 is not set
# CONFIG_MSM_GCC_8998 is not set
# CONFIG_MSM_LCC_8960 is not set
# CONFIG_MSM_MMCC_8960 is not set
# CONFIG_MSM_MMCC_8974 is not set
# CONFIG_MSM_MMCC_8996 is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_NAND_CORE=y
CONFIG_MTD_NAND_ECC_SW_BCH=y
CONFIG_MTD_NAND_ECC_SW_HAMMING=y
CONFIG_MTD_NAND_QCOM=y
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_SPI_NAND=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_FIT_FW=y
CONFIG_MTD_SPLIT_WRGG_FW=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
CONFIG_MTD_UBI_BLOCK=y
CONFIG_MTD_UBI_WL_THRESHOLD=4096
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_NLS=y
CONFIG_NO_HZ=y
CONFIG_NO_HZ_COMMON=y
CONFIG_NO_HZ_IDLE=y
CONFIG_NR_CPUS=4
CONFIG_NVMEM=y
CONFIG_NVMEM_SYSFS=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_OLD_SIGACTION=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_OPTEE=y
CONFIG_OPTEE_SHM_NUM_PRIV_PAGES=1
CONFIG_PADATA=y
CONFIG_PAGE_OFFSET=0xC0000000
CONFIG_PCI=y
CONFIG_PCIEAER=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIE_DW=y
CONFIG_PCIE_DW_HOST=y
CONFIG_PCIE_QCOM=y
CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
# CONFIG_PHY_QCOM_APQ8064_SATA is not set
CONFIG_PHY_QCOM_IPQ4019_USB=y
# CONFIG_PHY_QCOM_IPQ806X_SATA is not set
# CONFIG_PHY_QCOM_PCIE2 is not set
# CONFIG_PHY_QCOM_QMP is not set
# CONFIG_PHY_QCOM_QUSB2 is not set
# CONFIG_PHY_QCOM_UFS is not set
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_APQ8064 is not set
# CONFIG_PINCTRL_APQ8084 is not set
CONFIG_PINCTRL_IPQ4019=y
# CONFIG_PINCTRL_IPQ8064 is not set
# CONFIG_PINCTRL_IPQ8074 is not set
# CONFIG_PINCTRL_MDM9615 is not set
CONFIG_PINCTRL_MSM=y
# CONFIG_PINCTRL_MSM8660 is not set
# CONFIG_PINCTRL_MSM8916 is not set
# CONFIG_PINCTRL_MSM8960 is not set
# CONFIG_PINCTRL_MSM8994 is not set
# CONFIG_PINCTRL_MSM8996 is not set
# CONFIG_PINCTRL_MSM8998 is not set
# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set
# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set
# CONFIG_PINCTRL_QCS404 is not set
# CONFIG_PINCTRL_SC7180 is not set
# CONFIG_PINCTRL_SDM660 is not set
# CONFIG_PINCTRL_SDM845 is not set
# CONFIG_PINCTRL_SM8150 is not set
CONFIG_PM_OPP=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_MSM=y
CONFIG_POWER_SUPPLY=y
CONFIG_PPS=y
CONFIG_PRINTK_TIME=y
CONFIG_PTP_1588_CLOCK=y
CONFIG_QCA807X_PHY=y
CONFIG_QCOM_A53PLL=y
CONFIG_QCOM_BAM_DMA=y
# CONFIG_QCOM_COMMAND_DB is not set
# CONFIG_QCOM_EBI2 is not set
# CONFIG_QCOM_GENI_SE is not set
# CONFIG_QCOM_GSBI is not set
# CONFIG_QCOM_HFPLL is not set
# CONFIG_QCOM_IOMMU is not set
# CONFIG_QCOM_LLCC is not set
# CONFIG_QCOM_PDC is not set
CONFIG_QCOM_PM=y
CONFIG_QCOM_QFPROM=y
# CONFIG_QCOM_RMTFS_MEM is not set
CONFIG_QCOM_SCM=y
CONFIG_QCOM_SCM_32=y
# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set
CONFIG_QCOM_SMEM=y
# CONFIG_QCOM_SMSM is not set
# CONFIG_QCOM_SOCINFO is not set
CONFIG_QCOM_TCSR=y
# CONFIG_QCOM_TSENS is not set
CONFIG_QCOM_WDT=y
# CONFIG_QCS_GCC_404 is not set
# CONFIG_QCS_TURING_404 is not set
# CONFIG_QRTR is not set
CONFIG_RAS=y
CONFIG_RATIONAL=y
CONFIG_REFCOUNT_FULL=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MMIO=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
# CONFIG_REGULATOR_QCOM_SPMI is not set
CONFIG_REGULATOR_VCTRL=y
CONFIG_REGULATOR_VQMMC_IPQ4019=y
CONFIG_RESET_CONTROLLER=y
# CONFIG_RESET_QCOM_AOSS is not set
# CONFIG_RESET_QCOM_PDC is not set
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_I2C_AND_SPI=y
CONFIG_RTC_MC146818_LIB=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
# CONFIG_SDM_CAMCC_845 is not set
# CONFIG_SDM_DISPCC_845 is not set
# CONFIG_SDM_GCC_660 is not set
# CONFIG_SDM_GCC_845 is not set
# CONFIG_SDM_GPUCC_845 is not set
# CONFIG_SDM_LPASSCC_845 is not set
# CONFIG_SDM_VIDEOCC_845 is not set
CONFIG_SERIAL_8250_FSL=y
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SGL_ALLOC=y
CONFIG_SMP=y
CONFIG_SMP_ON_UP=y
# CONFIG_SM_GCC_8150 is not set
CONFIG_SPARSE_IRQ=y
CONFIG_SPI=y
CONFIG_SPI_BITBANG=y
CONFIG_SPI_GPIO=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SPI_QUP=y
CONFIG_SPMI=y
CONFIG_SPMI_MSM_PMIC_ARB=y
# CONFIG_SPMI_PMIC_CLKDIV is not set
CONFIG_SRCU=y
CONFIG_SWCONFIG=y
CONFIG_SWCONFIG_LEDS=y
CONFIG_SWPHY=y
CONFIG_SWP_EMULATE=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_TEE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_OF=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
CONFIG_UBIFS_FS=y
CONFIG_UEVENT_HELPER_PATH=""
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
CONFIG_UNWINDER_ARM=y
CONFIG_USB=y
CONFIG_USB_COMMON=y
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_VFP=y
CONFIG_VFPv3=y
CONFIG_WATCHDOG_CORE=y
CONFIG_XPS=y
CONFIG_XXHASH=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_ZSTD_COMPRESS=y
CONFIG_ZSTD_DECOMPRESS=y

View File

@ -1,1890 +0,0 @@
/*
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
*
* 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 <linux/bitfield.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/bitops.h>
#include <linux/switch.h>
#include <linux/delay.h>
#include <linux/phy.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/lockdep.h>
#include <linux/workqueue.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_mdio.h>
#include <linux/mdio.h>
#include <linux/gpio.h>
#include "ar40xx.h"
static struct ar40xx_priv *ar40xx_priv;
#define MIB_DESC(_s , _o, _n) \
{ \
.size = (_s), \
.offset = (_o), \
.name = (_n), \
}
static const struct ar40xx_mib_desc ar40xx_mibs[] = {
MIB_DESC(1, AR40XX_STATS_RXBROAD, "RxBroad"),
MIB_DESC(1, AR40XX_STATS_RXPAUSE, "RxPause"),
MIB_DESC(1, AR40XX_STATS_RXMULTI, "RxMulti"),
MIB_DESC(1, AR40XX_STATS_RXFCSERR, "RxFcsErr"),
MIB_DESC(1, AR40XX_STATS_RXALIGNERR, "RxAlignErr"),
MIB_DESC(1, AR40XX_STATS_RXRUNT, "RxRunt"),
MIB_DESC(1, AR40XX_STATS_RXFRAGMENT, "RxFragment"),
MIB_DESC(1, AR40XX_STATS_RX64BYTE, "Rx64Byte"),
MIB_DESC(1, AR40XX_STATS_RX128BYTE, "Rx128Byte"),
MIB_DESC(1, AR40XX_STATS_RX256BYTE, "Rx256Byte"),
MIB_DESC(1, AR40XX_STATS_RX512BYTE, "Rx512Byte"),
MIB_DESC(1, AR40XX_STATS_RX1024BYTE, "Rx1024Byte"),
MIB_DESC(1, AR40XX_STATS_RX1518BYTE, "Rx1518Byte"),
MIB_DESC(1, AR40XX_STATS_RXMAXBYTE, "RxMaxByte"),
MIB_DESC(1, AR40XX_STATS_RXTOOLONG, "RxTooLong"),
MIB_DESC(2, AR40XX_STATS_RXGOODBYTE, "RxGoodByte"),
MIB_DESC(2, AR40XX_STATS_RXBADBYTE, "RxBadByte"),
MIB_DESC(1, AR40XX_STATS_RXOVERFLOW, "RxOverFlow"),
MIB_DESC(1, AR40XX_STATS_FILTERED, "Filtered"),
MIB_DESC(1, AR40XX_STATS_TXBROAD, "TxBroad"),
MIB_DESC(1, AR40XX_STATS_TXPAUSE, "TxPause"),
MIB_DESC(1, AR40XX_STATS_TXMULTI, "TxMulti"),
MIB_DESC(1, AR40XX_STATS_TXUNDERRUN, "TxUnderRun"),
MIB_DESC(1, AR40XX_STATS_TX64BYTE, "Tx64Byte"),
MIB_DESC(1, AR40XX_STATS_TX128BYTE, "Tx128Byte"),
MIB_DESC(1, AR40XX_STATS_TX256BYTE, "Tx256Byte"),
MIB_DESC(1, AR40XX_STATS_TX512BYTE, "Tx512Byte"),
MIB_DESC(1, AR40XX_STATS_TX1024BYTE, "Tx1024Byte"),
MIB_DESC(1, AR40XX_STATS_TX1518BYTE, "Tx1518Byte"),
MIB_DESC(1, AR40XX_STATS_TXMAXBYTE, "TxMaxByte"),
MIB_DESC(1, AR40XX_STATS_TXOVERSIZE, "TxOverSize"),
MIB_DESC(2, AR40XX_STATS_TXBYTE, "TxByte"),
MIB_DESC(1, AR40XX_STATS_TXCOLLISION, "TxCollision"),
MIB_DESC(1, AR40XX_STATS_TXABORTCOL, "TxAbortCol"),
MIB_DESC(1, AR40XX_STATS_TXMULTICOL, "TxMultiCol"),
MIB_DESC(1, AR40XX_STATS_TXSINGLECOL, "TxSingleCol"),
MIB_DESC(1, AR40XX_STATS_TXEXCDEFER, "TxExcDefer"),
MIB_DESC(1, AR40XX_STATS_TXDEFER, "TxDefer"),
MIB_DESC(1, AR40XX_STATS_TXLATECOL, "TxLateCol"),
};
static u32
ar40xx_read(struct ar40xx_priv *priv, int reg)
{
return readl(priv->hw_addr + reg);
}
static u32
ar40xx_psgmii_read(struct ar40xx_priv *priv, int reg)
{
return readl(priv->psgmii_hw_addr + reg);
}
static void
ar40xx_write(struct ar40xx_priv *priv, int reg, u32 val)
{
writel(val, priv->hw_addr + reg);
}
static u32
ar40xx_rmw(struct ar40xx_priv *priv, int reg, u32 mask, u32 val)
{
u32 ret;
ret = ar40xx_read(priv, reg);
ret &= ~mask;
ret |= val;
ar40xx_write(priv, reg, ret);
return ret;
}
static void
ar40xx_psgmii_write(struct ar40xx_priv *priv, int reg, u32 val)
{
writel(val, priv->psgmii_hw_addr + reg);
}
static void
ar40xx_phy_dbg_write(struct ar40xx_priv *priv, int phy_addr,
u16 dbg_addr, u16 dbg_data)
{
struct mii_bus *bus = priv->mii_bus;
mutex_lock(&bus->mdio_lock);
bus->write(bus, phy_addr, AR40XX_MII_ATH_DBG_ADDR, dbg_addr);
bus->write(bus, phy_addr, AR40XX_MII_ATH_DBG_DATA, dbg_data);
mutex_unlock(&bus->mdio_lock);
}
static void
ar40xx_phy_dbg_read(struct ar40xx_priv *priv, int phy_addr,
u16 dbg_addr, u16 *dbg_data)
{
struct mii_bus *bus = priv->mii_bus;
mutex_lock(&bus->mdio_lock);
bus->write(bus, phy_addr, AR40XX_MII_ATH_DBG_ADDR, dbg_addr);
*dbg_data = bus->read(bus, phy_addr, AR40XX_MII_ATH_DBG_DATA);
mutex_unlock(&bus->mdio_lock);
}
static void
ar40xx_phy_mmd_write(struct ar40xx_priv *priv, u32 phy_id,
u16 mmd_num, u16 reg_id, u16 reg_val)
{
struct mii_bus *bus = priv->mii_bus;
mutex_lock(&bus->mdio_lock);
bus->write(bus, phy_id,
AR40XX_MII_ATH_MMD_ADDR, mmd_num);
bus->write(bus, phy_id,
AR40XX_MII_ATH_MMD_DATA, reg_id);
bus->write(bus, phy_id,
AR40XX_MII_ATH_MMD_ADDR,
0x4000 | mmd_num);
bus->write(bus, phy_id,
AR40XX_MII_ATH_MMD_DATA, reg_val);
mutex_unlock(&bus->mdio_lock);
}
static u16
ar40xx_phy_mmd_read(struct ar40xx_priv *priv, u32 phy_id,
u16 mmd_num, u16 reg_id)
{
u16 value;
struct mii_bus *bus = priv->mii_bus;
mutex_lock(&bus->mdio_lock);
bus->write(bus, phy_id,
AR40XX_MII_ATH_MMD_ADDR, mmd_num);
bus->write(bus, phy_id,
AR40XX_MII_ATH_MMD_DATA, reg_id);
bus->write(bus, phy_id,
AR40XX_MII_ATH_MMD_ADDR,
0x4000 | mmd_num);
value = bus->read(bus, phy_id, AR40XX_MII_ATH_MMD_DATA);
mutex_unlock(&bus->mdio_lock);
return value;
}
/* Start of swconfig support */
static void
ar40xx_phy_poll_reset(struct ar40xx_priv *priv)
{
u32 i, in_reset, retries = 500;
struct mii_bus *bus = priv->mii_bus;
/* Assume RESET was recently issued to some or all of the phys */
in_reset = GENMASK(AR40XX_NUM_PHYS - 1, 0);
while (retries--) {
/* 1ms should be plenty of time.
* 802.3 spec allows for a max wait time of 500ms
*/
usleep_range(1000, 2000);
for (i = 0; i < AR40XX_NUM_PHYS; i++) {
int val;
/* skip devices which have completed reset */
if (!(in_reset & BIT(i)))
continue;
val = mdiobus_read(bus, i, MII_BMCR);
if (val < 0)
continue;
/* mark when phy is no longer in reset state */
if (!(val & BMCR_RESET))
in_reset &= ~BIT(i);
}
if (!in_reset)
return;
}
dev_warn(&bus->dev, "Failed to reset all phys! (in_reset: 0x%x)\n",
in_reset);
}
static void
ar40xx_phy_init(struct ar40xx_priv *priv)
{
int i;
struct mii_bus *bus;
u16 val;
bus = priv->mii_bus;
for (i = 0; i < AR40XX_NUM_PORTS - 1; i++) {
ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_0, &val);
val &= ~AR40XX_PHY_MANU_CTRL_EN;
ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_0, val);
mdiobus_write(bus, i,
MII_ADVERTISE, ADVERTISE_ALL |
ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM);
mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
}
ar40xx_phy_poll_reset(priv);
}
static void
ar40xx_port_phy_linkdown(struct ar40xx_priv *priv)
{
struct mii_bus *bus;
int i;
u16 val;
bus = priv->mii_bus;
for (i = 0; i < AR40XX_NUM_PORTS - 1; i++) {
mdiobus_write(bus, i, MII_CTRL1000, 0);
mdiobus_write(bus, i, MII_ADVERTISE, 0);
mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_0, &val);
val |= AR40XX_PHY_MANU_CTRL_EN;
ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_0, val);
/* disable transmit */
ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_2, &val);
val &= 0xf00f;
ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_2, val);
}
}
static void
ar40xx_set_mirror_regs(struct ar40xx_priv *priv)
{
int port;
/* reset all mirror registers */
ar40xx_rmw(priv, AR40XX_REG_FWD_CTRL0,
AR40XX_FWD_CTRL0_MIRROR_PORT,
(0xF << AR40XX_FWD_CTRL0_MIRROR_PORT_S));
for (port = 0; port < AR40XX_NUM_PORTS; port++) {
ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(port),
AR40XX_PORT_LOOKUP_ING_MIRROR_EN, 0);
ar40xx_rmw(priv, AR40XX_REG_PORT_HOL_CTRL1(port),
AR40XX_PORT_HOL_CTRL1_EG_MIRROR_EN, 0);
}
/* now enable mirroring if necessary */
if (priv->source_port >= AR40XX_NUM_PORTS ||
priv->monitor_port >= AR40XX_NUM_PORTS ||
priv->source_port == priv->monitor_port) {
return;
}
ar40xx_rmw(priv, AR40XX_REG_FWD_CTRL0,
AR40XX_FWD_CTRL0_MIRROR_PORT,
(priv->monitor_port << AR40XX_FWD_CTRL0_MIRROR_PORT_S));
if (priv->mirror_rx)
ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(priv->source_port), 0,
AR40XX_PORT_LOOKUP_ING_MIRROR_EN);
if (priv->mirror_tx)
ar40xx_rmw(priv, AR40XX_REG_PORT_HOL_CTRL1(priv->source_port),
0, AR40XX_PORT_HOL_CTRL1_EG_MIRROR_EN);
}
static int
ar40xx_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
u8 ports = priv->vlan_table[val->port_vlan];
int i;
val->len = 0;
for (i = 0; i < dev->ports; i++) {
struct switch_port *p;
if (!(ports & BIT(i)))
continue;
p = &val->value.ports[val->len++];
p->id = i;
if ((priv->vlan_tagged & BIT(i)) ||
(priv->pvid[i] != val->port_vlan))
p->flags = BIT(SWITCH_PORT_FLAG_TAGGED);
else
p->flags = 0;
}
return 0;
}
static int
ar40xx_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
u8 *vt = &priv->vlan_table[val->port_vlan];
int i;
*vt = 0;
for (i = 0; i < val->len; i++) {
struct switch_port *p = &val->value.ports[i];
if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED)) {
if (val->port_vlan == priv->pvid[p->id])
priv->vlan_tagged |= BIT(p->id);
} else {
priv->vlan_tagged &= ~BIT(p->id);
priv->pvid[p->id] = val->port_vlan;
}
*vt |= BIT(p->id);
}
return 0;
}
static int
ar40xx_reg_wait(struct ar40xx_priv *priv, u32 reg, u32 mask, u32 val,
unsigned timeout)
{
int i;
for (i = 0; i < timeout; i++) {
u32 t;
t = ar40xx_read(priv, reg);
if ((t & mask) == val)
return 0;
usleep_range(1000, 2000);
}
return -ETIMEDOUT;
}
static int
ar40xx_mib_op(struct ar40xx_priv *priv, u32 op)
{
int ret;
lockdep_assert_held(&priv->mib_lock);
/* Capture the hardware statistics for all ports */
ar40xx_rmw(priv, AR40XX_REG_MIB_FUNC,
AR40XX_MIB_FUNC, (op << AR40XX_MIB_FUNC_S));
/* Wait for the capturing to complete. */
ret = ar40xx_reg_wait(priv, AR40XX_REG_MIB_FUNC,
AR40XX_MIB_BUSY, 0, 10);
return ret;
}
static void
ar40xx_mib_fetch_port_stat(struct ar40xx_priv *priv, int port, bool flush)
{
unsigned int base;
u64 *mib_stats;
int i;
u32 num_mibs = ARRAY_SIZE(ar40xx_mibs);
WARN_ON(port >= priv->dev.ports);
lockdep_assert_held(&priv->mib_lock);
base = AR40XX_REG_PORT_STATS_START +
AR40XX_REG_PORT_STATS_LEN * port;
mib_stats = &priv->mib_stats[port * num_mibs];
if (flush) {
u32 len;
len = num_mibs * sizeof(*mib_stats);
memset(mib_stats, 0, len);
return;
}
for (i = 0; i < num_mibs; i++) {
const struct ar40xx_mib_desc *mib;
u64 t;
mib = &ar40xx_mibs[i];
t = ar40xx_read(priv, base + mib->offset);
if (mib->size == 2) {
u64 hi;
hi = ar40xx_read(priv, base + mib->offset + 4);
t |= hi << 32;
}
mib_stats[i] += t;
}
}
static int
ar40xx_mib_capture(struct ar40xx_priv *priv)
{
return ar40xx_mib_op(priv, AR40XX_MIB_FUNC_CAPTURE);
}
static int
ar40xx_mib_flush(struct ar40xx_priv *priv)
{
return ar40xx_mib_op(priv, AR40XX_MIB_FUNC_FLUSH);
}
static int
ar40xx_sw_set_reset_mibs(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
unsigned int len;
int ret;
u32 num_mibs = ARRAY_SIZE(ar40xx_mibs);
mutex_lock(&priv->mib_lock);
len = priv->dev.ports * num_mibs * sizeof(*priv->mib_stats);
memset(priv->mib_stats, 0, len);
ret = ar40xx_mib_flush(priv);
mutex_unlock(&priv->mib_lock);
return ret;
}
static int
ar40xx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
priv->vlan = !!val->value.i;
return 0;
}
static int
ar40xx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
val->value.i = priv->vlan;
return 0;
}
static int
ar40xx_sw_set_mirror_rx_enable(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
mutex_lock(&priv->reg_mutex);
priv->mirror_rx = !!val->value.i;
ar40xx_set_mirror_regs(priv);
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
ar40xx_sw_get_mirror_rx_enable(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
mutex_lock(&priv->reg_mutex);
val->value.i = priv->mirror_rx;
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
ar40xx_sw_set_mirror_tx_enable(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
mutex_lock(&priv->reg_mutex);
priv->mirror_tx = !!val->value.i;
ar40xx_set_mirror_regs(priv);
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
ar40xx_sw_get_mirror_tx_enable(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
mutex_lock(&priv->reg_mutex);
val->value.i = priv->mirror_tx;
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
ar40xx_sw_set_mirror_monitor_port(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
mutex_lock(&priv->reg_mutex);
priv->monitor_port = val->value.i;
ar40xx_set_mirror_regs(priv);
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
ar40xx_sw_get_mirror_monitor_port(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
mutex_lock(&priv->reg_mutex);
val->value.i = priv->monitor_port;
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
ar40xx_sw_set_mirror_source_port(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
mutex_lock(&priv->reg_mutex);
priv->source_port = val->value.i;
ar40xx_set_mirror_regs(priv);
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
ar40xx_sw_get_mirror_source_port(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
mutex_lock(&priv->reg_mutex);
val->value.i = priv->source_port;
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
ar40xx_sw_set_linkdown(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
if (val->value.i == 1)
ar40xx_port_phy_linkdown(priv);
else
ar40xx_phy_init(priv);
return 0;
}
static int
ar40xx_sw_set_port_reset_mib(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
int port;
int ret;
port = val->port_vlan;
if (port >= dev->ports)
return -EINVAL;
mutex_lock(&priv->mib_lock);
ret = ar40xx_mib_capture(priv);
if (ret)
goto unlock;
ar40xx_mib_fetch_port_stat(priv, port, true);
unlock:
mutex_unlock(&priv->mib_lock);
return ret;
}
static int
ar40xx_sw_get_port_mib(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
u64 *mib_stats;
int port;
int ret;
char *buf = priv->buf;
int i, len = 0;
u32 num_mibs = ARRAY_SIZE(ar40xx_mibs);
port = val->port_vlan;
if (port >= dev->ports)
return -EINVAL;
mutex_lock(&priv->mib_lock);
ret = ar40xx_mib_capture(priv);
if (ret)
goto unlock;
ar40xx_mib_fetch_port_stat(priv, port, false);
len += snprintf(buf + len, sizeof(priv->buf) - len,
"Port %d MIB counters\n",
port);
mib_stats = &priv->mib_stats[port * num_mibs];
for (i = 0; i < num_mibs; i++)
len += snprintf(buf + len, sizeof(priv->buf) - len,
"%-12s: %llu\n",
ar40xx_mibs[i].name,
mib_stats[i]);
val->value.s = buf;
val->len = len;
unlock:
mutex_unlock(&priv->mib_lock);
return ret;
}
static int
ar40xx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
priv->vlan_id[val->port_vlan] = val->value.i;
return 0;
}
static int
ar40xx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
val->value.i = priv->vlan_id[val->port_vlan];
return 0;
}
static int
ar40xx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
*vlan = priv->pvid[port];
return 0;
}
static int
ar40xx_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
/* make sure no invalid PVIDs get set */
if (vlan >= dev->vlans)
return -EINVAL;
priv->pvid[port] = vlan;
return 0;
}
static void
ar40xx_read_port_link(struct ar40xx_priv *priv, int port,
struct switch_port_link *link)
{
u32 status;
u32 speed;
memset(link, 0, sizeof(*link));
status = ar40xx_read(priv, AR40XX_REG_PORT_STATUS(port));
link->aneg = !!(status & AR40XX_PORT_AUTO_LINK_EN);
if (link->aneg || (port != AR40XX_PORT_CPU))
link->link = !!(status & AR40XX_PORT_STATUS_LINK_UP);
else
link->link = true;
if (!link->link)
return;
link->duplex = !!(status & AR40XX_PORT_DUPLEX);
link->tx_flow = !!(status & AR40XX_PORT_STATUS_TXFLOW);
link->rx_flow = !!(status & AR40XX_PORT_STATUS_RXFLOW);
speed = (status & AR40XX_PORT_SPEED) >>
AR40XX_PORT_STATUS_SPEED_S;
switch (speed) {
case AR40XX_PORT_SPEED_10M:
link->speed = SWITCH_PORT_SPEED_10;
break;
case AR40XX_PORT_SPEED_100M:
link->speed = SWITCH_PORT_SPEED_100;
break;
case AR40XX_PORT_SPEED_1000M:
link->speed = SWITCH_PORT_SPEED_1000;
break;
default:
link->speed = SWITCH_PORT_SPEED_UNKNOWN;
break;
}
}
static int
ar40xx_sw_get_port_link(struct switch_dev *dev, int port,
struct switch_port_link *link)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
ar40xx_read_port_link(priv, port, link);
return 0;
}
static const struct switch_attr ar40xx_sw_attr_globals[] = {
{
.type = SWITCH_TYPE_INT,
.name = "enable_vlan",
.description = "Enable VLAN mode",
.set = ar40xx_sw_set_vlan,
.get = ar40xx_sw_get_vlan,
.max = 1
},
{
.type = SWITCH_TYPE_NOVAL,
.name = "reset_mibs",
.description = "Reset all MIB counters",
.set = ar40xx_sw_set_reset_mibs,
},
{
.type = SWITCH_TYPE_INT,
.name = "enable_mirror_rx",
.description = "Enable mirroring of RX packets",
.set = ar40xx_sw_set_mirror_rx_enable,
.get = ar40xx_sw_get_mirror_rx_enable,
.max = 1
},
{
.type = SWITCH_TYPE_INT,
.name = "enable_mirror_tx",
.description = "Enable mirroring of TX packets",
.set = ar40xx_sw_set_mirror_tx_enable,
.get = ar40xx_sw_get_mirror_tx_enable,
.max = 1
},
{
.type = SWITCH_TYPE_INT,
.name = "mirror_monitor_port",
.description = "Mirror monitor port",
.set = ar40xx_sw_set_mirror_monitor_port,
.get = ar40xx_sw_get_mirror_monitor_port,
.max = AR40XX_NUM_PORTS - 1
},
{
.type = SWITCH_TYPE_INT,
.name = "mirror_source_port",
.description = "Mirror source port",
.set = ar40xx_sw_set_mirror_source_port,
.get = ar40xx_sw_get_mirror_source_port,
.max = AR40XX_NUM_PORTS - 1
},
{
.type = SWITCH_TYPE_INT,
.name = "linkdown",
.description = "Link down all the PHYs",
.set = ar40xx_sw_set_linkdown,
.max = 1
},
};
static const struct switch_attr ar40xx_sw_attr_port[] = {
{
.type = SWITCH_TYPE_NOVAL,
.name = "reset_mib",
.description = "Reset single port MIB counters",
.set = ar40xx_sw_set_port_reset_mib,
},
{
.type = SWITCH_TYPE_STRING,
.name = "mib",
.description = "Get port's MIB counters",
.set = NULL,
.get = ar40xx_sw_get_port_mib,
},
};
const struct switch_attr ar40xx_sw_attr_vlan[] = {
{
.type = SWITCH_TYPE_INT,
.name = "vid",
.description = "VLAN ID (0-4094)",
.set = ar40xx_sw_set_vid,
.get = ar40xx_sw_get_vid,
.max = 4094,
},
};
/* End of swconfig support */
static int
ar40xx_wait_bit(struct ar40xx_priv *priv, int reg, u32 mask, u32 val)
{
int timeout = 20;
u32 t;
while (1) {
t = ar40xx_read(priv, reg);
if ((t & mask) == val)
return 0;
if (timeout-- <= 0)
break;
usleep_range(10, 20);
}
pr_err("ar40xx: timeout for reg %08x: %08x & %08x != %08x\n",
(unsigned int)reg, t, mask, val);
return -ETIMEDOUT;
}
static int
ar40xx_atu_flush(struct ar40xx_priv *priv)
{
int ret;
ret = ar40xx_wait_bit(priv, AR40XX_REG_ATU_FUNC,
AR40XX_ATU_FUNC_BUSY, 0);
if (!ret)
ar40xx_write(priv, AR40XX_REG_ATU_FUNC,
AR40XX_ATU_FUNC_OP_FLUSH |
AR40XX_ATU_FUNC_BUSY);
return ret;
}
static void
ar40xx_ess_reset(struct ar40xx_priv *priv)
{
reset_control_assert(priv->ess_rst);
mdelay(10);
reset_control_deassert(priv->ess_rst);
/* Waiting for all inner tables init done.
* It cost 5~10ms.
*/
mdelay(10);
pr_info("ESS reset ok!\n");
}
/* Start of psgmii self test */
static void
ar40xx_malibu_psgmii_ess_reset(struct ar40xx_priv *priv)
{
u32 n;
struct mii_bus *bus = priv->mii_bus;
/* reset phy psgmii */
/* fix phy psgmii RX 20bit */
mdiobus_write(bus, 5, 0x0, 0x005b);
/* reset phy psgmii */
mdiobus_write(bus, 5, 0x0, 0x001b);
/* release reset phy psgmii */
mdiobus_write(bus, 5, 0x0, 0x005b);
for (n = 0; n < AR40XX_PSGMII_CALB_NUM; n++) {
u16 status;
status = ar40xx_phy_mmd_read(priv, 5, 1, 0x28);
if (status & BIT(0))
break;
/* Polling interval to check PSGMII PLL in malibu is ready
* the worst time is 8.67ms
* for 25MHz reference clock
* [512+(128+2048)*49]*80ns+100us
*/
mdelay(2);
}
/*check malibu psgmii calibration done end..*/
/*freeze phy psgmii RX CDR*/
mdiobus_write(bus, 5, 0x1a, 0x2230);
ar40xx_ess_reset(priv);
/*check psgmii calibration done start*/
for (n = 0; n < AR40XX_PSGMII_CALB_NUM; n++) {
u32 status;
status = ar40xx_psgmii_read(priv, 0xa0);
if (status & BIT(0))
break;
/* Polling interval to check PSGMII PLL in ESS is ready */
mdelay(2);
}
/* check dakota psgmii calibration done end..*/
/* relesae phy psgmii RX CDR */
mdiobus_write(bus, 5, 0x1a, 0x3230);
/* release phy psgmii RX 20bit */
mdiobus_write(bus, 5, 0x0, 0x005f);
}
static void
ar40xx_psgmii_single_phy_testing(struct ar40xx_priv *priv, int phy)
{
int j;
u32 tx_ok, tx_error;
u32 rx_ok, rx_error;
u32 tx_ok_high16;
u32 rx_ok_high16;
u32 tx_all_ok, rx_all_ok;
struct mii_bus *bus = priv->mii_bus;
mdiobus_write(bus, phy, 0x0, 0x9000);
mdiobus_write(bus, phy, 0x0, 0x4140);
for (j = 0; j < AR40XX_PSGMII_CALB_NUM; j++) {
u16 status;
status = mdiobus_read(bus, phy, 0x11);
if (status & AR40XX_PHY_SPEC_STATUS_LINK)
break;
/* the polling interval to check if the PHY link up or not
* maxwait_timer: 750 ms +/-10 ms
* minwait_timer : 1 us +/- 0.1us
* time resides in minwait_timer ~ maxwait_timer
* see IEEE 802.3 section 40.4.5.2
*/
mdelay(8);
}
/* enable check */
ar40xx_phy_mmd_write(priv, phy, 7, 0x8029, 0x0000);
ar40xx_phy_mmd_write(priv, phy, 7, 0x8029, 0x0003);
/* start traffic */
ar40xx_phy_mmd_write(priv, phy, 7, 0x8020, 0xa000);
/* wait for all traffic end
* 4096(pkt num)*1524(size)*8ns(125MHz)=49.9ms
*/
mdelay(50);
/* check counter */
tx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802e);
tx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802d);
tx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802f);
rx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802b);
rx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802a);
rx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802c);
tx_all_ok = tx_ok + (tx_ok_high16 << 16);
rx_all_ok = rx_ok + (rx_ok_high16 << 16);
if (tx_all_ok == 0x1000 && tx_error == 0) {
/* success */
priv->phy_t_status &= (~BIT(phy));
} else {
pr_info("PHY %d single test PSGMII issue happen!\n", phy);
priv->phy_t_status |= BIT(phy);
}
mdiobus_write(bus, phy, 0x0, 0x1840);
}
static void
ar40xx_psgmii_all_phy_testing(struct ar40xx_priv *priv)
{
int phy, j;
struct mii_bus *bus = priv->mii_bus;
mdiobus_write(bus, 0x1f, 0x0, 0x9000);
mdiobus_write(bus, 0x1f, 0x0, 0x4140);
for (j = 0; j < AR40XX_PSGMII_CALB_NUM; j++) {
for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
u16 status;
status = mdiobus_read(bus, phy, 0x11);
if (!(status & BIT(10)))
break;
}
if (phy >= (AR40XX_NUM_PORTS - 1))
break;
/* The polling interva to check if the PHY link up or not */
mdelay(8);
}
/* enable check */
ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8029, 0x0000);
ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8029, 0x0003);
/* start traffic */
ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8020, 0xa000);
/* wait for all traffic end
* 4096(pkt num)*1524(size)*8ns(125MHz)=49.9ms
*/
mdelay(50);
for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
u32 tx_ok, tx_error;
u32 rx_ok, rx_error;
u32 tx_ok_high16;
u32 rx_ok_high16;
u32 tx_all_ok, rx_all_ok;
/* check counter */
tx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802e);
tx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802d);
tx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802f);
rx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802b);
rx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802a);
rx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802c);
tx_all_ok = tx_ok + (tx_ok_high16<<16);
rx_all_ok = rx_ok + (rx_ok_high16<<16);
if (tx_all_ok == 0x1000 && tx_error == 0) {
/* success */
priv->phy_t_status &= ~BIT(phy + 8);
} else {
pr_info("PHY%d test see issue!\n", phy);
priv->phy_t_status |= BIT(phy + 8);
}
}
pr_debug("PHY all test 0x%x \r\n", priv->phy_t_status);
}
void
ar40xx_psgmii_self_test(struct ar40xx_priv *priv)
{
u32 i, phy;
struct mii_bus *bus = priv->mii_bus;
ar40xx_malibu_psgmii_ess_reset(priv);
/* switch to access MII reg for copper */
mdiobus_write(bus, 4, 0x1f, 0x8500);
for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
/*enable phy mdio broadcast write*/
ar40xx_phy_mmd_write(priv, phy, 7, 0x8028, 0x801f);
}
/* force no link by power down */
mdiobus_write(bus, 0x1f, 0x0, 0x1840);
/*packet number*/
ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8021, 0x1000);
ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8062, 0x05e0);
/*fix mdi status */
mdiobus_write(bus, 0x1f, 0x10, 0x6800);
for (i = 0; i < AR40XX_PSGMII_CALB_NUM; i++) {
priv->phy_t_status = 0;
for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(phy + 1),
AR40XX_PORT_LOOKUP_LOOPBACK,
AR40XX_PORT_LOOKUP_LOOPBACK);
}
for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++)
ar40xx_psgmii_single_phy_testing(priv, phy);
ar40xx_psgmii_all_phy_testing(priv);
if (priv->phy_t_status)
ar40xx_malibu_psgmii_ess_reset(priv);
else
break;
}
if (i >= AR40XX_PSGMII_CALB_NUM)
pr_info("PSGMII cannot recover\n");
else
pr_debug("PSGMII recovered after %d times reset\n", i);
/* configuration recover */
/* packet number */
ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8021, 0x0);
/* disable check */
ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8029, 0x0);
/* disable traffic */
ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8020, 0x0);
}
void
ar40xx_psgmii_self_test_clean(struct ar40xx_priv *priv)
{
int phy;
struct mii_bus *bus = priv->mii_bus;
/* disable phy internal loopback */
mdiobus_write(bus, 0x1f, 0x10, 0x6860);
mdiobus_write(bus, 0x1f, 0x0, 0x9040);
for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
/* disable mac loop back */
ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(phy + 1),
AR40XX_PORT_LOOKUP_LOOPBACK, 0);
/* disable phy mdio broadcast write */
ar40xx_phy_mmd_write(priv, phy, 7, 0x8028, 0x001f);
}
/* clear fdb entry */
ar40xx_atu_flush(priv);
}
/* End of psgmii self test */
static void
ar40xx_mac_mode_init(struct ar40xx_priv *priv, u32 mode)
{
if (mode == PORT_WRAPPER_PSGMII) {
ar40xx_psgmii_write(priv, AR40XX_PSGMII_MODE_CONTROL, 0x2200);
ar40xx_psgmii_write(priv, AR40XX_PSGMIIPHY_TX_CONTROL, 0x8380);
}
}
static
int ar40xx_cpuport_setup(struct ar40xx_priv *priv)
{
u32 t;
t = AR40XX_PORT_STATUS_TXFLOW |
AR40XX_PORT_STATUS_RXFLOW |
AR40XX_PORT_TXHALF_FLOW |
AR40XX_PORT_DUPLEX |
AR40XX_PORT_SPEED_1000M;
ar40xx_write(priv, AR40XX_REG_PORT_STATUS(0), t);
usleep_range(10, 20);
t |= AR40XX_PORT_TX_EN |
AR40XX_PORT_RX_EN;
ar40xx_write(priv, AR40XX_REG_PORT_STATUS(0), t);
return 0;
}
static void
ar40xx_init_port(struct ar40xx_priv *priv, int port)
{
u32 t;
ar40xx_write(priv, AR40XX_REG_PORT_STATUS(port), 0);
ar40xx_write(priv, AR40XX_REG_PORT_HEADER(port), 0);
ar40xx_write(priv, AR40XX_REG_PORT_VLAN0(port), 0);
t = AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH << AR40XX_PORT_VLAN1_OUT_MODE_S;
ar40xx_write(priv, AR40XX_REG_PORT_VLAN1(port), t);
t = AR40XX_PORT_LOOKUP_LEARN;
t |= AR40XX_PORT_STATE_FORWARD << AR40XX_PORT_LOOKUP_STATE_S;
ar40xx_write(priv, AR40XX_REG_PORT_LOOKUP(port), t);
}
void
ar40xx_init_globals(struct ar40xx_priv *priv)
{
u32 t;
/* enable CPU port and disable mirror port */
t = AR40XX_FWD_CTRL0_CPU_PORT_EN |
AR40XX_FWD_CTRL0_MIRROR_PORT;
ar40xx_write(priv, AR40XX_REG_FWD_CTRL0, t);
/* forward multicast and broadcast frames to CPU */
t = (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_UC_FLOOD_S) |
(AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_MC_FLOOD_S) |
(AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_BC_FLOOD_S);
ar40xx_write(priv, AR40XX_REG_FWD_CTRL1, t);
/* enable jumbo frames */
ar40xx_rmw(priv, AR40XX_REG_MAX_FRAME_SIZE,
AR40XX_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2);
/* Enable MIB counters */
ar40xx_rmw(priv, AR40XX_REG_MODULE_EN, 0,
AR40XX_MODULE_EN_MIB);
/* Disable AZ */
ar40xx_write(priv, AR40XX_REG_EEE_CTRL, 0);
/* set flowctrl thershold for cpu port */
t = (AR40XX_PORT0_FC_THRESH_ON_DFLT << 16) |
AR40XX_PORT0_FC_THRESH_OFF_DFLT;
ar40xx_write(priv, AR40XX_REG_PORT_FLOWCTRL_THRESH(0), t);
}
static int
ar40xx_hw_init(struct ar40xx_priv *priv)
{
u32 i;
ar40xx_ess_reset(priv);
if (!priv->mii_bus)
return -1;
ar40xx_psgmii_self_test(priv);
ar40xx_psgmii_self_test_clean(priv);
ar40xx_mac_mode_init(priv, priv->mac_mode);
for (i = 0; i < priv->dev.ports; i++)
ar40xx_init_port(priv, i);
ar40xx_init_globals(priv);
return 0;
}
/* Start of qm error WAR */
static
int ar40xx_force_1g_full(struct ar40xx_priv *priv, u32 port_id)
{
u32 reg;
if (port_id < 0 || port_id > 6)
return -1;
reg = AR40XX_REG_PORT_STATUS(port_id);
return ar40xx_rmw(priv, reg, AR40XX_PORT_SPEED,
(AR40XX_PORT_SPEED_1000M | AR40XX_PORT_DUPLEX));
}
static
int ar40xx_get_qm_status(struct ar40xx_priv *priv,
u32 port_id, u32 *qm_buffer_err)
{
u32 reg;
u32 qm_val;
if (port_id < 1 || port_id > 5) {
*qm_buffer_err = 0;
return -1;
}
if (port_id < 4) {
reg = AR40XX_REG_QM_PORT0_3_QNUM;
ar40xx_write(priv, AR40XX_REG_QM_DEBUG_ADDR, reg);
qm_val = ar40xx_read(priv, AR40XX_REG_QM_DEBUG_VALUE);
/* every 8 bits for each port */
*qm_buffer_err = (qm_val >> (port_id * 8)) & 0xFF;
} else {
reg = AR40XX_REG_QM_PORT4_6_QNUM;
ar40xx_write(priv, AR40XX_REG_QM_DEBUG_ADDR, reg);
qm_val = ar40xx_read(priv, AR40XX_REG_QM_DEBUG_VALUE);
/* every 8 bits for each port */
*qm_buffer_err = (qm_val >> ((port_id-4) * 8)) & 0xFF;
}
return 0;
}
static void
ar40xx_sw_mac_polling_task(struct ar40xx_priv *priv)
{
static int task_count;
u32 i;
u32 reg, value;
u32 link, speed, duplex;
u32 qm_buffer_err;
u16 port_phy_status[AR40XX_NUM_PORTS];
static u32 qm_err_cnt[AR40XX_NUM_PORTS] = {0, 0, 0, 0, 0, 0};
static u32 link_cnt[AR40XX_NUM_PORTS] = {0, 0, 0, 0, 0, 0};
struct mii_bus *bus = NULL;
if (!priv || !priv->mii_bus)
return;
bus = priv->mii_bus;
++task_count;
for (i = 1; i < AR40XX_NUM_PORTS; ++i) {
port_phy_status[i] =
mdiobus_read(bus, i-1, AR40XX_PHY_SPEC_STATUS);
speed = FIELD_GET(AR40XX_PHY_SPEC_STATUS_SPEED,
port_phy_status[i]);
link = FIELD_GET(AR40XX_PHY_SPEC_STATUS_LINK,
port_phy_status[i]);
duplex = FIELD_GET(AR40XX_PHY_SPEC_STATUS_DUPLEX,
port_phy_status[i]);
if (link != priv->ar40xx_port_old_link[i]) {
++link_cnt[i];
/* Up --> Down */
if ((priv->ar40xx_port_old_link[i] ==
AR40XX_PORT_LINK_UP) &&
(link == AR40XX_PORT_LINK_DOWN)) {
/* LINK_EN disable(MAC force mode)*/
reg = AR40XX_REG_PORT_STATUS(i);
ar40xx_rmw(priv, reg,
AR40XX_PORT_AUTO_LINK_EN, 0);
/* Check queue buffer */
qm_err_cnt[i] = 0;
ar40xx_get_qm_status(priv, i, &qm_buffer_err);
if (qm_buffer_err) {
priv->ar40xx_port_qm_buf[i] =
AR40XX_QM_NOT_EMPTY;
} else {
u16 phy_val = 0;
priv->ar40xx_port_qm_buf[i] =
AR40XX_QM_EMPTY;
ar40xx_force_1g_full(priv, i);
/* Ref:QCA8337 Datasheet,Clearing
* MENU_CTRL_EN prevents phy to
* stuck in 100BT mode when
* bringing up the link
*/
ar40xx_phy_dbg_read(priv, i-1,
AR40XX_PHY_DEBUG_0,
&phy_val);
phy_val &= (~AR40XX_PHY_MANU_CTRL_EN);
ar40xx_phy_dbg_write(priv, i-1,
AR40XX_PHY_DEBUG_0,
phy_val);
}
priv->ar40xx_port_old_link[i] = link;
} else if ((priv->ar40xx_port_old_link[i] ==
AR40XX_PORT_LINK_DOWN) &&
(link == AR40XX_PORT_LINK_UP)) {
/* Down --> Up */
if (priv->port_link_up[i] < 1) {
++priv->port_link_up[i];
} else {
/* Change port status */
reg = AR40XX_REG_PORT_STATUS(i);
value = ar40xx_read(priv, reg);
priv->port_link_up[i] = 0;
value &= ~(AR40XX_PORT_DUPLEX |
AR40XX_PORT_SPEED);
value |= speed | (duplex ? BIT(6) : 0);
ar40xx_write(priv, reg, value);
/* clock switch need such time
* to avoid glitch
*/
usleep_range(100, 200);
value |= AR40XX_PORT_AUTO_LINK_EN;
ar40xx_write(priv, reg, value);
/* HW need such time to make sure link
* stable before enable MAC
*/
usleep_range(100, 200);
if (speed == AR40XX_PORT_SPEED_100M) {
u16 phy_val = 0;
/* Enable @100M, if down to 10M
* clock will change smoothly
*/
ar40xx_phy_dbg_read(priv, i-1,
0,
&phy_val);
phy_val |=
AR40XX_PHY_MANU_CTRL_EN;
ar40xx_phy_dbg_write(priv, i-1,
0,
phy_val);
}
priv->ar40xx_port_old_link[i] = link;
}
}
}
if (priv->ar40xx_port_qm_buf[i] == AR40XX_QM_NOT_EMPTY) {
/* Check QM */
ar40xx_get_qm_status(priv, i, &qm_buffer_err);
if (qm_buffer_err) {
++qm_err_cnt[i];
} else {
priv->ar40xx_port_qm_buf[i] =
AR40XX_QM_EMPTY;
qm_err_cnt[i] = 0;
ar40xx_force_1g_full(priv, i);
}
}
}
}
static void
ar40xx_qm_err_check_work_task(struct work_struct *work)
{
struct ar40xx_priv *priv = container_of(work, struct ar40xx_priv,
qm_dwork.work);
mutex_lock(&priv->qm_lock);
ar40xx_sw_mac_polling_task(priv);
mutex_unlock(&priv->qm_lock);
schedule_delayed_work(&priv->qm_dwork,
msecs_to_jiffies(AR40XX_QM_WORK_DELAY));
}
static int
ar40xx_qm_err_check_work_start(struct ar40xx_priv *priv)
{
mutex_init(&priv->qm_lock);
INIT_DELAYED_WORK(&priv->qm_dwork, ar40xx_qm_err_check_work_task);
schedule_delayed_work(&priv->qm_dwork,
msecs_to_jiffies(AR40XX_QM_WORK_DELAY));
return 0;
}
/* End of qm error WAR */
static int
ar40xx_vlan_init(struct ar40xx_priv *priv)
{
int port;
unsigned long bmp;
/* By default Enable VLAN */
priv->vlan = 1;
priv->vlan_table[AR40XX_LAN_VLAN] = priv->cpu_bmp | priv->lan_bmp;
priv->vlan_table[AR40XX_WAN_VLAN] = priv->cpu_bmp | priv->wan_bmp;
priv->vlan_tagged = priv->cpu_bmp;
bmp = priv->lan_bmp;
for_each_set_bit(port, &bmp, AR40XX_NUM_PORTS)
priv->pvid[port] = AR40XX_LAN_VLAN;
bmp = priv->wan_bmp;
for_each_set_bit(port, &bmp, AR40XX_NUM_PORTS)
priv->pvid[port] = AR40XX_WAN_VLAN;
return 0;
}
static void
ar40xx_mib_work_func(struct work_struct *work)
{
struct ar40xx_priv *priv;
int err;
priv = container_of(work, struct ar40xx_priv, mib_work.work);
mutex_lock(&priv->mib_lock);
err = ar40xx_mib_capture(priv);
if (err)
goto next_port;
ar40xx_mib_fetch_port_stat(priv, priv->mib_next_port, false);
next_port:
priv->mib_next_port++;
if (priv->mib_next_port >= priv->dev.ports)
priv->mib_next_port = 0;
mutex_unlock(&priv->mib_lock);
schedule_delayed_work(&priv->mib_work,
msecs_to_jiffies(AR40XX_MIB_WORK_DELAY));
}
static void
ar40xx_setup_port(struct ar40xx_priv *priv, int port, u32 members)
{
u32 t;
u32 egress, ingress;
u32 pvid = priv->vlan_id[priv->pvid[port]];
if (priv->vlan) {
egress = AR40XX_PORT_VLAN1_OUT_MODE_UNMOD;
ingress = AR40XX_IN_SECURE;
} else {
egress = AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH;
ingress = AR40XX_IN_PORT_ONLY;
}
t = pvid << AR40XX_PORT_VLAN0_DEF_SVID_S;
t |= pvid << AR40XX_PORT_VLAN0_DEF_CVID_S;
ar40xx_write(priv, AR40XX_REG_PORT_VLAN0(port), t);
t = AR40XX_PORT_VLAN1_PORT_VLAN_PROP;
t |= egress << AR40XX_PORT_VLAN1_OUT_MODE_S;
ar40xx_write(priv, AR40XX_REG_PORT_VLAN1(port), t);
t = members;
t |= AR40XX_PORT_LOOKUP_LEARN;
t |= ingress << AR40XX_PORT_LOOKUP_IN_MODE_S;
t |= AR40XX_PORT_STATE_FORWARD << AR40XX_PORT_LOOKUP_STATE_S;
ar40xx_write(priv, AR40XX_REG_PORT_LOOKUP(port), t);
}
static void
ar40xx_vtu_op(struct ar40xx_priv *priv, u32 op, u32 val)
{
if (ar40xx_wait_bit(priv, AR40XX_REG_VTU_FUNC1,
AR40XX_VTU_FUNC1_BUSY, 0))
return;
if ((op & AR40XX_VTU_FUNC1_OP) == AR40XX_VTU_FUNC1_OP_LOAD)
ar40xx_write(priv, AR40XX_REG_VTU_FUNC0, val);
op |= AR40XX_VTU_FUNC1_BUSY;
ar40xx_write(priv, AR40XX_REG_VTU_FUNC1, op);
}
static void
ar40xx_vtu_load_vlan(struct ar40xx_priv *priv, u32 vid, u32 port_mask)
{
u32 op;
u32 val;
int i;
op = AR40XX_VTU_FUNC1_OP_LOAD | (vid << AR40XX_VTU_FUNC1_VID_S);
val = AR40XX_VTU_FUNC0_VALID | AR40XX_VTU_FUNC0_IVL;
for (i = 0; i < AR40XX_NUM_PORTS; i++) {
u32 mode;
if ((port_mask & BIT(i)) == 0)
mode = AR40XX_VTU_FUNC0_EG_MODE_NOT;
else if (priv->vlan == 0)
mode = AR40XX_VTU_FUNC0_EG_MODE_KEEP;
else if ((priv->vlan_tagged & BIT(i)) ||
(priv->vlan_id[priv->pvid[i]] != vid))
mode = AR40XX_VTU_FUNC0_EG_MODE_TAG;
else
mode = AR40XX_VTU_FUNC0_EG_MODE_UNTAG;
val |= mode << AR40XX_VTU_FUNC0_EG_MODE_S(i);
}
ar40xx_vtu_op(priv, op, val);
}
static void
ar40xx_vtu_flush(struct ar40xx_priv *priv)
{
ar40xx_vtu_op(priv, AR40XX_VTU_FUNC1_OP_FLUSH, 0);
}
static int
ar40xx_sw_hw_apply(struct switch_dev *dev)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
u8 portmask[AR40XX_NUM_PORTS];
int i, j;
mutex_lock(&priv->reg_mutex);
/* flush all vlan entries */
ar40xx_vtu_flush(priv);
memset(portmask, 0, sizeof(portmask));
if (priv->vlan) {
for (j = 0; j < AR40XX_MAX_VLANS; j++) {
u8 vp = priv->vlan_table[j];
if (!vp)
continue;
for (i = 0; i < dev->ports; i++) {
u8 mask = BIT(i);
if (vp & mask)
portmask[i] |= vp & ~mask;
}
ar40xx_vtu_load_vlan(priv, priv->vlan_id[j],
priv->vlan_table[j]);
}
} else {
/* 8021q vlan disabled */
for (i = 0; i < dev->ports; i++) {
if (i == AR40XX_PORT_CPU)
continue;
portmask[i] = BIT(AR40XX_PORT_CPU);
portmask[AR40XX_PORT_CPU] |= BIT(i);
}
}
/* update the port destination mask registers and tag settings */
for (i = 0; i < dev->ports; i++)
ar40xx_setup_port(priv, i, portmask[i]);
ar40xx_set_mirror_regs(priv);
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
ar40xx_sw_reset_switch(struct switch_dev *dev)
{
struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
int i, rv;
mutex_lock(&priv->reg_mutex);
memset(&priv->vlan, 0, sizeof(struct ar40xx_priv) -
offsetof(struct ar40xx_priv, vlan));
for (i = 0; i < AR40XX_MAX_VLANS; i++)
priv->vlan_id[i] = i;
ar40xx_vlan_init(priv);
priv->mirror_rx = false;
priv->mirror_tx = false;
priv->source_port = 0;
priv->monitor_port = 0;
mutex_unlock(&priv->reg_mutex);
rv = ar40xx_sw_hw_apply(dev);
return rv;
}
static int
ar40xx_start(struct ar40xx_priv *priv)
{
int ret;
ret = ar40xx_hw_init(priv);
if (ret)
return ret;
ret = ar40xx_sw_reset_switch(&priv->dev);
if (ret)
return ret;
/* at last, setup cpu port */
ret = ar40xx_cpuport_setup(priv);
if (ret)
return ret;
schedule_delayed_work(&priv->mib_work,
msecs_to_jiffies(AR40XX_MIB_WORK_DELAY));
ar40xx_qm_err_check_work_start(priv);
return 0;
}
static const struct switch_dev_ops ar40xx_sw_ops = {
.attr_global = {
.attr = ar40xx_sw_attr_globals,
.n_attr = ARRAY_SIZE(ar40xx_sw_attr_globals),
},
.attr_port = {
.attr = ar40xx_sw_attr_port,
.n_attr = ARRAY_SIZE(ar40xx_sw_attr_port),
},
.attr_vlan = {
.attr = ar40xx_sw_attr_vlan,
.n_attr = ARRAY_SIZE(ar40xx_sw_attr_vlan),
},
.get_port_pvid = ar40xx_sw_get_pvid,
.set_port_pvid = ar40xx_sw_set_pvid,
.get_vlan_ports = ar40xx_sw_get_ports,
.set_vlan_ports = ar40xx_sw_set_ports,
.apply_config = ar40xx_sw_hw_apply,
.reset_switch = ar40xx_sw_reset_switch,
.get_port_link = ar40xx_sw_get_port_link,
};
/* Platform driver probe function */
static int ar40xx_probe(struct platform_device *pdev)
{
struct device_node *switch_node;
struct device_node *psgmii_node;
struct device_node *mdio_node;
const __be32 *mac_mode;
struct clk *ess_clk;
struct switch_dev *swdev;
struct ar40xx_priv *priv;
u32 len;
u32 num_mibs;
struct resource psgmii_base = {0};
struct resource switch_base = {0};
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
ar40xx_priv = priv;
switch_node = of_node_get(pdev->dev.of_node);
if (of_address_to_resource(switch_node, 0, &switch_base) != 0)
return -EIO;
priv->hw_addr = devm_ioremap_resource(&pdev->dev, &switch_base);
if (IS_ERR(priv->hw_addr)) {
dev_err(&pdev->dev, "Failed to ioremap switch_base!\n");
return PTR_ERR(priv->hw_addr);
}
/*psgmii dts get*/
psgmii_node = of_find_node_by_name(NULL, "ess-psgmii");
if (!psgmii_node) {
dev_err(&pdev->dev, "Failed to find ess-psgmii node!\n");
return -EINVAL;
}
if (of_address_to_resource(psgmii_node, 0, &psgmii_base) != 0)
return -EIO;
priv->psgmii_hw_addr = devm_ioremap_resource(&pdev->dev, &psgmii_base);
if (IS_ERR(priv->psgmii_hw_addr)) {
dev_err(&pdev->dev, "psgmii ioremap fail!\n");
return PTR_ERR(priv->psgmii_hw_addr);
}
mac_mode = of_get_property(switch_node, "switch_mac_mode", &len);
if (!mac_mode) {
dev_err(&pdev->dev, "Failed to read switch_mac_mode\n");
return -EINVAL;
}
priv->mac_mode = be32_to_cpup(mac_mode);
ess_clk = of_clk_get_by_name(switch_node, "ess_clk");
if (ess_clk)
clk_prepare_enable(ess_clk);
priv->ess_rst = devm_reset_control_get(&pdev->dev, "ess_rst");
if (IS_ERR(priv->ess_rst)) {
dev_err(&pdev->dev, "Failed to get ess_rst control!\n");
return PTR_ERR(priv->ess_rst);
}
if (of_property_read_u32(switch_node, "switch_cpu_bmp",
&priv->cpu_bmp) ||
of_property_read_u32(switch_node, "switch_lan_bmp",
&priv->lan_bmp) ||
of_property_read_u32(switch_node, "switch_wan_bmp",
&priv->wan_bmp)) {
dev_err(&pdev->dev, "Failed to read port properties\n");
return -EIO;
}
mutex_init(&priv->reg_mutex);
mutex_init(&priv->mib_lock);
INIT_DELAYED_WORK(&priv->mib_work, ar40xx_mib_work_func);
/* register switch */
swdev = &priv->dev;
mdio_node = of_find_compatible_node(NULL, NULL, "qcom,ipq4019-mdio");
if (!mdio_node) {
dev_err(&pdev->dev, "Probe failed - Cannot find mdio node by phandle!\n");
ret = -ENODEV;
goto err_missing_phy;
}
priv->mii_bus = of_mdio_find_bus(mdio_node);
if (priv->mii_bus == NULL) {
dev_err(&pdev->dev, "Probe failed - Missing PHYs!\n");
ret = -ENODEV;
goto err_missing_phy;
}
swdev->alias = dev_name(&priv->mii_bus->dev);
swdev->cpu_port = AR40XX_PORT_CPU;
swdev->name = "QCA AR40xx";
swdev->vlans = AR40XX_MAX_VLANS;
swdev->ports = AR40XX_NUM_PORTS;
swdev->ops = &ar40xx_sw_ops;
ret = register_switch(swdev, NULL);
if (ret < 0) {
dev_err(&pdev->dev, "Switch registration failed!\n");
return ret;
}
num_mibs = ARRAY_SIZE(ar40xx_mibs);
len = priv->dev.ports * num_mibs *
sizeof(*priv->mib_stats);
priv->mib_stats = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
if (!priv->mib_stats) {
ret = -ENOMEM;
goto err_unregister_switch;
}
ar40xx_start(priv);
return 0;
err_unregister_switch:
unregister_switch(&priv->dev);
err_missing_phy:
platform_set_drvdata(pdev, NULL);
return ret;
}
static int ar40xx_remove(struct platform_device *pdev)
{
struct ar40xx_priv *priv = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&priv->qm_dwork);
cancel_delayed_work_sync(&priv->mib_work);
unregister_switch(&priv->dev);
return 0;
}
static const struct of_device_id ar40xx_of_mtable[] = {
{.compatible = "qcom,ess-switch" },
{}
};
struct platform_driver ar40xx_drv = {
.probe = ar40xx_probe,
.remove = ar40xx_remove,
.driver = {
.name = "ar40xx",
.of_match_table = ar40xx_of_mtable,
},
};
module_platform_driver(ar40xx_drv);
MODULE_DESCRIPTION("IPQ40XX ESS driver");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -1,342 +0,0 @@
/*
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
*
* 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.
*/
#ifndef __AR40XX_H
#define __AR40XX_H
#define AR40XX_MAX_VLANS 128
#define AR40XX_NUM_PORTS 6
#define AR40XX_NUM_PHYS 5
#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s)
struct ar40xx_priv {
struct switch_dev dev;
u8 __iomem *hw_addr;
u8 __iomem *psgmii_hw_addr;
u32 mac_mode;
struct reset_control *ess_rst;
u32 cpu_bmp;
u32 lan_bmp;
u32 wan_bmp;
struct mii_bus *mii_bus;
struct phy_device *phy;
/* mutex for qm task */
struct mutex qm_lock;
struct delayed_work qm_dwork;
u32 port_link_up[AR40XX_NUM_PORTS];
u32 ar40xx_port_old_link[AR40XX_NUM_PORTS];
u32 ar40xx_port_qm_buf[AR40XX_NUM_PORTS];
u32 phy_t_status;
/* mutex for switch reg access */
struct mutex reg_mutex;
/* mutex for mib task */
struct mutex mib_lock;
struct delayed_work mib_work;
int mib_next_port;
u64 *mib_stats;
char buf[2048];
/* all fields below will be cleared on reset */
bool vlan;
u16 vlan_id[AR40XX_MAX_VLANS];
u8 vlan_table[AR40XX_MAX_VLANS];
u8 vlan_tagged;
u16 pvid[AR40XX_NUM_PORTS];
/* mirror */
bool mirror_rx;
bool mirror_tx;
int source_port;
int monitor_port;
};
#define AR40XX_PORT_LINK_UP 1
#define AR40XX_PORT_LINK_DOWN 0
#define AR40XX_QM_NOT_EMPTY 1
#define AR40XX_QM_EMPTY 0
#define AR40XX_LAN_VLAN 1
#define AR40XX_WAN_VLAN 2
enum ar40xx_port_wrapper_cfg {
PORT_WRAPPER_PSGMII = 0,
};
struct ar40xx_mib_desc {
u32 size;
u32 offset;
const char *name;
};
#define AR40XX_PORT_CPU 0
#define AR40XX_PSGMII_MODE_CONTROL 0x1b4
#define AR40XX_PSGMII_ATHR_CSCO_MODE_25M BIT(0)
#define AR40XX_PSGMIIPHY_TX_CONTROL 0x288
#define AR40XX_MII_ATH_MMD_ADDR 0x0d
#define AR40XX_MII_ATH_MMD_DATA 0x0e
#define AR40XX_MII_ATH_DBG_ADDR 0x1d
#define AR40XX_MII_ATH_DBG_DATA 0x1e
#define AR40XX_STATS_RXBROAD 0x00
#define AR40XX_STATS_RXPAUSE 0x04
#define AR40XX_STATS_RXMULTI 0x08
#define AR40XX_STATS_RXFCSERR 0x0c
#define AR40XX_STATS_RXALIGNERR 0x10
#define AR40XX_STATS_RXRUNT 0x14
#define AR40XX_STATS_RXFRAGMENT 0x18
#define AR40XX_STATS_RX64BYTE 0x1c
#define AR40XX_STATS_RX128BYTE 0x20
#define AR40XX_STATS_RX256BYTE 0x24
#define AR40XX_STATS_RX512BYTE 0x28
#define AR40XX_STATS_RX1024BYTE 0x2c
#define AR40XX_STATS_RX1518BYTE 0x30
#define AR40XX_STATS_RXMAXBYTE 0x34
#define AR40XX_STATS_RXTOOLONG 0x38
#define AR40XX_STATS_RXGOODBYTE 0x3c
#define AR40XX_STATS_RXBADBYTE 0x44
#define AR40XX_STATS_RXOVERFLOW 0x4c
#define AR40XX_STATS_FILTERED 0x50
#define AR40XX_STATS_TXBROAD 0x54
#define AR40XX_STATS_TXPAUSE 0x58
#define AR40XX_STATS_TXMULTI 0x5c
#define AR40XX_STATS_TXUNDERRUN 0x60
#define AR40XX_STATS_TX64BYTE 0x64
#define AR40XX_STATS_TX128BYTE 0x68
#define AR40XX_STATS_TX256BYTE 0x6c
#define AR40XX_STATS_TX512BYTE 0x70
#define AR40XX_STATS_TX1024BYTE 0x74
#define AR40XX_STATS_TX1518BYTE 0x78
#define AR40XX_STATS_TXMAXBYTE 0x7c
#define AR40XX_STATS_TXOVERSIZE 0x80
#define AR40XX_STATS_TXBYTE 0x84
#define AR40XX_STATS_TXCOLLISION 0x8c
#define AR40XX_STATS_TXABORTCOL 0x90
#define AR40XX_STATS_TXMULTICOL 0x94
#define AR40XX_STATS_TXSINGLECOL 0x98
#define AR40XX_STATS_TXEXCDEFER 0x9c
#define AR40XX_STATS_TXDEFER 0xa0
#define AR40XX_STATS_TXLATECOL 0xa4
#define AR40XX_REG_MODULE_EN 0x030
#define AR40XX_MODULE_EN_MIB BIT(0)
#define AR40XX_REG_MIB_FUNC 0x034
#define AR40XX_MIB_BUSY BIT(17)
#define AR40XX_MIB_CPU_KEEP BIT(20)
#define AR40XX_MIB_FUNC BITS(24, 3)
#define AR40XX_MIB_FUNC_S 24
#define AR40XX_MIB_FUNC_NO_OP 0x0
#define AR40XX_MIB_FUNC_FLUSH 0x1
#define AR40XX_ESS_SERVICE_TAG 0x48
#define AR40XX_ESS_SERVICE_TAG_STAG BIT(17)
#define AR40XX_REG_PORT_STATUS(_i) (0x07c + (_i) * 4)
#define AR40XX_PORT_SPEED BITS(0, 2)
#define AR40XX_PORT_STATUS_SPEED_S 0
#define AR40XX_PORT_TX_EN BIT(2)
#define AR40XX_PORT_RX_EN BIT(3)
#define AR40XX_PORT_STATUS_TXFLOW BIT(4)
#define AR40XX_PORT_STATUS_RXFLOW BIT(5)
#define AR40XX_PORT_DUPLEX BIT(6)
#define AR40XX_PORT_TXHALF_FLOW BIT(7)
#define AR40XX_PORT_STATUS_LINK_UP BIT(8)
#define AR40XX_PORT_AUTO_LINK_EN BIT(9)
#define AR40XX_PORT_STATUS_FLOW_CONTROL BIT(12)
#define AR40XX_REG_MAX_FRAME_SIZE 0x078
#define AR40XX_MAX_FRAME_SIZE_MTU BITS(0, 14)
#define AR40XX_REG_PORT_HEADER(_i) (0x09c + (_i) * 4)
#define AR40XX_REG_EEE_CTRL 0x100
#define AR40XX_EEE_CTRL_DISABLE_PHY(_i) BIT(4 + (_i) * 2)
#define AR40XX_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8)
#define AR40XX_PORT_VLAN0_DEF_SVID BITS(0, 12)
#define AR40XX_PORT_VLAN0_DEF_SVID_S 0
#define AR40XX_PORT_VLAN0_DEF_CVID BITS(16, 12)
#define AR40XX_PORT_VLAN0_DEF_CVID_S 16
#define AR40XX_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8)
#define AR40XX_PORT_VLAN1_CORE_PORT BIT(9)
#define AR40XX_PORT_VLAN1_PORT_TLS_MODE BIT(7)
#define AR40XX_PORT_VLAN1_PORT_VLAN_PROP BIT(6)
#define AR40XX_PORT_VLAN1_OUT_MODE BITS(12, 2)
#define AR40XX_PORT_VLAN1_OUT_MODE_S 12
#define AR40XX_PORT_VLAN1_OUT_MODE_UNMOD 0
#define AR40XX_PORT_VLAN1_OUT_MODE_UNTAG 1
#define AR40XX_PORT_VLAN1_OUT_MODE_TAG 2
#define AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH 3
#define AR40XX_REG_VTU_FUNC0 0x0610
#define AR40XX_VTU_FUNC0_EG_MODE BITS(4, 14)
#define AR40XX_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2)
#define AR40XX_VTU_FUNC0_EG_MODE_KEEP 0
#define AR40XX_VTU_FUNC0_EG_MODE_UNTAG 1
#define AR40XX_VTU_FUNC0_EG_MODE_TAG 2
#define AR40XX_VTU_FUNC0_EG_MODE_NOT 3
#define AR40XX_VTU_FUNC0_IVL BIT(19)
#define AR40XX_VTU_FUNC0_VALID BIT(20)
#define AR40XX_REG_VTU_FUNC1 0x0614
#define AR40XX_VTU_FUNC1_OP BITS(0, 3)
#define AR40XX_VTU_FUNC1_OP_NOOP 0
#define AR40XX_VTU_FUNC1_OP_FLUSH 1
#define AR40XX_VTU_FUNC1_OP_LOAD 2
#define AR40XX_VTU_FUNC1_OP_PURGE 3
#define AR40XX_VTU_FUNC1_OP_REMOVE_PORT 4
#define AR40XX_VTU_FUNC1_OP_GET_NEXT 5
#define AR40XX7_VTU_FUNC1_OP_GET_ONE 6
#define AR40XX_VTU_FUNC1_FULL BIT(4)
#define AR40XX_VTU_FUNC1_PORT BIT(8, 4)
#define AR40XX_VTU_FUNC1_PORT_S 8
#define AR40XX_VTU_FUNC1_VID BIT(16, 12)
#define AR40XX_VTU_FUNC1_VID_S 16
#define AR40XX_VTU_FUNC1_BUSY BIT(31)
#define AR40XX_REG_FWD_CTRL0 0x620
#define AR40XX_FWD_CTRL0_CPU_PORT_EN BIT(10)
#define AR40XX_FWD_CTRL0_MIRROR_PORT BITS(4, 4)
#define AR40XX_FWD_CTRL0_MIRROR_PORT_S 4
#define AR40XX_REG_FWD_CTRL1 0x624
#define AR40XX_FWD_CTRL1_UC_FLOOD BITS(0, 7)
#define AR40XX_FWD_CTRL1_UC_FLOOD_S 0
#define AR40XX_FWD_CTRL1_MC_FLOOD BITS(8, 7)
#define AR40XX_FWD_CTRL1_MC_FLOOD_S 8
#define AR40XX_FWD_CTRL1_BC_FLOOD BITS(16, 7)
#define AR40XX_FWD_CTRL1_BC_FLOOD_S 16
#define AR40XX_FWD_CTRL1_IGMP BITS(24, 7)
#define AR40XX_FWD_CTRL1_IGMP_S 24
#define AR40XX_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc)
#define AR40XX_PORT_LOOKUP_MEMBER BITS(0, 7)
#define AR40XX_PORT_LOOKUP_IN_MODE BITS(8, 2)
#define AR40XX_PORT_LOOKUP_IN_MODE_S 8
#define AR40XX_PORT_LOOKUP_STATE BITS(16, 3)
#define AR40XX_PORT_LOOKUP_STATE_S 16
#define AR40XX_PORT_LOOKUP_LEARN BIT(20)
#define AR40XX_PORT_LOOKUP_LOOPBACK BIT(21)
#define AR40XX_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
#define AR40XX_REG_ATU_FUNC 0x60c
#define AR40XX_ATU_FUNC_OP BITS(0, 4)
#define AR40XX_ATU_FUNC_OP_NOOP 0x0
#define AR40XX_ATU_FUNC_OP_FLUSH 0x1
#define AR40XX_ATU_FUNC_OP_LOAD 0x2
#define AR40XX_ATU_FUNC_OP_PURGE 0x3
#define AR40XX_ATU_FUNC_OP_FLUSH_LOCKED 0x4
#define AR40XX_ATU_FUNC_OP_FLUSH_UNICAST 0x5
#define AR40XX_ATU_FUNC_OP_GET_NEXT 0x6
#define AR40XX_ATU_FUNC_OP_SEARCH_MAC 0x7
#define AR40XX_ATU_FUNC_OP_CHANGE_TRUNK 0x8
#define AR40XX_ATU_FUNC_BUSY BIT(31)
#define AR40XX_REG_QM_DEBUG_ADDR 0x820
#define AR40XX_REG_QM_DEBUG_VALUE 0x824
#define AR40XX_REG_QM_PORT0_3_QNUM 0x1d
#define AR40XX_REG_QM_PORT4_6_QNUM 0x1e
#define AR40XX_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8)
#define AR40XX_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16)
#define AR40XX_REG_PORT_FLOWCTRL_THRESH(_i) (0x9b0 + (_i) * 0x4)
#define AR40XX_PORT0_FC_THRESH_ON_DFLT 0x60
#define AR40XX_PORT0_FC_THRESH_OFF_DFLT 0x90
#define AR40XX_PHY_DEBUG_0 0
#define AR40XX_PHY_MANU_CTRL_EN BIT(12)
#define AR40XX_PHY_DEBUG_2 2
#define AR40XX_PHY_SPEC_STATUS 0x11
#define AR40XX_PHY_SPEC_STATUS_LINK BIT(10)
#define AR40XX_PHY_SPEC_STATUS_DUPLEX BIT(13)
#define AR40XX_PHY_SPEC_STATUS_SPEED BITS(14, 2)
/* port forwarding state */
enum {
AR40XX_PORT_STATE_DISABLED = 0,
AR40XX_PORT_STATE_BLOCK = 1,
AR40XX_PORT_STATE_LISTEN = 2,
AR40XX_PORT_STATE_LEARN = 3,
AR40XX_PORT_STATE_FORWARD = 4
};
/* ingress 802.1q mode */
enum {
AR40XX_IN_PORT_ONLY = 0,
AR40XX_IN_PORT_FALLBACK = 1,
AR40XX_IN_VLAN_ONLY = 2,
AR40XX_IN_SECURE = 3
};
/* egress 802.1q mode */
enum {
AR40XX_OUT_KEEP = 0,
AR40XX_OUT_STRIP_VLAN = 1,
AR40XX_OUT_ADD_VLAN = 2
};
/* port speed */
enum {
AR40XX_PORT_SPEED_10M = 0,
AR40XX_PORT_SPEED_100M = 1,
AR40XX_PORT_SPEED_1000M = 2,
AR40XX_PORT_SPEED_ERR = 3,
};
#define AR40XX_MIB_WORK_DELAY 2000 /* msecs */
#define AR40XX_QM_WORK_DELAY 100
#define AR40XX_MIB_FUNC_CAPTURE 0x3
#define AR40XX_REG_PORT_STATS_START 0x1000
#define AR40XX_REG_PORT_STATS_LEN 0x100
#define AR40XX_PORTS_ALL 0x3f
#define AR40XX_PSGMII_ID 5
#define AR40XX_PSGMII_CALB_NUM 100
#define AR40XX_MALIBU_PSGMII_MODE_CTRL 0x6d
#define AR40XX_MALIBU_PHY_PSGMII_MODE_CTRL_ADJUST_VAL 0x220c
#define AR40XX_MALIBU_PHY_MMD7_DAC_CTRL 0x801a
#define AR40XX_MALIBU_DAC_CTRL_MASK 0x380
#define AR40XX_MALIBU_DAC_CTRL_VALUE 0x280
#define AR40XX_MALIBU_PHY_RLP_CTRL 0x805a
#define AR40XX_PSGMII_TX_DRIVER_1_CTRL 0xb
#define AR40XX_MALIBU_PHY_PSGMII_REDUCE_SERDES_TX_AMP 0x8a
#define AR40XX_MALIBU_PHY_LAST_ADDR 4
static inline struct ar40xx_priv *
swdev_to_ar40xx(struct switch_dev *swdev)
{
return container_of(swdev, struct ar40xx_priv, dev);
}
#endif

View File

@ -1,42 +0,0 @@
From f125e2d4339dda6937865f975470b29c84714c9b Mon Sep 17 00:00:00 2001
From: Christian Lamparter <chunkeey@gmail.com>
Date: Mon, 6 Jan 2020 14:57:15 +0100
Subject: [PATCH] ARM: qcom: Add support for IPQ40xx
Add support for the Qualcomm IPQ40xx SoC in Kconfig.
Also add its appropriate textofs.
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: John Crispin <john@phrozen.org>
Tested-by: Robert Marko <robert.marko@sartura.hr>
Cc: Luka Perkov <luka.perkov@sartura.hr>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/Makefile | 1 +
arch/arm/mach-qcom/Kconfig | 5 +++++
2 files changed, 6 insertions(+)
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -152,6 +152,7 @@ textofs-$(CONFIG_PM_H1940) := 0x001
ifeq ($(CONFIG_ARCH_SA1100),y)
textofs-$(CONFIG_SA1111) := 0x00208000
endif
+textofs-$(CONFIG_ARCH_IPQ40XX) := 0x00208000
textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000
textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000
textofs-$(CONFIG_ARCH_MESON) := 0x00208000
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -12,6 +12,11 @@ menuconfig ARCH_QCOM
if ARCH_QCOM
+config ARCH_IPQ40XX
+ bool "Enable support for IPQ40XX"
+ select CLKSRC_QCOM
+ select HAVE_ARM_ARCH_TIMER
+
config ARCH_MSM8X60
bool "Enable support for MSM8X60"
select CLKSRC_QCOM

View File

@ -1,153 +0,0 @@
From 97043d292365ae39d62b54a6d79dff98d048b501 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Wed, 22 Jan 2020 12:44:14 +0100
Subject: [PATCH] From ebf652b408200504194be32ad0a3f5bb49d6000a Mon Sep 17
00:00:00 2001 From: Robert Marko <robert.marko@sartura.hr> Date: Sun, 12 Jan
2020 12:30:01 +0100 Subject: [PATCH] regulator: add IPQ4019 SDHCI VQMMC LDO
driver
This introduces the IPQ4019 VQMMC LDO driver needed for
the SD/EMMC driver I/O level operation.
This will enable introducing SD/EMMC support for the built-in controller.
Signed-off-by: Mantas Pucka <mantas@8devices.com>
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Link: https://lore.kernel.org/r/20200112113003.11110-1-robert.marko@sartura.hr
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/regulator/Kconfig | 7 ++
drivers/regulator/Makefile | 1 +
drivers/regulator/vqmmc-ipq4019-regulator.c | 101 ++++++++++++++++++++
3 files changed, 109 insertions(+)
create mode 100644 drivers/regulator/vqmmc-ipq4019-regulator.c
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1077,6 +1077,13 @@ config REGULATOR_VEXPRESS
This driver provides support for voltage regulators available
on the ARM Ltd's Versatile Express platform.
+config REGULATOR_VQMMC_IPQ4019
+ tristate "IPQ4019 VQMMC SD LDO regulator support"
+ depends on ARCH_QCOM
+ help
+ This driver provides support for the VQMMC LDO I/0
+ voltage regulator of the IPQ4019 SD/EMMC controller.
+
config REGULATOR_WM831X
tristate "Wolfson Microelectronics WM831x PMIC regulators"
depends on MFD_WM831X
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -132,6 +132,7 @@ obj-$(CONFIG_REGULATOR_TWL4030) += twl-r
obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o
obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o
obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
+obj-$(CONFIG_REGULATOR_VQMMC_IPQ4019) += vqmmc-ipq4019-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
--- /dev/null
+++ b/drivers/regulator/vqmmc-ipq4019-regulator.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2019 Mantas Pucka <mantas@8devices.com>
+// Copyright (c) 2019 Robert Marko <robert.marko@sartura.hr>
+//
+// Driver for IPQ4019 SD/MMC controller's I/O LDO voltage regulator
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+static const unsigned int ipq4019_vmmc_voltages[] = {
+ 1500000, 1800000, 2500000, 3000000,
+};
+
+static const struct regulator_ops ipq4019_regulator_voltage_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc vmmc_regulator = {
+ .name = "vmmcq",
+ .ops = &ipq4019_regulator_voltage_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .volt_table = ipq4019_vmmc_voltages,
+ .n_voltages = ARRAY_SIZE(ipq4019_vmmc_voltages),
+ .vsel_reg = 0,
+ .vsel_mask = 0x3,
+};
+
+static const struct regmap_config ipq4019_vmmcq_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+};
+
+static int ipq4019_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct regulator_init_data *init_data;
+ struct regulator_config cfg = {};
+ struct regulator_dev *rdev;
+ struct resource *res;
+ struct regmap *rmap;
+ void __iomem *base;
+
+ init_data = of_get_regulator_init_data(dev, dev->of_node,
+ &vmmc_regulator);
+ if (!init_data)
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rmap = devm_regmap_init_mmio(dev, base, &ipq4019_vmmcq_regmap_config);
+ if (IS_ERR(rmap))
+ return PTR_ERR(rmap);
+
+ cfg.dev = dev;
+ cfg.init_data = init_data;
+ cfg.of_node = dev->of_node;
+ cfg.regmap = rmap;
+
+ rdev = devm_regulator_register(dev, &vmmc_regulator, &cfg);
+ if (IS_ERR(rdev)) {
+ dev_err(dev, "Failed to register regulator: %ld\n",
+ PTR_ERR(rdev));
+ return PTR_ERR(rdev);
+ }
+ platform_set_drvdata(pdev, rdev);
+
+ return 0;
+}
+
+static const struct of_device_id regulator_ipq4019_of_match[] = {
+ { .compatible = "qcom,vqmmc-ipq4019-regulator", },
+ {},
+};
+
+static struct platform_driver ipq4019_regulator_driver = {
+ .probe = ipq4019_regulator_probe,
+ .driver = {
+ .name = "vqmmc-ipq4019-regulator",
+ .of_match_table = of_match_ptr(regulator_ipq4019_of_match),
+ },
+};
+module_platform_driver(ipq4019_regulator_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mantas Pucka <mantas@8devices.com>");
+MODULE_DESCRIPTION("IPQ4019 VQMMC voltage regulator");

View File

@ -1,36 +0,0 @@
From 04b3b72b5b8fdb883bfdc619cb29b03641b1cc6a Mon Sep 17 00:00:00 2001
From: Robert Marko <robimarko@gmail.com>
Date: Thu, 15 Aug 2019 19:28:23 +0200
Subject: [PATCH] ARM: dts: qcom: ipq4019: Add SDHCI controller node
IPQ4019 has a built in SD/eMMC controller which is supported by the
SDHCI MSM driver, by the "qcom,sdhci-msm-v4" binding.
So lets add the appropriate node for it.
Signed-off-by: Robert Marko <robimarko@gmail.com>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -206,6 +206,18 @@
interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
};
+ sdhci: sdhci@7824900 {
+ compatible = "qcom,sdhci-msm-v4";
+ reg = <0x7824900 0x11c>, <0x7824000 0x800>;
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "hc_irq", "pwr_irq";
+ bus-width = <8>;
+ clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>,
+ <&gcc GCC_DCD_XO_CLK>;
+ clock-names = "core", "iface", "xo";
+ status = "disabled";
+ };
+
blsp_dma: dma@7884000 {
compatible = "qcom,bam-v1.7.0";
reg = <0x07884000 0x23000>;

View File

@ -1,71 +0,0 @@
From 5e4548922009870a38bcf1d887317676d4e08f54 Mon Sep 17 00:00:00 2001
From: Damir Franusic <damir.franusic@sartura.hr>
Date: Thu, 21 Nov 2019 16:29:02 +0100
Subject: [PATCH] ARM: dts: qcom: Add nodes for SMP boot in IPQ40xx
Add missing nodes and properties to enable SMP
support on IPQ40xx devices.
Booting without "saw_l2" node:
[ 0.001400] CPU: Testing write buffer coherency: ok
[ 0.001856] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[ 0.060163] Setting up static identity map for 0x80300000 - 0x80300060
[ 0.080140] rcu: Hierarchical SRCU implementation.
[ 0.120258] smp: Bringing up secondary CPUs ...
[ 0.200540] CPU1: failed to boot: -19
[ 0.280689] CPU2: failed to boot: -19
[ 0.360874] CPU3: failed to boot: -19
[ 0.360966] smp: Brought up 1 node, 1 CPU
[ 0.360979] SMP: Total of 1 processors activated (96.00 BogoMIPS).
[ 0.360988] CPU: All CPU(s) started in SVC mode.
Then, booting with "saw_l2" node present (this patch applied):
[ 0.001450] CPU: Testing write buffer coherency: ok
[ 0.001904] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[ 0.060161] Setting up static identity map for 0x80300000 - 0x80300060
[ 0.080137] rcu: Hierarchical SRCU implementation.
[ 0.120252] smp: Bringing up secondary CPUs ...
[ 0.200958] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[ 0.281091] CPU2: thread -1, cpu 2, socket 0, mpidr 80000002
[ 0.361264] CPU3: thread -1, cpu 3, socket 0, mpidr 80000003
[ 0.361430] smp: Brought up 1 node, 4 CPUs
[ 0.361460] SMP: Total of 4 processors activated (384.00 BogoMIPS).
[ 0.361469] CPU: All CPU(s) started in SVC mode.
Signed-off-by: Damir Franusic <damir.franusic@sartura.hr>
Cc: Luka Perkov <luka.perkov@sartura.hr>
Cc: Robert Marko <robert.marko@sartura.hr>
Cc: Andy Gross <agross@kernel.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: linux-arm-msm@vger.kernel.org
Link: https://lore.kernel.org/r/20191121152902.21394-1-damir.franusic@gmail.com
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -102,6 +102,7 @@
L2: l2-cache {
compatible = "cache";
cache-level = <2>;
+ qcom,saw = <&saw_l2>;
};
};
@@ -353,6 +354,12 @@
regulator;
};
+ saw_l2: regulator@b012000 {
+ compatible = "qcom,saw2";
+ reg = <0xb012000 0x1000>;
+ regulator;
+ };
+
blsp1_uart1: serial@78af000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x78af000 0x200>;

View File

@ -1,119 +0,0 @@
From 8b99dc0922618062a1589ebd74df6108b4f9ac22 Mon Sep 17 00:00:00 2001
From: Christian Lamparter <chunkeey@gmail.com>
Date: Wed, 8 Jan 2020 13:54:55 +0100
Subject: [PATCH] ARM: dts: qcom: add gpio-ranges property
This patch adds the gpio-ranges property to almost all of
the Qualcomm ARM platforms that utilize the pinctrl-msm
framework.
The gpio-ranges property is part of the gpiolib subsystem.
As a result, the binding text is available in section
"2.1 gpio- and pin-controller interaction" of
Documentation/devicetree/bindings/gpio/gpio.txt
For more information please see the patch titled:
"pinctrl: msm: fix gpio-hog related boot issues" from
this series.
Reported-by: Sven Eckelmann <sven.eckelmann@openmesh.com>
Tested-by: Sven Eckelmann <sven.eckelmann@openmesh.com> [ipq4019]
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Tested-by: Robert Marko <robert.marko@sartura.hr> [ipq4019]
Cc: Luka Perkov <luka.perkov@sartura.hr>
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Link: https://lore.kernel.org/r/20200108125455.308969-1-robert.marko@sartura.hr
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
arch/arm/boot/dts/qcom-apq8064.dtsi | 1 +
arch/arm/boot/dts/qcom-apq8084.dtsi | 1 +
arch/arm/boot/dts/qcom-ipq4019.dtsi | 1 +
arch/arm/boot/dts/qcom-ipq8064.dtsi | 1 +
arch/arm/boot/dts/qcom-mdm9615.dtsi | 1 +
arch/arm/boot/dts/qcom-msm8660.dtsi | 1 +
arch/arm/boot/dts/qcom-msm8960.dtsi | 1 +
arch/arm/boot/dts/qcom-msm8974.dtsi | 1 +
8 files changed, 8 insertions(+)
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -350,6 +350,7 @@
reg = <0x800000 0x4000>;
gpio-controller;
+ gpio-ranges = <&tlmm_pinmux 0 0 90>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
--- a/arch/arm/boot/dts/qcom-apq8084.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8084.dtsi
@@ -401,6 +401,7 @@
compatible = "qcom,apq8084-pinctrl";
reg = <0xfd510000 0x4000>;
gpio-controller;
+ gpio-ranges = <&tlmm 0 0 147>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -201,6 +201,7 @@
compatible = "qcom,ipq4019-pinctrl";
reg = <0x01000000 0x300000>;
gpio-controller;
+ gpio-ranges = <&tlmm 0 0 100>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -119,6 +119,7 @@
reg = <0x800000 0x4000>;
gpio-controller;
+ gpio-ranges = <&qcom_pinmux 0 0 69>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
--- a/arch/arm/boot/dts/qcom-mdm9615.dtsi
+++ b/arch/arm/boot/dts/qcom-mdm9615.dtsi
@@ -128,6 +128,7 @@
msmgpio: pinctrl@800000 {
compatible = "qcom,mdm9615-pinctrl";
gpio-controller;
+ gpio-ranges = <&msmgpio 0 0 88>;
#gpio-cells = <2>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
--- a/arch/arm/boot/dts/qcom-msm8660.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8660.dtsi
@@ -115,6 +115,7 @@
reg = <0x800000 0x4000>;
gpio-controller;
+ gpio-ranges = <&tlmm 0 0 173>;
#gpio-cells = <2>;
interrupts = <0 16 0x4>;
interrupt-controller;
--- a/arch/arm/boot/dts/qcom-msm8960.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8960.dtsi
@@ -107,6 +107,7 @@
msmgpio: pinctrl@800000 {
compatible = "qcom,msm8960-pinctrl";
gpio-controller;
+ gpio-ranges = <&msmgpio 0 0 152>;
#gpio-cells = <2>;
interrupts = <0 16 0x4>;
interrupt-controller;
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -707,6 +707,7 @@
compatible = "qcom,msm8974-pinctrl";
reg = <0xfd510000 0x4000>;
gpio-controller;
+ gpio-ranges = <&msmgpio 0 0 146>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;

View File

@ -1,33 +0,0 @@
From 8acc36189dcaf4487d8c6ba7445948f39b1d248a Mon Sep 17 00:00:00 2001
From: Abhishek Sahu <absahu@codeaurora.org>
Date: Fri, 3 Apr 2020 13:40:40 +0200
Subject: [PATCH] ARM: dts: qcom: ipq4019: fix high resolution timer
Cherry-picked from CAF QSDK repo.
Original commit message:
The kernel is failing in switching the timer for high resolution
mode and clock source operates in 10ms resolution. The always-on
property needs to be given for timer device tree node to make
clock source working in 1ns resolution.
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Tested-by: Robert Marko <robert.marko@sartura.hr>
Cc: Luka Perkov <luka.perkov@sartura.hr>
Link: https://lore.kernel.org/r/20200403114040.349787-1-robert.marko@sartura.hr
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 1 +
1 file changed, 1 insertion(+)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -166,6 +166,7 @@
<1 4 0xf08>,
<1 1 0xf08>;
clock-frequency = <48000000>;
+ always-on;
};
soc {

View File

@ -1,210 +0,0 @@
From 466ed24fb22342f3ae1c10758a6a0c6a8c081b2d Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Thu, 30 Apr 2020 11:07:05 +0200
Subject: [PATCH] net: phy: mdio: add IPQ4019 MDIO driver
This patch adds the driver for the MDIO interface
inside of Qualcomm IPQ40xx series SoC-s.
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Cc: Luka Perkov <luka.perkov@sartura.hr>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/Kconfig | 7 ++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/mdio-ipq4019.c | 160 +++++++++++++++++++++++++++++++++
3 files changed, 168 insertions(+)
create mode 100644 drivers/net/phy/mdio-ipq4019.c
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -156,6 +156,13 @@ config MDIO_I2C
This is library mode.
+config MDIO_IPQ4019
+ tristate "Qualcomm IPQ4019 MDIO interface support"
+ depends on HAS_IOMEM && OF_MDIO
+ help
+ This driver supports the MDIO interface found in Qualcomm
+ IPQ40xx series Soc-s.
+
config MDIO_MOXART
tristate "MOXA ART MDIO interface support"
depends on ARCH_MOXART || COMPILE_TEST
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o
obj-$(CONFIG_MDIO_I2C) += mdio-i2c.o
+obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o
obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
--- /dev/null
+++ b/drivers/net/phy/mdio-ipq4019.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2020 Sartura Ltd. */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
+#define MDIO_ADDR_REG 0x44
+#define MDIO_DATA_WRITE_REG 0x48
+#define MDIO_DATA_READ_REG 0x4c
+#define MDIO_CMD_REG 0x50
+#define MDIO_CMD_ACCESS_BUSY BIT(16)
+#define MDIO_CMD_ACCESS_START BIT(8)
+#define MDIO_CMD_ACCESS_CODE_READ 0
+#define MDIO_CMD_ACCESS_CODE_WRITE 1
+
+#define ipq4019_MDIO_TIMEOUT 10000
+#define ipq4019_MDIO_SLEEP 10
+
+struct ipq4019_mdio_data {
+ void __iomem *membase;
+};
+
+static int ipq4019_mdio_wait_busy(struct mii_bus *bus)
+{
+ struct ipq4019_mdio_data *priv = bus->priv;
+ unsigned int busy;
+
+ return readl_poll_timeout(priv->membase + MDIO_CMD_REG, busy,
+ (busy & MDIO_CMD_ACCESS_BUSY) == 0,
+ ipq4019_MDIO_SLEEP, ipq4019_MDIO_TIMEOUT);
+}
+
+static int ipq4019_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct ipq4019_mdio_data *priv = bus->priv;
+ unsigned int cmd;
+
+ /* Reject clause 45 */
+ if (regnum & MII_ADDR_C45)
+ return -EOPNOTSUPP;
+
+ if (ipq4019_mdio_wait_busy(bus))
+ return -ETIMEDOUT;
+
+ /* issue the phy address and reg */
+ writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
+
+ cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_READ;
+
+ /* issue read command */
+ writel(cmd, priv->membase + MDIO_CMD_REG);
+
+ /* Wait read complete */
+ if (ipq4019_mdio_wait_busy(bus))
+ return -ETIMEDOUT;
+
+ /* Read and return data */
+ return readl(priv->membase + MDIO_DATA_READ_REG);
+}
+
+static int ipq4019_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+ u16 value)
+{
+ struct ipq4019_mdio_data *priv = bus->priv;
+ unsigned int cmd;
+
+ /* Reject clause 45 */
+ if (regnum & MII_ADDR_C45)
+ return -EOPNOTSUPP;
+
+ if (ipq4019_mdio_wait_busy(bus))
+ return -ETIMEDOUT;
+
+ /* issue the phy address and reg */
+ writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
+
+ /* issue write data */
+ writel(value, priv->membase + MDIO_DATA_WRITE_REG);
+
+ cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_WRITE;
+ /* issue write command */
+ writel(cmd, priv->membase + MDIO_CMD_REG);
+
+ /* Wait write complete */
+ if (ipq4019_mdio_wait_busy(bus))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int ipq4019_mdio_probe(struct platform_device *pdev)
+{
+ struct ipq4019_mdio_data *priv;
+ struct mii_bus *bus;
+ int ret;
+
+ bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
+ if (!bus)
+ return -ENOMEM;
+
+ priv = bus->priv;
+
+ priv->membase = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->membase))
+ return PTR_ERR(priv->membase);
+
+ bus->name = "ipq4019_mdio";
+ bus->read = ipq4019_mdio_read;
+ bus->write = ipq4019_mdio_write;
+ bus->parent = &pdev->dev;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);
+
+ ret = of_mdiobus_register(bus, pdev->dev.of_node);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, bus);
+
+ return 0;
+}
+
+static int ipq4019_mdio_remove(struct platform_device *pdev)
+{
+ struct mii_bus *bus = platform_get_drvdata(pdev);
+
+ mdiobus_unregister(bus);
+
+ return 0;
+}
+
+static const struct of_device_id ipq4019_mdio_dt_ids[] = {
+ { .compatible = "qcom,ipq4019-mdio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ipq4019_mdio_dt_ids);
+
+static struct platform_driver ipq4019_mdio_driver = {
+ .probe = ipq4019_mdio_probe,
+ .remove = ipq4019_mdio_remove,
+ .driver = {
+ .name = "ipq4019-mdio",
+ .of_match_table = ipq4019_mdio_dt_ids,
+ },
+};
+
+module_platform_driver(ipq4019_mdio_driver);
+
+MODULE_DESCRIPTION("ipq4019 MDIO interface driver");
+MODULE_AUTHOR("Qualcomm Atheros");
+MODULE_LICENSE("Dual BSD/GPL");

View File

@ -1,57 +0,0 @@
From 9c8c0f70ec6fdac2398632c723c48277be09b7c0 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Thu, 30 Apr 2020 11:07:07 +0200
Subject: [PATCH] ARM: dts: qcom: ipq4019: add MDIO node
This patch adds the necessary MDIO interface node
to the Qualcomm IPQ4019 DTSI.
Built-in QCA8337N switch is managed using it,
and since we have a driver for it lets add it.
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Cc: Luka Perkov <luka.perkov@sartura.hr>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -577,5 +577,33 @@
"legacy";
status = "disabled";
};
+
+ mdio: mdio@90000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "qcom,ipq4019-mdio";
+ reg = <0x90000 0x64>;
+ status = "disabled";
+
+ ethphy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+
+ ethphy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+
+ ethphy2: ethernet-phy@2 {
+ reg = <2>;
+ };
+
+ ethphy3: ethernet-phy@3 {
+ reg = <3>;
+ };
+
+ ethphy4: ethernet-phy@4 {
+ reg = <4>;
+ };
+ };
};
};

View File

@ -1,31 +0,0 @@
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Subject: [PATCH] crypto: qce - add CRYPTO_ALG_KERN_DRIVER_ONLY flag
Set the CRYPTO_ALG_KERN_DRIVER_ONLY flag to all algorithms exposed by
the qce driver, since they are all hardware accelerated, accessible
through a kernel driver only, and not available directly to userspace.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
--- a/drivers/crypto/qce/ablkcipher.c
+++ b/drivers/crypto/qce/ablkcipher.c
@@ -380,7 +380,7 @@ static int qce_ablkcipher_register_one(c
alg->cra_priority = 300;
alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK;
+ CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_KERN_DRIVER_ONLY;
alg->cra_ctxsize = sizeof(struct qce_cipher_ctx);
alg->cra_alignmask = 0;
alg->cra_type = &crypto_ablkcipher_type;
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -495,7 +495,7 @@ static int qce_ahash_register_one(const
base = &alg->halg.base;
base->cra_blocksize = def->blocksize;
base->cra_priority = 300;
- base->cra_flags = CRYPTO_ALG_ASYNC;
+ base->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
base->cra_ctxsize = sizeof(struct qce_sha_ctx);
base->cra_alignmask = 0;
base->cra_module = THIS_MODULE;

View File

@ -1,993 +0,0 @@
From f441873642eebf20566c18d2966a8cd4b433ec1c Mon Sep 17 00:00:00 2001
From: Ard Biesheuvel <ardb@kernel.org>
Date: Tue, 5 Nov 2019 14:28:17 +0100
Subject: [PATCH] crypto: qce - switch to skcipher API
Commit 7a7ffe65c8c5 ("crypto: skcipher - Add top-level skcipher interface")
dated 20 august 2015 introduced the new skcipher API which is supposed to
replace both blkcipher and ablkcipher. While all consumers of the API have
been converted long ago, some producers of the ablkcipher remain, forcing
us to keep the ablkcipher support routines alive, along with the matching
code to expose [a]blkciphers via the skcipher API.
So switch this driver to the skcipher API, allowing us to finally drop the
blkcipher code in the near future.
Reviewed-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Backported-to-4.19-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
--- a/drivers/crypto/qce/Makefile
+++ b/drivers/crypto/qce/Makefile
@@ -4,4 +4,4 @@ qcrypto-objs := core.o \
common.o \
dma.o \
sha.o \
- ablkcipher.o
+ skcipher.o
--- a/drivers/crypto/qce/cipher.h
+++ b/drivers/crypto/qce/cipher.h
@@ -45,12 +45,12 @@ struct qce_cipher_reqctx {
unsigned int cryptlen;
};
-static inline struct qce_alg_template *to_cipher_tmpl(struct crypto_tfm *tfm)
+static inline struct qce_alg_template *to_cipher_tmpl(struct crypto_skcipher *tfm)
{
- struct crypto_alg *alg = tfm->__crt_alg;
- return container_of(alg, struct qce_alg_template, alg.crypto);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ return container_of(alg, struct qce_alg_template, alg.skcipher);
}
-extern const struct qce_algo_ops ablkcipher_ops;
+extern const struct qce_algo_ops skcipher_ops;
#endif /* _CIPHER_H_ */
--- a/drivers/crypto/qce/common.c
+++ b/drivers/crypto/qce/common.c
@@ -304,13 +304,13 @@ go_proc:
return 0;
}
-static int qce_setup_regs_ablkcipher(struct crypto_async_request *async_req,
+static int qce_setup_regs_skcipher(struct crypto_async_request *async_req,
u32 totallen, u32 offset)
{
- struct ablkcipher_request *req = ablkcipher_request_cast(async_req);
- struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
+ struct skcipher_request *req = skcipher_request_cast(async_req);
+ struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
struct qce_cipher_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
- struct qce_alg_template *tmpl = to_cipher_tmpl(async_req->tfm);
+ struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
struct qce_device *qce = tmpl->qce;
__be32 enckey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(__be32)] = {0};
__be32 enciv[QCE_MAX_IV_SIZE / sizeof(__be32)] = {0};
@@ -389,8 +389,8 @@ int qce_start(struct crypto_async_reques
u32 offset)
{
switch (type) {
- case CRYPTO_ALG_TYPE_ABLKCIPHER:
- return qce_setup_regs_ablkcipher(async_req, totallen, offset);
+ case CRYPTO_ALG_TYPE_SKCIPHER:
+ return qce_setup_regs_skcipher(async_req, totallen, offset);
case CRYPTO_ALG_TYPE_AHASH:
return qce_setup_regs_ahash(async_req, totallen, offset);
default:
--- a/drivers/crypto/qce/common.h
+++ b/drivers/crypto/qce/common.h
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <crypto/aes.h>
#include <crypto/hash.h>
+#include <crypto/internal/skcipher.h>
/* key size in bytes */
#define QCE_SHA_HMAC_KEY_SIZE 64
@@ -79,7 +80,7 @@ struct qce_alg_template {
unsigned long alg_flags;
const u32 *std_iv;
union {
- struct crypto_alg crypto;
+ struct skcipher_alg skcipher;
struct ahash_alg ahash;
} alg;
struct qce_device *qce;
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -22,7 +22,7 @@
#define QCE_QUEUE_LENGTH 1
static const struct qce_algo_ops *qce_ops[] = {
- &ablkcipher_ops,
+ &skcipher_ops,
&ahash_ops,
};
--- a/drivers/crypto/qce/ablkcipher.c
+++ /dev/null
@@ -1,440 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/types.h>
-#include <crypto/aes.h>
-#include <crypto/internal/des.h>
-#include <crypto/internal/skcipher.h>
-
-#include "cipher.h"
-
-static LIST_HEAD(ablkcipher_algs);
-
-static void qce_ablkcipher_done(void *data)
-{
- struct crypto_async_request *async_req = data;
- struct ablkcipher_request *req = ablkcipher_request_cast(async_req);
- struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
- struct qce_alg_template *tmpl = to_cipher_tmpl(async_req->tfm);
- struct qce_device *qce = tmpl->qce;
- enum dma_data_direction dir_src, dir_dst;
- u32 status;
- int error;
- bool diff_dst;
-
- diff_dst = (req->src != req->dst) ? true : false;
- dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
- dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
-
- error = qce_dma_terminate_all(&qce->dma);
- if (error)
- dev_dbg(qce->dev, "ablkcipher dma termination error (%d)\n",
- error);
-
- if (diff_dst)
- dma_unmap_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src);
- dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
-
- sg_free_table(&rctx->dst_tbl);
-
- error = qce_check_status(qce, &status);
- if (error < 0)
- dev_dbg(qce->dev, "ablkcipher operation error (%x)\n", status);
-
- qce->async_req_done(tmpl->qce, error);
-}
-
-static int
-qce_ablkcipher_async_req_handle(struct crypto_async_request *async_req)
-{
- struct ablkcipher_request *req = ablkcipher_request_cast(async_req);
- struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct qce_alg_template *tmpl = to_cipher_tmpl(async_req->tfm);
- struct qce_device *qce = tmpl->qce;
- enum dma_data_direction dir_src, dir_dst;
- struct scatterlist *sg;
- bool diff_dst;
- gfp_t gfp;
- int ret;
-
- rctx->iv = req->info;
- rctx->ivsize = crypto_ablkcipher_ivsize(ablkcipher);
- rctx->cryptlen = req->nbytes;
-
- diff_dst = (req->src != req->dst) ? true : false;
- dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
- dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
-
- rctx->src_nents = sg_nents_for_len(req->src, req->nbytes);
- if (diff_dst)
- rctx->dst_nents = sg_nents_for_len(req->dst, req->nbytes);
- else
- rctx->dst_nents = rctx->src_nents;
- if (rctx->src_nents < 0) {
- dev_err(qce->dev, "Invalid numbers of src SG.\n");
- return rctx->src_nents;
- }
- if (rctx->dst_nents < 0) {
- dev_err(qce->dev, "Invalid numbers of dst SG.\n");
- return -rctx->dst_nents;
- }
-
- rctx->dst_nents += 1;
-
- gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
- GFP_KERNEL : GFP_ATOMIC;
-
- ret = sg_alloc_table(&rctx->dst_tbl, rctx->dst_nents, gfp);
- if (ret)
- return ret;
-
- sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
-
- sg = qce_sgtable_add(&rctx->dst_tbl, req->dst);
- if (IS_ERR(sg)) {
- ret = PTR_ERR(sg);
- goto error_free;
- }
-
- sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg);
- if (IS_ERR(sg)) {
- ret = PTR_ERR(sg);
- goto error_free;
- }
-
- sg_mark_end(sg);
- rctx->dst_sg = rctx->dst_tbl.sgl;
-
- ret = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
- if (ret < 0)
- goto error_free;
-
- if (diff_dst) {
- ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, dir_src);
- if (ret < 0)
- goto error_unmap_dst;
- rctx->src_sg = req->src;
- } else {
- rctx->src_sg = rctx->dst_sg;
- }
-
- ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, rctx->src_nents,
- rctx->dst_sg, rctx->dst_nents,
- qce_ablkcipher_done, async_req);
- if (ret)
- goto error_unmap_src;
-
- qce_dma_issue_pending(&qce->dma);
-
- ret = qce_start(async_req, tmpl->crypto_alg_type, req->nbytes, 0);
- if (ret)
- goto error_terminate;
-
- return 0;
-
-error_terminate:
- qce_dma_terminate_all(&qce->dma);
-error_unmap_src:
- if (diff_dst)
- dma_unmap_sg(qce->dev, req->src, rctx->src_nents, dir_src);
-error_unmap_dst:
- dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
-error_free:
- sg_free_table(&rctx->dst_tbl);
- return ret;
-}
-
-static int qce_ablkcipher_setkey(struct crypto_ablkcipher *ablk, const u8 *key,
- unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablk);
- struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
- int ret;
-
- if (!key || !keylen)
- return -EINVAL;
-
- switch (keylen) {
- case AES_KEYSIZE_128:
- case AES_KEYSIZE_256:
- break;
- default:
- goto fallback;
- }
-
- ctx->enc_keylen = keylen;
- memcpy(ctx->enc_key, key, keylen);
- return 0;
-fallback:
- ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
- if (!ret)
- ctx->enc_keylen = keylen;
- return ret;
-}
-
-static int qce_des_setkey(struct crypto_ablkcipher *ablk, const u8 *key,
- unsigned int keylen)
-{
- struct qce_cipher_ctx *ctx = crypto_ablkcipher_ctx(ablk);
- int err;
-
- err = verify_ablkcipher_des_key(ablk, key);
- if (err)
- return err;
-
- ctx->enc_keylen = keylen;
- memcpy(ctx->enc_key, key, keylen);
- return 0;
-}
-
-static int qce_des3_setkey(struct crypto_ablkcipher *ablk, const u8 *key,
- unsigned int keylen)
-{
- struct qce_cipher_ctx *ctx = crypto_ablkcipher_ctx(ablk);
- int err;
-
- err = verify_ablkcipher_des3_key(ablk, key);
- if (err)
- return err;
-
- ctx->enc_keylen = keylen;
- memcpy(ctx->enc_key, key, keylen);
- return 0;
-}
-
-static int qce_ablkcipher_crypt(struct ablkcipher_request *req, int encrypt)
-{
- struct crypto_tfm *tfm =
- crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req));
- struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
- struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
- struct qce_alg_template *tmpl = to_cipher_tmpl(tfm);
- int ret;
-
- rctx->flags = tmpl->alg_flags;
- rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
-
- if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 &&
- ctx->enc_keylen != AES_KEYSIZE_256) {
- SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
-
- skcipher_request_set_sync_tfm(subreq, ctx->fallback);
- skcipher_request_set_callback(subreq, req->base.flags,
- NULL, NULL);
- skcipher_request_set_crypt(subreq, req->src, req->dst,
- req->nbytes, req->info);
- ret = encrypt ? crypto_skcipher_encrypt(subreq) :
- crypto_skcipher_decrypt(subreq);
- skcipher_request_zero(subreq);
- return ret;
- }
-
- return tmpl->qce->async_req_enqueue(tmpl->qce, &req->base);
-}
-
-static int qce_ablkcipher_encrypt(struct ablkcipher_request *req)
-{
- return qce_ablkcipher_crypt(req, 1);
-}
-
-static int qce_ablkcipher_decrypt(struct ablkcipher_request *req)
-{
- return qce_ablkcipher_crypt(req, 0);
-}
-
-static int qce_ablkcipher_init(struct crypto_tfm *tfm)
-{
- struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-
- memset(ctx, 0, sizeof(*ctx));
- tfm->crt_ablkcipher.reqsize = sizeof(struct qce_cipher_reqctx);
-
- ctx->fallback = crypto_alloc_sync_skcipher(crypto_tfm_alg_name(tfm),
- 0, CRYPTO_ALG_NEED_FALLBACK);
- return PTR_ERR_OR_ZERO(ctx->fallback);
-}
-
-static void qce_ablkcipher_exit(struct crypto_tfm *tfm)
-{
- struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-
- crypto_free_sync_skcipher(ctx->fallback);
-}
-
-struct qce_ablkcipher_def {
- unsigned long flags;
- const char *name;
- const char *drv_name;
- unsigned int blocksize;
- unsigned int ivsize;
- unsigned int min_keysize;
- unsigned int max_keysize;
-};
-
-static const struct qce_ablkcipher_def ablkcipher_def[] = {
- {
- .flags = QCE_ALG_AES | QCE_MODE_ECB,
- .name = "ecb(aes)",
- .drv_name = "ecb-aes-qce",
- .blocksize = AES_BLOCK_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- },
- {
- .flags = QCE_ALG_AES | QCE_MODE_CBC,
- .name = "cbc(aes)",
- .drv_name = "cbc-aes-qce",
- .blocksize = AES_BLOCK_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- },
- {
- .flags = QCE_ALG_AES | QCE_MODE_CTR,
- .name = "ctr(aes)",
- .drv_name = "ctr-aes-qce",
- .blocksize = AES_BLOCK_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- },
- {
- .flags = QCE_ALG_AES | QCE_MODE_XTS,
- .name = "xts(aes)",
- .drv_name = "xts-aes-qce",
- .blocksize = AES_BLOCK_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- },
- {
- .flags = QCE_ALG_DES | QCE_MODE_ECB,
- .name = "ecb(des)",
- .drv_name = "ecb-des-qce",
- .blocksize = DES_BLOCK_SIZE,
- .ivsize = 0,
- .min_keysize = DES_KEY_SIZE,
- .max_keysize = DES_KEY_SIZE,
- },
- {
- .flags = QCE_ALG_DES | QCE_MODE_CBC,
- .name = "cbc(des)",
- .drv_name = "cbc-des-qce",
- .blocksize = DES_BLOCK_SIZE,
- .ivsize = DES_BLOCK_SIZE,
- .min_keysize = DES_KEY_SIZE,
- .max_keysize = DES_KEY_SIZE,
- },
- {
- .flags = QCE_ALG_3DES | QCE_MODE_ECB,
- .name = "ecb(des3_ede)",
- .drv_name = "ecb-3des-qce",
- .blocksize = DES3_EDE_BLOCK_SIZE,
- .ivsize = 0,
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- },
- {
- .flags = QCE_ALG_3DES | QCE_MODE_CBC,
- .name = "cbc(des3_ede)",
- .drv_name = "cbc-3des-qce",
- .blocksize = DES3_EDE_BLOCK_SIZE,
- .ivsize = DES3_EDE_BLOCK_SIZE,
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- },
-};
-
-static int qce_ablkcipher_register_one(const struct qce_ablkcipher_def *def,
- struct qce_device *qce)
-{
- struct qce_alg_template *tmpl;
- struct crypto_alg *alg;
- int ret;
-
- tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
- if (!tmpl)
- return -ENOMEM;
-
- alg = &tmpl->alg.crypto;
-
- snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
- snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
- def->drv_name);
-
- alg->cra_blocksize = def->blocksize;
- alg->cra_ablkcipher.ivsize = def->ivsize;
- alg->cra_ablkcipher.min_keysize = def->min_keysize;
- alg->cra_ablkcipher.max_keysize = def->max_keysize;
- alg->cra_ablkcipher.setkey = IS_3DES(def->flags) ? qce_des3_setkey :
- IS_DES(def->flags) ? qce_des_setkey :
- qce_ablkcipher_setkey;
- alg->cra_ablkcipher.encrypt = qce_ablkcipher_encrypt;
- alg->cra_ablkcipher.decrypt = qce_ablkcipher_decrypt;
-
- alg->cra_priority = 300;
- alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_KERN_DRIVER_ONLY;
- alg->cra_ctxsize = sizeof(struct qce_cipher_ctx);
- alg->cra_alignmask = 0;
- alg->cra_type = &crypto_ablkcipher_type;
- alg->cra_module = THIS_MODULE;
- alg->cra_init = qce_ablkcipher_init;
- alg->cra_exit = qce_ablkcipher_exit;
-
- INIT_LIST_HEAD(&tmpl->entry);
- tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_ABLKCIPHER;
- tmpl->alg_flags = def->flags;
- tmpl->qce = qce;
-
- ret = crypto_register_alg(alg);
- if (ret) {
- kfree(tmpl);
- dev_err(qce->dev, "%s registration failed\n", alg->cra_name);
- return ret;
- }
-
- list_add_tail(&tmpl->entry, &ablkcipher_algs);
- dev_dbg(qce->dev, "%s is registered\n", alg->cra_name);
- return 0;
-}
-
-static void qce_ablkcipher_unregister(struct qce_device *qce)
-{
- struct qce_alg_template *tmpl, *n;
-
- list_for_each_entry_safe(tmpl, n, &ablkcipher_algs, entry) {
- crypto_unregister_alg(&tmpl->alg.crypto);
- list_del(&tmpl->entry);
- kfree(tmpl);
- }
-}
-
-static int qce_ablkcipher_register(struct qce_device *qce)
-{
- int ret, i;
-
- for (i = 0; i < ARRAY_SIZE(ablkcipher_def); i++) {
- ret = qce_ablkcipher_register_one(&ablkcipher_def[i], qce);
- if (ret)
- goto err;
- }
-
- return 0;
-err:
- qce_ablkcipher_unregister(qce);
- return ret;
-}
-
-const struct qce_algo_ops ablkcipher_ops = {
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .register_algs = qce_ablkcipher_register,
- .unregister_algs = qce_ablkcipher_unregister,
- .async_req_handle = qce_ablkcipher_async_req_handle,
-};
--- /dev/null
+++ b/drivers/crypto/qce/skcipher.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <crypto/aes.h>
+#include <crypto/internal/des.h>
+#include <crypto/internal/skcipher.h>
+
+#include "cipher.h"
+
+static LIST_HEAD(skcipher_algs);
+
+static void qce_skcipher_done(void *data)
+{
+ struct crypto_async_request *async_req = data;
+ struct skcipher_request *req = skcipher_request_cast(async_req);
+ struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
+ struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
+ struct qce_device *qce = tmpl->qce;
+ enum dma_data_direction dir_src, dir_dst;
+ u32 status;
+ int error;
+ bool diff_dst;
+
+ diff_dst = (req->src != req->dst) ? true : false;
+ dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
+ dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
+
+ error = qce_dma_terminate_all(&qce->dma);
+ if (error)
+ dev_dbg(qce->dev, "skcipher dma termination error (%d)\n",
+ error);
+
+ if (diff_dst)
+ dma_unmap_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src);
+ dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+
+ sg_free_table(&rctx->dst_tbl);
+
+ error = qce_check_status(qce, &status);
+ if (error < 0)
+ dev_dbg(qce->dev, "skcipher operation error (%x)\n", status);
+
+ qce->async_req_done(tmpl->qce, error);
+}
+
+static int
+qce_skcipher_async_req_handle(struct crypto_async_request *async_req)
+{
+ struct skcipher_request *req = skcipher_request_cast(async_req);
+ struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
+ struct qce_device *qce = tmpl->qce;
+ enum dma_data_direction dir_src, dir_dst;
+ struct scatterlist *sg;
+ bool diff_dst;
+ gfp_t gfp;
+ int ret;
+
+ rctx->iv = req->iv;
+ rctx->ivsize = crypto_skcipher_ivsize(skcipher);
+ rctx->cryptlen = req->cryptlen;
+
+ diff_dst = (req->src != req->dst) ? true : false;
+ dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
+ dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
+
+ rctx->src_nents = sg_nents_for_len(req->src, req->cryptlen);
+ if (diff_dst)
+ rctx->dst_nents = sg_nents_for_len(req->dst, req->cryptlen);
+ else
+ rctx->dst_nents = rctx->src_nents;
+ if (rctx->src_nents < 0) {
+ dev_err(qce->dev, "Invalid numbers of src SG.\n");
+ return rctx->src_nents;
+ }
+ if (rctx->dst_nents < 0) {
+ dev_err(qce->dev, "Invalid numbers of dst SG.\n");
+ return -rctx->dst_nents;
+ }
+
+ rctx->dst_nents += 1;
+
+ gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+
+ ret = sg_alloc_table(&rctx->dst_tbl, rctx->dst_nents, gfp);
+ if (ret)
+ return ret;
+
+ sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
+
+ sg = qce_sgtable_add(&rctx->dst_tbl, req->dst);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto error_free;
+ }
+
+ sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto error_free;
+ }
+
+ sg_mark_end(sg);
+ rctx->dst_sg = rctx->dst_tbl.sgl;
+
+ ret = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+ if (ret < 0)
+ goto error_free;
+
+ if (diff_dst) {
+ ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, dir_src);
+ if (ret < 0)
+ goto error_unmap_dst;
+ rctx->src_sg = req->src;
+ } else {
+ rctx->src_sg = rctx->dst_sg;
+ }
+
+ ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, rctx->src_nents,
+ rctx->dst_sg, rctx->dst_nents,
+ qce_skcipher_done, async_req);
+ if (ret)
+ goto error_unmap_src;
+
+ qce_dma_issue_pending(&qce->dma);
+
+ ret = qce_start(async_req, tmpl->crypto_alg_type, req->cryptlen, 0);
+ if (ret)
+ goto error_terminate;
+
+ return 0;
+
+error_terminate:
+ qce_dma_terminate_all(&qce->dma);
+error_unmap_src:
+ if (diff_dst)
+ dma_unmap_sg(qce->dev, req->src, rctx->src_nents, dir_src);
+error_unmap_dst:
+ dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+error_free:
+ sg_free_table(&rctx->dst_tbl);
+ return ret;
+}
+
+static int qce_skcipher_setkey(struct crypto_skcipher *ablk, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_tfm *tfm = crypto_skcipher_tfm(ablk);
+ struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+ if (!key || !keylen)
+ return -EINVAL;
+
+ switch (keylen) {
+ case AES_KEYSIZE_128:
+ case AES_KEYSIZE_256:
+ break;
+ default:
+ goto fallback;
+ }
+
+ ctx->enc_keylen = keylen;
+ memcpy(ctx->enc_key, key, keylen);
+ return 0;
+fallback:
+ ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
+ if (!ret)
+ ctx->enc_keylen = keylen;
+ return ret;
+}
+
+static int qce_des_setkey(struct crypto_skcipher *ablk, const u8 *key,
+ unsigned int keylen)
+{
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(ablk);
+ int err;
+
+ err = verify_skcipher_des_key(ablk, key);
+ if (err)
+ return err;
+
+ ctx->enc_keylen = keylen;
+ memcpy(ctx->enc_key, key, keylen);
+ return 0;
+}
+
+static int qce_des3_setkey(struct crypto_skcipher *ablk, const u8 *key,
+ unsigned int keylen)
+{
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(ablk);
+ int err;
+
+ err = verify_skcipher_des3_key(ablk, key);
+ if (err)
+ return err;
+
+ ctx->enc_keylen = keylen;
+ memcpy(ctx->enc_key, key, keylen);
+ return 0;
+}
+
+static int qce_skcipher_crypt(struct skcipher_request *req, int encrypt)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
+ struct qce_alg_template *tmpl = to_cipher_tmpl(tfm);
+ int ret;
+
+ rctx->flags = tmpl->alg_flags;
+ rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
+
+ if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 &&
+ ctx->enc_keylen != AES_KEYSIZE_256) {
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
+ skcipher_request_set_callback(subreq, req->base.flags,
+ NULL, NULL);
+ skcipher_request_set_crypt(subreq, req->src, req->dst,
+ req->cryptlen, req->iv);
+ ret = encrypt ? crypto_skcipher_encrypt(subreq) :
+ crypto_skcipher_decrypt(subreq);
+ skcipher_request_zero(subreq);
+ return ret;
+ }
+
+ return tmpl->qce->async_req_enqueue(tmpl->qce, &req->base);
+}
+
+static int qce_skcipher_encrypt(struct skcipher_request *req)
+{
+ return qce_skcipher_crypt(req, 1);
+}
+
+static int qce_skcipher_decrypt(struct skcipher_request *req)
+{
+ return qce_skcipher_crypt(req, 0);
+}
+
+static int qce_skcipher_init(struct crypto_skcipher *tfm)
+{
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ memset(ctx, 0, sizeof(*ctx));
+ crypto_skcipher_set_reqsize(tfm, sizeof(struct qce_cipher_reqctx));
+
+ ctx->fallback = crypto_alloc_sync_skcipher(crypto_tfm_alg_name(&tfm->base),
+ 0, CRYPTO_ALG_NEED_FALLBACK);
+ return PTR_ERR_OR_ZERO(ctx->fallback);
+}
+
+static void qce_skcipher_exit(struct crypto_skcipher *tfm)
+{
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ crypto_free_sync_skcipher(ctx->fallback);
+}
+
+struct qce_skcipher_def {
+ unsigned long flags;
+ const char *name;
+ const char *drv_name;
+ unsigned int blocksize;
+ unsigned int ivsize;
+ unsigned int min_keysize;
+ unsigned int max_keysize;
+};
+
+static const struct qce_skcipher_def skcipher_def[] = {
+ {
+ .flags = QCE_ALG_AES | QCE_MODE_ECB,
+ .name = "ecb(aes)",
+ .drv_name = "ecb-aes-qce",
+ .blocksize = AES_BLOCK_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ },
+ {
+ .flags = QCE_ALG_AES | QCE_MODE_CBC,
+ .name = "cbc(aes)",
+ .drv_name = "cbc-aes-qce",
+ .blocksize = AES_BLOCK_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ },
+ {
+ .flags = QCE_ALG_AES | QCE_MODE_CTR,
+ .name = "ctr(aes)",
+ .drv_name = "ctr-aes-qce",
+ .blocksize = AES_BLOCK_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ },
+ {
+ .flags = QCE_ALG_AES | QCE_MODE_XTS,
+ .name = "xts(aes)",
+ .drv_name = "xts-aes-qce",
+ .blocksize = AES_BLOCK_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ },
+ {
+ .flags = QCE_ALG_DES | QCE_MODE_ECB,
+ .name = "ecb(des)",
+ .drv_name = "ecb-des-qce",
+ .blocksize = DES_BLOCK_SIZE,
+ .ivsize = 0,
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ },
+ {
+ .flags = QCE_ALG_DES | QCE_MODE_CBC,
+ .name = "cbc(des)",
+ .drv_name = "cbc-des-qce",
+ .blocksize = DES_BLOCK_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ },
+ {
+ .flags = QCE_ALG_3DES | QCE_MODE_ECB,
+ .name = "ecb(des3_ede)",
+ .drv_name = "ecb-3des-qce",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .ivsize = 0,
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ },
+ {
+ .flags = QCE_ALG_3DES | QCE_MODE_CBC,
+ .name = "cbc(des3_ede)",
+ .drv_name = "cbc-3des-qce",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ },
+};
+
+static int qce_skcipher_register_one(const struct qce_skcipher_def *def,
+ struct qce_device *qce)
+{
+ struct qce_alg_template *tmpl;
+ struct skcipher_alg *alg;
+ int ret;
+
+ tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
+ if (!tmpl)
+ return -ENOMEM;
+
+ alg = &tmpl->alg.skcipher;
+
+ snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
+ snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ def->drv_name);
+
+ alg->base.cra_blocksize = def->blocksize;
+ alg->ivsize = def->ivsize;
+ alg->min_keysize = def->min_keysize;
+ alg->max_keysize = def->max_keysize;
+ alg->setkey = IS_3DES(def->flags) ? qce_des3_setkey :
+ IS_DES(def->flags) ? qce_des_setkey :
+ qce_skcipher_setkey;
+ alg->encrypt = qce_skcipher_encrypt;
+ alg->decrypt = qce_skcipher_decrypt;
+
+ alg->base.cra_priority = 300;
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK |
+ CRYPTO_ALG_KERN_DRIVER_ONLY;
+ alg->base.cra_ctxsize = sizeof(struct qce_cipher_ctx);
+ alg->base.cra_alignmask = 0;
+ alg->base.cra_module = THIS_MODULE;
+
+ alg->init = qce_skcipher_init;
+ alg->exit = qce_skcipher_exit;
+
+ INIT_LIST_HEAD(&tmpl->entry);
+ tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_SKCIPHER;
+ tmpl->alg_flags = def->flags;
+ tmpl->qce = qce;
+
+ ret = crypto_register_skcipher(alg);
+ if (ret) {
+ kfree(tmpl);
+ dev_err(qce->dev, "%s registration failed\n", alg->base.cra_name);
+ return ret;
+ }
+
+ list_add_tail(&tmpl->entry, &skcipher_algs);
+ dev_dbg(qce->dev, "%s is registered\n", alg->base.cra_name);
+ return 0;
+}
+
+static void qce_skcipher_unregister(struct qce_device *qce)
+{
+ struct qce_alg_template *tmpl, *n;
+
+ list_for_each_entry_safe(tmpl, n, &skcipher_algs, entry) {
+ crypto_unregister_skcipher(&tmpl->alg.skcipher);
+ list_del(&tmpl->entry);
+ kfree(tmpl);
+ }
+}
+
+static int qce_skcipher_register(struct qce_device *qce)
+{
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(skcipher_def); i++) {
+ ret = qce_skcipher_register_one(&skcipher_def[i], qce);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+err:
+ qce_skcipher_unregister(qce);
+ return ret;
+}
+
+const struct qce_algo_ops skcipher_ops = {
+ .type = CRYPTO_ALG_TYPE_SKCIPHER,
+ .register_algs = qce_skcipher_register,
+ .unregister_algs = qce_skcipher_unregister,
+ .async_req_handle = qce_skcipher_async_req_handle,
+};

View File

@ -1,43 +0,0 @@
From bb5c863b3d3cbd10e80b2ebf409934a091058f54 Mon Sep 17 00:00:00 2001
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Date: Fri, 20 Dec 2019 16:02:13 -0300
Subject: [PATCH 02/11] crypto: qce - fix ctr-aes-qce block, chunk sizes
Set blocksize of ctr-aes-qce to 1, so it can operate as a stream cipher,
adding the definition for chucksize instead, where the underlying block
size belongs.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/qce/skcipher.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -270,6 +270,7 @@ struct qce_skcipher_def {
const char *name;
const char *drv_name;
unsigned int blocksize;
+ unsigned int chunksize;
unsigned int ivsize;
unsigned int min_keysize;
unsigned int max_keysize;
@@ -298,7 +299,8 @@ static const struct qce_skcipher_def skc
.flags = QCE_ALG_AES | QCE_MODE_CTR,
.name = "ctr(aes)",
.drv_name = "ctr-aes-qce",
- .blocksize = AES_BLOCK_SIZE,
+ .blocksize = 1,
+ .chunksize = AES_BLOCK_SIZE,
.ivsize = AES_BLOCK_SIZE,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
@@ -368,6 +370,7 @@ static int qce_skcipher_register_one(con
def->drv_name);
alg->base.cra_blocksize = def->blocksize;
+ alg->chunksize = def->chunksize;
alg->ivsize = def->ivsize;
alg->min_keysize = def->min_keysize;
alg->max_keysize = def->max_keysize;

View File

@ -1,60 +0,0 @@
From 7de4c2bd196f111e39cc60f6197654aff23ba2b4 Mon Sep 17 00:00:00 2001
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Date: Fri, 20 Dec 2019 16:02:14 -0300
Subject: [PATCH 03/11] crypto: qce - fix xts-aes-qce key sizes
XTS-mode uses two keys, so the keysizes should be doubled in
skcipher_def, and halved when checking if it is AES-128/192/256.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/qce/skcipher.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -154,12 +154,13 @@ static int qce_skcipher_setkey(struct cr
{
struct crypto_tfm *tfm = crypto_skcipher_tfm(ablk);
struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ unsigned long flags = to_cipher_tmpl(ablk)->alg_flags;
int ret;
if (!key || !keylen)
return -EINVAL;
- switch (keylen) {
+ switch (IS_XTS(flags) ? keylen >> 1 : keylen) {
case AES_KEYSIZE_128:
case AES_KEYSIZE_256:
break;
@@ -213,13 +214,15 @@ static int qce_skcipher_crypt(struct skc
struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
struct qce_alg_template *tmpl = to_cipher_tmpl(tfm);
+ int keylen;
int ret;
rctx->flags = tmpl->alg_flags;
rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
+ keylen = IS_XTS(rctx->flags) ? ctx->enc_keylen >> 1 : ctx->enc_keylen;
- if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 &&
- ctx->enc_keylen != AES_KEYSIZE_256) {
+ if (IS_AES(rctx->flags) && keylen != AES_KEYSIZE_128 &&
+ keylen != AES_KEYSIZE_256) {
SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
skcipher_request_set_sync_tfm(subreq, ctx->fallback);
@@ -311,8 +314,8 @@ static const struct qce_skcipher_def skc
.drv_name = "xts-aes-qce",
.blocksize = AES_BLOCK_SIZE,
.ivsize = AES_BLOCK_SIZE,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
},
{
.flags = QCE_ALG_DES | QCE_MODE_ECB,

View File

@ -1,85 +0,0 @@
From 3ee50c896d712dc2fc8f34c2cd1918d035e74045 Mon Sep 17 00:00:00 2001
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Date: Fri, 20 Dec 2019 16:02:15 -0300
Subject: [PATCH 04/11] crypto: qce - save a sg table slot for result buf
When ctr-aes-qce is used for gcm-mode, an extra sg entry for the
authentication tag is present, causing trouble when the qce driver
prepares the dst-results sg table for dma.
It computes the number of entries needed with sg_nents_for_len, leaving
out the tag entry. Then it creates a sg table with that number plus
one, used to store a result buffer.
When copying the sg table, there's no limit to the number of entries
copied, so the extra slot is filled with the authentication tag sg.
When the driver tries to add the result sg, the list is full, and it
returns EINVAL.
By limiting the number of sg entries copied to the dest table, the slot
for the result buffer is guaranteed to be unused.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/qce/dma.c | 6 ++++--
drivers/crypto/qce/dma.h | 3 ++-
drivers/crypto/qce/skcipher.c | 4 ++--
3 files changed, 8 insertions(+), 5 deletions(-)
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -47,7 +47,8 @@ void qce_dma_release(struct qce_dma_data
}
struct scatterlist *
-qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl)
+qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl,
+ int max_ents)
{
struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
@@ -60,12 +61,13 @@ qce_sgtable_add(struct sg_table *sgt, st
if (!sg)
return ERR_PTR(-EINVAL);
- while (new_sgl && sg) {
+ while (new_sgl && sg && max_ents) {
sg_set_page(sg, sg_page(new_sgl), new_sgl->length,
new_sgl->offset);
sg_last = sg;
sg = sg_next(sg);
new_sgl = sg_next(new_sgl);
+ max_ents--;
}
return sg_last;
--- a/drivers/crypto/qce/dma.h
+++ b/drivers/crypto/qce/dma.h
@@ -42,6 +42,7 @@ int qce_dma_prep_sgs(struct qce_dma_data
void qce_dma_issue_pending(struct qce_dma_data *dma);
int qce_dma_terminate_all(struct qce_dma_data *dma);
struct scatterlist *
-qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add);
+qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add,
+ int max_ents);
#endif /* _DMA_H_ */
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -95,13 +95,13 @@ qce_skcipher_async_req_handle(struct cry
sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
- sg = qce_sgtable_add(&rctx->dst_tbl, req->dst);
+ sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, rctx->dst_nents - 1);
if (IS_ERR(sg)) {
ret = PTR_ERR(sg);
goto error_free;
}
- sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg);
+ sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg, 1);
if (IS_ERR(sg)) {
ret = PTR_ERR(sg);
goto error_free;

View File

@ -1,31 +0,0 @@
From 3e806a12d10af2581aa26c37b58439286eab9782 Mon Sep 17 00:00:00 2001
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Date: Fri, 20 Dec 2019 16:02:16 -0300
Subject: [PATCH 05/11] crypto: qce - update the skcipher IV
Update the IV after the completion of each cipher operation.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/qce/skcipher.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -21,6 +21,7 @@ static void qce_skcipher_done(void *data
struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
struct qce_device *qce = tmpl->qce;
+ struct qce_result_dump *result_buf = qce->dma.result_buf;
enum dma_data_direction dir_src, dir_dst;
u32 status;
int error;
@@ -45,6 +46,7 @@ static void qce_skcipher_done(void *data
if (error < 0)
dev_dbg(qce->dev, "skcipher operation error (%x)\n", status);
+ memcpy(rctx->iv, result_buf->encr_cntr_iv, rctx->ivsize);
qce->async_req_done(tmpl->qce, error);
}

View File

@ -1,54 +0,0 @@
From 8ceda883205db6dfedb82e39f67feae3b50c95a1 Mon Sep 17 00:00:00 2001
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Date: Fri, 20 Dec 2019 16:02:17 -0300
Subject: [PATCH 06/11] crypto: qce - initialize fallback only for AES
Adjust cra_flags to add CRYPTO_NEED_FALLBACK only for AES ciphers, where
AES-192 is not handled by the qce hardware, and don't allocate & free
the fallback skcipher for other algorithms.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/qce/skcipher.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -257,7 +257,14 @@ static int qce_skcipher_init(struct cryp
memset(ctx, 0, sizeof(*ctx));
crypto_skcipher_set_reqsize(tfm, sizeof(struct qce_cipher_reqctx));
+ return 0;
+}
+
+static int qce_skcipher_init_fallback(struct crypto_skcipher *tfm)
+{
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+ qce_skcipher_init(tfm);
ctx->fallback = crypto_alloc_sync_skcipher(crypto_tfm_alg_name(&tfm->base),
0, CRYPTO_ALG_NEED_FALLBACK);
return PTR_ERR_OR_ZERO(ctx->fallback);
@@ -387,14 +394,18 @@ static int qce_skcipher_register_one(con
alg->base.cra_priority = 300;
alg->base.cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK |
CRYPTO_ALG_KERN_DRIVER_ONLY;
alg->base.cra_ctxsize = sizeof(struct qce_cipher_ctx);
alg->base.cra_alignmask = 0;
alg->base.cra_module = THIS_MODULE;
- alg->init = qce_skcipher_init;
- alg->exit = qce_skcipher_exit;
+ if (IS_AES(def->flags)) {
+ alg->base.cra_flags |= CRYPTO_ALG_NEED_FALLBACK;
+ alg->init = qce_skcipher_init_fallback;
+ alg->exit = qce_skcipher_exit;
+ } else {
+ alg->init = qce_skcipher_init;
+ }
INIT_LIST_HEAD(&tmpl->entry);
tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_SKCIPHER;

View File

@ -1,419 +0,0 @@
From 59e056cda4beb5412e3653e6360c2eb0fa770baa Mon Sep 17 00:00:00 2001
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Date: Fri, 20 Dec 2019 16:02:18 -0300
Subject: [PATCH 07/11] crypto: qce - allow building only hashes/ciphers
Allow the user to choose whether to build support for all algorithms
(default), hashes-only, or skciphers-only.
The QCE engine does not appear to scale as well as the CPU to handle
multiple crypto requests. While the ipq40xx chips have 4-core CPUs, the
QCE handles only 2 requests in parallel.
Ipsec throughput seems to improve when disabling either family of
algorithms, sharing the load with the CPU. Enabling skciphers-only
appears to work best.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -617,6 +617,14 @@ config CRYPTO_DEV_QCE
tristate "Qualcomm crypto engine accelerator"
depends on ARCH_QCOM || COMPILE_TEST
depends on HAS_IOMEM
+ help
+ This driver supports Qualcomm crypto engine accelerator
+ hardware. To compile this driver as a module, choose M here. The
+ module will be called qcrypto.
+
+config CRYPTO_DEV_QCE_SKCIPHER
+ bool
+ depends on CRYPTO_DEV_QCE
select CRYPTO_AES
select CRYPTO_LIB_DES
select CRYPTO_ECB
@@ -624,10 +632,57 @@ config CRYPTO_DEV_QCE
select CRYPTO_XTS
select CRYPTO_CTR
select CRYPTO_BLKCIPHER
+
+config CRYPTO_DEV_QCE_SHA
+ bool
+ depends on CRYPTO_DEV_QCE
+
+choice
+ prompt "Algorithms enabled for QCE acceleration"
+ default CRYPTO_DEV_QCE_ENABLE_ALL
+ depends on CRYPTO_DEV_QCE
help
- This driver supports Qualcomm crypto engine accelerator
- hardware. To compile this driver as a module, choose M here. The
- module will be called qcrypto.
+ This option allows to choose whether to build support for all algorihtms
+ (default), hashes-only, or skciphers-only.
+
+ The QCE engine does not appear to scale as well as the CPU to handle
+ multiple crypto requests. While the ipq40xx chips have 4-core CPUs, the
+ QCE handles only 2 requests in parallel.
+
+ Ipsec throughput seems to improve when disabling either family of
+ algorithms, sharing the load with the CPU. Enabling skciphers-only
+ appears to work best.
+
+ config CRYPTO_DEV_QCE_ENABLE_ALL
+ bool "All supported algorithms"
+ select CRYPTO_DEV_QCE_SKCIPHER
+ select CRYPTO_DEV_QCE_SHA
+ help
+ Enable all supported algorithms:
+ - AES (CBC, CTR, ECB, XTS)
+ - 3DES (CBC, ECB)
+ - DES (CBC, ECB)
+ - SHA1, HMAC-SHA1
+ - SHA256, HMAC-SHA256
+
+ config CRYPTO_DEV_QCE_ENABLE_SKCIPHER
+ bool "Symmetric-key ciphers only"
+ select CRYPTO_DEV_QCE_SKCIPHER
+ help
+ Enable symmetric-key ciphers only:
+ - AES (CBC, CTR, ECB, XTS)
+ - 3DES (ECB, CBC)
+ - DES (ECB, CBC)
+
+ config CRYPTO_DEV_QCE_ENABLE_SHA
+ bool "Hash/HMAC only"
+ select CRYPTO_DEV_QCE_SHA
+ help
+ Enable hashes/HMAC algorithms only:
+ - SHA1, HMAC-SHA1
+ - SHA256, HMAC-SHA256
+
+endchoice
config CRYPTO_DEV_QCOM_RNG
tristate "Qualcomm Random Number Generator Driver"
--- a/drivers/crypto/qce/Makefile
+++ b/drivers/crypto/qce/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_CRYPTO_DEV_QCE) += qcrypto.o
qcrypto-objs := core.o \
common.o \
- dma.o \
- sha.o \
- skcipher.o
+ dma.o
+
+qcrypto-$(CONFIG_CRYPTO_DEV_QCE_SHA) += sha.o
+qcrypto-$(CONFIG_CRYPTO_DEV_QCE_SKCIPHER) += skcipher.o
--- a/drivers/crypto/qce/common.c
+++ b/drivers/crypto/qce/common.c
@@ -45,52 +45,56 @@ qce_clear_array(struct qce_device *qce,
qce_write(qce, offset + i * sizeof(u32), 0);
}
-static u32 qce_encr_cfg(unsigned long flags, u32 aes_key_size)
+static u32 qce_config_reg(struct qce_device *qce, int little)
{
- u32 cfg = 0;
+ u32 beats = (qce->burst_size >> 3) - 1;
+ u32 pipe_pair = qce->pipe_pair_id;
+ u32 config;
- if (IS_AES(flags)) {
- if (aes_key_size == AES_KEYSIZE_128)
- cfg |= ENCR_KEY_SZ_AES128 << ENCR_KEY_SZ_SHIFT;
- else if (aes_key_size == AES_KEYSIZE_256)
- cfg |= ENCR_KEY_SZ_AES256 << ENCR_KEY_SZ_SHIFT;
- }
+ config = (beats << REQ_SIZE_SHIFT) & REQ_SIZE_MASK;
+ config |= BIT(MASK_DOUT_INTR_SHIFT) | BIT(MASK_DIN_INTR_SHIFT) |
+ BIT(MASK_OP_DONE_INTR_SHIFT) | BIT(MASK_ERR_INTR_SHIFT);
+ config |= (pipe_pair << PIPE_SET_SELECT_SHIFT) & PIPE_SET_SELECT_MASK;
+ config &= ~HIGH_SPD_EN_N_SHIFT;
- if (IS_AES(flags))
- cfg |= ENCR_ALG_AES << ENCR_ALG_SHIFT;
- else if (IS_DES(flags) || IS_3DES(flags))
- cfg |= ENCR_ALG_DES << ENCR_ALG_SHIFT;
+ if (little)
+ config |= BIT(LITTLE_ENDIAN_MODE_SHIFT);
- if (IS_DES(flags))
- cfg |= ENCR_KEY_SZ_DES << ENCR_KEY_SZ_SHIFT;
+ return config;
+}
- if (IS_3DES(flags))
- cfg |= ENCR_KEY_SZ_3DES << ENCR_KEY_SZ_SHIFT;
+void qce_cpu_to_be32p_array(__be32 *dst, const u8 *src, unsigned int len)
+{
+ __be32 *d = dst;
+ const u8 *s = src;
+ unsigned int n;
- switch (flags & QCE_MODE_MASK) {
- case QCE_MODE_ECB:
- cfg |= ENCR_MODE_ECB << ENCR_MODE_SHIFT;
- break;
- case QCE_MODE_CBC:
- cfg |= ENCR_MODE_CBC << ENCR_MODE_SHIFT;
- break;
- case QCE_MODE_CTR:
- cfg |= ENCR_MODE_CTR << ENCR_MODE_SHIFT;
- break;
- case QCE_MODE_XTS:
- cfg |= ENCR_MODE_XTS << ENCR_MODE_SHIFT;
- break;
- case QCE_MODE_CCM:
- cfg |= ENCR_MODE_CCM << ENCR_MODE_SHIFT;
- cfg |= LAST_CCM_XFR << LAST_CCM_SHIFT;
- break;
- default:
- return ~0;
+ n = len / sizeof(u32);
+ for (; n > 0; n--) {
+ *d = cpu_to_be32p((const __u32 *) s);
+ s += sizeof(__u32);
+ d++;
}
+}
- return cfg;
+static void qce_setup_config(struct qce_device *qce)
+{
+ u32 config;
+
+ /* get big endianness */
+ config = qce_config_reg(qce, 0);
+
+ /* clear status */
+ qce_write(qce, REG_STATUS, 0);
+ qce_write(qce, REG_CONFIG, config);
+}
+
+static inline void qce_crypto_go(struct qce_device *qce)
+{
+ qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
}
+#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
static u32 qce_auth_cfg(unsigned long flags, u32 key_size)
{
u32 cfg = 0;
@@ -137,88 +141,6 @@ static u32 qce_auth_cfg(unsigned long fl
return cfg;
}
-static u32 qce_config_reg(struct qce_device *qce, int little)
-{
- u32 beats = (qce->burst_size >> 3) - 1;
- u32 pipe_pair = qce->pipe_pair_id;
- u32 config;
-
- config = (beats << REQ_SIZE_SHIFT) & REQ_SIZE_MASK;
- config |= BIT(MASK_DOUT_INTR_SHIFT) | BIT(MASK_DIN_INTR_SHIFT) |
- BIT(MASK_OP_DONE_INTR_SHIFT) | BIT(MASK_ERR_INTR_SHIFT);
- config |= (pipe_pair << PIPE_SET_SELECT_SHIFT) & PIPE_SET_SELECT_MASK;
- config &= ~HIGH_SPD_EN_N_SHIFT;
-
- if (little)
- config |= BIT(LITTLE_ENDIAN_MODE_SHIFT);
-
- return config;
-}
-
-void qce_cpu_to_be32p_array(__be32 *dst, const u8 *src, unsigned int len)
-{
- __be32 *d = dst;
- const u8 *s = src;
- unsigned int n;
-
- n = len / sizeof(u32);
- for (; n > 0; n--) {
- *d = cpu_to_be32p((const __u32 *) s);
- s += sizeof(__u32);
- d++;
- }
-}
-
-static void qce_xts_swapiv(__be32 *dst, const u8 *src, unsigned int ivsize)
-{
- u8 swap[QCE_AES_IV_LENGTH];
- u32 i, j;
-
- if (ivsize > QCE_AES_IV_LENGTH)
- return;
-
- memset(swap, 0, QCE_AES_IV_LENGTH);
-
- for (i = (QCE_AES_IV_LENGTH - ivsize), j = ivsize - 1;
- i < QCE_AES_IV_LENGTH; i++, j--)
- swap[i] = src[j];
-
- qce_cpu_to_be32p_array(dst, swap, QCE_AES_IV_LENGTH);
-}
-
-static void qce_xtskey(struct qce_device *qce, const u8 *enckey,
- unsigned int enckeylen, unsigned int cryptlen)
-{
- u32 xtskey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(u32)] = {0};
- unsigned int xtsklen = enckeylen / (2 * sizeof(u32));
- unsigned int xtsdusize;
-
- qce_cpu_to_be32p_array((__be32 *)xtskey, enckey + enckeylen / 2,
- enckeylen / 2);
- qce_write_array(qce, REG_ENCR_XTS_KEY0, xtskey, xtsklen);
-
- /* xts du size 512B */
- xtsdusize = min_t(u32, QCE_SECTOR_SIZE, cryptlen);
- qce_write(qce, REG_ENCR_XTS_DU_SIZE, xtsdusize);
-}
-
-static void qce_setup_config(struct qce_device *qce)
-{
- u32 config;
-
- /* get big endianness */
- config = qce_config_reg(qce, 0);
-
- /* clear status */
- qce_write(qce, REG_STATUS, 0);
- qce_write(qce, REG_CONFIG, config);
-}
-
-static inline void qce_crypto_go(struct qce_device *qce)
-{
- qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
-}
-
static int qce_setup_regs_ahash(struct crypto_async_request *async_req,
u32 totallen, u32 offset)
{
@@ -303,6 +225,87 @@ go_proc:
return 0;
}
+#endif
+
+#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
+static u32 qce_encr_cfg(unsigned long flags, u32 aes_key_size)
+{
+ u32 cfg = 0;
+
+ if (IS_AES(flags)) {
+ if (aes_key_size == AES_KEYSIZE_128)
+ cfg |= ENCR_KEY_SZ_AES128 << ENCR_KEY_SZ_SHIFT;
+ else if (aes_key_size == AES_KEYSIZE_256)
+ cfg |= ENCR_KEY_SZ_AES256 << ENCR_KEY_SZ_SHIFT;
+ }
+
+ if (IS_AES(flags))
+ cfg |= ENCR_ALG_AES << ENCR_ALG_SHIFT;
+ else if (IS_DES(flags) || IS_3DES(flags))
+ cfg |= ENCR_ALG_DES << ENCR_ALG_SHIFT;
+
+ if (IS_DES(flags))
+ cfg |= ENCR_KEY_SZ_DES << ENCR_KEY_SZ_SHIFT;
+
+ if (IS_3DES(flags))
+ cfg |= ENCR_KEY_SZ_3DES << ENCR_KEY_SZ_SHIFT;
+
+ switch (flags & QCE_MODE_MASK) {
+ case QCE_MODE_ECB:
+ cfg |= ENCR_MODE_ECB << ENCR_MODE_SHIFT;
+ break;
+ case QCE_MODE_CBC:
+ cfg |= ENCR_MODE_CBC << ENCR_MODE_SHIFT;
+ break;
+ case QCE_MODE_CTR:
+ cfg |= ENCR_MODE_CTR << ENCR_MODE_SHIFT;
+ break;
+ case QCE_MODE_XTS:
+ cfg |= ENCR_MODE_XTS << ENCR_MODE_SHIFT;
+ break;
+ case QCE_MODE_CCM:
+ cfg |= ENCR_MODE_CCM << ENCR_MODE_SHIFT;
+ cfg |= LAST_CCM_XFR << LAST_CCM_SHIFT;
+ break;
+ default:
+ return ~0;
+ }
+
+ return cfg;
+}
+
+static void qce_xts_swapiv(__be32 *dst, const u8 *src, unsigned int ivsize)
+{
+ u8 swap[QCE_AES_IV_LENGTH];
+ u32 i, j;
+
+ if (ivsize > QCE_AES_IV_LENGTH)
+ return;
+
+ memset(swap, 0, QCE_AES_IV_LENGTH);
+
+ for (i = (QCE_AES_IV_LENGTH - ivsize), j = ivsize - 1;
+ i < QCE_AES_IV_LENGTH; i++, j--)
+ swap[i] = src[j];
+
+ qce_cpu_to_be32p_array(dst, swap, QCE_AES_IV_LENGTH);
+}
+
+static void qce_xtskey(struct qce_device *qce, const u8 *enckey,
+ unsigned int enckeylen, unsigned int cryptlen)
+{
+ u32 xtskey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(u32)] = {0};
+ unsigned int xtsklen = enckeylen / (2 * sizeof(u32));
+ unsigned int xtsdusize;
+
+ qce_cpu_to_be32p_array((__be32 *)xtskey, enckey + enckeylen / 2,
+ enckeylen / 2);
+ qce_write_array(qce, REG_ENCR_XTS_KEY0, xtskey, xtsklen);
+
+ /* xts du size 512B */
+ xtsdusize = min_t(u32, QCE_SECTOR_SIZE, cryptlen);
+ qce_write(qce, REG_ENCR_XTS_DU_SIZE, xtsdusize);
+}
static int qce_setup_regs_skcipher(struct crypto_async_request *async_req,
u32 totallen, u32 offset)
@@ -384,15 +387,20 @@ static int qce_setup_regs_skcipher(struc
return 0;
}
+#endif
int qce_start(struct crypto_async_request *async_req, u32 type, u32 totallen,
u32 offset)
{
switch (type) {
+#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
case CRYPTO_ALG_TYPE_SKCIPHER:
return qce_setup_regs_skcipher(async_req, totallen, offset);
+#endif
+#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
case CRYPTO_ALG_TYPE_AHASH:
return qce_setup_regs_ahash(async_req, totallen, offset);
+#endif
default:
return -EINVAL;
}
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -22,8 +22,12 @@
#define QCE_QUEUE_LENGTH 1
static const struct qce_algo_ops *qce_ops[] = {
+#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
&skcipher_ops,
+#endif
+#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
&ahash_ops,
+#endif
};
static void qce_unregister_algs(struct qce_device *qce)

View File

@ -1,89 +0,0 @@
From d6364b8128439a8c0e381f80c38667de9f15eef8 Mon Sep 17 00:00:00 2001
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Date: Fri, 7 Feb 2020 12:02:25 -0300
Subject: [PATCH 09/11] crypto: qce - use cryptlen when adding extra sgl
The qce crypto driver appends an extra entry to the dst sgl, to maintain
private state information.
When the gcm driver sends requests to the ctr skcipher, it passes the
authentication tag after the actual crypto payload, but it must not be
touched.
Commit 1336c2221bee ("crypto: qce - save a sg table slot for result
buf") limited the destination sgl to avoid overwriting the
authentication tag but it assumed the tag would be in a separate sgl
entry.
This is not always the case, so it is better to limit the length of the
destination buffer to req->cryptlen before appending the result buf.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/qce/dma.c | 11 ++++++-----
drivers/crypto/qce/dma.h | 2 +-
drivers/crypto/qce/skcipher.c | 5 +++--
3 files changed, 10 insertions(+), 8 deletions(-)
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -48,9 +48,10 @@ void qce_dma_release(struct qce_dma_data
struct scatterlist *
qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl,
- int max_ents)
+ unsigned int max_len)
{
struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
+ unsigned int new_len;
while (sg) {
if (!sg_page(sg))
@@ -61,13 +62,13 @@ qce_sgtable_add(struct sg_table *sgt, st
if (!sg)
return ERR_PTR(-EINVAL);
- while (new_sgl && sg && max_ents) {
- sg_set_page(sg, sg_page(new_sgl), new_sgl->length,
- new_sgl->offset);
+ while (new_sgl && sg && max_len) {
+ new_len = new_sgl->length > max_len ? max_len : new_sgl->length;
+ sg_set_page(sg, sg_page(new_sgl), new_len, new_sgl->offset);
sg_last = sg;
sg = sg_next(sg);
new_sgl = sg_next(new_sgl);
- max_ents--;
+ max_len -= new_len;
}
return sg_last;
--- a/drivers/crypto/qce/dma.h
+++ b/drivers/crypto/qce/dma.h
@@ -43,6 +43,6 @@ void qce_dma_issue_pending(struct qce_dm
int qce_dma_terminate_all(struct qce_dma_data *dma);
struct scatterlist *
qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add,
- int max_ents);
+ unsigned int max_len);
#endif /* _DMA_H_ */
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -97,13 +97,14 @@ qce_skcipher_async_req_handle(struct cry
sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
- sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, rctx->dst_nents - 1);
+ sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, req->cryptlen);
if (IS_ERR(sg)) {
ret = PTR_ERR(sg);
goto error_free;
}
- sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg, 1);
+ sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg,
+ QCE_RESULT_BUF_SZ);
if (IS_ERR(sg)) {
ret = PTR_ERR(sg);
goto error_free;

View File

@ -1,113 +0,0 @@
From ce163ba0bf298f1707321ac025ef639f88e62801 Mon Sep 17 00:00:00 2001
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Date: Fri, 7 Feb 2020 12:02:26 -0300
Subject: [PATCH 10/11] crypto: qce - use AES fallback for small requests
Process small blocks using the fallback cipher, as a workaround for an
observed failure (DMA-related, apparently) when computing the GCM ghash
key. This brings a speed gain as well, since it avoids the latency of
using the hardware engine to process small blocks.
Using software for all 16-byte requests would be enough to make GCM
work, but to increase performance, a larger threshold would be better.
Measuring the performance of supported ciphers with openssl speed,
software matches hardware at around 768-1024 bytes.
Considering the 256-bit ciphers, software is 2-3 times faster than qce
at 256-bytes, 30% faster at 512, and about even at 768-bytes. With
128-bit keys, the break-even point would be around 1024-bytes.
This adds the 'aes_sw_max_len' parameter, to set the largest request
length processed by the software fallback. Its default is being set to
512 bytes, a little lower than the break-even point, to balance the cost
in CPU usage.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -684,6 +684,29 @@ choice
endchoice
+config CRYPTO_DEV_QCE_SW_MAX_LEN
+ int "Default maximum request size to use software for AES"
+ depends on CRYPTO_DEV_QCE && CRYPTO_DEV_QCE_SKCIPHER
+ default 512
+ help
+ This sets the default maximum request size to perform AES requests
+ using software instead of the crypto engine. It can be changed by
+ setting the aes_sw_max_len parameter.
+
+ Small blocks are processed faster in software than hardware.
+ Considering the 256-bit ciphers, software is 2-3 times faster than
+ qce at 256-bytes, 30% faster at 512, and about even at 768-bytes.
+ With 128-bit keys, the break-even point would be around 1024-bytes.
+
+ The default is set a little lower, to 512 bytes, to balance the
+ cost in CPU usage. The minimum recommended setting is 16-bytes
+ (1 AES block), since AES-GCM will fail if you set it lower.
+ Setting this to zero will send all requests to the hardware.
+
+ Note that 192-bit keys are not supported by the hardware and are
+ always processed by the software fallback, and all DES requests
+ are done by the hardware.
+
config CRYPTO_DEV_QCOM_RNG
tristate "Qualcomm Random Number Generator Driver"
depends on ARCH_QCOM || COMPILE_TEST
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -5,6 +5,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
#include <linux/types.h>
#include <crypto/aes.h>
#include <crypto/internal/des.h>
@@ -12,6 +13,13 @@
#include "cipher.h"
+static unsigned int aes_sw_max_len = CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN;
+module_param(aes_sw_max_len, uint, 0644);
+MODULE_PARM_DESC(aes_sw_max_len,
+ "Only use hardware for AES requests larger than this "
+ "[0=always use hardware; anything <16 breaks AES-GCM; default="
+ __stringify(CONFIG_CRYPTO_DEV_QCE_SOFT_THRESHOLD)"]");
+
static LIST_HEAD(skcipher_algs);
static void qce_skcipher_done(void *data)
@@ -166,15 +174,10 @@ static int qce_skcipher_setkey(struct cr
switch (IS_XTS(flags) ? keylen >> 1 : keylen) {
case AES_KEYSIZE_128:
case AES_KEYSIZE_256:
+ memcpy(ctx->enc_key, key, keylen);
break;
- default:
- goto fallback;
}
- ctx->enc_keylen = keylen;
- memcpy(ctx->enc_key, key, keylen);
- return 0;
-fallback:
ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
if (!ret)
ctx->enc_keylen = keylen;
@@ -224,8 +227,9 @@ static int qce_skcipher_crypt(struct skc
rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
keylen = IS_XTS(rctx->flags) ? ctx->enc_keylen >> 1 : ctx->enc_keylen;
- if (IS_AES(rctx->flags) && keylen != AES_KEYSIZE_128 &&
- keylen != AES_KEYSIZE_256) {
+ if (IS_AES(rctx->flags) &&
+ ((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) ||
+ req->cryptlen <= aes_sw_max_len)) {
SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
skcipher_request_set_sync_tfm(subreq, ctx->fallback);

View File

@ -1,59 +0,0 @@
From 7f19380b2cfd412dcef2facefb3f6c62788864d7 Mon Sep 17 00:00:00 2001
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
Date: Fri, 7 Feb 2020 12:02:27 -0300
Subject: [PATCH 11/11] crypto: qce - handle AES-XTS cases that qce fails
QCE hangs when presented with an AES-XTS request whose length is larger
than QCE_SECTOR_SIZE (512-bytes), and is not a multiple of it. Let the
fallback cipher handle them.
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/qce/common.c | 2 --
drivers/crypto/qce/common.h | 3 +++
drivers/crypto/qce/skcipher.c | 9 +++++++--
3 files changed, 10 insertions(+), 4 deletions(-)
--- a/drivers/crypto/qce/common.c
+++ b/drivers/crypto/qce/common.c
@@ -15,8 +15,6 @@
#include "regs-v5.h"
#include "sha.h"
-#define QCE_SECTOR_SIZE 512
-
static inline u32 qce_read(struct qce_device *qce, u32 offset)
{
return readl(qce->base + offset);
--- a/drivers/crypto/qce/common.h
+++ b/drivers/crypto/qce/common.h
@@ -12,6 +12,9 @@
#include <crypto/hash.h>
#include <crypto/internal/skcipher.h>
+/* xts du size */
+#define QCE_SECTOR_SIZE 512
+
/* key size in bytes */
#define QCE_SHA_HMAC_KEY_SIZE 64
#define QCE_MAX_CIPHER_KEY_SIZE AES_KEYSIZE_256
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -227,9 +227,14 @@ static int qce_skcipher_crypt(struct skc
rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
keylen = IS_XTS(rctx->flags) ? ctx->enc_keylen >> 1 : ctx->enc_keylen;
+ /* qce is hanging when AES-XTS request len > QCE_SECTOR_SIZE and
+ * is not a multiple of it; pass such requests to the fallback
+ */
if (IS_AES(rctx->flags) &&
- ((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) ||
- req->cryptlen <= aes_sw_max_len)) {
+ (((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) ||
+ req->cryptlen <= aes_sw_max_len) ||
+ (IS_XTS(rctx->flags) && req->cryptlen > QCE_SECTOR_SIZE &&
+ req->cryptlen % QCE_SECTOR_SIZE))) {
SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
skcipher_request_set_sync_tfm(subreq, ctx->fallback);

View File

@ -1,197 +0,0 @@
From 3c9d8f6c03a2cda1849ec3c84f82ec030d1f49ef Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Sun, 3 May 2020 22:18:22 +0200
Subject: [PATCH] phy: add driver for Qualcomm IPQ40xx USB PHY
Add a driver to setup the USB PHY-s on Qualcom m IPQ40xx series SoCs.
The driver sets up HS and SS phys.
Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Cc: Luka Perkov <luka.perkov@sartura.hr>
Link: https://lore.kernel.org/r/20200503201823.531757-1-robert.marko@sartura.hr
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/phy/qualcomm/Kconfig | 7 +
drivers/phy/qualcomm/Makefile | 1 +
drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c | 148 ++++++++++++++++++++
3 files changed, 156 insertions(+)
create mode 100644 drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -18,6 +18,13 @@ config PHY_QCOM_APQ8064_SATA
depends on OF
select GENERIC_PHY
+config PHY_QCOM_IPQ4019_USB
+ tristate "Qualcomm IPQ4019 USB PHY driver"
+ depends on OF && (ARCH_QCOM || COMPILE_TEST)
+ select GENERIC_PHY
+ help
+ Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s.
+
config PHY_QCOM_IPQ806X_SATA
tristate "Qualcomm IPQ806x SATA SerDes/PHY driver"
depends on ARCH_QCOM
--- a/drivers/phy/qualcomm/Makefile
+++ b/drivers/phy/qualcomm/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_ATH79_USB) += phy-ath79-usb.o
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
+obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2018 John Crispin <john@phrozen.org>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+struct ipq4019_usb_phy {
+ struct device *dev;
+ struct phy *phy;
+ void __iomem *base;
+ struct reset_control *por_rst;
+ struct reset_control *srif_rst;
+};
+
+static int ipq4019_ss_phy_power_off(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
+
+ reset_control_assert(phy->por_rst);
+ msleep(10);
+
+ return 0;
+}
+
+static int ipq4019_ss_phy_power_on(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
+
+ ipq4019_ss_phy_power_off(_phy);
+
+ reset_control_deassert(phy->por_rst);
+
+ return 0;
+}
+
+static struct phy_ops ipq4019_usb_ss_phy_ops = {
+ .power_on = ipq4019_ss_phy_power_on,
+ .power_off = ipq4019_ss_phy_power_off,
+};
+
+static int ipq4019_hs_phy_power_off(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
+
+ reset_control_assert(phy->por_rst);
+ msleep(10);
+
+ reset_control_assert(phy->srif_rst);
+ msleep(10);
+
+ return 0;
+}
+
+static int ipq4019_hs_phy_power_on(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
+
+ ipq4019_hs_phy_power_off(_phy);
+
+ reset_control_deassert(phy->srif_rst);
+ msleep(10);
+
+ reset_control_deassert(phy->por_rst);
+
+ return 0;
+}
+
+static struct phy_ops ipq4019_usb_hs_phy_ops = {
+ .power_on = ipq4019_hs_phy_power_on,
+ .power_off = ipq4019_hs_phy_power_off,
+};
+
+static const struct of_device_id ipq4019_usb_phy_of_match[] = {
+ { .compatible = "qcom,usb-hs-ipq4019-phy", .data = &ipq4019_usb_hs_phy_ops},
+ { .compatible = "qcom,usb-ss-ipq4019-phy", .data = &ipq4019_usb_ss_phy_ops},
+ { },
+};
+MODULE_DEVICE_TABLE(of, ipq4019_usb_phy_of_match);
+
+static int ipq4019_usb_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct phy_provider *phy_provider;
+ struct ipq4019_usb_phy *phy;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->dev = &pdev->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ phy->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(phy->base)) {
+ dev_err(dev, "failed to remap register memory\n");
+ return PTR_ERR(phy->base);
+ }
+
+ phy->por_rst = devm_reset_control_get(phy->dev, "por_rst");
+ if (IS_ERR(phy->por_rst)) {
+ if (PTR_ERR(phy->por_rst) != -EPROBE_DEFER)
+ dev_err(dev, "POR reset is missing\n");
+ return PTR_ERR(phy->por_rst);
+ }
+
+ phy->srif_rst = devm_reset_control_get_optional(phy->dev, "srif_rst");
+ if (IS_ERR(phy->srif_rst))
+ return PTR_ERR(phy->srif_rst);
+
+ phy->phy = devm_phy_create(dev, NULL, of_device_get_match_data(dev));
+ if (IS_ERR(phy->phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(phy->phy);
+ }
+ phy_set_drvdata(phy->phy, phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static struct platform_driver ipq4019_usb_phy_driver = {
+ .probe = ipq4019_usb_phy_probe,
+ .driver = {
+ .of_match_table = ipq4019_usb_phy_of_match,
+ .name = "ipq4019-usb-phy",
+ }
+};
+module_platform_driver(ipq4019_usb_phy_driver);
+
+MODULE_DESCRIPTION("QCOM/IPQ4019 USB phy driver");
+MODULE_AUTHOR("John Crispin <john@phrozen.org>");
+MODULE_LICENSE("GPL v2");

View File

@ -1,81 +0,0 @@
From 5b08c1d567ee8e6af94696b3e549997cbdb2bb80 Mon Sep 17 00:00:00 2001
From: Jaiganesh Narayanan <njaigane@codeaurora.org>
Date: Thu, 1 Sep 2016 10:40:38 +0530
Subject: [PATCH] pinctrl: qcom: ipq4019: add open drain support
Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
[ Brian: adapted from from the Chromium OS kernel used on IPQ4019-based
WiFi APs. ]
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
https://lore.kernel.org/linux-gpio/20200703080646.23233-1-computersforpeace@gmail.com/
drivers/pinctrl/qcom/pinctrl-ipq4019.c | 1 +
drivers/pinctrl/qcom/pinctrl-msm.c | 13 +++++++++++++
drivers/pinctrl/qcom/pinctrl-msm.h | 2 ++
3 files changed, 16 insertions(+)
--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -254,6 +254,7 @@ DECLARE_QCA_GPIO_PINS(99);
.mux_bit = 2, \
.pull_bit = 0, \
.drv_bit = 6, \
+ .od_bit = 12, \
.oe_bit = 9, \
.in_bit = 0, \
.out_bit = 1, \
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -225,6 +225,10 @@ static int msm_config_reg(struct msm_pin
*bit = g->pull_bit;
*mask = 3;
break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ *bit = g->od_bit;
+ *mask = 1;
+ break;
case PIN_CONFIG_DRIVE_STRENGTH:
*bit = g->drv_bit;
*mask = 7;
@@ -302,6 +306,12 @@ static int msm_config_group_get(struct p
if (!arg)
return -EINVAL;
break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ /* Pin is not open-drain */
+ if (!arg)
+ return -EINVAL;
+ arg = 1;
+ break;
case PIN_CONFIG_DRIVE_STRENGTH:
arg = msm_regval_to_drive(arg);
break;
@@ -374,6 +384,9 @@ static int msm_config_group_set(struct p
else
arg = MSM_PULL_UP;
break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ arg = 1;
+ break;
case PIN_CONFIG_DRIVE_STRENGTH:
/* Check for invalid values */
if (arg > 16 || arg < 2 || (arg % 2) != 0)
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -38,6 +38,7 @@ struct msm_function {
* @mux_bit: Offset in @ctl_reg for the pinmux function selection.
* @pull_bit: Offset in @ctl_reg for the bias configuration.
* @drv_bit: Offset in @ctl_reg for the drive strength configuration.
+ * @od_bit: Offset in @ctl_reg for controlling open drain.
* @oe_bit: Offset in @ctl_reg for controlling output enable.
* @in_bit: Offset in @io_reg for the input bit value.
* @out_bit: Offset in @io_reg for the output bit value.
@@ -75,6 +76,7 @@ struct msm_pingroup {
unsigned pull_bit:5;
unsigned drv_bit:5;
+ unsigned od_bit:5;
unsigned oe_bit:5;
unsigned in_bit:5;
unsigned out_bit:5;

View File

@ -1,29 +0,0 @@
From 707745e8d4e75b638b990d67950ab292b3b8ea2a Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Mon, 16 Dec 2019 01:36:46 +0100
Subject: [PATCH] mtd: spi-nor: Add support for mx25r3235f
Add MTD support for the Macronix MX25R3235F SPI NOR chip from Macronix.
The chip has 4MB of total capacity, divided into a total of 64 sectors,
each 64KB sized. The chip also supports 4KB large sectors.
Additionally, it supports dual and quad read modes.
Functionality was verified on an HPE/Aruba AP-303 board.
Signed-off-by: David Bauer <mail@david-bauer.net>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
drivers/mtd/spi-nor/spi-nor.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -2354,6 +2354,8 @@ static const struct flash_info spi_nor_i
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+ { "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64,
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512,

View File

@ -1,165 +0,0 @@
From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 12 Aug 2014 20:49:27 +0200
Subject: [PATCH 24/53] GPIO: add named gpio exports
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/gpio/gpiolib-of.c | 68 +++++++++++++++++++++++++++++++++++++++++
drivers/gpio/gpiolib-sysfs.c | 10 +++++-
include/asm-generic/gpio.h | 6 ++++
include/linux/gpio/consumer.h | 8 +++++
4 files changed, 91 insertions(+), 1 deletion(-)
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -19,6 +19,8 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
#include <linux/gpio/machine.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
#include "gpiolib.h"
#include "gpiolib-of.h"
@@ -915,3 +917,68 @@ void of_gpiochip_remove(struct gpio_chip
{
of_node_put(chip->of_node);
}
+
+static struct of_device_id gpio_export_ids[] = {
+ { .compatible = "gpio-export" },
+ { /* sentinel */ }
+};
+
+static int of_gpio_export_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *cnp;
+ u32 val;
+ int nb = 0;
+
+ for_each_child_of_node(np, cnp) {
+ const char *name = NULL;
+ int gpio;
+ bool dmc;
+ int max_gpio = 1;
+ int i;
+
+ of_property_read_string(cnp, "gpio-export,name", &name);
+
+ if (!name)
+ max_gpio = of_gpio_count(cnp);
+
+ for (i = 0; i < max_gpio; i++) {
+ unsigned flags = 0;
+ enum of_gpio_flags of_flags;
+
+ gpio = of_get_gpio_flags(cnp, i, &of_flags);
+ if (!gpio_is_valid(gpio))
+ return gpio;
+
+ if (of_flags == OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ if (!of_property_read_u32(cnp, "gpio-export,output", &val))
+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ else
+ flags |= GPIOF_IN;
+
+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
+ continue;
+
+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
+ gpio_export_with_name(gpio, dmc, name);
+ nb++;
+ }
+ }
+
+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
+
+ return 0;
+}
+
+static struct platform_driver gpio_export_driver = {
+ .driver = {
+ .name = "gpio-export",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpio_export_ids),
+ },
+ .probe = of_gpio_export_probe,
+};
+
+module_platform_driver(gpio_export_driver);
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -571,7 +571,7 @@ static struct class gpio_class = {
*
* Returns zero on success, else an error.
*/
-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
{
struct gpio_chip *chip;
struct gpio_device *gdev;
@@ -633,6 +633,8 @@ int gpiod_export(struct gpio_desc *desc,
offset = gpio_chip_hwgpio(desc);
if (chip->names && chip->names[offset])
ioname = chip->names[offset];
+ if (name)
+ ioname = name;
dev = device_create_with_groups(&gpio_class, &gdev->dev,
MKDEV(0, 0), data, gpio_groups,
@@ -654,6 +656,12 @@ err_unlock:
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
+EXPORT_SYMBOL_GPL(__gpiod_export);
+
+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+{
+ return __gpiod_export(desc, direction_may_change, NULL);
+}
EXPORT_SYMBOL_GPL(gpiod_export);
static int match_export(struct device *dev, const void *desc)
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -127,6 +127,12 @@ static inline int gpio_export(unsigned g
return gpiod_export(gpio_to_desc(gpio), direction_may_change);
}
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
+{
+ return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
+}
+
static inline int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
{
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -668,6 +668,7 @@ static inline void devm_acpi_dev_remove_
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
+int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
@@ -675,6 +676,13 @@ void gpiod_unexport(struct gpio_desc *de
#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
+static inline int _gpiod_export(struct gpio_desc *desc,
+ bool direction_may_change,
+ const char *name)
+{
+ return -ENOSYS;
+}
+
static inline int gpiod_export(struct gpio_desc *desc,
bool direction_may_change)
{

View File

@ -1,32 +0,0 @@
From 77d9b11ae7269dcf376c3b9493209f712524e986 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Wed, 22 Jan 2020 12:56:35 +0100
Subject: [PATCH] arm: dts: IPQ4019: add SDHCI VQMMC LDO node
Since we now have driver for the SDHCI VQMMC LDO needed
for I/0 voltage levels lets introduce the necessary node for it.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -209,6 +209,16 @@
interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
};
+ vqmmc: regulator@1948000 {
+ compatible = "qcom,vqmmc-ipq4019-regulator";
+ reg = <0x01948000 0x4>;
+ regulator-name = "vqmmc";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ status = "disabled";
+ };
+
sdhci: sdhci@7824900 {
compatible = "qcom,sdhci-msm-v4";
reg = <0x7824900 0x11c>, <0x7824000 0x800>;

View File

@ -1,97 +0,0 @@
From 193856b5fe11c50a0b6ff22457dd674c1a45fec6 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Wed, 9 Sep 2020 18:31:03 +0200
Subject: [PATCH] ARM: dts: qcom: ipq4019: add USB devicetree nodes
Since we now have driver for the USB PHY, and USB controller is already supported by the DWC3 driver lets add the necessary nodes to DTSI.
Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Cc: Luka Perkov <luka.perkov@sartura.hr>
Reviewed-by: Vinod Koul <vkoul@kernel.org>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 74 +++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -615,5 +615,79 @@
reg = <4>;
};
};
+
+ usb3_ss_phy: ssphy@9a000 {
+ compatible = "qcom,usb-ss-ipq4019-phy";
+ #phy-cells = <0>;
+ reg = <0x9a000 0x800>;
+ reg-names = "phy_base";
+ resets = <&gcc USB3_UNIPHY_PHY_ARES>;
+ reset-names = "por_rst";
+ status = "disabled";
+ };
+
+ usb3_hs_phy: hsphy@a6000 {
+ compatible = "qcom,usb-hs-ipq4019-phy";
+ #phy-cells = <0>;
+ reg = <0xa6000 0x40>;
+ reg-names = "phy_base";
+ resets = <&gcc USB3_HSPHY_POR_ARES>, <&gcc USB3_HSPHY_S_ARES>;
+ reset-names = "por_rst", "srif_rst";
+ status = "disabled";
+ };
+
+ usb3: usb3@8af8800 {
+ compatible = "qcom,dwc3";
+ reg = <0x8af8800 0x100>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&gcc GCC_USB3_MASTER_CLK>,
+ <&gcc GCC_USB3_SLEEP_CLK>,
+ <&gcc GCC_USB3_MOCK_UTMI_CLK>;
+ clock-names = "master", "sleep", "mock_utmi";
+ ranges;
+ status = "disabled";
+
+ dwc3@8a00000 {
+ compatible = "snps,dwc3";
+ reg = <0x8a00000 0xf8000>;
+ interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb3_hs_phy>, <&usb3_ss_phy>;
+ phy-names = "usb2-phy", "usb3-phy";
+ dr_mode = "host";
+ };
+ };
+
+ usb2_hs_phy: hsphy@a8000 {
+ compatible = "qcom,usb-hs-ipq4019-phy";
+ #phy-cells = <0>;
+ reg = <0xa8000 0x40>;
+ reg-names = "phy_base";
+ resets = <&gcc USB2_HSPHY_POR_ARES>, <&gcc USB2_HSPHY_S_ARES>;
+ reset-names = "por_rst", "srif_rst";
+ status = "disabled";
+ };
+
+ usb2: usb2@60f8800 {
+ compatible = "qcom,dwc3";
+ reg = <0x60f8800 0x100>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&gcc GCC_USB2_MASTER_CLK>,
+ <&gcc GCC_USB2_SLEEP_CLK>,
+ <&gcc GCC_USB2_MOCK_UTMI_CLK>;
+ clock-names = "master", "sleep", "mock_utmi";
+ ranges;
+ status = "disabled";
+
+ dwc3@6000000 {
+ compatible = "snps,dwc3";
+ reg = <0x6000000 0xf8000>;
+ interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb2_hs_phy>;
+ phy-names = "usb2-phy";
+ dr_mode = "host";
+ };
+ };
};
};

View File

@ -1,42 +0,0 @@
From caa3ee6b094ee18021943504c938919fcac325ec Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Wed, 9 Sep 2020 20:40:33 +0200
Subject: [PATCH] arm: dts: qcom: ipq4019: add more labels
Lets add labels to more commonly used nodes for easier modification in board DTS files.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Cc: Luka Perkov <luka.perkov@sartura.hr>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -190,7 +190,7 @@
reg = <0x1800000 0x60000>;
};
- rng@22000 {
+ prng: rng@22000 {
compatible = "qcom,prng";
reg = <0x22000 0x140>;
clocks = <&gcc GCC_PRNG_AHB_CLK>;
@@ -310,7 +310,7 @@
status = "disabled";
};
- crypto@8e3a000 {
+ crypto: crypto@8e3a000 {
compatible = "qcom,crypto-v5.1";
reg = <0x08e3a000 0x6000>;
clocks = <&gcc GCC_CRYPTO_AHB_CLK>,
@@ -396,7 +396,7 @@
dma-names = "rx", "tx";
};
- watchdog@b017000 {
+ watchdog: watchdog@b017000 {
compatible = "qcom,kpss-wdt", "qcom,kpss-wdt-ipq4019";
reg = <0xb017000 0x40>;
clocks = <&sleep_clk>;

View File

@ -1,115 +0,0 @@
From f2b87dc1028b710ec8ce25808b9d21f92b376184 Mon Sep 17 00:00:00 2001
From: Christian Lamparter <chunkeey@googlemail.com>
Date: Sun, 11 Mar 2018 14:41:31 +0100
Subject: [PATCH 2/2] clk: fix apss cpu overclocking
There's an interaction issue between the clk changes:"
clk: qcom: ipq4019: Add the apss cpu pll divider clock node
clk: qcom: ipq4019: remove fixed clocks and add pll clocks
" and the cpufreq-dt.
cpufreq-dt is now spamming the kernel-log with the following:
[ 1099.190658] cpu cpu0: dev_pm_opp_set_rate: failed to find current OPP
for freq 761142857 (-34)
This only happens on certain devices like the Compex WPJ428
and AVM FritzBox!4040. However, other devices like the Asus
RT-AC58U and Meraki MR33 work just fine.
The issue stem from the fact that all higher CPU-Clocks
are achieved by switching the clock-parent to the P_DDRPLLAPSS
(ddrpllapss). Which is set by Qualcomm's proprietary bootcode
as part of the DDR calibration.
For example, the FB4040 uses 256 MiB Nanya NT5CC128M16IP clocked
at round 533 MHz (ddrpllsdcc = 190285714 Hz).
whereas the 128 MiB Nanya NT5CC64M16GP-DI in the ASUS RT-AC58U is
clocked at a slightly higher 537 MHz ( ddrpllsdcc = 192000000 Hz).
This patch attempts to fix the issue by modifying
clk_cpu_div_round_rate(), clk_cpu_div_set_rate(), clk_cpu_div_recalc_rate()
to use a new qcom_find_freq_close() function, which returns the closest
matching frequency, instead of the next higher. This way, the SoC in
the FB4040 (with its max clock speed of 710.4 MHz) will no longer
try to overclock to 761 MHz.
Fixes: d83dcacea18 ("clk: qcom: ipq4019: Add the apss cpu pll divider clock node")
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: John Crispin <john@phrozen.org>
---
drivers/clk/qcom/gcc-ipq4019.c | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)
--- a/drivers/clk/qcom/gcc-ipq4019.c
+++ b/drivers/clk/qcom/gcc-ipq4019.c
@@ -1243,6 +1243,29 @@ static const struct clk_fepll_vco gcc_fe
.reg = 0x2f020,
};
+
+const struct freq_tbl *qcom_find_freq_close(const struct freq_tbl *f,
+ unsigned long rate)
+{
+ const struct freq_tbl *last = NULL;
+
+ for ( ; f->freq; f++) {
+ if (rate == f->freq)
+ return f;
+
+ if (f->freq > rate) {
+ if (!last ||
+ (f->freq - rate) < (rate - last->freq))
+ return f;
+ else
+ return last;
+ }
+ last = f;
+ }
+
+ return last;
+}
+
/*
* Round rate function for APSS CPU PLL Clock divider.
* It looks up the frequency table and returns the next higher frequency
@@ -1255,7 +1278,7 @@ static long clk_cpu_div_round_rate(struc
struct clk_hw *p_hw;
const struct freq_tbl *f;
- f = qcom_find_freq(pll->freq_tbl, rate);
+ f = qcom_find_freq_close(pll->freq_tbl, rate);
if (!f)
return -EINVAL;
@@ -1278,7 +1301,7 @@ static int clk_cpu_div_set_rate(struct c
u32 mask;
int ret;
- f = qcom_find_freq(pll->freq_tbl, rate);
+ f = qcom_find_freq_close(pll->freq_tbl, rate);
if (!f)
return -EINVAL;
@@ -1305,6 +1328,7 @@ static unsigned long
clk_cpu_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
+ const struct freq_tbl *f;
struct clk_fepll *pll = to_clk_fepll(hw);
u32 cdiv, pre_div;
u64 rate;
@@ -1325,7 +1349,11 @@ clk_cpu_div_recalc_rate(struct clk_hw *h
rate = clk_fepll_vco_calc_rate(pll, parent_rate) * 2;
do_div(rate, pre_div);
- return rate;
+ f = qcom_find_freq_close(pll->freq_tbl, rate);
+ if (!f)
+ return rate;
+
+ return f->freq;
};
static const struct clk_ops clk_regmap_cpu_div_ops = {

View File

@ -1,29 +0,0 @@
From 4d44bb1031a68d7d5b604d3b340c059f41ca62af Mon Sep 17 00:00:00 2001
From: dissent1 <be.dissent@gmail.com>
Date: Mon, 6 May 2019 20:55:16 +0300
Subject: [PATCH] ipq40xx: fix sleep clock
It seems like sleep_clk was copied from ipq806x.
Fix ipq40xx sleep_clk to the value QSDK defines.
Also rename the sleep clock node like the GCC driver names it.
Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -140,9 +140,9 @@
};
clocks {
- sleep_clk: sleep_clk {
+ sleep_clk: gcc_sleep_clk_src {
compatible = "fixed-clock";
- clock-frequency = <32768>;
+ clock-frequency = <32000>;
#clock-cells = <0>;
};

View File

@ -1,52 +0,0 @@
From 480c1f7648fc586db12d6003c717c23667a4fcf0 Mon Sep 17 00:00:00 2001
From: Ram Chandra Jangir <rjangir@codeaurora.org>
Date: Tue, 28 Mar 2017 22:35:33 +0530
Subject: [PATCH] clk: qcom: ipq4019: add ess reset
Added the ESS reset in IPQ4019 GCC.
Signed-off-by: Ram Chandra Jangir <rjangir@codeaurora.org>
---
drivers/clk/qcom/gcc-ipq4019.c | 11 +++++++++++
include/dt-bindings/clock/qcom,gcc-ipq4019.h | 11 +++++++++++
2 files changed, 22 insertions(+)
--- a/drivers/clk/qcom/gcc-ipq4019.c
+++ b/drivers/clk/qcom/gcc-ipq4019.c
@@ -1736,6 +1736,17 @@ static const struct qcom_reset_map gcc_i
[GCC_TCSR_BCR] = {0x22000, 0},
[GCC_MPM_BCR] = {0x24000, 0},
[GCC_SPDM_BCR] = {0x25000, 0},
+ [ESS_MAC1_ARES] = {0x1200C, 0},
+ [ESS_MAC2_ARES] = {0x1200C, 1},
+ [ESS_MAC3_ARES] = {0x1200C, 2},
+ [ESS_MAC4_ARES] = {0x1200C, 3},
+ [ESS_MAC5_ARES] = {0x1200C, 4},
+ [ESS_PSGMII_ARES] = {0x1200C, 5},
+ [ESS_MAC1_CLK_DIS] = {0x1200C, 8},
+ [ESS_MAC2_CLK_DIS] = {0x1200C, 9},
+ [ESS_MAC3_CLK_DIS] = {0x1200C, 10},
+ [ESS_MAC4_CLK_DIS] = {0x1200C, 11},
+ [ESS_MAC5_CLK_DIS] = {0x1200C, 12},
};
static const struct regmap_config gcc_ipq4019_regmap_config = {
--- a/include/dt-bindings/clock/qcom,gcc-ipq4019.h
+++ b/include/dt-bindings/clock/qcom,gcc-ipq4019.h
@@ -165,5 +165,16 @@
#define GCC_QDSS_BCR 69
#define GCC_MPM_BCR 70
#define GCC_SPDM_BCR 71
+#define ESS_MAC1_ARES 72
+#define ESS_MAC2_ARES 73
+#define ESS_MAC3_ARES 74
+#define ESS_MAC4_ARES 75
+#define ESS_MAC5_ARES 76
+#define ESS_PSGMII_ARES 77
+#define ESS_MAC1_CLK_DIS 78
+#define ESS_MAC2_CLK_DIS 79
+#define ESS_MAC3_CLK_DIS 80
+#define ESS_MAC4_CLK_DIS 81
+#define ESS_MAC5_CLK_DIS 82
#endif

View File

@ -1,48 +0,0 @@
From 0843a61d6913bdac8889eb048ed89f7903059787 Mon Sep 17 00:00:00 2001
From: Robert Marko <robimarko@gmail.com>
Date: Fri, 30 Oct 2020 13:36:31 +0100
Subject: [PATCH] arm: compressed: add appended DTB section
This adds a appended_dtb section to the ARM decompressor
linker script.
This allows using the existing ARM zImage appended DTB support for
appending a DTB to the raw ELF kernel.
Its size is set to 1MB max to match the zImage appended DTB size limit.
To use it to pass the DTB to the kernel, objcopy is used:
objcopy --set-section-flags=.appended_dtb=alloc,contents \
--update-section=.appended_dtb=<target>.dtb vmlinux
This is based off the following patch:
https://github.com/openwrt/openwrt/commit/c063e27e02a9dcac0e7f5877fb154e58fa3e1a69
Signed-off-by: Robert Marko <robimarko@gmail.com>
---
arch/arm/boot/compressed/vmlinux.lds.S | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -93,6 +93,13 @@ SECTIONS
_edata = .;
+ .appended_dtb : {
+ /* leave space for appended DTB */
+ . += 0x100000;
+ }
+
+ _edata_dtb = .;
+
/*
* The image_end section appears after any additional loadable sections
* that the linker may decide to insert in the binary image. Having
@@ -132,4 +139,4 @@ SECTIONS
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
-ASSERT(_edata_real == _edata, "error: zImage file size is incorrect");
+ASSERT(_edata_real == _edata_dtb, "error: zImage file size is incorrect");

View File

@ -1,66 +0,0 @@
From 11d6a6128a5a07c429941afc202b6e62a19771be Mon Sep 17 00:00:00 2001
From: John Thomson <git@johnthomson.fastmail.com.au>
Date: Fri, 23 Oct 2020 19:42:36 +1000
Subject: [PATCH 2/2] arm: compressed: set ipq40xx watchdog to allow boot
For IPQ40XX systems where the SoC watchdog is activated before linux,
the watchdog timer may be too small for linux to finish uncompress,
boot, and watchdog management start.
If the watchdog is enabled, set the timeout for it to 30 seconds.
The functionality and offsets were copied from:
drivers/watchdog/qcom-wdt.c qcom_wdt_set_timeout & qcom_wdt_start
The watchdog memory address was taken from:
arch/arm/boot/dts/qcom-ipq4019.dtsi
This was required on Mikrotik IPQ40XX consumer hardware using Mikrotik's
RouterBoot bootloader.
Signed-off-by: John Thomson <git@johnthomson.fastmail.com.au>
---
arch/arm/boot/compressed/head.S | 35 +++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -599,6 +599,41 @@ not_relocated: mov r0, #0
bic r4, r4, #1
blne cache_on
+/* Set the Qualcom IPQ40xx watchdog timeout to 30 seconds
+ * if it is enabled, so that there is time for kernel
+ * to decompress, boot, and take over the watchdog.
+ * data and functionality from drivers/watchdog/qcom-wdt.c
+ * address from arch/arm/boot/dts/qcom-ipq4019.dtsi
+ */
+#ifdef CONFIG_ARCH_IPQ40XX
+watchdog_set:
+ /* offsets:
+ * 0x04 reset (=1 resets countdown)
+ * 0x08 enable (=0 disables)
+ * 0x0c status (=1 when SoC was reset by watchdog)
+ * 0x10 bark (=timeout warning in ticks)
+ * 0x14 bite (=timeout reset in ticks)
+ * clock rate is 1<<15 hertz
+ */
+ .equ watchdog, 0x0b017000 @Store watchdog base address
+ movw r0, #:lower16:watchdog
+ movt r0, #:upper16:watchdog
+ ldr r1, [r0, #0x08] @Get enabled?
+ cmp r1, #1 @If not enabled, do not change
+ bne watchdog_finished
+ mov r1, #0
+ str r1, [r0, #0x08] @Disable the watchdog
+ mov r1, #1
+ str r1, [r0, #0x04] @Pet the watchdog
+ mov r1, #30 @30 seconds timeout
+ lsl r1, r1, #15 @converted to ticks
+ str r1, [r0, #0x10] @Set the bark timeout
+ str r1, [r0, #0x14] @Set the bite timeout
+ mov r1, #1
+ str r1, [r0, #0x08] @Enable the watchdog
+watchdog_finished:
+#endif /* CONFIG_ARCH_IPQ40XX */
+
/*
* The C runtime environment should now be setup sufficiently.
* Set up some pointers, and start decompressing.

View File

@ -1,25 +0,0 @@
From 0e28623a11f3916c1fe5b7e789c7ab8ca932a929 Mon Sep 17 00:00:00 2001
From: Robert Marko <robimarko@gmail.com>
Date: Wed, 22 Jan 2020 13:02:13 +0100
Subject: [PATCH] mmc: sdhci: sdhci-msm: use sdhci_set_clock instead of
sdhci_msm_set_clock
When using sdhci_msm_set_clock clock setting will fail, so lets
use the generic sdhci_set_clock.
Signed-off-by: Robert Marko <robimarko@gmail.com>
---
drivers/mmc/host/sdhci-msm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1763,7 +1763,7 @@ MODULE_DEVICE_TABLE(of, sdhci_msm_dt_mat
static const struct sdhci_ops sdhci_msm_ops = {
.reset = sdhci_reset,
- .set_clock = sdhci_msm_set_clock,
+ .set_clock = sdhci_set_clock,
.get_min_clock = sdhci_msm_get_min_clock,
.get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width,

View File

@ -1,46 +0,0 @@
From 9deeec35dd3b628b95624e41d4e04acf728991ba Mon Sep 17 00:00:00 2001
From: Christian Lamparter <chunkeey@gmail.com>
Date: Sun, 20 Nov 2016 02:20:54 +0100
Subject: [PATCH] dts: ipq4019: add PHY/switch nodes
This patch adds both the "qcom,ess-switch" and "qcom,ess-psgmii"
nodes which are needed for the ar40xx.c driver to initialize the
switch.
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -616,6 +616,29 @@
};
};
+ ess-switch@c000000 {
+ compatible = "qcom,ess-switch";
+ reg = <0xc000000 0x80000>;
+ switch_access_mode = "local bus";
+ resets = <&gcc ESS_RESET>;
+ reset-names = "ess_rst";
+ clocks = <&gcc GCC_ESS_CLK>;
+ clock-names = "ess_clk";
+ switch_cpu_bmp = <0x1>;
+ switch_lan_bmp = <0x1e>;
+ switch_wan_bmp = <0x20>;
+ switch_mac_mode = <0>; /* PORT_WRAPPER_PSGMII */
+ switch_initvlas = <0x7c 0x54>;
+ status = "disabled";
+ };
+
+ ess-psgmii@98000 {
+ compatible = "qcom,ess-psgmii";
+ reg = <0x98000 0x800>;
+ psgmii_access_mode = "local bus";
+ status = "disabled";
+ };
+
usb3_ss_phy: ssphy@9a000 {
compatible = "qcom,usb-ss-ipq4019-phy";
#phy-cells = <0>;

View File

@ -1,53 +0,0 @@
From 7c129254adb1093d10a62ed7bf7b956fcc6ffe34 Mon Sep 17 00:00:00 2001
From: Rakesh Nair <ranair@codeaurora.org>
Date: Wed, 20 Jul 2016 15:02:01 +0530
Subject: [PATCH] net: IPQ4019 needs rfs/vlan_tag callbacks in
netdev_ops
Add callback support to get default vlan tag and register
receive flow steering filter.
Used by IPQ4019 ess-edma driver.
BUG=chrome-os-partner:33096
TEST=none
Change-Id: I266070e4a0fbe4a0d9966fe79a71e50ec4f26c75
Signed-off-by: Rakesh Nair <ranair@codeaurora.org>
Reviewed-on: https://chromium-review.googlesource.com/362203
Commit-Ready: Grant Grundler <grundler@chromium.org>
Tested-by: Grant Grundler <grundler@chromium.org>
Reviewed-by: Grant Grundler <grundler@chromium.org>
---
include/linux/netdevice.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -767,6 +767,16 @@ struct xps_map {
#define XPS_MIN_MAP_ALLOC ((L1_CACHE_ALIGN(offsetof(struct xps_map, queues[1])) \
- sizeof(struct xps_map)) / sizeof(u16))
+#ifdef CONFIG_RFS_ACCEL
+typedef int (*set_rfs_filter_callback_t)(struct net_device *dev,
+ __be32 src,
+ __be32 dst,
+ __be16 sport,
+ __be16 dport,
+ u8 proto,
+ u16 rxq_index,
+ u32 action);
+#endif
/*
* This structure holds all XPS maps for device. Maps are indexed by CPU.
*/
@@ -1370,6 +1380,9 @@ struct net_device_ops {
const struct sk_buff *skb,
u16 rxq_index,
u32 flow_id);
+ int (*ndo_register_rfs_filter)(struct net_device *dev,
+ set_rfs_filter_callback_t set_filter);
+ int (*ndo_get_default_vlan_tag)(struct net_device *net);
#endif
int (*ndo_add_slave)(struct net_device *dev,
struct net_device *slave_dev,

View File

@ -1,26 +0,0 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -580,6 +580,13 @@ config XILINX_GMII2RGMII
the Reduced Gigabit Media Independent Interface(RGMII) between
Ethernet physical media devices and the Gigabit Ethernet controller.
+config AR40XX_PHY
+ tristate "Driver for Qualcomm Atheros IPQ40XX switches"
+ depends on HAS_IOMEM && OF && OF_MDIO
+ select SWCONFIG
+ help
+ This is the driver for Qualcomm Atheros IPQ40XX ESS switches.
+
endif # PHYLIB
config MICREL_KS8995MA
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -68,6 +68,7 @@ ifdef CONFIG_HWMON
aquantia-objs += aquantia_hwmon.o
endif
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
+obj-$(CONFIG_AR40XX_PHY) += ar40xx.o
obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
obj-$(CONFIG_AT803X_PHY) += at803x.o
obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o

View File

@ -1,61 +0,0 @@
From c66863c1ba8995b61e6d727d78a241c734f5bb57 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Thu, 1 Oct 2020 15:05:35 +0200
Subject: [PATCH] dt-bindings: net: add QCA807x PHY
Add DT bindings for Qualcomm QCA807x PHY series.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
include/dt-bindings/net/qcom-qca807x.h | 45 ++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 include/dt-bindings/net/qcom-qca807x.h
--- /dev/null
+++ b/include/dt-bindings/net/qcom-qca807x.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Device Tree constants for the Qualcomm QCA807X PHYs
+ */
+
+#ifndef _DT_BINDINGS_QCOM_QCA807X_H
+#define _DT_BINDINGS_QCOM_QCA807X_H
+
+#define PSGMII_QSGMII_TX_DRIVER_140MV 0
+#define PSGMII_QSGMII_TX_DRIVER_160MV 1
+#define PSGMII_QSGMII_TX_DRIVER_180MV 2
+#define PSGMII_QSGMII_TX_DRIVER_200MV 3
+#define PSGMII_QSGMII_TX_DRIVER_220MV 4
+#define PSGMII_QSGMII_TX_DRIVER_240MV 5
+#define PSGMII_QSGMII_TX_DRIVER_260MV 6
+#define PSGMII_QSGMII_TX_DRIVER_280MV 7
+#define PSGMII_QSGMII_TX_DRIVER_300MV 8
+#define PSGMII_QSGMII_TX_DRIVER_320MV 9
+#define PSGMII_QSGMII_TX_DRIVER_400MV 10
+#define PSGMII_QSGMII_TX_DRIVER_500MV 11
+/* Default value */
+#define PSGMII_QSGMII_TX_DRIVER_600MV 12
+
+/* Full amplitude, full bias current */
+#define QCA807X_CONTROL_DAC_FULL_VOLT_BIAS 0
+/* Amplitude follow DSP (amplitude is adjusted based on cable length), half bias current */
+#define QCA807X_CONTROL_DAC_DSP_VOLT_HALF_BIAS 1
+/* Full amplitude, bias current follow DSP (bias current is adjusted based on cable length) */
+#define QCA807X_CONTROL_DAC_FULL_VOLT_DSP_BIAS 2
+/* Both amplitude and bias current follow DSP */
+#define QCA807X_CONTROL_DAC_DSP_VOLT_BIAS 3
+/* Full amplitude, half bias current */
+#define QCA807X_CONTROL_DAC_FULL_VOLT_HALF_BIAS 4
+/* Amplitude follow DSP setting; 1/4 bias current when cable<10m,
+ * otherwise half bias current
+ */
+#define QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS 5
+/* Full amplitude; same bias current setting with “010” and “011”,
+ * but half more bias is reduced when cable <10m
+ */
+#define QCA807X_CONTROL_DAC_FULL_VOLT_HALF_BIAS_SHORT 6
+/* Amplitude follow DSP; same bias current setting with “110”, default value */
+#define QCA807X_CONTROL_DAC_DSP_VOLT_HALF_BIAS_SHORT 7
+
+#endif

View File

@ -1,50 +0,0 @@
From f825cdc8bfde7616a14e2163f16303a8973031d2 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Wed, 7 Oct 2020 17:38:48 +0200
Subject: [PATCH] net: phy: Add Qualcom QCA807x driver
This adds driver for the Qualcomm QCA8072 and QCA8075 PHY-s.
They are 2 or 5 port IEEE 802.3 clause 22 compliant 10BASE-Te, 100BASE-TX and 1000BASE-T PHY-s.
They feature 2 SerDes, one for PSGMII or QSGMII connection with MAC, while second one is SGMII for connection to MAC or fiber.
Both models have a combo port that supports 1000BASE-X and 100BASE-FX fiber.
Each PHY inside of QCA807x series has 4 digitally controlled output only pins that natively drive LED-s.
But some vendors used these to driver generic LED-s controlled by userspace,
so lets enable registering each PHY as GPIO controller and add driver for it.
These are commonly used in Qualcomm IPQ40xx, IPQ60xx and IPQ807x boards.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/net/phy/Kconfig | 6 ++++++
drivers/net/phy/Makefile | 1 +
2 files changed, 7 insertions(+)
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -533,6 +533,12 @@ config NXP_TJA11XX_PHY
---help---
Currently supports the NXP TJA1100 and TJA1101 PHY.
+config QCA807X_PHY
+ tristate "Qualcomm QCA807X PHYs"
+ depends on OF_MDIO
+ help
+ Currently supports the QCA8072 and QCA8075 models.
+
config QSEMI_PHY
tristate "Quality Semiconductor PHYs"
---help---
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_MICROSEMI_PHY) += mscc.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
+obj-$(CONFIG_QCA807X_PHY) += qca807x.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_RENESAS_PHY) += uPD60620.o
obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o

View File

@ -1,62 +0,0 @@
From e0fa88eaa3c176b71e563da68949ac2ab45aaa61 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Fri, 2 Oct 2020 10:43:26 +0200
Subject: [PATCH] arm: dts: ipq4019: QCA807x properties
This adds necessary DT properties for QCA807x PHY-s to IPQ4019 DTSI.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -8,6 +8,7 @@
#include <dt-bindings/clock/qcom,gcc-ipq4019.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/net/qcom-qca807x.h>
/ {
#address-cells = <1>;
@@ -597,22 +598,39 @@
ethphy0: ethernet-phy@0 {
reg = <0>;
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
};
ethphy1: ethernet-phy@1 {
reg = <1>;
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
};
ethphy2: ethernet-phy@2 {
reg = <2>;
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
};
ethphy3: ethernet-phy@3 {
reg = <3>;
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
};
ethphy4: ethernet-phy@4 {
reg = <4>;
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
+ };
+
+ psgmiiphy: psgmii-phy@5 {
+ reg = <5>;
+
+ qcom,tx-driver-strength = <PSGMII_QSGMII_TX_DRIVER_300MV>;
+ qcom,psgmii-az;
};
};

View File

@ -1,37 +0,0 @@
From 12e9319da1adacac92930c899c99f0e1970cac11 Mon Sep 17 00:00:00 2001
From: Christian Lamparter <chunkeey@googlemail.com>
Date: Thu, 19 Jan 2017 02:01:31 +0100
Subject: [PATCH 33/38] NET: add qualcomm essedma ethernet driver
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
drivers/net/ethernet/qualcomm/Kconfig | 9 +++++++++
drivers/net/ethernet/qualcomm/Makefile | 1 +
2 files changed, 10 insertions(+)
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -62,4 +62,14 @@ config QCOM_EMAC
source "drivers/net/ethernet/qualcomm/rmnet/Kconfig"
+config ESSEDMA
+ tristate "Qualcomm Atheros ESS Edma support"
+ depends on OF_MDIO
+ help
+ This driver supports ethernet edma adapter.
+ Say Y to build this driver.
+
+ To compile this driver as a module, choose M here. The module
+ will be called essedma.ko.
+
endif # NET_VENDOR_QUALCOMM
--- a/drivers/net/ethernet/qualcomm/Makefile
+++ b/drivers/net/ethernet/qualcomm/Makefile
@@ -10,5 +10,6 @@ obj-$(CONFIG_QCA7000_UART) += qcauart.o
qcauart-objs := qca_uart.o
obj-y += emac/
+obj-$(CONFIG_ESSEDMA) += essedma/
obj-$(CONFIG_RMNET) += rmnet/

View File

@ -1,92 +0,0 @@
From c611d3780fa101662a822d10acf8feb04ca97409 Mon Sep 17 00:00:00 2001
From: Christian Lamparter <chunkeey@gmail.com>
Date: Sun, 20 Nov 2016 01:01:10 +0100
Subject: [PATCH] dts: ipq4019: add ethernet essedma node
This patch adds the device-tree node for the ethernet
interfaces.
Note: The driver isn't anywhere close to be upstream,
so the info might change.
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 60 +++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -39,6 +39,8 @@
spi1 = &blsp1_spi2;
i2c0 = &blsp1_i2c3;
i2c1 = &blsp1_i2c4;
+ ethernet0 = &gmac0;
+ ethernet1 = &gmac1;
};
cpus {
@@ -657,6 +659,64 @@
status = "disabled";
};
+ edma@c080000 {
+ compatible = "qcom,ess-edma";
+ reg = <0xc080000 0x8000>;
+ qcom,page-mode = <0>;
+ qcom,rx_head_buf_size = <1540>;
+ qcom,mdio_supported;
+ qcom,poll_required = <1>;
+ qcom,num_gmac = <2>;
+ interrupts = <0 65 IRQ_TYPE_EDGE_RISING
+ 0 66 IRQ_TYPE_EDGE_RISING
+ 0 67 IRQ_TYPE_EDGE_RISING
+ 0 68 IRQ_TYPE_EDGE_RISING
+ 0 69 IRQ_TYPE_EDGE_RISING
+ 0 70 IRQ_TYPE_EDGE_RISING
+ 0 71 IRQ_TYPE_EDGE_RISING
+ 0 72 IRQ_TYPE_EDGE_RISING
+ 0 73 IRQ_TYPE_EDGE_RISING
+ 0 74 IRQ_TYPE_EDGE_RISING
+ 0 75 IRQ_TYPE_EDGE_RISING
+ 0 76 IRQ_TYPE_EDGE_RISING
+ 0 77 IRQ_TYPE_EDGE_RISING
+ 0 78 IRQ_TYPE_EDGE_RISING
+ 0 79 IRQ_TYPE_EDGE_RISING
+ 0 80 IRQ_TYPE_EDGE_RISING
+ 0 240 IRQ_TYPE_EDGE_RISING
+ 0 241 IRQ_TYPE_EDGE_RISING
+ 0 242 IRQ_TYPE_EDGE_RISING
+ 0 243 IRQ_TYPE_EDGE_RISING
+ 0 244 IRQ_TYPE_EDGE_RISING
+ 0 245 IRQ_TYPE_EDGE_RISING
+ 0 246 IRQ_TYPE_EDGE_RISING
+ 0 247 IRQ_TYPE_EDGE_RISING
+ 0 248 IRQ_TYPE_EDGE_RISING
+ 0 249 IRQ_TYPE_EDGE_RISING
+ 0 250 IRQ_TYPE_EDGE_RISING
+ 0 251 IRQ_TYPE_EDGE_RISING
+ 0 252 IRQ_TYPE_EDGE_RISING
+ 0 253 IRQ_TYPE_EDGE_RISING
+ 0 254 IRQ_TYPE_EDGE_RISING
+ 0 255 IRQ_TYPE_EDGE_RISING>;
+
+ status = "disabled";
+
+ gmac0: gmac0 {
+ local-mac-address = [00 00 00 00 00 00];
+ vlan_tag = <1 0x1f>;
+ };
+
+ gmac1: gmac1 {
+ local-mac-address = [00 00 00 00 00 00];
+ qcom,phy_mdio_addr = <4>;
+ qcom,poll_required = <1>;
+ qcom,forced_speed = <1000>;
+ qcom,forced_duplex = <1>;
+ vlan_tag = <2 0x20>;
+ };
+ };
+
usb3_ss_phy: ssphy@9a000 {
compatible = "qcom,usb-ss-ipq4019-phy";
#phy-cells = <0>;

View File

@ -1,180 +0,0 @@
From: Christian Lamparter <chunkeey@googlemail.com>
Subject: SoC: add qualcomm syscon
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
+obj-$(CONFIG_QCOM_TCSR) += qcom_tcsr.o
obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -183,6 +183,13 @@ config QCOM_SOCINFO
Say yes here to support the Qualcomm socinfo driver, providing
information about the SoC to user space.
+config QCOM_TCSR
+ tristate "QCOM Top Control and Status Registers"
+ depends on ARCH_QCOM
+ help
+ Say y here to enable TCSR support. The TCSR provides control
+ functions for various peripherals.
+
config QCOM_WCNSS_CTRL
tristate "Qualcomm WCNSS control driver"
depends on ARCH_QCOM || COMPILE_TEST
--- /dev/null
+++ b/drivers/soc/qcom/qcom_tcsr.c
@@ -0,0 +1,98 @@
+/*
+ * 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 rev 2 and
+ * only rev 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 <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#define TCSR_USB_PORT_SEL 0xb0
+#define TCSR_USB_HSPHY_CONFIG 0xC
+
+#define TCSR_ESS_INTERFACE_SEL_OFFSET 0x0
+#define TCSR_ESS_INTERFACE_SEL_MASK 0xf
+
+#define TCSR_WIFI0_GLB_CFG_OFFSET 0x0
+#define TCSR_WIFI1_GLB_CFG_OFFSET 0x4
+#define TCSR_PNOC_SNOC_MEMTYPE_M0_M2 0x4
+
+static int tcsr_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ const struct device_node *node = pdev->dev.of_node;
+ void __iomem *base;
+ u32 val;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ if (!of_property_read_u32(node, "qcom,usb-ctrl-select", &val)) {
+ dev_err(&pdev->dev, "setting usb port select = %d\n", val);
+ writel(val, base + TCSR_USB_PORT_SEL);
+ }
+
+ if (!of_property_read_u32(node, "qcom,usb-hsphy-mode-select", &val)) {
+ dev_info(&pdev->dev, "setting usb hs phy mode select = %x\n", val);
+ writel(val, base + TCSR_USB_HSPHY_CONFIG);
+ }
+
+ if (!of_property_read_u32(node, "qcom,ess-interface-select", &val)) {
+ u32 tmp = 0;
+ dev_info(&pdev->dev, "setting ess interface select = %x\n", val);
+ tmp = readl(base + TCSR_ESS_INTERFACE_SEL_OFFSET);
+ tmp = tmp & (~TCSR_ESS_INTERFACE_SEL_MASK);
+ tmp = tmp | (val&TCSR_ESS_INTERFACE_SEL_MASK);
+ writel(tmp, base + TCSR_ESS_INTERFACE_SEL_OFFSET);
+ }
+
+ if (!of_property_read_u32(node, "qcom,wifi_glb_cfg", &val)) {
+ dev_info(&pdev->dev, "setting wifi_glb_cfg = %x\n", val);
+ writel(val, base + TCSR_WIFI0_GLB_CFG_OFFSET);
+ writel(val, base + TCSR_WIFI1_GLB_CFG_OFFSET);
+ }
+
+ if (!of_property_read_u32(node, "qcom,wifi_noc_memtype_m0_m2", &val)) {
+ dev_info(&pdev->dev,
+ "setting wifi_noc_memtype_m0_m2 = %x\n", val);
+ writel(val, base + TCSR_PNOC_SNOC_MEMTYPE_M0_M2);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id tcsr_dt_match[] = {
+ { .compatible = "qcom,tcsr", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, tcsr_dt_match);
+
+static struct platform_driver tcsr_driver = {
+ .driver = {
+ .name = "tcsr",
+ .owner = THIS_MODULE,
+ .of_match_table = tcsr_dt_match,
+ },
+ .probe = tcsr_probe,
+};
+
+module_platform_driver(tcsr_driver);
+
+MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
+MODULE_DESCRIPTION("QCOM TCSR driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+++ b/include/dt-bindings/soc/qcom,tcsr.h
@@ -0,0 +1,48 @@
+/* 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.
+ */
+#ifndef __DT_BINDINGS_QCOM_TCSR_H
+#define __DT_BINDINGS_QCOM_TCSR_H
+
+#define TCSR_USB_SELECT_USB3_P0 0x1
+#define TCSR_USB_SELECT_USB3_P1 0x2
+#define TCSR_USB_SELECT_USB3_DUAL 0x3
+
+/* IPQ40xx HS PHY Mode Select */
+#define TCSR_USB_HSPHY_HOST_MODE 0x00E700E7
+#define TCSR_USB_HSPHY_DEVICE_MODE 0x00C700E7
+
+/* IPQ40xx ess interface mode select */
+#define TCSR_ESS_PSGMII 0
+#define TCSR_ESS_PSGMII_RGMII5 1
+#define TCSR_ESS_PSGMII_RMII0 2
+#define TCSR_ESS_PSGMII_RMII1 4
+#define TCSR_ESS_PSGMII_RMII0_RMII1 6
+#define TCSR_ESS_PSGMII_RGMII4 9
+
+/*
+ * IPQ40xx WiFi Global Config
+ * Bit 30:AXID_EN
+ * Enable AXI master bus Axid translating to confirm all txn submitted by order
+ * Bit 24: Use locally generated socslv_wxi_bvalid
+ * 1: use locally generate socslv_wxi_bvalid for performance.
+ * 0: use SNOC socslv_wxi_bvalid.
+ */
+#define TCSR_WIFI_GLB_CFG 0x41000000
+
+/* IPQ40xx MEM_TYPE_SEL_M0_M2 Select Bit 26:24 - 2 NORMAL */
+#define TCSR_WIFI_NOC_MEMTYPE_M0_M2 0x02222222
+
+/* TCSR A/B REG */
+#define IPQ806X_TCSR_REG_A_ADM_CRCI_MUX_SEL 0
+#define IPQ806X_TCSR_REG_B_ADM_CRCI_MUX_SEL 1
+
+#endif

View File

@ -1,176 +0,0 @@
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
@@ -15,6 +15,7 @@
*/
#include "qcom-ipq4019.dtsi"
+#include <dt-bindings/soc/qcom,tcsr.h>
/ {
model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK01.1";
@@ -29,6 +30,32 @@
};
soc {
+ tcsr@194b000 {
+ /* select hostmode */
+ compatible = "qcom,tcsr";
+ reg = <0x194b000 0x100>;
+ qcom,usb-hsphy-mode-select = <TCSR_USB_HSPHY_HOST_MODE>;
+ status = "okay";
+ };
+
+ ess_tcsr@1953000 {
+ compatible = "qcom,tcsr";
+ reg = <0x1953000 0x1000>;
+ qcom,ess-interface-select = <TCSR_ESS_PSGMII>;
+ };
+
+ tcsr@1949000 {
+ compatible = "qcom,tcsr";
+ reg = <0x1949000 0x100>;
+ qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
+ };
+
+ tcsr@1957000 {
+ compatible = "qcom,tcsr";
+ reg = <0x1957000 0x100>;
+ qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
+ };
+
rng@22000 {
status = "ok";
};
@@ -74,14 +101,6 @@
pinctrl-names = "default";
status = "ok";
cs-gpios = <&tlmm 54 0>;
-
- mx25l25635e@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0>;
- compatible = "mx25l25635e";
- spi-max-frequency = <24000000>;
- };
};
serial@78af000 {
@@ -109,5 +128,41 @@
wifi@a800000 {
status = "ok";
};
+
+ mdio@90000 {
+ status = "okay";
+ };
+
+ ess-switch@c000000 {
+ status = "okay";
+ };
+
+ ess-psgmii@98000 {
+ status = "okay";
+ };
+
+ edma@c080000 {
+ status = "okay";
+ };
+
+ usb3_ss_phy: ssphy@9a000 {
+ status = "okay";
+ };
+
+ usb3_hs_phy: hsphy@a6000 {
+ status = "okay";
+ };
+
+ usb3: usb3@8af8800 {
+ status = "okay";
+ };
+
+ usb2_hs_phy: hsphy@a8000 {
+ status = "okay";
+ };
+
+ usb2: usb2@60f8800 {
+ status = "okay";
+ };
};
};
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1-c1.dts
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1-c1.dts
@@ -18,5 +18,73 @@
/ {
model = "Qualcomm Technologies, Inc. IPQ40xx/AP-DK01.1-C1";
+ compatible = "qcom,ap-dk01.1-c1", "qcom,ap-dk01.2-c1";
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x10000000>;
+ };
+};
+
+&blsp1_spi1 {
+ mx25l25635f@0 {
+ compatible = "mx25l25635f", "jedec,spi-nor";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0>;
+ spi-max-frequency = <24000000>;
+
+ SBL1@0 {
+ label = "SBL1";
+ reg = <0x0 0x40000>;
+ read-only;
+ };
+ MIBIB@40000 {
+ label = "MIBIB";
+ reg = <0x40000 0x20000>;
+ read-only;
+ };
+ QSEE@60000 {
+ label = "QSEE";
+ reg = <0x60000 0x60000>;
+ read-only;
+ };
+ CDT@c0000 {
+ label = "CDT";
+ reg = <0xc0000 0x10000>;
+ read-only;
+ };
+ DDRPARAMS@d0000 {
+ label = "DDRPARAMS";
+ reg = <0xd0000 0x10000>;
+ read-only;
+ };
+ APPSBLENV@e0000 {
+ label = "APPSBLENV";
+ reg = <0xe0000 0x10000>;
+ read-only;
+ };
+ APPSBL@f0000 {
+ label = "APPSBL";
+ reg = <0xf0000 0x80000>;
+ read-only;
+ };
+ ART@170000 {
+ label = "ART";
+ reg = <0x170000 0x10000>;
+ read-only;
+ };
+ kernel@180000 {
+ label = "kernel";
+ reg = <0x180000 0x400000>;
+ };
+ rootfs@580000 {
+ label = "rootfs";
+ reg = <0x580000 0x1600000>;
+ };
+ firmware@180000 {
+ label = "firmware";
+ reg = <0x180000 0x1a00000>;
+ };
+ };
};

View File

@ -1,82 +0,0 @@
From a10fab12a927e60b7141a602e740d70cb4d09e4a Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 9 Mar 2017 11:03:18 +0100
Subject: [PATCH] arm: boot: add dts files
Signed-off-by: John Crispin <john@phrozen.org>
---
arch/arm/boot/dts/Makefile | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -837,11 +837,69 @@ dtb-$(CONFIG_ARCH_QCOM) += \
qcom-apq8074-dragonboard.dtb \
qcom-apq8084-ifc6540.dtb \
qcom-apq8084-mtp.dtb \
+ qcom-ipq4018-a42.dtb \
+ qcom-ipq4018-ap120c-ac.dtb \
+ qcom-ipq4018-dap-2610.dtb \
+ qcom-ipq4018-cs-w3-wd1200g-eup.dtb \
+ qcom-ipq4018-magic-2-wifi-next.dtb \
+ qcom-ipq4018-ea6350v3.dtb \
+ qcom-ipq4018-eap1300.dtb \
+ qcom-ipq4018-ecw5211.dtb \
+ qcom-ipq4018-emd1.dtb \
+ qcom-ipq4018-emr3500.dtb \
+ qcom-ipq4018-ens620ext.dtb \
+ qcom-ipq4018-ex6100v2.dtb \
+ qcom-ipq4018-ex6150v2.dtb \
+ qcom-ipq4018-fritzbox-4040.dtb \
+ qcom-ipq4018-gl-ap1300.dtb \
+ qcom-ipq4018-jalapeno.dtb \
+ qcom-ipq4018-meshpoint-one.dtb \
+ qcom-ipq4018-hap-ac2.dtb \
+ qcom-ipq4018-sxtsq-5-ac.dtb \
+ qcom-ipq4018-nbg6617.dtb \
+ qcom-ipq4019-oap100.dtb \
+ qcom-ipq4018-pa1200.dtb \
+ qcom-ipq4018-rt-ac58u.dtb \
+ qcom-ipq4018-rutx10.dtb \
+ qcom-ipq4018-wac510.dtb \
+ qcom-ipq4018-wre6606.dtb \
+ qcom-ipq4018-wrtq-329acn.dtb \
qcom-ipq4019-ap.dk01.1-c1.dtb \
qcom-ipq4019-ap.dk04.1-c1.dtb \
qcom-ipq4019-ap.dk04.1-c3.dtb \
qcom-ipq4019-ap.dk07.1-c1.dtb \
qcom-ipq4019-ap.dk07.1-c2.dtb \
+ qcom-ipq4019-a62.dtb \
+ qcom-ipq4019-cm520-79f.dtb \
+ qcom-ipq4019-ea8300.dtb \
+ qcom-ipq4019-eap2200.dtb \
+ qcom-ipq4019-fritzbox-7530.dtb \
+ qcom-ipq4019-fritzrepeater-1200.dtb \
+ qcom-ipq4019-fritzrepeater-3000.dtb \
+ qcom-ipq4019-hap-ac3.dtb \
+ qcom-ipq4019-map-ac2200.dtb \
+ qcom-ipq4019-lhgg-60ad.dtb \
+ qcom-ipq4019-mr8300.dtb \
+ qcom-ipq4019-e2600ac-c1.dtb \
+ qcom-ipq4019-e2600ac-c2.dtb \
+ qcom-ipq4019-habanero-dvk.dtb \
+ qcom-ipq4019-pa2200.dtb \
+ qcom-ipq4019-rbr50.dtb \
+ qcom-ipq4019-rbs50.dtb \
+ qcom-ipq4019-rtl30vw.dtb \
+ qcom-ipq4019-srr60.dtb \
+ qcom-ipq4019-srs60.dtb \
+ qcom-ipq4019-u4019-32m.dtb \
+ qcom-ipq4019-wpj419.dtb \
+ qcom-ipq4019-wtr-m2133hp.dtb \
+ qcom-ipq4028-wpj428.dtb \
+ qcom-ipq4029-ap-303.dtb \
+ qcom-ipq4029-ap-303h.dtb \
+ qcom-ipq4029-ap-365.dtb \
+ qcom-ipq4029-gl-b1300.dtb \
+ qcom-ipq4019-gl-b2200.dtb \
+ qcom-ipq4029-gl-s1300.dtb \
+ qcom-ipq4029-mr33.dtb \
qcom-ipq8064-ap148.dtb \
qcom-msm8660-surf.dtb \
qcom-msm8960-cdp.dtb \

View File

@ -1,167 +0,0 @@
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk04.1.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk04.1.dtsi
@@ -17,53 +17,79 @@
stdout-path = "serial0:115200n8";
};
- memory {
- device_type = "memory";
- reg = <0x80000000 0x10000000>; /* 256MB */
- };
-
soc {
+ rng@22000 {
+ status = "okay";
+ };
+
pinctrl@1000000 {
serial_0_pins: serial0-pinmux {
- pins = "gpio16", "gpio17";
- function = "blsp_uart0";
- bias-disable;
+ mux {
+ pins = "gpio16", "gpio17";
+ function = "blsp_uart0";
+ bias-disable;
+ };
};
serial_1_pins: serial1-pinmux {
- pins = "gpio8", "gpio9",
- "gpio10", "gpio11";
- function = "blsp_uart1";
- bias-disable;
+ mux {
+ pins = "gpio8", "gpio9";
+ function = "blsp_uart1";
+ bias-disable;
+ };
};
spi_0_pins: spi-0-pinmux {
pinmux {
function = "blsp_spi0";
pins = "gpio13", "gpio14", "gpio15";
- bias-disable;
};
pinmux_cs {
function = "gpio";
pins = "gpio12";
+ };
+ pinconf {
+ pins = "gpio13", "gpio14", "gpio15";
+ drive-strength = <12>;
+ bias-disable;
+ };
+ pinconf_cs {
+ pins = "gpio12";
+ drive-strength = <2>;
bias-disable;
output-high;
};
};
i2c_0_pins: i2c-0-pinmux {
- pins = "gpio20", "gpio21";
- function = "blsp_i2c0";
- bias-disable;
+ pinmux {
+ function = "blsp_i2c0";
+ pins = "gpio10", "gpio11";
+ };
+ pinconf {
+ pins = "gpio10", "gpio11";
+ drive-strength = <16>;
+ bias-disable;
+ };
};
nand_pins: nand-pins {
- pins = "gpio53", "gpio55", "gpio56",
- "gpio57", "gpio58", "gpio59",
- "gpio60", "gpio62", "gpio63",
- "gpio64", "gpio65", "gpio66",
- "gpio67", "gpio68", "gpio69";
- function = "qpic";
+ pullups {
+ pins = "gpio52", "gpio53", "gpio58",
+ "gpio59";
+ function = "qpic";
+ bias-pull-up;
+ };
+
+ pulldowns {
+ pins = "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio60", "gpio61",
+ "gpio62", "gpio63", "gpio64",
+ "gpio65", "gpio66", "gpio67",
+ "gpio68", "gpio69";
+ function = "qpic";
+ bias-pull-down;
+ };
};
};
@@ -89,11 +115,11 @@
status = "ok";
cs-gpios = <&tlmm 12 0>;
- m25p80@0 {
+ mx25l25635e@0 {
#address-cells = <1>;
#size-cells = <1>;
reg = <0>;
- compatible = "n25q128a11";
+ compatible = "mx25l25635e";
spi-max-frequency = <24000000>;
};
};
@@ -103,9 +129,48 @@
perst-gpio = <&tlmm 38 0x1>;
};
+ i2c0: i2c@78b7000 { /* BLSP1 QUP2 */
+ pinctrl-0 = <&i2c_0_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+ };
+
qpic-nand@79b0000 {
pinctrl-0 = <&nand_pins>;
pinctrl-names = "default";
};
+
+ usb3_ss_phy: ssphy@9a000 {
+ status = "okay";
+ };
+
+ usb3_hs_phy: hsphy@a6000 {
+ status = "okay";
+ };
+
+ usb3: usb3@8af8800 {
+ status = "okay";
+ };
+
+ usb2_hs_phy: hsphy@a8000 {
+ status = "okay";
+ };
+
+ usb2: usb2@60f8800 {
+ status = "okay";
+ };
+
+ cryptobam: dma@8e04000 {
+ status = "okay";
+ };
+
+ crypto@8e3a000 {
+ status = "okay";
+ };
+
+ watchdog@b017000 {
+ status = "okay";
+ };
};
};

View File

@ -1,12 +0,0 @@
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -1059,6 +1059,9 @@ int __init early_init_dt_scan_chosen(uns
p = of_get_flat_dt_prop(node, "bootargs", &l);
if (p != NULL && l > 0)
strlcpy(data, p, min(l, COMMAND_LINE_SIZE));
+ p = of_get_flat_dt_prop(node, "bootargs-append", &l);
+ if (p != NULL && l > 0)
+ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE));
/*
* CONFIG_CMDLINE is meant to be a default in case nothing else