1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
4 * Author: Rob Clark <rob@ti.com>
7 #include <linux/dma-mapping.h>
9 #include <drm/drm_modeset_helper.h>
10 #include <drm/drm_fourcc.h>
11 #include <drm/drm_gem_framebuffer_helper.h>
13 #include "omap_dmm_tiler.h"
20 static const u32 formats
[] = {
22 DRM_FORMAT_RGB565
, /* RGB16-565 */
23 DRM_FORMAT_RGBX4444
, /* RGB12x-4444 */
24 DRM_FORMAT_XRGB4444
, /* xRGB12-4444 */
25 DRM_FORMAT_RGBA4444
, /* RGBA12-4444 */
26 DRM_FORMAT_ARGB4444
, /* ARGB16-4444 */
27 DRM_FORMAT_XRGB1555
, /* xRGB15-1555 */
28 DRM_FORMAT_ARGB1555
, /* ARGB16-1555 */
30 DRM_FORMAT_RGB888
, /* RGB24-888 */
32 DRM_FORMAT_RGBX8888
, /* RGBx24-8888 */
33 DRM_FORMAT_XRGB8888
, /* xRGB24-8888 */
34 DRM_FORMAT_RGBA8888
, /* RGBA32-8888 */
35 DRM_FORMAT_ARGB8888
, /* ARGB32-8888 */
42 /* per-plane info for the fb: */
47 #define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base)
49 struct omap_framebuffer
{
50 struct drm_framebuffer base
;
52 const struct drm_format_info
*format
;
53 struct plane planes
[2];
54 /* lock for pinning (pin_count and planes.dma_addr) */
58 static int omap_framebuffer_dirty(struct drm_framebuffer
*fb
,
59 struct drm_file
*file_priv
,
60 unsigned flags
, unsigned color
,
61 struct drm_clip_rect
*clips
,
64 struct drm_crtc
*crtc
;
66 drm_modeset_lock_all(fb
->dev
);
68 drm_for_each_crtc(crtc
, fb
->dev
)
69 omap_crtc_flush(crtc
);
71 drm_modeset_unlock_all(fb
->dev
);
76 static const struct drm_framebuffer_funcs omap_framebuffer_funcs
= {
77 .create_handle
= drm_gem_fb_create_handle
,
78 .dirty
= omap_framebuffer_dirty
,
79 .destroy
= drm_gem_fb_destroy
,
82 static u32
get_linear_addr(struct drm_framebuffer
*fb
,
83 const struct drm_format_info
*format
, int n
, int x
, int y
)
85 struct omap_framebuffer
*omap_fb
= to_omap_framebuffer(fb
);
86 struct plane
*plane
= &omap_fb
->planes
[n
];
89 offset
= fb
->offsets
[n
]
90 + (x
* format
->cpp
[n
] / (n
== 0 ? 1 : format
->hsub
))
91 + (y
* fb
->pitches
[n
] / (n
== 0 ? 1 : format
->vsub
));
93 return plane
->dma_addr
+ offset
;
96 bool omap_framebuffer_supports_rotation(struct drm_framebuffer
*fb
)
98 return omap_gem_flags(fb
->obj
[0]) & OMAP_BO_TILED_MASK
;
101 /* Note: DRM rotates counter-clockwise, TILER & DSS rotates clockwise */
102 static u32
drm_rotation_to_tiler(unsigned int drm_rot
)
106 switch (drm_rot
& DRM_MODE_ROTATE_MASK
) {
108 case DRM_MODE_ROTATE_0
:
111 case DRM_MODE_ROTATE_90
:
112 orient
= MASK_XY_FLIP
| MASK_X_INVERT
;
114 case DRM_MODE_ROTATE_180
:
115 orient
= MASK_X_INVERT
| MASK_Y_INVERT
;
117 case DRM_MODE_ROTATE_270
:
118 orient
= MASK_XY_FLIP
| MASK_Y_INVERT
;
122 if (drm_rot
& DRM_MODE_REFLECT_X
)
123 orient
^= MASK_X_INVERT
;
125 if (drm_rot
& DRM_MODE_REFLECT_Y
)
126 orient
^= MASK_Y_INVERT
;
131 /* update ovl info for scanout, handles cases of multi-planar fb's, etc.
133 void omap_framebuffer_update_scanout(struct drm_framebuffer
*fb
,
134 struct drm_plane_state
*state
, struct omap_overlay_info
*info
)
136 struct omap_framebuffer
*omap_fb
= to_omap_framebuffer(fb
);
137 const struct drm_format_info
*format
= omap_fb
->format
;
138 u32 x
, y
, orient
= 0;
140 info
->fourcc
= fb
->format
->format
;
142 info
->pos_x
= state
->crtc_x
;
143 info
->pos_y
= state
->crtc_y
;
144 info
->out_width
= state
->crtc_w
;
145 info
->out_height
= state
->crtc_h
;
146 info
->width
= state
->src_w
>> 16;
147 info
->height
= state
->src_h
>> 16;
149 /* DSS driver wants the w & h in rotated orientation */
150 if (drm_rotation_90_or_270(state
->rotation
))
151 swap(info
->width
, info
->height
);
153 x
= state
->src_x
>> 16;
154 y
= state
->src_y
>> 16;
156 if (omap_gem_flags(fb
->obj
[0]) & OMAP_BO_TILED_MASK
) {
157 u32 w
= state
->src_w
>> 16;
158 u32 h
= state
->src_h
>> 16;
160 orient
= drm_rotation_to_tiler(state
->rotation
);
163 * omap_gem_rotated_paddr() wants the x & y in tiler units.
164 * Usually tiler unit size is the same as the pixel size, except
165 * for YUV422 formats, for which the tiler unit size is 32 bits
166 * and pixel size is 16 bits.
168 if (fb
->format
->format
== DRM_FORMAT_UYVY
||
169 fb
->format
->format
== DRM_FORMAT_YUYV
) {
174 /* adjust x,y offset for invert: */
175 if (orient
& MASK_Y_INVERT
)
177 if (orient
& MASK_X_INVERT
)
180 /* Note: x and y are in TILER units, not pixels */
181 omap_gem_rotated_dma_addr(fb
->obj
[0], orient
, x
, y
,
183 info
->rotation_type
= OMAP_DSS_ROT_TILER
;
184 info
->rotation
= state
->rotation
?: DRM_MODE_ROTATE_0
;
185 /* Note: stride in TILER units, not pixels */
186 info
->screen_width
= omap_gem_tiled_stride(fb
->obj
[0], orient
);
188 switch (state
->rotation
& DRM_MODE_ROTATE_MASK
) {
190 case DRM_MODE_ROTATE_0
:
195 dev_warn(fb
->dev
->dev
,
196 "rotation '%d' ignored for non-tiled fb\n",
201 info
->paddr
= get_linear_addr(fb
, format
, 0, x
, y
);
202 info
->rotation_type
= OMAP_DSS_ROT_NONE
;
203 info
->rotation
= DRM_MODE_ROTATE_0
;
204 info
->screen_width
= fb
->pitches
[0];
207 /* convert to pixels: */
208 info
->screen_width
/= format
->cpp
[0];
210 if (fb
->format
->format
== DRM_FORMAT_NV12
) {
211 if (info
->rotation_type
== OMAP_DSS_ROT_TILER
) {
212 WARN_ON(!(omap_gem_flags(fb
->obj
[1]) & OMAP_BO_TILED_MASK
));
213 omap_gem_rotated_dma_addr(fb
->obj
[1], orient
, x
/2, y
/2,
216 info
->p_uv_addr
= get_linear_addr(fb
, format
, 1, x
, y
);
223 /* pin, prepare for scanout: */
224 int omap_framebuffer_pin(struct drm_framebuffer
*fb
)
226 struct omap_framebuffer
*omap_fb
= to_omap_framebuffer(fb
);
227 int ret
, i
, n
= fb
->format
->num_planes
;
229 mutex_lock(&omap_fb
->lock
);
231 if (omap_fb
->pin_count
> 0) {
232 omap_fb
->pin_count
++;
233 mutex_unlock(&omap_fb
->lock
);
237 for (i
= 0; i
< n
; i
++) {
238 struct plane
*plane
= &omap_fb
->planes
[i
];
239 ret
= omap_gem_pin(fb
->obj
[i
], &plane
->dma_addr
);
242 omap_gem_dma_sync_buffer(fb
->obj
[i
], DMA_TO_DEVICE
);
245 omap_fb
->pin_count
++;
247 mutex_unlock(&omap_fb
->lock
);
252 for (i
--; i
>= 0; i
--) {
253 struct plane
*plane
= &omap_fb
->planes
[i
];
254 omap_gem_unpin(fb
->obj
[i
]);
258 mutex_unlock(&omap_fb
->lock
);
263 /* unpin, no longer being scanned out: */
264 void omap_framebuffer_unpin(struct drm_framebuffer
*fb
)
266 struct omap_framebuffer
*omap_fb
= to_omap_framebuffer(fb
);
267 int i
, n
= fb
->format
->num_planes
;
269 mutex_lock(&omap_fb
->lock
);
271 omap_fb
->pin_count
--;
273 if (omap_fb
->pin_count
> 0) {
274 mutex_unlock(&omap_fb
->lock
);
278 for (i
= 0; i
< n
; i
++) {
279 struct plane
*plane
= &omap_fb
->planes
[i
];
280 omap_gem_unpin(fb
->obj
[i
]);
284 mutex_unlock(&omap_fb
->lock
);
287 #ifdef CONFIG_DEBUG_FS
288 void omap_framebuffer_describe(struct drm_framebuffer
*fb
, struct seq_file
*m
)
290 int i
, n
= fb
->format
->num_planes
;
292 seq_printf(m
, "fb: %dx%d@%4.4s\n", fb
->width
, fb
->height
,
293 (char *)&fb
->format
->format
);
295 for (i
= 0; i
< n
; i
++) {
296 seq_printf(m
, " %d: offset=%d pitch=%d, obj: ",
297 i
, fb
->offsets
[n
], fb
->pitches
[i
]);
298 omap_gem_describe(fb
->obj
[i
], m
);
303 struct drm_framebuffer
*omap_framebuffer_create(struct drm_device
*dev
,
304 struct drm_file
*file
, const struct drm_mode_fb_cmd2
*mode_cmd
)
306 const struct drm_format_info
*info
= drm_get_format_info(dev
,
308 unsigned int num_planes
= info
->num_planes
;
309 struct drm_gem_object
*bos
[4];
310 struct drm_framebuffer
*fb
;
313 for (i
= 0; i
< num_planes
; i
++) {
314 bos
[i
] = drm_gem_object_lookup(file
, mode_cmd
->handles
[i
]);
316 fb
= ERR_PTR(-ENOENT
);
321 fb
= omap_framebuffer_init(dev
, mode_cmd
, bos
);
329 drm_gem_object_put(bos
[i
]);
334 struct drm_framebuffer
*omap_framebuffer_init(struct drm_device
*dev
,
335 const struct drm_mode_fb_cmd2
*mode_cmd
, struct drm_gem_object
**bos
)
337 const struct drm_format_info
*format
= NULL
;
338 struct omap_framebuffer
*omap_fb
= NULL
;
339 struct drm_framebuffer
*fb
= NULL
;
340 unsigned int pitch
= mode_cmd
->pitches
[0];
343 DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
344 dev
, mode_cmd
, mode_cmd
->width
, mode_cmd
->height
,
345 (char *)&mode_cmd
->pixel_format
);
347 format
= drm_get_format_info(dev
, mode_cmd
);
349 for (i
= 0; i
< ARRAY_SIZE(formats
); i
++) {
350 if (formats
[i
] == mode_cmd
->pixel_format
)
354 if (!format
|| i
== ARRAY_SIZE(formats
)) {
355 dev_dbg(dev
->dev
, "unsupported pixel format: %4.4s\n",
356 (char *)&mode_cmd
->pixel_format
);
361 omap_fb
= kzalloc(sizeof(*omap_fb
), GFP_KERNEL
);
368 omap_fb
->format
= format
;
369 mutex_init(&omap_fb
->lock
);
372 * The code below assumes that no format use more than two planes, and
373 * that the two planes of multiplane formats need the same number of
376 if (format
->num_planes
== 2 && pitch
!= mode_cmd
->pitches
[1]) {
377 dev_dbg(dev
->dev
, "pitches differ between planes 0 and 1\n");
382 if (pitch
% format
->cpp
[0]) {
384 "buffer pitch (%u bytes) is not a multiple of pixel size (%u bytes)\n",
385 pitch
, format
->cpp
[0]);
390 for (i
= 0; i
< format
->num_planes
; i
++) {
391 struct plane
*plane
= &omap_fb
->planes
[i
];
392 unsigned int vsub
= i
== 0 ? 1 : format
->vsub
;
395 size
= pitch
* mode_cmd
->height
/ vsub
;
397 if (size
> omap_gem_mmap_size(bos
[i
]) - mode_cmd
->offsets
[i
]) {
399 "provided buffer object is too small! %zu < %d\n",
400 bos
[i
]->size
- mode_cmd
->offsets
[i
], size
);
409 drm_helper_mode_fill_fb_struct(dev
, fb
, mode_cmd
);
411 ret
= drm_framebuffer_init(dev
, fb
, &omap_framebuffer_funcs
);
413 dev_err(dev
->dev
, "framebuffer init failed: %d\n", ret
);
417 DBG("create: FB ID: %d (%p)", fb
->base
.id
, fb
);