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