]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/serial/serial_uniphier.c
ddr: altera: Tweak DQS tracking enable handling
[people/ms/u-boot.git] / drivers / serial / serial_uniphier.c
CommitLineData
7f368553 1/*
f6e7f07c 2 * Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
7f368553 3 *
7f368553
MY
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
f6e7f07c 7#include <linux/io.h>
325b708a 8#include <linux/serial_reg.h>
b37a1cce 9#include <linux/sizes.h>
d064cbff
MY
10#include <asm/errno.h>
11#include <dm/device.h>
0eb25b61 12#include <mapmem.h>
7f368553 13#include <serial.h>
625177d2 14#include <fdtdec.h>
7f368553 15
7f368553
MY
16/*
17 * Note: Register map is slightly different from that of 16550.
18 */
19struct uniphier_serial {
d0c47b3e
MY
20 u32 rx; /* In: Receive buffer */
21#define tx rx /* Out: Transmit buffer */
22 u32 ier; /* Interrupt Enable Register */
23 u32 iir; /* In: Interrupt ID Register */
24 u32 char_fcr; /* Charactor / FIFO Control Register */
25 u32 lcr_mcr; /* Line/Modem Control Register */
26#define LCR_SHIFT 8
27#define LCR_MASK (0xff << (LCR_SHIFT))
28 u32 lsr; /* In: Line Status Register */
29 u32 msr; /* In: Modem Status Register */
30 u32 __rsv0;
31 u32 __rsv1;
32 u32 dlr; /* Divisor Latch Register */
7f368553
MY
33};
34
d064cbff
MY
35struct uniphier_serial_private_data {
36 struct uniphier_serial __iomem *membase;
6d99cfae 37 unsigned int uartclk;
d064cbff
MY
38};
39
40#define uniphier_serial_port(dev) \
41 ((struct uniphier_serial_private_data *)dev_get_priv(dev))->membase
7f368553 42
d9bc8fd1 43static int uniphier_serial_setbrg(struct udevice *dev, int baudrate)
7f368553 44{
6d99cfae 45 struct uniphier_serial_private_data *priv = dev_get_priv(dev);
d064cbff 46 struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
7f368553
MY
47 const unsigned int mode_x_div = 16;
48 unsigned int divisor;
7f368553 49
6d99cfae 50 divisor = DIV_ROUND_CLOSEST(priv->uartclk, mode_x_div * baudrate);
7f368553 51
d0c47b3e 52 writel(divisor, &port->dlr);
7f368553 53
d064cbff 54 return 0;
7f368553
MY
55}
56
d064cbff 57static int uniphier_serial_getc(struct udevice *dev)
7f368553 58{
d064cbff 59 struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
7f368553 60
d0c47b3e 61 if (!(readl(&port->lsr) & UART_LSR_DR))
d064cbff 62 return -EAGAIN;
7f368553 63
d0c47b3e 64 return readl(&port->rx);
7f368553
MY
65}
66
d064cbff 67static int uniphier_serial_putc(struct udevice *dev, const char c)
7f368553 68{
d064cbff 69 struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
7f368553 70
d0c47b3e 71 if (!(readl(&port->lsr) & UART_LSR_THRE))
d064cbff 72 return -EAGAIN;
7f368553 73
d0c47b3e 74 writel(c, &port->tx);
d064cbff
MY
75
76 return 0;
7f368553
MY
77}
78
bb72148b
MY
79static int uniphier_serial_pending(struct udevice *dev, bool input)
80{
81 struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
82
83 if (input)
d0c47b3e 84 return readl(&port->lsr) & UART_LSR_DR;
bb72148b 85 else
d0c47b3e 86 return !(readl(&port->lsr) & UART_LSR_THRE);
bb72148b
MY
87}
88
d9bc8fd1 89static int uniphier_serial_probe(struct udevice *dev)
d064cbff 90{
6d99cfae 91 DECLARE_GLOBAL_DATA_PTR;
d064cbff 92 struct uniphier_serial_private_data *priv = dev_get_priv(dev);
099cf77c 93 struct uniphier_serial __iomem *port;
6d99cfae 94 fdt_addr_t base;
6d99cfae 95 u32 tmp;
7f368553 96
b37a1cce
MY
97 base = dev_get_addr(dev);
98 if (base == FDT_ADDR_T_NONE)
99 return -EINVAL;
6d99cfae 100
b37a1cce 101 port = map_sysmem(base, SZ_64);
099cf77c 102 if (!port)
d064cbff 103 return -ENOMEM;
7f368553 104
099cf77c
MY
105 priv->membase = port;
106
6d99cfae
MY
107 priv->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
108 "clock-frequency", 0);
109
099cf77c
MY
110 tmp = readl(&port->lcr_mcr);
111 tmp &= ~LCR_MASK;
112 tmp |= UART_LCR_WLEN8 << LCR_SHIFT;
113 writel(tmp, &port->lcr_mcr);
114
d064cbff
MY
115 return 0;
116}
117
d9bc8fd1 118static int uniphier_serial_remove(struct udevice *dev)
7f368553 119{
d064cbff
MY
120 unmap_sysmem(uniphier_serial_port(dev));
121
122 return 0;
7f368553
MY
123}
124
625177d2 125static const struct udevice_id uniphier_uart_of_match[] = {
6462cded
MY
126 { .compatible = "socionext,uniphier-uart" },
127 { /* sentinel */ }
d064cbff
MY
128};
129
d064cbff
MY
130static const struct dm_serial_ops uniphier_serial_ops = {
131 .setbrg = uniphier_serial_setbrg,
132 .getc = uniphier_serial_getc,
133 .putc = uniphier_serial_putc,
bb72148b 134 .pending = uniphier_serial_pending,
d064cbff
MY
135};
136
137U_BOOT_DRIVER(uniphier_serial) = {
6d99cfae 138 .name = "uniphier-uart",
d064cbff 139 .id = UCLASS_SERIAL,
6d99cfae 140 .of_match = uniphier_uart_of_match,
d064cbff
MY
141 .probe = uniphier_serial_probe,
142 .remove = uniphier_serial_remove,
143 .priv_auto_alloc_size = sizeof(struct uniphier_serial_private_data),
d064cbff 144 .ops = &uniphier_serial_ops,
d064cbff 145};