1 /* 2 * Copyright (C) 2012-2014 Panasonic Corporation 3 * Author: Masahiro Yamada <yamada.m@jp.panasonic.com> 4 * 5 * Based on serial_ns16550.c 6 * (C) Copyright 2000 7 * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <serial.h> 14 15 #define UART_REG(x) \ 16 u8 x; \ 17 u8 postpad_##x[3]; 18 19 /* 20 * Note: Register map is slightly different from that of 16550. 21 */ 22 struct uniphier_serial { 23 UART_REG(rbr); /* 0x00 */ 24 UART_REG(ier); /* 0x04 */ 25 UART_REG(iir); /* 0x08 */ 26 UART_REG(fcr); /* 0x0c */ 27 u8 mcr; /* 0x10 */ 28 u8 lcr; 29 u16 __postpad; 30 UART_REG(lsr); /* 0x14 */ 31 UART_REG(msr); /* 0x18 */ 32 u32 __none1; 33 u32 __none2; 34 u16 dlr; 35 u16 __postpad2; 36 }; 37 38 #define thr rbr 39 40 /* 41 * These are the definitions for the Line Control Register 42 */ 43 #define UART_LCR_WLS_8 0x03 /* 8 bit character length */ 44 45 /* 46 * These are the definitions for the Line Status Register 47 */ 48 #define UART_LSR_DR 0x01 /* Data ready */ 49 #define UART_LSR_THRE 0x20 /* Xmit holding register empty */ 50 51 DECLARE_GLOBAL_DATA_PTR; 52 53 static void uniphier_serial_init(struct uniphier_serial *port) 54 { 55 const unsigned int mode_x_div = 16; 56 unsigned int divisor; 57 58 writeb(UART_LCR_WLS_8, &port->lcr); 59 60 divisor = DIV_ROUND_CLOSEST(CONFIG_SYS_UNIPHIER_UART_CLK, 61 mode_x_div * gd->baudrate); 62 63 writew(divisor, &port->dlr); 64 } 65 66 static void uniphier_serial_setbrg(struct uniphier_serial *port) 67 { 68 uniphier_serial_init(port); 69 } 70 71 static int uniphier_serial_tstc(struct uniphier_serial *port) 72 { 73 return (readb(&port->lsr) & UART_LSR_DR) != 0; 74 } 75 76 static int uniphier_serial_getc(struct uniphier_serial *port) 77 { 78 while (!uniphier_serial_tstc(port)) 79 ; 80 81 return readb(&port->rbr); 82 } 83 84 static void uniphier_serial_putc(struct uniphier_serial *port, const char c) 85 { 86 if (c == '\n') 87 uniphier_serial_putc(port, '\r'); 88 89 while (!(readb(&port->lsr) & UART_LSR_THRE)) 90 ; 91 92 writeb(c, &port->thr); 93 } 94 95 static struct uniphier_serial *serial_ports[4] = { 96 #ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE0 97 (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE0, 98 #else 99 NULL, 100 #endif 101 #ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE1 102 (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE1, 103 #else 104 NULL, 105 #endif 106 #ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE2 107 (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE2, 108 #else 109 NULL, 110 #endif 111 #ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE3 112 (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE3, 113 #else 114 NULL, 115 #endif 116 }; 117 118 /* Multi serial device functions */ 119 #define DECLARE_ESERIAL_FUNCTIONS(port) \ 120 static int eserial##port##_init(void) \ 121 { \ 122 uniphier_serial_init(serial_ports[port]); \ 123 return 0 ; \ 124 } \ 125 static void eserial##port##_setbrg(void) \ 126 { \ 127 uniphier_serial_setbrg(serial_ports[port]); \ 128 } \ 129 static int eserial##port##_getc(void) \ 130 { \ 131 return uniphier_serial_getc(serial_ports[port]); \ 132 } \ 133 static int eserial##port##_tstc(void) \ 134 { \ 135 return uniphier_serial_tstc(serial_ports[port]); \ 136 } \ 137 static void eserial##port##_putc(const char c) \ 138 { \ 139 uniphier_serial_putc(serial_ports[port], c); \ 140 } 141 142 /* Serial device descriptor */ 143 #define INIT_ESERIAL_STRUCTURE(port, __name) { \ 144 .name = __name, \ 145 .start = eserial##port##_init, \ 146 .stop = NULL, \ 147 .setbrg = eserial##port##_setbrg, \ 148 .getc = eserial##port##_getc, \ 149 .tstc = eserial##port##_tstc, \ 150 .putc = eserial##port##_putc, \ 151 .puts = default_serial_puts, \ 152 } 153 154 #if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) 155 DECLARE_ESERIAL_FUNCTIONS(0); 156 struct serial_device uniphier_serial0_device = 157 INIT_ESERIAL_STRUCTURE(0, "ttyS0"); 158 #endif 159 #if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) 160 DECLARE_ESERIAL_FUNCTIONS(1); 161 struct serial_device uniphier_serial1_device = 162 INIT_ESERIAL_STRUCTURE(1, "ttyS1"); 163 #endif 164 #if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) 165 DECLARE_ESERIAL_FUNCTIONS(2); 166 struct serial_device uniphier_serial2_device = 167 INIT_ESERIAL_STRUCTURE(2, "ttyS2"); 168 #endif 169 #if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) 170 DECLARE_ESERIAL_FUNCTIONS(3); 171 struct serial_device uniphier_serial3_device = 172 INIT_ESERIAL_STRUCTURE(3, "ttyS3"); 173 #endif 174 175 __weak struct serial_device *default_serial_console(void) 176 { 177 #if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) 178 return &uniphier_serial0_device; 179 #elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) 180 return &uniphier_serial1_device; 181 #elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) 182 return &uniphier_serial2_device; 183 #elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) 184 return &uniphier_serial3_device; 185 #else 186 #error "No uniphier serial ports configured." 187 #endif 188 } 189 190 void uniphier_serial_initialize(void) 191 { 192 #if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) 193 serial_register(&uniphier_serial0_device); 194 #endif 195 #if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) 196 serial_register(&uniphier_serial1_device); 197 #endif 198 #if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) 199 serial_register(&uniphier_serial2_device); 200 #endif 201 #if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) 202 serial_register(&uniphier_serial3_device); 203 #endif 204 } 205