uart_cpu_fdt.c revision 250840
1250840Smarcel/*- 2250840Smarcel * Copyright (c) 2009-2010 The FreeBSD Foundation 3250840Smarcel * All rights reserved. 4250840Smarcel * 5250840Smarcel * This software was developed by Semihalf under sponsorship from 6250840Smarcel * the FreeBSD Foundation. 7250840Smarcel * 8250840Smarcel * Redistribution and use in source and binary forms, with or without 9250840Smarcel * modification, are permitted provided that the following conditions 10250840Smarcel * are met: 11250840Smarcel * 1. Redistributions of source code must retain the above copyright 12250840Smarcel * notice, this list of conditions and the following disclaimer. 13250840Smarcel * 2. Redistributions in binary form must reproduce the above copyright 14250840Smarcel * notice, this list of conditions and the following disclaimer in the 15250840Smarcel * documentation and/or other materials provided with the distribution. 16250840Smarcel * 17250840Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18250840Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19250840Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20250840Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21250840Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22250840Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23250840Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24250840Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25250840Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26250840Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27250840Smarcel * SUCH DAMAGE. 28250840Smarcel */ 29250840Smarcel 30250840Smarcel#include <sys/cdefs.h> 31250840Smarcel__FBSDID("$FreeBSD: head/sys/dev/uart/uart_cpu_fdt.c 250840 2013-05-21 03:05:49Z marcel $"); 32250840Smarcel 33250840Smarcel#include <sys/param.h> 34250840Smarcel#include <sys/bus.h> 35250840Smarcel#include <sys/kernel.h> 36250840Smarcel#include <sys/module.h> 37250840Smarcel 38250840Smarcel#include <machine/bus.h> 39250840Smarcel#include <machine/fdt.h> 40250840Smarcel 41250840Smarcel#include <dev/fdt/fdt_common.h> 42250840Smarcel#include <dev/ofw/ofw_bus.h> 43250840Smarcel#include <dev/ofw/ofw_bus_subr.h> 44250840Smarcel#include <dev/uart/uart.h> 45250840Smarcel#include <dev/uart/uart_bus.h> 46250840Smarcel#include <dev/uart/uart_cpu.h> 47250840Smarcel 48250840Smarcel/* 49250840Smarcel * UART console routines. 50250840Smarcel */ 51250840Smarcelbus_space_tag_t uart_bus_space_io; 52250840Smarcelbus_space_tag_t uart_bus_space_mem; 53250840Smarcel 54250840Smarcelstatic int 55250840Smarceluart_fdt_get_clock(phandle_t node, pcell_t *cell) 56250840Smarcel{ 57250840Smarcel pcell_t clock; 58250840Smarcel 59250840Smarcel if ((OF_getprop(node, "clock-frequency", &clock, 60250840Smarcel sizeof(clock))) <= 0) 61250840Smarcel return (ENXIO); 62250840Smarcel 63250840Smarcel if (clock == 0) 64250840Smarcel /* Try to retrieve parent 'bus-frequency' */ 65250840Smarcel /* XXX this should go to simple-bus fixup or so */ 66250840Smarcel if ((OF_getprop(OF_parent(node), "bus-frequency", &clock, 67250840Smarcel sizeof(clock))) <= 0) 68250840Smarcel clock = 0; 69250840Smarcel 70250840Smarcel *cell = fdt32_to_cpu(clock); 71250840Smarcel return (0); 72250840Smarcel} 73250840Smarcel 74250840Smarcelstatic int 75250840Smarceluart_fdt_get_shift(phandle_t node, pcell_t *cell) 76250840Smarcel{ 77250840Smarcel pcell_t shift; 78250840Smarcel 79250840Smarcel if ((OF_getprop(node, "reg-shift", &shift, sizeof(shift))) <= 0) 80250840Smarcel shift = 0; 81250840Smarcel *cell = fdt32_to_cpu(shift); 82250840Smarcel return (0); 83250840Smarcel} 84250840Smarcel 85250840Smarcelint 86250840Smarceluart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) 87250840Smarcel{ 88250840Smarcel 89250840Smarcel return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); 90250840Smarcel} 91250840Smarcel 92250840Smarcelint 93250840Smarceluart_cpu_getdev(int devtype, struct uart_devinfo *di) 94250840Smarcel{ 95250840Smarcel char buf[64]; 96250840Smarcel struct uart_class *class; 97250840Smarcel phandle_t node, chosen; 98250840Smarcel pcell_t shift, br, rclk; 99250840Smarcel u_long start, size, pbase, psize; 100250840Smarcel int err; 101250840Smarcel 102250840Smarcel uart_bus_space_mem = fdtbus_bs_tag; 103250840Smarcel uart_bus_space_io = NULL; 104250840Smarcel 105250840Smarcel /* Allow overriding the FDT uning the environment. */ 106250840Smarcel class = &uart_ns8250_class; 107250840Smarcel err = uart_getenv(devtype, di, class); 108250840Smarcel if (!err) 109250840Smarcel return (0); 110250840Smarcel 111250840Smarcel if (devtype != UART_DEV_CONSOLE) 112250840Smarcel return (ENXIO); 113250840Smarcel 114250840Smarcel /* 115250840Smarcel * Retrieve /chosen/std{in,out}. 116250840Smarcel */ 117250840Smarcel if ((chosen = OF_finddevice("/chosen")) == -1) 118250840Smarcel return (ENXIO); 119250840Smarcel if (OF_getprop(chosen, "stdin", buf, sizeof(buf)) <= 0) 120250840Smarcel return (ENXIO); 121250840Smarcel if ((node = OF_finddevice(buf)) == -1) 122250840Smarcel return (ENXIO); 123250840Smarcel if (OF_getprop(chosen, "stdout", buf, sizeof(buf)) <= 0) 124250840Smarcel return (ENXIO); 125250840Smarcel if (OF_finddevice(buf) != node) 126250840Smarcel /* Only stdin == stdout is supported. */ 127250840Smarcel return (ENXIO); 128250840Smarcel /* 129250840Smarcel * Retrieve serial attributes. 130250840Smarcel */ 131250840Smarcel uart_fdt_get_shift(node, &shift); 132250840Smarcel 133250840Smarcel if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0) 134250840Smarcel br = 0; 135250840Smarcel br = fdt32_to_cpu(br); 136250840Smarcel 137250840Smarcel if ((err = uart_fdt_get_clock(node, &rclk)) != 0) 138250840Smarcel return (err); 139250840Smarcel /* 140250840Smarcel * Finalize configuration. 141250840Smarcel */ 142250840Smarcel if (fdt_is_compatible(node, "fsl,imx-uart")) 143250840Smarcel class = &uart_imx_class; 144250840Smarcel if (fdt_is_compatible(node, "quicc")) 145250840Smarcel class = &uart_quicc_class; 146250840Smarcel if (fdt_is_compatible(node, "lpc")) 147250840Smarcel class = &uart_lpc_class; 148250840Smarcel if (fdt_is_compatible(node, "ns16550")) 149250840Smarcel class = &uart_ns8250_class; 150250840Smarcel if (fdt_is_compatible(node, "arm,pl011")) 151250840Smarcel class = &uart_pl011_class; 152250840Smarcel if (fdt_is_compatible(node, "cadence,uart")) 153250840Smarcel class = &uart_cdnc_class; 154250840Smarcel 155250840Smarcel di->bas.chan = 0; 156250840Smarcel di->bas.regshft = (u_int)shift; 157250840Smarcel di->baudrate = br; 158250840Smarcel di->bas.rclk = (u_int)rclk; 159250840Smarcel di->ops = uart_getops(class); 160250840Smarcel di->databits = 8; 161250840Smarcel di->stopbits = 1; 162250840Smarcel di->parity = UART_PARITY_NONE; 163250840Smarcel di->bas.bst = uart_bus_space_mem; 164250840Smarcel 165250840Smarcel err = fdt_regsize(node, &start, &size); 166250840Smarcel if (err) 167250840Smarcel return (ENXIO); 168250840Smarcel err = fdt_get_range(OF_parent(node), 0, &pbase, &psize); 169250840Smarcel if (err) 170250840Smarcel pbase = 0; 171250840Smarcel 172250840Smarcel start += pbase; 173250840Smarcel 174250840Smarcel return (bus_space_map(di->bas.bst, start, size, 0, &di->bas.bsh)); 175250840Smarcel} 176