static void cx18_setscl(void *data, int state)
{
	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
	u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
	u32 r = cx18_read_reg(cx, addr);

	if (state)
		cx18_write_reg(cx, r | SETSCL_BIT, addr);
	else
		cx18_write_reg(cx, r & ~SETSCL_BIT, addr);
}
void exit_cx18_i2c(struct cx18 *cx)
{
	int i;
	CX18_DEBUG_I2C("i2c exit\n");
	cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4,
							CX18_REG_I2C_1_WR);
	cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4,
							CX18_REG_I2C_2_WR);

	for (i = 0; i < 2; i++) {
		i2c_del_adapter(&cx->i2c_adap[i]);
	}
}
Example #3
0
/* Kernel DVB framework calls this when the feed needs to start.
 * The CX18 framework should enable the transport DMA handling
 * and queue processing.
 */
static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
{
	struct dvb_demux *demux = feed->demux;
	struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
	struct cx18 *cx = stream->cx;
	int ret;
	u32 v;

	CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
			feed->pid, feed->index);

	mutex_lock(&cx->serialize_lock);
	ret = cx18_init_on_first_open(cx);
	mutex_unlock(&cx->serialize_lock);
	if (ret) {
		CX18_ERR("Failed to initialize firmware starting DVB feed\n");
		return ret;
	}
	ret = -EINVAL;

	switch (cx->card->type) {
	case CX18_CARD_HVR_1600_ESMT:
	case CX18_CARD_HVR_1600_SAMSUNG:
		v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
		v |= 0x00400000; /* Serial Mode */
		v |= 0x00002000; /* Data Length - Byte */
		v |= 0x00010000; /* Error - Polarity */
		v |= 0x00020000; /* Error - Passthru */
		v |= 0x000c0000; /* Error - Ignore */
		cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
		break;

	default:
		/* Assumption - Parallel transport - Signalling
		 * undefined or default.
		 */
		break;
	}

	if (!demux->dmx.frontend)
		return -EINVAL;

	if (stream) {
		mutex_lock(&stream->dvb.feedlock);
		if (stream->dvb.feeding++ == 0) {
			CX18_DEBUG_INFO("Starting Transport DMA\n");
			ret = cx18_start_v4l2_encode_stream(stream);
			if (ret < 0) {
				CX18_DEBUG_INFO(
					"Failed to start Transport DMA\n");
				stream->dvb.feeding--;
			}
		} else
			ret = 0;
		mutex_unlock(&stream->dvb.feedlock);
	}

	return ret;
}
Example #4
0
int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
{
	struct cx18 *cx = s->cx;
	unsigned long then;

	if (!cx18_stream_enabled(s))
		return -EINVAL;

	/* This function assumes that you are allowed to stop the capture
	   and that we are actually capturing */

	CX18_DEBUG_INFO("Stop Capture\n");

	if (atomic_read(&cx->tot_capturing) == 0)
		return 0;

	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, !gop_end);
	else
		cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);

	then = jiffies;

	if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
		CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
	}

	if (s->type != CX18_ENC_STREAM_TYPE_TS)
		atomic_dec(&cx->ana_capturing);
	atomic_dec(&cx->tot_capturing);

	/* Clear capture and no-read bits */
	clear_bit(CX18_F_S_STREAMING, &s->s_flags);

	/* Tell the CX23418 it can't use our buffers anymore */
	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)
		return 0;

	cx2341x_handler_set_busy(&cx->cxhdl, 0);
	cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
	wake_up(&s->waitq);

	return 0;
}
Example #5
0
long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
{
	const struct cx18_api_info *info = find_api_info(mb->cmd);
	struct cx18_mailbox __iomem *ack_mb;
	u32 ack_irq;
	u8 rpu = CPU;

	if (info == NULL && mb->cmd) {
		CX18_WARN("Cannot ack unknown command %x\n", mb->cmd);
		return -EINVAL;
	}
	if (info)
		rpu = info->rpu;

	switch (rpu) {
	case HPU:
		ack_irq = IRQ_EPU_TO_HPU_ACK;
		ack_mb = &cx->scb->hpu2epu_mb;
		break;
	case APU:
		ack_irq = IRQ_EPU_TO_APU_ACK;
		ack_mb = &cx->scb->apu2epu_mb;
		break;
	case CPU:
		ack_irq = IRQ_EPU_TO_CPU_ACK;
		ack_mb = &cx->scb->cpu2epu_mb;
		break;
	default:
		CX18_WARN("Unknown RPU for command %x\n", mb->cmd);
		return -EINVAL;
	}

	cx18_setup_page(cx, SCB_OFFSET);
	cx18_write_sync(cx, mb->request, &ack_mb->ack);
	cx18_write_reg(cx, ack_irq, SW2_INT_SET);
	return 0;
}
Example #6
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;
}
Example #7
0
static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
{
	const struct cx18_api_info *info = find_api_info(cmd);
	u32 state = 0, irq = 0, req, oldreq, err;
	struct cx18_mailbox __iomem *mb;
	wait_queue_head_t *waitq;
	int timeout = 100;
	int cnt = 0;
	int sig = 0;
	int i;

	if (info == NULL) {
		CX18_WARN("unknown cmd %x\n", cmd);
		return -EINVAL;
	}

	if (cmd == CX18_CPU_DE_SET_MDL)
		CX18_DEBUG_HI_API("%s\n", info->name);
	else
		CX18_DEBUG_API("%s\n", info->name);
	cx18_setup_page(cx, SCB_OFFSET);
	mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);

	if (mb == NULL) {
		CX18_ERR("mb %s busy\n", info->name);
		return -EBUSY;
	}

	oldreq = req - 1;
	cx18_writel(cx, cmd, &mb->cmd);
	for (i = 0; i < args; i++)
		cx18_writel(cx, data[i], &mb->args[i]);
	cx18_writel(cx, 0, &mb->error);
	cx18_writel(cx, req, &mb->request);

	switch (info->rpu) {
	case APU: waitq = &cx->mb_apu_waitq; break;
	case CPU: waitq = &cx->mb_cpu_waitq; break;
	case EPU: waitq = &cx->mb_epu_waitq; break;
	case HPU: waitq = &cx->mb_hpu_waitq; break;
	default: return -EINVAL;
	}
	if (info->flags & API_FAST)
		timeout /= 2;
	cx18_write_reg(cx, irq, SW1_INT_SET);

	while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request)
	       && cnt < 660) {
		if (cnt > 200 && !in_atomic())
			sig = cx18_msleep_timeout(10, 1);
		cnt++;
	}
	if (sig)
		return -EINTR;
	if (cnt == 660) {
		cx18_writel(cx, oldreq, &mb->request);
		CX18_ERR("mb %s failed\n", info->name);
		return -EINVAL;
	}
	for (i = 0; i < MAX_MB_ARGUMENTS; i++)
		data[i] = cx18_readl(cx, &mb->args[i]);
	err = cx18_readl(cx, &mb->error);
	if (!in_atomic() && (info->flags & API_SLOW))
		cx18_msleep_timeout(300, 0);
	if (err)
		CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
				info->name);
	return err ? -EIO : 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
		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_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;
}
void cx18_init_memory(struct cx18 *cx)
{
	cx18_msleep_timeout(10, 0);
	cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET,
				  0x00000000, 0x00010001);
	cx18_msleep_timeout(10, 0);

	cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);

	cx18_msleep_timeout(10, 0);

	cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH);
	cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1);
	cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2);

	cx18_msleep_timeout(10, 0);

	/* Initialize DQS pad time */
	cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
	cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);

	cx18_msleep_timeout(10, 0);

	cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET,
				  0x00000000, 0x00020002);
	cx18_msleep_timeout(10, 0);

	/* use power-down mode when idle */
	cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG);

	cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN,
				  0x00000001, 0x00010001);

	cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7);
	cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR);

	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02);  /* AO */
	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09);  /* AI2 */
	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05);  /* VIM1 */
	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06);  /* AI1 */
	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07);  /* 3D comb */
	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10);  /* ME */
	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12);  /* ENC */
	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13);  /* PK */
	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11);  /* RC */
	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14);  /* AVO */
}
void cx18_init_power(struct cx18 *cx, int lowpwr)
{
	/* power-down Spare and AOM PLLs */
	/* power-up fast, slow and mpeg PLLs */
	cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN);

	/* ADEC out of sleep */
	cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
				  0x00000000, 0x00020002);

	/*
	 * The PLL parameters are based on the external crystal frequency that
	 * would ideally be:
	 *
	 * NTSC Color subcarrier freq * 8 =
	 * 	4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
	 *
	 * The accidents of history and rationale that explain from where this
	 * combination of magic numbers originate can be found in:
	 *
	 * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
	 * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
	 *
	 * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
	 * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
	 *
	 * As Mike Bradley has rightly pointed out, it's not the exact crystal
	 * frequency that matters, only that all parts of the driver and
	 * firmware are using the same value (close to the ideal value).
	 *
	 * Since I have a strong suspicion that, if the firmware ever assumes a
	 * crystal value at all, it will assume 28.636360 MHz, the crystal
	 * freq used in calculations in this driver will be:
	 *
	 *	xtal_freq = 28.636360 MHz
	 *
	 * an error of less than 0.13 ppm which is way, way better than any off
	 * the shelf crystal will have for accuracy anyway.
	 *
	 * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors.
	 *
	 * Many thanks to Jeff Campbell and Mike Bradley for their extensive
	 * investigation, experimentation, testing, and suggested solutions of
	 * of audio/video sync problems with SVideo and CVBS captures.
	 */

	/* the fast clock is at 200/245 MHz */
	/* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/
	/* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/
	cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
	cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
						CX18_FAST_CLOCK_PLL_FRAC);

	cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST);
	cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE);
	cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);

	/* set slow clock to 125/120 MHz */
	/* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
	/* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */
	cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT);
	cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F,
						CX18_SLOW_CLOCK_PLL_FRAC);
	cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);

	/* mpeg clock pll 54MHz */
	/* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */
	cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
	cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
	cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);

	/* Defaults */
	/* APU = SC or SC/2 = 125/62.5 */
	/* EPU = SC = 125 */
	/* DDR = FC = 180 */
	/* ENC = SC = 125 */
	/* AI1 = SC = 125 */
	/* VIM2 = disabled */
	/* PCI = FC/2 = 90 */
	/* AI2 = disabled */
	/* DEMUX = disabled */
	/* AO = SC/2 = 62.5 */
	/* SER = 54MHz */
	/* VFC = disabled */
	/* USB = disabled */

	if (lowpwr) {
		cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1,
					  0x00000020, 0xFFFFFFFF);
		cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2,
					  0x00000004, 0xFFFFFFFF);
	} else {
		/* This doesn't explicitly set every clock select */
		cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1,
					  0x00000004, 0x00060006);
		cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2,
					  0x00000006, 0x00060006);
	}

	cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1,
				  0x00000002, 0xFFFFFFFF);
	cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2,
				  0x00000104, 0xFFFFFFFF);
	cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1,
				  0x00009026, 0xFFFFFFFF);
	cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2,
				  0x00003105, 0xFFFFFFFF);
}
/* init + register i2c algo-bit adapter */
int init_cx18_i2c(struct cx18 *cx)
{
	int i;
	CX18_DEBUG_I2C("i2c init\n");

	/* Sanity checks for the I2C hardware arrays. They must be the
	 * same size and GPIO/CX23418 must be the last entries.
	 */
	if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
	    ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
	    CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) ||
	    CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
	    hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
		CX18_ERR("Mismatched I2C hardware arrays\n");
		return -ENODEV;
	}

	for (i = 0; i < 2; i++) {
		memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
			sizeof(struct i2c_adapter));
		memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template,
			sizeof(struct i2c_algo_bit_data));
		cx->i2c_algo_cb_data[i].cx = cx;
		cx->i2c_algo_cb_data[i].bus_index = i;
		cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
		cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];

		sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
				" #%d-%d", cx->num, i);
		i2c_set_adapdata(&cx->i2c_adap[i], cx);

		memcpy(&cx->i2c_client[i], &cx18_i2c_client_template,
			sizeof(struct i2c_client));
		sprintf(cx->i2c_client[i].name +
				strlen(cx->i2c_client[i].name), "%d", i);
		cx->i2c_client[i].adapter = &cx->i2c_adap[i];
		cx->i2c_adap[i].dev.parent = &cx->dev->dev;
	}

	if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
		/* Reset/Unreset I2C hardware block */
		/* Clock select 220MHz */
		cx18_write_reg_expect(cx, 0x10000000, 0xc71004,
					  0x00000000, 0x10001000);
		/* Clock Enable */
		cx18_write_reg_expect(cx, 0x10001000, 0xc71024,
					  0x00001000, 0x10001000);
	}
	/* courtesy of Steven Toth <*****@*****.**> */
	cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
	mdelay(10);
	cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0);
	mdelay(10);
	cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
	mdelay(10);

	/* Set to edge-triggered intrs. */
	cx18_write_reg(cx, 0x00c00000, 0xc730c8);
	/* Clear any stale intrs */
	cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS,
		       ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT);

	/* Hw I2C1 Clock Freq ~100kHz */
	cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);
	cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
	cx18_setsda(&cx->i2c_algo_cb_data[0], 1);

	/* Hw I2C2 Clock Freq ~100kHz */
	cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR);
	cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
	cx18_setsda(&cx->i2c_algo_cb_data[1], 1);

	cx18_reset_i2c_slaves_gpio(cx);

	return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
		i2c_bit_add_bus(&cx->i2c_adap[1]);
}
Example #13
0
int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
{
	struct cx18 *cx = s->cx;
	unsigned long then;

	if (!cx18_stream_enabled(s))
		return -EINVAL;

	/* This function assumes that you are allowed to stop the capture
	   and that we are actually capturing */

	CX18_DEBUG_INFO("Stop Capture\n");

	if (atomic_read(&cx->tot_capturing) == 0)
		return 0;

	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, !gop_end);
	else
		cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);

	then = jiffies;

	if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
