Загрузка данных


#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/mfd/imx-flexio.h>
#include <linux/of.h>

#include <media/videobuf2-dma-contig.h>

#include "flexio-capture-v4l.h"

#define MHZ(v) ((u32)((v) * 1000000U))

#define FLEXIO_CLK_RATE          MHZ(120)
#define FLEXIO_SHIFTER_START_IDX 0
#define FLEXIO_TIMER_IDX         0
#define FLEXIO_XCLK_TIMER_IDX    1

/* Register offsets missed in imx-flexio.h */
#ifndef SHIFTBUF
#define SHIFTBUF 0x200
#endif

static void  flexio_capture_clear_status_flag(struct imx_flexio_capture_dev *fcam)
{
	void __iomem *base = fcam->hw.base;

	flexio_writel(base, (((1UL << FLEXIO_SHIFTER_COUNT) - 1U) << FLEXIO_SHIFTER_START_IDX), SHIFTSTAT);
	flexio_writel(base, (((1UL << FLEXIO_SHIFTER_COUNT) - 1U) << FLEXIO_SHIFTER_START_IDX), SHIFTERR);
}

static void
flexio_capture_enable_rx_dma(struct imx_flexio_capture_dev *fcam, bool enable)
{
	void __iomem *base = fcam->hw.base;
	u32 val, mask = 1UL << FLEXIO_SHIFTER_START_IDX;

	val = flexio_readl(base, SHIFTSDEN);
	if (enable)
		val |= mask;
	else
		val &= ~mask;
	flexio_writel(base, val, SHIFTSDEN);
}

static int flexio_capture_prepare_dma(struct imx_flexio_capture_dev *fcam)
{
	struct dma_slave_config cfg = { 0 };


	cfg.src_addr = (phys_addr_t)(fcam->hw.src_addr + SHIFTBUF + FLEXIO_SHIFTER_START_IDX * 4);
	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_32_BYTES;
	cfg.src_maxburst = 1;
	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_32_BYTES;
	cfg.dst_maxburst = 1;
	cfg.direction = DMA_DEV_TO_MEM;

	return dmaengine_slave_config(fcam->hw.dma, &cfg);
}

static void flexio_capture_cleanup_dma(struct imx_flexio_capture_dev *fcam)
{
	dmaengine_terminate_sync(fcam->hw.dma);
}

