All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] Versatile Express infrastructure
@ 2012-09-03 16:25 Pawel Moll
  2012-09-03 16:25 ` [PATCH 01/11] input: ambakmi: Add missing clk_[un]prepare() calls Pawel Moll
                   ` (10 more replies)
  0 siblings, 11 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 UTC (permalink / raw)
  To: linux-arm-kernel

Hi All,

This series is a complete set of patches implementing platform
control infrastructure, clocking etc. It is sent as a one off
for completeness, but eventually ambakmi, hwmon and regulators
patches will go through their subsystems.

The clocking patches depend on Linus Walleij's "clk: convert
ARM RealView to common clk" and should go through Mike
Turquette's tree. I am a little bit worried about merging
this, as it depends on the "config_bus" infrastructure which
should go through arm-soc. Any ideas and suggestions more
then welcome.

Most of the random bits and pieces (reset controllers and alike)
are located in drivers/misc/vexpress now, and I'm more than
happy to move them if anyone has better idea.

Regards

Pawel


Pawel Moll (11):
  input: ambakmi: Add missing clk_[un]prepare() calls
  misc: Versatile Express config bus infrastructure
  misc: Versatile Express reset driver
  misc: Versatile Express display muxer driver
  clk: Versatile Express clock generators ("osc") driver
  clk: Common clocks implementation for Versatile Express
  regulators: Versatile Express regulator driver
  hwmon: Versatile Express hwmon driver
  misc: Versatile Express system registers driver
  ARM: vexpress: Add config bus components and clocks to DTs
  ARM: vexpress: Start using new Versatile Express infrastructure

 Documentation/devicetree/bindings/arm/vexpress.txt |  173 +++++-
 arch/arm/Kconfig                                   |    4 +-
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi            |  136 ++++-
 arch/arm/boot/dts/vexpress-v2m.dtsi                |  136 ++++-
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts        |  103 ++++
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts         |  169 ++++++
 arch/arm/boot/dts/vexpress-v2p-ca5s.dts            |   71 +++
 arch/arm/boot/dts/vexpress-v2p-ca9.dts             |  121 ++++
 arch/arm/include/asm/hardware/sp810.h              |    6 +-
 arch/arm/mach-vexpress/ct-ca9x4.c                  |   37 +-
 arch/arm/mach-vexpress/include/mach/motherboard.h  |   81 ---
 arch/arm/mach-vexpress/platsmp.c                   |    3 +-
 arch/arm/mach-vexpress/v2m.c                       |  321 +++--------
 drivers/clk/Kconfig                                |    8 +-
 drivers/clk/versatile/Makefile                     |    2 +
 drivers/clk/versatile/clk-vexpress-osc.c           |  154 +++++
 drivers/clk/versatile/clk-vexpress.c               |  174 ++++++
 drivers/hwmon/Kconfig                              |    8 +
 drivers/hwmon/Makefile                             |    1 +
 drivers/hwmon/vexpress.c                           |  275 +++++++++
 drivers/input/serio/ambakmi.c                      |    9 +-
 drivers/misc/Kconfig                               |    1 +
 drivers/misc/Makefile                              |    1 +
 drivers/misc/vexpress/Kconfig                      |    5 +
 drivers/misc/vexpress/Makefile                     |    4 +
 drivers/misc/vexpress/config_bus.c                 |  596 ++++++++++++++++++++
 drivers/misc/vexpress/display.c                    |  197 +++++++
 drivers/misc/vexpress/reset.c                      |  110 ++++
 drivers/misc/vexpress/sysreg.c                     |  423 ++++++++++++++
 drivers/regulator/Kconfig                          |    7 +
 drivers/regulator/Makefile                         |    1 +
 drivers/regulator/vexpress.c                       |  144 +++++
 include/linux/vexpress.h                           |  150 +++++
 33 files changed, 3257 insertions(+), 374 deletions(-)
 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/misc/vexpress/Kconfig
 create mode 100644 drivers/misc/vexpress/Makefile
 create mode 100644 drivers/misc/vexpress/config_bus.c
 create mode 100644 drivers/misc/vexpress/display.c
 create mode 100644 drivers/misc/vexpress/reset.c
 create mode 100644 drivers/misc/vexpress/sysreg.c
 create mode 100644 drivers/regulator/vexpress.c
 create mode 100644 include/linux/vexpress.h

-- 
1.7.9.5

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

* [PATCH 01/11] input: ambakmi: Add missing clk_[un]prepare() calls
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-04 13:37   ` Thomas Petazzoni
  2012-09-03 16:25 ` [PATCH 02/11] misc: Versatile Express config bus infrastructure Pawel Moll
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 UTC (permalink / raw)
  To: linux-arm-kernel

Clocks must be prepared before enabling and unprepared
after disabling. Without that clk_enable() fails with
warning.

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

diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 2ffd110..ab2d25b 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -72,10 +72,14 @@ static int amba_kmi_open(struct serio *io)
 	unsigned int divisor;
 	int ret;
 
-	ret = clk_enable(kmi->clk);
+	ret = clk_prepare(kmi->clk);
 	if (ret)
 		goto out;
 
+	ret = clk_enable(kmi->clk);
+	if (ret)
+		goto clk_unprepare;
+
 	divisor = clk_get_rate(kmi->clk) / 8000000 - 1;
 	writeb(divisor, KMICLKDIV);
 	writeb(KMICR_EN, KMICR);
@@ -93,6 +97,8 @@ static int amba_kmi_open(struct serio *io)
 
  clk_disable:
 	clk_disable(kmi->clk);
+ clk_unprepare:
+	clk_unprepare(kmi->clk);
  out:
 	return ret;
 }
@@ -105,6 +111,7 @@ static void amba_kmi_close(struct serio *io)
 
 	free_irq(kmi->irq, kmi);
 	clk_disable(kmi->clk);
