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