1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7
8 #include <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
get_resources_id(u32 hw_id,u32 * pipe_id,u32 * comp_id)15 static 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
get_valid_inputs(struct block_header * blk)60 static 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
get_values_from_reg(void __iomem * reg,u32 offset,u32 count,u32 * val)75 static void get_values_from_reg(void __iomem *reg, u32 offset,
76 u32 count, u32 *val)
77 {
78 u32 i, addr;
79
80 for (i = 0; i < count; i++) {
81 addr = offset + (i << 2);
82 /* 0xA4 is WO register */
83 if (addr != 0xA4)
84 val[i] = malidp_read32(reg, addr);
85 else
86 val[i] = 0xDEADDEAD;
87 }
88 }
89
dump_block_header(struct seq_file * sf,void __iomem * reg)90 static 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 have
112 * a line size register to indicate the fifo size.
113 */
__get_blk_line_size(struct d71_dev * d71,u32 __iomem * reg,u32 max_default)114 static 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
get_blk_line_size(struct d71_dev * d71,u32 __iomem * reg)123 static 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
to_rot_ctrl(u32 rot)128 static 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
to_ad_ctrl(u64 modifier)155 static 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
to_d71_input_id(struct komeda_component_state * st,int idx)176 static 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 else
184 return 0;
185 }
186
d71_layer_update_fb(struct komeda_component * c,struct komeda_fb * kfb,dma_addr_t * addr)187 static 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
d71_layer_disable(struct komeda_component * c)211 static void d71_layer_disable(struct komeda_component *c)
212 {
213 malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
214 }
215
d71_layer_update(struct komeda_component * c,struct komeda_component_state * state)216 static 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 else
241 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
d71_layer_dump(struct komeda_component * c,struct seq_file * sf)288 static 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
d71_layer_validate(struct komeda_component * c,struct komeda_component_state * state)354 static 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 else
371 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 else
378 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
402 static 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
d71_layer_init(struct d71_dev * d71,struct block_header * blk,u32 __iomem * reg)409 static 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 else
434 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
d71_wb_layer_update(struct komeda_component * c,struct komeda_component_state * state)467 static 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
d71_wb_layer_dump(struct komeda_component * c,struct seq_file * sf)486 static 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
d71_wb_layer_disable(struct komeda_component * c)515 static 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
521 static 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
d71_wb_layer_init(struct d71_dev * d71,struct block_header * blk,u32 __iomem * reg)527 static 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
d71_component_disable(struct komeda_component * c)557 static 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 has
568 * input enable bit in CU_INPUTx_CONTROL which need to be
569 * 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
compiz_enable_input(u32 __iomem * id_reg,u32 __iomem * cfg_reg,u32 input_hw_id,struct komeda_compiz_input_cfg * cin)578 static 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
d71_compiz_update(struct komeda_component * c,struct komeda_component_state * state)602 static 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
d71_compiz_dump(struct komeda_component * c,struct seq_file * sf)626 static 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
662 static 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
d71_compiz_init(struct d71_dev * d71,struct block_header * blk,u32 __iomem * reg)668 static 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
d71_scaler_update_filter_lut(u32 __iomem * reg,u32 hsize_in,u32 vsize_in,u32 hsize_out,u32 vsize_out)695 static 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 else
710 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 else
721 val |= SC_VTSEL(0x6E);
722
723 malidp_write32(reg, SC_COEFFTAB, val);
724 }
725
d71_scaler_update(struct komeda_component * c,struct komeda_component_state * state)726 static 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 pixels
741 * 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 formula
757 */
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
d71_scaler_dump(struct komeda_component * c,struct seq_file * sf)795 static 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
831 static 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
d71_scaler_init(struct d71_dev * d71,struct block_header * blk,u32 __iomem * reg)837 static 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
d71_downscaling_clk_check(struct komeda_pipeline * pipe,struct drm_display_mode * mode,unsigned long aclk_rate,struct komeda_data_flow_cfg * dflow)871 static 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 equation
882 *
883 * ACLK h_in * v_in
884 * ------- >= ---------------------------------------------
885 * PXLCLK (h_total - (1 + 2 * v_in / v_out)) * v_out
886 *
887 * In only horizontal downscaling situation, the right side should be
888 * multiplied by (h_total - 3) / (h_active - 3), then equation becomes
889 *
890 * ACLK h_in
891 * ------- >= ----------------
892 * PXLCLK (h_active - 3)
893 *
894 * To avoid precision lost the equation 1 will be convert to:
895 *
896 * ACLK h_in * v_in
897 * ------- >= -----------------------------------
898 * PXLCLK (h_total -1 ) * v_out - 2 * v_in
899 */
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
d71_splitter_update(struct komeda_component * c,struct komeda_component_state * state)912 static 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
d71_splitter_dump(struct komeda_component * c,struct seq_file * sf)924 static 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
939 static 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
d71_splitter_init(struct d71_dev * d71,struct block_header * blk,u32 __iomem * reg)945 static 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
d71_merger_update(struct komeda_component * c,struct komeda_component_state * state)974 static 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
d71_merger_dump(struct komeda_component * c,struct seq_file * sf)990 static 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
1009 static 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
d71_merger_init(struct d71_dev * d71,struct block_header * blk,u32 __iomem * reg)1015 static 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
d71_improc_update(struct komeda_component * c,struct komeda_component_state * state)1046 static 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
d71_improc_dump(struct komeda_component * c,struct seq_file * sf)1093 static 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
1120 static 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
d71_improc_init(struct d71_dev * d71,struct block_header * blk,u32 __iomem * reg)1126 static 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
d71_timing_ctrlr_disable(struct komeda_component * c)1161 static void d71_timing_ctrlr_disable(struct komeda_component *c)
1162 {
1163 malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
1164 }
1165
d71_timing_ctrlr_update(struct komeda_component * c,struct komeda_component_state * state)1166 static 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
d71_timing_ctrlr_dump(struct komeda_component * c,struct seq_file * sf)1210 static 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
1247 static 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
d71_timing_ctrlr_init(struct d71_dev * d71,struct block_header * blk,u32 __iomem * reg)1253 static 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
d71_probe_block(struct d71_dev * d71,struct block_header * blk,u32 __iomem * reg)1280 int 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
d71_gcu_dump(struct d71_dev * d71,struct seq_file * sf)1358 static 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
d71_lpu_dump(struct d71_pipeline * pipe,struct seq_file * sf)1385 static 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
d71_dou_dump(struct d71_pipeline * pipe,struct seq_file * sf)1410 static 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
d71_pipeline_dump(struct komeda_pipeline * pipe,struct seq_file * sf)1426 static 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
1434 const struct komeda_pipeline_funcs d71_pipeline_funcs = {
1435 .downscaling_clk_check = d71_downscaling_clk_check,
1436 .dump_register = d71_pipeline_dump,
1437 };
1438
d71_dump(struct komeda_dev * mdev,struct seq_file * sf)1439 void 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