1 /**************************************************************************//**
2 *
3 * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date            Author       Notes
9 * 2022-10-10      Wayne        First version
10 *
11 ******************************************************************************/
12 
13 #include <rtthread.h>
14 
15 #if defined(BSP_USING_WHC)
16 
17 #include "drv_whc.h"
18 #include <stdio.h>
19 
20 #define DBG_ENABLE
21 #define DBG_LEVEL DBG_LOG
22 #define DBG_SECTION_NAME  "whc.demo"
23 #define DBG_COLOR
24 #include <rtdbg.h>
25 
26 #define USE_WORMHOLE_CHNAME    "whc0-0"
27 
28 typedef enum
29 {
30     evCMD_MEM_ALLOCATE,
31     evCMD_MEM_FREE,
32     evCMD_MEM_COPY,
33     evCMD_DEVMEM_WRITE,
34     evCMD_DEVMEM_READ,
35     evCMD_MEM_SET
36 } nu_whc_cmd;
37 
38 typedef enum
39 {
40     evCMD_REQ,
41     evCMD_RESP,
42 } nu_whc_cmd_type;
43 
44 #define CMD_TYPE_Pos           16
45 #define CMD_TYPE_Msk           (3<<CMD_TYPE_Pos)
46 #define PACK_MSG_CMD(t, x)     (((t<<CMD_TYPE_Pos)&CMD_TYPE_Msk)|x)
47 #define CMD_IS_REQ(m)          (((m.u32Cmd&CMD_TYPE_Msk)>>CMD_TYPE_Pos)==evCMD_REQ)
48 #define CMD_IS_RESP(m)         (((m.u32Cmd&CMD_TYPE_Msk)>>CMD_TYPE_Pos)==evCMD_RESP)
49 
50 typedef struct
51 {
52     union
53     {
54         nu_whc_msg sMsgBuf;
55         struct
56         {
57             uint32_t   u32Cmd;
58             uint32_t   u32Addr0; //Dst, free, allocate, set
59             uint32_t   u32Addr1; //Src, value
60             uint32_t   u32Size;
61         } msg;
62     };
63 } whc_mem;
64 typedef whc_mem *whc_mem_t;
65 
66 static struct rt_semaphore tx_sem;
67 static struct rt_semaphore rx_sem;
68 static rt_device_t device = RT_NULL;
69 
whc_tx_complete(rt_device_t dev,void * buffer)70 static rt_err_t whc_tx_complete(rt_device_t dev, void *buffer)
71 {
72     return rt_sem_release(&tx_sem);
73 }
74 
whc_rx_indicate(rt_device_t dev,rt_size_t size)75 static rt_err_t whc_rx_indicate(rt_device_t dev, rt_size_t size)
76 {
77     return rt_sem_release(&rx_sem);
78 }
79 
proc_msg(whc_mem_t req,whc_mem_t resp)80 static rt_err_t proc_msg(whc_mem_t req, whc_mem_t resp)
81 {
82     switch ((nu_whc_cmd)req->msg.u32Cmd)
83     {
84     case evCMD_MEM_ALLOCATE:
85         resp->msg.u32Addr0 = (uint32_t)rt_malloc(req->msg.u32Size);
86         resp->msg.u32Size  = req->msg.u32Size;
87         resp->msg.u32Cmd   = PACK_MSG_CMD(evCMD_RESP, evCMD_MEM_ALLOCATE);
88         break;
89 
90     case evCMD_MEM_FREE:
91         rt_free((void *)req->msg.u32Addr0);
92         resp->msg.u32Addr0 = (uint32_t)req->msg.u32Addr0;
93         resp->msg.u32Cmd   = PACK_MSG_CMD(evCMD_RESP, evCMD_MEM_FREE);
94         resp->msg.u32Size  = 0;
95         break;
96 
97     case evCMD_MEM_COPY:
98         rt_memcpy((void *)req->msg.u32Addr0, (void *)req->msg.u32Addr1, req->msg.u32Size);
99         resp->msg.u32Cmd   = PACK_MSG_CMD(evCMD_RESP, evCMD_MEM_COPY);
100         resp->msg.u32Addr0 = (uint32_t)req->msg.u32Addr0;
101         resp->msg.u32Addr1 = (uint32_t)req->msg.u32Addr1;
102         resp->msg.u32Size  = req->msg.u32Size;
103         break;
104 
105     case evCMD_MEM_SET:
106         rt_memset((void *)req->msg.u32Addr0, (req->msg.u32Addr1 & 0xff), req->msg.u32Size);
107         resp->msg.u32Cmd   = PACK_MSG_CMD(evCMD_RESP, evCMD_MEM_SET);
108         resp->msg.u32Addr0 = (uint32_t)req->msg.u32Addr0;
109         resp->msg.u32Addr1 = (uint32_t)(req->msg.u32Addr1 & 0xff);
110         resp->msg.u32Size  = req->msg.u32Size;
111         break;
112 
113     case evCMD_DEVMEM_WRITE:
114         *((vu32 *)req->msg.u32Addr0) = req->msg.u32Addr1;
115 
116         resp->msg.u32Cmd   = PACK_MSG_CMD(evCMD_RESP, evCMD_DEVMEM_WRITE);
117         resp->msg.u32Addr0 = 0;
118         resp->msg.u32Addr1 = 0;
119         resp->msg.u32Size  = sizeof(uint32_t);
120         break;
121 
122     case evCMD_DEVMEM_READ:
123         resp->msg.u32Cmd   = PACK_MSG_CMD(evCMD_RESP, evCMD_DEVMEM_READ);
124         resp->msg.u32Addr0 = *((vu32 *)req->msg.u32Addr0);
125         resp->msg.u32Addr1 = 0;
126         resp->msg.u32Size  = sizeof(uint32_t);
127         break;
128 
129     default:
130         return -RT_ERROR;
131     }
132 
133     return -RT_ERROR;
134 }
135 
send_msg(whc_mem_t req)136 static rt_err_t send_msg(whc_mem_t req)
137 {
138     if (device)
139     {
140         if (sizeof(nu_whc_msg) != rt_device_write(device, 0, req, sizeof(nu_whc_msg)))
141         {
142             LOG_E("Failed to send msg.");
143             return -RT_ERROR;
144         }
145 
146         if (-RT_ETIMEOUT == rt_sem_take(&tx_sem, 100))
147             LOG_E("Timeout cant get ACK.");
148     }
149 
150     return RT_EOK;
151 }
152 
153 
whc_daemon(void * parameter)154 static void whc_daemon(void *parameter)
155 {
156     rt_err_t ret;
157 
158     device  = rt_device_find(USE_WORMHOLE_CHNAME);
159     RT_ASSERT(device);
160 
161     /* Init semaphores */
162     ret = rt_sem_init(&tx_sem, "whc_tx", 0, RT_IPC_FLAG_PRIO);
163     RT_ASSERT(ret == RT_EOK);
164 
165     ret = rt_sem_init(&rx_sem, "whc_rx", 0, RT_IPC_FLAG_PRIO);
166     RT_ASSERT(ret == RT_EOK);
167 
168     /* Set tx complete function */
169     ret = rt_device_set_tx_complete(device, whc_tx_complete);
170     RT_ASSERT(ret == RT_EOK);
171 
172     /* Set rx indicate function */
173     ret = rt_device_set_rx_indicate(device, whc_rx_indicate);
174     RT_ASSERT(ret == RT_EOK);
175 
176     ret = rt_device_open(device, 0);
177     if (!device)
178     {
179         LOG_E("Failed to open %s", USE_WORMHOLE_CHNAME);
180         return;
181     }
182 
183     while (1)
184     {
185         if (rt_sem_take(&rx_sem, RT_WAITING_FOREVER) == RT_EOK)
186         {
187             nu_whc_msg sNuWhcMsg;
188             whc_mem_t psWhcMem = (whc_mem_t)&sNuWhcMsg;
189 
190             if (sizeof(nu_whc_msg) != rt_device_read(device, 0, psWhcMem, sizeof(nu_whc_msg)))
191                 continue;
192 
193             if (CMD_IS_REQ(psWhcMem->msg))
194             {
195                 nu_whc_msg sNuWhcMsg_Resp;
196 
197                 proc_msg((whc_mem_t)&sNuWhcMsg, (whc_mem_t)&sNuWhcMsg_Resp);
198                 send_msg((whc_mem_t)&sNuWhcMsg_Resp);
199             }
200             else if (CMD_IS_RESP(psWhcMem->msg))
201             {
202                 LOG_I("Get Resp. 0x%08x 0x%08x 0x%08x %d",
203                       psWhcMem->msg.u32Cmd,
204                       psWhcMem->msg.u32Addr0,
205                       psWhcMem->msg.u32Addr1,
206                       psWhcMem->msg.u32Size);
207             }
208 
209         } //if
210 
211     } //while
212 }
213 
wormhole_app(void)214 static int wormhole_app(void)
215 {
216     rt_err_t result = 0;
217     rt_thread_t thread;
218 
219     thread = rt_thread_create("whcD", whc_daemon, RT_NULL, 2048, 25, 20);
220     if (thread != RT_NULL)
221     {
222         result = rt_thread_startup(thread);
223         RT_ASSERT(result == RT_EOK);
224     }
225 
226     return 0;
227 }
228 INIT_COMPONENT_EXPORT(wormhole_app);
229 
whc_malloc(uint32_t u32Size)230 void *whc_malloc(uint32_t u32Size)
231 {
232     whc_mem sWhcMem;
233 
234     sWhcMem.msg.u32Cmd = PACK_MSG_CMD(evCMD_REQ, evCMD_MEM_ALLOCATE);
235     sWhcMem.msg.u32Size  = (uint32_t)u32Size;
236 
237     send_msg(&sWhcMem);
238 
239     return 0;
240 }
241 RTM_EXPORT(whc_malloc);
242 
whc_memcpy(void * pvDst,void * pvSrc,uint32_t u32Size)243 void *whc_memcpy(void *pvDst, void *pvSrc, uint32_t u32Size)
244 {
245     whc_mem sWhcMem;
246 
247     sWhcMem.msg.u32Cmd = PACK_MSG_CMD(evCMD_REQ, evCMD_MEM_COPY);
248     sWhcMem.msg.u32Addr0 = (uint32_t)pvDst;
249     sWhcMem.msg.u32Addr1 = (uint32_t)pvSrc;
250     sWhcMem.msg.u32Size  = (uint32_t)u32Size;
251 
252     send_msg(&sWhcMem);
253 
254     return 0;
255 }
256 RTM_EXPORT(whc_memcpy);
257 
258 
whc_devmem_write(void * pvaddr,uint32_t u32value)259 uint32_t whc_devmem_write(void *pvaddr, uint32_t u32value)
260 {
261     whc_mem sWhcMem;
262 
263     sWhcMem.msg.u32Cmd = PACK_MSG_CMD(evCMD_REQ, evCMD_DEVMEM_WRITE);
264     sWhcMem.msg.u32Addr0 = (uint32_t)pvaddr;
265     sWhcMem.msg.u32Addr1 = u32value;
266     sWhcMem.msg.u32Size  = sizeof(uint32_t);
267 
268     send_msg(&sWhcMem);
269 
270     return 0;
271 }
272 RTM_EXPORT(whc_devmem_write);
273 
whc_devmem_read(void * pvaddr)274 uint32_t whc_devmem_read(void *pvaddr)
275 {
276     whc_mem sWhcMem;
277 
278     sWhcMem.msg.u32Cmd = PACK_MSG_CMD(evCMD_REQ, evCMD_DEVMEM_READ);
279     sWhcMem.msg.u32Addr0 = (uint32_t)pvaddr;
280     sWhcMem.msg.u32Addr1 = 0;
281     sWhcMem.msg.u32Size  = sizeof(uint32_t);
282 
283     send_msg(&sWhcMem);
284 
285     return 0;
286 }
287 RTM_EXPORT(whc_devmem_read);
288 
whc_devmem(int argc,char * argv[])289 void whc_devmem(int argc, char *argv[])
290 {
291     volatile unsigned int u32Addr;
292     unsigned int value = 0, mode = 0;
293 
294     if (argc < 2 || argc > 3)
295     {
296         goto exit_devmem;
297     }
298 
299     if (argc == 3)
300     {
301         if (rt_sscanf(argv[2], "0x%x", &value) != 1)
302             goto exit_devmem;
303         mode = 1; //Write
304     }
305 
306     if (rt_sscanf(argv[1], "0x%x", &u32Addr) != 1)
307         goto exit_devmem;
308     else if (u32Addr & (4 - 1))
309         goto exit_devmem;
310 
311     if (mode)
312     {
313         whc_devmem_write((void *) u32Addr, value);
314     }
315     rt_kprintf("0x%08x\n", whc_devmem_read((void *)u32Addr));
316 
317     return;
318 exit_devmem:
319     rt_kprintf("Read: whc_devmem <physical address in hex>\n");
320     rt_kprintf("Write: whc_devmem <physical address in hex> <value in hex format>\n");
321     return;
322 }
323 MSH_CMD_EXPORT(whc_devmem, dump device registers);
324 
325 #endif /* #if defined(BSP_USING_HWSEM)*/
326