linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/13] Versatile Express infrastructure
@ 2012-09-18 14:17 Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 01/13] input: ambakmi: (Un)prepare clocks when (dis)enabling Pawel Moll
                   ` (12 more replies)
  0 siblings, 13 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi All,

This is a second version of the series I posted two weeks ago.
It has been heavily reworked based on feedback - mainly there
is no special bus_type and the interaction between a device
and a bridge is much more similar to what clocks/interrupts/
GPIOs are doing.

I believe I have Cc-ed all relevant maintainers (input,
fb, hwmon, regulators, common clock) in the subsystem-specific
patches (1 to 6). If the code looks good I'll prepare a git
pull request for Arnd and Olof with patches 7 to 13. I still
hope to get this series merged in 3.7 window.

Regards

Pawel


Pawel Moll (13):
  input: ambakmi: (Un)prepare clocks when (dis)enabling
  video: Versatile Express display output driver
  hwmon: Versatile Express hwmon driver
  regulators: Versatile Express regulator driver
  clk: Versatile Express clock generators ("osc") driver
  clk: Common clocks implementation for Versatile Express
  misc: Versatile Express config infrastructure
  mfd: Versatile Express system registers driver
  ARM: vexpress: Reset driver
  ARM: vexpress: Add config bus components and clocks to DTs
  ARM: vexpress: Start using new Versatile Express infrastructure
  ARM: vexpress: Remove motherboard dependencies in the DTS files
  ARM: vexpress: Make the DEBUG_LL UART detection more specific

 .../devicetree/bindings/arm/vexpress-sysreg.txt    |   50 ++
 Documentation/devicetree/bindings/arm/vexpress.txt |   68 ++-
 arch/arm/Kconfig                                   |    4 +-
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi            |  145 +++++-
 arch/arm/boot/dts/vexpress-v2m.dtsi                |  145 +++++-
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts        |  115 ++++-
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts         |  179 ++++++-
 arch/arm/boot/dts/vexpress-v2p-ca5s.dts            |   79 ++-
 arch/arm/boot/dts/vexpress-v2p-ca9.dts             |  125 ++++-
 arch/arm/include/asm/hardware/sp810.h              |    6 +-
 arch/arm/mach-vexpress/Makefile                    |    2 +-
 arch/arm/mach-vexpress/ct-ca9x4.c                  |   41 +-
 arch/arm/mach-vexpress/include/mach/debug-macro.S  |   10 +-
 arch/arm/mach-vexpress/include/mach/motherboard.h  |   81 ---
 arch/arm/mach-vexpress/include/mach/uncompress.h   |   12 +-
 arch/arm/mach-vexpress/platsmp.c                   |    3 +-
 arch/arm/mach-vexpress/reset.c                     |  141 +++++
 arch/arm/mach-vexpress/v2m.c                       |  350 ++++---------
 drivers/clk/Kconfig                                |    8 +-
 drivers/clk/versatile/Makefile                     |    2 +
 drivers/clk/versatile/clk-vexpress-osc.c           |  146 ++++++
 drivers/clk/versatile/clk-vexpress.c               |  142 +++++
 drivers/hwmon/Kconfig                              |    8 +
 drivers/hwmon/Makefile                             |    1 +
 drivers/hwmon/vexpress.c                           |  330 ++++++++++++
 drivers/input/serio/ambakmi.c                      |    6 +-
 drivers/mfd/Makefile                               |    1 +
 drivers/mfd/vexpress-sysreg.c                      |  542 ++++++++++++++++++++
 drivers/misc/Kconfig                               |    6 +
 drivers/misc/Makefile                              |    1 +
 drivers/misc/vexpress-config.c                     |  276 ++++++++++
 drivers/regulator/Kconfig                          |    7 +
 drivers/regulator/Makefile                         |    1 +
 drivers/regulator/vexpress.c                       |  155 ++++++
 drivers/video/Makefile                             |    3 +
 drivers/video/vexpress-dvi.c                       |  208 ++++++++
 include/linux/vexpress.h                           |  100 ++++
 37 files changed, 3067 insertions(+), 432 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
 create mode 100644 arch/arm/mach-vexpress/reset.c
 create mode 100644 drivers/clk/versatile/clk-vexpress-osc.c
 create mode 100644 drivers/clk/versatile/clk-vexpress.c
 create mode 100644 drivers/hwmon/vexpress.c
 create mode 100644 drivers/mfd/vexpress-sysreg.c
 create mode 100644 drivers/misc/vexpress-config.c
 create mode 100644 drivers/regulator/vexpress.c
 create mode 100644 drivers/video/vexpress-dvi.c
 create mode 100644 include/linux/vexpress.h

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 01/13] input: ambakmi: (Un)prepare clocks when (dis)enabling
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 02/13] video: Versatile Express display output driver Pawel Moll
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

Clocks must be prepared before enabling and unprepared
after disabling. Use appropriate functions to do this
in one go.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/input/serio/ambakmi.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Hi Russell, Dmitry,

What would be your preference regarding merging this patch? Russell's patch
system? Dmitry's git tree? Or maybe you want me to add it to a pull request
for arm-soc guys?

Cheers!

Pawel

diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 2ffd110..2e77246 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -72,7 +72,7 @@ static int amba_kmi_open(struct serio *io)
 	unsigned int divisor;
 	int ret;
 
-	ret = clk_enable(kmi->clk);
+	ret = clk_prepare_enable(kmi->clk);
 	if (ret)
 		goto out;
 
@@ -92,7 +92,7 @@ static int amba_kmi_open(struct serio *io)
 	return 0;
 
  clk_disable:
-	clk_disable(kmi->clk);
+	clk_disable_unprepare(kmi->clk);
  out:
 	return ret;
 }
@@ -104,7 +104,7 @@ static void amba_kmi_close(struct serio *io)
 	writeb(0, KMICR);
 
 	free_irq(kmi->irq, kmi);
-	clk_disable(kmi->clk);
+	clk_disable_unprepare(kmi->clk);
 }
 
 static int __devinit amba_kmi_probe(struct amba_device *dev,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 02/13] video: Versatile Express display output driver
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 01/13] input: ambakmi: (Un)prepare clocks when (dis)enabling Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 03/13] hwmon: Versatile Express hwmon driver Pawel Moll
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

Versatile Express' DVI video output can be connected to one the three
sources - motherboard's CLCD controller or a video signal generated
by one of the daughterboards.

This driver configures the muxer FPGA so the output displays
content of one of the framebuffers in the system (0 by default,
can be changed by user writing to "fb" attribute of the muxfpga
device). The decision is based on an educated guess in case of
DT-less system or on the "arm,vexpress,site" property of the
display controller's DT node.

It will also set up the display formatter mode and keep it up
to date with mode changes requested by the user (eg. with fbset
tool).

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/video/Makefile       |    3 +
 drivers/video/vexpress-dvi.c |  208 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 211 insertions(+)
 create mode 100644 drivers/video/vexpress-dvi.c

Hi Florian,

Assuming it's not totally crap ;-) what would be you preference about
merging this patch? Would you take it through your tree?

Regards

Pawel

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ee8dafb..01d28d5 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -170,3 +170,6 @@ obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
 
 #video output switch sysfs driver
 obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
+
+# platform specific output drivers
+obj-$(CONFIG_VEXPRESS_CONFIG)	  += vexpress-dvi.o
diff --git a/drivers/video/vexpress-dvi.c b/drivers/video/vexpress-dvi.c
new file mode 100644
index 0000000..fc50fc6
--- /dev/null
+++ b/drivers/video/vexpress-dvi.c
@@ -0,0 +1,208 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-dvi: " fmt
+
+#include <linux/fb.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/vexpress.h>
+
+
+static struct vexpress_config_func *vexpress_dvimode_func;
+
+static struct {
+	u32 xres, yres, mode;
+} vexpress_dvi_dvimodes[] = {
+	{ 640, 480, 0 }, /* VGA */
+	{ 800, 600, 1 }, /* SVGA */
+	{ 1024, 768, 2 }, /* XGA */
+	{ 1280, 1024, 3 }, /* SXGA */
+	{ 1600, 1200, 4 }, /* UXGA */
+	{ 1920, 1080, 5 }, /* HD1080 */
+};
+
+static void vexpress_dvi_mode_set(struct fb_info *info, u32 xres, u32 yres)
+{
+	int err = -ENOENT;
+	int i;
+
+	if (!vexpress_dvimode_func)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_dvi_dvimodes); i++) {
+		if (vexpress_dvi_dvimodes[i].xres == xres &&
+				vexpress_dvi_dvimodes[i].yres == yres) {
+			pr_debug("mode: %ux%u = %d\n", xres, yres,
+					vexpress_dvi_dvimodes[i].mode);
+			err = vexpress_config_write(vexpress_dvimode_func, 0,
+					vexpress_dvi_dvimodes[i].mode);
+			break;
+		}
+	}
+
+	if (err)
+		pr_warn("Failed to set %ux%u mode! (%d)\n", xres, yres, err);
+}
+
+
+static struct vexpress_config_func *vexpress_muxfpga_func;
+static int vexpress_dvi_fb = -1;
+
+static int vexpress_dvi_mux_set(struct fb_info *info)
+{
+	u32 site = vexpress_get_site_by_dev(info->device);
+	int err = vexpress_config_write(vexpress_muxfpga_func, 0, site);
+
+	if (!err) {
+		pr_debug("Selected MUXFPGA input %d (fb%d)\n", site,
+				info->node);
+		vexpress_dvi_fb = info->node;
+		vexpress_dvi_mode_set(info, info->var.xres,
+				info->var.yres);
+	} else {
+		pr_warn("Failed to select MUXFPGA input %d (fb%d)! (%d)\n",
+				site, info->node, err);
+	}
+
+	return err;
+}
+
+static int vexpress_dvi_fb_select(int fb)
+{
+	int err;
+	struct fb_info *info = registered_fb[fb];
+
+	if (!info || !lock_fb_info(info))
+		return -ENODEV;
+
+	err = vexpress_dvi_mux_set(info);
+
+	unlock_fb_info(info);
+
+	return err;
+}
+
+static ssize_t vexpress_dvi_fb_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", vexpress_dvi_fb);
+}
+
+static ssize_t vexpress_dvi_fb_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	long value;
+	int err = kstrtol(buf, 0, &value);
+
+	if (!err)
+		err = vexpress_dvi_fb_select(value);
+
+	return err ? err : count;
+}
+
+DEVICE_ATTR(fb, S_IRUGO | S_IWUSR, vexpress_dvi_fb_show,
+		vexpress_dvi_fb_store);
+
+
+static int vexpress_dvi_fb_event_notify(struct notifier_block *self,
+			      unsigned long action, void *data)
+{
+	struct fb_event *event = data;
+	struct fb_info *info = event->info;
+	struct fb_videomode *mode = event->data;
+
+	switch (action) {
+	case FB_EVENT_FB_REGISTERED:
+		if (vexpress_dvi_fb < 0)
+			vexpress_dvi_mux_set(info);
+		break;
+	case FB_EVENT_MODE_CHANGE:
+	case FB_EVENT_MODE_CHANGE_ALL:
+		if (info->node == vexpress_dvi_fb)
+			vexpress_dvi_mode_set(info, mode->xres, mode->yres);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block vexpress_dvi_fb_notifier = {
+	.notifier_call = vexpress_dvi_fb_event_notify,
+};
+
+
+enum vexpress_dvi_func { FUNC_MUXFPGA, FUNC_DVIMODE };
+
+static struct of_device_id vexpress_dvi_of_match[] = {
+	{
+		.compatible = "arm,vexpress-muxfpga",
+		.data = (void *)FUNC_MUXFPGA,
+	}, {
+		.compatible = "arm,vexpress-dvimode",
+		.data = (void *)FUNC_DVIMODE,
+	},
+	{}
+};
+
+static int vexpress_dvi_probe(struct platform_device *pdev)
+{
+	enum vexpress_dvi_func func;
+	const struct of_device_id *match =
+			of_match_device(vexpress_dvi_of_match, &pdev->dev);
+
+	if (match)
+		func = (enum vexpress_dvi_func)match->data;
+	else
+		func = pdev->id_entry->driver_data;
+
+	switch (func) {
+	case FUNC_MUXFPGA:
+		vexpress_muxfpga_func =
+				vexpress_config_func_get_by_dev(&pdev->dev);
+		device_create_file(&pdev->dev, &dev_attr_fb);
+		break;
+	case FUNC_DVIMODE:
+		vexpress_dvimode_func =
+				vexpress_config_func_get_by_dev(&pdev->dev);
+		break;
+	}
+
+	if (vexpress_muxfpga_func && vexpress_dvimode_func) {
+		fb_register_client(&vexpress_dvi_fb_notifier);
+		vexpress_dvi_fb_select(0);
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id vexpress_dvi_id_table[] = {
+	{ .name = "vexpress-muxfpga", .driver_data = FUNC_MUXFPGA, },
+	{ .name = "vexpress-dvimode", .driver_data = FUNC_DVIMODE, },
+	{}
+};
+
+static struct platform_driver vexpress_dvi_driver = {
+	.probe = vexpress_dvi_probe,
+	.driver = {
+		.name = "vexpress-dvi",
+		.of_match_table = vexpress_dvi_of_match,
+	},
+	.id_table = vexpress_dvi_id_table,
+};
+
+static int __init vexpress_dvi_init(void)
+{
+	return platform_driver_register(&vexpress_dvi_driver);
+}
+device_initcall(vexpress_dvi_init);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 03/13] hwmon: Versatile Express hwmon driver
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 01/13] input: ambakmi: (Un)prepare clocks when (dis)enabling Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 02/13] video: Versatile Express display output driver Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 15:24   ` Guenter Roeck
  2012-09-18 14:17 ` [PATCH v2 04/13] regulators: Versatile Express regulator driver Pawel Moll
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

hwmon framework driver for Versatile Express sensors, providing
information about board level voltage (only when regulator driver
is not configured), currents, temperature and power/energy usage.
Labels for the values can be defined as DT properties.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/hwmon/Kconfig    |    8 ++
 drivers/hwmon/Makefile   |    1 +
 drivers/hwmon/vexpress.c |  330 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 339 insertions(+)
 create mode 100644 drivers/hwmon/vexpress.c

Hi Jean, Guenter,

Would you be able to merge this in time for 3.7? (if it looks fine, that is)

Regards

Pawel

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index b0a2e4c..7359a07 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1187,6 +1187,14 @@ config SENSORS_TWL4030_MADC
 	This driver can also be built as a module. If so it will be called
 	twl4030-madc-hwmon.
 
+config SENSORS_VEXPRESS
+	tristate "Versatile Express"
+	depends on VEXPRESS_CONFIG
+	help
+	  This driver provides support for hardware sensors available on
+	  the ARM Ltd's Versatile Express platform. It can provide wide
+	  range of information like temperature, power, energy.
+
 config SENSORS_VIA_CPUTEMP
 	tristate "VIA CPU temperature sensor"
 	depends on X86
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 7aa9811..e719a7d 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -120,6 +120,7 @@ obj-$(CONFIG_SENSORS_TMP102)	+= tmp102.o
 obj-$(CONFIG_SENSORS_TMP401)	+= tmp401.o
 obj-$(CONFIG_SENSORS_TMP421)	+= tmp421.o
 obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
+obj-$(CONFIG_SENSORS_VEXPRESS)	+= vexpress.o
 obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
 obj-$(CONFIG_SENSORS_VT1211)	+= vt1211.o
diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c
new file mode 100644
index 0000000..fe80c63
--- /dev/null
+++ b/drivers/hwmon/vexpress.c
@@ -0,0 +1,330 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#define DRVNAME "vexpress-hwmon"
+#define pr_fmt(fmt) DRVNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/vexpress.h>
+
+static struct device *vexpress_hwmon_dev;
+static int vexpress_hwmon_dev_refcount;
+static DEFINE_SPINLOCK(vexpress_hwmon_dev_lock);
+
+static ssize_t vexpress_hwmon_name_show(struct device *dev,
+		struct device_attribute *dev_attr, char *buffer)
+{
+	return sprintf(buffer, "%s\n", DRVNAME);
+}
+
+static struct device_attribute vexpress_hwmon_name_attr =
+		__ATTR(name, 0444, vexpress_hwmon_name_show, NULL);
+
+struct vexpress_hwmon_attrs {
+	struct vexpress_config_func *func;
+	const char *label;
+	struct device_attribute label_attr;
+	char label_name[16];
+	struct device_attribute input_attr;
+	char input_name[16];
+	u32 divisor;
+};
+
+static ssize_t vexpress_hwmon_label_show(struct device *dev,
+		struct device_attribute *dev_attr, char *buffer)
+{
+	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
+			struct vexpress_hwmon_attrs, label_attr);
+
+	return snprintf(buffer, PAGE_SIZE, "%s\n", attrs->label);
+}
+
+static ssize_t vexpress_hwmon_u32_show(struct device *dev,
+		struct device_attribute *dev_attr, char *buffer)
+{
+	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
+			struct vexpress_hwmon_attrs, input_attr);
+	int err;
+	u32 value;
+
+	err = vexpress_config_read(attrs->func, 0, &value);
+	if (err)
+		return err;
+
+	return snprintf(buffer, PAGE_SIZE, "%u\n", value / attrs->divisor);
+}
+
+static ssize_t vexpress_hwmon_u64_show(struct device *dev,
+		struct device_attribute *dev_attr, char *buffer)
+{
+	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
+			struct vexpress_hwmon_attrs, input_attr);
+	int err;
+	u32 value_hi, value_lo;
+
+	err = vexpress_config_read(attrs->func, 0, &value_lo);
+	if (err)
+		return err;
+
+	err = vexpress_config_read(attrs->func, 1, &value_hi);
+	if (err)
+		return err;
+
+	return snprintf(buffer, PAGE_SIZE, "%llu\n",
+			div_u64(((u64)value_hi << 32) | value_lo,
+			attrs->divisor));
+}
+
+static struct device *vexpress_hwmon_dev_get(void)
+{
+	struct device *result;
+
+	spin_lock(&vexpress_hwmon_dev_lock);
+
+	if (vexpress_hwmon_dev) {
+		result = vexpress_hwmon_dev;
+	} else {
+		int err;
+
+		result = hwmon_device_register(NULL);
+		if (IS_ERR(result))
+			goto out;
+
+		err = device_create_file(result, &vexpress_hwmon_name_attr);
+		if (err) {
+			result = ERR_PTR(err);
+			hwmon_device_unregister(result);
+			goto out;
+		}
+
+		vexpress_hwmon_dev = result;
+	}
+
+	vexpress_hwmon_dev_refcount++;
+
+out:
+	spin_unlock(&vexpress_hwmon_dev_lock);
+
+	return result;
+}
+
+static void vexpress_hwmon_dev_put(void)
+{
+	spin_lock(&vexpress_hwmon_dev_lock);
+
+	if (--vexpress_hwmon_dev_refcount == 0) {
+		hwmon_device_unregister(vexpress_hwmon_dev);
+		vexpress_hwmon_dev = NULL;
+	}
+
+	WARN_ON(vexpress_hwmon_dev_refcount < 0);
+
+	spin_unlock(&vexpress_hwmon_dev_lock);
+}
+
+struct vexpress_hwmon_func {
+	const char *name;
+	bool wide;
+	u32 divisor;
+	atomic_t index;
+};
+
+#if !defined(CONFIG_REGULATOR_VEXPRESS)
+static struct vexpress_hwmon_func vexpress_hwmon_volt = {
+	.name = "in",
+	.divisor = 1000,
+};
+#endif
+
+static struct vexpress_hwmon_func vexpress_hwmon_amp = {
+	.name = "curr",
+	.divisor = 1000,
+};
+
+static struct vexpress_hwmon_func vexpress_hwmon_temp = {
+	.name = "temp",
+	.divisor = 1000,
+};
+
+static struct vexpress_hwmon_func vexpress_hwmon_power = {
+	.name = "power",
+	.divisor = 1,
+};
+
+static struct vexpress_hwmon_func vexpress_hwmon_energy = {
+	.name = "energy",
+	.wide = true,
+	.divisor = 1,
+};
+
+static struct of_device_id vexpress_hwmon_of_match[] = {
+#if !defined(CONFIG_REGULATOR_VEXPRESS)
+	{
+		.compatible = "arm,vexpress-volt",
+		.data = &vexpress_hwmon_volt,
+	},
+#endif
+	{
+		.compatible = "arm,vexpress-amp",
+		.data = &vexpress_hwmon_amp,
+	}, {
+		.compatible = "arm,vexpress-temp",
+		.data = &vexpress_hwmon_temp,
+	}, {
+		.compatible = "arm,vexpress-power",
+		.data = &vexpress_hwmon_power,
+	}, {
+		.compatible = "arm,vexpress-energy",
+		.data = &vexpress_hwmon_energy,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match);
+
+static int vexpress_hwmon_probe(struct platform_device *pdev)
+{
+	int err;
+	const struct of_device_id *match;
+	struct vexpress_hwmon_func *hwmon_func;
+	struct device *hwmon_dev;
+	struct vexpress_hwmon_attrs *attrs;
+	const char *attr_name;
+	int attr_index;
+
+	match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
+	if (!match) {
+		err = -EINVAL;
+		goto error_match_device;
+	}
+	hwmon_func = match->data;
+
+	hwmon_dev = vexpress_hwmon_dev_get();
+	if (IS_ERR(hwmon_dev)) {
+		err = PTR_ERR(hwmon_dev);
+		goto error_hwmon_dev_get;
+	}
+
+	attrs = devm_kzalloc(&pdev->dev, sizeof(*attrs), GFP_KERNEL);
+	if (!attrs) {
+		err = -ENOMEM;
+		goto error_kzalloc;
+	}
+
+	attrs->func = vexpress_config_func_get_by_dev(&pdev->dev);
+	if (!attrs->func) {
+		err = -ENXIO;
+		goto error_get_func;
+	}
+
+	err = sysfs_create_link(&pdev->dev.kobj, &hwmon_dev->kobj, "hwmon");
+	if (err)
+		goto error_create_link;
+
+	attr_index = atomic_inc_return(&hwmon_func->index);
+	attr_name = hwmon_func->name;
+
+	snprintf(attrs->input_name, sizeof(attrs->input_name),
+			"%s%d_input", attr_name, attr_index);
+	attrs->input_attr.attr.name = attrs->input_name;
+	attrs->input_attr.attr.mode = 0444;
+	if (hwmon_func->wide)
+		attrs->input_attr.show = vexpress_hwmon_u64_show;
+	else
+		attrs->input_attr.show = vexpress_hwmon_u32_show;
+	sysfs_attr_init(&attrs->input_attr.attr);
+	err = device_create_file(hwmon_dev, &attrs->input_attr);
+	if (err)
+		goto error_create_input;
+
+	attrs->label = of_get_property(pdev->dev.of_node, "label", NULL);
+	if (attrs->label) {
+		snprintf(attrs->label_name, sizeof(attrs->label_name),
+				"%s%d_label", attr_name, attr_index);
+		attrs->label_attr.attr.name = attrs->label_name;
+		attrs->label_attr.attr.mode = 0444;
+		attrs->label_attr.show = vexpress_hwmon_label_show;
+		sysfs_attr_init(&attrs->label_attr.attr);
+		err = device_create_file(hwmon_dev, &attrs->label_attr);
+		if (err)
+			goto error_create_label;
+	}
+
+	attrs->divisor = hwmon_func->divisor;
+
+	platform_set_drvdata(pdev, attrs);
+
+	return 0;
+
+error_create_label:
+	device_remove_file(hwmon_dev, &attrs->input_attr);
+error_create_input:
+	sysfs_remove_link(&pdev->dev.kobj, "hwmon");
+error_create_link:
+	vexpress_config_func_put(attrs->func);
+error_get_func:
+error_kzalloc:
+	vexpress_hwmon_dev_put();
+error_hwmon_dev_get:
+error_match_device:
+	return err;
+}
+
+static int __devexit vexpress_hwmon_remove(struct platform_device *pdev)
+{
+	struct vexpress_hwmon_attrs *attrs = platform_get_drvdata(pdev);
+	const struct of_device_id *match =
+		of_match_device(vexpress_hwmon_of_match, &pdev->dev);
+	struct vexpress_hwmon_func *hwmon_func = match->data;
+
+	if (attrs->label)
+		device_remove_file(vexpress_hwmon_dev, &attrs->label_attr);
+	device_remove_file(vexpress_hwmon_dev, &attrs->input_attr);
+	atomic_dec(&hwmon_func->index);
+	sysfs_remove_link(&pdev->dev.kobj, "hwmon");
+	vexpress_config_func_put(attrs->func);
+	vexpress_hwmon_dev_put();
+
+	return 0;
+}
+
+static struct platform_driver vexpress_hwmon_driver = {
+	.probe = vexpress_hwmon_probe,
+	.remove = __devexit_p(vexpress_hwmon_remove),
+	.driver	= {
+		.name = DRVNAME,
+		.owner = THIS_MODULE,
+		.of_match_table = vexpress_hwmon_of_match,
+	},
+};
+
+static int __init vexpress_hwmon_init(void)
+{
+	return platform_driver_register(&vexpress_hwmon_driver);
+}
+
+static void __exit vexpress_hwmon_exit(void)
+{
+	platform_driver_unregister(&vexpress_hwmon_driver);
+}
+
+MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
+MODULE_DESCRIPTION("Versatile Express hwmon");
+MODULE_LICENSE("GPL");
+
+module_init(vexpress_hwmon_init);
+module_exit(vexpress_hwmon_exit);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (2 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 03/13] hwmon: Versatile Express hwmon driver Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 15:02   ` Mark Brown
  2012-09-18 14:17 ` [PATCH v2 05/13] clk: Versatile Express clock generators ("osc") driver Pawel Moll
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

Implementation of the regulator framework driver for the
Versatile Express voltage control. Devices without
voltage constraints (ie. "regulator-[min|max]-microvolt"
properties in the DT node) are treated as fixed (or rather
read-only) regulators.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/regulator/Kconfig    |    7 ++
 drivers/regulator/Makefile   |    1 +
 drivers/regulator/vexpress.c |  155 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 163 insertions(+)
 create mode 100644 drivers/regulator/vexpress.c

Hi Liam, Mark,

Do you think it would be possible to have this merged in time for 3.7?

Cheers!

Pawel

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 4e932cc..a823951 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -404,6 +404,13 @@ config REGULATOR_TWL4030
 	  This driver supports the voltage regulators provided by
 	  this family of companion chips.
 
+config REGULATOR_VEXPRESS
+	tristate "Versatile Express regulators"
+	depends on VEXPRESS_CONFIG
+	help
+	  This driver provides support for voltage regulators available
+	  on the ARM Ltd's Versatile Express platform.
+
 config REGULATOR_WM831X
 	tristate "Wolfson Microelectronics WM831x PMIC regulators"
 	depends on MFD_WM831X
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 3342615..0d4e10f 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
 obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
+obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c
new file mode 100644
index 0000000..a2682bb
--- /dev/null
+++ b/drivers/regulator/vexpress.c
@@ -0,0 +1,155 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#define DRVNAME "vexpress-regulator"
+#define pr_fmt(fmt) DRVNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/vexpress.h>
+
+struct vexpress_regulator {
+	struct regulator_desc desc;
+	struct regulator_dev *regdev;
+	struct vexpress_config_func *func;
+};
+
+static int vexpress_regulator_get_voltage(struct regulator_dev *regdev)
+{
+	struct vexpress_regulator *reg = rdev_get_drvdata(regdev);
+	u32 uV;
+	int err = vexpress_config_read(reg->func, 0, &uV);
+
+	return err ? err : uV;
+}
+
+static int vexpress_regulator_set_voltage(struct regulator_dev *regdev,
+		int min_uV, int max_uV, unsigned *selector)
+{
+	struct vexpress_regulator *reg = rdev_get_drvdata(regdev);
+
+	return vexpress_config_write(reg->func, 0, min_uV);
+}
+
+static struct regulator_ops vexpress_regulator_ops_ro = {
+	.get_voltage = vexpress_regulator_get_voltage,
+};
+
+static struct regulator_ops vexpress_regulator_ops = {
+	.get_voltage = vexpress_regulator_get_voltage,
+	.set_voltage = vexpress_regulator_set_voltage,
+};
+
+static int vexpress_regulator_probe(struct platform_device *pdev)
+{
+	int err;
+	struct vexpress_regulator *reg;
+	struct regulator_init_data *init_data;
+	struct regulator_config config = { };
+
+	reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL);
+	if (!reg) {
+		err = -ENOMEM;
+		goto error_kzalloc;
+	}
+
+	reg->func = vexpress_config_func_get_by_dev(&pdev->dev);
+	if (!reg->func) {
+		err = -ENXIO;
+		goto error_get_func;
+	}
+
+	reg->desc.name = dev_name(&pdev->dev);
+	reg->desc.type = REGULATOR_VOLTAGE;
+	reg->desc.owner = THIS_MODULE;
+
+	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+	if (!init_data) {
+		err = -EINVAL;
+		goto error_get_regulator_init_data;
+	}
+
+	init_data->constraints.apply_uV = 0;
+	if (init_data->constraints.min_uV && init_data->constraints.max_uV)
+		reg->desc.ops = &vexpress_regulator_ops;
+	else
+		reg->desc.ops = &vexpress_regulator_ops_ro;
+
+	config.dev = &pdev->dev;
+	config.init_data = init_data;
+	config.driver_data = reg;
+	config.of_node = pdev->dev.of_node;
+
+	reg->regdev = regulator_register(&reg->desc, &config);
+	if (IS_ERR(reg->regdev)) {
+		err = PTR_ERR(reg->regdev);
+		goto error_regulator_register;
+	}
+
+	platform_set_drvdata(pdev, reg);
+
+	return 0;
+
+error_regulator_register:
+error_get_regulator_init_data:
+	vexpress_config_func_put(reg->func);
+error_get_func:
+error_kzalloc:
+	return err;
+}
+
+static int __devexit vexpress_regulator_remove(struct platform_device *pdev)
+{
+	struct vexpress_regulator *reg = platform_get_drvdata(pdev);
+
+	vexpress_config_func_put(reg->func);
+	regulator_unregister(reg->regdev);
+
+	return 0;
+}
+
+static struct of_device_id vexpress_regulator_of_match[] = {
+	{ .compatible = "arm,vexpress-volt", },
+};
+
+static struct platform_driver vexpress_regulator_driver = {
+	.probe = vexpress_regulator_probe,
+	.remove = __devexit_p(vexpress_regulator_remove),
+	.driver	= {
+		.name = DRVNAME,
+		.owner = THIS_MODULE,
+		.of_match_table = vexpress_regulator_of_match,
+	},
+};
+
+static int __init vexpress_regulator_init(void)
+{
+	return platform_driver_register(&vexpress_regulator_driver);
+}
+
+static void __exit vexpress_regulator_exit(void)
+{
+	platform_driver_unregister(&vexpress_regulator_driver);
+}
+
+MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
+MODULE_DESCRIPTION("Versatile Express regulator");
+MODULE_LICENSE("GPL");
+
+module_init(vexpress_regulator_init);
+module_exit(vexpress_regulator_exit);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 05/13] clk: Versatile Express clock generators ("osc") driver
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (3 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 04/13] regulators: Versatile Express regulator driver Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-10-29 17:44   ` Mike Turquette
  2012-09-18 14:17 ` [PATCH v2 06/13] clk: Common clocks implementation for Versatile Express Pawel Moll
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

This driver provides a common clock framework hardware driver
for Versatile Express clock generators (a.k.a "osc") controlled
via the config bus.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/clk/versatile/Makefile           |    1 +
 drivers/clk/versatile/clk-vexpress-osc.c |  146 ++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+)
 create mode 100644 drivers/clk/versatile/clk-vexpress-osc.c

Hi Mike,

As agreed - this patch and the next one ("clk: Common clocks
implementation for Versatile Express") are all yours.

Regards

Pawel

diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index c0a0f64..1e49a7a 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -2,3 +2,4 @@
 obj-$(CONFIG_ICST)		+= clk-icst.o
 obj-$(CONFIG_ARCH_INTEGRATOR)	+= clk-integrator.o
 obj-$(CONFIG_ARCH_REALVIEW)	+= clk-realview.o
+obj-$(CONFIG_VEXPRESS_CONFIG)	+= clk-vexpress-osc.o
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
new file mode 100644
index 0000000..dcb6ae0
--- /dev/null
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -0,0 +1,146 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-osc: " fmt
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/vexpress.h>
+
+struct vexpress_osc {
+	struct vexpress_config_func *func;
+	struct clk_hw hw;
+	unsigned long rate_min;
+	unsigned long rate_max;
+};
+
+#define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw)
+
+static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct vexpress_osc *osc = to_vexpress_osc(hw);
+	u32 rate;
+
+	vexpress_config_read(osc->func, 0, &rate);
+
+	return rate;
+}
+
+static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *parent_rate)
+{
+	struct vexpress_osc *osc = to_vexpress_osc(hw);
+
+	if (WARN_ON(osc->rate_min && rate < osc->rate_min))
+		rate = osc->rate_min;
+
+	if (WARN_ON(osc->rate_max && rate > osc->rate_max))
+		rate = osc->rate_max;
+
+	return rate;
+}
+
+static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct vexpress_osc *osc = to_vexpress_osc(hw);
+
+	return vexpress_config_write(osc->func, 0, rate);
+}
+
+static struct clk_ops vexpress_osc_ops = {
+	.recalc_rate = vexpress_osc_recalc_rate,
+	.round_rate = vexpress_osc_round_rate,
+	.set_rate = vexpress_osc_set_rate,
+};
+
+
+struct clk * __init vexpress_osc_setup(struct device *dev)
+{
+	struct clk_init_data init;
+	struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+
+	if (!osc)
+		return NULL;
+
+	osc->func = vexpress_config_func_get_by_dev(dev);
+	if (!osc->func) {
+		kfree(osc);
+		return NULL;
+	}
+
+	init.name = dev_name(dev);
+	init.ops = &vexpress_osc_ops;
+	init.flags = CLK_IS_ROOT;
+	init.num_parents = 0;
+	osc->hw.init = &init;
+
+	return clk_register(NULL, &osc->hw);
+}
+
+void __init vexpress_osc_of_setup(struct device_node *node)
+{
+	struct clk_init_data init;
+	struct vexpress_osc *osc;
+	struct clk *clk;
+	u32 range[2];
+
+	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+	if (!osc)
+		goto error;
+
+	osc->func = vexpress_config_func_get_by_node(node);
+	if (!osc->func) {
+		pr_err("Failed to obtain config func for node '%s'!\n",
+				node->name);
+		goto error;
+	}
+
+	if (of_property_read_u32_array(node, "freq-range", range,
+			ARRAY_SIZE(range)) == 0) {
+		osc->rate_min = range[0];
+		osc->rate_max = range[1];
+	}
+
+	of_property_read_string(node, "clock-output-names", &init.name);
+	if (!init.name)
+		init.name = node->name;
+
+	init.ops = &vexpress_osc_ops;
+	init.flags = CLK_IS_ROOT;
+	init.num_parents = 0;
+
+	osc->hw.init = &init;
+
+	clk = clk_register(NULL, &osc->hw);
+	if (IS_ERR(clk)) {
+		pr_err("Failed to register clock '%s'!\n", init.name);
+		goto error;
+	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+	pr_debug("Registered clock '%s'\n", init.name);
+
+	return;
+
+error:
+	if (osc->func)
+		vexpress_config_func_put(osc->func);
+	kfree(osc);
+}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 06/13] clk: Common clocks implementation for Versatile Express
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (4 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 05/13] clk: Versatile Express clock generators ("osc") driver Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 07/13] misc: Versatile Express config infrastructure Pawel Moll
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds a DT and non-DT based implementation of
the common clock infrastructure for Versatile Express
platform. It registers (statically or using DT) all
required fixed clocks, initialises motherboard's SP810
cell (that provides clocks for SP804 timers) and
explicitly registers VE "osc" driver, to make the
clock generators available early.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 arch/arm/include/asm/hardware/sp810.h |    2 +
 drivers/clk/Kconfig                   |    8 +-
 drivers/clk/versatile/Makefile        |    1 +
 drivers/clk/versatile/clk-vexpress.c  |  142 +++++++++++++++++++++++++++++++++
 4 files changed, 150 insertions(+), 3 deletions(-)
 create mode 100644 drivers/clk/versatile/clk-vexpress.c

diff --git a/arch/arm/include/asm/hardware/sp810.h b/arch/arm/include/asm/hardware/sp810.h
index 6b9b077..afd7e91 100644
--- a/arch/arm/include/asm/hardware/sp810.h
+++ b/arch/arm/include/asm/hardware/sp810.h
@@ -56,6 +56,8 @@
 #define SCCTRL_TIMEREN1SEL_REFCLK	(0 << 17)
 #define SCCTRL_TIMEREN1SEL_TIMCLK	(1 << 17)
 
+#define SCCTRL_TIMERENnSEL_SHIFT(n)	(15 + ((n) * 2))
+
 static inline void sysctl_soft_reset(void __iomem *base)
 {
 	/* switch to slow mode */
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 89b726d..3e4eda2 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -42,9 +42,11 @@ config COMMON_CLK_WM831X
 
 config COMMON_CLK_VERSATILE
 	tristate "Clock driver for ARM Reference designs"
-	depends on ARCH_INTEGRATOR || ARCH_REALVIEW
+	depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS
 	---help---
-          Supports clocking on ARM Reference designs Integrator/AP,
-	  Integrator/CP, RealView PB1176, EB, PB11MP and PBX.
+          Supports clocking on ARM Reference designs:
+	  - Integrator/AP and Integrator/CP
+	  - RealView PB1176, EB, PB11MP and PBX
+	  - Versatile Express
 
 endmenu
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index 1e49a7a..c776053 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -2,4 +2,5 @@
 obj-$(CONFIG_ICST)		+= clk-icst.o
 obj-$(CONFIG_ARCH_INTEGRATOR)	+= clk-integrator.o
 obj-$(CONFIG_ARCH_REALVIEW)	+= clk-realview.o
+obj-$(CONFIG_ARCH_VEXPRESS)	+= clk-vexpress.o
 obj-$(CONFIG_VEXPRESS_CONFIG)	+= clk-vexpress-osc.o
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c
new file mode 100644
index 0000000..c742ac7
--- /dev/null
+++ b/drivers/clk/versatile/clk-vexpress.c
@@ -0,0 +1,142 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/vexpress.h>
+
+#include <asm/hardware/sp810.h>
+
+static struct clk *vexpress_sp810_timerclken[4];
+static DEFINE_SPINLOCK(vexpress_sp810_lock);
+
+static void __init vexpress_sp810_init(void __iomem *base)
+{
+	int i;
+
+	if (WARN_ON(!base))
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) {
+		char name[12];
+		const char *parents[] = {
+			"v2m:refclk32khz", /* REFCLK */
+			"v2m:refclk1mhz" /* TIMCLK */
+		};
+
+		snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
+
+		vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name,
+				parents, 2, 0, base + SCCTRL,
+				SCCTRL_TIMERENnSEL_SHIFT(i), 1,
+				0, &vexpress_sp810_lock);
+
+		if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i])))
+			break;
+	}
+}
+
+
+static const char * const vexpress_clk_24mhz_periphs[] __initconst = {
+	"mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3",
+	"mb:mmci", "mb:kmi0", "mb:kmi1"
+};
+
+void __init vexpress_clk_init(void __iomem *sp810_base)
+{
+	struct clk *clk;
+	int i;
+
+	clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
+			CLK_IS_ROOT, 0);
+	WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL));
+
+	clk = clk_register_fixed_rate(NULL, "v2m:clk_24mhz", NULL,
+			CLK_IS_ROOT, 24000000);
+	for (i = 0; i < ARRAY_SIZE(vexpress_clk_24mhz_periphs); i++)
+		WARN_ON(clk_register_clkdev(clk, NULL,
+				vexpress_clk_24mhz_periphs[i]));
+
+	clk = clk_register_fixed_rate(NULL, "v2m:refclk32khz", NULL,
+			CLK_IS_ROOT, 32768);
+	WARN_ON(clk_register_clkdev(clk, NULL, "v2m:wdt"));
+
+	clk = clk_register_fixed_rate(NULL, "v2m:refclk1mhz", NULL,
+			CLK_IS_ROOT, 1000000);
+
+	vexpress_sp810_init(sp810_base);
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
+		WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], clk));
+
+	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
+				"v2m-timer0", "sp804"));
+	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
+				"v2m-timer1", "sp804"));
+}
+
+#if defined(CONFIG_OF)
+
+struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data)
+{
+	if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] >
+			ARRAY_SIZE(vexpress_sp810_timerclken)))
+		return NULL;
+
+	return vexpress_sp810_timerclken[clkspec->args[0]];
+}
+
+static const __initconst struct of_device_id vexpress_fixed_clk_match[] = {
+	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+	{ .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, },
+	{}
+};
+
+void __init vexpress_clk_of_init(void)
+{
+	struct device_node *node;
+	struct clk *clk;
+	struct clk *refclk, *timclk;
+
+	of_clk_init(vexpress_fixed_clk_match);
+
+	node = of_find_compatible_node(NULL, NULL, "arm,sp810");
+	vexpress_sp810_init(of_iomap(node, 0));
+	of_clk_add_provider(node, vexpress_sp810_of_get, NULL);
+
+	/* Select "better" (faster) parent for SP804 timers */
+	refclk = of_clk_get_by_name(node, "refclk");
+	timclk = of_clk_get_by_name(node, "timclk");
+	if (!WARN_ON(IS_ERR(refclk) || IS_ERR(timclk))) {
+		int i = 0;
+
+		if (clk_get_rate(refclk) > clk_get_rate(timclk))
+			clk = refclk;
+		else
+			clk = timclk;
+
+		for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
+			WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i],
+					clk));
+	}
+
+	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
+				"v2m-timer0", "sp804"));
+	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
+				"v2m-timer1", "sp804"));
+}
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 07/13] misc: Versatile Express config infrastructure
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (5 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 06/13] clk: Common clocks implementation for Versatile Express Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-19 13:08   ` Arnd Bergmann
  2012-09-18 14:17 ` [PATCH v2 08/13] mfd: Versatile Express system registers driver Pawel Moll
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

Versatile Express platform has an elaborated configuration system,
consisting of microcontrollers residing on the mother- and
daughterboards known as Motherboard/Daughterboard Configuration
Controller (MCC and DCC). The controllers are responsible for
the platform initialization (reset generation, flash programming,
FPGA bitfiles loading etc.) but also control clock generators,
voltage regulators, gather environmental data like temperature,
power consumption etc. Even the video output switch (FPGA) is
controlled that way.

Those devices are _not_ visible in the main address space and
the usual communication channel uses some kind of a bridge in
the peripheral block sending commands (requests) to the
controllers and receiving responses. It can take up to
500 microseconds for a transaction to be completed, therefore
it is important to provide a non-blocking interface to it.

This patch adds an abstraction of this infrastructure. Bridge
drivers can register themselves with the framework. Then,
a driver of a device can request an abstract "function" - the
request will be redirected to a bridge referred by thedd
"arm,vexpress,config-bridge" property of the device tree node.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 Documentation/devicetree/bindings/arm/vexpress.txt |   68 ++++-
 drivers/misc/Kconfig                               |    6 +
 drivers/misc/Makefile                              |    1 +
 drivers/misc/vexpress-config.c                     |  276 ++++++++++++++++++++
 include/linux/vexpress.h                           |   64 +++++
 5 files changed, 414 insertions(+), 1 deletion(-)
 create mode 100644 drivers/misc/vexpress-config.c
 create mode 100644 include/linux/vexpress.h

Hi Arnd,

As it doesn't seem to be a "bus" any more, I left it in in misc for
now... It looks to me like there should be some kind of place for
"system/soc control" drivers. Or maybe there is, and I just missed
it?

Cheers!

Pawel

diff --git a/Documentation/devicetree/bindings/arm/vexpress.txt b/Documentation/devicetree/bindings/arm/vexpress.txt
index ec8b50c..5d9996b 100644
--- a/Documentation/devicetree/bindings/arm/vexpress.txt
+++ b/Documentation/devicetree/bindings/arm/vexpress.txt
@@ -11,6 +11,10 @@ the motherboard file using a /include/ directive. As the motherboard
 can be initialized in one of two different configurations ("memory
 maps"), care must be taken to include the correct one.
 
+
+Root node
+---------
+
 Required properties in the root node:
 - compatible value:
 	compatible = "arm,vexpress,<model>", "arm,vexpress";
@@ -45,6 +49,10 @@ Optional properties in the root node:
   - Coretile Express A9x4 (V2P-CA9) HBI-0225:
 	arm,hbi = <0x225>;
 
+
+CPU nodes
+---------
+
 Top-level standard "cpus" node is required. It must contain a node
 with device_type = "cpu" property for every available core, eg.:
 
@@ -59,6 +67,52 @@ with device_type = "cpu" property for every available core, eg.:
 		};
 	};
 
+
+Configuration infrastructure
+----------------------------
+
+The platform has an elaborated configuration system, consisting of
+microcontrollers residing on the mother- and daughterboards known
+as Motherboard/Daughterboard Configuration Controller (MCC and DCC).
+The controllers are responsible for the platform initialization
+(reset generation, flash programming, FPGA bitfiles loading etc.)
+but also control clock generators, voltage regulators, gather
+environmental data like temperature, power consumption etc. Even
+the video output switch (FPGA) is controlled that way.
+
+Nodes describing devices controlled by this infrastructure should
+point at the bridge device node:
+- bridge phandle:
+	arm,vexpress,config-bridge = <phandle>;
+This property can be also defined in a parent node (eg. for a DCC)
+and is effective for all children.
+
+
+Platform topology
+-----------------
+
+As Versatile Express can be configured in number of physically
+different setups, the device tree should describe platform topology.
+Root node and main motherboard node must define the following
+property, describing physical location of the children nodes:
+- site number:
+	arm,vexpress,site = <number>;
+  where 0 means motherboard, 1 or 2 are daugtherboard sites,
+  0xf means "master" site (site containing main CPU tile)
+- when daughterboards are stacked on one site, their position
+  in the stack be be described with:
+	arm,vexpress,position = <number>;
+- when describing tiles consisting more than one DCC, its number
+  can be described with:
+	arm,vexpress,dcc = <number>;
+
+Any of the numbers above defaults to zero if not defined in
+the node or any of its parent.
+
+
+Motherboard
+-----------
+
 The motherboard description file provides a single "motherboard" node
 using 2 address cells corresponding to the Static Memory Bus used
 between the motherboard and the tile. The first cell defines the Chip
@@ -96,13 +150,16 @@ The tile description must define "ranges", "interrupt-map-mask" and
 "interrupt-map" properties to translate the motherboard's address
 and interrupt space into one used by the tile's processor.
 
-Abbreviated example:
+
+Example of a VE tile description (simplified)
+---------------------------------------------
 
 /dts-v1/;
 
 / {
 	model = "V2P-CA5s";
 	arm,hbi = <0x225>;
+	arm,vexpress,site = <0xf>;
 	compatible = "arm,vexpress-v2p-ca5s", "arm,vexpress";
 	interrupt-parent = <&gic>;
 	#address-cells = <1>;
@@ -134,6 +191,15 @@ Abbreviated example:
 		      <0x2c000100 0x100>;
 	};
 
+	dcc {
+		compatible = "simple-bus";
+		arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+		osc at 0 {
+			compatible = "arm,vexpress-osc";
+		};
+	};
+
 	motherboard {
 		/* CS0 is visible at 0x08000000 */
 		ranges = <0 0 0x08000000 0x04000000>;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 98a442d..77274c9d 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -509,6 +509,12 @@ config USB_SWITCH_FSA9480
 	  stereo and mono audio, video, microphone and UART data to use
 	  a common connector port.
 
+config VEXPRESS_CONFIG
+	bool
+	help
+	  Platform configuration infrastructure for the ARM Ltd.
+	  Versatile Express.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b88df7a..dc180c6 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -50,3 +50,4 @@ obj-y				+= carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
 obj-$(CONFIG_ALTERA_STAPL)	+=altera-stapl/
 obj-$(CONFIG_INTEL_MEI)		+= mei/
+obj-$(CONFIG_VEXPRESS_CONFIG)	+= vexpress-config.o
diff --git a/drivers/misc/vexpress-config.c b/drivers/misc/vexpress-config.c
new file mode 100644
index 0000000..340cb2d
--- /dev/null
+++ b/drivers/misc/vexpress-config.c
@@ -0,0 +1,276 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-config: " fmt
+
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vexpress.h>
+
+
+#define VEXPRESS_CONFIG_MAX_BRIDGES 2
+
+struct vexpress_config_bridge {
+	struct device_node *node;
+	struct vexpress_config_bridge_info *info;
+	struct list_head transactions;
+	spinlock_t transactions_lock;
+} vexpress_config_bridges[VEXPRESS_CONFIG_MAX_BRIDGES];
+
+static DECLARE_BITMAP(vexpress_config_bridges_map,
+		ARRAY_SIZE(vexpress_config_bridges));
+static DEFINE_MUTEX(vexpress_config_bridges_mutex);
+
+struct vexpress_config_bridge *vexpress_config_bridge_register(
+		struct device_node *node,
+		struct vexpress_config_bridge_info *info)
+{
+	struct vexpress_config_bridge *bridge;
+	int i;
+
+	pr_debug("Registering bridge '%s'\n", info->name);
+
+	mutex_lock(&vexpress_config_bridges_mutex);
+	i = find_first_zero_bit(vexpress_config_bridges_map,
+			ARRAY_SIZE(vexpress_config_bridges));
+	if (i >= ARRAY_SIZE(vexpress_config_bridges)) {
+		pr_err("Can't register more bridges!\n");
+		mutex_unlock(&vexpress_config_bridges_mutex);
+		return NULL;
+	}
+	__set_bit(i, vexpress_config_bridges_map);
+	bridge = &vexpress_config_bridges[i];
+
+	bridge->node = node;
+	bridge->info = info;
+	INIT_LIST_HEAD(&bridge->transactions);
+	spin_lock_init(&bridge->transactions_lock);
+
+	mutex_unlock(&vexpress_config_bridges_mutex);
+
+	return bridge;
+}
+
+void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge)
+{
+	struct vexpress_config_bridge __bridge = *bridge;
+	int i;
+
+	mutex_lock(&vexpress_config_bridges_mutex);
+	for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++)
+		if (&vexpress_config_bridges[i] == bridge)
+			__clear_bit(i, vexpress_config_bridges_map);
+	mutex_unlock(&vexpress_config_bridges_mutex);
+
+	WARN_ON(!list_empty(&__bridge.transactions));
+	while (!list_empty(&__bridge.transactions))
+		cpu_relax();
+}
+
+
+struct vexpress_config_func {
+	struct vexpress_config_bridge *bridge;
+	void *func;
+};
+
+struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
+		struct device_node *node)
+{
+	struct device_node *bridge_node;
+	struct vexpress_config_func *func;
+	int i;
+
+	if (WARN_ON(dev && node && dev->of_node != node))
+		return NULL;
+	if (dev && !node)
+		node = dev->of_node;
+
+	func = kzalloc(sizeof(*func), GFP_KERNEL);
+	if (!func)
+		return NULL;
+
+	bridge_node = of_node_get(node);
+	while (bridge_node) {
+		const __be32 *prop = of_get_property(bridge_node,
+				"arm,vexpress,config-bridge", NULL);
+
+		if (prop) {
+			bridge_node = of_find_node_by_phandle(
+					be32_to_cpup(prop));
+			break;
+		}
+
+		bridge_node = of_get_next_parent(bridge_node);
+	}
+
+	mutex_lock(&vexpress_config_bridges_mutex);
+	for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++) {
+		struct vexpress_config_bridge *bridge =
+				&vexpress_config_bridges[i];
+
+		if (test_bit(i, vexpress_config_bridges_map) &&
+				bridge->node == bridge_node) {
+			func->bridge = bridge;
+			func->func = bridge->info->func_get(dev, node);
+			break;
+		}
+	}
+	mutex_unlock(&vexpress_config_bridges_mutex);
+
+	if (!func->func) {
+		of_node_put(node);
+		kfree(func);
+		return NULL;
+	}
+
+	return func;
+}
+
+void vexpress_config_func_put(struct vexpress_config_func *func)
+{
+	func->bridge->info->func_put(func->func);
+	of_node_put(func->bridge->node);
+	kfree(func);
+}
+
+
+struct vexpress_config_trans {
+	struct vexpress_config_func *func;
+	int offset;
+	bool write;
+	u32 *data;
+	int status;
+	struct completion completion;
+	struct list_head list;
+};
+
+static void vexpress_config_dump_trans(const char *what,
+		struct vexpress_config_trans *trans)
+{
+	pr_debug("%s %s trans %p func 0x%p offset %d data 0x%x status %d\n",
+			what, trans->write ? "write" : "read", trans,
+			trans->func->func, trans->offset,
+			trans->data ? *trans->data : 0, trans->status);
+}
+
+static int vexpress_config_schedule(struct vexpress_config_trans *trans)
+{
+	int res;
+	struct vexpress_config_bridge *bridge = trans->func->bridge;
+	unsigned long flags;
+
+	init_completion(&trans->completion);
+	trans->status = -EFAULT;
+
+	spin_lock_irqsave(&bridge->transactions_lock, flags);
+
+	vexpress_config_dump_trans("Executing", trans);
+
+	if (list_empty(&bridge->transactions))
+		res = bridge->info->func_exec(trans->func->func, trans->offset,
+				trans->write, trans->data);
+	else
+		res = VEXPRESS_CONFIG_EXEC_WAIT;
+
+	switch (res) {
+	case VEXPRESS_CONFIG_EXEC_DONE:
+		vexpress_config_dump_trans("Finished", trans);
+		res = trans->status;
+		break;
+	case VEXPRESS_CONFIG_EXEC_WAIT:
+		list_add_tail(&trans->list, &bridge->transactions);
+		break;
+	}
+
+	spin_unlock_irqrestore(&bridge->transactions_lock, flags);
+
+	return res;
+}
+
+void vexpress_config_complete(struct vexpress_config_bridge *bridge,
+		int status)
+{
+	struct vexpress_config_trans *trans;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bridge->transactions_lock, flags);
+
+	trans = list_first_entry(&bridge->transactions,
+			struct vexpress_config_trans, list);
+	vexpress_config_dump_trans("Completed", trans);
+
+	trans->status = status;
+	list_del(&trans->list);
+
+	if (!list_empty(&bridge->transactions)) {
+		vexpress_config_dump_trans("Pending", trans);
+
+		bridge->info->func_exec(trans->func->func, trans->offset,
+				trans->write, trans->data);
+	}
+	spin_unlock_irqrestore(&bridge->transactions_lock, flags);
+
+	complete(&trans->completion);
+}
+
+int vexpress_config_wait(struct vexpress_config_trans *trans)
+{
+	wait_for_completion(&trans->completion);
+
+	return trans->status;
+}
+
+
+int vexpress_config_read(struct vexpress_config_func *func, int offset,
+		u32 *data)
+{
+	struct vexpress_config_trans trans = {
+		.func = func,
+		.offset = offset,
+		.write = false,
+		.data = data,
+		.status = 0,
+	};
+	int res = vexpress_config_schedule(&trans);
+
+	if (res == VEXPRESS_CONFIG_EXEC_WAIT)
+		res = vexpress_config_wait(&trans);
+
+	return res;
+}
+EXPORT_SYMBOL(vexpress_config_read);
+
+int vexpress_config_write(struct vexpress_config_func *func, int offset,
+		u32 data)
+{
+	struct vexpress_config_trans trans = {
+		.func = func,
+		.offset = offset,
+		.write = true,
+		.data = &data,
+		.status = 0,
+	};
+	int res = vexpress_config_schedule(&trans);
+
+	if (res == VEXPRESS_CONFIG_EXEC_WAIT)
+		res = vexpress_config_wait(&trans);
+
+	return res;
+}
+EXPORT_SYMBOL(vexpress_config_write);
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
new file mode 100644
index 0000000..b4acb20
--- /dev/null
+++ b/include/linux/vexpress.h
@@ -0,0 +1,64 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#ifndef _LINUX_VEXPRESS_H
+#define _LINUX_VEXPRESS_H
+
+#include <linux/device.h>
+
+#define VEXPRESS_SITE_MB		0
+#define VEXPRESS_SITE_DB1		1
+#define VEXPRESS_SITE_DB2		2
+#define VEXPRESS_SITE_MASTER		0xf
+
+#define VEXPRESS_CONFIG_EXEC_DONE	0
+#define VEXPRESS_CONFIG_EXEC_WAIT	1
+
+/* Config bridge API */
+
+struct vexpress_config_bridge_info {
+	const char *name;
+	void *(*func_get)(struct device *dev, struct device_node *node);
+	void (*func_put)(void *func);
+	int (*func_exec)(void *func, int offset, bool write, u32 *data);
+};
+
+struct vexpress_config_bridge;
+
+struct vexpress_config_bridge *vexpress_config_bridge_register(
+		struct device_node *node,
+		struct vexpress_config_bridge_info *info);
+void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge);
+
+void vexpress_config_complete(struct vexpress_config_bridge *bridge,
+		int status);
+
+/* Config function API */
+
+struct vexpress_config_func;
+
+struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
+		struct device_node *node);
+#define vexpress_config_func_get_by_dev(dev) \
+		__vexpress_config_func_get(dev, NULL)
+#define vexpress_config_func_get_by_node(node) \
+		__vexpress_config_func_get(NULL, node)
+void vexpress_config_func_put(struct vexpress_config_func *func);
+
+/* Both may sleep! */
+int vexpress_config_read(struct vexpress_config_func *func, int offset,
+		u32 *data);
+int vexpress_config_write(struct vexpress_config_func *func, int offset,
+		u32 data);
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 08/13] mfd: Versatile Express system registers driver
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (6 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 07/13] misc: Versatile Express config infrastructure Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 15:24   ` Arnd Bergmann
  2012-09-18 14:17 ` [PATCH v2 09/13] ARM: vexpress: Reset driver Pawel Moll
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

This is a platform driver for Versatile Express' "system
register" block. It's a random collection of registers providing
the following functionality:

- low level platform functions like board ID access; in order to
  use those, the driver must be initialized early, either statically
  or based on the DT

- config bus bridge via "system control" interface; as the response
  from the controller does not generate interrupt (yet), the status
  register is periodically polled using a timer

- pseudo GPIO lines providing MMC card status and Flash WP#
  signal control

- LED interface for a set of 8 LEDs on the motherboard, with
  "heartbeat" and "mmc0" as default triggers for 2 of them

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 .../devicetree/bindings/arm/vexpress-sysreg.txt    |   50 ++
 drivers/mfd/Makefile                               |    1 +
 drivers/mfd/vexpress-sysreg.c                      |  542 ++++++++++++++++++++
 include/linux/vexpress.h                           |   25 +
 4 files changed, 618 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
 create mode 100644 drivers/mfd/vexpress-sysreg.c

diff --git a/Documentation/devicetree/bindings/arm/vexpress-sysreg.txt b/Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
new file mode 100644
index 0000000..9cf3f25
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
@@ -0,0 +1,50 @@
+ARM Versatile Express system registers
+--------------------------------------
+
+This is a system control registers block, providing multiple low level
+platform functions like board detection and identification, software
+interrupt generation, MMC and NOR Flash control etc.
+
+Required node properties:
+- compatible value : = "arm,vexpress,sysreg";
+- reg : physical base address and the size of the registers window
+- gpio-controller : specifies that the node is a GPIO controller
+- #gpio-cells : size of the GPIO specifier, should be 2:
+  - first cell is the pseudo-GPIO line number:
+    0 - MMC CARDIN
+    1 - MMC WPROT
+    2 - NOR FLASH WPn
+  - second cell can take standard GPIO flags (currently ignored).
+
+Example:
+	v2m_sysreg: sysreg at 10000000 {
+ 		compatible = "arm,vexpress-sysreg";
+ 		reg = <0x10000000 0x1000>;
+		gpio-controller;
+		#gpio-cells = <2>;
+ 	};
+
+This block also can also act a bridge to the platform's configuration
+bus via "system control" interface, addressing devices with site number,
+position in the board stack, config controller, function and device
+numbers - see motherboard's TRM for more details.
+
+The node describing a config device must refer to the sysreg node via
+"arm,vexpress,config-bridge" phandle (can be also defined in the node's
+parent) and relies on the board topology properties - see main vexpress
+node documentation for more details. It must must also define the
+following property:
+- arm,vexpress-sysreg,func : must contain two cells:
+  - first cell defines function number (eg. 1 for clock generator,
+    2 for voltage regulators etc.)
+  - device number (eg. osc 0, osc 1 etc.)
+
+Example:
+	mcc {
+		arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+		osc at 0 {
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 0>;
+		};
+	};
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 79dd22d..6b3f9f9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -132,3 +132,4 @@ obj-$(CONFIG_MFD_RC5T583)	+= rc5t583.o rc5t583-irq.o
 obj-$(CONFIG_MFD_SEC_CORE)	+= sec-core.o sec-irq.o
 obj-$(CONFIG_MFD_ANATOP)	+= anatop-mfd.o
 obj-$(CONFIG_MFD_LM3533)	+= lm3533-core.o lm3533-ctrlbank.o
+obj-$(CONFIG_VEXPRESS_CONFIG)	+= vexpress-sysreg.o
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
new file mode 100644
index 0000000..d33dcf3
--- /dev/null
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -0,0 +1,542 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/timer.h>
+#include <linux/vexpress.h>
+
+#define SYS_ID			0x000
+#define SYS_SW			0x004
+#define SYS_LED			0x008
+#define SYS_100HZ		0x024
+#define SYS_FLAGS		0x030
+#define SYS_FLAGSSET		0x030
+#define SYS_FLAGSCLR		0x034
+#define SYS_NVFLAGS		0x038
+#define SYS_NVFLAGSSET		0x038
+#define SYS_NVFLAGSCLR		0x03c
+#define SYS_MCI			0x048
+#define SYS_FLASH		0x04c
+#define SYS_CFGSW		0x058
+#define SYS_24MHZ		0x05c
+#define SYS_MISC		0x060
+#define SYS_DMA			0x064
+#define SYS_PROCID0		0x084
+#define SYS_PROCID1		0x088
+#define SYS_CFGDATA		0x0a0
+#define SYS_CFGCTRL		0x0a4
+#define SYS_CFGSTAT		0x0a8
+
+#define SYS_HBI_MASK		0xfff
+#define SYS_ID_HBI_SHIFT	16
+#define SYS_PROCIDx_HBI_SHIFT	0
+
+#define SYS_MCI_CARDIN		(1 << 0)
+#define SYS_MCI_WPROT		(1 << 1)
+
+#define SYS_FLASH_WPn		(1 << 0)
+
+#define SYS_MISC_MASTERSITE	(1 << 14)
+
+#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_ERR		(1 << 1)
+#define SYS_CFGSTAT_COMPLETE	(1 << 0)
+
+
+static void __iomem *vexpress_sysreg_base;
+static struct device *vexpress_sysreg_dev;
+static int vexpress_master_site;
+
+
+void vexpress_flags_set(u32 data)
+{
+	writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR);
+	writel(data, vexpress_sysreg_base + SYS_FLAGSSET);
+}
+
+u32 vexpress_get_procid(int site)
+{
+	if (site == VEXPRESS_SITE_MASTER)
+		site = vexpress_master_site;
+
+	return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ?
+			SYS_PROCID0 : SYS_PROCID1));
+}
+
+u32 vexpress_get_hbi(int site)
+{
+	u32 id;
+
+	switch (site) {
+	case VEXPRESS_SITE_MB:
+		id = readl(vexpress_sysreg_base + SYS_ID);
+		return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK;
+	case VEXPRESS_SITE_MASTER:
+	case VEXPRESS_SITE_DB1:
+	case VEXPRESS_SITE_DB2:
+		id = vexpress_get_procid(site);
+		return (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
+	}
+
+	return ~0;
+}
+
+void __iomem *vexpress_get_24mhz_clock_base(void)
+{
+	return vexpress_sysreg_base + SYS_24MHZ;
+}
+
+
+static void vexpress_sysreg_find_prop(struct device_node *node,
+		const char *name, u32 *val)
+{
+	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);
+	}
+}
+
+unsigned __vexpress_get_site(struct device *dev, struct device_node *node)
+{
+	u32 site = 0;
+
+	WARN_ON(dev && node && dev->of_node != node);
+	if (dev && !node)
+		node = dev->of_node;
+
+	if (node) {
+		vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
+	} else if (dev && dev->bus == &platform_bus_type) {
+		struct platform_device *pdev = to_platform_device(dev);
+
+		if (pdev->num_resources == 1 &&
+				pdev->resource[0].flags == IORESOURCE_BUS)
+			site = pdev->resource[0].start;
+	} else if (dev && strncmp(dev_name(dev), "ct:", 3) == 0) {
+		site = VEXPRESS_SITE_MASTER;
+	}
+
+	if (site == VEXPRESS_SITE_MASTER)
+		site = vexpress_master_site;
+
+	return site;
+}
+
+
+struct vexpress_sysreg_config_func {
+	u32 template;
+	u32 device;
+};
+
+static struct vexpress_config_bridge *vexpress_sysreg_config_bridge;
+static struct timer_list vexpress_sysreg_config_timer;
+static u32 *vexpress_sysreg_config_data;
+static int vexpress_sysreg_config_tries;
+
+static void *vexpress_sysreg_config_func_get(struct device *dev,
+		struct device_node *node)
+{
+	struct vexpress_sysreg_config_func *config_func;
+	u32 site;
+	u32 position = 0;
+	u32 dcc = 0;
+	u32 func_device[2];
+	int err = -EFAULT;
+
+	if (node) {
+		of_node_get(node);
+		vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
+		vexpress_sysreg_find_prop(node, "arm,vexpress,position",
+				&position);
+		vexpress_sysreg_find_prop(node, "arm,vexpress,dcc", &dcc);
+		err = of_property_read_u32_array(node,
+				"arm,vexpress-sysreg,func", func_device,
+				ARRAY_SIZE(func_device));
+		of_node_put(node);
+	} else if (dev && dev->bus == &platform_bus_type) {
+		struct platform_device *pdev = to_platform_device(dev);
+
+		if (pdev->num_resources == 1 &&
+				pdev->resource[0].flags == IORESOURCE_BUS) {
+			site = pdev->resource[0].start;
+			func_device[0] = pdev->resource[0].end;
+			func_device[1] = pdev->id;
+			err = 0;
+		}
+	}
+	if (err)
+		return NULL;
+
+	config_func = kzalloc(sizeof(*config_func), GFP_KERNEL);
+	if (!config_func)
+		return NULL;
+
+	config_func->template = SYS_CFGCTRL_DCC(dcc);
+	config_func->template |= SYS_CFGCTRL_FUNC(func_device[0]);
+	config_func->template |= SYS_CFGCTRL_SITE(site == VEXPRESS_SITE_MASTER ?
+			vexpress_master_site : site);
+	config_func->template |= SYS_CFGCTRL_POSITION(position);
+	config_func->device |= func_device[1];
+
+	dev_dbg(vexpress_sysreg_dev, "func 0x%p = 0x%x, %d\n", config_func,
+			config_func->template, config_func->device);
+
+	return config_func;
+}
+
+static void vexpress_sysreg_config_func_put(void *func)
+{
+	kfree(func);
+}
+
+static int vexpress_sysreg_config_func_exec(void *func, int offset,
+		bool write, u32 *data)
+{
+	int res;
+	struct vexpress_sysreg_config_func *config_func = func;
+	u32 command;
+
+	if (WARN_ON(!vexpress_sysreg_base))
+		return -ENOENT;
+
+	command = readl(vexpress_sysreg_base + SYS_CFGCTRL);
+	if (WARN_ON(command & SYS_CFGCTRL_START))
+		return -EBUSY;
+
+	command = SYS_CFGCTRL_START;
+	command |= write ? SYS_CFGCTRL_WRITE : 0;
+	command |= config_func->template;
+	command |= SYS_CFGCTRL_DEVICE(config_func->device + offset);
+
+	if (write) {
+		dev_dbg(vexpress_sysreg_dev, "write cmd %x, data %x\n",
+				command, *data);
+		writel(*data, vexpress_sysreg_base + SYS_CFGDATA);
+	} else {
+		dev_dbg(vexpress_sysreg_dev, "read cmd %x\n", command);
+		vexpress_sysreg_config_data = data;
+	}
+	writel(0, vexpress_sysreg_base + SYS_CFGSTAT);
+	writel(command, vexpress_sysreg_base + SYS_CFGCTRL);
+	mb();
+
+	if (vexpress_sysreg_dev) {
+		/* Schedule completion check */
+		vexpress_sysreg_config_tries = 100;
+		mod_timer(&vexpress_sysreg_config_timer,
+				jiffies + usecs_to_jiffies(100));
+		res = VEXPRESS_CONFIG_EXEC_WAIT;
+	} else {
+		/* Early execution, no timer available, have to spin */
+		u32 stat;
+
+		do {
+			cpu_relax();
+			stat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
+		} while (!stat);
+
+		if (!write && (stat & SYS_CFGSTAT_COMPLETE))
+			*data = readl(vexpress_sysreg_base + SYS_CFGDATA);
+		res = VEXPRESS_CONFIG_EXEC_DONE;
+
+		if (stat & SYS_CFGSTAT_ERR)
+			res = -EINVAL;
+	}
+
+	return res;
+}
+
+struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = {
+	.name = "vexpress-sysreg",
+	.func_get = vexpress_sysreg_config_func_get,
+	.func_put = vexpress_sysreg_config_func_put,
+	.func_exec = vexpress_sysreg_config_func_exec,
+};
+
+static void vexpress_sysreg_config_complete(unsigned long data)
+{
+	int err = 0;
+	u32 stat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
+
+	if (stat & SYS_CFGSTAT_ERR)
+		err = -EINVAL;
+	if (!vexpress_sysreg_config_tries--)
+		err = -ETIMEDOUT;
+
+	if (err)
+		dev_err(vexpress_sysreg_dev, "error %d\n", err);
+
+	if (!err && !(stat & SYS_CFGSTAT_COMPLETE)) {
+		mod_timer(&vexpress_sysreg_config_timer,
+				jiffies + usecs_to_jiffies(50));
+		return;
+	}
+
+	if (vexpress_sysreg_config_data) {
+		*vexpress_sysreg_config_data = readl(vexpress_sysreg_base +
+				SYS_CFGDATA);
+		dev_dbg(vexpress_sysreg_dev, "read data %x\n",
+				*vexpress_sysreg_config_data);
+		vexpress_sysreg_config_data = NULL;
+	}
+
+	vexpress_config_complete(vexpress_sysreg_config_bridge, err);
+}
+
+
+void __init vexpress_sysreg_early_init(void __iomem *base)
+{
+	struct device_node *node = of_find_compatible_node(NULL, NULL,
+			"arm,vexpress-sysreg");
+
+	if (node)
+		base = of_iomap(node, 0);
+
+	if (WARN_ON(!base))
+		return;
+
+	vexpress_sysreg_base = base;
+
+	if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE)
+		vexpress_master_site = VEXPRESS_SITE_DB2;
+	else
+		vexpress_master_site = VEXPRESS_SITE_DB1;
+
+	vexpress_sysreg_config_bridge = vexpress_config_bridge_register(
+			node, &vexpress_sysreg_config_bridge_info);
+	WARN_ON(!vexpress_sysreg_config_bridge);
+}
+
+void __init vexpress_sysreg_of_early_init(void)
+{
+	vexpress_sysreg_early_init(NULL);
+}
+
+
+static struct vexpress_sysreg_gpio {
+	unsigned long reg;
+	u32 value;
+} vexpress_sysreg_gpios[] = {
+	[VEXPRESS_GPIO_MMC_CARDIN] = {
+		.reg = SYS_MCI,
+		.value = SYS_MCI_CARDIN,
+	},
+	[VEXPRESS_GPIO_MMC_WPROT] = {
+		.reg = SYS_MCI,
+		.value = SYS_MCI_WPROT,
+	},
+	[VEXPRESS_GPIO_FLASH_WPn] = {
+		.reg = SYS_FLASH,
+		.value = SYS_FLASH_WPn,
+	},
+};
+
+static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
+				       unsigned offset)
+{
+	return 0;
+}
+
+static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
+						unsigned offset, int value)
+{
+	return 0;
+}
+
+static int vexpress_sysreg_gpio_get(struct gpio_chip *chip,
+				       unsigned offset)
+{
+	struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
+	u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
+
+	return !!(reg_value & gpio->value);
+}
+
+static void vexpress_sysreg_gpio_set(struct gpio_chip *chip,
+				       unsigned offset, int value)
+{
+	struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
+	u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
+
+	if (value)
+		reg_value |= gpio->value;
+	else
+		reg_value &= ~gpio->value;
+
+	writel(reg_value, vexpress_sysreg_base + gpio->reg);
+}
+
+static struct gpio_chip vexpress_sysreg_gpio_chip = {
+	.label = "vexpress-sysreg",
+	.direction_input = vexpress_sysreg_gpio_direction_input,
+	.direction_output = vexpress_sysreg_gpio_direction_output,
+	.get = vexpress_sysreg_gpio_get,
+	.set = vexpress_sysreg_gpio_set,
+	.ngpio = ARRAY_SIZE(vexpress_sysreg_gpios),
+	.base = 0,
+};
+
+
+static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0x%08x\n", readl(vexpress_sysreg_base + SYS_ID));
+}
+
+DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL);
+
+static int __devinit vexpress_sysreg_probe(struct platform_device *pdev)
+{
+	int err;
+	struct resource *res = platform_get_resource(pdev,
+			IORESOURCE_MEM, 0);
+
+	if (!devm_request_mem_region(&pdev->dev, res->start,
+			resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "Failed to request memory region!\n");
+		return -EBUSY;
+	}
+
+	if (!vexpress_sysreg_base)
+		vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start,
+				resource_size(res));
+
+	if (!vexpress_sysreg_base) {
+		dev_err(&pdev->dev, "Failed to obtain base address!\n");
+		return -EFAULT;
+	}
+
+	setup_timer(&vexpress_sysreg_config_timer,
+			vexpress_sysreg_config_complete, 0);
+
+	vexpress_sysreg_gpio_chip.dev = &pdev->dev;
+	err = gpiochip_add(&vexpress_sysreg_gpio_chip);
+	if (err) {
+		vexpress_config_bridge_unregister(
+				vexpress_sysreg_config_bridge);
+		dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n",
+				err);
+		return err;
+	}
+
+	vexpress_sysreg_dev = &pdev->dev;
+
+	device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
+
+	return 0;
+}
+
+static const struct of_device_id vexpress_sysreg_match[] = {
+	{ .compatible = "arm,vexpress-sysreg", },
+	{},
+};
+
+static struct platform_driver vexpress_sysreg_driver = {
+	.driver = {
+		.name = "vexpress-sysreg",
+		.of_match_table = vexpress_sysreg_match,
+	},
+	.probe = vexpress_sysreg_probe,
+};
+
+static int __init vexpress_sysreg_init(void)
+{
+	return platform_driver_register(&vexpress_sysreg_driver);
+}
+core_initcall(vexpress_sysreg_init);
+
+
+struct vexpress_sysreg_led {
+	u32 mask;
+	struct led_classdev cdev;
+} vexpress_sysreg_leds[] = {
+	{ .mask = 1 << 0, .cdev.name = "v2m:green:user1",
+			.cdev.default_trigger = "heartbeat", },
+	{ .mask = 1 << 1, .cdev.name = "v2m:green:user2",
+			.cdev.default_trigger = "mmc0", },
+	{ .mask = 1 << 2, .cdev.name = "v2m:green:user3", },
+	{ .mask = 1 << 3, .cdev.name = "v2m:green:user4", },
+	{ .mask = 1 << 4, .cdev.name = "v2m:green:user5", },
+	{ .mask = 1 << 5, .cdev.name = "v2m:green:user6", },
+	{ .mask = 1 << 6, .cdev.name = "v2m:green:user7", },
+	{ .mask = 1 << 7, .cdev.name = "v2m:green:user8", },
+};
+
+static DEFINE_SPINLOCK(vexpress_sysreg_leds_lock);
+
+static void vexpress_sysreg_led_brightness_set(struct led_classdev *cdev,
+		enum led_brightness brightness)
+{
+	struct vexpress_sysreg_led *led = container_of(cdev,
+			struct vexpress_sysreg_led, cdev);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&vexpress_sysreg_leds_lock, flags);
+
+	val = readl(vexpress_sysreg_base + SYS_LED);
+	if (brightness == LED_OFF)
+		val &= ~led->mask;
+	else
+		val |= led->mask;
+	writel(val, vexpress_sysreg_base + SYS_LED);
+
+	spin_unlock_irqrestore(&vexpress_sysreg_leds_lock, flags);
+}
+
+static int __init vexpress_sysreg_init_leds(void)
+{
+	struct vexpress_sysreg_led *led;
+	int i;
+
+	/* Clear all user LEDs */
+	writel(0, vexpress_sysreg_base + SYS_LED);
+
+	for (i = 0, led = vexpress_sysreg_leds;
+			i < ARRAY_SIZE(vexpress_sysreg_leds); i++, led++) {
+		int err;
+
+		led->cdev.brightness_set = vexpress_sysreg_led_brightness_set;
+		err = led_classdev_register(vexpress_sysreg_dev, &led->cdev);
+		if (err) {
+			dev_err(vexpress_sysreg_dev,
+					"Failed to register LED %d! (%d)\n",
+					i, err);
+			while (led--, i--)
+				led_classdev_unregister(&led->cdev);
+			return err;
+		}
+	}
+
+	return 0;
+}
+device_initcall(vexpress_sysreg_init_leds);
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index b4acb20..8ed285c 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -24,6 +24,17 @@
 #define VEXPRESS_CONFIG_EXEC_DONE	0
 #define VEXPRESS_CONFIG_EXEC_WAIT	1
 
+#define VEXPRESS_GPIO_MMC_CARDIN	0
+#define VEXPRESS_GPIO_MMC_WPROT		1
+#define VEXPRESS_GPIO_FLASH_WPn		2
+
+#define VEXPRESS_RES_FUNC(_site, _func)	\
+{					\
+	.start = (_site),		\
+	.end = (_func),			\
+	.flags = IORESOURCE_BUS,	\
+}
+
 /* Config bridge API */
 
 struct vexpress_config_bridge_info {
@@ -61,4 +72,18 @@ int vexpress_config_read(struct vexpress_config_func *func, int offset,
 int vexpress_config_write(struct vexpress_config_func *func, int offset,
 		u32 data);
 
+/* Platform control */
+
+u32 vexpress_get_procid(int site);
+u32 vexpress_get_hbi(int site);
+void *vexpress_get_24mhz_clock_base(void);
+void vexpress_flags_set(u32 data);
+
+#define vexpress_get_site_by_node(node) __vexpress_get_site(NULL, node)
+#define vexpress_get_site_by_dev(dev) __vexpress_get_site(dev, NULL)
+unsigned __vexpress_get_site(struct device *dev, struct device_node *node);
+
+void vexpress_sysreg_early_init(void __iomem *base);
+void vexpress_sysreg_of_early_init(void);
+
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 09/13] ARM: vexpress: Reset driver
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (7 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 08/13] mfd: Versatile Express system registers driver Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 10/13] ARM: vexpress: Add config bus components and clocks to DTs Pawel Moll
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

This is a simple driver providing platform restart and power off
functions using VE config infrastructure.

By writing to the "active" attribute of the reboot or reset device,
user can decide what if the platform is supposed to execute full power
cycle (reboot, default) or simply assert system level reset signal.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 arch/arm/mach-vexpress/reset.c |  141 ++++++++++++++++++++++++++++++++++++++++
 include/linux/vexpress.h       |    3 +
 2 files changed, 144 insertions(+)
 create mode 100644 arch/arm/mach-vexpress/reset.c

diff --git a/arch/arm/mach-vexpress/reset.c b/arch/arm/mach-vexpress/reset.c
new file mode 100644
index 0000000..465923a
--- /dev/null
+++ b/arch/arm/mach-vexpress/reset.c
@@ -0,0 +1,141 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/stat.h>
+#include <linux/vexpress.h>
+
+static void vexpress_reset_do(struct device *dev, const char *what)
+{
+	int err = -ENOENT;
+	struct vexpress_config_func *func =
+			vexpress_config_func_get_by_dev(dev);
+
+	if (func) {
+		unsigned long timeout;
+
+		err = vexpress_config_write(func, 0, 0);
+
+		timeout = jiffies + HZ;
+		while (time_before(jiffies, timeout))
+			cpu_relax();
+	}
+
+	dev_emerg(dev, "Unable to %s (%d)\n", what, err);
+}
+
+static struct device *vexpress_power_off_device;
+
+void vexpress_power_off(void)
+{
+	vexpress_reset_do(vexpress_power_off_device, "power off");
+}
+
+static struct device *vexpress_restart_device;
+
+void vexpress_restart(char str, const char *cmd)
+{
+	vexpress_reset_do(vexpress_restart_device, "restart");
+}
+
+static ssize_t vexpress_reset_active_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", vexpress_restart_device == dev);
+}
+
+static ssize_t vexpress_reset_active_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	long value;
+	int err = kstrtol(buf, 0, &value);
+
+	if (!err && value)
+		vexpress_restart_device = dev;
+
+	return err ? err : count;
+}
+
+DEVICE_ATTR(active, S_IRUGO | S_IWUSR, vexpress_reset_active_show,
+		vexpress_reset_active_store);
+
+
+enum vexpress_reset_func { FUNC_RESET, FUNC_SHUTDOWN, FUNC_REBOOT };
+
+static struct of_device_id vexpress_reset_of_match[] = {
+	{
+		.compatible = "arm,vexpress-reset",
+		.data = (void *)FUNC_RESET,
+	}, {
+		.compatible = "arm,vexpress-shutdown",
+		.data = (void *)FUNC_SHUTDOWN
+	}, {
+		.compatible = "arm,vexpress-reboot",
+		.data = (void *)FUNC_REBOOT
+	},
+	{}
+};
+
+static int vexpress_reset_probe(struct platform_device *pdev)
+{
+	enum vexpress_reset_func func;
+	const struct of_device_id *match =
+			of_match_device(vexpress_reset_of_match, &pdev->dev);
+
+	if (match)
+		func = (enum vexpress_reset_func)match->data;
+	else
+		func = pdev->id_entry->driver_data;
+
+	switch (func) {
+	case FUNC_SHUTDOWN:
+		vexpress_power_off_device = &pdev->dev;
+		break;
+	case FUNC_RESET:
+		if (!vexpress_restart_device)
+			vexpress_restart_device = &pdev->dev;
+		device_create_file(&pdev->dev, &dev_attr_active);
+		break;
+	case FUNC_REBOOT:
+		vexpress_restart_device = &pdev->dev;
+		device_create_file(&pdev->dev, &dev_attr_active);
+		break;
+	};
+
+	return 0;
+}
+
+static const struct platform_device_id vexpress_reset_id_table[] = {
+	{ .name = "vexpress-reset", .driver_data = FUNC_RESET, },
+	{ .name = "vexpress-shutdown", .driver_data = FUNC_SHUTDOWN, },
+	{ .name = "vexpress-reboot", .driver_data = FUNC_REBOOT, },
+	{}
+};
+
+static struct platform_driver vexpress_reset_driver = {
+	.probe = vexpress_reset_probe,
+	.driver = {
+		.name = "vexpress-reset",
+		.of_match_table = vexpress_reset_of_match,
+	},
+	.id_table = vexpress_reset_id_table,
+};
+
+static int __init vexpress_reset_init(void)
+{
+	return platform_driver_register(&vexpress_reset_driver);
+}
+device_initcall(vexpress_reset_init);
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index 8ed285c..8423083 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -86,4 +86,7 @@ unsigned __vexpress_get_site(struct device *dev, struct device_node *node);
 void vexpress_sysreg_early_init(void __iomem *base);
 void vexpress_sysreg_of_early_init(void);
 
+void vexpress_power_off(void);
+void vexpress_restart(char str, const char *cmd);
+
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 10/13] ARM: vexpress: Add config bus components and clocks to DTs
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (8 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 09/13] ARM: vexpress: Reset driver Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 11/13] ARM: vexpress: Start using new Versatile Express infrastructure Pawel Moll
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

Add description of all functions provided by Versatile Express
motherboard and daughterboards configuration controllers and
clock dependencies between devices.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi     |  134 ++++++++++++++++++++-
 arch/arm/boot/dts/vexpress-v2m.dtsi         |  134 ++++++++++++++++++++-
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts |  109 +++++++++++++++++
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts  |  173 +++++++++++++++++++++++++++
 arch/arm/boot/dts/vexpress-v2p-ca5s.dts     |   73 +++++++++++
 arch/arm/boot/dts/vexpress-v2p-ca9.dts      |  119 ++++++++++++++++++
 6 files changed, 738 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index d8a827b..fffda1f 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -24,6 +24,7 @@
 
 	motherboard {
 		compatible = "simple-bus";
+		arm,vexpress,site = <0>;
 		arm,v2m-memory-map = "rs1";
 		#address-cells = <2>; /* SMB chipselect number and offset */
 		#size-cells = <1>;
@@ -72,14 +73,20 @@
 			#size-cells = <1>;
 			ranges = <0 3 0 0x200000>;
 
-			sysreg at 010000 {
+			v2m_sysreg: sysreg at 010000 {
 				compatible = "arm,vexpress-sysreg";
 				reg = <0x010000 0x1000>;
+				gpio-controller;
+				#gpio-cells = <2>;
 			};
 
-			sysctl at 020000 {
+			v2m_sysctl: sysctl at 020000 {
 				compatible = "arm,sp810", "arm,primecell";
 				reg = <0x020000 0x1000>;
+				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>;
+				clock-names = "refclk", "timclk", "apb_pclk";
+				#clock-cells = <1>;
+				clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
 			};
 
 			/* PCI-E I2C bus */
@@ -100,66 +107,92 @@
 				compatible = "arm,pl041", "arm,primecell";
 				reg = <0x040000 0x1000>;
 				interrupts = <11>;
+				clocks = <&smbclk>;
+				clock-names = "apb_pclk";
 			};
 
 			mmci at 050000 {
 				compatible = "arm,pl180", "arm,primecell";
 				reg = <0x050000 0x1000>;
 				interrupts = <9 10>;
+				cd-gpios = <&v2m_sysreg 0 0>;
+				wp-gpios = <&v2m_sysreg 1 0>;
+				max-frequency = <12000000>;
+				vmmc-supply = <&v2m_fixed_3v3>;
+				clocks = <&v2m_clk24mhz>, <&smbclk>;
+				clock-names = "mclk", "apb_pclk";
 			};
 
 			kmi at 060000 {
 				compatible = "arm,pl050", "arm,primecell";
 				reg = <0x060000 0x1000>;
 				interrupts = <12>;
+				clocks = <&v2m_clk24mhz>, <&smbclk>;
+				clock-names = "KMIREFCLK", "apb_pclk";
 			};
 
 			kmi at 070000 {
 				compatible = "arm,pl050", "arm,primecell";
 				reg = <0x070000 0x1000>;
 				interrupts = <13>;
+				clocks = <&v2m_clk24mhz>, <&smbclk>;
+				clock-names = "KMIREFCLK", "apb_pclk";
 			};
 
 			v2m_serial0: uart at 090000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x090000 0x1000>;
 				interrupts = <5>;
+				clocks = <&v2m_oscclk2>, <&smbclk>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial1: uart at 0a0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0a0000 0x1000>;
 				interrupts = <6>;
+				clocks = <&v2m_oscclk2>, <&smbclk>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial2: uart at 0b0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0b0000 0x1000>;
 				interrupts = <7>;
+				clocks = <&v2m_oscclk2>, <&smbclk>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial3: uart at 0c0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0c0000 0x1000>;
 				interrupts = <8>;
+				clocks = <&v2m_oscclk2>, <&smbclk>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			wdt at 0f0000 {
 				compatible = "arm,sp805", "arm,primecell";
 				reg = <0x0f0000 0x1000>;
 				interrupts = <0>;
+				clocks = <&v2m_refclk32khz>, <&smbclk>;
+				clock-names = "wdogclk", "apb_pclk";
 			};
 
 			v2m_timer01: timer at 110000 {
 				compatible = "arm,sp804", "arm,primecell";
 				reg = <0x110000 0x1000>;
 				interrupts = <2>;
+				clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&smbclk>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
 			};
 
 			v2m_timer23: timer at 120000 {
 				compatible = "arm,sp804", "arm,primecell";
 				reg = <0x120000 0x1000>;
 				interrupts = <3>;
+				clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&smbclk>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
 			};
 
 			/* DVI I2C bus */
@@ -185,6 +218,8 @@
 				compatible = "arm,pl031", "arm,primecell";
 				reg = <0x170000 0x1000>;
 				interrupts = <4>;
+				clocks = <&smbclk>;
+				clock-names = "apb_pclk";
 			};
 
 			compact-flash at 1a0000 {
@@ -198,6 +233,8 @@
 				compatible = "arm,pl111", "arm,primecell";
 				reg = <0x1f0000 0x1000>;
 				interrupts = <14>;
+				clocks = <&v2m_oscclk1>, <&smbclk>;
+				clock-names = "clcdclk", "apb_pclk";
 			};
 		};
 
@@ -208,5 +245,98 @@
 			regulator-max-microvolt = <3300000>;
 			regulator-always-on;
 		};
+
+		v2m_clk24mhz: clk24mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <24000000>;
+			clock-output-names = "v2m:clk24mhz";
+		};
+
+		v2m_refclk1mhz: refclk1mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <1000000>;
+			clock-output-names = "v2m:refclk1mhz";
+		};
+
+		v2m_refclk32khz: refclk32khz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+			clock-output-names = "v2m:refclk32khz";
+		};
+
+		mcc {
+			compatible = "simple-bus";
+			arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+			osc at 0 {
+				/* MCC static memory clock */
+				compatible = "arm,vexpress-osc";
+				arm,vexpress-sysreg,func = <1 0>;
+				freq-range = <25000000 60000000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:oscclk0";
+			};
+
+			v2m_oscclk1: osc at 1 {
+				/* CLCD clock */
+				compatible = "arm,vexpress-osc";
+				arm,vexpress-sysreg,func = <1 1>;
+				freq-range = <23750000 63500000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:oscclk1";
+			};
+
+			v2m_oscclk2: osc at 2 {
+				/* IO FPGA peripheral clock */
+				compatible = "arm,vexpress-osc";
+				arm,vexpress-sysreg,func = <1 2>;
+				freq-range = <24000000 24000000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:oscclk2";
+			};
+
+			volt at 0 {
+				/* Logic level voltage */
+				compatible = "arm,vexpress-volt";
+				arm,vexpress-sysreg,func = <2 0>;
+				regulator-name = "VIO";
+				regulator-always-on;
+			};
+
+			temp at 0 {
+				/* MCC internal operating temperature */
+				compatible = "arm,vexpress-temp";
+				arm,vexpress-sysreg,func = <4 0>;
+				label = "MCC";
+			};
+
+			reset at 0 {
+				compatible = "arm,vexpress-reset";
+				arm,vexpress-sysreg,func = <5 0>;
+			};
+
+			muxfpga at 0 {
+				compatible = "arm,vexpress-muxfpga";
+				arm,vexpress-sysreg,func = <7 0>;
+			};
+
+			shutdown at 0 {
+				compatible = "arm,vexpress-shutdown";
+				arm,vexpress-sysreg,func = <8 0>;
+			};
+
+			reboot at 0 {
+				compatible = "arm,vexpress-reboot";
+				arm,vexpress-sysreg,func = <9 0>;
+			};
+
+			dvimode at 0 {
+				compatible = "arm,vexpress-dvimode";
+				arm,vexpress-sysreg,func = <11 0>;
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
index dba53fd..10e05d9 100644
--- a/arch/arm/boot/dts/vexpress-v2m.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -24,6 +24,7 @@
 
 	motherboard {
 		compatible = "simple-bus";
+		arm,vexpress,site = <0>;
 		#address-cells = <2>; /* SMB chipselect number and offset */
 		#size-cells = <1>;
 		#interrupt-cells = <1>;
@@ -71,14 +72,20 @@
 			#size-cells = <1>;
 			ranges = <0 7 0 0x20000>;
 
-			sysreg at 00000 {
+			v2m_sysreg: sysreg at 00000 {
 				compatible = "arm,vexpress-sysreg";
 				reg = <0x00000 0x1000>;
+				gpio-controller;
+				#gpio-cells = <2>;
 			};
 
-			sysctl at 01000 {
+			v2m_sysctl: sysctl at 01000 {
 				compatible = "arm,sp810", "arm,primecell";
 				reg = <0x01000 0x1000>;
+				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>;
+				clock-names = "refclk", "timclk", "apb_pclk";
+				#clock-cells = <1>;
+				clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
 			};
 
 			/* PCI-E I2C bus */
@@ -99,66 +106,92 @@
 				compatible = "arm,pl041", "arm,primecell";
 				reg = <0x04000 0x1000>;
 				interrupts = <11>;
+				clocks = <&smbclk>;
+				clock-names = "apb_pclk";
 			};
 
 			mmci at 05000 {
 				compatible = "arm,pl180", "arm,primecell";
 				reg = <0x05000 0x1000>;
 				interrupts = <9 10>;
+				cd-gpios = <&v2m_sysreg 0 0>;
+				wp-gpios = <&v2m_sysreg 1 0>;
+				max-frequency = <12000000>;
+				vmmc-supply = <&v2m_fixed_3v3>;
+				clocks = <&v2m_clk24mhz>, <&smbclk>;
+				clock-names = "mclk", "apb_pclk";
 			};
 
 			kmi at 06000 {
 				compatible = "arm,pl050", "arm,primecell";
 				reg = <0x06000 0x1000>;
 				interrupts = <12>;
+				clocks = <&v2m_clk24mhz>, <&smbclk>;
+				clock-names = "KMIREFCLK", "apb_pclk";
 			};
 
 			kmi at 07000 {
 				compatible = "arm,pl050", "arm,primecell";
 				reg = <0x07000 0x1000>;
 				interrupts = <13>;
+				clocks = <&v2m_clk24mhz>, <&smbclk>;
+				clock-names = "KMIREFCLK", "apb_pclk";
 			};
 
 			v2m_serial0: uart at 09000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x09000 0x1000>;
 				interrupts = <5>;
+				clocks = <&v2m_oscclk2>, <&smbclk>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial1: uart at 0a000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0a000 0x1000>;
 				interrupts = <6>;
+				clocks = <&v2m_oscclk2>, <&smbclk>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial2: uart at 0b000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0b000 0x1000>;
 				interrupts = <7>;
+				clocks = <&v2m_oscclk2>, <&smbclk>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial3: uart at 0c000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0c000 0x1000>;
 				interrupts = <8>;
+				clocks = <&v2m_oscclk2>, <&smbclk>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			wdt at 0f000 {
 				compatible = "arm,sp805", "arm,primecell";
 				reg = <0x0f000 0x1000>;
 				interrupts = <0>;
+				clocks = <&v2m_refclk32khz>, <&smbclk>;
+				clock-names = "wdogclk", "apb_pclk";
 			};
 
 			v2m_timer01: timer at 11000 {
 				compatible = "arm,sp804", "arm,primecell";
 				reg = <0x11000 0x1000>;
 				interrupts = <2>;
+				clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&smbclk>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
 			};
 
 			v2m_timer23: timer at 12000 {
 				compatible = "arm,sp804", "arm,primecell";
 				reg = <0x12000 0x1000>;
 				interrupts = <3>;
+				clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&smbclk>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
 			};
 
 			/* DVI I2C bus */
@@ -184,6 +217,8 @@
 				compatible = "arm,pl031", "arm,primecell";
 				reg = <0x17000 0x1000>;
 				interrupts = <4>;
+				clocks = <&smbclk>;
+				clock-names = "apb_pclk";
 			};
 
 			compact-flash at 1a000 {
@@ -197,6 +232,8 @@
 				compatible = "arm,pl111", "arm,primecell";
 				reg = <0x1f000 0x1000>;
 				interrupts = <14>;
+				clocks = <&v2m_oscclk1>, <&smbclk>;
+				clock-names = "clcdclk", "apb_pclk";
 			};
 		};
 
@@ -207,5 +244,98 @@
 			regulator-max-microvolt = <3300000>;
 			regulator-always-on;
 		};
+
+		v2m_clk24mhz: clk24mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <24000000>;
+			clock-output-names = "v2m:clk24mhz";
+		};
+
+		v2m_refclk1mhz: refclk1mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <1000000>;
+			clock-output-names = "v2m:refclk1mhz";
+		};
+
+		v2m_refclk32khz: refclk32khz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+			clock-output-names = "v2m:refclk32khz";
+		};
+
+		mcc {
+			compatible = "simple-bus";
+			arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+			osc at 0 {
+				/* MCC static memory clock */
+				compatible = "arm,vexpress-osc";
+				arm,vexpress-sysreg,func = <1 0>;
+				freq-range = <25000000 60000000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:oscclk0";
+			};
+
+			v2m_oscclk1: osc at 1 {
+				/* CLCD clock */
+				compatible = "arm,vexpress-osc";
+				arm,vexpress-sysreg,func = <1 1>;
+				freq-range = <23750000 63500000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:oscclk1";
+			};
+
+			v2m_oscclk2: osc at 2 {
+				/* IO FPGA peripheral clock */
+				compatible = "arm,vexpress-osc";
+				arm,vexpress-sysreg,func = <1 2>;
+				freq-range = <24000000 24000000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:oscclk2";
+			};
+
+			volt at 0 {
+				/* Logic level voltage */
+				compatible = "arm,vexpress-volt";
+				arm,vexpress-sysreg,func = <2 0>;
+				regulator-name = "VIO";
+				regulator-always-on;
+			};
+
+			temp at 0 {
+				/* MCC internal operating temperature */
+				compatible = "arm,vexpress-temp";
+				arm,vexpress-sysreg,func = <4 0>;
+				label = "MCC";
+			};
+
+			reset at 0 {
+				compatible = "arm,vexpress-reset";
+				arm,vexpress-sysreg,func = <5 0>;
+			};
+
+			muxfpga at 0 {
+				compatible = "arm,vexpress-muxfpga";
+				arm,vexpress-sysreg,func = <7 0>;
+			};
+
+			shutdown at 0 {
+				compatible = "arm,vexpress-shutdown";
+				arm,vexpress-sysreg,func = <8 0>;
+			};
+
+			reboot at 0 {
+				compatible = "arm,vexpress-reboot";
+				arm,vexpress-sysreg,func = <9 0>;
+			};
+
+			dvimode at 0 {
+				compatible = "arm,vexpress-dvimode";
+				arm,vexpress-sysreg,func = <11 0>;
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
index d12b34c..7c237af 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
@@ -12,6 +12,7 @@
 / {
 	model = "V2P-CA15";
 	arm,hbi = <0x237>;
+	arm,vexpress,site = <0xf>;
 	compatible = "arm,vexpress,v2p-ca15,tc1", "arm,vexpress,v2p-ca15", "arm,vexpress";
 	interrupt-parent = <&gic>;
 	#address-cells = <2>;
@@ -54,17 +55,24 @@
 		compatible = "arm,hdlcd";
 		reg = <0 0x2b000000 0 0x1000>;
 		interrupts = <0 85 4>;
+		clocks = <&oscclk5>;
+		clock-names = "pxlclk";
 	};
 
 	memory-controller at 2b0a0000 {
 		compatible = "arm,pl341", "arm,primecell";
 		reg = <0 0x2b0a0000 0 0x1000>;
+		clocks = <&oscclk7>;
+		clock-names = "apb_pclk";
 	};
 
 	wdt at 2b060000 {
 		compatible = "arm,sp805", "arm,primecell";
+		status = "disabled";
 		reg = <0 0x2b060000 0 0x1000>;
 		interrupts = <98>;
+		clocks = <&oscclk7>;
+		clock-names = "apb_pclk";
 	};
 
 	gic: interrupt-controller at 2c001000 {
@@ -84,6 +92,8 @@
 		reg = <0 0x7ffd0000 0 0x1000>;
 		interrupts = <0 86 4>,
 			     <0 87 4>;
+		clocks = <&oscclk7>;
+		clock-names = "apb_pclk";
 	};
 
 	dma at 7ffb0000 {
@@ -94,6 +104,8 @@
 			     <0 89 4>,
 			     <0 90 4>,
 			     <0 91 4>;
+		clocks = <&oscclk7>;
+		clock-names = "apb_pclk";
 	};
 
 	timer {
@@ -110,6 +122,103 @@
 			     <0 69 4>;
 	};
 
+	dcc {
+		compatible = "simple-bus";
+		arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+		osc at 0 {
+			/* CPU PLL reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 0>;
+			freq-range = <50000000 60000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk0";
+		};
+
+		osc at 4 {
+			/* Multiplexed AXI master clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 4>;
+			freq-range = <20000000 40000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk4";
+		};
+
+		oscclk5: osc at 5 {
+			/* HDLCD PLL reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 5>;
+			freq-range = <23750000 165000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk5";
+		};
+
+		smbclk: osc at 6 {
+			/* SMB clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 6>;
+			freq-range = <20000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk6";
+		};
+
+		oscclk7: osc at 7 {
+			/* SYS PLL reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 7>;
+			freq-range = <20000000 60000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk7";
+		};
+
+		osc at 8 {
+			/* DDR2 PLL reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 8>;
+			freq-range = <40000000 40000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk8";
+		};
+
+		volt at 0 {
+			/* CPU core voltage */
+			compatible = "arm,vexpress-volt";
+			arm,vexpress-sysreg,func = <2 0>;
+			regulator-name = "Cores";
+			regulator-min-microvolt = <900000>;
+			regulator-max-microvolt = <1050000>;
+			regulator-always-on;
+		};
+
+		amp at 0 {
+			/* Total current for the two cores */
+			compatible = "arm,vexpress-amp";
+			arm,vexpress-sysreg,func = <3 0>;
+			label = "Cores";
+		};
+
+		temp at 0 {
+			/* DCC internal temperature */
+			compatible = "arm,vexpress-temp";
+			arm,vexpress-sysreg,func = <4 0>;
+			label = "DCC";
+		};
+
+		power at 0 {
+			/* Total power */
+			compatible = "arm,vexpress-power";
+			arm,vexpress-sysreg,func = <12 0>;
+			label = "Cores";
+		};
+
+		energy at 0 {
+			/* Total energy */
+			compatible = "arm,vexpress-energy";
+			arm,vexpress-sysreg,func = <13 0>;
+			label = "Cores";
+		};
+	};
+
 	motherboard {
 		ranges = <0 0 0 0x08000000 0x04000000>,
 			 <1 0 0 0x14000000 0x04000000>,
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
index 4890a81..c41a82d 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -12,6 +12,7 @@
 / {
 	model = "V2P-CA15_CA7";
 	arm,hbi = <0x249>;
+	arm,vexpress,site = <0xf>;
 	compatible = "arm,vexpress,v2p-ca15_a7", "arm,vexpress";
 	interrupt-parent = <&gic>;
 	#address-cells = <2>;
@@ -74,17 +75,23 @@
 		compatible = "arm,sp805", "arm,primecell";
 		reg = <0 0x2a490000 0 0x1000>;
 		interrupts = <98>;
+		clocks = <&oscclk6a>, <&oscclk6a>;
+		clock-names = "wdogclk", "apb_pclk";
 	};
 
 	hdlcd at 2b000000 {
 		compatible = "arm,hdlcd";
 		reg = <0 0x2b000000 0 0x1000>;
 		interrupts = <0 85 4>;
+		clocks = <&oscclk5>;
+		clock-names = "pxlclk";
 	};
 
 	memory-controller at 2b0a0000 {
 		compatible = "arm,pl341", "arm,primecell";
 		reg = <0 0x2b0a0000 0 0x1000>;
+		clocks = <&oscclk6a>;
+		clock-names = "apb_pclk";
 	};
 
 	gic: interrupt-controller at 2c001000 {
@@ -104,6 +111,8 @@
 		reg = <0 0x7ffd0000 0 0x1000>;
 		interrupts = <0 86 4>,
 			     <0 87 4>;
+		clocks = <&oscclk6a>;
+		clock-names = "apb_pclk";
 	};
 
 	dma at 7ff00000 {
@@ -114,6 +123,8 @@
 			     <0 89 4>,
 			     <0 90 4>,
 			     <0 91 4>;
+		clocks = <&oscclk6a>;
+		clock-names = "apb_pclk";
 	};
 
 	timer {
@@ -130,6 +141,168 @@
 			     <0 69 4>;
 	};
 
+	oscclk6a: oscclk6a {
+		/* Reference 24MHz clock */
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+		clock-output-names = "oscclk6a";
+	};
+
+	dcc {
+		compatible = "simple-bus";
+		arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+		osc at 0 {
+			/* A15 PLL 0 reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 0>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk0";
+		};
+
+		osc at 1 {
+			/* A15 PLL 1 reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 1>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk1";
+		};
+
+		osc at 2 {
+			/* A7 PLL 0 reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 2>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk2";
+		};
+
+		osc at 3 {
+			/* A7 PLL 1 reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 3>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk3";
+		};
+
+		osc at 4 {
+			/* External AXI master clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 4>;
+			freq-range = <20000000 40000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk4";
+		};
+
+		oscclk5: osc at 5 {
+			/* HDLCD PLL reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 5>;
+			freq-range = <23750000 165000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk5";
+		};
+
+		smbclk: osc at 6 {
+			/* Static memory controller clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 6>;
+			freq-range = <20000000 40000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk6";
+		};
+
+		osc at 7 {
+			/* SYS PLL reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 7>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk7";
+		};
+
+		osc at 8 {
+			/* DDR2 PLL reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 8>;
+			freq-range = <20000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk8";
+		};
+
+		volt at 0 {
+			/* A15 CPU core voltage */
+			compatible = "arm,vexpress-volt";
+			arm,vexpress-sysreg,func = <2 0>;
+			regulator-name = "A15 Vcore";
+			regulator-min-microvolt = <900000>;
+			regulator-max-microvolt = <1050000>;
+			regulator-always-on;
+		};
+
+		volt at 1 {
+			/* A7 CPU core voltage */
+			compatible = "arm,vexpress-volt";
+			arm,vexpress-sysreg,func = <2 1>;
+			regulator-name = "A7 Vcore";
+			regulator-min-microvolt = <900000>;
+			regulator-max-microvolt = <1050000>;
+			regulator-always-on;
+		};
+
+		amp at 0 {
+			/* Total current for the two A15 cores */
+			compatible = "arm,vexpress-amp";
+			arm,vexpress-sysreg,func = <3 0>;
+			label = "A15 Icore";
+		};
+
+		amp at 1 {
+			/* Total current for the three A7 cores */
+			compatible = "arm,vexpress-amp";
+			arm,vexpress-sysreg,func = <3 1>;
+			label = "A7 Icore";
+		};
+
+		temp at 0 {
+			/* DCC internal temperature */
+			compatible = "arm,vexpress-temp";
+			arm,vexpress-sysreg,func = <4 0>;
+			label = "DCC";
+		};
+
+		power at 0 {
+			/* Total power for the two A15 cores */
+			compatible = "arm,vexpress-power";
+			arm,vexpress-sysreg,func = <12 0>;
+			label = "A15 Pcore";
+		};
+		power at 1 {
+			/* Total power for the three A7 cores */
+			compatible = "arm,vexpress-power";
+			arm,vexpress-sysreg,func = <12 1>;
+			label = "A7 Pcore";
+		};
+
+		energy at 0 {
+			/* Total energy for the two A15 cores */
+			compatible = "arm,vexpress-energy";
+			arm,vexpress-sysreg,func = <13 0>;
+			label = "A15 Jcore";
+		};
+
+		energy at 2 {
+			/* Total energy for the three A7 cores */
+			compatible = "arm,vexpress-energy";
+			arm,vexpress-sysreg,func = <13 2>;
+			label = "A7 Jcore";
+		};
+	};
+
 	motherboard {
 		ranges = <0 0 0 0x08000000 0x04000000>,
 			 <1 0 0 0x14000000 0x04000000>,
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
index 18917a0..94486d6 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
@@ -12,6 +12,7 @@
 / {
 	model = "V2P-CA5s";
 	arm,hbi = <0x225>;
+	arm,vexpress,site = <0xf>;
 	compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
 	interrupt-parent = <&gic>;
 	#address-cells = <1>;
@@ -56,11 +57,15 @@
 		compatible = "arm,hdlcd";
 		reg = <0x2a110000 0x1000>;
 		interrupts = <0 85 4>;
+		clocks = <&oscclk3>;
+		clock-names = "pxlclk";
 	};
 
 	memory-controller at 2a150000 {
 		compatible = "arm,pl341", "arm,primecell";
 		reg = <0x2a150000 0x1000>;
+		clocks = <&oscclk1>;
+		clock-names = "apb_pclk";
 	};
 
 	memory-controller at 2a190000 {
@@ -68,6 +73,8 @@
 		reg = <0x2a190000 0x1000>;
 		interrupts = <0 86 4>,
 			     <0 87 4>;
+		clocks = <&oscclk1>;
+		clock-names = "apb_pclk";
 	};
 
 	scu at 2c000000 {
@@ -109,6 +116,72 @@
 			     <0 69 4>;
 	};
 
+	dcc {
+		compatible = "simple-bus";
+		arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+		osc at 0 {
+			/* CPU and internal AXI reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 0>;
+			freq-range = <50000000 100000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk0";
+		};
+
+		oscclk1: osc at 1 {
+			/* Multiplexed AXI master clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 1>;
+			freq-range = <5000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk1";
+		};
+
+		osc at 2 {
+			/* DDR2 */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 2>;
+			freq-range = <80000000 120000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk2";
+		};
+
+		oscclk3: osc at 3 {
+			/* HDLCD */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 3>;
+			freq-range = <23750000 165000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk3";
+		};
+
+		osc at 4 {
+			/* Test chip gate configuration */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 4>;
+			freq-range = <80000000 80000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk4";
+		};
+
+		smbclk: osc at 5 {
+			/* SMB clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 5>;
+			freq-range = <25000000 60000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk5";
+		};
+
+		temp at 0 {
+			/* DCC internal operating temperature */
+			compatible = "arm,vexpress-temp";
+			arm,vexpress-sysreg,func = <4 0>;
+			label = "DCC";
+		};
+	};
+
 	motherboard {
 		ranges = <0 0 0x08000000 0x04000000>,
 			 <1 0 0x14000000 0x04000000>,
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
index 3f0c736..bebbea4 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -12,6 +12,7 @@
 / {
 	model = "V2P-CA9";
 	arm,hbi = <0x191>;
+	arm,vexpress,site = <0xf>;
 	compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
 	interrupt-parent = <&gic>;
 	#address-cells = <1>;
@@ -70,11 +71,15 @@
 		compatible = "arm,pl111", "arm,primecell";
 		reg = <0x10020000 0x1000>;
 		interrupts = <0 44 4>;
+		clocks = <&oscclk1>, <&oscclk2>;
+		clock-names = "clcdclk", "apb_pclk";
 	};
 
 	memory-controller at 100e0000 {
 		compatible = "arm,pl341", "arm,primecell";
 		reg = <0x100e0000 0x1000>;
+		clocks = <&oscclk2>;
+		clock-names = "apb_pclk";
 	};
 
 	memory-controller at 100e1000 {
@@ -82,6 +87,8 @@
 		reg = <0x100e1000 0x1000>;
 		interrupts = <0 45 4>,
 			     <0 46 4>;
+		clocks = <&oscclk2>;
+		clock-names = "apb_pclk";
 	};
 
 	timer at 100e4000 {
@@ -89,12 +96,16 @@
 		reg = <0x100e4000 0x1000>;
 		interrupts = <0 48 4>,
 			     <0 49 4>;
+		clocks = <&oscclk2>, <&oscclk2>;
+		clock-names = "timclk", "apb_pclk";
 	};
 
 	watchdog at 100e5000 {
 		compatible = "arm,sp805", "arm,primecell";
 		reg = <0x100e5000 0x1000>;
 		interrupts = <0 51 4>;
+		clocks = <&oscclk2>, <&oscclk2>;
+		clock-names = "wdogclk", "apb_pclk";
 	};
 
 	scu at 1e000000 {
@@ -140,6 +151,114 @@
 			     <0 63 4>;
 	};
 
+	dcc {
+		compatible = "simple-bus";
+		arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+		osc at 0 {
+			/* ACLK clock to the AXI master port on the test chip */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 0>;
+			freq-range = <30000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "extsaxiclk";
+		};
+
+		oscclk1: osc at 1 {
+			/* Reference clock for the CLCD */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 1>;
+			freq-range = <10000000 80000000>;
+			#clock-cells = <0>;
+			clock-output-names = "clcdclk";
+		};
+
+		smbclk: oscclk2: osc at 2 {
+			/* Reference clock for the test chip internal PLLs */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 2>;
+			freq-range = <33000000 100000000>;
+			#clock-cells = <0>;
+			clock-output-names = "tcrefclk";
+		};
+
+		volt at 0 {
+			/* Test Chip internal logic voltage */
+			compatible = "arm,vexpress-volt";
+			arm,vexpress-sysreg,func = <2 0>;
+			regulator-name = "VD10";
+			regulator-always-on;
+		};
+
+		volt at 1 {
+			/* PL310, L2 cache, RAM cell supply (not PL310 logic) */
+			compatible = "arm,vexpress-volt";
+			arm,vexpress-sysreg,func = <2 1>;
+			regulator-name = "VD10_S2";
+			regulator-always-on;
+		};
+
+		volt at 2 {
+			/* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */
+			compatible = "arm,vexpress-volt";
+			arm,vexpress-sysreg,func = <2 2>;
+			regulator-name = "VD10_S3";
+			regulator-always-on;
+		};
+
+		volt at 3 {
+			/* DDR2 SDRAM and Test Chip DDR2 I/O supply */
+			compatible = "arm,vexpress-volt";
+			arm,vexpress-sysreg,func = <2 3>;
+			regulator-name = "VCC1V8";
+			regulator-always-on;
+		};
+
+		volt at 4 {
+			/* DDR2 SDRAM VTT termination voltage */
+			compatible = "arm,vexpress-volt";
+			arm,vexpress-sysreg,func = <2 4>;
+			regulator-name = "DDR2VTT";
+			regulator-always-on;
+		};
+
+		volt at 5 {
+			/* Local board supply for miscellaneous logic external to the Test Chip */
+			arm,vexpress-sysreg,func = <2 5>;
+			compatible = "arm,vexpress-volt";
+			regulator-name = "VCC3V3";
+			regulator-always-on;
+		};
+
+		amp at 0 {
+			/* PL310, L2 cache, RAM cell supply (not PL310 logic) */
+			compatible = "arm,vexpress-amp";
+			arm,vexpress-sysreg,func = <3 0>;
+			label = "VD10_S2";
+		};
+
+		amp at 1 {
+			/* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */
+			compatible = "arm,vexpress-amp";
+			arm,vexpress-sysreg,func = <3 1>;
+			label = "VD10_S3";
+		};
+
+		power at 0 {
+			/* PL310, L2 cache, RAM cell supply (not PL310 logic) */
+			compatible = "arm,vexpress-power";
+			arm,vexpress-sysreg,func = <12 0>;
+			label = "PVD10_S2";
+		};
+
+		power at 1 {
+			/* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */
+			compatible = "arm,vexpress-power";
+			arm,vexpress-sysreg,func = <12 1>;
+			label = "PVD10_S3";
+		};
+	};
+
 	motherboard {
 		ranges = <0 0 0x40000000 0x04000000>,
 			 <1 0 0x44000000 0x04000000>,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 11/13] ARM: vexpress: Start using new Versatile Express infrastructure
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (9 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 10/13] ARM: vexpress: Add config bus components and clocks to DTs Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 12/13] ARM: vexpress: Remove motherboard dependencies in the DTS files Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 13/13] ARM: vexpress: Make the DEBUG_LL UART detection more specific Pawel Moll
  12 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

This patch starts using all the configuration infrastructure.

- generic GPIO library is forced now

- sysreg GPIOs are used to as MMC CD and WP information sources;
  thanks to this MMCI auxiliary data is not longer necessary

- DVI muxer and mode control is removed from non-DT V2P-CA9 code
  as this is now handled by the vexpress-display driver

- oscillator control is removed as is being handled by the
  common clock driver now

- the sysreg and sysctl control is now delegated to the
  appropriate drivers and all related code was removed

- NOR Flash set_vpp function has been removed as the control
  bit used does _not_ control its VPP line, but the #WP signal
  instead (which is de facto unusable in case of Linux MTD
  drivers); this also allowed the remove its DT auxiliary
  data

The non-DT code defines only minimal required number of
the config devices. Device Trees are updated to make use
of all new features.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 arch/arm/Kconfig                                  |    4 +-
 arch/arm/include/asm/hardware/sp810.h             |    6 -
 arch/arm/mach-vexpress/Makefile                   |    2 +-
 arch/arm/mach-vexpress/ct-ca9x4.c                 |   41 +--
 arch/arm/mach-vexpress/include/mach/motherboard.h |   81 -----
 arch/arm/mach-vexpress/platsmp.c                  |    3 +-
 arch/arm/mach-vexpress/v2m.c                      |  334 +++++----------------
 include/linux/vexpress.h                          |    8 +
 8 files changed, 104 insertions(+), 375 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b53ea6c..dc67a77 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -322,11 +322,12 @@ config ARCH_VERSATILE
 
 config ARCH_VEXPRESS
 	bool "ARM Ltd. Versatile Express family"
-	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select ARCH_REQUIRE_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
 	select CLKDEV_LOOKUP
 	select COMMON_CLK
+	select COMMON_CLK_VERSATILE
 	select GENERIC_CLOCKEVENTS
 	select HAVE_CLK
 	select HAVE_PATA_PLATFORM
@@ -335,6 +336,7 @@ config ARCH_VEXPRESS
 	select PLAT_VERSATILE
 	select PLAT_VERSATILE_CLCD
 	select REGULATOR_FIXED_VOLTAGE if REGULATOR
+	select VEXPRESS_CONFIG
 	help
 	  This enables support for the ARM Ltd Versatile Express boards.
 
diff --git a/arch/arm/include/asm/hardware/sp810.h b/arch/arm/include/asm/hardware/sp810.h
index afd7e91..6636430 100644
--- a/arch/arm/include/asm/hardware/sp810.h
+++ b/arch/arm/include/asm/hardware/sp810.h
@@ -50,12 +50,6 @@
 #define SCPCELLID2		0xFF8
 #define SCPCELLID3		0xFFC
 
-#define SCCTRL_TIMEREN0SEL_REFCLK	(0 << 15)
-#define SCCTRL_TIMEREN0SEL_TIMCLK	(1 << 15)
-
-#define SCCTRL_TIMEREN1SEL_REFCLK	(0 << 17)
-#define SCCTRL_TIMEREN1SEL_TIMCLK	(1 << 17)
-
 #define SCCTRL_TIMERENnSEL_SHIFT(n)	(15 + ((n) * 2))
 
 static inline void sysctl_soft_reset(void __iomem *base)
diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile
index 90551b9..a1e2921 100644
--- a/arch/arm/mach-vexpress/Makefile
+++ b/arch/arm/mach-vexpress/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel.
 #
 
-obj-y					:= v2m.o
+obj-y					:= v2m.o reset.o
 obj-$(CONFIG_ARCH_VEXPRESS_CA9X4)	+= ct-ca9x4.o
 obj-$(CONFIG_SMP)			+= platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 61c4924..49ddf7e 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -9,6 +9,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
 #include <linux/clkdev.h>
+#include <linux/vexpress.h>
 
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -64,19 +65,6 @@ static void __init ct_ca9x4_init_irq(void)
 	ca9x4_twd_init();
 }
 
-static void ct_ca9x4_clcd_enable(struct clcd_fb *fb)
-{
-	u32 site = v2m_get_master_site();
-
-	/*
-	 * Old firmware was using the "site" component of the command
-	 * to control the DVI muxer (while it should be always 0 ie. MB).
-	 * Newer firmware uses the data register. Keep both for compatibility.
-	 */
-	v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE(site), site);
-	v2m_cfg_write(SYS_CFG_DVIMODE | SYS_CFG_SITE(SYS_CFG_SITE_MB), 2);
-}
-
 static int ct_ca9x4_clcd_setup(struct clcd_fb *fb)
 {
 	unsigned long framesize = 1024 * 768 * 2;
@@ -93,7 +81,6 @@ static struct clcd_board ct_ca9x4_clcd_data = {
 	.caps		= CLCD_CAP_5551 | CLCD_CAP_565,
 	.check		= clcdfb_check,
 	.decode		= clcdfb_decode,
-	.enable		= ct_ca9x4_clcd_enable,
 	.setup		= ct_ca9x4_clcd_setup,
 	.mmap		= versatile_clcd_mmap_dma,
 	.remove		= versatile_clcd_remove_dma,
@@ -111,14 +98,6 @@ static struct amba_device *ct_ca9x4_amba_devs[] __initdata = {
 	&gpio_device,
 };
 
-
-static struct v2m_osc ct_osc1 = {
-	.osc = 1,
-	.rate_min = 10000000,
-	.rate_max = 80000000,
-	.rate_default = 23750000,
-};
-
 static struct resource pmu_resources[] = {
 	[0] = {
 		.start	= IRQ_CT_CA9X4_PMU_CPU0,
@@ -149,10 +128,18 @@ static struct platform_device pmu_device = {
 	.resource	= pmu_resources,
 };
 
+static struct platform_device osc1_device = {
+	.name		= "vexpress-osc",
+	.id		= 1,
+	.num_resources	= 1,
+	.resource	= (struct resource []) {
+		VEXPRESS_RES_FUNC(0xf, 1),
+	},
+};
+
 static void __init ct_ca9x4_init(void)
 {
 	int i;
-	struct clk *clk;
 
 #ifdef CONFIG_CACHE_L2X0
 	void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
@@ -164,14 +151,14 @@ static void __init ct_ca9x4_init(void)
 	l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
 #endif
 
-	ct_osc1.site = v2m_get_master_site();
-	clk = v2m_osc_register("ct:osc1", &ct_osc1);
-	clk_register_clkdev(clk, NULL, "ct:clcd");
-
 	for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++)
 		amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource);
 
 	platform_device_register(&pmu_device);
+	platform_device_register(&osc1_device);
+
+	WARN_ON(clk_register_clkdev(vexpress_osc_setup(&osc1_device.dev),
+			NULL, "ct:clcd"));
 }
 
 #ifdef CONFIG_SMP
diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h
index 1e388c7..68abc8b 100644
--- a/arch/arm/mach-vexpress/include/mach/motherboard.h
+++ b/arch/arm/mach-vexpress/include/mach/motherboard.h
@@ -1,8 +1,6 @@
 #ifndef __MACH_MOTHERBOARD_H
 #define __MACH_MOTHERBOARD_H
 
-#include <linux/clk-provider.h>
-
 /*
  * Physical addresses, offset from V2M_PA_CS0-3
  */
@@ -41,31 +39,6 @@
 #define V2M_CF			(V2M_PA_CS7 + 0x0001a000)
 #define V2M_CLCD		(V2M_PA_CS7 + 0x0001f000)
 
-/*
- * Offsets from SYSREGS base
- */
-#define V2M_SYS_ID		0x000
-#define V2M_SYS_SW		0x004
-#define V2M_SYS_LED		0x008
-#define V2M_SYS_100HZ		0x024
-#define V2M_SYS_FLAGS		0x030
-#define V2M_SYS_FLAGSSET	0x030
-#define V2M_SYS_FLAGSCLR	0x034
-#define V2M_SYS_NVFLAGS		0x038
-#define V2M_SYS_NVFLAGSSET	0x038
-#define V2M_SYS_NVFLAGSCLR	0x03c
-#define V2M_SYS_MCI		0x048
-#define V2M_SYS_FLASH		0x03c
-#define V2M_SYS_CFGSW		0x058
-#define V2M_SYS_24MHZ		0x05c
-#define V2M_SYS_MISC		0x060
-#define V2M_SYS_DMA		0x064
-#define V2M_SYS_PROCID0		0x084
-#define V2M_SYS_PROCID1		0x088
-#define V2M_SYS_CFGDATA		0x0a0
-#define V2M_SYS_CFGCTRL		0x0a4
-#define V2M_SYS_CFGSTAT		0x0a8
-
 
 /*
  * Interrupts.  Those in {} are for AMBA devices
@@ -91,43 +64,6 @@
 
 
 /*
- * Configuration
- */
-#define SYS_CFG_START		(1 << 31)
-#define SYS_CFG_WRITE		(1 << 30)
-#define SYS_CFG_OSC		(1 << 20)
-#define SYS_CFG_VOLT		(2 << 20)
-#define SYS_CFG_AMP		(3 << 20)
-#define SYS_CFG_TEMP		(4 << 20)
-#define SYS_CFG_RESET		(5 << 20)
-#define SYS_CFG_SCC		(6 << 20)
-#define SYS_CFG_MUXFPGA		(7 << 20)
-#define SYS_CFG_SHUTDOWN	(8 << 20)
-#define SYS_CFG_REBOOT		(9 << 20)
-#define SYS_CFG_DVIMODE		(11 << 20)
-#define SYS_CFG_POWER		(12 << 20)
-#define SYS_CFG_SITE(n)		((n) << 16)
-#define SYS_CFG_SITE_MB		0
-#define SYS_CFG_SITE_DB1	1
-#define SYS_CFG_SITE_DB2	2
-#define SYS_CFG_STACK(n)	((n) << 12)
-
-#define SYS_CFG_ERR		(1 << 1)
-#define SYS_CFG_COMPLETE	(1 << 0)
-
-int v2m_cfg_write(u32 devfn, u32 data);
-int v2m_cfg_read(u32 devfn, u32 *data);
-void v2m_flags_set(u32 data);
-
-/*
- * Miscellaneous
- */
-#define SYS_MISC_MASTERSITE	(1 << 14)
-#define SYS_PROCIDx_HBI_MASK	0xfff
-
-int v2m_get_master_site(void);
-
-/*
  * Core tile IDs
  */
 #define V2M_CT_ID_CA9		0x0c000191
@@ -149,21 +85,4 @@ struct ct_desc {
 
 extern struct ct_desc *ct_desc;
 
-/*
- * OSC clock provider
- */
-struct v2m_osc {
-	struct clk_hw hw;
-	u8 site; /* 0 = motherboard, 1 = site 1, 2 = site 2 */
-	u8 stack; /* board stack position */
-	u16 osc;
-	unsigned long rate_min;
-	unsigned long rate_max;
-	unsigned long rate_default;
-};
-
-#define to_v2m_osc(osc) container_of(osc, struct v2m_osc, hw)
-
-struct clk *v2m_osc_register(const char *name, struct v2m_osc *osc);
-
 #endif
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index 14ba112..f07cb2f 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -13,6 +13,7 @@
 #include <linux/smp.h>
 #include <linux/io.h>
 #include <linux/of_fdt.h>
+#include <linux/vexpress.h>
 
 #include <asm/smp_scu.h>
 #include <asm/hardware/gic.h>
@@ -193,5 +194,5 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
 	 * until it receives a soft interrupt, and then the
 	 * secondary CPU branches to this address.
 	 */
-	v2m_flags_set(virt_to_phys(versatile_secondary_startup));
+	vexpress_flags_set(virt_to_phys(versatile_secondary_startup));
 }
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 37608f2..827d02f 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -15,11 +15,10 @@
 #include <linux/smsc911x.h>
 #include <linux/spinlock.h>
 #include <linux/usb/isp1760.h>
-#include <linux/clkdev.h>
-#include <linux/clk-provider.h>
 #include <linux/mtd/physmap.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
+#include <linux/vexpress.h>
 
 #include <asm/arch_timer.h>
 #include <asm/mach-types.h>
@@ -32,7 +31,6 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/timer-sp.h>
-#include <asm/hardware/sp810.h>
 
 #include <mach/ct-ca9x4.h>
 #include <mach/motherboard.h>
@@ -56,22 +54,6 @@ static struct map_desc v2m_io_desc[] __initdata = {
 	},
 };
 
-static void __iomem *v2m_sysreg_base;
-
-static void __init v2m_sysctl_init(void __iomem *base)
-{
-	u32 scctrl;
-
-	if (WARN_ON(!base))
-		return;
-
-	/* Select 1MHz TIMCLK as the reference clock for SP804 timers */
-	scctrl = readl(base + SCCTRL);
-	scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
-	scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
-	writel(scctrl, base + SCCTRL);
-}
-
 static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
 {
 	if (WARN_ON(!base || irq == NO_IRQ))
@@ -85,69 +67,6 @@ static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
 }
 
 
-static DEFINE_SPINLOCK(v2m_cfg_lock);
-
-int v2m_cfg_write(u32 devfn, u32 data)
-{
-	/* Configuration interface broken? */
-	u32 val;
-
-	printk("%s: writing %08x to %08x\n", __func__, data, devfn);
-
-	devfn |= SYS_CFG_START | SYS_CFG_WRITE;
-
-	spin_lock(&v2m_cfg_lock);
-	val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
-	writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT);
-
-	writel(data, v2m_sysreg_base +  V2M_SYS_CFGDATA);
-	writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
-
-	do {
-		val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
-	} while (val == 0);
-	spin_unlock(&v2m_cfg_lock);
-
-	return !!(val & SYS_CFG_ERR);
-}
-
-int v2m_cfg_read(u32 devfn, u32 *data)
-{
-	u32 val;
-
-	devfn |= SYS_CFG_START;
-
-	spin_lock(&v2m_cfg_lock);
-	writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT);
-	writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
-
-	mb();
-
-	do {
-		cpu_relax();
-		val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
-	} while (val == 0);
-
-	*data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA);
-	spin_unlock(&v2m_cfg_lock);
-
-	return !!(val & SYS_CFG_ERR);
-}
-
-void __init v2m_flags_set(u32 data)
-{
-	writel(~0, v2m_sysreg_base + V2M_SYS_FLAGSCLR);
-	writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET);
-}
-
-int v2m_get_master_site(void)
-{
-	u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC);
-
-	return misc & SYS_MISC_MASTERSITE ? SYS_CFG_SITE_DB2 : SYS_CFG_SITE_DB1;
-}
-
-
 static struct resource v2m_pcie_i2c_resource = {
 	.start	= V2M_SERIAL_BUS_PCI,
 	.end	= V2M_SERIAL_BUS_PCI + SZ_4K - 1,
@@ -235,14 +154,8 @@ static struct platform_device v2m_usb_device = {
 	.dev.platform_data = &v2m_usb_config,
 };
 
-static void v2m_flash_set_vpp(struct platform_device *pdev, int on)
-{
-	writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH);
-}
-
 static struct physmap_flash_data v2m_flash_data = {
 	.width		= 4,
-	.set_vpp	= v2m_flash_set_vpp,
 };
 
 static struct resource v2m_flash_resources[] = {
@@ -289,14 +202,61 @@ static struct platform_device v2m_cf_device = {
 	.dev.platform_data = &v2m_pata_data,
 };
 
-static unsigned int v2m_mmci_status(struct device *dev)
-{
-	return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0);
-}
-
 static struct mmci_platform_data v2m_mmci_data = {
 	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
-	.status		= v2m_mmci_status,
+	.gpio_wp	= VEXPRESS_GPIO_MMC_WPROT,
+	.gpio_cd	= VEXPRESS_GPIO_MMC_CARDIN,
+};
+
+static struct resource v2m_sysreg_resources[] = {
+	{
+		.start	= V2M_SYSREGS,
+		.end	= V2M_SYSREGS + 0xfff,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device v2m_sysreg_device = {
+	.name		= "vexpress-sysreg",
+	.id		= -1,
+	.resource	= v2m_sysreg_resources,
+	.num_resources	= ARRAY_SIZE(v2m_sysreg_resources),
+};
+
+static struct platform_device v2m_muxfpga_device = {
+	.name		= "vexpress-muxfpga",
+	.id		= 0,
+	.num_resources	= 1,
+	.resource	= (struct resource []) {
+		VEXPRESS_RES_FUNC(0, 7),
+	}
+};
+
+static struct platform_device v2m_shutdown_device = {
+	.name		= "vexpress-shutdown",
+	.id		= 0,
+	.num_resources	= 1,
+	.resource	= (struct resource []) {
+		VEXPRESS_RES_FUNC(0, 8),
+	}
+};
+
+static struct platform_device v2m_reboot_device = {
+	.name		= "vexpress-reboot",
+	.id		= 0,
+	.num_resources	= 1,
+	.resource	= (struct resource []) {
+		VEXPRESS_RES_FUNC(0, 9),
+	}
+};
+
+static struct platform_device v2m_dvimode_device = {
+	.name		= "vexpress-dvimode",
+	.id		= 0,
+	.num_resources	= 1,
+	.resource	= (struct resource []) {
+		VEXPRESS_RES_FUNC(0, 11),
+	}
 };
 
 static AMBA_APB_DEVICE(aaci,  "mb:aaci",  0, V2M_AACI, IRQ_V2M_AACI, NULL);
@@ -323,123 +283,9 @@ static struct amba_device *v2m_amba_devs[] __initdata = {
 	&rtc_device,
 };
 
-
-static unsigned long v2m_osc_recalc_rate(struct clk_hw *hw,
-		unsigned long parent_rate)
-{
-	struct v2m_osc *osc = to_v2m_osc(hw);
-
-	return !parent_rate ? osc->rate_default : parent_rate;
-}
-
-static long v2m_osc_round_rate(struct clk_hw *hw, unsigned long rate,
-		unsigned long *parent_rate)
-{
-	struct v2m_osc *osc = to_v2m_osc(hw);
-
-	if (WARN_ON(rate < osc->rate_min))
-		rate = osc->rate_min;
-
-	if (WARN_ON(rate > osc->rate_max))
-		rate = osc->rate_max;
-
-	return rate;
-}
-
-static int v2m_osc_set_rate(struct clk_hw *hw, unsigned long rate,
-		unsigned long parent_rate)
-{
-	struct v2m_osc *osc = to_v2m_osc(hw);
-
-	v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE(osc->site) |
-			SYS_CFG_STACK(osc->stack) | osc->osc, rate);
-
-	return 0;
-}
-
-static struct clk_ops v2m_osc_ops = {
-	.recalc_rate = v2m_osc_recalc_rate,
-	.round_rate = v2m_osc_round_rate,
-	.set_rate = v2m_osc_set_rate,
-};
-
-struct clk * __init v2m_osc_register(const char *name, struct v2m_osc *osc)
-{
-	struct clk_init_data init;
-
-	WARN_ON(osc->site > 2);
-	WARN_ON(osc->stack > 15);
-	WARN_ON(osc->osc > 4095);
-
-	init.name = name;
-	init.ops = &v2m_osc_ops;
-	init.flags = CLK_IS_ROOT;
-	init.num_parents = 0;
-
-	osc->hw.init = &init;
-
-	return clk_register(NULL, &osc->hw);
-}
-
-static struct v2m_osc v2m_mb_osc1 = {
-	.site = SYS_CFG_SITE_MB,
-	.osc = 1,
-	.rate_min = 23750000,
-	.rate_max = 63500000,
-	.rate_default = 23750000,
-};
-
-static const char *v2m_ref_clk_periphs[] __initconst = {
-	"mb:wdt",   "1000f000.wdt",  "1c0f0000.wdt",	/* SP805 WDT */
-};
-
-static const char *v2m_osc1_periphs[] __initconst = {
-	"mb:clcd",  "1001f000.clcd", "1c1f0000.clcd",	/* PL111 CLCD */
-};
-
-static const char *v2m_osc2_periphs[] __initconst = {
-	"mb:mmci",  "10005000.mmci", "1c050000.mmci",	/* PL180 MMCI */
-	"mb:kmi0",  "10006000.kmi",  "1c060000.kmi",	/* PL050 KMI0 */
-	"mb:kmi1",  "10007000.kmi",  "1c070000.kmi",	/* PL050 KMI1 */
-	"mb:uart0", "10009000.uart", "1c090000.uart",	/* PL011 UART0 */
-	"mb:uart1", "1000a000.uart", "1c0a0000.uart",	/* PL011 UART1 */
-	"mb:uart2", "1000b000.uart", "1c0b0000.uart",	/* PL011 UART2 */
-	"mb:uart3", "1000c000.uart", "1c0c0000.uart",	/* PL011 UART3 */
-};
-
-static void __init v2m_clk_init(void)
-{
-	struct clk *clk;
-	int i;
-
-	clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
-			CLK_IS_ROOT, 0);
-	WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL));
-
-	clk = clk_register_fixed_rate(NULL, "mb:ref_clk", NULL,
-			CLK_IS_ROOT, 32768);
-	for (i = 0; i < ARRAY_SIZE(v2m_ref_clk_periphs); i++)
-		WARN_ON(clk_register_clkdev(clk, NULL, v2m_ref_clk_periphs[i]));
-
-	clk = clk_register_fixed_rate(NULL, "mb:sp804_clk", NULL,
-			CLK_IS_ROOT, 1000000);
-	WARN_ON(clk_register_clkdev(clk, "v2m-timer0", "sp804"));
-	WARN_ON(clk_register_clkdev(clk, "v2m-timer1", "sp804"));
-
-	clk = v2m_osc_register("mb:osc1", &v2m_mb_osc1);
-	for (i = 0; i < ARRAY_SIZE(v2m_osc1_periphs); i++)
-		WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc1_periphs[i]));
-
-	clk = clk_register_fixed_rate(NULL, "mb:osc2", NULL,
-			CLK_IS_ROOT, 24000000);
-	for (i = 0; i < ARRAY_SIZE(v2m_osc2_periphs); i++)
-		WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc2_periphs[i]));
-}
-
 static void __init v2m_timer_init(void)
 {
-	v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
-	v2m_clk_init();
+	vexpress_clk_init(ioremap(V2M_SYSCTL, SZ_4K));
 	v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
 }
 
@@ -451,19 +297,7 @@ static void __init v2m_init_early(void)
 {
 	if (ct_desc->init_early)
 		ct_desc->init_early();
-	versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
-}
-
-static void v2m_power_off(void)
-{
-	if (v2m_cfg_write(SYS_CFG_SHUTDOWN | SYS_CFG_SITE(SYS_CFG_SITE_MB), 0))
-		printk(KERN_EMERG "Unable to shutdown\n");
-}
-
-static void v2m_restart(char str, const char *cmd)
-{
-	if (v2m_cfg_write(SYS_CFG_REBOOT | SYS_CFG_SITE(SYS_CFG_SITE_MB), 0))
-		printk(KERN_EMERG "Unable to reboot\n");
+	versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), 24000000);
 }
 
 struct ct_desc *ct_desc;
@@ -480,7 +314,7 @@ static void __init v2m_populate_ct_desc(void)
 	u32 current_tile_id;
 
 	ct_desc = NULL;
-	current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0)
+	current_tile_id = vexpress_get_procid(VEXPRESS_SITE_MASTER)
 				& V2M_CT_ID_MASK;
 
 	for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
@@ -496,7 +330,7 @@ static void __init v2m_populate_ct_desc(void)
 static void __init v2m_map_io(void)
 {
 	iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
-	v2m_sysreg_base = ioremap(V2M_SYSREGS, SZ_4K);
+	vexpress_sysreg_early_init(ioremap(V2M_SYSREGS, SZ_4K));
 	v2m_populate_ct_desc();
 	ct_desc->map_io();
 }
@@ -513,6 +347,12 @@ static void __init v2m_init(void)
 	regulator_register_fixed(0, v2m_eth_supplies,
 			ARRAY_SIZE(v2m_eth_supplies));
 
+	platform_device_register(&v2m_muxfpga_device);
+	platform_device_register(&v2m_shutdown_device);
+	platform_device_register(&v2m_reboot_device);
+	platform_device_register(&v2m_dvimode_device);
+
+	platform_device_register(&v2m_sysreg_device);
 	platform_device_register(&v2m_pcie_i2c_device);
 	platform_device_register(&v2m_ddc_i2c_device);
 	platform_device_register(&v2m_flash_device);
@@ -523,7 +363,7 @@ static void __init v2m_init(void)
 	for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++)
 		amba_device_register(v2m_amba_devs[i], &iomem_resource);
 
-	pm_power_off = v2m_power_off;
+	pm_power_off = vexpress_power_off;
 
 	ct_desc->init_tile();
 }
@@ -536,7 +376,7 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express")
 	.timer		= &v2m_timer,
 	.handle_irq	= gic_handle_irq,
 	.init_machine	= v2m_init,
-	.restart	= v2m_restart,
+	.restart	= vexpress_restart,
 MACHINE_END
 
 #if defined(CONFIG_ARCH_VEXPRESS_DT)
@@ -579,20 +419,13 @@ void __init v2m_dt_map_io(void)
 
 void __init v2m_dt_init_early(void)
 {
-	struct device_node *node;
 	u32 dt_hbi;
 
-	node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
-	v2m_sysreg_base = of_iomap(node, 0);
-	if (WARN_ON(!v2m_sysreg_base))
-		return;
+	vexpress_sysreg_of_early_init();
 
 	/* Confirm board type against DT property, if available */
 	if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) {
-		int site = v2m_get_master_site();
-		u32 id = readl(v2m_sysreg_base + (site == SYS_CFG_SITE_DB2 ?
-				V2M_SYS_PROCID1 : V2M_SYS_PROCID0));
-		u32 hbi = id & SYS_PROCIDx_HBI_MASK;
+		u32 hbi = vexpress_get_hbi(VEXPRESS_SITE_MASTER);
 
 		if (WARN_ON(dt_hbi != hbi))
 			pr_warning("vexpress: DT HBI (%x) is not matching "
@@ -612,14 +445,10 @@ static void __init v2m_dt_init_irq(void)
 
 static void __init v2m_dt_timer_init(void)
 {
-	struct device_node *node;
-	const char *path;
-	int err;
+	struct device_node *node = NULL;
 
-	node = of_find_compatible_node(NULL, NULL, "arm,sp810");
-	v2m_sysctl_init(of_iomap(node, 0));
+	vexpress_clk_of_init();
 
-	v2m_clk_init();
 
 	err = of_property_read_string(of_aliases, "arm,v2m_timer", &path);
 	if (WARN_ON(err))
@@ -630,33 +459,22 @@ static void __init v2m_dt_timer_init(void)
 		twd_local_timer_of_register();
 
 	if (arch_timer_sched_clock_init() != 0)
-		versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
+		versatile_sched_clock_init(vexpress_get_24mhz_clock_base(),
+				24000000);
 }
 
 static struct sys_timer v2m_dt_timer = {
 	.init = v2m_dt_timer_init,
 };
 
-static struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = {
-	OF_DEV_AUXDATA("arm,vexpress-flash", V2M_NOR0, "physmap-flash",
-			&v2m_flash_data),
-	OF_DEV_AUXDATA("arm,primecell", V2M_MMCI, "mb:mmci", &v2m_mmci_data),
-	/* RS1 memory map */
-	OF_DEV_AUXDATA("arm,vexpress-flash", 0x08000000, "physmap-flash",
-			&v2m_flash_data),
-	OF_DEV_AUXDATA("arm,primecell", 0x1c050000, "mb:mmci", &v2m_mmci_data),
-	{}
-};
-
 static void __init v2m_dt_init(void)
 {
 	l2x0_of_init(0x00400000, 0xfe0fffff);
-	of_platform_populate(NULL, of_default_bus_match_table,
-			v2m_dt_auxdata_lookup, NULL);
-	pm_power_off = v2m_power_off;
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+	pm_power_off = vexpress_power_off;
 }
 
-const static char *v2m_dt_match[] __initconst = {
+static const char * const v2m_dt_match[] __initconst = {
 	"arm,vexpress",
 	NULL,
 };
@@ -669,7 +487,7 @@ DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
 	.timer		= &v2m_dt_timer,
 	.init_machine	= v2m_dt_init,
 	.handle_irq	= gic_handle_irq,
-	.restart	= v2m_restart,
+	.restart	= vexpress_restart,
 MACHINE_END
 
 #endif
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index 8423083..021e8cf 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -89,4 +89,12 @@ void vexpress_sysreg_of_early_init(void);
 void vexpress_power_off(void);
 void vexpress_restart(char str, const char *cmd);
 
+/* Clocks */
+
+struct clk *vexpress_osc_setup(struct device *dev);
+void vexpress_osc_of_setup(struct device_node *node);
+
+void vexpress_clk_init(void __iomem *sp810_base);
+void vexpress_clk_of_init(void);
+
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 12/13] ARM: vexpress: Remove motherboard dependencies in the DTS files
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (10 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 11/13] ARM: vexpress: Start using new Versatile Express infrastructure Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  2012-09-18 14:17 ` [PATCH v2 13/13] ARM: vexpress: Make the DEBUG_LL UART detection more specific Pawel Moll
  12 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

