Module Name:    src
Committed By:   jmcneill
Date:           Sun Jul  2 15:27:58 UTC 2017

Modified Files:
        src/sys/dev/fdt: fdt_pinctrl.c fdt_subr.c fdtvar.h

Log Message:
Fix the pinctrl api to match the spec. A pinctrl config can have more
than one xref, and an xref may have specifier data associated with it.


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/fdt/fdt_pinctrl.c
cvs rdiff -u -r1.14 -r1.15 src/sys/dev/fdt/fdt_subr.c
cvs rdiff -u -r1.22 -r1.23 src/sys/dev/fdt/fdtvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/fdt/fdt_pinctrl.c
diff -u src/sys/dev/fdt/fdt_pinctrl.c:1.3 src/sys/dev/fdt/fdt_pinctrl.c:1.4
--- src/sys/dev/fdt/fdt_pinctrl.c:1.3	Tue Oct 11 13:04:57 2016
+++ src/sys/dev/fdt/fdt_pinctrl.c	Sun Jul  2 15:27:58 2017
@@ -1,6 +1,7 @@
-/* $NetBSD: fdt_pinctrl.c,v 1.3 2016/10/11 13:04:57 maxv Exp $ */
+/* $NetBSD: fdt_pinctrl.c,v 1.4 2017/07/02 15:27:58 jmcneill Exp $ */
 
 /*-
+ * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca>
  * Copyright (c) 2015 Martin Fouts
  * All rights reserved.
  *
@@ -27,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fdt_pinctrl.c,v 1.3 2016/10/11 13:04:57 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fdt_pinctrl.c,v 1.4 2017/07/02 15:27:58 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -37,8 +38,8 @@ __KERNEL_RCSID(0, "$NetBSD: fdt_pinctrl.
 #include <dev/fdt/fdtvar.h>
 
 struct fdtbus_pinctrl_controller {
+	device_t pc_dev;
 	int pc_phandle;
-	void *pc_cookie;
 	const struct fdtbus_pinctrl_controller_func *pc_funcs;
 
 	struct fdtbus_pinctrl_controller *pc_next;
@@ -47,13 +48,13 @@ struct fdtbus_pinctrl_controller {
 static struct fdtbus_pinctrl_controller *fdtbus_pc = NULL;
 
 int
-fdtbus_register_pinctrl_config(void *cookie, int phandle,
+fdtbus_register_pinctrl_config(device_t dev, int phandle,
     const struct fdtbus_pinctrl_controller_func *funcs)
 {
 	struct fdtbus_pinctrl_controller *pc;
 
 	pc = kmem_alloc(sizeof(*pc), KM_SLEEP);
-	pc->pc_cookie = cookie;
+	pc->pc_dev = dev;
 	pc->pc_phandle = phandle;
 	pc->pc_funcs = funcs;
 
@@ -78,57 +79,88 @@ fdtbus_pinctrl_lookup(int phandle)
 int
 fdtbus_pinctrl_set_config_index(int phandle, u_int index)
 {
-	char buf[80];
-	int len, handle;
 	struct fdtbus_pinctrl_controller *pc;
+	const u_int *pinctrl_data;
+	char buf[16];
+	u_int xref, pinctrl_cells;
+	int len, error;
+
+	snprintf(buf, sizeof(buf), "pinctrl-%u", index);
+
+	pinctrl_data = fdtbus_get_prop(phandle, buf, &len);
+	if (pinctrl_data == NULL)
+		return ENOENT;
+
+	while (len > 0) {
+		xref = fdtbus_get_phandle_from_native(be32toh(pinctrl_data[0]));
+		pc = fdtbus_pinctrl_lookup(xref);
+		if (pc == NULL)
+			return ENXIO;
+
+		if (of_getprop_uint32(OF_parent(xref), "#pinctrl-cells", &pinctrl_cells) != 0)
+			pinctrl_cells = 1;
+
+		error = pc->pc_funcs->set_config(pc->pc_dev, pinctrl_data, pinctrl_cells * 4);
+		if (error != 0)
+			return error;
 
-	snprintf(buf, 80, "pinctrl-%d", index);
-
-	len = OF_getprop(phandle, buf, (char *)&handle,
-                        sizeof(handle));
-	if (len != sizeof(int)) {
-		printf("%s: couldn't get %s.\n", __func__, buf);
-               return -1;
-       }
-
-	handle = fdtbus_get_phandle_from_native(be32toh(handle));
-
-	pc = fdtbus_pinctrl_lookup(handle);
-	if (!pc) {
-		printf("%s: Couldn't get handle %d for %s\n", __func__, handle,
-		       buf);
-		return -1;
+		pinctrl_data += pinctrl_cells;
+		len -= (pinctrl_cells * 4);
 	}
 
-	return pc->pc_funcs->set_config(pc->pc_cookie);
+	return 0;
 }
 
 int
 fdtbus_pinctrl_set_config(int phandle, const char *cfgname)
 {
-	int index = 0;
-	int len;
-	char *result;
-	char *next;
+	const char *pinctrl_names, *name;
+	int len, index;
 
-	len = OF_getproplen(phandle, "pinctrl-names");
-	if (len <= 0)
+	if ((len = OF_getproplen(phandle, "pinctrl-names")) < 0)
 		return -1;
-	result = kmem_zalloc(len, KM_SLEEP);
-	OF_getprop(phandle, "pinctrl-names", result, len);
 
-	next = result;
-	while (next - result < len) {
-		if (!strcmp(next, cfgname)) {
-			kmem_free(result, len);
+	pinctrl_names = fdtbus_get_string(phandle, "pinctrl-names");
+
+	for (name = pinctrl_names, index = 0; len > 0;
+	     name += strlen(name) + 1, index++) {
+		if (strcmp(name, cfgname) == 0)
 			return fdtbus_pinctrl_set_config_index(phandle, index);
-		}
-		index++;
-		while (*next)
-			next++;
-		next++;
 	}
 
-	kmem_free(result, len);
+	/* Not found */
 	return -1;
 }
