linux/drivers/media/platform/s3c-camif/camif-regs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Samsung s3c24xx/s3c64xx SoC CAMIF driver
   4 *
   5 * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
   6 * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com>
   7*/
   8#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
   9
  10#include <linux/delay.h>
  11#include "camif-regs.h"
  12
  13#define camif_write(_camif, _off, _val) writel(_val, (_camif)->io_base + (_off))
  14#define camif_read(_camif, _off)        readl((_camif)->io_base + (_off))
  15
  16void camif_hw_reset(struct camif_dev *camif)
  17{
  18        u32 cfg;
  19
  20        cfg = camif_read(camif, S3C_CAMIF_REG_CISRCFMT);
  21        cfg |= CISRCFMT_ITU601_8BIT;
  22        camif_write(camif, S3C_CAMIF_REG_CISRCFMT, cfg);
  23
  24        /* S/W reset */
  25        cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
  26        cfg |= CIGCTRL_SWRST;
  27        if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV)
  28                cfg |= CIGCTRL_IRQ_LEVEL;
  29        camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
  30        udelay(10);
  31
  32        cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
  33        cfg &= ~CIGCTRL_SWRST;
  34        camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
  35        udelay(10);
  36}
  37
  38void camif_hw_clear_pending_irq(struct camif_vp *vp)
  39{
  40        u32 cfg = camif_read(vp->camif, S3C_CAMIF_REG_CIGCTRL);
  41        cfg |= CIGCTRL_IRQ_CLR(vp->id);
  42        camif_write(vp->camif, S3C_CAMIF_REG_CIGCTRL, cfg);
  43}
  44
  45/*
  46 * Sets video test pattern (off, color bar, horizontal or vertical gradient).
  47 * External sensor pixel clock must be active for the test pattern to work.
  48 */
  49void camif_hw_set_test_pattern(struct camif_dev *camif, unsigned int pattern)
  50{
  51        u32 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
  52        cfg &= ~CIGCTRL_TESTPATTERN_MASK;
  53        cfg |= (pattern << 27);
  54        camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
  55}
  56
  57void camif_hw_set_effect(struct camif_dev *camif, unsigned int effect,
  58                        unsigned int cr, unsigned int cb)
  59{
  60        static const struct v4l2_control colorfx[] = {
  61                { V4L2_COLORFX_NONE,            CIIMGEFF_FIN_BYPASS },
  62                { V4L2_COLORFX_BW,              CIIMGEFF_FIN_ARBITRARY },
  63                { V4L2_COLORFX_SEPIA,           CIIMGEFF_FIN_ARBITRARY },
  64                { V4L2_COLORFX_NEGATIVE,        CIIMGEFF_FIN_NEGATIVE },
  65                { V4L2_COLORFX_ART_FREEZE,      CIIMGEFF_FIN_ARTFREEZE },
  66                { V4L2_COLORFX_EMBOSS,          CIIMGEFF_FIN_EMBOSSING },
  67                { V4L2_COLORFX_SILHOUETTE,      CIIMGEFF_FIN_SILHOUETTE },
  68                { V4L2_COLORFX_SET_CBCR,        CIIMGEFF_FIN_ARBITRARY },
  69        };
  70        unsigned int i, cfg;
  71
  72        for (i = 0; i < ARRAY_SIZE(colorfx); i++)
  73                if (colorfx[i].id == effect)
  74                        break;
  75
  76        if (i == ARRAY_SIZE(colorfx))
  77                return;
  78
  79        cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGEFF(camif->vp->offset));
  80        /* Set effect */
  81        cfg &= ~CIIMGEFF_FIN_MASK;
  82        cfg |= colorfx[i].value;
  83        /* Set both paths */
  84        if (camif->variant->ip_revision >= S3C6400_CAMIF_IP_REV) {
  85                if (effect == V4L2_COLORFX_NONE)
  86                        cfg &= ~CIIMGEFF_IE_ENABLE_MASK;
  87                else
  88                        cfg |= CIIMGEFF_IE_ENABLE_MASK;
  89        }
  90        cfg &= ~CIIMGEFF_PAT_CBCR_MASK;
  91        cfg |= cr | (cb << 13);
  92        camif_write(camif, S3C_CAMIF_REG_CIIMGEFF(camif->vp->offset), cfg);
  93}
  94
  95static const u32 src_pixfmt_map[8][2] = {
  96        { MEDIA_BUS_FMT_YUYV8_2X8, CISRCFMT_ORDER422_YCBYCR },
  97        { MEDIA_BUS_FMT_YVYU8_2X8, CISRCFMT_ORDER422_YCRYCB },
  98        { MEDIA_BUS_FMT_UYVY8_2X8, CISRCFMT_ORDER422_CBYCRY },
  99        { MEDIA_BUS_FMT_VYUY8_2X8, CISRCFMT_ORDER422_CRYCBY },
 100};
 101
 102/* Set camera input pixel format and resolution */
 103void camif_hw_set_source_format(struct camif_dev *camif)
 104{
 105        struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt;
 106        int i;
 107        u32 cfg;
 108
 109        for (i = ARRAY_SIZE(src_pixfmt_map) - 1; i >= 0; i--) {
 110                if (src_pixfmt_map[i][0] == mf->code)
 111                        break;
 112        }
 113        if (i < 0) {
 114                i = 0;
 115                dev_err(camif->dev,
 116                        "Unsupported pixel code, falling back to %#08x\n",
 117                        src_pixfmt_map[i][0]);
 118        }
 119
 120        cfg = camif_read(camif, S3C_CAMIF_REG_CISRCFMT);
 121        cfg &= ~(CISRCFMT_ORDER422_MASK | CISRCFMT_SIZE_CAM_MASK);
 122        cfg |= (mf->width << 16) | mf->height;
 123        cfg |= src_pixfmt_map[i][1];
 124        camif_write(camif, S3C_CAMIF_REG_CISRCFMT, cfg);
 125}
 126
 127/* Set the camera host input window offsets (cropping) */
 128void camif_hw_set_camera_crop(struct camif_dev *camif)
 129{
 130        struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt;
 131        struct v4l2_rect *crop = &camif->camif_crop;
 132        u32 hoff2, voff2;
 133        u32 cfg;
 134
 135        /* Note: s3c244x requirement: left = f_width - rect.width / 2 */
 136        cfg = camif_read(camif, S3C_CAMIF_REG_CIWDOFST);
 137        cfg &= ~(CIWDOFST_OFST_MASK | CIWDOFST_WINOFSEN);
 138        cfg |= (crop->left << 16) | crop->top;
 139        if (crop->left != 0 || crop->top != 0)
 140                cfg |= CIWDOFST_WINOFSEN;
 141        camif_write(camif, S3C_CAMIF_REG_CIWDOFST, cfg);
 142
 143        if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) {
 144                hoff2 = mf->width - crop->width - crop->left;
 145                voff2 = mf->height - crop->height - crop->top;
 146                cfg = (hoff2 << 16) | voff2;
 147                camif_write(camif, S3C_CAMIF_REG_CIWDOFST2, cfg);
 148        }
 149}
 150
 151void camif_hw_clear_fifo_overflow(struct camif_vp *vp)
 152{
 153        struct camif_dev *camif = vp->camif;
 154        u32 cfg;
 155
 156        cfg = camif_read(camif, S3C_CAMIF_REG_CIWDOFST);
 157        if (vp->id == 0)
 158                cfg |= (CIWDOFST_CLROVCOFIY | CIWDOFST_CLROVCOFICB |
 159                        CIWDOFST_CLROVCOFICR);
 160        else
 161                cfg |= (/* CIWDOFST_CLROVPRFIY | */ CIWDOFST_CLROVPRFICB |
 162                        CIWDOFST_CLROVPRFICR);
 163        camif_write(camif, S3C_CAMIF_REG_CIWDOFST, cfg);
 164}
 165
 166/* Set video bus signals polarity */
 167void camif_hw_set_camera_bus(struct camif_dev *camif)
 168{
 169        unsigned int flags = camif->pdata.sensor.flags;
 170
 171        u32 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
 172
 173        cfg &= ~(CIGCTRL_INVPOLPCLK | CIGCTRL_INVPOLVSYNC |
 174                 CIGCTRL_INVPOLHREF | CIGCTRL_INVPOLFIELD);
 175
 176        if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
 177                cfg |= CIGCTRL_INVPOLPCLK;
 178
 179        if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
 180                cfg |= CIGCTRL_INVPOLVSYNC;
 181        /*
 182         * HREF is normally high during frame active data
 183         * transmission and low during horizontal synchronization
 184         * period. Thus HREF active high means HSYNC active low.
 185         */
 186        if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
 187                cfg |= CIGCTRL_INVPOLHREF; /* HREF active low */
 188
 189        if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) {
 190                if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
 191                        cfg |= CIGCTRL_INVPOLFIELD;
 192                cfg |= CIGCTRL_FIELDMODE;
 193        }
 194
 195        pr_debug("Setting CIGCTRL to: %#x\n", cfg);
 196
 197        camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
 198}
 199
 200void camif_hw_set_output_addr(struct camif_vp *vp,
 201                              struct camif_addr *paddr, int i)
 202{
 203        struct camif_dev *camif = vp->camif;
 204
 205        camif_write(camif, S3C_CAMIF_REG_CIYSA(vp->id, i), paddr->y);
 206        if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV
 207                || vp->id == VP_CODEC) {
 208                camif_write(camif, S3C_CAMIF_REG_CICBSA(vp->id, i),
 209                                                                paddr->cb);
 210                camif_write(camif, S3C_CAMIF_REG_CICRSA(vp->id, i),
 211                                                                paddr->cr);
 212        }
 213
 214        pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad\n",
 215                 i, &paddr->y, &paddr->cb, &paddr->cr);
 216}
 217
 218static void camif_hw_set_out_dma_size(struct camif_vp *vp)
 219{
 220        struct camif_frame *frame = &vp->out_frame;
 221        u32 cfg;
 222
 223        cfg = camif_read(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset));
 224        cfg &= ~CITRGFMT_TARGETSIZE_MASK;
 225        cfg |= (frame->f_width << 16) | frame->f_height;
 226        camif_write(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg);
 227}
 228
 229static void camif_get_dma_burst(u32 width, u32 ybpp, u32 *mburst, u32 *rburst)
 230{
 231        unsigned int nwords = width * ybpp / 4;
 232        unsigned int div, rem;
 233
 234        if (WARN_ON(width < 8 || (width * ybpp) & 7))
 235                return;
 236
 237        for (div = 16; div >= 2; div /= 2) {
 238                if (nwords < div)
 239                        continue;
 240
 241                rem = nwords & (div - 1);
 242                if (rem == 0) {
 243                        *mburst = div;
 244                        *rburst = div;
 245                        break;
 246                }
 247                if (rem == div / 2 || rem == div / 4) {
 248                        *mburst = div;
 249                        *rburst = rem;
 250                        break;
 251                }
 252        }
 253}
 254
 255void camif_hw_set_output_dma(struct camif_vp *vp)
 256{
 257        struct camif_dev *camif = vp->camif;
 258        struct camif_frame *frame = &vp->out_frame;
 259        const struct camif_fmt *fmt = vp->out_fmt;
 260        unsigned int ymburst = 0, yrburst = 0;
 261        u32 cfg;
 262
 263        camif_hw_set_out_dma_size(vp);
 264
 265        if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) {
 266                struct camif_dma_offset *offset = &frame->dma_offset;
 267                /* Set the input dma offsets. */
 268                cfg = S3C_CISS_OFFS_INITIAL(offset->initial);
 269                cfg |= S3C_CISS_OFFS_LINE(offset->line);
 270                camif_write(camif, S3C_CAMIF_REG_CISSY(vp->id), cfg);
 271                camif_write(camif, S3C_CAMIF_REG_CISSCB(vp->id), cfg);
 272                camif_write(camif, S3C_CAMIF_REG_CISSCR(vp->id), cfg);
 273        }
 274
 275        /* Configure DMA burst values */
 276        camif_get_dma_burst(frame->rect.width, fmt->ybpp, &ymburst, &yrburst);
 277
 278        cfg = camif_read(camif, S3C_CAMIF_REG_CICTRL(vp->id, vp->offset));
 279        cfg &= ~CICTRL_BURST_MASK;
 280
 281        cfg |= CICTRL_YBURST1(ymburst) | CICTRL_YBURST2(yrburst);
 282        cfg |= CICTRL_CBURST1(ymburst / 2) | CICTRL_CBURST2(yrburst / 2);
 283
 284        camif_write(camif, S3C_CAMIF_REG_CICTRL(vp->id, vp->offset), cfg);
 285
 286        pr_debug("ymburst: %u, yrburst: %u\n", ymburst, yrburst);
 287}
 288
 289void camif_hw_set_input_path(struct camif_vp *vp)
 290{
 291        u32 cfg = camif_read(vp->camif, S3C_CAMIF_REG_MSCTRL(vp->id));
 292        cfg &= ~MSCTRL_SEL_DMA_CAM;
 293        camif_write(vp->camif, S3C_CAMIF_REG_MSCTRL(vp->id), cfg);
 294}
 295
 296void camif_hw_set_target_format(struct camif_vp *vp)
 297{
 298        struct camif_dev *camif = vp->camif;
 299        struct camif_frame *frame = &vp->out_frame;
 300        u32 cfg;
 301
 302        pr_debug("fw: %d, fh: %d color: %d\n", frame->f_width,
 303                 frame->f_height, vp->out_fmt->color);
 304
 305        cfg = camif_read(camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset));
 306        cfg &= ~CITRGFMT_TARGETSIZE_MASK;
 307
 308        if (camif->variant->ip_revision == S3C244X_CAMIF_IP_REV) {
 309                /* We currently support only YCbCr 4:2:2 at the camera input */
 310                cfg |= CITRGFMT_IN422;
 311                cfg &= ~CITRGFMT_OUT422;
 312                if (vp->out_fmt->color == IMG_FMT_YCBCR422P)
 313                        cfg |= CITRGFMT_OUT422;
 314        } else {
 315                cfg &= ~CITRGFMT_OUTFORMAT_MASK;
 316                switch (vp->out_fmt->color) {
 317                case IMG_FMT_RGB565...IMG_FMT_XRGB8888:
 318                        cfg |= CITRGFMT_OUTFORMAT_RGB;
 319                        break;
 320                case IMG_FMT_YCBCR420...IMG_FMT_YCRCB420:
 321                        cfg |= CITRGFMT_OUTFORMAT_YCBCR420;
 322                        break;
 323                case IMG_FMT_YCBCR422P:
 324                        cfg |= CITRGFMT_OUTFORMAT_YCBCR422;
 325                        break;
 326                case IMG_FMT_YCBYCR422...IMG_FMT_CRYCBY422:
 327                        cfg |= CITRGFMT_OUTFORMAT_YCBCR422I;
 328                        break;
 329                }
 330        }
 331
 332        /* Rotation is only supported by s3c64xx */
 333        if (vp->rotation == 90 || vp->rotation == 270)
 334                cfg |= (frame->f_height << 16) | frame->f_width;
 335        else
 336                cfg |= (frame->f_width << 16) | frame->f_height;
 337        camif_write(camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg);
 338
 339        /* Target area, output pixel width * height */
 340        cfg = camif_read(camif, S3C_CAMIF_REG_CITAREA(vp->id, vp->offset));
 341        cfg &= ~CITAREA_MASK;
 342        cfg |= (frame->f_width * frame->f_height);
 343        camif_write(camif, S3C_CAMIF_REG_CITAREA(vp->id, vp->offset), cfg);
 344}
 345
 346void camif_hw_set_flip(struct camif_vp *vp)
 347{
 348        u32 cfg = camif_read(vp->camif,
 349                                S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset));
 350
 351        cfg &= ~CITRGFMT_FLIP_MASK;
 352
 353        if (vp->hflip)
 354                cfg |= CITRGFMT_FLIP_Y_MIRROR;
 355        if (vp->vflip)
 356                cfg |= CITRGFMT_FLIP_X_MIRROR;
 357
 358        camif_write(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg);
 359}
 360
 361static void camif_hw_set_prescaler(struct camif_vp *vp)
 362{
 363        struct camif_dev *camif = vp->camif;
 364        struct camif_scaler *sc = &vp->scaler;
 365        u32 cfg, shfactor, addr;
 366
 367        addr = S3C_CAMIF_REG_CISCPRERATIO(vp->id, vp->offset);
 368
 369        shfactor = 10 - (sc->h_shift + sc->v_shift);
 370        cfg = shfactor << 28;
 371
 372        cfg |= (sc->pre_h_ratio << 16) | sc->pre_v_ratio;
 373        camif_write(camif, addr, cfg);
 374
 375        cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height;
 376        camif_write(camif, S3C_CAMIF_REG_CISCPREDST(vp->id, vp->offset), cfg);
 377}
 378
 379static void camif_s3c244x_hw_set_scaler(struct camif_vp *vp)
 380{
 381        struct camif_dev *camif = vp->camif;
 382        struct camif_scaler *scaler = &vp->scaler;
 383        unsigned int color = vp->out_fmt->color;
 384        u32 cfg;
 385
 386        camif_hw_set_prescaler(vp);
 387
 388        cfg = camif_read(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset));
 389
 390        cfg &= ~(CISCCTRL_SCALEUP_MASK | CISCCTRL_SCALERBYPASS |
 391                 CISCCTRL_MAIN_RATIO_MASK | CIPRSCCTRL_RGB_FORMAT_24BIT);
 392
 393        if (scaler->enable) {
 394                if (scaler->scaleup_h) {
 395                        if (vp->id == VP_CODEC)
 396                                cfg |= CISCCTRL_SCALEUP_H;
 397                        else
 398                                cfg |= CIPRSCCTRL_SCALEUP_H;
 399                }
 400                if (scaler->scaleup_v) {
 401                        if (vp->id == VP_CODEC)
 402                                cfg |= CISCCTRL_SCALEUP_V;
 403                        else
 404                                cfg |= CIPRSCCTRL_SCALEUP_V;
 405                }
 406        } else {
 407                if (vp->id == VP_CODEC)
 408                        cfg |= CISCCTRL_SCALERBYPASS;
 409        }
 410
 411        cfg |= ((scaler->main_h_ratio & 0x1ff) << 16);
 412        cfg |= scaler->main_v_ratio & 0x1ff;
 413
 414        if (vp->id == VP_PREVIEW) {
 415                if (color == IMG_FMT_XRGB8888)
 416                        cfg |= CIPRSCCTRL_RGB_FORMAT_24BIT;
 417                cfg |= CIPRSCCTRL_SAMPLE;
 418        }
 419
 420        camif_write(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset), cfg);
 421
 422        pr_debug("main: h_ratio: %#x, v_ratio: %#x",
 423                 scaler->main_h_ratio, scaler->main_v_ratio);
 424}
 425
 426static void camif_s3c64xx_hw_set_scaler(struct camif_vp *vp)
 427{
 428        struct camif_dev *camif = vp->camif;
 429        struct camif_scaler *scaler = &vp->scaler;
 430        unsigned int color = vp->out_fmt->color;
 431        u32 cfg;
 432
 433        camif_hw_set_prescaler(vp);
 434
 435        cfg = camif_read(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset));
 436
 437        cfg &= ~(CISCCTRL_CSCR2Y_WIDE | CISCCTRL_CSCY2R_WIDE
 438                | CISCCTRL_SCALEUP_H | CISCCTRL_SCALEUP_V
 439                | CISCCTRL_SCALERBYPASS | CISCCTRL_ONE2ONE
 440                | CISCCTRL_INRGB_FMT_MASK | CISCCTRL_OUTRGB_FMT_MASK
 441                | CISCCTRL_INTERLACE | CISCCTRL_EXTRGB_EXTENSION
 442                | CISCCTRL_MAIN_RATIO_MASK);
 443
 444        cfg |= (CISCCTRL_CSCR2Y_WIDE | CISCCTRL_CSCY2R_WIDE);
 445
 446        if (!scaler->enable) {
 447                cfg |= CISCCTRL_SCALERBYPASS;
 448        } else {
 449                if (scaler->scaleup_h)
 450                        cfg |= CISCCTRL_SCALEUP_H;
 451                if (scaler->scaleup_v)
 452                        cfg |= CISCCTRL_SCALEUP_V;
 453                if (scaler->copy)
 454                        cfg |= CISCCTRL_ONE2ONE;
 455        }
 456
 457        switch (color) {
 458        case IMG_FMT_RGB666:
 459                cfg |= CISCCTRL_OUTRGB_FMT_RGB666;
 460                break;
 461        case IMG_FMT_XRGB8888:
 462                cfg |= CISCCTRL_OUTRGB_FMT_RGB888;
 463                break;
 464        }
 465
 466        cfg |= (scaler->main_h_ratio & 0x1ff) << 16;
 467        cfg |= scaler->main_v_ratio & 0x1ff;
 468
 469        camif_write(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset), cfg);
 470
 471        pr_debug("main: h_ratio: %#x, v_ratio: %#x",
 472                 scaler->main_h_ratio, scaler->main_v_ratio);
 473}
 474
 475void camif_hw_set_scaler(struct camif_vp *vp)
 476{
 477        unsigned int ip_rev = vp->camif->variant->ip_revision;
 478
 479        if (ip_rev == S3C244X_CAMIF_IP_REV)
 480                camif_s3c244x_hw_set_scaler(vp);
 481        else
 482                camif_s3c64xx_hw_set_scaler(vp);
 483}
 484
 485void camif_hw_enable_scaler(struct camif_vp *vp, bool on)
 486{
 487        u32 addr = S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset);
 488        u32 cfg;
 489
 490        cfg = camif_read(vp->camif, addr);
 491        if (on)
 492                cfg |= CISCCTRL_SCALERSTART;
 493        else
 494                cfg &= ~CISCCTRL_SCALERSTART;
 495        camif_write(vp->camif, addr, cfg);
 496}
 497
 498void camif_hw_set_lastirq(struct camif_vp *vp, int enable)
 499{
 500        u32 addr = S3C_CAMIF_REG_CICTRL(vp->id, vp->offset);
 501        u32 cfg;
 502
 503        cfg = camif_read(vp->camif, addr);
 504        if (enable)
 505                cfg |= CICTRL_LASTIRQ_ENABLE;
 506        else
 507                cfg &= ~CICTRL_LASTIRQ_ENABLE;
 508        camif_write(vp->camif, addr, cfg);
 509}
 510
 511void camif_hw_enable_capture(struct camif_vp *vp)
 512{
 513        struct camif_dev *camif = vp->camif;
 514        u32 cfg;
 515
 516        cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset));
 517        camif->stream_count++;
 518
 519        if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV)
 520                cfg |= CIIMGCPT_CPT_FREN_ENABLE(vp->id);
 521
 522        if (vp->scaler.enable)
 523                cfg |= CIIMGCPT_IMGCPTEN_SC(vp->id);
 524
 525        if (camif->stream_count == 1)
 526                cfg |= CIIMGCPT_IMGCPTEN;
 527
 528        camif_write(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset), cfg);
 529
 530        pr_debug("CIIMGCPT: %#x, camif->stream_count: %d\n",
 531                 cfg, camif->stream_count);
 532}
 533
 534void camif_hw_disable_capture(struct camif_vp *vp)
 535{
 536        struct camif_dev *camif = vp->camif;
 537        u32 cfg;
 538
 539        cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset));
 540        cfg &= ~CIIMGCPT_IMGCPTEN_SC(vp->id);
 541
 542        if (WARN_ON(--(camif->stream_count) < 0))
 543                camif->stream_count = 0;
 544
 545        if (camif->stream_count == 0)
 546                cfg &= ~CIIMGCPT_IMGCPTEN;
 547
 548        pr_debug("CIIMGCPT: %#x, camif->stream_count: %d\n",
 549                 cfg, camif->stream_count);
 550
 551        camif_write(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset), cfg);
 552}
 553
 554void camif_hw_dump_regs(struct camif_dev *camif, const char *label)
 555{
 556        static const struct {
 557                u32 offset;
 558                const char * const name;
 559        } registers[] = {
 560                { S3C_CAMIF_REG_CISRCFMT,               "CISRCFMT" },
 561                { S3C_CAMIF_REG_CIWDOFST,               "CIWDOFST" },
 562                { S3C_CAMIF_REG_CIGCTRL,                "CIGCTRL" },
 563                { S3C_CAMIF_REG_CIWDOFST2,              "CIWDOFST2" },
 564                { S3C_CAMIF_REG_CIYSA(0, 0),            "CICOYSA0" },
 565                { S3C_CAMIF_REG_CICBSA(0, 0),           "CICOCBSA0" },
 566                { S3C_CAMIF_REG_CICRSA(0, 0),           "CICOCRSA0" },
 567                { S3C_CAMIF_REG_CIYSA(0, 1),            "CICOYSA1" },
 568                { S3C_CAMIF_REG_CICBSA(0, 1),           "CICOCBSA1" },
 569                { S3C_CAMIF_REG_CICRSA(0, 1),           "CICOCRSA1" },
 570                { S3C_CAMIF_REG_CIYSA(0, 2),            "CICOYSA2" },
 571                { S3C_CAMIF_REG_CICBSA(0, 2),           "CICOCBSA2" },
 572                { S3C_CAMIF_REG_CICRSA(0, 2),           "CICOCRSA2" },
 573                { S3C_CAMIF_REG_CIYSA(0, 3),            "CICOYSA3" },
 574                { S3C_CAMIF_REG_CICBSA(0, 3),           "CICOCBSA3" },
 575                { S3C_CAMIF_REG_CICRSA(0, 3),           "CICOCRSA3" },
 576                { S3C_CAMIF_REG_CIYSA(1, 0),            "CIPRYSA0" },
 577                { S3C_CAMIF_REG_CIYSA(1, 1),            "CIPRYSA1" },
 578                { S3C_CAMIF_REG_CIYSA(1, 2),            "CIPRYSA2" },
 579                { S3C_CAMIF_REG_CIYSA(1, 3),            "CIPRYSA3" },
 580                { S3C_CAMIF_REG_CITRGFMT(0, 0),         "CICOTRGFMT" },
 581                { S3C_CAMIF_REG_CITRGFMT(1, 0),         "CIPRTRGFMT" },
 582                { S3C_CAMIF_REG_CICTRL(0, 0),           "CICOCTRL" },
 583                { S3C_CAMIF_REG_CICTRL(1, 0),           "CIPRCTRL" },
 584                { S3C_CAMIF_REG_CISCPREDST(0, 0),       "CICOSCPREDST" },
 585                { S3C_CAMIF_REG_CISCPREDST(1, 0),       "CIPRSCPREDST" },
 586                { S3C_CAMIF_REG_CISCPRERATIO(0, 0),     "CICOSCPRERATIO" },
 587                { S3C_CAMIF_REG_CISCPRERATIO(1, 0),     "CIPRSCPRERATIO" },
 588                { S3C_CAMIF_REG_CISCCTRL(0, 0),         "CICOSCCTRL" },
 589                { S3C_CAMIF_REG_CISCCTRL(1, 0),         "CIPRSCCTRL" },
 590                { S3C_CAMIF_REG_CITAREA(0, 0),          "CICOTAREA" },
 591                { S3C_CAMIF_REG_CITAREA(1, 0),          "CIPRTAREA" },
 592                { S3C_CAMIF_REG_CISTATUS(0, 0),         "CICOSTATUS" },
 593                { S3C_CAMIF_REG_CISTATUS(1, 0),         "CIPRSTATUS" },
 594                { S3C_CAMIF_REG_CIIMGCPT(0),            "CIIMGCPT" },
 595        };
 596        u32 i;
 597
 598        pr_info("--- %s ---\n", label);
 599        for (i = 0; i < ARRAY_SIZE(registers); i++) {
 600                u32 cfg = readl(camif->io_base + registers[i].offset);
 601                dev_info(camif->dev, "%s:\t0x%08x\n", registers[i].name, cfg);
 602        }
 603}
 604