1 // SPDX-License-Identifier: GPL-2.0
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
8 #include <drm/drm_print.h>
10 #include "komeda_kms.h"
11 #include "malidp_io.h"
12 #include "komeda_framebuffer.h"
13 #include "komeda_color_mgmt.h"
15 static void get_resources_id(u32 hw_id, u32 *pipe_id, u32 *comp_id)
17 u32 id = BLOCK_INFO_BLK_ID(hw_id);
20 switch (BLOCK_INFO_BLK_TYPE(hw_id)) {
21 case D71_BLK_TYPE_LPU_WB_LAYER:
22 id = KOMEDA_COMPONENT_WB_LAYER;
24 case D71_BLK_TYPE_CU_SPLITTER:
25 id = KOMEDA_COMPONENT_SPLITTER;
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;
33 id += KOMEDA_COMPONENT_COMPIZ0;
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;
40 case D71_BLK_TYPE_DOU_IPS:
41 id += KOMEDA_COMPONENT_IPS0;
43 case D71_BLK_TYPE_CU_MERGER:
44 id = KOMEDA_COMPONENT_MERGER;
46 case D71_BLK_TYPE_DOU:
47 id = KOMEDA_COMPONENT_TIMING_CTRLR;
60 static u32 get_valid_inputs(struct block_header *blk)
62 u32 valid_inputs = 0, comp_id;
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)
69 valid_inputs |= BIT(comp_id);
75 static void get_values_from_reg(void __iomem *reg, u32 offset,
80 for (i = 0; i < count; i++) {
81 addr = offset + (i << 2);
82 /* 0xA4 is WO register */
84 val[i] = malidp_read32(reg, addr);
90 static void dump_block_header(struct seq_file *sf, void __iomem *reg)
92 struct block_header hdr;
93 u32 i, n_input, n_output;
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);
99 n_output = PIPELINE_INFO_N_OUTPUTS(hdr.pipeline_info);
100 n_input = PIPELINE_INFO_N_VALID_INPUTS(hdr.pipeline_info);
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]);
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]);
111 static u32 to_rot_ctrl(u32 rot)
115 switch (rot & DRM_MODE_ROTATE_MASK) {
116 case DRM_MODE_ROTATE_0:
117 lr_ctrl |= L_ROT(L_ROT_R0);
119 case DRM_MODE_ROTATE_90:
120 lr_ctrl |= L_ROT(L_ROT_R90);
122 case DRM_MODE_ROTATE_180:
123 lr_ctrl |= L_ROT(L_ROT_R180);
125 case DRM_MODE_ROTATE_270:
126 lr_ctrl |= L_ROT(L_ROT_R270);
130 if (rot & DRM_MODE_REFLECT_X)
132 if (rot & DRM_MODE_REFLECT_Y)
138 static u32 to_ad_ctrl(u64 modifier)
140 u32 afbc_ctrl = AD_AEN;
145 if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
146 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
149 if (modifier & AFBC_FORMAT_MOD_YTR)
151 if (modifier & AFBC_FORMAT_MOD_SPLIT)
153 if (modifier & AFBC_FORMAT_MOD_TILED)
159 static inline u32 to_d71_input_id(struct komeda_component_output *output)
161 struct komeda_component *comp = output->component;
163 return comp ? (comp->hw_id + output->output_port) : 0;
166 static void d71_layer_update_fb(struct komeda_component *c,
167 struct komeda_fb *kfb,
170 struct drm_framebuffer *fb = &kfb->base;
171 const struct drm_format_info *info = fb->format;
172 u32 __iomem *reg = c->reg;
175 if (info->num_planes > 2)
176 malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]);
178 if (info->num_planes > 1) {
179 block_h = drm_format_info_block_height(info, 1);
180 malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h);
181 malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]);
184 block_h = drm_format_info_block_height(info, 0);
185 malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h);
186 malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]);
187 malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
190 static void d71_layer_disable(struct komeda_component *c)
192 malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
195 static void d71_layer_update(struct komeda_component *c,
196 struct komeda_component_state *state)
198 struct komeda_layer_state *st = to_layer_st(state);
199 struct drm_plane_state *plane_st = state->plane->state;
200 struct drm_framebuffer *fb = plane_st->fb;
201 struct komeda_fb *kfb = to_kfb(fb);
202 u32 __iomem *reg = c->reg;
203 u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
204 u32 ctrl = L_EN | to_rot_ctrl(st->rot);
206 d71_layer_update_fb(c, kfb, st->addr);
208 malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier));
212 malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l,
214 malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t,
216 /* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */
217 if (fb->modifier & AFBC_FORMAT_MOD_TILED)
218 addr = st->addr[0] + kfb->offset_payload;
220 addr = st->addr[0] + kfb->afbc_size - 1;
222 malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr));
223 malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr));
226 if (fb->format->is_yuv) {
229 switch (kfb->format_caps->fourcc) {
230 case DRM_FORMAT_YUYV:
231 upsampling = fb->modifier ? LR_CHI422_BILINEAR :
232 LR_CHI422_REPLICATION;
234 case DRM_FORMAT_UYVY:
235 upsampling = LR_CHI422_REPLICATION;
237 case DRM_FORMAT_NV12:
238 case DRM_FORMAT_YUV420_8BIT:
239 case DRM_FORMAT_YUV420_10BIT:
240 case DRM_FORMAT_YUV420:
241 case DRM_FORMAT_P010:
242 /* these fmt support MPGE/JPEG both, here perfer JPEG*/
243 upsampling = LR_CHI420_JPEG;
245 case DRM_FORMAT_X0L2:
246 upsampling = LR_CHI420_JPEG;
252 malidp_write32(reg, LAYER_R_CONTROL, upsampling);
253 malidp_write_group(reg, LAYER_YUV_RGB_COEFF0,
254 KOMEDA_N_YUV2RGB_COEFFS,
255 komeda_select_yuv2rgb_coeffs(
256 plane_st->color_encoding,
257 plane_st->color_range));
260 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
264 malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
267 static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
273 get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
282 rgb2rgb = !!(v[14] & L_INFO_CM);
284 dump_block_header(sf, c->reg);
286 seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
288 get_values_from_reg(c->reg, 0xD0, 1, v);
289 seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
291 get_values_from_reg(c->reg, 0xD4, 1, v);
292 seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
294 get_values_from_reg(c->reg, 0xD8, 4, v);
295 seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
296 seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
297 seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
298 seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
300 get_values_from_reg(c->reg, 0x100, 3, v);
301 seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
302 seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
303 seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
305 get_values_from_reg(c->reg, 0x110, 2, v);
306 seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
307 seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
309 get_values_from_reg(c->reg, 0x118, 1, v);
310 seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
312 get_values_from_reg(c->reg, 0x120, 2, v);
313 seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
314 seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
316 get_values_from_reg(c->reg, 0x130, 12, v);
317 for (i = 0; i < 12; i++)
318 seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
322 get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
323 for (i = 0; i < 12; i++)
324 seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
327 get_values_from_reg(c->reg, 0x160, 3, v);
328 seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
329 seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
330 seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
333 static const struct komeda_component_funcs d71_layer_funcs = {
334 .update = d71_layer_update,
335 .disable = d71_layer_disable,
336 .dump_register = d71_layer_dump,
339 static int d71_layer_init(struct d71_dev *d71,
340 struct block_header *blk, u32 __iomem *reg)
342 struct komeda_component *c;
343 struct komeda_layer *layer;
344 u32 pipe_id, layer_id, layer_info;
346 get_resources_id(blk->block_info, &pipe_id, &layer_id);
347 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
349 BLOCK_INFO_INPUT_ID(blk->block_info),
351 get_valid_inputs(blk),
352 1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
354 DRM_ERROR("Failed to add layer component\n");
359 layer_info = malidp_read32(reg, LAYER_INFO);
361 if (layer_info & L_INFO_RF)
362 layer->layer_type = KOMEDA_FMT_RICH_LAYER;
364 layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
366 set_range(&layer->hsize_in, 4, d71->max_line_size);
367 set_range(&layer->vsize_in, 4, d71->max_vsize);
369 malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
371 layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
376 static void d71_wb_layer_update(struct komeda_component *c,
377 struct komeda_component_state *state)
379 struct komeda_layer_state *st = to_layer_st(state);
380 struct drm_connector_state *conn_st = state->wb_conn->state;
381 struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);
382 u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN;
383 u32 __iomem *reg = c->reg;
385 d71_layer_update_fb(c, kfb, st->addr);
390 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
391 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0]));
392 malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
395 static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf)
399 dump_block_header(sf, c->reg);
401 get_values_from_reg(c->reg, 0x80, 1, v);
402 seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]);
404 get_values_from_reg(c->reg, 0xD0, 3, v);
405 seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]);
406 seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]);
407 seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]);
409 get_values_from_reg(c->reg, 0xE0, 1, v);
410 seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]);
412 for (i = 0; i < 2; i++) {
413 get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v);
414 seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]);
415 seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]);
416 seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]);
419 get_values_from_reg(c->reg, 0x130, 12, v);
420 for (i = 0; i < 12; i++)
421 seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
424 static void d71_wb_layer_disable(struct komeda_component *c)
426 malidp_write32(c->reg, BLK_INPUT_ID0, 0);
427 malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
430 static const struct komeda_component_funcs d71_wb_layer_funcs = {
431 .update = d71_wb_layer_update,
432 .disable = d71_wb_layer_disable,
433 .dump_register = d71_wb_layer_dump,
436 static int d71_wb_layer_init(struct d71_dev *d71,
437 struct block_header *blk, u32 __iomem *reg)
439 struct komeda_component *c;
440 struct komeda_layer *wb_layer;
441 u32 pipe_id, layer_id;
443 get_resources_id(blk->block_info, &pipe_id, &layer_id);
445 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer),
446 layer_id, BLOCK_INFO_INPUT_ID(blk->block_info),
448 1, get_valid_inputs(blk), 0, reg,
449 "LPU%d_LAYER_WR", pipe_id);
451 DRM_ERROR("Failed to add wb_layer component\n");
455 wb_layer = to_layer(c);
456 wb_layer->layer_type = KOMEDA_FMT_WB_LAYER;
458 set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size);
459 set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
464 static void d71_component_disable(struct komeda_component *c)
466 u32 __iomem *reg = c->reg;
469 malidp_write32(reg, BLK_CONTROL, 0);
471 for (i = 0; i < c->max_active_inputs; i++) {
472 malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
474 /* Besides clearing the input ID to zero, D71 compiz also has
475 * input enable bit in CU_INPUTx_CONTROL which need to be
478 if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS))
479 malidp_write32(reg, CU_INPUT0_CONTROL +
480 i * CU_PER_INPUT_REGS * 4,
481 CU_INPUT_CTRL_ALPHA(0xFF));
485 static void compiz_enable_input(u32 __iomem *id_reg,
486 u32 __iomem *cfg_reg,
488 struct komeda_compiz_input_cfg *cin)
490 u32 ctrl = CU_INPUT_CTRL_EN;
491 u8 blend = cin->pixel_blend_mode;
493 if (blend == DRM_MODE_BLEND_PIXEL_NONE)
494 ctrl |= CU_INPUT_CTRL_PAD;
495 else if (blend == DRM_MODE_BLEND_PREMULTI)
496 ctrl |= CU_INPUT_CTRL_PMUL;
498 ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
500 malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
502 malidp_write32(cfg_reg, CU_INPUT0_SIZE,
503 HV_SIZE(cin->hsize, cin->vsize));
504 malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
505 HV_OFFSET(cin->hoffset, cin->voffset));
506 malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
509 static void d71_compiz_update(struct komeda_component *c,
510 struct komeda_component_state *state)
512 struct komeda_compiz_state *st = to_compiz_st(state);
513 u32 __iomem *reg = c->reg;
514 u32 __iomem *id_reg, *cfg_reg;
515 u32 index, input_hw_id;
517 for_each_changed_input(state, index) {
518 id_reg = reg + index;
519 cfg_reg = reg + index * CU_PER_INPUT_REGS;
520 input_hw_id = to_d71_input_id(&state->inputs[index]);
521 if (state->active_inputs & BIT(index)) {
522 compiz_enable_input(id_reg, cfg_reg,
523 input_hw_id, &st->cins[index]);
525 malidp_write32(id_reg, BLK_INPUT_ID0, 0);
526 malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
530 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
533 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
537 dump_block_header(sf, c->reg);
539 get_values_from_reg(c->reg, 0x80, 5, v);
540 for (i = 0; i < 5; i++)
541 seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
543 get_values_from_reg(c->reg, 0xA0, 5, v);
544 seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
545 seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
546 seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
547 seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
548 seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
550 get_values_from_reg(c->reg, 0xD0, 2, v);
551 seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
552 seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
554 get_values_from_reg(c->reg, 0xDC, 1, v);
555 seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
557 for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
558 get_values_from_reg(c->reg, v[4], 3, v);
559 seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
560 seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
561 seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
564 get_values_from_reg(c->reg, 0x130, 2, v);
565 seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
566 seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
569 static const struct komeda_component_funcs d71_compiz_funcs = {
570 .update = d71_compiz_update,
571 .disable = d71_component_disable,
572 .dump_register = d71_compiz_dump,
575 static int d71_compiz_init(struct d71_dev *d71,
576 struct block_header *blk, u32 __iomem *reg)
578 struct komeda_component *c;
579 struct komeda_compiz *compiz;
580 u32 pipe_id, comp_id;
582 get_resources_id(blk->block_info, &pipe_id, &comp_id);
584 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
586 BLOCK_INFO_INPUT_ID(blk->block_info),
588 CU_NUM_INPUT_IDS, get_valid_inputs(blk),
589 CU_NUM_OUTPUT_IDS, reg,
594 compiz = to_compiz(c);
596 set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size);
597 set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
602 static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in,
603 u32 vsize_in, u32 hsize_out,
608 if (hsize_in <= hsize_out)
610 else if (hsize_in <= (hsize_out + hsize_out / 2))
612 else if (hsize_in <= hsize_out * 2)
614 else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4)
619 if (vsize_in <= vsize_out)
620 val |= SC_VTSEL(0x6A);
621 else if (vsize_in <= (vsize_out + vsize_out / 2))
622 val |= SC_VTSEL(0x6B);
623 else if (vsize_in <= vsize_out * 2)
624 val |= SC_VTSEL(0x6C);
625 else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4)
626 val |= SC_VTSEL(0x6D);
628 val |= SC_VTSEL(0x6E);
630 malidp_write32(reg, SC_COEFFTAB, val);
633 static void d71_scaler_update(struct komeda_component *c,
634 struct komeda_component_state *state)
636 struct komeda_scaler_state *st = to_scaler_st(state);
637 u32 __iomem *reg = c->reg;
638 u32 init_ph, delta_ph, ctrl;
640 d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in,
641 st->hsize_out, st->vsize_out);
643 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));
644 malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));
645 malidp_write32(reg, SC_H_CROP, HV_CROP(st->left_crop, st->right_crop));
647 /* for right part, HW only sample the valid pixel which means the pixels
648 * in left_crop will be jumpped, and the first sample pixel is:
650 * dst_a = st->total_hsize_out - st->hsize_out + st->left_crop + 0.5;
652 * Then the corresponding texel in src is:
654 * h_delta_phase = st->total_hsize_in / st->total_hsize_out;
655 * src_a = dst_A * h_delta_phase;
657 * and h_init_phase is src_a deduct the real source start src_S;
659 * src_S = st->total_hsize_in - st->hsize_in;
660 * h_init_phase = src_a - src_S;
662 * And HW precision for the initial/delta_phase is 16:16 fixed point,
663 * the following is the simplified formula
665 if (st->right_part) {
666 u32 dst_a = st->total_hsize_out - st->hsize_out + st->left_crop;
668 if (st->en_img_enhancement)
671 init_ph = ((st->total_hsize_in * (2 * dst_a + 1) -
672 2 * st->total_hsize_out * (st->total_hsize_in -
673 st->hsize_in)) << 15) / st->total_hsize_out;
675 init_ph = (st->total_hsize_in << 15) / st->total_hsize_out;
678 malidp_write32(reg, SC_H_INIT_PH, init_ph);
680 delta_ph = (st->total_hsize_in << 16) / st->total_hsize_out;
681 malidp_write32(reg, SC_H_DELTA_PH, delta_ph);
683 init_ph = (st->total_vsize_in << 15) / st->vsize_out;
684 malidp_write32(reg, SC_V_INIT_PH, init_ph);
686 delta_ph = (st->total_vsize_in << 16) / st->vsize_out;
687 malidp_write32(reg, SC_V_DELTA_PH, delta_ph);
690 ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;
691 ctrl |= st->en_alpha ? SC_CTRL_AP : 0;
692 ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0;
693 /* If we use the hardware splitter we shouldn't set SC_CTRL_LS */
695 state->inputs[0].component->id != KOMEDA_COMPONENT_SPLITTER)
698 malidp_write32(reg, BLK_CONTROL, ctrl);
699 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0]));
702 static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)
706 dump_block_header(sf, c->reg);
708 get_values_from_reg(c->reg, 0x80, 1, v);
709 seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]);
711 get_values_from_reg(c->reg, 0xD0, 1, v);
712 seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]);
714 get_values_from_reg(c->reg, 0xDC, 9, v);
715 seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]);
716 seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]);
717 seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]);
718 seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]);
719 seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]);
720 seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]);
721 seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);
722 seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);
723 seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]);
726 static const struct komeda_component_funcs d71_scaler_funcs = {
727 .update = d71_scaler_update,
728 .disable = d71_component_disable,
729 .dump_register = d71_scaler_dump,
732 static int d71_scaler_init(struct d71_dev *d71,
733 struct block_header *blk, u32 __iomem *reg)
735 struct komeda_component *c;
736 struct komeda_scaler *scaler;
737 u32 pipe_id, comp_id;
739 get_resources_id(blk->block_info, &pipe_id, &comp_id);
741 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler),
742 comp_id, BLOCK_INFO_INPUT_ID(blk->block_info),
744 1, get_valid_inputs(blk), 1, reg,
746 pipe_id, BLOCK_INFO_BLK_ID(blk->block_info));
749 DRM_ERROR("Failed to initialize scaler");
753 scaler = to_scaler(c);
754 set_range(&scaler->hsize, 4, 2048);
755 set_range(&scaler->vsize, 4, 4096);
756 scaler->max_downscaling = 6;
757 scaler->max_upscaling = 64;
758 scaler->scaling_split_overlap = 8;
759 scaler->enh_split_overlap = 1;
761 malidp_write32(c->reg, BLK_CONTROL, 0);
766 static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
767 struct drm_display_mode *mode,
768 unsigned long aclk_rate,
769 struct komeda_data_flow_cfg *dflow)
771 u32 h_in = dflow->in_w;
772 u32 v_in = dflow->in_h;
773 u32 v_out = dflow->out_h;
774 u64 fraction, denominator;
776 /* D71 downscaling must satisfy the following equation
779 * ------- >= ---------------------------------------------
780 * PXLCLK (h_total - (1 + 2 * v_in / v_out)) * v_out
782 * In only horizontal downscaling situation, the right side should be
783 * multiplied by (h_total - 3) / (h_active - 3), then equation becomes
786 * ------- >= ----------------
787 * PXLCLK (h_active - 3)
789 * To avoid precision lost the equation 1 will be convert to:
792 * ------- >= -----------------------------------
793 * PXLCLK (h_total -1 ) * v_out - 2 * v_in
797 denominator = mode->hdisplay - 3;
799 fraction = h_in * v_in;
800 denominator = (mode->htotal - 1) * v_out - 2 * v_in;
803 return aclk_rate * denominator >= mode->clock * 1000 * fraction ?
807 static void d71_merger_update(struct komeda_component *c,
808 struct komeda_component_state *state)
810 struct komeda_merger_state *st = to_merger_st(state);
811 u32 __iomem *reg = c->reg;
814 for_each_changed_input(state, index)
815 malidp_write32(reg, MG_INPUT_ID0 + index * 4,
816 to_d71_input_id(&state->inputs[index]));
818 malidp_write32(reg, MG_SIZE, HV_SIZE(st->hsize_merged,
820 malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
823 static void d71_merger_dump(struct komeda_component *c, struct seq_file *sf)
827 dump_block_header(sf, c->reg);
829 get_values_from_reg(c->reg, MG_INPUT_ID0, 1, &v);
830 seq_printf(sf, "MG_INPUT_ID0:\t\t0x%X\n", v);
832 get_values_from_reg(c->reg, MG_INPUT_ID1, 1, &v);
833 seq_printf(sf, "MG_INPUT_ID1:\t\t0x%X\n", v);
835 get_values_from_reg(c->reg, BLK_CONTROL, 1, &v);
836 seq_printf(sf, "MG_CONTROL:\t\t0x%X\n", v);
838 get_values_from_reg(c->reg, MG_SIZE, 1, &v);
839 seq_printf(sf, "MG_SIZE:\t\t0x%X\n", v);
842 static const struct komeda_component_funcs d71_merger_funcs = {
843 .update = d71_merger_update,
844 .disable = d71_component_disable,
845 .dump_register = d71_merger_dump,
848 static int d71_merger_init(struct d71_dev *d71,
849 struct block_header *blk, u32 __iomem *reg)
851 struct komeda_component *c;
852 struct komeda_merger *merger;
853 u32 pipe_id, comp_id;
855 get_resources_id(blk->block_info, &pipe_id, &comp_id);
857 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*merger),
859 BLOCK_INFO_INPUT_ID(blk->block_info),
861 MG_NUM_INPUTS_IDS, get_valid_inputs(blk),
862 MG_NUM_OUTPUTS_IDS, reg,
863 "CU%d_MERGER", pipe_id);
866 DRM_ERROR("Failed to initialize merger.\n");
870 merger = to_merger(c);
872 set_range(&merger->hsize_merged, 4, 4032);
873 set_range(&merger->vsize_merged, 4, 4096);
878 static void d71_improc_update(struct komeda_component *c,
879 struct komeda_component_state *state)
881 struct komeda_improc_state *st = to_improc_st(state);
882 u32 __iomem *reg = c->reg;
883 u32 index, input_hw_id;
885 for_each_changed_input(state, index) {
886 input_hw_id = state->active_inputs & BIT(index) ?
887 to_d71_input_id(&state->inputs[index]) : 0;
888 malidp_write32(reg, BLK_INPUT_ID0 + index * 4, input_hw_id);
891 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
894 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
898 dump_block_header(sf, c->reg);
900 get_values_from_reg(c->reg, 0x80, 2, v);
901 seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
902 seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
904 get_values_from_reg(c->reg, 0xC0, 1, v);
905 seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
907 get_values_from_reg(c->reg, 0xD0, 3, v);
908 seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
909 seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
910 seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
912 get_values_from_reg(c->reg, 0x130, 12, v);
913 for (i = 0; i < 12; i++)
914 seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
916 get_values_from_reg(c->reg, 0x170, 12, v);
917 for (i = 0; i < 12; i++)
918 seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
921 static const struct komeda_component_funcs d71_improc_funcs = {
922 .update = d71_improc_update,
923 .disable = d71_component_disable,
924 .dump_register = d71_improc_dump,
927 static int d71_improc_init(struct d71_dev *d71,
928 struct block_header *blk, u32 __iomem *reg)
930 struct komeda_component *c;
931 struct komeda_improc *improc;
932 u32 pipe_id, comp_id, value;
934 get_resources_id(blk->block_info, &pipe_id, &comp_id);
936 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),
938 BLOCK_INFO_INPUT_ID(blk->block_info),
939 &d71_improc_funcs, IPS_NUM_INPUT_IDS,
940 get_valid_inputs(blk),
941 IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);
943 DRM_ERROR("Failed to add improc component\n");
947 improc = to_improc(c);
948 improc->supported_color_depths = BIT(8) | BIT(10);
949 improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
950 DRM_COLOR_FORMAT_YCRCB444 |
951 DRM_COLOR_FORMAT_YCRCB422;
952 value = malidp_read32(reg, BLK_INFO);
953 if (value & IPS_INFO_CHD420)
954 improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420;
956 improc->supports_csc = true;
957 improc->supports_gamma = true;
962 static void d71_timing_ctrlr_disable(struct komeda_component *c)
964 malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
967 static void d71_timing_ctrlr_update(struct komeda_component *c,
968 struct komeda_component_state *state)
970 struct drm_crtc_state *crtc_st = state->crtc->state;
971 u32 __iomem *reg = c->reg;
975 drm_display_mode_to_videomode(&crtc_st->adjusted_mode, &vm);
977 malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(vm.hactive, vm.vactive));
978 malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(vm.hfront_porch,
980 malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vm.vfront_porch,
983 value = BS_SYNC_VSW(vm.vsync_len) | BS_SYNC_HSW(vm.hsync_len);
984 value |= vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? BS_SYNC_VSP : 0;
985 value |= vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? BS_SYNC_HSP : 0;
986 malidp_write32(reg, BS_SYNC, value);
988 malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
989 malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);
991 /* configure bs control register */
992 value = BS_CTRL_EN | BS_CTRL_VM;
994 malidp_write32(reg, BLK_CONTROL, value);
997 static void d71_timing_ctrlr_dump(struct komeda_component *c,
1002 dump_block_header(sf, c->reg);
1004 get_values_from_reg(c->reg, 0xC0, 1, v);
1005 seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
1007 get_values_from_reg(c->reg, 0xD0, 8, v);
1008 seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
1009 seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
1010 seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
1011 seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
1012 seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
1013 seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
1014 seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
1015 seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
1017 get_values_from_reg(c->reg, 0x100, 3, v);
1018 seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
1019 seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
1020 seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
1022 get_values_from_reg(c->reg, 0x110, 3, v);
1023 for (i = 0; i < 3; i++)
1024 seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
1026 get_values_from_reg(c->reg, 0x120, 5, v);
1027 for (i = 0; i < 2; i++) {
1028 seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
1029 seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
1031 seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
1034 static const struct komeda_component_funcs d71_timing_ctrlr_funcs = {
1035 .update = d71_timing_ctrlr_update,
1036 .disable = d71_timing_ctrlr_disable,
1037 .dump_register = d71_timing_ctrlr_dump,
1040 static int d71_timing_ctrlr_init(struct d71_dev *d71,
1041 struct block_header *blk, u32 __iomem *reg)
1043 struct komeda_component *c;
1044 struct komeda_timing_ctrlr *ctrlr;
1045 u32 pipe_id, comp_id;
1047 get_resources_id(blk->block_info, &pipe_id, &comp_id);
1049 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),
1050 KOMEDA_COMPONENT_TIMING_CTRLR,
1051 BLOCK_INFO_INPUT_ID(blk->block_info),
1052 &d71_timing_ctrlr_funcs,
1053 1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),
1054 BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);
1056 DRM_ERROR("Failed to add display_ctrl component\n");
1060 ctrlr = to_ctrlr(c);
1062 ctrlr->supports_dual_link = true;
1067 int d71_probe_block(struct d71_dev *d71,
1068 struct block_header *blk, u32 __iomem *reg)
1070 struct d71_pipeline *pipe;
1071 int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
1075 switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
1076 case D71_BLK_TYPE_GCU:
1079 case D71_BLK_TYPE_LPU:
1080 pipe = d71->pipes[blk_id];
1081 pipe->lpu_addr = reg;
1084 case D71_BLK_TYPE_LPU_LAYER:
1085 err = d71_layer_init(d71, blk, reg);
1088 case D71_BLK_TYPE_LPU_WB_LAYER:
1089 err = d71_wb_layer_init(d71, blk, reg);
1092 case D71_BLK_TYPE_CU:
1093 pipe = d71->pipes[blk_id];
1094 pipe->cu_addr = reg;
1095 err = d71_compiz_init(d71, blk, reg);
1098 case D71_BLK_TYPE_CU_SCALER:
1099 err = d71_scaler_init(d71, blk, reg);
1102 case D71_BLK_TYPE_CU_SPLITTER:
1105 case D71_BLK_TYPE_CU_MERGER:
1106 err = d71_merger_init(d71, blk, reg);
1109 case D71_BLK_TYPE_DOU:
1110 pipe = d71->pipes[blk_id];
1111 pipe->dou_addr = reg;
1114 case D71_BLK_TYPE_DOU_IPS:
1115 err = d71_improc_init(d71, blk, reg);
1118 case D71_BLK_TYPE_DOU_FT_COEFF:
1119 pipe = d71->pipes[blk_id];
1120 pipe->dou_ft_coeff_addr = reg;
1123 case D71_BLK_TYPE_DOU_BS:
1124 err = d71_timing_ctrlr_init(d71, blk, reg);
1127 case D71_BLK_TYPE_GLB_LT_COEFF:
1130 case D71_BLK_TYPE_GLB_SCL_COEFF:
1131 d71->glb_scl_coeff_addr[blk_id] = reg;
1135 DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
1144 const struct komeda_pipeline_funcs d71_pipeline_funcs = {
1145 .downscaling_clk_check = d71_downscaling_clk_check,