From 3b9334ac835bb431e2186645230c9f1eb94b5d49 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Wed, 30 Apr 2014 16:46:29 +0100 Subject: mfd: vexpress: Convert custom func API to regmap Components of the Versatile Express platform (configuration microcontrollers on motherboard and daughterboards in particular) talk to each other over a custom configuration bus. They provide miscellaneous functions (from clock generator control to energy sensors) which are represented as platform devices (and Device Tree nodes). The transactions on the bus can be generated by different "bridges" in the system, some of which are universal for the whole platform (for the price of high transfer latencies), others restricted to a subsystem (but much faster). Until now drivers for such functions were using custom "func" API, which is being replaced in this patch by regmap calls. This required: * a rework (and move to drivers/bus directory, as suggested by Samuel and Arnd) of the config bus core, which is much simpler now and uses device model infrastructure (class) to keep track of the bridges; non-DT case (soon to be retired anyway) is simply covered by a special device registration function * the new config-bus driver also takes over device population, so there is no need for special matching table for of_platform_populate nor "simple-bus" hack in the arm64 model dtsi file (relevant bindings documentation has been updated); this allows all the vexpress devices fit into normal device model, making it possible to remove plenty of early inits and other hacks in the near future * adaptation of the syscfg bridge implementation in the sysreg driver, again making it much simpler; there is a special case of the "energy" function spanning two registers, where they should be both defined in the tree now, but backward compatibility is maintained in the code * modification of the relevant drivers: * hwmon - just a straight-forward API change * power/reset driver - API change * regulator - API change plus error handling simplification * osc clock driver - this one required larger rework in order to turn in into a standard platform driver Signed-off-by: Pawel Moll Acked-by: Mark Brown Acked-by: Lee Jones Acked-by: Guenter Roeck Acked-by: Mike Turquette --- drivers/bus/Kconfig | 9 ++ drivers/bus/Makefile | 2 + drivers/bus/vexpress-config.c | 202 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 drivers/bus/vexpress-config.c (limited to 'drivers/bus') diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 552373c4e362..f24e79dd51bf 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -41,4 +41,13 @@ config ARM_CCI help Driver supporting the CCI cache coherent interconnect for ARM platforms. + +config VEXPRESS_CONFIG + bool "Versatile Express configuration bus" + default y if ARCH_VEXPRESS + depends on ARM || ARM64 + select REGMAP + help + Platform configuration infrastructure for the ARM Ltd. + Versatile Express. endmenu diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 8947bdd0de8b..f095aa771de9 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -10,3 +10,5 @@ obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o # CCI cache coherent interconnect for ARM platforms obj-$(CONFIG_ARM_CCI) += arm-cci.o + +obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c new file mode 100644 index 000000000000..27a07dfcd626 --- /dev/null +++ b/drivers/bus/vexpress-config.c @@ -0,0 +1,202 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2014 ARM Limited + */ + +#include +#include +#include +#include +#include + + +struct vexpress_config_bridge { + struct vexpress_config_bridge_ops *ops; + void *context; +}; + + +static DEFINE_MUTEX(vexpress_config_mutex); +static struct class *vexpress_config_class; +static u32 vexpress_config_site_master = VEXPRESS_SITE_MASTER; + + +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) +{ + mutex_lock(&vexpress_config_mutex); +} + +void vexpress_config_unlock(void *arg) +{ + mutex_unlock(&vexpress_config_mutex); +} + + +static void vexpress_config_find_prop(struct device_node *node, + const char *name, u32 *val) +{ + /* Default value */ + *val = 0; + + of_node_get(node); + while (node) { + if (of_property_read_u32(node, name, val) == 0) { + of_node_put(node); + return; + } + node = of_get_next_parent(node); + } +} + +int vexpress_config_get_topo(struct device_node *node, u32 *site, + u32 *position, u32 *dcc) +{ + vexpress_config_find_prop(node, "arm,vexpress,site", site); + if (*site == VEXPRESS_SITE_MASTER) + *site = vexpress_config_site_master; + if (WARN_ON(vexpress_config_site_master == VEXPRESS_SITE_MASTER)) + return -EINVAL; + vexpress_config_find_prop(node, "arm,vexpress,position", position); + vexpress_config_find_prop(node, "arm,vexpress,dcc", dcc); + + return 0; +} + + +static void vexpress_config_devres_release(struct device *dev, void *res) +{ + struct vexpress_config_bridge *bridge = dev_get_drvdata(dev->parent); + struct regmap *regmap = res; + + bridge->ops->regmap_exit(regmap, bridge->context); +} + +struct regmap *devm_regmap_init_vexpress_config(struct device *dev) +{ + struct vexpress_config_bridge *bridge; + struct regmap *regmap; + struct regmap **res; + + if (WARN_ON(dev->parent->class != vexpress_config_class)) + return ERR_PTR(-ENODEV); + + bridge = dev_get_drvdata(dev->parent); + if (WARN_ON(!bridge)) + return ERR_PTR(-EINVAL); + + res = devres_alloc(vexpress_config_devres_release, sizeof(*res), + GFP_KERNEL); + if (!res) + return ERR_PTR(-ENOMEM); + + regmap = bridge->ops->regmap_init(dev, bridge->context); + if (IS_ERR(regmap)) { + devres_free(res); + return regmap; + } + + *res = regmap; + devres_add(dev, res); + + return regmap; +} + + +struct device *vexpress_config_bridge_register(struct device *parent, + struct vexpress_config_bridge_ops *ops, void *context) +{ + struct device *dev; + struct vexpress_config_bridge *bridge; + + if (!vexpress_config_class) { + vexpress_config_class = class_create(THIS_MODULE, + "vexpress-config"); + if (IS_ERR(vexpress_config_class)) + return (void *)vexpress_config_class; + } + + dev = device_create(vexpress_config_class, parent, 0, + NULL, "%s.bridge", dev_name(parent)); + + if (IS_ERR(dev)) + return dev; + + bridge = devm_kmalloc(dev, sizeof(*bridge), GFP_KERNEL); + if (!bridge) { + put_device(dev); + device_unregister(dev); + return ERR_PTR(-ENOMEM); + } + bridge->ops = ops; + bridge->context = context; + + dev_set_drvdata(dev, bridge); + + dev_dbg(parent, "Registered bridge '%s', parent node %p\n", + dev_name(dev), parent->of_node); + + return dev; +} + + +static int vexpress_config_node_match(struct device *dev, const void *data) +{ + const struct device_node *node = data; + + dev_dbg(dev, "Parent node %p, looking for %p\n", + dev->parent->of_node, node); + + return dev->parent->of_node == node; +} + +static int vexpress_config_populate(struct device_node *node) +{ + struct device_node *bridge; + struct device *parent; + + bridge = of_parse_phandle(node, "arm,vexpress,config-bridge", 0); + if (!bridge) + return -EINVAL; + + parent = class_find_device(vexpress_config_class, NULL, bridge, + vexpress_config_node_match); + if (WARN_ON(!parent)) + return -ENODEV; + + return of_platform_populate(node, NULL, NULL, parent); +} + +static int __init vexpress_config_init(void) +{ + int err = 0; + struct device_node *node; + + /* Need the config devices early, before the "normal" devices... */ + for_each_compatible_node(node, NULL, "arm,vexpress,config-bus") { + err = vexpress_config_populate(node); + if (err) + break; + } + + return err; +} +postcore_initcall(vexpress_config_init); + -- cgit v1.2.3 From b33cdd283bd917d431469c29419c2cf2624bd683 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 26 May 2014 17:25:22 +0200 Subject: ARM: vexpress: refine dependencies for new code The versatile express changes for 3.16 introduced a number of build regressions for randconfig kernels by not tracking dependencies between the components right. This patch tries to rectify that: * the mach-vexpress code cannot link without the syscfg driver, which in turn needs MFD_VEXPRESS_SYSREG * various drivers call devm_regmap_init_vexpress_config(), which has to be exported so it can be used by loadable modules * the configuration bus uses OF DT helper functions that are not available to platforms disable CONFIG_OF * The sysreg driver exports GPIOs through gpiolib, which can be disabled on some platforms. * The clocksource code cannot be built on platforms that don't use modern timekeeping but rely on gettimeoffset. Signed-off-by: Arnd Bergmann --- arch/arm/mach-vexpress/Kconfig | 2 ++ drivers/bus/Kconfig | 1 + drivers/bus/vexpress-config.c | 2 +- drivers/clocksource/Kconfig | 2 +- drivers/mfd/Kconfig | 2 +- 5 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/bus') diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 657d52d0391f..b8ac752fd24b 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -18,6 +18,8 @@ config ARCH_VEXPRESS select POWER_SUPPLY 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/drivers/bus/Kconfig b/drivers/bus/Kconfig index f24e79dd51bf..286342778884 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -46,6 +46,7 @@ config VEXPRESS_CONFIG bool "Versatile Express configuration bus" default y if ARCH_VEXPRESS depends on ARM || ARM64 + depends on OF select REGMAP help Platform configuration infrastructure for the ARM Ltd. diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c index 27a07dfcd626..a64763b6b5fd 100644 --- a/drivers/bus/vexpress-config.c +++ b/drivers/bus/vexpress-config.c @@ -118,7 +118,7 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev) return regmap; } - +EXPORT_SYMBOL_GPL(devm_regmap_init_vexpress_config); struct device *vexpress_config_bridge_register(struct device *parent, struct vexpress_config_bridge_ops *ops, void *context) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 2c27b02f0860..43f1acf0d1d2 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -194,7 +194,7 @@ config CLKSRC_QCOM config CLKSRC_VERSATILE bool "ARM Versatile (Express) reference platforms clock source" - depends on GENERIC_SCHED_CLOCK + depends on GENERIC_SCHED_CLOCK && !ARCH_USES_GETTIMEOFFSET select CLKSRC_OF default y if MFD_VEXPRESS_SYSREG help diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 490fd48a9541..f04ac62dd76b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1229,7 +1229,7 @@ endmenu config MFD_VEXPRESS_SYSREG bool "Versatile Express System Registers" - depends on VEXPRESS_CONFIG + depends on VEXPRESS_CONFIG && GPIOLIB default y select CLKSRC_MMIO select GPIO_GENERIC_PLATFORM -- cgit v1.2.3