+	clk_unprepare(kmi->clk);
 }
 
 static int __devinit amba_kmi_probe(struct amba_device *dev,
-- 
1.7.9.5

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

* [PATCH 02/11] misc: Versatile Express config bus infrastructure
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
  2012-09-03 16:25 ` [PATCH 01/11] input: ambakmi: Add missing clk_[un]prepare() calls Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-03 21:17   ` Arnd Bergmann
  2012-09-03 16:25 ` [PATCH 03/11] misc: Versatile Express reset driver Pawel Moll
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 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 in a
form of "config bus".

The devices (and their functions) are addressed by: site
number (motherboard is 0, daughterboard sites 1 and 2),
position in the boards stack (eg. logic tiles are often
stacked on top of each other), controller number (boards can
have more then one controller) and the device number (eg.
oscillators 1 to 5, temperature sensors 1 to 3 etc.).

Function number (eg. oscillator is 1, temperature sensor is 4)
is common across all system and is used to bind devices with
respective drivers. Static devices can use defined constants,
devices instantiated from a DT should use appropriate compatible
values that will be translated into numbers during device
creation.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 Documentation/devicetree/bindings/arm/vexpress.txt |  154 ++++-
 drivers/misc/Kconfig                               |    1 +
 drivers/misc/Makefile                              |    1 +
 drivers/misc/vexpress/Kconfig                      |    5 +
 drivers/misc/vexpress/Makefile                     |    1 +
 drivers/misc/vexpress/config_bus.c                 |  596 ++++++++++++++++++++
 include/linux/vexpress.h                           |  120 ++++
 7 files changed, 877 insertions(+), 1 deletion(-)
 create mode 100644 drivers/misc/vexpress/Kconfig
 create mode 100644 drivers/misc/vexpress/Makefile
 create mode 100644 drivers/misc/vexpress/config_bus.c
 create mode 100644 include/linux/vexpress.h

diff --git a/Documentation/devicetree/bindings/arm/vexpress.txt b/Documentation/devicetree/bindings/arm/vexpress.txt
index ec8b50c..8f69b6b 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,10 @@ with device_type = "cpu" property for every available core, eg.:
 		};
 	};
 
+
+Motherboard node
+----------------
+
 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,7 +108,132 @@ 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:
+
+Configuration bus
+-----------------
+
+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
+are addressed by: site number (motherboard is 0, daughterboard
+sites 1 and 2), position in the boards stack (eg. logic tiles
+are often stacked on top of each other), controller number
+(boards can have more then one controller) and the device number
+(eg.  oscillators 1 to 5, temperature sensors 1 to 3 etc.).
+
+They should be by a separate node of the device tree, called
+"dcc" or "mcc", with the following required properties:
+- site number:
+	arm,vexpress,site = <number>;
+  where 0 means motherboard, 1 or 2 are daugtherboard sites,
+  0xff means "master" site (site containing main CPU tile)
+- address and size cells for the children
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+Optional properties:
+- position and/or controller number:
+	arm,vexpress,position = <number>;
+	arm,vexpress,dcc = <number>;
+  if not defined, the numbers default to zero.
+
+The controller's node children define functions of all
+devices available through the controller. The compatible
+value defines the function, the reg value defines the
+device number.
+
+- clock generators:
+	osc@<device> {
+		compatible = "arm,vexpress-config,osc";
+		reg = <device>;
+		freq-range = <freq_min freq_max>;
+		#clock-cells = <0>;
+		clock-output-names = "<name>";
+	};
+
+- voltage regulators:
+	volt@<device> {
+		compatible = "arm,vexpress-config,volt";
+		reg = <device>;
+		regulator-name = "<name>";
+		regulator-always-on;
+	};
+
+- current meters:
+	amp@<device> {
+		compatible = "arm,vexpress-config,amp";
+		reg = <device>;
+		label = "<name>";
+	};
+
+- temperature sensors:
+	temp@<device> {
+		compatible = "arm,vexpress-config,temp";
+		reg = <device>;
+		label = "<name>";
+	};
+
+- reset generator:
+	reset@<device> {
+		compatible = "arm,vexpress-config,reset";
+		reg = <device>;
+	};
+
+- SCC registers access:
+	scc@<device> {
+		compatible = "arm,vexpress-config,scc";
+		reg = <device>;
+	};
+
+- DVI muxing (switching) FPGAs:
+	muxfpga@<device> {
+		compatible = "arm,vexpress-config,muxfpga";
+		reg = <device>;
+	};
+
+- power supply control:
+	shutdown@<device> {
+		compatible = "arm,vexpress-config,shutdown";
+		reg = <0>;
+	};
+	reboot@<device> {
+		compatible = "arm,vexpress-config,reboot";
+		reg = <device>;
+	};
+
+- DVI formatter mode control:
+	dvimode@<device> {
+		compatible = "arm,vexpress-config,dvimode";
+		reg = <device>;
+	};
+
+- instant power monitors:
+	power@<device> {
+		compatible = "arm,vexpress-config,power";
+		reg = <device>;
+		label = "<name>";
+	};
+
+- continuous energy consumption monitors:
+	energy@<device> {
+		compatible = "arm,vexpress-config,energy";
+		reg = <device>;
+		label = "<name>";
+	};
+  Note: Amount of the consumed energy is available as a 64-bit
+  value, in two consecutive registers.
+
+
+Example of a VE tile description (simplified)
+---------------------------------------------
 
 /dts-v1/;
 
@@ -141,6 +278,21 @@ Abbreviated example:
 		/* Active high IRQ 0 is connected to GIC's SPI0 */
 		interrupt-map = <0 0 0 &gic 0 0 4>;
 	};
+
+	dcc at 0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#interrupt-cells = <0>;
+		arm,vexpress,site = <0xff>; /* Master site */
+
+		osc at 0 {
+			compatible = "arm,vexpress-config,osc";
+			reg = <0>;
+			freq-range = <50000000 100000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk0";
+		};
+	};
 };
 
 /include/ "vexpress-v2m-rs1.dtsi"
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 98a442d..2a9434a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -517,4 +517,5 @@ source "drivers/misc/lis3lv02d/Kconfig"
 source "drivers/misc/carma/Kconfig"
 source "drivers/misc/altera-stapl/Kconfig"
 source "drivers/misc/mei/Kconfig"
+source "drivers/misc/vexpress/Kconfig"
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b88df7a..49964fd 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-y				+= vexpress/
diff --git a/drivers/misc/vexpress/Kconfig b/drivers/misc/vexpress/Kconfig
new file mode 100644
index 0000000..887f103
--- /dev/null
+++ b/drivers/misc/vexpress/Kconfig
@@ -0,0 +1,5 @@
+config VEXPRESS_CONFIG_BUS
+	bool
+	help
+	  Infrastructure for the ARM Ltd. Versatile Expres platform
+	  configuration bus.
diff --git a/drivers/misc/vexpress/Makefile b/drivers/misc/vexpress/Makefile
new file mode 100644
index 0000000..5b1e8fc
--- /dev/null
+++ b/drivers/misc/vexpress/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += config_bus.o
diff --git a/drivers/misc/vexpress/config_bus.c b/drivers/misc/vexpress/config_bus.c
new file mode 100644
index 0000000..3609987
--- /dev/null
+++ b/drivers/misc/vexpress/config_bus.c
@@ -0,0 +1,596 @@
+/*
+ * 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 ADDR_FMT "%u.%x:%x:%x:%x"
+
+#define ADDR_ARGS(_ptr) \
+		_ptr->func, _ptr->addr.site, _ptr->addr.position, \
+		_ptr->addr.dcc, _ptr->addr.device
+
+#define ADDR_TO_U64(addr) \
+		(((u64)(addr).site << 32) | ((addr).position << 24) | \
+		((addr).dcc << 16) | (addr).device)
+
+static bool vexpress_config_early = true;
+static DEFINE_MUTEX(vexpress_config_early_mutex);
+static LIST_HEAD(vexpress_config_early_drivers);
+static LIST_HEAD(vexpress_config_early_devices);
+
+static int vexpress_config_match(struct device *dev, struct device_driver *drv)
+{
+	struct vexpress_config_device *vecdev = to_vexpress_config_device(dev);
+	struct vexpress_config_driver *vecdrv = to_vexpress_config_driver(drv);
+
+	if (vecdrv->funcs) {
+		const unsigned *func = vecdrv->funcs;
+
+		while (*func) {
+			if (*func == vecdev->func)
+				return 1;
+			func++;
+		}
+	}
+
+	return 0;
+}
+
+static struct device vexpress_config_bus = {
+	.init_name = "vexpress-config",
+};
+
+struct bus_type vexpress_config_bus_type = {
+	.name = "vexpress-config",
+	.match = vexpress_config_match,
+};
+
+static int __init vexpress_config_bus_init(void)
+{
+	int err;
+	struct vexpress_config_driver *vecdrv, *__vecdrv;
+	struct vexpress_config_device *vecdev, *__vecdev;
+
+	err = device_register(&vexpress_config_bus);
+	if (err)
+		return err;
+
+	err = bus_register(&vexpress_config_bus_type);
+	if (err) {
+		device_unregister(&vexpress_config_bus);
+		return err;
+	}
+
+	vexpress_config_early = false;
+
+	list_for_each_entry_safe(vecdrv, __vecdrv,
+			&vexpress_config_early_drivers, early) {
+		err = vexpress_config_driver_register(vecdrv);
+		if (err)
+			pr_err("Failed to re-register early driver '%s'! (%d)\n",
+					vecdrv->driver.name, err);
+		list_del(&vecdrv->early);
+	}
+
+	list_for_each_entry_safe(vecdev, __vecdev,
+			&vexpress_config_early_devices, early) {
+		err = vexpress_config_device_register(vecdev);
+		if (err)
+			pr_err("Failed to re-register early device '%s."
+					ADDR_FMT "'! (%d)\n", vecdev->name,
+					ADDR_ARGS(vecdev), err);
+		list_del(&vecdev->early);
+	}
+
+	return 0;
+}
+arch_initcall(vexpress_config_bus_init);
+
+static void vexpress_config_early_probe(struct vexpress_config_device *vecdev,
+		struct vexpress_config_driver *vecdrv)
+{
+	int err;
+
+	if (!vecdrv->probe) {
+		pr_debug("Skipping early probing of '%s." ADDR_FMT "'\n",
+				vecdev->name, ADDR_ARGS(vecdev));
+		return;
+	}
+
+	err = vecdrv->probe(vecdev);
+	if (err) {
+		pr_err("Failed to probe '%s." ADDR_FMT "! (%d)\n",
+				vecdev->name, ADDR_ARGS(vecdev), err);
+		return;
+	}
+
+	vecdev->status |= VEXPRESS_CONFIG_DEVICE_PROBED_EARLY;
+}
+
+static void vexpress_config_early_bind(void)
+{
+	struct vexpress_config_driver *vecdrv;
+	struct vexpress_config_device *vecdev;
+
+	list_for_each_entry(vecdev, &vexpress_config_early_devices, early)
+		list_for_each_entry(vecdrv, &vexpress_config_early_drivers,
+				early)
+			if (vexpress_config_match(&vecdev->dev,
+					&vecdrv->driver))
+				vexpress_config_early_probe(vecdev, vecdrv);
+}
+
+
+#define VEXPRESS_CONFIG_MAX_BRIDGES 2
+
+struct vexpress_config_bridge {
+	struct vexpress_config_bridge_info *info;
+	struct list_head transactions;
+	spinlock_t transactions_lock;
+	bool transaction_pending;
+	struct list_head list;
+} vexpress_config_bridges[VEXPRESS_CONFIG_MAX_BRIDGES];
+
+DECLARE_BITMAP(vexpress_config_bridges_map,
+		ARRAY_SIZE(vexpress_config_bridges));
+static DEFINE_SPINLOCK(vexpress_config_bridges_lock);
+
+static int vexpress_config_bridge_find(struct device *dev, void *data)
+{
+	struct vexpress_config_device *vecdev = to_vexpress_config_device(dev);
+	u64 dev_addr = ADDR_TO_U64(vecdev->addr);
+	unsigned long best_weight = 65;
+	int i;
+
+	pr_debug("Device '%s." ADDR_FMT "' (%llx)\n",
+			vecdev->name, ADDR_ARGS(vecdev), dev_addr);
+
+	vecdev->bridge = NULL;
+
+	/* Find the best, that is the most specific, bridge */
+	for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++) {
+		struct vexpress_config_bridge *bridge;
+		u64 br_addr, br_mask;
+		unsigned long weight;
+
+		if (!test_bit(i, vexpress_config_bridges_map))
+			continue;
+		bridge = &vexpress_config_bridges[i];
+
+		br_addr = ADDR_TO_U64(bridge->info->addr);
+		br_mask = ADDR_TO_U64(bridge->info->mask);
+		weight = br_mask ? hweight64(br_mask) : 64;
+
+		pr_debug("Bridge '%s' (%llx & %llx), weight %lu\n",
+				bridge->info->name, br_addr, br_mask, weight);
+
+		if ((dev_addr & br_mask) == br_addr && weight < best_weight) {
+			pr_debug("Bridge '%s' best so far\n",
+					bridge->info->name);
+			vecdev->bridge = bridge;
+			best_weight = weight;
+		}
+	}
+
+	return 0;
+}
+
+static void vexpress_config_bridges_assign(void)
+{
+	if (vexpress_config_early) {
+		struct vexpress_config_device *vecdev;
+
+		list_for_each_entry(vecdev, &vexpress_config_early_devices,
+				early)
+			vexpress_config_bridge_find(&vecdev->dev, NULL);
+	} else {
+		bus_for_each_dev(&vexpress_config_bus_type, NULL, NULL,
+				vexpress_config_bridge_find);
+	}
+}
+
+struct vexpress_config_bridge *vexpress_config_bridge_register(
+		struct vexpress_config_bridge_info *info)
+{
+	struct vexpress_config_bridge *bridge;
+	int i;
+
+	pr_debug("Registering bridge '%s'\n", info->name);
+
+	spin_lock(&vexpress_config_bridges_lock);
+
+	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");
+		spin_unlock(&vexpress_config_bridges_lock);
+		return NULL;
+	}
+	__set_bit(i, vexpress_config_bridges_map);
+	bridge = &vexpress_config_bridges[i];
+
+	bridge->info = info;
+	INIT_LIST_HEAD(&bridge->transactions);
+	spin_lock_init(&bridge->transactions_lock);
+
+	vexpress_config_bridges_assign();
+
+	spin_unlock(&vexpress_config_bridges_lock);
+
+	return bridge;
+}
+
+void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge)
+{
+	struct vexpress_config_bridge __bridge = *bridge;
+	int i;
+
+	spin_lock(&vexpress_config_bridges_lock);
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++)
+		if (&vexpress_config_bridges[i] == bridge)
+			__clear_bit(i, vexpress_config_bridges_map);
+
+	vexpress_config_bridges_assign();
+
+	spin_unlock(&vexpress_config_bridges_lock);
+
+	WARN_ON(!list_empty(&__bridge.transactions));
+	while (!list_empty(&__bridge.transactions))
+		cpu_relax();
+}
+
+
+static u8 vexpress_config_master_site = VEXPRESS_SITE_MASTER;
+
+void vexpress_config_set_master_site(u8 site)
+{
+	vexpress_config_master_site = site;
+}
+
+u8 vexpress_config_get_master_site(void)
+{
+	return vexpress_config_master_site;
+}
+
+
+#define VEXPRESS_COMPATIBLE_TO_FUNC(_compatible, _func) \
+	{ \
+		.compatible = "arm,vexpress-config," _compatible, \
+		.data = (void *)VEXPRESS_CONFIG_FUNC_##_func \
+	}
+
+static struct of_device_id vexpress_config_devices_matches[] = {
+	VEXPRESS_COMPATIBLE_TO_FUNC("osc", OSC),
+	VEXPRESS_COMPATIBLE_TO_FUNC("volt", VOLT),
+	VEXPRESS_COMPATIBLE_TO_FUNC("amp", AMP),
+	VEXPRESS_COMPATIBLE_TO_FUNC("temp", TEMP),
+	VEXPRESS_COMPATIBLE_TO_FUNC("reset", RESET),
+	VEXPRESS_COMPATIBLE_TO_FUNC("scc", SCC),
+	VEXPRESS_COMPATIBLE_TO_FUNC("muxfpga", MUXFPGA),
+	VEXPRESS_COMPATIBLE_TO_FUNC("shutdown", SHUTDOWN),
+	VEXPRESS_COMPATIBLE_TO_FUNC("reboot", REBOOT),
+	VEXPRESS_COMPATIBLE_TO_FUNC("dvimode", DVIMODE),
+	VEXPRESS_COMPATIBLE_TO_FUNC("power", POWER),
+	VEXPRESS_COMPATIBLE_TO_FUNC("energy", ENERGY),
+	{},
+};
+
+static void vexpress_config_of_device_add(struct device_node *node)
+{
+	int err;
+	struct vexpress_config_device *vecdev;
+	const struct of_device_id *match;
+	u32 value;
+
+	if (!of_device_is_available(node))
+		return;
+
+	vecdev = kzalloc(sizeof(*vecdev), GFP_KERNEL);
+	if (WARN_ON(!vecdev))
+		return;
+
+	vecdev->dev.of_node = of_node_get(node);
+
+	vecdev->name = node->name;
+
+	match = of_match_node(vexpress_config_devices_matches, node);
+	vecdev->func = (unsigned)match->data;
+
+	err = of_property_read_u32(node->parent, "arm,vexpress,site", &value);
+	if (!err)
+		vecdev->addr.site = value;
+
+	err = of_property_read_u32(node->parent, "arm,vexpress,position",
+			&value);
+	if (!err)
+		vecdev->addr.position = value;
+
+	err = of_property_read_u32(node->parent, "arm,vexpress,dcc", &value);
+	if (!err)
+		vecdev->addr.dcc = value;
+
+	err = of_property_read_u32(node, "reg", &value);
+	if (!err) {
+		vecdev->addr.device = value;
+	} else {
+		pr_err("Invalid reg property in '%s'! (%d)\n",
+				node->full_name, err);
+		kfree(vecdev);
+		return;
+	}
+
+	err = vexpress_config_device_register(vecdev);
+	if (err) {
+		pr_err("Failed to add OF device '%s'! (%d)\n",
+				node->full_name, err);
+		kfree(vecdev);
+		return;
+	}
+}
+
+void vexpress_config_of_populate(void)
+{
+	struct device_node *node;
+
+	for_each_matching_node(node, vexpress_config_devices_matches)
+		vexpress_config_of_device_add(node);
+}
+
+
+int vexpress_config_device_register(struct vexpress_config_device *vecdev)
+{
+	pr_debug("Registering %sdevice '%s." ADDR_FMT "'\n",
+			vexpress_config_early ? "early " : "",
+			vecdev->name, ADDR_ARGS(vecdev));
+
+	if (vecdev->addr.site == VEXPRESS_SITE_MASTER)
+		vecdev->addr.site = vexpress_config_get_master_site();
+
+	if (!vecdev->bridge) {
+		spin_lock(&vexpress_config_bridges_lock);
+		vexpress_config_bridge_find(&vecdev->dev, NULL);
+		spin_unlock(&vexpress_config_bridges_lock);
+	}
+
+	if (vexpress_config_early) {
+		list_add(&vecdev->early, &vexpress_config_early_devices);
+		vexpress_config_early_bind();
+
+		return 0;
+	}
+
+	device_initialize(&vecdev->dev);
+	vecdev->dev.bus = &vexpress_config_bus_type;
+	if (!vecdev->dev.parent)
+		vecdev->dev.parent = &vexpress_config_bus;
+
+	dev_set_name(&vecdev->dev, "%s." ADDR_FMT,
+			vecdev->name, ADDR_ARGS(vecdev));
+
+	return device_add(&vecdev->dev);
+}
+EXPORT_SYMBOL(vexpress_config_device_register);
+
+void vexpress_config_device_unregister(struct vexpress_config_device *vecdev)
+{
+	device_del(&vecdev->dev);
+	put_device(&vecdev->dev);
+}
+EXPORT_SYMBOL(vexpress_config_device_unregister);
+
+static int vexpress_config_driver_probe(struct device *dev)
+{
+	struct vexpress_config_device *vecdev = to_vexpress_config_device(dev);
+	struct vexpress_config_driver *vecdrv =
+			to_vexpress_config_driver(dev->driver);
+
+	return vecdrv->probe(vecdev);
+}
+
+static int vexpress_config_driver_remove(struct device *dev)
+{
+	struct vexpress_config_device *vecdev = to_vexpress_config_device(dev);
+	struct vexpress_config_driver *vecdrv =
+			to_vexpress_config_driver(dev->driver);
+
+	return vecdrv->remove(vecdev);
+}
+
+int vexpress_config_driver_register(struct vexpress_config_driver *vecdrv)
+{
+	pr_debug("Registering %sdriver '%s'\n",
+			vexpress_config_early ? "early " : "",
+			vecdrv->driver.name);
+
+	if (vexpress_config_early) {
+		list_add(&vecdrv->early, &vexpress_config_early_drivers);
+		vexpress_config_early_bind();
+
+		return 0;
+	}
+
+	vecdrv->driver.bus = &vexpress_config_bus_type;
+	if (vecdrv->probe)
+		vecdrv->driver.probe = vexpress_config_driver_probe;
+	if (vecdrv->remove)
+		vecdrv->driver.remove = vexpress_config_driver_remove;
+
+	return driver_register(&vecdrv->driver);
+}
+EXPORT_SYMBOL(vexpress_config_driver_register);
+
+void vexpress_config_driver_unregister(struct vexpress_config_driver *vecdrv)
+{
+	driver_unregister(&vecdrv->driver);
+}
+EXPORT_SYMBOL(vexpress_config_driver_unregister);
+
+
+struct vexpress_config_trans {
+	struct vexpress_config_bridge *bridge;
+	bool write;
+	unsigned func;
+	struct vexpress_config_address addr;
+	u32 *data;
+	struct completion completion;
+	int status;
+	struct list_head list;
+};
+
+static void vexpress_config_dump_trans(const char *what,
+		struct vexpress_config_trans *trans)
+{
+	pr_debug("%s %s transaction on " ADDR_FMT ", data 0x%x, status %d\n",
+			what, trans->write ? "write" : "read", ADDR_ARGS(trans),
+			trans->data ? *trans->data : 0, trans->status);
+}
+
+void vexpress_config_complete(struct vexpress_config_bridge *bridge,
+		int status)
+{
+	struct vexpress_config_trans *trans;
+	bool do_command = false;
+	unsigned long flags;
+
+	trans = list_first_entry(&bridge->transactions,
+			struct vexpress_config_trans, list);
+
+	trans->status = status;
+
+	vexpress_config_dump_trans("Completed", trans);
+
+	spin_lock_irqsave(&bridge->transactions_lock, flags);
+	list_del(&trans->list);
+	if (list_empty(&bridge->transactions))
+		bridge->transaction_pending = false;
+	else
+		do_command = true;
+	spin_unlock_irqrestore(&bridge->transactions_lock, flags);
+
+	complete(&trans->completion);
+
+	if (do_command) {
+		vexpress_config_dump_trans("Pending", trans);
+		bridge->info->command(true, trans->write, trans->func,
+				&trans->addr, trans->data);
+	}
+}
+
+static int vexpress_config_schedule(struct vexpress_config_trans *trans)
+{
+	struct vexpress_config_bridge *bridge = trans->bridge;
+	bool do_command = false;
+	unsigned long flags;
+
+	if (WARN_ON(!bridge))
+		return -ENOENT;
+	if (WARN_ON(trans->addr.site == VEXPRESS_SITE_MASTER))
+		return -EINVAL;
+
+	init_completion(&trans->completion);
+	trans->status = -EFAULT;
+
+	spin_lock_irqsave(&bridge->transactions_lock, flags);
+	list_add_tail(&trans->list, &bridge->transactions);
+	if (!bridge->transaction_pending)
+		bridge->transaction_pending = do_command = true;
+	spin_unlock_irqrestore(&bridge->transactions_lock, flags);
+
+	if (do_command) {
+		vexpress_config_dump_trans("New", trans);
+		return bridge->info->command(true, trans->write, trans->func,
+				&trans->addr, trans->data);
+	} else {
+		return 1;
+	}
+}
+
+int vexpress_config_wait(struct vexpress_config_trans *trans)
+{
+	wait_for_completion(&trans->completion);
+
+	return trans->status;
+}
+
+
+int vexpress_config_read(struct vexpress_config_device *vecdev, int offset,
+		u32 *data)
+{
+	int err;
+
+	if (vexpress_config_early) {
+		mutex_lock(&vexpress_config_early_mutex);
+		err = vecdev->bridge->info->command(false, false, vecdev->func,
+				&vecdev->addr, data);
+		mutex_unlock(&vexpress_config_early_mutex);
+	} else {
+		struct vexpress_config_trans trans = {
+			.bridge = vecdev->bridge,
+			.write = false,
+			.func = vecdev->func,
+			.addr = vecdev->addr,
+			.data = data,
+		};
+
+		trans.addr.device += offset;
+
+		err = vexpress_config_schedule(&trans);
+		if (!err)
+			err = vexpress_config_wait(&trans);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(vexpress_config_read);
+
+int vexpress_config_write(struct vexpress_config_device *vecdev, int offset,
+		u32 data)
+{
+	int err;
+
+	if (vexpress_config_early) {
+		mutex_lock(&vexpress_config_early_mutex);
+		err = vecdev->bridge->info->command(false, true, vecdev->func,
+				&vecdev->addr, &data);
+		mutex_unlock(&vexpress_config_early_mutex);
+	} else {
+		struct vexpress_config_trans trans = {
+			.bridge = vecdev->bridge,
+			.write = true,
+			.func = vecdev->func,
+			.addr = vecdev->addr,
+			.data = &data,
+		};
+
+		trans.addr.device += offset;
+
+		err = vexpress_config_schedule(&trans);
+		if (!err)
+			err = vexpress_config_wait(&trans);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(vexpress_config_write);
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
new file mode 100644
index 0000000..f1ed744
--- /dev/null
+++ b/include/linux/vexpress.h
@@ -0,0 +1,120 @@
+/*
+ * 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_CONFIG_FUNC_OSC	1
+#define VEXPRESS_CONFIG_FUNC_VOLT	2
+#define VEXPRESS_CONFIG_FUNC_AMP	3
+#define VEXPRESS_CONFIG_FUNC_TEMP	4
+#define VEXPRESS_CONFIG_FUNC_RESET	5
+#define VEXPRESS_CONFIG_FUNC_SCC	6
+#define VEXPRESS_CONFIG_FUNC_MUXFPGA	7
+#define VEXPRESS_CONFIG_FUNC_SHUTDOWN	8
+#define VEXPRESS_CONFIG_FUNC_REBOOT	9
+#define VEXPRESS_CONFIG_FUNC_DVIMODE	11
+#define VEXPRESS_CONFIG_FUNC_POWER	12
+#define VEXPRESS_CONFIG_FUNC_ENERGY	13
+
+#define VEXPRESS_SITE_MB		0
+#define VEXPRESS_SITE_DB1		1
+#define VEXPRESS_SITE_DB2		2
+#define VEXPRESS_SITE_MASTER		0xff
+#define VEXPRESS_SITES_NUM		3
+
+extern struct bus_type vexpress_config_bus_type;
+
+struct vexpress_config_address {
+	u8 site;
+	u8 position;
+	u8 dcc;
+	u16 device;
+};
+
+
+struct vexpress_config_bridge_info {
+	const char *name;
+	struct vexpress_config_address addr, mask;
+	int (*command)(bool async, bool write, unsigned func,
+			struct vexpress_config_address *addr, u32 *data);
+};
+
+struct vexpress_config_bridge *vexpress_config_bridge_register(
+		struct vexpress_config_bridge_info *info);
+void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge);
+
+void vexpress_config_set_master_site(u8 site);
+u8 vexpress_config_get_master_site(void);
+
+void vexpress_config_complete(struct vexpress_config_bridge *bridge,
+		int status);
+
+
+struct vexpress_config_device {
+	const char *name;
+	unsigned func;
+	struct vexpress_config_address addr;
+	struct device dev;
+#define VEXPRESS_CONFIG_DEVICE_PROBED_EARLY (1 << 0)
+	unsigned status;
+	/* private members */
+	struct vexpress_config_bridge *bridge;
+	struct list_head early;
+};
+
+#define to_vexpress_config_device(x) \
+		container_of((x), struct vexpress_config_device, dev)
+
+void vexpress_config_of_populate(void);
+int vexpress_config_device_register(struct vexpress_config_device *vecdev);
+void vexpress_config_device_unregister(struct vexpress_config_device *vecdev);
+
+
+struct vexpress_config_driver {
+	const unsigned *funcs; /* zero terminated array */
+	int (*probe)(struct vexpress_config_device *vecdev);
+	int (*remove)(struct vexpress_config_device *vecdev);
+	struct device_driver driver;
+	/* private members */
+	struct list_head early;
+};
+
+#define to_vexpress_config_driver(x) \
+		container_of((x), struct vexpress_config_driver, driver)
+
+int vexpress_config_driver_register(struct vexpress_config_driver *vecdrv);
+void vexpress_config_driver_unregister(struct vexpress_config_driver *vecdrv);
+
+static inline void *vexpress_config_get_drvdata(
+		const struct vexpress_config_device *vecdev)
+{
+	return dev_get_drvdata(&vecdev->dev);
+}
+
+static inline void vexpress_config_set_drvdata(
+		struct vexpress_config_device *vecdev, void *data)
+{
+	dev_set_drvdata(&vecdev->dev, data);
+}
+
+
+/* Both may sleep! */
+int vexpress_config_read(struct vexpress_config_device *vecdev, int offset,
+		u32 *data);
+int vexpress_config_write(struct vexpress_config_device *vecdev, int offset,
+		u32 data);
+
+#endif
-- 
1.7.9.5

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

* [PATCH 03/11] misc: Versatile Express reset driver
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
  2012-09-03 16:25 ` [PATCH 01/11] input: ambakmi: Add missing clk_[un]prepare() calls Pawel Moll
  2012-09-03 16:25 ` [PATCH 02/11] misc: Versatile Express config bus infrastructure Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-03 16:25 ` [PATCH 04/11] misc: Versatile Express display muxer driver Pawel Moll
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 UTC (permalink / raw)
  To: linux-arm-kernel

This is a simple vexpress config driver providing platform restart and
power off functions.

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>
---
 drivers/misc/vexpress/Makefile |    1 +
 drivers/misc/vexpress/reset.c  |  110 ++++++++++++++++++++++++++++++++++++++++
 include/linux/vexpress.h       |    4 ++
 3 files changed, 115 insertions(+)
 create mode 100644 drivers/misc/vexpress/reset.c

diff --git a/drivers/misc/vexpress/Makefile b/drivers/misc/vexpress/Makefile
index 5b1e8fc..af11749 100644
--- a/drivers/misc/vexpress/Makefile
+++ b/drivers/misc/vexpress/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += config_bus.o
+obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += reset.o
diff --git a/drivers/misc/vexpress/reset.c b/drivers/misc/vexpress/reset.c
new file mode 100644
index 0000000..1be7cba
--- /dev/null
+++ b/drivers/misc/vexpress/reset.c
@@ -0,0 +1,110 @@
+/*
+ * 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/stat.h>
+#include <linux/vexpress.h>
+
+static void vexpress_reset_do(struct vexpress_config_device *vecdev,
+		const char *what)
+{
+	int err = -ENOENT;
+
+	if (vecdev) {
+		unsigned long timeout;
+
+		err = vexpress_config_write(vecdev, 0, 0);
+
+		timeout = jiffies + HZ;
+		while (time_before(jiffies, timeout))
+			cpu_relax();
+	}
+
+	dev_emerg(&vecdev->dev, "Unable to %s (%d)\n", what, err);
+}
+
+static struct vexpress_config_device *vexpress_power_off_device;
+
+void vexpress_power_off(void)
+{
+	vexpress_reset_do(vexpress_power_off_device, "power off");
+}
+
+static struct vexpress_config_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 ==
+			to_vexpress_config_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 = to_vexpress_config_device(dev);
+
+	return err ? err : count;
+}
+
+DEVICE_ATTR(active, S_IRUGO | S_IWUSR, vexpress_reset_active_show,
+		vexpress_reset_active_store);
+
+
+static int vexpress_reset_probe(struct vexpress_config_device *vecdev)
+{
+	switch (vecdev->func) {
+	case VEXPRESS_CONFIG_FUNC_SHUTDOWN:
+		vexpress_power_off_device = vecdev;
+		break;
+	case VEXPRESS_CONFIG_FUNC_RESET:
+		if (!vexpress_restart_device)
+			vexpress_restart_device = vecdev;
+		device_create_file(&vecdev->dev, &dev_attr_active);
+		break;
+	case VEXPRESS_CONFIG_FUNC_REBOOT:
+		vexpress_restart_device = vecdev;
+		device_create_file(&vecdev->dev, &dev_attr_active);
+		break;
+	};
+
+	return 0;
+}
+
+static const unsigned vexpress_reset_funcs[] = {
+	VEXPRESS_CONFIG_FUNC_RESET,
+	VEXPRESS_CONFIG_FUNC_SHUTDOWN,
+	VEXPRESS_CONFIG_FUNC_REBOOT,
+	0,
+};
+
+static struct vexpress_config_driver vexpress_reset_driver = {
+	.funcs = vexpress_reset_funcs,
+	.probe = vexpress_reset_probe,
+	.driver.name = "vexpress-reset",
+};
+
+static int __init vexpress_reset_init(void)
+{
+	return vexpress_config_driver_register(&vexpress_reset_driver);
+}
+device_initcall(vexpress_reset_init);
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index f1ed744..7b02341 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -117,4 +117,8 @@ int vexpress_config_read(struct vexpress_config_device *vecdev, int offset,
 int vexpress_config_write(struct vexpress_config_device *vecdev, int offset,
 		u32 data);
 
+/* Reset control */
+void vexpress_power_off(void);
+void vexpress_restart(char str, const char *cmd);
+
 #endif
-- 
1.7.9.5

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

* [PATCH 04/11] misc: Versatile Express display muxer driver
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
                   ` (2 preceding siblings ...)
  2012-09-03 16:25 ` [PATCH 03/11] misc: Versatile Express reset driver Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-03 21:21   ` Arnd Bergmann
  2012-09-03 16:25 ` [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver Pawel Moll
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 UTC (permalink / raw)
  To: linux-arm-kernel

Versatile Express 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>
---
 Documentation/devicetree/bindings/arm/vexpress.txt |   19 ++
 drivers/misc/vexpress/Makefile                     |    1 +
 drivers/misc/vexpress/display.c                    |  197 ++++++++++++++++++++
 3 files changed, 217 insertions(+)
 create mode 100644 drivers/misc/vexpress/display.c

diff --git a/Documentation/devicetree/bindings/arm/vexpress.txt b/Documentation/devicetree/bindings/arm/vexpress.txt
index 8f69b6b..832a63a 100644
--- a/Documentation/devicetree/bindings/arm/vexpress.txt
+++ b/Documentation/devicetree/bindings/arm/vexpress.txt
@@ -232,6 +232,16 @@ device number.
   value, in two consecutive registers.
 
 
+Display controller nodes
+------------------------
+
+All nodes describing display controllers connected to the VE's
+multimedia bus (that is CLCD and HDLCD) should contain the
+"arm,vexpress,site" property (see the previous section for
+possible values) describing the controller's location in the
+system.
+
+
 Example of a VE tile description (simplified)
 ---------------------------------------------
 
@@ -279,6 +289,15 @@ Example of a VE tile description (simplified)
 		interrupt-map = <0 0 0 &gic 0 0 4>;
 	};
 
+	hdlcd at 2b000000 {
+		compatible = "arm,hdlcd";
+		reg = <0 0x2b000000 0 0x1000>;
+		interrupts = <0 85 4>;
+		arm,vexpress,site = <0xff>;
+		clocks = <&oscclk3>;
+		clock-names = "pxlclk";
+	};
+
 	dcc at 0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/drivers/misc/vexpress/Makefile b/drivers/misc/vexpress/Makefile
index af11749..d83d6b6 100644
--- a/drivers/misc/vexpress/Makefile
+++ b/drivers/misc/vexpress/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += config_bus.o
+obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += display.o
 obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += reset.o
diff --git a/drivers/misc/vexpress/display.c b/drivers/misc/vexpress/display.c
new file mode 100644
index 0000000..c439925
--- /dev/null
+++ b/drivers/misc/vexpress/display.c
@@ -0,0 +1,197 @@
+/*
+ * 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/fb.h>
+#include <linux/vexpress.h>
+
+
+static struct vexpress_config_device *vexpress_dvimode_device;
+
+static struct {
+	u32 xres, yres, mode;
+} vexpress_display_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_display_mode_set(struct fb_info *info, u32 xres, u32 yres)
+{
+	int err = -ENOENT;
+	int i;
+
+	if (!vexpress_dvimode_device)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_display_dvimodes); i++) {
+		if (vexpress_display_dvimodes[i].xres == xres &&
+				vexpress_display_dvimodes[i].yres == yres) {
+			dev_dbg(&vexpress_dvimode_device->dev,
+					"mode: %ux%u = %d\n", xres, yres,
+					vexpress_display_dvimodes[i].mode);
+			err = vexpress_config_write(vexpress_dvimode_device, 0,
+					vexpress_display_dvimodes[i].mode);
+			break;
+		}
+	}
+
+	if (err)
+		dev_warn(&vexpress_dvimode_device->dev,
+				"Failed to set %ux%u mode! (%d)\n",
+				xres, yres, err);
+}
+
+
+static struct vexpress_config_device *vexpress_muxfpga_device;
+static int vexpress_display_fb = -1;
+
+static int vexpress_display_fb_select(int fb)
+{
+	int err = 0;
+	struct fb_info *info = registered_fb[fb];
+	u32 site;
+	struct device *device;
+
+	if (!info || !lock_fb_info(info))
+		return -ENODEV;
+
+	device = info->device;
+
+	/* No DT means V2P-CA9, so assume master site if it's a CLCD */
+	if (!device->of_node) {
+		site = VEXPRESS_SITE_MASTER;
+		if (strcmp(device->driver->name, "clcd-pl11x") != 0)
+			err = -EINVAL;
+	} else {
+		err = of_property_read_u32(device->of_node,
+				"arm,vexpress,site", &site);
+		if (err)
+			dev_warn(&vexpress_muxfpga_device->dev,
+					"No site property found!");
+	}
+
+	if (!err) {
+		if (site == VEXPRESS_SITE_MASTER)
+			site = vexpress_config_get_master_site();
+
+		err = vexpress_config_write(vexpress_muxfpga_device, 0, site);
+		if (!err) {
+			dev_dbg(&vexpress_muxfpga_device->dev,
+					"Selected MUXFPGA input %d (fb%d)\n",
+					site, fb);
+			vexpress_display_fb = fb;
+			vexpress_display_mode_set(info, info->var.xres,
+					info->var.yres);
+		} else {
+			dev_warn(&vexpress_muxfpga_device->dev,
+					"Failed to select MUXFPGA input %d (fb%d)! (%d)\n",
+					site, fb, err);
+		}
+	}
+
+	unlock_fb_info(info);
+
+	return err;
+}
+
+static ssize_t vexpress_display_fb_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", vexpress_display_fb);
+}
+
+static ssize_t vexpress_display_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_display_fb_select(value);
+
+	return err ? err : count;
+}
+
+DEVICE_ATTR(fb, S_IRUGO | S_IWUSR, vexpress_display_fb_show,
+		vexpress_display_fb_store);
+
+
+static int vexpress_display_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_display_fb < 0)
+			vexpress_display_fb_select(info->node);
+		break;
+	case FB_EVENT_MODE_CHANGE:
+	case FB_EVENT_MODE_CHANGE_ALL:
+		if (info->node == vexpress_display_fb)
+			vexpress_display_mode_set(info, mode->xres, mode->yres);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block vexpress_display_fb_notifier = {
+	.notifier_call = vexpress_display_fb_event_notify,
+};
+
+
+static int vexpress_display_probe(struct vexpress_config_device *vecdev)
+{
+
+	switch (vecdev->func) {
+	case VEXPRESS_CONFIG_FUNC_MUXFPGA:
+		vexpress_muxfpga_device = vecdev;
+		break;
+	case VEXPRESS_CONFIG_FUNC_DVIMODE:
+		vexpress_dvimode_device = vecdev;
+		break;
+	};
+
+	if (vexpress_muxfpga_device && vexpress_dvimode_device) {
+		device_create_file(&vexpress_muxfpga_device->dev,
+				&dev_attr_fb);
+		fb_register_client(&vexpress_display_fb_notifier);
+		vexpress_display_fb_select(0);
+	}
+
+	return 0;
+}
+
+static const unsigned vexpress_display_funcs[] = {
+	VEXPRESS_CONFIG_FUNC_MUXFPGA,
+	VEXPRESS_CONFIG_FUNC_DVIMODE,
+	0,
+};
+
+static struct vexpress_config_driver vexpress_display_driver = {
+	.funcs = vexpress_display_funcs,
+	.probe = vexpress_display_probe,
+	.driver.name = "vexpress-display",
+};
+
+static int __init vexpress_display_init(void)
+{
+	return vexpress_config_driver_register(&vexpress_display_driver);
+}
+device_initcall(vexpress_display_init);
-- 
1.7.9.5

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

