Загрузка данных
#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;
}