The way the VE motherboard Device Trees were constructed
enforced naming and structure of daughterboard files. This
patch makes it possible to simply include the motherboard
description anywhere in the main Device Tree and retires
the "arm,v2m-timer" alias - any of the motherboard SP804
timers will be used instead.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi     |   11 ++---------
 arch/arm/boot/dts/vexpress-v2m.dtsi         |   11 ++---------
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts |    6 +++---
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts  |    6 +++---
 arch/arm/boot/dts/vexpress-v2p-ca5s.dts     |    6 +++---
 arch/arm/boot/dts/vexpress-v2p-ca9.dts      |    6 +++---
 arch/arm/mach-vexpress/v2m.c                |   16 ++++++++++------
 7 files changed, 26 insertions(+), 36 deletions(-)

diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index fffda1f..03b72de 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -17,13 +17,8 @@
  * CHANGES TO vexpress-v2m.dtsi!
  */
 
-/ {
-	aliases {
-		arm,v2m_timer = &v2m_timer01;
-	};
-
-	motherboard {
-		compatible = "simple-bus";
+		compatible = "arm,vexpress,v2m-p1", "simple-bus";
+		arm,hbi = <0x190>;
 		arm,vexpress,site = <0>;
 		arm,v2m-memory-map = "rs1";
 		#address-cells = <2>; /* SMB chipselect number and offset */
@@ -338,5 +333,3 @@
 				arm,vexpress-sysreg,func = <11 0>;
 			};
 		};
