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