Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH v3 3/4] arm64: dts: freescale: moduline-display-av101hdt-a10: add backlight
From: Maud Spierings via B4 Relay @ 2025-09-11  7:53 UTC (permalink / raw)
  To: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Helge Deller, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
  Cc: dri-devel, linux-leds, devicetree, linux-kernel, linux-fbdev, imx,
	linux-arm-kernel, Maud Spierings
In-Reply-To: <20250911-max25014-v3-0-d03f4eba375e@gocontroll.com>

From: Maud Spierings <maudspierings@gocontroll.com>

Add the missing backlight driver.

Signed-off-by: Maud Spierings <maudspierings@gocontroll.com>
---
 ...tx8p-ml81-moduline-display-106-av101hdt-a10.dtso | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av101hdt-a10.dtso b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av101hdt-a10.dtso
index e3965caca6be42a17aa89b77bd5b919382c84151..3d0983a3ab5463196de8cefb863bde74426b735d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av101hdt-a10.dtso
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av101hdt-a10.dtso
@@ -17,6 +17,7 @@
 
 	panel {
 		compatible = "boe,av101hdt-a10";
+		backlight = <&backlight>;
 		enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
 		pinctrl-0 = <&pinctrl_panel>;
 		pinctrl-names = "default";
@@ -40,7 +41,27 @@ reg_vbus: regulator-vbus {
 	};
 };
 
+&i2c4 {
+	backlight: backlight@6f {
+		compatible = "maxim,max25014";
+		reg = <0x6f>;
+		default-brightness = <50>;
+		enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_backlight>;
+		maxim,iset = <7>;
+		maxim,strings = <1 1 1 0>;
+	};
+};
+
 &iomuxc {
+	pinctrl_backlight: backlightgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04
+				(MX8MP_PULL_UP | MX8MP_PULL_ENABLE)
+		>;
+	};
+
 	pinctrl_panel: panelgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07

-- 
2.51.0



^ permalink raw reply related

* [PATCH v3 2/4] backlight: add max25014atg backlight
From: Maud Spierings via B4 Relay @ 2025-09-11  7:53 UTC (permalink / raw)
  To: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Helge Deller, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
  Cc: dri-devel, linux-leds, devicetree, linux-kernel, linux-fbdev, imx,
	linux-arm-kernel, Maud Spierings,
	"Maud Spierings maudspierings"
In-Reply-To: <20250911-max25014-v3-0-d03f4eba375e@gocontroll.com>

From: Maud Spierings <maudspierings@gocontroll.com>

The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
with integrated boost controller.

Signed-off-by: Maud Spierings maudspierings@gocontroll.com
---
 MAINTAINERS                        |   1 +
 drivers/video/backlight/Kconfig    |   7 +
 drivers/video/backlight/Makefile   |   1 +
 drivers/video/backlight/max25014.c | 394 +++++++++++++++++++++++++++++++++++++
 4 files changed, 403 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5a592eefbe7562734aada05ab9e3aea8cee010e7..f73d0b94922fe9d7e691a5578a72af41b998a365 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15073,6 +15073,7 @@ MAX25014 BACKLIGHT DRIVER
 M:	Maud Spierings <maudspierings@gocontroll.com>
 S:	Maintained
 F:	Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
+F:	drivers/video/backlight/max25014.c
 
 MAX31335 RTC DRIVER
 M:	Antoniu Miclaus <antoniu.miclaus@analog.com>
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index d9374d208ceebbf8b3c27976e9cb4d725939b942..d3bb6ccd41853d940f24c6ab8135e4b9b9ebefd7 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -262,6 +262,13 @@ config BACKLIGHT_DA9052
 	help
 	  Enable the Backlight Driver for DA9052-BC and DA9053-AA/Bx PMICs.
 
+config BACKLIGHT_MAX25014
+	tristate "Backlight driver for the Maxim MAX25014 chip"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  If you are using a MAX25014 chip as a backlight driver say Y to enable it.
+
 config BACKLIGHT_MAX8925
 	tristate "Backlight driver for MAX8925"
 	depends on MFD_MAX8925
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index dfbb169bf6ea215704859f633b6c4a887f4ebacd..1170d9ec40b8dbd52aeec1dade1cd2d2b56af466 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_BACKLIGHT_LOCOMO)		+= locomolcd.o
 obj-$(CONFIG_BACKLIGHT_LP855X)		+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_LP8788)		+= lp8788_bl.o
 obj-$(CONFIG_BACKLIGHT_LV5207LP)	+= lv5207lp.o
+obj-$(CONFIG_BACKLIGHT_MAX25014)	+= max25014.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)		+= max8925_bl.o
 obj-$(CONFIG_BACKLIGHT_MP3309C)		+= mp3309c.o
 obj-$(CONFIG_BACKLIGHT_MT6370)		+= mt6370-backlight.o
