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 "exynos_drm_drv.h"
17 #include "exynos_drm_crtc.h"
18 #include "exynos_drm_fb.h"
19 #include "exynos_drm_gem.h"
20 #include "exynos_drm_plane.h"
22 static const uint32_t formats
[] = {
29 * This function is to get X or Y size shown via screen. This needs length and
30 * start position of CRTC.
33 * CRTC ----------------
36 * There are six cases from a to f.
38 * <----- SCREEN ----->
40 * ----------|------------------|----------
44 * c --------------------------
49 static int exynos_plane_get_size(int start
, unsigned length
, unsigned last
)
51 int end
= start
+ length
;
56 size
= min_t(unsigned, end
, last
);
57 } else if (start
<= last
) {
58 size
= min_t(unsigned, last
- start
, length
);
64 int exynos_check_plane(struct drm_plane
*plane
, struct drm_framebuffer
*fb
)
66 struct exynos_drm_plane
*exynos_plane
= to_exynos_plane(plane
);
73 nr
= exynos_drm_fb_get_buf_cnt(fb
);
74 for (i
= 0; i
< nr
; i
++) {
75 struct exynos_drm_gem_buf
*buffer
= exynos_drm_fb_buffer(fb
, i
);
78 DRM_DEBUG_KMS("buffer is null\n");
82 exynos_plane
->dma_addr
[i
] = buffer
->dma_addr
+ fb
->offsets
[i
];
84 DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
85 i
, (unsigned long)exynos_plane
->dma_addr
[i
]);
91 void exynos_plane_mode_set(struct drm_plane
*plane
, struct drm_crtc
*crtc
,
92 struct drm_framebuffer
*fb
, int crtc_x
, int crtc_y
,
93 unsigned int crtc_w
, unsigned int crtc_h
,
94 uint32_t src_x
, uint32_t src_y
,
95 uint32_t src_w
, uint32_t src_h
)
97 struct exynos_drm_plane
*exynos_plane
= to_exynos_plane(plane
);
98 struct drm_display_mode
*mode
= &crtc
->state
->adjusted_mode
;
99 unsigned int actual_w
;
100 unsigned int actual_h
;
102 actual_w
= exynos_plane_get_size(crtc_x
, crtc_w
, mode
->hdisplay
);
103 actual_h
= exynos_plane_get_size(crtc_y
, crtc_h
, mode
->vdisplay
);
118 exynos_plane
->h_ratio
= (src_w
<< 16) / crtc_w
;
119 exynos_plane
->v_ratio
= (src_h
<< 16) / crtc_h
;
121 /* set drm framebuffer data. */
122 exynos_plane
->src_x
= src_x
;
123 exynos_plane
->src_y
= src_y
;
124 exynos_plane
->src_width
= (actual_w
* exynos_plane
->h_ratio
) >> 16;
125 exynos_plane
->src_height
= (actual_h
* exynos_plane
->v_ratio
) >> 16;
126 exynos_plane
->fb_width
= fb
->width
;
127 exynos_plane
->fb_height
= fb
->height
;
128 exynos_plane
->bpp
= fb
->bits_per_pixel
;
129 exynos_plane
->pitch
= fb
->pitches
[0];
130 exynos_plane
->pixel_format
= fb
->pixel_format
;
132 /* set plane range to be displayed. */
133 exynos_plane
->crtc_x
= crtc_x
;
134 exynos_plane
->crtc_y
= crtc_y
;
135 exynos_plane
->crtc_width
= actual_w
;
136 exynos_plane
->crtc_height
= actual_h
;
138 /* set drm mode data. */
139 exynos_plane
->mode_width
= mode
->hdisplay
;
140 exynos_plane
->mode_height
= mode
->vdisplay
;
141 exynos_plane
->refresh
= mode
->vrefresh
;
142 exynos_plane
->scan_flag
= mode
->flags
;
144 DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)",
145 exynos_plane
->crtc_x
, exynos_plane
->crtc_y
,
146 exynos_plane
->crtc_width
, exynos_plane
->crtc_height
);
152 exynos_update_plane(struct drm_plane
*plane
, struct drm_crtc
*crtc
,
153 struct drm_framebuffer
*fb
, int crtc_x
, int crtc_y
,
154 unsigned int crtc_w
, unsigned int crtc_h
,
155 uint32_t src_x
, uint32_t src_y
,
156 uint32_t src_w
, uint32_t src_h
)
158 struct exynos_drm_crtc
*exynos_crtc
= to_exynos_crtc(crtc
);
159 struct exynos_drm_plane
*exynos_plane
= to_exynos_plane(plane
);
161 exynos_plane_mode_set(plane
, crtc
, fb
, crtc_x
, crtc_y
,
162 crtc_w
, crtc_h
, src_x
>> 16, src_y
>> 16,
163 src_w
>> 16, src_h
>> 16);
165 if (exynos_crtc
->ops
->win_commit
)
166 exynos_crtc
->ops
->win_commit(exynos_crtc
, exynos_plane
->zpos
);
169 static struct drm_plane_funcs exynos_plane_funcs
= {
170 .update_plane
= drm_plane_helper_update
,
171 .disable_plane
= drm_plane_helper_disable
,
172 .destroy
= drm_plane_cleanup
,
175 static int exynos_plane_atomic_check(struct drm_plane
*plane
,
176 struct drm_plane_state
*state
)
178 return exynos_check_plane(plane
, state
->fb
);
181 static void exynos_plane_atomic_update(struct drm_plane
*plane
,
182 struct drm_plane_state
*old_state
)
184 struct drm_plane_state
*state
= plane
->state
;
189 exynos_update_plane(plane
, state
->crtc
, state
->fb
,
190 state
->crtc_x
, state
->crtc_y
,
191 state
->crtc_w
, state
->crtc_h
,
192 state
->src_x
, state
->src_y
,
193 state
->src_w
, state
->src_h
);
196 static void exynos_plane_atomic_disable(struct drm_plane
*plane
,
197 struct drm_plane_state
*old_state
)
199 struct exynos_drm_plane
*exynos_plane
= to_exynos_plane(plane
);
200 struct exynos_drm_crtc
*exynos_crtc
= to_exynos_crtc(old_state
->crtc
);
202 if (!old_state
->crtc
)
205 if (exynos_crtc
->ops
->win_disable
)
206 exynos_crtc
->ops
->win_disable(exynos_crtc
,
210 static const struct drm_plane_helper_funcs plane_helper_funcs
= {
211 .atomic_check
= exynos_plane_atomic_check
,
212 .atomic_update
= exynos_plane_atomic_update
,
213 .atomic_disable
= exynos_plane_atomic_disable
,
216 static void exynos_plane_attach_zpos_property(struct drm_plane
*plane
,
219 struct drm_device
*dev
= plane
->dev
;
220 struct exynos_drm_private
*dev_priv
= dev
->dev_private
;
221 struct drm_property
*prop
;
223 prop
= dev_priv
->plane_zpos_property
;
225 prop
= drm_property_create_range(dev
, DRM_MODE_PROP_IMMUTABLE
,
226 "zpos", 0, MAX_PLANE
- 1);
230 dev_priv
->plane_zpos_property
= prop
;
233 drm_object_attach_property(&plane
->base
, prop
, zpos
);
236 int exynos_plane_init(struct drm_device
*dev
,
237 struct exynos_drm_plane
*exynos_plane
,
238 unsigned long possible_crtcs
, enum drm_plane_type type
,
243 err
= drm_universal_plane_init(dev
, &exynos_plane
->base
, possible_crtcs
,
244 &exynos_plane_funcs
, formats
,
245 ARRAY_SIZE(formats
), type
);
247 DRM_ERROR("failed to initialize plane\n");
251 drm_plane_helper_add(&exynos_plane
->base
, &plane_helper_funcs
);
253 exynos_plane
->zpos
= zpos
;
255 if (type
== DRM_PLANE_TYPE_OVERLAY
)
256 exynos_plane_attach_zpos_property(&exynos_plane
->base
, zpos
);