uart_cpu_fdt.c revision 257183
1185377Ssam/*- 2185377Ssam * Copyright (c) 2009-2010 The FreeBSD Foundation 3185377Ssam * All rights reserved. 4185377Ssam * 5185377Ssam * This software was developed by Semihalf under sponsorship from 6185377Ssam * the FreeBSD Foundation. 7185377Ssam * 8185377Ssam * Redistribution and use in source and binary forms, with or without 9185377Ssam * modification, are permitted provided that the following conditions 10185377Ssam * are met: 11185377Ssam * 1. Redistributions of source code must retain the above copyright 12185377Ssam * notice, this list of conditions and the following disclaimer. 13185377Ssam * 2. Redistributions in binary form must reproduce the above copyright 14185377Ssam * notice, this list of conditions and the following disclaimer in the 15185377Ssam * documentation and/or other materials provided with the distribution. 16185377Ssam * 17204644Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18185377Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19185377Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20185377Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21185377Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22185377Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23185377Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24185377Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25185377Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26185377Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27185377Ssam * SUCH DAMAGE. 28185377Ssam */ 29185377Ssam 30185377Ssam#include <sys/cdefs.h> 31185377Ssam__FBSDID("$FreeBSD: head/sys/dev/uart/uart_cpu_fdt.c 257183 2013-10-26 18:25:55Z nwhitehorn $"); 32185377Ssam 33185377Ssam#include <sys/param.h> 34185377Ssam#include <sys/bus.h> 35185377Ssam#include <sys/kernel.h> 36185377Ssam#include <sys/module.h> 37185377Ssam#include <sys/systm.h> 38185377Ssam 39185377Ssam#include <vm/vm.h> 40185377Ssam#include <vm/pmap.h> 41185377Ssam 42185377Ssam#include <machine/bus.h> 43185377Ssam#include <machine/fdt.h> 44185377Ssam 45185377Ssam#include <dev/fdt/fdt_common.h> 46185377Ssam#include <dev/ofw/ofw_bus.h> 47185377Ssam#include <dev/ofw/ofw_bus_subr.h> 48185377Ssam#include <dev/uart/uart.h> 49185377Ssam#include <dev/uart/uart_bus.h> 50185377Ssam#include <dev/uart/uart_cpu.h> 51185377Ssam 52185377Ssam/* 53185377Ssam * UART console routines. 54185377Ssam */ 55185377Ssambus_space_tag_t uart_bus_space_io; 56185377Ssambus_space_tag_t uart_bus_space_mem; 57185377Ssam 58185377Ssamstatic int 59185377Ssamuart_fdt_get_clock(phandle_t node, pcell_t *cell) 60185377Ssam{ 61185377Ssam pcell_t clock; 62185377Ssam 63185377Ssam if ((OF_getprop(node, "clock-frequency", &clock, 64185377Ssam sizeof(clock))) <= 0) 65185377Ssam return (ENXIO); 66185377Ssam 67185377Ssam if (clock == 0) 68185377Ssam /* Try to retrieve parent 'bus-frequency' */ 69185377Ssam /* XXX this should go to simple-bus fixup or so */ 70185377Ssam if ((OF_getprop(OF_parent(node), "bus-frequency", &clock, 71185377Ssam sizeof(clock))) <= 0) 72185377Ssam clock = 0; 73185377Ssam 74185377Ssam *cell = fdt32_to_cpu(clock); 75185377Ssam return (0); 76185377Ssam} 77185377Ssam 78185377Ssamstatic int 79185377Ssamuart_fdt_get_shift(phandle_t node, pcell_t *cell) 80185377Ssam{ 81185377Ssam pcell_t shift; 82185377Ssam 83185377Ssam if ((OF_getprop(node, "reg-shift", &shift, sizeof(shift))) <= 0) 84185377Ssam shift = 0; 85185377Ssam *cell = fdt32_to_cpu(shift); 86185377Ssam return (0); 87185377Ssam} 88185377Ssam 89185377Ssamint 90185377Ssamuart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) 91185377Ssam{ 92185377Ssam 93185377Ssam if (b1->bst != b2->bst) 94185377Ssam return (0); 95185377Ssam if (pmap_kextract(b1->bsh) == 0) 96185377Ssam return (0); 97185377Ssam if (pmap_kextract(b2->bsh) == 0) 98185377Ssam return (0); 99185377Ssam return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0); 100185377Ssam} 101185377Ssam 102185377Ssamstatic int 103185377Ssamphandle_chosen_propdev(phandle_t chosen, const char *name, phandle_t *node) 104185377Ssam{ 105185377Ssam char buf[64]; 106185377Ssam 107185377Ssam if (OF_getprop(chosen, name, buf, sizeof(buf)) <= 0) 108185377Ssam return (ENXIO); 109185377Ssam if ((*node = OF_finddevice(buf)) == -1) 110185377Ssam return (ENXIO); 111185377Ssam 112185377Ssam return (0); 113185377Ssam} 114185377Ssam 115185377Ssamint 116185377Ssamuart_cpu_getdev(int devtype, struct uart_devinfo *di) 117185377Ssam{ 118185377Ssam const char *propnames[] = {"stdout-path", "linux,stdout-path", "stdout", 119185377Ssam "stdin-path", "stdin", NULL}; 120185377Ssam const char **name; 121185377Ssam struct uart_class *class; 122185377Ssam phandle_t node, chosen; 123185377Ssam pcell_t shift, br, rclk; 124185377Ssam u_long start, size, pbase, psize; 125185377Ssam int err; 126185377Ssam 127185377Ssam uart_bus_space_mem = fdtbus_bs_tag; 128185377Ssam uart_bus_space_io = NULL; 129185377Ssam 130185377Ssam /* Allow overriding the FDT using the environment. */ 131185377Ssam class = &uart_ns8250_class; 132185377Ssam err = uart_getenv(devtype, di, class); 133185377Ssam if (!err) 134185377Ssam return (0); 135185377Ssam 136185377Ssam if (devtype != UART_DEV_CONSOLE) 137185377Ssam return (ENXIO); 138185377Ssam 139185377Ssam /* 140185377Ssam * Retrieve /chosen/std{in,out}. 141185377Ssam */ 142185377Ssam if ((chosen = OF_finddevice("/chosen")) == -1) 143185377Ssam return (ENXIO); 144185377Ssam for (name = propnames; *name != NULL; name++) { 145185377Ssam if (phandle_chosen_propdev(chosen, *name, &node) == 0) 146185377Ssam break; 147185377Ssam } 148185377Ssam if (*name == NULL) 149185377Ssam return (ENXIO); 150185377Ssam /* 151185377Ssam * Retrieve serial attributes. 152185377Ssam */ 153185377Ssam uart_fdt_get_shift(node, &shift); 154185377Ssam 155185377Ssam if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0) 156185377Ssam br = 0; 157185377Ssam br = fdt32_to_cpu(br); 158185377Ssam 159185377Ssam if ((err = uart_fdt_get_clock(node, &rclk)) != 0) 160185377Ssam return (err); 161185377Ssam /* 162185377Ssam * Finalize configuration. 163185377Ssam */ 164185377Ssam if (fdt_is_compatible(node, "fsl,imx-uart")) 165185377Ssam class = &uart_imx_class; 166185377Ssam else if (fdt_is_compatible(node, "quicc")) 167185377Ssam class = &uart_quicc_class; 168185377Ssam else if (fdt_is_compatible(node, "lpc")) 169185377Ssam class = &uart_lpc_class; 170185377Ssam else if (fdt_is_compatible(node, "arm,pl011")) 171185377Ssam class = &uart_pl011_class; 172185377Ssam else if (fdt_is_compatible(node, "exynos")) 173185377Ssam class = &uart_s3c2410_class; 174185377Ssam else if (fdt_is_compatible(node, "cadence,uart")) 175185377Ssam class = &uart_cdnc_class; 176185377Ssam else if (fdt_is_compatible(node, "ti,ns16550")) 177185377Ssam class = &uart_ti8250_class; 178185377Ssam else if (fdt_is_compatible(node, "ns16550")) 179185377Ssam class = &uart_ns8250_class; 180185377Ssam 181185377Ssam di->bas.chan = 0; 182185377Ssam di->bas.regshft = (u_int)shift; 183185377Ssam di->baudrate = br; 184185377Ssam di->bas.rclk = (u_int)rclk; 185185377Ssam di->ops = uart_getops(class); 186185377Ssam di->databits = 8; 187185377Ssam di->stopbits = 1; 188185377Ssam di->parity = UART_PARITY_NONE; 189185377Ssam di->bas.bst = uart_bus_space_mem; 190185377Ssam 191185377Ssam err = fdt_regsize(node, &start, &size); 192185377Ssam if (err) 193185377Ssam return (ENXIO); 194185377Ssam err = fdt_get_range(OF_parent(node), 0, &pbase, &psize); 195185377Ssam if (err) 196185377Ssam pbase = 0; 197185377Ssam 198185377Ssam start += pbase; 199185377Ssam 200185377Ssam return (bus_space_map(di->bas.bst, start, size, 0, &di->bas.bsh)); 201185377Ssam} 202185377Ssam