-	};
-};
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
index 10e05d9..b3b223a 100644
--- a/arch/arm/boot/dts/vexpress-v2m.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -17,13 +17,8 @@
  * CHANGES TO vexpress-v2m-rs1.dtsi!
  */
 
-/ {
-	aliases {
-		arm,v2m_timer = &v2m_timer01;
-	};
-
-	motherboard {
-		compatible = "simple-bus";
+		compatible = "arm,vexpress,v2m-p1", "simple-bus";
+		arm,hbi = <0x190>;
 		arm,vexpress,site = <0>;
 		#address-cells = <2>; /* SMB chipselect number and offset */
 		#size-cells = <1>;
@@ -337,5 +332,3 @@
 				arm,vexpress-sysreg,func = <11 0>;
 			};
 		};
-	};
-};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
index 7c237af..959bcb0 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
@@ -219,7 +219,7 @@
 		};
 	};
 
-	motherboard {
+	smb {
 		ranges = <0 0 0 0x08000000 0x04000000>,
 			 <1 0 0 0x14000000 0x04000000>,
 			 <2 0 0 0x18000000 0x04000000>,
@@ -271,7 +271,7 @@
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
 				<0 0 42 &gic 0 42 4>;
+
+		/include/ "vexpress-v2m-rs1.dtsi"
 	};
 };