* [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
                   ` (3 preceding siblings ...)
  2012-09-03 16:25 ` [PATCH 04/11] misc: Versatile Express display muxer driver Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-10 19:14   ` Mike Turquette
  2012-09-03 16:25 ` [PATCH 06/11] clk: Common clocks implementation for Versatile Express Pawel Moll
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 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>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/include/asm/hardware/sp810.h    |    2 +
 drivers/clk/versatile/Makefile           |    1 +
 drivers/clk/versatile/clk-vexpress-osc.c |  154 ++++++++++++++++++++++++++++++
 include/linux/vexpress.h                 |    9 ++
 4 files changed, 166 insertions(+)
 create mode 100644 drivers/clk/versatile/clk-vexpress-osc.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/versatile/Makefile b/drivers/clk/versatile/Makefile
index c0a0f64..dd32e77 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_BUS) += 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..969e03f
--- /dev/null
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -0,0 +1,154 @@
+/*
+ * 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/slab.h>
+#include <linux/vexpress.h>
+
+struct vexpress_osc {
+	struct vexpress_config_device *vecdev;
+	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->vecdev, 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(rate < osc->rate_min))
+		rate = osc->rate_min;
+
+	if (WARN_ON(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->vecdev, 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,
+};
+
+
+static int vexpress_osc_probe(struct vexpress_config_device *vecdev)
+{
+	int err;
+	struct device_node *node = vecdev->dev.of_node;
+	struct vexpress_osc_info *info = vecdev->dev.platform_data;
+	struct clk_init_data init;
+	struct vexpress_osc *osc;
+	struct clk *clk;
+	const char * const *dev_ids = NULL;
+	u32 range[2];
+
+	if (vecdev->status & VEXPRESS_CONFIG_DEVICE_PROBED_EARLY)
+		return 0;
+
+	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+	if (!osc) {
+		err = -ENOMEM;
+		goto error;
+	}
+	osc->vecdev = vecdev;
+
+	if (info) {
+		init.name = info->clock_name;
+		osc->rate_min = info->rate_min;
+		osc->rate_max = info->rate_max;
+		dev_ids = info->dev_ids;
+	}
+
+	of_property_read_string(node, "clock-output-names", &init.name);
+
+	if (of_property_read_u32_array(node, "freq-range", range,
+			ARRAY_SIZE(range)) == 0) {
+		osc->rate_min = range[0];
+		osc->rate_max = range[1];
+	}
+
+	if (!init.name)
+		init.name = vecdev->name;
+	init.ops = &vexpress_osc_ops;
+	init.flags = CLK_IS_ROOT;
+	init.num_parents = 0;
+
+	osc->hw.init = &init;
+
+	dev_dbg(&vecdev->dev, "New osc %lu-%luHz\n",
+			osc->rate_min, osc->rate_max);
+
+	clk = clk_register(NULL, &osc->hw);
+	if (IS_ERR(clk)) {
+		err = PTR_ERR(clk);
+		goto error;
+	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+	while (dev_ids && *dev_ids) {
+		err = clk_register_clkdev(clk, NULL, *dev_ids);
+		if (err)
+			dev_warn(&vecdev->dev, "Failed to register clkdev lookup for '%s'!\n",
+					*dev_ids);
+		dev_ids++;
+	}
+
+	return 0;
+
+error:
+	kfree(osc);
+	return err;
+}
+
+static const unsigned vexpress_osc_funcs[] = {
+	VEXPRESS_CONFIG_FUNC_OSC,
+	0,
+};
+
+static struct vexpress_config_driver vexpress_osc_driver = {
+	.funcs = vexpress_osc_funcs,
+	.probe = vexpress_osc_probe,
+	.driver.name = "vexpress-osc",
+};
+
+int __init vexpress_osc_driver_register(void)
+{
+	return vexpress_config_driver_register(&vexpress_osc_driver);
+}
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index 7b02341..4768e6e 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -121,4 +121,13 @@ int vexpress_config_write(struct vexpress_config_device *vecdev, int offset,
 void vexpress_power_off(void);
 void vexpress_restart(char str, const char *cmd);
 
+/* Clock generators */
+struct vexpress_osc_info {
+	const char *clock_name;
+	unsigned long rate_min;
+	unsigned long rate_max;
+	const char * const *dev_ids;
+};
+int vexpress_osc_driver_register(void);
+
 #endif
-- 
1.7.9.5

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

* [PATCH 06/11] clk: Common clocks implementation for Versatile Express
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
                   ` (4 preceding siblings ...)
  2012-09-03 16:25 ` [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-03 21:24   ` Arnd Bergmann
  2012-09-10 20:10   ` Mike Turquette
  2012-09-03 16:25 ` [PATCH 07/11] regulators: Versatile Express regulator driver Pawel Moll
                   ` (4 subsequent siblings)
  10 siblings, 2 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 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
explicitely registers VE "osc" driver, to make the
clock generators availalable early.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/clk/Kconfig                  |    8 +-
 drivers/clk/versatile/Makefile       |    1 +
 drivers/clk/versatile/clk-vexpress.c |  174 ++++++++++++++++++++++++++++++++++
 include/linux/vexpress.h             |    4 +
 4 files changed, 184 insertions(+), 3 deletions(-)
 create mode 100644 drivers/clk/versatile/clk-vexpress.c

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 dd32e77..c2a5868 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_BUS) += 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..375e259
--- /dev/null
+++ b/drivers/clk/versatile/clk-vexpress.c
@@ -0,0 +1,174 @@
+/*
+ * 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:mmci", "mb:kmi0", "mb:kmi1"
+};
+
+static const char * const vexpress_osc_clk1_periphs[] = {
+	"mb:clcd",
+	NULL
+};
+
+static struct vexpress_osc_info vexpress_osc_clk1_info = {
+	.clock_name	= "v2m:osc_clk1",
+	.rate_min	= 23750000,
+	.rate_max	= 63500000,
+	.dev_ids	= vexpress_osc_clk1_periphs,
+};
+
+static struct vexpress_config_device vexpress_osc1_device = {
+	.name		= "mb:osc1",
+	.func		= VEXPRESS_CONFIG_FUNC_OSC,
+	.addr		= { VEXPRESS_SITE_MB, 0, 0, 1 },
+	.dev.platform_data = &vexpress_osc_clk1_info,
+};
+
+static const char * const vexpress_osc_clk2_periphs[] __initconst = {
+	"mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3"
+};
+
+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"));
+
+	vexpress_config_device_register(&vexpress_osc1_device);
+
+	clk = clk_register_fixed_rate(NULL, "v2m:osc_clk2", NULL,
+			CLK_IS_ROOT, 24000000);
+	for (i = 0; i < ARRAY_SIZE(vexpress_osc_clk2_periphs); i++)
+		WARN_ON(clk_register_clkdev(clk, NULL,
+				vexpress_osc_clk2_periphs[i]));
+
+	vexpress_osc_driver_register();
+}
+
+#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, },
+	{}
+};
+
+void __init vexpress_clk_of_init(void)
+{
+	struct device_node *node;
+	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 */
+	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))) {
+		struct clk *clk;
+		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"));
+
+	vexpress_osc_driver_register();
+}
+
+#endif
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index 4768e6e..18f03d1 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -130,4 +130,8 @@ struct vexpress_osc_info {
 };
 int vexpress_osc_driver_register(void);
 
+/* Clocks */
+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] 36+ messages in thread

