From 9b06fc39084e161da84a399b6b5dc524e673f51e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Apr 2020 15:58:10 -0500 Subject: ARM: vexpress: Move vexpress_flags_set() into arch code vexpress_flags_set() is only used by the platform SMP related code and has nothing to do with the vexpress-sysreg MFD driver other than both access the same h/w block. It's also only needed for 32-bit systems and must be built-in for them. Let's move vexpress_flags_set() closer to where it is being used. This will allow for vexpress-sysreg to be built as a module. Cc: Lorenzo Pieralisi Cc: Linus Walleij Reviewed-by: Sudeep Holla Acked-by: Arnd Bergmann Acked-by: Liviu Dudau Acked-by: Lee Jones Signed-off-by: Rob Herring --- arch/arm/mach-vexpress/Kconfig | 1 - arch/arm/mach-vexpress/core.h | 1 + arch/arm/mach-vexpress/dcscb.c | 1 + arch/arm/mach-vexpress/v2m.c | 23 +++++++++++++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 726a68085c3b..18951cd20d9d 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -22,7 +22,6 @@ menuconfig ARCH_VEXPRESS select REGULATOR_FIXED_VOLTAGE if REGULATOR select VEXPRESS_CONFIG select VEXPRESS_SYSCFG - select MFD_VEXPRESS_SYSREG help This option enables support for systems using Cortex processor based ARM core and logic (FPGA) tiles on the Versatile Express motherboard, diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h index f4a7519084f1..bda78675c55d 100644 --- a/arch/arm/mach-vexpress/core.h +++ b/arch/arm/mach-vexpress/core.h @@ -1,3 +1,4 @@ bool vexpress_smp_init_ops(void); +void vexpress_flags_set(u32 data); extern const struct smp_operations vexpress_smp_dt_ops; diff --git a/arch/arm/mach-vexpress/dcscb.c b/arch/arm/mach-vexpress/dcscb.c index 46a903c88c6a..a0554d7d04f7 100644 --- a/arch/arm/mach-vexpress/dcscb.c +++ b/arch/arm/mach-vexpress/dcscb.c @@ -20,6 +20,7 @@ #include #include +#include "core.h" #define RST_HOLD0 0x0 #define RST_HOLD1 0x4 diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 95886b3bb9dd..ffe7c7a85ae9 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -1,8 +1,31 @@ // SPDX-License-Identifier: GPL-2.0 +#include +#include #include #include "core.h" +#define SYS_FLAGSSET 0x030 +#define SYS_FLAGSCLR 0x034 + +void vexpress_flags_set(u32 data) +{ + static void __iomem *base; + + if (!base) { + struct device_node *node = of_find_compatible_node(NULL, NULL, + "arm,vexpress-sysreg"); + + base = of_iomap(node, 0); + } + + if (WARN_ON(!base)) + return; + + writel(~0, base + SYS_FLAGSCLR); + writel(data, base + SYS_FLAGSSET); +} + static const char * const v2m_dt_match[] __initconst = { "arm,vexpress", NULL, -- cgit v1.2.3 From 81134fb541d46d0441ce7fce557eba6c418fcc36 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Apr 2020 15:58:13 -0500 Subject: clk: versatile: Rework kconfig structure CONFIG_COMMON_CLK_VERSATILE doesn't really do anything other than hiding Arm Ltd reference platform clock drivers. It is both selected by the platforms that need it and has a 'depends on' for those platforms. Let's drop the selects and convert CONFIG_COMMON_CLK_VERSATILE into a menuconfig entry. With this make CONFIG_ICST visible. Move the 'select REGMAP_MMIO' to the drivers that require it (SP810 did not). This also has the side effect of enabling CONFIG_ICST for COMPILE_TEST as it was not visible before. Cc: Catalin Marinas Cc: Will Deacon Cc: Liviu Dudau Cc: Lorenzo Pieralisi Cc: Linus Walleij Reviewed-by: Sudeep Holla Reviewed-by: Stephen Boyd Signed-off-by: Rob Herring --- arch/arm/mach-integrator/Kconfig | 1 - arch/arm/mach-realview/Kconfig | 1 - arch/arm/mach-versatile/Kconfig | 1 - arch/arm/mach-vexpress/Kconfig | 1 - arch/arm64/Kconfig.platforms | 1 - drivers/clk/Makefile | 2 +- drivers/clk/versatile/Kconfig | 22 ++++++++++++---------- 7 files changed, 13 insertions(+), 16 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index 982eabc36163..d59ba15a6b69 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -3,7 +3,6 @@ menuconfig ARCH_INTEGRATOR bool "ARM Ltd. Integrator family" depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6 select ARM_AMBA - select COMMON_CLK_VERSATILE select HAVE_TCM select ICST select MFD_SYSCON diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig index 44ebbf9ec673..002404fafc14 100644 --- a/arch/arm/mach-realview/Kconfig +++ b/arch/arm/mach-realview/Kconfig @@ -6,7 +6,6 @@ menuconfig ARCH_REALVIEW select ARM_GIC select ARM_TIMER_SP804 select CLK_SP810 - select COMMON_CLK_VERSATILE select GPIO_PL061 if GPIOLIB select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig index f5c275434d6c..d88e7725bf99 100644 --- a/arch/arm/mach-versatile/Kconfig +++ b/arch/arm/mach-versatile/Kconfig @@ -6,7 +6,6 @@ config ARCH_VERSATILE select ARM_TIMER_SP804 select ARM_VIC select CLKSRC_VERSATILE - select COMMON_CLK_VERSATILE select CPU_ARM926T select ICST select MFD_SYSCON diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 18951cd20d9d..2d1fdec4c230 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -7,7 +7,6 @@ menuconfig ARCH_VEXPRESS select ARM_GIC select ARM_GLOBAL_TIMER select ARM_TIMER_SP804 - select COMMON_CLK_VERSATILE select GPIOLIB select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 5c38dc56b808..25cbb556d863 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -274,7 +274,6 @@ config ARCH_UNIPHIER config ARCH_VEXPRESS bool "ARMv8 software model (Versatile Express)" - select COMMON_CLK_VERSATILE select GPIOLIB select PM select PM_GENERIC_DOMAINS diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f4169cc2fd31..fb30c16e1596 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -114,7 +114,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_ARCH_U8500) += ux500/ -obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ +obj-y += versatile/ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_X86) += x86/ endif diff --git a/drivers/clk/versatile/Kconfig b/drivers/clk/versatile/Kconfig index c2618f1477a2..df0d50bb846c 100644 --- a/drivers/clk/versatile/Kconfig +++ b/drivers/clk/versatile/Kconfig @@ -1,22 +1,22 @@ # SPDX-License-Identifier: GPL-2.0-only -config ICST - bool -config COMMON_CLK_VERSATILE - bool "Clock driver for ARM Reference designs" - depends on ARCH_INTEGRATOR || ARCH_REALVIEW || \ - ARCH_VERSATILE || ARCH_VEXPRESS || ARM64 || \ - COMPILE_TEST +menuconfig COMMON_CLK_VERSATILE + bool "Clock driver for ARM Reference designs" if COMPILE_TEST + default y if ARCH_INTEGRATOR || ARCH_REALVIEW || \ + ARCH_VERSATILE || ARCH_VEXPRESS + +if COMMON_CLK_VERSATILE + +config ICST + bool "Clock driver for ARM Reference designs ICST" select REGMAP_MMIO ---help--- Supports clocking on ARM Reference designs: - Integrator/AP and Integrator/CP - RealView PB1176, EB, PB11MP and PBX - - Versatile Express config CLK_SP810 bool "Clock driver for ARM SP810 System Controller" - depends on COMMON_CLK_VERSATILE default y if ARCH_VEXPRESS ---help--- Supports clock muxing (REFCLK/TIMCLK to TIMERCLKEN0-3) capabilities @@ -24,10 +24,12 @@ config CLK_SP810 config CLK_VEXPRESS_OSC bool "Clock driver for Versatile Express OSC clock generators" - depends on COMMON_CLK_VERSATILE depends on VEXPRESS_CONFIG + select REGMAP_MMIO default y if ARCH_VEXPRESS ---help--- Simple regmap-based driver driving clock generators on Versatile Express platforms hidden behind its configuration infrastructure, commonly known as OSCs. + +endif -- cgit v1.2.3 From d06cfe3f123c50449a0c3ece21bc16668289c50f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Apr 2020 15:58:21 -0500 Subject: bus: vexpress-config: Merge vexpress-syscfg into vexpress-config The only thing that vexpress-syscfg does is provide a regmap to vexpress-config bus child devices. There's little reason to have 2 components for this. The current structure with initcall ordering requirements makes turning these components into modules more difficult. So let's start to simplify things and merge vexpress-syscfg into vexpress-config. There's no functional change in this commit and it's still separate components until subsequent commits. Cc: Lorenzo Pieralisi Cc: Linus Walleij Cc: Arnd Bergmann Reviewed-by: Sudeep Holla Acked-by: Greg Kroah-Hartman Acked-by: Liviu Dudau Signed-off-by: Rob Herring --- arch/arm/mach-vexpress/Kconfig | 1 - drivers/bus/vexpress-config.c | 283 +++++++++++++++++++++++++++++++++++++++-- drivers/misc/Kconfig | 9 -- drivers/misc/Makefile | 1 - drivers/misc/vexpress-syscfg.c | 280 ---------------------------------------- include/linux/vexpress.h | 17 --- 6 files changed, 274 insertions(+), 317 deletions(-) delete mode 100644 drivers/misc/vexpress-syscfg.c (limited to 'arch/arm') diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 2d1fdec4c230..065e12991663 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -20,7 +20,6 @@ menuconfig ARCH_VEXPRESS select REGULATOR if MMC_ARMMMCI select REGULATOR_FIXED_VOLTAGE if REGULATOR select VEXPRESS_CONFIG - select VEXPRESS_SYSCFG help This option enables support for systems using Cortex processor based ARM core and logic (FPGA) tiles on the Versatile Express motherboard, diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c index ff70575b2db6..43f5beac9811 100644 --- a/drivers/bus/vexpress-config.c +++ b/drivers/bus/vexpress-config.c @@ -6,10 +6,48 @@ #include #include +#include #include +#include #include +#include +#include #include +#define SYS_CFGDATA 0x0 + +#define SYS_CFGCTRL 0x4 +#define SYS_CFGCTRL_START (1 << 31) +#define SYS_CFGCTRL_WRITE (1 << 30) +#define SYS_CFGCTRL_DCC(n) (((n) & 0xf) << 26) +#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20) +#define SYS_CFGCTRL_SITE(n) (((n) & 0x3) << 16) +#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12) +#define SYS_CFGCTRL_DEVICE(n) (((n) & 0xfff) << 0) + +#define SYS_CFGSTAT 0x8 +#define SYS_CFGSTAT_ERR (1 << 1) +#define SYS_CFGSTAT_COMPLETE (1 << 0) + + +struct vexpress_syscfg { + struct device *dev; + void __iomem *base; + struct list_head funcs; +}; + +struct vexpress_syscfg_func { + struct list_head list; + struct vexpress_syscfg *syscfg; + struct regmap *regmap; + int num_templates; + u32 template[]; /* Keep it last! */ +}; + +struct vexpress_config_bridge_ops { + struct regmap * (*regmap_init)(struct device *dev, void *context); + void (*regmap_exit)(struct regmap *regmap, void *context); +}; struct vexpress_config_bridge { struct vexpress_config_bridge_ops *ops; @@ -27,17 +65,12 @@ void vexpress_config_set_master(u32 site) vexpress_config_site_master = site; } -u32 vexpress_config_get_master(void) -{ - return vexpress_config_site_master; -} - -void vexpress_config_lock(void *arg) +static void vexpress_config_lock(void *arg) { mutex_lock(&vexpress_config_mutex); } -void vexpress_config_unlock(void *arg) +static void vexpress_config_unlock(void *arg) { mutex_unlock(&vexpress_config_mutex); } @@ -59,7 +92,7 @@ static void vexpress_config_find_prop(struct device_node *node, } } -int vexpress_config_get_topo(struct device_node *node, u32 *site, +static int vexpress_config_get_topo(struct device_node *node, u32 *site, u32 *position, u32 *dcc) { vexpress_config_find_prop(node, "arm,vexpress,site", site); @@ -113,7 +146,7 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev) } EXPORT_SYMBOL_GPL(devm_regmap_init_vexpress_config); -struct device *vexpress_config_bridge_register(struct device *parent, +static struct device *vexpress_config_bridge_register(struct device *parent, struct vexpress_config_bridge_ops *ops, void *context) { struct device *dev; @@ -201,3 +234,235 @@ static int __init vexpress_config_init(void) } postcore_initcall(vexpress_config_init); +static int vexpress_syscfg_exec(struct vexpress_syscfg_func *func, + int index, bool write, u32 *data) +{ + struct vexpress_syscfg *syscfg = func->syscfg; + u32 command, status; + int tries; + long timeout; + + if (WARN_ON(index >= func->num_templates)) + return -EINVAL; + + command = readl(syscfg->base + SYS_CFGCTRL); + if (WARN_ON(command & SYS_CFGCTRL_START)) + return -EBUSY; + + command = func->template[index]; + command |= SYS_CFGCTRL_START; + command |= write ? SYS_CFGCTRL_WRITE : 0; + + /* Use a canary for reads */ + if (!write) + *data = 0xdeadbeef; + + dev_dbg(syscfg->dev, "func %p, command %x, data %x\n", + func, command, *data); + writel(*data, syscfg->base + SYS_CFGDATA); + writel(0, syscfg->base + SYS_CFGSTAT); + writel(command, syscfg->base + SYS_CFGCTRL); + mb(); + + /* The operation can take ages... Go to sleep, 100us initially */ + tries = 100; + timeout = 100; + do { + if (!irqs_disabled()) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(timeout)); + if (signal_pending(current)) + return -EINTR; + } else { + udelay(timeout); + } + + status = readl(syscfg->base + SYS_CFGSTAT); + if (status & SYS_CFGSTAT_ERR) + return -EFAULT; + + if (timeout > 20) + timeout -= 20; + } while (--tries && !(status & SYS_CFGSTAT_COMPLETE)); + if (WARN_ON_ONCE(!tries)) + return -ETIMEDOUT; + + if (!write) { + *data = readl(syscfg->base + SYS_CFGDATA); + dev_dbg(syscfg->dev, "func %p, read data %x\n", func, *data); + } + + return 0; +} + +static int vexpress_syscfg_read(void *context, unsigned int index, + unsigned int *val) +{ + struct vexpress_syscfg_func *func = context; + + return vexpress_syscfg_exec(func, index, false, val); +} + +static int vexpress_syscfg_write(void *context, unsigned int index, + unsigned int val) +{ + struct vexpress_syscfg_func *func = context; + + return vexpress_syscfg_exec(func, index, true, &val); +} + +static struct regmap_config vexpress_syscfg_regmap_config = { + .lock = vexpress_config_lock, + .unlock = vexpress_config_unlock, + .reg_bits = 32, + .val_bits = 32, + .reg_read = vexpress_syscfg_read, + .reg_write = vexpress_syscfg_write, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + + +static struct regmap *vexpress_syscfg_regmap_init(struct device *dev, + void *context) +{ + int err; + struct vexpress_syscfg *syscfg = context; + struct vexpress_syscfg_func *func; + struct property *prop; + const __be32 *val = NULL; + __be32 energy_quirk[4]; + int num; + u32 site, position, dcc; + int i; + + err = vexpress_config_get_topo(dev->of_node, &site, + &position, &dcc); + if (err) + return ERR_PTR(err); + + prop = of_find_property(dev->of_node, + "arm,vexpress-sysreg,func", NULL); + if (!prop) + return ERR_PTR(-EINVAL); + + num = prop->length / sizeof(u32) / 2; + val = prop->value; + + /* + * "arm,vexpress-energy" function used to be described + * by its first device only, now it requires both + */ + if (num == 1 && of_device_is_compatible(dev->of_node, + "arm,vexpress-energy")) { + num = 2; + energy_quirk[0] = *val; + energy_quirk[2] = *val++; + energy_quirk[1] = *val; + energy_quirk[3] = cpu_to_be32(be32_to_cpup(val) + 1); + val = energy_quirk; + } + + func = kzalloc(struct_size(func, template, num), GFP_KERNEL); + if (!func) + return ERR_PTR(-ENOMEM); + + func->syscfg = syscfg; + func->num_templates = num; + + for (i = 0; i < num; i++) { + u32 function, device; + + function = be32_to_cpup(val++); + device = be32_to_cpup(val++); + + dev_dbg(dev, "func %p: %u/%u/%u/%u/%u\n", + func, site, position, dcc, + function, device); + + func->template[i] = SYS_CFGCTRL_DCC(dcc); + func->template[i] |= SYS_CFGCTRL_SITE(site); + func->template[i] |= SYS_CFGCTRL_POSITION(position); + func->template[i] |= SYS_CFGCTRL_FUNC(function); + func->template[i] |= SYS_CFGCTRL_DEVICE(device); + } + + vexpress_syscfg_regmap_config.max_register = num - 1; + + func->regmap = regmap_init(dev, NULL, func, + &vexpress_syscfg_regmap_config); + + if (IS_ERR(func->regmap)) { + void *err = func->regmap; + + kfree(func); + return err; + } + + list_add(&func->list, &syscfg->funcs); + + return func->regmap; +} + +static void vexpress_syscfg_regmap_exit(struct regmap *regmap, void *context) +{ + struct vexpress_syscfg *syscfg = context; + struct vexpress_syscfg_func *func, *tmp; + + regmap_exit(regmap); + + list_for_each_entry_safe(func, tmp, &syscfg->funcs, list) { + if (func->regmap == regmap) { + list_del(&syscfg->funcs); + kfree(func); + break; + } + } +} + +static struct vexpress_config_bridge_ops vexpress_syscfg_bridge_ops = { + .regmap_init = vexpress_syscfg_regmap_init, + .regmap_exit = vexpress_syscfg_regmap_exit, +}; + + +static int vexpress_syscfg_probe(struct platform_device *pdev) +{ + struct vexpress_syscfg *syscfg; + struct resource *res; + struct device *bridge; + + syscfg = devm_kzalloc(&pdev->dev, sizeof(*syscfg), GFP_KERNEL); + if (!syscfg) + return -ENOMEM; + syscfg->dev = &pdev->dev; + INIT_LIST_HEAD(&syscfg->funcs); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + syscfg->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(syscfg->base)) + return PTR_ERR(syscfg->base); + + /* Must use dev.parent (MFD), as that's where DT phandle points at... */ + bridge = vexpress_config_bridge_register(pdev->dev.parent, + &vexpress_syscfg_bridge_ops, syscfg); + + return PTR_ERR_OR_ZERO(bridge); +} + +static const struct platform_device_id vexpress_syscfg_id_table[] = { + { "vexpress-syscfg", }, + {}, +}; + +static struct platform_driver vexpress_syscfg_driver = { + .driver.name = "vexpress-syscfg", + .id_table = vexpress_syscfg_id_table, + .probe = vexpress_syscfg_probe, +}; + +static int __init vexpress_syscfg_init(void) +{ + return platform_driver_register(&vexpress_syscfg_driver); +} +core_initcall(vexpress_syscfg_init); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 99e151475d8f..edd5dd5ebfdc 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -423,15 +423,6 @@ config SRAM config SRAM_EXEC bool -config VEXPRESS_SYSCFG - bool "Versatile Express System Configuration driver" - depends on VEXPRESS_CONFIG - default y - help - ARM Ltd. Versatile Express uses specialised platform configuration - bus. System Configuration interface is one of the possible means - of generating transactions on this bus. - config PCI_ENDPOINT_TEST depends on PCI select CRC32 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 9abf2923d831..c7bd01ac6291 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -49,7 +49,6 @@ obj-$(CONFIG_SRAM_EXEC) += sram-exec.o obj-y += mic/ obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_ECHO) += echo/ -obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o obj-$(CONFIG_OCXL) += ocxl/ diff --git a/drivers/misc/vexpress-syscfg.c b/drivers/misc/vexpress-syscfg.c deleted file mode 100644 index a431787c0898..000000000000 --- a/drivers/misc/vexpress-syscfg.c +++ /dev/null @@ -1,280 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Copyright (C) 2014 ARM Limited - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define SYS_CFGDATA 0x0 - -#define SYS_CFGCTRL 0x4 -#define SYS_CFGCTRL_START (1 << 31) -#define SYS_CFGCTRL_WRITE (1 << 30) -#define SYS_CFGCTRL_DCC(n) (((n) & 0xf) << 26) -#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20) -#define SYS_CFGCTRL_SITE(n) (((n) & 0x3) << 16) -#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12) -#define SYS_CFGCTRL_DEVICE(n) (((n) & 0xfff) << 0) - -#define SYS_CFGSTAT 0x8 -#define SYS_CFGSTAT_ERR (1 << 1) -#define SYS_CFGSTAT_COMPLETE (1 << 0) - - -struct vexpress_syscfg { - struct device *dev; - void __iomem *base; - struct list_head funcs; -}; - -struct vexpress_syscfg_func { - struct list_head list; - struct vexpress_syscfg *syscfg; - struct regmap *regmap; - int num_templates; - u32 template[]; /* Keep it last! */ -}; - - -static int vexpress_syscfg_exec(struct vexpress_syscfg_func *func, - int index, bool write, u32 *data) -{ - struct vexpress_syscfg *syscfg = func->syscfg; - u32 command, status; - int tries; - long timeout; - - if (WARN_ON(index >= func->num_templates)) - return -EINVAL; - - command = readl(syscfg->base + SYS_CFGCTRL); - if (WARN_ON(command & SYS_CFGCTRL_START)) - return -EBUSY; - - command = func->template[index]; - command |= SYS_CFGCTRL_START; - command |= write ? SYS_CFGCTRL_WRITE : 0; - - /* Use a canary for reads */ - if (!write) - *data = 0xdeadbeef; - - dev_dbg(syscfg->dev, "func %p, command %x, data %x\n", - func, command, *data); - writel(*data, syscfg->base + SYS_CFGDATA); - writel(0, syscfg->base + SYS_CFGSTAT); - writel(command, syscfg->base + SYS_CFGCTRL); - mb(); - - /* The operation can take ages... Go to sleep, 100us initially */ - tries = 100; - timeout = 100; - do { - if (!irqs_disabled()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(timeout)); - if (signal_pending(current)) - return -EINTR; - } else { - udelay(timeout); - } - - status = readl(syscfg->base + SYS_CFGSTAT); - if (status & SYS_CFGSTAT_ERR) - return -EFAULT; - - if (timeout > 20) - timeout -= 20; - } while (--tries && !(status & SYS_CFGSTAT_COMPLETE)); - if (WARN_ON_ONCE(!tries)) - return -ETIMEDOUT; - - if (!write) { - *data = readl(syscfg->base + SYS_CFGDATA); - dev_dbg(syscfg->dev, "func %p, read data %x\n", func, *data); - } - - return 0; -} - -static int vexpress_syscfg_read(void *context, unsigned int index, - unsigned int *val) -{ - struct vexpress_syscfg_func *func = context; - - return vexpress_syscfg_exec(func, index, false, val); -} - -static int vexpress_syscfg_write(void *context, unsigned int index, - unsigned int val) -{ - struct vexpress_syscfg_func *func = context; - - return vexpress_syscfg_exec(func, index, true, &val); -} - -static struct regmap_config vexpress_syscfg_regmap_config = { - .lock = vexpress_config_lock, - .unlock = vexpress_config_unlock, - .reg_bits = 32, - .val_bits = 32, - .reg_read = vexpress_syscfg_read, - .reg_write = vexpress_syscfg_write, - .reg_format_endian = REGMAP_ENDIAN_LITTLE, - .val_format_endian = REGMAP_ENDIAN_LITTLE, -}; - - -static struct regmap *vexpress_syscfg_regmap_init(struct device *dev, - void *context) -{ - int err; - struct vexpress_syscfg *syscfg = context; - struct vexpress_syscfg_func *func; - struct property *prop; - const __be32 *val = NULL; - __be32 energy_quirk[4]; - int num; - u32 site, position, dcc; - int i; - - err = vexpress_config_get_topo(dev->of_node, &site, - &position, &dcc); - if (err) - return ERR_PTR(err); - - prop = of_find_property(dev->of_node, - "arm,vexpress-sysreg,func", NULL); - if (!prop) - return ERR_PTR(-EINVAL); - - num = prop->length / sizeof(u32) / 2; - val = prop->value; - - /* - * "arm,vexpress-energy" function used to be described - * by its first device only, now it requires both - */ - if (num == 1 && of_device_is_compatible(dev->of_node, - "arm,vexpress-energy")) { - num = 2; - energy_quirk[0] = *val; - energy_quirk[2] = *val++; - energy_quirk[1] = *val; - energy_quirk[3] = cpu_to_be32(be32_to_cpup(val) + 1); - val = energy_quirk; - } - - func = kzalloc(struct_size(func, template, num), GFP_KERNEL); - if (!func) - return ERR_PTR(-ENOMEM); - - func->syscfg = syscfg; - func->num_templates = num; - - for (i = 0; i < num; i++) { - u32 function, device; - - function = be32_to_cpup(val++); - device = be32_to_cpup(val++); - - dev_dbg(dev, "func %p: %u/%u/%u/%u/%u\n", - func, site, position, dcc, - function, device); - - func->template[i] = SYS_CFGCTRL_DCC(dcc); - func->template[i] |= SYS_CFGCTRL_SITE(site); - func->template[i] |= SYS_CFGCTRL_POSITION(position); - func->template[i] |= SYS_CFGCTRL_FUNC(function); - func->template[i] |= SYS_CFGCTRL_DEVICE(device); - } - - vexpress_syscfg_regmap_config.max_register = num - 1; - - func->regmap = regmap_init(dev, NULL, func, - &vexpress_syscfg_regmap_config); - - if (IS_ERR(func->regmap)) { - void *err = func->regmap; - - kfree(func); - return err; - } - - list_add(&func->list, &syscfg->funcs); - - return func->regmap; -} - -static void vexpress_syscfg_regmap_exit(struct regmap *regmap, void *context) -{ - struct vexpress_syscfg *syscfg = context; - struct vexpress_syscfg_func *func, *tmp; - - regmap_exit(regmap); - - list_for_each_entry_safe(func, tmp, &syscfg->funcs, list) { - if (func->regmap == regmap) { - list_del(&syscfg->funcs); - kfree(func); - break; - } - } -} - -static struct vexpress_config_bridge_ops vexpress_syscfg_bridge_ops = { - .regmap_init = vexpress_syscfg_regmap_init, - .regmap_exit = vexpress_syscfg_regmap_exit, -}; - - -static int vexpress_syscfg_probe(struct platform_device *pdev) -{ - struct vexpress_syscfg *syscfg; - struct resource *res; - struct device *bridge; - - syscfg = devm_kzalloc(&pdev->dev, sizeof(*syscfg), GFP_KERNEL); - if (!syscfg) - return -ENOMEM; - syscfg->dev = &pdev->dev; - INIT_LIST_HEAD(&syscfg->funcs); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - syscfg->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(syscfg->base)) - return PTR_ERR(syscfg->base); - - /* Must use dev.parent (MFD), as that's where DT phandle points at... */ - bridge = vexpress_config_bridge_register(pdev->dev.parent, - &vexpress_syscfg_bridge_ops, syscfg); - - return PTR_ERR_OR_ZERO(bridge); -} - -static const struct platform_device_id vexpress_syscfg_id_table[] = { - { "vexpress-syscfg", }, - {}, -}; - -static struct platform_driver vexpress_syscfg_driver = { - .driver.name = "vexpress-syscfg", - .id_table = vexpress_syscfg_id_table, - .probe = vexpress_syscfg_probe, -}; - -static int __init vexpress_syscfg_init(void) -{ - return platform_driver_register(&vexpress_syscfg_driver); -} -core_initcall(vexpress_syscfg_init); diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h index 2ec7992b054c..65096c792d57 100644 --- a/include/linux/vexpress.h +++ b/include/linux/vexpress.h @@ -18,23 +18,6 @@ /* Config infrastructure */ void vexpress_config_set_master(u32 site); -u32 vexpress_config_get_master(void); - -void vexpress_config_lock(void *arg); -void vexpress_config_unlock(void *arg); - -int vexpress_config_get_topo(struct device_node *node, u32 *site, - u32 *position, u32 *dcc); - -/* Config bridge API */ - -struct vexpress_config_bridge_ops { - struct regmap * (*regmap_init)(struct device *dev, void *context); - void (*regmap_exit)(struct regmap *regmap, void *context); -}; - -struct device *vexpress_config_bridge_register(struct device *parent, - struct vexpress_config_bridge_ops *ops, void *context); /* Config regmap API */ -- cgit v1.2.3 From 848685c25da99d871bbd87369f3c3d6eead661ac Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Apr 2020 15:58:25 -0500 Subject: ARM: vexpress: Don't select VEXPRESS_CONFIG CONFIG_VEXPRESS_CONFIG has 'default y if ARCH_VEXPRESS', so selecting is unnecessary. Selecting it also prevents setting CONFIG_VEXPRESS_CONFIG to a module. Cc: Lorenzo Pieralisi Cc: Linus Walleij Reviewed-by: Sudeep Holla Acked-by: Liviu Dudau Signed-off-by: Rob Herring --- arch/arm/mach-vexpress/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 065e12991663..8391a5b3cd78 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -19,7 +19,6 @@ menuconfig ARCH_VEXPRESS select POWER_SUPPLY select REGULATOR if MMC_ARMMMCI select REGULATOR_FIXED_VOLTAGE if REGULATOR - select VEXPRESS_CONFIG help This option enables support for systems using Cortex processor based ARM core and logic (FPGA) tiles on the Versatile Express motherboard, -- cgit v1.2.3