2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors: Joonyoung Shim <jy0922.shim@samsung.com>
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.
14 #include <drm/exynos_drm.h>
15 #include <drm/drm_plane_helper.h>
16 #include <drm/drm_atomic_helper.h>
17 #include "exynos_drm_drv.h"
18 #include "exynos_drm_crtc.h"
19 #include "exynos_drm_fb.h"
20 #include "exynos_drm_gem.h"
21 #include "exynos_drm_plane.h"
24 * This function is to get X or Y size shown via screen. This needs length and
25 * start position of CRTC.
28 * CRTC ----------------
31 * There are six cases from a to f.
33 * <----- SCREEN ----->
35 * ----------|------------------|----------
39 * c --------------------------
44 static int exynos_plane_get_size(int start
, unsigned length
, unsigned last
)
46 int end
= start
+ length
;
51 size
= min_t(unsigned, end
, last
);
52 } else if (start
<= last
) {
53 size
= min_t(unsigned, last
- start
, length
);
59 static void exynos_plane_mode_set(struct drm_plane
*plane
,
60 struct drm_crtc
*crtc
,
61 struct drm_framebuffer
*fb
,
62 int crtc_x
, int crtc_y
,
63 unsigned int crtc_w
, unsigned int crtc_h
,
64 uint32_t src_x
, uint32_t src_y
,
65 uint32_t src_w
, uint32_t src_h
)
67 struct exynos_drm_plane
*exynos_plane
= to_exynos_plane(plane
);
68 struct drm_display_mode
*mode
= &crtc
->state
->adjusted_mode
;
69 unsigned int actual_w
;
70 unsigned int actual_h
;
72 actual_w
= exynos_plane_get_size(crtc_x
, crtc_w
, mode
->hdisplay
);
73 actual_h
= exynos_plane_get_size(crtc_y
, crtc_h
, mode
->vdisplay
);
88 exynos_plane
->h_ratio
= (src_w
<< 16) / crtc_w
;
89 exynos_plane
->v_ratio
= (src_h
<< 16) / crtc_h
;
91 /* set drm framebuffer data. */
92 exynos_plane
->src_x
= src_x
;
93 exynos_plane
->src_y
= src_y
;
94 exynos_plane
->src_w
= (actual_w
* exynos_plane
->h_ratio
) >> 16;
95 exynos_plane
->src_h
= (actual_h
* exynos_plane
->v_ratio
) >> 16;
97 /* set plane range to be displayed. */
98 exynos_plane
->crtc_x
= crtc_x
;
99 exynos_plane
->crtc_y
= crtc_y
;
100 exynos_plane
->crtc_w
= actual_w
;
101 exynos_plane
->crtc_h
= actual_h
;
103 DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)",
104 exynos_plane
->crtc_x
, exynos_plane
->crtc_y
,
105 exynos_plane
->crtc_w
, exynos_plane
->crtc_h
);
110 static struct drm_plane_funcs exynos_plane_funcs
= {
111 .update_plane
= drm_atomic_helper_update_plane
,
112 .disable_plane
= drm_atomic_helper_disable_plane
,
113 .destroy
= drm_plane_cleanup
,
114 .reset
= drm_atomic_helper_plane_reset
,
115 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
116 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
119 static int exynos_plane_atomic_check(struct drm_plane
*plane
,
120 struct drm_plane_state
*state
)
122 struct exynos_drm_plane
*exynos_plane
= to_exynos_plane(plane
);
129 nr
= drm_format_num_planes(state
->fb
->pixel_format
);
130 for (i
= 0; i
< nr
; i
++) {
131 struct exynos_drm_gem
*exynos_gem
=
132 exynos_drm_fb_gem(state
->fb
, i
);
134 DRM_DEBUG_KMS("gem object is null\n");
138 exynos_plane
->dma_addr
[i
] = exynos_gem
->dma_addr
+
139 state
->fb
->offsets
[i
];
141 DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
142 i
, (unsigned long)exynos_plane
->dma_addr
[i
]);
148 static void exynos_plane_atomic_update(struct drm_plane
*plane
,
149 struct drm_plane_state
*old_state
)
151 struct drm_plane_state
*state
= plane
->state
;
152 struct exynos_drm_crtc
*exynos_crtc
= to_exynos_crtc(state
->crtc
);
153 struct exynos_drm_plane
*exynos_plane
= to_exynos_plane(plane
);
158 exynos_plane_mode_set(plane
, state
->crtc
, state
->fb
,
159 state
->crtc_x
, state
->crtc_y
,
160 state
->crtc_w
, state
->crtc_h
,
161 state
->src_x
>> 16, state
->src_y
>> 16,
162 state
->src_w
>> 16, state
->src_h
>> 16);
164 exynos_plane
->pending_fb
= state
->fb
;
166 if (exynos_crtc
->ops
->update_plane
)
167 exynos_crtc
->ops
->update_plane(exynos_crtc
, exynos_plane
);
170 static void exynos_plane_atomic_disable(struct drm_plane
*plane
,
171 struct drm_plane_state
*old_state
)
173 struct exynos_drm_plane
*exynos_plane
= to_exynos_plane(plane
);
174 struct exynos_drm_crtc
*exynos_crtc
= to_exynos_crtc(old_state
->crtc
);
176 if (!old_state
->crtc
)
179 if (exynos_crtc
->ops
->disable_plane
)
180 exynos_crtc
->ops
->disable_plane(exynos_crtc
,
184 static const struct drm_plane_helper_funcs plane_helper_funcs
= {
185 .atomic_check
= exynos_plane_atomic_check
,
186 .atomic_update
= exynos_plane_atomic_update
,
187 .atomic_disable
= exynos_plane_atomic_disable
,
190 static void exynos_plane_attach_zpos_property(struct drm_plane
*plane
,
193 struct drm_device
*dev
= plane
->dev
;
194 struct exynos_drm_private
*dev_priv
= dev
->dev_private
;
195 struct drm_property
*prop
;
197 prop
= dev_priv
->plane_zpos_property
;
199 prop
= drm_property_create_range(dev
, DRM_MODE_PROP_IMMUTABLE
,
200 "zpos", 0, MAX_PLANE
- 1);
204 dev_priv
->plane_zpos_property
= prop
;
207 drm_object_attach_property(&plane
->base
, prop
, zpos
);
210 enum drm_plane_type
exynos_plane_get_type(unsigned int zpos
,
211 unsigned int cursor_win
)
213 if (zpos
== DEFAULT_WIN
)
214 return DRM_PLANE_TYPE_PRIMARY
;
215 else if (zpos
== cursor_win
)
216 return DRM_PLANE_TYPE_CURSOR
;
218 return DRM_PLANE_TYPE_OVERLAY
;
221 int exynos_plane_init(struct drm_device
*dev
,
222 struct exynos_drm_plane
*exynos_plane
,
223 unsigned long possible_crtcs
, enum drm_plane_type type
,
224 const uint32_t *formats
, unsigned int fcount
,
229 err
= drm_universal_plane_init(dev
, &exynos_plane
->base
, possible_crtcs
,
230 &exynos_plane_funcs
, formats
, fcount
,
233 DRM_ERROR("failed to initialize plane\n");
237 drm_plane_helper_add(&exynos_plane
->base
, &plane_helper_funcs
);
239 exynos_plane
->zpos
= zpos
;
241 if (type
== DRM_PLANE_TYPE_OVERLAY
)
242 exynos_plane_attach_zpos_property(&exynos_plane
->base
, zpos
);