]> Git Repo - linux.git/blob - drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
Linux 6.14-rc3
[linux.git] / drivers / gpu / drm / atmel-hlcdc / atmel_hlcdc_crtc.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2014 Traphandler
4  * Copyright (C) 2014 Free Electrons
5  *
6  * Author: Jean-Jacques Hiblot <[email protected]>
7  * Author: Boris BREZILLON <[email protected]>
8  */
9
10 #include <linux/clk.h>
11 #include <linux/media-bus-format.h>
12 #include <linux/mfd/atmel-hlcdc.h>
13 #include <linux/pinctrl/consumer.h>
14 #include <linux/pm.h>
15 #include <linux/pm_runtime.h>
16
17 #include <video/videomode.h>
18
19 #include <drm/drm_atomic.h>
20 #include <drm/drm_atomic_helper.h>
21 #include <drm/drm_crtc.h>
22 #include <drm/drm_modeset_helper_vtables.h>
23 #include <drm/drm_probe_helper.h>
24 #include <drm/drm_vblank.h>
25
26 #include "atmel_hlcdc_dc.h"
27
28 /**
29  * struct atmel_hlcdc_crtc_state - Atmel HLCDC CRTC state structure
30  *
31  * @base: base CRTC state
32  * @output_mode: RGBXXX output mode
33  * @dpi: output DPI mode
34  */
35 struct atmel_hlcdc_crtc_state {
36         struct drm_crtc_state base;
37         unsigned int output_mode;
38         u8 dpi;
39 };
40
41 static inline struct atmel_hlcdc_crtc_state *
42 drm_crtc_state_to_atmel_hlcdc_crtc_state(struct drm_crtc_state *state)
43 {
44         return container_of(state, struct atmel_hlcdc_crtc_state, base);
45 }
46
47 /**
48  * struct atmel_hlcdc_crtc - Atmel HLCDC CRTC structure
49  *
50  * @base: base DRM CRTC structure
51  * @dc: pointer to the atmel_hlcdc structure provided by the MFD device
52  * @event: pointer to the current page flip event
53  * @id: CRTC id (returned by drm_crtc_index)
54  */
55 struct atmel_hlcdc_crtc {
56         struct drm_crtc base;
57         struct atmel_hlcdc_dc *dc;
58         struct drm_pending_vblank_event *event;
59         int id;
60 };
61
62 static inline struct atmel_hlcdc_crtc *
63 drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
64 {
65         return container_of(crtc, struct atmel_hlcdc_crtc, base);
66 }
67
68 static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
69 {
70         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
71         struct regmap *regmap = crtc->dc->hlcdc->regmap;
72         struct drm_display_mode *adj = &c->state->adjusted_mode;
73         struct drm_encoder *encoder = NULL, *en_iter;
74         struct drm_connector *connector = NULL;
75         struct atmel_hlcdc_crtc_state *state;
76         struct drm_device *ddev = c->dev;
77         struct drm_connector_list_iter iter;
78         unsigned long mode_rate;
79         struct videomode vm;
80         unsigned long prate;
81         unsigned int mask = ATMEL_HLCDC_CLKDIV_MASK | ATMEL_HLCDC_CLKPOL;
82         unsigned int cfg = 0;
83         int div, ret;
84
85         /* get encoder from crtc */
86         drm_for_each_encoder(en_iter, ddev) {
87                 if (en_iter->crtc == c) {
88                         encoder = en_iter;
89                         break;
90                 }
91         }
92
93         if (encoder) {
94                 /* Get the connector from encoder */
95                 drm_connector_list_iter_begin(ddev, &iter);
96                 drm_for_each_connector_iter(connector, &iter)
97                         if (connector->encoder == encoder)
98                                 break;
99                 drm_connector_list_iter_end(&iter);
100         }
101
102         ret = clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
103         if (ret)
104                 return;
105
106         vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
107         vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
108         vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start;
109         vm.hfront_porch = adj->crtc_hsync_start - adj->crtc_hdisplay;
110         vm.hback_porch = adj->crtc_htotal - adj->crtc_hsync_end;
111         vm.hsync_len = adj->crtc_hsync_end - adj->crtc_hsync_start;
112
113         regmap_write(regmap, ATMEL_HLCDC_CFG(1),
114                      (vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
115
116         regmap_write(regmap, ATMEL_HLCDC_CFG(2),
117                      (vm.vfront_porch - 1) | (vm.vback_porch << 16));
118
119         regmap_write(regmap, ATMEL_HLCDC_CFG(3),
120                      (vm.hfront_porch - 1) | ((vm.hback_porch - 1) << 16));
121
122         regmap_write(regmap, ATMEL_HLCDC_CFG(4),
123                      (adj->crtc_hdisplay - 1) |
124                      ((adj->crtc_vdisplay - 1) << 16));
125
126         prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
127         mode_rate = adj->crtc_clock * 1000;
128         if (!crtc->dc->desc->fixed_clksrc) {
129                 prate *= 2;
130                 cfg |= ATMEL_HLCDC_CLKSEL;
131                 mask |= ATMEL_HLCDC_CLKSEL;
132         }
133
134         div = DIV_ROUND_UP(prate, mode_rate);
135         if (div < 2) {
136                 div = 2;
137         } else if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK) {
138                 /* The divider ended up too big, try a lower base rate. */
139                 cfg &= ~ATMEL_HLCDC_CLKSEL;
140                 prate /= 2;
141                 div = DIV_ROUND_UP(prate, mode_rate);
142                 if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK)
143                         div = ATMEL_HLCDC_CLKDIV_MASK;
144         } else {
145                 int div_low = prate / mode_rate;
146
147                 if (div_low >= 2 &&
148                     (10 * (prate / div_low - mode_rate) <
149                      (mode_rate - prate / div)))
150                         /*
151                          * At least 10 times better when using a higher
152                          * frequency than requested, instead of a lower.
153                          * So, go with that.
154                          */
155                         div = div_low;
156         }
157
158         cfg |= ATMEL_HLCDC_CLKDIV(div);
159
160         if (connector &&
161             connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
162                 cfg |= ATMEL_HLCDC_CLKPOL;
163
164         regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0), mask, cfg);
165
166         state = drm_crtc_state_to_atmel_hlcdc_crtc_state(c->state);
167         cfg = state->output_mode << 8;
168
169         if (!crtc->dc->desc->is_xlcdc) {
170                 if (adj->flags & DRM_MODE_FLAG_NVSYNC)
171                         cfg |= ATMEL_HLCDC_VSPOL;
172
173                 if (adj->flags & DRM_MODE_FLAG_NHSYNC)
174                         cfg |= ATMEL_HLCDC_HSPOL;
175         } else {
176                 cfg |= state->dpi << 11;
177         }
178
179         regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
180                            ATMEL_HLCDC_HSPOL | ATMEL_HLCDC_VSPOL |
181                            ATMEL_HLCDC_VSPDLYS | ATMEL_HLCDC_VSPDLYE |
182                            ATMEL_HLCDC_DISPPOL | ATMEL_HLCDC_DISPDLY |
183                            ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
184                            ATMEL_HLCDC_GUARDTIME_MASK |
185                            (crtc->dc->desc->is_xlcdc ? ATMEL_XLCDC_MODE_MASK |
186                            ATMEL_XLCDC_DPI : ATMEL_HLCDC_MODE_MASK),
187                            cfg);
188
189         clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
190 }
191
192 static enum drm_mode_status
193 atmel_hlcdc_crtc_mode_valid(struct drm_crtc *c,
194                             const struct drm_display_mode *mode)
195 {
196         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
197
198         return atmel_hlcdc_dc_mode_valid(crtc->dc, mode);
199 }
200
201 static void atmel_hlcdc_crtc_atomic_disable(struct drm_crtc *c,
202                                             struct drm_atomic_state *state)
203 {
204         struct drm_device *dev = c->dev;
205         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
206         struct regmap *regmap = crtc->dc->hlcdc->regmap;
207         unsigned int status;
208
209         drm_crtc_vblank_off(c);
210
211         pm_runtime_get_sync(dev->dev);
212
213         if (crtc->dc->desc->is_xlcdc) {
214                 regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_XLCDC_CM);
215                 if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
216                                              !(status & ATMEL_XLCDC_CM),
217                                              10, 1000))
218                         dev_warn(dev->dev, "Atmel LCDC status register CMSTS timeout\n");
219
220                 regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_XLCDC_SD);
221                 if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
222                                              status & ATMEL_XLCDC_SD,
223                                              10, 1000))
224                         dev_warn(dev->dev, "Atmel LCDC status register SDSTS timeout\n");
225         }
226
227         regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
228         if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
229                                      !(status & ATMEL_HLCDC_DISP),
230                                     10, 1000))
231                 dev_warn(dev->dev, "Atmel LCDC status register DISPSTS timeout\n");
232
233         regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
234         if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
235                                      !(status & ATMEL_HLCDC_SYNC),
236                                     10, 1000))
237                 dev_warn(dev->dev, "Atmel LCDC status register LCDSTS timeout\n");
238
239         regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
240         if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
241                                      !(status & ATMEL_HLCDC_PIXEL_CLK),
242                                     10, 1000))
243                 dev_warn(dev->dev, "Atmel LCDC status register CLKSTS timeout\n");
244
245         clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
246         pinctrl_pm_select_sleep_state(dev->dev);
247
248         pm_runtime_allow(dev->dev);
249
250         pm_runtime_put_sync(dev->dev);
251 }
252
253 static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
254                                            struct drm_atomic_state *state)
255 {
256         struct drm_device *dev = c->dev;
257         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
258         struct regmap *regmap = crtc->dc->hlcdc->regmap;
259         unsigned int status;
260
261         pm_runtime_get_sync(dev->dev);
262
263         pm_runtime_forbid(dev->dev);
264
265         pinctrl_pm_select_default_state(dev->dev);
266         clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
267
268         regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
269         if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
270                                      status & ATMEL_HLCDC_PIXEL_CLK,
271                                      10, 1000))
272                 dev_warn(dev->dev, "Atmel LCDC status register CLKSTS timeout\n");
273
274         regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
275         if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
276                                      status & ATMEL_HLCDC_SYNC,
277                                      10, 1000))
278                 dev_warn(dev->dev, "Atmel LCDC status register LCDSTS timeout\n");
279
280         regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
281         if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
282                                      status & ATMEL_HLCDC_DISP,
283                                      10, 1000))
284                 dev_warn(dev->dev, "Atmel LCDC status register DISPSTS timeout\n");
285
286         if (crtc->dc->desc->is_xlcdc) {
287                 regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_XLCDC_CM);
288                 if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
289                                              status & ATMEL_XLCDC_CM,
290                                              10, 1000))
291                         dev_warn(dev->dev, "Atmel LCDC status register CMSTS timeout\n");
292
293                 regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_XLCDC_SD);
294                 if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
295                                              !(status & ATMEL_XLCDC_SD),
296                                              10, 1000))
297                         dev_warn(dev->dev, "Atmel LCDC status register SDSTS timeout\n");
298         }
299
300         pm_runtime_put_sync(dev->dev);
301
302 }
303
304 #define ATMEL_HLCDC_RGB444_OUTPUT               BIT(0)
305 #define ATMEL_HLCDC_RGB565_OUTPUT               BIT(1)
306 #define ATMEL_HLCDC_RGB666_OUTPUT               BIT(2)
307 #define ATMEL_HLCDC_RGB888_OUTPUT               BIT(3)
308 #define ATMEL_HLCDC_DPI_RGB565C1_OUTPUT         BIT(4)
309 #define ATMEL_HLCDC_DPI_RGB565C2_OUTPUT         BIT(5)
310 #define ATMEL_HLCDC_DPI_RGB565C3_OUTPUT         BIT(6)
311 #define ATMEL_HLCDC_DPI_RGB666C1_OUTPUT         BIT(7)
312 #define ATMEL_HLCDC_DPI_RGB666C2_OUTPUT         BIT(8)
313 #define ATMEL_HLCDC_DPI_RGB888_OUTPUT           BIT(9)
314 #define ATMEL_HLCDC_OUTPUT_MODE_MASK            GENMASK(3, 0)
315 #define ATMEL_XLCDC_OUTPUT_MODE_MASK            GENMASK(9, 0)
316
317 static int atmel_xlcdc_connector_output_dsi(struct drm_encoder *encoder,
318                                             struct drm_display_info *info)
319 {
320         int j;
321         unsigned int supported_fmts = 0;
322
323         switch (atmel_hlcdc_encoder_get_bus_fmt(encoder)) {
324         case 0:
325                 break;
326         case MEDIA_BUS_FMT_RGB565_1X16:
327                 return ATMEL_HLCDC_DPI_RGB565C1_OUTPUT;
328         case MEDIA_BUS_FMT_RGB666_1X18:
329                 return ATMEL_HLCDC_DPI_RGB666C1_OUTPUT;
330         case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
331                 return ATMEL_HLCDC_DPI_RGB666C2_OUTPUT;
332         case MEDIA_BUS_FMT_RGB888_1X24:
333                 return ATMEL_HLCDC_DPI_RGB888_OUTPUT;
334         default:
335                 return -EINVAL;
336         }
337
338         for (j = 0; j < info->num_bus_formats; j++) {
339                 switch (info->bus_formats[j]) {
340                 case MEDIA_BUS_FMT_RGB565_1X16:
341                         supported_fmts |= ATMEL_HLCDC_DPI_RGB565C1_OUTPUT;
342                         break;
343                 case MEDIA_BUS_FMT_RGB666_1X18:
344                         supported_fmts |= ATMEL_HLCDC_DPI_RGB666C1_OUTPUT;
345                         break;
346                 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
347                         supported_fmts |= ATMEL_HLCDC_DPI_RGB666C2_OUTPUT;
348                         break;
349                 case MEDIA_BUS_FMT_RGB888_1X24:
350                         supported_fmts |= ATMEL_HLCDC_DPI_RGB888_OUTPUT;
351                         break;
352                 default:
353                         break;
354                 }
355         }
356         return supported_fmts;
357 }
358
359 static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
360 {
361         struct drm_connector *connector = state->connector;
362         struct drm_display_info *info = &connector->display_info;
363         struct drm_encoder *encoder;
364         unsigned int supported_fmts = 0;
365         int j;
366
367         encoder = state->best_encoder;
368         if (!encoder)
369                 encoder = connector->encoder;
370         /*
371          * atmel-hlcdc to support DSI formats with DSI video pipeline
372          * when DRM_MODE_ENCODER_DSI type is set by
373          * connector driver component.
374          */
375         if (encoder->encoder_type == DRM_MODE_ENCODER_DSI)
376                 return atmel_xlcdc_connector_output_dsi(encoder, info);
377
378         switch (atmel_hlcdc_encoder_get_bus_fmt(encoder)) {
379         case 0:
380                 break;
381         case MEDIA_BUS_FMT_RGB444_1X12:
382                 return ATMEL_HLCDC_RGB444_OUTPUT;
383         case MEDIA_BUS_FMT_RGB565_1X16:
384                 return ATMEL_HLCDC_RGB565_OUTPUT;
385         case MEDIA_BUS_FMT_RGB666_1X18:
386                 return ATMEL_HLCDC_RGB666_OUTPUT;
387         case MEDIA_BUS_FMT_RGB888_1X24:
388                 return ATMEL_HLCDC_RGB888_OUTPUT;
389         default:
390                 return -EINVAL;
391         }
392
393         for (j = 0; j < info->num_bus_formats; j++) {
394                 switch (info->bus_formats[j]) {
395                 case MEDIA_BUS_FMT_RGB444_1X12:
396                         supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
397                         break;
398                 case MEDIA_BUS_FMT_RGB565_1X16:
399                         supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
400                         break;
401                 case MEDIA_BUS_FMT_RGB666_1X18:
402                         supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
403                         break;
404                 case MEDIA_BUS_FMT_RGB888_1X24:
405                         supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
406                         break;
407                 default:
408                         break;
409                 }
410         }
411
412         return supported_fmts;
413 }
414
415 static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
416 {
417         unsigned int output_fmts;
418         struct atmel_hlcdc_crtc_state *hstate;
419         struct drm_connector_state *cstate;
420         struct drm_connector *connector;
421         struct atmel_hlcdc_crtc *crtc;
422         int i;
423
424         crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
425         output_fmts = crtc->dc->desc->is_xlcdc ? ATMEL_XLCDC_OUTPUT_MODE_MASK :
426                       ATMEL_HLCDC_OUTPUT_MODE_MASK;
427
428         for_each_new_connector_in_state(state->state, connector, cstate, i) {
429                 unsigned int supported_fmts = 0;
430
431                 if (!cstate->crtc)
432                         continue;
433
434                 supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
435
436                 if (crtc->dc->desc->conflicting_output_formats)
437                         output_fmts &= supported_fmts;
438                 else
439                         output_fmts |= supported_fmts;
440         }
441
442         if (!output_fmts)
443                 return -EINVAL;
444
445         hstate = drm_crtc_state_to_atmel_hlcdc_crtc_state(state);
446         hstate->output_mode = fls(output_fmts) - 1;
447         if (crtc->dc->desc->is_xlcdc) {
448                 /* check if MIPI DPI bit needs to be set */
449                 if (fls(output_fmts) > 3) {
450                         hstate->output_mode -= 4;
451                         hstate->dpi = 1;
452                 } else {
453                         hstate->dpi = 0;
454                 }
455         }
456         return 0;
457 }
458
459 static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
460                                          struct drm_atomic_state *state)
461 {
462         struct drm_crtc_state *s = drm_atomic_get_new_crtc_state(state, c);
463         int ret;
464
465         ret = atmel_hlcdc_crtc_select_output_mode(s);
466         if (ret)
467                 return ret;
468
469         ret = atmel_hlcdc_plane_prepare_disc_area(s);
470         if (ret)
471                 return ret;
472
473         return atmel_hlcdc_plane_prepare_ahb_routing(s);
474 }
475
476 static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c,
477                                           struct drm_atomic_state *state)
478 {
479         drm_crtc_vblank_on(c);
480 }
481
482 static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *c,
483                                           struct drm_atomic_state *state)
484 {
485         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
486         unsigned long flags;
487
488         spin_lock_irqsave(&c->dev->event_lock, flags);
489
490         if (c->state->event) {
491                 c->state->event->pipe = drm_crtc_index(c);
492
493                 WARN_ON(drm_crtc_vblank_get(c) != 0);
494
495                 crtc->event = c->state->event;
496                 c->state->event = NULL;
497         }
498         spin_unlock_irqrestore(&c->dev->event_lock, flags);
499 }
500
501 static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
502         .mode_valid = atmel_hlcdc_crtc_mode_valid,
503         .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
504         .atomic_check = atmel_hlcdc_crtc_atomic_check,
505         .atomic_begin = atmel_hlcdc_crtc_atomic_begin,
506         .atomic_flush = atmel_hlcdc_crtc_atomic_flush,
507         .atomic_enable = atmel_hlcdc_crtc_atomic_enable,
508         .atomic_disable = atmel_hlcdc_crtc_atomic_disable,
509 };
510
511 static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
512 {
513         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
514
515         drm_crtc_cleanup(c);
516         kfree(crtc);
517 }
518
519 static void atmel_hlcdc_crtc_finish_page_flip(struct atmel_hlcdc_crtc *crtc)
520 {
521         struct drm_device *dev = crtc->base.dev;
522         unsigned long flags;
523
524         spin_lock_irqsave(&dev->event_lock, flags);
525         if (crtc->event) {
526                 drm_crtc_send_vblank_event(&crtc->base, crtc->event);
527                 drm_crtc_vblank_put(&crtc->base);
528                 crtc->event = NULL;
529         }
530         spin_unlock_irqrestore(&dev->event_lock, flags);
531 }
532
533 void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
534 {
535         drm_crtc_handle_vblank(c);
536         atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
537 }
538
539 static void atmel_hlcdc_crtc_reset(struct drm_crtc *crtc)
540 {
541         struct atmel_hlcdc_crtc_state *state;
542
543         if (crtc->state) {
544                 __drm_atomic_helper_crtc_destroy_state(crtc->state);
545                 state = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state);
546                 kfree(state);
547                 crtc->state = NULL;
548         }
549
550         state = kzalloc(sizeof(*state), GFP_KERNEL);
551         if (state)
552                 __drm_atomic_helper_crtc_reset(crtc, &state->base);
553 }
554
555 static struct drm_crtc_state *
556 atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc)
557 {
558         struct atmel_hlcdc_crtc_state *state, *cur;
559         struct atmel_hlcdc_crtc *c = drm_crtc_to_atmel_hlcdc_crtc(crtc);
560
561         if (WARN_ON(!crtc->state))
562                 return NULL;
563
564         state = kmalloc(sizeof(*state), GFP_KERNEL);
565         if (!state)
566                 return NULL;
567         __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
568
569         cur = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state);
570         state->output_mode = cur->output_mode;
571         if (c->dc->desc->is_xlcdc)
572                 state->dpi = cur->dpi;
573
574         return &state->base;
575 }
576
577 static void atmel_hlcdc_crtc_destroy_state(struct drm_crtc *crtc,
578                                            struct drm_crtc_state *s)
579 {
580         struct atmel_hlcdc_crtc_state *state;
581
582         state = drm_crtc_state_to_atmel_hlcdc_crtc_state(s);
583         __drm_atomic_helper_crtc_destroy_state(s);
584         kfree(state);
585 }
586
587 static int atmel_hlcdc_crtc_enable_vblank(struct drm_crtc *c)
588 {
589         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
590         struct regmap *regmap = crtc->dc->hlcdc->regmap;
591
592         /* Enable SOF (Start Of Frame) interrupt for vblank counting */
593         regmap_write(regmap, ATMEL_HLCDC_IER, ATMEL_HLCDC_SOF);
594
595         return 0;
596 }
597
598 static void atmel_hlcdc_crtc_disable_vblank(struct drm_crtc *c)
599 {
600         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
601         struct regmap *regmap = crtc->dc->hlcdc->regmap;
602
603         regmap_write(regmap, ATMEL_HLCDC_IDR, ATMEL_HLCDC_SOF);
604 }
605
606 static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
607         .page_flip = drm_atomic_helper_page_flip,
608         .set_config = drm_atomic_helper_set_config,
609         .destroy = atmel_hlcdc_crtc_destroy,
610         .reset = atmel_hlcdc_crtc_reset,
611         .atomic_duplicate_state =  atmel_hlcdc_crtc_duplicate_state,
612         .atomic_destroy_state = atmel_hlcdc_crtc_destroy_state,
613         .enable_vblank = atmel_hlcdc_crtc_enable_vblank,
614         .disable_vblank = atmel_hlcdc_crtc_disable_vblank,
615 };
616
617 int atmel_hlcdc_crtc_create(struct drm_device *dev)
618 {
619         struct atmel_hlcdc_plane *primary = NULL, *cursor = NULL;
620         struct atmel_hlcdc_dc *dc = dev->dev_private;
621         struct atmel_hlcdc_crtc *crtc;
622         int ret;
623         int i;
624
625         crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
626         if (!crtc)
627                 return -ENOMEM;
628
629         crtc->dc = dc;
630
631         for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
632                 if (!dc->layers[i])
633                         continue;
634
635                 switch (dc->layers[i]->desc->type) {
636                 case ATMEL_HLCDC_BASE_LAYER:
637                         primary = atmel_hlcdc_layer_to_plane(dc->layers[i]);
638                         break;
639
640                 case ATMEL_HLCDC_CURSOR_LAYER:
641                         cursor = atmel_hlcdc_layer_to_plane(dc->layers[i]);
642                         break;
643
644                 default:
645                         break;
646                 }
647         }
648
649         ret = drm_crtc_init_with_planes(dev, &crtc->base, &primary->base,
650                                         &cursor->base, &atmel_hlcdc_crtc_funcs,
651                                         NULL);
652         if (ret < 0)
653                 goto fail;
654
655         crtc->id = drm_crtc_index(&crtc->base);
656
657         for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
658                 struct atmel_hlcdc_plane *overlay;
659
660                 if (dc->layers[i] &&
661                     dc->layers[i]->desc->type == ATMEL_HLCDC_OVERLAY_LAYER) {
662                         overlay = atmel_hlcdc_layer_to_plane(dc->layers[i]);
663                         overlay->base.possible_crtcs = 1 << crtc->id;
664                 }
665         }
666
667         drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
668
669         drm_mode_crtc_set_gamma_size(&crtc->base, ATMEL_HLCDC_CLUT_SIZE);
670         drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
671                                    ATMEL_HLCDC_CLUT_SIZE);
672
673         dc->crtc = &crtc->base;
674
675         return 0;
676
677 fail:
678         atmel_hlcdc_crtc_destroy(&crtc->base);
679         return ret;
680 }
This page took 0.06921 seconds and 4 git commands to generate.