-
-/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
index c41a82d..8a6d66d 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -303,7 +303,7 @@
 		};
 	};
 
-	motherboard {
+	smb {
 		ranges = <0 0 0 0x08000000 0x04000000>,
 			 <1 0 0 0x14000000 0x04000000>,
 			 <2 0 0 0x18000000 0x04000000>,
@@ -355,7 +355,7 @@
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
 				<0 0 42 &gic 0 42 4>;
+
+		/include/ "vexpress-v2m-rs1.dtsi"
 	};
 };
-
-/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
index 94486d6..e389066 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
@@ -182,7 +182,7 @@
 		};
 	};
 
-	motherboard {
+	smb {
 		ranges = <0 0 0x08000000 0x04000000>,
 			 <1 0 0x14000000 0x04000000>,
 			 <2 0 0x18000000 0x04000000>,
@@ -234,7 +234,7 @@
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
 				<0 0 42 &gic 0 42 4>;
+
+		/include/ "vexpress-v2m-rs1.dtsi"
 	};
 };
-
-/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
index bebbea4..8ab7995 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -259,7 +259,7 @@
 		};
 	};
 
-	motherboard {
+	smb {
 		ranges = <0 0 0x40000000 0x04000000>,
 			 <1 0 0x44000000 0x04000000>,
 			 <2 0 0x48000000 0x04000000>,
@@ -310,7 +310,7 @@
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
 				<0 0 42 &gic 0 42 4>;
+
+		/include/ "vexpress-v2m.dtsi"
 	};
 };
