Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2e3b3c42 LPC |
2 | /* |
3 | * drm kms/fb cma (contiguous memory allocator) helper functions | |
4 | * | |
add0aff2 | 5 | * Copyright (C) 2012 Analog Devices Inc. |
2e3b3c42 LPC |
6 | * Author: Lars-Peter Clausen <lars@metafoo.de> |
7 | * | |
8 | * Based on udl_fbdev.c | |
9 | * Copyright (C) 2012 Red Hat | |
2e3b3c42 LPC |
10 | */ |
11 | ||
b0906904 | 12 | #include <drm/drm_damage_helper.h> |
9d10fc26 | 13 | #include <drm/drm_fb_cma_helper.h> |
2de304b4 | 14 | #include <drm/drm_fourcc.h> |
5628648d | 15 | #include <drm/drm_framebuffer.h> |
2e3b3c42 | 16 | #include <drm/drm_gem_cma_helper.h> |
5628648d | 17 | #include <drm/drm_gem_framebuffer_helper.h> |
2de304b4 | 18 | #include <drm/drm_plane.h> |
b0906904 | 19 | #include <linux/dma-mapping.h> |
2e3b3c42 LPC |
20 | #include <linux/module.h> |
21 | ||
199c7717 NT |
22 | /** |
23 | * DOC: framebuffer cma helper functions | |
24 | * | |
25 | * Provides helper functions for creating a cma (contiguous memory allocator) | |
26 | * backed framebuffer. | |
27 | * | |
c0f095f7 | 28 | * drm_gem_fb_create() is used in the &drm_mode_config_funcs.fb_create |
02da16d0 | 29 | * callback function to create a cma backed framebuffer. |
199c7717 NT |
30 | */ |
31 | ||
2e3b3c42 LPC |
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 | */ | |
41 | struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, | |
890358a6 | 42 | unsigned int plane) |
2e3b3c42 | 43 | { |
5628648d | 44 | struct drm_gem_object *gem; |
2e3b3c42 | 45 | |
5628648d NT |
46 | gem = drm_gem_fb_get_obj(fb, plane); |
47 | if (!gem) | |
2e3b3c42 LPC |
48 | return NULL; |
49 | ||
5628648d | 50 | return to_drm_gem_cma_obj(gem); |
2e3b3c42 LPC |
51 | } |
52 | EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); | |
53 | ||
4636ce93 | 54 | /** |
042bf753 AG |
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 | |
4636ce93 YF |
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 | */ | |
65 | dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, | |
66 | struct drm_plane_state *state, | |
67 | unsigned int plane) | |
68 | { | |
5628648d | 69 | struct drm_gem_cma_object *obj; |
4636ce93 | 70 | dma_addr_t paddr; |
c76abab5 | 71 | u8 h_div = 1, v_div = 1; |
042bf753 AG |
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; | |
4636ce93 | 79 | |
5628648d NT |
80 | obj = drm_fb_cma_get_gem_obj(fb, plane); |
81 | if (!obj) | |
4636ce93 YF |
82 | return 0; |
83 | ||
5628648d | 84 | paddr = obj->paddr + fb->offsets[plane]; |
c76abab5 AKH |
85 | |
86 | if (plane > 0) { | |
87 | h_div = fb->format->hsub; | |
88 | v_div = fb->format->vsub; | |
89 | } | |
90 | ||
042bf753 AG |
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; | |
4636ce93 YF |
98 | |
99 | return paddr; | |
100 | } | |
101 | EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); | |
b0906904 PC |
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 | */ | |
115 | void 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 | } | |
145 | EXPORT_SYMBOL_GPL(drm_fb_cma_sync_non_coherent); |