0001
0002
0003
0004
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
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
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,
0114 .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
0115 .ic_conf_csc2_en = 0,
0116 .ic_cmb_galpha_bit = 0,
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
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
0227
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
0239 if ((out_size << 2) < in_size) {
0240 dev_err(ipu->dev, "Unsupported downsize\n");
0241 return -EINVAL;
0242 }
0243
0244
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
0256
0257
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
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
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
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
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)
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);