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