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 <tomek_n@o2.pl>
v19.07.3_mercusys_ac12_duma
Tomasz Maciej Nowak 6 years ago committed by Hauke Mehrtens
parent be3da900cd
commit 584d7c53bd

@ -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 <kaloz@openwrt.org>
KERNEL_PATCHVER:=4.14

@ -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"
;;

@ -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"
;;

@ -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

@ -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

@ -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

@ -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

@ -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))

@ -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

@ -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}

@ -0,0 +1,78 @@
From adf4e289dd7f801c3fe12e0e6b491e11e548cd3d Mon Sep 17 00:00:00 2001
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
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 <gregory.clement@free-electrons.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
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]);

@ -0,0 +1,178 @@
From 9818a7a4fd10f72537cdf2a5ec3402f2c245ea24 Mon Sep 17 00:00:00 2001
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
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 <gregory.clement@free-electrons.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
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,

@ -0,0 +1,315 @@
From 2089dc33ea0e3917465929d4020fbff3d6dbf7f4 Mon Sep 17 00:00:00 2001
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
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 <gregory.clement@free-electrons.com>
[sboyd@codeaurora.org: Grow a local variable for regmap pointer
to keep lines shorter]
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
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 <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#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, &reg, &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, &reg, &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, &reg, &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, &reg, &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, &reg, &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,

@ -0,0 +1,297 @@
From 92ce45fb875d7c3e021cc454482fe0687ff54f29 Mon Sep 17 00:00:00 2001
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
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 <a.heider@gmail.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
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 <gregory.clement@free-electrons.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* 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 <gregory.clement@free-electrons.com>");
+MODULE_DESCRIPTION("Armada 37xx cpufreq driver");
+MODULE_LICENSE("GPL");

@ -0,0 +1,70 @@
From dd7aa8d4b53b3484ba31ba56f3ff1be7deb38530 Mon Sep 17 00:00:00 2001
From: Maxime Chevallier <maxime.chevallier@smile.fr>
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 <maxime.chevallier@smile.fr>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
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;
}

@ -0,0 +1,39 @@
From c737abc193d16e62e23e2fb585b8b7398ab380d8 Mon Sep 17 00:00:00 2001
From: allen yan <yanwei@marvell.com>
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 <yanwei@marvell.com>
Signed-off-by: Miquel Raynal <miquel.raynal@free-electrons.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
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 = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};

@ -0,0 +1,27 @@
From 2ff0d0b5bb397c3dc5c9b97bd0f20948f0b77740 Mon Sep 17 00:00:00 2001
From: Miquel Raynal <miquel.raynal@free-electrons.com>
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 <miquel.raynal@free-electrons.com>
Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
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 = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};

@ -0,0 +1,48 @@
From e8d66e7927b2a15310df0eb44a67d120ea147a59 Mon Sep 17 00:00:00 2001
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
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 <gregory.clement@free-electrons.com>
---
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";

@ -0,0 +1,20 @@
From be893f672e340b56ca60f2f6c32fdd713a5852f5 Mon Sep 17 00:00:00 2001
From: Kevin Mihelich <kevin@archlinuxarm.org>
Date: Tue, 4 Jul 2017 19:25:28 -0600
Subject: arm64: dts: marvell: armada37xx: Add eth0 alias
Signed-off-by: Kevin Mihelich <kevin@archlinuxarm.org>
---
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 = &eth0;
serial0 = &uart0;
};

@ -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";

