linux/drivers/media/platform/omap3isp/isppreview.c
<<
>>
Prefs
   1/*
   2 * isppreview.c
   3 *
   4 * TI OMAP3 ISP driver - Preview module
   5 *
   6 * Copyright (C) 2010 Nokia Corporation
   7 * Copyright (C) 2009 Texas Instruments, Inc.
   8 *
   9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  10 *           Sakari Ailus <sakari.ailus@iki.fi>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 */
  16
  17#include <linux/device.h>
  18#include <linux/mm.h>
  19#include <linux/module.h>
  20#include <linux/mutex.h>
  21#include <linux/uaccess.h>
  22
  23#include "isp.h"
  24#include "ispreg.h"
  25#include "isppreview.h"
  26
  27/* Default values in Office Fluorescent Light for RGBtoRGB Blending */
  28static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
  29        {       /* RGB-RGB Matrix */
  30                {0x01E2, 0x0F30, 0x0FEE},
  31                {0x0F9B, 0x01AC, 0x0FB9},
  32                {0x0FE0, 0x0EC0, 0x0260}
  33        },      /* RGB Offset */
  34        {0x0000, 0x0000, 0x0000}
  35};
  36
  37/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/
  38static struct omap3isp_prev_csc flr_prev_csc = {
  39        {       /* CSC Coef Matrix */
  40                {66, 129, 25},
  41                {-38, -75, 112},
  42                {112, -94 , -18}
  43        },      /* CSC Offset */
  44        {0x0, 0x0, 0x0}
  45};
  46
  47/* Default values in Office Fluorescent Light for CFA Gradient*/
  48#define FLR_CFA_GRADTHRS_HORZ   0x28
  49#define FLR_CFA_GRADTHRS_VERT   0x28
  50
  51/* Default values in Office Fluorescent Light for Chroma Suppression*/
  52#define FLR_CSUP_GAIN           0x0D
  53#define FLR_CSUP_THRES          0xEB
  54
  55/* Default values in Office Fluorescent Light for Noise Filter*/
  56#define FLR_NF_STRGTH           0x03
  57
  58/* Default values for White Balance */
  59#define FLR_WBAL_DGAIN          0x100
  60#define FLR_WBAL_COEF           0x20
  61
  62/* Default values in Office Fluorescent Light for Black Adjustment*/
  63#define FLR_BLKADJ_BLUE         0x0
  64#define FLR_BLKADJ_GREEN        0x0
  65#define FLR_BLKADJ_RED          0x0
  66
  67#define DEF_DETECT_CORRECT_VAL  0xe
  68
  69/*
  70 * Margins and image size limits.
  71 *
  72 * The preview engine crops several rows and columns internally depending on
  73 * which filters are enabled. To avoid format changes when the filters are
  74 * enabled or disabled (which would prevent them from being turned on or off
  75 * during streaming), the driver assumes all filters that can be configured
  76 * during streaming are enabled when computing sink crop and source format
  77 * limits.
  78 *
  79 * If a filter is disabled, additional cropping is automatically added at the
  80 * preview engine input by the driver to avoid overflow at line and frame end.
  81 * This is completely transparent for applications.
  82 *
  83 * Median filter                4 pixels
  84 * Noise filter,
  85 * Faulty pixels correction     4 pixels, 4 lines
  86 * Color suppression            2 pixels
  87 * or luma enhancement
  88 * -------------------------------------------------------------
  89 * Maximum total                10 pixels, 4 lines
  90 *
  91 * The color suppression and luma enhancement filters are applied after bayer to
  92 * YUV conversion. They thus can crop one pixel on the left and one pixel on the
  93 * right side of the image without changing the color pattern. When both those
  94 * filters are disabled, the driver must crop the two pixels on the same side of
  95 * the image to avoid changing the bayer pattern. The left margin is thus set to
  96 * 6 pixels and the right margin to 4 pixels.
  97 */
  98
  99#define PREV_MARGIN_LEFT        6
 100#define PREV_MARGIN_RIGHT       4
 101#define PREV_MARGIN_TOP         2
 102#define PREV_MARGIN_BOTTOM      2
 103
 104#define PREV_MIN_IN_WIDTH       64
 105#define PREV_MIN_IN_HEIGHT      8
 106#define PREV_MAX_IN_HEIGHT      16384
 107
 108#define PREV_MIN_OUT_WIDTH              0
 109#define PREV_MIN_OUT_HEIGHT             0
 110#define PREV_MAX_OUT_WIDTH_REV_1        1280
 111#define PREV_MAX_OUT_WIDTH_REV_2        3300
 112#define PREV_MAX_OUT_WIDTH_REV_15       4096
 113
 114/*
 115 * Coefficient Tables for the submodules in Preview.
 116 * Array is initialised with the values from.the tables text file.
 117 */
 118
 119/*
 120 * CFA Filter Coefficient Table
 121 *
 122 */
 123static u32 cfa_coef_table[4][OMAP3ISP_PREV_CFA_BLK_SIZE] = {
 124#include "cfa_coef_table.h"
 125};
 126
 127/*
 128 * Default Gamma Correction Table - All components
 129 */
 130static u32 gamma_table[] = {
 131#include "gamma_table.h"
 132};
 133
 134/*
 135 * Noise Filter Threshold table
 136 */
 137static u32 noise_filter_table[] = {
 138#include "noise_filter_table.h"
 139};
 140
 141/*
 142 * Luminance Enhancement Table
 143 */
 144static u32 luma_enhance_table[] = {
 145#include "luma_enhance_table.h"
 146};
 147
 148/*
 149 * preview_config_luma_enhancement - Configure the Luminance Enhancement table
 150 */
 151static void
 152preview_config_luma_enhancement(struct isp_prev_device *prev,
 153                                const struct prev_params *params)
 154{
 155        struct isp_device *isp = to_isp_device(prev);
 156        const struct omap3isp_prev_luma *yt = &params->luma;
 157        unsigned int i;
 158
 159        isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
 160                       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 161        for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
 162                isp_reg_writel(isp, yt->table[i],
 163                               OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
 164        }
 165}
 166
 167/*
 168 * preview_enable_luma_enhancement - Enable/disable Luminance Enhancement
 169 */
 170static void
 171preview_enable_luma_enhancement(struct isp_prev_device *prev, bool enable)
 172{
 173        struct isp_device *isp = to_isp_device(prev);
 174
 175        if (enable)
 176                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 177                            ISPPRV_PCR_YNENHEN);
 178        else
 179                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 180                            ISPPRV_PCR_YNENHEN);
 181}
 182
 183/*
 184 * preview_enable_invalaw - Enable/disable Inverse A-Law decompression
 185 */
 186static void preview_enable_invalaw(struct isp_prev_device *prev, bool enable)
 187{
 188        struct isp_device *isp = to_isp_device(prev);
 189
 190        if (enable)
 191                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 192                            ISPPRV_PCR_INVALAW);
 193        else
 194                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 195                            ISPPRV_PCR_INVALAW);
 196}
 197
 198/*
 199 * preview_config_hmed - Configure the Horizontal Median Filter
 200 */
 201static void preview_config_hmed(struct isp_prev_device *prev,
 202                                const struct prev_params *params)
 203{
 204        struct isp_device *isp = to_isp_device(prev);
 205        const struct omap3isp_prev_hmed *hmed = &params->hmed;
 206
 207        isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
 208                       (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
 209                       (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
 210                       OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
 211}
 212
 213/*
 214 * preview_enable_hmed - Enable/disable the Horizontal Median Filter
 215 */
 216static void preview_enable_hmed(struct isp_prev_device *prev, bool enable)
 217{
 218        struct isp_device *isp = to_isp_device(prev);
 219
 220        if (enable)
 221                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 222                            ISPPRV_PCR_HMEDEN);
 223        else
 224                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 225                            ISPPRV_PCR_HMEDEN);
 226}
 227
 228/*
 229 * preview_config_cfa - Configure CFA Interpolation for Bayer formats
 230 *
 231 * The CFA table is organised in four blocks, one per Bayer component. The
 232 * hardware expects blocks to follow the Bayer order of the input data, while
 233 * the driver stores the table in GRBG order in memory. The blocks need to be
 234 * reordered to support non-GRBG Bayer patterns.
 235 */
 236static void preview_config_cfa(struct isp_prev_device *prev,
 237                               const struct prev_params *params)
 238{
 239        static const unsigned int cfa_coef_order[4][4] = {
 240                { 0, 1, 2, 3 }, /* GRBG */
 241                { 1, 0, 3, 2 }, /* RGGB */
 242                { 2, 3, 0, 1 }, /* BGGR */
 243                { 3, 2, 1, 0 }, /* GBRG */
 244        };
 245        const unsigned int *order = cfa_coef_order[prev->params.cfa_order];
 246        const struct omap3isp_prev_cfa *cfa = &params->cfa;
 247        struct isp_device *isp = to_isp_device(prev);
 248        unsigned int i;
 249        unsigned int j;
 250
 251        isp_reg_writel(isp,
 252                (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
 253                (cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
 254                OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
 255
 256        isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
 257                       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 258
 259        for (i = 0; i < 4; ++i) {
 260                const __u32 *block = cfa->table[order[i]];
 261
 262                for (j = 0; j < OMAP3ISP_PREV_CFA_BLK_SIZE; ++j)
 263                        isp_reg_writel(isp, block[j], OMAP3_ISP_IOMEM_PREV,
 264                                       ISPPRV_SET_TBL_DATA);
 265        }
 266}
 267
 268/*
 269 * preview_config_chroma_suppression - Configure Chroma Suppression
 270 */
 271static void
 272preview_config_chroma_suppression(struct isp_prev_device *prev,
 273                                  const struct prev_params *params)
 274{
 275        struct isp_device *isp = to_isp_device(prev);
 276        const struct omap3isp_prev_csup *cs = &params->csup;
 277
 278        isp_reg_writel(isp,
 279                       cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
 280                       (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
 281                       OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
 282}
 283
 284/*
 285 * preview_enable_chroma_suppression - Enable/disable Chrominance Suppression
 286 */
 287static void
 288preview_enable_chroma_suppression(struct isp_prev_device *prev, bool enable)
 289{
 290        struct isp_device *isp = to_isp_device(prev);
 291
 292        if (enable)
 293                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 294                            ISPPRV_PCR_SUPEN);
 295        else
 296                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 297                            ISPPRV_PCR_SUPEN);
 298}
 299
 300/*
 301 * preview_config_whitebalance - Configure White Balance parameters
 302 *
 303 * Coefficient matrix always with default values.
 304 */
 305static void
 306preview_config_whitebalance(struct isp_prev_device *prev,
 307                            const struct prev_params *params)
 308{
 309        struct isp_device *isp = to_isp_device(prev);
 310        const struct omap3isp_prev_wbal *wbal = &params->wbal;
 311        u32 val;
 312
 313        isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
 314
 315        val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
 316        val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
 317        val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
 318        val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
 319        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
 320
 321        isp_reg_writel(isp,
 322                       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
 323                       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
 324                       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
 325                       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
 326                       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT |
 327                       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT |
 328                       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT |
 329                       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT |
 330                       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT |
 331                       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT |
 332                       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT |
 333                       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT |
 334                       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT |
 335                       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT |
 336                       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT |
 337                       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT,
 338                       OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL);
 339}
 340
 341/*
 342 * preview_config_blkadj - Configure Black Adjustment
 343 */
 344static void
 345preview_config_blkadj(struct isp_prev_device *prev,
 346                      const struct prev_params *params)
 347{
 348        struct isp_device *isp = to_isp_device(prev);
 349        const struct omap3isp_prev_blkadj *blkadj = &params->blkadj;
 350
 351        isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
 352                       (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
 353                       (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT),
 354                       OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
 355}
 356
 357/*
 358 * preview_config_rgb_blending - Configure RGB-RGB Blending
 359 */
 360static void
 361preview_config_rgb_blending(struct isp_prev_device *prev,
 362                            const struct prev_params *params)
 363{
 364        struct isp_device *isp = to_isp_device(prev);
 365        const struct omap3isp_prev_rgbtorgb *rgbrgb = &params->rgb2rgb;
 366        u32 val;
 367
 368        val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
 369        val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
 370        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
 371
 372        val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
 373        val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
 374        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
 375
 376        val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
 377        val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
 378        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
 379
 380        val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
 381        val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
 382        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
 383
 384        val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
 385        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
 386
 387        val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
 388        val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
 389        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
 390
 391        val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
 392        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
 393}
 394
 395/*
 396 * preview_config_csc - Configure Color Space Conversion (RGB to YCbYCr)
 397 */
 398static void
 399preview_config_csc(struct isp_prev_device *prev,
 400                   const struct prev_params *params)
 401{
 402        struct isp_device *isp = to_isp_device(prev);
 403        const struct omap3isp_prev_csc *csc = &params->csc;
 404        u32 val;
 405
 406        val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
 407        val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
 408        val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
 409        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
 410
 411        val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
 412        val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
 413        val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
 414        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
 415
 416        val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
 417        val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
 418        val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
 419        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
 420
 421        val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
 422        val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
 423        val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
 424        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
 425}
 426
 427/*
 428 * preview_config_yc_range - Configure the max and min Y and C values
 429 */
 430static void
 431preview_config_yc_range(struct isp_prev_device *prev,
 432                        const struct prev_params *params)
 433{
 434        struct isp_device *isp = to_isp_device(prev);
 435        const struct omap3isp_prev_yclimit *yc = &params->yclimit;
 436
 437        isp_reg_writel(isp,
 438                       yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
 439                       yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
 440                       yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
 441                       yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
 442                       OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
 443}
 444
 445/*
 446 * preview_config_dcor - Configure Couplet Defect Correction
 447 */
 448static void
 449preview_config_dcor(struct isp_prev_device *prev,
 450                    const struct prev_params *params)
 451{
 452        struct isp_device *isp = to_isp_device(prev);
 453        const struct omap3isp_prev_dcor *dcor = &params->dcor;
 454
 455        isp_reg_writel(isp, dcor->detect_correct[0],
 456                       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
 457        isp_reg_writel(isp, dcor->detect_correct[1],
 458                       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
 459        isp_reg_writel(isp, dcor->detect_correct[2],
 460                       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
 461        isp_reg_writel(isp, dcor->detect_correct[3],
 462                       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
 463        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 464                        ISPPRV_PCR_DCCOUP,
 465                        dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
 466}
 467
 468/*
 469 * preview_enable_dcor - Enable/disable Couplet Defect Correction
 470 */
 471static void preview_enable_dcor(struct isp_prev_device *prev, bool enable)
 472{
 473        struct isp_device *isp = to_isp_device(prev);
 474
 475        if (enable)
 476                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 477                            ISPPRV_PCR_DCOREN);
 478        else
 479                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 480                            ISPPRV_PCR_DCOREN);
 481}
 482
 483/*
 484 * preview_enable_drkframe_capture - Enable/disable Dark Frame Capture
 485 */
 486static void
 487preview_enable_drkframe_capture(struct isp_prev_device *prev, bool enable)
 488{
 489        struct isp_device *isp = to_isp_device(prev);
 490
 491        if (enable)
 492                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 493                            ISPPRV_PCR_DRKFCAP);
 494        else
 495                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 496                            ISPPRV_PCR_DRKFCAP);
 497}
 498
 499/*
 500 * preview_enable_drkframe - Enable/disable Dark Frame Subtraction
 501 */
 502static void preview_enable_drkframe(struct isp_prev_device *prev, bool enable)
 503{
 504        struct isp_device *isp = to_isp_device(prev);
 505
 506        if (enable)
 507                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 508                            ISPPRV_PCR_DRKFEN);
 509        else
 510                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 511                            ISPPRV_PCR_DRKFEN);
 512}
 513
 514/*
 515 * preview_config_noisefilter - Configure the Noise Filter
 516 */
 517static void
 518preview_config_noisefilter(struct isp_prev_device *prev,
 519                           const struct prev_params *params)
 520{
 521        struct isp_device *isp = to_isp_device(prev);
 522        const struct omap3isp_prev_nf *nf = &params->nf;
 523        unsigned int i;
 524
 525        isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
 526        isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
 527                       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 528        for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
 529                isp_reg_writel(isp, nf->table[i],
 530                               OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
 531        }
 532}
 533
 534/*
 535 * preview_enable_noisefilter - Enable/disable the Noise Filter
 536 */
 537static void
 538preview_enable_noisefilter(struct isp_prev_device *prev, bool enable)
 539{
 540        struct isp_device *isp = to_isp_device(prev);
 541
 542        if (enable)
 543                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 544                            ISPPRV_PCR_NFEN);
 545        else
 546                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 547                            ISPPRV_PCR_NFEN);
 548}
 549
 550/*
 551 * preview_config_gammacorrn - Configure the Gamma Correction tables
 552 */
 553static void
 554preview_config_gammacorrn(struct isp_prev_device *prev,
 555                          const struct prev_params *params)
 556{
 557        struct isp_device *isp = to_isp_device(prev);
 558        const struct omap3isp_prev_gtables *gt = &params->gamma;
 559        unsigned int i;
 560
 561        isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
 562                       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 563        for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
 564                isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
 565                               ISPPRV_SET_TBL_DATA);
 566
 567        isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
 568                       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 569        for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
 570                isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
 571                               ISPPRV_SET_TBL_DATA);
 572
 573        isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
 574                       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 575        for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
 576                isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
 577                               ISPPRV_SET_TBL_DATA);
 578}
 579
 580/*
 581 * preview_enable_gammacorrn - Enable/disable Gamma Correction
 582 *
 583 * When gamma correction is disabled, the module is bypassed and its output is
 584 * the 8 MSB of the 10-bit input .
 585 */
 586static void
 587preview_enable_gammacorrn(struct isp_prev_device *prev, bool enable)
 588{
 589        struct isp_device *isp = to_isp_device(prev);
 590
 591        if (enable)
 592                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 593                            ISPPRV_PCR_GAMMA_BYPASS);
 594        else
 595                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 596                            ISPPRV_PCR_GAMMA_BYPASS);
 597}
 598
 599/*
 600 * preview_config_contrast - Configure the Contrast
 601 *
 602 * Value should be programmed before enabling the module.
 603 */
 604static void
 605preview_config_contrast(struct isp_prev_device *prev,
 606                        const struct prev_params *params)
 607{
 608        struct isp_device *isp = to_isp_device(prev);
 609
 610        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
 611                        0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
 612                        params->contrast << ISPPRV_CNT_BRT_CNT_SHIFT);
 613}
 614
 615/*
 616 * preview_config_brightness - Configure the Brightness
 617 */
 618static void
 619preview_config_brightness(struct isp_prev_device *prev,
 620                          const struct prev_params *params)
 621{
 622        struct isp_device *isp = to_isp_device(prev);
 623
 624        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
 625                        0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
 626                        params->brightness << ISPPRV_CNT_BRT_BRT_SHIFT);
 627}
 628
 629/*
 630 * preview_update_contrast - Updates the contrast.
 631 * @contrast: Pointer to hold the current programmed contrast value.
 632 *
 633 * Value should be programmed before enabling the module.
 634 */
 635static void
 636preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
 637{
 638        struct prev_params *params;
 639        unsigned long flags;
 640
 641        spin_lock_irqsave(&prev->params.lock, flags);
 642        params = (prev->params.active & OMAP3ISP_PREV_CONTRAST)
 643               ? &prev->params.params[0] : &prev->params.params[1];
 644
 645        if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
 646                params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
 647                params->update |= OMAP3ISP_PREV_CONTRAST;
 648        }
 649        spin_unlock_irqrestore(&prev->params.lock, flags);
 650}
 651
 652/*
 653 * preview_update_brightness - Updates the brightness in preview module.
 654 * @brightness: Pointer to hold the current programmed brightness value.
 655 *
 656 */
 657static void
 658preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
 659{
 660        struct prev_params *params;
 661        unsigned long flags;
 662
 663        spin_lock_irqsave(&prev->params.lock, flags);
 664        params = (prev->params.active & OMAP3ISP_PREV_BRIGHTNESS)
 665               ? &prev->params.params[0] : &prev->params.params[1];
 666
 667        if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
 668                params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
 669                params->update |= OMAP3ISP_PREV_BRIGHTNESS;
 670        }
 671        spin_unlock_irqrestore(&prev->params.lock, flags);
 672}
 673
 674static u32
 675preview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow)
 676{
 677        u32 active = prev->params.active;
 678
 679        if (shadow) {
 680                /* Mark all shadow parameters we are going to touch as busy. */
 681                prev->params.params[0].busy |= ~active & update;
 682                prev->params.params[1].busy |= active & update;
 683        } else {
 684                /* Mark all active parameters we are going to touch as busy. */
 685                update = (prev->params.params[0].update & active)
 686                       | (prev->params.params[1].update & ~active);
 687
 688                prev->params.params[0].busy |= active & update;
 689                prev->params.params[1].busy |= ~active & update;
 690        }
 691
 692        return update;
 693}
 694
 695static void
 696preview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow)
 697{
 698        u32 active = prev->params.active;
 699
 700        if (shadow) {
 701                /* Set the update flag for shadow parameters that have been
 702                 * updated and clear the busy flag for all shadow parameters.
 703                 */
 704                prev->params.params[0].update |= (~active & update);
 705                prev->params.params[1].update |= (active & update);
 706                prev->params.params[0].busy &= active;
 707                prev->params.params[1].busy &= ~active;
 708        } else {
 709                /* Clear the update flag for active parameters that have been
 710                 * applied and the busy flag for all active parameters.
 711                 */
 712                prev->params.params[0].update &= ~(active & update);
 713                prev->params.params[1].update &= ~(~active & update);
 714                prev->params.params[0].busy &= ~active;
 715                prev->params.params[1].busy &= active;
 716        }
 717}
 718
 719static void preview_params_switch(struct isp_prev_device *prev)
 720{
 721        u32 to_switch;
 722
 723        /* Switch active parameters with updated shadow parameters when the
 724         * shadow parameter has been updated and neither the active not the
 725         * shadow parameter is busy.
 726         */
 727        to_switch = (prev->params.params[0].update & ~prev->params.active)
 728                  | (prev->params.params[1].update & prev->params.active);
 729        to_switch &= ~(prev->params.params[0].busy |
 730                       prev->params.params[1].busy);
 731        if (to_switch == 0)
 732                return;
 733
 734        prev->params.active ^= to_switch;
 735
 736        /* Remove the update flag for the shadow copy of parameters we have
 737         * switched.
 738         */
 739        prev->params.params[0].update &= ~(~prev->params.active & to_switch);
 740        prev->params.params[1].update &= ~(prev->params.active & to_switch);
 741}
 742
 743/* preview parameters update structure */
 744struct preview_update {
 745        void (*config)(struct isp_prev_device *, const struct prev_params *);
 746        void (*enable)(struct isp_prev_device *, bool);
 747        unsigned int param_offset;
 748        unsigned int param_size;
 749        unsigned int config_offset;
 750        bool skip;
 751};
 752
 753/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
 754static const struct preview_update update_attrs[] = {
 755        /* OMAP3ISP_PREV_LUMAENH */ {
 756                preview_config_luma_enhancement,
 757                preview_enable_luma_enhancement,
 758                offsetof(struct prev_params, luma),
 759                FIELD_SIZEOF(struct prev_params, luma),
 760                offsetof(struct omap3isp_prev_update_config, luma),
 761        }, /* OMAP3ISP_PREV_INVALAW */ {
 762                NULL,
 763                preview_enable_invalaw,
 764        }, /* OMAP3ISP_PREV_HRZ_MED */ {
 765                preview_config_hmed,
 766                preview_enable_hmed,
 767                offsetof(struct prev_params, hmed),
 768                FIELD_SIZEOF(struct prev_params, hmed),
 769                offsetof(struct omap3isp_prev_update_config, hmed),
 770        }, /* OMAP3ISP_PREV_CFA */ {
 771                preview_config_cfa,
 772                NULL,
 773                offsetof(struct prev_params, cfa),
 774                FIELD_SIZEOF(struct prev_params, cfa),
 775                offsetof(struct omap3isp_prev_update_config, cfa),
 776        }, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
 777                preview_config_chroma_suppression,
 778                preview_enable_chroma_suppression,
 779                offsetof(struct prev_params, csup),
 780                FIELD_SIZEOF(struct prev_params, csup),
 781                offsetof(struct omap3isp_prev_update_config, csup),
 782        }, /* OMAP3ISP_PREV_WB */ {
 783                preview_config_whitebalance,
 784                NULL,
 785                offsetof(struct prev_params, wbal),
 786                FIELD_SIZEOF(struct prev_params, wbal),
 787                offsetof(struct omap3isp_prev_update_config, wbal),
 788        }, /* OMAP3ISP_PREV_BLKADJ */ {
 789                preview_config_blkadj,
 790                NULL,
 791                offsetof(struct prev_params, blkadj),
 792                FIELD_SIZEOF(struct prev_params, blkadj),
 793                offsetof(struct omap3isp_prev_update_config, blkadj),
 794        }, /* OMAP3ISP_PREV_RGB2RGB */ {
 795                preview_config_rgb_blending,
 796                NULL,
 797                offsetof(struct prev_params, rgb2rgb),
 798                FIELD_SIZEOF(struct prev_params, rgb2rgb),
 799                offsetof(struct omap3isp_prev_update_config, rgb2rgb),
 800        }, /* OMAP3ISP_PREV_COLOR_CONV */ {
 801                preview_config_csc,
 802                NULL,
 803                offsetof(struct prev_params, csc),
 804                FIELD_SIZEOF(struct prev_params, csc),
 805                offsetof(struct omap3isp_prev_update_config, csc),
 806        }, /* OMAP3ISP_PREV_YC_LIMIT */ {
 807                preview_config_yc_range,
 808                NULL,
 809                offsetof(struct prev_params, yclimit),
 810                FIELD_SIZEOF(struct prev_params, yclimit),
 811                offsetof(struct omap3isp_prev_update_config, yclimit),
 812        }, /* OMAP3ISP_PREV_DEFECT_COR */ {
 813                preview_config_dcor,
 814                preview_enable_dcor,
 815                offsetof(struct prev_params, dcor),
 816                FIELD_SIZEOF(struct prev_params, dcor),
 817                offsetof(struct omap3isp_prev_update_config, dcor),
 818        }, /* Previously OMAP3ISP_PREV_GAMMABYPASS, not used anymore */ {
 819                NULL,
 820                NULL,
 821        }, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
 822                NULL,
 823                preview_enable_drkframe_capture,
 824        }, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
 825                NULL,
 826                preview_enable_drkframe,
 827        }, /* OMAP3ISP_PREV_LENS_SHADING */ {
 828                NULL,
 829                preview_enable_drkframe,
 830        }, /* OMAP3ISP_PREV_NF */ {
 831                preview_config_noisefilter,
 832                preview_enable_noisefilter,
 833                offsetof(struct prev_params, nf),
 834                FIELD_SIZEOF(struct prev_params, nf),
 835                offsetof(struct omap3isp_prev_update_config, nf),
 836        }, /* OMAP3ISP_PREV_GAMMA */ {
 837                preview_config_gammacorrn,
 838                preview_enable_gammacorrn,
 839                offsetof(struct prev_params, gamma),
 840                FIELD_SIZEOF(struct prev_params, gamma),
 841                offsetof(struct omap3isp_prev_update_config, gamma),
 842        }, /* OMAP3ISP_PREV_CONTRAST */ {
 843                preview_config_contrast,
 844                NULL,
 845                0, 0, 0, true,
 846        }, /* OMAP3ISP_PREV_BRIGHTNESS */ {
 847                preview_config_brightness,
 848                NULL,
 849                0, 0, 0, true,
 850        },
 851};
 852
 853/*
 854 * preview_config - Copy and update local structure with userspace preview
 855 *                  configuration.
 856 * @prev: ISP preview engine
 857 * @cfg: Configuration
 858 *
 859 * Return zero if success or -EFAULT if the configuration can't be copied from
 860 * userspace.
 861 */
 862static int preview_config(struct isp_prev_device *prev,
 863                          struct omap3isp_prev_update_config *cfg)
 864{
 865        unsigned long flags;
 866        unsigned int i;
 867        int rval = 0;
 868        u32 update;
 869        u32 active;
 870
 871        if (cfg->update == 0)
 872                return 0;
 873
 874        /* Mark the shadow parameters we're going to update as busy. */
 875        spin_lock_irqsave(&prev->params.lock, flags);
 876        preview_params_lock(prev, cfg->update, true);
 877        active = prev->params.active;
 878        spin_unlock_irqrestore(&prev->params.lock, flags);
 879
 880        update = 0;
 881
 882        for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
 883                const struct preview_update *attr = &update_attrs[i];
 884                struct prev_params *params;
 885                unsigned int bit = 1 << i;
 886
 887                if (attr->skip || !(cfg->update & bit))
 888                        continue;
 889
 890                params = &prev->params.params[!!(active & bit)];
 891
 892                if (cfg->flag & bit) {
 893                        void __user *from = *(void * __user *)
 894                                ((void *)cfg + attr->config_offset);
 895                        void *to = (void *)params + attr->param_offset;
 896                        size_t size = attr->param_size;
 897
 898                        if (to && from && size) {
 899                                if (copy_from_user(to, from, size)) {
 900                                        rval = -EFAULT;
 901                                        break;
 902                                }
 903                        }
 904                        params->features |= bit;
 905                } else {
 906                        params->features &= ~bit;
 907                }
 908
 909                update |= bit;
 910        }
 911
 912        spin_lock_irqsave(&prev->params.lock, flags);
 913        preview_params_unlock(prev, update, true);
 914        preview_params_switch(prev);
 915        spin_unlock_irqrestore(&prev->params.lock, flags);
 916
 917        return rval;
 918}
 919
 920/*
 921 * preview_setup_hw - Setup preview registers and/or internal memory
 922 * @prev: pointer to preview private structure
 923 * @update: Bitmask of parameters to setup
 924 * @active: Bitmask of parameters active in set 0
 925 * Note: can be called from interrupt context
 926 * Return none
 927 */
 928static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
 929                             u32 active)
 930{
 931        unsigned int i;
 932
 933        if (update == 0)
 934                return;
 935
 936        for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
 937                const struct preview_update *attr = &update_attrs[i];
 938                struct prev_params *params;
 939                unsigned int bit = 1 << i;
 940
 941                if (!(update & bit))
 942                        continue;
 943
 944                params = &prev->params.params[!(active & bit)];
 945
 946                if (params->features & bit) {
 947                        if (attr->config)
 948                                attr->config(prev, params);
 949                        if (attr->enable)
 950                                attr->enable(prev, true);
 951                } else {
 952                        if (attr->enable)
 953                                attr->enable(prev, false);
 954                }
 955        }
 956}
 957
 958/*
 959 * preview_config_ycpos - Configure byte layout of YUV image.
 960 * @prev: pointer to previewer private structure
 961 * @pixelcode: pixel code
 962 */
 963static void preview_config_ycpos(struct isp_prev_device *prev, u32 pixelcode)
 964{
 965        struct isp_device *isp = to_isp_device(prev);
 966        enum preview_ycpos_mode mode;
 967
 968        switch (pixelcode) {
 969        case MEDIA_BUS_FMT_YUYV8_1X16:
 970                mode = YCPOS_CrYCbY;
 971                break;
 972        case MEDIA_BUS_FMT_UYVY8_1X16:
 973                mode = YCPOS_YCrYCb;
 974                break;
 975        default:
 976                return;
 977        }
 978
 979        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 980                        ISPPRV_PCR_YCPOS_CrYCbY,
 981                        mode << ISPPRV_PCR_YCPOS_SHIFT);
 982}
 983
 984/*
 985 * preview_config_averager - Enable / disable / configure averager
 986 * @average: Average value to be configured.
 987 */
 988static void preview_config_averager(struct isp_prev_device *prev, u8 average)
 989{
 990        struct isp_device *isp = to_isp_device(prev);
 991
 992        isp_reg_writel(isp, ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
 993                       ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
 994                       average, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
 995}
 996
 997
 998/*
 999 * preview_config_input_format - Configure the input format
1000 * @prev: The preview engine
1001 * @info: Sink pad format information
1002 *
1003 * Enable and configure CFA interpolation for Bayer formats and disable it for
1004 * greyscale formats.
1005 *
1006 * The CFA table is organised in four blocks, one per Bayer component. The
1007 * hardware expects blocks to follow the Bayer order of the input data, while
1008 * the driver stores the table in GRBG order in memory. The blocks need to be
1009 * reordered to support non-GRBG Bayer patterns.
1010 */
1011static void preview_config_input_format(struct isp_prev_device *prev,
1012                                        const struct isp_format_info *info)
1013{
1014        struct isp_device *isp = to_isp_device(prev);
1015        struct prev_params *params;
1016
1017        if (info->width == 8)
1018                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1019                            ISPPRV_PCR_WIDTH);
1020        else
1021                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1022                            ISPPRV_PCR_WIDTH);
1023
1024        switch (info->flavor) {
1025        case MEDIA_BUS_FMT_SGRBG8_1X8:
1026                prev->params.cfa_order = 0;
1027                break;
1028        case MEDIA_BUS_FMT_SRGGB8_1X8:
1029                prev->params.cfa_order = 1;
1030                break;
1031        case MEDIA_BUS_FMT_SBGGR8_1X8:
1032                prev->params.cfa_order = 2;
1033                break;
1034        case MEDIA_BUS_FMT_SGBRG8_1X8:
1035                prev->params.cfa_order = 3;
1036                break;
1037        default:
1038                /* Disable CFA for non-Bayer formats. */
1039                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1040                            ISPPRV_PCR_CFAEN);
1041                return;
1042        }
1043
1044        isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_CFAEN);
1045        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1046                        ISPPRV_PCR_CFAFMT_MASK, ISPPRV_PCR_CFAFMT_BAYER);
1047
1048        params = (prev->params.active & OMAP3ISP_PREV_CFA)
1049               ? &prev->params.params[0] : &prev->params.params[1];
1050
1051        preview_config_cfa(prev, params);
1052}
1053
1054/*
1055 * preview_config_input_size - Configure the input frame size
1056 *
1057 * The preview engine crops several rows and columns internally depending on
1058 * which processing blocks are enabled. The driver assumes all those blocks are
1059 * enabled when reporting source pad formats to userspace. If this assumption is
1060 * not true, rows and columns must be manually cropped at the preview engine
1061 * input to avoid overflows at the end of lines and frames.
1062 *
1063 * See the explanation at the PREV_MARGIN_* definitions for more details.
1064 */
1065static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
1066{
1067        const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
1068        struct isp_device *isp = to_isp_device(prev);
1069        unsigned int sph = prev->crop.left;
1070        unsigned int eph = prev->crop.left + prev->crop.width - 1;
1071        unsigned int slv = prev->crop.top;
1072        unsigned int elv = prev->crop.top + prev->crop.height - 1;
1073        u32 features;
1074
1075        if (format->code != MEDIA_BUS_FMT_Y8_1X8 &&
1076            format->code != MEDIA_BUS_FMT_Y10_1X10) {
1077                sph -= 2;
1078                eph += 2;
1079                slv -= 2;
1080                elv += 2;
1081        }
1082
1083        features = (prev->params.params[0].features & active)
1084                 | (prev->params.params[1].features & ~active);
1085
1086        if (features & (OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF)) {
1087                sph -= 2;
1088                eph += 2;
1089                slv -= 2;
1090                elv += 2;
1091        }
1092        if (features & OMAP3ISP_PREV_HRZ_MED) {
1093                sph -= 2;
1094                eph += 2;
1095        }
1096        if (features & (OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH))
1097                sph -= 2;
1098
1099        isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
1100                       OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
1101        isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv,
1102                       OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
1103}
1104
1105/*
1106 * preview_config_inlineoffset - Configures the Read address line offset.
1107 * @prev: Preview module
1108 * @offset: Line offset
1109 *
1110 * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
1111 * However, a hardware bug requires the memory start address to be aligned on a
1112 * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
1113 * well.
1114 */
1115static void
1116preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
1117{
1118        struct isp_device *isp = to_isp_device(prev);
1119
1120        isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
1121                       ISPPRV_RADR_OFFSET);
1122}
1123
1124/*
1125 * preview_set_inaddr - Sets memory address of input frame.
1126 * @addr: 32bit memory address aligned on 32byte boundary.
1127 *
1128 * Configures the memory address from which the input frame is to be read.
1129 */
1130static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr)
1131{
1132        struct isp_device *isp = to_isp_device(prev);
1133
1134        isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
1135}
1136
1137/*
1138 * preview_config_outlineoffset - Configures the Write address line offset.
1139 * @offset: Line Offset for the preview output.
1140 *
1141 * The offset must be a multiple of 32 bytes.
1142 */
1143static void preview_config_outlineoffset(struct isp_prev_device *prev,
1144                                    u32 offset)
1145{
1146        struct isp_device *isp = to_isp_device(prev);
1147
1148        isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
1149                       ISPPRV_WADD_OFFSET);
1150}
1151
1152/*
1153 * preview_set_outaddr - Sets the memory address to store output frame
1154 * @addr: 32bit memory address aligned on 32byte boundary.
1155 *
1156 * Configures the memory address to which the output frame is written.
1157 */
1158static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr)
1159{
1160        struct isp_device *isp = to_isp_device(prev);
1161
1162        isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
1163}
1164
1165static void preview_adjust_bandwidth(struct isp_prev_device *prev)
1166{
1167        struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
1168        struct isp_device *isp = to_isp_device(prev);
1169        const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK];
1170        unsigned long l3_ick = pipe->l3_ick;
1171        struct v4l2_fract *timeperframe;
1172        unsigned int cycles_per_frame;
1173        unsigned int requests_per_frame;
1174        unsigned int cycles_per_request;
1175        unsigned int minimum;
1176        unsigned int maximum;
1177        unsigned int value;
1178
1179        if (prev->input != PREVIEW_INPUT_MEMORY) {
1180                isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
1181                            ISPSBL_SDR_REQ_PRV_EXP_MASK);
1182                return;
1183        }
1184
1185        /* Compute the minimum number of cycles per request, based on the
1186         * pipeline maximum data rate. This is an absolute lower bound if we
1187         * don't want SBL overflows, so round the value up.
1188         */
1189        cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
1190                                     pipe->max_rate);
1191        minimum = DIV_ROUND_UP(cycles_per_request, 32);
1192
1193        /* Compute the maximum number of cycles per request, based on the
1194         * requested frame rate. This is a soft upper bound to achieve a frame
1195         * rate equal or higher than the requested value, so round the value
1196         * down.
1197         */
1198        timeperframe = &pipe->max_timeperframe;
1199
1200        requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height;
1201        cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
1202                                   timeperframe->denominator);
1203        cycles_per_request = cycles_per_frame / requests_per_frame;
1204
1205        maximum = cycles_per_request / 32;
1206
1207        value = max(minimum, maximum);
1208
1209        dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
1210        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
1211                        ISPSBL_SDR_REQ_PRV_EXP_MASK,
1212                        value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT);
1213}
1214
1215/*
1216 * omap3isp_preview_busy - Gets busy state of preview module.
1217 */
1218int omap3isp_preview_busy(struct isp_prev_device *prev)
1219{
1220        struct isp_device *isp = to_isp_device(prev);
1221
1222        return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
1223                & ISPPRV_PCR_BUSY;
1224}
1225
1226/*
1227 * omap3isp_preview_restore_context - Restores the values of preview registers
1228 */
1229void omap3isp_preview_restore_context(struct isp_device *isp)
1230{
1231        struct isp_prev_device *prev = &isp->isp_prev;
1232        const u32 update = OMAP3ISP_PREV_FEATURES_END - 1;
1233
1234        prev->params.params[0].update = prev->params.active & update;
1235        prev->params.params[1].update = ~prev->params.active & update;
1236
1237        preview_setup_hw(prev, update, prev->params.active);
1238
1239        prev->params.params[0].update = 0;
1240        prev->params.params[1].update = 0;
1241}
1242
1243/*
1244 * preview_print_status - Dump preview module registers to the kernel log
1245 */
1246#define PREV_PRINT_REGISTER(isp, name)\
1247        dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
1248                isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
1249
1250static void preview_print_status(struct isp_prev_device *prev)
1251{
1252        struct isp_device *isp = to_isp_device(prev);
1253
1254        dev_dbg(isp->dev, "-------------Preview Register dump----------\n");
1255
1256        PREV_PRINT_REGISTER(isp, PCR);
1257        PREV_PRINT_REGISTER(isp, HORZ_INFO);
1258        PREV_PRINT_REGISTER(isp, VERT_INFO);
1259        PREV_PRINT_REGISTER(isp, RSDR_ADDR);
1260        PREV_PRINT_REGISTER(isp, RADR_OFFSET);
1261        PREV_PRINT_REGISTER(isp, DSDR_ADDR);
1262        PREV_PRINT_REGISTER(isp, DRKF_OFFSET);
1263        PREV_PRINT_REGISTER(isp, WSDR_ADDR);
1264        PREV_PRINT_REGISTER(isp, WADD_OFFSET);
1265        PREV_PRINT_REGISTER(isp, AVE);
1266        PREV_PRINT_REGISTER(isp, HMED);
1267        PREV_PRINT_REGISTER(isp, NF);
1268        PREV_PRINT_REGISTER(isp, WB_DGAIN);
1269        PREV_PRINT_REGISTER(isp, WBGAIN);
1270        PREV_PRINT_REGISTER(isp, WBSEL);
1271        PREV_PRINT_REGISTER(isp, CFA);
1272        PREV_PRINT_REGISTER(isp, BLKADJOFF);
1273        PREV_PRINT_REGISTER(isp, RGB_MAT1);
1274        PREV_PRINT_REGISTER(isp, RGB_MAT2);
1275        PREV_PRINT_REGISTER(isp, RGB_MAT3);
1276        PREV_PRINT_REGISTER(isp, RGB_MAT4);
1277        PREV_PRINT_REGISTER(isp, RGB_MAT5);
1278        PREV_PRINT_REGISTER(isp, RGB_OFF1);
1279        PREV_PRINT_REGISTER(isp, RGB_OFF2);
1280        PREV_PRINT_REGISTER(isp, CSC0);
1281        PREV_PRINT_REGISTER(isp, CSC1);
1282        PREV_PRINT_REGISTER(isp, CSC2);
1283        PREV_PRINT_REGISTER(isp, CSC_OFFSET);
1284        PREV_PRINT_REGISTER(isp, CNT_BRT);
1285        PREV_PRINT_REGISTER(isp, CSUP);
1286        PREV_PRINT_REGISTER(isp, SETUP_YC);
1287        PREV_PRINT_REGISTER(isp, SET_TBL_ADDR);
1288        PREV_PRINT_REGISTER(isp, CDC_THR0);
1289        PREV_PRINT_REGISTER(isp, CDC_THR1);
1290        PREV_PRINT_REGISTER(isp, CDC_THR2);
1291        PREV_PRINT_REGISTER(isp, CDC_THR3);
1292
1293        dev_dbg(isp->dev, "--------------------------------------------\n");
1294}
1295
1296/*
1297 * preview_init_params - init image processing parameters.
1298 * @prev: pointer to previewer private structure
1299 */
1300static void preview_init_params(struct isp_prev_device *prev)
1301{
1302        struct prev_params *params;
1303        unsigned int i;
1304
1305        spin_lock_init(&prev->params.lock);
1306
1307        prev->params.active = ~0;
1308        prev->params.params[0].busy = 0;
1309        prev->params.params[0].update = OMAP3ISP_PREV_FEATURES_END - 1;
1310        prev->params.params[1].busy = 0;
1311        prev->params.params[1].update = 0;
1312
1313        params = &prev->params.params[0];
1314
1315        /* Init values */
1316        params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
1317        params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS;
1318        params->cfa.format = OMAP3ISP_CFAFMT_BAYER;
1319        memcpy(params->cfa.table, cfa_coef_table,
1320               sizeof(params->cfa.table));
1321        params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
1322        params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT;
1323        params->csup.gain = FLR_CSUP_GAIN;
1324        params->csup.thres = FLR_CSUP_THRES;
1325        params->csup.hypf_en = 0;
1326        memcpy(params->luma.table, luma_enhance_table,
1327               sizeof(params->luma.table));
1328        params->nf.spread = FLR_NF_STRGTH;
1329        memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
1330        params->dcor.couplet_mode_en = 1;
1331        for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++)
1332                params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL;
1333        memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue));
1334        memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green));
1335        memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red));
1336        params->wbal.dgain = FLR_WBAL_DGAIN;
1337        params->wbal.coef0 = FLR_WBAL_COEF;
1338        params->wbal.coef1 = FLR_WBAL_COEF;
1339        params->wbal.coef2 = FLR_WBAL_COEF;
1340        params->wbal.coef3 = FLR_WBAL_COEF;
1341        params->blkadj.red = FLR_BLKADJ_RED;
1342        params->blkadj.green = FLR_BLKADJ_GREEN;
1343        params->blkadj.blue = FLR_BLKADJ_BLUE;
1344        params->rgb2rgb = flr_rgb2rgb;
1345        params->csc = flr_prev_csc;
1346        params->yclimit.minC = ISPPRV_YC_MIN;
1347        params->yclimit.maxC = ISPPRV_YC_MAX;
1348        params->yclimit.minY = ISPPRV_YC_MIN;
1349        params->yclimit.maxY = ISPPRV_YC_MAX;
1350
1351        params->features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR
1352                         | OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA
1353                         | OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT
1354                         | OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV
1355                         | OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS
1356                         | OMAP3ISP_PREV_CONTRAST;
1357}
1358
1359/*
1360 * preview_max_out_width - Handle previewer hardware output limitations
1361 * @prev: pointer to previewer private structure
1362 * returns maximum width output for current isp revision
1363 */
1364static unsigned int preview_max_out_width(struct isp_prev_device *prev)
1365{
1366        struct isp_device *isp = to_isp_device(prev);
1367
1368        switch (isp->revision) {
1369        case ISP_REVISION_1_0:
1370                return PREV_MAX_OUT_WIDTH_REV_1;
1371
1372        case ISP_REVISION_2_0:
1373        default:
1374                return PREV_MAX_OUT_WIDTH_REV_2;
1375
1376        case ISP_REVISION_15_0:
1377                return PREV_MAX_OUT_WIDTH_REV_15;
1378        }
1379}
1380
1381static void preview_configure(struct isp_prev_device *prev)
1382{
1383        struct isp_device *isp = to_isp_device(prev);
1384        const struct isp_format_info *info;
1385        struct v4l2_mbus_framefmt *format;
1386        unsigned long flags;
1387        u32 update;
1388        u32 active;
1389
1390        spin_lock_irqsave(&prev->params.lock, flags);
1391        /* Mark all active parameters we are going to touch as busy. */
1392        update = preview_params_lock(prev, 0, false);
1393        active = prev->params.active;
1394        spin_unlock_irqrestore(&prev->params.lock, flags);
1395
1396        /* PREV_PAD_SINK */
1397        format = &prev->formats[PREV_PAD_SINK];
1398        info = omap3isp_video_format_info(format->code);
1399
1400        preview_adjust_bandwidth(prev);
1401
1402        preview_config_input_format(prev, info);
1403        preview_config_input_size(prev, active);
1404
1405        if (prev->input == PREVIEW_INPUT_CCDC)
1406                preview_config_inlineoffset(prev, 0);
1407        else
1408                preview_config_inlineoffset(prev, ALIGN(format->width, 0x20) *
1409                                            info->bpp);
1410
1411        preview_setup_hw(prev, update, active);
1412
1413        /* PREV_PAD_SOURCE */
1414        format = &prev->formats[PREV_PAD_SOURCE];
1415
1416        if (prev->output & PREVIEW_OUTPUT_MEMORY)
1417                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1418                            ISPPRV_PCR_SDRPORT);
1419        else
1420                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1421                            ISPPRV_PCR_SDRPORT);
1422
1423        if (prev->output & PREVIEW_OUTPUT_RESIZER)
1424                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1425                            ISPPRV_PCR_RSZPORT);
1426        else
1427                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1428                            ISPPRV_PCR_RSZPORT);
1429
1430        if (prev->output & PREVIEW_OUTPUT_MEMORY)
1431                preview_config_outlineoffset(prev,
1432                                ALIGN(format->width, 0x10) * 2);
1433
1434        preview_config_averager(prev, 0);
1435        preview_config_ycpos(prev, format->code);
1436
1437        spin_lock_irqsave(&prev->params.lock, flags);
1438        preview_params_unlock(prev, update, false);
1439        spin_unlock_irqrestore(&prev->params.lock, flags);
1440}
1441
1442/* -----------------------------------------------------------------------------
1443 * Interrupt handling
1444 */
1445
1446static void preview_enable_oneshot(struct isp_prev_device *prev)
1447{
1448        struct isp_device *isp = to_isp_device(prev);
1449
1450        /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
1451         * bit is set. As the preview engine is used in single-shot mode, we
1452         * need to set PCR.SOURCE before enabling the preview engine.
1453         */
1454        if (prev->input == PREVIEW_INPUT_MEMORY)
1455                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1456                            ISPPRV_PCR_SOURCE);
1457
1458        isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1459                    ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
1460}
1461
1462void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
1463{
1464        /*
1465         * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
1466         * condition, the module was paused and now we have a buffer queued
1467         * on the output again. Restart the pipeline if running in continuous
1468         * mode.
1469         */
1470        if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
1471            prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1472                preview_enable_oneshot(prev);
1473                isp_video_dmaqueue_flags_clr(&prev->video_out);
1474        }
1475}
1476
1477static void preview_isr_buffer(struct isp_prev_device *prev)
1478{
1479        struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
1480        struct isp_buffer *buffer;
1481        int restart = 0;
1482
1483        if (prev->output & PREVIEW_OUTPUT_MEMORY) {
1484                buffer = omap3isp_video_buffer_next(&prev->video_out);
1485                if (buffer != NULL) {
1486                        preview_set_outaddr(prev, buffer->dma);
1487                        restart = 1;
1488                }
1489                pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
1490        }
1491
1492        if (prev->input == PREVIEW_INPUT_MEMORY) {
1493                buffer = omap3isp_video_buffer_next(&prev->video_in);
1494                if (buffer != NULL)
1495                        preview_set_inaddr(prev, buffer->dma);
1496                pipe->state |= ISP_PIPELINE_IDLE_INPUT;
1497        }
1498
1499        switch (prev->state) {
1500        case ISP_PIPELINE_STREAM_SINGLESHOT:
1501                if (isp_pipeline_ready(pipe))
1502                        omap3isp_pipeline_set_stream(pipe,
1503                                                ISP_PIPELINE_STREAM_SINGLESHOT);
1504                break;
1505
1506        case ISP_PIPELINE_STREAM_CONTINUOUS:
1507                /* If an underrun occurs, the video queue operation handler will
1508                 * restart the preview engine. Otherwise restart it immediately.
1509                 */
1510                if (restart)
1511                        preview_enable_oneshot(prev);
1512                break;
1513
1514        case ISP_PIPELINE_STREAM_STOPPED:
1515        default:
1516                return;
1517        }
1518}
1519
1520/*
1521 * omap3isp_preview_isr - ISP preview engine interrupt handler
1522 *
1523 * Manage the preview engine video buffers and configure shadowed registers.
1524 */
1525void omap3isp_preview_isr(struct isp_prev_device *prev)
1526{
1527        unsigned long flags;
1528        u32 update;
1529        u32 active;
1530
1531        if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
1532                return;
1533
1534        spin_lock_irqsave(&prev->params.lock, flags);
1535        preview_params_switch(prev);
1536        update = preview_params_lock(prev, 0, false);
1537        active = prev->params.active;
1538        spin_unlock_irqrestore(&prev->params.lock, flags);
1539
1540        preview_setup_hw(prev, update, active);
1541        preview_config_input_size(prev, active);
1542
1543        if (prev->input == PREVIEW_INPUT_MEMORY ||
1544            prev->output & PREVIEW_OUTPUT_MEMORY)
1545                preview_isr_buffer(prev);
1546        else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
1547                preview_enable_oneshot(prev);
1548
1549        spin_lock_irqsave(&prev->params.lock, flags);
1550        preview_params_unlock(prev, update, false);
1551        spin_unlock_irqrestore(&prev->params.lock, flags);
1552}
1553
1554/* -----------------------------------------------------------------------------
1555 * ISP video operations
1556 */
1557
1558static int preview_video_queue(struct isp_video *video,
1559                               struct isp_buffer *buffer)
1560{
1561        struct isp_prev_device *prev = &video->isp->isp_prev;
1562
1563        if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1564                preview_set_inaddr(prev, buffer->dma);
1565
1566        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1567                preview_set_outaddr(prev, buffer->dma);
1568
1569        return 0;
1570}
1571
1572static const struct isp_video_operations preview_video_ops = {
1573        .queue = preview_video_queue,
1574};
1575
1576/* -----------------------------------------------------------------------------
1577 * V4L2 subdev operations
1578 */
1579
1580/*
1581 * preview_s_ctrl - Handle set control subdev method
1582 * @ctrl: pointer to v4l2 control structure
1583 */
1584static int preview_s_ctrl(struct v4l2_ctrl *ctrl)
1585{
1586        struct isp_prev_device *prev =
1587                container_of(ctrl->handler, struct isp_prev_device, ctrls);
1588
1589        switch (ctrl->id) {
1590        case V4L2_CID_BRIGHTNESS:
1591                preview_update_brightness(prev, ctrl->val);
1592                break;
1593        case V4L2_CID_CONTRAST:
1594                preview_update_contrast(prev, ctrl->val);
1595                break;
1596        }
1597
1598        return 0;
1599}
1600
1601static const struct v4l2_ctrl_ops preview_ctrl_ops = {
1602        .s_ctrl = preview_s_ctrl,
1603};
1604
1605/*
1606 * preview_ioctl - Handle preview module private ioctl's
1607 * @sd: pointer to v4l2 subdev structure
1608 * @cmd: configuration command
1609 * @arg: configuration argument
1610 * return -EINVAL or zero on success
1611 */
1612static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
1613{
1614        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1615
1616        switch (cmd) {
1617        case VIDIOC_OMAP3ISP_PRV_CFG:
1618                return preview_config(prev, arg);
1619
1620        default:
1621                return -ENOIOCTLCMD;
1622        }
1623}
1624
1625/*
1626 * preview_set_stream - Enable/Disable streaming on preview subdev
1627 * @sd    : pointer to v4l2 subdev structure
1628 * @enable: 1 == Enable, 0 == Disable
1629 * return -EINVAL or zero on success
1630 */
1631static int preview_set_stream(struct v4l2_subdev *sd, int enable)
1632{
1633        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1634        struct isp_video *video_out = &prev->video_out;
1635        struct isp_device *isp = to_isp_device(prev);
1636        struct device *dev = to_device(prev);
1637
1638        if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
1639                if (enable == ISP_PIPELINE_STREAM_STOPPED)
1640                        return 0;
1641
1642                omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
1643                preview_configure(prev);
1644                atomic_set(&prev->stopping, 0);
1645                preview_print_status(prev);
1646        }
1647
1648        switch (enable) {
1649        case ISP_PIPELINE_STREAM_CONTINUOUS:
1650                if (prev->output & PREVIEW_OUTPUT_MEMORY)
1651                        omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
1652
1653                if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
1654                    !(prev->output & PREVIEW_OUTPUT_MEMORY))
1655                        preview_enable_oneshot(prev);
1656
1657                isp_video_dmaqueue_flags_clr(video_out);
1658                break;
1659
1660        case ISP_PIPELINE_STREAM_SINGLESHOT:
1661                if (prev->input == PREVIEW_INPUT_MEMORY)
1662                        omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
1663                if (prev->output & PREVIEW_OUTPUT_MEMORY)
1664                        omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
1665
1666                preview_enable_oneshot(prev);
1667                break;
1668
1669        case ISP_PIPELINE_STREAM_STOPPED:
1670                if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
1671                                              &prev->stopping))
1672                        dev_dbg(dev, "%s: stop timeout.\n", sd->name);
1673                omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
1674                omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
1675                omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
1676                isp_video_dmaqueue_flags_clr(video_out);
1677                break;
1678        }
1679
1680        prev->state = enable;
1681        return 0;
1682}
1683
1684static struct v4l2_mbus_framefmt *
1685__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
1686                     unsigned int pad, enum v4l2_subdev_format_whence which)
1687{
1688        if (which == V4L2_SUBDEV_FORMAT_TRY)
1689                return v4l2_subdev_get_try_format(&prev->subdev, cfg, pad);
1690        else
1691                return &prev->formats[pad];
1692}
1693
1694static struct v4l2_rect *
1695__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
1696                   enum v4l2_subdev_format_whence which)
1697{
1698        if (which == V4L2_SUBDEV_FORMAT_TRY)
1699                return v4l2_subdev_get_try_crop(&prev->subdev, cfg, PREV_PAD_SINK);
1700        else
1701                return &prev->crop;
1702}
1703
1704/* previewer format descriptions */
1705static const unsigned int preview_input_fmts[] = {
1706        MEDIA_BUS_FMT_Y8_1X8,
1707        MEDIA_BUS_FMT_SGRBG8_1X8,
1708        MEDIA_BUS_FMT_SRGGB8_1X8,
1709        MEDIA_BUS_FMT_SBGGR8_1X8,
1710        MEDIA_BUS_FMT_SGBRG8_1X8,
1711        MEDIA_BUS_FMT_Y10_1X10,
1712        MEDIA_BUS_FMT_SGRBG10_1X10,
1713        MEDIA_BUS_FMT_SRGGB10_1X10,
1714        MEDIA_BUS_FMT_SBGGR10_1X10,
1715        MEDIA_BUS_FMT_SGBRG10_1X10,
1716};
1717
1718static const unsigned int preview_output_fmts[] = {
1719        MEDIA_BUS_FMT_UYVY8_1X16,
1720        MEDIA_BUS_FMT_YUYV8_1X16,
1721};
1722
1723/*
1724 * preview_try_format - Validate a format
1725 * @prev: ISP preview engine
1726 * @cfg: V4L2 subdev pad configuration
1727 * @pad: pad number
1728 * @fmt: format to be validated
1729 * @which: try/active format selector
1730 *
1731 * Validate and adjust the given format for the given pad based on the preview
1732 * engine limits and the format and crop rectangles on other pads.
1733 */
1734static void preview_try_format(struct isp_prev_device *prev,
1735                               struct v4l2_subdev_pad_config *cfg, unsigned int pad,
1736                               struct v4l2_mbus_framefmt *fmt,
1737                               enum v4l2_subdev_format_whence which)
1738{
1739        u32 pixelcode;
1740        struct v4l2_rect *crop;
1741        unsigned int i;
1742
1743        switch (pad) {
1744        case PREV_PAD_SINK:
1745                /* When reading data from the CCDC, the input size has already
1746                 * been mangled by the CCDC output pad so it can be accepted
1747                 * as-is.
1748                 *
1749                 * When reading data from memory, clamp the requested width and
1750                 * height. The TRM doesn't specify a minimum input height, make
1751                 * sure we got enough lines to enable the noise filter and color
1752                 * filter array interpolation.
1753                 */
1754                if (prev->input == PREVIEW_INPUT_MEMORY) {
1755                        fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH,
1756                                             preview_max_out_width(prev));
1757                        fmt->height = clamp_t(u32, fmt->height,
1758                                              PREV_MIN_IN_HEIGHT,
1759                                              PREV_MAX_IN_HEIGHT);
1760                }
1761
1762                fmt->colorspace = V4L2_COLORSPACE_SRGB;
1763
1764                for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) {
1765                        if (fmt->code == preview_input_fmts[i])
1766                                break;
1767                }
1768
1769                /* If not found, use SGRBG10 as default */
1770                if (i >= ARRAY_SIZE(preview_input_fmts))
1771                        fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
1772                break;
1773
1774        case PREV_PAD_SOURCE:
1775                pixelcode = fmt->code;
1776                *fmt = *__preview_get_format(prev, cfg, PREV_PAD_SINK, which);
1777
1778                switch (pixelcode) {
1779                case MEDIA_BUS_FMT_YUYV8_1X16:
1780                case MEDIA_BUS_FMT_UYVY8_1X16:
1781                        fmt->code = pixelcode;
1782                        break;
1783
1784                default:
1785                        fmt->code = MEDIA_BUS_FMT_YUYV8_1X16;
1786                        break;
1787                }
1788
1789                /* The preview module output size is configurable through the
1790                 * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This
1791                 * is not supported yet, hardcode the output size to the crop
1792                 * rectangle size.
1793                 */
1794                crop = __preview_get_crop(prev, cfg, which);
1795                fmt->width = crop->width;
1796                fmt->height = crop->height;
1797
1798                fmt->colorspace = V4L2_COLORSPACE_JPEG;
1799                break;
1800        }
1801
1802        fmt->field = V4L2_FIELD_NONE;
1803}
1804
1805/*
1806 * preview_try_crop - Validate a crop rectangle
1807 * @prev: ISP preview engine
1808 * @sink: format on the sink pad
1809 * @crop: crop rectangle to be validated
1810 *
1811 * The preview engine crops lines and columns for its internal operation,
1812 * depending on which filters are enabled. Enforce minimum crop margins to
1813 * handle that transparently for userspace.
1814 *
1815 * See the explanation at the PREV_MARGIN_* definitions for more details.
1816 */
1817static void preview_try_crop(struct isp_prev_device *prev,
1818                             const struct v4l2_mbus_framefmt *sink,
1819                             struct v4l2_rect *crop)
1820{
1821        unsigned int left = PREV_MARGIN_LEFT;
1822        unsigned int right = sink->width - PREV_MARGIN_RIGHT;
1823        unsigned int top = PREV_MARGIN_TOP;
1824        unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM;
1825
1826        /* When processing data on-the-fly from the CCDC, at least 2 pixels must
1827         * be cropped from the left and right sides of the image. As we don't
1828         * know which filters will be enabled, increase the left and right
1829         * margins by two.
1830         */
1831        if (prev->input == PREVIEW_INPUT_CCDC) {
1832                left += 2;
1833                right -= 2;
1834        }
1835
1836        /* The CFA filter crops 4 lines and 4 columns in Bayer mode, and 2 lines
1837         * and no columns in other modes. Increase the margins based on the sink
1838         * format.
1839         */
1840        if (sink->code != MEDIA_BUS_FMT_Y8_1X8 &&
1841            sink->code != MEDIA_BUS_FMT_Y10_1X10) {
1842                left += 2;
1843                right -= 2;
1844                top += 2;
1845                bottom -= 2;
1846        }
1847
1848        /* Restrict left/top to even values to keep the Bayer pattern. */
1849        crop->left &= ~1;
1850        crop->top &= ~1;
1851
1852        crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH);
1853        crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT);
1854        crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH,
1855                              right - crop->left);
1856        crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT,
1857                               bottom - crop->top);
1858}
1859
1860/*
1861 * preview_enum_mbus_code - Handle pixel format enumeration
1862 * @sd     : pointer to v4l2 subdev structure
1863 * @cfg: V4L2 subdev pad configuration
1864 * @code   : pointer to v4l2_subdev_mbus_code_enum structure
1865 * return -EINVAL or zero on success
1866 */
1867static int preview_enum_mbus_code(struct v4l2_subdev *sd,
1868                                  struct v4l2_subdev_pad_config *cfg,
1869                                  struct v4l2_subdev_mbus_code_enum *code)
1870{
1871        switch (code->pad) {
1872        case PREV_PAD_SINK:
1873                if (code->index >= ARRAY_SIZE(preview_input_fmts))
1874                        return -EINVAL;
1875
1876                code->code = preview_input_fmts[code->index];
1877                break;
1878        case PREV_PAD_SOURCE:
1879                if (code->index >= ARRAY_SIZE(preview_output_fmts))
1880                        return -EINVAL;
1881
1882                code->code = preview_output_fmts[code->index];
1883                break;
1884        default:
1885                return -EINVAL;
1886        }
1887
1888        return 0;
1889}
1890
1891static int preview_enum_frame_size(struct v4l2_subdev *sd,
1892                                   struct v4l2_subdev_pad_config *cfg,
1893                                   struct v4l2_subdev_frame_size_enum *fse)
1894{
1895        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1896        struct v4l2_mbus_framefmt format;
1897
1898        if (fse->index != 0)
1899                return -EINVAL;
1900
1901        format.code = fse->code;
1902        format.width = 1;
1903        format.height = 1;
1904        preview_try_format(prev, cfg, fse->pad, &format, fse->which);
1905        fse->min_width = format.width;
1906        fse->min_height = format.height;
1907
1908        if (format.code != fse->code)
1909                return -EINVAL;
1910
1911        format.code = fse->code;
1912        format.width = -1;
1913        format.height = -1;
1914        preview_try_format(prev, cfg, fse->pad, &format, fse->which);
1915        fse->max_width = format.width;
1916        fse->max_height = format.height;
1917
1918        return 0;
1919}
1920
1921/*
1922 * preview_get_selection - Retrieve a selection rectangle on a pad
1923 * @sd: ISP preview V4L2 subdevice
1924 * @cfg: V4L2 subdev pad configuration
1925 * @sel: Selection rectangle
1926 *
1927 * The only supported rectangles are the crop rectangles on the sink pad.
1928 *
1929 * Return 0 on success or a negative error code otherwise.
1930 */
1931static int preview_get_selection(struct v4l2_subdev *sd,
1932                                 struct v4l2_subdev_pad_config *cfg,
1933                                 struct v4l2_subdev_selection *sel)
1934{
1935        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1936        struct v4l2_mbus_framefmt *format;
1937
1938        if (sel->pad != PREV_PAD_SINK)
1939                return -EINVAL;
1940
1941        switch (sel->target) {
1942        case V4L2_SEL_TGT_CROP_BOUNDS:
1943                sel->r.left = 0;
1944                sel->r.top = 0;
1945                sel->r.width = INT_MAX;
1946                sel->r.height = INT_MAX;
1947
1948                format = __preview_get_format(prev, cfg, PREV_PAD_SINK,
1949                                              sel->which);
1950                preview_try_crop(prev, format, &sel->r);
1951                break;
1952
1953        case V4L2_SEL_TGT_CROP:
1954                sel->r = *__preview_get_crop(prev, cfg, sel->which);
1955                break;
1956
1957        default:
1958                return -EINVAL;
1959        }
1960
1961        return 0;
1962}
1963
1964/*
1965 * preview_set_selection - Set a selection rectangle on a pad
1966 * @sd: ISP preview V4L2 subdevice
1967 * @cfg: V4L2 subdev pad configuration
1968 * @sel: Selection rectangle
1969 *
1970 * The only supported rectangle is the actual crop rectangle on the sink pad.
1971 *
1972 * Return 0 on success or a negative error code otherwise.
1973 */
1974static int preview_set_selection(struct v4l2_subdev *sd,
1975                                 struct v4l2_subdev_pad_config *cfg,
1976                                 struct v4l2_subdev_selection *sel)
1977{
1978        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1979        struct v4l2_mbus_framefmt *format;
1980
1981        if (sel->target != V4L2_SEL_TGT_CROP ||
1982            sel->pad != PREV_PAD_SINK)
1983                return -EINVAL;
1984
1985        /* The crop rectangle can't be changed while streaming. */
1986        if (prev->state != ISP_PIPELINE_STREAM_STOPPED)
1987                return -EBUSY;
1988
1989        /* Modifying the crop rectangle always changes the format on the source
1990         * pad. If the KEEP_CONFIG flag is set, just return the current crop
1991         * rectangle.
1992         */
1993        if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
1994                sel->r = *__preview_get_crop(prev, cfg, sel->which);
1995                return 0;
1996        }
1997
1998        format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which);
1999        preview_try_crop(prev, format, &sel->r);
2000        *__preview_get_crop(prev, cfg, sel->which) = sel->r;
2001
2002        /* Update the source format. */
2003        format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, sel->which);
2004        preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, sel->which);
2005
2006        return 0;
2007}
2008
2009/*
2010 * preview_get_format - Handle get format by pads subdev method
2011 * @sd : pointer to v4l2 subdev structure
2012 * @cfg: V4L2 subdev pad configuration
2013 * @fmt: pointer to v4l2 subdev format structure
2014 * return -EINVAL or zero on success
2015 */
2016static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
2017                              struct v4l2_subdev_format *fmt)
2018{
2019        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
2020        struct v4l2_mbus_framefmt *format;
2021
2022        format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
2023        if (format == NULL)
2024                return -EINVAL;
2025
2026        fmt->format = *format;
2027        return 0;
2028}
2029
2030/*
2031 * preview_set_format - Handle set format by pads subdev method
2032 * @sd : pointer to v4l2 subdev structure
2033 * @cfg: V4L2 subdev pad configuration
2034 * @fmt: pointer to v4l2 subdev format structure
2035 * return -EINVAL or zero on success
2036 */
2037static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
2038                              struct v4l2_subdev_format *fmt)
2039{
2040        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
2041        struct v4l2_mbus_framefmt *format;
2042        struct v4l2_rect *crop;
2043
2044        format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
2045        if (format == NULL)
2046                return -EINVAL;
2047
2048        preview_try_format(prev, cfg, fmt->pad, &fmt->format, fmt->which);
2049        *format = fmt->format;
2050
2051        /* Propagate the format from sink to source */
2052        if (fmt->pad == PREV_PAD_SINK) {
2053                /* Reset the crop rectangle. */
2054                crop = __preview_get_crop(prev, cfg, fmt->which);
2055                crop->left = 0;
2056                crop->top = 0;
2057                crop->width = fmt->format.width;
2058                crop->height = fmt->format.height;
2059
2060                preview_try_crop(prev, &fmt->format, crop);
2061
2062                /* Update the source format. */
2063                format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE,
2064                                              fmt->which);
2065                preview_try_format(prev, cfg, PREV_PAD_SOURCE, format,
2066                                   fmt->which);
2067        }
2068
2069        return 0;
2070}
2071
2072/*
2073 * preview_init_formats - Initialize formats on all pads
2074 * @sd: ISP preview V4L2 subdevice
2075 * @fh: V4L2 subdev file handle
2076 *
2077 * Initialize all pad formats with default values. If fh is not NULL, try
2078 * formats are initialized on the file handle. Otherwise active formats are
2079 * initialized on the device.
2080 */
2081static int preview_init_formats(struct v4l2_subdev *sd,
2082                                struct v4l2_subdev_fh *fh)
2083{
2084        struct v4l2_subdev_format format;
2085
2086        memset(&format, 0, sizeof(format));
2087        format.pad = PREV_PAD_SINK;
2088        format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
2089        format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
2090        format.format.width = 4096;
2091        format.format.height = 4096;
2092        preview_set_format(sd, fh ? fh->pad : NULL, &format);
2093
2094        return 0;
2095}
2096
2097/* subdev core operations */
2098static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
2099        .ioctl = preview_ioctl,
2100};
2101
2102/* subdev video operations */
2103static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
2104        .s_stream = preview_set_stream,
2105};
2106
2107/* subdev pad operations */
2108static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
2109        .enum_mbus_code = preview_enum_mbus_code,
2110        .enum_frame_size = preview_enum_frame_size,
2111        .get_fmt = preview_get_format,
2112        .set_fmt = preview_set_format,
2113        .get_selection = preview_get_selection,
2114        .set_selection = preview_set_selection,
2115};
2116
2117/* subdev operations */
2118static const struct v4l2_subdev_ops preview_v4l2_ops = {
2119        .core = &preview_v4l2_core_ops,
2120        .video = &preview_v4l2_video_ops,
2121        .pad = &preview_v4l2_pad_ops,
2122};
2123
2124/* subdev internal operations */
2125static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
2126        .open = preview_init_formats,
2127};
2128
2129/* -----------------------------------------------------------------------------
2130 * Media entity operations
2131 */
2132
2133/*
2134 * preview_link_setup - Setup previewer connections.
2135 * @entity : Pointer to media entity structure
2136 * @local  : Pointer to local pad array
2137 * @remote : Pointer to remote pad array
2138 * @flags  : Link flags
2139 * return -EINVAL or zero on success
2140 */
2141static int preview_link_setup(struct media_entity *entity,
2142                              const struct media_pad *local,
2143                              const struct media_pad *remote, u32 flags)
2144{
2145        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
2146        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
2147        unsigned int index = local->index;
2148
2149        /* FIXME: this is actually a hack! */
2150        if (is_media_entity_v4l2_subdev(remote->entity))
2151                index |= 2 << 16;
2152
2153        switch (index) {
2154        case PREV_PAD_SINK:
2155                /* read from memory */
2156                if (flags & MEDIA_LNK_FL_ENABLED) {
2157                        if (prev->input == PREVIEW_INPUT_CCDC)
2158                                return -EBUSY;
2159                        prev->input = PREVIEW_INPUT_MEMORY;
2160                } else {
2161                        if (prev->input == PREVIEW_INPUT_MEMORY)
2162                                prev->input = PREVIEW_INPUT_NONE;
2163                }
2164                break;
2165
2166        case PREV_PAD_SINK | 2 << 16:
2167                /* read from ccdc */
2168                if (flags & MEDIA_LNK_FL_ENABLED) {
2169                        if (prev->input == PREVIEW_INPUT_MEMORY)
2170                                return -EBUSY;
2171                        prev->input = PREVIEW_INPUT_CCDC;
2172                } else {
2173                        if (prev->input == PREVIEW_INPUT_CCDC)
2174                                prev->input = PREVIEW_INPUT_NONE;
2175                }
2176                break;
2177
2178        /*
2179         * The ISP core doesn't support pipelines with multiple video outputs.
2180         * Revisit this when it will be implemented, and return -EBUSY for now.
2181         */
2182
2183        case PREV_PAD_SOURCE:
2184                /* write to memory */
2185                if (flags & MEDIA_LNK_FL_ENABLED) {
2186                        if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
2187                                return -EBUSY;
2188                        prev->output |= PREVIEW_OUTPUT_MEMORY;
2189                } else {
2190                        prev->output &= ~PREVIEW_OUTPUT_MEMORY;
2191                }
2192                break;
2193
2194        case PREV_PAD_SOURCE | 2 << 16:
2195                /* write to resizer */
2196                if (flags & MEDIA_LNK_FL_ENABLED) {
2197                        if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
2198                                return -EBUSY;
2199                        prev->output |= PREVIEW_OUTPUT_RESIZER;
2200                } else {
2201                        prev->output &= ~PREVIEW_OUTPUT_RESIZER;
2202                }
2203                break;
2204
2205        default:
2206                return -EINVAL;
2207        }
2208
2209        return 0;
2210}
2211
2212/* media operations */
2213static const struct media_entity_operations preview_media_ops = {
2214        .link_setup = preview_link_setup,
2215        .link_validate = v4l2_subdev_link_validate,
2216};
2217
2218void omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
2219{
2220        v4l2_device_unregister_subdev(&prev->subdev);
2221        omap3isp_video_unregister(&prev->video_in);
2222        omap3isp_video_unregister(&prev->video_out);
2223}
2224
2225int omap3isp_preview_register_entities(struct isp_prev_device *prev,
2226        struct v4l2_device *vdev)
2227{
2228        int ret;
2229
2230        /* Register the subdev and video nodes. */
2231        ret = v4l2_device_register_subdev(vdev, &prev->subdev);
2232        if (ret < 0)
2233                goto error;
2234
2235        ret = omap3isp_video_register(&prev->video_in, vdev);
2236        if (ret < 0)
2237                goto error;
2238
2239        ret = omap3isp_video_register(&prev->video_out, vdev);
2240        if (ret < 0)
2241                goto error;
2242
2243        return 0;
2244
2245error:
2246        omap3isp_preview_unregister_entities(prev);
2247        return ret;
2248}
2249
2250/* -----------------------------------------------------------------------------
2251 * ISP previewer initialisation and cleanup
2252 */
2253
2254/*
2255 * preview_init_entities - Initialize subdev and media entity.
2256 * @prev : Pointer to preview structure
2257 * return -ENOMEM or zero on success
2258 */
2259static int preview_init_entities(struct isp_prev_device *prev)
2260{
2261        struct v4l2_subdev *sd = &prev->subdev;
2262        struct media_pad *pads = prev->pads;
2263        struct media_entity *me = &sd->entity;
2264        int ret;
2265
2266        prev->input = PREVIEW_INPUT_NONE;
2267
2268        v4l2_subdev_init(sd, &preview_v4l2_ops);
2269        sd->internal_ops = &preview_v4l2_internal_ops;
2270        strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
2271        sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
2272        v4l2_set_subdevdata(sd, prev);
2273        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
2274
2275        v4l2_ctrl_handler_init(&prev->ctrls, 2);
2276        v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS,
2277                          ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH,
2278                          ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF);
2279        v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST,
2280                          ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH,
2281                          ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF);
2282        v4l2_ctrl_handler_setup(&prev->ctrls);
2283        sd->ctrl_handler = &prev->ctrls;
2284
2285        pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK
2286                                    | MEDIA_PAD_FL_MUST_CONNECT;
2287        pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
2288
2289        me->ops = &preview_media_ops;
2290        ret = media_entity_pads_init(me, PREV_PADS_NUM, pads);
2291        if (ret < 0)
2292                return ret;
2293
2294        preview_init_formats(sd, NULL);
2295
2296        /* According to the OMAP34xx TRM, video buffers need to be aligned on a
2297         * 32 bytes boundary. However, an undocumented hardware bug requires a
2298         * 64 bytes boundary at the preview engine input.
2299         */
2300        prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2301        prev->video_in.ops = &preview_video_ops;
2302        prev->video_in.isp = to_isp_device(prev);
2303        prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
2304        prev->video_in.bpl_alignment = 64;
2305        prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2306        prev->video_out.ops = &preview_video_ops;
2307        prev->video_out.isp = to_isp_device(prev);
2308        prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
2309        prev->video_out.bpl_alignment = 32;
2310
2311        ret = omap3isp_video_init(&prev->video_in, "preview");
2312        if (ret < 0)
2313                goto error_video_in;
2314
2315        ret = omap3isp_video_init(&prev->video_out, "preview");
2316        if (ret < 0)
2317                goto error_video_out;
2318
2319        return 0;
2320
2321error_video_out:
2322        omap3isp_video_cleanup(&prev->video_in);
2323error_video_in:
2324        media_entity_cleanup(&prev->subdev.entity);
2325        return ret;
2326}
2327
2328/*
2329 * omap3isp_preview_init - Previewer initialization.
2330 * @isp : Pointer to ISP device
2331 * return -ENOMEM or zero on success
2332 */
2333int omap3isp_preview_init(struct isp_device *isp)
2334{
2335        struct isp_prev_device *prev = &isp->isp_prev;
2336
2337        init_waitqueue_head(&prev->wait);
2338
2339        preview_init_params(prev);
2340
2341        return preview_init_entities(prev);
2342}
2343
2344void omap3isp_preview_cleanup(struct isp_device *isp)
2345{
2346        struct isp_prev_device *prev = &isp->isp_prev;
2347
2348        v4l2_ctrl_handler_free(&prev->ctrls);
2349        omap3isp_video_cleanup(&prev->video_in);
2350        omap3isp_video_cleanup(&prev->video_out);
2351        media_entity_cleanup(&prev->subdev.entity);
2352}
2353