diff --git a/drivers/video/backlight/max25014.c b/drivers/video/backlight/max25014.c
new file mode 100644
index 0000000000000000000000000000000000000000..f4ca79dfc39ccb04702e6114c35a5863f80b8853
--- /dev/null
+++ b/drivers/video/backlight/max25014.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Backlight driver for Maxim MAX25014
+ *
+ * Copyright (C) 2025 GOcontroll B.V.
+ * Author: Maud Spierings <maudspierings@gocontroll.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define MAX25014_ISET_DEFAULT_100 11
+#define MAX_BRIGHTNESS            100
+#define MIN_BRIGHTNESS            0
+#define TON_MAX                   130720 /* @153Hz */
+#define TON_STEP                  1307 /* @153Hz */
+#define TON_MIN                   0
+
+#define MAX25014_DEV_ID           0x00
+#define MAX25014_REV_ID           0x01
+#define MAX25014_ISET             0x02
+#define MAX25014_IMODE            0x03
+#define MAX25014_TON1H            0x04
+#define MAX25014_TON1L            0x05
+#define MAX25014_TON2H            0x06
+#define MAX25014_TON2L            0x07
+#define MAX25014_TON3H            0x08
+#define MAX25014_TON3L            0x09
+#define MAX25014_TON4H            0x0A
+#define MAX25014_TON4L            0x0B
+#define MAX25014_TON_1_4_LSB      0x0C
+#define MAX25014_SETTING          0x12
+#define MAX25014_DISABLE          0x13
+#define MAX25014_BSTMON           0x14
+#define MAX25014_IOUT1            0x15
+#define MAX25014_IOUT2            0x16
+#define MAX25014_IOUT3            0x17
+#define MAX25014_IOUT4            0x18
+#define MAX25014_OPEN             0x1B
+#define MAX25014_SHORT_GND        0x1C
+#define MAX25014_SHORT_LED        0x1D
+#define MAX25014_MASK             0x1E
+#define MAX25014_DIAG             0x1F
+
+#define MAX25014_IMODE_HDIM       BIT(2)
+#define MAX25014_ISET_ENABLE      BIT(5)
+#define MAX25014_ISET_PSEN        BIT(4)
+#define MAX25014_DIAG_HW_RST      BIT(2)
+#define MAX25014_SETTING_FPWM     GENMASK(6, 4)
+
+struct max25014 {
+	struct i2c_client *client;
+	struct backlight_device *bl;
+	struct regmap *regmap;
+	struct gpio_desc *enable;
+	struct regulator *vin; /* regulator for boost converter Vin rail */
+	uint32_t iset;
+	uint8_t strings_mask;
+};
+
+static const struct regmap_config max25014_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = MAX25014_DIAG,
+};
+
+/**
+ * @brief control the brightness with i2c registers
+ *
+ * @param regmap trivial
+ * @param brt brightness
+ * @return int
+ */
+static int max25014_register_control(struct regmap *regmap, uint32_t brt)
+{
+	uint32_t reg = TON_STEP * brt;
+	int ret;
+	/*
+	 * 18 bit number lowest, 2 bits in first register,
+	 * next lowest 8 in the L register, next 8 in the H register
+	 * Seemingly setting the strength of only one string controls all of
+	 * them, individual settings don't affect the outcome.
+	 */
+
+	ret = regmap_write(regmap, MAX25014_TON_1_4_LSB, reg & 0b00000011);
+	if (ret != 0)
+		return ret;
+	ret = regmap_write(regmap, MAX25014_TON1L, (reg >> 2) & 0b11111111);
+	if (ret != 0)
+		return ret;
+	return regmap_write(regmap, MAX25014_TON1H, (reg >> 10) & 0b11111111);
+}
+
+static int max25014_check_errors(struct max25014 *maxim)
+{
+	uint8_t i;
+	int ret;
+	uint32_t val;
+
+	ret = regmap_read(maxim->regmap, MAX25014_OPEN, &val);
+	if (ret != 0)
+		return ret;
+	if (val > 0) {
+		dev_err(&maxim->client->dev, "Open led strings detected on:\n");
+		for (i = 0; i < 4; i++) {
+			if (val & 1 << i)
+				dev_err(&maxim->client->dev, "string %d\n", i + 1);
+		}
+		return -EIO;
+	}
+
+	ret = regmap_read(maxim->regmap, MAX25014_SHORT_GND, &val);
+	if (ret != 0)
+		return ret;
+	if (val > 0) {
+		dev_err(&maxim->client->dev, "Short to ground detected on:\n");
+		for (i = 0; i < 4; i++) {
+			if (val & 1 << i)
+				dev_err(&maxim->client->dev, "string %d\n", i + 1);
+		}
+		return -EIO;
+	}
+
+	ret = regmap_read(maxim->regmap, MAX25014_SHORT_GND, &val);
+	if (ret != 0)
+		return ret;
+	if (val > 0) {
+		dev_err(&maxim->client->dev, "Shorted led detected on:\n");
+		for (i = 0; i < 4; i++) {
+			if (val & 1 << i)
+				dev_err(&maxim->client->dev, "string %d\n", i + 1);
+		}
+		return -EIO;
+	}
+
+	ret = regmap_read(maxim->regmap, MAX25014_DIAG, &val);
+	if (ret != 0)
+		return ret;
+	/*
+	 * The HW_RST bit always starts at 1 after power up.
+	 * It is reset on first read, does not indicate an error.
+	 */
+	if (val > 0 && val != MAX25014_DIAG_HW_RST) {
+		if (val & 0b1)
+			dev_err(&maxim->client->dev, "Overtemperature shutdown\n");
+		if (val & 0b10)
+			dev_warn(&maxim->client->dev,
+				 "Chip is getting too hot (>125C)\n");
+		if (val & 0b1000)
+			dev_err(&maxim->client->dev, "Boost converter overvoltage\n");
+		if (val & 0b10000)
+			dev_err(&maxim->client->dev, "Boost converter undervoltage\n");
+		if (val & 0b100000)
+			dev_err(&maxim->client->dev, "IREF out of range\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+/*
+ * 1. disable unused strings
+ * 2. set dim mode
+ * 3. set initial brightness
+ * 4. set setting register
+ * 5. enable the backlight
+ */
+static int max25014_configure(struct max25014 *maxim, uint32_t initial_brightness)
+{
+	int ret;
+	uint32_t val;
+
+	ret = regmap_write(maxim->regmap, MAX25014_DISABLE,
+			   maxim->strings_mask);
+	if (ret != 0)
+		return ret;
+
+	ret = regmap_write(maxim->regmap, MAX25014_IMODE, MAX25014_IMODE_HDIM);
+	if (ret != 0)
+		return ret;
+
+	max25014_register_control(maxim->regmap,
+				  initial_brightness);
+
+	ret = regmap_read(maxim->regmap, MAX25014_SETTING, &val);
+	if (ret != 0)
+		return ret;
+
+	ret = regmap_write(
+		maxim->regmap, MAX25014_SETTING,
+		val & ~MAX25014_SETTING_FPWM);
+	if (ret != 0)
+		return ret;
+
+	ret = regmap_write(maxim->regmap, MAX25014_ISET,
+			   maxim->iset | MAX25014_ISET_ENABLE | MAX25014_ISET_PSEN);
+	return ret;
+}
+
+static int max25014_update_status(struct backlight_device *bl_dev)
+{
+	struct max25014 *maxim = bl_get_data(bl_dev);
+
+	if (bl_dev->props.state & BL_CORE_SUSPENDED)
+		bl_dev->props.brightness = 0;
+
+	return max25014_register_control(maxim->regmap, bl_dev->props.brightness);
+}
+
+static const struct backlight_ops max25014_bl_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = max25014_update_status,
+};
+
+static int max25014_parse_dt(struct max25014 *maxim, uint32_t *initial_brightness)
+{
+	struct device *dev = &maxim->client->dev;
+	struct device_node *node = dev->of_node;
+	uint32_t strings[4];
+	int res, i;
+
+	if (!node) {
+		dev_err(dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	res = of_property_count_u32_elems(node, "maxim,strings");
+	if (res == 4) {
+		of_property_read_u32_array(node, "maxim,strings", strings, 4);
+	} else {
+		dev_err(dev, "strings property not correctly defined\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (strings[i] == 0)
+			maxim->strings_mask |= 1 << i;
+	}
+
+	*initial_brightness = 50U;
+	of_property_read_u32(node, "default-brightness", initial_brightness);
+	maxim->iset = MAX25014_ISET_DEFAULT_100;
+	of_property_read_u32(node, "maxim,iset", &maxim->iset);
+
+	if (maxim->iset < 0 || maxim->iset > 15) {
+		dev_err(dev,
+			"Invalid iset, should be a value from 0-15, entered was %d\n",
+			maxim->iset);
+		return -EINVAL;
+	}
+
+	if (*initial_brightness < 0 || *initial_brightness > 100) {
+		dev_err(dev,
+			"Invalid initial brightness, should be a value from 0-100, entered was %d\n",
+			*initial_brightness);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int max25014_probe(struct i2c_client *cl)
+{
+	struct backlight_device *bl;
+	const struct i2c_device_id *id = i2c_client_get_device_id(cl);
+	struct max25014 *maxim;
+	struct backlight_properties props;
+	int ret;
+	uint32_t initial_brightness;
+
+	maxim = devm_kzalloc(&cl->dev, sizeof(struct max25014), GFP_KERNEL);
+	if (!maxim)
+		return -ENOMEM;
+
+	maxim->client = cl;
+
+	ret = max25014_parse_dt(maxim, &initial_brightness);
+	if (ret < 0)
+		return ret;
+
+	maxim->vin = devm_regulator_get(&maxim->client->dev, "power");
+	if (IS_ERR(maxim->vin)) {
+		if (PTR_ERR(maxim->vin) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		maxim->vin = NULL;
+	}
+
+	if (maxim->vin) {
+		ret = regulator_enable(maxim->vin);
+		if (ret < 0) {
+			dev_err(&maxim->client->dev, "failed to enable Vin: %d\n", ret);
+			return ret;
+		}
+	}
+
+	maxim->enable =
+		devm_gpiod_get_optional(&maxim->client->dev, "enable", GPIOD_ASIS);
+	if (IS_ERR(maxim->enable)) {
+		ret = PTR_ERR(maxim->enable);
+		dev_err(&maxim->client->dev, "failed to get enable gpio: %d\n", ret);
+		goto disable_vin;
+	}
+
+	if (maxim->enable) {
+		gpiod_set_value_cansleep(maxim->enable, 1);
+
+		/* Datasheet Electrical Characteristics tSTARTUP 2ms */
+		usleep_range(2000, 2500);
+	}
+
+	maxim->regmap = devm_regmap_init_i2c(cl, &max25014_regmap_config);
+	if (IS_ERR(maxim->regmap)) {
+		ret = PTR_ERR(maxim->regmap);
+		dev_err(&maxim->client->dev, "failed to initialize the i2c regmap: %d\n", ret);
+		goto disable_full;
+	}
+
+	i2c_set_clientdata(cl, maxim);
+
+	ret = max25014_check_errors(maxim);
+	if (ret) { /* error is already reported in the above function */
+		goto disable_full;
+	}
+
+	ret = max25014_configure(maxim, initial_brightness);
+	if (ret) {
+		dev_err(&maxim->client->dev, "device config err: %d", ret);
+		goto disable_full;
+	}
+
+	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_PLATFORM;
+	props.max_brightness = MAX_BRIGHTNESS;
+
+	props.brightness = initial_brightness;
+
+	bl = devm_backlight_device_register(&maxim->client->dev, id->name, &maxim->client->dev,
+					    maxim, &max25014_bl_ops, &props);
+	if (IS_ERR(bl))
+		return PTR_ERR(bl);
+
+	maxim->bl = bl;
+
+	return 0;
+
+disable_full:
+	if (maxim->enable)
+		gpiod_set_value_cansleep(maxim->enable, 0);
+disable_vin:
+	if (maxim->vin)
+		regulator_disable(maxim->vin);
+	return ret;
+}
+
+static void max25014_remove(struct i2c_client *cl)
+{
+	struct max25014 *maxim = i2c_get_clientdata(cl);
+
+	maxim->bl->props.brightness = 0;
+	max25014_update_status(maxim->bl);
+	if (maxim->enable)
+		gpiod_set_value_cansleep(maxim->enable, 0);
+	if (maxim->vin)
+		regulator_disable(maxim->vin);
+}
+
+static const struct of_device_id max25014_dt_ids[] = {
+	{ .compatible = "maxim,max25014", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max25014_dt_ids);
+
+static const struct i2c_device_id max25014_ids[] = {
+	{ "max25014" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max25014_ids);
+
+static struct i2c_driver max25014_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.of_match_table = of_match_ptr(max25014_dt_ids),
+	},
+	.probe = max25014_probe,
+	.remove = max25014_remove,
+	.id_table = max25014_ids,
+};
+module_i2c_driver(max25014_driver);
+
+MODULE_DESCRIPTION("Maxim MAX25014 backlight driver");
+MODULE_AUTHOR("Maud Spierings <maudspierings@gocontroll.com>");
+MODULE_LICENSE("GPL");

-- 
2.51.0



^ permalink raw reply related

* [PATCH v3 4/4] arm64: dts: freescale: moduline-display-av123z7m-n17: add backlight
From: Maud Spierings via B4 Relay @ 2025-09-11  7:53 UTC (permalink / raw)
  To: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Helge Deller, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
  Cc: dri-devel, linux-leds, devicetree, linux-kernel, linux-fbdev, imx,
	linux-arm-kernel, Maud Spierings
In-Reply-To: <20250911-max25014-v3-0-d03f4eba375e@gocontroll.com>

From: Maud Spierings <maudspierings@gocontroll.com>

Add the missing backlight.

Signed-off-by: Maud Spierings <maudspierings@gocontroll.com>
---
 ...p-tx8p-ml81-moduline-display-106-av123z7m-n17.dtso | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17.dtso b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17.dtso
index 3eb665ce9d5d2a1c742ffb4feca046e406e29956..0b969c8c04db1c86b2a90c5f5ef91e494e5de7a6 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17.dtso
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17.dtso
@@ -16,6 +16,7 @@
 
 	panel {
 		compatible = "boe,av123z7m-n17";
+		backlight = <&backlight>;
 		enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
 		pinctrl-0 = <&pinctrl_panel>;
 		pinctrl-names = "default";
@@ -91,10 +92,26 @@ lvds1_out: endpoint {
 		};
 	};
 
-	/* max25014 @ 0x6f */
+	backlight: backlight@6f {
+		compatible = "maxim,max25014";
+		reg = <0x6f>;
+		default-brightness = <50>;
+		enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_backlight>;
+		maxim,iset = <7>;
+		maxim,strings = <1 1 1 1>;
+	};
 };
 
 &iomuxc {
+	pinctrl_backlight: backlightgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04
+				(MX8MP_PULL_UP | MX8MP_PULL_ENABLE)
+		>;
+	};
+
 	pinctrl_lvds_bridge: lvdsbridgegrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SAI1_TXD2__GPIO4_IO14

-- 
2.51.0



^ permalink raw reply related

* [PATCH v3 0/4] backlight: add new max25014 backlight driver
From: Maud Spierings via B4 Relay @ 2025-09-11  7:53 UTC (permalink / raw)
  To: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Helge Deller, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
  Cc: dri-devel, linux-leds, devicetree, linux-kernel, linux-fbdev, imx,
	linux-arm-kernel, Maud Spierings,
	"Maud Spierings maudspierings"

The Maxim MAX25014 is an automotive grade backlight driver IC. Its
datasheet can be found at [1].

With its integrated boost controller, it can power 4 channels (led
strings) and has a number of different modes using pwm and or i2c.
Currently implemented is only i2c control.

link: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX25014.pdf [1]

Signed-off-by: Maud Spierings <maudspierings@gocontroll.com>
---
Changes in v3:
- fixed commit message type intgrated -> integrated
- added maximum and description to maxim,iset-property
- dropped unused labels and pinctrl in bindings example
- put the compatible first in the bindings example and dts
- removed brackets around defines
- removed the leftover pdata struct field
- removed the initial_brightness struct field
- Link to v2: https://lore.kernel.org/r/20250819-max25014-v2-0-5fd7aeb141ea@gocontroll.com

Changes in v2:
- Remove leftover unused property from the bindings example
- Complete the bindings example with all properties
- Remove some double info from the maxim,iset property
- Remove platform_data header, fold its data into the max25014 struct
- Don't force defines to be unsigned
- Remove stray struct max25014 declaration
- Remove chipname and device from the max25014 struct
- Inline the max25014_backlight_register() and strings_mask() functions
- Remove CONFIG_OF ifdef
- Link to v1: https://lore.kernel.org/r/20250725-max25014-v1-0-0e8cce92078e@gocontroll.com

---
Maud Spierings (4):
      dt-bindings: backlight: Add max25014 bindings
      backlight: add max25014atg backlight
      arm64: dts: freescale: moduline-display-av101hdt-a10: add backlight
      arm64: dts: freescale: moduline-display-av123z7m-n17: add backlight

 .../bindings/leds/backlight/maxim,max25014.yaml    |  81 +++++
 MAINTAINERS                                        |   6 +
 ...x8p-ml81-moduline-display-106-av101hdt-a10.dtso |  21 ++
 ...x8p-ml81-moduline-display-106-av123z7m-n17.dtso |  19 +-
 drivers/video/backlight/Kconfig                    |   7 +
 drivers/video/backlight/Makefile                   |   1 +
 drivers/video/backlight/max25014.c                 | 394 +++++++++++++++++++++
 7 files changed, 528 insertions(+), 1 deletion(-)
---
base-commit: 8f21d9da46702c4d6951ba60ca8a05f42870fe8f
change-id: 20250626-max25014-4207591e1af5

Best regards,
-- 
Maud Spierings <maudspierings@gocontroll.com>



^ permalink raw reply

* [PATCH v3 1/4] dt-bindings: backlight: Add max25014 bindings
From: Maud Spierings via B4 Relay @ 2025-09-11  7:53 UTC (permalink / raw)
  To: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Helge Deller, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
  Cc: dri-devel, linux-leds, devicetree, linux-kernel, linux-fbdev, imx,
	linux-arm-kernel, Maud Spierings
In-Reply-To: <20250911-max25014-v3-0-d03f4eba375e@gocontroll.com>

From: Maud Spierings <maudspierings@gocontroll.com>

The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
with integrated boost controller.

Signed-off-by: Maud Spierings <maudspierings@gocontroll.com>
---
 .../bindings/leds/backlight/maxim,max25014.yaml    | 81 ++++++++++++++++++++++
 MAINTAINERS                                        |  5 ++
 2 files changed, 86 insertions(+)

diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e113a2ad16aa74f982b9c2ea80578aed2d9424fe
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim max25014 backlight controller
+
+maintainers:
+  - Maud Spierings <maudspierings@gocontroll.com>
+
+allOf:
+  - $ref: common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - maxim,max25014
+
+  reg:
+    maxItems: 1
+
+  enable-gpios:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  power-supply:
+    description: Regulator which controls the boost converter input rail.
+
+  pwms:
+    maxItems: 1
+
+  maxim,iset:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 15
+    default: 11
+    description:
+      Value of the ISET register field. This controls the current scale of the
+      outputs, a higher number means more current.
+
+  maxim,strings:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description:
+      A 4-bit bitfield that describes which led strings to turn on.
+    minItems: 4
+    maxItems: 4
+    items:
+      maximum: 1
+
+required:
+  - compatible
+  - reg
+  - maxim,strings
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        backlight@6f {
+            compatible = "maxim,max25014";
+            reg = <0x6f>;
+            default-brightness = <50>;
+            enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+            interrupt-parent = <&gpio1>;
+            interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+            power-supply = <&reg_backlight>;
+            pwms = <&pwm1>;
+            maxim,iset = <7>;
+            maxim,strings = <1 1 1 1>;
+        };
+    };
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 7b7396ed28a700a2aab318553ce8ba1788312bff..5a592eefbe7562734aada05ab9e3aea8cee010e7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15069,6 +15069,11 @@ F:	Documentation/userspace-api/media/drivers/max2175.rst
 F:	drivers/media/i2c/max2175*
 F:	include/uapi/linux/max2175.h
 
+MAX25014 BACKLIGHT DRIVER
+M:	Maud Spierings <maudspierings@gocontroll.com>
+S:	Maintained
+F:	Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
+
 MAX31335 RTC DRIVER
 M:	Antoniu Miclaus <antoniu.miclaus@analog.com>
 L:	linux-rtc@vger.kernel.org

-- 
2.51.0



^ permalink raw reply related

* Re: [PATCH 0/3] Documentation: fbcon: formatting cleanup and improvements
From: Randy Dunlap @ 2025-09-11  3:35 UTC (permalink / raw)
  To: Bagas Sanjaya, Linux Kernel Mailing List, Linux Documentation,
	Linux Framebuffer, Linux DRI Development
  Cc: Helge Deller, Jonathan Corbet
In-Reply-To: <20250909063744.30053-1-bagasdotme@gmail.com>



On 9/8/25 11:37 PM, Bagas Sanjaya wrote:
> Hi,
> 
> Here are reST formatting cleanup and improvements for fbcon documentation.
> The shortlog below should be self-explanatory.
> 
> This series is based on docs-next tree.
> 
> Enjoy!
> 
> Bagas Sanjaya (3):
>   Documentation: fbcon: Add boot options and attach/detach/unload
>     section headings
>   Documentation: fbcon: Reindent 8th step of attach/detach/unload
>   Documentation: fbcon: Use admonition directives
> 
>  Documentation/fb/fbcon.rst | 42 ++++++++++++++++++++++----------------
>  1 file changed, 24 insertions(+), 18 deletions(-)
> 
> 
> base-commit: 7e5a0fe4e8ae2eb341f8ebbee2b24231a58fc28b

For all 3 patches:

Reviewed-by: Randy Dunlap <rdunlap@infradead.org>
Tested-by: Randy Dunlap <rdunlap@infradead.org>

Thanks.

-- 
~Randy

^ permalink raw reply

* Re: [RFC 1/3] fbdev: hyperv_fb: Remove hyperv_fb driver
From: Thomas Zimmermann @ 2025-09-10 15:48 UTC (permalink / raw)
  To: Michael Kelley, Prasanna Kumar T S M, deller@gmx.de,
	arnd@arndb.de, soci@c64.rulez.org, gonzalo.silvalde@gmail.com,
	rdunlap@infradead.org, bartosz.golaszewski@linaro.org,
	wei.liu@kernel.org, ssengar@linux.microsoft.com,
	linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org,
	dri-devel@lists.freedesktop.org
In-Reply-To: <SN6PR02MB415755A10BD2C9D0E7F847FCD40EA@SN6PR02MB4157.namprd02.prod.outlook.com>

Hi

Am 10.09.25 um 17:25 schrieb Michael Kelley:
> From: Thomas Zimmermann <tzimmermann@suse.de> Sent: Wednesday, September 10, 2025 2:36 AM
>> Hi
>>
>> Am 09.09.25 um 18:58 schrieb Prasanna Kumar T S M:
>>> The Hyper-V DRM driver is available since kernel version 5.14 and
>>> provides full KMS support along with fbdev emulation via the DRM fbdev
>>> helpers. This makes the hyperv_fb driver redundant, remove it.
>> I'm all for removing obsolete drivers. But hyperv_drm likely first needs
>> to merge the patch at
>> https://lore.kernel.org/dri-devel/20250904145806.430568-5-tzimmermann@suse.de/
>> It's been tested and works well. If maintainers from Microsoft have a
>> look at the patch first, we could possibly land it fairly soon.
> Thomas --
>
> My testing of your v3 patch series for vblank timers ended up getting a
> WARN_ON after about 3 days of usage. See [1]. So I don't think it's 100%
> ready yet.

Yeah, I've seen your message, but didn't have time to investigate yet. 
It might not be that much of an issue.

>
> But I agree we need your synthetic vblank timer support to address the
> Hyper-V DRM driver performance issue, before removing the Hyper-V
> fbdev driver. (See [2] for a description of the performance issue.)
>
> Second, isn't it customary to mark a driver as deprecated for a period
> of time, before removing it entirely? I don't see any documentation
> on the deprecation process, but I've seen it done in other cases. If you
> grep through all the kernel Kconfig files, you'll see entries tagged with
> DEPRECATED. Also the driver should be updated to output a deprecated
> message when it loads.

Sure, we can do that.

Best regards
Thomas

>
> Michael
>
> [1] https://lore.kernel.org/dri-devel/BN7PR02MB4148E80C13605F6EAD2B0A03D40FA@BN7PR02MB4148.namprd02.prod.outlook.com/
> [2] https://lore.kernel.org/dri-devel/SN6PR02MB415702B00D6D52B0EE962C98D46CA@SN6PR02MB4157.namprd02.prod.outlook.com/
>
>> Best regards
>> Thomas
>>
>>> Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
>>> ---
>>>    MAINTAINERS                     |    1 -
>>>    drivers/video/fbdev/Kconfig     |    8 -
>>>    drivers/video/fbdev/Makefile    |    1 -
>>>    drivers/video/fbdev/hyperv_fb.c | 1386 -------------------------------
>>>    4 files changed, 1396 deletions(-)
>>>    delete mode 100644 drivers/video/fbdev/hyperv_fb.c
>>>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)



^ permalink raw reply

* RE: [RFC 1/3] fbdev: hyperv_fb: Remove hyperv_fb driver
From: Michael Kelley @ 2025-09-10 15:25 UTC (permalink / raw)
  To: Thomas Zimmermann, Prasanna Kumar T S M, deller@gmx.de,
	arnd@arndb.de, soci@c64.rulez.org, gonzalo.silvalde@gmail.com,
	rdunlap@infradead.org, bartosz.golaszewski@linaro.org,
	wei.liu@kernel.org, ssengar@linux.microsoft.com,
	linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org,
	dri-devel@lists.freedesktop.org
In-Reply-To: <8a958fe8-fbba-4bd6-a79d-fd310f08f8d7@suse.de>

From: Thomas Zimmermann <tzimmermann@suse.de> Sent: Wednesday, September 10, 2025 2:36 AM
> 
> Hi
> 
> Am 09.09.25 um 18:58 schrieb Prasanna Kumar T S M:
> > The Hyper-V DRM driver is available since kernel version 5.14 and
> > provides full KMS support along with fbdev emulation via the DRM fbdev
> > helpers. This makes the hyperv_fb driver redundant, remove it.
> 
> I'm all for removing obsolete drivers. But hyperv_drm likely first needs
> to merge the patch at
> https://lore.kernel.org/dri-devel/20250904145806.430568-5-tzimmermann@suse.de/
> It's been tested and works well. If maintainers from Microsoft have a
> look at the patch first, we could possibly land it fairly soon.

Thomas --

My testing of your v3 patch series for vblank timers ended up getting a
WARN_ON after about 3 days of usage. See [1]. So I don't think it's 100%
ready yet.

But I agree we need your synthetic vblank timer support to address the
Hyper-V DRM driver performance issue, before removing the Hyper-V
fbdev driver. (See [2] for a description of the performance issue.)

Second, isn't it customary to mark a driver as deprecated for a period
of time, before removing it entirely? I don't see any documentation
on the deprecation process, but I've seen it done in other cases. If you
grep through all the kernel Kconfig files, you'll see entries tagged with
DEPRECATED. Also the driver should be updated to output a deprecated
message when it loads.

Michael

[1] https://lore.kernel.org/dri-devel/BN7PR02MB4148E80C13605F6EAD2B0A03D40FA@BN7PR02MB4148.namprd02.prod.outlook.com/
[2] https://lore.kernel.org/dri-devel/SN6PR02MB415702B00D6D52B0EE962C98D46CA@SN6PR02MB4157.namprd02.prod.outlook.com/

> 
> Best regards
> Thomas
> 
> >
> > Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
> > ---
> >   MAINTAINERS                     |    1 -
> >   drivers/video/fbdev/Kconfig     |    8 -
> >   drivers/video/fbdev/Makefile    |    1 -
> >   drivers/video/fbdev/hyperv_fb.c | 1386 -------------------------------
> >   4 files changed, 1396 deletions(-)
> >   delete mode 100644 drivers/video/fbdev/hyperv_fb.c
> >

^ permalink raw reply

* Re: [PATCH v2] fbdev/simplefb: Fix use after free in simplefb_detach_genpds()
From: Hans de Goede @ 2025-09-10 15:07 UTC (permalink / raw)
  To: Janne Grunau, Helge Deller, Thierry Reding
  Cc: linux-fbdev, dri-devel, linux-kernel, Daniel Huhardeaux, stable
In-Reply-To: <20250908-simplefb-genpd-uaf-v2-1-f88a0d9d880f@jannau.net>

Hi Janne,

On 8-Sep-25 11:23 PM, Janne Grunau wrote:
> The pm_domain cleanup can not be devres managed as it uses struct
> simplefb_par which is allocated within struct fb_info by
> framebuffer_alloc(). This allocation is explicitly freed by
> unregister_framebuffer() in simplefb_remove().
> Devres managed cleanup runs after the device remove call and thus can no
> longer access struct simplefb_par.
> Call simplefb_detach_genpds() explicitly from simplefb_destroy() like
> the cleanup functions for clocks and regulators.
> 
> Fixes an use after free on M2 Mac mini during
> aperture_remove_conflicting_devices() using the downstream asahi kernel
> with Debian's kernel config. For unknown reasons this started to
> consistently dereference an invalid pointer in v6.16.3 based kernels.

Thank you for your patch.

This patch seems to miss adding a simplefb_detach_genpds()
on error-exit from simplefb_probe() after a successful
simplefb_attach_genpds() call ?

Regards,

Hans




> 
> [    6.736134] BUG: KASAN: slab-use-after-free in simplefb_detach_genpds+0x58/0x220
> [    6.743545] Read of size 4 at addr ffff8000304743f0 by task (udev-worker)/227
> [    6.750697]
> [    6.752182] CPU: 6 UID: 0 PID: 227 Comm: (udev-worker) Tainted: G S                  6.16.3-asahi+ #16 PREEMPTLAZY
> [    6.752186] Tainted: [S]=CPU_OUT_OF_SPEC
> [    6.752187] Hardware name: Apple Mac mini (M2, 2023) (DT)
> [    6.752189] Call trace:
> [    6.752190]  show_stack+0x34/0x98 (C)
> [    6.752194]  dump_stack_lvl+0x60/0x80
> [    6.752197]  print_report+0x17c/0x4d8
> [    6.752201]  kasan_report+0xb4/0x100
> [    6.752206]  __asan_report_load4_noabort+0x20/0x30
> [    6.752209]  simplefb_detach_genpds+0x58/0x220
> [    6.752213]  devm_action_release+0x50/0x98
> [    6.752216]  release_nodes+0xd0/0x2c8
> [    6.752219]  devres_release_all+0xfc/0x178
> [    6.752221]  device_unbind_cleanup+0x28/0x168
> [    6.752224]  device_release_driver_internal+0x34c/0x470
> [    6.752228]  device_release_driver+0x20/0x38
> [    6.752231]  bus_remove_device+0x1b0/0x380
> [    6.752234]  device_del+0x314/0x820
> [    6.752238]  platform_device_del+0x3c/0x1e8
> [    6.752242]  platform_device_unregister+0x20/0x50
> [    6.752246]  aperture_detach_platform_device+0x1c/0x30
> [    6.752250]  aperture_detach_devices+0x16c/0x290
> [    6.752253]  aperture_remove_conflicting_devices+0x34/0x50
> ...
> [    6.752343]
> [    6.967409] Allocated by task 62:
> [    6.970724]  kasan_save_stack+0x3c/0x70
> [    6.974560]  kasan_save_track+0x20/0x40
> [    6.978397]  kasan_save_alloc_info+0x40/0x58
> [    6.982670]  __kasan_kmalloc+0xd4/0xd8
> [    6.986420]  __kmalloc_noprof+0x194/0x540
> [    6.990432]  framebuffer_alloc+0xc8/0x130
> [    6.994444]  simplefb_probe+0x258/0x2378
> ...
> [    7.054356]
> [    7.055838] Freed by task 227:
> [    7.058891]  kasan_save_stack+0x3c/0x70
> [    7.062727]  kasan_save_track+0x20/0x40
> [    7.066565]  kasan_save_free_info+0x4c/0x80
> [    7.070751]  __kasan_slab_free+0x6c/0xa0
> [    7.074675]  kfree+0x10c/0x380
> [    7.077727]  framebuffer_release+0x5c/0x90
> [    7.081826]  simplefb_destroy+0x1b4/0x2c0
> [    7.085837]  put_fb_info+0x98/0x100
> [    7.089326]  unregister_framebuffer+0x178/0x320
> [    7.093861]  simplefb_remove+0x3c/0x60
> [    7.097611]  platform_remove+0x60/0x98
> [    7.101361]  device_remove+0xb8/0x160
> [    7.105024]  device_release_driver_internal+0x2fc/0x470
> [    7.110256]  device_release_driver+0x20/0x38
> [    7.114529]  bus_remove_device+0x1b0/0x380
> [    7.118628]  device_del+0x314/0x820
> [    7.122116]  platform_device_del+0x3c/0x1e8
> [    7.126302]  platform_device_unregister+0x20/0x50
> [    7.131012]  aperture_detach_platform_device+0x1c/0x30
> [    7.136157]  aperture_detach_devices+0x16c/0x290
> [    7.140779]  aperture_remove_conflicting_devices+0x34/0x50
> ...
> 
> Reported-by: Daniel Huhardeaux <tech@tootai.net>
> Cc: stable@vger.kernel.org
> Fixes: 92a511a568e44 ("fbdev/simplefb: Add support for generic power-domains")
> Signed-off-by: Janne Grunau <j@jannau.net>
> ---
> Changes in v2:
> - reworked change due to missed use of `par->num_genpds` before setting
>   it. Missed in testing due to FB_SIMPLE vs. SYSFB_SIMPLEFB.
> - Link to v1: https://lore.kernel.org/r/20250901-simplefb-genpd-uaf-v1-1-0d9f3a34c4dc@jannau.net
> ---
>  drivers/video/fbdev/simplefb.c | 22 ++++++++++++++++------
>  1 file changed, 16 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
> index 1893815dc67f4c1403eea42c0e10a7ead4d96ba9..2f3e5449509d1824a3d26f73e103af82d56d558a 100644
> --- a/drivers/video/fbdev/simplefb.c
> +++ b/drivers/video/fbdev/simplefb.c
> @@ -93,6 +93,7 @@ struct simplefb_par {
>  
>  static void simplefb_clocks_destroy(struct simplefb_par *par);
>  static void simplefb_regulators_destroy(struct simplefb_par *par);
> +static void simplefb_detach_genpds(void *res);
>  
>  /*
>   * fb_ops.fb_destroy is called by the last put_fb_info() call at the end
> @@ -105,6 +106,7 @@ static void simplefb_destroy(struct fb_info *info)
>  
>  	simplefb_regulators_destroy(info->par);
>  	simplefb_clocks_destroy(info->par);
> +	simplefb_detach_genpds(info->par);
>  	if (info->screen_base)
>  		iounmap(info->screen_base);
>  
> @@ -451,7 +453,7 @@ static int simplefb_attach_genpds(struct simplefb_par *par,
>  				  struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> -	unsigned int i;
> +	unsigned int i, num_genpds;
>  	int err;
>  
>  	err = of_count_phandle_with_args(dev->of_node, "power-domains",
> @@ -465,26 +467,33 @@ static int simplefb_attach_genpds(struct simplefb_par *par,
>  		return err;
>  	}
>  
> -	par->num_genpds = err;
> +	num_genpds = err;
>  
>  	/*
>  	 * Single power-domain devices are handled by the driver core, so
>  	 * nothing to do here.
>  	 */
> -	if (par->num_genpds <= 1)
> +	if (num_genpds <= 1)
>  		return 0;
>  
> -	par->genpds = devm_kcalloc(dev, par->num_genpds, sizeof(*par->genpds),
> +	par->genpds = devm_kcalloc(dev, num_genpds, sizeof(*par->genpds),
>  				   GFP_KERNEL);
>  	if (!par->genpds)
>  		return -ENOMEM;
>  
> -	par->genpd_links = devm_kcalloc(dev, par->num_genpds,
> +	par->genpd_links = devm_kcalloc(dev, num_genpds,
>  					sizeof(*par->genpd_links),
>  					GFP_KERNEL);
>  	if (!par->genpd_links)
>  		return -ENOMEM;
>  
> +	/*
> +	 * Set par->num_genpds only after genpds and genpd_links are allocated
> +	 * to exit early from simplefb_detach_genpds() without full
> +	 * initialisation.
> +	 */
> +	par->num_genpds = num_genpds;
> +
>  	for (i = 0; i < par->num_genpds; i++) {
>  		par->genpds[i] = dev_pm_domain_attach_by_id(dev, i);
>  		if (IS_ERR(par->genpds[i])) {
> @@ -506,9 +515,10 @@ static int simplefb_attach_genpds(struct simplefb_par *par,
>  			dev_warn(dev, "failed to link power-domain %u\n", i);
>  	}
>  
> -	return devm_add_action_or_reset(dev, simplefb_detach_genpds, par);
> +	return 0;
>  }
>  #else
> +static void simplefb_detach_genpds(void *res) { }
>  static int simplefb_attach_genpds(struct simplefb_par *par,
>  				  struct platform_device *pdev)
>  {
> 
> ---
> base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
> change-id: 20250901-simplefb-genpd-uaf-352704761a29
> 
> Best regards,


^ permalink raw reply

* Re: [PATCH 1/1] Revert "fbdev: Disable sysfb device registration when removing conflicting FBs"
From: Javier Martinez Canillas @ 2025-09-10 11:09 UTC (permalink / raw)
  To: Brett A C Sheffield
  Cc: stable, regressions, linux-kernel, linux-fbdev, dri-devel,
	Simona Vetter, Helge Deller, Thomas Zimmermann, Lee Jones,
	Murad Masimov, Yongzhen Zhang, Greg Kroah-Hartman, Sasha Levin
In-Reply-To: <aMFYeV4UdD7NnrSC@karahi.gladserv.com>

Brett A C Sheffield <bacs@librecast.net> writes:

> On 2025-09-10 12:46, Javier Martinez Canillas wrote:
>> Brett A C Sheffield <bacs@librecast.net> writes:
>> 
>> Hello Brett,
>> 
>> > This reverts commit 13d28e0c79cbf69fc6f145767af66905586c1249.
>> >
>> > Commit ee7a69aa38d8 ("fbdev: Disable sysfb device registration when
>> > removing conflicting FBs") was backported to 5.15.y LTS. This causes a
>> > regression where all virtual consoles stop responding during boot at:
>> >
>> > "Populating /dev with existing devices through uevents ..."
>> >
>> > Reverting the commit fixes the regression.
>> >
>> > Signed-off-by: Brett A C Sheffield <bacs@librecast.net>
>> > ---
>> 
>> In the other email you said:
>> 
>> > Newer stable kernels with this
>> > patch (6.1.y, 6.6.y, 6.12,y, 6.15.y, 6.16.y) and mainline are unaffected.
>> 
>> But are you proposing to revert the mentioned commit in mainline too
>> or just in the 5.15.y LTS tree ?
>
> Only the 5.15.y tree. Sorry - that could have been clearer.  There's no
> regression anywhere else. Mainline and other stable kernels are all ok.
>

That's what I thought but just wanted to confirm that was the case. Thanks!

> Cheers,
>
>
> Brett
>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* Re: [PATCH 1/1] Revert "fbdev: Disable sysfb device registration when removing conflicting FBs"
From: Sasha Levin @ 2025-09-10 11:01 UTC (permalink / raw)
  To: Brett A C Sheffield
  Cc: Javier Martinez Canillas, stable, regressions, linux-kernel,
	linux-fbdev, dri-devel, Simona Vetter, Helge Deller,
	Thomas Zimmermann, Lee Jones, Murad Masimov, Yongzhen Zhang,
	Greg Kroah-Hartman
In-Reply-To: <aMFYeV4UdD7NnrSC@karahi.gladserv.com>

On Wed, Sep 10, 2025 at 12:52:41PM +0200, Brett A C Sheffield wrote:
>On 2025-09-10 12:46, Javier Martinez Canillas wrote:
>> Brett A C Sheffield <bacs@librecast.net> writes:
>>
>> Hello Brett,
>>
>> > This reverts commit 13d28e0c79cbf69fc6f145767af66905586c1249.
>> >
>> > Commit ee7a69aa38d8 ("fbdev: Disable sysfb device registration when
>> > removing conflicting FBs") was backported to 5.15.y LTS. This causes a
>> > regression where all virtual consoles stop responding during boot at:
>> >
>> > "Populating /dev with existing devices through uevents ..."
>> >
>> > Reverting the commit fixes the regression.
>> >
>> > Signed-off-by: Brett A C Sheffield <bacs@librecast.net>
>> > ---
>>
>> In the other email you said:
>>
>> > Newer stable kernels with this
>> > patch (6.1.y, 6.6.y, 6.12,y, 6.15.y, 6.16.y) and mainline are unaffected.
>>
>> But are you proposing to revert the mentioned commit in mainline too
>> or just in the 5.15.y LTS tree ?
>
>Only the 5.15.y tree. Sorry - that could have been clearer.  There's no
>regression anywhere else. Mainline and other stable kernels are all ok.

Thanks for investigating this! I'll queue it up for 5.15.

-- 
Thanks,
Sasha

^ permalink raw reply

* Re: [PATCH 1/1] Revert "fbdev: Disable sysfb device registration when removing conflicting FBs"
From: Brett A C Sheffield @ 2025-09-10 10:52 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: stable, regressions, linux-kernel, linux-fbdev, dri-devel,
	Simona Vetter, Helge Deller, Thomas Zimmermann, Lee Jones,
	Murad Masimov, Yongzhen Zhang, Greg Kroah-Hartman, Sasha Levin
In-Reply-To: <87frcuegb7.fsf@minerva.mail-host-address-is-not-set>

On 2025-09-10 12:46, Javier Martinez Canillas wrote:
> Brett A C Sheffield <bacs@librecast.net> writes:
> 
> Hello Brett,
> 
> > This reverts commit 13d28e0c79cbf69fc6f145767af66905586c1249.
> >
> > Commit ee7a69aa38d8 ("fbdev: Disable sysfb device registration when
> > removing conflicting FBs") was backported to 5.15.y LTS. This causes a
> > regression where all virtual consoles stop responding during boot at:
> >
> > "Populating /dev with existing devices through uevents ..."
> >
> > Reverting the commit fixes the regression.
> >
> > Signed-off-by: Brett A C Sheffield <bacs@librecast.net>
> > ---
> 
> In the other email you said:
> 
> > Newer stable kernels with this
> > patch (6.1.y, 6.6.y, 6.12,y, 6.15.y, 6.16.y) and mainline are unaffected.
> 
> But are you proposing to revert the mentioned commit in mainline too
> or just in the 5.15.y LTS tree ?

Only the 5.15.y tree. Sorry - that could have been clearer.  There's no
regression anywhere else. Mainline and other stable kernels are all ok.

Cheers,


Brett

^ permalink raw reply

* Re: [PATCH 1/1] Revert "fbdev: Disable sysfb device registration when removing conflicting FBs"
From: Javier Martinez Canillas @ 2025-09-10 10:46 UTC (permalink / raw)
  To: Brett A C Sheffield, stable
  Cc: regressions, linux-kernel, linux-fbdev, dri-devel, Simona Vetter,
	Helge Deller, Thomas Zimmermann, Lee Jones, Murad Masimov,
	Yongzhen Zhang, Greg Kroah-Hartman, Sasha Levin,
	Brett A C Sheffield
In-Reply-To: <20250910095124.6213-5-bacs@librecast.net>

Brett A C Sheffield <bacs@librecast.net> writes:

Hello Brett,

> This reverts commit 13d28e0c79cbf69fc6f145767af66905586c1249.
>
> Commit ee7a69aa38d8 ("fbdev: Disable sysfb device registration when
> removing conflicting FBs") was backported to 5.15.y LTS. This causes a
> regression where all virtual consoles stop responding during boot at:
>
> "Populating /dev with existing devices through uevents ..."
>
> Reverting the commit fixes the regression.
>
> Signed-off-by: Brett A C Sheffield <bacs@librecast.net>
> ---

In the other email you said:

> Newer stable kernels with this
> patch (6.1.y, 6.6.y, 6.12,y, 6.15.y, 6.16.y) and mainline are unaffected.

But are you proposing to revert the mentioned commit in mainline too
or just in the 5.15.y LTS tree ?

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* [PATCH 1/1] Revert "fbdev: Disable sysfb device registration when removing conflicting FBs"
From: Brett A C Sheffield @ 2025-09-10  9:38 UTC (permalink / raw)
  To: stable
  Cc: regressions, linux-kernel, linux-fbdev, dri-devel,
	Javier Martinez Canillas, Simona Vetter, Helge Deller,
	Thomas Zimmermann, Lee Jones, Murad Masimov, Yongzhen Zhang,
	Greg Kroah-Hartman, Sasha Levin, Brett A C Sheffield
In-Reply-To: <20250910095124.6213-3-bacs@librecast.net>

This reverts commit 13d28e0c79cbf69fc6f145767af66905586c1249.

Commit ee7a69aa38d8 ("fbdev: Disable sysfb device registration when
removing conflicting FBs") was backported to 5.15.y LTS. This causes a
regression where all virtual consoles stop responding during boot at:

"Populating /dev with existing devices through uevents ..."

Reverting the commit fixes the regression.

Signed-off-by: Brett A C Sheffield <bacs@librecast.net>
---
 drivers/video/fbdev/core/fbmem.c | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index d938c31e8f90..3b52ddfe0350 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
-#include <linux/sysfb.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/vt.h>
@@ -1795,17 +1794,6 @@ int remove_conflicting_framebuffers(struct apertures_struct *a,
 		do_free = true;
 	}
 
-	/*
-	 * If a driver asked to unregister a platform device registered by
-	 * sysfb, then can be assumed that this is a driver for a display
-	 * that is set up by the system firmware and has a generic driver.
-	 *
-	 * Drivers for devices that don't have a generic driver will never
-	 * ask for this, so let's assume that a real driver for the display
-	 * was already probed and prevent sysfb to register devices later.
-	 */
-	sysfb_disable();
-
 	mutex_lock(&registration_lock);
 	do_remove_conflicting_framebuffers(a, name, primary);
 	mutex_unlock(&registration_lock);
-- 
2.49.1


^ permalink raw reply related

* [REGRESSION 5.15.y][BISECTED][PATCH 0/1] console hangs at uevents
From: Brett A C Sheffield @ 2025-09-10  9:38 UTC (permalink / raw)
  To: stable
  Cc: regressions, linux-kernel, linux-fbdev, dri-devel,
	Javier Martinez Canillas, Simona Vetter, Helge Deller,
	Thomas Zimmermann, Lee Jones, Murad Masimov, Yongzhen Zhang,
	Greg Kroah-Hartman, Sasha Levin, Brett A C Sheffield

Commit ee7a69aa38d8 ("fbdev: Disable sysfb device registration when removing
conflicting FBs") was backported to 5.15.y LTS. This causes a regression where
all virtual consoles stop responding during boot at:

"Populating /dev with existing devices through uevents ..."

The console is no longer responding, nor is it possible to switch to another
virtual console. It is possible to force a reboot with CTRL+ALT+DEL.

The system is otherwise still working normally, and can be connected to over
ssh.

This patch was not backported to 5.4.y or 5.10.y. Newer stable kernels with this
patch (6.1.y, 6.6.y, 6.12,y, 6.15.y, 6.16.y) and mainline are unaffected.

There are a bunch of patches that touch fbmem.c in later stable kernels, and I
started looking at this but it gets messy very quickly as e23a5e14aa27 is a
merge commit.

Given this was an autoselected patch that was not backported to fix any specific
issue the simplest and cleanest fix is to simply revert.


Bisection log:

git bisect start
# status: waiting for both good and bad commits
# good: [8bb7eca972ad531c9b149c0a51ab43a417385813] Linux 5.15
git bisect good 8bb7eca972ad531c9b149c0a51ab43a417385813
# status: waiting for bad commit, 1 good commit known
# bad: [c275eaaaa34260e6c907bc5e7ee07c096bc45064] Linux 5.15.125
git bisect bad c275eaaaa34260e6c907bc5e7ee07c096bc45064
# bad: [ff2932ac8ee1ce6f66ba1b5017843c87492cd1a8] tcp: Fix a data-race around sysctl_tcp_challenge_ack_limit.
git bisect bad ff2932ac8ee1ce6f66ba1b5017843c87492cd1a8
# good: [72ea28d88d30cefc5b0184e4666cf4817f2a0fa8] arm64: dts: marvell: armada-37xx: Remap IO space to bus address 0x0
git bisect good 72ea28d88d30cefc5b0184e4666cf4817f2a0fa8
# good: [acd12d16528152b32fa09be2c5ef95047f69af05] KVM: x86/mmu: fix NULL pointer dereference on guest INVPCID
git bisect good acd12d16528152b32fa09be2c5ef95047f69af05
# good: [ce49b94ddb70e607c476a12d26002715d694b23a] random: avoid checking crng_ready() twice in random_init()
git bisect good ce49b94ddb70e607c476a12d26002715d694b23a
# good: [6886327780254ba749b770373653b6afc2a339fc] fbcon: Disallow setting font bigger than screen size
git bisect good 6886327780254ba749b770373653b6afc2a339fc
# bad: [1f068f9da7436b11276f23ebf65dd641c8ae0b62] x86/entry: Avoid very early RET
git bisect bad 1f068f9da7436b11276f23ebf65dd641c8ae0b62
# good: [5a4bb158f4c638d1fc494d2730357cfb6f5a4eea] netfilter: nf_tables: replace BUG_ON by element length check
git bisect good 5a4bb158f4c638d1fc494d2730357cfb6f5a4eea
# bad: [e71d0e1370b162271a0053e1f1215961c31dc4cb] ASoC: codecs: rt700/rt711/rt711-sdca: initialize workqueues in probe
git bisect bad e71d0e1370b162271a0053e1f1215961c31dc4cb
# good: [2d84fcb6e6f74c96eb03e6a1b9eed0a164e37b2c] seg6: bpf: fix skb checksum in bpf_push_seg6_encap()
git bisect good 2d84fcb6e6f74c96eb03e6a1b9eed0a164e37b2c
# good: [06f818de1621ea4da689fd45f1eb54ff7617342b] scsi: hisi_sas: Limit max hw sectors for v3 HW
git bisect good 06f818de1621ea4da689fd45f1eb54ff7617342b
# bad: [7a2294c5f2e5636772afe6bd6c5b28218e0ea154] nvme: fix regression when disconnect a recovering ctrl
git bisect bad 7a2294c5f2e5636772afe6bd6c5b28218e0ea154
# good: [b952569e03168e23258fabf3faa4d6d2b8e08835] firmware: sysfb: Add sysfb_disable() helper function
git bisect good b952569e03168e23258fabf3faa4d6d2b8e08835
# bad: [833ecd0eae76eadf81d6d747bb5bc992d1151867] net: tipc: fix possible refcount leak in tipc_sk_create()
git bisect bad 833ecd0eae76eadf81d6d747bb5bc992d1151867
# bad: [13d28e0c79cbf69fc6f145767af66905586c1249] fbdev: Disable sysfb device registration when removing conflicting FBs
git bisect bad 13d28e0c79cbf69fc6f145767af66905586c1249
# first bad commit: [13d28e0c79cbf69fc6f145767af66905586c1249] fbdev: Disable sysfb device registration when removing conflicting FBs



Brett A C Sheffield (1):
  Revert "fbdev: Disable sysfb device registration when removing
    conflicting FBs"

 drivers/video/fbdev/core/fbmem.c | 12 ------------
 1 file changed, 12 deletions(-)

-- 
2.49.1


^ permalink raw reply

* Re: [RFC 1/3] fbdev: hyperv_fb: Remove hyperv_fb driver
From: Thomas Zimmermann @ 2025-09-10  9:36 UTC (permalink / raw)
  To: Prasanna Kumar T S M, deller, arnd, soci, gonzalo.silvalde,
	rdunlap, bartosz.golaszewski, wei.liu, mhklinux, ssengar,
	linux-kernel, linux-fbdev, dri-devel
In-Reply-To: <1757437112-2509-1-git-send-email-ptsm@linux.microsoft.com>

Hi

Am 09.09.25 um 18:58 schrieb Prasanna Kumar T S M:
> The Hyper-V DRM driver is available since kernel version 5.14 and
> provides full KMS support along with fbdev emulation via the DRM fbdev
> helpers. This makes the hyperv_fb driver redundant, remove it.

I'm all for removing obsolete drivers. But hyperv_drm likely first needs 
to merge the patch at 
https://lore.kernel.org/dri-devel/20250904145806.430568-5-tzimmermann@suse.de/ 
It's been tested and works well. If maintainers from Microsoft have a 
look at the patch first, we could possibly land it fairly soon.

Best regards
Thomas

>
> Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
> ---
>   MAINTAINERS                     |    1 -
>   drivers/video/fbdev/Kconfig     |    8 -
>   drivers/video/fbdev/Makefile    |    1 -
>   drivers/video/fbdev/hyperv_fb.c | 1386 -------------------------------
>   4 files changed, 1396 deletions(-)
>   delete mode 100644 drivers/video/fbdev/hyperv_fb.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index e94d68c980c5..9d0f0e929356 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11416,7 +11416,6 @@ F:	drivers/pci/controller/pci-hyperv-intf.c
>   F:	drivers/pci/controller/pci-hyperv.c
>   F:	drivers/scsi/storvsc_drv.c
>   F:	drivers/uio/uio_hv_generic.c
> -F:	drivers/video/fbdev/hyperv_fb.c
>   F:	include/asm-generic/mshyperv.h
>   F:	include/clocksource/hyperv_timer.h
>   F:	include/hyperv/hvgdk.h
> diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
> index c21484d15f0c..bb8ac759f6aa 100644
> --- a/drivers/video/fbdev/Kconfig
> +++ b/drivers/video/fbdev/Kconfig
> @@ -1772,14 +1772,6 @@ config FB_BROADSHEET
>   	  and could also have been called by other names when coupled with
>   	  a bridge adapter.
>   
> -config FB_HYPERV
> -	tristate "Microsoft Hyper-V Synthetic Video support"
> -	depends on FB && HYPERV
> -	select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA
> -	select FB_IOMEM_HELPERS_DEFERRED
> -	help
> -	  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
> -
>   config FB_SIMPLE
>   	tristate "Simple framebuffer support"
>   	depends on FB
> diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
> index b3d12f977c06..36a18d958ba0 100644
> --- a/drivers/video/fbdev/Makefile
> +++ b/drivers/video/fbdev/Makefile
> @@ -111,7 +111,6 @@ obj-y                             += omap2/
>   obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
>   obj-$(CONFIG_FB_CARMINE)          += carminefb.o
>   obj-$(CONFIG_FB_MB862XX)	  += mb862xx/
> -obj-$(CONFIG_FB_HYPERV)		  += hyperv_fb.o
>   obj-$(CONFIG_FB_OPENCORES)	  += ocfb.o
>   obj-$(CONFIG_FB_SM712)		  += sm712fb.o
>   
> diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
> deleted file mode 100644
> index 75338ffc703f..000000000000
> --- a/drivers/video/fbdev/hyperv_fb.c
> +++ /dev/null
> @@ -1,1386 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/*
> - * Copyright (c) 2012, Microsoft Corporation.
> - *
> - * Author:
> - *   Haiyang Zhang <haiyangz@microsoft.com>
> - */
> -
> -/*
> - * Hyper-V Synthetic Video Frame Buffer Driver
> - *
> - * This is the driver for the Hyper-V Synthetic Video, which supports
> - * screen resolution up to Full HD 1920x1080 with 32 bit color on Windows
> - * Server 2012, and 1600x1200 with 16 bit color on Windows Server 2008 R2
> - * or earlier.
> - *
> - * It also solves the double mouse cursor issue of the emulated video mode.
> - *
> - * The default screen resolution is 1152x864, which may be changed by a
> - * kernel parameter:
> - *     video=hyperv_fb:<width>x<height>
> - *     For example: video=hyperv_fb:1280x1024
> - *
> - * Portrait orientation is also supported:
> - *     For example: video=hyperv_fb:864x1152
> - *
> - * When a Windows 10 RS5+ host is used, the virtual machine screen
> - * resolution is obtained from the host. The "video=hyperv_fb" option is
> - * not needed, but still can be used to overwrite what the host specifies.
> - * The VM resolution on the host could be set by executing the powershell
> - * "set-vmvideo" command. For example
> - *     set-vmvideo -vmname name -horizontalresolution:1920 \
> - * -verticalresolution:1200 -resolutiontype single
> - *
> - * Gen 1 VMs also support direct using VM's physical memory for framebuffer.
> - * It could improve the efficiency and performance for framebuffer and VM.
> - * This requires to allocate contiguous physical memory from Linux kernel's
> - * CMA memory allocator. To enable this, supply a kernel parameter to give
> - * enough memory space to CMA allocator for framebuffer. For example:
> - *    cma=130m
> - * This gives 130MB memory to CMA allocator that can be allocated to
> - * framebuffer. For reference, 8K resolution (7680x4320) takes about
> - * 127MB memory.
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/aperture.h>
> -#include <linux/module.h>
> -#include <linux/kernel.h>
> -#include <linux/vmalloc.h>
> -#include <linux/init.h>
> -#include <linux/completion.h>
> -#include <linux/fb.h>
> -#include <linux/pci.h>
> -#include <linux/panic_notifier.h>
> -#include <linux/efi.h>
> -#include <linux/console.h>
> -
> -#include <linux/hyperv.h>
> -
> -/* Hyper-V Synthetic Video Protocol definitions and structures */
> -#define MAX_VMBUS_PKT_SIZE 0x4000
> -
> -#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
> -/* Support for VERSION_WIN7 is removed. #define is retained for reference. */
> -#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
> -#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
> -#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
> -
> -#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
> -#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
> -
> -#define SYNTHVID_DEPTH_WIN8 32
> -#define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
> -
> -enum pipe_msg_type {
> -	PIPE_MSG_INVALID,
> -	PIPE_MSG_DATA,
> -	PIPE_MSG_MAX
> -};
> -
> -struct pipe_msg_hdr {
> -	u32 type;
> -	u32 size; /* size of message after this field */
> -} __packed;
> -
> -
> -enum synthvid_msg_type {
> -	SYNTHVID_ERROR			= 0,
> -	SYNTHVID_VERSION_REQUEST	= 1,
> -	SYNTHVID_VERSION_RESPONSE	= 2,
> -	SYNTHVID_VRAM_LOCATION		= 3,
> -	SYNTHVID_VRAM_LOCATION_ACK	= 4,
> -	SYNTHVID_SITUATION_UPDATE	= 5,
> -	SYNTHVID_SITUATION_UPDATE_ACK	= 6,
> -	SYNTHVID_POINTER_POSITION	= 7,
> -	SYNTHVID_POINTER_SHAPE		= 8,
> -	SYNTHVID_FEATURE_CHANGE		= 9,
> -	SYNTHVID_DIRT			= 10,
> -	SYNTHVID_RESOLUTION_REQUEST	= 13,
> -	SYNTHVID_RESOLUTION_RESPONSE	= 14,
> -
> -	SYNTHVID_MAX			= 15
> -};
> -
> -#define		SYNTHVID_EDID_BLOCK_SIZE	128
> -#define		SYNTHVID_MAX_RESOLUTION_COUNT	64
> -
> -struct hvd_screen_info {
> -	u16 width;
> -	u16 height;
> -} __packed;
> -
> -struct synthvid_msg_hdr {
> -	u32 type;
> -	u32 size;  /* size of this header + payload after this field*/
> -} __packed;
> -
> -struct synthvid_version_req {
> -	u32 version;
> -} __packed;
> -
> -struct synthvid_version_resp {
> -	u32 version;
> -	u8 is_accepted;
> -	u8 max_video_outputs;
> -} __packed;
> -
> -struct synthvid_supported_resolution_req {
> -	u8 maximum_resolution_count;
> -} __packed;
> -
> -struct synthvid_supported_resolution_resp {
> -	u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
> -	u8 resolution_count;
> -	u8 default_resolution_index;
> -	u8 is_standard;
> -	struct hvd_screen_info
> -		supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
> -} __packed;
> -
> -struct synthvid_vram_location {
> -	u64 user_ctx;
> -	u8 is_vram_gpa_specified;
> -	u64 vram_gpa;
> -} __packed;
> -
> -struct synthvid_vram_location_ack {
> -	u64 user_ctx;
> -} __packed;
> -
> -struct video_output_situation {
> -	u8 active;
> -	u32 vram_offset;
> -	u8 depth_bits;
> -	u32 width_pixels;
> -	u32 height_pixels;
> -	u32 pitch_bytes;
> -} __packed;
> -
> -struct synthvid_situation_update {
> -	u64 user_ctx;
> -	u8 video_output_count;
> -	struct video_output_situation video_output[1];
> -} __packed;
> -
> -struct synthvid_situation_update_ack {
> -	u64 user_ctx;
> -} __packed;
> -
> -struct synthvid_pointer_position {
> -	u8 is_visible;
> -	u8 video_output;
> -	s32 image_x;
> -	s32 image_y;
> -} __packed;
> -
> -
> -#define CURSOR_MAX_X 96
> -#define CURSOR_MAX_Y 96
> -#define CURSOR_ARGB_PIXEL_SIZE 4
> -#define CURSOR_MAX_SIZE (CURSOR_MAX_X * CURSOR_MAX_Y * CURSOR_ARGB_PIXEL_SIZE)
> -#define CURSOR_COMPLETE (-1)
> -
> -struct synthvid_pointer_shape {
> -	u8 part_idx;
> -	u8 is_argb;
> -	u32 width; /* CURSOR_MAX_X at most */
> -	u32 height; /* CURSOR_MAX_Y at most */
> -	u32 hot_x; /* hotspot relative to upper-left of pointer image */
> -	u32 hot_y;
> -	u8 data[4];
> -} __packed;
> -
> -struct synthvid_feature_change {
> -	u8 is_dirt_needed;
> -	u8 is_ptr_pos_needed;
> -	u8 is_ptr_shape_needed;
> -	u8 is_situ_needed;
> -} __packed;
> -
> -struct rect {
> -	s32 x1, y1; /* top left corner */
> -	s32 x2, y2; /* bottom right corner, exclusive */
> -} __packed;
> -
> -struct synthvid_dirt {
> -	u8 video_output;
> -	u8 dirt_count;
> -	struct rect rect[1];
> -} __packed;
> -
> -struct synthvid_msg {
> -	struct pipe_msg_hdr pipe_hdr;
> -	struct synthvid_msg_hdr vid_hdr;
> -	union {
> -		struct synthvid_version_req ver_req;
> -		struct synthvid_version_resp ver_resp;
> -		struct synthvid_vram_location vram;
> -		struct synthvid_vram_location_ack vram_ack;
> -		struct synthvid_situation_update situ;
> -		struct synthvid_situation_update_ack situ_ack;
> -		struct synthvid_pointer_position ptr_pos;
> -		struct synthvid_pointer_shape ptr_shape;
> -		struct synthvid_feature_change feature_chg;
> -		struct synthvid_dirt dirt;
> -		struct synthvid_supported_resolution_req resolution_req;
> -		struct synthvid_supported_resolution_resp resolution_resp;
> -	};
> -} __packed;
> -
> -
> -/* FB driver definitions and structures */
> -#define HVFB_WIDTH 1152 /* default screen width */
> -#define HVFB_HEIGHT 864 /* default screen height */
> -#define HVFB_WIDTH_MIN 640
> -#define HVFB_HEIGHT_MIN 480
> -
> -#define RING_BUFSIZE (256 * 1024)
> -#define VSP_TIMEOUT (10 * HZ)
> -#define HVFB_UPDATE_DELAY (HZ / 20)
> -#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
> -
> -struct hvfb_par {
> -	struct fb_info *info;
> -	struct resource *mem;
> -	bool fb_ready; /* fb device is ready */
> -	struct completion wait;
> -	u32 synthvid_version;
> -
> -	struct delayed_work dwork;
> -	bool update;
> -	bool update_saved; /* The value of 'update' before hibernation */
> -
> -	u32 pseudo_palette[16];
> -	u8 init_buf[MAX_VMBUS_PKT_SIZE];
> -	u8 recv_buf[MAX_VMBUS_PKT_SIZE];
> -
> -	/* If true, the VSC notifies the VSP on every framebuffer change */
> -	bool synchronous_fb;
> -
> -	/* If true, need to copy from deferred IO mem to framebuffer mem */
> -	bool need_docopy;
> -
> -	struct notifier_block hvfb_panic_nb;
> -
> -	/* Memory for deferred IO and frame buffer itself */
> -	unsigned char *dio_vp;
> -	unsigned char *mmio_vp;
> -	phys_addr_t mmio_pp;
> -
> -	/* Dirty rectangle, protected by delayed_refresh_lock */
> -	int x1, y1, x2, y2;
> -	bool delayed_refresh;
> -	spinlock_t delayed_refresh_lock;
> -};
> -
> -static uint screen_width = HVFB_WIDTH;
> -static uint screen_height = HVFB_HEIGHT;
> -static uint screen_depth;
> -static uint screen_fb_size;
> -static uint dio_fb_size; /* FB size for deferred IO */
> -
> -static void hvfb_putmem(struct fb_info *info);
> -
> -/* Send message to Hyper-V host */
> -static inline int synthvid_send(struct hv_device *hdev,
> -				struct synthvid_msg *msg)
> -{
> -	static atomic64_t request_id = ATOMIC64_INIT(0);
> -	int ret;
> -
> -	msg->pipe_hdr.type = PIPE_MSG_DATA;
> -	msg->pipe_hdr.size = msg->vid_hdr.size;
> -
> -	ret = vmbus_sendpacket(hdev->channel, msg,
> -			       msg->vid_hdr.size + sizeof(struct pipe_msg_hdr),
> -			       atomic64_inc_return(&request_id),
> -			       VM_PKT_DATA_INBAND, 0);
> -
> -	if (ret)
> -		pr_err_ratelimited("Unable to send packet via vmbus; error %d\n", ret);
> -
> -	return ret;
> -}
> -
> -
> -/* Send screen resolution info to host */
> -static int synthvid_send_situ(struct hv_device *hdev)
> -{
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct synthvid_msg msg;
> -
> -	if (!info)
> -		return -ENODEV;
> -
> -	memset(&msg, 0, sizeof(struct synthvid_msg));
> -
> -	msg.vid_hdr.type = SYNTHVID_SITUATION_UPDATE;
> -	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
> -		sizeof(struct synthvid_situation_update);
> -	msg.situ.user_ctx = 0;
> -	msg.situ.video_output_count = 1;
> -	msg.situ.video_output[0].active = 1;
> -	msg.situ.video_output[0].vram_offset = 0;
> -	msg.situ.video_output[0].depth_bits = info->var.bits_per_pixel;
> -	msg.situ.video_output[0].width_pixels = info->var.xres;
> -	msg.situ.video_output[0].height_pixels = info->var.yres;
> -	msg.situ.video_output[0].pitch_bytes = info->fix.line_length;
> -
> -	synthvid_send(hdev, &msg);
> -
> -	return 0;
> -}
> -
> -/* Send mouse pointer info to host */
> -static int synthvid_send_ptr(struct hv_device *hdev)
> -{
> -	struct synthvid_msg msg;
> -
> -	memset(&msg, 0, sizeof(struct synthvid_msg));
> -	msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
> -	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
> -		sizeof(struct synthvid_pointer_position);
> -	msg.ptr_pos.is_visible = 1;
> -	msg.ptr_pos.video_output = 0;
> -	msg.ptr_pos.image_x = 0;
> -	msg.ptr_pos.image_y = 0;
> -	synthvid_send(hdev, &msg);
> -
> -	memset(&msg, 0, sizeof(struct synthvid_msg));
> -	msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE;
> -	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
> -		sizeof(struct synthvid_pointer_shape);
> -	msg.ptr_shape.part_idx = CURSOR_COMPLETE;
> -	msg.ptr_shape.is_argb = 1;
> -	msg.ptr_shape.width = 1;
> -	msg.ptr_shape.height = 1;
> -	msg.ptr_shape.hot_x = 0;
> -	msg.ptr_shape.hot_y = 0;
> -	msg.ptr_shape.data[0] = 0;
> -	msg.ptr_shape.data[1] = 1;
> -	msg.ptr_shape.data[2] = 1;
> -	msg.ptr_shape.data[3] = 1;
> -	synthvid_send(hdev, &msg);
> -
> -	return 0;
> -}
> -
> -/* Send updated screen area (dirty rectangle) location to host */
> -static int
> -synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
> -{
> -	struct hv_device *hdev = device_to_hv_device(info->device);
> -	struct synthvid_msg msg;
> -
> -	memset(&msg, 0, sizeof(struct synthvid_msg));
> -	if (x2 == INT_MAX)
> -		x2 = info->var.xres;
> -	if (y2 == INT_MAX)
> -		y2 = info->var.yres;
> -
> -	msg.vid_hdr.type = SYNTHVID_DIRT;
> -	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
> -		sizeof(struct synthvid_dirt);
> -	msg.dirt.video_output = 0;
> -	msg.dirt.dirt_count = 1;
> -	msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
> -	msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
> -	msg.dirt.rect[0].x2 =
> -		(x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
> -	msg.dirt.rect[0].y2 =
> -		(y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
> -
> -	synthvid_send(hdev, &msg);
> -
> -	return 0;
> -}
> -
> -static void hvfb_docopy(struct hvfb_par *par,
> -			unsigned long offset,
> -			unsigned long size)
> -{
> -	if (!par || !par->mmio_vp || !par->dio_vp || !par->fb_ready ||
> -	    size == 0 || offset >= dio_fb_size)
> -		return;
> -
> -	if (offset + size > dio_fb_size)
> -		size = dio_fb_size - offset;
> -
> -	memcpy(par->mmio_vp + offset, par->dio_vp + offset, size);
> -}
> -
> -/* Deferred IO callback */
> -static void synthvid_deferred_io(struct fb_info *p, struct list_head *pagereflist)
> -{
> -	struct hvfb_par *par = p->par;
> -	struct fb_deferred_io_pageref *pageref;
> -	unsigned long start, end;
> -	int y1, y2, miny, maxy;
> -
> -	miny = INT_MAX;
> -	maxy = 0;
> -
> -	/*
> -	 * Merge dirty pages. It is possible that last page cross
> -	 * over the end of frame buffer row yres. This is taken care of
> -	 * in synthvid_update function by clamping the y2
> -	 * value to yres.
> -	 */
> -	list_for_each_entry(pageref, pagereflist, list) {
> -		start = pageref->offset;
> -		end = start + PAGE_SIZE - 1;
> -		y1 = start / p->fix.line_length;
> -		y2 = end / p->fix.line_length;
> -		miny = min_t(int, miny, y1);
> -		maxy = max_t(int, maxy, y2);
> -
> -		/* Copy from dio space to mmio address */
> -		if (par->fb_ready && par->need_docopy)
> -			hvfb_docopy(par, start, PAGE_SIZE);
> -	}
> -
> -	if (par->fb_ready && par->update)
> -		synthvid_update(p, 0, miny, p->var.xres, maxy + 1);
> -}
> -
> -static struct fb_deferred_io synthvid_defio = {
> -	.delay		= HZ / 20,
> -	.deferred_io	= synthvid_deferred_io,
> -};
> -
> -/*
> - * Actions on received messages from host:
> - * Complete the wait event.
> - * Or, reply with screen and cursor info.
> - */
> -static void synthvid_recv_sub(struct hv_device *hdev)
> -{
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct hvfb_par *par;
> -	struct synthvid_msg *msg;
> -
> -	if (!info)
> -		return;
> -
> -	par = info->par;
> -	msg = (struct synthvid_msg *)par->recv_buf;
> -
> -	/* Complete the wait event */
> -	if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
> -	    msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
> -	    msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
> -		memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
> -		complete(&par->wait);
> -		return;
> -	}
> -
> -	/* Reply with screen and cursor info */
> -	if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) {
> -		if (par->fb_ready) {
> -			synthvid_send_ptr(hdev);
> -			synthvid_send_situ(hdev);
> -		}
> -
> -		par->update = msg->feature_chg.is_dirt_needed;
> -		if (par->update)
> -			schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
> -	}
> -}
> -
> -/* Receive callback for messages from the host */
> -static void synthvid_receive(void *ctx)
> -{
> -	struct hv_device *hdev = ctx;
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct hvfb_par *par;
> -	struct synthvid_msg *recv_buf;
> -	u32 bytes_recvd;
> -	u64 req_id;
> -	int ret;
> -
> -	if (!info)
> -		return;
> -
> -	par = info->par;
> -	recv_buf = (struct synthvid_msg *)par->recv_buf;
> -
> -	do {
> -		ret = vmbus_recvpacket(hdev->channel, recv_buf,
> -				       MAX_VMBUS_PKT_SIZE,
> -				       &bytes_recvd, &req_id);
> -		if (bytes_recvd > 0 &&
> -		    recv_buf->pipe_hdr.type == PIPE_MSG_DATA)
> -			synthvid_recv_sub(hdev);
> -	} while (bytes_recvd > 0 && ret == 0);
> -}
> -
> -/* Check if the ver1 version is equal or greater than ver2 */
> -static inline bool synthvid_ver_ge(u32 ver1, u32 ver2)
> -{
> -	if (SYNTHVID_VER_GET_MAJOR(ver1) > SYNTHVID_VER_GET_MAJOR(ver2) ||
> -	    (SYNTHVID_VER_GET_MAJOR(ver1) == SYNTHVID_VER_GET_MAJOR(ver2) &&
> -	     SYNTHVID_VER_GET_MINOR(ver1) >= SYNTHVID_VER_GET_MINOR(ver2)))
> -		return true;
> -
> -	return false;
> -}
> -
> -/* Check synthetic video protocol version with the host */
> -static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)
> -{
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct hvfb_par *par = info->par;
> -	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
> -	int ret = 0;
> -	unsigned long t;
> -
> -	memset(msg, 0, sizeof(struct synthvid_msg));
> -	msg->vid_hdr.type = SYNTHVID_VERSION_REQUEST;
> -	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
> -		sizeof(struct synthvid_version_req);
> -	msg->ver_req.version = ver;
> -	synthvid_send(hdev, msg);
> -
> -	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
> -	if (!t) {
> -		pr_err("Time out on waiting version response\n");
> -		ret = -ETIMEDOUT;
> -		goto out;
> -	}
> -	if (!msg->ver_resp.is_accepted) {
> -		ret = -ENODEV;
> -		goto out;
> -	}
> -
> -	par->synthvid_version = ver;
> -	pr_info("Synthvid Version major %d, minor %d\n",
> -		SYNTHVID_VER_GET_MAJOR(ver), SYNTHVID_VER_GET_MINOR(ver));
> -
> -out:
> -	return ret;
> -}
> -
> -/* Get current resolution from the host */
> -static int synthvid_get_supported_resolution(struct hv_device *hdev)
> -{
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct hvfb_par *par = info->par;
> -	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
> -	int ret = 0;
> -	unsigned long t;
> -	u8 index;
> -
> -	memset(msg, 0, sizeof(struct synthvid_msg));
> -	msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST;
> -	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
> -		sizeof(struct synthvid_supported_resolution_req);
> -
> -	msg->resolution_req.maximum_resolution_count =
> -		SYNTHVID_MAX_RESOLUTION_COUNT;
> -	synthvid_send(hdev, msg);
> -
> -	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
> -	if (!t) {
> -		pr_err("Time out on waiting resolution response\n");
> -		ret = -ETIMEDOUT;
> -		goto out;
> -	}
> -
> -	if (msg->resolution_resp.resolution_count == 0) {
> -		pr_err("No supported resolutions\n");
> -		ret = -ENODEV;
> -		goto out;
> -	}
> -
> -	index = msg->resolution_resp.default_resolution_index;
> -	if (index >= msg->resolution_resp.resolution_count) {
> -		pr_err("Invalid resolution index: %d\n", index);
> -		ret = -ENODEV;
> -		goto out;
> -	}
> -
> -	screen_width =
> -		msg->resolution_resp.supported_resolution[index].width;
> -	screen_height =
> -		msg->resolution_resp.supported_resolution[index].height;
> -
> -out:
> -	return ret;
> -}
> -
> -/* Connect to VSP (Virtual Service Provider) on host */
> -static int synthvid_connect_vsp(struct hv_device *hdev)
> -{
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct hvfb_par *par = info->par;
> -	int ret;
> -
> -	ret = vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE,
> -			 NULL, 0, synthvid_receive, hdev);
> -	if (ret) {
> -		pr_err("Unable to open vmbus channel\n");
> -		return ret;
> -	}
> -
> -	/* Negotiate the protocol version with host */
> -	switch (vmbus_proto_version) {
> -	case VERSION_WIN10:
> -	case VERSION_WIN10_V5:
> -		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
> -		if (!ret)
> -			break;
> -		fallthrough;
> -	case VERSION_WIN8:
> -	case VERSION_WIN8_1:
> -		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
> -		break;
> -	default:
> -		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
> -		break;
> -	}
> -
> -	if (ret) {
> -		pr_err("Synthetic video device version not accepted\n");
> -		goto error;
> -	}
> -
> -	screen_depth = SYNTHVID_DEPTH_WIN8;
> -	if (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10)) {
> -		ret = synthvid_get_supported_resolution(hdev);
> -		if (ret)
> -			pr_info("Failed to get supported resolution from host, use default\n");
> -	}
> -
> -	screen_fb_size = hdev->channel->offermsg.offer.
> -				mmio_megabytes * 1024 * 1024;
> -
> -	return 0;
> -
> -error:
> -	vmbus_close(hdev->channel);
> -	return ret;
> -}
> -
> -/* Send VRAM and Situation messages to the host */
> -static int synthvid_send_config(struct hv_device *hdev)
> -{
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct hvfb_par *par = info->par;
> -	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
> -	int ret = 0;
> -	unsigned long t;
> -
> -	/* Send VRAM location */
> -	memset(msg, 0, sizeof(struct synthvid_msg));
> -	msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
> -	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
> -		sizeof(struct synthvid_vram_location);
> -	msg->vram.user_ctx = msg->vram.vram_gpa = par->mmio_pp;
> -	msg->vram.is_vram_gpa_specified = 1;
> -	synthvid_send(hdev, msg);
> -
> -	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
> -	if (!t) {
> -		pr_err("Time out on waiting vram location ack\n");
> -		ret = -ETIMEDOUT;
> -		goto out;
> -	}
> -	if (msg->vram_ack.user_ctx != par->mmio_pp) {
> -		pr_err("Unable to set VRAM location\n");
> -		ret = -ENODEV;
> -		goto out;
> -	}
> -
> -	/* Send pointer and situation update */
> -	synthvid_send_ptr(hdev);
> -	synthvid_send_situ(hdev);
> -
> -out:
> -	return ret;
> -}
> -
> -
> -/*
> - * Delayed work callback:
> - * It is scheduled to call whenever update request is received and it has
> - * not been called in last HVFB_ONDEMAND_THROTTLE time interval.
> - */
> -static void hvfb_update_work(struct work_struct *w)
> -{
> -	struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);
> -	struct fb_info *info = par->info;
> -	unsigned long flags;
> -	int x1, x2, y1, y2;
> -	int j;
> -
> -	spin_lock_irqsave(&par->delayed_refresh_lock, flags);
> -	/* Reset the request flag */
> -	par->delayed_refresh = false;
> -
> -	/* Store the dirty rectangle to local variables */
> -	x1 = par->x1;
> -	x2 = par->x2;
> -	y1 = par->y1;
> -	y2 = par->y2;
> -
> -	/* Clear dirty rectangle */
> -	par->x1 = par->y1 = INT_MAX;
> -	par->x2 = par->y2 = 0;
> -
> -	spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
> -
> -	if (x1 > info->var.xres || x2 > info->var.xres ||
> -	    y1 > info->var.yres || y2 > info->var.yres || x2 <= x1)
> -		return;
> -
> -	/* Copy the dirty rectangle to frame buffer memory */
> -	if (par->need_docopy)
> -		for (j = y1; j < y2; j++)
> -			hvfb_docopy(par,
> -				    j * info->fix.line_length +
> -				    (x1 * screen_depth / 8),
> -				    (x2 - x1) * screen_depth / 8);
> -
> -	/* Refresh */
> -	if (par->fb_ready && par->update)
> -		synthvid_update(info, x1, y1, x2, y2);
> -}
> -
> -/*
> - * Control the on-demand refresh frequency. It schedules a delayed
> - * screen update if it has not yet.
> - */
> -static void hvfb_ondemand_refresh_throttle(struct hvfb_par *par,
> -					   int x1, int y1, int w, int h)
> -{
> -	unsigned long flags;
> -	int x2 = x1 + w;
> -	int y2 = y1 + h;
> -
> -	spin_lock_irqsave(&par->delayed_refresh_lock, flags);
> -
> -	/* Merge dirty rectangle */
> -	par->x1 = min_t(int, par->x1, x1);
> -	par->y1 = min_t(int, par->y1, y1);
> -	par->x2 = max_t(int, par->x2, x2);
> -	par->y2 = max_t(int, par->y2, y2);
> -
> -	/* Schedule a delayed screen update if not yet */
> -	if (par->delayed_refresh == false) {
> -		schedule_delayed_work(&par->dwork,
> -				      HVFB_ONDEMAND_THROTTLE);
> -		par->delayed_refresh = true;
> -	}
> -
> -	spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
> -}
> -
> -static int hvfb_on_panic(struct notifier_block *nb,
> -			 unsigned long e, void *p)
> -{
> -	struct hv_device *hdev;
> -	struct hvfb_par *par;
> -	struct fb_info *info;
> -
> -	par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
> -	info = par->info;
> -	hdev = device_to_hv_device(info->device);
> -
> -	if (hv_ringbuffer_spinlock_busy(hdev->channel))
> -		return NOTIFY_DONE;
> -
> -	par->synchronous_fb = true;
> -	if (par->need_docopy)
> -		hvfb_docopy(par, 0, dio_fb_size);
> -	synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
> -
> -	return NOTIFY_DONE;
> -}
> -
> -/* Framebuffer operation handlers */
> -
> -static int hvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
> -{
> -	if (var->xres < HVFB_WIDTH_MIN || var->yres < HVFB_HEIGHT_MIN ||
> -	    var->xres > screen_width || var->yres >  screen_height ||
> -	    var->bits_per_pixel != screen_depth)
> -		return -EINVAL;
> -
> -	var->xres_virtual = var->xres;
> -	var->yres_virtual = var->yres;
> -
> -	return 0;
> -}
> -
> -static int hvfb_set_par(struct fb_info *info)
> -{
> -	struct hv_device *hdev = device_to_hv_device(info->device);
> -
> -	return synthvid_send_situ(hdev);
> -}
> -
> -
> -static inline u32 chan_to_field(u32 chan, struct fb_bitfield *bf)
> -{
> -	return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
> -}
> -
> -static int hvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
> -			  unsigned blue, unsigned transp, struct fb_info *info)
> -{
> -	u32 *pal = info->pseudo_palette;
> -
> -	if (regno > 15)
> -		return -EINVAL;
> -
> -	pal[regno] = chan_to_field(red, &info->var.red)
> -		| chan_to_field(green, &info->var.green)
> -		| chan_to_field(blue, &info->var.blue)
> -		| chan_to_field(transp, &info->var.transp);
> -
> -	return 0;
> -}
> -
> -static int hvfb_blank(int blank, struct fb_info *info)
> -{
> -	return 1;	/* get fb_blank to set the colormap to all black */
> -}
> -
> -static void hvfb_ops_damage_range(struct fb_info *info, off_t off, size_t len)
> -{
> -	/* TODO: implement damage handling */
> -}
> -
> -static void hvfb_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height)
> -{
> -	struct hvfb_par *par = info->par;
> -
> -	if (par->synchronous_fb)
> -		synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
> -	else
> -		hvfb_ondemand_refresh_throttle(par, x, y, width, height);
> -}
> -
> -/*
> - * fb_ops.fb_destroy is called by the last put_fb_info() call at the end
> - * of unregister_framebuffer() or fb_release(). Do any cleanup related to
> - * framebuffer here.
> - */
> -static void hvfb_destroy(struct fb_info *info)
> -{
> -	hvfb_putmem(info);
> -	framebuffer_release(info);
> -}
> -
> -/*
> - * TODO: GEN1 codepaths allocate from system or DMA-able memory. Fix the
> - *       driver to use the _SYSMEM_ or _DMAMEM_ helpers in these cases.
> - */
> -FB_GEN_DEFAULT_DEFERRED_IOMEM_OPS(hvfb_ops,
> -				  hvfb_ops_damage_range,
> -				  hvfb_ops_damage_area)
> -
> -static const struct fb_ops hvfb_ops = {
> -	.owner = THIS_MODULE,
> -	FB_DEFAULT_DEFERRED_OPS(hvfb_ops),
> -	.fb_check_var = hvfb_check_var,
> -	.fb_set_par = hvfb_set_par,
> -	.fb_setcolreg = hvfb_setcolreg,
> -	.fb_blank = hvfb_blank,
> -	.fb_destroy	= hvfb_destroy,
> -};
> -
> -/* Get options from kernel paramenter "video=" */
> -static void hvfb_get_option(struct fb_info *info)
> -{
> -	struct hvfb_par *par = info->par;
> -	char *opt = NULL, *p;
> -	uint x = 0, y = 0;
> -
> -	if (fb_get_options(KBUILD_MODNAME, &opt) || !opt || !*opt)
> -		return;
> -
> -	p = strsep(&opt, "x");
> -	if (!*p || kstrtouint(p, 0, &x) ||
> -	    !opt || !*opt || kstrtouint(opt, 0, &y)) {
> -		pr_err("Screen option is invalid: skipped\n");
> -		return;
> -	}
> -
> -	if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
> -	    (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) &&
> -	    (x * y * screen_depth / 8 > screen_fb_size)) ||
> -	    (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
> -	     x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8)) {
> -		pr_err("Screen resolution option is out of range: skipped\n");
> -		return;
> -	}
> -
> -	screen_width = x;
> -	screen_height = y;
> -	return;
> -}
> -
> -/*
> - * Allocate enough contiguous physical memory.
> - * Return physical address if succeeded or -1 if failed.
> - */
> -static phys_addr_t hvfb_get_phymem(struct hv_device *hdev,
> -				   unsigned int request_size)
> -{
> -	struct page *page = NULL;
> -	dma_addr_t dma_handle;
> -	void *vmem;
> -	phys_addr_t paddr = 0;
> -	unsigned int order = get_order(request_size);
> -
> -	if (request_size == 0)
> -		return -1;
> -
> -	if (order <= MAX_PAGE_ORDER) {
> -		/* Call alloc_pages if the size is less than 2^MAX_PAGE_ORDER */
> -		page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
> -		if (!page)
> -			return -1;
> -
> -		paddr = (page_to_pfn(page) << PAGE_SHIFT);
> -	} else {
> -		/* Allocate from CMA */
> -		hdev->device.coherent_dma_mask = DMA_BIT_MASK(64);
> -
> -		vmem = dma_alloc_coherent(&hdev->device,
> -					  round_up(request_size, PAGE_SIZE),
> -					  &dma_handle,
> -					  GFP_KERNEL | __GFP_NOWARN);
> -
> -		if (!vmem)
> -			return -1;
> -
> -		paddr = virt_to_phys(vmem);
> -	}
> -
> -	return paddr;
> -}
> -
> -/* Release contiguous physical memory */
> -static void hvfb_release_phymem(struct device *device,
> -				phys_addr_t paddr, unsigned int size)
> -{
> -	unsigned int order = get_order(size);
> -
> -	if (order <= MAX_PAGE_ORDER)
> -		__free_pages(pfn_to_page(paddr >> PAGE_SHIFT), order);
> -	else
> -		dma_free_coherent(device,
> -				  round_up(size, PAGE_SIZE),
> -				  phys_to_virt(paddr),
> -				  paddr);
> -}
> -
> -
> -/* Get framebuffer memory from Hyper-V video pci space */
> -static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
> -{
> -	struct hvfb_par *par = info->par;
> -	struct pci_dev *pdev  = NULL;
> -	void __iomem *fb_virt;
> -	int gen2vm = efi_enabled(EFI_BOOT);
> -	resource_size_t base = 0;
> -	resource_size_t size = 0;
> -	phys_addr_t paddr;
> -	int ret;
> -
> -	if (!gen2vm) {
> -		pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
> -			PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
> -		if (!pdev) {
> -			pr_err("Unable to find PCI Hyper-V video\n");
> -			return -ENODEV;
> -		}
> -
> -		base = pci_resource_start(pdev, 0);
> -		size = pci_resource_len(pdev, 0);
> -		aperture_remove_conflicting_devices(base, size, KBUILD_MODNAME);
> -
> -		/*
> -		 * For Gen 1 VM, we can directly use the contiguous memory
> -		 * from VM. If we succeed, deferred IO happens directly
> -		 * on this allocated framebuffer memory, avoiding extra
> -		 * memory copy.
> -		 */
> -		paddr = hvfb_get_phymem(hdev, screen_fb_size);
> -		if (paddr != (phys_addr_t) -1) {
> -			par->mmio_pp = paddr;
> -			par->mmio_vp = par->dio_vp = __va(paddr);
> -
> -			info->fix.smem_start = paddr;
> -			info->fix.smem_len = screen_fb_size;
> -			info->screen_base = par->mmio_vp;
> -			info->screen_size = screen_fb_size;
> -
> -			par->need_docopy = false;
> -			goto getmem_done;
> -		}
> -		pr_info("Unable to allocate enough contiguous physical memory on Gen 1 VM. Using MMIO instead.\n");
> -	} else {
> -		aperture_remove_all_conflicting_devices(KBUILD_MODNAME);
> -	}
> -
> -	/*
> -	 * Cannot use contiguous physical memory, so allocate MMIO space for
> -	 * the framebuffer. At this point in the function, conflicting devices
> -	 * that might have claimed the framebuffer MMIO space based on
> -	 * screen_info.lfb_base must have already been removed so that
> -	 * vmbus_allocate_mmio() does not allocate different MMIO space. If the
> -	 * kdump image were to be loaded using kexec_file_load(), the
> -	 * framebuffer location in the kdump image would be set from
> -	 * screen_info.lfb_base at the time that kdump is enabled. If the
> -	 * framebuffer has moved elsewhere, this could be the wrong location,
> -	 * causing kdump to hang when efifb (for example) loads.
> -	 */
> -	dio_fb_size =
> -		screen_width * screen_height * screen_depth / 8;
> -
> -	ret = vmbus_allocate_mmio(&par->mem, hdev, 0, -1,
> -				  screen_fb_size, 0x100000, true);
> -	if (ret != 0) {
> -		pr_err("Unable to allocate framebuffer memory\n");
> -		goto err1;
> -	}
> -
> -	/*
> -	 * Map the VRAM cacheable for performance. This is also required for
> -	 * VM Connect to display properly for ARM64 Linux VM, as the host also
> -	 * maps the VRAM cacheable.
> -	 */
> -	fb_virt = ioremap_cache(par->mem->start, screen_fb_size);
> -	if (!fb_virt)
> -		goto err2;
> -
> -	/* Allocate memory for deferred IO */
> -	par->dio_vp = vzalloc(round_up(dio_fb_size, PAGE_SIZE));
> -	if (par->dio_vp == NULL)
> -		goto err3;
> -
> -	/* Physical address of FB device */
> -	par->mmio_pp = par->mem->start;
> -	/* Virtual address of FB device */
> -	par->mmio_vp = (unsigned char *) fb_virt;
> -
> -	info->fix.smem_start = par->mem->start;
> -	info->fix.smem_len = dio_fb_size;
> -	info->screen_base = par->dio_vp;
> -	info->screen_size = dio_fb_size;
> -
> -getmem_done:
> -	if (!gen2vm)
> -		pci_dev_put(pdev);
> -
> -	return 0;
> -
> -err3:
> -	iounmap(fb_virt);
> -err2:
> -	vmbus_free_mmio(par->mem->start, screen_fb_size);
> -	par->mem = NULL;
> -err1:
> -	if (!gen2vm)
> -		pci_dev_put(pdev);
> -
> -	return -ENOMEM;
> -}
> -
> -/* Release the framebuffer */
> -static void hvfb_putmem(struct fb_info *info)
> -{
> -	struct hvfb_par *par = info->par;
> -
> -	if (par->need_docopy) {
> -		vfree(par->dio_vp);
> -		iounmap(par->mmio_vp);
> -		vmbus_free_mmio(par->mem->start, screen_fb_size);
> -	} else {
> -		hvfb_release_phymem(info->device, info->fix.smem_start,
> -				    screen_fb_size);
> -	}
> -
> -	par->mem = NULL;
> -}
> -
> -
> -static int hvfb_probe(struct hv_device *hdev,
> -		      const struct hv_vmbus_device_id *dev_id)
> -{
> -	struct fb_info *info;
> -	struct hvfb_par *par;
> -	int ret;
> -
> -	info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device);
> -	if (!info)
> -		return -ENOMEM;
> -
> -	par = info->par;
> -	par->info = info;
> -	par->fb_ready = false;
> -	par->need_docopy = true;
> -	init_completion(&par->wait);
> -	INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);
> -
> -	par->delayed_refresh = false;
> -	spin_lock_init(&par->delayed_refresh_lock);
> -	par->x1 = par->y1 = INT_MAX;
> -	par->x2 = par->y2 = 0;
> -
> -	/* Connect to VSP */
> -	hv_set_drvdata(hdev, info);
> -	ret = synthvid_connect_vsp(hdev);
> -	if (ret) {
> -		pr_err("Unable to connect to VSP\n");
> -		goto error1;
> -	}
> -
> -	hvfb_get_option(info);
> -	pr_info("Screen resolution: %dx%d, Color depth: %d, Frame buffer size: %d\n",
> -		screen_width, screen_height, screen_depth, screen_fb_size);
> -
> -	ret = hvfb_getmem(hdev, info);
> -	if (ret) {
> -		pr_err("No memory for framebuffer\n");
> -		goto error2;
> -	}
> -
> -	/* Set up fb_info */
> -	info->var.xres_virtual = info->var.xres = screen_width;
> -	info->var.yres_virtual = info->var.yres = screen_height;
> -	info->var.bits_per_pixel = screen_depth;
> -
> -	if (info->var.bits_per_pixel == 16) {
> -		info->var.red = (struct fb_bitfield){11, 5, 0};
> -		info->var.green = (struct fb_bitfield){5, 6, 0};
> -		info->var.blue = (struct fb_bitfield){0, 5, 0};
> -		info->var.transp = (struct fb_bitfield){0, 0, 0};
> -	} else {
> -		info->var.red = (struct fb_bitfield){16, 8, 0};
> -		info->var.green = (struct fb_bitfield){8, 8, 0};
> -		info->var.blue = (struct fb_bitfield){0, 8, 0};
> -		info->var.transp = (struct fb_bitfield){24, 8, 0};
> -	}
> -
> -	info->var.activate = FB_ACTIVATE_NOW;
> -	info->var.height = -1;
> -	info->var.width = -1;
> -	info->var.vmode = FB_VMODE_NONINTERLACED;
> -
> -	strcpy(info->fix.id, KBUILD_MODNAME);
> -	info->fix.type = FB_TYPE_PACKED_PIXELS;
> -	info->fix.visual = FB_VISUAL_TRUECOLOR;
> -	info->fix.line_length = screen_width * screen_depth / 8;
> -	info->fix.accel = FB_ACCEL_NONE;
> -
> -	info->fbops = &hvfb_ops;
> -	info->pseudo_palette = par->pseudo_palette;
> -
> -	/* Initialize deferred IO */
> -	info->fbdefio = &synthvid_defio;
> -	fb_deferred_io_init(info);
> -
> -	/* Send config to host */
> -	ret = synthvid_send_config(hdev);
> -	if (ret)
> -		goto error;
> -
> -	ret = devm_register_framebuffer(&hdev->device, info);
> -	if (ret) {
> -		pr_err("Unable to register framebuffer\n");
> -		goto error;
> -	}
> -
> -	par->fb_ready = true;
> -
> -	par->synchronous_fb = false;
> -
> -	/*
> -	 * We need to be sure this panic notifier runs _before_ the
> -	 * vmbus disconnect, so order it by priority. It must execute
> -	 * before the function hv_panic_vmbus_unload() [drivers/hv/vmbus_drv.c],
> -	 * which is almost at the end of list, with priority = INT_MIN + 1.
> -	 */
> -	par->hvfb_panic_nb.notifier_call = hvfb_on_panic;
> -	par->hvfb_panic_nb.priority = INT_MIN + 10;
> -	atomic_notifier_chain_register(&panic_notifier_list,
> -				       &par->hvfb_panic_nb);
> -
> -	return 0;
> -
> -error:
> -	fb_deferred_io_cleanup(info);
> -	hvfb_putmem(info);
> -error2:
> -	vmbus_close(hdev->channel);
> -error1:
> -	cancel_delayed_work_sync(&par->dwork);
> -	hv_set_drvdata(hdev, NULL);
> -	framebuffer_release(info);
> -	return ret;
> -}
> -
> -static void hvfb_remove(struct hv_device *hdev)
> -{
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct hvfb_par *par = info->par;
> -
> -	atomic_notifier_chain_unregister(&panic_notifier_list,
> -					 &par->hvfb_panic_nb);
> -
> -	par->update = false;
> -	par->fb_ready = false;
> -
> -	fb_deferred_io_cleanup(info);
> -
> -	cancel_delayed_work_sync(&par->dwork);
> -
> -	vmbus_close(hdev->channel);
> -	hv_set_drvdata(hdev, NULL);
> -}
> -
> -static int hvfb_suspend(struct hv_device *hdev)
> -{
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct hvfb_par *par = info->par;
> -
> -	console_lock();
> -
> -	/* 1 means do suspend */
> -	fb_set_suspend(info, 1);
> -
> -	cancel_delayed_work_sync(&par->dwork);
> -	cancel_delayed_work_sync(&info->deferred_work);
> -
> -	par->update_saved = par->update;
> -	par->update = false;
> -	par->fb_ready = false;
> -
> -	vmbus_close(hdev->channel);
> -
> -	console_unlock();
> -
> -	return 0;
> -}
> -
> -static int hvfb_resume(struct hv_device *hdev)
> -{
> -	struct fb_info *info = hv_get_drvdata(hdev);
> -	struct hvfb_par *par = info->par;
> -	int ret;
> -
> -	console_lock();
> -
> -	ret = synthvid_connect_vsp(hdev);
> -	if (ret != 0)
> -		goto out;
> -
> -	ret = synthvid_send_config(hdev);
> -	if (ret != 0) {
> -		vmbus_close(hdev->channel);
> -		goto out;
> -	}
> -
> -	par->fb_ready = true;
> -	par->update = par->update_saved;
> -
> -	schedule_delayed_work(&info->deferred_work, info->fbdefio->delay);
> -	schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
> -
> -	/* 0 means do resume */
> -	fb_set_suspend(info, 0);
> -
> -out:
> -	console_unlock();
> -
> -	return ret;
> -}
> -
> -
> -static const struct pci_device_id pci_stub_id_table[] = {
> -	{
> -		.vendor      = PCI_VENDOR_ID_MICROSOFT,
> -		.device      = PCI_DEVICE_ID_HYPERV_VIDEO,
> -	},
> -	{ /* end of list */ }
> -};
> -
> -static const struct hv_vmbus_device_id id_table[] = {
> -	/* Synthetic Video Device GUID */
> -	{HV_SYNTHVID_GUID},
> -	{}
> -};
> -
> -MODULE_DEVICE_TABLE(pci, pci_stub_id_table);
> -MODULE_DEVICE_TABLE(vmbus, id_table);
> -
> -static struct hv_driver hvfb_drv = {
> -	.name = KBUILD_MODNAME,
> -	.id_table = id_table,
> -	.probe = hvfb_probe,
> -	.remove = hvfb_remove,
> -	.suspend = hvfb_suspend,
> -	.resume = hvfb_resume,
> -	.driver = {
> -		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> -	},
> -};
> -
> -static int hvfb_pci_stub_probe(struct pci_dev *pdev,
> -			       const struct pci_device_id *ent)
> -{
> -	return 0;
> -}
> -
> -static void hvfb_pci_stub_remove(struct pci_dev *pdev)
> -{
> -}
> -
> -static struct pci_driver hvfb_pci_stub_driver = {
> -	.name =		KBUILD_MODNAME,
> -	.id_table =	pci_stub_id_table,
> -	.probe =	hvfb_pci_stub_probe,
> -	.remove =	hvfb_pci_stub_remove,
> -	.driver = {
> -		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> -	}
> -};
> -
> -static int __init hvfb_drv_init(void)
> -{
> -	int ret;
> -
> -	if (fb_modesetting_disabled("hyper_fb"))
> -		return -ENODEV;
> -
> -	ret = vmbus_driver_register(&hvfb_drv);
> -	if (ret != 0)
> -		return ret;
> -
> -	ret = pci_register_driver(&hvfb_pci_stub_driver);
> -	if (ret != 0) {
> -		vmbus_driver_unregister(&hvfb_drv);
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -
> -static void __exit hvfb_drv_exit(void)
> -{
> -	pci_unregister_driver(&hvfb_pci_stub_driver);
> -	vmbus_driver_unregister(&hvfb_drv);
> -}
> -
> -module_init(hvfb_drv_init);
> -module_exit(hvfb_drv_exit);
> -
> -MODULE_LICENSE("GPL");
> -MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver");

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)



^ permalink raw reply

* Re: [PATCH] backlight: pwm_bl: apply the initial backlight state with sane defaults
From: Michael Grzeschik @ 2025-09-10  7:33 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Helge Deller, Pengutronix,
	linux-pwm, dri-devel, linux-fbdev, linux-kernel
In-Reply-To: <7zae3uaz5wdk2ktmg44aqdnfjglklqujtktslvlye3ssd3xvbv@qwwjiip6kgfo>

[-- Attachment #1: Type: text/plain, Size: 3533 bytes --]

Hi Uwe

On Tue, Sep 09, 2025 at 03:49:22PM +0200, Uwe Kleine-König wrote:
>On Fri, Aug 01, 2025 at 08:32:20AM +0200, Uwe Kleine-König wrote:
>> On Thu, Jul 31, 2025 at 10:47:18AM +0200, Michael Grzeschik wrote:
>> > diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
>> > index 237d3d3f3bb1a..5924e0b9f01e7 100644
>> > --- a/drivers/video/backlight/pwm_bl.c
>> > +++ b/drivers/video/backlight/pwm_bl.c
>> > @@ -518,13 +518,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
>> >  	if (!state.period && (data->pwm_period_ns > 0))
>> >  		state.period = data->pwm_period_ns;
>> >
>> > -	ret = pwm_apply_might_sleep(pb->pwm, &state);
>> > -	if (ret) {
>> > -		dev_err_probe(&pdev->dev, ret,
>> > -			      "failed to apply initial PWM state");
>> > -		goto err_alloc;
>> > -	}
>> > -
>> >  	memset(&props, 0, sizeof(struct backlight_properties));
>> >
>> >  	if (data->levels) {
>> > @@ -582,6 +575,15 @@ static int pwm_backlight_probe(struct platform_device *pdev)
>> >  	pb->lth_brightness = data->lth_brightness * (div_u64(state.period,
>> >  				pb->scale));
>> >
>> > +	state.duty_cycle = compute_duty_cycle(pb, data->dft_brightness, &state);
>> > +
>> > +	ret = pwm_apply_might_sleep(pb->pwm, &state);
>> > +	if (ret) {
>> > +		dev_err_probe(&pdev->dev, ret,
>> > +			      "failed to apply initial PWM state");
>> > +		goto err_alloc;
>> > +	}
>> > +
>>
>> I wonder why the PWM is updated at all in .probe(). Wouldn't it be the
>> natural thing to keep the PWM configured as it was (in its reset default
>> state or how the bootloader set it up)?
>>
>> Orthogonal to your change, while looking at the driver I wondered about:
>>
>>         bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
>>                                        &pwm_backlight_ops, &props);
>>         if (IS_ERR(bl)) {
>>                 ret = dev_err_probe(&pdev->dev, PTR_ERR(bl),
>>                                     "failed to register backlight\n");
>>                 goto err_alloc;
>>         }
>>
>>         if (data->dft_brightness > data->max_brightness) {
>>                 dev_warn(&pdev->dev,
>>                          "invalid default brightness level: %u, using %u\n",
>>                          data->dft_brightness, data->max_brightness);
>>                 data->dft_brightness = data->max_brightness;
>>         }
>>
>>         bl->props.brightness = data->dft_brightness;
>>         bl->props.power = pwm_backlight_initial_power_state(pb);
>>         backlight_update_status(bl);
>>
>> Shoudn't setting data->dft_brightness, bl->props.brightness and
>> bl->props.power better happen before backlight_device_register()? Also
>> calling backlight_update_status() after backlight_device_register()
>> seems wrong to me, I'd claim the backend driver shouldn't call that.
>
>Do you intend to work on this orthogonal feedback? If not, I'll put it
>on my todo list.

Oh, yes, the orthogonal feedback. Thanks for the reminder of this
actually intended patch not being ready. I will work on this first. If you
like, please take the opurtunity to fix the issue you found.

Regards,
Michael

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* [RFC 1/3] fbdev: hyperv_fb: Remove hyperv_fb driver
From: Prasanna Kumar T S M @ 2025-09-09 16:58 UTC (permalink / raw)
  To: deller, tzimmermann, arnd, soci, gonzalo.silvalde, rdunlap,
	bartosz.golaszewski, wei.liu, mhklinux, ssengar, linux-kernel,
	linux-fbdev, dri-devel, ptsm
In-Reply-To: <E2D7F2119CB4>

The Hyper-V DRM driver is available since kernel version 5.14 and
provides full KMS support along with fbdev emulation via the DRM fbdev
helpers. This makes the hyperv_fb driver redundant, remove it.

Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
---
 MAINTAINERS                     |    1 -
 drivers/video/fbdev/Kconfig     |    8 -
 drivers/video/fbdev/Makefile    |    1 -
 drivers/video/fbdev/hyperv_fb.c | 1386 -------------------------------
 4 files changed, 1396 deletions(-)
 delete mode 100644 drivers/video/fbdev/hyperv_fb.c

diff --git a/MAINTAINERS b/MAINTAINERS
index e94d68c980c5..9d0f0e929356 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11416,7 +11416,6 @@ F:	drivers/pci/controller/pci-hyperv-intf.c
 F:	drivers/pci/controller/pci-hyperv.c
 F:	drivers/scsi/storvsc_drv.c
 F:	drivers/uio/uio_hv_generic.c
-F:	drivers/video/fbdev/hyperv_fb.c
 F:	include/asm-generic/mshyperv.h
 F:	include/clocksource/hyperv_timer.h
 F:	include/hyperv/hvgdk.h
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index c21484d15f0c..bb8ac759f6aa 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1772,14 +1772,6 @@ config FB_BROADSHEET
 	  and could also have been called by other names when coupled with
 	  a bridge adapter.
 
-config FB_HYPERV
-	tristate "Microsoft Hyper-V Synthetic Video support"
-	depends on FB && HYPERV
-	select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA
-	select FB_IOMEM_HELPERS_DEFERRED
-	help
-	  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
-
 config FB_SIMPLE
 	tristate "Simple framebuffer support"
 	depends on FB
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index b3d12f977c06..36a18d958ba0 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -111,7 +111,6 @@ obj-y                             += omap2/
 obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
 obj-$(CONFIG_FB_CARMINE)          += carminefb.o
 obj-$(CONFIG_FB_MB862XX)	  += mb862xx/
-obj-$(CONFIG_FB_HYPERV)		  += hyperv_fb.o
 obj-$(CONFIG_FB_OPENCORES)	  += ocfb.o
 obj-$(CONFIG_FB_SM712)		  += sm712fb.o
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
deleted file mode 100644
index 75338ffc703f..000000000000
--- a/drivers/video/fbdev/hyperv_fb.c
+++ /dev/null
@@ -1,1386 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2012, Microsoft Corporation.
- *
- * Author:
- *   Haiyang Zhang <haiyangz@microsoft.com>
- */
-
-/*
- * Hyper-V Synthetic Video Frame Buffer Driver
- *
- * This is the driver for the Hyper-V Synthetic Video, which supports
- * screen resolution up to Full HD 1920x1080 with 32 bit color on Windows
- * Server 2012, and 1600x1200 with 16 bit color on Windows Server 2008 R2
- * or earlier.
- *
- * It also solves the double mouse cursor issue of the emulated video mode.
- *
- * The default screen resolution is 1152x864, which may be changed by a
- * kernel parameter:
- *     video=hyperv_fb:<width>x<height>
- *     For example: video=hyperv_fb:1280x1024
- *
- * Portrait orientation is also supported:
- *     For example: video=hyperv_fb:864x1152
- *
- * When a Windows 10 RS5+ host is used, the virtual machine screen
- * resolution is obtained from the host. The "video=hyperv_fb" option is
- * not needed, but still can be used to overwrite what the host specifies.
- * The VM resolution on the host could be set by executing the powershell
- * "set-vmvideo" command. For example
- *     set-vmvideo -vmname name -horizontalresolution:1920 \
- * -verticalresolution:1200 -resolutiontype single
- *
- * Gen 1 VMs also support direct using VM's physical memory for framebuffer.
- * It could improve the efficiency and performance for framebuffer and VM.
- * This requires to allocate contiguous physical memory from Linux kernel's
- * CMA memory allocator. To enable this, supply a kernel parameter to give
- * enough memory space to CMA allocator for framebuffer. For example:
- *    cma=130m
- * This gives 130MB memory to CMA allocator that can be allocated to
- * framebuffer. For reference, 8K resolution (7680x4320) takes about
- * 127MB memory.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/aperture.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/fb.h>
-#include <linux/pci.h>
-#include <linux/panic_notifier.h>
-#include <linux/efi.h>
-#include <linux/console.h>
-
-#include <linux/hyperv.h>
-
-/* Hyper-V Synthetic Video Protocol definitions and structures */
-#define MAX_VMBUS_PKT_SIZE 0x4000
-
-#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
-/* Support for VERSION_WIN7 is removed. #define is retained for reference. */
-#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
-#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
-#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
-
-#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
-#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
-
-#define SYNTHVID_DEPTH_WIN8 32
-#define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
-
-enum pipe_msg_type {
-	PIPE_MSG_INVALID,
-	PIPE_MSG_DATA,
-	PIPE_MSG_MAX
-};
-
-struct pipe_msg_hdr {
-	u32 type;
-	u32 size; /* size of message after this field */
-} __packed;
-
-
-enum synthvid_msg_type {
-	SYNTHVID_ERROR			= 0,
-	SYNTHVID_VERSION_REQUEST	= 1,
-	SYNTHVID_VERSION_RESPONSE	= 2,
-	SYNTHVID_VRAM_LOCATION		= 3,
-	SYNTHVID_VRAM_LOCATION_ACK	= 4,
-	SYNTHVID_SITUATION_UPDATE	= 5,
-	SYNTHVID_SITUATION_UPDATE_ACK	= 6,
-	SYNTHVID_POINTER_POSITION	= 7,
-	SYNTHVID_POINTER_SHAPE		= 8,
-	SYNTHVID_FEATURE_CHANGE		= 9,
-	SYNTHVID_DIRT			= 10,
-	SYNTHVID_RESOLUTION_REQUEST	= 13,
-	SYNTHVID_RESOLUTION_RESPONSE	= 14,
-
-	SYNTHVID_MAX			= 15
-};
-
-#define		SYNTHVID_EDID_BLOCK_SIZE	128
-#define		SYNTHVID_MAX_RESOLUTION_COUNT	64
-
-struct hvd_screen_info {
-	u16 width;
-	u16 height;
-} __packed;
-
-struct synthvid_msg_hdr {
-	u32 type;
-	u32 size;  /* size of this header + payload after this field*/
-} __packed;
-
-struct synthvid_version_req {
-	u32 version;
-} __packed;
-
-struct synthvid_version_resp {
-	u32 version;
-	u8 is_accepted;
-	u8 max_video_outputs;
-} __packed;
-
-struct synthvid_supported_resolution_req {
-	u8 maximum_resolution_count;
-} __packed;
-
-struct synthvid_supported_resolution_resp {
-	u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
-	u8 resolution_count;
-	u8 default_resolution_index;
-	u8 is_standard;
-	struct hvd_screen_info
-		supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
-} __packed;
-
-struct synthvid_vram_location {
-	u64 user_ctx;
-	u8 is_vram_gpa_specified;
-	u64 vram_gpa;
-} __packed;
-
-struct synthvid_vram_location_ack {
-	u64 user_ctx;
-} __packed;
-
-struct video_output_situation {
-	u8 active;
-	u32 vram_offset;
-	u8 depth_bits;
-	u32 width_pixels;
-	u32 height_pixels;
-	u32 pitch_bytes;
-} __packed;
-
-struct synthvid_situation_update {
-	u64 user_ctx;
-	u8 video_output_count;
-	struct video_output_situation video_output[1];
-} __packed;
-
-struct synthvid_situation_update_ack {
-	u64 user_ctx;
-} __packed;
-
-struct synthvid_pointer_position {
-	u8 is_visible;
-	u8 video_output;
-	s32 image_x;
-	s32 image_y;
-} __packed;
-
-
-#define CURSOR_MAX_X 96
-#define CURSOR_MAX_Y 96
-#define CURSOR_ARGB_PIXEL_SIZE 4
-#define CURSOR_MAX_SIZE (CURSOR_MAX_X * CURSOR_MAX_Y * CURSOR_ARGB_PIXEL_SIZE)
-#define CURSOR_COMPLETE (-1)
-
-struct synthvid_pointer_shape {
-	u8 part_idx;
-	u8 is_argb;
-	u32 width; /* CURSOR_MAX_X at most */
-	u32 height; /* CURSOR_MAX_Y at most */
-	u32 hot_x; /* hotspot relative to upper-left of pointer image */
-	u32 hot_y;
-	u8 data[4];
-} __packed;
-
-struct synthvid_feature_change {
-	u8 is_dirt_needed;
-	u8 is_ptr_pos_needed;
-	u8 is_ptr_shape_needed;
-	u8 is_situ_needed;
-} __packed;
-
-struct rect {
-	s32 x1, y1; /* top left corner */
-	s32 x2, y2; /* bottom right corner, exclusive */
-} __packed;
-
-struct synthvid_dirt {
-	u8 video_output;
-	u8 dirt_count;
-	struct rect rect[1];
-} __packed;
-
-struct synthvid_msg {
-	struct pipe_msg_hdr pipe_hdr;
-	struct synthvid_msg_hdr vid_hdr;
-	union {
-		struct synthvid_version_req ver_req;
-		struct synthvid_version_resp ver_resp;
-		struct synthvid_vram_location vram;
-		struct synthvid_vram_location_ack vram_ack;
-		struct synthvid_situation_update situ;
-		struct synthvid_situation_update_ack situ_ack;
-		struct synthvid_pointer_position ptr_pos;
-		struct synthvid_pointer_shape ptr_shape;
-		struct synthvid_feature_change feature_chg;
-		struct synthvid_dirt dirt;
-		struct synthvid_supported_resolution_req resolution_req;
-		struct synthvid_supported_resolution_resp resolution_resp;
-	};
-} __packed;
-
-
-/* FB driver definitions and structures */
-#define HVFB_WIDTH 1152 /* default screen width */
-#define HVFB_HEIGHT 864 /* default screen height */
-#define HVFB_WIDTH_MIN 640
-#define HVFB_HEIGHT_MIN 480
-
-#define RING_BUFSIZE (256 * 1024)
-#define VSP_TIMEOUT (10 * HZ)
-#define HVFB_UPDATE_DELAY (HZ / 20)
-#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
-
-struct hvfb_par {
-	struct fb_info *info;
-	struct resource *mem;
-	bool fb_ready; /* fb device is ready */
-	struct completion wait;
-	u32 synthvid_version;
-
-	struct delayed_work dwork;
-	bool update;
-	bool update_saved; /* The value of 'update' before hibernation */
-
-	u32 pseudo_palette[16];
-	u8 init_buf[MAX_VMBUS_PKT_SIZE];
-	u8 recv_buf[MAX_VMBUS_PKT_SIZE];
-
-	/* If true, the VSC notifies the VSP on every framebuffer change */
-	bool synchronous_fb;
-
-	/* If true, need to copy from deferred IO mem to framebuffer mem */
-	bool need_docopy;
-
-	struct notifier_block hvfb_panic_nb;
-
-	/* Memory for deferred IO and frame buffer itself */
-	unsigned char *dio_vp;
-	unsigned char *mmio_vp;
-	phys_addr_t mmio_pp;
-
-	/* Dirty rectangle, protected by delayed_refresh_lock */
-	int x1, y1, x2, y2;
-	bool delayed_refresh;
-	spinlock_t delayed_refresh_lock;
-};
-
-static uint screen_width = HVFB_WIDTH;
-static uint screen_height = HVFB_HEIGHT;
-static uint screen_depth;
-static uint screen_fb_size;
-static uint dio_fb_size; /* FB size for deferred IO */
-
-static void hvfb_putmem(struct fb_info *info);
-
-/* Send message to Hyper-V host */
-static inline int synthvid_send(struct hv_device *hdev,
-				struct synthvid_msg *msg)
-{
-	static atomic64_t request_id = ATOMIC64_INIT(0);
-	int ret;
-
-	msg->pipe_hdr.type = PIPE_MSG_DATA;
-	msg->pipe_hdr.size = msg->vid_hdr.size;
-
-	ret = vmbus_sendpacket(hdev->channel, msg,
-			       msg->vid_hdr.size + sizeof(struct pipe_msg_hdr),
-			       atomic64_inc_return(&request_id),
-			       VM_PKT_DATA_INBAND, 0);
-
-	if (ret)
-		pr_err_ratelimited("Unable to send packet via vmbus; error %d\n", ret);
-
-	return ret;
-}
-
-
-/* Send screen resolution info to host */
-static int synthvid_send_situ(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct synthvid_msg msg;
-
-	if (!info)
-		return -ENODEV;
-
-	memset(&msg, 0, sizeof(struct synthvid_msg));
-
-	msg.vid_hdr.type = SYNTHVID_SITUATION_UPDATE;
-	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_situation_update);
-	msg.situ.user_ctx = 0;
-	msg.situ.video_output_count = 1;
-	msg.situ.video_output[0].active = 1;
-	msg.situ.video_output[0].vram_offset = 0;
-	msg.situ.video_output[0].depth_bits = info->var.bits_per_pixel;
-	msg.situ.video_output[0].width_pixels = info->var.xres;
-	msg.situ.video_output[0].height_pixels = info->var.yres;
-	msg.situ.video_output[0].pitch_bytes = info->fix.line_length;
-
-	synthvid_send(hdev, &msg);
-
-	return 0;
-}
-
-/* Send mouse pointer info to host */
-static int synthvid_send_ptr(struct hv_device *hdev)
-{
-	struct synthvid_msg msg;
-
-	memset(&msg, 0, sizeof(struct synthvid_msg));
-	msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
-	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_pointer_position);
-	msg.ptr_pos.is_visible = 1;
-	msg.ptr_pos.video_output = 0;
-	msg.ptr_pos.image_x = 0;
-	msg.ptr_pos.image_y = 0;
-	synthvid_send(hdev, &msg);
-
-	memset(&msg, 0, sizeof(struct synthvid_msg));
-	msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE;
-	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_pointer_shape);
-	msg.ptr_shape.part_idx = CURSOR_COMPLETE;
-	msg.ptr_shape.is_argb = 1;
-	msg.ptr_shape.width = 1;
-	msg.ptr_shape.height = 1;
-	msg.ptr_shape.hot_x = 0;
-	msg.ptr_shape.hot_y = 0;
-	msg.ptr_shape.data[0] = 0;
-	msg.ptr_shape.data[1] = 1;
-	msg.ptr_shape.data[2] = 1;
-	msg.ptr_shape.data[3] = 1;
-	synthvid_send(hdev, &msg);
-
-	return 0;
-}
-
-/* Send updated screen area (dirty rectangle) location to host */
-static int
-synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
-{
-	struct hv_device *hdev = device_to_hv_device(info->device);
-	struct synthvid_msg msg;
-
-	memset(&msg, 0, sizeof(struct synthvid_msg));
-	if (x2 == INT_MAX)
-		x2 = info->var.xres;
-	if (y2 == INT_MAX)
-		y2 = info->var.yres;
-
-	msg.vid_hdr.type = SYNTHVID_DIRT;
-	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_dirt);
-	msg.dirt.video_output = 0;
-	msg.dirt.dirt_count = 1;
-	msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
-	msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
-	msg.dirt.rect[0].x2 =
-		(x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
-	msg.dirt.rect[0].y2 =
-		(y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
-
-	synthvid_send(hdev, &msg);
-
-	return 0;
-}
-
-static void hvfb_docopy(struct hvfb_par *par,
-			unsigned long offset,
-			unsigned long size)
-{
-	if (!par || !par->mmio_vp || !par->dio_vp || !par->fb_ready ||
-	    size == 0 || offset >= dio_fb_size)
-		return;
-
-	if (offset + size > dio_fb_size)
-		size = dio_fb_size - offset;
-
-	memcpy(par->mmio_vp + offset, par->dio_vp + offset, size);
-}
-
-/* Deferred IO callback */
-static void synthvid_deferred_io(struct fb_info *p, struct list_head *pagereflist)
-{
-	struct hvfb_par *par = p->par;
-	struct fb_deferred_io_pageref *pageref;
-	unsigned long start, end;
-	int y1, y2, miny, maxy;
-
-	miny = INT_MAX;
-	maxy = 0;
-
-	/*
-	 * Merge dirty pages. It is possible that last page cross
-	 * over the end of frame buffer row yres. This is taken care of
-	 * in synthvid_update function by clamping the y2
-	 * value to yres.
-	 */
-	list_for_each_entry(pageref, pagereflist, list) {
-		start = pageref->offset;
-		end = start + PAGE_SIZE - 1;
-		y1 = start / p->fix.line_length;
-		y2 = end / p->fix.line_length;
-		miny = min_t(int, miny, y1);
-		maxy = max_t(int, maxy, y2);
-
-		/* Copy from dio space to mmio address */
-		if (par->fb_ready && par->need_docopy)
-			hvfb_docopy(par, start, PAGE_SIZE);
-	}
-
-	if (par->fb_ready && par->update)
-		synthvid_update(p, 0, miny, p->var.xres, maxy + 1);
-}
-
-static struct fb_deferred_io synthvid_defio = {
-	.delay		= HZ / 20,
-	.deferred_io	= synthvid_deferred_io,
-};
-
-/*
- * Actions on received messages from host:
- * Complete the wait event.
- * Or, reply with screen and cursor info.
- */
-static void synthvid_recv_sub(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par;
-	struct synthvid_msg *msg;
-
-	if (!info)
-		return;
-
-	par = info->par;
-	msg = (struct synthvid_msg *)par->recv_buf;
-
-	/* Complete the wait event */
-	if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
-	    msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
-	    msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
-		memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
-		complete(&par->wait);
-		return;
-	}
-
-	/* Reply with screen and cursor info */
-	if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) {
-		if (par->fb_ready) {
-			synthvid_send_ptr(hdev);
-			synthvid_send_situ(hdev);
-		}
-
-		par->update = msg->feature_chg.is_dirt_needed;
-		if (par->update)
-			schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
-	}
-}
-
-/* Receive callback for messages from the host */
-static void synthvid_receive(void *ctx)
-{
-	struct hv_device *hdev = ctx;
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par;
-	struct synthvid_msg *recv_buf;
-	u32 bytes_recvd;
-	u64 req_id;
-	int ret;
-
-	if (!info)
-		return;
-
-	par = info->par;
-	recv_buf = (struct synthvid_msg *)par->recv_buf;
-
-	do {
-		ret = vmbus_recvpacket(hdev->channel, recv_buf,
-				       MAX_VMBUS_PKT_SIZE,
-				       &bytes_recvd, &req_id);
-		if (bytes_recvd > 0 &&
-		    recv_buf->pipe_hdr.type == PIPE_MSG_DATA)
-			synthvid_recv_sub(hdev);
-	} while (bytes_recvd > 0 && ret == 0);
-}
-
-/* Check if the ver1 version is equal or greater than ver2 */
-static inline bool synthvid_ver_ge(u32 ver1, u32 ver2)
-{
-	if (SYNTHVID_VER_GET_MAJOR(ver1) > SYNTHVID_VER_GET_MAJOR(ver2) ||
-	    (SYNTHVID_VER_GET_MAJOR(ver1) == SYNTHVID_VER_GET_MAJOR(ver2) &&
-	     SYNTHVID_VER_GET_MINOR(ver1) >= SYNTHVID_VER_GET_MINOR(ver2)))
-		return true;
-
-	return false;
-}
-
-/* Check synthetic video protocol version with the host */
-static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
-	int ret = 0;
-	unsigned long t;
-
-	memset(msg, 0, sizeof(struct synthvid_msg));
-	msg->vid_hdr.type = SYNTHVID_VERSION_REQUEST;
-	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_version_req);
-	msg->ver_req.version = ver;
-	synthvid_send(hdev, msg);
-
-	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
-	if (!t) {
-		pr_err("Time out on waiting version response\n");
-		ret = -ETIMEDOUT;
-		goto out;
-	}
-	if (!msg->ver_resp.is_accepted) {
-		ret = -ENODEV;
-		goto out;
-	}
-
-	par->synthvid_version = ver;
-	pr_info("Synthvid Version major %d, minor %d\n",
-		SYNTHVID_VER_GET_MAJOR(ver), SYNTHVID_VER_GET_MINOR(ver));
-
-out:
-	return ret;
-}
-
-/* Get current resolution from the host */
-static int synthvid_get_supported_resolution(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
-	int ret = 0;
-	unsigned long t;
-	u8 index;
-
-	memset(msg, 0, sizeof(struct synthvid_msg));
-	msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST;
-	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_supported_resolution_req);
-
-	msg->resolution_req.maximum_resolution_count =
-		SYNTHVID_MAX_RESOLUTION_COUNT;
-	synthvid_send(hdev, msg);
-
-	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
-	if (!t) {
-		pr_err("Time out on waiting resolution response\n");
-		ret = -ETIMEDOUT;
-		goto out;
-	}
-
-	if (msg->resolution_resp.resolution_count == 0) {
-		pr_err("No supported resolutions\n");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	index = msg->resolution_resp.default_resolution_index;
-	if (index >= msg->resolution_resp.resolution_count) {
-		pr_err("Invalid resolution index: %d\n", index);
-		ret = -ENODEV;
-		goto out;
-	}
-
-	screen_width =
-		msg->resolution_resp.supported_resolution[index].width;
-	screen_height =
-		msg->resolution_resp.supported_resolution[index].height;
-
-out:
-	return ret;
-}
-
-/* Connect to VSP (Virtual Service Provider) on host */
-static int synthvid_connect_vsp(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	int ret;
-
-	ret = vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE,
-			 NULL, 0, synthvid_receive, hdev);
-	if (ret) {
-		pr_err("Unable to open vmbus channel\n");
-		return ret;
-	}
-
-	/* Negotiate the protocol version with host */
-	switch (vmbus_proto_version) {
-	case VERSION_WIN10:
-	case VERSION_WIN10_V5:
-		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
-		if (!ret)
-			break;
-		fallthrough;
-	case VERSION_WIN8:
-	case VERSION_WIN8_1:
-		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
-		break;
-	default:
-		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
-		break;
-	}
-
-	if (ret) {
-		pr_err("Synthetic video device version not accepted\n");
-		goto error;
-	}
-
-	screen_depth = SYNTHVID_DEPTH_WIN8;
-	if (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10)) {
-		ret = synthvid_get_supported_resolution(hdev);
-		if (ret)
-			pr_info("Failed to get supported resolution from host, use default\n");
-	}
-
-	screen_fb_size = hdev->channel->offermsg.offer.
-				mmio_megabytes * 1024 * 1024;
-
-	return 0;
-
-error:
-	vmbus_close(hdev->channel);
-	return ret;
-}
-
-/* Send VRAM and Situation messages to the host */
-static int synthvid_send_config(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
-	int ret = 0;
-	unsigned long t;
-
-	/* Send VRAM location */
-	memset(msg, 0, sizeof(struct synthvid_msg));
-	msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
-	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_vram_location);
-	msg->vram.user_ctx = msg->vram.vram_gpa = par->mmio_pp;
-	msg->vram.is_vram_gpa_specified = 1;
-	synthvid_send(hdev, msg);
-
-	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
-	if (!t) {
-		pr_err("Time out on waiting vram location ack\n");
-		ret = -ETIMEDOUT;
-		goto out;
-	}
-	if (msg->vram_ack.user_ctx != par->mmio_pp) {
-		pr_err("Unable to set VRAM location\n");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	/* Send pointer and situation update */
-	synthvid_send_ptr(hdev);
-	synthvid_send_situ(hdev);
-
-out:
-	return ret;
-}
-
-
-/*
- * Delayed work callback:
- * It is scheduled to call whenever update request is received and it has
- * not been called in last HVFB_ONDEMAND_THROTTLE time interval.
- */
-static void hvfb_update_work(struct work_struct *w)
-{
-	struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);
-	struct fb_info *info = par->info;
-	unsigned long flags;
-	int x1, x2, y1, y2;
-	int j;
-
-	spin_lock_irqsave(&par->delayed_refresh_lock, flags);
-	/* Reset the request flag */
-	par->delayed_refresh = false;
-
-	/* Store the dirty rectangle to local variables */
-	x1 = par->x1;
-	x2 = par->x2;
-	y1 = par->y1;
-	y2 = par->y2;
-
-	/* Clear dirty rectangle */
-	par->x1 = par->y1 = INT_MAX;
-	par->x2 = par->y2 = 0;
-
-	spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
-
-	if (x1 > info->var.xres || x2 > info->var.xres ||
-	    y1 > info->var.yres || y2 > info->var.yres || x2 <= x1)
-		return;
-
-	/* Copy the dirty rectangle to frame buffer memory */
-	if (par->need_docopy)
-		for (j = y1; j < y2; j++)
-			hvfb_docopy(par,
-				    j * info->fix.line_length +
-				    (x1 * screen_depth / 8),
-				    (x2 - x1) * screen_depth / 8);
-
-	/* Refresh */
-	if (par->fb_ready && par->update)
-		synthvid_update(info, x1, y1, x2, y2);
-}
-
-/*
- * Control the on-demand refresh frequency. It schedules a delayed
- * screen update if it has not yet.
- */
-static void hvfb_ondemand_refresh_throttle(struct hvfb_par *par,
-					   int x1, int y1, int w, int h)
-{
-	unsigned long flags;
-	int x2 = x1 + w;
-	int y2 = y1 + h;
-
-	spin_lock_irqsave(&par->delayed_refresh_lock, flags);
-
-	/* Merge dirty rectangle */
-	par->x1 = min_t(int, par->x1, x1);
-	par->y1 = min_t(int, par->y1, y1);
-	par->x2 = max_t(int, par->x2, x2);
-	par->y2 = max_t(int, par->y2, y2);
-
-	/* Schedule a delayed screen update if not yet */
-	if (par->delayed_refresh == false) {
-		schedule_delayed_work(&par->dwork,
-				      HVFB_ONDEMAND_THROTTLE);
-		par->delayed_refresh = true;
-	}
-
-	spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
-}
-
-static int hvfb_on_panic(struct notifier_block *nb,
-			 unsigned long e, void *p)
-{
-	struct hv_device *hdev;
-	struct hvfb_par *par;
-	struct fb_info *info;
-
-	par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
-	info = par->info;
-	hdev = device_to_hv_device(info->device);
-
-	if (hv_ringbuffer_spinlock_busy(hdev->channel))
-		return NOTIFY_DONE;
-
-	par->synchronous_fb = true;
-	if (par->need_docopy)
-		hvfb_docopy(par, 0, dio_fb_size);
-	synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
-
-	return NOTIFY_DONE;
-}
-
-/* Framebuffer operation handlers */
-
-static int hvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
-	if (var->xres < HVFB_WIDTH_MIN || var->yres < HVFB_HEIGHT_MIN ||
-	    var->xres > screen_width || var->yres >  screen_height ||
-	    var->bits_per_pixel != screen_depth)
-		return -EINVAL;
-
-	var->xres_virtual = var->xres;
-	var->yres_virtual = var->yres;
-
-	return 0;
-}
-
-static int hvfb_set_par(struct fb_info *info)
-{
-	struct hv_device *hdev = device_to_hv_device(info->device);
-
-	return synthvid_send_situ(hdev);
-}
-
-
-static inline u32 chan_to_field(u32 chan, struct fb_bitfield *bf)
-{
-	return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
-}
-
-static int hvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-			  unsigned blue, unsigned transp, struct fb_info *info)
-{
-	u32 *pal = info->pseudo_palette;
-
-	if (regno > 15)
-		return -EINVAL;
-
-	pal[regno] = chan_to_field(red, &info->var.red)
-		| chan_to_field(green, &info->var.green)
-		| chan_to_field(blue, &info->var.blue)
-		| chan_to_field(transp, &info->var.transp);
-
-	return 0;
-}
-
-static int hvfb_blank(int blank, struct fb_info *info)
-{
-	return 1;	/* get fb_blank to set the colormap to all black */
-}
-
-static void hvfb_ops_damage_range(struct fb_info *info, off_t off, size_t len)
-{
-	/* TODO: implement damage handling */
-}
-
-static void hvfb_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height)
-{
-	struct hvfb_par *par = info->par;
-
-	if (par->synchronous_fb)
-		synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
-	else
-		hvfb_ondemand_refresh_throttle(par, x, y, width, height);
-}
-
-/*
- * fb_ops.fb_destroy is called by the last put_fb_info() call at the end
- * of unregister_framebuffer() or fb_release(). Do any cleanup related to
- * framebuffer here.
- */
-static void hvfb_destroy(struct fb_info *info)
-{
-	hvfb_putmem(info);
-	framebuffer_release(info);
-}
-
-/*
- * TODO: GEN1 codepaths allocate from system or DMA-able memory. Fix the
- *       driver to use the _SYSMEM_ or _DMAMEM_ helpers in these cases.
- */
-FB_GEN_DEFAULT_DEFERRED_IOMEM_OPS(hvfb_ops,
-				  hvfb_ops_damage_range,
-				  hvfb_ops_damage_area)
-
-static const struct fb_ops hvfb_ops = {
-	.owner = THIS_MODULE,
-	FB_DEFAULT_DEFERRED_OPS(hvfb_ops),
-	.fb_check_var = hvfb_check_var,
-	.fb_set_par = hvfb_set_par,
-	.fb_setcolreg = hvfb_setcolreg,
-	.fb_blank = hvfb_blank,
-	.fb_destroy	= hvfb_destroy,
-};
-
-/* Get options from kernel paramenter "video=" */
-static void hvfb_get_option(struct fb_info *info)
-{
-	struct hvfb_par *par = info->par;
-	char *opt = NULL, *p;
-	uint x = 0, y = 0;
-
-	if (fb_get_options(KBUILD_MODNAME, &opt) || !opt || !*opt)
-		return;
-
-	p = strsep(&opt, "x");
-	if (!*p || kstrtouint(p, 0, &x) ||
-	    !opt || !*opt || kstrtouint(opt, 0, &y)) {
-		pr_err("Screen option is invalid: skipped\n");
-		return;
-	}
-
-	if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
-	    (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) &&
-	    (x * y * screen_depth / 8 > screen_fb_size)) ||
-	    (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
-	     x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8)) {
-		pr_err("Screen resolution option is out of range: skipped\n");
-		return;
-	}
-
-	screen_width = x;
-	screen_height = y;
-	return;
-}
-
-/*
- * Allocate enough contiguous physical memory.
- * Return physical address if succeeded or -1 if failed.
- */
-static phys_addr_t hvfb_get_phymem(struct hv_device *hdev,
-				   unsigned int request_size)
-{
-	struct page *page = NULL;
-	dma_addr_t dma_handle;
-	void *vmem;
-	phys_addr_t paddr = 0;
-	unsigned int order = get_order(request_size);
-
-	if (request_size == 0)
-		return -1;
-
-	if (order <= MAX_PAGE_ORDER) {
-		/* Call alloc_pages if the size is less than 2^MAX_PAGE_ORDER */
-		page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
-		if (!page)
-			return -1;
-
-		paddr = (page_to_pfn(page) << PAGE_SHIFT);
-	} else {
-		/* Allocate from CMA */
-		hdev->device.coherent_dma_mask = DMA_BIT_MASK(64);
-
-		vmem = dma_alloc_coherent(&hdev->device,
-					  round_up(request_size, PAGE_SIZE),
-					  &dma_handle,
-					  GFP_KERNEL | __GFP_NOWARN);
-
-		if (!vmem)
-			return -1;
-
-		paddr = virt_to_phys(vmem);
-	}
-
-	return paddr;
-}
-
-/* Release contiguous physical memory */
-static void hvfb_release_phymem(struct device *device,
-				phys_addr_t paddr, unsigned int size)
-{
-	unsigned int order = get_order(size);
-
-	if (order <= MAX_PAGE_ORDER)
-		__free_pages(pfn_to_page(paddr >> PAGE_SHIFT), order);
-	else
-		dma_free_coherent(device,
-				  round_up(size, PAGE_SIZE),
-				  phys_to_virt(paddr),
-				  paddr);
-}
-
-
-/* Get framebuffer memory from Hyper-V video pci space */
-static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
-{
-	struct hvfb_par *par = info->par;
-	struct pci_dev *pdev  = NULL;
-	void __iomem *fb_virt;
-	int gen2vm = efi_enabled(EFI_BOOT);
-	resource_size_t base = 0;
-	resource_size_t size = 0;
-	phys_addr_t paddr;
-	int ret;
-
-	if (!gen2vm) {
-		pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
-			PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
-		if (!pdev) {
-			pr_err("Unable to find PCI Hyper-V video\n");
-			return -ENODEV;
-		}
-
-		base = pci_resource_start(pdev, 0);
-		size = pci_resource_len(pdev, 0);
-		aperture_remove_conflicting_devices(base, size, KBUILD_MODNAME);
-
-		/*
-		 * For Gen 1 VM, we can directly use the contiguous memory
-		 * from VM. If we succeed, deferred IO happens directly
-		 * on this allocated framebuffer memory, avoiding extra
-		 * memory copy.
-		 */
-		paddr = hvfb_get_phymem(hdev, screen_fb_size);
-		if (paddr != (phys_addr_t) -1) {
-			par->mmio_pp = paddr;
-			par->mmio_vp = par->dio_vp = __va(paddr);
-
-			info->fix.smem_start = paddr;
-			info->fix.smem_len = screen_fb_size;
-			info->screen_base = par->mmio_vp;
-			info->screen_size = screen_fb_size;
-
-			par->need_docopy = false;
-			goto getmem_done;
-		}
-		pr_info("Unable to allocate enough contiguous physical memory on Gen 1 VM. Using MMIO instead.\n");
-	} else {
-		aperture_remove_all_conflicting_devices(KBUILD_MODNAME);
-	}
-
-	/*
-	 * Cannot use contiguous physical memory, so allocate MMIO space for
-	 * the framebuffer. At this point in the function, conflicting devices
-	 * that might have claimed the framebuffer MMIO space based on
-	 * screen_info.lfb_base must have already been removed so that
-	 * vmbus_allocate_mmio() does not allocate different MMIO space. If the
-	 * kdump image were to be loaded using kexec_file_load(), the
-	 * framebuffer location in the kdump image would be set from
-	 * screen_info.lfb_base at the time that kdump is enabled. If the
-	 * framebuffer has moved elsewhere, this could be the wrong location,
-	 * causing kdump to hang when efifb (for example) loads.
-	 */
-	dio_fb_size =
-		screen_width * screen_height * screen_depth / 8;
-
-	ret = vmbus_allocate_mmio(&par->mem, hdev, 0, -1,
-				  screen_fb_size, 0x100000, true);
-	if (ret != 0) {
-		pr_err("Unable to allocate framebuffer memory\n");
-		goto err1;
-	}
-
-	/*
-	 * Map the VRAM cacheable for performance. This is also required for
-	 * VM Connect to display properly for ARM64 Linux VM, as the host also
-	 * maps the VRAM cacheable.
-	 */
-	fb_virt = ioremap_cache(par->mem->start, screen_fb_size);
-	if (!fb_virt)
-		goto err2;
-
-	/* Allocate memory for deferred IO */
-	par->dio_vp = vzalloc(round_up(dio_fb_size, PAGE_SIZE));
-	if (par->dio_vp == NULL)
-		goto err3;
-
-	/* Physical address of FB device */
-	par->mmio_pp = par->mem->start;
-	/* Virtual address of FB device */
-	par->mmio_vp = (unsigned char *) fb_virt;
-
-	info->fix.smem_start = par->mem->start;
-	info->fix.smem_len = dio_fb_size;
-	info->screen_base = par->dio_vp;
-	info->screen_size = dio_fb_size;
-
-getmem_done:
-	if (!gen2vm)
-		pci_dev_put(pdev);
-
-	return 0;
-
-err3:
-	iounmap(fb_virt);
-err2:
-	vmbus_free_mmio(par->mem->start, screen_fb_size);
-	par->mem = NULL;
-err1:
-	if (!gen2vm)
-		pci_dev_put(pdev);
-
-	return -ENOMEM;
-}
-
-/* Release the framebuffer */
-static void hvfb_putmem(struct fb_info *info)
-{
-	struct hvfb_par *par = info->par;
-
-	if (par->need_docopy) {
-		vfree(par->dio_vp);
-		iounmap(par->mmio_vp);
-		vmbus_free_mmio(par->mem->start, screen_fb_size);
-	} else {
-		hvfb_release_phymem(info->device, info->fix.smem_start,
-				    screen_fb_size);
-	}
-
-	par->mem = NULL;
-}
-
-
-static int hvfb_probe(struct hv_device *hdev,
-		      const struct hv_vmbus_device_id *dev_id)
-{
-	struct fb_info *info;
-	struct hvfb_par *par;
-	int ret;
-
-	info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device);
-	if (!info)
-		return -ENOMEM;
-
-	par = info->par;
-	par->info = info;
-	par->fb_ready = false;
-	par->need_docopy = true;
-	init_completion(&par->wait);
-	INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);
-
-	par->delayed_refresh = false;
-	spin_lock_init(&par->delayed_refresh_lock);
-	par->x1 = par->y1 = INT_MAX;
-	par->x2 = par->y2 = 0;
-
-	/* Connect to VSP */
-	hv_set_drvdata(hdev, info);
-	ret = synthvid_connect_vsp(hdev);
-	if (ret) {
-		pr_err("Unable to connect to VSP\n");
-		goto error1;
-	}
-
-	hvfb_get_option(info);
-	pr_info("Screen resolution: %dx%d, Color depth: %d, Frame buffer size: %d\n",
-		screen_width, screen_height, screen_depth, screen_fb_size);
-
-	ret = hvfb_getmem(hdev, info);
-	if (ret) {
-		pr_err("No memory for framebuffer\n");
-		goto error2;
-	}
-
-	/* Set up fb_info */
-	info->var.xres_virtual = info->var.xres = screen_width;
-	info->var.yres_virtual = info->var.yres = screen_height;
-	info->var.bits_per_pixel = screen_depth;
-
-	if (info->var.bits_per_pixel == 16) {
-		info->var.red = (struct fb_bitfield){11, 5, 0};
-		info->var.green = (struct fb_bitfield){5, 6, 0};
-		info->var.blue = (struct fb_bitfield){0, 5, 0};
-		info->var.transp = (struct fb_bitfield){0, 0, 0};
-	} else {
-		info->var.red = (struct fb_bitfield){16, 8, 0};
-		info->var.green = (struct fb_bitfield){8, 8, 0};
-		info->var.blue = (struct fb_bitfield){0, 8, 0};
-		info->var.transp = (struct fb_bitfield){24, 8, 0};
-	}
-
-	info->var.activate = FB_ACTIVATE_NOW;
-	info->var.height = -1;
-	info->var.width = -1;
-	info->var.vmode = FB_VMODE_NONINTERLACED;
-
-	strcpy(info->fix.id, KBUILD_MODNAME);
-	info->fix.type = FB_TYPE_PACKED_PIXELS;
-	info->fix.visual = FB_VISUAL_TRUECOLOR;
-	info->fix.line_length = screen_width * screen_depth / 8;
-	info->fix.accel = FB_ACCEL_NONE;
-
-	info->fbops = &hvfb_ops;
-	info->pseudo_palette = par->pseudo_palette;
-
-	/* Initialize deferred IO */
-	info->fbdefio = &synthvid_defio;
-	fb_deferred_io_init(info);
-
-	/* Send config to host */
-	ret = synthvid_send_config(hdev);
-	if (ret)
-		goto error;
-
-	ret = devm_register_framebuffer(&hdev->device, info);
-	if (ret) {
-		pr_err("Unable to register framebuffer\n");
-		goto error;
-	}
-
-	par->fb_ready = true;
-
-	par->synchronous_fb = false;
-
-	/*
-	 * We need to be sure this panic notifier runs _before_ the
-	 * vmbus disconnect, so order it by priority. It must execute
-	 * before the function hv_panic_vmbus_unload() [drivers/hv/vmbus_drv.c],
-	 * which is almost at the end of list, with priority = INT_MIN + 1.
-	 */
-	par->hvfb_panic_nb.notifier_call = hvfb_on_panic;
-	par->hvfb_panic_nb.priority = INT_MIN + 10;
-	atomic_notifier_chain_register(&panic_notifier_list,
-				       &par->hvfb_panic_nb);
-
-	return 0;
-
-error:
-	fb_deferred_io_cleanup(info);
-	hvfb_putmem(info);
-error2:
-	vmbus_close(hdev->channel);
-error1:
-	cancel_delayed_work_sync(&par->dwork);
-	hv_set_drvdata(hdev, NULL);
-	framebuffer_release(info);
-	return ret;
-}
-
-static void hvfb_remove(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-
-	atomic_notifier_chain_unregister(&panic_notifier_list,
-					 &par->hvfb_panic_nb);
-
-	par->update = false;
-	par->fb_ready = false;
-
-	fb_deferred_io_cleanup(info);
-
-	cancel_delayed_work_sync(&par->dwork);
-
-	vmbus_close(hdev->channel);
-	hv_set_drvdata(hdev, NULL);
-}
-
-static int hvfb_suspend(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-
-	console_lock();
-
-	/* 1 means do suspend */
-	fb_set_suspend(info, 1);
-
-	cancel_delayed_work_sync(&par->dwork);
-	cancel_delayed_work_sync(&info->deferred_work);
-
-	par->update_saved = par->update;
-	par->update = false;
-	par->fb_ready = false;
-
-	vmbus_close(hdev->channel);
-
-	console_unlock();
-
-	return 0;
-}
-
-static int hvfb_resume(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	int ret;
-
-	console_lock();
-
-	ret = synthvid_connect_vsp(hdev);
-	if (ret != 0)
-		goto out;
-
-	ret = synthvid_send_config(hdev);
-	if (ret != 0) {
-		vmbus_close(hdev->channel);
-		goto out;
-	}
-
-	par->fb_ready = true;
-	par->update = par->update_saved;
-
-	schedule_delayed_work(&info->deferred_work, info->fbdefio->delay);
-	schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
-
-	/* 0 means do resume */
-	fb_set_suspend(info, 0);
-
-out:
-	console_unlock();
-
-	return ret;
-}
-
-
-static const struct pci_device_id pci_stub_id_table[] = {
-	{
-		.vendor      = PCI_VENDOR_ID_MICROSOFT,
-		.device      = PCI_DEVICE_ID_HYPERV_VIDEO,
-	},
-	{ /* end of list */ }
-};
-
-static const struct hv_vmbus_device_id id_table[] = {
-	/* Synthetic Video Device GUID */
-	{HV_SYNTHVID_GUID},
-	{}
-};
-
-MODULE_DEVICE_TABLE(pci, pci_stub_id_table);
-MODULE_DEVICE_TABLE(vmbus, id_table);
-
-static struct hv_driver hvfb_drv = {
-	.name = KBUILD_MODNAME,
-	.id_table = id_table,
-	.probe = hvfb_probe,
-	.remove = hvfb_remove,
-	.suspend = hvfb_suspend,
-	.resume = hvfb_resume,
-	.driver = {
-		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
-	},
-};
-
-static int hvfb_pci_stub_probe(struct pci_dev *pdev,
-			       const struct pci_device_id *ent)
-{
-	return 0;
-}
-
-static void hvfb_pci_stub_remove(struct pci_dev *pdev)
-{
-}
-
-static struct pci_driver hvfb_pci_stub_driver = {
-	.name =		KBUILD_MODNAME,
-	.id_table =	pci_stub_id_table,
-	.probe =	hvfb_pci_stub_probe,
-	.remove =	hvfb_pci_stub_remove,
-	.driver = {
-		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
-	}
-};
-
-static int __init hvfb_drv_init(void)
-{
-	int ret;
-
-	if (fb_modesetting_disabled("hyper_fb"))
-		return -ENODEV;
-
-	ret = vmbus_driver_register(&hvfb_drv);
-	if (ret != 0)
-		return ret;
-
-	ret = pci_register_driver(&hvfb_pci_stub_driver);
-	if (ret != 0) {
-		vmbus_driver_unregister(&hvfb_drv);
-		return ret;
-	}
-
-	return 0;
-}
-
-static void __exit hvfb_drv_exit(void)
-{
-	pci_unregister_driver(&hvfb_pci_stub_driver);
-	vmbus_driver_unregister(&hvfb_drv);
-}
-
-module_init(hvfb_drv_init);
-module_exit(hvfb_drv_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver");
-- 
2.49.0


^ permalink raw reply related

* [RFC 0/3] fbdev: remove Hyper-V framebuffer driver
From: Prasanna Kumar T S M @ 2025-09-09 16:57 UTC (permalink / raw)
  To: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	drawat.floss, kys, haiyangz, wei.liu, decui, deller, arnd, soci,
	rdunlap, gonzalo.silvalde, bartosz.golaszewski, mhklinux, ssengar,
	linux-kernel, dri-devel, linux-hyperv, linux-fbdev

This series removes the Hyper-V framebuffer driver. The Hyper-V DRM
driver is available since kernel version 5.14 and provides full KMS
support along with fbdev emulation via the DRM fbdev helpers. This makes
the hyperv_fb driver redundant. So remove hyperv_fb driver.

Prasanna Kumar T S M (3):
  drivers: video: fbdev: Remove hyperv_fb driver
  drm: hyprev: Remove reference to hyperv_fb driver
  drivers: hv: vmbus_drv: Remove reference to hpyerv_fb

 MAINTAINERS                               |    1 -
 drivers/gpu/drm/Kconfig                   |    3 +-
 drivers/gpu/drm/hyperv/hyperv_drm_proto.c |   15 +-
 drivers/hv/vmbus_drv.c                    |    4 +-
 drivers/video/fbdev/Kconfig               |    8 -
 drivers/video/fbdev/Makefile              |    1 -
 drivers/video/fbdev/hyperv_fb.c           | 1386 ---------------------
 7 files changed, 8 insertions(+), 1410 deletions(-)
 delete mode 100644 drivers/video/fbdev/hyperv_fb.c

--
2.49.0


^ permalink raw reply

* Re: [PATCH] backlight: pwm_bl: apply the initial backlight state with sane defaults
From: Uwe Kleine-König @ 2025-09-09 13:49 UTC (permalink / raw)
  To: Michael Grzeschik
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Helge Deller, Pengutronix,
	linux-pwm, dri-devel, linux-fbdev, linux-kernel
In-Reply-To: <n6rltuxqwybh2mwzz3hxi3tzix2c7q3mbovscobzzmkj6puo6w@gc3qnchjlagq>

[-- Attachment #1: Type: text/plain, Size: 2924 bytes --]

Hello Michael,

On Fri, Aug 01, 2025 at 08:32:20AM +0200, Uwe Kleine-König wrote:
> Hallo Michael,
> 
> On Thu, Jul 31, 2025 at 10:47:18AM +0200, Michael Grzeschik wrote:
> > diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
> > index 237d3d3f3bb1a..5924e0b9f01e7 100644
> > --- a/drivers/video/backlight/pwm_bl.c
> > +++ b/drivers/video/backlight/pwm_bl.c
> > @@ -518,13 +518,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
> >  	if (!state.period && (data->pwm_period_ns > 0))
> >  		state.period = data->pwm_period_ns;
> >  
> > -	ret = pwm_apply_might_sleep(pb->pwm, &state);
> > -	if (ret) {
> > -		dev_err_probe(&pdev->dev, ret,
> > -			      "failed to apply initial PWM state");
> > -		goto err_alloc;
> > -	}
> > -
> >  	memset(&props, 0, sizeof(struct backlight_properties));
> >  
> >  	if (data->levels) {
> > @@ -582,6 +575,15 @@ static int pwm_backlight_probe(struct platform_device *pdev)
> >  	pb->lth_brightness = data->lth_brightness * (div_u64(state.period,
> >  				pb->scale));
> >  
> > +	state.duty_cycle = compute_duty_cycle(pb, data->dft_brightness, &state);
> > +
> > +	ret = pwm_apply_might_sleep(pb->pwm, &state);
> > +	if (ret) {
> > +		dev_err_probe(&pdev->dev, ret,
> > +			      "failed to apply initial PWM state");
> > +		goto err_alloc;
> > +	}
> > +
> 
> I wonder why the PWM is updated at all in .probe(). Wouldn't it be the
> natural thing to keep the PWM configured as it was (in its reset default
> state or how the bootloader set it up)?
> 
> Orthogonal to your change, while looking at the driver I wondered about:
> 
>         bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
>                                        &pwm_backlight_ops, &props);
>         if (IS_ERR(bl)) {
>                 ret = dev_err_probe(&pdev->dev, PTR_ERR(bl),
>                                     "failed to register backlight\n");
>                 goto err_alloc;
>         }
> 
>         if (data->dft_brightness > data->max_brightness) {
>                 dev_warn(&pdev->dev,
>                          "invalid default brightness level: %u, using %u\n",
>                          data->dft_brightness, data->max_brightness);
>                 data->dft_brightness = data->max_brightness;
>         }
> 
>         bl->props.brightness = data->dft_brightness;
>         bl->props.power = pwm_backlight_initial_power_state(pb);
>         backlight_update_status(bl);
> 
> Shoudn't setting data->dft_brightness, bl->props.brightness and
> bl->props.power better happen before backlight_device_register()? Also
> calling backlight_update_status() after backlight_device_register()
> seems wrong to me, I'd claim the backend driver shouldn't call that.

Do you intend to work on this orthogonal feedback? If not, I'll put it
on my todo list.

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH 0/2] backlight: mp3309c: Drop pwm_apply_args()
From: Uwe Kleine-König @ 2025-09-09 13:43 UTC (permalink / raw)
  To: Lee Jones
  Cc: Flavio Suligoi, Daniel Thompson, Jingoo Han, Helge Deller,
	dri-devel, linux-fbdev, linux-pwm
In-Reply-To: <175680932706.2261091.9987211835426797993.b4-ty@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 1302 bytes --]