* [PATCH 07/11] regulators: Versatile Express regulator driver
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
                   ` (5 preceding siblings ...)
  2012-09-03 16:25 ` [PATCH 06/11] clk: Common clocks implementation for Versatile Express Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-03 16:25 ` [PATCH 08/11] hwmon: Versatile Express hwmon driver Pawel Moll
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 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 |  144 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 152 insertions(+)
 create mode 100644 drivers/regulator/vexpress.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 4e932cc..7642773 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_BUS
+	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..c659b2e
--- /dev/null
+++ b/drivers/regulator/vexpress.c
@@ -0,0 +1,144 @@
+/*
+ * 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_device *vecdev;
+};
+
+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->vecdev, 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->vecdev, 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 vexpress_config_device *vecdev)
+{
+	struct vexpress_regulator *reg;
+	struct regulator_init_data *init_data;
+	struct regulator_config config = { };
+
+	reg = devm_kzalloc(&vecdev->dev, sizeof(*reg), GFP_KERNEL);
+	if (!reg)
+		return -ENOMEM;
+
+	reg->vecdev = vecdev;
+
+	reg->desc.name = dev_name(&vecdev->dev);
+	reg->desc.type = REGULATOR_VOLTAGE;
+	reg->desc.owner = THIS_MODULE;
+
+	init_data = of_get_regulator_init_data(&vecdev->dev,
+			vecdev->dev.of_node);
+	if (!init_data) {
+		dev_err(&vecdev->dev, "Failed to get regulator data!\n");
+		return -EINVAL;
+	}
+
+	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 = &vecdev->dev;
+	config.init_data = init_data;
+	config.driver_data = reg;
+	config.of_node = vecdev->dev.of_node;
+
+	reg->regdev = regulator_register(&reg->desc, &config);
+	if (IS_ERR(reg->regdev)) {
+		dev_err(&vecdev->dev, "Failed to register regulator! (%ld)\n",
+				PTR_ERR(reg->regdev));
+		return PTR_ERR(reg->regdev);
+	}
+
+	vexpress_config_set_drvdata(vecdev, reg);
+
+	return 0;
+}
+
+static int __devexit vexpress_regulator_remove(struct vexpress_config_device
+		*vecdev)
+{
+	struct vexpress_regulator *reg = vexpress_config_get_drvdata(vecdev);
+
+	regulator_unregister(reg->regdev);
+
+	return 0;
+}
+
+static const unsigned vexpress_regulator_funcs[] = {
+	VEXPRESS_CONFIG_FUNC_VOLT,
+	0,
+};
+
+static struct vexpress_config_driver vexpress_regulator_driver = {
+	.funcs = vexpress_regulator_funcs,
+	.probe = vexpress_regulator_probe,
+	.remove = __devexit_p(vexpress_regulator_remove),
+	.driver	= {
+		.name = DRVNAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init vexpress_regulator_init(void)
+{
+	return vexpress_config_driver_register(&vexpress_regulator_driver);
+}
+
+static void __exit vexpress_regulator_exit(void)
+{
+	vexpress_config_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] 36+ messages in thread

* [PATCH 08/11] hwmon: Versatile Express hwmon driver
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
                   ` (6 preceding siblings ...)
  2012-09-03 16:25 ` [PATCH 07/11] regulators: Versatile Express regulator driver Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-03 16:25 ` [PATCH 09/11] misc: Versatile Express system registers driver Pawel Moll
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 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 |  275 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 284 insertions(+)
 create mode 100644 drivers/hwmon/vexpress.c

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index b0a2e4c..3915794 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_BUS
+	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..7ada171
--- /dev/null
+++ b/drivers/hwmon/vexpress.c
@@ -0,0 +1,275 @@
+/*
+ * 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/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_device *vecdev;
+	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->vecdev, 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->vecdev, 0, &value_lo);
+	if (err)
+		return err;
+
+	err = vexpress_config_read(attrs->vecdev, 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) {
+		vexpress_hwmon_dev = NULL;
+		hwmon_device_unregister(vexpress_hwmon_dev);
+	}
+
+	WARN_ON(vexpress_hwmon_dev_refcount < 0);
+
+	spin_unlock(&vexpress_hwmon_dev_lock);
+}
+
+static struct {
+	const char *name;
+	u32 divisor;
+	atomic_t index;
+} vexpress_hwmon_func_list[] = {
+	[VEXPRESS_CONFIG_FUNC_VOLT] = { .name = "in", .divisor = 1000, },
+	[VEXPRESS_CONFIG_FUNC_AMP] = { .name = "curr", .divisor = 1000, },
+	[VEXPRESS_CONFIG_FUNC_TEMP] = { .name = "temp", .divisor = 1000, },
+	[VEXPRESS_CONFIG_FUNC_POWER] = { .name = "power", .divisor = 1, },
+	[VEXPRESS_CONFIG_FUNC_ENERGY] = { .name = "energy", .divisor = 1, },
+};
+
+static int vexpress_hwmon_probe(struct vexpress_config_device *vecdev)
+{
+	int err;
+	struct device *hwmon_dev;
+	unsigned func = vecdev->func;
+	struct vexpress_hwmon_attrs *attrs;
+	const char *attr_name;
+	int attr_index;
+
+	hwmon_dev = vexpress_hwmon_dev_get();
+	if (IS_ERR(hwmon_dev)) {
+		err = PTR_ERR(hwmon_dev);
+		goto error_hwmon_dev_get;
+	}
+
+	attrs = devm_kzalloc(&vecdev->dev, sizeof(*attrs), GFP_KERNEL);
+	if (!attrs) {
+		err = -ENOMEM;
+		goto error_kzalloc;
+	}
+	attrs->vecdev = vecdev;
+
+	err = sysfs_create_link(&vecdev->dev.kobj, &hwmon_dev->kobj, "hwmon");
+	if (err)
+		goto error_create_link;
+
+	attr_index = atomic_inc_return(&vexpress_hwmon_func_list[func].index);
+	attr_name = vexpress_hwmon_func_list[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 (func == VEXPRESS_CONFIG_FUNC_ENERGY)
+		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(vecdev->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 = vexpress_hwmon_func_list[func].divisor;
+
+	vexpress_config_set_drvdata(vecdev, attrs);
+
+	return 0;
+
+error_create_label:
+	device_remove_file(hwmon_dev, &attrs->input_attr);
+error_create_input:
+	sysfs_remove_link(&vecdev->dev.kobj, "hwmon");
+error_create_link:
+error_kzalloc:
+	vexpress_hwmon_dev_put();
+error_hwmon_dev_get:
+	return err;
+}
+
+static int __devexit vexpress_hwmon_remove(struct vexpress_config_device
+		*vecdev)
+{
+	struct vexpress_hwmon_attrs *attrs =
+			vexpress_config_get_drvdata(vecdev);
+
+	if (attrs->label)
+		device_remove_file(vexpress_hwmon_dev, &attrs->label_attr);
+	device_remove_file(vexpress_hwmon_dev, &attrs->input_attr);
+	atomic_dec(&vexpress_hwmon_func_list[vecdev->func].index);
+	sysfs_remove_link(&vecdev->dev.kobj, "hwmon");
+	vexpress_hwmon_dev_put();
+
+	return 0;
+}
+
+static const unsigned vexpress_hwmon_funcs[] = {
+#if !defined(CONFIG_REGULATOR_VEXPRESS)
+	VEXPRESS_CONFIG_FUNC_VOLT,
+#endif
+	VEXPRESS_CONFIG_FUNC_AMP,
+	VEXPRESS_CONFIG_FUNC_TEMP,
+	VEXPRESS_CONFIG_FUNC_POWER,
+	VEXPRESS_CONFIG_FUNC_ENERGY,
+	0,
+};
+
+static struct vexpress_config_driver vexpress_hwmon_driver = {
+	.funcs = vexpress_hwmon_funcs,
+	.probe = vexpress_hwmon_probe,
+	.remove = __devexit_p(vexpress_hwmon_remove),
+	.driver	= {
+		.name = DRVNAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init vexpress_hwmon_init(void)
+{
+	return vexpress_config_driver_register(&vexpress_hwmon_driver);
+}
+
+static void __exit vexpress_hwmon_exit(void)
+{
+	vexpress_config_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] 36+ messages in thread

* [PATCH 09/11] misc: Versatile Express system registers driver
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
                   ` (7 preceding siblings ...)
  2012-09-03 16:25 ` [PATCH 08/11] hwmon: Versatile Express hwmon driver Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-03 16:25 ` [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs Pawel Moll
  2012-09-03 16:25 ` [PATCH 11/11] ARM: vexpress: Start using new Versatile Express infrastructure Pawel Moll
  10 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 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>
---
 drivers/misc/vexpress/Makefile |    1 +
 drivers/misc/vexpress/sysreg.c |  423 ++++++++++++++++++++++++++++++++++++++++
 include/linux/vexpress.h       |   13 ++
 3 files changed, 437 insertions(+)
 create mode 100644 drivers/misc/vexpress/sysreg.c

diff --git a/drivers/misc/vexpress/Makefile b/drivers/misc/vexpress/Makefile
index d83d6b6..45af621 100644
--- a/drivers/misc/vexpress/Makefile
+++ b/drivers/misc/vexpress/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += config_bus.o
 obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += display.o
 obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += reset.o
+obj-$(CONFIG_VEXPRESS_CONFIG_BUS) += sysreg.o
diff --git a/drivers/misc/vexpress/sysreg.c b/drivers/misc/vexpress/sysreg.c
new file mode 100644
index 0000000..e43abc8
--- /dev/null
+++ b/drivers/misc/vexpress/sysreg.c
@@ -0,0 +1,423 @@
+/*
+ * 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/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 __init 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 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 int vexpress_sysreg_config_command(bool async, bool write,
+		unsigned func, struct vexpress_config_address *addr, u32 *data)
+{
+	int res = 0;
+	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 |= SYS_CFGCTRL_DCC(addr->dcc);
+	command |= SYS_CFGCTRL_FUNC(func);
+	command |= SYS_CFGCTRL_SITE(addr->site);
+	command |= SYS_CFGCTRL_POSITION(addr->position);
+	command |= SYS_CFGCTRL_DEVICE(addr->device);
+
+	if (write)
+		writel(*data, vexpress_sysreg_base + SYS_CFGDATA);
+	else
+		vexpress_sysreg_config_data = data;
+	writel(0, vexpress_sysreg_base + SYS_CFGSTAT);
+	writel(command, vexpress_sysreg_base + SYS_CFGCTRL);
+	mb();
+
+	if (async) {
+		vexpress_sysreg_config_tries = 100;
+		mod_timer(&vexpress_sysreg_config_timer,
+				jiffies + usecs_to_jiffies(100));
+	} else {
+		u32 val;
+
+		do {
+			cpu_relax();
+			val = readl(vexpress_sysreg_base + SYS_CFGSTAT);
+		} while (!val);
+
+		if (!write && (val & SYS_CFGSTAT_COMPLETE))
+			*data = readl(vexpress_sysreg_base + SYS_CFGDATA);
+
+		if (val & SYS_CFGSTAT_ERR)
+			res = -EINVAL;
+	}
+
+	return res;
+}
+
+struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = {
+	.name = "vexpress-sysreg",
+	.command = vexpress_sysreg_config_command,
+};
+
+static void vexpress_sysreg_config_complete(unsigned long data)
+{
+	int err = 0;
+	u32 val = readl(vexpress_sysreg_base + SYS_CFGSTAT);
+
+	if (val & SYS_CFGSTAT_ERR)
+		err = -EINVAL;
+	if (!vexpress_sysreg_config_tries--)
+		err = -ETIMEDOUT;
+
+	if (!err && !(val & 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);
+		vexpress_sysreg_config_data = NULL;
+	}
+
+	vexpress_config_complete(vexpress_sysreg_config_bridge, err);
+}
+
+
+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,
+};
+
+
+void __init vexpress_sysreg_early_init(void __iomem *base)
+{
+	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_config_set_master_site(vexpress_master_site);
+
+	vexpress_sysreg_config_bridge = vexpress_config_bridge_register(
+			&vexpress_sysreg_config_bridge_info);
+}
+
+void __init vexpress_sysreg_of_early_init(void)
+{
+	struct device_node *node = of_find_compatible_node(NULL, NULL,
+			"arm,vexpress-sysreg");
+
+	vexpress_sysreg_early_init(of_iomap(node, 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) {
+		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);
+}
+subsys_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 18f03d1..c44d2dc 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -134,4 +134,17 @@ int vexpress_osc_driver_register(void);
 void vexpress_clk_init(void __iomem *sp810_base);
 void vexpress_clk_of_init(void);
 
+/* System facilities */
+void vexpress_sysreg_early_init(void __iomem *base);
+void vexpress_sysreg_of_early_init(void);
+u32 vexpress_get_procid(int site);
+u32 vexpress_get_hbi(int site);
+void *vexpress_get_24mhz_clock_base(void);
+void __init vexpress_flags_set(u32 data);
+
+/* System pseudo-GPIOs */
+#define VEXPRESS_GPIO_MMC_CARDIN	0
+#define VEXPRESS_GPIO_MMC_WPROT		1
+#define VEXPRESS_GPIO_FLASH_WPn		2
+
 #endif
-- 
1.7.9.5

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

* [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
                   ` (8 preceding siblings ...)
  2012-09-03 16:25 ` [PATCH 09/11] misc: Versatile Express system registers driver Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  2012-09-04 12:58   ` Rob Herring
  2012-09-03 16:25 ` [PATCH 11/11] ARM: vexpress: Start using new Versatile Express infrastructure Pawel Moll
  10 siblings, 1 reply; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 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     |  136 ++++++++++++++++++++-
 arch/arm/boot/dts/vexpress-v2m.dtsi         |  136 ++++++++++++++++++++-
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts |  103 ++++++++++++++++
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts  |  169 +++++++++++++++++++++++++++
 arch/arm/boot/dts/vexpress-v2p-ca5s.dts     |   71 +++++++++++
 arch/arm/boot/dts/vexpress-v2p-ca9.dts      |  121 +++++++++++++++++++
 6 files changed, 732 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..9cc2a56 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -72,14 +72,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>, <&v2m_osc_clk0>;
+				clock-names = "refclk", "timclk", "apb_pclk";
+				#clock-cells = <1>;
+				clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
 			};
 
 			/* PCI-E I2C bus */
@@ -100,66 +106,92 @@
 				compatible = "arm,pl041", "arm,primecell";
 				reg = <0x040000 0x1000>;
 				interrupts = <11>;
+				clocks = <&v2m_osc_clk0>;
+				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_clk_24mhz>, <&v2m_osc_clk0>;
+				clock-names = "mclk", "apb_pclk";
 			};
 
 			kmi at 060000 {
 				compatible = "arm,pl050", "arm,primecell";
 				reg = <0x060000 0x1000>;
 				interrupts = <12>;
+				clocks = <&v2m_clk_24mhz>, <&v2m_osc_clk0>;
+				clock-names = "KMIREFCLK", "apb_pclk";
 			};
 
 			kmi at 070000 {
 				compatible = "arm,pl050", "arm,primecell";
 				reg = <0x070000 0x1000>;
 				interrupts = <13>;
+				clocks = <&v2m_clk_24mhz>, <&v2m_osc_clk0>;
+				clock-names = "KMIREFCLK", "apb_pclk";
 			};
 
 			v2m_serial0: uart at 090000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x090000 0x1000>;
 				interrupts = <5>;
+				clocks = <&v2m_osc_clk2>, <&v2m_osc_clk0>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial1: uart at 0a0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0a0000 0x1000>;
 				interrupts = <6>;
+				clocks = <&v2m_osc_clk2>, <&v2m_osc_clk0>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial2: uart at 0b0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0b0000 0x1000>;
 				interrupts = <7>;
+				clocks = <&v2m_osc_clk2>, <&v2m_osc_clk0>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial3: uart at 0c0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0c0000 0x1000>;
 				interrupts = <8>;
+				clocks = <&v2m_osc_clk2>, <&v2m_osc_clk0>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			wdt at 0f0000 {
 				compatible = "arm,sp805", "arm,primecell";
 				reg = <0x0f0000 0x1000>;
 				interrupts = <0>;
+				clocks = <&v2m_refclk32khz>, <&v2m_osc_clk0>;
+				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>, <&v2m_osc_clk0>;
+				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>, <&v2m_osc_clk0>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
 			};
 
 			/* DVI I2C bus */
@@ -185,6 +217,8 @@
 				compatible = "arm,pl031", "arm,primecell";
 				reg = <0x170000 0x1000>;
 				interrupts = <4>;
+				clocks = <&v2m_osc_clk0>;
+				clock-names = "apb_pclk";
 			};
 
 			compact-flash at 1a0000 {
@@ -198,6 +232,9 @@
 				compatible = "arm,pl111", "arm,primecell";
 				reg = <0x1f0000 0x1000>;
 				interrupts = <14>;
+				arm,vexpress,site = <0>;
+				clocks = <&v2m_osc_clk1>, <&v2m_osc_clk0>;
+				clock-names = "clcdclk", "apb_pclk";
 			};
 		};
 
@@ -208,5 +245,100 @@
 			regulator-max-microvolt = <3300000>;
 			regulator-always-on;
 		};
+
+		v2m_clk_24mhz: clk_24mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <24000000>;
+			clock-output-names = "v2m:clk_24mhz";
+		};
+
+		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 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#interrupt-cells = <0>;
+			arm,vexpress,site = <0>; /* Motherboard */
+
+			v2m_osc_clk0: osc at 0 {
+				/* MCC static memory clock */
+				compatible = "arm,vexpress-config,osc";
+				reg = <0>;
+				freq-range = <25000000 60000000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:osc_clk0";
+			};
+
+			v2m_osc_clk1: osc at 1 {
+				/* CLCD clock */
+				compatible = "arm,vexpress-config,osc";
+				reg = <1>;
+				freq-range = <23750000 63500000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:osc_clk1";
+			};
+
+			v2m_osc_clk2: osc at 2 {
+				/* IO FPGA peripheral clock */
+				compatible = "arm,vexpress-config,osc";
+				reg = <2>;
+				freq-range = <24000000 24000000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:osc_clk2";
+			};
+
+			volt at 0 {
+				/* Logic level voltage */
+				compatible = "arm,vexpress-config,volt";
+				reg = <0>;
+				regulator-name = "VIO";
+				regulator-always-on;
+			};
+
+			temp at 0 {
+				/* MCC internal operating temperature */
+				compatible = "arm,vexpress-config,temp";
+				reg = <0>;
+				label = "MCC";
+			};
+
+			reset at 0 {
+				compatible = "arm,vexpress-config,reset";
+				reg = <0>;
+			};
+
+			muxfpga at 0 {
+				compatible = "arm,vexpress-config,muxfpga";
+				reg = <0>;
+			};
+
+			shutdown at 0 {
+				compatible = "arm,vexpress-config,shutdown";
+				reg = <0>;
+			};
+
+			reboot at 0 {
+				compatible = "arm,vexpress-config,reboot";
+				reg = <0>;
+			};
+
+			dvimode at 0 {
+				compatible = "arm,vexpress-config,dvimode";
+				reg = <0>;
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
index dba53fd..03133a8 100644
--- a/arch/arm/boot/dts/vexpress-v2m.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -71,14 +71,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>, <&v2m_osc_clk0>;
+				clock-names = "refclk", "timclk", "apb_pclk";
+				#clock-cells = <1>;
+				clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
 			};
 
 			/* PCI-E I2C bus */
@@ -99,66 +105,92 @@
 				compatible = "arm,pl041", "arm,primecell";
 				reg = <0x04000 0x1000>;
 				interrupts = <11>;
+				clocks = <&v2m_osc_clk0>;
+				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_clk_24mhz>, <&v2m_osc_clk0>;
+				clock-names = "mclk", "apb_pclk";
 			};
 
 			kmi at 06000 {
 				compatible = "arm,pl050", "arm,primecell";
 				reg = <0x06000 0x1000>;
 				interrupts = <12>;
+				clocks = <&v2m_clk_24mhz>, <&v2m_osc_clk0>;
+				clock-names = "KMIREFCLK", "apb_pclk";
 			};
 
 			kmi at 07000 {
 				compatible = "arm,pl050", "arm,primecell";
 				reg = <0x07000 0x1000>;
 				interrupts = <13>;
+				clocks = <&v2m_clk_24mhz>, <&v2m_osc_clk0>;
+				clock-names = "KMIREFCLK", "apb_pclk";
 			};
 
 			v2m_serial0: uart at 09000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x09000 0x1000>;
 				interrupts = <5>;
+				clocks = <&v2m_osc_clk2>, <&v2m_osc_clk0>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial1: uart at 0a000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0a000 0x1000>;
 				interrupts = <6>;
+				clocks = <&v2m_osc_clk2>, <&v2m_osc_clk0>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial2: uart at 0b000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0b000 0x1000>;
 				interrupts = <7>;
+				clocks = <&v2m_osc_clk2>, <&v2m_osc_clk0>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			v2m_serial3: uart at 0c000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0c000 0x1000>;
 				interrupts = <8>;
+				clocks = <&v2m_osc_clk2>, <&v2m_osc_clk0>;
+				clock-names = "uartclk", "apb_pclk";
 			};
 
 			wdt at 0f000 {
 				compatible = "arm,sp805", "arm,primecell";
 				reg = <0x0f000 0x1000>;
 				interrupts = <0>;
+				clocks = <&v2m_refclk32khz>, <&v2m_osc_clk0>;
+				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>, <&v2m_osc_clk0>;
+				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>, <&v2m_osc_clk0>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
 			};
 
 			/* DVI I2C bus */
@@ -184,6 +216,8 @@
 				compatible = "arm,pl031", "arm,primecell";
 				reg = <0x17000 0x1000>;
 				interrupts = <4>;
+				clocks = <&v2m_osc_clk0>;
+				clock-names = "apb_pclk";
 			};
 
 			compact-flash at 1a000 {
@@ -197,6 +231,9 @@
 				compatible = "arm,pl111", "arm,primecell";
 				reg = <0x1f000 0x1000>;
 				interrupts = <14>;
+				arm,vexpress,site = <0>;
+				clocks = <&v2m_osc_clk1>, <&v2m_osc_clk0>;
+				clock-names = "clcdclk", "apb_pclk";
 			};
 		};
 
@@ -207,5 +244,100 @@
 			regulator-max-microvolt = <3300000>;
 			regulator-always-on;
 		};
