1 /*
2  * Copyright 2018-2021, NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 #include <string.h>
9 #include <assert.h>
10 #include <string.h>
11 
12 #include "fsl_common.h"
13 
14 #include "srtm_heap.h"
15 #include "srtm_list.h"
16 #include "srtm_dispatcher.h"
17 #include "srtm_service.h"
18 #include "srtm_service_struct.h"
19 #include "srtm_i2c_service.h"
20 #include "srtm_message.h"
21 #include "srtm_message_struct.h"
22 #include "srtm_channel.h"
23 #include "srtm_channel_struct.h"
24 
25 /*******************************************************************************
26  * Definitions
27  ******************************************************************************/
28 /* Protocol definition */
29 #define SRTM_I2C_CATEGORY (0x9U)
30 #define SRTM_I2C_VERSION  (0x0100U)
31 
32 #define SRTM_I2C_RETURN_CODE_SUCEESS     (0x0U)
33 #define SRTM_I2C_RETURN_CODE_FAIL        (0x1U)
34 #define SRTM_I2C_RETURN_CODE_UNSUPPORTED (0x2U)
35 
36 typedef struct _srtm_i2c_service
37 {
38     struct _srtm_service service;
39     srtm_i2c_adapter_t adapter;
40 } *srtm_i2c_service_t;
41 
42 static srtm_status_t SRTM_I2CService_Request(srtm_service_t service, srtm_request_t request);
43 static srtm_status_t SRTM_I2CService_Notify(srtm_service_t service, srtm_notification_t notif);
44 
SRTM_I2C_SearchBus(srtm_i2c_adapter_t adapter,uint8_t busID)45 static i2c_bus_t SRTM_I2C_SearchBus(srtm_i2c_adapter_t adapter, uint8_t busID)
46 {
47     uint8_t bus_num    = adapter->bus_structure.bus_num;
48     i2c_bus_t busArray = adapter->bus_structure.buses;
49     uint8_t i;
50 
51     for (i = 0U; i != bus_num; i++)
52     {
53         if (busArray[i].bus_id == busID)
54         {
55             break;
56         }
57     }
58 
59     return (i == bus_num) ? NULL : (busArray + i);
60 }
61 
SRTM_I2CService_ReadBus(srtm_service_t service,uint8_t busID,uint16_t slaveAddr,uint8_t * buf,uint16_t len,uint16_t flags)62 static srtm_status_t SRTM_I2CService_ReadBus(
63     srtm_service_t service, uint8_t busID, uint16_t slaveAddr, uint8_t *buf, uint16_t len, uint16_t flags)
64 {
65     srtm_i2c_service_t handle  = (srtm_i2c_service_t)(void *)service;
66     srtm_i2c_adapter_t adapter = handle->adapter;
67     i2c_bus_t targetBus;
68     uint32_t base_addr;
69     uint8_t switch_index;
70     uint16_t switch_addr;
71     srtm_i2c_switch_channel switch_channel;
72     srtm_status_t status;
73     srtm_i2c_type_t type;
74     i2c_switch_t switch_inst;
75 
76     targetBus    = SRTM_I2C_SearchBus(adapter, busID);
77     base_addr    = targetBus->base_addr;
78     switch_index = targetBus->switch_idx;
79     type         = targetBus->type;
80     /*
81      * Switch Channel
82      */
83     if (switch_index < adapter->bus_structure.switch_num)
84     {
85         switch_inst    = &adapter->bus_structure.switches[switch_index];
86         switch_addr    = switch_inst->slaveAddr;
87         switch_channel = targetBus->switch_channel;
88         if (switch_inst->cur_channel != switch_channel)
89         {
90             (void)adapter->switchchannel(adapter, base_addr, type, switch_addr, switch_channel);
91             switch_inst->cur_channel = switch_channel;
92         }
93     }
94     /*
95      * Read
96      */
97     status = adapter->read(adapter, base_addr, type, slaveAddr, buf, len, flags); // APP_SRTM_I2C_Read
98     return status;
99 }
100 
SRTM_I2CService_WriteBus(srtm_service_t service,uint8_t busID,uint16_t slaveAddr,uint8_t * buf,uint16_t len,uint16_t flags)101 static srtm_status_t SRTM_I2CService_WriteBus(
102     srtm_service_t service, uint8_t busID, uint16_t slaveAddr, uint8_t *buf, uint16_t len, uint16_t flags)
103 {
104     srtm_i2c_service_t handle  = (srtm_i2c_service_t)(void *)service;
105     srtm_i2c_adapter_t adapter = handle->adapter;
106     i2c_bus_t targetBus;
107     uint32_t base_addr;
108     uint8_t switch_index;
109     uint16_t switch_addr;
110     srtm_i2c_switch_channel switch_channel;
111     srtm_status_t status;
112     srtm_i2c_type_t type;
113     i2c_switch_t switch_inst;
114 
115     targetBus    = SRTM_I2C_SearchBus(adapter, busID);
116     base_addr    = targetBus->base_addr;
117     switch_index = targetBus->switch_idx;
118     type         = targetBus->type;
119     /*
120      * Switch Channel
121      */
122     if (switch_index < adapter->bus_structure.switch_num)
123     {
124         switch_inst    = &adapter->bus_structure.switches[switch_index];
125         switch_addr    = switch_inst->slaveAddr;
126         switch_channel = targetBus->switch_channel;
127         if (switch_inst->cur_channel != switch_channel)
128         {
129             (void)adapter->switchchannel(adapter, base_addr, type, switch_addr, switch_channel);
130             switch_inst->cur_channel = switch_channel;
131         }
132     }
133     /*
134      * Write
135      */
136     status = adapter->write(adapter, base_addr, type, slaveAddr, buf, len, flags); // APP_SRTM_I2C_Write
137     return status;
138 }
139 
SRTM_I2CService_Create(srtm_i2c_adapter_t adapter)140 srtm_service_t SRTM_I2CService_Create(srtm_i2c_adapter_t adapter)
141 {
142     srtm_i2c_service_t handle;
143 
144     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
145     handle = (srtm_i2c_service_t)SRTM_Heap_Malloc(sizeof(struct _srtm_i2c_service));
146     assert(handle);
147 
148     adapter->service = &handle->service;
149     handle->adapter  = adapter;
150 
151     SRTM_List_Init(&handle->service.node);
152     handle->service.dispatcher = NULL;
153     handle->service.category   = SRTM_I2C_CATEGORY;
154     handle->service.destroy    = SRTM_I2CService_Destroy;
155     handle->service.request    = SRTM_I2CService_Request;
156     handle->service.notify     = SRTM_I2CService_Notify;
157 
158     return &handle->service;
159 }
160 
SRTM_I2CService_Destroy(srtm_service_t service)161 void SRTM_I2CService_Destroy(srtm_service_t service)
162 {
163     srtm_i2c_service_t handle = (srtm_i2c_service_t)(void *)service;
164 
165     assert(service);
166 
167     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
168 
169     /* Service must be unregistered from dispatcher before destroy */
170     assert(SRTM_List_IsEmpty(&service->node));
171 
172     SRTM_Heap_Free(handle);
173 }
174 
SRTM_I2CService_Reset(srtm_service_t service,srtm_peercore_t core)175 void SRTM_I2CService_Reset(srtm_service_t service, srtm_peercore_t core)
176 {
177     assert(service);
178 
179     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
180 }
181 
SRTM_I2CService_Request(srtm_service_t service,srtm_request_t request)182 static srtm_status_t SRTM_I2CService_Request(srtm_service_t service, srtm_request_t request)
183 {
184     srtm_status_t status;
185     srtm_channel_t channel;
186     uint8_t command;
187     uint32_t payloadLen;
188     srtm_response_t response;
189     struct _srtm_i2c_payload *i2cReq;
190     struct _srtm_i2c_payload *i2cResp;
191 
192     assert(service->dispatcher);
193 
194     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
195 
196     channel    = SRTM_CommMessage_GetChannel(request);
197     command    = SRTM_CommMessage_GetCommand(request);
198     i2cReq     = (struct _srtm_i2c_payload *)(void *)SRTM_CommMessage_GetPayload(request);
199     payloadLen = SRTM_CommMessage_GetPayloadLen(request);
200     (void)payloadLen; /* try to fix warning: variable 'payloadLen' set but not used */
201     assert(i2cReq);
202     assert((uint32_t)(i2cReq->len + sizeof(struct _srtm_i2c_payload) - sizeof(i2cReq->data[0])) <= payloadLen);
203 
204     response =
205         SRTM_Response_Create(channel, SRTM_I2C_CATEGORY, SRTM_I2C_VERSION, command,
206                              (uint16_t)((sizeof(struct _srtm_i2c_payload) - sizeof(i2cReq->data[0])) + i2cReq->len));
207     if (response == NULL)
208     {
209         return SRTM_Status_OutOfMemory;
210     }
211 
212     i2cResp = (struct _srtm_i2c_payload *)(void *)SRTM_CommMessage_GetPayload(response);
213 
214     status = SRTM_Service_CheckVersion(service, request, SRTM_I2C_VERSION);
215     if (status != SRTM_Status_Success)
216     {
217         SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: format error!\r\n", __func__);
218         i2cResp->retCode = SRTM_I2C_RETURN_CODE_UNSUPPORTED;
219     }
220     else
221     {
222         SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO,
223                            "SRTM receive I2C request:cmd=%x, busID %d, slaveAddr 0x%x!, data %d bytes\r\n", command,
224                            i2cReq->busID, i2cReq->slaveAddr, i2cReq->len);
225         (void)memcpy(i2cResp, i2cReq,
226                      (sizeof(struct _srtm_i2c_payload) - sizeof(i2cReq->data[0]) + (size_t)i2cReq->len));
227 
228         switch (command)
229         {
230             case (uint8_t)SRTM_I2C_CMD_READ:
231                 status = SRTM_I2CService_ReadBus(service, i2cResp->busID, i2cResp->slaveAddr, i2cResp->data,
232                                                  i2cReq->len, i2cReq->flags);
233                 i2cResp->retCode =
234                     status == SRTM_Status_Success ? SRTM_I2C_RETURN_CODE_SUCEESS : SRTM_I2C_RETURN_CODE_FAIL;
235                 break;
236             case (uint8_t)SRTM_I2C_CMD_WRITE:
237                 status = SRTM_I2CService_WriteBus(service, i2cResp->busID, i2cResp->slaveAddr, i2cResp->data,
238                                                   i2cReq->len, i2cReq->flags);
239                 i2cResp->retCode =
240                     status == SRTM_Status_Success ? SRTM_I2C_RETURN_CODE_SUCEESS : SRTM_I2C_RETURN_CODE_FAIL;
241                 break;
242             default:
243                 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: command %d unsupported!\r\n", __func__, command);
244                 assert(false);
245                 break;
246         }
247     }
248 
249     return SRTM_Dispatcher_DeliverResponse(service->dispatcher, response);
250 }
251 
SRTM_I2CService_Notify(srtm_service_t service,srtm_notification_t notif)252 static srtm_status_t SRTM_I2CService_Notify(srtm_service_t service, srtm_notification_t notif)
253 {
254     SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: command %d unsupported!\r\n", __func__,
255                        SRTM_CommMessage_GetCommand(notif));
256 
257     return SRTM_Status_ServiceNotFound;
258 }
259 
SRTM_I2C_HandleBusRead(srtm_dispatcher_t dispatcher,void * param1,void * param2)260 static void SRTM_I2C_HandleBusRead(srtm_dispatcher_t dispatcher, void *param1, void *param2)
261 {
262     srtm_status_t status;
263     srtm_i2c_payload_t i2c_payload = (srtm_i2c_payload_t)param1;
264     srtm_service_t service         = (srtm_service_t)param2;
265     status = SRTM_I2CService_ReadBus(service, i2c_payload->busID, i2c_payload->slaveAddr, i2c_payload->data,
266                                      (uint8_t)i2c_payload->len, i2c_payload->flags);
267     i2c_payload->retCode = (status == SRTM_Status_Success) ? SRTM_I2C_RETURN_CODE_SUCEESS : SRTM_I2C_RETURN_CODE_FAIL;
268 }
269 
SRTM_I2C_HandleBusWrite(srtm_dispatcher_t dispatcher,void * param1,void * param2)270 static void SRTM_I2C_HandleBusWrite(srtm_dispatcher_t dispatcher, void *param1, void *param2)
271 {
272     srtm_status_t status;
273     srtm_i2c_payload_t i2c_payload = (srtm_i2c_payload_t)param1;
274     srtm_service_t service         = (srtm_service_t)param2;
275     status = SRTM_I2CService_WriteBus(service, i2c_payload->busID, i2c_payload->slaveAddr, i2c_payload->data,
276                                       (uint8_t)i2c_payload->len, i2c_payload->flags);
277     i2c_payload->retCode = (status == SRTM_Status_Success) ? SRTM_I2C_RETURN_CODE_SUCEESS : SRTM_I2C_RETURN_CODE_FAIL;
278 }
279 
SRTM_I2C_RequestBusRead(srtm_service_t service,uint8_t busID,uint16_t slaveAddr,uint8_t * buf,uint16_t len)280 srtm_status_t SRTM_I2C_RequestBusRead(
281     srtm_service_t service, uint8_t busID, uint16_t slaveAddr, uint8_t *buf, uint16_t len)
282 {
283     srtm_request_t request;
284     srtm_status_t status;
285     srtm_i2c_payload_t i2cReq;
286     srtm_procedure_t proc;
287     /*
288      * Allocate an SRTM message and copy necessary information
289      */
290     request           = SRTM_Request_Create(NULL, SRTM_I2C_CATEGORY, SRTM_I2C_VERSION, (uint8_t)SRTM_I2C_CMD_READ,
291                                             (uint16_t)((sizeof(struct _srtm_i2c_payload) - sizeof(uint8_t)) + len));
292     i2cReq            = (struct _srtm_i2c_payload *)(void *)SRTM_CommMessage_GetPayload(request);
293     i2cReq->busID     = busID;
294     i2cReq->slaveAddr = slaveAddr;
295     i2cReq->len       = len;
296     (void)memset(i2cReq->data, 0, len);
297     /*
298      * Call proc in sync manner
299      */
300     proc = SRTM_Procedure_Create(SRTM_I2C_HandleBusRead, i2cReq, service);
301     (void)SRTM_Dispatcher_CallProc(service->dispatcher, proc, SRTM_WAIT_FOR_EVER); /*synchronized call*/
302     /*
303      * Save proc exec result
304      */
305     (void)memcpy(buf, i2cReq->data, len);
306     status = (srtm_status_t)i2cReq->retCode;
307     /*
308      * Clean the allocated SRTM object
309      */
310     SRTM_Procedure_Destroy(proc);
311     SRTM_Response_Destroy(request);
312 
313     return status;
314 }
315 
SRTM_I2C_RequestBusWrite(srtm_service_t service,uint8_t busID,uint16_t slaveAddr,uint8_t * buf,uint16_t len,uint8_t needStop)316 srtm_status_t SRTM_I2C_RequestBusWrite(
317     srtm_service_t service, uint8_t busID, uint16_t slaveAddr, uint8_t *buf, uint16_t len, uint8_t needStop)
318 {
319     srtm_request_t request;
320     srtm_status_t status;
321     srtm_i2c_payload_t i2cReq;
322     srtm_procedure_t proc;
323     /*
324      * Allocate an SRTM message and copy necessary information
325      */
326     request           = SRTM_Request_Create(NULL, SRTM_I2C_CATEGORY, SRTM_I2C_VERSION, (uint8_t)SRTM_I2C_CMD_WRITE,
327                                             (uint16_t)((sizeof(struct _srtm_i2c_payload) - sizeof(uint8_t)) + len));
328     i2cReq            = (struct _srtm_i2c_payload *)(void *)SRTM_CommMessage_GetPayload(request);
329     i2cReq->busID     = busID;
330     i2cReq->slaveAddr = slaveAddr;
331     i2cReq->len       = len;
332     i2cReq->flags     = needStop > 0U ? (SRTM_I2C_FLAG_NEED_STOP) : 0U;
333 
334     (void)memcpy(i2cReq->data, buf, len);
335     /*
336      * Call proc in sync manner
337      */
338     proc = SRTM_Procedure_Create(SRTM_I2C_HandleBusWrite, i2cReq, service);
339     (void)SRTM_Dispatcher_CallProc(service->dispatcher, proc, SRTM_WAIT_FOR_EVER); /*synchronized call*/
340     /*
341      * Save proc exec result
342      */
343     status = (srtm_status_t)i2cReq->retCode;
344     /*
345      * Clean the allocated SRTM object
346      */
347     SRTM_Procedure_Destroy(proc);
348     SRTM_Response_Destroy(request);
349 
350     return status;
351 }
352