linux/drivers/media/platform/exynos4-is/fimc-lite-reg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
   4 *
   5 * Copyright (C) 2012 Samsung Electronics Co., Ltd.
   6 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
   7*/
   8
   9#include <linux/bitops.h>
  10#include <linux/delay.h>
  11#include <linux/io.h>
  12#include <media/drv-intf/exynos-fimc.h>
  13
  14#include "fimc-lite-reg.h"
  15#include "fimc-lite.h"
  16#include "fimc-core.h"
  17
  18#define FLITE_RESET_TIMEOUT 50 /* in ms */
  19
  20void flite_hw_reset(struct fimc_lite *dev)
  21{
  22        unsigned long end = jiffies + msecs_to_jiffies(FLITE_RESET_TIMEOUT);
  23        u32 cfg;
  24
  25        cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  26        cfg |= FLITE_REG_CIGCTRL_SWRST_REQ;
  27        writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  28
  29        while (time_is_after_jiffies(end)) {
  30                cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  31                if (cfg & FLITE_REG_CIGCTRL_SWRST_RDY)
  32                        break;
  33                usleep_range(1000, 5000);
  34        }
  35
  36        cfg |= FLITE_REG_CIGCTRL_SWRST;
  37        writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  38}
  39
  40void flite_hw_clear_pending_irq(struct fimc_lite *dev)
  41{
  42        u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS);
  43        cfg &= ~FLITE_REG_CISTATUS_IRQ_CAM;
  44        writel(cfg, dev->regs + FLITE_REG_CISTATUS);
  45}
  46
  47u32 flite_hw_get_interrupt_source(struct fimc_lite *dev)
  48{
  49        u32 intsrc = readl(dev->regs + FLITE_REG_CISTATUS);
  50        return intsrc & FLITE_REG_CISTATUS_IRQ_MASK;
  51}
  52
  53void flite_hw_clear_last_capture_end(struct fimc_lite *dev)
  54{
  55
  56        u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS2);
  57        cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
  58        writel(cfg, dev->regs + FLITE_REG_CISTATUS2);
  59}
  60
  61void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
  62{
  63        u32 cfg, intsrc;
  64
  65        /* Select interrupts to be enabled for each output mode */
  66        if (atomic_read(&dev->out_path) == FIMC_IO_DMA) {
  67                intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
  68                         FLITE_REG_CIGCTRL_IRQ_LASTEN |
  69                         FLITE_REG_CIGCTRL_IRQ_STARTEN |
  70                         FLITE_REG_CIGCTRL_IRQ_ENDEN;
  71        } else {
  72                /* An output to the FIMC-IS */
  73                intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
  74                         FLITE_REG_CIGCTRL_IRQ_LASTEN;
  75        }
  76
  77        cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  78        cfg |= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK;
  79        cfg &= ~intsrc;
  80        writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  81}
  82
  83void flite_hw_capture_start(struct fimc_lite *dev)
  84{
  85        u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
  86        cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
  87        writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
  88}
  89
  90void flite_hw_capture_stop(struct fimc_lite *dev)
  91{
  92        u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
  93        cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
  94        writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
  95}
  96
  97/*
  98 * Test pattern (color bars) enable/disable. External sensor
  99 * pixel clock must be active for the test pattern to work.
 100 */
 101void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on)
 102{
 103        u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
 104        if (on)
 105                cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
 106        else
 107                cfg &= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
 108        writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
 109}
 110
 111static const u32 src_pixfmt_map[8][3] = {
 112        { MEDIA_BUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR,
 113          FLITE_REG_CIGCTRL_YUV422_1P },
 114        { MEDIA_BUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB,
 115          FLITE_REG_CIGCTRL_YUV422_1P },
 116        { MEDIA_BUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY,
 117          FLITE_REG_CIGCTRL_YUV422_1P },
 118        { MEDIA_BUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY,
 119          FLITE_REG_CIGCTRL_YUV422_1P },
 120        { MEDIA_BUS_FMT_SGRBG8_1X8, 0, FLITE_REG_CIGCTRL_RAW8 },
 121        { MEDIA_BUS_FMT_SGRBG10_1X10, 0, FLITE_REG_CIGCTRL_RAW10 },
 122        { MEDIA_BUS_FMT_SGRBG12_1X12, 0, FLITE_REG_CIGCTRL_RAW12 },
 123        { MEDIA_BUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) },
 124};
 125
 126/* Set camera input pixel format and resolution */
 127void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
 128{
 129        u32 pixelcode = f->fmt->mbus_code;
 130        int i = ARRAY_SIZE(src_pixfmt_map);
 131        u32 cfg;
 132
 133        while (--i) {
 134                if (src_pixfmt_map[i][0] == pixelcode)
 135                        break;
 136        }
 137
 138        if (i == 0 && src_pixfmt_map[i][0] != pixelcode) {
 139                v4l2_err(&dev->ve.vdev,
 140                         "Unsupported pixel code, falling back to %#08x\n",
 141                         src_pixfmt_map[i][0]);
 142        }
 143
 144        cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
 145        cfg &= ~FLITE_REG_CIGCTRL_FMT_MASK;
 146        cfg |= src_pixfmt_map[i][2];
 147        writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
 148
 149        cfg = readl(dev->regs + FLITE_REG_CISRCSIZE);
 150        cfg &= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK |
 151                 FLITE_REG_CISRCSIZE_SIZE_CAM_MASK);
 152        cfg |= (f->f_width << 16) | f->f_height;
 153        cfg |= src_pixfmt_map[i][1];
 154        writel(cfg, dev->regs + FLITE_REG_CISRCSIZE);
 155}
 156
 157/* Set the camera host input window offsets (cropping) */
 158void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f)
 159{
 160        u32 hoff2, voff2;
 161        u32 cfg;
 162
 163        cfg = readl(dev->regs + FLITE_REG_CIWDOFST);
 164        cfg &= ~FLITE_REG_CIWDOFST_OFST_MASK;
 165        cfg |= (f->rect.left << 16) | f->rect.top;
 166        cfg |= FLITE_REG_CIWDOFST_WINOFSEN;
 167        writel(cfg, dev->regs + FLITE_REG_CIWDOFST);
 168
 169        hoff2 = f->f_width - f->rect.width - f->rect.left;
 170        voff2 = f->f_height - f->rect.height - f->rect.top;
 171
 172        cfg = (hoff2 << 16) | voff2;
 173        writel(cfg, dev->regs + FLITE_REG_CIWDOFST2);
 174}
 175
 176/* Select camera port (A, B) */
 177static void flite_hw_set_camera_port(struct fimc_lite *dev, int id)
 178{
 179        u32 cfg = readl(dev->regs + FLITE_REG_CIGENERAL);
 180        if (id == 0)
 181                cfg &= ~FLITE_REG_CIGENERAL_CAM_B;
 182        else
 183                cfg |= FLITE_REG_CIGENERAL_CAM_B;
 184        writel(cfg, dev->regs + FLITE_REG_CIGENERAL);
 185}
 186
 187/* Select serial or parallel bus, camera port (A,B) and set signals polarity */
 188void flite_hw_set_camera_bus(struct fimc_lite *dev,
 189                             struct fimc_source_info *si)
 190{
 191        u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
 192        unsigned int flags = si->flags;
 193
 194        if (si->sensor_bus_type != FIMC_BUS_TYPE_MIPI_CSI2) {
 195                cfg &= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI |
 196                         FLITE_REG_CIGCTRL_INVPOLPCLK |
 197                         FLITE_REG_CIGCTRL_INVPOLVSYNC |
 198                         FLITE_REG_CIGCTRL_INVPOLHREF);
 199
 200                if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
 201                        cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK;
 202
 203                if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
 204                        cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC;
 205
 206                if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
 207                        cfg |= FLITE_REG_CIGCTRL_INVPOLHREF;
 208        } else {
 209                cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
 210        }
 211
 212        writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
 213
 214        flite_hw_set_camera_port(dev, si->mux_id);
 215}
 216
 217static void flite_hw_set_pack12(struct fimc_lite *dev, int on)
 218{
 219        u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
 220
 221        cfg &= ~FLITE_REG_CIODMAFMT_PACK12;
 222
 223        if (on)
 224                cfg |= FLITE_REG_CIODMAFMT_PACK12;
 225
 226        writel(cfg, dev->regs + FLITE_REG_CIODMAFMT);
 227}
 228
 229static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
 230{
 231        static const u32 pixcode[4][2] = {
 232                { MEDIA_BUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
 233                { MEDIA_BUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB },
 234                { MEDIA_BUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY },
 235                { MEDIA_BUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
 236        };
 237        u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
 238        int i = ARRAY_SIZE(pixcode);
 239
 240        while (--i)
 241                if (pixcode[i][0] == f->fmt->mbus_code)
 242                        break;
 243        cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;
 244        writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT);
 245}
 246
 247void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f)
 248{
 249        u32 cfg;
 250
 251        /* Maximum output pixel size */
 252        cfg = readl(dev->regs + FLITE_REG_CIOCAN);
 253        cfg &= ~FLITE_REG_CIOCAN_MASK;
 254        cfg |= (f->f_height << 16) | f->f_width;
 255        writel(cfg, dev->regs + FLITE_REG_CIOCAN);
 256
 257        /* DMA offsets */
 258        cfg = readl(dev->regs + FLITE_REG_CIOOFF);
 259        cfg &= ~FLITE_REG_CIOOFF_MASK;
 260        cfg |= (f->rect.top << 16) | f->rect.left;
 261        writel(cfg, dev->regs + FLITE_REG_CIOOFF);
 262}
 263
 264void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf)
 265{
 266        unsigned int index;
 267        u32 cfg;
 268
 269        if (dev->dd->max_dma_bufs == 1)
 270                index = 0;
 271        else
 272                index = buf->index;
 273
 274        if (index == 0)
 275                writel(buf->addr, dev->regs + FLITE_REG_CIOSA);
 276        else
 277                writel(buf->addr, dev->regs + FLITE_REG_CIOSAN(index - 1));
 278
 279        cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ);
 280        cfg |= BIT(index);
 281        writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ);
 282}
 283
 284void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index)
 285{
 286        u32 cfg;
 287
 288        if (dev->dd->max_dma_bufs == 1)
 289                index = 0;
 290
 291        cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ);
 292        cfg &= ~BIT(index);
 293        writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ);
 294}
 295
 296/* Enable/disable output DMA, set output pixel size and offsets (composition) */
 297void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
 298                             bool enable)
 299{
 300        u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
 301
 302        if (!enable) {
 303                cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
 304                writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
 305                return;
 306        }
 307
 308        cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
 309        writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
 310
 311        flite_hw_set_out_order(dev, f);
 312        flite_hw_set_dma_window(dev, f);
 313        flite_hw_set_pack12(dev, 0);
 314}
 315
 316void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
 317{
 318        struct {
 319                u32 offset;
 320                const char * const name;
 321        } registers[] = {
 322                { 0x00, "CISRCSIZE" },
 323                { 0x04, "CIGCTRL" },
 324                { 0x08, "CIIMGCPT" },
 325                { 0x0c, "CICPTSEQ" },
 326                { 0x10, "CIWDOFST" },
 327                { 0x14, "CIWDOFST2" },
 328                { 0x18, "CIODMAFMT" },
 329                { 0x20, "CIOCAN" },
 330                { 0x24, "CIOOFF" },
 331                { 0x30, "CIOSA" },
 332                { 0x40, "CISTATUS" },
 333                { 0x44, "CISTATUS2" },
 334                { 0xf0, "CITHOLD" },
 335                { 0xfc, "CIGENERAL" },
 336        };
 337        u32 i;
 338
 339        v4l2_info(&dev->subdev, "--- %s ---\n", label);
 340
 341        for (i = 0; i < ARRAY_SIZE(registers); i++) {
 342                u32 cfg = readl(dev->regs + registers[i].offset);
 343                v4l2_info(&dev->subdev, "%9s: 0x%08x\n",
 344                          registers[i].name, cfg);
 345        }
 346}
 347