diff --git a/target/linux/ipq40xx/Makefile b/target/linux/ipq40xx/Makefile index acba78e9c..ab7b174e4 100644 --- a/target/linux/ipq40xx/Makefile +++ b/target/linux/ipq40xx/Makefile @@ -8,16 +8,16 @@ CPU_TYPE:=cortex-a7 CPU_SUBTYPE:=neon-vfpv4 MAINTAINER:=John Crispin +# TODO: drop kmod-usb-dwc3-of-simple when migrating to 4.19 KERNEL_PATCHVER:=4.14 KERNELNAME:=zImage Image dtbs include $(INCLUDE_DIR)/target.mk DEFAULT_PACKAGES += \ + kmod-usb-dwc3-of-simple \ kmod-leds-gpio kmod-gpio-button-hotplug swconfig \ - kmod-ath10k wpad-basic \ - kmod-usb3 kmod-usb-dwc3-of-simple kmod-usb-phy-qcom-dwc3 \ - ath10k-firmware-qca4019 \ - automount autosamba luci-app-ipsec-vpnd luci-app-zerotier htop + kmod-ath10k-ct wpad-basic \ + kmod-usb3 kmod-usb-dwc3 ath10k-firmware-qca4019-ct $(eval $(call BuildTarget)) diff --git a/target/linux/ipq40xx/base-files/etc/board.d/01_leds b/target/linux/ipq40xx/base-files/etc/board.d/01_leds index fa6b848c0..85b131630 100755 --- a/target/linux/ipq40xx/base-files/etc/board.d/01_leds +++ b/target/linux/ipq40xx/base-files/etc/board.d/01_leds @@ -11,11 +11,9 @@ board=$(board_name) boardname="${board##*,}" case "$board" in -asus,rt-ac1300uhp |\ asus,rt-ac58u) ucidef_set_led_wlan "wlan2g" "WLAN2G" "${boardname}:blue:wlan2G" "phy0tpt" ucidef_set_led_wlan "wlan5g" "WLAN5G" "${boardname}:blue:wlan5G" "phy1tpt" - ucidef_set_led_usbport "usb" "USB" "${boardname}:blue:usb" "usb1-port1" "usb2-port1" "usb3-port1" "usb4-port1" ucidef_set_led_switch "wan" "WAN" "${boardname}:blue:wan" "switch0" "0x20" ucidef_set_led_switch "lan" "LAN" "${boardname}:blue:lan" "switch0" "0x1e" ;; @@ -34,6 +32,12 @@ avm,fritzbox-4040) ucidef_set_led_switch "wan" "WAN" "fritz4040:green:wan" "switch0" "0x20" ucidef_set_led_switch "lan" "LAN" "fritz4040:green:lan" "switch0" "0x1e" ;; +engenius,eap1300) + ucidef_set_led_netdev "lan" "LAN" "${boardname}:blue:lan" "eth0" + ucidef_set_led_wlan "wlan2g" "WLAN2G" "${boardname}:blue:wlan2g" "phy0tpt" + ucidef_set_led_wlan "wlan5g" "WLAN5G" "${boardname}:yellow:wlan5g" "phy1tpt" + ucidef_set_led_default "mesh" "MESH" "${boardname}:blue:mesh" "0" + ;; glinet,gl-b1300) ucidef_set_led_wlan "wlan" "WLAN" "${boardname}:green:wlan" "phy0tpt" ;; @@ -42,13 +46,9 @@ netgear,ex6150v2) ucidef_set_led_wlan "wlan2g" "WLAN2G" "ex61x0v2:green:router" "phy0tpt" ucidef_set_led_wlan "wlan5g" "WLAN5G" "ex61x0v2:green:client" "phy1tpt" ;; -meraki,mr33) - ucidef_set_interface_lan "eth0" - ;; zyxel,nbg6617) - ucidef_set_led_wlan "wlan2g" "WLAN2G" "$board:green:wlan2G" "phy0tpt" - ucidef_set_led_wlan "wlan5g" "WLAN5G" "$board:green:wlan5G" "phy1tpt" - ucidef_set_led_usbport "usb" "USB" "${board}:green:usb" "usb1-port1" "usb2-port1" "usb3-port1" "usb4-port1" + ucidef_set_led_wlan "wlan2g" "WLAN2G" "${boardname}:green:wlan2G" "phy0tpt" + ucidef_set_led_wlan "wlan5g" "WLAN5G" "${boardname}:green:wlan5G" "phy1tpt" ;; zyxel,wre6606) ucidef_set_led_wlan "wlan2g" "WLAN2G" "${boardname}:green:wlan2g" "phy0tpt" diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network index 358c444ed..959374cf9 100755 --- a/target/linux/ipq40xx/base-files/etc/board.d/02_network +++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network @@ -7,59 +7,77 @@ . /lib/functions/uci-defaults.sh . /lib/functions/system.sh +ipq40xx_setup_interfaces() +{ + local board="$1" + + case "$board" in + 8dev,jalapeno) + ucidef_add_switch "switch0" \ + "0t@eth0" "4:lan" "5:wan" + ;; + zyxel,nbg6617) + ucidef_add_switch "switch0" \ + "0t@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" "5:wan:5" + ;; + asus,map-ac2200|\ + openmesh,a42|\ + openmesh,a62) + ucidef_add_switch "switch0" \ + "0t@eth0" "5:lan" "4:wan" + ;; + asus,rt-acrh17|\ + asus,rt-ac58u|\ + avm,fritzbox-4040|\ + linksys,ea6350v3) + ucidef_add_switch "switch0" \ + "0t@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "5:wan" + ;; + compex,wpj428) + ucidef_set_interface_lan "eth0 eth1" + ;; + engenius,eap1300|\ + meraki,mr33|\ + netgear,ex6100v2|\ + netgear,ex6150v2|\ + zyxel,wre6606) + ucidef_set_interface_lan "eth0" + ;; + glinet,gl-b1300) + ucidef_add_switch "switch0" \ + "0t@eth0" "3:lan" "4:lan" "5:wan" + ;; + *) + echo "Unsupported hardware. Network interfaces not initialized" + ;; + esac +} + +ipq40xx_setup_macs() +{ + local board="$1" + + case "$board" in + asus,rt-acrh17|\ + asus,rt-ac58u) + CI_UBIPART=UBI_DEV + lan_mac=$(cat /sys/class/net/eth0/address) + wan_mac=$(macaddr_add "$lan_mac" 1) + ;; + linksys,ea6350v3) + wan_mac=$(mtd_get_mac_ascii devinfo hw_mac_addr) + lan_mac=$(macaddr_add "$wan_mac" 1) + ;; + esac + + [ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac + [ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac +} + board_config_update - board=$(board_name) - -case "$board" in -asus,rt-ac1300uhp |\ -asus,rt-ac58u |\ -asus,rt-acrh17) - ucidef_add_switch "switch0" \ - "0t@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "5:wan" - lan_mac_addr=$(cat /sys/class/net/eth0/address) - wan_mac_addr=$(macaddr_add "$lan_mac_addr" 1) - ucidef_set_interface_macaddr "lan" "$lan_mac_addr" - ucidef_set_interface_macaddr "wan" "$wan_mac_addr" - ;; -linksys,ea6350v3 |\ -avm,fritzbox-4040) - ucidef_add_switch "switch0" \ - "0t@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "5:wan" - ;; -compex,wpj428) - ucidef_add_switch "switch0" \ - "0t@eth0" "4:wan" "5:lan" - ;; -glinet,gl-b1300) - ucidef_add_switch "switch0" \ - "0t@eth0" "3:lan" "4:lan" "5:wan" - ;; -8dev,jalapeno |\ -openmesh,a42 |\ -openmesh,a62) - ucidef_add_switch "switch0" \ - "0t@eth0" "4:lan" "5:wan" - ;; -meraki,mr33 |\ -netgear,ex6100v2 |\ -netgear,ex6150v2 |\ -zyxel,wre6606) - ucidef_set_interface_lan "eth0" - ;; -zyxel,nbg6617) - ucidef_add_switch "switch0" \ - "0u@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" "5:wan:5" - lan_mac_addr=$(macaddr_add $(cat /sys/class/net/eth0/address) +2) - wan_mac_addr=$(macaddr_add "$lan_mac_addr" +1) - ucidef_set_interface_macaddr "lan" "$lan_mac_addr" - ucidef_set_interface_macaddr "wan" "$wan_mac_addr" - ;; -*) - echo "Unsupported hardware. Network interfaces not intialized" - ;; -esac - +ipq40xx_setup_interfaces $board +ipq40xx_setup_macs $board board_config_flush exit 0 diff --git a/target/linux/ipq40xx/base-files/etc/diag.sh b/target/linux/ipq40xx/base-files/etc/diag.sh deleted file mode 100755 index 3ea7ac1a1..000000000 --- a/target/linux/ipq40xx/base-files/etc/diag.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -. /lib/functions/leds.sh - -boot="$(get_dt_led boot)" -failsafe="$(get_dt_led failsafe)" -running="$(get_dt_led running)" -upgrade="$(get_dt_led upgrade)" - -set_state() { - status_led="$boot" - - case "$1" in - preinit) - status_led_blink_preinit - ;; - failsafe) - status_led_off - [ -n "$running" ] && { - status_led="$running" - status_led_off - } - status_led="$failsafe" - status_led_blink_failsafe - ;; - preinit_regular) - status_led_blink_preinit_regular - ;; - upgrade) - [ -n "$running" ] && { - status_led="$running" - status_led_off - } - status_led="$upgrade" - status_led_blink_preinit_regular - ;; - done) - status_led_off - [ -n "$running" ] && { - status_led="$running" - status_led_on - } - ;; - esac -} diff --git a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata index 79fa283af..1062500f7 100644 --- a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +++ b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -31,7 +31,7 @@ ath10kcal_extract() { [ -n "$mtd" ] || \ ath10kcal_die "no mtd device found for partition $part" - dd if=$mtd of=/lib/firmware/$FIRMWARE bs=1 skip=$offset count=$count 2>/dev/null || \ + dd if=$mtd of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \ ath10kcal_die "failed to extract calibration data from $mtd" } @@ -49,18 +49,10 @@ ath10kcal_ubi_extract() { [ -n "$ubi" ] || \ ath10kcal_die "no UBI volume found for $part" - dd if=/dev/$ubi of=/lib/firmware/$FIRMWARE bs=1 skip=$offset count=$count 2>/dev/null || \ + dd if=/dev/$ubi of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \ ath10kcal_die "failed to extract from $ubi" } -ath10kcal_patch_mac() { - local mac=$1 - - [ -z "$mac" ] && return - - macaddr_2bin $mac | dd of=/lib/firmware/$FIRMWARE conv=notrunc bs=1 seek=6 count=6 -} - ath10kcal_patch_mac_crc() { local mac=$1 local mac_offset=6 @@ -69,19 +61,21 @@ ath10kcal_patch_mac_crc() { local xor_fw_mac local xor_fw_chksum + [ -z "$mac" ] && return + xor_fw_mac=$(hexdump -v -n 6 -s $mac_offset -e '/1 "%02x"' /lib/firmware/$FIRMWARE) xor_fw_mac="${xor_fw_mac:0:4} ${xor_fw_mac:4:4} ${xor_fw_mac:8:4}" - ath10kcal_patch_mac "$mac" && { - xor_mac=${mac//:/} - xor_mac="${xor_mac:0:4} ${xor_mac:4:4} ${xor_mac:8:4}" + macaddr_2bin $mac | dd of=/lib/firmware/$FIRMWARE conv=notrunc bs=1 seek=6 count=6 - xor_fw_chksum=$(hexdump -v -n 2 -s $chksum_offset -e '/1 "%02x"' /lib/firmware/$FIRMWARE) - xor_fw_chksum=$(xor $xor_fw_chksum $xor_fw_mac $xor_mac) + xor_mac=${mac//:/} + xor_mac="${xor_mac:0:4} ${xor_mac:4:4} ${xor_mac:8:4}" - printf "%b" "\x${xor_fw_chksum:0:2}\x${xor_fw_chksum:2:2}" | \ - dd of=/lib/firmware/$FIRMWARE conv=notrunc bs=1 seek=$chksum_offset count=2 - } + xor_fw_chksum=$(hexdump -v -n 2 -s $chksum_offset -e '/1 "%02x"' /lib/firmware/$FIRMWARE) + xor_fw_chksum=$(xor $xor_fw_chksum $xor_fw_mac $xor_mac) + + printf "%b" "\x${xor_fw_chksum:0:2}\x${xor_fw_chksum:2:2}" | \ + dd of=/lib/firmware/$FIRMWARE conv=notrunc bs=1 seek=$chksum_offset count=2 } ath10kcal_is_caldata_valid() { @@ -106,12 +100,17 @@ case "$FIRMWARE" in meraki,mr33) ath10kcal_ubi_extract "ART" 36864 2116 ath10kcal_is_caldata_valid "4408" || ath10kcal_extract "ART" 36864 2116 - ath10kcal_patch_mac $(macaddr_add $(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 102) +1) + ath10kcal_patch_mac_crc $(macaddr_add $(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 102) +1) ;; esac ;; "ath10k/pre-cal-pci-0000:01:00.0.bin") case "$board" in + asus,map-ac2200) + ath10kcal_ubi_extract "Factory" 36864 12064 + ln -sf /lib/firmware/ath10k/pre-cal-pci-0000\:00\:00.0.bin \ + /lib/firmware/ath10k/QCA9888/hw2.0/board.bin + ;; asus,rt-acrh17) CI_UBIPART=UBI_DEV ath10kcal_ubi_extract "Factory" 36864 12064 @@ -124,12 +123,14 @@ case "$FIRMWARE" in "ath10k/pre-cal-ahb-a000000.wifi.bin") case "$board" in 8dev,jalapeno |\ - linksys,ea6350v3 |\ glinet,gl-b1300 |\ + linksys,ea6350v3 |\ qcom,ap-dk01.1-c1) ath10kcal_extract "ART" 4096 12064 ;; - asus,rt-ac1300uhp |\ + asus,map-ac2200) + ath10kcal_ubi_extract "Factory" 4096 12064 + ;; asus,rt-acrh17|\ asus,rt-ac58u) CI_UBIPART=UBI_DEV @@ -149,6 +150,7 @@ case "$FIRMWARE" in ath10kcal_patch_mac_crc $(mtd_get_mac_binary dnidata 0) ;; compex,wpj428 |\ + engenius,eap1300 |\ openmesh,a42 |\ openmesh,a62) ath10kcal_extract "0:ART" 4096 12064 @@ -163,12 +165,14 @@ case "$FIRMWARE" in "ath10k/pre-cal-ahb-a800000.wifi.bin") case "$board" in 8dev,jalapeno |\ - linksys,ea6350v3 |\ glinet,gl-b1300 |\ + linksys,ea6350v3 |\ qcom,ap-dk01.1-c1) ath10kcal_extract "ART" 20480 12064 ;; - asus,rt-ac1300uhp |\ + asus,map-ac2200) + ath10kcal_ubi_extract "Factory" 20480 12064 + ;; asus,rt-ac58u) CI_UBIPART=UBI_DEV ath10kcal_ubi_extract "Factory" 20480 12064 @@ -187,6 +191,7 @@ case "$FIRMWARE" in ath10kcal_patch_mac_crc $(mtd_get_mac_binary dnidata 12) ;; compex,wpj428 |\ + engenius,eap1300 |\ openmesh,a42 |\ openmesh,a62) ath10kcal_extract "0:ART" 20480 12064 diff --git a/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh b/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh index 8be0d3dc7..44dc510a0 100644 --- a/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh +++ b/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh @@ -4,6 +4,11 @@ preinit_set_mac_address() { case $(board_name) in + asus,map-ac2200) + base_mac=$(mtd_get_mac_binary_ubi Factory 4102) + ip link set dev eth0 address $(macaddr_add "$base_mac" +1) + ip link set dev eth1 address $(macaddr_add "$base_mac" +3) + ;; asus,rt-acrh17|\ asus,rt-ac58u) CI_UBIPART=UBI_DEV @@ -14,6 +19,10 @@ preinit_set_mac_address() { mac_lan=$(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 102) [ -n "$mac_lan" ] && ip link set dev eth0 address "$mac_lan" ;; + zyxel,nbg6617) + base_mac=$(cat /sys/class/net/eth0/address) + ip link set dev eth0 address $(macaddr_add "$base_mac" +2) + ;; esac } diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh b/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh old mode 100644 new mode 100755 diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/openmesh.sh b/target/linux/ipq40xx/base-files/lib/upgrade/openmesh.sh index 081f3305c..f4bc7e756 100644 --- a/target/linux/ipq40xx/base-files/lib/upgrade/openmesh.sh +++ b/target/linux/ipq40xx/base-files/lib/upgrade/openmesh.sh @@ -76,9 +76,9 @@ platform_do_upgrade_openmesh() { # take care of restoring a saved config [ "$SAVE_CONFIG" -eq 1 ] && restore_backup="${MTD_CONFIG_ARGS} -j ${CONF_TAR}" - # write concatinated kernel + rootfs to flash - tar xf $tar_file ${board_dir}/kernel ${board_dir}/root -O | \ - mtd $restore_backup write - $PART_NAME + mtd -q erase inactive + tar xf $tar_file ${board_dir}/root -O | mtd -n -p $kernel_length $restore_backup write - $PART_NAME + tar xf $tar_file ${board_dir}/kernel -O | mtd -n write - $PART_NAME # prepare new u-boot env if [ "$next_boot_part" = "1" ]; then diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh index 39758f540..0397b317f 100644 --- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh +++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh @@ -162,7 +162,10 @@ platform_do_upgrade() { 8dev,jalapeno) nand_do_upgrade "$ARGV" ;; - asus,rt-ac1300uhp |\ + asus,map-ac2200) + CI_KERNPART="linux" + nand_do_upgrade "$1" + ;; asus,rt-acrh17|\ asus,rt-ac58u) local magic=$(get_magic_long "$1") @@ -198,10 +201,6 @@ platform_do_upgrade() { platform_nand_pre_upgrade() { case "$(board_name)" in - linksys,ea6350v3) - CI_UBIPART="UBI_DEV" - CI_KERNPART="linux" - ;; meraki,mr33) CI_KERNPART="part.safe" ;; diff --git a/target/linux/ipq40xx/config-4.14 b/target/linux/ipq40xx/config-4.14 index 0bd9ff7a1..c72e69320 100644 --- a/target/linux/ipq40xx/config-4.14 +++ b/target/linux/ipq40xx/config-4.14 @@ -102,6 +102,7 @@ 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 @@ -263,6 +264,7 @@ CONFIG_IRQ_DOMAIN=y CONFIG_IRQ_DOMAIN_HIERARCHY=y CONFIG_IRQ_FORCED_THREADING=y CONFIG_IRQ_WORK=y +CONFIG_LEDS_LP5523=y CONFIG_LEDS_LP5562=y CONFIG_LEDS_LP55XX_COMMON=y CONFIG_LIBFDT=y @@ -281,6 +283,7 @@ CONFIG_MDIO_IPQ40XX=y CONFIG_MFD_SYSCON=y CONFIG_MIGHT_HAVE_CACHE_L2X0=y CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y CONFIG_MODULES_USE_ELF_REL=y # CONFIG_MSM_GCC_8660 is not set # CONFIG_MSM_GCC_8916 is not set diff --git a/target/linux/ipq40xx/config-4.19 b/target/linux/ipq40xx/config-4.19 new file mode 100644 index 000000000..a40f4b6bc --- /dev/null +++ b/target/linux/ipq40xx/config-4.19 @@ -0,0 +1,500 @@ +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_APQ_GCC_8084 is not set +# CONFIG_APQ_MMCC_8084 is not set +CONFIG_AR40XX_PHY=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_PHYS_TO_DMA=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_IPQ40XX=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_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_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_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +# CONFIG_ARM_LPAE is not set +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_SMMU is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_AT803X_PHY=y +CONFIG_AUTO_ZRELADDR=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_COMMON_CLK=y +CONFIG_COMMON_CLK_QCOM=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_BIG_ENDIAN is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_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_ICACHE_DISABLE is not set +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_CBC=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_DEV_QCE=y +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_GF128MUL=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=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_WORKQUEUE=y +CONFIG_CRYPTO_XTS=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_DEBUG_USER is not set +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=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_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_SYSFS=y +CONFIG_GPIO_WATCHDOG=y +# CONFIG_GPIO_WATCHDOG_ARCH_INITCALL is not set +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_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_HW_RANDOM=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_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_LEDS_LP5562=y +CONFIG_LEDS_LP55XX_COMMON=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_IPQ40XX=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_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MSCC_OCELOT_SWITCH is not set +# 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_M25P80=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_CORE=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_QCOM=y +CONFIG_MTD_SPI_NAND=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_SPLIT_FIT_FW=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_LEGACY=y +CONFIG_NET_DSA_QCA8K=y +# CONFIG_NET_DSA_REALTEK_SMI is not set +CONFIG_NET_DSA_TAG_QCA=y +# CONFIG_NET_DSA_VITESSE_VSC73XX is not set +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_SWITCHDEV=y +CONFIG_NLS=y +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=4 +CONFIG_NVMEM=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_OF_RESERVED_MEM=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_PCI_V3_SEMI is not set +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=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_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_SDM845 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_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_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_TCSR=y +# CONFIG_QCOM_TSENS is not set +CONFIG_QCOM_WDT=y +# CONFIG_QRTR is not set +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_QCOM_SPMI is not set +CONFIG_REGULATOR_VCTRL=y +CONFIG_RESET_CONTROLLER=y +# CONFIG_RESET_QCOM_AOSS is not set +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_SDM_DISPCC_845 is not set +# CONFIG_SDM_GCC_845 is not set +# CONFIG_SDM_VIDEOCC_845 is not set +CONFIG_SERIAL_8250_FSL=y +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +# CONFIG_SFP is not set +CONFIG_SGL_ALLOC=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +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_THUMB2_KERNEL is not set +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_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_USB=y +CONFIG_USB_COMMON=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_SUPPORT=y +CONFIG_USE_OF=y +CONFIG_VDSO=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-a42.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-a42.dts index 7a2e1c734..566ec814a 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-a42.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-a42.dts @@ -63,12 +63,6 @@ status = "okay"; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - crypto@8e3a000 { status = "okay"; }; @@ -86,7 +80,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; reset { @@ -103,7 +97,7 @@ led-upgrade = &power; }; - gpio-leds { + leds { compatible = "gpio-leds"; red { @@ -180,6 +174,12 @@ }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &cryptobam { status = "okay"; }; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts index b344527f0..f27aa68d2 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts @@ -1,18 +1,4 @@ -/* Copyright (c) 2015, 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT #include "qcom-ipq4019.dtsi" #include @@ -23,11 +9,6 @@ model = "Linksys EA6350v3"; compatible = "linksys,ea6350v3", "qcom,ipq4019"; - memory { - device_type = "memory"; - reg = <0x80000000 0x10000000>; - }; - aliases { led-boot = &power; led-failsafe = &power; @@ -72,12 +53,6 @@ status = "okay"; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - usb3@8af8800 { status = "okay"; }; @@ -86,16 +61,6 @@ status = "okay"; }; - wifi@a000000 { - status = "okay"; - qcom,ath10k-calibration-variant = "linksys-ea6350v3"; - }; - - wifi@a800000 { - status = "okay"; - qcom,ath10k-calibration-variant = "linksys-ea6350v3"; - }; - watchdog@b017000 { status = "okay"; }; @@ -109,7 +74,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; reset { @@ -125,20 +90,37 @@ }; }; - gpio-leds { + leds { compatible = "gpio-leds"; power: status { - label = "rt-ac58u:blue:status"; + label = "EA6350v3:green:status"; gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>; }; }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &cryptobam { status = "okay"; }; +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "linksys-ea6350v3"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "linksys-ea6350v3"; +}; + + &blsp_dma { status = "okay"; }; @@ -177,17 +159,9 @@ cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>, <&tlmm 59 GPIO_ACTIVE_HIGH>; - m25p80@0 { - #address-cells = <1>; - #size-cells = <0>; - /* - * U-boot looks for "n25q128a11" node, - * if we don't have it, it will spit out the following warning: - * "ipq: fdt fixup unable to find compatible node". - */ + flash@0 { compatible = "jedec,spi-nor"; reg = <0>; - linux,modalias = "m25p80", "mx25l1606e", "n25q128a11"; spi-max-frequency = <24000000>; partitions { @@ -195,75 +169,95 @@ #address-cells = <1>; #size-cells = <1>; - partition0@0 { + SBL1@0 { label = "SBL1"; reg = <0x00000000 0x00040000>; read-only; }; - partition1@40000 { + MBIB@40000 { label = "MIBIB"; reg = <0x00040000 0x00020000>; read-only; }; - partition2@60000 { + QSEE@60000 { label = "QSEE"; reg = <0x00060000 0x00060000>; read-only; }; - partition3@c0000 { + CDT@c0000 { label = "CDT"; reg = <0x000c0000 0x00010000>; read-only; }; - partition4@d0000 { + APPSBLENV@d0000 { label = "APPSBLENV"; reg = <0x000d0000 0x00010000>; read-only; }; - partition5@e0000 { + APPSBL@e0000 { label = "APPSBL"; /* uboot */ reg = <0x000e0000 0x00080000>; read-only; }; - partition6@160000 { + ART@160000 { label = "ART"; reg = <0x00160000 0x00010000>; read-only; }; - partition7@170000 { + u_env@170000 { label = "u_env"; reg = <0x00170000 0x00020000>; }; - partition8@190000 { + s_env@190000 { label = "s_env"; reg = <0x00190000 0x00020000>; }; - partition9@1b0000 { + devinfo@1b0000 { label = "devinfo"; reg = <0x001b0000 0x00010000>; }; /* 0x001c0000 - 0x00200000 unused */ }; }; - mt29f@1 { - status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - compatible = "spinand,mt29f", "w25n01gv"; - reg = <1>; - spi-max-frequency = <24000000>; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - partition0@0 { - label = "ubi"; - reg = <0x00000000 0x08000000>; - }; - }; - }; + flash@1 { + status = "okay"; + compatible = "spinand,mt29f", "w25n01gv"; + reg = <1>; + spi-max-frequency = <24000000>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + kernel@0 { + label = "kernel"; + reg = <0x00000000 0x02800000>; + }; + rootfs@300000 { + label = "rootfs"; + reg = <0x00300000 0x02500000>; + }; + alt_kernel@2800000 { + label = "alt_kernel"; + reg = <0x02800000 0x02800000>; + }; + alt_rootfs@2b00000 { + label = "alt_rootfs"; + reg = <0x02b00000 0x02500000>; + }; + sysdiag@5000000 { + label = "sysdiag"; + reg = <0x05000000 0x00100000>; + }; + syscfg@5100000 { + label = "syscfg"; + reg = <0x05100000 0x02F00000>; + }; + /* 0x00000000 - 0x08000000: 128 MiB */ + }; + }; }; &usb3_ss_phy { diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts new file mode 100644 index 000000000..25b4f1304 --- /dev/null +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "EnGenius EAP1300"; + compatible = "engenius,eap1300", "qcom,ipq4019"; + + soc { + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 18 GPIO_ACTIVE_HIGH>; + linux,code = ; + }; + }; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + leds { + compatible = "gpio-leds"; + + power: orange { + label = "eap1300:orange:power"; + gpios = <&tlmm 58 GPIO_ACTIVE_LOW>; + }; + + lan { + label = "eap1300:blue:lan"; + gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>; + }; + + mesh { + label = "eap1300:blue:mesh"; + gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>; + }; + + wlan2g { + label = "eap1300:blue:wlan2g"; + gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>; + }; + + wlan5g { + label = "eap1300:yellow:wlan5g"; + gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pin { + function = "blsp_spi0"; + pins = "gpio54", "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + pin_cs { + function = "gpio"; + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_spi1 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "0:SBL1"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition1@40000 { + label = "0:MIBIB"; + reg = <0x00040000 0x00020000>; + read-only; + }; + partition2@60000 { + label = "0:QSEE"; + reg = <0x00060000 0x00060000>; + read-only; + }; + partition3@c0000 { + label = "0:CDT"; + reg = <0x000c0000 0x00010000>; + read-only; + }; + partition4@d0000 { + label = "0:DDRPARAMS"; + reg = <0x000d0000 0x00010000>; + read-only; + }; + partition5@e0000 { + label = "0:APPSBLENV"; + reg = <0x000e0000 0x00010000>; + read-only; + }; + partition6@f0000 { + label = "0:APPSBL"; + reg = <0x000f0000 0x00090000>; + read-only; + }; + partition7@180000 { + label = "0:ART"; + reg = <0x00180000 0x00010000>; + read-only; + }; + partition8@190000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x190000 0x1dc0000>; + }; + partition9@1f50000 { + label = "u-boot-env"; + reg = <0x01f50000 0x00010000>; + }; + partition10@1f60000 { + label = "userconfig"; + reg = <0x01f60000 0x000a0000>; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&gmac0 { + vlan_tag = <1 0x31>; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "EnGenius-EAP1300"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "EnGenius-EAP1300"; +}; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi index 36555f000..636e42e8b 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi @@ -51,12 +51,6 @@ qcom,wifi_noc_memtype_m0_m2 = ; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - crypto@8e3a000 { status = "okay"; }; @@ -82,7 +76,7 @@ led-upgrade = &power_amber; }; - gpio-keys { + keys { compatible = "gpio-keys"; wps { @@ -117,7 +111,7 @@ }; }; - gpio-leds { + leds { compatible = "gpio-leds"; power_amber: power_amber { @@ -276,6 +270,7 @@ }; partition11@1b0000 { + compatible = "denx,fit"; label = "firmware"; reg = <0x001b0000 0x00e10000>; }; @@ -289,6 +284,12 @@ }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &blsp_dma { status = "okay"; }; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-fritz4040.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-fritz4040.dts index 4423e83ba..9576e14f2 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-fritz4040.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-fritz4040.dts @@ -1,18 +1,4 @@ -/* Copyright (c) 2015, 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT #include "qcom-ipq4019.dtsi" #include @@ -67,12 +53,6 @@ status = "okay"; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - usb3@8af8800 { status = "okay"; }; @@ -81,16 +61,6 @@ status = "okay"; }; - wifi@a000000 { - status = "okay"; - qcom,ath10k-calibration-variant = "AVM-FRITZBox-4040"; - }; - - wifi@a800000 { - status = "okay"; - qcom,ath10k-calibration-variant = "AVM-FRITZBox-4040"; - }; - watchdog@b017000 { status = "okay"; }; @@ -114,7 +84,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; wlan { @@ -130,7 +100,7 @@ }; }; - gpio-leds { + switch-leds { compatible = "gpio-leds"; wlan { @@ -207,7 +177,7 @@ status = "okay"; cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; - mx25l25635f@0 { + flash@0 { compatible = "jedec,spi-nor"; #address-cells = <1>; #size-cells = <0>; @@ -278,6 +248,7 @@ read-only; }; partition11@2A0000 { + compatible = "denx,fit"; label = "firmware"; reg = <0x002a0000 0x01c60000>; }; @@ -289,6 +260,12 @@ }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &usb3_ss_phy { status = "okay"; }; @@ -300,3 +277,13 @@ &usb2_hs_phy { status = "okay"; }; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "AVM-FRITZBox-4040"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "AVM-FRITZBox-4040"; +}; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts index 8e0e134e8..4e9a3f22c 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts @@ -70,12 +70,6 @@ status = "okay"; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - usb3: usb3@8af8800 { status = "okay"; }; @@ -225,6 +219,12 @@ }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &cryptobam { status = "okay"; }; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts index 4d366142a..8df3796da 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts @@ -1,18 +1,4 @@ -/* Copyright (c) 2015, 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT #include "qcom-ipq4019.dtsi" #include @@ -75,16 +61,35 @@ usb2@60f8800 { status = "okay"; - }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; + dwc3@6000000 { + #address-cells = <1>; + #size-cells = <0>; + + usb2_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; + }; }; usb3@8af8800 { status = "okay"; + + dwc3@8a00000 { + #address-cells = <1>; + #size-cells = <0>; + + usb3_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; + + usb3_port2: port@2 { + reg = <2>; + #trigger-source-cells = <0>; + }; + }; }; crypto@8e3a000 { @@ -104,7 +109,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; wlan { @@ -127,7 +132,7 @@ }; }; - gpio-leds { + leds { compatible = "gpio-leds"; pinctrl-0 = <&led_pins>; pinctrl-names = "default"; @@ -140,6 +145,8 @@ usb { label = "nbg6617:green:usb"; gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>; + trigger-sources = <&usb2_port1>, <&usb3_port1>, <&usb3_port2>; + linux,default-trigger = "usbport"; }; wlan2G { @@ -291,6 +298,12 @@ }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &cryptobam { status = "okay"; }; @@ -301,10 +314,12 @@ &wifi0 { status = "okay"; + qcom,ath10k-calibration-variant = "ZyXEL-NBG6617"; }; &wifi1 { status = "okay"; + qcom,ath10k-calibration-variant = "ZyXEL-NBG6617"; }; &usb3_ss_phy { diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts index 89b697dcb..0f6cd689c 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts @@ -1,18 +1,4 @@ -/* Copyright (c) 2015, 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT #include "qcom-ipq4019.dtsi" #include @@ -25,7 +11,7 @@ memory { device_type = "memory"; - reg = <0x80000000 0x10000000>; + reg = <0x80000000 0x8000000>; }; aliases { @@ -35,6 +21,10 @@ led-upgrade = &power; }; + chosen { + bootargs-append = " ubi.mtd=UBI_DEV"; + }; + soc { mdio@90000 { status = "okay"; @@ -70,16 +60,35 @@ usb2@60f8800 { status = "okay"; - }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; + dwc3@6000000 { + #address-cells = <1>; + #size-cells = <0>; + + usb2_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; + }; }; usb3@8af8800 { status = "okay"; + + dwc3@8a00000 { + #address-cells = <1>; + #size-cells = <0>; + + usb3_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; + + usb3_port2: port@2 { + reg = <2>; + #trigger-source-cells = <0>; + }; + }; }; crypto@8e3a000 { @@ -109,7 +118,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; reset { @@ -125,7 +134,7 @@ }; }; - gpio-leds { + leds { compatible = "gpio-leds"; power: status { @@ -151,6 +160,8 @@ usb { label = "rt-ac58u:blue:usb"; gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>; + trigger-sources = <&usb3_port1>, <&usb3_port2>, <&usb2_port1>; + linux,default-trigger = "usbport"; }; lan { @@ -202,7 +213,7 @@ cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>, <&tlmm 59 GPIO_ACTIVE_HIGH>; - m25p80@0 { + flash@0 { #address-cells = <1>; #size-cells = <0>; /* @@ -264,19 +275,25 @@ }; }; - mt29f@1 { + flash@1 { #address-cells = <1>; #size-cells = <0>; compatible = "spinand,mt29f"; reg = <1>; spi-max-frequency = <24000000>; + /* + * U-boot looks for "spinand,mt29f" node, + * if we don't have it, it will spit out the following warning: + * "ipq: fdt fixup unable to find compatible node". + */ + partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; - partition0@0 { + partition@0 { label = "ubi"; reg = <0x00000000 0x08000000>; }; @@ -284,6 +301,12 @@ }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &usb3_ss_phy { status = "okay"; }; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts index 996d64c12..81612bc50 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts @@ -62,12 +62,6 @@ qcom,wifi_noc_memtype_m0_m2 = ; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - crypto@8e3a000 { status = "okay"; }; @@ -86,7 +80,7 @@ }; }; - gpio-leds { + leds { compatible = "gpio-leds"; wps { @@ -120,7 +114,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; wps { @@ -157,6 +151,10 @@ }; }; +&blsp_dma { + status = "okay"; +}; + &blsp1_spi1 { pinctrl-0 = <&spi_0_pins>; pinctrl-names = "default"; @@ -222,6 +220,7 @@ }; partition8@180000 { + compatible = "denx,fit"; label = "firmware"; reg = <0x00180000 0x00ce0000>; }; @@ -241,7 +240,9 @@ }; }; -&blsp_dma { +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-a62.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-a62.dts index 8092e95e4..487b081c4 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-a62.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-a62.dts @@ -63,12 +63,6 @@ status = "okay"; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - crypto@8e3a000 { status = "okay"; }; @@ -89,7 +83,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; reset { @@ -106,7 +100,7 @@ led-upgrade = &power; }; - gpio-leds { + leds { compatible = "gpio-leds"; red { @@ -190,6 +184,12 @@ }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &cryptobam { status = "okay"; }; @@ -217,7 +217,7 @@ #size-cells = <2>; ranges; - wifi2: wifi@0,0 { + wifi2: wifi@1,0 { compatible = "qcom,ath10k"; status = "okay"; reg = <0x00010000 0 0 0 0>; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts new file mode 100644 index 000000000..ea39428b8 --- /dev/null +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/dts-v1/; + +#include "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "ASUS Lyra MAP-AC2200"; + compatible = "asus,map-ac2200"; + + aliases { + led-boot = &led_blue0; + led-failsafe = &led_red0; + led-running = &led_blue0; + led-upgrade = &led_red0; + }; + + soc { + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2@60f8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + reset { + label = "reset"; + gpios = <&tlmm 34 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&tlmm 18 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; + +&nand { + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + status = "okay"; + + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0 0x80000>; + read-only; + }; + + partition@80000 { + label = "MIBIB"; + reg = <0x80000 0x80000>; + read-only; + }; + + partition@100000 { + label = "QSEE"; + reg = <0x100000 0x100000>; + read-only; + }; + + partition@200000 { + label = "CDT"; + reg = <0x200000 0x80000>; + read-only; + }; + + partition@280000 { + label = "APPSBL"; + reg = <0x280000 0x140000>; + read-only; + }; + + partition@3c0000 { + label = "APPSBLENV"; + reg = <0x3c0000 0x40000>; + read-only; + }; + + partition@400000 { + label = "ubi"; + reg = <0x400000 0x7c00000>; + }; + }; + }; +}; + +&tlmm { + i2c_0_pins: i2c_0_pinmux { + pinmux { + function = "blsp_i2c0"; + pins = "gpio20", "gpio21"; + drive-strength = <16>; + bias-disable; + }; + }; + + serial_pins: serial_pinmux { + mux { + pins = "gpio16", "gpio17"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + nand_pins: nand_pins { + 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; + }; + }; +}; + +&cryptobam { + status = "okay"; +}; + +&blsp_dma { + status = "okay"; +}; + +&qpic_bam { + status = "okay"; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "ASUS-MAP-AC2200"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "ASUS-MAP-AC2200"; +}; + +&pcie0 { + status = "okay"; + perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>; + wake-gpio = <&tlmm 50 GPIO_ACTIVE_LOW>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi2: wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "ASUS-MAP-AC2200"; + }; + }; +}; + +&usb2_hs_phy { + /* Bluetooth module attached via USB */ + status = "okay"; +}; + +&blsp1_i2c3 { + pinctrl-0 = <&i2c_0_pins>; + pinctrl-names = "default"; + status = "okay"; + + led-controller@32 { + /* 9-channel RGB LED controller */ + compatible = "national,lp5523"; + reg = <0x32>; + clock-mode = [01]; + + led_blue0: blue0 { + chan-name = "blue0"; + label = "map-ac2200:blue:chan0"; + led-cur = [fa]; + max-cur = [ff]; + }; + + blue1 { + chan-name = "blue1"; + label = "map-ac2200:blue:chan1"; + led-cur = [fa]; + max-cur = [ff]; + }; + + blue2 { + chan-name = "blue2"; + label = "map-ac2200:blue:chan2"; + led-cur = [fa]; + max-cur = [ff]; + }; + + led_green0: green0 { + chan-name = "green0"; + label = "map-ac2200:green:chan0"; + led-cur = [fa]; + max-cur = [ff]; + }; + + green1 { + chan-name = "green1"; + label = "map-ac2200:green:chan1"; + led-cur = [fa]; + max-cur = [ff]; + }; + + green2 { + chan-name = "green2"; + label = "map-ac2200:green:chan2"; + led-cur = [fa]; + max-cur = [ff]; + }; + + led_red0: red0 { + chan-name = "red0"; + label = "map-ac2200:red:chan0"; + led-cur = [fa]; + max-cur = [ff]; + }; + + red1 { + chan-name = "red1"; + label = "map-ac2200:red:chan1"; + led-cur = [fa]; + max-cur = [ff]; + }; + + red2 { + chan-name = "red2"; + label = "map-ac2200:red:chan2"; + led-cur = [fa]; + max-cur = [ff]; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-rt-acrh17.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-rt-acrh17.dts index ba1022301..b7ebe8c9f 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-rt-acrh17.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-rt-acrh17.dts @@ -35,6 +35,10 @@ led-upgrade = &power; }; + chosen { + bootargs-append = " ubi.mtd=UBI_DEV"; + }; + soc { mdio@90000 { status = "okay"; @@ -72,12 +76,6 @@ status = "okay"; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - usb3@8af8800 { status = "okay"; }; @@ -234,6 +232,8 @@ status = "okay"; perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>; wake-gpio = <&tlmm 50 GPIO_ACTIVE_LOW>; + /* overwrite interrupts */ + interrupts = ; bridge@0,0 { reg = <0x00000000 0 0 0 0>; @@ -241,7 +241,7 @@ #size-cells = <2>; ranges; - wifi2: wifi@0,0 { + wifi2: wifi@1,0 { compatible = "qcom,ath10k"; status = "okay"; reg = <0x00010000 0 0 0 0>; @@ -254,6 +254,12 @@ qcom,ath10k-calibration-variant = "RT-ACRH17"; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &usb3_ss_phy { status = "okay"; }; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts index 36b3331e7..82e56d7ff 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts @@ -64,12 +64,6 @@ status = "okay"; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - usb3: usb3@8af8800 { status = "okay"; }; @@ -94,7 +88,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; reset { @@ -110,19 +104,17 @@ led-upgrade = &status; }; - gpio-leds { + leds { compatible = "gpio-leds"; status: rss4 { label = "wpj428:green:rss4"; gpios = <&tlmm 5 GPIO_ACTIVE_HIGH>; - default-state = "off"; }; rss3 { label = "wpj428:green:rss3"; gpios = <&tlmm 4 GPIO_ACTIVE_HIGH>; - default-state = "off"; }; }; @@ -221,6 +213,7 @@ read-only; }; partition6@180000 { + compatible = "denx,fit"; label = "firmware"; reg = <0x00180000 0x01e80000>; }; @@ -228,6 +221,12 @@ }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &cryptobam { status = "okay"; }; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts index 1d1a9680b..95a7c2b60 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts @@ -74,12 +74,6 @@ status = "okay"; }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - usb3@8af8800 { status = "okay"; }; @@ -103,7 +97,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; wps { @@ -119,7 +113,7 @@ }; }; - gpio-leds { + leds { compatible = "gpio-leds"; power: power { @@ -161,61 +155,74 @@ reg = <0>; spi-max-frequency = <24000000>; - SBL1@0 { - label = "SBL1"; - reg = <0x0 0x40000>; - read-only; - }; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; - MIBIB@40000 { - label = "MIBIB"; - reg = <0x40000 0x20000>; - read-only; - }; + SBL1@0 { + label = "SBL1"; + reg = <0x0 0x40000>; + read-only; + }; - QSEE@60000 { - label = "QSEE"; - reg = <0x60000 0x60000>; - read-only; - }; + MIBIB@40000 { + label = "MIBIB"; + reg = <0x40000 0x20000>; + read-only; + }; - CDT@c0000 { - label = "CDT"; - reg = <0xc0000 0x10000>; - read-only; - }; + QSEE@60000 { + label = "QSEE"; + reg = <0x60000 0x60000>; + read-only; + }; - DDRPARAMS@d0000 { - label = "DDRPARAMS"; - reg = <0xd0000 0x10000>; - read-only; - }; + CDT@c0000 { + label = "CDT"; + reg = <0xc0000 0x10000>; + read-only; + }; - APPSBLENV@e0000 { - label = "APPSBLENV"; - reg = <0xe0000 0x10000>; - read-only; - }; + DDRPARAMS@d0000 { + label = "DDRPARAMS"; + reg = <0xd0000 0x10000>; + read-only; + }; - APPSBL@f0000 { - label = "APPSBL"; - reg = <0xf0000 0x80000>; - read-only; - }; + APPSBLENV@e0000 { + label = "APPSBLENV"; + reg = <0xe0000 0x10000>; + read-only; + }; - ART@170000 { - label = "ART"; - reg = <0x170000 0x10000>; - read-only; - }; + APPSBL@f0000 { + label = "APPSBL"; + reg = <0xf0000 0x80000>; + read-only; + }; - firmware@180000 { - label = "firmware"; - reg = <0x180000 0x1e80000>; + ART@170000 { + label = "ART"; + reg = <0x170000 0x10000>; + read-only; + }; + + firmware@180000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x180000 0x1e80000>; + }; }; }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &tlmm { serial_pins: serial_pinmux { mux { diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-mr33.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-mr33.dts index a91634e62..fcc6410b8 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-mr33.dts +++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-mr33.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device Tree Source for Meraki MR33 (Stinkbug) * @@ -69,12 +70,6 @@ qcom,wifi_noc_memtype_m0_m2 = ; }; - serial@78af000 { - pinctrl-0 = <&serial_0_pins>; - pinctrl-names = "default"; - status = "okay"; - }; - serial@78b0000 { pinctrl-0 = <&serial_1_pins>; pinctrl-names = "default"; @@ -108,7 +103,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; reset { @@ -118,7 +113,7 @@ }; }; - gpio-leds { + leds { compatible = "gpio-leds"; power_orange: power { @@ -133,6 +128,12 @@ status = "okay"; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &cryptobam { status = "okay"; }; @@ -160,11 +161,11 @@ pinctrl-names = "default"; status = "okay"; - lp5562@30 { - enable-gpio = <&tlmm 48 GPIO_ACTIVE_HIGH>; + led-controller@30 { compatible = "ti,lp5562"; - clock-mode = /bits/8 <2>; reg = <0x30>; + clock-mode = /bits/8 <2>; + enable-gpio = <&tlmm 48 GPIO_ACTIVE_HIGH>; /* RGB led */ status_red: chan0 { @@ -278,7 +279,7 @@ #size-cells = <2>; ranges; - wifi2: wifi@0,0 { + wifi2: wifi@1,0 { compatible = "qcom,ath10k"; status = "okay"; reg = <0x00010000 0 0 0 0>; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-a42.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-a42.dts new file mode 100644 index 000000000..33c44a809 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-a42.dts @@ -0,0 +1,219 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, Sven Eckelmann + * + * 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 "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "OpenMesh A42"; + compatible = "openmesh,a42"; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@194b000 { + /* select hostmode */ + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2: usb2@60f8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 59 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + leds { + compatible = "gpio-leds"; + + red { + label = "a42:red:status"; + gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-off"; + }; + + power: green { + label = "a42:green:status"; + gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>; + }; + + blue { + label = "a42:blue:status"; + gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-off"; + }; + }; + + watchdog { + compatible = "linux,wdt-gpio"; + gpios = <&tlmm 5 GPIO_ACTIVE_LOW>; + hw_algo = "toggle"; + /* hw_margin_ms is actually 300s but driver limits it to 60s */ + hw_margin_ms = <60000>; + always-running; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pin { + function = "blsp_spi0"; + pins = "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + pin_cs { + function = "gpio"; + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_spi1 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + /* partitions are passed via bootloader */ + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&gmac0 { + qcom,phy_mdio_addr = <4>; + qcom,poll_required = <1>; + qcom,forced_speed = <1000>; + qcom,forced_duplex = <1>; + vlan_tag = <2 0x20>; +}; + +&gmac1 { + qcom,phy_mdio_addr = <3>; + qcom,poll_required = <1>; + qcom,forced_speed = <1000>; + qcom,forced_duplex = <1>; + vlan_tag = <1 0x10>; +}; + +&usb2_hs_phy { + status = "okay"; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "OM-A42"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "OM-A42"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts new file mode 100644 index 000000000..2f9a89048 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "Linksys EA6350v3"; + compatible = "linksys,ea6350v3"; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + tcsr@194b000 { + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2@60f8800 { + status = "okay"; + }; + + usb3@8af8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 63 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&tlmm 0 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + power: status { + label = "EA6350v3:green:status"; + gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "linksys-ea6350v3"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "linksys-ea6350v3"; +}; + + +&blsp_dma { + status = "okay"; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + mux { + function = "blsp_spi0"; + pins = "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + + mux_cs { + function = "gpio"; + pins = "gpio54", "gpio59"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&blsp1_spi1 { /* BLSP1 QUP1 */ + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>, + <&tlmm 59 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + SBL1@0 { + label = "SBL1"; + reg = <0x00000000 0x00040000>; + read-only; + }; + MBIB@40000 { + label = "MIBIB"; + reg = <0x00040000 0x00020000>; + read-only; + }; + QSEE@60000 { + label = "QSEE"; + reg = <0x00060000 0x00060000>; + read-only; + }; + CDT@c0000 { + label = "CDT"; + reg = <0x000c0000 0x00010000>; + read-only; + }; + APPSBLENV@d0000 { + label = "APPSBLENV"; + reg = <0x000d0000 0x00010000>; + read-only; + }; + APPSBL@e0000 { + label = "APPSBL"; /* uboot */ + reg = <0x000e0000 0x00080000>; + read-only; + }; + ART@160000 { + label = "ART"; + reg = <0x00160000 0x00010000>; + read-only; + }; + u_env@170000 { + label = "u_env"; + reg = <0x00170000 0x00020000>; + }; + s_env@190000 { + label = "s_env"; + reg = <0x00190000 0x00020000>; + }; + devinfo@1b0000 { + label = "devinfo"; + reg = <0x001b0000 0x00010000>; + }; + /* 0x001c0000 - 0x00200000 unused */ + }; + }; + + flash@1 { + status = "okay"; + compatible = "spi-nand"; + reg = <1>; + spi-max-frequency = <24000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + kernel@0 { + label = "kernel"; + reg = <0x00000000 0x02800000>; + }; + rootfs@300000 { + label = "rootfs"; + reg = <0x00300000 0x02500000>; + }; + alt_kernel@2800000 { + label = "alt_kernel"; + reg = <0x02800000 0x02800000>; + }; + alt_rootfs@2b00000 { + label = "alt_rootfs"; + reg = <0x02b00000 0x02500000>; + }; + sysdiag@5000000 { + label = "sysdiag"; + reg = <0x05000000 0x00100000>; + }; + syscfg@5100000 { + label = "syscfg"; + reg = <0x05100000 0x02F00000>; + }; + /* 0x00000000 - 0x08000000: 128 MiB */ + }; + }; +}; + +&usb3_ss_phy { + status = "okay"; +}; + +&usb3_hs_phy { + status = "okay"; +}; + +&usb2_hs_phy { + status = "okay"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts new file mode 100644 index 000000000..32fded4c0 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "EnGenius EAP1300"; + compatible = "engenius,eap1300"; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 18 GPIO_ACTIVE_HIGH>; + linux,code = ; + }; + }; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + leds { + compatible = "gpio-leds"; + + power: orange { + label = "eap1300:orange:power"; + gpios = <&tlmm 58 GPIO_ACTIVE_LOW>; + }; + + lan { + label = "eap1300:blue:lan"; + gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>; + }; + + mesh { + label = "eap1300:blue:mesh"; + gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>; + }; + + wlan2g { + label = "eap1300:blue:wlan2g"; + gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>; + }; + + wlan5g { + label = "eap1300:yellow:wlan5g"; + gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pin { + function = "blsp_spi0"; + pins = "gpio54", "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + pin_cs { + function = "gpio"; + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_spi1 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "0:SBL1"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition1@40000 { + label = "0:MIBIB"; + reg = <0x00040000 0x00020000>; + read-only; + }; + partition2@60000 { + label = "0:QSEE"; + reg = <0x00060000 0x00060000>; + read-only; + }; + partition3@c0000 { + label = "0:CDT"; + reg = <0x000c0000 0x00010000>; + read-only; + }; + partition4@d0000 { + label = "0:DDRPARAMS"; + reg = <0x000d0000 0x00010000>; + read-only; + }; + partition5@e0000 { + label = "0:APPSBLENV"; + reg = <0x000e0000 0x00010000>; + read-only; + }; + partition6@f0000 { + label = "0:APPSBL"; + reg = <0x000f0000 0x00090000>; + read-only; + }; + partition7@180000 { + label = "0:ART"; + reg = <0x00180000 0x00010000>; + read-only; + }; + partition8@190000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x190000 0x1dc0000>; + }; + partition9@1f50000 { + label = "u-boot-env"; + reg = <0x01f50000 0x00010000>; + }; + partition10@1f60000 { + label = "userconfig"; + reg = <0x01f60000 0x000a0000>; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&gmac0 { + vlan_tag = <2 0x20>; +}; + +&gmac1 { + vlan_tag = <1 0x10>; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "EnGenius-EAP1300"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "EnGenius-EAP1300"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ex6100v2.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ex6100v2.dts new file mode 100644 index 000000000..2b93dcbb9 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ex6100v2.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, David Bauer + * + * 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 "qcom-ipq4018-ex61x0v2.dtsi" +#include +#include + +/ { + model = "Netgear EX6100v2"; + compatible = "netgear,ex6100v2"; +}; + +&wifi0 { + qcom,ath10k-calibration-variant = "Netgear-EX6100v2"; +}; + +&wifi1 { + qcom,ath10k-calibration-variant = "Netgear-EX6100v2"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ex6150v2.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ex6150v2.dts new file mode 100644 index 000000000..f1c44c1ae --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ex6150v2.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, David Bauer + * + * 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 "qcom-ipq4018-ex61x0v2.dtsi" +#include +#include + +/ { + model = "Netgear EX6150v2"; + compatible = "netgear,ex6150v2"; +}; + +&wifi0 { + qcom,ath10k-calibration-variant = "Netgear-EX6150v2"; +}; + +&wifi1 { + qcom,ath10k-calibration-variant = "Netgear-EX6150v2"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi new file mode 100644 index 000000000..ca514e294 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi @@ -0,0 +1,311 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, David Bauer + * + * 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 "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "Netgear EX61X0v2"; + compatible = "netgear,ex61x0v2"; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + qcom,num_gmac = <1>; + }; + }; + + aliases { + led-boot = &power_amber; + led-failsafe = &power_amber; + led-running = &power_green; + led-upgrade = &power_amber; + }; + + keys { + compatible = "gpio-keys"; + + wps { + label = "wps"; + gpios = <&tlmm 0 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&tlmm 63 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + led_spi { + compatible = "spi-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + gpio-sck = <&tlmm 5 GPIO_ACTIVE_HIGH>; + gpio-mosi = <&tlmm 4 GPIO_ACTIVE_HIGH>; + num-chipselects = <0>; + + led_gpio: led_gpio@0 { + compatible = "fairchild,74hc595"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + registers-number = <1>; + spi-max-frequency = <1000000>; + }; + }; + + leds { + compatible = "gpio-leds"; + + power_amber: power_amber { + label = "ex61x0v2:amber:power"; + gpios = <&led_gpio 7 GPIO_ACTIVE_LOW>; + }; + + power_green: power_green { + label = "ex61x0v2:green:power"; + gpios = <&led_gpio 6 GPIO_ACTIVE_LOW>; + }; + + right { + label = "ex61x0v2:blue:right"; + gpios = <&led_gpio 5 GPIO_ACTIVE_LOW>; + }; + + left { + label = "ex61x0v2:blue:left"; + gpios = <&led_gpio 4 GPIO_ACTIVE_LOW>; + }; + + client_green { + label = "ex61x0v2:green:client"; + gpios = <&led_gpio 3 GPIO_ACTIVE_LOW>; + }; + + client_red { + label = "ex61x0v2:red:client"; + gpios = <&led_gpio 2 GPIO_ACTIVE_LOW>; + }; + + router_green { + label = "ex61x0v2:green:router"; + gpios = <&led_gpio 1 GPIO_ACTIVE_LOW>; + }; + + router_red { + label = "ex61x0v2:red:router"; + gpios = <&led_gpio 0 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "ex61x0v2:green:wps"; + gpios = <&tlmm 1 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pin { + function = "blsp_spi0"; + pins = "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + pin_cs { + function = "gpio"; + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&blsp1_spi1 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + mx25l12805d@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition0@0 { + label = "SBL1"; + reg = <0x00000000 0x00040000>; + read-only; + }; + + partition1@40000 { + label = "MIBIB"; + reg = <0x00040000 0x00020000>; + read-only; + }; + + partition2@60000 { + label = "QSEE"; + reg = <0x00060000 0x00060000>; + read-only; + }; + + partition3@c0000 { + label = "CDT"; + reg = <0x000c0000 0x00010000>; + read-only; + }; + + partition4@d0000 { + label = "DDRPARAMS"; + reg = <0x000d0000 0x00010000>; + read-only; + }; + + partition5@E0000 { + label = "APPSBLENV"; + reg = <0x000e0000 0x00010000>; + read-only; + }; + + partition6@F0000 { + label = "APPSBL"; + reg = <0x000f0000 0x00080000>; + read-only; + }; + + partition7@170000 { + label = "ART"; + reg = <0x00170000 0x00010000>; + read-only; + }; + + partition8@180000 { + label = "config"; + reg = <0x00180000 0x00010000>; + read-only; + }; + + partition9@190000 { + label = "pot"; + reg = <0x00190000 0x00010000>; + read-only; + }; + + partition10@1a0000 { + label = "dnidata"; + reg = <0x001a0000 0x00010000>; + read-only; + }; + + partition11@1b0000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x001b0000 0x00e10000>; + }; + + partition12@fc0000 { + label = "language"; + reg = <0x00fc0000 0x00040000>; + read-only; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&blsp_dma { + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&wifi0 { + status = "okay"; +}; + +&wifi1 { + status = "okay"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-fritz4040.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-fritz4040.dts new file mode 100644 index 000000000..f9508cc46 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-fritz4040.dts @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "AVM FRITZ!Box 4040"; + compatible = "avm,fritzbox-4040"; + + aliases { + led-boot = &power; + led-failsafe = &flash; + led-running = &power; + led-upgrade = &flash; + }; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + tcsr@194b000 { + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2@60f8800 { + status = "okay"; + }; + + usb3@8af8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + qca8075: ess-switch@c000000 { + status = "okay"; + + #gpio-cells = <2>; + gpio-controller; + + enable-usb-power { + gpio-hog; + line-name = "enable USB3 power"; + gpios = <7 GPIO_ACTIVE_HIGH>; + output-high; + }; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + wlan { + label = "wlan"; + gpios = <&tlmm 58 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&tlmm 63 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + switch-leds { + compatible = "gpio-leds"; + + wlan { + label = "fritz4040:green:wlan"; + gpios = <&qca8075 1 GPIO_ACTIVE_HIGH>; + }; + + panic: info_red { + label = "fritz4040:red:info"; + gpios = <&qca8075 3 GPIO_ACTIVE_HIGH>; + panic-indicator; + }; + + wan { + label = "fritz4040:green:wan"; + gpios = <&qca8075 5 GPIO_ACTIVE_HIGH>; + }; + + power: power { + label = "fritz4040:green:power"; + gpios = <&qca8075 11 GPIO_ACTIVE_HIGH>; + }; + + lan { + label = "fritz4040:green:lan"; + gpios = <&qca8075 13 GPIO_ACTIVE_HIGH>; + }; + + flash: info_amber { + label = "fritz4040:amber:info"; + gpios = <&qca8075 15 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + mux { + function = "blsp_spi0"; + pins = "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + + mux_cs { + function = "gpio"; + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&cryptobam { + status = "okay"; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_spi1 { /* BLSP1 QUP1 */ + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + status = "okay"; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition0@0 { + label = "SBL1"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition1@40000 { + label = "MIBIB"; + reg = <0x00040000 0x00020000>; + read-only; + }; + partition2@60000 { + label = "QSEE"; + reg = <0x00060000 0x00060000>; + read-only; + }; + partition3@c0000 { + label = "CDT"; + reg = <0x000c0000 0x00010000>; + read-only; + }; + partition4@d0000 { + label = "DDRPARAMS"; + reg = <0x000d0000 0x00010000>; + read-only; + }; + partition5@e0000 { + label = "APPSBLENV"; /* uboot env - empty */ + reg = <0x000e0000 0x00010000>; + read-only; + }; + partition6@f0000 { + label = "urlader"; /* APPSBL */ + reg = <0x000f0000 0x0002dc000>; + read-only; + }; + partition7@11dc00 { + /* make a backup of this partition! */ + label = "urlader_config"; + reg = <0x0011dc00 0x00002400>; + read-only; + }; + partition8@120000 { + label = "tffs1"; + reg = <0x00120000 0x00080000>; + read-only; + }; + partition9@1a0000 { + label = "tffs2"; + reg = <0x001a0000 0x00080000>; + read-only; + }; + partition10@220000 { + label = "uboot"; + reg = <0x00220000 0x00080000>; + read-only; + }; + partition11@2A0000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x002a0000 0x01c60000>; + }; + partition12@1f00000 { + label = "jffs2"; + reg = <0x01f00000 0x00100000>; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&usb3_ss_phy { + status = "okay"; +}; + +&usb3_hs_phy { + status = "okay"; +}; + +&usb2_hs_phy { + status = "okay"; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "AVM-FRITZBox-4040"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "AVM-FRITZBox-4040"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts new file mode 100644 index 000000000..9730f1027 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dts @@ -0,0 +1,266 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, Robert Marko + * + * 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 "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "8devices Jalapeno"; + compatible = "8dev,jalapeno"; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + pinctrl-0 = <&mdio_pins>; + pinctrl-names = "default"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + counter@4a1000 { + compatible = "qcom,qca-gcnt"; + reg = <0x4a1000 0x4>; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + tcsr@194b000 { + /* select hostmode */ + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + status = "okay"; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2: usb2@60f8800 { + status = "okay"; + }; + + usb3: usb3@8af8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + switch_lan_bmp = <0x10>; /* lan port bitmap */ + }; + + edma@c080000 { + status = "okay"; + }; + }; +}; + +&tlmm { + mdio_pins: mdio_pinmux { + pinmux_1 { + pins = "gpio53"; + function = "mdio"; + }; + pinmux_2 { + pins = "gpio52"; + function = "mdc"; + }; + pinconf { + pins = "gpio52", "gpio53"; + bias-pull-up; + }; + }; + + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pin { + function = "blsp_spi0"; + pins = "gpio55", "gpio56", "gpio57"; + drive-strength = <2>; + bias-disable; + }; + pin_cs { + function = "gpio"; + pins = "gpio54", "gpio59"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_spi1 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>, <&tlmm 59 GPIO_ACTIVE_HIGH>; + status = "okay"; + + m25p80@0 { + reg = <0>; + compatible = "jedec,spi-nor"; + spi-max-frequency = <24000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition0@0 { + label = "SBL1"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition1@40000 { + label = "MIBIB"; + reg = <0x00040000 0x00020000>; + read-only; + }; + partition2@60000 { + label = "QSEE"; + reg = <0x00060000 0x00060000>; + read-only; + }; + partition3@c0000 { + label = "CDT"; + reg = <0x000c0000 0x00010000>; + read-only; + }; + partition4@d0000 { + label = "DDRPARAMS"; + reg = <0x000d0000 0x00010000>; + read-only; + }; + partition5@e0000 { + label = "APPSBLENV"; /* uboot env*/ + reg = <0x000e0000 0x00010000>; + read-only; + }; + partition5@f0000 { + label = "APPSBL"; /* uboot */ + reg = <0x000f0000 0x00080000>; + read-only; + }; + partition5@170000 { + label = "ART"; + reg = <0x00170000 0x00010000>; + read-only; + }; + }; + }; + + spi-nand@1 { + status = "okay"; + compatible = "spi-nand"; + reg = <1>; + spi-max-frequency = <24000000>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition0@0 { + label = "ubi"; + reg = <0x00000000 0x08000000>; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&gmac0 { + qcom,poll_required = <1>; + qcom,poll_required_dynamic = <1>; + qcom,phy_mdio_addr = <3>; + vlan_tag = <1 0x10>; +}; + +&gmac1 { + qcom,poll_required = <1>; + qcom,poll_required_dynamic = <1>; + qcom,phy_mdio_addr = <4>; + vlan_tag = <2 0x20>; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "8devices-Jalapeno"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "8devices-Jalapeno"; +}; + +&usb3_ss_phy { + status = "okay"; +}; + +&usb3_hs_phy { + status = "okay"; +}; + +&usb2_hs_phy { + status = "okay"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts new file mode 100644 index 000000000..a8c144f92 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq4019.dtsi" +#include +#include +#include +#include + +/ { + model = "ZyXEL NBG6617"; + compatible = "zyxel,nbg6617"; + + chosen { + /* + * the vendor u-boot adds root and mtdparts cmdline parameters + * which we don't want... but we have to overwrite them or else + * the kernel will take them at face value. + */ + bootargs-append = " mtdparts= root=31:13"; + }; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + tcsr@194b000 { + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2@60f8800 { + status = "okay"; + + dwc3@6000000 { + #address-cells = <1>; + #size-cells = <0>; + + usb2_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; + }; + }; + + usb3@8af8800 { + status = "okay"; + + dwc3@8a00000 { + #address-cells = <1>; + #size-cells = <0>; + + usb3_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; + + usb3_port2: port@2 { + reg = <2>; + #trigger-source-cells = <0>; + }; + }; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + wlan { + label = "wlan"; + gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>; + linux,code = ; + linux,input-type = ; + }; + + wps { + label = "wps"; + gpios = <&tlmm 63 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&tlmm 4 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + power: power { + label = "nbg6617:green:power"; + gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>; + }; + + usb { + label = "nbg6617:green:usb"; + gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>; + trigger-sources = <&usb2_port1>, <&usb3_port1>, <&usb3_port2>; + linux,default-trigger = "usbport"; + }; + + wlan2G { + label = "nbg6617:green:wlan2G"; + gpios = <&tlmm 58 GPIO_ACTIVE_HIGH>; + }; + + wlan5G { + label = "nbg6617:green:wlan5G"; + gpios = <&tlmm 5 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "nbg6617:green:wps"; + gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + spi_0_pins: spi_0_pinmux { + mux { + function = "blsp_spi0"; + pins = "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + + mux_cs { + function = "gpio"; + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + led_pins: led_pinmux { + mux { + pins = "gpio0", "gpio1", "gpio3", "gpio5", "gpio58"; + drive-strength = <0x8>; + bias-disable; + output-low; + }; + }; +}; + +&blsp1_spi1 { /* BLSP1 QUP1 */ + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + mx25l25635f@0 { + compatible = "mx25l25635f", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + status = "okay"; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition0@0 { + label = "SBL1"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition1@40000 { + label = "MIBIB"; + reg = <0x00040000 0x00020000>; + read-only; + }; + partition2@60000 { + label = "QSEE"; + reg = <0x00060000 0x00060000>; + read-only; + }; + partition3@c0000 { + label = "CDT"; + reg = <0x000c0000 0x00010000>; + read-only; + }; + partition4@d0000 { + label = "DDRPARAMS"; + reg = <0x000d0000 0x00010000>; + read-only; + }; + partition5@e0000 { + label = "APPSBL"; /* u-boot */ + reg = <0x000e0000 0x00080000>; + /* U-Boot Standalone App "zloader" is located at 0x64000 */ + read-only; + }; + partition6@160000 { + label = "APPSBLENV"; /* u-boot env */ + reg = <0x00160000 0x00010000>; + }; + partition7@170000 { + /* make a backup of this partition! */ + label = "ART"; + reg = <0x00170000 0x00010000>; + read-only; + }; + partition8@180000 { + label = "kernel"; + reg = <0x00180000 0x00400000>; + }; + partition9@580000 { + label = "dualflag"; + reg = <0x00580000 0x00010000>; + read-only; + }; + partition10@590000 { + label = "header"; + reg = <0x00590000 0x00010000>; + }; + partition11@5a0000 { + label = "romd"; + reg = <0x005a0000 0x00100000>; + read-only; + }; + partition12@6a0000 { + label = "not_root_data"; + /* + * for some strange reason, someone at ZyXEL + * had the "great" idea to put the rootfs_data + * in front of rootfs... Don't do that! + * As a result this one, full MebiByte remains + * unused. + */ + reg = <0x006a0000 0x00100000>; + }; + partition13@7a0000 { + label = "rootfs"; + reg = <0x007a0000 0x01860000>; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&blsp_dma { + status = "okay"; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "ZyXEL-NBG6617"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "ZyXEL-NBG6617"; +}; + +&usb3_ss_phy { + status = "okay"; +}; + +&usb3_hs_phy { + status = "okay"; +}; + +&usb2_hs_phy { + status = "okay"; +}; diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-rt-ac1300uhp.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts similarity index 72% rename from target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-rt-ac1300uhp.dts rename to target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts index 2ead521e6..26c086ed2 100644 --- a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-rt-ac1300uhp.dts +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts @@ -1,18 +1,4 @@ -/* Copyright (c) 2015, 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT #include "qcom-ipq4019.dtsi" #include @@ -20,12 +6,12 @@ #include / { - model = "ASUS RT-AC1300UHP"; - compatible = "asus,rt-ac1300uhp", "qcom,ipq4019"; + model = "ASUS RT-AC58U"; + compatible = "asus,rt-ac58u"; memory { device_type = "memory"; - reg = <0x80000000 0x10000000>; + reg = <0x80000000 0x8000000>; }; aliases { @@ -35,7 +21,15 @@ led-upgrade = &power; }; + chosen { + bootargs-append = " ubi.mtd=UBI_DEV"; + }; + soc { + rng@22000 { + status = "okay"; + }; + mdio@90000 { status = "okay"; }; @@ -70,32 +64,41 @@ usb2@60f8800 { status = "okay"; - }; - serial@78af000 { - pinctrl-0 = <&serial_pins>; - pinctrl-names = "default"; - status = "okay"; + dwc3@6000000 { + #address-cells = <1>; + #size-cells = <0>; + + usb2_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; + }; }; usb3@8af8800 { status = "okay"; + + dwc3@8a00000 { + #address-cells = <1>; + #size-cells = <0>; + + usb3_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; + + usb3_port2: port@2 { + reg = <2>; + #trigger-source-cells = <0>; + }; + }; }; crypto@8e3a000 { status = "okay"; }; - wifi@a000000 { - status = "okay"; - qcom,ath10k-calibration-variant = "RT-AC58U"; - }; - - wifi@a800000 { - status = "okay"; - qcom,ath10k-calibration-variant = "RT-AC58U"; - }; - watchdog@b017000 { status = "okay"; }; @@ -109,7 +112,7 @@ }; }; - gpio-keys { + keys { compatible = "gpio-keys"; reset { @@ -125,7 +128,7 @@ }; }; - gpio-leds { + leds { compatible = "gpio-leds"; power: status { @@ -151,6 +154,8 @@ usb { label = "rt-ac58u:blue:usb"; gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>; + trigger-sources = <&usb3_port1>, <&usb3_port2>, <&usb2_port1>; + linux,default-trigger = "usbport"; }; lan { @@ -202,9 +207,7 @@ cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>, <&tlmm 59 GPIO_ACTIVE_HIGH>; - m25p80@0 { - #address-cells = <1>; - #size-cells = <0>; + flash@0 { /* * U-boot looks for "n25q128a11" node, * if we don't have it, it will spit out the following warning: @@ -220,42 +223,42 @@ #address-cells = <1>; #size-cells = <1>; - partition0@0 { + partition@0 { label = "SBL1"; reg = <0x00000000 0x00040000>; read-only; }; - partition1@40000 { + partition@40000 { label = "MIBIB"; reg = <0x00040000 0x00020000>; read-only; }; - partition2@60000 { + partition@60000 { label = "QSEE"; reg = <0x00060000 0x00060000>; read-only; }; - partition3@c0000 { + partition@c0000 { label = "CDT"; reg = <0x000c0000 0x00010000>; read-only; }; - partition4@d0000 { + partition@d0000 { label = "DDRPARAMS"; reg = <0x000d0000 0x00010000>; read-only; }; - partition5@e0000 { + partition@e0000 { label = "APPSBLENV"; /* uboot env*/ reg = <0x000e0000 0x00010000>; read-only; }; - partition5@f0000 { + partition@f0000 { label = "APPSBL"; /* uboot */ reg = <0x000f0000 0x00080000>; read-only; }; - partition5@170000 { + partition@170000 { label = "ART"; reg = <0x00170000 0x00010000>; read-only; @@ -264,26 +267,41 @@ }; }; - mt29f@1 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "spinand,mt29f"; + spi-nand@1 { + compatible = "spi-nand"; reg = <1>; spi-max-frequency = <24000000>; + /* + * U-boot looks for "spinand,mt29f" node, + * if we don't have it, it will spit out the following warning: + * "ipq: fdt fixup unable to find compatible node". + */ + partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; - partition0@0 { - label = "ubi"; + partition@0 { + /* + * TODO: change to label = "ubi" once we drop 4.14. + * also drop the bootargs-append and all the + * userspace CI_UBIPART="UBI_DEV" remains. + */ + label = "UBI_DEV"; reg = <0x00000000 0x08000000>; }; }; }; }; +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &usb3_ss_phy { status = "okay"; }; @@ -295,3 +313,13 @@ &usb2_hs_phy { status = "okay"; }; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "RT-AC58U"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "RT-AC58U"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts new file mode 100644 index 000000000..5932638da --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts @@ -0,0 +1,265 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, David Bauer + * + * 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 "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "ZyXEL WRE6606"; + compatible = "zyxel,wre6606"; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + chosen { + bootargs-append = " mtdparts="; + }; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + qcom,num_gmac = <1>; + }; + }; + + leds { + compatible = "gpio-leds"; + + wps { + label = "wre6606:green:wps"; + gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>; + }; + + wlan5g_green { + label = "wre6606:green:wlan5g"; + gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>; + }; + + power: power { + label = "wre6606:green:power"; + gpios = <&tlmm 4 GPIO_ACTIVE_HIGH>; + }; + + wlan5g_red { + label = "wre6606:red:wlan5g"; + gpios = <&tlmm 5 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_red { + label = "wre6606:red:wlan2g"; + gpios = <&tlmm 58 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_green { + label = "wre6606:green:wlan2g"; + gpios = <&tlmm 59 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + + wps { + label = "wps"; + gpios = <&tlmm 63 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pin { + function = "blsp_spi0"; + pins = "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + pin_cs { + function = "gpio"; + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_spi1 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + mx25l12805d@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition0@0 { + label = "SBL1"; + reg = <0x00000000 0x00040000>; + read-only; + }; + + partition1@40000 { + label = "MIBIB"; + reg = <0x00040000 0x00020000>; + read-only; + }; + + partition2@60000 { + label = "QSEE"; + reg = <0x00060000 0x00060000>; + read-only; + }; + + partition3@c0000 { + label = "CDT"; + reg = <0x000c0000 0x00010000>; + read-only; + }; + + partition4@d0000 { + label = "DDRPARAMS"; + reg = <0x000d0000 0x00010000>; + read-only; + }; + + partition5@E0000 { + label = "APPSBLENV"; + reg = <0x000e0000 0x00010000>; + read-only; + }; + + partition6@F0000 { + label = "APPSBL"; + reg = <0x000f0000 0x00080000>; + read-only; + }; + + partition7@170000 { + label = "ART"; + reg = <0x00170000 0x00010000>; + read-only; + }; + + partition8@180000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x00180000 0x00ce0000>; + }; + + partition9@e60000 { + label = "manufacture"; + reg = <0x00e60000 0x00050000>; + read-only; + }; + + partition10@eb0000 { + label = "storage"; + reg = <0x00eb0000 0x00150000>; + read-only; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "ZyXEL-WRE6606"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "ZyXEL-WRE6606"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-a62.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-a62.dts new file mode 100644 index 000000000..25bbd6b33 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-a62.dts @@ -0,0 +1,243 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, Sven Eckelmann + * + * 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 "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "OpenMesh A62"; + compatible = "openmesh,a62"; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@194b000 { + /* select hostmode */ + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2: usb2@60f8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + switch_lan_bmp = <0x10>; + switch_wan_bmp = <0x20>; + + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 18 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + leds { + compatible = "gpio-leds"; + + red { + label = "a62:red:status"; + gpios = <&tlmm 43 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-off"; + }; + + power: green { + label = "a62:green:status"; + gpios = <&tlmm 45 GPIO_ACTIVE_HIGH>; + }; + + blue { + label = "a62:blue:status"; + gpios = <&tlmm 46 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-off"; + }; + }; + + watchdog { + compatible = "linux,wdt-gpio"; + gpios = <&tlmm 59 GPIO_ACTIVE_LOW>; + hw_algo = "toggle"; + /* hw_margin_ms is actually 300s but driver limits it to 60s */ + hw_margin_ms = <60000>; + always-running; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio16", "gpio17"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pin { + function = "blsp_spi0"; + pins = "gpio13", "gpio14", "gpio15"; + drive-strength = <12>; + bias-disable; + }; + pin_cs { + function = "gpio"; + pins = "gpio12"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + enable-usb-power { + gpio-hog; + gpios = <58 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "enable USB2 power"; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_spi1 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + /* partitions are passed via bootloader */ + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&gmac0 { + qcom,phy_mdio_addr = <3>; + qcom,poll_required = <1>; + qcom,forced_speed = <1000>; + qcom,forced_duplex = <1>; + vlan_tag = <1 0x10>; +}; + +&usb2_hs_phy { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>; + wake-gpio = <&tlmm 50 GPIO_ACTIVE_LOW>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi2: wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "OM-A62"; + ieee80211-freq-limit = <5170000 5350000>; + }; + }; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "OM-A62"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "OM-A62"; + ieee80211-freq-limit = <5470000 5875000>; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-ap.dk04.1-c1.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-ap.dk04.1-c1.dts new file mode 100644 index 000000000..47202d28f --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-ap.dk04.1-c1.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2015, 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 "qcom-ipq4019-ap.dk04.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. IPQ40xx/AP-DK04.1-C1"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-ap.dk04.1.dtsi b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-ap.dk04.1.dtsi new file mode 100644 index 000000000..980135462 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-ap.dk04.1.dtsi @@ -0,0 +1,181 @@ +/* Copyright (c) 2015, 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 "qcom-ipq4019.dtsi" +#include + +/ { + model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK04.1"; + compatible = "qcom,ipq4019"; + + soc { + rng@22000 { + status = "okay"; + }; + + pinctrl@1000000 { + serial_0_pins: serial_pinmux { + mux { + pins = "gpio16", "gpio17"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + serial_1_pins: serial1_pinmux { + mux { + pins = "gpio8", "gpio9"; + function = "blsp_uart1"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pinmux { + function = "blsp_spi0"; + pins = "gpio13", "gpio14", "gpio15"; + }; + 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 { + pinmux { + function = "blsp_i2c0"; + pins = "gpio10", "gpio11"; + }; + pinconf { + pins = "gpio10", "gpio11"; + drive-strength = <16>; + bias-disable; + }; + }; + + nand_pins: nand_pins { + + 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; + }; + }; + }; + + blsp_dma: dma@7884000 { + status = "okay"; + }; + + spi0: spi@78b5000 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>; + + mx25l25635e@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; + compatible = "mx25l25635e"; + spi-max-frequency = <24000000>; + }; + }; + + i2c0: i2c@78b7000 { /* BLSP1 QUP2 */ + pinctrl-0 = <&i2c_0_pins>; + pinctrl-names = "default"; + + status = "okay"; + }; + + serial@78af000 { + pinctrl-0 = <&serial_0_pins>; + pinctrl-names = "default"; + status = "okay"; + }; + + serial@78b0000 { + pinctrl-0 = <&serial_1_pins>; + pinctrl-names = "default"; + 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"; + }; + + cryptobam: dma@8e04000 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + qpic_bam: dma@7984000 { + status = "okay"; + }; + + nand: qpic-nand@79b0000 { + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + status = "okay"; + }; + }; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts new file mode 100644 index 000000000..7f6aa51bf --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/dts-v1/; + +#include "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "ASUS Lyra MAP-AC2200"; + compatible = "asus,map-ac2200"; + + aliases { + led-boot = &led_blue0; + led-failsafe = &led_red0; + led-running = &led_blue0; + led-upgrade = &led_red0; + }; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2@60f8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 34 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&tlmm 18 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; + +&nand { + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + status = "okay"; + + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0 0x80000>; + read-only; + }; + + partition@80000 { + label = "MIBIB"; + reg = <0x80000 0x80000>; + read-only; + }; + + partition@100000 { + label = "QSEE"; + reg = <0x100000 0x100000>; + read-only; + }; + + partition@200000 { + label = "CDT"; + reg = <0x200000 0x80000>; + read-only; + }; + + partition@280000 { + label = "APPSBL"; + reg = <0x280000 0x140000>; + read-only; + }; + + partition@3c0000 { + label = "APPSBLENV"; + reg = <0x3c0000 0x40000>; + read-only; + }; + + partition@400000 { + label = "ubi"; + reg = <0x400000 0x7c00000>; + }; + }; + }; +}; + +&tlmm { + i2c_0_pins: i2c_0_pinmux { + pinmux { + function = "blsp_i2c0"; + pins = "gpio20", "gpio21"; + drive-strength = <16>; + bias-disable; + }; + }; + + serial_pins: serial_pinmux { + mux { + pins = "gpio16", "gpio17"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + nand_pins: nand_pins { + 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; + }; + }; +}; + +&cryptobam { + status = "okay"; +}; + +&blsp_dma { + status = "okay"; +}; + +&qpic_bam { + status = "okay"; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "ASUS-MAP-AC2200"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "ASUS-MAP-AC2200"; +}; + +&pcie0 { + status = "okay"; + perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>; + wake-gpio = <&tlmm 50 GPIO_ACTIVE_LOW>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi2: wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "ASUS-MAP-AC2200"; + }; + }; +}; + +&usb2_hs_phy { + /* Bluetooth module attached via USB */ + status = "okay"; +}; + +&blsp1_i2c3 { + pinctrl-0 = <&i2c_0_pins>; + pinctrl-names = "default"; + status = "okay"; + + led-controller@32 { + /* 9-channel RGB LED controller */ + compatible = "national,lp5523"; + reg = <0x32>; + clock-mode = [01]; + + led_blue0: blue0 { + chan-name = "blue0"; + label = "map-ac2200:blue:chan0"; + led-cur = [fa]; + max-cur = [ff]; + }; + + blue1 { + chan-name = "blue1"; + label = "map-ac2200:blue:chan1"; + led-cur = [fa]; + max-cur = [ff]; + }; + + blue2 { + chan-name = "blue2"; + label = "map-ac2200:blue:chan2"; + led-cur = [fa]; + max-cur = [ff]; + }; + + led_green0: green0 { + chan-name = "green0"; + label = "map-ac2200:green:chan0"; + led-cur = [fa]; + max-cur = [ff]; + }; + + green1 { + chan-name = "green1"; + label = "map-ac2200:green:chan1"; + led-cur = [fa]; + max-cur = [ff]; + }; + + green2 { + chan-name = "green2"; + label = "map-ac2200:green:chan2"; + led-cur = [fa]; + max-cur = [ff]; + }; + + led_red0: red0 { + chan-name = "red0"; + label = "map-ac2200:red:chan0"; + led-cur = [fa]; + max-cur = [ff]; + }; + + red1 { + chan-name = "red1"; + label = "map-ac2200:red:chan1"; + led-cur = [fa]; + max-cur = [ff]; + }; + + red2 { + chan-name = "red2"; + label = "map-ac2200:red:chan2"; + led-cur = [fa]; + max-cur = [ff]; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-rt-acrh17.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-rt-acrh17.dts new file mode 100644 index 000000000..6eb56e23f --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4019-rt-acrh17.dts @@ -0,0 +1,277 @@ +/* Copyright (c) 2015, 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 "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "ASUS RT-ACRH17"; + compatible = "asus,rt-acrh17"; + + memory { + device_type = "memory"; + reg = <0x80000000 0x10000000>; + }; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + chosen { + bootargs-append = " ubi.mtd=UBI_DEV"; + }; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + tcsr@194b000 { + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2@60f8800 { + status = "okay"; + }; + + usb3@8af8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 18 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&tlmm 11 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + power: status { + label = "rt-acrh17:blue:status"; + gpios = <&tlmm 40 GPIO_ACTIVE_LOW>; + }; + + lan1 { + label = "rt-acrh17:blue:lan1"; + gpios = <&tlmm 45 GPIO_ACTIVE_LOW>; + }; + + lan2 { + label = "rt-acrh17:blue:lan2"; + gpios = <&tlmm 43 GPIO_ACTIVE_LOW>; + }; + + lan3 { + label = "rt-acrh17:blue:lan3"; + gpios = <&tlmm 42 GPIO_ACTIVE_LOW>; + }; + + lan4 { + label = "rt-acrh17:blue:lan4"; + gpios = <&tlmm 49 GPIO_ACTIVE_LOW>; + }; + + wan_blue { + label = "rt-acrh17:blue:wan"; + gpios = <&tlmm 61 GPIO_ACTIVE_HIGH>; + }; + + wan_red { + label = "rt-acrh17:red:wan"; + gpios = <&tlmm 68 GPIO_ACTIVE_HIGH>; + }; + + wlan2g { + label = "rt-acrh17:blue:wlan2g"; + gpios = <&tlmm 52 GPIO_ACTIVE_LOW>; + }; + + wlan5g { + label = "rt-acrh17:blue:wlan5g"; + gpios = <&tlmm 54 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&cryptobam { + status = "okay"; +}; + +&blsp_dma { + status = "okay"; +}; + +&qpic_bam { + status = "okay"; +}; + +&nand { + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + status = "okay"; + + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "Bootloader"; + reg = <0x000000000000 0x000000400000>; + read-only; + }; + partition@400000 { + label = "UBI_DEV"; + reg = <0x000000400000 0x000007C00000>; + }; + }; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio16", "gpio17"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + nand_pins: nand_pins { + pullups { + pins = "gpio53", "gpio58", + "gpio59"; + function = "qpic"; + bias-pull-up; + }; + + pulldowns { + pins = "gpio55", "gpio56", + "gpio57", "gpio60", + "gpio62", "gpio63", "gpio64", + "gpio65", "gpio66", "gpio67", + "gpio69"; + function = "qpic"; + bias-pull-down; + }; + }; +}; + +&pcie0 { + status = "okay"; + perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>; + wake-gpio = <&tlmm 50 GPIO_ACTIVE_LOW>; + /* overwrite interrupts */ + interrupts = ; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi2: wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + }; + }; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "RT-ACRH17"; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&usb3_ss_phy { + status = "okay"; +}; + +&usb3_hs_phy { + status = "okay"; +}; + +&usb2_hs_phy { + status = "okay"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts new file mode 100644 index 000000000..cf8540c10 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts @@ -0,0 +1,270 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, Christian Mehlis + * Copyright (c) 2017-2018, Sven Eckelmann + * + * 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 "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "Compex WPJ428"; + compatible = "compex,wpj428"; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@194b000 { + /* select hostmode */ + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2: usb2@60f8800 { + status = "okay"; + }; + + usb3: usb3@8af8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + switch_lan_bmp = <0x10>; + switch_wan_bmp = <0x20>; + + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 63 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + aliases { + led-boot = &status; + led-failsafe = &status; + led-upgrade = &status; + }; + + leds { + compatible = "gpio-leds"; + + status: rss4 { + label = "wpj428:green:rss4"; + gpios = <&tlmm 5 GPIO_ACTIVE_HIGH>; + }; + + rss3 { + label = "wpj428:green:rss3"; + gpios = <&tlmm 4 GPIO_ACTIVE_HIGH>; + }; + }; + + beeper: beeper { + compatible = "gpio-beeper"; + gpios = <&tlmm 58 GPIO_ACTIVE_HIGH>; + }; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pin { + function = "blsp_spi0"; + pins = "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + pin_cs { + function = "gpio"; + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_spi1 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition0@0 { + label = "0:SBL1"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition1@40000 { + label = "0:MIBIB"; + reg = <0x00040000 0x00020000>; + read-only; + }; + partition2@60000 { + label = "0:QSEE"; + reg = <0x00060000 0x00060000>; + read-only; + }; + partition3@c0000 { + label = "0:CDT"; + reg = <0x000c0000 0x00010000>; + read-only; + }; + partition4@d0000 { + label = "0:DDRPARAMS"; + reg = <0x000d0000 0x00010000>; + read-only; + }; + partition5@e0000 { + label = "0:APPSBLENV"; /* uboot env*/ + reg = <0x000e0000 0x00010000>; + read-only; + }; + partition5@f0000 { + label = "0:APPSBL"; /* uboot */ + reg = <0x000f0000 0x00080000>; + read-only; + }; + partition5@170000 { + label = "0:ART"; + reg = <0x00170000 0x00010000>; + read-only; + }; + partition6@180000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x00180000 0x01e80000>; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&gmac0 { + qcom,phy_mdio_addr = <4>; + qcom,poll_required = <1>; + qcom,forced_speed = <1000>; + qcom,forced_duplex = <1>; + vlan_tag = <2 0x20>; +}; + +&gmac1 { + qcom,phy_mdio_addr = <3>; + qcom,poll_required = <1>; + qcom,forced_speed = <1000>; + qcom,forced_duplex = <1>; + vlan_tag = <1 0x10>; +}; + +&usb3_ss_phy { + status = "okay"; +}; + +&usb3_hs_phy { + status = "okay"; +}; + +&usb2_hs_phy { + status = "okay"; +}; + +&wifi0 { + status = "okay"; +}; + +&wifi1 { + status = "okay"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts new file mode 100644 index 000000000..b32eb29f8 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts @@ -0,0 +1,280 @@ +/* Copyright (c) 2015, 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 "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "GL.iNet GL-B1300"; + compatible = "glinet,gl-b1300"; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x10000000>; + }; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + tcsr@194b000 { + /* select hostmode */ + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + status = "okay"; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2@60f8800 { + status = "okay"; + }; + + usb3@8af8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + switch_lan_bmp = <0x18>; + switch_wan_bmp = <0x20>; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + wps { + label = "wps"; + gpios = <&tlmm 5 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&tlmm 63 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + power: power { + label = "gl-b1300:green:power"; + gpios = <&tlmm 4 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + mesh { + label = "gl-b1300:green:mesh"; + gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>; + }; + + wlan { + label = "gl-b1300:green:wlan"; + gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&blsp1_spi1 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + mx25l25635f@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <24000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + 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; + }; + + firmware@180000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x180000 0x1e80000>; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&tlmm { + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + spi_0_pins: spi_0_pinmux { + pinmux { + function = "blsp_spi0"; + pins = "gpio55", "gpio56", "gpio57"; + }; + pinmux_cs { + function = "gpio"; + pins = "gpio54"; + }; + pinconf { + pins = "gpio55", "gpio56", "gpio57"; + drive-strength = <12>; + bias-disable; + }; + pinconf_cs { + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; +}; + +&usb2_hs_phy { + status = "okay"; +}; + +&usb3_hs_phy { + status = "okay"; +}; + +&usb3_ss_phy { + status = "okay"; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "GL-B1300"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "GL-B1300"; +}; diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4029-mr33.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4029-mr33.dts new file mode 100644 index 000000000..500357242 --- /dev/null +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4029-mr33.dts @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for Meraki MR33 (Stinkbug) + * + * Copyright (C) 2017 Chris Blake + * Copyright (C) 2017 Christian Lamparter + * + * Based on Cisco Meraki DTS from GPL release r25-linux-3.14-20170427 + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +#include "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + model = "Meraki MR33 Access Point"; + compatible = "meraki,mr33"; + + aliases { + led-boot = &status_green; + led-failsafe = &status_red; + led-running = &status_green; + led-upgrade = &power_orange; + }; + + /* Do we really need this defined? */ + memory { + device_type = "memory"; + reg = <0x80000000 0x10000000>; + }; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + pinctrl-0 = <&mdio_pins>; + pinctrl-names = "default"; + }; + + /* It is a 56-bit counter that supplies the count to the ARM arch + timers and without upstream driver */ + counter@4a1000 { + compatible = "qcom,qca-gcnt"; + reg = <0x4a1000 0x4>; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + serial@78b0000 { + pinctrl-0 = <&serial_1_pins>; + pinctrl-names = "default"; + status = "okay"; + + bluetooth { + compatible = "ti,cc2650"; + enable-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + }; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + switch_mac_mode = <0x3>; /* mac mode for RGMII RMII */ + switch_lan_bmp = <0x0>; /* lan port bitmap */ + switch_wan_bmp = <0x10>; /* wan port bitmap */ + }; + + edma@c080000 { + qcom,single-phy; + qcom,num_gmac = <1>; + phy-mode = "rgmii-rxid"; + status = "okay"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 18 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + power_orange: power { + label = "mr33:orange:power"; + gpios = <&tlmm 49 GPIO_ACTIVE_LOW>; + panic-indicator; + }; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&gmac0 { + qcom,phy_mdio_addr = <1>; + qcom,poll_required = <1>; + vlan_tag = <0 0x20>; +}; + +&blsp1_i2c3 { + pinctrl-0 = <&i2c_0_pins>; + pinctrl-names = "default"; + status = "okay"; + at24@50 { + compatible = "atmel,24c64"; + pagesize = <32>; + reg = <0x50>; + read-only; /* This holds our MAC & Meraki board-data */ + }; +}; + +&blsp1_i2c4 { + pinctrl-0 = <&i2c_1_pins>; + pinctrl-names = "default"; + status = "okay"; + + led-controller@30 { + compatible = "ti,lp5562"; + reg = <0x30>; + clock-mode = /bits/8 <2>; + enable-gpio = <&tlmm 48 GPIO_ACTIVE_HIGH>; + + /* RGB led */ + status_red: chan0 { + chan-name = "mr33:red:status"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + + status_green: chan1 { + chan-name = "mr33:green:status"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + + chan2 { + chan-name = "mr33:blue:status"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + + chan3 { + chan-name = "mr33:white:status"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + }; +}; + +&nand { + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + status = "okay"; + + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "sbl1"; + reg = <0x00000000 0x00100000>; + read-only; + }; + partition@100000 { + label = "mibib"; + reg = <0x00100000 0x00100000>; + read-only; + }; + partition@200000 { + label = "bootconfig"; + reg = <0x00200000 0x00100000>; + read-only; + }; + partition@300000 { + label = "qsee"; + reg = <0x00300000 0x00100000>; + read-only; + }; + partition@400000 { + label = "qsee_alt"; + reg = <0x00400000 0x00100000>; + read-only; + }; + partition@500000 { + label = "cdt"; + reg = <0x00500000 0x00080000>; + read-only; + }; + partition@580000 { + label = "cdt_alt"; + reg = <0x00580000 0x00080000>; + read-only; + }; + partition@600000 { + label = "ddrparams"; + reg = <0x00600000 0x00080000>; + read-only; + }; + partition@700000 { + label = "u-boot"; + reg = <0x00700000 0x00200000>; + read-only; + }; + partition@900000 { + label = "u-boot-backup"; + reg = <0x00900000 0x00200000>; + read-only; + }; + partition@b00000 { + label = "ART"; + reg = <0x00b00000 0x00080000>; + read-only; + }; + partition@c00000 { + label = "ubi"; + reg = <0x00c00000 0x07000000>; + /* + * Do not try to allocate the remaining + * 4 MiB to this ubi partition. It will + * confuse the u-boot and it might not + * find the kernel partition anymore. + */ + }; + }; + }; +}; + +&pcie0 { + status = "okay"; + perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>; + wake-gpio = <&tlmm 50 GPIO_ACTIVE_LOW>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi2: wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + }; + }; +}; + +&qpic_bam { + status = "okay"; +}; + +&tlmm { + /* + * GPIO43 should be 0/1 whenever the unit is + * powered through PoE or AC-Adapter. + * That said, playing with this seems to + * reset the AP. + */ + + mdio_pins: mdio_pinmux { + mux_1 { + pins = "gpio6"; + function = "mdio"; + bias-pull-up; + }; + mux_2 { + pins = "gpio7"; + function = "mdc"; + bias-pull-up; + }; + }; + + serial_0_pins: serial_pinmux { + mux { + pins = "gpio16", "gpio17"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + serial_1_pins: serial1_pinmux { + mux { + /* We use the i2c-0 pins for serial_1 */ + pins = "gpio8", "gpio9"; + function = "blsp_uart1"; + bias-disable; + }; + }; + + i2c_0_pins: i2c_0_pinmux { + pinmux { + function = "blsp_i2c0"; + pins = "gpio20", "gpio21"; + }; + pinconf { + pins = "gpio20", "gpio21"; + drive-strength = <16>; + bias-disable; + }; + }; + + i2c_1_pins: i2c_1_pinmux { + pinmux { + function = "blsp_i2c1"; + pins = "gpio34", "gpio35"; + }; + pinconf { + pins = "gpio34", "gpio35"; + drive-strength = <16>; + bias-disable; + }; + }; + + nand_pins: nand_pins { + /* + * There are 18 pins. 15 pins are common between LCD and NAND. + * The QPIC controller arbitrates between LCD and NAND. Of the + * remaining 4, 2 are for NAND and 2 are for LCD exclusively. + * + * The meraki source hints that the bluetooth module claims + * pin 52 as well. But sadly, there's no data whenever this + * is a NAND or LCD exclusive pin or not. + */ + + 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; + }; + }; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "Meraki-MR33"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "Meraki-MR33"; +}; diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile index a9b7b9bb1..62abeea5b 100644 --- a/target/linux/ipq40xx/image/Makefile +++ b/target/linux/ipq40xx/image/Makefile @@ -46,8 +46,8 @@ define Device/DniImage NETGEAR_BOARD_ID := NETGEAR_HW_ID := IMAGES := factory.img sysupgrade.bin - IMAGE/factory.img := append-kernel | pad-offset 64k 64 | append-uImage-fakehdr filesystem | pad-to $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | netgear-dni - IMAGE/sysupgrade.bin := append-kernel | pad-offset 64k 64 | append-uImage-fakehdr filesystem | pad-to $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | append-metadata + IMAGE/factory.img := append-kernel | pad-offset 64k 64 | append-uImage-fakehdr filesystem | append-rootfs | pad-rootfs | netgear-dni + IMAGE/sysupgrade.bin := append-kernel | pad-offset 64k 64 | append-uImage-fakehdr filesystem | append-rootfs | pad-rootfs | append-metadata endef DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_HW_ID @@ -62,6 +62,15 @@ define Device/8dev_jalapeno endef TARGET_DEVICES += 8dev_jalapeno +define Device/asus_map-ac2200 + $(call Device/FitImageLzma) + DEVICE_DTS := qcom-ipq4019-map-ac2200 + DEVICE_TITLE := ASUS Lyra MAP-AC2200 + IMAGES := sysupgrade.bin + DEVICE_PACKAGES := ipq-wifi-asus_map-ac2200 ath10k-firmware-qca9888-ct kmod-ath3k +endef +TARGET_DEVICES += asus_map-ac2200 + define Device/asus_rt-ac58u $(call Device/FitImageLzma) DEVICE_DTS := qcom-ipq4018-rt-ac58u @@ -84,23 +93,6 @@ define Device/asus_rt-ac58u endef TARGET_DEVICES += asus_rt-ac58u -define Device/asus_rt-ac1300uhp - $(call Device/FitImageLzma) - DEVICE_DTS := qcom-ipq4018-rt-ac1300uhp - BLOCKSIZE := 128k - PAGESIZE := 2048 - DTB_SIZE := 65536 - DEVICE_TITLE := Asus RT-AC1300UHP - IMAGE_SIZE := 20439364 - FILESYSTEMS := squashfs - UIMAGE_NAME:=$(shell echo -e '\03\01\01\01RT-AC58U') - KERNEL_INITRAMFS := $$(KERNEL) | uImage none - KERNEL_INITRAMFS_SUFFIX := -factory.trx - IMAGES := sysupgrade.bin - DEVICE_PACKAGES := kmod-usb-ledtrig-usbport -endef -TARGET_DEVICES += asus_rt-ac1300uhp - define Device/asus_rt-acrh17 $(call Device/FitImageLzma) DEVICE_DTS := qcom-ipq4019-rt-acrh17 @@ -114,7 +106,7 @@ define Device/asus_rt-acrh17 KERNEL_INITRAMFS := $$(KERNEL) | uImage none KERNEL_INITRAMFS_SUFFIX := -factory.trx IMAGES := sysupgrade.bin - DEVICE_PACKAGES := ipq-wifi-rt-acrh17 ath10k-firmware-qca9984 + DEVICE_PACKAGES := ipq-wifi-rt-acrh17 ath10k-firmware-qca9984 kmod-ath10k ath10k-firmware-qca4019 -kmod-ath10k-ct -ath10k-firmware-qca4019-ct endef TARGET_DEVICES += asus_rt-acrh17 @@ -124,12 +116,12 @@ define Device/avm_fritzbox-4040 BOARD_NAME := fritz4040 DEVICE_TITLE := AVM Fritz!Box 4040 IMAGE_SIZE := 29753344 - UBOOT_PATH := $$(BIN_DIR)/u-boot-fritz4040/uboot-fritz4040.bin + UBOOT_PATH := $(STAGING_DIR_IMAGE)/uboot-fritz4040.bin UBOOT_PARTITION_SIZE := 524288 IMAGES = eva.bin sysupgrade.bin IMAGE/eva.bin := append-uboot | pad-to $$$$(UBOOT_PARTITION_SIZE) | append-kernel | append-rootfs | pad-rootfs IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata - DEVICE_PACKAGES := fritz-tffs fritz-caldata u-boot-fritz4040 + DEVICE_PACKAGES := fritz-tffs fritz-caldata endef TARGET_DEVICES += avm_fritzbox-4040 @@ -147,6 +139,20 @@ define Device/compex_wpj428 endef TARGET_DEVICES += compex_wpj428 +define Device/engenius_eap1300 + $(call Device/FitImage) + DEVICE_TITLE := EnGenius EAP1300 + DEVICE_DTS_CONFIG := config@4 + BOARD_NAME := eap1300 + DEVICE_DTS := qcom-ipq4018-eap1300 + KERNEL_SIZE := 5120k + IMAGE_SIZE := 25344k + IMAGES := sysupgrade.bin + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata + DEVICE_PACKAGES := ipq-wifi-engenius_eap1300 +endef +TARGET_DEVICES += engenius_eap1300 + define Device/glinet_gl-b1300 $(call Device/FitImage) DEVICE_TITLE := GL.iNet GL-B1300 @@ -159,6 +165,41 @@ define Device/glinet_gl-b1300 endef TARGET_DEVICES += glinet_gl-b1300 +define Device/linksys_ea6350v3 + # The Linksys EA6350v3 has a uboot bootloader that does not + # support either booting lzma kernel images nor booting UBI + # partitions. This uboot, however, supports raw kernel images and + # gzipped images. + # + # As for the time of writing this, the device will boot the kernel + # from a fixed address with a fixed length of 3MiB. Also, the + # device has a hard-coded kernel command line that requieres the + # rootfs and alt_rootfs to be in mtd11 and mtd13 respectively. + # Oh... and the kernel partition overlaps with the rootfs + # partition (the same for alt_kernel and alt_rootfs). + # + # If you are planing re-partitioning the device, you may want to + # keep those details in mind: + # 1. The kernel adresses you should honor are 0x00000000 and + # 0x02800000 respectively. + # 2. The kernel size (plus the dtb) cannot exceed 3.00MiB in size. + # 3. You can use 'zImage', but not a raw 'Image' packed with lzma. + # 4. The kernel command line from uboot is harcoded to boot with + # rootfs either in mtd11 or mtd13. + $(call Device/FitzImage) + DEVICE_TITLE := Linksys EA6350v3 + DEVICE_DTS := qcom-ipq4018-ea6350v3 + BLOCKSIZE := 128k + PAGESIZE := 2048 + KERNEL_SIZE := 3145728 + IMAGE_SIZE := 38797312 + UBINIZE_OPTS := -E 5 + IMAGES := factory.bin sysupgrade.bin + IMAGE/factory.bin := append-kernel | append-uImage-fakehdr filesystem | pad-to $$$${KERNEL_SIZE} | append-ubi | linksys-image type=EA6350v3 + DEVICE_PACKAGES := ipq-wifi-linksys_ea6350v3 uboot-envtools +endef +TARGET_DEVICES += linksys_ea6350v3 + define Device/meraki_mr33 $(call Device/FitImage) DEVICE_DTS := qcom-ipq4029-mr33 @@ -172,7 +213,6 @@ TARGET_DEVICES += meraki_mr33 define Device/netgear_ex61x0v2 $(call Device/DniImage) - KERNEL_SIZE := 3080192 DEVICE_DTS_CONFIG := config@4 NETGEAR_BOARD_ID := EX6150v2series NETGEAR_HW_ID := 29765285+16+0+128+2x2 @@ -236,20 +276,6 @@ define Device/qcom_ap-dk01.1-c1 endef TARGET_DEVICES += qcom_ap-dk01.1-c1 -define Device/linksys_ea6350v3 - $(call Device/FitzImage) - DEVICE_TITLE := Linksys EA6350v3 - DEVICE_DTS := qcom-ipq4018-ea6350v3 - BLOCKSIZE := 128k - PAGESIZE := 2048 - KERNEL_SIZE := 3145728 - IMAGE_SIZE := 38797312 - UBINIZE_OPTS := -E 5 - IMAGES := sysupgrade.bin - DEVICE_PACKAGES := ath10k-firmware-qca4019 ipq-wifi-linksys_ea6350v3 uboot-envtools -endef -TARGET_DEVICES += linksys_ea6350v3 - define Device/qcom_ap-dk04.1-c1 $(call Device/FitImage) $(call Device/UbiFit) @@ -279,7 +305,7 @@ define Device/zyxel_nbg6617 # this minimum-size. However, the larger image can be flashed both ways. IMAGE/factory.bin := append-rootfs | pad-rootfs | pad-to 64k | check-size $$$$(ROOTFS_SIZE) | zyxel-ras-image separate-kernel IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-rootfs | check-size $$$$(ROOTFS_SIZE) | sysupgrade-tar rootfs=$$$$@ | append-metadata - DEVICE_PACKAGES := ipq-wifi-zyxel_nbg6617 uboot-envtools + DEVICE_PACKAGES := uboot-envtools kmod-usb-ledtrig-usbport endef TARGET_DEVICES += zyxel_nbg6617 @@ -288,7 +314,6 @@ define Device/zyxel_wre6606 DEVICE_TITLE := ZyXEL WRE6606 DEVICE_DTS_CONFIG := config@4 DEVICE_DTS := qcom-ipq4018-wre6606 - DEVICE_PACKAGES := ipq-wifi-zyxel_wre6606 IMAGES := sysupgrade.bin IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata endef diff --git a/target/linux/ipq40xx/patches-4.14/077-qcom-ipq4019-add-USB-devicetree-nodes.patch b/target/linux/ipq40xx/patches-4.14/077-qcom-ipq4019-add-USB-devicetree-nodes.patch index 94156dce2..44c07f8f4 100644 --- a/target/linux/ipq40xx/patches-4.14/077-qcom-ipq4019-add-USB-devicetree-nodes.patch +++ b/target/linux/ipq40xx/patches-4.14/077-qcom-ipq4019-add-USB-devicetree-nodes.patch @@ -81,7 +81,7 @@ Signed-off-by: John Crispin + dwc3@8a00000 { + compatible = "snps,dwc3"; + reg = <0x8a00000 0xf8000>; -+ interrupts = <0 132 0>; ++ interrupts = ; + phys = <&usb3_hs_phy>, <&usb3_ss_phy>; + phy-names = "usb2-phy", "usb3-phy"; + dr_mode = "host"; @@ -113,7 +113,7 @@ Signed-off-by: John Crispin + dwc3@6000000 { + compatible = "snps,dwc3"; + reg = <0x6000000 0xf8000>; -+ interrupts = <0 136 0>; ++ interrupts = ; + phys = <&usb2_hs_phy>; + phy-names = "usb2-phy"; + dr_mode = "host"; diff --git a/target/linux/ipq40xx/patches-4.14/084-ARM-dts-ipq4019-Add-a-default-chosen-node.patch b/target/linux/ipq40xx/patches-4.14/084-ARM-dts-ipq4019-Add-a-default-chosen-node.patch new file mode 100644 index 000000000..513e623de --- /dev/null +++ b/target/linux/ipq40xx/patches-4.14/084-ARM-dts-ipq4019-Add-a-default-chosen-node.patch @@ -0,0 +1,45 @@ +From c696a020193e7f96ead97b6b19a2bcd929b299d3 Mon Sep 17 00:00:00 2001 +From: Sricharan R +Date: Fri, 25 May 2018 11:41:11 +0530 +Subject: [PATCH] ARM: dts: ipq4019: Add a default chosen node + +Add a 'chosen' node to select the serial console. +This is needed when bootloaders do not pass the +'console=' bootargs. + +Acked-by: Bjorn Andersson +Signed-off-by: Sricharan R +Signed-off-by: Andy Gross +--- + arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi | 8 ++++++++ + arch/arm/boot/dts/qcom-ipq4019.dtsi | 2 +- + 2 files changed, 9 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi +@@ -20,6 +20,14 @@ + model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK01.1"; + compatible = "qcom,ipq4019"; + ++ aliases { ++ serial0 = &blsp1_uart1; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ + soc { + rng@22000 { + status = "ok"; +--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi +@@ -346,7 +346,7 @@ + regulator; + }; + +- serial@78af000 { ++ blsp1_uart1: serial@78af000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0x78af000 0x200>; + interrupts = ; diff --git a/target/linux/ipq40xx/patches-4.14/400-mtd-ubi-add-quirk-to-autoload-ubi-on-rt-ac58u.patch b/target/linux/ipq40xx/patches-4.14/400-mtd-ubi-add-quirk-to-autoload-ubi-on-rt-ac58u.patch deleted file mode 100644 index 6a83d79d8..000000000 --- a/target/linux/ipq40xx/patches-4.14/400-mtd-ubi-add-quirk-to-autoload-ubi-on-rt-ac58u.patch +++ /dev/null @@ -1,29 +0,0 @@ -From b8f3a7ccbeca5bdbd1b6210b94b38d3fef2dd0bd Mon Sep 17 00:00:00 2001 -From: Christian Lamparter -Date: Thu, 19 Jan 2017 01:57:22 +0100 -Subject: [PATCH 16/38] mtd: ubi: add auto_attach HACK for the ASUS RT-AC58U - -This patch adds a hack that allows UBI's autoattach feature -to work with the custom ASUS UBI_DEV partition name. - -This is necessary because the vendor's u-boot doesn't leave -the bootargs / cmdline alone, so the it can't be overwritten -easily otherwise. - -Signed-off-by: Christian Lamparter ---- - drivers/mtd/ubi/build.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/mtd/ubi/build.c -+++ b/drivers/mtd/ubi/build.c -@@ -1187,6 +1187,9 @@ static void __init ubi_auto_attach(void) - mtd = open_mtd_device("ubi"); - if (IS_ERR(mtd)) - mtd = open_mtd_device("data"); -+ /* Hack for the Asus RT-AC58U */ -+ if (IS_ERR(mtd)) -+ mtd = open_mtd_device("UBI_DEV"); - - if (IS_ERR(mtd)) - return; diff --git a/target/linux/ipq40xx/patches-4.14/900-dts-ipq4019-ap-dk01.1.patch b/target/linux/ipq40xx/patches-4.14/900-dts-ipq4019-ap-dk01.1.patch index 25652bb2c..349f67c66 100644 --- a/target/linux/ipq40xx/patches-4.14/900-dts-ipq4019-ap-dk01.1.patch +++ b/target/linux/ipq40xx/patches-4.14/900-dts-ipq4019-ap-dk01.1.patch @@ -1,6 +1,6 @@ --- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi +++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi -@@ -15,12 +15,39 @@ +@@ -15,6 +15,7 @@ */ #include "qcom-ipq4019.dtsi" @@ -8,7 +8,8 @@ / { model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK01.1"; - compatible = "qcom,ipq4019"; +@@ -29,6 +30,32 @@ + }; soc { + tcsr@194b000 { @@ -40,7 +41,7 @@ rng@22000 { status = "ok"; }; -@@ -66,14 +93,6 @@ +@@ -74,14 +101,6 @@ pinctrl-names = "default"; status = "ok"; cs-gpios = <&tlmm 54 0>; @@ -55,7 +56,7 @@ }; serial@78af000 { -@@ -102,6 +121,22 @@ +@@ -110,6 +129,22 @@ status = "ok"; }; diff --git a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch index 4dc4ea14a..0eff38a33 100644 --- a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch +++ b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch @@ -10,27 +10,28 @@ Signed-off-by: John Crispin --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -697,7 +697,23 @@ dtb-$(CONFIG_ARCH_QCOM) += \ +@@ -697,7 +697,24 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-apq8074-dragonboard.dtb \ qcom-apq8084-ifc6540.dtb \ qcom-apq8084-mtp.dtb \ + qcom-ipq4018-a42.dtb \ ++ qcom-ipq4018-ea6350v3.dtb \ ++ qcom-ipq4018-eap1300.dtb \ + qcom-ipq4018-ex6100v2.dtb \ + qcom-ipq4018-ex6150v2.dtb \ + qcom-ipq4018-fritz4040.dtb \ + qcom-ipq4018-jalapeno.dtb \ + qcom-ipq4018-nbg6617.dtb \ + qcom-ipq4018-rt-ac58u.dtb \ -+ qcom-ipq4018-rt-ac1300uhp.dtb \ + qcom-ipq4018-wre6606.dtb \ qcom-ipq4019-ap.dk01.1-c1.dtb \ + qcom-ipq4019-a62.dtb \ + qcom-ipq4019-ap.dk04.1-c1.dtb \ ++ qcom-ipq4019-map-ac2200.dtb \ + qcom-ipq4019-rt-acrh17.dtb \ + qcom-ipq4028-wpj428.dtb \ + qcom-ipq4029-gl-b1300.dtb \ + qcom-ipq4029-mr33.dtb \ -+ qcom-ipq4018-ea6350v3.dtb \ qcom-ipq8064-ap148.dtb \ qcom-msm8660-surf.dtb \ qcom-msm8960-cdp.dtb \ diff --git a/target/linux/ipq40xx/patches-4.14/998-ignore-peer-stats-debug-info.patch b/target/linux/ipq40xx/patches-4.14/998-ignore-peer-stats-debug-info.patch deleted file mode 100644 index 376496399..000000000 --- a/target/linux/ipq40xx/patches-4.14/998-ignore-peer-stats-debug-info.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c -index 7d295ee71534..50670d651cff 100644 ---- a/drivers/net/wireless/ath/ath10k/htt_rx.c -+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c -@@ -2387,7 +2387,7 @@ static void ath10k_htt_fetch_peer_stats( - ppdu_len = resp->peer_tx_stats.ppdu_len * sizeof(__le32); - - if (skb->len < sizeof(struct htt_resp_hdr) + num_ppdu * ppdu_len) { -- ath10k_warn(ar, "Invalid peer stats buf length %d\n", skb->len); -+ - return; - } - -@@ -2399,8 +2399,8 @@ static void ath10k_htt_fetch_peer_stats( - spin_lock_bh(&ar->data_lock); - peer = ath10k_peer_find_by_id(ar, peer_id); - if (!peer) { -- ath10k_warn(ar, "Invalid peer id %d peer stats buffer\n", -- peer_id); -+ -+ - goto out; - } - diff --git a/target/linux/ipq40xx/patches-4.14/999-fix-ipq4019-dtsi.patch b/target/linux/ipq40xx/patches-4.14/999-fix-ipq4019-dtsi.patch deleted file mode 100644 index f01c5d806..000000000 --- a/target/linux/ipq40xx/patches-4.14/999-fix-ipq4019-dtsi.patch +++ /dev/null @@ -1,158 +0,0 @@ -diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi -index a15993f..94dcb6c 100644 ---- a/arch/arm/boot/dts/qcom-ipq4019.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi -@@ -204,13 +204,13 @@ - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; -- interrupts = ; -+ interrupts = ; - }; - - blsp_dma: dma@7884000 { - compatible = "qcom,bam-v1.7.0"; - reg = <0x07884000 0x23000>; -- interrupts = ; -+ interrupts = ; - clocks = <&gcc GCC_BLSP1_AHB_CLK>; - clock-names = "bam_clk"; - #dma-cells = <1>; -@@ -277,7 +277,7 @@ - cryptobam: dma@8e04000 { - compatible = "qcom,bam-v1.7.0"; - reg = <0x08e04000 0x20000>; -- interrupts = ; -+ interrupts = ; - clocks = <&gcc GCC_CRYPTO_AHB_CLK>; - clock-names = "bam_clk"; - #dma-cells = <1>; -@@ -298,49 +298,49 @@ - status = "disabled"; - }; - -- acc0: clock-controller@b088000 { -+ acc0: clock-controller@b088000 { - compatible = "qcom,kpss-acc-v2"; -- reg = <0x0b088000 0x1000>, <0xb008000 0x1000>; -- }; -+ reg = <0x0b088000 0x1000>, <0xb008000 0x1000>; -+ }; - -- acc1: clock-controller@b098000 { -+ acc1: clock-controller@b098000 { - compatible = "qcom,kpss-acc-v2"; -- reg = <0x0b098000 0x1000>, <0xb008000 0x1000>; -- }; -+ reg = <0x0b098000 0x1000>, <0xb008000 0x1000>; -+ }; - -- acc2: clock-controller@b0a8000 { -+ acc2: clock-controller@b0a8000 { - compatible = "qcom,kpss-acc-v2"; -- reg = <0x0b0a8000 0x1000>, <0xb008000 0x1000>; -- }; -+ reg = <0x0b0a8000 0x1000>, <0xb008000 0x1000>; -+ }; - -- acc3: clock-controller@b0b8000 { -+ acc3: clock-controller@b0b8000 { - compatible = "qcom,kpss-acc-v2"; -- reg = <0x0b0b8000 0x1000>, <0xb008000 0x1000>; -- }; -+ reg = <0x0b0b8000 0x1000>, <0xb008000 0x1000>; -+ }; - -- saw0: regulator@b089000 { -- compatible = "qcom,saw2"; -+ saw0: regulator@b089000 { -+ compatible = "qcom,saw2"; - reg = <0x0b089000 0x1000>, <0x0b009000 0x1000>; -- regulator; -- }; -- -- saw1: regulator@b099000 { -- compatible = "qcom,saw2"; -- reg = <0x0b099000 0x1000>, <0x0b009000 0x1000>; -- regulator; -- }; -- -- saw2: regulator@b0a9000 { -- compatible = "qcom,saw2"; -- reg = <0x0b0a9000 0x1000>, <0x0b009000 0x1000>; -- regulator; -- }; -- -- saw3: regulator@b0b9000 { -- compatible = "qcom,saw2"; -- reg = <0x0b0b9000 0x1000>, <0x0b009000 0x1000>; -- regulator; -- }; -+ regulator; -+ }; -+ -+ saw1: regulator@b099000 { -+ compatible = "qcom,saw2"; -+ reg = <0x0b099000 0x1000>, <0x0b009000 0x1000>; -+ regulator; -+ }; -+ -+ saw2: regulator@b0a9000 { -+ compatible = "qcom,saw2"; -+ reg = <0x0b0a9000 0x1000>, <0x0b009000 0x1000>; -+ regulator; -+ }; -+ -+ saw3: regulator@b0b9000 { -+ compatible = "qcom,saw2"; -+ reg = <0x0b0b9000 0x1000>, <0x0b009000 0x1000>; -+ regulator; -+ }; - - saw_l2: regulator@b012000 { - compatible = "qcom,saw2"; -@@ -351,7 +351,7 @@ - serial@78af000 { - compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; - reg = <0x78af000 0x200>; -- interrupts = ; -+ interrupts = ; - status = "disabled"; - clocks = <&gcc GCC_BLSP1_UART1_APPS_CLK>, - <&gcc GCC_BLSP1_AHB_CLK>; -@@ -363,7 +363,7 @@ - serial@78b0000 { - compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; - reg = <0x78b0000 0x200>; -- interrupts = ; -+ interrupts = ; - status = "disabled"; - clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, - <&gcc GCC_BLSP1_AHB_CLK>; -@@ -402,7 +402,7 @@ - ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000 - 0x82000000 0 0x40300000 0x40300000 0 0x400000>; - -- interrupts = ; -+ interrupts = ; - interrupt-names = "msi"; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 0x7>; -@@ -513,7 +513,7 @@ - , - , - , -- ; -+ ; - interrupt-names = "msi0", "msi1", "msi2", "msi3", - "msi4", "msi5", "msi6", "msi7", - "msi8", "msi9", "msi10", "msi11", -@@ -555,7 +555,7 @@ - , - , - , -- ; -+ ; - interrupt-names = "msi0", "msi1", "msi2", "msi3", - "msi4", "msi5", "msi6", "msi7", - "msi8", "msi9", "msi10", "msi11", diff --git a/target/linux/ipq40xx/patches-4.19/070-v4.20-soc-qcom-spm-add-SCM-probe-dependency.patch b/target/linux/ipq40xx/patches-4.19/070-v4.20-soc-qcom-spm-add-SCM-probe-dependency.patch new file mode 100644 index 000000000..d0b520f38 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/070-v4.20-soc-qcom-spm-add-SCM-probe-dependency.patch @@ -0,0 +1,27 @@ +From 61a3bd10082b0e861b4e1bc451a92e20181a52f5 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 23 Jul 2018 16:17:35 +0200 +Subject: [PATCH] soc: qcom: spm: add SCM probe dependency + +Check for SCM availability before attempting to use SPM. SPM probe will +fail otherwise. + +Signed-off-by: Felix Fietkau +Signed-off-by: John Crispin +Signed-off-by: Andy Gross +--- + drivers/soc/qcom/spm.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/soc/qcom/spm.c ++++ b/drivers/soc/qcom/spm.c +@@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(stru + cpumask_t mask; + bool use_scm_power_down = false; + ++ if (!qcom_scm_is_available()) ++ return -EPROBE_DEFER; ++ + for (i = 0; ; i++) { + state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); + if (!state_node) diff --git a/target/linux/ipq40xx/patches-4.19/071-01-v4.20-ARM-dts-qcom-ipq4019-use-v2-of-the-kpss-bringup-mech.patch b/target/linux/ipq40xx/patches-4.19/071-01-v4.20-ARM-dts-qcom-ipq4019-use-v2-of-the-kpss-bringup-mech.patch new file mode 100644 index 000000000..b1d69ca0e --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/071-01-v4.20-ARM-dts-qcom-ipq4019-use-v2-of-the-kpss-bringup-mech.patch @@ -0,0 +1,97 @@ +From 233c77d4f1d12e4337fba1146d5197f4c0f9107d Mon Sep 17 00:00:00 2001 +From: Matthew McClintock +Date: Wed, 25 Jul 2018 10:37:45 +0200 +Subject: [PATCH] ARM: dts: qcom: ipq4019: use v2 of the kpss bringup mechanism + +v1 was the incorrect choice here and sometimes the board +would not come up properly. + +Signed-off-by: Matthew McClintock +Signed-off-by: Christian Lamparter +Signed-off-by: John Crispin +Signed-off-by: Andy Gross +--- + arch/arm/boot/dts/qcom-ipq4019.dtsi | 25 +++++++++++++++++-------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi +@@ -52,7 +52,8 @@ + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; +- enable-method = "qcom,kpss-acc-v1"; ++ enable-method = "qcom,kpss-acc-v2"; ++ next-level-cache = <&L2>; + qcom,acc = <&acc0>; + qcom,saw = <&saw0>; + reg = <0x0>; +@@ -71,7 +72,8 @@ + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; +- enable-method = "qcom,kpss-acc-v1"; ++ enable-method = "qcom,kpss-acc-v2"; ++ next-level-cache = <&L2>; + qcom,acc = <&acc1>; + qcom,saw = <&saw1>; + reg = <0x1>; +@@ -90,7 +92,8 @@ + cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; +- enable-method = "qcom,kpss-acc-v1"; ++ enable-method = "qcom,kpss-acc-v2"; ++ next-level-cache = <&L2>; + qcom,acc = <&acc2>; + qcom,saw = <&saw2>; + reg = <0x2>; +@@ -109,7 +112,8 @@ + cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; +- enable-method = "qcom,kpss-acc-v1"; ++ enable-method = "qcom,kpss-acc-v2"; ++ next-level-cache = <&L2>; + qcom,acc = <&acc3>; + qcom,saw = <&saw3>; + reg = <0x3>; +@@ -124,6 +128,11 @@ + >; + clock-latency = <256000>; + }; ++ ++ L2: l2-cache { ++ compatible = "cache"; ++ cache-level = <2>; ++ }; + }; + + pmu { +@@ -292,22 +301,22 @@ + }; + + acc0: clock-controller@b088000 { +- compatible = "qcom,kpss-acc-v1"; ++ compatible = "qcom,kpss-acc-v2"; + reg = <0x0b088000 0x1000>, <0xb008000 0x1000>; + }; + + acc1: clock-controller@b098000 { +- compatible = "qcom,kpss-acc-v1"; ++ compatible = "qcom,kpss-acc-v2"; + reg = <0x0b098000 0x1000>, <0xb008000 0x1000>; + }; + + acc2: clock-controller@b0a8000 { +- compatible = "qcom,kpss-acc-v1"; ++ compatible = "qcom,kpss-acc-v2"; + reg = <0x0b0a8000 0x1000>, <0xb008000 0x1000>; + }; + + acc3: clock-controller@b0b8000 { +- compatible = "qcom,kpss-acc-v1"; ++ compatible = "qcom,kpss-acc-v2"; + reg = <0x0b0b8000 0x1000>, <0xb008000 0x1000>; + }; + diff --git a/target/linux/ipq40xx/patches-4.19/071-02-ipq40xx-Fix-booting-secondary-cores.patch b/target/linux/ipq40xx/patches-4.19/071-02-ipq40xx-Fix-booting-secondary-cores.patch new file mode 100644 index 000000000..d37a8cb6b --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/071-02-ipq40xx-Fix-booting-secondary-cores.patch @@ -0,0 +1,38 @@ +From 8a4540321e8bcf7a5b485c332a2e78f3501c78ed Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Thu, 29 Nov 2018 22:29:36 +0100 +Subject: [PATCH] ipq40xx: Fix booting secondary cores + +Add the second part of old 071-qcom-ipq4019-use-v2-of-the-kpss-bringup-mechanism.patch +We dont modify the patch itself as its upstream and this change is not. + +Originally added by Mantas Pucka Mantas Pucka + +Signed-off-by: Robert Marko +--- + 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 +@@ -132,6 +132,7 @@ + L2: l2-cache { + compatible = "cache"; + cache-level = <2>; ++ qcom,saw = <&saw_l2>; + }; + }; + +@@ -344,6 +345,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>; diff --git a/target/linux/ipq40xx/patches-4.19/072-v4.20-ARM-dts-qcom-ipq4019-add-cpu-operating-points-for-cp.patch b/target/linux/ipq40xx/patches-4.19/072-v4.20-ARM-dts-qcom-ipq4019-add-cpu-operating-points-for-cp.patch new file mode 100644 index 000000000..303546105 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/072-v4.20-ARM-dts-qcom-ipq4019-add-cpu-operating-points-for-cp.patch @@ -0,0 +1,110 @@ +From bcb9ab4c2917e92114d2f4c2b1da97cdf15b471b Mon Sep 17 00:00:00 2001 +From: Matthew McClintock +Date: Wed, 25 Jul 2018 10:37:46 +0200 +Subject: [PATCH] ARM: dts: qcom: ipq4019: add cpu operating points for cpufreq + support + +This adds some operating points for cpu frequeny scaling + +Signed-off-by: Matthew McClintock +Signed-off-by: John Crispin +Signed-off-by: Andy Gross +--- + arch/arm/boot/dts/qcom-ipq4019.dtsi | 54 ++++++++++++++--------------- + 1 file changed, 26 insertions(+), 28 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi +@@ -59,14 +59,8 @@ + reg = <0x0>; + clocks = <&gcc GCC_APPS_CLK_SRC>; + clock-frequency = <0>; +- operating-points = < +- /* kHz uV (fixed) */ +- 48000 1100000 +- 200000 1100000 +- 500000 1100000 +- 716000 1100000 +- >; + clock-latency = <256000>; ++ operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu@1 { +@@ -79,14 +73,8 @@ + reg = <0x1>; + clocks = <&gcc GCC_APPS_CLK_SRC>; + clock-frequency = <0>; +- operating-points = < +- /* kHz uV (fixed) */ +- 48000 1100000 +- 200000 1100000 +- 500000 1100000 +- 666000 1100000 +- >; + clock-latency = <256000>; ++ operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu@2 { +@@ -99,14 +87,8 @@ + reg = <0x2>; + clocks = <&gcc GCC_APPS_CLK_SRC>; + clock-frequency = <0>; +- operating-points = < +- /* kHz uV (fixed) */ +- 48000 1100000 +- 200000 1100000 +- 500000 1100000 +- 666000 1100000 +- >; + clock-latency = <256000>; ++ operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu@3 { +@@ -119,14 +101,8 @@ + reg = <0x3>; + clocks = <&gcc GCC_APPS_CLK_SRC>; + clock-frequency = <0>; +- operating-points = < +- /* kHz uV (fixed) */ +- 48000 1100000 +- 200000 1100000 +- 500000 1100000 +- 666000 1100000 +- >; + clock-latency = <256000>; ++ operating-points-v2 = <&cpu0_opp_table>; + }; + + L2: l2-cache { +@@ -136,6 +112,28 @@ + }; + }; + ++ cpu0_opp_table: opp_table0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-48000000 { ++ opp-hz = /bits/ 64 <48000000>; ++ clock-latency-ns = <256000>; ++ }; ++ opp-200000000 { ++ opp-hz = /bits/ 64 <200000000>; ++ clock-latency-ns = <256000>; ++ }; ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ clock-latency-ns = <256000>; ++ }; ++ opp-716000000 { ++ opp-hz = /bits/ 64 <716000000>; ++ clock-latency-ns = <256000>; ++ }; ++ }; ++ + pmu { + compatible = "arm,cortex-a7-pmu"; + interrupts = +Date: Wed, 25 Jul 2018 10:37:47 +0200 +Subject: [PATCH] ARM: dts: qcom: ipq4019: fix cpu0's qcom,saw2 reg value + +while compiling an ipq4019 target, dtc will complain: +regulator@b089000 unit address format error, expected "2089000" + +The saw0 regulator reg value seems to be +copied and pasted from qcom-ipq8064.dtsi. + +This patch fixes the reg value to match that of the +unit address which in turn silences the warning. +(There is no driver for qcom,saw2 right now. +So this went unnoticed) + +Signed-off-by: Christian Lamparter +Signed-off-by: John Crispin +Signed-off-by: Andy Gross +--- + 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 +@@ -321,7 +321,7 @@ + + saw0: regulator@b089000 { + compatible = "qcom,saw2"; +- reg = <0x02089000 0x1000>, <0x0b009000 0x1000>; ++ reg = <0x0b089000 0x1000>, <0x0b009000 0x1000>; + regulator; + }; + diff --git a/target/linux/ipq40xx/patches-4.19/074-ARM-qcom-Add-IPQ4019-SoC-support.patch b/target/linux/ipq40xx/patches-4.19/074-ARM-qcom-Add-IPQ4019-SoC-support.patch new file mode 100644 index 000000000..76fcdc6ab --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/074-ARM-qcom-Add-IPQ4019-SoC-support.patch @@ -0,0 +1,36 @@ +From 89b43d59ec8c9cda588555eb1f2754dd19ef5144 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Sun, 22 Jul 2018 12:07:57 +0200 +Subject: [PATCH 8/8] ARM: qcom: Add IPQ4019 SoC support + +Add support for the Qualcomm Atheros IPQ4019 SoC. + +Signed-off-by: Christian Lamparter +Signed-off-by: John Crispin +--- + arch/arm/Makefile | 1 + + arch/arm/mach-qcom/Kconfig | 5 +++++ + 2 files changed, 6 insertions(+) + +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -150,6 +150,7 @@ textofs-$(CONFIG_ARCH_MSM8X60) := 0x0020 + textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000 + textofs-$(CONFIG_ARCH_MESON) := 0x00208000 + textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000 ++textofs-$(CONFIG_ARCH_IPQ40XX) := 0x00208000 + + # Machine directory name. This list is sorted alphanumerically + # by CONFIG_* macro name. +--- a/arch/arm/mach-qcom/Kconfig ++++ b/arch/arm/mach-qcom/Kconfig +@@ -27,4 +27,9 @@ config ARCH_MDM9615 + bool "Enable support for MDM9615" + select CLKSRC_QCOM + ++config ARCH_IPQ40XX ++ bool "Enable support for IPQ40XX" ++ select CLKSRC_QCOM ++ select HAVE_ARM_ARCH_TIMER ++ + endif diff --git a/target/linux/ipq40xx/patches-4.19/075-dt-bindings-phy-qcom-ipq4019-usb-add-binding-documen.patch b/target/linux/ipq40xx/patches-4.19/075-dt-bindings-phy-qcom-ipq4019-usb-add-binding-documen.patch new file mode 100644 index 000000000..e7407bcba --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/075-dt-bindings-phy-qcom-ipq4019-usb-add-binding-documen.patch @@ -0,0 +1,38 @@ +From 5f01733dc755dfadfa51b7b3c6c160e632fc6002 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 24 Jul 2018 15:09:36 +0200 +Subject: [PATCH 1/3] dt-bindings: phy-qcom-ipq4019-usb: add binding document + +This patch adds the binding documentation for the HS/SS USB PHY found +inside Qualcom Dakota SoCs. + +Signed-off-by: John Crispin +--- + .../bindings/phy/phy-qcom-ipq4019-usb.txt | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + create mode 100644 Documentation/devicetree/bindings/phy/phy-qcom-ipq4019-usb.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/phy/phy-qcom-ipq4019-usb.txt +@@ -0,0 +1,21 @@ ++Qualcom Dakota HS/SS USB PHY ++ ++Required properties: ++ - compatible: "qcom,usb-ss-ipq4019-phy", ++ "qcom,usb-hs-ipq4019-phy" ++ - reg: offset and length of the registers ++ - #phy-cells: should be 0 ++ - resets: the reset controllers as listed below ++ - reset-names: the names of the reset controllers ++ "por_rst" - the POR reset line for SS and HS phys ++ "srif_rst" - the SRIF reset line for HS phys ++Example: ++ ++hsphy@a8000 { ++ compatible = "qcom,usb-hs-ipq4019-phy"; ++ phy-cells = <0>; ++ reg = <0xa8000 0x40>; ++ resets = <&gcc USB2_HSPHY_POR_ARES>, ++ <&gcc USB2_HSPHY_S_ARES>; ++ reset-names = "por_rst", "srif_rst"; ++}; diff --git a/target/linux/ipq40xx/patches-4.19/076-phy-qcom-ipq4019-usb-add-driver-for-QCOM-IPQ4019.patch b/target/linux/ipq40xx/patches-4.19/076-phy-qcom-ipq4019-usb-add-driver-for-QCOM-IPQ4019.patch new file mode 100644 index 000000000..e7e7a1f89 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/076-phy-qcom-ipq4019-usb-add-driver-for-QCOM-IPQ4019.patch @@ -0,0 +1,234 @@ +From 633f0e08498aebfdb932bd71319b4cb136709499 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 24 Jul 2018 14:45:49 +0200 +Subject: [PATCH 2/3] phy: qcom-ipq4019-usb: add driver for QCOM/IPQ4019 + +Add a driver to setup the USB phy on Qualcom Dakota SoCs. +The driver sets up HS and SS phys. In case of HS some magic values need to +be written to magic offsets. These were taken from the SDK driver. + +Signed-off-by: John Crispin +--- + drivers/phy/qualcomm/Kconfig | 7 ++ + drivers/phy/qualcomm/Makefile | 1 + + drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c | 188 ++++++++++++++++++++++++++++ + 3 files changed, 196 insertions(+) + create mode 100644 drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c + +--- a/drivers/phy/qualcomm/Kconfig ++++ b/drivers/phy/qualcomm/Kconfig +@@ -17,6 +17,13 @@ config PHY_QCOM_APQ8064_SATA + depends on OF + select GENERIC_PHY + ++config PHY_QCOM_IPQ4019_USB ++ tristate "Qualcomm IPQ4019 USB PHY module" ++ depends on OF && ARCH_QCOM ++ select GENERIC_PHY ++ help ++ Support for the USB PHY on QCOM IPQ4019/Dakota chipsets. ++ + config PHY_QCOM_IPQ806X_SATA + tristate "Qualcomm IPQ806x SATA SerDes/PHY driver" + depends on ARCH_QCOM +--- /dev/null ++++ b/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c +@@ -0,0 +1,188 @@ ++/* ++ * Copyright (C) 2018 John Crispin ++ * ++ * Based on code from ++ * Allwinner Technology Co., Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Magic registers copied from the SDK driver code ++ */ ++#define PHY_CTRL0_ADDR 0x000 ++#define PHY_CTRL1_ADDR 0x004 ++#define PHY_CTRL2_ADDR 0x008 ++#define PHY_CTRL3_ADDR 0x00C ++#define PHY_CTRL4_ADDR 0x010 ++#define PHY_MISC_ADDR 0x024 ++#define PHY_IPG_ADDR 0x030 ++ ++#define PHY_CTRL0_VAL 0xA4600015 ++#define PHY_CTRL1_VAL 0x09500000 ++#define PHY_CTRL2_VAL 0x00058180 ++#define PHY_CTRL3_VAL 0x6DB6DCD6 ++#define PHY_CTRL4_VAL 0x836DB6DB ++#define PHY_MISC_VAL 0x3803FB0C ++#define PHY_IPG_VAL 0x47323232 ++ ++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); ++ ++ writel(PHY_CTRL0_VAL, phy->base + PHY_CTRL0_ADDR); ++ writel(PHY_CTRL1_VAL, phy->base + PHY_CTRL1_ADDR); ++ writel(PHY_CTRL2_VAL, phy->base + PHY_CTRL2_ADDR); ++ writel(PHY_CTRL3_VAL, phy->base + PHY_CTRL3_ADDR); ++ writel(PHY_CTRL4_VAL, phy->base + PHY_CTRL4_ADDR); ++ writel(PHY_MISC_VAL, phy->base + PHY_MISC_ADDR); ++ writel(PHY_IPG_VAL, phy->base + PHY_IPG_ADDR); ++ 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; ++ const struct of_device_id *match; ++ ++ match = of_match_device(ipq4019_usb_phy_of_match, &pdev->dev); ++ if (!match) ++ return -ENODEV; ++ ++ 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, match->data); ++ 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 "); ++MODULE_LICENSE("GPL v2"); +--- 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_QMP) += phy-qcom-qmp.o + obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o diff --git a/target/linux/ipq40xx/patches-4.19/077-qcom-ipq4019-add-USB-devicetree-nodes.patch b/target/linux/ipq40xx/patches-4.19/077-qcom-ipq4019-add-USB-devicetree-nodes.patch new file mode 100644 index 000000000..ff6fb4b57 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/077-qcom-ipq4019-add-USB-devicetree-nodes.patch @@ -0,0 +1,123 @@ +From 1fc7d5523e21ed140fed43c4dde011a3b6d9ba08 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 24 Jul 2018 14:47:55 +0200 +Subject: [PATCH 3/3] qcom: ipq4019: add USB devicetree nodes + +This patch makes USB work on the Dakota EVB. + +Signed-off-by: John Crispin +--- + arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi | 20 ++++++++ + arch/arm/boot/dts/qcom-ipq4019.dtsi | 74 +++++++++++++++++++++++++++ + 2 files changed, 94 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi +@@ -109,5 +109,25 @@ + wifi@a800000 { + status = "ok"; + }; ++ ++ usb3_ss_phy: ssphy@9a000 { ++ status = "ok"; ++ }; ++ ++ usb3_hs_phy: hsphy@a6000 { ++ status = "ok"; ++ }; ++ ++ usb3: usb3@8af8800 { ++ status = "ok"; ++ }; ++ ++ usb2_hs_phy: hsphy@a8000 { ++ status = "ok"; ++ }; ++ ++ usb2: usb2@60f8800 { ++ status = "ok"; ++ }; + }; + }; +--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi +@@ -564,5 +564,79 @@ + "legacy"; + status = "disabled"; + }; ++ ++ 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@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 = ; ++ 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@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 = ; ++ phys = <&usb2_hs_phy>; ++ phy-names = "usb2-phy"; ++ dr_mode = "host"; ++ }; ++ }; + }; + }; diff --git a/target/linux/ipq40xx/patches-4.19/079-v4.20-ARM-dts-qcom-ipq4019-fix-PCI-range.patch b/target/linux/ipq40xx/patches-4.19/079-v4.20-ARM-dts-qcom-ipq4019-fix-PCI-range.patch new file mode 100644 index 000000000..6bfea2a5c --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/079-v4.20-ARM-dts-qcom-ipq4019-fix-PCI-range.patch @@ -0,0 +1,25 @@ +From da89f500cb55fb3f19c4b399b46d8add0abbd4d6 Mon Sep 17 00:00:00 2001 +From: Mathias Kresin +Date: Wed, 25 Jul 2018 10:37:48 +0200 +Subject: [PATCH] ARM: dts: qcom: ipq4019: fix PCI range + +The PCI range is invalid and PCI attached devices doen't work. + +Signed-off-by: Mathias Kresin +Signed-off-by: John Crispin +Signed-off-by: Andy Gross +--- + 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 +@@ -401,7 +401,7 @@ + #size-cells = <2>; + + ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000 +- 0x82000000 0 0x48000000 0x48000000 0 0x10000000>; ++ 0x82000000 0 0x40300000 0x40300000 0 0x400000>; + + interrupts = ; + interrupt-names = "msi"; diff --git a/target/linux/ipq40xx/patches-4.19/080-ARM-dts-qcom-add-gpio-ranges-property.patch b/target/linux/ipq40xx/patches-4.19/080-ARM-dts-qcom-add-gpio-ranges-property.patch new file mode 100644 index 000000000..67522f5cf --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/080-ARM-dts-qcom-add-gpio-ranges-property.patch @@ -0,0 +1,70 @@ +From patchwork Mon May 21 20:57:38 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v5,3/4] ARM: dts: qcom: add gpio-ranges property +X-Patchwork-Submitter: Christian Lamparter +X-Patchwork-Id: 917856 +Message-Id: <0ae3376606a89bcdf3fe753a5c967f7103699e09.1526935804.git.chunkeey@gmail.com> +To: linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org +Cc: Bjorn Andersson , + Linus Walleij , + Stephen Boyd , David Brown , + Rob Herring , Mark Rutland , + Andy Gross , + Sven Eckelmann +Date: Mon, 21 May 2018 22:57:38 +0200 +From: Christian Lamparter +List-Id: + +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 +Tested-by: Sven Eckelmann [ipq4019] +Reviewed-by: Bjorn Andersson +Signed-off-by: Christian Lamparter +Reviewed-by: Linus Walleij +--- +To help with git bisect, the DT update patch has been intentionally +placed after the "pinctrl: msm: fix gpio-hog related boot issues". +Otherwise - if the order was reveresed - and bisect decides to split +between these two patches, the gpiochip_add_pin_ranges() function +will be executed twice with the same parameters for the same pinctrl. +--- + 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 + + arch/arm64/boot/dts/qcom/ipq8074.dtsi | 3 ++- + arch/arm64/boot/dts/qcom/msm8916.dtsi | 1 + + arch/arm64/boot/dts/qcom/msm8992.dtsi | 1 + + arch/arm64/boot/dts/qcom/msm8994.dtsi | 1 + + arch/arm64/boot/dts/qcom/msm8996.dtsi | 1 + + 13 files changed, 14 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi +@@ -202,6 +202,7 @@ + compatible = "qcom,ipq4019-pinctrl"; + reg = <0x01000000 0x300000>; + gpio-controller; ++ gpio-ranges = <&tlmm 0 0 100>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; diff --git a/target/linux/ipq40xx/patches-4.19/081-clk-fix-apss-cpu-overclocking.patch b/target/linux/ipq40xx/patches-4.19/081-clk-fix-apss-cpu-overclocking.patch new file mode 100644 index 000000000..de9979254 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/081-clk-fix-apss-cpu-overclocking.patch @@ -0,0 +1,115 @@ +From f2b87dc1028b710ec8ce25808b9d21f92b376184 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +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 +Signed-off-by: John Crispin +--- + 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 +@@ -1251,6 +1251,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 +@@ -1263,7 +1286,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; + +@@ -1286,7 +1309,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; + +@@ -1313,6 +1336,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; +@@ -1333,7 +1357,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 = { diff --git a/target/linux/ipq40xx/patches-4.19/082-v4.20-mtd-spinand-winbond-Add-support-for-W25N01GV.patch b/target/linux/ipq40xx/patches-4.19/082-v4.20-mtd-spinand-winbond-Add-support-for-W25N01GV.patch new file mode 100644 index 000000000..22bd98512 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/082-v4.20-mtd-spinand-winbond-Add-support-for-W25N01GV.patch @@ -0,0 +1,31 @@ +From 342fc01bfd6d717602c71d96d3ef40a36e45e060 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Fri, 5 Oct 2018 09:02:50 +0200 +Subject: [PATCH] mtd: spinand: winbond: Add support for W25N01GV + +W25N01GV is a single die version of the already supported +W25M02GV with half the capacity. Everything else is the +same so introduce support for W25N01GV. + +Signed-off-by: Robert Marko +--- + drivers/mtd/nand/spi/winbond.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -84,6 +84,14 @@ static const struct spinand_info winbond + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), + SPINAND_SELECT_TARGET(w25m02gv_select_target)), ++ SPINAND_INFO("W25N01GV", 0xAA, ++ NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), ++ NAND_ECCREQ(1, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ 0, ++ SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), + }; + + /** diff --git a/target/linux/ipq40xx/patches-4.19/303-spi-nor-enable-4B-opcodes-for-mx25l25635f.patch b/target/linux/ipq40xx/patches-4.19/303-spi-nor-enable-4B-opcodes-for-mx25l25635f.patch new file mode 100644 index 000000000..bcc6f6566 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/303-spi-nor-enable-4B-opcodes-for-mx25l25635f.patch @@ -0,0 +1,62 @@ +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -1092,6 +1092,7 @@ static const struct flash_info spi_nor_i + { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, + { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, + { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "mx25l25635f", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, + { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, + { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +@@ -1274,11 +1275,12 @@ static const struct flash_info spi_nor_i + { }, + }; + +-static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) ++static const struct flash_info *spi_nor_read_id(struct spi_nor *nor, ++ const char *name) + { + int tmp; + u8 id[SPI_NOR_MAX_ID_LEN]; +- const struct flash_info *info; ++ const struct flash_info *info, *first_match = NULL; + + tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); + if (tmp < 0) { +@@ -1289,10 +1291,16 @@ static const struct flash_info *spi_nor_ + for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { + info = &spi_nor_ids[tmp]; + if (info->id_len) { +- if (!memcmp(info->id, id, info->id_len)) +- return &spi_nor_ids[tmp]; ++ if (!memcmp(info->id, id, info->id_len)) { ++ if (!name || !strcmp(name, info->name)) ++ return info; ++ if (!first_match) ++ first_match = info; ++ } + } + } ++ if (first_match) ++ return first_match; + dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n", + id[0], id[1], id[2]); + return ERR_PTR(-ENODEV); +@@ -2826,7 +2834,7 @@ int spi_nor_scan(struct spi_nor *nor, co + info = spi_nor_match_id(name); + /* Try to auto-detect if chip name wasn't specified or not found */ + if (!info) +- info = spi_nor_read_id(nor); ++ info = spi_nor_read_id(nor, NULL); + if (IS_ERR_OR_NULL(info)) + return -ENOENT; + +@@ -2837,7 +2845,7 @@ int spi_nor_scan(struct spi_nor *nor, co + if (name && info->id_len) { + const struct flash_info *jinfo; + +- jinfo = spi_nor_read_id(nor); ++ jinfo = spi_nor_read_id(nor, name); + if (IS_ERR(jinfo)) { + return PTR_ERR(jinfo); + } else if (jinfo != info) { diff --git a/target/linux/ipq40xx/patches-4.19/700-net-add-qualcomm-mdio-and-phy.patch b/target/linux/ipq40xx/patches-4.19/700-net-add-qualcomm-mdio-and-phy.patch new file mode 100644 index 000000000..58ae6b990 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/700-net-add-qualcomm-mdio-and-phy.patch @@ -0,0 +1,2690 @@ +From 5a71a2005a2e1e6bbe36f00386c495ad6626beb2 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Thu, 19 Jan 2017 01:59:43 +0100 +Subject: [PATCH 30/38] NET: add qualcomm mdio and PHY + +--- + drivers/net/phy/Kconfig | 14 ++++++++++++++ + drivers/net/phy/Makefile | 2 ++ + 2 files changed, 16 insertions(+) + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -519,6 +519,20 @@ config XILINX_GMII2RGMII + the Reduced Gigabit Media Independent Interface(RGMII) between + Ethernet physical media devices and the Gigabit Ethernet controller. + ++config MDIO_IPQ40XX ++ tristate "Qualcomm Atheros ipq40xx MDIO interface" ++ depends on HAS_IOMEM && OF ++ ---help--- ++ This driver supports the MDIO interface found in Qualcomm ++ Atheros ipq40xx Soc chip. ++ ++config AR40XX_PHY ++ tristate "Driver for Qualcomm Atheros IPQ40XX switches" ++ depends on HAS_IOMEM && OF ++ 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 +@@ -48,6 +48,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_IPQ40XX) += mdio-ipq40xx.o + obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o + obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o + obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o +@@ -61,6 +62,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) + + obj-$(CONFIG_AMD_PHY) += amd.o + obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o ++obj-$(CONFIG_AR40XX_PHY) += ar40xx.o + obj-$(CONFIG_ASIX_PHY) += asix.o + obj-$(CONFIG_AT803X_PHY) += at803x.o + obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o +--- /dev/null ++++ b/drivers/net/phy/ar40xx.c +@@ -0,0 +1,2090 @@ ++/* ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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_rmw(priv, AR40XX_REG_PORT_STATUS(port), ++ AR40XX_PORT_AUTO_LINK_EN, 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 void ++ar40xx_malibu_init(struct ar40xx_priv *priv) ++{ ++ int i; ++ struct mii_bus *bus; ++ u16 val; ++ ++ bus = priv->mii_bus; ++ ++ /* war to enable AZ transmitting ability */ ++ ar40xx_phy_mmd_write(priv, AR40XX_PSGMII_ID, 1, ++ AR40XX_MALIBU_PSGMII_MODE_CTRL, ++ AR40XX_MALIBU_PHY_PSGMII_MODE_CTRL_ADJUST_VAL); ++ for (i = 0; i < AR40XX_NUM_PORTS - 1; i++) { ++ /* change malibu control_dac */ ++ val = ar40xx_phy_mmd_read(priv, i, 7, ++ AR40XX_MALIBU_PHY_MMD7_DAC_CTRL); ++ val &= ~AR40XX_MALIBU_DAC_CTRL_MASK; ++ val |= AR40XX_MALIBU_DAC_CTRL_VALUE; ++ ar40xx_phy_mmd_write(priv, i, 7, ++ AR40XX_MALIBU_PHY_MMD7_DAC_CTRL, val); ++ if (i == AR40XX_MALIBU_PHY_LAST_ADDR) { ++ /* to avoid goes into hibernation */ ++ val = ar40xx_phy_mmd_read(priv, i, 3, ++ AR40XX_MALIBU_PHY_RLP_CTRL); ++ val &= (~(1<<1)); ++ ar40xx_phy_mmd_write(priv, i, 3, ++ AR40XX_MALIBU_PHY_RLP_CTRL, val); ++ } ++ } ++ ++ /* adjust psgmii serdes tx amp */ ++ mdiobus_write(bus, AR40XX_PSGMII_ID, AR40XX_PSGMII_TX_DRIVER_1_CTRL, ++ AR40XX_MALIBU_PHY_PSGMII_REDUCE_SERDES_TX_AMP); ++} ++ ++static int ++ar40xx_hw_init(struct ar40xx_priv *priv) ++{ ++ u32 i; ++ ++ ar40xx_ess_reset(priv); ++ ++ if (priv->mii_bus) ++ ar40xx_malibu_init(priv); ++ else ++ 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 = link = duplex = port_phy_status[i]; ++ speed &= AR40XX_PHY_SPEC_STATUS_SPEED; ++ speed >>= 14; ++ link &= AR40XX_PHY_SPEC_STATUS_LINK; ++ link >>= 10; ++ duplex &= AR40XX_PHY_SPEC_STATUS_DUPLEX; ++ duplex >>= 13; ++ ++ 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, ++}; ++ ++/* Start of phy driver support */ ++ ++static const u32 ar40xx_phy_ids[] = { ++ 0x004dd0b1, ++ 0x004dd0b2, /* AR40xx */ ++}; ++ ++static bool ++ar40xx_phy_match(u32 phy_id) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ar40xx_phy_ids); i++) ++ if (phy_id == ar40xx_phy_ids[i]) ++ return true; ++ ++ return false; ++} ++ ++static bool ++is_ar40xx_phy(struct mii_bus *bus) ++{ ++ unsigned i; ++ ++ for (i = 0; i < 4; i++) { ++ u32 phy_id; ++ ++ phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16; ++ phy_id |= mdiobus_read(bus, i, MII_PHYSID2); ++ if (!ar40xx_phy_match(phy_id)) ++ return false; ++ } ++ ++ return true; ++} ++ ++static int ++ar40xx_phy_probe(struct phy_device *phydev) ++{ ++ if (!is_ar40xx_phy(phydev->mdio.bus)) ++ return -ENODEV; ++ ++ ar40xx_priv->mii_bus = phydev->mdio.bus; ++ phydev->priv = ar40xx_priv; ++ if (phydev->mdio.addr == 0) ++ ar40xx_priv->phy = phydev; ++ ++ phydev->supported |= SUPPORTED_1000baseT_Full; ++ phydev->advertising |= ADVERTISED_1000baseT_Full; ++ return 0; ++} ++ ++static void ++ar40xx_phy_remove(struct phy_device *phydev) ++{ ++ ar40xx_priv->mii_bus = NULL; ++ phydev->priv = NULL; ++} ++ ++static int ++ar40xx_phy_config_init(struct phy_device *phydev) ++{ ++ return 0; ++} ++ ++static int ++ar40xx_phy_read_status(struct phy_device *phydev) ++{ ++ if (phydev->mdio.addr != 0) ++ return genphy_read_status(phydev); ++ ++ return 0; ++} ++ ++static int ++ar40xx_phy_config_aneg(struct phy_device *phydev) ++{ ++ if (phydev->mdio.addr == 0) ++ return 0; ++ ++ return genphy_config_aneg(phydev); ++} ++ ++static struct phy_driver ar40xx_phy_driver = { ++ .phy_id = 0x004d0000, ++ .name = "QCA Malibu", ++ .phy_id_mask = 0xffff0000, ++ .features = PHY_BASIC_FEATURES, ++ .probe = ar40xx_phy_probe, ++ .remove = ar40xx_phy_remove, ++ .config_init = ar40xx_phy_config_init, ++ .config_aneg = ar40xx_phy_config_aneg, ++ .read_status = ar40xx_phy_read_status, ++}; ++ ++static uint16_t ar40xx_gpio_get_phy(unsigned int offset) ++{ ++ return offset / 4; ++} ++ ++static uint16_t ar40xx_gpio_get_reg(unsigned int offset) ++{ ++ return 0x8074 + offset % 4; ++} ++ ++static void ar40xx_gpio_set(struct gpio_chip *gc, unsigned int offset, ++ int value) ++{ ++ struct ar40xx_priv *priv = gpiochip_get_data(gc); ++ ++ ar40xx_phy_mmd_write(priv, ar40xx_gpio_get_phy(offset), 0x7, ++ ar40xx_gpio_get_reg(offset), ++ value ? 0xA000 : 0x8000); ++} ++ ++static int ar40xx_gpio_get(struct gpio_chip *gc, unsigned offset) ++{ ++ struct ar40xx_priv *priv = gpiochip_get_data(gc); ++ ++ return ar40xx_phy_mmd_read(priv, ar40xx_gpio_get_phy(offset), 0x7, ++ ar40xx_gpio_get_reg(offset)) == 0xA000; ++} ++ ++static int ar40xx_gpio_get_dir(struct gpio_chip *gc, unsigned offset) ++{ ++ return 0; /* only out direction */ ++} ++ ++static int ar40xx_gpio_dir_out(struct gpio_chip *gc, unsigned offset, ++ int value) ++{ ++ /* ++ * the direction out value is used to set the initial value. ++ * support of this function is required by leds-gpio.c ++ */ ++ ar40xx_gpio_set(gc, offset, value); ++ return 0; ++} ++ ++static void ar40xx_register_gpio(struct device *pdev, ++ struct ar40xx_priv *priv, ++ struct device_node *switch_node) ++{ ++ struct gpio_chip *gc; ++ int err; ++ ++ gc = devm_kzalloc(pdev, sizeof(*gc), GFP_KERNEL); ++ if (!gc) ++ return; ++ ++ gc->label = "ar40xx_gpio", ++ gc->base = -1, ++ gc->ngpio = 5 /* mmd 0 - 4 */ * 4 /* 0x8074 - 0x8077 */, ++ gc->parent = pdev; ++ gc->owner = THIS_MODULE; ++ ++ gc->get_direction = ar40xx_gpio_get_dir; ++ gc->direction_output = ar40xx_gpio_dir_out; ++ gc->get = ar40xx_gpio_get; ++ gc->set = ar40xx_gpio_set; ++ gc->can_sleep = true; ++ gc->label = priv->dev.name; ++ gc->of_node = switch_node; ++ ++ err = devm_gpiochip_add_data(pdev, gc, priv); ++ if (err != 0) ++ dev_err(pdev, "Failed to register gpio %d.\n", err); ++} ++ ++/* End of phy driver support */ ++ ++/* Platform driver probe function */ ++ ++static int ar40xx_probe(struct platform_device *pdev) ++{ ++ struct device_node *switch_node; ++ struct device_node *psgmii_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; ++ } ++ ++ ret = phy_driver_register(&ar40xx_phy_driver, THIS_MODULE); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register ar40xx phy driver!\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; ++ ++ 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) ++ goto err_unregister_phy; ++ ++ 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); ++ ++ if (of_property_read_bool(switch_node, "gpio-controller")) ++ ar40xx_register_gpio(&pdev->dev, ar40xx_priv, switch_node); ++ ++ return 0; ++ ++err_unregister_switch: ++ unregister_switch(&priv->dev); ++err_unregister_phy: ++ phy_driver_unregister(&ar40xx_phy_driver); ++ 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); ++ ++ phy_driver_unregister(&ar40xx_phy_driver); ++ ++ 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"); +--- /dev/null ++++ b/drivers/net/phy/ar40xx.h +@@ -0,0 +1,337 @@ ++/* ++ * 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_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_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 +--- /dev/null ++++ b/drivers/net/phy/mdio-ipq40xx.c +@@ -0,0 +1,203 @@ ++/* ++ * Copyright (c) 2015-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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MDIO_CTRL_0_REG 0x40 ++#define MDIO_CTRL_1_REG 0x44 ++#define MDIO_CTRL_2_REG 0x48 ++#define MDIO_CTRL_3_REG 0x4c ++#define MDIO_CTRL_4_REG 0x50 ++#define MDIO_CTRL_4_ACCESS_BUSY BIT(16) ++#define MDIO_CTRL_4_ACCESS_START BIT(8) ++#define MDIO_CTRL_4_ACCESS_CODE_READ 0 ++#define MDIO_CTRL_4_ACCESS_CODE_WRITE 1 ++#define CTRL_0_REG_DEFAULT_VALUE 0x150FF ++ ++#define IPQ40XX_MDIO_RETRY 1000 ++#define IPQ40XX_MDIO_DELAY 10 ++ ++struct ipq40xx_mdio_data { ++ struct mii_bus *mii_bus; ++ void __iomem *membase; ++ int phy_irq[PHY_MAX_ADDR]; ++ struct device *dev; ++}; ++ ++static int ipq40xx_mdio_wait_busy(struct ipq40xx_mdio_data *am) ++{ ++ int i; ++ ++ for (i = 0; i < IPQ40XX_MDIO_RETRY; i++) { ++ unsigned int busy; ++ ++ busy = readl(am->membase + MDIO_CTRL_4_REG) & ++ MDIO_CTRL_4_ACCESS_BUSY; ++ if (!busy) ++ return 0; ++ ++ /* BUSY might take to be cleard by 15~20 times of loop */ ++ udelay(IPQ40XX_MDIO_DELAY); ++ } ++ ++ dev_err(am->dev, "%s: MDIO operation timed out\n", am->mii_bus->name); ++ ++ return -ETIMEDOUT; ++} ++ ++static int ipq40xx_mdio_read(struct mii_bus *bus, int mii_id, int regnum) ++{ ++ struct ipq40xx_mdio_data *am = bus->priv; ++ int value = 0; ++ unsigned int cmd = 0; ++ ++ lockdep_assert_held(&bus->mdio_lock); ++ ++ if (ipq40xx_mdio_wait_busy(am)) ++ return -ETIMEDOUT; ++ ++ /* issue the phy address and reg */ ++ writel((mii_id << 8) | regnum, am->membase + MDIO_CTRL_1_REG); ++ ++ cmd = MDIO_CTRL_4_ACCESS_START|MDIO_CTRL_4_ACCESS_CODE_READ; ++ ++ /* issue read command */ ++ writel(cmd, am->membase + MDIO_CTRL_4_REG); ++ ++ /* Wait read complete */ ++ if (ipq40xx_mdio_wait_busy(am)) ++ return -ETIMEDOUT; ++ ++ /* Read data */ ++ value = readl(am->membase + MDIO_CTRL_3_REG); ++ ++ return value; ++} ++ ++static int ipq40xx_mdio_write(struct mii_bus *bus, int mii_id, int regnum, ++ u16 value) ++{ ++ struct ipq40xx_mdio_data *am = bus->priv; ++ unsigned int cmd = 0; ++ ++ lockdep_assert_held(&bus->mdio_lock); ++ ++ if (ipq40xx_mdio_wait_busy(am)) ++ return -ETIMEDOUT; ++ ++ /* issue the phy address and reg */ ++ writel((mii_id << 8) | regnum, am->membase + MDIO_CTRL_1_REG); ++ ++ /* issue write data */ ++ writel(value, am->membase + MDIO_CTRL_2_REG); ++ ++ cmd = MDIO_CTRL_4_ACCESS_START|MDIO_CTRL_4_ACCESS_CODE_WRITE; ++ /* issue write command */ ++ writel(cmd, am->membase + MDIO_CTRL_4_REG); ++ ++ /* Wait write complete */ ++ if (ipq40xx_mdio_wait_busy(am)) ++ return -ETIMEDOUT; ++ ++ return 0; ++} ++ ++static int ipq40xx_mdio_probe(struct platform_device *pdev) ++{ ++ struct ipq40xx_mdio_data *am; ++ struct resource *res; ++ int i; ++ ++ am = devm_kzalloc(&pdev->dev, sizeof(*am), GFP_KERNEL); ++ if (!am) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "no iomem resource found\n"); ++ return -ENXIO; ++ } ++ ++ am->membase = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(am->membase)) { ++ dev_err(&pdev->dev, "unable to ioremap registers\n"); ++ return PTR_ERR(am->membase); ++ } ++ ++ am->mii_bus = devm_mdiobus_alloc(&pdev->dev); ++ if (!am->mii_bus) ++ return -ENOMEM; ++ ++ writel(CTRL_0_REG_DEFAULT_VALUE, am->membase + MDIO_CTRL_0_REG); ++ ++ am->mii_bus->name = "ipq40xx_mdio"; ++ am->mii_bus->read = ipq40xx_mdio_read; ++ am->mii_bus->write = ipq40xx_mdio_write; ++ memcpy(am->mii_bus->irq, am->phy_irq, sizeof(am->phy_irq)); ++ am->mii_bus->priv = am; ++ am->mii_bus->parent = &pdev->dev; ++ snprintf(am->mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(&pdev->dev)); ++ ++ for (i = 0; i < PHY_MAX_ADDR; i++) ++ am->phy_irq[i] = PHY_POLL; ++ ++ am->dev = &pdev->dev; ++ platform_set_drvdata(pdev, am); ++ ++ /* edma_axi_probe() use "am" drvdata. ++ * ipq40xx_mdio_probe() must be called first. ++ */ ++ return of_mdiobus_register(am->mii_bus, pdev->dev.of_node); ++} ++ ++static int ipq40xx_mdio_remove(struct platform_device *pdev) ++{ ++ struct ipq40xx_mdio_data *am = platform_get_drvdata(pdev); ++ ++ mdiobus_unregister(am->mii_bus); ++ return 0; ++} ++ ++static const struct of_device_id ipq40xx_mdio_dt_ids[] = { ++ { .compatible = "qcom,ipq4019-mdio" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ipq40xx_mdio_dt_ids); ++ ++static struct platform_driver ipq40xx_mdio_driver = { ++ .probe = ipq40xx_mdio_probe, ++ .remove = ipq40xx_mdio_remove, ++ .driver = { ++ .name = "ipq40xx-mdio", ++ .of_match_table = ipq40xx_mdio_dt_ids, ++ }, ++}; ++ ++module_platform_driver(ipq40xx_mdio_driver); ++ ++#define DRV_VERSION "1.0" ++ ++MODULE_DESCRIPTION("IPQ40XX MDIO interface driver"); ++MODULE_AUTHOR("Qualcomm Atheros"); ++MODULE_VERSION(DRV_VERSION); ++MODULE_LICENSE("Dual BSD/GPL"); diff --git a/target/linux/ipq40xx/patches-4.19/701-dts-ipq4019-add-mdio-node.patch b/target/linux/ipq40xx/patches-4.19/701-dts-ipq4019-add-mdio-node.patch new file mode 100644 index 000000000..0e1bb8736 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/701-dts-ipq4019-add-mdio-node.patch @@ -0,0 +1,52 @@ +From 09ed737593f71bcca08a537a6c15264a1a6add08 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Sun, 20 Nov 2016 01:10:33 +0100 +Subject: [PATCH] dts: ipq4019: add mdio node for ethernet + +This patch adds the mdio device-tree node. +This is where the switch is connected to, so it's needed +for the ethernet interfaces. + +Note: The driver isn't anywhere close to be upstream, +so the info might change. +--- + 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 +@@ -566,6 +566,34 @@ + status = "disabled"; + }; + ++ mdio@90000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "qcom,ipq4019-mdio"; ++ reg = <0x90000 0x64>; ++ status = "disabled"; ++ ++ ethernet-phy@0 { ++ reg = <0>; ++ }; ++ ++ ethernet-phy@1 { ++ reg = <1>; ++ }; ++ ++ ethernet-phy@2 { ++ reg = <2>; ++ }; ++ ++ ethernet-phy@3 { ++ reg = <3>; ++ }; ++ ++ ethernet-phy@4 { ++ reg = <4>; ++ }; ++ }; ++ + usb3_ss_phy: ssphy@9a000 { + compatible = "qcom,usb-ss-ipq4019-phy"; + #phy-cells = <0>; diff --git a/target/linux/ipq40xx/patches-4.19/702-dts-ipq4019-add-PHY-switch-nodes.patch b/target/linux/ipq40xx/patches-4.19/702-dts-ipq4019-add-PHY-switch-nodes.patch new file mode 100644 index 000000000..03da6c863 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/702-dts-ipq4019-add-PHY-switch-nodes.patch @@ -0,0 +1,46 @@ +From 9deeec35dd3b628b95624e41d4e04acf728991ba Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +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 +--- + 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 +@@ -594,6 +594,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>; diff --git a/target/linux/ipq40xx/patches-4.19/703-net-IPQ4019-needs-rfs-vlan_tag-callbacks-in.patch b/target/linux/ipq40xx/patches-4.19/703-net-IPQ4019-needs-rfs-vlan_tag-callbacks-in.patch new file mode 100644 index 000000000..cc7e49736 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/703-net-IPQ4019-needs-rfs-vlan_tag-callbacks-in.patch @@ -0,0 +1,53 @@ +From 7c129254adb1093d10a62ed7bf7b956fcc6ffe34 Mon Sep 17 00:00:00 2001 +From: Rakesh Nair +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 +Reviewed-on: https://chromium-review.googlesource.com/362203 +Commit-Ready: Grant Grundler +Tested-by: Grant Grundler +Reviewed-by: Grant Grundler +--- + include/linux/netdevice.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -739,6 +739,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. + */ +@@ -1353,6 +1363,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, diff --git a/target/linux/ipq40xx/patches-4.19/710-net-add-qualcomm-essedma-ethernet-driver.patch b/target/linux/ipq40xx/patches-4.19/710-net-add-qualcomm-essedma-ethernet-driver.patch new file mode 100644 index 000000000..9fe3a1a9d --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/710-net-add-qualcomm-essedma-ethernet-driver.patch @@ -0,0 +1,4575 @@ +From 12e9319da1adacac92930c899c99f0e1970cac11 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Thu, 19 Jan 2017 02:01:31 +0100 +Subject: [PATCH 33/38] NET: add qualcomm essedma ethernet driver + +Signed-off-by: Christian Lamparter +--- + 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 +@@ -61,4 +61,13 @@ config QCOM_EMAC + + source "drivers/net/ethernet/qualcomm/rmnet/Kconfig" + ++config ESSEDMA ++ tristate "Qualcomm Atheros ESS Edma support" ++ ---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/ +--- /dev/null ++++ b/drivers/net/ethernet/qualcomm/essedma/Makefile +@@ -0,0 +1,9 @@ ++# ++## Makefile for the Qualcomm Atheros ethernet edma driver ++# ++ ++ ++obj-$(CONFIG_ESSEDMA) += essedma.o ++ ++essedma-objs := edma_axi.o edma.o edma_ethtool.o ++ +--- /dev/null ++++ b/drivers/net/ethernet/qualcomm/essedma/edma.c +@@ -0,0 +1,2143 @@ ++/* ++ * Copyright (c) 2014 - 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 ++#include ++#include "ess_edma.h" ++#include "edma.h" ++ ++extern struct net_device *edma_netdev[EDMA_MAX_PORTID_SUPPORTED]; ++bool edma_stp_rstp; ++u16 edma_ath_eth_type; ++ ++/* edma_skb_priority_offset() ++ * get edma skb priority ++ */ ++static unsigned int edma_skb_priority_offset(struct sk_buff *skb) ++{ ++ return (skb->priority >> 2) & 1; ++} ++ ++/* edma_alloc_tx_ring() ++ * Allocate Tx descriptors ring ++ */ ++static int edma_alloc_tx_ring(struct edma_common_info *edma_cinfo, ++ struct edma_tx_desc_ring *etdr) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ ++ /* Initialize ring */ ++ etdr->size = sizeof(struct edma_sw_desc) * etdr->count; ++ etdr->sw_next_to_fill = 0; ++ etdr->sw_next_to_clean = 0; ++ ++ /* Allocate SW descriptors */ ++ etdr->sw_desc = vzalloc(etdr->size); ++ if (!etdr->sw_desc) { ++ dev_err(&pdev->dev, "buffer alloc of tx ring failed=%p", etdr); ++ return -ENOMEM; ++ } ++ ++ /* Allocate HW descriptors */ ++ etdr->hw_desc = dma_alloc_coherent(&pdev->dev, etdr->size, &etdr->dma, ++ GFP_KERNEL); ++ if (!etdr->hw_desc) { ++ dev_err(&pdev->dev, "descriptor allocation for tx ring failed"); ++ vfree(etdr->sw_desc); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++/* edma_free_tx_ring() ++ * Free tx rings allocated by edma_alloc_tx_rings ++ */ ++static void edma_free_tx_ring(struct edma_common_info *edma_cinfo, ++ struct edma_tx_desc_ring *etdr) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ ++ if (likely(etdr->dma)) ++ dma_free_coherent(&pdev->dev, etdr->size, etdr->hw_desc, ++ etdr->dma); ++ ++ vfree(etdr->sw_desc); ++ etdr->sw_desc = NULL; ++} ++ ++/* edma_alloc_rx_ring() ++ * allocate rx descriptor ring ++ */ ++static int edma_alloc_rx_ring(struct edma_common_info *edma_cinfo, ++ struct edma_rfd_desc_ring *erxd) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ ++ erxd->size = sizeof(struct edma_sw_desc) * erxd->count; ++ erxd->sw_next_to_fill = 0; ++ erxd->sw_next_to_clean = 0; ++ ++ /* Allocate SW descriptors */ ++ erxd->sw_desc = vzalloc(erxd->size); ++ if (!erxd->sw_desc) ++ return -ENOMEM; ++ ++ /* Alloc HW descriptors */ ++ erxd->hw_desc = dma_alloc_coherent(&pdev->dev, erxd->size, &erxd->dma, ++ GFP_KERNEL); ++ if (!erxd->hw_desc) { ++ vfree(erxd->sw_desc); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++/* edma_free_rx_ring() ++ * Free rx ring allocated by alloc_rx_ring ++ */ ++static void edma_free_rx_ring(struct edma_common_info *edma_cinfo, ++ struct edma_rfd_desc_ring *rxdr) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ ++ if (likely(rxdr->dma)) ++ dma_free_coherent(&pdev->dev, rxdr->size, rxdr->hw_desc, ++ rxdr->dma); ++ ++ vfree(rxdr->sw_desc); ++ rxdr->sw_desc = NULL; ++} ++ ++/* edma_configure_tx() ++ * Configure transmission control data ++ */ ++static void edma_configure_tx(struct edma_common_info *edma_cinfo) ++{ ++ u32 txq_ctrl_data; ++ ++ txq_ctrl_data = (EDMA_TPD_BURST << EDMA_TXQ_NUM_TPD_BURST_SHIFT); ++ txq_ctrl_data |= EDMA_TXQ_CTRL_TPD_BURST_EN; ++ txq_ctrl_data |= (EDMA_TXF_BURST << EDMA_TXQ_TXF_BURST_NUM_SHIFT); ++ edma_write_reg(EDMA_REG_TXQ_CTRL, txq_ctrl_data); ++} ++ ++ ++/* edma_configure_rx() ++ * configure reception control data ++ */ ++static void edma_configure_rx(struct edma_common_info *edma_cinfo) ++{ ++ struct edma_hw *hw = &edma_cinfo->hw; ++ u32 rss_type, rx_desc1, rxq_ctrl_data; ++ ++ /* Set RSS type */ ++ rss_type = hw->rss_type; ++ edma_write_reg(EDMA_REG_RSS_TYPE, rss_type); ++ ++ /* Set RFD burst number */ ++ rx_desc1 = (EDMA_RFD_BURST << EDMA_RXQ_RFD_BURST_NUM_SHIFT); ++ ++ /* Set RFD prefetch threshold */ ++ rx_desc1 |= (EDMA_RFD_THR << EDMA_RXQ_RFD_PF_THRESH_SHIFT); ++ ++ /* Set RFD in host ring low threshold to generte interrupt */ ++ rx_desc1 |= (EDMA_RFD_LTHR << EDMA_RXQ_RFD_LOW_THRESH_SHIFT); ++ edma_write_reg(EDMA_REG_RX_DESC1, rx_desc1); ++ ++ /* Set Rx FIFO threshold to start to DMA data to host */ ++ rxq_ctrl_data = EDMA_FIFO_THRESH_128_BYTE; ++ ++ /* Set RX remove vlan bit */ ++ rxq_ctrl_data |= EDMA_RXQ_CTRL_RMV_VLAN; ++ ++ edma_write_reg(EDMA_REG_RXQ_CTRL, rxq_ctrl_data); ++} ++ ++/* edma_alloc_rx_buf() ++ * does skb allocation for the received packets. ++ */ ++static int edma_alloc_rx_buf(struct edma_common_info ++ *edma_cinfo, ++ struct edma_rfd_desc_ring *erdr, ++ int cleaned_count, int queue_id) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ struct edma_rx_free_desc *rx_desc; ++ struct edma_sw_desc *sw_desc; ++ struct sk_buff *skb; ++ unsigned int i; ++ u16 prod_idx, length; ++ u32 reg_data; ++ ++ if (cleaned_count > erdr->count) { ++ dev_err(&pdev->dev, "Incorrect cleaned_count %d", ++ cleaned_count); ++ return -1; ++ } ++ ++ i = erdr->sw_next_to_fill; ++ ++ while (cleaned_count) { ++ sw_desc = &erdr->sw_desc[i]; ++ length = edma_cinfo->rx_head_buffer_len; ++ ++ if (sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_REUSE) { ++ skb = sw_desc->skb; ++ } else { ++ /* alloc skb */ ++ skb = netdev_alloc_skb(edma_netdev[0], length); ++ if (!skb) { ++ /* Better luck next round */ ++ break; ++ } ++ } ++ ++ if (edma_cinfo->page_mode) { ++ struct page *pg = alloc_page(GFP_ATOMIC); ++ ++ if (!pg) { ++ dev_kfree_skb_any(skb); ++ break; ++ } ++ ++ sw_desc->dma = dma_map_page(&pdev->dev, pg, 0, ++ edma_cinfo->rx_page_buffer_len, ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(&pdev->dev, ++ sw_desc->dma)) { ++ __free_page(pg); ++ dev_kfree_skb_any(skb); ++ break; ++ } ++ ++ skb_fill_page_desc(skb, 0, pg, 0, ++ edma_cinfo->rx_page_buffer_len); ++ sw_desc->flags = EDMA_SW_DESC_FLAG_SKB_FRAG; ++ sw_desc->length = edma_cinfo->rx_page_buffer_len; ++ } else { ++ sw_desc->dma = dma_map_single(&pdev->dev, skb->data, ++ length, DMA_FROM_DEVICE); ++ if (dma_mapping_error(&pdev->dev, ++ sw_desc->dma)) { ++ dev_kfree_skb_any(skb); ++ break; ++ } ++ ++ sw_desc->flags = EDMA_SW_DESC_FLAG_SKB_HEAD; ++ sw_desc->length = length; ++ } ++ ++ /* Update the buffer info */ ++ sw_desc->skb = skb; ++ rx_desc = (&((struct edma_rx_free_desc *)(erdr->hw_desc))[i]); ++ rx_desc->buffer_addr = cpu_to_le64(sw_desc->dma); ++ if (++i == erdr->count) ++ i = 0; ++ cleaned_count--; ++ } ++ ++ erdr->sw_next_to_fill = i; ++ ++ if (i == 0) ++ prod_idx = erdr->count - 1; ++ else ++ prod_idx = i - 1; ++ ++ /* Update the producer index */ ++ edma_read_reg(EDMA_REG_RFD_IDX_Q(queue_id), ®_data); ++ reg_data &= ~EDMA_RFD_PROD_IDX_BITS; ++ reg_data |= prod_idx; ++ edma_write_reg(EDMA_REG_RFD_IDX_Q(queue_id), reg_data); ++ return cleaned_count; ++} ++ ++/* edma_init_desc() ++ * update descriptor ring size, buffer and producer/consumer index ++ */ ++static void edma_init_desc(struct edma_common_info *edma_cinfo) ++{ ++ struct edma_rfd_desc_ring *rfd_ring; ++ struct edma_tx_desc_ring *etdr; ++ int i = 0, j = 0; ++ u32 data = 0; ++ u16 hw_cons_idx = 0; ++ ++ /* Set the base address of every TPD ring. */ ++ for (i = 0; i < edma_cinfo->num_tx_queues; i++) { ++ etdr = edma_cinfo->tpd_ring[i]; ++ ++ /* Update descriptor ring base address */ ++ edma_write_reg(EDMA_REG_TPD_BASE_ADDR_Q(i), (u32)etdr->dma); ++ edma_read_reg(EDMA_REG_TPD_IDX_Q(i), &data); ++ ++ /* Calculate hardware consumer index */ ++ hw_cons_idx = (data >> EDMA_TPD_CONS_IDX_SHIFT) & 0xffff; ++ etdr->sw_next_to_fill = hw_cons_idx; ++ etdr->sw_next_to_clean = hw_cons_idx; ++ data &= ~(EDMA_TPD_PROD_IDX_MASK << EDMA_TPD_PROD_IDX_SHIFT); ++ data |= hw_cons_idx; ++ ++ /* update producer index */ ++ edma_write_reg(EDMA_REG_TPD_IDX_Q(i), data); ++ ++ /* update SW consumer index register */ ++ edma_write_reg(EDMA_REG_TX_SW_CONS_IDX_Q(i), hw_cons_idx); ++ ++ /* Set TPD ring size */ ++ edma_write_reg(EDMA_REG_TPD_RING_SIZE, ++ edma_cinfo->tx_ring_count & ++ EDMA_TPD_RING_SIZE_MASK); ++ } ++ ++ for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { ++ rfd_ring = edma_cinfo->rfd_ring[j]; ++ /* Update Receive Free descriptor ring base address */ ++ edma_write_reg(EDMA_REG_RFD_BASE_ADDR_Q(j), ++ (u32)(rfd_ring->dma)); ++ j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); ++ } ++ ++ data = edma_cinfo->rx_head_buffer_len; ++ if (edma_cinfo->page_mode) ++ data = edma_cinfo->rx_page_buffer_len; ++ ++ data &= EDMA_RX_BUF_SIZE_MASK; ++ data <<= EDMA_RX_BUF_SIZE_SHIFT; ++ ++ /* Update RFD ring size and RX buffer size */ ++ data |= (edma_cinfo->rx_ring_count & EDMA_RFD_RING_SIZE_MASK) ++ << EDMA_RFD_RING_SIZE_SHIFT; ++ ++ edma_write_reg(EDMA_REG_RX_DESC0, data); ++ ++ /* Disable TX FIFO low watermark and high watermark */ ++ edma_write_reg(EDMA_REG_TXF_WATER_MARK, 0); ++ ++ /* Load all of base address above */ ++ edma_read_reg(EDMA_REG_TX_SRAM_PART, &data); ++ data |= 1 << EDMA_LOAD_PTR_SHIFT; ++ edma_write_reg(EDMA_REG_TX_SRAM_PART, data); ++} ++ ++/* edma_receive_checksum ++ * Api to check checksum on receive packets ++ */ ++static void edma_receive_checksum(struct edma_rx_return_desc *rd, ++ struct sk_buff *skb) ++{ ++ skb_checksum_none_assert(skb); ++ ++ /* check the RRD IP/L4 checksum bit to see if ++ * its set, which in turn indicates checksum ++ * failure. ++ */ ++ if (rd->rrd6 & EDMA_RRD_CSUM_FAIL_MASK) ++ return; ++ ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++} ++ ++/* edma_clean_rfd() ++ * clean up rx resourcers on error ++ */ ++static void edma_clean_rfd(struct edma_rfd_desc_ring *erdr, u16 index) ++{ ++ struct edma_rx_free_desc *rx_desc; ++ struct edma_sw_desc *sw_desc; ++ ++ rx_desc = (&((struct edma_rx_free_desc *)(erdr->hw_desc))[index]); ++ sw_desc = &erdr->sw_desc[index]; ++ if (sw_desc->skb) { ++ dev_kfree_skb_any(sw_desc->skb); ++ sw_desc->skb = NULL; ++ } ++ ++ memset(rx_desc, 0, sizeof(struct edma_rx_free_desc)); ++} ++ ++/* edma_rx_complete_fraglist() ++ * Complete Rx processing for fraglist skbs ++ */ ++static void edma_rx_complete_stp_rstp(struct sk_buff *skb, int port_id, struct edma_rx_return_desc *rd) ++{ ++ int i; ++ u32 priority; ++ u16 port_type; ++ u8 mac_addr[EDMA_ETH_HDR_LEN]; ++ ++ port_type = (rd->rrd1 >> EDMA_RRD_PORT_TYPE_SHIFT) ++ & EDMA_RRD_PORT_TYPE_MASK; ++ /* if port type is 0x4, then only proceed with ++ * other stp/rstp calculation ++ */ ++ if (port_type == EDMA_RX_ATH_HDR_RSTP_PORT_TYPE) { ++ u8 bpdu_mac[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}; ++ ++ /* calculate the frame priority */ ++ priority = (rd->rrd1 >> EDMA_RRD_PRIORITY_SHIFT) ++ & EDMA_RRD_PRIORITY_MASK; ++ ++ for (i = 0; i < EDMA_ETH_HDR_LEN; i++) ++ mac_addr[i] = skb->data[i]; ++ ++ /* Check if destination mac addr is bpdu addr */ ++ if (!memcmp(mac_addr, bpdu_mac, 6)) { ++ /* destination mac address is BPDU ++ * destination mac address, then add ++ * atheros header to the packet. ++ */ ++ u16 athr_hdr = (EDMA_RX_ATH_HDR_VERSION << EDMA_RX_ATH_HDR_VERSION_SHIFT) | ++ (priority << EDMA_RX_ATH_HDR_PRIORITY_SHIFT) | ++ (EDMA_RX_ATH_HDR_RSTP_PORT_TYPE << EDMA_RX_ATH_PORT_TYPE_SHIFT) | port_id; ++ skb_push(skb, 4); ++ memcpy(skb->data, mac_addr, EDMA_ETH_HDR_LEN); ++ *(uint16_t *)&skb->data[12] = htons(edma_ath_eth_type); ++ *(uint16_t *)&skb->data[14] = htons(athr_hdr); ++ } ++ } ++} ++ ++/* ++ * edma_rx_complete_fraglist() ++ * Complete Rx processing for fraglist skbs ++ */ ++static int edma_rx_complete_fraglist(struct sk_buff *skb, u16 num_rfds, u16 length, u32 sw_next_to_clean, ++ u16 *cleaned_count, struct edma_rfd_desc_ring *erdr, struct edma_common_info *edma_cinfo) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ struct edma_hw *hw = &edma_cinfo->hw; ++ struct sk_buff *skb_temp; ++ struct edma_sw_desc *sw_desc; ++ int i; ++ u16 size_remaining; ++ ++ skb->data_len = 0; ++ skb->tail += (hw->rx_head_buff_size - 16); ++ skb->len = skb->truesize = length; ++ size_remaining = length - (hw->rx_head_buff_size - 16); ++ ++ /* clean-up all related sw_descs */ ++ for (i = 1; i < num_rfds; i++) { ++ struct sk_buff *skb_prev; ++ sw_desc = &erdr->sw_desc[sw_next_to_clean]; ++ skb_temp = sw_desc->skb; ++ ++ dma_unmap_single(&pdev->dev, sw_desc->dma, ++ sw_desc->length, DMA_FROM_DEVICE); ++ ++ if (size_remaining < hw->rx_head_buff_size) ++ skb_put(skb_temp, size_remaining); ++ else ++ skb_put(skb_temp, hw->rx_head_buff_size); ++ ++ /* ++ * If we are processing the first rfd, we link ++ * skb->frag_list to the skb corresponding to the ++ * first RFD ++ */ ++ if (i == 1) ++ skb_shinfo(skb)->frag_list = skb_temp; ++ else ++ skb_prev->next = skb_temp; ++ skb_prev = skb_temp; ++ skb_temp->next = NULL; ++ ++ skb->data_len += skb_temp->len; ++ size_remaining -= skb_temp->len; ++ ++ /* Increment SW index */ ++ sw_next_to_clean = (sw_next_to_clean + 1) & (erdr->count - 1); ++ (*cleaned_count)++; ++ } ++ ++ return sw_next_to_clean; ++} ++ ++/* edma_rx_complete_paged() ++ * Complete Rx processing for paged skbs ++ */ ++static int edma_rx_complete_paged(struct sk_buff *skb, u16 num_rfds, u16 length, u32 sw_next_to_clean, ++ u16 *cleaned_count, struct edma_rfd_desc_ring *erdr, struct edma_common_info *edma_cinfo) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ struct sk_buff *skb_temp; ++ struct edma_sw_desc *sw_desc; ++ int i; ++ u16 size_remaining; ++ ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[0]; ++ ++ /* Setup skbuff fields */ ++ skb->len = length; ++ ++ if (likely(num_rfds <= 1)) { ++ skb->data_len = length; ++ skb->truesize += edma_cinfo->rx_page_buffer_len; ++ skb_fill_page_desc(skb, 0, skb_frag_page(frag), ++ 16, length); ++ } else { ++ frag->size -= 16; ++ skb->data_len = frag->size; ++ skb->truesize += edma_cinfo->rx_page_buffer_len; ++ size_remaining = length - frag->size; ++ ++ skb_fill_page_desc(skb, 0, skb_frag_page(frag), ++ 16, frag->size); ++ ++ /* clean-up all related sw_descs */ ++ for (i = 1; i < num_rfds; i++) { ++ sw_desc = &erdr->sw_desc[sw_next_to_clean]; ++ skb_temp = sw_desc->skb; ++ frag = &skb_shinfo(skb_temp)->frags[0]; ++ dma_unmap_page(&pdev->dev, sw_desc->dma, ++ sw_desc->length, DMA_FROM_DEVICE); ++ ++ if (size_remaining < edma_cinfo->rx_page_buffer_len) ++ frag->size = size_remaining; ++ ++ skb_fill_page_desc(skb, i, skb_frag_page(frag), ++ 0, frag->size); ++ ++ skb_shinfo(skb_temp)->nr_frags = 0; ++ dev_kfree_skb_any(skb_temp); ++ ++ skb->data_len += frag->size; ++ skb->truesize += edma_cinfo->rx_page_buffer_len; ++ size_remaining -= frag->size; ++ ++ /* Increment SW index */ ++ sw_next_to_clean = (sw_next_to_clean + 1) & (erdr->count - 1); ++ (*cleaned_count)++; ++ } ++ } ++ ++ return sw_next_to_clean; ++} ++ ++/* ++ * edma_rx_complete() ++ * Main api called from the poll function to process rx packets. ++ */ ++static void edma_rx_complete(struct edma_common_info *edma_cinfo, ++ int *work_done, int work_to_do, int queue_id, ++ struct napi_struct *napi) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ struct edma_rfd_desc_ring *erdr = edma_cinfo->rfd_ring[queue_id]; ++ struct net_device *netdev; ++ struct edma_adapter *adapter; ++ struct edma_sw_desc *sw_desc; ++ struct sk_buff *skb; ++ struct edma_rx_return_desc *rd; ++ u16 hash_type, rrd[8], cleaned_count = 0, length = 0, num_rfds = 1, ++ sw_next_to_clean, hw_next_to_clean = 0, vlan = 0, ret_count = 0; ++ u32 data = 0; ++ u8 *vaddr; ++ int port_id, i, drop_count = 0; ++ u32 priority; ++ u16 count = erdr->count, rfd_avail; ++ u8 queue_to_rxid[8] = {0, 0, 1, 1, 2, 2, 3, 3}; ++ ++ sw_next_to_clean = erdr->sw_next_to_clean; ++ ++ edma_read_reg(EDMA_REG_RFD_IDX_Q(queue_id), &data); ++ hw_next_to_clean = (data >> EDMA_RFD_CONS_IDX_SHIFT) & ++ EDMA_RFD_CONS_IDX_MASK; ++ ++ do { ++ while (sw_next_to_clean != hw_next_to_clean) { ++ if (!work_to_do) ++ break; ++ ++ sw_desc = &erdr->sw_desc[sw_next_to_clean]; ++ skb = sw_desc->skb; ++ ++ /* Unmap the allocated buffer */ ++ if (likely(sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_HEAD)) ++ dma_unmap_single(&pdev->dev, sw_desc->dma, ++ sw_desc->length, DMA_FROM_DEVICE); ++ else ++ dma_unmap_page(&pdev->dev, sw_desc->dma, ++ sw_desc->length, DMA_FROM_DEVICE); ++ ++ /* Get RRD */ ++ if (edma_cinfo->page_mode) { ++ vaddr = kmap_atomic(skb_frag_page(&skb_shinfo(skb)->frags[0])); ++ memcpy((uint8_t *)&rrd[0], vaddr, 16); ++ rd = (struct edma_rx_return_desc *)rrd; ++ kunmap_atomic(vaddr); ++ } else { ++ rd = (struct edma_rx_return_desc *)skb->data; ++ } ++ ++ /* Check if RRD is valid */ ++ if (!(rd->rrd7 & EDMA_RRD_DESC_VALID)) { ++ edma_clean_rfd(erdr, sw_next_to_clean); ++ sw_next_to_clean = (sw_next_to_clean + 1) & ++ (erdr->count - 1); ++ cleaned_count++; ++ continue; ++ } ++ ++ /* Get the number of RFDs from RRD */ ++ num_rfds = rd->rrd1 & EDMA_RRD_NUM_RFD_MASK; ++ ++ /* Get Rx port ID from switch */ ++ port_id = (rd->rrd1 >> EDMA_PORT_ID_SHIFT) & EDMA_PORT_ID_MASK; ++ if ((!port_id) || (port_id > EDMA_MAX_PORTID_SUPPORTED)) { ++ dev_err(&pdev->dev, "Invalid RRD source port bit set"); ++ for (i = 0; i < num_rfds; i++) { ++ edma_clean_rfd(erdr, sw_next_to_clean); ++ sw_next_to_clean = (sw_next_to_clean + 1) & (erdr->count - 1); ++ cleaned_count++; ++ } ++ continue; ++ } ++ ++ /* check if we have a sink for the data we receive. ++ * If the interface isn't setup, we have to drop the ++ * incoming data for now. ++ */ ++ netdev = edma_cinfo->portid_netdev_lookup_tbl[port_id]; ++ if (!netdev) { ++ edma_clean_rfd(erdr, sw_next_to_clean); ++ sw_next_to_clean = (sw_next_to_clean + 1) & ++ (erdr->count - 1); ++ cleaned_count++; ++ continue; ++ } ++ adapter = netdev_priv(netdev); ++ ++ /* This code is added to handle a usecase where high ++ * priority stream and a low priority stream are ++ * received simultaneously on DUT. The problem occurs ++ * if one of the Rx rings is full and the corresponding ++ * core is busy with other stuff. This causes ESS CPU ++ * port to backpressure all incoming traffic including ++ * high priority one. We monitor free descriptor count ++ * on each CPU and whenever it reaches threshold (< 80), ++ * we drop all low priority traffic and let only high ++ * priotiy traffic pass through. We can hence avoid ++ * ESS CPU port to send backpressure on high priroity ++ * stream. ++ */ ++ priority = (rd->rrd1 >> EDMA_RRD_PRIORITY_SHIFT) ++ & EDMA_RRD_PRIORITY_MASK; ++ if (likely(!priority && !edma_cinfo->page_mode && (num_rfds <= 1))) { ++ rfd_avail = (count + sw_next_to_clean - hw_next_to_clean - 1) & (count - 1); ++ if (rfd_avail < EDMA_RFD_AVAIL_THR) { ++ sw_desc->flags = EDMA_SW_DESC_FLAG_SKB_REUSE; ++ sw_next_to_clean = (sw_next_to_clean + 1) & (erdr->count - 1); ++ adapter->stats.rx_dropped++; ++ cleaned_count++; ++ drop_count++; ++ if (drop_count == 3) { ++ work_to_do--; ++ (*work_done)++; ++ drop_count = 0; ++ } ++ if (cleaned_count == EDMA_RX_BUFFER_WRITE) { ++ /* If buffer clean count reaches 16, we replenish HW buffers. */ ++ ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id); ++ edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id), ++ sw_next_to_clean); ++ cleaned_count = ret_count; ++ } ++ continue; ++ } ++ } ++ ++ work_to_do--; ++ (*work_done)++; ++ ++ /* Increment SW index */ ++ sw_next_to_clean = (sw_next_to_clean + 1) & ++ (erdr->count - 1); ++ ++ cleaned_count++; ++ ++ /* Get the packet size and allocate buffer */ ++ length = rd->rrd6 & EDMA_RRD_PKT_SIZE_MASK; ++ ++ if (edma_cinfo->page_mode) { ++ /* paged skb */ ++ sw_next_to_clean = edma_rx_complete_paged(skb, num_rfds, length, sw_next_to_clean, &cleaned_count, erdr, edma_cinfo); ++ if (!pskb_may_pull(skb, ETH_HLEN)) { ++ dev_kfree_skb_any(skb); ++ continue; ++ } ++ } else { ++ /* single or fraglist skb */ ++ ++ /* Addition of 16 bytes is required, as in the packet ++ * first 16 bytes are rrd descriptors, so actual data ++ * starts from an offset of 16. ++ */ ++ skb_reserve(skb, 16); ++ if (likely((num_rfds <= 1) || !edma_cinfo->fraglist_mode)) { ++ skb_put(skb, length); ++ } else { ++ sw_next_to_clean = edma_rx_complete_fraglist(skb, num_rfds, length, sw_next_to_clean, &cleaned_count, erdr, edma_cinfo); ++ } ++ } ++ ++ if (edma_stp_rstp) { ++ edma_rx_complete_stp_rstp(skb, port_id, rd); ++ } ++ ++ skb->protocol = eth_type_trans(skb, netdev); ++ ++ /* Record Rx queue for RFS/RPS and fill flow hash from HW */ ++ skb_record_rx_queue(skb, queue_to_rxid[queue_id]); ++ if (netdev->features & NETIF_F_RXHASH) { ++ hash_type = (rd->rrd5 >> EDMA_HASH_TYPE_SHIFT); ++ if ((hash_type > EDMA_HASH_TYPE_START) && (hash_type < EDMA_HASH_TYPE_END)) ++ skb_set_hash(skb, rd->rrd2, PKT_HASH_TYPE_L4); ++ } ++ ++#ifdef CONFIG_NF_FLOW_COOKIE ++ skb->flow_cookie = rd->rrd3 & EDMA_RRD_FLOW_COOKIE_MASK; ++#endif ++ edma_receive_checksum(rd, skb); ++ ++ /* Process VLAN HW acceleration indication provided by HW */ ++ if (unlikely(adapter->default_vlan_tag != rd->rrd4)) { ++ vlan = rd->rrd4; ++ if (likely(rd->rrd7 & EDMA_RRD_CVLAN)) ++ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); ++ else if (rd->rrd1 & EDMA_RRD_SVLAN) ++ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD), vlan); ++ } ++ ++ /* Update rx statistics */ ++ adapter->stats.rx_packets++; ++ adapter->stats.rx_bytes += length; ++ ++ /* Check if we reached refill threshold */ ++ if (cleaned_count == EDMA_RX_BUFFER_WRITE) { ++ ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id); ++ edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id), ++ sw_next_to_clean); ++ cleaned_count = ret_count; ++ } ++ ++ /* At this point skb should go to stack */ ++ napi_gro_receive(napi, skb); ++ } ++ ++ /* Check if we still have NAPI budget */ ++ if (!work_to_do) ++ break; ++ ++ /* Read index once again since we still have NAPI budget */ ++ edma_read_reg(EDMA_REG_RFD_IDX_Q(queue_id), &data); ++ hw_next_to_clean = (data >> EDMA_RFD_CONS_IDX_SHIFT) & ++ EDMA_RFD_CONS_IDX_MASK; ++ } while (hw_next_to_clean != sw_next_to_clean); ++ ++ erdr->sw_next_to_clean = sw_next_to_clean; ++ ++ /* Refill here in case refill threshold wasn't reached */ ++ if (likely(cleaned_count)) { ++ ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id); ++ if (ret_count) ++ dev_dbg(&pdev->dev, "Not all buffers was reallocated"); ++ edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id), ++ erdr->sw_next_to_clean); ++ } ++} ++ ++/* edma_delete_rfs_filter() ++ * Remove RFS filter from switch ++ */ ++static int edma_delete_rfs_filter(struct edma_adapter *adapter, ++ struct edma_rfs_filter_node *filter_node) ++{ ++ int res = -1; ++ ++ struct flow_keys *keys = &filter_node->keys; ++ ++ if (likely(adapter->set_rfs_rule)) ++ res = (*adapter->set_rfs_rule)(adapter->netdev, ++ flow_get_u32_src(keys), flow_get_u32_dst(keys), ++ keys->ports.src, keys->ports.dst, ++ keys->basic.ip_proto, filter_node->rq_id, 0); ++ ++ return res; ++} ++ ++/* edma_add_rfs_filter() ++ * Add RFS filter to switch ++ */ ++static int edma_add_rfs_filter(struct edma_adapter *adapter, ++ struct flow_keys *keys, u16 rq, ++ struct edma_rfs_filter_node *filter_node) ++{ ++ int res = -1; ++ ++ struct flow_keys *dest_keys = &filter_node->keys; ++ ++ memcpy(dest_keys, &filter_node->keys, sizeof(*dest_keys)); ++/* ++ dest_keys->control = keys->control; ++ dest_keys->basic = keys->basic; ++ dest_keys->addrs = keys->addrs; ++ dest_keys->ports = keys->ports; ++ dest_keys.ip_proto = keys->ip_proto; ++*/ ++ /* Call callback registered by ESS driver */ ++ if (likely(adapter->set_rfs_rule)) ++ res = (*adapter->set_rfs_rule)(adapter->netdev, flow_get_u32_src(keys), ++ flow_get_u32_dst(keys), keys->ports.src, keys->ports.dst, ++ keys->basic.ip_proto, rq, 1); ++ ++ return res; ++} ++ ++/* edma_rfs_key_search() ++ * Look for existing RFS entry ++ */ ++static struct edma_rfs_filter_node *edma_rfs_key_search(struct hlist_head *h, ++ struct flow_keys *key) ++{ ++ struct edma_rfs_filter_node *p; ++ ++ hlist_for_each_entry(p, h, node) ++ if (flow_get_u32_src(&p->keys) == flow_get_u32_src(key) && ++ flow_get_u32_dst(&p->keys) == flow_get_u32_dst(key) && ++ p->keys.ports.src == key->ports.src && ++ p->keys.ports.dst == key->ports.dst && ++ p->keys.basic.ip_proto == key->basic.ip_proto) ++ return p; ++ return NULL; ++} ++ ++/* edma_initialise_rfs_flow_table() ++ * Initialise EDMA RFS flow table ++ */ ++static void edma_initialise_rfs_flow_table(struct edma_adapter *adapter) ++{ ++ int i; ++ ++ spin_lock_init(&adapter->rfs.rfs_ftab_lock); ++ ++ /* Initialize EDMA flow hash table */ ++ for (i = 0; i < EDMA_RFS_FLOW_ENTRIES; i++) ++ INIT_HLIST_HEAD(&adapter->rfs.hlist_head[i]); ++ ++ adapter->rfs.max_num_filter = EDMA_RFS_FLOW_ENTRIES; ++ adapter->rfs.filter_available = adapter->rfs.max_num_filter; ++ adapter->rfs.hashtoclean = 0; ++ ++ /* Add timer to get periodic RFS updates from OS */ ++ timer_setup(&adapter->rfs.expire_rfs, edma_flow_may_expire, 0); ++ mod_timer(&adapter->rfs.expire_rfs, jiffies + HZ / 4); ++} ++ ++/* edma_free_rfs_flow_table() ++ * Free EDMA RFS flow table ++ */ ++static void edma_free_rfs_flow_table(struct edma_adapter *adapter) ++{ ++ int i; ++ ++ /* Remove sync timer */ ++ del_timer_sync(&adapter->rfs.expire_rfs); ++ spin_lock_bh(&adapter->rfs.rfs_ftab_lock); ++ ++ /* Free EDMA RFS table entries */ ++ adapter->rfs.filter_available = 0; ++ ++ /* Clean-up EDMA flow hash table */ ++ for (i = 0; i < EDMA_RFS_FLOW_ENTRIES; i++) { ++ struct hlist_head *hhead; ++ struct hlist_node *tmp; ++ struct edma_rfs_filter_node *filter_node; ++ int res; ++ ++ hhead = &adapter->rfs.hlist_head[i]; ++ hlist_for_each_entry_safe(filter_node, tmp, hhead, node) { ++ res = edma_delete_rfs_filter(adapter, filter_node); ++ if (res < 0) ++ dev_warn(&adapter->netdev->dev, ++ "EDMA going down but RFS entry %d not allowed to be flushed by Switch", ++ filter_node->flow_id); ++ hlist_del(&filter_node->node); ++ kfree(filter_node); ++ } ++ } ++ spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); ++} ++ ++/* edma_tx_unmap_and_free() ++ * clean TX buffer ++ */ ++static inline void edma_tx_unmap_and_free(struct platform_device *pdev, ++ struct edma_sw_desc *sw_desc) ++{ ++ struct sk_buff *skb = sw_desc->skb; ++ ++ if (likely((sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_HEAD) || ++ (sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_FRAGLIST))) ++ /* unmap_single for skb head area */ ++ dma_unmap_single(&pdev->dev, sw_desc->dma, ++ sw_desc->length, DMA_TO_DEVICE); ++ else if (sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_FRAG) ++ /* unmap page for paged fragments */ ++ dma_unmap_page(&pdev->dev, sw_desc->dma, ++ sw_desc->length, DMA_TO_DEVICE); ++ ++ if (likely(sw_desc->flags & EDMA_SW_DESC_FLAG_LAST)) ++ dev_kfree_skb_any(skb); ++ ++ sw_desc->flags = 0; ++} ++ ++/* edma_tx_complete() ++ * Used to clean tx queues and update hardware and consumer index ++ */ ++static void edma_tx_complete(struct edma_common_info *edma_cinfo, int queue_id) ++{ ++ struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; ++ struct edma_sw_desc *sw_desc; ++ struct platform_device *pdev = edma_cinfo->pdev; ++ int i; ++ ++ u16 sw_next_to_clean = etdr->sw_next_to_clean; ++ u16 hw_next_to_clean; ++ u32 data = 0; ++ ++ edma_read_reg(EDMA_REG_TPD_IDX_Q(queue_id), &data); ++ hw_next_to_clean = (data >> EDMA_TPD_CONS_IDX_SHIFT) & EDMA_TPD_CONS_IDX_MASK; ++ ++ /* clean the buffer here */ ++ while (sw_next_to_clean != hw_next_to_clean) { ++ sw_desc = &etdr->sw_desc[sw_next_to_clean]; ++ edma_tx_unmap_and_free(pdev, sw_desc); ++ sw_next_to_clean = (sw_next_to_clean + 1) & (etdr->count - 1); ++ } ++ ++ etdr->sw_next_to_clean = sw_next_to_clean; ++ ++ /* update the TPD consumer index register */ ++ edma_write_reg(EDMA_REG_TX_SW_CONS_IDX_Q(queue_id), sw_next_to_clean); ++ ++ /* Wake the queue if queue is stopped and netdev link is up */ ++ for (i = 0; i < EDMA_MAX_NETDEV_PER_QUEUE && etdr->nq[i] ; i++) { ++ if (netif_tx_queue_stopped(etdr->nq[i])) { ++ if ((etdr->netdev[i]) && netif_carrier_ok(etdr->netdev[i])) ++ netif_tx_wake_queue(etdr->nq[i]); ++ } ++ } ++} ++ ++/* edma_get_tx_buffer() ++ * Get sw_desc corresponding to the TPD ++ */ ++static struct edma_sw_desc *edma_get_tx_buffer(struct edma_common_info *edma_cinfo, ++ struct edma_tx_desc *tpd, int queue_id) ++{ ++ struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; ++ return &etdr->sw_desc[tpd - (struct edma_tx_desc *)etdr->hw_desc]; ++} ++ ++/* edma_get_next_tpd() ++ * Return a TPD descriptor for transfer ++ */ ++static struct edma_tx_desc *edma_get_next_tpd(struct edma_common_info *edma_cinfo, ++ int queue_id) ++{ ++ struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; ++ u16 sw_next_to_fill = etdr->sw_next_to_fill; ++ struct edma_tx_desc *tpd_desc = ++ (&((struct edma_tx_desc *)(etdr->hw_desc))[sw_next_to_fill]); ++ ++ etdr->sw_next_to_fill = (etdr->sw_next_to_fill + 1) & (etdr->count - 1); ++ ++ return tpd_desc; ++} ++ ++/* edma_tpd_available() ++ * Check number of free TPDs ++ */ ++static inline u16 edma_tpd_available(struct edma_common_info *edma_cinfo, ++ int queue_id) ++{ ++ struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; ++ ++ u16 sw_next_to_fill; ++ u16 sw_next_to_clean; ++ u16 count = 0; ++ ++ sw_next_to_clean = etdr->sw_next_to_clean; ++ sw_next_to_fill = etdr->sw_next_to_fill; ++ ++ if (likely(sw_next_to_clean <= sw_next_to_fill)) ++ count = etdr->count; ++ ++ return count + sw_next_to_clean - sw_next_to_fill - 1; ++} ++ ++/* edma_tx_queue_get() ++ * Get the starting number of the queue ++ */ ++static inline int edma_tx_queue_get(struct edma_adapter *adapter, ++ struct sk_buff *skb, int txq_id) ++{ ++ /* skb->priority is used as an index to skb priority table ++ * and based on packet priority, correspong queue is assigned. ++ */ ++ return adapter->tx_start_offset[txq_id] + edma_skb_priority_offset(skb); ++} ++ ++/* edma_tx_update_hw_idx() ++ * update the producer index for the ring transmitted ++ */ ++static void edma_tx_update_hw_idx(struct edma_common_info *edma_cinfo, ++ struct sk_buff *skb, int queue_id) ++{ ++ struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; ++ u32 tpd_idx_data; ++ ++ /* Read and update the producer index */ ++ edma_read_reg(EDMA_REG_TPD_IDX_Q(queue_id), &tpd_idx_data); ++ tpd_idx_data &= ~EDMA_TPD_PROD_IDX_BITS; ++ tpd_idx_data |= (etdr->sw_next_to_fill & EDMA_TPD_PROD_IDX_MASK) ++ << EDMA_TPD_PROD_IDX_SHIFT; ++ ++ edma_write_reg(EDMA_REG_TPD_IDX_Q(queue_id), tpd_idx_data); ++} ++ ++/* edma_rollback_tx() ++ * Function to retrieve tx resources in case of error ++ */ ++static void edma_rollback_tx(struct edma_adapter *adapter, ++ struct edma_tx_desc *start_tpd, int queue_id) ++{ ++ struct edma_tx_desc_ring *etdr = adapter->edma_cinfo->tpd_ring[queue_id]; ++ struct edma_sw_desc *sw_desc; ++ struct edma_tx_desc *tpd = NULL; ++ u16 start_index, index; ++ ++ start_index = start_tpd - (struct edma_tx_desc *)(etdr->hw_desc); ++ ++ index = start_index; ++ while (index != etdr->sw_next_to_fill) { ++ tpd = (&((struct edma_tx_desc *)(etdr->hw_desc))[index]); ++ sw_desc = &etdr->sw_desc[index]; ++ edma_tx_unmap_and_free(adapter->pdev, sw_desc); ++ memset(tpd, 0, sizeof(struct edma_tx_desc)); ++ if (++index == etdr->count) ++ index = 0; ++ } ++ etdr->sw_next_to_fill = start_index; ++} ++ ++/* edma_tx_map_and_fill() ++ * gets called from edma_xmit_frame ++ * ++ * This is where the dma of the buffer to be transmitted ++ * gets mapped ++ */ ++static int edma_tx_map_and_fill(struct edma_common_info *edma_cinfo, ++ struct edma_adapter *adapter, struct sk_buff *skb, int queue_id, ++ unsigned int flags_transmit, u16 from_cpu, u16 dp_bitmap, ++ bool packet_is_rstp, int nr_frags) ++{ ++ struct edma_sw_desc *sw_desc = NULL; ++ struct platform_device *pdev = edma_cinfo->pdev; ++ struct edma_tx_desc *tpd = NULL, *start_tpd = NULL; ++ struct sk_buff *iter_skb; ++ int i = 0; ++ u32 word1 = 0, word3 = 0, lso_word1 = 0, svlan_tag = 0; ++ u16 buf_len, lso_desc_len = 0; ++ ++ /* It should either be a nr_frags skb or fraglist skb but not both */ ++ BUG_ON(nr_frags && skb_has_frag_list(skb)); ++ ++ if (skb_is_gso(skb)) { ++ /* TODO: What additional checks need to be performed here */ ++ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) { ++ lso_word1 |= EDMA_TPD_IPV4_EN; ++ ip_hdr(skb)->check = 0; ++ tcp_hdr(skb)->check = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, ++ ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); ++ } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) { ++ lso_word1 |= EDMA_TPD_LSO_V2_EN; ++ ipv6_hdr(skb)->payload_len = 0; ++ tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); ++ } else ++ return -EINVAL; ++ ++ lso_word1 |= EDMA_TPD_LSO_EN | ((skb_shinfo(skb)->gso_size & EDMA_TPD_MSS_MASK) << EDMA_TPD_MSS_SHIFT) | ++ (skb_transport_offset(skb) << EDMA_TPD_HDR_SHIFT); ++ } else if (flags_transmit & EDMA_HW_CHECKSUM) { ++ u8 css, cso; ++ cso = skb_checksum_start_offset(skb); ++ css = cso + skb->csum_offset; ++ ++ word1 |= (EDMA_TPD_CUSTOM_CSUM_EN); ++ word1 |= (cso >> 1) << EDMA_TPD_HDR_SHIFT; ++ word1 |= ((css >> 1) << EDMA_TPD_CUSTOM_CSUM_SHIFT); ++ } ++ ++ if (skb->protocol == htons(ETH_P_PPP_SES)) ++ word1 |= EDMA_TPD_PPPOE_EN; ++ ++ if (flags_transmit & EDMA_VLAN_TX_TAG_INSERT_FLAG) { ++ switch(skb->vlan_proto) { ++ case htons(ETH_P_8021Q): ++ word3 |= (1 << EDMA_TX_INS_CVLAN); ++ word3 |= skb_vlan_tag_get(skb) << EDMA_TX_CVLAN_TAG_SHIFT; ++ break; ++ case htons(ETH_P_8021AD): ++ word1 |= (1 << EDMA_TX_INS_SVLAN); ++ svlan_tag = skb_vlan_tag_get(skb) << EDMA_TX_SVLAN_TAG_SHIFT; ++ break; ++ default: ++ dev_err(&pdev->dev, "no ctag or stag present\n"); ++ goto vlan_tag_error; ++ } ++ } else if (flags_transmit & EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG) { ++ word3 |= (1 << EDMA_TX_INS_CVLAN); ++ word3 |= (adapter->default_vlan_tag) << EDMA_TX_CVLAN_TAG_SHIFT; ++ } ++ ++ if (packet_is_rstp) { ++ word3 |= dp_bitmap << EDMA_TPD_PORT_BITMAP_SHIFT; ++ word3 |= from_cpu << EDMA_TPD_FROM_CPU_SHIFT; ++ } else { ++ word3 |= adapter->dp_bitmap << EDMA_TPD_PORT_BITMAP_SHIFT; ++ } ++ ++ buf_len = skb_headlen(skb); ++ ++ if (lso_word1) { ++ if (lso_word1 & EDMA_TPD_LSO_V2_EN) { ++ ++ /* IPv6 LSOv2 descriptor */ ++ start_tpd = tpd = edma_get_next_tpd(edma_cinfo, queue_id); ++ sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); ++ sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_NONE; ++ ++ /* LSOv2 descriptor overrides addr field to pass length */ ++ tpd->addr = cpu_to_le16(skb->len); ++ tpd->svlan_tag = svlan_tag; ++ tpd->word1 = word1 | lso_word1; ++ tpd->word3 = word3; ++ } ++ ++ tpd = edma_get_next_tpd(edma_cinfo, queue_id); ++ if (!start_tpd) ++ start_tpd = tpd; ++ sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); ++ ++ /* The last buffer info contain the skb address, ++ * so skb will be freed after unmap ++ */ ++ sw_desc->length = lso_desc_len; ++ sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_HEAD; ++ ++ sw_desc->dma = dma_map_single(&adapter->pdev->dev, ++ skb->data, buf_len, DMA_TO_DEVICE); ++ if (dma_mapping_error(&pdev->dev, sw_desc->dma)) ++ goto dma_error; ++ ++ tpd->addr = cpu_to_le32(sw_desc->dma); ++ tpd->len = cpu_to_le16(buf_len); ++ ++ tpd->svlan_tag = svlan_tag; ++ tpd->word1 = word1 | lso_word1; ++ tpd->word3 = word3; ++ ++ /* The last buffer info contain the skb address, ++ * so it will be freed after unmap ++ */ ++ sw_desc->length = lso_desc_len; ++ sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_HEAD; ++ ++ buf_len = 0; ++ } ++ ++ if (likely(buf_len)) { ++ ++ /* TODO Do not dequeue descriptor if there is a potential error */ ++ tpd = edma_get_next_tpd(edma_cinfo, queue_id); ++ ++ if (!start_tpd) ++ start_tpd = tpd; ++ ++ sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); ++ ++ /* The last buffer info contain the skb address, ++ * so it will be free after unmap ++ */ ++ sw_desc->length = buf_len; ++ sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_HEAD; ++ sw_desc->dma = dma_map_single(&adapter->pdev->dev, ++ skb->data, buf_len, DMA_TO_DEVICE); ++ if (dma_mapping_error(&pdev->dev, sw_desc->dma)) ++ goto dma_error; ++ ++ tpd->addr = cpu_to_le32(sw_desc->dma); ++ tpd->len = cpu_to_le16(buf_len); ++ ++ tpd->svlan_tag = svlan_tag; ++ tpd->word1 = word1 | lso_word1; ++ tpd->word3 = word3; ++ } ++ ++ /* Walk through all paged fragments */ ++ while (nr_frags--) { ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; ++ buf_len = skb_frag_size(frag); ++ tpd = edma_get_next_tpd(edma_cinfo, queue_id); ++ sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); ++ sw_desc->length = buf_len; ++ sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_FRAG; ++ ++ sw_desc->dma = skb_frag_dma_map(&pdev->dev, frag, 0, buf_len, DMA_TO_DEVICE); ++ ++ if (dma_mapping_error(NULL, sw_desc->dma)) ++ goto dma_error; ++ ++ tpd->addr = cpu_to_le32(sw_desc->dma); ++ tpd->len = cpu_to_le16(buf_len); ++ ++ tpd->svlan_tag = svlan_tag; ++ tpd->word1 = word1 | lso_word1; ++ tpd->word3 = word3; ++ i++; ++ } ++ ++ /* Walk through all fraglist skbs */ ++ skb_walk_frags(skb, iter_skb) { ++ buf_len = iter_skb->len; ++ tpd = edma_get_next_tpd(edma_cinfo, queue_id); ++ sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); ++ sw_desc->length = buf_len; ++ sw_desc->dma = dma_map_single(&adapter->pdev->dev, ++ iter_skb->data, buf_len, DMA_TO_DEVICE); ++ ++ if (dma_mapping_error(NULL, sw_desc->dma)) ++ goto dma_error; ++ ++ tpd->addr = cpu_to_le32(sw_desc->dma); ++ tpd->len = cpu_to_le16(buf_len); ++ tpd->svlan_tag = svlan_tag; ++ tpd->word1 = word1 | lso_word1; ++ tpd->word3 = word3; ++ sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_FRAGLIST; ++ } ++ ++ if (tpd) ++ tpd->word1 |= 1 << EDMA_TPD_EOP_SHIFT; ++ ++ sw_desc->skb = skb; ++ sw_desc->flags |= EDMA_SW_DESC_FLAG_LAST; ++ ++ return 0; ++ ++dma_error: ++ edma_rollback_tx(adapter, start_tpd, queue_id); ++ dev_err(&pdev->dev, "TX DMA map failed\n"); ++vlan_tag_error: ++ return -ENOMEM; ++} ++ ++/* edma_check_link() ++ * check Link status ++ */ ++static int edma_check_link(struct edma_adapter *adapter) ++{ ++ struct phy_device *phydev = adapter->phydev; ++ ++ if (!(adapter->poll_required)) ++ return __EDMA_LINKUP; ++ ++ if (phydev->link) ++ return __EDMA_LINKUP; ++ ++ return __EDMA_LINKDOWN; ++} ++ ++/* edma_adjust_link() ++ * check for edma link status ++ */ ++void edma_adjust_link(struct net_device *netdev) ++{ ++ int status; ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ struct phy_device *phydev = adapter->phydev; ++ ++ if (!test_bit(__EDMA_UP, &adapter->state_flags)) ++ return; ++ ++ status = edma_check_link(adapter); ++ ++ if (status == __EDMA_LINKUP && adapter->link_state == __EDMA_LINKDOWN) { ++ dev_info(&adapter->pdev->dev, "%s: GMAC Link is up with phy_speed=%d\n", netdev->name, phydev->speed); ++ adapter->link_state = __EDMA_LINKUP; ++ netif_carrier_on(netdev); ++ if (netif_running(netdev)) ++ netif_tx_wake_all_queues(netdev); ++ } else if (status == __EDMA_LINKDOWN && adapter->link_state == __EDMA_LINKUP) { ++ dev_info(&adapter->pdev->dev, "%s: GMAC Link is down\n", netdev->name); ++ adapter->link_state = __EDMA_LINKDOWN; ++ netif_carrier_off(netdev); ++ netif_tx_stop_all_queues(netdev); ++ } ++} ++ ++/* edma_get_stats() ++ * Statistics api used to retreive the tx/rx statistics ++ */ ++struct net_device_stats *edma_get_stats(struct net_device *netdev) ++{ ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ ++ return &adapter->stats; ++} ++ ++/* edma_xmit() ++ * Main api to be called by the core for packet transmission ++ */ ++netdev_tx_t edma_xmit(struct sk_buff *skb, ++ struct net_device *net_dev) ++{ ++ struct edma_adapter *adapter = netdev_priv(net_dev); ++ struct edma_common_info *edma_cinfo = adapter->edma_cinfo; ++ struct edma_tx_desc_ring *etdr; ++ u16 from_cpu, dp_bitmap, txq_id; ++ int ret, nr_frags = 0, num_tpds_needed = 1, queue_id; ++ unsigned int flags_transmit = 0; ++ bool packet_is_rstp = false; ++ struct netdev_queue *nq = NULL; ++ ++ if (skb_shinfo(skb)->nr_frags) { ++ nr_frags = skb_shinfo(skb)->nr_frags; ++ num_tpds_needed += nr_frags; ++ } else if (skb_has_frag_list(skb)) { ++ struct sk_buff *iter_skb; ++ ++ skb_walk_frags(skb, iter_skb) ++ num_tpds_needed++; ++ } ++ ++ if (num_tpds_needed > EDMA_MAX_SKB_FRAGS) { ++ dev_err(&net_dev->dev, ++ "skb received with fragments %d which is more than %lu", ++ num_tpds_needed, EDMA_MAX_SKB_FRAGS); ++ dev_kfree_skb_any(skb); ++ adapter->stats.tx_errors++; ++ return NETDEV_TX_OK; ++ } ++ ++ if (edma_stp_rstp) { ++ u16 ath_hdr, ath_eth_type; ++ u8 mac_addr[EDMA_ETH_HDR_LEN]; ++ ath_eth_type = ntohs(*(uint16_t *)&skb->data[12]); ++ if (ath_eth_type == edma_ath_eth_type) { ++ packet_is_rstp = true; ++ ath_hdr = htons(*(uint16_t *)&skb->data[14]); ++ dp_bitmap = ath_hdr & EDMA_TX_ATH_HDR_PORT_BITMAP_MASK; ++ from_cpu = (ath_hdr & EDMA_TX_ATH_HDR_FROM_CPU_MASK) >> EDMA_TX_ATH_HDR_FROM_CPU_SHIFT; ++ memcpy(mac_addr, skb->data, EDMA_ETH_HDR_LEN); ++ ++ skb_pull(skb, 4); ++ ++ memcpy(skb->data, mac_addr, EDMA_ETH_HDR_LEN); ++ } ++ } ++ ++ /* this will be one of the 4 TX queues exposed to linux kernel */ ++ txq_id = skb_get_queue_mapping(skb); ++ queue_id = edma_tx_queue_get(adapter, skb, txq_id); ++ etdr = edma_cinfo->tpd_ring[queue_id]; ++ nq = netdev_get_tx_queue(net_dev, txq_id); ++ ++ local_bh_disable(); ++ /* Tx is not handled in bottom half context. Hence, we need to protect ++ * Tx from tasks and bottom half ++ */ ++ ++ if (num_tpds_needed > edma_tpd_available(edma_cinfo, queue_id)) { ++ /* not enough descriptor, just stop queue */ ++ netif_tx_stop_queue(nq); ++ local_bh_enable(); ++ dev_dbg(&net_dev->dev, "Not enough descriptors available"); ++ edma_cinfo->edma_ethstats.tx_desc_error++; ++ return NETDEV_TX_BUSY; ++ } ++ ++ /* Check and mark VLAN tag offload */ ++ if (skb_vlan_tag_present(skb)) ++ flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG; ++ else if (adapter->default_vlan_tag) ++ flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG; ++ ++ /* Check and mark checksum offload */ ++ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) ++ flags_transmit |= EDMA_HW_CHECKSUM; ++ ++ /* Map and fill descriptor for Tx */ ++ ret = edma_tx_map_and_fill(edma_cinfo, adapter, skb, queue_id, ++ flags_transmit, from_cpu, dp_bitmap, packet_is_rstp, nr_frags); ++ if (ret) { ++ dev_kfree_skb_any(skb); ++ adapter->stats.tx_errors++; ++ goto netdev_okay; ++ } ++ ++ /* Update SW producer index */ ++ edma_tx_update_hw_idx(edma_cinfo, skb, queue_id); ++ ++ /* update tx statistics */ ++ adapter->stats.tx_packets++; ++ adapter->stats.tx_bytes += skb->len; ++ ++netdev_okay: ++ local_bh_enable(); ++ return NETDEV_TX_OK; ++} ++ ++/* ++ * edma_flow_may_expire() ++ * Timer function called periodically to delete the node ++ */ ++void edma_flow_may_expire(struct timer_list *t) ++{ ++ struct edma_rfs_flow_table *table = from_timer(table, t, expire_rfs); ++ struct edma_adapter *adapter = ++ container_of(table, typeof(*adapter), rfs); ++ int j; ++ ++ spin_lock_bh(&adapter->rfs.rfs_ftab_lock); ++ for (j = 0; j < EDMA_RFS_EXPIRE_COUNT_PER_CALL; j++) { ++ struct hlist_head *hhead; ++ struct hlist_node *tmp; ++ struct edma_rfs_filter_node *n; ++ bool res; ++ ++ hhead = &adapter->rfs.hlist_head[adapter->rfs.hashtoclean++]; ++ hlist_for_each_entry_safe(n, tmp, hhead, node) { ++ res = rps_may_expire_flow(adapter->netdev, n->rq_id, ++ n->flow_id, n->filter_id); ++ if (res) { ++ int ret; ++ ret = edma_delete_rfs_filter(adapter, n); ++ if (ret < 0) ++ dev_dbg(&adapter->netdev->dev, ++ "RFS entry %d not allowed to be flushed by Switch", ++ n->flow_id); ++ else { ++ hlist_del(&n->node); ++ kfree(n); ++ adapter->rfs.filter_available++; ++ } ++ } ++ } ++ } ++ ++ adapter->rfs.hashtoclean = adapter->rfs.hashtoclean & (EDMA_RFS_FLOW_ENTRIES - 1); ++ spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); ++ mod_timer(&adapter->rfs.expire_rfs, jiffies + HZ / 4); ++} ++ ++/* edma_rx_flow_steer() ++ * Called by core to to steer the flow to CPU ++ */ ++int edma_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, ++ u16 rxq, u32 flow_id) ++{ ++ struct flow_keys keys; ++ struct edma_rfs_filter_node *filter_node; ++ struct edma_adapter *adapter = netdev_priv(dev); ++ u16 hash_tblid; ++ int res; ++ ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ dev_err(&adapter->pdev->dev, "IPv6 not supported\n"); ++ res = -EINVAL; ++ goto no_protocol_err; ++ } ++ ++ /* Dissect flow parameters ++ * We only support IPv4 + TCP/UDP ++ */ ++ res = skb_flow_dissect_flow_keys(skb, &keys, 0); ++ if (!((keys.basic.ip_proto == IPPROTO_TCP) || (keys.basic.ip_proto == IPPROTO_UDP))) { ++ res = -EPROTONOSUPPORT; ++ goto no_protocol_err; ++ } ++ ++ /* Check if table entry exists */ ++ hash_tblid = skb_get_hash_raw(skb) & EDMA_RFS_FLOW_ENTRIES_MASK; ++ ++ spin_lock_bh(&adapter->rfs.rfs_ftab_lock); ++ filter_node = edma_rfs_key_search(&adapter->rfs.hlist_head[hash_tblid], &keys); ++ ++ if (filter_node) { ++ if (rxq == filter_node->rq_id) { ++ res = -EEXIST; ++ goto out; ++ } else { ++ res = edma_delete_rfs_filter(adapter, filter_node); ++ if (res < 0) ++ dev_warn(&adapter->netdev->dev, ++ "Cannot steer flow %d to different queue", ++ filter_node->flow_id); ++ else { ++ adapter->rfs.filter_available++; ++ res = edma_add_rfs_filter(adapter, &keys, rxq, filter_node); ++ if (res < 0) { ++ dev_warn(&adapter->netdev->dev, ++ "Cannot steer flow %d to different queue", ++ filter_node->flow_id); ++ } else { ++ adapter->rfs.filter_available--; ++ filter_node->rq_id = rxq; ++ filter_node->filter_id = res; ++ } ++ } ++ } ++ } else { ++ if (adapter->rfs.filter_available == 0) { ++ res = -EBUSY; ++ goto out; ++ } ++ ++ filter_node = kmalloc(sizeof(*filter_node), GFP_ATOMIC); ++ if (!filter_node) { ++ res = -ENOMEM; ++ goto out; ++ } ++ ++ res = edma_add_rfs_filter(adapter, &keys, rxq, filter_node); ++ if (res < 0) { ++ kfree(filter_node); ++ goto out; ++ } ++ ++ adapter->rfs.filter_available--; ++ filter_node->rq_id = rxq; ++ filter_node->filter_id = res; ++ filter_node->flow_id = flow_id; ++ filter_node->keys = keys; ++ INIT_HLIST_NODE(&filter_node->node); ++ hlist_add_head(&filter_node->node, &adapter->rfs.hlist_head[hash_tblid]); ++ } ++ ++out: ++ spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); ++no_protocol_err: ++ return res; ++} ++ ++/* edma_register_rfs_filter() ++ * Add RFS filter callback ++ */ ++int edma_register_rfs_filter(struct net_device *netdev, ++ set_rfs_filter_callback_t set_filter) ++{ ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ ++ spin_lock_bh(&adapter->rfs.rfs_ftab_lock); ++ ++ if (adapter->set_rfs_rule) { ++ spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); ++ return -1; ++ } ++ ++ adapter->set_rfs_rule = set_filter; ++ spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); ++ ++ return 0; ++} ++ ++/* edma_alloc_tx_rings() ++ * Allocate rx rings ++ */ ++int edma_alloc_tx_rings(struct edma_common_info *edma_cinfo) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ int i, err = 0; ++ ++ for (i = 0; i < edma_cinfo->num_tx_queues; i++) { ++ err = edma_alloc_tx_ring(edma_cinfo, edma_cinfo->tpd_ring[i]); ++ if (err) { ++ dev_err(&pdev->dev, "Tx Queue alloc %u failed\n", i); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++/* edma_free_tx_rings() ++ * Free tx rings ++ */ ++void edma_free_tx_rings(struct edma_common_info *edma_cinfo) ++{ ++ int i; ++ ++ for (i = 0; i < edma_cinfo->num_tx_queues; i++) ++ edma_free_tx_ring(edma_cinfo, edma_cinfo->tpd_ring[i]); ++} ++ ++/* edma_free_tx_resources() ++ * Free buffers associated with tx rings ++ */ ++void edma_free_tx_resources(struct edma_common_info *edma_cinfo) ++{ ++ struct edma_tx_desc_ring *etdr; ++ struct edma_sw_desc *sw_desc; ++ struct platform_device *pdev = edma_cinfo->pdev; ++ int i, j; ++ ++ for (i = 0; i < edma_cinfo->num_tx_queues; i++) { ++ etdr = edma_cinfo->tpd_ring[i]; ++ for (j = 0; j < EDMA_TX_RING_SIZE; j++) { ++ sw_desc = &etdr->sw_desc[j]; ++ if (sw_desc->flags & (EDMA_SW_DESC_FLAG_SKB_HEAD | ++ EDMA_SW_DESC_FLAG_SKB_FRAG | EDMA_SW_DESC_FLAG_SKB_FRAGLIST)) ++ edma_tx_unmap_and_free(pdev, sw_desc); ++ } ++ } ++} ++ ++/* edma_alloc_rx_rings() ++ * Allocate rx rings ++ */ ++int edma_alloc_rx_rings(struct edma_common_info *edma_cinfo) ++{ ++ struct platform_device *pdev = edma_cinfo->pdev; ++ int i, j, err = 0; ++ ++ for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { ++ err = edma_alloc_rx_ring(edma_cinfo, edma_cinfo->rfd_ring[j]); ++ if (err) { ++ dev_err(&pdev->dev, "Rx Queue alloc%u failed\n", i); ++ return err; ++ } ++ j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); ++ } ++ ++ return 0; ++} ++ ++/* edma_free_rx_rings() ++ * free rx rings ++ */ ++void edma_free_rx_rings(struct edma_common_info *edma_cinfo) ++{ ++ int i, j; ++ ++ for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { ++ edma_free_rx_ring(edma_cinfo, edma_cinfo->rfd_ring[j]); ++ j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); ++ } ++} ++ ++/* edma_free_queues() ++ * Free the queues allocaated ++ */ ++void edma_free_queues(struct edma_common_info *edma_cinfo) ++{ ++ int i , j; ++ ++ for (i = 0; i < edma_cinfo->num_tx_queues; i++) { ++ if (edma_cinfo->tpd_ring[i]) ++ kfree(edma_cinfo->tpd_ring[i]); ++ edma_cinfo->tpd_ring[i] = NULL; ++ } ++ ++ for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { ++ if (edma_cinfo->rfd_ring[j]) ++ kfree(edma_cinfo->rfd_ring[j]); ++ edma_cinfo->rfd_ring[j] = NULL; ++ j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); ++ } ++ ++ edma_cinfo->num_rx_queues = 0; ++ edma_cinfo->num_tx_queues = 0; ++ ++ return; ++} ++ ++/* edma_free_rx_resources() ++ * Free buffers associated with tx rings ++ */ ++void edma_free_rx_resources(struct edma_common_info *edma_cinfo) ++{ ++ struct edma_rfd_desc_ring *erdr; ++ struct edma_sw_desc *sw_desc; ++ struct platform_device *pdev = edma_cinfo->pdev; ++ int i, j, k; ++ ++ for (i = 0, k = 0; i < edma_cinfo->num_rx_queues; i++) { ++ erdr = edma_cinfo->rfd_ring[k]; ++ for (j = 0; j < EDMA_RX_RING_SIZE; j++) { ++ sw_desc = &erdr->sw_desc[j]; ++ if (likely(sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_HEAD)) { ++ dma_unmap_single(&pdev->dev, sw_desc->dma, ++ sw_desc->length, DMA_FROM_DEVICE); ++ edma_clean_rfd(erdr, j); ++ } else if ((sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_FRAG)) { ++ dma_unmap_page(&pdev->dev, sw_desc->dma, ++ sw_desc->length, DMA_FROM_DEVICE); ++ edma_clean_rfd(erdr, j); ++ } ++ } ++ k += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); ++ ++ } ++} ++ ++/* edma_alloc_queues_tx() ++ * Allocate memory for all rings ++ */ ++int edma_alloc_queues_tx(struct edma_common_info *edma_cinfo) ++{ ++ int i; ++ ++ for (i = 0; i < edma_cinfo->num_tx_queues; i++) { ++ struct edma_tx_desc_ring *etdr; ++ etdr = kzalloc(sizeof(struct edma_tx_desc_ring), GFP_KERNEL); ++ if (!etdr) ++ goto err; ++ etdr->count = edma_cinfo->tx_ring_count; ++ edma_cinfo->tpd_ring[i] = etdr; ++ } ++ ++ return 0; ++err: ++ edma_free_queues(edma_cinfo); ++ return -1; ++} ++ ++/* edma_alloc_queues_rx() ++ * Allocate memory for all rings ++ */ ++int edma_alloc_queues_rx(struct edma_common_info *edma_cinfo) ++{ ++ int i, j; ++ ++ for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { ++ struct edma_rfd_desc_ring *rfd_ring; ++ rfd_ring = kzalloc(sizeof(struct edma_rfd_desc_ring), ++ GFP_KERNEL); ++ if (!rfd_ring) ++ goto err; ++ rfd_ring->count = edma_cinfo->rx_ring_count; ++ edma_cinfo->rfd_ring[j] = rfd_ring; ++ j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); ++ } ++ return 0; ++err: ++ edma_free_queues(edma_cinfo); ++ return -1; ++} ++ ++/* edma_clear_irq_status() ++ * Clear interrupt status ++ */ ++void edma_clear_irq_status() ++{ ++ edma_write_reg(EDMA_REG_RX_ISR, 0xff); ++ edma_write_reg(EDMA_REG_TX_ISR, 0xffff); ++ edma_write_reg(EDMA_REG_MISC_ISR, 0x1fff); ++ edma_write_reg(EDMA_REG_WOL_ISR, 0x1); ++}; ++ ++/* edma_configure() ++ * Configure skb, edma interrupts and control register. ++ */ ++int edma_configure(struct edma_common_info *edma_cinfo) ++{ ++ struct edma_hw *hw = &edma_cinfo->hw; ++ u32 intr_modrt_data; ++ u32 intr_ctrl_data = 0; ++ int i, j, ret_count; ++ ++ edma_read_reg(EDMA_REG_INTR_CTRL, &intr_ctrl_data); ++ intr_ctrl_data &= ~(1 << EDMA_INTR_SW_IDX_W_TYP_SHIFT); ++ intr_ctrl_data |= hw->intr_sw_idx_w << EDMA_INTR_SW_IDX_W_TYP_SHIFT; ++ edma_write_reg(EDMA_REG_INTR_CTRL, intr_ctrl_data); ++ ++ edma_clear_irq_status(); ++ ++ /* Clear any WOL status */ ++ edma_write_reg(EDMA_REG_WOL_CTRL, 0); ++ intr_modrt_data = (EDMA_TX_IMT << EDMA_IRQ_MODRT_TX_TIMER_SHIFT); ++ intr_modrt_data |= (EDMA_RX_IMT << EDMA_IRQ_MODRT_RX_TIMER_SHIFT); ++ edma_write_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, intr_modrt_data); ++ edma_configure_tx(edma_cinfo); ++ edma_configure_rx(edma_cinfo); ++ ++ /* Allocate the RX buffer */ ++ for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { ++ struct edma_rfd_desc_ring *ring = edma_cinfo->rfd_ring[j]; ++ ret_count = edma_alloc_rx_buf(edma_cinfo, ring, ring->count, j); ++ if (ret_count) { ++ dev_dbg(&edma_cinfo->pdev->dev, "not all rx buffers allocated\n"); ++ } ++ j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); ++ } ++ ++ /* Configure descriptor Ring */ ++ edma_init_desc(edma_cinfo); ++ return 0; ++} ++ ++/* edma_irq_enable() ++ * Enable default interrupt generation settings ++ */ ++void edma_irq_enable(struct edma_common_info *edma_cinfo) ++{ ++ struct edma_hw *hw = &edma_cinfo->hw; ++ int i, j; ++ ++ edma_write_reg(EDMA_REG_RX_ISR, 0xff); ++ for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { ++ edma_write_reg(EDMA_REG_RX_INT_MASK_Q(j), hw->rx_intr_mask); ++ j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); ++ } ++ edma_write_reg(EDMA_REG_TX_ISR, 0xffff); ++ for (i = 0; i < edma_cinfo->num_tx_queues; i++) ++ edma_write_reg(EDMA_REG_TX_INT_MASK_Q(i), hw->tx_intr_mask); ++} ++ ++/* edma_irq_disable() ++ * Disable Interrupt ++ */ ++void edma_irq_disable(struct edma_common_info *edma_cinfo) ++{ ++ int i; ++ ++ for (i = 0; i < EDMA_MAX_RECEIVE_QUEUE; i++) ++ edma_write_reg(EDMA_REG_RX_INT_MASK_Q(i), 0x0); ++ ++ for (i = 0; i < EDMA_MAX_TRANSMIT_QUEUE; i++) ++ edma_write_reg(EDMA_REG_TX_INT_MASK_Q(i), 0x0); ++ edma_write_reg(EDMA_REG_MISC_IMR, 0); ++ edma_write_reg(EDMA_REG_WOL_IMR, 0); ++} ++ ++/* edma_free_irqs() ++ * Free All IRQs ++ */ ++void edma_free_irqs(struct edma_adapter *adapter) ++{ ++ struct edma_common_info *edma_cinfo = adapter->edma_cinfo; ++ int i, j; ++ int k = ((edma_cinfo->num_rx_queues == 4) ? 1 : 2); ++ ++ for (i = 0; i < CONFIG_NR_CPUS; i++) { ++ for (j = edma_cinfo->edma_percpu_info[i].tx_start; j < (edma_cinfo->edma_percpu_info[i].tx_start + 4); j++) ++ free_irq(edma_cinfo->tx_irq[j], &edma_cinfo->edma_percpu_info[i]); ++ ++ for (j = edma_cinfo->edma_percpu_info[i].rx_start; j < (edma_cinfo->edma_percpu_info[i].rx_start + k); j++) ++ free_irq(edma_cinfo->rx_irq[j], &edma_cinfo->edma_percpu_info[i]); ++ } ++} ++ ++/* edma_enable_rx_ctrl() ++ * Enable RX queue control ++ */ ++void edma_enable_rx_ctrl(struct edma_hw *hw) ++{ ++ u32 data; ++ ++ edma_read_reg(EDMA_REG_RXQ_CTRL, &data); ++ data |= EDMA_RXQ_CTRL_EN; ++ edma_write_reg(EDMA_REG_RXQ_CTRL, data); ++} ++ ++ ++/* edma_enable_tx_ctrl() ++ * Enable TX queue control ++ */ ++void edma_enable_tx_ctrl(struct edma_hw *hw) ++{ ++ u32 data; ++ ++ edma_read_reg(EDMA_REG_TXQ_CTRL, &data); ++ data |= EDMA_TXQ_CTRL_TXQ_EN; ++ edma_write_reg(EDMA_REG_TXQ_CTRL, data); ++} ++ ++/* edma_stop_rx_tx() ++ * Disable RX/TQ Queue control ++ */ ++void edma_stop_rx_tx(struct edma_hw *hw) ++{ ++ u32 data; ++ ++ edma_read_reg(EDMA_REG_RXQ_CTRL, &data); ++ data &= ~EDMA_RXQ_CTRL_EN; ++ edma_write_reg(EDMA_REG_RXQ_CTRL, data); ++ edma_read_reg(EDMA_REG_TXQ_CTRL, &data); ++ data &= ~EDMA_TXQ_CTRL_TXQ_EN; ++ edma_write_reg(EDMA_REG_TXQ_CTRL, data); ++} ++ ++/* edma_reset() ++ * Reset the EDMA ++ */ ++int edma_reset(struct edma_common_info *edma_cinfo) ++{ ++ struct edma_hw *hw = &edma_cinfo->hw; ++ ++ edma_irq_disable(edma_cinfo); ++ ++ edma_clear_irq_status(); ++ ++ edma_stop_rx_tx(hw); ++ ++ return 0; ++} ++ ++/* edma_fill_netdev() ++ * Fill netdev for each etdr ++ */ ++int edma_fill_netdev(struct edma_common_info *edma_cinfo, int queue_id, ++ int dev, int txq_id) ++{ ++ struct edma_tx_desc_ring *etdr; ++ int i = 0; ++ ++ etdr = edma_cinfo->tpd_ring[queue_id]; ++ ++ while (etdr->netdev[i]) ++ i++; ++ ++ if (i >= EDMA_MAX_NETDEV_PER_QUEUE) ++ return -1; ++ ++ /* Populate the netdev associated with the tpd ring */ ++ etdr->netdev[i] = edma_netdev[dev]; ++ etdr->nq[i] = netdev_get_tx_queue(edma_netdev[dev], txq_id); ++ ++ return 0; ++} ++ ++/* edma_set_mac() ++ * Change the Ethernet Address of the NIC ++ */ ++int edma_set_mac_addr(struct net_device *netdev, void *p) ++{ ++ struct sockaddr *addr = p; ++ ++ if (!is_valid_ether_addr(addr->sa_data)) ++ return -EINVAL; ++ ++ if (netif_running(netdev)) ++ return -EBUSY; ++ ++ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ++ return 0; ++} ++ ++/* edma_set_stp_rstp() ++ * set stp/rstp ++ */ ++void edma_set_stp_rstp(bool rstp) ++{ ++ edma_stp_rstp = rstp; ++} ++ ++/* edma_assign_ath_hdr_type() ++ * assign atheros header eth type ++ */ ++void edma_assign_ath_hdr_type(int eth_type) ++{ ++ edma_ath_eth_type = eth_type & EDMA_ETH_TYPE_MASK; ++} ++ ++/* edma_get_default_vlan_tag() ++ * Used by other modules to get the default vlan tag ++ */ ++int edma_get_default_vlan_tag(struct net_device *netdev) ++{ ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ ++ if (adapter->default_vlan_tag) ++ return adapter->default_vlan_tag; ++ ++ return 0; ++} ++ ++/* edma_open() ++ * gets called when netdevice is up, start the queue. ++ */ ++int edma_open(struct net_device *netdev) ++{ ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ struct platform_device *pdev = adapter->edma_cinfo->pdev; ++ ++ netif_tx_start_all_queues(netdev); ++ edma_initialise_rfs_flow_table(adapter); ++ set_bit(__EDMA_UP, &adapter->state_flags); ++ ++ /* if Link polling is enabled, in our case enabled for WAN, then ++ * do a phy start, else always set link as UP ++ */ ++ if (adapter->poll_required) { ++ if (!IS_ERR(adapter->phydev)) { ++ phy_start(adapter->phydev); ++ phy_start_aneg(adapter->phydev); ++ adapter->link_state = __EDMA_LINKDOWN; ++ } else { ++ dev_dbg(&pdev->dev, "Invalid PHY device for a link polled interface\n"); ++ } ++ } else { ++ adapter->link_state = __EDMA_LINKUP; ++ netif_carrier_on(netdev); ++ } ++ ++ return 0; ++} ++ ++ ++/* edma_close() ++ * gets called when netdevice is down, stops the queue. ++ */ ++int edma_close(struct net_device *netdev) ++{ ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ ++ edma_free_rfs_flow_table(adapter); ++ netif_carrier_off(netdev); ++ netif_tx_stop_all_queues(netdev); ++ ++ if (adapter->poll_required) { ++ if (!IS_ERR(adapter->phydev)) ++ phy_stop(adapter->phydev); ++ } ++ ++ adapter->link_state = __EDMA_LINKDOWN; ++ ++ /* Set GMAC state to UP before link state is checked ++ */ ++ clear_bit(__EDMA_UP, &adapter->state_flags); ++ ++ return 0; ++} ++ ++/* edma_poll ++ * polling function that gets called when the napi gets scheduled. ++ * ++ * Main sequence of task performed in this api ++ * is clear irq status -> clear_tx_irq -> clean_rx_irq-> ++ * enable interrupts. ++ */ ++int edma_poll(struct napi_struct *napi, int budget) ++{ ++ struct edma_per_cpu_queues_info *edma_percpu_info = container_of(napi, ++ struct edma_per_cpu_queues_info, napi); ++ struct edma_common_info *edma_cinfo = edma_percpu_info->edma_cinfo; ++ u32 reg_data; ++ u32 shadow_rx_status, shadow_tx_status; ++ int queue_id; ++ int i, work_done = 0; ++ ++ /* Store the Rx/Tx status by ANDing it with ++ * appropriate CPU RX?TX mask ++ */ ++ edma_read_reg(EDMA_REG_RX_ISR, ®_data); ++ edma_percpu_info->rx_status |= reg_data & edma_percpu_info->rx_mask; ++ shadow_rx_status = edma_percpu_info->rx_status; ++ edma_read_reg(EDMA_REG_TX_ISR, ®_data); ++ edma_percpu_info->tx_status |= reg_data & edma_percpu_info->tx_mask; ++ shadow_tx_status = edma_percpu_info->tx_status; ++ ++ /* Every core will have a start, which will be computed ++ * in probe and stored in edma_percpu_info->tx_start variable. ++ * We will shift the status bit by tx_start to obtain ++ * status bits for the core on which the current processing ++ * is happening. Since, there are 4 tx queues per core, ++ * we will run the loop till we get the correct queue to clear. ++ */ ++ while (edma_percpu_info->tx_status) { ++ queue_id = ffs(edma_percpu_info->tx_status) - 1; ++ edma_tx_complete(edma_cinfo, queue_id); ++ edma_percpu_info->tx_status &= ~(1 << queue_id); ++ } ++ ++ /* Every core will have a start, which will be computed ++ * in probe and stored in edma_percpu_info->tx_start variable. ++ * We will shift the status bit by tx_start to obtain ++ * status bits for the core on which the current processing ++ * is happening. Since, there are 4 tx queues per core, we ++ * will run the loop till we get the correct queue to clear. ++ */ ++ while (edma_percpu_info->rx_status) { ++ queue_id = ffs(edma_percpu_info->rx_status) - 1; ++ edma_rx_complete(edma_cinfo, &work_done, ++ budget, queue_id, napi); ++ ++ if (likely(work_done < budget)) ++ edma_percpu_info->rx_status &= ~(1 << queue_id); ++ else ++ break; ++ } ++ ++ /* Clear the status register, to avoid the interrupts to ++ * reoccur.This clearing of interrupt status register is ++ * done here as writing to status register only takes place ++ * once the producer/consumer index has been updated to ++ * reflect that the packet transmission/reception went fine. ++ */ ++ edma_write_reg(EDMA_REG_RX_ISR, shadow_rx_status); ++ edma_write_reg(EDMA_REG_TX_ISR, shadow_tx_status); ++ ++ /* If budget not fully consumed, exit the polling mode */ ++ if (likely(work_done < budget)) { ++ napi_complete(napi); ++ ++ /* re-enable the interrupts */ ++ for (i = 0; i < edma_cinfo->num_rxq_per_core; i++) ++ edma_write_reg(EDMA_REG_RX_INT_MASK_Q(edma_percpu_info->rx_start + i), 0x1); ++ for (i = 0; i < edma_cinfo->num_txq_per_core; i++) ++ edma_write_reg(EDMA_REG_TX_INT_MASK_Q(edma_percpu_info->tx_start + i), 0x1); ++ } ++ ++ return work_done; ++} ++ ++/* edma interrupt() ++ * interrupt handler ++ */ ++irqreturn_t edma_interrupt(int irq, void *dev) ++{ ++ struct edma_per_cpu_queues_info *edma_percpu_info = (struct edma_per_cpu_queues_info *) dev; ++ struct edma_common_info *edma_cinfo = edma_percpu_info->edma_cinfo; ++ int i; ++ ++ /* Unmask the TX/RX interrupt register */ ++ for (i = 0; i < edma_cinfo->num_rxq_per_core; i++) ++ edma_write_reg(EDMA_REG_RX_INT_MASK_Q(edma_percpu_info->rx_start + i), 0x0); ++ ++ for (i = 0; i < edma_cinfo->num_txq_per_core; i++) ++ edma_write_reg(EDMA_REG_TX_INT_MASK_Q(edma_percpu_info->tx_start + i), 0x0); ++ ++ napi_schedule(&edma_percpu_info->napi); ++ ++ return IRQ_HANDLED; ++} +--- /dev/null ++++ b/drivers/net/ethernet/qualcomm/essedma/edma.h +@@ -0,0 +1,447 @@ ++/* ++ * Copyright (c) 2014 - 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 _EDMA_H_ ++#define _EDMA_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ess_edma.h" ++ ++#define EDMA_CPU_CORES_SUPPORTED 4 ++#define EDMA_MAX_PORTID_SUPPORTED 5 ++#define EDMA_MAX_VLAN_SUPPORTED EDMA_MAX_PORTID_SUPPORTED ++#define EDMA_MAX_PORTID_BITMAP_INDEX (EDMA_MAX_PORTID_SUPPORTED + 1) ++#define EDMA_MAX_PORTID_BITMAP_SUPPORTED 0x1f /* 0001_1111 = 0x1f */ ++#define EDMA_MAX_NETDEV_PER_QUEUE 4 /* 3 Netdev per queue, 1 space for indexing */ ++ ++#define EDMA_MAX_RECEIVE_QUEUE 8 ++#define EDMA_MAX_TRANSMIT_QUEUE 16 ++ ++/* WAN/LAN adapter number */ ++#define EDMA_WAN 0 ++#define EDMA_LAN 1 ++ ++/* VLAN tag */ ++#define EDMA_LAN_DEFAULT_VLAN 1 ++#define EDMA_WAN_DEFAULT_VLAN 2 ++ ++#define EDMA_DEFAULT_GROUP1_VLAN 1 ++#define EDMA_DEFAULT_GROUP2_VLAN 2 ++#define EDMA_DEFAULT_GROUP3_VLAN 3 ++#define EDMA_DEFAULT_GROUP4_VLAN 4 ++#define EDMA_DEFAULT_GROUP5_VLAN 5 ++ ++/* Queues exposed to linux kernel */ ++#define EDMA_NETDEV_TX_QUEUE 4 ++#define EDMA_NETDEV_RX_QUEUE 4 ++ ++/* Number of queues per core */ ++#define EDMA_NUM_TXQ_PER_CORE 4 ++#define EDMA_NUM_RXQ_PER_CORE 2 ++ ++#define EDMA_TPD_EOP_SHIFT 31 ++ ++#define EDMA_PORT_ID_SHIFT 12 ++#define EDMA_PORT_ID_MASK 0x7 ++ ++/* tpd word 3 bit 18-28 */ ++#define EDMA_TPD_PORT_BITMAP_SHIFT 18 ++ ++#define EDMA_TPD_FROM_CPU_SHIFT 25 ++ ++#define EDMA_FROM_CPU_MASK 0x80 ++#define EDMA_SKB_PRIORITY_MASK 0x38 ++ ++/* TX/RX descriptor ring count */ ++/* should be a power of 2 */ ++#define EDMA_RX_RING_SIZE 128 ++#define EDMA_TX_RING_SIZE 128 ++ ++/* Flags used in paged/non paged mode */ ++#define EDMA_RX_HEAD_BUFF_SIZE_JUMBO 256 ++#define EDMA_RX_HEAD_BUFF_SIZE 1540 ++ ++/* MAX frame size supported by switch */ ++#define EDMA_MAX_JUMBO_FRAME_SIZE 9216 ++ ++/* Configurations */ ++#define EDMA_INTR_CLEAR_TYPE 0 ++#define EDMA_INTR_SW_IDX_W_TYPE 0 ++#define EDMA_FIFO_THRESH_TYPE 0 ++#define EDMA_RSS_TYPE 0 ++#define EDMA_RX_IMT 0x0020 ++#define EDMA_TX_IMT 0x0050 ++#define EDMA_TPD_BURST 5 ++#define EDMA_TXF_BURST 0x100 ++#define EDMA_RFD_BURST 8 ++#define EDMA_RFD_THR 16 ++#define EDMA_RFD_LTHR 0 ++ ++/* RX/TX per CPU based mask/shift */ ++#define EDMA_TX_PER_CPU_MASK 0xF ++#define EDMA_RX_PER_CPU_MASK 0x3 ++#define EDMA_TX_PER_CPU_MASK_SHIFT 0x2 ++#define EDMA_RX_PER_CPU_MASK_SHIFT 0x1 ++#define EDMA_TX_CPU_START_SHIFT 0x2 ++#define EDMA_RX_CPU_START_SHIFT 0x1 ++ ++/* FLags used in transmit direction */ ++#define EDMA_HW_CHECKSUM 0x00000001 ++#define EDMA_VLAN_TX_TAG_INSERT_FLAG 0x00000002 ++#define EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG 0x00000004 ++ ++#define EDMA_SW_DESC_FLAG_LAST 0x1 ++#define EDMA_SW_DESC_FLAG_SKB_HEAD 0x2 ++#define EDMA_SW_DESC_FLAG_SKB_FRAG 0x4 ++#define EDMA_SW_DESC_FLAG_SKB_FRAGLIST 0x8 ++#define EDMA_SW_DESC_FLAG_SKB_NONE 0x10 ++#define EDMA_SW_DESC_FLAG_SKB_REUSE 0x20 ++ ++ ++#define EDMA_MAX_SKB_FRAGS (MAX_SKB_FRAGS + 1) ++ ++/* Ethtool specific list of EDMA supported features */ ++#define EDMA_SUPPORTED_FEATURES (SUPPORTED_10baseT_Half \ ++ | SUPPORTED_10baseT_Full \ ++ | SUPPORTED_100baseT_Half \ ++ | SUPPORTED_100baseT_Full \ ++ | SUPPORTED_1000baseT_Full) ++ ++/* Recevie side atheros Header */ ++#define EDMA_RX_ATH_HDR_VERSION 0x2 ++#define EDMA_RX_ATH_HDR_VERSION_SHIFT 14 ++#define EDMA_RX_ATH_HDR_PRIORITY_SHIFT 11 ++#define EDMA_RX_ATH_PORT_TYPE_SHIFT 6 ++#define EDMA_RX_ATH_HDR_RSTP_PORT_TYPE 0x4 ++ ++/* Transmit side atheros Header */ ++#define EDMA_TX_ATH_HDR_PORT_BITMAP_MASK 0x7F ++#define EDMA_TX_ATH_HDR_FROM_CPU_MASK 0x80 ++#define EDMA_TX_ATH_HDR_FROM_CPU_SHIFT 7 ++ ++#define EDMA_TXQ_START_CORE0 8 ++#define EDMA_TXQ_START_CORE1 12 ++#define EDMA_TXQ_START_CORE2 0 ++#define EDMA_TXQ_START_CORE3 4 ++ ++#define EDMA_TXQ_IRQ_MASK_CORE0 0x0F00 ++#define EDMA_TXQ_IRQ_MASK_CORE1 0xF000 ++#define EDMA_TXQ_IRQ_MASK_CORE2 0x000F ++#define EDMA_TXQ_IRQ_MASK_CORE3 0x00F0 ++ ++#define EDMA_ETH_HDR_LEN 12 ++#define EDMA_ETH_TYPE_MASK 0xFFFF ++ ++#define EDMA_RX_BUFFER_WRITE 16 ++#define EDMA_RFD_AVAIL_THR 80 ++ ++#define EDMA_GMAC_NO_MDIO_PHY PHY_MAX_ADDR ++ ++extern int ssdk_rfs_ipct_rule_set(__be32 ip_src, __be32 ip_dst, ++ __be16 sport, __be16 dport, ++ uint8_t proto, u16 loadbalance, bool action); ++struct edma_ethtool_statistics { ++ u32 tx_q0_pkt; ++ u32 tx_q1_pkt; ++ u32 tx_q2_pkt; ++ u32 tx_q3_pkt; ++ u32 tx_q4_pkt; ++ u32 tx_q5_pkt; ++ u32 tx_q6_pkt; ++ u32 tx_q7_pkt; ++ u32 tx_q8_pkt; ++ u32 tx_q9_pkt; ++ u32 tx_q10_pkt; ++ u32 tx_q11_pkt; ++ u32 tx_q12_pkt; ++ u32 tx_q13_pkt; ++ u32 tx_q14_pkt; ++ u32 tx_q15_pkt; ++ u32 tx_q0_byte; ++ u32 tx_q1_byte; ++ u32 tx_q2_byte; ++ u32 tx_q3_byte; ++ u32 tx_q4_byte; ++ u32 tx_q5_byte; ++ u32 tx_q6_byte; ++ u32 tx_q7_byte; ++ u32 tx_q8_byte; ++ u32 tx_q9_byte; ++ u32 tx_q10_byte; ++ u32 tx_q11_byte; ++ u32 tx_q12_byte; ++ u32 tx_q13_byte; ++ u32 tx_q14_byte; ++ u32 tx_q15_byte; ++ u32 rx_q0_pkt; ++ u32 rx_q1_pkt; ++ u32 rx_q2_pkt; ++ u32 rx_q3_pkt; ++ u32 rx_q4_pkt; ++ u32 rx_q5_pkt; ++ u32 rx_q6_pkt; ++ u32 rx_q7_pkt; ++ u32 rx_q0_byte; ++ u32 rx_q1_byte; ++ u32 rx_q2_byte; ++ u32 rx_q3_byte; ++ u32 rx_q4_byte; ++ u32 rx_q5_byte; ++ u32 rx_q6_byte; ++ u32 rx_q7_byte; ++ u32 tx_desc_error; ++}; ++ ++struct edma_mdio_data { ++ struct mii_bus *mii_bus; ++ void __iomem *membase; ++ int phy_irq[PHY_MAX_ADDR]; ++}; ++ ++/* EDMA LINK state */ ++enum edma_link_state { ++ __EDMA_LINKUP, /* Indicate link is UP */ ++ __EDMA_LINKDOWN /* Indicate link is down */ ++}; ++ ++/* EDMA GMAC state */ ++enum edma_gmac_state { ++ __EDMA_UP /* use to indicate GMAC is up */ ++}; ++ ++/* edma transmit descriptor */ ++struct edma_tx_desc { ++ __le16 len; /* full packet including CRC */ ++ __le16 svlan_tag; /* vlan tag */ ++ __le32 word1; /* byte 4-7 */ ++ __le32 addr; /* address of buffer */ ++ __le32 word3; /* byte 12 */ ++}; ++ ++/* edma receive return descriptor */ ++struct edma_rx_return_desc { ++ u16 rrd0; ++ u16 rrd1; ++ u16 rrd2; ++ u16 rrd3; ++ u16 rrd4; ++ u16 rrd5; ++ u16 rrd6; ++ u16 rrd7; ++}; ++ ++/* RFD descriptor */ ++struct edma_rx_free_desc { ++ __le32 buffer_addr; /* buffer address */ ++}; ++ ++/* edma hw specific data */ ++struct edma_hw { ++ u32 __iomem *hw_addr; /* inner register address */ ++ struct edma_adapter *adapter; /* netdevice adapter */ ++ u32 rx_intr_mask; /*rx interrupt mask */ ++ u32 tx_intr_mask; /* tx interrupt nask */ ++ u32 misc_intr_mask; /* misc interrupt mask */ ++ u32 wol_intr_mask; /* wake on lan interrupt mask */ ++ bool intr_clear_type; /* interrupt clear */ ++ bool intr_sw_idx_w; /* interrupt software index */ ++ u32 rx_head_buff_size; /* Rx buffer size */ ++ u8 rss_type; /* rss protocol type */ ++}; ++ ++/* edma_sw_desc stores software descriptor ++ * SW descriptor has 1:1 map with HW descriptor ++ */ ++struct edma_sw_desc { ++ struct sk_buff *skb; ++ dma_addr_t dma; /* dma address */ ++ u16 length; /* Tx/Rx buffer length */ ++ u32 flags; ++}; ++ ++/* per core related information */ ++struct edma_per_cpu_queues_info { ++ struct napi_struct napi; /* napi associated with the core */ ++ u32 tx_mask; /* tx interrupt mask */ ++ u32 rx_mask; /* rx interrupt mask */ ++ u32 tx_status; /* tx interrupt status */ ++ u32 rx_status; /* rx interrupt status */ ++ u32 tx_start; /* tx queue start */ ++ u32 rx_start; /* rx queue start */ ++ struct edma_common_info *edma_cinfo; /* edma common info */ ++}; ++ ++/* edma specific common info */ ++struct edma_common_info { ++ struct edma_tx_desc_ring *tpd_ring[16]; /* 16 Tx queues */ ++ struct edma_rfd_desc_ring *rfd_ring[8]; /* 8 Rx queues */ ++ struct platform_device *pdev; /* device structure */ ++ struct net_device *netdev[EDMA_MAX_PORTID_SUPPORTED]; ++ struct net_device *portid_netdev_lookup_tbl[EDMA_MAX_PORTID_BITMAP_INDEX]; ++ struct ctl_table_header *edma_ctl_table_hdr; ++ int num_gmac; ++ struct edma_ethtool_statistics edma_ethstats; /* ethtool stats */ ++ int num_rx_queues; /* number of rx queue */ ++ u32 num_tx_queues; /* number of tx queue */ ++ u32 tx_irq[16]; /* number of tx irq */ ++ u32 rx_irq[8]; /* number of rx irq */ ++ u32 from_cpu; /* from CPU TPD field */ ++ u32 num_rxq_per_core; /* Rx queues per core */ ++ u32 num_txq_per_core; /* Tx queues per core */ ++ u16 tx_ring_count; /* Tx ring count */ ++ u16 rx_ring_count; /* Rx ring*/ ++ u16 rx_head_buffer_len; /* rx buffer length */ ++ u16 rx_page_buffer_len; /* rx buffer length */ ++ u32 page_mode; /* Jumbo frame supported flag */ ++ u32 fraglist_mode; /* fraglist supported flag */ ++ struct edma_hw hw; /* edma hw specific structure */ ++ struct edma_per_cpu_queues_info edma_percpu_info[CONFIG_NR_CPUS]; /* per cpu information */ ++ spinlock_t stats_lock; /* protect edma stats area for updation */ ++ struct timer_list edma_stats_timer; ++}; ++ ++/* transimit packet descriptor (tpd) ring */ ++struct edma_tx_desc_ring { ++ struct netdev_queue *nq[EDMA_MAX_NETDEV_PER_QUEUE]; /* Linux queue index */ ++ struct net_device *netdev[EDMA_MAX_NETDEV_PER_QUEUE]; ++ /* Array of netdevs associated with the tpd ring */ ++ void *hw_desc; /* descriptor ring virtual address */ ++ struct edma_sw_desc *sw_desc; /* buffer associated with ring */ ++ int netdev_bmp; /* Bitmap for per-ring netdevs */ ++ u32 size; /* descriptor ring length in bytes */ ++ u16 count; /* number of descriptors in the ring */ ++ dma_addr_t dma; /* descriptor ring physical address */ ++ u16 sw_next_to_fill; /* next Tx descriptor to fill */ ++ u16 sw_next_to_clean; /* next Tx descriptor to clean */ ++}; ++ ++/* receive free descriptor (rfd) ring */ ++struct edma_rfd_desc_ring { ++ void *hw_desc; /* descriptor ring virtual address */ ++ struct edma_sw_desc *sw_desc; /* buffer associated with ring */ ++ u16 size; /* bytes allocated to sw_desc */ ++ u16 count; /* number of descriptors in the ring */ ++ dma_addr_t dma; /* descriptor ring physical address */ ++ u16 sw_next_to_fill; /* next descriptor to fill */ ++ u16 sw_next_to_clean; /* next descriptor to clean */ ++}; ++ ++/* edma_rfs_flter_node - rfs filter node in hash table */ ++struct edma_rfs_filter_node { ++ struct flow_keys keys; ++ u32 flow_id; /* flow_id of filter provided by kernel */ ++ u16 filter_id; /* filter id of filter returned by adaptor */ ++ u16 rq_id; /* desired rq index */ ++ struct hlist_node node; /* edma rfs list node */ ++}; ++ ++/* edma_rfs_flow_tbl - rfs flow table */ ++struct edma_rfs_flow_table { ++ u16 max_num_filter; /* Maximum number of filters edma supports */ ++ u16 hashtoclean; /* hash table index to clean next */ ++ int filter_available; /* Number of free filters available */ ++ struct hlist_head hlist_head[EDMA_RFS_FLOW_ENTRIES]; ++ spinlock_t rfs_ftab_lock; ++ struct timer_list expire_rfs; /* timer function for edma_rps_may_expire_flow */ ++}; ++ ++/* EDMA net device structure */ ++struct edma_adapter { ++ struct net_device *netdev; /* netdevice */ ++ struct platform_device *pdev; /* platform device */ ++ struct edma_common_info *edma_cinfo; /* edma common info */ ++ struct phy_device *phydev; /* Phy device */ ++ struct edma_rfs_flow_table rfs; /* edma rfs flow table */ ++ struct net_device_stats stats; /* netdev statistics */ ++ set_rfs_filter_callback_t set_rfs_rule; ++ u32 flags;/* status flags */ ++ unsigned long state_flags; /* GMAC up/down flags */ ++ u32 forced_speed; /* link force speed */ ++ u32 forced_duplex; /* link force duplex */ ++ u32 link_state; /* phy link state */ ++ u32 phy_mdio_addr; /* PHY device address on MII interface */ ++ u32 poll_required; /* check if link polling is required */ ++ u32 tx_start_offset[CONFIG_NR_CPUS]; /* tx queue start */ ++ u32 default_vlan_tag; /* vlan tag */ ++ u32 dp_bitmap; ++ uint8_t phy_id[MII_BUS_ID_SIZE + 3]; ++}; ++ ++int edma_alloc_queues_tx(struct edma_common_info *edma_cinfo); ++int edma_alloc_queues_rx(struct edma_common_info *edma_cinfo); ++int edma_open(struct net_device *netdev); ++int edma_close(struct net_device *netdev); ++void edma_free_tx_resources(struct edma_common_info *edma_c_info); ++void edma_free_rx_resources(struct edma_common_info *edma_c_info); ++int edma_alloc_tx_rings(struct edma_common_info *edma_cinfo); ++int edma_alloc_rx_rings(struct edma_common_info *edma_cinfo); ++void edma_free_tx_rings(struct edma_common_info *edma_cinfo); ++void edma_free_rx_rings(struct edma_common_info *edma_cinfo); ++void edma_free_queues(struct edma_common_info *edma_cinfo); ++void edma_irq_disable(struct edma_common_info *edma_cinfo); ++int edma_reset(struct edma_common_info *edma_cinfo); ++int edma_poll(struct napi_struct *napi, int budget); ++netdev_tx_t edma_xmit(struct sk_buff *skb, ++ struct net_device *netdev); ++int edma_configure(struct edma_common_info *edma_cinfo); ++void edma_irq_enable(struct edma_common_info *edma_cinfo); ++void edma_enable_tx_ctrl(struct edma_hw *hw); ++void edma_enable_rx_ctrl(struct edma_hw *hw); ++void edma_stop_rx_tx(struct edma_hw *hw); ++void edma_free_irqs(struct edma_adapter *adapter); ++irqreturn_t edma_interrupt(int irq, void *dev); ++void edma_write_reg(u16 reg_addr, u32 reg_value); ++void edma_read_reg(u16 reg_addr, volatile u32 *reg_value); ++struct net_device_stats *edma_get_stats(struct net_device *netdev); ++int edma_set_mac_addr(struct net_device *netdev, void *p); ++int edma_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, ++ u16 rxq, u32 flow_id); ++int edma_register_rfs_filter(struct net_device *netdev, ++ set_rfs_filter_callback_t set_filter); ++void edma_flow_may_expire(struct timer_list *t); ++void edma_set_ethtool_ops(struct net_device *netdev); ++void edma_set_stp_rstp(bool tag); ++void edma_assign_ath_hdr_type(int tag); ++int edma_get_default_vlan_tag(struct net_device *netdev); ++void edma_adjust_link(struct net_device *netdev); ++int edma_fill_netdev(struct edma_common_info *edma_cinfo, int qid, int num, int txq_id); ++void edma_read_append_stats(struct edma_common_info *edma_cinfo); ++void edma_change_tx_coalesce(int usecs); ++void edma_change_rx_coalesce(int usecs); ++void edma_get_tx_rx_coalesce(u32 *reg_val); ++void edma_clear_irq_status(void); ++#endif /* _EDMA_H_ */ +--- /dev/null ++++ b/drivers/net/ethernet/qualcomm/essedma/edma_axi.c +@@ -0,0 +1,1216 @@ ++/* ++ * Copyright (c) 2014 - 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 ++#include ++#include ++#include ++#include "edma.h" ++#include "ess_edma.h" ++ ++/* Weight round robin and virtual QID mask */ ++#define EDMA_WRR_VID_SCTL_MASK 0xffff ++ ++/* Weight round robin and virtual QID shift */ ++#define EDMA_WRR_VID_SCTL_SHIFT 16 ++ ++char edma_axi_driver_name[] = "ess_edma"; ++static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | ++ NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP; ++ ++static u32 edma_hw_addr; ++ ++char edma_tx_irq[16][64]; ++char edma_rx_irq[8][64]; ++struct net_device *edma_netdev[EDMA_MAX_PORTID_SUPPORTED]; ++static u16 tx_start[4] = {EDMA_TXQ_START_CORE0, EDMA_TXQ_START_CORE1, ++ EDMA_TXQ_START_CORE2, EDMA_TXQ_START_CORE3}; ++static u32 tx_mask[4] = {EDMA_TXQ_IRQ_MASK_CORE0, EDMA_TXQ_IRQ_MASK_CORE1, ++ EDMA_TXQ_IRQ_MASK_CORE2, EDMA_TXQ_IRQ_MASK_CORE3}; ++ ++static u32 edma_default_ltag __read_mostly = EDMA_LAN_DEFAULT_VLAN; ++static u32 edma_default_wtag __read_mostly = EDMA_WAN_DEFAULT_VLAN; ++static u32 edma_default_group1_vtag __read_mostly = EDMA_DEFAULT_GROUP1_VLAN; ++static u32 edma_default_group2_vtag __read_mostly = EDMA_DEFAULT_GROUP2_VLAN; ++static u32 edma_default_group3_vtag __read_mostly = EDMA_DEFAULT_GROUP3_VLAN; ++static u32 edma_default_group4_vtag __read_mostly = EDMA_DEFAULT_GROUP4_VLAN; ++static u32 edma_default_group5_vtag __read_mostly = EDMA_DEFAULT_GROUP5_VLAN; ++static u32 edma_rss_idt_val = EDMA_RSS_IDT_VALUE; ++static u32 edma_rss_idt_idx; ++ ++static int edma_weight_assigned_to_q __read_mostly; ++static int edma_queue_to_virtual_q __read_mostly; ++static bool edma_enable_rstp __read_mostly; ++static int edma_athr_hdr_eth_type __read_mostly; ++ ++static int page_mode; ++module_param(page_mode, int, 0); ++MODULE_PARM_DESC(page_mode, "enable page mode"); ++ ++static int overwrite_mode; ++module_param(overwrite_mode, int, 0); ++MODULE_PARM_DESC(overwrite_mode, "overwrite default page_mode setting"); ++ ++static int jumbo_mru = EDMA_RX_HEAD_BUFF_SIZE; ++module_param(jumbo_mru, int, 0); ++MODULE_PARM_DESC(jumbo_mru, "enable fraglist support"); ++ ++static int num_rxq = 4; ++module_param(num_rxq, int, 0); ++MODULE_PARM_DESC(num_rxq, "change the number of rx queues"); ++ ++void edma_write_reg(u16 reg_addr, u32 reg_value) ++{ ++ writel(reg_value, ((void __iomem *)(edma_hw_addr + reg_addr))); ++} ++ ++void edma_read_reg(u16 reg_addr, volatile u32 *reg_value) ++{ ++ *reg_value = readl((void __iomem *)(edma_hw_addr + reg_addr)); ++} ++ ++/* edma_change_tx_coalesce() ++ * change tx interrupt moderation timer ++ */ ++void edma_change_tx_coalesce(int usecs) ++{ ++ u32 reg_value; ++ ++ /* Here, we right shift the value from the user by 1, this is ++ * done because IMT resolution timer is 2usecs. 1 count ++ * of this register corresponds to 2 usecs. ++ */ ++ edma_read_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, ®_value); ++ reg_value = ((reg_value & 0xffff) | ((usecs >> 1) << 16)); ++ edma_write_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, reg_value); ++} ++ ++/* edma_change_rx_coalesce() ++ * change rx interrupt moderation timer ++ */ ++void edma_change_rx_coalesce(int usecs) ++{ ++ u32 reg_value; ++ ++ /* Here, we right shift the value from the user by 1, this is ++ * done because IMT resolution timer is 2usecs. 1 count ++ * of this register corresponds to 2 usecs. ++ */ ++ edma_read_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, ®_value); ++ reg_value = ((reg_value & 0xffff0000) | (usecs >> 1)); ++ edma_write_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, reg_value); ++} ++ ++/* edma_get_tx_rx_coalesce() ++ * Get tx/rx interrupt moderation value ++ */ ++void edma_get_tx_rx_coalesce(u32 *reg_val) ++{ ++ edma_read_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, reg_val); ++} ++ ++void edma_read_append_stats(struct edma_common_info *edma_cinfo) ++{ ++ uint32_t *p; ++ int i; ++ u32 stat; ++ ++ spin_lock(&edma_cinfo->stats_lock); ++ p = (uint32_t *)&(edma_cinfo->edma_ethstats); ++ ++ for (i = 0; i < EDMA_MAX_TRANSMIT_QUEUE; i++) { ++ edma_read_reg(EDMA_REG_TX_STAT_PKT_Q(i), &stat); ++ *p += stat; ++ p++; ++ } ++ ++ for (i = 0; i < EDMA_MAX_TRANSMIT_QUEUE; i++) { ++ edma_read_reg(EDMA_REG_TX_STAT_BYTE_Q(i), &stat); ++ *p += stat; ++ p++; ++ } ++ ++ for (i = 0; i < EDMA_MAX_RECEIVE_QUEUE; i++) { ++ edma_read_reg(EDMA_REG_RX_STAT_PKT_Q(i), &stat); ++ *p += stat; ++ p++; ++ } ++ ++ for (i = 0; i < EDMA_MAX_RECEIVE_QUEUE; i++) { ++ edma_read_reg(EDMA_REG_RX_STAT_BYTE_Q(i), &stat); ++ *p += stat; ++ p++; ++ } ++ ++ spin_unlock(&edma_cinfo->stats_lock); ++} ++ ++static void edma_statistics_timer(struct timer_list *t) ++{ ++ struct edma_common_info *edma_cinfo = ++ from_timer(edma_cinfo, t, edma_stats_timer); ++ ++ edma_read_append_stats(edma_cinfo); ++ ++ mod_timer(&edma_cinfo->edma_stats_timer, jiffies + 1*HZ); ++} ++ ++static int edma_enable_stp_rstp(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ if (write) ++ edma_set_stp_rstp(edma_enable_rstp); ++ ++ return ret; ++} ++ ++static int edma_ath_hdr_eth_type(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ if (write) ++ edma_assign_ath_hdr_type(edma_athr_hdr_eth_type); ++ ++ return ret; ++} ++ ++static int edma_change_default_lan_vlan(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct edma_adapter *adapter; ++ int ret; ++ ++ if (!edma_netdev[1]) { ++ pr_err("Netdevice for default_lan does not exist\n"); ++ return -1; ++ } ++ ++ adapter = netdev_priv(edma_netdev[1]); ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ ++ if (write) ++ adapter->default_vlan_tag = edma_default_ltag; ++ ++ return ret; ++} ++ ++static int edma_change_default_wan_vlan(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct edma_adapter *adapter; ++ int ret; ++ ++ if (!edma_netdev[0]) { ++ pr_err("Netdevice for default_wan does not exist\n"); ++ return -1; ++ } ++ ++ adapter = netdev_priv(edma_netdev[0]); ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ ++ if (write) ++ adapter->default_vlan_tag = edma_default_wtag; ++ ++ return ret; ++} ++ ++static int edma_change_group1_vtag(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct edma_adapter *adapter; ++ struct edma_common_info *edma_cinfo; ++ int ret; ++ ++ if (!edma_netdev[0]) { ++ pr_err("Netdevice for Group 1 does not exist\n"); ++ return -1; ++ } ++ ++ adapter = netdev_priv(edma_netdev[0]); ++ edma_cinfo = adapter->edma_cinfo; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ ++ if (write) ++ adapter->default_vlan_tag = edma_default_group1_vtag; ++ ++ return ret; ++} ++ ++static int edma_change_group2_vtag(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct edma_adapter *adapter; ++ struct edma_common_info *edma_cinfo; ++ int ret; ++ ++ if (!edma_netdev[1]) { ++ pr_err("Netdevice for Group 2 does not exist\n"); ++ return -1; ++ } ++ ++ adapter = netdev_priv(edma_netdev[1]); ++ edma_cinfo = adapter->edma_cinfo; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ ++ if (write) ++ adapter->default_vlan_tag = edma_default_group2_vtag; ++ ++ return ret; ++} ++ ++static int edma_change_group3_vtag(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct edma_adapter *adapter; ++ struct edma_common_info *edma_cinfo; ++ int ret; ++ ++ if (!edma_netdev[2]) { ++ pr_err("Netdevice for Group 3 does not exist\n"); ++ return -1; ++ } ++ ++ adapter = netdev_priv(edma_netdev[2]); ++ edma_cinfo = adapter->edma_cinfo; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ ++ if (write) ++ adapter->default_vlan_tag = edma_default_group3_vtag; ++ ++ return ret; ++} ++ ++static int edma_change_group4_vtag(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct edma_adapter *adapter; ++ struct edma_common_info *edma_cinfo; ++ int ret; ++ ++ if (!edma_netdev[3]) { ++ pr_err("Netdevice for Group 4 does not exist\n"); ++ return -1; ++ } ++ ++ adapter = netdev_priv(edma_netdev[3]); ++ edma_cinfo = adapter->edma_cinfo; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ ++ if (write) ++ adapter->default_vlan_tag = edma_default_group4_vtag; ++ ++ return ret; ++} ++ ++static int edma_change_group5_vtag(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct edma_adapter *adapter; ++ struct edma_common_info *edma_cinfo; ++ int ret; ++ ++ if (!edma_netdev[4]) { ++ pr_err("Netdevice for Group 5 does not exist\n"); ++ return -1; ++ } ++ ++ adapter = netdev_priv(edma_netdev[4]); ++ edma_cinfo = adapter->edma_cinfo; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ ++ if (write) ++ adapter->default_vlan_tag = edma_default_group5_vtag; ++ ++ return ret; ++} ++ ++static int edma_set_rss_idt_value(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ if (write && !ret) ++ edma_write_reg(EDMA_REG_RSS_IDT(edma_rss_idt_idx), ++ edma_rss_idt_val); ++ return ret; ++} ++ ++static int edma_set_rss_idt_idx(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret; ++ u32 old_value = edma_rss_idt_idx; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ if (!write || ret) ++ return ret; ++ ++ if (edma_rss_idt_idx >= EDMA_NUM_IDT) { ++ pr_err("Invalid RSS indirection table index %d\n", ++ edma_rss_idt_idx); ++ edma_rss_idt_idx = old_value; ++ return -EINVAL; ++ } ++ return ret; ++} ++ ++static int edma_weight_assigned_to_queues(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret, queue_id, weight; ++ u32 reg_data, data, reg_addr; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ if (write) { ++ queue_id = edma_weight_assigned_to_q & EDMA_WRR_VID_SCTL_MASK; ++ if (queue_id < 0 || queue_id > 15) { ++ pr_err("queue_id not within desired range\n"); ++ return -EINVAL; ++ } ++ ++ weight = edma_weight_assigned_to_q >> EDMA_WRR_VID_SCTL_SHIFT; ++ if (weight < 0 || weight > 0xF) { ++ pr_err("queue_id not within desired range\n"); ++ return -EINVAL; ++ } ++ ++ data = weight << EDMA_WRR_SHIFT(queue_id); ++ ++ reg_addr = EDMA_REG_WRR_CTRL_Q0_Q3 + (queue_id & ~0x3); ++ edma_read_reg(reg_addr, ®_data); ++ reg_data &= ~(1 << EDMA_WRR_SHIFT(queue_id)); ++ edma_write_reg(reg_addr, data | reg_data); ++ } ++ ++ return ret; ++} ++ ++static int edma_queue_to_virtual_queue_map(struct ctl_table *table, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret, queue_id, virtual_qid; ++ u32 reg_data, data, reg_addr; ++ ++ ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ if (write) { ++ queue_id = edma_queue_to_virtual_q & EDMA_WRR_VID_SCTL_MASK; ++ if (queue_id < 0 || queue_id > 15) { ++ pr_err("queue_id not within desired range\n"); ++ return -EINVAL; ++ } ++ ++ virtual_qid = edma_queue_to_virtual_q >> ++ EDMA_WRR_VID_SCTL_SHIFT; ++ if (virtual_qid < 0 || virtual_qid > 8) { ++ pr_err("queue_id not within desired range\n"); ++ return -EINVAL; ++ } ++ ++ data = virtual_qid << EDMA_VQ_ID_SHIFT(queue_id); ++ ++ reg_addr = EDMA_REG_VQ_CTRL0 + (queue_id & ~0x3); ++ edma_read_reg(reg_addr, ®_data); ++ reg_data &= ~(1 << EDMA_VQ_ID_SHIFT(queue_id)); ++ edma_write_reg(reg_addr, data | reg_data); ++ } ++ ++ return ret; ++} ++ ++static struct ctl_table edma_table[] = { ++ { ++ .procname = "default_lan_tag", ++ .data = &edma_default_ltag, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_change_default_lan_vlan ++ }, ++ { ++ .procname = "default_wan_tag", ++ .data = &edma_default_wtag, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_change_default_wan_vlan ++ }, ++ { ++ .procname = "weight_assigned_to_queues", ++ .data = &edma_weight_assigned_to_q, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_weight_assigned_to_queues ++ }, ++ { ++ .procname = "queue_to_virtual_queue_map", ++ .data = &edma_queue_to_virtual_q, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_queue_to_virtual_queue_map ++ }, ++ { ++ .procname = "enable_stp_rstp", ++ .data = &edma_enable_rstp, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_enable_stp_rstp ++ }, ++ { ++ .procname = "athr_hdr_eth_type", ++ .data = &edma_athr_hdr_eth_type, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_ath_hdr_eth_type ++ }, ++ { ++ .procname = "default_group1_vlan_tag", ++ .data = &edma_default_group1_vtag, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_change_group1_vtag ++ }, ++ { ++ .procname = "default_group2_vlan_tag", ++ .data = &edma_default_group2_vtag, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_change_group2_vtag ++ }, ++ { ++ .procname = "default_group3_vlan_tag", ++ .data = &edma_default_group3_vtag, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_change_group3_vtag ++ }, ++ { ++ .procname = "default_group4_vlan_tag", ++ .data = &edma_default_group4_vtag, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_change_group4_vtag ++ }, ++ { ++ .procname = "default_group5_vlan_tag", ++ .data = &edma_default_group5_vtag, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_change_group5_vtag ++ }, ++ { ++ .procname = "edma_rss_idt_value", ++ .data = &edma_rss_idt_val, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_set_rss_idt_value ++ }, ++ { ++ .procname = "edma_rss_idt_idx", ++ .data = &edma_rss_idt_idx, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = edma_set_rss_idt_idx ++ }, ++ {} ++}; ++ ++/* edma_axi_netdev_ops ++ * Describe the operations supported by registered netdevices ++ * ++ * static const struct net_device_ops edma_axi_netdev_ops = { ++ * .ndo_open = edma_open, ++ * .ndo_stop = edma_close, ++ * .ndo_start_xmit = edma_xmit_frame, ++ * .ndo_set_mac_address = edma_set_mac_addr, ++ * } ++ */ ++static const struct net_device_ops edma_axi_netdev_ops = { ++ .ndo_open = edma_open, ++ .ndo_stop = edma_close, ++ .ndo_start_xmit = edma_xmit, ++ .ndo_set_mac_address = edma_set_mac_addr, ++#ifdef CONFIG_RFS_ACCEL ++ .ndo_rx_flow_steer = edma_rx_flow_steer, ++ .ndo_register_rfs_filter = edma_register_rfs_filter, ++ .ndo_get_default_vlan_tag = edma_get_default_vlan_tag, ++#endif ++ .ndo_get_stats = edma_get_stats, ++}; ++ ++/* edma_axi_probe() ++ * Initialise an adapter identified by a platform_device structure. ++ * ++ * The OS initialization, configuring of the adapter private structure, ++ * and a hardware reset occur in the probe. ++ */ ++static int edma_axi_probe(struct platform_device *pdev) ++{ ++ struct edma_common_info *edma_cinfo; ++ struct edma_hw *hw; ++ struct edma_adapter *adapter[EDMA_MAX_PORTID_SUPPORTED]; ++ struct resource *res; ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *pnp; ++ struct device_node *mdio_node = NULL; ++ struct platform_device *mdio_plat = NULL; ++ struct mii_bus *miibus = NULL; ++ struct edma_mdio_data *mdio_data = NULL; ++ int i, j, k, err = 0; ++ int portid_bmp; ++ int idx = 0, idx_mac = 0; ++ ++ if (CONFIG_NR_CPUS != EDMA_CPU_CORES_SUPPORTED) { ++ dev_err(&pdev->dev, "Invalid CPU Cores\n"); ++ return -EINVAL; ++ } ++ ++ if ((num_rxq != 4) && (num_rxq != 8)) { ++ dev_err(&pdev->dev, "Invalid RX queue, edma probe failed\n"); ++ return -EINVAL; ++ } ++ edma_cinfo = kzalloc(sizeof(struct edma_common_info), GFP_KERNEL); ++ if (!edma_cinfo) { ++ err = -ENOMEM; ++ goto err_alloc; ++ } ++ ++ edma_cinfo->pdev = pdev; ++ ++ of_property_read_u32(np, "qcom,num_gmac", &edma_cinfo->num_gmac); ++ if (edma_cinfo->num_gmac > EDMA_MAX_PORTID_SUPPORTED) { ++ pr_err("Invalid DTSI Entry for qcom,num_gmac\n"); ++ err = -EINVAL; ++ goto err_cinfo; ++ } ++ ++ /* Initialize the netdev array before allocation ++ * to avoid double free ++ */ ++ for (i = 0 ; i < edma_cinfo->num_gmac ; i++) ++ edma_netdev[i] = NULL; ++ ++ for (i = 0 ; i < edma_cinfo->num_gmac ; i++) { ++ edma_netdev[i] = alloc_etherdev_mqs(sizeof(struct edma_adapter), ++ EDMA_NETDEV_TX_QUEUE, EDMA_NETDEV_RX_QUEUE); ++ ++ if (!edma_netdev[i]) { ++ dev_err(&pdev->dev, ++ "net device alloc fails for index=%d\n", i); ++ err = -ENODEV; ++ goto err_ioremap; ++ } ++ ++ SET_NETDEV_DEV(edma_netdev[i], &pdev->dev); ++ platform_set_drvdata(pdev, edma_netdev[i]); ++ edma_cinfo->netdev[i] = edma_netdev[i]; ++ } ++ ++ /* Fill ring details */ ++ edma_cinfo->num_tx_queues = EDMA_MAX_TRANSMIT_QUEUE; ++ edma_cinfo->num_txq_per_core = (EDMA_MAX_TRANSMIT_QUEUE / 4); ++ edma_cinfo->tx_ring_count = EDMA_TX_RING_SIZE; ++ ++ /* Update num rx queues based on module parameter */ ++ edma_cinfo->num_rx_queues = num_rxq; ++ edma_cinfo->num_rxq_per_core = ((num_rxq == 4) ? 1 : 2); ++ ++ edma_cinfo->rx_ring_count = EDMA_RX_RING_SIZE; ++ ++ hw = &edma_cinfo->hw; ++ ++ /* Fill HW defaults */ ++ hw->tx_intr_mask = EDMA_TX_IMR_NORMAL_MASK; ++ hw->rx_intr_mask = EDMA_RX_IMR_NORMAL_MASK; ++ ++ of_property_read_u32(np, "qcom,page-mode", &edma_cinfo->page_mode); ++ of_property_read_u32(np, "qcom,rx_head_buf_size", ++ &hw->rx_head_buff_size); ++ ++ if (overwrite_mode) { ++ dev_info(&pdev->dev, "page mode overwritten"); ++ edma_cinfo->page_mode = page_mode; ++ } ++ ++ if (jumbo_mru) ++ edma_cinfo->fraglist_mode = 1; ++ ++ if (edma_cinfo->page_mode) ++ hw->rx_head_buff_size = EDMA_RX_HEAD_BUFF_SIZE_JUMBO; ++ else if (edma_cinfo->fraglist_mode) ++ hw->rx_head_buff_size = jumbo_mru; ++ else if (!hw->rx_head_buff_size) ++ hw->rx_head_buff_size = EDMA_RX_HEAD_BUFF_SIZE; ++ ++ hw->misc_intr_mask = 0; ++ hw->wol_intr_mask = 0; ++ ++ hw->intr_clear_type = EDMA_INTR_CLEAR_TYPE; ++ hw->intr_sw_idx_w = EDMA_INTR_SW_IDX_W_TYPE; ++ ++ /* configure RSS type to the different protocol that can be ++ * supported ++ */ ++ hw->rss_type = EDMA_RSS_TYPE_IPV4TCP | EDMA_RSS_TYPE_IPV6_TCP | ++ EDMA_RSS_TYPE_IPV4_UDP | EDMA_RSS_TYPE_IPV6UDP | ++ EDMA_RSS_TYPE_IPV4 | EDMA_RSS_TYPE_IPV6; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ edma_cinfo->hw.hw_addr = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(edma_cinfo->hw.hw_addr)) { ++ err = PTR_ERR(edma_cinfo->hw.hw_addr); ++ goto err_ioremap; ++ } ++ ++ edma_hw_addr = (u32)edma_cinfo->hw.hw_addr; ++ ++ /* Parse tx queue interrupt number from device tree */ ++ for (i = 0; i < edma_cinfo->num_tx_queues; i++) ++ edma_cinfo->tx_irq[i] = platform_get_irq(pdev, i); ++ ++ /* Parse rx queue interrupt number from device tree ++ * Here we are setting j to point to the point where we ++ * left tx interrupt parsing(i.e 16) and run run the loop ++ * from 0 to 7 to parse rx interrupt number. ++ */ ++ for (i = 0, j = edma_cinfo->num_tx_queues, k = 0; ++ i < edma_cinfo->num_rx_queues; i++) { ++ edma_cinfo->rx_irq[k] = platform_get_irq(pdev, j); ++ k += ((num_rxq == 4) ? 2 : 1); ++ j += ((num_rxq == 4) ? 2 : 1); ++ } ++ ++ edma_cinfo->rx_head_buffer_len = edma_cinfo->hw.rx_head_buff_size; ++ edma_cinfo->rx_page_buffer_len = PAGE_SIZE; ++ ++ err = edma_alloc_queues_tx(edma_cinfo); ++ if (err) { ++ dev_err(&pdev->dev, "Allocation of TX queue failed\n"); ++ goto err_tx_qinit; ++ } ++ ++ err = edma_alloc_queues_rx(edma_cinfo); ++ if (err) { ++ dev_err(&pdev->dev, "Allocation of RX queue failed\n"); ++ goto err_rx_qinit; ++ } ++ ++ err = edma_alloc_tx_rings(edma_cinfo); ++ if (err) { ++ dev_err(&pdev->dev, "Allocation of TX resources failed\n"); ++ goto err_tx_rinit; ++ } ++ ++ err = edma_alloc_rx_rings(edma_cinfo); ++ if (err) { ++ dev_err(&pdev->dev, "Allocation of RX resources failed\n"); ++ goto err_rx_rinit; ++ } ++ ++ /* Initialize netdev and netdev bitmap for transmit descriptor rings */ ++ for (i = 0; i < edma_cinfo->num_tx_queues; i++) { ++ struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[i]; ++ int j; ++ ++ etdr->netdev_bmp = 0; ++ for (j = 0; j < EDMA_MAX_NETDEV_PER_QUEUE; j++) { ++ etdr->netdev[j] = NULL; ++ etdr->nq[j] = NULL; ++ } ++ } ++ ++ if (of_property_read_bool(np, "qcom,mdio_supported")) { ++ mdio_node = of_find_compatible_node(NULL, NULL, ++ "qcom,ipq4019-mdio"); ++ if (!mdio_node) { ++ dev_err(&pdev->dev, "cannot find mdio node by phandle"); ++ err = -EIO; ++ goto err_mdiobus_init_fail; ++ } ++ ++ mdio_plat = of_find_device_by_node(mdio_node); ++ if (!mdio_plat) { ++ dev_err(&pdev->dev, ++ "cannot find platform device from mdio node"); ++ of_node_put(mdio_node); ++ err = -EIO; ++ goto err_mdiobus_init_fail; ++ } ++ ++ mdio_data = dev_get_drvdata(&mdio_plat->dev); ++ if (!mdio_data) { ++ dev_err(&pdev->dev, ++ "cannot get mii bus reference from device data"); ++ of_node_put(mdio_node); ++ err = -EIO; ++ goto err_mdiobus_init_fail; ++ } ++ ++ miibus = mdio_data->mii_bus; ++ } ++ ++ for_each_available_child_of_node(np, pnp) { ++ const char *mac_addr; ++ ++ /* this check is needed if parent and daughter dts have ++ * different number of gmac nodes ++ */ ++ if (idx_mac == edma_cinfo->num_gmac) { ++ of_node_put(np); ++ break; ++ } ++ ++ mac_addr = of_get_mac_address(pnp); ++ if (mac_addr) ++ memcpy(edma_netdev[idx_mac]->dev_addr, mac_addr, ETH_ALEN); ++ ++ idx_mac++; ++ } ++ ++ /* Populate the adapter structure register the netdevice */ ++ for (i = 0; i < edma_cinfo->num_gmac; i++) { ++ int k, m; ++ ++ adapter[i] = netdev_priv(edma_netdev[i]); ++ adapter[i]->netdev = edma_netdev[i]; ++ adapter[i]->pdev = pdev; ++ for (j = 0; j < CONFIG_NR_CPUS; j++) { ++ m = i % 2; ++ adapter[i]->tx_start_offset[j] = ++ ((j << EDMA_TX_CPU_START_SHIFT) + (m << 1)); ++ /* Share the queues with available net-devices. ++ * For instance , with 5 net-devices ++ * eth0/eth2/eth4 will share q0,q1,q4,q5,q8,q9,q12,q13 ++ * and eth1/eth3 will get the remaining. ++ */ ++ for (k = adapter[i]->tx_start_offset[j]; k < ++ (adapter[i]->tx_start_offset[j] + 2); k++) { ++ if (edma_fill_netdev(edma_cinfo, k, i, j)) { ++ pr_err("Netdev overflow Error\n"); ++ goto err_register; ++ } ++ } ++ } ++ ++ adapter[i]->edma_cinfo = edma_cinfo; ++ edma_netdev[i]->netdev_ops = &edma_axi_netdev_ops; ++ edma_netdev[i]->max_mtu = 9000; ++ edma_netdev[i]->features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM ++ | NETIF_F_HW_VLAN_CTAG_TX ++ | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_SG | ++ NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GRO; ++ edma_netdev[i]->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | ++ NETIF_F_HW_VLAN_CTAG_RX ++ | NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | ++ NETIF_F_GRO; ++ edma_netdev[i]->vlan_features = NETIF_F_HW_CSUM | NETIF_F_SG | ++ NETIF_F_TSO | NETIF_F_TSO6 | ++ NETIF_F_GRO; ++ edma_netdev[i]->wanted_features = NETIF_F_HW_CSUM | NETIF_F_SG | ++ NETIF_F_TSO | NETIF_F_TSO6 | ++ NETIF_F_GRO; ++ ++#ifdef CONFIG_RFS_ACCEL ++ edma_netdev[i]->features |= NETIF_F_RXHASH | NETIF_F_NTUPLE; ++ edma_netdev[i]->hw_features |= NETIF_F_RXHASH | NETIF_F_NTUPLE; ++ edma_netdev[i]->vlan_features |= NETIF_F_RXHASH | NETIF_F_NTUPLE; ++ edma_netdev[i]->wanted_features |= NETIF_F_RXHASH | NETIF_F_NTUPLE; ++#endif ++ edma_set_ethtool_ops(edma_netdev[i]); ++ ++ /* This just fill in some default MAC address ++ */ ++ if (!is_valid_ether_addr(edma_netdev[i]->dev_addr)) { ++ random_ether_addr(edma_netdev[i]->dev_addr); ++ pr_info("EDMA using MAC@ - using"); ++ pr_info("%02x:%02x:%02x:%02x:%02x:%02x\n", ++ *(edma_netdev[i]->dev_addr), ++ *(edma_netdev[i]->dev_addr + 1), ++ *(edma_netdev[i]->dev_addr + 2), ++ *(edma_netdev[i]->dev_addr + 3), ++ *(edma_netdev[i]->dev_addr + 4), ++ *(edma_netdev[i]->dev_addr + 5)); ++ } ++ ++ err = register_netdev(edma_netdev[i]); ++ if (err) ++ goto err_register; ++ ++ /* carrier off reporting is important to ++ * ethtool even BEFORE open ++ */ ++ netif_carrier_off(edma_netdev[i]); ++ ++ /* Allocate reverse irq cpu mapping structure for ++ * receive queues ++ */ ++#ifdef CONFIG_RFS_ACCEL ++ edma_netdev[i]->rx_cpu_rmap = ++ alloc_irq_cpu_rmap(EDMA_NETDEV_RX_QUEUE); ++ if (!edma_netdev[i]->rx_cpu_rmap) { ++ err = -ENOMEM; ++ goto err_rmap_alloc_fail; ++ } ++#endif ++ } ++ ++ for (i = 0; i < EDMA_MAX_PORTID_BITMAP_INDEX; i++) ++ edma_cinfo->portid_netdev_lookup_tbl[i] = NULL; ++ ++ for_each_available_child_of_node(np, pnp) { ++ const uint32_t *vlan_tag = NULL; ++ int len; ++ ++ /* this check is needed if parent and daughter dts have ++ * different number of gmac nodes ++ */ ++ if (idx == edma_cinfo->num_gmac) ++ break; ++ ++ /* Populate port-id to netdev lookup table */ ++ vlan_tag = of_get_property(pnp, "vlan_tag", &len); ++ if (!vlan_tag) { ++ pr_err("Vlan tag parsing Failed.\n"); ++ goto err_rmap_alloc_fail; ++ } ++ ++ adapter[idx]->default_vlan_tag = of_read_number(vlan_tag, 1); ++ vlan_tag++; ++ portid_bmp = of_read_number(vlan_tag, 1); ++ adapter[idx]->dp_bitmap = portid_bmp; ++ ++ portid_bmp = portid_bmp >> 1; /* We ignore CPU Port bit 0 */ ++ while (portid_bmp) { ++ int port_bit = ffs(portid_bmp); ++ ++ if (port_bit > EDMA_MAX_PORTID_SUPPORTED) ++ goto err_rmap_alloc_fail; ++ edma_cinfo->portid_netdev_lookup_tbl[port_bit] = ++ edma_netdev[idx]; ++ portid_bmp &= ~(1 << (port_bit - 1)); ++ } ++ ++ if (!of_property_read_u32(pnp, "qcom,poll_required", ++ &adapter[idx]->poll_required)) { ++ if (adapter[idx]->poll_required) { ++ of_property_read_u32(pnp, "qcom,phy_mdio_addr", ++ &adapter[idx]->phy_mdio_addr); ++ of_property_read_u32(pnp, "qcom,forced_speed", ++ &adapter[idx]->forced_speed); ++ of_property_read_u32(pnp, "qcom,forced_duplex", ++ &adapter[idx]->forced_duplex); ++ ++ /* create a phyid using MDIO bus id ++ * and MDIO bus address ++ */ ++ snprintf(adapter[idx]->phy_id, ++ MII_BUS_ID_SIZE + 3, PHY_ID_FMT, ++ miibus->id, ++ adapter[idx]->phy_mdio_addr); ++ } ++ } else { ++ adapter[idx]->poll_required = 0; ++ adapter[idx]->forced_speed = SPEED_1000; ++ adapter[idx]->forced_duplex = DUPLEX_FULL; ++ } ++ ++ idx++; ++ } ++ ++ edma_cinfo->edma_ctl_table_hdr = register_net_sysctl(&init_net, ++ "net/edma", ++ edma_table); ++ if (!edma_cinfo->edma_ctl_table_hdr) { ++ dev_err(&pdev->dev, "edma sysctl table hdr not registered\n"); ++ goto err_unregister_sysctl_tbl; ++ } ++ ++ /* Disable all 16 Tx and 8 rx irqs */ ++ edma_irq_disable(edma_cinfo); ++ ++ err = edma_reset(edma_cinfo); ++ if (err) { ++ err = -EIO; ++ goto err_reset; ++ } ++ ++ /* populate per_core_info, do a napi_Add, request 16 TX irqs, ++ * 8 RX irqs, do a napi enable ++ */ ++ for (i = 0; i < CONFIG_NR_CPUS; i++) { ++ u8 rx_start; ++ ++ edma_cinfo->edma_percpu_info[i].napi.state = 0; ++ ++ netif_napi_add(edma_netdev[0], ++ &edma_cinfo->edma_percpu_info[i].napi, ++ edma_poll, 64); ++ napi_enable(&edma_cinfo->edma_percpu_info[i].napi); ++ edma_cinfo->edma_percpu_info[i].tx_mask = tx_mask[i]; ++ edma_cinfo->edma_percpu_info[i].rx_mask = EDMA_RX_PER_CPU_MASK ++ << (i << EDMA_RX_PER_CPU_MASK_SHIFT); ++ edma_cinfo->edma_percpu_info[i].tx_start = tx_start[i]; ++ edma_cinfo->edma_percpu_info[i].rx_start = ++ i << EDMA_RX_CPU_START_SHIFT; ++ rx_start = i << EDMA_RX_CPU_START_SHIFT; ++ edma_cinfo->edma_percpu_info[i].tx_status = 0; ++ edma_cinfo->edma_percpu_info[i].rx_status = 0; ++ edma_cinfo->edma_percpu_info[i].edma_cinfo = edma_cinfo; ++ ++ /* Request irq per core */ ++ for (j = edma_cinfo->edma_percpu_info[i].tx_start; ++ j < tx_start[i] + 4; j++) { ++ sprintf(&edma_tx_irq[j][0], "edma_eth_tx%d", j); ++ err = request_irq(edma_cinfo->tx_irq[j], ++ edma_interrupt, ++ 0, ++ &edma_tx_irq[j][0], ++ &edma_cinfo->edma_percpu_info[i]); ++ if (err) ++ goto err_reset; ++ } ++ ++ for (j = edma_cinfo->edma_percpu_info[i].rx_start; ++ j < (rx_start + ++ ((edma_cinfo->num_rx_queues == 4) ? 1 : 2)); ++ j++) { ++ sprintf(&edma_rx_irq[j][0], "edma_eth_rx%d", j); ++ err = request_irq(edma_cinfo->rx_irq[j], ++ edma_interrupt, ++ 0, ++ &edma_rx_irq[j][0], ++ &edma_cinfo->edma_percpu_info[i]); ++ if (err) ++ goto err_reset; ++ } ++ ++#ifdef CONFIG_RFS_ACCEL ++ for (j = edma_cinfo->edma_percpu_info[i].rx_start; ++ j < rx_start + 2; j += 2) { ++ err = irq_cpu_rmap_add(edma_netdev[0]->rx_cpu_rmap, ++ edma_cinfo->rx_irq[j]); ++ if (err) ++ goto err_rmap_add_fail; ++ } ++#endif ++ } ++ ++ /* Used to clear interrupt status, allocate rx buffer, ++ * configure edma descriptors registers ++ */ ++ err = edma_configure(edma_cinfo); ++ if (err) { ++ err = -EIO; ++ goto err_configure; ++ } ++ ++ /* Configure RSS indirection table. ++ * 128 hash will be configured in the following ++ * pattern: hash{0,1,2,3} = {Q0,Q2,Q4,Q6} respectively ++ * and so on ++ */ ++ for (i = 0; i < EDMA_NUM_IDT; i++) ++ edma_write_reg(EDMA_REG_RSS_IDT(i), EDMA_RSS_IDT_VALUE); ++ ++ /* Configure load balance mapping table. ++ * 4 table entry will be configured according to the ++ * following pattern: load_balance{0,1,2,3} = {Q0,Q1,Q3,Q4} ++ * respectively. ++ */ ++ edma_write_reg(EDMA_REG_LB_RING, EDMA_LB_REG_VALUE); ++ ++ /* Configure Virtual queue for Tx rings ++ * User can also change this value runtime through ++ * a sysctl ++ */ ++ edma_write_reg(EDMA_REG_VQ_CTRL0, EDMA_VQ_REG_VALUE); ++ edma_write_reg(EDMA_REG_VQ_CTRL1, EDMA_VQ_REG_VALUE); ++ ++ /* Configure Max AXI Burst write size to 128 bytes*/ ++ edma_write_reg(EDMA_REG_AXIW_CTRL_MAXWRSIZE, ++ EDMA_AXIW_MAXWRSIZE_VALUE); ++ ++ /* Enable All 16 tx and 8 rx irq mask */ ++ edma_irq_enable(edma_cinfo); ++ edma_enable_tx_ctrl(&edma_cinfo->hw); ++ edma_enable_rx_ctrl(&edma_cinfo->hw); ++ ++ for (i = 0; i < edma_cinfo->num_gmac; i++) { ++ if (adapter[i]->poll_required) { ++ adapter[i]->phydev = ++ phy_connect(edma_netdev[i], ++ (const char *)adapter[i]->phy_id, ++ &edma_adjust_link, ++ PHY_INTERFACE_MODE_SGMII); ++ if (IS_ERR(adapter[i]->phydev)) { ++ dev_dbg(&pdev->dev, "PHY attach FAIL"); ++ err = -EIO; ++ goto edma_phy_attach_fail; ++ } else { ++ adapter[i]->phydev->advertising |= ++ ADVERTISED_Pause | ++ ADVERTISED_Asym_Pause; ++ adapter[i]->phydev->supported |= ++ SUPPORTED_Pause | ++ SUPPORTED_Asym_Pause; ++ } ++ } else { ++ adapter[i]->phydev = NULL; ++ } ++ } ++ ++ spin_lock_init(&edma_cinfo->stats_lock); ++ ++ timer_setup(&edma_cinfo->edma_stats_timer, edma_statistics_timer, 0); ++ mod_timer(&edma_cinfo->edma_stats_timer, jiffies + 1*HZ); ++ ++ return 0; ++ ++edma_phy_attach_fail: ++ miibus = NULL; ++err_configure: ++#ifdef CONFIG_RFS_ACCEL ++ for (i = 0; i < edma_cinfo->num_gmac; i++) { ++ free_irq_cpu_rmap(adapter[i]->netdev->rx_cpu_rmap); ++ adapter[i]->netdev->rx_cpu_rmap = NULL; ++ } ++#endif ++err_rmap_add_fail: ++ edma_free_irqs(adapter[0]); ++ for (i = 0; i < CONFIG_NR_CPUS; i++) ++ napi_disable(&edma_cinfo->edma_percpu_info[i].napi); ++err_reset: ++err_unregister_sysctl_tbl: ++err_rmap_alloc_fail: ++ for (i = 0; i < edma_cinfo->num_gmac; i++) ++ unregister_netdev(edma_netdev[i]); ++err_register: ++err_mdiobus_init_fail: ++ edma_free_rx_rings(edma_cinfo); ++err_rx_rinit: ++ edma_free_tx_rings(edma_cinfo); ++err_tx_rinit: ++ edma_free_queues(edma_cinfo); ++err_rx_qinit: ++err_tx_qinit: ++ iounmap(edma_cinfo->hw.hw_addr); ++err_ioremap: ++ for (i = 0; i < edma_cinfo->num_gmac; i++) { ++ if (edma_netdev[i]) ++ free_netdev(edma_netdev[i]); ++ } ++err_cinfo: ++ kfree(edma_cinfo); ++err_alloc: ++ return err; ++} ++ ++/* edma_axi_remove() ++ * Device Removal Routine ++ * ++ * edma_axi_remove is called by the platform subsystem to alert the driver ++ * that it should release a platform device. ++ */ ++static int edma_axi_remove(struct platform_device *pdev) ++{ ++ struct edma_adapter *adapter = netdev_priv(edma_netdev[0]); ++ struct edma_common_info *edma_cinfo = adapter->edma_cinfo; ++ struct edma_hw *hw = &edma_cinfo->hw; ++ int i; ++ ++ for (i = 0; i < edma_cinfo->num_gmac; i++) ++ unregister_netdev(edma_netdev[i]); ++ ++ edma_stop_rx_tx(hw); ++ for (i = 0; i < CONFIG_NR_CPUS; i++) ++ napi_disable(&edma_cinfo->edma_percpu_info[i].napi); ++ ++ edma_irq_disable(edma_cinfo); ++ edma_write_reg(EDMA_REG_RX_ISR, 0xff); ++ edma_write_reg(EDMA_REG_TX_ISR, 0xffff); ++#ifdef CONFIG_RFS_ACCEL ++ for (i = 0; i < edma_cinfo->num_gmac; i++) { ++ free_irq_cpu_rmap(edma_netdev[i]->rx_cpu_rmap); ++ edma_netdev[i]->rx_cpu_rmap = NULL; ++ } ++#endif ++ ++ for (i = 0; i < edma_cinfo->num_gmac; i++) { ++ struct edma_adapter *adapter = netdev_priv(edma_netdev[i]); ++ ++ if (adapter->phydev) ++ phy_disconnect(adapter->phydev); ++ } ++ ++ del_timer_sync(&edma_cinfo->edma_stats_timer); ++ edma_free_irqs(adapter); ++ unregister_net_sysctl_table(edma_cinfo->edma_ctl_table_hdr); ++ edma_free_tx_resources(edma_cinfo); ++ edma_free_rx_resources(edma_cinfo); ++ edma_free_tx_rings(edma_cinfo); ++ edma_free_rx_rings(edma_cinfo); ++ edma_free_queues(edma_cinfo); ++ for (i = 0; i < edma_cinfo->num_gmac; i++) ++ free_netdev(edma_netdev[i]); ++ ++ kfree(edma_cinfo); ++ ++ return 0; ++} ++ ++static const struct of_device_id edma_of_mtable[] = { ++ {.compatible = "qcom,ess-edma" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, edma_of_mtable); ++ ++static struct platform_driver edma_axi_driver = { ++ .driver = { ++ .name = edma_axi_driver_name, ++ .of_match_table = edma_of_mtable, ++ }, ++ .probe = edma_axi_probe, ++ .remove = edma_axi_remove, ++}; ++ ++module_platform_driver(edma_axi_driver); ++ ++MODULE_AUTHOR("Qualcomm Atheros Inc"); ++MODULE_DESCRIPTION("QCA ESS EDMA driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/net/ethernet/qualcomm/essedma/edma_ethtool.c +@@ -0,0 +1,374 @@ ++/* ++ * Copyright (c) 2015 - 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 ++#include ++#include ++#include "edma.h" ++ ++struct edma_ethtool_stats { ++ uint8_t stat_string[ETH_GSTRING_LEN]; ++ uint32_t stat_offset; ++}; ++ ++#define EDMA_STAT(m) offsetof(struct edma_ethtool_statistics, m) ++#define DRVINFO_LEN 32 ++ ++/* Array of strings describing statistics ++ */ ++static const struct edma_ethtool_stats edma_gstrings_stats[] = { ++ {"tx_q0_pkt", EDMA_STAT(tx_q0_pkt)}, ++ {"tx_q1_pkt", EDMA_STAT(tx_q1_pkt)}, ++ {"tx_q2_pkt", EDMA_STAT(tx_q2_pkt)}, ++ {"tx_q3_pkt", EDMA_STAT(tx_q3_pkt)}, ++ {"tx_q4_pkt", EDMA_STAT(tx_q4_pkt)}, ++ {"tx_q5_pkt", EDMA_STAT(tx_q5_pkt)}, ++ {"tx_q6_pkt", EDMA_STAT(tx_q6_pkt)}, ++ {"tx_q7_pkt", EDMA_STAT(tx_q7_pkt)}, ++ {"tx_q8_pkt", EDMA_STAT(tx_q8_pkt)}, ++ {"tx_q9_pkt", EDMA_STAT(tx_q9_pkt)}, ++ {"tx_q10_pkt", EDMA_STAT(tx_q10_pkt)}, ++ {"tx_q11_pkt", EDMA_STAT(tx_q11_pkt)}, ++ {"tx_q12_pkt", EDMA_STAT(tx_q12_pkt)}, ++ {"tx_q13_pkt", EDMA_STAT(tx_q13_pkt)}, ++ {"tx_q14_pkt", EDMA_STAT(tx_q14_pkt)}, ++ {"tx_q15_pkt", EDMA_STAT(tx_q15_pkt)}, ++ {"tx_q0_byte", EDMA_STAT(tx_q0_byte)}, ++ {"tx_q1_byte", EDMA_STAT(tx_q1_byte)}, ++ {"tx_q2_byte", EDMA_STAT(tx_q2_byte)}, ++ {"tx_q3_byte", EDMA_STAT(tx_q3_byte)}, ++ {"tx_q4_byte", EDMA_STAT(tx_q4_byte)}, ++ {"tx_q5_byte", EDMA_STAT(tx_q5_byte)}, ++ {"tx_q6_byte", EDMA_STAT(tx_q6_byte)}, ++ {"tx_q7_byte", EDMA_STAT(tx_q7_byte)}, ++ {"tx_q8_byte", EDMA_STAT(tx_q8_byte)}, ++ {"tx_q9_byte", EDMA_STAT(tx_q9_byte)}, ++ {"tx_q10_byte", EDMA_STAT(tx_q10_byte)}, ++ {"tx_q11_byte", EDMA_STAT(tx_q11_byte)}, ++ {"tx_q12_byte", EDMA_STAT(tx_q12_byte)}, ++ {"tx_q13_byte", EDMA_STAT(tx_q13_byte)}, ++ {"tx_q14_byte", EDMA_STAT(tx_q14_byte)}, ++ {"tx_q15_byte", EDMA_STAT(tx_q15_byte)}, ++ {"rx_q0_pkt", EDMA_STAT(rx_q0_pkt)}, ++ {"rx_q1_pkt", EDMA_STAT(rx_q1_pkt)}, ++ {"rx_q2_pkt", EDMA_STAT(rx_q2_pkt)}, ++ {"rx_q3_pkt", EDMA_STAT(rx_q3_pkt)}, ++ {"rx_q4_pkt", EDMA_STAT(rx_q4_pkt)}, ++ {"rx_q5_pkt", EDMA_STAT(rx_q5_pkt)}, ++ {"rx_q6_pkt", EDMA_STAT(rx_q6_pkt)}, ++ {"rx_q7_pkt", EDMA_STAT(rx_q7_pkt)}, ++ {"rx_q0_byte", EDMA_STAT(rx_q0_byte)}, ++ {"rx_q1_byte", EDMA_STAT(rx_q1_byte)}, ++ {"rx_q2_byte", EDMA_STAT(rx_q2_byte)}, ++ {"rx_q3_byte", EDMA_STAT(rx_q3_byte)}, ++ {"rx_q4_byte", EDMA_STAT(rx_q4_byte)}, ++ {"rx_q5_byte", EDMA_STAT(rx_q5_byte)}, ++ {"rx_q6_byte", EDMA_STAT(rx_q6_byte)}, ++ {"rx_q7_byte", EDMA_STAT(rx_q7_byte)}, ++ {"tx_desc_error", EDMA_STAT(tx_desc_error)}, ++}; ++ ++#define EDMA_STATS_LEN ARRAY_SIZE(edma_gstrings_stats) ++ ++/* edma_get_strset_count() ++ * Get strset count ++ */ ++static int edma_get_strset_count(struct net_device *netdev, ++ int sset) ++{ ++ switch (sset) { ++ case ETH_SS_STATS: ++ return EDMA_STATS_LEN; ++ default: ++ netdev_dbg(netdev, "%s: Invalid string set", __func__); ++ return -EOPNOTSUPP; ++ } ++} ++ ++ ++/* edma_get_strings() ++ * get stats string ++ */ ++static void edma_get_strings(struct net_device *netdev, uint32_t stringset, ++ uint8_t *data) ++{ ++ uint8_t *p = data; ++ uint32_t i; ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < EDMA_STATS_LEN; i++) { ++ memcpy(p, edma_gstrings_stats[i].stat_string, ++ min((size_t)ETH_GSTRING_LEN, ++ strlen(edma_gstrings_stats[i].stat_string) ++ + 1)); ++ p += ETH_GSTRING_LEN; ++ } ++ break; ++ } ++} ++ ++/* edma_get_ethtool_stats() ++ * Get ethtool statistics ++ */ ++static void edma_get_ethtool_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, uint64_t *data) ++{ ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ struct edma_common_info *edma_cinfo = adapter->edma_cinfo; ++ int i; ++ uint8_t *p = NULL; ++ ++ edma_read_append_stats(edma_cinfo); ++ ++ for(i = 0; i < EDMA_STATS_LEN; i++) { ++ p = (uint8_t *)&(edma_cinfo->edma_ethstats) + ++ edma_gstrings_stats[i].stat_offset; ++ data[i] = *(uint32_t *)p; ++ } ++} ++ ++/* edma_get_drvinfo() ++ * get edma driver info ++ */ ++static void edma_get_drvinfo(struct net_device *dev, ++ struct ethtool_drvinfo *info) ++{ ++ strlcpy(info->driver, "ess_edma", DRVINFO_LEN); ++ strlcpy(info->bus_info, "axi", ETHTOOL_BUSINFO_LEN); ++} ++ ++/* edma_nway_reset() ++ * Reset the phy, if available. ++ */ ++static int edma_nway_reset(struct net_device *netdev) ++{ ++ return -EINVAL; ++} ++ ++/* edma_get_wol() ++ * get wake on lan info ++ */ ++static void edma_get_wol(struct net_device *netdev, ++ struct ethtool_wolinfo *wol) ++{ ++ wol->supported = 0; ++ wol->wolopts = 0; ++} ++ ++/* edma_get_msglevel() ++ * get message level. ++ */ ++static uint32_t edma_get_msglevel(struct net_device *netdev) ++{ ++ return 0; ++} ++ ++/* edma_get_settings() ++ * Get edma settings ++ */ ++static int edma_get_settings(struct net_device *netdev, ++ struct ethtool_cmd *ecmd) ++{ ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ ++ if (adapter->poll_required) { ++ struct phy_device *phydev = NULL; ++ uint16_t phyreg; ++ ++ if ((adapter->forced_speed != SPEED_UNKNOWN) ++ && !(adapter->poll_required)) ++ return -EPERM; ++ ++ phydev = adapter->phydev; ++ ++ ecmd->advertising = phydev->advertising; ++ ecmd->autoneg = phydev->autoneg; ++ ++ if (adapter->link_state == __EDMA_LINKDOWN) { ++ ecmd->speed = SPEED_UNKNOWN; ++ ecmd->duplex = DUPLEX_UNKNOWN; ++ } else { ++ ecmd->speed = phydev->speed; ++ ecmd->duplex = phydev->duplex; ++ } ++ ++ ecmd->phy_address = adapter->phy_mdio_addr; ++ ++ phyreg = (uint16_t)phy_read(adapter->phydev, MII_LPA); ++ if (phyreg & LPA_10HALF) ++ ecmd->lp_advertising |= ADVERTISED_10baseT_Half; ++ ++ if (phyreg & LPA_10FULL) ++ ecmd->lp_advertising |= ADVERTISED_10baseT_Full; ++ ++ if (phyreg & LPA_100HALF) ++ ecmd->lp_advertising |= ADVERTISED_100baseT_Half; ++ ++ if (phyreg & LPA_100FULL) ++ ecmd->lp_advertising |= ADVERTISED_100baseT_Full; ++ ++ phyreg = (uint16_t)phy_read(adapter->phydev, MII_STAT1000); ++ if (phyreg & LPA_1000HALF) ++ ecmd->lp_advertising |= ADVERTISED_1000baseT_Half; ++ ++ if (phyreg & LPA_1000FULL) ++ ecmd->lp_advertising |= ADVERTISED_1000baseT_Full; ++ } else { ++ /* If the speed/duplex for this GMAC is forced and we ++ * are not polling for link state changes, return the ++ * values as specified by platform. This will be true ++ * for GMACs connected to switch, and interfaces that ++ * do not use a PHY. ++ */ ++ if (!(adapter->poll_required)) { ++ if (adapter->forced_speed != SPEED_UNKNOWN) { ++ /* set speed and duplex */ ++ ethtool_cmd_speed_set(ecmd, SPEED_1000); ++ ecmd->duplex = DUPLEX_FULL; ++ ++ /* Populate capabilities advertised by self */ ++ ecmd->advertising = 0; ++ ecmd->autoneg = 0; ++ ecmd->port = PORT_TP; ++ ecmd->transceiver = XCVR_EXTERNAL; ++ } else { ++ /* non link polled and non ++ * forced speed/duplex interface ++ */ ++ return -EIO; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* edma_set_settings() ++ * Set EDMA settings ++ */ ++static int edma_set_settings(struct net_device *netdev, ++ struct ethtool_cmd *ecmd) ++{ ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ struct phy_device *phydev = NULL; ++ ++ if ((adapter->forced_speed != SPEED_UNKNOWN) && ++ !adapter->poll_required) ++ return -EPERM; ++ ++ phydev = adapter->phydev; ++ phydev->advertising = ecmd->advertising; ++ phydev->autoneg = ecmd->autoneg; ++ phydev->speed = ethtool_cmd_speed(ecmd); ++ phydev->duplex = ecmd->duplex; ++ ++ genphy_config_aneg(phydev); ++ ++ return 0; ++} ++ ++/* edma_get_coalesce ++ * get interrupt mitigation ++ */ ++static int edma_get_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) ++{ ++ u32 reg_val; ++ ++ edma_get_tx_rx_coalesce(®_val); ++ ++ /* We read the Interrupt Moderation Timer(IMT) register value, ++ * use lower 16 bit for rx and higher 16 bit for Tx. We do a ++ * left shift by 1, because IMT resolution timer is 2usecs. ++ * Hence the value given by the register is multiplied by 2 to ++ * get the actual time in usecs. ++ */ ++ ec->tx_coalesce_usecs = (((reg_val >> 16) & 0xffff) << 1); ++ ec->rx_coalesce_usecs = ((reg_val & 0xffff) << 1); ++ ++ return 0; ++} ++ ++/* edma_set_coalesce ++ * set interrupt mitigation ++ */ ++static int edma_set_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) ++{ ++ if (ec->tx_coalesce_usecs) ++ edma_change_tx_coalesce(ec->tx_coalesce_usecs); ++ if (ec->rx_coalesce_usecs) ++ edma_change_rx_coalesce(ec->rx_coalesce_usecs); ++ ++ return 0; ++} ++ ++/* edma_set_priv_flags() ++ * Set EDMA private flags ++ */ ++static int edma_set_priv_flags(struct net_device *netdev, u32 flags) ++{ ++ return 0; ++} ++ ++/* edma_get_priv_flags() ++ * get edma driver flags ++ */ ++static u32 edma_get_priv_flags(struct net_device *netdev) ++{ ++ return 0; ++} ++ ++/* edma_get_ringparam() ++ * get ring size ++ */ ++static void edma_get_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *ring) ++{ ++ struct edma_adapter *adapter = netdev_priv(netdev); ++ struct edma_common_info *edma_cinfo = adapter->edma_cinfo; ++ ++ ring->tx_max_pending = edma_cinfo->tx_ring_count; ++ ring->rx_max_pending = edma_cinfo->rx_ring_count; ++} ++ ++/* Ethtool operations ++ */ ++static const struct ethtool_ops edma_ethtool_ops = { ++ .get_drvinfo = &edma_get_drvinfo, ++ .get_link = ðtool_op_get_link, ++ .get_msglevel = &edma_get_msglevel, ++ .nway_reset = &edma_nway_reset, ++ .get_wol = &edma_get_wol, ++ .get_settings = &edma_get_settings, ++ .set_settings = &edma_set_settings, ++ .get_strings = &edma_get_strings, ++ .get_sset_count = &edma_get_strset_count, ++ .get_ethtool_stats = &edma_get_ethtool_stats, ++ .get_coalesce = &edma_get_coalesce, ++ .set_coalesce = &edma_set_coalesce, ++ .get_priv_flags = edma_get_priv_flags, ++ .set_priv_flags = edma_set_priv_flags, ++ .get_ringparam = edma_get_ringparam, ++}; ++ ++/* edma_set_ethtool_ops ++ * Set ethtool operations ++ */ ++void edma_set_ethtool_ops(struct net_device *netdev) ++{ ++ netdev->ethtool_ops = &edma_ethtool_ops; ++} +--- /dev/null ++++ b/drivers/net/ethernet/qualcomm/essedma/ess_edma.h +@@ -0,0 +1,332 @@ ++/* ++ * Copyright (c) 2014 - 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 _ESS_EDMA_H_ ++#define _ESS_EDMA_H_ ++ ++#include ++ ++struct edma_adapter; ++struct edma_hw; ++ ++/* register definition */ ++#define EDMA_REG_MAS_CTRL 0x0 ++#define EDMA_REG_TIMEOUT_CTRL 0x004 ++#define EDMA_REG_DBG0 0x008 ++#define EDMA_REG_DBG1 0x00C ++#define EDMA_REG_SW_CTRL0 0x100 ++#define EDMA_REG_SW_CTRL1 0x104 ++ ++/* Interrupt Status Register */ ++#define EDMA_REG_RX_ISR 0x200 ++#define EDMA_REG_TX_ISR 0x208 ++#define EDMA_REG_MISC_ISR 0x210 ++#define EDMA_REG_WOL_ISR 0x218 ++ ++#define EDMA_MISC_ISR_RX_URG_Q(x) (1 << x) ++ ++#define EDMA_MISC_ISR_AXIR_TIMEOUT 0x00000100 ++#define EDMA_MISC_ISR_AXIR_ERR 0x00000200 ++#define EDMA_MISC_ISR_TXF_DEAD 0x00000400 ++#define EDMA_MISC_ISR_AXIW_ERR 0x00000800 ++#define EDMA_MISC_ISR_AXIW_TIMEOUT 0x00001000 ++ ++#define EDMA_WOL_ISR 0x00000001 ++ ++/* Interrupt Mask Register */ ++#define EDMA_REG_MISC_IMR 0x214 ++#define EDMA_REG_WOL_IMR 0x218 ++ ++#define EDMA_RX_IMR_NORMAL_MASK 0x1 ++#define EDMA_TX_IMR_NORMAL_MASK 0x1 ++#define EDMA_MISC_IMR_NORMAL_MASK 0x80001FFF ++#define EDMA_WOL_IMR_NORMAL_MASK 0x1 ++ ++/* Edma receive consumer index */ ++#define EDMA_REG_RX_SW_CONS_IDX_Q(x) (0x220 + ((x) << 2)) /* x is the queue id */ ++/* Edma transmit consumer index */ ++#define EDMA_REG_TX_SW_CONS_IDX_Q(x) (0x240 + ((x) << 2)) /* x is the queue id */ ++ ++/* IRQ Moderator Initial Timer Register */ ++#define EDMA_REG_IRQ_MODRT_TIMER_INIT 0x280 ++#define EDMA_IRQ_MODRT_TIMER_MASK 0xFFFF ++#define EDMA_IRQ_MODRT_RX_TIMER_SHIFT 0 ++#define EDMA_IRQ_MODRT_TX_TIMER_SHIFT 16 ++ ++/* Interrupt Control Register */ ++#define EDMA_REG_INTR_CTRL 0x284 ++#define EDMA_INTR_CLR_TYP_SHIFT 0 ++#define EDMA_INTR_SW_IDX_W_TYP_SHIFT 1 ++#define EDMA_INTR_CLEAR_TYPE_W1 0 ++#define EDMA_INTR_CLEAR_TYPE_R 1 ++ ++/* RX Interrupt Mask Register */ ++#define EDMA_REG_RX_INT_MASK_Q(x) (0x300 + ((x) << 2)) /* x = queue id */ ++ ++/* TX Interrupt mask register */ ++#define EDMA_REG_TX_INT_MASK_Q(x) (0x340 + ((x) << 2)) /* x = queue id */ ++ ++/* Load Ptr Register ++ * Software sets this bit after the initialization of the head and tail ++ */ ++#define EDMA_REG_TX_SRAM_PART 0x400 ++#define EDMA_LOAD_PTR_SHIFT 16 ++ ++/* TXQ Control Register */ ++#define EDMA_REG_TXQ_CTRL 0x404 ++#define EDMA_TXQ_CTRL_IP_OPTION_EN 0x10 ++#define EDMA_TXQ_CTRL_TXQ_EN 0x20 ++#define EDMA_TXQ_CTRL_ENH_MODE 0x40 ++#define EDMA_TXQ_CTRL_LS_8023_EN 0x80 ++#define EDMA_TXQ_CTRL_TPD_BURST_EN 0x100 ++#define EDMA_TXQ_CTRL_LSO_BREAK_EN 0x200 ++#define EDMA_TXQ_NUM_TPD_BURST_MASK 0xF ++#define EDMA_TXQ_TXF_BURST_NUM_MASK 0xFFFF ++#define EDMA_TXQ_NUM_TPD_BURST_SHIFT 0 ++#define EDMA_TXQ_TXF_BURST_NUM_SHIFT 16 ++ ++#define EDMA_REG_TXF_WATER_MARK 0x408 /* In 8-bytes */ ++#define EDMA_TXF_WATER_MARK_MASK 0x0FFF ++#define EDMA_TXF_LOW_WATER_MARK_SHIFT 0 ++#define EDMA_TXF_HIGH_WATER_MARK_SHIFT 16 ++#define EDMA_TXQ_CTRL_BURST_MODE_EN 0x80000000 ++ ++/* WRR Control Register */ ++#define EDMA_REG_WRR_CTRL_Q0_Q3 0x40c ++#define EDMA_REG_WRR_CTRL_Q4_Q7 0x410 ++#define EDMA_REG_WRR_CTRL_Q8_Q11 0x414 ++#define EDMA_REG_WRR_CTRL_Q12_Q15 0x418 ++ ++/* Weight round robin(WRR), it takes queue as input, and computes ++ * starting bits where we need to write the weight for a particular ++ * queue ++ */ ++#define EDMA_WRR_SHIFT(x) (((x) * 5) % 20) ++ ++/* Tx Descriptor Control Register */ ++#define EDMA_REG_TPD_RING_SIZE 0x41C ++#define EDMA_TPD_RING_SIZE_SHIFT 0 ++#define EDMA_TPD_RING_SIZE_MASK 0xFFFF ++ ++/* Transmit descriptor base address */ ++#define EDMA_REG_TPD_BASE_ADDR_Q(x) (0x420 + ((x) << 2)) /* x = queue id */ ++ ++/* TPD Index Register */ ++#define EDMA_REG_TPD_IDX_Q(x) (0x460 + ((x) << 2)) /* x = queue id */ ++ ++#define EDMA_TPD_PROD_IDX_BITS 0x0000FFFF ++#define EDMA_TPD_CONS_IDX_BITS 0xFFFF0000 ++#define EDMA_TPD_PROD_IDX_MASK 0xFFFF ++#define EDMA_TPD_CONS_IDX_MASK 0xFFFF ++#define EDMA_TPD_PROD_IDX_SHIFT 0 ++#define EDMA_TPD_CONS_IDX_SHIFT 16 ++ ++/* TX Virtual Queue Mapping Control Register */ ++#define EDMA_REG_VQ_CTRL0 0x4A0 ++#define EDMA_REG_VQ_CTRL1 0x4A4 ++ ++/* Virtual QID shift, it takes queue as input, and computes ++ * Virtual QID position in virtual qid control register ++ */ ++#define EDMA_VQ_ID_SHIFT(i) (((i) * 3) % 24) ++ ++/* Virtual Queue Default Value */ ++#define EDMA_VQ_REG_VALUE 0x240240 ++ ++/* Tx side Port Interface Control Register */ ++#define EDMA_REG_PORT_CTRL 0x4A8 ++#define EDMA_PAD_EN_SHIFT 15 ++ ++/* Tx side VLAN Configuration Register */ ++#define EDMA_REG_VLAN_CFG 0x4AC ++ ++#define EDMA_TX_CVLAN 16 ++#define EDMA_TX_INS_CVLAN 17 ++#define EDMA_TX_CVLAN_TAG_SHIFT 0 ++ ++#define EDMA_TX_SVLAN 14 ++#define EDMA_TX_INS_SVLAN 15 ++#define EDMA_TX_SVLAN_TAG_SHIFT 16 ++ ++/* Tx Queue Packet Statistic Register */ ++#define EDMA_REG_TX_STAT_PKT_Q(x) (0x700 + ((x) << 3)) /* x = queue id */ ++ ++#define EDMA_TX_STAT_PKT_MASK 0xFFFFFF ++ ++/* Tx Queue Byte Statistic Register */ ++#define EDMA_REG_TX_STAT_BYTE_Q(x) (0x704 + ((x) << 3)) /* x = queue id */ ++ ++/* Load Balance Based Ring Offset Register */ ++#define EDMA_REG_LB_RING 0x800 ++#define EDMA_LB_RING_ENTRY_MASK 0xff ++#define EDMA_LB_RING_ID_MASK 0x7 ++#define EDMA_LB_RING_PROFILE_ID_MASK 0x3 ++#define EDMA_LB_RING_ENTRY_BIT_OFFSET 8 ++#define EDMA_LB_RING_ID_OFFSET 0 ++#define EDMA_LB_RING_PROFILE_ID_OFFSET 3 ++#define EDMA_LB_REG_VALUE 0x6040200 ++ ++/* Load Balance Priority Mapping Register */ ++#define EDMA_REG_LB_PRI_START 0x804 ++#define EDMA_REG_LB_PRI_END 0x810 ++#define EDMA_LB_PRI_REG_INC 4 ++#define EDMA_LB_PRI_ENTRY_BIT_OFFSET 4 ++#define EDMA_LB_PRI_ENTRY_MASK 0xf ++ ++/* RSS Priority Mapping Register */ ++#define EDMA_REG_RSS_PRI 0x820 ++#define EDMA_RSS_PRI_ENTRY_MASK 0xf ++#define EDMA_RSS_RING_ID_MASK 0x7 ++#define EDMA_RSS_PRI_ENTRY_BIT_OFFSET 4 ++ ++/* RSS Indirection Register */ ++#define EDMA_REG_RSS_IDT(x) (0x840 + ((x) << 2)) /* x = No. of indirection table */ ++#define EDMA_NUM_IDT 16 ++#define EDMA_RSS_IDT_VALUE 0x64206420 ++ ++/* Default RSS Ring Register */ ++#define EDMA_REG_DEF_RSS 0x890 ++#define EDMA_DEF_RSS_MASK 0x7 ++ ++/* RSS Hash Function Type Register */ ++#define EDMA_REG_RSS_TYPE 0x894 ++#define EDMA_RSS_TYPE_NONE 0x01 ++#define EDMA_RSS_TYPE_IPV4TCP 0x02 ++#define EDMA_RSS_TYPE_IPV6_TCP 0x04 ++#define EDMA_RSS_TYPE_IPV4_UDP 0x08 ++#define EDMA_RSS_TYPE_IPV6UDP 0x10 ++#define EDMA_RSS_TYPE_IPV4 0x20 ++#define EDMA_RSS_TYPE_IPV6 0x40 ++#define EDMA_RSS_HASH_MODE_MASK 0x7f ++ ++#define EDMA_REG_RSS_HASH_VALUE 0x8C0 ++ ++#define EDMA_REG_RSS_TYPE_RESULT 0x8C4 ++ ++#define EDMA_HASH_TYPE_START 0 ++#define EDMA_HASH_TYPE_END 5 ++#define EDMA_HASH_TYPE_SHIFT 12 ++ ++#define EDMA_RFS_FLOW_ENTRIES 1024 ++#define EDMA_RFS_FLOW_ENTRIES_MASK (EDMA_RFS_FLOW_ENTRIES - 1) ++#define EDMA_RFS_EXPIRE_COUNT_PER_CALL 128 ++ ++/* RFD Base Address Register */ ++#define EDMA_REG_RFD_BASE_ADDR_Q(x) (0x950 + ((x) << 2)) /* x = queue id */ ++ ++/* RFD Index Register */ ++#define EDMA_REG_RFD_IDX_Q(x) (0x9B0 + ((x) << 2)) ++ ++#define EDMA_RFD_PROD_IDX_BITS 0x00000FFF ++#define EDMA_RFD_CONS_IDX_BITS 0x0FFF0000 ++#define EDMA_RFD_PROD_IDX_MASK 0xFFF ++#define EDMA_RFD_CONS_IDX_MASK 0xFFF ++#define EDMA_RFD_PROD_IDX_SHIFT 0 ++#define EDMA_RFD_CONS_IDX_SHIFT 16 ++ ++/* Rx Descriptor Control Register */ ++#define EDMA_REG_RX_DESC0 0xA10 ++#define EDMA_RFD_RING_SIZE_MASK 0xFFF ++#define EDMA_RX_BUF_SIZE_MASK 0xFFFF ++#define EDMA_RFD_RING_SIZE_SHIFT 0 ++#define EDMA_RX_BUF_SIZE_SHIFT 16 ++ ++#define EDMA_REG_RX_DESC1 0xA14 ++#define EDMA_RXQ_RFD_BURST_NUM_MASK 0x3F ++#define EDMA_RXQ_RFD_PF_THRESH_MASK 0x1F ++#define EDMA_RXQ_RFD_LOW_THRESH_MASK 0xFFF ++#define EDMA_RXQ_RFD_BURST_NUM_SHIFT 0 ++#define EDMA_RXQ_RFD_PF_THRESH_SHIFT 8 ++#define EDMA_RXQ_RFD_LOW_THRESH_SHIFT 16 ++ ++/* RXQ Control Register */ ++#define EDMA_REG_RXQ_CTRL 0xA18 ++#define EDMA_FIFO_THRESH_TYPE_SHIF 0 ++#define EDMA_FIFO_THRESH_128_BYTE 0x0 ++#define EDMA_FIFO_THRESH_64_BYTE 0x1 ++#define EDMA_RXQ_CTRL_RMV_VLAN 0x00000002 ++#define EDMA_RXQ_CTRL_EN 0x0000FF00 ++ ++/* AXI Burst Size Config */ ++#define EDMA_REG_AXIW_CTRL_MAXWRSIZE 0xA1C ++#define EDMA_AXIW_MAXWRSIZE_VALUE 0x0 ++ ++/* Rx Statistics Register */ ++#define EDMA_REG_RX_STAT_BYTE_Q(x) (0xA30 + ((x) << 2)) /* x = queue id */ ++#define EDMA_REG_RX_STAT_PKT_Q(x) (0xA50 + ((x) << 2)) /* x = queue id */ ++ ++/* WoL Pattern Length Register */ ++#define EDMA_REG_WOL_PATTERN_LEN0 0xC00 ++#define EDMA_WOL_PT_LEN_MASK 0xFF ++#define EDMA_WOL_PT0_LEN_SHIFT 0 ++#define EDMA_WOL_PT1_LEN_SHIFT 8 ++#define EDMA_WOL_PT2_LEN_SHIFT 16 ++#define EDMA_WOL_PT3_LEN_SHIFT 24 ++ ++#define EDMA_REG_WOL_PATTERN_LEN1 0xC04 ++#define EDMA_WOL_PT4_LEN_SHIFT 0 ++#define EDMA_WOL_PT5_LEN_SHIFT 8 ++#define EDMA_WOL_PT6_LEN_SHIFT 16 ++ ++/* WoL Control Register */ ++#define EDMA_REG_WOL_CTRL 0xC08 ++#define EDMA_WOL_WK_EN 0x00000001 ++#define EDMA_WOL_MG_EN 0x00000002 ++#define EDMA_WOL_PT0_EN 0x00000004 ++#define EDMA_WOL_PT1_EN 0x00000008 ++#define EDMA_WOL_PT2_EN 0x00000010 ++#define EDMA_WOL_PT3_EN 0x00000020 ++#define EDMA_WOL_PT4_EN 0x00000040 ++#define EDMA_WOL_PT5_EN 0x00000080 ++#define EDMA_WOL_PT6_EN 0x00000100 ++ ++/* MAC Control Register */ ++#define EDMA_REG_MAC_CTRL0 0xC20 ++#define EDMA_REG_MAC_CTRL1 0xC24 ++ ++/* WoL Pattern Register */ ++#define EDMA_REG_WOL_PATTERN_START 0x5000 ++#define EDMA_PATTERN_PART_REG_OFFSET 0x40 ++ ++ ++/* TX descriptor fields */ ++#define EDMA_TPD_HDR_SHIFT 0 ++#define EDMA_TPD_PPPOE_EN 0x00000100 ++#define EDMA_TPD_IP_CSUM_EN 0x00000200 ++#define EDMA_TPD_TCP_CSUM_EN 0x0000400 ++#define EDMA_TPD_UDP_CSUM_EN 0x00000800 ++#define EDMA_TPD_CUSTOM_CSUM_EN 0x00000C00 ++#define EDMA_TPD_LSO_EN 0x00001000 ++#define EDMA_TPD_LSO_V2_EN 0x00002000 ++#define EDMA_TPD_IPV4_EN 0x00010000 ++#define EDMA_TPD_MSS_MASK 0x1FFF ++#define EDMA_TPD_MSS_SHIFT 18 ++#define EDMA_TPD_CUSTOM_CSUM_SHIFT 18 ++ ++/* RRD descriptor fields */ ++#define EDMA_RRD_NUM_RFD_MASK 0x000F ++#define EDMA_RRD_SVLAN 0x8000 ++#define EDMA_RRD_FLOW_COOKIE_MASK 0x07FF; ++ ++#define EDMA_RRD_PKT_SIZE_MASK 0x3FFF ++#define EDMA_RRD_CSUM_FAIL_MASK 0xC000 ++#define EDMA_RRD_CVLAN 0x0001 ++#define EDMA_RRD_DESC_VALID 0x8000 ++ ++#define EDMA_RRD_PRIORITY_SHIFT 4 ++#define EDMA_RRD_PRIORITY_MASK 0x7 ++#define EDMA_RRD_PORT_TYPE_SHIFT 7 ++#define EDMA_RRD_PORT_TYPE_MASK 0x1F ++#endif /* _ESS_EDMA_H_ */ diff --git a/target/linux/ipq40xx/patches-4.19/711-dts-ipq4019-add-ethernet-essedma-node.patch b/target/linux/ipq40xx/patches-4.19/711-dts-ipq4019-add-ethernet-essedma-node.patch new file mode 100644 index 000000000..7302d237b --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/711-dts-ipq4019-add-ethernet-essedma-node.patch @@ -0,0 +1,92 @@ +From c611d3780fa101662a822d10acf8feb04ca97409 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +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 +--- + 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 +@@ -44,6 +44,8 @@ + spi1 = &blsp1_spi2; + i2c0 = &blsp1_i2c3; + i2c1 = &blsp1_i2c4; ++ ethernet0 = &gmac0; ++ ethernet1 = &gmac1; + }; + + cpus { +@@ -617,6 +619,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>; diff --git a/target/linux/ipq40xx/patches-4.19/712-mr33-essedma.patch b/target/linux/ipq40xx/patches-4.19/712-mr33-essedma.patch new file mode 100644 index 000000000..ee6452eeb --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/712-mr33-essedma.patch @@ -0,0 +1,334 @@ +--- a/drivers/net/ethernet/qualcomm/essedma/edma.c ++++ b/drivers/net/ethernet/qualcomm/essedma/edma.c +@@ -161,8 +161,10 @@ static void edma_configure_rx(struct edm + /* Set Rx FIFO threshold to start to DMA data to host */ + rxq_ctrl_data = EDMA_FIFO_THRESH_128_BYTE; + ++ if (!edma_cinfo->is_single_phy) { + /* Set RX remove vlan bit */ + rxq_ctrl_data |= EDMA_RXQ_CTRL_RMV_VLAN; ++ } + + edma_write_reg(EDMA_REG_RXQ_CTRL, rxq_ctrl_data); + } +@@ -1293,6 +1295,10 @@ void edma_adjust_link(struct net_device + if (status == __EDMA_LINKUP && adapter->link_state == __EDMA_LINKDOWN) { + dev_info(&adapter->pdev->dev, "%s: GMAC Link is up with phy_speed=%d\n", netdev->name, phydev->speed); + adapter->link_state = __EDMA_LINKUP; ++ if (adapter->edma_cinfo->is_single_phy) { ++ ess_set_port_status_speed(adapter->edma_cinfo, phydev, ++ ffs(adapter->dp_bitmap) - 1); ++ } + netif_carrier_on(netdev); + if (netif_running(netdev)) + netif_tx_wake_all_queues(netdev); +@@ -1386,10 +1392,12 @@ netdev_tx_t edma_xmit(struct sk_buff *sk + } + + /* Check and mark VLAN tag offload */ +- if (skb_vlan_tag_present(skb)) +- flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG; +- else if (adapter->default_vlan_tag) +- flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG; ++ if (!adapter->edma_cinfo->is_single_phy) { ++ if (unlikely(skb_vlan_tag_present(skb))) ++ flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG; ++ else if (adapter->default_vlan_tag) ++ flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG; ++ } + + /* Check and mark checksum offload */ + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) +--- a/drivers/net/ethernet/qualcomm/essedma/edma.h ++++ b/drivers/net/ethernet/qualcomm/essedma/edma.h +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -332,6 +333,9 @@ struct edma_common_info { + struct edma_per_cpu_queues_info edma_percpu_info[CONFIG_NR_CPUS]; /* per cpu information */ + spinlock_t stats_lock; /* protect edma stats area for updation */ + struct timer_list edma_stats_timer; ++ bool is_single_phy; ++ void __iomem *ess_hw_addr; ++ struct clk *ess_clk; + }; + + /* transimit packet descriptor (tpd) ring */ +@@ -444,4 +448,6 @@ void edma_change_tx_coalesce(int usecs); + void edma_change_rx_coalesce(int usecs); + void edma_get_tx_rx_coalesce(u32 *reg_val); + void edma_clear_irq_status(void); ++void ess_set_port_status_speed(struct edma_common_info *edma_cinfo, ++ struct phy_device *phydev, uint8_t port_id); + #endif /* _EDMA_H_ */ +--- a/drivers/net/ethernet/qualcomm/essedma/edma_axi.c ++++ b/drivers/net/ethernet/qualcomm/essedma/edma_axi.c +@@ -17,6 +17,11 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + #include "edma.h" + #include "ess_edma.h" + +@@ -81,6 +86,101 @@ void edma_read_reg(u16 reg_addr, volatil + *reg_value = readl((void __iomem *)(edma_hw_addr + reg_addr)); + } + ++static void ess_write_reg(struct edma_common_info *edma, u16 reg_addr, u32 reg_value) ++{ ++ writel(reg_value, ((void __iomem *) ++ ((unsigned long)edma->ess_hw_addr + reg_addr))); ++} ++ ++static void ess_read_reg(struct edma_common_info *edma, u16 reg_addr, ++ volatile u32 *reg_value) ++{ ++ *reg_value = readl((void __iomem *) ++ ((unsigned long)edma->ess_hw_addr + reg_addr)); ++} ++ ++static int ess_reset(struct edma_common_info *edma) ++{ ++ struct device_node *switch_node = NULL; ++ struct reset_control *ess_rst; ++ u32 regval; ++ ++ switch_node = of_find_node_by_name(NULL, "ess-switch"); ++ if (!switch_node) { ++ pr_err("switch-node not found\n"); ++ return -EINVAL; ++ } ++ ++ ess_rst = of_reset_control_get(switch_node, "ess_rst"); ++ of_node_put(switch_node); ++ ++ if (IS_ERR(ess_rst)) { ++ pr_err("failed to find ess_rst!\n"); ++ return -ENOENT; ++ } ++ ++ reset_control_assert(ess_rst); ++ msleep(10); ++ reset_control_deassert(ess_rst); ++ msleep(100); ++ reset_control_put(ess_rst); ++ ++ /* Enable only port 5 <--> port 0 ++ * bits 0:6 bitmap of ports it can fwd to */ ++#define SET_PORT_BMP(r,v) \ ++ ess_read_reg(edma, r, ®val); \ ++ ess_write_reg(edma, r, ((regval & ~0x3F) | v)); ++ ++ SET_PORT_BMP(ESS_PORT0_LOOKUP_CTRL,0x20); ++ SET_PORT_BMP(ESS_PORT1_LOOKUP_CTRL,0x00); ++ SET_PORT_BMP(ESS_PORT2_LOOKUP_CTRL,0x00); ++ SET_PORT_BMP(ESS_PORT3_LOOKUP_CTRL,0x00); ++ SET_PORT_BMP(ESS_PORT4_LOOKUP_CTRL,0x00); ++ SET_PORT_BMP(ESS_PORT5_LOOKUP_CTRL,0x01); ++ ess_write_reg(edma, ESS_RGMII_CTRL, 0x400); ++ ess_write_reg(edma, ESS_PORT0_STATUS, ESS_PORT_1G_FDX); ++ ess_write_reg(edma, ESS_PORT5_STATUS, ESS_PORT_1G_FDX); ++ ess_write_reg(edma, ESS_PORT0_HEADER_CTRL, 0); ++#undef SET_PORT_BMP ++ ++ /* forward multicast and broadcast frames to CPU */ ++ ess_write_reg(edma, ESS_FWD_CTRL1, ++ (ESS_PORTS_ALL << ESS_FWD_CTRL1_UC_FLOOD_S) | ++ (ESS_PORTS_ALL << ESS_FWD_CTRL1_MC_FLOOD_S) | ++ (ESS_PORTS_ALL << ESS_FWD_CTRL1_BC_FLOOD_S)); ++ ++ return 0; ++} ++ ++void ess_set_port_status_speed(struct edma_common_info *edma, ++ struct phy_device *phydev, uint8_t port_id) ++{ ++ uint16_t reg_off = ESS_PORT0_STATUS + (4 * port_id); ++ uint32_t reg_val = 0; ++ ++ ess_read_reg(edma, reg_off, ®_val); ++ ++ /* reset the speed bits [0:1] */ ++ reg_val &= ~ESS_PORT_STATUS_SPEED_INV; ++ ++ /* set the new speed */ ++ switch(phydev->speed) { ++ case SPEED_1000: reg_val |= ESS_PORT_STATUS_SPEED_1000; break; ++ case SPEED_100: reg_val |= ESS_PORT_STATUS_SPEED_100; break; ++ case SPEED_10: reg_val |= ESS_PORT_STATUS_SPEED_10; break; ++ default: reg_val |= ESS_PORT_STATUS_SPEED_INV; break; ++ } ++ ++ /* check full/half duplex */ ++ if (phydev->duplex) { ++ reg_val |= ESS_PORT_STATUS_DUPLEX_MODE; ++ } else { ++ reg_val &= ~ESS_PORT_STATUS_DUPLEX_MODE; ++ } ++ ++ ess_write_reg(edma, reg_off, reg_val); ++} ++ + /* edma_change_tx_coalesce() + * change tx interrupt moderation timer + */ +@@ -550,6 +650,31 @@ static struct ctl_table edma_table[] = { + {} + }; + ++static int ess_parse(struct edma_common_info *edma) ++{ ++ struct device_node *switch_node; ++ int ret = -EINVAL; ++ ++ switch_node = of_find_node_by_name(NULL, "ess-switch"); ++ if (!switch_node) { ++ pr_err("cannot find ess-switch node\n"); ++ goto out; ++ } ++ ++ edma->ess_hw_addr = of_io_request_and_map(switch_node, ++ 0, KBUILD_MODNAME); ++ if (!edma->ess_hw_addr) { ++ pr_err("%s ioremap fail.", __func__); ++ goto out; ++ } ++ ++ edma->ess_clk = of_clk_get_by_name(switch_node, "ess_clk"); ++ ret = clk_prepare_enable(edma->ess_clk); ++out: ++ of_node_put(switch_node); ++ return ret; ++} ++ + /* edma_axi_netdev_ops + * Describe the operations supported by registered netdevices + * +@@ -785,6 +910,17 @@ static int edma_axi_probe(struct platfor + miibus = mdio_data->mii_bus; + } + ++ if (of_property_read_bool(np, "qcom,single-phy") && ++ edma_cinfo->num_gmac == 1) { ++ err = ess_parse(edma_cinfo); ++ if (!err) ++ err = ess_reset(edma_cinfo); ++ if (err) ++ goto err_single_phy_init; ++ else ++ edma_cinfo->is_single_phy = true; ++ } ++ + for_each_available_child_of_node(np, pnp) { + const char *mac_addr; + +@@ -1073,11 +1209,15 @@ static int edma_axi_probe(struct platfor + + for (i = 0; i < edma_cinfo->num_gmac; i++) { + if (adapter[i]->poll_required) { ++ int phy_mode = of_get_phy_mode(np); ++ ++ if (phy_mode < 0) ++ phy_mode = PHY_INTERFACE_MODE_SGMII; + adapter[i]->phydev = + phy_connect(edma_netdev[i], + (const char *)adapter[i]->phy_id, + &edma_adjust_link, +- PHY_INTERFACE_MODE_SGMII); ++ phy_mode); + if (IS_ERR(adapter[i]->phydev)) { + dev_dbg(&pdev->dev, "PHY attach FAIL"); + err = -EIO; +@@ -1121,6 +1261,9 @@ err_rmap_alloc_fail: + for (i = 0; i < edma_cinfo->num_gmac; i++) + unregister_netdev(edma_netdev[i]); + err_register: ++err_single_phy_init: ++ iounmap(edma_cinfo->ess_hw_addr); ++ clk_disable_unprepare(edma_cinfo->ess_clk); + err_mdiobus_init_fail: + edma_free_rx_rings(edma_cinfo); + err_rx_rinit: +@@ -1181,6 +1324,8 @@ static int edma_axi_remove(struct platfo + del_timer_sync(&edma_cinfo->edma_stats_timer); + edma_free_irqs(adapter); + unregister_net_sysctl_table(edma_cinfo->edma_ctl_table_hdr); ++ iounmap(edma_cinfo->ess_hw_addr); ++ clk_disable_unprepare(edma_cinfo->ess_clk); + edma_free_tx_resources(edma_cinfo); + edma_free_rx_resources(edma_cinfo); + edma_free_tx_rings(edma_cinfo); +--- a/drivers/net/ethernet/qualcomm/essedma/ess_edma.h ++++ b/drivers/net/ethernet/qualcomm/essedma/ess_edma.h +@@ -329,4 +329,61 @@ struct edma_hw; + #define EDMA_RRD_PRIORITY_MASK 0x7 + #define EDMA_RRD_PORT_TYPE_SHIFT 7 + #define EDMA_RRD_PORT_TYPE_MASK 0x1F ++ ++#define ESS_RGMII_CTRL 0x0004 ++ ++/* Port status registers */ ++#define ESS_PORT0_STATUS 0x007C ++#define ESS_PORT1_STATUS 0x0080 ++#define ESS_PORT2_STATUS 0x0084 ++#define ESS_PORT3_STATUS 0x0088 ++#define ESS_PORT4_STATUS 0x008C ++#define ESS_PORT5_STATUS 0x0090 ++ ++#define ESS_PORT_STATUS_HDX_FLOW_CTL 0x80 ++#define ESS_PORT_STATUS_DUPLEX_MODE 0x40 ++#define ESS_PORT_STATUS_RX_FLOW_EN 0x20 ++#define ESS_PORT_STATUS_TX_FLOW_EN 0x10 ++#define ESS_PORT_STATUS_RX_MAC_EN 0x08 ++#define ESS_PORT_STATUS_TX_MAC_EN 0x04 ++#define ESS_PORT_STATUS_SPEED_INV 0x03 ++#define ESS_PORT_STATUS_SPEED_1000 0x02 ++#define ESS_PORT_STATUS_SPEED_100 0x01 ++#define ESS_PORT_STATUS_SPEED_10 0x00 ++ ++#define ESS_PORT_1G_FDX (ESS_PORT_STATUS_DUPLEX_MODE | ESS_PORT_STATUS_RX_FLOW_EN | \ ++ ESS_PORT_STATUS_TX_FLOW_EN | ESS_PORT_STATUS_RX_MAC_EN | \ ++ ESS_PORT_STATUS_TX_MAC_EN | ESS_PORT_STATUS_SPEED_1000) ++ ++#define PHY_STATUS_REG 0x11 ++#define PHY_STATUS_SPEED 0xC000 ++#define PHY_STATUS_SPEED_SHIFT 14 ++#define PHY_STATUS_DUPLEX 0x2000 ++#define PHY_STATUS_DUPLEX_SHIFT 13 ++#define PHY_STATUS_SPEED_DUPLEX_RESOLVED 0x0800 ++#define PHY_STATUS_CARRIER 0x0400 ++#define PHY_STATUS_CARRIER_SHIFT 10 ++ ++/* Port lookup control registers */ ++#define ESS_PORT0_LOOKUP_CTRL 0x0660 ++#define ESS_PORT1_LOOKUP_CTRL 0x066C ++#define ESS_PORT2_LOOKUP_CTRL 0x0678 ++#define ESS_PORT3_LOOKUP_CTRL 0x0684 ++#define ESS_PORT4_LOOKUP_CTRL 0x0690 ++#define ESS_PORT5_LOOKUP_CTRL 0x069C ++ ++#define ESS_PORT0_HEADER_CTRL 0x009C ++ ++#define ESS_PORTS_ALL 0x3f ++ ++#define ESS_FWD_CTRL1 0x0624 ++#define ESS_FWD_CTRL1_UC_FLOOD BITS(0, 7) ++#define ESS_FWD_CTRL1_UC_FLOOD_S 0 ++#define ESS_FWD_CTRL1_MC_FLOOD BITS(8, 7) ++#define ESS_FWD_CTRL1_MC_FLOOD_S 8 ++#define ESS_FWD_CTRL1_BC_FLOOD BITS(16, 7) ++#define ESS_FWD_CTRL1_BC_FLOOD_S 16 ++#define ESS_FWD_CTRL1_IGMP BITS(24, 7) ++#define ESS_FWD_CTRL1_IGMP_S 24 ++ + #endif /* _ESS_EDMA_H_ */ diff --git a/target/linux/ipq40xx/patches-4.19/713-essedma-alloc-skb-ip-align.patch b/target/linux/ipq40xx/patches-4.19/713-essedma-alloc-skb-ip-align.patch new file mode 100644 index 000000000..8c70fceb0 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/713-essedma-alloc-skb-ip-align.patch @@ -0,0 +1,21 @@ +From 17681f0bb474d0d227f07369144149d1555d8bce Mon Sep 17 00:00:00 2001 +From: Chen Minqiang +Date: Sun, 17 Jun 2018 04:14:13 +0800 +Subject: [PATCH] essedma: alloc skb ip align + +Signed-off-by: Chen Minqiang +--- + drivers/net/ethernet/qualcomm/essedma/edma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/qualcomm/essedma/edma.c ++++ b/drivers/net/ethernet/qualcomm/essedma/edma.c +@@ -201,7 +201,7 @@ static int edma_alloc_rx_buf(struct edma + skb = sw_desc->skb; + } else { + /* alloc skb */ +- skb = netdev_alloc_skb(edma_netdev[0], length); ++ skb = netdev_alloc_skb_ip_align(edma_netdev[0], length); + if (!skb) { + /* Better luck next round */ + break; diff --git a/target/linux/ipq40xx/patches-4.19/850-soc-add-qualcomm-syscon.patch b/target/linux/ipq40xx/patches-4.19/850-soc-add-qualcomm-syscon.patch new file mode 100644 index 000000000..7b4eeff5b --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/850-soc-add-qualcomm-syscon.patch @@ -0,0 +1,180 @@ +From: Christian Lamparter +Subject: SoC: add qualcomm syscon +--- a/drivers/soc/qcom/Makefile ++++ b/drivers/soc/qcom/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_st + obj-$(CONFIG_QCOM_SMP2P) += smp2p.o + obj-$(CONFIG_QCOM_SMSM) += smsm.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 +@@ -146,6 +146,13 @@ config QCOM_SMSM + Say yes here to support the Qualcomm Shared Memory State Machine. + The state machine is represented by bits in shared memory. + ++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 +--- /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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++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 diff --git a/target/linux/ipq40xx/patches-4.19/900-dts-ipq4019-ap-dk01.1.patch b/target/linux/ipq40xx/patches-4.19/900-dts-ipq4019-ap-dk01.1.patch new file mode 100644 index 000000000..48825375e --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/900-dts-ipq4019-ap-dk01.1.patch @@ -0,0 +1,157 @@ +--- 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 + + / { + 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 = ; ++ status = "ok"; ++ }; ++ ++ ess_tcsr@1953000 { ++ compatible = "qcom,tcsr"; ++ reg = <0x1953000 0x1000>; ++ qcom,ess-interface-select = ; ++ }; ++ ++ tcsr@1949000 { ++ compatible = "qcom,tcsr"; ++ reg = <0x1949000 0x100>; ++ qcom,wifi_glb_cfg = ; ++ }; ++ ++ tcsr@1957000 { ++ compatible = "qcom,tcsr"; ++ reg = <0x1957000 0x100>; ++ qcom,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 { +@@ -110,6 +129,22 @@ + 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 = "ok"; + }; +--- 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>; ++ }; ++ }; + }; diff --git a/target/linux/ipq40xx/patches-4.19/901-arm-boot-add-dts-files.patch b/target/linux/ipq40xx/patches-4.19/901-arm-boot-add-dts-files.patch new file mode 100644 index 000000000..bd06be83b --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/901-arm-boot-add-dts-files.patch @@ -0,0 +1,40 @@ +From 8f68331e14dff9a101f2d0e1d6bec84a031f27ee Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 11:03:18 +0100 +Subject: [PATCH 69/69] arm: boot: add dts files + +Signed-off-by: John Crispin +--- + arch/arm/boot/dts/Makefile | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -785,11 +785,27 @@ dtb-$(CONFIG_ARCH_QCOM) += \ + qcom-apq8074-dragonboard.dtb \ + qcom-apq8084-ifc6540.dtb \ + qcom-apq8084-mtp.dtb \ ++ qcom-ipq4018-a42.dtb \ ++ qcom-ipq4018-ea6350v3.dtb \ ++ qcom-ipq4018-eap1300.dtb \ ++ qcom-ipq4018-ex6100v2.dtb \ ++ qcom-ipq4018-ex6150v2.dtb \ ++ qcom-ipq4018-fritz4040.dtb \ ++ qcom-ipq4018-jalapeno.dtb \ ++ qcom-ipq4018-nbg6617.dtb \ ++ qcom-ipq4018-rt-ac58u.dtb \ ++ qcom-ipq4018-wre6606.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-map-ac2200.dtb \ ++ qcom-ipq4019-rt-acrh17.dtb \ ++ qcom-ipq4028-wpj428.dtb \ ++ qcom-ipq4029-gl-b1300.dtb \ ++ qcom-ipq4029-mr33.dtb \ + qcom-ipq8064-ap148.dtb \ + qcom-msm8660-surf.dtb \ + qcom-msm8960-cdp.dtb \ diff --git a/target/linux/ipq40xx/patches-4.19/997-device_tree_cmdline.patch b/target/linux/ipq40xx/patches-4.19/997-device_tree_cmdline.patch new file mode 100644 index 000000000..7600b0e83 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.19/997-device_tree_cmdline.patch @@ -0,0 +1,12 @@ +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1090,6 +1090,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((int)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