root/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_resources_id
  2. get_valid_inputs
  3. get_values_from_reg
  4. dump_block_header
  5. to_rot_ctrl
  6. to_ad_ctrl
  7. to_d71_input_id
  8. d71_layer_update_fb
  9. d71_layer_disable
  10. d71_layer_update
  11. d71_layer_dump
  12. d71_layer_init
  13. d71_wb_layer_update
  14. d71_wb_layer_dump
  15. d71_wb_layer_disable
  16. d71_wb_layer_init
  17. d71_component_disable
  18. compiz_enable_input
  19. d71_compiz_update
  20. d71_compiz_dump
  21. d71_compiz_init
  22. d71_scaler_update_filter_lut
  23. d71_scaler_update
  24. d71_scaler_dump
  25. d71_scaler_init
  26. d71_downscaling_clk_check
  27. d71_splitter_update
  28. d71_splitter_dump
  29. d71_splitter_init
  30. d71_merger_update
  31. d71_merger_dump
  32. d71_merger_init
  33. d71_improc_update
  34. d71_improc_dump
  35. d71_improc_init
  36. d71_timing_ctrlr_disable
  37. d71_timing_ctrlr_update
  38. d71_timing_ctrlr_dump
  39. d71_timing_ctrlr_init
  40. d71_probe_block

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
   4  * Author: James.Qian.Wang <james.qian.wang@arm.com>
   5  *
   6  */
   7 #include "d71_dev.h"
   8 #include "komeda_kms.h"
   9 #include "malidp_io.h"
  10 #include "komeda_framebuffer.h"
  11 #include "komeda_color_mgmt.h"
  12 
  13 static void get_resources_id(u32 hw_id, u32 *pipe_id, u32 *comp_id)
  14 {
  15         u32 id = BLOCK_INFO_BLK_ID(hw_id);
  16         u32 pipe = id;
  17 
  18         switch (BLOCK_INFO_BLK_TYPE(hw_id)) {
  19         case D71_BLK_TYPE_LPU_WB_LAYER:
  20                 id = KOMEDA_COMPONENT_WB_LAYER;
  21                 break;
  22         case D71_BLK_TYPE_CU_SPLITTER:
  23                 id = KOMEDA_COMPONENT_SPLITTER;
  24                 break;
  25         case D71_BLK_TYPE_CU_SCALER:
  26                 pipe = id / D71_PIPELINE_MAX_SCALERS;
  27                 id %= D71_PIPELINE_MAX_SCALERS;
  28                 id += KOMEDA_COMPONENT_SCALER0;
  29                 break;
  30         case D71_BLK_TYPE_CU:
  31                 id += KOMEDA_COMPONENT_COMPIZ0;
  32                 break;
  33         case D71_BLK_TYPE_LPU_LAYER:
  34                 pipe = id / D71_PIPELINE_MAX_LAYERS;
  35                 id %= D71_PIPELINE_MAX_LAYERS;
  36                 id += KOMEDA_COMPONENT_LAYER0;
  37                 break;
  38         case D71_BLK_TYPE_DOU_IPS:
  39                 id += KOMEDA_COMPONENT_IPS0;
  40                 break;
  41         case D71_BLK_TYPE_CU_MERGER:
  42                 id = KOMEDA_COMPONENT_MERGER;
  43                 break;
  44         case D71_BLK_TYPE_DOU:
  45                 id = KOMEDA_COMPONENT_TIMING_CTRLR;
  46                 break;
  47         default:
  48                 id = 0xFFFFFFFF;
  49         }
  50 
  51         if (comp_id)
  52                 *comp_id = id;
  53 
  54         if (pipe_id)
  55                 *pipe_id = pipe;
  56 }
  57 
  58 static u32 get_valid_inputs(struct block_header *blk)
  59 {
  60         u32 valid_inputs = 0, comp_id;
  61         int i;
  62 
  63         for (i = 0; i < PIPELINE_INFO_N_VALID_INPUTS(blk->pipeline_info); i++) {
  64                 get_resources_id(blk->input_ids[i], NULL, &comp_id);
  65                 if (comp_id == 0xFFFFFFFF)
  66                         continue;
  67                 valid_inputs |= BIT(comp_id);
  68         }
  69 
  70         return valid_inputs;
  71 }
  72 
  73 static void get_values_from_reg(void __iomem *reg, u32 offset,
  74                                 u32 count, u32 *val)
  75 {
  76         u32 i, addr;
  77 
  78         for (i = 0; i < count; i++) {
  79                 addr = offset + (i << 2);
  80                 /* 0xA4 is WO register */
  81                 if (addr != 0xA4)
  82                         val[i] = malidp_read32(reg, addr);
  83                 else
  84                         val[i] = 0xDEADDEAD;
  85         }
  86 }
  87 
  88 static void dump_block_header(struct seq_file *sf, void __iomem *reg)
  89 {
  90         struct block_header hdr;
  91         u32 i, n_input, n_output;
  92 
  93         d71_read_block_header(reg, &hdr);
  94         seq_printf(sf, "BLOCK_INFO:\t\t0x%X\n", hdr.block_info);
  95         seq_printf(sf, "PIPELINE_INFO:\t\t0x%X\n", hdr.pipeline_info);
  96 
  97         n_output = PIPELINE_INFO_N_OUTPUTS(hdr.pipeline_info);
  98         n_input  = PIPELINE_INFO_N_VALID_INPUTS(hdr.pipeline_info);
  99 
 100         for (i = 0; i < n_input; i++)
 101                 seq_printf(sf, "VALID_INPUT_ID%u:\t0x%X\n",
 102                            i, hdr.input_ids[i]);
 103 
 104         for (i = 0; i < n_output; i++)
 105                 seq_printf(sf, "OUTPUT_ID%u:\t\t0x%X\n",
 106                            i, hdr.output_ids[i]);
 107 }
 108 
 109 static u32 to_rot_ctrl(u32 rot)
 110 {
 111         u32 lr_ctrl = 0;
 112 
 113         switch (rot & DRM_MODE_ROTATE_MASK) {
 114         case DRM_MODE_ROTATE_0:
 115                 lr_ctrl |= L_ROT(L_ROT_R0);
 116                 break;
 117         case DRM_MODE_ROTATE_90:
 118                 lr_ctrl |= L_ROT(L_ROT_R90);
 119                 break;
 120         case DRM_MODE_ROTATE_180:
 121                 lr_ctrl |= L_ROT(L_ROT_R180);
 122                 break;
 123         case DRM_MODE_ROTATE_270:
 124                 lr_ctrl |= L_ROT(L_ROT_R270);
 125                 break;
 126         }
 127 
 128         if (rot & DRM_MODE_REFLECT_X)
 129                 lr_ctrl |= L_HFLIP;
 130         if (rot & DRM_MODE_REFLECT_Y)
 131                 lr_ctrl |= L_VFLIP;
 132 
 133         return lr_ctrl;
 134 }
 135 
 136 static u32 to_ad_ctrl(u64 modifier)
 137 {
 138         u32 afbc_ctrl = AD_AEN;
 139 
 140         if (!modifier)
 141                 return 0;
 142 
 143         if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
 144             AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
 145                 afbc_ctrl |= AD_WB;
 146 
 147         if (modifier & AFBC_FORMAT_MOD_YTR)
 148                 afbc_ctrl |= AD_YT;
 149         if (modifier & AFBC_FORMAT_MOD_SPLIT)
 150                 afbc_ctrl |= AD_BS;
 151         if (modifier & AFBC_FORMAT_MOD_TILED)
 152                 afbc_ctrl |= AD_TH;
 153 
 154         return afbc_ctrl;
 155 }
 156 
 157 static inline u32 to_d71_input_id(struct komeda_component_state *st, int idx)
 158 {
 159         struct komeda_component_output *input = &st->inputs[idx];
 160 
 161         /* if input is not active, set hw input_id(0) to disable it */
 162         if (has_bit(idx, st->active_inputs))
 163                 return input->component->hw_id + input->output_port;
 164         else
 165                 return 0;
 166 }
 167 
 168 static void d71_layer_update_fb(struct komeda_component *c,
 169                                 struct komeda_fb *kfb,
 170                                 dma_addr_t *addr)
 171 {
 172         struct drm_framebuffer *fb = &kfb->base;
 173         const struct drm_format_info *info = fb->format;
 174         u32 __iomem *reg = c->reg;
 175         int block_h;
 176 
 177         if (info->num_planes > 2)
 178                 malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]);
 179 
 180         if (info->num_planes > 1) {
 181                 block_h = drm_format_info_block_height(info, 1);
 182                 malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h);
 183                 malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]);
 184         }
 185 
 186         block_h = drm_format_info_block_height(info, 0);
 187         malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h);
 188         malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]);
 189         malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
 190 }
 191 
 192 static void d71_layer_disable(struct komeda_component *c)
 193 {
 194         malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
 195 }
 196 
 197 static void d71_layer_update(struct komeda_component *c,
 198                              struct komeda_component_state *state)
 199 {
 200         struct komeda_layer_state *st = to_layer_st(state);
 201         struct drm_plane_state *plane_st = state->plane->state;
 202         struct drm_framebuffer *fb = plane_st->fb;
 203         struct komeda_fb *kfb = to_kfb(fb);
 204         u32 __iomem *reg = c->reg;
 205         u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
 206         u32 ctrl = L_EN | to_rot_ctrl(st->rot);
 207 
 208         d71_layer_update_fb(c, kfb, st->addr);
 209 
 210         malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier));
 211         if (fb->modifier) {
 212                 u64 addr;
 213 
 214                 malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l,
 215                                                              st->afbc_crop_r));
 216                 malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t,
 217                                                              st->afbc_crop_b));
 218                 /* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */
 219                 if (fb->modifier & AFBC_FORMAT_MOD_TILED)
 220                         addr = st->addr[0] + kfb->offset_payload;
 221                 else
 222                         addr = st->addr[0] + kfb->afbc_size - 1;
 223 
 224                 malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr));
 225                 malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr));
 226         }
 227 
 228         if (fb->format->is_yuv) {
 229                 u32 upsampling = 0;
 230 
 231                 switch (kfb->format_caps->fourcc) {
 232                 case DRM_FORMAT_YUYV:
 233                         upsampling = fb->modifier ? LR_CHI422_BILINEAR :
 234                                      LR_CHI422_REPLICATION;
 235                         break;
 236                 case DRM_FORMAT_UYVY:
 237                         upsampling = LR_CHI422_REPLICATION;
 238                         break;
 239                 case DRM_FORMAT_NV12:
 240                 case DRM_FORMAT_YUV420_8BIT:
 241                 case DRM_FORMAT_YUV420_10BIT:
 242                 case DRM_FORMAT_YUV420:
 243                 case DRM_FORMAT_P010:
 244                 /* these fmt support MPGE/JPEG both, here perfer JPEG*/
 245                         upsampling = LR_CHI420_JPEG;
 246                         break;
 247                 case DRM_FORMAT_X0L2:
 248                         upsampling = LR_CHI420_JPEG;
 249                         break;
 250                 default:
 251                         break;
 252                 }
 253 
 254                 malidp_write32(reg, LAYER_R_CONTROL, upsampling);
 255                 malidp_write_group(reg, LAYER_YUV_RGB_COEFF0,
 256                                    KOMEDA_N_YUV2RGB_COEFFS,
 257                                    komeda_select_yuv2rgb_coeffs(
 258                                         plane_st->color_encoding,
 259                                         plane_st->color_range));
 260         }
 261 
 262         malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
 263 
 264         if (kfb->is_va)
 265                 ctrl |= L_TBU_EN;
 266         malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
 267 }
 268 
 269 static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
 270 {
 271         u32 v[15], i;
 272         bool rich, rgb2rgb;
 273         char *prefix;
 274 
 275         get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
 276         if (v[14] & 0x1) {
 277                 rich = true;
 278                 prefix = "LR_";
 279         } else {
 280                 rich = false;
 281                 prefix = "LS_";
 282         }
 283 
 284         rgb2rgb = !!(v[14] & L_INFO_CM);
 285 
 286         dump_block_header(sf, c->reg);
 287 
 288         seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
 289 
 290         get_values_from_reg(c->reg, 0xD0, 1, v);
 291         seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
 292         if (rich) {
 293                 get_values_from_reg(c->reg, 0xD4, 1, v);
 294                 seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
 295         }
 296         get_values_from_reg(c->reg, 0xD8, 4, v);
 297         seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
 298         seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
 299         seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
 300         seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
 301 
 302         get_values_from_reg(c->reg, 0x100, 3, v);
 303         seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
 304         seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
 305         seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
 306 
 307         get_values_from_reg(c->reg, 0x110, 2, v);
 308         seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
 309         seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
 310         if (rich) {
 311                 get_values_from_reg(c->reg, 0x118, 1, v);
 312                 seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
 313 
 314                 get_values_from_reg(c->reg, 0x120, 2, v);
 315                 seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
 316                 seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
 317 
 318                 get_values_from_reg(c->reg, 0x130, 12, v);
 319                 for (i = 0; i < 12; i++)
 320                         seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
 321         }
 322 
 323         if (rgb2rgb) {
 324                 get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
 325                 for (i = 0; i < 12; i++)
 326                         seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
 327         }
 328 
 329         get_values_from_reg(c->reg, 0x160, 3, v);
 330         seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
 331         seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
 332         seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
 333 }
 334 
 335 static const struct komeda_component_funcs d71_layer_funcs = {
 336         .update         = d71_layer_update,
 337         .disable        = d71_layer_disable,
 338         .dump_register  = d71_layer_dump,
 339 };
 340 
 341 static int d71_layer_init(struct d71_dev *d71,
 342                           struct block_header *blk, u32 __iomem *reg)
 343 {
 344         struct komeda_component *c;
 345         struct komeda_layer *layer;
 346         u32 pipe_id, layer_id, layer_info;
 347 
 348         get_resources_id(blk->block_info, &pipe_id, &layer_id);
 349         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
 350                                  layer_id,
 351                                  BLOCK_INFO_INPUT_ID(blk->block_info),
 352                                  &d71_layer_funcs, 0,
 353                                  get_valid_inputs(blk),
 354                                  1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
 355         if (IS_ERR(c)) {
 356                 DRM_ERROR("Failed to add layer component\n");
 357                 return PTR_ERR(c);
 358         }
 359 
 360         layer = to_layer(c);
 361         layer_info = malidp_read32(reg, LAYER_INFO);
 362 
 363         if (layer_info & L_INFO_RF)
 364                 layer->layer_type = KOMEDA_FMT_RICH_LAYER;
 365         else
 366                 layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
 367 
 368         set_range(&layer->hsize_in, 4, d71->max_line_size);
 369         set_range(&layer->vsize_in, 4, d71->max_vsize);
 370 
 371         malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
 372 
 373         layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
 374 
 375         return 0;
 376 }
 377 
 378 static void d71_wb_layer_update(struct komeda_component *c,
 379                                 struct komeda_component_state *state)
 380 {
 381         struct komeda_layer_state *st = to_layer_st(state);
 382         struct drm_connector_state *conn_st = state->wb_conn->state;
 383         struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);
 384         u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN;
 385         u32 __iomem *reg = c->reg;
 386 
 387         d71_layer_update_fb(c, kfb, st->addr);
 388 
 389         if (kfb->is_va)
 390                 ctrl |= LW_TBU_EN;
 391 
 392         malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
 393         malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
 394         malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
 395 }
 396 
 397 static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf)
 398 {
 399         u32 v[12], i;
 400 
 401         dump_block_header(sf, c->reg);
 402 
 403         get_values_from_reg(c->reg, 0x80, 1, v);
 404         seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]);
 405 
 406         get_values_from_reg(c->reg, 0xD0, 3, v);
 407         seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]);
 408         seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]);
 409         seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]);
 410 
 411         get_values_from_reg(c->reg, 0xE0, 1, v);
 412         seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]);
 413 
 414         for (i = 0; i < 2; i++) {
 415                 get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v);
 416                 seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]);
 417                 seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]);
 418                 seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]);
 419         }
 420 
 421         get_values_from_reg(c->reg, 0x130, 12, v);
 422         for (i = 0; i < 12; i++)
 423                 seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
 424 }
 425 
 426 static void d71_wb_layer_disable(struct komeda_component *c)
 427 {
 428         malidp_write32(c->reg, BLK_INPUT_ID0, 0);
 429         malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
 430 }
 431 
 432 static const struct komeda_component_funcs d71_wb_layer_funcs = {
 433         .update         = d71_wb_layer_update,
 434         .disable        = d71_wb_layer_disable,
 435         .dump_register  = d71_wb_layer_dump,
 436 };
 437 
 438 static int d71_wb_layer_init(struct d71_dev *d71,
 439                              struct block_header *blk, u32 __iomem *reg)
 440 {
 441         struct komeda_component *c;
 442         struct komeda_layer *wb_layer;
 443         u32 pipe_id, layer_id;
 444 
 445         get_resources_id(blk->block_info, &pipe_id, &layer_id);
 446 
 447         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer),
 448                                  layer_id, BLOCK_INFO_INPUT_ID(blk->block_info),
 449                                  &d71_wb_layer_funcs,
 450                                  1, get_valid_inputs(blk), 0, reg,
 451                                  "LPU%d_LAYER_WR", pipe_id);
 452         if (IS_ERR(c)) {
 453                 DRM_ERROR("Failed to add wb_layer component\n");
 454                 return PTR_ERR(c);
 455         }
 456 
 457         wb_layer = to_layer(c);
 458         wb_layer->layer_type = KOMEDA_FMT_WB_LAYER;
 459 
 460         set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size);
 461         set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
 462 
 463         return 0;
 464 }
 465 
 466 static void d71_component_disable(struct komeda_component *c)
 467 {
 468         u32 __iomem *reg = c->reg;
 469         u32 i;
 470 
 471         malidp_write32(reg, BLK_CONTROL, 0);
 472 
 473         for (i = 0; i < c->max_active_inputs; i++) {
 474                 malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
 475 
 476                 /* Besides clearing the input ID to zero, D71 compiz also has
 477                  * input enable bit in CU_INPUTx_CONTROL which need to be
 478                  * cleared.
 479                  */
 480                 if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS))
 481                         malidp_write32(reg, CU_INPUT0_CONTROL +
 482                                        i * CU_PER_INPUT_REGS * 4,
 483                                        CU_INPUT_CTRL_ALPHA(0xFF));
 484         }
 485 }
 486 
 487 static void compiz_enable_input(u32 __iomem *id_reg,
 488                                 u32 __iomem *cfg_reg,
 489                                 u32 input_hw_id,
 490                                 struct komeda_compiz_input_cfg *cin)
 491 {
 492         u32 ctrl = CU_INPUT_CTRL_EN;
 493         u8 blend = cin->pixel_blend_mode;
 494 
 495         if (blend == DRM_MODE_BLEND_PIXEL_NONE)
 496                 ctrl |= CU_INPUT_CTRL_PAD;
 497         else if (blend == DRM_MODE_BLEND_PREMULTI)
 498                 ctrl |= CU_INPUT_CTRL_PMUL;
 499 
 500         ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
 501 
 502         malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
 503 
 504         malidp_write32(cfg_reg, CU_INPUT0_SIZE,
 505                        HV_SIZE(cin->hsize, cin->vsize));
 506         malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
 507                        HV_OFFSET(cin->hoffset, cin->voffset));
 508         malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
 509 }
 510 
 511 static void d71_compiz_update(struct komeda_component *c,
 512                               struct komeda_component_state *state)
 513 {
 514         struct komeda_compiz_state *st = to_compiz_st(state);
 515         u32 __iomem *reg = c->reg;
 516         u32 __iomem *id_reg, *cfg_reg;
 517         u32 index;
 518 
 519         for_each_changed_input(state, index) {
 520                 id_reg = reg + index;
 521                 cfg_reg = reg + index * CU_PER_INPUT_REGS;
 522                 if (state->active_inputs & BIT(index)) {
 523                         compiz_enable_input(id_reg, cfg_reg,
 524                                             to_d71_input_id(state, index),
 525                                             &st->cins[index]);
 526                 } else {
 527                         malidp_write32(id_reg, BLK_INPUT_ID0, 0);
 528                         malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
 529                 }
 530         }
 531 
 532         malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
 533 }
 534 
 535 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
 536 {
 537         u32 v[8], i;
 538 
 539         dump_block_header(sf, c->reg);
 540 
 541         get_values_from_reg(c->reg, 0x80, 5, v);
 542         for (i = 0; i < 5; i++)
 543                 seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
 544 
 545         get_values_from_reg(c->reg, 0xA0, 5, v);
 546         seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
 547         seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
 548         seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
 549         seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
 550         seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
 551 
 552         get_values_from_reg(c->reg, 0xD0, 2, v);
 553         seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
 554         seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
 555 
 556         get_values_from_reg(c->reg, 0xDC, 1, v);
 557         seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
 558 
 559         for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
 560                 get_values_from_reg(c->reg, v[4], 3, v);
 561                 seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
 562                 seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
 563                 seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
 564         }
 565 
 566         get_values_from_reg(c->reg, 0x130, 2, v);
 567         seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
 568         seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
 569 }
 570 
 571 static const struct komeda_component_funcs d71_compiz_funcs = {
 572         .update         = d71_compiz_update,
 573         .disable        = d71_component_disable,
 574         .dump_register  = d71_compiz_dump,
 575 };
 576 
 577 static int d71_compiz_init(struct d71_dev *d71,
 578                            struct block_header *blk, u32 __iomem *reg)
 579 {
 580         struct komeda_component *c;
 581         struct komeda_compiz *compiz;
 582         u32 pipe_id, comp_id;
 583 
 584         get_resources_id(blk->block_info, &pipe_id, &comp_id);
 585 
 586         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
 587                                  comp_id,
 588                                  BLOCK_INFO_INPUT_ID(blk->block_info),
 589                                  &d71_compiz_funcs,
 590                                  CU_NUM_INPUT_IDS, get_valid_inputs(blk),
 591                                  CU_NUM_OUTPUT_IDS, reg,
 592                                  "CU%d", pipe_id);
 593         if (IS_ERR(c))
 594                 return PTR_ERR(c);
 595 
 596         compiz = to_compiz(c);
 597 
 598         set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size);
 599         set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
 600 
 601         return 0;
 602 }
 603 
 604 static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in,
 605                                          u32 vsize_in, u32 hsize_out,
 606                                          u32 vsize_out)
 607 {
 608         u32 val = 0;
 609 
 610         if (hsize_in <= hsize_out)
 611                 val  |= 0x62;
 612         else if (hsize_in <= (hsize_out + hsize_out / 2))
 613                 val |= 0x63;
 614         else if (hsize_in <= hsize_out * 2)
 615                 val |= 0x64;
 616         else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4)
 617                 val |= 0x65;
 618         else
 619                 val |= 0x66;
 620 
 621         if (vsize_in <= vsize_out)
 622                 val  |= SC_VTSEL(0x6A);
 623         else if (vsize_in <= (vsize_out + vsize_out / 2))
 624                 val |= SC_VTSEL(0x6B);
 625         else if (vsize_in <= vsize_out * 2)
 626                 val |= SC_VTSEL(0x6C);
 627         else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4)
 628                 val |= SC_VTSEL(0x6D);
 629         else
 630                 val |= SC_VTSEL(0x6E);
 631 
 632         malidp_write32(reg, SC_COEFFTAB, val);
 633 }
 634 
 635 static void d71_scaler_update(struct komeda_component *c,
 636                               struct komeda_component_state *state)
 637 {
 638         struct komeda_scaler_state *st = to_scaler_st(state);
 639         u32 __iomem *reg = c->reg;
 640         u32 init_ph, delta_ph, ctrl;
 641 
 642         d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in,
 643                                      st->hsize_out, st->vsize_out);
 644 
 645         malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));
 646         malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));
 647         malidp_write32(reg, SC_H_CROP, HV_CROP(st->left_crop, st->right_crop));
 648 
 649         /* for right part, HW only sample the valid pixel which means the pixels
 650          * in left_crop will be jumpped, and the first sample pixel is:
 651          *
 652          * dst_a = st->total_hsize_out - st->hsize_out + st->left_crop + 0.5;
 653          *
 654          * Then the corresponding texel in src is:
 655          *
 656          * h_delta_phase = st->total_hsize_in / st->total_hsize_out;
 657          * src_a = dst_A * h_delta_phase;
 658          *
 659          * and h_init_phase is src_a deduct the real source start src_S;
 660          *
 661          * src_S = st->total_hsize_in - st->hsize_in;
 662          * h_init_phase = src_a - src_S;
 663          *
 664          * And HW precision for the initial/delta_phase is 16:16 fixed point,
 665          * the following is the simplified formula
 666          */
 667         if (st->right_part) {
 668                 u32 dst_a = st->total_hsize_out - st->hsize_out + st->left_crop;
 669 
 670                 if (st->en_img_enhancement)
 671                         dst_a -= 1;
 672 
 673                 init_ph = ((st->total_hsize_in * (2 * dst_a + 1) -
 674                             2 * st->total_hsize_out * (st->total_hsize_in -
 675                             st->hsize_in)) << 15) / st->total_hsize_out;
 676         } else {
 677                 init_ph = (st->total_hsize_in << 15) / st->total_hsize_out;
 678         }
 679 
 680         malidp_write32(reg, SC_H_INIT_PH, init_ph);
 681 
 682         delta_ph = (st->total_hsize_in << 16) / st->total_hsize_out;
 683         malidp_write32(reg, SC_H_DELTA_PH, delta_ph);
 684 
 685         init_ph = (st->total_vsize_in << 15) / st->vsize_out;
 686         malidp_write32(reg, SC_V_INIT_PH, init_ph);
 687 
 688         delta_ph = (st->total_vsize_in << 16) / st->vsize_out;
 689         malidp_write32(reg, SC_V_DELTA_PH, delta_ph);
 690 
 691         ctrl = 0;
 692         ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;
 693         ctrl |= st->en_alpha ? SC_CTRL_AP : 0;
 694         ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0;
 695         /* If we use the hardware splitter we shouldn't set SC_CTRL_LS */
 696         if (st->en_split &&
 697             state->inputs[0].component->id != KOMEDA_COMPONENT_SPLITTER)
 698                 ctrl |= SC_CTRL_LS;
 699 
 700         malidp_write32(reg, BLK_CONTROL, ctrl);
 701         malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
 702 }
 703 
 704 static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)
 705 {
 706         u32 v[9];
 707 
 708         dump_block_header(sf, c->reg);
 709 
 710         get_values_from_reg(c->reg, 0x80, 1, v);
 711         seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]);
 712 
 713         get_values_from_reg(c->reg, 0xD0, 1, v);
 714         seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]);
 715 
 716         get_values_from_reg(c->reg, 0xDC, 9, v);
 717         seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]);
 718         seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]);
 719         seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]);
 720         seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]);
 721         seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]);
 722         seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]);
 723         seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);
 724         seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);
 725         seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]);
 726 }
 727 
 728 static const struct komeda_component_funcs d71_scaler_funcs = {
 729         .update         = d71_scaler_update,
 730         .disable        = d71_component_disable,
 731         .dump_register  = d71_scaler_dump,
 732 };
 733 
 734 static int d71_scaler_init(struct d71_dev *d71,
 735                            struct block_header *blk, u32 __iomem *reg)
 736 {
 737         struct komeda_component *c;
 738         struct komeda_scaler *scaler;
 739         u32 pipe_id, comp_id;
 740 
 741         get_resources_id(blk->block_info, &pipe_id, &comp_id);
 742 
 743         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler),
 744                                  comp_id, BLOCK_INFO_INPUT_ID(blk->block_info),
 745                                  &d71_scaler_funcs,
 746                                  1, get_valid_inputs(blk), 1, reg,
 747                                  "CU%d_SCALER%d",
 748                                  pipe_id, BLOCK_INFO_BLK_ID(blk->block_info));
 749 
 750         if (IS_ERR(c)) {
 751                 DRM_ERROR("Failed to initialize scaler");
 752                 return PTR_ERR(c);
 753         }
 754 
 755         scaler = to_scaler(c);
 756         set_range(&scaler->hsize, 4, 2048);
 757         set_range(&scaler->vsize, 4, 4096);
 758         scaler->max_downscaling = 6;
 759         scaler->max_upscaling = 64;
 760         scaler->scaling_split_overlap = 8;
 761         scaler->enh_split_overlap = 1;
 762 
 763         malidp_write32(c->reg, BLK_CONTROL, 0);
 764 
 765         return 0;
 766 }
 767 
 768 static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
 769                                      struct drm_display_mode *mode,
 770                                      unsigned long aclk_rate,
 771                                      struct komeda_data_flow_cfg *dflow)
 772 {
 773         u32 h_in = dflow->in_w;
 774         u32 v_in = dflow->in_h;
 775         u32 v_out = dflow->out_h;
 776         u64 fraction, denominator;
 777 
 778         /* D71 downscaling must satisfy the following equation
 779          *
 780          *   ACLK                   h_in * v_in
 781          * ------- >= ---------------------------------------------
 782          *  PXLCLK     (h_total - (1 + 2 * v_in / v_out)) * v_out
 783          *
 784          * In only horizontal downscaling situation, the right side should be
 785          * multiplied by (h_total - 3) / (h_active - 3), then equation becomes
 786          *
 787          *   ACLK          h_in
 788          * ------- >= ----------------
 789          *  PXLCLK     (h_active - 3)
 790          *
 791          * To avoid precision lost the equation 1 will be convert to:
 792          *
 793          *   ACLK             h_in * v_in
 794          * ------- >= -----------------------------------
 795          *  PXLCLK     (h_total -1 ) * v_out -  2 * v_in
 796          */
 797         if (v_in == v_out) {
 798                 fraction = h_in;
 799                 denominator = mode->hdisplay - 3;
 800         } else {
 801                 fraction = h_in * v_in;
 802                 denominator = (mode->htotal - 1) * v_out -  2 * v_in;
 803         }
 804 
 805         return aclk_rate * denominator >= mode->crtc_clock * 1000 * fraction ?
 806                0 : -EINVAL;
 807 }
 808 
 809 static void d71_splitter_update(struct komeda_component *c,
 810                                 struct komeda_component_state *state)
 811 {
 812         struct komeda_splitter_state *st = to_splitter_st(state);
 813         u32 __iomem *reg = c->reg;
 814 
 815         malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
 816         malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
 817         malidp_write32(reg, SP_OVERLAP_SIZE, st->overlap & 0x1FFF);
 818         malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
 819 }
 820 
 821 static void d71_splitter_dump(struct komeda_component *c, struct seq_file *sf)
 822 {
 823         u32 v[3];
 824 
 825         dump_block_header(sf, c->reg);
 826 
 827         get_values_from_reg(c->reg, BLK_INPUT_ID0, 1, v);
 828         seq_printf(sf, "SP_INPUT_ID0:\t\t0x%X\n", v[0]);
 829 
 830         get_values_from_reg(c->reg, BLK_CONTROL, 3, v);
 831         seq_printf(sf, "SP_CONTROL:\t\t0x%X\n", v[0]);
 832         seq_printf(sf, "SP_SIZE:\t\t0x%X\n", v[1]);
 833         seq_printf(sf, "SP_OVERLAP_SIZE:\t0x%X\n", v[2]);
 834 }
 835 
 836 static const struct komeda_component_funcs d71_splitter_funcs = {
 837         .update         = d71_splitter_update,
 838         .disable        = d71_component_disable,
 839         .dump_register  = d71_splitter_dump,
 840 };
 841 
 842 static int d71_splitter_init(struct d71_dev *d71,
 843                              struct block_header *blk, u32 __iomem *reg)
 844 {
 845         struct komeda_component *c;
 846         struct komeda_splitter *splitter;
 847         u32 pipe_id, comp_id;
 848 
 849         get_resources_id(blk->block_info, &pipe_id, &comp_id);
 850 
 851         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*splitter),
 852                                  comp_id,
 853                                  BLOCK_INFO_INPUT_ID(blk->block_info),
 854                                  &d71_splitter_funcs,
 855                                  1, get_valid_inputs(blk), 2, reg,
 856                                  "CU%d_SPLITTER", pipe_id);
 857 
 858         if (IS_ERR(c)) {
 859                 DRM_ERROR("Failed to initialize splitter");
 860                 return -1;
 861         }
 862 
 863         splitter = to_splitter(c);
 864 
 865         set_range(&splitter->hsize, 4, d71->max_line_size);
 866         set_range(&splitter->vsize, 4, d71->max_vsize);
 867 
 868         return 0;
 869 }
 870 
 871 static void d71_merger_update(struct komeda_component *c,
 872                               struct komeda_component_state *state)
 873 {
 874         struct komeda_merger_state *st = to_merger_st(state);
 875         u32 __iomem *reg = c->reg;
 876         u32 index;
 877 
 878         for_each_changed_input(state, index)
 879                 malidp_write32(reg, MG_INPUT_ID0 + index * 4,
 880                                to_d71_input_id(state, index));
 881 
 882         malidp_write32(reg, MG_SIZE, HV_SIZE(st->hsize_merged,
 883                                              st->vsize_merged));
 884         malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
 885 }
 886 
 887 static void d71_merger_dump(struct komeda_component *c, struct seq_file *sf)
 888 {
 889         u32 v;
 890 
 891         dump_block_header(sf, c->reg);
 892 
 893         get_values_from_reg(c->reg, MG_INPUT_ID0, 1, &v);
 894         seq_printf(sf, "MG_INPUT_ID0:\t\t0x%X\n", v);
 895 
 896         get_values_from_reg(c->reg, MG_INPUT_ID1, 1, &v);
 897         seq_printf(sf, "MG_INPUT_ID1:\t\t0x%X\n", v);
 898 
 899         get_values_from_reg(c->reg, BLK_CONTROL, 1, &v);
 900         seq_printf(sf, "MG_CONTROL:\t\t0x%X\n", v);
 901 
 902         get_values_from_reg(c->reg, MG_SIZE, 1, &v);
 903         seq_printf(sf, "MG_SIZE:\t\t0x%X\n", v);
 904 }
 905 
 906 static const struct komeda_component_funcs d71_merger_funcs = {
 907         .update         = d71_merger_update,
 908         .disable        = d71_component_disable,
 909         .dump_register  = d71_merger_dump,
 910 };
 911 
 912 static int d71_merger_init(struct d71_dev *d71,
 913                            struct block_header *blk, u32 __iomem *reg)
 914 {
 915         struct komeda_component *c;
 916         struct komeda_merger *merger;
 917         u32 pipe_id, comp_id;
 918 
 919         get_resources_id(blk->block_info, &pipe_id, &comp_id);
 920 
 921         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*merger),
 922                                  comp_id,
 923                                  BLOCK_INFO_INPUT_ID(blk->block_info),
 924                                  &d71_merger_funcs,
 925                                  MG_NUM_INPUTS_IDS, get_valid_inputs(blk),
 926                                  MG_NUM_OUTPUTS_IDS, reg,
 927                                  "CU%d_MERGER", pipe_id);
 928 
 929         if (IS_ERR(c)) {
 930                 DRM_ERROR("Failed to initialize merger.\n");
 931                 return PTR_ERR(c);
 932         }
 933 
 934         merger = to_merger(c);
 935 
 936         set_range(&merger->hsize_merged, 4, 4032);
 937         set_range(&merger->vsize_merged, 4, 4096);
 938 
 939         return 0;
 940 }
 941 
 942 static void d71_improc_update(struct komeda_component *c,
 943                               struct komeda_component_state *state)
 944 {
 945         struct komeda_improc_state *st = to_improc_st(state);
 946         u32 __iomem *reg = c->reg;
 947         u32 index;
 948 
 949         for_each_changed_input(state, index)
 950                 malidp_write32(reg, BLK_INPUT_ID0 + index * 4,
 951                                to_d71_input_id(state, index));
 952 
 953         malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
 954 }
 955 
 956 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
 957 {
 958         u32 v[12], i;
 959 
 960         dump_block_header(sf, c->reg);
 961 
 962         get_values_from_reg(c->reg, 0x80, 2, v);
 963         seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
 964         seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
 965 
 966         get_values_from_reg(c->reg, 0xC0, 1, v);
 967         seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
 968 
 969         get_values_from_reg(c->reg, 0xD0, 3, v);
 970         seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
 971         seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
 972         seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
 973 
 974         get_values_from_reg(c->reg, 0x130, 12, v);
 975         for (i = 0; i < 12; i++)
 976                 seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
 977 
 978         get_values_from_reg(c->reg, 0x170, 12, v);
 979         for (i = 0; i < 12; i++)
 980                 seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
 981 }
 982 
 983 static const struct komeda_component_funcs d71_improc_funcs = {
 984         .update         = d71_improc_update,
 985         .disable        = d71_component_disable,
 986         .dump_register  = d71_improc_dump,
 987 };
 988 
 989 static int d71_improc_init(struct d71_dev *d71,
 990                            struct block_header *blk, u32 __iomem *reg)
 991 {
 992         struct komeda_component *c;
 993         struct komeda_improc *improc;
 994         u32 pipe_id, comp_id, value;
 995 
 996         get_resources_id(blk->block_info, &pipe_id, &comp_id);
 997 
 998         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),
 999                                  comp_id,
