Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
0004  * Author: James.Qian.Wang <james.qian.wang@arm.com>
0005  *
0006  */
0007 #include "d71_dev.h"
0008 #include "komeda_kms.h"
0009 #include "malidp_io.h"
0010 #include "komeda_framebuffer.h"
0011 #include "komeda_color_mgmt.h"
0012 
0013 static void get_resources_id(u32 hw_id, u32 *pipe_id, u32 *comp_id)
0014 {
0015     u32 id = BLOCK_INFO_BLK_ID(hw_id);
0016     u32 pipe = id;
0017 
0018     switch (BLOCK_INFO_BLK_TYPE(hw_id)) {
0019     case D71_BLK_TYPE_LPU_WB_LAYER:
0020         id = KOMEDA_COMPONENT_WB_LAYER;
0021         break;
0022     case D71_BLK_TYPE_CU_SPLITTER:
0023         id = KOMEDA_COMPONENT_SPLITTER;
0024         break;
0025     case D71_BLK_TYPE_CU_SCALER:
0026         pipe = id / D71_PIPELINE_MAX_SCALERS;
0027         id %= D71_PIPELINE_MAX_SCALERS;
0028         id += KOMEDA_COMPONENT_SCALER0;
0029         break;
0030     case D71_BLK_TYPE_CU:
0031         id += KOMEDA_COMPONENT_COMPIZ0;
0032         break;
0033     case D71_BLK_TYPE_LPU_LAYER:
0034         pipe = id / D71_PIPELINE_MAX_LAYERS;
0035         id %= D71_PIPELINE_MAX_LAYERS;
0036         id += KOMEDA_COMPONENT_LAYER0;
0037         break;
0038     case D71_BLK_TYPE_DOU_IPS:
0039         id += KOMEDA_COMPONENT_IPS0;
0040         break;
0041     case D71_BLK_TYPE_CU_MERGER:
0042         id = KOMEDA_COMPONENT_MERGER;
0043         break;
0044     case D71_BLK_TYPE_DOU:
0045         id = KOMEDA_COMPONENT_TIMING_CTRLR;
0046         break;
0047     default:
0048         id = 0xFFFFFFFF;
0049     }
0050 
0051     if (comp_id)
0052         *comp_id = id;
0053 
0054     if (pipe_id)
0055         *pipe_id = pipe;
0056 }
0057 
0058 static u32 get_valid_inputs(struct block_header *blk)
0059 {
0060     u32 valid_inputs = 0, comp_id;
0061     int i;
0062 
0063     for (i = 0; i < PIPELINE_INFO_N_VALID_INPUTS(blk->pipeline_info); i++) {
0064         get_resources_id(blk->input_ids[i], NULL, &comp_id);
0065         if (comp_id == 0xFFFFFFFF)
0066             continue;
0067         valid_inputs |= BIT(comp_id);
0068     }
0069 
0070     return valid_inputs;
0071 }
0072 
0073 static void get_values_from_reg(void __iomem *reg, u32 offset,
0074                 u32 count, u32 *val)
0075 {
0076     u32 i, addr;
0077 
0078     for (i = 0; i < count; i++) {
0079         addr = offset + (i << 2);
0080         /* 0xA4 is WO register */
0081         if (addr != 0xA4)
0082             val[i] = malidp_read32(reg, addr);
0083         else
0084             val[i] = 0xDEADDEAD;
0085     }
0086 }
0087 
0088 static void dump_block_header(struct seq_file *sf, void __iomem *reg)
0089 {
0090     struct block_header hdr;
0091     u32 i, n_input, n_output;
0092 
0093     d71_read_block_header(reg, &hdr);
0094     seq_printf(sf, "BLOCK_INFO:\t\t0x%X\n", hdr.block_info);
0095     seq_printf(sf, "PIPELINE_INFO:\t\t0x%X\n", hdr.pipeline_info);
0096 
0097     n_output = PIPELINE_INFO_N_OUTPUTS(hdr.pipeline_info);
0098     n_input  = PIPELINE_INFO_N_VALID_INPUTS(hdr.pipeline_info);
0099 
0100     for (i = 0; i < n_input; i++)
0101         seq_printf(sf, "VALID_INPUT_ID%u:\t0x%X\n",
0102                i, hdr.input_ids[i]);
0103 
0104     for (i = 0; i < n_output; i++)
0105         seq_printf(sf, "OUTPUT_ID%u:\t\t0x%X\n",
0106                i, hdr.output_ids[i]);
0107 }
0108 
0109 /* On D71, we are using the global line size. From D32, every component have
0110  * a line size register to indicate the fifo size.
0111  */
0112 static u32 __get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg,
0113                    u32 max_default)
0114 {
0115     if (!d71->periph_addr)
0116         max_default = malidp_read32(reg, BLK_MAX_LINE_SIZE);
0117 
0118     return max_default;
0119 }
0120 
0121 static u32 get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg)
0122 {
0123     return __get_blk_line_size(d71, reg, d71->max_line_size);
0124 }
0125 
0126 static u32 to_rot_ctrl(u32 rot)
0127 {
0128     u32 lr_ctrl = 0;
0129 
0130     switch (rot & DRM_MODE_ROTATE_MASK) {
0131     case DRM_MODE_ROTATE_0:
0132         lr_ctrl |= L_ROT(L_ROT_R0);
0133         break;
0134     case DRM_MODE_ROTATE_90:
0135         lr_ctrl |= L_ROT(L_ROT_R90);
0136         break;
0137     case DRM_MODE_ROTATE_180:
0138         lr_ctrl |= L_ROT(L_ROT_R180);
0139         break;
0140     case DRM_MODE_ROTATE_270:
0141         lr_ctrl |= L_ROT(L_ROT_R270);
0142         break;
0143     }
0144 
0145     if (rot & DRM_MODE_REFLECT_X)
0146         lr_ctrl |= L_HFLIP;
0147     if (rot & DRM_MODE_REFLECT_Y)
0148         lr_ctrl |= L_VFLIP;
0149 
0150     return lr_ctrl;
0151 }
0152 
0153 static u32 to_ad_ctrl(u64 modifier)
0154 {
0155     u32 afbc_ctrl = AD_AEN;
0156 
0157     if (!modifier)
0158         return 0;
0159 
0160     if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
0161         AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
0162         afbc_ctrl |= AD_WB;
0163 
0164     if (modifier & AFBC_FORMAT_MOD_YTR)
0165         afbc_ctrl |= AD_YT;
0166     if (modifier & AFBC_FORMAT_MOD_SPLIT)
0167         afbc_ctrl |= AD_BS;
0168     if (modifier & AFBC_FORMAT_MOD_TILED)
0169         afbc_ctrl |= AD_TH;
0170 
0171     return afbc_ctrl;
0172 }
0173 
0174 static inline u32 to_d71_input_id(struct komeda_component_state *st, int idx)
0175 {
0176     struct komeda_component_output *input = &st->inputs[idx];
0177 
0178     /* if input is not active, set hw input_id(0) to disable it */
0179     if (has_bit(idx, st->active_inputs))
0180         return input->component->hw_id + input->output_port;
0181     else
0182         return 0;
0183 }
0184 
0185 static void d71_layer_update_fb(struct komeda_component *c,
0186                 struct komeda_fb *kfb,
0187                 dma_addr_t *addr)
0188 {
0189     struct drm_framebuffer *fb = &kfb->base;
0190     const struct drm_format_info *info = fb->format;
0191     u32 __iomem *reg = c->reg;
0192     int block_h;
0193 
0194     if (info->num_planes > 2)
0195         malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]);
0196 
0197     if (info->num_planes > 1) {
0198         block_h = drm_format_info_block_height(info, 1);
0199         malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h);
0200         malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]);
0201     }
0202 
0203     block_h = drm_format_info_block_height(info, 0);
0204     malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h);
0205     malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]);
0206     malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
0207 }
0208 
0209 static void d71_layer_disable(struct komeda_component *c)
0210 {
0211     malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
0212 }
0213 
0214 static void d71_layer_update(struct komeda_component *c,
0215                  struct komeda_component_state *state)
0216 {
0217     struct komeda_layer_state *st = to_layer_st(state);
0218     struct drm_plane_state *plane_st = state->plane->state;
0219     struct drm_framebuffer *fb = plane_st->fb;
0220     struct komeda_fb *kfb = to_kfb(fb);
0221     u32 __iomem *reg = c->reg;
0222     u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
0223     u32 ctrl = L_EN | to_rot_ctrl(st->rot);
0224 
0225     d71_layer_update_fb(c, kfb, st->addr);
0226 
0227     malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier));
0228     if (fb->modifier) {
0229         u64 addr;
0230 
0231         malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l,
0232                                  st->afbc_crop_r));
0233         malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t,
0234                                  st->afbc_crop_b));
0235         /* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */
0236         if (fb->modifier & AFBC_FORMAT_MOD_TILED)
0237             addr = st->addr[0] + kfb->offset_payload;
0238         else
0239             addr = st->addr[0] + kfb->afbc_size - 1;
0240 
0241         malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr));
0242         malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr));
0243     }
0244 
0245     if (fb->format->is_yuv) {
0246         u32 upsampling = 0;
0247 
0248         switch (kfb->format_caps->fourcc) {
0249         case DRM_FORMAT_YUYV:
0250             upsampling = fb->modifier ? LR_CHI422_BILINEAR :
0251                      LR_CHI422_REPLICATION;
0252             break;
0253         case DRM_FORMAT_UYVY:
0254             upsampling = LR_CHI422_REPLICATION;
0255             break;
0256         case DRM_FORMAT_NV12:
0257         case DRM_FORMAT_YUV420_8BIT:
0258         case DRM_FORMAT_YUV420_10BIT:
0259         case DRM_FORMAT_YUV420:
0260         case DRM_FORMAT_P010:
0261         /* these fmt support MPGE/JPEG both, here perfer JPEG*/
0262             upsampling = LR_CHI420_JPEG;
0263             break;
0264         case DRM_FORMAT_X0L2:
0265             upsampling = LR_CHI420_JPEG;
0266             break;
0267         default:
0268             break;
0269         }
0270 
0271         malidp_write32(reg, LAYER_R_CONTROL, upsampling);
0272         malidp_write_group(reg, LAYER_YUV_RGB_COEFF0,
0273                    KOMEDA_N_YUV2RGB_COEFFS,
0274                    komeda_select_yuv2rgb_coeffs(
0275                     plane_st->color_encoding,
0276                     plane_st->color_range));
0277     }
0278 
0279     malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
0280 
0281     if (kfb->is_va)
0282         ctrl |= L_TBU_EN;
0283     malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
0284 }
0285 
0286 static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
0287 {
0288     u32 v[15], i;
0289     bool rich, rgb2rgb;
0290     char *prefix;
0291 
0292     get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
0293     if (v[14] & 0x1) {
0294         rich = true;
0295         prefix = "LR_";
0296     } else {
0297         rich = false;
0298         prefix = "LS_";
0299     }
0300 
0301     rgb2rgb = !!(v[14] & L_INFO_CM);
0302 
0303     dump_block_header(sf, c->reg);
0304 
0305     seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
0306 
0307     get_values_from_reg(c->reg, 0xD0, 1, v);
0308     seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
0309     if (rich) {
0310         get_values_from_reg(c->reg, 0xD4, 1, v);
0311         seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
0312     }
0313     get_values_from_reg(c->reg, 0xD8, 4, v);
0314     seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
0315     seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
0316     seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
0317     seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
0318 
0319     get_values_from_reg(c->reg, 0x100, 3, v);
0320     seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
0321     seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
0322     seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
0323 
0324     get_values_from_reg(c->reg, 0x110, 2, v);
0325     seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
0326     seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
0327     if (rich) {
0328         get_values_from_reg(c->reg, 0x118, 1, v);
0329         seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
0330 
0331         get_values_from_reg(c->reg, 0x120, 2, v);
0332         seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
0333         seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
0334 
0335         get_values_from_reg(c->reg, 0x130, 12, v);
0336         for (i = 0; i < 12; i++)
0337             seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
0338     }
0339 
0340     if (rgb2rgb) {
0341         get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
0342         for (i = 0; i < 12; i++)
0343             seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
0344     }
0345 
0346     get_values_from_reg(c->reg, 0x160, 3, v);
0347     seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
0348     seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
0349     seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
0350 }
0351 
0352 static int d71_layer_validate(struct komeda_component *c,
0353                   struct komeda_component_state *state)
0354 {
0355     struct komeda_layer_state *st = to_layer_st(state);
0356     struct komeda_layer *layer = to_layer(c);
0357     struct drm_plane_state *plane_st;
0358     struct drm_framebuffer *fb;
0359     u32 fourcc, line_sz, max_line_sz;
0360 
0361     plane_st = drm_atomic_get_new_plane_state(state->obj.state,
0362                           state->plane);
0363     fb = plane_st->fb;
0364     fourcc = fb->format->format;
0365 
0366     if (drm_rotation_90_or_270(st->rot))
0367         line_sz = st->vsize - st->afbc_crop_t - st->afbc_crop_b;
0368     else
0369         line_sz = st->hsize - st->afbc_crop_l - st->afbc_crop_r;
0370 
0371     if (fb->modifier) {
0372         if ((fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
0373             AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
0374             max_line_sz = layer->line_sz;
0375         else
0376             max_line_sz = layer->line_sz / 2;
0377 
0378         if (line_sz > max_line_sz) {
0379             DRM_DEBUG_ATOMIC("afbc request line_sz: %d exceed the max afbc line_sz: %d.\n",
0380                      line_sz, max_line_sz);
0381             return -EINVAL;
0382         }
0383     }
0384 
0385     if (fourcc == DRM_FORMAT_YUV420_10BIT && line_sz > 2046 && (st->afbc_crop_l % 4)) {
0386         DRM_DEBUG_ATOMIC("YUV420_10BIT input_hsize: %d exceed the max size 2046.\n",
0387                  line_sz);
0388         return -EINVAL;
0389     }
0390 
0391     if (fourcc == DRM_FORMAT_X0L2 && line_sz > 2046 && (st->addr[0] % 16)) {
0392         DRM_DEBUG_ATOMIC("X0L2 input_hsize: %d exceed the max size 2046.\n",
0393                  line_sz);
0394         return -EINVAL;
0395     }
0396 
0397     return 0;
0398 }
0399 
0400 static const struct komeda_component_funcs d71_layer_funcs = {
0401     .validate   = d71_layer_validate,
0402     .update     = d71_layer_update,
0403     .disable    = d71_layer_disable,
0404     .dump_register  = d71_layer_dump,
0405 };
0406 
0407 static int d71_layer_init(struct d71_dev *d71,
0408               struct block_header *blk, u32 __iomem *reg)
0409 {
0410     struct komeda_component *c;
0411     struct komeda_layer *layer;
0412     u32 pipe_id, layer_id, layer_info;
0413 
0414     get_resources_id(blk->block_info, &pipe_id, &layer_id);
0415     c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
0416                  layer_id,
0417                  BLOCK_INFO_INPUT_ID(blk->block_info),
0418                  &d71_layer_funcs, 0,
0419                  get_valid_inputs(blk),
0420                  1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
0421     if (IS_ERR(c)) {
0422         DRM_ERROR("Failed to add layer component\n");
0423         return PTR_ERR(c);
0424     }
0425 
0426     layer = to_layer(c);
0427     layer_info = malidp_read32(reg, LAYER_INFO);
0428 
0429     if (layer_info & L_INFO_RF)
0430         layer->layer_type = KOMEDA_FMT_RICH_LAYER;
0431     else
0432         layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
0433 
0434     if (!d71->periph_addr) {
0435         /* D32 or newer product */
0436         layer->line_sz = malidp_read32(reg, BLK_MAX_LINE_SIZE);
0437         layer->yuv_line_sz = L_INFO_YUV_MAX_LINESZ(layer_info);
0438     } else if (d71->max_line_size > 2048) {
0439         /* D71 4K */
0440         layer->line_sz = d71->max_line_size;
0441         layer->yuv_line_sz = layer->line_sz / 2;
0442     } else  {
0443         /* D71 2K */
0444         if (layer->layer_type == KOMEDA_FMT_RICH_LAYER) {
0445             /* rich layer is 4K configuration */
0446             layer->line_sz = d71->max_line_size * 2;
0447             layer->yuv_line_sz = layer->line_sz / 2;
0448         } else {
0449             layer->line_sz = d71->max_line_size;
0450             layer->yuv_line_sz = 0;
0451         }
0452     }
0453 
0454     set_range(&layer->hsize_in, 4, layer->line_sz);
0455 
0456     set_range(&layer->vsize_in, 4, d71->max_vsize);
0457 
0458     malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
0459 
0460     layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
0461 
0462     return 0;
0463 }
0464 
0465 static void d71_wb_layer_update(struct komeda_component *c,
0466                 struct komeda_component_state *state)
0467 {
0468     struct komeda_layer_state *st = to_layer_st(state);
0469     struct drm_connector_state *conn_st = state->wb_conn->state;
0470     struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);
0471     u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN;
0472     u32 __iomem *reg = c->reg;
0473 
0474     d71_layer_update_fb(c, kfb, st->addr);
0475 
0476     if (kfb->is_va)
0477         ctrl |= LW_TBU_EN;
0478 
0479     malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
0480     malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
0481     malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
0482 }
0483 
0484 static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf)
0485 {
0486     u32 v[12], i;
0487 
0488     dump_block_header(sf, c->reg);
0489 
0490     get_values_from_reg(c->reg, 0x80, 1, v);
0491     seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]);
0492 
0493     get_values_from_reg(c->reg, 0xD0, 3, v);
0494     seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]);
0495     seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]);
0496     seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]);
0497 
0498     get_values_from_reg(c->reg, 0xE0, 1, v);
0499     seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]);
0500 
0501     for (i = 0; i < 2; i++) {
0502         get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v);
0503         seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]);
0504         seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]);
0505         seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]);
0506     }
0507 
0508     get_values_from_reg(c->reg, 0x130, 12, v);
0509     for (i = 0; i < 12; i++)
0510         seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
0511 }
0512 
0513 static void d71_wb_layer_disable(struct komeda_component *c)
0514 {
0515     malidp_write32(c->reg, BLK_INPUT_ID0, 0);
0516     malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
0517 }
0518 
0519 static const struct komeda_component_funcs d71_wb_layer_funcs = {
0520     .update     = d71_wb_layer_update,
0521     .disable    = d71_wb_layer_disable,
0522     .dump_register  = d71_wb_layer_dump,
0523 };
0524 
0525 static int d71_wb_layer_init(struct d71_dev *d71,
0526                  struct block_header *blk, u32 __iomem *reg)
0527 {
0528     struct komeda_component *c;
0529     struct komeda_layer *wb_layer;
0530     u32 pipe_id, layer_id;
0531 
0532     get_resources_id(blk->block_info, &pipe_id, &layer_id);
0533 
0534     c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer),
0535                  layer_id, BLOCK_INFO_INPUT_ID(blk->block_info),
0536                  &d71_wb_layer_funcs,
0537                  1, get_valid_inputs(blk), 0, reg,
0538                  "LPU%d_LAYER_WR", pipe_id);
0539     if (IS_ERR(c)) {
0540         DRM_ERROR("Failed to add wb_layer component\n");
0541         return PTR_ERR(c);
0542     }
0543 
0544     wb_layer = to_layer(c);
0545     wb_layer->layer_type = KOMEDA_FMT_WB_LAYER;
0546     wb_layer->line_sz = get_blk_line_size(d71, reg);
0547     wb_layer->yuv_line_sz = wb_layer->line_sz;
0548 
0549     set_range(&wb_layer->hsize_in, 64, wb_layer->line_sz);
0550     set_range(&wb_layer->vsize_in, 64, d71->max_vsize);
0551 
0552     return 0;
0553 }
0554 
0555 static void d71_component_disable(struct komeda_component *c)
0556 {
0557     u32 __iomem *reg = c->reg;
0558     u32 i;
0559 
0560     malidp_write32(reg, BLK_CONTROL, 0);
0561 
0562     for (i = 0; i < c->max_active_inputs; i++) {
0563         malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
0564 
0565         /* Besides clearing the input ID to zero, D71 compiz also has
0566          * input enable bit in CU_INPUTx_CONTROL which need to be
0567          * cleared.
0568          */
0569         if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS))
0570             malidp_write32(reg, CU_INPUT0_CONTROL +
0571                        i * CU_PER_INPUT_REGS * 4,
0572                        CU_INPUT_CTRL_ALPHA(0xFF));
0573     }
0574 }
0575 
0576 static void compiz_enable_input(u32 __iomem *id_reg,
0577                 u32 __iomem *cfg_reg,
0578                 u32 input_hw_id,
0579                 struct komeda_compiz_input_cfg *cin)
0580 {
0581     u32 ctrl = CU_INPUT_CTRL_EN;
0582     u8 blend = cin->pixel_blend_mode;
0583 
0584     if (blend == DRM_MODE_BLEND_PIXEL_NONE)
0585         ctrl |= CU_INPUT_CTRL_PAD;
0586     else if (blend == DRM_MODE_BLEND_PREMULTI)
0587         ctrl |= CU_INPUT_CTRL_PMUL;
0588 
0589     ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
0590 
0591     malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
0592 
0593     malidp_write32(cfg_reg, CU_INPUT0_SIZE,
0594                HV_SIZE(cin->hsize, cin->vsize));
0595     malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
0596                HV_OFFSET(cin->hoffset, cin->voffset));
0597     malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
0598 }
0599 
0600 static void d71_compiz_update(struct komeda_component *c,
0601                   struct komeda_component_state *state)
0602 {
0603     struct komeda_compiz_state *st = to_compiz_st(state);
0604     u32 __iomem *reg = c->reg;
0605     u32 __iomem *id_reg, *cfg_reg;
0606     u32 index;
0607 
0608     for_each_changed_input(state, index) {
0609         id_reg = reg + index;
0610         cfg_reg = reg + index * CU_PER_INPUT_REGS;
0611         if (state->active_inputs & BIT(index)) {
0612             compiz_enable_input(id_reg, cfg_reg,
0613                         to_d71_input_id(state, index),
0614                         &st->cins[index]);
0615         } else {
0616             malidp_write32(id_reg, BLK_INPUT_ID0, 0);
0617             malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
0618         }
0619     }
0620 
0621     malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
0622 }
0623 
0624 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
0625 {
0626     u32 v[8], i;
0627 
0628     dump_block_header(sf, c->reg);
0629 
0630     get_values_from_reg(c->reg, 0x80, 5, v);
0631     for (i = 0; i < 5; i++)
0632         seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
0633 
0634     get_values_from_reg(c->reg, 0xA0, 5, v);
0635     seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
0636     seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
0637     seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
0638     seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
0639     seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
0640 
0641     get_values_from_reg(c->reg, 0xD0, 2, v);
0642     seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
0643     seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
0644 
0645     get_values_from_reg(c->reg, 0xDC, 1, v);
0646     seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
0647 
0648     for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
0649         get_values_from_reg(c->reg, v[4], 3, v);
0650         seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
0651         seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
0652         seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
0653     }
0654 
0655     get_values_from_reg(c->reg, 0x130, 2, v);
0656     seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
0657     seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
0658 }
0659 
0660 static const struct komeda_component_funcs d71_compiz_funcs = {
0661     .update     = d71_compiz_update,
0662     .disable    = d71_component_disable,
0663     .dump_register  = d71_compiz_dump,
0664 };
0665 
0666 static int d71_compiz_init(struct d71_dev *d71,
0667                struct block_header *blk, u32 __iomem *reg)
0668 {
0669     struct komeda_component *c;
0670     struct komeda_compiz *compiz;
0671     u32 pipe_id, comp_id;
0672 
0673     get_resources_id(blk->block_info, &pipe_id, &comp_id);
0674 
0675     c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
0676                  comp_id,
0677                  BLOCK_INFO_INPUT_ID(blk->block_info),
0678                  &d71_compiz_funcs,
0679                  CU_NUM_INPUT_IDS, get_valid_inputs(blk),
0680                  CU_NUM_OUTPUT_IDS, reg,
0681                  "CU%d", pipe_id);
0682     if (IS_ERR(c))
0683         return PTR_ERR(c);
0684 
0685     compiz = to_compiz(c);
0686 
0687     set_range(&compiz->hsize, 64, get_blk_line_size(d71, reg));
0688     set_range(&compiz->vsize, 64, d71->max_vsize);
0689 
0690     return 0;
0691 }
0692 
0693 static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in,
0694                      u32 vsize_in, u32 hsize_out,
0695                      u32 vsize_out)
0696 {
0697     u32 val = 0;
0698 
0699     if (hsize_in <= hsize_out)
0700         val  |= 0x62;
0701     else if (hsize_in <= (hsize_out + hsize_out / 2))
0702         val |= 0x63;
0703     else if (hsize_in <= hsize_out * 2)
0704         val |= 0x64;
0705     else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4)
0706         val |= 0x65;
0707     else
0708         val |= 0x66;
0709 
0710     if (vsize_in <= vsize_out)
0711         val  |= SC_VTSEL(0x6A);
0712     else if (vsize_in <= (vsize_out + vsize_out / 2))
0713         val |= SC_VTSEL(0x6B);
0714     else if (vsize_in <= vsize_out * 2)
0715         val |= SC_VTSEL(0x6C);
0716     else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4)
0717         val |= SC_VTSEL(0x6D);
0718     else
0719         val |= SC_VTSEL(0x6E);
0720 
0721     malidp_write32(reg, SC_COEFFTAB, val);
0722 }
0723 
0724 static void d71_scaler_update(struct komeda_component *c,
0725                   struct komeda_component_state *state)
0726 {
0727     struct komeda_scaler_state *st = to_scaler_st(state);
0728     u32 __iomem *reg = c->reg;
0729     u32 init_ph, delta_ph, ctrl;
0730 
0731     d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in,
0732                      st->hsize_out, st->vsize_out);
0733 
0734     malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));
0735     malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));
0736     malidp_write32(reg, SC_H_CROP, HV_CROP(st->left_crop, st->right_crop));
0737 
0738     /* for right part, HW only sample the valid pixel which means the pixels
0739      * in left_crop will be jumpped, and the first sample pixel is:
0740      *
0741      * dst_a = st->total_hsize_out - st->hsize_out + st->left_crop + 0.5;
0742      *
0743      * Then the corresponding texel in src is:
0744      *
0745      * h_delta_phase = st->total_hsize_in / st->total_hsize_out;
0746      * src_a = dst_A * h_delta_phase;
0747      *
0748      * and h_init_phase is src_a deduct the real source start src_S;
0749      *
0750      * src_S = st->total_hsize_in - st->hsize_in;
0751      * h_init_phase = src_a - src_S;
0752      *
0753      * And HW precision for the initial/delta_phase is 16:16 fixed point,
0754      * the following is the simplified formula
0755      */
0756     if (st->right_part) {
0757         u32 dst_a = st->total_hsize_out - st->hsize_out + st->left_crop;
0758 
0759         if (st->en_img_enhancement)
0760             dst_a -= 1;
0761 
0762         init_ph = ((st->total_hsize_in * (2 * dst_a + 1) -
0763                 2 * st->total_hsize_out * (st->total_hsize_in -
0764                 st->hsize_in)) << 15) / st->total_hsize_out;
0765     } else {
0766         init_ph = (st->total_hsize_in << 15) / st->total_hsize_out;
0767     }
0768 
0769     malidp_write32(reg, SC_H_INIT_PH, init_ph);
0770 
0771     delta_ph = (st->total_hsize_in << 16) / st->total_hsize_out;
0772     malidp_write32(reg, SC_H_DELTA_PH, delta_ph);
0773 
0774     init_ph = (st->total_vsize_in << 15) / st->vsize_out;
0775     malidp_write32(reg, SC_V_INIT_PH, init_ph);
0776 
0777     delta_ph = (st->total_vsize_in << 16) / st->vsize_out;
0778     malidp_write32(reg, SC_V_DELTA_PH, delta_ph);
0779 
0780     ctrl = 0;
0781     ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;
0782     ctrl |= st->en_alpha ? SC_CTRL_AP : 0;
0783     ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0;
0784     /* If we use the hardware splitter we shouldn't set SC_CTRL_LS */
0785     if (st->en_split &&
0786         state->inputs[0].component->id != KOMEDA_COMPONENT_SPLITTER)
0787         ctrl |= SC_CTRL_LS;
0788 
0789     malidp_write32(reg, BLK_CONTROL, ctrl);
0790     malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
0791 }
0792 
0793 static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)
0794 {
0795     u32 v[10];
0796 
0797     dump_block_header(sf, c->reg);
0798 
0799     get_values_from_reg(c->reg, 0x80, 1, v);
0800     seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]);
0801 
0802     get_values_from_reg(c->reg, 0xD0, 1, v);
0803     seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]);
0804 
0805     get_values_from_reg(c->reg, 0xDC, 9, v);
0806     seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]);
0807     seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]);
0808     seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]);
0809     seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]);
0810     seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]);
0811     seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]);
0812     seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);
0813     seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);
0814     seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]);
0815 
0816     get_values_from_reg(c->reg, 0x130, 10, v);
0817     seq_printf(sf, "SC_ENH_LIMITS:\t\t0x%X\n", v[0]);
0818     seq_printf(sf, "SC_ENH_COEFF0:\t\t0x%X\n", v[1]);
0819     seq_printf(sf, "SC_ENH_COEFF1:\t\t0x%X\n", v[2]);
0820     seq_printf(sf, "SC_ENH_COEFF2:\t\t0x%X\n", v[3]);
0821     seq_printf(sf, "SC_ENH_COEFF3:\t\t0x%X\n", v[4]);
0822     seq_printf(sf, "SC_ENH_COEFF4:\t\t0x%X\n", v[5]);
0823     seq_printf(sf, "SC_ENH_COEFF5:\t\t0x%X\n", v[6]);
0824     seq_printf(sf, "SC_ENH_COEFF6:\t\t0x%X\n", v[7]);
0825     seq_printf(sf, "SC_ENH_COEFF7:\t\t0x%X\n", v[8]);
0826     seq_printf(sf, "SC_ENH_COEFF8:\t\t0x%X\n", v[9]);
0827 }
0828 
0829 static const struct komeda_component_funcs d71_scaler_funcs = {
0830     .update     = d71_scaler_update,
0831     .disable    = d71_component_disable,
0832     .dump_register  = d71_scaler_dump,
0833 };
0834 
0835 static int d71_scaler_init(struct d71_dev *d71,
0836                struct block_header *blk, u32 __iomem *reg)
0837 {
0838     struct komeda_component *c;
0839     struct komeda_scaler *scaler;
0840     u32 pipe_id, comp_id;
0841 
0842     get_resources_id(blk->block_info, &pipe_id, &comp_id);
0843 
0844     c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler),
0845                  comp_id, BLOCK_INFO_INPUT_ID(blk->block_info),
0846                  &d71_scaler_funcs,
0847                  1, get_valid_inputs(blk), 1, reg,
0848                  "CU%d_SCALER%d",
0849                  pipe_id, BLOCK_INFO_BLK_ID(blk->block_info));
0850 
0851     if (IS_ERR(c)) {
0852         DRM_ERROR("Failed to initialize scaler");
0853         return PTR_ERR(c);
0854     }
0855 
0856     scaler = to_scaler(c);
0857     set_range(&scaler->hsize, 4, __get_blk_line_size(d71, reg, 2048));
0858     set_range(&scaler->vsize, 4, 4096);
0859     scaler->max_downscaling = 6;
0860     scaler->max_upscaling = 64;
0861     scaler->scaling_split_overlap = 8;
0862     scaler->enh_split_overlap = 1;
0863 
0864     malidp_write32(c->reg, BLK_CONTROL, 0);
0865 
0866     return 0;
0867 }
0868 
0869 static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
0870                      struct drm_display_mode *mode,
0871                      unsigned long aclk_rate,
0872                      struct komeda_data_flow_cfg *dflow)
0873 {
0874     u32 h_in = dflow->in_w;
0875     u32 v_in = dflow->in_h;
0876     u32 v_out = dflow->out_h;
0877     u64 fraction, denominator;
0878 
0879     /* D71 downscaling must satisfy the following equation
0880      *
0881      *   ACLK                   h_in * v_in
0882      * ------- >= ---------------------------------------------
0883      *  PXLCLK     (h_total - (1 + 2 * v_in / v_out)) * v_out
0884      *
0885      * In only horizontal downscaling situation, the right side should be
0886      * multiplied by (h_total - 3) / (h_active - 3), then equation becomes
0887      *
0888      *   ACLK          h_in
0889      * ------- >= ----------------
0890      *  PXLCLK     (h_active - 3)
0891      *
0892      * To avoid precision lost the equation 1 will be convert to:
0893      *
0894      *   ACLK             h_in * v_in
0895      * ------- >= -----------------------------------
0896      *  PXLCLK     (h_total -1 ) * v_out -  2 * v_in
0897      */
0898     if (v_in == v_out) {
0899         fraction = h_in;
0900         denominator = mode->hdisplay - 3;
0901     } else {
0902         fraction = h_in * v_in;
0903         denominator = (mode->htotal - 1) * v_out -  2 * v_in;
0904     }
0905 
0906     return aclk_rate * denominator >= mode->crtc_clock * 1000 * fraction ?
0907            0 : -EINVAL;
0908 }
0909 
0910 static void d71_splitter_update(struct komeda_component *c,
0911                 struct komeda_component_state *state)
0912 {
0913     struct komeda_splitter_state *st = to_splitter_st(state);
0914     u32 __iomem *reg = c->reg;
0915 
0916     malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
0917     malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
0918     malidp_write32(reg, SP_OVERLAP_SIZE, st->overlap & 0x1FFF);
0919     malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
0920 }
0921 
0922 static void d71_splitter_dump(struct komeda_component *c, struct seq_file *sf)
0923 {
0924     u32 v[3];
0925 
0926     dump_block_header(sf, c->reg);
0927 
0928     get_values_from_reg(c->reg, BLK_INPUT_ID0, 1, v);
0929     seq_printf(sf, "SP_INPUT_ID0:\t\t0x%X\n", v[0]);
0930 
0931     get_values_from_reg(c->reg, BLK_CONTROL, 3, v);
0932     seq_printf(sf, "SP_CONTROL:\t\t0x%X\n", v[0]);
0933     seq_printf(sf, "SP_SIZE:\t\t0x%X\n", v[1]);
0934     seq_printf(sf, "SP_OVERLAP_SIZE:\t0x%X\n", v[2]);
0935 }
0936 
0937 static const struct komeda_component_funcs d71_splitter_funcs = {
0938     .update     = d71_splitter_update,
0939     .disable    = d71_component_disable,
0940     .dump_register  = d71_splitter_dump,
0941 };
0942 
0943 static int d71_splitter_init(struct d71_dev *d71,
0944                  struct block_header *blk, u32 __iomem *reg)
0945 {
0946     struct komeda_component *c;
0947     struct komeda_splitter *splitter;
0948     u32 pipe_id, comp_id;
0949 
0950     get_resources_id(blk->block_info, &pipe_id, &comp_id);
0951 
0952     c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*splitter),
0953                  comp_id,
0954                  BLOCK_INFO_INPUT_ID(blk->block_info),
0955                  &d71_splitter_funcs,
0956                  1, get_valid_inputs(blk), 2, reg,
0957                  "CU%d_SPLITTER", pipe_id);
0958 
0959     if (IS_ERR(c)) {
0960         DRM_ERROR("Failed to initialize splitter");
0961         return -1;
0962     }
0963 
0964     splitter = to_splitter(c);
0965 
0966     set_range(&splitter->hsize, 4, get_blk_line_size(d71, reg));
0967     set_range(&splitter->vsize, 4, d71->max_vsize);
0968 
0969     return 0;
0970 }
0971 
0972 static void d71_merger_update(struct komeda_component *c,
0973                   struct komeda_component_state *state)
0974 {
0975     struct komeda_merger_state *st = to_merger_st(state);
0976     u32 __iomem *reg = c->reg;
0977     u32 index;
0978 
0979     for_each_changed_input(state, index)
0980         malidp_write32(reg, MG_INPUT_ID0 + index * 4,
0981                    to_d71_input_id(state, index));
0982 
0983     malidp_write32(reg, MG_SIZE, HV_SIZE(st->hsize_merged,
0984                          st->vsize_merged));
0985     malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
0986 }
0987 
0988 static void d71_merger_dump(struct komeda_component *c, struct seq_file *sf)
0989 {
0990     u32 v;
0991 
0992     dump_block_header(sf, c->reg);
0993 
0994     get_values_from_reg(c->reg, MG_INPUT_ID0, 1, &v);
0995     seq_printf(sf, "MG_INPUT_ID0:\t\t0x%X\n", v);
0996 
0997     get_values_from_reg(c->reg, MG_INPUT_ID1, 1, &v);
0998     seq_printf(sf, "MG_INPUT_ID1:\t\t0x%X\n", v);
0999 
1000     get_values_from_reg(c->reg, BLK_CONTROL, 1, &v);
1001     seq_printf(sf, "MG_CONTROL:\t\t0x%X\n", v);
1002 
1003     get_values_from_reg(c->reg, MG_SIZE, 1, &v);
1004     seq_printf(sf, "MG_SIZE:\t\t0x%X\n", v);
1005 }
1006 
1007 static const struct komeda_component_funcs d71_merger_funcs = {
1008     .update     = d71_merger_update,
1009     .disable    = d71_component_disable,
1010     .dump_register  = d71_merger_dump,
1011 };
1012 
1013 static int d71_merger_init(struct d71_dev *d71,
1014                struct block_header *blk, u32 __iomem *reg)
1015 {
1016     struct komeda_component *c;
1017     struct komeda_merger *merger;
1018     u32 pipe_id, comp_id;
1019 
1020     get_resources_id(blk->block_info, &pipe_id, &comp_id);
1021 
1022     c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*merger),
1023                  comp_id,
1024                  BLOCK_INFO_INPUT_ID(blk->block_info),
1025                  &d71_merger_funcs,
1026                  MG_NUM_INPUTS_IDS, get_valid_inputs(blk),
1027                  MG_NUM_OUTPUTS_IDS, reg,
1028                  "CU%d_MERGER", pipe_id);
1029 
1030     if (IS_ERR(c)) {
1031         DRM_ERROR("Failed to initialize merger.\n");
1032         return PTR_ERR(c);
1033     }
1034 
1035     merger = to_merger(c);
1036 
1037     set_range(&merger->hsize_merged, 4,
1038           __get_blk_line_size(d71, reg, 4032));
1039     set_range(&merger->vsize_merged, 4, 4096);
1040 
1041     return 0;
1042 }
1043 
1044 static void d71_improc_update(struct komeda_component *c,
1045                   struct komeda_component_state *state)
1046 {
1047     struct drm_crtc_state *crtc_st = state->crtc->state;
1048     struct komeda_improc_state *st = to_improc_st(state);
1049     struct d71_pipeline *pipe = to_d71_pipeline(c->pipeline);
1050     u32 __iomem *reg = c->reg;
1051     u32 index, mask = 0, ctrl = 0;
1052 
1053     for_each_changed_input(state, index)
1054         malidp_write32(reg, BLK_INPUT_ID0 + index * 4,
1055                    to_d71_input_id(state, index));
1056 
1057     malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
1058     malidp_write32(reg, IPS_DEPTH, st->color_depth);
1059 
1060     if (crtc_st->color_mgmt_changed) {
1061         mask |= IPS_CTRL_FT | IPS_CTRL_RGB;
1062 
1063         if (crtc_st->gamma_lut) {
1064             malidp_write_group(pipe->dou_ft_coeff_addr, FT_COEFF0,
1065                        KOMEDA_N_GAMMA_COEFFS,
1066                        st->fgamma_coeffs);
1067             ctrl |= IPS_CTRL_FT; /* enable gamma */
1068         }
1069 
1070         if (crtc_st->ctm) {
1071             malidp_write_group(reg, IPS_RGB_RGB_COEFF0,
1072                        KOMEDA_N_CTM_COEFFS,
1073                        st->ctm_coeffs);
1074             ctrl |= IPS_CTRL_RGB; /* enable gamut */
1075         }
1076     }
1077 
1078     mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420;
1079 
1080     /* config color format */
1081     if (st->color_format == DRM_COLOR_FORMAT_YCBCR420)
1082         ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420;
1083     else if (st->color_format == DRM_COLOR_FORMAT_YCBCR422)
1084         ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422;
1085     else if (st->color_format == DRM_COLOR_FORMAT_YCBCR444)
1086         ctrl |= IPS_CTRL_YUV;
1087 
1088     malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
1089 }
1090 
1091 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
1092 {
1093     u32 v[12], i;
1094 
1095     dump_block_header(sf, c->reg);
1096 
1097     get_values_from_reg(c->reg, 0x80, 2, v);
1098     seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
1099     seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
1100 
1101     get_values_from_reg(c->reg, 0xC0, 1, v);
1102     seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
1103 
1104     get_values_from_reg(c->reg, 0xD0, 3, v);
1105     seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
1106     seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
1107     seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
1108 
1109     get_values_from_reg(c->reg, 0x130, 12, v);
1110     for (i = 0; i < 12; i++)
1111         seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
1112 
1113     get_values_from_reg(c->reg, 0x170, 12, v);
1114     for (i = 0; i < 12; i++)
1115         seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
1116 }
1117 
1118 static const struct komeda_component_funcs d71_improc_funcs = {
1119     .update     = d71_improc_update,
1120     .disable    = d71_component_disable,
1121     .dump_register  = d71_improc_dump,
1122 };
1123 
1124 static int d71_improc_init(struct d71_dev *d71,
1125                struct block_header *blk, u32 __iomem *reg)
1126 {
1127     struct komeda_component *c;
1128     struct komeda_improc *improc;
1129     u32 pipe_id, comp_id, value;
1130 
1131     get_resources_id(blk->block_info, &pipe_id, &comp_id);
1132 
1133     c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),
1134                  comp_id,
1135                  BLOCK_INFO_INPUT_ID(blk->block_info),
1136                  &d71_improc_funcs, IPS_NUM_INPUT_IDS,
1137                  get_valid_inputs(blk),
1138                  IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);
1139     if (IS_ERR(c)) {
1140         DRM_ERROR("Failed to add improc component\n");
1141         return PTR_ERR(c);
1142     }
1143 
1144     improc = to_improc(c);
1145     improc->supported_color_depths = BIT(8) | BIT(10);
1146     improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
1147                       DRM_COLOR_FORMAT_YCBCR444 |
1148                       DRM_COLOR_FORMAT_YCBCR422;
1149     value = malidp_read32(reg, BLK_INFO);
1150     if (value & IPS_INFO_CHD420)
1151         improc->supported_color_formats |= DRM_COLOR_FORMAT_YCBCR420;
1152 
1153     improc->supports_csc = true;
1154     improc->supports_gamma = true;
1155 
1156     return 0;
1157 }
1158 
1159 static void d71_timing_ctrlr_disable(struct komeda_component *c)
1160 {
1161     malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
1162 }
1163 
1164 static void d71_timing_ctrlr_update(struct komeda_component *c,
1165                     struct komeda_component_state *state)
1166 {
1167     struct drm_crtc_state *crtc_st = state->crtc->state;
1168     struct drm_display_mode *mode = &crtc_st->adjusted_mode;
1169     u32 __iomem *reg = c->reg;
1170     u32 hactive, hfront_porch, hback_porch, hsync_len;
1171     u32 vactive, vfront_porch, vback_porch, vsync_len;
1172     u32 value;
1173 
1174     hactive = mode->crtc_hdisplay;
1175     hfront_porch = mode->crtc_hsync_start - mode->crtc_hdisplay;
1176     hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
1177     hback_porch = mode->crtc_htotal - mode->crtc_hsync_end;
1178 
1179     vactive = mode->crtc_vdisplay;
1180     vfront_porch = mode->crtc_vsync_start - mode->crtc_vdisplay;
1181     vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
1182     vback_porch = mode->crtc_vtotal - mode->crtc_vsync_end;
1183 
1184     malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(hactive, vactive));
1185     malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(hfront_porch,
1186                             hback_porch));
1187     malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vfront_porch,
1188                             vback_porch));
1189 
1190     value = BS_SYNC_VSW(vsync_len) | BS_SYNC_HSW(hsync_len);
1191     value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BS_SYNC_VSP : 0;
1192     value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BS_SYNC_HSP : 0;
1193     malidp_write32(reg, BS_SYNC, value);
1194 
1195     malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
1196     malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);
1197 
1198     /* configure bs control register */
1199     value = BS_CTRL_EN | BS_CTRL_VM;
1200     if (c->pipeline->dual_link) {
1201         malidp_write32(reg, BS_DRIFT_TO, hfront_porch + 16);
1202         value |= BS_CTRL_DL;
1203     }
1204 
1205     malidp_write32(reg, BLK_CONTROL, value);
1206 }
1207 
1208 static void d71_timing_ctrlr_dump(struct komeda_component *c,
1209                   struct seq_file *sf)
1210 {
1211     u32 v[8], i;
1212 
1213     dump_block_header(sf, c->reg);
1214 
1215     get_values_from_reg(c->reg, 0xC0, 1, v);
1216     seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
1217 
1218     get_values_from_reg(c->reg, 0xD0, 8, v);
1219     seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
1220     seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
1221     seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
1222     seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
1223     seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
1224     seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
1225     seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
1226     seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
1227 
1228     get_values_from_reg(c->reg, 0x100, 3, v);
1229     seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
1230     seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
1231     seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
1232 
1233     get_values_from_reg(c->reg, 0x110, 3, v);
1234     for (i = 0; i < 3; i++)
1235         seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
1236 
1237     get_values_from_reg(c->reg, 0x120, 5, v);
1238     for (i = 0; i < 2; i++) {
1239         seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
1240         seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
1241     }
1242     seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
1243 }
1244 
1245 static const struct komeda_component_funcs d71_timing_ctrlr_funcs = {
1246     .update     = d71_timing_ctrlr_update,
1247     .disable    = d71_timing_ctrlr_disable,
1248     .dump_register  = d71_timing_ctrlr_dump,
1249 };
1250 
1251 static int d71_timing_ctrlr_init(struct d71_dev *d71,
1252                  struct block_header *blk, u32 __iomem *reg)
1253 {
1254     struct komeda_component *c;
1255     struct komeda_timing_ctrlr *ctrlr;
1256     u32 pipe_id, comp_id;
1257 
1258     get_resources_id(blk->block_info, &pipe_id, &comp_id);
1259 
1260     c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),
1261                  KOMEDA_COMPONENT_TIMING_CTRLR,
1262                  BLOCK_INFO_INPUT_ID(blk->block_info),
1263                  &d71_timing_ctrlr_funcs,
1264                  1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),
1265                  BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);
1266     if (IS_ERR(c)) {
1267         DRM_ERROR("Failed to add display_ctrl component\n");
1268         return PTR_ERR(c);
1269     }
1270 
1271     ctrlr = to_ctrlr(c);
1272 
1273     ctrlr->supports_dual_link = d71->supports_dual_link;
1274 
1275     return 0;
1276 }
1277 
1278 int d71_probe_block(struct d71_dev *d71,
1279             struct block_header *blk, u32 __iomem *reg)
1280 {
1281     struct d71_pipeline *pipe;
1282     int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
1283 
1284     int err = 0;
1285 
1286     switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
1287     case D71_BLK_TYPE_GCU:
1288         break;
1289 
1290     case D71_BLK_TYPE_LPU:
1291         pipe = d71->pipes[blk_id];
1292         pipe->lpu_addr = reg;
1293         break;
1294 
1295     case D71_BLK_TYPE_LPU_LAYER:
1296         err = d71_layer_init(d71, blk, reg);
1297         break;
1298 
1299     case D71_BLK_TYPE_LPU_WB_LAYER:
1300         err = d71_wb_layer_init(d71, blk, reg);
1301         break;
1302 
1303     case D71_BLK_TYPE_CU:
1304         pipe = d71->pipes[blk_id];
1305         pipe->cu_addr = reg;
1306         err = d71_compiz_init(d71, blk, reg);
1307         break;
1308 
1309     case D71_BLK_TYPE_CU_SCALER:
1310         err = d71_scaler_init(d71, blk, reg);
1311         break;
1312 
1313     case D71_BLK_TYPE_CU_SPLITTER:
1314         err = d71_splitter_init(d71, blk, reg);
1315         break;
1316 
1317     case D71_BLK_TYPE_CU_MERGER:
1318         err = d71_merger_init(d71, blk, reg);
1319         break;
1320 
1321     case D71_BLK_TYPE_DOU:
1322         pipe = d71->pipes[blk_id];
1323         pipe->dou_addr = reg;
1324         break;
1325 
1326     case D71_BLK_TYPE_DOU_IPS:
1327         err = d71_improc_init(d71, blk, reg);
1328         break;
1329 
1330     case D71_BLK_TYPE_DOU_FT_COEFF:
1331         pipe = d71->pipes[blk_id];
1332         pipe->dou_ft_coeff_addr = reg;
1333         break;
1334 
1335     case D71_BLK_TYPE_DOU_BS:
1336         err = d71_timing_ctrlr_init(d71, blk, reg);
1337         break;
1338 
1339     case D71_BLK_TYPE_GLB_LT_COEFF:
1340         break;
1341 
1342     case D71_BLK_TYPE_GLB_SCL_COEFF:
1343         d71->glb_scl_coeff_addr[blk_id] = reg;
1344         break;
1345 
1346     default:
1347         DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
1348               blk->block_info);
1349         err = -EINVAL;
1350         break;
1351     }
1352 
1353     return err;
1354 }
1355 
1356 static void d71_gcu_dump(struct d71_dev *d71, struct seq_file *sf)
1357 {
1358     u32 v[5];
1359 
1360     seq_puts(sf, "\n------ GCU ------\n");
1361 
1362     get_values_from_reg(d71->gcu_addr, 0, 3, v);
1363     seq_printf(sf, "GLB_ARCH_ID:\t\t0x%X\n", v[0]);
1364     seq_printf(sf, "GLB_CORE_ID:\t\t0x%X\n", v[1]);
1365     seq_printf(sf, "GLB_CORE_INFO:\t\t0x%X\n", v[2]);
1366 
1367     get_values_from_reg(d71->gcu_addr, 0x10, 1, v);
1368     seq_printf(sf, "GLB_IRQ_STATUS:\t\t0x%X\n", v[0]);
1369 
1370     get_values_from_reg(d71->gcu_addr, 0xA0, 5, v);
1371     seq_printf(sf, "GCU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
1372     seq_printf(sf, "GCU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
1373     seq_printf(sf, "GCU_IRQ_MASK:\t\t0x%X\n", v[2]);
1374     seq_printf(sf, "GCU_IRQ_STATUS:\t\t0x%X\n", v[3]);
1375     seq_printf(sf, "GCU_STATUS:\t\t0x%X\n", v[4]);
1376 
1377     get_values_from_reg(d71->gcu_addr, 0xD0, 3, v);
1378     seq_printf(sf, "GCU_CONTROL:\t\t0x%X\n", v[0]);
1379     seq_printf(sf, "GCU_CONFIG_VALID0:\t0x%X\n", v[1]);
1380     seq_printf(sf, "GCU_CONFIG_VALID1:\t0x%X\n", v[2]);
1381 }
1382 
1383 static void d71_lpu_dump(struct d71_pipeline *pipe, struct seq_file *sf)
1384 {
1385     u32 v[6];
1386 
1387     seq_printf(sf, "\n------ LPU%d ------\n", pipe->base.id);
1388 
1389     dump_block_header(sf, pipe->lpu_addr);
1390 
1391     get_values_from_reg(pipe->lpu_addr, 0xA0, 6, v);
1392     seq_printf(sf, "LPU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
1393     seq_printf(sf, "LPU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
1394     seq_printf(sf, "LPU_IRQ_MASK:\t\t0x%X\n", v[2]);
1395     seq_printf(sf, "LPU_IRQ_STATUS:\t\t0x%X\n", v[3]);
1396     seq_printf(sf, "LPU_STATUS:\t\t0x%X\n", v[4]);
1397     seq_printf(sf, "LPU_TBU_STATUS:\t\t0x%X\n", v[5]);
1398 
1399     get_values_from_reg(pipe->lpu_addr, 0xC0, 1, v);
1400     seq_printf(sf, "LPU_INFO:\t\t0x%X\n", v[0]);
1401 
1402     get_values_from_reg(pipe->lpu_addr, 0xD0, 3, v);
1403     seq_printf(sf, "LPU_RAXI_CONTROL:\t0x%X\n", v[0]);
1404     seq_printf(sf, "LPU_WAXI_CONTROL:\t0x%X\n", v[1]);
1405     seq_printf(sf, "LPU_TBU_CONTROL:\t0x%X\n", v[2]);
1406 }
1407 
1408 static void d71_dou_dump(struct d71_pipeline *pipe, struct seq_file *sf)
1409 {
1410     u32 v[5];
1411 
1412     seq_printf(sf, "\n------ DOU%d ------\n", pipe->base.id);
1413 
1414     dump_block_header(sf, pipe->dou_addr);
1415 
1416     get_values_from_reg(pipe->dou_addr, 0xA0, 5, v);
1417     seq_printf(sf, "DOU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
1418     seq_printf(sf, "DOU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
1419     seq_printf(sf, "DOU_IRQ_MASK:\t\t0x%X\n", v[2]);
1420     seq_printf(sf, "DOU_IRQ_STATUS:\t\t0x%X\n", v[3]);
1421     seq_printf(sf, "DOU_STATUS:\t\t0x%X\n", v[4]);
1422 }
1423 
1424 static void d71_pipeline_dump(struct komeda_pipeline *pipe, struct seq_file *sf)
1425 {
1426     struct d71_pipeline *d71_pipe = to_d71_pipeline(pipe);
1427 
1428     d71_lpu_dump(d71_pipe, sf);
1429     d71_dou_dump(d71_pipe, sf);
1430 }
1431 
1432 const struct komeda_pipeline_funcs d71_pipeline_funcs = {
1433     .downscaling_clk_check  = d71_downscaling_clk_check,
1434     .dump_register      = d71_pipeline_dump,
1435 };
1436 
1437 void d71_dump(struct komeda_dev *mdev, struct seq_file *sf)
1438 {
1439     struct d71_dev *d71 = mdev->chip_data;
1440 
1441     d71_gcu_dump(d71, sf);
1442 }