@ -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 <thomas.petazzoni@free-electrons.com>
X-Patchwork-Id: 819586
Message-Id: <20170928125838.11887-2-thomas.petazzoni@free-electrons.com>
To: Bjorn Helgaas <bhelgaas@google.com>, linux-pci@vger.kernel.org
Cc: Jason Cooper <jason@lakedaemon.net>, Andrew Lunn <andrew@lunn.ch>,
Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>, Gregory Clement
<gregory.clement@free-electrons.com>,
Nadav Haklai <nadavh@marvell.com>, Hanna Hawa <hannah@marvell.com>,
Yehuda Yitschak <yehuday@marvell.com>,
linux-arm-kernel@lists.infradead.org, Antoine Tenart
<antoine.tenart@free-electrons.com>, =?utf-8?q?Miqu=C3=A8l_Raynal?=
<miquel.raynal@free-electrons.com>, Victor Gu <xigu@marvell.com>,
stable@vger.kernel.org, Thomas Petazzoni
<thomas.petazzoni@free-electrons.com>
Date: Thu, 28 Sep 2017 14:58:32 +0200
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
List-Id: <linux-pci.vger.kernel.org>
From: Victor Gu <xigu@marvell.com>
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: <stable@vger.kernel.org>
Signed-off-by: Victor Gu <xigu@marvell.com>
Reviewed-by: Wilson Ding <dingwei@marvell.com>
Reviewed-by: Nadav Haklai <nadavh@marvell.com>
[Thomas: tweak commit log.]
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
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)

@ -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 <thomas.petazzoni@free-electrons.com>
X-Patchwork-Id: 819589
Message-Id: <20170928125838.11887-3-thomas.petazzoni@free-electrons.com>
To: Bjorn Helgaas <bhelgaas@google.com>, linux-pci@vger.kernel.org
Cc: Jason Cooper <jason@lakedaemon.net>, Andrew Lunn <andrew@lunn.ch>,
Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>, Gregory Clement
<gregory.clement@free-electrons.com>,
Nadav Haklai <nadavh@marvell.com>, Hanna Hawa <hannah@marvell.com>,
Yehuda Yitschak <yehuday@marvell.com>,
linux-arm-kernel@lists.infradead.org, Antoine Tenart
<antoine.tenart@free-electrons.com>, =?utf-8?q?Miqu=C3=A8l_Raynal?=
<miquel.raynal@free-electrons.com>, Victor Gu <xigu@marvell.com>,
stable@vger.kernel.org, Thomas Petazzoni
<thomas.petazzoni@free-electrons.com>
Date: Thu, 28 Sep 2017 14:58:33 +0200
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
List-Id: <linux-pci.vger.kernel.org>
From: Victor Gu <xigu@marvell.com>
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: <stable@vger.kernel.org>
Signed-off-by: Victor Gu <xigu@marvell.com>
Reviewed-by: Wilson Ding <dingwei@marvell.com>
Reviewed-by: Nadav Haklai <nadavh@marvell.com>
[Thomas: tweak commit log.]
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
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);

@ -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 <thomas.petazzoni@free-electrons.com>
X-Patchwork-Id: 819587
Message-Id: <20170928125838.11887-4-thomas.petazzoni@free-electrons.com>
To: Bjorn Helgaas <bhelgaas@google.com>, linux-pci@vger.kernel.org
Cc: Jason Cooper <jason@lakedaemon.net>, Andrew Lunn <andrew@lunn.ch>,
Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>, Gregory Clement
<gregory.clement@free-electrons.com>,
Nadav Haklai <nadavh@marvell.com>, Hanna Hawa <hannah@marvell.com>,
Yehuda Yitschak <yehuday@marvell.com>,
linux-arm-kernel@lists.infradead.org, Antoine Tenart
<antoine.tenart@free-electrons.com>, =?utf-8?q?Miqu=C3=A8l_Raynal?=
<miquel.raynal@free-electrons.com>, Victor Gu <xigu@marvell.com>,
Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Date: Thu, 28 Sep 2017 14:58:34 +0200
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
List-Id: <linux-pci.vger.kernel.org>
From: Victor Gu <xigu@marvell.com>
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 <xigu@marvell.com>
Reviewed-by: Evan Wang <xswang@marvell.com>
Reviewed-by: Nadav Haklai <nadavh@marvell.com>
[Thomas: tweak commit log.]
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
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;
}

