Merge git://git.denx.de/u-boot-socfpga
[platform/kernel/u-boot.git] / drivers / serial / serial_stm32x7.c
1 /*
2  * (C) Copyright 2016
3  * Vikas Manocha, <vikas.manocha@st.com>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <clk.h>
10 #include <dm.h>
11 #include <asm/io.h>
12 #include <serial.h>
13 #include <asm/arch/stm32.h>
14 #include "serial_stm32x7.h"
15
16 DECLARE_GLOBAL_DATA_PTR;
17
18 static int stm32_serial_setbrg(struct udevice *dev, int baudrate)
19 {
20         struct stm32x7_serial_platdata *plat = dev->platdata;
21         struct stm32_usart *const usart = plat->base;
22         u32 int_div, mantissa, fraction, oversampling;
23
24         int_div = DIV_ROUND_CLOSEST(plat->clock_rate, baudrate);
25
26         if (int_div < 16) {
27                 oversampling = 8;
28                 setbits_le32(&usart->cr1, USART_CR1_OVER8);
29         } else {
30                 oversampling = 16;
31                 clrbits_le32(&usart->cr1, USART_CR1_OVER8);
32         }
33
34         mantissa = (int_div / oversampling) << USART_BRR_M_SHIFT;
35         fraction = int_div % oversampling;
36
37         writel(mantissa | fraction, &usart->brr);
38
39         return 0;
40 }
41
42 static int stm32_serial_getc(struct udevice *dev)
43 {
44         struct stm32x7_serial_platdata *plat = dev->platdata;
45         struct stm32_usart *const usart = plat->base;
46
47         if ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0)
48                 return -EAGAIN;
49
50         return readl(&usart->rd_dr);
51 }
52
53 static int stm32_serial_putc(struct udevice *dev, const char c)
54 {
55         struct stm32x7_serial_platdata *plat = dev->platdata;
56         struct stm32_usart *const usart = plat->base;
57
58         if ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0)
59                 return -EAGAIN;
60
61         writel(c, &usart->tx_dr);
62
63         return 0;
64 }
65
66 static int stm32_serial_pending(struct udevice *dev, bool input)
67 {
68         struct stm32x7_serial_platdata *plat = dev->platdata;
69         struct stm32_usart *const usart = plat->base;
70
71         if (input)
72                 return readl(&usart->sr) & USART_SR_FLAG_RXNE ? 1 : 0;
73         else
74                 return readl(&usart->sr) & USART_SR_FLAG_TXE ? 0 : 1;
75 }
76
77 static int stm32_serial_probe(struct udevice *dev)
78 {
79         struct stm32x7_serial_platdata *plat = dev->platdata;
80         struct stm32_usart *const usart = plat->base;
81
82 #ifdef CONFIG_CLK
83         int ret;
84         struct clk clk;
85
86         ret = clk_get_by_index(dev, 0, &clk);
87         if (ret < 0)
88                 return ret;
89
90         ret = clk_enable(&clk);
91         if (ret) {
92                 dev_err(dev, "failed to enable clock\n");
93                 return ret;
94         }
95 #endif
96
97         plat->clock_rate = clk_get_rate(&clk);
98         if (plat->clock_rate < 0) {
99                 clk_disable(&clk);
100                 return plat->clock_rate;
101         };
102
103         /* Disable usart-> disable overrun-> enable usart */
104         clrbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
105         setbits_le32(&usart->cr3, USART_CR3_OVRDIS);
106         setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
107
108         return 0;
109 }
110
111 #if CONFIG_IS_ENABLED(OF_CONTROL)
112 static const struct udevice_id stm32_serial_id[] = {
113         {.compatible = "st,stm32f7-usart"},
114         {.compatible = "st,stm32f7-uart"},
115         {}
116 };
117
118 static int stm32_serial_ofdata_to_platdata(struct udevice *dev)
119 {
120         struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
121         fdt_addr_t addr;
122
123         addr = devfdt_get_addr(dev);
124         if (addr == FDT_ADDR_T_NONE)
125                 return -EINVAL;
126
127         plat->base = (struct stm32_usart *)addr;
128
129         return 0;
130 }
131 #endif
132
133 static const struct dm_serial_ops stm32_serial_ops = {
134         .putc = stm32_serial_putc,
135         .pending = stm32_serial_pending,
136         .getc = stm32_serial_getc,
137         .setbrg = stm32_serial_setbrg,
138 };
139
140 U_BOOT_DRIVER(serial_stm32) = {
141         .name = "serial_stm32x7",
142         .id = UCLASS_SERIAL,
143         .of_match = of_match_ptr(stm32_serial_id),
144         .ofdata_to_platdata = of_match_ptr(stm32_serial_ofdata_to_platdata),
145         .platdata_auto_alloc_size = sizeof(struct stm32x7_serial_platdata),
146         .ops = &stm32_serial_ops,
147         .probe = stm32_serial_probe,
148         .flags = DM_FLAG_PRE_RELOC,
149 };