blob: e8a1608b9988c193c1c860795730ecced5b4c107 [file] [log] [blame]
Masahiro Yamada7f368552014-10-03 19:21:05 +09001/*
2 * Copyright (C) 2012-2014 Panasonic Corporation
3 * Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
4 *
Masahiro Yamada7f368552014-10-03 19:21:05 +09005 * SPDX-License-Identifier: GPL-2.0+
6 */
7
Masahiro Yamada325b7082014-10-30 12:11:14 +09008#include <linux/serial_reg.h>
Masahiro Yamadad064cbf2014-10-23 22:26:10 +09009#include <asm/io.h>
10#include <asm/errno.h>
11#include <dm/device.h>
12#include <dm/platform_data/serial-uniphier.h>
Masahiro Yamada7f368552014-10-03 19:21:05 +090013#include <serial.h>
Masahiro Yamada625177d2014-11-26 18:34:00 +090014#include <fdtdec.h>
Masahiro Yamada7f368552014-10-03 19:21:05 +090015
16#define UART_REG(x) \
17 u8 x; \
18 u8 postpad_##x[3];
19
20/*
21 * Note: Register map is slightly different from that of 16550.
22 */
23struct uniphier_serial {
24 UART_REG(rbr); /* 0x00 */
25 UART_REG(ier); /* 0x04 */
26 UART_REG(iir); /* 0x08 */
27 UART_REG(fcr); /* 0x0c */
28 u8 mcr; /* 0x10 */
29 u8 lcr;
30 u16 __postpad;
31 UART_REG(lsr); /* 0x14 */
32 UART_REG(msr); /* 0x18 */
33 u32 __none1;
34 u32 __none2;
35 u16 dlr;
36 u16 __postpad2;
37};
38
39#define thr rbr
40
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090041struct uniphier_serial_private_data {
42 struct uniphier_serial __iomem *membase;
43};
Masahiro Yamada7f368552014-10-03 19:21:05 +090044
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090045#define uniphier_serial_port(dev) \
46 ((struct uniphier_serial_private_data *)dev_get_priv(dev))->membase
47
Masahiro Yamadad9bc8fd2014-10-24 17:00:11 +090048static int uniphier_serial_setbrg(struct udevice *dev, int baudrate)
Masahiro Yamada7f368552014-10-03 19:21:05 +090049{
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090050 struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
51 struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
Masahiro Yamada7f368552014-10-03 19:21:05 +090052 const unsigned int mode_x_div = 16;
53 unsigned int divisor;
54
Masahiro Yamada325b7082014-10-30 12:11:14 +090055 writeb(UART_LCR_WLEN8, &port->lcr);
Masahiro Yamada7f368552014-10-03 19:21:05 +090056
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090057 divisor = DIV_ROUND_CLOSEST(plat->uartclk, mode_x_div * baudrate);
Masahiro Yamada7f368552014-10-03 19:21:05 +090058
59 writew(divisor, &port->dlr);
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090060
61 return 0;
Masahiro Yamada7f368552014-10-03 19:21:05 +090062}
63
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090064static int uniphier_serial_getc(struct udevice *dev)
Masahiro Yamada7f368552014-10-03 19:21:05 +090065{
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090066 struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
Masahiro Yamada7f368552014-10-03 19:21:05 +090067
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090068 if (!(readb(&port->lsr) & UART_LSR_DR))
69 return -EAGAIN;
Masahiro Yamada7f368552014-10-03 19:21:05 +090070
71 return readb(&port->rbr);
72}
73
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090074static int uniphier_serial_putc(struct udevice *dev, const char c)
Masahiro Yamada7f368552014-10-03 19:21:05 +090075{
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090076 struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
Masahiro Yamada7f368552014-10-03 19:21:05 +090077
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090078 if (!(readb(&port->lsr) & UART_LSR_THRE))
79 return -EAGAIN;
Masahiro Yamada7f368552014-10-03 19:21:05 +090080
81 writeb(c, &port->thr);
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090082
83 return 0;
Masahiro Yamada7f368552014-10-03 19:21:05 +090084}
85
Masahiro Yamadabb721482014-10-24 17:00:10 +090086static int uniphier_serial_pending(struct udevice *dev, bool input)
87{
88 struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
89
90 if (input)
91 return readb(&port->lsr) & UART_LSR_DR;
92 else
93 return !(readb(&port->lsr) & UART_LSR_THRE);
94}
95
Masahiro Yamadad9bc8fd2014-10-24 17:00:11 +090096static int uniphier_serial_probe(struct udevice *dev)
Masahiro Yamadad064cbf2014-10-23 22:26:10 +090097{
98 struct uniphier_serial_private_data *priv = dev_get_priv(dev);
99 struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
100
101 priv->membase = map_sysmem(plat->base, sizeof(struct uniphier_serial));
102
103 if (!priv->membase)
104 return -ENOMEM;
105
106 return 0;
107}
108
Masahiro Yamadad9bc8fd2014-10-24 17:00:11 +0900109static int uniphier_serial_remove(struct udevice *dev)
Masahiro Yamadad064cbf2014-10-23 22:26:10 +0900110{
111 unmap_sysmem(uniphier_serial_port(dev));
112
113 return 0;
114}
115
116#ifdef CONFIG_OF_CONTROL
Masahiro Yamada625177d2014-11-26 18:34:00 +0900117static const struct udevice_id uniphier_uart_of_match[] = {
118 { .compatible = "panasonic,uniphier-uart" },
Masahiro Yamadad064cbf2014-10-23 22:26:10 +0900119 {},
Masahiro Yamada7f368552014-10-03 19:21:05 +0900120};
121
Masahiro Yamadad064cbf2014-10-23 22:26:10 +0900122static int uniphier_serial_ofdata_to_platdata(struct udevice *dev)
Masahiro Yamada7f368552014-10-03 19:21:05 +0900123{
Masahiro Yamada625177d2014-11-26 18:34:00 +0900124 struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
125 DECLARE_GLOBAL_DATA_PTR;
126
127 plat->base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
128 plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
129 "clock-frequency", 0);
130
131 return 0;
Masahiro Yamada7f368552014-10-03 19:21:05 +0900132}
Masahiro Yamadad064cbf2014-10-23 22:26:10 +0900133#endif
Masahiro Yamada7f368552014-10-03 19:21:05 +0900134
Masahiro Yamadad064cbf2014-10-23 22:26:10 +0900135static const struct dm_serial_ops uniphier_serial_ops = {
136 .setbrg = uniphier_serial_setbrg,
137 .getc = uniphier_serial_getc,
138 .putc = uniphier_serial_putc,
Masahiro Yamadabb721482014-10-24 17:00:10 +0900139 .pending = uniphier_serial_pending,
Masahiro Yamadad064cbf2014-10-23 22:26:10 +0900140};
141
142U_BOOT_DRIVER(uniphier_serial) = {
143 .name = DRIVER_NAME,
144 .id = UCLASS_SERIAL,
145 .of_match = of_match_ptr(uniphier_uart_of_match),
146 .ofdata_to_platdata = of_match_ptr(uniphier_serial_ofdata_to_platdata),
147 .probe = uniphier_serial_probe,
148 .remove = uniphier_serial_remove,
149 .priv_auto_alloc_size = sizeof(struct uniphier_serial_private_data),
150 .platdata_auto_alloc_size =
151 sizeof(struct uniphier_serial_platform_data),
152 .ops = &uniphier_serial_ops,
153 .flags = DM_FLAG_PRE_RELOC,
154};