1 /*
2 * Copyright (C) 2019 Allwinnertech Co.Ltd
3 * Authors: zhengwanyu
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 */
11 #include <drm/drm_crtc_helper.h>
12 #include <drm/drm_fb_helper.h>
13 #include <drm/drm_plane_helper.h>
14 #include <drm/drm_atomic_helper.h>
15 #include <drm/drm_atomic.h>
16 #include <drm/drm_print.h>
17 #include <drm/drm_vblank.h>
18
19 #include "sunxi_drm_drv.h"
20 #include "sunxi_drm_crtc.h"
21 #include "sunxi_drm_plane.h"
22 #include "sunxi_drm_connector.h"
23
24 static unsigned int sunxi_crtc_cnt;
25 static struct sunxi_drm_crtc *sunxi_crtc;
26
sunxi_drm_crtc_get_crtc(int id)27 struct sunxi_drm_crtc *sunxi_drm_crtc_get_crtc(int id)
28 {
29 if (id >= sunxi_crtc_cnt) {
30 DRM_ERROR("crtc id:%d is too big\n", id);
31 return NULL;
32 }
33
34 return &sunxi_crtc[id];
35 }
36
sunxi_drm_get_crtc_count(void)37 unsigned int sunxi_drm_get_crtc_count(void)
38 {
39 return sunxi_crtc_cnt;
40 }
41
42 void sunxi_drm_crtc_destroy(struct drm_crtc *drm_crtc);
43
44 static struct drm_connector *
sunxi_crtc_get_attached_connector(struct drm_crtc * crtc)45 sunxi_crtc_get_attached_connector(struct drm_crtc *crtc)
46 {
47 bool find = false;
48 struct drm_encoder *encoder;
49 struct drm_connector *connector;
50 struct drm_connector_list_iter conn_iter;
51 struct drm_device *dev;
52
53 drm_for_each_encoder(encoder, crtc->dev) {
54 if (encoder->crtc == crtc) {
55 find = true;
56 break;
57 }
58 }
59
60 if (!find) {
61 DRM_ERROR("can NOT find the attached encoder for crtc:%d\n",
62 crtc->index);
63 return NULL;
64 }
65 dev = encoder->dev;
66 find = false;
67 drm_connector_list_iter_begin(dev, &conn_iter);
68 drm_for_each_connector_iter(connector, &conn_iter) {
69 if (connector->encoder == encoder) {
70 drm_connector_list_iter_end(&conn_iter);
71 find = true;
72 break;
73 }
74 }
75 drm_connector_list_iter_end(&conn_iter);
76
77 if (!find) {
78 DRM_ERROR("can NOT find the attached connector for encoder:%d\n",
79 encoder->index);
80 return NULL;
81 }
82
83 return connector;
84 }
85
sunxi_crtc_set_enhance(struct drm_crtc * crtc,struct sunxi_drm_crtc_enhance * enhance)86 static int sunxi_crtc_set_enhance(struct drm_crtc *crtc,
87 struct sunxi_drm_crtc_enhance *enhance)
88 {
89 int ret;
90 struct drm_connector *connector;
91 struct sunxi_drm_connector *sconnector;
92 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
93 struct sunxi_de_funcs *de_funcs = scrtc->hw_funcs;
94
95 connector = sunxi_crtc_get_attached_connector(crtc);
96 if (!connector) {
97 DRM_ERROR("Not find attached connector for crtc:%d\n",
98 crtc->index);
99 return -EINVAL;
100 }
101
102 sconnector = to_sunxi_connector(connector);
103
104 mutex_lock(&scrtc->update_reg_lock);
105 ret = de_funcs->set_enhance(crtc->index,
106 enhance->mode, enhance->enable,
107 crtc->mode.hdisplay, crtc->mode.vdisplay,
108 sconnector->type);
109
110 atomic_set(&scrtc->update, 1);
111
112 mutex_unlock(&scrtc->update_reg_lock);
113
114 return ret;
115 }
116
117
sunxi_crtc_get_enhance(struct drm_crtc * crtc,struct sunxi_drm_crtc_enhance * enhance)118 static void sunxi_crtc_get_enhance(struct drm_crtc *crtc,
119 struct sunxi_drm_crtc_enhance *enhance)
120 {
121 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
122 struct sunxi_de_funcs *de_funcs = scrtc->hw_funcs;
123
124 mutex_lock(&scrtc->update_reg_lock);
125 de_funcs->get_enhance(crtc->index,
126 &enhance->mode, &enhance->enable, NULL, NULL);
127 mutex_unlock(&scrtc->update_reg_lock);
128 }
129
sunxi_drm_crtc_set_enhance_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)130 int sunxi_drm_crtc_set_enhance_ioctl(struct drm_device *dev,
131 void *data, struct drm_file *file_priv)
132 {
133 struct drm_crtc *crtc;
134 struct sunxi_drm_crtc_enhance *enhance =
135 (struct sunxi_drm_crtc_enhance *)data;
136
137 crtc = drm_crtc_find(dev, file_priv, enhance->crtc_obj_id);
138 if (!crtc) {
139 DRM_ERROR("can NOT find crtc for crtc_id:%d\n",
140 enhance->crtc_obj_id);
141 return -EINVAL;
142 }
143
144 return sunxi_crtc_set_enhance(crtc, enhance);
145 }
146
sunxi_drm_crtc_get_enhance_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)147 int sunxi_drm_crtc_get_enhance_ioctl(struct drm_device *dev,
148 void *data, struct drm_file *file_priv)
149 {
150 struct drm_crtc *crtc;
151 struct sunxi_drm_crtc_enhance *enhance =
152 (struct sunxi_drm_crtc_enhance *)data;
153
154 crtc = drm_crtc_find(dev, file_priv, enhance->crtc_obj_id);
155 if (!crtc) {
156 DRM_ERROR("can NOT find crtc for crtc_id:%d\n",
157 enhance->crtc_obj_id);
158 return -EINVAL;
159 }
160
161 sunxi_crtc_get_enhance(crtc, enhance);
162
163 return 0;
164 }
165
166 /*smbl*/
sunxi_crtc_set_smbl(struct drm_crtc * crtc,struct sunxi_drm_crtc_smbl * smbl)167 static int sunxi_crtc_set_smbl(struct drm_crtc *crtc,
168 struct sunxi_drm_crtc_smbl *smbl)
169 {
170 int ret;
171 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
172 struct sunxi_de_funcs *de_funcs = scrtc->hw_funcs;
173
174 mutex_lock(&scrtc->update_reg_lock);
175 ret = de_funcs->set_smbl(crtc->index,
176 smbl->enable, &smbl->window);
177
178 atomic_set(&scrtc->update, 1);
179
180 mutex_unlock(&scrtc->update_reg_lock);
181
182 return ret;
183 }
184
sunxi_crtc_get_smbl(struct drm_crtc * crtc,struct sunxi_drm_crtc_smbl * smbl)185 static void sunxi_crtc_get_smbl(struct drm_crtc *crtc,
186 struct sunxi_drm_crtc_smbl *smbl)
187 {
188 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
189 struct sunxi_de_funcs *de_funcs = scrtc->hw_funcs;
190
191 mutex_lock(&scrtc->update_reg_lock);
192 de_funcs->get_smbl(crtc->index,
193 &smbl->enable, &smbl->window);
194 mutex_unlock(&scrtc->update_reg_lock);
195 }
196
sunxi_drm_crtc_set_smbl_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)197 int sunxi_drm_crtc_set_smbl_ioctl(struct drm_device *dev,
198 void *data, struct drm_file *file_priv)
199 {
200 struct drm_crtc *crtc;
201 struct sunxi_drm_crtc_smbl *smbl =
202 (struct sunxi_drm_crtc_smbl *)data;
203
204 crtc = drm_crtc_find(dev, file_priv, smbl->crtc_obj_id);
205 if (!crtc) {
206 DRM_ERROR("can NOT find crtc for crtc_id:%d\n",
207 smbl->crtc_obj_id);
208 return -EINVAL;
209 }
210
211 return sunxi_crtc_set_smbl(crtc, smbl);
212 }
213
sunxi_drm_crtc_get_smbl_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)214 int sunxi_drm_crtc_get_smbl_ioctl(struct drm_device *dev,
215 void *data, struct drm_file *file_priv)
216 {
217 struct drm_crtc *crtc;
218 struct sunxi_drm_crtc_smbl *smbl =
219 (struct sunxi_drm_crtc_smbl *)data;
220
221 crtc = drm_crtc_find(dev, file_priv, smbl->crtc_obj_id);
222 if (!crtc) {
223 DRM_ERROR("can NOT find crtc for crtc_id:%d\n",
224 smbl->crtc_obj_id);
225 return -EINVAL;
226 }
227
228 sunxi_crtc_get_smbl(crtc, smbl);
229
230 return 0;
231 }
232
233
sunxi_crtc_modeinfo_dump(struct drm_mode_modeinfo * mode)234 void sunxi_crtc_modeinfo_dump(struct drm_mode_modeinfo *mode)
235 {
236 DRM_INFO("MODE INFO:\n");
237 DRM_INFO("clock:%u\n flag:%u type:%u name:%s\n",
238 mode->clock, mode->flags, mode->type, mode->name);
239 DRM_INFO("hdisplay:%u hsync_start:%u hsync_end:%u htotal:%u hskew:%u\n",
240 mode->hdisplay, mode->hsync_start, mode->hsync_end,
241 mode->htotal, mode->hskew);
242 DRM_INFO("vdisplay:%u vsync_start:%u vsync_end:%u "
243 "vtotal:%u hscan:%u vrefresh:%u\n",
244 mode->vdisplay, mode->vsync_start, mode->vsync_end,
245 mode->vtotal, mode->vscan, mode->vrefresh);
246 }
247
248 /*void sunxi_crtc_state_dump(struct drm_crtc_state *state)
249 {
250 struct drm_mode_modeinfo modeinfo;
251
252 DRM_INFO("drm_crtc_state info:\n");
253 DRM_INFO("CRTC index: %d\n", drm_crtc_index(state->crtc));
254 DRM_INFO("enable:%u active:%u\n", state->enable, state->active);
255 DRM_INFO("Changed: planes:%u mode:%u active:%u connectors:%u "
256 "zops:%u color_mgmt_changed:%u\n", state->planes_changed,
257 state->mode_changed, state->active_changed,
258 state->connectors_changed,
259 state->zpos_changed, state->color_mgmt_changed);
260 DRM_INFO("MASK: plane:0x%x connector:0x%x encoder:0x%x\n",
261 state->plane_mask, state->connector_mask, state->encoder_mask);
262 DRM_INFO("last_vblank_count:%u\n", state->last_vblank_count);
263
264 drm_property_reference_blob(state->mode_blob);
265 memcpy(&modeinfo, state->mode_blob->data, state->mode_blob->length);
266 sunxi_crtc_modeinfo_dump(&modeinfo);
267 drm_property_unreference_blob(state->mode_blob);
268 }*/
269
sunxi_crtc_modeinfo_show(char * buf,struct drm_mode_modeinfo * mode)270 static ssize_t sunxi_crtc_modeinfo_show(char *buf, struct drm_mode_modeinfo *mode)
271 {
272 ssize_t n = 0;
273
274 n += sprintf(buf + n, "clock:%u flag:%u type:%u name:%s\n",
275 mode->clock, mode->flags, mode->type, mode->name);
276 n += sprintf(buf + n, "hdisplay:%u hsync_start:%u hsync_end:%u htotal:%u hskew:%u\n",
277 mode->hdisplay, mode->hsync_start, mode->hsync_end,
278 mode->htotal, mode->hskew);
279 n += sprintf(buf + n, "vdisplay:%u vsync_start:%u vsync_end:%u "
280 "vtotal:%u hscan:%u vrefresh:%u\n\n",
281 mode->vdisplay, mode->vsync_start, mode->vsync_end,
282 mode->vtotal, mode->vscan, mode->vrefresh);
283
284 return n;
285 }
286
287 /*static ssize_t sunxi_crtc_state_show(char *buf, struct drm_crtc_state *state)
288 {
289 ssize_t n = 0;
290 struct drm_mode_modeinfo modeinfo;
291
292 n += sprintf(buf + n, "enable:%u active:%u\n", state->enable, state->active);
293 n += sprintf(buf + n, "Changed: planes:%u mode:%u active:%u connectors:%u "
294 "zops:%u color_mgmt_changed:%u\n", state->planes_changed,
295 state->mode_changed, state->active_changed,
296 state->connectors_changed,
297 state->zpos_changed, state->color_mgmt_changed);
298 n += sprintf(buf + n, "MASK: plane:0x%x connector:0x%x encoder:0x%x\n",
299 state->plane_mask, state->connector_mask, state->encoder_mask);
300 n += sprintf(buf + n, "last_vblank_count:%u\n", state->last_vblank_count);
301
302 if (!state->mode_blob) {
303 n += sprintf(buf + n, "No mode blob\n");
304 return n;
305 }
306
307 n += sprintf(buf + n, "[crtc state MODE INFO]:\n");
308 drm_property_reference_blob(state->mode_blob);
309 memcpy(&modeinfo, state->mode_blob->data, state->mode_blob->length);
310 n += sunxi_crtc_modeinfo_show(buf + n, &modeinfo);
311 drm_property_unreference_blob(state->mode_blob);
312
313 return n;
314 }
315
316
317 ssize_t sunxi_drm_crtc_show(char *buf, struct drm_device *dev)
318 {
319 ssize_t n = 0;
320 struct drm_crtc *crtc;
321
322 drm_for_each_crtc(crtc, dev) {
323 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
324
325 n += sprintf(buf + n, "crtc id:%d\n\n", scrtc->crtc_id);
326
327 n += sprintf(buf + n, "[crtc id:%d basic info]:\n", scrtc->crtc_id);
328 n += sprintf(buf + n, "enabled(core):%d enable(hal):%d\n",
329 crtc->enabled, scrtc->enabled);
330 n += sprintf(buf + n, "overlay_plane_num:%d plane_num:%d\n",
331 scrtc->overlay_plane_num, scrtc->plane_num);
332 n += sprintf(buf + n, "crtc name:%s\n", crtc->name);
333 n += sprintf(buf + n, "drm_mode_object id:%u\n", crtc->base.id);
334
335 if (!crtc->enabled || !scrtc->enabled) {
336 n += sprintf(buf + n, "NOT enabled!!!\n\n");
337 return n;
338 }
339
340 n += sprintf(buf + n, "x-y:%d-%d\n", crtc->x, crtc->y);
341 n += sprintf(buf + n, "fence_seqno:%lu\n", crtc->fence_seqno);
342 n += sprintf(buf + n, "timeline_name:%s\n\n", crtc->timeline_name);
343
344 if (crtc->state) {
345 n += sprintf(buf + n, "[crtc id:%d state info]:\n", scrtc->crtc_id);
346 n += sunxi_crtc_state_show(buf + n, crtc->state);
347 }
348
349 n += sprintf(buf + n, "[crtc id:%d enabled planes info]:\n", scrtc->crtc_id);
350 n += sunxi_drm_planes_show(buf + n, crtc->dev, crtc);
351
352 n += sprintf(buf + n, "\n");
353 }
354
355 return n;
356 }*/
357
sunxi_drm_crtc_in_use(struct sunxi_drm_crtc * scrtc)358 bool sunxi_drm_crtc_in_use(struct sunxi_drm_crtc *scrtc)
359 {
360 struct drm_encoder *encoder;
361 struct sunxi_drm_encoder *sencoder;
362 struct drm_crtc *crtc = &scrtc->crtc;
363 struct drm_device *dev = crtc->dev;
364
365 drm_for_each_encoder(encoder, dev) {
366 sencoder = to_sunxi_encoder(encoder);
367 if (encoder->crtc == crtc && sencoder->is_in_use(sencoder))
368 return true;
369 }
370
371 return false;
372 }
373
sunxi_crtc_finish_page_flip(struct drm_device * dev,struct sunxi_drm_crtc * scrtc)374 static void sunxi_crtc_finish_page_flip(struct drm_device *dev,
375 struct sunxi_drm_crtc *scrtc)
376 {
377 unsigned long flags;
378
379 /*send the vblank of drm_crtc_state->event*/
380 spin_lock_irqsave(&dev->event_lock, flags);
381 if (scrtc->event) {
382 drm_crtc_send_vblank_event(&scrtc->crtc, scrtc->event);
383 drm_crtc_vblank_put(&scrtc->crtc);
384 scrtc->event = NULL;
385 }
386 spin_unlock_irqrestore(&dev->event_lock, flags);
387 }
388
sunxi_crtc_event_proc(int irq,void * parg)389 static irqreturn_t sunxi_crtc_event_proc(int irq, void *parg)
390 {
391 int ret = 0;
392 struct drm_crtc *crtc = (struct drm_crtc *)parg;
393 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
394 struct sunxi_de_funcs *hw_funcs = scrtc->hw_funcs;
395
396 ret = hw_funcs->query_irq(scrtc->crtc_id);
397 if (ret < 0) {
398 DRM_ERROR("sunxi_de_query_irq FAILED!\n");
399 goto out;
400 }
401
402 ret = hw_funcs->event_proc(scrtc->crtc_id,
403 atomic_read(&scrtc->update));
404 if (ret < 0) {
405 DRM_ERROR("sunxi_de_event_proc FAILED!\n");
406 goto out;
407 }
408 atomic_set(&scrtc->update, 0);
409
410 out:
411 drm_crtc_handle_vblank(&scrtc->crtc);
412 sunxi_crtc_finish_page_flip(crtc->dev, scrtc);
413
414 return IRQ_HANDLED;
415 }
416
417 static bool
sunxi_crtc_encoder_is_supported(struct sunxi_drm_crtc * scrtc,struct sunxi_drm_encoder * senc)418 sunxi_crtc_encoder_is_supported(struct sunxi_drm_crtc *scrtc,
419 struct sunxi_drm_encoder *senc)
420 {
421 struct sunxi_de_funcs *hw_funcs = scrtc->hw_funcs;
422
423 return hw_funcs->is_support_tcon(scrtc->crtc_id, senc->encoder_id);
424 }
425
426 static char crtc_irq_name[30][4];
sunxi_drm_crtc_irq_register(struct sunxi_drm_crtc * scrtc,unsigned int irq_no)427 static int sunxi_drm_crtc_irq_register(struct sunxi_drm_crtc *scrtc,
428 unsigned int irq_no)
429 {
430 int ret;
431 struct drm_crtc *crtc = &scrtc->crtc;
432
433 sprintf(crtc_irq_name[scrtc->crtc_id], "sunxi-crtc%d", scrtc->crtc_id);
434 DRM_INFO("irq name:%s, irq num:%d\n", crtc_irq_name[scrtc->crtc_id], irq_no);
435
436 ret = devm_request_irq(crtc->dev->dev, irq_no,
437 sunxi_crtc_event_proc, IRQF_TRIGGER_NONE,
438 crtc_irq_name[scrtc->crtc_id], crtc);
439 if (ret < 0) {
440 DRM_ERROR("sunxi crtc request irq failed\n");
441 return -1;
442 }
443
444 drm_crtc_vblank_on(crtc);
445
446 return 0;
447 }
448
sunxi_drm_crtc_irq_unregister(struct sunxi_drm_crtc * scrtc,unsigned int irq_no)449 static void sunxi_drm_crtc_irq_unregister(struct sunxi_drm_crtc *scrtc,
450 unsigned int irq_no)
451 {
452 struct drm_crtc *crtc = &scrtc->crtc;
453 devm_free_irq(crtc->dev->dev, irq_no, crtc);
454
455 if (crtc->state->event && !crtc->state->active) {
456 spin_lock_irq(&crtc->dev->event_lock);
457 drm_crtc_send_vblank_event(crtc, crtc->state->event);
458 spin_unlock_irq(&crtc->dev->event_lock);
459 crtc->state->event = NULL;
460 }
461 }
462
sunxi_crtc_destroy(struct drm_crtc * crtc)463 static void sunxi_crtc_destroy(struct drm_crtc *crtc)
464 {
465 sunxi_drm_crtc_destroy(crtc);
466 }
467
sunxi_crtc_reset(struct drm_crtc * crtc)468 static void sunxi_crtc_reset(struct drm_crtc *crtc)
469 {
470 drm_atomic_helper_crtc_reset(crtc);
471 }
472
sunxi_crtc_atomic_get_property(struct drm_crtc * crtc,const struct drm_crtc_state * state,struct drm_property * property,uint64_t * val)473 int sunxi_crtc_atomic_get_property(struct drm_crtc *crtc,
474 const struct drm_crtc_state *state,
475 struct drm_property *property,
476 uint64_t *val)
477 {
478 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
479
480 if (scrtc->support_smbl == property) {
481 *val = scrtc->hw_funcs->is_support_smbl(crtc->index);
482 return 0;
483 }
484
485 return -1;
486 }
487
sunxi_crtc_atomic_enable(struct drm_crtc * crtc,struct drm_crtc_state * old_state)488 static void sunxi_crtc_atomic_enable(struct drm_crtc *crtc,
489 struct drm_crtc_state *old_state)
490 {
491 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
492 struct drm_crtc_state *new_state = crtc->state;
493 struct sunxi_drm_connector *sconn;
494 struct drm_mode_modeinfo modeinfo;
495 int crtc_id, enc_id = 0, i;
496
497 struct disp_manager_data config;
498 struct disp_manager_info *info = &config.config;
499 struct sunxi_de_funcs *hw_funcs = scrtc->hw_funcs;
500
501 #ifdef CONFIG_VIDEO_SUNXI_CAR_REVERSE
502 if (sunxi_drm_get_force_plane_en())
503 return;
504 #endif
505
506 DRM_DEBUG_DRIVER("[SUNXI-CRTC]%s\n", __func__);
507 if (scrtc->enabled) {
508 DRM_INFO("[SUNXI-CRTC]Warn: crtc has been enable,"
509 "do NOT enable again\n");
510 return;
511 }
512
513 if ((!new_state->enable) || (!new_state->active)) {
514 DRM_INFO("Warn: DRM do NOT want to enable or active crtc%d,"
515 " so can NOT be enabled\n", scrtc->crtc_id);
516 return;
517 }
518
519 memset(&config, 0, sizeof(struct disp_manager_data));
520 crtc_id = drm_crtc_index(new_state->crtc);
521
522 //sunxi_crtc_state_dump(new_state);
523
524 drm_property_blob_get(new_state->mode_blob);
525 memcpy(&modeinfo, new_state->mode_blob->data,
526 new_state->mode_blob->length);
527 drm_property_blob_put(new_state->mode_blob);
528
529 config.flag = MANAGER_ALL_DIRTY;
530 info->size.x = crtc->x;
531 info->size.y = crtc->y;
532 info->size.width = modeinfo.hdisplay;
533 info->size.height = modeinfo.vdisplay;
534
535 /*check which connector will be attached to this crtc*/
536 for (i = 0; i < sunxi_drm_connector_get_count(); i++) {
537 if ((new_state->connector_mask >> i) & 0x1)
538 break;
539 }
540
541 sconn = sunxi_drm_connector_get_connector(i);
542 if (!sconn) {
543 DRM_ERROR("Get sunxi connector:%d failed!\n", i);
544 return;
545 }
546
547 for (i = 0; i < sunxi_drm_encoder_get_count(); i++) {
548 if ((new_state->encoder_mask >> i) & 0x1) {
549 enc_id = i;
550 break;
551 }
552 }
553
554 info->color_space = DISP_BT601_F;
555
556 if (sconn->get_work_mode) {
557 struct sunxi_connector_work_mode conn_work_mode;
558
559 sconn->get_work_mode(sconn, &conn_work_mode);
560 info->cs = conn_work_mode.color_fmt;
561 } else {
562 info->cs = DISP_CSC_TYPE_RGB;
563 }
564
565 if (info->cs == DISP_CSC_TYPE_RGB)
566 info->color_range = DISP_COLOR_RANGE_0_255;
567 else
568 info->color_range = DISP_COLOR_RANGE_16_235;
569
570 //info->conn_type = sconn->type;
571
572 info->enable = true;
573 info->disp_device = crtc_id;
574
575 info->hwdev_index = enc_id;
576
577 info->blank = false;
578 info->de_freq = hw_funcs->get_freq(crtc_id);
579 info->device_fps = modeinfo.vrefresh;
580 info->eotf = DISP_EOTF_GAMMA22;
581 info->data_bits = DISP_DATA_8BITS;
582
583 /*DRM_INFO("%s de_freq:%u fps:%u\n", __func__,
584 info->de_freq, info->fps);
585 */
586
587 if (hw_funcs->enable(crtc_id, &config) < 0)
588 DRM_ERROR("de_al_mgr_apply FAILED\n");
589 else
590 DRM_INFO("%s success\n", __func__);
591
592 if (hw_funcs->is_use_irq(crtc_id)) {
593 if (scrtc->irq_register(scrtc,
594 hw_funcs->get_irq_no(crtc_id)) < 0) {
595 DRM_ERROR("sunxi_drm_crtc_irq_register failed\n");
596 return;
597 }
598 }
599 scrtc->enabled = true;
600 drm_crtc_vblank_on(crtc);
601 }
602
sunxi_crtc_sw_enable(struct sunxi_drm_crtc * scrtc)603 static void sunxi_crtc_sw_enable(struct sunxi_drm_crtc *scrtc)
604 {
605 int crtc_id;
606 struct disp_manager_data config;
607 struct drm_display_mode *mode;
608 struct disp_manager_info *info = &config.config;
609 struct drm_crtc *crtc = &scrtc->crtc;
610 struct sunxi_drm_connector *sconn;
611 struct drm_encoder *encoder;
612 bool find = false;
613 struct sunxi_de_funcs *hw_funcs = scrtc->hw_funcs;
614
615 memset(&config, 0, sizeof(struct disp_manager_data));
616 crtc_id = drm_crtc_index(crtc);
617
618 /*In general, bootlogo is output through connector 0*/
619 sconn = sunxi_drm_connector_get_connector(0);
620 if (!sconn) {
621 DRM_ERROR("Get sunxi connector 0 failed!\n");
622 return;
623 }
624
625 if (!crtc->state) {
626 DRM_ERROR("crtc:%d has no state\n", crtc_id);
627 return;
628 }
629 mode = &crtc->state->mode;
630
631 config.flag = MANAGER_ALL_DIRTY;
632 info->size.x = crtc->x;
633 info->size.y = crtc->y;
634 info->size.width = mode->hdisplay;
635 info->size.height = mode->vdisplay;
636
637 info->color_space = DISP_BT601_F;
638
639 if (sconn->get_work_mode) {
640 struct sunxi_connector_work_mode conn_work_mode;
641
642 sconn->get_work_mode(sconn, &conn_work_mode);
643 info->cs = conn_work_mode.color_fmt;
644 } else {
645 info->cs = DISP_CSC_TYPE_RGB;
646 }
647
648 if (info->cs == DISP_CSC_TYPE_RGB)
649 info->color_range = DISP_COLOR_RANGE_0_255;
650 else
651 info->color_range = DISP_COLOR_RANGE_16_235;
652
653 //info->conn_type = sconn->type;
654
655 info->enable = true;
656 info->disp_device = crtc_id;
657
658 drm_for_each_encoder(encoder, crtc->dev) {
659 if (encoder->crtc == crtc) {
660 find = true;
661 break;
662 }
663 }
664
665 if (!find) {
666 DRM_ERROR("crtc:%d has NO attaching encoder!\n", crtc->index);
667 return;
668 }
669
670 info->hwdev_index = encoder->index;
671
672 info->blank = false;
673 info->de_freq = hw_funcs->get_freq(crtc_id);
674 //info->device_fps = mode->vrefresh;
675 info->eotf = DISP_EOTF_GAMMA22;
676 info->data_bits = DISP_DATA_8BITS;
677
678 if (hw_funcs->enable(crtc_id, &config) < 0)
679 DRM_ERROR("de_al_mgr_apply FAILED\n");
680 else
681 DRM_INFO("%s success\n", __func__);
682
683 if (hw_funcs->is_use_irq(crtc_id)) {
684 if (scrtc->irq_register(scrtc,
685 hw_funcs->get_irq_no(crtc_id)) < 0) {
686 DRM_ERROR("sunxi_drm_crtc_irq_register failed\n");
687 return;
688 }
689 }
690 scrtc->enabled = true;
691 }
692
sunxi_crtc_atomic_disable(struct drm_crtc * crtc,struct drm_crtc_state * old_state)693 static void sunxi_crtc_atomic_disable(struct drm_crtc *crtc,
694 struct drm_crtc_state *old_state)
695
696 {
697 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
698 struct drm_crtc_state *new_state = crtc->state;
699 struct disp_manager_data config;
700 struct disp_manager_info *info = &config.config;
701 int crtc_id;
702 struct sunxi_de_funcs *hw_funcs = scrtc->hw_funcs;
703
704 DRM_INFO("[SUNXI-CRTC]%s\n", __func__);
705 drm_crtc_vblank_off(crtc);
706 if (!scrtc->enabled) {
707 DRM_ERROR("%s: crtc has been disable\n", __func__);
708 return;
709 }
710
711 memset(&config, 0, sizeof(struct disp_manager_data));
712 crtc_id = drm_crtc_index(new_state->crtc);
713 scrtc->enabled = false;
714
715 if (hw_funcs->is_use_irq(crtc_id))
716 scrtc->irq_unregister(scrtc, hw_funcs->get_irq_no(crtc_id));
717
718 config.flag = MANAGER_ALL_DIRTY;
719 info->enable = false;
720 info->blank = true;
721
722 hw_funcs->disable(crtc_id, &config);
723
724 if (crtc->state->event && !crtc->state->active) {
725 spin_lock_irq(&crtc->dev->event_lock);
726 drm_crtc_send_vblank_event(crtc, crtc->state->event);
727 spin_unlock_irq(&crtc->dev->event_lock);
728
729 crtc->state->event = NULL;
730 }
731
732 return;
733 }
734
sunxi_crtc_atomic_begin(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)735 static void sunxi_crtc_atomic_begin(struct drm_crtc *crtc,
736 struct drm_crtc_state *old_crtc_state)
737 {
738 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
739 struct drm_device *dev = crtc->dev;
740 unsigned long flags;
741
742 DRM_DEBUG_DRIVER("[SUNXI-CRTC]%s\n", __func__);
743
744 atomic_set(&scrtc->update, 0);
745
746 if (crtc->state->event) {
747 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
748
749 spin_lock_irqsave(&dev->event_lock, flags);
750 scrtc->event = crtc->state->event;
751 spin_unlock_irqrestore(&dev->event_lock, flags);
752 crtc->state->event = NULL;
753 }
754
755 return;
756 }
757
sunxi_crtc_atomic_flush(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)758 static void sunxi_crtc_atomic_flush(struct drm_crtc *crtc,
759 struct drm_crtc_state *old_crtc_state)
760 {
761 struct sunxi_drm_crtc *scrtc = to_sunxi_crtc(crtc);
762 struct drm_pending_vblank_event *event = crtc->state->event;
763
764 DRM_DEBUG_DRIVER("[SUNXI-CRTC]%s\n", __func__);
765 if (event) {
766 crtc->state->event = NULL;
767
768 spin_lock_irq(&crtc->dev->event_lock);
769 if (drm_crtc_vblank_get(crtc) == 0)
770 drm_crtc_arm_vblank_event(crtc, event);
771 else
772 drm_crtc_send_vblank_event(crtc, event);
773 spin_unlock_irq(&crtc->dev->event_lock);
774 }
775
776 atomic_set(&scrtc->update, 1);
777
778 return;
779 }
780
sunxi_drm_crtc_enable_vblank(struct drm_crtc * crtc)781 int sunxi_drm_crtc_enable_vblank(struct drm_crtc *crtc)
782 {
783 return 0;
784 }
785
786 static const struct drm_crtc_funcs sunxi_crtc_funcs = {
787 .set_config = drm_atomic_helper_set_config,
788 .page_flip = drm_atomic_helper_page_flip,
789 .destroy = sunxi_crtc_destroy,
790 .reset = drm_atomic_helper_crtc_reset,
791 .atomic_get_property = sunxi_crtc_atomic_get_property,
792 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
793 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
794 .enable_vblank = sunxi_drm_crtc_enable_vblank,
795 };
796
797 static const struct drm_crtc_helper_funcs sunxi_crtc_helper_funcs = {
798 .atomic_enable = sunxi_crtc_atomic_enable,
799 .atomic_disable = sunxi_crtc_atomic_disable,
800 //.atomic_begin = sunxi_crtc_atomic_begin,
801 .atomic_flush = sunxi_crtc_atomic_flush,
802 };
803
804
805 /*init all of the crtcs*/
sunxi_drm_crtc_init(struct drm_device * dev)806 int sunxi_drm_crtc_init(struct drm_device *dev)
807 {
808 int i, j, ret, max_crtc, max_plane;
809
810 int max_vi_layers;
811 struct sunxi_de_funcs *hw_funcs;
812
813 /*The max counts of crtc is decided by connector counts*/
814 max_crtc = sunxi_drm_get_connector_count();
815 if (!max_crtc)
816 max_crtc = 1; /*There must be at least one crtc*/
817
818 sunxi_crtc = kzalloc(
819 max_crtc * sizeof(struct sunxi_drm_crtc), GFP_KERNEL);
820 if (!sunxi_crtc) {
821 DRM_ERROR("can NOT allocate memory for sunxi_crtc\n");
822 goto crtc_err;
823 }
824 sunxi_crtc_cnt = max_crtc;
825
826 for (i = 0; i < max_crtc; i++) {
827 sunxi_crtc[i].crtc_id = i;
828 mutex_init(&sunxi_crtc[i].update_reg_lock);
829
830 hw_funcs = sunxi_de_get_funcs(i);
831 sunxi_crtc[i].hw_funcs = hw_funcs;
832
833 /*init planes of crtc*/
834 max_plane = hw_funcs->get_layer_count(i);
835 sunxi_crtc[i].plane_num = max_plane;
836 sunxi_crtc[i].plane = kzalloc(max_plane
837 * sizeof(struct sunxi_drm_plane),
838 GFP_KERNEL);
839 if (!sunxi_crtc[i].plane) {
840 DRM_ERROR("can NOT allocate mem for planes of "
841 "crtc:%d\n", i);
842 goto crtc_err;
843 }
844
845 max_vi_layers = hw_funcs->get_vi_layer_count(i);
846 sunxi_crtc[i].overlay_plane_num = max_vi_layers;
847
848 for (j = 0; j < max_plane; j++) {
849 /*check if it is the first ui layer*/
850 if ((j - max_vi_layers) == 0) {
851 ret = sunxi_drm_plane_init(dev,
852 &sunxi_crtc[i].plane[j], i, j,
853 DRM_PLANE_TYPE_PRIMARY);
854 } else {
855 ret = sunxi_drm_plane_init(dev,
856 &sunxi_crtc[i].plane[j],
857 i, j, DRM_PLANE_TYPE_OVERLAY);
858 }
859
860 if (ret < 0) {
861 DRM_ERROR("sunxi crtc:%d plane:%d init failed",
862 i, j);
863 goto crtc_err;
864 }
865 DRM_DEBUG_DRIVER("INIT crtc:%d plane:%d success\n", i, j);
866 }
867
868 /*init curtain crtc with a default primary plane*/
869 ret = drm_crtc_init_with_planes(dev, &sunxi_crtc[i].crtc,
870 &sunxi_crtc[i].plane[max_vi_layers].plane,
871 NULL, &sunxi_crtc_funcs, "sunxi-crtc%d", i);
872 if (ret < 0) {
873 DRM_ERROR("drm_crtc_init_with_planes failed\n");
874 goto crtc_err;
875 }
876
877 drm_crtc_helper_add(&sunxi_crtc[i].crtc,
878 &sunxi_crtc_helper_funcs);
879
880 sunxi_crtc_reset(&sunxi_crtc[i].crtc);
881
882 sunxi_crtc[i].encoder_is_supported = sunxi_crtc_encoder_is_supported;
883 sunxi_crtc[i].is_in_use = sunxi_drm_crtc_in_use;
884 sunxi_crtc[i].sw_enable = sunxi_crtc_sw_enable;
885 sunxi_crtc[i].irq_register = sunxi_drm_crtc_irq_register;
886 sunxi_crtc[i].irq_unregister = sunxi_drm_crtc_irq_unregister;
887
888 sunxi_crtc[i].support_smbl =
889 drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE,
890 "support_smbl");
891 if (!sunxi_crtc[i].support_smbl)
892 return -ENOMEM;
893
894 DRM_DEBUG_DRIVER("INIT crtc:%d success\n", i);
895 }
896
897 return 0;
898
899 crtc_err:
900
901 if (sunxi_crtc) {
902 for (i = 0; i < sunxi_crtc_cnt; i++) {
903 drm_crtc_cleanup(&sunxi_crtc[i].crtc);
904
905 max_plane = sunxi_crtc[i].plane_num;
906 for (j = 0; j < max_plane; j++)
907 drm_plane_cleanup(&sunxi_crtc[i].plane[j].plane);
908 kfree(sunxi_crtc[i].plane);
909 }
910 kfree(sunxi_crtc);
911 }
912 DRM_ERROR("crtc init failed\n");
913 return -1;
914 }
915
916 /*destroy all of the crtcs*/
sunxi_drm_crtc_exit(struct drm_device * dev)917 void sunxi_drm_crtc_exit(struct drm_device *dev)
918 {
919 int i, j, max_plane;
920
921 if (sunxi_crtc) {
922 for (i = 0; i < sunxi_crtc_cnt; i++) {
923 if (!sunxi_crtc)
924 break;
925 drm_crtc_cleanup(&sunxi_crtc[i].crtc);
926
927 max_plane = sunxi_crtc[i].plane_num;
928 for (j = 0; j < max_plane; j++)
929 drm_plane_cleanup(&sunxi_crtc[i].plane[j].plane);
930
931 kfree(sunxi_crtc[i].plane);
932 sunxi_crtc[i].plane = NULL;
933 }
934
935 kfree(sunxi_crtc);
936 sunxi_crtc = NULL;
937 }
938 }
939
940 /*destroy curtain crtc*/
sunxi_drm_crtc_destroy(struct drm_crtc * drm_crtc)941 void sunxi_drm_crtc_destroy(struct drm_crtc *drm_crtc)
942 {
943 int j, max_plane;
944 struct sunxi_drm_crtc *crtc = to_sunxi_crtc(drm_crtc);
945
946 drm_crtc_cleanup(drm_crtc);
947
948 max_plane = crtc->plane_num;
949 for (j = 0; j < max_plane; j++)
950 drm_plane_cleanup(&crtc->plane[j].plane);
951
952 kfree(crtc->plane);
953 crtc->plane = NULL;
954 }
955