blob: 0903c9ddd426dad55134d6b5dece3534b0be53de [file] [log] [blame]
Deepa Dinamani9d470af2012-06-29 18:27:17 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2
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 Code Aurora Forum, 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#include <bam.h>
30#include <reg.h>
31#include <debug.h>
32#include <stdlib.h>
33#include <platform/interrupts.h>
34#include <platform/iomap.h>
35#include <platform/irqs.h>
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -070036#include <pow2.h>
Deepa Dinamani9d470af2012-06-29 18:27:17 -070037
38#define HLOS_EE_INDEX 0
39
40/* Reset BAM registers and pipes */
41static void bam_reset(struct bam_instance *bam)
42{
43 /* Initiate SW reset */
44 writel(BAM_SW_RST_BIT_MASK, BAM_CTRL_REG(bam->base));
45
46 /* No delay required */
47
48 /* Disable SW reset */
49 writel(~BAM_SW_RST_BIT_MASK, BAM_CTRL_REG(bam->base));
50}
51
52/* Resets pipe registers and state machines */
Deepa Dinamani87feab82012-10-04 14:28:05 -070053void bam_pipe_reset(struct bam_instance *bam,
54 uint8_t pipe_num)
Deepa Dinamani9d470af2012-06-29 18:27:17 -070055{
56 /* Start sw reset of the pipe to be allocated */
57 writel(1, BAM_P_RSTn(bam->pipe[pipe_num].pipe_num, bam->base));
58
59 /* No delay required */
60
61 /* Stop sw reset of the pipe to be allocated */
62 writel(0, BAM_P_RSTn(bam->pipe[pipe_num].pipe_num, bam->base));
63}
64
65static enum handler_return bam_interrupt_handler(void* arg)
66{
67 return 0;
68}
69
70/* A blocking function that waits till an interrupt is signalled.
71 * bam : BAM instance for the descriptors to be queued.
72 * pipe_num : pipe number for the descriptors to be queued.
73 * interrupt: interrupt to wait for.
74 */
75int bam_wait_for_interrupt(struct bam_instance *bam,
76 uint8_t pipe_num,
77 enum p_int_type interrupt)
78{
79 uint32_t val;
80
81 while (1)
82 {
83 /* Wait for a interrupt on the right pipe */
84 do{
85 /* Determine the pipe causing the interrupt */
86 val = readl(BAM_IRQ_SRCS(bam->base));
87 /* Flush out the right most global interrupt bit */
88 } while (!((val & 0x7FFF) & (1 << bam->pipe[pipe_num].pipe_num)));
89
90 /* Check the reason for this BAM interrupt */
91 if (readl(BAM_IRQ_STTS(bam->base)))
92 goto bam_wait_int_error;
93
94 /* Check the interrupt type */
95 /* Read interrupt status register */
96 val = readl(BAM_P_IRQ_STTSn(bam->pipe[pipe_num].pipe_num, bam->base));
97
98 /* Check for error */
99 if (val & P_ERR_EN_MASK)
100 goto bam_wait_int_error;
101
102 if (val & interrupt)
103 {
104 /* Correct interrupt was fired. */
105 /* Clear the other interrupts */
106 val = P_OUT_OF_DESC_EN_MASK | P_PRCSD_DESC_EN_MASK | P_TRNSFR_END_EN_MASK;
107 writel (val, BAM_P_IRQ_CLRn(bam->pipe[pipe_num].pipe_num, bam->base));
108 return BAM_RESULT_SUCCESS;
109 }
110 else if (val & P_TRNSFR_END_EN_MASK)
111 {
112 dprintf(CRITICAL,
113 "Trasfer end signalled before the last descc was processed\n");
114 goto bam_wait_int_error;
115 }
116 }
117
118bam_wait_int_error:
119
120 dprintf(CRITICAL, "Unexpected interrupt\n");
121 return BAM_RESULT_FAILURE;
122}
123
124/* Enable BAM and pipe level interrupts */
125void bam_enable_interrupts(struct bam_instance *bam, uint8_t pipe_num)
126{
127
128 uint32_t int_mask = P_ERR_EN_MASK | P_OUT_OF_DESC_EN_MASK |
129 P_PRCSD_DESC_EN_MASK | P_TRNSFR_END_EN_MASK;
130 uint32_t val;
131
132 /* Enable BAM error interrupts */
133 writel(BAM_ERROR_EN_MASK, BAM_IRQ_EN_REG(bam->base));
134
135 /* Enable the interrupts for the pipe by enabling the relevant bits
136 * in the BAM_PIPE_INTERRUPT_ENABLE register.
137 */
138 writel(int_mask,
139 BAM_P_IRQ_ENn(bam->pipe[pipe_num].pipe_num, bam->base));
140
141 /* Enable pipe interrups */
142 /* Do read-modify-write */
143 val = readl(BAM_IRQ_SRCS_MSK(bam->base));
144 writel((1 << bam->pipe[pipe_num].pipe_num) | val,
145 BAM_IRQ_SRCS_MSK(bam->base));
146
147 /* Unmask the QGIC interrupts only in the case of
148 * interrupt based transfer.
149 * Use polling othwerwise.
150 */
151 if (bam->pipe[pipe_num].int_mode)
152 {
153 /* Register interrupt handler */
154 register_int_handler(bam->pipe[pipe_num].spi_num, bam_interrupt_handler, 0);
155
156 /* Unmask the interrupt */
157 unmask_interrupt(bam->pipe[pipe_num].spi_num);
158 }
159}
160
161/* Reset and initialize the bam module */
162void bam_init(struct bam_instance *bam)
163{
164 uint32_t val = 0;
165
Deepa Dinamani87feab82012-10-04 14:28:05 -0700166// bam_reset(bam);
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700167
168 /* Check for only one pipe's direction.
169 * The other is assumed to be the opposite system
170 * transaction.
171 */
172 if (bam->pipe[0].trans_type == SYS2BAM ||
173 bam->pipe[0].trans_type == BAM2SYS)
174 {
175 /* Program the threshold count */
176 writel(bam->threshold, BAM_DESC_CNT_TRSHLD_REG(bam->base));
177 }
178
179 /* Program config register for H/W bug fixes */
180 val = 0xffffffff & ~(1 << 11);
181 writel(val, BAM_CNFG_BITS(bam->base));
182
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700183 /* Enable the BAM */
184 writel(BAM_ENABLE_BIT_MASK, BAM_CTRL_REG(bam->base));
185}
186
187/* Funtion to setup a simple fifo structure.
188 * Note: Addr should be 8 byte aligned.
189 * bam : BAM instance for the descriptors to be queued.
190 * pipe_num : pipe number for the descriptors to be queued.
191 */
192int bam_pipe_fifo_init(struct bam_instance *bam,
193 uint8_t pipe_num)
194{
195
196 if (bam->pipe[pipe_num].fifo.size > 0x7FFF)
197 {
198 dprintf(CRITICAL,
199 "Size exceeds max size for a descriptor(0x7FFF)\n");
200 return BAM_RESULT_FAILURE;
201 }
202
203 /* Check if fifo start is 8-byte alligned */
204 ASSERT(!((uint32_t)bam->pipe[pipe_num].fifo.head & 0x7));
205
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700206 /* Check if fifo size is a power of 2.
207 * The circular fifo logic in lk expects this.
208 */
209 ASSERT(ispow2(bam->pipe[pipe_num].fifo.size));
210
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700211 bam->pipe[pipe_num].fifo.current = bam->pipe[pipe_num].fifo.head;
212
213 /* Set the descriptor buffer size. Must be a multiple of 8 */
214 writel(bam->pipe[pipe_num].fifo.size * BAM_DESC_SIZE,
215 BAM_P_FIFO_SIZESn(bam->pipe[pipe_num].pipe_num, bam->base));
216
217 /* Write descriptors FIFO base addr must be 8-byte aligned */
218 writel((uint32_t)bam->pipe[pipe_num].fifo.head,
219 BAM_P_DESC_FIFO_ADDRn(bam->pipe[pipe_num].pipe_num, bam->base));
220
221 /* Initialize FIFO offset for the first read */
222 bam->pipe[pipe_num].fifo.offset = BAM_DESC_SIZE;
223
224 /* Everything is set.
225 * Flag pipe init done.
226 */
227 bam->pipe[pipe_num].initialized = 1;
228
229 return BAM_RESULT_SUCCESS;
230}
231
232void bam_sys_pipe_init(struct bam_instance *bam,
233 uint8_t pipe_num)
234{
235 uint32_t val = 0;
236
237 /* Reset the pipe to be allocated */
238 bam_pipe_reset(bam, pipe_num);
239
240 /* Enable minimal interrupts */
241 bam_enable_interrupts(bam, pipe_num);
242
243 /* Pipe event threshold register is not relevant in sys modes */
244
245 /* Enable pipe in system mode and set the direction */
246 writel(P_SYS_MODE_MASK | P_ENABLE |
247 (bam->pipe[pipe_num].trans_type << P_DIRECTION_SHIFT),
248 BAM_P_CTRLn(bam->pipe[pipe_num].pipe_num, bam->base));
249
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700250 /* Mark the pipe FIFO as uninitialized. */
251 bam->pipe[pipe_num].initialized = 0;
252}
253
254/* Function to notify written descriptors to BAM.
255 * bam : BAM instance for the descriptors to be queued.
256 * pipe_num : pipe number for the descriptors to be queued.
257 * num_desc : number of the descriptors.
258 * fifo : Circular FIFO used for the descriptors.
259 */
260void bam_sys_gen_event(struct bam_instance *bam,
261 uint8_t pipe_num,
262 unsigned int num_desc)
263{
264 uint32_t val = 0;
265
266 if (num_desc >= bam->pipe[pipe_num].fifo.size) {
267 dprintf(CRITICAL,
268 "Max allowed desc is one less than the fifo length\n");
269 return;
270 }
271
272 /* Update the fifo peer offset */
273 val = (num_desc - 1) * BAM_DESC_SIZE;
274 val += bam->pipe[pipe_num].fifo.offset;
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700275 val &= (bam->pipe[pipe_num].fifo.size * BAM_DESC_SIZE - 1);
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700276
277 writel(val, BAM_P_EVNT_REGn(bam->pipe[pipe_num].pipe_num, bam->base));
278}
279
280/* Function to read the updates for FIFO offsets.
281 * bam : BAM that uses the FIFO.
282 * pipe : BAM pipe that uses the FIFO.
283 * return : FIFO offset where the next descriptor should be written.
284 * Note : S/W maintains the circular properties of the FIFO and updates
285 * the offsets accordingly.
286 */
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700287void bam_read_offset_update(struct bam_instance *bam, unsigned int pipe_num)
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700288{
289 uint32_t offset;
290
291 offset = readl(BAM_P_SW_OFSTSn(bam->pipe[pipe_num].pipe_num, bam->base));
292 offset &= 0xFFFF;
293
294 dprintf(INFO, "Offset value is %d \n", offset);
295
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700296 /* Save the next offset to be written to. */
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700297 bam->pipe[pipe_num].fifo.current = (struct bam_desc*)
298 ((uint32_t)bam->pipe[pipe_num].fifo.head + offset);
299
300 bam->pipe[pipe_num].fifo.offset = offset + BAM_DESC_SIZE ;
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700301}
302
303/* Function to get the next desc address.
304 * Keeps track of circular properties of the FIFO
305 * and returns the appropriate address.
306 */
307static struct bam_desc* fifo_getnext(struct bam_desc_fifo *fifo,
308 struct bam_desc* desc)
309{
310 uint16_t offset;
311
312 offset = desc - fifo->head;
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700313
314 if (offset == (fifo->size - 1))
315 return fifo->head;
316 else
317 return desc + 1;
318}
319
320/* Function to add BAM descriptors for a given fifo.
321 * bam : BAM instance to be used.
322 * data_ptr : Memory address for data transfer.
323 * data_len : Length of the data_ptr.
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700324 * flags : Flags to be set on the last desc added.
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700325 *
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700326 * Note: This function also notifies the BAM about the added descriptors.
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700327 */
328int bam_add_desc(struct bam_instance *bam,
329 unsigned int pipe_num,
330 unsigned char *data_ptr,
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700331 unsigned int data_len,
332 unsigned flags)
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700333{
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700334 int bam_ret = BAM_RESULT_SUCCESS;
335 unsigned int len = data_len;
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700336 unsigned int desc_len;
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700337 unsigned int n = 0;
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700338 unsigned int desc_flags;
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700339
340 dprintf(INFO, "Data length for BAM transfer is %u\n", data_len);
341
342 if (data_ptr == NULL || len == 0)
343 {
344 dprintf(CRITICAL, "Wrong params for BAM transfer \n");
345 bam_ret = BAM_RESULT_FAILURE;
346 goto bam_add_desc_error;
347 }
348
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700349 /* Check if we have enough space in FIFO */
350 if (len > (unsigned)bam->pipe[pipe_num].fifo.size * BAM_MAX_DESC_DATA_LEN)
351 {
352 dprintf(CRITICAL, "Data transfer exceeds desc fifo length.\n");
353 bam_ret = BAM_RESULT_FAILURE;
354 goto bam_add_desc_error;
355 }
356
357 while (len)
358 {
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700359
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700360 /* There are only 16 bits to write data length.
361 * If more bits are needed, create more
362 * descriptors.
363 */
364 if (len > BAM_MAX_DESC_DATA_LEN)
365 {
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700366 desc_len = BAM_MAX_DESC_DATA_LEN;
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700367 len -= BAM_MAX_DESC_DATA_LEN;
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700368 desc_flags = 0;
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700369 }
370 else
371 {
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700372 desc_len = len;
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700373 len = 0;
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700374 /* Set correct flags on the last desc. */
375 desc_flags = flags;
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700376 }
377
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700378 /* Write descriptor */
379 bam_add_one_desc(bam, pipe_num, data_ptr, desc_len, desc_flags);
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700380
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700381 data_ptr += BAM_MAX_DESC_DATA_LEN;
382 n++;
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700383 }
384
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700385
386 /* Create a read/write event to notify the periperal of the added desc. */
387 bam_sys_gen_event(bam, pipe_num, n);
388
389bam_add_desc_error:
390
391 return bam_ret;
392}
393
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700394/* Function to add a BAM descriptor for a given fifo.
395 * bam : BAM instance to be used.
396 * data_ptr : Memory address for data transfer.
397 * data_len : Length of the data_ptr.
398 * flags : Flags to be set on the desc added.
399 *
400 * Note: This function does not notify the BAM about the added descriptor.
401 */
402int bam_add_one_desc(struct bam_instance *bam,
403 unsigned int pipe_num,
404 unsigned char* data_ptr,
405 uint32_t len,
406 uint8_t flags)
407{
408
409 struct bam_desc *desc = bam->pipe[pipe_num].fifo.current;
410 int bam_ret = BAM_RESULT_SUCCESS;
411
412 if (data_ptr == NULL || len == 0)
413 {
414 dprintf(CRITICAL, "Wrong params for BAM transfer \n");
415 bam_ret = BAM_RESULT_FAILURE;
416 goto bam_add_one_desc_error;
417 }
418
419 /* Check if the FIFO is allocated for the pipe */
420 if (!bam->pipe[pipe_num].initialized)
421 {
422 dprintf(CRITICAL, "Please allocate the FIFO for the BAM pipe %d\n",
423 bam->pipe[pipe_num].pipe_num);
424 bam_ret = BAM_RESULT_FAILURE;
425 goto bam_add_one_desc_error;
426 }
427
428 if ((flags & BAM_DESC_LOCK_FLAG) && (flags & BAM_DESC_UNLOCK_FLAG))
429 {
430 dprintf(CRITICAL, "Can't lock and unlock in the same desc\n");
431 bam_ret = BAM_RESULT_FAILURE;
432 goto bam_add_one_desc_error;
433 }
434
435 /* Setting EOT flag on a CMD desc is not valid */
436 if ((flags & BAM_DESC_EOT_FLAG) && (flags & BAM_DESC_CMD_FLAG))
437 {
438 dprintf(CRITICAL, "EOT flag set on the CMD desc\n");
439 bam_ret = BAM_RESULT_FAILURE;
440 goto bam_add_one_desc_error;
441 }
442
443 /* Check for the length of the desc. */
444 if (len > BAM_MAX_DESC_DATA_LEN)
445 {
446 dprintf(CRITICAL, "len of the desc exceeds max length"
447 " %d > %d\n", len, BAM_MAX_DESC_DATA_LEN);
448 bam_ret = BAM_RESULT_FAILURE;
449 goto bam_add_one_desc_error;
450 }
451
452 desc->flags = flags;
453 desc->addr = (uint32_t)data_ptr;
454 desc->size = (uint16_t)len;
455 desc->reserved = 0;
456
457 /* Update the FIFO to point to the head */
458 bam->pipe[pipe_num].fifo.current = fifo_getnext(&bam->pipe[pipe_num].fifo, desc);
459
460bam_add_one_desc_error:
461 return bam_ret;
462}
463
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700464struct cmd_element* bam_add_cmd_element(struct cmd_element *ptr,
465 uint32_t reg_addr,
466 uint32_t value,
467 enum bam_ce_cmd_t cmd_type)
468{
469 /* Write cmd type.
470 * Also, write the register address.
471 */
Deepa Dinamanie5ccd6c2012-08-16 11:41:06 -0700472 ptr->addr_n_cmd = (reg_addr & ~(0xFF000000)) | (cmd_type << 24);
Deepa Dinamani9d470af2012-06-29 18:27:17 -0700473
474 /* Do not mask any of the addr bits by default */
475 ptr->reg_mask = 0xFFFFFFFF;
476
477 /* Write the value to be written */
478 ptr->reg_data = value;
479
480 /* Return the address to add the next element to */
481 return ptr + 1;
482}