blob: 758947cf86adcb3b6d4f3292a672c1bfcae9b108 [file] [log] [blame]
Maria Yu4c12e922018-05-10 16:18:20 +08001/* Copyright (c) 2014-2015, 2018, 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>
Maria Yu4c12e922018-05-10 16:18:20 +080041#include <stdlib.h>
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070042
Channagoud Kadabibafde162014-12-16 10:12:45 -080043#define SMD_CHANNEL_ACCESS_RETRY 1000000
44
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070045smd_channel_alloc_entry_t *smd_channel_alloc_entry;
Channagoud Kadabi54aafe42014-11-21 19:26:16 -080046static event_t smd_closed;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070047
48static void smd_write_state(smd_channel_info_t *ch, uint32_t state)
49{
50 if(state == SMD_SS_OPENED)
51 {
52 ch->port_info->ch0.DTR_DSR = 1;
53 ch->port_info->ch0.CTS_RTS = 1;
54 ch->port_info->ch0.CD = 1;
55 }
56 else
57 {
58 ch->port_info->ch0.DTR_DSR = 0;
59 ch->port_info->ch0.CTS_RTS = 0;
60 ch->port_info->ch0.CD = 0;
61 }
62
63 ch->port_info->ch0.stream_state = state;
64}
65
66static void smd_state_update(smd_channel_info_t *ch, uint32_t flag)
67{
68 ch->port_info->ch0.state_updated = flag;
69}
70
Channagoud Kadabibafde162014-12-16 10:12:45 -080071int smd_get_channel_entry(smd_channel_info_t *ch, uint32_t ch_type)
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070072{
73 int i = 0;
74
75 for(i = 0; i< SMEM_NUM_SMD_STREAM_CHANNELS; i++)
76 {
77 if((smd_channel_alloc_entry[i].ctype & 0xFF) == ch_type)
78 {
79 memcpy(&ch->alloc_entry, &smd_channel_alloc_entry[i], sizeof(smd_channel_alloc_entry_t));
80 break;
81 }
82 }
83
Channagoud Kadabibafde162014-12-16 10:12:45 -080084 /* Channel not found, retry again */
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070085 if(i == SMEM_NUM_SMD_STREAM_CHANNELS)
86 {
Channagoud Kadabibafde162014-12-16 10:12:45 -080087 dprintf(SPEW, "Channel not found, wait and retry for the update\n");
88 return -1;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070089 }
Channagoud Kadabibafde162014-12-16 10:12:45 -080090
91 return 0;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -070092}
93
94int smd_get_channel_info(smd_channel_info_t *ch, uint32_t ch_type)
95{
96 int ret = 0;
97 uint8_t *fifo_buf = NULL;
98 uint32_t fifo_buf_size = 0;
99 uint32_t size = 0;
100
Channagoud Kadabibafde162014-12-16 10:12:45 -0800101 ret = smd_get_channel_entry(ch, ch_type);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700102
Channagoud Kadabibafde162014-12-16 10:12:45 -0800103 if (ret)
104 return ret;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700105
106 ch->port_info = smem_get_alloc_entry(SMEM_SMD_BASE_ID + ch->alloc_entry.cid,
107 &size);
108
109 fifo_buf = smem_get_alloc_entry(SMEM_SMD_FIFO_BASE_ID + ch->alloc_entry.cid,
110 &fifo_buf_size);
111
112 fifo_buf_size /= 2;
113 ch->send_buf = fifo_buf;
114 ch->recv_buf = fifo_buf + fifo_buf_size;
115 ch->fifo_size = fifo_buf_size;
116
117 return ret;
118}
119
120int smd_init(smd_channel_info_t *ch, uint32_t ch_type)
121{
122 unsigned ret = 0;
Channagoud Kadabibafde162014-12-16 10:12:45 -0800123 int chnl_found = 0;
124 uint64_t timeout = SMD_CHANNEL_ACCESS_RETRY;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700125
126 smd_channel_alloc_entry = (smd_channel_alloc_entry_t*)memalign(CACHE_LINE, SMD_CHANNEL_ALLOC_MAX);
127 ASSERT(smd_channel_alloc_entry);
128
Channagoud Kadabibafde162014-12-16 10:12:45 -0800129 dprintf(INFO, "Waiting for the RPM to populate smd channel table\n");
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700130
Channagoud Kadabibafde162014-12-16 10:12:45 -0800131 do
132 {
133 ret = smem_read_alloc_entry(SMEM_CHANNEL_ALLOC_TBL,
134 (void*)smd_channel_alloc_entry,
135 SMD_CHANNEL_ALLOC_MAX);
136 if(ret)
137 {
138 dprintf(CRITICAL,"ERROR reading smem channel alloc tbl\n");
139 return -1;
140 }
141
142 chnl_found = smd_get_channel_info(ch, ch_type);
143 timeout--;
144 udelay(10);
145 } while(timeout && chnl_found);
146
147 if (!timeout)
148 {
149 dprintf(CRITICAL, "Apps timed out waiting for RPM-->APPS channel entry\n");
150 ASSERT(0);
151 }
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700152
153 register_int_handler(SMD_IRQ, smd_irq_handler, ch);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700154
155 smd_set_state(ch, SMD_SS_OPENING, 1);
156
157 smd_notify_rpm();
158
Unnati Gandhia7d9a0b2014-11-13 16:03:35 +0530159 unmask_interrupt(SMD_IRQ);
160
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700161 return 0;
162}
163
164void smd_uninit(smd_channel_info_t *ch)
165{
Channagoud Kadabi54aafe42014-11-21 19:26:16 -0800166 event_init(&smd_closed, false, EVENT_FLAG_AUTOUNSIGNAL);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700167 smd_set_state(ch, SMD_SS_CLOSING, 1);
168
169 smd_notify_rpm();
Channagoud Kadabi54aafe42014-11-21 19:26:16 -0800170 /* Wait for the SMD-RPM channel to be closed */
171 event_wait(&smd_closed);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700172}
173
174bool is_channel_open(smd_channel_info_t *ch)
175{
176 if(ch->port_info->ch0.stream_state == SMD_SS_OPENED &&
177 (ch->port_info->ch1.stream_state == SMD_SS_OPENED ||
178 ch->port_info->ch1.stream_state == SMD_SS_FLUSHING))
179 return true;
180 else
181 return false;
182}
183
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700184/* Copy the local buffer to fifo buffer.
185 * Takes care of fifo overlap.
186 * Uses the fifo as circular buffer, if the request data
187 * exceeds the max size of the buffer start from the beginning.
188 */
189static void memcpy_to_fifo(smd_channel_info_t *ch_ptr, uint32_t *src, size_t len)
190{
191 uint32_t write_index = ch_ptr->port_info->ch0.write_index;
192 uint32_t *dest = (uint32_t *)(ch_ptr->send_buf + write_index);
193
194 while(len)
195 {
Maria Yu4c12e922018-05-10 16:18:20 +0800196 writel(*src++, dest++);
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700197 write_index += 4;
198 len -= 4;
199
200 if (write_index >= ch_ptr->fifo_size)
201 {
202 write_index = 0;
203 dest = (uint32_t *)(ch_ptr->send_buf + write_index);
204 }
205 }
206 ch_ptr->port_info->ch0.write_index = write_index;
207}
208
209/* Copy the fifo buffer to a local destination.
210 * Takes care of fifo overlap.
211 * If the response data is split across with some part at
212 * end of fifo and some at the beginning of the fifo
213 */
214void memcpy_from_fifo(smd_channel_info_t *ch_ptr, uint32_t *dest, size_t len)
215{
216 uint32_t read_index = ch_ptr->port_info->ch1.read_index;
217 uint32_t *src = (uint32_t *)(ch_ptr->recv_buf + read_index);
218
219 while(len)
220 {
Maria Yu4c12e922018-05-10 16:18:20 +0800221 *dest++ = readl(src++);
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700222 read_index += 4;
223 len -= 4;
224
225 if (read_index >= ch_ptr->fifo_size)
226 {
227 read_index = 0;
228 src = (uint32_t *) (ch_ptr->recv_buf + read_index);
229 }
230 }
231
232 ch_ptr->port_info->ch1.read_index = read_index;
233}
234
Channagoud Kadabi637683d2014-11-26 14:51:14 -0800235void smd_read(smd_channel_info_t *ch, uint32_t *len, int ch_type, uint32_t *response)
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700236{
237 smd_pkt_hdr smd_hdr;
238 uint32_t size = 0;
239
240 /* Read the indices from smem */
241 ch->port_info = smem_get_alloc_entry(SMEM_SMD_BASE_ID + ch->alloc_entry.cid,
242 &size);
Parth Dixit99ae9a82015-06-03 12:12:33 +0530243 if(!ch->port_info)
244 {
245 dprintf(CRITICAL,"%s: unable to find index in smem\n", __func__);
246 ASSERT(0);
247 }
248
Maria Yu4c12e922018-05-10 16:18:20 +0800249 arch_invalidate_cache_range((addr_t) ch->port_info, ROUNDUP(size, CACHE_LINE));
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700250 if(!ch->port_info->ch1.DTR_DSR)
251 {
252 dprintf(CRITICAL,"%s: DTR is off\n", __func__);
Sridhar Parasuramf2348af2014-11-18 16:16:57 -0800253 ASSERT(0);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700254 }
255
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700256 /* Wait until the data updated in the smd buffer is equal to smd packet header*/
Maria Yu4c12e922018-05-10 16:18:20 +0800257 do {
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700258 /* Get the update info from memory */
Maria Yu4c12e922018-05-10 16:18:20 +0800259 arch_invalidate_cache_range((addr_t) ch->port_info, ROUNDUP(size, CACHE_LINE));
260 } while ((ch->port_info->ch1.write_index - ch->port_info->ch1.read_index) < sizeof(smd_pkt_hdr));
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700261
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700262 /* Copy the smd buffer to local buf */
Sridhar Parasuramf2348af2014-11-18 16:16:57 -0800263 memcpy_from_fifo(ch, (uint32_t *)&smd_hdr, sizeof(smd_hdr));
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700264
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 */
Maria Yu4c12e922018-05-10 16:18:20 +0800269 do {
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700270 /* Get the update info from memory */
Maria Yu4c12e922018-05-10 16:18:20 +0800271 arch_invalidate_cache_range((addr_t) ch->port_info, ROUNDUP(size, CACHE_LINE));
272 } while ((ch->port_info->ch1.write_index - ch->port_info->ch1.read_index) < smd_hdr.pkt_size);
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700273
274 /* We are good to return the response now */
Channagoud Kadabi637683d2014-11-26 14:51:14 -0800275 memcpy_from_fifo(ch, response, smd_hdr.pkt_size);
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700276
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700277}
278
279void smd_signal_read_complete(smd_channel_info_t *ch, uint32_t len)
280{
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700281 /* Clear the data_written flag */
282 ch->port_info->ch1.data_written = 0;
283
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700284 /* Set the data_read flag */
Channagoud Kadabi161d7cc2014-08-13 12:57:16 -0700285 ch->port_info->ch0.data_read = 1;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700286 ch->port_info->ch0.mask_recv_intr = 1;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700287
288 dsb();
289
290 smd_notify_rpm();
291}
292
293int smd_write(smd_channel_info_t *ch, void *data, uint32_t len, int ch_type)
294{
295 smd_pkt_hdr smd_hdr;
296 uint32_t size = 0;
297
298 memset(&smd_hdr, 0, sizeof(smd_pkt_hdr));
299
300 if(len + sizeof(smd_hdr) > ch->fifo_size)
301 {
302 dprintf(CRITICAL,"%s: len is greater than fifo sz\n", __func__);
303 return -1;
304 }
305
306 /* Read the indices from smem */
307 ch->port_info = smem_get_alloc_entry(SMEM_SMD_BASE_ID + ch->alloc_entry.cid,
308 &size);
Parth Dixit99ae9a82015-06-03 12:12:33 +0530309 if(!ch->port_info)
310 {
311 dprintf(CRITICAL,"%s: unable to find index in smem\n", __func__);
312 ASSERT(0);
313 }
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700314
315 if(!is_channel_open(ch))
316 {
317 dprintf(CRITICAL,"%s: channel is not in OPEN state \n", __func__);
318 return -1;
319 }
320
321 if(!ch->port_info->ch0.DTR_DSR)
322 {
323 dprintf(CRITICAL,"%s: DTR is off\n", __func__);
324 return -1;
325 }
326
327 /* Clear the data_read flag */
328 ch->port_info->ch1.data_read = 0;
329
330 /*copy the local buf to smd buf */
331 smd_hdr.pkt_size = len;
332
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700333 memcpy_to_fifo(ch, (uint32_t *)&smd_hdr, sizeof(smd_hdr));
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700334
Channagoud Kadabi4e3dc812014-10-14 12:32:56 -0700335 memcpy_to_fifo(ch, data, len);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700336
337 dsb();
338
339 /* Set the necessary flags */
340
341 ch->port_info->ch0.data_written = 1;
342 ch->port_info->ch0.mask_recv_intr = 0;
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700343
344 dsb();
345
346 smd_notify_rpm();
347
348 return 0;
349}
350
351void smd_notify_rpm()
352{
353 /* Set BIT 0 to notify RPM via IPC interrupt*/
354 writel(BIT(0), APCS_ALIAS0_IPC_INTERRUPT);
355}
356
357void smd_set_state(smd_channel_info_t *ch, uint32_t state, uint32_t flag)
358{
359 uint32_t current_state;
360 uint32_t size = 0;
361
362 if(!ch->port_info)
363 {
364 ch->port_info = smem_get_alloc_entry(SMEM_SMD_BASE_ID + ch->alloc_entry.cid,
365 &size);
366 ASSERT(ch->port_info);
367 }
368
369 current_state = ch->port_info->ch0.stream_state;
370
371 switch(state)
372 {
373 case SMD_SS_CLOSED:
374 if(current_state == SMD_SS_OPENED)
375 {
376 smd_write_state(ch, SMD_SS_CLOSING);
377 }
378 else
379 {
380 smd_write_state(ch, SMD_SS_CLOSED);
381 }
382 break;
383 case SMD_SS_OPENING:
384 if(current_state == SMD_SS_CLOSING || current_state == SMD_SS_CLOSED)
385 {
386 smd_write_state(ch, SMD_SS_OPENING);
387 ch->port_info->ch1.read_index = 0;
388 ch->port_info->ch0.write_index = 0;
389 ch->port_info->ch0.mask_recv_intr = 0;
390 }
391 break;
392 case SMD_SS_OPENED:
393 if(current_state == SMD_SS_OPENING)
394 {
395 smd_write_state(ch, SMD_SS_OPENED);
396 }
397 break;
398 case SMD_SS_CLOSING:
399 if(current_state == SMD_SS_OPENED)
400 {
401 smd_write_state(ch, SMD_SS_CLOSING);
402 }
403 break;
404 case SMD_SS_FLUSHING:
405 case SMD_SS_RESET:
406 case SMD_SS_RESET_OPENING:
407 default:
408 break;
409 }
410
411 ch->current_state = state;
412
413 smd_state_update(ch, flag);
414}
415
Parth Dixit7cda4982015-06-24 12:36:25 +0530416static void flush_smd_channel_entries()
417{
Maria Yu4c12e922018-05-10 16:18:20 +0800418 arch_invalidate_cache_range((addr_t)smd_channel_alloc_entry,
419 SMD_CHANNEL_ALLOC_MAX);
Parth Dixit7cda4982015-06-24 12:36:25 +0530420}
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700421
422enum handler_return smd_irq_handler(void* data)
423{
424 smd_channel_info_t *ch = (smd_channel_info_t*)data;
425
426 if(ch->current_state == SMD_SS_CLOSED)
427 {
Parth Dixit7cda4982015-06-24 12:36:25 +0530428 flush_smd_channel_entries();
Parth Dixit5be68892016-01-13 11:43:58 +0530429 if(smd_channel_alloc_entry)
430 {
431 free(smd_channel_alloc_entry);
432 smd_channel_alloc_entry = NULL;
433 }
Channagoud Kadabi54aafe42014-11-21 19:26:16 -0800434 event_signal(&smd_closed, false);
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700435 return INT_NO_RESCHEDULE;
436 }
437
438 if(ch->port_info->ch1.state_updated)
439 ch->port_info->ch1.state_updated = 0;
440
441 /* Should we have to use a do while and change states until we complete */
442 if(ch->current_state != ch->port_info->ch1.stream_state)
443 {
444 smd_set_state(ch, ch->port_info->ch1.stream_state, 0);
445 }
446
447 if(ch->current_state == SMD_SS_CLOSING)
448 {
449 smd_set_state(ch, SMD_SS_CLOSED, 1);
450 smd_notify_rpm();
Mayank Grover71f63862018-05-03 17:06:41 +0530451 dprintf(SPEW,"Channel alloc freed\n");
Sundarajan Srinivasanae6ece02014-07-01 14:01:29 -0700452 }
453
454 return INT_NO_RESCHEDULE;
455}