+
+		v2m_clk_24mhz: clk_24mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <24000000>;
+			clock-output-names = "v2m:clk_24mhz";
+		};
+
+		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 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#interrupt-cells = <0>;
+			arm,vexpress,site = <0>; /* Motherboard */
+
+			v2m_osc_clk0: osc at 0 {
+				/* MCC static memory clock */
+				compatible = "arm,vexpress-config,osc";
+				reg = <0>;
+				freq-range = <25000000 60000000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:osc_clk0";
+			};
+
+			v2m_osc_clk1: osc at 1 {
+				/* CLCD clock */
+				compatible = "arm,vexpress-config,osc";
+				reg = <1>;
+				freq-range = <23750000 63500000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:osc_clk1";
+			};
+
+			v2m_osc_clk2: osc at 2 {
+				/* IO FPGA peripheral clock */
+				compatible = "arm,vexpress-config,osc";
+				reg = <2>;
+				freq-range = <24000000 24000000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:osc_clk2";
+			};
+
+			volt at 0 {
+				/* Logic level voltage */
+				compatible = "arm,vexpress-config,volt";
+				reg = <0>;
+				regulator-name = "VIO";
+				regulator-always-on;
+			};
+
+			temp at 0 {
+				/* MCC internal operating temperature */
+				compatible = "arm,vexpress-config,temp";
+				reg = <0>;
+				label = "MCC";
+			};
+
+			reset at 0 {
+				compatible = "arm,vexpress-config,reset";
+				reg = <0>;
+			};
+
+			muxfpga at 0 {
+				compatible = "arm,vexpress-config,muxfpga";
+				reg = <0>;
+			};
+
+			shutdown at 0 {
+				compatible = "arm,vexpress-config,shutdown";
+				reg = <0>;
+			};
+
+			reboot at 0 {
+				compatible = "arm,vexpress-config,reboot";
+				reg = <0>;
+			};
+
+			dvimode at 0 {
+				compatible = "arm,vexpress-config,dvimode";
+				reg = <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..9297dd6 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
@@ -54,6 +54,9 @@
 		compatible = "arm,hdlcd";
 		reg = <0 0x2b000000 0 0x1000>;
 		interrupts = <0 85 4>;
+		arm,vexpress,site = <0xff>;
+		clocks = <&oscclk5>;
+		clock-names = "pxlclk";
 	};
 
 	memory-controller at 2b0a0000 {
@@ -65,6 +68,7 @@
 		compatible = "arm,sp805", "arm,primecell";
 		reg = <0 0x2b060000 0 0x1000>;
 		interrupts = <98>;
+		status = "disabled";
 	};
 
 	gic: interrupt-controller at 2c001000 {
@@ -163,6 +167,105 @@
 				<0 0 41 &gic 0 41 4>,
 				<0 0 42 &gic 0 42 4>;
 	};
+
+	dcc at 0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#interrupt-cells = <0>;
+		arm,vexpress,site = <0xff>; /* Master site */
+
+		osc at 0 {
+			/* CPU PLL reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <0>;
+			freq-range = <50000000 60000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk0";
+		};
+
+		osc at 4 {
+			/* Multiplexed AXI master clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <4>;
+			freq-range = <20000000 40000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk4";
+		};
+
+		oscclk5: osc at 5 {
+			/* HDLCD PLL reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <5>;
+			freq-range = <23750000 165000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk5";
+		};
+
+		osc at 6 {
+			/* SMB clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <6>;
+			freq-range = <20000000 50000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk6";
+		};
+
+		osc at 7 {
+			/* SYS PLL reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <7>;
+			freq-range = <20000000 60000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk7";
+		};
+
+		osc at 8 {
+			/* DDR2 PLL reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <8>;
+			freq-range = <40000000 40000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk8";
+		};
+
+		volt at 0 {
+			/* CPU core voltage */
+			compatible = "arm,vexpress-config,volt";
+			reg = <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-config,amp";
+			reg = <0>;
+			label = "Cores";
+		};
+
+		temp at 0 {
+			/* DCC internal temperature */
+			compatible = "arm,vexpress-config,temp";
+			reg = <0>;
+			label = "DCC";
+		};
+
+		power at 0 {
+			/* Total power */
+			compatible = "arm,vexpress-config,power";
+			reg = <0>;
+			label = "Cores";
+		};
+
+		energy at 0 {
+			/* Total energy */
+			compatible = "arm,vexpress-config,energy";
+			reg = <0>;
+			label = "Cores";
+		};
+	};
 };
 
 /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 4890a81..a451478 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -74,12 +74,17 @@
 		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>;
+		arm,vexpress,site = <0xff>;
+		clocks = <&oscclk5>;
+		clock-names = "pxlclk";
 	};
 
 	memory-controller at 2b0a0000 {
@@ -183,6 +188,170 @@
 				<0 0 41 &gic 0 41 4>,
 				<0 0 42 &gic 0 42 4>;
 	};
+
+	oscclk6a: oscclk6a {
+		/* Reference 24MHz clock */
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+		clock-output-names = "oscclk6a";
+	};
+
+	dcc at 0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#interrupt-cells = <0>;
+		arm,vexpress,site = <0xff>; /* Master site */
+
+		osc at 0 {
+			/* A15 PLL 0 reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <0>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk0";
+		};
+
+		osc at 1 {
+			/* A15 PLL 1 reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <1>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk1";
+		};
+
+		osc at 2 {
+			/* A7 PLL 0 reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <2>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk2";
+		};
+
+		osc at 3 {
+			/* A7 PLL 1 reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <3>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk3";
+		};
+
+		osc at 4 {
+			/* External AXI master clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <4>;
+			freq-range = <20000000 40000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk4";
+		};
+
+		oscclk5: osc at 5 {
+			/* HDLCD PLL reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <5>;
+			freq-range = <23750000 165000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk5";
+		};
+
+		osc at 6 {
+			/* Static memory controller clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <6>;
+			freq-range = <20000000 40000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk6";
+		};
+
+		osc at 7 {
+			/* SYS PLL reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <7>;
+			freq-range = <17000000 50000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk7";
+		};
+
+		osc at 8 {
+			/* DDR2 PLL reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <8>;
+			freq-range = <20000000 50000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk8";
+		};
+
+		volt at 0 {
+			/* A15 CPU core voltage */
+			compatible = "arm,vexpress-config,volt";
+			reg = <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-config,volt";
+			reg = <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-config,amp";
+			reg = <0>;
+			label = "A15 Icore";
+		};
+
+		amp at 1 {
+			/* Total current for the three A7 cores */
+			compatible = "arm,vexpress-config,amp";
+			reg = <1>;
+			label = "A7 Icore";
+		};
+
+		temp at 0 {
+			/* DCC internal temperature */
+			compatible = "arm,vexpress-config,temp";
+			reg = <0>;
+			label = "DCC";
+		};
+
+		power at 0 {
+			/* Total power for the two A15 cores */
+			compatible = "arm,vexpress-config,power";
+			reg = <0>;
+			label = "A15 Pcore";
+		};
+		power at 1 {
+			/* Total power for the three A7 cores */
+			compatible = "arm,vexpress-config,power";
+			reg = <1>;
+			label = "A7 Pcore";
+		};
+
+		energy at 0 {
+			/* Total energy for the two A15 cores */
+			compatible = "arm,vexpress-config,energy";
+			reg = <0>;
+			label = "A15 Jcore";
+		};
+
+		energy at 2 {
+			/* Total energy for the three A7 cores */
+			compatible = "arm,vexpress-config,energy";
+			reg = <2>;
+			label = "A7 Jcore";
+		};
+	};
 };
 
 /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 18917a0..84b9a19 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
@@ -56,6 +56,9 @@
 		compatible = "arm,hdlcd";
 		reg = <0x2a110000 0x1000>;
 		interrupts = <0 85 4>;
+		arm,vexpress,site = <0xff>;
+		clocks = <&oscclk3>;
+		clock-names = "pxlclk";
 	};
 
 	memory-controller at 2a150000 {
@@ -162,6 +165,74 @@
 				<0 0 41 &gic 0 41 4>,
 				<0 0 42 &gic 0 42 4>;
 	};
+
+	dcc at 0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#interrupt-cells = <0>;
+		arm,vexpress,site = <0xff>; /* Master site */
+
+		osc at 0 {
+			/* CPU and internal AXI reference clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <0>;
+			freq-range = <50000000 100000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk0";
+		};
+
+		osc at 1 {
+			/* Multiplexed AXI master clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <1>;
+			freq-range = <5000000 50000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk1";
+		};
+
+		osc at 2 {
+			/* DDR2 */
+			compatible = "arm,vexpress-config,osc";
+			reg = <2>;
+			freq-range = <80000000 120000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk2";
+		};
+
+		oscclk3: osc at 3 {
+			/* HDLCD */
+			compatible = "arm,vexpress-config,osc";
+			reg = <3>;
+			freq-range = <23750000 165000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk3";
+		};
+
+		osc at 4 {
+			/* Test chip gate configuration */
+			compatible = "arm,vexpress-config,osc";
+			reg = <4>;
+			freq-range = <80000000 80000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk4";
+		};
+
+		osc at 5 {
+			/* SMB clock */
+			compatible = "arm,vexpress-config,osc";
+			reg = <5>;
+			freq-range = <25000000 60000000>;
+			#clock-cells = <1>;
+			clock-output-names = "oscclk5";
+		};
+
+		temp at 0 {
+			/* DCC internal operating temperature */
+			compatible = "arm,vexpress-config,temp";
+			reg = <0>;
+			label = "DCC";
+		};
+	};
 };
 
 /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 3f0c736..5a421f7 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -70,11 +70,16 @@
 		compatible = "arm,pl111", "arm,primecell";
 		reg = <0x10020000 0x1000>;
 		interrupts = <0 44 4>;
+		arm,vexpress,site = <0xff>;
+		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 {
@@ -192,6 +203,116 @@
 				<0 0 41 &gic 0 41 4>,
 				<0 0 42 &gic 0 42 4>;
 	};
+
+	dcc at 0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#interrupt-cells = <0>;
+		arm,vexpress,site = <0xff>; /* Master site */
+
+		osc at 0 {
+			/* ACLK clock to the AXI master port on the test chip */
+			compatible = "arm,vexpress-config,osc";
+			reg = <0>;
+			freq-range = <30000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "extsaxiclk";
+		};
+
+		oscclk1: osc at 1 {
+			/* Reference clock for the CLCD */
+			compatible = "arm,vexpress-config,osc";
+			reg = <1>;
+			freq-range = <10000000 80000000>;
+			#clock-cells = <0>;
+			clock-output-names = "clcdclk";
+		};
+
+		oscclk2: osc at 2 {
+			/* Reference clock for the test chip internal PLLs */
+			compatible = "arm,vexpress-config,osc";
+			reg = <2>;
+			freq-range = <33000000 100000000>;
+			#clock-cells = <0>;
+			clock-output-names = "tcrefclk";
+		};
+
+		volt at 0 {
+			/* Test Chip internal logic voltage */
+			compatible = "arm,vexpress-config,volt";
+			reg = <0>;
+			regulator-name = "VD10";
+			regulator-always-on;
+		};
+
+		volt at 1 {
+			/* PL310, L2 cache, RAM cell supply (not PL310 logic) */
+			compatible = "arm,vexpress-config,volt";
+			reg = <1>;
+			regulator-name = "VD10_S2";
+			regulator-always-on;
+		};
+
+		volt at 2 {
+			/* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */
+			compatible = "arm,vexpress-config,volt";
+			reg = <2>;
+			regulator-name = "VD10_S3";
+			regulator-always-on;
+		};
+
+		volt at 3 {
+			/* DDR2 SDRAM and Test Chip DDR2 I/O supply */
+			compatible = "arm,vexpress-config,volt";
+			reg = <3>;
+			regulator-name = "VCC1V8";
+			regulator-always-on;
+		};
+
+		volt at 4 {
+			/* DDR2 SDRAM VTT termination voltage */
+			compatible = "arm,vexpress-config,volt";
+			reg = <4>;
+			regulator-name = "DDR2VTT";
+			regulator-always-on;
+		};
+
+		volt at 5 {
+			/* Local board supply for miscellaneous logic external to the Test Chip */
+			compatible = "arm,vexpress-config,volt";
+			reg = <5>;
+			regulator-name = "VCC3V3";
+			regulator-always-on;
+		};
+
+		amp at 0 {
+			/* PL310, L2 cache, RAM cell supply (not PL310 logic) */
+			compatible = "arm,vexpress-config,amp";
+			reg = <0>;
+			label = "VD10_S2";
+		};
+
+		amp at 1 {
+			/* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */
+			compatible = "arm,vexpress-config,amp";
+			reg = <1>;
+			label = "VD10_S3";
+		};
+
+		power at 0 {
+			/* PL310, L2 cache, RAM cell supply (not PL310 logic) */
+			compatible = "arm,vexpress-config,power";
+			reg = <0>;
+			label = "PVD10_S2";
+		};
+
+		power at 1 {
+			/* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */
+			compatible = "arm,vexpress-config,power";
+			reg = <1>;
+			label = "PVD10_S3";
+		};
+	};
 };
 
 /include/ "vexpress-v2m.dtsi"
-- 
1.7.9.5

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

* [PATCH 11/11] ARM: vexpress: Start using new Versatile Express infrastructure
  2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
                   ` (9 preceding siblings ...)
  2012-09-03 16:25 ` [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs Pawel Moll
@ 2012-09-03 16:25 ` Pawel Moll
  10 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-03 16:25 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/ct-ca9x4.c                 |   37 +--
 arch/arm/mach-vexpress/include/mach/motherboard.h |   81 ------
 arch/arm/mach-vexpress/platsmp.c                  |    3 +-
 arch/arm/mach-vexpress/v2m.c                      |  321 +++++----------------
 6 files changed, 86 insertions(+), 366 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e88fe09..45a5d88 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_BUS
 	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/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 61c4924..3e93058 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,12 +98,23 @@ static struct amba_device *ct_ca9x4_amba_devs[] __initdata = {
 	&gpio_device,
 };
 
+static const char * const ct_ca9x4_osc1_periphs[] = {
+	"ct:clcd",
+	NULL
+};
 
-static struct v2m_osc ct_osc1 = {
-	.osc = 1,
+static struct vexpress_osc_info ct_ca9x4_osc1_info = {
+	.clock_name = "clcdclk",
 	.rate_min = 10000000,
 	.rate_max = 80000000,
-	.rate_default = 23750000,
+	.dev_ids = ct_ca9x4_osc1_periphs,
+};
+
+static struct vexpress_config_device ct_ca9x4_osc1_device = {
+	.name		= "ct:osc1",
+	.func		= VEXPRESS_CONFIG_FUNC_OSC,
+	.addr		= { VEXPRESS_SITE_MASTER, 0, 0, 1 },
+	.dev.platform_data = &ct_ca9x4_osc1_info,
 };
 
 static struct resource pmu_resources[] = {
@@ -152,7 +150,6 @@ static struct platform_device pmu_device = {
 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,9 +161,7 @@ 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");
+	vexpress_config_device_register(&ct_ca9x4_osc1_device);
 
 	for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++)
 		amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource);
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..e4535db 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,49 @@ 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 vexpress_config_device v2m_muxfpga_device = {
+	.name		= "mb:muxfpga",
+	.func		= VEXPRESS_CONFIG_FUNC_MUXFPGA,
+	.addr		= { VEXPRESS_SITE_MB, 0, 0, 0 },
+};
+
+static struct vexpress_config_device v2m_shutdown_device = {
+	.name		= "mb:shutdown",
+	.func		= VEXPRESS_CONFIG_FUNC_SHUTDOWN,
+	.addr		= { VEXPRESS_SITE_MB, 0, 0, 0 },
+};
+
+static struct vexpress_config_device v2m_reboot_device = {
+	.name		= "mb:reboot",
+	.func		= VEXPRESS_CONFIG_FUNC_REBOOT,
+	.addr		= { VEXPRESS_SITE_MB, 0, 0, 0 },
+};
+
+static struct vexpress_config_device v2m_dvimode_device = {
+	.name		= "mb:dvimode",
+	.func		= VEXPRESS_CONFIG_FUNC_DVIMODE,
+	.addr		= { VEXPRESS_SITE_MB, 0, 0, 0 },
 };
 
 static AMBA_APB_DEVICE(aaci,  "mb:aaci",  0, V2M_AACI, IRQ_V2M_AACI, NULL);
@@ -323,123 +271,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 +285,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 +302,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 +318,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 +335,12 @@ static void __init v2m_init(void)
 	regulator_register_fixed(0, v2m_eth_supplies,
 			ARRAY_SIZE(v2m_eth_supplies));
 
+	vexpress_config_device_register(&v2m_muxfpga_device);
+	vexpress_config_device_register(&v2m_shutdown_device);
+	vexpress_config_device_register(&v2m_reboot_device);
+	vexpress_config_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 +351,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 +364,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 +407,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 "
@@ -608,6 +429,7 @@ static  struct of_device_id vexpress_irq_match[] __initdata = {
 static void __init v2m_dt_init_irq(void)
 {
 	of_irq_init(vexpress_irq_match);
+	vexpress_config_of_populate();
 }
 
 static void __init v2m_dt_timer_init(void)
@@ -616,47 +438,34 @@ static void __init v2m_dt_timer_init(void)
 	const char *path;
 	int err;
 
-	node = of_find_compatible_node(NULL, NULL, "arm,sp810");
-	v2m_sysctl_init(of_iomap(node, 0));
-
-	v2m_clk_init();
+	vexpress_clk_of_init();
 
 	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();
 
 	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 +478,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
-- 
1.7.9.5

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

* [PATCH 02/11] misc: Versatile Express config bus infrastructure
  2012-09-03 16:25 ` [PATCH 02/11] misc: Versatile Express config bus infrastructure Pawel Moll
@ 2012-09-03 21:17   ` Arnd Bergmann
  2012-09-04 11:53     ` Pawel Moll
  0 siblings, 1 reply; 36+ messages in thread
From: Arnd Bergmann @ 2012-09-03 21:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 03 September 2012, Pawel Moll wrote:
> +	dcc at 0 {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		#interrupt-cells = <0>;
> +		arm,vexpress,site = <0xff>; /* Master site */
> +
> +		osc at 0 {
> +			compatible = "arm,vexpress-config,osc";
> +			reg = <0>;
> +			freq-range = <50000000 100000000>;
> +			#clock-cells = <1>;
> +			clock-output-names = "oscclk0";
> +		};
> +	};
>  };

The #interrupt-cells property seems misplaced here.

> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -517,4 +517,5 @@ source "drivers/misc/lis3lv02d/Kconfig"
>  source "drivers/misc/carma/Kconfig"
>  source "drivers/misc/altera-stapl/Kconfig"
>  source "drivers/misc/mei/Kconfig"
> +source "drivers/misc/vexpress/Kconfig"
>  endmenu
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index b88df7a..49964fd 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-y				+= vexpress/

This does not look like something that should go to drivers/misc (well,
basically nothing ever does). How about drivers/mfd or drivers/bus instead?

> +#define ADDR_FMT "%u.%x:%x:%x:%x"
> +
> +#define ADDR_ARGS(_ptr) \
> +		_ptr->func, _ptr->addr.site, _ptr->addr.position, \
> +		_ptr->addr.dcc, _ptr->addr.device

Can't you use dev_printk() to print the device name in the normal format?

> +#define ADDR_TO_U64(addr) \
> +		(((u64)(addr).site << 32) | ((addr).position << 24) | \
> +		((addr).dcc << 16) | (addr).device)
> +
> +static bool vexpress_config_early = true;
> +static DEFINE_MUTEX(vexpress_config_early_mutex);
> +static LIST_HEAD(vexpress_config_early_drivers);
> +static LIST_HEAD(vexpress_config_early_devices);

What is the reason for needing early devices that you have to keep in a list
like this? If it's only for setup purposes, it's probably easier to
have a platform hook that probes the hardware you want to initialize at boot
time and only start using the device method at device init time.