Hello Lee,

On Tue, Sep 02, 2025 at 11:35:27AM +0100, Lee Jones wrote:
> On Tue, 01 Jul 2025 11:22:35 +0200, Uwe Kleine-König wrote:
> > the first patch of this series is what I really care about: There are
> > hardly any drivers left that use pwm_apply_args(). When all of them are
> > converted to not use it any more, I intend to drop that function.
> > 
> > The 2nd patch is just a change that I noticed while editing the driver
> > that is IMHO nice. If you don't agree and only apply the first patch, I
> > won't argue. It's an alternative approach to what Daniel Thompson did in
> > commit 7ee6478d5aa9 ("backlight: mp3309c: Fully initialize
> > backlight_properties during probe").
> > 
> > [...]
> 
> Applied, thanks!
> 
> [1/2] backlight: mp3309c: Drop pwm_apply_args()
>       commit: d22caa15de3a11b503157aec079cad4bf305ff47
> [2/2] backlight: mp3309c: Initialize backlight properties without memset
>       commit: 71ca0594c11b4030c6dece9ba9b080d652a82473

I would expect to see these commits in your repo at
https://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git, but
the exact commits don't exist there and if the patches are included
under a different commit-id it's not obvious to me in which branch. Did
you forget to push?

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH 2/2] backlight: mp3309c: Initialize backlight properties without memset
From: Uwe Kleine-König @ 2025-09-09 13:16 UTC (permalink / raw)
  To: Lee Jones
  Cc: Daniel Thompson, Flavio Suligoi, Daniel Thompson, Jingoo Han,
	Helge Deller, dri-devel, linux-fbdev, linux-pwm
