diff options
author | Thierry Reding <treding@nvidia.com> | 2014-06-03 08:48:12 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-08-04 04:07:34 -0400 |
commit | c134f019abcfaa1cb6e07f6154e92a4f8ce8ddd8 (patch) | |
tree | 0d26c79eefb921fd0841b9d48c48b589a3ad2f8a | |
parent | 0c6b1e4ba74f58ee1507d456e52c630b4b8ff174 (diff) |
drm/tegra: Implement more tiling modes
Tegra124 supports a block-linear mode in addition to the regular pitch
linear and tiled modes. Add support for these by moving the internal
representation into a structure rather than a simple flag.
Tested-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 102 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dc.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/fb.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.h | 16 |
6 files changed, 118 insertions, 24 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index ef40381f3909..afcca04f5367 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
@@ -18,6 +18,7 @@ | |||
18 | struct tegra_dc_soc_info { | 18 | struct tegra_dc_soc_info { |
19 | bool supports_interlacing; | 19 | bool supports_interlacing; |
20 | bool supports_cursor; | 20 | bool supports_cursor; |
21 | bool supports_block_linear; | ||
21 | }; | 22 | }; |
22 | 23 | ||
23 | struct tegra_plane { | 24 | struct tegra_plane { |
@@ -212,15 +213,44 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | |||
212 | tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); | 213 | tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); |
213 | tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); | 214 | tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); |
214 | 215 | ||
215 | if (window->tiled) { | 216 | if (dc->soc->supports_block_linear) { |
216 | value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | | 217 | unsigned long height = window->tiling.value; |
217 | DC_WIN_BUFFER_ADDR_MODE_TILE; | 218 | |
219 | switch (window->tiling.mode) { | ||
220 | case TEGRA_BO_TILING_MODE_PITCH: | ||
221 | value = DC_WINBUF_SURFACE_KIND_PITCH; | ||
222 | break; | ||
223 | |||
224 | case TEGRA_BO_TILING_MODE_TILED: | ||
225 | value = DC_WINBUF_SURFACE_KIND_TILED; | ||
226 | break; | ||
227 | |||
228 | case TEGRA_BO_TILING_MODE_BLOCK: | ||
229 | value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) | | ||
230 | DC_WINBUF_SURFACE_KIND_BLOCK; | ||
231 | break; | ||
232 | } | ||
233 | |||
234 | tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND); | ||
218 | } else { | 235 | } else { |
219 | value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | | 236 | switch (window->tiling.mode) { |
220 | DC_WIN_BUFFER_ADDR_MODE_LINEAR; | 237 | case TEGRA_BO_TILING_MODE_PITCH: |
221 | } | 238 | value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | |
239 | DC_WIN_BUFFER_ADDR_MODE_LINEAR; | ||
240 | break; | ||
222 | 241 | ||
223 | tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); | 242 | case TEGRA_BO_TILING_MODE_TILED: |
243 | value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | | ||
244 | DC_WIN_BUFFER_ADDR_MODE_TILE; | ||
245 | break; | ||
246 | |||
247 | case TEGRA_BO_TILING_MODE_BLOCK: | ||
248 | DRM_ERROR("hardware doesn't support block linear mode\n"); | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | |||
252 | tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); | ||
253 | } | ||
224 | 254 | ||
225 | value = WIN_ENABLE; | 255 | value = WIN_ENABLE; |
226 | 256 | ||
@@ -288,6 +318,7 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | |||
288 | struct tegra_dc *dc = to_tegra_dc(crtc); | 318 | struct tegra_dc *dc = to_tegra_dc(crtc); |
289 | struct tegra_dc_window window; | 319 | struct tegra_dc_window window; |
290 | unsigned int i; | 320 | unsigned int i; |
321 | int err; | ||
291 | 322 | ||
292 | memset(&window, 0, sizeof(window)); | 323 | memset(&window, 0, sizeof(window)); |
293 | window.src.x = src_x >> 16; | 324 | window.src.x = src_x >> 16; |
@@ -301,7 +332,10 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | |||
301 | window.format = tegra_dc_format(fb->pixel_format, &window.swap); | 332 | window.format = tegra_dc_format(fb->pixel_format, &window.swap); |
302 | window.bits_per_pixel = fb->bits_per_pixel; | 333 | window.bits_per_pixel = fb->bits_per_pixel; |
303 | window.bottom_up = tegra_fb_is_bottom_up(fb); | 334 | window.bottom_up = tegra_fb_is_bottom_up(fb); |
304 | window.tiled = tegra_fb_is_tiled(fb); | 335 | |
336 | err = tegra_fb_get_tiling(fb, &window.tiling); | ||
337 | if (err < 0) | ||
338 | return err; | ||
305 | 339 | ||
306 | for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { | 340 | for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { |
307 | struct tegra_bo *bo = tegra_fb_get_plane(fb, i); | 341 | struct tegra_bo *bo = tegra_fb_get_plane(fb, i); |
@@ -402,8 +436,14 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, | |||
402 | { | 436 | { |
403 | struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); | 437 | struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); |
404 | unsigned int h_offset = 0, v_offset = 0; | 438 | unsigned int h_offset = 0, v_offset = 0; |
439 | struct tegra_bo_tiling tiling; | ||
405 | unsigned int format, swap; | 440 | unsigned int format, swap; |
406 | unsigned long value; | 441 | unsigned long value; |
442 | int err; | ||
443 | |||
444 | err = tegra_fb_get_tiling(fb, &tiling); | ||
445 | if (err < 0) | ||
446 | return err; | ||
407 | 447 | ||
408 | tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); | 448 | tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); |
409 | 449 | ||
@@ -417,15 +457,44 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, | |||
417 | tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH); | 457 | tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH); |
418 | tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP); | 458 | tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP); |
419 | 459 | ||
420 | if (tegra_fb_is_tiled(fb)) { | 460 | if (dc->soc->supports_block_linear) { |
421 | value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | | 461 | unsigned long height = tiling.value; |
422 | DC_WIN_BUFFER_ADDR_MODE_TILE; | 462 | |
463 | switch (tiling.mode) { | ||
464 | case TEGRA_BO_TILING_MODE_PITCH: | ||
465 | value = DC_WINBUF_SURFACE_KIND_PITCH; | ||
466 | break; | ||
467 | |||
468 | case TEGRA_BO_TILING_MODE_TILED: | ||
469 | value = DC_WINBUF_SURFACE_KIND_TILED; | ||
470 | break; | ||
471 | |||
472 | case TEGRA_BO_TILING_MODE_BLOCK: | ||
473 | value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) | | ||
474 | DC_WINBUF_SURFACE_KIND_BLOCK; | ||
475 | break; | ||
476 | } | ||
477 | |||
478 | tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND); | ||
423 | } else { | 479 | } else { |
424 | value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | | 480 | switch (tiling.mode) { |
425 | DC_WIN_BUFFER_ADDR_MODE_LINEAR; | 481 | case TEGRA_BO_TILING_MODE_PITCH: |
426 | } | 482 | value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | |
483 | DC_WIN_BUFFER_ADDR_MODE_LINEAR; | ||
484 | break; | ||
427 | 485 | ||
428 | tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); | 486 | case TEGRA_BO_TILING_MODE_TILED: |
487 | value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | | ||
488 | DC_WIN_BUFFER_ADDR_MODE_TILE; | ||
489 | break; | ||
490 | |||
491 | case TEGRA_BO_TILING_MODE_BLOCK: | ||
492 | DRM_ERROR("hardware doesn't support block linear mode\n"); | ||
493 | return -EINVAL; | ||
494 | } | ||
495 | |||
496 | tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); | ||
497 | } | ||
429 | 498 | ||
430 | /* make sure bottom-up buffers are properly displayed */ | 499 | /* make sure bottom-up buffers are properly displayed */ |
431 | if (tegra_fb_is_bottom_up(fb)) { | 500 | if (tegra_fb_is_bottom_up(fb)) { |
@@ -1277,16 +1346,19 @@ static const struct host1x_client_ops dc_client_ops = { | |||
1277 | static const struct tegra_dc_soc_info tegra20_dc_soc_info = { | 1346 | static const struct tegra_dc_soc_info tegra20_dc_soc_info = { |
1278 | .supports_interlacing = false, | 1347 | .supports_interlacing = false, |
1279 | .supports_cursor = false, | 1348 | .supports_cursor = false, |
1349 | .supports_block_linear = false, | ||
1280 | }; | 1350 | }; |
1281 | 1351 | ||
1282 | static const struct tegra_dc_soc_info tegra30_dc_soc_info = { | 1352 | static const struct tegra_dc_soc_info tegra30_dc_soc_info = { |
1283 | .supports_interlacing = false, | 1353 | .supports_interlacing = false, |
1284 | .supports_cursor = false, | 1354 | .supports_cursor = false, |
1355 | .supports_block_linear = false, | ||
1285 | }; | 1356 | }; |
1286 | 1357 | ||
1287 | static const struct tegra_dc_soc_info tegra124_dc_soc_info = { | 1358 | static const struct tegra_dc_soc_info tegra124_dc_soc_info = { |
1288 | .supports_interlacing = true, | 1359 | .supports_interlacing = true, |
1289 | .supports_cursor = true, | 1360 | .supports_cursor = true, |
1361 | .supports_block_linear = true, | ||
1290 | }; | 1362 | }; |
1291 | 1363 | ||
1292 | static const struct of_device_id tegra_dc_of_match[] = { | 1364 | static const struct of_device_id tegra_dc_of_match[] = { |
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 78c5feff95d2..705c93b00794 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h | |||
@@ -428,6 +428,11 @@ | |||
428 | #define DC_WINBUF_ADDR_V_OFFSET_NS 0x809 | 428 | #define DC_WINBUF_ADDR_V_OFFSET_NS 0x809 |
429 | 429 | ||
430 | #define DC_WINBUF_UFLOW_STATUS 0x80a | 430 | #define DC_WINBUF_UFLOW_STATUS 0x80a |
431 | #define DC_WINBUF_SURFACE_KIND 0x80b | ||
432 | #define DC_WINBUF_SURFACE_KIND_PITCH (0 << 0) | ||
433 | #define DC_WINBUF_SURFACE_KIND_TILED (1 << 0) | ||
434 | #define DC_WINBUF_SURFACE_KIND_BLOCK (2 << 0) | ||
435 | #define DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(x) (((x) & 0x7) << 4) | ||
431 | 436 | ||
432 | #define DC_WINBUF_AD_UFLOW_STATUS 0xbca | 437 | #define DC_WINBUF_AD_UFLOW_STATUS 0xbca |
433 | #define DC_WINBUF_BD_UFLOW_STATUS 0xdca | 438 | #define DC_WINBUF_BD_UFLOW_STATUS 0xdca |
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 0d30689dff01..96d754e7b3eb 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <drm/drm_fb_helper.h> | 19 | #include <drm/drm_fb_helper.h> |
20 | #include <drm/drm_fixed.h> | 20 | #include <drm/drm_fixed.h> |
21 | 21 | ||
22 | #include "gem.h" | ||
23 | |||
22 | struct reset_control; | 24 | struct reset_control; |
23 | 25 | ||
24 | struct tegra_fb { | 26 | struct tegra_fb { |
@@ -160,7 +162,8 @@ struct tegra_dc_window { | |||
160 | unsigned int stride[2]; | 162 | unsigned int stride[2]; |
161 | unsigned long base[3]; | 163 | unsigned long base[3]; |
162 | bool bottom_up; | 164 | bool bottom_up; |
163 | bool tiled; | 165 | |
166 | struct tegra_bo_tiling tiling; | ||
164 | }; | 167 | }; |
165 | 168 | ||
166 | /* from dc.c */ | 169 | /* from dc.c */ |
@@ -279,7 +282,8 @@ int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link, | |||
279 | struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, | 282 | struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, |
280 | unsigned int index); | 283 | unsigned int index); |
281 | bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer); | 284 | bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer); |
282 | bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer); | 285 | int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, |
286 | struct tegra_bo_tiling *tiling); | ||
283 | int tegra_drm_fb_prepare(struct drm_device *drm); | 287 | int tegra_drm_fb_prepare(struct drm_device *drm); |
284 | int tegra_drm_fb_init(struct drm_device *drm); | 288 | int tegra_drm_fb_init(struct drm_device *drm); |
285 | void tegra_drm_fb_exit(struct drm_device *drm); | 289 | void tegra_drm_fb_exit(struct drm_device *drm); |
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index fc1528e0bda1..7790d43ad082 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c | |||
@@ -46,14 +46,15 @@ bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer) | |||
46 | return false; | 46 | return false; |
47 | } | 47 | } |
48 | 48 | ||
49 | bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer) | 49 | int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, |
50 | struct tegra_bo_tiling *tiling) | ||
50 | { | 51 | { |
51 | struct tegra_fb *fb = to_tegra_fb(framebuffer); | 52 | struct tegra_fb *fb = to_tegra_fb(framebuffer); |
52 | 53 | ||
53 | if (fb->planes[0]->flags & TEGRA_BO_TILED) | 54 | /* TODO: handle YUV formats? */ |
54 | return true; | 55 | *tiling = fb->planes[0]->tiling; |
55 | 56 | ||
56 | return false; | 57 | return 0; |
57 | } | 58 | } |
58 | 59 | ||
59 | static void tegra_fb_destroy(struct drm_framebuffer *framebuffer) | 60 | static void tegra_fb_destroy(struct drm_framebuffer *framebuffer) |
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index aa85b7b26f10..c1e4e8b6e5ca 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c | |||
@@ -126,7 +126,7 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size, | |||
126 | goto err_mmap; | 126 | goto err_mmap; |
127 | 127 | ||
128 | if (flags & DRM_TEGRA_GEM_CREATE_TILED) | 128 | if (flags & DRM_TEGRA_GEM_CREATE_TILED) |
129 | bo->flags |= TEGRA_BO_TILED; | 129 | bo->tiling.mode = TEGRA_BO_TILING_MODE_TILED; |
130 | 130 | ||
131 | if (flags & DRM_TEGRA_GEM_CREATE_BOTTOM_UP) | 131 | if (flags & DRM_TEGRA_GEM_CREATE_BOTTOM_UP) |
132 | bo->flags |= TEGRA_BO_BOTTOM_UP; | 132 | bo->flags |= TEGRA_BO_BOTTOM_UP; |
diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index 2f3fe96c5154..43a25c853357 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h | |||
@@ -16,8 +16,18 @@ | |||
16 | #include <drm/drm.h> | 16 | #include <drm/drm.h> |
17 | #include <drm/drmP.h> | 17 | #include <drm/drmP.h> |
18 | 18 | ||
19 | #define TEGRA_BO_TILED (1 << 0) | 19 | #define TEGRA_BO_BOTTOM_UP (1 << 0) |
20 | #define TEGRA_BO_BOTTOM_UP (1 << 1) | 20 | |
21 | enum tegra_bo_tiling_mode { | ||
22 | TEGRA_BO_TILING_MODE_PITCH, | ||
23 | TEGRA_BO_TILING_MODE_TILED, | ||
24 | TEGRA_BO_TILING_MODE_BLOCK, | ||
25 | }; | ||
26 | |||
27 | struct tegra_bo_tiling { | ||
28 | enum tegra_bo_tiling_mode mode; | ||
29 | unsigned long value; | ||
30 | }; | ||
21 | 31 | ||
22 | struct tegra_bo { | 32 | struct tegra_bo { |
23 | struct drm_gem_object gem; | 33 | struct drm_gem_object gem; |
@@ -26,6 +36,8 @@ struct tegra_bo { | |||
26 | struct sg_table *sgt; | 36 | struct sg_table *sgt; |
27 | dma_addr_t paddr; | 37 | dma_addr_t paddr; |
28 | void *vaddr; | 38 | void *vaddr; |
39 | |||
40 | struct tegra_bo_tiling tiling; | ||
29 | }; | 41 | }; |
30 | 42 | ||
31 | static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem) | 43 | static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem) |