-
-/include/ "vexpress-v2m.dtsi"
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 827d02f..32ec333 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -393,7 +393,7 @@ static int __init v2m_dt_scan_memory_map(unsigned long node, const char *uname,
 {
 	const char **map = data;
 
-	if (strcmp(uname, "motherboard") != 0)
+	if (!of_flat_dt_is_compatible(node, "arm,vexpress,v2m-p1"))
 		return 0;
 
 	*map = of_get_flat_dt_prop(node, "arm,v2m-memory-map", NULL);
@@ -449,12 +449,16 @@ static void __init v2m_dt_timer_init(void)
 
 	vexpress_clk_of_init();
 
+	do {
+		node = of_find_compatible_node(node, NULL, "arm,sp804");
+	} while (node && vexpress_get_site_by_node(node) != VEXPRESS_SITE_MB);
+	if (node) {
+		pr_info("Using SP804 '%s' as a clock & events source\n",
+				node->full_name);
+		v2m_sp804_init(of_iomap(node, 0),
+				irq_of_parse_and_map(node, 0));
+	}
 
-	err = of_property_read_string(of_aliases, "arm,v2m_timer", &path);
-	if (WARN_ON(err))
-		return;
-	node = of_find_node_by_path(path);
-	v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0));
 	if (arch_timer_of_register() != 0)
 		twd_local_timer_of_register();
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 13/13] ARM: vexpress: Make the DEBUG_LL UART detection more specific
  2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
                   ` (11 preceding siblings ...)
  2012-09-18 14:17 ` [PATCH v2 12/13] ARM: vexpress: Remove motherboard dependencies in the DTS files Pawel Moll
