|  | // SPDX-License-Identifier: GPL-2.0-or-later | 
|  | /* | 
|  | * drm kms/fb cma (contiguous memory allocator) helper functions | 
|  | * | 
|  | * Copyright (C) 2012 Analog Device Inc. | 
|  | *   Author: Lars-Peter Clausen <lars@metafoo.de> | 
|  | * | 
|  | * Based on udl_fbdev.c | 
|  | *  Copyright (C) 2012 Red Hat | 
|  | */ | 
|  |  | 
|  | #include <drm/drm_fourcc.h> | 
|  | #include <drm/drm_framebuffer.h> | 
|  | #include <drm/drm_gem_cma_helper.h> | 
|  | #include <drm/drm_gem_framebuffer_helper.h> | 
|  | #include <drm/drm_plane.h> | 
|  | #include <linux/module.h> | 
|  |  | 
|  | /** | 
|  | * DOC: framebuffer cma helper functions | 
|  | * | 
|  | * Provides helper functions for creating a cma (contiguous memory allocator) | 
|  | * backed framebuffer. | 
|  | * | 
|  | * drm_gem_fb_create() is used in the &drm_mode_config_funcs.fb_create | 
|  | * callback function to create a cma backed framebuffer. | 
|  | */ | 
|  |  | 
|  | /** | 
|  | * 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, | 
|  | unsigned int plane) | 
|  | { | 
|  | struct drm_gem_object *gem; | 
|  |  | 
|  | gem = drm_gem_fb_get_obj(fb, plane); | 
|  | if (!gem) | 
|  | return NULL; | 
|  |  | 
|  | return to_drm_gem_cma_obj(gem); | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); | 
|  |  | 
|  | /** | 
|  | * 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 | 
|  | * @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) | 
|  | { | 
|  | struct drm_gem_cma_object *obj; | 
|  | dma_addr_t paddr; | 
|  | u8 h_div = 1, v_div = 1; | 
|  | 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; | 
|  |  | 
|  | obj = drm_fb_cma_get_gem_obj(fb, plane); | 
|  | if (!obj) | 
|  | return 0; | 
|  |  | 
|  | paddr = obj->paddr + fb->offsets[plane]; | 
|  |  | 
|  | if (plane > 0) { | 
|  | h_div = fb->format->hsub; | 
|  | v_div = fb->format->vsub; | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | return paddr; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); |