diff options
author | Andy Walls <awalls@radix.net> | 2008-12-14 19:26:25 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:39:09 -0500 |
commit | fd6b9c978dc3447b9b4677d8949ef3ea7f946abc (patch) | |
tree | d51f63f2f2b19b14e12d5e847b0357de39296cb1 /drivers/media/video | |
parent | 50b86bac6ae6dda00faa14f7d73ae2412eacc240 (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/media/video')
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 1 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-firmware.c | 101 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 3 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-scb.c | 1 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx23418.h | 6 |
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 | ||
333 | int cx18_firmware_init(struct cx18 *cx) | 333 | int 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_... */ |