linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 2/8] ARM:global_timer: Add ARM global timer support.
       [not found] <1368022187-1633-1-git-send-email-srinivas.kandagatla@st.com>
@ 2013-05-08 14:11 ` Srinivas KANDAGATLA
  2013-05-08 14:26   ` Rob Herring
  2013-05-08 14:38   ` Arnd Bergmann
  2013-05-08 14:11 ` [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs Srinivas KANDAGATLA
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 14:11 UTC (permalink / raw)
  To: linux, will.deacon
  Cc: Rob Landley, Grant Likely, Rob Herring, Samuel Ortiz,
	Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Srinivas Kandagatla, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Dave Martin, Marc Zyngier, Viresh Kumar, Arnd Bergmann,
	Mark Brown, Dong Aisheng, linux-doc, linux-kernel,
	devicetree-discuss, linux-arm-kernel, linux-serial

From: Stuart Menefy <stuart.menefy@st.com>

This is a simple driver for the global timer module found in the Cortex
A9-MP cores from revision r1p0 onwards. This should be able to perform
the functions of the system timer and the local timer in an SMP system.

The global timer has the following features:
    The global timer is a 64-bit incrementing counter with an
auto-incrementing feature. It continues incrementing after sending
interrupts. The global timer is memory mapped in the private memory
region.
    The global timer is accessible to all Cortex-A9 processors in the
cluster. Each Cortex-A9 processor has a private 64-bit comparator that
is used to assert a private interrupt when the global timer has reached
the comparator value. All the Cortex-A9 processors in a design use the
banked ID, ID27, for this interrupt. ID27 is sent to the Interrupt
Controller as a Private Peripheral Interrupt. The global timer is
clocked by PERIPHCLK.

Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
---
 Documentation/devicetree/bindings/arm/gt.txt |   21 ++
 arch/arm/Kconfig                             |    6 +
 arch/arm/include/asm/global_timer.h          |   12 +
 arch/arm/kernel/Makefile                     |    1 +
 arch/arm/kernel/global_timer.c               |  325 ++++++++++++++++++++++++++
 5 files changed, 365 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/gt.txt
 create mode 100644 arch/arm/include/asm/global_timer.h
 create mode 100644 arch/arm/kernel/global_timer.c

diff --git a/Documentation/devicetree/bindings/arm/gt.txt b/Documentation/devicetree/bindings/arm/gt.txt
new file mode 100644
index 0000000..4ec5fb0
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/gt.txt
@@ -0,0 +1,21 @@
+
+* ARM Global Timer
+	Cortex-A9 are often associated with a per-core Global timer.
+
+** Timer node required properties:
+
+- compatible : Should be one of:
+	"arm,cortex-a9-global-timer"
+
+- interrupts : One interrupt to each core
+
+- reg : Specify the base address and the size of the GT timer
+	register window.
+
+Example:
+
+	gt-timer@2c000600 {
+		compatible = "arm,cortex-a9-global-timer";
+		reg = <0x2c000600 0x20>;
+		interrupts = <1 13 0xf01>;
+	};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1cacda4..c8c524e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1606,6 +1606,12 @@ config HAVE_ARM_TWD
 	help
 	  This options enables support for the ARM timer and watchdog unit
 
+config HAVE_ARM_GT
+	bool
+	select CLKSRC_OF if OF
+	help
+	  This options enables support for the ARM global timer unit
+
 choice
 	prompt "Memory split"
 	default VMSPLIT_3G
diff --git a/arch/arm/include/asm/global_timer.h b/arch/arm/include/asm/global_timer.h
new file mode 100644
index 0000000..46f9188
--- /dev/null
+++ b/arch/arm/include/asm/global_timer.h
@@ -0,0 +1,12 @@
+/*
+ * arch/arm/include/asm/global_timer.h
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ *
+ * 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.
+ */
+
+int __init global_timer_init(void __iomem *base, unsigned int timer_irq);
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 5f3338e..af51808 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_ARM_CPU_SUSPEND)	+= sleep.o suspend.o
 obj-$(CONFIG_SMP)		+= smp.o smp_tlb.o
 obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
 obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
+obj-$(CONFIG_HAVE_ARM_GT)	+= global_timer.o
 obj-$(CONFIG_ARM_ARCH_TIMER)	+= arch_timer.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
diff --git a/arch/arm/kernel/global_timer.c b/arch/arm/kernel/global_timer.c
new file mode 100644
index 0000000..0ab1af3
--- /dev/null
+++ b/arch/arm/kernel/global_timer.c
@@ -0,0 +1,325 @@
+/*
+ * linux/arch/arm/kernel/global_timer.c
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include <asm/mach/irq.h>
+#include <asm/global_timer.h>
+#include <asm/localtimer.h>
+
+#define GT_COUNTER0	0x00
+#define GT_COUNTER1	0x04
+
+#define GT_CONTROL	0x08
+#define GT_CONTROL_TIMER_ENABLE		BIT(0)
+#define GT_CONTROL_COMP_ENABLE		BIT(1)	/* banked */
+#define GT_CONTROL_IRQ_ENABLE		BIT(2)	/* banked */
+#define GT_CONTROL_AUTO_INC		BIT(3)	/* banked */
+
+#define GT_INT_STATUS	0x0c
+#define GT_INT_STATUS_EVENT_FLAG	BIT(0)
+
+#define GT_COMP0	0x10
+#define GT_COMP1	0x14
+#define GT_AUTO_INC	0x18
+
+/*
+ * We are expecting to be clocked by the ARM peripheral clock.
+ *
+ * Note: it is assumed we are using a prescaler value of zero, so this is
+ * the units for all operations.
+ */
+static void __iomem *gt_base;
+static struct clk *gt_clk;
+static unsigned long gt_clk_rate;
+static int gt_ppi;
+static struct clock_event_device __percpu **gt_evt;
+static DEFINE_PER_CPU(bool, percpu_init_called);
+static DEFINE_PER_CPU(struct clock_event_device, gt_clockevent);
+
+union gt_counter {
+	cycle_t cycles;
+	struct {
+		uint32_t lower;
+		uint32_t upper;
+	};
+};
+
+static union gt_counter gt_counter_read(void)
+{
+	union gt_counter res;
+	uint32_t upper;
+
+	upper = readl(gt_base + GT_COUNTER1);
+	do {
+		res.upper = upper;
+		res.lower = readl(gt_base + GT_COUNTER0);
+		upper = readl(gt_base + GT_COUNTER1);
+	} while (upper != res.upper);
+
+	return res;
+}
+
+static void gt_compare_set(unsigned long delta, int periodic)
+{
+	union gt_counter counter = gt_counter_read();
+	unsigned long ctrl = readl(gt_base + GT_CONTROL);
+
+	BUG_ON(!(ctrl & GT_CONTROL_TIMER_ENABLE));
+	BUG_ON(ctrl & (GT_CONTROL_COMP_ENABLE |
+		       GT_CONTROL_IRQ_ENABLE |
+		       GT_CONTROL_AUTO_INC));
+
+	counter.cycles += delta;
+	writel(counter.lower, gt_base + GT_COMP0);
+	writel(counter.upper, gt_base + GT_COMP1);
+
+	ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE;
+
+	if (periodic) {
+		writel(delta, gt_base + GT_AUTO_INC);
+		ctrl |= GT_CONTROL_AUTO_INC;
+	}
+
+	writel(ctrl, gt_base + GT_CONTROL);
+}
+
+static void gt_clockevent_set_mode(enum clock_event_mode mode,
+				   struct clock_event_device *clk)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		gt_compare_set(gt_clk_rate/HZ, 1);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* period set, and timer enabled in 'next_event' hook */
+		BUG_ON(readl(gt_base + GT_CONTROL) &
+		       (GT_CONTROL_COMP_ENABLE |
+			GT_CONTROL_IRQ_ENABLE |
+			GT_CONTROL_AUTO_INC));
+		/* Fall through */
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	default:
+		writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+		break;
+	}
+}
+
+static int gt_clockevent_set_next_event(unsigned long evt,
+					struct clock_event_device *unused)
+{
+	gt_compare_set(evt, 0);
+	return 0;
+}
+
+static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+
+	writel(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS);
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static int __cpuinit gt_clockevents_init(struct clock_event_device *clk)
+{
+	struct clock_event_device **this_cpu_clk;
+	int cpu = smp_processor_id();
+
+	clk->name = "Global Timer CE";
+	clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+	clk->set_mode = gt_clockevent_set_mode;
+	clk->set_next_event = gt_clockevent_set_next_event;
+	this_cpu_clk = __this_cpu_ptr(gt_evt);
+	*this_cpu_clk = clk;
+	clk->irq = gt_ppi;
+	clockevents_config_and_register(clk, gt_clk_rate,
+					0xf, 0xffffffff);
+	per_cpu(percpu_init_called, cpu) = true;
+	enable_percpu_irq(clk->irq, IRQ_TYPE_NONE);
+	return 0;
+}
+
+static void gt_clockevents_stop(struct clock_event_device *clk)
+{
+	gt_clockevent_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+	disable_percpu_irq(clk->irq);
+}
+
+static int __cpuinit gt_clockevents_setup(struct clock_event_device *clk)
+{
+	int cpu = smp_processor_id();
+
+	/* Use existing clock_event for boot cpu */
+	if (per_cpu(percpu_init_called, cpu))
+		return 0;
+
+	writel(0, gt_base + GT_CONTROL);
+	writel(0, gt_base + GT_COUNTER0);
+	writel(0, gt_base + GT_COUNTER1);
+	writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+
+	return gt_clockevents_init(clk);
+}
+
+static cycle_t gt_clocksource_read(struct clocksource *cs)
+{
+	union gt_counter res = gt_counter_read();
+	return res.cycles;
+}
+
+static struct clocksource gt_clocksource = {
+	.name	= "Global Timer CS",
+	.rating	= 300,
+	.read	= gt_clocksource_read,
+	.mask	= CLOCKSOURCE_MASK(64),
+	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init gt_clocksource_init(void)
+{
+	writel(0, gt_base + GT_CONTROL);
+	writel(0, gt_base + GT_COUNTER0);
+	writel(0, gt_base + GT_COUNTER1);
+	writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+
+	gt_clocksource.shift = 20;
+	gt_clocksource.mult =
+		clocksource_hz2mult(gt_clk_rate, gt_clocksource.shift);
+	clocksource_register(&gt_clocksource);
+}
+
+static struct clk *gt_get_clock(void)
+{
+	struct clk *clk;
+	int err;
+
+	clk = clk_get_sys("gt", NULL);
+	if (IS_ERR(clk)) {
+		pr_err("global-timer: clock not found: %ld\n", PTR_ERR(clk));
+		return clk;
+	}
+
+	err = clk_prepare_enable(clk);
+	if (err) {
+		pr_err("global-timer: clock prepare+enable failed: %d\n", err);
+		clk_put(clk);
+		return ERR_PTR(err);
+	}
+
+	return clk;
+}
+
+static struct local_timer_ops gt_lt_ops __cpuinitdata = {
+	.setup	= gt_clockevents_setup,
+	.stop	= gt_clockevents_stop,
+};
+
+int __init global_timer_init(void __iomem *base, unsigned int timer_irq)
+{
+	unsigned int cpu = smp_processor_id();
+	struct clock_event_device *evt = &per_cpu(gt_clockevent, cpu);
+	int err = 0;
+
+	if (gt_base) {
+		pr_warn("global-timer: invalid base address\n");
+		return -EINVAL;
+	}
+
+	gt_clk = gt_get_clock();
+	if (IS_ERR(gt_clk)) {
+		pr_warn("global-timer: clk not found\n");
+		return -EINVAL;
+	}
+
+	gt_evt = alloc_percpu(struct clock_event_device *);
+	if (!gt_evt) {
+		pr_warn("global-timer: can't allocate memory\n");
+		return -ENOMEM;
+	}
+
+	err = request_percpu_irq(timer_irq, gt_clockevent_interrupt,
+				 "gt", gt_evt);
+	if (err) {
+		pr_warn("global-timer: can't register interrupt %d (%d)\n",
+			timer_irq, err);
+		goto out_free;
+	}
+
+	gt_base = base;
+	gt_clk_rate = clk_get_rate(gt_clk);
+
+	evt->irq = timer_irq;
+	gt_ppi = timer_irq;
+	evt->cpumask = cpumask_of(cpu);
+
+	gt_clocksource_init();
+	gt_clockevents_init(evt);
+	err =  local_timer_register(&gt_lt_ops);
+	if (err) {
+		pr_warn("global-timer: unable to register local timer.\n");
+		goto out_irq;
+	}
+
+	return 0;
+
+out_irq:
+	free_percpu_irq(timer_irq, gt_evt);
+out_free:
+	free_percpu(gt_evt);
+	return err;
+}
+
+#ifdef CONFIG_OF
+static void __init global_timer_of_register(struct device_node *np)
+{
+	struct clk *clk;
+	int err = 0;
+	int gt_ppi;
+	static void __iomem *gt_base;
+
+	gt_ppi = irq_of_parse_and_map(np, 0);
+	if (!gt_ppi) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	gt_base = of_iomap(np, 0);
+	if (!gt_base) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	clk = of_clk_get(np, 0);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "gt");
+
+	global_timer_init(gt_base, gt_ppi);
+
+out:
+	WARN(err, "Global timer register failed (%d)\n", err);
+}
+
+CLOCKSOURCE_OF_DECLARE(arm_gt_a9, "arm,cortex-a9-global-timer",
+			global_timer_of_register);
+#endif
-- 
1.7.6.5


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

* [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
       [not found] <1368022187-1633-1-git-send-email-srinivas.kandagatla@st.com>
  2013-05-08 14:11 ` [RFC 2/8] ARM:global_timer: Add ARM global timer support Srinivas KANDAGATLA
@ 2013-05-08 14:11 ` Srinivas KANDAGATLA
  2013-05-08 14:50   ` Arnd Bergmann
  2013-05-08 14:11 ` =?y?q?=5BRFC=205/8=5D=20ARM=3Astih41x=3A=20Add=20STiH415=20SOC=20support?= Srinivas KANDAGATLA
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 14:11 UTC (permalink / raw)
  To: dong.aisheng, sameo
  Cc: Rob Landley, Grant Likely, Rob Herring, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Srinivas Kandagatla, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Will Deacon, Dave Martin, Marc Zyngier, Viresh Kumar,
	Arnd Bergmann, Mark Brown, linux-doc, linux-kernel,
	devicetree-discuss, linux-arm-kernel, linux-serial

From: Srinivas Kandagatla <srinivas.kandagatla@st.com>

This patch introduces syscon_claim, syscon_read, syscon_write,
syscon_release APIs to help drivers to use syscon registers in much more
flexible way.

With this patch, a driver can claim few/all bits in the syscon registers
and do read/write and then release them when its totally finished with
them, in the mean time if another driver requests same bits or registers
the API will detect conflit and return error to the second request.

Reason to introduce this API.
System configuration/control registers are very basic configuration
registers arranged in groups across ST Settop Box parts. These registers
are independent of IP itself. Many IPs, clock, pad and other functions
are wired up to these registers.

In many cases a single syconf register contains bits related to multiple
devices, and therefore it need to be shared across multiple drivers at
bit level. The same IP block can have different syscon mappings on
different SOCs.

Typically in a SOC there will be more than hundreds of these registers,
which are again divided into groups.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
CC: Stuart Menefy <stuart.menefy@st.com>
---
 drivers/mfd/syscon.c       |  199 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/syscon.h |   43 ++++++++++
 2 files changed, 242 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 61aea63..fab85da 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/slab.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
@@ -28,8 +29,23 @@ struct syscon {
 	struct device *dev;
 	void __iomem *base;
 	struct regmap *regmap;
+	struct device_node *of_node;
+	struct list_head list;
+	struct list_head fields;
+	spinlock_t fields_lock;
 };
 
+struct syscon_field {
+	struct syscon *syscon;
+	u16 num;
+	u8 lsb, msb;
+	unsigned int offset;
+	const char *owner;
+	struct list_head list;
+};
+
+static LIST_HEAD(syscons);
+
 static int syscon_match(struct device *dev, void *data)
 {
 	struct syscon *syscon = dev_get_drvdata(dev);
@@ -87,6 +103,185 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);
 
+static int syscon_add_field(struct syscon_field *field)
+{
+	struct syscon_field *entry;
+	enum {
+		status_not_found,
+		status_found_register,
+		status_add_field_here,
+	} status = status_not_found;
+	int bit_avail = 0;
+	struct syscon *syscon = field->syscon;
+	int rval = 0;
+	int num = field->num;
+	int lsb = field->lsb;
+	int msb = field->msb;
+
+	spin_lock(&syscon->fields_lock);
+	/*
+	 * The list is always in syscon->num->lsb/msb order, so it's easy to
+	 * find a place to insert a new field (and to detect conflicts)
+	 */
+	list_for_each_entry(entry, &syscon->fields, list) {
+		if (entry->num == num) {
+			status = status_found_register;
+			/*
+			 * Someone already claimed a field from this
+			 * register - let's try to find some space for
+			 * requested bits...
+			 */
+			if (bit_avail <= lsb && msb < entry->lsb) {
+				status = status_add_field_here;
+				break;
+			}
+			bit_avail = entry->msb + 1;
+		} else if (entry->num > num) {
+			/*
+			 * There is no point of looking further -
+			 * the num values are bigger then
+			 * the ones we are looking for
+			 */
+			if ((status == status_found_register &&
+					bit_avail <= lsb) ||
+					status == status_not_found)
+				/*
+				 * A remainder of the given register is not
+				 * used or the register wasn't used at all
+				 */
+				status = status_add_field_here;
+			else
+				/*
+				 * Apparently some bits of the claimed field
+				 * are already in use...
+				 */
+				rval = -EBUSY;
+			break;
+		}
+	}
+
+	if ((status == status_not_found) || (status == status_found_register))
+		list_add_tail(&field->list, &syscon->fields);
+	else if (status == status_add_field_here)
+		list_add(&field->list, entry->list.prev);
+
+	spin_unlock(&syscon->fields_lock);
+	return rval;
+}
+
+static struct syscon *find_syscon(struct device_node *np)
+{
+	struct syscon *syscon;
+
+	list_for_each_entry(syscon, &syscons, list) {
+		if (syscon->of_node == np)
+			return syscon;
+	}
+	return NULL;
+}
+
+#define MIN_SYSCON_CELLS	(4)
+
+struct syscon_field *syscon_claim(struct device_node *np,
+				const char *prop)
+{
+	const __be32 *list;
+	const struct property *pp;
+	struct syscon_field *field;
+	phandle phandle;
+	struct device_node *syscon_np;
+	u32 syscon_num;
+
+	pp = of_find_property(np, prop, NULL);
+	if (!pp)
+		return NULL;
+
+	if (pp->length < ((MIN_SYSCON_CELLS) * sizeof(*list)))
+		return NULL;
+
+	list = pp->value;
+
+	/* syscon */
+	phandle = be32_to_cpup(list++);
+	syscon_np = of_find_node_by_phandle(phandle);
+	if (!syscon_np) {
+		pr_warn("No syscon found for %s syscon\n", prop);
+		return NULL;
+	}
+
+	field = kzalloc(sizeof(struct syscon_field), GFP_KERNEL);
+	if (!field)
+		return NULL;
+
+	field->syscon = find_syscon(syscon_np);
+	if (!field->syscon) {
+		pr_warn("No syscon registered for %s syscon\n", prop);
+		goto error;
+	}
+
+	of_node_put(syscon_np);
+	syscon_num = be32_to_cpup(list++);
+	field->offset = (syscon_num) * 4;
+	field->lsb = be32_to_cpup(list++);
+	field->msb = be32_to_cpup(list++);
+	field->num = syscon_num;
+	field->owner = pp->name;
+
+	if (syscon_add_field(field))
+		goto error;
+
+	return field;
+error:
+	kfree(field);
+	return NULL;
+}
+EXPORT_SYMBOL(syscon_claim);
+
+void syscon_release(struct syscon_field *field)
+{
+	struct syscon *syscon;
+	if (field) {
+		syscon = field->syscon;
+		spin_lock(&syscon->fields_lock);
+		list_del(&field->list);
+		spin_unlock(&syscon->fields_lock);
+		kfree(field);
+	}
+}
+EXPORT_SYMBOL(syscon_release);
+
+void syscon_write(struct syscon_field *field, unsigned long value)
+{
+	int field_bits;
+	struct syscon *syscon = field->syscon;
+
+	field_bits = field->msb - field->lsb + 1;
+	if (field_bits == 32) {
+		regmap_write(syscon->regmap, field->offset, value);
+	} else {
+		u32 reg_mask;
+		reg_mask = (((1 << field_bits) - 1) << field->lsb);
+		regmap_update_bits(syscon->regmap, field->offset,
+					reg_mask, value << field->lsb);
+	}
+}
+EXPORT_SYMBOL(syscon_write);
+
+unsigned long syscon_read(struct syscon_field *field)
+{
+	int field_bits;
+	u32 result;
+	struct syscon *syscon = field->syscon;
+
+	regmap_read(syscon->regmap, field->offset, &result);
+	field_bits = field->msb - field->lsb + 1;
+	result >>= field->lsb;
+	result &= (1 << field_bits) - 1;
+
+	return result;
+}
+EXPORT_SYMBOL(syscon_read);
+
 static const struct of_device_id of_syscon_match[] = {
 	{ .compatible = "syscon", },
 	{ },
@@ -122,6 +317,10 @@ static int syscon_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	list_add_tail(&syscon->list, &syscons);
+	INIT_LIST_HEAD(&syscon->fields);
+	syscon->of_node = np;
+
 	syscon_regmap_config.max_register = res.end - res.start - 3;
 	syscon->regmap = devm_regmap_init_mmio(dev, syscon->base,
 					&syscon_regmap_config);
diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h
index 6aeb6b8..0de0da5 100644
--- a/include/linux/mfd/syscon.h
+++ b/include/linux/mfd/syscon.h
@@ -15,9 +15,52 @@
 #ifndef __LINUX_MFD_SYSCON_H__
 #define __LINUX_MFD_SYSCON_H__
 
+struct syscon_field;
+
 extern struct regmap *syscon_node_to_regmap(struct device_node *np);
 extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s);
 extern struct regmap *syscon_regmap_lookup_by_phandle(
 					struct device_node *np,
 					const char *property);
+
+/**
+ * syscon_claim - Claim ownership of a field of a syscon register
+ * @np: parent node pointer.
+ * @prop: name of sysconf to claim.
+ *
+ * This function claims ownership of a field from a syscon register.
+ * It returns a &struct syscon_field which can be used in subsequent
+ * operations on this field.
+ */
+struct syscon_field *syscon_claim(struct device_node *np,
+			const char *prop);
+
+/**
+ * syscon_release - Release ownership of a field of a syscon register
+ * @field: the syscon field to write to
+ *
+ * Release ownership of a field from a syscon register.
+ * @field must have been claimed using syscon_claim().
+ */
+void syscon_release(struct syscon_field *field);
+
+/**
+ * syscon_write - Write a value into a field of a syscon register
+ * @field: the syscon field to write to
+ * @value: the value to write into the field
+ *
+ * This writes @value into the field of the syscon register @field.
+ * @field must have been claimed using syscon_claim().
+ */
+void syscon_write(struct syscon_field *field, unsigned long value);
+
+/**
+ * syscon_read - Read a field of a syscon register
+ * @field: the syscon field to read
+ *
+ * This reads a field of the syscon register @field.
+ * @field must have been claimed using syscon_claim().
+ */
+unsigned long syscon_read(struct syscon_field *field);
+
 #endif /* __LINUX_MFD_SYSCON_H__ */
-- 
1.7.6.5


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

* =?y?q?=5BRFC=205/8=5D=20ARM=3Astih41x=3A=20Add=20STiH415=20SOC=20support?=
       [not found] <1368022187-1633-1-git-send-email-srinivas.kandagatla@st.com>
  2013-05-08 14:11 ` [RFC 2/8] ARM:global_timer: Add ARM global timer support Srinivas KANDAGATLA
  2013-05-08 14:11 ` [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs Srinivas KANDAGATLA
@ 2013-05-08 14:11 ` Srinivas KANDAGATLA
  2013-05-08 16:18   ` [RFC 5/8] ARM:stih41x: Add STiH415 SOC support Arnd Bergmann
  2013-05-08 14:11 ` [RFC 6/8] ARM:stih41x: Add STiH416 " Srinivas KANDAGATLA
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 14:11 UTC (permalink / raw)
  To: linux, arnd, olof
  Cc: Rob Landley, Grant Likely, Rob Herring, Samuel Ortiz,
	Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Srinivas Kandagatla, Stuart Menefy, Shawn Guo, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown,
	Dong Aisheng, linux-doc, linux-kernel, devicetree-discuss,
	linux-arm-kernel, linux-serial, Stephen Gallimore

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 49749 bytes --]

From: Srinivas Kandagatla <srinivas.kandagatla@st.com>

The STiH415 is the next generation of HD, AVC set-top box processors for
satellite, cable, terrestrial and IP-STB markets. It is an ARM Cortex-A9
1.0 GHz, dual-core CPU.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
CC: Stephen Gallimore <stephen.gallimore@st.com>
CC: Stuart Menefy <stuart.menefy@st.com>
---
 Documentation/arm/STiH41x/overview.txt         |   39 ++
 Documentation/arm/STiH41x/stih415-overview.txt |   12 +
 arch/arm/Kconfig                               |    3 +
 arch/arm/Kconfig.debug                         |   38 ++
 arch/arm/Makefile                              |    2 +
 arch/arm/boot/dts/stih415-clock.dtsi           |   38 ++
 arch/arm/boot/dts/stih415-pinctrl.dtsi         |  480 ++++++++++++++++++++++++
 arch/arm/boot/dts/stih415.dtsi                 |   94 +++++
 arch/arm/boot/dts/stih415.h                    |   20 +
 arch/arm/boot/dts/stih41x.dtsi                 |   30 ++
 arch/arm/boot/dts/stixxxx-pincfg.h             |   95 +++++
 arch/arm/configs/stih41x_defconfig             |   94 +++++
 arch/arm/include/debug/stixxxx.S               |   61 +++
 arch/arm/mach-stih41x/Kconfig                  |   35 ++
 arch/arm/mach-stih41x/Makefile                 |    4 +
 arch/arm/mach-stih41x/board-dt.c               |   76 ++++
 arch/arm/mach-stih41x/stih41x.c                |   82 ++++
 arch/arm/mach-stih41x/stih41x.h                |    7 +
 arch/arm/plat-stixxxx/Kconfig                  |    2 +
 arch/arm/plat-stixxxx/Makefile                 |    2 +
 arch/arm/plat-stixxxx/headsmp.S                |   44 +++
 arch/arm/plat-stixxxx/include/plat/hardware.h  |   20 +
 arch/arm/plat-stixxxx/include/plat/smp.h       |   19 +
 arch/arm/plat-stixxxx/platsmp.c                |  144 +++++++
 24 files changed, 1441 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/arm/STiH41x/overview.txt
 create mode 100644 Documentation/arm/STiH41x/stih415-overview.txt
 create mode 100644 arch/arm/boot/dts/stih415-clock.dtsi
 create mode 100644 arch/arm/boot/dts/stih415-pinctrl.dtsi
 create mode 100644 arch/arm/boot/dts/stih415.dtsi
 create mode 100644 arch/arm/boot/dts/stih415.h
 create mode 100644 arch/arm/boot/dts/stih41x.dtsi
 create mode 100644 arch/arm/boot/dts/stixxxx-pincfg.h
 create mode 100644 arch/arm/configs/stih41x_defconfig
 create mode 100644 arch/arm/include/debug/stixxxx.S
 create mode 100644 arch/arm/mach-stih41x/Kconfig
 create mode 100644 arch/arm/mach-stih41x/Makefile
 create mode 100644 arch/arm/mach-stih41x/board-dt.c
 create mode 100644 arch/arm/mach-stih41x/stih41x.c
 create mode 100644 arch/arm/mach-stih41x/stih41x.h
 create mode 100644 arch/arm/plat-stixxxx/Kconfig
 create mode 100644 arch/arm/plat-stixxxx/Makefile
 create mode 100644 arch/arm/plat-stixxxx/headsmp.S
 create mode 100644 arch/arm/plat-stixxxx/include/plat/hardware.h
 create mode 100644 arch/arm/plat-stixxxx/include/plat/smp.h
 create mode 100644 arch/arm/plat-stixxxx/platsmp.c

diff --git a/Documentation/arm/STiH41x/overview.txt b/Documentation/arm/STiH41x/overview.txt
new file mode 100644
index 0000000..2411506
--- /dev/null
+++ b/Documentation/arm/STiH41x/overview.txt
@@ -0,0 +1,39 @@
+			STiH41x ARM Linux Overview
+			==========================
+
+Introduction
+------------
+
+  The ST Microelectronics Multimedia and Application Processors range of
+  CortexA9 System-on-Chip are supported by the 'STixxxx' platform of
+  ARM Linux. Currently STiH415, STiH416 SOCs are supported with both
+  B2000 and B2020 Reference boards.
+
+
+  configuration
+  -------------
+
+  A generic configuration is provided for both STiH415/416, and can be used as the
+  default by
+	make stih41x_defconfig
+
+  Layout
+  ------
+  The common files for multiple machine families (STiH415, STiH416, and STiG125)
+  are located in the platform code contained in arch/arm/plat-stixxxx
+  with headers in plat/.
+	- common files to support Stixxxx SoCs which includes things
+	like platsmp.
+
+  Each machine series have a directory with name arch/arm/mach-sti followed by
+  series name. Like mach-stih41x to support stih415 and stih416.
+
+  There is a generic board board-dt.c in each mach folder which support
+  Flattened Device Tree, which means, It works with any compatible board with
+  Device Trees.
+
+
+  Document Author
+  ---------------
+
+  Srinivas Kandagatla <srinivas.kandagatla@st.com>, (c) 2013 ST Microelectronics
diff --git a/Documentation/arm/STiH41x/stih415-overview.txt b/Documentation/arm/STiH41x/stih415-overview.txt
new file mode 100644
index 0000000..1c264b7
--- /dev/null
+++ b/Documentation/arm/STiH41x/stih415-overview.txt
@@ -0,0 +1,12 @@
+			STiH415 Overview
+			================
+
+Introduction
+------------
+
+    The STiH415 is the next generation of HD, AVC set-top box processors
+    for satellite, cable, terrestrial and IP-STB markets.
+
+    Features
+    - ARM Cortex-A9 1.0 GHz, dual-core CPU
+    - SATA2×2,USB 2.0×3, PCIe, Gbit Ethernet MAC×2
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c8c524e..b960c7d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1106,6 +1106,9 @@ source "arch/arm/mach-socfpga/Kconfig"
 
 source "arch/arm/plat-spear/Kconfig"
 
+source "arch/arm/mach-stih41x/Kconfig"
+source "arch/arm/plat-stixxxx/Kconfig"
+
 source "arch/arm/mach-s3c24xx/Kconfig"
 
 if ARCH_S3C64XX
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 9b31f43..42a5193 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -447,6 +447,16 @@ choice
 		  This option selects UART0 on VIA/Wondermedia System-on-a-chip
 		  devices, including VT8500, WM8505, WM8650 and WM8850.
 
+	config DEBUG_STIH41X_UART
+		depends on ARCH_STIH41X
+		bool "Use StiH415/416 ASC for low-level debug"
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on StiH415/416 based platforms like B2000, B2020.
+		  It support UART2 and SBC_UART1.
+
+		  If unsure, say N.
+
 	config DEBUG_LL_UART_NONE
 		bool "No low-level debugging UART"
 		depends on !ARCH_MULTIPLATFORM
@@ -578,6 +588,33 @@ choice
 
 endchoice
 
+choice
+	prompt "Low-level debug console UART"
+	depends on DEBUG_LL && DEBUG_STIH41X_UART
+
+	config STIH41X_DEBUG_ASC2
+		bool "ASC2 UART"
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on STiH415/416 based platforms like b2000, which has
+		  default UART wired up to ASC2.
+
+		  If unsure, say N.
+
+	config STIH41X_DEBUG_SBC_ASC1
+		bool "SBC ASC1 UART"
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on STiH415/416 based platforms like b2020. which has
+		  default UART wired up to SBC ASC1.
+
+		  If unsure, say N.
+
+endchoice
+
+
+
+
 config DEBUG_LL_INCLUDE
 	string
 	default "debug/icedcc.S" if DEBUG_ICEDCC
@@ -600,6 +637,7 @@ config DEBUG_LL_INCLUDE
 	default "debug/vt8500.S" if DEBUG_VT8500_UART0
 	default "debug/tegra.S" if DEBUG_TEGRA_UART
 	default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
+	default "debug/stixxxx.S" if DEBUG_STIH41X_UART
 	default "mach/debug-macro.S"
 
 config EARLY_PRINTK
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ee4605f..2bb7e7d 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -194,6 +194,7 @@ machine-$(CONFIG_ARCH_SOCFPGA)		+= socfpga
 machine-$(CONFIG_ARCH_SPEAR13XX)	+= spear13xx
 machine-$(CONFIG_ARCH_SPEAR3XX)		+= spear3xx
 machine-$(CONFIG_MACH_SPEAR600)		+= spear6xx
+machine-$(CONFIG_ARCH_STIH41X)		+= stih41x
 machine-$(CONFIG_ARCH_VIRT)		+= virt
 machine-$(CONFIG_ARCH_ZYNQ)		+= zynq
 machine-$(CONFIG_ARCH_SUNXI)		+= sunxi
@@ -207,6 +208,7 @@ plat-$(CONFIG_PLAT_ORION)	+= orion
 plat-$(CONFIG_PLAT_PXA)		+= pxa
 plat-$(CONFIG_PLAT_S3C24XX)	+= samsung
 plat-$(CONFIG_PLAT_S5P)		+= samsung
+plat-$(CONFIG_PLAT_STIXXXX)	+= stixxxx
 plat-$(CONFIG_PLAT_SPEAR)	+= spear
 plat-$(CONFIG_PLAT_VERSATILE)	+= versatile
 
diff --git a/arch/arm/boot/dts/stih415-clock.dtsi b/arch/arm/boot/dts/stih415-clock.dtsi
new file mode 100644
index 0000000..174c799
--- /dev/null
+++ b/arch/arm/boot/dts/stih415-clock.dtsi
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited
+ *
+ * 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.
+ */
+/ {
+	clocks {
+		/*
+		 * Fixed 30MHz oscillator input to SoC
+		 */
+		CLK_SYSIN: CLK_SYSIN {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <30000000>;
+		};
+
+		/*
+		 * ARM Peripheral clock for timers
+		 */
+		arm_periph_clk: arm_periph_clk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <500000000>;
+		};
+
+		/*
+		 * Bootloader initialized system infrastructure clock for
+		 * serial devices.
+		 */
+		CLKS_ICN_REG_0: CLKS_ICN_REG_0 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <100000000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stih415-pinctrl.dtsi b/arch/arm/boot/dts/stih415-pinctrl.dtsi
new file mode 100644
index 0000000..0f8c770
--- /dev/null
+++ b/arch/arm/boot/dts/stih415-pinctrl.dtsi
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stih415.h"
+#include "stixxxx-pincfg.h"
+/ {
+
+	aliases {
+		gpio0	= &PIO0;
+		gpio1	= &PIO1;
+		gpio2	= &PIO2;
+		gpio3	= &PIO3;
+		gpio4	= &PIO4;
+		gpio5	= &PIO5;
+		gpio6	= &PIO6;
+		gpio7	= &PIO7;
+		gpio8	= &PIO8;
+		gpio9	= &PIO9;
+		gpio10	= &PIO10;
+		gpio11	= &PIO11;
+		gpio12	= &PIO12;
+		gpio13	= &PIO13;
+		gpio14	= &PIO14;
+		gpio15	= &PIO15;
+		gpio16	= &PIO16;
+		gpio17	= &PIO17;
+		gpio18	= &PIO18;
+		gpio19	= &PIO100;
+		gpio20	= &PIO101;
+		gpio21	= &PIO102;
+		gpio22	= &PIO103;
+		gpio23	= &PIO104;
+		gpio24	= &PIO105;
+		gpio25	= &PIO106;
+		gpio26	= &PIO107;
+	};
+
+
+	soc {
+		pin-controller {
+			#address-cells	= <1>;
+			#size-cells	= <1>;
+			#retime-delay-cells	= <4>;
+			compatible	= "st,stixxxx-pinctrl", "simple-bus";
+			st,retime-offset	= <&pio_retime_offset>;
+			st,retime-in-delay	= <0 500 1000 1500>;
+			st,retime-out-delay	= <0 1000 2000 3000>;
+			ranges;
+
+			PIO0: pinctrl@fe610000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe610000 0x100>;
+				st,bank-name	= "PIO0";
+				st,alt-control	= <&SYSCFG_SBC(0) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(5) 0 7>;
+				st,pu-control	= <&SYSCFG_SBC(7) 0 7>;
+				st,od-control	= <&SYSCFG_SBC(9) 0 7>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_SBC(16) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(17) 0 31>;
+			};
+			PIO1: pinctrl@fe611000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe611000 0x100>;
+				st,bank-name	= "PIO1";
+				st,alt-control	= <&SYSCFG_SBC(1) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(5) 8 15>;
+				st,pu-control	= <&SYSCFG_SBC(7) 8 15>;
+				st,od-control	= <&SYSCFG_SBC(9) 8 15>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_SBC(18) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(19) 0 31>;
+			};
+			PIO2: pinctrl@fe612000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe612000 0x100>;
+				st,bank-name	= "PIO2";
+				st,alt-control	= <&SYSCFG_SBC(2) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(5) 16 23>;
+				st,pu-control	= <&SYSCFG_SBC(7) 16 23>;
+				st,od-control	= <&SYSCFG_SBC(9) 16 23>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_SBC(20) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(21) 0 31>;
+			};
+			PIO3: pinctrl@fe613000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe613000 0x100>;
+				st,bank-name	= "PIO3";
+				st,alt-control	= <&SYSCFG_SBC(3) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(5) 24 31>;
+				st,pu-control	= <&SYSCFG_SBC(7) 24 31>;
+				st,od-control	= <&SYSCFG_SBC(9) 24 31>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_SBC(22) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(23) 0 31>;
+
+			};
+			PIO4: pinctrl@fe614000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe614000 0x100>;
+				st,bank-name	= "PIO4";
+				st,alt-control	= <&SYSCFG_SBC(4) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(6) 0 7>;
+				st,pu-control	= <&SYSCFG_SBC(8) 0 7>;
+				st,od-control	= <&SYSCFG_SBC(10) 0 7>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_SBC(24) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(25) 0 31>;
+
+			};
+			 /* 5-12:pinctrl_FRONT */
+			PIO5: pinctrl@fee00000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfee00000 0x100>;
+				st,bank-name	= "PIO5";
+				st,alt-control	= <&SYSCFG_FRONT(100) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(108) 0 7>;
+				st,pu-control	= <&SYSCFG_FRONT(110) 0 7>;
+				st,od-control	= <&SYSCFG_FRONT(112) 0 7>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_FRONT(116) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(117) 0 31>;
+			};
+			PIO6: pinctrl@fee01000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfee01000 0x100>;
+				st,bank-name	= "PIO6";
+				st,alt-control	= <&SYSCFG_FRONT(101) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(108) 8 15>;
+				st,pu-control	= <&SYSCFG_FRONT(110) 8 15>;
+				st,od-control	= <&SYSCFG_FRONT(112) 8 15>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_FRONT(118) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(119) 0 31>;
+			};
+
+			PIO7: pinctrl@fee02000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfee02000 0x100>;
+				st,bank-name	= "PIO7";
+				st,alt-control	= <&SYSCFG_FRONT(102) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(108) 16 23>;
+				st,pu-control	= <&SYSCFG_FRONT(110) 16 23>;
+				st,od-control	= <&SYSCFG_FRONT(112) 16 23>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_FRONT(120) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(121) 0 31>;
+			};
+			PIO8: pinctrl@fee03000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfee03000 0x100>;
+				st,bank-name	= "PIO8";
+				st,alt-control	= <&SYSCFG_FRONT(103) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(108) 24 31>;
+				st,pu-control	= <&SYSCFG_FRONT(110) 24 31>;
+				st,od-control	= <&SYSCFG_FRONT(112) 24 31>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_FRONT(122) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(123) 0 31>;
+			};
+			PIO9: pinctrl@fee04000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfee04000 0x100>;
+				st,bank-name	= "PIO9";
+				st,alt-control	= <&SYSCFG_FRONT(104) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(109) 0 7>;
+				st,pu-control	= <&SYSCFG_FRONT(111) 0 7>;
+				st,od-control	= <&SYSCFG_FRONT(113) 0 7>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_FRONT(124) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(125) 0 31>;
+			};
+			PIO10: pinctrl@fee05000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfee05000 0x100>;
+				st,bank-name	= "PIO10";
+				st,alt-control	= <&SYSCFG_FRONT(105) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(109) 8 15>;
+				st,pu-control	= <&SYSCFG_FRONT(111) 8 15>;
+				st,od-control	= <&SYSCFG_FRONT(113) 8 15>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_FRONT(126) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(127) 0 31>;
+			};
+			PIO11: pinctrl@fee06000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfee06000 0x100>;
+				st,bank-name	= "PIO11";
+				st,alt-control	= <&SYSCFG_FRONT(106) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(109) 16 23>;
+				st,pu-control	= <&SYSCFG_FRONT(111) 16 23>;
+				st,od-control	= <&SYSCFG_FRONT(113) 16 23>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_FRONT(128) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(129) 0 31>;
+			};
+			PIO12: pinctrl@fee07000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfee07000 0x100>;
+				st,bank-name	= "PIO12";
+				st,alt-control	= <&SYSCFG_FRONT(107) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(109) 24 31>;
+				st,pu-control	= <&SYSCFG_FRONT(111) 24 31>;
+				st,od-control	= <&SYSCFG_FRONT(113) 24 31>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_FRONT(130) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(131) 0 31>;
+			};
+			 /* 13-18:pinctrl_REAR */
+			PIO13: pinctrl@fe820000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe820000 0x100>;
+				st,bank-name	= "PIO13";
+				st,alt-control	= <&SYSCFG_REAR(300) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(306) 0 7>;
+				st,pu-control	= <&SYSCFG_REAR(308) 0 7>;
+				st,od-control	= <&SYSCFG_REAR(310) 0 7>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_REAR(338) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(339) 0 31>;
+			};
+			PIO14: pinctrl@fe821000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe821000 0x100>;
+				st,bank-name	= "PIO14";
+				st,alt-control	= <&SYSCFG_REAR(301) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(306) 8 15>;
+				st,pu-control	= <&SYSCFG_REAR(308) 8 15>;
+				st,od-control	= <&SYSCFG_REAR(310) 8 15>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_REAR(340) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(341) 0 31>;
+			};
+			PIO15: pinctrl@fe822000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe822000 0x100>;
+				st,bank-name	= "PIO15";
+				st,alt-control	= <&SYSCFG_REAR(302) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(306) 16 23>;
+				st,pu-control	= <&SYSCFG_REAR(308) 16 23>;
+				st,od-control	= <&SYSCFG_REAR(310) 16 23>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_REAR(342) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(343) 0 31>;
+			};
+			PIO16: pinctrl@fe823000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe823000 0x100>;
+				st,bank-name	= "PIO16";
+				st,alt-control	= <&SYSCFG_REAR(303) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(306) 24 31>;
+				st,pu-control	= <&SYSCFG_REAR(308) 24 31>;
+				st,od-control	= <&SYSCFG_REAR(310) 24 31>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_REAR(344) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(345) 0 31>;
+
+			};
+			PIO17: pinctrl@fe824000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe824000 0x100>;
+				st,bank-name	= "PIO17";
+				st,alt-control	= <&SYSCFG_REAR(304) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(307) 0 7>;
+				st,pu-control	= <&SYSCFG_REAR(309) 0 7>;
+				st,od-control	= <&SYSCFG_REAR(311) 0 7>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_REAR(346) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(347) 0 31>;
+
+			};
+			PIO18: pinctrl@fe825000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfe825000 0x100>;
+				st,bank-name	= "PIO18";
+				st,alt-control	= <&SYSCFG_REAR(305) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(307) 8 15>;
+				st,pu-control	= <&SYSCFG_REAR(309) 8 15>;
+				st,od-control	= <&SYSCFG_REAR(311) 8 15>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_REAR(348) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(349) 0 31>;
+
+			};
+			 /* MPE */
+			 /* 100-102:pinctrl_RIGHT (aka MPE_pinctrl) */
+			PIO100: pinctrl@fd6b0000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfd6b0000 0x100>;
+				st,bank-name	= "PIO100";
+				st,alt-control	= <&SYSCFG_LEFT(400) 0 31>;
+				st,oe-control	= <&SYSCFG_LEFT(403) 0 7>;
+				st,pu-control	= <&SYSCFG_LEFT(404) 0 7>;
+				st,od-control	= <&SYSCFG_LEFT(405) 0 7>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_LEFT(406) 0 31>;
+				st,retime-control1	= <&SYSCFG_LEFT(407) 0 31>;
+			};
+			PIO101: pinctrl@fd6b1000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfd6b1000 0x100>;
+				st,bank-name	= "PIO101";
+				st,alt-control	= <&SYSCFG_LEFT(401) 0 31>;
+				st,oe-control	= <&SYSCFG_LEFT(403) 8 15>;
+				st,pu-control	= <&SYSCFG_LEFT(404) 8 15>;
+				st,od-control	= <&SYSCFG_LEFT(405) 8 15>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_LEFT(408) 0 31>;
+				st,retime-control1	= <&SYSCFG_LEFT(409) 0 31>;
+
+			};
+			PIO102: pinctrl@fd6b2000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfd6b2000 0x100>;
+				st,bank-name	= "PIO102";
+				st,alt-control	= <&SYSCFG_LEFT(402) 0 31>;
+				st,oe-control	= <&SYSCFG_LEFT(403) 16 23>;
+				st,pu-control	= <&SYSCFG_LEFT(404) 16 23>;
+				st,od-control	= <&SYSCFG_LEFT(405) 16 23>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_LEFT(410) 0 31>;
+				st,retime-control1	= <&SYSCFG_LEFT(411) 0 31>;
+
+			};
+			 /* 103-107:pinctrl_LEFT (aka pinctrl_1_MPE) */
+			PIO103: pinctrl@fd330000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfd330000 0x100>;
+				st,bank-name	= "PIO103";
+				st,alt-control	= <&SYSCFG_RIGHT(500) 0 31>;
+				st,oe-control	= <&SYSCFG_RIGHT(505) 0 7>;
+				st,pu-control	= <&SYSCFG_RIGHT(507) 0 7>;
+				st,od-control	= <&SYSCFG_RIGHT(509) 0 7>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_RIGHT(511) 0 31>;
+				st,retime-control1	= <&SYSCFG_RIGHT(512) 0 31>;
+			};
+			PIO104: pinctrl@fd331000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfd331000 0x100>;
+				st,bank-name	= "PIO104";
+				st,alt-control	= <&SYSCFG_RIGHT(501) 0 31>;
+				st,oe-control	= <&SYSCFG_RIGHT(505) 8 15>;
+				st,pu-control	= <&SYSCFG_RIGHT(507) 8 15>;
+				st,od-control	= <&SYSCFG_RIGHT(509) 8 15>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_RIGHT(513) 0 31>;
+				st,retime-control1	= <&SYSCFG_RIGHT(514) 0 31>;
+			};
+			PIO105: pinctrl@fd332000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfd332000 0x100>;
+				st,bank-name	= "PIO105";
+				st,alt-control	= <&SYSCFG_RIGHT(502) 0 31>;
+				st,oe-control	= <&SYSCFG_RIGHT(505) 16 23>;
+				st,pu-control	= <&SYSCFG_RIGHT(507) 16 23>;
+				st,od-control	= <&SYSCFG_RIGHT(509) 16 23>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_RIGHT(515) 0 31>;
+				st,retime-control1	= <&SYSCFG_RIGHT(516) 0 31>;
+			};
+			PIO106: pinctrl@fd333000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfd333000 0x100>;
+				st,bank-name	= "PIO106";
+				st,alt-control	= <&SYSCFG_RIGHT(503) 0 31>;
+				st,oe-control	= <&SYSCFG_RIGHT(505) 24 31>;
+				st,pu-control	= <&SYSCFG_RIGHT(507) 24 31>;
+				st,od-control	= <&SYSCFG_RIGHT(509) 24 31>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_RIGHT(517) 0 31>;
+				st,retime-control1	= <&SYSCFG_RIGHT(518) 0 31>;
+			};
+			PIO107: pinctrl@fd334000 {
+				gpio-controller;
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				reg	= <0xfd334000 0x100>;
+				st,bank-name	= "PIO107";
+				st,alt-control	= <&SYSCFG_RIGHT(504) 0 31>;
+				st,oe-control	= <&SYSCFG_RIGHT(506) 0 7>;
+				st,pu-control	= <&SYSCFG_RIGHT(508) 0 7>;
+				st,od-control	= <&SYSCFG_RIGHT(510) 0 7>;
+				st,retime-style	= "packed";
+				st,retime-control0	= <&SYSCFG_RIGHT(519) 0 31>;
+				st,retime-control1	= <&SYSCFG_RIGHT(520) 0 31>;
+			};
+
+			uart2 {
+				pinctrl_uart2: uart2-0 {
+					st,function = <ALT2>;
+					st,pins {
+						tx	= <&PIO17 4 OUT>;
+						rx	= <&PIO17 5 IN>;
+					};
+				};
+			};
+
+			sbc_uart1 {
+				pinctrl_sbc_uart1: sbc_uart1 {
+					st,function = <ALT3>;
+					st,pins {
+						tx	= <&PIO2 6 OUT>;
+						rx	= <&PIO2 7 IN>;
+					};
+				};
+			};
+
+		};
+
+		pio_retime_offset: pio-retime-offset {
+			clk1notclk0	= <0>;
+			delay-lsb	= <2>;
+			delay-msb	= <3>;
+			invertclk	= <4>;
+			retime		= <5>;
+			clknotdata	= <6>;
+			double-edge	= <7>;
+		};
+
+	};
+};
diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi
new file mode 100644
index 0000000..b881d22
--- /dev/null
+++ b/arch/arm/boot/dts/stih415.dtsi
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stih41x.dtsi"
+#include "stih415-clock.dtsi"
+#include "stih415-pinctrl.dtsi"
+/ {
+
+	L2: cache-controller {
+		compatible = "arm,pl310-cache";
+		reg = <0xfffe2000 0x1000>;
+		arm,data-latency = <3 2 2>;
+		arm,tag-latency = <1 1 1>;
+		cache-unified;
+		cache-level = <2>;
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <3>;
+		interrupt-parent = <&intc>;
+		ranges;
+		compatible	= "simple-bus";
+
+		syscfg_sbc: syscon@fe600000{
+			compatible      = "syscon";
+			reg		= <0xfe600000 0xb4>;
+			syscon-name	= "SYSCFG_SBC";
+		};
+
+		syscfg_front: syscon@fee10000{
+			compatible      = "syscon";
+			reg		= <0xfee10000 0x194>;
+			syscon-name	= "SYSCFG_FRONT";
+		};
+
+		syscfg_rear: syscon@fe830000{
+			compatible      = "syscon";
+			reg		= <0xfe830000 0x190>;
+			syscon-name	= "SYSCFG_REAR";
+		};
+
+		syscfg_left: syscon@fd690000{
+			compatible      = "syscon";
+			reg		= <0xfd690000 0x78>;
+			syscon-name	= "SYSCFG_LEFT";
+		};
+
+		syscfg_right: syscon@fd320000{
+			compatible      = "syscon";
+			reg		= <0xfd320000 0x180>;
+			syscon-name	= "SYSCFG_RIGHT";
+		};
+
+		syscfg_system: syscon@fdde0000  {
+			compatible      = "syscon";
+			reg		= <0xfdde0000 0x15c>;
+			syscon-name	= "SYSCFG_SYSTEM";
+		};
+
+		syscfg_lpm: syscon@fe4b5100{
+			compatible      = "syscon";
+			reg		= <0xfe4b5100 0x08>;
+			syscon-name	= "LPM_CFG_REGS";
+		};
+
+		uart2: uart@fed32000 {
+			compatible	= "st,asc";
+			status 		= "disabled";
+			reg		= <0xfed32000 0x2c>;
+			interrupts	= <0 197 0>;
+			pinctrl-names 	= "default";
+			pinctrl-0 	= <&pinctrl_uart2>;
+			clocks		= <&CLKS_ICN_REG_0>;
+		};
+
+		/* SBC comms block ASCs in SASG1 */
+		sbc_uart1: uart@fe531000 {
+			compatible	= "st,asc";
+			status 		= "disabled";
+			reg		= <0xfe531000 0x2c>;
+			interrupts	= <0 210 0>;
+			clocks		= <&CLK_SYSIN>;
+			pinctrl-names 	= "default";
+			pinctrl-0	= <&pinctrl_sbc_uart1>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stih415.h b/arch/arm/boot/dts/stih415.h
new file mode 100644
index 0000000..fc46ecc
--- /dev/null
+++ b/arch/arm/boot/dts/stih415.h
@@ -0,0 +1,20 @@
+#ifndef __STIH415_H_
+#define __STIH415_H_
+
+#define CONFIG_SBC(num)		(num)
+#define CONFIG_FRONT(num)	(num - 100)
+#define CONFIG_REAR(num)	(num - 300)
+#define CONFIG_LEFT(num)	(num - 400)
+#define CONFIG_RIGHT(num)	(num - 500)
+#define CONFIG_SYSTEM(num)	(num - 600)
+#define CONFIG_LPM(num)		(num)
+
+#define SYSCFG_SBC(num)		syscfg_sbc CONFIG_SBC(num)
+#define SYSCFG_FRONT(num)	syscfg_front CONFIG_FRONT(num)
+#define SYSCFG_REAR(num)	syscfg_rear CONFIG_REAR(num)
+#define SYSCFG_LEFT(num)	syscfg_left CONFIG_LEFT(num)
+#define SYSCFG_RIGHT(num)	syscfg_right CONFIG_RIGHT(num)
+#define SYSCFG_SYSTEM(num)	syscfg_system CONFIG_SYSTEM(num)
+#define SYSCFG_LPM(num)		syscfg_lpm CONFIG_LPM(num)
+
+#endif /* __STIH415_H_ */
diff --git a/arch/arm/boot/dts/stih41x.dtsi b/arch/arm/boot/dts/stih41x.dtsi
new file mode 100644
index 0000000..a7f0fa4
--- /dev/null
+++ b/arch/arm/boot/dts/stih41x.dtsi
@@ -0,0 +1,30 @@
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		cpu@0 {
+			compatible = "arm,cortex-a9";
+		};
+		cpu@1 {
+			compatible = "arm,cortex-a9";
+		};
+	};
+
+	intc: interrupt-controller@fffe1000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		interrupt-controller;
+		reg = <0xfffe1000 0x1000>,
+		      <0xfffe0100 0x100>;
+	};
+
+	timer@fffe0200 {
+		#interrupt-cells = <3>;
+		interrupt-parent = <&intc>;
+		compatible = "arm,cortex-a9-global-timer";
+		reg = <0xfffe0200 0x100>;
+		interrupts = <1 11 0x04>;
+		clocks = <&arm_periph_clk>;
+	};
+};
diff --git a/arch/arm/boot/dts/stixxxx-pincfg.h b/arch/arm/boot/dts/stixxxx-pincfg.h
new file mode 100644
index 0000000..5398ff2
--- /dev/null
+++ b/arch/arm/boot/dts/stixxxx-pincfg.h
@@ -0,0 +1,95 @@
+#ifndef _ST_PINCFG_H_
+#define _ST_PINCFG_H
+
+/* Alternate functions */
+#define ALT1	1
+#define ALT2	2
+#define ALT3	3
+#define ALT4	4
+#define ALT5	5
+#define ALT6	6
+#define ALT7	7
+
+/* Output enable */
+#define OE_MASK			0x1
+#define OE_SHIFT		27
+#define OE			(1 << OE_SHIFT)
+
+/* Pull Up */
+#define PU_MASK			0x1
+#define PU_SHIFT		26
+#define PU			(1 << PU_SHIFT)
+
+/* Open Drain */
+#define OD_MASK			0x1
+#define OD_SHIFT		25
+#define OD			(1 << OD_SHIFT)
+
+#define RT_MASK			0x1
+#define RT_SHIFT		23
+#define RT			(1 << RT_SHIFT)
+
+#define INVERTCLK_MASK		0x1
+#define INVERTCLK_SHIFT		22
+#define INVERTCLK		(1 << INVERTCLK_SHIFT)
+
+#define CLKNOTDATA_MASK		0x1
+#define CLKNOTDATA_SHIFT	21
+#define CLKNOTDATA		(1 << CLKNOTDATA_SHIFT)
+
+#define DOUBLE_EDGE_MASK	 0x1
+#define DOUBLE_EDGE_SHIFT	 20
+#define DOUBLE_EDGE		(1 << DOUBLE_EDGE_SHIFT)
+
+#define CLK_MASK		0x3
+#define CLK_SHIFT		18
+#define CLK_A			(0 << CLK_SHIFT)
+#define CLK_B			(1 << CLK_SHIFT)
+#define CLK_C			(2 << CLK_SHIFT)
+#define CLK_D			(3 << CLK_SHIFT)
+
+/* User-frendly defines for Pin Direction */
+		/* oe = 0, pu = 0, od = 0 */
+#define IN			(0)
+		/* oe = 0, pu = 1, od = 0 */
+#define IN_PU			(PU)
+		/* oe = 1, pu = 0, od = 0 */
+#define OUT			(OE)
+		/* oe = 1, pu = 0, od = 1 */
+#define BIDIR			(OE | OD)
+		/* oe = 1, pu = 1, od = 1 */
+#define BIDIR_PU		(OE | PU | OD)
+
+/* RETIME_TYPE */
+/*
+ * B Mode
+ * Bypass retime with optional delay parameter
+ */
+#define BYPASS		(0)
+/*
+ * R0, R1, R0D, R1D modes
+ * single-edge data non inverted clock, retime data with clk
+ */
+#define SE_NICLK_IO	(RT)
+/*
+ * RIV0, RIV1, RIV0D, RIV1D modes
+ * single-edge data inverted clock, retime data with clk
+ */
+#define SE_ICLK_IO	(RT | INVERTCLK)
+/*
+ * R0E, R1E, R0ED, R1ED modes
+ * double-edge data, retime data with clk
+ */
+#define DE_IO		(RT | DOUBLE_EDGE)
+/*
+ * CIV0, CIV1 modes with inverted clock
+ * Retiming the clk pins will park clock & reduce the noise within the core.
+ */
+#define ICLK		(RT | CLKNOTDATA | INVERTCLK)
+/*
+ * CLK0, CLK1 modes with non-inverted clock
+ * Retiming the clk pins will park clock & reduce the noise within the core.
+ */
+#define NICLK		(RT | CLKNOTDATA)
+#endif /* _ST_PINCFG_H */
+
diff --git a/arch/arm/configs/stih41x_defconfig b/arch/arm/configs/stih41x_defconfig
new file mode 100644
index 0000000..dd9268b
--- /dev/null
+++ b/arch/arm/configs/stih41x_defconfig
@@ -0,0 +1,94 @@
+CONFIG_LOCALVERSION="-STiH41x"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_NAMESPACES=y
+CONFIG_RELAY=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_ARCH_STIH41X=y
+CONFIG_SOC_STIH415=y
+# CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set
+# CONFIG_SWP_EMULATE is not set
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_PL310_ERRATA_753970=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_SMP=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_KSM=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_DEBUG_DEVRES=y
+# CONFIG_BLK_DEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HWMON is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_COMMON_CLK_DEBUG=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_XFS_FS=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_NLS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_UNUSED_SYMBOLS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_FTRACE is not set
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_STIH41X_UART=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_SECURITYFS=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_SEQIV=y
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_T10DIF=y
diff --git a/arch/arm/include/debug/stixxxx.S b/arch/arm/include/debug/stixxxx.S
new file mode 100644
index 0000000..7bc02a7
--- /dev/null
+++ b/arch/arm/include/debug/stixxxx.S
@@ -0,0 +1,61 @@
+/*
+ * arch/arm/include/debug/stixxxx.S
+ *
+ * Debugging macro include header
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ *
+ * 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.
+ */
+
+#define STIH41X_COMMS_BASE              0xfed00000
+#define STIH41X_ASC2_BASE               (STIH41X_COMMS_BASE+0x32000)
+
+#define STIH41X_SBC_LPM_BASE            0xfe400000
+#define STIH41X_SBC_COMMS_BASE          (STIH41X_SBC_LPM_BASE + 0x100000)
+#define STIH41X_SBC_ASC1_BASE           (STIH41X_SBC_COMMS_BASE + 0x31000)
+
+
+#define VIRT_ADDRESS(x)		(x - 0x1000000)
+
+#if IS_ENABLED(CONFIG_STIH41X_DEBUG_ASC2)
+#define DEBUG_LL_UART_BASE	STIH41X_ASC2_BASE
+#endif
+
+#if IS_ENABLED(CONFIG_STIH41X_DEBUG_SBC_ASC1)
+#define DEBUG_LL_UART_BASE	STIH41X_SBC_ASC1_BASE
+#endif
+
+#ifndef DEBUG_LL_UART_BASE
+#error "DEBUG UART is not Configured"
+#endif
+
+#define ASC_TX_BUF_OFF  0x04
+#define ASC_CTRL_OFF    0x0c
+#define ASC_STA_OFF     0x14
+
+#define ASC_STA_TX_FULL         (1<<9)
+#define ASC_STA_TX_EMPTY        (1<<1)
+
+
+		.macro	addruart, rp, rv, tmp
+		ldr	\rp,      =DEBUG_LL_UART_BASE	@ physical base
+		ldr	\rv,      =VIRT_ADDRESS(DEBUG_LL_UART_BASE) @ virt base
+		.endm
+
+                .macro  senduart,rd,rx
+                strb    \rd, [\rx, #ASC_TX_BUF_OFF]
+                .endm
+
+                .macro  waituart,rd,rx
+1001:           ldr     \rd, [\rx, #ASC_STA_OFF]
+                tst     \rd, #ASC_STA_TX_FULL
+                bne     1001b
+                .endm
+
+                .macro  busyuart,rd,rx
+1001:           ldr     \rd, [\rx, #ASC_STA_OFF]
+                tst     \rd, #ASC_STA_TX_EMPTY
+                beq     1001b
+                .endm
diff --git a/arch/arm/mach-stih41x/Kconfig b/arch/arm/mach-stih41x/Kconfig
new file mode 100644
index 0000000..9c40540
--- /dev/null
+++ b/arch/arm/mach-stih41x/Kconfig
@@ -0,0 +1,35 @@
+config ARCH_STIH41X
+	bool "STMicroelectronics STiH41x SOCs with Flattened Device Tree" if ARCH_MULTI_V7
+	select GENERIC_CLOCKEVENTS
+	select CLKDEV_LOOKUP
+	select ARM_GIC
+	select HAVE_ARM_GT
+	select PINCTRL
+	select PINCTRL_STIXXXX
+	select MIGHT_HAVE_CACHE_L2X0
+	select HAVE_SMP
+	select GPIOLIB
+	select MACH_STIH41X_GENERIC
+	help
+	  Include support for STiH41x SOCs like STiH415/416 using the device tree
+	  for discovery
+	  More information at Documentation/arm/STiH41x and
+	  at Documentation/devicetree
+
+config MACH_STIH41X_GENERIC
+	bool
+
+if ARCH_STIH41X
+menu "STMicroelectronics Consumer Electronics SOCs"
+
+config SOC_STIH415
+	bool "STiH415 STMicroelectronics Consumer Electronics family"
+	select PLAT_STIXXXX
+	help
+	  This enables support for STMicroelectronics Digital Consumer
+	  Electronics family StiH415 parts, primarily targetted at set-top-box
+	  and other digital audio/video applications using Flattned Device
+	  Trees.
+
+endmenu
+endif
diff --git a/arch/arm/mach-stih41x/Makefile b/arch/arm/mach-stih41x/Makefile
new file mode 100644
index 0000000..91d6863
--- /dev/null
+++ b/arch/arm/mach-stih41x/Makefile
@@ -0,0 +1,4 @@
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
+	-I$(srctree)/arch/arm/plat-stixxxx/include
+obj-y		 			:= stih41x.o
+obj-$(CONFIG_MACH_STIH41X_GENERIC) 	+= board-dt.o
diff --git a/arch/arm/mach-stih41x/board-dt.c b/arch/arm/mach-stih41x/board-dt.c
new file mode 100644
index 0000000..c51e2c9
--- /dev/null
+++ b/arch/arm/mach-stih41x/board-dt.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author(s): Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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.
+ */
+
+#include <linux/of_platform.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
+
+#include <asm/mach/arch.h>
+
+#include <plat/smp.h>
+#include <plat/hardware.h>
+
+#include "stih41x.h"
+
+static void __init stih41x_timer_init(void)
+{
+	of_clk_init(NULL);
+	clocksource_of_init();
+	stih41x_l2x0_init();
+}
+
+/*
+ * A basic implementation of irq_set_wake that ensures wakeup source
+ * interrupts are not disabled during PM_SUSPEND_FREEZE.
+ */
+static int stih41x_set_wake(struct irq_data *d, unsigned int on)
+{
+	struct irq_desc *desc = irq_to_desc(d->irq);
+
+	if (on) {
+		if (desc->action)
+			desc->action->flags |= IRQF_NO_SUSPEND;
+	} else {
+		if (desc->action)
+			desc->action->flags &= ~IRQF_NO_SUSPEND;
+	}
+	return 0;
+}
+
+static void __init stih41x_irq_init(void)
+{
+	gic_arch_extn.irq_set_wake = stih41x_set_wake;
+	gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+	irqchip_init();
+}
+
+void __init stih41x_dt_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+				NULL, NULL);
+	return;
+}
+
+static const char *stih41x_dt_match[] __initdata = {
+	NULL
+};
+
+DT_MACHINE_START(STM, "STiH415 SoC with Flattened Device Tree")
+	.map_io		= stih41x_map_io,
+	.init_time	= stih41x_timer_init,
+	.init_machine	= stih41x_dt_init,
+	.smp		= smp_ops(stixxxx_smp_ops),
+	.init_irq	= stih41x_irq_init,
+	.dt_compat	= stih41x_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-stih41x/stih41x.c b/arch/arm/mach-stih41x/stih41x.c
new file mode 100644
index 0000000..b76cac1
--- /dev/null
+++ b/arch/arm/mach-stih41x/stih41x.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author(s): Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/bug.h>
+
+#include <asm/mach/map.h>
+#include <asm/page.h>
+#include <asm/mach/arch.h>
+
+#include <plat/smp.h>
+#include <plat/hardware.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#define MPE41_SCU_BASE			(0xFFFE0000 + 0x0000)
+
+#define STIH41X_COMMS_BASE              0xFED00000
+#define STIH41X_ASC0_BASE               (STIH41X_COMMS_BASE+0x30000)
+#define STIH41X_ASC1_BASE               (STIH41X_COMMS_BASE+0x31000)
+#define STIH41X_ASC2_BASE               (STIH41X_COMMS_BASE+0x32000)
+#define STIH41X_ASC3_BASE               (STIH41X_COMMS_BASE+0x33000)
+
+#define STIH41X_SBC_LPM_BASE            0xfe400000
+#define STIH41X_SBC_COMMS_BASE          (STIH41X_SBC_LPM_BASE + 0x100000)
+#define STIH41X_SBC_ASC0_BASE           (STIH41X_SBC_COMMS_BASE + 0x30000)
+#define STIH41X_SBC_ASC1_BASE           (STIH41X_SBC_COMMS_BASE + 0x31000)
+
+
+static struct map_desc stih41x_io_desc[] __initdata = {
+#ifdef CONFIG_SMP
+	{
+		.virtual	= IO_ADDRESS(MPE41_SCU_BASE),
+		.pfn		= __phys_to_pfn(MPE41_SCU_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	},
+#endif
+#ifdef CONFIG_STIH41X_DEBUG_ASC2
+	{ /* For DEBUG_LL and Early Prints */
+		.virtual	= IO_ADDRESS(STIH41X_ASC2_BASE),
+		.pfn		= __phys_to_pfn(STIH41X_ASC2_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	},
+#endif
+#ifdef CONFIG_STIH41X_DEBUG_SBC_ASC1
+	{
+		.virtual	= IO_ADDRESS(STIH41X_SBC_ASC1_BASE),
+		.pfn		= __phys_to_pfn(STIH41X_SBC_ASC1_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	},
+#endif
+};
+
+void __init stih41x_map_io(void)
+{
+#ifdef CONFIG_SMP
+	stixxxx_scu_base_addr = ((void __iomem *)IO_ADDRESS(MPE41_SCU_BASE));
+#endif
+	iotable_init(stih41x_io_desc, ARRAY_SIZE(stih41x_io_desc));
+}
+
+void __init stih41x_l2x0_init(void)
+{
+	u32 way_size = 0x4;
+	u32 aux_ctrl;
+
+	aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
+		(0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
+		(0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
+		(way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+
+	l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK);
+}
diff --git a/arch/arm/mach-stih41x/stih41x.h b/arch/arm/mach-stih41x/stih41x.h
new file mode 100644
index 0000000..6c0e90b
--- /dev/null
+++ b/arch/arm/mach-stih41x/stih41x.h
@@ -0,0 +1,7 @@
+#ifndef __STIH41X_H_
+#define __STIH41X_H_
+
+void stih41x_map_io(void);
+void stih41x_l2x0_init(void);
+
+#endif /* __STIH41X_H_ */
diff --git a/arch/arm/plat-stixxxx/Kconfig b/arch/arm/plat-stixxxx/Kconfig
new file mode 100644
index 0000000..ceeda96
--- /dev/null
+++ b/arch/arm/plat-stixxxx/Kconfig
@@ -0,0 +1,2 @@
+config PLAT_STIXXXX
+	bool
diff --git a/arch/arm/plat-stixxxx/Makefile b/arch/arm/plat-stixxxx/Makefile
new file mode 100644
index 0000000..36534a9
--- /dev/null
+++ b/arch/arm/plat-stixxxx/Makefile
@@ -0,0 +1,2 @@
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
+obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
diff --git a/arch/arm/plat-stixxxx/headsmp.S b/arch/arm/plat-stixxxx/headsmp.S
new file mode 100644
index 0000000..3dd5c04
--- /dev/null
+++ b/arch/arm/plat-stixxxx/headsmp.S
@@ -0,0 +1,44 @@
+/*
+ *  arch/arm/plat-stixxxx/headsmp.S
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ *		http://www.st.com
+ *
+ * Cloned from linux/arch/arm/mach-vexpress/headsmp.S
+ *
+ *  Copyright (c) 2003 ARM Limited
+ *  All Rights Reserved
+ *
+ * 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.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+	__INIT
+
+/*
+ * ST specific entry point for secondary CPUs.  This provides
+ * a "holding pen" into which all secondary cores are held until we're
+ * ready for them to initialise.
+ */
+ENTRY(stixxxx_secondary_startup)
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, r0, #15
+	adr	r4, 1f
+	ldmia	r4, {r5, r6}
+	sub	r4, r4, r5
+	add	r6, r6, r4
+pen:	ldr	r7, [r6]
+	cmp	r7, r0
+	bne	pen
+
+	/*
+	 * we've been released from the holding pen: secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
+
+1:	.long	.
+	.long	pen_release
diff --git a/arch/arm/plat-stixxxx/include/plat/hardware.h b/arch/arm/plat-stixxxx/include/plat/hardware.h
new file mode 100644
index 0000000..7a9a804
--- /dev/null
+++ b/arch/arm/plat-stixxxx/include/plat/hardware.h
@@ -0,0 +1,20 @@
+/*
+ *  arch/arm/plat-stixxxx/include/mach/hardware.h
+ *
+ * Copyright (C) 2013 STMicroelectronics Limited.
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ *
+ * 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.
+ */
+
+#ifndef __PLAT_HARDWARE_H
+#define __PLAT_HARDWARE_H
+/*
+ * Statically mapped addresses:
+ *
+ * fc000000 to ffffffff (physical) -> fb000000 to feffffff (virtual)
+ */
+#define IO_ADDRESS(x)		(((x) & 0x03ffffff) + 0xfb000000)
+#endif
diff --git a/arch/arm/plat-stixxxx/include/plat/smp.h b/arch/arm/plat-stixxxx/include/plat/smp.h
new file mode 100644
index 0000000..c3e3d40
--- /dev/null
+++ b/arch/arm/plat-stixxxx/include/plat/smp.h
@@ -0,0 +1,19 @@
+/*
+ *  arch/arm/plat-stixxxx/platsmp.c
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ *		http://www.st.com
+ *
+ * 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.
+ */
+
+#ifndef __PLAT_SMP_H
+#define __PLAT_SMP_H
+
+extern struct smp_operations	stixxxx_smp_ops;
+extern void __iomem *stixxxx_scu_base_addr;
+extern void stixxxx_secondary_startup(void);
+
+#endif
diff --git a/arch/arm/plat-stixxxx/platsmp.c b/arch/arm/plat-stixxxx/platsmp.c
new file mode 100644
index 0000000..256640d
--- /dev/null
+++ b/arch/arm/plat-stixxxx/platsmp.c
@@ -0,0 +1,144 @@
+/*
+ *  arch/arm/plat-stixxxx/platsmp.c
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ *		http://www.st.com
+ *
+ * Cloned from linux/arch/arm/mach-vexpress/platsmp.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * 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.
+ */
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+
+#include <plat/hardware.h>
+#include <plat/smp.h>
+
+
+void __iomem *stixxxx_scu_base_addr;
+
+static void __cpuinit write_pen_release(int val)
+{
+	pen_release = val;
+	smp_wmb();
+	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
+static inline unsigned int get_core_count(void)
+{
+	return scu_get_core_count(stixxxx_scu_base_addr);
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+void __cpuinit stixxxx_secondary_init(unsigned int cpu)
+{
+	trace_hardirqs_off();
+
+	/*
+	 * if any interrupts are already enabled for the primary
+	 * core (e.g. timer irq), then they will not have been enabled
+	 * for us: do so
+	 */
+	gic_secondary_init(0);
+
+	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+int __cpuinit stixxxx_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	/*
+	 * set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * The secondary processor is waiting to be released from
+	 * the holding pen - release it, then wait for it to flag
+	 * that it has been released by resetting pen_release.
+	 *
+	 * Note that "pen_release" is the hardware CPU ID, whereas
+	 * "cpu" is Linux's internal ID.
+	 */
+	write_pen_release(cpu_logical_map(cpu));
+
+	/*
+	 * Send the secondary CPU a soft interrupt, thereby causing
+	 * it to jump to the secondary entrypoint.
+	 */
+	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+	timeout = jiffies + (1 * HZ);
+	while (time_before(jiffies, timeout)) {
+		smp_rmb();
+		if (pen_release == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return pen_release != -1 ? -ENOSYS : 0;
+}
+
+/*
+ * Initialise the CPU possible map early - this describes the CPUs
+ * which may be present or become present in the system.
+ */
+void __init stixxxx_smp_init_cpus(void)
+{
+	unsigned int i, ncores = get_core_count();
+
+	if (ncores > nr_cpu_ids) {
+		pr_warn("STM: %u greater than maximum (%u), clipping\n",
+			ncores, nr_cpu_ids);
+		ncores = nr_cpu_ids;
+	}
+
+	for (i = 0; i < ncores; i++)
+		set_cpu_possible(i, true);
+}
+
+void __init stixxxx_smp_prepare_cpus(unsigned int max_cpus)
+{
+	scu_enable(stixxxx_scu_base_addr);
+}
+
+struct smp_operations __initdata stixxxx_smp_ops = {
+	.smp_init_cpus		= stixxxx_smp_init_cpus,
+	.smp_prepare_cpus	= stixxxx_smp_prepare_cpus,
+	.smp_secondary_init	= stixxxx_secondary_init,
+	.smp_boot_secondary	= stixxxx_boot_secondary,
+};
-- 
1.7.6.5


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

* [RFC 6/8] ARM:stih41x: Add STiH416 SOC support
       [not found] <1368022187-1633-1-git-send-email-srinivas.kandagatla@st.com>
                   ` (2 preceding siblings ...)
  2013-05-08 14:11 ` =?y?q?=5BRFC=205/8=5D=20ARM=3Astih41x=3A=20Add=20STiH415=20SOC=20support?= Srinivas KANDAGATLA
@ 2013-05-08 14:11 ` Srinivas KANDAGATLA
  2013-05-08 14:12 ` [RFC 7/8] ARM:stih41x: Add B2000 board support Srinivas KANDAGATLA
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 14:11 UTC (permalink / raw)
  To: linux, arnd, olof
  Cc: Rob Landley, Grant Likely, Rob Herring, Samuel Ortiz,
	Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Srinivas Kandagatla, Stuart Menefy, Shawn Guo, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown,
	Dong Aisheng, linux-doc, linux-kernel, devicetree-discuss,
	linux-arm-kernel, linux-serial, Stephen Gallimore

From: Srinivas Kandagatla <srinivas.kandagatla@st.com>

The STiH416 is advanced HD AVC processor with 3D graphics acceleration
and 1.2-GHz ARM Cortex-A9 SMP CPU.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
CC: Stephen Gallimore <stephen.gallimore@st.com>
CC: Stuart Menefy <stuart.menefy@st.com>
---
 Documentation/arm/STiH41x/stih416-overview.txt |   12 +
 arch/arm/boot/dts/stih416-clock.dtsi           |   41 ++
 arch/arm/boot/dts/stih416-pinctrl.dtsi         |  718 ++++++++++++++++++++++++
 arch/arm/boot/dts/stih416.dtsi                 |  103 ++++
 arch/arm/boot/dts/stih416.h                    |   24 +
 arch/arm/configs/stih41x_defconfig             |    1 +
 arch/arm/mach-stih41x/Kconfig                  |    9 +
 arch/arm/mach-stih41x/board-dt.c               |    2 +-
 8 files changed, 909 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/arm/STiH41x/stih416-overview.txt
 create mode 100644 arch/arm/boot/dts/stih416-clock.dtsi
 create mode 100644 arch/arm/boot/dts/stih416-pinctrl.dtsi
 create mode 100644 arch/arm/boot/dts/stih416.dtsi
 create mode 100644 arch/arm/boot/dts/stih416.h

diff --git a/Documentation/arm/STiH41x/stih416-overview.txt b/Documentation/arm/STiH41x/stih416-overview.txt
new file mode 100644
index 0000000..e060867
--- /dev/null
+++ b/Documentation/arm/STiH41x/stih416-overview.txt
@@ -0,0 +1,12 @@
+			STiH416 Overview
+			================
+
+Introduction
+------------
+
+    The STiH416 is the next generation of HD, AVC set-top box processors
+    for satellite, cable, terrestrial and IP-STB markets.
+
+    Features
+    - ARM Cortex-A9 1.2 GHz dual core CPU
+    - SATA2×2,USB 2.0×3, PCIe, Gbit Ethernet MAC×2
diff --git a/arch/arm/boot/dts/stih416-clock.dtsi b/arch/arm/boot/dts/stih416-clock.dtsi
new file mode 100644
index 0000000..7026bf1
--- /dev/null
+++ b/arch/arm/boot/dts/stih416-clock.dtsi
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics R&D Limited
+ * <stlinux-devel@stlinux.com>
+ *
+ * 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.
+ */
+/ {
+	clocks {
+		/*
+		 * Fixed 30MHz oscillator inputs to SoC
+		 */
+		CLK_SYSIN: CLK_SYSIN {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <30000000>;
+			clock-output-names = "CLK_SYSIN";
+		};
+
+		/*
+		 * ARM Peripheral clock for timers
+		 */
+		arm_periph_clk: arm_periph_clk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <600000000>;
+		};
+
+		/*
+		 * Bootloader initialized system infrastructure clock for
+		 * serial devices.
+		 */
+		CLK_S_ICN_REG_0: clockgenA0@4 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <100000000>;
+			clock-output-names = "CLK_S_ICN_REG_0";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stih416-pinctrl.dtsi b/arch/arm/boot/dts/stih416-pinctrl.dtsi
new file mode 100644
index 0000000..f1266bb
--- /dev/null
+++ b/arch/arm/boot/dts/stih416-pinctrl.dtsi
@@ -0,0 +1,718 @@
+
+/*
+ * Copyright (C) 2013 STMicroelectronics Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stixxxx-pincfg.h"
+#include "stih416.h"
+/ {
+
+	aliases {
+		gpio0	= &PIO0;
+		gpio1	= &PIO1;
+		gpio2	= &PIO2;
+		gpio3	= &PIO3;
+		gpio4	= &PIO4;
+		gpio5	= &PIO40;
+		gpio6	= &PIO5;
+		gpio7	= &PIO6;
+		gpio8	= &PIO7;
+		gpio9	= &PIO8;
+		gpio10	= &PIO9;
+		gpio11	= &PIO10;
+		gpio12	= &PIO11;
+		gpio13	= &PIO12;
+		gpio14	= &PIO30;
+		gpio15	= &PIO31;
+		gpio16	= &PIO13;
+		gpio17	= &PIO14;
+		gpio18	= &PIO15;
+		gpio19	= &PIO16;
+		gpio20	= &PIO17;
+		gpio21	= &PIO18;
+		gpio22	= &PIO100;
+		gpio23	= &PIO101;
+		gpio24	= &PIO102;
+		gpio25	= &PIO103;
+		gpio26	= &PIO104;
+		gpio27	= &PIO105;
+		gpio28	= &PIO106;
+		gpio29	= &PIO107;
+	};
+
+
+	soc {
+		pin-controller {
+			#address-cells	= <1>;
+			#size-cells	= <1>;
+			#retime-delay-cells	= <14>;
+			compatible	= "st,stixxxx-pinctrl", "simple-bus";
+			st,retime-in-delay	= <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+			st,retime-out-delay	= <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+			ranges;
+			PIO0: pinctrl@fe610000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe610000 0x100>;
+				st,bank-name 	= "PIO0";
+				st,alt-control	= <&SYSCFG_SBC(0) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(40) 0 7>;
+				st,pu-control	= <&SYSCFG_SBC(50) 0 7>;
+				st,od-control	= <&SYSCFG_SBC(60) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_SBC(100) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(101) 0 31>;
+				st,retime-control2	= <&SYSCFG_SBC(102) 0 31>;
+				st,retime-control3	= <&SYSCFG_SBC(103) 0 31>;
+				st,retime-control4	= <&SYSCFG_SBC(104) 0 31>;
+				st,retime-control5	= <&SYSCFG_SBC(105) 0 31>;
+				st,retime-control6	= <&SYSCFG_SBC(106) 0 31>;
+				st,retime-control7	= <&SYSCFG_SBC(107) 0 31>;
+			};
+			PIO1: pinctrl@fe611000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe611000 0x100>;
+				st,bank-name 	= "PIO1";
+				st,alt-control	= <&SYSCFG_SBC(1) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(40) 8 15>;
+				st,pu-control	= <&SYSCFG_SBC(50) 8 15>;
+				st,od-control	= <&SYSCFG_SBC(60) 8 15>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_SBC(108) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(109) 0 31>;
+				st,retime-control2	= <&SYSCFG_SBC(110) 0 31>;
+				st,retime-control3	= <&SYSCFG_SBC(111) 0 31>;
+				st,retime-control4	= <&SYSCFG_SBC(112) 0 31>;
+				st,retime-control5	= <&SYSCFG_SBC(113) 0 31>;
+				st,retime-control6	= <&SYSCFG_SBC(114) 0 31>;
+				st,retime-control7	= <&SYSCFG_SBC(115) 0 31>;
+			};
+			PIO2: pinctrl@fe612000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe612000 0x100>;
+				st,bank-name 	= "PIO2";
+				st,alt-control	= <&SYSCFG_SBC(2) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(40) 16 23>;
+				st,pu-control	= <&SYSCFG_SBC(50) 16 23>;
+				st,od-control	= <&SYSCFG_SBC(60) 16 23>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_SBC(116) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(117) 0 31>;
+				st,retime-control2	= <&SYSCFG_SBC(118) 0 31>;
+				st,retime-control3	= <&SYSCFG_SBC(119) 0 31>;
+				st,retime-control4	= <&SYSCFG_SBC(120) 0 31>;
+				st,retime-control5	= <&SYSCFG_SBC(121) 0 31>;
+				st,retime-control6	= <&SYSCFG_SBC(122) 0 31>;
+				st,retime-control7	= <&SYSCFG_SBC(123) 0 31>;
+			};
+			PIO3: pinctrl@fe613000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe613000 0x100>;
+				st,bank-name 	= "PIO3";
+				st,alt-control	= <&SYSCFG_SBC(3) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(40) 24 31>;
+				st,pu-control	= <&SYSCFG_SBC(50) 24 31>;
+				st,od-control	= <&SYSCFG_SBC(60) 24 31>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_SBC(124) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(125) 0 31>;
+				st,retime-control2	= <&SYSCFG_SBC(126) 0 31>;
+				st,retime-control3	= <&SYSCFG_SBC(127) 0 31>;
+				st,retime-control4	= <&SYSCFG_SBC(128) 0 31>;
+				st,retime-control5	= <&SYSCFG_SBC(129) 0 31>;
+				st,retime-control6	= <&SYSCFG_SBC(130) 0 31>;
+				st,retime-control7	= <&SYSCFG_SBC(131) 0 31>;
+			};
+
+			PIO4: pinctrl@fe614000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe614000 0x100>;
+				st,bank-name 	= "PIO4";
+				st,alt-control	= <&SYSCFG_SBC(4) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(41) 0 7>;
+				st,pu-control	= <&SYSCFG_SBC(51) 0 7>;
+				st,od-control	= <&SYSCFG_SBC(61) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_SBC(132) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(133) 0 31>;
+				st,retime-control2	= <&SYSCFG_SBC(134) 0 31>;
+				st,retime-control3	= <&SYSCFG_SBC(135) 0 31>;
+				st,retime-control4	= <&SYSCFG_SBC(136) 0 31>;
+				st,retime-control5	= <&SYSCFG_SBC(137) 0 31>;
+				st,retime-control6	= <&SYSCFG_SBC(138) 0 31>;
+				st,retime-control7	= <&SYSCFG_SBC(139) 0 31>;
+			};
+
+			PIO40: pinctrl@fe615000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe615000 0x100>;
+				st,bank-name 	= "PIO40";
+				st,alt-control	= <&SYSCFG_SBC(5) 0 31>;
+				st,oe-control	= <&SYSCFG_SBC(41) 8 15>;
+				st,pu-control	= <&SYSCFG_SBC(51) 8 15>;
+				st,od-control	= <&SYSCFG_SBC(61) 8 15>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0x7f>;
+				st,retime-control0	= <&SYSCFG_SBC(140) 0 31>;
+				st,retime-control1	= <&SYSCFG_SBC(141) 0 31>;
+				st,retime-control2	= <&SYSCFG_SBC(142) 0 31>;
+				st,retime-control3	= <&SYSCFG_SBC(143) 0 31>;
+				st,retime-control4	= <&SYSCFG_SBC(144) 0 31>;
+				st,retime-control5	= <&SYSCFG_SBC(145) 0 31>;
+				st,retime-control6	= <&SYSCFG_SBC(146) 0 31>;
+			};
+
+			PIO5: pinctrl@fee00000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee00000 0x100>;
+				st,bank-name 	= "PIO5";
+				st,alt-control	= <&SYSCFG_FRONT(1000) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1040) 0 7>;
+				st,pu-control	= <&SYSCFG_FRONT(1050) 0 7>;
+				st,od-control	= <&SYSCFG_FRONT(1060) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1100) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1101) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1102) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1103) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1104) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1105) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1106) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1107) 0 31>;
+			};
+			PIO6: pinctrl@fee01000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee01000 0x100>;
+				st,bank-name 	= "PIO6";
+				st,alt-control	= <&SYSCFG_FRONT(1001) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1040) 8 15>;
+				st,pu-control	= <&SYSCFG_FRONT(1050) 8 15>;
+				st,od-control	= <&SYSCFG_FRONT(1060) 8 15>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1108) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1109) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1110) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1111) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1112) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1113) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1114) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1115) 0 31>;
+			};
+			PIO7: pinctrl@fee02000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee02000 0x100>;
+				st,bank-name 	= "PIO7";
+				st,alt-control	= <&SYSCFG_FRONT(1002) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1040) 16 23>;
+				st,pu-control	= <&SYSCFG_FRONT(1050) 16 23>;
+				st,od-control	= <&SYSCFG_FRONT(1060) 16 23>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1116) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1117) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1118) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1119) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1120) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1121) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1122) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1123) 0 31>;
+			};
+			PIO8: pinctrl@fee03000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee03000 0x100>;
+				st,bank-name 	= "PIO8";
+				st,alt-control	= <&SYSCFG_FRONT(1003) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1040) 24 31>;
+				st,pu-control	= <&SYSCFG_FRONT(1050) 24 31>;
+				st,od-control	= <&SYSCFG_FRONT(1060) 24 31>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1124) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1125) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1126) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1127) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1128) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1129) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1130) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1131) 0 31>;
+			};
+
+			PIO9: pinctrl@fee04000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee04000 0x100>;
+				st,bank-name 	= "PIO9";
+				st,alt-control	= <&SYSCFG_FRONT(1004) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1041) 0 7>;
+				st,pu-control	= <&SYSCFG_FRONT(1051) 0 7>;
+				st,od-control	= <&SYSCFG_FRONT(1061) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1132) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1133) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1134) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1135) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1136) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1137) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1138) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1139) 0 31>;
+			};
+			PIO10: pinctrl@fee05000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee05000 0x100>;
+				st,bank-name 	= "PIO10";
+				st,alt-control	= <&SYSCFG_FRONT(1005) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1041) 8 15>;
+				st,pu-control	= <&SYSCFG_FRONT(1051) 8 15>;
+				st,od-control	= <&SYSCFG_FRONT(1061) 8 15>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1140) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1141) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1142) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1143) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1144) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1145) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1146) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1147) 0 31>;
+			};
+			PIO11: pinctrl@fee06000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee06000 0x100>;
+				st,bank-name 	= "PIO11";
+				st,alt-control	= <&SYSCFG_FRONT(1006) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1041) 16 23>;
+				st,pu-control	= <&SYSCFG_FRONT(1051) 16 23>;
+				st,od-control	= <&SYSCFG_FRONT(1061) 16 23>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1148) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1149) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1150) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1151) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1152) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1153) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1154) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1155) 0 31>;
+			};
+			PIO12: pinctrl@fee07000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee07000 0x100>;
+				st,bank-name 	= "PIO12";
+				st,alt-control	= <&SYSCFG_FRONT(1007) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1041) 24 31>;
+				st,pu-control	= <&SYSCFG_FRONT(1051) 24 31>;
+				st,od-control	= <&SYSCFG_FRONT(1061) 24 31>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1156) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1157) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1158) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1159) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1160) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1161) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1162) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1163) 0 31>;
+			};
+
+			PIO30: pinctrl@fee08000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee08000 0x100>;
+				st,bank-name 	= "PIO30";
+				st,alt-control	= <&SYSCFG_FRONT(1008) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1042) 0 7>;
+				st,pu-control	= <&SYSCFG_FRONT(1052) 0 7>;
+				st,od-control	= <&SYSCFG_FRONT(1062) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1164) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1165) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1166) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1167) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1168) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1169) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1170) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1171) 0 31>;
+			};
+
+			PIO31: pinctrl@fee09000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfee09000 0x100>;
+				st,bank-name 	= "PIO31";
+				st,alt-control	= <&SYSCFG_FRONT(1009) 0 31>;
+				st,oe-control	= <&SYSCFG_FRONT(1042) 8 15>;
+				st,pu-control	= <&SYSCFG_FRONT(1052) 8 15>;
+				st,od-control	= <&SYSCFG_FRONT(1062) 8 15>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FRONT(1172) 0 31>;
+				st,retime-control1	= <&SYSCFG_FRONT(1173) 0 31>;
+				st,retime-control2	= <&SYSCFG_FRONT(1174) 0 31>;
+				st,retime-control3	= <&SYSCFG_FRONT(1175) 0 31>;
+				st,retime-control4	= <&SYSCFG_FRONT(1176) 0 31>;
+				st,retime-control5	= <&SYSCFG_FRONT(1177) 0 31>;
+				st,retime-control6	= <&SYSCFG_FRONT(1178) 0 31>;
+				st,retime-control7	= <&SYSCFG_FRONT(1179) 0 31>;
+			};
+
+
+
+			PIO13: pinctrl@fe820000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe820000 0x100>;
+				st,bank-name 	= "PIO13";
+				st,alt-control	= <&SYSCFG_REAR(2000) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(2040) 0 7>;
+				st,pu-control	= <&SYSCFG_REAR(2050) 0 7>;
+				st,od-control	= <&SYSCFG_REAR(2060) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_REAR(2100) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(2101) 0 31>;
+				st,retime-control2	= <&SYSCFG_REAR(2102) 0 31>;
+				st,retime-control3	= <&SYSCFG_REAR(2103) 0 31>;
+				st,retime-control4	= <&SYSCFG_REAR(2104) 0 31>;
+				st,retime-control5	= <&SYSCFG_REAR(2105) 0 31>;
+				st,retime-control6	= <&SYSCFG_REAR(2106) 0 31>;
+				st,retime-control7	= <&SYSCFG_REAR(2107) 0 31>;
+			};
+			PIO14: pinctrl@fe821000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe821000 0x100>;
+				st,bank-name 	= "PIO14";
+				st,alt-control	= <&SYSCFG_REAR(2001) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(2040) 8 15>;
+				st,pu-control	= <&SYSCFG_REAR(2050) 8 15>;
+				st,od-control	= <&SYSCFG_REAR(2060) 8 15>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_REAR(2108) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(2109) 0 31>;
+				st,retime-control2	= <&SYSCFG_REAR(2110) 0 31>;
+				st,retime-control3	= <&SYSCFG_REAR(2111) 0 31>;
+				st,retime-control4	= <&SYSCFG_REAR(2112) 0 31>;
+				st,retime-control5	= <&SYSCFG_REAR(2113) 0 31>;
+				st,retime-control6	= <&SYSCFG_REAR(2114) 0 31>;
+				st,retime-control7	= <&SYSCFG_REAR(2115) 0 31>;
+			};
+			PIO15: pinctrl@fe822000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe822000 0x100>;
+				st,bank-name 	= "PIO15";
+				st,alt-control	= <&SYSCFG_REAR(2002) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(2040) 16 23>;
+				st,pu-control	= <&SYSCFG_REAR(2050) 16 23>;
+				st,od-control	= <&SYSCFG_REAR(2060) 16 23>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_REAR(2116) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(2117) 0 31>;
+				st,retime-control2	= <&SYSCFG_REAR(2118) 0 31>;
+				st,retime-control3	= <&SYSCFG_REAR(2119) 0 31>;
+				st,retime-control4	= <&SYSCFG_REAR(2120) 0 31>;
+				st,retime-control5	= <&SYSCFG_REAR(2121) 0 31>;
+				st,retime-control6	= <&SYSCFG_REAR(2122) 0 31>;
+				st,retime-control7	= <&SYSCFG_REAR(2123) 0 31>;
+			};
+			PIO16: pinctrl@fe823000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe823000 0x100>;
+				st,bank-name 	= "PIO16";
+				st,alt-control	= <&SYSCFG_REAR(2003) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(2040) 24 31>;
+				st,pu-control	= <&SYSCFG_REAR(2050) 24 31>;
+				st,od-control	= <&SYSCFG_REAR(2060) 24 31>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_REAR(2124) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(2125) 0 31>;
+				st,retime-control2	= <&SYSCFG_REAR(2126) 0 31>;
+				st,retime-control3	= <&SYSCFG_REAR(2127) 0 31>;
+				st,retime-control4	= <&SYSCFG_REAR(2128) 0 31>;
+				st,retime-control5	= <&SYSCFG_REAR(2129) 0 31>;
+				st,retime-control6	= <&SYSCFG_REAR(2130) 0 31>;
+				st,retime-control7	= <&SYSCFG_REAR(2131) 0 31>;
+			};
+
+			PIO17: pinctrl@fe824000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe824000 0x100>;
+				st,bank-name 	= "PIO17";
+				st,alt-control	= <&SYSCFG_REAR(2004) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(2041) 0 7>;
+				st,pu-control	= <&SYSCFG_REAR(2051) 0 7>;
+				st,od-control	= <&SYSCFG_REAR(2061) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_REAR(2132) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(2133) 0 31>;
+				st,retime-control2	= <&SYSCFG_REAR(2134) 0 31>;
+				st,retime-control3	= <&SYSCFG_REAR(2135) 0 31>;
+				st,retime-control4	= <&SYSCFG_REAR(2136) 0 31>;
+				st,retime-control5	= <&SYSCFG_REAR(2137) 0 31>;
+				st,retime-control6	= <&SYSCFG_REAR(2138) 0 31>;
+				st,retime-control7	= <&SYSCFG_REAR(2139) 0 31>;
+			};
+
+			PIO18: pinctrl@fe825000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfe825000 0x100>;
+				st,bank-name 	= "PIO18";
+				st,alt-control	= <&SYSCFG_REAR(2005) 0 31>;
+				st,oe-control	= <&SYSCFG_REAR(2041) 8 15>;
+				st,pu-control	= <&SYSCFG_REAR(2051) 8 15>;
+				st,od-control	= <&SYSCFG_REAR(2061) 8 15>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xf>;
+				st,retime-control0	= <&SYSCFG_REAR(2140) 0 31>;
+				st,retime-control1	= <&SYSCFG_REAR(2141) 0 31>;
+				st,retime-control2	= <&SYSCFG_REAR(2142) 0 31>;
+				st,retime-control3	= <&SYSCFG_REAR(2143) 0 31>;
+			};
+			PIO100: pinctrl@fd6b0000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfd6b0000 0x100>;
+				st,bank-name 	= "PIO100";
+				st,alt-control	= <&SYSCFG_FVDP_FE(5000) 0 31>;
+				st,oe-control	= <&SYSCFG_FVDP_FE(5040) 0 7>;
+				st,pu-control	= <&SYSCFG_FVDP_FE(5050) 0 7>;
+				st,od-control	= <&SYSCFG_FVDP_FE(5060) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FVDP_FE(5100) 0 31>;
+				st,retime-control1	= <&SYSCFG_FVDP_FE(5101) 0 31>;
+				st,retime-control2	= <&SYSCFG_FVDP_FE(5102) 0 31>;
+				st,retime-control3	= <&SYSCFG_FVDP_FE(5103) 0 31>;
+				st,retime-control4	= <&SYSCFG_FVDP_FE(5104) 0 31>;
+				st,retime-control5	= <&SYSCFG_FVDP_FE(5105) 0 31>;
+				st,retime-control6	= <&SYSCFG_FVDP_FE(5106) 0 31>;
+				st,retime-control7	= <&SYSCFG_FVDP_FE(5107) 0 31>;
+			};
+
+			PIO101: pinctrl@fd6b1000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfd6b1000 0x100>;
+				st,bank-name 	= "PIO101";
+				st,alt-control	= <&SYSCFG_FVDP_FE(5001) 0 31>;
+				st,oe-control	= <&SYSCFG_FVDP_FE(5040) 8 15>;
+				st,pu-control	= <&SYSCFG_FVDP_FE(5050) 8 15>;
+				st,od-control	= <&SYSCFG_FVDP_FE(5060) 8 15>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FVDP_FE(5108) 0 31>;
+				st,retime-control1	= <&SYSCFG_FVDP_FE(5109) 0 31>;
+				st,retime-control2	= <&SYSCFG_FVDP_FE(5110) 0 31>;
+				st,retime-control3	= <&SYSCFG_FVDP_FE(5111) 0 31>;
+				st,retime-control4	= <&SYSCFG_FVDP_FE(5112) 0 31>;
+				st,retime-control5	= <&SYSCFG_FVDP_FE(5113) 0 31>;
+				st,retime-control6	= <&SYSCFG_FVDP_FE(5114) 0 31>;
+				st,retime-control7	= <&SYSCFG_FVDP_FE(5115) 0 31>;
+			};
+
+			PIO102: pinctrl@fd6b2000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfd6b2000 0x100>;
+				st,bank-name 	= "PIO102";
+				st,alt-control	= <&SYSCFG_FVDP_FE(5002) 0 31>;
+				st,oe-control	= <&SYSCFG_FVDP_FE(5040) 16 23>;
+				st,pu-control	= <&SYSCFG_FVDP_FE(5050) 16 23>;
+				st,od-control	= <&SYSCFG_FVDP_FE(5060) 16 23>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FVDP_FE(5116) 0 31>;
+				st,retime-control1	= <&SYSCFG_FVDP_FE(5117) 0 31>;
+				st,retime-control2	= <&SYSCFG_FVDP_FE(5118) 0 31>;
+				st,retime-control3	= <&SYSCFG_FVDP_FE(5119) 0 31>;
+				st,retime-control4	= <&SYSCFG_FVDP_FE(5120) 0 31>;
+				st,retime-control5	= <&SYSCFG_FVDP_FE(5121) 0 31>;
+				st,retime-control6	= <&SYSCFG_FVDP_FE(5122) 0 31>;
+				st,retime-control7	= <&SYSCFG_FVDP_FE(5123) 0 31>;
+			};
+
+
+
+			PIO103: pinctrl@fd330000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfd330000 0x100>;
+				st,bank-name 	= "PIO103";
+				st,alt-control	= <&SYSCFG_FVDP_LITE(6000) 0 31>;
+				st,oe-control	= <&SYSCFG_FVDP_LITE(6040) 0 7>;
+				st,pu-control	= <&SYSCFG_FVDP_LITE(6050) 0 7>;
+				st,od-control	= <&SYSCFG_FVDP_LITE(6060) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FVDP_LITE(6100) 0 31>;
+				st,retime-control1	= <&SYSCFG_FVDP_LITE(6101) 0 31>;
+				st,retime-control2	= <&SYSCFG_FVDP_LITE(6102) 0 31>;
+				st,retime-control3	= <&SYSCFG_FVDP_LITE(6103) 0 31>;
+				st,retime-control4	= <&SYSCFG_FVDP_LITE(6104) 0 31>;
+				st,retime-control5	= <&SYSCFG_FVDP_LITE(6105) 0 31>;
+				st,retime-control6	= <&SYSCFG_FVDP_LITE(6106) 0 31>;
+				st,retime-control7	= <&SYSCFG_FVDP_LITE(6107) 0 31>;
+			};
+			PIO104: pinctrl@fd331000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfd331000 0x100>;
+				st,bank-name 	= "PIO104";
+				st,alt-control	= <&SYSCFG_FVDP_LITE(6001) 0 31>;
+				st,oe-control	= <&SYSCFG_FVDP_LITE(6040) 8 15>;
+				st,pu-control	= <&SYSCFG_FVDP_LITE(6050) 8 15>;
+				st,od-control	= <&SYSCFG_FVDP_LITE(6060) 8 15>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FVDP_LITE(6108) 0 31>;
+				st,retime-control1	= <&SYSCFG_FVDP_LITE(6109) 0 31>;
+				st,retime-control2	= <&SYSCFG_FVDP_LITE(6110) 0 31>;
+				st,retime-control3	= <&SYSCFG_FVDP_LITE(6111) 0 31>;
+				st,retime-control4	= <&SYSCFG_FVDP_LITE(6112) 0 31>;
+				st,retime-control5	= <&SYSCFG_FVDP_LITE(6113) 0 31>;
+				st,retime-control6	= <&SYSCFG_FVDP_LITE(6114) 0 31>;
+				st,retime-control7	= <&SYSCFG_FVDP_LITE(6115) 0 31>;
+			};
+			PIO105: pinctrl@fd332000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfd332000 0x100>;
+				st,bank-name 	= "PIO105";
+				st,alt-control	= <&SYSCFG_FVDP_LITE(6002) 0 31>;
+				st,oe-control	= <&SYSCFG_FVDP_LITE(6040) 16 23>;
+				st,pu-control	= <&SYSCFG_FVDP_LITE(6050) 16 23>;
+				st,od-control	= <&SYSCFG_FVDP_LITE(6060) 16 23>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FVDP_LITE(6116) 0 31>;
+				st,retime-control1	= <&SYSCFG_FVDP_LITE(6117) 0 31>;
+				st,retime-control2	= <&SYSCFG_FVDP_LITE(6118) 0 31>;
+				st,retime-control3	= <&SYSCFG_FVDP_LITE(6119) 0 31>;
+				st,retime-control4	= <&SYSCFG_FVDP_LITE(6120) 0 31>;
+				st,retime-control5	= <&SYSCFG_FVDP_LITE(6121) 0 31>;
+				st,retime-control6	= <&SYSCFG_FVDP_LITE(6122) 0 31>;
+				st,retime-control7	= <&SYSCFG_FVDP_LITE(6123) 0 31>;
+			};
+			PIO106: pinctrl@fd333000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfd333000 0x100>;
+				st,bank-name 	= "PIO106";
+				st,alt-control	= <&SYSCFG_FVDP_LITE(6003) 0 31>;
+				st,oe-control	= <&SYSCFG_FVDP_LITE(6040) 24 31>;
+				st,pu-control	= <&SYSCFG_FVDP_LITE(6050) 24 31>;
+				st,od-control	= <&SYSCFG_FVDP_LITE(6060) 24 31>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xff>;
+				st,retime-control0	= <&SYSCFG_FVDP_LITE(6124) 0 31>;
+				st,retime-control1	= <&SYSCFG_FVDP_LITE(6125) 0 31>;
+				st,retime-control2	= <&SYSCFG_FVDP_LITE(6126) 0 31>;
+				st,retime-control3	= <&SYSCFG_FVDP_LITE(6127) 0 31>;
+				st,retime-control4	= <&SYSCFG_FVDP_LITE(6128) 0 31>;
+				st,retime-control5	= <&SYSCFG_FVDP_LITE(6129) 0 31>;
+				st,retime-control6	= <&SYSCFG_FVDP_LITE(6130) 0 31>;
+				st,retime-control7	= <&SYSCFG_FVDP_LITE(6131) 0 31>;
+			};
+
+			PIO107: pinctrl@fd334000 {
+				#gpio-cells	= <1>;
+				compatible	= "st,stixxxx-gpio";
+				gpio-controller;
+				reg	= <0xfd334000 0x100>;
+				st,bank-name 	= "PIO107";
+				st,alt-control	= <&SYSCFG_FVDP_LITE(6004) 0 31>;
+				st,oe-control	= <&SYSCFG_FVDP_LITE(6041) 0 7>;
+				st,pu-control	= <&SYSCFG_FVDP_LITE(6051) 0 7>;
+				st,od-control	= <&SYSCFG_FVDP_LITE(6061) 0 7>;
+				st,retime-style	= "dedicated";
+				st,retime-pin-mask	= <0xf>;
+				st,retime-control0	= <&SYSCFG_FVDP_LITE(6132) 0 31>;
+				st,retime-control1	= <&SYSCFG_FVDP_LITE(6133) 0 31>;
+				st,retime-control2	= <&SYSCFG_FVDP_LITE(6134) 0 31>;
+				st,retime-control3	= <&SYSCFG_FVDP_LITE(6135) 0 31>;
+			};
+
+			uart2 {
+				pinctrl_uart2: uart2-0 {
+					st,function = <ALT2>;
+					st,pins {
+						tx	= <&PIO17 4 OUT>;
+						rx	= <&PIO17 5 IN>;
+						output-enable	= <&PIO11 3 OUT>;
+					};
+				};
+			};
+
+			sbc_uart1 {
+				pinctrl_sbc_uart1: sbc_uart1 {
+					st,function = <ALT3>;
+					st,pins {
+						tx	= <&PIO2 6 OUT>;
+						rx	= <&PIO2 7 IN>;
+					};
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi
new file mode 100644
index 0000000..47439b3
--- /dev/null
+++ b/arch/arm/boot/dts/stih416.dtsi
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 STMicroelectronics Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stih41x.dtsi"
+#include "stih416-clock.dtsi"
+#include "stih416-pinctrl.dtsi"
+/ {
+	L2: cache-controller {
+		compatible = "arm,pl310-cache";
+		reg = <0xfffe2000 0x1000>;
+		arm,data-latency = <3 3 3>;
+		arm,tag-latency = <2 2 2>;
+		cache-unified;
+		cache-level = <2>;
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <3>;
+		interrupt-parent = <&intc>;
+		ranges;
+		compatible	= "simple-bus";
+
+		syscfg_sbc:syscon@fe600000{
+			compatible	= "syscon";
+			reg		= <0xfe600000 0x1000>;
+			syscon-name	= "SYSCFG_SBC";
+		};
+		syscfg_front:syscon@fee10000{
+			compatible	= "syscon";
+			reg		= <0xfee10000 0x1000>;
+			syscon-name	= "SYSCFG_FRONT";
+		};
+		syscfg_rear:syscon@fe830000{
+			compatible	= "syscon";
+			reg		= <0xfe830000 0x1000>;
+			syscon-name	= "SYSCFG_REAR";
+		};
+
+		/* MPE */
+		syscfg_fvdp_fe:syscon@fddf0000{
+			compatible	= "syscon";
+			reg		= <0xfddf0000 0x1000>;
+			syscon-name	= "SYSCFG_FVDP_FE";
+		};
+		syscfg_fvdp_lite:syscon@fd6a0000{
+			compatible	= "syscon";
+			reg		= <0xfd6a0000 0x1000>;
+			syscon-name	= "SYSCFG_FVDP_LITE";
+		};
+
+		syscfg_cpu:syscon@fdde0000{
+			compatible	= "syscon";
+			reg		= <0xfdde0000 0x1000>;
+			syscon-name	= "SYSCFG_CPU";
+		};
+
+		syscfg_compo:syscon@fd320000{
+			compatible	= "syscon";
+			reg		= <0xfd320000 0x1000>;
+			syscon-name	= "SYSCFG_COMPO";
+		};
+
+		syscfg_transport:syscon@fd690000{
+			compatible	= "syscon";
+			reg		= <0xfd690000 0x1000>;
+			syscon-name	= "SYSCFG_TRANSPORT";
+		};
+
+		syscfg_lpm:syscon@fe4b5100{
+			compatible	= "syscon";
+			reg		= <0xfe4b5100 0x54>;
+			syscon-name	= "LPM_CFG_REGS";
+		};
+
+		uart2: uart@fed32000{
+			compatible	= "st,asc";
+			status 		= "disabled";
+			reg		= <0xfed32000 0x2c>;
+			interrupts	= <0 197 0>;
+			clocks          = <&CLK_S_ICN_REG_0>;
+			pinctrl-names 	= "default";
+			pinctrl-0 	= <&pinctrl_uart2>;
+		};
+
+		/* SBC_UART1 */
+		sbc_uart1: uart@fe531000 {
+			compatible	= "st,asc";
+			status 		= "disabled";
+			reg		= <0xfe531000 0x2c>;
+			interrupts	= <0 210 0>;
+			pinctrl-names 	= "default";
+			pinctrl-0 	= <&pinctrl_sbc_uart1>;
+			clocks          = <&CLK_SYSIN>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stih416.h b/arch/arm/boot/dts/stih416.h
new file mode 100644
index 0000000..2e27792
--- /dev/null
+++ b/arch/arm/boot/dts/stih416.h
@@ -0,0 +1,24 @@
+#ifndef __STIH416_H_
+#define __STIH416_H_
+
+#define CONFIG_SBC(num)		num
+#define CONFIG_FRONT(num)	(num - 1000)
+#define CONFIG_REAR(num)	(num - 2000)
+#define CONFIG_FVDP_FE(num)	(num - 5000)
+#define CONFIG_FVDP_LITE(num)	(num - 6000)
+#define CONFIG_CPU(num)		(num - 7000)
+#define CONFIG_COMPO(num)	(num - 8000)
+#define CONFIG_TRANSPORT(num)	(num - 9000)
+#define CONFIG_LPM(num)		num
+
+#define SYSCFG_SBC(num)		syscfg_sbc CONFIG_SBC(num)
+#define SYSCFG_FRONT(num)	syscfg_front CONFIG_FRONT(num)
+#define SYSCFG_REAR(num)	syscfg_rear CONFIG_REAR(num)
+#define SYSCFG_FVDP_FE(num)	syscfg_fvdp_fe CONFIG_FVDP_FE(num)
+#define SYSCFG_FVDP_LITE(num)	syscfg_fvdp_lite CONFIG_FVDP_LITE(num)
+#define SYSCFG_CPU(num)		syscfg_cpu CONFIG_CPU(num)
+#define SYSCFG_COMPO(num)	syscfg_compo CONFIG_COMPO(num)
+#define SYSCFG_TRANSPORT(num)	syscfg_transport CONFIG_TRANSPORT(num)
+#define SYSCFG_LPM(num)		syscfg_lpm CONFIG_LPM(num)
+
+#endif /* __STIH416_H_ */
diff --git a/arch/arm/configs/stih41x_defconfig b/arch/arm/configs/stih41x_defconfig
index dd9268b..cc4e2dc 100644
--- a/arch/arm/configs/stih41x_defconfig
+++ b/arch/arm/configs/stih41x_defconfig
@@ -24,6 +24,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_BLK_DEV_INTEGRITY=y
 CONFIG_ARCH_STIH41X=y
 CONFIG_SOC_STIH415=y
+CONFIG_SOC_STIH416=y
 # CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set
 # CONFIG_SWP_EMULATE is not set
 CONFIG_ARM_ERRATA_720789=y
diff --git a/arch/arm/mach-stih41x/Kconfig b/arch/arm/mach-stih41x/Kconfig
index 9c40540..848d3e8 100644
--- a/arch/arm/mach-stih41x/Kconfig
+++ b/arch/arm/mach-stih41x/Kconfig
@@ -31,5 +31,14 @@ config SOC_STIH415
 	  and other digital audio/video applications using Flattned Device
 	  Trees.
 
+config SOC_STIH416
+	bool "STiH416 STMicroelectronics Consumer Electronics family"
+	select PLAT_STIXXXX
+	help
+	  This enables support for STMicroelectronics Digital Consumer
+	  Electronics family StiH416 parts, primarily targetted at set-top-box
+	  and other digital audio/video applications using Flattened Device
+	  Trees.
+
 endmenu
 endif
diff --git a/arch/arm/mach-stih41x/board-dt.c b/arch/arm/mach-stih41x/board-dt.c
index c51e2c9..8005f71 100644
--- a/arch/arm/mach-stih41x/board-dt.c
+++ b/arch/arm/mach-stih41x/board-dt.c
@@ -66,7 +66,7 @@ static const char *stih41x_dt_match[] __initdata = {
 	NULL
 };
 
-DT_MACHINE_START(STM, "STiH415 SoC with Flattened Device Tree")
+DT_MACHINE_START(STM, "STiH415/416 SoC with Flattened Device Tree")
 	.map_io		= stih41x_map_io,
 	.init_time	= stih41x_timer_init,
 	.init_machine	= stih41x_dt_init,
-- 
1.7.6.5


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

* [RFC 7/8] ARM:stih41x: Add B2000 board support
       [not found] <1368022187-1633-1-git-send-email-srinivas.kandagatla@st.com>
                   ` (3 preceding siblings ...)
  2013-05-08 14:11 ` [RFC 6/8] ARM:stih41x: Add STiH416 " Srinivas KANDAGATLA
@ 2013-05-08 14:12 ` Srinivas KANDAGATLA
  2013-05-08 16:20   ` Arnd Bergmann
  2013-05-08 14:12 ` [RFC 8/8] ARM:stih41x: Add B2020 " Srinivas KANDAGATLA
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 14:12 UTC (permalink / raw)
  To: linux, arnd, olof
  Cc: Rob Landley, Grant Likely, Rob Herring, Samuel Ortiz,
	Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Srinivas Kandagatla, Stuart Menefy, Shawn Guo, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown,
	Dong Aisheng, linux-doc, linux-kernel, devicetree-discuss,
	linux-arm-kernel, linux-serial, Stephen Gallimore

From: Srinivas Kandagatla <srinivas.kandagatla@st.com>

B2000 board is reference board for STIH415/416 SOCs, it has
2 x UART, 4x USB, 2 x Ethernet, 1 x SATA, 1 x PCIe, and 1GB RAM.

This patch add initial support to b2000 with STiH415/416 with UART2 as
console and a heard beat LED.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
CC: Stephen Gallimore <stephen.gallimore@st.com>
CC: Stuart Menefy <stuart.menefy@st.com>
---
 arch/arm/boot/dts/Makefile           |    2 +
 arch/arm/boot/dts/stih415-b2000.dtsp |   15 ++++++++++++
 arch/arm/boot/dts/stih416-b2000.dtsp |   16 +++++++++++++
 arch/arm/boot/dts/stih41x-b2000.dtsi |   41 ++++++++++++++++++++++++++++++++++
 arch/arm/mach-stih41x/board-dt.c     |    2 +
 5 files changed, 76 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/boot/dts/stih415-b2000.dtsp
 create mode 100644 arch/arm/boot/dts/stih416-b2000.dtsp
 create mode 100644 arch/arm/boot/dts/stih41x-b2000.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 9c62558..78b0271 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -147,6 +147,8 @@ dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
 	spear320-evb.dtb \
 	spear320-hmi.dtb
 dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
+dtb-$(CONFIG_ARCH_STIH41X)+= stih415-b2000.dtb \
+	stih416-b2000.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun4i-a10-cubieboard.dtb \
 	sun4i-a10-hackberry.dtb \
 	sun5i-a13-olinuxino.dtb
diff --git a/arch/arm/boot/dts/stih415-b2000.dtsp b/arch/arm/boot/dts/stih415-b2000.dtsp
new file mode 100644
index 0000000..d4af531
--- /dev/null
+++ b/arch/arm/boot/dts/stih415-b2000.dtsp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih415.dtsi"
+#include "stih41x-b2000.dtsi"
+/ {
+	model = "STiH415 B2000 Board";
+	compatible = "st,stih415", "st,stih415-b2000";
+};
diff --git a/arch/arm/boot/dts/stih416-b2000.dtsp b/arch/arm/boot/dts/stih416-b2000.dtsp
new file mode 100644
index 0000000..a5eb6ee
--- /dev/null
+++ b/arch/arm/boot/dts/stih416-b2000.dtsp
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih416.dtsi"
+#include "stih41x-b2000.dtsi"
+
+/ {
+	compatible = "st,stih416", "st,stih416-b2000";
+	model = "STiH416 B2000";
+};
diff --git a/arch/arm/boot/dts/stih41x-b2000.dtsi b/arch/arm/boot/dts/stih41x-b2000.dtsi
new file mode 100644
index 0000000..8c17e4a
--- /dev/null
+++ b/arch/arm/boot/dts/stih41x-b2000.dtsi
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+/ {
+
+	memory{
+		device_type = "memory";
+		reg = <0x60000000 0x40000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyAS0,115200";
+		linux,stdout-path = &uart2;
+	};
+
+	aliases {
+		ttyAS0 = &uart2;
+	};
+
+	soc {
+		uart2: uart@fed32000 {
+			status = "okay";
+		};
+
+		leds {
+			compatible	= "gpio-leds";
+			fp_led {
+				#gpio-cells = <1>;
+				label	= "Front Panel LED";
+				gpios	= <&PIO105 7>;
+				linux,default-trigger	= "heartbeat";
+			};
+		};
+
+	};
+};
diff --git a/arch/arm/mach-stih41x/board-dt.c b/arch/arm/mach-stih41x/board-dt.c
index 8005f71..1f23aca 100644
--- a/arch/arm/mach-stih41x/board-dt.c
+++ b/arch/arm/mach-stih41x/board-dt.c
@@ -63,6 +63,8 @@ void __init stih41x_dt_init(void)
 }
 
 static const char *stih41x_dt_match[] __initdata = {
+	"st,stih415-b2000",
+	"st,stih416-b2000",
 	NULL
 };
 
-- 
1.7.6.5


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

* [RFC 8/8] ARM:stih41x: Add B2020 board support
       [not found] <1368022187-1633-1-git-send-email-srinivas.kandagatla@st.com>
                   ` (4 preceding siblings ...)
  2013-05-08 14:12 ` [RFC 7/8] ARM:stih41x: Add B2000 board support Srinivas KANDAGATLA
@ 2013-05-08 14:12 ` Srinivas KANDAGATLA
       [not found] ` <1368022248-2153-1-git-send-email-srinivas.kandagatla@st.com>
       [not found] ` <1368022284-2283-1-git-send-email-srinivas.kandagatla@st.com>
  7 siblings, 0 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 14:12 UTC (permalink / raw)
  To: arnd, linux, olof
  Cc: Rob Landley, Grant Likely, Rob Herring, Samuel Ortiz,
	Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Srinivas Kandagatla, Stuart Menefy, Shawn Guo, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown,
	Dong Aisheng, linux-doc, linux-kernel, devicetree-discuss,
	linux-arm-kernel, linux-serial, Stephen Gallimore

From: Srinivas Kandagatla <srinivas.kandagatla@st.com>

B2020 ADI board is reference board for STIH415/416 SOCs, it has 2 x
UART, 4x USB, 1 x Ethernet, 1 x SATA, 1 x PCIe, and 2GB RAM  with
standard set-top box IPs.

This patch adds initial support to B2020 with STiH415/416 with SBC_UART1
as console and a heard beat LED.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
CC: Stephen Gallimore <stephen.gallimore@st.com>
CC: Stuart Menefy <stuart.menefy@st.com>
---
 arch/arm/boot/dts/Makefile           |    4 ++-
 arch/arm/boot/dts/stih415-b2020.dtsp |   15 ++++++++++++
 arch/arm/boot/dts/stih416-b2020.dtsp |   16 +++++++++++++
 arch/arm/boot/dts/stih41x-b2020.dtsi |   42 ++++++++++++++++++++++++++++++++++
 arch/arm/mach-stih41x/board-dt.c     |    2 +
 5 files changed, 78 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/boot/dts/stih415-b2020.dtsp
 create mode 100644 arch/arm/boot/dts/stih416-b2020.dtsp
 create mode 100644 arch/arm/boot/dts/stih41x-b2020.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 78b0271..2e69b90 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -148,7 +148,9 @@ dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
 	spear320-hmi.dtb
 dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
 dtb-$(CONFIG_ARCH_STIH41X)+= stih415-b2000.dtb \
-	stih416-b2000.dtb
+	stih416-b2000.dtb \
+	stih415-b2020.dtb \
+	stih416-b2020.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun4i-a10-cubieboard.dtb \
 	sun4i-a10-hackberry.dtb \
 	sun5i-a13-olinuxino.dtb
diff --git a/arch/arm/boot/dts/stih415-b2020.dtsp b/arch/arm/boot/dts/stih415-b2020.dtsp
new file mode 100644
index 0000000..442b019
--- /dev/null
+++ b/arch/arm/boot/dts/stih415-b2020.dtsp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih415.dtsi"
+#include "stih41x-b2020.dtsi"
+/ {
+	model = "STiH415 B2020 Board";
+	compatible = "st,stih415", "st,stih415-b2020";
+};
diff --git a/arch/arm/boot/dts/stih416-b2020.dtsp b/arch/arm/boot/dts/stih416-b2020.dtsp
new file mode 100644
index 0000000..276f28d
--- /dev/null
+++ b/arch/arm/boot/dts/stih416-b2020.dtsp
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih416.dtsi"
+#include "stih41x-b2020.dtsi"
+/ {
+	model = "STiH416 B2020";
+	compatible = "st,stih416", "st,stih416-b2020";
+
+};
diff --git a/arch/arm/boot/dts/stih41x-b2020.dtsi b/arch/arm/boot/dts/stih41x-b2020.dtsi
new file mode 100644
index 0000000..855b583
--- /dev/null
+++ b/arch/arm/boot/dts/stih41x-b2020.dtsi
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+/ {
+	memory{
+		device_type = "memory";
+		reg = <0x40000000 0x80000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyAS0,115200";
+		linux,stdout-path = &sbc_uart1;
+	};
+
+	aliases {
+		ttyAS0 = &sbc_uart1;
+	};
+	soc {
+		sbc_uart1: uart@fe531000 {
+			status = "okay";
+		};
+
+		leds {
+			compatible	= "gpio-leds";
+			red {
+				#gpio-cells = <1>;
+				label	= "Front Panel LED";
+				gpios	= <&PIO4 1>;
+				linux,default-trigger	= "heartbeat";
+			};
+			green {
+				gpios	= <&PIO4 7>;
+				default-state = "off";
+			};
+		};
+	};
+};
diff --git a/arch/arm/mach-stih41x/board-dt.c b/arch/arm/mach-stih41x/board-dt.c
index 1f23aca..ed0ccae 100644
--- a/arch/arm/mach-stih41x/board-dt.c
+++ b/arch/arm/mach-stih41x/board-dt.c
@@ -65,6 +65,8 @@ void __init stih41x_dt_init(void)
 static const char *stih41x_dt_match[] __initdata = {
 	"st,stih415-b2000",
 	"st,stih416-b2000",
+	"st,stih415-b2020",
+	"st,stih416-b2020",
 	NULL
 };
 
-- 
1.7.6.5


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

* Re: [RFC 2/8] ARM:global_timer: Add ARM global timer support.
  2013-05-08 14:11 ` [RFC 2/8] ARM:global_timer: Add ARM global timer support Srinivas KANDAGATLA
@ 2013-05-08 14:26   ` Rob Herring
  2013-05-08 15:06     ` Stuart MENEFY
  2013-05-08 14:38   ` Arnd Bergmann
  1 sibling, 1 reply; 64+ messages in thread
From: Rob Herring @ 2013-05-08 14:26 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: linux, will.deacon, Rob Landley, Grant Likely, Samuel Ortiz,
	Linus Walleij, Greg Kroah-Hartman, Jiri Slaby, Stuart Menefy,
	Shawn Guo, Olof Johansson, Jason Cooper, Stephen Warren,
	Maxime Ripard, Nicolas Pitre, Dave Martin, Marc Zyngier,
	Viresh Kumar, Arnd Bergmann, Mark Brown, Dong Aisheng, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

On 05/08/2013 09:11 AM, Srinivas KANDAGATLA wrote:
> From: Stuart Menefy <stuart.menefy@st.com>
> 
> This is a simple driver for the global timer module found in the Cortex
> A9-MP cores from revision r1p0 onwards. This should be able to perform
> the functions of the system timer and the local timer in an SMP system.
> 
> The global timer has the following features:
>     The global timer is a 64-bit incrementing counter with an
> auto-incrementing feature. It continues incrementing after sending
> interrupts. The global timer is memory mapped in the private memory
> region.
>     The global timer is accessible to all Cortex-A9 processors in the
> cluster. Each Cortex-A9 processor has a private 64-bit comparator that
> is used to assert a private interrupt when the global timer has reached
> the comparator value. All the Cortex-A9 processors in a design use the
> banked ID, ID27, for this interrupt. ID27 is sent to the Interrupt
> Controller as a Private Peripheral Interrupt. The global timer is
> clocked by PERIPHCLK.

PERIPHCLK scales with cpu clock typically so the global timer is not a
suitable clocksource if you use cpufreq. You can deal with the scaling
on clockevents, but not a clocksource. I imagine the global timers is
also typically power-gated in some low power modes. This is why no one
has added support already. Are neither of those an issue or going to be
an issue for you?

Rob

> 
> Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> ---
>  Documentation/devicetree/bindings/arm/gt.txt |   21 ++
>  arch/arm/Kconfig                             |    6 +
>  arch/arm/include/asm/global_timer.h          |   12 +
>  arch/arm/kernel/Makefile                     |    1 +
>  arch/arm/kernel/global_timer.c               |  325 ++++++++++++++++++++++++++
>  5 files changed, 365 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/gt.txt
>  create mode 100644 arch/arm/include/asm/global_timer.h
>  create mode 100644 arch/arm/kernel/global_timer.c
> 
> diff --git a/Documentation/devicetree/bindings/arm/gt.txt b/Documentation/devicetree/bindings/arm/gt.txt
> new file mode 100644
> index 0000000..4ec5fb0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/gt.txt
> @@ -0,0 +1,21 @@
> +
> +* ARM Global Timer
> +	Cortex-A9 are often associated with a per-core Global timer.
> +
> +** Timer node required properties:
> +
> +- compatible : Should be one of:
> +	"arm,cortex-a9-global-timer"
> +
> +- interrupts : One interrupt to each core
> +
> +- reg : Specify the base address and the size of the GT timer
> +	register window.
> +
> +Example:
> +
> +	gt-timer@2c000600 {
> +		compatible = "arm,cortex-a9-global-timer";
> +		reg = <0x2c000600 0x20>;
> +		interrupts = <1 13 0xf01>;
> +	};
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 1cacda4..c8c524e 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1606,6 +1606,12 @@ config HAVE_ARM_TWD
>  	help
>  	  This options enables support for the ARM timer and watchdog unit
>  
> +config HAVE_ARM_GT
> +	bool
> +	select CLKSRC_OF if OF
> +	help
> +	  This options enables support for the ARM global timer unit
> +
>  choice
>  	prompt "Memory split"
>  	default VMSPLIT_3G
> diff --git a/arch/arm/include/asm/global_timer.h b/arch/arm/include/asm/global_timer.h
> new file mode 100644
> index 0000000..46f9188
> --- /dev/null
> +++ b/arch/arm/include/asm/global_timer.h
> @@ -0,0 +1,12 @@
> +/*
> + * arch/arm/include/asm/global_timer.h
> + *
> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
> + * Author: Stuart Menefy <stuart.menefy@st.com>
> + *
> + * 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.
> + */
> +
> +int __init global_timer_init(void __iomem *base, unsigned int timer_irq);
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index 5f3338e..af51808 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_ARM_CPU_SUSPEND)	+= sleep.o suspend.o
>  obj-$(CONFIG_SMP)		+= smp.o smp_tlb.o
>  obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
>  obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
> +obj-$(CONFIG_HAVE_ARM_GT)	+= global_timer.o
>  obj-$(CONFIG_ARM_ARCH_TIMER)	+= arch_timer.o
>  obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
>  obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
> diff --git a/arch/arm/kernel/global_timer.c b/arch/arm/kernel/global_timer.c
> new file mode 100644
> index 0000000..0ab1af3
> --- /dev/null
> +++ b/arch/arm/kernel/global_timer.c
> @@ -0,0 +1,325 @@
> +/*
> + * linux/arch/arm/kernel/global_timer.c
> + *
> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
> + * Author: Stuart Menefy <stuart.menefy@st.com>
> + *
> + * 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.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/clocksource.h>
> +#include <linux/clockchips.h>
> +#include <linux/clk.h>
> +#include <linux/clkdev.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_address.h>
> +
> +#include <asm/mach/irq.h>
> +#include <asm/global_timer.h>
> +#include <asm/localtimer.h>
> +
> +#define GT_COUNTER0	0x00
> +#define GT_COUNTER1	0x04
> +
> +#define GT_CONTROL	0x08
> +#define GT_CONTROL_TIMER_ENABLE		BIT(0)
> +#define GT_CONTROL_COMP_ENABLE		BIT(1)	/* banked */
> +#define GT_CONTROL_IRQ_ENABLE		BIT(2)	/* banked */
> +#define GT_CONTROL_AUTO_INC		BIT(3)	/* banked */
> +
> +#define GT_INT_STATUS	0x0c
> +#define GT_INT_STATUS_EVENT_FLAG	BIT(0)
> +
> +#define GT_COMP0	0x10
> +#define GT_COMP1	0x14
> +#define GT_AUTO_INC	0x18
> +
> +/*
> + * We are expecting to be clocked by the ARM peripheral clock.
> + *
> + * Note: it is assumed we are using a prescaler value of zero, so this is
> + * the units for all operations.
> + */
> +static void __iomem *gt_base;
> +static struct clk *gt_clk;
> +static unsigned long gt_clk_rate;
> +static int gt_ppi;
> +static struct clock_event_device __percpu **gt_evt;
> +static DEFINE_PER_CPU(bool, percpu_init_called);
> +static DEFINE_PER_CPU(struct clock_event_device, gt_clockevent);
> +
> +union gt_counter {
> +	cycle_t cycles;
> +	struct {
> +		uint32_t lower;
> +		uint32_t upper;
> +	};
> +};
> +
> +static union gt_counter gt_counter_read(void)
> +{
> +	union gt_counter res;
> +	uint32_t upper;
> +
> +	upper = readl(gt_base + GT_COUNTER1);
> +	do {
> +		res.upper = upper;
> +		res.lower = readl(gt_base + GT_COUNTER0);
> +		upper = readl(gt_base + GT_COUNTER1);
> +	} while (upper != res.upper);
> +
> +	return res;
> +}
> +
> +static void gt_compare_set(unsigned long delta, int periodic)
> +{
> +	union gt_counter counter = gt_counter_read();
> +	unsigned long ctrl = readl(gt_base + GT_CONTROL);
> +
> +	BUG_ON(!(ctrl & GT_CONTROL_TIMER_ENABLE));
> +	BUG_ON(ctrl & (GT_CONTROL_COMP_ENABLE |
> +		       GT_CONTROL_IRQ_ENABLE |
> +		       GT_CONTROL_AUTO_INC));
> +
> +	counter.cycles += delta;
> +	writel(counter.lower, gt_base + GT_COMP0);
> +	writel(counter.upper, gt_base + GT_COMP1);
> +
> +	ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE;
> +
> +	if (periodic) {
> +		writel(delta, gt_base + GT_AUTO_INC);
> +		ctrl |= GT_CONTROL_AUTO_INC;
> +	}
> +
> +	writel(ctrl, gt_base + GT_CONTROL);
> +}
> +
> +static void gt_clockevent_set_mode(enum clock_event_mode mode,
> +				   struct clock_event_device *clk)
> +{
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		gt_compare_set(gt_clk_rate/HZ, 1);
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +		/* period set, and timer enabled in 'next_event' hook */
> +		BUG_ON(readl(gt_base + GT_CONTROL) &
> +		       (GT_CONTROL_COMP_ENABLE |
> +			GT_CONTROL_IRQ_ENABLE |
> +			GT_CONTROL_AUTO_INC));
> +		/* Fall through */
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +	default:
> +		writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
> +		break;
> +	}
> +}
> +
> +static int gt_clockevent_set_next_event(unsigned long evt,
> +					struct clock_event_device *unused)
> +{
> +	gt_compare_set(evt, 0);
> +	return 0;
> +}
> +
> +static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id)
> +{
> +	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
> +
> +	writel(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS);
> +	evt->event_handler(evt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int __cpuinit gt_clockevents_init(struct clock_event_device *clk)
> +{
> +	struct clock_event_device **this_cpu_clk;
> +	int cpu = smp_processor_id();
> +
> +	clk->name = "Global Timer CE";
> +	clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
> +	clk->set_mode = gt_clockevent_set_mode;
> +	clk->set_next_event = gt_clockevent_set_next_event;
> +	this_cpu_clk = __this_cpu_ptr(gt_evt);
> +	*this_cpu_clk = clk;
> +	clk->irq = gt_ppi;
> +	clockevents_config_and_register(clk, gt_clk_rate,
> +					0xf, 0xffffffff);
> +	per_cpu(percpu_init_called, cpu) = true;
> +	enable_percpu_irq(clk->irq, IRQ_TYPE_NONE);
> +	return 0;
> +}
> +
> +static void gt_clockevents_stop(struct clock_event_device *clk)
> +{
> +	gt_clockevent_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
> +	disable_percpu_irq(clk->irq);
> +}
> +
> +static int __cpuinit gt_clockevents_setup(struct clock_event_device *clk)
> +{
> +	int cpu = smp_processor_id();
> +
> +	/* Use existing clock_event for boot cpu */
> +	if (per_cpu(percpu_init_called, cpu))
> +		return 0;
> +
> +	writel(0, gt_base + GT_CONTROL);
> +	writel(0, gt_base + GT_COUNTER0);
> +	writel(0, gt_base + GT_COUNTER1);
> +	writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
> +
> +	return gt_clockevents_init(clk);
> +}
> +
> +static cycle_t gt_clocksource_read(struct clocksource *cs)
> +{
> +	union gt_counter res = gt_counter_read();
> +	return res.cycles;
> +}
> +
> +static struct clocksource gt_clocksource = {
> +	.name	= "Global Timer CS",
> +	.rating	= 300,
> +	.read	= gt_clocksource_read,
> +	.mask	= CLOCKSOURCE_MASK(64),
> +	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
> +};
> +
> +static void __init gt_clocksource_init(void)
> +{
> +	writel(0, gt_base + GT_CONTROL);
> +	writel(0, gt_base + GT_COUNTER0);
> +	writel(0, gt_base + GT_COUNTER1);
> +	writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
> +
> +	gt_clocksource.shift = 20;
> +	gt_clocksource.mult =
> +		clocksource_hz2mult(gt_clk_rate, gt_clocksource.shift);
> +	clocksource_register(&gt_clocksource);
> +}
> +
> +static struct clk *gt_get_clock(void)
> +{
> +	struct clk *clk;
> +	int err;
> +
> +	clk = clk_get_sys("gt", NULL);
> +	if (IS_ERR(clk)) {
> +		pr_err("global-timer: clock not found: %ld\n", PTR_ERR(clk));
> +		return clk;
> +	}
> +
> +	err = clk_prepare_enable(clk);
> +	if (err) {
> +		pr_err("global-timer: clock prepare+enable failed: %d\n", err);
> +		clk_put(clk);
> +		return ERR_PTR(err);
> +	}
> +
> +	return clk;
> +}
> +
> +static struct local_timer_ops gt_lt_ops __cpuinitdata = {
> +	.setup	= gt_clockevents_setup,
> +	.stop	= gt_clockevents_stop,
> +};
> +
> +int __init global_timer_init(void __iomem *base, unsigned int timer_irq)
> +{
> +	unsigned int cpu = smp_processor_id();
> +	struct clock_event_device *evt = &per_cpu(gt_clockevent, cpu);
> +	int err = 0;
> +
> +	if (gt_base) {
> +		pr_warn("global-timer: invalid base address\n");
> +		return -EINVAL;
> +	}
> +
> +	gt_clk = gt_get_clock();
> +	if (IS_ERR(gt_clk)) {
> +		pr_warn("global-timer: clk not found\n");
> +		return -EINVAL;
> +	}
> +
> +	gt_evt = alloc_percpu(struct clock_event_device *);
> +	if (!gt_evt) {
> +		pr_warn("global-timer: can't allocate memory\n");
> +		return -ENOMEM;
> +	}
> +
> +	err = request_percpu_irq(timer_irq, gt_clockevent_interrupt,
> +				 "gt", gt_evt);
> +	if (err) {
> +		pr_warn("global-timer: can't register interrupt %d (%d)\n",
> +			timer_irq, err);
> +		goto out_free;
> +	}
> +
> +	gt_base = base;
> +	gt_clk_rate = clk_get_rate(gt_clk);
> +
> +	evt->irq = timer_irq;
> +	gt_ppi = timer_irq;
> +	evt->cpumask = cpumask_of(cpu);
> +
> +	gt_clocksource_init();
> +	gt_clockevents_init(evt);
> +	err =  local_timer_register(&gt_lt_ops);
> +	if (err) {
> +		pr_warn("global-timer: unable to register local timer.\n");
> +		goto out_irq;
> +	}
> +
> +	return 0;
> +
> +out_irq:
> +	free_percpu_irq(timer_irq, gt_evt);
> +out_free:
> +	free_percpu(gt_evt);
> +	return err;
> +}
> +
> +#ifdef CONFIG_OF
> +static void __init global_timer_of_register(struct device_node *np)
> +{
> +	struct clk *clk;
> +	int err = 0;
> +	int gt_ppi;
> +	static void __iomem *gt_base;
> +
> +	gt_ppi = irq_of_parse_and_map(np, 0);
> +	if (!gt_ppi) {
> +		err = -EINVAL;
> +		goto out;
> +	}
> +
> +	gt_base = of_iomap(np, 0);
> +	if (!gt_base) {
> +		err = -ENOMEM;
> +		goto out;
> +	}
> +
> +	clk = of_clk_get(np, 0);
> +	if (!IS_ERR(clk))
> +		clk_register_clkdev(clk, NULL, "gt");
> +
> +	global_timer_init(gt_base, gt_ppi);
> +
> +out:
> +	WARN(err, "Global timer register failed (%d)\n", err);
> +}
> +
> +CLOCKSOURCE_OF_DECLARE(arm_gt_a9, "arm,cortex-a9-global-timer",
> +			global_timer_of_register);
> +#endif
> 


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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
       [not found] ` <1368022248-2153-1-git-send-email-srinivas.kandagatla@st.com>
@ 2013-05-08 14:34   ` Arnd Bergmann
  2013-05-08 14:39     ` Jean-Christophe PLAGNIOL-VILLARD
                       ` (3 more replies)
  0 siblings, 4 replies; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 14:34 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: gregkh, jslaby, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Samuel Ortiz, Linus Walleij, Stuart Menefy,
	Shawn Guo, Olof Johansson, Jason Cooper, Stephen Warren,
	Maxime Ripard, Nicolas Pitre, Will Deacon, Dave Martin,
	Marc Zyngier, Viresh Kumar, Mark Brown, Dong Aisheng, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial,
	Stephen Gallimore

On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>

> +*st-asc(Serial Port)
> +
> +Required properties:
> +- compatible : Should be "st,asc".

Are there any hardware revision numbers for the asc? If there are potentially
incompatible or backwards-compatible variants, it would be good to include
the version in this string.

> +- reg, reg-names, interrupts, interrupt-names	: Standard way to define device
> +			resources with names. look in
> +			Documentation/devicetree/bindings/resource-names.txt
> +
> +Optional properties:
> +- st,hw-flow-ctrl	bool flag to enable hardware flow control.
> +- st,force-m1		bool flat to force asc to be in Mode-1 recommeded
> +			for high bit rates (above 19.2K)
> +Example:
> +serial@fe440000{
> +    compatible    = "st,asc";
> +    reg         = <0xfe440000 0x2c>;
> +    interrupts     =  <0 209 0>;
> +};

I would also recommed adding a way to set the default baud rate through
a property. Following the example of the 8250 driver, you should probably
call that "current-speed".

> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index 7e7006f..346f325 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1484,6 +1484,25 @@ config SERIAL_RP2_NR_UARTS
>  	  If multiple cards are present, the default limit of 32 ports may
>  	  need to be increased.
>  
> +config SERIAL_ST_ASC
> +	tristate "ST ASC serial port support"
> +	depends on PLAT_STIXXXX
> +	default y
> +	select SERIAL_CORE
> +	help
> +	  This driver is for the on-chip Asychronous Serial Controller on
> +	  STMicroelectronics STixxxx SoCs.
> +	  ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
> +	  It support all industry standard baud rates.
> +
> +	  If unsure, say N.

I would not make it "default y".

> +config SERIAL_ST_ASC_CONSOLE
> +	bool "Support for console on ST ASC"
> +	depends on SERIAL_ST_ASC
> +	default y
> +	select SERIAL_CORE_CONSOLE
> +
>  endmenu

This needs to be "depends on SERIAL_ST_ASC=y". You would get a link error
if you try to make SERIAL_ST_ASC a loadable module and SERIAL_ST_ASC_CONSOLE
built-in.

> +
> +static struct asc_port asc_ports[ASC_MAX_PORTS];
> +static struct uart_driver asc_uart_driver;
> +
> +/*---- Forward function declarations---------------------------*/
> +static irqreturn_t asc_interrupt(int irq, void *ptr);
> +static void asc_transmit_chars(struct uart_port *);
> +static int asc_set_baud(struct asc_port *ascport, int baud);
> +

Please remove all forward declarations, by reordering the functions in
the way they are called.


> diff --git a/drivers/tty/serial/st-asc.h b/drivers/tty/serial/st-asc.h
> new file mode 100644
> index 0000000..e59f818
> --- /dev/null
> +++ b/drivers/tty/serial/st-asc.h
> +#ifndef _ST_ASC_H
> +#define _ST_ASC_H
> +
> +#include <linux/serial_core.h>
> +#include <linux/clk.h>
> +
> +struct asc_port {
> +	struct uart_port port;
> +	struct clk *clk;
> +	unsigned int hw_flow_control:1;
> +	unsigned int check_parity:1;
> +	unsigned int force_m1:1;
> +};

Since this header file is only used in one place, just merge it into
the driver itself.

> +#define ASC_MAJOR		204
> +#define ASC_MINOR_START		40

I don't know what the current policy is on allocating major/minor numbers,
but I'm sure you cannot just reuse one that is already used.

Documentation/devices.txt lists the ones that are officially assigned.
Can't you use dynamic allocation here?

	Arnd

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

* Re: [RFC 2/8] ARM:global_timer: Add ARM global timer support.
  2013-05-08 14:11 ` [RFC 2/8] ARM:global_timer: Add ARM global timer support Srinivas KANDAGATLA
  2013-05-08 14:26   ` Rob Herring
@ 2013-05-08 14:38   ` Arnd Bergmann
  2013-05-08 14:51     ` Steffen Trumtrar
  2013-05-09 14:07     ` Srinivas KANDAGATLA
  1 sibling, 2 replies; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 14:38 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: linux, will.deacon, Rob Landley, Grant Likely, Rob Herring,
	Samuel Ortiz, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Dave Martin,
	Marc Zyngier, Viresh Kumar, Mark Brown, Dong Aisheng, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> From: Stuart Menefy <stuart.menefy@st.com>
> 
> This is a simple driver for the global timer module found in the Cortex
> A9-MP cores from revision r1p0 onwards. This should be able to perform
> the functions of the system timer and the local timer in an SMP system.
> 
> The global timer has the following features:
>     The global timer is a 64-bit incrementing counter with an
> auto-incrementing feature. It continues incrementing after sending
> interrupts. The global timer is memory mapped in the private memory
> region.
>     The global timer is accessible to all Cortex-A9 processors in the
> cluster. Each Cortex-A9 processor has a private 64-bit comparator that
> is used to assert a private interrupt when the global timer has reached
> the comparator value. All the Cortex-A9 processors in a design use the
> banked ID, ID27, for this interrupt. ID27 is sent to the Interrupt
> Controller as a Private Peripheral Interrupt. The global timer is
> clocked by PERIPHCLK.
> 
> Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>

Are you sure we don't already have a driver for this? It sounds unlikely
that you are the first one to do this when the hardware is so common.

>  Documentation/devicetree/bindings/arm/gt.txt |   21 ++
>  arch/arm/Kconfig                             |    6 +
>  arch/arm/include/asm/global_timer.h          |   12 +
>  arch/arm/kernel/Makefile                     |    1 +
>  arch/arm/kernel/global_timer.c               |  325 ++++++++++++++++++++++++++
>  5 files changed, 365 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/gt.txt
>  create mode 100644 arch/arm/include/asm/global_timer.h
>  create mode 100644 arch/arm/kernel/global_timer.c

Move it into drivers/clocksource?
 
> diff --git a/arch/arm/include/asm/global_timer.h b/arch/arm/include/asm/global_timer.h
> new file mode 100644
> index 0000000..46f9188
> --- /dev/null
> +++ b/arch/arm/include/asm/global_timer.h
> @@ -0,0 +1,12 @@
> +int __init global_timer_init(void __iomem *base, unsigned int timer_irq);

I don't see a need to call this from platform code for non-DT platforms, it
can easily be used with CLOCKSOURCE_OF_DECLARE() all the time I think.

	Arnd

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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 14:34   ` [RFC 1/8] serial:st-asc: Add ST ASC driver Arnd Bergmann
@ 2013-05-08 14:39     ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 18:18       ` Srinivas KANDAGATLA
  2013-05-08 18:02     ` Srinivas KANDAGATLA
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 64+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-08 14:39 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Srinivas KANDAGATLA, linux-doc, Viresh Kumar, Will Deacon,
	jslaby, Russell King, Samuel Ortiz, Nicolas Pitre,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, gregkh, Mark Brown, linux-kernel

On 16:34 Wed 08 May     , Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> > From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> 
> > +*st-asc(Serial Port)
> > +
> > +Required properties:
> > +- compatible : Should be "st,asc".
> 
> Are there any hardware revision numbers for the asc? If there are potentially
> incompatible or backwards-compatible variants, it would be good to include
> the version in this string.

The st,asc come from st20 or st200 IIRC which was not ARM but a ST arch
and then used on st40 series

an the st,asc for st200 and st40 are not compatible completly
> 
> > +- reg, reg-names, interrupts, interrupt-names	: Standard way to define device
> > +			resources with names. look in
> > +			Documentation/devicetree/bindings/resource-names.txt
> > +
> > +Optional properties:
> > +- st,hw-flow-ctrl	bool flag to enable hardware flow control.
> > +- st,force-m1		bool flat to force asc to be in Mode-1 recommeded
> > +			for high bit rates (above 19.2K)
> > +Example:
> > +serial@fe440000{
> > +    compatible    = "st,asc";
> > +    reg         = <0xfe440000 0x2c>;
> > +    interrupts     =  <0 209 0>;
> > +};
> 
> I would also recommed adding a way to set the default baud rate through
> a property. Following the example of the 8250 driver, you should probably
> call that "current-speed".
on st it has always be 38k

> 
> > diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> > index 7e7006f..346f325 100644
> > --- a/drivers/tty/serial/Kconfig
> > +++ b/drivers/tty/serial/Kconfig
> > @@ -1484,6 +1484,25 @@ config SERIAL_RP2_NR_UARTS
> >  	  If multiple cards are present, the default limit of 32 ports may
> >  	  need to be increased.
> >  
> > +config SERIAL_ST_ASC
> > +	tristate "ST ASC serial port support"
> > +	depends on PLAT_STIXXXX
> > +	default y
> > +	select SERIAL_CORE
> > +	help
> > +	  This driver is for the on-chip Asychronous Serial Controller on
> > +	  STMicroelectronics STixxxx SoCs.
> > +	  ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
> > +	  It support all industry standard baud rates.
> > +
> > +	  If unsure, say N.
> 
> I would not make it "default y".
me too
> 
> > +config SERIAL_ST_ASC_CONSOLE
> > +	bool "Support for console on ST ASC"
> > +	depends on SERIAL_ST_ASC
> > +	default y
> > +	select SERIAL_CORE_CONSOLE
> > +
> >  endmenu
> 
> This needs to be "depends on SERIAL_ST_ASC=y". You would get a link error
> if you try to make SERIAL_ST_ASC a loadable module and SERIAL_ST_ASC_CONSOLE
> built-in.
> 
> > +
> > +static struct asc_port asc_ports[ASC_MAX_PORTS];
> > +static struct uart_driver asc_uart_driver;
> > +
> > +/*---- Forward function declarations---------------------------*/
> > +static irqreturn_t asc_interrupt(int irq, void *ptr);
> > +static void asc_transmit_chars(struct uart_port *);
> > +static int asc_set_baud(struct asc_port *ascport, int baud);
> > +
> 
> Please remove all forward declarations, by reordering the functions in
> the way they are called.
> 
and drop the dummy functions
> 
> > diff --git a/drivers/tty/serial/st-asc.h b/drivers/tty/serial/st-asc.h
> > new file mode 100644
> > index 0000000..e59f818
> > --- /dev/null
> > +++ b/drivers/tty/serial/st-asc.h
> > +#ifndef _ST_ASC_H
> > +#define _ST_ASC_H
> > +
> > +#include <linux/serial_core.h>
> > +#include <linux/clk.h>
> > +
> > +struct asc_port {
> > +	struct uart_port port;
> > +	struct clk *clk;
> > +	unsigned int hw_flow_control:1;
> > +	unsigned int check_parity:1;
> > +	unsigned int force_m1:1;
> > +};
> 
> Since this header file is only used in one place, just merge it into
> the driver itself.
> 
> > +#define ASC_MAJOR		204
> > +#define ASC_MINOR_START		40
> 
> I don't know what the current policy is on allocating major/minor numbers,
> but I'm sure you cannot just reuse one that is already used.
> 
> Documentation/devices.txt lists the ones that are officially assigned.
> Can't you use dynamic allocation here?
> 
> 	Arnd
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-08 14:11 ` [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs Srinivas KANDAGATLA
@ 2013-05-08 14:50   ` Arnd Bergmann
  2013-05-08 15:01     ` Mark Brown
  2013-05-08 17:32     ` Srinivas KANDAGATLA
  0 siblings, 2 replies; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 14:50 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: dong.aisheng, sameo, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> 
> This patch introduces syscon_claim, syscon_read, syscon_write,
> syscon_release APIs to help drivers to use syscon registers in much more
> flexible way.
> 
> With this patch, a driver can claim few/all bits in the syscon registers
> and do read/write and then release them when its totally finished with
> them, in the mean time if another driver requests same bits or registers
> the API will detect conflit and return error to the second request.
> 
> Reason to introduce this API.
> System configuration/control registers are very basic configuration
> registers arranged in groups across ST Settop Box parts. These registers
> are independent of IP itself. Many IPs, clock, pad and other functions
> are wired up to these registers.
> 
> In many cases a single syconf register contains bits related to multiple
> devices, and therefore it need to be shared across multiple drivers at
> bit level. The same IP block can have different syscon mappings on
> different SOCs.
> 
> Typically in a SOC there will be more than hundreds of these registers,
> which are again divided into groups.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> CC: Stuart Menefy <stuart.menefy@st.com>

My feeling is that syscon is the wrong place for this functionality,
since regmap already handles (some of?) these issues. If you need
additional synchronization, it's probably best to extend regmap
as needed so other code besides syscon can take advantage of that
as well.

	Arnd

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

* Re: [RFC 2/8] ARM:global_timer: Add ARM global timer support.
  2013-05-08 14:38   ` Arnd Bergmann
@ 2013-05-08 14:51     ` Steffen Trumtrar
  2013-05-09 14:07     ` Srinivas KANDAGATLA
  1 sibling, 0 replies; 64+ messages in thread
From: Steffen Trumtrar @ 2013-05-08 14:51 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Srinivas KANDAGATLA, linux-doc, Viresh Kumar, will.deacon,
	Jiri Slaby, linux, Samuel Ortiz, Nicolas Pitre, linux-serial,
	Jason Cooper, devicetree-discuss, Rob Herring, Stuart Menefy,
	Stephen Warren, Dong Aisheng, linux-arm-kernel,
	Greg Kroah-Hartman, Mark Brown, linux-kernel

On Wed, May 08, 2013 at 04:38:22PM +0200, Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> > From: Stuart Menefy <stuart.menefy@st.com>
> > 
> > This is a simple driver for the global timer module found in the Cortex
> > A9-MP cores from revision r1p0 onwards. This should be able to perform
> > the functions of the system timer and the local timer in an SMP system.
> > 
> > The global timer has the following features:
> >     The global timer is a 64-bit incrementing counter with an
> > auto-incrementing feature. It continues incrementing after sending
> > interrupts. The global timer is memory mapped in the private memory
> > region.
> >     The global timer is accessible to all Cortex-A9 processors in the
> > cluster. Each Cortex-A9 processor has a private 64-bit comparator that
> > is used to assert a private interrupt when the global timer has reached
> > the comparator value. All the Cortex-A9 processors in a design use the
> > banked ID, ID27, for this interrupt. ID27 is sent to the Interrupt
> > Controller as a Private Peripheral Interrupt. The global timer is
> > clocked by PERIPHCLK.
> > 
> > Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
> > Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> >
> 
> Are you sure we don't already have a driver for this? It sounds unlikely
> that you are the first one to do this when the hardware is so common.
> 

Isn't this the same as arch/arm/kernel/smp_twd.c ?
That is atleast the timer I used with Cortex-A9. I don't think the core
has another one. But maybe I'm wrong.

> >  Documentation/devicetree/bindings/arm/gt.txt |   21 ++
> >  arch/arm/Kconfig                             |    6 +
> >  arch/arm/include/asm/global_timer.h          |   12 +
> >  arch/arm/kernel/Makefile                     |    1 +
> >  arch/arm/kernel/global_timer.c               |  325 ++++++++++++++++++++++++++
> >  5 files changed, 365 insertions(+), 0 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/arm/gt.txt
> >  create mode 100644 arch/arm/include/asm/global_timer.h
> >  create mode 100644 arch/arm/kernel/global_timer.c
> 
> Move it into drivers/clocksource?
>  
> > diff --git a/arch/arm/include/asm/global_timer.h b/arch/arm/include/asm/global_timer.h
> > new file mode 100644
> > index 0000000..46f9188
> > --- /dev/null
> > +++ b/arch/arm/include/asm/global_timer.h
> > @@ -0,0 +1,12 @@
> > +int __init global_timer_init(void __iomem *base, unsigned int timer_irq);
> 
> I don't see a need to call this from platform code for non-DT platforms, it
> can easily be used with CLOCKSOURCE_OF_DECLARE() all the time I think.
> 

Regards,
Steffen

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-08 14:50   ` Arnd Bergmann
@ 2013-05-08 15:01     ` Mark Brown
  2013-05-08 17:42       ` Srinivas KANDAGATLA
  2013-05-08 17:32     ` Srinivas KANDAGATLA
  1 sibling, 1 reply; 64+ messages in thread
From: Mark Brown @ 2013-05-08 15:01 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Srinivas KANDAGATLA, dong.aisheng, sameo, Rob Landley,
	Grant Likely, Rob Herring, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Jiri Slaby, Stuart Menefy, Shawn Guo,
	Olof Johansson, Jason Cooper, Stephen Warren, Maxime Ripard,
	Nicolas Pitre, Will Deacon, Dave Martin, Marc Zyngier,
	Viresh Kumar, linux-doc, linux-kernel, devicetree-discuss,
	linux-arm-kernel, linux-serial

[-- Attachment #1: Type: text/plain, Size: 662 bytes --]

On Wed, May 08, 2013 at 04:50:22PM +0200, Arnd Bergmann wrote:

> > In many cases a single syconf register contains bits related to multiple
> > devices, and therefore it need to be shared across multiple drivers at
> > bit level. The same IP block can have different syscon mappings on
> > different SOCs.

> My feeling is that syscon is the wrong place for this functionality,
> since regmap already handles (some of?) these issues. If you need
> additional synchronization, it's probably best to extend regmap
> as needed so other code besides syscon can take advantage of that
> as well.

This sounds like regmap_update_bits() ought to be all that's needed.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [RFC 4/8] pinctrl:stixxxx: Add pinctrl and pinconf support.
       [not found] ` <1368022284-2283-1-git-send-email-srinivas.kandagatla@st.com>
@ 2013-05-08 15:06   ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 16:27     ` Srinivas KANDAGATLA
  0 siblings, 1 reply; 64+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-08 15:06 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: linus.walleij, Viresh Kumar, Will Deacon, Jiri Slaby,
	Russell King, Samuel Ortiz, Nicolas Pitre, linux-doc,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Greg Kroah-Hartman, Mark Brown,
	linux-kernel

On 15:11 Wed 08 May     , Srinivas KANDAGATLA wrote:
> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> 
> This patch add pinctrl support to ST SoCs.
> 
> About hardware:
> ST Set-Top-Box parts have two blocks called PIO and PIO-mux which handle
> pin configurations.
> 
> Each multi-function pin is controlled, driven and routed through the PIO
> multiplexing block. Each pin supports GPIO functionality (ALT0) and
> multiple alternate functions(ALT1 - ALTx) that directly connect the pin
> to different hardware blocks. When a pin is in GPIO mode, Output Enable
> (OE), Open Drain(OD), and Pull Up (PU) are driven by the related PIO
> block. Otherwise the PIO multiplexing block configures these parameters
> and retiming the signal.
> 
g> About driver:
> This pinctrl driver manages both PIO and PIO-mux block using pinctrl,
> pinconf, pinmux, gpio subsystems. All the pinctrl related config
> information can only come from device trees.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> CC: Stephen Gallimore <stephen.gallimore@st.com>
> CC: Stuart Menefy <stuart.menefy@st.com>
> ---
>  .../bindings/pinctrl/pinctrl-stixxxx.txt           |  160 +++
>  drivers/pinctrl/Kconfig                            |   13 +
>  drivers/pinctrl/Makefile                           |    1 +
>  drivers/pinctrl/pinctrl-stixxxx.c                  | 1151 ++++++++++++++++++++
>  drivers/pinctrl/pinctrl-stixxxx.h                  |  197 ++++
the pinctrl is present in older SoC ST40 not only stixxx

and you must provide a proper name not stixxxx

>  5 files changed, 1522 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
>  create mode 100644 drivers/pinctrl/pinctrl-stixxxx.c
>  create mode 100644 drivers/pinctrl/pinctrl-stixxxx.h
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
> new file mode 100644
> index 0000000..b0a93b5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
> @@ -0,0 +1,160 @@
> +*ST pin controller.
> +
> +Each multi-function pin is controlled, driven and routed through the
> +PIO multiplexing block. Each pin supports GPIO functionality (ALT0)
> +and multiple alternate functions(ALT1 - ALTx) that directly connect
> +the pin to different hardware blocks.
> +
> +When a pin is in GPIO mode, Output Enable (OE), Open Drain(OD), and
> +Pull Up (PU) are driven by the related PIO block.
HighZ too

this driver look very similar with AT91 we should consolidate at binding and C
level
> 
> ---
> +
> +ST pinctrl driver controls PIO multiplexing block and also interacts with
> +gpio driver to configure a pin.
> +
> +Required properties: (PIO multiplexing block)
> +- compatible	: should be "st,stixxxx-pinctrl"
> +			each subnode should set "st,stixxxx-gpio"
> +			as compatible for each gpio-controller bank.
first soc where the IP is present
> +- gpio-controller : Indicates this device is a GPIO controller
> +- #gpio-cells	  : Should be one. The first cell is the pin number.
> +- #retime-delay-cells	: Should be number of possible retime delays.
> +- st,retime-in-delay	: Should be array of delays in nsecs.
> +- st,retime-out-delay	: Should be array of delays in nsecs.
> +- retime-style		: Should indicate which type of retime is used.
> +			possible values are "none", "packed" and "dedicated".
always prefix st, when specific property
st,
> +- st,retime-offset	: phandle to retime offsets in retime registers.
> +		These are not necessary for "dedicated" retime-style registers.
> +	- clk1notclk0	: Should define offset for clk1not clk0 in retime register.
> +	- delay-lsb	: Should define offset for delay-lsb in retime register.
> +	- delay-msb	: Should define offset for delay msb in retime register.
> +	- invertclk	: Should define offset for invertclk in retime register.
> +	- retime	: Should define offset for retime in retime register.
> +	- clknotdata	: Should define offset for clknotdata in retime register.
> +	- double_edge	: Should define offset for double edge in retime register.

As much as I like to describe the IP in the DT, I think it's too much this
time move this to C and use the compatible or detect it on the hardware to
handle this 

> +- st,alt-control		: Should be sysconf to control alternate function on pio.
> +- st,oe-control		: Should be sysconf to control output enable on pio.
> +- st,pu-control		: Should be sysconf to control pull up on pio.
> +- st,od-control		: Should be sysconf to control open drain on pio.
> +- st,retime-style		: Should indicate which type of retime is used.
> +			possible values are "none", "packed" and "dedicated".
> +- st,retime-pin-mask	: Should be mask to specify which pins can be retimed.
> +- retime-control[0...N]: These properties point to sysconfs which control retime.
> +			Depending on retime-style the number of retime-controls
> +			vary: 2 for "packed"; 8 for "dedicated".


> +- st,bank-name		: Should be a name string for this bank.
> +
> +Example:
> +	pio_retime_offset: pio-retime-offset {
> +		clk1notclk0	= <0>;
> +		delay-lsb	= <2>;
> +		delay-msb	= <3>;
> +		invertclk	= <4>;
> +		retime		= <5>;
> +		clknotdata	= <6>;
> +		double-edge	= <7>;
> +	};
> +
> +	pin-controller {
> +		#retime-delay-cells = <4>;
> +		compatible = "st,stixxxx-pinctrl", "simple-bus";
> +		st,retime-offset = <&pio_retime_offset>;
> +		st,retime-in-delay = <0 500 1000 1500>;
> +		st,retime-out-delay = <0 1000 2000 3000>;
> +		ranges;
> +		PIO0: pinctrl@fe610000 {
> +			gpio-controller;
> +			#gpio-cells = <1>;
> +			compatible = "st,stixxxx-gpio";
> +			reg = <0xfe610000 0x100>;
> +			st,bank-name  = "PIO0";
> +			st,alt-control = <&SYSCONF_SBC(0) 0 31>;
> +			st,oe-control = <&SYSCONF_SBC(5)  0 7>;
> +			st,pu-control = <&SYSCONF_SBC(7)  0 7>;
> +			st,od-control = <&SYSCONF_SBC(9)  0 7>;
> +			st,retime-style = "packed";
> +			st,retime-pin-mask = <0xff>;
> +			st,retime-control0 = <&SYSCONF_SBC(16) 0 31>;
> +			st,retime-control1 = <&SYSCONF_SBC(17) 0 31>;
> +		};
> +		...
> +		pin-functions nodes follow...
> +	};
> +
> +
> +Contents of function subnode node:
> +----------------------
> +Required properties for pin configuration node:
> +- st,function	: Should be alternate function number associated
> +		with this set of pins.
> +		possible altfunction values:
> +		ALT1
> +		ALT2
> +		ALT3
> +		ALT4
> +		ALT5
> +		ALT6
> +		ALT7
use number in the DoC


> +
> +- st,pins	: Child node with list of pins with configuration.
> +
> +Below is the format of how each pin conf should look like.
> +
> +<bank offset mode rt_type rt_delay rt_clk>
> +
> +Every PIO is represented with 4-7 parameters depending on retime configuration.
> +Each parameter is explained as below.
> +
> +-bank		: Should be bank phandle to which this PIO belongs.
> +-offset		: Offset in the PIO bank.
> +-mode		:pin configuration is selected from one of the below values.
> +		IN
> +		IN_PU
> +		OUT
> +		BIDIR
> +		BIDIR_PU
ditto
> +
> +-rt_type	Retiming Configuration for the pin.
> +		Possible retime configuration are:
> +
> +		-------		-------------
> +		value		args
> +		-------		-------------
> +		NICLK		<delay> <clk>
> +		ICLK_IO		<delay> <clk>
> +		BYPASS		<delay>
> +		DE_IO		<delay> <clk>
> +		SE_ICLK_IO	<delay> <clk>
> +		SE_NICLK_IO	<delay> <clk>
> +
> +- delay	is retime delay in pico seconds.
> +		Possible values are: refer to retime-in/out-delays
> +
> +- rt_clk	:clk to be use for retime.
> +		Possible values are:
> +		CLK_A
> +		CLK_B
> +		CLK_C
> +		CLK_D
> +
> +Example of mmcclk pin which is a bi-direction pull pu with retime config
> +as non inverted clock retimed with CLK_B and delay of 0 pico seconds:
> +
> +pin-controller {
> +	...
> +	mmc0 {
> +		pinctrl_mmc: mmc {
> +			st,function = <ALT4>;
> +			st,pins {
> +				mmcclk = <&PIO13 4 BIDIR_PU NICLK  0  CLK_B>;
> +				...
> +			};
> +		};
> +	...
> +	};
> +};
> +
> +sdhci0:sdhci@fe810000{
> +	...
> +	pinctrl-names = "default";
> +	pinctrl-0	= <&pinctrl_mmc>;
> +};
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index 34f51d2..611a399 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -179,6 +179,19 @@ config PINCTRL_SUNXI
>  	select PINMUX
>  	select GENERIC_PINCONF
>  
> +config PINCTRL_STIXXXX
> +	bool "ST Microelectronics pin controller driver for STixxxx SoCs"
> +	depends on PLAT_STIXXXX
> +	select PINMUX
> +	select PINCONF
> +	select MFD_SYSCON
> +	help
> +	  Say yes here to support pinctrl interface on STixxxx SOCs.
> +	  This driver is used to control both PIO block and PIO-mux
> +	  block to configure a pin.
> +
> +	  If unsure, say N.
> +
>  config PINCTRL_TEGRA
>  	bool
>  	select PINMUX
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index f82cc5b..99a2c78 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -47,6 +47,7 @@ obj-$(CONFIG_PINCTRL_EXYNOS)	+= pinctrl-exynos.o
>  obj-$(CONFIG_PINCTRL_EXYNOS5440)	+= pinctrl-exynos5440.o
>  obj-$(CONFIG_PINCTRL_XWAY)	+= pinctrl-xway.o
>  obj-$(CONFIG_PINCTRL_LANTIQ)	+= pinctrl-lantiq.o
> +obj-$(CONFIG_PINCTRL_STIXXXX) 	+= pinctrl-stixxxx.o
>  
>  obj-$(CONFIG_PLAT_ORION)        += mvebu/
>  obj-$(CONFIG_ARCH_SHMOBILE)	+= sh-pfc/
> diff --git a/drivers/pinctrl/pinctrl-stixxxx.c b/drivers/pinctrl/pinctrl-stixxxx.c
> new file mode 100644
> index 0000000..7d2c59c
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-stixxxx.c
> @@ -0,0 +1,1151 @@
> +/*
> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
> + * Authors:
> + *	Srinivas Kandagatla <srinivas.kandagatla@st.com>
> + *
> + * 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.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_address.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/pinctrl/pinctrl.h>
> +#include <linux/pinctrl/pinmux.h>
> +#include <linux/pinctrl/pinconf.h>
> +#include <linux/platform_device.h>
> +#include "core.h"
> +#include "pinctrl-stixxxx.h"
> +
> +struct stixxxx_pinconf {
> +	int		pin;
> +	const char	*name;
> +	unsigned long	config;
> +};
> +
> +struct stixxxx_pmx_func {
> +	const char	*name;
> +	const char	**groups;
> +	unsigned	ngroups;
> +};
> +
> +struct stixxxx_pctl_group {
> +	const char		*name;
> +	unsigned int		*pins;
> +	unsigned		npins;
> +	int			altfunc;
> +	struct stixxxx_pinconf	*pin_conf;
> +};
> +
> +#define to_stixxxx_gpio_port(chip) \
> +		container_of(chip, struct stixxxx_gpio_port, gpio_chip)
> +
> +struct stixxxx_gpio_port {
> +	struct gpio_chip	gpio_chip;
> +	struct pinctrl_gpio_range range;
> +	void __iomem		*base;
> +	struct device_node	*of_node;
> +	const char		*bank_name;
> +};
> +
> +static struct stixxxx_gpio_port *gpio_ports[STIXXXX_MAX_GPIO_BANKS];
> +
> +struct stixxxx_pinctrl {
> +	struct device			*dev;
> +	struct pinctrl_dev		*pctl;
> +	int				nbanks;
> +	struct stixxxx_pmx_func		*functions;
> +	int				nfunctions;
> +	struct stixxxx_pctl_group	*groups;
> +	int				ngroups;
> +	struct stixxxx_pio_control	*pio_controls;
> +};
> +
> +/* Low level functions.. */
> +static void stixxxx_pinconf_set_direction(struct stixxxx_pio_control *pc,
> +				int pin_id, unsigned long config)
> +{
> +	struct syscon_field *output_enable;
> +	struct syscon_field *pull_up;
> +	struct syscon_field *open_drain;
> +	unsigned long oe_value, pu_value, od_value;
> +	unsigned long mask;
> +	int pin = stixxxx_gpio_pin(pin_id);
> +
> +	output_enable = pc->oe;
> +	pull_up = pc->pu;
> +	open_drain = pc->od;
> +
> +	mask = BIT(pin);
> +
> +	oe_value = syscon_read(output_enable);
> +	pu_value = syscon_read(pull_up);
> +	od_value = syscon_read(open_drain);
> +
> +	/* Clear old values */
> +	oe_value &= ~mask;
> +	pu_value &= ~mask;
> +	od_value &= ~mask;
> +
> +	if (config & STIXXXX_PINCONF_OE)
> +		oe_value |= mask;
> +	if (config & STIXXXX_PINCONF_PU)
> +		pu_value |= mask;
> +	if (config & STIXXXX_PINCONF_OD)
> +		od_value |= mask;
> +
> +	syscon_write(output_enable, oe_value);
> +	syscon_write(pull_up, pu_value);
> +	syscon_write(open_drain, od_value);
> +}
> +
> +static void stixxxx_pctl_set_function(struct stixxxx_pio_control *pc,
> +				int pin_id, int function)
> +{
> +	struct syscon_field *selector;
> +	int offset;
> +	unsigned long val;
> +	int pin = stixxxx_gpio_pin(pin_id);
> +
> +	selector = pc->alt;
> +	offset = pin * 4;
> +	val = syscon_read(selector);
> +	val &= ~(0xf << offset);
> +	val |= function << offset;
> +	syscon_write(selector, val);
> +}
> +
> +static unsigned long stixxxx_pinconf_delay_to_bit(unsigned int delay,
> +		const struct stixxxx_retime_params *rt_params,
> +		unsigned long config)
> +{
> +	unsigned int *delay_times;
> +	int num_delay_times, i, closest_index = -1;
> +	unsigned int closest_divergence = UINT_MAX;
> +
> +	if (STIXXXX_PINCONF_UNPACK_OE(config)) {
> +		delay_times = rt_params->delay_times_out;
> +		num_delay_times = rt_params->num_delay_times_out;
> +	} else {
> +		delay_times = rt_params->delay_times_in;
> +		num_delay_times = rt_params->num_delay_times_in;
> +	}
> +
> +	for (i = 0; i < num_delay_times; i++) {
> +		unsigned int divergence = abs(delay - delay_times[i]);
> +
> +		if (divergence == 0)
> +			return i;
> +
> +		if (divergence < closest_divergence) {
> +			closest_divergence = divergence;
> +			closest_index = i;
> +		}
> +	}
> +
> +	pr_warn("Attempt to set delay %d, closest available %d\n",
> +	     delay, delay_times[closest_index]);
> +
> +	return closest_index;
> +}
> +
> +static unsigned long stixxxx_pinconf_bit_to_delay(unsigned int index,
> +		const struct stixxxx_retime_params *rt_params,
> +		unsigned long output)
> +{
> +	unsigned int *delay_times;
> +	int num_delay_times;
> +
> +	if (output) {
> +		delay_times = rt_params->delay_times_out;
> +		num_delay_times = rt_params->num_delay_times_out;
> +	} else {
> +		delay_times = rt_params->delay_times_in;
> +		num_delay_times = rt_params->num_delay_times_in;
> +	}
> +
> +	if (index < num_delay_times) {
> +		return delay_times[index];
> +	} else {
> +		pr_warn("Delay not found in/out delay list\n");
> +		return 0;
> +	}
> +}
> +
> +static void stixxxx_pinconf_set_retime_packed(
> +		struct stixxxx_pio_control *pc,
> +		unsigned long config, int pin)
> +{
> +	const struct stixxxx_retime_params *rt_params = pc->rt_params;
> +	const struct stixxxx_retime_offset *offset = rt_params->retime_offset;
> +	struct syscon_field **regs;
> +	unsigned long values[2];
> +	unsigned long mask;
> +	int i, j;
> +	int clk = STIXXXX_PINCONF_UNPACK_RT_CLK(config);
> +	int clknotdata = STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config);
> +	int double_edge = STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
> +	int invertclk = STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config);
> +	int retime = STIXXXX_PINCONF_UNPACK_RT(config);
> +	unsigned long delay = stixxxx_pinconf_delay_to_bit(
> +			STIXXXX_PINCONF_UNPACK_RT_DELAY(config),
> +			pc->rt_params, config);
> +
> +	unsigned long rt_cfg =
> +		((clk		& 1) << offset->clk1notclk0_offset) |
> +		((clknotdata	& 1) << offset->clknotdata_offset) |
> +		((delay		& 1) << offset->delay_lsb_offset) |
> +		(((delay >> 1)  & 1) << offset->delay_msb_offset) |
> +		((double_edge	& 1) << offset->double_edge_offset) |
> +		((invertclk	& 1) << offset->invertclk_offset) |
> +		((retime	& 1) << offset->retime_offset);
> +
> +	regs = pc->retiming;
> +	values[0] = syscon_read(regs[0]);
> +	values[1] = syscon_read(regs[1]);
> +
> +	for (i = 0; i < 2; i++) {
> +		mask = BIT(pin);
> +		for (j = 0; j < 4; j++) {
> +			if (rt_cfg & 1)
> +				values[i] |= mask;
> +			else
> +				values[i] &= ~mask;
> +			mask <<= 8;
> +			rt_cfg >>= 1;
> +		}
> +	}
> +
> +	syscon_write(regs[0], values[0]);
> +	syscon_write(regs[1], values[1]);
> +}
> +
> +static void stixxxx_pinconf_set_retime_dedicated(
> +	struct stixxxx_pio_control *pc,
> +	unsigned long config, int pin)
> +{
> +	struct syscon_field *reg;
> +	int input = STIXXXX_PINCONF_UNPACK_OE(config) ? 0 : 1;
> +	int clk = STIXXXX_PINCONF_UNPACK_RT_CLK(config);
> +	int clknotdata = STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config);
> +	int double_edge = STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
> +	int invertclk = STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config);
> +	int retime = STIXXXX_PINCONF_UNPACK_RT(config);
> +	unsigned long delay = stixxxx_pinconf_delay_to_bit(
> +			STIXXXX_PINCONF_UNPACK_RT_DELAY(config),
> +			pc->rt_params, config);
> +
> +	unsigned long retime_config =
> +		((clk		& 0x3) << 0) |
> +		((clknotdata	& 0x1) << 2) |
> +		((delay		& 0xf) << 3) |
> +		((input		& 0x1) << 7) |
> +		((double_edge	& 0x1) << 8) |
> +		((invertclk	& 0x1) << 9) |
> +		((retime	& 0x1) << 10);
> +
> +	reg = pc->retiming[pin];
> +	syscon_write(reg, retime_config);
> +}
> +
> +static void stixxxx_pinconf_get_direction(struct stixxxx_pio_control *pc,
> +	int pin_id, unsigned long *config)
> +{
> +	unsigned long oe_value, pu_value, od_value;
> +	int pin = stixxxx_gpio_pin(pin_id);
> +
> +	oe_value = (syscon_read(pc->oe) >> pin) & 1;
> +	pu_value = (syscon_read(pc->pu) >> pin) & 1;
> +	od_value = (syscon_read(pc->od) >> pin) & 1;
> +
> +	STIXXXX_PINCONF_PACK_OE(*config, oe_value);
> +	STIXXXX_PINCONF_PACK_PU(*config, pu_value);
> +	STIXXXX_PINCONF_PACK_OD(*config, od_value);
> +}
> +
> +static int stixxxx_pinconf_get_retime_packed(
> +		struct stixxxx_pio_control *pc,
> +		int pin, unsigned long *config)
> +{
> +	const struct stixxxx_retime_params *rt_params = pc->rt_params;
> +	const struct stixxxx_retime_offset *offset = rt_params->retime_offset;
> +	unsigned long delay_bits, delay, rt_reduced;
> +	unsigned long rt_value[2];
> +	int i, j;
> +	int output = STIXXXX_PINCONF_UNPACK_OE(*config);
> +
> +	rt_value[0] = syscon_read(pc->retiming[0]);
> +	rt_value[1] = syscon_read(pc->retiming[1]);
> +
> +	rt_reduced = 0;
> +	for (i = 0; i < 2; i++) {
> +		for (j = 0; j < 4; j++) {
> +			if (rt_value[i] & (1<<((8*j)+pin)))
> +				rt_reduced |= 1 << ((i*4)+j);
> +		}
> +	}
> +
> +	STIXXXX_PINCONF_PACK_RT(*config,
> +			(rt_reduced >> offset->retime_offset) & 1);
> +	STIXXXX_PINCONF_PACK_RT_CLK(*config,
> +			(rt_reduced >> offset->clk1notclk0_offset) & 1);
> +	STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(*config,
> +			(rt_reduced >> offset->clknotdata_offset) & 1);
> +	STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(*config,
> +			(rt_reduced >> offset->double_edge_offset) & 1);
> +	STIXXXX_PINCONF_PACK_RT_INVERTCLK(*config,
> +			(rt_reduced >> offset->invertclk_offset) & 1);
> +
> +	delay_bits =  (((rt_reduced >> offset->delay_msb_offset) & 1)<<1) |
> +			((rt_reduced >> offset->delay_lsb_offset) & 1);
> +	delay =  stixxxx_pinconf_bit_to_delay(delay_bits, rt_params, output);
> +	STIXXXX_PINCONF_PACK_RT_DELAY(*config, delay);
> +	return 0;
> +}
> +
> +static int stixxxx_pinconf_get_retime_dedicated(
> +		struct stixxxx_pio_control *pc,
> +		int pin, unsigned long *config)
> +{
> +	unsigned long value;
> +	unsigned long delay_bits, delay;
> +	const struct stixxxx_retime_params *rt_params = pc->rt_params;
> +	int output = STIXXXX_PINCONF_UNPACK_OE(*config);
> +
> +	value = syscon_read(pc->retiming[pin]);
> +	STIXXXX_PINCONF_PACK_RT_CLK(*config, ((value >> 0) & 0x3));
> +	STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(*config, ((value >> 2) & 0x1));
> +	delay_bits = ((value >> 3) & 0xf);
> +	delay =  stixxxx_pinconf_bit_to_delay(delay_bits, rt_params, output);
> +	STIXXXX_PINCONF_PACK_RT_DELAY(*config, delay);
> +	STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(*config, ((value >> 8) & 0x1));
> +	STIXXXX_PINCONF_PACK_RT_INVERTCLK(*config, ((value >> 9) & 0x1));
> +	STIXXXX_PINCONF_PACK_RT(*config, ((value >> 10) & 0x1));
> +
> +	return 0;
> +}
> +
> +/* GPIO related functions */
> +
> +static inline void __stixxxx_gpio_set(struct stixxxx_gpio_port *port,
> +	unsigned offset, int value)
> +{
> +	if (value)
> +		writel(BIT(offset), port->base + REG_PIO_SET_POUT);
> +	else
> +		writel(BIT(offset), port->base + REG_PIO_CLR_POUT);
> +}
> +
> +static void stixxxx_gpio_direction(unsigned int gpio, unsigned int direction)
> +{
> +	int port_num = stixxxx_gpio_port(gpio);
> +	int offset = stixxxx_gpio_pin(gpio);
> +	struct stixxxx_gpio_port *port  = gpio_ports[port_num];
> +	int i = 0;
> +
> +	for (i = 0; i <= 2; i++) {
> +		if (direction & BIT(i))
> +			writel(BIT(offset), port->base + REG_PIO_SET_PC(i));
> +		else
> +			writel(BIT(offset), port->base + REG_PIO_CLR_PC(i));
> +	}
> +}
> +
> +static int stixxxx_gpio_request(struct gpio_chip *chip, unsigned offset)
> +{
> +	return pinctrl_request_gpio(chip->base + offset);
> +}
> +
> +static void stixxxx_gpio_free(struct gpio_chip *chip, unsigned offset)
> +{
> +	pinctrl_free_gpio(chip->base + offset);
> +}
> +
> +static int stixxxx_gpio_get(struct gpio_chip *chip, unsigned offset)
> +{
> +	struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
> +
> +	return (readl(port->base + REG_PIO_PIN) >> offset) & 1;
> +}
> +
> +static void stixxxx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
> +{
> +	struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
> +	__stixxxx_gpio_set(port, offset, value);
> +}
> +
> +static int stixxxx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
> +{
> +	pinctrl_gpio_direction_input(chip->base + offset);
> +	return 0;
> +}
> +
> +static int stixxxx_gpio_direction_output(struct gpio_chip *chip,
> +	unsigned offset, int value)
> +{
> +	struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
> +
> +	__stixxxx_gpio_set(port, offset, value);
> +	pinctrl_gpio_direction_output(chip->base + offset);
> +
> +	return 0;
> +}
> +
> +static int stixxxx_gpio_xlate(struct gpio_chip *gc,
> +			const struct of_phandle_args *gpiospec, u32 *flags)
> +{
> +	if (WARN_ON(gc->of_gpio_n_cells < 1))
> +		return -EINVAL;
> +
> +	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
> +		return -EINVAL;
> +
> +	if (gpiospec->args[0] > gc->ngpio)
> +		return -EINVAL;
> +
> +	return gpiospec->args[0];
> +}
> +
> +/* Pinctrl Groups */
> +static int stixxxx_pctl_get_groups_count(struct pinctrl_dev *pctldev)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +
> +	return info->ngroups;
> +}
> +
> +static const char *stixxxx_pctl_get_group_name(struct pinctrl_dev *pctldev,
> +				       unsigned selector)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +
> +	return info->groups[selector].name;
> +}
> +
> +static int stixxxx_pctl_get_group_pins(struct pinctrl_dev *pctldev,
> +	unsigned selector, const unsigned **pins, unsigned *npins)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +
> +	if (selector >= info->ngroups)
> +		return -EINVAL;
> +
> +	*pins = info->groups[selector].pins;
> +	*npins = info->groups[selector].npins;
> +
> +	return 0;
> +}
> +
> +static const inline struct stixxxx_pctl_group *stixxxx_pctl_find_group_by_name(
> +	const struct stixxxx_pinctrl *info, const char *name)
> +{
> +	int i;
> +
> +	for (i = 0; i < info->ngroups; i++) {
> +		if (!strcmp(info->groups[i].name, name))
> +			return &info->groups[i];
> +	}
> +
> +	return NULL;
> +}
> +
> +static int stixxxx_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
> +	struct device_node *np, struct pinctrl_map **map, unsigned *num_maps)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +	const struct stixxxx_pctl_group *grp;
> +	struct pinctrl_map *new_map;
> +	struct device_node *parent;
> +	int map_num, i;
> +
> +	grp = stixxxx_pctl_find_group_by_name(info, np->name);
> +	if (!grp) {
> +		dev_err(info->dev, "unable to find group for node %s\n",
> +			np->name);
> +		return -EINVAL;
> +	}
> +
> +	map_num = grp->npins + 1;
> +	new_map = devm_kzalloc(pctldev->dev,
> +				sizeof(*new_map) * map_num, GFP_KERNEL);
> +	if (!new_map)
> +		return -ENOMEM;
> +
> +	parent = of_get_parent(np);
> +	if (!parent) {
> +		devm_kfree(pctldev->dev, new_map);
> +		return -EINVAL;
> +	}
> +
> +	*map = new_map;
> +	*num_maps = map_num;
> +	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
> +	new_map[0].data.mux.function = parent->name;
> +	new_map[0].data.mux.group = np->name;
> +	of_node_put(parent);
> +
> +	/* create config map per pin */
> +	new_map++;
> +	for (i = 0; i < grp->npins; i++) {
> +		new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
> +		new_map[i].data.configs.group_or_pin =
> +				pin_get_name(pctldev, grp->pins[i]);
> +		new_map[i].data.configs.configs = &grp->pin_conf[i].config;
> +		new_map[i].data.configs.num_configs = 1;
> +	}
> +	dev_info(pctldev->dev, "maps: function %s group %s num %d\n",
> +		(*map)->data.mux.function, grp->name, map_num);
> +
> +	return 0;
> +}
> +
> +static void stixxxx_pctl_dt_free_map(struct pinctrl_dev *pctldev,
> +				struct pinctrl_map *map, unsigned num_maps)
> +{
> +}
> +
> +static struct pinctrl_ops stixxxx_pctlops = {
> +	.get_groups_count	= stixxxx_pctl_get_groups_count,
> +	.get_group_pins		= stixxxx_pctl_get_group_pins,
> +	.get_group_name		= stixxxx_pctl_get_group_name,
> +	.dt_node_to_map		= stixxxx_pctl_dt_node_to_map,
> +	.dt_free_map		= stixxxx_pctl_dt_free_map,
> +};
> +
> +/* Pinmux */
> +static int stixxxx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +
> +	return info->nfunctions;
> +}
> +
> +const char *stixxxx_pmx_get_fname(struct pinctrl_dev *pctldev,
> +	unsigned selector)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +
> +	return info->functions[selector].name;
> +}
> +
> +static int stixxxx_pmx_get_groups(struct pinctrl_dev *pctldev,
> +	unsigned selector, const char * const **grps, unsigned * const ngrps)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +	*grps = info->functions[selector].groups;
> +	*ngrps = info->functions[selector].ngroups;
> +
> +	return 0;
> +}
> +
> +static struct stixxxx_pio_control *stixxxx_get_pio_control(
> +			struct stixxxx_pinctrl *info, int pin_id)
> +{
> +	int port = stixxxx_gpio_port(pin_id);
> +	return &info->pio_controls[port];
> +}
> +
> +static int stixxxx_pmx_enable(struct pinctrl_dev *pctldev, unsigned fselector,
> +		unsigned group)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +	struct stixxxx_pinconf *conf = info->groups[group].pin_conf;
> +	struct stixxxx_pio_control *pc;
> +	int i;
> +
> +	for (i = 0; i < info->groups[group].npins; i++) {
> +		pc = stixxxx_get_pio_control(info, conf[i].pin);
> +		stixxxx_pctl_set_function(pc, conf[i].pin,
> +					info->groups[group].altfunc);
> +	}
> +
> +	return 0;
> +}
> +
> +static void stixxxx_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
> +		unsigned group)
> +{
> +}
> +
> +static int stixxxx_pmx_set_gpio_direction(struct pinctrl_dev *pctldev,
> +			struct pinctrl_gpio_range *range, unsigned gpio,
> +			bool input)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +	struct stixxxx_pio_control *pc = &info->pio_controls[range->id];
> +	/*
> +	 * When a PIO port is used in its primary function mode (altfunc = 0)
> +	 * Output Enable (OE), Open Drain(OD), and Pull Up (PU)
> +	 * for the primary PIO functions are driven by the related PIO block
> +	 */
> +	stixxxx_pctl_set_function(pc, gpio, 0);
> +	stixxxx_gpio_direction(gpio, input ?
> +		STIXXXX_GPIO_DIRECTION_IN : STIXXXX_GPIO_DIRECTION_OUT);
> +
> +	return 0;
> +}
> +
> +static struct pinmux_ops stixxxx_pmxops = {
> +	.get_functions_count	= stixxxx_pmx_get_funcs_count,
> +	.get_function_name	= stixxxx_pmx_get_fname,
> +	.get_function_groups	= stixxxx_pmx_get_groups,
> +	.enable			= stixxxx_pmx_enable,
> +	.disable		= stixxxx_pmx_disable,
> +	.gpio_set_direction	= stixxxx_pmx_set_gpio_direction,
> +};
> +
> +/* Pinconf  */
> +static void stixxxx_pinconf_get_retime(struct stixxxx_pio_control *pc,
> +	int pin_id, unsigned long *config)
> +{
> +	int pin = stixxxx_gpio_pin(pin_id);
> +	if (pc->rt_style == stixxxx_retime_style_packed)
> +		stixxxx_pinconf_get_retime_packed(pc, pin, config);
> +	else if (pc->rt_style == stixxxx_retime_style_dedicated)
> +		if ((BIT(pin) & pc->rt_pin_mask))
> +			stixxxx_pinconf_get_retime_dedicated(pc, pin, config);
> +}
> +
> +static void stixxxx_pinconf_set_retime(struct stixxxx_pio_control *pc,
> +	int pin_id, unsigned long config)
> +{
> +	int pin = stixxxx_gpio_pin(pin_id);
> +
> +	if (pc->rt_style == stixxxx_retime_style_packed)
> +		stixxxx_pinconf_set_retime_packed(pc, config, pin);
> +	else if (pc->rt_style == stixxxx_retime_style_dedicated)
> +		if ((BIT(pin) & pc->rt_pin_mask))
> +			stixxxx_pinconf_set_retime_dedicated(pc, config, pin);
> +}
> +
> +static int stixxxx_pinconf_set(struct pinctrl_dev *pctldev,
> +			     unsigned pin_id, unsigned long config)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +	struct stixxxx_pio_control *pc = stixxxx_get_pio_control(info, pin_id);
> +
> +	stixxxx_pinconf_set_direction(pc, pin_id, config);
> +	stixxxx_pinconf_set_retime(pc, pin_id, config);
> +	return 0;
> +}
> +
> +static int stixxxx_pinconf_get(struct pinctrl_dev *pctldev,
> +			     unsigned pin_id, unsigned long *config)
> +{
> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
> +	struct stixxxx_pio_control *pc = stixxxx_get_pio_control(info, pin_id);
> +
> +	*config = 0;
> +	stixxxx_pinconf_get_direction(pc, pin_id, config);
> +	stixxxx_pinconf_get_retime(pc, pin_id, config);
> +
> +	return 0;
> +}
> +
> +static void stixxxx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
> +				   struct seq_file *s, unsigned pin_id)
> +{
> +	unsigned long config;
> +	stixxxx_pinconf_get(pctldev, pin_id, &config);
> +
> +	seq_printf(s, "[OE:%ld,PU:%ld,OD:%ld]\n"
> +		"\t\t[retime:%ld,invclk:%ld,clknotdat:%ld,"
> +		"de:%ld,rt-clk:%ld,rt-delay:%ld]",
> +		STIXXXX_PINCONF_UNPACK_OE(config),
> +		STIXXXX_PINCONF_UNPACK_PU(config),
> +		STIXXXX_PINCONF_UNPACK_OD(config),
> +		STIXXXX_PINCONF_UNPACK_RT(config),
> +		STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config),
> +		STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config),
> +		STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config),
> +		STIXXXX_PINCONF_UNPACK_RT_CLK(config),
> +		STIXXXX_PINCONF_UNPACK_RT_DELAY(config));
> +}
> +
> +static struct pinconf_ops stixxxx_confops = {
> +	.pin_config_get		= stixxxx_pinconf_get,
> +	.pin_config_set		= stixxxx_pinconf_set,
> +	.pin_config_dbg_show	= stixxxx_pinconf_dbg_show,
> +};
> +
> +/* pinctrl */
> +static struct pinctrl_desc stixxxx_pctl_desc = {
> +	.owner		= THIS_MODULE,
> +	.pctlops	= &stixxxx_pctlops,
> +	.pmxops		= &stixxxx_pmxops,
> +	.confops	= &stixxxx_confops,
> +};
> +
> +static int stixxxx_pinconf_dt_parse_rt_params(struct stixxxx_pinctrl *info,
> +	struct device_node *np,	struct stixxxx_retime_params *params)
> +{
> +	const __be32 *ip;
> +	struct device_node *offset_np;
> +	struct stixxxx_retime_offset *rt_offset;
> +	int delay_count = 0;
> +
> +	ip = of_get_property(np, "#retime-delay-cells", NULL);
> +	if (ip)
> +		delay_count = be32_to_cpup(ip);
> +	else
> +		pr_warn("No #retime-delay-cells specified\n");
> +
> +	params->num_delay_times_out = delay_count;
> +	params->num_delay_times_in = delay_count;
> +	params->delay_times_in = devm_kzalloc(info->dev,
> +				sizeof(u32) * delay_count, GFP_KERNEL);
> +	params->delay_times_out = devm_kzalloc(info->dev,
> +				sizeof(u32) * delay_count, GFP_KERNEL);
> +
> +	if (!params->delay_times_in || !params->delay_times_out)
> +		return -ENOMEM;
> +
> +	of_property_read_u32_array(np, "st,retime-in-delay",
> +				(u32 *)params->delay_times_in, delay_count);
> +	of_property_read_u32_array(np, "st,retime-out-delay",
> +				(u32 *)params->delay_times_out, delay_count);
> +
> +	offset_np = of_parse_phandle(np, "st,retime-offset", 0);
> +
> +	if (offset_np) {
> +		rt_offset = devm_kzalloc(info->dev,
> +				sizeof(*rt_offset), GFP_KERNEL);
> +		if (!rt_offset)
> +			return -ENOMEM;
> +
> +		params->retime_offset = rt_offset;
> +		WARN_ON(of_property_read_u32(offset_np, "retime",
> +					&rt_offset->retime_offset));
> +		WARN_ON(of_property_read_u32(offset_np, "clk1notclk0",
> +					&rt_offset->clk1notclk0_offset));
> +		WARN_ON(of_property_read_u32(offset_np, "clknotdata",
> +					&rt_offset->clknotdata_offset));
> +		WARN_ON(of_property_read_u32(offset_np, "double-edge",
> +					&rt_offset->double_edge_offset));
> +		WARN_ON(of_property_read_u32(offset_np, "invertclk",
> +					&rt_offset->invertclk_offset));
> +		WARN_ON(of_property_read_u32(offset_np, "delay-lsb",
> +					&rt_offset->delay_lsb_offset));
> +		WARN_ON(of_property_read_u32(offset_np, "delay-msb",
> +					&rt_offset->delay_msb_offset));
> +	}
> +
> +	return 0;
> +}
> +
> +static const char *gpio_compat = "st,stixxxx-gpio";
> +
> +static void stixxxx_pctl_dt_child_count(struct stixxxx_pinctrl *info,
> +				     struct device_node *np)
> +{
> +	struct device_node *child;
> +	for_each_child_of_node(np, child) {
> +		if (of_device_is_compatible(child, gpio_compat)) {
> +			info->nbanks++;
> +		} else {
> +			info->nfunctions++;
> +			info->ngroups += of_get_child_count(child);
> +		}
> +	}
> +}
> +
> +static int stixxxx_pctl_dt_get_retime_conf(struct device_node *np,
> +	struct stixxxx_pio_control *pc)
> +{
> +	const char *style;
> +	char name[20];
> +	unsigned int j;
> +	of_property_read_string(np, "st,retime-style", &style);
> +
> +	if (strcmp(style, "packed") == 0) {
> +		pc->rt_style = stixxxx_retime_style_packed;
> +		for (j = 0; j < 2; j++) {
> +			snprintf(name, sizeof(name), "st,retime-control%d", j);
> +			pc->retiming[j] = syscon_claim(np, name);
> +			if (!pc->retiming[j])
> +				return -ENODATA;
> +		}
> +	} else if (strcmp(style, "dedicated") == 0) {
> +		pc->rt_style = stixxxx_retime_style_dedicated;
> +		for (j = 0; j < 8; j++) {
> +			if ((1<<j) & pc->rt_pin_mask) {
> +				snprintf(name, sizeof(name),
> +						"st,retime-control%d", j);
> +				pc->retiming[j] = syscon_claim(np, name);
> +				if (!pc->retiming[j])
> +					return -ENODATA;
> +			}
> +		}
> +	} else if (strcmp(style, "none") == 0) {
> +		pc->rt_style = stixxxx_retime_style_none;
> +	}
> +
> +	return 0;
> +}
> +
> +static int stixxxx_pctl_dt_init(struct stixxxx_pinctrl *info,
> +			struct device_node *np)
> +{
> +	struct stixxxx_pio_control *pc;
> +	struct stixxxx_retime_params *rt_params;
> +	struct device *dev = info->dev;
> +	unsigned int i = 0;
> +	struct device_node *child = NULL;
> +
> +	pc = devm_kzalloc(dev, sizeof(*pc) * info->nbanks, GFP_KERNEL);
> +	rt_params = devm_kzalloc(dev, sizeof(*rt_params), GFP_KERNEL);
> +
> +	if (!pc || !rt_params)
> +		return -ENOMEM;
> +
> +	info->pio_controls = pc;
> +	if (stixxxx_pinconf_dt_parse_rt_params(info, np, rt_params))
> +		return -ENOMEM;
> +
> +	for_each_child_of_node(np, child) {
> +		if (of_device_is_compatible(child, gpio_compat)) {
> +			pc[i].rt_params = rt_params;
> +
> +			pc[i].alt = syscon_claim(child, "st,alt-control");
> +			if (!pc[i].alt)
> +				goto failed;
> +
> +			pc[i].oe = syscon_claim(child, "st,oe-control");
> +			if (!pc[i].oe)
> +				goto failed;
> +
> +			pc[i].pu = syscon_claim(child, "st,pu-control");
> +			if (!pc[i].pu)
> +				goto failed;
> +
> +			pc[i].od = syscon_claim(child, "st,od-control");
> +			if (!pc[i].od)
> +				goto failed;
> +
> +			of_property_read_u32(child, "st,retime-pin-mask",
> +							&pc[i].rt_pin_mask);
> +
> +			stixxxx_pctl_dt_get_retime_conf(child, &pc[i]);
> +			i++;
> +		}
> +	}
> +
> +	return 0;
> +failed:
> +	return -ENODATA;
> +}
> +
> +#define OF_GPIO_ARGS_MIN	(3)
> +/*
> + * Each pin is represented in of the below forms.
> + * <bank offset direction func rt_type rt_delay rt_clk>
> + */
> +static int stixxxx_pctl_dt_parse_groups(struct device_node *np,
> +	struct stixxxx_pctl_group *grp, struct stixxxx_pinctrl *info, int idx)
> +{
> +	/* bank pad direction val altfunction */
> +	const __be32 *list;
> +	struct property *pp;
> +	struct stixxxx_pinconf *conf;
> +	phandle phandle;
> +	struct device_node *pins;
> +	u32 pin;
> +	int i = 0, npins = 0, nr_props;
> +
> +	pins = of_get_child_by_name(np, "st,pins");
> +	if (!pins)
> +		return -ENODATA;
> +
> +	for_each_property_of_node(pins, pp) {
> +		/* Skip those we do not want to proceed */
> +		if (!strcmp(pp->name, "name"))
> +			continue;
> +
> +		if (pp  && (pp->length/sizeof(__be32)) >= OF_GPIO_ARGS_MIN) {
> +			npins++;
> +		} else {
> +			pr_warn("Invalid st,pins in %s node\n", np->name);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	grp->npins = npins;
> +	grp->name = np->name;
> +	grp->pins = devm_kzalloc(info->dev, npins * sizeof(u32), GFP_KERNEL);
> +	grp->pin_conf = devm_kzalloc(info->dev,
> +					npins * sizeof(*conf), GFP_KERNEL);
> +	of_property_read_u32(np, "st,function", &grp->altfunc);
> +
> +	if (!grp->pins || !grp->pin_conf)
> +		return -ENOMEM;
> +
> +	/* <bank offset direction func rt_type rt_delay rt_clk> */
> +	for_each_property_of_node(pins, pp) {
> +		if (!strcmp(pp->name, "name"))
> +			continue;
> +		nr_props = pp->length/sizeof(u32);
> +		list = pp->value;
> +		conf = &grp->pin_conf[i];
> +
> +		/* bank & offset */
> +		phandle = be32_to_cpup(list++);
> +		pin = be32_to_cpup(list++);
> +		conf->pin = of_get_named_gpio(pins, pp->name, 0);
> +		conf->name = pp->name;
> +		grp->pins[i] = conf->pin;
> +
> +		conf->config = 0;
> +		/* direction */
> +		conf->config |= be32_to_cpup(list++);
> +		/* rt_type rt_delay rt_clk */
> +		if (nr_props >= OF_GPIO_ARGS_MIN + 2) {
> +			/* rt_type */
> +			conf->config |= be32_to_cpup(list++);
> +			/* rt_delay */
> +			conf->config |= be32_to_cpup(list++);
> +			/* rt_clk */
> +			if (nr_props > OF_GPIO_ARGS_MIN + 2)
> +				conf->config |= be32_to_cpup(list++);
> +		}
> +		i++;
> +	}
> +	of_node_put(pins);
> +
> +	return 0;
> +}
> +
> +static int stixxxx_pctl_parse_functions(struct device_node *np,
> +			struct stixxxx_pinctrl *info, u32 index, int *grp_index)
> +{
> +	struct device_node *child;
> +	struct stixxxx_pmx_func *func;
> +	struct stixxxx_pctl_group *grp;
> +	int ret, i;
> +
> +	func = &info->functions[index];
> +	func->name = np->name;
> +	func->ngroups = of_get_child_count(np);
> +	if (func->ngroups <= 0) {
> +		dev_err(info->dev, "No groups defined\n");
> +		return -EINVAL;
> +	}
> +	func->groups = devm_kzalloc(info->dev,
> +			func->ngroups * sizeof(char *), GFP_KERNEL);
> +	if (!func->groups)
> +		return -ENOMEM;
> +
> +	i = 0;
> +	for_each_child_of_node(np, child) {
> +		func->groups[i] = child->name;
> +		grp = &info->groups[*grp_index];
> +		*grp_index += 1;
> +		ret = stixxxx_pctl_dt_parse_groups(child, grp, info, i++);
> +		if (ret)
> +			return ret;
> +	}
> +	dev_info(info->dev, "Function[%d\t name:%s,\tgroups:%d]\n",
> +				index, func->name, func->ngroups);
> +
> +	return 0;
> +}
> +
> +static int stixxxx_pctl_probe_dt(struct platform_device *pdev,
> +				 struct stixxxx_pinctrl *info)
> +{
> +	int ret = 0;
> +	int i = 0, j = 0, k = 0;
> +	struct pinctrl_pin_desc *pdesc;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device_node *child;
> +	int grp_index = 0;
> +
> +	stixxxx_pctl_dt_child_count(info, np);
> +	if (info->nbanks < 1) {
> +		dev_err(&pdev->dev, "you need atleast one gpio bank\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = stixxxx_pctl_dt_init(info, np);
> +	if (ret)
> +		return ret;
> +
> +	dev_info(&pdev->dev, "nbanks = %d\n", info->nbanks);
> +	dev_info(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
> +	dev_info(&pdev->dev, "ngroups = %d\n", info->ngroups);
> +	info->functions = devm_kzalloc(&pdev->dev,
> +		info->nfunctions * sizeof(*info->functions), GFP_KERNEL);
> +
> +	info->groups = devm_kzalloc(&pdev->dev,
> +		info->ngroups * sizeof(*info->groups) ,	GFP_KERNEL);
> +
> +	if (!info->functions || !info->groups)
> +		return -ENOMEM;
> +
> +	stixxxx_pctl_desc.npins = info->nbanks * STIXXXX_GPIO_PINS_PER_PORT;
> +	pdesc =	devm_kzalloc(&pdev->dev,
> +			sizeof(*pdesc) * stixxxx_pctl_desc.npins, GFP_KERNEL);
> +	if (!pdesc)
> +		return -ENOMEM;
> +
> +	stixxxx_pctl_desc.pins = pdesc;
> +
> +	for_each_child_of_node(np, child) {
> +		if (of_device_is_compatible(child, gpio_compat)) {
> +			for (j = 0; j < STIXXXX_GPIO_PINS_PER_PORT; j++, k++) {
> +				const char *port_name = NULL;
> +				pdesc->number = k;
> +				of_property_read_string(child, "st,bank-name",
> +							&port_name);
> +				pdesc->name = kasprintf(GFP_KERNEL, "%s[%d]",
> +							port_name ? : "PIO",
> +							port_name ? j : k);
> +				pdesc++;
> +			}
> +		} else {
> +			ret = stixxxx_pctl_parse_functions(child, info,
> +							i++, &grp_index);
> +			if (ret) {
> +				dev_err(&pdev->dev, "No functions found.\n");
> +				return ret;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int stixxxx_pctl_probe(struct platform_device *pdev)
> +{
> +	struct stixxxx_pinctrl *info;
> +	int ret, i;
> +
> +	if (!pdev->dev.of_node) {
> +		dev_err(&pdev->dev, "device node not found.\n");
> +		return -EINVAL;
> +	}
> +
> +	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
> +	if (!info)
> +		return -ENOMEM;
> +
> +	info->dev = &pdev->dev;
> +	platform_set_drvdata(pdev, info);
> +	ret = stixxxx_pctl_probe_dt(pdev, info);
> +	if (ret)
> +		return ret;
> +
> +	stixxxx_pctl_desc.name = dev_name(&pdev->dev);
> +	info->pctl = pinctrl_register(&stixxxx_pctl_desc, &pdev->dev, info);
> +	if (IS_ERR(info->pctl)) {
> +		dev_err(&pdev->dev, "Failed pinctrl registration\n");
> +		return PTR_ERR(info->pctl);
> +	}
> +
> +	for (i = 0; i < info->nbanks; i++)
> +		pinctrl_add_gpio_range(info->pctl, &gpio_ports[i]->range);
> +
> +	return 0;
> +}
> +
> +static struct gpio_chip stixxxx_gpio_template = {
> +	.request		= stixxxx_gpio_request,
> +	.free			= stixxxx_gpio_free,
> +	.get			= stixxxx_gpio_get,
> +	.set			= stixxxx_gpio_set,
> +	.direction_input	= stixxxx_gpio_direction_input,
> +	.direction_output	= stixxxx_gpio_direction_output,
> +	.ngpio			= STIXXXX_GPIO_PINS_PER_PORT,
> +	.of_gpio_n_cells	= 1,
> +	.of_xlate		= stixxxx_gpio_xlate,
> +};
> +
> +static int stixxxx_gpio_probe(struct platform_device *pdev)
> +{
> +	struct stixxxx_gpio_port *port;
> +	struct pinctrl_gpio_range *range;
> +	struct device_node *np  = pdev->dev.of_node;
> +	int port_num = of_alias_get_id(np, "gpio");
> +	struct resource *res;
> +	int err;
> +
> +	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
> +	if (!port)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	port->base = devm_request_and_ioremap(&pdev->dev, res);
> +	if (!port->base) {
> +		dev_err(&pdev->dev, "Can't get IO memory mapping!\n");
> +		return -ENODEV;
> +	}
> +
> +	of_property_read_string(np, "st,bank-name", &port->bank_name);
> +	port->of_node = np;
> +
> +	port->gpio_chip = stixxxx_gpio_template;
> +	port->gpio_chip.base = port_num * STIXXXX_GPIO_PINS_PER_PORT;
> +	port->gpio_chip.ngpio = STIXXXX_GPIO_PINS_PER_PORT;
> +	port->gpio_chip.of_node = np;
> +	port->gpio_chip.label = dev_name(&pdev->dev);
> +
> +	dev_set_drvdata(&pdev->dev, port);
> +	range = &port->range;
> +	range->name = port->gpio_chip.label;
> +	range->id = port_num;
> +	range->pin_base = range->base = range->id * STIXXXX_GPIO_PINS_PER_PORT;
> +	range->npins = port->gpio_chip.ngpio;
> +	range->gc = &port->gpio_chip;
> +	gpio_ports[port_num] = port;
> +	err  = gpiochip_add(&port->gpio_chip);
> +	if (err) {
> +		dev_err(&pdev->dev, "Failed to add gpiochip(%d)!\n", port_num);
> +		return err;
> +	}
> +	dev_info(&pdev->dev, "gpioport[%s] Added as bank%d\n",
> +				port->bank_name, port_num);
> +	return 0;
> +}
> +
> +static struct of_device_id stixxxx_gpio_of_match[] = {
> +	{ .compatible = "st,stixxxx-gpio", },
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver stixxxx_gpio_driver = {
> +	.driver = {
> +		.name = "st-gpio",
> +		.owner = THIS_MODULE,
> +		.of_match_table = of_match_ptr(stixxxx_gpio_of_match),
> +	},
> +	.probe = stixxxx_gpio_probe,
> +};
> +
> +static struct of_device_id stixxxx_pctl_of_match[] = {
> +	{ .compatible = "st,stixxxx-pinctrl",},
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver stixxxx_pctl_driver = {
> +	.driver = {
> +		.name = "st-pinctrl",
> +		.owner = THIS_MODULE,
> +		.of_match_table = of_match_ptr(stixxxx_pctl_of_match),
> +	},
> +	.probe = stixxxx_pctl_probe,
> +};
> +
> +static int __init stixxxx_pctl_init(void)
> +{
> +	int ret = platform_driver_register(&stixxxx_gpio_driver);
> +	if (ret)
> +		return ret;
> +	return platform_driver_register(&stixxxx_pctl_driver);
> +}
> +arch_initcall(stixxxx_pctl_init);
> diff --git a/drivers/pinctrl/pinctrl-stixxxx.h b/drivers/pinctrl/pinctrl-stixxxx.h
> new file mode 100644
> index 0000000..a340964
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-stixxxx.h
> @@ -0,0 +1,197 @@
> +
> +/*
> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
> + * Authors:
> + *	Srinivas Kandagatla <srinivas.kandagatla@st.com>
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __LINUX_DRIVERS_PINCTRL_STIXXXX_H
> +#define __LINUX_DRIVERS_PINCTRL_STIXXXX_H
> +
> +enum stixxxx_retime_style {
> +	stixxxx_retime_style_none,
> +	stixxxx_retime_style_packed,
> +	stixxxx_retime_style_dedicated,
> +};
> +
> +/* Byte positions in 2 syscon words, starts from 0 */
> +struct stixxxx_retime_offset {
> +	int retime_offset;
> +	int clk1notclk0_offset;
> +	int clknotdata_offset;
> +	int double_edge_offset;
> +	int invertclk_offset;
> +	int delay_lsb_offset;
> +	int delay_msb_offset;
> +};
> +
> +struct stixxxx_retime_params {
> +	const struct stixxxx_retime_offset *retime_offset;
> +	unsigned int *delay_times_in;
> +	int num_delay_times_in;
> +	unsigned int *delay_times_out;
> +	int num_delay_times_out;
> +};
> +
> +struct stixxxx_pio_control {
> +	enum stixxxx_retime_style rt_style;
> +	u32 rt_pin_mask;
> +	const struct stixxxx_retime_params *rt_params;
> +	struct syscon_field *alt;
> +	struct syscon_field *oe, *pu, *od;
> +	struct syscon_field *retiming[8];
> +};
> +
> +/* PIO Block registers */
> +/* PIO output */
> +#define REG_PIO_POUT			0x00
> +/* Set bits of POUT */
> +#define REG_PIO_SET_POUT		0x04
> +/* Clear bits of POUT */
> +#define REG_PIO_CLR_POUT		0x08
> +/* PIO input */
> +#define REG_PIO_PIN			0x10
> +/* PIO configuration */
> +#define REG_PIO_PC(n)			(0x20 + (n) * 0x10)
> +/* Set bits of PC[2:0] */
> +#define REG_PIO_SET_PC(n)		(0x24 + (n) * 0x10)
> +/* Clear bits of PC[2:0] */
> +#define REG_PIO_CLR_PC(n)		(0x28 + (n) * 0x10)
> +/* PIO input comparison */
> +#define REG_PIO_PCOMP			0x50
> +/* Set bits of PCOMP */
> +#define REG_PIO_SET_PCOMP		0x54
> +/* Clear bits of PCOMP */
> +#define REG_PIO_CLR_PCOMP		0x58
> +/* PIO input comparison mask */
> +#define REG_PIO_PMASK			0x60
> +/* Set bits of PMASK */
> +#define REG_PIO_SET_PMASK		0x64
> +/* Clear bits of PMASK */
> +#define REG_PIO_CLR_PMASK		0x68
> +
> +#define STIXXXX_MAX_GPIO_BANKS		32
> +
> +#define STIXXXX_GPIO_DIRECTION_BIDIR	0x1
> +#define STIXXXX_GPIO_DIRECTION_OUT	0x2
> +#define STIXXXX_GPIO_DIRECTION_IN	0x4
> +
> +#define STIXXXX_GPIO_PINS_PER_PORT	8
> +#define stixxxx_gpio_port(gpio) ((gpio) / STIXXXX_GPIO_PINS_PER_PORT)
> +#define stixxxx_gpio_pin(gpio) ((gpio) % STIXXXX_GPIO_PINS_PER_PORT)
> +
> +/* pinconf */
> +/*
> + * Pinconf is represented in an opaque unsigned long variable.
> + * Below is the bit allocation details for each possible configuration.
> + * All the bit fields can be encapsulated into four variables
> + * (direction, retime-type, retime-clk, retime-delay)
> + *
> + *	 +----------------+
> + *[31:28]| reserved-3     |
> + *	 +----------------+-------------
> + *[27]   |	oe	  |		|
> + *	 +----------------+		v
> + *[26]   |	pu	  |	[Direction	]
> + *	 +----------------+		^
> + *[25]   |	od	  |		|
> + *	 +----------------+-------------
> + *[24]   | reserved-2     |
> + *	 +----------------+-------------
> + *[23]   |    retime      |		|
> + *	 +----------------+		|
> + *[22]   | retime-invclk  |		|
> + *	 +----------------+		v
> + *[21]   |retime-clknotdat|	[Retime-type	]
> + *	 +----------------+		^
> + *[20]   | retime-de      |		|
> + *	 +----------------+-------------
> + *[19:18]| retime-clk     |------>[Retime-Clk	]
> + *	 +----------------+
> + *[17:16]|  reserved-1    |
> + *	 +----------------+
> + *[15..0]| retime-delay   |------>[Retime Delay]
> + *	 +----------------+
> + */
> +
> +#define STIXXXX_PINCONF_UNPACK(conf, param)\
> +				((conf >> STIXXXX_PINCONF_ ##param ##_SHIFT) \
> +				& STIXXXX_PINCONF_ ##param ##_MASK)
> +
> +#define STIXXXX_PINCONF_PACK(conf, val, param)	(conf |=\
> +				((val & STIXXXX_PINCONF_ ##param ##_MASK) << \
> +					STIXXXX_PINCONF_ ##param ##_SHIFT))
> +
> +/* Output enable */
> +#define STIXXXX_PINCONF_OE_MASK		0x1
> +#define STIXXXX_PINCONF_OE_SHIFT	27
> +#define STIXXXX_PINCONF_OE		BIT(27)
> +#define STIXXXX_PINCONF_UNPACK_OE(conf)	STIXXXX_PINCONF_UNPACK(conf, OE)
> +#define STIXXXX_PINCONF_PACK_OE(conf, val)  STIXXXX_PINCONF_PACK(conf, val, OE)
> +
> +/* Pull Up */
> +#define STIXXXX_PINCONF_PU_MASK		0x1
> +#define STIXXXX_PINCONF_PU_SHIFT	26
> +#define STIXXXX_PINCONF_PU		BIT(26)
> +#define STIXXXX_PINCONF_UNPACK_PU(conf)	STIXXXX_PINCONF_UNPACK(conf, PU)
> +#define STIXXXX_PINCONF_PACK_PU(conf, val) STIXXXX_PINCONF_PACK(conf, val, PU)
> +
> +/* Open Drain */
> +#define STIXXXX_PINCONF_OD_MASK		0x1
> +#define STIXXXX_PINCONF_OD_SHIFT	25
> +#define STIXXXX_PINCONF_OD		BIT(25)
> +#define STIXXXX_PINCONF_UNPACK_OD(conf)	STIXXXX_PINCONF_UNPACK(conf, OD)
> +#define STIXXXX_PINCONF_PACK_OD(conf, val) STIXXXX_PINCONF_PACK(conf, val, OD)
> +
> +#define STIXXXX_PINCONF_RT_MASK		0x1
> +#define STIXXXX_PINCONF_RT_SHIFT	23
> +#define STIXXXX_PINCONF_RT		BIT(23)
> +#define STIXXXX_PINCONF_UNPACK_RT(conf)	STIXXXX_PINCONF_UNPACK(conf, RT)
> +#define STIXXXX_PINCONF_PACK_RT(conf, val) STIXXXX_PINCONF_PACK(conf, val, RT)
> +
> +#define STIXXXX_PINCONF_RT_INVERTCLK_MASK	0x1
> +#define STIXXXX_PINCONF_RT_INVERTCLK_SHIFT	22
> +#define STIXXXX_PINCONF_RT_INVERTCLK		BIT(22)
> +#define STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(conf) \
> +			STIXXXX_PINCONF_UNPACK(conf, RT_INVERTCLK)
> +#define STIXXXX_PINCONF_PACK_RT_INVERTCLK(conf, val) \
> +			STIXXXX_PINCONF_PACK(conf, val, RT_INVERTCLK)
> +
> +#define STIXXXX_PINCONF_RT_CLKNOTDATA_MASK	0x1
> +#define STIXXXX_PINCONF_RT_CLKNOTDATA_SHIFT	21
> +#define STIXXXX_PINCONF_RT_CLKNOTDATA		BIT(21)
> +#define STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(conf)	\
> +				STIXXXX_PINCONF_UNPACK(conf, RT_CLKNOTDATA)
> +#define STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(conf, val) \
> +				STIXXXX_PINCONF_PACK(conf, val, RT_CLKNOTDATA)
> +
> +#define STIXXXX_PINCONF_RT_DOUBLE_EDGE_MASK	0x1
> +#define STIXXXX_PINCONF_RT_DOUBLE_EDGE_SHIFT	20
> +#define STIXXXX_PINCONF_RT_DOUBLE_EDGE		BIT(20)
> +#define STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(conf) \
> +				STIXXXX_PINCONF_UNPACK(conf, RT_DOUBLE_EDGE)
> +#define STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(conf, val) \
> +				STIXXXX_PINCONF_PACK(conf, val, RT_DOUBLE_EDGE)
> +
> +#define STIXXXX_PINCONF_RT_CLK_MASK		0x3
> +#define STIXXXX_PINCONF_RT_CLK_SHIFT		18
> +#define STIXXXX_PINCONF_RT_CLK			BIT(18)
> +#define STIXXXX_PINCONF_UNPACK_RT_CLK(conf)	\
> +			STIXXXX_PINCONF_UNPACK(conf, RT_CLK)
> +#define STIXXXX_PINCONF_PACK_RT_CLK(conf, val) \
> +			STIXXXX_PINCONF_PACK(conf, val, RT_CLK)
> +
> +/* RETIME_DELAY in Pico Secs */
> +#define STIXXXX_PINCONF_RT_DELAY_MASK		0xffff
> +#define STIXXXX_PINCONF_RT_DELAY_SHIFT		0
> +#define STIXXXX_PINCONF_UNPACK_RT_DELAY(conf) \
> +				STIXXXX_PINCONF_UNPACK(conf, RT_DELAY)
> +#define STIXXXX_PINCONF_PACK_RT_DELAY(conf, val) \
> +				STIXXXX_PINCONF_PACK(conf, val, RT_DELAY)
> +
> +#endif /* __LINUX_DRIVERS_PINCTRL_STIXXXX_H */
> -- 
> 1.7.6.5
> 
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss

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

* Re: [RFC 2/8] ARM:global_timer: Add ARM global timer support.
  2013-05-08 14:26   ` Rob Herring
@ 2013-05-08 15:06     ` Stuart MENEFY
  0 siblings, 0 replies; 64+ messages in thread
From: Stuart MENEFY @ 2013-05-08 15:06 UTC (permalink / raw)
  To: Rob Herring
  Cc: Srinivas KANDAGATLA, linux, will.deacon, Rob Landley,
	Grant Likely, Samuel Ortiz, Linus Walleij, Greg Kroah-Hartman,
	Jiri Slaby, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Dave Martin,
	Marc Zyngier, Viresh Kumar, Arnd Bergmann, Mark Brown,
	Dong Aisheng, linux-doc, linux-kernel, devicetree-discuss,
	linux-arm-kernel, linux-serial

On 08/05/13 15:26, Rob Herring wrote:
> On 05/08/2013 09:11 AM, Srinivas KANDAGATLA wrote:
>> From: Stuart Menefy <stuart.menefy@st.com>
>>
>> This is a simple driver for the global timer module found in the Cortex
>> A9-MP cores from revision r1p0 onwards. This should be able to perform
>> the functions of the system timer and the local timer in an SMP system.
>>
>> The global timer has the following features:
>>     The global timer is a 64-bit incrementing counter with an
>> auto-incrementing feature. It continues incrementing after sending
>> interrupts. The global timer is memory mapped in the private memory
>> region.
>>     The global timer is accessible to all Cortex-A9 processors in the
>> cluster. Each Cortex-A9 processor has a private 64-bit comparator that
>> is used to assert a private interrupt when the global timer has reached
>> the comparator value. All the Cortex-A9 processors in a design use the
>> banked ID, ID27, for this interrupt. ID27 is sent to the Interrupt
>> Controller as a Private Peripheral Interrupt. The global timer is
>> clocked by PERIPHCLK.
> 
> PERIPHCLK scales with cpu clock typically so the global timer is not a
> suitable clocksource if you use cpufreq. You can deal with the scaling
> on clockevents, but not a clocksource. I imagine the global timers is
> also typically power-gated in some low power modes. This is why no one
> has added support already. Are neither of those an issue or going to be
> an issue for you?

I agree but we're limited by the available hardware, the SoC designers
didn't put down any general purpose timers unfortunately, so we have to
use the global timer as a clocksource.

The full version of this code has a cpufreq notifier to try and cope with
changes, but we didn't include that as the rest of the cpufreq code is
missing in this first post. There will be inaccuracies of course, but its
the best we can do.

There is no power gating on these devices, and clock gating only occurs
at the clock input to the A9 subsystem including the cores and timers,
so we don't have that issue.

Stuart

>> Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>> ---
>>  Documentation/devicetree/bindings/arm/gt.txt |   21 ++
>>  arch/arm/Kconfig                             |    6 +
>>  arch/arm/include/asm/global_timer.h          |   12 +
>>  arch/arm/kernel/Makefile                     |    1 +
>>  arch/arm/kernel/global_timer.c               |  325 ++++++++++++++++++++++++++
>>  5 files changed, 365 insertions(+), 0 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/arm/gt.txt
>>  create mode 100644 arch/arm/include/asm/global_timer.h
>>  create mode 100644 arch/arm/kernel/global_timer.c
>>
>> diff --git a/Documentation/devicetree/bindings/arm/gt.txt b/Documentation/devicetree/bindings/arm/gt.txt
>> new file mode 100644
>> index 0000000..4ec5fb0
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/arm/gt.txt
>> @@ -0,0 +1,21 @@
>> +
>> +* ARM Global Timer
>> +	Cortex-A9 are often associated with a per-core Global timer.
>> +
>> +** Timer node required properties:
>> +
>> +- compatible : Should be one of:
>> +	"arm,cortex-a9-global-timer"
>> +
>> +- interrupts : One interrupt to each core
>> +
>> +- reg : Specify the base address and the size of the GT timer
>> +	register window.
>> +
>> +Example:
>> +
>> +	gt-timer@2c000600 {
>> +		compatible = "arm,cortex-a9-global-timer";
>> +		reg = <0x2c000600 0x20>;
>> +		interrupts = <1 13 0xf01>;
>> +	};
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index 1cacda4..c8c524e 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -1606,6 +1606,12 @@ config HAVE_ARM_TWD
>>  	help
>>  	  This options enables support for the ARM timer and watchdog unit
>>  
>> +config HAVE_ARM_GT
>> +	bool
>> +	select CLKSRC_OF if OF
>> +	help
>> +	  This options enables support for the ARM global timer unit
>> +
>>  choice
>>  	prompt "Memory split"
>>  	default VMSPLIT_3G
>> diff --git a/arch/arm/include/asm/global_timer.h b/arch/arm/include/asm/global_timer.h
>> new file mode 100644
>> index 0000000..46f9188
>> --- /dev/null
>> +++ b/arch/arm/include/asm/global_timer.h
>> @@ -0,0 +1,12 @@
>> +/*
>> + * arch/arm/include/asm/global_timer.h
>> + *
>> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
>> + * Author: Stuart Menefy <stuart.menefy@st.com>
>> + *
>> + * 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.
>> + */
>> +
>> +int __init global_timer_init(void __iomem *base, unsigned int timer_irq);
>> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
>> index 5f3338e..af51808 100644
>> --- a/arch/arm/kernel/Makefile
>> +++ b/arch/arm/kernel/Makefile
>> @@ -35,6 +35,7 @@ obj-$(CONFIG_ARM_CPU_SUSPEND)	+= sleep.o suspend.o
>>  obj-$(CONFIG_SMP)		+= smp.o smp_tlb.o
>>  obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
>>  obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
>> +obj-$(CONFIG_HAVE_ARM_GT)	+= global_timer.o
>>  obj-$(CONFIG_ARM_ARCH_TIMER)	+= arch_timer.o
>>  obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
>>  obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
>> diff --git a/arch/arm/kernel/global_timer.c b/arch/arm/kernel/global_timer.c
>> new file mode 100644
>> index 0000000..0ab1af3
>> --- /dev/null
>> +++ b/arch/arm/kernel/global_timer.c
>> @@ -0,0 +1,325 @@
>> +/*
>> + * linux/arch/arm/kernel/global_timer.c
>> + *
>> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
>> + * Author: Stuart Menefy <stuart.menefy@st.com>
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/clocksource.h>
>> +#include <linux/clockchips.h>
>> +#include <linux/clk.h>
>> +#include <linux/clkdev.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/of.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of_address.h>
>> +
>> +#include <asm/mach/irq.h>
>> +#include <asm/global_timer.h>
>> +#include <asm/localtimer.h>
>> +
>> +#define GT_COUNTER0	0x00
>> +#define GT_COUNTER1	0x04
>> +
>> +#define GT_CONTROL	0x08
>> +#define GT_CONTROL_TIMER_ENABLE		BIT(0)
>> +#define GT_CONTROL_COMP_ENABLE		BIT(1)	/* banked */
>> +#define GT_CONTROL_IRQ_ENABLE		BIT(2)	/* banked */
>> +#define GT_CONTROL_AUTO_INC		BIT(3)	/* banked */
>> +
>> +#define GT_INT_STATUS	0x0c
>> +#define GT_INT_STATUS_EVENT_FLAG	BIT(0)
>> +
>> +#define GT_COMP0	0x10
>> +#define GT_COMP1	0x14
>> +#define GT_AUTO_INC	0x18
>> +
>> +/*
>> + * We are expecting to be clocked by the ARM peripheral clock.
>> + *
>> + * Note: it is assumed we are using a prescaler value of zero, so this is
>> + * the units for all operations.
>> + */
>> +static void __iomem *gt_base;
>> +static struct clk *gt_clk;
>> +static unsigned long gt_clk_rate;
>> +static int gt_ppi;
>> +static struct clock_event_device __percpu **gt_evt;
>> +static DEFINE_PER_CPU(bool, percpu_init_called);
>> +static DEFINE_PER_CPU(struct clock_event_device, gt_clockevent);
>> +
>> +union gt_counter {
>> +	cycle_t cycles;
>> +	struct {
>> +		uint32_t lower;
>> +		uint32_t upper;
>> +	};
>> +};
>> +
>> +static union gt_counter gt_counter_read(void)
>> +{
>> +	union gt_counter res;
>> +	uint32_t upper;
>> +
>> +	upper = readl(gt_base + GT_COUNTER1);
>> +	do {
>> +		res.upper = upper;
>> +		res.lower = readl(gt_base + GT_COUNTER0);
>> +		upper = readl(gt_base + GT_COUNTER1);
>> +	} while (upper != res.upper);
>> +
>> +	return res;
>> +}
>> +
>> +static void gt_compare_set(unsigned long delta, int periodic)
>> +{
>> +	union gt_counter counter = gt_counter_read();
>> +	unsigned long ctrl = readl(gt_base + GT_CONTROL);
>> +
>> +	BUG_ON(!(ctrl & GT_CONTROL_TIMER_ENABLE));
>> +	BUG_ON(ctrl & (GT_CONTROL_COMP_ENABLE |
>> +		       GT_CONTROL_IRQ_ENABLE |
>> +		       GT_CONTROL_AUTO_INC));
>> +
>> +	counter.cycles += delta;
>> +	writel(counter.lower, gt_base + GT_COMP0);
>> +	writel(counter.upper, gt_base + GT_COMP1);
>> +
>> +	ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE;
>> +
>> +	if (periodic) {
>> +		writel(delta, gt_base + GT_AUTO_INC);
>> +		ctrl |= GT_CONTROL_AUTO_INC;
>> +	}
>> +
>> +	writel(ctrl, gt_base + GT_CONTROL);
>> +}
>> +
>> +static void gt_clockevent_set_mode(enum clock_event_mode mode,
>> +				   struct clock_event_device *clk)
>> +{
>> +	switch (mode) {
>> +	case CLOCK_EVT_MODE_PERIODIC:
>> +		gt_compare_set(gt_clk_rate/HZ, 1);
>> +		break;
>> +	case CLOCK_EVT_MODE_ONESHOT:
>> +		/* period set, and timer enabled in 'next_event' hook */
>> +		BUG_ON(readl(gt_base + GT_CONTROL) &
>> +		       (GT_CONTROL_COMP_ENABLE |
>> +			GT_CONTROL_IRQ_ENABLE |
>> +			GT_CONTROL_AUTO_INC));
>> +		/* Fall through */
>> +	case CLOCK_EVT_MODE_UNUSED:
>> +	case CLOCK_EVT_MODE_SHUTDOWN:
>> +	default:
>> +		writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
>> +		break;
>> +	}
>> +}
>> +
>> +static int gt_clockevent_set_next_event(unsigned long evt,
>> +					struct clock_event_device *unused)
>> +{
>> +	gt_compare_set(evt, 0);
>> +	return 0;
>> +}
>> +
>> +static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id)
>> +{
>> +	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
>> +
>> +	writel(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS);
>> +	evt->event_handler(evt);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static int __cpuinit gt_clockevents_init(struct clock_event_device *clk)
>> +{
>> +	struct clock_event_device **this_cpu_clk;
>> +	int cpu = smp_processor_id();
>> +
>> +	clk->name = "Global Timer CE";
>> +	clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
>> +	clk->set_mode = gt_clockevent_set_mode;
>> +	clk->set_next_event = gt_clockevent_set_next_event;
>> +	this_cpu_clk = __this_cpu_ptr(gt_evt);
>> +	*this_cpu_clk = clk;
>> +	clk->irq = gt_ppi;
>> +	clockevents_config_and_register(clk, gt_clk_rate,
>> +					0xf, 0xffffffff);
>> +	per_cpu(percpu_init_called, cpu) = true;
>> +	enable_percpu_irq(clk->irq, IRQ_TYPE_NONE);
>> +	return 0;
>> +}
>> +
>> +static void gt_clockevents_stop(struct clock_event_device *clk)
>> +{
>> +	gt_clockevent_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
>> +	disable_percpu_irq(clk->irq);
>> +}
>> +
>> +static int __cpuinit gt_clockevents_setup(struct clock_event_device *clk)
>> +{
>> +	int cpu = smp_processor_id();
>> +
>> +	/* Use existing clock_event for boot cpu */
>> +	if (per_cpu(percpu_init_called, cpu))
>> +		return 0;
>> +
>> +	writel(0, gt_base + GT_CONTROL);
>> +	writel(0, gt_base + GT_COUNTER0);
>> +	writel(0, gt_base + GT_COUNTER1);
>> +	writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
>> +
>> +	return gt_clockevents_init(clk);
>> +}
>> +
>> +static cycle_t gt_clocksource_read(struct clocksource *cs)
>> +{
>> +	union gt_counter res = gt_counter_read();
>> +	return res.cycles;
>> +}
>> +
>> +static struct clocksource gt_clocksource = {
>> +	.name	= "Global Timer CS",
>> +	.rating	= 300,
>> +	.read	= gt_clocksource_read,
>> +	.mask	= CLOCKSOURCE_MASK(64),
>> +	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
>> +};
>> +
>> +static void __init gt_clocksource_init(void)
>> +{
>> +	writel(0, gt_base + GT_CONTROL);
>> +	writel(0, gt_base + GT_COUNTER0);
>> +	writel(0, gt_base + GT_COUNTER1);
>> +	writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
>> +
>> +	gt_clocksource.shift = 20;
>> +	gt_clocksource.mult =
>> +		clocksource_hz2mult(gt_clk_rate, gt_clocksource.shift);
>> +	clocksource_register(&gt_clocksource);
>> +}
>> +
>> +static struct clk *gt_get_clock(void)
>> +{
>> +	struct clk *clk;
>> +	int err;
>> +
>> +	clk = clk_get_sys("gt", NULL);
>> +	if (IS_ERR(clk)) {
>> +		pr_err("global-timer: clock not found: %ld\n", PTR_ERR(clk));
>> +		return clk;
>> +	}
>> +
>> +	err = clk_prepare_enable(clk);
>> +	if (err) {
>> +		pr_err("global-timer: clock prepare+enable failed: %d\n", err);
>> +		clk_put(clk);
>> +		return ERR_PTR(err);
>> +	}
>> +
>> +	return clk;
>> +}
>> +
>> +static struct local_timer_ops gt_lt_ops __cpuinitdata = {
>> +	.setup	= gt_clockevents_setup,
>> +	.stop	= gt_clockevents_stop,
>> +};
>> +
>> +int __init global_timer_init(void __iomem *base, unsigned int timer_irq)
>> +{
>> +	unsigned int cpu = smp_processor_id();
>> +	struct clock_event_device *evt = &per_cpu(gt_clockevent, cpu);
>> +	int err = 0;
>> +
>> +	if (gt_base) {
>> +		pr_warn("global-timer: invalid base address\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	gt_clk = gt_get_clock();
>> +	if (IS_ERR(gt_clk)) {
>> +		pr_warn("global-timer: clk not found\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	gt_evt = alloc_percpu(struct clock_event_device *);
>> +	if (!gt_evt) {
>> +		pr_warn("global-timer: can't allocate memory\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	err = request_percpu_irq(timer_irq, gt_clockevent_interrupt,
>> +				 "gt", gt_evt);
>> +	if (err) {
>> +		pr_warn("global-timer: can't register interrupt %d (%d)\n",
>> +			timer_irq, err);
>> +		goto out_free;
>> +	}
>> +
>> +	gt_base = base;
>> +	gt_clk_rate = clk_get_rate(gt_clk);
>> +
>> +	evt->irq = timer_irq;
>> +	gt_ppi = timer_irq;
>> +	evt->cpumask = cpumask_of(cpu);
>> +
>> +	gt_clocksource_init();
>> +	gt_clockevents_init(evt);
>> +	err =  local_timer_register(&gt_lt_ops);
>> +	if (err) {
>> +		pr_warn("global-timer: unable to register local timer.\n");
>> +		goto out_irq;
>> +	}
>> +
>> +	return 0;
>> +
>> +out_irq:
>> +	free_percpu_irq(timer_irq, gt_evt);
>> +out_free:
>> +	free_percpu(gt_evt);
>> +	return err;
>> +}
>> +
>> +#ifdef CONFIG_OF
>> +static void __init global_timer_of_register(struct device_node *np)
>> +{
>> +	struct clk *clk;
>> +	int err = 0;
>> +	int gt_ppi;
>> +	static void __iomem *gt_base;
>> +
>> +	gt_ppi = irq_of_parse_and_map(np, 0);
>> +	if (!gt_ppi) {
>> +		err = -EINVAL;
>> +		goto out;
>> +	}
>> +
>> +	gt_base = of_iomap(np, 0);
>> +	if (!gt_base) {
>> +		err = -ENOMEM;
>> +		goto out;
>> +	}
>> +
>> +	clk = of_clk_get(np, 0);
>> +	if (!IS_ERR(clk))
>> +		clk_register_clkdev(clk, NULL, "gt");
>> +
>> +	global_timer_init(gt_base, gt_ppi);
>> +
>> +out:
>> +	WARN(err, "Global timer register failed (%d)\n", err);
>> +}
>> +
>> +CLOCKSOURCE_OF_DECLARE(arm_gt_a9, "arm,cortex-a9-global-timer",
>> +			global_timer_of_register);
>> +#endif
>>
> 



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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
       [not found]     ` <20130508153459.GA17186@kroah.com>
@ 2013-05-08 15:40       ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 15:53         ` Greg KH
  2013-05-08 16:10       ` Stephen GALLIMORE
  2013-05-10 13:50       ` Stephen GALLIMORE
  2 siblings, 1 reply; 64+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-08 15:40 UTC (permalink / raw)
  To: Greg KH
  Cc: Arnd Bergmann, Srinivas KANDAGATLA, Viresh Kumar, Will Deacon,
	jslaby, Russell King, Samuel Ortiz, Nicolas Pitre, linux-doc,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Mark Brown, linux-kernel

On 08:34 Wed 08 May     , Greg KH wrote:
> On Wed, May 08, 2013 at 04:34:43PM +0200, Arnd Bergmann wrote:
> > > +#define ASC_MAJOR		204
> > > +#define ASC_MINOR_START		40
> > 
> > I don't know what the current policy is on allocating major/minor numbers,
> > but I'm sure you cannot just reuse one that is already used.
> 
> I agree, why are you trying to create a new tty device name?  Can't you
> use the existing ttyS name and minor number as you will not have any
> other type of serial device on this system?

Greg on ST STB for more than 10 years we use ttyASC I'll prefer ttySx

on the DTB SoC you have one one IP present the st,asc

Best Regards,
J.
> 
> thanks,
> 
> greg k-h
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss

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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 15:40       ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 15:53         ` Greg KH
  2013-05-08 16:03           ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 64+ messages in thread
From: Greg KH @ 2013-05-08 15:53 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD
  Cc: Arnd Bergmann, Srinivas KANDAGATLA, Viresh Kumar, Will Deacon,
	jslaby, Russell King, Samuel Ortiz, Nicolas Pitre, linux-doc,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Mark Brown, linux-kernel

On Wed, May 08, 2013 at 05:40:57PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 08:34 Wed 08 May     , Greg KH wrote:
> > On Wed, May 08, 2013 at 04:34:43PM +0200, Arnd Bergmann wrote:
> > > > +#define ASC_MAJOR		204
> > > > +#define ASC_MINOR_START		40
> > > 
> > > I don't know what the current policy is on allocating major/minor numbers,
> > > but I'm sure you cannot just reuse one that is already used.
> > 
> > I agree, why are you trying to create a new tty device name?  Can't you
> > use the existing ttyS name and minor number as you will not have any
> > other type of serial device on this system?
> 
> Greg on ST STB for more than 10 years we use ttyASC I'll prefer ttySx

For 10+ years you have had an out-of-tree serial driver?  What
major/minor numbers did you use for it?

> on the DTB SoC you have one one IP present the st,asc

I don't understand, what do you mean by this?

confused,

greg k-h

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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 15:53         ` Greg KH
@ 2013-05-08 16:03           ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 16:15             ` Greg KH
  0 siblings, 1 reply; 64+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-08 16:03 UTC (permalink / raw)
  To: Greg KH
  Cc: Jean-Christophe PLAGNIOL-VILLARD, Arnd Bergmann,
	Srinivas KANDAGATLA, Viresh Kumar, Will Deacon, jslaby,
	Russell King, Samuel Ortiz, Nicolas Pitre, linux-doc,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Mark Brown, linux-kernel


On May 8, 2013, at 11:53 PM, Greg KH <gregkh@linuxfoundation.org> wrote:

> On Wed, May 08, 2013 at 05:40:57PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
>> On 08:34 Wed 08 May     , Greg KH wrote:
>>> On Wed, May 08, 2013 at 04:34:43PM +0200, Arnd Bergmann wrote:
>>>>> +#define ASC_MAJOR		204
>>>>> +#define ASC_MINOR_START		40
>>>> 
>>>> I don't know what the current policy is on allocating major/minor numbers,
>>>> but I'm sure you cannot just reuse one that is already used.
>>> 
>>> I agree, why are you trying to create a new tty device name?  Can't you
>>> use the existing ttyS name and minor number as you will not have any
>>> other type of serial device on this system?
>> 
>> Greg on ST STB for more than 10 years we use ttyASC I'll prefer ttySx
> 
> For 10+ years you have had an out-of-tree serial driver?
yes ST have it out of tree for very long time even I puts them to come mainline

>  What
> major/minor numbers did you use for it?

http://git.stlinux.com/?p=havana/com.st.havana.kernel.git;a=blob;f=drivers/serial/stm-asc.h;h=79e003ffeb21df55a6af94774fc9c4b3d8de18e9;hb=HEAD

  52 #define ASC_MAJOR               204
  53 #define ASC_MINOR_START         40

same as in this patch

> 
>> on the DTB SoC you have one one IP present the st,asc
> 
> I don't understand, what do you mean by this?
> 
> confused,

just mention there is not hardware reason to not use the generic ttySx in place of ttyAS
as we have only one IP that handle serial on this family of SoC

personally I'll switch to ttySx

Best Regards,
J.

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

* RE: [RFC 1/8] serial:st-asc: Add ST ASC driver.
       [not found]     ` <20130508153459.GA17186@kroah.com>
  2013-05-08 15:40       ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 16:10       ` Stephen GALLIMORE
  2013-05-10 13:50       ` Stephen GALLIMORE
  2 siblings, 0 replies; 64+ messages in thread
From: Stephen GALLIMORE @ 2013-05-08 16:10 UTC (permalink / raw)
  To: Greg KH, Arnd Bergmann
  Cc: Srinivas KANDAGATLA, Stuart MENEFY, linux-doc, linux-kernel,
	linux-arm-kernel, linux-serial


>On Wed, May 08, 2013 at 04:34:43PM +0200, Arnd Bergmann wrote:
> > > +#define ASC_MAJOR		204
> > > +#define ASC_MINOR_START		40
> > 
> > I don't know what the current policy is on allocating major/minor 
> > numbers, but I'm sure you cannot just reuse one that is already used.

First, our apologies, this issue was raised internally and then got forgotten about, there's always something I guess.
 
> >I agree, why are you trying to create a new tty device name?  Can't you use the existing ttyS name and minor number as you will not have any other type of serial
> >device on this system?

That is an interesting question Greg; I believe it probably stems from historic ST SoCs that had two different types of serial devices, something that is no longer the case. We will review our approach to this again, although we are not sure we can use the existing ttyS major/minor (even if that is an acceptable thing to do) because of the (remote) possibility of someone using a standard PCIe attached serial card.

Regards,
-stephen



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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 16:03           ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 16:15             ` Greg KH
  2013-05-08 16:31               ` Arnd Bergmann
  0 siblings, 1 reply; 64+ messages in thread
From: Greg KH @ 2013-05-08 16:15 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD
  Cc: Arnd Bergmann, Srinivas KANDAGATLA, Viresh Kumar, Will Deacon,
	jslaby, Russell King, Samuel Ortiz, Nicolas Pitre, linux-doc,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Mark Brown, linux-kernel

On Thu, May 09, 2013 at 12:03:05AM +0800, Jean-Christophe PLAGNIOL-VILLARD wrote:
> 
> On May 8, 2013, at 11:53 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> 
> > On Wed, May 08, 2013 at 05:40:57PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> >> On 08:34 Wed 08 May     , Greg KH wrote:
> >>> On Wed, May 08, 2013 at 04:34:43PM +0200, Arnd Bergmann wrote:
> >>>>> +#define ASC_MAJOR		204
> >>>>> +#define ASC_MINOR_START		40
> >>>> 
> >>>> I don't know what the current policy is on allocating major/minor numbers,
> >>>> but I'm sure you cannot just reuse one that is already used.
> >>> 
> >>> I agree, why are you trying to create a new tty device name?  Can't you
> >>> use the existing ttyS name and minor number as you will not have any
> >>> other type of serial device on this system?
> >> 
> >> Greg on ST STB for more than 10 years we use ttyASC I'll prefer ttySx
> > 
> > For 10+ years you have had an out-of-tree serial driver?
> yes ST have it out of tree for very long time even I puts them to come mainline

Crazy...

> >  What
> > major/minor numbers did you use for it?
> 
> http://git.stlinux.com/?p=havana/com.st.havana.kernel.git;a=blob;f=drivers/serial/stm-asc.h;h=79e003ffeb21df55a6af94774fc9c4b3d8de18e9;hb=HEAD
> 
>   52 #define ASC_MAJOR               204
>   53 #define ASC_MINOR_START         40
> 
> same as in this patch

Ok, but just because you have been using an out-of-tree name, and
non-reserved major/minor, doesn't mean we have to accept it.  As you are
probably using a tool like udev/devtmpfs on your systems, the
major/minor number shouldn't matter, only the name.

And I'd argue that we should change the name as well.

> >> on the DTB SoC you have one one IP present the st,asc
> > 
> > I don't understand, what do you mean by this?
> > 
> > confused,
> 
> just mention there is not hardware reason to not use the generic ttySx
> in place of ttyAS as we have only one IP that handle serial on this
> family of SoC
> 
> personally I'll switch to ttySx

Great, then you can use the same major/minor range as well, so there's
no more objection from me about this :)

thanks,

greg k-h

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

* Re: [RFC 5/8] ARM:stih41x: Add STiH415 SOC support
  2013-05-08 14:11 ` =?y?q?=5BRFC=205/8=5D=20ARM=3Astih41x=3A=20Add=20STiH415=20SOC=20support?= Srinivas KANDAGATLA
@ 2013-05-08 16:18   ` Arnd Bergmann
  2013-05-08 16:21     ` Jean-Christophe PLAGNIOL-VILLARD
                       ` (2 more replies)
  0 siblings, 3 replies; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 16:18 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: linux, olof, Rob Landley, Grant Likely, Rob Herring,
	Samuel Ortiz, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Jason Cooper, Stephen Warren,
	Maxime Ripard, Nicolas Pitre, Will Deacon, Dave Martin,
	Marc Zyngier, Viresh Kumar, Mark Brown, Dong Aisheng, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial,
	Stephen Gallimore

On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> 
> The STiH415 is the next generation of HD, AVC set-top box processors for
> satellite, cable, terrestrial and IP-STB markets. It is an ARM Cortex-A9
> 1.0 GHz, dual-core CPU.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> CC: Stephen Gallimore <stephen.gallimore@st.com>
> CC: Stuart Menefy <stuart.menefy@st.com>
> ---
>  Documentation/arm/STiH41x/overview.txt         |   39 ++
>  Documentation/arm/STiH41x/stih415-overview.txt |   12 +
>  arch/arm/Kconfig                               |    3 +
>  arch/arm/Kconfig.debug                         |   38 ++
>  arch/arm/Makefile                              |    2 +
>  arch/arm/boot/dts/stih415-clock.dtsi           |   38 ++
>  arch/arm/boot/dts/stih415-pinctrl.dtsi         |  480 ++++++++++++++++++++++++
>  arch/arm/boot/dts/stih415.dtsi                 |   94 +++++
>  arch/arm/boot/dts/stih415.h                    |   20 +
>  arch/arm/boot/dts/stih41x.dtsi                 |   30 ++
>  arch/arm/boot/dts/stixxxx-pincfg.h             |   95 +++++
>  arch/arm/configs/stih41x_defconfig             |   94 +++++
>  arch/arm/include/debug/stixxxx.S               |   61 +++
>  arch/arm/mach-stih41x/Kconfig                  |   35 ++
>  arch/arm/mach-stih41x/Makefile                 |    4 +
>  arch/arm/mach-stih41x/board-dt.c               |   76 ++++
>  arch/arm/mach-stih41x/stih41x.c                |   82 ++++
>  arch/arm/mach-stih41x/stih41x.h                |    7 +
>  arch/arm/plat-stixxxx/Kconfig                  |    2 +
>  arch/arm/plat-stixxxx/Makefile                 |    2 +
>  arch/arm/plat-stixxxx/headsmp.S                |   44 +++
>  arch/arm/plat-stixxxx/include/plat/hardware.h  |   20 +
>  arch/arm/plat-stixxxx/include/plat/smp.h       |   19 +
>  arch/arm/plat-stixxxx/platsmp.c                |  144 +++++++

I think there is no point in having a separate mach- and plat- directory
here, given that modern machines require very little code. You can probably
fold the three files in mach-stih41x (board-dt.c, stih41x.c and stih41x.h)
into a single file and rename plat-stixxxx to mach-stixxxx

> diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
> index 9b31f43..42a5193 100644
> --- a/arch/arm/Kconfig.debug
> +++ b/arch/arm/Kconfig.debug
> @@ -447,6 +447,16 @@ choice
>  		  This option selects UART0 on VIA/Wondermedia System-on-a-chip
>  		  devices, including VT8500, WM8505, WM8650 and WM8850.
>  
> +	config DEBUG_STIH41X_UART
> +		depends on ARCH_STIH41X
> +		bool "Use StiH415/416 ASC for low-level debug"
> +		help
> +		  Say Y here if you want kernel low-level debugging support
> +		  on StiH415/416 based platforms like B2000, B2020.
> +		  It support UART2 and SBC_UART1.
> +
> +		  If unsure, say N.
> +
>  	config DEBUG_LL_UART_NONE
>  		bool "No low-level debugging UART"
>  		depends on !ARCH_MULTIPLATFORM

I would split out the debug code into a separate patch though.

> @@ -600,6 +637,7 @@ config DEBUG_LL_INCLUDE
>  	default "debug/vt8500.S" if DEBUG_VT8500_UART0
>  	default "debug/tegra.S" if DEBUG_TEGRA_UART
>  	default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
> +	default "debug/stixxxx.S" if DEBUG_STIH41X_UART
>  	default "mach/debug-macro.S"

Please keep this in alphabetical order.

> +	soc {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		#interrupt-cells = <3>;
> +		interrupt-parent = <&intc>;

The "#interrupt-cells" property doesn't belong here I think.

> +
> +		uart2: uart@fed32000 {
> +			compatible	= "st,asc";
> +			status 		= "disabled";
> +			reg		= <0xfed32000 0x2c>;
> +			interrupts	= <0 197 0>;
> +			pinctrl-names 	= "default";
> +			pinctrl-0 	= <&pinctrl_uart2>;
> +			clocks		= <&CLKS_ICN_REG_0>;
> +		};
> +
> +		/* SBC comms block ASCs in SASG1 */
> +		sbc_uart1: uart@fe531000 {
> +			compatible	= "st,asc";
> +			status 		= "disabled";
> +			reg		= <0xfe531000 0x2c>;
> +			interrupts	= <0 210 0>;
> +			clocks		= <&CLK_SYSIN>;
> +			pinctrl-names 	= "default";
> +			pinctrl-0	= <&pinctrl_sbc_uart1>;
> +		};
> +	};

Please name these devices "serial", not "uart".

> diff --git a/arch/arm/configs/stih41x_defconfig b/arch/arm/configs/stih41x_defconfig
> new file mode 100644
> index 0000000..dd9268b
> --- /dev/null
> +++ b/arch/arm/configs/stih41x_defconfig

I would prefer to have this be part of multi_v7_defconfig, unless
you have strong reason why it can't be.

> diff --git a/arch/arm/mach-stih41x/Kconfig b/arch/arm/mach-stih41x/Kconfig
> new file mode 100644
> index 0000000..9c40540
> --- /dev/null
> +++ b/arch/arm/mach-stih41x/Kconfig
> @@ -0,0 +1,35 @@
> +config ARCH_STIH41X
> +	bool "STMicroelectronics STiH41x SOCs with Flattened Device Tree" if ARCH_MULTI_V7
> +	select GENERIC_CLOCKEVENTS
> +	select CLKDEV_LOOKUP
> +	select ARM_GIC


> +if ARCH_STIH41X
> +menu "STMicroelectronics Consumer Electronics SOCs"

You can use 'menuconfig' to combine these two.

> +static void __init stih41x_timer_init(void)
> +{
> +	of_clk_init(NULL);
> +	clocksource_of_init();
> +	stih41x_l2x0_init();
> +}

I'm hoping we can kill make the clk and l2x0 init work by default in 3.11,
as clocksource_of_init already does, so you won't need this function
any more.

> +/*
> + * A basic implementation of irq_set_wake that ensures wakeup source
> + * interrupts are not disabled during PM_SUSPEND_FREEZE.
> + */
> +static int stih41x_set_wake(struct irq_data *d, unsigned int on)
> +{
> +	struct irq_desc *desc = irq_to_desc(d->irq);
> +
> +	if (on) {
> +		if (desc->action)
> +			desc->action->flags |= IRQF_NO_SUSPEND;
> +	} else {
> +		if (desc->action)
> +			desc->action->flags &= ~IRQF_NO_SUSPEND;
> +	}
> +	return 0;
> +}
> +
> +static void __init stih41x_irq_init(void)
> +{
> +	gic_arch_extn.irq_set_wake = stih41x_set_wake;
> +	gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
> +
> +	irqchip_init();
> +}

This looks like it should be generic. Why do you need this?

> +void __init stih41x_dt_init(void)
> +{
> +	of_platform_populate(NULL, of_default_bus_match_table,
> +				NULL, NULL);
> +	return;
> +}

This is already not needed in 3.10.

> +static struct map_desc stih41x_io_desc[] __initdata = {
> +#ifdef CONFIG_SMP
> +	{
> +		.virtual	= IO_ADDRESS(MPE41_SCU_BASE),
> +		.pfn		= __phys_to_pfn(MPE41_SCU_BASE),
> +		.length		= SZ_4K,
> +		.type		= MT_DEVICE,
> +	},
> +#endif

> +void __init stih41x_map_io(void)
> +{
> +#ifdef CONFIG_SMP
> +	stixxxx_scu_base_addr = ((void __iomem *)IO_ADDRESS(MPE41_SCU_BASE));
> +#endif
> +	iotable_init(stih41x_io_desc, ARRAY_SIZE(stih41x_io_desc));
> +}

IIRC the SCU no longer needs to be mapped this early, so you can use
ioremap these days.

> +void __init stih41x_l2x0_init(void)
> +{
> +	u32 way_size = 0x4;
> +	u32 aux_ctrl;
> +
> +	aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
> +		(0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
> +		(0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
> +		(way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
> +
> +	l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK);
> +}

I don't know where we stand on this, but I think we should kill all
calls like these.

	Arnd

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

* Re: [RFC 7/8] ARM:stih41x: Add B2000 board support
  2013-05-08 14:12 ` [RFC 7/8] ARM:stih41x: Add B2000 board support Srinivas KANDAGATLA
@ 2013-05-08 16:20   ` Arnd Bergmann
  2013-05-08 16:24     ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 17:04     ` Srinivas KANDAGATLA
  0 siblings, 2 replies; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 16:20 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: linux, olof, Rob Landley, Grant Likely, Rob Herring,
	Samuel Ortiz, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Jason Cooper, Stephen Warren,
	Maxime Ripard, Nicolas Pitre, Will Deacon, Dave Martin,
	Marc Zyngier, Viresh Kumar, Mark Brown, Dong Aisheng, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial,
	Stephen Gallimore

On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> diff --git a/arch/arm/mach-stih41x/board-dt.c b/arch/arm/mach-stih41x/board-dt.c
> index 8005f71..1f23aca 100644
> --- a/arch/arm/mach-stih41x/board-dt.c
> +++ b/arch/arm/mach-stih41x/board-dt.c
> @@ -63,6 +63,8 @@ void __init stih41x_dt_init(void)
>  }
>  
>  static const char *stih41x_dt_match[] __initdata = {
> +       "st,stih415-b2000",
> +       "st,stih416-b2000",
>         NULL
>  };

I probably wouldn't bother listing all the boards here. Just make sure
the .dts file lists both the name of the board and of the soc in
its compatible property, and list all the SoCs here that you can boot on.

	Arnd

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

* Re: [RFC 5/8] ARM:stih41x: Add STiH415 SOC support
  2013-05-08 16:18   ` [RFC 5/8] ARM:stih41x: Add STiH415 SOC support Arnd Bergmann
@ 2013-05-08 16:21     ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 16:50     ` Stephen GALLIMORE
  2013-05-08 17:03     ` Srinivas KANDAGATLA
  2 siblings, 0 replies; 64+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-08 16:21 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Srinivas KANDAGATLA, linux-doc, Viresh Kumar, Will Deacon,
	Jiri Slaby, linux, Samuel Ortiz, Nicolas Pitre,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Greg Kroah-Hartman, Mark Brown,
	linux-kernel

On 18:18 Wed 08 May     , Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> > From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> > 
> > The STiH415 is the next generation of HD, AVC set-top box processors for
> > satellite, cable, terrestrial and IP-STB markets. It is an ARM Cortex-A9
> > 1.0 GHz, dual-core CPU.
> > 
> > Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
> > CC: Stephen Gallimore <stephen.gallimore@st.com>
> > CC: Stuart Menefy <stuart.menefy@st.com>
> > ---
patch no receive on the ML

please resend

Best Regards,
J.

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

* Re: [RFC 7/8] ARM:stih41x: Add B2000 board support
  2013-05-08 16:20   ` Arnd Bergmann
@ 2013-05-08 16:24     ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 17:04     ` Srinivas KANDAGATLA
  1 sibling, 0 replies; 64+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-08 16:24 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Srinivas KANDAGATLA, linux-doc, Viresh Kumar, Will Deacon,
	Jiri Slaby, linux, Samuel Ortiz, Nicolas Pitre,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Greg Kroah-Hartman, Mark Brown,
	linux-kernel

On 18:20 Wed 08 May     , Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> > diff --git a/arch/arm/mach-stih41x/board-dt.c b/arch/arm/mach-stih41x/board-dt.c
> > index 8005f71..1f23aca 100644
> > --- a/arch/arm/mach-stih41x/board-dt.c
> > +++ b/arch/arm/mach-stih41x/board-dt.c
> > @@ -63,6 +63,8 @@ void __init stih41x_dt_init(void)
> >  }
> >  
> >  static const char *stih41x_dt_match[] __initdata = {
> > +       "st,stih415-b2000",
> > +       "st,stih416-b2000",
> >         NULL
> >  };
> 
> I probably wouldn't bother listing all the boards here. Just make sure
> the .dts file lists both the name of the board and of the soc in
> its compatible property, and list all the SoCs here that you can boot on.

was going to do the same comment

Best Regards,
J.
> 
> 	Arnd
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss

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

* Re: [RFC 4/8] pinctrl:stixxxx: Add pinctrl and pinconf support.
  2013-05-08 15:06   ` [RFC 4/8] pinctrl:stixxxx: Add pinctrl and pinconf support Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 16:27     ` Srinivas KANDAGATLA
  2013-05-08 16:38       ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 16:27 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD
  Cc: linus.walleij, Viresh Kumar, Will Deacon, Jiri Slaby,
	Russell King, Samuel Ortiz, Nicolas Pitre, linux-doc,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Greg Kroah-Hartman, Mark Brown,
	linux-kernel

Thankyou for the comments.
On 08/05/13 16:06, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 15:11 Wed 08 May     , Srinivas KANDAGATLA wrote:
>> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>>
>> This patch add pinctrl support to ST SoCs.
>>
>> About hardware:
>> ST Set-Top-Box parts have two blocks called PIO and PIO-mux which handle
>> pin configurations.
>>
>> Each multi-function pin is controlled, driven and routed through the PIO
>> multiplexing block. Each pin supports GPIO functionality (ALT0) and
>> multiple alternate functions(ALT1 - ALTx) that directly connect the pin
>> to different hardware blocks. When a pin is in GPIO mode, Output Enable
>> (OE), Open Drain(OD), and Pull Up (PU) are driven by the related PIO
>> block. Otherwise the PIO multiplexing block configures these parameters
>> and retiming the signal.
>>
> g> About driver:
>> This pinctrl driver manages both PIO and PIO-mux block using pinctrl,
>> pinconf, pinmux, gpio subsystems. All the pinctrl related config
>> information can only come from device trees.
>>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>> CC: Stephen Gallimore <stephen.gallimore@st.com>
>> CC: Stuart Menefy <stuart.menefy@st.com>
>> ---
>>  .../bindings/pinctrl/pinctrl-stixxxx.txt           |  160 +++
>>  drivers/pinctrl/Kconfig                            |   13 +
>>  drivers/pinctrl/Makefile                           |    1 +
>>  drivers/pinctrl/pinctrl-stixxxx.c                  | 1151 ++++++++++++++++++++
>>  drivers/pinctrl/pinctrl-stixxxx.h                  |  197 ++++
> the pinctrl is present in older SoC ST40 not only stixxx
>
> and you must provide a proper name not stixxxx
The reason for giving it stixxxx name is all the set-top-box based SOCs
have the naming convention of stixxxx like stih7108, stih415, stih416
and stig125.. and so on..

>>  5 files changed, 1522 insertions(+), 0 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
>>  create mode 100644 drivers/pinctrl/pinctrl-stixxxx.c
>>  create mode 100644 drivers/pinctrl/pinctrl-stixxxx.h
>>
>> diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
>> new file mode 100644
>> index 0000000..b0a93b5
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
>> @@ -0,0 +1,160 @@
>> +*ST pin controller.
>> +
>> +Each multi-function pin is controlled, driven and routed through the
>> +PIO multiplexing block. Each pin supports GPIO functionality (ALT0)
>> +and multiple alternate functions(ALT1 - ALTx) that directly connect
>> +the pin to different hardware blocks.
>> +
>> +When a pin is in GPIO mode, Output Enable (OE), Open Drain(OD), and
>> +Pull Up (PU) are driven by the related PIO block.
> HighZ too
>
> this driver look very similar with AT91 we should consolidate at binding and C
> level
Yes, it look very similar to at91, however they are very much different
w.r.t pinconf.
>> ---
>> +
>> +ST pinctrl driver controls PIO multiplexing block and also interacts with
>> +gpio driver to configure a pin.
>> +
>> +Required properties: (PIO multiplexing block)
>> +- compatible	: should be "st,stixxxx-pinctrl"
>> +			each subnode should set "st,stixxxx-gpio"
>> +			as compatible for each gpio-controller bank.
> first soc where the IP is present
>> +- gpio-controller : Indicates this device is a GPIO controller
>> +- #gpio-cells	  : Should be one. The first cell is the pin number.
>> +- #retime-delay-cells	: Should be number of possible retime delays.
>> +- st,retime-in-delay	: Should be array of delays in nsecs.
>> +- st,retime-out-delay	: Should be array of delays in nsecs.
>> +- retime-style		: Should indicate which type of retime is used.
>> +			possible values are "none", "packed" and "dedicated".
> always prefix st, when specific property
> st,
Its a typo, will fix it.
>> +- st,retime-offset	: phandle to retime offsets in retime registers.
>> +		These are not necessary for "dedicated" retime-style registers.
>> +	- clk1notclk0	: Should define offset for clk1not clk0 in retime register.
>> +	- delay-lsb	: Should define offset for delay-lsb in retime register.
>> +	- delay-msb	: Should define offset for delay msb in retime register.
>> +	- invertclk	: Should define offset for invertclk in retime register.
>> +	- retime	: Should define offset for retime in retime register.
>> +	- clknotdata	: Should define offset for clknotdata in retime register.
>> +	- double_edge	: Should define offset for double edge in retime register.
> As much as I like to describe the IP in the DT, I think it's too much this
> time move this to C and use the compatible or detect it on the hardware to
> handle this 
That is a good idea.
>
>> +- st,alt-control		: Should be sysconf to control alternate function on pio.
>> +- st,oe-control		: Should be sysconf to control output enable on pio.
>> +- st,pu-control		: Should be sysconf to control pull up on pio.
>> +- st,od-control		: Should be sysconf to control open drain on pio.
>> +- st,retime-style		: Should indicate which type of retime is used.
>> +			possible values are "none", "packed" and "dedicated".
>> +- st,retime-pin-mask	: Should be mask to specify which pins can be retimed.
>> +- retime-control[0...N]: These properties point to sysconfs which control retime.
>> +			Depending on retime-style the number of retime-controls
>> +			vary: 2 for "packed"; 8 for "dedicated".
>
>> +- st,bank-name		: Should be a name string for this bank.
>> +
>> +Example:
>> +	pio_retime_offset: pio-retime-offset {
>> +		clk1notclk0	= <0>;
>> +		delay-lsb	= <2>;
>> +		delay-msb	= <3>;
>> +		invertclk	= <4>;
>> +		retime		= <5>;
>> +		clknotdata	= <6>;
>> +		double-edge	= <7>;
>> +	};
>> +
>> +	pin-controller {
>> +		#retime-delay-cells = <4>;
>> +		compatible = "st,stixxxx-pinctrl", "simple-bus";
>> +		st,retime-offset = <&pio_retime_offset>;
>> +		st,retime-in-delay = <0 500 1000 1500>;
>> +		st,retime-out-delay = <0 1000 2000 3000>;
>> +		ranges;
>> +		PIO0: pinctrl@fe610000 {
>> +			gpio-controller;
>> +			#gpio-cells = <1>;
>> +			compatible = "st,stixxxx-gpio";
>> +			reg = <0xfe610000 0x100>;
>> +			st,bank-name  = "PIO0";
>> +			st,alt-control = <&SYSCONF_SBC(0) 0 31>;
>> +			st,oe-control = <&SYSCONF_SBC(5)  0 7>;
>> +			st,pu-control = <&SYSCONF_SBC(7)  0 7>;
>> +			st,od-control = <&SYSCONF_SBC(9)  0 7>;
>> +			st,retime-style = "packed";
>> +			st,retime-pin-mask = <0xff>;
>> +			st,retime-control0 = <&SYSCONF_SBC(16) 0 31>;
>> +			st,retime-control1 = <&SYSCONF_SBC(17) 0 31>;
>> +		};
>> +		...
>> +		pin-functions nodes follow...
>> +	};
>> +
>> +
>> +Contents of function subnode node:
>> +----------------------
>> +Required properties for pin configuration node:
>> +- st,function	: Should be alternate function number associated
>> +		with this set of pins.
>> +		possible altfunction values:
>> +		ALT1
>> +		ALT2
>> +		ALT3
>> +		ALT4
>> +		ALT5
>> +		ALT6
>> +		ALT7
> use number in the DoC
Ok.
>
>> +
>> +- st,pins	: Child node with list of pins with configuration.
>> +
>> +Below is the format of how each pin conf should look like.
>> +
>> +<bank offset mode rt_type rt_delay rt_clk>
>> +
>> +Every PIO is represented with 4-7 parameters depending on retime configuration.
>> +Each parameter is explained as below.
>> +
>> +-bank		: Should be bank phandle to which this PIO belongs.
>> +-offset		: Offset in the PIO bank.
>> +-mode		:pin configuration is selected from one of the below values.
>> +		IN
>> +		IN_PU
>> +		OUT
>> +		BIDIR
>> +		BIDIR_PU
> ditto
Actually these modes are top level defines of three different variables,
OE, PU, OD used in the registers.
Its very common that driver might just be interested in one of listed modes.
>> +
>> +-rt_type	Retiming Configuration for the pin.
>> +		Possible retime configuration are:
>> +
>> +		-------		-------------
>> +		value		args
>> +		-------		-------------
>> +		NICLK		<delay> <clk>
>> +		ICLK_IO		<delay> <clk>
>> +		BYPASS		<delay>
>> +		DE_IO		<delay> <clk>
>> +		SE_ICLK_IO	<delay> <clk>
>> +		SE_NICLK_IO	<delay> <clk>
>> +
>> +- delay	is retime delay in pico seconds.
>> +		Possible values are: refer to retime-in/out-delays
>> +
>> +- rt_clk	:clk to be use for retime.
>> +		Possible values are:
>> +		CLK_A
>> +		CLK_B
>> +		CLK_C
>> +		CLK_D
>> +
>> +Example of mmcclk pin which is a bi-direction pull pu with retime config
>> +as non inverted clock retimed with CLK_B and delay of 0 pico seconds:
>> +
>> +pin-controller {
>> +	...
>> +	mmc0 {
>> +		pinctrl_mmc: mmc {
>> +			st,function = <ALT4>;
>> +			st,pins {
>> +				mmcclk = <&PIO13 4 BIDIR_PU NICLK  0  CLK_B>;
>> +				...
>> +			};
>> +		};
>> +	...
>> +	};
>> +};
>> +
>> +sdhci0:sdhci@fe810000{
>> +	...
>> +	pinctrl-names = "default";
>> +	pinctrl-0	= <&pinctrl_mmc>;
>> +};
>> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
>> index 34f51d2..611a399 100644
>> --- a/drivers/pinctrl/Kconfig
>> +++ b/drivers/pinctrl/Kconfig
>> @@ -179,6 +179,19 @@ config PINCTRL_SUNXI
>>  	select PINMUX
>>  	select GENERIC_PINCONF
>>  
>> +config PINCTRL_STIXXXX
>> +	bool "ST Microelectronics pin controller driver for STixxxx SoCs"
>> +	depends on PLAT_STIXXXX
>> +	select PINMUX
>> +	select PINCONF
>> +	select MFD_SYSCON
>> +	help
>> +	  Say yes here to support pinctrl interface on STixxxx SOCs.
>> +	  This driver is used to control both PIO block and PIO-mux
>> +	  block to configure a pin.
>> +
>> +	  If unsure, say N.
>> +
>>  config PINCTRL_TEGRA
>>  	bool
>>  	select PINMUX
>> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
>> index f82cc5b..99a2c78 100644
>> --- a/drivers/pinctrl/Makefile
>> +++ b/drivers/pinctrl/Makefile
>> @@ -47,6 +47,7 @@ obj-$(CONFIG_PINCTRL_EXYNOS)	+= pinctrl-exynos.o
>>  obj-$(CONFIG_PINCTRL_EXYNOS5440)	+= pinctrl-exynos5440.o
>>  obj-$(CONFIG_PINCTRL_XWAY)	+= pinctrl-xway.o
>>  obj-$(CONFIG_PINCTRL_LANTIQ)	+= pinctrl-lantiq.o
>> +obj-$(CONFIG_PINCTRL_STIXXXX) 	+= pinctrl-stixxxx.o
>>  
>>  obj-$(CONFIG_PLAT_ORION)        += mvebu/
>>  obj-$(CONFIG_ARCH_SHMOBILE)	+= sh-pfc/
>> diff --git a/drivers/pinctrl/pinctrl-stixxxx.c b/drivers/pinctrl/pinctrl-stixxxx.c
>> new file mode 100644
>> index 0000000..7d2c59c
>> --- /dev/null
>> +++ b/drivers/pinctrl/pinctrl-stixxxx.c
>> @@ -0,0 +1,1151 @@
>> +/*
>> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
>> + * Authors:
>> + *	Srinivas Kandagatla <srinivas.kandagatla@st.com>
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/module.h>
>> +#include <linux/slab.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/of.h>
>> +#include <linux/of_gpio.h>
>> +#include <linux/of_address.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/pinctrl/pinctrl.h>
>> +#include <linux/pinctrl/pinmux.h>
>> +#include <linux/pinctrl/pinconf.h>
>> +#include <linux/platform_device.h>
>> +#include "core.h"
>> +#include "pinctrl-stixxxx.h"
>> +
>> +struct stixxxx_pinconf {
>> +	int		pin;
>> +	const char	*name;
>> +	unsigned long	config;
>> +};
>> +
>> +struct stixxxx_pmx_func {
>> +	const char	*name;
>> +	const char	**groups;
>> +	unsigned	ngroups;
>> +};
>> +
>> +struct stixxxx_pctl_group {
>> +	const char		*name;
>> +	unsigned int		*pins;
>> +	unsigned		npins;
>> +	int			altfunc;
>> +	struct stixxxx_pinconf	*pin_conf;
>> +};
>> +
>> +#define to_stixxxx_gpio_port(chip) \
>> +		container_of(chip, struct stixxxx_gpio_port, gpio_chip)
>> +
>> +struct stixxxx_gpio_port {
>> +	struct gpio_chip	gpio_chip;
>> +	struct pinctrl_gpio_range range;
>> +	void __iomem		*base;
>> +	struct device_node	*of_node;
>> +	const char		*bank_name;
>> +};
>> +
>> +static struct stixxxx_gpio_port *gpio_ports[STIXXXX_MAX_GPIO_BANKS];
>> +
>> +struct stixxxx_pinctrl {
>> +	struct device			*dev;
>> +	struct pinctrl_dev		*pctl;
>> +	int				nbanks;
>> +	struct stixxxx_pmx_func		*functions;
>> +	int				nfunctions;
>> +	struct stixxxx_pctl_group	*groups;
>> +	int				ngroups;
>> +	struct stixxxx_pio_control	*pio_controls;
>> +};
>> +
>> +/* Low level functions.. */
>> +static void stixxxx_pinconf_set_direction(struct stixxxx_pio_control *pc,
>> +				int pin_id, unsigned long config)
>> +{
>> +	struct syscon_field *output_enable;
>> +	struct syscon_field *pull_up;
>> +	struct syscon_field *open_drain;
>> +	unsigned long oe_value, pu_value, od_value;
>> +	unsigned long mask;
>> +	int pin = stixxxx_gpio_pin(pin_id);
>> +
>> +	output_enable = pc->oe;
>> +	pull_up = pc->pu;
>> +	open_drain = pc->od;
>> +
>> +	mask = BIT(pin);
>> +
>> +	oe_value = syscon_read(output_enable);
>> +	pu_value = syscon_read(pull_up);
>> +	od_value = syscon_read(open_drain);
>> +
>> +	/* Clear old values */
>> +	oe_value &= ~mask;
>> +	pu_value &= ~mask;
>> +	od_value &= ~mask;
>> +
>> +	if (config & STIXXXX_PINCONF_OE)
>> +		oe_value |= mask;
>> +	if (config & STIXXXX_PINCONF_PU)
>> +		pu_value |= mask;
>> +	if (config & STIXXXX_PINCONF_OD)
>> +		od_value |= mask;
>> +
>> +	syscon_write(output_enable, oe_value);
>> +	syscon_write(pull_up, pu_value);
>> +	syscon_write(open_drain, od_value);
>> +}
>> +
>> +static void stixxxx_pctl_set_function(struct stixxxx_pio_control *pc,
>> +				int pin_id, int function)
>> +{
>> +	struct syscon_field *selector;
>> +	int offset;
>> +	unsigned long val;
>> +	int pin = stixxxx_gpio_pin(pin_id);
>> +
>> +	selector = pc->alt;
>> +	offset = pin * 4;
>> +	val = syscon_read(selector);
>> +	val &= ~(0xf << offset);
>> +	val |= function << offset;
>> +	syscon_write(selector, val);
>> +}
>> +
>> +static unsigned long stixxxx_pinconf_delay_to_bit(unsigned int delay,
>> +		const struct stixxxx_retime_params *rt_params,
>> +		unsigned long config)
>> +{
>> +	unsigned int *delay_times;
>> +	int num_delay_times, i, closest_index = -1;
>> +	unsigned int closest_divergence = UINT_MAX;
>> +
>> +	if (STIXXXX_PINCONF_UNPACK_OE(config)) {
>> +		delay_times = rt_params->delay_times_out;
>> +		num_delay_times = rt_params->num_delay_times_out;
>> +	} else {
>> +		delay_times = rt_params->delay_times_in;
>> +		num_delay_times = rt_params->num_delay_times_in;
>> +	}
>> +
>> +	for (i = 0; i < num_delay_times; i++) {
>> +		unsigned int divergence = abs(delay - delay_times[i]);
>> +
>> +		if (divergence == 0)
>> +			return i;
>> +
>> +		if (divergence < closest_divergence) {
>> +			closest_divergence = divergence;
>> +			closest_index = i;
>> +		}
>> +	}
>> +
>> +	pr_warn("Attempt to set delay %d, closest available %d\n",
>> +	     delay, delay_times[closest_index]);
>> +
>> +	return closest_index;
>> +}
>> +
>> +static unsigned long stixxxx_pinconf_bit_to_delay(unsigned int index,
>> +		const struct stixxxx_retime_params *rt_params,
>> +		unsigned long output)
>> +{
>> +	unsigned int *delay_times;
>> +	int num_delay_times;
>> +
>> +	if (output) {
>> +		delay_times = rt_params->delay_times_out;
>> +		num_delay_times = rt_params->num_delay_times_out;
>> +	} else {
>> +		delay_times = rt_params->delay_times_in;
>> +		num_delay_times = rt_params->num_delay_times_in;
>> +	}
>> +
>> +	if (index < num_delay_times) {
>> +		return delay_times[index];
>> +	} else {
>> +		pr_warn("Delay not found in/out delay list\n");
>> +		return 0;
>> +	}
>> +}
>> +
>> +static void stixxxx_pinconf_set_retime_packed(
>> +		struct stixxxx_pio_control *pc,
>> +		unsigned long config, int pin)
>> +{
>> +	const struct stixxxx_retime_params *rt_params = pc->rt_params;
>> +	const struct stixxxx_retime_offset *offset = rt_params->retime_offset;
>> +	struct syscon_field **regs;
>> +	unsigned long values[2];
>> +	unsigned long mask;
>> +	int i, j;
>> +	int clk = STIXXXX_PINCONF_UNPACK_RT_CLK(config);
>> +	int clknotdata = STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config);
>> +	int double_edge = STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
>> +	int invertclk = STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config);
>> +	int retime = STIXXXX_PINCONF_UNPACK_RT(config);
>> +	unsigned long delay = stixxxx_pinconf_delay_to_bit(
>> +			STIXXXX_PINCONF_UNPACK_RT_DELAY(config),
>> +			pc->rt_params, config);
>> +
>> +	unsigned long rt_cfg =
>> +		((clk		& 1) << offset->clk1notclk0_offset) |
>> +		((clknotdata	& 1) << offset->clknotdata_offset) |
>> +		((delay		& 1) << offset->delay_lsb_offset) |
>> +		(((delay >> 1)  & 1) << offset->delay_msb_offset) |
>> +		((double_edge	& 1) << offset->double_edge_offset) |
>> +		((invertclk	& 1) << offset->invertclk_offset) |
>> +		((retime	& 1) << offset->retime_offset);
>> +
>> +	regs = pc->retiming;
>> +	values[0] = syscon_read(regs[0]);
>> +	values[1] = syscon_read(regs[1]);
>> +
>> +	for (i = 0; i < 2; i++) {
>> +		mask = BIT(pin);
>> +		for (j = 0; j < 4; j++) {
>> +			if (rt_cfg & 1)
>> +				values[i] |= mask;
>> +			else
>> +				values[i] &= ~mask;
>> +			mask <<= 8;
>> +			rt_cfg >>= 1;
>> +		}
>> +	}
>> +
>> +	syscon_write(regs[0], values[0]);
>> +	syscon_write(regs[1], values[1]);
>> +}
>> +
>> +static void stixxxx_pinconf_set_retime_dedicated(
>> +	struct stixxxx_pio_control *pc,
>> +	unsigned long config, int pin)
>> +{
>> +	struct syscon_field *reg;
>> +	int input = STIXXXX_PINCONF_UNPACK_OE(config) ? 0 : 1;
>> +	int clk = STIXXXX_PINCONF_UNPACK_RT_CLK(config);
>> +	int clknotdata = STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config);
>> +	int double_edge = STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
>> +	int invertclk = STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config);
>> +	int retime = STIXXXX_PINCONF_UNPACK_RT(config);
>> +	unsigned long delay = stixxxx_pinconf_delay_to_bit(
>> +			STIXXXX_PINCONF_UNPACK_RT_DELAY(config),
>> +			pc->rt_params, config);
>> +
>> +	unsigned long retime_config =
>> +		((clk		& 0x3) << 0) |
>> +		((clknotdata	& 0x1) << 2) |
>> +		((delay		& 0xf) << 3) |
>> +		((input		& 0x1) << 7) |
>> +		((double_edge	& 0x1) << 8) |
>> +		((invertclk	& 0x1) << 9) |
>> +		((retime	& 0x1) << 10);
>> +
>> +	reg = pc->retiming[pin];
>> +	syscon_write(reg, retime_config);
>> +}
>> +
>> +static void stixxxx_pinconf_get_direction(struct stixxxx_pio_control *pc,
>> +	int pin_id, unsigned long *config)
>> +{
>> +	unsigned long oe_value, pu_value, od_value;
>> +	int pin = stixxxx_gpio_pin(pin_id);
>> +
>> +	oe_value = (syscon_read(pc->oe) >> pin) & 1;
>> +	pu_value = (syscon_read(pc->pu) >> pin) & 1;
>> +	od_value = (syscon_read(pc->od) >> pin) & 1;
>> +
>> +	STIXXXX_PINCONF_PACK_OE(*config, oe_value);
>> +	STIXXXX_PINCONF_PACK_PU(*config, pu_value);
>> +	STIXXXX_PINCONF_PACK_OD(*config, od_value);
>> +}
>> +
>> +static int stixxxx_pinconf_get_retime_packed(
>> +		struct stixxxx_pio_control *pc,
>> +		int pin, unsigned long *config)
>> +{
>> +	const struct stixxxx_retime_params *rt_params = pc->rt_params;
>> +	const struct stixxxx_retime_offset *offset = rt_params->retime_offset;
>> +	unsigned long delay_bits, delay, rt_reduced;
>> +	unsigned long rt_value[2];
>> +	int i, j;
>> +	int output = STIXXXX_PINCONF_UNPACK_OE(*config);
>> +
>> +	rt_value[0] = syscon_read(pc->retiming[0]);
>> +	rt_value[1] = syscon_read(pc->retiming[1]);
>> +
>> +	rt_reduced = 0;
>> +	for (i = 0; i < 2; i++) {
>> +		for (j = 0; j < 4; j++) {
>> +			if (rt_value[i] & (1<<((8*j)+pin)))
>> +				rt_reduced |= 1 << ((i*4)+j);
>> +		}
>> +	}
>> +
>> +	STIXXXX_PINCONF_PACK_RT(*config,
>> +			(rt_reduced >> offset->retime_offset) & 1);
>> +	STIXXXX_PINCONF_PACK_RT_CLK(*config,
>> +			(rt_reduced >> offset->clk1notclk0_offset) & 1);
>> +	STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(*config,
>> +			(rt_reduced >> offset->clknotdata_offset) & 1);
>> +	STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(*config,
>> +			(rt_reduced >> offset->double_edge_offset) & 1);
>> +	STIXXXX_PINCONF_PACK_RT_INVERTCLK(*config,
>> +			(rt_reduced >> offset->invertclk_offset) & 1);
>> +
>> +	delay_bits =  (((rt_reduced >> offset->delay_msb_offset) & 1)<<1) |
>> +			((rt_reduced >> offset->delay_lsb_offset) & 1);
>> +	delay =  stixxxx_pinconf_bit_to_delay(delay_bits, rt_params, output);
>> +	STIXXXX_PINCONF_PACK_RT_DELAY(*config, delay);
>> +	return 0;
>> +}
>> +
>> +static int stixxxx_pinconf_get_retime_dedicated(
>> +		struct stixxxx_pio_control *pc,
>> +		int pin, unsigned long *config)
>> +{
>> +	unsigned long value;
>> +	unsigned long delay_bits, delay;
>> +	const struct stixxxx_retime_params *rt_params = pc->rt_params;
>> +	int output = STIXXXX_PINCONF_UNPACK_OE(*config);
>> +
>> +	value = syscon_read(pc->retiming[pin]);
>> +	STIXXXX_PINCONF_PACK_RT_CLK(*config, ((value >> 0) & 0x3));
>> +	STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(*config, ((value >> 2) & 0x1));
>> +	delay_bits = ((value >> 3) & 0xf);
>> +	delay =  stixxxx_pinconf_bit_to_delay(delay_bits, rt_params, output);
>> +	STIXXXX_PINCONF_PACK_RT_DELAY(*config, delay);
>> +	STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(*config, ((value >> 8) & 0x1));
>> +	STIXXXX_PINCONF_PACK_RT_INVERTCLK(*config, ((value >> 9) & 0x1));
>> +	STIXXXX_PINCONF_PACK_RT(*config, ((value >> 10) & 0x1));
>> +
>> +	return 0;
>> +}
>> +
>> +/* GPIO related functions */
>> +
>> +static inline void __stixxxx_gpio_set(struct stixxxx_gpio_port *port,
>> +	unsigned offset, int value)
>> +{
>> +	if (value)
>> +		writel(BIT(offset), port->base + REG_PIO_SET_POUT);
>> +	else
>> +		writel(BIT(offset), port->base + REG_PIO_CLR_POUT);
>> +}
>> +
>> +static void stixxxx_gpio_direction(unsigned int gpio, unsigned int direction)
>> +{
>> +	int port_num = stixxxx_gpio_port(gpio);
>> +	int offset = stixxxx_gpio_pin(gpio);
>> +	struct stixxxx_gpio_port *port  = gpio_ports[port_num];
>> +	int i = 0;
>> +
>> +	for (i = 0; i <= 2; i++) {
>> +		if (direction & BIT(i))
>> +			writel(BIT(offset), port->base + REG_PIO_SET_PC(i));
>> +		else
>> +			writel(BIT(offset), port->base + REG_PIO_CLR_PC(i));
>> +	}
>> +}
>> +
>> +static int stixxxx_gpio_request(struct gpio_chip *chip, unsigned offset)
>> +{
>> +	return pinctrl_request_gpio(chip->base + offset);
>> +}
>> +
>> +static void stixxxx_gpio_free(struct gpio_chip *chip, unsigned offset)
>> +{
>> +	pinctrl_free_gpio(chip->base + offset);
>> +}
>> +
>> +static int stixxxx_gpio_get(struct gpio_chip *chip, unsigned offset)
>> +{
>> +	struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
>> +
>> +	return (readl(port->base + REG_PIO_PIN) >> offset) & 1;
>> +}
>> +
>> +static void stixxxx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
>> +{
>> +	struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
>> +	__stixxxx_gpio_set(port, offset, value);
>> +}
>> +
>> +static int stixxxx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
>> +{
>> +	pinctrl_gpio_direction_input(chip->base + offset);
>> +	return 0;
>> +}
>> +
>> +static int stixxxx_gpio_direction_output(struct gpio_chip *chip,
>> +	unsigned offset, int value)
>> +{
>> +	struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
>> +
>> +	__stixxxx_gpio_set(port, offset, value);
>> +	pinctrl_gpio_direction_output(chip->base + offset);
>> +
>> +	return 0;
>> +}
>> +
>> +static int stixxxx_gpio_xlate(struct gpio_chip *gc,
>> +			const struct of_phandle_args *gpiospec, u32 *flags)
>> +{
>> +	if (WARN_ON(gc->of_gpio_n_cells < 1))
>> +		return -EINVAL;
>> +
>> +	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
>> +		return -EINVAL;
>> +
>> +	if (gpiospec->args[0] > gc->ngpio)
>> +		return -EINVAL;
>> +
>> +	return gpiospec->args[0];
>> +}
>> +
>> +/* Pinctrl Groups */
>> +static int stixxxx_pctl_get_groups_count(struct pinctrl_dev *pctldev)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +
>> +	return info->ngroups;
>> +}
>> +
>> +static const char *stixxxx_pctl_get_group_name(struct pinctrl_dev *pctldev,
>> +				       unsigned selector)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +
>> +	return info->groups[selector].name;
>> +}
>> +
>> +static int stixxxx_pctl_get_group_pins(struct pinctrl_dev *pctldev,
>> +	unsigned selector, const unsigned **pins, unsigned *npins)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +
>> +	if (selector >= info->ngroups)
>> +		return -EINVAL;
>> +
>> +	*pins = info->groups[selector].pins;
>> +	*npins = info->groups[selector].npins;
>> +
>> +	return 0;
>> +}
>> +
>> +static const inline struct stixxxx_pctl_group *stixxxx_pctl_find_group_by_name(
>> +	const struct stixxxx_pinctrl *info, const char *name)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < info->ngroups; i++) {
>> +		if (!strcmp(info->groups[i].name, name))
>> +			return &info->groups[i];
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +static int stixxxx_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
>> +	struct device_node *np, struct pinctrl_map **map, unsigned *num_maps)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +	const struct stixxxx_pctl_group *grp;
>> +	struct pinctrl_map *new_map;
>> +	struct device_node *parent;
>> +	int map_num, i;
>> +
>> +	grp = stixxxx_pctl_find_group_by_name(info, np->name);
>> +	if (!grp) {
>> +		dev_err(info->dev, "unable to find group for node %s\n",
>> +			np->name);
>> +		return -EINVAL;
>> +	}
>> +
>> +	map_num = grp->npins + 1;
>> +	new_map = devm_kzalloc(pctldev->dev,
>> +				sizeof(*new_map) * map_num, GFP_KERNEL);
>> +	if (!new_map)
>> +		return -ENOMEM;
>> +
>> +	parent = of_get_parent(np);
>> +	if (!parent) {
>> +		devm_kfree(pctldev->dev, new_map);
>> +		return -EINVAL;
>> +	}
>> +
>> +	*map = new_map;
>> +	*num_maps = map_num;
>> +	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
>> +	new_map[0].data.mux.function = parent->name;
>> +	new_map[0].data.mux.group = np->name;
>> +	of_node_put(parent);
>> +
>> +	/* create config map per pin */
>> +	new_map++;
>> +	for (i = 0; i < grp->npins; i++) {
>> +		new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
>> +		new_map[i].data.configs.group_or_pin =
>> +				pin_get_name(pctldev, grp->pins[i]);
>> +		new_map[i].data.configs.configs = &grp->pin_conf[i].config;
>> +		new_map[i].data.configs.num_configs = 1;
>> +	}
>> +	dev_info(pctldev->dev, "maps: function %s group %s num %d\n",
>> +		(*map)->data.mux.function, grp->name, map_num);
>> +
>> +	return 0;
>> +}
>> +
>> +static void stixxxx_pctl_dt_free_map(struct pinctrl_dev *pctldev,
>> +				struct pinctrl_map *map, unsigned num_maps)
>> +{
>> +}
>> +
>> +static struct pinctrl_ops stixxxx_pctlops = {
>> +	.get_groups_count	= stixxxx_pctl_get_groups_count,
>> +	.get_group_pins		= stixxxx_pctl_get_group_pins,
>> +	.get_group_name		= stixxxx_pctl_get_group_name,
>> +	.dt_node_to_map		= stixxxx_pctl_dt_node_to_map,
>> +	.dt_free_map		= stixxxx_pctl_dt_free_map,
>> +};
>> +
>> +/* Pinmux */
>> +static int stixxxx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +
>> +	return info->nfunctions;
>> +}
>> +
>> +const char *stixxxx_pmx_get_fname(struct pinctrl_dev *pctldev,
>> +	unsigned selector)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +
>> +	return info->functions[selector].name;
>> +}
>> +
>> +static int stixxxx_pmx_get_groups(struct pinctrl_dev *pctldev,
>> +	unsigned selector, const char * const **grps, unsigned * const ngrps)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +	*grps = info->functions[selector].groups;
>> +	*ngrps = info->functions[selector].ngroups;
>> +
>> +	return 0;
>> +}
>> +
>> +static struct stixxxx_pio_control *stixxxx_get_pio_control(
>> +			struct stixxxx_pinctrl *info, int pin_id)
>> +{
>> +	int port = stixxxx_gpio_port(pin_id);
>> +	return &info->pio_controls[port];
>> +}
>> +
>> +static int stixxxx_pmx_enable(struct pinctrl_dev *pctldev, unsigned fselector,
>> +		unsigned group)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +	struct stixxxx_pinconf *conf = info->groups[group].pin_conf;
>> +	struct stixxxx_pio_control *pc;
>> +	int i;
>> +
>> +	for (i = 0; i < info->groups[group].npins; i++) {
>> +		pc = stixxxx_get_pio_control(info, conf[i].pin);
>> +		stixxxx_pctl_set_function(pc, conf[i].pin,
>> +					info->groups[group].altfunc);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void stixxxx_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
>> +		unsigned group)
>> +{
>> +}
>> +
>> +static int stixxxx_pmx_set_gpio_direction(struct pinctrl_dev *pctldev,
>> +			struct pinctrl_gpio_range *range, unsigned gpio,
>> +			bool input)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +	struct stixxxx_pio_control *pc = &info->pio_controls[range->id];
>> +	/*
>> +	 * When a PIO port is used in its primary function mode (altfunc = 0)
>> +	 * Output Enable (OE), Open Drain(OD), and Pull Up (PU)
>> +	 * for the primary PIO functions are driven by the related PIO block
>> +	 */
>> +	stixxxx_pctl_set_function(pc, gpio, 0);
>> +	stixxxx_gpio_direction(gpio, input ?
>> +		STIXXXX_GPIO_DIRECTION_IN : STIXXXX_GPIO_DIRECTION_OUT);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct pinmux_ops stixxxx_pmxops = {
>> +	.get_functions_count	= stixxxx_pmx_get_funcs_count,
>> +	.get_function_name	= stixxxx_pmx_get_fname,
>> +	.get_function_groups	= stixxxx_pmx_get_groups,
>> +	.enable			= stixxxx_pmx_enable,
>> +	.disable		= stixxxx_pmx_disable,
>> +	.gpio_set_direction	= stixxxx_pmx_set_gpio_direction,
>> +};
>> +
>> +/* Pinconf  */
>> +static void stixxxx_pinconf_get_retime(struct stixxxx_pio_control *pc,
>> +	int pin_id, unsigned long *config)
>> +{
>> +	int pin = stixxxx_gpio_pin(pin_id);
>> +	if (pc->rt_style == stixxxx_retime_style_packed)
>> +		stixxxx_pinconf_get_retime_packed(pc, pin, config);
>> +	else if (pc->rt_style == stixxxx_retime_style_dedicated)
>> +		if ((BIT(pin) & pc->rt_pin_mask))
>> +			stixxxx_pinconf_get_retime_dedicated(pc, pin, config);
>> +}
>> +
>> +static void stixxxx_pinconf_set_retime(struct stixxxx_pio_control *pc,
>> +	int pin_id, unsigned long config)
>> +{
>> +	int pin = stixxxx_gpio_pin(pin_id);
>> +
>> +	if (pc->rt_style == stixxxx_retime_style_packed)
>> +		stixxxx_pinconf_set_retime_packed(pc, config, pin);
>> +	else if (pc->rt_style == stixxxx_retime_style_dedicated)
>> +		if ((BIT(pin) & pc->rt_pin_mask))
>> +			stixxxx_pinconf_set_retime_dedicated(pc, config, pin);
>> +}
>> +
>> +static int stixxxx_pinconf_set(struct pinctrl_dev *pctldev,
>> +			     unsigned pin_id, unsigned long config)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +	struct stixxxx_pio_control *pc = stixxxx_get_pio_control(info, pin_id);
>> +
>> +	stixxxx_pinconf_set_direction(pc, pin_id, config);
>> +	stixxxx_pinconf_set_retime(pc, pin_id, config);
>> +	return 0;
>> +}
>> +
>> +static int stixxxx_pinconf_get(struct pinctrl_dev *pctldev,
>> +			     unsigned pin_id, unsigned long *config)
>> +{
>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>> +	struct stixxxx_pio_control *pc = stixxxx_get_pio_control(info, pin_id);
>> +
>> +	*config = 0;
>> +	stixxxx_pinconf_get_direction(pc, pin_id, config);
>> +	stixxxx_pinconf_get_retime(pc, pin_id, config);
>> +
>> +	return 0;
>> +}
>> +
>> +static void stixxxx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
>> +				   struct seq_file *s, unsigned pin_id)
>> +{
>> +	unsigned long config;
>> +	stixxxx_pinconf_get(pctldev, pin_id, &config);
>> +
>> +	seq_printf(s, "[OE:%ld,PU:%ld,OD:%ld]\n"
>> +		"\t\t[retime:%ld,invclk:%ld,clknotdat:%ld,"
>> +		"de:%ld,rt-clk:%ld,rt-delay:%ld]",
>> +		STIXXXX_PINCONF_UNPACK_OE(config),
>> +		STIXXXX_PINCONF_UNPACK_PU(config),
>> +		STIXXXX_PINCONF_UNPACK_OD(config),
>> +		STIXXXX_PINCONF_UNPACK_RT(config),
>> +		STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config),
>> +		STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config),
>> +		STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config),
>> +		STIXXXX_PINCONF_UNPACK_RT_CLK(config),
>> +		STIXXXX_PINCONF_UNPACK_RT_DELAY(config));
>> +}
>> +
>> +static struct pinconf_ops stixxxx_confops = {
>> +	.pin_config_get		= stixxxx_pinconf_get,
>> +	.pin_config_set		= stixxxx_pinconf_set,
>> +	.pin_config_dbg_show	= stixxxx_pinconf_dbg_show,
>> +};
>> +
>> +/* pinctrl */
>> +static struct pinctrl_desc stixxxx_pctl_desc = {
>> +	.owner		= THIS_MODULE,
>> +	.pctlops	= &stixxxx_pctlops,
>> +	.pmxops		= &stixxxx_pmxops,
>> +	.confops	= &stixxxx_confops,
>> +};
>> +
>> +static int stixxxx_pinconf_dt_parse_rt_params(struct stixxxx_pinctrl *info,
>> +	struct device_node *np,	struct stixxxx_retime_params *params)
>> +{
>> +	const __be32 *ip;
>> +	struct device_node *offset_np;
>> +	struct stixxxx_retime_offset *rt_offset;
>> +	int delay_count = 0;
>> +
>> +	ip = of_get_property(np, "#retime-delay-cells", NULL);
>> +	if (ip)
>> +		delay_count = be32_to_cpup(ip);
>> +	else
>> +		pr_warn("No #retime-delay-cells specified\n");
>> +
>> +	params->num_delay_times_out = delay_count;
>> +	params->num_delay_times_in = delay_count;
>> +	params->delay_times_in = devm_kzalloc(info->dev,
>> +				sizeof(u32) * delay_count, GFP_KERNEL);
>> +	params->delay_times_out = devm_kzalloc(info->dev,
>> +				sizeof(u32) * delay_count, GFP_KERNEL);
>> +
>> +	if (!params->delay_times_in || !params->delay_times_out)
>> +		return -ENOMEM;
>> +
>> +	of_property_read_u32_array(np, "st,retime-in-delay",
>> +				(u32 *)params->delay_times_in, delay_count);
>> +	of_property_read_u32_array(np, "st,retime-out-delay",
>> +				(u32 *)params->delay_times_out, delay_count);
>> +
>> +	offset_np = of_parse_phandle(np, "st,retime-offset", 0);
>> +
>> +	if (offset_np) {
>> +		rt_offset = devm_kzalloc(info->dev,
>> +				sizeof(*rt_offset), GFP_KERNEL);
>> +		if (!rt_offset)
>> +			return -ENOMEM;
>> +
>> +		params->retime_offset = rt_offset;
>> +		WARN_ON(of_property_read_u32(offset_np, "retime",
>> +					&rt_offset->retime_offset));
>> +		WARN_ON(of_property_read_u32(offset_np, "clk1notclk0",
>> +					&rt_offset->clk1notclk0_offset));
>> +		WARN_ON(of_property_read_u32(offset_np, "clknotdata",
>> +					&rt_offset->clknotdata_offset));
>> +		WARN_ON(of_property_read_u32(offset_np, "double-edge",
>> +					&rt_offset->double_edge_offset));
>> +		WARN_ON(of_property_read_u32(offset_np, "invertclk",
>> +					&rt_offset->invertclk_offset));
>> +		WARN_ON(of_property_read_u32(offset_np, "delay-lsb",
>> +					&rt_offset->delay_lsb_offset));
>> +		WARN_ON(of_property_read_u32(offset_np, "delay-msb",
>> +					&rt_offset->delay_msb_offset));
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static const char *gpio_compat = "st,stixxxx-gpio";
>> +
>> +static void stixxxx_pctl_dt_child_count(struct stixxxx_pinctrl *info,
>> +				     struct device_node *np)
>> +{
>> +	struct device_node *child;
>> +	for_each_child_of_node(np, child) {
>> +		if (of_device_is_compatible(child, gpio_compat)) {
>> +			info->nbanks++;
>> +		} else {
>> +			info->nfunctions++;
>> +			info->ngroups += of_get_child_count(child);
>> +		}
>> +	}
>> +}
>> +
>> +static int stixxxx_pctl_dt_get_retime_conf(struct device_node *np,
>> +	struct stixxxx_pio_control *pc)
>> +{
>> +	const char *style;
>> +	char name[20];
>> +	unsigned int j;
>> +	of_property_read_string(np, "st,retime-style", &style);
>> +
>> +	if (strcmp(style, "packed") == 0) {
>> +		pc->rt_style = stixxxx_retime_style_packed;
>> +		for (j = 0; j < 2; j++) {
>> +			snprintf(name, sizeof(name), "st,retime-control%d", j);
>> +			pc->retiming[j] = syscon_claim(np, name);
>> +			if (!pc->retiming[j])
>> +				return -ENODATA;
>> +		}
>> +	} else if (strcmp(style, "dedicated") == 0) {
>> +		pc->rt_style = stixxxx_retime_style_dedicated;
>> +		for (j = 0; j < 8; j++) {
>> +			if ((1<<j) & pc->rt_pin_mask) {
>> +				snprintf(name, sizeof(name),
>> +						"st,retime-control%d", j);
>> +				pc->retiming[j] = syscon_claim(np, name);
>> +				if (!pc->retiming[j])
>> +					return -ENODATA;
>> +			}
>> +		}
>> +	} else if (strcmp(style, "none") == 0) {
>> +		pc->rt_style = stixxxx_retime_style_none;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int stixxxx_pctl_dt_init(struct stixxxx_pinctrl *info,
>> +			struct device_node *np)
>> +{
>> +	struct stixxxx_pio_control *pc;
>> +	struct stixxxx_retime_params *rt_params;
>> +	struct device *dev = info->dev;
>> +	unsigned int i = 0;
>> +	struct device_node *child = NULL;
>> +
>> +	pc = devm_kzalloc(dev, sizeof(*pc) * info->nbanks, GFP_KERNEL);
>> +	rt_params = devm_kzalloc(dev, sizeof(*rt_params), GFP_KERNEL);
>> +
>> +	if (!pc || !rt_params)
>> +		return -ENOMEM;
>> +
>> +	info->pio_controls = pc;
>> +	if (stixxxx_pinconf_dt_parse_rt_params(info, np, rt_params))
>> +		return -ENOMEM;
>> +
>> +	for_each_child_of_node(np, child) {
>> +		if (of_device_is_compatible(child, gpio_compat)) {
>> +			pc[i].rt_params = rt_params;
>> +
>> +			pc[i].alt = syscon_claim(child, "st,alt-control");
>> +			if (!pc[i].alt)
>> +				goto failed;
>> +
>> +			pc[i].oe = syscon_claim(child, "st,oe-control");
>> +			if (!pc[i].oe)
>> +				goto failed;
>> +
>> +			pc[i].pu = syscon_claim(child, "st,pu-control");
>> +			if (!pc[i].pu)
>> +				goto failed;
>> +
>> +			pc[i].od = syscon_claim(child, "st,od-control");
>> +			if (!pc[i].od)
>> +				goto failed;
>> +
>> +			of_property_read_u32(child, "st,retime-pin-mask",
>> +							&pc[i].rt_pin_mask);
>> +
>> +			stixxxx_pctl_dt_get_retime_conf(child, &pc[i]);
>> +			i++;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +failed:
>> +	return -ENODATA;
>> +}
>> +
>> +#define OF_GPIO_ARGS_MIN	(3)
>> +/*
>> + * Each pin is represented in of the below forms.
>> + * <bank offset direction func rt_type rt_delay rt_clk>
>> + */
>> +static int stixxxx_pctl_dt_parse_groups(struct device_node *np,
>> +	struct stixxxx_pctl_group *grp, struct stixxxx_pinctrl *info, int idx)
>> +{
>> +	/* bank pad direction val altfunction */
>> +	const __be32 *list;
>> +	struct property *pp;
>> +	struct stixxxx_pinconf *conf;
>> +	phandle phandle;
>> +	struct device_node *pins;
>> +	u32 pin;
>> +	int i = 0, npins = 0, nr_props;
>> +
>> +	pins = of_get_child_by_name(np, "st,pins");
>> +	if (!pins)
>> +		return -ENODATA;
>> +
>> +	for_each_property_of_node(pins, pp) {
>> +		/* Skip those we do not want to proceed */
>> +		if (!strcmp(pp->name, "name"))
>> +			continue;
>> +
>> +		if (pp  && (pp->length/sizeof(__be32)) >= OF_GPIO_ARGS_MIN) {
>> +			npins++;
>> +		} else {
>> +			pr_warn("Invalid st,pins in %s node\n", np->name);
>> +			return -EINVAL;
>> +		}
>> +	}
>> +
>> +	grp->npins = npins;
>> +	grp->name = np->name;
>> +	grp->pins = devm_kzalloc(info->dev, npins * sizeof(u32), GFP_KERNEL);
>> +	grp->pin_conf = devm_kzalloc(info->dev,
>> +					npins * sizeof(*conf), GFP_KERNEL);
>> +	of_property_read_u32(np, "st,function", &grp->altfunc);
>> +
>> +	if (!grp->pins || !grp->pin_conf)
>> +		return -ENOMEM;
>> +
>> +	/* <bank offset direction func rt_type rt_delay rt_clk> */
>> +	for_each_property_of_node(pins, pp) {
>> +		if (!strcmp(pp->name, "name"))
>> +			continue;
>> +		nr_props = pp->length/sizeof(u32);
>> +		list = pp->value;
>> +		conf = &grp->pin_conf[i];
>> +
>> +		/* bank & offset */
>> +		phandle = be32_to_cpup(list++);
>> +		pin = be32_to_cpup(list++);
>> +		conf->pin = of_get_named_gpio(pins, pp->name, 0);
>> +		conf->name = pp->name;
>> +		grp->pins[i] = conf->pin;
>> +
>> +		conf->config = 0;
>> +		/* direction */
>> +		conf->config |= be32_to_cpup(list++);
>> +		/* rt_type rt_delay rt_clk */
>> +		if (nr_props >= OF_GPIO_ARGS_MIN + 2) {
>> +			/* rt_type */
>> +			conf->config |= be32_to_cpup(list++);
>> +			/* rt_delay */
>> +			conf->config |= be32_to_cpup(list++);
>> +			/* rt_clk */
>> +			if (nr_props > OF_GPIO_ARGS_MIN + 2)
>> +				conf->config |= be32_to_cpup(list++);
>> +		}
>> +		i++;
>> +	}
>> +	of_node_put(pins);
>> +
>> +	return 0;
>> +}
>> +
>> +static int stixxxx_pctl_parse_functions(struct device_node *np,
>> +			struct stixxxx_pinctrl *info, u32 index, int *grp_index)
>> +{
>> +	struct device_node *child;
>> +	struct stixxxx_pmx_func *func;
>> +	struct stixxxx_pctl_group *grp;
>> +	int ret, i;
>> +
>> +	func = &info->functions[index];
>> +	func->name = np->name;
>> +	func->ngroups = of_get_child_count(np);
>> +	if (func->ngroups <= 0) {
>> +		dev_err(info->dev, "No groups defined\n");
>> +		return -EINVAL;
>> +	}
>> +	func->groups = devm_kzalloc(info->dev,
>> +			func->ngroups * sizeof(char *), GFP_KERNEL);
>> +	if (!func->groups)
>> +		return -ENOMEM;
>> +
>> +	i = 0;
>> +	for_each_child_of_node(np, child) {
>> +		func->groups[i] = child->name;
>> +		grp = &info->groups[*grp_index];
>> +		*grp_index += 1;
>> +		ret = stixxxx_pctl_dt_parse_groups(child, grp, info, i++);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +	dev_info(info->dev, "Function[%d\t name:%s,\tgroups:%d]\n",
>> +				index, func->name, func->ngroups);
>> +
>> +	return 0;
>> +}
>> +
>> +static int stixxxx_pctl_probe_dt(struct platform_device *pdev,
>> +				 struct stixxxx_pinctrl *info)
>> +{
>> +	int ret = 0;
>> +	int i = 0, j = 0, k = 0;
>> +	struct pinctrl_pin_desc *pdesc;
>> +	struct device_node *np = pdev->dev.of_node;
>> +	struct device_node *child;
>> +	int grp_index = 0;
>> +
>> +	stixxxx_pctl_dt_child_count(info, np);
>> +	if (info->nbanks < 1) {
>> +		dev_err(&pdev->dev, "you need atleast one gpio bank\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = stixxxx_pctl_dt_init(info, np);
>> +	if (ret)
>> +		return ret;
>> +
>> +	dev_info(&pdev->dev, "nbanks = %d\n", info->nbanks);
>> +	dev_info(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
>> +	dev_info(&pdev->dev, "ngroups = %d\n", info->ngroups);
>> +	info->functions = devm_kzalloc(&pdev->dev,
>> +		info->nfunctions * sizeof(*info->functions), GFP_KERNEL);
>> +
>> +	info->groups = devm_kzalloc(&pdev->dev,
>> +		info->ngroups * sizeof(*info->groups) ,	GFP_KERNEL);
>> +
>> +	if (!info->functions || !info->groups)
>> +		return -ENOMEM;
>> +
>> +	stixxxx_pctl_desc.npins = info->nbanks * STIXXXX_GPIO_PINS_PER_PORT;
>> +	pdesc =	devm_kzalloc(&pdev->dev,
>> +			sizeof(*pdesc) * stixxxx_pctl_desc.npins, GFP_KERNEL);
>> +	if (!pdesc)
>> +		return -ENOMEM;
>> +
>> +	stixxxx_pctl_desc.pins = pdesc;
>> +
>> +	for_each_child_of_node(np, child) {
>> +		if (of_device_is_compatible(child, gpio_compat)) {
>> +			for (j = 0; j < STIXXXX_GPIO_PINS_PER_PORT; j++, k++) {
>> +				const char *port_name = NULL;
>> +				pdesc->number = k;
>> +				of_property_read_string(child, "st,bank-name",
>> +							&port_name);
>> +				pdesc->name = kasprintf(GFP_KERNEL, "%s[%d]",
>> +							port_name ? : "PIO",
>> +							port_name ? j : k);
>> +				pdesc++;
>> +			}
>> +		} else {
>> +			ret = stixxxx_pctl_parse_functions(child, info,
>> +							i++, &grp_index);
>> +			if (ret) {
>> +				dev_err(&pdev->dev, "No functions found.\n");
>> +				return ret;
>> +			}
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int stixxxx_pctl_probe(struct platform_device *pdev)
>> +{
>> +	struct stixxxx_pinctrl *info;
>> +	int ret, i;
>> +
>> +	if (!pdev->dev.of_node) {
>> +		dev_err(&pdev->dev, "device node not found.\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
>> +	if (!info)
>> +		return -ENOMEM;
>> +
>> +	info->dev = &pdev->dev;
>> +	platform_set_drvdata(pdev, info);
>> +	ret = stixxxx_pctl_probe_dt(pdev, info);
>> +	if (ret)
>> +		return ret;
>> +
>> +	stixxxx_pctl_desc.name = dev_name(&pdev->dev);
>> +	info->pctl = pinctrl_register(&stixxxx_pctl_desc, &pdev->dev, info);
>> +	if (IS_ERR(info->pctl)) {
>> +		dev_err(&pdev->dev, "Failed pinctrl registration\n");
>> +		return PTR_ERR(info->pctl);
>> +	}
>> +
>> +	for (i = 0; i < info->nbanks; i++)
>> +		pinctrl_add_gpio_range(info->pctl, &gpio_ports[i]->range);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct gpio_chip stixxxx_gpio_template = {
>> +	.request		= stixxxx_gpio_request,
>> +	.free			= stixxxx_gpio_free,
>> +	.get			= stixxxx_gpio_get,
>> +	.set			= stixxxx_gpio_set,
>> +	.direction_input	= stixxxx_gpio_direction_input,
>> +	.direction_output	= stixxxx_gpio_direction_output,
>> +	.ngpio			= STIXXXX_GPIO_PINS_PER_PORT,
>> +	.of_gpio_n_cells	= 1,
>> +	.of_xlate		= stixxxx_gpio_xlate,
>> +};
>> +
>> +static int stixxxx_gpio_probe(struct platform_device *pdev)
>> +{
>> +	struct stixxxx_gpio_port *port;
>> +	struct pinctrl_gpio_range *range;
>> +	struct device_node *np  = pdev->dev.of_node;
>> +	int port_num = of_alias_get_id(np, "gpio");
>> +	struct resource *res;
>> +	int err;
>> +
>> +	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
>> +	if (!port)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	port->base = devm_request_and_ioremap(&pdev->dev, res);
>> +	if (!port->base) {
>> +		dev_err(&pdev->dev, "Can't get IO memory mapping!\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	of_property_read_string(np, "st,bank-name", &port->bank_name);
>> +	port->of_node = np;
>> +
>> +	port->gpio_chip = stixxxx_gpio_template;
>> +	port->gpio_chip.base = port_num * STIXXXX_GPIO_PINS_PER_PORT;
>> +	port->gpio_chip.ngpio = STIXXXX_GPIO_PINS_PER_PORT;
>> +	port->gpio_chip.of_node = np;
>> +	port->gpio_chip.label = dev_name(&pdev->dev);
>> +
>> +	dev_set_drvdata(&pdev->dev, port);
>> +	range = &port->range;
>> +	range->name = port->gpio_chip.label;
>> +	range->id = port_num;
>> +	range->pin_base = range->base = range->id * STIXXXX_GPIO_PINS_PER_PORT;
>> +	range->npins = port->gpio_chip.ngpio;
>> +	range->gc = &port->gpio_chip;
>> +	gpio_ports[port_num] = port;
>> +	err  = gpiochip_add(&port->gpio_chip);
>> +	if (err) {
>> +		dev_err(&pdev->dev, "Failed to add gpiochip(%d)!\n", port_num);
>> +		return err;
>> +	}
>> +	dev_info(&pdev->dev, "gpioport[%s] Added as bank%d\n",
>> +				port->bank_name, port_num);
>> +	return 0;
>> +}
>> +
>> +static struct of_device_id stixxxx_gpio_of_match[] = {
>> +	{ .compatible = "st,stixxxx-gpio", },
>> +	{ /* sentinel */ }
>> +};
>> +
>> +static struct platform_driver stixxxx_gpio_driver = {
>> +	.driver = {
>> +		.name = "st-gpio",
>> +		.owner = THIS_MODULE,
>> +		.of_match_table = of_match_ptr(stixxxx_gpio_of_match),
>> +	},
>> +	.probe = stixxxx_gpio_probe,
>> +};
>> +
>> +static struct of_device_id stixxxx_pctl_of_match[] = {
>> +	{ .compatible = "st,stixxxx-pinctrl",},
>> +	{ /* sentinel */ }
>> +};
>> +
>> +static struct platform_driver stixxxx_pctl_driver = {
>> +	.driver = {
>> +		.name = "st-pinctrl",
>> +		.owner = THIS_MODULE,
>> +		.of_match_table = of_match_ptr(stixxxx_pctl_of_match),
>> +	},
>> +	.probe = stixxxx_pctl_probe,
>> +};
>> +
>> +static int __init stixxxx_pctl_init(void)
>> +{
>> +	int ret = platform_driver_register(&stixxxx_gpio_driver);
>> +	if (ret)
>> +		return ret;
>> +	return platform_driver_register(&stixxxx_pctl_driver);
>> +}
>> +arch_initcall(stixxxx_pctl_init);
>> diff --git a/drivers/pinctrl/pinctrl-stixxxx.h b/drivers/pinctrl/pinctrl-stixxxx.h
>> new file mode 100644
>> index 0000000..a340964
>> --- /dev/null
>> +++ b/drivers/pinctrl/pinctrl-stixxxx.h
>> @@ -0,0 +1,197 @@
>> +
>> +/*
>> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
>> + * Authors:
>> + *	Srinivas Kandagatla <srinivas.kandagatla@st.com>
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#ifndef __LINUX_DRIVERS_PINCTRL_STIXXXX_H
>> +#define __LINUX_DRIVERS_PINCTRL_STIXXXX_H
>> +
>> +enum stixxxx_retime_style {
>> +	stixxxx_retime_style_none,
>> +	stixxxx_retime_style_packed,
>> +	stixxxx_retime_style_dedicated,
>> +};
>> +
>> +/* Byte positions in 2 syscon words, starts from 0 */
>> +struct stixxxx_retime_offset {
>> +	int retime_offset;
>> +	int clk1notclk0_offset;
>> +	int clknotdata_offset;
>> +	int double_edge_offset;
>> +	int invertclk_offset;
>> +	int delay_lsb_offset;
>> +	int delay_msb_offset;
>> +};
>> +
>> +struct stixxxx_retime_params {
>> +	const struct stixxxx_retime_offset *retime_offset;
>> +	unsigned int *delay_times_in;
>> +	int num_delay_times_in;
>> +	unsigned int *delay_times_out;
>> +	int num_delay_times_out;
>> +};
>> +
>> +struct stixxxx_pio_control {
>> +	enum stixxxx_retime_style rt_style;
>> +	u32 rt_pin_mask;
>> +	const struct stixxxx_retime_params *rt_params;
>> +	struct syscon_field *alt;
>> +	struct syscon_field *oe, *pu, *od;
>> +	struct syscon_field *retiming[8];
>> +};
>> +
>> +/* PIO Block registers */
>> +/* PIO output */
>> +#define REG_PIO_POUT			0x00
>> +/* Set bits of POUT */
>> +#define REG_PIO_SET_POUT		0x04
>> +/* Clear bits of POUT */
>> +#define REG_PIO_CLR_POUT		0x08
>> +/* PIO input */
>> +#define REG_PIO_PIN			0x10
>> +/* PIO configuration */
>> +#define REG_PIO_PC(n)			(0x20 + (n) * 0x10)
>> +/* Set bits of PC[2:0] */
>> +#define REG_PIO_SET_PC(n)		(0x24 + (n) * 0x10)
>> +/* Clear bits of PC[2:0] */
>> +#define REG_PIO_CLR_PC(n)		(0x28 + (n) * 0x10)
>> +/* PIO input comparison */
>> +#define REG_PIO_PCOMP			0x50
>> +/* Set bits of PCOMP */
>> +#define REG_PIO_SET_PCOMP		0x54
>> +/* Clear bits of PCOMP */
>> +#define REG_PIO_CLR_PCOMP		0x58
>> +/* PIO input comparison mask */
>> +#define REG_PIO_PMASK			0x60
>> +/* Set bits of PMASK */
>> +#define REG_PIO_SET_PMASK		0x64
>> +/* Clear bits of PMASK */
>> +#define REG_PIO_CLR_PMASK		0x68
>> +
>> +#define STIXXXX_MAX_GPIO_BANKS		32
>> +
>> +#define STIXXXX_GPIO_DIRECTION_BIDIR	0x1
>> +#define STIXXXX_GPIO_DIRECTION_OUT	0x2
>> +#define STIXXXX_GPIO_DIRECTION_IN	0x4
>> +
>> +#define STIXXXX_GPIO_PINS_PER_PORT	8
>> +#define stixxxx_gpio_port(gpio) ((gpio) / STIXXXX_GPIO_PINS_PER_PORT)
>> +#define stixxxx_gpio_pin(gpio) ((gpio) % STIXXXX_GPIO_PINS_PER_PORT)
>> +
>> +/* pinconf */
>> +/*
>> + * Pinconf is represented in an opaque unsigned long variable.
>> + * Below is the bit allocation details for each possible configuration.
>> + * All the bit fields can be encapsulated into four variables
>> + * (direction, retime-type, retime-clk, retime-delay)
>> + *
>> + *	 +----------------+
>> + *[31:28]| reserved-3     |
>> + *	 +----------------+-------------
>> + *[27]   |	oe	  |		|
>> + *	 +----------------+		v
>> + *[26]   |	pu	  |	[Direction	]
>> + *	 +----------------+		^
>> + *[25]   |	od	  |		|
>> + *	 +----------------+-------------
>> + *[24]   | reserved-2     |
>> + *	 +----------------+-------------
>> + *[23]   |    retime      |		|
>> + *	 +----------------+		|
>> + *[22]   | retime-invclk  |		|
>> + *	 +----------------+		v
>> + *[21]   |retime-clknotdat|	[Retime-type	]
>> + *	 +----------------+		^
>> + *[20]   | retime-de      |		|
>> + *	 +----------------+-------------
>> + *[19:18]| retime-clk     |------>[Retime-Clk	]
>> + *	 +----------------+
>> + *[17:16]|  reserved-1    |
>> + *	 +----------------+
>> + *[15..0]| retime-delay   |------>[Retime Delay]
>> + *	 +----------------+
>> + */
>> +
>> +#define STIXXXX_PINCONF_UNPACK(conf, param)\
>> +				((conf >> STIXXXX_PINCONF_ ##param ##_SHIFT) \
>> +				& STIXXXX_PINCONF_ ##param ##_MASK)
>> +
>> +#define STIXXXX_PINCONF_PACK(conf, val, param)	(conf |=\
>> +				((val & STIXXXX_PINCONF_ ##param ##_MASK) << \
>> +					STIXXXX_PINCONF_ ##param ##_SHIFT))
>> +
>> +/* Output enable */
>> +#define STIXXXX_PINCONF_OE_MASK		0x1
>> +#define STIXXXX_PINCONF_OE_SHIFT	27
>> +#define STIXXXX_PINCONF_OE		BIT(27)
>> +#define STIXXXX_PINCONF_UNPACK_OE(conf)	STIXXXX_PINCONF_UNPACK(conf, OE)
>> +#define STIXXXX_PINCONF_PACK_OE(conf, val)  STIXXXX_PINCONF_PACK(conf, val, OE)
>> +
>> +/* Pull Up */
>> +#define STIXXXX_PINCONF_PU_MASK		0x1
>> +#define STIXXXX_PINCONF_PU_SHIFT	26
>> +#define STIXXXX_PINCONF_PU		BIT(26)
>> +#define STIXXXX_PINCONF_UNPACK_PU(conf)	STIXXXX_PINCONF_UNPACK(conf, PU)
>> +#define STIXXXX_PINCONF_PACK_PU(conf, val) STIXXXX_PINCONF_PACK(conf, val, PU)
>> +
>> +/* Open Drain */
>> +#define STIXXXX_PINCONF_OD_MASK		0x1
>> +#define STIXXXX_PINCONF_OD_SHIFT	25
>> +#define STIXXXX_PINCONF_OD		BIT(25)
>> +#define STIXXXX_PINCONF_UNPACK_OD(conf)	STIXXXX_PINCONF_UNPACK(conf, OD)
>> +#define STIXXXX_PINCONF_PACK_OD(conf, val) STIXXXX_PINCONF_PACK(conf, val, OD)
>> +
>> +#define STIXXXX_PINCONF_RT_MASK		0x1
>> +#define STIXXXX_PINCONF_RT_SHIFT	23
>> +#define STIXXXX_PINCONF_RT		BIT(23)
>> +#define STIXXXX_PINCONF_UNPACK_RT(conf)	STIXXXX_PINCONF_UNPACK(conf, RT)
>> +#define STIXXXX_PINCONF_PACK_RT(conf, val) STIXXXX_PINCONF_PACK(conf, val, RT)
>> +
>> +#define STIXXXX_PINCONF_RT_INVERTCLK_MASK	0x1
>> +#define STIXXXX_PINCONF_RT_INVERTCLK_SHIFT	22
>> +#define STIXXXX_PINCONF_RT_INVERTCLK		BIT(22)
>> +#define STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(conf) \
>> +			STIXXXX_PINCONF_UNPACK(conf, RT_INVERTCLK)
>> +#define STIXXXX_PINCONF_PACK_RT_INVERTCLK(conf, val) \
>> +			STIXXXX_PINCONF_PACK(conf, val, RT_INVERTCLK)
>> +
>> +#define STIXXXX_PINCONF_RT_CLKNOTDATA_MASK	0x1
>> +#define STIXXXX_PINCONF_RT_CLKNOTDATA_SHIFT	21
>> +#define STIXXXX_PINCONF_RT_CLKNOTDATA		BIT(21)
>> +#define STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(conf)	\
>> +				STIXXXX_PINCONF_UNPACK(conf, RT_CLKNOTDATA)
>> +#define STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(conf, val) \
>> +				STIXXXX_PINCONF_PACK(conf, val, RT_CLKNOTDATA)
>> +
>> +#define STIXXXX_PINCONF_RT_DOUBLE_EDGE_MASK	0x1
>> +#define STIXXXX_PINCONF_RT_DOUBLE_EDGE_SHIFT	20
>> +#define STIXXXX_PINCONF_RT_DOUBLE_EDGE		BIT(20)
>> +#define STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(conf) \
>> +				STIXXXX_PINCONF_UNPACK(conf, RT_DOUBLE_EDGE)
>> +#define STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(conf, val) \
>> +				STIXXXX_PINCONF_PACK(conf, val, RT_DOUBLE_EDGE)
>> +
>> +#define STIXXXX_PINCONF_RT_CLK_MASK		0x3
>> +#define STIXXXX_PINCONF_RT_CLK_SHIFT		18
>> +#define STIXXXX_PINCONF_RT_CLK			BIT(18)
>> +#define STIXXXX_PINCONF_UNPACK_RT_CLK(conf)	\
>> +			STIXXXX_PINCONF_UNPACK(conf, RT_CLK)
>> +#define STIXXXX_PINCONF_PACK_RT_CLK(conf, val) \
>> +			STIXXXX_PINCONF_PACK(conf, val, RT_CLK)
>> +
>> +/* RETIME_DELAY in Pico Secs */
>> +#define STIXXXX_PINCONF_RT_DELAY_MASK		0xffff
>> +#define STIXXXX_PINCONF_RT_DELAY_SHIFT		0
>> +#define STIXXXX_PINCONF_UNPACK_RT_DELAY(conf) \
>> +				STIXXXX_PINCONF_UNPACK(conf, RT_DELAY)
>> +#define STIXXXX_PINCONF_PACK_RT_DELAY(conf, val) \
>> +				STIXXXX_PINCONF_PACK(conf, val, RT_DELAY)
>> +
>> +#endif /* __LINUX_DRIVERS_PINCTRL_STIXXXX_H */
>> -- 
>> 1.7.6.5
>>
>> _______________________________________________
>> devicetree-discuss mailing list
>> devicetree-discuss@lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/devicetree-discuss


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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 16:15             ` Greg KH
@ 2013-05-08 16:31               ` Arnd Bergmann
  2013-05-08 16:36                 ` Greg KH
                                   ` (2 more replies)
  0 siblings, 3 replies; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 16:31 UTC (permalink / raw)
  To: Greg KH
  Cc: Jean-Christophe PLAGNIOL-VILLARD, Srinivas KANDAGATLA,
	Viresh Kumar, Will Deacon, jslaby, Russell King, Samuel Ortiz,
	Nicolas Pitre, linux-doc, Stephen Gallimore, linux-serial,
	Jason Cooper, devicetree-discuss, Rob Herring, Stuart Menefy,
	Stephen Warren, Dong Aisheng, linux-arm-kernel, Mark Brown,
	linux-kernel

On Wednesday 08 May 2013, Greg KH wrote:
> > just mention there is not hardware reason to not use the generic ttySx
> > in place of ttyAS as we have only one IP that handle serial on this
> > family of SoC
> > 
> > personally I'll switch to ttySx
> 
> Great, then you can use the same major/minor range as well, so there's
> no more objection from me about this :)

Does that work these days when you have kernel with multiple built-in
uart drivers?

I think it would be good if all uarts were using the same name space
and major/minor numbers, but I think the mess we currently have is
the result of the tty_register_driver() interface reserving the
device number range at driver load time, independent of the presence
of devices.  I would assume that normal distro kernels always ship
with an 8250 driver built-in to allow using that as the console,
and if I read the code correctly, that currently prevents another
uart driver from registering the same major/minor numbers.

	Arnd

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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 16:31               ` Arnd Bergmann
@ 2013-05-08 16:36                 ` Greg KH
  2013-05-10 23:29                   ` Russell King - ARM Linux
  2013-05-08 16:39                 ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 16:45                 ` Nicolas Pitre
  2 siblings, 1 reply; 64+ messages in thread
From: Greg KH @ 2013-05-08 16:36 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jean-Christophe PLAGNIOL-VILLARD, Srinivas KANDAGATLA,
	Viresh Kumar, Will Deacon, jslaby, Russell King, Samuel Ortiz,
	Nicolas Pitre, linux-doc, Stephen Gallimore, linux-serial,
	Jason Cooper, devicetree-discuss, Rob Herring, Stuart Menefy,
	Stephen Warren, Dong Aisheng, linux-arm-kernel, Mark Brown,
	linux-kernel

On Wed, May 08, 2013 at 06:31:48PM +0200, Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Greg KH wrote:
> > > just mention there is not hardware reason to not use the generic ttySx
> > > in place of ttyAS as we have only one IP that handle serial on this
> > > family of SoC
> > > 
> > > personally I'll switch to ttySx
> > 
> > Great, then you can use the same major/minor range as well, so there's
> > no more objection from me about this :)
> 
> Does that work these days when you have kernel with multiple built-in
> uart drivers?

It "should", as the major/minor registration should only happen when the
hardware is found, but I haven't tested it out, so I can't say for sure.

> I think it would be good if all uarts were using the same name space
> and major/minor numbers, but I think the mess we currently have is
> the result of the tty_register_driver() interface reserving the
> device number range at driver load time, independent of the presence
> of devices.  I would assume that normal distro kernels always ship
> with an 8250 driver built-in to allow using that as the console,
> and if I read the code correctly, that currently prevents another
> uart driver from registering the same major/minor numbers.

We can always fix this if needed :)

thanks,

greg k-h

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

* Re: [RFC 4/8] pinctrl:stixxxx: Add pinctrl and pinconf support.
  2013-05-08 16:27     ` Srinivas KANDAGATLA
@ 2013-05-08 16:38       ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 64+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-08 16:38 UTC (permalink / raw)
  To: srinivas.kandagatla
  Cc: Jean-Christophe PLAGNIOL-VILLARD, linus.walleij, Viresh Kumar,
	Will Deacon, Jiri Slaby, Russell King, Samuel Ortiz,
	Nicolas Pitre, linux-doc, Stephen Gallimore, linux-serial,
	Jason Cooper, devicetree-discuss, Rob Herring, Stuart Menefy,
	Stephen Warren, Dong Aisheng, linux-arm-kernel,
	Greg Kroah-Hartman, Mark Brown, linux-kernel


On May 9, 2013, at 12:27 AM, Srinivas KANDAGATLA <srinivas.kandagatla@st.com> wrote:

> Thankyou for the comments.
> On 08/05/13 16:06, Jean-Christophe PLAGNIOL-VILLARD wrote:
>> On 15:11 Wed 08 May     , Srinivas KANDAGATLA wrote:
>>> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>>> 
>>> This patch add pinctrl support to ST SoCs.
>>> 
>>> About hardware:
>>> ST Set-Top-Box parts have two blocks called PIO and PIO-mux which handle
>>> pin configurations.
>>> 
>>> Each multi-function pin is controlled, driven and routed through the PIO
>>> multiplexing block. Each pin supports GPIO functionality (ALT0) and
>>> multiple alternate functions(ALT1 - ALTx) that directly connect the pin
>>> to different hardware blocks. When a pin is in GPIO mode, Output Enable
>>> (OE), Open Drain(OD), and Pull Up (PU) are driven by the related PIO
>>> block. Otherwise the PIO multiplexing block configures these parameters
>>> and retiming the signal.
>>> 
>> g> About driver:
>>> This pinctrl driver manages both PIO and PIO-mux block using pinctrl,
>>> pinconf, pinmux, gpio subsystems. All the pinctrl related config
>>> information can only come from device trees.
>>> 
>>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>>> CC: Stephen Gallimore <stephen.gallimore@st.com>
>>> CC: Stuart Menefy <stuart.menefy@st.com>
>>> ---
>>> .../bindings/pinctrl/pinctrl-stixxxx.txt           |  160 +++
>>> drivers/pinctrl/Kconfig                            |   13 +
>>> drivers/pinctrl/Makefile                           |    1 +
>>> drivers/pinctrl/pinctrl-stixxxx.c                  | 1151 ++++++++++++++++++++
>>> drivers/pinctrl/pinctrl-stixxxx.h                  |  197 ++++
>> the pinctrl is present in older SoC ST40 not only stixxx
>> 
>> and you must provide a proper name not stixxxx
> The reason for giving it stixxxx name is all the set-top-box based SOCs
> have the naming convention of stixxxx like stih7108, stih415, stih416
> and stig125.. and so on..
I known perfectly the ST SoCs for years (st20/st200 & co)

no you need to use the name of the first SoC using the IP

cf ePAR
> 
>>> 5 files changed, 1522 insertions(+), 0 deletions(-)
>>> create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
>>> create mode 100644 drivers/pinctrl/pinctrl-stixxxx.c
>>> create mode 100644 drivers/pinctrl/pinctrl-stixxxx.h
>>> 
>>> diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
>>> new file mode 100644
>>> index 0000000..b0a93b5
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
>>> @@ -0,0 +1,160 @@
>>> +*ST pin controller.
>>> +
>>> +Each multi-function pin is controlled, driven and routed through the
>>> +PIO multiplexing block. Each pin supports GPIO functionality (ALT0)
>>> +and multiple alternate functions(ALT1 - ALTx) that directly connect
>>> +the pin to different hardware blocks.
>>> +
>>> +When a pin is in GPIO mode, Output Enable (OE), Open Drain(OD), and
>>> +Pull Up (PU) are driven by the related PIO block.
>> HighZ too
>> 
>> this driver look very similar with AT91 we should consolidate at binding and C
>> level
> Yes, it look very similar to at91, however they are very much different
> w.r.t pinconf.

that's why I said we need to consolidate

>>> ---
>>> +
>>> +ST pinctrl driver controls PIO multiplexing block and also interacts with
>>> +gpio driver to configure a pin.
>>> +
>>> +Required properties: (PIO multiplexing block)
>>> +- compatible	: should be "st,stixxxx-pinctrl"
>>> +			each subnode should set "st,stixxxx-gpio"
>>> +			as compatible for each gpio-controller bank.
>> first soc where the IP is present
>>> +- gpio-controller : Indicates this device is a GPIO controller
>>> +- #gpio-cells	  : Should be one. The first cell is the pin number.
>>> +- #retime-delay-cells	: Should be number of possible retime delays.
>>> +- st,retime-in-delay	: Should be array of delays in nsecs.
>>> +- st,retime-out-delay	: Should be array of delays in nsecs.
>>> +- retime-style		: Should indicate which type of retime is used.
>>> +			possible values are "none", "packed" and "dedicated".
>> always prefix st, when specific property
>> st,
> Its a typo, will fix it.
>>> +- st,retime-offset	: phandle to retime offsets in retime registers.
>>> +		These are not necessary for "dedicated" retime-style registers.
>>> +	- clk1notclk0	: Should define offset for clk1not clk0 in retime register.
>>> +	- delay-lsb	: Should define offset for delay-lsb in retime register.
>>> +	- delay-msb	: Should define offset for delay msb in retime register.
>>> +	- invertclk	: Should define offset for invertclk in retime register.
>>> +	- retime	: Should define offset for retime in retime register.
>>> +	- clknotdata	: Should define offset for clknotdata in retime register.
>>> +	- double_edge	: Should define offset for double edge in retime register.
>> As much as I like to describe the IP in the DT, I think it's too much this
>> time move this to C and use the compatible or detect it on the hardware to
>> handle this 
> That is a good idea.

cf at91 pinctrl
>> 
>>> +- st,alt-control		: Should be sysconf to control alternate function on pio.
>>> +- st,oe-control		: Should be sysconf to control output enable on pio.
>>> +- st,pu-control		: Should be sysconf to control pull up on pio.
>>> +- st,od-control		: Should be sysconf to control open drain on pio.
>>> +- st,retime-style		: Should indicate which type of retime is used.
>>> +			possible values are "none", "packed" and "dedicated".
>>> +- st,retime-pin-mask	: Should be mask to specify which pins can be retimed.
>>> +- retime-control[0...N]: These properties point to sysconfs which control retime.
>>> +			Depending on retime-style the number of retime-controls
>>> +			vary: 2 for "packed"; 8 for "dedicated".
>> 
>>> +- st,bank-name		: Should be a name string for this bank.
>>> +
>>> +Example:
>>> +	pio_retime_offset: pio-retime-offset {
>>> +		clk1notclk0	= <0>;
>>> +		delay-lsb	= <2>;
>>> +		delay-msb	= <3>;
>>> +		invertclk	= <4>;
>>> +		retime		= <5>;
>>> +		clknotdata	= <6>;
>>> +		double-edge	= <7>;
>>> +	};
>>> +
>>> +	pin-controller {
>>> +		#retime-delay-cells = <4>;
>>> +		compatible = "st,stixxxx-pinctrl", "simple-bus";
>>> +		st,retime-offset = <&pio_retime_offset>;
>>> +		st,retime-in-delay = <0 500 1000 1500>;
>>> +		st,retime-out-delay = <0 1000 2000 3000>;
>>> +		ranges;
>>> +		PIO0: pinctrl@fe610000 {
>>> +			gpio-controller;
>>> +			#gpio-cells = <1>;
>>> +			compatible = "st,stixxxx-gpio";
>>> +			reg = <0xfe610000 0x100>;
>>> +			st,bank-name  = "PIO0";
>>> +			st,alt-control = <&SYSCONF_SBC(0) 0 31>;
>>> +			st,oe-control = <&SYSCONF_SBC(5)  0 7>;
>>> +			st,pu-control = <&SYSCONF_SBC(7)  0 7>;
>>> +			st,od-control = <&SYSCONF_SBC(9)  0 7>;
>>> +			st,retime-style = "packed";
>>> +			st,retime-pin-mask = <0xff>;
>>> +			st,retime-control0 = <&SYSCONF_SBC(16) 0 31>;
>>> +			st,retime-control1 = <&SYSCONF_SBC(17) 0 31>;
>>> +		};
>>> +		...
>>> +		pin-functions nodes follow...
>>> +	};
>>> +
>>> +
>>> +Contents of function subnode node:
>>> +----------------------
>>> +Required properties for pin configuration node:
>>> +- st,function	: Should be alternate function number associated
>>> +		with this set of pins.
>>> +		possible altfunction values:
>>> +		ALT1
>>> +		ALT2
>>> +		ALT3
>>> +		ALT4
>>> +		ALT5
>>> +		ALT6
>>> +		ALT7
>> use number in the DoC
> Ok.
>> 
>>> +
>>> +- st,pins	: Child node with list of pins with configuration.
>>> +
>>> +Below is the format of how each pin conf should look like.
>>> +
>>> +<bank offset mode rt_type rt_delay rt_clk>
>>> +
>>> +Every PIO is represented with 4-7 parameters depending on retime configuration.
>>> +Each parameter is explained as below.
>>> +
>>> +-bank		: Should be bank phandle to which this PIO belongs.
>>> +-offset		: Offset in the PIO bank.
>>> +-mode		:pin configuration is selected from one of the below values.
>>> +		IN
>>> +		IN_PU
>>> +		OUT
>>> +		BIDIR
>>> +		BIDIR_PU
>> ditto
> Actually these modes are top level defines of three different variables,
> OE, PU, OD used in the registers.
> Its very common that driver might just be interested in one of listed modes.

we need to represent the value in the doc as the Macro was just introduce recently for the Kernel only
It's not DT spec
>>> +
>>> +-rt_type	Retiming Configuration for the pin.
>>> +		Possible retime configuration are:
>>> +
>>> +		-------		-------------
>>> +		value		args
>>> +		-------		-------------
>>> +		NICLK		<delay> <clk>
>>> +		ICLK_IO		<delay> <clk>
>>> +		BYPASS		<delay>
>>> +		DE_IO		<delay> <clk>
>>> +		SE_ICLK_IO	<delay> <clk>
>>> +		SE_NICLK_IO	<delay> <clk>
>>> +
>>> +- delay	is retime delay in pico seconds.
>>> +		Possible values are: refer to retime-in/out-delays
>>> +
>>> +- rt_clk	:clk to be use for retime.
>>> +		Possible values are:
>>> +		CLK_A
>>> +		CLK_B
>>> +		CLK_C
>>> +		CLK_D
>>> +
>>> +Example of mmcclk pin which is a bi-direction pull pu with retime config
>>> +as non inverted clock retimed with CLK_B and delay of 0 pico seconds:
>>> +
>>> +pin-controller {
>>> +	...
>>> +	mmc0 {
>>> +		pinctrl_mmc: mmc {
>>> +			st,function = <ALT4>;
>>> +			st,pins {
>>> +				mmcclk = <&PIO13 4 BIDIR_PU NICLK  0  CLK_B>;
>>> +				...
>>> +			};
>>> +		};
>>> +	...
>>> +	};
>>> +};
>>> +
>>> +sdhci0:sdhci@fe810000{
>>> +	...
>>> +	pinctrl-names = "default";
>>> +	pinctrl-0	= <&pinctrl_mmc>;
>>> +};
>>> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
>>> index 34f51d2..611a399 100644
>>> --- a/drivers/pinctrl/Kconfig
>>> +++ b/drivers/pinctrl/Kconfig
>>> @@ -179,6 +179,19 @@ config PINCTRL_SUNXI
>>> 	select PINMUX
>>> 	select GENERIC_PINCONF
>>> 
>>> +config PINCTRL_STIXXXX
>>> +	bool "ST Microelectronics pin controller driver for STixxxx SoCs"
>>> +	depends on PLAT_STIXXXX
>>> +	select PINMUX
>>> +	select PINCONF
>>> +	select MFD_SYSCON
>>> +	help
>>> +	  Say yes here to support pinctrl interface on STixxxx SOCs.
>>> +	  This driver is used to control both PIO block and PIO-mux
>>> +	  block to configure a pin.
>>> +
>>> +	  If unsure, say N.
>>> +
>>> config PINCTRL_TEGRA
>>> 	bool
>>> 	select PINMUX
>>> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
>>> index f82cc5b..99a2c78 100644
>>> --- a/drivers/pinctrl/Makefile
>>> +++ b/drivers/pinctrl/Makefile
>>> @@ -47,6 +47,7 @@ obj-$(CONFIG_PINCTRL_EXYNOS)	+= pinctrl-exynos.o
>>> obj-$(CONFIG_PINCTRL_EXYNOS5440)	+= pinctrl-exynos5440.o
>>> obj-$(CONFIG_PINCTRL_XWAY)	+= pinctrl-xway.o
>>> obj-$(CONFIG_PINCTRL_LANTIQ)	+= pinctrl-lantiq.o
>>> +obj-$(CONFIG_PINCTRL_STIXXXX) 	+= pinctrl-stixxxx.o
>>> 
>>> obj-$(CONFIG_PLAT_ORION)        += mvebu/
>>> obj-$(CONFIG_ARCH_SHMOBILE)	+= sh-pfc/
>>> diff --git a/drivers/pinctrl/pinctrl-stixxxx.c b/drivers/pinctrl/pinctrl-stixxxx.c
>>> new file mode 100644
>>> index 0000000..7d2c59c
>>> --- /dev/null
>>> +++ b/drivers/pinctrl/pinctrl-stixxxx.c
>>> @@ -0,0 +1,1151 @@
>>> +/*
>>> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
>>> + * Authors:
>>> + *	Srinivas Kandagatla <srinivas.kandagatla@st.com>
>>> + *
>>> + * 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.
>>> + */
>>> +
>>> +#include <linux/init.h>
>>> +#include <linux/module.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/err.h>
>>> +#include <linux/io.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_gpio.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/mfd/syscon.h>
>>> +#include <linux/pinctrl/pinctrl.h>
>>> +#include <linux/pinctrl/pinmux.h>
>>> +#include <linux/pinctrl/pinconf.h>
>>> +#include <linux/platform_device.h>
>>> +#include "core.h"
>>> +#include "pinctrl-stixxxx.h"
>>> +
>>> +struct stixxxx_pinconf {
>>> +	int		pin;
>>> +	const char	*name;
>>> +	unsigned long	config;
>>> +};
>>> +
>>> +struct stixxxx_pmx_func {
>>> +	const char	*name;
>>> +	const char	**groups;
>>> +	unsigned	ngroups;
>>> +};
>>> +
>>> +struct stixxxx_pctl_group {
>>> +	const char		*name;
>>> +	unsigned int		*pins;
>>> +	unsigned		npins;
>>> +	int			altfunc;
>>> +	struct stixxxx_pinconf	*pin_conf;
>>> +};
>>> +
>>> +#define to_stixxxx_gpio_port(chip) \
>>> +		container_of(chip, struct stixxxx_gpio_port, gpio_chip)
>>> +
>>> +struct stixxxx_gpio_port {
>>> +	struct gpio_chip	gpio_chip;
>>> +	struct pinctrl_gpio_range range;
>>> +	void __iomem		*base;
>>> +	struct device_node	*of_node;
>>> +	const char		*bank_name;
>>> +};
>>> +
>>> +static struct stixxxx_gpio_port *gpio_ports[STIXXXX_MAX_GPIO_BANKS];
>>> +
>>> +struct stixxxx_pinctrl {
>>> +	struct device			*dev;
>>> +	struct pinctrl_dev		*pctl;
>>> +	int				nbanks;
>>> +	struct stixxxx_pmx_func		*functions;
>>> +	int				nfunctions;
>>> +	struct stixxxx_pctl_group	*groups;
>>> +	int				ngroups;
>>> +	struct stixxxx_pio_control	*pio_controls;
>>> +};
>>> +
>>> +/* Low level functions.. */
>>> +static void stixxxx_pinconf_set_direction(struct stixxxx_pio_control *pc,
>>> +				int pin_id, unsigned long config)
>>> +{
>>> +	struct syscon_field *output_enable;
>>> +	struct syscon_field *pull_up;
>>> +	struct syscon_field *open_drain;
>>> +	unsigned long oe_value, pu_value, od_value;
>>> +	unsigned long mask;
>>> +	int pin = stixxxx_gpio_pin(pin_id);
>>> +
>>> +	output_enable = pc->oe;
>>> +	pull_up = pc->pu;
>>> +	open_drain = pc->od;
>>> +
>>> +	mask = BIT(pin);
>>> +
>>> +	oe_value = syscon_read(output_enable);
>>> +	pu_value = syscon_read(pull_up);
>>> +	od_value = syscon_read(open_drain);
>>> +
>>> +	/* Clear old values */
>>> +	oe_value &= ~mask;
>>> +	pu_value &= ~mask;
>>> +	od_value &= ~mask;
>>> +
>>> +	if (config & STIXXXX_PINCONF_OE)
>>> +		oe_value |= mask;
>>> +	if (config & STIXXXX_PINCONF_PU)
>>> +		pu_value |= mask;
>>> +	if (config & STIXXXX_PINCONF_OD)
>>> +		od_value |= mask;
>>> +
>>> +	syscon_write(output_enable, oe_value);
>>> +	syscon_write(pull_up, pu_value);
>>> +	syscon_write(open_drain, od_value);
>>> +}
>>> +
>>> +static void stixxxx_pctl_set_function(struct stixxxx_pio_control *pc,
>>> +				int pin_id, int function)
>>> +{
>>> +	struct syscon_field *selector;
>>> +	int offset;
>>> +	unsigned long val;
>>> +	int pin = stixxxx_gpio_pin(pin_id);
>>> +
>>> +	selector = pc->alt;
>>> +	offset = pin * 4;
>>> +	val = syscon_read(selector);
>>> +	val &= ~(0xf << offset);
>>> +	val |= function << offset;
>>> +	syscon_write(selector, val);
>>> +}
>>> +
>>> +static unsigned long stixxxx_pinconf_delay_to_bit(unsigned int delay,
>>> +		const struct stixxxx_retime_params *rt_params,
>>> +		unsigned long config)
>>> +{
>>> +	unsigned int *delay_times;
>>> +	int num_delay_times, i, closest_index = -1;
>>> +	unsigned int closest_divergence = UINT_MAX;
>>> +
>>> +	if (STIXXXX_PINCONF_UNPACK_OE(config)) {
>>> +		delay_times = rt_params->delay_times_out;
>>> +		num_delay_times = rt_params->num_delay_times_out;
>>> +	} else {
>>> +		delay_times = rt_params->delay_times_in;
>>> +		num_delay_times = rt_params->num_delay_times_in;
>>> +	}
>>> +
>>> +	for (i = 0; i < num_delay_times; i++) {
>>> +		unsigned int divergence = abs(delay - delay_times[i]);
>>> +
>>> +		if (divergence == 0)
>>> +			return i;
>>> +
>>> +		if (divergence < closest_divergence) {
>>> +			closest_divergence = divergence;
>>> +			closest_index = i;
>>> +		}
>>> +	}
>>> +
>>> +	pr_warn("Attempt to set delay %d, closest available %d\n",
>>> +	     delay, delay_times[closest_index]);
>>> +
>>> +	return closest_index;
>>> +}
>>> +
>>> +static unsigned long stixxxx_pinconf_bit_to_delay(unsigned int index,
>>> +		const struct stixxxx_retime_params *rt_params,
>>> +		unsigned long output)
>>> +{
>>> +	unsigned int *delay_times;
>>> +	int num_delay_times;
>>> +
>>> +	if (output) {
>>> +		delay_times = rt_params->delay_times_out;
>>> +		num_delay_times = rt_params->num_delay_times_out;
>>> +	} else {
>>> +		delay_times = rt_params->delay_times_in;
>>> +		num_delay_times = rt_params->num_delay_times_in;
>>> +	}
>>> +
>>> +	if (index < num_delay_times) {
>>> +		return delay_times[index];
>>> +	} else {
>>> +		pr_warn("Delay not found in/out delay list\n");
>>> +		return 0;
>>> +	}
>>> +}
>>> +
>>> +static void stixxxx_pinconf_set_retime_packed(
>>> +		struct stixxxx_pio_control *pc,
>>> +		unsigned long config, int pin)
>>> +{
>>> +	const struct stixxxx_retime_params *rt_params = pc->rt_params;
>>> +	const struct stixxxx_retime_offset *offset = rt_params->retime_offset;
>>> +	struct syscon_field **regs;
>>> +	unsigned long values[2];
>>> +	unsigned long mask;
>>> +	int i, j;
>>> +	int clk = STIXXXX_PINCONF_UNPACK_RT_CLK(config);
>>> +	int clknotdata = STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config);
>>> +	int double_edge = STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
>>> +	int invertclk = STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config);
>>> +	int retime = STIXXXX_PINCONF_UNPACK_RT(config);
>>> +	unsigned long delay = stixxxx_pinconf_delay_to_bit(
>>> +			STIXXXX_PINCONF_UNPACK_RT_DELAY(config),
>>> +			pc->rt_params, config);
>>> +
>>> +	unsigned long rt_cfg =
>>> +		((clk		& 1) << offset->clk1notclk0_offset) |
>>> +		((clknotdata	& 1) << offset->clknotdata_offset) |
>>> +		((delay		& 1) << offset->delay_lsb_offset) |
>>> +		(((delay >> 1)  & 1) << offset->delay_msb_offset) |
>>> +		((double_edge	& 1) << offset->double_edge_offset) |
>>> +		((invertclk	& 1) << offset->invertclk_offset) |
>>> +		((retime	& 1) << offset->retime_offset);
>>> +
>>> +	regs = pc->retiming;
>>> +	values[0] = syscon_read(regs[0]);
>>> +	values[1] = syscon_read(regs[1]);
>>> +
>>> +	for (i = 0; i < 2; i++) {
>>> +		mask = BIT(pin);
>>> +		for (j = 0; j < 4; j++) {
>>> +			if (rt_cfg & 1)
>>> +				values[i] |= mask;
>>> +			else
>>> +				values[i] &= ~mask;
>>> +			mask <<= 8;
>>> +			rt_cfg >>= 1;
>>> +		}
>>> +	}
>>> +
>>> +	syscon_write(regs[0], values[0]);
>>> +	syscon_write(regs[1], values[1]);
>>> +}
>>> +
>>> +static void stixxxx_pinconf_set_retime_dedicated(
>>> +	struct stixxxx_pio_control *pc,
>>> +	unsigned long config, int pin)
>>> +{
>>> +	struct syscon_field *reg;
>>> +	int input = STIXXXX_PINCONF_UNPACK_OE(config) ? 0 : 1;
>>> +	int clk = STIXXXX_PINCONF_UNPACK_RT_CLK(config);
>>> +	int clknotdata = STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config);
>>> +	int double_edge = STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
>>> +	int invertclk = STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config);
>>> +	int retime = STIXXXX_PINCONF_UNPACK_RT(config);
>>> +	unsigned long delay = stixxxx_pinconf_delay_to_bit(
>>> +			STIXXXX_PINCONF_UNPACK_RT_DELAY(config),
>>> +			pc->rt_params, config);
>>> +
>>> +	unsigned long retime_config =
>>> +		((clk		& 0x3) << 0) |
>>> +		((clknotdata	& 0x1) << 2) |
>>> +		((delay		& 0xf) << 3) |
>>> +		((input		& 0x1) << 7) |
>>> +		((double_edge	& 0x1) << 8) |
>>> +		((invertclk	& 0x1) << 9) |
>>> +		((retime	& 0x1) << 10);
>>> +
>>> +	reg = pc->retiming[pin];
>>> +	syscon_write(reg, retime_config);
>>> +}
>>> +
>>> +static void stixxxx_pinconf_get_direction(struct stixxxx_pio_control *pc,
>>> +	int pin_id, unsigned long *config)
>>> +{
>>> +	unsigned long oe_value, pu_value, od_value;
>>> +	int pin = stixxxx_gpio_pin(pin_id);
>>> +
>>> +	oe_value = (syscon_read(pc->oe) >> pin) & 1;
>>> +	pu_value = (syscon_read(pc->pu) >> pin) & 1;
>>> +	od_value = (syscon_read(pc->od) >> pin) & 1;
>>> +
>>> +	STIXXXX_PINCONF_PACK_OE(*config, oe_value);
>>> +	STIXXXX_PINCONF_PACK_PU(*config, pu_value);
>>> +	STIXXXX_PINCONF_PACK_OD(*config, od_value);
>>> +}
>>> +
>>> +static int stixxxx_pinconf_get_retime_packed(
>>> +		struct stixxxx_pio_control *pc,
>>> +		int pin, unsigned long *config)
>>> +{
>>> +	const struct stixxxx_retime_params *rt_params = pc->rt_params;
>>> +	const struct stixxxx_retime_offset *offset = rt_params->retime_offset;
>>> +	unsigned long delay_bits, delay, rt_reduced;
>>> +	unsigned long rt_value[2];
>>> +	int i, j;
>>> +	int output = STIXXXX_PINCONF_UNPACK_OE(*config);
>>> +
>>> +	rt_value[0] = syscon_read(pc->retiming[0]);
>>> +	rt_value[1] = syscon_read(pc->retiming[1]);
>>> +
>>> +	rt_reduced = 0;
>>> +	for (i = 0; i < 2; i++) {
>>> +		for (j = 0; j < 4; j++) {
>>> +			if (rt_value[i] & (1<<((8*j)+pin)))
>>> +				rt_reduced |= 1 << ((i*4)+j);
>>> +		}
>>> +	}
>>> +
>>> +	STIXXXX_PINCONF_PACK_RT(*config,
>>> +			(rt_reduced >> offset->retime_offset) & 1);
>>> +	STIXXXX_PINCONF_PACK_RT_CLK(*config,
>>> +			(rt_reduced >> offset->clk1notclk0_offset) & 1);
>>> +	STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(*config,
>>> +			(rt_reduced >> offset->clknotdata_offset) & 1);
>>> +	STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(*config,
>>> +			(rt_reduced >> offset->double_edge_offset) & 1);
>>> +	STIXXXX_PINCONF_PACK_RT_INVERTCLK(*config,
>>> +			(rt_reduced >> offset->invertclk_offset) & 1);
>>> +
>>> +	delay_bits =  (((rt_reduced >> offset->delay_msb_offset) & 1)<<1) |
>>> +			((rt_reduced >> offset->delay_lsb_offset) & 1);
>>> +	delay =  stixxxx_pinconf_bit_to_delay(delay_bits, rt_params, output);
>>> +	STIXXXX_PINCONF_PACK_RT_DELAY(*config, delay);
>>> +	return 0;
>>> +}
>>> +
>>> +static int stixxxx_pinconf_get_retime_dedicated(
>>> +		struct stixxxx_pio_control *pc,
>>> +		int pin, unsigned long *config)
>>> +{
>>> +	unsigned long value;
>>> +	unsigned long delay_bits, delay;
>>> +	const struct stixxxx_retime_params *rt_params = pc->rt_params;
>>> +	int output = STIXXXX_PINCONF_UNPACK_OE(*config);
>>> +
>>> +	value = syscon_read(pc->retiming[pin]);
>>> +	STIXXXX_PINCONF_PACK_RT_CLK(*config, ((value >> 0) & 0x3));
>>> +	STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(*config, ((value >> 2) & 0x1));
>>> +	delay_bits = ((value >> 3) & 0xf);
>>> +	delay =  stixxxx_pinconf_bit_to_delay(delay_bits, rt_params, output);
>>> +	STIXXXX_PINCONF_PACK_RT_DELAY(*config, delay);
>>> +	STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(*config, ((value >> 8) & 0x1));
>>> +	STIXXXX_PINCONF_PACK_RT_INVERTCLK(*config, ((value >> 9) & 0x1));
>>> +	STIXXXX_PINCONF_PACK_RT(*config, ((value >> 10) & 0x1));
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +/* GPIO related functions */
>>> +
>>> +static inline void __stixxxx_gpio_set(struct stixxxx_gpio_port *port,
>>> +	unsigned offset, int value)
>>> +{
>>> +	if (value)
>>> +		writel(BIT(offset), port->base + REG_PIO_SET_POUT);
>>> +	else
>>> +		writel(BIT(offset), port->base + REG_PIO_CLR_POUT);
>>> +}
>>> +
>>> +static void stixxxx_gpio_direction(unsigned int gpio, unsigned int direction)
>>> +{
>>> +	int port_num = stixxxx_gpio_port(gpio);
>>> +	int offset = stixxxx_gpio_pin(gpio);
>>> +	struct stixxxx_gpio_port *port  = gpio_ports[port_num];
>>> +	int i = 0;
>>> +
>>> +	for (i = 0; i <= 2; i++) {
>>> +		if (direction & BIT(i))
>>> +			writel(BIT(offset), port->base + REG_PIO_SET_PC(i));
>>> +		else
>>> +			writel(BIT(offset), port->base + REG_PIO_CLR_PC(i));
>>> +	}
>>> +}
>>> +
>>> +static int stixxxx_gpio_request(struct gpio_chip *chip, unsigned offset)
>>> +{
>>> +	return pinctrl_request_gpio(chip->base + offset);
>>> +}
>>> +
>>> +static void stixxxx_gpio_free(struct gpio_chip *chip, unsigned offset)
>>> +{
>>> +	pinctrl_free_gpio(chip->base + offset);
>>> +}
>>> +
>>> +static int stixxxx_gpio_get(struct gpio_chip *chip, unsigned offset)
>>> +{
>>> +	struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
>>> +
>>> +	return (readl(port->base + REG_PIO_PIN) >> offset) & 1;
>>> +}
>>> +
>>> +static void stixxxx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
>>> +{
>>> +	struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
>>> +	__stixxxx_gpio_set(port, offset, value);
>>> +}
>>> +
>>> +static int stixxxx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
>>> +{
>>> +	pinctrl_gpio_direction_input(chip->base + offset);
>>> +	return 0;
>>> +}
>>> +
>>> +static int stixxxx_gpio_direction_output(struct gpio_chip *chip,
>>> +	unsigned offset, int value)
>>> +{
>>> +	struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
>>> +
>>> +	__stixxxx_gpio_set(port, offset, value);
>>> +	pinctrl_gpio_direction_output(chip->base + offset);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int stixxxx_gpio_xlate(struct gpio_chip *gc,
>>> +			const struct of_phandle_args *gpiospec, u32 *flags)
>>> +{
>>> +	if (WARN_ON(gc->of_gpio_n_cells < 1))
>>> +		return -EINVAL;
>>> +
>>> +	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
>>> +		return -EINVAL;
>>> +
>>> +	if (gpiospec->args[0] > gc->ngpio)
>>> +		return -EINVAL;
>>> +
>>> +	return gpiospec->args[0];
>>> +}
>>> +
>>> +/* Pinctrl Groups */
>>> +static int stixxxx_pctl_get_groups_count(struct pinctrl_dev *pctldev)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +
>>> +	return info->ngroups;
>>> +}
>>> +
>>> +static const char *stixxxx_pctl_get_group_name(struct pinctrl_dev *pctldev,
>>> +				       unsigned selector)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +
>>> +	return info->groups[selector].name;
>>> +}
>>> +
>>> +static int stixxxx_pctl_get_group_pins(struct pinctrl_dev *pctldev,
>>> +	unsigned selector, const unsigned **pins, unsigned *npins)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +
>>> +	if (selector >= info->ngroups)
>>> +		return -EINVAL;
>>> +
>>> +	*pins = info->groups[selector].pins;
>>> +	*npins = info->groups[selector].npins;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static const inline struct stixxxx_pctl_group *stixxxx_pctl_find_group_by_name(
>>> +	const struct stixxxx_pinctrl *info, const char *name)
>>> +{
>>> +	int i;
>>> +
>>> +	for (i = 0; i < info->ngroups; i++) {
>>> +		if (!strcmp(info->groups[i].name, name))
>>> +			return &info->groups[i];
>>> +	}
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +static int stixxxx_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
>>> +	struct device_node *np, struct pinctrl_map **map, unsigned *num_maps)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +	const struct stixxxx_pctl_group *grp;
>>> +	struct pinctrl_map *new_map;
>>> +	struct device_node *parent;
>>> +	int map_num, i;
>>> +
>>> +	grp = stixxxx_pctl_find_group_by_name(info, np->name);
>>> +	if (!grp) {
>>> +		dev_err(info->dev, "unable to find group for node %s\n",
>>> +			np->name);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	map_num = grp->npins + 1;
>>> +	new_map = devm_kzalloc(pctldev->dev,
>>> +				sizeof(*new_map) * map_num, GFP_KERNEL);
>>> +	if (!new_map)
>>> +		return -ENOMEM;
>>> +
>>> +	parent = of_get_parent(np);
>>> +	if (!parent) {
>>> +		devm_kfree(pctldev->dev, new_map);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	*map = new_map;
>>> +	*num_maps = map_num;
>>> +	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
>>> +	new_map[0].data.mux.function = parent->name;
>>> +	new_map[0].data.mux.group = np->name;
>>> +	of_node_put(parent);
>>> +
>>> +	/* create config map per pin */
>>> +	new_map++;
>>> +	for (i = 0; i < grp->npins; i++) {
>>> +		new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
>>> +		new_map[i].data.configs.group_or_pin =
>>> +				pin_get_name(pctldev, grp->pins[i]);
>>> +		new_map[i].data.configs.configs = &grp->pin_conf[i].config;
>>> +		new_map[i].data.configs.num_configs = 1;
>>> +	}
>>> +	dev_info(pctldev->dev, "maps: function %s group %s num %d\n",
>>> +		(*map)->data.mux.function, grp->name, map_num);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void stixxxx_pctl_dt_free_map(struct pinctrl_dev *pctldev,
>>> +				struct pinctrl_map *map, unsigned num_maps)
>>> +{
>>> +}
>>> +
>>> +static struct pinctrl_ops stixxxx_pctlops = {
>>> +	.get_groups_count	= stixxxx_pctl_get_groups_count,
>>> +	.get_group_pins		= stixxxx_pctl_get_group_pins,
>>> +	.get_group_name		= stixxxx_pctl_get_group_name,
>>> +	.dt_node_to_map		= stixxxx_pctl_dt_node_to_map,
>>> +	.dt_free_map		= stixxxx_pctl_dt_free_map,
>>> +};
>>> +
>>> +/* Pinmux */
>>> +static int stixxxx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +
>>> +	return info->nfunctions;
>>> +}
>>> +
>>> +const char *stixxxx_pmx_get_fname(struct pinctrl_dev *pctldev,
>>> +	unsigned selector)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +
>>> +	return info->functions[selector].name;
>>> +}
>>> +
>>> +static int stixxxx_pmx_get_groups(struct pinctrl_dev *pctldev,
>>> +	unsigned selector, const char * const **grps, unsigned * const ngrps)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +	*grps = info->functions[selector].groups;
>>> +	*ngrps = info->functions[selector].ngroups;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static struct stixxxx_pio_control *stixxxx_get_pio_control(
>>> +			struct stixxxx_pinctrl *info, int pin_id)
>>> +{
>>> +	int port = stixxxx_gpio_port(pin_id);
>>> +	return &info->pio_controls[port];
>>> +}
>>> +
>>> +static int stixxxx_pmx_enable(struct pinctrl_dev *pctldev, unsigned fselector,
>>> +		unsigned group)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +	struct stixxxx_pinconf *conf = info->groups[group].pin_conf;
>>> +	struct stixxxx_pio_control *pc;
>>> +	int i;
>>> +
>>> +	for (i = 0; i < info->groups[group].npins; i++) {
>>> +		pc = stixxxx_get_pio_control(info, conf[i].pin);
>>> +		stixxxx_pctl_set_function(pc, conf[i].pin,
>>> +					info->groups[group].altfunc);
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void stixxxx_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
>>> +		unsigned group)
>>> +{
>>> +}
>>> +
>>> +static int stixxxx_pmx_set_gpio_direction(struct pinctrl_dev *pctldev,
>>> +			struct pinctrl_gpio_range *range, unsigned gpio,
>>> +			bool input)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +	struct stixxxx_pio_control *pc = &info->pio_controls[range->id];
>>> +	/*
>>> +	 * When a PIO port is used in its primary function mode (altfunc = 0)
>>> +	 * Output Enable (OE), Open Drain(OD), and Pull Up (PU)
>>> +	 * for the primary PIO functions are driven by the related PIO block
>>> +	 */
>>> +	stixxxx_pctl_set_function(pc, gpio, 0);
>>> +	stixxxx_gpio_direction(gpio, input ?
>>> +		STIXXXX_GPIO_DIRECTION_IN : STIXXXX_GPIO_DIRECTION_OUT);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static struct pinmux_ops stixxxx_pmxops = {
>>> +	.get_functions_count	= stixxxx_pmx_get_funcs_count,
>>> +	.get_function_name	= stixxxx_pmx_get_fname,
>>> +	.get_function_groups	= stixxxx_pmx_get_groups,
>>> +	.enable			= stixxxx_pmx_enable,
>>> +	.disable		= stixxxx_pmx_disable,
>>> +	.gpio_set_direction	= stixxxx_pmx_set_gpio_direction,
>>> +};
>>> +
>>> +/* Pinconf  */
>>> +static void stixxxx_pinconf_get_retime(struct stixxxx_pio_control *pc,
>>> +	int pin_id, unsigned long *config)
>>> +{
>>> +	int pin = stixxxx_gpio_pin(pin_id);
>>> +	if (pc->rt_style == stixxxx_retime_style_packed)
>>> +		stixxxx_pinconf_get_retime_packed(pc, pin, config);
>>> +	else if (pc->rt_style == stixxxx_retime_style_dedicated)
>>> +		if ((BIT(pin) & pc->rt_pin_mask))
>>> +			stixxxx_pinconf_get_retime_dedicated(pc, pin, config);
>>> +}
>>> +
>>> +static void stixxxx_pinconf_set_retime(struct stixxxx_pio_control *pc,
>>> +	int pin_id, unsigned long config)
>>> +{
>>> +	int pin = stixxxx_gpio_pin(pin_id);
>>> +
>>> +	if (pc->rt_style == stixxxx_retime_style_packed)
>>> +		stixxxx_pinconf_set_retime_packed(pc, config, pin);
>>> +	else if (pc->rt_style == stixxxx_retime_style_dedicated)
>>> +		if ((BIT(pin) & pc->rt_pin_mask))
>>> +			stixxxx_pinconf_set_retime_dedicated(pc, config, pin);
>>> +}
>>> +
>>> +static int stixxxx_pinconf_set(struct pinctrl_dev *pctldev,
>>> +			     unsigned pin_id, unsigned long config)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +	struct stixxxx_pio_control *pc = stixxxx_get_pio_control(info, pin_id);
>>> +
>>> +	stixxxx_pinconf_set_direction(pc, pin_id, config);
>>> +	stixxxx_pinconf_set_retime(pc, pin_id, config);
>>> +	return 0;
>>> +}
>>> +
>>> +static int stixxxx_pinconf_get(struct pinctrl_dev *pctldev,
>>> +			     unsigned pin_id, unsigned long *config)
>>> +{
>>> +	struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
>>> +	struct stixxxx_pio_control *pc = stixxxx_get_pio_control(info, pin_id);
>>> +
>>> +	*config = 0;
>>> +	stixxxx_pinconf_get_direction(pc, pin_id, config);
>>> +	stixxxx_pinconf_get_retime(pc, pin_id, config);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void stixxxx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
>>> +				   struct seq_file *s, unsigned pin_id)
>>> +{
>>> +	unsigned long config;
>>> +	stixxxx_pinconf_get(pctldev, pin_id, &config);
>>> +
>>> +	seq_printf(s, "[OE:%ld,PU:%ld,OD:%ld]\n"
>>> +		"\t\t[retime:%ld,invclk:%ld,clknotdat:%ld,"
>>> +		"de:%ld,rt-clk:%ld,rt-delay:%ld]",
>>> +		STIXXXX_PINCONF_UNPACK_OE(config),
>>> +		STIXXXX_PINCONF_UNPACK_PU(config),
>>> +		STIXXXX_PINCONF_UNPACK_OD(config),
>>> +		STIXXXX_PINCONF_UNPACK_RT(config),
>>> +		STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config),
>>> +		STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config),
>>> +		STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config),
>>> +		STIXXXX_PINCONF_UNPACK_RT_CLK(config),
>>> +		STIXXXX_PINCONF_UNPACK_RT_DELAY(config));
>>> +}
>>> +
>>> +static struct pinconf_ops stixxxx_confops = {
>>> +	.pin_config_get		= stixxxx_pinconf_get,
>>> +	.pin_config_set		= stixxxx_pinconf_set,
>>> +	.pin_config_dbg_show	= stixxxx_pinconf_dbg_show,
>>> +};
>>> +
>>> +/* pinctrl */
>>> +static struct pinctrl_desc stixxxx_pctl_desc = {
>>> +	.owner		= THIS_MODULE,
>>> +	.pctlops	= &stixxxx_pctlops,
>>> +	.pmxops		= &stixxxx_pmxops,
>>> +	.confops	= &stixxxx_confops,
>>> +};
>>> +
>>> +static int stixxxx_pinconf_dt_parse_rt_params(struct stixxxx_pinctrl *info,
>>> +	struct device_node *np,	struct stixxxx_retime_params *params)
>>> +{
>>> +	const __be32 *ip;
>>> +	struct device_node *offset_np;
>>> +	struct stixxxx_retime_offset *rt_offset;
>>> +	int delay_count = 0;
>>> +
>>> +	ip = of_get_property(np, "#retime-delay-cells", NULL);
>>> +	if (ip)
>>> +		delay_count = be32_to_cpup(ip);
>>> +	else
>>> +		pr_warn("No #retime-delay-cells specified\n");
>>> +
>>> +	params->num_delay_times_out = delay_count;
>>> +	params->num_delay_times_in = delay_count;
>>> +	params->delay_times_in = devm_kzalloc(info->dev,
>>> +				sizeof(u32) * delay_count, GFP_KERNEL);
>>> +	params->delay_times_out = devm_kzalloc(info->dev,
>>> +				sizeof(u32) * delay_count, GFP_KERNEL);
>>> +
>>> +	if (!params->delay_times_in || !params->delay_times_out)
>>> +		return -ENOMEM;
>>> +
>>> +	of_property_read_u32_array(np, "st,retime-in-delay",
>>> +				(u32 *)params->delay_times_in, delay_count);
>>> +	of_property_read_u32_array(np, "st,retime-out-delay",
>>> +				(u32 *)params->delay_times_out, delay_count);
>>> +
>>> +	offset_np = of_parse_phandle(np, "st,retime-offset", 0);
>>> +
>>> +	if (offset_np) {
>>> +		rt_offset = devm_kzalloc(info->dev,
>>> +				sizeof(*rt_offset), GFP_KERNEL);
>>> +		if (!rt_offset)
>>> +			return -ENOMEM;
>>> +
>>> +		params->retime_offset = rt_offset;
>>> +		WARN_ON(of_property_read_u32(offset_np, "retime",
>>> +					&rt_offset->retime_offset));
>>> +		WARN_ON(of_property_read_u32(offset_np, "clk1notclk0",
>>> +					&rt_offset->clk1notclk0_offset));
>>> +		WARN_ON(of_property_read_u32(offset_np, "clknotdata",
>>> +					&rt_offset->clknotdata_offset));
>>> +		WARN_ON(of_property_read_u32(offset_np, "double-edge",
>>> +					&rt_offset->double_edge_offset));
>>> +		WARN_ON(of_property_read_u32(offset_np, "invertclk",
>>> +					&rt_offset->invertclk_offset));
>>> +		WARN_ON(of_property_read_u32(offset_np, "delay-lsb",
>>> +					&rt_offset->delay_lsb_offset));
>>> +		WARN_ON(of_property_read_u32(offset_np, "delay-msb",
>>> +					&rt_offset->delay_msb_offset));
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static const char *gpio_compat = "st,stixxxx-gpio";
>>> +
>>> +static void stixxxx_pctl_dt_child_count(struct stixxxx_pinctrl *info,
>>> +				     struct device_node *np)
>>> +{
>>> +	struct device_node *child;
>>> +	for_each_child_of_node(np, child) {
>>> +		if (of_device_is_compatible(child, gpio_compat)) {
>>> +			info->nbanks++;
>>> +		} else {
>>> +			info->nfunctions++;
>>> +			info->ngroups += of_get_child_count(child);
>>> +		}
>>> +	}
>>> +}
>>> +
>>> +static int stixxxx_pctl_dt_get_retime_conf(struct device_node *np,
>>> +	struct stixxxx_pio_control *pc)
>>> +{
>>> +	const char *style;
>>> +	char name[20];
>>> +	unsigned int j;
>>> +	of_property_read_string(np, "st,retime-style", &style);
>>> +
>>> +	if (strcmp(style, "packed") == 0) {
>>> +		pc->rt_style = stixxxx_retime_style_packed;
>>> +		for (j = 0; j < 2; j++) {
>>> +			snprintf(name, sizeof(name), "st,retime-control%d", j);
>>> +			pc->retiming[j] = syscon_claim(np, name);
>>> +			if (!pc->retiming[j])
>>> +				return -ENODATA;
>>> +		}
>>> +	} else if (strcmp(style, "dedicated") == 0) {
>>> +		pc->rt_style = stixxxx_retime_style_dedicated;
>>> +		for (j = 0; j < 8; j++) {
>>> +			if ((1<<j) & pc->rt_pin_mask) {
>>> +				snprintf(name, sizeof(name),
>>> +						"st,retime-control%d", j);
>>> +				pc->retiming[j] = syscon_claim(np, name);
>>> +				if (!pc->retiming[j])
>>> +					return -ENODATA;
>>> +			}
>>> +		}
>>> +	} else if (strcmp(style, "none") == 0) {
>>> +		pc->rt_style = stixxxx_retime_style_none;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int stixxxx_pctl_dt_init(struct stixxxx_pinctrl *info,
>>> +			struct device_node *np)
>>> +{
>>> +	struct stixxxx_pio_control *pc;
>>> +	struct stixxxx_retime_params *rt_params;
>>> +	struct device *dev = info->dev;
>>> +	unsigned int i = 0;
>>> +	struct device_node *child = NULL;
>>> +
>>> +	pc = devm_kzalloc(dev, sizeof(*pc) * info->nbanks, GFP_KERNEL);
>>> +	rt_params = devm_kzalloc(dev, sizeof(*rt_params), GFP_KERNEL);
>>> +
>>> +	if (!pc || !rt_params)
>>> +		return -ENOMEM;
>>> +
>>> +	info->pio_controls = pc;
>>> +	if (stixxxx_pinconf_dt_parse_rt_params(info, np, rt_params))
>>> +		return -ENOMEM;
>>> +
>>> +	for_each_child_of_node(np, child) {
>>> +		if (of_device_is_compatible(child, gpio_compat)) {
>>> +			pc[i].rt_params = rt_params;
>>> +
>>> +			pc[i].alt = syscon_claim(child, "st,alt-control");
>>> +			if (!pc[i].alt)
>>> +				goto failed;
>>> +
>>> +			pc[i].oe = syscon_claim(child, "st,oe-control");
>>> +			if (!pc[i].oe)
>>> +				goto failed;
>>> +
>>> +			pc[i].pu = syscon_claim(child, "st,pu-control");
>>> +			if (!pc[i].pu)
>>> +				goto failed;
>>> +
>>> +			pc[i].od = syscon_claim(child, "st,od-control");
>>> +			if (!pc[i].od)
>>> +				goto failed;
>>> +
>>> +			of_property_read_u32(child, "st,retime-pin-mask",
>>> +							&pc[i].rt_pin_mask);
>>> +
>>> +			stixxxx_pctl_dt_get_retime_conf(child, &pc[i]);
>>> +			i++;
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +failed:
>>> +	return -ENODATA;
>>> +}
>>> +
>>> +#define OF_GPIO_ARGS_MIN	(3)
>>> +/*
>>> + * Each pin is represented in of the below forms.
>>> + * <bank offset direction func rt_type rt_delay rt_clk>
>>> + */
>>> +static int stixxxx_pctl_dt_parse_groups(struct device_node *np,
>>> +	struct stixxxx_pctl_group *grp, struct stixxxx_pinctrl *info, int idx)
>>> +{
>>> +	/* bank pad direction val altfunction */
>>> +	const __be32 *list;
>>> +	struct property *pp;
>>> +	struct stixxxx_pinconf *conf;
>>> +	phandle phandle;
>>> +	struct device_node *pins;
>>> +	u32 pin;
>>> +	int i = 0, npins = 0, nr_props;
>>> +
>>> +	pins = of_get_child_by_name(np, "st,pins");
>>> +	if (!pins)
>>> +		return -ENODATA;
>>> +
>>> +	for_each_property_of_node(pins, pp) {
>>> +		/* Skip those we do not want to proceed */
>>> +		if (!strcmp(pp->name, "name"))
>>> +			continue;
>>> +
>>> +		if (pp  && (pp->length/sizeof(__be32)) >= OF_GPIO_ARGS_MIN) {
>>> +			npins++;
>>> +		} else {
>>> +			pr_warn("Invalid st,pins in %s node\n", np->name);
>>> +			return -EINVAL;
>>> +		}
>>> +	}
>>> +
>>> +	grp->npins = npins;
>>> +	grp->name = np->name;
>>> +	grp->pins = devm_kzalloc(info->dev, npins * sizeof(u32), GFP_KERNEL);
>>> +	grp->pin_conf = devm_kzalloc(info->dev,
>>> +					npins * sizeof(*conf), GFP_KERNEL);
>>> +	of_property_read_u32(np, "st,function", &grp->altfunc);
>>> +
>>> +	if (!grp->pins || !grp->pin_conf)
>>> +		return -ENOMEM;
>>> +
>>> +	/* <bank offset direction func rt_type rt_delay rt_clk> */
>>> +	for_each_property_of_node(pins, pp) {
>>> +		if (!strcmp(pp->name, "name"))
>>> +			continue;
>>> +		nr_props = pp->length/sizeof(u32);
>>> +		list = pp->value;
>>> +		conf = &grp->pin_conf[i];
>>> +
>>> +		/* bank & offset */
>>> +		phandle = be32_to_cpup(list++);
>>> +		pin = be32_to_cpup(list++);
>>> +		conf->pin = of_get_named_gpio(pins, pp->name, 0);
>>> +		conf->name = pp->name;
>>> +		grp->pins[i] = conf->pin;
>>> +
>>> +		conf->config = 0;
>>> +		/* direction */
>>> +		conf->config |= be32_to_cpup(list++);
>>> +		/* rt_type rt_delay rt_clk */
>>> +		if (nr_props >= OF_GPIO_ARGS_MIN + 2) {
>>> +			/* rt_type */
>>> +			conf->config |= be32_to_cpup(list++);
>>> +			/* rt_delay */
>>> +			conf->config |= be32_to_cpup(list++);
>>> +			/* rt_clk */
>>> +			if (nr_props > OF_GPIO_ARGS_MIN + 2)
>>> +				conf->config |= be32_to_cpup(list++);
>>> +		}
>>> +		i++;
>>> +	}
>>> +	of_node_put(pins);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int stixxxx_pctl_parse_functions(struct device_node *np,
>>> +			struct stixxxx_pinctrl *info, u32 index, int *grp_index)
>>> +{
>>> +	struct device_node *child;
>>> +	struct stixxxx_pmx_func *func;
>>> +	struct stixxxx_pctl_group *grp;
>>> +	int ret, i;
>>> +
>>> +	func = &info->functions[index];
>>> +	func->name = np->name;
>>> +	func->ngroups = of_get_child_count(np);
>>> +	if (func->ngroups <= 0) {
>>> +		dev_err(info->dev, "No groups defined\n");
>>> +		return -EINVAL;
>>> +	}
>>> +	func->groups = devm_kzalloc(info->dev,
>>> +			func->ngroups * sizeof(char *), GFP_KERNEL);
>>> +	if (!func->groups)
>>> +		return -ENOMEM;
>>> +
>>> +	i = 0;
>>> +	for_each_child_of_node(np, child) {
>>> +		func->groups[i] = child->name;
>>> +		grp = &info->groups[*grp_index];
>>> +		*grp_index += 1;
>>> +		ret = stixxxx_pctl_dt_parse_groups(child, grp, info, i++);
>>> +		if (ret)
>>> +			return ret;
>>> +	}
>>> +	dev_info(info->dev, "Function[%d\t name:%s,\tgroups:%d]\n",
>>> +				index, func->name, func->ngroups);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int stixxxx_pctl_probe_dt(struct platform_device *pdev,
>>> +				 struct stixxxx_pinctrl *info)
>>> +{
>>> +	int ret = 0;
>>> +	int i = 0, j = 0, k = 0;
>>> +	struct pinctrl_pin_desc *pdesc;
>>> +	struct device_node *np = pdev->dev.of_node;
>>> +	struct device_node *child;
>>> +	int grp_index = 0;
>>> +
>>> +	stixxxx_pctl_dt_child_count(info, np);
>>> +	if (info->nbanks < 1) {
>>> +		dev_err(&pdev->dev, "you need atleast one gpio bank\n");
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	ret = stixxxx_pctl_dt_init(info, np);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	dev_info(&pdev->dev, "nbanks = %d\n", info->nbanks);
>>> +	dev_info(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
>>> +	dev_info(&pdev->dev, "ngroups = %d\n", info->ngroups);
>>> +	info->functions = devm_kzalloc(&pdev->dev,
>>> +		info->nfunctions * sizeof(*info->functions), GFP_KERNEL);
>>> +
>>> +	info->groups = devm_kzalloc(&pdev->dev,
>>> +		info->ngroups * sizeof(*info->groups) ,	GFP_KERNEL);
>>> +
>>> +	if (!info->functions || !info->groups)
>>> +		return -ENOMEM;
>>> +
>>> +	stixxxx_pctl_desc.npins = info->nbanks * STIXXXX_GPIO_PINS_PER_PORT;
>>> +	pdesc =	devm_kzalloc(&pdev->dev,
>>> +			sizeof(*pdesc) * stixxxx_pctl_desc.npins, GFP_KERNEL);
>>> +	if (!pdesc)
>>> +		return -ENOMEM;
>>> +
>>> +	stixxxx_pctl_desc.pins = pdesc;
>>> +
>>> +	for_each_child_of_node(np, child) {
>>> +		if (of_device_is_compatible(child, gpio_compat)) {
>>> +			for (j = 0; j < STIXXXX_GPIO_PINS_PER_PORT; j++, k++) {
>>> +				const char *port_name = NULL;
>>> +				pdesc->number = k;
>>> +				of_property_read_string(child, "st,bank-name",
>>> +							&port_name);
>>> +				pdesc->name = kasprintf(GFP_KERNEL, "%s[%d]",
>>> +							port_name ? : "PIO",
>>> +							port_name ? j : k);
>>> +				pdesc++;
>>> +			}
>>> +		} else {
>>> +			ret = stixxxx_pctl_parse_functions(child, info,
>>> +							i++, &grp_index);
>>> +			if (ret) {
>>> +				dev_err(&pdev->dev, "No functions found.\n");
>>> +				return ret;
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int stixxxx_pctl_probe(struct platform_device *pdev)
>>> +{
>>> +	struct stixxxx_pinctrl *info;
>>> +	int ret, i;
>>> +
>>> +	if (!pdev->dev.of_node) {
>>> +		dev_err(&pdev->dev, "device node not found.\n");
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
>>> +	if (!info)
>>> +		return -ENOMEM;
>>> +
>>> +	info->dev = &pdev->dev;
>>> +	platform_set_drvdata(pdev, info);
>>> +	ret = stixxxx_pctl_probe_dt(pdev, info);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	stixxxx_pctl_desc.name = dev_name(&pdev->dev);
>>> +	info->pctl = pinctrl_register(&stixxxx_pctl_desc, &pdev->dev, info);
>>> +	if (IS_ERR(info->pctl)) {
>>> +		dev_err(&pdev->dev, "Failed pinctrl registration\n");
>>> +		return PTR_ERR(info->pctl);
>>> +	}
>>> +
>>> +	for (i = 0; i < info->nbanks; i++)
>>> +		pinctrl_add_gpio_range(info->pctl, &gpio_ports[i]->range);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static struct gpio_chip stixxxx_gpio_template = {
>>> +	.request		= stixxxx_gpio_request,
>>> +	.free			= stixxxx_gpio_free,
>>> +	.get			= stixxxx_gpio_get,
>>> +	.set			= stixxxx_gpio_set,
>>> +	.direction_input	= stixxxx_gpio_direction_input,
>>> +	.direction_output	= stixxxx_gpio_direction_output,
>>> +	.ngpio			= STIXXXX_GPIO_PINS_PER_PORT,
>>> +	.of_gpio_n_cells	= 1,
>>> +	.of_xlate		= stixxxx_gpio_xlate,
>>> +};
>>> +
>>> +static int stixxxx_gpio_probe(struct platform_device *pdev)
>>> +{
>>> +	struct stixxxx_gpio_port *port;
>>> +	struct pinctrl_gpio_range *range;
>>> +	struct device_node *np  = pdev->dev.of_node;
>>> +	int port_num = of_alias_get_id(np, "gpio");
>>> +	struct resource *res;
>>> +	int err;
>>> +
>>> +	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
>>> +	if (!port)
>>> +		return -ENOMEM;
>>> +
>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +	port->base = devm_request_and_ioremap(&pdev->dev, res);
>>> +	if (!port->base) {
>>> +		dev_err(&pdev->dev, "Can't get IO memory mapping!\n");
>>> +		return -ENODEV;
>>> +	}
>>> +
>>> +	of_property_read_string(np, "st,bank-name", &port->bank_name);
>>> +	port->of_node = np;
>>> +
>>> +	port->gpio_chip = stixxxx_gpio_template;
>>> +	port->gpio_chip.base = port_num * STIXXXX_GPIO_PINS_PER_PORT;
>>> +	port->gpio_chip.ngpio = STIXXXX_GPIO_PINS_PER_PORT;
>>> +	port->gpio_chip.of_node = np;
>>> +	port->gpio_chip.label = dev_name(&pdev->dev);
>>> +
>>> +	dev_set_drvdata(&pdev->dev, port);
>>> +	range = &port->range;
>>> +	range->name = port->gpio_chip.label;
>>> +	range->id = port_num;
>>> +	range->pin_base = range->base = range->id * STIXXXX_GPIO_PINS_PER_PORT;
>>> +	range->npins = port->gpio_chip.ngpio;
>>> +	range->gc = &port->gpio_chip;
>>> +	gpio_ports[port_num] = port;
>>> +	err  = gpiochip_add(&port->gpio_chip);
>>> +	if (err) {
>>> +		dev_err(&pdev->dev, "Failed to add gpiochip(%d)!\n", port_num);
>>> +		return err;
>>> +	}
>>> +	dev_info(&pdev->dev, "gpioport[%s] Added as bank%d\n",
>>> +				port->bank_name, port_num);
>>> +	return 0;
>>> +}
>>> +
>>> +static struct of_device_id stixxxx_gpio_of_match[] = {
>>> +	{ .compatible = "st,stixxxx-gpio", },
>>> +	{ /* sentinel */ }
>>> +};
>>> +
>>> +static struct platform_driver stixxxx_gpio_driver = {
>>> +	.driver = {
>>> +		.name = "st-gpio",
>>> +		.owner = THIS_MODULE,
>>> +		.of_match_table = of_match_ptr(stixxxx_gpio_of_match),
>>> +	},
>>> +	.probe = stixxxx_gpio_probe,
>>> +};
>>> +
>>> +static struct of_device_id stixxxx_pctl_of_match[] = {
>>> +	{ .compatible = "st,stixxxx-pinctrl",},
>>> +	{ /* sentinel */ }
>>> +};
>>> +
>>> +static struct platform_driver stixxxx_pctl_driver = {
>>> +	.driver = {
>>> +		.name = "st-pinctrl",
>>> +		.owner = THIS_MODULE,
>>> +		.of_match_table = of_match_ptr(stixxxx_pctl_of_match),
>>> +	},
>>> +	.probe = stixxxx_pctl_probe,
>>> +};
>>> +
>>> +static int __init stixxxx_pctl_init(void)
>>> +{
>>> +	int ret = platform_driver_register(&stixxxx_gpio_driver);
>>> +	if (ret)
>>> +		return ret;
>>> +	return platform_driver_register(&stixxxx_pctl_driver);
>>> +}
>>> +arch_initcall(stixxxx_pctl_init);
>>> diff --git a/drivers/pinctrl/pinctrl-stixxxx.h b/drivers/pinctrl/pinctrl-stixxxx.h
>>> new file mode 100644
>>> index 0000000..a340964
>>> --- /dev/null
>>> +++ b/drivers/pinctrl/pinctrl-stixxxx.h
>>> @@ -0,0 +1,197 @@
>>> +
>>> +/*
>>> + * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
>>> + * Authors:
>>> + *	Srinivas Kandagatla <srinivas.kandagatla@st.com>
>>> + *
>>> + * 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.
>>> + *
>>> + */
>>> +
>>> +#ifndef __LINUX_DRIVERS_PINCTRL_STIXXXX_H
>>> +#define __LINUX_DRIVERS_PINCTRL_STIXXXX_H
>>> +
>>> +enum stixxxx_retime_style {
>>> +	stixxxx_retime_style_none,
>>> +	stixxxx_retime_style_packed,
>>> +	stixxxx_retime_style_dedicated,
>>> +};
>>> +
>>> +/* Byte positions in 2 syscon words, starts from 0 */
>>> +struct stixxxx_retime_offset {
>>> +	int retime_offset;
>>> +	int clk1notclk0_offset;
>>> +	int clknotdata_offset;
>>> +	int double_edge_offset;
>>> +	int invertclk_offset;
>>> +	int delay_lsb_offset;
>>> +	int delay_msb_offset;
>>> +};
>>> +
>>> +struct stixxxx_retime_params {
>>> +	const struct stixxxx_retime_offset *retime_offset;
>>> +	unsigned int *delay_times_in;
>>> +	int num_delay_times_in;
>>> +	unsigned int *delay_times_out;
>>> +	int num_delay_times_out;
>>> +};
>>> +
>>> +struct stixxxx_pio_control {
>>> +	enum stixxxx_retime_style rt_style;
>>> +	u32 rt_pin_mask;
>>> +	const struct stixxxx_retime_params *rt_params;
>>> +	struct syscon_field *alt;
>>> +	struct syscon_field *oe, *pu, *od;
>>> +	struct syscon_field *retiming[8];
>>> +};
>>> +
>>> +/* PIO Block registers */
>>> +/* PIO output */
>>> +#define REG_PIO_POUT			0x00
>>> +/* Set bits of POUT */
>>> +#define REG_PIO_SET_POUT		0x04
>>> +/* Clear bits of POUT */
>>> +#define REG_PIO_CLR_POUT		0x08
>>> +/* PIO input */
>>> +#define REG_PIO_PIN			0x10
>>> +/* PIO configuration */
>>> +#define REG_PIO_PC(n)			(0x20 + (n) * 0x10)
>>> +/* Set bits of PC[2:0] */
>>> +#define REG_PIO_SET_PC(n)		(0x24 + (n) * 0x10)
>>> +/* Clear bits of PC[2:0] */
>>> +#define REG_PIO_CLR_PC(n)		(0x28 + (n) * 0x10)
>>> +/* PIO input comparison */
>>> +#define REG_PIO_PCOMP			0x50
>>> +/* Set bits of PCOMP */
>>> +#define REG_PIO_SET_PCOMP		0x54
>>> +/* Clear bits of PCOMP */
>>> +#define REG_PIO_CLR_PCOMP		0x58
>>> +/* PIO input comparison mask */
>>> +#define REG_PIO_PMASK			0x60
>>> +/* Set bits of PMASK */
>>> +#define REG_PIO_SET_PMASK		0x64
>>> +/* Clear bits of PMASK */
>>> +#define REG_PIO_CLR_PMASK		0x68
>>> +
>>> +#define STIXXXX_MAX_GPIO_BANKS		32
>>> +
>>> +#define STIXXXX_GPIO_DIRECTION_BIDIR	0x1
>>> +#define STIXXXX_GPIO_DIRECTION_OUT	0x2
>>> +#define STIXXXX_GPIO_DIRECTION_IN	0x4
>>> +
>>> +#define STIXXXX_GPIO_PINS_PER_PORT	8
>>> +#define stixxxx_gpio_port(gpio) ((gpio) / STIXXXX_GPIO_PINS_PER_PORT)
>>> +#define stixxxx_gpio_pin(gpio) ((gpio) % STIXXXX_GPIO_PINS_PER_PORT)
>>> +
>>> +/* pinconf */
>>> +/*
>>> + * Pinconf is represented in an opaque unsigned long variable.
>>> + * Below is the bit allocation details for each possible configuration.
>>> + * All the bit fields can be encapsulated into four variables
>>> + * (direction, retime-type, retime-clk, retime-delay)
>>> + *
>>> + *	 +----------------+
>>> + *[31:28]| reserved-3     |
>>> + *	 +----------------+-------------
>>> + *[27]   |	oe	  |		|
>>> + *	 +----------------+		v
>>> + *[26]   |	pu	  |	[Direction	]
>>> + *	 +----------------+		^
>>> + *[25]   |	od	  |		|
>>> + *	 +----------------+-------------
>>> + *[24]   | reserved-2     |
>>> + *	 +----------------+-------------
>>> + *[23]   |    retime      |		|
>>> + *	 +----------------+		|
>>> + *[22]   | retime-invclk  |		|
>>> + *	 +----------------+		v
>>> + *[21]   |retime-clknotdat|	[Retime-type	]
>>> + *	 +----------------+		^
>>> + *[20]   | retime-de      |		|
>>> + *	 +----------------+-------------
>>> + *[19:18]| retime-clk     |------>[Retime-Clk	]
>>> + *	 +----------------+
>>> + *[17:16]|  reserved-1    |
>>> + *	 +----------------+
>>> + *[15..0]| retime-delay   |------>[Retime Delay]
>>> + *	 +----------------+
>>> + */
>>> +
>>> +#define STIXXXX_PINCONF_UNPACK(conf, param)\
>>> +				((conf >> STIXXXX_PINCONF_ ##param ##_SHIFT) \
>>> +				& STIXXXX_PINCONF_ ##param ##_MASK)
>>> +
>>> +#define STIXXXX_PINCONF_PACK(conf, val, param)	(conf |=\
>>> +				((val & STIXXXX_PINCONF_ ##param ##_MASK) << \
>>> +					STIXXXX_PINCONF_ ##param ##_SHIFT))
>>> +
>>> +/* Output enable */
>>> +#define STIXXXX_PINCONF_OE_MASK		0x1
>>> +#define STIXXXX_PINCONF_OE_SHIFT	27
>>> +#define STIXXXX_PINCONF_OE		BIT(27)
>>> +#define STIXXXX_PINCONF_UNPACK_OE(conf)	STIXXXX_PINCONF_UNPACK(conf, OE)
>>> +#define STIXXXX_PINCONF_PACK_OE(conf, val)  STIXXXX_PINCONF_PACK(conf, val, OE)
>>> +
>>> +/* Pull Up */
>>> +#define STIXXXX_PINCONF_PU_MASK		0x1
>>> +#define STIXXXX_PINCONF_PU_SHIFT	26
>>> +#define STIXXXX_PINCONF_PU		BIT(26)
>>> +#define STIXXXX_PINCONF_UNPACK_PU(conf)	STIXXXX_PINCONF_UNPACK(conf, PU)
>>> +#define STIXXXX_PINCONF_PACK_PU(conf, val) STIXXXX_PINCONF_PACK(conf, val, PU)
>>> +
>>> +/* Open Drain */
>>> +#define STIXXXX_PINCONF_OD_MASK		0x1
>>> +#define STIXXXX_PINCONF_OD_SHIFT	25
>>> +#define STIXXXX_PINCONF_OD		BIT(25)
>>> +#define STIXXXX_PINCONF_UNPACK_OD(conf)	STIXXXX_PINCONF_UNPACK(conf, OD)
>>> +#define STIXXXX_PINCONF_PACK_OD(conf, val) STIXXXX_PINCONF_PACK(conf, val, OD)
>>> +
>>> +#define STIXXXX_PINCONF_RT_MASK		0x1
>>> +#define STIXXXX_PINCONF_RT_SHIFT	23
>>> +#define STIXXXX_PINCONF_RT		BIT(23)
>>> +#define STIXXXX_PINCONF_UNPACK_RT(conf)	STIXXXX_PINCONF_UNPACK(conf, RT)
>>> +#define STIXXXX_PINCONF_PACK_RT(conf, val) STIXXXX_PINCONF_PACK(conf, val, RT)
>>> +
>>> +#define STIXXXX_PINCONF_RT_INVERTCLK_MASK	0x1
>>> +#define STIXXXX_PINCONF_RT_INVERTCLK_SHIFT	22
>>> +#define STIXXXX_PINCONF_RT_INVERTCLK		BIT(22)
>>> +#define STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(conf) \
>>> +			STIXXXX_PINCONF_UNPACK(conf, RT_INVERTCLK)
>>> +#define STIXXXX_PINCONF_PACK_RT_INVERTCLK(conf, val) \
>>> +			STIXXXX_PINCONF_PACK(conf, val, RT_INVERTCLK)
>>> +
>>> +#define STIXXXX_PINCONF_RT_CLKNOTDATA_MASK	0x1
>>> +#define STIXXXX_PINCONF_RT_CLKNOTDATA_SHIFT	21
>>> +#define STIXXXX_PINCONF_RT_CLKNOTDATA		BIT(21)
>>> +#define STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(conf)	\
>>> +				STIXXXX_PINCONF_UNPACK(conf, RT_CLKNOTDATA)
>>> +#define STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(conf, val) \
>>> +				STIXXXX_PINCONF_PACK(conf, val, RT_CLKNOTDATA)
>>> +
>>> +#define STIXXXX_PINCONF_RT_DOUBLE_EDGE_MASK	0x1
>>> +#define STIXXXX_PINCONF_RT_DOUBLE_EDGE_SHIFT	20
>>> +#define STIXXXX_PINCONF_RT_DOUBLE_EDGE		BIT(20)
>>> +#define STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(conf) \
>>> +				STIXXXX_PINCONF_UNPACK(conf, RT_DOUBLE_EDGE)
>>> +#define STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(conf, val) \
>>> +				STIXXXX_PINCONF_PACK(conf, val, RT_DOUBLE_EDGE)
>>> +
>>> +#define STIXXXX_PINCONF_RT_CLK_MASK		0x3
>>> +#define STIXXXX_PINCONF_RT_CLK_SHIFT		18
>>> +#define STIXXXX_PINCONF_RT_CLK			BIT(18)
>>> +#define STIXXXX_PINCONF_UNPACK_RT_CLK(conf)	\
>>> +			STIXXXX_PINCONF_UNPACK(conf, RT_CLK)
>>> +#define STIXXXX_PINCONF_PACK_RT_CLK(conf, val) \
>>> +			STIXXXX_PINCONF_PACK(conf, val, RT_CLK)
>>> +
>>> +/* RETIME_DELAY in Pico Secs */
>>> +#define STIXXXX_PINCONF_RT_DELAY_MASK		0xffff
>>> +#define STIXXXX_PINCONF_RT_DELAY_SHIFT		0
>>> +#define STIXXXX_PINCONF_UNPACK_RT_DELAY(conf) \
>>> +				STIXXXX_PINCONF_UNPACK(conf, RT_DELAY)
>>> +#define STIXXXX_PINCONF_PACK_RT_DELAY(conf, val) \
>>> +				STIXXXX_PINCONF_PACK(conf, val, RT_DELAY)
>>> +
>>> +#endif /* __LINUX_DRIVERS_PINCTRL_STIXXXX_H */
>>> -- 
>>> 1.7.6.5
>>> 
>>> _______________________________________________
>>> devicetree-discuss mailing list
>>> devicetree-discuss@lists.ozlabs.org
>>> https://lists.ozlabs.org/listinfo/devicetree-discuss
> 


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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 16:31               ` Arnd Bergmann
  2013-05-08 16:36                 ` Greg KH
@ 2013-05-08 16:39                 ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 16:45                 ` Nicolas Pitre
  2 siblings, 0 replies; 64+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-08 16:39 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jean-Christophe PLAGNIOL-VILLARD, Greg KH, Mark Brown,
	Russell King, Samuel Ortiz, Srinivas KANDAGATLA, Viresh Kumar,
	devicetree-discuss, Will Deacon, Stephen Gallimore, Rob Herring,
	linux-doc, Stuart Menefy, Nicolas Pitre, linux-serial,
	Stephen Warren, linux-kernel, Dong Aisheng, jslaby,
	linux-arm-kernel, Jason Cooper


On May 9, 2013, at 12:31 AM, Arnd Bergmann <arnd@arndb.de> wrote:

> On Wednesday 08 May 2013, Greg KH wrote:
>>> just mention there is not hardware reason to not use the generic ttySx
>>> in place of ttyAS as we have only one IP that handle serial on this
>>> family of SoC
>>> 
>>> personally I'll switch to ttySx
>> 
>> Great, then you can use the same major/minor range as well, so there's
>> no more objection from me about this :)
> 
> Does that work these days when you have kernel with multiple built-in
> uart drivers?

not for very long time and no this family
> 
> I think it would be good if all uarts were using the same name space
> and major/minor numbers, but I think the mess we currently have is
> the result of the tty_register_driver() interface reserving the
> device number range at driver load time, independent of the presence
> of devices.  I would assume that normal distro kernels always ship
> with an 8250 driver built-in to allow using that as the console,
> and if I read the code correctly, that currently prevents another
> uart driver from registering the same major/minor numbers.

so we need to fix this
> 
> 	Arnd
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 16:31               ` Arnd Bergmann
  2013-05-08 16:36                 ` Greg KH
  2013-05-08 16:39                 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 16:45                 ` Nicolas Pitre
  2013-05-08 18:35                   ` Arnd Bergmann
  2 siblings, 1 reply; 64+ messages in thread
From: Nicolas Pitre @ 2013-05-08 16:45 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Greg KH, Jean-Christophe PLAGNIOL-VILLARD, Srinivas KANDAGATLA,
	Viresh Kumar, Will Deacon, jslaby, Russell King, Samuel Ortiz,
	linux-doc, Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Mark Brown, linux-kernel

On Wed, 8 May 2013, Arnd Bergmann wrote:

> On Wednesday 08 May 2013, Greg KH wrote:
> > > just mention there is not hardware reason to not use the generic ttySx
> > > in place of ttyAS as we have only one IP that handle serial on this
> > > family of SoC
> > > 
> > > personally I'll switch to ttySx
> > 
> > Great, then you can use the same major/minor range as well, so there's
> > no more objection from me about this :)
> 
> Does that work these days when you have kernel with multiple built-in
> uart drivers?
> 
> I think it would be good if all uarts were using the same name space
> and major/minor numbers, but I think the mess we currently have is
> the result of the tty_register_driver() interface reserving the
> device number range at driver load time, independent of the presence
> of devices.  I would assume that normal distro kernels always ship
> with an 8250 driver built-in to allow using that as the console,
> and if I read the code correctly, that currently prevents another
> uart driver from registering the same major/minor numbers.

I tried to fix this up over 10 years ago.  RMK tried as well. This 
failed because X86 people insisted on always having COM1 as /dev/ttyS0, 
COM3 as /dev/ttyS2 and so on, even when some of them weren't present.

A common and dynamic namespace eventually succeeded for hard disks.
Maybe people are ready to accept it for serial ports as well now?


Nicolas

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

* RE: [RFC 5/8] ARM:stih41x: Add STiH415 SOC support
  2013-05-08 16:18   ` [RFC 5/8] ARM:stih41x: Add STiH415 SOC support Arnd Bergmann
  2013-05-08 16:21     ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 16:50     ` Stephen GALLIMORE
  2013-05-08 18:55       ` Arnd Bergmann
  2013-05-08 17:03     ` Srinivas KANDAGATLA
  2 siblings, 1 reply; 64+ messages in thread
From: Stephen GALLIMORE @ 2013-05-08 16:50 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Srinivas KANDAGATLA, Stuart MENEFY, linux-kernel, linux-arm-kernel

Hi Arnd,

Thank you for the feedback so far.

> +/*
> + * A basic implementation of irq_set_wake that ensures wakeup source
> + * interrupts are not disabled during PM_SUSPEND_FREEZE.
> + */
> +static int stih41x_set_wake(struct irq_data *d, unsigned int on) {
> +	struct irq_desc *desc = irq_to_desc(d->irq);
> +
> +	if (on) {
> +		if (desc->action)
> +			desc->action->flags |= IRQF_NO_SUSPEND;
> +	} else {
> +		if (desc->action)
> +			desc->action->flags &= ~IRQF_NO_SUSPEND;
> +	}
> +	return 0;
> +}
> +
> +static void __init stih41x_irq_init(void) {
> +	gic_arch_extn.irq_set_wake = stih41x_set_wake;
> +	gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
> +
> +	irqchip_init();
> +}
>
>This looks like it should be generic. Why do you need this?

On this point, I wrote it so I am happy to take some advice. Basically this was to allow us to wakeup from the new PM_SUSPEND_FREEZE state that was added at the beginning of the year, without having to pollute individual drivers (particularly the serial driver) with having to somehow change the IRQ flags, or uninstall/re-install the interrupt handler on suspend/resume when marked as a wakeup source with different flags. Those approaches all seemed too messy and not really the driver's responsibility and installing the interrupt handlers of all possible wakeup sources with IRQF_NO_SUSPEND regardless of if they are currently activated as a wakeup source or not also seemed wrong. The code I ended up with was inspired by the existing mach-mmp (mmp2) PM support which does the same thing, so it is not without precedent.

If you have a better solution, or a way to generalize this that would make sense for the ARM architecture as a whole, then we are more than happy to change.

Regards,
-stephen

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

* Re: [RFC 5/8] ARM:stih41x: Add STiH415 SOC support
  2013-05-08 16:18   ` [RFC 5/8] ARM:stih41x: Add STiH415 SOC support Arnd Bergmann
  2013-05-08 16:21     ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 16:50     ` Stephen GALLIMORE
@ 2013-05-08 17:03     ` Srinivas KANDAGATLA
  2 siblings, 0 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 17:03 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux, olof, Rob Landley, Grant Likely, Rob Herring,
	Samuel Ortiz, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Jason Cooper, Stephen Warren,
	Maxime Ripard, Nicolas Pitre, Will Deacon, Dave Martin,
	Marc Zyngier, Viresh Kumar, Mark Brown, Dong Aisheng, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial,
	Stephen Gallimore

Thankyou for the comments.
On 08/05/13 17:18, Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
>> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>>
>> The STiH415 is the next generation of HD, AVC set-top box processors for
>> satellite, cable, terrestrial and IP-STB markets. It is an ARM Cortex-A9
>> 1.0 GHz, dual-core CPU.
>>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>> CC: Stephen Gallimore <stephen.gallimore@st.com>
>> CC: Stuart Menefy <stuart.menefy@st.com>
>> ---
>>  Documentation/arm/STiH41x/overview.txt         |   39 ++
>>  Documentation/arm/STiH41x/stih415-overview.txt |   12 +
>>  arch/arm/Kconfig                               |    3 +
>>  arch/arm/Kconfig.debug                         |   38 ++
>>  arch/arm/Makefile                              |    2 +
>>  arch/arm/boot/dts/stih415-clock.dtsi           |   38 ++
>>  arch/arm/boot/dts/stih415-pinctrl.dtsi         |  480 ++++++++++++++++++++++++
>>  arch/arm/boot/dts/stih415.dtsi                 |   94 +++++
>>  arch/arm/boot/dts/stih415.h                    |   20 +
>>  arch/arm/boot/dts/stih41x.dtsi                 |   30 ++
>>  arch/arm/boot/dts/stixxxx-pincfg.h             |   95 +++++
>>  arch/arm/configs/stih41x_defconfig             |   94 +++++
>>  arch/arm/include/debug/stixxxx.S               |   61 +++
>>  arch/arm/mach-stih41x/Kconfig                  |   35 ++
>>  arch/arm/mach-stih41x/Makefile                 |    4 +
>>  arch/arm/mach-stih41x/board-dt.c               |   76 ++++
>>  arch/arm/mach-stih41x/stih41x.c                |   82 ++++
>>  arch/arm/mach-stih41x/stih41x.h                |    7 +
>>  arch/arm/plat-stixxxx/Kconfig                  |    2 +
>>  arch/arm/plat-stixxxx/Makefile                 |    2 +
>>  arch/arm/plat-stixxxx/headsmp.S                |   44 +++
>>  arch/arm/plat-stixxxx/include/plat/hardware.h  |   20 +
>>  arch/arm/plat-stixxxx/include/plat/smp.h       |   19 +
>>  arch/arm/plat-stixxxx/platsmp.c                |  144 +++++++
> I think there is no point in having a separate mach- and plat- directory
> here, given that modern machines require very little code. You can probably
> fold the three files in mach-stih41x (board-dt.c, stih41x.c and stih41x.h)
> into a single file and rename plat-stixxxx to mach-stixxxx
Yep, sounds good.
>
>> diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
>> index 9b31f43..42a5193 100644
>> --- a/arch/arm/Kconfig.debug
>> +++ b/arch/arm/Kconfig.debug
>> @@ -447,6 +447,16 @@ choice
>>  		  This option selects UART0 on VIA/Wondermedia System-on-a-chip
>>  		  devices, including VT8500, WM8505, WM8650 and WM8850.
>>  
>> +	config DEBUG_STIH41X_UART
>> +		depends on ARCH_STIH41X
>> +		bool "Use StiH415/416 ASC for low-level debug"
>> +		help
>> +		  Say Y here if you want kernel low-level debugging support
>> +		  on StiH415/416 based platforms like B2000, B2020.
>> +		  It support UART2 and SBC_UART1.
>> +
>> +		  If unsure, say N.
>> +
>>  	config DEBUG_LL_UART_NONE
>>  		bool "No low-level debugging UART"
>>  		depends on !ARCH_MULTIPLATFORM
> I would split out the debug code into a separate patch though.
Will do this in next version.
>
>> @@ -600,6 +637,7 @@ config DEBUG_LL_INCLUDE
>>  	default "debug/vt8500.S" if DEBUG_VT8500_UART0
>>  	default "debug/tegra.S" if DEBUG_TEGRA_UART
>>  	default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
>> +	default "debug/stixxxx.S" if DEBUG_STIH41X_UART
>>  	default "mach/debug-macro.S"
> Please keep this in alphabetical order.
Yes.
>
>> +	soc {
>> +		#address-cells = <1>;
>> +		#size-cells = <1>;
>> +		#interrupt-cells = <3>;
>> +		interrupt-parent = <&intc>;
> The "#interrupt-cells" property doesn't belong here I think.
>
>> +
>> +		uart2: uart@fed32000 {
>> +			compatible	= "st,asc";
>> +			status 		= "disabled";
>> +			reg		= <0xfed32000 0x2c>;
>> +			interrupts	= <0 197 0>;
>> +			pinctrl-names 	= "default";
>> +			pinctrl-0 	= <&pinctrl_uart2>;
>> +			clocks		= <&CLKS_ICN_REG_0>;
>> +		};
>> +
>> +		/* SBC comms block ASCs in SASG1 */
>> +		sbc_uart1: uart@fe531000 {
>> +			compatible	= "st,asc";
>> +			status 		= "disabled";
>> +			reg		= <0xfe531000 0x2c>;
>> +			interrupts	= <0 210 0>;
>> +			clocks		= <&CLK_SYSIN>;
>> +			pinctrl-names 	= "default";
>> +			pinctrl-0	= <&pinctrl_sbc_uart1>;
>> +		};
>> +	};
> Please name these devices "serial", not "uart".
Ok, I will rename them to serial.
>> diff --git a/arch/arm/configs/stih41x_defconfig b/arch/arm/configs/stih41x_defconfig
>> new file mode 100644
>> index 0000000..dd9268b
>> --- /dev/null
>> +++ b/arch/arm/configs/stih41x_defconfig
> I would prefer to have this be part of multi_v7_defconfig, unless
> you have strong reason why it can't be.
I think we can move this to multi_v7_defconfig.
>> diff --git a/arch/arm/mach-stih41x/Kconfig b/arch/arm/mach-stih41x/Kconfig
>> new file mode 100644
>> index 0000000..9c40540
>> --- /dev/null
>> +++ b/arch/arm/mach-stih41x/Kconfig
>> @@ -0,0 +1,35 @@
>> +config ARCH_STIH41X
>> +	bool "STMicroelectronics STiH41x SOCs with Flattened Device Tree" if ARCH_MULTI_V7
>> +	select GENERIC_CLOCKEVENTS
>> +	select CLKDEV_LOOKUP
>> +	select ARM_GIC
>
>> +if ARCH_STIH41X
>> +menu "STMicroelectronics Consumer Electronics SOCs"
> You can use 'menuconfig' to combine these two.
Thats a nice one.. Will use it.
>> +static void __init stih41x_timer_init(void)
>> +{
>> +	of_clk_init(NULL);
>> +	clocksource_of_init();
>> +	stih41x_l2x0_init();
>> +}
> I'm hoping we can kill make the clk and l2x0 init work by default in 3.11,
> as clocksource_of_init already does, so you won't need this function
> any more.
Ok.
>
>> +/*
>> + * A basic implementation of irq_set_wake that ensures wakeup source
>> + * interrupts are not disabled during PM_SUSPEND_FREEZE.
>> + */
>> +static int stih41x_set_wake(struct irq_data *d, unsigned int on)
>> +{
>> +	struct irq_desc *desc = irq_to_desc(d->irq);
>> +
>> +	if (on) {
>> +		if (desc->action)
>> +			desc->action->flags |= IRQF_NO_SUSPEND;
>> +	} else {
>> +		if (desc->action)
>> +			desc->action->flags &= ~IRQF_NO_SUSPEND;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static void __init stih41x_irq_init(void)
>> +{
>> +	gic_arch_extn.irq_set_wake = stih41x_set_wake;
>> +	gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
>> +
>> +	irqchip_init();
>> +}
> This looks like it should be generic. Why do you need this?

>
>> +void __init stih41x_dt_init(void)
>> +{
>> +	of_platform_populate(NULL, of_default_bus_match_table,
>> +				NULL, NULL);
>> +	return;
>> +}
> This is already not needed in 3.10.
Ok, cool... will get rid of this..
>
>> +static struct map_desc stih41x_io_desc[] __initdata = {
>> +#ifdef CONFIG_SMP
>> +	{
>> +		.virtual	= IO_ADDRESS(MPE41_SCU_BASE),
>> +		.pfn		= __phys_to_pfn(MPE41_SCU_BASE),
>> +		.length		= SZ_4K,
>> +		.type		= MT_DEVICE,
>> +	},
>> +#endif
>> +void __init stih41x_map_io(void)
>> +{
>> +#ifdef CONFIG_SMP
>> +	stixxxx_scu_base_addr = ((void __iomem *)IO_ADDRESS(MPE41_SCU_BASE));
>> +#endif
>> +	iotable_init(stih41x_io_desc, ARRAY_SIZE(stih41x_io_desc));
>> +}
> IIRC the SCU no longer needs to be mapped this early, so you can use
> ioremap these days.
yep, I agree.
>
>> +void __init stih41x_l2x0_init(void)
>> +{
>> +	u32 way_size = 0x4;
>> +	u32 aux_ctrl;
>> +
>> +	aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
>> +		(0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
>> +		(0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
>> +		(way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
>> +
>> +	l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK);
>> +}
> I don't know where we stand on this, but I think we should kill all
> calls like these.
I agree, but we don't have other ways as of today..
>
> 	Arnd
>


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

* Re: [RFC 7/8] ARM:stih41x: Add B2000 board support
  2013-05-08 16:20   ` Arnd Bergmann
  2013-05-08 16:24     ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 17:04     ` Srinivas KANDAGATLA
  1 sibling, 0 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 17:04 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux, olof, Rob Landley, Grant Likely, Rob Herring,
	Samuel Ortiz, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Jason Cooper, Stephen Warren,
	Maxime Ripard, Nicolas Pitre, Will Deacon, Dave Martin,
	Marc Zyngier, Viresh Kumar, Mark Brown, Dong Aisheng, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial,
	Stephen Gallimore

On 08/05/13 17:20, Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
>> diff --git a/arch/arm/mach-stih41x/board-dt.c b/arch/arm/mach-stih41x/board-dt.c
>> index 8005f71..1f23aca 100644
>> --- a/arch/arm/mach-stih41x/board-dt.c
>> +++ b/arch/arm/mach-stih41x/board-dt.c
>> @@ -63,6 +63,8 @@ void __init stih41x_dt_init(void)
>>  }
>>  
>>  static const char *stih41x_dt_match[] __initdata = {
>> +       "st,stih415-b2000",
>> +       "st,stih416-b2000",
>>         NULL
>>  };
> I probably wouldn't bother listing all the boards here. Just make sure
> the .dts file lists both the name of the board and of the soc in
> its compatible property, and list all the SoCs here that you can boot on.
I like that approach. Will change in the next version.
>
> 	Arnd
>


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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-08 14:50   ` Arnd Bergmann
  2013-05-08 15:01     ` Mark Brown
@ 2013-05-08 17:32     ` Srinivas KANDAGATLA
  2013-05-08 19:48       ` Arnd Bergmann
  1 sibling, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 17:32 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: dong.aisheng, sameo, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

Thankyou for your comments.
On 08/05/13 15:50, Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
>> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>>
>> This patch introduces syscon_claim, syscon_read, syscon_write,
>> syscon_release APIs to help drivers to use syscon registers in much more
>> flexible way.
>>
>> With this patch, a driver can claim few/all bits in the syscon registers
>> and do read/write and then release them when its totally finished with
>> them, in the mean time if another driver requests same bits or registers
>> the API will detect conflit and return error to the second request.
>>
>> Reason to introduce this API.
>> System configuration/control registers are very basic configuration
>> registers arranged in groups across ST Settop Box parts. These registers
>> are independent of IP itself. Many IPs, clock, pad and other functions
>> are wired up to these registers.
>>
>> In many cases a single syconf register contains bits related to multiple
>> devices, and therefore it need to be shared across multiple drivers at
>> bit level. The same IP block can have different syscon mappings on
>> different SOCs.
>>
>> Typically in a SOC there will be more than hundreds of these registers,
>> which are again divided into groups.
>>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>> CC: Stuart Menefy <stuart.menefy@st.com>
> My feeling is that syscon is the wrong place for this functionality,
> since regmap already handles (some of?) these issues. If you need
> additional synchronization, it's probably best to extend regmap
> as needed so other code besides syscon can take advantage of that
> as well.
Its not just synchronisation that we are looking for.
It also the usability, drivers want to just refer to a syscon
register/bits of it from device trees/non-devicetrees.

The extent of syscon usage is very high in ST set-top-box parts.
As example, ST pinctrl driver uses use bits of the syscon register to
control alternate functions, and many other parameters of pinconf.

In device tree we do something like:
        syscfg_sbc: syscon@fe600000{
            compatible      = "syscon";
            reg        = <0xfe600000 0xb4>;         
        };
and in pinctrl dts file
    st,alt-control    = <&syscfg_sbc  0 0 31>;
    st,od-control    = <&syscfg_sbc  9 0 7>;

the pinctrl driver calls syconf_claim(np, "st,alt-control) to get a
field and then do a read/write on the field.

Just in pinctrl driver we use around 50-100 sysconf registers scatters
across different groups.

Without these new APIs, its very difficult to pass this information to
the drivers.

Thanks,
srini
>
> 	Arnd
>


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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-08 15:01     ` Mark Brown
@ 2013-05-08 17:42       ` Srinivas KANDAGATLA
  2013-05-09  9:51         ` Mark Brown
  0 siblings, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 17:42 UTC (permalink / raw)
  To: Mark Brown
  Cc: Arnd Bergmann, dong.aisheng, sameo, Rob Landley, Grant Likely,
	Rob Herring, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Jiri Slaby, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Will Deacon, Dave Martin, Marc Zyngier, Viresh Kumar, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

Thankyou for the comments.
On 08/05/13 16:01, Mark Brown wrote:
> On Wed, May 08, 2013 at 04:50:22PM +0200, Arnd Bergmann wrote:
>
>>> In many cases a single syconf register contains bits related to multiple
>>> devices, and therefore it need to be shared across multiple drivers at
>>> bit level. The same IP block can have different syscon mappings on
>>> different SOCs.
>> My feeling is that syscon is the wrong place for this functionality,
>> since regmap already handles (some of?) these issues. If you need
>> additional synchronization, it's probably best to extend regmap
>> as needed so other code besides syscon can take advantage of that
>> as well.
> This sounds like regmap_update_bits() ought to be all that's needed.

Ultimately the syscon_write use the regmap_update_bits, however we really want is the flexibility in using/referring the syscon registers/bits in both device-trees and non-device tree cases.

The reason for these APIs, is the extent of syscon usage is very high in ST set-top-box parts.

Without these new APIs, its very difficult to pass this information to
the drivers.

Thanks,
srini

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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 14:34   ` [RFC 1/8] serial:st-asc: Add ST ASC driver Arnd Bergmann
  2013-05-08 14:39     ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 18:02     ` Srinivas KANDAGATLA
       [not found]     ` <20130508153459.GA17186@kroah.com>
  2013-05-20 11:49     ` Stephen GALLIMORE
  3 siblings, 0 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 18:02 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: gregkh, jslaby, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Samuel Ortiz, Linus Walleij, Stuart Menefy,
	Shawn Guo, Olof Johansson, Jason Cooper, Stephen Warren,
	Maxime Ripard, Nicolas Pitre, Will Deacon, Dave Martin,
	Marc Zyngier, Viresh Kumar, Mark Brown, Dong Aisheng, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial,
	Stephen Gallimore

Thankyou for the comments.
On 08/05/13 15:34, Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
>> From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>> +*st-asc(Serial Port)
>> +
>> +Required properties:
>> +- compatible : Should be "st,asc".
> Are there any hardware revision numbers for the asc? If there are potentially
> incompatible or backwards-compatible variants, it would be good to include
> the version in this string.
Unfortunately, there is no version numbering for this IP.
>
>> +- reg, reg-names, interrupts, interrupt-names	: Standard way to define device
>> +			resources with names. look in
>> +			Documentation/devicetree/bindings/resource-names.txt
>> +
>> +Optional properties:
>> +- st,hw-flow-ctrl	bool flag to enable hardware flow control.
>> +- st,force-m1		bool flat to force asc to be in Mode-1 recommeded
>> +			for high bit rates (above 19.2K)
>> +Example:
>> +serial@fe440000{
>> +    compatible    = "st,asc";
>> +    reg         = <0xfe440000 0x2c>;
>> +    interrupts     =  <0 209 0>;
>> +};
> I would also recommed adding a way to set the default baud rate through
> a property. Following the example of the 8250 driver, you should probably
> call that "current-speed".
Yes, I will add this in the next version.
>
>> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
>> index 7e7006f..346f325 100644
>> --- a/drivers/tty/serial/Kconfig
>> +++ b/drivers/tty/serial/Kconfig
>> @@ -1484,6 +1484,25 @@ config SERIAL_RP2_NR_UARTS
>>  	  If multiple cards are present, the default limit of 32 ports may
>>  	  need to be increased.
>>  
>> +config SERIAL_ST_ASC
>> +	tristate "ST ASC serial port support"
>> +	depends on PLAT_STIXXXX
>> +	default y
>> +	select SERIAL_CORE
>> +	help
>> +	  This driver is for the on-chip Asychronous Serial Controller on
>> +	  STMicroelectronics STixxxx SoCs.
>> +	  ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
>> +	  It support all industry standard baud rates.
>> +
>> +	  If unsure, say N.
> I would not make it "default y".
Yep.
>> +config SERIAL_ST_ASC_CONSOLE
>> +	bool "Support for console on ST ASC"
>> +	depends on SERIAL_ST_ASC
>> +	default y
>> +	select SERIAL_CORE_CONSOLE
>> +
>>  endmenu
> This needs to be "depends on SERIAL_ST_ASC=y". You would get a link error
> if you try to make SERIAL_ST_ASC a loadable module and SERIAL_ST_ASC_CONSOLE
> built-in.
Ok, got it.
>
>> +
>> +static struct asc_port asc_ports[ASC_MAX_PORTS];
>> +static struct uart_driver asc_uart_driver;
>> +
>> +/*---- Forward function declarations---------------------------*/
>> +static irqreturn_t asc_interrupt(int irq, void *ptr);
>> +static void asc_transmit_chars(struct uart_port *);
>> +static int asc_set_baud(struct asc_port *ascport, int baud);
>> +
> Please remove all forward declarations, by reordering the functions in
> the way they are called.
Will do.
>
>
>> diff --git a/drivers/tty/serial/st-asc.h b/drivers/tty/serial/st-asc.h
>> new file mode 100644
>> index 0000000..e59f818
>> --- /dev/null
>> +++ b/drivers/tty/serial/st-asc.h
>> +#ifndef _ST_ASC_H
>> +#define _ST_ASC_H
>> +
>> +#include <linux/serial_core.h>
>> +#include <linux/clk.h>
>> +
>> +struct asc_port {
>> +	struct uart_port port;
>> +	struct clk *clk;
>> +	unsigned int hw_flow_control:1;
>> +	unsigned int check_parity:1;
>> +	unsigned int force_m1:1;
>> +};
> Since this header file is only used in one place, just merge it into
> the driver itself.
Ok, will do it.

>
>> +#define ASC_MAJOR		204
>> +#define ASC_MINOR_START		40
> I don't know what the current policy is on allocating major/minor numbers,
> but I'm sure you cannot just reuse one that is already used.
>
> Documentation/devices.txt lists the ones that are officially assigned.
> Can't you use dynamic allocation here?
>
> 	Arnd
>


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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 14:39     ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 18:18       ` Srinivas KANDAGATLA
  2013-05-08 19:55         ` Arnd Bergmann
  0 siblings, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-08 18:18 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD
  Cc: Arnd Bergmann, linux-doc, Viresh Kumar, Will Deacon, jslaby,
	Russell King, Samuel Ortiz, Nicolas Pitre, Stephen Gallimore,
	linux-serial, Jason Cooper, devicetree-discuss, Rob Herring,
	Stuart Menefy, Stephen Warren, Dong Aisheng, linux-arm-kernel,
	gregkh, Mark Brown, linux-kernel

On 08/05/13 15:39, Jean-Christophe PLAGNIOL-VILLARD wrote:
>>> +
>> > 
>> > Please remove all forward declarations, by reordering the functions in
>> > the way they are called.
>> > 
> and drop the dummy functions
We can not remove the dummy functions, as the serial-core does not check
it before using them.
>> > 
>>> > > diff --git a/drivers/tty/serial/st-asc.h b/drivers/tty/serial/st-asc.h
>>> > > new file mode 100644
>>> > > index 0000000..e59f818
>>> > > --- /dev/null
>>> > > +++ b/drivers/tty/serial/st-asc.h


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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 16:45                 ` Nicolas Pitre
@ 2013-05-08 18:35                   ` Arnd Bergmann
  2013-05-09 13:36                     ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 18:35 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Greg KH, Jean-Christophe PLAGNIOL-VILLARD, Srinivas KANDAGATLA,
	Viresh Kumar, Will Deacon, jslaby, Russell King, Samuel Ortiz,
	linux-doc, Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Mark Brown, linux-kernel

On Wednesday 08 May 2013, Nicolas Pitre wrote:
> I tried to fix this up over 10 years ago.  RMK tried as well. This 
> failed because X86 people insisted on always having COM1 as /dev/ttyS0, 
> COM3 as /dev/ttyS2 and so on, even when some of them weren't present.
> 
> A common and dynamic namespace eventually succeeded for hard disks.
> Maybe people are ready to accept it for serial ports as well now?

Unfortunately it only worked for hard disks because the old name
space was abandoned entirely. It also caused a lot of surprises
for people upgrading their kernels, which is something we probably
don't want to repeat.

Now we could add a new dynamic registration facility to the tty
layer for drivers that don't already have a name and dev_t
associated with the driver, and then use it for all new drivers
as well as those that intentionally want to convert.

With DT aliases, we already have a way to enumerate serial ports
across device drivers, so if we are going to do something new,
we should make sure it works with the numbers defined there.

	Arnd

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

* Re: [RFC 5/8] ARM:stih41x: Add STiH415 SOC support
  2013-05-08 16:50     ` Stephen GALLIMORE
@ 2013-05-08 18:55       ` Arnd Bergmann
  2013-05-09 11:09         ` Stephen GALLIMORE
  0 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 18:55 UTC (permalink / raw)
  To: Stephen GALLIMORE
  Cc: Srinivas KANDAGATLA, Stuart MENEFY, linux-kernel, linux-arm-kernel

On Wednesday 08 May 2013, Stephen GALLIMORE wrote:

> If you have a better solution, or a way to generalize this that would
> make sense for the ARM architecture as a whole, then we are more than
> happy to change.

No idea, sorry. Upon closer inspection I wonder if your code actually
does anything to the hardware that causes it to wake up on an interrupt.

	Arnd

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-08 17:32     ` Srinivas KANDAGATLA
@ 2013-05-08 19:48       ` Arnd Bergmann
  2013-05-09 10:17         ` Srinivas KANDAGATLA
  0 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 19:48 UTC (permalink / raw)
  To: srinivas.kandagatla
  Cc: dong.aisheng, sameo, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> the pinctrl driver calls syconf_claim(np, "st,alt-control) to get a
> field and then do a read/write on the field.
> 
> Just in pinctrl driver we use around 50-100 sysconf registers scatters
> across different groups.
> 
> Without these new APIs, its very difficult to pass this information to
> the drivers.

But are those necessarily things you would configure using DT?

If there are so many registers that are shared between mutliple
subsystems, maybe using drivers/mfd/syscon for that is taking things
further than you should, since it is unlike what any of the other
SoC families need from syscon.

Can you describe how your syscon registers are laid out?
Which subsystems beside pinctrl need to directly interact
with it? Is there any logical structure in it or do you just
have tons of bits scattered around an MMIO area?

	Arnd

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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 18:18       ` Srinivas KANDAGATLA
@ 2013-05-08 19:55         ` Arnd Bergmann
  0 siblings, 0 replies; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-08 19:55 UTC (permalink / raw)
  To: srinivas.kandagatla
  Cc: Jean-Christophe PLAGNIOL-VILLARD, linux-doc, Viresh Kumar,
	Will Deacon, jslaby, Russell King, Samuel Ortiz, Nicolas Pitre,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, gregkh, Mark Brown, linux-kernel

On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
> 
> On 08/05/13 15:39, Jean-Christophe PLAGNIOL-VILLARD wrote:
> >>> +
> >> > 
> >> > Please remove all forward declarations, by reordering the functions in
> >> > the way they are called.
> >> > 
> > and drop the dummy functions
>
> We can not remove the dummy functions, as the serial-core does not check
> it before using them.

None of them seem performance critical, so it sounds reasonable to change
this in the core so you don't have to provide them. It's up to Greg to decide
whether he'd like that change or not.

	Arnd

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-08 17:42       ` Srinivas KANDAGATLA
@ 2013-05-09  9:51         ` Mark Brown
  2013-05-09 11:58           ` Srinivas KANDAGATLA
  2013-05-10 12:51           ` Srinivas KANDAGATLA
  0 siblings, 2 replies; 64+ messages in thread
From: Mark Brown @ 2013-05-09  9:51 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: Arnd Bergmann, dong.aisheng, sameo, Rob Landley, Grant Likely,
	Rob Herring, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Jiri Slaby, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Will Deacon, Dave Martin, Marc Zyngier, Viresh Kumar, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

[-- Attachment #1: Type: text/plain, Size: 1021 bytes --]

On Wed, May 08, 2013 at 06:42:04PM +0100, Srinivas KANDAGATLA wrote:

Fix your mailer to word wrap within paragraphs.

> Ultimately the syscon_write use the regmap_update_bits, however we
> really want is the flexibility in using/referring the syscon
> registers/bits in both device-trees and non-device tree cases.

So what you're looking for here is some way to offload discovery of
register fields from the driver?

> The reason for these APIs, is the extent of syscon usage is very high
> in ST set-top-box parts.

> Without these new APIs, its very difficult to pass this information to
> the drivers.

I'm not 100% convinced that putting all this information into DT is a
good idea, and to the extent that it is sensible it feels like something
which might be useful with any device using register maps, not just
syscon.  For example many MFDs have similar needs - essentially the
system controllers are just a particular kind of MFD.  To me that says
that this should be outside syscon so other things can use it.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-08 19:48       ` Arnd Bergmann
@ 2013-05-09 10:17         ` Srinivas KANDAGATLA
  2013-05-17 14:36           ` Arnd Bergmann
  0 siblings, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-09 10:17 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: dong.aisheng, sameo, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

Hi Arnd,
Thankyou for extending the discussion.

On 08/05/13 20:48, Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
>> the pinctrl driver calls syconf_claim(np, "st,alt-control) to get a
>> field and then do a read/write on the field.
>>
>> Just in pinctrl driver we use around 50-100 sysconf registers scatters
>> across different groups.
>>
>> Without these new APIs, its very difficult to pass this information to
>> the drivers.
> But are those necessarily things you would configure using DT?
In last comment.
>
> If there are so many registers that are shared between mutliple
> subsystems, maybe using drivers/mfd/syscon for that is taking things
> further than you should, since it is unlike what any of the other
> SoC families need from syscon.
I agree, my initial approach was having a dedicated driver specific to
ST syscon, however syscon seems to do things very much similar to what
we want, so I have integrated those 3 functions in syscon.
Am happy to go back with my first approach of adding ST specific syscon
driver if no one is actually going to benefit with such a change to
syscon driver.

>
> Can you describe how your syscon registers are laid out?
On STiH416 SOC we have 9 SYSCONF(aka System Configuration
Registers)named banks/groups, each bank has its own memory map.
Each sysconf bank has number of 32 bit registers which vary from bank to
bank, like sysconf bank "sbc" has range from SYSTEM_CONFIG0 to
SYSTEM_CONFIG999 where as  sysconf bank "front" has range of
SYSTEM_CONFIG1000 to SYSTEM_CONFIG1999 and so on.

Each register is assigned with a unique SYCONF number, example:
SYSTEM_CONFIG100, SYSTEM_CONFIG101 , .. and so on.
Each sysconf contains bits of the IP configurations wired-up to the
sysconf register bits.

As example:

- Each pinctrl entry for set of 8 pins uses around 8-10 sysconfig
register to control pinconf and pin functions.
- IPs like Ethernet have few bit like Ethernet-Mode selection external
or internal phyclk wired up to bits in sysconf registers,
- Few clocks are controlled by sysconf registers.
- Reset to IPs are wired up to bits of sysconf same registers.
- ARM core soft reset is wired up to the sysconf registers...
And most of the IPs have similar requirements ......

Total layout of the sysconf changes per SOC, and the bit arrangements
aswell, however the core IP(pinctrl, etherenet ...) and logic to drive
those bits remains exactly same.

As the code remains the same, the information about the hardware
configuration and offsets to the registers are passed by device trees
using the node properties.

In general the requirements of the sysconf support to the SOC/driver
support is.
1> It should be able to read/write a sysconf register bits without
having to "if" each SOC in the code. So that code is totally abstracted.
Which is currently achieved by passing the information from the device
trees and the driver just uses the property to get it.
2> The infrastructure should protect the claimed registers from
over-writing by other drivers. We do this by claim-read/write-release
style API.
3> The driver should be able to set a group of sysconf registers bits to
a particular values before initialises the IP. I was thinking of doing
this in a same way as pinctrl state.

Any suggestion is most appreciated?

Thanks,
srini

> Which subsystems beside pinctrl need to directly interact
> with it? Is there any logical structure in it or do you just
> have tons of bits scattered around an MMIO area?
>
> 	Arnd
>


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

* RE: [RFC 5/8] ARM:stih41x: Add STiH415 SOC support
  2013-05-08 18:55       ` Arnd Bergmann
@ 2013-05-09 11:09         ` Stephen GALLIMORE
  0 siblings, 0 replies; 64+ messages in thread
From: Stephen GALLIMORE @ 2013-05-09 11:09 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Srinivas KANDAGATLA, Stuart MENEFY, linux-kernel, linux-arm-kernel

> If you have a better solution, or a way to generalize this that would 
> make sense for the ARM architecture as a whole, then we are more than 
> happy to change.
>
>No idea, sorry. Upon closer inspection I wonder if your code actually does anything to the hardware that causes it to wake up on an interrupt.

You are correct that it does not affect the hardware and as such it may be entirely the wrong approach to put this code here. However, as drivers or subsystems are expected to call enable/disable_irq_ wake() when appropriate it seemed a reasonable place to do it and of course in the future when we add in support for the other suspend states this is also expected to do something with the system standby controller, as is the case on other platforms. But we concede that in this first minimal version that it may look a little out of place.

To quickly summarize the issue we were trying to address, the new freeze state suspends the drivers but then rather than calling the arch suspend code simply goes to sleep on a wake queue. It is relying on wakeup source interrupt handlers actually being run (this is not the case in the other "traditional" suspend states) and that the driver or some subsystem code called as part of the driver's interrupt processing will call pm_wakeup_event() which signals the freeze wake queue and causes the generic suspend code to start going through its wakeup path. But the driver suspend code will suspend the calling of IRQ handlers, dpm_suspend_noirq() calls suspend_device_irqs(), except for those with the NO_SUSPEND flag set.

Now it is possible that we have simply tried to finesse the solution too much and that using the ASC serial device as a wakeup source was an unfortunate place to start, because most wakeup devices on a set top box have a single instance, e.g. the IR device for the remote control and you probably always want them to be a wakeup source. Maybe it would not have really mattered that much in the end if the ASC driver simply installed the interrupts for all UART ports with the flag, regardless of if the port was going to be used to wake up or not; but as I said in my previous response that solution left us feeling a bit uncomfortable which is why we went looking for another approach that was independent of the device driver and hooking into enable/disable_irq_wake() at the architecture level seemed more appropriate once we noticed it being used elsewhere. However, until you put it out there for comment it is hard to know if you have backed the right horse.

Regards,
-stephen


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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-09  9:51         ` Mark Brown
@ 2013-05-09 11:58           ` Srinivas KANDAGATLA
  2013-05-09 13:26             ` Mark Brown
  2013-05-10 12:51           ` Srinivas KANDAGATLA
  1 sibling, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-09 11:58 UTC (permalink / raw)
  To: Mark Brown
  Cc: Arnd Bergmann, dong.aisheng, sameo, Rob Landley, Grant Likely,
	Rob Herring, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Jiri Slaby, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Will Deacon, Dave Martin, Marc Zyngier, Viresh Kumar, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

On 09/05/13 10:51, Mark Brown wrote:
> On Wed, May 08, 2013 at 06:42:04PM +0100, Srinivas KANDAGATLA wrote:
> 
> Fix your mailer to word wrap within paragraphs.
> 
Sorry about that.
>> Ultimately the syscon_write use the regmap_update_bits, however we
>> really want is the flexibility in using/referring the syscon
>> registers/bits in both device-trees and non-device tree cases.
> 
> So what you're looking for here is some way to offload discovery of
> register fields from the driver?

Exactly,

As the System configuration registers change per each SOC, and the
logic/code to drive still remain same across SOCs.

It makes sense to abstract the information of sysconf register and its
offsets from the driver, as we do not want to change the driver per each
SOC.

> 
>> The reason for these APIs, is the extent of syscon usage is very high
>> in ST set-top-box parts.
> 
>> Without these new APIs, its very difficult to pass this information to
>> the drivers.
> 
> I'm not 100% convinced that putting all this information into DT is a
> good idea,

Currently, we have two bits of information which come from device trees.
1> The syscon bank/group definition itself.
2> syscon register offsets and bits information to the drivers.

These are the 2 things which keep changing per each SOC.

There is no other way to pass this information to the drivers other than
passing them as part of their own device node and syscon node.

>  and to the extent that it is sensible it feels like something
> which might be useful with any device using register maps, not just
> syscon.

If you think this is going to be useful for other drivers, Am happy to
move this out of syscon to regmap something like adding
of_regmap_field_claim/regmap_field_claim/regmap_field_read/regmap_field_write/regmap_field_release
functions.

so any exiting drivers can still use the old syscon API to get the
regmap instance.
Alternatively they can use the new regmap APIs directly.

regmap_field_claim to claim bits of the register
of_regmap_field_claim DT version of reg_map_field_claim.
regmap_field_write to write to bits of register
regmap_field_read to bit of the register.
regmap_field_release to release the bits of the register.

For DT version it might involve adding new member to struct
regmap_config to lookup regmap by phandle, so that regmap can get hold
of regmap instance from device tree phandle.
syscon driver already does this in syscon_regmap_lookup_by_phandle()

On the device tree side it will look like:
syscfg_sbc:syscon@fe600000{
	compatible	= "syscon";
	reg		= <0xfe600000 0x1000>;
};

node {
	property-1 = <&syscfg_sbc 10 0 31>;
};

property has "phandle", register_offset, lsb, msb.

On the driver side, it can just use the API's like

field = of_regmap_field_claim(np, "property-1");
regmap_field_write(field, val);
regmap_field_release(field);

All this involves is very minimal code change in syscon and a new APIs
and DT awareness into regmap.

What do you think?

Thanks,
srini

>  For example many MFDs have similar needs - essentially the
> system controllers are just a particular kind of MFD.  To me that says
> that this should be outside syscon so other things can use it.

> 


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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-09 11:58           ` Srinivas KANDAGATLA
@ 2013-05-09 13:26             ` Mark Brown
  2013-05-09 14:00               ` Srinivas KANDAGATLA
  0 siblings, 1 reply; 64+ messages in thread
From: Mark Brown @ 2013-05-09 13:26 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: Arnd Bergmann, dong.aisheng, sameo, Rob Landley, Grant Likely,
	Rob Herring, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Jiri Slaby, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Will Deacon, Dave Martin, Marc Zyngier, Viresh Kumar, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

[-- Attachment #1: Type: text/plain, Size: 1489 bytes --]

On Thu, May 09, 2013 at 12:58:01PM +0100, Srinivas KANDAGATLA wrote:

> Currently, we have two bits of information which come from device trees.
> 1> The syscon bank/group definition itself.
> 2> syscon register offsets and bits information to the drivers.

> These are the 2 things which keep changing per each SOC.

> There is no other way to pass this information to the drivers other than
> passing them as part of their own device node and syscon node.

Sure there is, for example the drivers could have this information
internally as part of knowing which device they're working with or they
could take advantage of some patterns in the register map to store some
higher level information that they use to configure.

> >  and to the extent that it is sensible it feels like something
> > which might be useful with any device using register maps, not just
> > syscon.

> If you think this is going to be useful for other drivers, Am happy to
> move this out of syscon to regmap something like adding
> of_regmap_field_claim/regmap_field_claim/regmap_field_read/regmap_field_write/regmap_field_release
> functions.

> so any exiting drivers can still use the old syscon API to get the
> regmap instance.
> Alternatively they can use the new regmap APIs directly.

Well, I'd need to see the code to decide if it was sane but I do think
that if this is a good approach it's not syscon specific.  Anything like
this needs to be independent of DT too since not all architectures use
DT.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 18:35                   ` Arnd Bergmann
@ 2013-05-09 13:36                     ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 64+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-09 13:36 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Nicolas Pitre, Greg KH, Srinivas KANDAGATLA, Viresh Kumar,
	Will Deacon, jslaby, Russell King, Samuel Ortiz, linux-doc,
	Stephen Gallimore, linux-serial, Jason Cooper,
	devicetree-discuss, Rob Herring, Stuart Menefy, Stephen Warren,
	Dong Aisheng, linux-arm-kernel, Mark Brown, linux-kernel

On 20:35 Wed 08 May     , Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Nicolas Pitre wrote:
> > I tried to fix this up over 10 years ago.  RMK tried as well. This 
> > failed because X86 people insisted on always having COM1 as /dev/ttyS0, 
> > COM3 as /dev/ttyS2 and so on, even when some of them weren't present.
> > 
> > A common and dynamic namespace eventually succeeded for hard disks.
> > Maybe people are ready to accept it for serial ports as well now?
> 
> Unfortunately it only worked for hard disks because the old name
> space was abandoned entirely. It also caused a lot of surprises
> for people upgrading their kernels, which is something we probably
> don't want to repeat.
> 
> Now we could add a new dynamic registration facility to the tty
> layer for drivers that don't already have a name and dev_t
> associated with the driver, and then use it for all new drivers
> as well as those that intentionally want to convert.

specially that we use devtmpfs and udev

we do not care much about minor/major
> 
> With DT aliases, we already have a way to enumerate serial ports
> across device drivers, so if we are going to do something new,
> we should make sure it works with the numbers defined there.
> 
> 	Arnd

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-09 13:26             ` Mark Brown
@ 2013-05-09 14:00               ` Srinivas KANDAGATLA
  2013-05-09 14:40                 ` Mark Brown
  0 siblings, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-09 14:00 UTC (permalink / raw)
  To: Mark Brown
  Cc: Arnd Bergmann, dong.aisheng, sameo, Rob Landley, Grant Likely,
	Rob Herring, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Jiri Slaby, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Will Deacon, Dave Martin, Marc Zyngier, Viresh Kumar, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

On 09/05/13 14:26, Mark Brown wrote:
> On Thu, May 09, 2013 at 12:58:01PM +0100, Srinivas KANDAGATLA wrote:
> 
>> Currently, we have two bits of information which come from device trees.
>> 1> The syscon bank/group definition itself.
>> 2> syscon register offsets and bits information to the drivers.
> 
>> These are the 2 things which keep changing per each SOC.
> 
>> There is no other way to pass this information to the drivers other than
>> passing them as part of their own device node and syscon node.
> 
> Sure there is, for example the drivers could have this information
> internally as part of knowing which device they're working with or they
> could take advantage of some patterns in the register map to store some
> higher level information that they use to configure.
> 
Some of layouts of the sysconf registers are totally changed for each SOC.

Looking at driver by driver maybe some drivers can take advantage of the
patterns, but Am not sure if this will be a sustainable solution for all
the drivers.

The big disadvantage of this approach is that
- Every driver has to be touched for new SOC,
- Secondly the drivers will end up having more of such information than
code over a time.

>>>  and to the extent that it is sensible it feels like something
>>> which might be useful with any device using register maps, not just
>>> syscon.
> 
>> If you think this is going to be useful for other drivers, Am happy to
>> move this out of syscon to regmap something like adding
>> of_regmap_field_claim/regmap_field_claim/regmap_field_read/regmap_field_write/regmap_field_release
>> functions.
> 
>> so any exiting drivers can still use the old syscon API to get the
>> regmap instance.
>> Alternatively they can use the new regmap APIs directly.
> 
> Well, I'd need to see the code to decide if it was sane but I do think
> that if this is a good approach it's not syscon specific.  Anything like
> this needs to be independent of DT too since not all architectures use
> DT.
In the suggested approach, the API supports, both DT and non-DT style.

for DT style user can use.
of_regmap_field_claim -> regmap_field_read -> regmap_field_write-
->regmap_field_release

and for NON-DT user can use
regmap_field_claim  -> regmap_field_read -> regmap_field_write-
->regmap_field_release


thanks,
srini


> 


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

* Re: [RFC 2/8] ARM:global_timer: Add ARM global timer support.
  2013-05-08 14:38   ` Arnd Bergmann
  2013-05-08 14:51     ` Steffen Trumtrar
@ 2013-05-09 14:07     ` Srinivas KANDAGATLA
  2013-05-09 14:51       ` Arnd Bergmann
  1 sibling, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-09 14:07 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Dave Martin, linux-doc, Viresh Kumar, Linus Walleij, will.deacon,
	Grant Likely, Jiri Slaby, linux, Samuel Ortiz, Nicolas Pitre,
	linux-serial, Jason Cooper, Marc Zyngier, devicetree-discuss,
	Rob Herring, Stuart Menefy, Stephen Warren, Dong Aisheng,
	linux-arm-kernel, Greg Kroah-Hartman, Mark Brown, linux-kernel,
	Rob Landley, Olof Johansson, Maxime Ripard, Shawn Guo

On 08/05/13 15:38, Arnd Bergmann wrote:
> On Wednesday 08 May 2013, Srinivas KANDAGATLA wrote:
>> From: Stuart Menefy <stuart.menefy@st.com>
>>
>> This is a simple driver for the global timer module found in the Cortex
>> A9-MP cores from revision r1p0 onwards. This should be able to perform
>> the functions of the system timer and the local timer in an SMP system.
>>
>> The global timer has the following features:
>>     The global timer is a 64-bit incrementing counter with an
>> auto-incrementing feature. It continues incrementing after sending
>> interrupts. The global timer is memory mapped in the private memory
>> region.
>>     The global timer is accessible to all Cortex-A9 processors in the
>> cluster. Each Cortex-A9 processor has a private 64-bit comparator that
>> is used to assert a private interrupt when the global timer has reached
>> the comparator value. All the Cortex-A9 processors in a design use the
>> banked ID, ID27, for this interrupt. ID27 is sent to the Interrupt
>> Controller as a Private Peripheral Interrupt. The global timer is
>> clocked by PERIPHCLK.
>>
>> Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>>
> 
> Are you sure we don't already have a driver for this? It sounds unlikely
> that you are the first one to do this when the hardware is so common.

Yes, in mainline we do not have support to this.

> 
>>  Documentation/devicetree/bindings/arm/gt.txt |   21 ++
>>  arch/arm/Kconfig                             |    6 +
>>  arch/arm/include/asm/global_timer.h          |   12 +
>>  arch/arm/kernel/Makefile                     |    1 +
>>  arch/arm/kernel/global_timer.c               |  325 ++++++++++++++++++++++++++
>>  5 files changed, 365 insertions(+), 0 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/arm/gt.txt
>>  create mode 100644 arch/arm/include/asm/global_timer.h
>>  create mode 100644 arch/arm/kernel/global_timer.c
> 
> Move it into drivers/clocksource?

Sure, I will move this in the next version.

>  
>> diff --git a/arch/arm/include/asm/global_timer.h b/arch/arm/include/asm/global_timer.h
>> new file mode 100644
>> index 0000000..46f9188
>> --- /dev/null
>> +++ b/arch/arm/include/asm/global_timer.h
>> @@ -0,0 +1,12 @@
>> +int __init global_timer_init(void __iomem *base, unsigned int timer_irq);
> 
> I don't see a need to call this from platform code for non-DT platforms, it
> can easily be used with CLOCKSOURCE_OF_DECLARE() all the time I think.

sorry Am confused here.
How would this work for non-DT?

Looking at the code in clocksource_of_init it just goes through the
of_device_id table, which is not used in case of non-DT.
> 
> 	Arnd
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 
> 


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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-09 14:00               ` Srinivas KANDAGATLA
@ 2013-05-09 14:40                 ` Mark Brown
  2013-05-09 14:47                   ` Srinivas KANDAGATLA
  0 siblings, 1 reply; 64+ messages in thread
From: Mark Brown @ 2013-05-09 14:40 UTC (permalink / raw)
  To: Srinivas KANDAGATLA
  Cc: Arnd Bergmann, dong.aisheng, sameo, Rob Landley, Grant Likely,
	Rob Herring, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Jiri Slaby, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Will Deacon, Dave Martin, Marc Zyngier, Viresh Kumar, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

[-- Attachment #1: Type: text/plain, Size: 469 bytes --]

On Thu, May 09, 2013 at 03:00:16PM +0100, Srinivas KANDAGATLA wrote:

> Some of layouts of the sysconf registers are totally changed for each SOC.

> Looking at driver by driver maybe some drivers can take advantage of the
> patterns, but Am not sure if this will be a sustainable solution for all
> the drivers.

So what exactly is the driver doing then?  If the register maps look
nothing like each other then what's the common functionality the driver
is providing?

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-09 14:40                 ` Mark Brown
@ 2013-05-09 14:47                   ` Srinivas KANDAGATLA
  0 siblings, 0 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-09 14:47 UTC (permalink / raw)
  To: Mark Brown
  Cc: Arnd Bergmann, dong.aisheng, sameo, Rob Landley, Grant Likely,
	Rob Herring, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Jiri Slaby, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Will Deacon, Dave Martin, Marc Zyngier, Viresh Kumar, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

On 09/05/13 15:40, Mark Brown wrote:
> So what exactly is the driver doing then?  If the register maps look
> nothing like each other then what's the common functionality the driver
> is providing?
What I meant here is that, sysconf registers are reassigned per SOC, so
the sysconf register definitions change per SOC, not the register map of
the device itself.

The register map of the device itself still looks the same, however few
bits of the IP are wired up to the global sysconf registers, which is
what keeps changing, w.r.t sysconf number or bits of the sysconf itself.





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

* Re: [RFC 2/8] ARM:global_timer: Add ARM global timer support.
  2013-05-09 14:07     ` Srinivas KANDAGATLA
@ 2013-05-09 14:51       ` Arnd Bergmann
  2013-05-09 14:51         ` Srinivas KANDAGATLA
  0 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-09 14:51 UTC (permalink / raw)
  To: srinivas.kandagatla
  Cc: Dave Martin, linux-doc, Viresh Kumar, Linus Walleij, will.deacon,
	Grant Likely, Jiri Slaby, linux, Samuel Ortiz, Nicolas Pitre,
	linux-serial, Jason Cooper, Marc Zyngier, devicetree-discuss,
	Rob Herring, Stuart Menefy, Stephen Warren, Dong Aisheng,
	linux-arm-kernel, Greg Kroah-Hartman, Mark Brown, linux-kernel,
	Rob Landley, Olof Johansson, Maxime Ripard, Shawn Guo

On Thursday 09 May 2013, Srinivas KANDAGATLA wrote:
> >> diff --git a/arch/arm/include/asm/global_timer.h b/arch/arm/include/asm/global_timer.h
> >> new file mode 100644
> >> index 0000000..46f9188
> >> --- /dev/null
> >> +++ b/arch/arm/include/asm/global_timer.h
> >> @@ -0,0 +1,12 @@
> >> +int __init global_timer_init(void __iomem *base, unsigned int timer_irq);
> > 
> > I don't see a need to call this from platform code for non-DT platforms, it
> > can easily be used with CLOCKSOURCE_OF_DECLARE() all the time I think.
> 
> sorry Am confused here.
> How would this work for non-DT?

It won't.

> Looking at the code in clocksource_of_init it just goes through the
> of_device_id table, which is not used in case of non-DT.

All new platforms are DT-only, and none of the old platforms use this
driver, so it does not matter.

	Arnd

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

* Re: [RFC 2/8] ARM:global_timer: Add ARM global timer support.
  2013-05-09 14:51       ` Arnd Bergmann
@ 2013-05-09 14:51         ` Srinivas KANDAGATLA
  0 siblings, 0 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-09 14:51 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Dave Martin, linux-doc, Viresh Kumar, Linus Walleij, will.deacon,
	Grant Likely, Jiri Slaby, linux, Samuel Ortiz, Nicolas Pitre,
	linux-serial, Jason Cooper, Marc Zyngier, devicetree-discuss,
	Rob Herring, Stuart Menefy, Stephen Warren, Dong Aisheng,
	linux-arm-kernel, Greg Kroah-Hartman, Mark Brown, linux-kernel,
	Rob Landley, Olof Johansson, Maxime Ripard, Shawn Guo

On 09/05/13 15:51, Arnd Bergmann wrote:
> It won't.
> 
>> > Looking at the code in clocksource_of_init it just goes through the
>> > of_device_id table, which is not used in case of non-DT.
> All new platforms are DT-only, and none of the old platforms use this
> driver, so it does not matter.
> 
It makes sense, I will remove the header file.
> 	Arnd
> 


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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-09  9:51         ` Mark Brown
  2013-05-09 11:58           ` Srinivas KANDAGATLA
@ 2013-05-10 12:51           ` Srinivas KANDAGATLA
  1 sibling, 0 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-10 12:51 UTC (permalink / raw)
  To: Mark Brown
  Cc: Arnd Bergmann, dong.aisheng, sameo, Rob Landley, Grant Likely,
	Rob Herring, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Jiri Slaby, Stuart Menefy, Shawn Guo, Olof Johansson,
	Jason Cooper, Stephen Warren, Maxime Ripard, Nicolas Pitre,
	Will Deacon, Dave Martin, Marc Zyngier, Viresh Kumar, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

Hi Marc,

I would like to explain you bit more about "ST System Configuration
registers".

The SOCs are assembled from existing IP blocks, which don't change very
often. However these blocks are assembled in different configurations to
meet the device requirements. So most IP blocks as well as having a bus
interface through which their own registers are accessible, will also
have a number of bristles(wires) which are signals that are going in and
out of the IP for configuration and status. To make these signals
accessible to software they are wired to "System Configuration Registers".

Drivers target the IP blocks, which don't change much. Where as the
mapping of IP specific bristles(wires) to "System Configuration
Registers" do change per each SOC, and therefore we do not want this
information to be part of the driver.

Having a System Configuration infrastructure gives much flexibility and
abstraction to drivers to configure them.

Given the comments on the patch, I am inclined not to use syscon for ST
specific "System Configuration Registers", alternatively I would like to
create a separate mfd system configuration driver specific to ST.

This is how we did it initially in the out-of-tree kernel.
http://git.stlinux.com/?p=stm/linux-stm.git;a=blob;f=drivers/stm/sysconf.c

Any suggestions?


thanks,
srini

On 09/05/13 10:51, Mark Brown wrote:
> On Wed, May 08, 2013 at 06:42:04PM +0100, Srinivas KANDAGATLA wrote:
> 
> Fix your mailer to word wrap within paragraphs.
> 
>> Ultimately the syscon_write use the regmap_update_bits, however we
>> really want is the flexibility in using/referring the syscon
>> registers/bits in both device-trees and non-device tree cases.
> 
> So what you're looking for here is some way to offload discovery of
> register fields from the driver?
> 
>> The reason for these APIs, is the extent of syscon usage is very high
>> in ST set-top-box parts.
> 
>> Without these new APIs, its very difficult to pass this information to
>> the drivers.
> 
> I'm not 100% convinced that putting all this information into DT is a
> good idea, and to the extent that it is sensible it feels like something
> which might be useful with any device using register maps, not just
> syscon.  For example many MFDs have similar needs - essentially the
> system controllers are just a particular kind of MFD.  To me that says
> that this should be outside syscon so other things can use it.
> 


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

* RE: [RFC 1/8] serial:st-asc: Add ST ASC driver.
       [not found]     ` <20130508153459.GA17186@kroah.com>
  2013-05-08 15:40       ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 16:10       ` Stephen GALLIMORE
@ 2013-05-10 13:50       ` Stephen GALLIMORE
  2013-05-10 14:08         ` Greg KH
  2 siblings, 1 reply; 64+ messages in thread
From: Stephen GALLIMORE @ 2013-05-10 13:50 UTC (permalink / raw)
  To: Greg KH, Arnd Bergmann
  Cc: Srinivas KANDAGATLA, Stuart MENEFY, linux-kernel, linux-serial

>On Wed, May 08, 2013 at 04:34:43PM +0200, Arnd Bergmann wrote:
> > > +#define ASC_MAJOR		204
> > > +#define ASC_MINOR_START		40
> > 
> > I don't know what the current policy is on allocating major/minor 
> > numbers, but I'm sure you cannot just reuse one that is already used.
>
> First, our apologies, this issue was raised internally and then got forgotten about, there's always something I guess.
> 
> > >I agree, why are you trying to create a new tty device name?  Can't 
> > >you use the existing ttyS name and minor number as you will not have any other type of serial device on this system?
>
> That is an interesting question Greg; I believe it probably stems from historic ST SoCs that had two different types of serial devices,
> something that is no longer the case. We will review our approach to this again, although we are not sure we can use the
> existing ttyS major/minor (even if that is an acceptable thing to do) because of the (remote) possibility of someone using 
> a standard PCIe attached serial card.

Greg, having looked at this we have concluded that we should just go dynamic, as others have mentioned with udev on a full system
or devtmpfs on a minimal initramfs system there is no reason to use a static major/minor. However the view here is that we
would prefer to keep the unique name, as for example the lantiq driver which is also dynamic does, for the reason previously
mentioned regarding PCIe cards.

Is that acceptable?

Regards,
-stephen

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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-10 13:50       ` Stephen GALLIMORE
@ 2013-05-10 14:08         ` Greg KH
  0 siblings, 0 replies; 64+ messages in thread
From: Greg KH @ 2013-05-10 14:08 UTC (permalink / raw)
  To: Stephen GALLIMORE
  Cc: Arnd Bergmann, Srinivas KANDAGATLA, Stuart MENEFY, linux-kernel,
	linux-serial

On Fri, May 10, 2013 at 03:50:16PM +0200, Stephen GALLIMORE wrote:
> Greg, having looked at this we have concluded that we should just go
> dynamic, as others have mentioned with udev on a full system or
> devtmpfs on a minimal initramfs system there is no reason to use a
> static major/minor. However the view here is that we would prefer to
> keep the unique name, as for example the lantiq driver which is also
> dynamic does, for the reason previously mentioned regarding PCIe
> cards.

Why do you want your own name?

> Is that acceptable?

I would prefer not to use a new serial port name, as this is only going
to make it harder for me to delete that name in the next year :)

Sorry,

greg k-h

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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 16:36                 ` Greg KH
@ 2013-05-10 23:29                   ` Russell King - ARM Linux
  0 siblings, 0 replies; 64+ messages in thread
From: Russell King - ARM Linux @ 2013-05-10 23:29 UTC (permalink / raw)
  To: Greg KH
  Cc: Arnd Bergmann, Jean-Christophe PLAGNIOL-VILLARD,
	Srinivas KANDAGATLA, Viresh Kumar, Will Deacon, jslaby,
	Samuel Ortiz, Nicolas Pitre, linux-doc, Stephen Gallimore,
	linux-serial, Jason Cooper, devicetree-discuss, Rob Herring,
	Stuart Menefy, Stephen Warren, Dong Aisheng, linux-arm-kernel,
	Mark Brown, linux-kernel

On Wed, May 08, 2013 at 09:36:13AM -0700, Greg KH wrote:
> On Wed, May 08, 2013 at 06:31:48PM +0200, Arnd Bergmann wrote:
> > On Wednesday 08 May 2013, Greg KH wrote:
> > > > just mention there is not hardware reason to not use the generic ttySx
> > > > in place of ttyAS as we have only one IP that handle serial on this
> > > > family of SoC
> > > > 
> > > > personally I'll switch to ttySx
> > > 
> > > Great, then you can use the same major/minor range as well, so there's
> > > no more objection from me about this :)
> > 
> > Does that work these days when you have kernel with multiple built-in
> > uart drivers?
> 
> It "should", as the major/minor registration should only happen when the
> hardware is found, but I haven't tested it out, so I can't say for sure.

serial stuff has never operated like that.  More specifically, it's a
limitation with the tty stuff that the way stuff works is that a
tty driver can only drive a single bunch of contiguous minor numbers.
No interleaving is allowed.

That limitation has existed for years, and I don't see it going away.
As long as that limitation exists, you can only ever have one serial
driver driving a set of contiguous minor numbers.

There has been an attempt to "work around" this by making the 8250
driver "special" which was a complete hack to get it to work.  That
was while I maintained this stuff and I outright refused to make one
serial driver magically special.

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-09 10:17         ` Srinivas KANDAGATLA
@ 2013-05-17 14:36           ` Arnd Bergmann
  2013-05-20 12:48             ` Srinivas KANDAGATLA
  0 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-17 14:36 UTC (permalink / raw)
  To: srinivas.kandagatla
  Cc: dong.aisheng, sameo, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

On Thursday 09 May 2013, Srinivas KANDAGATLA wrote:
> On 08/05/13 20:48, Arnd Bergmann wrote:
> I agree, my initial approach was having a dedicated driver specific to
> ST syscon, however syscon seems to do things very much similar to what
> we want, so I have integrated those 3 functions in syscon.
> Am happy to go back with my first approach of adding ST specific syscon
> driver if no one is actually going to benefit with such a change to
> syscon driver.

That would at least be less controversial.

> > Can you describe how your syscon registers are laid out?
> On STiH416 SOC we have 9 SYSCONF(aka System Configuration
> Registers)named banks/groups, each bank has its own memory map.
> Each sysconf bank has number of 32 bit registers which vary from bank to
> bank, like sysconf bank "sbc" has range from SYSTEM_CONFIG0 to
> SYSTEM_CONFIG999 where as  sysconf bank "front" has range of
> SYSTEM_CONFIG1000 to SYSTEM_CONFIG1999 and so on.
> 
> Each register is assigned with a unique SYCONF number, example:
> SYSTEM_CONFIG100, SYSTEM_CONFIG101 , .. and so on.
> Each sysconf contains bits of the IP configurations wired-up to the
> sysconf register bits.

Ok.

> As example:
> 
> - Each pinctrl entry for set of 8 pins uses around 8-10 sysconfig
> register to control pinconf and pin functions.
> - IPs like Ethernet have few bit like Ethernet-Mode selection external
> or internal phyclk wired up to bits in sysconf registers,
> - Few clocks are controlled by sysconf registers.
> - Reset to IPs are wired up to bits of sysconf same registers.
> - ARM core soft reset is wired up to the sysconf registers...
> And most of the IPs have similar requirements ......
> 
> Total layout of the sysconf changes per SOC, and the bit arrangements
> aswell, however the core IP(pinctrl, etherenet ...) and logic to drive
> those bits remains exactly same.

It sounds like you really need a driver with high-level interfaces
for the bits that change by each core and are needed by otherwise
identical drivers, like the Ethernet driver you mention.

I would not go as far as you did describing the individual bits in
the device node using these however. That driver can be layered on
top of the existing syscon driver, but hardcode the bits for each
SoC it knows of.

For drivers that are essentially just wrappers around sysconf,
I would make them one driver per SoC and use a low-level interface
but still hardcode the offsets in the driver instead of using DT
to find the registers.

The pinctrl and reset drivers are examples of this.

> In general the requirements of the sysconf support to the SOC/driver
> support is.
> 1> It should be able to read/write a sysconf register bits without
> having to "if" each SOC in the code. So that code is totally abstracted.
> Which is currently achieved by passing the information from the device
> trees and the driver just uses the property to get it.

The goal sounds fine, just the method is a bit more complex than necessary
here I think.

> 2> The infrastructure should protect the claimed registers from
> over-writing by other drivers. We do this by claim-read/write-release
> style API.

I don't understand this part. Is it about atomicity of accesses to
32-bit registers when you only want to change a bit? That is something
the regmap interface handles already.

If this is about drivers touching registers they should not touch
in the first place, I think it should not be needed at all, because
that would be a driver bug, and you can't really protect yourself
from broken drivers anyway.

> 3> The driver should be able to set a group of sysconf registers bits to
> a particular values before initialises the IP. I was thinking of doing
> this in a same way as pinctrl state.

That does not fit well with the model we use for other subsystems. If possible,
try to use the existing abstractions for clock, regulator, pinctrl, reset,
etc. and call generic interfaces from the driver. When that does not work,
create a high-level function call from your sysconf driver to do a particular
thing (e.g. stih_sysconf_ethernet_set_phy_mode()) rather than set up random
bits from the driver.

	Arnd

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

* RE: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-08 14:34   ` [RFC 1/8] serial:st-asc: Add ST ASC driver Arnd Bergmann
                       ` (2 preceding siblings ...)
       [not found]     ` <20130508153459.GA17186@kroah.com>
@ 2013-05-20 11:49     ` Stephen GALLIMORE
  2013-05-22 15:13       ` Arnd Bergmann
  3 siblings, 1 reply; 64+ messages in thread
From: Stephen GALLIMORE @ 2013-05-20 11:49 UTC (permalink / raw)
  To: Arnd Bergmann, Srinivas KANDAGATLA; +Cc: linux-serial, linux-kernel

Hi Arnd,

We have pretty much completed reworking the patch set we sent recently, but
there is one comment you made which seemed to make perfect sense
but after investigating it has left me totally confused, which was:

>I would also recommed adding a way to set the default baud rate through
> a property. Following the example of the 8250 driver, you should probably
> call that "current-speed".

I note that you are listed as the author of of_serial.c so I was assuming
that looking at this would make sense, but it doesn't at all, and I would
be really grateful if you could explain what you were trying to achieve
and how you thought it worked. The code does:

        /* If current-speed was set, then try not to change it. */
        if (of_property_read_u32(np, "current-speed", &spd) == 0)
                port->custom_divisor = clk / (16 * spd);

The "spd" variable is not used again and I do not understand why you 
thought setting port->custom_divisor would have any impact on the default 
or current baud rate of the UART, or that this information was useful to 
any other part of the system. A search has only revealed that this port 
field has only one purpose, which is to provide a "custom" speed 
(unsurprisingly) when the user requests 38.4K _and_ the port flag 
UPF_SPD_CUST has been set through a TIOCSSERIAL ioctl call, instead of
actually getting 38.4K. The key part of that assessment being the 
implementation of uart_get_divisor() :

       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
                quot = port->custom_divisor;
        else
                quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);

Also all of the custom_divisor functionality is basically commented as "old" 
or has a kernel warning saying it is deprecated (see uart_set_info), so as
far as I can see for our (and I suspect most) hardware it is completely 
irrelevant functionality.

If you really wanted to specify a default rate for a TTY then surely you need 
to change the driver's init_termios, or change the termios on a per port basis 
after they get registered. Only a handful of drivers do not use the default 
uart_register_driver() and change the init_termios (statically) to something 
other than 9600 8N1. I have been unable so far to find any evidence of drivers 
changing the termios after a port has been registered based on either platform 
data or OF attributes. So I do not see why we would want to provide that 
functionality explicitly in the ASC driver if nobody else does; if you want 
to change the TTY speed, use the tty IOCTL interfaces (or stty).

So I don't see why you think the concept of a default or current speed belongs 
in the device tree description of the uart at all, unless there is something 
special about the hardware. One possible example of that seems to be the ARC
driver which only appears to support one serial speed and uses "current-speed"
attribute to specify that speed; or the ARC driver is broken and they have
made a mistake in their set_termios implementation, we cannot quite work out
which of those two things is true. But that isn't the case for the ASC
hardware so it again would not be relevant in this driver.

So basically we would like some help understanding what it is you would
really like us to do. Clearly we can just duplicate what you did in
of_serial.c for the 8250 and move on, but we would like to understand why
that wouldn't just be adding redundant code.

Regards,
-stephen


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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-17 14:36           ` Arnd Bergmann
@ 2013-05-20 12:48             ` Srinivas KANDAGATLA
  2013-05-23 21:44               ` Arnd Bergmann
  0 siblings, 1 reply; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-20 12:48 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: dong.aisheng, sameo, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

Hi Arnd,
Thankyou for the comments.

On 17/05/13 15:36, Arnd Bergmann wrote:
> On Thursday 09 May 2013, Srinivas KANDAGATLA wrote:
>> On 08/05/13 20:48, Arnd Bergmann wrote:
>> I agree, my initial approach was having a dedicated driver specific to
>> ST syscon, however syscon seems to do things very much similar to what
>> we want, so I have integrated those 3 functions in syscon.
>> Am happy to go back with my first approach of adding ST specific syscon
>> driver if no one is actually going to benefit with such a change to
>> syscon driver.
> 
> That would at least be less controversial.

yes I agree.
> 
>> Total layout of the sysconf changes per SOC, and the bit arrangements
>> aswell, however the core IP(pinctrl, etherenet ...) and logic to drive
>> those bits remains exactly same.
> 
> It sounds like you really need a driver with high-level interfaces
> for the bits that change by each core and are needed by otherwise
> identical drivers, like the Ethernet driver you mention.
> 
> I would not go as far as you did describing the individual bits in
> the device node using these however. That driver can be layered on
> top of the existing syscon driver, but hardcode the bits for each
> SoC it knows of.
Some of the drivers like Ethernet already provide higher level
interfaces via callbacks. We did implement such a callbacks per each SOC
in non-DT case, and ended up having code duplicated for each SOC.

On the other hand using device trees to describe the HW
configuration(sysconfs) made more sense and got rid of SOC specific
callbacks.

> 
> For drivers that are essentially just wrappers around sysconf,
> I would make them one driver per SoC and use a low-level interface
> but still hardcode the offsets in the driver instead of using DT
> to find the registers.
> 
> The pinctrl and reset drivers are examples of this.

In pinctrl bindings case, I think we could do better job by replacing
the existing bindings of sysconfs for a group of banks with just two
integer offsets. This would mean that, we can still use the a common
driver across the SOCs.

And w.r.t to reset, we are planning on using sysconf based
reset-controller API sitting underneath the reset-controller subsystem.
Passing the information from device trees would be much clear and
flexible than adding new driver per/SOC.

>> 2> The infrastructure should protect the claimed registers from
>> over-writing by other drivers. We do this by claim-read/write-release
>> style API.
> 
> I don't understand this part. Is it about atomicity of accesses to
> 32-bit registers when you only want to change a bit? That is something
> the regmap interface handles already.

I forget to mention a important point here, the protection is at bit
level for the sysconfs. Some of sysconfs have bits shared across IPs, so
protecting them while the IP is still using it is what we are trying to
achieve with sysconf-claim/release apis.
While it may be overkill, but In past it has found bugs and been helpful
with a meaning full debug output.

>> 3> The driver should be able to set a group of sysconf registers bits to
>> a particular values before initialises the IP. I was thinking of doing
>> this in a same way as pinctrl state.
> 
> That does not fit well with the model we use for other subsystems. If possible,
> try to use the existing abstractions for clock, regulator, pinctrl, reset,
> etc. and call generic interfaces from the driver. When that does not work,
> create a high-level function call from your sysconf driver to do a particular
> thing (e.g. stih_sysconf_ethernet_set_phy_mode()) rather than set up random
> bits from the driver.
I agree going for a higher level api in this case makes sense.

Thanks,
srini

> 
> 	Arnd
> 
> 


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

* Re: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-20 11:49     ` Stephen GALLIMORE
@ 2013-05-22 15:13       ` Arnd Bergmann
  2013-05-23 16:26         ` Stephen GALLIMORE
  0 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-22 15:13 UTC (permalink / raw)
  To: Stephen GALLIMORE; +Cc: Srinivas KANDAGATLA, linux-serial, linux-kernel

On Monday 20 May 2013, Stephen GALLIMORE wrote:
> We have pretty much completed reworking the patch set we sent recently, but
> there is one comment you made which seemed to make perfect sense
> but after investigating it has left me totally confused, which was:
> 
> >I would also recommed adding a way to set the default baud rate through
> > a property. Following the example of the 8250 driver, you should probably
> > call that "current-speed".
> 
> I note that you are listed as the author of of_serial.c so I was assuming
> that looking at this would make sense, but it doesn't at all, and I would
> be really grateful if you could explain what you were trying to achieve
> and how you thought it worked. The code does:
> 
>         /* If current-speed was set, then try not to change it. */
>         if (of_property_read_u32(np, "current-speed", &spd) == 0)
>                 port->custom_divisor = clk / (16 * spd);
> 
> The "spd" variable is not used again and I do not understand why you 
> thought setting port->custom_divisor would have any impact on the default 
> or current baud rate of the UART, or that this information was useful to 
> any other part of the system. A search has only revealed that this port 
> field has only one purpose, which is to provide a "custom" speed 
> (unsurprisingly) when the user requests 38.4K and the port flag 
> UPF_SPD_CUST has been set through a TIOCSSERIAL ioctl call, instead of
> actually getting 38.4K. The key part of that assessment being the 
> implementation of uart_get_divisor() :
> 
>        if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
>                 quot = port->custom_divisor;
>         else
>                 quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
> 
> Also all of the custom_divisor functionality is basically commented as "old" 
> or has a kernel warning saying it is deprecated (see uart_set_info), so as
> far as I can see for our (and I suspect most) hardware it is completely 
> irrelevant functionality.

What may have happened here is that custom_divisor was used in a different
way when I added that code than it is today, and the change was not propagated
into the of_serial driver. However, going back to 2.6.20 shows no different
code than what we have today in this regard. It may simply have been a mistake
on my side.

> So I don't see why you think the concept of a default or current speed belongs 
> in the device tree description of the uart at all, unless there is something 
> special about the hardware.

I looked it up in the original serial port binding at
http://www.openfirmware.org/1275/bindings/devices/html/serial.html, which does
not specify the property, and in ePAPR, which does have it in the section about
"serial class devices":

18 6.2.1.2 current-speed
19 Property: current-speed
20 Value type: <u32>
21 Description:
22 Specifies the current speed of a serial device in bits per second. A boot program should set
23 this property if it has initialized the serial device.
24 Example:
25 current - speed = <115200>; # 115200 baud

The reason you want this is so that the driver can initialize the hardware from
scratch more easily and get back to the same settings. Why they only specified
the baud rate but not also start/stop bits and flow control I don't understand
though.

I guess you can ignore my original comment.

	Arnd

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

* RE: [RFC 1/8] serial:st-asc: Add ST ASC driver.
  2013-05-22 15:13       ` Arnd Bergmann
@ 2013-05-23 16:26         ` Stephen GALLIMORE
  0 siblings, 0 replies; 64+ messages in thread
From: Stephen GALLIMORE @ 2013-05-23 16:26 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: Srinivas KANDAGATLA, linux-kernel, linux-serial


On Wednesday 22 May 2013, Arnd Bergmann wrote:
> > Also all of the custom_divisor functionality is basically commented as "old"
> > or has a kernel warning saying it is deprecated (see uart_set_info), so as
> > far as I can see for our (and I suspect most) hardware it is completely
> > irrelevant functionality.
> 
> What may have happened here is that custom_divisor was used in a different
> way when I added that code than it is today, and the change was not propagated
> into the of_serial driver. However, going back to 2.6.20 shows no different
> code than what we have today in this regard. It may simply have been
> a mistake on my side.

Thanks for looking into this and digging around in the history. At least I didn't
miss something really obvious.

> I looked it up in the original serial port binding at
> http://www.openfirmware.org/1275/bindings/devices/html/serial.ht
> ml, which does
> not specify the property, and in ePAPR, which does have it in the
> section about
> "serial class devices":
> 
> 18 6.2.1.2 current-speed
> 19 Property: current-speed
> 20 Value type: <u32>
> 21 Description:
> 22 Specifies the current speed of a serial device in bits per second. A
> boot program should set
> 23 this property if it has initialized the serial device.
> 24 Example:
> 25 current - speed = <115200>; # 115200 baud
> 
> The reason you want this is so that the driver can initialize the hardware from
> scratch more easily and get back to the same settings. Why they only specified
> the baud rate but not also start/stop bits and flow control I don't understand
> though.

Yes, I had been made aware of the ePAPR definition by Srini after I sent the post.
In fact I had exactly the same question in my head about the other settings as
well.  

> 
> I guess you can ignore my original comment.
> 
OK.

Thanks again for your time.

Regards,
-stephen

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-20 12:48             ` Srinivas KANDAGATLA
@ 2013-05-23 21:44               ` Arnd Bergmann
  2013-05-24 16:06                 ` Srinivas KANDAGATLA
  0 siblings, 1 reply; 64+ messages in thread
From: Arnd Bergmann @ 2013-05-23 21:44 UTC (permalink / raw)
  To: srinivas.kandagatla
  Cc: dong.aisheng, sameo, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial

On Monday 20 May 2013, Srinivas KANDAGATLA wrote:
> On 17/05/13 15:36, Arnd Bergmann wrote:
>
> Some of the drivers like Ethernet already provide higher level
> interfaces via callbacks. We did implement such a callbacks per each SOC
> in non-DT case, and ended up having code duplicated for each SOC.
> 
> On the other hand using device trees to describe the HW
> configuration(sysconfs) made more sense and got rid of SOC specific
> callbacks.

I'm sure it's possible to reduce the duplication without going all
the way to describing every bit in DT.

> > For drivers that are essentially just wrappers around sysconf,
> > I would make them one driver per SoC and use a low-level interface
> > but still hardcode the offsets in the driver instead of using DT
> > to find the registers.
> > 
> > The pinctrl and reset drivers are examples of this.
> 
> In pinctrl bindings case, I think we could do better job by replacing
> the existing bindings of sysconfs for a group of banks with just two
> integer offsets. This would mean that, we can still use the a common
> driver across the SOCs.
>
> And w.r.t to reset, we are planning on using sysconf based
> reset-controller API sitting underneath the reset-controller subsystem.
> Passing the information from device trees would be much clear and
> flexible than adding new driver per/SOC.

Ok

> >> 2> The infrastructure should protect the claimed registers from
> >> over-writing by other drivers. We do this by claim-read/write-release
> >> style API.
> > 
> > I don't understand this part. Is it about atomicity of accesses to
> > 32-bit registers when you only want to change a bit? That is something
> > the regmap interface handles already.
> 
> I forget to mention a important point here, the protection is at bit
> level for the sysconfs. Some of sysconfs have bits shared across IPs, so
> protecting them while the IP is still using it is what we are trying to
> achieve with sysconf-claim/release apis.
> While it may be overkill, but In past it has found bugs and been helpful
> with a meaning full debug output.

Can you give an example of something that is shared across multiple IPs?

Are those always done in the way that you have e.g. the ethernet pinctrl
in the same register as the usb pinctrl, or could you have an ethernet
pinctrl setting mixed together with the usb clock setting for instance?

If the hardware has been designed in a sensible way rather than just
grown by randomly adding bits in open spaces, I would assume that it's
possible to have high-level interfaces built around ranges of registers
rather than arbitrary subsets of registers.

	Arnd

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

* Re: [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs
  2013-05-23 21:44               ` Arnd Bergmann
@ 2013-05-24 16:06                 ` Srinivas KANDAGATLA
  0 siblings, 0 replies; 64+ messages in thread
From: Srinivas KANDAGATLA @ 2013-05-24 16:06 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: dong.aisheng, sameo, Rob Landley, Grant Likely, Rob Herring,
	Russell King, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Stuart Menefy, Shawn Guo, Olof Johansson, Jason Cooper,
	Stephen Warren, Maxime Ripard, Nicolas Pitre, Will Deacon,
	Dave Martin, Marc Zyngier, Viresh Kumar, Mark Brown, linux-doc,
	linux-kernel, devicetree-discuss, linux-arm-kernel, linux-serial,
	Stephen GALLIMORE

On 23/05/13 22:44, Arnd Bergmann wrote:
Thankyou Arnd for extending this discussion.
> On Monday 20 May 2013, Srinivas KANDAGATLA wrote:
>> On 17/05/13 15:36, Arnd Bergmann wrote:
>>
>> On the other hand using device trees to describe the HW
>> configuration(sysconfs) made more sense and got rid of SOC specific
>> callbacks.
> 
> I'm sure it's possible to reduce the duplication without going all
> the way to describing every bit in DT.

Yes, I agree with you. I think just passing the offset information from
DT would enough in cases like Ethernet or USB where the sysconf
registers tend to be mostly standard. And the generic higher level
function should be able to do the rest.

>> I forget to mention a important point here, the protection is at bit
>> level for the sysconfs. Some of sysconfs have bits shared across IPs, so
>> protecting them while the IP is still using it is what we are trying to
>> achieve with sysconf-claim/release apis.
>> While it may be overkill, but In past it has found bugs and been helpful
>> with a meaning full debug output.
> 
> Can you give an example of something that is shared across multiple IPs?
> 
> Are those always done in the way that you have e.g. the ethernet pinctrl
> in the same register as the usb pinctrl, or could you have an ethernet
> pinctrl setting mixed together with the usb clock setting for instance?
> 
> If the hardware has been designed in a sensible way rather than just
> grown by randomly adding bits in open spaces, I would assume that it's
> possible to have high-level interfaces built around ranges of registers
> rather than arbitrary subsets of registers.

We have decided to go with using higher level functions as you
suggested, hopefully based on regmap with some helper functions on top
of it.

System configuration registers in the past used to very much shared
across IPs, However with the new chips they seems be mostly dedicated
registers for specific IP configurations.
As we have no plans to support very old chips, So I think I can move
this out bit level information from device tree and add a higher level
functions to be accessed by the drivers.

As an example the below sysconf register for a STi7105 chip(Very old
SOC) looks like:
SYSTEM_CONFIG7 Comms/Ethernet config control register

[31:28] RESERVED
[27] ENMII:
	1: MII mode 0: Reverse MII mode
[26:25] PHY_INTF_SELECT: Selects the type of Ethernet mode
	00: MII mode (Default)
	01: Reserved
	1x: Reserved
[23] GLOBAL_POWER_DOWN:
	1: Activate low power
[24] RESERVED
	0: Normal mode
[22] DAA_CONFIG_CTRL: DAA configuration control
[21] RESERVED
[20] MAC_SPEED_SEL:
	1: Indicates that the MAC is running at 100 Mbps speed
	0: Indicates that the MAC is running at 10 Mbps speed
[19] RESERVED
[18] RMII_MODE:
	1: RMII interface activated
	0: MII interface activated
[17] MIIM_DIO_SELECT:
	1: MIIM_DIO from external input, else from GMAC
	0: All MII pads in input mode
[16] ETHERNET_INTERFACE_ON:
	1: Ethernet on (pads enables controlled by MAC)
[15:13] RESERVED
[12] DAA_SERIAL_MODE: DAA serial interface mode select pin

[11] SC1_COND_VCC_ENABLE: Enables control of smart card VCC upon
bit in the PDES.
[10] SC_DETECT_VPP_POL:
	1: Output pin SC_NOT_SETVPP is inverted of PDES_SC_SETVPP
	0: Output pin SC_NOT_SETVPP is PDES_SC_SETVPP
[9] IRB_DATA_OUT_POL_OD: Selection of polarity of IRB output signal
routed as alternate function

...
...
Thanks,
srini

> 
> 	Arnd
> 
> 


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

end of thread, other threads:[~2013-05-24 16:15 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1368022187-1633-1-git-send-email-srinivas.kandagatla@st.com>
2013-05-08 14:11 ` [RFC 2/8] ARM:global_timer: Add ARM global timer support Srinivas KANDAGATLA
2013-05-08 14:26   ` Rob Herring
2013-05-08 15:06     ` Stuart MENEFY
2013-05-08 14:38   ` Arnd Bergmann
2013-05-08 14:51     ` Steffen Trumtrar
2013-05-09 14:07     ` Srinivas KANDAGATLA
2013-05-09 14:51       ` Arnd Bergmann
2013-05-09 14:51         ` Srinivas KANDAGATLA
2013-05-08 14:11 ` [RFC 3/8] mfd:syscon: Introduce claim/read/write/release APIs Srinivas KANDAGATLA
2013-05-08 14:50   ` Arnd Bergmann
2013-05-08 15:01     ` Mark Brown
2013-05-08 17:42       ` Srinivas KANDAGATLA
2013-05-09  9:51         ` Mark Brown
2013-05-09 11:58           ` Srinivas KANDAGATLA
2013-05-09 13:26             ` Mark Brown
2013-05-09 14:00               ` Srinivas KANDAGATLA
2013-05-09 14:40                 ` Mark Brown
2013-05-09 14:47                   ` Srinivas KANDAGATLA
2013-05-10 12:51           ` Srinivas KANDAGATLA
2013-05-08 17:32     ` Srinivas KANDAGATLA
2013-05-08 19:48       ` Arnd Bergmann
2013-05-09 10:17         ` Srinivas KANDAGATLA
2013-05-17 14:36           ` Arnd Bergmann
2013-05-20 12:48             ` Srinivas KANDAGATLA
2013-05-23 21:44               ` Arnd Bergmann
2013-05-24 16:06                 ` Srinivas KANDAGATLA
2013-05-08 14:11 ` =?y?q?=5BRFC=205/8=5D=20ARM=3Astih41x=3A=20Add=20STiH415=20SOC=20support?= Srinivas KANDAGATLA
2013-05-08 16:18   ` [RFC 5/8] ARM:stih41x: Add STiH415 SOC support Arnd Bergmann
2013-05-08 16:21     ` Jean-Christophe PLAGNIOL-VILLARD
2013-05-08 16:50     ` Stephen GALLIMORE
2013-05-08 18:55       ` Arnd Bergmann
2013-05-09 11:09         ` Stephen GALLIMORE
2013-05-08 17:03     ` Srinivas KANDAGATLA
2013-05-08 14:11 ` [RFC 6/8] ARM:stih41x: Add STiH416 " Srinivas KANDAGATLA
2013-05-08 14:12 ` [RFC 7/8] ARM:stih41x: Add B2000 board support Srinivas KANDAGATLA
2013-05-08 16:20   ` Arnd Bergmann
2013-05-08 16:24     ` Jean-Christophe PLAGNIOL-VILLARD
2013-05-08 17:04     ` Srinivas KANDAGATLA
2013-05-08 14:12 ` [RFC 8/8] ARM:stih41x: Add B2020 " Srinivas KANDAGATLA
     [not found] ` <1368022248-2153-1-git-send-email-srinivas.kandagatla@st.com>
2013-05-08 14:34   ` [RFC 1/8] serial:st-asc: Add ST ASC driver Arnd Bergmann
2013-05-08 14:39     ` Jean-Christophe PLAGNIOL-VILLARD
2013-05-08 18:18       ` Srinivas KANDAGATLA
2013-05-08 19:55         ` Arnd Bergmann
2013-05-08 18:02     ` Srinivas KANDAGATLA
     [not found]     ` <20130508153459.GA17186@kroah.com>
2013-05-08 15:40       ` Jean-Christophe PLAGNIOL-VILLARD
2013-05-08 15:53         ` Greg KH
2013-05-08 16:03           ` Jean-Christophe PLAGNIOL-VILLARD
2013-05-08 16:15             ` Greg KH
2013-05-08 16:31               ` Arnd Bergmann
2013-05-08 16:36                 ` Greg KH
2013-05-10 23:29                   ` Russell King - ARM Linux
2013-05-08 16:39                 ` Jean-Christophe PLAGNIOL-VILLARD
2013-05-08 16:45                 ` Nicolas Pitre
2013-05-08 18:35                   ` Arnd Bergmann
2013-05-09 13:36                     ` Jean-Christophe PLAGNIOL-VILLARD
2013-05-08 16:10       ` Stephen GALLIMORE
2013-05-10 13:50       ` Stephen GALLIMORE
2013-05-10 14:08         ` Greg KH
2013-05-20 11:49     ` Stephen GALLIMORE
2013-05-22 15:13       ` Arnd Bergmann
2013-05-23 16:26         ` Stephen GALLIMORE
     [not found] ` <1368022284-2283-1-git-send-email-srinivas.kandagatla@st.com>
2013-05-08 15:06   ` [RFC 4/8] pinctrl:stixxxx: Add pinctrl and pinconf support Jean-Christophe PLAGNIOL-VILLARD
2013-05-08 16:27     ` Srinivas KANDAGATLA
2013-05-08 16:38       ` Jean-Christophe PLAGNIOL-VILLARD

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