drm_fb_cma_helper.c (4153B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * drm kms/fb cma (contiguous memory allocator) helper functions 4 * 5 * Copyright (C) 2012 Analog Devices Inc. 6 * Author: Lars-Peter Clausen <lars@metafoo.de> 7 * 8 * Based on udl_fbdev.c 9 * Copyright (C) 2012 Red Hat 10 */ 11 12#include <drm/drm_damage_helper.h> 13#include <drm/drm_fb_cma_helper.h> 14#include <drm/drm_fourcc.h> 15#include <drm/drm_framebuffer.h> 16#include <drm/drm_gem_cma_helper.h> 17#include <drm/drm_gem_framebuffer_helper.h> 18#include <drm/drm_plane.h> 19#include <linux/dma-mapping.h> 20#include <linux/module.h> 21 22/** 23 * DOC: framebuffer cma helper functions 24 * 25 * Provides helper functions for creating a cma (contiguous memory allocator) 26 * backed framebuffer. 27 * 28 * drm_gem_fb_create() is used in the &drm_mode_config_funcs.fb_create 29 * callback function to create a cma backed framebuffer. 30 */ 31 32/** 33 * drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer 34 * @fb: The framebuffer 35 * @plane: Which plane 36 * 37 * Return the CMA GEM object for given framebuffer. 38 * 39 * This function will usually be called from the CRTC callback functions. 40 */ 41struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, 42 unsigned int plane) 43{ 44 struct drm_gem_object *gem; 45 46 gem = drm_gem_fb_get_obj(fb, plane); 47 if (!gem) 48 return NULL; 49 50 return to_drm_gem_cma_obj(gem); 51} 52EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); 53 54/** 55 * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer, for pixel 56 * formats where values are grouped in blocks this will get you the beginning of 57 * the block 58 * @fb: The framebuffer 59 * @state: Which state of drm plane 60 * @plane: Which plane 61 * Return the CMA GEM address for given framebuffer. 62 * 63 * This function will usually be called from the PLANE callback functions. 64 */ 65dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, 66 struct drm_plane_state *state, 67 unsigned int plane) 68{ 69 struct drm_gem_cma_object *obj; 70 dma_addr_t paddr; 71 u8 h_div = 1, v_div = 1; 72 u32 block_w = drm_format_info_block_width(fb->format, plane); 73 u32 block_h = drm_format_info_block_height(fb->format, plane); 74 u32 block_size = fb->format->char_per_block[plane]; 75 u32 sample_x; 76 u32 sample_y; 77 u32 block_start_y; 78 u32 num_hblocks; 79 80 obj = drm_fb_cma_get_gem_obj(fb, plane); 81 if (!obj) 82 return 0; 83 84 paddr = obj->paddr + fb->offsets[plane]; 85 86 if (plane > 0) { 87 h_div = fb->format->hsub; 88 v_div = fb->format->vsub; 89 } 90 91 sample_x = (state->src_x >> 16) / h_div; 92 sample_y = (state->src_y >> 16) / v_div; 93 block_start_y = (sample_y / block_h) * block_h; 94 num_hblocks = sample_x / block_w; 95 96 paddr += fb->pitches[plane] * block_start_y; 97 paddr += block_size * num_hblocks; 98 99 return paddr; 100} 101EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); 102 103/** 104 * drm_fb_cma_sync_non_coherent - Sync GEM object to non-coherent backing 105 * memory 106 * @drm: DRM device 107 * @old_state: Old plane state 108 * @state: New plane state 109 * 110 * This function can be used by drivers that use damage clips and have 111 * CMA GEM objects backed by non-coherent memory. Calling this function 112 * in a plane's .atomic_update ensures that all the data in the backing 113 * memory have been written to RAM. 114 */ 115void drm_fb_cma_sync_non_coherent(struct drm_device *drm, 116 struct drm_plane_state *old_state, 117 struct drm_plane_state *state) 118{ 119 const struct drm_format_info *finfo = state->fb->format; 120 struct drm_atomic_helper_damage_iter iter; 121 const struct drm_gem_cma_object *cma_obj; 122 unsigned int offset, i; 123 struct drm_rect clip; 124 dma_addr_t daddr; 125 size_t nb_bytes; 126 127 for (i = 0; i < finfo->num_planes; i++) { 128 cma_obj = drm_fb_cma_get_gem_obj(state->fb, i); 129 if (!cma_obj->map_noncoherent) 130 continue; 131 132 daddr = drm_fb_cma_get_gem_addr(state->fb, state, i); 133 drm_atomic_helper_damage_iter_init(&iter, old_state, state); 134 135 drm_atomic_for_each_plane_damage(&iter, &clip) { 136 /* Ignore x1/x2 values, invalidate complete lines */ 137 offset = clip.y1 * state->fb->pitches[i]; 138 139 nb_bytes = (clip.y2 - clip.y1) * state->fb->pitches[i]; 140 dma_sync_single_for_device(drm->dev, daddr + offset, 141 nb_bytes, DMA_TO_DEVICE); 142 } 143 } 144} 145EXPORT_SYMBOL_GPL(drm_fb_cma_sync_non_coherent);