]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
8be273fc7ca96b655ff643ca32b18f01d6ae25b3
[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 u32 to_rot_ctrl(u32 rot)
75 {
76         u32 lr_ctrl = 0;
77
78         switch (rot & DRM_MODE_ROTATE_MASK) {
79         case DRM_MODE_ROTATE_0:
80                 lr_ctrl |= L_ROT(L_ROT_R0);
81                 break;
82         case DRM_MODE_ROTATE_90:
83                 lr_ctrl |= L_ROT(L_ROT_R90);
84                 break;
85         case DRM_MODE_ROTATE_180:
86                 lr_ctrl |= L_ROT(L_ROT_R180);
87                 break;
88         case DRM_MODE_ROTATE_270:
89                 lr_ctrl |= L_ROT(L_ROT_R270);
90                 break;
91         }
92
93         if (rot & DRM_MODE_REFLECT_X)
94                 lr_ctrl |= L_HFLIP;
95         if (rot & DRM_MODE_REFLECT_Y)
96                 lr_ctrl |= L_VFLIP;
97
98         return lr_ctrl;
99 }
100
101 static inline u32 to_d71_input_id(struct komeda_component_output *output)
102 {
103         struct komeda_component *comp = output->component;
104
105         return comp ? (comp->hw_id + output->output_port) : 0;
106 }
107
108 static void d71_layer_disable(struct komeda_component *c)
109 {
110         malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
111 }
112
113 static void d71_layer_update(struct komeda_component *c,
114                              struct komeda_component_state *state)
115 {
116         struct komeda_layer_state *st = to_layer_st(state);
117         struct drm_plane_state *plane_st = state->plane->state;
118         struct drm_framebuffer *fb = plane_st->fb;
119         struct komeda_fb *kfb = to_kfb(fb);
120         u32 __iomem *reg = c->reg;
121         u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
122         u32 ctrl = L_EN | to_rot_ctrl(st->rot);
123         int i;
124
125         for (i = 0; i < fb->format->num_planes; i++) {
126                 malidp_write32(reg,
127                                BLK_P0_PTR_LOW + i * LAYER_PER_PLANE_REGS * 4,
128                                lower_32_bits(st->addr[i]));
129                 malidp_write32(reg,
130                                BLK_P0_PTR_HIGH + i * LAYER_PER_PLANE_REGS * 4,
131                                upper_32_bits(st->addr[i]));
132                 if (i >= 2)
133                         break;
134
135                 malidp_write32(reg,
136                                BLK_P0_STRIDE + i * LAYER_PER_PLANE_REGS * 4,
137                                fb->pitches[i] & 0xFFFF);
138         }
139
140         malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
141         malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
142
143         malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
144 }
145
146 static struct komeda_component_funcs d71_layer_funcs = {
147         .update         = d71_layer_update,
148         .disable        = d71_layer_disable,
149 };
150
151 static int d71_layer_init(struct d71_dev *d71,
152                           struct block_header *blk, u32 __iomem *reg)
153 {
154         struct komeda_component *c;
155         struct komeda_layer *layer;
156         u32 pipe_id, layer_id, layer_info;
157
158         get_resources_id(blk->block_info, &pipe_id, &layer_id);
159         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
160                                  layer_id,
161                                  BLOCK_INFO_INPUT_ID(blk->block_info),
162                                  &d71_layer_funcs, 0,
163                                  get_valid_inputs(blk),
164                                  1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
165         if (IS_ERR(c)) {
166                 DRM_ERROR("Failed to add layer component\n");
167                 return PTR_ERR(c);
168         }
169
170         layer = to_layer(c);
171         layer_info = malidp_read32(reg, LAYER_INFO);
172
173         if (layer_info & L_INFO_RF)
174                 layer->layer_type = KOMEDA_FMT_RICH_LAYER;
175         else
176                 layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
177
178         set_range(&layer->hsize_in, 4, d71->max_line_size);
179         set_range(&layer->vsize_in, 4, d71->max_vsize);
180
181         malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
182
183         layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
184
185         return 0;
186 }
187
188 static int d71_wb_layer_init(struct d71_dev *d71,
189                              struct block_header *blk, u32 __iomem *reg)
190 {
191         DRM_DEBUG("Detect D71_Wb_Layer.\n");
192
193         return 0;
194 }
195
196 static void d71_component_disable(struct komeda_component *c)
197 {
198         u32 __iomem *reg = c->reg;
199         u32 i;
200
201         malidp_write32(reg, BLK_CONTROL, 0);
202
203         for (i = 0; i < c->max_active_inputs; i++)
204                 malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
205 }
206
207 static void compiz_enable_input(u32 __iomem *id_reg,
208                                 u32 __iomem *cfg_reg,
209                                 u32 input_hw_id,
210                                 struct komeda_compiz_input_cfg *cin)
211 {
212         u32 ctrl = CU_INPUT_CTRL_EN;
213         u8 blend = cin->pixel_blend_mode;
214
215         if (blend == DRM_MODE_BLEND_PIXEL_NONE)
216                 ctrl |= CU_INPUT_CTRL_PAD;
217         else if (blend == DRM_MODE_BLEND_PREMULTI)
218                 ctrl |= CU_INPUT_CTRL_PMUL;
219
220         ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
221
222         malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
223
224         malidp_write32(cfg_reg, CU_INPUT0_SIZE,
225                        HV_SIZE(cin->hsize, cin->vsize));
226         malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
227                        HV_OFFSET(cin->hoffset, cin->voffset));
228         malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
229 }
230
231 static void d71_compiz_update(struct komeda_component *c,
232                               struct komeda_component_state *state)
233 {
234         struct komeda_compiz_state *st = to_compiz_st(state);
235         u32 __iomem *reg = c->reg;
236         u32 __iomem *id_reg, *cfg_reg;
237         u32 index, input_hw_id;
238
239         for_each_changed_input(state, index) {
240                 id_reg = reg + index;
241                 cfg_reg = reg + index * CU_PER_INPUT_REGS;
242                 input_hw_id = to_d71_input_id(&state->inputs[index]);
243                 if (state->active_inputs & BIT(index)) {
244                         compiz_enable_input(id_reg, cfg_reg,
245                                             input_hw_id, &st->cins[index]);
246                 } else {
247                         malidp_write32(id_reg, BLK_INPUT_ID0, 0);
248                         malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
249                 }
250         }
251
252         malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
253 }
254
255 struct komeda_component_funcs d71_compiz_funcs = {
256         .update         = d71_compiz_update,
257         .disable        = d71_component_disable,
258 };
259
260 static int d71_compiz_init(struct d71_dev *d71,
261                            struct block_header *blk, u32 __iomem *reg)
262 {
263         struct komeda_component *c;
264         struct komeda_compiz *compiz;
265         u32 pipe_id, comp_id;
266
267         get_resources_id(blk->block_info, &pipe_id, &comp_id);
268
269         c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
270                                  comp_id,
271                                  BLOCK_INFO_INPUT_ID(blk->block_info),
272                                  &d71_compiz_funcs,
273                                  CU_NUM_INPUT_IDS, get_valid_inputs(blk),
274                                  CU_NUM_OUTPUT_IDS, reg,
275                                  "CU%d", pipe_id);
276         if (IS_ERR(c))
277                 return PTR_ERR(c);
278
279         compiz = to_compiz(c);
280
281         set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size);
282         set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
283
284         return 0;
285 }
286
287 static int d71_improc_init(struct d71_dev *d71,
288                            struct block_header *blk, u32 __iomem *reg)
289 {
290         DRM_DEBUG("Detect D71_improc.\n");
291
292         return 0;
293 }
294
295 static int d71_timing_ctrlr_init(struct d71_dev *d71,
296                                  struct block_header *blk, u32 __iomem *reg)
297 {
298         DRM_DEBUG("Detect D71_timing_ctrlr.\n");
299
300         return 0;
301 }
302
303 int d71_probe_block(struct d71_dev *d71,
304                     struct block_header *blk, u32 __iomem *reg)
305 {
306         struct d71_pipeline *pipe;
307         int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
308
309         int err = 0;
310
311         switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
312         case D71_BLK_TYPE_GCU:
313                 break;
314
315         case D71_BLK_TYPE_LPU:
316                 pipe = d71->pipes[blk_id];
317                 pipe->lpu_addr = reg;
318                 break;
319
320         case D71_BLK_TYPE_LPU_LAYER:
321                 err = d71_layer_init(d71, blk, reg);
322                 break;
323
324         case D71_BLK_TYPE_LPU_WB_LAYER:
325                 err = d71_wb_layer_init(d71, blk, reg);
326                 break;
327
328         case D71_BLK_TYPE_CU:
329                 pipe = d71->pipes[blk_id];
330                 pipe->cu_addr = reg;
331                 err = d71_compiz_init(d71, blk, reg);
332                 break;
333
334         case D71_BLK_TYPE_CU_SPLITTER:
335         case D71_BLK_TYPE_CU_SCALER:
336         case D71_BLK_TYPE_CU_MERGER:
337                 break;
338
339         case D71_BLK_TYPE_DOU:
340                 pipe = d71->pipes[blk_id];
341                 pipe->dou_addr = reg;
342                 break;
343
344         case D71_BLK_TYPE_DOU_IPS:
345                 err = d71_improc_init(d71, blk, reg);
346                 break;
347
348         case D71_BLK_TYPE_DOU_FT_COEFF:
349                 pipe = d71->pipes[blk_id];
350                 pipe->dou_ft_coeff_addr = reg;
351                 break;
352
353         case D71_BLK_TYPE_DOU_BS:
354                 err = d71_timing_ctrlr_init(d71, blk, reg);
355                 break;
356
357         case D71_BLK_TYPE_GLB_LT_COEFF:
358                 break;
359
360         case D71_BLK_TYPE_GLB_SCL_COEFF:
361                 d71->glb_scl_coeff_addr[blk_id] = reg;
362                 break;
363
364         default:
365                 DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
366                           blk->block_info);
367                 err = -EINVAL;
368                 break;
369         }
370
371         return err;
372 }