linux/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
<<
>>
Prefs
   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
  13static 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
  58static 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
  73static 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
  88static 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/* On D71, we are using the global line size. From D32, every component have
 110 * a line size register to indicate the fifo size.
 111 */
 112static u32 __get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg,
 113                               u32 max_default)
 114{
 115        if (!d71->periph_addr)
 116                max_default = malidp_read32(reg, BLK_MAX_LINE_SIZE);
 117
 118        return max_default;
 119}
 120
 121static u32 get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg)
 122{
 123        return __get_blk_line_size(d71, reg, d71->max_line_size);
 124}
 125
 126static u32 to_rot_ctrl(u32 rot)
 127{
 128        u32 lr_ctrl = 0;
 129
 130        switch (rot & DRM_MODE_ROTATE_MASK) {
 131        case DRM_MODE_ROTATE_0:
 132                lr_ctrl |= L_ROT(L_ROT_R0);
 133                break;
 134        case DRM_MODE_ROTATE_90:
 135                lr_ctrl |= L_ROT(L_ROT_R90);
 136                break;
 137        case DRM_MODE_ROTATE_180:
 138                lr_ctrl |= L_ROT(L_ROT_R180);
 139                break;
 140        case DRM_MODE_ROTATE_270:
 141                lr_ctrl |= L_ROT(L_ROT_R270);
 142                break;
 143        }
 144
 145        if (rot & DRM_MODE_REFLECT_X)
 146                lr_ctrl |= L_HFLIP;
 147        if (rot & DRM_MODE_REFLECT_Y)
 148                lr_ctrl |= L_VFLIP;
 149
 150        return lr_ctrl;
 151}
 152
 153static u32 to_ad_ctrl(u64 modifier)
 154{
 155        u32 afbc_ctrl = AD_AEN;
 156
 157        if (!modifier)
 158                return 0;
 159
 160        if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
 161            AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
 162                afbc_ctrl |= AD_WB;
 163
 164        if (modifier & AFBC_FORMAT_MOD_YTR)
 165                afbc_ctrl |= AD_YT;
 166        if (modifier & AFBC_FORMAT_MOD_SPLIT)
 167                afbc_ctrl |= AD_BS;
 168        if (modifier & AFBC_FORMAT_MOD_TILED)
 169                afbc_ctrl |= AD_TH;
 170
 171        return afbc_ctrl;
 172}
 173
 174static inline u32 to_d71_input_id(struct komeda_component_state *st, int idx)
 175{
 176        struct komeda_component_output *input = &st->inputs[idx];
 177
 178        /* if input is not active, set hw input_id(0) to disable it */
 179        if (has_bit(idx, st->active_inputs))
 180                return input->component->hw_id + input->output_port;
 181        else
 182                return 0;
 183}
 184
 185static void d71_layer_update_fb(struct komeda_component *c,
 186                                struct komeda_fb *kfb,
 187                                dma_addr_t *addr)
 188{
 189        struct drm_framebuffer *fb = &kfb->base;
 190        const struct drm_format_info *info = fb->format;
 191        u32 __iomem *reg = c->reg;
 192        int block_h;
 193
 194        if (info->num_planes > 2)
 195                malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]);
 196
 197        if (info->num_planes > 1) {
 198                block_h = drm_format_info_block_height(info, 1);
 199                malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h);
 200                malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]);
 201        }
 202
 203        block_h = drm_format_info_block_height(info, 0);
 204        malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h);
 205        malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]);
 206        malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
 207}
 208
 209static void d71_layer_disable(struct komeda_component *c)
 210{
 211        malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
 212}
 213
 214static void d71_layer_update(struct komeda_component *c,
 215                             struct komeda_component_state *state)
 216{
 217        struct komeda_layer_state *st = to_layer_st(state);
 218        struct drm_plane_state *plane_st = state->plane->state;
 219        struct drm_framebuffer *fb = plane_st->fb;
 220        struct komeda_fb *kfb = to_kfb(fb);
 221        u32 __iomem *reg = c->reg;
 222        u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
 223        u32 ctrl = L_EN | to_rot_ctrl(st->rot);
 224
 225        d71_layer_update_fb(c, kfb, st->addr);
 226
 227        malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier));
 228        if (fb->modifier) {
 229                u64 addr;
 230
 231                malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l,
 232                                                             st->afbc_crop_r));
 233                malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t,
 234                                                             st->afbc_crop_b));
 235                /* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */
 236                if (fb->modifier & AFBC_FORMAT_MOD_TILED)
 237                        addr = st->addr[0] + kfb->offset_payload;
 238                else
 239                        addr = st->addr[0] + kfb->afbc_size - 1;
 240
 241                malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr));
 242                malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr));
 243        }
 244
 245        if (fb->format->is_yuv) {
 246                u32 upsampling = 0;
 247
 248                switch (kfb->format_caps->fourcc) {
 249                case DRM_FORMAT_YUYV:
 250                        upsampling = fb->modifier ? LR_CHI422_BILINEAR :
 251                                     LR_CHI422_REPLICATION;
 252                        break;
 253                case DRM_FORMAT_UYVY:
 254                        upsampling = LR_CHI422_REPLICATION;
 255                        break;
 256                case DRM_FORMAT_NV12:
 257                case DRM_FORMAT_YUV420_8BIT:
 258                case DRM_FORMAT_YUV420_10BIT:
 259                case DRM_FORMAT_YUV420:
 260                case DRM_FORMAT_P010:
 261                /* these fmt support MPGE/JPEG both, here perfer JPEG*/
 262                        upsampling = LR_CHI420_JPEG;
 263                        break;
 264                case DRM_FORMAT_X0L2:
 265                        upsampling = LR_CHI420_JPEG;
 266                        break;
 267                default:
 268                        break;
 269                }
 270
 271                malidp_write32(reg, LAYER_R_CONTROL, upsampling);
 272                malidp_write_group(reg, LAYER_YUV_RGB_COEFF0,
 273                                   KOMEDA_N_YUV2RGB_COEFFS,
 274                                   komeda_select_yuv2rgb_coeffs(
 275                                        plane_st->color_encoding,
 276                                        plane_st->color_range));
 277        }
 278
 279        malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
 280
 281        if (kfb->is_va)
 282                ctrl |= L_TBU_EN;
 283        malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
 284}
 285
 286static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
 287{
 288        u32 v[15], i;
 289        bool rich, rgb2rgb;
 290        char *prefix;
 291
 292        get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
 293        if (v[14] & 0x1) {
 294                rich = true;
 295                prefix = "LR_";
 296        } else {
 297                rich = false;
 298                prefix = "LS_";
 299        }
 300
 301        rgb2rgb = !!(v[14] & L_INFO_CM);
 302
 303        dump_block_header(sf, c->reg);
 304
 305        seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
 306
 307        get_values_from_reg(c->reg, 0xD0, 1, v);
 308        seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
 309        if (rich) {
 310                get_values_from_reg(c->reg, 0xD4, 1, v);
 311                seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
 312        }
 313        get_values_from_reg(c->reg, 0xD8, 4, v);
 314        seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
 315        seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
 316        seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
 317        seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
 318
 319        get_values_from_reg(c->reg, 0x100, 3, v);
 320        seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
 321        seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
 322        seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
 323
 324        get_values_from_reg(c->reg, 0x110, 2, v);
 325        seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
 326        seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
 327        if (rich) {
 328                get_values_from_reg(c->reg, 0x118, 1, v);
 329                seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
 330
 331                get_values_from_reg(c->reg, 0x120, 2, v);
 332                seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
 333                seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
 334
 335                get_values_from_reg(c->reg, 0x130, 12, v);
 336                for (i = 0; i < 12; i++)
 337                        seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
 338        }
 339
 340        if (rgb2rgb) {
 341                get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
 342                for (i = 0; i < 12; i++)
 343                        seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
 344        }
 345
 346        get_values_from_reg(c->reg, 0x160, 3, v);
 347        seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
 348        seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
 349        seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
 350}
 351
 352static int d71_layer_validate(struct komeda_component *c,
 353                              struct komeda_component_state *state)
 354{
 355        struct komeda_layer_state *st = to_layer_st(state);
 356        struct komeda_layer *layer = to_layer(c);
 357        struct drm_plane_state *plane_st;
 358        struct drm_framebuffer *fb;
 359        u32 fourcc, line_sz, max_line_sz;
 360
 361        plane_st = drm_atomic_get_new_plane_state(state->obj.state,
 362                                                  state->plane);
 363        fb = plane_st->fb;
 364        fourcc = fb->format->format;
 365
 366        if (drm_rotation_90_or_270(st->rot))
 367                line_sz = st->vsize - st->afbc_crop_t - st->afbc_crop_b;
 368        else
 369                line_sz = st->hsize - st->afbc_crop_l - st->afbc_crop_r;
 370
 371        if (fb->modifier) {
 372                if ((fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
 373                        AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
 374                        max_line_sz = layer->line_sz;
 375                else
 376                        max_line_sz = layer->line_sz / 2;
 377
 378                if (line_sz > max_line_sz) {
 379                        DRM_DEBUG_ATOMIC("afbc request line_sz: %d exceed the max afbc line_sz: %d.\n",
 380                                         line_sz, max_line_sz);
 381                        return -EINVAL;
 382                }
 383        }
 384
 385        if (fourcc == DRM_FORMAT_YUV420_10BIT && line_sz > 2046 && (st->afbc_crop_l % 4)) {
 386                DRM_DEBUG_ATOMIC("YUV420_10BIT input_hsize: %d exceed the max size 2046.\n",
 387                                 line_sz);
 388                return -EINVAL;
 389        }
 390
 391        if (fourcc == DRM_FORMAT_X0L2 && line_sz > 2046 && (st->addr[0] % 16)) {
 392                DRM_DEBUG_ATOMIC("X0L2 input_hsize: %d exceed the max size 2046.\n",
 393                                 line_sz);
 394                return -EINVAL;
 395        }
 396
 397        return 0;
 398}
 399
 400static const struct komeda_component_funcs d71_layer_funcs = {
 401        .validate       = d71_layer_validate,
 402        .update         = d71_layer_update,
 403        .disable        = d71_layer_disable,
 404        .dump_register  = d71_layer_dump,
 405};
 406
 407static int d71_layer_init(struct d71_dev *d71,
 408                          struct block_header *blk, u32 __iomem *reg)
 409{
 410        struct komeda_component *c;
 411        struct komeda_layer *layer;
 412        u32 pipe_id, layer_id, layer_info;
 413
 414        get_resources_id(blk->block_info, &pipe_id, &layer_id);
 415        c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
 416                                 layer_id,
 417                                 BLOCK_INFO_INPUT_ID(blk->block_info),
 418                                 &d71_layer_funcs, 0,
 419                                 get_valid_inputs(blk),
 420                                 1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
 421        if (IS_ERR(c)) {
 422                DRM_ERROR("Failed to add layer component\n");
 423                return PTR_ERR(c);
 424        }
 425
 426        layer = to_layer(c);
 427        layer_info = malidp_read32(reg, LAYER_INFO);
 428
 429        if (layer_info & L_INFO_RF)
 430                layer->layer_type = KOMEDA_FMT_RICH_LAYER;
 431        else
 432                layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
 433
 434        if (!d71->periph_addr) {
 435                /* D32 or newer product */
 436                layer->line_sz = malidp_read32(reg, BLK_MAX_LINE_SIZE);
 437                layer->yuv_line_sz = L_INFO_YUV_MAX_LINESZ(layer_info);
 438        } else if (d71->max_line_size > 2048) {
 439                /* D71 4K */
 440                layer->line_sz = d71->max_line_size;
 441                layer->yuv_line_sz = layer->line_sz / 2;
 442        } else  {
 443                /* D71 2K */
 444                if (layer->layer_type == KOMEDA_FMT_RICH_LAYER) {
 445                        /* rich layer is 4K configuration */
 446                        layer->line_sz = d71->max_line_size * 2;
 447                        layer->yuv_line_sz = layer->line_sz / 2;
 448                } else {
 449                        layer->line_sz = d71->max_line_size;
 450                        layer->yuv_line_sz = 0;
 451                }
 452        }
 453
 454        set_range(&layer->hsize_in, 4, layer->line_sz);
 455
 456        set_range(&layer->vsize_in, 4, d71->max_vsize);
 457
 458        malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
 459
 460        layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
 461
 462        return 0;
 463}
 464
 465static void d71_wb_layer_update(struct komeda_component *c,
 466                                struct komeda_component_state *state)
 467{
 468        struct komeda_layer_state *st = to_layer_st(state);
 469        struct drm_connector_state *conn_st = state->wb_conn->state;
 470        struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);
 471        u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN;
 472        u32 __iomem *reg = c->reg;
 473
 474        d71_layer_update_fb(c, kfb, st->addr);
 475
 476        if (kfb->is_va)
 477                ctrl |= LW_TBU_EN;
 478
 479        malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
 480        malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
 481        malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
 482}
 483
 484static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf)
 485{
 486        u32 v[12], i;
 487
 488        dump_block_header(sf, c->reg);
 489
 490        get_values_from_reg(c->reg, 0x80, 1, v);
 491        seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]);
 492
 493        get_values_from_reg(c->reg, 0xD0, 3, v);
 494        seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]);
 495        seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]);
 496        seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]);
 497
 498        get_values_from_reg(c->reg, 0xE0, 1, v);
 499        seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]);
 500
 501        for (i = 0; i < 2; i++) {
 502                get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v);
 503                seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]);
 504                seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]);
 505                seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]);
 506        }
 507
 508        get_values_from_reg(c->reg, 0x130, 12, v);
 509        for (i = 0; i < 12; i++)
 510                seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
 511}
 512
 513static void d71_wb_layer_disable(struct komeda_component *c)
 514{
 515        malidp_write32(c->reg, BLK_INPUT_ID0, 0);
 516        malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
 517}
 518
 519static const struct komeda_component_funcs d71_wb_layer_funcs = {
 520        .update         = d71_wb_layer_update,
 521        .disable        = d71_wb_layer_disable,
 522        .dump_register  = d71_wb_layer_dump,
 523};
 524
 525static int d71_wb_layer_init(struct d71_dev *d71,
 526                             struct block_header *blk, u32 __iomem *reg)
 527{
 528        struct komeda_component *c;
 529        struct komeda_layer *wb_layer;
 530        u32 pipe_id, layer_id;
 531
 532        get_resources_id(blk->block_info, &pipe_id, &layer_id);
 533
 534        c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer),
 535                                 layer_id, BLOCK_INFO_INPUT_ID(blk->block_info),
 536                                 &d71_wb_layer_funcs,
 537                                 1, get_valid_inputs(blk), 0, reg,
 538                                 "LPU%d_LAYER_WR", pipe_id);
 539        if (IS_ERR(c)) {
 540                DRM_ERROR("Failed to add wb_layer component\n");
 541                return PTR_ERR(c);
 542        }
 543
 544        wb_layer = to_layer(c);
 545        wb_layer->layer_type = KOMEDA_FMT_WB_LAYER;
 546        wb_layer->line_sz = get_blk_line_size(d71, reg);
 547        wb_layer->yuv_line_sz = wb_layer->line_sz;
 548
 549        set_range(&wb_layer->hsize_in, 64, wb_layer->line_sz);
 550        set_range(&wb_layer->vsize_in, 64, d71->max_vsize);
 551
 552        return 0;
 553}
 554
 555static void d71_component_disable(struct komeda_component *c)
 556{
 557        u32 __iomem *reg = c->reg;
 558        u32 i;
 559
 560        malidp_write32(reg, BLK_CONTROL, 0);
 561
 562        for (i = 0; i < c->max_active_inputs; i++) {
 563                malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
 564
 565                /* Besides clearing the input ID to zero, D71 compiz also has
 566                 * input enable bit in CU_INPUTx_CONTROL which need to be
 567                 * cleared.
 568                 */
 569                if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS))
 570                        malidp_write32(reg, CU_INPUT0_CONTROL +
 571                                       i * CU_PER_INPUT_REGS * 4,
 572                                       CU_INPUT_CTRL_ALPHA(0xFF));
 573        }
 574}
 575
 576static void compiz_enable_input(u32 __iomem *id_reg,
 577                                u32 __iomem *cfg_reg,
 578                                u32 input_hw_id,
 579                                struct komeda_compiz_input_cfg *cin)
 580{
 581        u32 ctrl = CU_INPUT_CTRL_EN;
 582        u8 blend = cin->pixel_blend_mode;
 583
 584        if (blend == DRM_MODE_BLEND_PIXEL_NONE)
 585                ctrl |= CU_INPUT_CTRL_PAD;
 586        else if (blend == DRM_MODE_BLEND_PREMULTI)
 587                ctrl |= CU_INPUT_CTRL_PMUL;
 588
 589        ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
 590
 591        malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
 592
 593        malidp_write32(cfg_reg, CU_INPUT0_SIZE,
 594                       HV_SIZE(cin->hsize, cin->vsize));
 595        malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
 596                       HV_OFFSET(cin->hoffset, cin->voffset));
 597        malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
 598}
 599
 600static void d71_compiz_update(struct komeda_component *c,
 601                              struct komeda_component_state *state)
 602{
 603        struct komeda_compiz_state *st = to_compiz_st(state);
 604        u32 __iomem *reg = c->reg;
 605        u32 __iomem *id_reg, *cfg_reg;
 606        u32 index;
 607
 608        for_each_changed_input(state, index) {
 609                id_reg = reg + index;
 610                cfg_reg = reg + index * CU_PER_INPUT_REGS;
 611                if (state->active_inputs & BIT(index)) {
 612                        compiz_enable_input(id_reg, cfg_reg,
 613                                            to_d71_input_id(state, index),
 614                                            &st->cins[index]);
 615                } else {
 616                        malidp_write32(id_reg, BLK_INPUT_ID0, 0);
 617                        malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
 618                }
 619        }
 620
 621        malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
 622}
 623
 624static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
 625{
 626        u32 v[8], i;
 627
 628        dump_block_header(sf, c->reg);
 629
 630        get_values_from_reg(c->reg, 0x80, 5, v);
 631        for (i = 0; i < 5; i++)
 632                seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
 633
 634        get_values_from_reg(c->reg, 0xA0, 5, v);
 635        seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
 636        seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
 637        seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
 638        seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
 639        seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
 640
 641        get_values_from_reg(c->reg, 0xD0, 2, v);
 642        seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
 643        seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
 644
 645        get_values_from_reg(c->reg, 0xDC, 1, v);
 646        seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
 647
 648        for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
 649                get_values_from_reg(c->reg, v[4], 3, v);
 650                seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
 651                seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
 652                seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
 653        }
 654
 655        get_values_from_reg(c->reg, 0x130, 2, v);
 656        seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
 657        seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
 658}
 659
 660static const struct komeda_component_funcs d71_compiz_funcs = {
 661        .update         = d71_compiz_update,
 662        .disable        = d71_component_disable,
 663        .dump_register  = d71_compiz_dump,
 664};
 665
 666static int d71_compiz_init(struct d71_dev *d71,
 667                           struct block_header *blk, u32 __iomem *reg)
 668{
 669        struct komeda_component *c;
 670        struct komeda_compiz *compiz;
 671        u32 pipe_id, comp_id;
 672
 673        get_resources_id(blk->block_info, &pipe_id, &comp_id);
 674
 675        c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
 676                                 comp_id,
 677                                 BLOCK_INFO_INPUT_ID(blk->block_info),
 678                                 &d71_compiz_funcs,
 679                                 CU_NUM_INPUT_IDS, get_valid_inputs(blk),
 680                                 CU_NUM_OUTPUT_IDS, reg,
 681                                 "CU%d", pipe_id);
 682        if (IS_ERR(c))
 683                return PTR_ERR(c);
 684
 685        compiz = to_compiz(c);
 686
 687        set_range(&compiz->hsize, 64, get_blk_line_size(d71, reg));
 688        set_range(&compiz->vsize, 64, d71->max_vsize);
 689
 690        return 0;
 691}
 692
 693static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in,
 694                                         u32 vsize_in, u32 hsize_out,
 695                                         u32 vsize_out)
 696{
 697        u32 val = 0;
 698
 699        if (hsize_in <= hsize_out)
 700                val  |= 0x62;
 701        else if (hsize_in <= (hsize_out + hsize_out / 2))
 702                val |= 0x63;
 703        else if (hsize_in <= hsize_out * 2)
 704                val |= 0x64;
 705        else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4)
 706                val |= 0x65;
 707        else
 708                val |= 0x66;
 709
 710        if (vsize_in <= vsize_out)
 711                val  |= SC_VTSEL(0x6A);
 712        else if (vsize_in <= (vsize_out + vsize_out / 2))
 713                val |= SC_VTSEL(0x6B);
 714        else if (vsize_in <= vsize_out * 2)
 715                val |= SC_VTSEL(0x6C);
 716        else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4)
 717                val |= SC_VTSEL(0x6D);
 718        else
 719                val |= SC_VTSEL(0x6E);
 720
 721        malidp_write32(reg, SC_COEFFTAB, val);
 722}
 723
 724static void d71_scaler_update(struct komeda_component *c,
 725                              struct komeda_component_state *state)
 726{
 727        struct komeda_scaler_state *st = to_scaler_st(state);
 728        u32 __iomem *reg = c->reg;
 729        u32 init_ph, delta_ph, ctrl;
 730
 731        d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in,
 732                                     st->hsize_out, st->vsize_out);
 733
 734        malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));
 735        malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));
 736        malidp_write32(reg, SC_H_CROP, HV_CROP(st->left_crop, st->right_crop));
 737
 738        /* for right part, HW only sample the valid pixel which means the pixels
 739         * in left_crop will be jumpped, and the first sample pixel is:
 740         *
 741         * dst_a = st->total_hsize_out - st->hsize_out + st->left_crop + 0.5;
 742         *
 743         * Then the corresponding texel in src is:
 744         *
 745         * h_delta_phase = st->total_hsize_in / st->total_hsize_out;
 746         * src_a = dst_A * h_delta_phase;
 747         *
 748         * and h_init_phase is src_a deduct the real source start src_S;
 749         *
 750         * src_S = st->total_hsize_in - st->hsize_in;
 751         * h_init_phase = src_a - src_S;
 752         *
 753         * And HW precision for the initial/delta_phase is 16:16 fixed point,
 754         * the following is the simplified formula
 755         */
 756        if (st->right_part) {
 757                u32 dst_a = st->total_hsize_out - st->hsize_out + st->left_crop;
 758
 759                if (st->en_img_enhancement)
 760                        dst_a -= 1;
 761
 762                init_ph = ((st->total_hsize_in * (2 * dst_a + 1) -
 763                            2 * st->total_hsize_out * (st->total_hsize_in -
 764                            st->hsize_in)) << 15) / st->total_hsize_out;
 765        } else {
 766                init_ph = (st->total_hsize_in << 15) / st->total_hsize_out;
 767        }
 768
 769        malidp_write32(reg, SC_H_INIT_PH, init_ph);
 770
 771        delta_ph = (st->total_hsize_in << 16) / st->total_hsize_out;
 772        malidp_write32(reg, SC_H_DELTA_PH, delta_ph);
 773
 774        init_ph = (st->total_vsize_in << 15) / st->vsize_out;
 775        malidp_write32(reg, SC_V_INIT_PH, init_ph);
 776
 777        delta_ph = (st->total_vsize_in << 16) / st->vsize_out;
 778        malidp_write32(reg, SC_V_DELTA_PH, delta_ph);
 779
 780        ctrl = 0;
 781        ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;
 782        ctrl |= st->en_alpha ? SC_CTRL_AP : 0;
 783        ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0;
 784        /* If we use the hardware splitter we shouldn't set SC_CTRL_LS */
 785        if (st->en_split &&
 786            state->inputs[0].component->id != KOMEDA_COMPONENT_SPLITTER)
 787                ctrl |= SC_CTRL_LS;
 788
 789        malidp_write32(reg, BLK_CONTROL, ctrl);
 790        malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
 791}
 792
 793static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)
 794{
 795        u32 v[10];
 796
 797        dump_block_header(sf, c->reg);
 798
 799        get_values_from_reg(c->reg, 0x80, 1, v);
 800        seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]);
 801
 802        get_values_from_reg(c->reg, 0xD0, 1, v);
 803        seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]);
 804
 805        get_values_from_reg(c->reg, 0xDC, 9, v);
 806        seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]);
 807        seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]);
 808        seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]);
 809        seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]);
 810        seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]);
 811        seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]);
 812        seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);
 813        seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);
 814        seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]);
 815
 816        get_values_from_reg(c->reg, 0x130, 10, v);
 817        seq_printf(sf, "SC_ENH_LIMITS:\t\t0x%X\n", v[0]);
 818        seq_printf(sf, "SC_ENH_COEFF0:\t\t0x%X\n", v[1]);
 819        seq_printf(sf, "SC_ENH_COEFF1:\t\t0x%X\n", v[2]);
 820        seq_printf(sf, "SC_ENH_COEFF2:\t\t0x%X\n", v[3]);
 821        seq_printf(sf, "SC_ENH_COEFF3:\t\t0x%X\n", v[4]);
 822        seq_printf(sf, "SC_ENH_COEFF4:\t\t0x%X\n", v[5]);
 823        seq_printf(sf, "SC_ENH_COEFF5:\t\t0x%X\n", v[6]);
 824        seq_printf(sf, "SC_ENH_COEFF6:\t\t0x%X\n", v[7]);
 825        seq_printf(sf, "SC_ENH_COEFF7:\t\t0x%X\n", v[8]);
 826        seq_printf(sf, "SC_ENH_COEFF8:\t\t0x%X\n", v[9]);
 827}
 828
 829static const struct komeda_component_funcs d71_scaler_funcs = {
 830        .update         = d71_scaler_update,
 831        .disable        = d71_component_disable,
 832        .dump_register  = d71_scaler_dump,
 833};
 834
 835static int d71_scaler_init(struct d71_dev *d71,
 836                           struct block_header *blk, u32 __iomem *reg)
 837{
 838        struct komeda_component *c;
 839        struct komeda_scaler *scaler;
 840        u32 pipe_id, comp_id;
 841
 842        get_resources_id(blk->block_info, &pipe_id, &comp_id);
 843
 844        c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler),
 845                                 comp_id, BLOCK_INFO_INPUT_ID(blk->block_info),
 846                                 &d71_scaler_funcs,
 847                                 1, get_valid_inputs(blk), 1, reg,
 848                                 "CU%d_SCALER%d",
 849                                 pipe_id, BLOCK_INFO_BLK_ID(blk->block_info));
 850
 851        if (IS_ERR(c)) {
 852                DRM_ERROR("Failed to initialize scaler");
 853                return PTR_ERR(c);
 854        }
 855
 856        scaler = to_scaler(c);
 857        set_range(&scaler->hsize, 4, __get_blk_line_size(d71, reg, 2048));
 858        set_range(&scaler->vsize, 4, 4096);
 859        scaler->max_downscaling = 6;
 860        scaler->max_upscaling = 64;
 861        scaler->scaling_split_overlap = 8;
 862        scaler->enh_split_overlap = 1;
 863
 864        malidp_write32(c->reg, BLK_CONTROL, 0);
 865
 866        return 0;
 867}
 868
 869static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
 870                                     struct drm_display_mode *mode,
 871                                     unsigned long aclk_rate,
 872                                     struct komeda_data_flow_cfg *dflow)
 873{
 874        u32 h_in = dflow->in_w;
 875        u32 v_in = dflow->in_h;
 876        u32 v_out = dflow->out_h;
 877        u64 fraction, denominator;
 878
 879        /* D71 downscaling must satisfy the following equation
 880         *
 881         *   ACLK                   h_in * v_in
 882         * ------- >= ---------------------------------------------
 883         *  PXLCLK     (h_total - (1 + 2 * v_in / v_out)) * v_out
 884         *
 885         * In only horizontal downscaling situation, the right side should be
 886         * multiplied by (h_total - 3) / (h_active - 3), then equation becomes
 887         *
 888         *   ACLK          h_in
 889         * ------- >= ----------------
 890         *  PXLCLK     (h_active - 3)
 891         *
 892         * To avoid precision lost the equation 1 will be convert to:
 893         *
 894         *   ACLK             h_in * v_in
 895         * ------- >= -----------------------------------
 896         *  PXLCLK     (h_total -1 ) * v_out -  2 * v_in
 897         */
 898        if (v_in == v_out) {
 899                fraction = h_in;
 900                denominator = mode->hdisplay - 3;
 901        } else {
 902                fraction = h_in * v_in;
 903                denominator = (mode->htotal - 1) * v_out -  2 * v_in;
 904        }
 905
 906        return aclk_rate * denominator >= mode->crtc_clock * 1000 * fraction ?
 907               0 : -EINVAL;
 908}
 909
 910static void d71_splitter_update(struct komeda_component *c,
 911                                struct komeda_component_state *state)
 912{
 913        struct komeda_splitter_state *st = to_splitter_st(state);
 914        u32 __iomem *reg = c->reg;
 915
 916        malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
 917        malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
 918        malidp_write32(reg, SP_OVERLAP_SIZE, st->overlap & 0x1FFF);
 919        malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
 920}
 921
 922static void d71_splitter_dump(struct komeda_component *c, struct seq_file *sf)
 923{
 924        u32 v[3];
 925
 926        dump_block_header(sf, c->reg);
 927
 928        get_values_from_reg(c->reg, BLK_INPUT_ID0, 1, v);
 929        seq_printf(sf, "SP_INPUT_ID0:\t\t0x%X\n", v[0]);
 930
 931        get_values_from_reg(c->reg, BLK_CONTROL, 3, v);
 932        seq_printf(sf, "SP_CONTROL:\t\t0x%X\n", v[0]);
 933        seq_printf(sf, "SP_SIZE:\t\t0x%X\n", v[1]);
 934        seq_printf(sf, "SP_OVERLAP_SIZE:\t0x%X\n", v[2]);
 935}
 936
 937static const struct komeda_component_funcs d71_splitter_funcs = {
 938        .update         = d71_splitter_update,
 939        .disable        = d71_component_disable,
 940        .dump_register  = d71_splitter_dump,
 941};
 942
 943static int d71_splitter_init(struct d71_dev *d71,
 944                             struct block_header *blk, u32 __iomem *reg)
 945{
 946        struct komeda_component *c;
 947        struct komeda_splitter *splitter;
 948        u32 pipe_id, comp_id;
 949
 950        get_resources_id(blk->block_info, &pipe_id, &comp_id);
 951
 952        c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*splitter),
 953                                 comp_id,
 954                                 BLOCK_INFO_INPUT_ID(blk->block_info),
 955                                 &d71_splitter_funcs,
 956                                 1, get_valid_inputs(blk), 2, reg,
 957                                 "CU%d_SPLITTER", pipe_id);
 958
 959        if (IS_ERR(c)) {
 960                DRM_ERROR("Failed to initialize splitter");
 961                return -1;
 962        }
 963
 964        splitter = to_splitter(c);
 965
 966        set_range(&splitter->hsize, 4, get_blk_line_size(d71, reg));
 967        set_range(&splitter->vsize, 4, d71->max_vsize);
 968
 969        return 0;
 970}
 971
 972static void d71_merger_update(struct komeda_component *c,
 973                              struct komeda_component_state *state)
 974{
 975        struct komeda_merger_state *st = to_merger_st(state);
 976        u32 __iomem *reg = c->reg;
 977        u32 index;
 978
 979        for_each_changed_input(state, index)
 980                malidp_write32(reg, MG_INPUT_ID0 + index * 4,
 981                               to_d71_input_id(state, index));
 982
 983        malidp_write32(reg, MG_SIZE, HV_SIZE(st->hsize_merged,
 984                                             st->vsize_merged));
 985        malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
 986}
 987
 988static void d71_merger_dump(struct komeda_component *c, struct seq_file *sf)
 989{
 990        u32 v;
 991
 992        dump_block_header(sf, c->reg);
 993
 994        get_values_from_reg(c->reg, MG_INPUT_ID0, 1, &v);
 995        seq_printf(sf, "MG_INPUT_ID0:\t\t0x%X\n", v);
 996
 997        get_values_from_reg(c->reg, MG_INPUT_ID1, 1, &v);
 998        seq_printf(sf, "MG_INPUT_ID1:\t\t0x%X\n", v);
 999
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
1007static 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
1013static 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
1044static 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_YCRCB420)
1082                ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420;
1083        else if (st->color_format == DRM_COLOR_FORMAT_YCRCB422)
1084                ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422;
1085        else if (st->color_format == DRM_COLOR_FORMAT_YCRCB444)
1086                ctrl |= IPS_CTRL_YUV;
1087
1088        malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
1089}
1090
1091static 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
1118static 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
1124static 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_YCRCB444 |
1148                                          DRM_COLOR_FORMAT_YCRCB422;
1149        value = malidp_read32(reg, BLK_INFO);
1150        if (value & IPS_INFO_CHD420)
1151                improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420;
1152
1153        improc->supports_csc = true;
1154        improc->supports_gamma = true;
1155
1156        return 0;
1157}
1158
1159static void d71_timing_ctrlr_disable(struct komeda_component *c)
1160{
1161        malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
1162}
1163
1164static 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
1208static 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
1245static 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
1251static 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
1278int 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
1356static 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
1383static 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
1408static 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
1424static 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
1432const struct komeda_pipeline_funcs d71_pipeline_funcs = {
1433        .downscaling_clk_check  = d71_downscaling_clk_check,
1434        .dump_register          = d71_pipeline_dump,
1435};
1436
1437void 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}
1443