Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2e3b3c42 | 2 | /* |
6bcfe8ea | 3 | * drm kms/fb dma helper functions |
2e3b3c42 | 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> |
6bcfe8ea | 13 | #include <drm/drm_fb_dma_helper.h> |
2de304b4 | 14 | #include <drm/drm_fourcc.h> |
5628648d | 15 | #include <drm/drm_framebuffer.h> |
4a83c26a | 16 | #include <drm/drm_gem_dma_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 | 22 | /** |
6bcfe8ea | 23 | * DOC: framebuffer dma helper functions |
199c7717 | 24 | * |
6bcfe8ea DK |
25 | * Provides helper functions for creating a DMA-contiguous framebuffer. |
26 | * | |
27 | * Depending on the platform, the buffers may be physically non-contiguous and | |
28 | * mapped through an IOMMU or a similar mechanism, or allocated from | |
29 | * physically-contiguous memory (using, for instance, CMA or a pool of memory | |
30 | * reserved at early boot). This is handled behind the scenes by the DMA mapping | |
31 | * API. | |
199c7717 | 32 | * |
c0f095f7 | 33 | * drm_gem_fb_create() is used in the &drm_mode_config_funcs.fb_create |
6bcfe8ea | 34 | * callback function to create a DMA-contiguous framebuffer. |
199c7717 NT |
35 | */ |
36 | ||
2e3b3c42 | 37 | /** |
4a83c26a | 38 | * drm_fb_dma_get_gem_obj() - Get DMA GEM object for framebuffer |
2e3b3c42 LPC |
39 | * @fb: The framebuffer |
40 | * @plane: Which plane | |
41 | * | |
4a83c26a | 42 | * Return the DMA GEM object for given framebuffer. |
2e3b3c42 LPC |
43 | * |
44 | * This function will usually be called from the CRTC callback functions. | |
45 | */ | |
4a83c26a | 46 | struct drm_gem_dma_object *drm_fb_dma_get_gem_obj(struct drm_framebuffer *fb, |
890358a6 | 47 | unsigned int plane) |
2e3b3c42 | 48 | { |
5628648d | 49 | struct drm_gem_object *gem; |
2e3b3c42 | 50 | |
5628648d NT |
51 | gem = drm_gem_fb_get_obj(fb, plane); |
52 | if (!gem) | |
2e3b3c42 LPC |
53 | return NULL; |
54 | ||
4a83c26a | 55 | return to_drm_gem_dma_obj(gem); |
2e3b3c42 | 56 | } |
6bcfe8ea | 57 | EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_obj); |
2e3b3c42 | 58 | |
4636ce93 | 59 | /** |
6bcfe8ea | 60 | * drm_fb_dma_get_gem_addr() - Get DMA (bus) address for framebuffer, for pixel |
042bf753 AG |
61 | * formats where values are grouped in blocks this will get you the beginning of |
62 | * the block | |
4636ce93 YF |
63 | * @fb: The framebuffer |
64 | * @state: Which state of drm plane | |
65 | * @plane: Which plane | |
6bcfe8ea | 66 | * Return the DMA GEM address for given framebuffer. |
4636ce93 YF |
67 | * |
68 | * This function will usually be called from the PLANE callback functions. | |
69 | */ | |
6bcfe8ea | 70 | dma_addr_t drm_fb_dma_get_gem_addr(struct drm_framebuffer *fb, |
4636ce93 YF |
71 | struct drm_plane_state *state, |
72 | unsigned int plane) | |
73 | { | |
4a83c26a | 74 | struct drm_gem_dma_object *obj; |
8c30eecc | 75 | dma_addr_t dma_addr; |
c76abab5 | 76 | u8 h_div = 1, v_div = 1; |
042bf753 AG |
77 | u32 block_w = drm_format_info_block_width(fb->format, plane); |
78 | u32 block_h = drm_format_info_block_height(fb->format, plane); | |
79 | u32 block_size = fb->format->char_per_block[plane]; | |
80 | u32 sample_x; | |
81 | u32 sample_y; | |
82 | u32 block_start_y; | |
83 | u32 num_hblocks; | |
4636ce93 | 84 | |
6bcfe8ea | 85 | obj = drm_fb_dma_get_gem_obj(fb, plane); |
5628648d | 86 | if (!obj) |
4636ce93 YF |
87 | return 0; |
88 | ||
8c30eecc | 89 | dma_addr = obj->dma_addr + fb->offsets[plane]; |
c76abab5 AKH |
90 | |
91 | if (plane > 0) { | |
92 | h_div = fb->format->hsub; | |
93 | v_div = fb->format->vsub; | |
94 | } | |
95 | ||
042bf753 AG |
96 | sample_x = (state->src_x >> 16) / h_div; |
97 | sample_y = (state->src_y >> 16) / v_div; | |
98 | block_start_y = (sample_y / block_h) * block_h; | |
99 | num_hblocks = sample_x / block_w; | |
100 | ||
8c30eecc DK |
101 | dma_addr += fb->pitches[plane] * block_start_y; |
102 | dma_addr += block_size * num_hblocks; | |
4636ce93 | 103 | |
8c30eecc | 104 | return dma_addr; |
4636ce93 | 105 | } |
6bcfe8ea | 106 | EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_addr); |
b0906904 PC |
107 | |
108 | /** | |
6bcfe8ea | 109 | * drm_fb_dma_sync_non_coherent - Sync GEM object to non-coherent backing |
b0906904 PC |
110 | * memory |
111 | * @drm: DRM device | |
112 | * @old_state: Old plane state | |
113 | * @state: New plane state | |
114 | * | |
115 | * This function can be used by drivers that use damage clips and have | |
4a83c26a | 116 | * DMA GEM objects backed by non-coherent memory. Calling this function |
b0906904 PC |
117 | * in a plane's .atomic_update ensures that all the data in the backing |
118 | * memory have been written to RAM. | |
119 | */ | |
6bcfe8ea | 120 | void drm_fb_dma_sync_non_coherent(struct drm_device *drm, |
b0906904 PC |
121 | struct drm_plane_state *old_state, |
122 | struct drm_plane_state *state) | |
123 | { | |
124 | const struct drm_format_info *finfo = state->fb->format; | |
125 | struct drm_atomic_helper_damage_iter iter; | |
4a83c26a | 126 | const struct drm_gem_dma_object *dma_obj; |
b0906904 PC |
127 | unsigned int offset, i; |
128 | struct drm_rect clip; | |
129 | dma_addr_t daddr; | |
130 | size_t nb_bytes; | |
131 | ||
132 | for (i = 0; i < finfo->num_planes; i++) { | |
4a83c26a DK |
133 | dma_obj = drm_fb_dma_get_gem_obj(state->fb, i); |
134 | if (!dma_obj->map_noncoherent) | |
b0906904 PC |
135 | continue; |
136 | ||
6bcfe8ea | 137 | daddr = drm_fb_dma_get_gem_addr(state->fb, state, i); |
b0906904 PC |
138 | drm_atomic_helper_damage_iter_init(&iter, old_state, state); |
139 | ||
140 | drm_atomic_for_each_plane_damage(&iter, &clip) { | |
141 | /* Ignore x1/x2 values, invalidate complete lines */ | |
142 | offset = clip.y1 * state->fb->pitches[i]; | |
143 | ||
144 | nb_bytes = (clip.y2 - clip.y1) * state->fb->pitches[i]; | |
145 | dma_sync_single_for_device(drm->dev, daddr + offset, | |
146 | nb_bytes, DMA_TO_DEVICE); | |
147 | } | |
148 | } | |
149 | } | |
6bcfe8ea | 150 | EXPORT_SYMBOL_GPL(drm_fb_dma_sync_non_coherent); |