1000                                  BLOCK_INFO_INPUT_ID(blk->block_info),
1001                                  &d71_improc_funcs, IPS_NUM_INPUT_IDS,
1002                                  get_valid_inputs(blk),
1003                                  IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);
1004         if (IS_ERR(c)) {
1005                 DRM_ERROR("Failed to add improc component\n");
1006                 return PTR_ERR(c);
1007         }
1008 
1009         improc = to_improc(c);
1010         improc->supported_color_depths = BIT(8) | BIT(10);
1011         improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
1012                                           DRM_COLOR_FORMAT_YCRCB444 |
1013                                           DRM_COLOR_FORMAT_YCRCB422;
1014         value = malidp_read32(reg, BLK_INFO);
1015         if (value & IPS_INFO_CHD420)
1016                 improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420;
1017 
1018         improc->supports_csc = true;
1019         improc->supports_gamma = true;
1020 
1021         return 0;
1022 }
1023 
1024 static void d71_timing_ctrlr_disable(struct komeda_component *c)
1025 {
1026         malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
1027 }
1028 
1029 static void d71_timing_ctrlr_update(struct komeda_component *c,
1030                                     struct komeda_component_state *state)
1031 {
1032         struct drm_crtc_state *crtc_st = state->crtc->state;
1033         struct drm_display_mode *mode = &crtc_st->adjusted_mode;
1034         u32 __iomem *reg = c->reg;
1035         u32 hactive, hfront_porch, hback_porch, hsync_len;
1036         u32 vactive, vfront_porch, vback_porch, vsync_len;
1037         u32 value;
1038 
1039         hactive = mode->crtc_hdisplay;
1040         hfront_porch = mode->crtc_hsync_start - mode->crtc_hdisplay;
1041         hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
1042         hback_porch = mode->crtc_htotal - mode->crtc_hsync_end;
1043 
1044         vactive = mode->crtc_vdisplay;
1045         vfront_porch = mode->crtc_vsync_start - mode->crtc_vdisplay;
1046         vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
1047         vback_porch = mode->crtc_vtotal - mode->crtc_vsync_end;
1048 
1049         malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(hactive, vactive));
1050         malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(hfront_porch,
1051                                                         hback_porch));
1052         malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vfront_porch,
1053                                                         vback_porch));
1054 
1055         value = BS_SYNC_VSW(vsync_len) | BS_SYNC_HSW(hsync_len);
1056         value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BS_SYNC_VSP : 0;
1057         value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BS_SYNC_HSP : 0;
1058         malidp_write32(reg, BS_SYNC, value);
1059 
1060         malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
1061         malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);
1062 
1063         /* configure bs control register */
1064         value = BS_CTRL_EN | BS_CTRL_VM;
1065         if (c->pipeline->dual_link) {
1066                 malidp_write32(reg, BS_DRIFT_TO, hfront_porch + 16);
1067                 value |= BS_CTRL_DL;
1068         }
1069 
1070         malidp_write32(reg, BLK_CONTROL, value);
1071 }
1072 
1073 static void d71_timing_ctrlr_dump(struct komeda_component *c,
1074                                   struct seq_file *sf)
1075 {
1076         u32 v[8], i;
1077 
1078         dump_block_header(sf, c->reg);
1079 
1080         get_values_from_reg(c->reg, 0xC0, 1, v);
1081         seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
1082 
1083         get_values_from_reg(c->reg, 0xD0, 8, v);
1084         seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
1085         seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
1086         seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
1087         seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
1088         seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
1089         seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
1090         seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
1091         seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
1092 
1093         get_values_from_reg(c->reg, 0x100, 3, v);
1094         seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
1095         seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
1096         seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
1097 
1098         get_values_from_reg(c->reg, 0x110, 3, v);
1099         for (i = 0; i < 3; i++)
1100                 seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
1101 
1102         get_values_from_reg(c->reg, 0x120, 5, v);
1103         for (i = 0; i < 2; i++) {
1104                 seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
1105                 seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
1106         }
1107         seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
1108 }
1109 
1110 static const struct komeda_component_funcs d71_timing_ctrlr_funcs = {
1111         .update         = d71_timing_ctrlr_update,
1112         .disable        = d71_timing_ctrlr_disable,
1113         .dump_register  = d71_timing_ctrlr_dump,
1114 };
1115 
1116 static int d71_timing_ctrlr_init(struct d71_dev *d71,
1117                                  struct block_header *blk, u32 __iomem *reg)
1118 {
1119         struct komeda_component *c;
1120         struct komeda_timing_ctrlr *ctrlr;
1121         u32 pipe_id, comp_id;
1122 
1123         get_resources_id(blk->block_info, &pipe_id, &comp_id);
1124 
1125         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),
1126                                  KOMEDA_COMPONENT_TIMING_CTRLR,
1127                                  BLOCK_INFO_INPUT_ID(blk->block_info),
1128                                  &d71_timing_ctrlr_funcs,
1129                                  1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),
1130                                  BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);
1131         if (IS_ERR(c)) {
1132                 DRM_ERROR("Failed to add display_ctrl component\n");
1133                 return PTR_ERR(c);
1134         }
1135 
1136         ctrlr = to_ctrlr(c);
1137 
1138         ctrlr->supports_dual_link = true;
1139 
1140         return 0;
1141 }
1142 
1143 int d71_probe_block(struct d71_dev *d71,
1144                     struct block_header *blk, u32 __iomem *reg)
1145 {
1146         struct d71_pipeline *pipe;
1147         int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
1148 
1149         int err = 0;
1150 
1151         switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
1152         case D71_BLK_TYPE_GCU:
1153                 break;
1154 
1155         case D71_BLK_TYPE_LPU:
1156                 pipe = d71->pipes[blk_id];
1157                 pipe->lpu_addr = reg;
1158                 break;
1159 
1160         case D71_BLK_TYPE_LPU_LAYER:
1161                 err = d71_layer_init(d71, blk, reg);
1162                 break;
1163 
1164         case D71_BLK_TYPE_LPU_WB_LAYER:
1165                 err = d71_wb_layer_init(d71, blk, reg);
1166                 break;
1167 
1168         case D71_BLK_TYPE_CU:
1169                 pipe = d71->pipes[blk_id];
1170                 pipe->cu_addr = reg;
1171                 err = d71_compiz_init(d71, blk, reg);
1172                 break;
1173 
1174         case D71_BLK_TYPE_CU_SCALER:
1175                 err = d71_scaler_init(d71, blk, reg);
1176                 break;
1177 
1178         case D71_BLK_TYPE_CU_SPLITTER:
1179                 err = d71_splitter_init(d71, blk, reg);
1180                 break;
1181 
1182         case D71_BLK_TYPE_CU_MERGER:
1183                 err = d71_merger_init(d71, blk, reg);
1184                 break;
1185 
1186         case D71_BLK_TYPE_DOU:
1187                 pipe = d71->pipes[blk_id];
1188                 pipe->dou_addr = reg;
1189                 break;
1190 
1191         case D71_BLK_TYPE_DOU_IPS:
1192                 err = d71_improc_init(d71, blk, reg);
1193                 break;
1194 
1195         case D71_BLK_TYPE_DOU_FT_COEFF:
1196                 pipe = d71->pipes[blk_id];
1197                 pipe->dou_ft_coeff_addr = reg;
1198                 break;
1199 
1200         case D71_BLK_TYPE_DOU_BS:
1201                 err = d71_timing_ctrlr_init(d71, blk, reg);
1202                 break;
1203 
1204         case D71_BLK_TYPE_GLB_LT_COEFF:
1205                 break;
1206 
1207         case D71_BLK_TYPE_GLB_SCL_COEFF:
1208                 d71->glb_scl_coeff_addr[blk_id] = reg;
1209                 break;
1210 
1211         default:
1212                 DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
1213                           blk->block_info);
1214                 err = -EINVAL;
1215                 break;
1216         }
1217 
1218         return err;
1219 }
1220 
1221 const struct komeda_pipeline_funcs d71_pipeline_funcs = {
1222         .downscaling_clk_check = d71_downscaling_clk_check,
1223 };

/* [<][>][^][v][top][bottom][index][help] */