1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #include <mod_i2c.h>
8 
9 #include <fwk_assert.h>
10 #include <fwk_core.h>
11 #include <fwk_event.h>
12 #include <fwk_id.h>
13 #include <fwk_mm.h>
14 #include <fwk_module.h>
15 #include <fwk_module_idx.h>
16 #include <fwk_status.h>
17 
18 #include <stdbool.h>
19 #include <string.h>
20 
21 enum mod_i2c_dev_state {
22     MOD_I2C_DEV_IDLE,
23     MOD_I2C_DEV_TX,
24     MOD_I2C_DEV_RX,
25     MOD_I2C_DEV_TX_RX,
26     MOD_I2C_DEV_RELOAD,
27     MOD_I2C_DEV_PANIC,
28 };
29 
30 struct mod_i2c_dev_ctx {
31     const struct mod_i2c_dev_config *config;
32     const struct mod_i2c_driver_api *driver_api;
33     struct mod_i2c_request request;
34     enum mod_i2c_dev_state state;
35 };
36 
37 static struct mod_i2c_dev_ctx *ctx_table;
38 
39 enum mod_i2c_internal_event_idx {
40     MOD_I2C_EVENT_IDX_REQUEST_COMPLETED = MOD_I2C_EVENT_IDX_COUNT,
41     MOD_I2C_EVENT_IDX_RELOAD,
42     MOD_I2C_EVENT_IDX_TOTAL_COUNT,
43 };
44 
45 /*! Request completed event identifier */
46 static const fwk_id_t mod_i2c_event_id_request_completed = FWK_ID_EVENT_INIT(
47     FWK_MODULE_IDX_I2C, MOD_I2C_EVENT_IDX_REQUEST_COMPLETED);
48 
49 /*! Reload event identifier */
50 static const fwk_id_t mod_i2c_event_id_reload = FWK_ID_EVENT_INIT(
51     FWK_MODULE_IDX_I2C, MOD_I2C_EVENT_IDX_RELOAD);
52 
53 /*
54  * Static helpers
55  */
get_ctx(fwk_id_t id,struct mod_i2c_dev_ctx ** ctx)56 static void get_ctx(fwk_id_t id, struct mod_i2c_dev_ctx **ctx)
57 {
58     fwk_assert(fwk_module_is_valid_element_id(id));
59 
60     *ctx = ctx_table + fwk_id_get_element_idx(id);
61 }
62 
create_i2c_request(fwk_id_t dev_id,struct mod_i2c_request * request)63 static int create_i2c_request(fwk_id_t dev_id,
64                               struct mod_i2c_request *request)
65 {
66     int status;
67     struct fwk_event event;
68     struct mod_i2c_request *event_param =
69         (struct mod_i2c_request *)event.params;
70 
71     /* The target address should be on 7 bits */
72     if (!fwk_expect(request->target_address < 0x80)) {
73         return FWK_E_PARAM;
74     }
75 
76     event = (struct fwk_event) {
77         .target_id = dev_id,
78         .response_requested = true,
79     };
80 
81     *event_param = *request;
82 
83     if ((request->transmit_byte_count > 0) &&
84         (request->receive_byte_count > 0)) {
85         event.id = mod_i2c_event_id_request_tx_rx;
86     } else if (request->transmit_byte_count > 0) {
87         event.id = mod_i2c_event_id_request_tx;
88     } else if (request->receive_byte_count > 0) {
89         event.id = mod_i2c_event_id_request_rx;
90     }
91 
92     status = fwk_put_event(&event);
93     if (status == FWK_SUCCESS) {
94         /*
95          * The request has been successfully queued for later processing by the
96          * I2C device but processing of this request has not yet begun. The
97          * caller is notified that the I2C request is in progress.
98          */
99         return FWK_PENDING;
100     }
101 
102     return status;
103 }
104 
105 /*
106  * I2C API
107  */
transmit_as_controller(fwk_id_t dev_id,uint8_t target_address,uint8_t * data,uint8_t byte_count)108 static int transmit_as_controller(
109     fwk_id_t dev_id,
110     uint8_t target_address,
111     uint8_t *data,
112     uint8_t byte_count)
113 {
114     if (!fwk_expect(byte_count != 0)) {
115         return FWK_E_PARAM;
116     }
117 
118     if (!fwk_expect(data != NULL)) {
119         return FWK_E_PARAM;
120     }
121 
122     struct mod_i2c_request request = {
123         .target_address = target_address,
124         .transmit_data = data,
125         .transmit_byte_count = byte_count,
126     };
127 
128     return create_i2c_request(dev_id, &request);
129 }
130 
receive_as_controller(fwk_id_t dev_id,uint8_t target_address,uint8_t * data,uint8_t byte_count)131 static int receive_as_controller(
132     fwk_id_t dev_id,
133     uint8_t target_address,
134     uint8_t *data,
135     uint8_t byte_count)
136 {
137     if (!fwk_expect(byte_count != 0)) {
138         return FWK_E_PARAM;
139     }
140 
141     if (!fwk_expect(data != NULL)) {
142         return FWK_E_PARAM;
143     }
144 
145     struct mod_i2c_request request = {
146         .target_address = target_address,
147         .receive_data = data,
148         .receive_byte_count = byte_count,
149     };
150 
151     return create_i2c_request(dev_id, &request);
152 }
153 
transmit_then_receive_as_controller(fwk_id_t dev_id,uint8_t target_address,uint8_t * transmit_data,uint8_t * receive_data,uint8_t transmit_byte_count,uint8_t receive_byte_count)154 static int transmit_then_receive_as_controller(
155     fwk_id_t dev_id,
156     uint8_t target_address,
157     uint8_t *transmit_data,
158     uint8_t *receive_data,
159     uint8_t transmit_byte_count,
160     uint8_t receive_byte_count)
161 {
162     if (!fwk_expect((transmit_byte_count != 0) && (receive_byte_count != 0))) {
163         return FWK_E_PARAM;
164     }
165 
166     if (!fwk_expect((transmit_data != NULL) && (receive_data != NULL))) {
167         return FWK_E_PARAM;
168     }
169 
170     struct mod_i2c_request request = {
171         .target_address = target_address,
172         .transmit_data = transmit_data,
173         .receive_data = receive_data,
174         .transmit_byte_count = transmit_byte_count,
175         .receive_byte_count = receive_byte_count,
176     };
177 
178     return create_i2c_request(dev_id, &request);
179 }
180 
181 static struct mod_i2c_api i2c_api = {
182     .transmit_as_controller = transmit_as_controller,
183     .receive_as_controller = receive_as_controller,
184     .transmit_then_receive_as_controller = transmit_then_receive_as_controller,
185 };
186 
187 /*
188  * Driver response API
189  */
transaction_completed(fwk_id_t dev_id,int i2c_status)190 static void transaction_completed(fwk_id_t dev_id, int i2c_status)
191 {
192     int status;
193     struct fwk_event event;
194     struct mod_i2c_event_param* param =
195         (struct mod_i2c_event_param *)event.params;
196 
197     event = (struct fwk_event) {
198         .target_id = dev_id,
199         .source_id = dev_id,
200         .id = mod_i2c_event_id_request_completed,
201     };
202 
203     param->status = i2c_status;
204 
205     status = fwk_put_event(&event);
206     fwk_assert(status == FWK_SUCCESS);
207 }
208 
209 static struct mod_i2c_driver_response_api driver_response_api = {
210     .transaction_completed = transaction_completed,
211 };
212 
213 /*
214  * Framework handlers
215  */
mod_i2c_init(fwk_id_t module_id,unsigned int element_count,const void * unused)216 static int mod_i2c_init(fwk_id_t module_id,
217                         unsigned int element_count,
218                         const void *unused)
219 {
220     ctx_table = fwk_mm_calloc(element_count, sizeof(ctx_table[0]));
221 
222     return FWK_SUCCESS;
223 }
224 
mod_i2c_dev_init(fwk_id_t element_id,unsigned int unused,const void * data)225 static int mod_i2c_dev_init(fwk_id_t element_id,
226                             unsigned int unused,
227                             const void *data)
228 {
229     struct mod_i2c_dev_ctx *ctx;
230 
231     ctx = ctx_table + fwk_id_get_element_idx(element_id);
232     ctx->config = (struct mod_i2c_dev_config *)data;
233 
234     return FWK_SUCCESS;
235 }
236 
mod_i2c_bind(fwk_id_t id,unsigned int round)237 static int mod_i2c_bind(fwk_id_t id, unsigned int round)
238 {
239     int status;
240     struct mod_i2c_dev_ctx *ctx;
241 
242     /*
243      * Only bind in first round of calls
244      * Nothing to do for module
245      */
246     if ((round > 0) || fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
247         return FWK_SUCCESS;
248     }
249 
250     ctx = ctx_table + fwk_id_get_element_idx(id);
251 
252     /* Bind to driver */
253     status = fwk_module_bind(ctx->config->driver_id,
254                              ctx->config->api_id,
255                              &ctx->driver_api);
256     if (status != FWK_SUCCESS) {
257         return status;
258     }
259 
260     if ((ctx->driver_api->transmit_as_controller == NULL) ||
261         (ctx->driver_api->receive_as_controller == NULL)) {
262         return FWK_E_DATA;
263     }
264 
265     return FWK_SUCCESS;
266 }
267 
mod_i2c_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)268 static int mod_i2c_process_bind_request(fwk_id_t source_id,
269                                         fwk_id_t target_id,
270                                         fwk_id_t api_id,
271                                         const void **api)
272 {
273     struct mod_i2c_dev_ctx *ctx;
274 
275     if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
276         return FWK_E_PARAM;
277     }
278 
279     ctx = ctx_table + fwk_id_get_element_idx(target_id);
280 
281     if (fwk_id_is_equal(source_id, ctx->config->driver_id)) {
282         if (fwk_id_is_equal(api_id, mod_i2c_api_id_driver_response)) {
283             *api = &driver_response_api;
284         } else {
285             return FWK_E_PARAM;
286         }
287     } else {
288         *api = &i2c_api;
289     }
290 
291     return FWK_SUCCESS;
292 }
293 
respond_to_caller(fwk_id_t dev_id,struct mod_i2c_dev_ctx * ctx,int drv_status)294 static int respond_to_caller(
295     fwk_id_t dev_id,
296     struct mod_i2c_dev_ctx *ctx,
297     int drv_status)
298 {
299     int status;
300     struct fwk_event resp;
301     struct mod_i2c_event_param *param =
302         (struct mod_i2c_event_param *)resp.params;
303 
304     status = fwk_get_first_delayed_response(dev_id, &resp);
305     if (status != FWK_SUCCESS) {
306         return status;
307     }
308 
309     param->status = (drv_status == FWK_SUCCESS) ? FWK_SUCCESS : FWK_E_DEVICE;
310 
311     return fwk_put_event(&resp);
312 }
313 
process_request(struct mod_i2c_dev_ctx * ctx,fwk_id_t event_id)314 static int process_request(struct mod_i2c_dev_ctx *ctx, fwk_id_t event_id)
315 {
316     int drv_status = FWK_E_PARAM;
317     const struct mod_i2c_driver_api *driver_api = ctx->driver_api;
318     fwk_id_t driver_id = ctx->config->driver_id;
319     enum mod_i2c_event_idx event_id_type =
320         (enum mod_i2c_event_idx)fwk_id_get_event_idx(event_id);
321 
322     switch (event_id_type) {
323     case MOD_I2C_EVENT_IDX_REQUEST_TRANSMIT:
324         ctx->state = MOD_I2C_DEV_TX;
325         drv_status =
326             driver_api->transmit_as_controller(driver_id, &ctx->request);
327         break;
328 
329     case MOD_I2C_EVENT_IDX_REQUEST_TRANSMIT_THEN_RECEIVE:
330         ctx->state = MOD_I2C_DEV_TX_RX;
331         drv_status =
332             driver_api->transmit_as_controller(driver_id, &ctx->request);
333 
334         if (drv_status != FWK_SUCCESS) {
335             /* The request has failed or been acknowledged */
336             break;
337         }
338         /* fall through */
339 
340     case MOD_I2C_EVENT_IDX_REQUEST_RECEIVE:
341         ctx->state = MOD_I2C_DEV_RX;
342         drv_status =
343             driver_api->receive_as_controller(driver_id, &ctx->request);
344         break;
345 
346     default:
347         break;
348     }
349 
350     return drv_status;
351 }
352 
reload(fwk_id_t dev_id,struct mod_i2c_dev_ctx * ctx)353 static int reload(fwk_id_t dev_id, struct mod_i2c_dev_ctx *ctx)
354 {
355     int status;
356     bool is_empty;
357     struct fwk_event event;
358 
359     status = fwk_is_delayed_response_list_empty(dev_id, &is_empty);
360     if (status != FWK_SUCCESS) {
361         return status;
362     }
363 
364     if (is_empty) {
365         ctx->state = MOD_I2C_DEV_IDLE;
366     } else {
367         ctx->state = MOD_I2C_DEV_RELOAD;
368         event = (struct fwk_event) {
369             .target_id = dev_id,
370             .id = mod_i2c_event_id_reload,
371         };
372         status = fwk_put_event(&event);
373     }
374 
375    return status;
376 }
377 
process_next_request(fwk_id_t dev_id,struct mod_i2c_dev_ctx * ctx)378 static int process_next_request(fwk_id_t dev_id, struct mod_i2c_dev_ctx *ctx)
379 {
380     int status, drv_status;
381     bool is_empty;
382     struct fwk_event delayed_response;
383     struct mod_i2c_request *request;
384     struct mod_i2c_event_param *event_param;
385 
386     status = fwk_is_delayed_response_list_empty(dev_id, &is_empty);
387     if (status != FWK_SUCCESS) {
388         return status;
389     }
390 
391     if (is_empty) {
392         ctx->state = MOD_I2C_DEV_IDLE;
393         return FWK_SUCCESS;
394     }
395 
396     status = fwk_get_first_delayed_response(dev_id, &delayed_response);
397     if (status != FWK_SUCCESS) {
398         return status;
399     }
400 
401     request = (struct mod_i2c_request *)delayed_response.params;
402     ctx->request = *request;
403 
404     drv_status = process_request(ctx, delayed_response.id);
405     if (drv_status != FWK_PENDING) {
406         event_param = (struct mod_i2c_event_param *)delayed_response.params;
407         event_param->status = drv_status;
408 
409         status = fwk_put_event(&delayed_response);
410         if (status == FWK_SUCCESS) {
411             status = reload(dev_id, ctx);
412         }
413     }
414 
415     return status;
416 }
417 
mod_i2c_process_event(const struct fwk_event * event,struct fwk_event * resp_event)418 static int mod_i2c_process_event(const struct fwk_event *event,
419                                  struct fwk_event *resp_event)
420 {
421     fwk_id_t dev_id;
422     int status, drv_status;
423     bool is_request;
424     struct mod_i2c_dev_ctx *ctx;
425     struct mod_i2c_request *request;
426     struct mod_i2c_event_param *event_param, *resp_param;
427 
428     enum mod_i2c_internal_event_idx event_id_type;
429 
430     dev_id = event->target_id;
431     get_ctx(dev_id, &ctx);
432 
433     is_request = fwk_id_get_event_idx(event->id) < MOD_I2C_EVENT_IDX_COUNT;
434 
435     if (is_request) {
436         if (ctx->state == MOD_I2C_DEV_PANIC) {
437             event_param = (struct mod_i2c_event_param *)resp_event->params;
438             event_param->status = FWK_E_PANIC;
439 
440             return FWK_SUCCESS;
441         } else if (ctx->state != MOD_I2C_DEV_IDLE) {
442             resp_event->is_delayed_response = true;
443 
444             return FWK_SUCCESS;
445         }
446 
447         request = (struct mod_i2c_request *)event->params;
448         ctx->request = *request;
449 
450         drv_status = process_request(ctx, event->id);
451 
452         if (drv_status == FWK_PENDING) {
453             resp_event->is_delayed_response = true;
454         } else {
455             /* The request has succeeded or failed, respond now */
456             resp_param = (struct mod_i2c_event_param *)resp_event->params;
457 
458             resp_param->status = (drv_status == FWK_SUCCESS) ?
459                                  FWK_SUCCESS : FWK_E_DEVICE;
460             ctx->state = MOD_I2C_DEV_IDLE;
461         }
462 
463         return FWK_SUCCESS;
464     }
465 
466     event_id_type =
467         (enum mod_i2c_internal_event_idx)fwk_id_get_event_idx(event->id);
468 
469     switch (event_id_type) {
470     case MOD_I2C_EVENT_IDX_REQUEST_COMPLETED:
471         event_param = (struct mod_i2c_event_param *)event->params;
472 
473         if ((ctx->state == MOD_I2C_DEV_TX) || (ctx->state == MOD_I2C_DEV_RX)) {
474             status = respond_to_caller(dev_id, ctx, event_param->status);
475             if (status == FWK_SUCCESS) {
476                 status = process_next_request(dev_id, ctx);
477             }
478 
479         } else if (ctx->state == MOD_I2C_DEV_TX_RX) {
480             drv_status = event_param->status;
481 
482             if (drv_status == FWK_SUCCESS) {
483                 /* The TX request succeeded, proceed with the RX */
484                 ctx->state = MOD_I2C_DEV_RX;
485 
486                 drv_status = ctx->driver_api->receive_as_controller(
487                     ctx->config->driver_id, &ctx->request);
488 
489                 if (drv_status == FWK_PENDING) {
490                     status = FWK_SUCCESS;
491                     break;
492                 }
493             }
494 
495             status = respond_to_caller(dev_id, ctx, drv_status);
496             if (status == FWK_SUCCESS) {
497                 status = process_next_request(dev_id, ctx);
498             }
499         } else {
500             status = FWK_E_STATE;
501         }
502 
503         break;
504 
505     case MOD_I2C_EVENT_IDX_RELOAD:
506         status = process_next_request(dev_id, ctx);
507         break;
508 
509     default:
510         status = FWK_E_PANIC;
511         break;
512     }
513 
514     if (status != FWK_SUCCESS) {
515         ctx->state = MOD_I2C_DEV_PANIC;
516     }
517 
518     return status;
519 }
520 
521 const struct fwk_module module_i2c = {
522     .type = FWK_MODULE_TYPE_HAL,
523     .api_count = (unsigned int)MOD_I2C_API_IDX_COUNT,
524     .event_count = (unsigned int)MOD_I2C_EVENT_IDX_TOTAL_COUNT,
525     .init = mod_i2c_init,
526     .element_init = mod_i2c_dev_init,
527     .bind = mod_i2c_bind,
528     .process_bind_request = mod_i2c_process_bind_request,
529     .process_event = mod_i2c_process_event,
530 };
531