1254598Sian/*- 2254598Sian * Copyright (c) 2013 Ian Lepore 3254598Sian * All rights reserved. 4254598Sian * 5254598Sian * Redistribution and use in source and binary forms, with or without 6254598Sian * modification, are permitted provided that the following conditions 7254598Sian * are met: 8254598Sian * 9254598Sian * 1. Redistributions of source code must retain the above copyright 10254598Sian * notice, this list of conditions and the following disclaimer. 11254598Sian * 2. Redistributions in binary form must reproduce the above copyright 12254598Sian * notice, this list of conditions and the following disclaimer in the 13254598Sian * documentation and/or other materials provided with the distribution. 14254598Sian * 15254598Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16254598Sian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17254598Sian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18254598Sian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19254598Sian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20254598Sian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21254598Sian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22254598Sian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23254598Sian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24254598Sian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25254598Sian */ 26254598Sian 27254598Sian#include "opt_platform.h" 28254598Sian 29254598Sian#include <sys/cdefs.h> 30254598Sian__FBSDID("$FreeBSD: releng/10.3/sys/dev/uart/uart_dev_ti8250.c 283327 2015-05-23 20:54:25Z ian $"); 31254598Sian 32254598Sian#include <sys/param.h> 33254598Sian#include <sys/systm.h> 34254598Sian#include <sys/bus.h> 35254598Sian#include <sys/conf.h> 36254598Sian#include <sys/kernel.h> 37254598Sian#include <sys/sysctl.h> 38254598Sian#include <machine/bus.h> 39254598Sian 40254598Sian#include <arm/ti/ti_prcm.h> 41254598Sian 42254598Sian#include <dev/fdt/fdt_common.h> 43254598Sian#include <dev/ofw/ofw_bus.h> 44254598Sian#include <dev/ofw/ofw_bus_subr.h> 45254598Sian 46254598Sian#include <dev/uart/uart.h> 47254598Sian#include <dev/uart/uart_cpu.h> 48283327Sian#include <dev/uart/uart_cpu_fdt.h> 49254598Sian#include <dev/uart/uart_bus.h> 50254598Sian#include <dev/uart/uart_dev_ns8250.h> 51254598Sian 52254598Sian#include "uart_if.h" 53254598Sian 54254598Sian/* 55254598Sian * High-level UART interface. 56254598Sian */ 57254598Sianstruct ti8250_softc { 58254598Sian struct ns8250_softc ns8250_base; 59254598Sian /*uint32_t mystuff;*/ 60254598Sian}; 61254598Sian 62254598Sian#define MDR1_REG 8 63254598Sian#define MDR1_MODE_UART 0 64254598Sian#define MDR1_MODE_DISABLE 7 65254598Sian#define SYSCC_REG 15 66254598Sian#define SYSCC_SOFTRESET (1 << 1) 67254598Sian#define SYSS_REG 16 68254598Sian#define SYSS_STATUS_RESETDONE (1 << 0) 69254598Sian 70254598Sianstatic int 71254598Sianti8250_bus_probe(struct uart_softc *sc) 72254598Sian{ 73254598Sian int status; 74254598Sian int devid; 75254598Sian clk_ident_t clkid; 76254598Sian pcell_t prop; 77254598Sian phandle_t node; 78254598Sian 79254598Sian /* 80254598Sian * Get the device id from FDT. If it's not there we can't turn on the 81254598Sian * right clocks, so bail, unless we're doing unit 0. We assume that's 82254598Sian * the serial console, whose clock isn't controllable anyway, and we 83254598Sian * sure don't want to break the console because of a config error. 84254598Sian */ 85254598Sian node = ofw_bus_get_node(sc->sc_dev); 86254598Sian if ((OF_getprop(node, "uart-device-id", &prop, sizeof(prop))) <= 0) { 87254598Sian device_printf(sc->sc_dev, 88254598Sian "missing uart-device-id attribute in FDT\n"); 89254598Sian if (device_get_unit(sc->sc_dev) != 0) 90254598Sian return (ENXIO); 91254598Sian devid = 0; 92254598Sian } else 93254598Sian devid = fdt32_to_cpu(prop); 94254598Sian 95254598Sian /* Enable clocks for this device. We can't continue if that fails. */ 96254598Sian clkid = UART0_CLK + devid; 97254598Sian if ((status = ti_prcm_clk_enable(clkid)) != 0) 98254598Sian return (status); 99254598Sian 100254598Sian /* 101254598Sian * Set the hardware to disabled mode, do a full device reset, then set 102254598Sian * it to uart mode. Most devices will be reset-and-disabled already, 103254598Sian * but you never know what a bootloader might have done. 104254598Sian */ 105254598Sian uart_setreg(&sc->sc_bas, MDR1_REG, MDR1_MODE_DISABLE); 106254598Sian uart_setreg(&sc->sc_bas, SYSCC_REG, SYSCC_SOFTRESET); 107254598Sian while (uart_getreg(&sc->sc_bas, SYSS_REG) & SYSS_STATUS_RESETDONE) 108254598Sian continue; 109254598Sian uart_setreg(&sc->sc_bas, MDR1_REG, MDR1_MODE_UART); 110254598Sian 111254598Sian status = ns8250_bus_probe(sc); 112254598Sian if (status == 0) 113254598Sian device_set_desc(sc->sc_dev, "TI UART (16550 compatible)"); 114254598Sian 115254598Sian return (status); 116254598Sian} 117254598Sian 118254598Sianstatic kobj_method_t ti8250_methods[] = { 119254598Sian KOBJMETHOD(uart_probe, ti8250_bus_probe), 120254598Sian 121254598Sian KOBJMETHOD(uart_attach, ns8250_bus_attach), 122254598Sian KOBJMETHOD(uart_detach, ns8250_bus_detach), 123254598Sian KOBJMETHOD(uart_flush, ns8250_bus_flush), 124254598Sian KOBJMETHOD(uart_getsig, ns8250_bus_getsig), 125254598Sian KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl), 126254598Sian KOBJMETHOD(uart_ipend, ns8250_bus_ipend), 127254598Sian KOBJMETHOD(uart_param, ns8250_bus_param), 128254598Sian KOBJMETHOD(uart_receive, ns8250_bus_receive), 129254598Sian KOBJMETHOD(uart_setsig, ns8250_bus_setsig), 130254598Sian KOBJMETHOD(uart_transmit, ns8250_bus_transmit), 131254598Sian KOBJMETHOD_END 132254598Sian}; 133254598Sian 134283327Sianstatic struct uart_class uart_ti8250_class = { 135254598Sian "ti8250", 136254598Sian ti8250_methods, 137254598Sian sizeof(struct ti8250_softc), 138254598Sian .uc_ops = &uart_ns8250_ops, 139254598Sian .uc_range = 0x88, 140254598Sian .uc_rclk = 48000000 141254598Sian}; 142283327Sianstatic struct ofw_compat_data compat_data[] = { 143283327Sian {"ti,ns16550", (uintptr_t)&uart_ti8250_class}, 144283327Sian {NULL, (uintptr_t)NULL}, 145283327Sian}; 146283327SianUART_FDT_CLASS_AND_DEVICE(compat_data); 147