diff options
author | ian <ian@FreeBSD.org> | 2015-05-23 20:54:25 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2015-05-23 20:54:25 +0000 |
commit | f3f411e10b20906a8640a6316ddcc3c1f24725e3 (patch) | |
tree | b8226cf0be8fe4cd6baeb7595bf89042db51e870 /sys/dev/uart | |
parent | ce1bf49e72ea9be2396679cd9569beeec685e9c6 (diff) | |
download | FreeBSD-src-f3f411e10b20906a8640a6316ddcc3c1f24725e3.zip FreeBSD-src-f3f411e10b20906a8640a6316ddcc3c1f24725e3.tar.gz |
MFC r279723, r279724:
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.
Move the uart_class definitions and fdt compat data into the individual
uart implementations, and export them using the new linker-set mechanism.
Diffstat (limited to 'sys/dev/uart')
-rw-r--r-- | sys/dev/uart/uart.h | 14 | ||||
-rw-r--r-- | sys/dev/uart/uart_bus_fdt.c | 53 | ||||
-rw-r--r-- | sys/dev/uart/uart_cpu_fdt.c | 66 | ||||
-rw-r--r-- | sys/dev/uart/uart_cpu_fdt.h | 54 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_imx.c | 15 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_lpc.c | 9 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_msm.c | 9 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_ns8250.c | 11 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_pl011.c | 9 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_ti8250.c | 9 | ||||
-rw-r--r-- | sys/dev/uart/uart_subr.c | 1 |
11 files changed, 181 insertions, 69 deletions
diff --git a/sys/dev/uart/uart.h b/sys/dev/uart/uart.h index b62dec6..c40846b 100644 --- a/sys/dev/uart/uart.h +++ b/sys/dev/uart/uart.h @@ -64,26 +64,12 @@ struct uart_bas { */ struct uart_class; -extern struct uart_class uart_imx_class __attribute__((weak)); -extern struct uart_class uart_msm_class __attribute__((weak)); extern struct uart_class uart_ns8250_class __attribute__((weak)); extern struct uart_class uart_quicc_class __attribute__((weak)); extern struct uart_class uart_s3c2410_class __attribute__((weak)); extern struct uart_class uart_sab82532_class __attribute__((weak)); extern struct uart_class uart_sbbc_class __attribute__((weak)); extern struct uart_class uart_z8530_class __attribute__((weak)); -extern struct uart_class uart_lpc_class __attribute__((weak)); -extern struct uart_class uart_pl011_class __attribute__((weak)); -extern struct uart_class uart_cdnc_class __attribute__((weak)); -extern struct uart_class uart_ti8250_class __attribute__((weak)); -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..3c68d95 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); @@ -62,37 +63,6 @@ static driver_t uart_fdt_driver = { sizeof(struct uart_softc), }; -/* - * Compatible devices. Keep this sorted in most- to least-specific order first, - * alphabetical second. That is, "zwie,ns16550" should appear before "ns16550" - * on the theory that the zwie driver knows how to make better use of the - * hardware than the generic driver. Likewise with chips within a family, the - * highest-numbers / most recent models should probably appear earlier. - */ -static struct ofw_compat_data compat_data[] = { - {"arm,pl011", (uintptr_t)&uart_pl011_class}, - {"atmel,at91rm9200-usart",(uintptr_t)&at91_usart_class}, - {"atmel,at91sam9260-usart",(uintptr_t)&at91_usart_class}, - {"cadence,uart", (uintptr_t)&uart_cdnc_class}, - {"exynos", (uintptr_t)&uart_exynos4210_class}, - {"fsl,imx6q-uart", (uintptr_t)&uart_imx_class}, - {"fsl,imx53-uart", (uintptr_t)&uart_imx_class}, - {"fsl,imx51-uart", (uintptr_t)&uart_imx_class}, - {"fsl,imx31-uart", (uintptr_t)&uart_imx_class}, - {"fsl,imx27-uart", (uintptr_t)&uart_imx_class}, - {"fsl,imx25-uart", (uintptr_t)&uart_imx_class}, - {"fsl,imx21-uart", (uintptr_t)&uart_imx_class}, - {"fsl,mvf600-uart", (uintptr_t)&uart_vybrid_class}, - {"lpc,uart", (uintptr_t)&uart_lpc_class}, - {"qcom,msm-uartdm", (uintptr_t)&uart_msm_class}, - {"ti,ns16550", (uintptr_t)&uart_ti8250_class}, - {"ns16550", (uintptr_t)&uart_ns8250_class}, - {NULL, (uintptr_t)NULL}, -}; - -/* 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; - static int uart_fdt_get_clock(phandle_t node, pcell_t *cell) { @@ -127,6 +97,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 +118,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_ */ diff --git a/sys/dev/uart/uart_dev_imx.c b/sys/dev/uart/uart_dev_imx.c index 2f5fc06..9e34473 100644 --- a/sys/dev/uart/uart_dev_imx.c +++ b/sys/dev/uart/uart_dev_imx.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_cpu.h> +#include <dev/uart/uart_cpu_fdt.h> #include <dev/uart/uart_bus.h> #include <dev/uart/uart_dev_imx.h> #include "uart_if.h" @@ -291,7 +292,7 @@ static kobj_method_t imx_uart_methods[] = { { 0, 0 } }; -struct uart_class uart_imx_class = { +static struct uart_class uart_imx_class = { "imx", imx_uart_methods, sizeof(struct imx_uart_softc), @@ -300,6 +301,18 @@ struct uart_class uart_imx_class = { .uc_rclk = 24000000 /* TODO: get value from CCM */ }; +static struct ofw_compat_data compat_data[] = { + {"fsl,imx6q-uart", (uintptr_t)&uart_imx_class}, + {"fsl,imx53-uart", (uintptr_t)&uart_imx_class}, + {"fsl,imx51-uart", (uintptr_t)&uart_imx_class}, + {"fsl,imx31-uart", (uintptr_t)&uart_imx_class}, + {"fsl,imx27-uart", (uintptr_t)&uart_imx_class}, + {"fsl,imx25-uart", (uintptr_t)&uart_imx_class}, + {"fsl,imx21-uart", (uintptr_t)&uart_imx_class}, + {NULL, (uintptr_t)NULL}, +}; +UART_FDT_CLASS_AND_DEVICE(compat_data); + #define SIGCHG(c, i, s, d) \ if (c) { \ i |= (i & s) ? s : s | d; \ diff --git a/sys/dev/uart/uart_dev_lpc.c b/sys/dev/uart/uart_dev_lpc.c index 08cebc9..992e890 100644 --- a/sys/dev/uart/uart_dev_lpc.c +++ b/sys/dev/uart/uart_dev_lpc.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_cpu.h> +#include <dev/uart/uart_cpu_fdt.h> #include <dev/uart/uart_bus.h> #include <dev/ic/ns16550.h> @@ -421,7 +422,7 @@ static kobj_method_t lpc_ns8250_methods[] = { { 0, 0 } }; -struct uart_class uart_lpc_class = { +static struct uart_class uart_lpc_class = { "lpc_ns8250", lpc_ns8250_methods, sizeof(struct lpc_ns8250_softc), @@ -430,6 +431,12 @@ struct uart_class uart_lpc_class = { .uc_rclk = DEFAULT_RCLK }; +static struct ofw_compat_data compat_data[] = { + {"lpc,uart", (uintptr_t)&uart_lpc_class}, + {NULL, (uintptr_t)NULL}, +}; +UART_FDT_CLASS_AND_DEVICE(compat_data); + #define SIGCHG(c, i, s, d) \ if (c) { \ i |= (i & s) ? s : s | d; \ diff --git a/sys/dev/uart/uart_dev_msm.c b/sys/dev/uart/uart_dev_msm.c index 12dc8a7..114a415 100644 --- a/sys/dev/uart/uart_dev_msm.c +++ b/sys/dev/uart/uart_dev_msm.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_cpu.h> +#include <dev/uart/uart_cpu_fdt.h> #include <dev/uart/uart_bus.h> #include <dev/uart/uart_dev_msm.h> @@ -558,7 +559,7 @@ msm_bus_ungrab(struct uart_softc *sc) uart_unlock(sc->sc_hwmtx); } -struct uart_class uart_msm_class = { +static struct uart_class uart_msm_class = { "msm", msm_methods, sizeof(struct msm_uart_softc), @@ -566,3 +567,9 @@ struct uart_class uart_msm_class = { .uc_range = 8, .uc_rclk = DEF_CLK, }; + +static struct ofw_compat_data compat_data[] = { + {"qcom,msm-uartdm", (uintptr_t)&uart_msm_class}, + {NULL, (uintptr_t)NULL}, +}; +UART_FDT_CLASS_AND_DEVICE(compat_data); diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c index 47a61bf..99692e6 100644 --- a/sys/dev/uart/uart_dev_ns8250.c +++ b/sys/dev/uart/uart_dev_ns8250.c @@ -45,6 +45,9 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_cpu.h> +#ifdef FDT +#include <dev/uart/uart_cpu_fdt.h> +#endif #include <dev/uart/uart_bus.h> #include <dev/uart/uart_dev_ns8250.h> @@ -379,6 +382,14 @@ struct uart_class uart_ns8250_class = { .uc_rclk = DEFAULT_RCLK }; +#ifdef FDT +static struct ofw_compat_data compat_data[] = { + {"ns16550", (uintptr_t)&uart_ns8250_class}, + {NULL, (uintptr_t)NULL}, +}; +UART_FDT_CLASS_AND_DEVICE(compat_data); +#endif + #define SIGCHG(c, i, s, d) \ if (c) { \ i |= (i & s) ? s : s | d; \ diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c index 1d17286..9084c35 100644 --- a/sys/dev/uart/uart_dev_pl011.c +++ b/sys/dev/uart/uart_dev_pl011.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_cpu.h> +#include <dev/uart/uart_cpu_fdt.h> #include <dev/uart/uart_bus.h> #include "uart_if.h" @@ -266,7 +267,7 @@ static kobj_method_t uart_pl011_methods[] = { { 0, 0 } }; -struct uart_class uart_pl011_class = { +static struct uart_class uart_pl011_class = { "uart_pl011", uart_pl011_methods, sizeof(struct uart_pl011_softc), @@ -275,6 +276,12 @@ struct uart_class uart_pl011_class = { .uc_rclk = 0 }; +static struct ofw_compat_data compat_data[] = { + {"arm,pl011", (uintptr_t)&uart_pl011_class}, + {NULL, (uintptr_t)NULL}, +}; +UART_FDT_CLASS_AND_DEVICE(compat_data); + static int uart_pl011_bus_attach(struct uart_softc *sc) { diff --git a/sys/dev/uart/uart_dev_ti8250.c b/sys/dev/uart/uart_dev_ti8250.c index 12d059a..daddbb7 100644 --- a/sys/dev/uart/uart_dev_ti8250.c +++ b/sys/dev/uart/uart_dev_ti8250.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_cpu.h> +#include <dev/uart/uart_cpu_fdt.h> #include <dev/uart/uart_bus.h> #include <dev/uart/uart_dev_ns8250.h> @@ -130,7 +131,7 @@ static kobj_method_t ti8250_methods[] = { KOBJMETHOD_END }; -struct uart_class uart_ti8250_class = { +static struct uart_class uart_ti8250_class = { "ti8250", ti8250_methods, sizeof(struct ti8250_softc), @@ -138,4 +139,8 @@ struct uart_class uart_ti8250_class = { .uc_range = 0x88, .uc_rclk = 48000000 }; - +static struct ofw_compat_data compat_data[] = { + {"ti,ns16550", (uintptr_t)&uart_ti8250_class}, + {NULL, (uintptr_t)NULL}, +}; +UART_FDT_CLASS_AND_DEVICE(compat_data); diff --git a/sys/dev/uart/uart_subr.c b/sys/dev/uart/uart_subr.c index 0277b21..b24f7eb 100644 --- a/sys/dev/uart/uart_subr.c +++ b/sys/dev/uart/uart_subr.c @@ -53,7 +53,6 @@ static struct uart_class *uart_classes[] = { &uart_sab82532_class, &uart_z8530_class, #if defined(__arm__) - &uart_lpc_class, &uart_s3c2410_class, #endif }; |