1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "f_uart3.h"
9
10 #include <mod_f_uart3.h>
11
12 #include <fwk_mm.h>
13 #include <fwk_module.h>
14 #include <fwk_module_idx.h>
15 #include <fwk_status.h>
16
17 #include <fmw_cmsis.h>
18
19 #include <stdbool.h>
20
21 struct mod_f_uart3_element_ctx {
22 /* Whether the device has an open file stream */
23 bool open;
24 };
25
26 static struct mod_f_uart3_ctx {
27 bool initialized; /* Whether the context has been initialized */
28
29 struct mod_f_uart3_element_ctx *elements; /* Element context table */
30 } mod_f_uart3_ctx = {
31 .initialized = false,
32 };
33
34 static const struct {
35 uint8_t DLM;
36 uint8_t DLL;
37 } mod_f_uart3_divider_latch_table[] = {
38 [MOD_F_UART3_BAUD_RATE_9600] = {
39 .DLM = F_UART3_DLM_9600,
40 .DLL = F_UART3_DLL_9600,
41 },
42
43 [MOD_F_UART3_BAUD_RATE_19200] = {
44 .DLM = F_UART3_DLM_19200,
45 .DLL = F_UART3_DLL_19200,
46 },
47
48 [MOD_F_UART3_BAUD_RATE_38400] = {
49 .DLM = F_UART3_DLM_38400,
50 .DLL = F_UART3_DLL_38400,
51 },
52
53 [MOD_F_UART3_BAUD_RATE_57600] = {
54 .DLM = F_UART3_DLM_57600,
55 .DLL = F_UART3_DLL_57600,
56 },
57
58 [MOD_F_UART3_BAUD_RATE_115200] = {
59 .DLM = F_UART3_DLM_115200,
60 .DLL = F_UART3_DLL_115200,
61 },
62
63 [MOD_F_UART3_BAUD_RATE_230400] = {
64 .DLM = F_UART3_DLM_230400,
65 .DLL = F_UART3_DLL_230400,
66 },
67 };
68
mod_f_uart3_init_ctx(struct mod_f_uart3_ctx * ctx)69 static int mod_f_uart3_init_ctx(struct mod_f_uart3_ctx *ctx)
70 {
71 size_t element_count;
72
73 fwk_assert(!mod_f_uart3_ctx.initialized);
74
75 element_count = fwk_module_get_element_count(fwk_module_id_f_uart3);
76 if (element_count == 0)
77 return FWK_SUCCESS;
78
79 ctx->elements = fwk_mm_alloc(element_count, sizeof(ctx->elements[0]));
80 if (!fwk_expect(ctx->elements != NULL))
81 return FWK_E_NOMEM;
82
83 for (size_t i = 0; i < element_count; i++) {
84 ctx->elements[i] = (struct mod_f_uart3_element_ctx){
85 .open = false, /* Assume the device is always powered */
86 };
87 }
88
89 mod_f_uart3_ctx.initialized = true;
90
91 return FWK_SUCCESS;
92 }
93
mod_f_uart3_enable(fwk_id_t id)94 static void mod_f_uart3_enable(fwk_id_t id)
95 {
96 const struct mod_f_uart3_element_cfg *cfg = fwk_module_get_data(id);
97
98 struct f_uart3_reg *reg;
99 struct f_uart3_dla_reg *dla_reg;
100
101 fwk_assert(cfg != NULL);
102
103 reg = (struct f_uart3_reg *)cfg->reg_base;
104 dla_reg = (struct f_uart3_dla_reg *)cfg->dla_reg_base;
105
106 /* Set DLAB */
107 reg->LCR |= F_UART3_LCR_DLAB;
108
109 __DSB();
110
111 dla_reg->DLL = mod_f_uart3_divider_latch_table[cfg->baud_rate].DLL;
112 dla_reg->DLM = mod_f_uart3_divider_latch_table[cfg->baud_rate].DLM;
113
114 __DSB();
115
116 /* Clear DLAB */
117 reg->LCR &= ~F_UART3_LCR_DLAB;
118
119 __DSB();
120
121 reg->LCR = F_UART3_LCR_WLS_8;
122 if (cfg->parity_enable_flag) {
123 reg->LCR |= F_UART3_LCR_PEN;
124 if (cfg->even_parity_flag)
125 reg->LCR |= F_UART3_LCR_EPS;
126 }
127
128 __DSB();
129
130 /* Disable interrupt */
131 reg->IER = 0x0;
132
133 __DSB();
134
135 /* FIFO Reset */
136 reg->IIR_FCR = (F_UART3_FCR_RXFRST | F_UART3_FCR_TXFRST);
137
138 __DSB();
139 }
140
mod_f_uart3_putch(fwk_id_t id,char ch)141 static void mod_f_uart3_putch(fwk_id_t id, char ch)
142 {
143 const struct mod_f_uart3_element_cfg *cfg = fwk_module_get_data(id);
144
145 struct f_uart3_reg *reg = (void *)cfg->reg_base;
146
147 while ((reg->LSR & F_UART3_LSR_THRE) == 0x0)
148 continue;
149
150 reg->RFR_TFR = ch;
151 }
152
mod_f_uart3_flush(fwk_id_t id)153 static void mod_f_uart3_flush(fwk_id_t id)
154 {
155 const struct mod_f_uart3_element_cfg *cfg = fwk_module_get_data(id);
156
157 struct f_uart3_reg *reg = (void *)cfg->reg_base;
158
159 while ((reg->LSR & F_UART3_LSR_TEMT) == 0x0)
160 continue;
161 }
162
mod_f_uart3_init(fwk_id_t module_id,unsigned int element_count,const void * data)163 static int mod_f_uart3_init(
164 fwk_id_t module_id,
165 unsigned int element_count,
166 const void *data)
167 {
168 if (mod_f_uart3_ctx.initialized)
169 return FWK_SUCCESS;
170
171 return mod_f_uart3_init_ctx(&mod_f_uart3_ctx);
172 }
173
mod_f_uart3_element_init(fwk_id_t element_id,unsigned int unused,const void * data)174 static int mod_f_uart3_element_init(
175 fwk_id_t element_id,
176 unsigned int unused,
177 const void *data)
178 {
179 return FWK_SUCCESS;
180 }
181
mod_f_uart3_io_open(const struct fwk_io_stream * stream)182 static int mod_f_uart3_io_open(const struct fwk_io_stream *stream)
183 {
184 int status;
185
186 struct mod_f_uart3_element_ctx *ctx;
187
188 if (!fwk_id_is_type(stream->id, FWK_ID_TYPE_ELEMENT))
189 return FWK_E_SUPPORT;
190
191 if (!mod_f_uart3_ctx.initialized) {
192 status = mod_f_uart3_init_ctx(&mod_f_uart3_ctx);
193 if (status != FWK_SUCCESS)
194 return FWK_E_STATE;
195 }
196
197 ctx = &mod_f_uart3_ctx.elements[fwk_id_get_element_idx(stream->id)];
198 if (ctx->open) /* Refuse to open the same device twice */
199 return FWK_E_BUSY;
200
201 ctx->open = true;
202
203 mod_f_uart3_enable(stream->id); /* Enable the device */
204
205 return FWK_SUCCESS;
206 }
207
mod_f_uart3_io_putch(const struct fwk_io_stream * stream,char ch)208 int mod_f_uart3_io_putch(const struct fwk_io_stream *stream, char ch)
209 {
210 const struct mod_f_uart3_element_ctx *ctx =
211 &mod_f_uart3_ctx.elements[fwk_id_get_element_idx(stream->id)];
212
213 fwk_assert(ctx->open);
214
215 if ((ch == '\n') && !(stream->mode & FWK_IO_MODE_BINARY))
216 mod_f_uart3_putch(stream->id, '\r'); /* Prepend carriage return */
217
218 mod_f_uart3_putch(stream->id, ch);
219
220 return FWK_SUCCESS;
221 }
222
mod_f_uart3_close(const struct fwk_io_stream * stream)223 int mod_f_uart3_close(const struct fwk_io_stream *stream)
224 {
225 struct mod_f_uart3_element_ctx *ctx;
226
227 fwk_assert(stream != NULL); /* Validated by the framework */
228 fwk_assert(fwk_module_is_valid_element_id(stream->id));
229
230 mod_f_uart3_flush(stream->id);
231
232 ctx = &mod_f_uart3_ctx.elements[fwk_id_get_element_idx(stream->id)];
233 fwk_assert(ctx->open);
234
235 ctx->open = false;
236
237 return FWK_SUCCESS;
238 }
239
240 const struct fwk_module module_f_uart3 = {
241 .type = FWK_MODULE_TYPE_DRIVER,
242
243 .init = mod_f_uart3_init,
244 .element_init = mod_f_uart3_element_init,
245
246 .adapter =
247 (struct fwk_io_adapter){
248 .open = mod_f_uart3_io_open,
249 .putch = mod_f_uart3_io_putch,
250 .close = mod_f_uart3_close,
251 },
252 };
253