2019-05-27 14:55:06 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2012-07-02 22:37:47 +08:00
|
|
|
/*
|
|
|
|
* drm kms/fb cma (contiguous memory allocator) helper functions
|
|
|
|
*
|
2020-04-16 18:30:55 +08:00
|
|
|
* Copyright (C) 2012 Analog Devices Inc.
|
2012-07-02 22:37:47 +08:00
|
|
|
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
|
|
|
*
|
|
|
|
* Based on udl_fbdev.c
|
|
|
|
* Copyright (C) 2012 Red Hat
|
|
|
|
*/
|
|
|
|
|
2021-05-24 01:04:14 +08:00
|
|
|
#include <drm/drm_damage_helper.h>
|
2019-11-19 18:57:53 +08:00
|
|
|
#include <drm/drm_fb_cma_helper.h>
|
2019-01-14 20:10:59 +08:00
|
|
|
#include <drm/drm_fourcc.h>
|
2017-08-13 21:31:45 +08:00
|
|
|
#include <drm/drm_framebuffer.h>
|
2012-07-02 22:37:47 +08:00
|
|
|
#include <drm/drm_gem_cma_helper.h>
|
2017-08-13 21:31:45 +08:00
|
|
|
#include <drm/drm_gem_framebuffer_helper.h>
|
2019-01-14 20:10:59 +08:00
|
|
|
#include <drm/drm_plane.h>
|
2021-05-24 01:04:14 +08:00
|
|
|
#include <linux/dma-mapping.h>
|
2012-07-02 22:37:47 +08:00
|
|
|
#include <linux/module.h>
|
|
|
|
|
2016-04-28 23:18:35 +08:00
|
|
|
/**
|
|
|
|
* DOC: framebuffer cma helper functions
|
|
|
|
*
|
|
|
|
* Provides helper functions for creating a cma (contiguous memory allocator)
|
|
|
|
* backed framebuffer.
|
|
|
|
*
|
2017-09-24 20:26:25 +08:00
|
|
|
* drm_gem_fb_create() is used in the &drm_mode_config_funcs.fb_create
|
2016-05-12 00:09:18 +08:00
|
|
|
* callback function to create a cma backed framebuffer.
|
2016-04-28 23:18:35 +08:00
|
|
|
*/
|
|
|
|
|
2012-07-02 22:37:47 +08:00
|
|
|
/**
|
|
|
|
* drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer
|
|
|
|
* @fb: The framebuffer
|
|
|
|
* @plane: Which plane
|
|
|
|
*
|
|
|
|
* Return the CMA GEM object for given framebuffer.
|
|
|
|
*
|
|
|
|
* This function will usually be called from the CRTC callback functions.
|
|
|
|
*/
|
|
|
|
struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
|
2016-06-01 05:11:12 +08:00
|
|
|
unsigned int plane)
|
2012-07-02 22:37:47 +08:00
|
|
|
{
|
2017-08-13 21:31:45 +08:00
|
|
|
struct drm_gem_object *gem;
|
2012-07-02 22:37:47 +08:00
|
|
|
|
2017-08-13 21:31:45 +08:00
|
|
|
gem = drm_gem_fb_get_obj(fb, plane);
|
|
|
|
if (!gem)
|
2012-07-02 22:37:47 +08:00
|
|
|
return NULL;
|
|
|
|
|
2017-08-13 21:31:45 +08:00
|
|
|
return to_drm_gem_cma_obj(gem);
|
2012-07-02 22:37:47 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
|
|
|
|
|
2017-04-14 18:13:32 +08:00
|
|
|
/**
|
drm/fourcc: Add char_per_block, block_w and block_h in drm_format_info
For some pixel formats .cpp structure in drm_format info it's not
enough to describe the peculiarities of the pixel layout, for example
tiled formats or packed formats at bit level.
What's implemented here is to add three new members to drm_format_info
that could describe such formats:
- char_per_block[3]
- block_w[3]
- block_h[3]
char_per_block will be put in a union alongside cpp, for transparent
compatibility with the existing format descriptions.
Regarding, block_w and block_h they are intended to be used through
their equivalent getters drm_format_info_block_width /
drm_format_info_block_height, the reason of the getters is to abstract
the fact that for normal formats block_w and block_h will be unset/0,
but the methods will be returning 1.
Additionally, convenience function drm_format_info_min_pitch had been
added that computes the minimum required pitch for a given pixel
format and buffer width.
Using that the following drm core functions had been updated to
generically handle both block and non-block formats:
- drm_fb_cma_get_gem_addr: for block formats it will just return the
beginning of the block.
- framebuffer_check: Use the newly added drm_format_info_min_pitch.
- drm_gem_fb_create_with_funcs: Use the newly added
drm_format_info_min_pitch.
- In places where is not expecting to handle block formats, like fbdev
helpers I just added some warnings in case the block width/height
are greater than 1.
Changes since v3:
- Add helper function for computing the minimum required pitch.
- Improve/cleanup documentation
Changes since v8:
- Fixed build on 32bits arm architectures, with:
- return DIV_ROUND_UP((u64)buffer_width * info->char_per_block[plane],
+ return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
Reviewed-by: Brian Starkey <brian.starkey@arm.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181101170055.5433-1-alexandru-cosmin.gheorghe@arm.com
2018-11-02 01:02:05 +08:00
|
|
|
* drm_fb_cma_get_gem_addr() - Get physical address for framebuffer, for pixel
|
|
|
|
* formats where values are grouped in blocks this will get you the beginning of
|
|
|
|
* the block
|
2017-04-14 18:13:32 +08:00
|
|
|
* @fb: The framebuffer
|
|
|
|
* @state: Which state of drm plane
|
|
|
|
* @plane: Which plane
|
|
|
|
* Return the CMA GEM address for given framebuffer.
|
|
|
|
*
|
|
|
|
* This function will usually be called from the PLANE callback functions.
|
|
|
|
*/
|
|
|
|
dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
|
|
|
|
struct drm_plane_state *state,
|
|
|
|
unsigned int plane)
|
|
|
|
{
|
2017-08-13 21:31:45 +08:00
|
|
|
struct drm_gem_cma_object *obj;
|
2017-04-14 18:13:32 +08:00
|
|
|
dma_addr_t paddr;
|
2018-08-18 00:54:00 +08:00
|
|
|
u8 h_div = 1, v_div = 1;
|
drm/fourcc: Add char_per_block, block_w and block_h in drm_format_info
For some pixel formats .cpp structure in drm_format info it's not
enough to describe the peculiarities of the pixel layout, for example
tiled formats or packed formats at bit level.
What's implemented here is to add three new members to drm_format_info
that could describe such formats:
- char_per_block[3]
- block_w[3]
- block_h[3]
char_per_block will be put in a union alongside cpp, for transparent
compatibility with the existing format descriptions.
Regarding, block_w and block_h they are intended to be used through
their equivalent getters drm_format_info_block_width /
drm_format_info_block_height, the reason of the getters is to abstract
the fact that for normal formats block_w and block_h will be unset/0,
but the methods will be returning 1.
Additionally, convenience function drm_format_info_min_pitch had been
added that computes the minimum required pitch for a given pixel
format and buffer width.
Using that the following drm core functions had been updated to
generically handle both block and non-block formats:
- drm_fb_cma_get_gem_addr: for block formats it will just return the
beginning of the block.
- framebuffer_check: Use the newly added drm_format_info_min_pitch.
- drm_gem_fb_create_with_funcs: Use the newly added
drm_format_info_min_pitch.
- In places where is not expecting to handle block formats, like fbdev
helpers I just added some warnings in case the block width/height
are greater than 1.
Changes since v3:
- Add helper function for computing the minimum required pitch.
- Improve/cleanup documentation
Changes since v8:
- Fixed build on 32bits arm architectures, with:
- return DIV_ROUND_UP((u64)buffer_width * info->char_per_block[plane],
+ return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
Reviewed-by: Brian Starkey <brian.starkey@arm.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181101170055.5433-1-alexandru-cosmin.gheorghe@arm.com
2018-11-02 01:02:05 +08:00
|
|
|
u32 block_w = drm_format_info_block_width(fb->format, plane);
|
|
|
|
u32 block_h = drm_format_info_block_height(fb->format, plane);
|
|
|
|
u32 block_size = fb->format->char_per_block[plane];
|
|
|
|
u32 sample_x;
|
|
|
|
u32 sample_y;
|
|
|
|
u32 block_start_y;
|
|
|
|
u32 num_hblocks;
|
2017-04-14 18:13:32 +08:00
|
|
|
|
2017-08-13 21:31:45 +08:00
|
|
|
obj = drm_fb_cma_get_gem_obj(fb, plane);
|
|
|
|
if (!obj)
|
2017-04-14 18:13:32 +08:00
|
|
|
return 0;
|
|
|
|
|
2017-08-13 21:31:45 +08:00
|
|
|
paddr = obj->paddr + fb->offsets[plane];
|
2018-08-18 00:54:00 +08:00
|
|
|
|
|
|
|
if (plane > 0) {
|
|
|
|
h_div = fb->format->hsub;
|
|
|
|
v_div = fb->format->vsub;
|
|
|
|
}
|
|
|
|
|
drm/fourcc: Add char_per_block, block_w and block_h in drm_format_info
For some pixel formats .cpp structure in drm_format info it's not
enough to describe the peculiarities of the pixel layout, for example
tiled formats or packed formats at bit level.
What's implemented here is to add three new members to drm_format_info
that could describe such formats:
- char_per_block[3]
- block_w[3]
- block_h[3]
char_per_block will be put in a union alongside cpp, for transparent
compatibility with the existing format descriptions.
Regarding, block_w and block_h they are intended to be used through
their equivalent getters drm_format_info_block_width /
drm_format_info_block_height, the reason of the getters is to abstract
the fact that for normal formats block_w and block_h will be unset/0,
but the methods will be returning 1.
Additionally, convenience function drm_format_info_min_pitch had been
added that computes the minimum required pitch for a given pixel
format and buffer width.
Using that the following drm core functions had been updated to
generically handle both block and non-block formats:
- drm_fb_cma_get_gem_addr: for block formats it will just return the
beginning of the block.
- framebuffer_check: Use the newly added drm_format_info_min_pitch.
- drm_gem_fb_create_with_funcs: Use the newly added
drm_format_info_min_pitch.
- In places where is not expecting to handle block formats, like fbdev
helpers I just added some warnings in case the block width/height
are greater than 1.
Changes since v3:
- Add helper function for computing the minimum required pitch.
- Improve/cleanup documentation
Changes since v8:
- Fixed build on 32bits arm architectures, with:
- return DIV_ROUND_UP((u64)buffer_width * info->char_per_block[plane],
+ return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
Reviewed-by: Brian Starkey <brian.starkey@arm.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181101170055.5433-1-alexandru-cosmin.gheorghe@arm.com
2018-11-02 01:02:05 +08:00
|
|
|
sample_x = (state->src_x >> 16) / h_div;
|
|
|
|
sample_y = (state->src_y >> 16) / v_div;
|
|
|
|
block_start_y = (sample_y / block_h) * block_h;
|
|
|
|
num_hblocks = sample_x / block_w;
|
|
|
|
|
|
|
|
paddr += fb->pitches[plane] * block_start_y;
|
|
|
|
paddr += block_size * num_hblocks;
|
2017-04-14 18:13:32 +08:00
|
|
|
|
|
|
|
return paddr;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr);
|
2021-05-24 01:04:14 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* drm_fb_cma_sync_non_coherent - Sync GEM object to non-coherent backing
|
|
|
|
* memory
|
|
|
|
* @drm: DRM device
|
|
|
|
* @old_state: Old plane state
|
|
|
|
* @state: New plane state
|
|
|
|
*
|
|
|
|
* This function can be used by drivers that use damage clips and have
|
|
|
|
* CMA GEM objects backed by non-coherent memory. Calling this function
|
|
|
|
* in a plane's .atomic_update ensures that all the data in the backing
|
|
|
|
* memory have been written to RAM.
|
|
|
|
*/
|
|
|
|
void drm_fb_cma_sync_non_coherent(struct drm_device *drm,
|
|
|
|
struct drm_plane_state *old_state,
|
|
|
|
struct drm_plane_state *state)
|
|
|
|
{
|
|
|
|
const struct drm_format_info *finfo = state->fb->format;
|
|
|
|
struct drm_atomic_helper_damage_iter iter;
|
|
|
|
const struct drm_gem_cma_object *cma_obj;
|
|
|
|
unsigned int offset, i;
|
|
|
|
struct drm_rect clip;
|
|
|
|
dma_addr_t daddr;
|
|
|
|
size_t nb_bytes;
|
|
|
|
|
|
|
|
for (i = 0; i < finfo->num_planes; i++) {
|
|
|
|
cma_obj = drm_fb_cma_get_gem_obj(state->fb, i);
|
|
|
|
if (!cma_obj->map_noncoherent)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
daddr = drm_fb_cma_get_gem_addr(state->fb, state, i);
|
|
|
|
drm_atomic_helper_damage_iter_init(&iter, old_state, state);
|
|
|
|
|
|
|
|
drm_atomic_for_each_plane_damage(&iter, &clip) {
|
|
|
|
/* Ignore x1/x2 values, invalidate complete lines */
|
|
|
|
offset = clip.y1 * state->fb->pitches[i];
|
|
|
|
|
|
|
|
nb_bytes = (clip.y2 - clip.y1) * state->fb->pitches[i];
|
|
|
|
dma_sync_single_for_device(drm->dev, daddr + offset,
|
|
|
|
nb_bytes, DMA_TO_DEVICE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(drm_fb_cma_sync_non_coherent);
|