@ 2012-09-18 14:17 ` Pawel Moll
  12 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

Base the UART detection heuristic on architecturally defined
MIDR register instead of implementation dependent CBAR. The
only tile using the original memory map is V2P-CA9 with Cortex
A9 r0p1, which MIDR contains 0x410fc091 value.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 arch/arm/mach-vexpress/include/mach/debug-macro.S |   10 ++++++----
 arch/arm/mach-vexpress/include/mach/uncompress.h  |   12 +++++-------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-vexpress/include/mach/debug-macro.S b/arch/arm/mach-vexpress/include/mach/debug-macro.S
index 9f509f5..0c6abbf 100644
--- a/arch/arm/mach-vexpress/include/mach/debug-macro.S
+++ b/arch/arm/mach-vexpress/include/mach/debug-macro.S
@@ -23,12 +23,14 @@
 		.macro	addruart,rp,rv,tmp
 
 		@ Make an educated guess regarding the memory map:
-		@ - the original A9 core tile, which has MPCore peripherals
-		@   located at 0x1e000000, should use UART at 0x10009000
+		@ - the original A9 core tile (based on ARM Cortex-A9 r0p1)
+		@   should use UART at 0x10009000
 		@ - all other (RS1 complaint) tiles use UART mapped
 		@   at 0x1c090000
-		mrc	p15, 4, \tmp, c15, c0, 0
-		cmp	\tmp, #0x1e000000
+		mrc	p15, 0, \rp, c0, c0, 0
+		movw	\rv, #0xc091
+		movt	\rv, #0x410f
+		cmp	\rp, \rv
 
 		@ Original memory map
 		moveq	\rp, #DEBUG_LL_UART_OFFSET
diff --git a/arch/arm/mach-vexpress/include/mach/uncompress.h b/arch/arm/mach-vexpress/include/mach/uncompress.h
index 1e472eb..8b8a2ef 100644
--- a/arch/arm/mach-vexpress/include/mach/uncompress.h
+++ b/arch/arm/mach-vexpress/include/mach/uncompress.h
@@ -17,6 +17,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <asm/cputype.h>
+
 #define AMBA_UART_DR(base)	(*(volatile unsigned char *)((base) + 0x00))
 #define AMBA_UART_LCRH(base)	(*(volatile unsigned char *)((base) + 0x2c))
 #define AMBA_UART_CR(base)	(*(volatile unsigned char *)((base) + 0x30))
@@ -28,18 +30,14 @@
 static unsigned long get_uart_base(void)
 {
 #if defined(CONFIG_DEBUG_VEXPRESS_UART0_DETECT)
-	unsigned long mpcore_periph;
-
 	/*
 	 * Make an educated guess regarding the memory map:
-	 * - the original A9 core tile, which has MPCore peripherals
-	 *   located at 0x1e000000, should use UART at 0x10009000
+	 * - the original A9 core tile (based on ARM Cortex-A9 r0p1)
+	 *   should use UART at 0x10009000
 	 * - all other (RS1 complaint) tiles use UART mapped
 	 *   at 0x1c090000
 	 */
-	asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (mpcore_periph));
-
-	if (mpcore_periph == 0x1e000000)
+	if (read_cpuid_id() == 0x410fc091)
 		return UART_BASE;
 	else
 		return UART_BASE_RS1;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-18 14:17 ` [PATCH v2 04/13] regulators: Versatile Express regulator driver Pawel Moll