In-Reply-To: <20250902103632.GH2163762@google.com>

[-- Attachment #1: Type: text/plain, Size: 1232 bytes --]

On Tue, Sep 02, 2025 at 11:36:32AM +0100, Lee Jones wrote:
> On Mon, 18 Aug 2025, Daniel Thompson wrote:
> 
> > On Tue, Jul 01, 2025 at 11:22:37AM +0200, Uwe Kleine-König wrote:
> > > Assigning values to a struct using a compound literal (since C99) also
> > > guarantees that all unspecified struct members are empty-initialized, so
> > > it properly replaces the memset to zero.
> > >
> > > The code looks a bit nicer and more idiomatic (though that might be
> > > subjective?). The resulting binary is a bit smaller. On ARCH=arm with
> > > an allnoconfig + minimal changes to enable the mp3309c driver the
> > > difference is 12 bytes.
> > >
> > > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
> > 
> > Reviewed-by: Daniel Thompson (RISCstar) <danielt@kernel.org>
> 
> Looks like you cannot send tags from non-related email accounts:
> 
> NOTE: some trailers ignored due to from/email mismatches:
>     ! Trailer: Reviewed-by: "Daniel Thompson (RISCstar)" <danielt@kernel.org>
>      Msg From: Daniel Thompson <daniel@riscstar.com>
> 
> I'll add the tags manually this time.

FTR: The email address *or* the real name has to match the From: line to
make b4 happy.

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* [PATCH v2 5/5] fbcon: Streamline setting rotated/unrotated bitops
From: Thomas Zimmermann @ 2025-09-09 12:44 UTC (permalink / raw)
  To: sam, simona, deller
  Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20250909124616.143365-1-tzimmermann@suse.de>

Support for console rotation is somewhat bolted onto the helper
fbcon_set_bitops() for unrotated displays.

Update fbcon_set_bitops() with a switch statement that picks the
correct settings helper for the current rotation. For unrotated
consoles, set the bitops for in the new helper fbcon_set_bitops_ur().
Rename the other, existing helpers to match the common naming
scheme.

The old helper fbcon_set_rotate() is no longer used.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
 drivers/video/fbdev/core/bitblit.c      |  5 +----
 drivers/video/fbdev/core/fbcon.c        | 21 +++++++++++++++++++++
 drivers/video/fbdev/core/fbcon.h        |  8 +-------
 drivers/video/fbdev/core/fbcon_ccw.c    |  2 +-
 drivers/video/fbdev/core/fbcon_cw.c     |  2 +-
 drivers/video/fbdev/core/fbcon_rotate.c | 15 ---------------
 drivers/video/fbdev/core/fbcon_rotate.h | 15 ++++++++++++---
 drivers/video/fbdev/core/fbcon_ud.c     |  2 +-
 8 files changed, 38 insertions(+), 32 deletions(-)

diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index 7a68372f0444..08cfcd81c6b4 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -393,10 +393,7 @@ static const struct fbcon_bitops bit_fbcon_bitops = {
 	.update_start = bit_update_start,
 };
 
-void fbcon_set_bitops(struct fbcon_par *par)
+void fbcon_set_bitops_ur(struct fbcon_par *par)
 {
 	par->bitops = &bit_fbcon_bitops;
-
-	if (par->rotate)
-		fbcon_set_rotate(par);
 }
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 1074dc90ed92..85f63f87d3c1 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -81,6 +81,7 @@
 #include <asm/irq.h>
 
 #include "fbcon.h"
+#include "fbcon_rotate.h"
 #include "fb_internal.h"
 
 /*
@@ -270,6 +271,26 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
 }
 #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
 
+static void fbcon_set_bitops(struct fbcon_par *par)
+{
+	switch (par->rotate) {
+	default:
+		fallthrough;
+	case FB_ROTATE_UR:
+		fbcon_set_bitops_ur(par);
+		break;
+	case FB_ROTATE_CW:
+		fbcon_set_bitops_cw(par);
+		break;
+	case FB_ROTATE_UD:
+		fbcon_set_bitops_ud(par);
+		break;
+	case FB_ROTATE_CCW:
+		fbcon_set_bitops_ccw(par);
+		break;
+	}
+}
+
 static int fbcon_get_rotate(struct fb_info *info)
 {
 	struct fbcon_par *par = info->fbcon_par;
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index 4bff4f5b3ec1..44ea4ae4bba0 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -191,7 +191,7 @@ static inline u_short fb_scrollmode(struct fbcon_display *fb)
 #ifdef CONFIG_FB_TILEBLITTING
 extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
 #endif
-extern void fbcon_set_bitops(struct fbcon_par *par);
+extern void fbcon_set_bitops_ur(struct fbcon_par *par);
 extern int  soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
 
 #define FBCON_ATTRIBUTE_UNDERLINE 1
@@ -229,10 +229,4 @@ static inline int get_attribute(struct fb_info *info, u16 c)
         (void) (&_r == &_v); \
         (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; })
 
-#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
-extern void fbcon_set_rotate(struct fbcon_par *par);
-#else
-#define fbcon_set_rotate(x) do {} while(0)
-#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
-
 #endif /* _VIDEO_FBCON_H */
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 4721f4b5e29a..2f394b5a17f7 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -400,7 +400,7 @@ static const struct fbcon_bitops ccw_fbcon_bitops = {
 	.rotate_font = fbcon_rotate_font,
 };
 
-void fbcon_rotate_ccw(struct fbcon_par *par)
+void fbcon_set_bitops_ccw(struct fbcon_par *par)
 {
 	par->bitops = &ccw_fbcon_bitops;
 }
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 2771924d0fb7..3c3ad3471ec4 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -383,7 +383,7 @@ static const struct fbcon_bitops cw_fbcon_bitops = {
 	.rotate_font = fbcon_rotate_font,
 };
 
-void fbcon_rotate_cw(struct fbcon_par *par)
+void fbcon_set_bitops_cw(struct fbcon_par *par)
 {
 	par->bitops = &cw_fbcon_bitops;
 }
diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
index 0c7cac71a9c2..1562a8f20b4f 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -92,18 +92,3 @@ int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 finished:
 	return err;
 }
-
-void fbcon_set_rotate(struct fbcon_par *par)
-{
-	switch (par->rotate) {
-	case FB_ROTATE_CW:
-		fbcon_rotate_cw(par);
-		break;
-	case FB_ROTATE_UD:
-		fbcon_rotate_ud(par);
-		break;
-	case FB_ROTATE_CCW:
-		fbcon_rotate_ccw(par);
-		break;
-	}
-}
diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h
index 784f3231a958..8cb019e8a9c0 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.h
+++ b/drivers/video/fbdev/core/fbcon_rotate.h
@@ -92,8 +92,17 @@ static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
 
 int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc);
 
-extern void fbcon_rotate_cw(struct fbcon_par *par);
-extern void fbcon_rotate_ud(struct fbcon_par *par);
-extern void fbcon_rotate_ccw(struct fbcon_par *par);
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION)
+void fbcon_set_bitops_cw(struct fbcon_par *par);
+void fbcon_set_bitops_ud(struct fbcon_par *par);
+void fbcon_set_bitops_ccw(struct fbcon_par *par);
+#else
+static inline void fbcon_set_bitops_cw(struct fbcon_par *par)
+{ }
+static inline void fbcon_set_bitops_ud(struct fbcon_par *par)
+{ }
+static inline void fbcon_set_bitops_ccw(struct fbcon_par *par)
+{ }
+#endif
 
 #endif
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index 148ca9b539d1..6fc30cad5b19 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -427,7 +427,7 @@ static const struct fbcon_bitops ud_fbcon_bitops = {
 	.rotate_font = fbcon_rotate_font,
 };
 
