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