@ 2012-09-18 15:02   ` Mark Brown
  2012-09-18 15:44     ` Pawel Moll
  0 siblings, 1 reply; 37+ messages in thread
From: Mark Brown @ 2012-09-18 15:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 18, 2012 at 03:17:46PM +0100, Pawel Moll wrote:
> Implementation of the regulator framework driver for the
> Versatile Express voltage control. Devices without
> voltage constraints (ie. "regulator-[min|max]-microvolt"
> properties in the DT node) are treated as fixed (or rather
> read-only) regulators.

This doesn't seem great...  it doesn't seem to know or represent
anything at all about the hardware, I'd expect a voltage regulator to at
a minimum be able to implement list_voltage().  You've not provided any
information on what the hardware actually is and the driver just seems
to proxy through to some other API which actually implements the
regulator support.

> +	init_data->constraints.apply_uV = 0;

This seems broken, why are you interfering with the supplied
constraints?

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 08/13] mfd: Versatile Express system registers driver
  2012-09-18 14:17 ` [PATCH v2 08/13] mfd: Versatile Express system registers driver Pawel Moll
@ 2012-09-18 15:24   ` Arnd Bergmann
  2012-09-19 10:53     ` Pawel Moll
  0 siblings, 1 reply; 37+ messages in thread
From: Arnd Bergmann @ 2012-09-18 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 18 September 2012, Pawel Moll wrote:
> +The node describing a config device must refer to the sysreg node via
> +"arm,vexpress,config-bridge" phandle (can be also defined in the node's
> +parent) and relies on the board topology properties - see main vexpress
> +node documentation for more details. It must must also define the
> +following property:
> +- arm,vexpress-sysreg,func : must contain two cells:
> +  - first cell defines function number (eg. 1 for clock generator,
> +    2 for voltage regulators etc.)
> +  - device number (eg. osc 0, osc 1 etc.)
> +
> +Example:
> +       mcc {
> +               arm,vexpress,config-bridge = <&v2m_sysreg>;
> +
> +               osc at 0 {
> +                       compatible = "arm,vexpress-osc";
> +                       arm,vexpress-sysreg,func = <1 0>;
> +               };
> +       };

Why are you using a nonstandard property for the address?
AFAICT, the same can be expressed normally doing

       mcc {
	        #address-cells = <2>;
	 	#size-cells = <0>;
               arm,vexpress,config-bridge = <&v2m_sysreg>;

               osc at 0 {
                       compatible = "arm,vexpress-osc";
                       reg = <1 0>;
               };
       };

which is more in line with how we represent e.g. i2c buses.

	Arnd

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 03/13] hwmon: Versatile Express hwmon driver
  2012-09-18 14:17 ` [PATCH v2 03/13] hwmon: Versatile Express hwmon driver Pawel Moll
@ 2012-09-18 15:24   ` Guenter Roeck
  2012-09-18 15:45     ` Jean Delvare
  2012-09-19 17:04     ` Pawel Moll
  0 siblings, 2 replies; 37+ messages in thread
From: Guenter Roeck @ 2012-09-18 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 18, 2012 at 03:17:45PM +0100, Pawel Moll wrote:
> hwmon framework driver for Versatile Express sensors, providing
> information about board level voltage (only when regulator driver
> is not configured), currents, temperature and power/energy usage.
> Labels for the values can be defined as DT properties.
> 
> Signed-off-by: Pawel Moll <pawel.moll@arm.com>
> ---
>  drivers/hwmon/Kconfig    |    8 ++
>  drivers/hwmon/Makefile   |    1 +
>  drivers/hwmon/vexpress.c |  330 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 339 insertions(+)
>  create mode 100644 drivers/hwmon/vexpress.c
> 
> Hi Jean, Guenter,
> 
> Would you be able to merge this in time for 3.7? (if it looks fine, that is)
> 
> Regards
> 
> Pawel
> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index b0a2e4c..7359a07 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -1187,6 +1187,14 @@ config SENSORS_TWL4030_MADC
>  	This driver can also be built as a module. If so it will be called
>  	twl4030-madc-hwmon.
>  
> +config SENSORS_VEXPRESS
> +	tristate "Versatile Express"
> +	depends on VEXPRESS_CONFIG
> +	help
> +	  This driver provides support for hardware sensors available on
> +	  the ARM Ltd's Versatile Express platform. It can provide wide
> +	  range of information like temperature, power, energy.
> +
>  config SENSORS_VIA_CPUTEMP
>  	tristate "VIA CPU temperature sensor"
>  	depends on X86
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 7aa9811..e719a7d 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -120,6 +120,7 @@ obj-$(CONFIG_SENSORS_TMP102)	+= tmp102.o
>  obj-$(CONFIG_SENSORS_TMP401)	+= tmp401.o
>  obj-$(CONFIG_SENSORS_TMP421)	+= tmp421.o
>  obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
> +obj-$(CONFIG_SENSORS_VEXPRESS)	+= vexpress.o
>  obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
>  obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
>  obj-$(CONFIG_SENSORS_VT1211)	+= vt1211.o
> diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c
> new file mode 100644
> index 0000000..fe80c63
> --- /dev/null
> +++ b/drivers/hwmon/vexpress.c
> @@ -0,0 +1,330 @@
> +/*
> + * 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) 2012 ARM Limited
> + */
> +
> +#define DRVNAME "vexpress-hwmon"
> +#define pr_fmt(fmt) DRVNAME ": " fmt
> +
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/hwmon.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/vexpress.h>
> +
> +static struct device *vexpress_hwmon_dev;
> +static int vexpress_hwmon_dev_refcount;
> +static DEFINE_SPINLOCK(vexpress_hwmon_dev_lock);
> +
> +static ssize_t vexpress_hwmon_name_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	return sprintf(buffer, "%s\n", DRVNAME);
> +}
> +
> +static struct device_attribute vexpress_hwmon_name_attr =
> +		__ATTR(name, 0444, vexpress_hwmon_name_show, NULL);
> +
> +struct vexpress_hwmon_attrs {
> +	struct vexpress_config_func *func;
> +	const char *label;
> +	struct device_attribute label_attr;
> +	char label_name[16];
> +	struct device_attribute input_attr;
> +	char input_name[16];
> +	u32 divisor;
> +};
> +
> +static ssize_t vexpress_hwmon_label_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
> +			struct vexpress_hwmon_attrs, label_attr);
> +
> +	return snprintf(buffer, PAGE_SIZE, "%s\n", attrs->label);
> +}
> +
> +static ssize_t vexpress_hwmon_u32_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
> +			struct vexpress_hwmon_attrs, input_attr);
> +	int err;
> +	u32 value;
> +
> +	err = vexpress_config_read(attrs->func, 0, &value);
> +	if (err)
> +		return err;
> +
> +	return snprintf(buffer, PAGE_SIZE, "%u\n", value / attrs->divisor);
> +}
> +
> +static ssize_t vexpress_hwmon_u64_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
> +			struct vexpress_hwmon_attrs, input_attr);
> +	int err;
> +	u32 value_hi, value_lo;
> +
> +	err = vexpress_config_read(attrs->func, 0, &value_lo);
> +	if (err)
> +		return err;
> +
> +	err = vexpress_config_read(attrs->func, 1, &value_hi);
> +	if (err)
> +		return err;
> +
> +	return snprintf(buffer, PAGE_SIZE, "%llu\n",
> +			div_u64(((u64)value_hi << 32) | value_lo,
> +			attrs->divisor));
> +}
> +
> +static struct device *vexpress_hwmon_dev_get(void)
> +{
> +	struct device *result;
> +
> +	spin_lock(&vexpress_hwmon_dev_lock);
> +
> +	if (vexpress_hwmon_dev) {
> +		result = vexpress_hwmon_dev;
> +	} else {
> +		int err;
> +
> +		result = hwmon_device_register(NULL);
> +		if (IS_ERR(result))
> +			goto out;
> +
> +		err = device_create_file(result, &vexpress_hwmon_name_attr);
> +		if (err) {
> +			result = ERR_PTR(err);
> +			hwmon_device_unregister(result);
> +			goto out;
> +		}
> +
> +		vexpress_hwmon_dev = result;
> +	}
> +
> +	vexpress_hwmon_dev_refcount++;
> +
> +out:
> +	spin_unlock(&vexpress_hwmon_dev_lock);
> +
> +	return result;
> +}
> +
> +static void vexpress_hwmon_dev_put(void)
> +{
> +	spin_lock(&vexpress_hwmon_dev_lock);
> +
> +	if (--vexpress_hwmon_dev_refcount == 0) {
> +		hwmon_device_unregister(vexpress_hwmon_dev);
> +		vexpress_hwmon_dev = NULL;
> +	}
> +
> +	WARN_ON(vexpress_hwmon_dev_refcount < 0);
> +
> +	spin_unlock(&vexpress_hwmon_dev_lock);
> +}
> +
This is a highly unusual means to register a hwmon driver (and you are leaking
the name attribute on remove as far as I can see).

> +struct vexpress_hwmon_func {
> +	const char *name;
> +	bool wide;
> +	u32 divisor;
> +	atomic_t index;
> +};
> +
> +#if !defined(CONFIG_REGULATOR_VEXPRESS)
> +static struct vexpress_hwmon_func vexpress_hwmon_volt = {
> +	.name = "in",
> +	.divisor = 1000,
> +};
> +#endif
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_amp = {
> +	.name = "curr",
> +	.divisor = 1000,
> +};
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_temp = {
> +	.name = "temp",
> +	.divisor = 1000,
> +};
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_power = {
> +	.name = "power",
> +	.divisor = 1,
> +};
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_energy = {
> +	.name = "energy",
> +	.wide = true,
> +	.divisor = 1,
> +};
> +
> +static struct of_device_id vexpress_hwmon_of_match[] = {
> +#if !defined(CONFIG_REGULATOR_VEXPRESS)
> +	{
> +		.compatible = "arm,vexpress-volt",
> +		.data = &vexpress_hwmon_volt,
> +	},
> +#endif
> +	{
> +		.compatible = "arm,vexpress-amp",
> +		.data = &vexpress_hwmon_amp,
> +	}, {
> +		.compatible = "arm,vexpress-temp",
> +		.data = &vexpress_hwmon_temp,
> +	}, {
> +		.compatible = "arm,vexpress-power",
> +		.data = &vexpress_hwmon_power,
> +	}, {
> +		.compatible = "arm,vexpress-energy",
> +		.data = &vexpress_hwmon_energy,
> +	},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match);
> +
> +static int vexpress_hwmon_probe(struct platform_device *pdev)
> +{
> +	int err;
> +	const struct of_device_id *match;
> +	struct vexpress_hwmon_func *hwmon_func;
> +	struct device *hwmon_dev;
> +	struct vexpress_hwmon_attrs *attrs;
> +	const char *attr_name;
> +	int attr_index;
> +
> +	match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
> +	if (!match) {
> +		err = -EINVAL;
> +		goto error_match_device;
> +	}
> +	hwmon_func = match->data;
> +
> +	hwmon_dev = vexpress_hwmon_dev_get();
> +	if (IS_ERR(hwmon_dev)) {
> +		err = PTR_ERR(hwmon_dev);
> +		goto error_hwmon_dev_get;
> +	}
> +
> +	attrs = devm_kzalloc(&pdev->dev, sizeof(*attrs), GFP_KERNEL);
> +	if (!attrs) {
> +		err = -ENOMEM;
> +		goto error_kzalloc;
> +	}
> +
> +	attrs->func = vexpress_config_func_get_by_dev(&pdev->dev);
> +	if (!attrs->func) {
> +		err = -ENXIO;
> +		goto error_get_func;
> +	}
> +
> +	err = sysfs_create_link(&pdev->dev.kobj, &hwmon_dev->kobj, "hwmon");
> +	if (err)
> +		goto error_create_link;
> +
> +	attr_index = atomic_inc_return(&hwmon_func->index);
> +	attr_name = hwmon_func->name;
> +
> +	snprintf(attrs->input_name, sizeof(attrs->input_name),
> +			"%s%d_input", attr_name, attr_index);
> +	attrs->input_attr.attr.name = attrs->input_name;
> +	attrs->input_attr.attr.mode = 0444;
> +	if (hwmon_func->wide)
> +		attrs->input_attr.show = vexpress_hwmon_u64_show;
> +	else
> +		attrs->input_attr.show = vexpress_hwmon_u32_show;
> +	sysfs_attr_init(&attrs->input_attr.attr);
> +	err = device_create_file(hwmon_dev, &attrs->input_attr);
> +	if (err)
> +		goto error_create_input;
> +
and a highly unusual way of, as much as I understand of it, bypass the hwmon
infrastructure as much as possible.

I don't even understand what you are trying to do, much less why you don't
just use the existing infrastructure, and I don't have time to try to figure
it out. Maybe Jean has time to review this driver, but not me.

So, no, for my part I don't think it would be a good idea to rush this driver
into 3.7.

Really, I would suggest to submit a standard hwmon driver (there are lots of
examples out there).

Guenter

> +	attrs->label = of_get_property(pdev->dev.of_node, "label", NULL);
> +	if (attrs->label) {
> +		snprintf(attrs->label_name, sizeof(attrs->label_name),
> +				"%s%d_label", attr_name, attr_index);
> +		attrs->label_attr.attr.name = attrs->label_name;
> +		attrs->label_attr.attr.mode = 0444;
> +		attrs->label_attr.show = vexpress_hwmon_label_show;
> +		sysfs_attr_init(&attrs->label_attr.attr);
> +		err = device_create_file(hwmon_dev, &attrs->label_attr);
> +		if (err)
> +			goto error_create_label;
> +	}
> +
> +	attrs->divisor = hwmon_func->divisor;
> +
> +	platform_set_drvdata(pdev, attrs);
> +
> +	return 0;
> +
> +error_create_label:
> +	device_remove_file(hwmon_dev, &attrs->input_attr);
> +error_create_input:
> +	sysfs_remove_link(&pdev->dev.kobj, "hwmon");
> +error_create_link:
> +	vexpress_config_func_put(attrs->func);
> +error_get_func:
> +error_kzalloc:
> +	vexpress_hwmon_dev_put();
> +error_hwmon_dev_get:
> +error_match_device:
> +	return err;
> +}
> +
> +static int __devexit vexpress_hwmon_remove(struct platform_device *pdev)
> +{
> +	struct vexpress_hwmon_attrs *attrs = platform_get_drvdata(pdev);
> +	const struct of_device_id *match =
> +		of_match_device(vexpress_hwmon_of_match, &pdev->dev);
> +	struct vexpress_hwmon_func *hwmon_func = match->data;
> +
> +	if (attrs->label)
> +		device_remove_file(vexpress_hwmon_dev, &attrs->label_attr);
> +	device_remove_file(vexpress_hwmon_dev, &attrs->input_attr);
> +	atomic_dec(&hwmon_func->index);
> +	sysfs_remove_link(&pdev->dev.kobj, "hwmon");
> +	vexpress_config_func_put(attrs->func);
> +	vexpress_hwmon_dev_put();
> +
> +	return 0;
> +}
> +
> +static struct platform_driver vexpress_hwmon_driver = {
> +	.probe = vexpress_hwmon_probe,
> +	.remove = __devexit_p(vexpress_hwmon_remove),
> +	.driver	= {
> +		.name = DRVNAME,
> +		.owner = THIS_MODULE,
> +		.of_match_table = vexpress_hwmon_of_match,
> +	},
> +};
> +
> +static int __init vexpress_hwmon_init(void)
> +{
> +	return platform_driver_register(&vexpress_hwmon_driver);
> +}
> +
> +static void __exit vexpress_hwmon_exit(void)
> +{
> +	platform_driver_unregister(&vexpress_hwmon_driver);
> +}
> +
> +MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
> +MODULE_DESCRIPTION("Versatile Express hwmon");
> +MODULE_LICENSE("GPL");
> +
> +module_init(vexpress_hwmon_init);
> +module_exit(vexpress_hwmon_exit);
> -- 
> 1.7.9.5
> 
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-18 15:02   ` Mark Brown
@ 2012-09-18 15:44     ` Pawel Moll
  2012-09-18 16:09       ` Mark Brown
  0 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 15:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-18 at 16:02 +0100, Mark Brown wrote:
> On Tue, Sep 18, 2012 at 03:17:46PM +0100, Pawel Moll wrote:
> > Implementation of the regulator framework driver for the
> > Versatile Express voltage control. Devices without
> > voltage constraints (ie. "regulator-[min|max]-microvolt"
> > properties in the DT node) are treated as fixed (or rather
> > read-only) regulators.
> 
> This doesn't seem great...  it doesn't seem to know or represent
> anything at all about the hardware, I'd expect a voltage regulator to at
> a minimum be able to implement list_voltage().  You've not provided any
> information on what the hardware actually is and the driver just seems
> to proxy through to some other API which actually implements the
> regulator support.

Well, that's what it really is. The config API sends a request "set xyz
uV" to the microcontrollers. And the micro can (at least in theory) get
you any voltage within the min/max limits by whatever means it has (at
least some of the daugtherboards use micro's DAC to adjust reference
voltage for a DC/DC converter with a feedback loop using ADC).

But fair enough, I should have done better work in describing this.

> > +	init_data->constraints.apply_uV = 0;
> 
> This seems broken, why are you interfering with the supplied
> constraints?

Hm. It's been about a month since I wrote that, so the best I can tell
now is "because fixed.c does the same" (and that's what I was looking
at)... Anyway, looked at the code again and tried everything without
that line and indeed I see no reason to do that, so consider it gone.

v3 to follow.

Cheers!

Pawel

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 03/13] hwmon: Versatile Express hwmon driver
  2012-09-18 15:24   ` Guenter Roeck
@ 2012-09-18 15:45     ` Jean Delvare
  2012-09-18 20:59       ` Guenter Roeck
  2012-09-19 17:04     ` Pawel Moll
  1 sibling, 1 reply; 37+ messages in thread
From: Jean Delvare @ 2012-09-18 15:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 18 Sep 2012 08:24:30 -0700, Guenter Roeck wrote:
> I don't even understand what you are trying to do, much less why you don't
> just use the existing infrastructure, and I don't have time to try to figure
> it out. Maybe Jean has time to review this driver, but not me.

No, I do not. My backlog is huge already :(

-- 
Jean Delvare

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-18 15:44     ` Pawel Moll
@ 2012-09-18 16:09       ` Mark Brown
  2012-09-18 17:03         ` Pawel Moll
  0 siblings, 1 reply; 37+ messages in thread
From: Mark Brown @ 2012-09-18 16:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 18, 2012 at 04:44:16PM +0100, Pawel Moll wrote:

> Well, that's what it really is. The config API sends a request "set xyz
> uV" to the microcontrollers. And the micro can (at least in theory) get
> you any voltage within the min/max limits by whatever means it has (at
> least some of the daugtherboards use micro's DAC to adjust reference
> voltage for a DC/DC converter with a feedback loop using ADC).

And the microcontroller is incapable of telling us what it supports, or
even what's physically present?

> But fair enough, I should have done better work in describing this.

So this is going to break interoperation with a bunch of consumer
drivers that rely on being able to tell what voltages are supported.
The key thing for them would be that regulator_is_supported_voltage()
works, currently it relies on list_voltage() as that's the only way to
do that right now.

> v3 to follow.

v3?  I didn't see V2.  Please also CC posts to the relevant mailing
lists for the subsystem (lkml in this case).

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-18 16:09       ` Mark Brown
@ 2012-09-18 17:03         ` Pawel Moll
  2012-09-19  2:21           ` Mark Brown
  0 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-18 17:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-18 at 17:09 +0100, Mark Brown wrote:
> On Tue, Sep 18, 2012 at 04:44:16PM +0100, Pawel Moll wrote:
> 
> > Well, that's what it really is. The config API sends a request "set xyz
> > uV" to the microcontrollers. And the micro can (at least in theory) get
> > you any voltage within the min/max limits by whatever means it has (at
> > least some of the daugtherboards use micro's DAC to adjust reference
> > voltage for a DC/DC converter with a feedback loop using ADC).
> 
> And the microcontroller is incapable of telling us what it supports, 

No, there is no such . Device Tree defines per-device min/max
constraints and any value between these values should be supported.

> or even what's physically present?

You mean read back what voltage is set now? By all means - that's what
it is doing for "read only" devices.

> > But fair enough, I should have done better work in describing this.
> 
> So this is going to break interoperation with a bunch of consumer
> drivers that rely on being able to tell what voltages are supported.
> The key thing for them would be that regulator_is_supported_voltage()
> works, currently it relies on list_voltage() as that's the only way to
> do that right now.

Ok, I guess I should use regulator_list_voltage_linear() and
regulator_map_voltage_linear() then? I'll just have to carefully think
what step to choose.

> > v3 to follow.
> 
> v3?  I didn't see V2.  Please also CC posts to the relevant mailing
> lists for the subsystem (lkml in this case).

Sure, will do.

Pawel

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 03/13] hwmon: Versatile Express hwmon driver
  2012-09-18 15:45     ` Jean Delvare
@ 2012-09-18 20:59       ` Guenter Roeck
  0 siblings, 0 replies; 37+ messages in thread
From: Guenter Roeck @ 2012-09-18 20:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 18, 2012 at 05:45:59PM +0200, Jean Delvare wrote:
> On Tue, 18 Sep 2012 08:24:30 -0700, Guenter Roeck wrote:
> > I don't even understand what you are trying to do, much less why you don't
> > just use the existing infrastructure, and I don't have time to try to figure
> > it out. Maybe Jean has time to review this driver, but not me.
> 
> No, I do not. My backlog is huge already :(
> 
then my conclusion is NACK and that it should be changed to a regular hwmon
driver. I'll be happy to review it once that is done.

Guenter

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-18 17:03         ` Pawel Moll
@ 2012-09-19  2:21           ` Mark Brown
  2012-09-19 16:58             ` Pawel Moll
  0 siblings, 1 reply; 37+ messages in thread
From: Mark Brown @ 2012-09-19  2:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 18, 2012 at 06:03:39PM +0100, Pawel Moll wrote:
> On Tue, 2012-09-18 at 17:09 +0100, Mark Brown wrote:

> > or even what's physically present?

> You mean read back what voltage is set now? By all means - that's what
> it is doing for "read only" devices.

No, I mean discovering which regulators are present and what they can
do.

> > So this is going to break interoperation with a bunch of consumer
> > drivers that rely on being able to tell what voltages are supported.
> > The key thing for them would be that regulator_is_supported_voltage()
> > works, currently it relies on list_voltage() as that's the only way to
> > do that right now.

> Ok, I guess I should use regulator_list_voltage_linear() and
> regulator_map_voltage_linear() then? I'll just have to carefully think
> what step to choose.

No, we should provide a way to describe this situation in the API - it's
not unreasonable and having to pick step sizes is obviously suboptimal.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 08/13] mfd: Versatile Express system registers driver
  2012-09-18 15:24   ` Arnd Bergmann
@ 2012-09-19 10:53     ` Pawel Moll
  2012-09-19 11:17       ` Arnd Bergmann
  0 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-19 10:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-18 at 16:24 +0100, Arnd Bergmann wrote:
> On Tuesday 18 September 2012, Pawel Moll wrote:
> > +The node describing a config device must refer to the sysreg node via
> > +"arm,vexpress,config-bridge" phandle (can be also defined in the node's
> > +parent) and relies on the board topology properties - see main vexpress
> > +node documentation for more details. It must must also define the
> > +following property:
> > +- arm,vexpress-sysreg,func : must contain two cells:
> > +  - first cell defines function number (eg. 1 for clock generator,
> > +    2 for voltage regulators etc.)
> > +  - device number (eg. osc 0, osc 1 etc.)
> > +
> > +Example:
> > +       mcc {
> > +               arm,vexpress,config-bridge = <&v2m_sysreg>;
> > +
> > +               osc at 0 {
> > +                       compatible = "arm,vexpress-osc";
> > +                       arm,vexpress-sysreg,func = <1 0>;
> > +               };
> > +       };
> 
> Why are you using a nonstandard property for the address?
> AFAICT, the same can be expressed normally doing
> 
>        mcc {
> 	        #address-cells = <2>;
> 	 	#size-cells = <0>;
>                arm,vexpress,config-bridge = <&v2m_sysreg>;
> 
>                osc at 0 {
>                        compatible = "arm,vexpress-osc";
>                        reg = <1 0>;
>                };
>        };
> 
> which is more in line with how we represent e.g. i2c buses.

Yes, but I2C devices are created by of_i2c_register_devices() which
knows how to interpret the reg property. And here, as these are normal
platform devices now (as you suggested), the of_platform_bus_create()
will treat it as a normal address, translate it via ranges and create
IORESOURCE_MEM out of it... And that's what I wanted to avoid. Maybe
unnecessarily?

Pawel

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 08/13] mfd: Versatile Express system registers driver
  2012-09-19 10:53     ` Pawel Moll
@ 2012-09-19 11:17       ` Arnd Bergmann
  2012-09-19 11:45         ` Pawel Moll
  0 siblings, 1 reply; 37+ messages in thread
From: Arnd Bergmann @ 2012-09-19 11:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 19 September 2012, Pawel Moll wrote:
> On Tue, 2012-09-18 at 16:24 +0100, Arnd Bergmann wrote:
> > On Tuesday 18 September 2012, Pawel Moll wrote:
> 
> Yes, but I2C devices are created by of_i2c_register_devices() which
> knows how to interpret the reg property. And here, as these are normal
> platform devices now (as you suggested), the of_platform_bus_create()
> will treat it as a normal address, translate it via ranges and create
> IORESOURCE_MEM out of it... And that's what I wanted to avoid. Maybe
> unnecessarily?

You are right, this is a bit nasty, it should not attempt to do this.
Basically the reg parsing logic has a hack to work around apply PowerMac
firmware that misses some "ranges" properties.

I think we should change the DT parsing code to not create those
resources if there is a bus that can't be translated.

	Arnd

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 08/13] mfd: Versatile Express system registers driver
  2012-09-19 11:17       ` Arnd Bergmann