@ -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 <thomas.petazzoni@free-electrons.com>
X-Patchwork-Id: 819592
Message-Id: <20170928125838.11887-5-thomas.petazzoni@free-electrons.com>
To: Bjorn Helgaas <bhelgaas@google.com>, linux-pci@vger.kernel.org
Cc: Jason Cooper <jason@lakedaemon.net>, Andrew Lunn <andrew@lunn.ch>,
Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>, Gregory Clement
<gregory.clement@free-electrons.com>,
Nadav Haklai <nadavh@marvell.com>, Hanna Hawa <hannah@marvell.com>,
Yehuda Yitschak <yehuday@marvell.com>,
linux-arm-kernel@lists.infradead.org, Antoine Tenart
<antoine.tenart@free-electrons.com>, =?utf-8?q?Miqu=C3=A8l_Raynal?=
<miquel.raynal@free-electrons.com>, Victor Gu <xigu@marvell.com>,
Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Date: Thu, 28 Sep 2017 14:58:35 +0200
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
List-Id: <linux-pci.vger.kernel.org>
From: Victor Gu <xigu@marvell.com>
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 <xigu@marvell.com>
Reviewed-by: Evan Wang <xswang@marvell.com>
Reviewed-by: Nadav Haklai <nadavh@marvell.com>
[Thomas: tweak commit log.]
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
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);

@ -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 <thomas.petazzoni@free-electrons.com>
X-Patchwork-Id: 819590
Message-Id: <20170928125838.11887-6-thomas.petazzoni@free-electrons.com>
To: Bjorn Helgaas <bhelgaas@google.com>, linux-pci@vger.kernel.org
Cc: Jason Cooper <jason@lakedaemon.net>, Andrew Lunn <andrew@lunn.ch>,
Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>, Gregory Clement
<gregory.clement@free-electrons.com>,
Nadav Haklai <nadavh@marvell.com>, Hanna Hawa <hannah@marvell.com>,
Yehuda Yitschak <yehuday@marvell.com>,
linux-arm-kernel@lists.infradead.org, Antoine Tenart
<antoine.tenart@free-electrons.com>, =?utf-8?q?Miqu=C3=A8l_Raynal?=
<miquel.raynal@free-electrons.com>, Victor Gu <xigu@marvell.com>,
Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Date: Thu, 28 Sep 2017 14:58:36 +0200
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
List-Id: <linux-pci.vger.kernel.org>
From: Victor Gu <xigu@marvell.com>
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 <xigu@marvell.com>
Reviewed-by: Evan Wang <xswang@marvell.com>
Reviewed-by: Nadav Haklai <nadavh@marvell.com>
[Thomas: tweak commit log.]
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
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);

@ -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 <thomas.petazzoni@free-electrons.com>
X-Patchwork-Id: 819591
Message-Id: <20170928125838.11887-7-thomas.petazzoni@free-electrons.com>
To: Bjorn Helgaas <bhelgaas@google.com>, linux-pci@vger.kernel.org
Cc: Jason Cooper <jason@lakedaemon.net>, Andrew Lunn <andrew@lunn.ch>,
Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>, Gregory Clement
<gregory.clement@free-electrons.com>,
Nadav Haklai <nadavh@marvell.com>, Hanna Hawa <hannah@marvell.com>,
Yehuda Yitschak <yehuday@marvell.com>,
linux-arm-kernel@lists.infradead.org, Antoine Tenart
<antoine.tenart@free-electrons.com>, =?utf-8?q?Miqu=C3=A8l_Raynal?=
<miquel.raynal@free-electrons.com>, Evan Wang <xswang@marvell.com>,
Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Date: Thu, 28 Sep 2017 14:58:37 +0200
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
List-Id: <linux-pci.vger.kernel.org>
From: Evan Wang <xswang@marvell.com>
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 <xswang@marvell.com>
Reviewed-by: Victor Gu <xigu@marvell.com>
Reviewed-by: Nadav Haklai <nadavh@marvell.com>
[Thomas: tweak commit log.]
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
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 */
Loading…
Cancel
Save