uart_cpu_fdt.c revision 257556
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 2009-2010 The FreeBSD Foundation 31590Srgrimes * All rights reserved. 489615Sdes * 589615Sdes * This software was developed by Semihalf under sponsorship from 61590Srgrimes * the FreeBSD Foundation. 789615Sdes * 889615Sdes * Redistribution and use in source and binary forms, with or without 989615Sdes * modification, are permitted provided that the following conditions 1089615Sdes * are met: 1189615Sdes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#include <sys/cdefs.h> 311590Srgrimes__FBSDID("$FreeBSD: head/sys/dev/uart/uart_cpu_fdt.c 257556 2013-11-02 20:14:39Z ian $"); 321590Srgrimes 331590Srgrimes#include "opt_platform.h" 341590Srgrimes 351590Srgrimes#include <sys/param.h> 361590Srgrimes#include <sys/bus.h> 371590Srgrimes#include <sys/kernel.h> 381590Srgrimes#include <sys/module.h> 391590Srgrimes#include <sys/systm.h> 401590Srgrimes 4187628Sdwmalone#include <vm/vm.h> 4287628Sdwmalone#include <vm/pmap.h> 4387628Sdwmalone 4487628Sdwmalone#include <machine/bus.h> 4587628Sdwmalone#include <machine/fdt.h> 4687628Sdwmalone 4787233Smarkm#include <dev/fdt/fdt_common.h> 4887233Smarkm#include <dev/ofw/ofw_bus.h> 4987233Smarkm#include <dev/ofw/ofw_bus_subr.h> 501590Srgrimes#include <dev/uart/uart.h> 511590Srgrimes#include <dev/uart/uart_bus.h> 521590Srgrimes#include <dev/uart/uart_cpu.h> 531590Srgrimes 541590Srgrimes/* 551590Srgrimes * UART console routines. 5687180Smarkm */ 5787180Smarkmbus_space_tag_t uart_bus_space_io; 581590Srgrimesbus_space_tag_t uart_bus_space_mem; 591590Srgrimes 601590Srgrimesstatic int 6187180Smarkmuart_fdt_get_clock(phandle_t node, pcell_t *cell) 621590Srgrimes{ 631590Srgrimes pcell_t clock; 641590Srgrimes 651590Srgrimes if ((OF_getprop(node, "clock-frequency", &clock, 66200462Sdelphij sizeof(clock))) <= 0) 6741079Sjdp return (ENXIO); 681590Srgrimes 691590Srgrimes if (clock == 0) 701590Srgrimes /* Try to retrieve parent 'bus-frequency' */ 711590Srgrimes /* XXX this should go to simple-bus fixup or so */ 721590Srgrimes if ((OF_getprop(OF_parent(node), "bus-frequency", &clock, 731590Srgrimes sizeof(clock))) <= 0) 741590Srgrimes clock = 0; 751590Srgrimes 761590Srgrimes *cell = fdt32_to_cpu(clock); 771590Srgrimes return (0); 7841279Sjdp} 7991714Sdes 803702Spststatic int 8187173Smarkmuart_fdt_get_shift(phandle_t node, pcell_t *cell) 821590Srgrimes{ 831590Srgrimes pcell_t shift; 8489994Sdes 8589994Sdes if ((OF_getprop(node, "reg-shift", &shift, sizeof(shift))) <= 0) 86264192Sjilles shift = 0; 8789994Sdes *cell = fdt32_to_cpu(shift); 8889994Sdes return (0); 8989994Sdes} 9089994Sdes 9189994Sdesint 9289994Sdesuart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) 9389994Sdes{ 9489994Sdes 9589994Sdes if (b1->bst != b2->bst) 9689994Sdes return (0); 9789994Sdes if (pmap_kextract(b1->bsh) == 0) 98264192Sjilles return (0); 9989994Sdes if (pmap_kextract(b2->bsh) == 0) 1001590Srgrimes return (0); 10187173Smarkm return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0); 10287173Smarkm} 10387173Smarkm 10476786Sobrienstatic int 10576786Sobrienphandle_chosen_propdev(phandle_t chosen, const char *name, phandle_t *node) 10689994Sdes{ 10787173Smarkm char buf[64]; 10889994Sdes 10989994Sdes if (OF_getprop(chosen, name, buf, sizeof(buf)) <= 0) 1101590Srgrimes return (ENXIO); 1111590Srgrimes if ((*node = OF_finddevice(buf)) == -1) 1121590Srgrimes return (ENXIO); 1131590Srgrimes 1141590Srgrimes return (0); 11589994Sdes} 1161590Srgrimes 11742272Seivindint 11889994Sdesuart_cpu_getdev(int devtype, struct uart_devinfo *di) 11942272Seivind{ 12089994Sdes const char *propnames[] = {"stdout-path", "linux,stdout-path", "stdout", 12189994Sdes "stdin-path", "stdin", NULL}; 1221590Srgrimes const char **name; 12389994Sdes const struct ofw_compat_data *cd; 12489994Sdes struct uart_class *class; 12589994Sdes phandle_t node, chosen; 12689994Sdes pcell_t shift, br, rclk; 12789994Sdes u_long start, size, pbase, psize; 12889994Sdes int err; 12989994Sdes 13089994Sdes uart_bus_space_mem = fdtbus_bs_tag; 13189994Sdes uart_bus_space_io = NULL; 13289994Sdes 13389994Sdes /* Allow overriding the FDT using the environment. */ 13489994Sdes class = &uart_ns8250_class; 13589994Sdes err = uart_getenv(devtype, di, class); 13689994Sdes if (!err) 13789994Sdes return (0); 13889994Sdes 13989994Sdes if (devtype != UART_DEV_CONSOLE) 14089994Sdes return (ENXIO); 14189994Sdes 14289994Sdes /* 14394203Sru * Retrieve /chosen/std{in,out}. 14489994Sdes */ 14594203Sru node = -1; 14689994Sdes if ((chosen = OF_finddevice("/chosen")) != -1) { 14789994Sdes for (name = propnames; *name != NULL; name++) { 14889994Sdes if (phandle_chosen_propdev(chosen, *name, &node) == 0) 14989994Sdes break; 15089994Sdes } 15189994Sdes } 15289994Sdes if (chosen == -1 || *name == NULL) 15391714Sdes node = OF_finddevice("serial0"); /* Last ditch */ 15489994Sdes 15589994Sdes if (node == -1) /* Can't find anything */ 15689994Sdes return (ENXIO); 15789994Sdes 15889994Sdes /* 1591590Srgrimes * Retrieve serial attributes. 16089994Sdes */ 1611590Srgrimes uart_fdt_get_shift(node, &shift); 1621590Srgrimes 1631590Srgrimes if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0) 16489994Sdes br = 0; 16589994Sdes br = fdt32_to_cpu(br); 16635559Speter 16746007Sache if ((err = uart_fdt_get_clock(node, &rclk)) != 0) 16889994Sdes return (err); 16945431Sbrian /* 17042272Seivind * Finalize configuration. 17194203Sru */ 17298960Sache for (cd = uart_fdt_compat_data; cd->ocd_str != NULL; ++cd) { 17394203Sru if (fdt_is_compatible(node, cd->ocd_str)) 17421528Sdavidn break; 175146867Smaxim } 17674874Smarkm if (cd->ocd_str == NULL) 177264192Sjilles return (ENXIO); 178264192Sjilles class = (struct uart_class *)cd->ocd_data; 179165152Scsjp 180155312Swsalamon di->bas.chan = 0; 181165152Scsjp di->bas.regshft = (u_int)shift; 1821590Srgrimes di->baudrate = br; 183264192Sjilles di->bas.rclk = (u_int)rclk; 184264192Sjilles di->ops = uart_getops(class); 185264192Sjilles di->databits = 8; 186264192Sjilles di->stopbits = 1; 187264192Sjilles di->parity = UART_PARITY_NONE; 188264192Sjilles di->bas.bst = uart_bus_space_mem; 18942272Seivind 19042272Seivind err = fdt_regsize(node, &start, &size); 19189994Sdes if (err) 19276788Sobrien return (ENXIO); 19376788Sobrien err = fdt_get_range(OF_parent(node), 0, &pbase, &psize); 19489994Sdes if (err) 19542272Seivind pbase = 0; 196264192Sjilles 197264192Sjilles start += pbase; 1981590Srgrimes 1991590Srgrimes return (bus_space_map(di->bas.bst, start, size, 0, &di->bas.bsh)); 2001590Srgrimes} 2011590Srgrimes