Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 17 Feb 2010 23:14:41 GMT
From:      Rafal Jaworowski <raj@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 174803 for review
Message-ID:  <201002172314.o1HNEfAI092400@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=174803

Change 174803 by raj@raj_fdt on 2010/02/17 23:13:41

	Convert GPIO init to device tree conventions.
	
	The initialization of statically assigned GPIO lines needs to happen
	as early as possible, because certain peripheral device connections
	could be routed via GPIO pins, and these pins need to be configured
	prior to any usage by their consumers.
	
	The new rework lets the GPIO code traverse device tree, discover GPIO
	usage by peripherals nodes and set the pins accordingly.
	
	This also adjusts MPP pin count prop naming, so it's uniform accross
	MPP and GPIO nodes.

Affected files ...

.. //depot/projects/fdt/sys/arm/mv/gpio.c#3 edit
.. //depot/projects/fdt/sys/arm/mv/kirkwood/db88f6xxx.c#3 edit
.. //depot/projects/fdt/sys/arm/mv/mv_machdep.c#8 edit
.. //depot/projects/fdt/sys/arm/mv/mvreg.h#2 edit
.. //depot/projects/fdt/sys/arm/mv/mvvar.h#5 edit
.. //depot/projects/fdt/sys/boot/fdt/dts/bindings-mpp.txt#2 edit

Differences ...

==== //depot/projects/fdt/sys/arm/mv/gpio.c#3 (text+ko) ====

@@ -44,8 +44,10 @@
 #include <sys/queue.h>
 #include <sys/timetc.h>
 #include <machine/bus.h>
+#include <machine/fdt.h>
 #include <machine/intr.h>
 
+#include <dev/fdt/fdt_common.h>
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
@@ -105,6 +107,21 @@
 
 DRIVER_MODULE(gpio, simplebus, mv_gpio_driver, mv_gpio_devclass, 0, 0);
 
+typedef int (*gpios_phandler_t)(phandle_t, pcell_t *, int);
+
+struct gpio_ctrl_entry {
+	const char		*compat;
+	gpios_phandler_t	handler;
+};
+
+int mv_handle_gpios_prop(phandle_t ctrl, pcell_t *gpios, int len);
+int gpio_get_config_from_dt(void);
+
+struct gpio_ctrl_entry gpio_controllers[] = {
+	{ "mrvl,gpio", &mv_handle_gpios_prop },
+	{ NULL, NULL }
+};
+
 static int
 mv_gpio_probe(device_t dev)
 {
@@ -125,8 +142,9 @@
 
 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
 
-	if (mv_gpio_softc != NULL)
+	if (sc == NULL)
 		return (ENXIO);
+
 	mv_gpio_softc = sc;
 
 	/* Get chip id and revision */
@@ -184,18 +202,9 @@
 		}
 	}
 
-	/* Setup GPIO lines */
-	for (i = 0; mv_gpio_config[i].gc_gpio >= 0; i++) {
-		mv_gpio_configure(mv_gpio_config[i].gc_gpio,
-		    mv_gpio_config[i].gc_flags, ~0u);
-
-		if (mv_gpio_config[i].gc_output < 0)
-			mv_gpio_out_en(mv_gpio_config[i].gc_gpio, 0);
-		else
-			mv_gpio_out(mv_gpio_config[i].gc_gpio,
-			    mv_gpio_config[i].gc_output, 1);
-	}
-
+	/*
+	 * GPIO lines setup is already done at this stage (see mv_machdep.c).
+	 */
 	return (0);
 }
 
@@ -274,7 +283,7 @@
 	if (pin >= mv_gpio_softc->pin_num)
 		return;
 
-	if (gpio_setup[pin] & MV_GPIO_EDGE)
+	if (gpio_setup[pin] & MV_GPIO_IN_IRQ_EDGE)
 		mv_gpio_edge(pin, 0);
 	else
 		mv_gpio_level(pin, 0);
@@ -287,7 +296,7 @@
 	if (pin >= mv_gpio_softc->pin_num)
 		return;
 
-	if (gpio_setup[pin] & MV_GPIO_EDGE)
+	if (gpio_setup[pin] & MV_GPIO_IN_IRQ_EDGE)
 		mv_gpio_edge(pin, 1);
 	else
 		mv_gpio_level(pin, 1);
