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