2019-06-04 10:11:33 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2012-11-15 21:28:22 +00:00
|
|
|
/*
|
2013-03-22 16:34:08 +02:00
|
|
|
* Copyright (C) 2012-2013 Avionic Design GmbH
|
2012-11-15 21:28:22 +00:00
|
|
|
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
|
|
|
*
|
2022-08-02 02:04:02 +02:00
|
|
|
* Based on the KMS/FB DMA helpers
|
2020-04-16 12:30:55 +02:00
|
|
|
* Copyright (C) 2012 Analog Devices Inc.
|
2012-11-15 21:28:22 +00:00
|
|
|
*/
|
|
|
|
|
2015-08-11 13:11:49 +02:00
|
|
|
#include <linux/console.h>
|
|
|
|
|
2019-08-04 11:41:30 +02:00
|
|
|
#include <drm/drm_fourcc.h>
|
2022-06-14 12:54:49 +03:00
|
|
|
#include <drm/drm_framebuffer.h>
|
2018-03-30 15:11:26 +01:00
|
|
|
#include <drm/drm_gem_framebuffer_helper.h>
|
2019-01-17 22:03:34 +01:00
|
|
|
#include <drm/drm_modeset_helper.h>
|
2013-03-22 16:34:08 +02:00
|
|
|
|
2019-08-04 11:41:30 +02:00
|
|
|
#include "drm.h"
|
|
|
|
#include "gem.h"
|
|
|
|
|
2013-03-22 16:34:08 +02:00
|
|
|
struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
|
|
|
|
unsigned int index)
|
|
|
|
{
|
2018-03-30 15:11:26 +01:00
|
|
|
return to_tegra_bo(drm_gem_fb_get_obj(framebuffer, index));
|
2013-03-22 16:34:08 +02:00
|
|
|
}
|
|
|
|
|
2013-10-07 09:47:58 +02:00
|
|
|
bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer)
|
|
|
|
{
|
2018-03-30 15:11:26 +01:00
|
|
|
struct tegra_bo *bo = tegra_fb_get_plane(framebuffer, 0);
|
2013-10-07 09:47:58 +02:00
|
|
|
|
2018-03-30 15:11:26 +01:00
|
|
|
if (bo->flags & TEGRA_BO_BOTTOM_UP)
|
2013-10-07 09:47:58 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-03 14:48:12 +02:00
|
|
|
int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
|
|
|
|
struct tegra_bo_tiling *tiling)
|
2013-10-04 22:34:01 +02:00
|
|
|
{
|
2018-03-30 15:11:26 +01:00
|
|
|
uint64_t modifier = framebuffer->modifier;
|
2016-11-08 16:50:42 +09:00
|
|
|
|
2021-06-10 13:12:36 +02:00
|
|
|
if (fourcc_mod_is_vendor(modifier, NVIDIA)) {
|
2021-03-26 15:51:39 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
drm/tegra: Sanitize format modifiers
The existing format modifier definitions were merged prematurely, and
recent work has unveiled that the definitions are suboptimal in several
ways:
- The format specifiers, except for one, are not Tegra specific, but
the names don't reflect that.
- The number space is split into two, reserving 32 bits for some
"parameter" which most of the modifiers are not going to have.
- Symbolic names for the modifiers are not using the standard
DRM_FORMAT_MOD_* prefix, which makes them awkward to use.
- The vendor prefix NV is somewhat ambiguous.
Fortunately, nobody's started using these modifiers, so we can still fix
the above issues. Do so by using the standard prefix. Also, remove TEGRA
from the name of those modifiers that exist on NVIDIA GPUs as well. In
case of the block linear modifiers, make the "parameter" smaller (4
bits, though only 6 values are valid) and don't let that leak into any
of the other modifiers.
Finally, also use the more canonical NVIDIA instead of the ambiguous NV
prefix.
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Thierry Reding <treding@nvidia.com>
2017-10-12 16:39:20 +02:00
|
|
|
switch (modifier) {
|
2018-03-15 16:45:45 +01:00
|
|
|
case DRM_FORMAT_MOD_LINEAR:
|
|
|
|
tiling->mode = TEGRA_BO_TILING_MODE_PITCH;
|
|
|
|
tiling->value = 0;
|
|
|
|
break;
|
|
|
|
|
drm/tegra: Sanitize format modifiers
The existing format modifier definitions were merged prematurely, and
recent work has unveiled that the definitions are suboptimal in several
ways:
- The format specifiers, except for one, are not Tegra specific, but
the names don't reflect that.
- The number space is split into two, reserving 32 bits for some
"parameter" which most of the modifiers are not going to have.
- Symbolic names for the modifiers are not using the standard
DRM_FORMAT_MOD_* prefix, which makes them awkward to use.
- The vendor prefix NV is somewhat ambiguous.
Fortunately, nobody's started using these modifiers, so we can still fix
the above issues. Do so by using the standard prefix. Also, remove TEGRA
from the name of those modifiers that exist on NVIDIA GPUs as well. In
case of the block linear modifiers, make the "parameter" smaller (4
bits, though only 6 values are valid) and don't let that leak into any
of the other modifiers.
Finally, also use the more canonical NVIDIA instead of the ambiguous NV
prefix.
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Thierry Reding <treding@nvidia.com>
2017-10-12 16:39:20 +02:00
|
|
|
case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
|
2016-11-08 16:50:42 +09:00
|
|
|
tiling->mode = TEGRA_BO_TILING_MODE_TILED;
|
|
|
|
tiling->value = 0;
|
|
|
|
break;
|
|
|
|
|
drm/tegra: Sanitize format modifiers
The existing format modifier definitions were merged prematurely, and
recent work has unveiled that the definitions are suboptimal in several
ways:
- The format specifiers, except for one, are not Tegra specific, but
the names don't reflect that.
- The number space is split into two, reserving 32 bits for some
"parameter" which most of the modifiers are not going to have.
- Symbolic names for the modifiers are not using the standard
DRM_FORMAT_MOD_* prefix, which makes them awkward to use.
- The vendor prefix NV is somewhat ambiguous.
Fortunately, nobody's started using these modifiers, so we can still fix
the above issues. Do so by using the standard prefix. Also, remove TEGRA
from the name of those modifiers that exist on NVIDIA GPUs as well. In
case of the block linear modifiers, make the "parameter" smaller (4
bits, though only 6 values are valid) and don't let that leak into any
of the other modifiers.
Finally, also use the more canonical NVIDIA instead of the ambiguous NV
prefix.
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Thierry Reding <treding@nvidia.com>
2017-10-12 16:39:20 +02:00
|
|
|
case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0):
|
2016-11-08 16:50:42 +09:00
|
|
|
tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
|
drm/tegra: Sanitize format modifiers
The existing format modifier definitions were merged prematurely, and
recent work has unveiled that the definitions are suboptimal in several
ways:
- The format specifiers, except for one, are not Tegra specific, but
the names don't reflect that.
- The number space is split into two, reserving 32 bits for some
"parameter" which most of the modifiers are not going to have.
- Symbolic names for the modifiers are not using the standard
DRM_FORMAT_MOD_* prefix, which makes them awkward to use.
- The vendor prefix NV is somewhat ambiguous.
Fortunately, nobody's started using these modifiers, so we can still fix
the above issues. Do so by using the standard prefix. Also, remove TEGRA
from the name of those modifiers that exist on NVIDIA GPUs as well. In
case of the block linear modifiers, make the "parameter" smaller (4
bits, though only 6 values are valid) and don't let that leak into any
of the other modifiers.
Finally, also use the more canonical NVIDIA instead of the ambiguous NV
prefix.
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Thierry Reding <treding@nvidia.com>
2017-10-12 16:39:20 +02:00
|
|
|
tiling->value = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1):
|
|
|
|
tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
|
|
|
|
tiling->value = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2):
|
|
|
|
tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
|
|
|
|
tiling->value = 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3):
|
|
|
|
tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
|
|
|
|
tiling->value = 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4):
|
|
|
|
tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
|
|
|
|
tiling->value = 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5):
|
|
|
|
tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
|
|
|
|
tiling->value = 5;
|
2016-11-08 16:50:42 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2021-03-26 15:51:35 +01:00
|
|
|
DRM_DEBUG_KMS("unknown format modifier: %llx\n", modifier);
|
2018-03-15 16:45:45 +01:00
|
|
|
return -EINVAL;
|
2016-11-08 16:50:42 +09:00
|
|
|
}
|
2013-10-04 22:34:01 +02:00
|
|
|
|
2014-06-03 14:48:12 +02:00
|
|
|
return 0;
|
2013-10-04 22:34:01 +02:00
|
|
|
}
|
|
|
|
|
2015-12-15 12:21:13 +01:00
|
|
|
static const struct drm_framebuffer_funcs tegra_fb_funcs = {
|
2018-03-30 15:11:29 +01:00
|
|
|
.destroy = drm_gem_fb_destroy,
|
2018-03-30 15:11:26 +01:00
|
|
|
.create_handle = drm_gem_fb_create_handle,
|
2013-03-22 16:34:08 +02:00
|
|
|
};
|
|
|
|
|
2023-03-30 10:36:05 +02:00
|
|
|
struct drm_framebuffer *tegra_fb_alloc(struct drm_device *drm,
|
2025-07-01 12:07:19 +03:00
|
|
|
const struct drm_format_info *info,
|
2023-03-30 10:36:05 +02:00
|
|
|
const struct drm_mode_fb_cmd2 *mode_cmd,
|
|
|
|
struct tegra_bo **planes,
|
|
|
|
unsigned int num_planes)
|
2013-03-22 16:34:08 +02:00
|
|
|
{
|
2018-03-30 15:11:27 +01:00
|
|
|
struct drm_framebuffer *fb;
|
2013-03-22 16:34:08 +02:00
|
|
|
unsigned int i;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
fb = kzalloc(sizeof(*fb), GFP_KERNEL);
|
|
|
|
if (!fb)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
2025-07-01 12:07:19 +03:00
|
|
|
drm_helper_mode_fill_fb_struct(drm, fb, info, mode_cmd);
|
2013-03-22 16:34:08 +02:00
|
|
|
|
2018-03-30 15:11:27 +01:00
|
|
|
for (i = 0; i < fb->format->num_planes; i++)
|
|
|
|
fb->obj[i] = &planes[i]->gem;
|
2013-03-22 16:34:08 +02:00
|
|
|
|
2018-03-30 15:11:27 +01:00
|
|
|
err = drm_framebuffer_init(drm, fb, &tegra_fb_funcs);
|
2013-03-22 16:34:08 +02:00
|
|
|
if (err < 0) {
|
|
|
|
dev_err(drm->dev, "failed to initialize framebuffer: %d\n",
|
|
|
|
err);
|
|
|
|
kfree(fb);
|
|
|
|
return ERR_PTR(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return fb;
|
|
|
|
}
|
|
|
|
|
2014-11-26 13:03:57 +01:00
|
|
|
struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
|
|
|
|
struct drm_file *file,
|
drm: Pass the format info to .fb_create()
Pass along the format information from the top to .fb_create()
so that we can avoid redundant (and somewhat expensive) lookups
in the drivers.
Done with cocci (with some manual fixups):
@@
identifier func =~ ".*create.*";
identifier dev, file, mode_cmd;
@@
struct drm_framebuffer *func(
struct drm_device *dev,
struct drm_file *file,
+ const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
...
(
- const struct drm_format_info *info = drm_get_format_info(...);
|
- const struct drm_format_info *info;
...
- info = drm_get_format_info(...);
)
<...
- if (!info)
- return ...;
...>
}
@@
identifier func =~ ".*create.*";
identifier dev, file, mode_cmd;
@@
struct drm_framebuffer *func(
struct drm_device *dev,
struct drm_file *file,
+ const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
...
}
@find@
identifier fb_create_func =~ ".*create.*";
identifier dev, file, mode_cmd;
@@
struct drm_framebuffer *fb_create_func(
struct drm_device *dev,
struct drm_file *file,
+ const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd);
@@
identifier find.fb_create_func;
expression dev, file, mode_cmd;
@@
fb_create_func(dev, file
+ ,info
,mode_cmd)
@@
expression dev, file, mode_cmd;
@@
drm_gem_fb_create(dev, file
+ ,info
,mode_cmd)
@@
expression dev, file, mode_cmd;
@@
drm_gem_fb_create_with_dirty(dev, file
+ ,info
,mode_cmd)
@@
expression dev, file_priv, mode_cmd;
identifier info, fb;
@@
info = drm_get_format_info(...);
...
fb = dev->mode_config.funcs->fb_create(dev, file_priv
+ ,info
,mode_cmd);
@@
identifier dev, file_priv, mode_cmd;
@@
struct drm_mode_config_funcs {
...
struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
struct drm_file *file_priv,
+ const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd);
...
};
v2: Fix kernel docs (Laurent)
Fix commit msg (Geert)
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Liviu Dudau <liviu.dudau@arm.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Inki Dae <inki.dae@samsung.com>
Cc: Seung-Woo Kim <sw0312.kim@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
Cc: Chun-Kuang Hu <chunkuang.hu@kernel.org>
Cc: Philipp Zabel <p.zabel@pengutronix.de>
Cc: Rob Clark <robdclark@gmail.com>
Cc: Abhinav Kumar <quic_abhinavk@quicinc.com>
Cc: Dmitry Baryshkov <lumag@kernel.org>
Cc: Sean Paul <sean@poorly.run>
Cc: Marijn Suijten <marijn.suijten@somainline.org>
Cc: Marek Vasut <marex@denx.de>
Cc: Stefan Agner <stefan@agner.ch>
Cc: Lyude Paul <lyude@redhat.com>
Cc: Danilo Krummrich <dakr@kernel.org>
Cc: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Cc: Dave Airlie <airlied@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Cc: Biju Das <biju.das.jz@bp.renesas.com>
Cc: Sandy Huang <hjc@rock-chips.com>
Cc: "Heiko Stübner" <heiko@sntech.de>
Cc: Andy Yan <andy.yan@rock-chips.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Mikko Perttunen <mperttunen@nvidia.com>
Cc: Dave Stevenson <dave.stevenson@raspberrypi.com>
Cc: "Maíra Canal" <mcanal@igalia.com>
Cc: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
Cc: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Cc: Gurchetan Singh <gurchetansingh@chromium.org>
Cc: Chia-I Wu <olvaffe@gmail.com>
Cc: Zack Rusin <zack.rusin@broadcom.com>
Cc: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Cc: amd-gfx@lists.freedesktop.org
Cc: linux-arm-msm@vger.kernel.org
Cc: freedreno@lists.freedesktop.org
Cc: nouveau@lists.freedesktop.org
Cc: virtualization@lists.linux.dev
Cc: spice-devel@lists.freedesktop.org
Cc: linux-renesas-soc@vger.kernel.org
Cc: linux-tegra@vger.kernel.org
Cc: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Acked-by: Liviu Dudau <liviu.dudau@arm.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250701090722.13645-5-ville.syrjala@linux.intel.com
2025-07-01 12:07:07 +03:00
|
|
|
const struct drm_format_info *info,
|
2015-11-11 19:11:29 +02:00
|
|
|
const struct drm_mode_fb_cmd2 *cmd)
|
2013-03-22 16:34:08 +02:00
|
|
|
{
|
|
|
|
struct tegra_bo *planes[4];
|
|
|
|
struct drm_gem_object *gem;
|
2018-03-30 15:11:27 +01:00
|
|
|
struct drm_framebuffer *fb;
|
2019-05-16 12:31:48 +02:00
|
|
|
unsigned int i;
|
2013-03-22 16:34:08 +02:00
|
|
|
int err;
|
|
|
|
|
2019-05-16 12:31:47 +02:00
|
|
|
for (i = 0; i < info->num_planes; i++) {
|
2019-05-16 12:31:48 +02:00
|
|
|
unsigned int width = cmd->width / (i ? info->hsub : 1);
|
|
|
|
unsigned int height = cmd->height / (i ? info->vsub : 1);
|
2013-03-22 16:34:08 +02:00
|
|
|
unsigned int size, bpp;
|
|
|
|
|
2016-05-09 11:04:54 +01:00
|
|
|
gem = drm_gem_object_lookup(file, cmd->handles[i]);
|
2013-03-22 16:34:08 +02:00
|
|
|
if (!gem) {
|
|
|
|
err = -ENXIO;
|
|
|
|
goto unreference;
|
|
|
|
}
|
|
|
|
|
2019-05-16 12:31:52 +02:00
|
|
|
bpp = info->cpp[i];
|
2013-03-22 16:34:08 +02:00
|
|
|
|
|
|
|
size = (height - 1) * cmd->pitches[i] +
|
|
|
|
width * bpp + cmd->offsets[i];
|
|
|
|
|
|
|
|
if (gem->size < size) {
|
|
|
|
err = -EINVAL;
|
2023-12-15 12:33:55 +03:00
|
|
|
drm_gem_object_put(gem);
|
2013-03-22 16:34:08 +02:00
|
|
|
goto unreference;
|
|
|
|
}
|
|
|
|
|
|
|
|
planes[i] = to_tegra_bo(gem);
|
|
|
|
}
|
|
|
|
|
2025-07-01 12:07:19 +03:00
|
|
|
fb = tegra_fb_alloc(drm, info, cmd, planes, i);
|
2013-03-22 16:34:08 +02:00
|
|
|
if (IS_ERR(fb)) {
|
|
|
|
err = PTR_ERR(fb);
|
|
|
|
goto unreference;
|
|
|
|
}
|
|
|
|
|
2018-03-30 15:11:27 +01:00
|
|
|
return fb;
|
2013-03-22 16:34:08 +02:00
|
|
|
|
|
|
|
unreference:
|
|
|
|
while (i--)
|
2020-05-15 10:51:11 +01:00
|
|
|
drm_gem_object_put(&planes[i]->gem);
|
2012-11-15 21:28:22 +00:00
|
|
|
|
2013-03-22 16:34:08 +02:00
|
|
|
return ERR_PTR(err);
|
|
|
|
}
|