+
+static void
+fdtbus_pinctrl_configure_node(int phandle)
+{
+	char buf[256];
+	int child, error;
+
+	for (child = OF_child(phandle); child; child = OF_peer(child)) {
+		if (!fdtbus_status_okay(child))
+			continue;
+
+		/* Configure child nodes */
+		fdtbus_pinctrl_configure_node(child);
+
+		/*
+		 * Set configuration 0 for this node. This may fail if the
+		 * pinctrl provider is missing; that's OK, we will re-configure
+		 * when that provider attaches.
+		 */
+		fdtbus_get_path(child, buf, sizeof(buf));
+		error = fdtbus_pinctrl_set_config_index(child, 0);
+		if (error == 0)
+			aprint_debug("pinctrl: set config pinctrl-0 for %s\n", buf);
+		else if (error != ENOENT)
+			aprint_debug("pinctrl: failed to set config pinctrl-0 for %s: %d\n", buf, error);
+	}
+}
+
+void
+fdtbus_pinctrl_configure(void)
+{
+	fdtbus_pinctrl_configure_node(OF_finddevice("/"));
+}

Index: src/sys/dev/fdt/fdt_subr.c
diff -u src/sys/dev/fdt/fdt_subr.c:1.14 src/sys/dev/fdt/fdt_subr.c:1.15
--- src/sys/dev/fdt/fdt_subr.c:1.14	Fri Jun 30 09:11:22 2017
+++ src/sys/dev/fdt/fdt_subr.c	Sun Jul  2 15:27:58 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: fdt_subr.c,v 1.14 2017/06/30 09:11:22 jmcneill Exp $ */
+/* $NetBSD: fdt_subr.c,v 1.15 2017/07/02 15:27:58 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.14 2017/06/30 09:11:22 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.15 2017/07/02 15:27:58 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -407,6 +407,14 @@ fdtbus_status_okay(int phandle)
 	return strncmp(prop, "ok", 2) == 0;
 }
 
+const void *
+fdtbus_get_prop(int phandle, const char *prop, int *plen)
+{
+	const int off = fdtbus_phandle2offset(phandle);
+
+	return fdt_getprop(fdtbus_get_data(), off, prop, plen);
+}
+
 const char *
 fdtbus_get_string(int phandle, const char *prop)
 {

Index: src/sys/dev/fdt/fdtvar.h
diff -u src/sys/dev/fdt/fdtvar.h:1.22 src/sys/dev/fdt/fdtvar.h:1.23
--- src/sys/dev/fdt/fdtvar.h:1.22	Fri Jun 30 09:11:22 2017
+++ src/sys/dev/fdt/fdtvar.h	Sun Jul  2 15:27:58 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: fdtvar.h,v 1.22 2017/06/30 09:11:22 jmcneill Exp $ */
+/* $NetBSD: fdtvar.h,v 1.23 2017/07/02 15:27:58 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -85,7 +85,7 @@ struct fdtbus_pinctrl_pin {
 };
 
 struct fdtbus_pinctrl_controller_func {
-	int (*set_config)(void *);
+	int (*set_config)(device_t, const void *, size_t);
 };
 
 struct fdtbus_regulator_controller;
@@ -211,7 +211,7 @@ int		fdtbus_register_i2c_controller(devi
 		    const struct fdtbus_i2c_controller_func *);
 int		fdtbus_register_gpio_controller(device_t, int,
 		    const struct fdtbus_gpio_controller_func *);
-int		fdtbus_register_pinctrl_config(void *, int,
+int		fdtbus_register_pinctrl_config(device_t, int,
 		    const struct fdtbus_pinctrl_controller_func *);
 int		fdtbus_register_regulator_controller(device_t, int,
 		    const struct fdtbus_regulator_controller_func *);
@@ -241,6 +241,7 @@ int		fdtbus_gpio_read(struct fdtbus_gpio
 void		fdtbus_gpio_write(struct fdtbus_gpio_pin *, int);
 int		fdtbus_gpio_read_raw(struct fdtbus_gpio_pin *);
 void		fdtbus_gpio_write_raw(struct fdtbus_gpio_pin *, int);
+void		fdtbus_pinctrl_configure(void);
 int		fdtbus_pinctrl_set_config_index(int, u_int);
 int		fdtbus_pinctrl_set_config(int, const char *);
 struct fdtbus_regulator *fdtbus_regulator_acquire(int, const char *);
@@ -294,6 +295,7 @@ tcflag_t	fdtbus_get_stdout_flags(void);
 
 bool		fdtbus_status_okay(int);
 
+const void *	fdtbus_get_prop(int, const char *, int *);
 const char *	fdtbus_get_string(int, const char *);
 
 int		fdtbus_print(void *, const char *);

Reply via email to