1445 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.4 * Author: James.Qian.Wang <james.qian.wang@arm.com>5 *6 */7 8#include <linux/seq_file.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 else86 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 111/* On D71, we are using the global line size. From D32, every component have112 * a line size register to indicate the fifo size.113 */114static u32 __get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg,115 u32 max_default)116{117 if (!d71->periph_addr)118 max_default = malidp_read32(reg, BLK_MAX_LINE_SIZE);119 120 return max_default;121}122 123static u32 get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg)124{125 return __get_blk_line_size(d71, reg, d71->max_line_size);126}127 128static u32 to_rot_ctrl(u32 rot)129{130 u32 lr_ctrl = 0;131 132 switch (rot & DRM_MODE_ROTATE_MASK) {133 case DRM_MODE_ROTATE_0:134 lr_ctrl |= L_ROT(L_ROT_R0);135 break;136 case DRM_MODE_ROTATE_90:137 lr_ctrl |= L_ROT(L_ROT_R90);138 break;139 case DRM_MODE_ROTATE_180:140 lr_ctrl |= L_ROT(L_ROT_R180);141 break;142 case DRM_MODE_ROTATE_270:143 lr_ctrl |= L_ROT(L_ROT_R270);144 break;145 }146 147 if (rot & DRM_MODE_REFLECT_X)148 lr_ctrl |= L_HFLIP;149 if (rot & DRM_MODE_REFLECT_Y)150 lr_ctrl |= L_VFLIP;151 152 return lr_ctrl;153}154 155static u32 to_ad_ctrl(u64 modifier)156{157 u32 afbc_ctrl = AD_AEN;158 159 if (!modifier)160 return 0;161 162 if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==163 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)164 afbc_ctrl |= AD_WB;165 166 if (modifier & AFBC_FORMAT_MOD_YTR)167 afbc_ctrl |= AD_YT;168 if (modifier & AFBC_FORMAT_MOD_SPLIT)169 afbc_ctrl |= AD_BS;170 if (modifier & AFBC_FORMAT_MOD_TILED)171 afbc_ctrl |= AD_TH;172 173 return afbc_ctrl;174}175 176static inline u32 to_d71_input_id(struct komeda_component_state *st, int idx)177{178 struct komeda_component_output *input = &st->inputs[idx];179 180 /* if input is not active, set hw input_id(0) to disable it */181 if (has_bit(idx, st->active_inputs))182 return input->component->hw_id + input->output_port;183 else184 return 0;185}186 187static void d71_layer_update_fb(struct komeda_component *c,188 struct komeda_fb *kfb,189 dma_addr_t *addr)190{191 struct drm_framebuffer *fb = &kfb->base;192 const struct drm_format_info *info = fb->format;193 u32 __iomem *reg = c->reg;194 int block_h;195 196 if (info->num_planes > 2)197 malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]);198 199 if (info->num_planes > 1) {200 block_h = drm_format_info_block_height(info, 1);201 malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h);202 malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]);203 }204 205 block_h = drm_format_info_block_height(info, 0);206 malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h);207 malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]);208 malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);209}210 211static void d71_layer_disable(struct komeda_component *c)212{213 malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);214}215 216static void d71_layer_update(struct komeda_component *c,217 struct komeda_component_state *state)218{219 struct komeda_layer_state *st = to_layer_st(state);220 struct drm_plane_state *plane_st = state->plane->state;221 struct drm_framebuffer *fb = plane_st->fb;222 struct komeda_fb *kfb = to_kfb(fb);223 u32 __iomem *reg = c->reg;224 u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;225 u32 ctrl = L_EN | to_rot_ctrl(st->rot);226 227 d71_layer_update_fb(c, kfb, st->addr);228 229 malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier));230 if (fb->modifier) {231 u64 addr;232 233 malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l,234 st->afbc_crop_r));235 malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t,236 st->afbc_crop_b));237 /* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */238 if (fb->modifier & AFBC_FORMAT_MOD_TILED)239 addr = st->addr[0] + kfb->offset_payload;240 else241 addr = st->addr[0] + kfb->afbc_size - 1;242 243 malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr));244 malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr));245 }246 247 if (fb->format->is_yuv) {248 u32 upsampling = 0;249 250 switch (kfb->format_caps->fourcc) {251 case DRM_FORMAT_YUYV:252 upsampling = fb->modifier ? LR_CHI422_BILINEAR :253 LR_CHI422_REPLICATION;254 break;255 case DRM_FORMAT_UYVY:256 upsampling = LR_CHI422_REPLICATION;257 break;258 case DRM_FORMAT_NV12:259 case DRM_FORMAT_YUV420_8BIT:260 case DRM_FORMAT_YUV420_10BIT:261 case DRM_FORMAT_YUV420:262 case DRM_FORMAT_P010:263 /* these fmt support MPGE/JPEG both, here perfer JPEG*/264 upsampling = LR_CHI420_JPEG;265 break;266 case DRM_FORMAT_X0L2:267 upsampling = LR_CHI420_JPEG;268 break;269 default:270 break;271 }272 273 malidp_write32(reg, LAYER_R_CONTROL, upsampling);274 malidp_write_group(reg, LAYER_YUV_RGB_COEFF0,275 KOMEDA_N_YUV2RGB_COEFFS,276 komeda_select_yuv2rgb_coeffs(277 plane_st->color_encoding,278 plane_st->color_range));279 }280 281 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));282 283 if (kfb->is_va)284 ctrl |= L_TBU_EN;285 malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);286}287 288static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)289{290 u32 v[15], i;291 bool rich, rgb2rgb;292 char *prefix;293 294 get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);295 if (v[14] & 0x1) {296 rich = true;297 prefix = "LR_";298 } else {299 rich = false;300 prefix = "LS_";301 }302 303 rgb2rgb = !!(v[14] & L_INFO_CM);304 305 dump_block_header(sf, c->reg);306 307 seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);308 309 get_values_from_reg(c->reg, 0xD0, 1, v);310 seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);311 if (rich) {312 get_values_from_reg(c->reg, 0xD4, 1, v);313 seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);314 }315 get_values_from_reg(c->reg, 0xD8, 4, v);316 seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);317 seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);318 seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);319 seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);320 321 get_values_from_reg(c->reg, 0x100, 3, v);322 seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);323 seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);324 seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);325 326 get_values_from_reg(c->reg, 0x110, 2, v);327 seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);328 seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);329 if (rich) {330 get_values_from_reg(c->reg, 0x118, 1, v);331 seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);332 333 get_values_from_reg(c->reg, 0x120, 2, v);334 seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);335 seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);336 337 get_values_from_reg(c->reg, 0x130, 12, v);338 for (i = 0; i < 12; i++)339 seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);340 }341 342 if (rgb2rgb) {343 get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);344 for (i = 0; i < 12; i++)345 seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);346 }347 348 get_values_from_reg(c->reg, 0x160, 3, v);349 seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);350 seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);351 seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);352}353 354static int d71_layer_validate(struct komeda_component *c,355 struct komeda_component_state *state)356{357 struct komeda_layer_state *st = to_layer_st(state);358 struct komeda_layer *layer = to_layer(c);359 struct drm_plane_state *plane_st;360 struct drm_framebuffer *fb;361 u32 fourcc, line_sz, max_line_sz;362 363 plane_st = drm_atomic_get_new_plane_state(state->obj.state,364 state->plane);365 fb = plane_st->fb;366 fourcc = fb->format->format;367 368 if (drm_rotation_90_or_270(st->rot))369 line_sz = st->vsize - st->afbc_crop_t - st->afbc_crop_b;370 else371 line_sz = st->hsize - st->afbc_crop_l - st->afbc_crop_r;372 373 if (fb->modifier) {374 if ((fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==375 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)376 max_line_sz = layer->line_sz;377 else378 max_line_sz = layer->line_sz / 2;379 380 if (line_sz > max_line_sz) {381 DRM_DEBUG_ATOMIC("afbc request line_sz: %d exceed the max afbc line_sz: %d.\n",382 line_sz, max_line_sz);383 return -EINVAL;384 }385 }386 387 if (fourcc == DRM_FORMAT_YUV420_10BIT && line_sz > 2046 && (st->afbc_crop_l % 4)) {388 DRM_DEBUG_ATOMIC("YUV420_10BIT input_hsize: %d exceed the max size 2046.\n",389 line_sz);390 return -EINVAL;391 }392 393 if (fourcc == DRM_FORMAT_X0L2 && line_sz > 2046 && (st->addr[0] % 16)) {394 DRM_DEBUG_ATOMIC("X0L2 input_hsize: %d exceed the max size 2046.\n",395 line_sz);396 return -EINVAL;397 }398 399 return 0;400}401 402static const struct komeda_component_funcs d71_layer_funcs = {403 .validate = d71_layer_validate,404 .update = d71_layer_update,405 .disable = d71_layer_disable,406 .dump_register = d71_layer_dump,407};408 409static int d71_layer_init(struct d71_dev *d71,410 struct block_header *blk, u32 __iomem *reg)411{412 struct komeda_component *c;413 struct komeda_layer *layer;414 u32 pipe_id, layer_id, layer_info;415 416 get_resources_id(blk->block_info, &pipe_id, &layer_id);417 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),418 layer_id,419 BLOCK_INFO_INPUT_ID(blk->block_info),420 &d71_layer_funcs, 0,421 get_valid_inputs(blk),422 1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);423 if (IS_ERR(c)) {424 DRM_ERROR("Failed to add layer component\n");425 return PTR_ERR(c);426 }427 428 layer = to_layer(c);429 layer_info = malidp_read32(reg, LAYER_INFO);430 431 if (layer_info & L_INFO_RF)432 layer->layer_type = KOMEDA_FMT_RICH_LAYER;433 else434 layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;435 436 if (!d71->periph_addr) {437 /* D32 or newer product */438 layer->line_sz = malidp_read32(reg, BLK_MAX_LINE_SIZE);439 layer->yuv_line_sz = L_INFO_YUV_MAX_LINESZ(layer_info);440 } else if (d71->max_line_size > 2048) {441 /* D71 4K */442 layer->line_sz = d71->max_line_size;443 layer->yuv_line_sz = layer->line_sz / 2;444 } else {445 /* D71 2K */446 if (layer->layer_type == KOMEDA_FMT_RICH_LAYER) {447 /* rich layer is 4K configuration */448 layer->line_sz = d71->max_line_size * 2;449 layer->yuv_line_sz = layer->line_sz / 2;450 } else {451 layer->line_sz = d71->max_line_size;452 layer->yuv_line_sz = 0;453 }454 }455 456 set_range(&layer->hsize_in, 4, layer->line_sz);457 458 set_range(&layer->vsize_in, 4, d71->max_vsize);459 460 malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);461 462 layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;463 464 return 0;465}466 467static void d71_wb_layer_update(struct komeda_component *c,468 struct komeda_component_state *state)469{470 struct komeda_layer_state *st = to_layer_st(state);471 struct drm_connector_state *conn_st = state->wb_conn->state;472 struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);473 u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN;474 u32 __iomem *reg = c->reg;475 476 d71_layer_update_fb(c, kfb, st->addr);477 478 if (kfb->is_va)479 ctrl |= LW_TBU_EN;480 481 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));482 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));483 malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);484}485 486static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf)487{488 u32 v[12], i;489 490 dump_block_header(sf, c->reg);491 492 get_values_from_reg(c->reg, 0x80, 1, v);493 seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]);494 495 get_values_from_reg(c->reg, 0xD0, 3, v);496 seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]);497 seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]);498 seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]);499 500 get_values_from_reg(c->reg, 0xE0, 1, v);501 seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]);502 503 for (i = 0; i < 2; i++) {504 get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v);505 seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]);506 seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]);507 seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]);508 }509 510 get_values_from_reg(c->reg, 0x130, 12, v);511 for (i = 0; i < 12; i++)512 seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);513}514 515static void d71_wb_layer_disable(struct komeda_component *c)516{517 malidp_write32(c->reg, BLK_INPUT_ID0, 0);518 malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);519}520 521static const struct komeda_component_funcs d71_wb_layer_funcs = {522 .update = d71_wb_layer_update,523 .disable = d71_wb_layer_disable,524 .dump_register = d71_wb_layer_dump,525};526 527static int d71_wb_layer_init(struct d71_dev *d71,528 struct block_header *blk, u32 __iomem *reg)529{530 struct komeda_component *c;531 struct komeda_layer *wb_layer;532 u32 pipe_id, layer_id;533 534 get_resources_id(blk->block_info, &pipe_id, &layer_id);535 536 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer),537 layer_id, BLOCK_INFO_INPUT_ID(blk->block_info),538 &d71_wb_layer_funcs,539 1, get_valid_inputs(blk), 0, reg,540 "LPU%d_LAYER_WR", pipe_id);541 if (IS_ERR(c)) {542 DRM_ERROR("Failed to add wb_layer component\n");543 return PTR_ERR(c);544 }545 546 wb_layer = to_layer(c);547 wb_layer->layer_type = KOMEDA_FMT_WB_LAYER;548 wb_layer->line_sz = get_blk_line_size(d71, reg);549 wb_layer->yuv_line_sz = wb_layer->line_sz;550 551 set_range(&wb_layer->hsize_in, 64, wb_layer->line_sz);552 set_range(&wb_layer->vsize_in, 64, d71->max_vsize);553 554 return 0;555}556 557static void d71_component_disable(struct komeda_component *c)558{559 u32 __iomem *reg = c->reg;560 u32 i;561 562 malidp_write32(reg, BLK_CONTROL, 0);563 564 for (i = 0; i < c->max_active_inputs; i++) {565 malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);566 567 /* Besides clearing the input ID to zero, D71 compiz also has568 * input enable bit in CU_INPUTx_CONTROL which need to be569 * cleared.570 */571 if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS))572 malidp_write32(reg, CU_INPUT0_CONTROL +573 i * CU_PER_INPUT_REGS * 4,574 CU_INPUT_CTRL_ALPHA(0xFF));575 }576}577 578static void compiz_enable_input(u32 __iomem *id_reg,579 u32 __iomem *cfg_reg,580 u32 input_hw_id,581 struct komeda_compiz_input_cfg *cin)582{583 u32 ctrl = CU_INPUT_CTRL_EN;584 u8 blend = cin->pixel_blend_mode;585 586 if (blend == DRM_MODE_BLEND_PIXEL_NONE)587 ctrl |= CU_INPUT_CTRL_PAD;588 else if (blend == DRM_MODE_BLEND_PREMULTI)589 ctrl |= CU_INPUT_CTRL_PMUL;590 591 ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);592 593 malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);594 595 malidp_write32(cfg_reg, CU_INPUT0_SIZE,596 HV_SIZE(cin->hsize, cin->vsize));597 malidp_write32(cfg_reg, CU_INPUT0_OFFSET,598 HV_OFFSET(cin->hoffset, cin->voffset));599 malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);600}601 602static void d71_compiz_update(struct komeda_component *c,603 struct komeda_component_state *state)604{605 struct komeda_compiz_state *st = to_compiz_st(state);606 u32 __iomem *reg = c->reg;607 u32 __iomem *id_reg, *cfg_reg;608 u32 index;609 610 for_each_changed_input(state, index) {611 id_reg = reg + index;612 cfg_reg = reg + index * CU_PER_INPUT_REGS;613 if (state->active_inputs & BIT(index)) {614 compiz_enable_input(id_reg, cfg_reg,615 to_d71_input_id(state, index),616 &st->cins[index]);617 } else {618 malidp_write32(id_reg, BLK_INPUT_ID0, 0);619 malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);620 }621 }622 623 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));624}625 626static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)627{628 u32 v[8], i;629 630 dump_block_header(sf, c->reg);631 632 get_values_from_reg(c->reg, 0x80, 5, v);633 for (i = 0; i < 5; i++)634 seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);635 636 get_values_from_reg(c->reg, 0xA0, 5, v);637 seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);638 seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);639 seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);640 seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);641 seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);642 643 get_values_from_reg(c->reg, 0xD0, 2, v);644 seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);645 seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);646 647 get_values_from_reg(c->reg, 0xDC, 1, v);648 seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);649 650 for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {651 get_values_from_reg(c->reg, v[4], 3, v);652 seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);653 seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);654 seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);655 }656 657 get_values_from_reg(c->reg, 0x130, 2, v);658 seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);659 seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);660}661 662static const struct komeda_component_funcs d71_compiz_funcs = {663 .update = d71_compiz_update,664 .disable = d71_component_disable,665 .dump_register = d71_compiz_dump,666};667 668static int d71_compiz_init(struct d71_dev *d71,669 struct block_header *blk, u32 __iomem *reg)670{671 struct komeda_component *c;672 struct komeda_compiz *compiz;673 u32 pipe_id, comp_id;674 675 get_resources_id(blk->block_info, &pipe_id, &comp_id);676 677 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),678 comp_id,679 BLOCK_INFO_INPUT_ID(blk->block_info),680 &d71_compiz_funcs,681 CU_NUM_INPUT_IDS, get_valid_inputs(blk),682 CU_NUM_OUTPUT_IDS, reg,683 "CU%d", pipe_id);684 if (IS_ERR(c))685 return PTR_ERR(c);686 687 compiz = to_compiz(c);688 689 set_range(&compiz->hsize, 64, get_blk_line_size(d71, reg));690 set_range(&compiz->vsize, 64, d71->max_vsize);691 692 return 0;693}694 695static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in,696 u32 vsize_in, u32 hsize_out,697 u32 vsize_out)698{699 u32 val = 0;700 701 if (hsize_in <= hsize_out)702 val |= 0x62;703 else if (hsize_in <= (hsize_out + hsize_out / 2))704 val |= 0x63;705 else if (hsize_in <= hsize_out * 2)706 val |= 0x64;707 else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4)708 val |= 0x65;709 else710 val |= 0x66;711 712 if (vsize_in <= vsize_out)713 val |= SC_VTSEL(0x6A);714 else if (vsize_in <= (vsize_out + vsize_out / 2))715 val |= SC_VTSEL(0x6B);716 else if (vsize_in <= vsize_out * 2)717 val |= SC_VTSEL(0x6C);718 else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4)719 val |= SC_VTSEL(0x6D);720 else721 val |= SC_VTSEL(0x6E);722 723 malidp_write32(reg, SC_COEFFTAB, val);724}725 726static void d71_scaler_update(struct komeda_component *c,727 struct komeda_component_state *state)728{729 struct komeda_scaler_state *st = to_scaler_st(state);730 u32 __iomem *reg = c->reg;731 u32 init_ph, delta_ph, ctrl;732 733 d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in,734 st->hsize_out, st->vsize_out);735 736 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));737 malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));738 malidp_write32(reg, SC_H_CROP, HV_CROP(st->left_crop, st->right_crop));739 740 /* for right part, HW only sample the valid pixel which means the pixels741 * in left_crop will be jumpped, and the first sample pixel is:742 *743 * dst_a = st->total_hsize_out - st->hsize_out + st->left_crop + 0.5;744 *745 * Then the corresponding texel in src is:746 *747 * h_delta_phase = st->total_hsize_in / st->total_hsize_out;748 * src_a = dst_A * h_delta_phase;749 *750 * and h_init_phase is src_a deduct the real source start src_S;751 *752 * src_S = st->total_hsize_in - st->hsize_in;753 * h_init_phase = src_a - src_S;754 *755 * And HW precision for the initial/delta_phase is 16:16 fixed point,756 * the following is the simplified formula757 */758 if (st->right_part) {759 u32 dst_a = st->total_hsize_out - st->hsize_out + st->left_crop;760 761 if (st->en_img_enhancement)762 dst_a -= 1;763 764 init_ph = ((st->total_hsize_in * (2 * dst_a + 1) -765 2 * st->total_hsize_out * (st->total_hsize_in -766 st->hsize_in)) << 15) / st->total_hsize_out;767 } else {768 init_ph = (st->total_hsize_in << 15) / st->total_hsize_out;769 }770 771 malidp_write32(reg, SC_H_INIT_PH, init_ph);772 773 delta_ph = (st->total_hsize_in << 16) / st->total_hsize_out;774 malidp_write32(reg, SC_H_DELTA_PH, delta_ph);775 776 init_ph = (st->total_vsize_in << 15) / st->vsize_out;777 malidp_write32(reg, SC_V_INIT_PH, init_ph);778 779 delta_ph = (st->total_vsize_in << 16) / st->vsize_out;780 malidp_write32(reg, SC_V_DELTA_PH, delta_ph);781 782 ctrl = 0;783 ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;784 ctrl |= st->en_alpha ? SC_CTRL_AP : 0;785 ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0;786 /* If we use the hardware splitter we shouldn't set SC_CTRL_LS */787 if (st->en_split &&788 state->inputs[0].component->id != KOMEDA_COMPONENT_SPLITTER)789 ctrl |= SC_CTRL_LS;790 791 malidp_write32(reg, BLK_CONTROL, ctrl);792 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));793}794 795static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)796{797 u32 v[10];798 799 dump_block_header(sf, c->reg);800 801 get_values_from_reg(c->reg, 0x80, 1, v);802 seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]);803 804 get_values_from_reg(c->reg, 0xD0, 1, v);805 seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]);806 807 get_values_from_reg(c->reg, 0xDC, 9, v);808 seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]);809 seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]);810 seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]);811 seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]);812 seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]);813 seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]);814 seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);815 seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);816 seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]);817 818 get_values_from_reg(c->reg, 0x130, 10, v);819 seq_printf(sf, "SC_ENH_LIMITS:\t\t0x%X\n", v[0]);820 seq_printf(sf, "SC_ENH_COEFF0:\t\t0x%X\n", v[1]);821 seq_printf(sf, "SC_ENH_COEFF1:\t\t0x%X\n", v[2]);822 seq_printf(sf, "SC_ENH_COEFF2:\t\t0x%X\n", v[3]);823 seq_printf(sf, "SC_ENH_COEFF3:\t\t0x%X\n", v[4]);824 seq_printf(sf, "SC_ENH_COEFF4:\t\t0x%X\n", v[5]);825 seq_printf(sf, "SC_ENH_COEFF5:\t\t0x%X\n", v[6]);826 seq_printf(sf, "SC_ENH_COEFF6:\t\t0x%X\n", v[7]);827 seq_printf(sf, "SC_ENH_COEFF7:\t\t0x%X\n", v[8]);828 seq_printf(sf, "SC_ENH_COEFF8:\t\t0x%X\n", v[9]);829}830 831static const struct komeda_component_funcs d71_scaler_funcs = {832 .update = d71_scaler_update,833 .disable = d71_component_disable,834 .dump_register = d71_scaler_dump,835};836 837static int d71_scaler_init(struct d71_dev *d71,838 struct block_header *blk, u32 __iomem *reg)839{840 struct komeda_component *c;841 struct komeda_scaler *scaler;842 u32 pipe_id, comp_id;843 844 get_resources_id(blk->block_info, &pipe_id, &comp_id);845 846 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler),847 comp_id, BLOCK_INFO_INPUT_ID(blk->block_info),848 &d71_scaler_funcs,849 1, get_valid_inputs(blk), 1, reg,850 "CU%d_SCALER%d",851 pipe_id, BLOCK_INFO_BLK_ID(blk->block_info));852 853 if (IS_ERR(c)) {854 DRM_ERROR("Failed to initialize scaler");855 return PTR_ERR(c);856 }857 858 scaler = to_scaler(c);859 set_range(&scaler->hsize, 4, __get_blk_line_size(d71, reg, 2048));860 set_range(&scaler->vsize, 4, 4096);861 scaler->max_downscaling = 6;862 scaler->max_upscaling = 64;863 scaler->scaling_split_overlap = 8;864 scaler->enh_split_overlap = 1;865 866 malidp_write32(c->reg, BLK_CONTROL, 0);867 868 return 0;869}870 871static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,872 struct drm_display_mode *mode,873 unsigned long aclk_rate,874 struct komeda_data_flow_cfg *dflow)875{876 u32 h_in = dflow->in_w;877 u32 v_in = dflow->in_h;878 u32 v_out = dflow->out_h;879 u64 fraction, denominator;880 881 /* D71 downscaling must satisfy the following equation882 *883 * ACLK h_in * v_in884 * ------- >= ---------------------------------------------885 * PXLCLK (h_total - (1 + 2 * v_in / v_out)) * v_out886 *887 * In only horizontal downscaling situation, the right side should be888 * multiplied by (h_total - 3) / (h_active - 3), then equation becomes889 *890 * ACLK h_in891 * ------- >= ----------------892 * PXLCLK (h_active - 3)893 *894 * To avoid precision lost the equation 1 will be convert to:895 *896 * ACLK h_in * v_in897 * ------- >= -----------------------------------898 * PXLCLK (h_total -1 ) * v_out - 2 * v_in899 */900 if (v_in == v_out) {901 fraction = h_in;902 denominator = mode->hdisplay - 3;903 } else {904 fraction = h_in * v_in;905 denominator = (mode->htotal - 1) * v_out - 2 * v_in;906 }907 908 return aclk_rate * denominator >= mode->crtc_clock * 1000 * fraction ?909 0 : -EINVAL;910}911 912static void d71_splitter_update(struct komeda_component *c,913 struct komeda_component_state *state)914{915 struct komeda_splitter_state *st = to_splitter_st(state);916 u32 __iomem *reg = c->reg;917 918 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));919 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));920 malidp_write32(reg, SP_OVERLAP_SIZE, st->overlap & 0x1FFF);921 malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);922}923 924static void d71_splitter_dump(struct komeda_component *c, struct seq_file *sf)925{926 u32 v[3];927 928 dump_block_header(sf, c->reg);929 930 get_values_from_reg(c->reg, BLK_INPUT_ID0, 1, v);931 seq_printf(sf, "SP_INPUT_ID0:\t\t0x%X\n", v[0]);932 933 get_values_from_reg(c->reg, BLK_CONTROL, 3, v);934 seq_printf(sf, "SP_CONTROL:\t\t0x%X\n", v[0]);935 seq_printf(sf, "SP_SIZE:\t\t0x%X\n", v[1]);936 seq_printf(sf, "SP_OVERLAP_SIZE:\t0x%X\n", v[2]);937}938 939static const struct komeda_component_funcs d71_splitter_funcs = {940 .update = d71_splitter_update,941 .disable = d71_component_disable,942 .dump_register = d71_splitter_dump,943};944 945static int d71_splitter_init(struct d71_dev *d71,946 struct block_header *blk, u32 __iomem *reg)947{948 struct komeda_component *c;949 struct komeda_splitter *splitter;950 u32 pipe_id, comp_id;951 952 get_resources_id(blk->block_info, &pipe_id, &comp_id);953 954 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*splitter),955 comp_id,956 BLOCK_INFO_INPUT_ID(blk->block_info),957 &d71_splitter_funcs,958 1, get_valid_inputs(blk), 2, reg,959 "CU%d_SPLITTER", pipe_id);960 961 if (IS_ERR(c)) {962 DRM_ERROR("Failed to initialize splitter");963 return -1;964 }965 966 splitter = to_splitter(c);967 968 set_range(&splitter->hsize, 4, get_blk_line_size(d71, reg));969 set_range(&splitter->vsize, 4, d71->max_vsize);970 971 return 0;972}973 974static void d71_merger_update(struct komeda_component *c,975 struct komeda_component_state *state)976{977 struct komeda_merger_state *st = to_merger_st(state);978 u32 __iomem *reg = c->reg;979 u32 index;980 981 for_each_changed_input(state, index)982 malidp_write32(reg, MG_INPUT_ID0 + index * 4,983 to_d71_input_id(state, index));984 985 malidp_write32(reg, MG_SIZE, HV_SIZE(st->hsize_merged,986 st->vsize_merged));987 malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);988}989 990static void d71_merger_dump(struct komeda_component *c, struct seq_file *sf)991{992 u32 v;993 994 dump_block_header(sf, c->reg);995 996 get_values_from_reg(c->reg, MG_INPUT_ID0, 1, &v);997 seq_printf(sf, "MG_INPUT_ID0:\t\t0x%X\n", v);998 999 get_values_from_reg(c->reg, MG_INPUT_ID1, 1, &v);1000 seq_printf(sf, "MG_INPUT_ID1:\t\t0x%X\n", v);1001 1002 get_values_from_reg(c->reg, BLK_CONTROL, 1, &v);1003 seq_printf(sf, "MG_CONTROL:\t\t0x%X\n", v);1004 1005 get_values_from_reg(c->reg, MG_SIZE, 1, &v);1006 seq_printf(sf, "MG_SIZE:\t\t0x%X\n", v);1007}1008 1009static const struct komeda_component_funcs d71_merger_funcs = {1010 .update = d71_merger_update,1011 .disable = d71_component_disable,1012 .dump_register = d71_merger_dump,1013};1014 1015static int d71_merger_init(struct d71_dev *d71,1016 struct block_header *blk, u32 __iomem *reg)1017{1018 struct komeda_component *c;1019 struct komeda_merger *merger;1020 u32 pipe_id, comp_id;1021 1022 get_resources_id(blk->block_info, &pipe_id, &comp_id);1023 1024 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*merger),1025 comp_id,1026 BLOCK_INFO_INPUT_ID(blk->block_info),1027 &d71_merger_funcs,1028 MG_NUM_INPUTS_IDS, get_valid_inputs(blk),1029 MG_NUM_OUTPUTS_IDS, reg,1030 "CU%d_MERGER", pipe_id);1031 1032 if (IS_ERR(c)) {1033 DRM_ERROR("Failed to initialize merger.\n");1034 return PTR_ERR(c);1035 }1036 1037 merger = to_merger(c);1038 1039 set_range(&merger->hsize_merged, 4,1040 __get_blk_line_size(d71, reg, 4032));1041 set_range(&merger->vsize_merged, 4, 4096);1042 1043 return 0;1044}1045 1046static void d71_improc_update(struct komeda_component *c,1047 struct komeda_component_state *state)1048{1049 struct drm_crtc_state *crtc_st = state->crtc->state;1050 struct komeda_improc_state *st = to_improc_st(state);1051 struct d71_pipeline *pipe = to_d71_pipeline(c->pipeline);1052 u32 __iomem *reg = c->reg;1053 u32 index, mask = 0, ctrl = 0;1054 1055 for_each_changed_input(state, index)1056 malidp_write32(reg, BLK_INPUT_ID0 + index * 4,1057 to_d71_input_id(state, index));1058 1059 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));1060 malidp_write32(reg, IPS_DEPTH, st->color_depth);1061 1062 if (crtc_st->color_mgmt_changed) {1063 mask |= IPS_CTRL_FT | IPS_CTRL_RGB;1064 1065 if (crtc_st->gamma_lut) {1066 malidp_write_group(pipe->dou_ft_coeff_addr, FT_COEFF0,1067 KOMEDA_N_GAMMA_COEFFS,1068 st->fgamma_coeffs);1069 ctrl |= IPS_CTRL_FT; /* enable gamma */1070 }1071 1072 if (crtc_st->ctm) {1073 malidp_write_group(reg, IPS_RGB_RGB_COEFF0,1074 KOMEDA_N_CTM_COEFFS,1075 st->ctm_coeffs);1076 ctrl |= IPS_CTRL_RGB; /* enable gamut */1077 }1078 }1079 1080 mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420;1081 1082 /* config color format */1083 if (st->color_format == DRM_COLOR_FORMAT_YCBCR420)1084 ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420;1085 else if (st->color_format == DRM_COLOR_FORMAT_YCBCR422)1086 ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422;1087 else if (st->color_format == DRM_COLOR_FORMAT_YCBCR444)1088 ctrl |= IPS_CTRL_YUV;1089 1090 malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);1091}1092 1093static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)1094{1095 u32 v[12], i;1096 1097 dump_block_header(sf, c->reg);1098 1099 get_values_from_reg(c->reg, 0x80, 2, v);1100 seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);1101 seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);1102 1103 get_values_from_reg(c->reg, 0xC0, 1, v);1104 seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);1105 1106 get_values_from_reg(c->reg, 0xD0, 3, v);1107 seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);1108 seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);1109 seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);1110 1111 get_values_from_reg(c->reg, 0x130, 12, v);1112 for (i = 0; i < 12; i++)1113 seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);1114 1115 get_values_from_reg(c->reg, 0x170, 12, v);1116 for (i = 0; i < 12; i++)1117 seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);1118}1119 1120static const struct komeda_component_funcs d71_improc_funcs = {1121 .update = d71_improc_update,1122 .disable = d71_component_disable,1123 .dump_register = d71_improc_dump,1124};1125 1126static int d71_improc_init(struct d71_dev *d71,1127 struct block_header *blk, u32 __iomem *reg)1128{1129 struct komeda_component *c;1130 struct komeda_improc *improc;1131 u32 pipe_id, comp_id, value;1132 1133 get_resources_id(blk->block_info, &pipe_id, &comp_id);1134 1135 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),1136 comp_id,1137 BLOCK_INFO_INPUT_ID(blk->block_info),1138 &d71_improc_funcs, IPS_NUM_INPUT_IDS,1139 get_valid_inputs(blk),1140 IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);1141 if (IS_ERR(c)) {1142 DRM_ERROR("Failed to add improc component\n");1143 return PTR_ERR(c);1144 }1145 1146 improc = to_improc(c);1147 improc->supported_color_depths = BIT(8) | BIT(10);1148 improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |1149 DRM_COLOR_FORMAT_YCBCR444 |1150 DRM_COLOR_FORMAT_YCBCR422;1151 value = malidp_read32(reg, BLK_INFO);1152 if (value & IPS_INFO_CHD420)1153 improc->supported_color_formats |= DRM_COLOR_FORMAT_YCBCR420;1154 1155 improc->supports_csc = true;1156 improc->supports_gamma = true;1157 1158 return 0;1159}1160 1161static void d71_timing_ctrlr_disable(struct komeda_component *c)1162{1163 malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);1164}1165 1166static void d71_timing_ctrlr_update(struct komeda_component *c,1167 struct komeda_component_state *state)1168{1169 struct drm_crtc_state *crtc_st = state->crtc->state;1170 struct drm_display_mode *mode = &crtc_st->adjusted_mode;1171 u32 __iomem *reg = c->reg;1172 u32 hactive, hfront_porch, hback_porch, hsync_len;1173 u32 vactive, vfront_porch, vback_porch, vsync_len;1174 u32 value;1175 1176 hactive = mode->crtc_hdisplay;1177 hfront_porch = mode->crtc_hsync_start - mode->crtc_hdisplay;1178 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;1179 hback_porch = mode->crtc_htotal - mode->crtc_hsync_end;1180 1181 vactive = mode->crtc_vdisplay;1182 vfront_porch = mode->crtc_vsync_start - mode->crtc_vdisplay;1183 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;1184 vback_porch = mode->crtc_vtotal - mode->crtc_vsync_end;1185 1186 malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(hactive, vactive));1187 malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(hfront_porch,1188 hback_porch));1189 malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vfront_porch,1190 vback_porch));1191 1192 value = BS_SYNC_VSW(vsync_len) | BS_SYNC_HSW(hsync_len);1193 value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BS_SYNC_VSP : 0;1194 value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BS_SYNC_HSP : 0;1195 malidp_write32(reg, BS_SYNC, value);1196 1197 malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);1198 malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);1199 1200 /* configure bs control register */1201 value = BS_CTRL_EN | BS_CTRL_VM;1202 if (c->pipeline->dual_link) {1203 malidp_write32(reg, BS_DRIFT_TO, hfront_porch + 16);1204 value |= BS_CTRL_DL;1205 }1206 1207 malidp_write32(reg, BLK_CONTROL, value);1208}1209 1210static void d71_timing_ctrlr_dump(struct komeda_component *c,1211 struct seq_file *sf)1212{1213 u32 v[8], i;1214 1215 dump_block_header(sf, c->reg);1216 1217 get_values_from_reg(c->reg, 0xC0, 1, v);1218 seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);1219 1220 get_values_from_reg(c->reg, 0xD0, 8, v);1221 seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);1222 seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);1223 seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);1224 seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);1225 seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);1226 seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);1227 seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);1228 seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);1229 1230 get_values_from_reg(c->reg, 0x100, 3, v);1231 seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);1232 seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);1233 seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);1234 1235 get_values_from_reg(c->reg, 0x110, 3, v);1236 for (i = 0; i < 3; i++)1237 seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);1238 1239 get_values_from_reg(c->reg, 0x120, 5, v);1240 for (i = 0; i < 2; i++) {1241 seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);1242 seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);1243 }1244 seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);1245}1246 1247static const struct komeda_component_funcs d71_timing_ctrlr_funcs = {1248 .update = d71_timing_ctrlr_update,1249 .disable = d71_timing_ctrlr_disable,1250 .dump_register = d71_timing_ctrlr_dump,1251};1252 1253static int d71_timing_ctrlr_init(struct d71_dev *d71,1254 struct block_header *blk, u32 __iomem *reg)1255{1256 struct komeda_component *c;1257 struct komeda_timing_ctrlr *ctrlr;1258 u32 pipe_id, comp_id;1259 1260 get_resources_id(blk->block_info, &pipe_id, &comp_id);1261 1262 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),1263 KOMEDA_COMPONENT_TIMING_CTRLR,1264 BLOCK_INFO_INPUT_ID(blk->block_info),1265 &d71_timing_ctrlr_funcs,1266 1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),1267 BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);1268 if (IS_ERR(c)) {1269 DRM_ERROR("Failed to add display_ctrl component\n");1270 return PTR_ERR(c);1271 }1272 1273 ctrlr = to_ctrlr(c);1274 1275 ctrlr->supports_dual_link = d71->supports_dual_link;1276 1277 return 0;1278}1279 1280int d71_probe_block(struct d71_dev *d71,1281 struct block_header *blk, u32 __iomem *reg)1282{1283 struct d71_pipeline *pipe;1284 int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);1285 1286 int err = 0;1287 1288 switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {1289 case D71_BLK_TYPE_GCU:1290 break;1291 1292 case D71_BLK_TYPE_LPU:1293 pipe = d71->pipes[blk_id];1294 pipe->lpu_addr = reg;1295 break;1296 1297 case D71_BLK_TYPE_LPU_LAYER:1298 err = d71_layer_init(d71, blk, reg);1299 break;1300 1301 case D71_BLK_TYPE_LPU_WB_LAYER:1302 err = d71_wb_layer_init(d71, blk, reg);1303 break;1304 1305 case D71_BLK_TYPE_CU:1306 pipe = d71->pipes[blk_id];1307 pipe->cu_addr = reg;1308 err = d71_compiz_init(d71, blk, reg);1309 break;1310 1311 case D71_BLK_TYPE_CU_SCALER:1312 err = d71_scaler_init(d71, blk, reg);1313 break;1314 1315 case D71_BLK_TYPE_CU_SPLITTER:1316 err = d71_splitter_init(d71, blk, reg);1317 break;1318 1319 case D71_BLK_TYPE_CU_MERGER:1320 err = d71_merger_init(d71, blk, reg);1321 break;1322 1323 case D71_BLK_TYPE_DOU:1324 pipe = d71->pipes[blk_id];1325 pipe->dou_addr = reg;1326 break;1327 1328 case D71_BLK_TYPE_DOU_IPS:1329 err = d71_improc_init(d71, blk, reg);1330 break;1331 1332 case D71_BLK_TYPE_DOU_FT_COEFF:1333 pipe = d71->pipes[blk_id];1334 pipe->dou_ft_coeff_addr = reg;1335 break;1336 1337 case D71_BLK_TYPE_DOU_BS:1338 err = d71_timing_ctrlr_init(d71, blk, reg);1339 break;1340 1341 case D71_BLK_TYPE_GLB_LT_COEFF:1342 break;1343 1344 case D71_BLK_TYPE_GLB_SCL_COEFF:1345 d71->glb_scl_coeff_addr[blk_id] = reg;1346 break;1347 1348 default:1349 DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",1350 blk->block_info);1351 err = -EINVAL;1352 break;1353 }1354 1355 return err;1356}1357 1358static void d71_gcu_dump(struct d71_dev *d71, struct seq_file *sf)1359{1360 u32 v[5];1361 1362 seq_puts(sf, "\n------ GCU ------\n");1363 1364 get_values_from_reg(d71->gcu_addr, 0, 3, v);1365 seq_printf(sf, "GLB_ARCH_ID:\t\t0x%X\n", v[0]);1366 seq_printf(sf, "GLB_CORE_ID:\t\t0x%X\n", v[1]);1367 seq_printf(sf, "GLB_CORE_INFO:\t\t0x%X\n", v[2]);1368 1369 get_values_from_reg(d71->gcu_addr, 0x10, 1, v);1370 seq_printf(sf, "GLB_IRQ_STATUS:\t\t0x%X\n", v[0]);1371 1372 get_values_from_reg(d71->gcu_addr, 0xA0, 5, v);1373 seq_printf(sf, "GCU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);1374 seq_printf(sf, "GCU_IRQ_CLEAR:\t\t0x%X\n", v[1]);1375 seq_printf(sf, "GCU_IRQ_MASK:\t\t0x%X\n", v[2]);1376 seq_printf(sf, "GCU_IRQ_STATUS:\t\t0x%X\n", v[3]);1377 seq_printf(sf, "GCU_STATUS:\t\t0x%X\n", v[4]);1378 1379 get_values_from_reg(d71->gcu_addr, 0xD0, 3, v);1380 seq_printf(sf, "GCU_CONTROL:\t\t0x%X\n", v[0]);1381 seq_printf(sf, "GCU_CONFIG_VALID0:\t0x%X\n", v[1]);1382 seq_printf(sf, "GCU_CONFIG_VALID1:\t0x%X\n", v[2]);1383}1384 1385static void d71_lpu_dump(struct d71_pipeline *pipe, struct seq_file *sf)1386{1387 u32 v[6];1388 1389 seq_printf(sf, "\n------ LPU%d ------\n", pipe->base.id);1390 1391 dump_block_header(sf, pipe->lpu_addr);1392 1393 get_values_from_reg(pipe->lpu_addr, 0xA0, 6, v);1394 seq_printf(sf, "LPU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);1395 seq_printf(sf, "LPU_IRQ_CLEAR:\t\t0x%X\n", v[1]);1396 seq_printf(sf, "LPU_IRQ_MASK:\t\t0x%X\n", v[2]);1397 seq_printf(sf, "LPU_IRQ_STATUS:\t\t0x%X\n", v[3]);1398 seq_printf(sf, "LPU_STATUS:\t\t0x%X\n", v[4]);1399 seq_printf(sf, "LPU_TBU_STATUS:\t\t0x%X\n", v[5]);1400 1401 get_values_from_reg(pipe->lpu_addr, 0xC0, 1, v);1402 seq_printf(sf, "LPU_INFO:\t\t0x%X\n", v[0]);1403 1404 get_values_from_reg(pipe->lpu_addr, 0xD0, 3, v);1405 seq_printf(sf, "LPU_RAXI_CONTROL:\t0x%X\n", v[0]);1406 seq_printf(sf, "LPU_WAXI_CONTROL:\t0x%X\n", v[1]);1407 seq_printf(sf, "LPU_TBU_CONTROL:\t0x%X\n", v[2]);1408}1409 1410static void d71_dou_dump(struct d71_pipeline *pipe, struct seq_file *sf)1411{1412 u32 v[5];1413 1414 seq_printf(sf, "\n------ DOU%d ------\n", pipe->base.id);1415 1416 dump_block_header(sf, pipe->dou_addr);1417 1418 get_values_from_reg(pipe->dou_addr, 0xA0, 5, v);1419 seq_printf(sf, "DOU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);1420 seq_printf(sf, "DOU_IRQ_CLEAR:\t\t0x%X\n", v[1]);1421 seq_printf(sf, "DOU_IRQ_MASK:\t\t0x%X\n", v[2]);1422 seq_printf(sf, "DOU_IRQ_STATUS:\t\t0x%X\n", v[3]);1423 seq_printf(sf, "DOU_STATUS:\t\t0x%X\n", v[4]);1424}1425 1426static void d71_pipeline_dump(struct komeda_pipeline *pipe, struct seq_file *sf)1427{1428 struct d71_pipeline *d71_pipe = to_d71_pipeline(pipe);1429 1430 d71_lpu_dump(d71_pipe, sf);1431 d71_dou_dump(d71_pipe, sf);1432}1433 1434const struct komeda_pipeline_funcs d71_pipeline_funcs = {1435 .downscaling_clk_check = d71_downscaling_clk_check,1436 .dump_register = d71_pipeline_dump,1437};1438 1439void d71_dump(struct komeda_dev *mdev, struct seq_file *sf)1440{1441 struct d71_dev *d71 = mdev->chip_data;1442 1443 d71_gcu_dump(d71, sf);1444}1445