]>
Commit | Line | Data |
---|---|---|
6a12cebd VM |
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> | |
fd03b83a | 9 | #include <clk.h> |
6a12cebd VM |
10 | #include <dm.h> |
11 | #include <asm/io.h> | |
12 | #include <serial.h> | |
ba0a3c16 | 13 | #include <asm/arch/stm32.h> |
6a12cebd VM |
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; | |
27265cee | 22 | u32 int_div, mantissa, fraction, oversampling; |
ba0a3c16 | 23 | |
27265cee | 24 | int_div = DIV_ROUND_CLOSEST(plat->clock_rate, baudrate); |
1afcf9cb PC |
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); | |
6a12cebd VM |
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; | |
fd03b83a VM |
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 | ||
27265cee PC |
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 | ||
6c0c3ce8 VM |
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); | |
6a12cebd VM |
106 | setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
42bf5e7c VM |
111 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
112 | static const struct udevice_id stm32_serial_id[] = { | |
1113ad49 PC |
113 | {.compatible = "st,stm32f7-usart"}, |
114 | {.compatible = "st,stm32f7-uart"}, | |
42bf5e7c VM |
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 | ||
a821c4af | 123 | addr = devfdt_get_addr(dev); |
42bf5e7c VM |
124 | if (addr == FDT_ADDR_T_NONE) |
125 | return -EINVAL; | |
126 | ||
127 | plat->base = (struct stm32_usart *)addr; | |
fd03b83a | 128 | |
42bf5e7c VM |
129 | return 0; |
130 | } | |
131 | #endif | |
132 | ||
6a12cebd VM |
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, | |
42bf5e7c VM |
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), | |
6a12cebd VM |
146 | .ops = &stm32_serial_ops, |
147 | .probe = stm32_serial_probe, | |
148 | .flags = DM_FLAG_PRE_RELOC, | |
149 | }; |