serial_bcm283x_mu: Always skip init
[oweals/u-boot.git] / drivers / serial / serial_bcm283x_mu.c
1 /*
2  * (C) Copyright 2016 Stephen Warren <swarren@wwwdotorg.org>
3  *
4  * Derived from pl01x code:
5  *
6  * (C) Copyright 2000
7  * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
8  *
9  * (C) Copyright 2004
10  * ARM Ltd.
11  * Philippe Robin, <philippe.robin@arm.com>
12  *
13  * SPDX-License-Identifier:     GPL-2.0+
14  */
15
16 /* Simple U-Boot driver for the BCM283x mini UART */
17
18 #include <common.h>
19 #include <dm.h>
20 #include <errno.h>
21 #include <watchdog.h>
22 #include <asm/io.h>
23 #include <serial.h>
24 #include <dm/platform_data/serial_bcm283x_mu.h>
25 #include <linux/compiler.h>
26
27 struct bcm283x_mu_regs {
28         u32 io;
29         u32 iir;
30         u32 ier;
31         u32 lcr;
32         u32 mcr;
33         u32 lsr;
34         u32 msr;
35         u32 scratch;
36         u32 cntl;
37         u32 stat;
38         u32 baud;
39 };
40
41 #define BCM283X_MU_LCR_DATA_SIZE_8      3
42
43 #define BCM283X_MU_LSR_TX_IDLE          BIT(6)
44 /* This actually means not full, but is named not empty in the docs */
45 #define BCM283X_MU_LSR_TX_EMPTY         BIT(5)
46 #define BCM283X_MU_LSR_RX_READY         BIT(0)
47
48 struct bcm283x_mu_priv {
49         struct bcm283x_mu_regs *regs;
50 };
51
52 static int bcm283x_mu_serial_setbrg(struct udevice *dev, int baudrate)
53 {
54         struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
55         struct bcm283x_mu_priv *priv = dev_get_priv(dev);
56         struct bcm283x_mu_regs *regs = priv->regs;
57         u32 divider;
58
59         if (plat->skip_init)
60                 return 0;
61
62         divider = plat->clock / (baudrate * 8);
63
64         writel(BCM283X_MU_LCR_DATA_SIZE_8, &regs->lcr);
65         writel(divider - 1, &regs->baud);
66
67         return 0;
68 }
69
70 static int bcm283x_mu_serial_probe(struct udevice *dev)
71 {
72         struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
73         struct bcm283x_mu_priv *priv = dev_get_priv(dev);
74
75         priv->regs = (struct bcm283x_mu_regs *)plat->base;
76
77         return 0;
78 }
79
80 static int bcm283x_mu_serial_getc(struct udevice *dev)
81 {
82         struct bcm283x_mu_priv *priv = dev_get_priv(dev);
83         struct bcm283x_mu_regs *regs = priv->regs;
84         u32 data;
85
86         /* Wait until there is data in the FIFO */
87         if (!(readl(&regs->lsr) & BCM283X_MU_LSR_RX_READY))
88                 return -EAGAIN;
89
90         data = readl(&regs->io);
91
92         return (int)data;
93 }
94
95 static int bcm283x_mu_serial_putc(struct udevice *dev, const char data)
96 {
97         struct bcm283x_mu_priv *priv = dev_get_priv(dev);
98         struct bcm283x_mu_regs *regs = priv->regs;
99
100         /* Wait until there is space in the FIFO */
101         if (!(readl(&regs->lsr) & BCM283X_MU_LSR_TX_EMPTY))
102                 return -EAGAIN;
103
104         /* Send the character */
105         writel(data, &regs->io);
106
107         return 0;
108 }
109
110 static int bcm283x_mu_serial_pending(struct udevice *dev, bool input)
111 {
112         struct bcm283x_mu_priv *priv = dev_get_priv(dev);
113         struct bcm283x_mu_regs *regs = priv->regs;
114         unsigned int lsr;
115
116         lsr = readl(&regs->lsr);
117
118         if (input) {
119                 WATCHDOG_RESET();
120                 return (lsr & BCM283X_MU_LSR_RX_READY) ? 1 : 0;
121         } else {
122                 return (lsr & BCM283X_MU_LSR_TX_IDLE) ? 0 : 1;
123         }
124 }
125
126 static const struct dm_serial_ops bcm283x_mu_serial_ops = {
127         .putc = bcm283x_mu_serial_putc,
128         .pending = bcm283x_mu_serial_pending,
129         .getc = bcm283x_mu_serial_getc,
130         .setbrg = bcm283x_mu_serial_setbrg,
131 };
132
133 #if CONFIG_IS_ENABLED(OF_CONTROL)
134 static const struct udevice_id bcm283x_mu_serial_id[] = {
135         {.compatible = "brcm,bcm2835-aux-uart"},
136         {}
137 };
138
139 static int bcm283x_mu_serial_ofdata_to_platdata(struct udevice *dev)
140 {
141         struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
142         fdt_addr_t addr;
143
144         addr = devfdt_get_addr(dev);
145         if (addr == FDT_ADDR_T_NONE)
146                 return -EINVAL;
147
148         plat->base = addr;
149         plat->clock = dev_read_u32_default(dev, "clock", 1);
150
151         /*
152          * TODO: Reinitialization doesn't always work for now, just skip
153          *       init always - we know we're already initialized
154          */
155         plat->skip_init = true;
156
157         return 0;
158 }
159 #endif
160
161 U_BOOT_DRIVER(serial_bcm283x_mu) = {
162         .name = "serial_bcm283x_mu",
163         .id = UCLASS_SERIAL,
164         .of_match = of_match_ptr(bcm283x_mu_serial_id),
165         .ofdata_to_platdata = of_match_ptr(bcm283x_mu_serial_ofdata_to_platdata),
166         .platdata_auto_alloc_size = sizeof(struct bcm283x_mu_serial_platdata),
167         .probe = bcm283x_mu_serial_probe,
168         .ops = &bcm283x_mu_serial_ops,
169         .flags = DM_FLAG_PRE_RELOC,
170         .priv_auto_alloc_size = sizeof(struct bcm283x_mu_priv),
171 };