.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License version 2 as |
---|
6 | | - * published by the Free Software Foundation. |
---|
7 | 4 | */ |
---|
| 5 | + |
---|
| 6 | +#include <linux/iommu.h> |
---|
8 | 7 | |
---|
9 | 8 | #include <drm/drm_atomic.h> |
---|
10 | 9 | #include <drm/drm_atomic_helper.h> |
---|
| 10 | +#include <drm/drm_fourcc.h> |
---|
| 11 | +#include <drm/drm_gem_framebuffer_helper.h> |
---|
11 | 12 | #include <drm/drm_plane_helper.h> |
---|
12 | 13 | |
---|
13 | 14 | #include "dc.h" |
---|
.. | .. |
---|
25 | 26 | { |
---|
26 | 27 | struct tegra_plane *p = to_tegra_plane(plane); |
---|
27 | 28 | struct tegra_plane_state *state; |
---|
| 29 | + unsigned int i; |
---|
28 | 30 | |
---|
29 | 31 | if (plane->state) |
---|
30 | 32 | __drm_atomic_helper_plane_destroy_state(plane->state); |
---|
.. | .. |
---|
38 | 40 | plane->state->plane = plane; |
---|
39 | 41 | plane->state->zpos = p->index; |
---|
40 | 42 | plane->state->normalized_zpos = p->index; |
---|
| 43 | + |
---|
| 44 | + for (i = 0; i < 3; i++) |
---|
| 45 | + state->iova[i] = DMA_MAPPING_ERROR; |
---|
41 | 46 | } |
---|
42 | 47 | } |
---|
43 | 48 | |
---|
.. | .. |
---|
56 | 61 | copy->tiling = state->tiling; |
---|
57 | 62 | copy->format = state->format; |
---|
58 | 63 | copy->swap = state->swap; |
---|
59 | | - copy->bottom_up = state->bottom_up; |
---|
| 64 | + copy->reflect_x = state->reflect_x; |
---|
| 65 | + copy->reflect_y = state->reflect_y; |
---|
60 | 66 | copy->opaque = state->opaque; |
---|
61 | 67 | |
---|
62 | 68 | for (i = 0; i < 2; i++) |
---|
63 | 69 | copy->blending[i] = state->blending[i]; |
---|
| 70 | + |
---|
| 71 | + for (i = 0; i < 3; i++) { |
---|
| 72 | + copy->iova[i] = DMA_MAPPING_ERROR; |
---|
| 73 | + copy->sgt[i] = NULL; |
---|
| 74 | + } |
---|
64 | 75 | |
---|
65 | 76 | return ©->base; |
---|
66 | 77 | } |
---|
.. | .. |
---|
97 | 108 | .format_mod_supported = tegra_plane_format_mod_supported, |
---|
98 | 109 | }; |
---|
99 | 110 | |
---|
| 111 | +static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state) |
---|
| 112 | +{ |
---|
| 113 | + struct iommu_domain *domain = iommu_get_domain_for_dev(dc->dev); |
---|
| 114 | + unsigned int i; |
---|
| 115 | + int err; |
---|
| 116 | + |
---|
| 117 | + for (i = 0; i < state->base.fb->format->num_planes; i++) { |
---|
| 118 | + struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); |
---|
| 119 | + dma_addr_t phys_addr, *phys; |
---|
| 120 | + struct sg_table *sgt; |
---|
| 121 | + |
---|
| 122 | + if (!domain || dc->client.group) |
---|
| 123 | + phys = &phys_addr; |
---|
| 124 | + else |
---|
| 125 | + phys = NULL; |
---|
| 126 | + |
---|
| 127 | + sgt = host1x_bo_pin(dc->dev, &bo->base, phys); |
---|
| 128 | + if (IS_ERR(sgt)) { |
---|
| 129 | + err = PTR_ERR(sgt); |
---|
| 130 | + goto unpin; |
---|
| 131 | + } |
---|
| 132 | + |
---|
| 133 | + if (sgt) { |
---|
| 134 | + err = dma_map_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0); |
---|
| 135 | + if (err) |
---|
| 136 | + goto unpin; |
---|
| 137 | + |
---|
| 138 | + /* |
---|
| 139 | + * The display controller needs contiguous memory, so |
---|
| 140 | + * fail if the buffer is discontiguous and we fail to |
---|
| 141 | + * map its SG table to a single contiguous chunk of |
---|
| 142 | + * I/O virtual memory. |
---|
| 143 | + */ |
---|
| 144 | + if (sgt->nents > 1) { |
---|
| 145 | + err = -EINVAL; |
---|
| 146 | + goto unpin; |
---|
| 147 | + } |
---|
| 148 | + |
---|
| 149 | + state->iova[i] = sg_dma_address(sgt->sgl); |
---|
| 150 | + state->sgt[i] = sgt; |
---|
| 151 | + } else { |
---|
| 152 | + state->iova[i] = phys_addr; |
---|
| 153 | + } |
---|
| 154 | + } |
---|
| 155 | + |
---|
| 156 | + return 0; |
---|
| 157 | + |
---|
| 158 | +unpin: |
---|
| 159 | + dev_err(dc->dev, "failed to map plane %u: %d\n", i, err); |
---|
| 160 | + |
---|
| 161 | + while (i--) { |
---|
| 162 | + struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); |
---|
| 163 | + struct sg_table *sgt = state->sgt[i]; |
---|
| 164 | + |
---|
| 165 | + if (sgt) |
---|
| 166 | + dma_unmap_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0); |
---|
| 167 | + |
---|
| 168 | + host1x_bo_unpin(dc->dev, &bo->base, sgt); |
---|
| 169 | + state->iova[i] = DMA_MAPPING_ERROR; |
---|
| 170 | + state->sgt[i] = NULL; |
---|
| 171 | + } |
---|
| 172 | + |
---|
| 173 | + return err; |
---|
| 174 | +} |
---|
| 175 | + |
---|
| 176 | +static void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state) |
---|
| 177 | +{ |
---|
| 178 | + unsigned int i; |
---|
| 179 | + |
---|
| 180 | + for (i = 0; i < state->base.fb->format->num_planes; i++) { |
---|
| 181 | + struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); |
---|
| 182 | + struct sg_table *sgt = state->sgt[i]; |
---|
| 183 | + |
---|
| 184 | + if (sgt) |
---|
| 185 | + dma_unmap_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0); |
---|
| 186 | + |
---|
| 187 | + host1x_bo_unpin(dc->dev, &bo->base, sgt); |
---|
| 188 | + state->iova[i] = DMA_MAPPING_ERROR; |
---|
| 189 | + state->sgt[i] = NULL; |
---|
| 190 | + } |
---|
| 191 | +} |
---|
| 192 | + |
---|
| 193 | +int tegra_plane_prepare_fb(struct drm_plane *plane, |
---|
| 194 | + struct drm_plane_state *state) |
---|
| 195 | +{ |
---|
| 196 | + struct tegra_dc *dc = to_tegra_dc(state->crtc); |
---|
| 197 | + |
---|
| 198 | + if (!state->fb) |
---|
| 199 | + return 0; |
---|
| 200 | + |
---|
| 201 | + drm_gem_fb_prepare_fb(plane, state); |
---|
| 202 | + |
---|
| 203 | + return tegra_dc_pin(dc, to_tegra_plane_state(state)); |
---|
| 204 | +} |
---|
| 205 | + |
---|
| 206 | +void tegra_plane_cleanup_fb(struct drm_plane *plane, |
---|
| 207 | + struct drm_plane_state *state) |
---|
| 208 | +{ |
---|
| 209 | + struct tegra_dc *dc = to_tegra_dc(state->crtc); |
---|
| 210 | + |
---|
| 211 | + if (dc) |
---|
| 212 | + tegra_dc_unpin(dc, to_tegra_plane_state(state)); |
---|
| 213 | +} |
---|
| 214 | + |
---|
100 | 215 | int tegra_plane_state_add(struct tegra_plane *plane, |
---|
101 | 216 | struct drm_plane_state *state) |
---|
102 | 217 | { |
---|