1ab3f0c7dSrev13@wp.pl /*
2ab3f0c7dSrev13@wp.pl * (C) Copyright 2015
3*66562414SKamil Lulko * Kamil Lulko, <kamil.lulko@gmail.com>
4ab3f0c7dSrev13@wp.pl *
5ab3f0c7dSrev13@wp.pl * SPDX-License-Identifier: GPL-2.0+
6ab3f0c7dSrev13@wp.pl */
7ab3f0c7dSrev13@wp.pl
8ab3f0c7dSrev13@wp.pl #include <common.h>
9*66562414SKamil Lulko #include <dm.h>
10ab3f0c7dSrev13@wp.pl #include <asm/io.h>
11ab3f0c7dSrev13@wp.pl #include <serial.h>
12ab3f0c7dSrev13@wp.pl #include <asm/arch/stm32.h>
13*66562414SKamil Lulko #include <dm/platform_data/serial_stm32.h>
14ab3f0c7dSrev13@wp.pl
15*66562414SKamil Lulko struct stm32_usart {
16ab3f0c7dSrev13@wp.pl u32 sr;
17ab3f0c7dSrev13@wp.pl u32 dr;
18ab3f0c7dSrev13@wp.pl u32 brr;
19ab3f0c7dSrev13@wp.pl u32 cr1;
20ab3f0c7dSrev13@wp.pl u32 cr2;
21ab3f0c7dSrev13@wp.pl u32 cr3;
22ab3f0c7dSrev13@wp.pl u32 gtpr;
23ab3f0c7dSrev13@wp.pl };
24ab3f0c7dSrev13@wp.pl
25ab3f0c7dSrev13@wp.pl #define USART_CR1_RE (1 << 2)
26ab3f0c7dSrev13@wp.pl #define USART_CR1_TE (1 << 3)
27ab3f0c7dSrev13@wp.pl #define USART_CR1_UE (1 << 13)
28ab3f0c7dSrev13@wp.pl
29ab3f0c7dSrev13@wp.pl #define USART_SR_FLAG_RXNE (1 << 5)
30ab3f0c7dSrev13@wp.pl #define USART_SR_FLAG_TXE (1 << 7)
31ab3f0c7dSrev13@wp.pl
32ab3f0c7dSrev13@wp.pl #define USART_BRR_F_MASK 0xF
33ab3f0c7dSrev13@wp.pl #define USART_BRR_M_SHIFT 4
34ab3f0c7dSrev13@wp.pl #define USART_BRR_M_MASK 0xFFF0
35ab3f0c7dSrev13@wp.pl
36ab3f0c7dSrev13@wp.pl DECLARE_GLOBAL_DATA_PTR;
37ab3f0c7dSrev13@wp.pl
stm32_serial_setbrg(struct udevice * dev,int baudrate)38*66562414SKamil Lulko static int stm32_serial_setbrg(struct udevice *dev, int baudrate)
39ab3f0c7dSrev13@wp.pl {
40*66562414SKamil Lulko struct stm32_serial_platdata *plat = dev->platdata;
41*66562414SKamil Lulko struct stm32_usart *const usart = plat->base;
42ab3f0c7dSrev13@wp.pl u32 clock, int_div, frac_div, tmp;
43ab3f0c7dSrev13@wp.pl
44*66562414SKamil Lulko if (((u32)usart & STM32_BUS_MASK) == STM32_APB1PERIPH_BASE)
45ab3f0c7dSrev13@wp.pl clock = clock_get(CLOCK_APB1);
46*66562414SKamil Lulko else if (((u32)usart & STM32_BUS_MASK) == STM32_APB2PERIPH_BASE)
47ab3f0c7dSrev13@wp.pl clock = clock_get(CLOCK_APB2);
48*66562414SKamil Lulko else
49*66562414SKamil Lulko return -EINVAL;
50ab3f0c7dSrev13@wp.pl
51*66562414SKamil Lulko int_div = (25 * clock) / (4 * baudrate);
52ab3f0c7dSrev13@wp.pl tmp = ((int_div / 100) << USART_BRR_M_SHIFT) & USART_BRR_M_MASK;
53ab3f0c7dSrev13@wp.pl frac_div = int_div - (100 * (tmp >> USART_BRR_M_SHIFT));
54ab3f0c7dSrev13@wp.pl tmp |= (((frac_div * 16) + 50) / 100) & USART_BRR_F_MASK;
55ab3f0c7dSrev13@wp.pl writel(tmp, &usart->brr);
56*66562414SKamil Lulko
57*66562414SKamil Lulko return 0;
58*66562414SKamil Lulko }
59*66562414SKamil Lulko
stm32_serial_getc(struct udevice * dev)60*66562414SKamil Lulko static int stm32_serial_getc(struct udevice *dev)
61*66562414SKamil Lulko {
62*66562414SKamil Lulko struct stm32_serial_platdata *plat = dev->platdata;
63*66562414SKamil Lulko struct stm32_usart *const usart = plat->base;
64*66562414SKamil Lulko
65*66562414SKamil Lulko if ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0)
66*66562414SKamil Lulko return -EAGAIN;
67*66562414SKamil Lulko
68*66562414SKamil Lulko return readl(&usart->dr);
69*66562414SKamil Lulko }
70*66562414SKamil Lulko
stm32_serial_putc(struct udevice * dev,const char c)71*66562414SKamil Lulko static int stm32_serial_putc(struct udevice *dev, const char c)
72*66562414SKamil Lulko {
73*66562414SKamil Lulko struct stm32_serial_platdata *plat = dev->platdata;
74*66562414SKamil Lulko struct stm32_usart *const usart = plat->base;
75*66562414SKamil Lulko
76*66562414SKamil Lulko if ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0)
77*66562414SKamil Lulko return -EAGAIN;
78*66562414SKamil Lulko
79*66562414SKamil Lulko writel(c, &usart->dr);
80*66562414SKamil Lulko
81*66562414SKamil Lulko return 0;
82*66562414SKamil Lulko }
83*66562414SKamil Lulko
stm32_serial_pending(struct udevice * dev,bool input)84*66562414SKamil Lulko static int stm32_serial_pending(struct udevice *dev, bool input)
85*66562414SKamil Lulko {
86*66562414SKamil Lulko struct stm32_serial_platdata *plat = dev->platdata;
87*66562414SKamil Lulko struct stm32_usart *const usart = plat->base;
88*66562414SKamil Lulko
89*66562414SKamil Lulko if (input)
90*66562414SKamil Lulko return readl(&usart->sr) & USART_SR_FLAG_RXNE ? 1 : 0;
91*66562414SKamil Lulko else
92*66562414SKamil Lulko return readl(&usart->sr) & USART_SR_FLAG_TXE ? 0 : 1;
93*66562414SKamil Lulko }
94*66562414SKamil Lulko
stm32_serial_probe(struct udevice * dev)95*66562414SKamil Lulko static int stm32_serial_probe(struct udevice *dev)
96*66562414SKamil Lulko {
97*66562414SKamil Lulko struct stm32_serial_platdata *plat = dev->platdata;
98*66562414SKamil Lulko struct stm32_usart *const usart = plat->base;
99ab3f0c7dSrev13@wp.pl setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
100ab3f0c7dSrev13@wp.pl
101ab3f0c7dSrev13@wp.pl return 0;
102ab3f0c7dSrev13@wp.pl }
103ab3f0c7dSrev13@wp.pl
104*66562414SKamil Lulko static const struct dm_serial_ops stm32_serial_ops = {
105ab3f0c7dSrev13@wp.pl .putc = stm32_serial_putc,
106*66562414SKamil Lulko .pending = stm32_serial_pending,
107ab3f0c7dSrev13@wp.pl .getc = stm32_serial_getc,
108*66562414SKamil Lulko .setbrg = stm32_serial_setbrg,
109ab3f0c7dSrev13@wp.pl };
110ab3f0c7dSrev13@wp.pl
111*66562414SKamil Lulko U_BOOT_DRIVER(serial_stm32) = {
112*66562414SKamil Lulko .name = "serial_stm32",
113*66562414SKamil Lulko .id = UCLASS_SERIAL,
114*66562414SKamil Lulko .ops = &stm32_serial_ops,
115*66562414SKamil Lulko .probe = stm32_serial_probe,
116*66562414SKamil Lulko .flags = DM_FLAG_PRE_RELOC,
117*66562414SKamil Lulko };
118