diff options
author | Ian Lepore <ian@FreeBSD.org> | 2015-03-07 15:18:57 +0000 |
---|---|---|
committer | Ian Lepore <ian@FreeBSD.org> | 2015-03-07 15:18:57 +0000 |
commit | bd69e3ad2fce2896264f6ce70c87e21e19d12c8c (patch) | |
tree | 43f5c6ee350e548782f4544fba4d85581a3ced67 /sys/dev/uart | |
parent | aad75bd7dbb2bbb52a4aead42133e521997502fc (diff) | |
download | src-bd69e3ad2fce2896264f6ce70c87e21e19d12c8c.tar.gz src-bd69e3ad2fce2896264f6ce70c87e21e19d12c8c.zip |
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
Notes
Notes:
svn path=/head/; revision=279723
Diffstat (limited to 'sys/dev/uart')
-rw-r--r-- | sys/dev/uart/uart.h | 4 | ||||
-rw-r--r-- | sys/dev/uart/uart_bus_fdt.c | 24 | ||||
-rw-r--r-- | sys/dev/uart/uart_cpu_fdt.c | 66 | ||||
-rw-r--r-- | sys/dev/uart/uart_cpu_fdt.h | 54 |
4 files changed, 126 insertions, 22 deletions
diff --git a/sys/dev/uart/uart.h b/sys/dev/uart/uart.h index b62dec6da4f4..2a5f02612d04 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 457e04185717..9ef5152b60c5 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 356049b9ae3e..8dfdb3c0de13 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 000000000000..e7aaecda4323 --- /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_ */ |