xref: /rk3399_rockchip-uboot/drivers/serial/serial_stm32.c (revision dffceb4b15e4c5fd2487e625a08062a8120bd17f)
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