Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2012-2014 Mentor Graphics Inc.
0004  * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
0005  */
0006 
0007 #include <linux/types.h>
0008 #include <linux/init.h>
0009 #include <linux/errno.h>
0010 #include <linux/spinlock.h>
0011 #include <linux/bitrev.h>
0012 #include <linux/io.h>
0013 #include <linux/err.h>
0014 #include <linux/sizes.h>
0015 #include "ipu-prv.h"
0016 
0017 /* IC Register Offsets */
0018 #define IC_CONF                 0x0000
0019 #define IC_PRP_ENC_RSC          0x0004
0020 #define IC_PRP_VF_RSC           0x0008
0021 #define IC_PP_RSC               0x000C
0022 #define IC_CMBP_1               0x0010
0023 #define IC_CMBP_2               0x0014
0024 #define IC_IDMAC_1              0x0018
0025 #define IC_IDMAC_2              0x001C
0026 #define IC_IDMAC_3              0x0020
0027 #define IC_IDMAC_4              0x0024
0028 
0029 /* IC Register Fields */
0030 #define IC_CONF_PRPENC_EN       (1 << 0)
0031 #define IC_CONF_PRPENC_CSC1     (1 << 1)
0032 #define IC_CONF_PRPENC_ROT_EN   (1 << 2)
0033 #define IC_CONF_PRPVF_EN        (1 << 8)
0034 #define IC_CONF_PRPVF_CSC1      (1 << 9)
0035 #define IC_CONF_PRPVF_CSC2      (1 << 10)
0036 #define IC_CONF_PRPVF_CMB       (1 << 11)
0037 #define IC_CONF_PRPVF_ROT_EN    (1 << 12)
0038 #define IC_CONF_PP_EN           (1 << 16)
0039 #define IC_CONF_PP_CSC1         (1 << 17)
0040 #define IC_CONF_PP_CSC2         (1 << 18)
0041 #define IC_CONF_PP_CMB          (1 << 19)
0042 #define IC_CONF_PP_ROT_EN       (1 << 20)
0043 #define IC_CONF_IC_GLB_LOC_A    (1 << 28)
0044 #define IC_CONF_KEY_COLOR_EN    (1 << 29)
0045 #define IC_CONF_RWS_EN          (1 << 30)
0046 #define IC_CONF_CSI_MEM_WR_EN   (1 << 31)
0047 
0048 #define IC_IDMAC_1_CB0_BURST_16         (1 << 0)
0049 #define IC_IDMAC_1_CB1_BURST_16         (1 << 1)
0050 #define IC_IDMAC_1_CB2_BURST_16         (1 << 2)
0051 #define IC_IDMAC_1_CB3_BURST_16         (1 << 3)
0052 #define IC_IDMAC_1_CB4_BURST_16         (1 << 4)
0053 #define IC_IDMAC_1_CB5_BURST_16         (1 << 5)
0054 #define IC_IDMAC_1_CB6_BURST_16         (1 << 6)
0055 #define IC_IDMAC_1_CB7_BURST_16         (1 << 7)
0056 #define IC_IDMAC_1_PRPENC_ROT_MASK      (0x7 << 11)
0057 #define IC_IDMAC_1_PRPENC_ROT_OFFSET    11
0058 #define IC_IDMAC_1_PRPVF_ROT_MASK       (0x7 << 14)
0059 #define IC_IDMAC_1_PRPVF_ROT_OFFSET     14
0060 #define IC_IDMAC_1_PP_ROT_MASK          (0x7 << 17)
0061 #define IC_IDMAC_1_PP_ROT_OFFSET        17
0062 #define IC_IDMAC_1_PP_FLIP_RS           (1 << 22)
0063 #define IC_IDMAC_1_PRPVF_FLIP_RS        (1 << 21)
0064 #define IC_IDMAC_1_PRPENC_FLIP_RS       (1 << 20)
0065 
0066 #define IC_IDMAC_2_PRPENC_HEIGHT_MASK   (0x3ff << 0)
0067 #define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
0068 #define IC_IDMAC_2_PRPVF_HEIGHT_MASK    (0x3ff << 10)
0069 #define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET  10
0070 #define IC_IDMAC_2_PP_HEIGHT_MASK       (0x3ff << 20)
0071 #define IC_IDMAC_2_PP_HEIGHT_OFFSET     20
0072 
0073 #define IC_IDMAC_3_PRPENC_WIDTH_MASK    (0x3ff << 0)
0074 #define IC_IDMAC_3_PRPENC_WIDTH_OFFSET  0
0075 #define IC_IDMAC_3_PRPVF_WIDTH_MASK     (0x3ff << 10)
0076 #define IC_IDMAC_3_PRPVF_WIDTH_OFFSET   10
0077 #define IC_IDMAC_3_PP_WIDTH_MASK        (0x3ff << 20)
0078 #define IC_IDMAC_3_PP_WIDTH_OFFSET      20
0079 
0080 struct ic_task_regoffs {
0081     u32 rsc;
0082     u32 tpmem_csc[2];
0083 };
0084 
0085 struct ic_task_bitfields {
0086     u32 ic_conf_en;
0087     u32 ic_conf_rot_en;
0088     u32 ic_conf_cmb_en;
0089     u32 ic_conf_csc1_en;
0090     u32 ic_conf_csc2_en;
0091     u32 ic_cmb_galpha_bit;
0092 };
0093 
0094 static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
0095     [IC_TASK_ENCODER] = {
0096         .rsc = IC_PRP_ENC_RSC,
0097         .tpmem_csc = {0x2008, 0},
0098     },
0099     [IC_TASK_VIEWFINDER] = {
0100         .rsc = IC_PRP_VF_RSC,
0101         .tpmem_csc = {0x4028, 0x4040},
0102     },
0103     [IC_TASK_POST_PROCESSOR] = {
0104         .rsc = IC_PP_RSC,
0105         .tpmem_csc = {0x6060, 0x6078},
0106     },
0107 };
0108 
0109 static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
0110     [IC_TASK_ENCODER] = {
0111         .ic_conf_en = IC_CONF_PRPENC_EN,
0112         .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
0113         .ic_conf_cmb_en = 0,    /* NA */
0114         .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
0115         .ic_conf_csc2_en = 0,   /* NA */
0116         .ic_cmb_galpha_bit = 0, /* NA */
0117     },
0118     [IC_TASK_VIEWFINDER] = {
0119         .ic_conf_en = IC_CONF_PRPVF_EN,
0120         .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
0121         .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
0122         .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
0123         .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
0124         .ic_cmb_galpha_bit = 0,
0125     },
0126     [IC_TASK_POST_PROCESSOR] = {
0127         .ic_conf_en = IC_CONF_PP_EN,
0128         .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
0129         .ic_conf_cmb_en = IC_CONF_PP_CMB,
0130         .ic_conf_csc1_en = IC_CONF_PP_CSC1,
0131         .ic_conf_csc2_en = IC_CONF_PP_CSC2,
0132         .ic_cmb_galpha_bit = 8,
0133     },
0134 };
0135 
0136 struct ipu_ic_priv;
0137 
0138 struct ipu_ic {
0139     enum ipu_ic_task task;
0140     const struct ic_task_regoffs *reg;
0141     const struct ic_task_bitfields *bit;
0142 
0143     struct ipu_ic_colorspace in_cs;
0144     struct ipu_ic_colorspace g_in_cs;
0145     struct ipu_ic_colorspace out_cs;
0146 
0147     bool graphics;
0148     bool rotation;
0149     bool in_use;
0150 
0151     struct ipu_ic_priv *priv;
0152 };
0153 
0154 struct ipu_ic_priv {
0155     void __iomem *base;
0156     void __iomem *tpmem_base;
0157     spinlock_t lock;
0158     struct ipu_soc *ipu;
0159     int use_count;
0160     int irt_use_count;
0161     struct ipu_ic task[IC_NUM_TASKS];
0162 };
0163 
0164 static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
0165 {
0166     return readl(ic->priv->base + offset);
0167 }
0168 
0169 static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
0170 {
0171     writel(value, ic->priv->base + offset);
0172 }
0173 
0174 static int init_csc(struct ipu_ic *ic,
0175             const struct ipu_ic_csc *csc,
0176             int csc_index)
0177 {
0178     struct ipu_ic_priv *priv = ic->priv;
0179     u32 __iomem *base;
0180     const u16 (*c)[3];
0181     const u16 *a;
0182     u32 param;
0183 
0184     base = (u32 __iomem *)
0185         (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
0186 
0187     /* Cast to unsigned */
0188     c = (const u16 (*)[3])csc->params.coeff;
0189     a = (const u16 *)csc->params.offset;
0190 
0191     param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
0192         ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
0193     writel(param, base++);
0194 
0195     param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) |
0196         (csc->params.sat << 10);
0197     writel(param, base++);
0198 
0199     param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
0200         ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
0201     writel(param, base++);
0202 
0203     param = ((a[1] & 0x1fe0) >> 5);
0204     writel(param, base++);
0205 
0206     param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
0207         ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
0208     writel(param, base++);
0209 
0210     param = ((a[2] & 0x1fe0) >> 5);
0211     writel(param, base++);
0212 
0213     return 0;
0214 }
0215 
0216 static int calc_resize_coeffs(struct ipu_ic *ic,
0217                   u32 in_size, u32 out_size,
0218                   u32 *resize_coeff,
0219                   u32 *downsize_coeff)
0220 {
0221     struct ipu_ic_priv *priv = ic->priv;
0222     struct ipu_soc *ipu = priv->ipu;
0223     u32 temp_size, temp_downsize;
0224 
0225     /*
0226      * Input size cannot be more than 4096, and output size cannot
0227      * be more than 1024
0228      */
0229     if (in_size > 4096) {
0230         dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
0231         return -EINVAL;
0232     }
0233     if (out_size > 1024) {
0234         dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
0235         return -EINVAL;
0236     }
0237 
0238     /* Cannot downsize more than 4:1 */
0239     if ((out_size << 2) < in_size) {
0240         dev_err(ipu->dev, "Unsupported downsize\n");
0241         return -EINVAL;
0242     }
0243 
0244     /* Compute downsizing coefficient */
0245     temp_downsize = 0;
0246     temp_size = in_size;
0247     while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
0248            (temp_downsize < 2)) {
0249         temp_size >>= 1;
0250         temp_downsize++;
0251     }
0252     *downsize_coeff = temp_downsize;
0253 
0254     /*
0255      * compute resizing coefficient using the following equation:
0256      * resize_coeff = M * (SI - 1) / (SO - 1)
0257      * where M = 2^13, SI = input size, SO = output size
0258      */
0259     *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
0260     if (*resize_coeff >= 16384L) {
0261         dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
0262         *resize_coeff = 0x3FFF;
0263     }
0264 
0265     return 0;
0266 }
0267 
0268 void ipu_ic_task_enable(struct ipu_ic *ic)
0269 {
0270     struct ipu_ic_priv *priv = ic->priv;
0271     unsigned long flags;
0272     u32 ic_conf;
0273 
0274     spin_lock_irqsave(&priv->lock, flags);
0275 
0276     ic_conf = ipu_ic_read(ic, IC_CONF);
0277 
0278     ic_conf |= ic->bit->ic_conf_en;
0279 
0280     if (ic->rotation)
0281         ic_conf |= ic->bit->ic_conf_rot_en;
0282 
0283     if (ic->in_cs.cs != ic->out_cs.cs)
0284         ic_conf |= ic->bit->ic_conf_csc1_en;
0285 
0286     if (ic->graphics) {
0287         ic_conf |= ic->bit->ic_conf_cmb_en;
0288         ic_conf |= ic->bit->ic_conf_csc1_en;
0289 
0290         if (ic->g_in_cs.cs != ic->out_cs.cs)
0291             ic_conf |= ic->bit->ic_conf_csc2_en;
0292     }
0293 
0294     ipu_ic_write(ic, ic_conf, IC_CONF);
0295 
0296     spin_unlock_irqrestore(&priv->lock, flags);
0297 }
0298 EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
0299 
0300 void ipu_ic_task_disable(struct ipu_ic *ic)
0301 {
0302     struct ipu_ic_priv *priv = ic->priv;
0303     unsigned long flags;
0304     u32 ic_conf;
0305 
0306     spin_lock_irqsave(&priv->lock, flags);
0307 
0308     ic_conf = ipu_ic_read(ic, IC_CONF);
0309 
0310     ic_conf &= ~(ic->bit->ic_conf_en |
0311              ic->bit->ic_conf_csc1_en |
0312              ic->bit->ic_conf_rot_en);
0313     if (ic->bit->ic_conf_csc2_en)
0314         ic_conf &= ~ic->bit->ic_conf_csc2_en;
0315     if (ic->bit->ic_conf_cmb_en)
0316         ic_conf &= ~ic->bit->ic_conf_cmb_en;
0317 
0318     ipu_ic_write(ic, ic_conf, IC_CONF);
0319 
0320     spin_unlock_irqrestore(&priv->lock, flags);
0321 }
0322 EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
0323 
0324 int ipu_ic_task_graphics_init(struct ipu_ic *ic,
0325                   const struct ipu_ic_colorspace *g_in_cs,
0326                   bool galpha_en, u32 galpha,
0327                   bool colorkey_en, u32 colorkey)
0328 {
0329     struct ipu_ic_priv *priv = ic->priv;
0330     struct ipu_ic_csc csc2;
0331     unsigned long flags;
0332     u32 reg, ic_conf;
0333     int ret = 0;
0334 
0335     if (ic->task == IC_TASK_ENCODER)
0336         return -EINVAL;
0337 
0338     spin_lock_irqsave(&priv->lock, flags);
0339 
0340     ic_conf = ipu_ic_read(ic, IC_CONF);
0341 
0342     if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
0343         struct ipu_ic_csc csc1;
0344 
0345         ret = ipu_ic_calc_csc(&csc1,
0346                       V4L2_YCBCR_ENC_601,
0347                       V4L2_QUANTIZATION_FULL_RANGE,
0348                       IPUV3_COLORSPACE_RGB,
0349                       V4L2_YCBCR_ENC_601,
0350                       V4L2_QUANTIZATION_FULL_RANGE,
0351                       IPUV3_COLORSPACE_RGB);
0352         if (ret)
0353             goto unlock;
0354 
0355         /* need transparent CSC1 conversion */
0356         ret = init_csc(ic, &csc1, 0);
0357         if (ret)
0358             goto unlock;
0359     }
0360 
0361     ic->g_in_cs = *g_in_cs;
0362     csc2.in_cs = ic->g_in_cs;
0363     csc2.out_cs = ic->out_cs;
0364 
0365     ret = __ipu_ic_calc_csc(&csc2);
0366     if (ret)
0367         goto unlock;
0368 
0369     ret = init_csc(ic, &csc2, 1);
0370     if (ret)
0371         goto unlock;
0372 
0373     if (galpha_en) {
0374         ic_conf |= IC_CONF_IC_GLB_LOC_A;
0375         reg = ipu_ic_read(ic, IC_CMBP_1);
0376         reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
0377         reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
0378         ipu_ic_write(ic, reg, IC_CMBP_1);
0379     } else
0380         ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
0381 
0382     if (colorkey_en) {
0383         ic_conf |= IC_CONF_KEY_COLOR_EN;
0384         ipu_ic_write(ic, colorkey, IC_CMBP_2);
0385     } else
0386         ic_conf &= ~IC_CONF_KEY_COLOR_EN;
0387 
0388     ipu_ic_write(ic, ic_conf, IC_CONF);
0389 
0390     ic->graphics = true;
0391 unlock:
0392     spin_unlock_irqrestore(&priv->lock, flags);
0393     return ret;
0394 }
0395 EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
0396 
0397 int ipu_ic_task_init_rsc(struct ipu_ic *ic,
0398              const struct ipu_ic_csc *csc,
0399              int in_width, int in_height,
0400              int out_width, int out_height,
0401              u32 rsc)
0402 {
0403     struct ipu_ic_priv *priv = ic->priv;
0404     u32 downsize_coeff, resize_coeff;
0405     unsigned long flags;
0406     int ret = 0;
0407 
0408     if (!rsc) {
0409         /* Setup vertical resizing */
0410 
0411         ret = calc_resize_coeffs(ic, in_height, out_height,
0412                      &resize_coeff, &downsize_coeff);
0413         if (ret)
0414             return ret;
0415 
0416         rsc = (downsize_coeff << 30) | (resize_coeff << 16);
0417 
0418         /* Setup horizontal resizing */
0419         ret = calc_resize_coeffs(ic, in_width, out_width,
0420                      &resize_coeff, &downsize_coeff);
0421         if (ret)
0422             return ret;
0423 
0424         rsc |= (downsize_coeff << 14) | resize_coeff;
0425     }
0426 
0427     spin_lock_irqsave(&priv->lock, flags);
0428 
0429     ipu_ic_write(ic, rsc, ic->reg->rsc);
0430 
0431     /* Setup color space conversion */
0432     ic->in_cs = csc->in_cs;
0433     ic->out_cs = csc->out_cs;
0434 
0435     ret = init_csc(ic, csc, 0);
0436 
0437     spin_unlock_irqrestore(&priv->lock, flags);
0438     return ret;
0439 }
0440 
0441 int ipu_ic_task_init(struct ipu_ic *ic,
0442              const struct ipu_ic_csc *csc,
0443              int in_width, int in_height,
0444              int out_width, int out_height)
0445 {
0446     return ipu_ic_task_init_rsc(ic, csc,
0447                     in_width, in_height,
0448                     out_width, out_height, 0);
0449 }
0450 EXPORT_SYMBOL_GPL(ipu_ic_task_init);
0451 
0452 int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
0453               u32 width, u32 height, int burst_size,
0454               enum ipu_rotate_mode rot)
0455 {
0456     struct ipu_ic_priv *priv = ic->priv;
0457     struct ipu_soc *ipu = priv->ipu;
0458     u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
0459     u32 temp_rot = bitrev8(rot) >> 5;
0460     bool need_hor_flip = false;
0461     unsigned long flags;
0462     int ret = 0;
0463 
0464     if ((burst_size != 8) && (burst_size != 16)) {
0465         dev_err(ipu->dev, "Illegal burst length for IC\n");
0466         return -EINVAL;
0467     }
0468 
0469     width--;
0470     height--;
0471 
0472     if (temp_rot & 0x2) /* Need horizontal flip */
0473         need_hor_flip = true;
0474 
0475     spin_lock_irqsave(&priv->lock, flags);
0476 
0477     ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
0478     ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
0479     ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
0480 
0481     switch (channel->num) {
0482     case IPUV3_CHANNEL_IC_PP_MEM:
0483         if (burst_size == 16)
0484             ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
0485         else
0486             ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
0487 
0488         if (need_hor_flip)
0489             ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
0490         else
0491             ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
0492 
0493         ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
0494         ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
0495 
0496         ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
0497         ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
0498         break;
0499     case IPUV3_CHANNEL_MEM_IC_PP:
0500         if (burst_size == 16)
0501             ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
0502         else
0503             ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
0504         break;
0505     case IPUV3_CHANNEL_MEM_ROT_PP:
0506         ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
0507         ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
0508         break;
0509     case IPUV3_CHANNEL_MEM_IC_PRP_VF:
0510         if (burst_size == 16)
0511             ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
0512         else
0513             ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
0514         break;
0515     case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
0516         if (burst_size == 16)
0517             ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
0518         else
0519             ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
0520 
0521         if (need_hor_flip)
0522             ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
0523         else
0524             ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
0525 
0526         ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
0527         ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
0528 
0529         ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
0530         ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
0531         break;
0532     case IPUV3_CHANNEL_MEM_ROT_ENC:
0533         ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
0534         ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
0535         break;
0536     case IPUV3_CHANNEL_IC_PRP_VF_MEM:
0537         if (burst_size == 16)
0538             ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
0539         else
0540             ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
0541 
0542         if (need_hor_flip)
0543             ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
0544         else
0545             ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
0546 
0547         ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
0548         ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
0549 
0550         ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
0551         ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
0552         break;
0553     case IPUV3_CHANNEL_MEM_ROT_VF:
0554         ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
0555         ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
0556         break;
0557     case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
0558         if (burst_size == 16)
0559             ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
0560         else
0561             ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
0562         break;
0563     case IPUV3_CHANNEL_G_MEM_IC_PP:
0564         if (burst_size == 16)
0565             ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
0566         else
0567             ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
0568         break;
0569     case IPUV3_CHANNEL_VDI_MEM_IC_VF:
0570         if (burst_size == 16)
0571             ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
0572         else
0573             ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
0574         break;
0575     default:
0576         goto unlock;
0577     }
0578 
0579     ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
0580     ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
0581     ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
0582 
0583     if (ipu_rot_mode_is_irt(rot))
0584         ic->rotation = true;
0585 
0586 unlock:
0587     spin_unlock_irqrestore(&priv->lock, flags);
0588     return ret;
0589 }
0590 EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
0591 
0592 static void ipu_irt_enable(struct ipu_ic *ic)
0593 {
0594     struct ipu_ic_priv *priv = ic->priv;
0595 
0596     if (!priv->irt_use_count)
0597         ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
0598 
0599     priv->irt_use_count++;
0600 }
0601 
0602 static void ipu_irt_disable(struct ipu_ic *ic)
0603 {
0604     struct ipu_ic_priv *priv = ic->priv;
0605 
0606     if (priv->irt_use_count) {
0607         if (!--priv->irt_use_count)
0608             ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
0609     }
0610 }
0611 
0612 int ipu_ic_enable(struct ipu_ic *ic)
0613 {
0614     struct ipu_ic_priv *priv = ic->priv;
0615     unsigned long flags;
0616 
0617     spin_lock_irqsave(&priv->lock, flags);
0618 
0619     if (!priv->use_count)
0620         ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
0621 
0622     priv->use_count++;
0623 
0624     if (ic->rotation)
0625         ipu_irt_enable(ic);
0626 
0627     spin_unlock_irqrestore(&priv->lock, flags);
0628 
0629     return 0;
0630 }
0631 EXPORT_SYMBOL_GPL(ipu_ic_enable);
0632 
0633 int ipu_ic_disable(struct ipu_ic *ic)
0634 {
0635     struct ipu_ic_priv *priv = ic->priv;
0636     unsigned long flags;
0637 
0638     spin_lock_irqsave(&priv->lock, flags);
0639 
0640     priv->use_count--;
0641 
0642     if (!priv->use_count)
0643         ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
0644 
0645     if (priv->use_count < 0)
0646         priv->use_count = 0;
0647 
0648     if (ic->rotation)
0649         ipu_irt_disable(ic);
0650 
0651     ic->rotation = ic->graphics = false;
0652 
0653     spin_unlock_irqrestore(&priv->lock, flags);
0654 
0655     return 0;
0656 }
0657 EXPORT_SYMBOL_GPL(ipu_ic_disable);
0658 
0659 struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
0660 {
0661     struct ipu_ic_priv *priv = ipu->ic_priv;
0662     unsigned long flags;
0663     struct ipu_ic *ic, *ret;
0664 
0665     if (task >= IC_NUM_TASKS)
0666         return ERR_PTR(-EINVAL);
0667 
0668     ic = &priv->task[task];
0669 
0670     spin_lock_irqsave(&priv->lock, flags);
0671 
0672     if (ic->in_use) {
0673         ret = ERR_PTR(-EBUSY);
0674         goto unlock;
0675     }
0676 
0677     ic->in_use = true;
0678     ret = ic;
0679 
0680 unlock:
0681     spin_unlock_irqrestore(&priv->lock, flags);
0682     return ret;
0683 }
0684 EXPORT_SYMBOL_GPL(ipu_ic_get);
0685 
0686 void ipu_ic_put(struct ipu_ic *ic)
0687 {
0688     struct ipu_ic_priv *priv = ic->priv;
0689     unsigned long flags;
0690 
0691     spin_lock_irqsave(&priv->lock, flags);
0692     ic->in_use = false;
0693     spin_unlock_irqrestore(&priv->lock, flags);
0694 }
0695 EXPORT_SYMBOL_GPL(ipu_ic_put);
0696 
0697 int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
0698         unsigned long base, unsigned long tpmem_base)
0699 {
0700     struct ipu_ic_priv *priv;
0701     int i;
0702 
0703     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0704     if (!priv)
0705         return -ENOMEM;
0706 
0707     ipu->ic_priv = priv;
0708 
0709     spin_lock_init(&priv->lock);
0710     priv->base = devm_ioremap(dev, base, PAGE_SIZE);
0711     if (!priv->base)
0712         return -ENOMEM;
0713     priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
0714     if (!priv->tpmem_base)
0715         return -ENOMEM;
0716 
0717     dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
0718 
0719     priv->ipu = ipu;
0720 
0721     for (i = 0; i < IC_NUM_TASKS; i++) {
0722         priv->task[i].task = i;
0723         priv->task[i].priv = priv;
0724         priv->task[i].reg = &ic_task_reg[i];
0725         priv->task[i].bit = &ic_task_bit[i];
0726     }
0727 
0728     return 0;
0729 }
0730 
0731 void ipu_ic_exit(struct ipu_soc *ipu)
0732 {
0733 }
0734 
0735 void ipu_ic_dump(struct ipu_ic *ic)
0736 {
0737     struct ipu_ic_priv *priv = ic->priv;
0738     struct ipu_soc *ipu = priv->ipu;
0739 
0740     dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
0741         ipu_ic_read(ic, IC_CONF));
0742     dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
0743         ipu_ic_read(ic, IC_PRP_ENC_RSC));
0744     dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
0745         ipu_ic_read(ic, IC_PRP_VF_RSC));
0746     dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
0747         ipu_ic_read(ic, IC_PP_RSC));
0748     dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
0749         ipu_ic_read(ic, IC_CMBP_1));
0750     dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
0751         ipu_ic_read(ic, IC_CMBP_2));
0752     dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
0753         ipu_ic_read(ic, IC_IDMAC_1));
0754     dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
0755         ipu_ic_read(ic, IC_IDMAC_2));
0756     dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
0757         ipu_ic_read(ic, IC_IDMAC_3));
0758     dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
0759         ipu_ic_read(ic, IC_IDMAC_4));
0760 }
0761 EXPORT_SYMBOL_GPL(ipu_ic_dump);