]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
drm/komeda: Added AFBC support for komeda driver
[linux.git] / drivers / gpu / drm / arm / display / komeda / d71 / d71_component.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4  * Author: James.Qian.Wang <james.qian.wang@arm.com>
5  *
6  */
7
8 #include <drm/drm_print.h>
9 #include "d71_dev.h"
10 #include "komeda_kms.h"
11 #include "malidp_io.h"
12 #include "komeda_framebuffer.h"
13
14 static void get_resources_id(u32 hw_id, u32 *pipe_id, u32 *comp_id)
15 {
16         u32 id = BLOCK_INFO_BLK_ID(hw_id);
17         u32 pipe = id;
18
19         switch (BLOCK_INFO_BLK_TYPE(hw_id)) {
20         case D71_BLK_TYPE_LPU_WB_LAYER:
21                 id = KOMEDA_COMPONENT_WB_LAYER;
22                 break;
23         case D71_BLK_TYPE_CU_SPLITTER:
24                 id = KOMEDA_COMPONENT_SPLITTER;
25                 break;
26         case D71_BLK_TYPE_CU_SCALER:
27                 pipe = id / D71_PIPELINE_MAX_SCALERS;
28                 id %= D71_PIPELINE_MAX_SCALERS;
29                 id += KOMEDA_COMPONENT_SCALER0;
30                 break;
31         case D71_BLK_TYPE_CU:
32                 id += KOMEDA_COMPONENT_COMPIZ0;
33                 break;
34         case D71_BLK_TYPE_LPU_LAYER:
35                 pipe = id / D71_PIPELINE_MAX_LAYERS;
36                 id %= D71_PIPELINE_MAX_LAYERS;
37                 id += KOMEDA_COMPONENT_LAYER0;
38                 break;
39         case D71_BLK_TYPE_DOU_IPS:
40                 id += KOMEDA_COMPONENT_IPS0;
41                 break;
42         case D71_BLK_TYPE_CU_MERGER:
43                 id = KOMEDA_COMPONENT_MERGER;
44                 break;
45         case D71_BLK_TYPE_DOU:
46                 id = KOMEDA_COMPONENT_TIMING_CTRLR;
47                 break;
48         default:
49                 id = 0xFFFFFFFF;
50         }
51
52         if (comp_id)
53                 *comp_id = id;
54
55         if (pipe_id)
56                 *pipe_id = pipe;
57 }
58
59 static u32 get_valid_inputs(struct block_header *blk)
60 {
61         u32 valid_inputs = 0, comp_id;
62         int i;
63
64         for (i = 0; i < PIPELINE_INFO_N_VALID_INPUTS(blk->pipeline_info); i++) {
65                 get_resources_id(blk->input_ids[i], NULL, &comp_id);
66                 if (comp_id == 0xFFFFFFFF)
67                         continue;
68                 valid_inputs |= BIT(comp_id);
69         }
70
71         return valid_inputs;
72 }
73
74 static void get_values_from_reg(void __iomem *reg, u32 offset,
75                                 u32 count, u32 *val)
76 {
77         u32 i, addr;
78
79         for (i = 0; i < count; i++) {
80                 addr = offset + (i << 2);
81                 /* 0xA4 is WO register */
82                 if (addr != 0xA4)
83                         val[i] = malidp_read32(reg, addr);
84                 else
85                         val[i] = 0xDEADDEAD;
86         }
87 }
88
89 static void dump_block_header(struct seq_file *sf, void __iomem *reg)
90 {
91         struct block_header hdr;
92         u32 i, n_input, n_output;
93
94         d71_read_block_header(reg, &hdr);
95         seq_printf(sf, "BLOCK_INFO:\t\t0x%X\n", hdr.block_info);
96         seq_printf(sf, "PIPELINE_INFO:\t\t0x%X\n", hdr.pipeline_info);
97
98         n_output = PIPELINE_INFO_N_OUTPUTS(hdr.pipeline_info);
99         n_input  = PIPELINE_INFO_N_VALID_INPUTS(hdr.pipeline_info);
100
101         for (i = 0; i < n_input; i++)
102                 seq_printf(sf, "VALID_INPUT_ID%u:\t0x%X\n",
103                            i, hdr.input_ids[i]);
104
105         for (i = 0; i < n_output; i++)
106                 seq_printf(sf, "OUTPUT_ID%u:\t\t0x%X\n",
107                            i, hdr.output_ids[i]);
108 }
109
110 static u32 to_rot_ctrl(u32 rot)
111 {
112         u32 lr_ctrl = 0;
113
114         switch (rot & DRM_MODE_ROTATE_MASK) {
115         case DRM_MODE_ROTATE_0:
116                 lr_ctrl |= L_ROT(L_ROT_R0);
117                 break;
118         case DRM_MODE_ROTATE_90:
119                 lr_ctrl |= L_ROT(L_ROT_R90);
120                 break;
121         case DRM_MODE_ROTATE_180:
122                 lr_ctrl |= L_ROT(L_ROT_R180);
123                 break;
124         case DRM_MODE_ROTATE_270:
125                 lr_ctrl |= L_ROT(L_ROT_R270);
126                 break;
127         }
128
129         if (rot & DRM_MODE_REFLECT_X)
130                 lr_ctrl |= L_HFLIP;
131         if (rot & DRM_MODE_REFLECT_Y)
132                 lr_ctrl |= L_VFLIP;
133
134         return lr_ctrl;
135 }
136
137 static u32 to_ad_ctrl(u64 modifier)
138 {
139         u32 afbc_ctrl = AD_AEN;
140
141         if (!modifier)
142                 return 0;
143
144         if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
145             AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
146                 afbc_ctrl |= AD_WB;
147
148         if (modifier & AFBC_FORMAT_MOD_YTR)
149                 afbc_ctrl |= AD_YT;
150         if (modifier & AFBC_FORMAT_MOD_SPLIT)
151                 afbc_ctrl |= AD_BS;
152         if (modifier & AFBC_FORMAT_MOD_TILED)
153                 afbc_ctrl |= AD_TH;
154
155         return afbc_ctrl;
156 }
157
158 static inline u32 to_d71_input_id(struct komeda_component_output *output)
159 {
160         struct komeda_component *comp = output->component;
161
162         return comp ? (comp->hw_id + output->output_port) : 0;
163 }
164
165 static void d71_layer_disable(struct komeda_component *c)
166 {
167         malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
168 }
169
170 static void d71_layer_update(struct komeda_component *c,
171                              struct komeda_component_state *state)
172 {
173         struct komeda_layer_state *st = to_layer_st(state);
174         struct drm_plane_state *plane_st = state->plane->state;
175         struct drm_framebuffer *fb = plane_st->fb;
176         struct komeda_fb *kfb = to_kfb(fb);
177         u32 __iomem *reg = c->reg;
178         u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
179         u32 ctrl = L_EN | to_rot_ctrl(st->rot);
180         int i;
181
182         for (i = 0; i < fb->format->num_planes; i++) {
183                 malidp_write32(reg,
184                                BLK_P0_PTR_LOW + i * LAYER_PER_PLANE_REGS * 4,
185                                lower_32_bits(st->addr[i]));
186                 malidp_write32(reg,
187                                BLK_P0_PTR_HIGH + i * LAYER_PER_PLANE_REGS * 4,
188                                upper_32_bits(st->addr[i]));
189                 if (i >= 2)
190                         break;
191
192                 malidp_write32(reg,
193                                BLK_P0_STRIDE + i * LAYER_PER_PLANE_REGS * 4,
194                                fb->pitches[i] & 0xFFFF);
195         }
196
197         malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier));
198         if (fb->modifier) {
199                 u64 addr;
200
201                 malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l,
202                                                              st->afbc_crop_r));
203                 malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t,
204                                                              st->afbc_crop_b));
205                 /* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */
206                 if (fb->modifier & AFBC_FORMAT_MOD_TILED)
207                         addr = st->addr[0] + kfb->offset_payload;
208                 else
209                         addr = st->addr[0] + kfb->afbc_size - 1;
210
211                 malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr));
212                 malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr));
213         }
214
215         malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
216         malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
217
218         malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
219 }
220
221 static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
222 {
223         u32 v[15], i;
224         bool rich, rgb2rgb;
225         char *prefix;
226
227         get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
228         if (v[14] & 0x1) {
229                 rich = true;
230                 prefix = "LR_";
231         } else {
232                 rich = false;
233                 prefix = "LS_";
234         }
235
236         rgb2rgb = !!(v[14] & L_INFO_CM);
237
238         dump_block_header(sf, c->reg);
239
240         seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
241
242         get_values_from_reg(c->reg, 0xD0, 1, v);
243         seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
244         if (rich) {
245                 get_values_from_reg(c->reg, 0xD4, 1, v);
246                 seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
247         }
248         get_values_from_reg(c->reg, 0xD8, 4, v);
249         seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
250         seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
251         seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
252         seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
253
254         get_values_from_reg(c->reg, 0x100, 3, v);
255         seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
256         seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
257         seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
258
259         get_values_from_reg(c->reg, 0x110, 2, v);
260         seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
261         seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
262         if (rich) {
263                 get_values_from_reg(c->reg, 0x118, 1, v);
264                 seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
265
266                 get_values_from_reg(c->reg, 0x120, 2, v);
267                 seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
268                 seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
269
270                 get_values_from_reg(c->reg, 0x130, 12, v);
271                 for (i = 0; i < 12; i++)
272                         seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
273         }
274
275         if (rgb2rgb) {
276                 get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
277                 for (i = 0; i < 12; i++)
278                         seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
279         }
280
281         get_values_from_reg(c->reg, 0x160, 3, v);
282         seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
283         seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
284         seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
285 }
286
287 static const struct komeda_component_funcs d71_layer_funcs = {
288         .update         = d71_layer_update,
289         .disable        = d71_layer_disable,
290         .dump_register  = d71_layer_dump,
291 };
292
293 static int d71_layer_init(struct d71_dev *d71,
294                           struct block_header *blk, u32 __iomem *reg)
295 {
296         struct komeda_component *c;
297         struct komeda_layer *layer;
298         u32 pipe_id, layer_id, layer_info;
299
300         get_resources_id(blk->block_info, &pipe_id, &layer_id);
301         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
302                                  layer_id,
303                                  BLOCK_INFO_INPUT_ID(blk->block_info),
304                                  &d71_layer_funcs, 0,
305                                  get_valid_inputs(blk),
306                                  1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
307         if (IS_ERR(c)) {
308                 DRM_ERROR("Failed to add layer component\n");
309                 return PTR_ERR(c);
310         }
311
312         layer = to_layer(c);
313         layer_info = malidp_read32(reg, LAYER_INFO);
314
315         if (layer_info & L_INFO_RF)
316                 layer->layer_type = KOMEDA_FMT_RICH_LAYER;
317         else
318                 layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
319
320         set_range(&layer->hsize_in, 4, d71->max_line_size);
321         set_range(&layer->vsize_in, 4, d71->max_vsize);
322
323         malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
324
325         layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
326
327         return 0;
328 }
329
330 static void d71_wb_layer_update(struct komeda_component *c,
331                                 struct komeda_component_state *state)
332 {
333         struct komeda_layer_state *st = to_layer_st(state);
334         struct drm_connector_state *conn_st = state->wb_conn->state;
335         struct drm_framebuffer *fb = conn_st->writeback_job->fb;
336         struct komeda_fb *kfb = to_kfb(fb);
337         u32 __iomem *reg = c->reg;
338         u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN;
339         int i;
340
341         for (i = 0; i < fb->format->num_planes; i++) {
342                 malidp_write32(reg + i * LAYER_PER_PLANE_REGS, BLK_P0_PTR_LOW,
343                                lower_32_bits(st->addr[i]));
344                 malidp_write32(reg + i * LAYER_PER_PLANE_REGS, BLK_P0_PTR_HIGH,
345                                upper_32_bits(st->addr[i]));
346
347                 malidp_write32(reg + i * LAYER_PER_PLANE_REGS, BLK_P0_STRIDE,
348                                fb->pitches[i] & 0xFFFF);
349         }
350
351         malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
352         malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
353         malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0]));
354         malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
355 }
356
357 static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf)
358 {
359         u32 v[12], i;
360
361         dump_block_header(sf, c->reg);
362
363         get_values_from_reg(c->reg, 0x80, 1, v);
364         seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]);
365
366         get_values_from_reg(c->reg, 0xD0, 3, v);
367         seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]);
368         seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]);
369         seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]);
370
371         get_values_from_reg(c->reg, 0xE0, 1, v);
372         seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]);
373
374         for (i = 0; i < 2; i++) {
375                 get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v);
376                 seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]);
377                 seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]);
378                 seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]);
379         }
380
381         get_values_from_reg(c->reg, 0x130, 12, v);
382         for (i = 0; i < 12; i++)
383                 seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
384 }
385
386 static void d71_wb_layer_disable(struct komeda_component *c)
387 {
388         malidp_write32(c->reg, BLK_INPUT_ID0, 0);
389         malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
390 }
391
392 static const struct komeda_component_funcs d71_wb_layer_funcs = {
393         .update         = d71_wb_layer_update,
394         .disable        = d71_wb_layer_disable,
395         .dump_register  = d71_wb_layer_dump,
396 };
397
398 static int d71_wb_layer_init(struct d71_dev *d71,
399                              struct block_header *blk, u32 __iomem *reg)
400 {
401         struct komeda_component *c;
402         struct komeda_layer *wb_layer;
403         u32 pipe_id, layer_id;
404
405         get_resources_id(blk->block_info, &pipe_id, &layer_id);
406
407         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer),
408                                  layer_id, BLOCK_INFO_INPUT_ID(blk->block_info),
409                                  &d71_wb_layer_funcs,
410                                  1, get_valid_inputs(blk), 0, reg,
411                                  "LPU%d_LAYER_WR", pipe_id);
412         if (IS_ERR(c)) {
413                 DRM_ERROR("Failed to add wb_layer component\n");
414                 return PTR_ERR(c);
415         }
416
417         wb_layer = to_layer(c);
418         wb_layer->layer_type = KOMEDA_FMT_WB_LAYER;
419
420         set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size);
421         set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
422
423         return 0;
424 }
425
426 static void d71_component_disable(struct komeda_component *c)
427 {
428         u32 __iomem *reg = c->reg;
429         u32 i;
430
431         malidp_write32(reg, BLK_CONTROL, 0);
432
433         for (i = 0; i < c->max_active_inputs; i++)
434                 malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
435 }
436
437 static void compiz_enable_input(u32 __iomem *id_reg,
438                                 u32 __iomem *cfg_reg,
439                                 u32 input_hw_id,
440                                 struct komeda_compiz_input_cfg *cin)
441 {
442         u32 ctrl = CU_INPUT_CTRL_EN;
443         u8 blend = cin->pixel_blend_mode;
444
445         if (blend == DRM_MODE_BLEND_PIXEL_NONE)
446                 ctrl |= CU_INPUT_CTRL_PAD;
447         else if (blend == DRM_MODE_BLEND_PREMULTI)
448                 ctrl |= CU_INPUT_CTRL_PMUL;
449
450         ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
451
452         malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
453
454         malidp_write32(cfg_reg, CU_INPUT0_SIZE,
455                        HV_SIZE(cin->hsize, cin->vsize));
456         malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
457                        HV_OFFSET(cin->hoffset, cin->voffset));
458         malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
459 }
460
461 static void d71_compiz_update(struct komeda_component *c,
462                               struct komeda_component_state *state)
463 {
464         struct komeda_compiz_state *st = to_compiz_st(state);
465         u32 __iomem *reg = c->reg;
466         u32 __iomem *id_reg, *cfg_reg;
467         u32 index, input_hw_id;
468
469         for_each_changed_input(state, index) {
470                 id_reg = reg + index;
471                 cfg_reg = reg + index * CU_PER_INPUT_REGS;
472                 input_hw_id = to_d71_input_id(&state->inputs[index]);
473                 if (state->active_inputs & BIT(index)) {
474                         compiz_enable_input(id_reg, cfg_reg,
475                                             input_hw_id, &st->cins[index]);
476                 } else {
477                         malidp_write32(id_reg, BLK_INPUT_ID0, 0);
478                         malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
479                 }
480         }
481
482         malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
483 }
484
485 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
486 {
487         u32 v[8], i;
488
489         dump_block_header(sf, c->reg);
490
491         get_values_from_reg(c->reg, 0x80, 5, v);
492         for (i = 0; i < 5; i++)
493                 seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
494
495         get_values_from_reg(c->reg, 0xA0, 5, v);
496         seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
497         seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
498         seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
499         seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
500         seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
501
502         get_values_from_reg(c->reg, 0xD0, 2, v);
503         seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
504         seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
505
506         get_values_from_reg(c->reg, 0xDC, 1, v);
507         seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
508
509         for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
510                 get_values_from_reg(c->reg, v[4], 3, v);
511                 seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
512                 seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
513                 seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
514         }
515
516         get_values_from_reg(c->reg, 0x130, 2, v);
517         seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
518         seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
519 }
520
521 static const struct komeda_component_funcs d71_compiz_funcs = {
522         .update         = d71_compiz_update,
523         .disable        = d71_component_disable,
524         .dump_register  = d71_compiz_dump,
525 };
526
527 static int d71_compiz_init(struct d71_dev *d71,
528                            struct block_header *blk, u32 __iomem *reg)
529 {
530         struct komeda_component *c;
531         struct komeda_compiz *compiz;
532         u32 pipe_id, comp_id;
533
534         get_resources_id(blk->block_info, &pipe_id, &comp_id);
535
536         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
537                                  comp_id,
538                                  BLOCK_INFO_INPUT_ID(blk->block_info),
539                                  &d71_compiz_funcs,
540                                  CU_NUM_INPUT_IDS, get_valid_inputs(blk),
541                                  CU_NUM_OUTPUT_IDS, reg,
542                                  "CU%d", pipe_id);
543         if (IS_ERR(c))
544                 return PTR_ERR(c);
545
546         compiz = to_compiz(c);
547
548         set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size);
549         set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
550
551         return 0;
552 }
553
554 static void d71_improc_update(struct komeda_component *c,
555                               struct komeda_component_state *state)
556 {
557         struct komeda_improc_state *st = to_improc_st(state);
558         u32 __iomem *reg = c->reg;
559         u32 index, input_hw_id;
560
561         for_each_changed_input(state, index) {
562                 input_hw_id = state->active_inputs & BIT(index) ?
563                               to_d71_input_id(&state->inputs[index]) : 0;
564                 malidp_write32(reg, BLK_INPUT_ID0 + index * 4, input_hw_id);
565         }
566
567         malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
568 }
569
570 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
571 {
572         u32 v[12], i;
573
574         dump_block_header(sf, c->reg);
575
576         get_values_from_reg(c->reg, 0x80, 2, v);
577         seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
578         seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
579
580         get_values_from_reg(c->reg, 0xC0, 1, v);
581         seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
582
583         get_values_from_reg(c->reg, 0xD0, 3, v);
584         seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
585         seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
586         seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
587
588         get_values_from_reg(c->reg, 0x130, 12, v);
589         for (i = 0; i < 12; i++)
590                 seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
591
592         get_values_from_reg(c->reg, 0x170, 12, v);
593         for (i = 0; i < 12; i++)
594                 seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
595 }
596
597 static const struct komeda_component_funcs d71_improc_funcs = {
598         .update         = d71_improc_update,
599         .disable        = d71_component_disable,
600         .dump_register  = d71_improc_dump,
601 };
602
603 static int d71_improc_init(struct d71_dev *d71,
604                            struct block_header *blk, u32 __iomem *reg)
605 {
606         struct komeda_component *c;
607         struct komeda_improc *improc;
608         u32 pipe_id, comp_id, value;
609
610         get_resources_id(blk->block_info, &pipe_id, &comp_id);
611
612         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),
613                                  comp_id,
614                                  BLOCK_INFO_INPUT_ID(blk->block_info),
615                                  &d71_improc_funcs, IPS_NUM_INPUT_IDS,
616                                  get_valid_inputs(blk),
617                                  IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);
618         if (IS_ERR(c)) {
619                 DRM_ERROR("Failed to add improc component\n");
620                 return PTR_ERR(c);
621         }
622
623         improc = to_improc(c);
624         improc->supported_color_depths = BIT(8) | BIT(10);
625         improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
626                                           DRM_COLOR_FORMAT_YCRCB444 |
627                                           DRM_COLOR_FORMAT_YCRCB422;
628         value = malidp_read32(reg, BLK_INFO);
629         if (value & IPS_INFO_CHD420)
630                 improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420;
631
632         improc->supports_csc = true;
633         improc->supports_gamma = true;
634
635         return 0;
636 }
637
638 static void d71_timing_ctrlr_disable(struct komeda_component *c)
639 {
640         malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
641 }
642
643 static void d71_timing_ctrlr_update(struct komeda_component *c,
644                                     struct komeda_component_state *state)
645 {
646         struct drm_crtc_state *crtc_st = state->crtc->state;
647         u32 __iomem *reg = c->reg;
648         struct videomode vm;
649         u32 value;
650
651         drm_display_mode_to_videomode(&crtc_st->adjusted_mode, &vm);
652
653         malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(vm.hactive, vm.vactive));
654         malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(vm.hfront_porch,
655                                                         vm.hback_porch));
656         malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vm.vfront_porch,
657                                                         vm.vback_porch));
658
659         value = BS_SYNC_VSW(vm.vsync_len) | BS_SYNC_HSW(vm.hsync_len);
660         value |= vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? BS_SYNC_VSP : 0;
661         value |= vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? BS_SYNC_HSP : 0;
662         malidp_write32(reg, BS_SYNC, value);
663
664         malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
665         malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);
666
667         /* configure bs control register */
668         value = BS_CTRL_EN | BS_CTRL_VM;
669
670         malidp_write32(reg, BLK_CONTROL, value);
671 }
672
673 static void d71_timing_ctrlr_dump(struct komeda_component *c,
674                                   struct seq_file *sf)
675 {
676         u32 v[8], i;
677
678         dump_block_header(sf, c->reg);
679
680         get_values_from_reg(c->reg, 0xC0, 1, v);
681         seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
682
683         get_values_from_reg(c->reg, 0xD0, 8, v);
684         seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
685         seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
686         seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
687         seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
688         seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
689         seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
690         seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
691         seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
692
693         get_values_from_reg(c->reg, 0x100, 3, v);
694         seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
695         seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
696         seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
697
698         get_values_from_reg(c->reg, 0x110, 3, v);
699         for (i = 0; i < 3; i++)
700                 seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
701
702         get_values_from_reg(c->reg, 0x120, 5, v);
703         for (i = 0; i < 2; i++) {
704                 seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
705                 seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
706         }
707         seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
708 }
709
710 static const struct komeda_component_funcs d71_timing_ctrlr_funcs = {
711         .update         = d71_timing_ctrlr_update,
712         .disable        = d71_timing_ctrlr_disable,
713         .dump_register  = d71_timing_ctrlr_dump,
714 };
715
716 static int d71_timing_ctrlr_init(struct d71_dev *d71,
717                                  struct block_header *blk, u32 __iomem *reg)
718 {
719         struct komeda_component *c;
720         struct komeda_timing_ctrlr *ctrlr;
721         u32 pipe_id, comp_id;
722
723         get_resources_id(blk->block_info, &pipe_id, &comp_id);
724
725         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),
726                                  KOMEDA_COMPONENT_TIMING_CTRLR,
727                                  BLOCK_INFO_INPUT_ID(blk->block_info),
728                                  &d71_timing_ctrlr_funcs,
729                                  1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),
730                                  BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);
731         if (IS_ERR(c)) {
732                 DRM_ERROR("Failed to add display_ctrl component\n");
733                 return PTR_ERR(c);
734         }
735
736         ctrlr = to_ctrlr(c);
737
738         ctrlr->supports_dual_link = true;
739
740         return 0;
741 }
742
743 int d71_probe_block(struct d71_dev *d71,
744                     struct block_header *blk, u32 __iomem *reg)
745 {
746         struct d71_pipeline *pipe;
747         int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
748
749         int err = 0;
750
751         switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
752         case D71_BLK_TYPE_GCU:
753                 break;
754
755         case D71_BLK_TYPE_LPU:
756                 pipe = d71->pipes[blk_id];
757                 pipe->lpu_addr = reg;
758                 break;
759
760         case D71_BLK_TYPE_LPU_LAYER:
761                 err = d71_layer_init(d71, blk, reg);
762                 break;
763
764         case D71_BLK_TYPE_LPU_WB_LAYER:
765                 err = d71_wb_layer_init(d71, blk, reg);
766                 break;
767
768         case D71_BLK_TYPE_CU:
769                 pipe = d71->pipes[blk_id];
770                 pipe->cu_addr = reg;
771                 err = d71_compiz_init(d71, blk, reg);
772                 break;
773
774         case D71_BLK_TYPE_CU_SPLITTER:
775         case D71_BLK_TYPE_CU_SCALER:
776         case D71_BLK_TYPE_CU_MERGER:
777                 break;
778
779         case D71_BLK_TYPE_DOU:
780                 pipe = d71->pipes[blk_id];
781                 pipe->dou_addr = reg;
782                 break;
783
784         case D71_BLK_TYPE_DOU_IPS:
785                 err = d71_improc_init(d71, blk, reg);
786                 break;
787
788         case D71_BLK_TYPE_DOU_FT_COEFF:
789                 pipe = d71->pipes[blk_id];
790                 pipe->dou_ft_coeff_addr = reg;
791                 break;
792
793         case D71_BLK_TYPE_DOU_BS:
794                 err = d71_timing_ctrlr_init(d71, blk, reg);
795                 break;
796
797         case D71_BLK_TYPE_GLB_LT_COEFF:
798                 break;
799
800         case D71_BLK_TYPE_GLB_SCL_COEFF:
801                 d71->glb_scl_coeff_addr[blk_id] = reg;
802                 break;
803
804         default:
805                 DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
806                           blk->block_info);
807                 err = -EINVAL;
808                 break;
809         }
810
811         return err;
812 }