From 2263c460bed14f36c9a87d97242c35cf1346f61e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Jun 2014 10:06:09 +0300 Subject: drm/tegra: sor - missing unlock on error We should unlock before returning the error code. Signed-off-by: Dan Carpenter Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 27c979b50111..64f57fa9b8f6 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -516,7 +516,7 @@ static int tegra_output_sor_enable(struct tegra_output *output) if (err < 0) { dev_err(sor->dev, "failed to probe eDP link: %d\n", err); - return err; + goto unlock; } } -- cgit v1.2.1 From 0c6b1e4ba74f58ee1507d456e52c630b4b8ff174 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 8 Jul 2014 21:32:13 +0900 Subject: drm/tegra: dsi - Handle non-continuous clock flag Handle the MIPI_DSI_CLOCK_NONCONTINUOUS flag and only set TX-only clock behavior when this flag is present to allow panels requiring continuous clock mode to operate with this driver. Signed-off-by: Alexandre Courbot Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index bd56f2affa78..eadfeaf9e1eb 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -474,7 +474,8 @@ static int tegra_output_dsi_enable(struct tegra_output *output) tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); value = tegra_dsi_readl(dsi, DSI_CONTROL); - value |= DSI_CONTROL_HS_CLK_CTRL; + if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) + value |= DSI_CONTROL_HS_CLK_CTRL; value &= ~DSI_CONTROL_TX_TRIG(3); value &= ~DSI_CONTROL_DCS_ENABLE; value |= DSI_CONTROL_VIDEO_ENABLE; -- cgit v1.2.1 From c134f019abcfaa1cb6e07f6154e92a4f8ce8ddd8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 3 Jun 2014 14:48:12 +0200 Subject: 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 Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 102 +++++++++++++++++++++++++++++++++++++------- drivers/gpu/drm/tegra/dc.h | 5 +++ drivers/gpu/drm/tegra/drm.h | 8 +++- drivers/gpu/drm/tegra/fb.c | 9 ++-- drivers/gpu/drm/tegra/gem.c | 2 +- drivers/gpu/drm/tegra/gem.h | 16 ++++++- 6 files changed, 118 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm') 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 @@ struct tegra_dc_soc_info { bool supports_interlacing; bool supports_cursor; + bool supports_block_linear; }; struct tegra_plane { @@ -212,15 +213,44 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); - if (window->tiled) { - value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | - DC_WIN_BUFFER_ADDR_MODE_TILE; + if (dc->soc->supports_block_linear) { + unsigned long height = window->tiling.value; + + switch (window->tiling.mode) { + case TEGRA_BO_TILING_MODE_PITCH: + value = DC_WINBUF_SURFACE_KIND_PITCH; + break; + + case TEGRA_BO_TILING_MODE_TILED: + value = DC_WINBUF_SURFACE_KIND_TILED; + break; + + case TEGRA_BO_TILING_MODE_BLOCK: + value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) | + DC_WINBUF_SURFACE_KIND_BLOCK; + break; + } + + tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND); } else { - value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | - DC_WIN_BUFFER_ADDR_MODE_LINEAR; - } + switch (window->tiling.mode) { + case TEGRA_BO_TILING_MODE_PITCH: + value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | + DC_WIN_BUFFER_ADDR_MODE_LINEAR; + break; - tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); + case TEGRA_BO_TILING_MODE_TILED: + value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | + DC_WIN_BUFFER_ADDR_MODE_TILE; + break; + + case TEGRA_BO_TILING_MODE_BLOCK: + DRM_ERROR("hardware doesn't support block linear mode\n"); + return -EINVAL; + } + + tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); + } value = WIN_ENABLE; @@ -288,6 +318,7 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct tegra_dc *dc = to_tegra_dc(crtc); struct tegra_dc_window window; unsigned int i; + int err; memset(&window, 0, sizeof(window)); window.src.x = src_x >> 16; @@ -301,7 +332,10 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, window.format = tegra_dc_format(fb->pixel_format, &window.swap); window.bits_per_pixel = fb->bits_per_pixel; window.bottom_up = tegra_fb_is_bottom_up(fb); - window.tiled = tegra_fb_is_tiled(fb); + + err = tegra_fb_get_tiling(fb, &window.tiling); + if (err < 0) + return err; for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { 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, { struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); unsigned int h_offset = 0, v_offset = 0; + struct tegra_bo_tiling tiling; unsigned int format, swap; unsigned long value; + int err; + + err = tegra_fb_get_tiling(fb, &tiling); + if (err < 0) + return err; tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); @@ -417,15 +457,44 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH); tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP); - if (tegra_fb_is_tiled(fb)) { - value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | - DC_WIN_BUFFER_ADDR_MODE_TILE; + if (dc->soc->supports_block_linear) { + unsigned long height = tiling.value; + + switch (tiling.mode) { + case TEGRA_BO_TILING_MODE_PITCH: + value = DC_WINBUF_SURFACE_KIND_PITCH; + break; + + case TEGRA_BO_TILING_MODE_TILED: + value = DC_WINBUF_SURFACE_KIND_TILED; + break; + + case TEGRA_BO_TILING_MODE_BLOCK: + value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) | + DC_WINBUF_SURFACE_KIND_BLOCK; + break; + } + + tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND); } else { - value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | - DC_WIN_BUFFER_ADDR_MODE_LINEAR; - } + switch (tiling.mode) { + case TEGRA_BO_TILING_MODE_PITCH: + value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | + DC_WIN_BUFFER_ADDR_MODE_LINEAR; + break; - tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); + case TEGRA_BO_TILING_MODE_TILED: + value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | + DC_WIN_BUFFER_ADDR_MODE_TILE; + break; + + case TEGRA_BO_TILING_MODE_BLOCK: + DRM_ERROR("hardware doesn't support block linear mode\n"); + return -EINVAL; + } + + tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); + } /* make sure bottom-up buffers are properly displayed */ if (tegra_fb_is_bottom_up(fb)) { @@ -1277,16 +1346,19 @@ static const struct host1x_client_ops dc_client_ops = { static const struct tegra_dc_soc_info tegra20_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, + .supports_block_linear = false, }; static const struct tegra_dc_soc_info tegra30_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, + .supports_block_linear = false, }; static const struct tegra_dc_soc_info tegra124_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, + .supports_block_linear = true, }; 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 @@ #define DC_WINBUF_ADDR_V_OFFSET_NS 0x809 #define DC_WINBUF_UFLOW_STATUS 0x80a +#define DC_WINBUF_SURFACE_KIND 0x80b +#define DC_WINBUF_SURFACE_KIND_PITCH (0 << 0) +#define DC_WINBUF_SURFACE_KIND_TILED (1 << 0) +#define DC_WINBUF_SURFACE_KIND_BLOCK (2 << 0) +#define DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(x) (((x) & 0x7) << 4) #define DC_WINBUF_AD_UFLOW_STATUS 0xbca #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 @@ #include #include +#include "gem.h" + struct reset_control; struct tegra_fb { @@ -160,7 +162,8 @@ struct tegra_dc_window { unsigned int stride[2]; unsigned long base[3]; bool bottom_up; - bool tiled; + + struct tegra_bo_tiling tiling; }; /* from dc.c */ @@ -279,7 +282,8 @@ int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link, struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, unsigned int index); bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer); -bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer); +int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, + struct tegra_bo_tiling *tiling); int tegra_drm_fb_prepare(struct drm_device *drm); int tegra_drm_fb_init(struct drm_device *drm); 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) return false; } -bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer) +int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, + struct tegra_bo_tiling *tiling) { struct tegra_fb *fb = to_tegra_fb(framebuffer); - if (fb->planes[0]->flags & TEGRA_BO_TILED) - return true; + /* TODO: handle YUV formats? */ + *tiling = fb->planes[0]->tiling; - return false; + return 0; } 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, goto err_mmap; if (flags & DRM_TEGRA_GEM_CREATE_TILED) - bo->flags |= TEGRA_BO_TILED; + bo->tiling.mode = TEGRA_BO_TILING_MODE_TILED; if (flags & DRM_TEGRA_GEM_CREATE_BOTTOM_UP) 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 @@ #include #include -#define TEGRA_BO_TILED (1 << 0) -#define TEGRA_BO_BOTTOM_UP (1 << 1) +#define TEGRA_BO_BOTTOM_UP (1 << 0) + +enum tegra_bo_tiling_mode { + TEGRA_BO_TILING_MODE_PITCH, + TEGRA_BO_TILING_MODE_TILED, + TEGRA_BO_TILING_MODE_BLOCK, +}; + +struct tegra_bo_tiling { + enum tegra_bo_tiling_mode mode; + unsigned long value; +}; struct tegra_bo { struct drm_gem_object gem; @@ -26,6 +36,8 @@ struct tegra_bo { struct sg_table *sgt; dma_addr_t paddr; void *vaddr; + + struct tegra_bo_tiling tiling; }; static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem) -- cgit v1.2.1 From 7678d71fb4bd6abe6ccb46afe7d90b3ed01ee936 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 3 Jun 2014 14:56:57 +0200 Subject: drm/tegra: Add SET/GET_TILING IOCTLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the tiling parameters of buffer objects can only be set at allocation time, and only a single tiled mode is supported. This new DRM_TEGRA_GEM_SET_TILING IOCTL allows more modes to be set and also allows the tiling mode to be changed after the allocation. This will enable the Tegra DRM driver to import buffers from a GPU and directly scan them out by configuring the display controller appropriately. To complement this, the DRM_TEGRA_GEM_GET_TILING IOCTL can query the current tiling mode of a buffer object. This is necessary when importing buffers via handle (as is done in Mesa for example) so that userspace can determine the proper parameters for the 2D or 3D engines. Reviewed-by: Stéphane Marchesin Tested-by: Alexandre Courbot Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.c | 95 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index fd736efd14bd..a029525b598f 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -455,6 +455,99 @@ static int tegra_get_syncpt_base(struct drm_device *drm, void *data, return 0; } + +static int tegra_gem_set_tiling(struct drm_device *drm, void *data, + struct drm_file *file) +{ + struct drm_tegra_gem_set_tiling *args = data; + enum tegra_bo_tiling_mode mode; + struct drm_gem_object *gem; + unsigned long value = 0; + struct tegra_bo *bo; + + switch (args->mode) { + case DRM_TEGRA_GEM_TILING_MODE_PITCH: + mode = TEGRA_BO_TILING_MODE_PITCH; + + if (args->value != 0) + return -EINVAL; + + break; + + case DRM_TEGRA_GEM_TILING_MODE_TILED: + mode = TEGRA_BO_TILING_MODE_TILED; + + if (args->value != 0) + return -EINVAL; + + break; + + case DRM_TEGRA_GEM_TILING_MODE_BLOCK: + mode = TEGRA_BO_TILING_MODE_BLOCK; + + if (args->value > 5) + return -EINVAL; + + value = args->value; + break; + + default: + return -EINVAL; + } + + gem = drm_gem_object_lookup(drm, file, args->handle); + if (!gem) + return -ENOENT; + + bo = to_tegra_bo(gem); + + bo->tiling.mode = mode; + bo->tiling.value = value; + + drm_gem_object_unreference(gem); + + return 0; +} + +static int tegra_gem_get_tiling(struct drm_device *drm, void *data, + struct drm_file *file) +{ + struct drm_tegra_gem_get_tiling *args = data; + struct drm_gem_object *gem; + struct tegra_bo *bo; + int err = 0; + + gem = drm_gem_object_lookup(drm, file, args->handle); + if (!gem) + return -ENOENT; + + bo = to_tegra_bo(gem); + + switch (bo->tiling.mode) { + case TEGRA_BO_TILING_MODE_PITCH: + args->mode = DRM_TEGRA_GEM_TILING_MODE_PITCH; + args->value = 0; + break; + + case TEGRA_BO_TILING_MODE_TILED: + args->mode = DRM_TEGRA_GEM_TILING_MODE_TILED; + args->value = 0; + break; + + case TEGRA_BO_TILING_MODE_BLOCK: + args->mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK; + args->value = bo->tiling.value; + break; + + default: + err = -EINVAL; + break; + } + + drm_gem_object_unreference(gem); + + return err; +} #endif static const struct drm_ioctl_desc tegra_drm_ioctls[] = { @@ -469,6 +562,8 @@ static const struct drm_ioctl_desc tegra_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, DRM_UNLOCKED), #endif }; -- cgit v1.2.1 From 7b129087874b925901def7ae507f7d9fac406211 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 10 Jun 2014 12:04:03 +0200 Subject: drm/tegra: Add SET/GET_FLAGS IOCTLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DRM_TEGRA_GEM_SET_FLAGS IOCTL can be used to set the flags of a buffer object after it has been allocated or imported. Flags associated with a buffer object can be queried using the DRM_TEGRA_GEM_GET_FLAGS IOCTL. Reviewed-by: Stéphane Marchesin Tested-by: Alexandre Courbot Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index a029525b598f..6e2e714a0649 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -548,6 +548,53 @@ static int tegra_gem_get_tiling(struct drm_device *drm, void *data, return err; } + +static int tegra_gem_set_flags(struct drm_device *drm, void *data, + struct drm_file *file) +{ + struct drm_tegra_gem_set_flags *args = data; + struct drm_gem_object *gem; + struct tegra_bo *bo; + + if (args->flags & ~DRM_TEGRA_GEM_FLAGS) + return -EINVAL; + + gem = drm_gem_object_lookup(drm, file, args->handle); + if (!gem) + return -ENOENT; + + bo = to_tegra_bo(gem); + bo->flags = 0; + + if (args->flags & DRM_TEGRA_GEM_BOTTOM_UP) + bo->flags |= TEGRA_BO_BOTTOM_UP; + + drm_gem_object_unreference(gem); + + return 0; +} + +static int tegra_gem_get_flags(struct drm_device *drm, void *data, + struct drm_file *file) +{ + struct drm_tegra_gem_get_flags *args = data; + struct drm_gem_object *gem; + struct tegra_bo *bo; + + gem = drm_gem_object_lookup(drm, file, args->handle); + if (!gem) + return -ENOENT; + + bo = to_tegra_bo(gem); + args->flags = 0; + + if (bo->flags & TEGRA_BO_BOTTOM_UP) + args->flags |= DRM_TEGRA_GEM_BOTTOM_UP; + + drm_gem_object_unreference(gem); + + return 0; +} #endif static const struct drm_ioctl_desc tegra_drm_ioctls[] = { @@ -564,6 +611,8 @@ static const struct drm_ioctl_desc tegra_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags, DRM_UNLOCKED), #endif }; -- cgit v1.2.1 From bd4f236024a8027b2d5ee9de1f823fbf07c39cef Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 3 Jun 2014 14:59:29 +0200 Subject: drm/tegra: Allow non-authenticated processes to create buffer objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This matches what other drivers do for equivalent IOCTLs. Reviewed-by: Stéphane Marchesin Tested-by: Alexandre Courbot Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 6e2e714a0649..5cba5e736130 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -599,7 +599,7 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data, static const struct drm_ioctl_desc tegra_drm_ioctls[] = { #ifdef CONFIG_DRM_TEGRA_STAGING - DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED | DRM_AUTH), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED), -- cgit v1.2.1 From 961e3beae3b29ae9463631415342244cdaf1cd47 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 10 Jun 2014 10:25:00 +0200 Subject: drm/tegra: Make job submission 64-bit safe Job submission currently relies on the fact that struct drm_tegra_reloc and struct host1x_reloc are the same size and uses a simple call to the copy_from_user() function to copy them to kernel space. This causes the handle to be stored in the buffer object field, which then needs a cast to a 32 bit integer to resolve it to a proper buffer object pointer and store it back in the buffer object field. On 64-bit architectures that will no longer work, since pointers are 64 bits wide whereas handles will remain 32 bits. This causes the sizes of both structures to because different and copying will no longer work. Fix this by adding a new function, host1x_reloc_get_user(), that copies the structures field by field. While at it, use substructures for the command and target buffers in struct host1x_reloc for better readability. Also use unsized types to make it more obvious that this isn't part of userspace ABI. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.c | 62 ++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 5cba5e736130..59736bb810cd 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -132,6 +132,45 @@ host1x_bo_lookup(struct drm_device *drm, struct drm_file *file, u32 handle) return &bo->base; } +static int host1x_reloc_copy_from_user(struct host1x_reloc *dest, + struct drm_tegra_reloc __user *src, + struct drm_device *drm, + struct drm_file *file) +{ + u32 cmdbuf, target; + int err; + + err = get_user(cmdbuf, &src->cmdbuf.handle); + if (err < 0) + return err; + + err = get_user(dest->cmdbuf.offset, &src->cmdbuf.offset); + if (err < 0) + return err; + + err = get_user(target, &src->target.handle); + if (err < 0) + return err; + + err = get_user(dest->target.offset, &src->cmdbuf.offset); + if (err < 0) + return err; + + err = get_user(dest->shift, &src->shift); + if (err < 0) + return err; + + dest->cmdbuf.bo = host1x_bo_lookup(drm, file, cmdbuf); + if (!dest->cmdbuf.bo) + return -ENOENT; + + dest->target.bo = host1x_bo_lookup(drm, file, target); + if (!dest->target.bo) + return -ENOENT; + + return 0; +} + int tegra_drm_submit(struct tegra_drm_context *context, struct drm_tegra_submit *args, struct drm_device *drm, struct drm_file *file) @@ -184,26 +223,13 @@ int tegra_drm_submit(struct tegra_drm_context *context, cmdbufs++; } - if (copy_from_user(job->relocarray, relocs, - sizeof(*relocs) * num_relocs)) { - err = -EFAULT; - goto fail; - } - + /* copy and resolve relocations from submit */ while (num_relocs--) { - struct host1x_reloc *reloc = &job->relocarray[num_relocs]; - struct host1x_bo *cmdbuf, *target; - - cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf); - target = host1x_bo_lookup(drm, file, (u32)reloc->target); - - reloc->cmdbuf = cmdbuf; - reloc->target = target; - - if (!reloc->target || !reloc->cmdbuf) { - err = -ENOENT; + err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs], + &relocs[num_relocs], drm, + file); + if (err < 0) goto fail; - } } if (copy_from_user(job->waitchk, waitchks, -- cgit v1.2.1 From 054b1bd16138f92cd690324958e48f790a4cd234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Marchesin?= Date: Thu, 19 Jun 2014 18:18:29 -0700 Subject: drm/tegra: sor - Use bits-per-color from panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change uses the value of bits-per-color from panel to remove one more hardcoded value. Signed-off-by: Stéphane Marchesin Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 64f57fa9b8f6..479da1b210b4 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -525,7 +525,7 @@ static int tegra_output_sor_enable(struct tegra_output *output) dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); memset(&config, 0, sizeof(config)); - config.bits_per_pixel = 24; /* XXX: don't hardcode? */ + config.bits_per_pixel = output->connector.display_info.bpc * 3; err = tegra_sor_calc_config(sor, mode, &config, &link); if (err < 0) -- cgit v1.2.1 From 3f4f3b5fede02d338383619ff57744a8415ccceb Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 7 Jul 2014 15:35:06 +0200 Subject: drm/tegra: sor - Configure proper sync polarities Program the sync signal polarities according to the display mode. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 479da1b210b4..6cb861bf1e03 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -815,12 +815,22 @@ static int tegra_output_sor_enable(struct tegra_output *output) * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete * raster, associate with display controller) */ - value = SOR_STATE_ASY_VSYNCPOL | - SOR_STATE_ASY_HSYNCPOL | - SOR_STATE_ASY_PROTOCOL_DP_A | + value = SOR_STATE_ASY_PROTOCOL_DP_A | SOR_STATE_ASY_CRC_MODE_COMPLETE | SOR_STATE_ASY_OWNER(dc->pipe + 1); + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + value &= ~SOR_STATE_ASY_HSYNCPOL; + + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + value |= SOR_STATE_ASY_HSYNCPOL; + + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + value &= ~SOR_STATE_ASY_VSYNCPOL; + + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + value |= SOR_STATE_ASY_VSYNCPOL; + switch (config.bits_per_pixel) { case 24: value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; -- cgit v1.2.1 From d1f3e1e0b38d49cbb996dcf0fde5b5205d12a23d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 11 Jul 2014 08:29:14 +0200 Subject: drm/tegra: Properly align stride for framebuffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tegra20 and Tegra30 both required the buffer line stride to be aligned on 8 byte boundaries. Tegra114 and Tegra124 increased the alignment to 64 bytes. Introduce a parameter to specify the alignment requirements for each display controller and round up the pitch of newly allocated framebuffers appropriately. Originally-by: Stéphane Marchesin Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 19 +++++++++++++++++++ drivers/gpu/drm/tegra/drm.h | 2 ++ drivers/gpu/drm/tegra/fb.c | 4 +++- drivers/gpu/drm/tegra/gem.c | 3 +++ 4 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index afcca04f5367..8886907d44b0 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -19,6 +19,7 @@ struct tegra_dc_soc_info { bool supports_interlacing; bool supports_cursor; bool supports_block_linear; + unsigned int pitch_align; }; struct tegra_plane { @@ -1283,12 +1284,20 @@ static int tegra_dc_init(struct host1x_client *client) { struct drm_device *drm = dev_get_drvdata(client->parent); struct tegra_dc *dc = host1x_client_to_dc(client); + struct tegra_drm *tegra = drm->dev_private; int err; drm_crtc_init(drm, &dc->base, &tegra_crtc_funcs); drm_mode_crtc_set_gamma_size(&dc->base, 256); drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); + /* + * Keep track of the minimum pitch alignment across all display + * controllers. + */ + if (dc->soc->pitch_align > tegra->pitch_align) + tegra->pitch_align = dc->soc->pitch_align; + err = tegra_dc_rgb_init(drm, dc); if (err < 0 && err != -ENODEV) { dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); @@ -1347,18 +1356,28 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, .supports_block_linear = false, + .pitch_align = 8, }; static const struct tegra_dc_soc_info tegra30_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, .supports_block_linear = false, + .pitch_align = 8, +}; + +static const struct tegra_dc_soc_info tegra114_dc_soc_info = { + .supports_interlacing = false, + .supports_cursor = false, + .supports_block_linear = false, + .pitch_align = 64, }; static const struct tegra_dc_soc_info tegra124_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, .supports_block_linear = true, + .pitch_align = 64, }; static const struct of_device_id tegra_dc_of_match[] = { diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 96d754e7b3eb..e89c70fa82d5 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -45,6 +45,8 @@ struct tegra_drm { #ifdef CONFIG_DRM_TEGRA_FBDEV struct tegra_fbdev *fbdev; #endif + + unsigned int pitch_align; }; struct tegra_drm_client; diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 7790d43ad082..3513d12d5aa1 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -194,6 +194,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { struct tegra_fbdev *fbdev = to_tegra_fbdev(helper); + struct tegra_drm *tegra = helper->dev->dev_private; struct drm_device *drm = helper->dev; struct drm_mode_fb_cmd2 cmd = { 0 }; unsigned int bytes_per_pixel; @@ -208,7 +209,8 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, cmd.width = sizes->surface_width; cmd.height = sizes->surface_height; - cmd.pitches[0] = sizes->surface_width * bytes_per_pixel; + cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel, + tegra->pitch_align); cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index c1e4e8b6e5ca..2545c7a468a2 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -16,6 +16,7 @@ #include #include +#include "drm.h" #include "gem.h" static inline struct tegra_bo *host1x_to_tegra_bo(struct host1x_bo *bo) @@ -259,8 +260,10 @@ int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, struct drm_mode_create_dumb *args) { int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + struct tegra_drm *tegra = drm->dev_private; struct tegra_bo *bo; + min_pitch = round_up(min_pitch, tegra->pitch_align); if (args->pitch < min_pitch) args->pitch = min_pitch; -- cgit v1.2.1 From 5482d75a6597de97f79255a257c486a6960c6c65 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 11 Jul 2014 08:39:03 +0200 Subject: drm/tegra: dc - Reset controller on driver remove Since the device will no longer be used, may as well keep it in reset to potentially save some power and make sure it is in a clean state the next time it's probed. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 8886907d44b0..b2065d9e13d4 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1521,6 +1521,7 @@ static int tegra_dc_remove(struct platform_device *pdev) return err; } + reset_control_assert(dc->rst); clk_disable_unprepare(dc->clk); return 0; -- cgit v1.2.1 From ef70728c7a6571a1a7115031e932b811f1740b2e Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 18 Jun 2014 16:21:55 -0600 Subject: drm/tegra: add MODULE_DEVICE_TABLEs When tegra-drm.ko is built as a module, these MODULE_DEVICE_TABLEs allow the module to be auto-loaded since the module will match the devices instantiated from device tree. (Notes for stable: in 3.14+, just git rm any conflicting file, since they are added in later kernels. For 3.13 and below, manual merging will be needed) Cc: Signed-off-by: Stephen Warren Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 1 + drivers/gpu/drm/tegra/dpaux.c | 1 + drivers/gpu/drm/tegra/dsi.c | 1 + drivers/gpu/drm/tegra/gr2d.c | 1 + drivers/gpu/drm/tegra/gr3d.c | 1 + drivers/gpu/drm/tegra/hdmi.c | 1 + drivers/gpu/drm/tegra/sor.c | 1 + 7 files changed, 7 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index b2065d9e13d4..6553fd238685 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1394,6 +1394,7 @@ static const struct of_device_id tegra_dc_of_match[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, tegra_dc_of_match); static int tegra_dc_parse_dt(struct tegra_dc *dc) { diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 3f132e356e9c..708f783ead47 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -382,6 +382,7 @@ static const struct of_device_id tegra_dpaux_of_match[] = { { .compatible = "nvidia,tegra124-dpaux", }, { }, }; +MODULE_DEVICE_TABLE(of, tegra_dpaux_of_match); struct platform_driver tegra_dpaux_driver = { .driver = { diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index eadfeaf9e1eb..f7874458926a 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -983,6 +983,7 @@ static const struct of_device_id tegra_dsi_of_match[] = { { .compatible = "nvidia,tegra114-dsi", }, { }, }; +MODULE_DEVICE_TABLE(of, tegra_dsi_of_match); struct platform_driver tegra_dsi_driver = { .driver = { diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 7c53941f2a9e..02cd3e37a6ec 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -121,6 +121,7 @@ static const struct of_device_id gr2d_match[] = { { .compatible = "nvidia,tegra20-gr2d" }, { }, }; +MODULE_DEVICE_TABLE(of, gr2d_match); static const u32 gr2d_addr_regs[] = { GR2D_UA_BASE_ADDR, diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index 30f5ba9bd6d0..2bea2b2d204e 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -130,6 +130,7 @@ static const struct of_device_id tegra_gr3d_match[] = { { .compatible = "nvidia,tegra20-gr3d" }, { } }; +MODULE_DEVICE_TABLE(of, tegra_gr3d_match); static const u32 gr3d_addr_regs[] = { GR3D_IDX_ATTRIBUTE( 0), diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index ba067bb767e3..ffe26547328d 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1450,6 +1450,7 @@ static const struct of_device_id tegra_hdmi_of_match[] = { { .compatible = "nvidia,tegra20-hdmi", .data = &tegra20_hdmi_config }, { }, }; +MODULE_DEVICE_TABLE(of, tegra_hdmi_of_match); static int tegra_hdmi_probe(struct platform_device *pdev) { diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 6cb861bf1e03..0410e467b828 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1465,6 +1465,7 @@ static const struct of_device_id tegra_sor_of_match[] = { { .compatible = "nvidia,tegra124-sor", }, { }, }; +MODULE_DEVICE_TABLE(of, tegra_sor_of_match); struct platform_driver tegra_sor_driver = { .driver = { -- cgit v1.2.1