* [PATCH 13/13] lib/fonts: Remove internal symbols and macros from public header file
From: Thomas Zimmermann @ 2026-02-18 8:16 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Define access macros for font_data_t in fonts.c. Define struct font_data
and declare most of the font symbols in the internal header font.h, where
they can only be seen by the font code. Add config guards around font
symbols.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
include/linux/font.h | 32 +++++------------------
lib/fonts/font.h | 52 ++++++++++++++++++++++++++++++++++++++
lib/fonts/font_10x18.c | 2 +-
lib/fonts/font_6x10.c | 3 ++-
lib/fonts/font_6x11.c | 2 +-
lib/fonts/font_6x8.c | 3 ++-
lib/fonts/font_7x14.c | 2 +-
lib/fonts/font_8x16.c | 3 ++-
lib/fonts/font_8x8.c | 2 +-
lib/fonts/font_acorn_8x8.c | 2 +-
lib/fonts/font_mini_4x6.c | 2 +-
lib/fonts/font_pearl_8x8.c | 2 +-
lib/fonts/font_sun12x22.c | 3 ++-
lib/fonts/font_sun8x16.c | 3 ++-
lib/fonts/font_ter10x18.c | 4 ++-
lib/fonts/font_ter16x32.c | 4 ++-
lib/fonts/fonts.c | 8 +++++-
17 files changed, 88 insertions(+), 41 deletions(-)
create mode 100644 lib/fonts/font.h
diff --git a/include/linux/font.h b/include/linux/font.h
index 4ff956a1cd0a..6e9a4c93b47b 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -92,20 +92,12 @@ struct font_desc {
#define FONT6x8_IDX 12
#define TER10x18_IDX 13
-extern const struct font_desc font_vga_8x8,
- font_vga_8x16,
- font_pearl_8x8,
- font_vga_6x11,
- font_7x14,
- font_10x18,
- font_sun_8x16,
- font_sun_12x22,
- font_acorn_8x8,
- font_mini_4x6,
- font_6x10,
- font_ter_16x32,
- font_6x8,
- font_ter_10x18;
+#if defined(CONFIG_FONT_8x8)
+extern const struct font_desc font_vga_8x8;
+#endif
+#if defined(CONFIG_FONT_8x16)
+extern const struct font_desc font_vga_8x16;
+#endif
/* Find a font with a specific name */
@@ -120,16 +112,4 @@ extern const struct font_desc *get_default_font(int xres, int yres,
/* Max. length for the name of a predefined font */
#define MAX_FONT_NAME 32
-/* Extra word getters */
-#define REFCOUNT(fd) (((int *)(fd))[-1])
-#define FNTSIZE(fd) (((int *)(fd))[-2])
-#define FNTSUM(fd) (((int *)(fd))[-4])
-
-#define FONT_EXTRA_WORDS 4
-
-struct font_data {
- unsigned int extra[FONT_EXTRA_WORDS];
- unsigned char data[];
-} __packed;
-
#endif /* _VIDEO_FONT_H */
diff --git a/lib/fonts/font.h b/lib/fonts/font.h
new file mode 100644
index 000000000000..00f65a3da5c2
--- /dev/null
+++ b/lib/fonts/font.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LIB_FONTS_FONT_H
+#define _LIB_FONTS_FONT_H
+
+#include <linux/font.h>
+
+#if defined(CONFIG_FONT_PEARL_8x8)
+extern const struct font_desc font_pearl_8x8;
+#endif
+#if defined(CONFIG_FONT_6x11)
+extern const struct font_desc font_vga_6x11;
+#endif
+#if defined(CONFIG_FONT_7x14)
+extern const struct font_desc font_7x14;
+#endif
+#if defined(CONFIG_FONT_10x18)
+extern const struct font_desc font_10x18;
+#endif
+#if defined(CONFIG_FONT_SUN8x16)
+extern const struct font_desc font_sun_8x16;
+#endif
+#if defined(CONFIG_FONT_SUN12x22)
+extern const struct font_desc font_sun_12x22;
+#endif
+#if defined(CONFIG_FONT_ACORN_8x8)
+extern const struct font_desc font_acorn_8x8;
+#endif
+#if defined(CONFIG_FONT_MINI_4x6)
+extern const struct font_desc font_mini_4x6;
+#endif
+#if defined(CONFIG_FONT_6x10)
+extern const struct font_desc font_6x10;
+#endif
+#if defined(CONFIG_FONT_TER16x32)
+extern const struct font_desc font_ter_16x32;
+#endif
+#if defined(CONFIG_FONT_6x8)
+extern const struct font_desc font_6x8;
+#endif
+#if defined(CONFIG_FONT_TER10x18)
+extern const struct font_desc font_ter_10x18;
+#endif
+
+#define FONT_EXTRA_WORDS 4
+
+struct font_data {
+ unsigned int extra[FONT_EXTRA_WORDS];
+ unsigned char data[];
+} __packed;
+
+#endif
diff --git a/lib/fonts/font_10x18.c b/lib/fonts/font_10x18.c
index 5d940db626e7..10edebc4bb74 100644
--- a/lib/fonts/font_10x18.c
+++ b/lib/fonts/font_10x18.c
@@ -4,7 +4,7 @@
* by Jurriaan Kalkman 06-2005 *
********************************/
-#include <linux/font.h>
+#include "font.h"
#define FONTDATAMAX 9216
diff --git a/lib/fonts/font_6x10.c b/lib/fonts/font_6x10.c
index e65df019e0d2..660d3a371b30 100644
--- a/lib/fonts/font_6x10.c
+++ b/lib/fonts/font_6x10.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
-#include <linux/font.h>
+
+#include "font.h"
#define FONTDATAMAX 2560
diff --git a/lib/fonts/font_6x11.c b/lib/fonts/font_6x11.c
index bd76b3f6b635..671487ccc172 100644
--- a/lib/fonts/font_6x11.c
+++ b/lib/fonts/font_6x11.c
@@ -5,7 +5,7 @@
/* */
/**********************************************/
-#include <linux/font.h>
+#include "font.h"
#define FONTDATAMAX (11*256)
diff --git a/lib/fonts/font_6x8.c b/lib/fonts/font_6x8.c
index 06ace7792521..5811ee07f4d8 100644
--- a/lib/fonts/font_6x8.c
+++ b/lib/fonts/font_6x8.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
-#include <linux/font.h>
+
+#include "font.h"
#define FONTDATAMAX 2048
diff --git a/lib/fonts/font_7x14.c b/lib/fonts/font_7x14.c
index a2f561c9fa04..0c7475d643c8 100644
--- a/lib/fonts/font_7x14.c
+++ b/lib/fonts/font_7x14.c
@@ -4,7 +4,7 @@
/* by Jurriaan Kalkman 05-2005 */
/**************************************/
-#include <linux/font.h>
+#include "font.h"
#define FONTDATAMAX 3584
diff --git a/lib/fonts/font_8x16.c b/lib/fonts/font_8x16.c
index 06ae14088514..523e95c75569 100644
--- a/lib/fonts/font_8x16.c
+++ b/lib/fonts/font_8x16.c
@@ -5,9 +5,10 @@
/* */
/**********************************************/
-#include <linux/font.h>
#include <linux/module.h>
+#include "font.h"
+
#define FONTDATAMAX 4096
static const struct font_data fontdata_8x16 = {
diff --git a/lib/fonts/font_8x8.c b/lib/fonts/font_8x8.c
index 69570b8c31af..e5b697fc9675 100644
--- a/lib/fonts/font_8x8.c
+++ b/lib/fonts/font_8x8.c
@@ -5,7 +5,7 @@
/* */
/**********************************************/
-#include <linux/font.h>
+#include "font.h"
#define FONTDATAMAX 2048
diff --git a/lib/fonts/font_acorn_8x8.c b/lib/fonts/font_acorn_8x8.c
index af5fa72aa8b7..36c51016769d 100644
--- a/lib/fonts/font_acorn_8x8.c
+++ b/lib/fonts/font_acorn_8x8.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Acorn-like font definition, with PC graphics characters */
-#include <linux/font.h>
+#include "font.h"
#define FONTDATAMAX 2048
diff --git a/lib/fonts/font_mini_4x6.c b/lib/fonts/font_mini_4x6.c
index cc21dc70cfd1..dc919c160dde 100644
--- a/lib/fonts/font_mini_4x6.c
+++ b/lib/fonts/font_mini_4x6.c
@@ -39,7 +39,7 @@ __END__;
MSBit to LSBit = left to right.
*/
-#include <linux/font.h>
+#include "font.h"
#define FONTDATAMAX 1536
diff --git a/lib/fonts/font_pearl_8x8.c b/lib/fonts/font_pearl_8x8.c
index ae98ca17982e..2438b374acea 100644
--- a/lib/fonts/font_pearl_8x8.c
+++ b/lib/fonts/font_pearl_8x8.c
@@ -10,7 +10,7 @@
/* */
/**********************************************/
-#include <linux/font.h>
+#include "font.h"
#define FONTDATAMAX 2048
diff --git a/lib/fonts/font_sun12x22.c b/lib/fonts/font_sun12x22.c
index 91daf5ab8b6b..2afbc144bea8 100644
--- a/lib/fonts/font_sun12x22.c
+++ b/lib/fonts/font_sun12x22.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
-#include <linux/font.h>
+
+#include "font.h"
#define FONTDATAMAX 11264
diff --git a/lib/fonts/font_sun8x16.c b/lib/fonts/font_sun8x16.c
index 81bb4eeae04e..2b7b2d8e548a 100644
--- a/lib/fonts/font_sun8x16.c
+++ b/lib/fonts/font_sun8x16.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
-#include <linux/font.h>
+
+#include "font.h"
#define FONTDATAMAX 4096
diff --git a/lib/fonts/font_ter10x18.c b/lib/fonts/font_ter10x18.c
index 80356e9d56c7..3f30b4a211ab 100644
--- a/lib/fonts/font_ter10x18.c
+++ b/lib/fonts/font_ter10x18.c
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
-#include <linux/font.h>
+
#include <linux/module.h>
+#include "font.h"
+
#define FONTDATAMAX 9216
static const struct font_data fontdata_ter10x18 = {
diff --git a/lib/fonts/font_ter16x32.c b/lib/fonts/font_ter16x32.c
index 5baedc573dd6..93616cffe642 100644
--- a/lib/fonts/font_ter16x32.c
+++ b/lib/fonts/font_ter16x32.c
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
-#include <linux/font.h>
+
#include <linux/module.h>
+#include "font.h"
+
#define FONTDATAMAX 16384
static const struct font_data fontdata_ter16x32 = {
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index 1830e6ae9c87..198aae869be2 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -13,7 +13,6 @@
*/
#include <linux/container_of.h>
-#include <linux/font.h>
#include <linux/kd.h>
#include <linux/module.h>
#include <linux/overflow.h>
@@ -26,12 +25,19 @@
#include <asm/setup.h>
#endif
+#include "font.h"
+
#define console_font_pitch(font) DIV_ROUND_UP((font)->width, 8)
/*
* Helpers for font_data_t
*/
+/* Extra word getters */
+#define REFCOUNT(fd) (((int *)(fd))[-1])
+#define FNTSIZE(fd) (((int *)(fd))[-2])
+#define FNTSUM(fd) (((int *)(fd))[-4])
+
static struct font_data *to_font_data_struct(font_data_t *fd)
{
return container_of(fd, struct font_data, data[0]);
--
2.52.0
^ permalink raw reply related
* [PATCH 12/13] lib/fonts: Store font data for user space with font_data_export()
From: Thomas Zimmermann @ 2026-02-18 8:16 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Add font_data_export() and update consoles to use it.
The helper font_data_export() is based on code in fbcon_get_font().
It extends the size of a single glyph to match the requested vpitch,
which us usually 32 bytes for fonts from user space. Internal fonts
have a pitch according to the glyph's height.
The implementation of font_data_export() differs in several ways from
the original code. The original implementation distinguished between
different pitches of the font data. This is not necessary as the pitch
is a parameter in the copying.
There was also special handling for a font pitch of 3 bytes, which got
expanded to 4 bytes (with trailing bits on each scanline). The logic
originated from long before git history exists even in the historical
tree. So it is not clear why this was implemented. It is not what user
space expects. The setfont utitlity loads font with 3-bytes pitches and
expects to read such fonts with a 3-byte pitch. For any font width, the
font pitch is always the width extended to the next multiple of 8. See
[1] for the user-space font-reading code.
With the changes ot handling the font pitches, font_data_export() replaces
the original code's various special cases with a single copying logic.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://github.com/legionus/kbd/blob/v2.9.0/src/libkfont/kdfontop.c#L73 # [1]
---
drivers/video/fbdev/core/fbcon.c | 57 ++------------------------------
include/linux/font.h | 1 +
lib/fonts/fonts.c | 40 ++++++++++++++++++++++
3 files changed, 43 insertions(+), 55 deletions(-)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 30d82290d01f..4d07904f62e9 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2287,68 +2287,15 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
{
- struct fbcon_display *p = &fb_display[vc->vc_num];
- font_data_t *fontdata = p->fontdata;
- u8 *data = font->data;
- int i, j;
+ const struct fbcon_display *p = &fb_display[vc->vc_num];
font->width = vc->vc_font.width;
font->height = vc->vc_font.height;
if (font->height > vpitch)
return -ENOSPC;
font->charcount = vc->vc_hi_font_mask ? 512 : 256;
- if (!font->data)
- return 0;
-
- if (font->width <= 8) {
- j = vc->vc_font.height;
- if (font->charcount * j > font_data_size(fontdata))
- return -EINVAL;
- for (i = 0; i < font->charcount; i++) {
- memcpy(data, fontdata, j);
- memset(data + j, 0, vpitch - j);
- data += vpitch;
- fontdata += j;
- }
- } else if (font->width <= 16) {
- j = vc->vc_font.height * 2;
- if (font->charcount * j > font_data_size(fontdata))
- return -EINVAL;
-
- for (i = 0; i < font->charcount; i++) {
- memcpy(data, fontdata, j);
- memset(data + j, 0, 2*vpitch - j);
- data += 2*vpitch;
- fontdata += j;
- }
- } else if (font->width <= 24) {
- if (font->charcount * (vc->vc_font.height * sizeof(u32)) > font_data_size(fontdata))
- return -EINVAL;
-
- for (i = 0; i < font->charcount; i++) {
- for (j = 0; j < vc->vc_font.height; j++) {
- *data++ = fontdata[0];
- *data++ = fontdata[1];
- *data++ = fontdata[2];
- fontdata += sizeof(u32);
- }
- memset(data, 0, 3 * (vpitch - j));
- data += 3 * (vpitch - j);
- }
- } else {
- j = vc->vc_font.height * 4;
- if (font->charcount * j > font_data_size(fontdata))
- return -EINVAL;
-
- for (i = 0; i < font->charcount; i++) {
- memcpy(data, fontdata, j);
- memset(data + j, 0, 4 * vpitch - j);
- data += 4 * vpitch;
- fontdata += j;
- }
- }
- return 0;
+ return font_data_export(p->fontdata, font, vpitch);
}
/* set/clear vc_hi_font_mask and update vc attrs accordingly */
diff --git a/include/linux/font.h b/include/linux/font.h
index 5a1bf433b275..4ff956a1cd0a 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -62,6 +62,7 @@ void font_data_get(font_data_t *fd);
bool font_data_put(font_data_t *fd);
unsigned int font_data_size(font_data_t *fd);
bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs);
+int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch);
/*
* Font lookup
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index 9b5355f6d2dc..1830e6ae9c87 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -202,6 +202,46 @@ bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs)
}
EXPORT_SYMBOL_GPL(font_data_is_equal);
+/**
+ * font_data_export - Stores font data for user space
+ * @fd: Font data
+ * @font: A font for user space
+ * @vpitch: The size of a single glyph in @font in bytes
+ *
+ * Store the font data given in @fd to the font in @font. Values and
+ * pointers in @font are pre-initialized. This helper mostly checks some
+ * corner cases and translates glyph sizes according to the value given
+ * @vpitch.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise.
+ */
+int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch)
+{
+ const unsigned char *font_data = font_data_buf(fd);
+ unsigned char *data = font->data;
+ unsigned int pitch = console_font_pitch(font);
+ unsigned int glyphsize, i;
+
+ if (!font->width || !font->height || !font->charcount || !font->data)
+ return 0;
+
+ glyphsize = font->height * pitch;
+
+ if (font->charcount * glyphsize > font_data_size(fd))
+ return -EINVAL;
+
+ for (i = 0; i < font->charcount; i++) {
+ memcpy(data, font_data, glyphsize);
+ memset(data + glyphsize, 0, pitch * vpitch - glyphsize);
+ data += pitch * vpitch;
+ font_data += glyphsize;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(font_data_export);
+
/*
* Font lookup
*/
--
2.52.0
^ permalink raw reply related
* [PATCH 10/13] lib/fonts: Manage font-data lifetime with font_data_get/_put()
From: Thomas Zimmermann @ 2026-02-18 8:16 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Add font_data_get() and font_data_put(). Update consoles to use them
over REFCOUNT() and plain kfree().
Newly allocated font data starts with a reference count of 1. Loading
the font puts the previously loaded font. If the reference count reaches
zero, font_data_put() frees the font data.
The kernel stores internal font data in a read-only section. Invoking
font_data_get() and font_data_put() tests this internally and returns
success without further operation. From the caller's perspective,
getting and putting works the same for all font data.
Fbcon used the userfont flag distinguish between internal fonts and
fonts loaded by user space. Only the latter where refcounted. With the
new helper's automatic handling of internal font data, remove the
userfont flag from fbcon.
Newport_con uses a default font, FONT_DATA, until user space loads
custom font data. Remove all special cases for FONT_DATA, as the get
and put calls' read-only handlign also covers this case.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/console/newport_con.c | 26 ++++-------
drivers/video/fbdev/core/fbcon.c | 65 +++++++++++++--------------
drivers/video/fbdev/core/fbcon.h | 1 -
include/linux/font.h | 2 +
lib/fonts/fonts.c | 70 +++++++++++++++++++++++++++++
5 files changed, 111 insertions(+), 53 deletions(-)
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 02bf4df05016..8870555cf837 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -517,7 +517,7 @@ static int newport_set_font(int unit, const struct console_font *op,
new_data += FONT_EXTRA_WORDS * sizeof(int);
FNTSIZE(new_data) = size;
- REFCOUNT(new_data) = 0; /* usage counter */
+ REFCOUNT(new_data) = 1; /* usage counter */
FNTSUM(new_data) = 0;
p = (unsigned char *)font_data_buf(new_data);
@@ -529,23 +529,18 @@ static int newport_set_font(int unit, const struct console_font *op,
/* check if font is already used by other console */
for (i = 0; i < MAX_NR_CONSOLES; i++) {
- if (font_data[i] != FONT_DATA
- && font_data_is_equal(font_data[i], new_data)) {
- kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
+ if (font_data_is_equal(font_data[i], new_data)) {
+ font_data_put(new_data);
/* current font is the same as the new one */
if (i == unit)
return 0;
new_data = font_data[i];
+ font_data_get(new_data);
break;
}
}
- /* old font is user font */
- if (font_data[unit] != FONT_DATA) {
- if (--REFCOUNT(font_data[unit]) == 0)
- kfree(font_data[unit] -
- FONT_EXTRA_WORDS * sizeof(int));
- }
- REFCOUNT(new_data)++;
+
+ font_data_put(font_data[unit]);
font_data[unit] = new_data;
return 0;
@@ -553,12 +548,9 @@ static int newport_set_font(int unit, const struct console_font *op,
static int newport_set_def_font(int unit, struct console_font *op)
{
- if (font_data[unit] != FONT_DATA) {
- if (--REFCOUNT(font_data[unit]) == 0)
- kfree(font_data[unit] -
- FONT_EXTRA_WORDS * sizeof(int));
- font_data[unit] = FONT_DATA;
- }
+ font_data_put(font_data[unit]);
+ font_data[unit] = FONT_DATA;
+ font_data_get(font_data[unit]);
return 0;
}
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 6fbecce606fd..b1123f3911d7 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1023,6 +1023,7 @@ static const char *fbcon_startup(void)
vc->vc_font.charcount = font->charcount;
p->fontdata = font->data;
+ font_data_get(p->fontdata);
}
cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
@@ -1085,10 +1086,7 @@ static void fbcon_init(struct vc_data *vc, bool init)
vc->vc_font.charcount = fvc->vc_font.charcount;
p->fontdata = t->fontdata;
- p->userfont = t->userfont;
-
- if (p->userfont)
- REFCOUNT(p->fontdata)++;
+ font_data_get(p->fontdata);
} else {
const struct font_desc *font = NULL;
@@ -1103,6 +1101,7 @@ static void fbcon_init(struct vc_data *vc, bool init)
vc->vc_font.charcount = font->charcount;
p->fontdata = font->data;
+ font_data_get(p->fontdata);
}
}
@@ -1193,10 +1192,10 @@ static void fbcon_init(struct vc_data *vc, bool init)
static void fbcon_free_font(struct fbcon_display *p)
{
- if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
- kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
- p->fontdata = NULL;
- p->userfont = 0;
+ if (p->fontdata) {
+ font_data_put(p->fontdata);
+ p->fontdata = NULL;
+ }
}
static void set_vc_hi_font(struct vc_data *vc, bool set);
@@ -1419,9 +1418,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
vc->vc_font.height = (*default_mode)->vc_font.height;
vc->vc_font.charcount = (*default_mode)->vc_font.charcount;
p->fontdata = t->fontdata;
- p->userfont = t->userfont;
- if (p->userfont)
- REFCOUNT(p->fontdata)++;
+ font_data_get(p->fontdata);
}
var->activate = FB_ACTIVATE_NOW;
@@ -2058,7 +2055,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
struct fb_var_screeninfo var = info->var;
int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
- if (p->userfont && font_data_size(p->fontdata)) {
+ if (font_data_size(p->fontdata)) {
unsigned int size = vc_font_size(&vc->vc_font);
/*
@@ -2418,21 +2415,20 @@ static void set_vc_hi_font(struct vc_data *vc, bool set)
}
static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
- font_data_t *data, int userfont)
+ font_data_t *data)
{
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_par *par = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];
- int resize, ret, old_userfont, old_width, old_height, old_charcount;
+ int resize, ret, old_width, old_height, old_charcount;
font_data_t *old_fontdata = p->fontdata;
const u8 *old_data = vc->vc_font.data;
+ font_data_get(data);
+
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
p->fontdata = data;
vc->vc_font.data = font_data_buf(p->fontdata);
- old_userfont = p->userfont;
- if ((p->userfont = userfont))
- REFCOUNT(data)++;
old_width = vc->vc_font.width;
old_height = vc->vc_font.height;
@@ -2462,24 +2458,20 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
update_screen(vc);
}
- if (old_userfont && (--REFCOUNT(old_fontdata) == 0))
- kfree(old_fontdata - FONT_EXTRA_WORDS * sizeof(int));
+ if (old_fontdata)
+ font_data_put(old_fontdata);
+
return 0;
err_out:
p->fontdata = old_fontdata;
vc->vc_font.data = old_data;
-
- if (userfont) {
- p->userfont = old_userfont;
- if (--REFCOUNT(data) == 0)
- kfree(data - FONT_EXTRA_WORDS * sizeof(int));
- }
-
vc->vc_font.width = old_width;
vc->vc_font.height = old_height;
vc->vc_font.charcount = old_charcount;
+ font_data_put(data);
+
return ret;
}
@@ -2496,9 +2488,9 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
int w = font->width;
int h = font->height;
int size, alloc_size;
- int i, csum;
+ int i, csum, ret;
font_data_t *new_data;
- u8 *data = font->data;
+ const u8 *data = font->data;
int pitch = PITCH(font->width);
/* Is there a reason why fbconsole couldn't handle any charcount >256?
@@ -2541,7 +2533,7 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
new_data += FONT_EXTRA_WORDS * sizeof(int);
FNTSIZE(new_data) = size;
- REFCOUNT(new_data) = 0; /* usage counter */
+ REFCOUNT(new_data) = 1; /* usage counter */
for (i=0; i< charcount; i++) {
memcpy((u8 *)new_data + i * h * pitch, data + i * vpitch * pitch, h * pitch);
}
@@ -2553,15 +2545,18 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
FNTSUM(new_data) = csum;
/* Check if the same font is on some other console already */
for (i = first_fb_vc; i <= last_fb_vc; i++) {
- if (fb_display[i].userfont &&
- fb_display[i].fontdata &&
+ if (fb_display[i].fontdata &&
font_data_is_equal(fb_display[i].fontdata, new_data)) {
- kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
- new_data = (u8 *)fb_display[i].fontdata;
+ font_data_get(fb_display[i].fontdata);
+ font_data_put(new_data);
+ new_data = fb_display[i].fontdata;
break;
}
}
- return fbcon_do_set_font(vc, font->width, font->height, charcount, new_data, 1);
+ ret = fbcon_do_set_font(vc, font->width, font->height, charcount, new_data);
+ font_data_put(new_data);
+
+ return ret;
}
static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font,
@@ -2578,7 +2573,7 @@ static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font,
font->width = f->width;
font->height = f->height;
- return fbcon_do_set_font(vc, f->width, f->height, f->charcount, f->data, 0);
+ return fbcon_do_set_font(vc, f->width, f->height, f->charcount, f->data);
}
static u16 palette_red[16];
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index d26ee7860cf5..1e3c1ef84762 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -27,7 +27,6 @@
struct fbcon_display {
/* Filled in by the low-level console driver */
font_data_t *fontdata;
- int userfont; /* != 0 if fontdata kmalloc()ed */
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
u_short scrollmode; /* Scroll Method, use fb_scrollmode() */
#endif
diff --git a/include/linux/font.h b/include/linux/font.h
index da9869ca2294..d548684e6430 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -54,6 +54,8 @@ static inline const unsigned char *font_data_buf(font_data_t *fd)
return (const unsigned char *)fd;
}
+void font_data_get(font_data_t *fd);
+bool font_data_put(font_data_t *fd);
unsigned int font_data_size(font_data_t *fd);
bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs);
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index c9f6328d5dda..1da0acdebf53 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -12,8 +12,10 @@
* for more details.
*/
+#include <linux/container_of.h>
#include <linux/font.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
@@ -26,11 +28,79 @@
* Helpers for font_data_t
*/
+static struct font_data *to_font_data_struct(font_data_t *fd)
+{
+ return container_of(fd, struct font_data, data[0]);
+}
+
static bool font_data_is_internal(font_data_t *fd)
{
return is_kernel_rodata((unsigned long)fd);
}
+static void font_data_free(font_data_t *fd)
+{
+ if (WARN_ON(font_data_is_internal(fd)))
+ return;
+
+ kfree(to_font_data_struct(fd));
+}
+
+/**
+ * font_data_get - Acquires a reference on font data
+ * @fd: Font data
+ *
+ * Font data from user space is reference counted. The helper
+ * font_data_get() increases the reference counter by one. Invoke
+ * font_data_put() to release the reference.
+ *
+ * Internal font data is located in read-only memory. In this case
+ * the helper returns success without modifying the counter field.
+ * It is still required to call font_data_put() on internal font data.
+ */
+void font_data_get(font_data_t *fd)
+{
+ if (font_data_is_internal(fd))
+ return; /* never ref static data */
+
+ if (WARN_ON(!REFCOUNT(fd)))
+ return; /* should never be 0 */
+ ++REFCOUNT(fd);
+}
+EXPORT_SYMBOL_GPL(font_data_get);
+
+/**
+ * font_data_put - Release a reference on font data
+ * @fd: Font data
+ *
+ * Font data from user space is reference counted. The helper
+ * font_data_put() decreases the reference counter by one. If this was
+ * the final reference, it frees the allocated memory.
+ *
+ * Internal font data is located in read-only memory. In this case
+ * the helper returns success without modifying the counter field.
+ *
+ * Returns:
+ * True if this was the final reference, false otherwise.
+ */
+bool font_data_put(font_data_t *fd)
+{
+ unsigned int count;
+
+ if (font_data_is_internal(fd))
+ return true; /* never unref static data */
+
+ if (WARN_ON(!REFCOUNT(fd)))
+ return true; /* should never be 0 */
+
+ count = --REFCOUNT(fd);
+ if (!count)
+ font_data_free(fd);
+
+ return !count;
+}
+EXPORT_SYMBOL_GPL(font_data_put);
+
/**
* font_data_size - Return size of the font data in bytes
* @fd: Font data
--
2.52.0
^ permalink raw reply related
* [PATCH 09/13] lib/fonts: Compare font data for equality with font_data_is_equal()
From: Thomas Zimmermann @ 2026-02-18 8:16 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Add font_data_is_equal() and update consoles to use it.
Font data is equal if it has the same size and contains the same values
on all bytes. Only fbcon uses a crc32 checksum. If set in both operands
the checksums have to be equal.
The new helper also guarantees to not compare internal fonts against
fonts from user space. Internal fonts cannot be ref-counted, so making
them equal to user-space fonts with the same byte sequence results in
undefined behavior.
The test only compares data buffers. Their interpretation is up each
console. Therefore remove a width test in fbcon_set_font().
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/console/newport_con.c | 3 +--
drivers/video/fbdev/core/fbcon.c | 7 +-----
include/linux/font.h | 1 +
lib/fonts/fonts.c | 37 +++++++++++++++++++++++++++--
4 files changed, 38 insertions(+), 10 deletions(-)
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index eee9695c3eb5..02bf4df05016 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -530,8 +530,7 @@ static int newport_set_font(int unit, const struct console_font *op,
/* check if font is already used by other console */
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (font_data[i] != FONT_DATA
- && font_data_size(font_data[i]) == size
- && !memcmp(font_data[i], new_data, size)) {
+ && font_data_is_equal(font_data[i], new_data)) {
kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
/* current font is the same as the new one */
if (i == unit)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index ebb9c5c1b247..6fbecce606fd 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2553,14 +2553,9 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
FNTSUM(new_data) = csum;
/* Check if the same font is on some other console already */
for (i = first_fb_vc; i <= last_fb_vc; i++) {
- struct vc_data *tmp = vc_cons[i].d;
-
if (fb_display[i].userfont &&
fb_display[i].fontdata &&
- FNTSUM(fb_display[i].fontdata) == csum &&
- font_data_size(fb_display[i].fontdata) == size &&
- tmp->vc_font.width == w &&
- !memcmp(fb_display[i].fontdata, new_data, size)) {
+ font_data_is_equal(fb_display[i].fontdata, new_data)) {
kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
new_data = (u8 *)fb_display[i].fontdata;
break;
diff --git a/include/linux/font.h b/include/linux/font.h
index 3afb32b625d3..da9869ca2294 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -55,6 +55,7 @@ static inline const unsigned char *font_data_buf(font_data_t *fd)
}
unsigned int font_data_size(font_data_t *fd);
+bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs);
/*
* Font lookup
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index 8c9a6762061c..c9f6328d5dda 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -12,18 +12,25 @@
* for more details.
*/
+#include <linux/font.h>
#include <linux/module.h>
-#include <linux/types.h>
#include <linux/string.h>
+#include <linux/types.h>
+
+#include <asm/sections.h>
#if defined(__mc68000__)
#include <asm/setup.h>
#endif
-#include <linux/font.h>
/*
* Helpers for font_data_t
*/
+static bool font_data_is_internal(font_data_t *fd)
+{
+ return is_kernel_rodata((unsigned long)fd);
+}
+
/**
* font_data_size - Return size of the font data in bytes
* @fd: Font data
@@ -37,6 +44,32 @@ unsigned int font_data_size(font_data_t *fd)
}
EXPORT_SYMBOL_GPL(font_data_size);
+/**
+ * font_data_is_equal - Compares font data for equality
+ * @lhs: Left-hand side font data
+ * @rhs: Right-hand-size font data
+ *
+ * Font data is equal if is constain the same sequence of values. The
+ * helper also use the checksum, if both arguments contain it. Font data
+ * coming from different origins, internal or from user space, is never
+ * equal. Allowing this would break reference counting.
+ *
+ * Returns:
+ * True if the given font data is equal, false otherwise.
+ */
+bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs)
+{
+ if (font_data_is_internal(lhs) != font_data_is_internal(rhs))
+ return false;
+ if (font_data_size(lhs) != font_data_size(rhs))
+ return false;
+ if (FNTSUM(lhs) && FNTSUM(rhs) && FNTSUM(lhs) != FNTSUM(rhs))
+ return false;
+
+ return !memcmp(lhs, rhs, FNTSIZE(lhs));
+}
+EXPORT_SYMBOL_GPL(font_data_is_equal);
+
/*
* Font lookup
*/
--
2.52.0
^ permalink raw reply related
* [PATCH 07/13] lib/fonts: Store font data as font_data_t; update consoles
From: Thomas Zimmermann @ 2026-02-18 8:15 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Store font data as pointer to font_data_t instead of unsigned char.
Update consoles.
Pointers to font data refer to the raw data. There is a hidden header
before the data that contains additional state. Document the existing
layout and semantics of font_data_t.
The data field in struct vc_font can be used by any console. Therefore
it still points to plain data without the additional header. Fbcon sets
its value from struct fbcon_display.fontdata. Hence, update the size
test in fbcon_resize() to use struct fbcon_display.fontdata instead of
struct vc_font.data.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/console/newport_con.c | 17 ++++++-----
drivers/video/fbdev/core/fbcon.c | 44 ++++++++++++++++-----------
drivers/video/fbdev/core/fbcon.h | 3 +-
include/linux/font.h | 47 ++++++++++++++++++++++++++++-
4 files changed, 84 insertions(+), 27 deletions(-)
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 6e9d61791888..fcf76f65b06e 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -33,9 +33,9 @@
#define NEWPORT_LEN 0x10000
-#define FONT_DATA ((unsigned char *)font_vga_8x16.data)
+#define FONT_DATA font_vga_8x16.data
-static unsigned char *font_data[MAX_NR_CONSOLES];
+static font_data_t *font_data[MAX_NR_CONSOLES];
static struct newport_regs *npregs;
static unsigned long newport_addr;
@@ -370,9 +370,9 @@ static void newport_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
static void newport_putc(struct vc_data *vc, u16 charattr, unsigned int ypos,
unsigned int xpos)
{
- unsigned char *p;
+ const unsigned char *p;
- p = &font_data[vc->vc_num][(charattr & 0xff) << 4];
+ p = &font_data_buf(font_data[vc->vc_num])[(charattr & 0xff) << 4];
charattr = (charattr >> 8) & 0xff;
xpos <<= 3;
ypos <<= 4;
@@ -400,7 +400,7 @@ static void newport_putcs(struct vc_data *vc, const u16 *s,
unsigned int count, unsigned int ypos,
unsigned int xpos)
{
- unsigned char *p;
+ const unsigned char *p;
unsigned int i;
u16 charattr;
@@ -424,7 +424,7 @@ static void newport_putcs(struct vc_data *vc, const u16 *s,
NPORT_DMODE0_L32);
for (i = 0; i < count; i++, xpos += 8) {
- p = &font_data[vc->vc_num][(scr_readw(s++) & 0xff) << 4];
+ p = &font_data_buf(font_data[vc->vc_num])[(scr_readw(s++) & 0xff) << 4];
newport_wait(npregs);
@@ -503,7 +503,8 @@ static int newport_set_font(int unit, const struct console_font *op,
int h = op->height;
int size = h * op->charcount;
int i;
- unsigned char *new_data, *data = op->data, *p;
+ font_data_t *new_data;
+ unsigned char *data = op->data, *p;
/* ladis: when I grow up, there will be a day... and more sizes will
* be supported ;-) */
@@ -519,7 +520,7 @@ static int newport_set_font(int unit, const struct console_font *op,
REFCOUNT(new_data) = 0; /* usage counter */
FNTSUM(new_data) = 0;
- p = new_data;
+ p = (unsigned char *)font_data_buf(new_data);
for (i = 0; i < op->charcount; i++) {
memcpy(p, data, h);
data += 32;
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 96cf890aa0c9..73f2757155e6 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1019,8 +1019,10 @@ static const char *fbcon_startup(void)
info->pixmap.blit_y);
vc->vc_font.width = font->width;
vc->vc_font.height = font->height;
- vc->vc_font.data = (void *)(p->fontdata = font->data);
+ vc->vc_font.data = font_data_buf(font->data);
vc->vc_font.charcount = font->charcount;
+
+ p->fontdata = font->data;
}
cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
@@ -1077,11 +1079,12 @@ static void fbcon_init(struct vc_data *vc, bool init)
if (t->fontdata) {
struct vc_data *fvc = vc_cons[fg_console].d;
- vc->vc_font.data = (void *)(p->fontdata =
- fvc->vc_font.data);
+ vc->vc_font.data = fvc->vc_font.data;
vc->vc_font.width = fvc->vc_font.width;
vc->vc_font.height = fvc->vc_font.height;
vc->vc_font.charcount = fvc->vc_font.charcount;
+
+ p->fontdata = t->fontdata;
p->userfont = t->userfont;
if (p->userfont)
@@ -1096,8 +1099,10 @@ static void fbcon_init(struct vc_data *vc, bool init)
info->pixmap.blit_y);
vc->vc_font.width = font->width;
vc->vc_font.height = font->height;
- vc->vc_font.data = (void *)(p->fontdata = font->data);
+ vc->vc_font.data = font_data_buf(font->data);
vc->vc_font.charcount = font->charcount;
+
+ p->fontdata = font->data;
}
}
@@ -1408,11 +1413,12 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
svc = *default_mode;
t = &fb_display[svc->vc_num];
- if (!vc->vc_font.data) {
- vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
+ if (!p->fontdata) {
+ vc->vc_font.data = font_data_buf(t->fontdata);
vc->vc_font.width = (*default_mode)->vc_font.width;
vc->vc_font.height = (*default_mode)->vc_font.height;
vc->vc_font.charcount = (*default_mode)->vc_font.charcount;
+ p->fontdata = t->fontdata;
p->userfont = t->userfont;
if (p->userfont)
REFCOUNT(p->fontdata)++;
@@ -2052,7 +2058,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
struct fb_var_screeninfo var = info->var;
int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
- if (p->userfont && FNTSIZE(vc->vc_font.data)) {
+ if (p->userfont && FNTSIZE(p->fontdata)) {
unsigned int size = vc_font_size(&vc->vc_font);
/*
@@ -2062,7 +2068,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
* charcount can change and cannot be used to determine the
* font data allocated size.
*/
- if (!size || size > FNTSIZE(vc->vc_font.data))
+ if (!size || size > FNTSIZE(p->fontdata))
return -EINVAL;
}
@@ -2286,7 +2292,8 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
{
- const u8 *fontdata = vc->vc_font.data;
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+ font_data_t *fontdata = p->fontdata;
u8 *data = font->data;
int i, j;
@@ -2411,16 +2418,18 @@ static void set_vc_hi_font(struct vc_data *vc, bool set)
}
static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
- const u8 * data, int userfont)
+ font_data_t *data, int userfont)
{
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_par *par = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];
int resize, ret, old_userfont, old_width, old_height, old_charcount;
+ font_data_t *old_fontdata = p->fontdata;
const u8 *old_data = vc->vc_font.data;
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
- vc->vc_font.data = (void *)(p->fontdata = data);
+ p->fontdata = data;
+ vc->vc_font.data = font_data_buf(p->fontdata);
old_userfont = p->userfont;
if ((p->userfont = userfont))
REFCOUNT(data)++;
@@ -2453,12 +2462,12 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
update_screen(vc);
}
- if (old_userfont && (--REFCOUNT(old_data) == 0))
- kfree(old_data - FONT_EXTRA_WORDS * sizeof(int));
+ if (old_userfont && (--REFCOUNT(old_fontdata) == 0))
+ kfree(old_fontdata - FONT_EXTRA_WORDS * sizeof(int));
return 0;
err_out:
- p->fontdata = old_data;
+ p->fontdata = old_fontdata;
vc->vc_font.data = old_data;
if (userfont) {
@@ -2488,7 +2497,8 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
int h = font->height;
int size, alloc_size;
int i, csum;
- u8 *new_data, *data = font->data;
+ font_data_t *new_data;
+ u8 *data = font->data;
int pitch = PITCH(font->width);
/* Is there a reason why fbconsole couldn't handle any charcount >256?
@@ -2527,13 +2537,13 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
if (!new_data)
return -ENOMEM;
- memset(new_data, 0, FONT_EXTRA_WORDS * sizeof(int));
+ memset((u8 *)new_data, 0, FONT_EXTRA_WORDS * sizeof(int));
new_data += FONT_EXTRA_WORDS * sizeof(int);
FNTSIZE(new_data) = size;
REFCOUNT(new_data) = 0; /* usage counter */
for (i=0; i< charcount; i++) {
- memcpy(new_data + i*h*pitch, data + i*vpitch*pitch, h*pitch);
+ memcpy((u8 *)new_data + i * h * pitch, data + i * vpitch * pitch, h * pitch);
}
/* Since linux has a nice crc32 function use it for counting font
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index 3f4386a40237..d26ee7860cf5 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -11,6 +11,7 @@
#ifndef _VIDEO_FBCON_H
#define _VIDEO_FBCON_H
+#include <linux/font.h>
#include <linux/types.h>
#include <linux/vt_buffer.h>
#include <linux/vt_kern.h>
@@ -25,7 +26,7 @@
struct fbcon_display {
/* Filled in by the low-level console driver */
- const u_char *fontdata;
+ font_data_t *fontdata;
int userfont; /* != 0 if fontdata kmalloc()ed */
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
u_short scrollmode; /* Scroll Method, use fb_scrollmode() */
diff --git a/include/linux/font.h b/include/linux/font.h
index d929c5fa32ca..4ff8d52e59c3 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -13,12 +13,57 @@
#include <linux/types.h>
+/*
+ * font_data_t and helpers
+ */
+
+/**
+ * font_data_t - Raw font data
+ *
+ * Values of type font_data_t store a pointer to raw font data. The format
+ * is monochrome. Each bit sets a pixel of a stored glyph. Font data does
+ * not store geometry information for the individual glyphs. Users of the
+ * font have to store glyph size, pitch and characer count separately.
+ *
+ * Font data in font_data_t is not equivalent to raw u8. Each pointer stores
+ * an additional hidden header before the fotn data. The layout is
+ *
+ * +------+-----------------------------+
+ * | -16 | CRC32 Checksum (optional) |
+ * | -12 | <Unused> |
+ * | -8 | Number of data bytes |
+ * | -4 | Reference count |
+ * +------+-----------------------------+
+ * | 0 | Data buffer |
+ * | ... | |
+ * +------+-----------------------------+
+ *
+ * Use helpers to access font_data_t. Use font_data_buf() to get the stored data.
+ */
+typedef const unsigned char font_data_t;
+
+/**
+ * font_data_buf() - Returns the font data as raw bytes
+ * @fd: The font data
+ *
+ * Returns:
+ * The raw font data. The provided buffer is read-only.
+ */
+static inline const unsigned char *font_data_buf(font_data_t *fd)
+{
+ return (const unsigned char *)fd;
+}
+
+/*
+ * Font lookup
+ */
+
struct font_desc {
int idx;
const char *name;
unsigned int width, height;
unsigned int charcount;
- const void *data;
+ font_data_t *data;
int pref;
};
--
2.52.0
^ permalink raw reply related
* [PATCH 06/13] lib/fonts: Remove FNTCHARCNT()
From: Thomas Zimmermann @ 2026-02-18 8:15 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
The character count in the font data is unused. The internal fonts also
do not set it. Remove FNTCHARCNT().
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/console/newport_con.c | 1 -
include/linux/font.h | 1 -
2 files changed, 2 deletions(-)
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index a474c5e8e97e..6e9d61791888 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -516,7 +516,6 @@ static int newport_set_font(int unit, const struct console_font *op,
new_data += FONT_EXTRA_WORDS * sizeof(int);
FNTSIZE(new_data) = size;
- FNTCHARCNT(new_data) = op->charcount;
REFCOUNT(new_data) = 0; /* usage counter */
FNTSUM(new_data) = 0;
diff --git a/include/linux/font.h b/include/linux/font.h
index fd8625cd76b2..d929c5fa32ca 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -68,7 +68,6 @@ extern const struct font_desc *get_default_font(int xres, int yres,
/* Extra word getters */
#define REFCOUNT(fd) (((int *)(fd))[-1])
#define FNTSIZE(fd) (((int *)(fd))[-2])
-#define FNTCHARCNT(fd) (((int *)(fd))[-3])
#define FNTSUM(fd) (((int *)(fd))[-4])
#define FONT_EXTRA_WORDS 4
--
2.52.0
^ permalink raw reply related
* [PATCH 11/13] lib/fonts: Create font_data_t from struct console_font with font_data_import()
From: Thomas Zimmermann @ 2026-02-18 8:16 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Add font_data_import() and update consoles to use it.
The implementation of font_data_import() is based on code from fbcon,
which supports overflow checks and crc32 checksums. Fbcon uses the crc32
checksum.
Newport_con now implements the same overflow checks as fbcon. As before,
this console does not support checksums, which are optional. Newport_con
can now also handle input font data with a vertical pitch other than 32
bytes. (The vertical pitch is the offset between two glyphs in the font
data.)
As an internal change, remove the const qualifier from the data field
if struct font_data. This allows font_data_import() to write the data
without type casting. For all users of the font data via font_data_t,
the stored data is still read only.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/console/newport_con.c | 22 ++--------
drivers/video/fbdev/core/fbcon.c | 38 ++----------------
include/linux/font.h | 6 ++-
lib/fonts/fonts.c | 62 +++++++++++++++++++++++++++++
4 files changed, 75 insertions(+), 53 deletions(-)
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 8870555cf837..15451c6512f7 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -501,31 +501,17 @@ static int newport_set_font(int unit, const struct console_font *op,
{
int w = op->width;
int h = op->height;
- int size = h * op->charcount;
int i;
font_data_t *new_data;
- unsigned char *data = op->data, *p;
/* ladis: when I grow up, there will be a day... and more sizes will
* be supported ;-) */
- if ((w != 8) || (h != 16) || (vpitch != 32)
- || (op->charcount != 256 && op->charcount != 512))
+ if (w != 8 || h != 16 || (op->charcount != 256 && op->charcount != 512))
return -EINVAL;
- if (!(new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size,
- GFP_USER))) return -ENOMEM;
-
- new_data += FONT_EXTRA_WORDS * sizeof(int);
- FNTSIZE(new_data) = size;
- REFCOUNT(new_data) = 1; /* usage counter */
- FNTSUM(new_data) = 0;
-
- p = (unsigned char *)font_data_buf(new_data);
- for (i = 0; i < op->charcount; i++) {
- memcpy(p, data, h);
- data += 32;
- p += h;
- }
+ new_data = font_data_import(op, vpitch, NULL);
+ if (IS_ERR(new_data))
+ return PTR_ERR(new_data);
/* check if font is already used by other console */
for (i = 0; i < MAX_NR_CONSOLES; i++) {
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index b1123f3911d7..30d82290d01f 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2044,8 +2044,6 @@ static void updatescrollmode(struct fbcon_display *p,
updatescrollmode_accel(p, info, vc);
}
-#define PITCH(w) (((w) + 7) >> 3)
-
static int fbcon_resize(struct vc_data *vc, unsigned int width,
unsigned int height, bool from_user)
{
@@ -2429,7 +2427,6 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
p->fontdata = data;
vc->vc_font.data = font_data_buf(p->fontdata);
-
old_width = vc->vc_font.width;
old_height = vc->vc_font.height;
old_charcount = vc->vc_font.charcount;
@@ -2487,11 +2484,8 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
unsigned charcount = font->charcount;
int w = font->width;
int h = font->height;
- int size, alloc_size;
- int i, csum, ret;
+ int i, ret;
font_data_t *new_data;
- const u8 *data = font->data;
- int pitch = PITCH(font->width);
/* Is there a reason why fbconsole couldn't handle any charcount >256?
* If not this check should be changed to charcount < 256 */
@@ -2515,34 +2509,10 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
if (fbcon_invalid_charcount(info, charcount))
return -EINVAL;
- /* Check for integer overflow in font size calculation */
- if (check_mul_overflow(h, pitch, &size) ||
- check_mul_overflow(size, charcount, &size))
- return -EINVAL;
-
- /* Check for overflow in allocation size calculation */
- if (check_add_overflow(FONT_EXTRA_WORDS * sizeof(int), size, &alloc_size))
- return -EINVAL;
-
- new_data = kmalloc(alloc_size, GFP_USER);
-
- if (!new_data)
- return -ENOMEM;
-
- memset((u8 *)new_data, 0, FONT_EXTRA_WORDS * sizeof(int));
-
- new_data += FONT_EXTRA_WORDS * sizeof(int);
- FNTSIZE(new_data) = size;
- REFCOUNT(new_data) = 1; /* usage counter */
- for (i=0; i< charcount; i++) {
- memcpy((u8 *)new_data + i * h * pitch, data + i * vpitch * pitch, h * pitch);
- }
-
- /* Since linux has a nice crc32 function use it for counting font
- * checksums. */
- csum = crc32(0, new_data, size);
+ new_data = font_data_import(font, vpitch, crc32);
+ if (IS_ERR(new_data))
+ return PTR_ERR(new_data);
- FNTSUM(new_data) = csum;
/* Check if the same font is on some other console already */
for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (fb_display[i].fontdata &&
diff --git a/include/linux/font.h b/include/linux/font.h
index d548684e6430..5a1bf433b275 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -13,6 +13,8 @@
#include <linux/types.h>
+struct console_font;
+
/*
* font_data_t and helpers
*/
@@ -54,6 +56,8 @@ static inline const unsigned char *font_data_buf(font_data_t *fd)
return (const unsigned char *)fd;
}
+font_data_t *font_data_import(const struct console_font *font, unsigned int vpitch,
+ u32 (*calc_csum)(u32, const void *, size_t));
void font_data_get(font_data_t *fd);
bool font_data_put(font_data_t *fd);
unsigned int font_data_size(font_data_t *fd);
@@ -124,7 +128,7 @@ extern const struct font_desc *get_default_font(int xres, int yres,
struct font_data {
unsigned int extra[FONT_EXTRA_WORDS];
- const unsigned char data[];
+ unsigned char data[];
} __packed;
#endif /* _VIDEO_FONT_H */
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index 1da0acdebf53..9b5355f6d2dc 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -14,7 +14,9 @@
#include <linux/container_of.h>
#include <linux/font.h>
+#include <linux/kd.h>
#include <linux/module.h>
+#include <linux/overflow.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
@@ -24,6 +26,8 @@
#include <asm/setup.h>
#endif
+#define console_font_pitch(font) DIV_ROUND_UP((font)->width, 8)
+
/*
* Helpers for font_data_t
*/
@@ -46,6 +50,64 @@ static void font_data_free(font_data_t *fd)
kfree(to_font_data_struct(fd));
}
+/**
+ * font_data_import - Allocates and initializes font data from user space
+ * @font: A font from user space
+ * @vpitch: The size of a single glyph in @font in bytes
+ * @calc_csum: An optional helper to calculate a chechsum
+ *
+ * Font data from user space must be translated to the kernel's format. The
+ * font's glyph geometry and data is provided in @font. The parameter @vpitch
+ * gives the number of bytes per glyph, including trailing bytes.
+ *
+ * The parameter @calc_sum is optional. Fbcon passes crc32() to calculate the
+ * font data's checksum.
+ *
+ * Returns:
+ * Newly initialized font data on success, or a pointer-encoded errno value otherwise.
+ */
+font_data_t *font_data_import(const struct console_font *font, unsigned int vpitch,
+ u32 (*calc_csum)(u32, const void *, size_t))
+{
+ unsigned int pitch = console_font_pitch(font);
+ unsigned int h = font->height;
+ unsigned int charcount = font->charcount;
+ const unsigned char *data = font->data;
+ u32 csum = 0;
+ struct font_data *font_data;
+ int size, alloc_size;
+ unsigned int i;
+ font_data_t *fd;
+
+ /* Check for integer overflow in font-size calculation */
+ if (check_mul_overflow(h, pitch, &size) ||
+ check_mul_overflow(size, charcount, &size))
+ return ERR_PTR(-EINVAL);
+
+ /* Check for overflow in allocation size calculation */
+ if (check_add_overflow(sizeof(*font_data), size, &alloc_size))
+ return ERR_PTR(-EINVAL);
+
+ font_data = kmalloc(alloc_size, GFP_USER);
+ if (!font_data)
+ return ERR_PTR(-ENOMEM);
+ memset(font_data->extra, 0, sizeof(font_data->extra));
+
+ for (i = 0; i < charcount; ++i)
+ memcpy(font_data->data + i * h * pitch, data + i * vpitch * pitch, h * pitch);
+
+ if (calc_csum)
+ csum = calc_csum(0, font_data->data, size);
+
+ fd = font_data->data;
+ REFCOUNT(fd) = 1; /* start with reference acquired */
+ FNTSIZE(fd) = size;
+ FNTSUM(fd) = csum;
+
+ return fd;
+}
+EXPORT_SYMBOL_GPL(font_data_import);
+
/**
* font_data_get - Acquires a reference on font data
* @fd: Font data
--
2.52.0
^ permalink raw reply related
* [PATCH 01/13] fbdev: Declare src parameter of fb_pad_ helpers as constant
From: Thomas Zimmermann @ 2026-02-18 8:15 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Fbdev's padding helpers do not modify the source buffer. Declare the
parameter as 'const'.
Fbcon's font-rendering code calls these helpers with the font data.
Declaring src as const will allow for making the font data constant
as well.
While at it, also remove the extern qualifier from the function
declarations in the header file.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/fbdev/core/fbmem.c | 6 +++---
include/linux/fb.h | 10 +++++-----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index eff757ebbed1..9c78fd32e7b3 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -91,14 +91,14 @@ EXPORT_SYMBOL(fb_get_color_depth);
/*
* Data padding functions.
*/
-void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
+void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, const u8 *src, u32 s_pitch, u32 height)
{
__fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);
}
EXPORT_SYMBOL(fb_pad_aligned_buffer);
-void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height,
- u32 shift_high, u32 shift_low, u32 mod)
+void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, const u8 *src, u32 idx, u32 height,
+ u32 shift_high, u32 shift_low, u32 mod)
{
u8 mask = (u8) (0xfff << shift_high), tmp;
int i, j;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index b8b6f54f3312..9a8051f258ac 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -606,9 +606,9 @@ extern int register_framebuffer(struct fb_info *fb_info);
extern void unregister_framebuffer(struct fb_info *fb_info);
extern int devm_register_framebuffer(struct device *dev, struct fb_info *fb_info);
extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);
-extern void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx,
- u32 height, u32 shift_high, u32 shift_low, u32 mod);
-extern void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height);
+void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, const u8 *src, u32 idx, u32 height,
+ u32 shift_high, u32 shift_low, u32 mod);
+void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, const u8 *src, u32 s_pitch, u32 height);
extern void fb_set_suspend(struct fb_info *info, int state);
extern int fb_get_color_depth(struct fb_var_screeninfo *var,
struct fb_fix_screeninfo *fix);
@@ -625,8 +625,8 @@ static inline void unlock_fb_info(struct fb_info *info)
mutex_unlock(&info->lock);
}
-static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch,
- u8 *src, u32 s_pitch, u32 height)
+static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, const u8 *src, u32 s_pitch,
+ u32 height)
{
u32 i, j;
--
2.52.0
^ permalink raw reply related
* [PATCH 08/13] lib/fonts: Read font size with font_data_size()
From: Thomas Zimmermann @ 2026-02-18 8:15 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Add font_data_size() and update consoles to use it.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/console/newport_con.c | 2 +-
drivers/video/fbdev/core/fbcon.c | 14 +++++++-------
include/linux/font.h | 2 ++
lib/fonts/fonts.c | 21 +++++++++++++++++++++
4 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index fcf76f65b06e..eee9695c3eb5 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -530,7 +530,7 @@ static int newport_set_font(int unit, const struct console_font *op,
/* check if font is already used by other console */
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (font_data[i] != FONT_DATA
- && FNTSIZE(font_data[i]) == size
+ && font_data_size(font_data[i]) == size
&& !memcmp(font_data[i], new_data, size)) {
kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
/* current font is the same as the new one */
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 73f2757155e6..ebb9c5c1b247 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2058,7 +2058,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
struct fb_var_screeninfo var = info->var;
int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
- if (p->userfont && FNTSIZE(p->fontdata)) {
+ if (p->userfont && font_data_size(p->fontdata)) {
unsigned int size = vc_font_size(&vc->vc_font);
/*
@@ -2068,7 +2068,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
* charcount can change and cannot be used to determine the
* font data allocated size.
*/
- if (!size || size > FNTSIZE(p->fontdata))
+ if (!size || size > font_data_size(p->fontdata))
return -EINVAL;
}
@@ -2307,7 +2307,7 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigne
if (font->width <= 8) {
j = vc->vc_font.height;
- if (font->charcount * j > FNTSIZE(fontdata))
+ if (font->charcount * j > font_data_size(fontdata))
return -EINVAL;
for (i = 0; i < font->charcount; i++) {
@@ -2318,7 +2318,7 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigne
}
} else if (font->width <= 16) {
j = vc->vc_font.height * 2;
- if (font->charcount * j > FNTSIZE(fontdata))
+ if (font->charcount * j > font_data_size(fontdata))
return -EINVAL;
for (i = 0; i < font->charcount; i++) {
@@ -2328,7 +2328,7 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigne
fontdata += j;
}
} else if (font->width <= 24) {
- if (font->charcount * (vc->vc_font.height * sizeof(u32)) > FNTSIZE(fontdata))
+ if (font->charcount * (vc->vc_font.height * sizeof(u32)) > font_data_size(fontdata))
return -EINVAL;
for (i = 0; i < font->charcount; i++) {
@@ -2343,7 +2343,7 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigne
}
} else {
j = vc->vc_font.height * 4;
- if (font->charcount * j > FNTSIZE(fontdata))
+ if (font->charcount * j > font_data_size(fontdata))
return -EINVAL;
for (i = 0; i < font->charcount; i++) {
@@ -2558,7 +2558,7 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
if (fb_display[i].userfont &&
fb_display[i].fontdata &&
FNTSUM(fb_display[i].fontdata) == csum &&
- FNTSIZE(fb_display[i].fontdata) == size &&
+ font_data_size(fb_display[i].fontdata) == size &&
tmp->vc_font.width == w &&
!memcmp(fb_display[i].fontdata, new_data, size)) {
kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
diff --git a/include/linux/font.h b/include/linux/font.h
index 4ff8d52e59c3..3afb32b625d3 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -54,6 +54,8 @@ static inline const unsigned char *font_data_buf(font_data_t *fd)
return (const unsigned char *)fd;
}
+unsigned int font_data_size(font_data_t *fd);
+
/*
* Font lookup
*/
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index a7f118b30171..8c9a6762061c 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -20,6 +20,27 @@
#endif
#include <linux/font.h>
+/*
+ * Helpers for font_data_t
+ */
+
+/**
+ * font_data_size - Return size of the font data in bytes
+ * @fd: Font data
+ *
+ * Returns:
+ * The number of bytes in the given font data.
+ */
+unsigned int font_data_size(font_data_t *fd)
+{
+ return FNTSIZE(fd);
+}
+EXPORT_SYMBOL_GPL(font_data_size);
+
+/*
+ * Font lookup
+ */
+
static const struct font_desc *fonts[] = {
#ifdef CONFIG_FONT_8x8
&font_vga_8x8,
--
2.52.0
^ permalink raw reply related
* [PATCH 05/13] lib/fonts: Remove trailing whitespaces
From: Thomas Zimmermann @ 2026-02-18 8:15 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Fix coding style. No functional changes.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
lib/fonts/font_acorn_8x8.c | 2 +-
lib/fonts/font_mini_4x6.c | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/lib/fonts/font_acorn_8x8.c b/lib/fonts/font_acorn_8x8.c
index 18755c33d249..af5fa72aa8b7 100644
--- a/lib/fonts/font_acorn_8x8.c
+++ b/lib/fonts/font_acorn_8x8.c
@@ -68,7 +68,7 @@ static const struct font_data acorndata_8x8 = {
/* 3A */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, /* : */
/* 3B */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, /* ; */
/* 3C */ 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, /* < */
-/* 3D */ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* = */
+/* 3D */ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* = */
/* 3E */ 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, /* > */
/* 3F */ 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, /* ? */
/* 40 */ 0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3C, 0x00, /* @ */
diff --git a/lib/fonts/font_mini_4x6.c b/lib/fonts/font_mini_4x6.c
index 8d39fd447952..cc21dc70cfd1 100644
--- a/lib/fonts/font_mini_4x6.c
+++ b/lib/fonts/font_mini_4x6.c
@@ -18,15 +18,15 @@
s{((0x)?[0-9a-fA-F]+)(.*\[([\*\ ]{4})\])}{
($num,$pat,$bits) = ($1,$3,$4);
-
+
$bits =~ s/([^\s0])|(.)/ defined($1) + 0 /ge;
-
+
$num = ord(pack("B8", $bits));
$num |= $num >> 4;
$num = sprintf("0x%.2x", $num);
-
+
#print "$num,$pat,$bits\n";
-
+
$num . $pat;
}ge;
--
2.52.0
^ permalink raw reply related
* [PATCH 04/13] vt: Calculate font-buffer size with vc_font_size()
From: Thomas Zimmermann @ 2026-02-18 8:15 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
In fbcon, fbcon_resize() computes the size of the font buffer from the
values stored in vc_font. Move these calculations to the dedicated helpers
vc_font_pitch() and vc_font_size().
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/fbdev/core/fbcon.c | 9 ++-------
include/linux/console_struct.h | 28 ++++++++++++++++++++++++++++
2 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 5467b37b1441..96cf890aa0c9 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2042,7 +2042,6 @@ static void updatescrollmode(struct fbcon_display *p,
}
#define PITCH(w) (((w) + 7) >> 3)
-#define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */
static int fbcon_resize(struct vc_data *vc, unsigned int width,
unsigned int height, bool from_user)
@@ -2054,8 +2053,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
if (p->userfont && FNTSIZE(vc->vc_font.data)) {
- int size;
- int pitch = PITCH(vc->vc_font.width);
+ unsigned int size = vc_font_size(&vc->vc_font);
/*
* If user font, ensure that a possible change to user font
@@ -2064,10 +2062,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
* charcount can change and cannot be used to determine the
* font data allocated size.
*/
- if (pitch <= 0)
- return -EINVAL;
- size = CALC_FONTSZ(vc->vc_font.height, pitch, vc->vc_font.charcount);
- if (size > FNTSIZE(vc->vc_font.data))
+ if (!size || size > FNTSIZE(vc->vc_font.data))
return -EINVAL;
}
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index 7fdcae6ed49c..fbb5dd5f6761 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -83,6 +83,34 @@ struct vc_font {
const unsigned char *data;
};
+/**
+ * vc_font_pitch - Calculates the number of bytes between two adjacent scanlines
+ * @font: The VC font
+ *
+ * Returns:
+ * The number of bytes between two adjacent scanlines in the font data
+ */
+static inline unsigned int vc_font_pitch(const struct vc_font *font)
+{
+ return DIV_ROUND_UP(font->width, 8);
+}
+
+/**
+ * vc_font_size - Calculates the size of the font data in bytes
+ * @font: The VC font
+ *
+ * vc_font_size() calculates the number of bytes of font data in the
+ * font specified by @font. The function calculates the size from the
+ * font parameters.
+ *
+ * Returns:
+ * The size of the font data in bytes.
+ */
+static inline unsigned int vc_font_size(const struct vc_font *font)
+{
+ return font->height * vc_font_pitch(font) * font->charcount;
+}
+
/*
* Example: vc_data of a console that was scrolled 3 lines down.
*
--
2.52.0
^ permalink raw reply related
* [PATCH 02/13] vt: Remove trailing whitespaces
From: Thomas Zimmermann @ 2026-02-18 8:15 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Fix coding style. No functional changes.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
include/linux/console_struct.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index 13b35637bd5a..ebdb9750d348 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -120,7 +120,7 @@ struct vc_data {
unsigned short vc_complement_mask; /* [#] Xor mask for mouse pointer */
unsigned short vc_s_complement_mask; /* Saved mouse pointer mask */
unsigned long vc_pos; /* Cursor address */
- /* fonts */
+ /* fonts */
unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
struct console_font vc_font; /* Current VC font set */
unsigned short vc_video_erase_char; /* Background erase character */
--
2.52.0
^ permalink raw reply related
* [PATCH 03/13] vt: Store font in struct vc_font
From: Thomas Zimmermann @ 2026-02-18 8:15 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20260218083855.10743-1-tzimmermann@suse.de>
Replace struct console_font with struct vc_font for the type of the
vc_font field of struct vc_data. Struct console_font is UAPI, which
prevents further changes. Hence a new data type is required.
Struct console_font has a documented vertical pitch of 32 bytes. This
is not the case after the font data has been loaded into the kernel.
Changing the type of vc_font addresses this inconsistency.
The font data is now declared as constant, as it might come from the
kernel's read-only section. There's some fallout throughout the console
code where non-const variables refer to it. Fix them. A later update
will declare the font data to a dedicated data type.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/fbdev/core/bitblit.c | 11 +++++------
drivers/video/fbdev/core/fbcon.c | 4 ++--
drivers/video/fbdev/core/fbcon.h | 4 ++--
include/linux/console_struct.h | 29 +++++++++++++++++++++++++++--
4 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index 085ffb44c51a..7478accea8ec 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -22,8 +22,7 @@
/*
* Accelerated handlers.
*/
-static void update_attr(u8 *dst, u8 *src, int attribute,
- struct vc_data *vc)
+static void update_attr(u8 *dst, const u8 *src, int attribute, struct vc_data *vc)
{
int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
int width = DIV_ROUND_UP(vc->vc_font.width, 8);
@@ -81,7 +80,7 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
unsigned int charcnt = vc->vc_font.charcount;
u32 idx = vc->vc_font.width >> 3;
- u8 *src;
+ const u8 *src;
while (cnt--) {
u16 ch = scr_readw(s++) & charmask;
@@ -120,7 +119,7 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
u32 shift_low = 0, mod = vc->vc_font.width % 8;
u32 shift_high = 8;
u32 idx = vc->vc_font.width >> 3;
- u8 *src;
+ const u8 *src;
while (cnt--) {
u16 ch = scr_readw(s++) & charmask;
@@ -267,7 +266,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1;
- char *src;
+ const u8 *src;
cursor.set = 0;
@@ -278,7 +277,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
attribute = get_attribute(info, c);
src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
- if (par->cursor_state.image.data != src ||
+ if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
par->cursor_state.image.data = src;
cursor.set |= FB_CUR_SETIMAGE;
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 34ea14412ace..5467b37b1441 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2291,7 +2291,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
{
- u8 *fontdata = vc->vc_font.data;
+ const u8 *fontdata = vc->vc_font.data;
u8 *data = font->data;
int i, j;
@@ -2422,7 +2422,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
struct fbcon_par *par = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];
int resize, ret, old_userfont, old_width, old_height, old_charcount;
- u8 *old_data = vc->vc_font.data;
+ const u8 *old_data = vc->vc_font.data;
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
vc->vc_font.data = (void *)(p->fontdata = data);
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index fca14e9b729b..3f4386a40237 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -82,8 +82,8 @@ struct fbcon_par {
int rotate;
int cur_rotate;
char *cursor_data;
- u8 *fontbuffer;
- u8 *fontdata;
+ u8 *fontbuffer;
+ const u8 *fontdata;
u8 *cursor_src;
u32 cursor_size;
u32 fd_size;
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index ebdb9750d348..7fdcae6ed49c 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -13,8 +13,9 @@
#ifndef _LINUX_CONSOLE_STRUCT_H
#define _LINUX_CONSOLE_STRUCT_H
-#include <linux/wait.h>
+#include <linux/math.h>
#include <linux/vt.h>
+#include <linux/wait.h>
#include <linux/workqueue.h>
struct uni_pagedict;
@@ -58,6 +59,30 @@ struct vc_state {
bool reverse;
};
+/**
+ * struct vc_font - Describes a font
+ * @width: The width of a single glyph in bits
+ * @height: The height of a single glyph in scanlines
+ * @charcount: The number of glyphs in the font
+ * @data: The raw font data
+ *
+ * Font data is organized as an array of glyphs. Each glyph is a bitmap with
+ * set bits indicating the foreground color. Unset bits indicate background
+ * color. The fields @width and @height store a single glyph's number of
+ * horizontal bits and vertical scanlines. If width is not a multiple of 8,
+ * there are trailing bits to fill up the byte. These bits should not be drawn.
+ *
+ * The field @data points to the first glphy's first byte. The value @charcount
+ * gives the number of glyphs in the font. There are no empty scanlines between
+ * two adjacent glyphs.
+ */
+struct vc_font {
+ unsigned int width;
+ unsigned int height;
+ unsigned int charcount;
+ const unsigned char *data;
+};
+
/*
* Example: vc_data of a console that was scrolled 3 lines down.
*
@@ -122,7 +147,7 @@ struct vc_data {
unsigned long vc_pos; /* Cursor address */
/* fonts */
unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
- struct console_font vc_font; /* Current VC font set */
+ struct vc_font vc_font; /* Current VC font set */
unsigned short vc_video_erase_char; /* Background erase character */
/* VT terminal data */
unsigned int vc_state; /* Escape sequence parser state */
--
2.52.0
^ permalink raw reply related
* [PATCH 00/13] vc,fbcon,fonts: Proper handling of font data
From: Thomas Zimmermann @ 2026-02-18 8:15 UTC (permalink / raw)
To: gregkh, deller, sam
Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
Provide helpers for handling console font data. Update consoles and VT.
VT's vc_state stores fotn data as a plain byte array of glphys. Fbcon,
newport_con and the kernel's internal fonts store the glyph data as an
array of plain bytes plus a hidden header for refcounting, check sums and
buffer sizes. The refcounting only works for user-space fonts but not
for internal fonts. Font-data handling is duplicated in several places.
Most of the font handling is open-coded and mixed up with VT's plain glyph
arrays.
To addiress these issues, add proper handling of font data to all involved
components: struct vc_font for font state in VC; a font data type for the
consoles. Then implement interfaces for handling font data one by one.
Patch 1 prepares the fbdev interface.
Patches 2 to 4 prepare VT's font handling.
Patches 5 to 13 refactor fbcon and newport_con to use clean interfaces for
their fonts.
Fbcon has long been a source of problems and bug reports. [1] With its
confusing implementation, it is hard to find the cause of these bugs.
Cleaning up the fbcon code will hopefully help with resolving bug reports
in the future.
The series has been tested with fbcon under DRM's bochs driver by changing
fonts at runtime useing the setfont utility. The changes to newport_con have
only been tested to compile.
[1] https://lore.kernel.org/all/6992c84c.a70a0220.2c38d7.00e8.GAE@google.com/
[2] https://www.man7.org/linux/man-pages/man8/setfont.8.html
Thomas Zimmermann (13):
fbdev: Declare src parameter of fb_pad_ helpers as constant
vt: Remove trailing whitespaces
vt: Store font in struct vc_font
vt: Calculate font-buffer size with vc_font_size()
lib/fonts: Remove trailing whitespaces
lib/fonts: Remove FNTCHARCNT()
lib/fonts: Store font data as font_data_t; update consoles
lib/fonts: Read font size with font_data_size()
lib/fonts: Compare font data for equality with font_data_is_equal()
lib/fonts: Manage font-data lifetime with font_data_get/_put()
lib/fonts: Create font_data_t from struct console_font with
font_data_import()
lib/fonts: Store font data for user space with font_data_export()
lib/fonts: Remove internal symbols and macros from public header file
drivers/video/console/newport_con.c | 61 +++----
drivers/video/fbdev/core/bitblit.c | 11 +-
drivers/video/fbdev/core/fbcon.c | 194 +++++++----------------
drivers/video/fbdev/core/fbcon.h | 8 +-
drivers/video/fbdev/core/fbmem.c | 6 +-
include/linux/console_struct.h | 59 ++++++-
include/linux/fb.h | 10 +-
include/linux/font.h | 90 +++++++----
lib/fonts/font.h | 52 ++++++
lib/fonts/font_10x18.c | 2 +-
lib/fonts/font_6x10.c | 3 +-
lib/fonts/font_6x11.c | 2 +-
lib/fonts/font_6x8.c | 3 +-
lib/fonts/font_7x14.c | 2 +-
lib/fonts/font_8x16.c | 3 +-
lib/fonts/font_8x8.c | 2 +-
lib/fonts/font_acorn_8x8.c | 4 +-
lib/fonts/font_mini_4x6.c | 10 +-
lib/fonts/font_pearl_8x8.c | 2 +-
lib/fonts/font_sun12x22.c | 3 +-
lib/fonts/font_sun8x16.c | 3 +-
lib/fonts/font_ter10x18.c | 4 +-
lib/fonts/font_ter16x32.c | 4 +-
lib/fonts/fonts.c | 236 +++++++++++++++++++++++++++-
24 files changed, 521 insertions(+), 253 deletions(-)
create mode 100644 lib/fonts/font.h
base-commit: 0082025812a31eda451fb14f13f52683ed375c49
--
2.52.0
^ permalink raw reply
* Re: [GIT PULL] fbdev fixes and updates for v7.0-rc1
From: Nathan Chancellor @ 2026-02-17 21:45 UTC (permalink / raw)
To: Linus Torvalds
Cc: Helge Deller, Nicolas Schier, linux-kernel, linux-fbdev,
dri-devel, Linux Kbuild mailing list
In-Reply-To: <CAHk-=wj03hLzK2D=+OYmjgcmGM+XYymp8GyaEs=C0=rXG2nb7w@mail.gmail.com>
Hi Linus,
On Sat, Feb 14, 2026 at 02:47:47PM -0800, Linus Torvalds wrote:
> [ Adding Kconfig maintainers and linux-kbuild list ]
>
> On Sat, 14 Feb 2026 at 13:30, Helge Deller <deller@kernel.org> wrote:
> >
> > Linus, I'm really sorry, but I messed up drivers/gpu/drm/Kconfig while
> > trying to fix a merge conflict.
> > My patch series should not have touched drivers/gpu/drm/Kconfig at all.
> > That's purely my fault and not the fault of the patch author.
>
> Humm. Funky how the Kconfig parts never complained about the
> duplication of all those source lines, so the problem was basically
> entirely hidden and things still "worked" even though that Kconfig
> file had been so messed up.
>
> I'm not sure if the Kconfig tools could perhaps warn about this kind
> of duplication - we might have some of it intentionally - but it does
> make me go "Hmm".
>
> Nathan, Nicolas, comments? See that commit ca4ee40bf13d for the
> partial revert, and notice how Kconfig is entirely happy both before
> and after that..
It seems like we should be able to check if we have seen an sourced
Kconfig already, presumably somewhere in or around zconf_nextfile() in
scripts/kconfig/lexer.l. Not sure how complicated it will be, I will see
if I can wire something like that up during the next development cycle
(amongst the other things on my plate). Given how wonky that looks in
menuconfig and the like, maybe it is worth making that a hard error.
Cheers,
Nathan
^ permalink raw reply
* [PATCH v4 01/12] firmware: google: framebuffer: Do not unregister platform device
From: Thomas Zimmermann @ 2026-02-17 15:56 UTC (permalink / raw)
To: tzungbi, briannorris, jwerner, javierm, samuel, maarten.lankhorst,
mripard, airlied, simona
Cc: chrome-platform, dri-devel, Thomas Zimmermann, Hans de Goede,
linux-fbdev, stable
In-Reply-To: <20260217155836.96267-1-tzimmermann@suse.de>
The native driver takes over the framebuffer aperture by removing the
system- framebuffer platform device. Afterwards the pointer in drvdata
is dangling. Remove the entire logic around drvdata and let the kernel's
aperture helpers handle this. The platform device depends on the native
hardware device instead of the coreboot device anyway.
When commit 851b4c14532d ("firmware: coreboot: Add coreboot framebuffer
driver") added the coreboot framebuffer code, the kernel did not support
device-based aperture management. Instead native driviers only removed
the conflicting fbdev device. At that point, unregistering the framebuffer
device most likely worked correctly. It was definitely broken after
commit d9702b2a2171 ("fbdev/simplefb: Do not use struct
fb_info.apertures"). So take this commit for the Fixes tag. Earlier
releases might work depending on the native hardware driver.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Fixes: d9702b2a2171 ("fbdev/simplefb: Do not use struct fb_info.apertures")
Acked-by: Tzung-Bi Shih <tzungbi@kernel.org>
Acked-by: Julius Werner <jwerner@chromium.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Javier Martinez Canillas <javierm@redhat.com>
Cc: Hans de Goede <hansg@kernel.org>
Cc: linux-fbdev@vger.kernel.org
Cc: <stable@vger.kernel.org> # v6.3+
---
drivers/firmware/google/framebuffer-coreboot.c | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c
index c68c9f56370f..4e9177105992 100644
--- a/drivers/firmware/google/framebuffer-coreboot.c
+++ b/drivers/firmware/google/framebuffer-coreboot.c
@@ -81,19 +81,10 @@ static int framebuffer_probe(struct coreboot_device *dev)
sizeof(pdata));
if (IS_ERR(pdev))
pr_warn("coreboot: could not register framebuffer\n");
- else
- dev_set_drvdata(&dev->dev, pdev);
return PTR_ERR_OR_ZERO(pdev);
}
-static void framebuffer_remove(struct coreboot_device *dev)
-{
- struct platform_device *pdev = dev_get_drvdata(&dev->dev);
-
- platform_device_unregister(pdev);
-}
-
static const struct coreboot_device_id framebuffer_ids[] = {
{ .tag = CB_TAG_FRAMEBUFFER },
{ /* sentinel */ }
@@ -102,7 +93,6 @@ MODULE_DEVICE_TABLE(coreboot, framebuffer_ids);
static struct coreboot_driver framebuffer_driver = {
.probe = framebuffer_probe,
- .remove = framebuffer_remove,
.drv = {
.name = "framebuffer",
},
--
2.52.0
^ permalink raw reply related
* [syzbot] Monthly fbdev report (Feb 2026)
From: syzbot @ 2026-02-16 7:33 UTC (permalink / raw)
To: deller, dri-devel, linux-fbdev, linux-kernel, syzkaller-bugs
Hello fbdev maintainers/developers,
This is a 31-day syzbot report for the fbdev subsystem.
All related reports/information can be found at:
https://syzkaller.appspot.com/upstream/s/fbdev
During the period, 0 new issues were detected and 0 were fixed.
In total, 5 issues are still open and 29 have already been fixed.
Some of the still happening issues:
Ref Crashes Repro Title
<1> 1321 Yes KASAN: slab-out-of-bounds Read in fbcon_prepare_logo
https://syzkaller.appspot.com/bug?extid=0c815b25cdb3678e7083
<2> 1281 Yes KASAN: vmalloc-out-of-bounds Write in imageblit (6)
https://syzkaller.appspot.com/bug?extid=5a40432dfe8f86ee657a
<3> 161 No KASAN: vmalloc-out-of-bounds Write in fillrect
https://syzkaller.appspot.com/bug?extid=7a63ce155648954e749b
<4> 9 No KASAN: slab-out-of-bounds Read in soft_cursor (2)
https://syzkaller.appspot.com/bug?extid=ae44b38396335bd847cd
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
To disable reminders for individual bugs, reply with the following command:
#syz set <Ref> no-reminders
To change bug's subsystems, reply with:
#syz set <Ref> subsystems: new-subsystem
You may send multiple commands in a single email message.
^ permalink raw reply
* Re: [PATCH v5 0/7] fbdev: au1100fb: support COMPILE_TEST and fix multi-device support and other cleanups
From: Helge Deller @ 2026-02-16 1:52 UTC (permalink / raw)
To: Uwe Kleine-König; +Cc: Chen Ni, linux-fbdev, dri-devel
In-Reply-To: <cover.1771198101.git.u.kleine-koenig@baylibre.com>
On 2/16/26 00:33, Uwe Kleine-König wrote:
> Uwe Kleine-König (7):
> fbdev: au1100fb: Don't store device specific data in global variables
> fbdev: au1100fb: Mark several local functions as static
> fbdev: au1100fb: Use proper conversion specifiers in printk formats
> fbdev: au1100fb: Make driver compilable on non-mips platforms
> fbdev: au1100fb: Replace custom printk wrappers by pr_*
> fbdev: au1100fb: Fold au1100fb.h into its only user
> fbdev: au1100fb: Replace license boilerplate by SPDX header
>
> drivers/video/au1100fb.c | 0
> drivers/video/fbdev/Kconfig | 3 +-
> drivers/video/fbdev/au1100fb.c | 487 +++++++++++++++++++++++++++------
> drivers/video/fbdev/au1100fb.h | 379 -------------------------
> 4 files changed, 406 insertions(+), 463 deletions(-)
> create mode 100644 drivers/video/au1100fb.c
> delete mode 100644 drivers/video/fbdev/au1100fb.h
series applied to fbdev git tree.
Thank you, Uwe!
^ permalink raw reply
* [PATCH v2] staging: fbtft: Optimize partial write()
From: Nam Cao @ 2026-02-16 0:57 UTC (permalink / raw)
To: Andy Shevchenko, Greg Kroah-Hartman, dri-devel, linux-fbdev,
linux-staging, linux-kernel
Cc: Nam Cao, Andy Shevchenko
When user write() only to part of the screen, the driver still updates the
entire screen. That wastes CPU cycles.
Optimize by updating only the changed lines.
Also remove a "special case" in fbtft_mkdirty() as its only user is removed
in this patch.
Tested with an Adafruit ILI9340 (drivers/staging/fbtft/fb_ili9340.c).
Improvement is measured by a pair of trace_printk() at the beginning of
fb_write() and at the end of fbtft_deferred_io().
Update type Before After
====================================
full screen 196ms 200ms
half screen 200ms 124ms
quarter screen 193ms 81ms
one pixel 199ms 43ms
It is interesting to note that if the deferred IO's delay time (40ms) is
subtracted, then the time amount scales linearly with the write size.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Nam Cao <namcao@linutronix.de>
---
v2: commit message amendment (add extra info & fix typo)
---
drivers/staging/fbtft/fbtft-core.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index 8a5ccc8ae0a1..16899b979623 100644
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -300,12 +300,6 @@ static void fbtft_mkdirty(struct fb_info *info, int y, int height)
struct fbtft_par *par = info->par;
struct fb_deferred_io *fbdefio = info->fbdefio;
- /* special case, needed ? */
- if (y == -1) {
- y = 0;
- height = info->var.yres;
- }
-
/* Mark display lines/area as dirty */
spin_lock(&par->dirty_lock);
if (y < par->dirty_lines_start)
@@ -414,9 +408,12 @@ static int fbtft_fb_blank(int blank, struct fb_info *info)
static void fbtft_ops_damage_range(struct fb_info *info, off_t off, size_t len)
{
struct fbtft_par *par = info->par;
+ u32 start, end;
+
+ start = off / info->fix.line_length;
+ end = (off + len - 1) / info->fix.line_length;
- /* TODO: only mark changed area update all for now */
- par->fbtftops.mkdirty(info, -1, 0);
+ par->fbtftops.mkdirty(info, start, end - start + 1);
}
static void fbtft_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height)
--
2.47.3
^ permalink raw reply related
* [PATCH v2] staging: sm750fb: add missing const to g_fbmode array
From: Eyüp Kerem Baş @ 2026-02-16 0:39 UTC (permalink / raw)
To: Ethan Tidmore
Cc: sudipm.mukherjee, teddy.wang, gregkh, linux-fbdev, linux-staging,
linux-kernel, Eyüp Kerem Baş
Checkpatch reported a warning that the static const char * array should
probably be static const char * const. This patch adds the missing const
keyword to g_fbmode array, moving it to read-only memory.
Signed-off-by: Eyüp Kerem Baş <baseyupkerem@gmail.com>
---
drivers/staging/sm750fb/sm750.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index fecd7457e615..15b5de33b8d9 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -33,7 +33,7 @@
static int g_hwcursor = 1;
static int g_noaccel;
static int g_nomtrr;
-static const char *g_fbmode[] = {NULL, NULL};
+static const char * const g_fbmode[] = {NULL, NULL};
static const char *g_def_fbmode = "1024x768-32@60";
static char *g_settings;
static int g_dualview;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] staging: sm750fb: add missing const to g_fbmode array
From: Ethan Tidmore @ 2026-02-16 0:26 UTC (permalink / raw)
To: Eyüp Kerem Baş, sudipm.mukherjee, teddy.wang, gregkh
Cc: linux-fbdev, linux-staging, linux-kernel
In-Reply-To: <20260215213102.111117-1-baseyupkerem@gmail.com>
On Sun Feb 15, 2026 at 3:31 PM CST, Eyüp Kerem Baş wrote:
> Checkpatch reported a warning that the static const char * array should probably be static const char * const. This patch adds the missing const keyword to g_fbmode array, moving it to read-only memory.
Please keep a maximum of 75 characters per line. Next time when
submitting a patch use "$ ./scripts/checkpatch.pl --strict <patch>" to
catch things like this.
Thanks,
ET
>
> Signed-off-by: Eyüp Kerem Baş <baseyupkerem@gmail.com>
> ---
^ permalink raw reply
* [PATCH v5 7/7] fbdev: au1100fb: Replace license boilerplate by SPDX header
From: Uwe Kleine-König @ 2026-02-15 23:33 UTC (permalink / raw)
To: Helge Deller; +Cc: Chen Ni, linux-fbdev, dri-devel
In-Reply-To: <cover.1771198101.git.u.kleine-koenig@baylibre.com>
This also gets rid of an old address of the FSF.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
---
drivers/video/fbdev/au1100fb.c | 21 +--------------------
1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c
index 13605337d724..1a04154bc535 100644
--- a/drivers/video/fbdev/au1100fb.c
+++ b/drivers/video/fbdev/au1100fb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* BRIEF MODULE DESCRIPTION
* Au1100 LCD Driver.
@@ -20,26 +21,6 @@
* Based on:
* linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
* Created 28 Dec 1997 by Geert Uytterhoeven
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define pr_fmt(fmt) "au1100fb:" fmt "\n"
--
2.47.3
^ permalink raw reply related
* [PATCH v5 6/7] fbdev: au1100fb: Fold au1100fb.h into its only user
From: Uwe Kleine-König @ 2026-02-15 23:33 UTC (permalink / raw)
To: Helge Deller; +Cc: Chen Ni, linux-fbdev, dri-devel
In-Reply-To: <cover.1771198101.git.u.kleine-koenig@baylibre.com>
This gets rid of a header that is only used once. The copyrights and
license specifications are all already covered in the au1100fb.c file.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
---
drivers/video/au1100fb.c | 0
drivers/video/fbdev/au1100fb.c | 339 +++++++++++++++++++++++++++++-
drivers/video/fbdev/au1100fb.h | 372 ---------------------------------
3 files changed, 338 insertions(+), 373 deletions(-)
create mode 100644 drivers/video/au1100fb.c
delete mode 100644 drivers/video/fbdev/au1100fb.h
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c
index f589f90cce2c..13605337d724 100644
--- a/drivers/video/fbdev/au1100fb.c
+++ b/drivers/video/fbdev/au1100fb.c
@@ -60,7 +60,344 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include "au1100fb.h"
+#if defined(__BIG_ENDIAN)
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
+#else
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
+#endif
+#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
+
+/********************************************************************/
+
+/* LCD controller restrictions */
+#define AU1100_LCD_MAX_XRES 800
+#define AU1100_LCD_MAX_YRES 600
+#define AU1100_LCD_MAX_BPP 16
+#define AU1100_LCD_MAX_CLK 48000000
+#define AU1100_LCD_NBR_PALETTE_ENTRIES 256
+
+/* Default number of visible screen buffer to allocate */
+#define AU1100FB_NBR_VIDEO_BUFFERS 4
+
+/********************************************************************/
+
+struct au1100fb_panel
+{
+ const char name[25]; /* Full name <vendor>_<model> */
+
+ u32 control_base; /* Mode-independent control values */
+ u32 clkcontrol_base; /* Panel pixclock preferences */
+
+ u32 horztiming;
+ u32 verttiming;
+
+ u32 xres; /* Maximum horizontal resolution */
+ u32 yres; /* Maximum vertical resolution */
+ u32 bpp; /* Maximum depth supported */
+};
+
+struct au1100fb_regs
+{
+ u32 lcd_control;
+ u32 lcd_intstatus;
+ u32 lcd_intenable;
+ u32 lcd_horztiming;
+ u32 lcd_verttiming;
+ u32 lcd_clkcontrol;
+ u32 lcd_dmaaddr0;
+ u32 lcd_dmaaddr1;
+ u32 lcd_words;
+ u32 lcd_pwmdiv;
+ u32 lcd_pwmhi;
+ u32 reserved[(0x0400-0x002C)/4];
+ u32 lcd_palettebase[256];
+};
+
+struct au1100fb_device {
+
+ struct fb_info info; /* FB driver info record */
+
+ struct au1100fb_panel *panel; /* Panel connected to this device */
+
+ struct au1100fb_regs* regs; /* Registers memory map */
+ size_t regs_len;
+ unsigned int regs_phys;
+
+#ifdef CONFIG_PM
+ /* stores the register values during suspend */
+ struct au1100fb_regs pm_regs;
+#endif
+
+ unsigned char* fb_mem; /* FrameBuffer memory map */
+ size_t fb_len;
+ dma_addr_t fb_phys;
+ int panel_idx;
+ struct clk *lcdclk;
+ struct device *dev;
+};
+
+/********************************************************************/
+
+#define LCD_CONTROL (AU1100_LCD_BASE + 0x0)
+ #define LCD_CONTROL_SBB_BIT 21
+ #define LCD_CONTROL_SBB_MASK (0x3 << LCD_CONTROL_SBB_BIT)
+ #define LCD_CONTROL_SBB_1 (0 << LCD_CONTROL_SBB_BIT)
+ #define LCD_CONTROL_SBB_2 (1 << LCD_CONTROL_SBB_BIT)
+ #define LCD_CONTROL_SBB_3 (2 << LCD_CONTROL_SBB_BIT)
+ #define LCD_CONTROL_SBB_4 (3 << LCD_CONTROL_SBB_BIT)
+ #define LCD_CONTROL_SBPPF_BIT 18
+ #define LCD_CONTROL_SBPPF_MASK (0x7 << LCD_CONTROL_SBPPF_BIT)
+ #define LCD_CONTROL_SBPPF_655 (0 << LCD_CONTROL_SBPPF_BIT)
+ #define LCD_CONTROL_SBPPF_565 (1 << LCD_CONTROL_SBPPF_BIT)
+ #define LCD_CONTROL_SBPPF_556 (2 << LCD_CONTROL_SBPPF_BIT)
+ #define LCD_CONTROL_SBPPF_1555 (3 << LCD_CONTROL_SBPPF_BIT)
+ #define LCD_CONTROL_SBPPF_5551 (4 << LCD_CONTROL_SBPPF_BIT)
+ #define LCD_CONTROL_WP (1<<17)
+ #define LCD_CONTROL_WD (1<<16)
+ #define LCD_CONTROL_C (1<<15)
+ #define LCD_CONTROL_SM_BIT 13
+ #define LCD_CONTROL_SM_MASK (0x3 << LCD_CONTROL_SM_BIT)
+ #define LCD_CONTROL_SM_0 (0 << LCD_CONTROL_SM_BIT)
+ #define LCD_CONTROL_SM_90 (1 << LCD_CONTROL_SM_BIT)
+ #define LCD_CONTROL_SM_180 (2 << LCD_CONTROL_SM_BIT)
+ #define LCD_CONTROL_SM_270 (3 << LCD_CONTROL_SM_BIT)
+ #define LCD_CONTROL_DB (1<<12)
+ #define LCD_CONTROL_CCO (1<<11)
+ #define LCD_CONTROL_DP (1<<10)
+ #define LCD_CONTROL_PO_BIT 8
+ #define LCD_CONTROL_PO_MASK (0x3 << LCD_CONTROL_PO_BIT)
+ #define LCD_CONTROL_PO_00 (0 << LCD_CONTROL_PO_BIT)
+ #define LCD_CONTROL_PO_01 (1 << LCD_CONTROL_PO_BIT)
+ #define LCD_CONTROL_PO_10 (2 << LCD_CONTROL_PO_BIT)
+ #define LCD_CONTROL_PO_11 (3 << LCD_CONTROL_PO_BIT)
+ #define LCD_CONTROL_MPI (1<<7)
+ #define LCD_CONTROL_PT (1<<6)
+ #define LCD_CONTROL_PC (1<<5)
+ #define LCD_CONTROL_BPP_BIT 1
+ #define LCD_CONTROL_BPP_MASK (0x7 << LCD_CONTROL_BPP_BIT)
+ #define LCD_CONTROL_BPP_1 (0 << LCD_CONTROL_BPP_BIT)
+ #define LCD_CONTROL_BPP_2 (1 << LCD_CONTROL_BPP_BIT)
+ #define LCD_CONTROL_BPP_4 (2 << LCD_CONTROL_BPP_BIT)
+ #define LCD_CONTROL_BPP_8 (3 << LCD_CONTROL_BPP_BIT)
+ #define LCD_CONTROL_BPP_12 (4 << LCD_CONTROL_BPP_BIT)
+ #define LCD_CONTROL_BPP_16 (5 << LCD_CONTROL_BPP_BIT)
+ #define LCD_CONTROL_GO (1<<0)
+
+#define LCD_INTSTATUS (AU1100_LCD_BASE + 0x4)
+#define LCD_INTENABLE (AU1100_LCD_BASE + 0x8)
+ #define LCD_INT_SD (1<<7)
+ #define LCD_INT_OF (1<<6)
+ #define LCD_INT_UF (1<<5)
+ #define LCD_INT_SA (1<<3)
+ #define LCD_INT_SS (1<<2)
+ #define LCD_INT_S1 (1<<1)
+ #define LCD_INT_S0 (1<<0)
+
+#define LCD_HORZTIMING (AU1100_LCD_BASE + 0xC)
+ #define LCD_HORZTIMING_HN2_BIT 24
+ #define LCD_HORZTIMING_HN2_MASK (0xFF << LCD_HORZTIMING_HN2_BIT)
+ #define LCD_HORZTIMING_HN2_N(N) ((((N)-1) << LCD_HORZTIMING_HN2_BIT) & LCD_HORZTIMING_HN2_MASK)
+ #define LCD_HORZTIMING_HN1_BIT 16
+ #define LCD_HORZTIMING_HN1_MASK (0xFF << LCD_HORZTIMING_HN1_BIT)
+ #define LCD_HORZTIMING_HN1_N(N) ((((N)-1) << LCD_HORZTIMING_HN1_BIT) & LCD_HORZTIMING_HN1_MASK)
+ #define LCD_HORZTIMING_HPW_BIT 10
+ #define LCD_HORZTIMING_HPW_MASK (0x3F << LCD_HORZTIMING_HPW_BIT)
+ #define LCD_HORZTIMING_HPW_N(N) ((((N)-1) << LCD_HORZTIMING_HPW_BIT) & LCD_HORZTIMING_HPW_MASK)
+ #define LCD_HORZTIMING_PPL_BIT 0
+ #define LCD_HORZTIMING_PPL_MASK (0x3FF << LCD_HORZTIMING_PPL_BIT)
+ #define LCD_HORZTIMING_PPL_N(N) ((((N)-1) << LCD_HORZTIMING_PPL_BIT) & LCD_HORZTIMING_PPL_MASK)
+
+#define LCD_VERTTIMING (AU1100_LCD_BASE + 0x10)
+ #define LCD_VERTTIMING_VN2_BIT 24
+ #define LCD_VERTTIMING_VN2_MASK (0xFF << LCD_VERTTIMING_VN2_BIT)
+ #define LCD_VERTTIMING_VN2_N(N) ((((N)-1) << LCD_VERTTIMING_VN2_BIT) & LCD_VERTTIMING_VN2_MASK)
+ #define LCD_VERTTIMING_VN1_BIT 16
+ #define LCD_VERTTIMING_VN1_MASK (0xFF << LCD_VERTTIMING_VN1_BIT)
+ #define LCD_VERTTIMING_VN1_N(N) ((((N)-1) << LCD_VERTTIMING_VN1_BIT) & LCD_VERTTIMING_VN1_MASK)
+ #define LCD_VERTTIMING_VPW_BIT 10
+ #define LCD_VERTTIMING_VPW_MASK (0x3F << LCD_VERTTIMING_VPW_BIT)
+ #define LCD_VERTTIMING_VPW_N(N) ((((N)-1) << LCD_VERTTIMING_VPW_BIT) & LCD_VERTTIMING_VPW_MASK)
+ #define LCD_VERTTIMING_LPP_BIT 0
+ #define LCD_VERTTIMING_LPP_MASK (0x3FF << LCD_VERTTIMING_LPP_BIT)
+ #define LCD_VERTTIMING_LPP_N(N) ((((N)-1) << LCD_VERTTIMING_LPP_BIT) & LCD_VERTTIMING_LPP_MASK)
+
+#define LCD_CLKCONTROL (AU1100_LCD_BASE + 0x14)
+ #define LCD_CLKCONTROL_IB (1<<18)
+ #define LCD_CLKCONTROL_IC (1<<17)
+ #define LCD_CLKCONTROL_IH (1<<16)
+ #define LCD_CLKCONTROL_IV (1<<15)
+ #define LCD_CLKCONTROL_BF_BIT 10
+ #define LCD_CLKCONTROL_BF_MASK (0x1F << LCD_CLKCONTROL_BF_BIT)
+ #define LCD_CLKCONTROL_BF_N(N) ((((N)-1) << LCD_CLKCONTROL_BF_BIT) & LCD_CLKCONTROL_BF_MASK)
+ #define LCD_CLKCONTROL_PCD_BIT 0
+ #define LCD_CLKCONTROL_PCD_MASK (0x3FF << LCD_CLKCONTROL_PCD_BIT)
+ #define LCD_CLKCONTROL_PCD_N(N) (((N) << LCD_CLKCONTROL_PCD_BIT) & LCD_CLKCONTROL_PCD_MASK)
+
+#define LCD_DMAADDR0 (AU1100_LCD_BASE + 0x18)
+#define LCD_DMAADDR1 (AU1100_LCD_BASE + 0x1C)
+ #define LCD_DMA_SA_BIT 5
+ #define LCD_DMA_SA_MASK (0x7FFFFFF << LCD_DMA_SA_BIT)
+ #define LCD_DMA_SA_N(N) ((N) & LCD_DMA_SA_MASK)
+
+#define LCD_WORDS (AU1100_LCD_BASE + 0x20)
+ #define LCD_WRD_WRDS_BIT 0
+ #define LCD_WRD_WRDS_MASK (0xFFFFFFFF << LCD_WRD_WRDS_BIT)
+ #define LCD_WRD_WRDS_N(N) ((((N)-1) << LCD_WRD_WRDS_BIT) & LCD_WRD_WRDS_MASK)
+
+#define LCD_PWMDIV (AU1100_LCD_BASE + 0x24)
+ #define LCD_PWMDIV_EN (1<<12)
+ #define LCD_PWMDIV_PWMDIV_BIT 0
+ #define LCD_PWMDIV_PWMDIV_MASK (0xFFF << LCD_PWMDIV_PWMDIV_BIT)
+ #define LCD_PWMDIV_PWMDIV_N(N) ((((N)-1) << LCD_PWMDIV_PWMDIV_BIT) & LCD_PWMDIV_PWMDIV_MASK)
+
+#define LCD_PWMHI (AU1100_LCD_BASE + 0x28)
+ #define LCD_PWMHI_PWMHI1_BIT 12
+ #define LCD_PWMHI_PWMHI1_MASK (0xFFF << LCD_PWMHI_PWMHI1_BIT)
+ #define LCD_PWMHI_PWMHI1_N(N) (((N) << LCD_PWMHI_PWMHI1_BIT) & LCD_PWMHI_PWMHI1_MASK)
+ #define LCD_PWMHI_PWMHI0_BIT 0
+ #define LCD_PWMHI_PWMHI0_MASK (0xFFF << LCD_PWMHI_PWMHI0_BIT)
+ #define LCD_PWMHI_PWMHI0_N(N) (((N) << LCD_PWMHI_PWMHI0_BIT) & LCD_PWMHI_PWMHI0_MASK)
+
+#define LCD_PALLETTEBASE (AU1100_LCD_BASE + 0x400)
+ #define LCD_PALLETTE_MONO_MI_BIT 0
+ #define LCD_PALLETTE_MONO_MI_MASK (0xF << LCD_PALLETTE_MONO_MI_BIT)
+ #define LCD_PALLETTE_MONO_MI_N(N) (((N)<< LCD_PALLETTE_MONO_MI_BIT) & LCD_PALLETTE_MONO_MI_MASK)
+
+ #define LCD_PALLETTE_COLOR_RI_BIT 8
+ #define LCD_PALLETTE_COLOR_RI_MASK (0xF << LCD_PALLETTE_COLOR_RI_BIT)
+ #define LCD_PALLETTE_COLOR_RI_N(N) (((N)<< LCD_PALLETTE_COLOR_RI_BIT) & LCD_PALLETTE_COLOR_RI_MASK)
+ #define LCD_PALLETTE_COLOR_GI_BIT 4
+ #define LCD_PALLETTE_COLOR_GI_MASK (0xF << LCD_PALLETTE_COLOR_GI_BIT)
+ #define LCD_PALLETTE_COLOR_GI_N(N) (((N)<< LCD_PALLETTE_COLOR_GI_BIT) & LCD_PALLETTE_COLOR_GI_MASK)
+ #define LCD_PALLETTE_COLOR_BI_BIT 0
+ #define LCD_PALLETTE_COLOR_BI_MASK (0xF << LCD_PALLETTE_COLOR_BI_BIT)
+ #define LCD_PALLETTE_COLOR_BI_N(N) (((N)<< LCD_PALLETTE_COLOR_BI_BIT) & LCD_PALLETTE_COLOR_BI_MASK)
+
+ #define LCD_PALLETTE_TFT_DC_BIT 0
+ #define LCD_PALLETTE_TFT_DC_MASK (0xFFFF << LCD_PALLETTE_TFT_DC_BIT)
+ #define LCD_PALLETTE_TFT_DC_N(N) (((N)<< LCD_PALLETTE_TFT_DC_BIT) & LCD_PALLETTE_TFT_DC_MASK)
+
+/********************************************************************/
+
+/* List of panels known to work with the AU1100 LCD controller.
+ * To add a new panel, enter the same specifications as the
+ * Generic_TFT one, and MAKE SURE that it doesn't conflicts
+ * with the controller restrictions. Restrictions are:
+ *
+ * STN color panels: max_bpp <= 12
+ * STN mono panels: max_bpp <= 4
+ * TFT panels: max_bpp <= 16
+ * max_xres <= 800
+ * max_yres <= 600
+ */
+static struct au1100fb_panel known_lcd_panels[] =
+{
+ /* 800x600x16bpp CRT */
+ [0] = {
+ .name = "CRT_800x600_16",
+ .xres = 800,
+ .yres = 600,
+ .bpp = 16,
+ .control_base = 0x0004886A |
+ LCD_CONTROL_DEFAULT_PO | LCD_CONTROL_DEFAULT_SBPPF |
+ LCD_CONTROL_BPP_16 | LCD_CONTROL_SBB_4,
+ .clkcontrol_base = 0x00020000,
+ .horztiming = 0x005aff1f,
+ .verttiming = 0x16000e57,
+ },
+ /* just the standard LCD */
+ [1] = {
+ .name = "WWPC LCD",
+ .xres = 240,
+ .yres = 320,
+ .bpp = 16,
+ .control_base = 0x0006806A,
+ .horztiming = 0x0A1010EF,
+ .verttiming = 0x0301013F,
+ .clkcontrol_base = 0x00018001,
+ },
+ /* Sharp 320x240 TFT panel */
+ [2] = {
+ .name = "Sharp_LQ038Q5DR01",
+ .xres = 320,
+ .yres = 240,
+ .bpp = 16,
+ .control_base =
+ ( LCD_CONTROL_SBPPF_565
+ | LCD_CONTROL_C
+ | LCD_CONTROL_SM_0
+ | LCD_CONTROL_DEFAULT_PO
+ | LCD_CONTROL_PT
+ | LCD_CONTROL_PC
+ | LCD_CONTROL_BPP_16 ),
+ .horztiming =
+ ( LCD_HORZTIMING_HN2_N(8)
+ | LCD_HORZTIMING_HN1_N(60)
+ | LCD_HORZTIMING_HPW_N(12)
+ | LCD_HORZTIMING_PPL_N(320) ),
+ .verttiming =
+ ( LCD_VERTTIMING_VN2_N(5)
+ | LCD_VERTTIMING_VN1_N(17)
+ | LCD_VERTTIMING_VPW_N(1)
+ | LCD_VERTTIMING_LPP_N(240) ),
+ .clkcontrol_base = LCD_CLKCONTROL_PCD_N(1),
+ },
+
+ /* Hitachi SP14Q005 and possibly others */
+ [3] = {
+ .name = "Hitachi_SP14Qxxx",
+ .xres = 320,
+ .yres = 240,
+ .bpp = 4,
+ .control_base =
+ ( LCD_CONTROL_C
+ | LCD_CONTROL_BPP_4 ),
+ .horztiming =
+ ( LCD_HORZTIMING_HN2_N(1)
+ | LCD_HORZTIMING_HN1_N(1)
+ | LCD_HORZTIMING_HPW_N(1)
+ | LCD_HORZTIMING_PPL_N(320) ),
+ .verttiming =
+ ( LCD_VERTTIMING_VN2_N(1)
+ | LCD_VERTTIMING_VN1_N(1)
+ | LCD_VERTTIMING_VPW_N(1)
+ | LCD_VERTTIMING_LPP_N(240) ),
+ .clkcontrol_base = LCD_CLKCONTROL_PCD_N(4),
+ },
+
+ /* Generic 640x480 TFT panel */
+ [4] = {
+ .name = "TFT_640x480_16",
+ .xres = 640,
+ .yres = 480,
+ .bpp = 16,
+ .control_base = 0x004806a | LCD_CONTROL_DEFAULT_PO,
+ .horztiming = 0x3434d67f,
+ .verttiming = 0x0e0e39df,
+ .clkcontrol_base = LCD_CLKCONTROL_PCD_N(1),
+ },
+
+ /* Pb1100 LCDB 640x480 PrimeView TFT panel */
+ [5] = {
+ .name = "PrimeView_640x480_16",
+ .xres = 640,
+ .yres = 480,
+ .bpp = 16,
+ .control_base = 0x0004886a | LCD_CONTROL_DEFAULT_PO,
+ .horztiming = 0x0e4bfe7f,
+ .verttiming = 0x210805df,
+ .clkcontrol_base = 0x00038001,
+ },
+};
+
+/********************************************************************/
+
+/* Inline helpers */
+
+#define panel_is_dual(panel) (panel->control_base & LCD_CONTROL_DP)
+#define panel_is_active(panel)(panel->control_base & LCD_CONTROL_PT)
+#define panel_is_color(panel) (panel->control_base & LCD_CONTROL_PC)
+#define panel_swap_rgb(panel) (panel->control_base & LCD_CONTROL_CCO)
#if defined(CONFIG_COMPILE_TEST) && !defined(CONFIG_MIPS)
/* This is only defined to be able to compile this driver on non-mips platforms */
diff --git a/drivers/video/fbdev/au1100fb.h b/drivers/video/fbdev/au1100fb.h
deleted file mode 100644
index 80743b3e2376..000000000000
--- a/drivers/video/fbdev/au1100fb.h
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Hardware definitions for the Au1100 LCD controller
- *
- * Copyright 2002 MontaVista Software
- * Copyright 2002 Alchemy Semiconductor
- * Author: Alchemy Semiconductor, MontaVista Software
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _AU1100LCD_H
-#define _AU1100LCD_H
-
-#if defined(__BIG_ENDIAN)
-#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
-#else
-#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
-#endif
-#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
-
-/********************************************************************/
-
-/* LCD controller restrictions */
-#define AU1100_LCD_MAX_XRES 800
-#define AU1100_LCD_MAX_YRES 600
-#define AU1100_LCD_MAX_BPP 16
-#define AU1100_LCD_MAX_CLK 48000000
-#define AU1100_LCD_NBR_PALETTE_ENTRIES 256
-
-/* Default number of visible screen buffer to allocate */
-#define AU1100FB_NBR_VIDEO_BUFFERS 4
-
-/********************************************************************/
-
-struct au1100fb_panel
-{
- const char name[25]; /* Full name <vendor>_<model> */
-
- u32 control_base; /* Mode-independent control values */
- u32 clkcontrol_base; /* Panel pixclock preferences */
-
- u32 horztiming;
- u32 verttiming;
-
- u32 xres; /* Maximum horizontal resolution */
- u32 yres; /* Maximum vertical resolution */
- u32 bpp; /* Maximum depth supported */
-};
-
-struct au1100fb_regs
-{
- u32 lcd_control;
- u32 lcd_intstatus;
- u32 lcd_intenable;
- u32 lcd_horztiming;
- u32 lcd_verttiming;
- u32 lcd_clkcontrol;
- u32 lcd_dmaaddr0;
- u32 lcd_dmaaddr1;
- u32 lcd_words;
- u32 lcd_pwmdiv;
- u32 lcd_pwmhi;
- u32 reserved[(0x0400-0x002C)/4];
- u32 lcd_palettebase[256];
-};
-
-struct au1100fb_device {
-
- struct fb_info info; /* FB driver info record */
-
- struct au1100fb_panel *panel; /* Panel connected to this device */
-
- struct au1100fb_regs* regs; /* Registers memory map */
- size_t regs_len;
- unsigned int regs_phys;
-
-#ifdef CONFIG_PM
- /* stores the register values during suspend */
- struct au1100fb_regs pm_regs;
-#endif
-
- unsigned char* fb_mem; /* FrameBuffer memory map */
- size_t fb_len;
- dma_addr_t fb_phys;
- int panel_idx;
- struct clk *lcdclk;
- struct device *dev;
-};
-
-/********************************************************************/
-
-#define LCD_CONTROL (AU1100_LCD_BASE + 0x0)
- #define LCD_CONTROL_SBB_BIT 21
- #define LCD_CONTROL_SBB_MASK (0x3 << LCD_CONTROL_SBB_BIT)
- #define LCD_CONTROL_SBB_1 (0 << LCD_CONTROL_SBB_BIT)
- #define LCD_CONTROL_SBB_2 (1 << LCD_CONTROL_SBB_BIT)
- #define LCD_CONTROL_SBB_3 (2 << LCD_CONTROL_SBB_BIT)
- #define LCD_CONTROL_SBB_4 (3 << LCD_CONTROL_SBB_BIT)
- #define LCD_CONTROL_SBPPF_BIT 18
- #define LCD_CONTROL_SBPPF_MASK (0x7 << LCD_CONTROL_SBPPF_BIT)
- #define LCD_CONTROL_SBPPF_655 (0 << LCD_CONTROL_SBPPF_BIT)
- #define LCD_CONTROL_SBPPF_565 (1 << LCD_CONTROL_SBPPF_BIT)
- #define LCD_CONTROL_SBPPF_556 (2 << LCD_CONTROL_SBPPF_BIT)
- #define LCD_CONTROL_SBPPF_1555 (3 << LCD_CONTROL_SBPPF_BIT)
- #define LCD_CONTROL_SBPPF_5551 (4 << LCD_CONTROL_SBPPF_BIT)
- #define LCD_CONTROL_WP (1<<17)
- #define LCD_CONTROL_WD (1<<16)
- #define LCD_CONTROL_C (1<<15)
- #define LCD_CONTROL_SM_BIT 13
- #define LCD_CONTROL_SM_MASK (0x3 << LCD_CONTROL_SM_BIT)
- #define LCD_CONTROL_SM_0 (0 << LCD_CONTROL_SM_BIT)
- #define LCD_CONTROL_SM_90 (1 << LCD_CONTROL_SM_BIT)
- #define LCD_CONTROL_SM_180 (2 << LCD_CONTROL_SM_BIT)
- #define LCD_CONTROL_SM_270 (3 << LCD_CONTROL_SM_BIT)
- #define LCD_CONTROL_DB (1<<12)
- #define LCD_CONTROL_CCO (1<<11)
- #define LCD_CONTROL_DP (1<<10)
- #define LCD_CONTROL_PO_BIT 8
- #define LCD_CONTROL_PO_MASK (0x3 << LCD_CONTROL_PO_BIT)
- #define LCD_CONTROL_PO_00 (0 << LCD_CONTROL_PO_BIT)
- #define LCD_CONTROL_PO_01 (1 << LCD_CONTROL_PO_BIT)
- #define LCD_CONTROL_PO_10 (2 << LCD_CONTROL_PO_BIT)
- #define LCD_CONTROL_PO_11 (3 << LCD_CONTROL_PO_BIT)
- #define LCD_CONTROL_MPI (1<<7)
- #define LCD_CONTROL_PT (1<<6)
- #define LCD_CONTROL_PC (1<<5)
- #define LCD_CONTROL_BPP_BIT 1
- #define LCD_CONTROL_BPP_MASK (0x7 << LCD_CONTROL_BPP_BIT)
- #define LCD_CONTROL_BPP_1 (0 << LCD_CONTROL_BPP_BIT)
- #define LCD_CONTROL_BPP_2 (1 << LCD_CONTROL_BPP_BIT)
- #define LCD_CONTROL_BPP_4 (2 << LCD_CONTROL_BPP_BIT)
- #define LCD_CONTROL_BPP_8 (3 << LCD_CONTROL_BPP_BIT)
- #define LCD_CONTROL_BPP_12 (4 << LCD_CONTROL_BPP_BIT)
- #define LCD_CONTROL_BPP_16 (5 << LCD_CONTROL_BPP_BIT)
- #define LCD_CONTROL_GO (1<<0)
-
-#define LCD_INTSTATUS (AU1100_LCD_BASE + 0x4)
-#define LCD_INTENABLE (AU1100_LCD_BASE + 0x8)
- #define LCD_INT_SD (1<<7)
- #define LCD_INT_OF (1<<6)
- #define LCD_INT_UF (1<<5)
- #define LCD_INT_SA (1<<3)
- #define LCD_INT_SS (1<<2)
- #define LCD_INT_S1 (1<<1)
- #define LCD_INT_S0 (1<<0)
-
-#define LCD_HORZTIMING (AU1100_LCD_BASE + 0xC)
- #define LCD_HORZTIMING_HN2_BIT 24
- #define LCD_HORZTIMING_HN2_MASK (0xFF << LCD_HORZTIMING_HN2_BIT)
- #define LCD_HORZTIMING_HN2_N(N) ((((N)-1) << LCD_HORZTIMING_HN2_BIT) & LCD_HORZTIMING_HN2_MASK)
- #define LCD_HORZTIMING_HN1_BIT 16
- #define LCD_HORZTIMING_HN1_MASK (0xFF << LCD_HORZTIMING_HN1_BIT)
- #define LCD_HORZTIMING_HN1_N(N) ((((N)-1) << LCD_HORZTIMING_HN1_BIT) & LCD_HORZTIMING_HN1_MASK)
- #define LCD_HORZTIMING_HPW_BIT 10
- #define LCD_HORZTIMING_HPW_MASK (0x3F << LCD_HORZTIMING_HPW_BIT)
- #define LCD_HORZTIMING_HPW_N(N) ((((N)-1) << LCD_HORZTIMING_HPW_BIT) & LCD_HORZTIMING_HPW_MASK)
- #define LCD_HORZTIMING_PPL_BIT 0
- #define LCD_HORZTIMING_PPL_MASK (0x3FF << LCD_HORZTIMING_PPL_BIT)
- #define LCD_HORZTIMING_PPL_N(N) ((((N)-1) << LCD_HORZTIMING_PPL_BIT) & LCD_HORZTIMING_PPL_MASK)
-
-#define LCD_VERTTIMING (AU1100_LCD_BASE + 0x10)
- #define LCD_VERTTIMING_VN2_BIT 24
- #define LCD_VERTTIMING_VN2_MASK (0xFF << LCD_VERTTIMING_VN2_BIT)
- #define LCD_VERTTIMING_VN2_N(N) ((((N)-1) << LCD_VERTTIMING_VN2_BIT) & LCD_VERTTIMING_VN2_MASK)
- #define LCD_VERTTIMING_VN1_BIT 16
- #define LCD_VERTTIMING_VN1_MASK (0xFF << LCD_VERTTIMING_VN1_BIT)
- #define LCD_VERTTIMING_VN1_N(N) ((((N)-1) << LCD_VERTTIMING_VN1_BIT) & LCD_VERTTIMING_VN1_MASK)
- #define LCD_VERTTIMING_VPW_BIT 10
- #define LCD_VERTTIMING_VPW_MASK (0x3F << LCD_VERTTIMING_VPW_BIT)
- #define LCD_VERTTIMING_VPW_N(N) ((((N)-1) << LCD_VERTTIMING_VPW_BIT) & LCD_VERTTIMING_VPW_MASK)
- #define LCD_VERTTIMING_LPP_BIT 0
- #define LCD_VERTTIMING_LPP_MASK (0x3FF << LCD_VERTTIMING_LPP_BIT)
- #define LCD_VERTTIMING_LPP_N(N) ((((N)-1) << LCD_VERTTIMING_LPP_BIT) & LCD_VERTTIMING_LPP_MASK)
-
-#define LCD_CLKCONTROL (AU1100_LCD_BASE + 0x14)
- #define LCD_CLKCONTROL_IB (1<<18)
- #define LCD_CLKCONTROL_IC (1<<17)
- #define LCD_CLKCONTROL_IH (1<<16)
- #define LCD_CLKCONTROL_IV (1<<15)
- #define LCD_CLKCONTROL_BF_BIT 10
- #define LCD_CLKCONTROL_BF_MASK (0x1F << LCD_CLKCONTROL_BF_BIT)
- #define LCD_CLKCONTROL_BF_N(N) ((((N)-1) << LCD_CLKCONTROL_BF_BIT) & LCD_CLKCONTROL_BF_MASK)
- #define LCD_CLKCONTROL_PCD_BIT 0
- #define LCD_CLKCONTROL_PCD_MASK (0x3FF << LCD_CLKCONTROL_PCD_BIT)
- #define LCD_CLKCONTROL_PCD_N(N) (((N) << LCD_CLKCONTROL_PCD_BIT) & LCD_CLKCONTROL_PCD_MASK)
-
-#define LCD_DMAADDR0 (AU1100_LCD_BASE + 0x18)
-#define LCD_DMAADDR1 (AU1100_LCD_BASE + 0x1C)
- #define LCD_DMA_SA_BIT 5
- #define LCD_DMA_SA_MASK (0x7FFFFFF << LCD_DMA_SA_BIT)
- #define LCD_DMA_SA_N(N) ((N) & LCD_DMA_SA_MASK)
-
-#define LCD_WORDS (AU1100_LCD_BASE + 0x20)
- #define LCD_WRD_WRDS_BIT 0
- #define LCD_WRD_WRDS_MASK (0xFFFFFFFF << LCD_WRD_WRDS_BIT)
- #define LCD_WRD_WRDS_N(N) ((((N)-1) << LCD_WRD_WRDS_BIT) & LCD_WRD_WRDS_MASK)
-
-#define LCD_PWMDIV (AU1100_LCD_BASE + 0x24)
- #define LCD_PWMDIV_EN (1<<12)
- #define LCD_PWMDIV_PWMDIV_BIT 0
- #define LCD_PWMDIV_PWMDIV_MASK (0xFFF << LCD_PWMDIV_PWMDIV_BIT)
- #define LCD_PWMDIV_PWMDIV_N(N) ((((N)-1) << LCD_PWMDIV_PWMDIV_BIT) & LCD_PWMDIV_PWMDIV_MASK)
-
-#define LCD_PWMHI (AU1100_LCD_BASE + 0x28)
- #define LCD_PWMHI_PWMHI1_BIT 12
- #define LCD_PWMHI_PWMHI1_MASK (0xFFF << LCD_PWMHI_PWMHI1_BIT)
- #define LCD_PWMHI_PWMHI1_N(N) (((N) << LCD_PWMHI_PWMHI1_BIT) & LCD_PWMHI_PWMHI1_MASK)
- #define LCD_PWMHI_PWMHI0_BIT 0
- #define LCD_PWMHI_PWMHI0_MASK (0xFFF << LCD_PWMHI_PWMHI0_BIT)
- #define LCD_PWMHI_PWMHI0_N(N) (((N) << LCD_PWMHI_PWMHI0_BIT) & LCD_PWMHI_PWMHI0_MASK)
-
-#define LCD_PALLETTEBASE (AU1100_LCD_BASE + 0x400)
- #define LCD_PALLETTE_MONO_MI_BIT 0
- #define LCD_PALLETTE_MONO_MI_MASK (0xF << LCD_PALLETTE_MONO_MI_BIT)
- #define LCD_PALLETTE_MONO_MI_N(N) (((N)<< LCD_PALLETTE_MONO_MI_BIT) & LCD_PALLETTE_MONO_MI_MASK)
-
- #define LCD_PALLETTE_COLOR_RI_BIT 8
- #define LCD_PALLETTE_COLOR_RI_MASK (0xF << LCD_PALLETTE_COLOR_RI_BIT)
- #define LCD_PALLETTE_COLOR_RI_N(N) (((N)<< LCD_PALLETTE_COLOR_RI_BIT) & LCD_PALLETTE_COLOR_RI_MASK)
- #define LCD_PALLETTE_COLOR_GI_BIT 4
- #define LCD_PALLETTE_COLOR_GI_MASK (0xF << LCD_PALLETTE_COLOR_GI_BIT)
- #define LCD_PALLETTE_COLOR_GI_N(N) (((N)<< LCD_PALLETTE_COLOR_GI_BIT) & LCD_PALLETTE_COLOR_GI_MASK)
- #define LCD_PALLETTE_COLOR_BI_BIT 0
- #define LCD_PALLETTE_COLOR_BI_MASK (0xF << LCD_PALLETTE_COLOR_BI_BIT)
- #define LCD_PALLETTE_COLOR_BI_N(N) (((N)<< LCD_PALLETTE_COLOR_BI_BIT) & LCD_PALLETTE_COLOR_BI_MASK)
-
- #define LCD_PALLETTE_TFT_DC_BIT 0
- #define LCD_PALLETTE_TFT_DC_MASK (0xFFFF << LCD_PALLETTE_TFT_DC_BIT)
- #define LCD_PALLETTE_TFT_DC_N(N) (((N)<< LCD_PALLETTE_TFT_DC_BIT) & LCD_PALLETTE_TFT_DC_MASK)
-
-/********************************************************************/
-
-/* List of panels known to work with the AU1100 LCD controller.
- * To add a new panel, enter the same specifications as the
- * Generic_TFT one, and MAKE SURE that it doesn't conflicts
- * with the controller restrictions. Restrictions are:
- *
- * STN color panels: max_bpp <= 12
- * STN mono panels: max_bpp <= 4
- * TFT panels: max_bpp <= 16
- * max_xres <= 800
- * max_yres <= 600
- */
-static struct au1100fb_panel known_lcd_panels[] =
-{
- /* 800x600x16bpp CRT */
- [0] = {
- .name = "CRT_800x600_16",
- .xres = 800,
- .yres = 600,
- .bpp = 16,
- .control_base = 0x0004886A |
- LCD_CONTROL_DEFAULT_PO | LCD_CONTROL_DEFAULT_SBPPF |
- LCD_CONTROL_BPP_16 | LCD_CONTROL_SBB_4,
- .clkcontrol_base = 0x00020000,
- .horztiming = 0x005aff1f,
- .verttiming = 0x16000e57,
- },
- /* just the standard LCD */
- [1] = {
- .name = "WWPC LCD",
- .xres = 240,
- .yres = 320,
- .bpp = 16,
- .control_base = 0x0006806A,
- .horztiming = 0x0A1010EF,
- .verttiming = 0x0301013F,
- .clkcontrol_base = 0x00018001,
- },
- /* Sharp 320x240 TFT panel */
- [2] = {
- .name = "Sharp_LQ038Q5DR01",
- .xres = 320,
- .yres = 240,
- .bpp = 16,
- .control_base =
- ( LCD_CONTROL_SBPPF_565
- | LCD_CONTROL_C
- | LCD_CONTROL_SM_0
- | LCD_CONTROL_DEFAULT_PO
- | LCD_CONTROL_PT
- | LCD_CONTROL_PC
- | LCD_CONTROL_BPP_16 ),
- .horztiming =
- ( LCD_HORZTIMING_HN2_N(8)
- | LCD_HORZTIMING_HN1_N(60)
- | LCD_HORZTIMING_HPW_N(12)
- | LCD_HORZTIMING_PPL_N(320) ),
- .verttiming =
- ( LCD_VERTTIMING_VN2_N(5)
- | LCD_VERTTIMING_VN1_N(17)
- | LCD_VERTTIMING_VPW_N(1)
- | LCD_VERTTIMING_LPP_N(240) ),
- .clkcontrol_base = LCD_CLKCONTROL_PCD_N(1),
- },
-
- /* Hitachi SP14Q005 and possibly others */
- [3] = {
- .name = "Hitachi_SP14Qxxx",
- .xres = 320,
- .yres = 240,
- .bpp = 4,
- .control_base =
- ( LCD_CONTROL_C
- | LCD_CONTROL_BPP_4 ),
- .horztiming =
- ( LCD_HORZTIMING_HN2_N(1)
- | LCD_HORZTIMING_HN1_N(1)
- | LCD_HORZTIMING_HPW_N(1)
- | LCD_HORZTIMING_PPL_N(320) ),
- .verttiming =
- ( LCD_VERTTIMING_VN2_N(1)
- | LCD_VERTTIMING_VN1_N(1)
- | LCD_VERTTIMING_VPW_N(1)
- | LCD_VERTTIMING_LPP_N(240) ),
- .clkcontrol_base = LCD_CLKCONTROL_PCD_N(4),
- },
-
- /* Generic 640x480 TFT panel */
- [4] = {
- .name = "TFT_640x480_16",
- .xres = 640,
- .yres = 480,
- .bpp = 16,
- .control_base = 0x004806a | LCD_CONTROL_DEFAULT_PO,
- .horztiming = 0x3434d67f,
- .verttiming = 0x0e0e39df,
- .clkcontrol_base = LCD_CLKCONTROL_PCD_N(1),
- },
-
- /* Pb1100 LCDB 640x480 PrimeView TFT panel */
- [5] = {
- .name = "PrimeView_640x480_16",
- .xres = 640,
- .yres = 480,
- .bpp = 16,
- .control_base = 0x0004886a | LCD_CONTROL_DEFAULT_PO,
- .horztiming = 0x0e4bfe7f,
- .verttiming = 0x210805df,
- .clkcontrol_base = 0x00038001,
- },
-};
-
-/********************************************************************/
-
-/* Inline helpers */
-
-#define panel_is_dual(panel) (panel->control_base & LCD_CONTROL_DP)
-#define panel_is_active(panel)(panel->control_base & LCD_CONTROL_PT)
-#define panel_is_color(panel) (panel->control_base & LCD_CONTROL_PC)
-#define panel_swap_rgb(panel) (panel->control_base & LCD_CONTROL_CCO)
-
-#endif /* _AU1100LCD_H */
--
2.47.3
^ permalink raw reply related
* [PATCH v5 5/7] fbdev: au1100fb: Replace custom printk wrappers by pr_*
From: Uwe Kleine-König @ 2026-02-15 23:33 UTC (permalink / raw)
To: Helge Deller; +Cc: Chen Ni, linux-fbdev, dri-devel
In-Reply-To: <cover.1771198101.git.u.kleine-koenig@baylibre.com>
The global wrappers also have the advantage to do stricter format
checking, so the pr_devel formats are also checked if DEBUG is not
defined. The global variants only check for DEBUG being defined and not
its actual value, so the #define to zero is dropped, too.
There is only a slight semantic change as the (by default disabled)
debug output doesn't contain __FILE__ any more.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
---
drivers/video/fbdev/au1100fb.c | 41 +++++++++++++++++-----------------
drivers/video/fbdev/au1100fb.h | 10 ---------
2 files changed, 21 insertions(+), 30 deletions(-)
diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c
index 7611dad0d68d..f589f90cce2c 100644
--- a/drivers/video/fbdev/au1100fb.c
+++ b/drivers/video/fbdev/au1100fb.c
@@ -41,6 +41,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
+#define pr_fmt(fmt) "au1100fb:" fmt "\n"
+
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -57,8 +60,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#define DEBUG 0
-
#include "au1100fb.h"
#if defined(CONFIG_COMPILE_TEST) && !defined(CONFIG_MIPS)
@@ -97,7 +98,7 @@ static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
{
struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
- print_dbg("fb_blank %d %p", blank_mode, fbi);
+ pr_devel("fb_blank %d %p", blank_mode, fbi);
switch (blank_mode) {
@@ -291,7 +292,7 @@ static int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info
fbdev = to_au1100fb_device(fbi);
- print_dbg("fb_pan_display %p %p", var, fbi);
+ pr_devel("fb_pan_display %p %p", var, fbi);
if (!var || !fbdev) {
return -EINVAL;
@@ -302,13 +303,13 @@ static int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info
return -EINVAL;
}
- print_dbg("fb_pan_display 2 %p %p", var, fbi);
+ pr_devel("fb_pan_display 2 %p %p", var, fbi);
dy = var->yoffset - fbi->var.yoffset;
if (dy) {
u32 dmaaddr;
- print_dbg("Panning screen of %d lines", dy);
+ pr_devel("Panning screen of %d lines", dy);
dmaaddr = fbdev->regs->lcd_dmaaddr0;
dmaaddr += (fbi->fix.line_length * dy);
@@ -322,7 +323,7 @@ static int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info
fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(dmaaddr);
}
}
- print_dbg("fb_pan_display 3 %p %p", var, fbi);
+ pr_devel("fb_pan_display 3 %p %p", var, fbi);
return 0;
}
@@ -365,7 +366,7 @@ static int au1100fb_setup(struct au1100fb_device *fbdev)
int num_panels = ARRAY_SIZE(known_lcd_panels);
if (num_panels <= 0) {
- print_err("No LCD panels supported by driver!");
+ pr_err("No LCD panels supported by driver!");
return -ENODEV;
}
@@ -388,16 +389,16 @@ static int au1100fb_setup(struct au1100fb_device *fbdev)
}
}
if (i >= num_panels) {
- print_warn("Panel '%s' not supported!", this_opt);
+ pr_warn("Panel '%s' not supported!", this_opt);
return -ENODEV;
}
}
/* Unsupported option */
else
- print_warn("Unsupported option \"%s\"", this_opt);
+ pr_warn("Unsupported option \"%s\"", this_opt);
}
- print_info("Panel=%s", fbdev->panel->name);
+ pr_info("Panel=%s", fbdev->panel->name);
return 0;
}
@@ -422,7 +423,7 @@ static int au1100fb_drv_probe(struct platform_device *dev)
/* Allocate region for our registers and map them */
regs_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!regs_res) {
- print_err("fail to retrieve registers resource");
+ pr_err("fail to retrieve registers resource");
return -EFAULT;
}
@@ -440,15 +441,15 @@ static int au1100fb_drv_probe(struct platform_device *dev)
fbdev->info.fix.mmio_start,
fbdev->info.fix.mmio_len,
DRIVER_NAME)) {
- print_err("fail to lock memory region at 0x%08lx",
+ pr_err("fail to lock memory region at 0x%08lx",
fbdev->info.fix.mmio_start);
return -EBUSY;
}
fbdev->regs = (struct au1100fb_regs*)KSEG1ADDR(fbdev->info.fix.mmio_start);
- print_dbg("Register memory map at %p", fbdev->regs);
- print_dbg("phys=0x%08x, size=%zu", fbdev->regs_phys, fbdev->regs_len);
+ pr_devel("Register memory map at %p", fbdev->regs);
+ pr_devel("phys=0x%08x, size=%zu", fbdev->regs_phys, fbdev->regs_len);
c = clk_get(NULL, "lcd_intclk");
if (!IS_ERR(c)) {
@@ -465,7 +466,7 @@ static int au1100fb_drv_probe(struct platform_device *dev)
PAGE_ALIGN(fbdev->fb_len),
&fbdev->fb_phys, GFP_KERNEL);
if (!fbdev->fb_mem) {
- print_err("fail to allocate framebuffer (size: %zuK))",
+ pr_err("fail to allocate framebuffer (size: %zuK))",
fbdev->fb_len / 1024);
return -ENOMEM;
}
@@ -473,8 +474,8 @@ static int au1100fb_drv_probe(struct platform_device *dev)
fbdev->info.fix.smem_start = fbdev->fb_phys;
fbdev->info.fix.smem_len = fbdev->fb_len;
- print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
- print_dbg("phys=0x%pad, size=%zuK", &fbdev->fb_phys, fbdev->fb_len / 1024);
+ pr_devel("Framebuffer memory map at %p", fbdev->fb_mem);
+ pr_devel("phys=0x%pad, size=%zuK", &fbdev->fb_phys, fbdev->fb_len / 1024);
/* load the panel info into the var struct */
fbdev->info.var = (struct fb_var_screeninfo) {
@@ -498,7 +499,7 @@ static int au1100fb_drv_probe(struct platform_device *dev)
return -ENOMEM;
if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
- print_err("Fail to allocate colormap (%d entries)",
+ pr_err("Fail to allocate colormap (%d entries)",
AU1100_LCD_NBR_PALETTE_ENTRIES);
return -EFAULT;
}
@@ -508,7 +509,7 @@ static int au1100fb_drv_probe(struct platform_device *dev)
/* Register new framebuffer */
if (register_framebuffer(&fbdev->info) < 0) {
- print_err("cannot register new framebuffer");
+ pr_err("cannot register new framebuffer");
goto failed;
}
diff --git a/drivers/video/fbdev/au1100fb.h b/drivers/video/fbdev/au1100fb.h
index 63aef2f52141..80743b3e2376 100644
--- a/drivers/video/fbdev/au1100fb.h
+++ b/drivers/video/fbdev/au1100fb.h
@@ -30,16 +30,6 @@
#ifndef _AU1100LCD_H
#define _AU1100LCD_H
-#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
-#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
-#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
-
-#if DEBUG
-#define print_dbg(f, arg...) printk(__FILE__ ": " f "\n", ## arg)
-#else
-#define print_dbg(f, arg...) do {} while (0)
-#endif
-
#if defined(__BIG_ENDIAN)
#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
#else
--
2.47.3
^ permalink raw reply related
* [PATCH v5 4/7] fbdev: au1100fb: Make driver compilable on non-mips platforms
From: Uwe Kleine-König @ 2026-02-15 23:33 UTC (permalink / raw)
To: Helge Deller; +Cc: Chen Ni, linux-fbdev, dri-devel
In-Reply-To: <cover.1771198101.git.u.kleine-koenig@baylibre.com>
The header asm/mach-au1x00/au1000.h is unused apart from pulling in
<linux/delay.h> (for mdelay()) and <linux/io.h> (for KSEG1ADDR()). Then
the only platform specific part in the driver is the usage of the KSEG1ADDR
macro, which for the non-mips case can be stubbed.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
---
drivers/video/fbdev/Kconfig | 3 ++-
drivers/video/fbdev/au1100fb.c | 12 ++++++++++--
drivers/video/fbdev/au1100fb.h | 2 --
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 45733522ff48..ac9ac4287c6a 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1345,7 +1345,8 @@ endchoice
config FB_AU1100
bool "Au1100 LCD Driver"
- depends on (FB = y) && MIPS_ALCHEMY
+ depends on FB = y
+ depends on MIPS_ALCHEMY || COMPILE_TEST
select FB_IOMEM_HELPERS
help
This is the framebuffer driver for the AMD Au1100 SOC. It can drive
diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c
index 398375793f57..7611dad0d68d 100644
--- a/drivers/video/fbdev/au1100fb.c
+++ b/drivers/video/fbdev/au1100fb.c
@@ -42,6 +42,8 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -55,12 +57,15 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <asm/mach-au1x00/au1000.h>
-
#define DEBUG 0
#include "au1100fb.h"
+#if defined(CONFIG_COMPILE_TEST) && !defined(CONFIG_MIPS)
+/* This is only defined to be able to compile this driver on non-mips platforms */
+#define KSEG1ADDR(x) (x)
+#endif
+
#define DRIVER_NAME "au1100fb"
#define DRIVER_DESC "LCD controller driver for AU1100 processors"
@@ -332,7 +337,10 @@ static int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
+#ifndef CONFIG_S390
+ /* On s390 pgprot_val() is a function and thus not a lvalue */
pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
+#endif
return dma_mmap_coherent(fbdev->dev, vma, fbdev->fb_mem, fbdev->fb_phys,
fbdev->fb_len);
diff --git a/drivers/video/fbdev/au1100fb.h b/drivers/video/fbdev/au1100fb.h
index b7bf6e005572..63aef2f52141 100644
--- a/drivers/video/fbdev/au1100fb.h
+++ b/drivers/video/fbdev/au1100fb.h
@@ -30,8 +30,6 @@
#ifndef _AU1100LCD_H
#define _AU1100LCD_H
-#include <asm/mach-au1x00/au1000.h>
-
#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
--
2.47.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox