aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2008-12-14 19:26:25 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:39:09 -0500
commitfd6b9c978dc3447b9b4677d8949ef3ea7f946abc (patch)
treed51f63f2f2b19b14e12d5e847b0357de39296cb1 /drivers
parent50b86bac6ae6dda00faa14f7d73ae2412eacc240 (diff)
V4L/DVB (9895): cx18: Refine the firmware load and firmware startup process
Refine the firmware load and firmware startup process. Significant changes are to ensure the SCB and IPC area are correct before starting up the firmware, and letting the CPU firmware start up the APU firmware for us. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/cx18/cx18-driver.c1
-rw-r--r--drivers/media/video/cx18/cx18-firmware.c101
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c3
-rw-r--r--drivers/media/video/cx18/cx18-scb.c1
-rw-r--r--drivers/media/video/cx18/cx23418.h6
5 files changed, 60 insertions, 52 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index d7baf1b97cb8..f50cf2167adc 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -878,6 +878,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
878 goto free_i2c; 878 goto free_i2c;
879 } 879 }
880 cx18_init_memory(cx); 880 cx18_init_memory(cx);
881 cx18_init_scb(cx);
881 882
882 /* Register IRQ */ 883 /* Register IRQ */
883 retval = request_irq(cx->dev->irq, cx18_irq_handler, 884 retval = request_irq(cx->dev->irq, cx18_irq_handler,
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
index 8eac84314d40..e74f76d47df5 100644
--- a/drivers/media/video/cx18/cx18-firmware.c
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -332,6 +332,10 @@ void cx18_init_memory(struct cx18 *cx)
332 332
333int cx18_firmware_init(struct cx18 *cx) 333int cx18_firmware_init(struct cx18 *cx)
334{ 334{
335 u32 fw_entry_addr;
336 int sz, retries;
337 u32 api_args[MAX_MB_ARGUMENTS];
338
335 /* Allow chip to control CLKRUN */ 339 /* Allow chip to control CLKRUN */
336 cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK); 340 cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
337 341
@@ -341,65 +345,62 @@ int cx18_firmware_init(struct cx18 *cx)
341 345
342 cx18_msleep_timeout(1, 0); 346 cx18_msleep_timeout(1, 0);
343 347
348 /* If the CPU is still running */
349 if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) {
350 CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__);
351 return -EIO;
352 }
353
344 cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); 354 cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
345 cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); 355 cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
346 356
347 /* Only if the processor is not running */ 357 sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx);
348 if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) { 358 if (sz <= 0)
349 u32 fw_entry_addr = 0; 359 return sz;
350 int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", 360
351 cx->enc_mem, cx, &fw_entry_addr); 361 /* The SCB & IPC area *must* be correct before starting the firmwares */
352 362 cx18_init_scb(cx);
353 if (sz <= 0) 363
354 return sz; 364 fw_entry_addr = 0;
355 365 sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx,
356 /* Clear bit0 for APU to start from 0 */ 366 &fw_entry_addr);
357 cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030); 367 if (sz <= 0)
358 368 return sz;
359 cx18_write_enc(cx, 0xE51FF004, 0); /* ldr pc, [pc, #-4] */ 369
360 cx18_write_enc(cx, fw_entry_addr, 4); 370 /* Start the CPU. The CPU will take care of the APU for us. */
361 371 cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET,
362 /* Start APU */ 372 0x00000000, 0x00080008);
363 cx18_write_reg_expect(cx, 0x00010000, CX18_PROC_SOFT_RESET, 373
364 0x00000000, 0x00010001); 374 /* Wait up to 500 ms for the APU to come out of reset */
365 cx18_msleep_timeout(500, 0); 375 for (retries = 0;
366 376 retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1;
367 sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", 377 retries++)
368 cx->enc_mem, cx); 378 cx18_msleep_timeout(10, 0);
369 379
370 if (sz > 0) { 380 cx18_msleep_timeout(200, 0);
371 int retries = 0; 381
372 382 if (retries == 50 &&
373 /* start the CPU */ 383 (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) {
374 cx18_write_reg_expect(cx, 384 CX18_ERR("Could not start the CPU\n");
375 0x00080000, CX18_PROC_SOFT_RESET, 385 return -EIO;
376 0x00000000, 0x00080008);
377 while (retries++ < 50) { /* Loop for max 500mS */
378 if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET)
379 & 1) == 0)
380 break;
381 cx18_msleep_timeout(10, 0);
382 }
383 cx18_msleep_timeout(200, 0);
384 if (retries == 51) {
385 CX18_ERR("Could not start the CPU\n");
386 return -EIO;
387 }
388 }
389 if (sz <= 0)
390 return -EIO;
391 } 386 }
392 387
393 /* 388 /*
394 * The CPU firmware apparently sets up to receive an interrupt for it's 389 * The CPU had once before set up to receive an interrupt for it's
395 * outgoing IRQ_CPU_TO_EPU_ACK to us (*boggle*). We get an interrupt 390 * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an
396 * when it sends us an ack, but by the time we process it, that flag in 391 * interrupt when it sends us an ack, but by the time we process it,
397 * the SW2 status register has been cleared by the CPU firmware. 392 * that flag in the SW2 status register has been cleared by the CPU
398 * We'll prevent that not so useful behavior by clearing the CPU's 393 * firmware. We'll prevent that not so useful condition from happening
399 * interrupt enables for Ack IRQ's we want to process. 394 * by clearing the CPU's interrupt enables for Ack IRQ's we want to
395 * process.
400 */ 396 */
401 cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); 397 cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
402 398
399 /* Try a benign command to see if the CPU is alive and well */
400 sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0);
401 if (sz < 0)
402 return sz;
403
403 /* initialize GPIO */ 404 /* initialize GPIO */
404 cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); 405 cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
405 return 0; 406 return 0;
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index d62351466e26..de5e723fdf44 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -82,8 +82,9 @@ static const struct cx18_api_info api_info[] = {
82 API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), 82 API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
83 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), 83 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
84 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), 84 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
85 API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST),
86 API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), 85 API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW),
86 API_ENTRY(APU, CX18_APU_RESETAI, 0),
87 API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0),
87 API_ENTRY(0, 0, 0), 88 API_ENTRY(0, 0, 0),
88}; 89};
89 90
diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c
index ac18bd9326d5..34b4d03c55cd 100644
--- a/drivers/media/video/cx18/cx18-scb.c
+++ b/drivers/media/video/cx18/cx18-scb.c
@@ -118,6 +118,5 @@ void cx18_init_scb(struct cx18 *cx)
118 cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state), 118 cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
119 &cx->scb->ipc_offset); 119 &cx->scb->ipc_offset);
120 120
121 cx18_writel(cx, 1, &cx->scb->hpu_state);
122 cx18_writel(cx, 1, &cx->scb->epu_state); 121 cx18_writel(cx, 1, &cx->scb->epu_state);
123} 122}
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 668f968d7761..601f3a2ab742 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -44,6 +44,7 @@
44 44
45/* All commands for CPU have the following mask set */ 45/* All commands for CPU have the following mask set */
46#define CPU_CMD_MASK 0x20000000 46#define CPU_CMD_MASK 0x20000000
47#define CPU_CMD_MASK_DEBUG (CPU_CMD_MASK | 0x00000000)
47#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000) 48#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000)
48#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000) 49#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000)
49#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000) 50#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000)
@@ -71,6 +72,11 @@
71 0/zero/NULL means "I have nothing to say" */ 72 0/zero/NULL means "I have nothing to say" */
72#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003) 73#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003)
73 74
75/* Reads memory/registers (32-bit)
76 IN[0] - Address
77 OUT[1] - Value */
78#define CX18_CPU_DEBUG_PEEK32 (CPU_CMD_MASK_DEBUG | 0x0003)
79
74/* Description: This command starts streaming with the set channel type 80/* Description: This command starts streaming with the set channel type
75 IN[0] - Task handle. Handle of the task to start 81 IN[0] - Task handle. Handle of the task to start
76 ReturnCode - One of the ERR_CAPTURE_... */ 82 ReturnCode - One of the ERR_CAPTURE_... */