diff options
Diffstat (limited to 'drivers')
-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_... */ |