drm/sti: GDP planes only support RGB formats
[deliverable/linux.git] / drivers / gpu / drm / sti / sti_gdp.c
CommitLineData
ba2d53fb
BG
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#include <linux/clk.h>
10#include <linux/dma-mapping.h>
11
29d1dc62
VA
12#include <drm/drm_fb_cma_helper.h>
13#include <drm/drm_gem_cma_helper.h>
14
d219673d 15#include "sti_compositor.h"
ba2d53fb 16#include "sti_gdp.h"
9e1f05b2 17#include "sti_plane.h"
ba2d53fb
BG
18#include "sti_vtg.h"
19
4af6b12a 20#define ALPHASWITCH BIT(6)
ba2d53fb 21#define ENA_COLOR_FILL BIT(8)
4af6b12a 22#define BIGNOTLITTLE BIT(23)
ba2d53fb
BG
23#define WAIT_NEXT_VSYNC BIT(31)
24
25/* GDP color formats */
26#define GDP_RGB565 0x00
27#define GDP_RGB888 0x01
28#define GDP_RGB888_32 0x02
8adb5776 29#define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH)
ba2d53fb
BG
30#define GDP_ARGB8565 0x04
31#define GDP_ARGB8888 0x05
29d1dc62 32#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
ba2d53fb
BG
33#define GDP_ARGB1555 0x06
34#define GDP_ARGB4444 0x07
ba2d53fb
BG
35
36#define GAM_GDP_CTL_OFFSET 0x00
37#define GAM_GDP_AGC_OFFSET 0x04
38#define GAM_GDP_VPO_OFFSET 0x0C
39#define GAM_GDP_VPS_OFFSET 0x10
40#define GAM_GDP_PML_OFFSET 0x14
41#define GAM_GDP_PMP_OFFSET 0x18
42#define GAM_GDP_SIZE_OFFSET 0x1C
43#define GAM_GDP_NVN_OFFSET 0x24
44#define GAM_GDP_KEY1_OFFSET 0x28
45#define GAM_GDP_KEY2_OFFSET 0x2C
46#define GAM_GDP_PPT_OFFSET 0x34
47#define GAM_GDP_CML_OFFSET 0x3C
48#define GAM_GDP_MST_OFFSET 0x68
49
50#define GAM_GDP_ALPHARANGE_255 BIT(5)
51#define GAM_GDP_AGC_FULL_RANGE 0x00808080
52#define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0))
53#define GAM_GDP_SIZE_MAX 0x7FF
54
29d1dc62
VA
55#define GDP_NODE_NB_BANK 2
56#define GDP_NODE_PER_FIELD 2
ba2d53fb
BG
57
58struct sti_gdp_node {
59 u32 gam_gdp_ctl;
60 u32 gam_gdp_agc;
61 u32 reserved1;
62 u32 gam_gdp_vpo;
63 u32 gam_gdp_vps;
64 u32 gam_gdp_pml;
65 u32 gam_gdp_pmp;
66 u32 gam_gdp_size;
67 u32 reserved2;
68 u32 gam_gdp_nvn;
69 u32 gam_gdp_key1;
70 u32 gam_gdp_key2;
71 u32 reserved3;
72 u32 gam_gdp_ppt;
73 u32 reserved4;
74 u32 gam_gdp_cml;
75};
76
77struct sti_gdp_node_list {
78 struct sti_gdp_node *top_field;
a51fe84d 79 dma_addr_t top_field_paddr;
ba2d53fb 80 struct sti_gdp_node *btm_field;
a51fe84d 81 dma_addr_t btm_field_paddr;
ba2d53fb
BG
82};
83
84/**
85 * STI GDP structure
86 *
871bcdfe
VA
87 * @sti_plane: sti_plane structure
88 * @dev: driver device
89 * @regs: gdp registers
ba2d53fb 90 * @clk_pix: pixel clock for the current gdp
5e03abc5
BG
91 * @clk_main_parent: gdp parent clock if main path used
92 * @clk_aux_parent: gdp parent clock if aux path used
ba2d53fb
BG
93 * @vtg_field_nb: callback for VTG FIELD (top or bottom) notification
94 * @is_curr_top: true if the current node processed is the top field
871bcdfe 95 * @node_list: array of node list
20c47601 96 * @vtg: registered vtg
ba2d53fb
BG
97 */
98struct sti_gdp {
871bcdfe
VA
99 struct sti_plane plane;
100 struct device *dev;
101 void __iomem *regs;
ba2d53fb 102 struct clk *clk_pix;
5e03abc5
BG
103 struct clk *clk_main_parent;
104 struct clk *clk_aux_parent;
ba2d53fb
BG
105 struct notifier_block vtg_field_nb;
106 bool is_curr_top;
107 struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK];
20c47601 108 struct sti_vtg *vtg;
ba2d53fb
BG
109};
110
871bcdfe 111#define to_sti_gdp(x) container_of(x, struct sti_gdp, plane)
ba2d53fb
BG
112
113static const uint32_t gdp_supported_formats[] = {
114 DRM_FORMAT_XRGB8888,
8adb5776 115 DRM_FORMAT_XBGR8888,
ba2d53fb 116 DRM_FORMAT_ARGB8888,
4af6b12a 117 DRM_FORMAT_ABGR8888,
ba2d53fb
BG
118 DRM_FORMAT_ARGB4444,
119 DRM_FORMAT_ARGB1555,
120 DRM_FORMAT_RGB565,
121 DRM_FORMAT_RGB888,
ba2d53fb
BG
122};
123
ba2d53fb
BG
124static int sti_gdp_fourcc2format(int fourcc)
125{
126 switch (fourcc) {
127 case DRM_FORMAT_XRGB8888:
128 return GDP_RGB888_32;
8adb5776
FD
129 case DRM_FORMAT_XBGR8888:
130 return GDP_XBGR8888;
ba2d53fb
BG
131 case DRM_FORMAT_ARGB8888:
132 return GDP_ARGB8888;
4af6b12a
BG
133 case DRM_FORMAT_ABGR8888:
134 return GDP_ABGR8888;
ba2d53fb
BG
135 case DRM_FORMAT_ARGB4444:
136 return GDP_ARGB4444;
137 case DRM_FORMAT_ARGB1555:
138 return GDP_ARGB1555;
139 case DRM_FORMAT_RGB565:
140 return GDP_RGB565;
141 case DRM_FORMAT_RGB888:
142 return GDP_RGB888;
ba2d53fb
BG
143 }
144 return -1;
145}
146
147static int sti_gdp_get_alpharange(int format)
148{
149 switch (format) {
150 case GDP_ARGB8565:
151 case GDP_ARGB8888:
4af6b12a 152 case GDP_ABGR8888:
ba2d53fb
BG
153 return GAM_GDP_ALPHARANGE_255;
154 }
155 return 0;
156}
157
158/**
159 * sti_gdp_get_free_nodes
29d1dc62 160 * @gdp: gdp pointer
ba2d53fb
BG
161 *
162 * Look for a GDP node list that is not currently read by the HW.
163 *
164 * RETURNS:
165 * Pointer to the free GDP node list
166 */
29d1dc62 167static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_gdp *gdp)
ba2d53fb
BG
168{
169 int hw_nvn;
ba2d53fb
BG
170 unsigned int i;
171
871bcdfe 172 hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
ba2d53fb
BG
173 if (!hw_nvn)
174 goto end;
175
ba2d53fb 176 for (i = 0; i < GDP_NODE_NB_BANK; i++)
a51fe84d
BG
177 if ((hw_nvn != gdp->node_list[i].btm_field_paddr) &&
178 (hw_nvn != gdp->node_list[i].top_field_paddr))
ba2d53fb
BG
179 return &gdp->node_list[i];
180
d219673d
BG
181 /* in hazardious cases restart with the first node */
182 DRM_ERROR("inconsistent NVN for %s: 0x%08X\n",
29d1dc62 183 sti_plane_to_str(&gdp->plane), hw_nvn);
d219673d 184
ba2d53fb
BG
185end:
186 return &gdp->node_list[0];
187}
188
189/**
190 * sti_gdp_get_current_nodes
29d1dc62 191 * @gdp: gdp pointer
ba2d53fb
BG
192 *
193 * Look for GDP nodes that are currently read by the HW.
194 *
195 * RETURNS:
196 * Pointer to the current GDP node list
197 */
198static
29d1dc62 199struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_gdp *gdp)
ba2d53fb
BG
200{
201 int hw_nvn;
ba2d53fb
BG
202 unsigned int i;
203
871bcdfe 204 hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
ba2d53fb
BG
205 if (!hw_nvn)
206 goto end;
207
ba2d53fb 208 for (i = 0; i < GDP_NODE_NB_BANK; i++)
a51fe84d
BG
209 if ((hw_nvn == gdp->node_list[i].btm_field_paddr) ||
210 (hw_nvn == gdp->node_list[i].top_field_paddr))
ba2d53fb
BG
211 return &gdp->node_list[i];
212
213end:
d219673d 214 DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n",
29d1dc62 215 hw_nvn, sti_plane_to_str(&gdp->plane));
d219673d 216
ba2d53fb
BG
217 return NULL;
218}
219
ba2d53fb 220/**
871bcdfe 221 * sti_gdp_disable
29d1dc62 222 * @gdp: gdp pointer
ba2d53fb
BG
223 *
224 * Disable a GDP.
ba2d53fb 225 */
29d1dc62 226static void sti_gdp_disable(struct sti_gdp *gdp)
ba2d53fb 227{
29d1dc62 228 unsigned int i;
d219673d 229
29d1dc62 230 DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&gdp->plane));
ba2d53fb
BG
231
232 /* Set the nodes as 'to be ignored on mixer' */
233 for (i = 0; i < GDP_NODE_NB_BANK; i++) {
234 gdp->node_list[i].top_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
235 gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
236 }
237
20c47601 238 if (sti_vtg_unregister_client(gdp->vtg, &gdp->vtg_field_nb))
d219673d
BG
239 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
240
ba2d53fb
BG
241 if (gdp->clk_pix)
242 clk_disable_unprepare(gdp->clk_pix);
243
29d1dc62 244 gdp->plane.status = STI_PLANE_DISABLED;
ba2d53fb
BG
245}
246
247/**
248 * sti_gdp_field_cb
249 * @nb: notifier block
250 * @event: event message
251 * @data: private data
252 *
253 * Handle VTG top field and bottom field event.
254 *
255 * RETURNS:
256 * 0 on success.
257 */
258int sti_gdp_field_cb(struct notifier_block *nb,
259 unsigned long event, void *data)
260{
261 struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb);
262
29d1dc62
VA
263 if (gdp->plane.status == STI_PLANE_FLUSHING) {
264 /* disable need to be synchronize on vsync event */
265 DRM_DEBUG_DRIVER("Vsync event received => disable %s\n",
266 sti_plane_to_str(&gdp->plane));
267
268 sti_gdp_disable(gdp);
269 }
270
ba2d53fb
BG
271 switch (event) {
272 case VTG_TOP_FIELD_EVENT:
273 gdp->is_curr_top = true;
274 break;
275 case VTG_BOTTOM_FIELD_EVENT:
276 gdp->is_curr_top = false;
277 break;
278 default:
279 DRM_ERROR("unsupported event: %lu\n", event);
280 break;
281 }
282
283 return 0;
284}
285
871bcdfe 286static void sti_gdp_init(struct sti_gdp *gdp)
ba2d53fb 287{
871bcdfe 288 struct device_node *np = gdp->dev->of_node;
a51fe84d 289 dma_addr_t dma_addr;
ba2d53fb
BG
290 void *base;
291 unsigned int i, size;
292
293 /* Allocate all the nodes within a single memory page */
294 size = sizeof(struct sti_gdp_node) *
295 GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK;
871bcdfe
VA
296 base = dma_alloc_writecombine(gdp->dev,
297 size, &dma_addr, GFP_KERNEL | GFP_DMA);
a51fe84d 298
ba2d53fb
BG
299 if (!base) {
300 DRM_ERROR("Failed to allocate memory for GDP node\n");
301 return;
302 }
303 memset(base, 0, size);
304
305 for (i = 0; i < GDP_NODE_NB_BANK; i++) {
a51fe84d 306 if (dma_addr & 0xF) {
ba2d53fb
BG
307 DRM_ERROR("Mem alignment failed\n");
308 return;
309 }
310 gdp->node_list[i].top_field = base;
a51fe84d
BG
311 gdp->node_list[i].top_field_paddr = dma_addr;
312
ba2d53fb
BG
313 DRM_DEBUG_DRIVER("node[%d].top_field=%p\n", i, base);
314 base += sizeof(struct sti_gdp_node);
a51fe84d 315 dma_addr += sizeof(struct sti_gdp_node);
ba2d53fb 316
a51fe84d 317 if (dma_addr & 0xF) {
ba2d53fb
BG
318 DRM_ERROR("Mem alignment failed\n");
319 return;
320 }
321 gdp->node_list[i].btm_field = base;
a51fe84d 322 gdp->node_list[i].btm_field_paddr = dma_addr;
ba2d53fb
BG
323 DRM_DEBUG_DRIVER("node[%d].btm_field=%p\n", i, base);
324 base += sizeof(struct sti_gdp_node);
a51fe84d 325 dma_addr += sizeof(struct sti_gdp_node);
ba2d53fb
BG
326 }
327
328 if (of_device_is_compatible(np, "st,stih407-compositor")) {
329 /* GDP of STiH407 chip have its own pixel clock */
330 char *clk_name;
331
871bcdfe 332 switch (gdp->plane.desc) {
ba2d53fb
BG
333 case STI_GDP_0:
334 clk_name = "pix_gdp1";
335 break;
336 case STI_GDP_1:
337 clk_name = "pix_gdp2";
338 break;
339 case STI_GDP_2:
340 clk_name = "pix_gdp3";
341 break;
342 case STI_GDP_3:
343 clk_name = "pix_gdp4";
344 break;
345 default:
346 DRM_ERROR("GDP id not recognized\n");
347 return;
348 }
349
871bcdfe 350 gdp->clk_pix = devm_clk_get(gdp->dev, clk_name);
ba2d53fb
BG
351 if (IS_ERR(gdp->clk_pix))
352 DRM_ERROR("Cannot get %s clock\n", clk_name);
5e03abc5 353
871bcdfe 354 gdp->clk_main_parent = devm_clk_get(gdp->dev, "main_parent");
5e03abc5
BG
355 if (IS_ERR(gdp->clk_main_parent))
356 DRM_ERROR("Cannot get main_parent clock\n");
357
871bcdfe 358 gdp->clk_aux_parent = devm_clk_get(gdp->dev, "aux_parent");
5e03abc5
BG
359 if (IS_ERR(gdp->clk_aux_parent))
360 DRM_ERROR("Cannot get aux_parent clock\n");
ba2d53fb
BG
361 }
362}
363
29d1dc62
VA
364static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
365 struct drm_plane_state *oldstate)
366{
367 struct drm_plane_state *state = drm_plane->state;
368 struct sti_plane *plane = to_sti_plane(drm_plane);
369 struct sti_gdp *gdp = to_sti_gdp(plane);
370 struct drm_crtc *crtc = state->crtc;
371 struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
372 struct drm_framebuffer *fb = state->fb;
373 bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
374 struct sti_mixer *mixer;
375 struct drm_display_mode *mode;
376 int dst_x, dst_y, dst_w, dst_h;
377 int src_x, src_y, src_w, src_h;
378 struct drm_gem_cma_object *cma_obj;
379 struct sti_gdp_node_list *list;
380 struct sti_gdp_node_list *curr_list;
381 struct sti_gdp_node *top_field, *btm_field;
382 u32 dma_updated_top;
383 u32 dma_updated_btm;
384 int format;
385 unsigned int depth, bpp;
386 u32 ydo, xdo, yds, xds;
387 int res;
388
389 /* Manage the case where crtc is null (disabled) */
390 if (!crtc)
391 return;
392
393 mixer = to_sti_mixer(crtc);
394 mode = &crtc->mode;
395 dst_x = state->crtc_x;
396 dst_y = state->crtc_y;
397 dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
398 dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
399 /* src_x are in 16.16 format */
400 src_x = state->src_x >> 16;
401 src_y = state->src_y >> 16;
402 src_w = state->src_w >> 16;
403 src_h = state->src_h >> 16;
404
405 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
406 crtc->base.id, sti_mixer_to_str(mixer),
407 drm_plane->base.id, sti_plane_to_str(plane));
408 DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
409 sti_plane_to_str(plane),
410 dst_w, dst_h, dst_x, dst_y,
411 src_w, src_h, src_x, src_y);
412
413 list = sti_gdp_get_free_nodes(gdp);
414 top_field = list->top_field;
415 btm_field = list->btm_field;
416
417 dev_dbg(gdp->dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
418 sti_plane_to_str(plane), top_field, btm_field);
419
420 /* build the top field */
421 top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
422 top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
423 format = sti_gdp_fourcc2format(fb->pixel_format);
424 if (format == -1) {
425 DRM_ERROR("Format not supported by GDP %.4s\n",
426 (char *)&fb->pixel_format);
427 return;
428 }
429 top_field->gam_gdp_ctl |= format;
430 top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
431 top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
432
433 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
434 if (!cma_obj) {
435 DRM_ERROR("Can't get CMA GEM object for fb\n");
436 return;
437 }
438
439 DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
440 (char *)&fb->pixel_format,
441 (unsigned long)cma_obj->paddr);
442
443 /* pixel memory location */
444 drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
445 top_field->gam_gdp_pml = (u32)cma_obj->paddr + fb->offsets[0];
446 top_field->gam_gdp_pml += src_x * (bpp >> 3);
447 top_field->gam_gdp_pml += src_y * fb->pitches[0];
448
449 /* input parameters */
450 top_field->gam_gdp_pmp = fb->pitches[0];
451 top_field->gam_gdp_size = clamp_val(src_h, 0, GAM_GDP_SIZE_MAX) << 16 |
452 clamp_val(src_w, 0, GAM_GDP_SIZE_MAX);
453
454 /* output parameters */
455 ydo = sti_vtg_get_line_number(*mode, dst_y);
456 yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
457 xdo = sti_vtg_get_pixel_number(*mode, dst_x);
458 xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1);
459 top_field->gam_gdp_vpo = (ydo << 16) | xdo;
460 top_field->gam_gdp_vps = (yds << 16) | xds;
461
462 /* Same content and chained together */
463 memcpy(btm_field, top_field, sizeof(*btm_field));
464 top_field->gam_gdp_nvn = list->btm_field_paddr;
465 btm_field->gam_gdp_nvn = list->top_field_paddr;
466
467 /* Interlaced mode */
468 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
469 btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
470 fb->pitches[0];
471
472 if (first_prepare) {
473 /* Register gdp callback */
20c47601 474 gdp->vtg = mixer->id == STI_MIXER_MAIN ?
475 compo->vtg_main : compo->vtg_aux;
476
477 if (sti_vtg_register_client(gdp->vtg == STI_MIXER_MAIN ?
29d1dc62 478 compo->vtg_main : compo->vtg_aux,
2388693e 479 &gdp->vtg_field_nb, crtc)) {
29d1dc62
VA
480 DRM_ERROR("Cannot register VTG notifier\n");
481 return;
482 }
483
484 /* Set and enable gdp clock */
485 if (gdp->clk_pix) {
486 struct clk *clkp;
487 int rate = mode->clock * 1000;
488
489 /* According to the mixer used, the gdp pixel clock
490 * should have a different parent clock. */
491 if (mixer->id == STI_MIXER_MAIN)
492 clkp = gdp->clk_main_parent;
493 else
494 clkp = gdp->clk_aux_parent;
495
496 if (clkp)
497 clk_set_parent(gdp->clk_pix, clkp);
498
499 res = clk_set_rate(gdp->clk_pix, rate);
500 if (res < 0) {
501 DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
502 rate);
503 return;
504 }
505
506 if (clk_prepare_enable(gdp->clk_pix)) {
507 DRM_ERROR("Failed to prepare/enable gdp\n");
508 return;
509 }
510 }
511 }
512
513 /* Update the NVN field of the 'right' field of the current GDP node
514 * (being used by the HW) with the address of the updated ('free') top
515 * field GDP node.
516 * - In interlaced mode the 'right' field is the bottom field as we
517 * update frames starting from their top field
518 * - In progressive mode, we update both bottom and top fields which
519 * are equal nodes.
520 * At the next VSYNC, the updated node list will be used by the HW.
521 */
522 curr_list = sti_gdp_get_current_nodes(gdp);
523 dma_updated_top = list->top_field_paddr;
524 dma_updated_btm = list->btm_field_paddr;
525
526 dev_dbg(gdp->dev, "Current NVN:0x%X\n",
527 readl(gdp->regs + GAM_GDP_NVN_OFFSET));
528 dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n",
529 (unsigned long)cma_obj->paddr,
530 readl(gdp->regs + GAM_GDP_PML_OFFSET));
531
532 if (!curr_list) {
533 /* First update or invalid node should directly write in the
534 * hw register */
535 DRM_DEBUG_DRIVER("%s first update (or invalid node)",
536 sti_plane_to_str(plane));
537
538 writel(gdp->is_curr_top ?
539 dma_updated_btm : dma_updated_top,
540 gdp->regs + GAM_GDP_NVN_OFFSET);
541 goto end;
542 }
543
544 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
545 if (gdp->is_curr_top) {
546 /* Do not update in the middle of the frame, but
547 * postpone the update after the bottom field has
548 * been displayed */
549 curr_list->btm_field->gam_gdp_nvn = dma_updated_top;
550 } else {
551 /* Direct update to avoid one frame delay */
552 writel(dma_updated_top,
553 gdp->regs + GAM_GDP_NVN_OFFSET);
554 }
555 } else {
556 /* Direct update for progressive to avoid one frame delay */
557 writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET);
558 }
559
560end:
561 plane->status = STI_PLANE_UPDATED;
562}
563
564static void sti_gdp_atomic_disable(struct drm_plane *drm_plane,
565 struct drm_plane_state *oldstate)
566{
567 struct sti_plane *plane = to_sti_plane(drm_plane);
568 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
569
570 if (!drm_plane->crtc) {
571 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
572 drm_plane->base.id);
573 return;
574 }
575
576 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
577 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
578 drm_plane->base.id, sti_plane_to_str(plane));
579
580 plane->status = STI_PLANE_DISABLING;
581}
582
583static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = {
584 .atomic_update = sti_gdp_atomic_update,
585 .atomic_disable = sti_gdp_atomic_disable,
ba2d53fb
BG
586};
587
29d1dc62
VA
588struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
589 struct device *dev, int desc,
590 void __iomem *baseaddr,
591 unsigned int possible_crtcs,
592 enum drm_plane_type type)
ba2d53fb
BG
593{
594 struct sti_gdp *gdp;
29d1dc62 595 int res;
ba2d53fb
BG
596
597 gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL);
598 if (!gdp) {
599 DRM_ERROR("Failed to allocate memory for GDP\n");
600 return NULL;
601 }
602
871bcdfe
VA
603 gdp->dev = dev;
604 gdp->regs = baseaddr;
605 gdp->plane.desc = desc;
29d1dc62 606 gdp->plane.status = STI_PLANE_DISABLED;
871bcdfe 607
ba2d53fb
BG
608 gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb;
609
871bcdfe
VA
610 sti_gdp_init(gdp);
611
29d1dc62
VA
612 res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane,
613 possible_crtcs,
614 &sti_plane_helpers_funcs,
615 gdp_supported_formats,
616 ARRAY_SIZE(gdp_supported_formats),
b0b3b795 617 type, NULL);
29d1dc62
VA
618 if (res) {
619 DRM_ERROR("Failed to initialize universal plane\n");
620 goto err;
621 }
622
623 drm_plane_helper_add(&gdp->plane.drm_plane, &sti_gdp_helpers_funcs);
624
625 sti_plane_init_property(&gdp->plane, type);
626
627 return &gdp->plane.drm_plane;
628
629err:
630 devm_kfree(dev, gdp);
631 return NULL;
ba2d53fb 632}
This page took 0.106908 seconds and 5 git commands to generate.