blob: 6ead08ec746090e5371656257b91387a350f1289 [file] [log] [blame]
Parth Dixit99ae9a82015-06-03 12:12:33 +05301/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -07002 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Fundation, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#include <smd.h>
31#include <smem.h>
32#include <debug.h>
Channagoud Kadabi54aafe42014-11-21 19:26:16 -080033#include <kernel/event.h>
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070034#include <platform/irqs.h>
35#include <platform/iomap.h>
36#include <platform/interrupts.h>
Sridhar Parasurama5664b22014-12-22 11:17:34 -080037#include <platform/timer.h>
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070038#include <reg.h>
39#include <malloc.h>
40#include <bits.h>
41
Channagoud Kadabibafde162014-12-16 10:12:45 -080042#define SMD_CHANNEL_ACCESS_RETRY 1000000
43
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070044smd_channel_alloc_entry_t *smd_channel_alloc_entry;
Channagoud Kadabi54aafe42014-11-21 19:26:16 -080045static event_t smd_closed;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070046
47static void smd_write_state(smd_channel_info_t *ch, uint32_t state)
48{
49 if(state == SMD_SS_OPENED)
50 {
51 ch->port_info->ch0.DTR_DSR = 1;
52 ch->port_info->ch0.CTS_RTS = 1;
53 ch->port_info->ch0.CD = 1;
54 }
55 else
56 {
57 ch->port_info->ch0.DTR_DSR = 0;
58 ch->port_info->ch0.CTS_RTS = 0;
59 ch->port_info->ch0.CD = 0;
60 }
61
62 ch->port_info->ch0.stream_state = state;
63}
64
65static void smd_state_update(smd_channel_info_t *ch, uint32_t flag)
66{
67 ch->port_info->ch0.state_updated = flag;
68}
69
Channagoud Kadabibafde162014-12-16 10:12:45 -080070int smd_get_channel_entry(smd_channel_info_t *ch, uint32_t ch_type)
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070071{
72 int i = 0;
73
74 for(i = 0; i< SMEM_NUM_SMD_STREAM_CHANNELS; i++)
75 {
76 if((smd_channel_alloc_entry[i].ctype & 0xFF) == ch_type)
77 {
78 memcpy(&ch->alloc_entry, &smd_channel_alloc_entry[i], sizeof(smd_channel_alloc_entry_t));
79 break;
80 }
81 }
82
Channagoud Kadabibafde162014-12-16 10:12:45 -080083 /* Channel not found, retry again */
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070084 if(i == SMEM_NUM_SMD_STREAM_CHANNELS)
85 {
Channagoud Kadabibafde162014-12-16 10:12:45 -080086 dprintf(SPEW, "Channel not found, wait and retry for the update\n");
87 return -1;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070088 }
Channagoud Kadabibafde162014-12-16 10:12:45 -080089
90 return 0;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070091}
92
93int smd_get_channel_info(smd_channel_info_t *ch, uint32_t ch_type)
94{
95 int ret = 0;
96 uint8_t *fifo_buf = NULL;
97 uint32_t fifo_buf_size = 0;
98 uint32_t size = 0;
99
Channagoud Kadabibafde162014-12-16 10:12:45 -0800100 ret = smd_get_channel_entry(ch, ch_type);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700101
Channagoud Kadabibafde162014-12-16 10:12:45 -0800102 if (ret)
103 return ret;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700104
105 ch->port_info = smem_get_alloc_entry(SMEM_SMD_BASE_ID + ch->alloc_entry.cid,
106 &size);
107
108 fifo_buf = smem_get_alloc_entry(SMEM_SMD_FIFO_BASE_ID + ch->alloc_entry.cid,
109 &fifo_buf_size);
110
111 fifo_buf_size /= 2;
112 ch->send_buf = fifo_buf;
113 ch->recv_buf = fifo_buf + fifo_buf_size;
114 ch->fifo_size = fifo_buf_size;
115
116 return ret;
117}
118
119int smd_init(smd_channel_info_t *ch, uint32_t ch_type)
120{
121 unsigned ret = 0;
Channagoud Kadabibafde162014-12-16 10:12:45 -0800122 int chnl_found = 0;
123 uint64_t timeout = SMD_CHANNEL_ACCESS_RETRY;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700124
125 smd_channel_alloc_entry = (smd_channel_alloc_entry_t*)memalign(CACHE_LINE, SMD_CHANNEL_ALLOC_MAX);
126 ASSERT(smd_channel_alloc_entry);
127
Channagoud Kadabibafde162014-12-16 10:12:45 -0800128 dprintf(INFO, "Waiting for the RPM to populate smd channel table\n");
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700129
Channagoud Kadabibafde162014-12-16 10:12:45 -0800130 do
131 {
132 ret = smem_read_alloc_entry(SMEM_CHANNEL_ALLOC_TBL,
133 (void*)smd_channel_alloc_entry,
134 SMD_CHANNEL_ALLOC_MAX);
135 if(ret)
136 {
137 dprintf(CRITICAL,"ERROR reading smem channel alloc tbl\n");
138 return -1;
139 }
140
141 chnl_found = smd_get_channel_info(ch, ch_type);
142 timeout--;
143 udelay(10);
144 } while(timeout && chnl_found);
145
146 if (!timeout)
147 {
148 dprintf(CRITICAL, "Apps timed out waiting for RPM-->APPS channel entry\n");
149 ASSERT(0);
150 }
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700151
152 register_int_handler(SMD_IRQ, smd_irq_handler, ch);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700153
154 smd_set_state(ch, SMD_SS_OPENING, 1);
155
156 smd_notify_rpm();
157
Unnati Gandhia7d9a0b2014-11-13 16:03:35 +0530158 unmask_interrupt(SMD_IRQ);
159
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700160 return 0;
161}
162
163void smd_uninit(smd_channel_info_t *ch)
164{
Channagoud Kadabi54aafe42014-11-21 19:26:16 -0800165 event_init(&smd_closed, false, EVENT_FLAG_AUTOUNSIGNAL);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700166 smd_set_state(ch, SMD_SS_CLOSING, 1);
167
168 smd_notify_rpm();
Channagoud Kadabi54aafe42014-11-21 19:26:16 -0800169 /* Wait for the SMD-RPM channel to be closed */
170 event_wait(&smd_closed);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700171}
172
173bool is_channel_open(smd_channel_info_t *ch)
174{
175 if(ch->port_info->ch0.stream_state == SMD_SS_OPENED &&
176 (ch->port_info->ch1.stream_state == SMD_SS_OPENED ||
177 ch->port_info->ch1.stream_state == SMD_SS_FLUSHING))
178 return true;
179 else
180 return false;
181}
182
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700183/* Copy the local buffer to fifo buffer.
184 * Takes care of fifo overlap.
185 * Uses the fifo as circular buffer, if the request data
186 * exceeds the max size of the buffer start from the beginning.
187 */
188static void memcpy_to_fifo(smd_channel_info_t *ch_ptr, uint32_t *src, size_t len)
189{
190 uint32_t write_index = ch_ptr->port_info->ch0.write_index;
191 uint32_t *dest = (uint32_t *)(ch_ptr->send_buf + write_index);
192
193 while(len)
194 {
195 *dest++ = *src++;
196 write_index += 4;
197 len -= 4;
198
199 if (write_index >= ch_ptr->fifo_size)
200 {
201 write_index = 0;
202 dest = (uint32_t *)(ch_ptr->send_buf + write_index);
203 }
204 }
205 ch_ptr->port_info->ch0.write_index = write_index;
206}
207
208/* Copy the fifo buffer to a local destination.
209 * Takes care of fifo overlap.
210 * If the response data is split across with some part at
211 * end of fifo and some at the beginning of the fifo
212 */
213void memcpy_from_fifo(smd_channel_info_t *ch_ptr, uint32_t *dest, size_t len)
214{
215 uint32_t read_index = ch_ptr->port_info->ch1.read_index;
216 uint32_t *src = (uint32_t *)(ch_ptr->recv_buf + read_index);
217
218 while(len)
219 {
220 *dest++ = *src++;
221 read_index += 4;
222 len -= 4;
223
224 if (read_index >= ch_ptr->fifo_size)
225 {
226 read_index = 0;
227 src = (uint32_t *) (ch_ptr->recv_buf + read_index);
228 }
229 }
230
231 ch_ptr->port_info->ch1.read_index = read_index;
232}
233
Channagoud Kadabi637683d2014-11-26 14:51:14 -0800234void smd_read(smd_channel_info_t *ch, uint32_t *len, int ch_type, uint32_t *response)
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700235{
236 smd_pkt_hdr smd_hdr;
237 uint32_t size = 0;
238
239 /* Read the indices from smem */
240 ch->port_info = smem_get_alloc_entry(SMEM_SMD_BASE_ID + ch->alloc_entry.cid,
241 &size);
Parth Dixit99ae9a82015-06-03 12:12:33 +0530242 if(!ch->port_info)
243 {
244 dprintf(CRITICAL,"%s: unable to find index in smem\n", __func__);
245 ASSERT(0);
246 }
247
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700248 if(!ch->port_info->ch1.DTR_DSR)
249 {
250 dprintf(CRITICAL,"%s: DTR is off\n", __func__);
Sridhar Parasuramf2348af2014-11-18 16:16:57 -0800251 ASSERT(0);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700252 }
253
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700254 /* Wait until the data updated in the smd buffer is equal to smd packet header*/
255 while ((ch->port_info->ch1.write_index - ch->port_info->ch1.read_index) < sizeof(smd_pkt_hdr))
256 {
257 /* Get the update info from memory */
258 arch_invalidate_cache_range((addr_t) ch->port_info, size);
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700259 }
260
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700261 /* Copy the smd buffer to local buf */
Sridhar Parasuramf2348af2014-11-18 16:16:57 -0800262 memcpy_from_fifo(ch, (uint32_t *)&smd_hdr, sizeof(smd_hdr));
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700263
264 arch_invalidate_cache_range((addr_t)&smd_hdr, sizeof(smd_hdr));
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700265
266 *len = smd_hdr.pkt_size;
267
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700268 /* Wait on the data being updated in SMEM before returing the response */
269 while ((ch->port_info->ch1.write_index - ch->port_info->ch1.read_index) < smd_hdr.pkt_size)
270 {
271 /* Get the update info from memory */
272 arch_invalidate_cache_range((addr_t) ch->port_info, size);
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700273 }
274
275 /* We are good to return the response now */
Channagoud Kadabi637683d2014-11-26 14:51:14 -0800276 memcpy_from_fifo(ch, response, smd_hdr.pkt_size);
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700277
Channagoud Kadabi637683d2014-11-26 14:51:14 -0800278 arch_invalidate_cache_range((addr_t)response, smd_hdr.pkt_size);
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700279
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700280}
281
282void smd_signal_read_complete(smd_channel_info_t *ch, uint32_t len)
283{
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700284 /* Clear the data_written flag */
285 ch->port_info->ch1.data_written = 0;
286
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700287 /* Set the data_read flag */
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700288 ch->port_info->ch0.data_read = 1;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700289 ch->port_info->ch0.mask_recv_intr = 1;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700290
291 dsb();
292
293 smd_notify_rpm();
294}
295
296int smd_write(smd_channel_info_t *ch, void *data, uint32_t len, int ch_type)
297{
298 smd_pkt_hdr smd_hdr;
299 uint32_t size = 0;
300
301 memset(&smd_hdr, 0, sizeof(smd_pkt_hdr));
302
303 if(len + sizeof(smd_hdr) > ch->fifo_size)
304 {
305 dprintf(CRITICAL,"%s: len is greater than fifo sz\n", __func__);
306 return -1;
307 }
308
309 /* Read the indices from smem */
310 ch->port_info = smem_get_alloc_entry(SMEM_SMD_BASE_ID + ch->alloc_entry.cid,
311 &size);
Parth Dixit99ae9a82015-06-03 12:12:33 +0530312 if(!ch->port_info)
313 {
314 dprintf(CRITICAL,"%s: unable to find index in smem\n", __func__);
315 ASSERT(0);
316 }
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700317
318 if(!is_channel_open(ch))
319 {
320 dprintf(CRITICAL,"%s: channel is not in OPEN state \n", __func__);
321 return -1;
322 }
323
324 if(!ch->port_info->ch0.DTR_DSR)
325 {
326 dprintf(CRITICAL,"%s: DTR is off\n", __func__);
327 return -1;
328 }
329
330 /* Clear the data_read flag */
331 ch->port_info->ch1.data_read = 0;
332
333 /*copy the local buf to smd buf */
334 smd_hdr.pkt_size = len;
335
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700336 memcpy_to_fifo(ch, (uint32_t *)&smd_hdr, sizeof(smd_hdr));
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700337
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700338 memcpy_to_fifo(ch, data, len);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700339
340 dsb();
341
342 /* Set the necessary flags */
343
344 ch->port_info->ch0.data_written = 1;
345 ch->port_info->ch0.mask_recv_intr = 0;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700346
347 dsb();
348
349 smd_notify_rpm();
350
351 return 0;
352}
353
354void smd_notify_rpm()
355{
356 /* Set BIT 0 to notify RPM via IPC interrupt*/
357 writel(BIT(0), APCS_ALIAS0_IPC_INTERRUPT);
358}
359
360void smd_set_state(smd_channel_info_t *ch, uint32_t state, uint32_t flag)
361{
362 uint32_t current_state;
363 uint32_t size = 0;
364
365 if(!ch->port_info)
366 {
367 ch->port_info = smem_get_alloc_entry(SMEM_SMD_BASE_ID + ch->alloc_entry.cid,
368 &size);
369 ASSERT(ch->port_info);
370 }
371
372 current_state = ch->port_info->ch0.stream_state;
373
374 switch(state)
375 {
376 case SMD_SS_CLOSED:
377 if(current_state == SMD_SS_OPENED)
378 {
379 smd_write_state(ch, SMD_SS_CLOSING);
380 }
381 else
382 {
383 smd_write_state(ch, SMD_SS_CLOSED);
384 }
385 break;
386 case SMD_SS_OPENING:
387 if(current_state == SMD_SS_CLOSING || current_state == SMD_SS_CLOSED)
388 {
389 smd_write_state(ch, SMD_SS_OPENING);
390 ch->port_info->ch1.read_index = 0;
391 ch->port_info->ch0.write_index = 0;
392 ch->port_info->ch0.mask_recv_intr = 0;
393 }
394 break;
395 case SMD_SS_OPENED:
396 if(current_state == SMD_SS_OPENING)
397 {
398 smd_write_state(ch, SMD_SS_OPENED);
399 }
400 break;
401 case SMD_SS_CLOSING:
402 if(current_state == SMD_SS_OPENED)
403 {
404 smd_write_state(ch, SMD_SS_CLOSING);
405 }
406 break;
407 case SMD_SS_FLUSHING:
408 case SMD_SS_RESET:
409 case SMD_SS_RESET_OPENING:
410 default:
411 break;
412 }
413
414 ch->current_state = state;
415
416 smd_state_update(ch, flag);
417}
418
Parth Dixit7cda4982015-06-24 12:36:25 +0530419static void flush_smd_channel_entries()
420{
421 int i = 0;
422 for(i = 0; i< SMEM_NUM_SMD_STREAM_CHANNELS; i++)
423 {
424 arch_invalidate_cache_range((addr_t)&smd_channel_alloc_entry[i],
425 sizeof(smd_channel_alloc_entry_t));
426 }
427}
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700428
429enum handler_return smd_irq_handler(void* data)
430{
431 smd_channel_info_t *ch = (smd_channel_info_t*)data;
432
433 if(ch->current_state == SMD_SS_CLOSED)
434 {
Parth Dixit7cda4982015-06-24 12:36:25 +0530435 flush_smd_channel_entries();
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700436 free(smd_channel_alloc_entry);
Channagoud Kadabi54aafe42014-11-21 19:26:16 -0800437 event_signal(&smd_closed, false);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700438 return INT_NO_RESCHEDULE;
439 }
440
441 if(ch->port_info->ch1.state_updated)
442 ch->port_info->ch1.state_updated = 0;
443
444 /* Should we have to use a do while and change states until we complete */
445 if(ch->current_state != ch->port_info->ch1.stream_state)
446 {
447 smd_set_state(ch, ch->port_info->ch1.stream_state, 0);
448 }
449
450 if(ch->current_state == SMD_SS_CLOSING)
451 {
452 smd_set_state(ch, SMD_SS_CLOSED, 1);
453 smd_notify_rpm();
454 dprintf(CRITICAL,"Channel alloc freed\n");
455 }
456
457 return INT_NO_RESCHEDULE;
458}