@@ -305,24 +314,23 @@
 	intr_event_handle(event, NULL);
 }
 
-int
-mv_gpio_configure(uint32_t pin, uint32_t flags, uint32_t mask)
+static int
+mv_gpio_configure(uint32_t pin, uint32_t flags)
 {
 
 	if (pin >= mv_gpio_softc->pin_num)
 		return (EINVAL);
 
-	if (mask & MV_GPIO_BLINK)
-		mv_gpio_blink(pin, flags & MV_GPIO_BLINK);
-	if (mask & MV_GPIO_POLAR_LOW)
-		mv_gpio_polarity(pin, flags & MV_GPIO_POLAR_LOW);
-	if (mask & MV_GPIO_EDGE)
-		mv_gpio_edge(pin, flags & MV_GPIO_EDGE);
-	if (mask & MV_GPIO_LEVEL)
-		mv_gpio_level(pin, flags & MV_GPIO_LEVEL);
+	if (flags & MV_GPIO_OUT_BLINK)
+		mv_gpio_blink(pin, 1);
+	if (flags & MV_GPIO_IN_POL_LOW)
+		mv_gpio_polarity(pin, 1);
+	if (flags & MV_GPIO_IN_IRQ_EDGE)
+		mv_gpio_edge(pin, 1);
+	if (flags & MV_GPIO_IN_IRQ_LEVEL)
+		mv_gpio_level(pin, 1);
 
-	gpio_setup[pin] &= ~(mask);
-	gpio_setup[pin] |= (flags & mask);
+	gpio_setup[pin] = flags;
 
 	return (0);
 }
@@ -533,3 +541,142 @@
 	else
 		mv_gpio_reg_clear(reg, pin);
 }
+
+int
+mv_handle_gpios_prop(phandle_t ctrl, pcell_t *gpios, int len)
+{
+	pcell_t gpio_cells, pincnt;
+	int inc, t, tuples, tuple_size;
+	int dir, flags, pin;
+	u_long gpio_ctrl, size;
+	struct mv_gpio_softc sc;
+
+	pincnt = 0;
+	if (OF_getproplen(ctrl, "gpio-controller") <= 0)
+		/* Node is not a GPIO controller. */
+		return (ENXIO);
+
+	if (OF_getprop(ctrl, "#gpio-cells", &gpio_cells, sizeof(pcell_t)) < 0)
+		return (ENXIO);
+
+	gpio_cells = fdt32_to_cpu(gpio_cells);
+	if (gpio_cells != 3)
+		return (ENXIO);
+
+	tuple_size = gpio_cells * sizeof(pcell_t) + sizeof(phandle_t);
+	tuples = len / tuple_size;
+
+	if (fdt_get_regsize(ctrl, &gpio_ctrl, &size))
+		return (ENXIO);
+	/*
+	 * Since to set up GPIO we use the same functions as GPIO driver, and
+	 * mv_gpio_softc is NULL at this early stage, we need to create a fake
+	 * softc and set mv_gpio_softc pointer to that newly created object.
+	 * After successful GPIO setup, the [shared] pointer will be set back
+	 * to NULL.
+	 */
+	mv_gpio_softc = &sc;
+
+	sc.bst = fdtbus_bs_tag;
+	gpio_ctrl += FDT_IMMR_VA;
+
+	if (bus_space_map(sc.bst, gpio_ctrl, size, 0, &sc.bsh) != 0)
+		return (ENXIO);
+
+	if (OF_getprop(ctrl, "pin-count", &pincnt, sizeof(pcell_t)) < 0)
+		return (ENXIO);
+	sc.pin_num = fdt32_to_cpu(pincnt);
+
+	/*
+	 * Skip controller reference, since contoller's phandle is given
+	 * explicitly (in a function argument).
+	 */
+	inc = sizeof(ihandle_t) / sizeof(pcell_t);
+	gpios += inc;
+
+	for (t = 0; t < tuples; t++) {
+		pin = fdt32_to_cpu(gpios[0]);
+		dir = fdt32_to_cpu(gpios[1]);
+		flags = fdt32_to_cpu(gpios[2]);
+
+		mv_gpio_configure(pin, flags);
+
+		if (dir == 1)
+			/* Input. */
+			mv_gpio_out_en(pin, 0);
+		else {
+			/* Output. */
+			if (flags & MV_GPIO_OUT_OPEN_DRAIN)
+				mv_gpio_out(pin, 0, 1);
+
+			if (flags & MV_GPIO_OUT_OPEN_SRC)
+				mv_gpio_out(pin, 1, 1);
+		}
+		gpios += gpio_cells + inc;
+	}
+
+	/* Reset pointer. */
+	mv_gpio_softc = NULL;
+	return (0);
+}
+
+#define MAX_PINS_PER_NODE	5
+#define GPIOS_PROP_CELLS	4
+int
+platform_gpio_init(void)
+{
+	phandle_t child, parent, root, ctrl;
+	ihandle_t ctrl_ihandle;
+	pcell_t gpios[MAX_PINS_PER_NODE * GPIOS_PROP_CELLS];
+	struct gpio_ctrl_entry *e;
+	int len, rv;
+
+	root = OF_finddevice("/");
+	len = 0;
+	parent = root;
+
+	/* Traverse through entire tree to find nodes with 'gpios' prop */
+	for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
+
+		/* Find a 'leaf'. Start the search from this node. */
+		while (OF_child(child)) {
+			parent = child;
+			child = OF_child(child);
+		}
+		if ((len = OF_getproplen(child, "gpios")) > 0) {
+
+			if (len > sizeof(gpios))
+				return (ENXIO);
+
+			/* Get 'gpios' property. */
+			OF_getprop(child, "gpios", &gpios, len);
+
+			e = (struct gpio_ctrl_entry *)&gpio_controllers;
+
+			/* Find and call a handler. */
+			for (; e->compat; e++) {
+				/*
+				 * First cell of 'gpios' property should
+				 * contain a ref. to a node defining GPIO
+				 * controller.
+				 */
+				ctrl_ihandle = (ihandle_t)gpios[0];
+				ctrl_ihandle = fdt32_to_cpu(ctrl_ihandle);
+				ctrl = OF_instance_to_package(ctrl_ihandle);
+
+				if (fdt_is_compatible(ctrl, e->compat))
+					/* Call a handler. */
+					if ((rv = e->handler(ctrl,
+					    (pcell_t *)&gpios, len)))
+						return (rv);
+			}
+		}
+
+		if (OF_peer(child) == 0) {
+			/* No more siblings. */
+			child = parent;
+			parent = OF_parent(child);
+		}
+	}
+	return (0);
+}