-void fbcon_rotate_ud(struct fbcon_par *par)
+void fbcon_set_bitops_ud(struct fbcon_par *par)
 {
 	par->bitops = &ud_fbcon_bitops;
 }
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 2/5] fbcon: Rename struct fbcon_ops to struct fbcon_par
From: Thomas Zimmermann @ 2025-09-09 12:44 UTC (permalink / raw)
  To: sam, simona, deller
  Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20250909124616.143365-1-tzimmermann@suse.de>

The type struct fbcon_ops contains fbcon state and callbacks. As the
callbacks will be removed from struct fbcon_ops, rename the data type
to struct fbcon_par. Also rename the variables from ops to par.

The _par postfix ("private access registers") is used throughout the
fbdev subsystem for per-driver state. The fbcon pointer within struct
fb_info is also named fbcon_par. Hence, the new naming fits existing
practice.

v2:
- rename struct fbcon_ops to struct fbcon_par
- fix build for CONFIG_FB_TILEBITTING=n (kernel test robot)
- fix indention

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
 drivers/video/fbdev/core/bitblit.c      | 122 +++----
 drivers/video/fbdev/core/fbcon.c        | 419 ++++++++++++------------
 drivers/video/fbdev/core/fbcon.h        |   6 +-
 drivers/video/fbdev/core/fbcon_ccw.c    | 146 ++++-----
 drivers/video/fbdev/core/fbcon_cw.c     | 146 ++++-----
 drivers/video/fbdev/core/fbcon_rotate.c |  40 +--
 drivers/video/fbdev/core/fbcon_rotate.h |   6 +-
 drivers/video/fbdev/core/fbcon_ud.c     | 162 ++++-----
 drivers/video/fbdev/core/softcursor.c   |  18 +-
 drivers/video/fbdev/core/tileblit.c     |  28 +-
 10 files changed, 541 insertions(+), 552 deletions(-)

diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index f9475c14f733..ebadc9619699 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -236,10 +236,10 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		       int fg, int bg)
 {
 	struct fb_cursor cursor;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 	int w = DIV_ROUND_UP(vc->vc_font.width, 8), c;
-	int y = real_y(ops->p, vc->state.y);
+	int y = real_y(par->p, vc->state.y);
 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
 	int err = 1;
 	char *src;
@@ -253,10 +253,10 @@ 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 (ops->cursor_state.image.data != src ||
-	    ops->cursor_reset) {
-	    ops->cursor_state.image.data = src;
-	    cursor.set |= FB_CUR_SETIMAGE;
+	if (par->cursor_state.image.data != src ||
+	    par->cursor_reset) {
+		par->cursor_state.image.data = src;
+		cursor.set |= FB_CUR_SETIMAGE;
 	}
 
 	if (attribute) {
@@ -265,46 +265,46 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
 		if (!dst)
 			return;
-		kfree(ops->cursor_data);
-		ops->cursor_data = dst;
+		kfree(par->cursor_data);
+		par->cursor_data = dst;
 		update_attr(dst, src, attribute, vc);
 		src = dst;
 	}
 
-	if (ops->cursor_state.image.fg_color != fg ||
-	    ops->cursor_state.image.bg_color != bg ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.fg_color = fg;
-		ops->cursor_state.image.bg_color = bg;
+	if (par->cursor_state.image.fg_color != fg ||
+	    par->cursor_state.image.bg_color != bg ||
+	    par->cursor_reset) {
+		par->cursor_state.image.fg_color = fg;
+		par->cursor_state.image.bg_color = bg;
 		cursor.set |= FB_CUR_SETCMAP;
 	}
 
-	if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->state.x)) ||
-	    (ops->cursor_state.image.dy != (vc->vc_font.height * y)) ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.dx = vc->vc_font.width * vc->state.x;
-		ops->cursor_state.image.dy = vc->vc_font.height * y;
+	if ((par->cursor_state.image.dx != (vc->vc_font.width * vc->state.x)) ||
+	    (par->cursor_state.image.dy != (vc->vc_font.height * y)) ||
+	    par->cursor_reset) {
+		par->cursor_state.image.dx = vc->vc_font.width * vc->state.x;
+		par->cursor_state.image.dy = vc->vc_font.height * y;
 		cursor.set |= FB_CUR_SETPOS;
 	}
 
-	if (ops->cursor_state.image.height != vc->vc_font.height ||
-	    ops->cursor_state.image.width != vc->vc_font.width ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.height = vc->vc_font.height;
-		ops->cursor_state.image.width = vc->vc_font.width;
+	if (par->cursor_state.image.height != vc->vc_font.height ||
+	    par->cursor_state.image.width != vc->vc_font.width ||
+	    par->cursor_reset) {
+		par->cursor_state.image.height = vc->vc_font.height;
+		par->cursor_state.image.width = vc->vc_font.width;
 		cursor.set |= FB_CUR_SETSIZE;
 	}
 
-	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
-	    ops->cursor_reset) {
-		ops->cursor_state.hot.x = cursor.hot.y = 0;
+	if (par->cursor_state.hot.x || par->cursor_state.hot.y ||
+	    par->cursor_reset) {
+		par->cursor_state.hot.x = cursor.hot.y = 0;
 		cursor.set |= FB_CUR_SETHOT;
 	}
 
 	if (cursor.set & FB_CUR_SETSIZE ||
-	    vc->vc_cursor_type != ops->p->cursor_shape ||
-	    ops->cursor_state.mask == NULL ||
-	    ops->cursor_reset) {
+	    vc->vc_cursor_type != par->p->cursor_shape ||
+	    par->cursor_state.mask == NULL ||
+	    par->cursor_reset) {
 		char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
 		int cur_height, size, i = 0;
 		u8 msk = 0xff;
@@ -312,13 +312,13 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		if (!mask)
 			return;
 
-		kfree(ops->cursor_state.mask);
-		ops->cursor_state.mask = mask;
+		kfree(par->cursor_state.mask);
+		par->cursor_state.mask = mask;
 
-		ops->p->cursor_shape = vc->vc_cursor_type;
+		par->p->cursor_shape = vc->vc_cursor_type;
 		cursor.set |= FB_CUR_SETSHAPE;
 
-		switch (CUR_SIZE(ops->p->cursor_shape)) {
+		switch (CUR_SIZE(par->p->cursor_shape)) {
 		case CUR_NONE:
 			cur_height = 0;
 			break;
@@ -347,19 +347,19 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 			mask[i++] = msk;
 	}
 
-	ops->cursor_state.enable = enable && !use_sw;
+	par->cursor_state.enable = enable && !use_sw;
 
 	cursor.image.data = src;
-	cursor.image.fg_color = ops->cursor_state.image.fg_color;
-	cursor.image.bg_color = ops->cursor_state.image.bg_color;
-	cursor.image.dx = ops->cursor_state.image.dx;
-	cursor.image.dy = ops->cursor_state.image.dy;
-	cursor.image.height = ops->cursor_state.image.height;
-	cursor.image.width = ops->cursor_state.image.width;
-	cursor.hot.x = ops->cursor_state.hot.x;
-	cursor.hot.y = ops->cursor_state.hot.y;
-	cursor.mask = ops->cursor_state.mask;
-	cursor.enable = ops->cursor_state.enable;
+	cursor.image.fg_color = par->cursor_state.image.fg_color;
+	cursor.image.bg_color = par->cursor_state.image.bg_color;
+	cursor.image.dx = par->cursor_state.image.dx;
+	cursor.image.dy = par->cursor_state.image.dy;
+	cursor.image.height = par->cursor_state.image.height;
+	cursor.image.width = par->cursor_state.image.width;
+	cursor.hot.x = par->cursor_state.hot.x;
+	cursor.hot.y = par->cursor_state.hot.y;
+	cursor.mask = par->cursor_state.mask;
+	cursor.enable = par->cursor_state.enable;
 	cursor.image.depth = 1;
 	cursor.rop = ROP_XOR;
 
@@ -369,31 +369,31 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	if (err)
 		soft_cursor(info, &cursor);
 
-	ops->cursor_reset = 0;
+	par->cursor_reset = 0;
 }
 
 static int bit_update_start(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int err;
 
-	err = fb_pan_display(info, &ops->var);
-	ops->var.xoffset = info->var.xoffset;
-	ops->var.yoffset = info->var.yoffset;
-	ops->var.vmode = info->var.vmode;
+	err = fb_pan_display(info, &par->var);
+	par->var.xoffset = info->var.xoffset;
+	par->var.yoffset = info->var.yoffset;
+	par->var.vmode = info->var.vmode;
 	return err;
 }
 
-void fbcon_set_bitops(struct fbcon_ops *ops)
+void fbcon_set_bitops(struct fbcon_par *par)
 {
-	ops->bmove = bit_bmove;
-	ops->clear = bit_clear;
-	ops->putcs = bit_putcs;
-	ops->clear_margins = bit_clear_margins;
-	ops->cursor = bit_cursor;
-	ops->update_start = bit_update_start;
-	ops->rotate_font = NULL;
-
-	if (ops->rotate)
-		fbcon_set_rotate(ops);
+	par->bmove = bit_bmove;
+	par->clear = bit_clear;
+	par->putcs = bit_putcs;
+	par->clear_margins = bit_clear_margins;
+	par->cursor = bit_cursor;
+	par->update_start = bit_update_start;
+	par->rotate_font = NULL;
+
+	if (par->rotate)
+		fbcon_set_rotate(par);
 }
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 55f5731e94c3..7f871ef3e624 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -198,27 +198,27 @@ static struct device *fbcon_device;
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
 static inline void fbcon_set_rotation(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	if (!(info->flags & FBINFO_MISC_TILEBLITTING) &&
-	    ops->p->con_rotate < 4)
-		ops->rotate = ops->p->con_rotate;
+	    par->p->con_rotate < 4)
+		par->rotate = par->p->con_rotate;
 	else
-		ops->rotate = 0;
+		par->rotate = 0;
 }
 
 static void fbcon_rotate(struct fb_info *info, u32 rotate)
 {
-	struct fbcon_ops *ops= info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fb_info *fb_info;
 
-	if (!ops || ops->currcon == -1)
+	if (!par || par->currcon == -1)
 		return;
 
-	fb_info = fbcon_info_from_console(ops->currcon);
+	fb_info = fbcon_info_from_console(par->currcon);
 
 	if (info == fb_info) {
-		struct fbcon_display *p = &fb_display[ops->currcon];
+		struct fbcon_display *p = &fb_display[par->currcon];
 
 		if (rotate < 4)
 			p->con_rotate = rotate;
@@ -231,12 +231,12 @@ static void fbcon_rotate(struct fb_info *info, u32 rotate)
 
 static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct vc_data *vc;
 	struct fbcon_display *p;
 	int i;
 
-	if (!ops || ops->currcon < 0 || rotate > 3)
+	if (!par || par->currcon < 0 || rotate > 3)
 		return;
 
 	for (i = first_fb_vc; i <= last_fb_vc; i++) {
@@ -254,9 +254,9 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
 #else
 static inline void fbcon_set_rotation(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
-	ops->rotate = FB_ROTATE_UR;
+	par->rotate = FB_ROTATE_UR;
 }
 
 static void fbcon_rotate(struct fb_info *info, u32 rotate)
@@ -272,9 +272,9 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
 
 static int fbcon_get_rotate(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
-	return (ops) ? ops->rotate : 0;
+	return (par) ? par->rotate : 0;
 }
 
 static bool fbcon_skip_panic(struct fb_info *info)
@@ -291,10 +291,10 @@ static bool fbcon_skip_panic(struct fb_info *info)
 
 static inline bool fbcon_is_active(struct vc_data *vc, struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	return info->state == FBINFO_STATE_RUNNING &&
-		vc->vc_mode == KD_TEXT && !ops->graphics && !fbcon_skip_panic(info);
+		vc->vc_mode == KD_TEXT && !par->graphics && !fbcon_skip_panic(info);
 }
 
 static int get_color(struct vc_data *vc, struct fb_info *info,
@@ -376,7 +376,7 @@ static int get_bg_color(struct vc_data *vc, struct fb_info *info, u16 c)
 
 static void fb_flashcursor(struct work_struct *work)
 {
-	struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work);
+	struct fbcon_par *par = container_of(work, struct fbcon_par, cursor_work.work);
 	struct fb_info *info;
 	struct vc_data *vc = NULL;
 	int c;
@@ -391,10 +391,10 @@ static void fb_flashcursor(struct work_struct *work)
 		return;
 
 	/* protected by console_lock */
-	info = ops->info;
+	info = par->info;
 
-	if (ops->currcon != -1)
-		vc = vc_cons[ops->currcon].d;
+	if (par->currcon != -1)
+		vc = vc_cons[par->currcon].d;
 
 	if (!vc || !con_is_visible(vc) ||
 	    fbcon_info_from_console(vc->vc_num) != info ||
@@ -404,30 +404,30 @@ static void fb_flashcursor(struct work_struct *work)
 	}
 
 	c = scr_readw((u16 *) vc->vc_pos);
-	enable = ops->cursor_flash && !ops->cursor_state.enable;
-	ops->cursor(vc, info, enable,
+	enable = par->cursor_flash && !par->cursor_state.enable;
+	par->cursor(vc, info, enable,
 		    get_fg_color(vc, info, c),
 		    get_bg_color(vc, info, c));
 	console_unlock();
 
-	queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
-			   ops->cur_blink_jiffies);
+	queue_delayed_work(system_power_efficient_wq, &par->cursor_work,
+			   par->cur_blink_jiffies);
 }
 
 static void fbcon_add_cursor_work(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	if (fbcon_cursor_blink)
-		queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
-				   ops->cur_blink_jiffies);
+		queue_delayed_work(system_power_efficient_wq, &par->cursor_work,
+				   par->cur_blink_jiffies);
 }
 
 static void fbcon_del_cursor_work(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
-	cancel_delayed_work_sync(&ops->cursor_work);
+	cancel_delayed_work_sync(&par->cursor_work);
 }
 
 #ifndef MODULE
@@ -587,7 +587,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
 			       int cols, int rows, int new_cols, int new_rows)
 {
 	/* Need to make room for the logo */
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int cnt, erase = vc->vc_video_erase_char, step;
 	unsigned short *save = NULL, *r, *q;
 	int logo_height;
@@ -603,7 +603,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
 	 */
 	if (fb_get_color_depth(&info->var, &info->fix) == 1)
 		erase &= ~0x400;
-	logo_height = fb_prepare_logo(info, ops->rotate);
+	logo_height = fb_prepare_logo(info, par->rotate);
 	logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height);
 	q = (unsigned short *) (vc->vc_origin +
 				vc->vc_size_row * rows);
@@ -675,15 +675,15 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
 #ifdef CONFIG_FB_TILEBLITTING
 static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
-	ops->p = &fb_display[vc->vc_num];
+	par->p = &fb_display[vc->vc_num];
 
 	if ((info->flags & FBINFO_MISC_TILEBLITTING))
 		fbcon_set_tileops(vc, info);
 	else {
 		fbcon_set_rotation(info);
-		fbcon_set_bitops(ops);
+		fbcon_set_bitops(par);
 	}
 }
 
@@ -700,12 +700,12 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
 #else
 static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	info->flags &= ~FBINFO_MISC_TILEBLITTING;
-	ops->p = &fb_display[vc->vc_num];
+	par->p = &fb_display[vc->vc_num];
 	fbcon_set_rotation(info);
-	fbcon_set_bitops(ops);
+	fbcon_set_bitops(par);
 }
 
 static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
@@ -725,13 +725,13 @@ static void fbcon_release(struct fb_info *info)
 	module_put(info->fbops->owner);
 
 	if (info->fbcon_par) {
-		struct fbcon_ops *ops = info->fbcon_par;
+		struct fbcon_par *par = info->fbcon_par;
 
 		fbcon_del_cursor_work(info);
-		kfree(ops->cursor_state.mask);
-		kfree(ops->cursor_data);
-		kfree(ops->cursor_src);
-		kfree(ops->fontbuffer);
+		kfree(par->cursor_state.mask);
+		kfree(par->cursor_data);
+		kfree(par->cursor_src);
+		kfree(par->fontbuffer);
 		kfree(info->fbcon_par);
 		info->fbcon_par = NULL;
 	}
@@ -739,7 +739,7 @@ static void fbcon_release(struct fb_info *info)
 
 static int fbcon_open(struct fb_info *info)
 {
-	struct fbcon_ops *ops;
+	struct fbcon_par *par;
 
 	if (!try_module_get(info->fbops->owner))
 		return -ENODEV;
@@ -753,16 +753,16 @@ static int fbcon_open(struct fb_info *info)
 	}
 	unlock_fb_info(info);
 
-	ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
-	if (!ops) {
+	par = kzalloc(sizeof(*par), GFP_KERNEL);
+	if (!par) {
 		fbcon_release(info);
 		return -ENOMEM;
 	}
 
-	INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
-	ops->info = info;
-	info->fbcon_par = ops;
-	ops->cur_blink_jiffies = HZ / 5;
+	INIT_DELAYED_WORK(&par->cursor_work, fb_flashcursor);
+	par->info = info;
+	info->fbcon_par = par;
+	par->cur_blink_jiffies = HZ / 5;
 
 	return 0;
 }
@@ -809,12 +809,12 @@ static void con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
 static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
 				int unit, int show_logo)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int ret;
 
-	ops->currcon = fg_console;
+	par->currcon = fg_console;
 
-	if (info->fbops->fb_set_par && !ops->initialized) {
+	if (info->fbops->fb_set_par && !par->initialized) {
 		ret = info->fbops->fb_set_par(info);
 
 		if (ret)
@@ -823,8 +823,8 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
 				"error code %d\n", ret);
 	}
 
-	ops->initialized = true;
-	ops->graphics = 0;
+	par->initialized = true;
+	par->graphics = 0;
 	fbcon_set_disp(info, &info->var, unit);
 
 	if (show_logo) {
@@ -961,7 +961,7 @@ static const char *fbcon_startup(void)
 	struct vc_data *vc = vc_cons[fg_console].d;
 	const struct font_desc *font = NULL;
 	struct fb_info *info = NULL;
-	struct fbcon_ops *ops;
+	struct fbcon_par *par;
 	int rows, cols;
 
 	/*
@@ -981,10 +981,10 @@ static const char *fbcon_startup(void)
 	if (fbcon_open(info))
 		return NULL;
 
-	ops = info->fbcon_par;
-	ops->currcon = -1;
-	ops->graphics = 1;
-	ops->cur_rotate = -1;
+	par = info->fbcon_par;
+	par->currcon = -1;
+	par->graphics = 1;
+	par->cur_rotate = -1;
 
 	p->con_rotate = initial_rotation;
 	if (p->con_rotate == -1)
@@ -1007,8 +1007,8 @@ static const char *fbcon_startup(void)
 		vc->vc_font.charcount = font->charcount;
 	}
 
-	cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
-	rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+	cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
+	rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
 	cols /= vc->vc_font.width;
 	rows /= vc->vc_font.height;
 	vc_resize(vc, cols, rows);
@@ -1026,7 +1026,7 @@ static const char *fbcon_startup(void)
 static void fbcon_init(struct vc_data *vc, bool init)
 {
 	struct fb_info *info;
-	struct fbcon_ops *ops;
+	struct fbcon_par *par;
 	struct vc_data **default_mode = vc->vc_display_fg;
 	struct vc_data *svc = *default_mode;
 	struct fbcon_display *t, *p = &fb_display[vc->vc_num];
@@ -1100,8 +1100,8 @@ static void fbcon_init(struct vc_data *vc, bool init)
 	if (!*vc->uni_pagedict_loc)
 		con_copy_unimap(vc, svc);
 
-	ops = info->fbcon_par;
-	ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+	par = info->fbcon_par;
+	par->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
 
 	p->con_rotate = initial_rotation;
 	if (p->con_rotate == -1)
@@ -1113,8 +1113,8 @@ static void fbcon_init(struct vc_data *vc, bool init)
 
 	cols = vc->vc_cols;
 	rows = vc->vc_rows;
-	new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
-	new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+	new_cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
+	new_rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
 	new_cols /= vc->vc_font.width;
 	new_rows /= vc->vc_font.height;
 
@@ -1126,7 +1126,7 @@ static void fbcon_init(struct vc_data *vc, bool init)
 	 * We need to do it in fbcon_init() to prevent screen corruption.
 	 */
 	if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) {
-		if (info->fbops->fb_set_par && !ops->initialized) {
+		if (info->fbops->fb_set_par && !par->initialized) {
 			ret = info->fbops->fb_set_par(info);
 
 			if (ret)
@@ -1135,10 +1135,10 @@ static void fbcon_init(struct vc_data *vc, bool init)
 					"error code %d\n", ret);
 		}
 
-		ops->initialized = true;
+		par->initialized = true;
 	}
 
-	ops->graphics = 0;
+	par->graphics = 0;
 
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
 	if ((info->flags & FBINFO_HWACCEL_COPYAREA) &&
@@ -1162,12 +1162,12 @@ static void fbcon_init(struct vc_data *vc, bool init)
 	if (logo)
 		fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
 
-	if (ops->rotate_font && ops->rotate_font(info, vc)) {
-		ops->rotate = FB_ROTATE_UR;
+	if (par->rotate_font && par->rotate_font(info, vc)) {
+		par->rotate = FB_ROTATE_UR;
 		set_blitting_type(vc, info);
 	}
 
-	ops->p = &fb_display[fg_console];
+	par->p = &fb_display[fg_console];
 }
 
 static void fbcon_free_font(struct fbcon_display *p)
@@ -1205,7 +1205,7 @@ static void fbcon_deinit(struct vc_data *vc)
 {
 	struct fbcon_display *p = &fb_display[vc->vc_num];
 	struct fb_info *info;
-	struct fbcon_ops *ops;
+	struct fbcon_par *par;
 	int idx;
 
 	fbcon_free_font(p);
@@ -1219,15 +1219,15 @@ static void fbcon_deinit(struct vc_data *vc)
 	if (!info)
 		goto finished;
 
-	ops = info->fbcon_par;
+	par = info->fbcon_par;
 
-	if (!ops)
+	if (!par)
 		goto finished;
 
 	if (con_is_visible(vc))
 		fbcon_del_cursor_work(info);
 
-	ops->initialized = false;
+	par->initialized = false;
 finished:
 
 	fbcon_free_font(p);
@@ -1274,7 +1274,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
 			  unsigned int height, unsigned int width)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int fg, bg;
 	struct fbcon_display *p = &fb_display[vc->vc_num];
 	u_int y_break;
@@ -1289,7 +1289,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
 		vc->vc_top = 0;
 		/*
 		 * If the font dimensions are not an integral of the display
-		 * dimensions then the ops->clear below won't end up clearing
+		 * dimensions then the par->clear below won't end up clearing
 		 * the margins.  Call clear_margins here in case the logo
 		 * bitmap stretched into the margin area.
 		 */
@@ -1303,11 +1303,10 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
 	y_break = p->vrows - p->yscroll;
 	if (sy < y_break && sy + height - 1 >= y_break) {
 		u_int b = y_break - sy;
-		ops->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg);
-		ops->clear(vc, info, real_y(p, sy + b), sx, height - b,
-				 width, fg, bg);
+		par->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg);
+		par->clear(vc, info, real_y(p, sy + b), sx, height - b, width, fg, bg);
 	} else
-		ops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg);
+		par->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg);
 }
 
 static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
@@ -1321,10 +1320,10 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
 	struct fbcon_display *p = &fb_display[vc->vc_num];
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	if (fbcon_is_active(vc, info))
-		ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
+		par->putcs(vc, info, s, count, real_y(p, ypos), xpos,
 			   get_fg_color(vc, info, scr_readw(s)),
 			   get_bg_color(vc, info, scr_readw(s)));
 }
@@ -1332,19 +1331,19 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	if (fbcon_is_active(vc, info))
-		ops->clear_margins(vc, info, margin_color, bottom_only);
+		par->clear_margins(vc, info, margin_color, bottom_only);
 }
 
 static void fbcon_cursor(struct vc_data *vc, bool enable)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
  	int c = scr_readw((u16 *) vc->vc_pos);
 
-	ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+	par->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
 
 	if (!fbcon_is_active(vc, info) || vc->vc_deccm != 1)
 		return;
@@ -1354,12 +1353,12 @@ static void fbcon_cursor(struct vc_data *vc, bool enable)
 	else
 		fbcon_add_cursor_work(info);
 
-	ops->cursor_flash = enable;
+	par->cursor_flash = enable;
 
-	if (!ops->cursor)
+	if (!par->cursor)
 		return;
 
-	ops->cursor(vc, info, enable,
+	par->cursor(vc, info, enable,
 		    get_fg_color(vc, info, c),
 		    get_bg_color(vc, info, c));
 }
@@ -1374,7 +1373,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
 	struct fbcon_display *p, *t;
 	struct vc_data **default_mode, *vc;
 	struct vc_data *svc;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int rows, cols;
 	unsigned long ret = 0;
 
@@ -1407,7 +1406,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
 	var->yoffset = info->var.yoffset;
 	var->xoffset = info->var.xoffset;
 	fb_set_var(info, var);
-	ops->var = info->var;
+	par->var = info->var;
 	vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
 	if (vc->vc_font.charcount == 256) {
@@ -1423,8 +1422,8 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
 	if (!*vc->uni_pagedict_loc)
 		con_copy_unimap(vc, svc);
 
-	cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
-	rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+	cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
+	rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
 	cols /= vc->vc_font.width;
 	rows /= vc->vc_font.height;
 	ret = vc_resize(vc, cols, rows);
@@ -1436,16 +1435,16 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
 static __inline__ void ywrap_up(struct vc_data *vc, int count)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fbcon_display *p = &fb_display[vc->vc_num];
 
 	p->yscroll += count;
 	if (p->yscroll >= p->vrows)	/* Deal with wrap */
 		p->yscroll -= p->vrows;
-	ops->var.xoffset = 0;
-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
-	ops->var.vmode |= FB_VMODE_YWRAP;
-	ops->update_start(info);
+	par->var.xoffset = 0;
+	par->var.yoffset = p->yscroll * vc->vc_font.height;
+	par->var.vmode |= FB_VMODE_YWRAP;
+	par->update_start(info);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
 		scrollback_max = scrollback_phys_max;
@@ -1455,16 +1454,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count)
 static __inline__ void ywrap_down(struct vc_data *vc, int count)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fbcon_display *p = &fb_display[vc->vc_num];
 
 	p->yscroll -= count;
 	if (p->yscroll < 0)	/* Deal with wrap */
 		p->yscroll += p->vrows;
-	ops->var.xoffset = 0;
-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
-	ops->var.vmode |= FB_VMODE_YWRAP;
-	ops->update_start(info);
+	par->var.xoffset = 0;
+	par->var.yoffset = p->yscroll * vc->vc_font.height;
+	par->var.vmode |= FB_VMODE_YWRAP;
+	par->update_start(info);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
 		scrollback_max = 0;
@@ -1475,19 +1474,19 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
 	struct fbcon_display *p = &fb_display[vc->vc_num];
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	p->yscroll += count;
 	if (p->yscroll > p->vrows - vc->vc_rows) {
-		ops->bmove(vc, info, p->vrows - vc->vc_rows,
+		par->bmove(vc, info, p->vrows - vc->vc_rows,
 			    0, 0, 0, vc->vc_rows, vc->vc_cols);
 		p->yscroll -= p->vrows - vc->vc_rows;
 	}
 
-	ops->var.xoffset = 0;
-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
-	ops->var.vmode &= ~FB_VMODE_YWRAP;
-	ops->update_start(info);
+	par->var.xoffset = 0;
+	par->var.yoffset = p->yscroll * vc->vc_font.height;
+	par->var.vmode &= ~FB_VMODE_YWRAP;
+	par->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
@@ -1498,7 +1497,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
 static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fbcon_display *p = &fb_display[vc->vc_num];
 
 	p->yscroll += count;
@@ -1508,10 +1507,10 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
 		fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
 	}
 
-	ops->var.xoffset = 0;
-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
-	ops->var.vmode &= ~FB_VMODE_YWRAP;
-	ops->update_start(info);
+	par->var.xoffset = 0;
+	par->var.yoffset = p->yscroll * vc->vc_font.height;
+	par->var.vmode &= ~FB_VMODE_YWRAP;
+	par->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
@@ -1523,19 +1522,19 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
 	struct fbcon_display *p = &fb_display[vc->vc_num];
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	p->yscroll -= count;
 	if (p->yscroll < 0) {
-		ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
+		par->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
 			    0, vc->vc_rows, vc->vc_cols);
 		p->yscroll += p->vrows - vc->vc_rows;
 	}
 
-	ops->var.xoffset = 0;
-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
-	ops->var.vmode &= ~FB_VMODE_YWRAP;
-	ops->update_start(info);
+	par->var.xoffset = 0;
+	par->var.yoffset = p->yscroll * vc->vc_font.height;
+	par->var.vmode &= ~FB_VMODE_YWRAP;
+	par->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
@@ -1546,7 +1545,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
 static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fbcon_display *p = &fb_display[vc->vc_num];
 
 	p->yscroll -= count;
@@ -1556,10 +1555,10 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
 		fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
 	}
 
-	ops->var.xoffset = 0;
-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
-	ops->var.vmode &= ~FB_VMODE_YWRAP;
-	ops->update_start(info);
+	par->var.xoffset = 0;
+	par->var.yoffset = p->yscroll * vc->vc_font.height;
+	par->var.vmode &= ~FB_VMODE_YWRAP;
+	par->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
@@ -1608,7 +1607,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
 	unsigned short *d = (unsigned short *)
 	    (vc->vc_origin + vc->vc_size_row * line);
 	unsigned short *s = d + offset;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	while (count--) {
 		unsigned short *start = s;
@@ -1621,8 +1620,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
 
 			if (c == scr_readw(d)) {
 				if (s > start) {
-					ops->bmove(vc, info, line + ycount, x,
-						   line, x, 1, s-start);
+					par->bmove(vc, info, line + ycount, x,
+						   line, x, 1, s - start);
 					x += s - start + 1;
 					start = s + 1;
 				} else {
@@ -1637,8 +1636,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
 			d++;
 		} while (s < le);
 		if (s > start)
-			ops->bmove(vc, info, line + ycount, x, line, x, 1,
-				   s-start);
+			par->bmove(vc, info, line + ycount, x, line, x, 1, s - start);
 		console_conditional_schedule();
 		if (ycount > 0)
 			line++;
@@ -1709,7 +1707,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy,
 			    int dy, int dx, int height, int width, u_int y_break)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	u_int b;
 
 	if (sy < y_break && sy + height > y_break) {
@@ -1743,8 +1741,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy,
 		}
 		return;
 	}