#if 0
		/* only run these if we're shutting down the last cap */
		DECLARE_WAITQUEUE(wait, current);
		unsigned long duration;

		then = jiffies;
		add_wait_queue(&cx->cap_w, &wait);

		set_current_state(TASK_INTERRUPTIBLE);

		/* TODO: wait 2s for EOS interrupt */
		while (!test_bit(CX18_F_I_EOS, &cx->i_flags) &&
		       time_before(jiffies, then + msecs_to_jiffies(2000)))
			schedule_timeout(msecs_to_jiffies(10));

		duration = jiffies_to_msecs(jiffies - then);

		if (!test_bit(CX18_F_I_EOS, &cx->i_flags)) {
			CX18_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name);
			CX18_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration);
		} else {
			CX18_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
		}
		set_current_state(TASK_RUNNING);
		remove_wait_queue(&cx->cap_w, &wait);
#else
		CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
#endif
	}

	if (s->type != CX18_ENC_STREAM_TYPE_TS)
		atomic_dec(&cx->ana_capturing);
	atomic_dec(&cx->tot_capturing);

	/* Clear capture and no-read bits */
	clear_bit(CX18_F_S_STREAMING, &s->s_flags);

	/* Tell the CX23418 it can't use our buffers anymore */
	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)
		return 0;

	cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
	wake_up(&s->waitq);

	return 0;
}