1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2017-2018, STMicroelectronics
*/
#include <compiler.h>
#include <console.h>
#include <drivers/serial.h>
#include <drivers/stm32_uart.h>
#include <io.h>
#include <keep.h>
#include <kernel/delay.h>
#include <kernel/dt.h>
#include <kernel/panic.h>
#include <stm32_util.h>
#include <util.h>
#define UART_REG_CR1 0x00 /* Control register 1 */
#define UART_REG_CR2 0x04 /* Control register 2 */
#define UART_REG_CR3 0x08 /* Control register 3 */
#define UART_REG_BRR 0x0c /* Baud rate register */
#define UART_REG_RQR 0x18 /* Request register */
#define UART_REG_ISR 0x1c /* Interrupt & status reg. */
#define UART_REG_ICR 0x20 /* Interrupt flag clear reg. */
#define UART_REG_RDR 0x24 /* Receive data register */
#define UART_REG_TDR 0x28 /* Transmit data register */
#define UART_REG_PRESC 0x2c /* Prescaler register */
#define PUTC_TIMEOUT_US 1000
#define FLUSH_TIMEOUT_US 16000
/*
* Uart Interrupt & status register bits
*
* Bit 5 RXNE: Read data register not empty/RXFIFO not empty
* Bit 6 TC: Transmission complete
* Bit 7 TXE/TXFNF: Transmit data register empty/TXFIFO not full
* Bit 27 TXFE: TXFIFO threshold reached
*/
#define USART_ISR_RXNE_RXFNE BIT(5)
#define USART_ISR_TC BIT(6)
#define USART_ISR_TXE_TXFNF BIT(7)
#define USART_ISR_TXFE BIT(27)
static vaddr_t loc_chip_to_base(struct serial_chip *chip)
{
struct stm32_uart_pdata *pd = NULL;
pd = container_of(chip, struct stm32_uart_pdata, chip);
return io_pa_or_va(&pd->base);
}
static void loc_flush(struct serial_chip *chip)
{
vaddr_t base = loc_chip_to_base(chip);
uint64_t timeout = timeout_init_us(FLUSH_TIMEOUT_US);
while (!(io_read32(base + UART_REG_ISR) & USART_ISR_TXFE))
if (timeout_elapsed(timeout))
return;
}
static void loc_putc(struct serial_chip *chip, int ch)
{
vaddr_t base = loc_chip_to_base(chip);
uint64_t timeout = timeout_init_us(PUTC_TIMEOUT_US);
while (!(io_read32(base + UART_REG_ISR) & USART_ISR_TXE_TXFNF))
if (timeout_elapsed(timeout))
return;
io_write32(base + UART_REG_TDR, ch);
}
static bool loc_have_rx_data(struct serial_chip *chip)
{
vaddr_t base = loc_chip_to_base(chip);
return io_read32(base + UART_REG_ISR) & USART_ISR_RXNE_RXFNE;
}
static int loc_getchar(struct serial_chip *chip)
{
vaddr_t base = loc_chip_to_base(chip);
while (!loc_have_rx_data(chip))
;
return io_read32(base + UART_REG_RDR) & 0xff;
}
static const struct serial_ops stm32_uart_serial_ops = {
.flush = loc_flush,
.putc = loc_putc,
.have_rx_data = loc_have_rx_data,
.getchar = loc_getchar,
};
KEEP_PAGER(stm32_uart_serial_ops);
void stm32_uart_init(struct stm32_uart_pdata *pd, vaddr_t base)
{
pd->base.pa = base;
pd->chip.ops = &stm32_uart_serial_ops;
}
#ifdef CFG_DT
static void register_secure_uart(struct stm32_uart_pdata *pd)
{
stm32mp_register_secure_periph_iomem(pd->base.pa);
}
static void register_non_secure_uart(struct stm32_uart_pdata *pd)
{
stm32mp_register_non_secure_periph_iomem(pd->base.pa);
}
struct stm32_uart_pdata *stm32_uart_init_from_dt_node(void *fdt, int node)
{
struct stm32_uart_pdata *pd = NULL;
struct dt_node_info info = { };
_fdt_fill_device_info(fdt, &info, node);
if (info.status == DT_STATUS_DISABLED)
return NULL;
assert(info.clock != DT_INFO_INVALID_CLOCK &&
info.reg != DT_INFO_INVALID_REG);
pd = calloc(1, sizeof(*pd));
if (!pd)
panic();
pd->chip.ops = &stm32_uart_serial_ops;
pd->base.pa = info.reg;
pd->secure = (info.status == DT_STATUS_OK_SEC);
pd->clock = (unsigned int)info.clock;
assert(cpu_mmu_enabled());
pd->base.va = (vaddr_t)phys_to_virt(pd->base.pa,
pd->secure ? MEM_AREA_IO_SEC :
MEM_AREA_IO_NSEC);
if (pd->secure)
register_secure_uart(pd);
else
register_non_secure_uart(pd);
return pd;
}
#endif /*CFG_DT*/
|