static int flexio_capture_dma_submit(struct imx_flexio_capture_dev *fcam)
{
	struct dma_chan *chan = fcam->hw.dma;
	struct dma_async_tx_descriptor *txdesc;
	struct v4l2_pix_format *fmt;
	dma_addr_t dest_addr;

	if (!fcam->pipe.active)
		return -EINVAL;


	fmt = &fcam->pipe.pixfmt;
	dest_addr = vb2_dma_contig_plane_dma_addr(&fcam->pipe.active->v4l2_buf.vb2_buf, 0);
	txdesc = dmaengine_prep_slave_single(chan, dest_addr, fmt->sizeimage,
					     DMA_DEV_TO_MEM,
					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
	if (!txdesc) {
		dev_err(fcam->dev, "FlexIO dma prep slave sg failed\n");
		flexio_capture_cleanup_dma(fcam);
		return -EINVAL;
	}
#if 0
	txdesc->callback = flexio_capture_dma_callback;
	txdesc->callback_param = (void *)fcam;
#endif

	if (dma_submit_error(dmaengine_submit(txdesc))) {
		dev_err(fcam->dev, "submitting flexio dma failed\n");
		flexio_capture_cleanup_dma(fcam);
		return -EINVAL;
	}
	dma_async_issue_pending(chan);

	return 0;
}

int flexio_capture_hw_init(struct imx_flexio_capture_dev *fcam)
{
	void __iomem *base = fcam->hw.base;
	struct flexio_shifter_control shiftctl;
	struct flexio_shifter_config shiftcfg;
	struct flexio_timer_control timerctl;
	struct flexio_timer_config timercfg;
	u32 bus_flags = fcam->pipe.buscfg.bus.parallel.flags;
	u32 timercmp, i;
	int ret = 0;
	int pwidth;

	if (!fcam->pipe.config)
		return -EINVAL;

	switch (fcam->pipe.buscfg.bus.parallel.bus_width) {
	case 8:
		pwidth = 8 - 1;
		timercmp = 16U / 2;
		break;
	case 16:
		pwidth = 16 - 1;
		timercmp = 16U / 1;
		break;
	default:
		return -EINVAL;
	}

	flexio_sw_reset(base, CTRL);

	/* FLEXIO_CAMERA shifter config */
	shiftctl.timsel = FLEXIO_TIMER_IDX;
	shiftctl.timpol = SHIFT_ON_POSEDGE;
	shiftctl.pincfg = SHIFTER_PIN_OUTPUT_DISABLE;
	shiftctl.pinsel = 0;
	shiftctl.pinpol = PIN_ACTIVE_HIGH;
	shiftctl.smod	= SHIFTER_RECEIVE;

	shiftcfg.pwidth = pwidth;

	shiftcfg.insrc	= INPUT_SRC_NEXT;
	shiftcfg.sstop	= SSTOP_BIT_DISABLE;
	shiftcfg.sstart = SSTART_BIT_DISABLE;
	/* Configure the shifters as FIFO buffer. */
	for (i = FLEXIO_SHIFTER_START_IDX; i < (FLEXIO_SHIFTER_START_IDX + FLEXIO_SHIFTER_COUNT - 1U); i++)
	{
		flexio_setup_shiftctl(base, &shiftctl, SHIFTCTL_0 + i * 4);
		flexio_setup_shiftcfg(base, &shiftcfg, SHIFTCFG_0 + i * 4);
	}
	shiftcfg.insrc	= INPUT_SRC_PIN;
	flexio_setup_shiftctl(base, &shiftctl, SHIFTCTL_0 + i * 4);
	flexio_setup_shiftcfg(base, &shiftcfg, SHIFTCFG_0 + i * 4);

	/* FLEXIO_CAMERA timer config, the PCLK is the source of timer
	 * to drive the shifter, the HREF is the selecting signal for
	 * available data. */
	timerctl.trgsel = TIMER_TRGSEL_SEL_PININPUT(fcam->hw.href_pin);
	if (bus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
		timerctl.trgpol = TIMER_TRG_ACTIVE_LOW;
	else
		timerctl.trgpol = TIMER_TRG_ACTIVE_HIGH;
	timerctl.trgsrc = TIMER_TRGSRC_INTER;
	timerctl.pincfg = TIMPIN_OUTPUT_DISABLE;
	timerctl.pinsel = fcam->hw.pclk_pin;
	if (bus_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
		timerctl.pinpol = TIMPIN_ACTIVE_LOW;
	else
		timerctl.pinpol = TIMPIN_ACTIVE_HIGH;
	timerctl.timod	= SINGLE_16BIT_COUNTER;
	flexio_setup_timerctl(base, &timerctl, TIMCTL_0 + FLEXIO_TIMER_IDX * 4);

	timercfg.timout	= TIMOUT_ZERO_NOTAFFECT_BY_RESET;
	timercfg.timdec	= TIMDEC_PIN_INPUT;
	timercfg.timrst	= TIMRST_TIMPIN_TRG_RISING_EDGE;
	timercfg.timdis	= TIMDIS_TRG_FALLING_EDGE;
	timercfg.timena	= TIMENA_TRG_RISING_EDGE;
	timercfg.tstop	= TSTOP_BIT_DISABLE;
	timercfg.tstart	= TSTART_BIT_DISABLE;
	flexio_setup_timercfg(base, &timercfg, TIMCFG_0 + FLEXIO_TIMER_IDX * 4);
	timercmp *= FLEXIO_SHIFTER_COUNT;
	timercmp -= 1U;
	flexio_writel(base, timercmp, TIMCMP_0 + FLEXIO_TIMER_IDX * 4);
#if 0 /* Use FlexIO Timer 1 to generate 24MHz clock. to drive sensor */
	timerctl.trgsel = 0;
	timerctl.trgpol = TIMER_TRG_ACTIVE_HIGH;
	timerctl.trgsrc = TIMER_TRGSRC_INTER;
	timerctl.pincfg = TIMPIN_OUTPUT;
	timerctl.pinsel = fcam->hw.xclk_pin;
	timerctl.pinpol = TIMPIN_ACTIVE_HIGH;
	timerctl.timod	= DUAL_8BIT_COUNTERS_PWM;
	flexio_setup_timerctl(base, &timerctl, TIMCTL_0 + FLEXIO_XCLK_TIMER_IDX * 4);

	/* configure the timer 1 to control shifters */
	timercfg.timout = TIMOUT_ZERO_NOTAFFECT_BY_RESET;
	timercfg.timdec = TIMDEC_FLEXIO_CLK;
	timercfg.timrst = TIMRST_NEVER;
	timercfg.timdis = TIMDIS_NEVER;
	timercfg.timena = TIMENA_ALWAYS;
	timercfg.tstop  = TSTOP_BIT_DISABLE;
	timercfg.tstart = TSTART_BIT_DISABLE;
	flexio_setup_timercfg(base, &timercfg, TIMCFG_0 + FLEXIO_XCLK_TIMER_IDX * 4);
	if (FLEXIO_CLK_RATE == MHZ(250))
		timercmp = 0x0401; /* 250MHz clock source generates 24MHz clock.*/
	else if (FLEXIO_CLK_RATE == MHZ(125))
		timercmp = 0x0201; /* 125MHz clock source generates 24MHz clock.*/
	else if (FLEXIO_CLK_RATE == MHZ(100))
		timercmp = 0x0100; /* 100MHz clock source generates 24MHz clock.*/
	else if (FLEXIO_CLK_RATE == MHZ(80))
		timercmp = 0x0100; /* 80MHz clock source generates 24MHz clock.*/
	else if (FLEXIO_CLK_RATE == MHZ(50))
		timercmp = 0x00CD; /* 50MHz clock source generates 24MHz clock.*/
	else
		timercmp = 0x090A; /* 500MHz clock source generates 24MHz clock.*/
	flexio_writel(base, timercmp, TIMCMP_0 + FLEXIO_XCLK_TIMER_IDX * 4);
#endif
	/* Clear flags. */
	flexio_writel(base, 1UL << (FLEXIO_TIMER_IDX), TIMSTAT);
	flexio_capture_clear_status_flag(fcam);

	/* disable the shifter status interrupt and shifter error interrupt */
	flexio_writel(base, 0, SHIFTSIEN);
	flexio_writel(base, 0, SHIFTEIEN);
	flexio_get_default_ctrl(&fcam->hw.ctrl);
	flexio_setup_ctrl(base, &fcam->hw.ctrl, CTRL);

	return ret;
}

int flexio_capture_hw_enable(struct imx_flexio_capture_dev *fcam)
{
	int ret;

	ret = flexio_capture_prepare_dma(fcam);
	if (ret)
		return ret;

	if (fcam->pipe.active) {
		ret = flexio_capture_dma_submit(fcam);
		if (ret)
			return ret;
	}

	flexio_capture_enable_rx_dma(fcam, true);

	enable_irq(fcam->hw.irq);

	return 0;
}