@ 2012-09-19 11:45         ` Pawel Moll
  0 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-19 11:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2012-09-19 at 12:17 +0100, Arnd Bergmann wrote:
> On Wednesday 19 September 2012, Pawel Moll wrote:
> > On Tue, 2012-09-18 at 16:24 +0100, Arnd Bergmann wrote:
> > > On Tuesday 18 September 2012, Pawel Moll wrote:
> > 
> > Yes, but I2C devices are created by of_i2c_register_devices() which
> > knows how to interpret the reg property. And here, as these are normal
> > platform devices now (as you suggested), the of_platform_bus_create()
> > will treat it as a normal address, translate it via ranges and create
> > IORESOURCE_MEM out of it... And that's what I wanted to avoid. Maybe
> > unnecessarily?
> 
> You are right, this is a bit nasty, it should not attempt to do this.
> Basically the reg parsing logic has a hack to work around apply PowerMac
> firmware that misses some "ranges" properties.
> 
> I think we should change the DT parsing code to not create those
> resources if there is a bus that can't be translated.

Well, I actually think the current solution is fine - the default bus is
the platform one, I'm creating a platform device, so the code can assume
that reg is a normal address and create an IORESOURCE_MEM from it. It's
just that my platform device is not memory mapped, so I don't really
want this to happen.

One way of working this around would be not using "simple-bus" as the
parent of my config devices, so that normal of_platform_populate() will
not create them, and then have a simple dcc driver that will do nothing
except for creating platform devices in a custom way.

Pawe?

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 07/13] misc: Versatile Express config infrastructure
  2012-09-18 14:17 ` [PATCH v2 07/13] misc: Versatile Express config infrastructure Pawel Moll
@ 2012-09-19 13:08   ` Arnd Bergmann
  2012-09-20 12:06     ` Pawel Moll
  0 siblings, 1 reply; 37+ messages in thread
From: Arnd Bergmann @ 2012-09-19 13:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 18 September 2012, Pawel Moll wrote:

> Hi Arnd,
> 
> As it doesn't seem to be a "bus" any more, I left it in in misc for
> now... It looks to me like there should be some kind of place for
> "system/soc control" drivers. Or maybe there is, and I just missed
> it?

We've discussed a generic system controller framework in the past,
but it hasn't happened so far.  Dong Aisheng has posted a
"syscon" driver a few times, and it could eventually merge with
this one.

For now, I'd suggest you put this driver into drivers/mfd together
with the other part from your patch 8.

	Arnd

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-19  2:21           ` Mark Brown
@ 2012-09-19 16:58             ` Pawel Moll
  2012-09-20 13:01               ` Mark Brown
  0 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-19 16:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2012-09-19 at 03:21 +0100, Mark Brown wrote:
> No, I mean discovering which regulators are present and what they can
> do.

Nope. This driver is supposed to work only on Device Tree "enabled"
platforms. Having said that, I should have added the bindings
documentation in the patch. Will do.

> > > So this is going to break interoperation with a bunch of consumer
> > > drivers that rely on being able to tell what voltages are supported.
> > > The key thing for them would be that regulator_is_supported_voltage()
> > > works, currently it relies on list_voltage() as that's the only way to
> > > do that right now.
> 
> > Ok, I guess I should use regulator_list_voltage_linear() and
> > regulator_map_voltage_linear() then? I'll just have to carefully think
> > what step to choose.
> 
> No, we should provide a way to describe this situation in the API - it's
> not unreasonable and having to pick step sizes is obviously suboptimal.

Actually before I finally got this mail (our mail system was playing
stupid today), I came up with idea of using the power supply specified
tolerance as a base to chose the step sizes. This comes down to such
code (with the regulator_*_voltage_linear in the ops):

8<---
                int range = init_data->constraints.max_uV -
                                init_data->constraints.min_uV;
                u32 tolerance;
                int avg_error;

                err = of_property_read_u32(pdev->dev.of_node,
                                "arm,vexpress-volt,tolerance", &tolerance);
                if (err)
                        goto error_property_read;

                reg->desc.min_uV = init_data->constraints.min_uV;
                avg_error = (range / 2 + reg->desc.min_uV) * tolerance / 100;
                reg->desc.n_voltages = range / avg_error + 1;
                reg->desc.uV_step = range / (reg->desc.n_voltages - 1);
8<---

so it doesn't look that bad to me. Now, if you are considering changing
the API, I would propose something like this:

8<---
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 4838531..a091719 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1948,8 +1948,14 @@ int regulator_is_supported_voltage(struct regulator *regulator,
        }
 
        ret = regulator_count_voltages(regulator);
-       if (ret < 0)
-               return ret;
+       if (ret < 0) {
+               /* No operating points defined, allow any value within range */
+               struct regulation_constraints *constraints =
+                               regulator->rdev->constraints;
+
+               return min_uV >= constraints->min_uV &&
+                               max_uV <= constraints->max_uV;
+       }
        voltages = ret;
 
        for (i = 0; i < voltages; i++) {
8<---

I originally assumed that if I provide no operating points (in the form
of list_voltage function) any voltage within the constraints range will
be allowed.

Both options are perfectly fine with me.

Thanks!

Pawel

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 03/13] hwmon: Versatile Express hwmon driver
  2012-09-18 15:24   ` Guenter Roeck
  2012-09-18 15:45     ` Jean Delvare
@ 2012-09-19 17:04     ` Pawel Moll
  2012-09-20  2:03       ` Guenter Roeck
  1 sibling, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-19 17:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Guenter,

Thanks for your quick response (and apologies about me being delayed), I
appreciate your time!

On Tue, 2012-09-18 at 16:24 +0100, Guenter Roeck wrote:
> and a highly unusual way of, as much as I understand of it, bypass the hwmon
> infrastructure as much as possible.

I can assure you that it wasn't my aim. Generally, my platform has a lot
of small "control" devices providing one sensor each. And as they are
separate from the device model point of view, I wanted them to be
logically grouped around a single hwmon device (I was actually looking
at the coretemp driver). But it's not a big deal, really.

> I don't even understand what you are trying to do, much less why you don't
> just use the existing infrastructure, and I don't have time to try to figure
> it out. Maybe Jean has time to review this driver, but not me.
> 
> So, no, for my part I don't think it would be a good idea to rush this driver
> into 3.7.
> 
> Really, I would suggest to submit a standard hwmon driver (there are lots of
> examples out there).

Sure thing, I'll quickly spin a simplified version and post it for
review.

Thanks!

Pawel

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 03/13] hwmon: Versatile Express hwmon driver
  2012-09-19 17:04     ` Pawel Moll
@ 2012-09-20  2:03       ` Guenter Roeck
  0 siblings, 0 replies; 37+ messages in thread
From: Guenter Roeck @ 2012-09-20  2:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 19, 2012 at 06:04:48PM +0100, Pawel Moll wrote:
> Hi Guenter,
> 
> Thanks for your quick response (and apologies about me being delayed), I
> appreciate your time!
> 
> On Tue, 2012-09-18 at 16:24 +0100, Guenter Roeck wrote:
> > and a highly unusual way of, as much as I understand of it, bypass the hwmon
> > infrastructure as much as possible.
> 
> I can assure you that it wasn't my aim. Generally, my platform has a lot
> of small "control" devices providing one sensor each. And as they are
> separate from the device model point of view, I wanted them to be
> logically grouped around a single hwmon device (I was actually looking
> at the coretemp driver). But it's not a big deal, really.
> 
I don't think the coretemp driver does what you are doing in your driver ...

> > I don't even understand what you are trying to do, much less why you don't
> > just use the existing infrastructure, and I don't have time to try to figure
> > it out. Maybe Jean has time to review this driver, but not me.
> > 
> > So, no, for my part I don't think it would be a good idea to rush this driver
> > into 3.7.
> > 
> > Really, I would suggest to submit a standard hwmon driver (there are lots of
> > examples out there).
> 
> Sure thing, I'll quickly spin a simplified version and post it for
> review.
> 
When you do that, please have a look at Documentation/hwmon/submitting-patches,
specifically the "New drivers" section.

Regarding your device model, yes, it is a bit odd that you have a separate
platform device for each sensor, especially if the vexpress is physically a
single chip. It would be much simpler to have a single vexpress-hwmon platform
device instead. But if you insist having such a complicated platform device
architecture, you should not try to clean it up with a complicated and
difficult to understand hwmon driver.

Thanks,
Guenter

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 07/13] misc: Versatile Express config infrastructure
  2012-09-19 13:08   ` Arnd Bergmann
@ 2012-09-20 12:06     ` Pawel Moll
  2012-09-20 12:36       ` Arnd Bergmann
  0 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-20 12:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2012-09-19 at 14:08 +0100, Arnd Bergmann wrote:
> > As it doesn't seem to be a "bus" any more, I left it in in misc for
> > now... It looks to me like there should be some kind of place for
> > "system/soc control" drivers. Or maybe there is, and I just missed
> > it?
> 
> We've discussed a generic system controller framework in the past,
> but it hasn't happened so far.  Dong Aisheng has posted a
> "syscon" driver a few times, and it could eventually merge with
> this one.

Yep, a generic framework for "random collection of stuff" would be
useful.

> For now, I'd suggest you put this driver into drivers/mfd together
> with the other part from your patch 8.

Do you mean - merge it into one file? I'd rather avoid that - the time
will come (and probably sooner than I would hope) when there will be a
new VE generation with some other "config bridge" instead of the
sysregs.

Pawe?

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 07/13] misc: Versatile Express config infrastructure
  2012-09-20 12:06     ` Pawel Moll
@ 2012-09-20 12:36       ` Arnd Bergmann
  2012-09-20 12:37         ` Pawel Moll
  0 siblings, 1 reply; 37+ messages in thread
From: Arnd Bergmann @ 2012-09-20 12:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 20 September 2012, Pawel Moll wrote:
> > For now, I'd suggest you put this driver into drivers/mfd together
> > with the other part from your patch 8.
> 
> Do you mean - merge it into one file? I'd rather avoid that - the time
> will come (and probably sooner than I would hope) when there will be a
> new VE generation with some other "config bridge" instead of the
> sysregs.

No, just leave it at two files. We have a number of examples of mfd drivers
that have a common part and e.g. i2c and spi based files as back-ends.
For now, you'd just build both files together.

	Arnd

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 07/13] misc: Versatile Express config infrastructure
  2012-09-20 12:36       ` Arnd Bergmann
@ 2012-09-20 12:37         ` Pawel Moll
  0 siblings, 0 replies; 37+ messages in thread
From: Pawel Moll @ 2012-09-20 12:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 2012-09-20 at 13:36 +0100, Arnd Bergmann wrote:
> On Thursday 20 September 2012, Pawel Moll wrote:
> > > For now, I'd suggest you put this driver into drivers/mfd together
> > > with the other part from your patch 8.
> > 
> > Do you mean - merge it into one file? I'd rather avoid that - the time
> > will come (and probably sooner than I would hope) when there will be a
> > new VE generation with some other "config bridge" instead of the
> > sysregs.
> 
> No, just leave it at two files. We have a number of examples of mfd drivers
> that have a common part and e.g. i2c and spi based files as back-ends.
> For now, you'd just build both files together.

Sure thing, thanks!

Pawe?

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-19 16:58             ` Pawel Moll
@ 2012-09-20 13:01               ` Mark Brown
  2012-09-20 17:34                 ` Pawel Moll
  0 siblings, 1 reply; 37+ messages in thread
From: Mark Brown @ 2012-09-20 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 19, 2012 at 05:58:25PM +0100, Pawel Moll wrote:
> On Wed, 2012-09-19 at 03:21 +0100, Mark Brown wrote:

> > No, we should provide a way to describe this situation in the API - it's
> > not unreasonable and having to pick step sizes is obviously suboptimal.

> Actually before I finally got this mail (our mail system was playing
> stupid today), I came up with idea of using the power supply specified
> tolerance as a base to chose the step sizes. This comes down to such
> code (with the regulator_*_voltage_linear in the ops):

That's probably OK, though check that the numbers come out sensible
(people tend to work to nice round numbers).

> +       if (ret < 0) {
> +               /* No operating points defined, allow any value within range */
> +               struct regulation_constraints *constraints =
> +                               regulator->rdev->constraints;
> +
> +               return min_uV >= constraints->min_uV &&
> +                               max_uV <= constraints->max_uV;
> +       }

I'd rather have the driver explicitly say it supports continuous
voltages with a flag in the descriptor (to make sure we don't end up
being overly optimistic because the driver wasn't well implemented) but
other than that this looks good.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-20 13:01               ` Mark Brown
@ 2012-09-20 17:34                 ` Pawel Moll
  2012-09-20 18:15                   ` Mark Brown
  0 siblings, 1 reply; 37+ messages in thread
From: Pawel Moll @ 2012-09-20 17:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 2012-09-20 at 14:01 +0100, Mark Brown wrote:
> > Actually before I finally got this mail (our mail system was playing
> > stupid today), I came up with idea of using the power supply specified
> > tolerance as a base to chose the step sizes. This comes down to such
> > code (with the regulator_*_voltage_linear in the ops):
> 
> That's probably OK, though check that the numbers come out sensible
> (people tend to work to nice round numbers).

These calculations try to maximize the range, but in most cases it's
impossible to be exactly in line with constraints. The delta should be
less then 1%, eg. in my test case I get:

A15 Vcore: override max_uV, 1050000 -> 1049990
A15 Vcore: 800 <--> 1049 mV at 906 mV 

I could try to add more math to interpolate the operating points to get
perfect match, but this sounds like a serious overkill...

> > +       if (ret < 0) {
> > +               /* No operating points defined, allow any value within range */
> > +               struct regulation_constraints *constraints =
> > +                               regulator->rdev->constraints;
> > +
> > +               return min_uV >= constraints->min_uV &&
> > +                               max_uV <= constraints->max_uV;
> > +       }
> 
> I'd rather have the driver explicitly say it supports continuous
> voltages with a flag in the descriptor (to make sure we don't end up
> being overly optimistic because the driver wasn't well implemented) 

Ok, so I see two options:

1. Something like bool "regulator_desc.linear"

2. A magic value for regulator_desc.n_voltages, something like
	#define N_VOLTAGES_LINEAR (~0)

Does any of them seem reasonable?

Pawel

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 04/13] regulators: Versatile Express regulator driver
  2012-09-20 17:34                 ` Pawel Moll
@ 2012-09-20 18:15                   ` Mark Brown
  0 siblings, 0 replies; 37+ messages in thread
From: Mark Brown @ 2012-09-20 18:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 20, 2012 at 06:34:32PM +0100, Pawel Moll wrote:

> These calculations try to maximize the range, but in most cases it's
> impossible to be exactly in line with constraints. The delta should be
> less then 1%, eg. in my test case I get:

No, what I mean is that we don't want steps of 343uV or something.

> 1. Something like bool "regulator_desc.linear"

> 2. A magic value for regulator_desc.n_voltages, something like
> 	#define N_VOLTAGES_LINEAR (~0)

> Does any of them seem reasonable?

The former of them seems much more tasteful, though I'd go with
continuous_volt or something, we already have linear maps.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 05/13] clk: Versatile Express clock generators ("osc") driver
  2012-09-18 14:17 ` [PATCH v2 05/13] clk: Versatile Express clock generators ("osc") driver Pawel Moll
@ 2012-10-29 17:44   ` Mike Turquette
  0 siblings, 0 replies; 37+ messages in thread
From: Mike Turquette @ 2012-10-29 17:44 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Pawel Moll (2012-09-18 07:17:47)
> This driver provides a common clock framework hardware driver
> for Versatile Express clock generators (a.k.a "osc") controlled
> via the config bus.
> 
> Signed-off-by: Pawel Moll <pawel.moll@arm.com>
> ---
>  drivers/clk/versatile/Makefile           |    1 +
>  drivers/clk/versatile/clk-vexpress-osc.c |  146 ++++++++++++++++++++++++++++++
>  2 files changed, 147 insertions(+)
>  create mode 100644 drivers/clk/versatile/clk-vexpress-osc.c
> 
> Hi Mike,
> 
> As agreed - this patch and the next one ("clk: Common clocks
> implementation for Versatile Express") are all yours.
> 

Taken into clk-next.

Thanks,
Mike

> Regards
> 
> Pawel
> 
> diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
> index c0a0f64..1e49a7a 100644
> --- a/drivers/clk/versatile/Makefile
> +++ b/drivers/clk/versatile/Makefile
> @@ -2,3 +2,4 @@
>  obj-$(CONFIG_ICST)             += clk-icst.o
>  obj-$(CONFIG_ARCH_INTEGRATOR)  += clk-integrator.o
>  obj-$(CONFIG_ARCH_REALVIEW)    += clk-realview.o
> +obj-$(CONFIG_VEXPRESS_CONFIG)  += clk-vexpress-osc.o
> diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
> new file mode 100644
> index 0000000..dcb6ae0
> --- /dev/null
> +++ b/drivers/clk/versatile/clk-vexpress-osc.c
> @@ -0,0 +1,146 @@
> +/*
> + * 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) 2012 ARM Limited
> + */
> +
> +#define pr_fmt(fmt) "vexpress-osc: " fmt
> +
> +#include <linux/clkdev.h>
> +#include <linux/clk-provider.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/vexpress.h>
> +
> +struct vexpress_osc {
> +       struct vexpress_config_func *func;
> +       struct clk_hw hw;
> +       unsigned long rate_min;
> +       unsigned long rate_max;
> +};
> +
> +#define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw)
> +
> +static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw,
> +               unsigned long parent_rate)
> +{
> +       struct vexpress_osc *osc = to_vexpress_osc(hw);
> +       u32 rate;
> +
> +       vexpress_config_read(osc->func, 0, &rate);
> +
> +       return rate;
> +}
> +
> +static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate,
> +               unsigned long *parent_rate)
> +{
> +       struct vexpress_osc *osc = to_vexpress_osc(hw);
> +
> +       if (WARN_ON(osc->rate_min && rate < osc->rate_min))
> +               rate = osc->rate_min;
> +
> +       if (WARN_ON(osc->rate_max && rate > osc->rate_max))
> +               rate = osc->rate_max;
> +
> +       return rate;
> +}
> +
> +static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate,
> +               unsigned long parent_rate)
> +{
> +       struct vexpress_osc *osc = to_vexpress_osc(hw);
> +
> +       return vexpress_config_write(osc->func, 0, rate);
> +}
> +
> +static struct clk_ops vexpress_osc_ops = {
> +       .recalc_rate = vexpress_osc_recalc_rate,
> +       .round_rate = vexpress_osc_round_rate,
> +       .set_rate = vexpress_osc_set_rate,
> +};
> +
> +
> +struct clk * __init vexpress_osc_setup(struct device *dev)
> +{
> +       struct clk_init_data init;
> +       struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL);
> +
> +       if (!osc)
> +               return NULL;
> +
> +       osc->func = vexpress_config_func_get_by_dev(dev);
> +       if (!osc->func) {
> +               kfree(osc);
> +               return NULL;
> +       }
> +
> +       init.name = dev_name(dev);
> +       init.ops = &vexpress_osc_ops;
> +       init.flags = CLK_IS_ROOT;
> +       init.num_parents = 0;
> +       osc->hw.init = &init;
> +
> +       return clk_register(NULL, &osc->hw);
> +}
> +
> +void __init vexpress_osc_of_setup(struct device_node *node)
> +{
> +       struct clk_init_data init;
> +       struct vexpress_osc *osc;
> +       struct clk *clk;
> +       u32 range[2];
> +
> +       osc = kzalloc(sizeof(*osc), GFP_KERNEL);
> +       if (!osc)
> +               goto error;
> +
> +       osc->func = vexpress_config_func_get_by_node(node);
> +       if (!osc->func) {
> +               pr_err("Failed to obtain config func for node '%s'!\n",
> +                               node->name);
> +               goto error;
> +       }
> +
> +       if (of_property_read_u32_array(node, "freq-range", range,
> +                       ARRAY_SIZE(range)) == 0) {
> +               osc->rate_min = range[0];
> +               osc->rate_max = range[1];
> +       }
> +
> +       of_property_read_string(node, "clock-output-names", &init.name);
> +       if (!init.name)
> +               init.name = node->name;
> +
> +       init.ops = &vexpress_osc_ops;
> +       init.flags = CLK_IS_ROOT;
> +       init.num_parents = 0;
> +
> +       osc->hw.init = &init;
> +
> +       clk = clk_register(NULL, &osc->hw);
> +       if (IS_ERR(clk)) {
> +               pr_err("Failed to register clock '%s'!\n", init.name);
> +               goto error;
> +       }
> +
> +       of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +
> +       pr_debug("Registered clock '%s'\n", init.name);
> +
> +       return;
> +
> +error:
> +       if (osc->func)
> +               vexpress_config_func_put(osc->func);
> +       kfree(osc);
> +}
> -- 
> 1.7.9.5

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2012-10-29 17:44 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
2012-09-18 14:17 ` [PATCH v2 01/13] input: ambakmi: (Un)prepare clocks when (dis)enabling Pawel Moll
2012-09-18 14:17 ` [PATCH v2 02/13] video: Versatile Express display output driver Pawel Moll
2012-09-18 14:17 ` [PATCH v2 03/13] hwmon: Versatile Express hwmon driver Pawel Moll
2012-09-18 15:24   ` Guenter Roeck
2012-09-18 15:45     ` Jean Delvare
2012-09-18 20:59       ` Guenter Roeck
2012-09-19 17:04     ` Pawel Moll
2012-09-20  2:03       ` Guenter Roeck
2012-09-18 14:17 ` [PATCH v2 04/13] regulators: Versatile Express regulator driver Pawel Moll
2012-09-18 15:02   ` Mark Brown
2012-09-18 15:44     ` Pawel Moll
2012-09-18 16:09       ` Mark Brown
2012-09-18 17:03         ` Pawel Moll
2012-09-19  2:21           ` Mark Brown
2012-09-19 16:58             ` Pawel Moll
2012-09-20 13:01               ` Mark Brown
2012-09-20 17:34                 ` Pawel Moll
2012-09-20 18:15                   ` Mark Brown
2012-09-18 14:17 ` [PATCH v2 05/13] clk: Versatile Express clock generators ("osc") driver Pawel Moll
2012-10-29 17:44   ` Mike Turquette
2012-09-18 14:17 ` [PATCH v2 06/13] clk: Common clocks implementation for Versatile Express Pawel Moll
2012-09-18 14:17 ` [PATCH v2 07/13] misc: Versatile Express config infrastructure Pawel Moll
2012-09-19 13:08   ` Arnd Bergmann
2012-09-20 12:06     ` Pawel Moll
2012-09-20 12:36       ` Arnd Bergmann
2012-09-20 12:37         ` Pawel Moll
2012-09-18 14:17 ` [PATCH v2 08/13] mfd: Versatile Express system registers driver Pawel Moll
2012-09-18 15:24   ` Arnd Bergmann
2012-09-19 10:53     ` Pawel Moll
2012-09-19 11:17       ` Arnd Bergmann
2012-09-19 11:45         ` Pawel Moll
2012-09-18 14:17 ` [PATCH v2 09/13] ARM: vexpress: Reset driver Pawel Moll
2012-09-18 14:17 ` [PATCH v2 10/13] ARM: vexpress: Add config bus components and clocks to DTs Pawel Moll
2012-09-18 14:17 ` [PATCH v2 11/13] ARM: vexpress: Start using new Versatile Express infrastructure Pawel Moll
2012-09-18 14:17 ` [PATCH v2 12/13] ARM: vexpress: Remove motherboard dependencies in the DTS files Pawel Moll
2012-09-18 14:17 ` [PATCH v2 13/13] ARM: vexpress: Make the DEBUG_LL UART detection more specific Pawel Moll

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).