1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2010 Lars-Peter Clausen <lars@metafoo.de> 4 * Copyright (C) 2015 Imagination Technologies 5 * 6 * Ingenic SoC UART support 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/console.h> 11 #include <linux/io.h> 12 #include <linux/libfdt.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/of_fdt.h> 16 #include <linux/of_device.h> 17 #include <linux/platform_device.h> 18 #include <linux/serial_8250.h> 19 #include <linux/serial_core.h> 20 #include <linux/serial_reg.h> 21 22 #include "8250.h" 23 24 /** ingenic_uart_config: SOC specific config data. */ 25 struct ingenic_uart_config { 26 int tx_loadsz; 27 int fifosize; 28 }; 29 30 struct ingenic_uart_data { 31 struct clk *clk_module; 32 struct clk *clk_baud; 33 int line; 34 }; 35 36 static const struct of_device_id of_match[]; 37 38 #define UART_FCR_UME BIT(4) 39 40 #define UART_MCR_MDCE BIT(7) 41 #define UART_MCR_FCM BIT(6) 42 43 static struct earlycon_device *early_device; 44 45 static uint8_t early_in(struct uart_port *port, int offset) 46 { 47 return readl(port->membase + (offset << 2)); 48 } 49 50 static void early_out(struct uart_port *port, int offset, uint8_t value) 51 { 52 writel(value, port->membase + (offset << 2)); 53 } 54 55 static void ingenic_early_console_putc(struct uart_port *port, int c) 56 { 57 uint8_t lsr; 58 59 do { 60 lsr = early_in(port, UART_LSR); 61 } while ((lsr & UART_LSR_TEMT) == 0); 62 63 early_out(port, UART_TX, c); 64 } 65 66 static void ingenic_early_console_write(struct console *console, 67 const char *s, unsigned int count) 68 { 69 uart_console_write(&early_device->port, s, count, 70 ingenic_early_console_putc); 71 } 72 73 static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev) 74 { 75 void *fdt = initial_boot_params; 76 const __be32 *prop; 77 int offset; 78 79 offset = fdt_path_offset(fdt, "/ext"); 80 if (offset < 0) 81 return; 82 83 prop = fdt_getprop(fdt, offset, "clock-frequency", NULL); 84 if (!prop) 85 return; 86 87 dev->port.uartclk = be32_to_cpup(prop); 88 } 89 90 static int __init ingenic_early_console_setup(struct earlycon_device *dev, 91 const char *opt) 92 { 93 struct uart_port *port = &dev->port; 94 unsigned int baud, divisor; 95 96 if (!dev->port.membase) 97 return -ENODEV; 98 99 ingenic_early_console_setup_clock(dev); 100 101 baud = dev->baud ?: 115200; 102 divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud); 103 104 early_out(port, UART_IER, 0); 105 early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); 106 early_out(port, UART_DLL, 0); 107 early_out(port, UART_DLM, 0); 108 early_out(port, UART_LCR, UART_LCR_WLEN8); 109 early_out(port, UART_FCR, UART_FCR_UME | UART_FCR_CLEAR_XMIT | 110 UART_FCR_CLEAR_RCVR | UART_FCR_ENABLE_FIFO); 111 early_out(port, UART_MCR, UART_MCR_RTS | UART_MCR_DTR); 112 113 early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); 114 early_out(port, UART_DLL, divisor & 0xff); 115 early_out(port, UART_DLM, (divisor >> 8) & 0xff); 116 early_out(port, UART_LCR, UART_LCR_WLEN8); 117 118 early_device = dev; 119 dev->con->write = ingenic_early_console_write; 120 121 return 0; 122 } 123 124 EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup); 125 OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", 126 ingenic_early_console_setup); 127 128 EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup); 129 OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", 130 ingenic_early_console_setup); 131 132 EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); 133 OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", 134 ingenic_early_console_setup); 135 136 static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) 137 { 138 int ier; 139 140 switch (offset) { 141 case UART_FCR: 142 /* UART module enable */ 143 value |= UART_FCR_UME; 144 break; 145 146 case UART_IER: 147 /* 148 * Enable receive timeout interrupt with the receive line 149 * status interrupt. 150 */ 151 value |= (value & 0x4) << 2; 152 break; 153 154 case UART_MCR: 155 /* 156 * If we have enabled modem status IRQs we should enable 157 * modem mode. 158 */ 159 ier = p->serial_in(p, UART_IER); 160 161 if (ier & UART_IER_MSI) 162 value |= UART_MCR_MDCE | UART_MCR_FCM; 163 else 164 value &= ~(UART_MCR_MDCE | UART_MCR_FCM); 165 break; 166 167 default: 168 break; 169 } 170 171 writeb(value, p->membase + (offset << p->regshift)); 172 } 173 174 static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset) 175 { 176 unsigned int value; 177 178 value = readb(p->membase + (offset << p->regshift)); 179 180 /* Hide non-16550 compliant bits from higher levels */ 181 switch (offset) { 182 case UART_FCR: 183 value &= ~UART_FCR_UME; 184 break; 185 186 case UART_MCR: 187 value &= ~(UART_MCR_MDCE | UART_MCR_FCM); 188 break; 189 190 default: 191 break; 192 } 193 return value; 194 } 195 196 static int ingenic_uart_probe(struct platform_device *pdev) 197 { 198 struct uart_8250_port uart = {}; 199 struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 200 struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 201 struct ingenic_uart_data *data; 202 const struct ingenic_uart_config *cdata; 203 const struct of_device_id *match; 204 int err, line; 205 206 match = of_match_device(of_match, &pdev->dev); 207 if (!match) { 208 dev_err(&pdev->dev, "Error: No device match found\n"); 209 return -ENODEV; 210 } 211 cdata = match->data; 212 213 if (!regs || !irq) { 214 dev_err(&pdev->dev, "no registers/irq defined\n"); 215 return -EINVAL; 216 } 217 218 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 219 if (!data) 220 return -ENOMEM; 221 222 spin_lock_init(&uart.port.lock); 223 uart.port.type = PORT_16550A; 224 uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE; 225 uart.port.iotype = UPIO_MEM; 226 uart.port.mapbase = regs->start; 227 uart.port.regshift = 2; 228 uart.port.serial_out = ingenic_uart_serial_out; 229 uart.port.serial_in = ingenic_uart_serial_in; 230 uart.port.irq = irq->start; 231 uart.port.dev = &pdev->dev; 232 uart.port.fifosize = cdata->fifosize; 233 uart.tx_loadsz = cdata->tx_loadsz; 234 uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE; 235 236 /* Check for a fixed line number */ 237 line = of_alias_get_id(pdev->dev.of_node, "serial"); 238 if (line >= 0) 239 uart.port.line = line; 240 241 uart.port.membase = devm_ioremap(&pdev->dev, regs->start, 242 resource_size(regs)); 243 if (!uart.port.membase) 244 return -ENOMEM; 245 246 data->clk_module = devm_clk_get(&pdev->dev, "module"); 247 if (IS_ERR(data->clk_module)) { 248 err = PTR_ERR(data->clk_module); 249 if (err != -EPROBE_DEFER) 250 dev_err(&pdev->dev, 251 "unable to get module clock: %d\n", err); 252 return err; 253 } 254 255 data->clk_baud = devm_clk_get(&pdev->dev, "baud"); 256 if (IS_ERR(data->clk_baud)) { 257 err = PTR_ERR(data->clk_baud); 258 if (err != -EPROBE_DEFER) 259 dev_err(&pdev->dev, 260 "unable to get baud clock: %d\n", err); 261 return err; 262 } 263 264 err = clk_prepare_enable(data->clk_module); 265 if (err) { 266 dev_err(&pdev->dev, "could not enable module clock: %d\n", err); 267 goto out; 268 } 269 270 err = clk_prepare_enable(data->clk_baud); 271 if (err) { 272 dev_err(&pdev->dev, "could not enable baud clock: %d\n", err); 273 goto out_disable_moduleclk; 274 } 275 uart.port.uartclk = clk_get_rate(data->clk_baud); 276 277 data->line = serial8250_register_8250_port(&uart); 278 if (data->line < 0) { 279 err = data->line; 280 goto out_disable_baudclk; 281 } 282 283 platform_set_drvdata(pdev, data); 284 return 0; 285 286 out_disable_baudclk: 287 clk_disable_unprepare(data->clk_baud); 288 out_disable_moduleclk: 289 clk_disable_unprepare(data->clk_module); 290 out: 291 return err; 292 } 293 294 static int ingenic_uart_remove(struct platform_device *pdev) 295 { 296 struct ingenic_uart_data *data = platform_get_drvdata(pdev); 297 298 serial8250_unregister_port(data->line); 299 clk_disable_unprepare(data->clk_module); 300 clk_disable_unprepare(data->clk_baud); 301 return 0; 302 } 303 304 static const struct ingenic_uart_config jz4740_uart_config = { 305 .tx_loadsz = 8, 306 .fifosize = 16, 307 }; 308 309 static const struct ingenic_uart_config jz4760_uart_config = { 310 .tx_loadsz = 16, 311 .fifosize = 32, 312 }; 313 314 static const struct ingenic_uart_config jz4780_uart_config = { 315 .tx_loadsz = 32, 316 .fifosize = 64, 317 }; 318 319 static const struct of_device_id of_match[] = { 320 { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, 321 { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, 322 { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, 323 { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config }, 324 { /* sentinel */ } 325 }; 326 MODULE_DEVICE_TABLE(of, of_match); 327 328 static struct platform_driver ingenic_uart_platform_driver = { 329 .driver = { 330 .name = "ingenic-uart", 331 .of_match_table = of_match, 332 }, 333 .probe = ingenic_uart_probe, 334 .remove = ingenic_uart_remove, 335 }; 336 337 module_platform_driver(ingenic_uart_platform_driver); 338 339 MODULE_AUTHOR("Paul Burton"); 340 MODULE_LICENSE("GPL"); 341 MODULE_DESCRIPTION("Ingenic SoC UART driver"); 342