serial: uniphier: use register macros instead of structure
[platform/kernel/u-boot.git] / drivers / serial / serial_uniphier.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2012-2015 Panasonic Corporation
4  * Copyright (C) 2015-2016 Socionext Inc.
5  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <linux/bitfield.h>
11 #include <linux/bitops.h>
12 #include <linux/bug.h>
13 #include <linux/io.h>
14 #include <linux/serial_reg.h>
15 #include <linux/sizes.h>
16 #include <linux/errno.h>
17 #include <serial.h>
18 #include <fdtdec.h>
19
20 #define UNIPHIER_UART_REGSHIFT          2
21
22 #define UNIPHIER_UART_RX                (0 << (UNIPHIER_UART_REGSHIFT))
23 #define UNIPHIER_UART_TX                UNIPHIER_UART_RX
24 /* bit[15:8] = CHAR, bit[7:0] = FCR */
25 #define UNIPHIER_UART_CHAR_FCR          (3 << (UNIPHIER_UART_REGSHIFT))
26 /* bit[15:8] = LCR, bit[7:0] = MCR */
27 #define UNIPHIER_UART_LCR_MCR           (4 << (UNIPHIER_UART_REGSHIFT))
28 #define   UNIPHIER_UART_LCR_MASK                GENMASK(15, 8)
29 #define UNIPHIER_UART_LSR               (5 << (UNIPHIER_UART_REGSHIFT))
30 /* Divisor Latch Register */
31 #define UNIPHIER_UART_DLR               (9 << (UNIPHIER_UART_REGSHIFT))
32
33 struct uniphier_serial_priv {
34         void __iomem *membase;
35         unsigned int uartclk;
36 };
37
38 static int uniphier_serial_setbrg(struct udevice *dev, int baudrate)
39 {
40         struct uniphier_serial_priv *priv = dev_get_priv(dev);
41         static const unsigned int mode_x_div = 16;
42         unsigned int divisor;
43
44         divisor = DIV_ROUND_CLOSEST(priv->uartclk, mode_x_div * baudrate);
45
46         writel(divisor, priv->membase + UNIPHIER_UART_DLR);
47
48         return 0;
49 }
50
51 static int uniphier_serial_getc(struct udevice *dev)
52 {
53         struct uniphier_serial_priv *priv = dev_get_priv(dev);
54
55         if (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_DR))
56                 return -EAGAIN;
57
58         return readl(priv->membase + UNIPHIER_UART_RX);
59 }
60
61 static int uniphier_serial_putc(struct udevice *dev, const char c)
62 {
63         struct uniphier_serial_priv *priv = dev_get_priv(dev);
64
65         if (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_THRE))
66                 return -EAGAIN;
67
68         writel(c, priv->membase + UNIPHIER_UART_TX);
69
70         return 0;
71 }
72
73 static int uniphier_serial_pending(struct udevice *dev, bool input)
74 {
75         struct uniphier_serial_priv *priv = dev_get_priv(dev);
76
77         if (input)
78                 return readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_DR;
79         else
80                 return !(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_THRE);
81 }
82
83 /*
84  * SPL does not have enough memory footprint for the clock driver.
85  * Hardcode clock frequency for each SoC.
86  */
87 struct uniphier_serial_clk_data {
88         const char *compatible;
89         unsigned int clk_rate;
90 };
91
92 static const struct uniphier_serial_clk_data uniphier_serial_clk_data[] = {
93         { .compatible = "socionext,uniphier-ld4",  .clk_rate = 36864000 },
94         { .compatible = "socionext,uniphier-pro4", .clk_rate = 73728000 },
95         { .compatible = "socionext,uniphier-sld8", .clk_rate = 80000000 },
96         { .compatible = "socionext,uniphier-pro5", .clk_rate = 73728000 },
97         { .compatible = "socionext,uniphier-pxs2", .clk_rate = 88888888 },
98         { .compatible = "socionext,uniphier-ld6b", .clk_rate = 88888888 },
99         { .compatible = "socionext,uniphier-ld11", .clk_rate = 58823529 },
100         { .compatible = "socionext,uniphier-ld20", .clk_rate = 58823529 },
101         { .compatible = "socionext,uniphier-pxs3", .clk_rate = 58823529 },
102         { /* sentinel */ },
103 };
104
105 static int uniphier_serial_probe(struct udevice *dev)
106 {
107         struct uniphier_serial_priv *priv = dev_get_priv(dev);
108         const struct uniphier_serial_clk_data *clk_data;
109         ofnode root_node;
110         fdt_addr_t base;
111         u32 tmp;
112
113         base = devfdt_get_addr(dev);
114         if (base == FDT_ADDR_T_NONE)
115                 return -EINVAL;
116
117         priv->membase = devm_ioremap(dev, base, SZ_64);
118         if (!priv->membase)
119                 return -ENOMEM;
120
121         root_node = ofnode_path("/");
122         clk_data = uniphier_serial_clk_data;
123         while (clk_data->compatible) {
124                 if (ofnode_device_is_compatible(root_node,
125                                                 clk_data->compatible))
126                         break;
127                 clk_data++;
128         }
129
130         if (WARN_ON(!clk_data->compatible))
131                 return -ENOTSUPP;
132
133         priv->uartclk = clk_data->clk_rate;
134
135         tmp = readl(priv->membase + UNIPHIER_UART_LCR_MCR);
136         tmp &= ~UNIPHIER_UART_LCR_MASK;
137         tmp |= FIELD_PREP(UNIPHIER_UART_LCR_MASK, UART_LCR_WLEN8);
138         writel(tmp, priv->membase + UNIPHIER_UART_LCR_MCR);
139
140         return 0;
141 }
142
143 static const struct udevice_id uniphier_uart_of_match[] = {
144         { .compatible = "socionext,uniphier-uart" },
145         { /* sentinel */ }
146 };
147
148 static const struct dm_serial_ops uniphier_serial_ops = {
149         .setbrg = uniphier_serial_setbrg,
150         .getc = uniphier_serial_getc,
151         .putc = uniphier_serial_putc,
152         .pending = uniphier_serial_pending,
153 };
154
155 U_BOOT_DRIVER(uniphier_serial) = {
156         .name = "uniphier-uart",
157         .id = UCLASS_SERIAL,
158         .of_match = uniphier_uart_of_match,
159         .probe = uniphier_serial_probe,
160         .priv_auto_alloc_size = sizeof(struct uniphier_serial_priv),
161         .ops = &uniphier_serial_ops,
162 };