123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
- */
- #include <linux/bitops.h>
- #include <linux/delay.h>
- #include <linux/io.h>
- #include <media/drv-intf/exynos-fimc.h>
- #include "fimc-lite-reg.h"
- #include "fimc-lite.h"
- #include "fimc-core.h"
- #define FLITE_RESET_TIMEOUT 50 /* in ms */
- void flite_hw_reset(struct fimc_lite *dev)
- {
- unsigned long end = jiffies + msecs_to_jiffies(FLITE_RESET_TIMEOUT);
- u32 cfg;
- cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
- cfg |= FLITE_REG_CIGCTRL_SWRST_REQ;
- writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
- while (time_is_after_jiffies(end)) {
- cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
- if (cfg & FLITE_REG_CIGCTRL_SWRST_RDY)
- break;
- usleep_range(1000, 5000);
- }
- cfg |= FLITE_REG_CIGCTRL_SWRST;
- writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
- }
- void flite_hw_clear_pending_irq(struct fimc_lite *dev)
- {
- u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS);
- cfg &= ~FLITE_REG_CISTATUS_IRQ_CAM;
- writel(cfg, dev->regs + FLITE_REG_CISTATUS);
- }
- u32 flite_hw_get_interrupt_source(struct fimc_lite *dev)
- {
- u32 intsrc = readl(dev->regs + FLITE_REG_CISTATUS);
- return intsrc & FLITE_REG_CISTATUS_IRQ_MASK;
- }
- void flite_hw_clear_last_capture_end(struct fimc_lite *dev)
- {
- u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS2);
- cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
- writel(cfg, dev->regs + FLITE_REG_CISTATUS2);
- }
- void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
- {
- u32 cfg, intsrc;
- /* Select interrupts to be enabled for each output mode */
- if (atomic_read(&dev->out_path) == FIMC_IO_DMA) {
- intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
- FLITE_REG_CIGCTRL_IRQ_LASTEN |
- FLITE_REG_CIGCTRL_IRQ_STARTEN |
- FLITE_REG_CIGCTRL_IRQ_ENDEN;
- } else {
- /* An output to the FIMC-IS */
- intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
- FLITE_REG_CIGCTRL_IRQ_LASTEN;
- }
- cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
- cfg |= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK;
- cfg &= ~intsrc;
- writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
- }
- void flite_hw_capture_start(struct fimc_lite *dev)
- {
- u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
- cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
- writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
- }
- void flite_hw_capture_stop(struct fimc_lite *dev)
- {
- u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
- cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
- writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
- }
- /*
- * Test pattern (color bars) enable/disable. External sensor
- * pixel clock must be active for the test pattern to work.
- */
- void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on)
- {
- u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
- if (on)
- cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
- else
- cfg &= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
- writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
- }
- static const u32 src_pixfmt_map[8][3] = {
- { MEDIA_BUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR,
- FLITE_REG_CIGCTRL_YUV422_1P },
- { MEDIA_BUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB,
- FLITE_REG_CIGCTRL_YUV422_1P },
- { MEDIA_BUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY,
- FLITE_REG_CIGCTRL_YUV422_1P },
- { MEDIA_BUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY,
- FLITE_REG_CIGCTRL_YUV422_1P },
- { MEDIA_BUS_FMT_SGRBG8_1X8, 0, FLITE_REG_CIGCTRL_RAW8 },
- { MEDIA_BUS_FMT_SGRBG10_1X10, 0, FLITE_REG_CIGCTRL_RAW10 },
- { MEDIA_BUS_FMT_SGRBG12_1X12, 0, FLITE_REG_CIGCTRL_RAW12 },
- { MEDIA_BUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) },
- };
- /* Set camera input pixel format and resolution */
- void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
- {
- u32 pixelcode = f->fmt->mbus_code;
- int i = ARRAY_SIZE(src_pixfmt_map);
- u32 cfg;
- while (--i) {
- if (src_pixfmt_map[i][0] == pixelcode)
- break;
- }
- if (i == 0 && src_pixfmt_map[i][0] != pixelcode) {
- v4l2_err(&dev->ve.vdev,
- "Unsupported pixel code, falling back to %#08x\n",
- src_pixfmt_map[i][0]);
- }
- cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
- cfg &= ~FLITE_REG_CIGCTRL_FMT_MASK;
- cfg |= src_pixfmt_map[i][2];
- writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
- cfg = readl(dev->regs + FLITE_REG_CISRCSIZE);
- cfg &= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK |
- FLITE_REG_CISRCSIZE_SIZE_CAM_MASK);
- cfg |= (f->f_width << 16) | f->f_height;
- cfg |= src_pixfmt_map[i][1];
- writel(cfg, dev->regs + FLITE_REG_CISRCSIZE);
- }
- /* Set the camera host input window offsets (cropping) */
- void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f)
- {
- u32 hoff2, voff2;
- u32 cfg;
- cfg = readl(dev->regs + FLITE_REG_CIWDOFST);
- cfg &= ~FLITE_REG_CIWDOFST_OFST_MASK;
- cfg |= (f->rect.left << 16) | f->rect.top;
- cfg |= FLITE_REG_CIWDOFST_WINOFSEN;
- writel(cfg, dev->regs + FLITE_REG_CIWDOFST);
- hoff2 = f->f_width - f->rect.width - f->rect.left;
- voff2 = f->f_height - f->rect.height - f->rect.top;
- cfg = (hoff2 << 16) | voff2;
- writel(cfg, dev->regs + FLITE_REG_CIWDOFST2);
- }
- /* Select camera port (A, B) */
- static void flite_hw_set_camera_port(struct fimc_lite *dev, int id)
- {
- u32 cfg = readl(dev->regs + FLITE_REG_CIGENERAL);
- if (id == 0)
- cfg &= ~FLITE_REG_CIGENERAL_CAM_B;
- else
- cfg |= FLITE_REG_CIGENERAL_CAM_B;
- writel(cfg, dev->regs + FLITE_REG_CIGENERAL);
- }
- /* Select serial or parallel bus, camera port (A,B) and set signals polarity */
- void flite_hw_set_camera_bus(struct fimc_lite *dev,
- struct fimc_source_info *si)
- {
- u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
- unsigned int flags = si->flags;
- if (si->sensor_bus_type != FIMC_BUS_TYPE_MIPI_CSI2) {
- cfg &= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI |
- FLITE_REG_CIGCTRL_INVPOLPCLK |
- FLITE_REG_CIGCTRL_INVPOLVSYNC |
- FLITE_REG_CIGCTRL_INVPOLHREF);
- if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
- cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK;
- if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC;
- if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- cfg |= FLITE_REG_CIGCTRL_INVPOLHREF;
- } else {
- cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
- }
- writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
- flite_hw_set_camera_port(dev, si->mux_id);
- }
- static void flite_hw_set_pack12(struct fimc_lite *dev, int on)
- {
- u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
- cfg &= ~FLITE_REG_CIODMAFMT_PACK12;
- if (on)
- cfg |= FLITE_REG_CIODMAFMT_PACK12;
- writel(cfg, dev->regs + FLITE_REG_CIODMAFMT);
- }
- static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
- {
- static const u32 pixcode[4][2] = {
- { MEDIA_BUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
- { MEDIA_BUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB },
- { MEDIA_BUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY },
- { MEDIA_BUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
- };
- u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
- int i = ARRAY_SIZE(pixcode);
- while (--i)
- if (pixcode[i][0] == f->fmt->mbus_code)
- break;
- cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;
- writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT);
- }
- void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f)
- {
- u32 cfg;
- /* Maximum output pixel size */
- cfg = readl(dev->regs + FLITE_REG_CIOCAN);
- cfg &= ~FLITE_REG_CIOCAN_MASK;
- cfg |= (f->f_height << 16) | f->f_width;
- writel(cfg, dev->regs + FLITE_REG_CIOCAN);
- /* DMA offsets */
- cfg = readl(dev->regs + FLITE_REG_CIOOFF);
- cfg &= ~FLITE_REG_CIOOFF_MASK;
- cfg |= (f->rect.top << 16) | f->rect.left;
- writel(cfg, dev->regs + FLITE_REG_CIOOFF);
- }
- void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf)
- {
- unsigned int index;
- u32 cfg;
- if (dev->dd->max_dma_bufs == 1)
- index = 0;
- else
- index = buf->index;
- if (index == 0)
- writel(buf->paddr, dev->regs + FLITE_REG_CIOSA);
- else
- writel(buf->paddr, dev->regs + FLITE_REG_CIOSAN(index - 1));
- cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ);
- cfg |= BIT(index);
- writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ);
- }
- void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index)
- {
- u32 cfg;
- if (dev->dd->max_dma_bufs == 1)
- index = 0;
- cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ);
- cfg &= ~BIT(index);
- writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ);
- }
- /* Enable/disable output DMA, set output pixel size and offsets (composition) */
- void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
- bool enable)
- {
- u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
- if (!enable) {
- cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
- writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
- return;
- }
- cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
- writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
- flite_hw_set_out_order(dev, f);
- flite_hw_set_dma_window(dev, f);
- flite_hw_set_pack12(dev, 0);
- }
- void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
- {
- struct {
- u32 offset;
- const char * const name;
- } registers[] = {
- { 0x00, "CISRCSIZE" },
- { 0x04, "CIGCTRL" },
- { 0x08, "CIIMGCPT" },
- { 0x0c, "CICPTSEQ" },
- { 0x10, "CIWDOFST" },
- { 0x14, "CIWDOFST2" },
- { 0x18, "CIODMAFMT" },
- { 0x20, "CIOCAN" },
- { 0x24, "CIOOFF" },
- { 0x30, "CIOSA" },
- { 0x40, "CISTATUS" },
- { 0x44, "CISTATUS2" },
- { 0xf0, "CITHOLD" },
- { 0xfc, "CIGENERAL" },
- };
- u32 i;
- v4l2_info(&dev->subdev, "--- %s ---\n", label);
- for (i = 0; i < ARRAY_SIZE(registers); i++) {
- u32 cfg = readl(dev->regs + registers[i].offset);
- v4l2_info(&dev->subdev, "%9s: 0x%08x\n",
- registers[i].name, cfg);
- }
- }
|