The patch number 9896 was added via Mauro Carvalho Chehab <mche...@redhat.com> to http://linuxtv.org/hg/v4l-dvb master development tree.
Kernel patches in this development tree may be modified to be backward compatible with older kernels. Compatibility modifications will be removed before inclusion into the mainstream Kernel If anyone has any objections, please let us know by sending a message to: v4l-dvb-maintai...@linuxtv.org ------ From: Mauro Carvalho Chehab <mche...@redhat.com> merge: http://linuxtv.org/hg/~awalls/v4l-dvb Priority: normal Signed-off-by: Mauro Carvalho Chehab <mche...@redhat.com> --- linux/drivers/media/video/cx18/cx18-controls.c | 5 linux/drivers/media/video/cx18/cx18-driver.c | 17 ++ linux/drivers/media/video/cx18/cx18-driver.h | 5 linux/drivers/media/video/cx18/cx18-firmware.c | 101 ++++++++--------- linux/drivers/media/video/cx18/cx18-mailbox.c | 8 - linux/drivers/media/video/cx18/cx18-mailbox.h | 7 + linux/drivers/media/video/cx18/cx18-queue.c | 23 +-- linux/drivers/media/video/cx18/cx18-scb.c | 1 linux/drivers/media/video/cx18/cx18-streams.c | 15 +- linux/drivers/media/video/cx18/cx23418.h | 6 + 10 files changed, 109 insertions(+), 79 deletions(-) diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx18-controls.c --- a/linux/drivers/media/video/cx18/cx18-controls.c Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx18-controls.c Mon Dec 15 01:28:43 2008 -0200 @@ -259,6 +259,7 @@ int cx18_s_ext_ctrls(struct file *file, return err; } if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + struct cx18_api_func_private priv; struct cx2341x_mpeg_params p = cx->params; int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), c, VIDIOC_S_EXT_CTRLS); @@ -278,7 +279,9 @@ int cx18_s_ext_ctrls(struct file *file, fmt.fmt.pix.height = cx->params.height; cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt); } - err = cx2341x_update(cx, cx18_api_func, &cx->params, &p); + priv.cx = cx; + priv.s = &cx->streams[id->type]; + err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p); if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt) err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); cx->params = p; diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx18-driver.c --- a/linux/drivers/media/video/cx18/cx18-driver.c Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx18-driver.c Mon Dec 15 01:28:43 2008 -0200 @@ -614,18 +614,21 @@ static int __devinit cx18_init_struct1(s * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line * length of 720 pixels @ 4:2:2 sampling. Thus... * - * For NTSC: + * For systems that use a 15.734 kHz horizontal rate, such as + * NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have: * - * (1/15,734 kHz) * 2 * 13.5 MHz = 1716 samples/line = + * (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line = * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples * - * For PAL: + * For systems that use a 15.625 kHz horizontal rate, such as + * PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have: * - * (1/15,625 kHz) * 2 * 13.5 MHz = 1728 samples/line = + * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line = * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples * */ + /* FIXME: init these based on tuner std & modify when std changes */ /* CX18-AV-Core number of VBI samples output per horizontal line */ cx->vbi.raw_decoder_line_size = 1444; /* 4 byte SAV + 2 * 720 */ cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */ @@ -880,6 +883,7 @@ static int __devinit cx18_probe(struct p goto free_i2c; } cx18_init_memory(cx); + cx18_init_scb(cx); /* Register IRQ */ retval = request_irq(cx->dev->irq, cx18_irq_handler, @@ -929,6 +933,11 @@ static int __devinit cx18_probe(struct p } cx->params.video_gop_size = cx->is_60hz ? 15 : 12; + /* + * FIXME: setting the buffer size based on the tuner standard is + * suboptimal, as the CVBS and SVideo inputs could use a different std + * and the buffer could end up being too small in that case. + */ vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size; diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx18-driver.h --- a/linux/drivers/media/video/cx18/cx18-driver.h Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx18-driver.h Mon Dec 15 01:28:43 2008 -0200 @@ -116,7 +116,7 @@ #define CX18_DEFAULT_ENC_PCM_BUFFERS 1 /* Maximum firmware DMA buffers per stream */ -#define CX18_MAX_MDLS_PER_STREAM 63 +#define CX18_MAX_FW_MDLS_PER_STREAM 63 /* DMA buffer, default size in kB allocated */ #define CX18_DEFAULT_ENC_TS_BUFSIZE 32 @@ -255,7 +255,8 @@ struct cx18_scb; /* forward reference */ #define CX18_MAX_MDL_ACKS 2 -#define CX18_MAX_EPU_WORK_ORDERS 70 /* CPU_DE_RELEASE_MDL bursts 63 commands */ +#define CX18_MAX_EPU_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7) +/* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */ #define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1 #define CX18_F_EWO_MB_STALE_WHILE_PROC 0x2 diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx18-firmware.c --- a/linux/drivers/media/video/cx18/cx18-firmware.c Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx18-firmware.c Mon Dec 15 01:28:43 2008 -0200 @@ -332,6 +332,10 @@ void cx18_init_memory(struct cx18 *cx) int cx18_firmware_init(struct cx18 *cx) { + u32 fw_entry_addr; + int sz, retries; + u32 api_args[MAX_MB_ARGUMENTS]; + /* Allow chip to control CLKRUN */ cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK); @@ -341,64 +345,61 @@ int cx18_firmware_init(struct cx18 *cx) cx18_msleep_timeout(1, 0); + /* If the CPU is still running */ + if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) { + CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__); + return -EIO; + } + cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); - /* Only if the processor is not running */ - if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) { - u32 fw_entry_addr = 0; - int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", - cx->enc_mem, cx, &fw_entry_addr); - - if (sz <= 0) - return sz; - - /* Clear bit0 for APU to start from 0 */ - cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030); - - cx18_write_enc(cx, 0xE51FF004, 0); /* ldr pc, [pc, #-4] */ - cx18_write_enc(cx, fw_entry_addr, 4); - - /* Start APU */ - cx18_write_reg_expect(cx, 0x00010000, CX18_PROC_SOFT_RESET, - 0x00000000, 0x00010001); - cx18_msleep_timeout(500, 0); - - sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", - cx->enc_mem, cx); - - if (sz > 0) { - int retries = 0; - - /* start the CPU */ - cx18_write_reg_expect(cx, - 0x00080000, CX18_PROC_SOFT_RESET, - 0x00000000, 0x00080008); - while (retries++ < 50) { /* Loop for max 500mS */ - if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) - & 1) == 0) - break; - cx18_msleep_timeout(10, 0); - } - cx18_msleep_timeout(200, 0); - if (retries == 51) { - CX18_ERR("Could not start the CPU\n"); - return -EIO; - } - } - if (sz <= 0) - return -EIO; + sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx); + if (sz <= 0) + return sz; + + /* The SCB & IPC area *must* be correct before starting the firmwares */ + cx18_init_scb(cx); + + fw_entry_addr = 0; + sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx, + &fw_entry_addr); + if (sz <= 0) + return sz; + + /* Start the CPU. The CPU will take care of the APU for us. */ + cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET, + 0x00000000, 0x00080008); + + /* Wait up to 500 ms for the APU to come out of reset */ + for (retries = 0; + retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1; + retries++) + cx18_msleep_timeout(10, 0); + + cx18_msleep_timeout(200, 0); + + if (retries == 50 && + (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) { + CX18_ERR("Could not start the CPU\n"); + return -EIO; } /* - * The CPU firmware apparently sets up to receive an interrupt for it's - * outgoing IRQ_CPU_TO_EPU_ACK to us (*boggle*). We get an interrupt - * when it sends us an ack, but by the time we process it, that flag in - * the SW2 status register has been cleared by the CPU firmware. - * We'll prevent that not so useful behavior by clearing the CPU's - * interrupt enables for Ack IRQ's we want to process. + * The CPU had once before set up to receive an interrupt for it's + * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an + * interrupt when it sends us an ack, but by the time we process it, + * that flag in the SW2 status register has been cleared by the CPU + * firmware. We'll prevent that not so useful condition from happening + * by clearing the CPU's interrupt enables for Ack IRQ's we want to + * process. */ cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + /* Try a benign command to see if the CPU is alive and well */ + sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0); + if (sz < 0) + return sz; /* initialize GPIO */ cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx18-mailbox.c --- a/linux/drivers/media/video/cx18/cx18-mailbox.c Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c Mon Dec 15 01:28:43 2008 -0200 @@ -82,8 +82,9 @@ static const struct cx18_api_info api_in API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), - API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST), API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), + API_ENTRY(APU, CX18_APU_RESETAI, 0), + API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0), API_ENTRY(0, 0, 0), }; @@ -612,8 +613,9 @@ int cx18_api_func(void *priv, u32 cmd, i int cx18_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { - struct cx18 *cx = priv; - struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; + struct cx18_api_func_private *api_priv = priv; + struct cx18 *cx = api_priv->cx; + struct cx18_stream *s = api_priv->s; switch (cmd) { case CX2341X_ENC_SET_OUTPUT_PORT: diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx18-mailbox.h --- a/linux/drivers/media/video/cx18/cx18-mailbox.h Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx18-mailbox.h Mon Dec 15 01:28:43 2008 -0200 @@ -79,6 +79,13 @@ struct cx18_mailbox { u32 error; }; +struct cx18_stream; + +struct cx18_api_func_private { + struct cx18 *cx; + struct cx18_stream *s; +}; + int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, int args, ...); diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx18-queue.c --- a/linux/drivers/media/video/cx18/cx18-queue.c Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx18-queue.c Mon Dec 15 01:28:43 2008 -0200 @@ -55,8 +55,9 @@ struct cx18_queue *_cx18_enqueue(struct mutex_lock(&s->qlock); - /* q_busy is restricted to 63 buffers to stay within firmware limits */ - if (q == &s->q_busy && atomic_read(&q->buffers) >= 63) + /* q_busy is restricted to a max buffer count imposed by firmware */ + if (q == &s->q_busy && + atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM) q = &s->q_free; if (to_front) @@ -76,8 +77,8 @@ struct cx18_buffer *cx18_dequeue(struct mutex_lock(&s->qlock); if (!list_empty(&q->list)) { - buf = list_entry(q->list.next, struct cx18_buffer, list); - list_del_init(q->list.next); + buf = list_first_entry(&q->list, struct cx18_buffer, list); + list_del_init(&buf->list); q->bytesused -= buf->bytesused - buf->readpos; buf->skipped = 0; atomic_dec(&q->buffers); @@ -91,13 +92,11 @@ struct cx18_buffer *cx18_queue_get_buf(s { struct cx18 *cx = s->cx; struct cx18_buffer *buf; + struct cx18_buffer *tmp; struct cx18_buffer *ret = NULL; - struct list_head *p, *t; - - mutex_lock(&s->qlock); - list_for_each_safe(p, t, &s->q_busy.list) { - buf = list_entry(p, struct cx18_buffer, list); - + + mutex_lock(&s->qlock); + list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) { if (buf->id != id) { buf->skipped++; if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) { @@ -151,8 +150,8 @@ static void cx18_queue_flush(struct cx18 mutex_lock(&s->qlock); while (!list_empty(&q->list)) { - buf = list_entry(q->list.next, struct cx18_buffer, list); - list_move_tail(q->list.next, &s->q_free.list); + buf = list_first_entry(&q->list, struct cx18_buffer, list); + list_move_tail(&buf->list, &s->q_free.list); buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0; atomic_inc(&s->q_free.buffers); } diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx18-scb.c --- a/linux/drivers/media/video/cx18/cx18-scb.c Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx18-scb.c Mon Dec 15 01:28:43 2008 -0200 @@ -118,6 +118,5 @@ void cx18_init_scb(struct cx18 *cx) cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state), &cx->scb->ipc_offset); - cx18_writel(cx, 1, &cx->scb->hpu_state); cx18_writel(cx, 1, &cx->scb->epu_state); } diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx18-streams.c --- a/linux/drivers/media/video/cx18/cx18-streams.c Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx18-streams.c Mon Dec 15 01:28:43 2008 -0200 @@ -425,7 +425,7 @@ void cx18_stream_load_fw_queue(struct cx struct cx18_buffer *buf; if (atomic_read(&s->q_free.buffers) == 0 || - atomic_read(&s->q_busy.buffers) >= 63) + atomic_read(&s->q_busy.buffers) >= CX18_MAX_FW_MDLS_PER_STREAM) return; /* Move from q_free to q_busy notifying the firmware, until the limit */ @@ -434,14 +434,14 @@ void cx18_stream_load_fw_queue(struct cx if (buf == NULL) break; q = cx18_stream_put_buf_fw(s, buf); - } while (atomic_read(&s->q_busy.buffers) < 63 && q == &s->q_busy); + } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM + && q == &s->q_busy); } int cx18_start_v4l2_encode_stream(struct cx18_stream *s) { u32 data[MAX_MB_ARGUMENTS]; struct cx18 *cx = s->cx; - struct list_head *p; struct cx18_buffer *buf; int ts = 0; int captype = 0; @@ -494,6 +494,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); if (atomic_read(&cx->ana_capturing) == 0 && !ts) { + struct cx18_api_func_private priv; + /* Stuff from Windows, we don't know what it is */ cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); @@ -513,7 +515,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0); /* Setup API for Stream */ - cx2341x_update(cx, cx18_api_func, NULL, &cx->params); + priv.cx = cx; + priv.s = s; + cx2341x_update(&priv, cx18_api_func, NULL, &cx->params); } if (atomic_read(&cx->tot_capturing) == 0) { @@ -528,8 +532,7 @@ int cx18_start_v4l2_encode_stream(struct /* Init all the cpu_mdls for this stream */ cx18_flush_queues(s); mutex_lock(&s->qlock); - list_for_each(p, &s->q_free.list) { - buf = list_entry(p, struct cx18_buffer, list); + list_for_each_entry(buf, &s->q_free.list, list) { cx18_writel(cx, buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr); cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); diff -r 2c4c547cb482 -r 3f096d061620 linux/drivers/media/video/cx18/cx23418.h --- a/linux/drivers/media/video/cx18/cx23418.h Sun Dec 14 21:53:32 2008 -0200 +++ b/linux/drivers/media/video/cx18/cx23418.h Mon Dec 15 01:28:43 2008 -0200 @@ -44,6 +44,7 @@ /* All commands for CPU have the following mask set */ #define CPU_CMD_MASK 0x20000000 +#define CPU_CMD_MASK_DEBUG (CPU_CMD_MASK | 0x00000000) #define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000) #define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000) #define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000) @@ -70,6 +71,11 @@ IN[1] - An offset of a string in the MiniMe memory; 0/zero/NULL means "I have nothing to say" */ #define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003) + +/* Reads memory/registers (32-bit) + IN[0] - Address + OUT[1] - Value */ +#define CX18_CPU_DEBUG_PEEK32 (CPU_CMD_MASK_DEBUG | 0x0003) /* Description: This command starts streaming with the set channel type IN[0] - Task handle. Handle of the task to start --- Patch is available at: http://linuxtv.org/hg/v4l-dvb/rev/3f096d06162089462e2c943e881b3e4478888dea _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits