1 /*
2  * Renesas SCP/MCP Software
3  * Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights
4  * reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "scif.h"
10 
11 #include <mmio.h>
12 #include <system_mmap.h>
13 
14 #include <mod_rcar_scif.h>
15 #include <mod_rcar_system.h>
16 
17 #include <fwk_mm.h>
18 #include <fwk_module.h>
19 #include <fwk_module_idx.h>
20 #include <fwk_notification.h>
21 #include <fwk_status.h>
22 
23 #include <assert.h>
24 
25 struct mod_rcar_scif_element_ctx {
26     /* Whether the device has an open file stream */
27     bool open;
28 };
29 
30 static struct mod_rcar_scif_ctx {
31     bool initialized; /* Whether the context has been initialized */
32 
33     struct mod_rcar_scif_element_ctx *elements; /* Element context table */
34 } mod_rcar_scif_ctx = {
35     .initialized = false,
36 };
37 
38 static const struct mod_rcar_scif_element_cfg *current_cfg;
39 
mod_rcar_scif_init_ctx(struct mod_rcar_scif_ctx * ctx)40 static int mod_rcar_scif_init_ctx(struct mod_rcar_scif_ctx *ctx)
41 {
42     size_t element_count;
43 
44     fwk_assert(!mod_rcar_scif_ctx.initialized);
45 
46     element_count = fwk_module_get_element_count(fwk_module_id_rcar_scif);
47     if (element_count == 0)
48         return FWK_SUCCESS;
49 
50     ctx->elements = fwk_mm_alloc(element_count, sizeof(ctx->elements[0]));
51     if (!fwk_expect(ctx->elements != NULL))
52         return FWK_E_NOMEM;
53 
54     for (size_t i = 0; i < element_count; i++) {
55         ctx->elements[i] = (struct mod_rcar_scif_element_ctx){
56             .open = false,
57         };
58     }
59 
60     mod_rcar_scif_ctx.initialized = true;
61 
62     return FWK_SUCCESS;
63 }
64 
65 /*
66  * For details on the constants and equations used to calculate the baud rate
67  * settings, please consult the SCIF TRM.
68  * However, this version does not support it.
69  */
mod_rcar_scif_set_baud_rate(const struct mod_rcar_scif_element_cfg * cfg)70 static int mod_rcar_scif_set_baud_rate(
71     const struct mod_rcar_scif_element_cfg *cfg)
72 {
73     struct scif_reg *reg = (void *)cfg->reg_base;
74     uint32_t status;
75     int i;
76 
77     assert(reg);
78     current_cfg = cfg;
79 
80     if (reg == (void *)BOARD_UART1_BASE) {
81         /* SCSI-1 */
82         status = mmio_read_32(CPG_SMSTPCR2);
83         status = (status & ~MSTP26);
84         mmio_write_32(CPG_CPGWPR, ~status);
85         mmio_write_32(CPG_SMSTPCR2, status);
86 
87         while (mmio_read_32(CPG_MSTPSR2) & MSTP26)
88             continue;
89     } else if (reg == (void *)BOARD_UART2_BASE) {
90         /* SCSI-2 */
91         status = mmio_read_32(CPG_SMSTPCR3);
92         status = (status & ~MSTP310);
93         mmio_write_32(CPG_CPGWPR, ~status);
94         mmio_write_32(CPG_SMSTPCR3, status);
95 
96         while (mmio_read_32(CPG_MSTPSR3) & MSTP310)
97             continue;
98     } else {
99         return FWK_E_PARAM;
100     }
101 
102     /* Clear bits TE and RE in SCSCR to 0 */
103     reg->SCSCR = (SCSCR_TE_DIS | SCSCR_RE_DIS);
104     /* Set bits TFRST and RFRST in SCFCR to 1 */
105     reg->SCFCR |= (SCFCR_TFRST_EN | SCFCR_RFRS_EN);
106     /* Read flags of ER, DR, BRK, */
107     reg->SCFSR = SCFSR_INIT_DATA;
108     reg->SCLSR = 0;
109     /* Set bits CKE[1:0] in SCSCR */
110     reg->SCSCR = (reg->SCSCR & ~SCSCR_CKE_MASK) | SCSCR_CKE_INT_CLK;
111     /* Set data transfer format in SCSMR */
112     reg->SCSMR = SCSMR_INIT_DATA;
113     /* Set value in SCBRR */
114 #if SCIF_CLK == SCIF_INTERNAL_CLK
115     if ((mmio_read_32(PRR) & (PRR_PRODUCT_MASK | PRR_CUT_MASK)) ==
116         PRR_PRODUCT_H3_VER_10) {
117         /* H3 Ver.1.0 sets clock to doubling */
118         reg->SCBRR = SCBRR_230400BPS;
119     } else {
120         reg->SCBRR = SCBRR_115200BPS;
121     }
122 #else
123     reg->DL = DL_INIT_DATA;
124     reg->CKS = CKS_INIT_DATA;
125 #endif /* SCIF_CLK == SCIF_INTERNAL_CLK */
126     for (i = 100; i; i--)
127         ;
128     reg->SCFCR = SCFCR_INIT_DATA;
129     reg->SCSCR = (reg->SCSCR | (SCSCR_TE_EN | SCSCR_RE_EN));
130     return FWK_SUCCESS;
131 }
132 
mod_rcar_scif_resume(void)133 static int mod_rcar_scif_resume(void)
134 {
135     return mod_rcar_scif_set_baud_rate(current_cfg);
136 }
137 
mod_rcar_scif_putch(fwk_id_t id,char c)138 static void mod_rcar_scif_putch(fwk_id_t id, char c)
139 {
140     const struct mod_rcar_scif_element_cfg *cfg = fwk_module_get_data(id);
141     struct scif_reg *reg = (void *)cfg->reg_base;
142 
143     /* Check if the transmit FIFO is full */
144     while (GET_SCFDR_T(reg) >= FIFO_FULL)
145         continue;
146 
147     reg->SCFTDR = c;
148 }
149 
mod_rcar_scif_getch(fwk_id_t id,char * ch)150 static bool mod_rcar_scif_getch(fwk_id_t id, char *ch)
151 {
152     return false; /* Not implemented yet */
153 }
154 
mod_rcar_scif_flush(fwk_id_t id)155 static void mod_rcar_scif_flush(fwk_id_t id)
156 {
157     const struct mod_rcar_scif_element_cfg *cfg = fwk_module_get_data(id);
158     struct scif_reg *reg = (void *)cfg->reg_base;
159 
160     /* Check if the transmit data is available */
161     while (GET_SCFDR_T(reg))
162         continue;
163 }
164 
165 /*
166  * Framework module handlers
167  */
mod_rcar_scif_init(fwk_id_t module_id,unsigned int element_count,const void * data)168 static int mod_rcar_scif_init(
169     fwk_id_t module_id,
170     unsigned int element_count,
171     const void *data)
172 {
173     if (mod_rcar_scif_ctx.initialized)
174         return FWK_SUCCESS;
175 
176     return mod_rcar_scif_init_ctx(&mod_rcar_scif_ctx);
177 }
178 
mod_rcar_scif_element_init(fwk_id_t element_id,unsigned int unused,const void * data)179 static int mod_rcar_scif_element_init(
180     fwk_id_t element_id,
181     unsigned int unused,
182     const void *data)
183 {
184     return FWK_SUCCESS;
185 }
186 
mod_rcar_scif_start(fwk_id_t id)187 static int mod_rcar_scif_start(fwk_id_t id)
188 {
189     return FWK_SUCCESS;
190 }
191 
192 /*
193  * Framework io handlers
194  */
mod_rcar_scif_io_open(const struct fwk_io_stream * stream)195 static int mod_rcar_scif_io_open(const struct fwk_io_stream *stream)
196 {
197     int status;
198     struct mod_rcar_scif_element_ctx *ctx;
199     const struct mod_rcar_scif_element_cfg *cfg;
200 
201     if (!fwk_id_is_type(stream->id, FWK_ID_TYPE_ELEMENT))
202         return FWK_E_SUPPORT;
203 
204     if (!mod_rcar_scif_ctx.initialized) {
205         status = mod_rcar_scif_init_ctx(&mod_rcar_scif_ctx);
206         if (status != FWK_SUCCESS)
207             return FWK_E_STATE;
208     }
209 
210     ctx = &mod_rcar_scif_ctx.elements[fwk_id_get_element_idx(stream->id)];
211     if (ctx->open) /* Refuse to open the same device twice */
212         return FWK_E_BUSY;
213 
214     ctx->open = true;
215 
216     /* Enable the device if possible */
217     cfg = fwk_module_get_data(stream->id);
218     status = mod_rcar_scif_set_baud_rate(cfg);
219 
220     return status;
221 }
222 
mod_rcar_scif_io_getch(const struct fwk_io_stream * restrict stream,char * restrict ch)223 static int mod_rcar_scif_io_getch(
224     const struct fwk_io_stream *restrict stream,
225     char *restrict ch)
226 {
227     const struct mod_rcar_scif_element_ctx *ctx =
228         &mod_rcar_scif_ctx.elements[fwk_id_get_element_idx(stream->id)];
229 
230     bool ok = true;
231 
232     fwk_assert(ctx->open);
233 
234     ok = mod_rcar_scif_getch(stream->id, ch);
235     if (!ok)
236         return FWK_PENDING;
237 
238     return FWK_SUCCESS;
239 }
240 
mod_rcar_scif_io_putch(const struct fwk_io_stream * stream,char ch)241 static int mod_rcar_scif_io_putch(const struct fwk_io_stream *stream, char ch)
242 {
243     const struct mod_rcar_scif_element_ctx *ctx =
244         &mod_rcar_scif_ctx.elements[fwk_id_get_element_idx(stream->id)];
245 
246     fwk_assert(ctx->open);
247 
248     if ((ch == '\n') && !(stream->mode & FWK_IO_MODE_BINARY))
249         mod_rcar_scif_putch(stream->id, '\r'); /* Prepend carriage return */
250 
251     mod_rcar_scif_putch(stream->id, ch);
252 
253     return FWK_SUCCESS;
254 }
255 
mod_rcar_scif_io_close(const struct fwk_io_stream * stream)256 static int mod_rcar_scif_io_close(const struct fwk_io_stream *stream)
257 {
258     struct mod_rcar_scif_element_ctx *ctx;
259 
260     fwk_assert(stream != NULL); /* Validated by the framework */
261     fwk_assert(fwk_module_is_valid_element_id(stream->id));
262 
263     mod_rcar_scif_flush(stream->id);
264 
265     ctx = &mod_rcar_scif_ctx.elements[fwk_id_get_element_idx(stream->id)];
266     fwk_assert(ctx->open);
267 
268     ctx->open = false;
269 
270     return FWK_SUCCESS;
271 }
272 
273 static const struct mod_rcar_system_drv_api api_system = {
274     .resume = mod_rcar_scif_resume,
275 };
276 
scif_process_bind_request(fwk_id_t requester_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)277 static int scif_process_bind_request(fwk_id_t requester_id, fwk_id_t target_id,
278     fwk_id_t api_id, const void **api)
279 {
280     switch (fwk_id_get_api_idx(api_id)) {
281     case MOD_RCAR_SCIF_API_TYPE_SYSTEM:
282         *api = &api_system;
283         break;
284     default:
285         break;
286     }
287 
288     return FWK_SUCCESS;
289 }
290 
291 const struct fwk_module module_rcar_scif = {
292     .type = FWK_MODULE_TYPE_DRIVER,
293     .api_count = MOD_RCAR_SCIF_API_COUNT,
294     .init = mod_rcar_scif_init,
295     .element_init = mod_rcar_scif_element_init,
296     .start = mod_rcar_scif_start,
297     .adapter =
298         (struct fwk_io_adapter){
299             .open = mod_rcar_scif_io_open,
300             .getch = mod_rcar_scif_io_getch,
301             .putch = mod_rcar_scif_io_putch,
302             .close = mod_rcar_scif_io_close,
303         },
304     .process_bind_request = scif_process_bind_request,
305 };
306