==== //depot/projects/fdt/sys/arm/mv/kirkwood/db88f6xxx.c#3 (text+ko) ====

@@ -98,10 +98,6 @@
 	{ 0, 0, 0, 0, 0, }
 };
 
-const struct gpio_config mv_gpio_config[] = {
-	{ -1, -1, -1 }
-};
-
 static void
 platform_identify(void *dummy)
 {

==== //depot/projects/fdt/sys/arm/mv/mv_machdep.c#8 (text+ko) ====

@@ -575,6 +575,12 @@
 	if (platform_mpp_init() != 0)
 		while (1);
 
+	/*
+	 * Initialize GPIO as early as possible.
+	 */
+	if (platform_gpio_init() != 0)
+		while (1);
+
 	cninit();
 	physmem = memsize / PAGE_SIZE;
 
@@ -678,7 +684,7 @@
 	pcell_t reg[4];
 	u_long start, size;
 	phandle_t node;
-	pcell_t pin_cells, *pinmap_ptr, pin_max;
+	pcell_t pin_cells, *pinmap_ptr, pin_count;
 	ssize_t len;
 	int par_addr_cells, par_size_cells;
 	int tuple_size, tuples, rv, pins, i, j;
@@ -732,12 +738,12 @@
 	start += FDT_IMMR_VA;
 
 	/*
-	 * Process 'pin-max' and 'pin-map' props.
+	 * Process 'pin-count' and 'pin-map' props.
 	 */
-	if (OF_getprop(node, "pin-max", &pin_max, sizeof(pin_max)) <= 0)
+	if (OF_getprop(node, "pin-count", &pin_count, sizeof(pin_count)) <= 0)
 		return (ENXIO);
-	pin_max = fdt32_to_cpu(pin_max);
-	if (pin_max > MPP_PIN_MAX)
+	pin_count = fdt32_to_cpu(pin_count);
+	if (pin_count > MPP_PIN_MAX)
 		return (ERANGE);
 
 	if (OF_getprop(node, "#pin-cells", &pin_cells, sizeof(pin_cells)) <= 0)
@@ -754,7 +760,7 @@
 	if (len % tuple_size)
 		return (ERANGE);
 	pins = len / tuple_size;
-	if (pins > pin_max)
+	if (pins > pin_count)
 		return (ERANGE);
 	/*
 	 * Fill out a "mpp[pin] => function" table. All pins unspecified in
@@ -773,16 +779,17 @@
 	 * Prepare and program MPP control register values.
 	 */
 	ctrl_offset = 0;
-	for (i = 0; i < pin_max;) {
+	for (i = 0; i < pin_count;) {
 		ctrl_val = 0;
 
 		for (j = 0; j < MPP_PINS_PER_REG; j++) {
-			if (i + j == pin_max - 1)
+			if (i + j == pin_count - 1)
 				break;
 			ctrl_val |= MPP_SEL(i + j, mpp[i + j]);
 		}
 		i += MPP_PINS_PER_REG;
-		bus_space_write_4(obio_tag, start, ctrl_offset, ctrl_val);
+		bus_space_write_4(fdtbus_bs_tag, start, ctrl_offset,
+		    ctrl_val);
 
 		/*
 		 * XXX this needs to be worked around for Orion, where MPP

==== //depot/projects/fdt/sys/arm/mv/mvreg.h#2 (text+ko) ====

@@ -378,10 +378,14 @@
 #define GPIO(n)			(1 << (n))
 #define MV_GPIO_MAX_NPINS	64
 
-#define MV_GPIO_BLINK		0x1
-#define MV_GPIO_POLAR_LOW	0x2
-#define MV_GPIO_EDGE		0x4
-#define MV_GPIO_LEVEL		0x8
+#define MV_GPIO_IN_NONE		0x0
+#define MV_GPIO_IN_POL_LOW	(1 << 16)
+#define MV_GPIO_IN_IRQ_EDGE	(2 << 16)
+#define MV_GPIO_IN_IRQ_LEVEL	(4 << 16)
+#define MV_GPIO_OUT_NONE	0x0
+#define MV_GPIO_OUT_BLINK	0x1
+#define MV_GPIO_OUT_OPEN_DRAIN	0x2
+#define MV_GPIO_OUT_OPEN_SRC	0x4
 
 #define IS_GPIO_IRQ(irq)	((irq) >= NIRQ && (irq) < NIRQ + MV_GPIO_MAX_NPINS)
 #define GPIO2IRQ(gpio)		((gpio) + NIRQ)

==== //depot/projects/fdt/sys/arm/mv/mvvar.h#5 (text+ko) ====

@@ -112,9 +112,9 @@
     void (*hand)(void *), void *arg, int pin, int flags, void **cookiep);
 void mv_gpio_intr_mask(int pin);
 void mv_gpio_intr_unmask(int pin);
-int mv_gpio_configure(uint32_t pin, uint32_t flags, uint32_t mask);
 void mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable);
 uint8_t mv_gpio_in(uint32_t pin);
+int platform_gpio_init(void);
 
 int soc_decode_win(void);
 void soc_id(uint32_t *dev, uint32_t *rev);

==== //depot/projects/fdt/sys/boot/fdt/dts/bindings-mpp.txt#2 (text+ko) ====

@@ -13,7 +13,7 @@
     User Manual. Each pin can have many possible functions depending on the
     MPP unit incarnation.
 
-- pin-max : number of the physical MPP connections on the SOC (depending on
+- pin-count: number of the physical MPP connections on the SOC (depending on
   the model it can be 24-50, or possibly else in future devices).
 
 Example:
@@ -22,7 +22,7 @@
 		#pin-cells = <2>;
 		compatible = "mrvl,mpp";
 		reg = <0x10000 0x34>;
-		pin-max = <50>;
+		pin-count= <50>;
 		pin-map = <
 			0  1		/* MPP[0]:  NF_IO[2] */
 			1  1		/* MPP[1]:  NF_IO[3] */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002172314.o1HNEfAI092400>