int cx18_start_v4l2_encode_stream(struct cx18_stream *s) { u32 data[MAX_MB_ARGUMENTS]; struct cx18 *cx = s->cx; int captype = 0; struct cx18_stream *s_idx; if (!cx18_stream_enabled(s)) return -EINVAL; CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { case CX18_ENC_STREAM_TYPE_MPG: captype = CAPTURE_CHANNEL_TYPE_MPEG; cx->mpg_data_received = cx->vbi_data_inserted = 0; cx->dualwatch_jiffies = jiffies; cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); cx->search_pack_header = 0; break; case CX18_ENC_STREAM_TYPE_IDX: captype = CAPTURE_CHANNEL_TYPE_INDEX; break; case CX18_ENC_STREAM_TYPE_TS: captype = CAPTURE_CHANNEL_TYPE_TS; break; case CX18_ENC_STREAM_TYPE_YUV: captype = CAPTURE_CHANNEL_TYPE_YUV; break; case CX18_ENC_STREAM_TYPE_PCM: captype = CAPTURE_CHANNEL_TYPE_PCM; break; case CX18_ENC_STREAM_TYPE_VBI: #ifdef CX18_ENCODER_PARSES_SLICED captype = cx18_raw_vbi(cx) ? CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; #else captype = CAPTURE_CHANNEL_TYPE_VBI; #endif cx->vbi.frame = 0; cx->vbi.inserted_frame = 0; memset(cx->vbi.sliced_mpeg_size, 0, sizeof(cx->vbi.sliced_mpeg_size)); break; default: return -EINVAL; } clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); s->handle = data[0]; cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); if (captype != CAPTURE_CHANNEL_TYPE_TS) { 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); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); if (atomic_read(&cx->ana_capturing) == 0) cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12); cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, s->handle, 312, 313); if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) cx18_vbi_setup(s); s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2, s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); cx->cxhdl.priv = s; cx2341x_handler_setup(&cx->cxhdl); if (!cx->cxhdl.video_mute && test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); if (captype == CAPTURE_CHANNEL_TYPE_YUV) { if (s->pixelformat == V4L2_PIX_FMT_UYVY) cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, s->handle, 1); else cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, s->handle, 0); } } if (atomic_read(&cx->tot_capturing) == 0) { cx2341x_handler_set_busy(&cx->cxhdl, 1); clear_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); } cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); cx18_stream_configure_mdls(s); _cx18_stream_load_fw_queue(s); if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { CX18_DEBUG_WARN("Error starting capture!\n"); set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); else cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); clear_bit(CX18_F_S_STREAMING, &s->s_flags); cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) == 0) { set_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); } return -EINVAL; } if (captype != CAPTURE_CHANNEL_TYPE_TS) atomic_inc(&cx->ana_capturing); atomic_inc(&cx->tot_capturing); return 0; }
int cx18_start_v4l2_encode_stream(struct cx18_stream *s) { u32 data[MAX_MB_ARGUMENTS]; struct cx18 *cx = s->cx; int captype = 0; struct cx18_stream *s_idx; if (!cx18_stream_enabled(s)) return -EINVAL; CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { case CX18_ENC_STREAM_TYPE_MPG: captype = CAPTURE_CHANNEL_TYPE_MPEG; cx->mpg_data_received = cx->vbi_data_inserted = 0; cx->dualwatch_jiffies = jiffies; cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); cx->search_pack_header = 0; break; case CX18_ENC_STREAM_TYPE_IDX: captype = CAPTURE_CHANNEL_TYPE_INDEX; break; case CX18_ENC_STREAM_TYPE_TS: captype = CAPTURE_CHANNEL_TYPE_TS; break; case CX18_ENC_STREAM_TYPE_YUV: captype = CAPTURE_CHANNEL_TYPE_YUV; break; case CX18_ENC_STREAM_TYPE_PCM: captype = CAPTURE_CHANNEL_TYPE_PCM; break; case CX18_ENC_STREAM_TYPE_VBI: #ifdef CX18_ENCODER_PARSES_SLICED captype = cx18_raw_vbi(cx) ? CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; #else /* * Currently we set things up so that Sliced VBI from the * digitizer is handled as Raw VBI by the encoder */ captype = CAPTURE_CHANNEL_TYPE_VBI; #endif cx->vbi.frame = 0; cx->vbi.inserted_frame = 0; memset(cx->vbi.sliced_mpeg_size, 0, sizeof(cx->vbi.sliced_mpeg_size)); break; default: return -EINVAL; } /* Clear Streamoff flags in case left from last capture */ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); s->handle = data[0]; cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); /* * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and * set up all the parameters, as it is not obvious which parameters the * firmware shares across capture channel types and which it does not. * * Some of the cx18_vapi() calls below apply to only certain capture * channel types. We're hoping there's no harm in calling most of them * anyway, as long as the values are all consistent. Setting some * shared parameters will have no effect once an analog capture channel * has started streaming. */ if (captype != CAPTURE_CHANNEL_TYPE_TS) { 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); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); /* * Audio related reset according to * Documentation/video4linux/cx2341x/fw-encoder-api.txt */ if (atomic_read(&cx->ana_capturing) == 0) cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12); /* * Number of lines for Field 1 & Field 2 according to * Documentation/video4linux/cx2341x/fw-encoder-api.txt * Field 1 is 312 for 625 line systems in BT.656 * Field 2 is 313 for 625 line systems in BT.656 */ cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, s->handle, 312, 313); if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) cx18_vbi_setup(s); /* * Select to receive I, P, and B frame index entries, if the * index stream is enabled. Otherwise disable index entry * generation. */ s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2, s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); /* Call out to the common CX2341x API setup for user controls */ cx->cxhdl.priv = s; cx2341x_handler_setup(&cx->cxhdl); /* * When starting a capture and we're set for radio, * ensure the video is muted, despite the user control. */ if (!cx->cxhdl.video_mute && test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); /* Enable the Video Format Converter for UYVY 4:2:2 support, * rather than the default HM12 Macroblovk 4:2:0 support. */ if (captype == CAPTURE_CHANNEL_TYPE_YUV) { if (s->pixelformat == V4L2_PIX_FMT_UYVY) cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, s->handle, 1); else /* If in doubt, default to HM12 */ cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, s->handle, 0); } } if (atomic_read(&cx->tot_capturing) == 0) { cx2341x_handler_set_busy(&cx->cxhdl, 1); clear_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); } cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); /* Init all the cpu_mdls for this stream */ cx18_stream_configure_mdls(s); _cx18_stream_load_fw_queue(s); /* begin_capture */ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { CX18_DEBUG_WARN("Error starting capture!\n"); /* Ensure we're really not capturing before releasing MDLs */ set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); else cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); clear_bit(CX18_F_S_STREAMING, &s->s_flags); /* FIXME - CX18_F_S_STREAMOFF as well? */ cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) == 0) { set_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); } return -EINVAL; } /* you're live! sit back and await interrupts :) */ if (captype != CAPTURE_CHANNEL_TYPE_TS) atomic_inc(&cx->ana_capturing); atomic_inc(&cx->tot_capturing); return 0; }
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); /* Stop the firmware */ cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, 0x0000000F, 0x000F000F); 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); 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 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); return 0; }