From: Tomasz Maciej Nowak Date: Wed, 7 Mar 2018 21:10:02 +0000 (+0100) Subject: mvebu: new subtarget cortex A53 X-Git-Tag: v18.06.0-rc1~676 X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fopenwrt.git;a=commitdiff_plain;h=584d7c53bd2d286a71fe5e8244624f59c529cb26 mvebu: new subtarget cortex A53 This commit introduces new subtarget for Marvell EBU Armada Cortex A53 processor based devices. The first device is Globalscale ESPRESSObin. Some hardware specs: SoC: Marvell Armada 3700LP (88F3720) dual core ARM Cortex A53 processor up to 1.2GHz RAM: 512MB, 1GB or 2GB DDR3 Storage: SATA interface µSD card slot with footprint for an optional 4GB EMMC 4MB SPI NOR flash for bootloader Ethernet: Topaz Networking Switch (88E6341) with 3x GbE ports Connectors: USB 3.0 USB 2.0 µUSB port connected to PL2303SA (USB to serial bridge controller) for UART access Expansion: 2x 46-pin GPIO headers for accessories and shields with I2C, GPIOs, PWM, UART, SPI, MMC, etc MiniPCIe slot Misc: Reset button, JTAG interface Currently booting only from µSD card is supported. The boards depending on date of dispatch can come with various U-Boot versions. For the newest version 2017.03-armada-17.10 no manual intervention should be needed to boot OpenWrt image. For the older ones it's necessary to modify default U-Boot environment: 1. Interrupt boot process to run U-Boot command line, 2. Run following commands: (for version 2017.03-armada-17.06 and 2017.03-armada-17.08) setenv bootcmd "load mmc 0:1 0x4d00000 boot.scr; source 0x4d00000" saveenv (for version 2015.01-armada-17.02 and 2015.01-armada-17.04) setenv bootargs "console=ttyMV0,115200 root=/dev/mmcblk0p2 rw rootwait" setenv bootcmd "ext4load mmc 0:1 ${fdt_addr} armada-3720-espressobin.dtb; ext4load mmc 0:1 ${kernel_addr} Image; booti ${kernel_addr} - ${fdt_addr}" saveenv 3. Poweroff, insert SD card with OpenWrt image, boot and enjoy. Signed-off-by: Tomasz Maciej Nowak --- diff --git a/target/linux/mvebu/Makefile b/target/linux/mvebu/Makefile index 93491954ab..0afc5771c2 100644 --- a/target/linux/mvebu/Makefile +++ b/target/linux/mvebu/Makefile @@ -7,9 +7,9 @@ include $(TOPDIR)/rules.mk BOARD:=mvebu -BOARDNAME:=Marvell Armada 37x/38x/XP +BOARDNAME:=Marvell EBU Armada FEATURES:=fpu usb pci pcie gpio nand squashfs ramdisk -SUBTARGETS:=cortexa9 +SUBTARGETS:=cortexa9 cortexa53 MAINTAINER:=Imre Kaloz KERNEL_PATCHVER:=4.14 diff --git a/target/linux/mvebu/base-files/etc/board.d/02_network b/target/linux/mvebu/base-files/etc/board.d/02_network index 36c4b23c5d..28cdc22b28 100755 --- a/target/linux/mvebu/base-files/etc/board.d/02_network +++ b/target/linux/mvebu/base-files/etc/board.d/02_network @@ -42,6 +42,9 @@ armada-388-clearfog-*) armada-xp-gp) ucidef_set_interface_lan "eth0 eth1 eth2 eth3" ;; +globalscale,espressobin) + ucidef_set_interfaces_lan_wan "lan0 lan1" "wan" + ;; *) ucidef_set_interface_lan "eth0" ;; diff --git a/target/linux/mvebu/base-files/lib/mvebu.sh b/target/linux/mvebu/base-files/lib/mvebu.sh index 1cd87507a3..707ceb18ef 100755 --- a/target/linux/mvebu/base-files/lib/mvebu.sh +++ b/target/linux/mvebu/base-files/lib/mvebu.sh @@ -17,6 +17,9 @@ mvebu_board_detect() { *"Marvell Armada 370 Evaluation Board") name="armada-370-db" ;; + *"Globalscale Marvell ESPRESSOBin Board") + name="globalscale,espressobin" + ;; *"Globalscale Mirabox") name="mirabox" ;; diff --git a/target/linux/mvebu/base-files/lib/upgrade/platform.sh b/target/linux/mvebu/base-files/lib/upgrade/platform.sh index ef8065a44e..3915bfdb7c 100755 --- a/target/linux/mvebu/base-files/lib/upgrade/platform.sh +++ b/target/linux/mvebu/base-files/lib/upgrade/platform.sh @@ -16,7 +16,7 @@ platform_do_upgrade() { armada-385-linksys-caiman|armada-385-linksys-cobra|armada-385-linksys-rango|armada-385-linksys-shelby|armada-xp-linksys-mamba) platform_do_upgrade_linksys "$ARGV" ;; - armada-385-turris-omnia|armada-388-clearfog-base|armada-388-clearfog-pro) + armada-385-turris-omnia|armada-388-clearfog-base|armada-388-clearfog-pro|globalscale,espressobin) platform_do_upgrade_sdcard "$ARGV" ;; *) @@ -29,7 +29,7 @@ platform_copy_config() { armada-385-linksys-caiman|armada-385-linksys-cobra|armada-385-linksys-rango|armada-385-linksys-shelby|armada-xp-linksys-mamba) platform_copy_config_linksys ;; - armada-385-turris-omnia|armada-388-clearfog-base|armada-388-clearfog-pro) + armada-385-turris-omnia|armada-388-clearfog-base|armada-388-clearfog-pro|globalscale,espressobin) platform_copy_config_sdcard "$ARGV" ;; esac diff --git a/target/linux/mvebu/config-4.14 b/target/linux/mvebu/config-4.14 index 738f0378b4..5286bf9b83 100644 --- a/target/linux/mvebu/config-4.14 +++ b/target/linux/mvebu/config-4.14 @@ -39,6 +39,7 @@ CONFIG_ARMADA_38X_CLK=y CONFIG_ARMADA_THERMAL=y CONFIG_ARMADA_XP_CLK=y CONFIG_ARM_APPENDED_DTB=y +# CONFIG_ARM_ARMADA_37XX_CPUFREQ is not set CONFIG_ARM_ATAG_DTB_COMPAT=y # CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y diff --git a/target/linux/mvebu/cortexa53/config-default b/target/linux/mvebu/cortexa53/config-default new file mode 100644 index 0000000000..0ee5d3cca6 --- /dev/null +++ b/target/linux/mvebu/cortexa53/config-default @@ -0,0 +1,112 @@ +CONFIG_64BIT=y +# CONFIG_ACPI is not set +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set +# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARM64=y +# CONFIG_ARM64_16K_PAGES is not set +CONFIG_ARM64_4K_PAGES=y +# CONFIG_ARM64_64K_PAGES is not set +CONFIG_ARM64_CONT_SHIFT=4 +# CONFIG_ARM64_CRYPTO is not set +# CONFIG_ARM64_HW_AFDBM is not set +# CONFIG_ARM64_LSE_ATOMICS is not set +CONFIG_ARM64_PAGE_SHIFT=12 +# CONFIG_ARM64_PAN is not set +# CONFIG_ARM64_PMEM is not set +# CONFIG_ARM64_PTDUMP_CORE is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +# CONFIG_ARM64_SW_TTBR0_PAN is not set +# CONFIG_ARM64_UAO is not set +CONFIG_ARM64_VA_BITS=39 +CONFIG_ARM64_VA_BITS_39=y +# CONFIG_ARM64_VA_BITS_48 is not set +# CONFIG_ARM64_VHE is not set +CONFIG_ARMADA_37XX_CLK=y +CONFIG_ARMADA_AP806_SYSCON=y +CONFIG_ARMADA_CP110_SYSCON=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ARMADA_37XX_CPUFREQ=y +CONFIG_ARM_GIC_V2M=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +# CONFIG_ARM_PL172_MPMC is not set +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +# CONFIG_COMPAT is not set +# CONFIG_DEBUG_ALIGN_RODATA is not set +CONFIG_FRAME_POINTER=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_DEBUG_BUGVERBOSE=y +CONFIG_HAVE_GENERIC_GUP=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_HAVE_PATA_PLATFORM=y +CONFIG_HAVE_RCU_TABLE_FREE=y +# CONFIG_HUGETLBFS is not set +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_MFD_SYSCON=y +CONFIG_MMC_SDHCI_XENON=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MVEBU_GICP=y +CONFIG_MVEBU_ICU=y +CONFIG_MVEBU_ODMI=y +CONFIG_MVEBU_PIC=y +CONFIG_NEED_SG_DMA_LENGTH=y +# CONFIG_NUMA is not set +CONFIG_PARTITION_PERCPU=y +CONFIG_PCI_AARDVARK=y +CONFIG_PCI_BUS_ADDR_T_64BIT=y +CONFIG_PGTABLE_LEVELS=3 +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PINCTRL_ARMADA_37XX=y +CONFIG_PINCTRL_ARMADA_AP806=y +CONFIG_PINCTRL_ARMADA_CP110=y +CONFIG_POWER_RESET=y +CONFIG_POWER_SUPPLY=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_REGULATOR_GPIO=y +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPI_ARMADA_3700=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_VMAP_STACK=y diff --git a/target/linux/mvebu/cortexa53/target.mk b/target/linux/mvebu/cortexa53/target.mk new file mode 100644 index 0000000000..acc18d3454 --- /dev/null +++ b/target/linux/mvebu/cortexa53/target.mk @@ -0,0 +1,15 @@ +# +# Copyright (C) 2017 Hauke Mehrtens +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +ARCH:=aarch64 +BOARDNAME:=Marvell Armada 3700LP (ARM64) +CPU_TYPE:=cortex-a53 +FEATURES+=ext4 + +KERNELNAME:=Image dtbs diff --git a/target/linux/mvebu/image/Makefile b/target/linux/mvebu/image/Makefile index 6e012a61e1..55e1a0b2dc 100644 --- a/target/linux/mvebu/image/Makefile +++ b/target/linux/mvebu/image/Makefile @@ -27,17 +27,28 @@ endef define Build/boot-scr rm -f $@-boot.scr - mkimage -A arm -O linux -T script -C none -a 0 -e 0 -d $(DEVICE_NAME).bootscript $@-boot.scr + sed -e 's#@ROOT@#$(SIGNATURE)#g' \ + $(DEVICE_NAME).bootscript > $@-new.bootscript + mkimage -A arm -O linux -T script -C none -a 0 -e 0 -d $@-new.bootscript $@-boot.scr endef define Build/boot-img rm -f $@.boot mkfs.fat -C $@.boot 16384 $(foreach dts,$(DEVICE_DTS), mcopy -i $@.boot $(DTS_DIR)/$(dts).dtb ::$(dts).dtb;) - mcopy -i $@.boot $(IMAGE_KERNEL) ::zImage + mcopy -i $@.boot $(IMAGE_KERNEL) ::$(KERNEL_NAME) -mcopy -i $@.boot $@-boot.scr ::boot.scr endef +define Build/boot-img-ext4 + rm -fR $@.boot + mkdir -p $@.boot + $(foreach dts,$(DEVICE_DTS), $(CP) $(DTS_DIR)/$(dts).dtb $@.boot;) + $(CP) $(IMAGE_KERNEL) $@.boot/$(KERNEL_NAME) + -$(CP) $@-boot.scr $@.boot/boot.scr + make_ext4fs -J -l 16384K $@.bootimg $@.boot +endef + define Build/sdcard-img if [ -n "$(UBOOT)" ]; then UBOOT="$(STAGING_DIR_IMAGE)/$(UBOOT)"; fi; \ ROOTFS_SIZE=$$(( $(CONFIG_TARGET_ROOTFS_PARTSIZE) * 1024 * 2 )); \ @@ -48,6 +59,16 @@ define Build/sdcard-img 83 $$ROOTFS_SIZE $(IMAGE_ROOTFS) endef +define Build/sdcard-img-ext4 + if [ -n "$(UBOOT)" ]; then UBOOT="$(STAGING_DIR_IMAGE)/$(UBOOT)"; fi; \ + ROOTFS_SIZE=$$(( $(CONFIG_TARGET_ROOTFS_PARTSIZE) * 1024 * 2 )); \ + SIGNATURE="$(SIGNATURE)" \ + ./gen_mvebu_sdcard_img.sh $@ \ + $$UBOOT \ + 83 32768 $@.bootimg \ + 83 $$ROOTFS_SIZE $(IMAGE_ROOTFS) +endef + define Build/omnia-medkit-initramfs $(TAR) -c -T /dev/null -f $@ rm -rf $(dir $(IMAGE_KERNEL))boot @@ -101,5 +122,6 @@ define Device/NAND-512K endef include cortex-a9.mk +include cortex-a53.mk $(eval $(call BuildImage)) diff --git a/target/linux/mvebu/image/cortex-a53.mk b/target/linux/mvebu/image/cortex-a53.mk new file mode 100644 index 0000000000..711d2c0be8 --- /dev/null +++ b/target/linux/mvebu/image/cortex-a53.mk @@ -0,0 +1,16 @@ +ifeq ($(SUBTARGET),cortexa53) + +define Device/globalscale-espressobin + KERNEL_NAME := Image + KERNEL := kernel-bin + DEVICE_TITLE := ESPRESSObin (Marvell Armada 3700 Community Board) + DEVICE_PACKAGES := e2fsprogs ethtool mkf2fs kmod-fs-vfat kmod-usb2 kmod-usb3 kmod-usb-storage + IMAGES := sdcard.img.gz + IMAGE/sdcard.img.gz := boot-scr | boot-img-ext4 | sdcard-img-ext4 | gzip | append-metadata + DEVICE_DTS := armada-3720-espressobin + DTS_DIR := $(DTS_DIR)/marvell + SUPPORTED_DEVICES := globalscale,espressobin +endef +TARGET_DEVICES += globalscale-espressobin + +endif diff --git a/target/linux/mvebu/image/globalscale-espressobin.bootscript b/target/linux/mvebu/image/globalscale-espressobin.bootscript new file mode 100644 index 0000000000..0d03ac8513 --- /dev/null +++ b/target/linux/mvebu/image/globalscale-espressobin.bootscript @@ -0,0 +1,10 @@ +setenv bootargs "root=PARTUUID=@ROOT@-02 rw rootwait" + +if test -n "${console}"; then + setenv bootargs "${bootargs} ${console}" +fi + +load mmc 0:1 ${fdt_addr} armada-3720-espressobin.dtb +load mmc 0:1 ${kernel_addr} Image + +booti ${kernel_addr} - ${fdt_addr} diff --git a/target/linux/mvebu/patches-4.14/500-clk-mvebu-armada-37xx-periph-cosmetic-changes.patch b/target/linux/mvebu/patches-4.14/500-clk-mvebu-armada-37xx-periph-cosmetic-changes.patch new file mode 100644 index 0000000000..7343e01d19 --- /dev/null +++ b/target/linux/mvebu/patches-4.14/500-clk-mvebu-armada-37xx-periph-cosmetic-changes.patch @@ -0,0 +1,78 @@ +From adf4e289dd7f801c3fe12e0e6b491e11e548cd3d Mon Sep 17 00:00:00 2001 +From: Gregory CLEMENT +Date: Thu, 30 Nov 2017 14:40:27 +0100 +Subject: clk: mvebu: armada-37xx-periph: cosmetic changes + +This patches fixes few cosmetic issues such as alignment, blank lines +and required space. + +Signed-off-by: Gregory CLEMENT +Signed-off-by: Stephen Boyd +--- + drivers/clk/mvebu/armada-37xx-periph.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +--- a/drivers/clk/mvebu/armada-37xx-periph.c ++++ b/drivers/clk/mvebu/armada-37xx-periph.c +@@ -79,6 +79,7 @@ static const struct clk_div_table clk_ta + { .val = 1, .div = 4, }, + { .val = 0, .div = 0, }, /* last entry */ + }; ++ + static const struct clk_ops clk_double_div_ops; + + #define PERIPH_GATE(_name, _bit) \ +@@ -217,7 +218,7 @@ PERIPH_CLK_FULL(counter, 23, 20, DIV_SEL + PERIPH_CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19); + PERIPH_CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, clk_table6); + +-static struct clk_periph_data data_nb[] ={ ++static struct clk_periph_data data_nb[] = { + REF_CLK_FULL_DD(mmc), + REF_CLK_FULL_DD(sata_host), + REF_CLK_FULL_DD(sec_at), +@@ -281,7 +282,7 @@ static unsigned int get_div(void __iomem + } + + static unsigned long clk_double_div_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) ++ unsigned long parent_rate) + { + struct clk_double_div *double_div = to_clk_double_div(hw); + unsigned int div; +@@ -303,6 +304,7 @@ static const struct of_device_id armada_ + .data = data_sb, }, + { } + }; ++ + static int armada_3700_add_composite_clk(const struct clk_periph_data *data, + void __iomem *reg, spinlock_t *lock, + struct device *dev, struct clk_hw **hw) +@@ -355,9 +357,9 @@ static int armada_3700_add_composite_clk + } + + *hw = clk_hw_register_composite(dev, data->name, data->parent_names, +- data->num_parents, mux_hw, +- mux_ops, rate_hw, rate_ops, +- gate_hw, gate_ops, CLK_IGNORE_UNUSED); ++ data->num_parents, mux_hw, ++ mux_ops, rate_hw, rate_ops, ++ gate_hw, gate_ops, CLK_IGNORE_UNUSED); + + if (IS_ERR(*hw)) + return PTR_ERR(*hw); +@@ -406,12 +408,11 @@ static int armada_3700_periph_clock_prob + if (armada_3700_add_composite_clk(&data[i], reg, + &driver_data->lock, dev, hw)) + dev_err(dev, "Can't register periph clock %s\n", +- data[i].name); +- ++ data[i].name); + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, +- driver_data->hw_data); ++ driver_data->hw_data); + if (ret) { + for (i = 0; i < num_periph; i++) + clk_hw_unregister(driver_data->hw_data->hws[i]); diff --git a/target/linux/mvebu/patches-4.14/501-clk-mvebu-armada-37xx-periph-prepare-cpu-clk-to-be-u.patch b/target/linux/mvebu/patches-4.14/501-clk-mvebu-armada-37xx-periph-prepare-cpu-clk-to-be-u.patch new file mode 100644 index 0000000000..f9dec9f2ee --- /dev/null +++ b/target/linux/mvebu/patches-4.14/501-clk-mvebu-armada-37xx-periph-prepare-cpu-clk-to-be-u.patch @@ -0,0 +1,178 @@ +From 9818a7a4fd10f72537cdf2a5ec3402f2c245ea24 Mon Sep 17 00:00:00 2001 +From: Gregory CLEMENT +Date: Thu, 30 Nov 2017 14:40:28 +0100 +Subject: clk: mvebu: armada-37xx-periph: prepare cpu clk to be + used with DVFS + +When DVFS will be enabled then the cpu clk will use a different set of +register at run time. That means that we won't be able to use the common +callback and need to use our own ones. + +This patch prepares this change by switching on our own set of callbacks +without modifying the behavior of the clocks. + +Signed-off-by: Gregory CLEMENT +Signed-off-by: Stephen Boyd +--- + drivers/clk/mvebu/armada-37xx-periph.c | 82 ++++++++++++++++++++++++++++++---- + 1 file changed, 73 insertions(+), 9 deletions(-) + +--- a/drivers/clk/mvebu/armada-37xx-periph.c ++++ b/drivers/clk/mvebu/armada-37xx-periph.c +@@ -46,7 +46,17 @@ struct clk_double_div { + u8 shift2; + }; + ++struct clk_pm_cpu { ++ struct clk_hw hw; ++ void __iomem *reg_mux; ++ u8 shift_mux; ++ u32 mask_mux; ++ void __iomem *reg_div; ++ u8 shift_div; ++}; ++ + #define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw) ++#define to_clk_pm_cpu(_hw) container_of(_hw, struct clk_pm_cpu, hw) + + struct clk_periph_data { + const char *name; +@@ -55,6 +65,7 @@ struct clk_periph_data { + struct clk_hw *mux_hw; + struct clk_hw *rate_hw; + struct clk_hw *gate_hw; ++ struct clk_hw *muxrate_hw; + bool is_double_div; + }; + +@@ -81,6 +92,7 @@ static const struct clk_div_table clk_ta + }; + + static const struct clk_ops clk_double_div_ops; ++static const struct clk_ops clk_pm_cpu_ops; + + #define PERIPH_GATE(_name, _bit) \ + struct clk_gate gate_##_name = { \ +@@ -122,6 +134,18 @@ struct clk_divider rate_##_name = { \ + } \ + }; + ++#define PERIPH_PM_CPU(_name, _shift1, _reg, _shift2) \ ++struct clk_pm_cpu muxrate_##_name = { \ ++ .reg_mux = (void *)TBG_SEL, \ ++ .mask_mux = 3, \ ++ .shift_mux = _shift1, \ ++ .reg_div = (void *)_reg, \ ++ .shift_div = _shift2, \ ++ .hw.init = &(struct clk_init_data){ \ ++ .ops = &clk_pm_cpu_ops, \ ++ } \ ++}; ++ + #define PERIPH_CLK_FULL_DD(_name, _bit, _shift, _reg1, _reg2, _shift1, _shift2)\ + static PERIPH_GATE(_name, _bit); \ + static PERIPH_MUX(_name, _shift); \ +@@ -136,10 +160,6 @@ static PERIPH_DIV(_name, _reg, _shift1, + static PERIPH_GATE(_name, _bit); \ + static PERIPH_DIV(_name, _reg, _shift, _table); + +-#define PERIPH_CLK_MUX_DIV(_name, _shift, _reg, _shift_div, _table) \ +-static PERIPH_MUX(_name, _shift); \ +-static PERIPH_DIV(_name, _reg, _shift_div, _table); +- + #define PERIPH_CLK_MUX_DD(_name, _shift, _reg1, _reg2, _shift1, _shift2)\ + static PERIPH_MUX(_name, _shift); \ + static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2); +@@ -180,13 +200,12 @@ static PERIPH_DOUBLEDIV(_name, _reg1, _r + .rate_hw = &rate_##_name.hw, \ + } + +-#define REF_CLK_MUX_DIV(_name) \ ++#define REF_CLK_PM_CPU(_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ "TBG-A-P", \ + "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ + .num_parents = 4, \ +- .mux_hw = &mux_##_name.hw, \ +- .rate_hw = &rate_##_name.hw, \ ++ .muxrate_hw = &muxrate_##_name.hw, \ + } + + #define REF_CLK_MUX_DD(_name) \ +@@ -216,7 +235,7 @@ PERIPH_CLK_FULL_DD(ddr_fclk, 21, 16, DIV + PERIPH_CLK_FULL(trace, 22, 18, DIV_SEL0, 20, clk_table6); + PERIPH_CLK_FULL(counter, 23, 20, DIV_SEL0, 23, clk_table6); + PERIPH_CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19); +-PERIPH_CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, clk_table6); ++static PERIPH_PM_CPU(cpu, 22, DIV_SEL0, 28); + + static struct clk_periph_data data_nb[] = { + REF_CLK_FULL_DD(mmc), +@@ -235,7 +254,7 @@ static struct clk_periph_data data_nb[] + REF_CLK_FULL(trace), + REF_CLK_FULL(counter), + REF_CLK_FULL_DD(eip97), +- REF_CLK_MUX_DIV(cpu), ++ REF_CLK_PM_CPU(cpu), + { }, + }; + +@@ -297,6 +316,37 @@ static const struct clk_ops clk_double_d + .recalc_rate = clk_double_div_recalc_rate, + }; + ++static u8 clk_pm_cpu_get_parent(struct clk_hw *hw) ++{ ++ struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); ++ int num_parents = clk_hw_get_num_parents(hw); ++ u32 val; ++ ++ val = readl(pm_cpu->reg_mux) >> pm_cpu->shift_mux; ++ val &= pm_cpu->mask_mux; ++ ++ if (val >= num_parents) ++ return -EINVAL; ++ ++ return val; ++} ++ ++static unsigned long clk_pm_cpu_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); ++ unsigned int div; ++ ++ div = get_div(pm_cpu->reg_div, pm_cpu->shift_div); ++ ++ return DIV_ROUND_UP_ULL((u64)parent_rate, div); ++} ++ ++static const struct clk_ops clk_pm_cpu_ops = { ++ .get_parent = clk_pm_cpu_get_parent, ++ .recalc_rate = clk_pm_cpu_recalc_rate, ++}; ++ + static const struct of_device_id armada_3700_periph_clock_of_match[] = { + { .compatible = "marvell,armada-3700-periph-clock-nb", + .data = data_nb, }, +@@ -356,6 +406,20 @@ static int armada_3700_add_composite_clk + } + } + ++ if (data->muxrate_hw) { ++ struct clk_pm_cpu *pmcpu_clk; ++ struct clk_hw *muxrate_hw = data->muxrate_hw; ++ ++ pmcpu_clk = to_clk_pm_cpu(muxrate_hw); ++ pmcpu_clk->reg_mux = reg + (u64)pmcpu_clk->reg_mux; ++ pmcpu_clk->reg_div = reg + (u64)pmcpu_clk->reg_div; ++ ++ mux_hw = muxrate_hw; ++ rate_hw = muxrate_hw; ++ mux_ops = muxrate_hw->init->ops; ++ rate_ops = muxrate_hw->init->ops; ++ } ++ + *hw = clk_hw_register_composite(dev, data->name, data->parent_names, + data->num_parents, mux_hw, + mux_ops, rate_hw, rate_ops, diff --git a/target/linux/mvebu/patches-4.14/502-clk-mvebu-armada-37xx-periph-add-DVFS-support-for-cp.patch b/target/linux/mvebu/patches-4.14/502-clk-mvebu-armada-37xx-periph-add-DVFS-support-for-cp.patch new file mode 100644 index 0000000000..2065e788af --- /dev/null +++ b/target/linux/mvebu/patches-4.14/502-clk-mvebu-armada-37xx-periph-add-DVFS-support-for-cp.patch @@ -0,0 +1,315 @@ +From 2089dc33ea0e3917465929d4020fbff3d6dbf7f4 Mon Sep 17 00:00:00 2001 +From: Gregory CLEMENT +Date: Thu, 30 Nov 2017 14:40:29 +0100 +Subject: clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks + +When DVFS is enabled the CPU clock setting is done using an other set of +registers. + +These Power Management registers are exposed through a syscon as they +will also be used by other drivers such as the cpufreq. + +This patch add the possibility to modify the CPU frequency using the +associate load level matching the target frequency. Then all the +frequency switch is handle by the hardware. + +Signed-off-by: Gregory CLEMENT +[sboyd@codeaurora.org: Grow a local variable for regmap pointer +to keep lines shorter] +Signed-off-by: Stephen Boyd +--- + drivers/clk/mvebu/armada-37xx-periph.c | 221 ++++++++++++++++++++++++++++++++- + 1 file changed, 217 insertions(+), 4 deletions(-) + +--- a/drivers/clk/mvebu/armada-37xx-periph.c ++++ b/drivers/clk/mvebu/armada-37xx-periph.c +@@ -21,9 +21,11 @@ + */ + + #include ++#include + #include + #include + #include ++#include + #include + + #define TBG_SEL 0x0 +@@ -33,6 +35,26 @@ + #define CLK_SEL 0x10 + #define CLK_DIS 0x14 + ++#define LOAD_LEVEL_NR 4 ++ ++#define ARMADA_37XX_NB_L0L1 0x18 ++#define ARMADA_37XX_NB_L2L3 0x1C ++#define ARMADA_37XX_NB_TBG_DIV_OFF 13 ++#define ARMADA_37XX_NB_TBG_DIV_MASK 0x7 ++#define ARMADA_37XX_NB_CLK_SEL_OFF 11 ++#define ARMADA_37XX_NB_CLK_SEL_MASK 0x1 ++#define ARMADA_37XX_NB_TBG_SEL_OFF 9 ++#define ARMADA_37XX_NB_TBG_SEL_MASK 0x3 ++#define ARMADA_37XX_NB_CONFIG_SHIFT 16 ++#define ARMADA_37XX_NB_DYN_MOD 0x24 ++#define ARMADA_37XX_NB_DFS_EN 31 ++#define ARMADA_37XX_NB_CPU_LOAD 0x30 ++#define ARMADA_37XX_NB_CPU_LOAD_MASK 0x3 ++#define ARMADA_37XX_DVFS_LOAD_0 0 ++#define ARMADA_37XX_DVFS_LOAD_1 1 ++#define ARMADA_37XX_DVFS_LOAD_2 2 ++#define ARMADA_37XX_DVFS_LOAD_3 3 ++ + struct clk_periph_driver_data { + struct clk_hw_onecell_data *hw_data; + spinlock_t lock; +@@ -53,6 +75,7 @@ struct clk_pm_cpu { + u32 mask_mux; + void __iomem *reg_div; + u8 shift_div; ++ struct regmap *nb_pm_base; + }; + + #define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw) +@@ -316,14 +339,94 @@ static const struct clk_ops clk_double_d + .recalc_rate = clk_double_div_recalc_rate, + }; + ++static void armada_3700_pm_dvfs_update_regs(unsigned int load_level, ++ unsigned int *reg, ++ unsigned int *offset) ++{ ++ if (load_level <= ARMADA_37XX_DVFS_LOAD_1) ++ *reg = ARMADA_37XX_NB_L0L1; ++ else ++ *reg = ARMADA_37XX_NB_L2L3; ++ ++ if (load_level == ARMADA_37XX_DVFS_LOAD_0 || ++ load_level == ARMADA_37XX_DVFS_LOAD_2) ++ *offset += ARMADA_37XX_NB_CONFIG_SHIFT; ++} ++ ++static bool armada_3700_pm_dvfs_is_enabled(struct regmap *base) ++{ ++ unsigned int val, reg = ARMADA_37XX_NB_DYN_MOD; ++ ++ if (IS_ERR(base)) ++ return false; ++ ++ regmap_read(base, reg, &val); ++ ++ return !!(val & BIT(ARMADA_37XX_NB_DFS_EN)); ++} ++ ++static unsigned int armada_3700_pm_dvfs_get_cpu_div(struct regmap *base) ++{ ++ unsigned int reg = ARMADA_37XX_NB_CPU_LOAD; ++ unsigned int offset = ARMADA_37XX_NB_TBG_DIV_OFF; ++ unsigned int load_level, div; ++ ++ /* ++ * This function is always called after the function ++ * armada_3700_pm_dvfs_is_enabled, so no need to check again ++ * if the base is valid. ++ */ ++ regmap_read(base, reg, &load_level); ++ ++ /* ++ * The register and the offset inside this register accessed to ++ * read the current divider depend on the load level ++ */ ++ load_level &= ARMADA_37XX_NB_CPU_LOAD_MASK; ++ armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); ++ ++ regmap_read(base, reg, &div); ++ ++ return (div >> offset) & ARMADA_37XX_NB_TBG_DIV_MASK; ++} ++ ++static unsigned int armada_3700_pm_dvfs_get_cpu_parent(struct regmap *base) ++{ ++ unsigned int reg = ARMADA_37XX_NB_CPU_LOAD; ++ unsigned int offset = ARMADA_37XX_NB_TBG_SEL_OFF; ++ unsigned int load_level, sel; ++ ++ /* ++ * This function is always called after the function ++ * armada_3700_pm_dvfs_is_enabled, so no need to check again ++ * if the base is valid ++ */ ++ regmap_read(base, reg, &load_level); ++ ++ /* ++ * The register and the offset inside this register accessed to ++ * read the current divider depend on the load level ++ */ ++ load_level &= ARMADA_37XX_NB_CPU_LOAD_MASK; ++ armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); ++ ++ regmap_read(base, reg, &sel); ++ ++ return (sel >> offset) & ARMADA_37XX_NB_TBG_SEL_MASK; ++} ++ + static u8 clk_pm_cpu_get_parent(struct clk_hw *hw) + { + struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); + int num_parents = clk_hw_get_num_parents(hw); + u32 val; + +- val = readl(pm_cpu->reg_mux) >> pm_cpu->shift_mux; +- val &= pm_cpu->mask_mux; ++ if (armada_3700_pm_dvfs_is_enabled(pm_cpu->nb_pm_base)) { ++ val = armada_3700_pm_dvfs_get_cpu_parent(pm_cpu->nb_pm_base); ++ } else { ++ val = readl(pm_cpu->reg_mux) >> pm_cpu->shift_mux; ++ val &= pm_cpu->mask_mux; ++ } + + if (val >= num_parents) + return -EINVAL; +@@ -331,19 +434,124 @@ static u8 clk_pm_cpu_get_parent(struct c + return val; + } + ++static int clk_pm_cpu_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); ++ struct regmap *base = pm_cpu->nb_pm_base; ++ int load_level; ++ ++ /* ++ * We set the clock parent only if the DVFS is available but ++ * not enabled. ++ */ ++ if (IS_ERR(base) || armada_3700_pm_dvfs_is_enabled(base)) ++ return -EINVAL; ++ ++ /* Set the parent clock for all the load level */ ++ for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) { ++ unsigned int reg, mask, val, ++ offset = ARMADA_37XX_NB_TBG_SEL_OFF; ++ ++ armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); ++ ++ val = index << offset; ++ mask = ARMADA_37XX_NB_TBG_SEL_MASK << offset; ++ regmap_update_bits(base, reg, mask, val); ++ } ++ return 0; ++} ++ + static unsigned long clk_pm_cpu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { + struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); + unsigned int div; + +- div = get_div(pm_cpu->reg_div, pm_cpu->shift_div); +- ++ if (armada_3700_pm_dvfs_is_enabled(pm_cpu->nb_pm_base)) ++ div = armada_3700_pm_dvfs_get_cpu_div(pm_cpu->nb_pm_base); ++ else ++ div = get_div(pm_cpu->reg_div, pm_cpu->shift_div); + return DIV_ROUND_UP_ULL((u64)parent_rate, div); + } + ++static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); ++ struct regmap *base = pm_cpu->nb_pm_base; ++ unsigned int div = *parent_rate / rate; ++ unsigned int load_level; ++ /* only available when DVFS is enabled */ ++ if (!armada_3700_pm_dvfs_is_enabled(base)) ++ return -EINVAL; ++ ++ for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) { ++ unsigned int reg, val, offset = ARMADA_37XX_NB_TBG_DIV_OFF; ++ ++ armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); ++ ++ regmap_read(base, reg, &val); ++ ++ val >>= offset; ++ val &= ARMADA_37XX_NB_TBG_DIV_MASK; ++ if (val == div) ++ /* ++ * We found a load level matching the target ++ * divider, switch to this load level and ++ * return. ++ */ ++ return *parent_rate / div; ++ } ++ ++ /* We didn't find any valid divider */ ++ return -EINVAL; ++} ++ ++static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); ++ struct regmap *base = pm_cpu->nb_pm_base; ++ unsigned int div = parent_rate / rate; ++ unsigned int load_level; ++ ++ /* only available when DVFS is enabled */ ++ if (!armada_3700_pm_dvfs_is_enabled(base)) ++ return -EINVAL; ++ ++ for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) { ++ unsigned int reg, mask, val, ++ offset = ARMADA_37XX_NB_TBG_DIV_OFF; ++ ++ armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); ++ ++ regmap_read(base, reg, &val); ++ val >>= offset; ++ val &= ARMADA_37XX_NB_TBG_DIV_MASK; ++ ++ if (val == div) { ++ /* ++ * We found a load level matching the target ++ * divider, switch to this load level and ++ * return. ++ */ ++ reg = ARMADA_37XX_NB_CPU_LOAD; ++ mask = ARMADA_37XX_NB_CPU_LOAD_MASK; ++ regmap_update_bits(base, reg, mask, load_level); ++ ++ return rate; ++ } ++ } ++ ++ /* We didn't find any valid divider */ ++ return -EINVAL; ++} ++ + static const struct clk_ops clk_pm_cpu_ops = { + .get_parent = clk_pm_cpu_get_parent, ++ .set_parent = clk_pm_cpu_set_parent, ++ .round_rate = clk_pm_cpu_round_rate, ++ .set_rate = clk_pm_cpu_set_rate, + .recalc_rate = clk_pm_cpu_recalc_rate, + }; + +@@ -409,6 +617,7 @@ static int armada_3700_add_composite_clk + if (data->muxrate_hw) { + struct clk_pm_cpu *pmcpu_clk; + struct clk_hw *muxrate_hw = data->muxrate_hw; ++ struct regmap *map; + + pmcpu_clk = to_clk_pm_cpu(muxrate_hw); + pmcpu_clk->reg_mux = reg + (u64)pmcpu_clk->reg_mux; +@@ -418,6 +627,10 @@ static int armada_3700_add_composite_clk + rate_hw = muxrate_hw; + mux_ops = muxrate_hw->init->ops; + rate_ops = muxrate_hw->init->ops; ++ ++ map = syscon_regmap_lookup_by_compatible( ++ "marvell,armada-3700-nb-pm"); ++ pmcpu_clk->nb_pm_base = map; + } + + *hw = clk_hw_register_composite(dev, data->name, data->parent_names, diff --git a/target/linux/mvebu/patches-4.14/503-cpufreq-Add-DVFS-support-for-Armada-37xx.patch b/target/linux/mvebu/patches-4.14/503-cpufreq-Add-DVFS-support-for-Armada-37xx.patch new file mode 100644 index 0000000000..11562c582b --- /dev/null +++ b/target/linux/mvebu/patches-4.14/503-cpufreq-Add-DVFS-support-for-Armada-37xx.patch @@ -0,0 +1,297 @@ +From 92ce45fb875d7c3e021cc454482fe0687ff54f29 Mon Sep 17 00:00:00 2001 +From: Gregory CLEMENT +Date: Thu, 14 Dec 2017 16:00:05 +0100 +Subject: cpufreq: Add DVFS support for Armada 37xx + +This patch adds DVFS support for the Armada 37xx SoCs + +There are up to four CPU frequency loads for Armada 37xx controlled by +the hardware. + +This driver associates the CPU load level to a frequency, then the +hardware will switch while selecting a load level. + +The hardware also can associate a voltage for each level (AVS support) +but it is not yet supported + +Tested-by: Andre Heider +Acked-by: Viresh Kumar +Signed-off-by: Gregory CLEMENT +Signed-off-by: Rafael J. Wysocki +--- + drivers/cpufreq/Kconfig.arm | 7 + + drivers/cpufreq/Makefile | 1 + + drivers/cpufreq/armada-37xx-cpufreq.c | 241 ++++++++++++++++++++++++++++++++++ + 3 files changed, 249 insertions(+) + create mode 100644 drivers/cpufreq/armada-37xx-cpufreq.c + +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -2,6 +2,13 @@ + # ARM CPU Frequency scaling drivers + # + ++config ARM_ARMADA_37XX_CPUFREQ ++ tristate "Armada 37xx CPUFreq support" ++ depends on ARCH_MVEBU ++ help ++ This adds the CPUFreq driver support for Marvell Armada 37xx SoCs. ++ The Armada 37xx PMU supports 4 frequency and VDD levels. ++ + # big LITTLE core layer and glue drivers + config ARM_BIG_LITTLE_CPUFREQ + tristate "Generic ARM big LITTLE CPUfreq driver" +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -52,6 +52,7 @@ obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += + # LITTLE drivers, so that it is probed last. + obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o + ++obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o + obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o + obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o + obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o +--- /dev/null ++++ b/drivers/cpufreq/armada-37xx-cpufreq.c +@@ -0,0 +1,241 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * CPU frequency scaling support for Armada 37xx platform. ++ * ++ * Copyright (C) 2017 Marvell ++ * ++ * Gregory CLEMENT ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Power management in North Bridge register set */ ++#define ARMADA_37XX_NB_L0L1 0x18 ++#define ARMADA_37XX_NB_L2L3 0x1C ++#define ARMADA_37XX_NB_TBG_DIV_OFF 13 ++#define ARMADA_37XX_NB_TBG_DIV_MASK 0x7 ++#define ARMADA_37XX_NB_CLK_SEL_OFF 11 ++#define ARMADA_37XX_NB_CLK_SEL_MASK 0x1 ++#define ARMADA_37XX_NB_CLK_SEL_TBG 0x1 ++#define ARMADA_37XX_NB_TBG_SEL_OFF 9 ++#define ARMADA_37XX_NB_TBG_SEL_MASK 0x3 ++#define ARMADA_37XX_NB_VDD_SEL_OFF 6 ++#define ARMADA_37XX_NB_VDD_SEL_MASK 0x3 ++#define ARMADA_37XX_NB_CONFIG_SHIFT 16 ++#define ARMADA_37XX_NB_DYN_MOD 0x24 ++#define ARMADA_37XX_NB_CLK_SEL_EN BIT(26) ++#define ARMADA_37XX_NB_TBG_EN BIT(28) ++#define ARMADA_37XX_NB_DIV_EN BIT(29) ++#define ARMADA_37XX_NB_VDD_EN BIT(30) ++#define ARMADA_37XX_NB_DFS_EN BIT(31) ++#define ARMADA_37XX_NB_CPU_LOAD 0x30 ++#define ARMADA_37XX_NB_CPU_LOAD_MASK 0x3 ++#define ARMADA_37XX_DVFS_LOAD_0 0 ++#define ARMADA_37XX_DVFS_LOAD_1 1 ++#define ARMADA_37XX_DVFS_LOAD_2 2 ++#define ARMADA_37XX_DVFS_LOAD_3 3 ++ ++/* ++ * On Armada 37xx the Power management manages 4 level of CPU load, ++ * each level can be associated with a CPU clock source, a CPU ++ * divider, a VDD level, etc... ++ */ ++#define LOAD_LEVEL_NR 4 ++ ++struct armada_37xx_dvfs { ++ u32 cpu_freq_max; ++ u8 divider[LOAD_LEVEL_NR]; ++}; ++ ++static struct armada_37xx_dvfs armada_37xx_dvfs[] = { ++ {.cpu_freq_max = 1200*1000*1000, .divider = {1, 2, 4, 6} }, ++ {.cpu_freq_max = 1000*1000*1000, .divider = {1, 2, 4, 5} }, ++ {.cpu_freq_max = 800*1000*1000, .divider = {1, 2, 3, 4} }, ++ {.cpu_freq_max = 600*1000*1000, .divider = {2, 4, 5, 6} }, ++}; ++ ++static struct armada_37xx_dvfs *armada_37xx_cpu_freq_info_get(u32 freq) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(armada_37xx_dvfs); i++) { ++ if (freq == armada_37xx_dvfs[i].cpu_freq_max) ++ return &armada_37xx_dvfs[i]; ++ } ++ ++ pr_err("Unsupported CPU frequency %d MHz\n", freq/1000000); ++ return NULL; ++} ++ ++/* ++ * Setup the four level managed by the hardware. Once the four level ++ * will be configured then the DVFS will be enabled. ++ */ ++static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, ++ struct clk *clk, u8 *divider) ++{ ++ int load_lvl; ++ struct clk *parent; ++ ++ for (load_lvl = 0; load_lvl < LOAD_LEVEL_NR; load_lvl++) { ++ unsigned int reg, mask, val, offset = 0; ++ ++ if (load_lvl <= ARMADA_37XX_DVFS_LOAD_1) ++ reg = ARMADA_37XX_NB_L0L1; ++ else ++ reg = ARMADA_37XX_NB_L2L3; ++ ++ if (load_lvl == ARMADA_37XX_DVFS_LOAD_0 || ++ load_lvl == ARMADA_37XX_DVFS_LOAD_2) ++ offset += ARMADA_37XX_NB_CONFIG_SHIFT; ++ ++ /* Set cpu clock source, for all the level we use TBG */ ++ val = ARMADA_37XX_NB_CLK_SEL_TBG << ARMADA_37XX_NB_CLK_SEL_OFF; ++ mask = (ARMADA_37XX_NB_CLK_SEL_MASK ++ << ARMADA_37XX_NB_CLK_SEL_OFF); ++ ++ /* ++ * Set cpu divider based on the pre-computed array in ++ * order to have balanced step. ++ */ ++ val |= divider[load_lvl] << ARMADA_37XX_NB_TBG_DIV_OFF; ++ mask |= (ARMADA_37XX_NB_TBG_DIV_MASK ++ << ARMADA_37XX_NB_TBG_DIV_OFF); ++ ++ /* Set VDD divider which is actually the load level. */ ++ val |= load_lvl << ARMADA_37XX_NB_VDD_SEL_OFF; ++ mask |= (ARMADA_37XX_NB_VDD_SEL_MASK ++ << ARMADA_37XX_NB_VDD_SEL_OFF); ++ ++ val <<= offset; ++ mask <<= offset; ++ ++ regmap_update_bits(base, reg, mask, val); ++ } ++ ++ /* ++ * Set cpu clock source, for all the level we keep the same ++ * clock source that the one already configured. For this one ++ * we need to use the clock framework ++ */ ++ parent = clk_get_parent(clk); ++ clk_set_parent(clk, parent); ++} ++ ++static void __init armada37xx_cpufreq_disable_dvfs(struct regmap *base) ++{ ++ unsigned int reg = ARMADA_37XX_NB_DYN_MOD, ++ mask = ARMADA_37XX_NB_DFS_EN; ++ ++ regmap_update_bits(base, reg, mask, 0); ++} ++ ++static void __init armada37xx_cpufreq_enable_dvfs(struct regmap *base) ++{ ++ unsigned int val, reg = ARMADA_37XX_NB_CPU_LOAD, ++ mask = ARMADA_37XX_NB_CPU_LOAD_MASK; ++ ++ /* Start with the highest load (0) */ ++ val = ARMADA_37XX_DVFS_LOAD_0; ++ regmap_update_bits(base, reg, mask, val); ++ ++ /* Now enable DVFS for the CPUs */ ++ reg = ARMADA_37XX_NB_DYN_MOD; ++ mask = ARMADA_37XX_NB_CLK_SEL_EN | ARMADA_37XX_NB_TBG_EN | ++ ARMADA_37XX_NB_DIV_EN | ARMADA_37XX_NB_VDD_EN | ++ ARMADA_37XX_NB_DFS_EN; ++ ++ regmap_update_bits(base, reg, mask, mask); ++} ++ ++static int __init armada37xx_cpufreq_driver_init(void) ++{ ++ struct armada_37xx_dvfs *dvfs; ++ struct platform_device *pdev; ++ unsigned int cur_frequency; ++ struct regmap *nb_pm_base; ++ struct device *cpu_dev; ++ int load_lvl, ret; ++ struct clk *clk; ++ ++ nb_pm_base = ++ syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm"); ++ ++ if (IS_ERR(nb_pm_base)) ++ return -ENODEV; ++ ++ /* Before doing any configuration on the DVFS first, disable it */ ++ armada37xx_cpufreq_disable_dvfs(nb_pm_base); ++ ++ /* ++ * On CPU 0 register the operating points supported (which are ++ * the nominal CPU frequency and full integer divisions of ++ * it). ++ */ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ dev_err(cpu_dev, "Cannot get CPU\n"); ++ return -ENODEV; ++ } ++ ++ clk = clk_get(cpu_dev, 0); ++ if (IS_ERR(clk)) { ++ dev_err(cpu_dev, "Cannot get clock for CPU0\n"); ++ return PTR_ERR(clk); ++ } ++ ++ /* Get nominal (current) CPU frequency */ ++ cur_frequency = clk_get_rate(clk); ++ if (!cur_frequency) { ++ dev_err(cpu_dev, "Failed to get clock rate for CPU\n"); ++ return -EINVAL; ++ } ++ ++ dvfs = armada_37xx_cpu_freq_info_get(cur_frequency); ++ if (!dvfs) ++ return -EINVAL; ++ ++ armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider); ++ ++ for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; ++ load_lvl++) { ++ unsigned long freq = cur_frequency / dvfs->divider[load_lvl]; ++ ++ ret = dev_pm_opp_add(cpu_dev, freq, 0); ++ if (ret) { ++ /* clean-up the already added opp before leaving */ ++ while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) { ++ freq = cur_frequency / dvfs->divider[load_lvl]; ++ dev_pm_opp_remove(cpu_dev, freq); ++ } ++ return ret; ++ } ++ } ++ ++ /* Now that everything is setup, enable the DVFS at hardware level */ ++ armada37xx_cpufreq_enable_dvfs(nb_pm_base); ++ ++ pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0); ++ ++ return PTR_ERR_OR_ZERO(pdev); ++} ++/* late_initcall, to guarantee the driver is loaded after A37xx clock driver */ ++late_initcall(armada37xx_cpufreq_driver_init); ++ ++MODULE_AUTHOR("Gregory CLEMENT "); ++MODULE_DESCRIPTION("Armada 37xx cpufreq driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/mvebu/patches-4.14/504-spi-a3700-Change-SPI-mode-before-asserting-chip-sele.patch b/target/linux/mvebu/patches-4.14/504-spi-a3700-Change-SPI-mode-before-asserting-chip-sele.patch new file mode 100644 index 0000000000..3ac7091188 --- /dev/null +++ b/target/linux/mvebu/patches-4.14/504-spi-a3700-Change-SPI-mode-before-asserting-chip-sele.patch @@ -0,0 +1,70 @@ +From dd7aa8d4b53b3484ba31ba56f3ff1be7deb38530 Mon Sep 17 00:00:00 2001 +From: Maxime Chevallier +Date: Tue, 10 Oct 2017 10:43:18 +0200 +Subject: spi: a3700: Change SPI mode before asserting chip-select + +The spi device mode should be configured in the controller before the +chip-select is asserted, so that a clock polarity configuration change +is not interpreted as a clock tick by the device. + +This patch moves the mode setting to the 'prepare_message' function +instead of the 'transfer_one' function. + +By doing so, this patch also removes redundant code in +a3700_spi_clock_set. + +This was tested on EspressoBin board, with spidev. + +Signed-off-by: Maxime Chevallier +Signed-off-by: Mark Brown +--- + drivers/spi/spi-armada-3700.c | 17 ++++------------- + 1 file changed, 4 insertions(+), 13 deletions(-) + +--- a/drivers/spi/spi-armada-3700.c ++++ b/drivers/spi/spi-armada-3700.c +@@ -214,7 +214,7 @@ static void a3700_spi_mode_set(struct a3 + } + + static void a3700_spi_clock_set(struct a3700_spi *a3700_spi, +- unsigned int speed_hz, u16 mode) ++ unsigned int speed_hz) + { + u32 val; + u32 prescale; +@@ -239,17 +239,6 @@ static void a3700_spi_clock_set(struct a + val |= A3700_SPI_CLK_CAPT_EDGE; + spireg_write(a3700_spi, A3700_SPI_IF_TIME_REG, val); + } +- +- val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); +- val &= ~(A3700_SPI_CLK_POL | A3700_SPI_CLK_PHA); +- +- if (mode & SPI_CPOL) +- val |= A3700_SPI_CLK_POL; +- +- if (mode & SPI_CPHA) +- val |= A3700_SPI_CLK_PHA; +- +- spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); + } + + static void a3700_spi_bytelen_set(struct a3700_spi *a3700_spi, unsigned int len) +@@ -431,7 +420,7 @@ static void a3700_spi_transfer_setup(str + + a3700_spi = spi_master_get_devdata(spi->master); + +- a3700_spi_clock_set(a3700_spi, xfer->speed_hz, spi->mode); ++ a3700_spi_clock_set(a3700_spi, xfer->speed_hz); + + byte_len = xfer->bits_per_word >> 3; + +@@ -592,6 +581,8 @@ static int a3700_spi_prepare_message(str + + a3700_spi_bytelen_set(a3700_spi, 4); + ++ a3700_spi_mode_set(a3700_spi, spi->mode); ++ + return 0; + } + diff --git a/target/linux/mvebu/patches-4.14/505-arm64-dts-marvell-Fix-A37xx-UART0-register-size.patch b/target/linux/mvebu/patches-4.14/505-arm64-dts-marvell-Fix-A37xx-UART0-register-size.patch new file mode 100644 index 0000000000..9e2b1c14eb --- /dev/null +++ b/target/linux/mvebu/patches-4.14/505-arm64-dts-marvell-Fix-A37xx-UART0-register-size.patch @@ -0,0 +1,39 @@ +From c737abc193d16e62e23e2fb585b8b7398ab380d8 Mon Sep 17 00:00:00 2001 +From: allen yan +Date: Thu, 7 Sep 2017 15:04:53 +0200 +Subject: arm64: dts: marvell: Fix A37xx UART0 register size + +Armada-37xx UART0 registers are 0x200 bytes wide. Right next to them are +the UART1 registers that should not be declared in this node. + +Update the example in DT bindings document accordingly. + +Signed-off-by: allen yan +Signed-off-by: Miquel Raynal +Signed-off-by: Gregory CLEMENT +--- + Documentation/devicetree/bindings/serial/mvebu-uart.txt | 2 +- + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt ++++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt +@@ -8,6 +8,6 @@ Required properties: + Example: + serial@12000 { + compatible = "marvell,armada-3700-uart"; +- reg = <0x12000 0x400>; ++ reg = <0x12000 0x200>; + interrupts = <43>; + }; +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -134,7 +134,7 @@ + + uart0: serial@12000 { + compatible = "marvell,armada-3700-uart"; +- reg = <0x12000 0x400>; ++ reg = <0x12000 0x200>; + interrupts = ; + status = "disabled"; + }; diff --git a/target/linux/mvebu/patches-4.14/506-arm64-dts-marvell-armada-37xx-add-UART-clock.patch b/target/linux/mvebu/patches-4.14/506-arm64-dts-marvell-armada-37xx-add-UART-clock.patch new file mode 100644 index 0000000000..47e0751c5f --- /dev/null +++ b/target/linux/mvebu/patches-4.14/506-arm64-dts-marvell-armada-37xx-add-UART-clock.patch @@ -0,0 +1,27 @@ +From 2ff0d0b5bb397c3dc5c9b97bd0f20948f0b77740 Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Fri, 13 Oct 2017 11:01:57 +0200 +Subject: arm64: dts: marvell: armada-37xx: add UART clock + +Add the missing clock property to armada-3700 UART node. + +This clock will be used to derive the prescaler value to comply with +the requested baudrate. + +Signed-off-by: Miquel Raynal +Acked-by: Gregory CLEMENT +Signed-off-by: Gregory CLEMENT +--- + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -135,6 +135,7 @@ + uart0: serial@12000 { + compatible = "marvell,armada-3700-uart"; + reg = <0x12000 0x200>; ++ clocks = <&xtalclk>; + interrupts = ; + status = "disabled"; + }; diff --git a/target/linux/mvebu/patches-4.14/507-arm64-dts-marvell-armada-37xx-add-nodes-allowing-cpu.patch b/target/linux/mvebu/patches-4.14/507-arm64-dts-marvell-armada-37xx-add-nodes-allowing-cpu.patch new file mode 100644 index 0000000000..dd3727c554 --- /dev/null +++ b/target/linux/mvebu/patches-4.14/507-arm64-dts-marvell-armada-37xx-add-nodes-allowing-cpu.patch @@ -0,0 +1,48 @@ +From e8d66e7927b2a15310df0eb44a67d120ea147a59 Mon Sep 17 00:00:00 2001 +From: Gregory CLEMENT +Date: Thu, 14 Dec 2017 16:00:06 +0100 +Subject: arm64: dts: marvell: armada-37xx: add nodes allowing cpufreq + support + +In order to be able to use cpu freq, we need to associate a clock to each +CPU and to expose the power management registers. + +Signed-off-by: Gregory CLEMENT +--- + arch/arm64/boot/dts/marvell/armada-372x.dtsi | 1 + + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 7 +++++++ + 2 files changed, 8 insertions(+) + +--- a/arch/arm64/boot/dts/marvell/armada-372x.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-372x.dtsi +@@ -56,6 +56,7 @@ + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x1>; ++ clocks = <&nb_periph_clk 16>; + enable-method = "psci"; + }; + }; +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -64,6 +64,7 @@ + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0>; ++ clocks = <&nb_periph_clk 16>; + enable-method = "psci"; + }; + }; +@@ -219,6 +220,12 @@ + }; + }; + ++ nb_pm: syscon@14000 { ++ compatible = "marvell,armada-3700-nb-pm", ++ "syscon"; ++ reg = <0x14000 0x60>; ++ }; ++ + pinctrl_sb: pinctrl@18800 { + compatible = "marvell,armada3710-sb-pinctrl", + "syscon", "simple-mfd"; diff --git a/target/linux/mvebu/patches-4.14/520-arm64-dts-marvell-armada37xx-Add-eth0-alias.patch b/target/linux/mvebu/patches-4.14/520-arm64-dts-marvell-armada37xx-Add-eth0-alias.patch new file mode 100644 index 0000000000..206caf2fce --- /dev/null +++ b/target/linux/mvebu/patches-4.14/520-arm64-dts-marvell-armada37xx-Add-eth0-alias.patch @@ -0,0 +1,20 @@ +From be893f672e340b56ca60f2f6c32fdd713a5852f5 Mon Sep 17 00:00:00 2001 +From: Kevin Mihelich +Date: Tue, 4 Jul 2017 19:25:28 -0600 +Subject: arm64: dts: marvell: armada37xx: Add eth0 alias + +Signed-off-by: Kevin Mihelich +--- + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -54,6 +54,7 @@ + #size-cells = <2>; + + aliases { ++ ethernet0 = ð0; + serial0 = &uart0; + }; + diff --git a/target/linux/mvebu/patches-4.14/521-esporessobin-dt-enable-spi-nor-on-i2c.patch b/target/linux/mvebu/patches-4.14/521-esporessobin-dt-enable-spi-nor-on-i2c.patch new file mode 100644 index 0000000000..3cabaa7a01 --- /dev/null +++ b/target/linux/mvebu/patches-4.14/521-esporessobin-dt-enable-spi-nor-on-i2c.patch @@ -0,0 +1,29 @@ +--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts ++++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts +@@ -111,6 +111,26 @@ + status = "okay"; + }; + ++&spi0 { ++ status = "okay"; ++ ++ w25q32dw@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ spi-max-frequency = <104000000>; ++ m25,fast-read; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi_quad_pins>; ++ }; ++}; ++ ++&i2c0 { ++ status = "okay"; ++}; ++ + &mdio { + switch0: switch0@1 { + compatible = "marvell,mv88e6085"; diff --git a/target/linux/mvebu/patches-4.14/522-PCI-aardvark-fix-logic-in-PCI-configuration-read-write-functions.patch b/target/linux/mvebu/patches-4.14/522-PCI-aardvark-fix-logic-in-PCI-configuration-read-write-functions.patch new file mode 100644 index 0000000000..0dead7d61d --- /dev/null +++ b/target/linux/mvebu/patches-4.14/522-PCI-aardvark-fix-logic-in-PCI-configuration-read-write-functions.patch @@ -0,0 +1,66 @@ +From patchwork Thu Sep 28 12:58:32 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v2, 1/7] PCI: aardvark: fix logic in PCI configuration read/write + functions +X-Patchwork-Submitter: Thomas Petazzoni +X-Patchwork-Id: 819586 +Message-Id: <20170928125838.11887-2-thomas.petazzoni@free-electrons.com> +To: Bjorn Helgaas , linux-pci@vger.kernel.org +Cc: Jason Cooper , Andrew Lunn , + Sebastian Hesselbarth , Gregory Clement + , + Nadav Haklai , Hanna Hawa , + Yehuda Yitschak , + linux-arm-kernel@lists.infradead.org, Antoine Tenart + , =?utf-8?q?Miqu=C3=A8l_Raynal?= + , Victor Gu , + stable@vger.kernel.org, Thomas Petazzoni + +Date: Thu, 28 Sep 2017 14:58:32 +0200 +From: Thomas Petazzoni +List-Id: + +From: Victor Gu + +The PCI configuration space read/write functions were special casing +the situation where PCI_SLOT(devfn) != 0, and returned +PCIBIOS_DEVICE_NOT_FOUND in this case. + +However, will this is what is intended for the root bus, it is not +intended for the child busses, as it prevents discovering devices with +PCI_SLOT(x) != 0. Therefore, we return PCIBIOS_DEVICE_NOT_FOUND only +if we're on the root bus. + +Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") +Cc: +Signed-off-by: Victor Gu +Reviewed-by: Wilson Ding +Reviewed-by: Nadav Haklai +[Thomas: tweak commit log.] +Signed-off-by: Thomas Petazzoni +--- + drivers/pci/host/pci-aardvark.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/pci/host/pci-aardvark.c ++++ b/drivers/pci/host/pci-aardvark.c +@@ -440,7 +440,7 @@ static int advk_pcie_rd_conf(struct pci_ + u32 reg; + int ret; + +- if (PCI_SLOT(devfn) != 0) { ++ if ((bus->number == pcie->root_bus_nr) && (PCI_SLOT(devfn) != 0)) { + *val = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } +@@ -494,7 +494,7 @@ static int advk_pcie_wr_conf(struct pci_ + int offset; + int ret; + +- if (PCI_SLOT(devfn) != 0) ++ if ((bus->number == pcie->root_bus_nr) && (PCI_SLOT(devfn) != 0)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (where % size) diff --git a/target/linux/mvebu/patches-4.14/523-PCI-aardvark-set-PIO_ADDR_LS-correctly-in-advk_pcie_rd_conf.patch b/target/linux/mvebu/patches-4.14/523-PCI-aardvark-set-PIO_ADDR_LS-correctly-in-advk_pcie_rd_conf.patch new file mode 100644 index 0000000000..238eb56269 --- /dev/null +++ b/target/linux/mvebu/patches-4.14/523-PCI-aardvark-set-PIO_ADDR_LS-correctly-in-advk_pcie_rd_conf.patch @@ -0,0 +1,53 @@ +From patchwork Thu Sep 28 12:58:33 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v2, + 2/7] PCI: aardvark: set PIO_ADDR_LS correctly in advk_pcie_rd_conf() +X-Patchwork-Submitter: Thomas Petazzoni +X-Patchwork-Id: 819589 +Message-Id: <20170928125838.11887-3-thomas.petazzoni@free-electrons.com> +To: Bjorn Helgaas , linux-pci@vger.kernel.org +Cc: Jason Cooper , Andrew Lunn , + Sebastian Hesselbarth , Gregory Clement + , + Nadav Haklai , Hanna Hawa , + Yehuda Yitschak , + linux-arm-kernel@lists.infradead.org, Antoine Tenart + , =?utf-8?q?Miqu=C3=A8l_Raynal?= + , Victor Gu , + stable@vger.kernel.org, Thomas Petazzoni + +Date: Thu, 28 Sep 2017 14:58:33 +0200 +From: Thomas Petazzoni +List-Id: + +From: Victor Gu + +When setting the PIO_ADDR_LS register during a configuration read, we +were properly passing the device number, function number and register +number, but not the bus number, causing issues when reading the +configuration of PCIe devices. + +Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") +Cc: +Signed-off-by: Victor Gu +Reviewed-by: Wilson Ding +Reviewed-by: Nadav Haklai +[Thomas: tweak commit log.] +Signed-off-by: Thomas Petazzoni +--- + drivers/pci/host/pci-aardvark.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pci/host/pci-aardvark.c ++++ b/drivers/pci/host/pci-aardvark.c +@@ -459,7 +459,7 @@ static int advk_pcie_rd_conf(struct pci_ + advk_writel(pcie, reg, PIO_CTRL); + + /* Program the address registers */ +- reg = PCIE_BDF(devfn) | PCIE_CONF_REG(where); ++ reg = PCIE_CONF_ADDR(bus->number, devfn, where); + advk_writel(pcie, reg, PIO_ADDR_LS); + advk_writel(pcie, 0, PIO_ADDR_MS); + diff --git a/target/linux/mvebu/patches-4.14/524-PCI-aardvark-set-host-and-device-to-the-same-MAX-payload-size.patch b/target/linux/mvebu/patches-4.14/524-PCI-aardvark-set-host-and-device-to-the-same-MAX-payload-size.patch new file mode 100644 index 0000000000..f7e71aa060 --- /dev/null +++ b/target/linux/mvebu/patches-4.14/524-PCI-aardvark-set-host-and-device-to-the-same-MAX-payload-size.patch @@ -0,0 +1,137 @@ +From patchwork Thu Sep 28 12:58:34 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v2, + 3/7] PCI: aardvark: set host and device to the same MAX payload size +X-Patchwork-Submitter: Thomas Petazzoni +X-Patchwork-Id: 819587 +Message-Id: <20170928125838.11887-4-thomas.petazzoni@free-electrons.com> +To: Bjorn Helgaas , linux-pci@vger.kernel.org +Cc: Jason Cooper , Andrew Lunn , + Sebastian Hesselbarth , Gregory Clement + , + Nadav Haklai , Hanna Hawa , + Yehuda Yitschak , + linux-arm-kernel@lists.infradead.org, Antoine Tenart + , =?utf-8?q?Miqu=C3=A8l_Raynal?= + , Victor Gu , + Thomas Petazzoni +Date: Thu, 28 Sep 2017 14:58:34 +0200 +From: Thomas Petazzoni +List-Id: + +From: Victor Gu + +Since the Aardvark does not implement a PCIe root bus, the Linux PCIe +subsystem will not align the MAX payload size between the host and the +device. This patch ensures that the host and device have the same MAX +payload size, fixing a number of problems with various PCIe devices. + +This is part of fixing bug +https://bugzilla.kernel.org/show_bug.cgi?id=196339, this commit was +reported as the user to be important to get a Intel 7260 mini-PCIe +WiFi card working. + +Fixes: Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") +Signed-off-by: Victor Gu +Reviewed-by: Evan Wang +Reviewed-by: Nadav Haklai +[Thomas: tweak commit log.] +Signed-off-by: Thomas Petazzoni +--- + drivers/pci/host/pci-aardvark.c | 60 ++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 59 insertions(+), 1 deletion(-) + +--- a/drivers/pci/host/pci-aardvark.c ++++ b/drivers/pci/host/pci-aardvark.c +@@ -30,8 +30,10 @@ + #define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8 + #define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4) + #define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT 5 ++#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ 0x2 + #define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11) + #define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT 12 ++#define PCIE_CORE_MPS_UNIT_BYTE 128 + #define PCIE_CORE_LINK_CTRL_STAT_REG 0xd0 + #define PCIE_CORE_LINK_L0S_ENTRY BIT(0) + #define PCIE_CORE_LINK_TRAINING BIT(5) +@@ -297,7 +299,8 @@ static void advk_pcie_setup_hw(struct ad + + /* Set PCIe Device Control and Status 1 PF0 register */ + reg = PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE | +- (7 << PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT) | ++ (PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ << ++ PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT) | + PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE | + PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT; + advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG); +@@ -879,6 +882,58 @@ out_release_res: + return err; + } + ++static int advk_pcie_find_smpss(struct pci_dev *dev, void *data) ++{ ++ u8 *smpss = data; ++ ++ if (!dev) ++ return 0; ++ ++ if (!pci_is_pcie(dev)) ++ return 0; ++ ++ if (*smpss > dev->pcie_mpss) ++ *smpss = dev->pcie_mpss; ++ ++ return 0; ++} ++ ++static int advk_pcie_bus_configure_mps(struct pci_dev *dev, void *data) ++{ ++ int mps; ++ ++ if (!dev) ++ return 0; ++ ++ if (!pci_is_pcie(dev)) ++ return 0; ++ ++ mps = PCIE_CORE_MPS_UNIT_BYTE << *(u8 *)data; ++ pcie_set_mps(dev, mps); ++ ++ return 0; ++} ++ ++static void advk_pcie_configure_mps(struct pci_bus *bus, struct advk_pcie *pcie) ++{ ++ u8 smpss = PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ; ++ u32 reg; ++ ++ /* Find the minimal supported MAX payload size */ ++ advk_pcie_find_smpss(bus->self, &smpss); ++ pci_walk_bus(bus, advk_pcie_find_smpss, &smpss); ++ ++ /* Configure RC MAX payload size */ ++ reg = advk_readl(pcie, PCIE_CORE_DEV_CTRL_STATS_REG); ++ reg &= ~PCI_EXP_DEVCTL_PAYLOAD; ++ reg |= smpss << PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT; ++ advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG); ++ ++ /* Configure device MAX payload size */ ++ advk_pcie_bus_configure_mps(bus->self, &smpss); ++ pci_walk_bus(bus, advk_pcie_bus_configure_mps, &smpss); ++} ++ + static int advk_pcie_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -952,6 +1007,9 @@ static int advk_pcie_probe(struct platfo + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + ++ /* Configure the MAX pay load size */ ++ advk_pcie_configure_mps(bus, pcie); ++ + pci_bus_add_devices(bus); + return 0; + } diff --git a/target/linux/mvebu/patches-4.14/525-PCI-aardvark-use-isr1-instead-of-isr0-interrupt-in-legacy-irq-mode.patch b/target/linux/mvebu/patches-4.14/525-PCI-aardvark-use-isr1-instead-of-isr0-interrupt-in-legacy-irq-mode.patch new file mode 100644 index 0000000000..777a078ef9 --- /dev/null +++ b/target/linux/mvebu/patches-4.14/525-PCI-aardvark-use-isr1-instead-of-isr0-interrupt-in-legacy-irq-mode.patch @@ -0,0 +1,143 @@ +From patchwork Thu Sep 28 12:58:35 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v2, + 4/7] PCI: aardvark: use isr1 instead of isr0 interrupt in legacy irq + mode +X-Patchwork-Submitter: Thomas Petazzoni +X-Patchwork-Id: 819592 +Message-Id: <20170928125838.11887-5-thomas.petazzoni@free-electrons.com> +To: Bjorn Helgaas , linux-pci@vger.kernel.org +Cc: Jason Cooper , Andrew Lunn , + Sebastian Hesselbarth , Gregory Clement + , + Nadav Haklai , Hanna Hawa , + Yehuda Yitschak , + linux-arm-kernel@lists.infradead.org, Antoine Tenart + , =?utf-8?q?Miqu=C3=A8l_Raynal?= + , Victor Gu , + Thomas Petazzoni +Date: Thu, 28 Sep 2017 14:58:35 +0200 +From: Thomas Petazzoni +List-Id: + +From: Victor Gu + +The Aardvark has two interrupts sets: + + - first set is bit[23:16] of PCIe ISR 0 register(RD0074840h) + + - second set is bit[11:8] of PCIe ISR 1 register(RD0074848h) + +Only one set should be used, while another set should be masked. + +The second set, ISR1, is more advanced, the Legacy INT_X status bit is +asserted once Assert_INTX message is received, and de-asserted after +Deassert_INTX message is received. Therefore, it matches what the +driver is currently doing in the ->irq_mask() and ->irq_unmask() +functions. The ISR0 requires additional work to deassert the +interrupt, which the driver doesn't do currently. + +This commit resolves a number of issues with legacy interrupts. + +This is part of fixing bug +https://bugzilla.kernel.org/show_bug.cgi?id=196339, this commit was +reported as the user to be important to get a Intel 7260 mini-PCIe +WiFi card working. + +Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") +Signed-off-by: Victor Gu +Reviewed-by: Evan Wang +Reviewed-by: Nadav Haklai +[Thomas: tweak commit log.] +Signed-off-by: Thomas Petazzoni +--- + drivers/pci/host/pci-aardvark.c | 41 ++++++++++++++++++++++++----------------- + 1 file changed, 24 insertions(+), 17 deletions(-) + +--- a/drivers/pci/host/pci-aardvark.c ++++ b/drivers/pci/host/pci-aardvark.c +@@ -105,7 +105,8 @@ + #define PCIE_ISR1_MASK_REG (CONTROL_BASE_ADDR + 0x4C) + #define PCIE_ISR1_POWER_STATE_CHANGE BIT(4) + #define PCIE_ISR1_FLUSH BIT(5) +-#define PCIE_ISR1_ALL_MASK GENMASK(5, 4) ++#define PCIE_ISR1_INTX_ASSERT(val) BIT(8 + (val)) ++#define PCIE_ISR1_ALL_MASK GENMASK(11, 4) + #define PCIE_MSI_ADDR_LOW_REG (CONTROL_BASE_ADDR + 0x50) + #define PCIE_MSI_ADDR_HIGH_REG (CONTROL_BASE_ADDR + 0x54) + #define PCIE_MSI_STATUS_REG (CONTROL_BASE_ADDR + 0x58) +@@ -615,9 +616,9 @@ static void advk_pcie_irq_mask(struct ir + irq_hw_number_t hwirq = irqd_to_hwirq(d); + u32 mask; + +- mask = advk_readl(pcie, PCIE_ISR0_MASK_REG); +- mask |= PCIE_ISR0_INTX_ASSERT(hwirq); +- advk_writel(pcie, mask, PCIE_ISR0_MASK_REG); ++ mask = advk_readl(pcie, PCIE_ISR1_MASK_REG); ++ mask |= PCIE_ISR1_INTX_ASSERT(hwirq); ++ advk_writel(pcie, mask, PCIE_ISR1_MASK_REG); + } + + static void advk_pcie_irq_unmask(struct irq_data *d) +@@ -626,9 +627,9 @@ static void advk_pcie_irq_unmask(struct + irq_hw_number_t hwirq = irqd_to_hwirq(d); + u32 mask; + +- mask = advk_readl(pcie, PCIE_ISR0_MASK_REG); +- mask &= ~PCIE_ISR0_INTX_ASSERT(hwirq); +- advk_writel(pcie, mask, PCIE_ISR0_MASK_REG); ++ mask = advk_readl(pcie, PCIE_ISR1_MASK_REG); ++ mask &= ~PCIE_ISR1_INTX_ASSERT(hwirq); ++ advk_writel(pcie, mask, PCIE_ISR1_MASK_REG); + } + + static int advk_pcie_irq_map(struct irq_domain *h, +@@ -771,29 +772,35 @@ static void advk_pcie_handle_msi(struct + + static void advk_pcie_handle_int(struct advk_pcie *pcie) + { +- u32 val, mask, status; ++ u32 isr0_val, isr0_mask, isr0_status; ++ u32 isr1_val, isr1_mask, isr1_status; + int i, virq; + +- val = advk_readl(pcie, PCIE_ISR0_REG); +- mask = advk_readl(pcie, PCIE_ISR0_MASK_REG); +- status = val & ((~mask) & PCIE_ISR0_ALL_MASK); +- +- if (!status) { +- advk_writel(pcie, val, PCIE_ISR0_REG); ++ isr0_val = advk_readl(pcie, PCIE_ISR0_REG); ++ isr0_mask = advk_readl(pcie, PCIE_ISR0_MASK_REG); ++ isr0_status = isr0_val & ((~isr0_mask) & PCIE_ISR0_ALL_MASK); ++ ++ isr1_val = advk_readl(pcie, PCIE_ISR1_REG); ++ isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG); ++ isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK); ++ ++ if (!isr0_status && !isr1_status) { ++ advk_writel(pcie, isr0_val, PCIE_ISR0_REG); ++ advk_writel(pcie, isr1_val, PCIE_ISR1_REG); + return; + } + + /* Process MSI interrupts */ +- if (status & PCIE_ISR0_MSI_INT_PENDING) ++ if (isr0_status & PCIE_ISR0_MSI_INT_PENDING) + advk_pcie_handle_msi(pcie); + + /* Process legacy interrupts */ + for (i = 0; i < PCI_NUM_INTX; i++) { +- if (!(status & PCIE_ISR0_INTX_ASSERT(i))) ++ if (!(isr1_status & PCIE_ISR1_INTX_ASSERT(i))) + continue; + +- advk_writel(pcie, PCIE_ISR0_INTX_ASSERT(i), +- PCIE_ISR0_REG); ++ advk_writel(pcie, PCIE_ISR1_INTX_ASSERT(i), ++ PCIE_ISR1_REG); + + virq = irq_find_mapping(pcie->irq_domain, i); + generic_handle_irq(virq); diff --git a/target/linux/mvebu/patches-4.14/526-PCI-aardvark-disable-LOS-state-by-default.patch b/target/linux/mvebu/patches-4.14/526-PCI-aardvark-disable-LOS-state-by-default.patch new file mode 100644 index 0000000000..0ee4af4e8d --- /dev/null +++ b/target/linux/mvebu/patches-4.14/526-PCI-aardvark-disable-LOS-state-by-default.patch @@ -0,0 +1,55 @@ +From patchwork Thu Sep 28 12:58:36 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v2,5/7] PCI: aardvark: disable LOS state by default +X-Patchwork-Submitter: Thomas Petazzoni +X-Patchwork-Id: 819590 +Message-Id: <20170928125838.11887-6-thomas.petazzoni@free-electrons.com> +To: Bjorn Helgaas , linux-pci@vger.kernel.org +Cc: Jason Cooper , Andrew Lunn , + Sebastian Hesselbarth , Gregory Clement + , + Nadav Haklai , Hanna Hawa , + Yehuda Yitschak , + linux-arm-kernel@lists.infradead.org, Antoine Tenart + , =?utf-8?q?Miqu=C3=A8l_Raynal?= + , Victor Gu , + Thomas Petazzoni +Date: Thu, 28 Sep 2017 14:58:36 +0200 +From: Thomas Petazzoni +List-Id: + +From: Victor Gu + +Some PCIe devices do not support LOS, and will cause timeouts if the +root complex forces the LOS state. This patch disables the LOS state +by default. + +This is part of fixing bug +https://bugzilla.kernel.org/show_bug.cgi?id=196339, this commit was +reported as the user to be important to get a Intel 7260 mini-PCIe +WiFi card working. + +Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") +Signed-off-by: Victor Gu +Reviewed-by: Evan Wang +Reviewed-by: Nadav Haklai +[Thomas: tweak commit log.] +Signed-off-by: Thomas Petazzoni +--- + drivers/pci/host/pci-aardvark.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/pci/host/pci-aardvark.c ++++ b/drivers/pci/host/pci-aardvark.c +@@ -368,8 +368,7 @@ static void advk_pcie_setup_hw(struct ad + + advk_pcie_wait_for_link(pcie); + +- reg = PCIE_CORE_LINK_L0S_ENTRY | +- (1 << PCIE_CORE_LINK_WIDTH_SHIFT); ++ reg = (1 << PCIE_CORE_LINK_WIDTH_SHIFT); + advk_writel(pcie, reg, PCIE_CORE_LINK_CTRL_STAT_REG); + + reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG); diff --git a/target/linux/mvebu/patches-4.14/527-PCI-aardvark-fix-PCIe-max-read-request-size-setting.patch b/target/linux/mvebu/patches-4.14/527-PCI-aardvark-fix-PCIe-max-read-request-size-setting.patch new file mode 100644 index 0000000000..eaf7b097b0 --- /dev/null +++ b/target/linux/mvebu/patches-4.14/527-PCI-aardvark-fix-PCIe-max-read-request-size-setting.patch @@ -0,0 +1,63 @@ +From patchwork Thu Sep 28 12:58:37 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v2,6/7] PCI: aardvark: fix PCIe max read request size setting +X-Patchwork-Submitter: Thomas Petazzoni +X-Patchwork-Id: 819591 +Message-Id: <20170928125838.11887-7-thomas.petazzoni@free-electrons.com> +To: Bjorn Helgaas , linux-pci@vger.kernel.org +Cc: Jason Cooper , Andrew Lunn , + Sebastian Hesselbarth , Gregory Clement + , + Nadav Haklai , Hanna Hawa , + Yehuda Yitschak , + linux-arm-kernel@lists.infradead.org, Antoine Tenart + , =?utf-8?q?Miqu=C3=A8l_Raynal?= + , Evan Wang , + Thomas Petazzoni +Date: Thu, 28 Sep 2017 14:58:37 +0200 +From: Thomas Petazzoni +List-Id: + +From: Evan Wang + +There is an obvious typo issue in the definition of the PCIe maximum +read request size: a bit shift is directly used as a value, while it +should be used to shift the correct value. + +This is part of fixing bug +https://bugzilla.kernel.org/show_bug.cgi?id=196339, this commit was +reported as the user to be important to get a Intel 7260 mini-PCIe +WiFi card working. + +Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") +Signed-off-by: Evan Wang +Reviewed-by: Victor Gu +Reviewed-by: Nadav Haklai +[Thomas: tweak commit log.] +Signed-off-by: Thomas Petazzoni +--- + drivers/pci/host/pci-aardvark.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/pci/host/pci-aardvark.c ++++ b/drivers/pci/host/pci-aardvark.c +@@ -33,6 +33,7 @@ + #define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ 0x2 + #define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11) + #define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT 12 ++#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SZ 0x2 + #define PCIE_CORE_MPS_UNIT_BYTE 128 + #define PCIE_CORE_LINK_CTRL_STAT_REG 0xd0 + #define PCIE_CORE_LINK_L0S_ENTRY BIT(0) +@@ -303,7 +304,8 @@ static void advk_pcie_setup_hw(struct ad + (PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ << + PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT) | + PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE | +- PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT; ++ (PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SZ << ++ PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT); + advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG); + + /* Program PCIe Control 2 to disable strict ordering */