-	ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
-		   height, width);
+	par->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
 }
 
 static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
@@ -1971,15 +1968,13 @@ static void updatescrollmode_accel(struct fbcon_display *p,
 					struct vc_data *vc)
 {
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int cap = info->flags;
 	u16 t = 0;
-	int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
-				  info->fix.xpanstep);
-	int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
-	int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
-	int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
-				   info->var.xres_virtual);
+	int ypan = FBCON_SWAP(par->rotate, info->fix.ypanstep, info->fix.xpanstep);
+	int ywrap = FBCON_SWAP(par->rotate, info->fix.ywrapstep, t);
+	int yres = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
+	int vyres = FBCON_SWAP(par->rotate, info->var.yres_virtual, info->var.xres_virtual);
 	int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
 		divides(ypan, vc->vc_font.height) && vyres > yres;
 	int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
@@ -2012,11 +2007,10 @@ static void updatescrollmode(struct fbcon_display *p,
 					struct fb_info *info,
 					struct vc_data *vc)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int fh = vc->vc_font.height;
-	int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
-	int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
-				   info->var.xres_virtual);
+	int yres = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
+	int vyres = FBCON_SWAP(par->rotate, info->var.yres_virtual, info->var.xres_virtual);
 
 	p->vrows = vyres/fh;
 	if (yres > (fh * (vc->vc_rows + 1)))
@@ -2035,7 +2029,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
 			unsigned int height, bool from_user)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fbcon_display *p = &fb_display[vc->vc_num];
 	struct fb_var_screeninfo var = info->var;
 	int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
@@ -2058,12 +2052,10 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
 			return -EINVAL;
 	}
 
-	virt_w = FBCON_SWAP(ops->rotate, width, height);
-	virt_h = FBCON_SWAP(ops->rotate, height, width);
-	virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
-				 vc->vc_font.height);
-	virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height,
-				 vc->vc_font.width);
+	virt_w = FBCON_SWAP(par->rotate, width, height);
+	virt_h = FBCON_SWAP(par->rotate, height, width);
+	virt_fw = FBCON_SWAP(par->rotate, vc->vc_font.width, vc->vc_font.height);
+	virt_fh = FBCON_SWAP(par->rotate, vc->vc_font.height, vc->vc_font.width);
 	var.xres = virt_w * virt_fw;
 	var.yres = virt_h * virt_fh;
 	x_diff = info->var.xres - var.xres;
@@ -2089,7 +2081,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
 			fb_set_var(info, &var);
 		}
 		var_to_display(p, &info->var, info);
-		ops->var = info->var;
+		par->var = info->var;
 	}
 	updatescrollmode(p, info, vc);
 	return 0;
@@ -2098,13 +2090,13 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
 static bool fbcon_switch(struct vc_data *vc)
 {
 	struct fb_info *info, *old_info = NULL;
-	struct fbcon_ops *ops;
+	struct fbcon_par *par;
 	struct fbcon_display *p = &fb_display[vc->vc_num];
 	struct fb_var_screeninfo var;
 	int i, ret, prev_console;
 
 	info = fbcon_info_from_console(vc->vc_num);
-	ops = info->fbcon_par;
+	par = info->fbcon_par;
 
 	if (logo_shown >= 0) {
 		struct vc_data *conp2 = vc_cons[logo_shown].d;
@@ -2115,7 +2107,7 @@ static bool fbcon_switch(struct vc_data *vc)
 		logo_shown = FBCON_LOGO_CANSHOW;
 	}
 
-	prev_console = ops->currcon;
+	prev_console = par->currcon;
 	if (prev_console != -1)
 		old_info = fbcon_info_from_console(prev_console);
 	/*
@@ -2128,9 +2120,9 @@ static bool fbcon_switch(struct vc_data *vc)
 	 */
 	fbcon_for_each_registered_fb(i) {
 		if (fbcon_registered_fb[i]->fbcon_par) {
-			struct fbcon_ops *o = fbcon_registered_fb[i]->fbcon_par;
+			struct fbcon_par *par = fbcon_registered_fb[i]->fbcon_par;
 
-			o->currcon = vc->vc_num;
+			par->currcon = vc->vc_num;
 		}
 	}
 	memset(&var, 0, sizeof(struct fb_var_screeninfo));
@@ -2144,7 +2136,7 @@ static bool fbcon_switch(struct vc_data *vc)
 	info->var.activate = var.activate;
 	var.vmode |= info->var.vmode & ~FB_VMODE_MASK;
 	fb_set_var(info, &var);
-	ops->var = info->var;
+	par->var = info->var;
 
 	if (old_info != NULL && (old_info != info ||
 				 info->flags & FBINFO_MISC_ALWAYS_SETPAR)) {
@@ -2161,17 +2153,16 @@ static bool fbcon_switch(struct vc_data *vc)
 			fbcon_del_cursor_work(old_info);
 	}
 
-	if (!fbcon_is_active(vc, info) ||
-	    ops->blank_state != FB_BLANK_UNBLANK)
+	if (!fbcon_is_active(vc, info) || par->blank_state != FB_BLANK_UNBLANK)
 		fbcon_del_cursor_work(info);
 	else
 		fbcon_add_cursor_work(info);
 
 	set_blitting_type(vc, info);
-	ops->cursor_reset = 1;
+	par->cursor_reset = 1;
 
-	if (ops->rotate_font && ops->rotate_font(info, vc)) {
-		ops->rotate = FB_ROTATE_UR;
+	if (par->rotate_font && par->rotate_font(info, vc)) {
+		par->rotate = FB_ROTATE_UR;
 		set_blitting_type(vc, info);
 	}
 
@@ -2202,8 +2193,8 @@ static bool fbcon_switch(struct vc_data *vc)
 	scrollback_current = 0;
 
 	if (fbcon_is_active(vc, info)) {
-	    ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
-	    ops->update_start(info);
+		par->var.xoffset = par->var.yoffset = p->yscroll = 0;
+		par->update_start(info);
 	}
 
 	fbcon_set_palette(vc, color_table);
@@ -2212,7 +2203,7 @@ static bool fbcon_switch(struct vc_data *vc)
 	if (logo_shown == FBCON_LOGO_DRAW) {
 
 		logo_shown = fg_console;
-		fb_show_logo(info, ops->rotate);
+		fb_show_logo(info, par->rotate);
 		update_region(vc,
 			      vc->vc_origin + vc->vc_size_row * vc->vc_top,
 			      vc->vc_size_row * (vc->vc_bottom -
@@ -2241,27 +2232,27 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
 			bool mode_switch)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
 	if (mode_switch) {
 		struct fb_var_screeninfo var = info->var;
 
-		ops->graphics = 1;
+		par->graphics = 1;
 
 		if (!blank) {
 			var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE |
 				FB_ACTIVATE_KD_TEXT;
 			fb_set_var(info, &var);
-			ops->graphics = 0;
-			ops->var = info->var;
+			par->graphics = 0;
+			par->var = info->var;
 		}
 	}
 
 	if (fbcon_is_active(vc, info)) {
-		if (ops->blank_state != blank) {
-			ops->blank_state = blank;
+		if (par->blank_state != blank) {
+			par->blank_state = blank;
 			fbcon_cursor(vc, !blank);
-			ops->cursor_flash = (!blank);
+			par->cursor_flash = (!blank);
 
 			if (fb_blank(info, blank))
 				fbcon_generic_blank(vc, info, blank);
@@ -2271,8 +2262,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
 			update_screen(vc);
 	}
 
-	if (mode_switch || !fbcon_is_active(vc, info) ||
-	    ops->blank_state != FB_BLANK_UNBLANK)
+	if (mode_switch || !fbcon_is_active(vc, info) || par->blank_state != FB_BLANK_UNBLANK)
 		fbcon_del_cursor_work(info);
 	else
 		fbcon_add_cursor_work(info);
@@ -2283,10 +2273,10 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
 static void fbcon_debug_enter(struct vc_data *vc)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
-	ops->save_graphics = ops->graphics;
-	ops->graphics = 0;
+	par->save_graphics = par->graphics;
+	par->graphics = 0;
 	if (info->fbops->fb_debug_enter)
 		info->fbops->fb_debug_enter(info);
 	fbcon_set_palette(vc, color_table);
@@ -2295,9 +2285,9 @@ static void fbcon_debug_enter(struct vc_data *vc)
 static void fbcon_debug_leave(struct vc_data *vc)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
-	ops->graphics = ops->save_graphics;
+	par->graphics = par->save_graphics;
 	if (info->fbops->fb_debug_leave)
 		info->fbops->fb_debug_leave(info);
 }
@@ -2432,7 +2422,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
 			     const u8 * data, int userfont)
 {
 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
-	struct fbcon_ops *ops = info->fbcon_par;
+	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;
@@ -2458,8 +2448,8 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
 	if (resize) {
 		int cols, rows;
 
-		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
-		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+		cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
+		rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
 		cols /= w;
 		rows /= h;
 		ret = vc_resize(vc, cols, rows);
@@ -2651,11 +2641,11 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
 void fbcon_suspended(struct fb_info *info)
 {
 	struct vc_data *vc = NULL;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
-	if (!ops || ops->currcon < 0)
+	if (!par || par->currcon < 0)
 		return;
-	vc = vc_cons[ops->currcon].d;
+	vc = vc_cons[par->currcon].d;
 
 	/* Clear cursor, restore saved data */
 	fbcon_cursor(vc, false);
@@ -2664,27 +2654,27 @@ void fbcon_suspended(struct fb_info *info)
 void fbcon_resumed(struct fb_info *info)
 {
 	struct vc_data *vc;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
-	if (!ops || ops->currcon < 0)
+	if (!par || par->currcon < 0)
 		return;
-	vc = vc_cons[ops->currcon].d;
+	vc = vc_cons[par->currcon].d;
 
 	update_screen(vc);
 }
 
 static void fbcon_modechanged(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct vc_data *vc;
 	struct fbcon_display *p;
 	int rows, cols;
 
-	if (!ops || ops->currcon < 0)
+	if (!par || par->currcon < 0)
 		return;
-	vc = vc_cons[ops->currcon].d;
+	vc = vc_cons[par->currcon].d;
 	if (vc->vc_mode != KD_TEXT ||
-	    fbcon_info_from_console(ops->currcon) != info)
+	    fbcon_info_from_console(par->currcon) != info)
 		return;
 
 	p = &fb_display[vc->vc_num];
@@ -2692,8 +2682,8 @@ static void fbcon_modechanged(struct fb_info *info)
 
 	if (con_is_visible(vc)) {
 		var_to_display(p, &info->var, info);
-		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
-		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+		cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
+		rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
 		cols /= vc->vc_font.width;
 		rows /= vc->vc_font.height;
 		vc_resize(vc, cols, rows);
@@ -2702,8 +2692,8 @@ static void fbcon_modechanged(struct fb_info *info)
 		scrollback_current = 0;
 
 		if (fbcon_is_active(vc, info)) {
-		    ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
-		    ops->update_start(info);
+			par->var.xoffset = par->var.yoffset = p->yscroll = 0;
+			par->update_start(info);
 		}
 
 		fbcon_set_palette(vc, color_table);
@@ -2713,12 +2703,12 @@ static void fbcon_modechanged(struct fb_info *info)
 
 static void fbcon_set_all_vcs(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct vc_data *vc;
 	struct fbcon_display *p;
 	int i, rows, cols, fg = -1;
 
-	if (!ops || ops->currcon < 0)
+	if (!par || par->currcon < 0)
 		return;
 
 	for (i = first_fb_vc; i <= last_fb_vc; i++) {
@@ -2735,8 +2725,8 @@ static void fbcon_set_all_vcs(struct fb_info *info)
 		p = &fb_display[vc->vc_num];
 		set_blitting_type(vc, info);
 		var_to_display(p, &info->var, info);
-		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
-		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+		cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
+		rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
 		cols /= vc->vc_font.width;
 		rows /= vc->vc_font.height;
 		vc_resize(vc, cols, rows);
@@ -2759,13 +2749,13 @@ EXPORT_SYMBOL(fbcon_update_vcs);
 /* let fbcon check if it supports a new screen resolution */
 int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct vc_data *vc;
 	unsigned int i;
 
 	WARN_CONSOLE_UNLOCKED();
 
-	if (!ops)
+	if (!par)
 		return 0;
 
 	/* prevent setting a screen size which is smaller than font size */
@@ -3037,15 +3027,14 @@ int fbcon_fb_registered(struct fb_info *info)
 
 void fbcon_fb_blanked(struct fb_info *info, int blank)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct vc_data *vc;
 
-	if (!ops || ops->currcon < 0)
+	if (!par || par->currcon < 0)
 		return;
 
-	vc = vc_cons[ops->currcon].d;
-	if (vc->vc_mode != KD_TEXT ||
-			fbcon_info_from_console(ops->currcon) != info)
+	vc = vc_cons[par->currcon].d;
+	if (vc->vc_mode != KD_TEXT || fbcon_info_from_console(par->currcon) != info)
 		return;
 
 	if (con_is_visible(vc)) {
@@ -3054,7 +3043,7 @@ void fbcon_fb_blanked(struct fb_info *info, int blank)
 		else
 			do_unblank_screen(0);
 	}
-	ops->blank_state = blank;
+	par->blank_state = blank;
 }
 
 void fbcon_new_modelist(struct fb_info *info)
@@ -3244,7 +3233,7 @@ static ssize_t cursor_blink_show(struct device *device,
 				 struct device_attribute *attr, char *buf)
 {
 	struct fb_info *info;
-	struct fbcon_ops *ops;
+	struct fbcon_par *par;
 	int idx, blink = -1;
 
 	console_lock();
@@ -3254,12 +3243,12 @@ static ssize_t cursor_blink_show(struct device *device,
 		goto err;
 
 	info = fbcon_registered_fb[idx];
-	ops = info->fbcon_par;
+	par = info->fbcon_par;
 
-	if (!ops)
+	if (!par)
 		goto err;
 
-	blink = delayed_work_pending(&ops->cursor_work);
+	blink = delayed_work_pending(&par->cursor_work);
 err:
 	console_unlock();
 	return sysfs_emit(buf, "%d\n", blink);
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index c535d8f84356..94991a1ba11f 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -51,7 +51,7 @@ struct fbcon_display {
     const struct fb_videomode *mode;
 };
 
-struct fbcon_ops {
+struct fbcon_par {
 	void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
 		      int sx, int dy, int dx, int height, int width);
 	void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
@@ -186,7 +186,7 @@ static inline u_short fb_scrollmode(struct fbcon_display *fb)
 #ifdef CONFIG_FB_TILEBLITTING
 extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
 #endif
-extern void fbcon_set_bitops(struct fbcon_ops *ops);
+extern void fbcon_set_bitops(struct fbcon_par *par);
 extern int  soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
 
 #define FBCON_ATTRIBUTE_UNDERLINE 1
@@ -225,7 +225,7 @@ static inline int get_attribute(struct fb_info *info, u16 c)
         (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; })
 
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
-extern void fbcon_set_rotate(struct fbcon_ops *ops);
+extern void fbcon_set_rotate(struct fbcon_par *par);
 #else
 #define fbcon_set_rotate(x) do {} while(0)
 #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 89ef4ba7e867..2ba8ec4c3e2b 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -63,9 +63,9 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
 static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int dy, int dx, int height, int width)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fb_copyarea area;
-	u32 vyres = GETVYRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
 
 	area.sx = sy * vc->vc_font.height;
 	area.sy = vyres - ((sx + width) * vc->vc_font.width);
@@ -80,9 +80,9 @@ static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int height, int width, int fg, int bg)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fb_fillrect region;
-	u32 vyres = GETVYRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
 
 	region.color = bg;
 	region.dx = sy * vc->vc_font.height;
@@ -99,13 +99,13 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
 				    u32 d_pitch, u32 s_pitch, u32 cellsize,
 				    struct fb_image *image, u8 *buf, u8 *dst)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 	u32 idx = (vc->vc_font.height + 7) >> 3;
 	u8 *src;
 
 	while (cnt--) {
-		src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+		src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize;
 
 		if (attr) {
 			ccw_update_attr(buf, src, attr, vc);
@@ -130,7 +130,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
 		      int fg, int bg)
 {
 	struct fb_image image;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	u32 width = (vc->vc_font.height + 7)/8;
 	u32 cellsize = width * vc->vc_font.width;
 	u32 maxcnt = info->pixmap.size/cellsize;
@@ -139,9 +139,9 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
 	u32 cnt, pitch, size;
 	u32 attribute = get_attribute(info, scr_readw(s));
 	u8 *dst, *buf = NULL;
-	u32 vyres = GETVYRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
 
-	if (!ops->fontbuffer)
+	if (!par->fontbuffer)
 		return;
 
 	image.fg_color = fg;
@@ -221,28 +221,28 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		       int fg, int bg)
 {
 	struct fb_cursor cursor;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 	int w = (vc->vc_font.height + 7) >> 3, c;
-	int y = real_y(ops->p, vc->state.y);
+	int y = real_y(par->p, vc->state.y);
 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
 	int err = 1, dx, dy;
 	char *src;
-	u32 vyres = GETVYRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
 
-	if (!ops->fontbuffer)
+	if (!par->fontbuffer)
 		return;
 
 	cursor.set = 0;
 
  	c = scr_readw((u16 *) vc->vc_pos);
 	attribute = get_attribute(info, c);
-	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+	src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
 
-	if (ops->cursor_state.image.data != src ||
-	    ops->cursor_reset) {
-	    ops->cursor_state.image.data = src;
-	    cursor.set |= FB_CUR_SETIMAGE;
+	if (par->cursor_state.image.data != src ||
+	    par->cursor_reset) {
+		par->cursor_state.image.data = src;
+		cursor.set |= FB_CUR_SETIMAGE;
 	}
 
 	if (attribute) {
@@ -251,49 +251,49 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
 		if (!dst)
 			return;
-		kfree(ops->cursor_data);
-		ops->cursor_data = dst;
+		kfree(par->cursor_data);
+		par->cursor_data = dst;
 		ccw_update_attr(dst, src, attribute, vc);
 		src = dst;
 	}
 
-	if (ops->cursor_state.image.fg_color != fg ||
-	    ops->cursor_state.image.bg_color != bg ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.fg_color = fg;
-		ops->cursor_state.image.bg_color = bg;
+	if (par->cursor_state.image.fg_color != fg ||
+	    par->cursor_state.image.bg_color != bg ||
+	    par->cursor_reset) {
+		par->cursor_state.image.fg_color = fg;
+		par->cursor_state.image.bg_color = bg;
 		cursor.set |= FB_CUR_SETCMAP;
 	}
 
-	if (ops->cursor_state.image.height != vc->vc_font.width ||
-	    ops->cursor_state.image.width != vc->vc_font.height ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.height = vc->vc_font.width;
-		ops->cursor_state.image.width = vc->vc_font.height;
+	if (par->cursor_state.image.height != vc->vc_font.width ||
+	    par->cursor_state.image.width != vc->vc_font.height ||
+	    par->cursor_reset) {
+		par->cursor_state.image.height = vc->vc_font.width;
+		par->cursor_state.image.width = vc->vc_font.height;
 		cursor.set |= FB_CUR_SETSIZE;
 	}
 
 	dx = y * vc->vc_font.height;
 	dy = vyres - ((vc->state.x + 1) * vc->vc_font.width);
 
-	if (ops->cursor_state.image.dx != dx ||
-	    ops->cursor_state.image.dy != dy ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.dx = dx;
-		ops->cursor_state.image.dy = dy;
+	if (par->cursor_state.image.dx != dx ||
+	    par->cursor_state.image.dy != dy ||
+	    par->cursor_reset) {
+		par->cursor_state.image.dx = dx;
+		par->cursor_state.image.dy = dy;
 		cursor.set |= FB_CUR_SETPOS;
 	}
 
-	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
-	    ops->cursor_reset) {
-		ops->cursor_state.hot.x = cursor.hot.y = 0;
+	if (par->cursor_state.hot.x || par->cursor_state.hot.y ||
+	    par->cursor_reset) {
+		par->cursor_state.hot.x = cursor.hot.y = 0;
 		cursor.set |= FB_CUR_SETHOT;
 	}
 
 	if (cursor.set & FB_CUR_SETSIZE ||
-	    vc->vc_cursor_type != ops->p->cursor_shape ||
-	    ops->cursor_state.mask == NULL ||
-	    ops->cursor_reset) {
+	    vc->vc_cursor_type != par->p->cursor_shape ||
+	    par->cursor_state.mask == NULL ||
+	    par->cursor_reset) {
 		char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
 						 GFP_ATOMIC);
 		int cur_height, size, i = 0;
@@ -309,13 +309,13 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 			return;
 		}
 
-		kfree(ops->cursor_state.mask);
-		ops->cursor_state.mask = mask;
+		kfree(par->cursor_state.mask);
+		par->cursor_state.mask = mask;
 
-		ops->p->cursor_shape = vc->vc_cursor_type;
+		par->p->cursor_shape = vc->vc_cursor_type;
 		cursor.set |= FB_CUR_SETSHAPE;
 
-		switch (CUR_SIZE(ops->p->cursor_shape)) {
+		switch (CUR_SIZE(par->p->cursor_shape)) {
 		case CUR_NONE:
 			cur_height = 0;
 			break;
@@ -348,19 +348,19 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		kfree(tmp);
 	}
 
-	ops->cursor_state.enable = enable && !use_sw;
+	par->cursor_state.enable = enable && !use_sw;
 
 	cursor.image.data = src;
-	cursor.image.fg_color = ops->cursor_state.image.fg_color;
-	cursor.image.bg_color = ops->cursor_state.image.bg_color;
-	cursor.image.dx = ops->cursor_state.image.dx;
-	cursor.image.dy = ops->cursor_state.image.dy;
-	cursor.image.height = ops->cursor_state.image.height;
-	cursor.image.width = ops->cursor_state.image.width;
-	cursor.hot.x = ops->cursor_state.hot.x;
-	cursor.hot.y = ops->cursor_state.hot.y;
-	cursor.mask = ops->cursor_state.mask;
-	cursor.enable = ops->cursor_state.enable;
+	cursor.image.fg_color = par->cursor_state.image.fg_color;
+	cursor.image.bg_color = par->cursor_state.image.bg_color;
+	cursor.image.dx = par->cursor_state.image.dx;
+	cursor.image.dy = par->cursor_state.image.dy;
+	cursor.image.height = par->cursor_state.image.height;
+	cursor.image.width = par->cursor_state.image.width;
+	cursor.hot.x = par->cursor_state.hot.x;
+	cursor.hot.y = par->cursor_state.hot.y;
+	cursor.mask = par->cursor_state.mask;
+	cursor.enable = par->cursor_state.enable;
 	cursor.image.depth = 1;
 	cursor.rop = ROP_XOR;
 
@@ -370,32 +370,32 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	if (err)
 		soft_cursor(info, &cursor);
 
-	ops->cursor_reset = 0;
+	par->cursor_reset = 0;
 }
 
 static int ccw_update_start(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	u32 yoffset;
-	u32 vyres = GETVYRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
 	int err;
 
-	yoffset = (vyres - info->var.yres) - ops->var.xoffset;
-	ops->var.xoffset = ops->var.yoffset;
-	ops->var.yoffset = yoffset;
-	err = fb_pan_display(info, &ops->var);
-	ops->var.xoffset = info->var.xoffset;
-	ops->var.yoffset = info->var.yoffset;
-	ops->var.vmode = info->var.vmode;
+	yoffset = (vyres - info->var.yres) - par->var.xoffset;
+	par->var.xoffset = par->var.yoffset;
+	par->var.yoffset = yoffset;
+	err = fb_pan_display(info, &par->var);
+	par->var.xoffset = info->var.xoffset;
+	par->var.yoffset = info->var.yoffset;
+	par->var.vmode = info->var.vmode;
 	return err;
 }
 
-void fbcon_rotate_ccw(struct fbcon_ops *ops)
+void fbcon_rotate_ccw(struct fbcon_par *par)
 {
-	ops->bmove = ccw_bmove;
-	ops->clear = ccw_clear;
-	ops->putcs = ccw_putcs;
-	ops->clear_margins = ccw_clear_margins;
-	ops->cursor = ccw_cursor;
-	ops->update_start = ccw_update_start;
+	par->bmove = ccw_bmove;
+	par->clear = ccw_clear;
+	par->putcs = ccw_putcs;
+	par->clear_margins = ccw_clear_margins;
+	par->cursor = ccw_cursor;
+	par->update_start = ccw_update_start;
 }
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index b9dac7940fb7..4bd22d5ee5f4 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -48,9 +48,9 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
 static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int dy, int dx, int height, int width)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fb_copyarea area;
-	u32 vxres = GETVXRES(ops->p, info);
+	u32 vxres = GETVXRES(par->p, info);
 
 	area.sx = vxres - ((sy + height) * vc->vc_font.height);
 	area.sy = sx * vc->vc_font.width;
@@ -65,9 +65,9 @@ static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int height, int width, int fg, int bg)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fb_fillrect region;
-	u32 vxres = GETVXRES(ops->p, info);
+	u32 vxres = GETVXRES(par->p, info);
 
 	region.color = bg;
 	region.dx = vxres - ((sy + height) * vc->vc_font.height);
@@ -84,13 +84,13 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
 				    u32 d_pitch, u32 s_pitch, u32 cellsize,
 				    struct fb_image *image, u8 *buf, u8 *dst)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 	u32 idx = (vc->vc_font.height + 7) >> 3;
 	u8 *src;
 
 	while (cnt--) {
-		src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize;
+		src = par->fontbuffer + (scr_readw(s++) & charmask) * cellsize;
 
 		if (attr) {
 			cw_update_attr(buf, src, attr, vc);
@@ -115,7 +115,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
 		      int fg, int bg)
 {
 	struct fb_image image;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	u32 width = (vc->vc_font.height + 7)/8;
 	u32 cellsize = width * vc->vc_font.width;
 	u32 maxcnt = info->pixmap.size/cellsize;
@@ -124,9 +124,9 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
 	u32 cnt, pitch, size;
 	u32 attribute = get_attribute(info, scr_readw(s));
 	u8 *dst, *buf = NULL;
-	u32 vxres = GETVXRES(ops->p, info);
+	u32 vxres = GETVXRES(par->p, info);
 
-	if (!ops->fontbuffer)
+	if (!par->fontbuffer)
 		return;
 
 	image.fg_color = fg;
@@ -204,28 +204,28 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		      int fg, int bg)
 {
 	struct fb_cursor cursor;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 	int w = (vc->vc_font.height + 7) >> 3, c;
-	int y = real_y(ops->p, vc->state.y);
+	int y = real_y(par->p, vc->state.y);
 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
 	int err = 1, dx, dy;
 	char *src;
-	u32 vxres = GETVXRES(ops->p, info);
+	u32 vxres = GETVXRES(par->p, info);
 
-	if (!ops->fontbuffer)
+	if (!par->fontbuffer)
 		return;
 
 	cursor.set = 0;
 
  	c = scr_readw((u16 *) vc->vc_pos);
 	attribute = get_attribute(info, c);
-	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+	src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
 
-	if (ops->cursor_state.image.data != src ||
-	    ops->cursor_reset) {
-	    ops->cursor_state.image.data = src;
-	    cursor.set |= FB_CUR_SETIMAGE;
+	if (par->cursor_state.image.data != src ||
+	    par->cursor_reset) {
+		par->cursor_state.image.data = src;
+		cursor.set |= FB_CUR_SETIMAGE;
 	}
 
 	if (attribute) {
@@ -234,49 +234,49 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
 		if (!dst)
 			return;
-		kfree(ops->cursor_data);
-		ops->cursor_data = dst;
+		kfree(par->cursor_data);
+		par->cursor_data = dst;
 		cw_update_attr(dst, src, attribute, vc);
 		src = dst;
 	}
 
-	if (ops->cursor_state.image.fg_color != fg ||
-	    ops->cursor_state.image.bg_color != bg ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.fg_color = fg;
-		ops->cursor_state.image.bg_color = bg;
+	if (par->cursor_state.image.fg_color != fg ||
+	    par->cursor_state.image.bg_color != bg ||
+	    par->cursor_reset) {
+		par->cursor_state.image.fg_color = fg;
+		par->cursor_state.image.bg_color = bg;
 		cursor.set |= FB_CUR_SETCMAP;
 	}
 
-	if (ops->cursor_state.image.height != vc->vc_font.width ||
-	    ops->cursor_state.image.width != vc->vc_font.height ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.height = vc->vc_font.width;
-		ops->cursor_state.image.width = vc->vc_font.height;
+	if (par->cursor_state.image.height != vc->vc_font.width ||
+	    par->cursor_state.image.width != vc->vc_font.height ||
+	    par->cursor_reset) {
+		par->cursor_state.image.height = vc->vc_font.width;
+		par->cursor_state.image.width = vc->vc_font.height;
 		cursor.set |= FB_CUR_SETSIZE;
 	}
 
 	dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height);
 	dy = vc->state.x * vc->vc_font.width;
 
-	if (ops->cursor_state.image.dx != dx ||
-	    ops->cursor_state.image.dy != dy ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.dx = dx;
-		ops->cursor_state.image.dy = dy;
+	if (par->cursor_state.image.dx != dx ||
+	    par->cursor_state.image.dy != dy ||
+	    par->cursor_reset) {
+		par->cursor_state.image.dx = dx;
+		par->cursor_state.image.dy = dy;
 		cursor.set |= FB_CUR_SETPOS;
 	}
 
-	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
-	    ops->cursor_reset) {
-		ops->cursor_state.hot.x = cursor.hot.y = 0;
+	if (par->cursor_state.hot.x || par->cursor_state.hot.y ||
+	    par->cursor_reset) {
+		par->cursor_state.hot.x = cursor.hot.y = 0;
 		cursor.set |= FB_CUR_SETHOT;
 	}
 
 	if (cursor.set & FB_CUR_SETSIZE ||
-	    vc->vc_cursor_type != ops->p->cursor_shape ||
-	    ops->cursor_state.mask == NULL ||
-	    ops->cursor_reset) {
+	    vc->vc_cursor_type != par->p->cursor_shape ||
+	    par->cursor_state.mask == NULL ||
+	    par->cursor_reset) {
 		char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
 						 GFP_ATOMIC);
 		int cur_height, size, i = 0;
@@ -292,13 +292,13 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 			return;
 		}
 
-		kfree(ops->cursor_state.mask);
-		ops->cursor_state.mask = mask;
+		kfree(par->cursor_state.mask);
+		par->cursor_state.mask = mask;
 
-		ops->p->cursor_shape = vc->vc_cursor_type;
+		par->p->cursor_shape = vc->vc_cursor_type;
 		cursor.set |= FB_CUR_SETSHAPE;
 
-		switch (CUR_SIZE(ops->p->cursor_shape)) {
+		switch (CUR_SIZE(par->p->cursor_shape)) {
 		case CUR_NONE:
 			cur_height = 0;
 			break;
@@ -331,19 +331,19 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		kfree(tmp);
 	}
 
-	ops->cursor_state.enable = enable && !use_sw;
+	par->cursor_state.enable = enable && !use_sw;
 
 	cursor.image.data = src;
-	cursor.image.fg_color = ops->cursor_state.image.fg_color;
-	cursor.image.bg_color = ops->cursor_state.image.bg_color;
-	cursor.image.dx = ops->cursor_state.image.dx;
-	cursor.image.dy = ops->cursor_state.image.dy;
-	cursor.image.height = ops->cursor_state.image.height;
-	cursor.image.width = ops->cursor_state.image.width;
-	cursor.hot.x = ops->cursor_state.hot.x;
-	cursor.hot.y = ops->cursor_state.hot.y;
-	cursor.mask = ops->cursor_state.mask;
-	cursor.enable = ops->cursor_state.enable;
+	cursor.image.fg_color = par->cursor_state.image.fg_color;
+	cursor.image.bg_color = par->cursor_state.image.bg_color;
+	cursor.image.dx = par->cursor_state.image.dx;
+	cursor.image.dy = par->cursor_state.image.dy;
+	cursor.image.height = par->cursor_state.image.height;
+	cursor.image.width = par->cursor_state.image.width;
+	cursor.hot.x = par->cursor_state.hot.x;
+	cursor.hot.y = par->cursor_state.hot.y;
+	cursor.mask = par->cursor_state.mask;
+	cursor.enable = par->cursor_state.enable;
 	cursor.image.depth = 1;
 	cursor.rop = ROP_XOR;
 
@@ -353,32 +353,32 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	if (err)
 		soft_cursor(info, &cursor);
 
-	ops->cursor_reset = 0;
+	par->cursor_reset = 0;
 }
 
 static int cw_update_start(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
-	u32 vxres = GETVXRES(ops->p, info);
+	struct fbcon_par *par = info->fbcon_par;
+	u32 vxres = GETVXRES(par->p, info);
 	u32 xoffset;
 	int err;
 
-	xoffset = vxres - (info->var.xres + ops->var.yoffset);
-	ops->var.yoffset = ops->var.xoffset;
-	ops->var.xoffset = xoffset;
-	err = fb_pan_display(info, &ops->var);
-	ops->var.xoffset = info->var.xoffset;
-	ops->var.yoffset = info->var.yoffset;
-	ops->var.vmode = info->var.vmode;
+	xoffset = vxres - (info->var.xres + par->var.yoffset);
+	par->var.yoffset = par->var.xoffset;
+	par->var.xoffset = xoffset;
+	err = fb_pan_display(info, &par->var);
+	par->var.xoffset = info->var.xoffset;
+	par->var.yoffset = info->var.yoffset;
+	par->var.vmode = info->var.vmode;
 	return err;
 }
 
-void fbcon_rotate_cw(struct fbcon_ops *ops)
+void fbcon_rotate_cw(struct fbcon_par *par)
 {
-	ops->bmove = cw_bmove;
-	ops->clear = cw_clear;
-	ops->putcs = cw_putcs;
-	ops->clear_margins = cw_clear_margins;
-	ops->cursor = cw_cursor;
-	ops->update_start = cw_update_start;
+	par->bmove = cw_bmove;
+	par->clear = cw_clear;
+	par->putcs = cw_putcs;
+	par->clear_margins = cw_clear_margins;
+	par->cursor = cw_cursor;
+	par->update_start = cw_update_start;
 }
diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
index ec3c883400f7..380b2746451a 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -20,32 +20,32 @@
 
 static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int len, err = 0;
 	int s_cellsize, d_cellsize, i;
 	const u8 *src;
 	u8 *dst;
 
-	if (vc->vc_font.data == ops->fontdata &&
-	    ops->p->con_rotate == ops->cur_rotate)
+	if (vc->vc_font.data == par->fontdata &&
+	    par->p->con_rotate == par->cur_rotate)
 		goto finished;
 
-	src = ops->fontdata = vc->vc_font.data;
-	ops->cur_rotate = ops->p->con_rotate;
+	src = par->fontdata = vc->vc_font.data;
+	par->cur_rotate = par->p->con_rotate;
 	len = vc->vc_font.charcount;
 	s_cellsize = ((vc->vc_font.width + 7)/8) *
 		vc->vc_font.height;
 	d_cellsize = s_cellsize;
 
-	if (ops->rotate == FB_ROTATE_CW ||
-	    ops->rotate == FB_ROTATE_CCW)
+	if (par->rotate == FB_ROTATE_CW ||
+	    par->rotate == FB_ROTATE_CCW)
 		d_cellsize = ((vc->vc_font.height + 7)/8) *
 			vc->vc_font.width;
 
 	if (info->fbops->fb_sync)
 		info->fbops->fb_sync(info);
 
-	if (ops->fd_size < d_cellsize * len) {
+	if (par->fd_size < d_cellsize * len) {
 		dst = kmalloc_array(len, d_cellsize, GFP_KERNEL);
 
 		if (dst == NULL) {
@@ -53,15 +53,15 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 			goto finished;
 		}
 
-		ops->fd_size = d_cellsize * len;
-		kfree(ops->fontbuffer);
-		ops->fontbuffer = dst;
+		par->fd_size = d_cellsize * len;
+		kfree(par->fontbuffer);
+		par->fontbuffer = dst;
 	}
 
-	dst = ops->fontbuffer;
-	memset(dst, 0, ops->fd_size);
+	dst = par->fontbuffer;
+	memset(dst, 0, par->fd_size);
 
-	switch (ops->rotate) {
+	switch (par->rotate) {
 	case FB_ROTATE_UD:
 		for (i = len; i--; ) {
 			rotate_ud(src, dst, vc->vc_font.width,
@@ -93,19 +93,19 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 	return err;
 }
 
-void fbcon_set_rotate(struct fbcon_ops *ops)
+void fbcon_set_rotate(struct fbcon_par *par)
 {
-	ops->rotate_font = fbcon_rotate_font;
+	par->rotate_font = fbcon_rotate_font;
 
-	switch(ops->rotate) {
+	switch (par->rotate) {
 	case FB_ROTATE_CW:
-		fbcon_rotate_cw(ops);
+		fbcon_rotate_cw(par);
 		break;
 	case FB_ROTATE_UD:
-		fbcon_rotate_ud(ops);
+		fbcon_rotate_ud(par);
 		break;
 	case FB_ROTATE_CCW:
-		fbcon_rotate_ccw(ops);
+		fbcon_rotate_ccw(par);
 		break;
 	}
 }
diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h
index 01cbe303b8a2..48305e1a0763 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.h
+++ b/drivers/video/fbdev/core/fbcon_rotate.h
@@ -90,7 +90,7 @@ static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
 	}
 }
 
-extern void fbcon_rotate_cw(struct fbcon_ops *ops);
-extern void fbcon_rotate_ud(struct fbcon_ops *ops);
-extern void fbcon_rotate_ccw(struct fbcon_ops *ops);
+extern void fbcon_rotate_cw(struct fbcon_par *par);
+extern void fbcon_rotate_ud(struct fbcon_par *par);
+extern void fbcon_rotate_ccw(struct fbcon_par *par);
 #endif
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index 0af7913a2abd..14b40e2bf323 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -48,10 +48,10 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute,
 static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int dy, int dx, int height, int width)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fb_copyarea area;
-	u32 vyres = GETVYRES(ops->p, info);
-	u32 vxres = GETVXRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
+	u32 vxres = GETVXRES(par->p, info);
 
 	area.sy = vyres - ((sy + height) * vc->vc_font.height);
 	area.sx = vxres - ((sx + width) * vc->vc_font.width);
@@ -66,10 +66,10 @@ static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int height, int width, int fg, int bg)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	struct fb_fillrect region;
-	u32 vyres = GETVYRES(ops->p, info);
-	u32 vxres = GETVXRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
+	u32 vxres = GETVXRES(par->p, info);
 
 	region.color = bg;
 	region.dy = vyres - ((sy + height) * vc->vc_font.height);
@@ -86,13 +86,13 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
 				    u32 d_pitch, u32 s_pitch, u32 cellsize,
 				    struct fb_image *image, u8 *buf, u8 *dst)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 	u32 idx = vc->vc_font.width >> 3;
 	u8 *src;
 
 	while (cnt--) {
-		src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+		src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize;
 
 		if (attr) {
 			ud_update_attr(buf, src, attr, vc);
@@ -119,7 +119,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc,
 				      struct fb_image *image, u8 *buf,
 				      u8 *dst)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 	u32 shift_low = 0, mod = vc->vc_font.width % 8;
 	u32 shift_high = 8;
@@ -127,7 +127,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc,
 	u8 *src;
 
 	while (cnt--) {
-		src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+		src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize;
 
 		if (attr) {
 			ud_update_attr(buf, src, attr, vc);
@@ -152,7 +152,7 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
 		      int fg, int bg)
 {
 	struct fb_image image;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	u32 width = (vc->vc_font.width + 7)/8;
 	u32 cellsize = width * vc->vc_font.height;
 	u32 maxcnt = info->pixmap.size/cellsize;
@@ -161,10 +161,10 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
 	u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
 	u32 attribute = get_attribute(info, scr_readw(s));
 	u8 *dst, *buf = NULL;
-	u32 vyres = GETVYRES(ops->p, info);
-	u32 vxres = GETVXRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
+	u32 vxres = GETVXRES(par->p, info);
 
-	if (!ops->fontbuffer)
+	if (!par->fontbuffer)
 		return;
 
 	image.fg_color = fg;
@@ -251,29 +251,29 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		      int fg, int bg)
 {
 	struct fb_cursor cursor;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 	int w = (vc->vc_font.width + 7) >> 3, c;
-	int y = real_y(ops->p, vc->state.y);
+	int y = real_y(par->p, vc->state.y);
 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
 	int err = 1, dx, dy;
 	char *src;
-	u32 vyres = GETVYRES(ops->p, info);
-	u32 vxres = GETVXRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
+	u32 vxres = GETVXRES(par->p, info);
 
-	if (!ops->fontbuffer)
+	if (!par->fontbuffer)
 		return;
 
 	cursor.set = 0;
 
  	c = scr_readw((u16 *) vc->vc_pos);
 	attribute = get_attribute(info, c);
-	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
+	src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
 
-	if (ops->cursor_state.image.data != src ||
-	    ops->cursor_reset) {
-	    ops->cursor_state.image.data = src;
-	    cursor.set |= FB_CUR_SETIMAGE;
+	if (par->cursor_state.image.data != src ||
+	    par->cursor_reset) {
+		par->cursor_state.image.data = src;
+		cursor.set |= FB_CUR_SETIMAGE;
 	}
 
 	if (attribute) {
@@ -282,49 +282,49 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
 		if (!dst)
 			return;
-		kfree(ops->cursor_data);
-		ops->cursor_data = dst;
+		kfree(par->cursor_data);
+		par->cursor_data = dst;
 		ud_update_attr(dst, src, attribute, vc);
 		src = dst;
 	}
 
-	if (ops->cursor_state.image.fg_color != fg ||
-	    ops->cursor_state.image.bg_color != bg ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.fg_color = fg;
-		ops->cursor_state.image.bg_color = bg;
+	if (par->cursor_state.image.fg_color != fg ||
+	    par->cursor_state.image.bg_color != bg ||
+	    par->cursor_reset) {
+		par->cursor_state.image.fg_color = fg;
+		par->cursor_state.image.bg_color = bg;
 		cursor.set |= FB_CUR_SETCMAP;
 	}
 
-	if (ops->cursor_state.image.height != vc->vc_font.height ||
-	    ops->cursor_state.image.width != vc->vc_font.width ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.height = vc->vc_font.height;
-		ops->cursor_state.image.width = vc->vc_font.width;
+	if (par->cursor_state.image.height != vc->vc_font.height ||
+	    par->cursor_state.image.width != vc->vc_font.width ||
+	    par->cursor_reset) {
+		par->cursor_state.image.height = vc->vc_font.height;
+		par->cursor_state.image.width = vc->vc_font.width;
 		cursor.set |= FB_CUR_SETSIZE;
 	}
 
 	dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height);
 	dx = vxres - ((vc->state.x * vc->vc_font.width) + vc->vc_font.width);
 
-	if (ops->cursor_state.image.dx != dx ||
-	    ops->cursor_state.image.dy != dy ||
-	    ops->cursor_reset) {
-		ops->cursor_state.image.dx = dx;
-		ops->cursor_state.image.dy = dy;
+	if (par->cursor_state.image.dx != dx ||
+	    par->cursor_state.image.dy != dy ||
+	    par->cursor_reset) {
+		par->cursor_state.image.dx = dx;
+		par->cursor_state.image.dy = dy;
 		cursor.set |= FB_CUR_SETPOS;
 	}
 
-	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
-	    ops->cursor_reset) {
-		ops->cursor_state.hot.x = cursor.hot.y = 0;
+	if (par->cursor_state.hot.x || par->cursor_state.hot.y ||
+	    par->cursor_reset) {
+		par->cursor_state.hot.x = cursor.hot.y = 0;
 		cursor.set |= FB_CUR_SETHOT;
 	}
 
 	if (cursor.set & FB_CUR_SETSIZE ||
-	    vc->vc_cursor_type != ops->p->cursor_shape ||
-	    ops->cursor_state.mask == NULL ||
-	    ops->cursor_reset) {
+	    vc->vc_cursor_type != par->p->cursor_shape ||
+	    par->cursor_state.mask == NULL ||
+	    par->cursor_reset) {
 		char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
 		int cur_height, size, i = 0;
 		u8 msk = 0xff;
@@ -332,13 +332,13 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		if (!mask)
 			return;
 
-		kfree(ops->cursor_state.mask);
-		ops->cursor_state.mask = mask;
+		kfree(par->cursor_state.mask);
+		par->cursor_state.mask = mask;
 
-		ops->p->cursor_shape = vc->vc_cursor_type;
+		par->p->cursor_shape = vc->vc_cursor_type;
 		cursor.set |= FB_CUR_SETSHAPE;
 
-		switch (CUR_SIZE(ops->p->cursor_shape)) {
+		switch (CUR_SIZE(par->p->cursor_shape)) {
 		case CUR_NONE:
 			cur_height = 0;
 			break;
@@ -371,19 +371,19 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 			mask[i++] = ~msk;
 	}
 
-	ops->cursor_state.enable = enable && !use_sw;
+	par->cursor_state.enable = enable && !use_sw;
 
 	cursor.image.data = src;
-	cursor.image.fg_color = ops->cursor_state.image.fg_color;
-	cursor.image.bg_color = ops->cursor_state.image.bg_color;
-	cursor.image.dx = ops->cursor_state.image.dx;
-	cursor.image.dy = ops->cursor_state.image.dy;
-	cursor.image.height = ops->cursor_state.image.height;
-	cursor.image.width = ops->cursor_state.image.width;
-	cursor.hot.x = ops->cursor_state.hot.x;
-	cursor.hot.y = ops->cursor_state.hot.y;
-	cursor.mask = ops->cursor_state.mask;
-	cursor.enable = ops->cursor_state.enable;
+	cursor.image.fg_color = par->cursor_state.image.fg_color;
+	cursor.image.bg_color = par->cursor_state.image.bg_color;
+	cursor.image.dx = par->cursor_state.image.dx;
+	cursor.image.dy = par->cursor_state.image.dy;
+	cursor.image.height = par->cursor_state.image.height;
+	cursor.image.width = par->cursor_state.image.width;
+	cursor.hot.x = par->cursor_state.hot.x;
+	cursor.hot.y = par->cursor_state.hot.y;
+	cursor.mask = par->cursor_state.mask;
+	cursor.enable = par->cursor_state.enable;
 	cursor.image.depth = 1;
 	cursor.rop = ROP_XOR;
 
@@ -393,36 +393,36 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	if (err)
 		soft_cursor(info, &cursor);
 
-	ops->cursor_reset = 0;
+	par->cursor_reset = 0;
 }
 
 static int ud_update_start(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int xoffset, yoffset;
-	u32 vyres = GETVYRES(ops->p, info);
-	u32 vxres = GETVXRES(ops->p, info);
+	u32 vyres = GETVYRES(par->p, info);
+	u32 vxres = GETVXRES(par->p, info);
 	int err;
 
-	xoffset = vxres - info->var.xres - ops->var.xoffset;
-	yoffset = vyres - info->var.yres - ops->var.yoffset;
+	xoffset = vxres - info->var.xres - par->var.xoffset;
+	yoffset = vyres - info->var.yres - par->var.yoffset;
 	if (yoffset < 0)
 		yoffset += vyres;
-	ops->var.xoffset = xoffset;
-	ops->var.yoffset = yoffset;
-	err = fb_pan_display(info, &ops->var);
-	ops->var.xoffset = info->var.xoffset;
-	ops->var.yoffset = info->var.yoffset;
-	ops->var.vmode = info->var.vmode;
+	par->var.xoffset = xoffset;
+	par->var.yoffset = yoffset;
+	err = fb_pan_display(info, &par->var);
+	par->var.xoffset = info->var.xoffset;
+	par->var.yoffset = info->var.yoffset;
+	par->var.vmode = info->var.vmode;
 	return err;
 }
 
-void fbcon_rotate_ud(struct fbcon_ops *ops)
+void fbcon_rotate_ud(struct fbcon_par *par)
 {
-	ops->bmove = ud_bmove;
-	ops->clear = ud_clear;
-	ops->putcs = ud_putcs;
-	ops->clear_margins = ud_clear_margins;
-	ops->cursor = ud_cursor;
-	ops->update_start = ud_update_start;
+	par->bmove = ud_bmove;
+	par->clear = ud_clear;
+	par->putcs = ud_putcs;
+	par->clear_margins = ud_clear_margins;
+	par->cursor = ud_cursor;
+	par->update_start = ud_update_start;
 }
diff --git a/drivers/video/fbdev/core/softcursor.c b/drivers/video/fbdev/core/softcursor.c
index 29e5b21cf373..900788c05915 100644
--- a/drivers/video/fbdev/core/softcursor.c
+++ b/drivers/video/fbdev/core/softcursor.c
@@ -21,7 +21,7 @@
 
 int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	unsigned int scan_align = info->pixmap.scan_align - 1;
 	unsigned int buf_align = info->pixmap.buf_align - 1;
 	unsigned int i, size, dsize, s_pitch, d_pitch;
@@ -34,19 +34,19 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
 	s_pitch = (cursor->image.width + 7) >> 3;
 	dsize = s_pitch * cursor->image.height;
 
-	if (dsize + sizeof(struct fb_image) != ops->cursor_size) {
-		kfree(ops->cursor_src);
-		ops->cursor_size = dsize + sizeof(struct fb_image);
+	if (dsize + sizeof(struct fb_image) != par->cursor_size) {
+		kfree(par->cursor_src);
+		par->cursor_size = dsize + sizeof(struct fb_image);
 
-		ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC);
-		if (!ops->cursor_src) {
-			ops->cursor_size = 0;
+		par->cursor_src = kmalloc(par->cursor_size, GFP_ATOMIC);
+		if (!par->cursor_src) {
+			par->cursor_size = 0;
 			return -ENOMEM;
 		}
 	}
 
-	src = ops->cursor_src + sizeof(struct fb_image);
-	image = (struct fb_image *)ops->cursor_src;
+	src = par->cursor_src + sizeof(struct fb_image);
+	image = (struct fb_image *)par->cursor_src;
 	*image = cursor->image;
 	d_pitch = (s_pitch + scan_align) & ~scan_align;
 
diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c
index d342b90c42b7..4428f2bcd3f8 100644
--- a/drivers/video/fbdev/core/tileblit.c
+++ b/drivers/video/fbdev/core/tileblit.c
@@ -151,34 +151,34 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 
 static int tile_update_start(struct fb_info *info)
 {
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 	int err;
 
-	err = fb_pan_display(info, &ops->var);
-	ops->var.xoffset = info->var.xoffset;
-	ops->var.yoffset = info->var.yoffset;
-	ops->var.vmode = info->var.vmode;
+	err = fb_pan_display(info, &par->var);
+	par->var.xoffset = info->var.xoffset;
+	par->var.yoffset = info->var.yoffset;
+	par->var.vmode = info->var.vmode;
 	return err;
 }
 
 void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info)
 {
 	struct fb_tilemap map;
-	struct fbcon_ops *ops = info->fbcon_par;
+	struct fbcon_par *par = info->fbcon_par;
 
-	ops->bmove = tile_bmove;
-	ops->clear = tile_clear;
-	ops->putcs = tile_putcs;
-	ops->clear_margins = tile_clear_margins;
-	ops->cursor = tile_cursor;
-	ops->update_start = tile_update_start;
+	par->bmove = tile_bmove;
+	par->clear = tile_clear;
+	par->putcs = tile_putcs;
+	par->clear_margins = tile_clear_margins;
+	par->cursor = tile_cursor;
+	par->update_start = tile_update_start;
 
-	if (ops->p) {
+	if (par->p) {
 		map.width = vc->vc_font.width;
 		map.height = vc->vc_font.height;
 		map.depth = 1;
 		map.length = vc->vc_font.charcount;
-		map.data = ops->p->fontdata;
+		map.data = par->p->fontdata;
 		info->tileops->fb_settile(info, &map);
 	}
 }
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 4/5] fbcon: Move fbcon callbacks into struct fbcon_bitops
From: Thomas Zimmermann @ 2025-09-09 12:44 UTC (permalink / raw)
  To: sam, simona, deller
  Cc: linux-fbdev, dri-devel, linux-kernel, Thomas Zimmermann
In-Reply-To: <20250909124616.143365-1-tzimmermann@suse.de>

Depending on rotation settings, fbcon sets different callback
functions in struct fbcon_par from within fbcon_set_bitops(). Declare
the callback functions in the new type struct fbcon_bitops. Then
only replace the single bitops pointer in struct fbcon_par.

Keeping callbacks in constant instances of struct fbcon_bitops
makes it harder to exploit the callbacks. Also makes the code slightly
easier to maintain.

For tile-based consoles, there's a separate instance of the bitops
structure.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
 drivers/video/fbdev/core/bitblit.c   | 17 ++++---
 drivers/video/fbdev/core/fbcon.c     | 67 +++++++++++++++-------------
 drivers/video/fbdev/core/fbcon.h     |  7 ++-
 drivers/video/fbdev/core/fbcon_ccw.c | 18 +++++---
 drivers/video/fbdev/core/fbcon_cw.c  | 18 +++++---
 drivers/video/fbdev/core/fbcon_ud.c  | 18 +++++---
 drivers/video/fbdev/core/tileblit.c  | 16 ++++---
 7 files changed, 94 insertions(+), 67 deletions(-)

diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index ebadc9619699..7a68372f0444 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -384,15 +384,18 @@ static int bit_update_start(struct fb_info *info)
 	return err;
 }
 
+static const struct fbcon_bitops bit_fbcon_bitops = {
+	.bmove = bit_bmove,
+	.clear = bit_clear,
+	.putcs = bit_putcs,
+	.clear_margins = bit_clear_margins,
+	.cursor = bit_cursor,
+	.update_start = bit_update_start,
+};
+
 void fbcon_set_bitops(struct fbcon_par *par)
 {
-	par->bmove = bit_bmove;
-	par->clear = bit_clear;
-	par->putcs = bit_putcs;
-	par->clear_margins = bit_clear_margins;
-	par->cursor = bit_cursor;
-	par->update_start = bit_update_start;
-	par->rotate_font = NULL;
+	par->bitops = &bit_fbcon_bitops;
 
 	if (par->rotate)
 		fbcon_set_rotate(par);
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 7f871ef3e624..1074dc90ed92 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -405,9 +405,9 @@ static void fb_flashcursor(struct work_struct *work)
 
 	c = scr_readw((u16 *) vc->vc_pos);
 	enable = par->cursor_flash && !par->cursor_state.enable;
-	par->cursor(vc, info, enable,
-		    get_fg_color(vc, info, c),
-		    get_bg_color(vc, info, c));
+	par->bitops->cursor(vc, info, enable,
+			    get_fg_color(vc, info, c),
+			    get_bg_color(vc, info, c));
 	console_unlock();
 
 	queue_delayed_work(system_power_efficient_wq, &par->cursor_work,
@@ -1162,7 +1162,7 @@ static void fbcon_init(struct vc_data *vc, bool init)
 	if (logo)
 		fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
 
-	if (par->rotate_font && par->rotate_font(info, vc)) {
+	if (par->bitops->rotate_font && par->bitops->rotate_font(info, vc)) {
 		par->rotate = FB_ROTATE_UR;
 		set_blitting_type(vc, info);
 	}
@@ -1303,10 +1303,11 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
 	y_break = p->vrows - p->yscroll;
 	if (sy < y_break && sy + height - 1 >= y_break) {
 		u_int b = y_break - sy;
-		par->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg);
-		par->clear(vc, info, real_y(p, sy + b), sx, height - b, width, fg, bg);
+		par->bitops->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg);
+		par->bitops->clear(vc, info, real_y(p, sy + b), sx, height - b,
+				     width, fg, bg);
 	} else
-		par->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg);
+		par->bitops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg);
 }
 
 static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
@@ -1323,9 +1324,9 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
 	struct fbcon_par *par = info->fbcon_par;
 
 	if (fbcon_is_active(vc, info))
-		par->putcs(vc, info, s, count, real_y(p, ypos), xpos,
-			   get_fg_color(vc, info, scr_readw(s)),
-			   get_bg_color(vc, info, scr_readw(s)));
+		par->bitops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
+				   get_fg_color(vc, info, scr_readw(s)),
+				   get_bg_color(vc, info, scr_readw(s)));
 }
 
 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
@@ -1334,7 +1335,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
 	struct fbcon_par *par = info->fbcon_par;
 
 	if (fbcon_is_active(vc, info))
-		par->clear_margins(vc, info, margin_color, bottom_only);
+		par->bitops->clear_margins(vc, info, margin_color, bottom_only);
 }
 
 static void fbcon_cursor(struct vc_data *vc, bool enable)
@@ -1355,12 +1356,12 @@ static void fbcon_cursor(struct vc_data *vc, bool enable)
 
 	par->cursor_flash = enable;
 
-	if (!par->cursor)
+	if (!par->bitops->cursor)
 		return;
 
-	par->cursor(vc, info, enable,
-		    get_fg_color(vc, info, c),
-		    get_bg_color(vc, info, c));
+	par->bitops->cursor(vc, info, enable,
+			    get_fg_color(vc, info, c),
+			    get_bg_color(vc, info, c));
 }
 
 static int scrollback_phys_max = 0;
@@ -1444,7 +1445,7 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count)
 	par->var.xoffset = 0;
 	par->var.yoffset = p->yscroll * vc->vc_font.height;
 	par->var.vmode |= FB_VMODE_YWRAP;
-	par->update_start(info);
+	par->bitops->update_start(info);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
 		scrollback_max = scrollback_phys_max;
@@ -1463,7 +1464,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count)
 	par->var.xoffset = 0;
 	par->var.yoffset = p->yscroll * vc->vc_font.height;
 	par->var.vmode |= FB_VMODE_YWRAP;
-	par->update_start(info);
+	par->bitops->update_start(info);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
 		scrollback_max = 0;
@@ -1478,15 +1479,15 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
 
 	p->yscroll += count;
 	if (p->yscroll > p->vrows - vc->vc_rows) {
-		par->bmove(vc, info, p->vrows - vc->vc_rows,
-			    0, 0, 0, vc->vc_rows, vc->vc_cols);
+		par->bitops->bmove(vc, info, p->vrows - vc->vc_rows,
+				   0, 0, 0, vc->vc_rows, vc->vc_cols);
 		p->yscroll -= p->vrows - vc->vc_rows;
 	}
 
 	par->var.xoffset = 0;
 	par->var.yoffset = p->yscroll * vc->vc_font.height;
 	par->var.vmode &= ~FB_VMODE_YWRAP;
-	par->update_start(info);
+	par->bitops->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
@@ -1510,7 +1511,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
 	par->var.xoffset = 0;
 	par->var.yoffset = p->yscroll * vc->vc_font.height;
 	par->var.vmode &= ~FB_VMODE_YWRAP;
-	par->update_start(info);
+	par->bitops->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
@@ -1526,15 +1527,15 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
 
 	p->yscroll -= count;
 	if (p->yscroll < 0) {
-		par->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
-			    0, vc->vc_rows, vc->vc_cols);
+		par->bitops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
+				   0, vc->vc_rows, vc->vc_cols);
 		p->yscroll += p->vrows - vc->vc_rows;
 	}
 
 	par->var.xoffset = 0;
 	par->var.yoffset = p->yscroll * vc->vc_font.height;
 	par->var.vmode &= ~FB_VMODE_YWRAP;
-	par->update_start(info);
+	par->bitops->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
@@ -1558,7 +1559,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
 	par->var.xoffset = 0;
 	par->var.yoffset = p->yscroll * vc->vc_font.height;
 	par->var.vmode &= ~FB_VMODE_YWRAP;
-	par->update_start(info);
+	par->bitops->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
@@ -1620,8 +1621,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
 
 			if (c == scr_readw(d)) {
 				if (s > start) {
-					par->bmove(vc, info, line + ycount, x,
-						   line, x, 1, s - start);
+					par->bitops->bmove(vc, info, line + ycount, x,
+							   line, x, 1, s - start);
 					x += s - start + 1;
 					start = s + 1;
 				} else {
@@ -1636,7 +1637,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
 			d++;
 		} while (s < le);
 		if (s > start)
-			par->bmove(vc, info, line + ycount, x, line, x, 1, s - start);
+			par->bitops->bmove(vc, info, line + ycount, x, line, x, 1,
+					     s - start);
 		console_conditional_schedule();
 		if (ycount > 0)
 			line++;
@@ -1741,7 +1743,8 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy,
 		}
 		return;
 	}
-	par->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
+	par->bitops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
+			     height, width);
 }
 
 static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
@@ -2161,7 +2164,7 @@ static bool fbcon_switch(struct vc_data *vc)
 	set_blitting_type(vc, info);
 	par->cursor_reset = 1;
 
-	if (par->rotate_font && par->rotate_font(info, vc)) {
+	if (par->bitops->rotate_font && par->bitops->rotate_font(info, vc)) {
 		par->rotate = FB_ROTATE_UR;
 		set_blitting_type(vc, info);
 	}
@@ -2194,7 +2197,7 @@ static bool fbcon_switch(struct vc_data *vc)
 
 	if (fbcon_is_active(vc, info)) {
 		par->var.xoffset = par->var.yoffset = p->yscroll = 0;
-		par->update_start(info);
+		par->bitops->update_start(info);
 	}
 
 	fbcon_set_palette(vc, color_table);
@@ -2693,7 +2696,7 @@ static void fbcon_modechanged(struct fb_info *info)
 
 		if (fbcon_is_active(vc, info)) {
 			par->var.xoffset = par->var.yoffset = p->yscroll = 0;
-			par->update_start(info);
+			par->bitops->update_start(info);
 		}
 
 		fbcon_set_palette(vc, color_table);
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index 94991a1ba11f..4bff4f5b3ec1 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -51,7 +51,7 @@ struct fbcon_display {
     const struct fb_videomode *mode;
 };
 
-struct fbcon_par {
+struct fbcon_bitops {
 	void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
 		      int sx, int dy, int dx, int height, int width);
 	void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
@@ -65,6 +65,9 @@ struct fbcon_par {
 		       bool enable, int fg, int bg);
 	int  (*update_start)(struct fb_info *info);
 	int  (*rotate_font)(struct fb_info *info, struct vc_data *vc);
+};
+
+struct fbcon_par {
 	struct fb_var_screeninfo var;  /* copy of the current fb_var_screeninfo */
 	struct delayed_work cursor_work; /* Cursor timer */
 	struct fb_cursor cursor_state;
@@ -86,6 +89,8 @@ struct fbcon_par {
 	u8    *cursor_src;
 	u32    cursor_size;
 	u32    fd_size;
+
+	const struct fbcon_bitops *bitops;
 };
 
     /*
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index ba744b67a4fd..4721f4b5e29a 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -390,13 +390,17 @@ static int ccw_update_start(struct fb_info *info)
 	return err;
 }
 
+static const struct fbcon_bitops ccw_fbcon_bitops = {
+	.bmove = ccw_bmove,
+	.clear = ccw_clear,
+	.putcs = ccw_putcs,
+	.clear_margins = ccw_clear_margins,
+	.cursor = ccw_cursor,
+	.update_start = ccw_update_start,
+	.rotate_font = fbcon_rotate_font,
+};
+
 void fbcon_rotate_ccw(struct fbcon_par *par)
 {
-	par->bmove = ccw_bmove;
-	par->clear = ccw_clear;
-	par->putcs = ccw_putcs;
-	par->clear_margins = ccw_clear_margins;
-	par->cursor = ccw_cursor;
-	par->update_start = ccw_update_start;
-	par->rotate_font = fbcon_rotate_font;
+	par->bitops = &ccw_fbcon_bitops;
 }
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 974bd9d9b770..2771924d0fb7 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -373,13 +373,17 @@ static int cw_update_start(struct fb_info *info)
 	return err;
 }
 
+static const struct fbcon_bitops cw_fbcon_bitops = {
+	.bmove = cw_bmove,
+	.clear = cw_clear,
+	.putcs = cw_putcs,
+	.clear_margins = cw_clear_margins,
+	.cursor = cw_cursor,
+	.update_start = cw_update_start,
+	.rotate_font = fbcon_rotate_font,
+};
+
 void fbcon_rotate_cw(struct fbcon_par *par)
 {
-	par->bmove = cw_bmove;
-	par->clear = cw_clear;
-	par->putcs = cw_putcs;
-	par->clear_margins = cw_clear_margins;
-	par->cursor = cw_cursor;
-	par->update_start = cw_update_start;
-	par->rotate_font = fbcon_rotate_font;
+	par->bitops = &cw_fbcon_bitops;
 }
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index 1a214a4d538f..148ca9b539d1 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -417,13 +417,17 @@ static int ud_update_start(struct fb_info *info)
 	return err;
 }
 
+static const struct fbcon_bitops ud_fbcon_bitops = {
+	.bmove = ud_bmove,
+	.clear = ud_clear,
+	.putcs = ud_putcs,
+	.clear_margins = ud_clear_margins,
+	.cursor = ud_cursor,
+	.update_start = ud_update_start,
+	.rotate_font = fbcon_rotate_font,
+};
+
 void fbcon_rotate_ud(struct fbcon_par *par)
 {
-	par->bmove = ud_bmove;
-	par->clear = ud_clear;
-	par->putcs = ud_putcs;
-	par->clear_margins = ud_clear_margins;
-	par->cursor = ud_cursor;
-	par->update_start = ud_update_start;
-	par->rotate_font = fbcon_rotate_font;
+	par->bitops = &ud_fbcon_bitops;
 }
diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c
index 4428f2bcd3f8..a9db668caf72 100644
--- a/drivers/video/fbdev/core/tileblit.c
+++ b/drivers/video/fbdev/core/tileblit.c
@@ -161,17 +161,21 @@ static int tile_update_start(struct fb_info *info)
 	return err;
 }
 
+static const struct fbcon_bitops tile_fbcon_bitops = {
+	.bmove = tile_bmove,
+	.clear = tile_clear,
+	.putcs = tile_putcs,
+	.clear_margins = tile_clear_margins,
+	.cursor = tile_cursor,
+	.update_start = tile_update_start,
+};
+
 void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info)
 {
 	struct fb_tilemap map;
 	struct fbcon_par *par = info->fbcon_par;
 
-	par->bmove = tile_bmove;
-	par->clear = tile_clear;
-	par->putcs = tile_putcs;
-	par->clear_margins = tile_clear_margins;
-	par->cursor = tile_cursor;
-	par->update_start = tile_update_start;
+	par->bitops = &tile_fbcon_bitops;
 
 	if (par->p) {
 		map.width = vc->vc_font.width;
-- 
2.51.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox