1 #include "FreeRTOS.h"
2 #include "hal_msgbox.h"
3 #include "msgbox_sx.h"
4 #include "../platform-msgbox.h"
5 #include "hal_interrupt.h"
6 #include "hal_log.h"
7 #include "string.h"
8 #include "hal_clk.h"
9 
10 struct messagebox *msgbox_dsp;
11 struct messagebox *msgbox_cpu;
12 
msgbox_sx_init_ccmu(void)13 int msgbox_sx_init_ccmu(void)
14 {
15     if (hal_clock_enable(HAL_CLK_PERIPH_MSGBOX0) < 0) {
16         hal_log_err("enable msgbox0 clk err!\n");
17         return -1;
18     }
19 
20     if (hal_clock_enable(HAL_CLK_PERIPH_MSGBOX1) < 0) {
21         hal_log_err("enable msgbox1 clk err!\n");
22         return -1;
23     }
24 
25     if (hal_clock_enable(HAL_CLK_PERIPH_MSGBOXR) < 0) {
26         hal_log_err("enable r_msgbox clk err!\n");
27         return -1;
28     }
29 
30     return 0;
31 }
32 
msgbox_init_sx(enum msgbox_direction dir)33 struct messagebox *msgbox_init_sx(enum msgbox_direction dir)
34 {
35     struct messagebox *mb = pvPortMalloc(sizeof(struct messagebox) +
36                          sizeof(struct msg_channel) *
37                              MSGBOX_MAX_QUEUE);
38 
39     if (!mb)
40         return 0;
41 
42     /* for reset and gating */
43 
44     memset(mb, 0,
45            sizeof(struct messagebox) +
46                sizeof(struct msg_channel) * MSGBOX_MAX_QUEUE);
47     if (dir == MSGBOX_DIRECTION_DSP) {
48         mb->base = MSGBOX_DSP_DSP;
49         mb->this_user = MSGBOX_DSP_DSP_USER;
50     } else {
51         mb->base = MSGBOX_CPU_DSP;
52         mb->this_user = MSGBOX_CPU_DSP_USER;
53     }
54 
55     msg_ops_init_sx(mb);
56 
57     if (dir == MSGBOX_DIRECTION_CPU) {
58         irq_request(SUNXI_DSP_IRQ_MSGBOX0_DSP, msg_irq_handler_sx, mb);
59         irq_enable(SUNXI_DSP_IRQ_MSGBOX0_DSP);
60     } else {
61         irq_request(SUNXI_DSP_IRQ_R_MSGBOX_DSP, msg_irq_handler_sx, mb);
62         irq_enable(SUNXI_DSP_IRQ_R_MSGBOX_DSP);
63     }
64 
65     return mb;
66 }
67 
msgbox_uninit_sx(struct messagebox * mb)68 void msgbox_uninit_sx(struct messagebox *mb)
69 {
70     irq_free(SUNXI_DSP_IRQ_MSGBOX0_DSP);
71     vPortFree(mb);
72 }
73 
74 /*
75  * msgbox_rev_handler - rev interrupt handler function
76  */
msgbox_rev_handler(int channel,void * c)77 static int msgbox_rev_handler(int channel, void *c)
78 {
79     struct msg_channel *ch = c;
80     struct messagebox *mb = ch->mb;
81     unsigned long data;
82 
83     while (mb->channel_fifo_len(mb, channel) > 0) {
84         mb->channel_read(mb, channel, &data);
85         if (ch->cb_rx)
86             ch->cb_rx(data, ch->data);
87     }
88     return 0;
89 }
90 
91 /*
92  * msgbox_send_handler - send interrutp handler function
93  */
msgbox_send_handler(int channel,void * c)94 static int msgbox_send_handler(int channel, void *c)
95 {
96     struct msg_channel *ch = c;
97     struct messagebox *mb = ch->mb;
98 
99     while (mb->channel_fifo_len(mb, channel) < MSGBOX_CHANNEL_DEPTH) {
100         unsigned long i;
101         unsigned long data = 0;
102 
103         if (ch->idx >= ch->len) {
104             goto finish;
105         }
106 
107         for (i = 0; i < sizeof(long); i++) {
108             if (ch->idx < ch->len)
109                 data |= ch->send[ch->idx++] << (i << 3);
110         }
111 
112         mb->channel_write(mb, channel, data);
113 
114     }
115 
116     return 0;
117 
118 finish:
119     mb->channel_irq_set(mb, channel, false);
120     if (ch->cb_tx_done)
121         ch->cb_tx_done(ch->idx, ch->data);
122 
123     return 0;
124 }
125 
126 
127 /**
128  * msgbox_alloc_channel - alloc channel from msgbox
129  * @func when function as send, it act as tx_done
130  *       when function as rev, it act as word reveive.
131  */
msgbox_alloc_channel_sx(struct messagebox * mb,int channel,enum msgbox_channel_direction dir,int (* func)(unsigned long,void *),void * data)132 struct msg_channel *msgbox_alloc_channel_sx(struct messagebox *mb, int channel,
133                      enum msgbox_channel_direction dir,
134                      int (*func)(unsigned long, void *),
135                      void *data)
136 {
137     struct msg_channel *ch;
138 
139     if (!mb || channel >= MSGBOX_MAX_QUEUE)
140         return 0;
141 
142     ch = &mb->msg_handler[channel];
143 
144     ch->mb = mb;
145     ch->channel = channel;
146     ch->data = data;
147     ch->dir = dir;
148 
149     if (mb->channel_set_direction(mb, channel, dir))
150         return 0;
151 
152     if (ch->dir == MSGBOX_CHANNEL_SEND) {
153         ch->cb_of_msg_queue = msgbox_send_handler;
154         ch->cb_tx_done = func;
155     }
156     else {
157         ch->cb_of_msg_queue = msgbox_rev_handler;
158         ch->cb_rx = func;
159 
160         mb->channel_irq_set(mb, channel, true);
161     }
162 
163     return ch;
164 }
165 
msgbox_free_channel_sx(struct messagebox * mb,struct msg_channel * ch)166 void msgbox_free_channel_sx(struct messagebox *mb, struct msg_channel *ch)
167 {
168     if (!mb || ch->channel >= MSGBOX_MAX_QUEUE)
169         return;
170 
171     mb->channel_irq_set(mb, ch->channel, false);
172 
173     ch->data = NULL;
174     ch->cb_of_msg_queue = NULL;
175     ch->cb_tx_done = NULL;
176     ch->cb_rx = NULL;
177 }
178 
msgbox_channel_send_data_sx(struct msg_channel * ch,unsigned char * d,size_t len)179 int msgbox_channel_send_data_sx(struct msg_channel *ch, unsigned char *d,
180                  size_t len)
181 {
182     struct messagebox *mb = ch->mb;
183 
184     ch->send = d;
185     ch->len = len;
186     ch->idx = 0;
187 
188     mb->channel_irq_set(mb, ch->channel, true);
189 
190     return 0;
191 }
192 
messagebox_init_sx(void)193 int messagebox_init_sx(void)
194 {
195     msgbox_sx_init_ccmu();
196     msgbox_dsp = msgbox_init_sx(MSGBOX_DIRECTION_DSP);
197     msgbox_cpu = msgbox_init_sx(MSGBOX_DIRECTION_CPU);
198 
199     return 0;
200 }
201 
202