summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2015-03-07 15:18:57 +0000
committerian <ian@FreeBSD.org>2015-03-07 15:18:57 +0000
commit7292a1689e4ab84c597c91255e4c24a2313d2420 (patch)
tree43f5c6ee350e548782f4544fba4d85581a3ced67 /sys/dev
parent964c68ec8c00bd969edc3ed901f7941685a69ad1 (diff)
downloadFreeBSD-src-7292a1689e4ab84c597c91255e4c24a2313d2420.zip
FreeBSD-src-7292a1689e4ab84c597c91255e4c24a2313d2420.tar.gz
Define new linker set, UART_FDT_CLASS_AND_DEVICE, for registering full
(class and device) FDT UART. Define second one, UART_FDT_CLASS, for UART class only. This paves the way for declaring uart_class data and ofw/fdt compat data with a uart implementation, rather than needing a big global table of compat data and weak-symbol declarations of every existing implementation. Differential Revision: https://reviews.freebsd.org/D1992 Submitted by: Michal Meloun
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/uart/uart.h4
-rw-r--r--sys/dev/uart/uart_bus_fdt.c24
-rw-r--r--sys/dev/uart/uart_cpu_fdt.c66
-rw-r--r--sys/dev/uart/uart_cpu_fdt.h54
4 files changed, 126 insertions, 22 deletions
diff --git a/sys/dev/uart/uart.h b/sys/dev/uart/uart.h
index b62dec6..2a5f026 100644
--- a/sys/dev/uart/uart.h
+++ b/sys/dev/uart/uart.h
@@ -80,10 +80,6 @@ extern struct uart_class uart_vybrid_class __attribute__((weak));
extern struct uart_class at91_usart_class __attribute__((weak));
extern struct uart_class uart_exynos4210_class __attribute__((weak));
-#ifdef FDT
-struct ofw_compat_data;
-extern const struct ofw_compat_data *uart_fdt_compat_data;
-#endif
#ifdef PC98
struct uart_class *uart_pc98_getdev(u_long port);
diff --git a/sys/dev/uart/uart_bus_fdt.c b/sys/dev/uart/uart_bus_fdt.c
index 457e041..9ef5152 100644
--- a/sys/dev/uart/uart_bus_fdt.c
+++ b/sys/dev/uart/uart_bus_fdt.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <dev/uart/uart.h>
#include <dev/uart/uart_bus.h>
#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_cpu_fdt.h>
static int uart_fdt_probe(device_t);
@@ -91,7 +92,7 @@ static struct ofw_compat_data compat_data[] = {
};
/* Export the compat_data table for use by the uart_cpu_fdt.c probe routine. */
-const struct ofw_compat_data *uart_fdt_compat_data = compat_data;
+UART_FDT_CLASS_AND_DEVICE(compat_data);
static int
uart_fdt_get_clock(phandle_t node, pcell_t *cell)
@@ -127,6 +128,20 @@ uart_fdt_get_shift(phandle_t node, pcell_t *cell)
return (0);
}
+static uintptr_t
+uart_fdt_find_device(device_t dev)
+{
+ struct ofw_compat_data **cd;
+ const struct ofw_compat_data *ocd;
+
+ SET_FOREACH(cd, uart_fdt_class_and_device_set) {
+ ocd = ofw_bus_search_compatible(dev, *cd);
+ if (ocd->ocd_data != 0)
+ return (ocd->ocd_data);
+ }
+ return (0);
+}
+
static int
uart_fdt_probe(device_t dev)
{
@@ -134,19 +149,16 @@ uart_fdt_probe(device_t dev)
phandle_t node;
pcell_t clock, shift;
int err;
- const struct ofw_compat_data * cd;
sc = device_get_softc(dev);
if (!ofw_bus_status_okay(dev))
return (ENXIO);
- cd = ofw_bus_search_compatible(dev, compat_data);
- if (cd->ocd_data == (uintptr_t)NULL)
+ sc->sc_class = (struct uart_class *)uart_fdt_find_device(dev);
+ if (sc->sc_class == NULL)
return (ENXIO);
- sc->sc_class = (struct uart_class *)cd->ocd_data;
-
node = ofw_bus_get_node(dev);
if ((err = uart_fdt_get_clock(node, &clock)) != 0)
diff --git a/sys/dev/uart/uart_cpu_fdt.c b/sys/dev/uart/uart_cpu_fdt.c
index 356049b..8dfdb3c 100644
--- a/sys/dev/uart/uart_cpu_fdt.c
+++ b/sys/dev/uart/uart_cpu_fdt.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <dev/uart/uart.h>
#include <dev/uart/uart_bus.h>
#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_cpu_fdt.h>
/*
* UART console routines.
@@ -115,13 +116,46 @@ phandle_chosen_propdev(phandle_t chosen, const char *name, phandle_t *node)
return (0);
}
+static const struct ofw_compat_data *
+uart_fdt_find_compatible(phandle_t node, const struct ofw_compat_data *cd)
+{
+ const struct ofw_compat_data *ocd;
+
+ for (ocd = cd; ocd->ocd_str != NULL; ocd++) {
+ if (fdt_is_compatible(node, ocd->ocd_str))
+ return (ocd);
+ }
+ return (NULL);
+}
+
+static uintptr_t
+uart_fdt_find_by_node(phandle_t node, int class_list)
+{
+ struct ofw_compat_data **cd;
+ const struct ofw_compat_data *ocd;
+
+ if (class_list) {
+ SET_FOREACH(cd, uart_fdt_class_set) {
+ ocd = uart_fdt_find_compatible(node, *cd);
+ if ((ocd != NULL) && (ocd->ocd_data != 0))
+ return (ocd->ocd_data);
+ }
+ } else {
+ SET_FOREACH(cd, uart_fdt_class_and_device_set) {
+ ocd = uart_fdt_find_compatible(node, *cd);
+ if ((ocd != NULL) && (ocd->ocd_data != 0))
+ return (ocd->ocd_data);
+ }
+ }
+ return (0);
+}
+
int
uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
const char *propnames[] = {"stdout-path", "linux,stdout-path", "stdout",
"stdin-path", "stdin", NULL};
const char **name;
- const struct ofw_compat_data *cd;
struct uart_class *class;
phandle_t node, chosen;
pcell_t shift, br, rclk;
@@ -160,24 +194,32 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
* Retrieve serial attributes.
*/
uart_fdt_get_shift(node, &shift);
-
if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0)
br = 0;
- br = fdt32_to_cpu(br);
+ else
+ br = fdt32_to_cpu(br);
- if ((err = uart_fdt_get_clock(node, &rclk)) != 0)
- return (err);
/*
- * Finalize configuration.
+ * Check old style of UART definition first. Unfortunately, the common
+ * FDT processing is not possible if we have clock, power domains and
+ * pinmux stuff.
*/
- for (cd = uart_fdt_compat_data; cd->ocd_str != NULL; ++cd) {
- if (fdt_is_compatible(node, cd->ocd_str))
- break;
+ class = (struct uart_class *)uart_fdt_find_by_node(node, 0);
+ if (class != NULL) {
+ if ((err = uart_fdt_get_clock(node, &rclk)) != 0)
+ return (err);
+ } else {
+ /* Check class only linker set */
+ class =
+ (struct uart_class *)uart_fdt_find_by_node(node, 1);
+ if (class == NULL)
+ return (ENXIO);
+ rclk = 0;
}
- if (cd->ocd_str == NULL)
- return (ENXIO);
- class = (struct uart_class *)cd->ocd_data;
+ /*
+ * Finalize configuration.
+ */
di->bas.chan = 0;
di->bas.regshft = (u_int)shift;
di->baudrate = br;
diff --git a/sys/dev/uart/uart_cpu_fdt.h b/sys/dev/uart/uart_cpu_fdt.h
new file mode 100644
index 0000000..e7aaecd
--- /dev/null
+++ b/sys/dev/uart/uart_cpu_fdt.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright 2015 Michal Meloun
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_UART_CPU_FDT_H_
+#define _DEV_UART_CPU_FDT_H_
+
+#include <sys/linker_set.h>
+
+#include <dev/ofw/ofw_bus_subr.h>
+
+/*
+ * If your UART driver implements only uart_class and uses uart_cpu_fdt.c
+ * for device instantiation, then use UART_FDT_CLASS_AND_DEVICE for its
+ * declaration
+ */
+SET_DECLARE(uart_fdt_class_and_device_set, struct ofw_compat_data );
+#define UART_FDT_CLASS_AND_DEVICE(data) \
+ DATA_SET(uart_fdt_class_and_device_set, data)
+
+/*
+ * If your UART driver implements uart_class and custom device layer,
+ * then use UART_FDT_CLASS for its declaration
+ */
+SET_DECLARE(uart_fdt_class_set, struct ofw_compat_data );
+#define UART_FDT_CLASS(data) \
+ DATA_SET(uart_fdt_class_set, data)
+
+
+#endif /* _DEV_UART_CPU_FDT_H_ */
OpenPOWER on IntegriCloud