* [PATCH 1/5] drm/tegra: fbdev: Do not assign to struct drm_fb_helper.info
2026-04-21 7:29 [PATCH 0/5] drm/tegra: fbdev: Use client buffers Thomas Zimmermann
@ 2026-04-21 7:29 ` Thomas Zimmermann
2026-04-21 7:29 ` [PATCH 2/5] drm/tegra: fbdev: Remove offset into framebuffer memory Thomas Zimmermann
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Thomas Zimmermann @ 2026-04-21 7:29 UTC (permalink / raw)
To: thierry.reding, mperttunen, airlied, simona, jonathanh
Cc: dri-devel, linux-tegra, Thomas Zimmermann
That field already contains the value being assigned. No need to do
this twice.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Fixes: 63c971af4036 ("drm/fb-helper: Allocate and release fb_info in single place")
Cc: linux-tegra@vger.kernel.org
---
drivers/gpu/drm/tegra/fbdev.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c
index 8f40882aa76e..19e39fa54bfa 100644
--- a/drivers/gpu/drm/tegra/fbdev.c
+++ b/drivers/gpu/drm/tegra/fbdev.c
@@ -110,7 +110,6 @@ int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
helper->funcs = &tegra_fbdev_helper_funcs;
helper->fb = fb;
- helper->info = info;
info->fbops = &tegra_fb_ops;
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/5] drm/tegra: fbdev: Remove offset into framebuffer memory
2026-04-21 7:29 [PATCH 0/5] drm/tegra: fbdev: Use client buffers Thomas Zimmermann
2026-04-21 7:29 ` [PATCH 1/5] drm/tegra: fbdev: Do not assign to struct drm_fb_helper.info Thomas Zimmermann
@ 2026-04-21 7:29 ` Thomas Zimmermann
2026-04-21 7:29 ` [PATCH 3/5] drm/tegra: fbdev: Calculate buffer geometry with format helpers Thomas Zimmermann
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Thomas Zimmermann @ 2026-04-21 7:29 UTC (permalink / raw)
To: thierry.reding, mperttunen, airlied, simona, jonathanh
Cc: dri-devel, linux-tegra, Thomas Zimmermann, stable
The screen_buffer field in struct fb_info contains the kernel address
of the first byte of framebuffer memory. Do not add the display offset.
This offset only describes scrolling during scanout.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Fixes: de2ba664c30f ("gpu: host1x: drm: Add memory manager and fb")
Cc: dri-devel@lists.freedesktop.org
Cc: linux-tegra@vger.kernel.org
Cc: <stable@vger.kernel.org> # v3.10+
---
drivers/gpu/drm/tegra/fbdev.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c
index 19e39fa54bfa..793849199783 100644
--- a/drivers/gpu/drm/tegra/fbdev.c
+++ b/drivers/gpu/drm/tegra/fbdev.c
@@ -76,7 +76,6 @@ int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
struct fb_info *info = helper->info;
unsigned int bytes_per_pixel;
struct drm_framebuffer *fb;
- unsigned long offset;
struct tegra_bo *bo;
size_t size;
int err;
@@ -115,9 +114,6 @@ int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
drm_fb_helper_fill_info(info, helper, sizes);
- offset = info->var.xoffset * bytes_per_pixel +
- info->var.yoffset * fb->pitches[0];
-
if (bo->pages) {
bo->vaddr = vmap(bo->pages, bo->num_pages, VM_MAP,
pgprot_writecombine(PAGE_KERNEL));
@@ -129,9 +125,9 @@ int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
}
info->flags |= FBINFO_VIRTFB;
- info->screen_buffer = bo->vaddr + offset;
+ info->screen_buffer = bo->vaddr;
info->screen_size = size;
- info->fix.smem_start = (unsigned long)(bo->iova + offset);
+ info->fix.smem_start = (unsigned long)(bo->iova);
info->fix.smem_len = size;
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/5] drm/tegra: fbdev: Calculate buffer geometry with format helpers
2026-04-21 7:29 [PATCH 0/5] drm/tegra: fbdev: Use client buffers Thomas Zimmermann
2026-04-21 7:29 ` [PATCH 1/5] drm/tegra: fbdev: Do not assign to struct drm_fb_helper.info Thomas Zimmermann
2026-04-21 7:29 ` [PATCH 2/5] drm/tegra: fbdev: Remove offset into framebuffer memory Thomas Zimmermann
@ 2026-04-21 7:29 ` Thomas Zimmermann
2026-04-21 7:29 ` [PATCH 4/5] drm/tegra: fbdev: Use a DRM client buffer Thomas Zimmermann
2026-04-21 7:29 ` [PATCH 5/5] drm/tegra: Make tegra_fb_alloc() an internal interface Thomas Zimmermann
4 siblings, 0 replies; 6+ messages in thread
From: Thomas Zimmermann @ 2026-04-21 7:29 UTC (permalink / raw)
To: thierry.reding, mperttunen, airlied, simona, jonathanh
Cc: dri-devel, linux-tegra, Thomas Zimmermann
Replace the geometry and size calculation in tegra's fbdev emulation
with DRM format helpers. This consists of a 4CC lookup from the fbdev
parameters, format lookup, pitch calculation and size calculation.
Then allocate the GEM buffer object for the framebuffer memory from
the calculated size.
Set up mode_cmd with the calculated values just before allocating the
framebuffer. This code will later be replaced with a DRM client buffer.
Set framebuffer size fields in struct fb_info from the size stored in
the GEM buffer object instead of what has been requested. The requested
size is an estimate, while the buffer size is the exact value rounded
to the correct alignment.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/tegra/fbdev.c | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c
index 793849199783..bcf32cfcf818 100644
--- a/drivers/gpu/drm/tegra/fbdev.c
+++ b/drivers/gpu/drm/tegra/fbdev.c
@@ -74,31 +74,29 @@ int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
struct drm_device *drm = helper->dev;
struct drm_mode_fb_cmd2 cmd = { 0 };
struct fb_info *info = helper->info;
- unsigned int bytes_per_pixel;
+ u32 fourcc, pitch;
+ u64 size;
+ const struct drm_format_info *format;
struct drm_framebuffer *fb;
struct tegra_bo *bo;
- size_t size;
int err;
- bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
-
- cmd.width = sizes->surface_width;
- cmd.height = sizes->surface_height;
- 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);
-
- size = cmd.pitches[0] * cmd.height;
+ fourcc = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
+ format = drm_get_format_info(drm, fourcc, DRM_FORMAT_MOD_LINEAR);
+ pitch = round_up(drm_format_info_min_pitch(format, 0, sizes->surface_width),
+ tegra->pitch_align);
+ size = ALIGN(pitch * sizes->surface_height, PAGE_SIZE);
bo = tegra_bo_create(drm, size, 0);
if (IS_ERR(bo))
return PTR_ERR(bo);
- fb = tegra_fb_alloc(drm,
- drm_get_format_info(drm, cmd.pixel_format, cmd.modifier[0]),
- &cmd, &bo, 1);
+ cmd.pixel_format = fourcc;
+ cmd.width = sizes->surface_width;
+ cmd.height = sizes->surface_height;
+ cmd.pitches[0] = pitch;
+
+ fb = tegra_fb_alloc(drm, format, &cmd, &bo, 1);
if (IS_ERR(fb)) {
err = PTR_ERR(fb);
dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n",
@@ -126,9 +124,9 @@ int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
info->flags |= FBINFO_VIRTFB;
info->screen_buffer = bo->vaddr;
- info->screen_size = size;
+ info->screen_size = bo->gem.size;
info->fix.smem_start = (unsigned long)(bo->iova);
- info->fix.smem_len = size;
+ info->fix.smem_len = bo->gem.size;
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/5] drm/tegra: fbdev: Use a DRM client buffer
2026-04-21 7:29 [PATCH 0/5] drm/tegra: fbdev: Use client buffers Thomas Zimmermann
` (2 preceding siblings ...)
2026-04-21 7:29 ` [PATCH 3/5] drm/tegra: fbdev: Calculate buffer geometry with format helpers Thomas Zimmermann
@ 2026-04-21 7:29 ` Thomas Zimmermann
2026-04-21 7:29 ` [PATCH 5/5] drm/tegra: Make tegra_fb_alloc() an internal interface Thomas Zimmermann
4 siblings, 0 replies; 6+ messages in thread
From: Thomas Zimmermann @ 2026-04-21 7:29 UTC (permalink / raw)
To: thierry.reding, mperttunen, airlied, simona, jonathanh
Cc: dri-devel, linux-tegra, Thomas Zimmermann
Replace the internal DRM framebuffer with a DRM client buffer. The
client buffer allocates the DRM framebuffer on a file and also uses
GEM object handles via the regular ADDFB2 interfaces.
Using client-buffer interfaces unifies framebuffer allocation for
DRM clients in user space and tegra's internal fbdev emulation. It
also simplifies the clean-up side of the fbdev emulation.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/tegra/fbdev.c | 61 +++++++++++++++++++++--------------
1 file changed, 36 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c
index bcf32cfcf818..003e80cf7b9a 100644
--- a/drivers/gpu/drm/tegra/fbdev.c
+++ b/drivers/gpu/drm/tegra/fbdev.c
@@ -40,8 +40,7 @@ static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
static void tegra_fbdev_fb_destroy(struct fb_info *info)
{
struct drm_fb_helper *helper = info->par;
- struct drm_framebuffer *fb = helper->fb;
- struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
+ struct tegra_bo *bo = tegra_fb_get_plane(helper->fb, 0);
drm_fb_helper_fini(helper);
@@ -50,8 +49,8 @@ static void tegra_fbdev_fb_destroy(struct fb_info *info)
vunmap(bo->vaddr);
bo->vaddr = NULL;
}
- drm_framebuffer_remove(fb);
+ drm_client_buffer_delete(helper->buffer);
drm_client_release(&helper->client);
}
@@ -70,15 +69,18 @@ static const struct drm_fb_helper_funcs tegra_fbdev_helper_funcs = {
int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
- struct tegra_drm *tegra = helper->dev->dev_private;
- struct drm_device *drm = helper->dev;
- struct drm_mode_fb_cmd2 cmd = { 0 };
+ struct drm_client_dev *client = &helper->client;
+ struct drm_device *drm = client->dev;
+ struct drm_file *file = client->file;
+ struct tegra_drm *tegra = drm->dev_private;
struct fb_info *info = helper->info;
u32 fourcc, pitch;
u64 size;
const struct drm_format_info *format;
- struct drm_framebuffer *fb;
struct tegra_bo *bo;
+ struct drm_gem_object *gem;
+ u32 handle;
+ struct drm_client_buffer *buffer;
int err;
fourcc = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
@@ -90,23 +92,22 @@ int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
bo = tegra_bo_create(drm, size, 0);
if (IS_ERR(bo))
return PTR_ERR(bo);
+ gem = &bo->gem;
- cmd.pixel_format = fourcc;
- cmd.width = sizes->surface_width;
- cmd.height = sizes->surface_height;
- cmd.pitches[0] = pitch;
-
- fb = tegra_fb_alloc(drm, format, &cmd, &bo, 1);
- if (IS_ERR(fb)) {
- err = PTR_ERR(fb);
- dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n",
- err);
- drm_gem_object_put(&bo->gem);
- return PTR_ERR(fb);
+ err = drm_gem_handle_create(file, gem, &handle);
+ if (err)
+ goto err_drm_gem_object_put;
+
+ buffer = drm_client_buffer_create(client, sizes->surface_width, sizes->surface_height,
+ fourcc, handle, pitch);
+ if (IS_ERR(buffer)) {
+ err = PTR_ERR(buffer);
+ goto err_drm_gem_handle_delete;
}
helper->funcs = &tegra_fbdev_helper_funcs;
- helper->fb = fb;
+ helper->buffer = buffer;
+ helper->fb = buffer->fb;
info->fbops = &tegra_fb_ops;
@@ -118,19 +119,29 @@ int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
if (!bo->vaddr) {
dev_err(drm->dev, "failed to vmap() framebuffer\n");
err = -ENOMEM;
- goto destroy;
+ goto err_drm_client_buffer_delete;
}
}
info->flags |= FBINFO_VIRTFB;
info->screen_buffer = bo->vaddr;
- info->screen_size = bo->gem.size;
+ info->screen_size = gem->size;
info->fix.smem_start = (unsigned long)(bo->iova);
- info->fix.smem_len = bo->gem.size;
+ info->fix.smem_len = gem->size;
+
+ /* The handle is only needed for creating the framebuffer. */
+ drm_gem_handle_delete(file, handle);
+
+ /* The framebuffer still holds a reference on the GEM object. */
+ drm_gem_object_put(gem);
return 0;
-destroy:
- drm_framebuffer_remove(fb);
+err_drm_client_buffer_delete:
+ drm_client_buffer_delete(buffer);
+err_drm_gem_handle_delete:
+ drm_gem_handle_delete(file, handle);
+err_drm_gem_object_put:
+ drm_gem_object_put(gem);
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 5/5] drm/tegra: Make tegra_fb_alloc() an internal interface
2026-04-21 7:29 [PATCH 0/5] drm/tegra: fbdev: Use client buffers Thomas Zimmermann
` (3 preceding siblings ...)
2026-04-21 7:29 ` [PATCH 4/5] drm/tegra: fbdev: Use a DRM client buffer Thomas Zimmermann
@ 2026-04-21 7:29 ` Thomas Zimmermann
4 siblings, 0 replies; 6+ messages in thread
From: Thomas Zimmermann @ 2026-04-21 7:29 UTC (permalink / raw)
To: thierry.reding, mperttunen, airlied, simona, jonathanh
Cc: dri-devel, linux-tegra, Thomas Zimmermann
Fbdev framebuffer allocation now goes through the regular ioctl call
chain. This makes tegra_fb_alloc() an internal helper function. Declare
it as static.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/tegra/drm.h | 5 -----
drivers/gpu/drm/tegra/fb.c | 1 +
2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index ae68b03d8483..bc720ae8d95e 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -184,11 +184,6 @@ struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer);
int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
struct tegra_bo_tiling *tiling);
-struct drm_framebuffer *tegra_fb_alloc(struct drm_device *drm,
- const struct drm_format_info *info,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct tegra_bo **planes,
- unsigned int num_planes);
struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
struct drm_file *file,
const struct drm_format_info *info,
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 1e4803d355dd..0a7cb9e462ff 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -102,6 +102,7 @@ static const struct drm_framebuffer_funcs tegra_fb_funcs = {
.create_handle = drm_gem_fb_create_handle,
};
+static
struct drm_framebuffer *tegra_fb_alloc(struct drm_device *drm,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd,
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread