diff options
Diffstat (limited to 'drivers/gpu/drm/tegra')
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 113 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dc.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/fb.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gr2d.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gr3d.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.c | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/plane.c | 32 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/vic.c | 4 |
11 files changed, 224 insertions, 28 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index c9385cfd0fc1..f9120dc24682 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -832,10 +832,14 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, return &plane->base; } -static const u32 tegra_cursor_plane_formats[] = { +static const u32 tegra_legacy_cursor_plane_formats[] = { DRM_FORMAT_RGBA8888, }; +static const u32 tegra_cursor_plane_formats[] = { + DRM_FORMAT_ARGB8888, +}; + static int tegra_cursor_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -875,12 +879,24 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane, plane); struct tegra_plane_state *tegra_plane_state = to_tegra_plane_state(new_state); struct tegra_dc *dc = to_tegra_dc(new_state->crtc); - u32 value = CURSOR_CLIP_DISPLAY; + struct tegra_drm *tegra = plane->dev->dev_private; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + u64 dma_mask = *dc->dev->dma_mask; +#endif + unsigned int x, y; + u32 value = 0; /* rien ne va plus */ if (!new_state->crtc || !new_state->fb) return; + /* + * Legacy display supports hardware clipping of the cursor, but + * nvdisplay relies on software to clip the cursor to the screen. + */ + if (!dc->soc->has_nvdisplay) + value |= CURSOR_CLIP_DISPLAY; + switch (new_state->crtc_w) { case 32: value |= CURSOR_SIZE_32x32; @@ -908,7 +924,7 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane, tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - value = (tegra_plane_state->iova[0] >> 32) & 0x3; + value = (tegra_plane_state->iova[0] >> 32) & (dma_mask >> 32); tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI); #endif @@ -920,15 +936,39 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane, value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL); value &= ~CURSOR_DST_BLEND_MASK; value &= ~CURSOR_SRC_BLEND_MASK; - value |= CURSOR_MODE_NORMAL; + + if (dc->soc->has_nvdisplay) + value &= ~CURSOR_COMPOSITION_MODE_XOR; + else + value |= CURSOR_MODE_NORMAL; + value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC; value |= CURSOR_SRC_BLEND_K1_TIMES_SRC; value |= CURSOR_ALPHA; tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL); + /* nvdisplay relies on software for clipping */ + if (dc->soc->has_nvdisplay) { + struct drm_rect src; + + x = new_state->dst.x1; + y = new_state->dst.y1; + + drm_rect_fp_to_int(&src, &new_state->src); + + value = (src.y1 & tegra->vmask) << 16 | (src.x1 & tegra->hmask); + tegra_dc_writel(dc, value, DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR); + + value = (drm_rect_height(&src) & tegra->vmask) << 16 | + (drm_rect_width(&src) & tegra->hmask); + tegra_dc_writel(dc, value, DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR); + } else { + x = new_state->crtc_x; + y = new_state->crtc_y; + } + /* position the cursor */ - value = (new_state->crtc_y & 0x3fff) << 16 | - (new_state->crtc_x & 0x3fff); + value = ((y & tegra->vmask) << 16) | (x & tegra->hmask); tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION); } @@ -982,8 +1022,13 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm, plane->index = 6; plane->dc = dc; - num_formats = ARRAY_SIZE(tegra_cursor_plane_formats); - formats = tegra_cursor_plane_formats; + if (!dc->soc->has_nvdisplay) { + num_formats = ARRAY_SIZE(tegra_legacy_cursor_plane_formats); + formats = tegra_legacy_cursor_plane_formats; + } else { + num_formats = ARRAY_SIZE(tegra_cursor_plane_formats); + formats = tegra_cursor_plane_formats; + } err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, &tegra_plane_funcs, formats, @@ -2035,6 +2080,16 @@ static bool tegra_dc_has_window_groups(struct tegra_dc *dc) return false; } +static int tegra_dc_early_init(struct host1x_client *client) +{ + struct drm_device *drm = dev_get_drvdata(client->host); + struct tegra_drm *tegra = drm->dev_private; + + tegra->num_crtcs++; + + return 0; +} + static int tegra_dc_init(struct host1x_client *client) { struct drm_device *drm = dev_get_drvdata(client->host); @@ -2046,6 +2101,12 @@ static int tegra_dc_init(struct host1x_client *client) int err; /* + * DC has been reset by now, so VBLANK syncpoint can be released + * for general use. + */ + host1x_syncpt_release_vblank_reservation(client, 26 + dc->pipe); + + /* * XXX do not register DCs with no window groups because we cannot * assign a primary plane to them, which in turn will cause KMS to * crash. @@ -2111,6 +2172,12 @@ static int tegra_dc_init(struct host1x_client *client) if (dc->soc->pitch_align > tegra->pitch_align) tegra->pitch_align = dc->soc->pitch_align; + /* track maximum resolution */ + if (dc->soc->has_nvdisplay) + drm->mode_config.max_width = drm->mode_config.max_height = 16384; + else + drm->mode_config.max_width = drm->mode_config.max_height = 4096; + err = tegra_dc_rgb_init(drm, dc); if (err < 0 && err != -ENODEV) { dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); @@ -2141,7 +2208,7 @@ cleanup: drm_plane_cleanup(primary); host1x_client_iommu_detach(client); - host1x_syncpt_free(dc->syncpt); + host1x_syncpt_put(dc->syncpt); return err; } @@ -2166,7 +2233,17 @@ static int tegra_dc_exit(struct host1x_client *client) } host1x_client_iommu_detach(client); - host1x_syncpt_free(dc->syncpt); + host1x_syncpt_put(dc->syncpt); + + return 0; +} + +static int tegra_dc_late_exit(struct host1x_client *client) +{ + struct drm_device *drm = dev_get_drvdata(client->host); + struct tegra_drm *tegra = drm->dev_private; + + tegra->num_crtcs--; return 0; } @@ -2235,8 +2312,10 @@ put_rpm: } static const struct host1x_client_ops dc_client_ops = { + .early_init = tegra_dc_early_init, .init = tegra_dc_init, .exit = tegra_dc_exit, + .late_exit = tegra_dc_late_exit, .suspend = tegra_dc_runtime_suspend, .resume = tegra_dc_runtime_resume, }; @@ -2246,6 +2325,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, .supports_block_linear = false, + .supports_sector_layout = false, .has_legacy_blending = true, .pitch_align = 8, .has_powergate = false, @@ -2265,6 +2345,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, .supports_block_linear = false, + .supports_sector_layout = false, .has_legacy_blending = true, .pitch_align = 8, .has_powergate = false, @@ -2284,6 +2365,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, .supports_block_linear = false, + .supports_sector_layout = false, .has_legacy_blending = true, .pitch_align = 64, .has_powergate = true, @@ -2303,6 +2385,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, .supports_block_linear = true, + .supports_sector_layout = false, .has_legacy_blending = false, .pitch_align = 64, .has_powergate = true, @@ -2322,6 +2405,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, .supports_block_linear = true, + .supports_sector_layout = false, .has_legacy_blending = false, .pitch_align = 64, .has_powergate = true, @@ -2375,6 +2459,7 @@ static const struct tegra_dc_soc_info tegra186_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, .supports_block_linear = true, + .supports_sector_layout = false, .has_legacy_blending = false, .pitch_align = 64, .has_powergate = false, @@ -2423,6 +2508,7 @@ static const struct tegra_dc_soc_info tegra194_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, .supports_block_linear = true, + .supports_sector_layout = true, .has_legacy_blending = false, .pitch_align = 64, .has_powergate = false, @@ -2532,9 +2618,16 @@ static int tegra_dc_couple(struct tegra_dc *dc) static int tegra_dc_probe(struct platform_device *pdev) { + u64 dma_mask = dma_get_mask(pdev->dev.parent); struct tegra_dc *dc; int err; + err = dma_coerce_mask_and_coherent(&pdev->dev, dma_mask); + if (err < 0) { + dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); + return err; + } + dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL); if (!dc) return -ENOMEM; diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 051d03dcb9b0..29f19c3c6149 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -52,6 +52,7 @@ struct tegra_dc_soc_info { bool supports_interlacing; bool supports_cursor; bool supports_block_linear; + bool supports_sector_layout; bool has_legacy_blending; unsigned int pitch_align; bool has_powergate; @@ -511,6 +512,8 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc); #define DC_DISP_CURSOR_START_ADDR_HI 0x4ec #define DC_DISP_BLEND_CURSOR_CONTROL 0x4f1 +#define CURSOR_COMPOSITION_MODE_BLEND (0 << 25) +#define CURSOR_COMPOSITION_MODE_XOR (1 << 25) #define CURSOR_MODE_LEGACY (0 << 24) #define CURSOR_MODE_NORMAL (1 << 24) #define CURSOR_DST_BLEND_ZERO (0 << 16) @@ -705,6 +708,9 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc); #define PROTOCOL_MASK (0xf << 8) #define PROTOCOL_SINGLE_TMDS_A (0x1 << 8) +#define DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR 0x442 +#define DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR 0x446 + #define DC_WIN_CORE_WINDOWGROUP_SET_CONTROL 0x702 #define OWNER_MASK (0xf << 0) #define OWNER(x) (((x) & 0xf) << 0) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 90709c38c993..0c350b0daab4 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -174,7 +174,7 @@ int tegra_drm_submit(struct tegra_drm_context *context, struct drm_tegra_syncpt syncpt; struct host1x *host1x = dev_get_drvdata(drm->dev->parent); struct drm_gem_object **refs; - struct host1x_syncpt *sp; + struct host1x_syncpt *sp = NULL; struct host1x_job *job; unsigned int num_refs; int err; @@ -301,8 +301,8 @@ int tegra_drm_submit(struct tegra_drm_context *context, goto fail; } - /* check whether syncpoint ID is valid */ - sp = host1x_syncpt_get(host1x, syncpt.id); + /* Syncpoint ref will be dropped on job release. */ + sp = host1x_syncpt_get_by_id(host1x, syncpt.id); if (!sp) { err = -ENOENT; goto fail; @@ -311,7 +311,7 @@ int tegra_drm_submit(struct tegra_drm_context *context, job->is_addr_reg = context->client->ops->is_addr_reg; job->is_valid_class = context->client->ops->is_valid_class; job->syncpt_incrs = syncpt.incrs; - job->syncpt_id = syncpt.id; + job->syncpt = sp; job->timeout = 10000; if (args->timeout && args->timeout < 10000) @@ -383,7 +383,7 @@ static int tegra_syncpt_read(struct drm_device *drm, void *data, struct drm_tegra_syncpt_read *args = data; struct host1x_syncpt *sp; - sp = host1x_syncpt_get(host, args->id); + sp = host1x_syncpt_get_by_id_noref(host, args->id); if (!sp) return -EINVAL; @@ -398,7 +398,7 @@ static int tegra_syncpt_incr(struct drm_device *drm, void *data, struct drm_tegra_syncpt_incr *args = data; struct host1x_syncpt *sp; - sp = host1x_syncpt_get(host1x, args->id); + sp = host1x_syncpt_get_by_id_noref(host1x, args->id); if (!sp) return -EINVAL; @@ -412,7 +412,7 @@ static int tegra_syncpt_wait(struct drm_device *drm, void *data, struct drm_tegra_syncpt_wait *args = data; struct host1x_syncpt *sp; - sp = host1x_syncpt_get(host1x, args->id); + sp = host1x_syncpt_get_by_id_noref(host1x, args->id); if (!sp) return -EINVAL; @@ -1121,9 +1121,8 @@ static int host1x_drm_probe(struct host1x_device *dev) drm->mode_config.min_width = 0; drm->mode_config.min_height = 0; - - drm->mode_config.max_width = 4096; - drm->mode_config.max_height = 4096; + drm->mode_config.max_width = 0; + drm->mode_config.max_height = 0; drm->mode_config.allow_fb_modifiers = true; @@ -1142,6 +1141,14 @@ static int host1x_drm_probe(struct host1x_device *dev) if (err < 0) goto fbdev; + /* + * Now that all display controller have been initialized, the maximum + * supported resolution is known and the bitmask for horizontal and + * vertical bitfields can be computed. + */ + tegra->hmask = drm->mode_config.max_width - 1; + tegra->vmask = drm->mode_config.max_height - 1; + if (tegra->use_explicit_iommu) { u64 carveout_start, carveout_end, gem_start, gem_end; u64 dma_mask = dma_get_mask(&dev->dev); diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index f38de08e0c95..87df251c1fcf 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -24,6 +24,9 @@ #include "hub.h" #include "trace.h" +/* XXX move to include/uapi/drm/drm_fourcc.h? */ +#define DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT BIT(22) + struct reset_control; #ifdef CONFIG_DRM_FBDEV_EMULATION @@ -54,7 +57,9 @@ struct tegra_drm { struct tegra_fbdev *fbdev; #endif + unsigned int hmask, vmask; unsigned int pitch_align; + unsigned int num_crtcs; struct tegra_display_hub *hub; }; diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 01939c57fc74..cae8b8cbe9dd 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -44,6 +44,15 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, { uint64_t modifier = framebuffer->modifier; + if ((modifier >> 56) == DRM_FORMAT_MOD_VENDOR_NVIDIA) { + if ((modifier & DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT) == 0) + tiling->sector_layout = TEGRA_BO_SECTOR_LAYOUT_TEGRA; + else + tiling->sector_layout = TEGRA_BO_SECTOR_LAYOUT_GPU; + + modifier &= ~DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT; + } + switch (modifier) { case DRM_FORMAT_MOD_LINEAR: tiling->mode = TEGRA_BO_TILING_MODE_PITCH; @@ -86,6 +95,7 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, break; default: + DRM_DEBUG_KMS("unknown format modifier: %llx\n", modifier); return -EINVAL; } diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index fafb5724499b..c15fd99d6cb2 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h @@ -21,9 +21,15 @@ enum tegra_bo_tiling_mode { TEGRA_BO_TILING_MODE_BLOCK, }; +enum tegra_bo_sector_layout { + TEGRA_BO_SECTOR_LAYOUT_TEGRA, + TEGRA_BO_SECTOR_LAYOUT_GPU, +}; + struct tegra_bo_tiling { enum tegra_bo_tiling_mode mode; unsigned long value; + enum tegra_bo_sector_layout sector_layout; }; struct tegra_bo { diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index adbe2ddcda19..de288cba3905 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -67,7 +67,7 @@ static int gr2d_init(struct host1x_client *client) detach: host1x_client_iommu_detach(client); free: - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); put: host1x_channel_put(gr2d->channel); return err; @@ -86,7 +86,7 @@ static int gr2d_exit(struct host1x_client *client) return err; host1x_client_iommu_detach(client); - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(gr2d->channel); return 0; diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index b0b8154e8104..24442ade0da3 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -76,7 +76,7 @@ static int gr3d_init(struct host1x_client *client) detach: host1x_client_iommu_detach(client); free: - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); put: host1x_channel_put(gr3d->channel); return err; @@ -94,7 +94,7 @@ static int gr3d_exit(struct host1x_client *client) return err; host1x_client_iommu_detach(client); - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(gr3d->channel); return 0; diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 8e6d329d062b..79bff8b48271 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -55,6 +55,18 @@ static const u64 tegra_shared_plane_modifiers[] = { DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3), DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4), DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5), + /* + * The GPU sector layout is only supported on Tegra194, but these will + * be filtered out later on by ->format_mod_supported() on SoCs where + * it isn't supported. + */ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + /* sentinel */ DRM_FORMAT_MOD_INVALID }; @@ -366,6 +378,12 @@ static int tegra_shared_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } + if (tiling->sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU && + !dc->soc->supports_sector_layout) { + DRM_ERROR("hardware doesn't support GPU sector layout\n"); + return -EINVAL; + } + /* * Tegra doesn't support different strides for U and V planes so we * error out if the user tries to display a framebuffer with such a @@ -485,6 +503,16 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, base = tegra_plane_state->iova[0] + fb->offsets[0]; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + /* + * Physical address bit 39 in Tegra194 is used as a switch for special + * logic that swizzles the memory using either the legacy Tegra or the + * dGPU sector layout. + */ + if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU) + base |= BIT(39); +#endif + tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH); tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS); @@ -562,9 +590,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; struct tegra_drm *tegra = drm->dev_private; struct tegra_display_hub *hub = tegra->hub; - /* planes can be assigned to arbitrary CRTCs */ - unsigned int possible_crtcs = 0x7; struct tegra_shared_plane *plane; + unsigned int possible_crtcs; unsigned int num_formats; const u64 *modifiers; struct drm_plane *p; @@ -583,6 +610,9 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, p = &plane->base.base; + /* planes can be assigned to arbitrary CRTCs */ + possible_crtcs = BIT(tegra->num_crtcs) - 1; + num_formats = ARRAY_SIZE(tegra_shared_plane_formats); formats = tegra_shared_plane_formats; modifiers = tegra_shared_plane_modifiers; @@ -848,12 +878,19 @@ static const struct host1x_client_ops tegra_display_hub_ops = { static int tegra_display_hub_probe(struct platform_device *pdev) { + u64 dma_mask = dma_get_mask(pdev->dev.parent); struct device_node *child = NULL; struct tegra_display_hub *hub; struct clk *clk; unsigned int i; int err; + err = dma_coerce_mask_and_coherent(&pdev->dev, dma_mask); + if (err < 0) { + dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); + return err; + } + hub = devm_kzalloc(&pdev->dev, sizeof(*hub), GFP_KERNEL); if (!hub) return -ENOMEM; diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index 19e8847a164b..2e11b4b1f702 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -83,6 +83,22 @@ static void tegra_plane_atomic_destroy_state(struct drm_plane *plane, kfree(state); } +static bool tegra_plane_supports_sector_layout(struct drm_plane *plane) +{ + struct drm_crtc *crtc; + + drm_for_each_crtc(crtc, plane->dev) { + if (plane->possible_crtcs & drm_crtc_mask(crtc)) { + struct tegra_dc *dc = to_tegra_dc(crtc); + + if (!dc->soc->supports_sector_layout) + return false; + } + } + + return true; +} + static bool tegra_plane_format_mod_supported(struct drm_plane *plane, uint32_t format, uint64_t modifier) @@ -92,6 +108,14 @@ static bool tegra_plane_format_mod_supported(struct drm_plane *plane, if (modifier == DRM_FORMAT_MOD_LINEAR) return true; + /* check for the sector layout bit */ + if ((modifier >> 56) == DRM_FORMAT_MOD_VENDOR_NVIDIA) { + if (modifier & DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT) { + if (!tegra_plane_supports_sector_layout(plane)) + return false; + } + } + if (info->num_planes == 1) return true; @@ -119,6 +143,14 @@ static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state) dma_addr_t phys_addr, *phys; struct sg_table *sgt; + /* + * If we're not attached to a domain, we already stored the + * physical address when the buffer was allocated. If we're + * part of a group that's shared between all display + * controllers, we've also already mapped the framebuffer + * through the SMMU. In both cases we can short-circuit the + * code below and retrieve the stored IOV address. + */ if (!domain || dc->client.group) phys = &phys_addr; else diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 77e128832920..72aea1cc0cfa 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -214,7 +214,7 @@ static int vic_init(struct host1x_client *client) return 0; free_syncpt: - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); free_channel: host1x_channel_put(vic->channel); detach: @@ -238,7 +238,7 @@ static int vic_exit(struct host1x_client *client) if (err < 0) return err; - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(vic->channel); host1x_client_iommu_detach(client); |