]>
Commit | Line | Data |
---|---|---|
6a12cebd | 1 | /* |
3bc599c9 PC |
2 | * Copyright (C) 2016, STMicroelectronics - All Rights Reserved |
3 | * Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics. | |
6a12cebd VM |
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> |
ae74de0d | 14 | #include "serial_stm32.h" |
6a12cebd VM |
15 | |
16 | DECLARE_GLOBAL_DATA_PTR; | |
17 | ||
18 | static int stm32_serial_setbrg(struct udevice *dev, int baudrate) | |
19 | { | |
60a996ba PC |
20 | struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); |
21 | bool stm32f4 = plat->uart_info->stm32f4; | |
22 | fdt_addr_t base = plat->base; | |
27265cee | 23 | u32 int_div, mantissa, fraction, oversampling; |
ba0a3c16 | 24 | |
27265cee | 25 | int_div = DIV_ROUND_CLOSEST(plat->clock_rate, baudrate); |
1afcf9cb PC |
26 | |
27 | if (int_div < 16) { | |
28 | oversampling = 8; | |
60a996ba | 29 | setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8); |
1afcf9cb PC |
30 | } else { |
31 | oversampling = 16; | |
60a996ba | 32 | clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8); |
1afcf9cb PC |
33 | } |
34 | ||
35 | mantissa = (int_div / oversampling) << USART_BRR_M_SHIFT; | |
36 | fraction = int_div % oversampling; | |
37 | ||
60a996ba | 38 | writel(mantissa | fraction, base + BRR_OFFSET(stm32f4)); |
6a12cebd VM |
39 | |
40 | return 0; | |
41 | } | |
42 | ||
43 | static int stm32_serial_getc(struct udevice *dev) | |
44 | { | |
60a996ba PC |
45 | struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); |
46 | bool stm32f4 = plat->uart_info->stm32f4; | |
47 | fdt_addr_t base = plat->base; | |
6a12cebd | 48 | |
60a996ba | 49 | if ((readl(base + ISR_OFFSET(stm32f4)) & USART_SR_FLAG_RXNE) == 0) |
6a12cebd VM |
50 | return -EAGAIN; |
51 | ||
60a996ba | 52 | return readl(base + RDR_OFFSET(stm32f4)); |
6a12cebd VM |
53 | } |
54 | ||
55 | static int stm32_serial_putc(struct udevice *dev, const char c) | |
56 | { | |
60a996ba PC |
57 | struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); |
58 | bool stm32f4 = plat->uart_info->stm32f4; | |
59 | fdt_addr_t base = plat->base; | |
6a12cebd | 60 | |
60a996ba | 61 | if ((readl(base + ISR_OFFSET(stm32f4)) & USART_SR_FLAG_TXE) == 0) |
6a12cebd VM |
62 | return -EAGAIN; |
63 | ||
60a996ba | 64 | writel(c, base + TDR_OFFSET(stm32f4)); |
6a12cebd VM |
65 | |
66 | return 0; | |
67 | } | |
68 | ||
69 | static int stm32_serial_pending(struct udevice *dev, bool input) | |
70 | { | |
60a996ba PC |
71 | struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); |
72 | bool stm32f4 = plat->uart_info->stm32f4; | |
73 | fdt_addr_t base = plat->base; | |
6a12cebd VM |
74 | |
75 | if (input) | |
60a996ba PC |
76 | return readl(base + ISR_OFFSET(stm32f4)) & |
77 | USART_SR_FLAG_RXNE ? 1 : 0; | |
6a12cebd | 78 | else |
60a996ba PC |
79 | return readl(base + ISR_OFFSET(stm32f4)) & |
80 | USART_SR_FLAG_TXE ? 0 : 1; | |
6a12cebd VM |
81 | } |
82 | ||
83 | static int stm32_serial_probe(struct udevice *dev) | |
84 | { | |
60a996ba | 85 | struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); |
9a212d7f | 86 | struct clk clk; |
60a996ba | 87 | fdt_addr_t base = plat->base; |
9a212d7f | 88 | int ret; |
60a996ba PC |
89 | bool stm32f4; |
90 | u8 uart_enable_bit; | |
91 | ||
92 | plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev); | |
93 | stm32f4 = plat->uart_info->stm32f4; | |
94 | uart_enable_bit = plat->uart_info->uart_enable_bit; | |
fd03b83a | 95 | |
fd03b83a VM |
96 | ret = clk_get_by_index(dev, 0, &clk); |
97 | if (ret < 0) | |
98 | return ret; | |
99 | ||
100 | ret = clk_enable(&clk); | |
101 | if (ret) { | |
102 | dev_err(dev, "failed to enable clock\n"); | |
103 | return ret; | |
104 | } | |
fd03b83a | 105 | |
27265cee PC |
106 | plat->clock_rate = clk_get_rate(&clk); |
107 | if (plat->clock_rate < 0) { | |
108 | clk_disable(&clk); | |
109 | return plat->clock_rate; | |
110 | }; | |
111 | ||
60a996ba PC |
112 | /* Disable uart-> disable overrun-> enable uart */ |
113 | clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | | |
114 | BIT(uart_enable_bit)); | |
115 | if (plat->uart_info->has_overrun_disable) | |
116 | setbits_le32(base + CR3_OFFSET(stm32f4), USART_CR3_OVRDIS); | |
2a7ecc53 PC |
117 | if (plat->uart_info->has_fifo) |
118 | setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_FIFOEN); | |
60a996ba PC |
119 | setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | |
120 | BIT(uart_enable_bit)); | |
6a12cebd VM |
121 | |
122 | return 0; | |
123 | } | |
124 | ||
42bf5e7c | 125 | static const struct udevice_id stm32_serial_id[] = { |
6c30f15b | 126 | { .compatible = "st,stm32-uart", .data = (ulong)&stm32f4_info}, |
2a7ecc53 PC |
127 | { .compatible = "st,stm32f7-uart", .data = (ulong)&stm32f7_info}, |
128 | { .compatible = "st,stm32h7-uart", .data = (ulong)&stm32h7_info}, | |
42bf5e7c VM |
129 | {} |
130 | }; | |
131 | ||
132 | static int stm32_serial_ofdata_to_platdata(struct udevice *dev) | |
133 | { | |
134 | struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); | |
42bf5e7c | 135 | |
60a996ba PC |
136 | plat->base = devfdt_get_addr(dev); |
137 | if (plat->base == FDT_ADDR_T_NONE) | |
42bf5e7c VM |
138 | return -EINVAL; |
139 | ||
42bf5e7c VM |
140 | return 0; |
141 | } | |
42bf5e7c | 142 | |
6a12cebd VM |
143 | static const struct dm_serial_ops stm32_serial_ops = { |
144 | .putc = stm32_serial_putc, | |
145 | .pending = stm32_serial_pending, | |
146 | .getc = stm32_serial_getc, | |
147 | .setbrg = stm32_serial_setbrg, | |
148 | }; | |
149 | ||
150 | U_BOOT_DRIVER(serial_stm32) = { | |
ae74de0d | 151 | .name = "serial_stm32", |
6a12cebd | 152 | .id = UCLASS_SERIAL, |
42bf5e7c VM |
153 | .of_match = of_match_ptr(stm32_serial_id), |
154 | .ofdata_to_platdata = of_match_ptr(stm32_serial_ofdata_to_platdata), | |
155 | .platdata_auto_alloc_size = sizeof(struct stm32x7_serial_platdata), | |
6a12cebd VM |
156 | .ops = &stm32_serial_ops, |
157 | .probe = stm32_serial_probe, | |
158 | .flags = DM_FLAG_PRE_RELOC, | |
159 | }; |