]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/serial/serial_stm32.c
8c613db95d5875a752e92ecbb7e7f3946eec1b79
[karo-tx-uboot.git] / drivers / serial / serial_stm32.c
1 /*
2  * (C) Copyright 2015
3  * Kamil Lulko, <rev13@wp.pl>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <asm/io.h>
10 #include <serial.h>
11 #include <asm/arch/stm32.h>
12
13 #define STM32_USART1_BASE       (STM32_APB2PERIPH_BASE + 0x1000)
14 #define RCC_APB2ENR_USART1EN    (1 << 4)
15
16 #define USART_BASE              STM32_USART1_BASE
17 #define RCC_USART_ENABLE        RCC_APB2ENR_USART1EN
18
19 struct stm32_serial {
20         u32 sr;
21         u32 dr;
22         u32 brr;
23         u32 cr1;
24         u32 cr2;
25         u32 cr3;
26         u32 gtpr;
27 };
28
29 #define USART_CR1_RE            (1 << 2)
30 #define USART_CR1_TE            (1 << 3)
31 #define USART_CR1_UE            (1 << 13)
32
33 #define USART_SR_FLAG_RXNE      (1 << 5)
34 #define USART_SR_FLAG_TXE       (1 << 7)
35
36 #define USART_BRR_F_MASK        0xF
37 #define USART_BRR_M_SHIFT       4
38 #define USART_BRR_M_MASK        0xFFF0
39
40 DECLARE_GLOBAL_DATA_PTR;
41
42 static void stm32_serial_setbrg(void)
43 {
44         serial_init();
45 }
46
47 static int stm32_serial_init(void)
48 {
49         struct stm32_serial *usart = (struct stm32_serial *)USART_BASE;
50         u32 clock, int_div, frac_div, tmp;
51
52         if ((USART_BASE & STM32_BUS_MASK) == STM32_APB1PERIPH_BASE) {
53                 setbits_le32(&STM32_RCC->apb1enr, RCC_USART_ENABLE);
54                 clock = clock_get(CLOCK_APB1);
55         } else if ((USART_BASE & STM32_BUS_MASK) == STM32_APB2PERIPH_BASE) {
56                 setbits_le32(&STM32_RCC->apb2enr, RCC_USART_ENABLE);
57                 clock = clock_get(CLOCK_APB2);
58         } else {
59                 return -1;
60         }
61
62         int_div = (25 * clock) / (4 * gd->baudrate);
63         tmp = ((int_div / 100) << USART_BRR_M_SHIFT) & USART_BRR_M_MASK;
64         frac_div = int_div - (100 * (tmp >> USART_BRR_M_SHIFT));
65         tmp |= (((frac_div * 16) + 50) / 100) & USART_BRR_F_MASK;
66
67         writel(tmp, &usart->brr);
68         setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
69
70         return 0;
71 }
72
73 static int stm32_serial_getc(void)
74 {
75         struct stm32_serial *usart = (struct stm32_serial *)USART_BASE;
76         while ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0)
77                 ;
78         return readl(&usart->dr);
79 }
80
81 static void stm32_serial_putc(const char c)
82 {
83         struct stm32_serial *usart = (struct stm32_serial *)USART_BASE;
84
85         if (c == '\n')
86                 stm32_serial_putc('\r');
87
88         while ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0)
89                 ;
90         writel(c, &usart->dr);
91 }
92
93 static int stm32_serial_tstc(void)
94 {
95         struct stm32_serial *usart = (struct stm32_serial *)USART_BASE;
96         u8 ret;
97
98         ret = readl(&usart->sr) & USART_SR_FLAG_RXNE;
99         return ret;
100 }
101
102 static struct serial_device stm32_serial_drv = {
103         .name   = "stm32_serial",
104         .start  = stm32_serial_init,
105         .stop   = NULL,
106         .setbrg = stm32_serial_setbrg,
107         .putc   = stm32_serial_putc,
108         .puts   = default_serial_puts,
109         .getc   = stm32_serial_getc,
110         .tstc   = stm32_serial_tstc,
111 };
112
113 void stm32_serial_initialize(void)
114 {
115         serial_register(&stm32_serial_drv);
116 }
117
118 __weak struct serial_device *default_serial_console(void)
119 {
120         return &stm32_serial_drv;
121 }