> +static int vexpress_config_match(struct device *dev, struct device_driver *drv)
> +{
> +	struct vexpress_config_device *vecdev = to_vexpress_config_device(dev);
> +	struct vexpress_config_driver *vecdrv = to_vexpress_config_driver(drv);
> +
> +	if (vecdrv->funcs) {
> +		const unsigned *func = vecdrv->funcs;
> +
> +		while (*func) {
> +			if (*func == vecdev->func)
> +				return 1;
> +			func++;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static struct device vexpress_config_bus = {
> +	.init_name = "vexpress-config",
> +};

No static devices in new code please. Just put it into the device tree.


> +struct bus_type vexpress_config_bus_type = {
> +	.name = "vexpress-config",
> +	.match = vexpress_config_match,
> +};

What is the reason for having a separate bus_type here?
Is this a discoverable bus? If it is, why do you need a
device tree binding for the child devices?


> +#define VEXPRESS_COMPATIBLE_TO_FUNC(_compatible, _func) \
> +	{ \
> +		.compatible = "arm,vexpress-config," _compatible, \
> +		.data = (void *)VEXPRESS_CONFIG_FUNC_##_func \
> +	}
> +
> +static struct of_device_id vexpress_config_devices_matches[] = {
> +	VEXPRESS_COMPATIBLE_TO_FUNC("osc", OSC),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("volt", VOLT),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("amp", AMP),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("temp", TEMP),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("reset", RESET),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("scc", SCC),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("muxfpga", MUXFPGA),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("shutdown", SHUTDOWN),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("reboot", REBOOT),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("dvimode", DVIMODE),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("power", POWER),
> +	VEXPRESS_COMPATIBLE_TO_FUNC("energy", ENERGY),
> +	{},
> +};

What is the purpose of this lookup? Can't you make the child devices get
probed by the compatible value?

> +static void vexpress_config_of_device_add(struct device_node *node)
> +{
> +	int err;
> +	struct vexpress_config_device *vecdev;
> +	const struct of_device_id *match;
> +	u32 value;
> +
> +	if (!of_device_is_available(node))
> +		return;
> +
> +	vecdev = kzalloc(sizeof(*vecdev), GFP_KERNEL);
> +	if (WARN_ON(!vecdev))
> +		return;
> +
> +	vecdev->dev.of_node = of_node_get(node);
> +
> +	vecdev->name = node->name;
> +
> +	match = of_match_node(vexpress_config_devices_matches, node);
> +	vecdev->func = (unsigned)match->data;
> +
> +	err = of_property_read_u32(node->parent, "arm,vexpress,site", &value);
> +	if (!err)
> +		vecdev->addr.site = value;
> +
> +	err = of_property_read_u32(node->parent, "arm,vexpress,position",
> +			&value);
> +	if (!err)
> +		vecdev->addr.position = value;
> +
> +	err = of_property_read_u32(node->parent, "arm,vexpress,dcc", &value);
> +	if (!err)
> +		vecdev->addr.dcc = value;
> +
> +	err = of_property_read_u32(node, "reg", &value);
> +	if (!err) {
> +		vecdev->addr.device = value;
> +	} else {
> +		pr_err("Invalid reg property in '%s'! (%d)\n",
> +				node->full_name, err);
> +		kfree(vecdev);
> +		return;
> +	}
> +
> +	err = vexpress_config_device_register(vecdev);
> +	if (err) {
> +		pr_err("Failed to add OF device '%s'! (%d)\n",
> +				node->full_name, err);
> +		kfree(vecdev);
> +		return;
> +	}
> +}
> +
> +void vexpress_config_of_populate(void)
> +{
> +	struct device_node *node;
> +
> +	for_each_matching_node(node, vexpress_config_devices_matches)
> +		vexpress_config_of_device_add(node);
> +}

This is unusual. Why do you only add the matching devices rather than
all of them? Doing it your way also means O(n^2) rather than O(n)
traversal through the list of children.

> +int vexpress_config_device_register(struct vexpress_config_device *vecdev)
> +{
> +	pr_debug("Registering %sdevice '%s." ADDR_FMT "'\n",
> +			vexpress_config_early ? "early " : "",
> +			vecdev->name, ADDR_ARGS(vecdev));
> +
> +	if (vecdev->addr.site == VEXPRESS_SITE_MASTER)
> +		vecdev->addr.site = vexpress_config_get_master_site();
> +
> +	if (!vecdev->bridge) {
> +		spin_lock(&vexpress_config_bridges_lock);
> +		vexpress_config_bridge_find(&vecdev->dev, NULL);
> +		spin_unlock(&vexpress_config_bridges_lock);
> +	}
> +
> +	if (vexpress_config_early) {
> +		list_add(&vecdev->early, &vexpress_config_early_devices);
> +		vexpress_config_early_bind();
> +
> +		return 0;
> +	}
> +
> +	device_initialize(&vecdev->dev);
> +	vecdev->dev.bus = &vexpress_config_bus_type;
> +	if (!vecdev->dev.parent)
> +		vecdev->dev.parent = &vexpress_config_bus;
> +
> +	dev_set_name(&vecdev->dev, "%s." ADDR_FMT,
> +			vecdev->name, ADDR_ARGS(vecdev));
> +
> +	return device_add(&vecdev->dev);
> +}
> +EXPORT_SYMBOL(vexpress_config_device_register);

Why is this exported to non-GPL drivers? It looks like the only caller should be
in this file.

	Arnd

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

* [PATCH 04/11] misc: Versatile Express display muxer driver
  2012-09-03 16:25 ` [PATCH 04/11] misc: Versatile Express display muxer driver Pawel Moll
@ 2012-09-03 21:21   ` Arnd Bergmann
  2012-09-04 11:53     ` Pawel Moll
  0 siblings, 1 reply; 36+ messages in thread
From: Arnd Bergmann @ 2012-09-03 21:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 03 September 2012, Pawel Moll wrote:
> Signed-off-by: Pawel Moll <pawel.moll@arm.com>
> ---
>  Documentation/devicetree/bindings/arm/vexpress.txt |   19 ++
>  drivers/misc/vexpress/Makefile                     |    1 +
>  drivers/misc/vexpress/display.c                    |  197 ++++++++++++++++++++
>  3 files changed, 217 insertions(+)
>  create mode 100644 drivers/misc/vexpress/display.c
> 

Shouldn't this go into the drivers/video directory?

	Arnd

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

* [PATCH 06/11] clk: Common clocks implementation for Versatile Express
  2012-09-03 16:25 ` [PATCH 06/11] clk: Common clocks implementation for Versatile Express Pawel Moll
@ 2012-09-03 21:24   ` Arnd Bergmann
  2012-09-04 11:53     ` Pawel Moll
  2012-09-10 20:10   ` Mike Turquette
  1 sibling, 1 reply; 36+ messages in thread
From: Arnd Bergmann @ 2012-09-03 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 03 September 2012, Pawel Moll wrote:
> +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));
> +

Isn't it time to just remove the non-DT parts of vexpress? That would
also simplify this driver.

	Arnd

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

* [PATCH 02/11] misc: Versatile Express config bus infrastructure
  2012-09-03 21:17   ` Arnd Bergmann
@ 2012-09-04 11:53     ` Pawel Moll
  2012-09-04 12:45       ` Arnd Bergmann
  0 siblings, 1 reply; 36+ messages in thread
From: Pawel Moll @ 2012-09-04 11:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

Thanks for your time!

On Mon, 2012-09-03 at 22:17 +0100, Arnd Bergmann wrote:
> On Monday 03 September 2012, Pawel Moll wrote:
> > +	dcc at 0 {
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +		#interrupt-cells = <0>;
> > +		arm,vexpress,site = <0xff>; /* Master site */
> > +
> > +		osc at 0 {
> > +			compatible = "arm,vexpress-config,osc";
> > +			reg = <0>;
> > +			freq-range = <50000000 100000000>;
> > +			#clock-cells = <1>;
> > +			clock-output-names = "oscclk0";
> > +		};
> > +	};
> >  };
> 
> The #interrupt-cells property seems misplaced here.

Right. I'm not sure what I meant here, probably a cut-and-paste error.

> > --- a/drivers/misc/Kconfig
> > +++ b/drivers/misc/Kconfig
> > @@ -517,4 +517,5 @@ source "drivers/misc/lis3lv02d/Kconfig"
> >  source "drivers/misc/carma/Kconfig"
> >  source "drivers/misc/altera-stapl/Kconfig"
> >  source "drivers/misc/mei/Kconfig"
> > +source "drivers/misc/vexpress/Kconfig"
> >  endmenu
> > diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> > index b88df7a..49964fd 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-y				+= vexpress/
> 
> This does not look like something that should go to drivers/misc (well,
> basically nothing ever does). How about drivers/mfd or drivers/bus instead?

I don't see drivers/bus in 3.6-rc4? If there will be such thing, I guess
I can move config_bus.c to drivers/bus/vexpress-config.c, display.c to
drivers/video/vexpress-display.c (see my other answer), sysreg.c to
drivers/mfd/vexpress-sysreg.c (it is a multifunction device indeed, not
argument about that), but reset.c seems to me should stay as
drivers/misc/vexpress-reset.c - it's hardly a mfd...

> > +#define ADDR_FMT "%u.%x:%x:%x:%x"
> > +
> > +#define ADDR_ARGS(_ptr) \
> > +		_ptr->func, _ptr->addr.site, _ptr->addr.position, \
> > +		_ptr->addr.dcc, _ptr->addr.device
> 
> Can't you use dev_printk() to print the device name in the normal format?

Well, in some places it's used before dev_set_name(), but I guess I can
get rid of those printk-s (they are debug messages anyway).

> > +#define ADDR_TO_U64(addr) \
> > +		(((u64)(addr).site << 32) | ((addr).position << 24) | \
> > +		((addr).dcc << 16) | (addr).device)
> > +
> > +static bool vexpress_config_early = true;
> > +static DEFINE_MUTEX(vexpress_config_early_mutex);
> > +static LIST_HEAD(vexpress_config_early_drivers);
> > +static LIST_HEAD(vexpress_config_early_devices);
> 
> What is the reason for needing early devices that you have to keep in a list
> like this? If it's only for setup purposes, it's probably easier to
> have a platform hook that probes the hardware you want to initialize at boot
> time and only start using the device method at device init time.

Funnily enough the first version didn't have anything "early related"...
Till I actually defined the real clock dependency in the tree :-(

So it's all about clocks, that must be available really early. The
particular problem I faced was the amba_probe() trying to enable
apb_pclk of each device and failing...

Now, during the clock registration the device model is not initialized
yet, so I can't do normal devices registration. I've stolen some ideas
from the early platform bus code...

> > +static int vexpress_config_match(struct device *dev, struct device_driver *drv)
> > +{
> > +	struct vexpress_config_device *vecdev = to_vexpress_config_device(dev);
> > +	struct vexpress_config_driver *vecdrv = to_vexpress_config_driver(drv);
> > +
> > +	if (vecdrv->funcs) {
> > +		const unsigned *func = vecdrv->funcs;
> > +
> > +		while (*func) {
> > +			if (*func == vecdev->func)
> > +				return 1;
> > +			func++;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static struct device vexpress_config_bus = {
> > +	.init_name = "vexpress-config",
> > +};
> 
> No static devices in new code please. Just put it into the device tree.

Hm. This is just a dummy device serving as a default parent, similarly
to:

struct device platform_bus = {
        .init_name      = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);

Without that I can see two options:

1. Create some kind of a device (platform?) for the dcc/mcc node and use
it as a parent.
2. Scan the device tree "downwards" searching for a node that has a
device already associated with it (but this may not work at the early
stage).

> > +struct bus_type vexpress_config_bus_type = {
> > +	.name = "vexpress-config",
> > +	.match = vexpress_config_match,
> > +};
> 
> What is the reason for having a separate bus_type here?
> Is this a discoverable bus? If it is, why do you need a
> device tree binding for the child devices?

It is not a discoverable bus, but the devices are very different from
the "normal" platform devices and have specific read/write interface, so
it seemed to me that a separate bus would make sense. And I didn't want
to reinvent the wheel with my own "device/driver model".

> > +#define VEXPRESS_COMPATIBLE_TO_FUNC(_compatible, _func) \
> > +	{ \
> > +		.compatible = "arm,vexpress-config," _compatible, \
> > +		.data = (void *)VEXPRESS_CONFIG_FUNC_##_func \
> > +	}
> > +
> > +static struct of_device_id vexpress_config_devices_matches[] = {
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("osc", OSC),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("volt", VOLT),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("amp", AMP),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("temp", TEMP),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("reset", RESET),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("scc", SCC),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("muxfpga", MUXFPGA),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("shutdown", SHUTDOWN),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("reboot", REBOOT),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("dvimode", DVIMODE),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("power", POWER),
> > +	VEXPRESS_COMPATIBLE_TO_FUNC("energy", ENERGY),
> > +	{},
> > +};
> 
> What is the purpose of this lookup? Can't you make the child devices get
> probed by the compatible value?

Ok, there are two reasons for this table existence:

1. vexpress_config_of_populate() below - I need a comprehensive list of
compatible values to be able to search the tree and create respective
devices.

2. Non-DT static devices - I need something to be able to match a driver
with a device, and the "functions list" seemed appropriate.

> > +static void vexpress_config_of_device_add(struct device_node *node)
> > +{
> > +	int err;
> > +	struct vexpress_config_device *vecdev;
> > +	const struct of_device_id *match;
> > +	u32 value;
> > +
> > +	if (!of_device_is_available(node))
> > +		return;
> > +
> > +	vecdev = kzalloc(sizeof(*vecdev), GFP_KERNEL);
> > +	if (WARN_ON(!vecdev))
> > +		return;
> > +
> > +	vecdev->dev.of_node = of_node_get(node);
> > +
> > +	vecdev->name = node->name;
> > +
> > +	match = of_match_node(vexpress_config_devices_matches, node);
> > +	vecdev->func = (unsigned)match->data;
> > +
> > +	err = of_property_read_u32(node->parent, "arm,vexpress,site", &value);
> > +	if (!err)
> > +		vecdev->addr.site = value;
> > +
> > +	err = of_property_read_u32(node->parent, "arm,vexpress,position",
> > +			&value);
> > +	if (!err)
> > +		vecdev->addr.position = value;
> > +
> > +	err = of_property_read_u32(node->parent, "arm,vexpress,dcc", &value);
> > +	if (!err)
> > +		vecdev->addr.dcc = value;
> > +
> > +	err = of_property_read_u32(node, "reg", &value);
> > +	if (!err) {
> > +		vecdev->addr.device = value;
> > +	} else {
> > +		pr_err("Invalid reg property in '%s'! (%d)\n",
> > +				node->full_name, err);
> > +		kfree(vecdev);
> > +		return;
> > +	}
> > +
> > +	err = vexpress_config_device_register(vecdev);
> > +	if (err) {
> > +		pr_err("Failed to add OF device '%s'! (%d)\n",
> > +				node->full_name, err);
> > +		kfree(vecdev);
> > +		return;
> > +	}
> > +}
> > +
> > +void vexpress_config_of_populate(void)
> > +{
> > +	struct device_node *node;
> > +
> > +	for_each_matching_node(node, vexpress_config_devices_matches)
> > +		vexpress_config_of_device_add(node);
> > +}
> 
> This is unusual. Why do you only add the matching devices rather than
> all of them? Doing it your way also means O(n^2) rather than O(n)
> traversal through the list of children.

Em, I'm not sure what do you mean... The idea is shamelessly stolen from
of_irq_init() and of_clk_init()...

> > +int vexpress_config_device_register(struct vexpress_config_device *vecdev)
> > +{
> > +	pr_debug("Registering %sdevice '%s." ADDR_FMT "'\n",
> > +			vexpress_config_early ? "early " : "",
> > +			vecdev->name, ADDR_ARGS(vecdev));
> > +
> > +	if (vecdev->addr.site == VEXPRESS_SITE_MASTER)
> > +		vecdev->addr.site = vexpress_config_get_master_site();
> > +
> > +	if (!vecdev->bridge) {
> > +		spin_lock(&vexpress_config_bridges_lock);
> > +		vexpress_config_bridge_find(&vecdev->dev, NULL);
> > +		spin_unlock(&vexpress_config_bridges_lock);
> > +	}
> > +
> > +	if (vexpress_config_early) {
> > +		list_add(&vecdev->early, &vexpress_config_early_devices);
> > +		vexpress_config_early_bind();
> > +
> > +		return 0;
> > +	}
> > +
> > +	device_initialize(&vecdev->dev);
> > +	vecdev->dev.bus = &vexpress_config_bus_type;
> > +	if (!vecdev->dev.parent)
> > +		vecdev->dev.parent = &vexpress_config_bus;
> > +
> > +	dev_set_name(&vecdev->dev, "%s." ADDR_FMT,
> > +			vecdev->name, ADDR_ARGS(vecdev));
> > +
> > +	return device_add(&vecdev->dev);
> > +}
> > +EXPORT_SYMBOL(vexpress_config_device_register);
> 
> Why is this exported to non-GPL drivers? It looks like the only caller should be
> in this file.

Hm. There's no hidden agenda behind the non-GPL export, if that's what
you are afraid of ;-) Now, why it is exported at all? Because
platform_device_register is, I suppose (you can tell that I was looking
at the platform bus code ;-). The non-DT platform code is using it, so
it can't be static, but I wouldn't really expect any module to use it.
So I can make it EXPORT_SYMBOL_GPL or drop it, no problem.

Cheers!

Pawel

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

* [PATCH 06/11] clk: Common clocks implementation for Versatile Express
  2012-09-03 21:24   ` Arnd Bergmann
@ 2012-09-04 11:53     ` Pawel Moll
  2012-09-04 12:43       ` Linus Walleij
  0 siblings, 1 reply; 36+ messages in thread
From: Pawel Moll @ 2012-09-04 11:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 2012-09-03 at 22:24 +0100, Arnd Bergmann wrote:
> On Monday 03 September 2012, Pawel Moll wrote:
> > +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));
> > +
> 
> Isn't it time to just remove the non-DT parts of vexpress? That would
> also simplify this driver.

It would simplify not only this driver, but the whole infrastructure
indeed. But we are still "CLCD driver away" from the full features
replacement. Ryan Harkin is working on this, but it doesn't look like he
was going to make it in time for 3.7. A second after this happens I'll
post a "big kill" patch removing all non-DT stuff - I'm really looking
forward to it :-)

Pawel

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

* [PATCH 04/11] misc: Versatile Express display muxer driver
  2012-09-03 21:21   ` Arnd Bergmann
@ 2012-09-04 11:53     ` Pawel Moll
  0 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-04 11:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 2012-09-03 at 22:21 +0100, Arnd Bergmann wrote:
> On Monday 03 September 2012, Pawel Moll wrote:
> > Signed-off-by: Pawel Moll <pawel.moll@arm.com>
> > ---
> >  Documentation/devicetree/bindings/arm/vexpress.txt |   19 ++
> >  drivers/misc/vexpress/Makefile                     |    1 +
> >  drivers/misc/vexpress/display.c                    |  197 ++++++++++++++++++++
> >  3 files changed, 217 insertions(+)
> >  create mode 100644 drivers/misc/vexpress/display.c
> > 
> 
> Shouldn't this go into the drivers/video directory?

I sort of assumed that drivers/video contain frame buffer drivers only,
but now I see there are some "control modules" there as well. Fine with
me.

Cheers!

Pawel

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

* [PATCH 06/11] clk: Common clocks implementation for Versatile Express
  2012-09-04 11:53     ` Pawel Moll
@ 2012-09-04 12:43       ` Linus Walleij
  2012-09-04 17:12         ` Ryan Harkin
  0 siblings, 1 reply; 36+ messages in thread
From: Linus Walleij @ 2012-09-04 12:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 4, 2012 at 1:53 PM, Pawel Moll <pawel.moll@arm.com> wrote:

> But we are still "CLCD driver away" from the full features
> replacement. Ryan Harkin is working on this,

Will be useful for Integrator, Versatile, RealView, and some non-ARM
SoCs too I think, so very interesting!

Yours,
Linus Walleij

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

* [PATCH 02/11] misc: Versatile Express config bus infrastructure
  2012-09-04 11:53     ` Pawel Moll
@ 2012-09-04 12:45       ` Arnd Bergmann
  2012-09-04 16:41         ` Pawel Moll
  0 siblings, 1 reply; 36+ messages in thread
From: Arnd Bergmann @ 2012-09-04 12:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 04 September 2012, Pawel Moll wrote:
> On Mon, 2012-09-03 at 22:17 +0100, Arnd Bergmann wrote:
> > On Monday 03 September 2012, Pawel Moll wrote:

> > > --- a/drivers/misc/Kconfig
> > > +++ b/drivers/misc/Kconfig
> > > @@ -517,4 +517,5 @@ source "drivers/misc/lis3lv02d/Kconfig"
> > >  source "drivers/misc/carma/Kconfig"
> > >  source "drivers/misc/altera-stapl/Kconfig"
> > >  source "drivers/misc/mei/Kconfig"
> > > +source "drivers/misc/vexpress/Kconfig"
> > >  endmenu
> > > diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> > > index b88df7a..49964fd 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-y				+= vexpress/
> > 
> > This does not look like something that should go to drivers/misc (well,
> > basically nothing ever does). How about drivers/mfd or drivers/bus instead?
> 
> I don't see drivers/bus in 3.6-rc4? If there will be such thing, I guess
> I can move config_bus.c to drivers/bus/vexpress-config.c, display.c to
> drivers/video/vexpress-display.c (see my other answer), sysreg.c to
> drivers/mfd/vexpress-sysreg.c (it is a multifunction device indeed, not
> argument about that), but reset.c seems to me should stay as
> drivers/misc/vexpress-reset.c - it's hardly a mfd...

We're adding drivers/bus in v3.7, I already have another bus driver in
the arm-soc tree.

The reset code can probably just go to arch/arm/mach-vexpress though,
we do the same for the reset code on all other platforms.

> > > +#define ADDR_TO_U64(addr) \
> > > +		(((u64)(addr).site << 32) | ((addr).position << 24) | \
> > > +		((addr).dcc << 16) | (addr).device)
> > > +
> > > +static bool vexpress_config_early = true;
> > > +static DEFINE_MUTEX(vexpress_config_early_mutex);
> > > +static LIST_HEAD(vexpress_config_early_drivers);
> > > +static LIST_HEAD(vexpress_config_early_devices);
> > 
> > What is the reason for needing early devices that you have to keep in a list
> > like this? If it's only for setup purposes, it's probably easier to
> > have a platform hook that probes the hardware you want to initialize at boot
> > time and only start using the device method at device init time.
> 
> Funnily enough the first version didn't have anything "early related"...
> Till I actually defined the real clock dependency in the tree :-(
> 
> So it's all about clocks, that must be available really early. The
> particular problem I faced was the amba_probe() trying to enable
> apb_pclk of each device and failing...
> 
> Now, during the clock registration the device model is not initialized
> yet, so I can't do normal devices registration. I've stolen some ideas
> from the early platform bus code...

Maybe you can change amba_probe() to provide a -EPROBE_DEFER return
code to the caller when the clock is not yet there, it should then
just come back later.

> > > +static int vexpress_config_match(struct device *dev, struct device_driver *drv)
> > > +{
> > > +	struct vexpress_config_device *vecdev = to_vexpress_config_device(dev);
> > > +	struct vexpress_config_driver *vecdrv = to_vexpress_config_driver(drv);
> > > +
> > > +	if (vecdrv->funcs) {
> > > +		const unsigned *func = vecdrv->funcs;
> > > +
> > > +		while (*func) {
> > > +			if (*func == vecdev->func)
> > > +				return 1;
> > > +			func++;
> > > +		}
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static struct device vexpress_config_bus = {
> > > +	.init_name = "vexpress-config",
> > > +};
> > 
> > No static devices in new code please. Just put it into the device tree.
> 
> Hm. This is just a dummy device serving as a default parent, similarly
> to:
> 
> struct device platform_bus = {
>         .init_name      = "platform",
> };
> EXPORT_SYMBOL_GPL(platform_bus);

The platform bus is very special, you should try not to use it as an
example for other buses ;-)
 
> Without that I can see two options:
> 
> 1. Create some kind of a device (platform?) for the dcc/mcc node and use
> it as a parent.
> 2. Scan the device tree "downwards" searching for a node that has a
> device already associated with it (but this may not work at the early
> stage).

I think 1. would be logical. The device should actually be created
by the device tree probe anyway.

> > > +struct bus_type vexpress_config_bus_type = {
> > > +	.name = "vexpress-config",
> > > +	.match = vexpress_config_match,
> > > +};
> > 
> > What is the reason for having a separate bus_type here?
> > Is this a discoverable bus? If it is, why do you need a
> > device tree binding for the child devices?
> 
> It is not a discoverable bus, but the devices are very different from
> the "normal" platform devices and have specific read/write interface, so
> it seemed to me that a separate bus would make sense. And I didn't want
> to reinvent the wheel with my own "device/driver model".

Not introducing a different way to do devices is good, but I don't think
that using something else than platform devices buys you much. If it's not
discoverable, this driver does not look all that different from an MFD
(which is based on platform devices).

A new bus type is typically used only for cases where you have multiple
different bus drivers and multiple different device drivers, and want a
bus layer to proxy between them. In your case, it seems you have only
a single device driver providing devices, and it just gets them by looking
at the device tree, so there is no real need for a bus_type.

> > > +#define VEXPRESS_COMPATIBLE_TO_FUNC(_compatible, _func) \
> > > +	{ \
> > > +		.compatible = "arm,vexpress-config," _compatible, \
> > > +		.data = (void *)VEXPRESS_CONFIG_FUNC_##_func \
> > > +	}
> > > +
> > > +static struct of_device_id vexpress_config_devices_matches[] = {
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("osc", OSC),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("volt", VOLT),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("amp", AMP),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("temp", TEMP),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("reset", RESET),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("scc", SCC),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("muxfpga", MUXFPGA),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("shutdown", SHUTDOWN),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("reboot", REBOOT),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("dvimode", DVIMODE),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("power", POWER),
> > > +	VEXPRESS_COMPATIBLE_TO_FUNC("energy", ENERGY),
> > > +	{},
> > > +};
> > 
> > What is the purpose of this lookup? Can't you make the child devices get
> > probed by the compatible value?
> 
> Ok, there are two reasons for this table existence:
> 
> 1. vexpress_config_of_populate() below - I need a comprehensive list of
> compatible values to be able to search the tree and create respective
> devices.

I don't see why you need this list. Just call of_platform_populate or a
copy of that. It does not require the compatible values of the devices,
just the one for the parent.

> 2. Non-DT static devices - I need something to be able to match a driver
> with a device, and the "functions list" seemed appropriate.

How important is this case really, given that the driver has never been
supported and that the non-DT case is going away soon?

> > > +static void vexpress_config_of_device_add(struct device_node *node)
> > > +{
> > > +	int err;
> > > +	struct vexpress_config_device *vecdev;
> > > +	const struct of_device_id *match;
> > > +	u32 value;
> > > +
> > > +	if (!of_device_is_available(node))
> > > +		return;
> > > +
> > > +	vecdev = kzalloc(sizeof(*vecdev), GFP_KERNEL);
> > > +	if (WARN_ON(!vecdev))
> > > +		return;
> > > +
> > > +	vecdev->dev.of_node = of_node_get(node);
> > > +
> > > +	vecdev->name = node->name;
> > > +
> > > +	match = of_match_node(vexpress_config_devices_matches, node);
> > > +	vecdev->func = (unsigned)match->data;
> > > +
> > > +	err = of_property_read_u32(node->parent, "arm,vexpress,site", &value);
> > > +	if (!err)
> > > +		vecdev->addr.site = value;
> > > +
> > > +	err = of_property_read_u32(node->parent, "arm,vexpress,position",
> > > +			&value);
> > > +	if (!err)
> > > +		vecdev->addr.position = value;
> > > +
> > > +	err = of_property_read_u32(node->parent, "arm,vexpress,dcc", &value);
> > > +	if (!err)
> > > +		vecdev->addr.dcc = value;
> > > +
> > > +	err = of_property_read_u32(node, "reg", &value);
> > > +	if (!err) {
> > > +		vecdev->addr.device = value;
> > > +	} else {
> > > +		pr_err("Invalid reg property in '%s'! (%d)\n",
> > > +				node->full_name, err);
> > > +		kfree(vecdev);
> > > +		return;
> > > +	}
> > > +
> > > +	err = vexpress_config_device_register(vecdev);
> > > +	if (err) {
> > > +		pr_err("Failed to add OF device '%s'! (%d)\n",
> > > +				node->full_name, err);
> > > +		kfree(vecdev);
> > > +		return;
> > > +	}
> > > +}
> > > +
> > > +void vexpress_config_of_populate(void)
> > > +{
> > > +	struct device_node *node;
> > > +
> > > +	for_each_matching_node(node, vexpress_config_devices_matches)
> > > +		vexpress_config_of_device_add(node);
> > > +}
> > 
> > This is unusual. Why do you only add the matching devices rather than
> > all of them? Doing it your way also means O(n^2) rather than O(n)
> > traversal through the list of children.
> 
> Em, I'm not sure what do you mean... The idea is shamelessly stolen from
> of_irq_init() and of_clk_init()...

But those are not buses, they are infrastructure that is used across
buses. The regular way to do this is to register a driver for your
parent node and then just iterate over the children, in the way that
we do for e.g. i2c or spi buses.

> > > +EXPORT_SYMBOL(vexpress_config_device_register);
> > 
> > Why is this exported to non-GPL drivers? It looks like the only caller should be
> > in this file.
> 
> Hm. There's no hidden agenda behind the non-GPL export, if that's what
> you are afraid of ;-) Now, why it is exported at all? Because
> platform_device_register is, I suppose (you can tell that I was looking
> at the platform bus code ;-). The non-DT platform code is using it, so
> it can't be static, but I wouldn't really expect any module to use it.
> So I can make it EXPORT_SYMBOL_GPL or drop it, no problem.

Ok. I'd say just drop it then.

	Arnd

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

* [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs
  2012-09-03 16:25 ` [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs Pawel Moll
@ 2012-09-04 12:58   ` Rob Herring
  2012-09-04 13:05     ` Pawel Moll
  0 siblings, 1 reply; 36+ messages in thread
From: Rob Herring @ 2012-09-04 12:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/03/2012 11:25 AM, Pawel Moll wrote:
> 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     |  136 ++++++++++++++++++++-
>  arch/arm/boot/dts/vexpress-v2m.dtsi         |  136 ++++++++++++++++++++-
>  arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts |  103 ++++++++++++++++
>  arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts  |  169 +++++++++++++++++++++++++++
>  arch/arm/boot/dts/vexpress-v2p-ca5s.dts     |   71 +++++++++++
>  arch/arm/boot/dts/vexpress-v2p-ca9.dts      |  121 +++++++++++++++++++
>  6 files changed, 732 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..9cc2a56 100644
> --- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
> +++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
> @@ -72,14 +72,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>, <&v2m_osc_clk0>;
> +				clock-names = "refclk", "timclk", "apb_pclk";

See Documentation/devicetree/bindings/arm/primecell.txt

apb_pclk should be first in the list.

Rob

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

* [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs
  2012-09-04 12:58   ` Rob Herring
@ 2012-09-04 13:05     ` Pawel Moll
  2012-09-04 14:31       ` Rob Herring
  0 siblings, 1 reply; 36+ messages in thread
From: Pawel Moll @ 2012-09-04 13:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-04 at 13:58 +0100, Rob Herring wrote:
> > -			sysctl at 020000 {
> > +			v2m_sysctl: sysctl at 020000 {
> >  				compatible = "arm,sp810", "arm,primecell";
> >  				reg = <0x020000 0x1000>;
> > +				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_osc_clk0>;
> > +				clock-names = "refclk", "timclk", "apb_pclk";
> 
> See Documentation/devicetree/bindings/arm/primecell.txt
> 
> apb_pclk should be first in the list.

Hm. Why, if you don't mind me asking? The amba_get_enable_pclk()
explicitly asks for "apb_pclk" id:

struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk");

Now, let's have a look at MMCI:

                        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_clk_24mhz>, <&v2m_osc_clk0>;
+                               clock-names = "mclk", "apb_pclk";
                        };

and mmci_probe() does:

        host->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(host->clk)) {
                ret = PTR_ERR(host->clk);
                host->clk = NULL;
                goto host_free;
        }       

Now, if I put "apb_pclk" first, before "mclk", the driver will get the
wrong clock.

Pawe?

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

* [PATCH 01/11] input: ambakmi: Add missing clk_[un]prepare() calls
  2012-09-03 16:25 ` [PATCH 01/11] input: ambakmi: Add missing clk_[un]prepare() calls Pawel Moll
@ 2012-09-04 13:37   ` Thomas Petazzoni
  2012-09-04 13:45     ` Pawel Moll
  0 siblings, 1 reply; 36+ messages in thread
From: Thomas Petazzoni @ 2012-09-04 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

Pawel,

Le Mon,  3 Sep 2012 17:25:21 +0100,
Pawel Moll <pawel.moll@arm.com> a ?crit :

> Clocks must be prepared before enabling and unprepared
> after disabling. Without that clk_enable() fails with
> warning.
> 
> Signed-off-by: Pawel Moll <pawel.moll@arm.com>
> ---
>  drivers/input/serio/ambakmi.c |    9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
> index 2ffd110..ab2d25b 100644
> --- a/drivers/input/serio/ambakmi.c
> +++ b/drivers/input/serio/ambakmi.c
> @@ -72,10 +72,14 @@ static int amba_kmi_open(struct serio *io)
>  	unsigned int divisor;
>  	int ret;
>  
> -	ret = clk_enable(kmi->clk);
> +	ret = clk_prepare(kmi->clk);
>  	if (ret)
>  		goto out;
>  
> +	ret = clk_enable(kmi->clk);
> +	if (ret)
> +		goto clk_unprepare;
> +

What about using clk_prepare_enable() here?

>  	free_irq(kmi->irq, kmi);
>  	clk_disable(kmi->clk);
> +	clk_unprepare(kmi->clk);

And clk_disable_unprepare() here?

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* [PATCH 01/11] input: ambakmi: Add missing clk_[un]prepare() calls
  2012-09-04 13:37   ` Thomas Petazzoni
@ 2012-09-04 13:45     ` Pawel Moll
  0 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-04 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-04 at 14:37 +0100, Thomas Petazzoni wrote:
> > --- a/drivers/input/serio/ambakmi.c
> > +++ b/drivers/input/serio/ambakmi.c
> > @@ -72,10 +72,14 @@ static int amba_kmi_open(struct serio *io)
> >  	unsigned int divisor;
> >  	int ret;
> >  
> > -	ret = clk_enable(kmi->clk);
> > +	ret = clk_prepare(kmi->clk);
> >  	if (ret)
> >  		goto out;
> >  
> > +	ret = clk_enable(kmi->clk);
> > +	if (ret)
> > +		goto clk_unprepare;
> > +
> 
> What about using clk_prepare_enable() here?
> 
> >  	free_irq(kmi->irq, kmi);
> >  	clk_disable(kmi->clk);
> > +	clk_unprepare(kmi->clk);
> 
> And clk_disable_unprepare() here?

Sure thing, thanks for pointing that out!

Pawel

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

* [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs
  2012-09-04 13:05     ` Pawel Moll
@ 2012-09-04 14:31       ` Rob Herring
  2012-09-04 15:37         ` Pawel Moll
  0 siblings, 1 reply; 36+ messages in thread
From: Rob Herring @ 2012-09-04 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/04/2012 08:05 AM, Pawel Moll wrote:
> On Tue, 2012-09-04 at 13:58 +0100, Rob Herring wrote:
>>> -			sysctl at 020000 {
>>> +			v2m_sysctl: sysctl at 020000 {
>>>  				compatible = "arm,sp810", "arm,primecell";
>>>  				reg = <0x020000 0x1000>;
>>> +				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_osc_clk0>;
>>> +				clock-names = "refclk", "timclk", "apb_pclk";
>>
>> See Documentation/devicetree/bindings/arm/primecell.txt
>>
>> apb_pclk should be first in the list.
> 
> Hm. Why, if you don't mind me asking? The amba_get_enable_pclk()
> explicitly asks for "apb_pclk" id:

So apb_pclk is always in the same position in the list and I had to
define something. Clock names are supposed to be optional, so we have to
be able to identify which clock is the bus clock without the name.

> struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk");
> 
> Now, let's have a look at MMCI:
> 
>                         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_clk_24mhz>, <&v2m_osc_clk0>;
> +                               clock-names = "mclk", "apb_pclk";
>                         };
> 
> and mmci_probe() does:
> 
>         host->clk = clk_get(&dev->dev, NULL);
>         if (IS_ERR(host->clk)) {
>                 ret = PTR_ERR(host->clk);
>                 host->clk = NULL;
>                 goto host_free;
>         }       
> 
> Now, if I put "apb_pclk" first, before "mclk", the driver will get the
> wrong clock.

You're getting lucky with how clk_get is implemented. The driver should
be more specific with which clock it wants if there is more than 1.
Perhaps we need a clk_get_by_index() function?

Rob

> 
> Pawe?
> 
> 

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

* [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs
  2012-09-04 14:31       ` Rob Herring
@ 2012-09-04 15:37         ` Pawel Moll
  2012-09-04 17:51           ` Rob Herring
  0 siblings, 1 reply; 36+ messages in thread
From: Pawel Moll @ 2012-09-04 15:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-04 at 15:31 +0100, Rob Herring wrote:
> On 09/04/2012 08:05 AM, Pawel Moll wrote:
> > On Tue, 2012-09-04 at 13:58 +0100, Rob Herring wrote:
> >>> -			sysctl at 020000 {
> >>> +			v2m_sysctl: sysctl at 020000 {
> >>>  				compatible = "arm,sp810", "arm,primecell";
> >>>  				reg = <0x020000 0x1000>;
> >>> +				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_osc_clk0>;
> >>> +				clock-names = "refclk", "timclk", "apb_pclk";
> >>
> >> See Documentation/devicetree/bindings/arm/primecell.txt
> >>
> >> apb_pclk should be first in the list.
> > 
> > Hm. Why, if you don't mind me asking? The amba_get_enable_pclk()
> > explicitly asks for "apb_pclk" id:
> 
> So apb_pclk is always in the same position in the list and I had to
> define something. Clock names are supposed to be optional, so we have to
> be able to identify which clock is the bus clock without the name.
[snip]
> You're getting lucky with how clk_get is implemented. The driver should
> be more specific with which clock it wants if there is more than 1.
> Perhaps we need a clk_get_by_index() function?

But the clocking framework doesn't know what "index", while it knows
exactly what is "id" (string). How about making the clock names
obligatory in the tree when there a node has more than one clock input?
This sounds much simpler to me and seems to be in line with the clocking
API. And the apb_pclk wouldn't have to be first/last/whatever.

Pawe?

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

* [PATCH 02/11] misc: Versatile Express config bus infrastructure
  2012-09-04 12:45       ` Arnd Bergmann
@ 2012-09-04 16:41         ` Pawel Moll
  0 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-04 16:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-04 at 13:45 +0100, Arnd Bergmann wrote:
> We're adding drivers/bus in v3.7, I already have another bus driver in
> the arm-soc tree.
> 
> The reset code can probably just go to arch/arm/mach-vexpress though,
> we do the same for the reset code on all other platforms.

Hm, ok, let's make it so. Of course the question is what will the arm64
use, but I'll ignore it for the moment.

> > So it's all about clocks, that must be available really early. The
> > particular problem I faced was the amba_probe() trying to enable
> > apb_pclk of each device and failing...
> > 
> > Now, during the clock registration the device model is not initialized
> > yet, so I can't do normal devices registration. I've stolen some ideas
> > from the early platform bus code...
> 
> Maybe you can change amba_probe() to provide a -EPROBE_DEFER return
> code to the caller when the clock is not yet there, it should then
> just come back later.

Hm. I'm honestly a little bit afraid to propose that, but I'll see how
would this work.

> > > > +struct bus_type vexpress_config_bus_type = {
> > > > +	.name = "vexpress-config",
> > > > +	.match = vexpress_config_match,
> > > > +};
> > > 
> > > What is the reason for having a separate bus_type here?
> > > Is this a discoverable bus? If it is, why do you need a
> > > device tree binding for the child devices?
> > 
> > It is not a discoverable bus, but the devices are very different from
> > the "normal" platform devices and have specific read/write interface, so
> > it seemed to me that a separate bus would make sense. And I didn't want
> > to reinvent the wheel with my own "device/driver model".
> 
> Not introducing a different way to do devices is good, but I don't think
> that using something else than platform devices buys you much. If it's not
> discoverable, this driver does not look all that different from an MFD
> (which is based on platform devices).

Generally you seem to suggest using the MFD "micro-framework" instead...
(quite frankly I wasn't aware of its existence till now_. Ok, I'll try
to use it instead of a custom bus. I have some doubts (eg. not quite
sure what to do with the resources and "reg" properties), but I'll give
it a go.

> A new bus type is typically used only for cases where you have multiple
> different bus drivers and multiple different device drivers, and want a
> bus layer to proxy between them. 

I'm not sure what do you mean by "bus driver", but to my mind the buses
are just a way of binding devices and their drivers of a particular
variety. And the VE config bus is of a very specific variety indeed :-)

> > > What is the purpose of this lookup? Can't you make the child devices get
> > > probed by the compatible value?
> > 
> > Ok, there are two reasons for this table existence:
> > 
> > 1. vexpress_config_of_populate() below - I need a comprehensive list of
> > compatible values to be able to search the tree and create respective
> > devices.
> 
> I don't see why you need this list. Just call of_platform_populate or a
> copy of that. It does not require the compatible values of the devices,
> just the one for the parent.

... but of course it only creates platform devices. So as long as 

> > 2. Non-DT static devices - I need something to be able to match a driver
> > with a device, and the "functions list" seemed appropriate.
> 
> How important is this case really, given that the driver has never been
> supported and that the non-DT case is going away soon?

The non-DT code used to use v2m_cfg_write() calls to do
restart/power_off and to control video output. So I felt obliged to
provide the same functionality.

> > Em, I'm not sure what do you mean... The idea is shamelessly stolen from
> > of_irq_init() and of_clk_init()...
> 
> But those are not buses, they are infrastructure that is used across
> buses. The regular way to do this is to register a driver for your
> parent node and then just iterate over the children, in the way that
> we do for e.g. i2c or spi buses.

Ok, I see what you mean, although this is a slightly different case than
SPI - there's no single master and straight hierarchy of the devices...
To use the I2C analogy - it would be hard to describe a multi-master I2C
segment (where one slave can be accessed by more than one master) with
the current framework and bindings. And this is roughly the VE case - a
device can be accessed through more than one bridge, and the way the
transactions are routed can be quite convoluted
(CPU->motherboard->IOFPGA->bridge->IOFPGA->motherboard
micro->daugtherboard micro->device).

Anyway, I'll see what can be simplified here.

Cheers!

Pawe?

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

* [PATCH 06/11] clk: Common clocks implementation for Versatile Express
  2012-09-04 12:43       ` Linus Walleij
@ 2012-09-04 17:12         ` Ryan Harkin
  0 siblings, 0 replies; 36+ messages in thread
From: Ryan Harkin @ 2012-09-04 17:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-04 at 14:43 +0200, Linus Walleij wrote:
> On Tue, Sep 4, 2012 at 1:53 PM, Pawel Moll <pawel.moll@arm.com> wrote:
> 
> > But we are still "CLCD driver away" from the full features
> > replacement. Ryan Harkin is working on this,
> 
> Will be useful for Integrator, Versatile, RealView, and some non-ARM
> SoCs too I think, so very interesting!

Well, we already have a patch set in our tree [1] that will support CLCD
in Device Tree, however, I have yet to get this reviewed, despite Pawel
reminding me about it, er, occasionally.

I guess that now we've seen it working on several tiles and FastModel, I
should get on with it...

I expect significant changes, particularly with the DT bindings, before
this will be acceptable upstream.

Cheers,
Ryan.

[1]
http://git.linaro.org/gitweb?p=landing-teams/working/arm/kernel.git;a=shortlog;h=refs/heads/tracking-armlt-clcd

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

* [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs
  2012-09-04 15:37         ` Pawel Moll
@ 2012-09-04 17:51           ` Rob Herring
  2012-09-19  9:44             ` Pawel Moll
  0 siblings, 1 reply; 36+ messages in thread
From: Rob Herring @ 2012-09-04 17:51 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/04/2012 10:37 AM, Pawel Moll wrote:
> On Tue, 2012-09-04 at 15:31 +0100, Rob Herring wrote:
>> On 09/04/2012 08:05 AM, Pawel Moll wrote:
>>> On Tue, 2012-09-04 at 13:58 +0100, Rob Herring wrote:
>>>>> -			sysctl at 020000 {
>>>>> +			v2m_sysctl: sysctl at 020000 {
>>>>>  				compatible = "arm,sp810", "arm,primecell";
>>>>>  				reg = <0x020000 0x1000>;
>>>>> +				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_osc_clk0>;
>>>>> +				clock-names = "refclk", "timclk", "apb_pclk";
>>>>
>>>> See Documentation/devicetree/bindings/arm/primecell.txt
>>>>
>>>> apb_pclk should be first in the list.
>>>
>>> Hm. Why, if you don't mind me asking? The amba_get_enable_pclk()
>>> explicitly asks for "apb_pclk" id:
>>
>> So apb_pclk is always in the same position in the list and I had to
>> define something. Clock names are supposed to be optional, so we have to
>> be able to identify which clock is the bus clock without the name.
> [snip]
>> You're getting lucky with how clk_get is implemented. The driver should
>> be more specific with which clock it wants if there is more than 1.
>> Perhaps we need a clk_get_by_index() function?
> 
> But the clocking framework doesn't know what "index", while it knows
> exactly what is "id" (string). How about making the clock names
> obligatory in the tree when there a node has more than one clock input?
> This sounds much simpler to me and seems to be in line with the clocking
> API. And the apb_pclk wouldn't have to be first/last/whatever.

I did say they are *supposed* to be optional, but the amba bus code
essentially makes them required. Ideally, Linux doesn't dictate what
goes in the dtb or not, but I don't have a problem if specific users of
the clock binding require the names.

Rob

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

* [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver
  2012-09-03 16:25 ` [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver Pawel Moll
@ 2012-09-10 19:14   ` Mike Turquette
  2012-09-11 16:10     ` Pawel Moll
  0 siblings, 1 reply; 36+ messages in thread
From: Mike Turquette @ 2012-09-10 19:14 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Pawel Moll (2012-09-03 09:25:25)
> +static int vexpress_osc_probe(struct vexpress_config_device *vecdev)
> +{
> +       int err;
> +       struct device_node *node = vecdev->dev.of_node;
> +       struct vexpress_osc_info *info = vecdev->dev.platform_data;
> +       struct clk_init_data init;
> +       struct vexpress_osc *osc;
> +       struct clk *clk;
> +       const char * const *dev_ids = NULL;
> +       u32 range[2];
> +
> +       if (vecdev->status & VEXPRESS_CONFIG_DEVICE_PROBED_EARLY)
> +               return 0;
> +
> +       osc = kzalloc(sizeof(*osc), GFP_KERNEL);
> +       if (!osc) {
> +               err = -ENOMEM;
> +               goto error;

Minor nitpick: the error label tries to free osc, which in this case
shouldn't be freed because it is NULL.

<snip>
> +error:
> +       kfree(osc);
> +       return err;

Would be better to have something like:

		error_clk:
			kfree(osc);
		error_osc:
			return err;

Otherwise patch looks good to me.  There are some changes to headers in
this patch, and it is part of a larger series.  How did you want the
common clk patches to get merged?

Regards,
Mike

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

* [PATCH 06/11] clk: Common clocks implementation for Versatile Express
  2012-09-03 16:25 ` [PATCH 06/11] clk: Common clocks implementation for Versatile Express Pawel Moll
  2012-09-03 21:24   ` Arnd Bergmann
@ 2012-09-10 20:10   ` Mike Turquette
  1 sibling, 0 replies; 36+ messages in thread
From: Mike Turquette @ 2012-09-10 20:10 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Pawel Moll (2012-09-03 09:25:26)
> 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
> explicitely registers VE "osc" driver, to make the
> clock generators availalable early.
> 
> Signed-off-by: Pawel Moll <pawel.moll@arm.com>
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: Linus Walleij <linus.walleij@linaro.org>

Barring the DT-related comments by Arnd and others, the common
clk-specific changes in this patch look good to me.  Which tree will
this patch go through?  (same question I asked on patch 5)

Regards,
Mike

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

* [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver
  2012-09-10 19:14   ` Mike Turquette
@ 2012-09-11 16:10     ` Pawel Moll
  2012-09-11 18:00       ` Linus Walleij
  2012-09-11 18:33       ` Mike Turquette
  0 siblings, 2 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-11 16:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Mike,

On Mon, 2012-09-10 at 20:14 +0100, Mike Turquette wrote:
> Quoting Pawel Moll (2012-09-03 09:25:25)
> > +static int vexpress_osc_probe(struct vexpress_config_device *vecdev)
> > +{
> > +       int err;
> > +       struct device_node *node = vecdev->dev.of_node;
> > +       struct vexpress_osc_info *info = vecdev->dev.platform_data;
> > +       struct clk_init_data init;
> > +       struct vexpress_osc *osc;
> > +       struct clk *clk;
> > +       const char * const *dev_ids = NULL;
> > +       u32 range[2];
> > +
> > +       if (vecdev->status & VEXPRESS_CONFIG_DEVICE_PROBED_EARLY)
> > +               return 0;
> > +
> > +       osc = kzalloc(sizeof(*osc), GFP_KERNEL);
> > +       if (!osc) {
> > +               err = -ENOMEM;
> > +               goto error;
> 
> Minor nitpick: the error label tries to free osc, which in this case
> shouldn't be freed because it is NULL.
> 
> <snip>
> > +error:
> > +       kfree(osc);
> > +       return err;

$ grep kfree scripts/checkpatch.pl 
# check for needless kfree() checks
			if ($line =~ /\bkfree\(\Q$expr\E\);/) {
				     "kfree(NULL) is safe this check is probably not required\n" . $hereprev);

$ grep -B2 kfree Documentation/CodingStyle 
	...
out:
	kfree(buffer);

;-)

> Otherwise patch looks good to me.  There are some changes to headers in
> this patch, and it is part of a larger series. How did you want the
> common clk patches to get merged?

I'm re-working the series right now, but generally I planned to push
drivers/clk changes via your tree, unless you want me to get it in
through arm-soc.

Cheers!

Pawel

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

* [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver
  2012-09-11 16:10     ` Pawel Moll
@ 2012-09-11 18:00       ` Linus Walleij
  2012-09-12 16:56         ` Pawel Moll
  2012-09-11 18:33       ` Mike Turquette
  1 sibling, 1 reply; 36+ messages in thread
From: Linus Walleij @ 2012-09-11 18:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 11, 2012 at 6:10 PM, Pawel Moll <pawel.moll@arm.com> wrote:
> On Mon, 2012-09-10 at 20:14 +0100, Mike Turquette wrote:
(...)
>> > +       osc = kzalloc(sizeof(*osc), GFP_KERNEL);
(...)
>> Minor nitpick: the error label tries to free osc, which in this case
>> shouldn't be freed because it is NULL.
>>
>> > +       kfree(osc);
(...)
> $ grep kfree scripts/checkpatch.pl
(...)
> $ grep -B2 kfree Documentation/CodingStyle

Can't you just use devm_kzalloc(&vecdev->dev, ...) and be done with it?

Yours,
Linus Walleij

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

* [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver
  2012-09-11 16:10     ` Pawel Moll
  2012-09-11 18:00       ` Linus Walleij
@ 2012-09-11 18:33       ` Mike Turquette
  1 sibling, 0 replies; 36+ messages in thread
From: Mike Turquette @ 2012-09-11 18:33 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Pawel Moll (2012-09-11 09:10:48)
> I'm re-working the series right now, but generally I planned to push
> drivers/clk changes via your tree, unless you want me to get it in
> through arm-soc.
> 

I'm happy to take the clk patches.  Just make it clear which patches you
want to go through me (I think it's obvious which two, but clarity is
always nice ;-)

Regards,
Mike

> Cheers!
> 
> Pawel
> 
> 
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver
  2012-09-11 18:00       ` Linus Walleij
@ 2012-09-12 16:56         ` Pawel Moll
  0 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-12 16:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-11 at 19:00 +0100, Linus Walleij wrote:
> >> > +       osc = kzalloc(sizeof(*osc), GFP_KERNEL);
>
> Can't you just use devm_kzalloc(&vecdev->dev, ...) and be done with it?

Eh. It was devm_kzalloc() initially, then the driver became an "early"
one and I could use devm_*(). I actually made it devm_kzalloc() again,
hope it will survive like this to v2.

Pawe?

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

* [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs
  2012-09-04 17:51           ` Rob Herring
@ 2012-09-19  9:44             ` Pawel Moll
  0 siblings, 0 replies; 36+ messages in thread
From: Pawel Moll @ 2012-09-19  9:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-09-04 at 18:51 +0100, Rob Herring wrote:
> I did say they are *supposed* to be optional, but the amba bus code
> essentially makes them required. Ideally, Linux doesn't dictate what
> goes in the dtb or not, but I don't have a problem if specific users of
> the clock binding require the names.

Ok, so how about such change in wording?

--- a/Documentation/devicetree/bindings/arm/primecell.txt
+++ b/Documentation/devicetree/bindings/arm/primecell.txt
@@ -13,17 +13,18 @@ Required properties:
 Optional properties:
 
 - arm,primecell-periphid : Value to override the h/w value with
-- clocks : From common clock binding. First clock is phandle to clock for apb
-       pclk. Additional clocks are optional and specific to those peripherals.
-- clock-names : From common clock binding. Shall be "apb_pclk" for first clock.
+- clocks : From common clock binding. One of the clocks should be a phandle to
+        clock for APB PCLK. Additional clocks are optional and specific to
+        those peripherals.
+- clock-names : From common clock binding. Required here if clocks are
+        defined. Shall be "apb_pclk" for the APB PCLK.
 
 Example:
 
 serial at fff36000 {
        compatible = "arm,pl011", "arm,primecell";
        arm,primecell-periphid = <0x00341011>;
-       clocks = <&pclk>;
-       clock-names = "apb_pclk";
-       
+       clocks = <&refclk>, <&pclk>;
+       clock-names = "uartclk", "apb_pclk";
 };



Also, maybe we could add a possibility of defining the APB clock for
whole APB "cluster" (as usually the same clock is shared across all
peripherals connected to a single AHB/APB bridge) using clock-ranges
parents? What I think about is something of this sort:

iofpga {
	clock-ranges;
	clocks = <&pclk>;
	clock-names = "apb_pclk";

	serial {
	        compatible = "arm,pl011", "arm,primecell";
		clocks = <&refclk>;
		clock-names = "uartclk";
	};
};

Cheers!

Pawel

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

end of thread, other threads:[~2012-09-19  9:44 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-03 16:25 [PATCH 00/11] Versatile Express infrastructure Pawel Moll
2012-09-03 16:25 ` [PATCH 01/11] input: ambakmi: Add missing clk_[un]prepare() calls Pawel Moll
2012-09-04 13:37   ` Thomas Petazzoni
2012-09-04 13:45     ` Pawel Moll
2012-09-03 16:25 ` [PATCH 02/11] misc: Versatile Express config bus infrastructure Pawel Moll
2012-09-03 21:17   ` Arnd Bergmann
2012-09-04 11:53     ` Pawel Moll
2012-09-04 12:45       ` Arnd Bergmann
2012-09-04 16:41         ` Pawel Moll
2012-09-03 16:25 ` [PATCH 03/11] misc: Versatile Express reset driver Pawel Moll
2012-09-03 16:25 ` [PATCH 04/11] misc: Versatile Express display muxer driver Pawel Moll
2012-09-03 21:21   ` Arnd Bergmann
2012-09-04 11:53     ` Pawel Moll
2012-09-03 16:25 ` [PATCH 05/11] clk: Versatile Express clock generators ("osc") driver Pawel Moll
2012-09-10 19:14   ` Mike Turquette
2012-09-11 16:10     ` Pawel Moll
2012-09-11 18:00       ` Linus Walleij
2012-09-12 16:56         ` Pawel Moll
2012-09-11 18:33       ` Mike Turquette
2012-09-03 16:25 ` [PATCH 06/11] clk: Common clocks implementation for Versatile Express Pawel Moll
2012-09-03 21:24   ` Arnd Bergmann
2012-09-04 11:53     ` Pawel Moll
2012-09-04 12:43       ` Linus Walleij
2012-09-04 17:12         ` Ryan Harkin
2012-09-10 20:10   ` Mike Turquette
2012-09-03 16:25 ` [PATCH 07/11] regulators: Versatile Express regulator driver Pawel Moll
2012-09-03 16:25 ` [PATCH 08/11] hwmon: Versatile Express hwmon driver Pawel Moll
2012-09-03 16:25 ` [PATCH 09/11] misc: Versatile Express system registers driver Pawel Moll
2012-09-03 16:25 ` [PATCH 10/11] ARM: vexpress: Add config bus components and clocks to DTs Pawel Moll
2012-09-04 12:58   ` Rob Herring
2012-09-04 13:05     ` Pawel Moll
2012-09-04 14:31       ` Rob Herring
2012-09-04 15:37         ` Pawel Moll
2012-09-04 17:51           ` Rob Herring
2012-09-19  9:44             ` Pawel Moll
2012-09-03 16:25 ` [PATCH 11/11] ARM: vexpress: Start using new Versatile Express infrastructure Pawel Moll

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.