* [PATCH v5 01/11] drm: Add MIPI DBI bus support
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
@ 2026-10-29 15:28 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 02/11] dt-bindings: display: panel: Document Hitachi TX10D07VM0BAA and LG LH400WV3 panels Svyatoslav Ryhel
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:28 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
From: Mikko Perttunen <mperttunen@nvidia.com>
The MIPI DBI bus allows modeling DBI hosts and peripherals using the Linux
driver model. DBI hosts are registered by their respective drivers. During
registration, DBI peripherals are created from the device tree nodes
provided by the host.
DBI hosts expose operations that can be used by peripheral drivers to
access associated devices.
The original code was authored by Mikko Perttunen; I have aligned it with
the existing MIPI DSI implementation.
Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/Makefile | 2 +-
drivers/gpu/drm/drm_mipi_dbi_bus.c | 232 +++++++++++++++++++++++++++++
include/drm/drm_mipi_dbi_bus.h | 103 +++++++++++++
3 files changed, 336 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/drm_mipi_dbi_bus.c
create mode 100644 include/drm/drm_mipi_dbi_bus.h
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 2c6bc093a923a..880f0dc930b85 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -166,7 +166,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
obj-y += tests/
-obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
+obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o drm_mipi_dbi_bus.o
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
obj-y += arm/
obj-y += clients/
diff --git a/drivers/gpu/drm/drm_mipi_dbi_bus.c b/drivers/gpu/drm/drm_mipi_dbi_bus.c
new file mode 100644
index 0000000000000..afad1f1508064
--- /dev/null
+++ b/drivers/gpu/drm/drm_mipi_dbi_bus.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * MIPI DBI devices with command transport through parallel interface
+ *
+ * Copyright 2026 Mikko Perttunen <mperttunen@nvidia.com>
+ * Copyright 2026 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <drm/drm_mipi_dbi.h>
+#include <drm/drm_mipi_dbi_bus.h>
+
+static int mipi_dbi_match(struct device *dev, const struct device_driver *driver)
+{
+ return of_driver_match_device(dev, driver);
+}
+
+static int mipi_dbi_uevent(const struct device *dev, struct kobj_uevent_env *env)
+{
+ return of_device_uevent_modalias(dev, env);
+}
+
+static const struct dev_pm_ops mipi_dbi_device_pm_ops = {
+ .runtime_suspend = pm_generic_runtime_suspend,
+ .runtime_resume = pm_generic_runtime_resume,
+ .suspend = pm_generic_suspend,
+ .resume = pm_generic_resume,
+ .freeze = pm_generic_freeze,
+ .thaw = pm_generic_thaw,
+ .poweroff = pm_generic_poweroff,
+ .restore = pm_generic_restore,
+};
+
+static const struct bus_type mipi_dbi_bus_type = {
+ .name = "mipi-dbi",
+ .match = mipi_dbi_match,
+ .uevent = mipi_dbi_uevent,
+ .pm = &mipi_dbi_device_pm_ops,
+};
+
+static void mipi_dbi_device_release(struct device *dev)
+{
+ of_node_put(dev->of_node);
+ kfree(to_mipi_dbi_device(dev));
+}
+
+static void mipi_dbi_device_unregister(void *data)
+{
+ struct device *dev = data;
+
+ of_node_clear_flag(dev->of_node, OF_POPULATED);
+ device_unregister(dev);
+}
+
+/**
+ * devm_mipi_dbi_device_register() - create a managed MIPI DBI device
+ * @dev: device to tie the MIPI-DBI device lifetime to
+ * @host: DBI host to which this device is connected
+ * @np: device tree node associated with the panel MIPI DBI device
+ *
+ * This function is called by DBI host driver to create panel device.
+ * It automatically calls mipi_dbi_device_unregister() when @dev is
+ * unbound. It does not automatically free passed device node pointer,
+ * it must be put manually.
+ *
+ * Returns:
+ * A pointer to the newly created MIPI DBI device, or, a pointer encoded
+ * with an error.
+ */
+struct mipi_dbi_device *
+devm_mipi_dbi_device_register(struct device *dev, struct mipi_dbi_host *host,
+ struct device_node *np)
+{
+ struct mipi_dbi_device *dbidev;
+ int ret;
+
+ if (!host || !host->dev || !host->dbi || !host->dbi->command ||
+ !host->ops || !host->ops->attach || !host->ops->detach || !np)
+ return ERR_PTR(-EINVAL);
+
+ if (!of_device_is_available(np))
+ return ERR_PTR(-ENODEV);
+
+ dbidev = kzalloc_obj(*dbidev);
+ if (!dbidev)
+ return ERR_PTR(-ENOMEM);
+
+ if (of_node_test_and_set_flag(np, OF_POPULATED)) {
+ kfree(dbidev);
+ return ERR_PTR(-EBUSY);
+ }
+
+ dbidev->host = host;
+ dbidev->dbi = host->dbi;
+ device_initialize(&dbidev->dev);
+ dbidev->dev.parent = host->dev;
+ dbidev->dev.bus = &mipi_dbi_bus_type;
+ dbidev->dev.release = mipi_dbi_device_release;
+ device_set_node(&dbidev->dev, of_fwnode_handle(of_node_get(np)));
+
+ ret = dev_set_name(&dbidev->dev, "%s:%s", dev_name(host->dev), np->full_name);
+ if (ret)
+ goto put_device;
+
+ ret = device_add(&dbidev->dev);
+ if (ret)
+ goto put_device;
+
+ ret = devm_add_action_or_reset(dev, mipi_dbi_device_unregister,
+ &dbidev->dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return dbidev;
+
+put_device:
+ of_node_clear_flag(np, OF_POPULATED);
+ put_device(&dbidev->dev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(devm_mipi_dbi_device_register);
+
+static void mipi_dbi_detach(void *data)
+{
+ struct mipi_dbi_device *dbidev = data;
+
+ dbidev->host->ops->detach(dbidev->host, dbidev);
+ dbidev->attached = false;
+}
+
+/**
+ * devm_mipi_dbi_attach() - managed attach of DBI device to its DBI host
+ * @dev: device to tie the MIPI-DBI device lifetime to
+ * @dbidev: DBI peripheral
+ */
+int devm_mipi_dbi_attach(struct device *dev, struct mipi_dbi_device *dbidev)
+{
+ int ret;
+
+ if (dbidev->attached)
+ return -EBUSY;
+
+ ret = dbidev->host->ops->attach(dbidev->host, dbidev);
+ if (ret)
+ return ret;
+
+ dbidev->attached = true;
+ return devm_add_action_or_reset(dev, mipi_dbi_detach, dbidev);
+}
+EXPORT_SYMBOL_GPL(devm_mipi_dbi_attach);
+
+static int mipi_dbi_drv_probe(struct device *dev)
+{
+ struct mipi_dbi_driver *drv = to_mipi_dbi_driver(dev->driver);
+ struct mipi_dbi_device *dbidev = to_mipi_dbi_device(dev);
+
+ return drv->probe(dbidev);
+}
+
+static int mipi_dbi_drv_remove(struct device *dev)
+{
+ struct mipi_dbi_driver *drv = to_mipi_dbi_driver(dev->driver);
+ struct mipi_dbi_device *dbidev = to_mipi_dbi_device(dev);
+
+ drv->remove(dbidev);
+
+ return 0;
+}
+
+static void mipi_dbi_drv_shutdown(struct device *dev)
+{
+ struct mipi_dbi_driver *drv = to_mipi_dbi_driver(dev->driver);
+ struct mipi_dbi_device *dbidev = to_mipi_dbi_device(dev);
+
+ drv->shutdown(dbidev);
+}
+
+/**
+ * __mipi_dbi_driver_register() - register a driver for DBI devices
+ * @drv: DBI driver structure
+ * @owner: owner module
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int __mipi_dbi_driver_register(struct mipi_dbi_driver *drv, struct module *owner)
+{
+ drv->driver.bus = &mipi_dbi_bus_type;
+ drv->driver.owner = owner;
+
+ if (drv->probe)
+ drv->driver.probe = mipi_dbi_drv_probe;
+ if (drv->remove)
+ drv->driver.remove = mipi_dbi_drv_remove;
+ if (drv->shutdown)
+ drv->driver.shutdown = mipi_dbi_drv_shutdown;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(__mipi_dbi_driver_register);
+
+/**
+ * mipi_dbi_driver_unregister() - unregister a driver for DBI devices
+ * @drv: DBI driver structure
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+void mipi_dbi_driver_unregister(struct mipi_dbi_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(mipi_dbi_driver_unregister);
+
+static int __init mipi_dbi_bus_init(void)
+{
+ return bus_register(&mipi_dbi_bus_type);
+}
+subsys_initcall(mipi_dbi_bus_init);
+
+static void __exit mipi_dbi_bus_exit(void)
+{
+ bus_unregister(&mipi_dbi_bus_type);
+}
+module_exit(mipi_dbi_bus_exit);
+
+MODULE_DESCRIPTION("MIPI DBI devices with command transport through parallel interface");
+MODULE_LICENSE("GPL");
diff --git a/include/drm/drm_mipi_dbi_bus.h b/include/drm/drm_mipi_dbi_bus.h
new file mode 100644
index 0000000000000..2b8b59bffd0b8
--- /dev/null
+++ b/include/drm/drm_mipi_dbi_bus.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * MIPI DBI devices with command transport through parallel interface
+ *
+ * Copyright 2026 Mikko Perttunen <mperttunen@nvidia.com>
+ * Copyright 2026 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#ifndef __DRM_MIPI_DBI_BUS_H__
+#define __DRM_MIPI_DBI_BUS_H__
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+struct device_node;
+struct mipi_dbi;
+struct mipi_dbi_device;
+struct mipi_dbi_host;
+
+/**
+ * struct mipi_dbi_host_ops - DBI bus operations
+ * @attach: attach DBI device to DBI host
+ * @detach: detach DBI device from DBI host
+ */
+struct mipi_dbi_host_ops {
+ int (*attach)(struct mipi_dbi_host *host, struct mipi_dbi_device *dev);
+ void (*detach)(struct mipi_dbi_host *host, struct mipi_dbi_device *dev);
+};
+
+/**
+ * struct mipi_dbi_host - DBI host device
+ * @dev: driver model device node for this DBI host
+ * @dbi: MIPI DBI interface
+ * @ops: DBI host operations
+ */
+struct mipi_dbi_host {
+ struct device *dev;
+ struct mipi_dbi *dbi;
+ const struct mipi_dbi_host_ops *ops;
+};
+
+/**
+ * struct mipi_dbi_device - DBI peripheral device
+ * @dev: driver model device node for this peripheral
+ * @dbi: MIPI DBI interface
+ * @host: DBI host for this peripheral
+ * @attached: the DBI device has been successfully attached
+ */
+struct mipi_dbi_device {
+ struct device dev;
+ struct mipi_dbi *dbi;
+ struct mipi_dbi_host *host;
+ bool attached;
+};
+
+#define to_mipi_dbi_device(__dev) container_of_const(__dev, struct mipi_dbi_device, dev)
+
+struct mipi_dbi_device *
+devm_mipi_dbi_device_register(struct device *dev, struct mipi_dbi_host *host,
+ struct device_node *np);
+int devm_mipi_dbi_attach(struct device *dev, struct mipi_dbi_device *dbidev);
+
+/**
+ * struct mipi_dbi_driver - DBI driver
+ * @driver: device driver model driver
+ * @probe: callback for device binding
+ * @remove: callback for device unbinding
+ * @shutdown: called at shutdown time to quiesce the device
+ */
+struct mipi_dbi_driver {
+ struct device_driver driver;
+ int (*probe)(struct mipi_dbi_device *dbi);
+ void (*remove)(struct mipi_dbi_device *dbi);
+ void (*shutdown)(struct mipi_dbi_device *dbi);
+};
+
+static inline struct mipi_dbi_driver *
+to_mipi_dbi_driver(struct device_driver *driver)
+{
+ return container_of(driver, struct mipi_dbi_driver, driver);
+}
+
+static inline void *mipi_dbi_get_drvdata(const struct mipi_dbi_device *dbi)
+{
+ return dev_get_drvdata(&dbi->dev);
+}
+
+static inline void mipi_dbi_set_drvdata(struct mipi_dbi_device *dbi, void *data)
+{
+ dev_set_drvdata(&dbi->dev, data);
+}
+
+int __mipi_dbi_driver_register(struct mipi_dbi_driver *drv, struct module *owner);
+void mipi_dbi_driver_unregister(struct mipi_dbi_driver *drv);
+
+#define mipi_dbi_driver_register(driver) \
+ __mipi_dbi_driver_register(driver, THIS_MODULE)
+
+#define module_mipi_dbi_driver(__mipi_dbi_driver) \
+ module_driver(__mipi_dbi_driver, mipi_dbi_driver_register, \
+ mipi_dbi_driver_unregister)
+
+#endif /* __DRM_MIPI_DBI_BUS__ */
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 02/11] dt-bindings: display: panel: Document Hitachi TX10D07VM0BAA and LG LH400WV3 panels
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
2026-10-29 15:28 ` [PATCH v5 01/11] drm: Add MIPI DBI bus support Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 03/11] drm/panel: Add Hitachi TX10D07VM0BAA MIPI DBI Type B panel driver Svyatoslav Ryhel
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Document Hitachi TX10D07VM0BAA and LG LH400WV3 MIPI DBI 4" WVGA panels
found in LG Optimus 2X P990.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
.../display/panel/hit,tx10d07vm0baa.yaml | 58 +++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/panel/hit,tx10d07vm0baa.yaml
diff --git a/Documentation/devicetree/bindings/display/panel/hit,tx10d07vm0baa.yaml b/Documentation/devicetree/bindings/display/panel/hit,tx10d07vm0baa.yaml
new file mode 100644
index 0000000000000..4642dc14c42eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/hit,tx10d07vm0baa.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/hit,tx10d07vm0baa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Hitachi/LG 4" WVGA TFT LCD panel
+
+maintainers:
+ - Svyatoslav Ryhel <clamor95@gmail.com>
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - hit,tx10d07vm0baa
+ - lg,lh400wv3-sd04
+
+ avci-supply:
+ description: Panel power supply
+
+ iovcc-supply:
+ description: I/O voltage supply
+
+ reset-gpios: true
+
+ backlight: true
+ port: true
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ panel {
+ compatible = "lg,lh400wv3-sd04";
+
+ reset-gpios = <&gpio 175 GPIO_ACTIVE_LOW>;
+
+ avci-supply = <&vcc_2v8_lcd>;
+ iovcc-supply = <&iovcc_1v8_lcd>;
+
+ backlight = <&backlight>;
+
+ port {
+ endpoint {
+ remote-endpoint = <&dbi_out>;
+ };
+ };
+ };
+...
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 03/11] drm/panel: Add Hitachi TX10D07VM0BAA MIPI DBI Type B panel driver
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
2026-10-29 15:28 ` [PATCH v5 01/11] drm: Add MIPI DBI bus support Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 02/11] dt-bindings: display: panel: Document Hitachi TX10D07VM0BAA and LG LH400WV3 panels Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 04/11] drm/panel: Add LG LH400WV3-SD04 " Svyatoslav Ryhel
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Add a driver for panel used in LG Optimus 2X P990. Panel is 4" WVGA MIPI
DBI Type B linked to DRM encoder via RGB to DBI bridge.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/panel/Kconfig | 14 +
drivers/gpu/drm/panel/Makefile | 1 +
.../drm/panel/panel-hitachi-tx10d07vm0baa.c | 294 ++++++++++++++++++
3 files changed, 309 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-hitachi-tx10d07vm0baa.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 7a520b4d60fef..0e86628bcdb80 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -274,6 +274,20 @@ config DRM_PANEL_HIMAX_HX8394
If M is selected the module will be called panel-himax-hx8394.
+config DRM_PANEL_HITACHI_TX10D07VM0BAA
+ tristate "Hitachi TX10D07VM0BAA MIPI DBI Type B panel"
+ depends on OF
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_MIPI_DBI
+ select VIDEOMODE_HELPERS
+ help
+ Say Y here if you want to enable support for the HITACHI
+ TX10D07VM0BAA MIPI DBI Type B panel found in the LG Optimus 2X
+ P990 smartphone.
+
+ To compile this driver as a module, choose M here: the module will
+ be called panel-hitachi-tx10d07vm0baa.
+
config DRM_PANEL_HYDIS_HV101HD1
tristate "Hydis HV101HD1 panel"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index da5175909d540..2f57e350311f3 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83121A) += panel-himax-hx83121a.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
+obj-$(CONFIG_DRM_PANEL_HITACHI_TX10D07VM0BAA) += panel-hitachi-tx10d07vm0baa.o
obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7807S) += panel-ilitek-ili7807s.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7836A) += panel-ilitek-ili7836a.o
diff --git a/drivers/gpu/drm/panel/panel-hitachi-tx10d07vm0baa.c b/drivers/gpu/drm/panel/panel-hitachi-tx10d07vm0baa.c
new file mode 100644
index 0000000000000..5ccc8d4725bc6
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-hitachi-tx10d07vm0baa.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dbi.h>
+#include <drm/drm_mipi_dbi_bus.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+static const struct regulator_bulk_data hitachi_tx10d07vm0baa_supplies[] = {
+ { .supply = "avci" }, { .supply = "iovcc" },
+};
+
+struct hitachi_tx10d07vm0baa {
+ struct drm_panel panel;
+ struct mipi_dbi_device *dbi;
+
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct hitachi_tx10d07vm0baa *to_hitachi_tx10d07vm0baa(struct drm_panel *panel)
+{
+ return container_of(panel, struct hitachi_tx10d07vm0baa, panel);
+}
+
+#define panel_dbi_command(dbidev, cmd, seq...) \
+({ \
+ const u8 d[] = { seq }; \
+ struct device *dev = &(dbidev)->dev; \
+ int ret; \
+ ret = mipi_dbi_command_stackbuf((dbidev)->dbi, cmd, d, ARRAY_SIZE(d)); \
+ if (ret) \
+ dev_err_ratelimited(dev, "error %d when sending command %#02x\n", ret, cmd); \
+ ret; \
+})
+
+static int hitachi_tx10d07vm0baa_prepare(struct drm_panel *panel)
+{
+ struct hitachi_tx10d07vm0baa *priv = to_hitachi_tx10d07vm0baa(panel);
+ struct device *dev = panel->dev;
+ int ret;
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(hitachi_tx10d07vm0baa_supplies), priv->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable power supplies: %d\n", ret);
+ return ret;
+ }
+
+ usleep_range(1000, 2000);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+
+ usleep_range(10000, 11000);
+
+ return 0;
+};
+
+static int hitachi_tx10d07vm0baa_enable(struct drm_panel *panel)
+{
+ struct hitachi_tx10d07vm0baa *priv = to_hitachi_tx10d07vm0baa(panel);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_PARTIAL_ROWS, 0x00, 0x00, 0x03, 0x1f);
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_SCROLL_AREA, 0x00, 0x00, 0x03, 0x20,
+ 0x00, 0x00);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_ADDRESS_MODE, 0x0a);
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_SCROLL_START, 0x00, 0x00);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_24BIT);
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x00);
+
+ panel_dbi_command(priv->dbi, 0x71, 0x00); /* Ex_Vsync_en */
+
+ panel_dbi_command(priv->dbi, 0xb2, 0x00); /* VCSEL */
+ panel_dbi_command(priv->dbi, 0xb4, 0xaa); /* setvgmpm */
+ panel_dbi_command(priv->dbi, 0xb5, 0x33); /* rbias1 */
+ panel_dbi_command(priv->dbi, 0xb6, 0x03); /* rbias2 */
+
+ panel_dbi_command(priv->dbi, 0xb7, 0x1a, 0x33, 0x03, 0x03,
+ 0x03, 0x00, 0x00, 0x01, 0x02, 0x00,
+ 0x00, 0x04, 0x00, 0x01, 0x01, 0x01); /* set_ddvdhp */
+ panel_dbi_command(priv->dbi, 0xb8, 0x1c, 0x53, 0x03, 0x03,
+ 0x00, 0x01, 0x02, 0x00, 0x00, 0x04,
+ 0x00, 0x01, 0x01); /* set_ddvdhm */
+
+ panel_dbi_command(priv->dbi, 0xb9, 0x0a, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x01); /* set_vgh */
+ panel_dbi_command(priv->dbi, 0xba, 0x0f, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x01); /* set_vgl */
+ panel_dbi_command(priv->dbi, 0xbb, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x01); /* set_vcl */
+
+ panel_dbi_command(priv->dbi, 0xc1, 0x01); /* number of lines */
+ panel_dbi_command(priv->dbi, 0xc2, 0x08); /* number of fp lines */
+ panel_dbi_command(priv->dbi, 0xc3, 0x04); /* gateset(1) */
+ panel_dbi_command(priv->dbi, 0xc4, 0x4c); /* 1h period */
+ panel_dbi_command(priv->dbi, 0xc5, 0x03); /* source precharge */
+ panel_dbi_command(priv->dbi, 0xc6, 0xc4, 0x04); /* source precharge timing */
+ panel_dbi_command(priv->dbi, 0xc7, 0x00); /* source level */
+ panel_dbi_command(priv->dbi, 0xc8, 0x02); /* number of bp lines */
+ panel_dbi_command(priv->dbi, 0xc9, 0x10); /* gateset(2) */
+ panel_dbi_command(priv->dbi, 0xca, 0x04, 0x04); /* gateset(3) */
+ panel_dbi_command(priv->dbi, 0xcb, 0x03); /* gateset(4) */
+ panel_dbi_command(priv->dbi, 0xcc, 0x12); /* gateset(5) */
+ panel_dbi_command(priv->dbi, 0xcd, 0x12); /* gateset(6) */
+ panel_dbi_command(priv->dbi, 0xce, 0x30); /* gateset(7) */
+ panel_dbi_command(priv->dbi, 0xcf, 0x30); /* gateset(8) */
+ panel_dbi_command(priv->dbi, 0xd0, 0x40); /* gateset(9) */
+ panel_dbi_command(priv->dbi, 0xd1, 0x22); /* flhw */
+ panel_dbi_command(priv->dbi, 0xd2, 0x22); /* vckhw */
+ panel_dbi_command(priv->dbi, 0xd3, 0x04); /* flt */
+ panel_dbi_command(priv->dbi, 0xd4, 0x14); /* tctrl */
+ panel_dbi_command(priv->dbi, 0xd6, 0x02); /* dotinv */
+ panel_dbi_command(priv->dbi, 0xd7, 0x00); /* on/off sequence period */
+
+ panel_dbi_command(priv->dbi, 0xd8, 0x01, 0x05, 0x06, 0x0d,
+ 0x18, 0x09, 0x22, 0x23, 0x00); /* ponseqa */
+ panel_dbi_command(priv->dbi, 0xd9, 0x24, 0x01); /* ponseqb */
+ panel_dbi_command(priv->dbi, 0xde, 0x09, 0x0f, 0x21, 0x12,
+ 0x04); /* ponseqc */
+
+ panel_dbi_command(priv->dbi, 0xdf, 0x02, 0x06, 0x06, 0x06,
+ 0x06, 0x00); /* pofseqa */
+ panel_dbi_command(priv->dbi, 0xe0, 0x01); /* pofseqb */
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0xff);
+ panel_dbi_command(priv->dbi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x40);
+
+ panel_dbi_command(priv->dbi, 0xe2, 0x00, 0x00); /* cabc pwm */
+ panel_dbi_command(priv->dbi, 0xe3, 0x03); /* cabc */
+ panel_dbi_command(priv->dbi, 0xe4, 0x66, 0x7b, 0x90, 0xa5,
+ 0xbb, 0xc7, 0xe1, 0xe5); /* cabc brightness */
+ panel_dbi_command(priv->dbi, 0xe5, 0xc5, 0xc5, 0xc9, 0xc9,
+ 0xd1, 0xe1, 0xf1, 0xfe); /* cabc brightness */
+ panel_dbi_command(priv->dbi, 0xe7, 0x2a); /* cabc */
+ panel_dbi_command(priv->dbi, 0xe8, 0x00); /* brt_rev */
+ panel_dbi_command(priv->dbi, 0xe9, 0x00); /* tefreq */
+
+ panel_dbi_command(priv->dbi, 0xea, 0x01); /* high speed ram */
+
+ panel_dbi_command(priv->dbi, 0xeb, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting r pos */
+ panel_dbi_command(priv->dbi, 0xec, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting r neg */
+ panel_dbi_command(priv->dbi, 0xed, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting g pos */
+ panel_dbi_command(priv->dbi, 0xee, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting g neg */
+ panel_dbi_command(priv->dbi, 0xef, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting b pos */
+ panel_dbi_command(priv->dbi, 0xf0, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting b neg */
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_EXIT_SLEEP_MODE);
+ msleep(110);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_DISPLAY_ON);
+
+ return 0;
+}
+
+static int hitachi_tx10d07vm0baa_disable(struct drm_panel *panel)
+{
+ struct hitachi_tx10d07vm0baa *priv = to_hitachi_tx10d07vm0baa(panel);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_DISPLAY_OFF);
+ msleep(35);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_ENTER_SLEEP_MODE);
+ msleep(50);
+
+ return 0;
+}
+
+static int hitachi_tx10d07vm0baa_unprepare(struct drm_panel *panel)
+{
+ struct hitachi_tx10d07vm0baa *priv = to_hitachi_tx10d07vm0baa(panel);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(hitachi_tx10d07vm0baa_supplies), priv->supplies);
+
+ msleep(50);
+
+ return 0;
+}
+
+static const struct drm_display_mode hitachi_tx10d07vm0baa_mode = {
+ .clock = (480 + 10 + 10 + 10) * (800 + 4 + 4 + 4) * 60 / 1000,
+ .hdisplay = 480,
+ .hsync_start = 480 + 10,
+ .hsync_end = 480 + 10 + 10,
+ .htotal = 480 + 10 + 10 + 10,
+ .vdisplay = 800,
+ .vsync_start = 800 + 4,
+ .vsync_end = 800 + 4 + 4,
+ .vtotal = 800 + 4 + 4 + 4,
+ .width_mm = 52,
+ .height_mm = 86,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static int hitachi_tx10d07vm0baa_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+
+ connector->display_info.bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_DATA_LSB_TO_MSB;
+
+ return drm_connector_helper_get_modes_fixed(connector, &hitachi_tx10d07vm0baa_mode);
+}
+
+static const struct drm_panel_funcs hitachi_tx10d07vm0baa_panel_funcs = {
+ .prepare = hitachi_tx10d07vm0baa_prepare,
+ .enable = hitachi_tx10d07vm0baa_enable,
+ .disable = hitachi_tx10d07vm0baa_disable,
+ .unprepare = hitachi_tx10d07vm0baa_unprepare,
+ .get_modes = hitachi_tx10d07vm0baa_get_modes,
+};
+
+static int hitachi_tx10d07vm0baa_probe(struct mipi_dbi_device *dbi)
+{
+ struct hitachi_tx10d07vm0baa *priv;
+ struct device *dev = &dbi->dev;
+ int ret;
+
+ priv = devm_drm_panel_alloc(dev, struct hitachi_tx10d07vm0baa, panel,
+ &hitachi_tx10d07vm0baa_panel_funcs, DRM_MODE_CONNECTOR_DPI);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(hitachi_tx10d07vm0baa_supplies),
+ hitachi_tx10d07vm0baa_supplies, &priv->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get supplies\n");
+
+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ priv->dbi = dbi;
+ mipi_dbi_set_drvdata(dbi, priv);
+
+ ret = drm_panel_of_backlight(&priv->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get backlight\n");
+
+ ret = devm_drm_panel_add(dev, &priv->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add panel\n");
+
+ return devm_mipi_dbi_attach(dev, dbi);
+}
+
+static const struct of_device_id hitachi_tx10d07vm0baa_of_match[] = {
+ { .compatible = "hit,tx10d07vm0baa" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, hitachi_tx10d07vm0baa_of_match);
+
+static struct mipi_dbi_driver hitachi_tx10d07vm0baa_driver = {
+ .driver = {
+ .name = "panel-hitachi-tx10d07vm0baa",
+ .of_match_table = hitachi_tx10d07vm0baa_of_match,
+ },
+ .probe = hitachi_tx10d07vm0baa_probe,
+};
+module_mipi_dbi_driver(hitachi_tx10d07vm0baa_driver);
+
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("HITACHI TX10D07VM0BAA MIPI DBI Type B panel driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 04/11] drm/panel: Add LG LH400WV3-SD04 MIPI DBI Type B panel driver
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (2 preceding siblings ...)
2026-10-29 15:29 ` [PATCH v5 03/11] drm/panel: Add Hitachi TX10D07VM0BAA MIPI DBI Type B panel driver Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 05/11] drm/tegra: dc: Refactor and expand header Svyatoslav Ryhel
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Add a driver for panel used in LG Optimus 2X P990. Panel is 4" WVGA MIPI
DBI Type B linked to DRM encoder via RGB to DBI bridge.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/panel/Kconfig | 13 ++
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-lg-lh400wv3.c | 233 ++++++++++++++++++++++
3 files changed, 247 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-lg-lh400wv3.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 0e86628bcdb80..036602e577953 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -554,6 +554,19 @@ config DRM_PANEL_LG_LG4573
Say Y here if you want to enable support for LG4573 RGB panel.
To compile this driver as a module, choose M here.
+config DRM_PANEL_LG_LH400WV3
+ tristate "LG LH400WV3 MIPI DBI Type B panel"
+ depends on OF
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_MIPI_DBI
+ select VIDEOMODE_HELPERS
+ help
+ Say Y here if you want to enable support for the LG LH400WV3 MIPI
+ DBI Type B panel found in the LG Optimus 2X P990 smartphone.
+
+ To compile this driver as a module, choose M here: the module will
+ be called panel-lg-lh400wv3.
+
config DRM_PANEL_LG_SW43408
tristate "LG SW43408 panel"
depends on GPIOLIB
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 2f57e350311f3..bed77ae90b660 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_DRM_PANEL_LINCOLNTECH_LCD197) += panel-lincolntech-lcd197.o
obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
obj-$(CONFIG_DRM_PANEL_LG_LD070WX3) += panel-lg-ld070wx3.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
+obj-$(CONFIG_DRM_PANEL_LG_LH400WV3) += panel-lg-lh400wv3.o
obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
obj-$(CONFIG_DRM_PANEL_LXD_M9189A) += panel-lxd-m9189a.o
obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
diff --git a/drivers/gpu/drm/panel/panel-lg-lh400wv3.c b/drivers/gpu/drm/panel/panel-lg-lh400wv3.c
new file mode 100644
index 0000000000000..8a11049948635
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-lg-lh400wv3.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dbi.h>
+#include <drm/drm_mipi_dbi_bus.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+static const struct regulator_bulk_data lg_lh400wv3_supplies[] = {
+ { .supply = "avci" }, { .supply = "iovcc" },
+};
+
+struct lg_lh400wv3 {
+ struct drm_panel panel;
+ struct mipi_dbi_device *dbi;
+
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct lg_lh400wv3 *to_lg_lh400wv3(struct drm_panel *panel)
+{
+ return container_of(panel, struct lg_lh400wv3, panel);
+}
+
+#define panel_dbi_command(dbidev, cmd, seq...) \
+({ \
+ const u8 d[] = { seq }; \
+ struct device *dev = &(dbidev)->dev; \
+ int ret; \
+ ret = mipi_dbi_command_stackbuf((dbidev)->dbi, cmd, d, ARRAY_SIZE(d)); \
+ if (ret) \
+ dev_err_ratelimited(dev, "error %d when sending command %#02x\n", ret, cmd); \
+ ret; \
+})
+
+static int lg_lh400wv3_prepare(struct drm_panel *panel)
+{
+ struct lg_lh400wv3 *priv = to_lg_lh400wv3(panel);
+ struct device *dev = panel->dev;
+ int ret;
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(lg_lh400wv3_supplies), priv->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable power supplies: %d\n", ret);
+ return ret;
+ }
+
+ usleep_range(1000, 2000);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+
+ usleep_range(10000, 11000);
+
+ return 0;
+};
+
+static int lg_lh400wv3_enable(struct drm_panel *panel)
+{
+ struct lg_lh400wv3 *priv = to_lg_lh400wv3(panel);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_EXIT_INVERT_MODE);
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_TEAR_ON);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_24BIT |
+ MIPI_DCS_PIXEL_FMT_24BIT << 4);
+
+ panel_dbi_command(priv->dbi, 0xb2, 0x00, 0xc8);
+ panel_dbi_command(priv->dbi, 0xb3, 0x00);
+ panel_dbi_command(priv->dbi, 0xb4, 0x04);
+ panel_dbi_command(priv->dbi, 0xb5, 0x42, 0x10, 0x10, 0x00, 0x20);
+ panel_dbi_command(priv->dbi, 0xb6, 0x0b, 0x0f, 0x3c, 0x13, 0x13, 0xe8);
+ panel_dbi_command(priv->dbi, 0xb7, 0x4c, 0x06, 0x0c, 0x00, 0x00);
+
+ panel_dbi_command(priv->dbi, 0xc0, 0x01, 0x11);
+ panel_dbi_command(priv->dbi, 0xc3, 0x07, 0x03, 0x04, 0x04, 0x04);
+ panel_dbi_command(priv->dbi, 0xc4, 0x12, 0x24, 0x18, 0x18, 0x02, 0x49);
+ panel_dbi_command(priv->dbi, 0xc5, 0x65);
+ panel_dbi_command(priv->dbi, 0xc6, 0x41, 0x63);
+
+ panel_dbi_command(priv->dbi, 0xd0, 0x00, 0x46, 0x74, 0x32, 0x1d, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv->dbi, 0xd1, 0x00, 0x46, 0x74, 0x32, 0x1d, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv->dbi, 0xd2, 0x00, 0x46, 0x74, 0x32, 0x1f, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv->dbi, 0xd3, 0x00, 0x46, 0x74, 0x32, 0x1f, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv->dbi, 0xd4, 0x01, 0x46, 0x74, 0x25, 0x00, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv->dbi, 0xd5, 0x01, 0x46, 0x74, 0x25, 0x00, 0x03, 0x51, 0x15, 0x04);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0xdf);
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_PAGE_ADDRESS, 0x00, 0x00, 0x03, 0x1f);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_EXIT_SLEEP_MODE);
+ msleep(120);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_WRITE_MEMORY_START);
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_DISPLAY_ON);
+
+ return 0;
+}
+
+static int lg_lh400wv3_disable(struct drm_panel *panel)
+{
+ struct lg_lh400wv3 *priv = to_lg_lh400wv3(panel);
+
+ panel_dbi_command(priv->dbi, MIPI_DCS_SET_DISPLAY_OFF);
+ panel_dbi_command(priv->dbi, MIPI_DCS_ENTER_SLEEP_MODE);
+ msleep(150);
+
+ panel_dbi_command(priv->dbi, 0xc1, 0x01);
+ usleep_range(10000, 11000);
+
+ return 0;
+};
+
+static int lg_lh400wv3_unprepare(struct drm_panel *panel)
+{
+ struct lg_lh400wv3 *priv = to_lg_lh400wv3(panel);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(lg_lh400wv3_supplies), priv->supplies);
+
+ msleep(50);
+
+ return 0;
+}
+
+static const struct drm_display_mode lg_lh400wv3_mode = {
+ .clock = (480 + 10 + 10 + 10) * (800 + 4 + 4 + 4) * 60 / 1000,
+ .hdisplay = 480,
+ .hsync_start = 480 + 10,
+ .hsync_end = 480 + 10 + 10,
+ .htotal = 480 + 10 + 10 + 10,
+ .vdisplay = 800,
+ .vsync_start = 800 + 4,
+ .vsync_end = 800 + 4 + 4,
+ .vtotal = 800 + 4 + 4 + 4,
+ .width_mm = 52,
+ .height_mm = 86,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static int lg_lh400wv3_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+
+ connector->display_info.bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_DATA_LSB_TO_MSB;
+
+ return drm_connector_helper_get_modes_fixed(connector, &lg_lh400wv3_mode);
+}
+
+static const struct drm_panel_funcs lg_lh400wv3_panel_funcs = {
+ .prepare = lg_lh400wv3_prepare,
+ .enable = lg_lh400wv3_enable,
+ .disable = lg_lh400wv3_disable,
+ .unprepare = lg_lh400wv3_unprepare,
+ .get_modes = lg_lh400wv3_get_modes,
+};
+
+static int lg_lh400wv3_probe(struct mipi_dbi_device *dbi)
+{
+ struct device *dev = &dbi->dev;
+ struct lg_lh400wv3 *priv;
+ int ret;
+
+ priv = devm_drm_panel_alloc(dev, struct lg_lh400wv3, panel,
+ &lg_lh400wv3_panel_funcs, DRM_MODE_CONNECTOR_DPI);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(lg_lh400wv3_supplies),
+ lg_lh400wv3_supplies, &priv->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get supplies\n");
+
+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ priv->dbi = dbi;
+ mipi_dbi_set_drvdata(dbi, priv);
+
+ ret = drm_panel_of_backlight(&priv->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get backlight\n");
+
+ ret = devm_drm_panel_add(dev, &priv->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add panel\n");
+
+ return devm_mipi_dbi_attach(dev, dbi);
+}
+
+static const struct of_device_id lg_lh400wv3_of_match[] = {
+ { .compatible = "lg,lh400wv3-sd04" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, lg_lh400wv3_of_match);
+
+static struct mipi_dbi_driver lg_lh400wv3_driver = {
+ .driver = {
+ .name = "panel-lg-lh400wv3",
+ .of_match_table = lg_lh400wv3_of_match,
+ },
+ .probe = lg_lh400wv3_probe,
+};
+module_mipi_dbi_driver(lg_lh400wv3_driver);
+
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("LG LH400WV3-SD04 MIPI DBI Type B panel driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 05/11] drm/tegra: dc: Refactor and expand header
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (3 preceding siblings ...)
2026-10-29 15:29 ` [PATCH v5 04/11] drm/panel: Add LG LH400WV3-SD04 " Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 06/11] dt-bindings: display: tegra: Document Tegra20 DSI port Svyatoslav Ryhel
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Refactor and expand existing DC register definitions with additional
fields in preparation for adding the 8-bit CPU interface.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/tegra/dc.c | 11 +-
drivers/gpu/drm/tegra/dc.h | 856 +++++++++++++++++++++---------------
drivers/gpu/drm/tegra/rgb.c | 8 +-
3 files changed, 514 insertions(+), 361 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index b0bfa946e6979..5bbf2c028edd8 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1591,10 +1591,10 @@ static const struct debugfs_reg32 tegra_dc_regs[] = {
DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(5)),
DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(6)),
DEBUGFS_REG32(DC_COM_PIN_MISC_CONTROL),
- DEBUGFS_REG32(DC_COM_PIN_PM0_CONTROL),
- DEBUGFS_REG32(DC_COM_PIN_PM0_DUTY_CYCLE),
- DEBUGFS_REG32(DC_COM_PIN_PM1_CONTROL),
- DEBUGFS_REG32(DC_COM_PIN_PM1_DUTY_CYCLE),
+ DEBUGFS_REG32(DC_COM_PM_CONTROL(0)),
+ DEBUGFS_REG32(DC_COM_PM_DUTY_CYCLE(0)),
+ DEBUGFS_REG32(DC_COM_PM_CONTROL(1)),
+ DEBUGFS_REG32(DC_COM_PM_DUTY_CYCLE(1)),
DEBUGFS_REG32(DC_COM_SPI_CONTROL),
DEBUGFS_REG32(DC_COM_SPI_START_BYTE),
DEBUGFS_REG32(DC_COM_HSPI_WRITE_DATA_AB),
@@ -2384,7 +2384,8 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
if (dc->rgb) {
/* XXX: parameterize? */
- value = SC0_H_QUALIFIER_NONE | SC1_H_QUALIFIER_NONE;
+ value = SC0_H_QUALIFIER(SC_H_QUALIFIER_NONE) |
+ SC1_H_QUALIFIER(SC_H_QUALIFIER_NONE);
tegra_dc_writel(dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);
}
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 0cb0515968b35..2b87bb675d4cf 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -178,9 +178,11 @@ int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_CMD_GENERAL_INCR_SYNCPT 0x000
+
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001
-#define SYNCPT_CNTRL_NO_STALL (1 << 8)
-#define SYNCPT_CNTRL_SOFT_RESET (1 << 0)
+#define SYNCPT_CNTRL_NO_STALL BIT(8)
+#define SYNCPT_CNTRL_SOFT_RESET BIT(0)
+
#define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002
#define DC_CMD_WIN_A_INCR_SYNCPT 0x008
#define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009
@@ -191,101 +193,226 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_CMD_WIN_C_INCR_SYNCPT 0x018
#define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019
#define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a
+
#define DC_CMD_CONT_SYNCPT_VSYNC 0x028
-#define SYNCPT_VSYNC_ENABLE (1 << 8)
+#define SYNCPT_VSYNC_ENABLE BIT(8)
+
#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
+
#define DC_CMD_DISPLAY_COMMAND 0x032
-#define DISP_CTRL_MODE_STOP (0 << 5)
-#define DISP_CTRL_MODE_C_DISPLAY (1 << 5)
-#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5)
-#define DISP_CTRL_MODE_MASK (3 << 5)
+#define DISP_CTRL_MODE_STOP (0 << 5)
+#define DISP_CTRL_MODE_C_DISPLAY (1 << 5)
+#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5)
+#define DISP_CTRL_MODE_MASK (3 << 5)
+
#define DC_CMD_SIGNAL_RAISE 0x033
+
#define DC_CMD_DISPLAY_POWER_CONTROL 0x036
-#define PW0_ENABLE (1 << 0)
-#define PW1_ENABLE (1 << 2)
-#define PW2_ENABLE (1 << 4)
-#define PW3_ENABLE (1 << 6)
-#define PW4_ENABLE (1 << 8)
-#define PM0_ENABLE (1 << 16)
-#define PM1_ENABLE (1 << 18)
+#define PW0_ENABLE BIT(0)
+#define PW1_ENABLE BIT(2)
+#define PW2_ENABLE BIT(4)
+#define PW3_ENABLE BIT(6)
+#define PW4_ENABLE BIT(8)
+#define PM0_ENABLE BIT(16)
+#define PM1_ENABLE BIT(18)
#define DC_CMD_INT_STATUS 0x037
#define DC_CMD_INT_MASK 0x038
#define DC_CMD_INT_ENABLE 0x039
#define DC_CMD_INT_TYPE 0x03a
+
#define DC_CMD_INT_POLARITY 0x03b
-#define CTXSW_INT (1 << 0)
-#define FRAME_END_INT (1 << 1)
-#define VBLANK_INT (1 << 2)
-#define V_PULSE3_INT (1 << 4)
-#define V_PULSE2_INT (1 << 5)
-#define REGION_CRC_INT (1 << 6)
-#define REG_TMOUT_INT (1 << 7)
-#define WIN_A_UF_INT (1 << 8)
-#define WIN_B_UF_INT (1 << 9)
-#define WIN_C_UF_INT (1 << 10)
-#define MSF_INT (1 << 12)
-#define WIN_A_OF_INT (1 << 14)
-#define WIN_B_OF_INT (1 << 15)
-#define WIN_C_OF_INT (1 << 16)
-#define HEAD_UF_INT (1 << 23)
-#define SD3_BUCKET_WALK_DONE_INT (1 << 24)
-#define DSC_OBUF_UF_INT (1 << 26)
-#define DSC_RBUF_UF_INT (1 << 27)
-#define DSC_BBUF_UF_INT (1 << 28)
-#define DSC_TO_UF_INT (1 << 29)
+#define CTXSW_INT BIT(0)
+#define FRAME_END_INT BIT(1)
+#define VBLANK_INT BIT(2)
+#define V_PULSE3_INT BIT(4)
+#define V_PULSE2_INT BIT(5)
+#define REGION_CRC_INT BIT(6)
+#define REG_TMOUT_INT BIT(7)
+#define WIN_A_UF_INT BIT(8)
+#define WIN_B_UF_INT BIT(9)
+#define WIN_C_UF_INT BIT(10)
+#define MSF_INT BIT(12)
+#define WIN_A_OF_INT BIT(14)
+#define WIN_B_OF_INT BIT(15)
+#define WIN_C_OF_INT BIT(16)
+#define HEAD_UF_INT BIT(23)
+#define SD3_BUCKET_WALK_DONE_INT BIT(24)
+#define DSC_OBUF_UF_INT BIT(26)
+#define DSC_RBUF_UF_INT BIT(27)
+#define DSC_BBUF_UF_INT BIT(28)
+#define DSC_TO_UF_INT BIT(29)
#define DC_CMD_SIGNAL_RAISE1 0x03c
#define DC_CMD_SIGNAL_RAISE2 0x03d
#define DC_CMD_SIGNAL_RAISE3 0x03e
#define DC_CMD_STATE_ACCESS 0x040
-#define READ_MUX (1 << 0)
-#define WRITE_MUX (1 << 2)
+#define READ_MUX BIT(0)
+#define WRITE_MUX BIT(2)
#define DC_CMD_STATE_CONTROL 0x041
-#define GENERAL_ACT_REQ (1 << 0)
-#define WIN_A_ACT_REQ (1 << 1)
-#define WIN_B_ACT_REQ (1 << 2)
-#define WIN_C_ACT_REQ (1 << 3)
-#define CURSOR_ACT_REQ (1 << 7)
-#define GENERAL_UPDATE (1 << 8)
-#define WIN_A_UPDATE (1 << 9)
-#define WIN_B_UPDATE (1 << 10)
-#define WIN_C_UPDATE (1 << 11)
-#define CURSOR_UPDATE (1 << 15)
-#define COMMON_ACTREQ (1 << 16)
-#define COMMON_UPDATE (1 << 17)
-#define NC_HOST_TRIG (1 << 24)
+#define GENERAL_ACT_REQ BIT(0)
+#define WIN_A_ACT_REQ BIT(1)
+#define WIN_B_ACT_REQ BIT(2)
+#define WIN_C_ACT_REQ BIT(3)
+#define CURSOR_ACT_REQ BIT(7)
+#define GENERAL_UPDATE BIT(8)
+#define WIN_A_UPDATE BIT(9)
+#define WIN_B_UPDATE BIT(10)
+#define WIN_C_UPDATE BIT(11)
+#define CURSOR_UPDATE BIT(15)
+#define COMMON_ACTREQ BIT(16)
+#define COMMON_UPDATE BIT(17)
+#define NC_HOST_TRIG BIT(24)
#define DC_CMD_DISPLAY_WINDOW_HEADER 0x042
-#define WINDOW_A_SELECT (1 << 4)
-#define WINDOW_B_SELECT (1 << 5)
-#define WINDOW_C_SELECT (1 << 6)
+#define WINDOW_A_SELECT BIT(4)
+#define WINDOW_B_SELECT BIT(5)
+#define WINDOW_C_SELECT BIT(6)
#define DC_CMD_REG_ACT_CONTROL 0x043
#define DC_COM_CRC_CONTROL 0x300
-#define DC_COM_CRC_CONTROL_ALWAYS (1 << 3)
-#define DC_COM_CRC_CONTROL_FULL_FRAME (0 << 2)
-#define DC_COM_CRC_CONTROL_ACTIVE_DATA (1 << 2)
-#define DC_COM_CRC_CONTROL_WAIT (1 << 1)
-#define DC_COM_CRC_CONTROL_ENABLE (1 << 0)
+#define DC_COM_CRC_CONTROL_ALWAYS BIT(3)
+#define DC_COM_CRC_CONTROL_FULL_FRAME (0 << 2)
+#define DC_COM_CRC_CONTROL_ACTIVE_DATA BIT(2)
+#define DC_COM_CRC_CONTROL_WAIT BIT(1)
+#define DC_COM_CRC_CONTROL_ENABLE BIT(0)
+
#define DC_COM_CRC_CHECKSUM 0x301
-#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
-#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
-#define LVS_OUTPUT_POLARITY_LOW (1 << 28)
-#define LHS_OUTPUT_POLARITY_LOW (1 << 30)
-#define DC_COM_PIN_OUTPUT_DATA(x) (0x30a + (x))
-#define DC_COM_PIN_INPUT_ENABLE(x) (0x30e + (x))
-#define DC_COM_PIN_INPUT_DATA(x) (0x312 + (x))
-#define DC_COM_PIN_OUTPUT_SELECT(x) (0x314 + (x))
+
+/* Defines in PIN_OUTPUT/INPUT_* describe pin position, not state */
+#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
+#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
+#define DC_COM_PIN_OUTPUT_DATA(x) (0x30a + (x))
+#define PIN_UNMASK(x) BIT((x) + 1)
+#define DC_COM_PIN_INPUT_ENABLE(x) (0x30e + (x))
+
+/* DC_COM_PIN_OUTPUT/INPUT_*_0 */
+#define PIN_LD0 0
+#define PIN_LD1 2
+#define PIN_LD2 4
+#define PIN_LD3 6
+#define PIN_LD4 8
+#define PIN_LD5 10
+#define PIN_LD6 12
+#define PIN_LD7 14
+#define PIN_LD8 16
+#define PIN_LD9 18
+#define PIN_LD10 20
+#define PIN_LD11 22
+#define PIN_LD12 24
+#define PIN_LD13 26
+#define PIN_LD14 28
+#define PIN_LD15 30
+
+/* DC_COM_PIN_OUTPUT/INPUT_*_1 */
+#define PIN_LD16 0
+#define PIN_LD17 2
+#define PIN_LPW0 16
+#define PIN_LPW1 18
+#define PIN_LPW2 20
+#define PIN_LSC0 24
+#define PIN_LSC1 26
+#define PIN_LVS 28
+#define PIN_LHS 30
+
+/* DC_COM_PIN_OUTPUT/INPUT_*_2 */
+#define PIN_LHP0 0
+#define PIN_LHP1 2
+#define PIN_LHP2 4
+#define PIN_LVP0 8
+#define PIN_LVP1 10
+#define PIN_LM0 16
+#define PIN_LM1 18
+#define PIN_LDI 20
+#define PIN_LPP 22
+
+/* DC_COM_PIN_OUTPUT/INPUT_*_3 */
+#define PIN_LSCK 0
+#define PIN_LSDA 2
+#define PIN_LCSN 4
+#define PIN_LDC 6
+#define PIN_LSPI 8
+#define PIN_LSDI 10
+
+#define DC_COM_PIN_INPUT_DATA(x) (0x312 + (x))
+#define DC_COM_PIN_OUTPUT_SELECT(x) (0x314 + (x))
+#define PIN_OUTPUT_SELECT_MASK(x) (0x7 << (x))
+#define PIN_OUTPUT_SELECT_PRIM(x) (0 << (x))
+#define PIN_OUTPUT_SELECT_OUT(x) (1 << (x))
+#define PIN_OUTPUT_SELECT_F2(x) (2 << (x))
+#define PIN_OUTPUT_SELECT_F3(x) (3 << (x))
+#define PIN_OUTPUT_SELECT_F4(x) (4 << (x))
+#define PIN_OUTPUT_SELECT_F5(x) (5 << (x))
+#define PIN_OUTPUT_SELECT_F6(x) (6 << (x))
+#define PIN_OUTPUT_SELECT_F7(x) (7 << (x))
+
+/* DC_COM_PIN_OUTPUT_SELECT0 */
+#define PIN_OUTPUT_SELECT_LD0 0
+#define PIN_OUTPUT_SELECT_LD1 4
+#define PIN_OUTPUT_SELECT_LD2 8
+#define PIN_OUTPUT_SELECT_LD3 12
+#define PIN_OUTPUT_SELECT_LD4 16
+#define PIN_OUTPUT_SELECT_LD5 20
+#define PIN_OUTPUT_SELECT_LD6 24
+#define PIN_OUTPUT_SELECT_LD7 28
+
+/* DC_COM_PIN_OUTPUT_SELECT1 */
+#define PIN_OUTPUT_SELECT_LD8 0
+#define PIN_OUTPUT_SELECT_LD9 4
+#define PIN_OUTPUT_SELECT_LD10 8
+#define PIN_OUTPUT_SELECT_LD11 12
+#define PIN_OUTPUT_SELECT_LD12 16
+#define PIN_OUTPUT_SELECT_LD13 20
+#define PIN_OUTPUT_SELECT_LD14 24
+#define PIN_OUTPUT_SELECT_LD15 28
+
+/* DC_COM_PIN_OUTPUT_SELECT2 */
+#define PIN_OUTPUT_SELECT_LD16 0
+#define PIN_OUTPUT_SELECT_LD17 4
+
+/* DC_COM_PIN_OUTPUT_SELECT3 */
+#define PIN_OUTPUT_SELECT_LPW0 0
+#define PIN_OUTPUT_SELECT_LPW1 4
+#define PIN_OUTPUT_SELECT_LPW2 8
+#define PIN_OUTPUT_SELECT_LSC0 16
+#define PIN_OUTPUT_SELECT_LSC1 20
+#define PIN_OUTPUT_SELECT_LVS 24
+#define PIN_OUTPUT_SELECT_LHS 28
+
+/* DC_COM_PIN_OUTPUT_SELECT4 */
+#define PIN_OUTPUT_SELECT_LHP0 0
+#define PIN_OUTPUT_SELECT_LHP1 4
+#define PIN_OUTPUT_SELECT_LHP2 8
+#define PIN_OUTPUT_SELECT_LVP0 16
+#define PIN_OUTPUT_SELECT_LVP1 20
+
+/* DC_COM_PIN_OUTPUT_SELECT5 */
+#define PIN_OUTPUT_SELECT_LM0 0
+#define PIN_OUTPUT_SELECT_LM1 4
+#define PIN_OUTPUT_SELECT_LDI 8
+#define PIN_OUTPUT_SELECT_LPP 12
+
+/* DC_COM_PIN_OUTPUT_SELECT6 */
+#define PIN_OUTPUT_SELECT_LSCK 0
+#define PIN_OUTPUT_SELECT_LSDA 4
+#define PIN_OUTPUT_SELECT_LCSN 8
+#define PIN_OUTPUT_SELECT_LDC 12
+#define PIN_OUTPUT_SELECT_LSPI 16
+#define PIN_OUTPUT_SELECT_LSDI 20
#define DC_COM_PIN_MISC_CONTROL 0x31b
-#define DC_COM_PIN_PM0_CONTROL 0x31c
-#define DC_COM_PIN_PM0_DUTY_CYCLE 0x31d
-#define DC_COM_PIN_PM1_CONTROL 0x31e
-#define DC_COM_PIN_PM1_DUTY_CYCLE 0x31f
+#define DC_COM_PM_CONTROL(x) (0x31c + (x) * 2)
+#define PM_CLOCK_SELECT_SHIFT_DIV 0
+#define PM_CLOCK_SELECT_PIX_CLK 1
+#define PM_CLOCK_SELECT_LINE_CLK 2
+#define PM_CLOCK_SELECT_FRAME_CLK 3
+#define PM_CLOCK_DIVIDER(x) (((x) & 0x3f) << 4)
+#define PM_PERIOD(x) (((x) & 0x3f) << 18)
+#define DC_COM_PM_DUTY_CYCLE(x) (0x31d + (x) * 2)
+#define PM_DUTY_CYCLE_MASK(x) ((x) & 0xff)
#define DC_COM_SPI_CONTROL 0x320
#define DC_COM_SPI_START_BYTE 0x321
@@ -299,38 +426,43 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_COM_CRC_CHECKSUM_LATCHED 0x329
#define DC_COM_RG_UNDERFLOW 0x365
-#define UNDERFLOW_MODE_RED (1 << 8)
-#define UNDERFLOW_REPORT_ENABLE (1 << 0)
+#define UNDERFLOW_MODE_RED BIT(8)
+#define UNDERFLOW_REPORT_ENABLE BIT(0)
#define DC_DISP_DISP_SIGNAL_OPTIONS0 0x400
-#define H_PULSE0_ENABLE (1 << 8)
-#define H_PULSE1_ENABLE (1 << 10)
-#define H_PULSE2_ENABLE (1 << 12)
+#define H_PULSE0_ENABLE BIT(8)
+#define H_PULSE1_ENABLE BIT(10)
+#define H_PULSE2_ENABLE BIT(12)
+#define V_PULSE0_ENABLE BIT(16)
+#define V_PULSE1_ENABLE BIT(18)
+#define V_PULSE2_ENABLE BIT(19)
+#define V_PULSE3_ENABLE BIT(20)
+#define M0_ENABLE BIT(24)
+#define M1_ENABLE BIT(26)
#define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401
#define DC_DISP_DISP_WIN_OPTIONS 0x402
-#define HDMI_ENABLE (1 << 30)
-#define DSI_ENABLE (1 << 29)
-#define SOR1_TIMING_CYA (1 << 27)
-#define CURSOR_ENABLE (1 << 16)
-
-#define SOR_ENABLE(x) (1 << (25 + (((x) > 1) ? ((x) + 1) : (x))))
+#define HDMI_ENABLE BIT(30)
+#define DSI_ENABLE BIT(29)
+#define SOR1_TIMING_CYA BIT(27)
+#define SOR_ENABLE(x) BIT((25 + (((x) > 1) ? ((x) + 1) : (x))))
+#define CURSOR_ENABLE BIT(16)
#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403
-#define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24)
-#define WINDOW_A_THRESHOLD(x) (((x) & 0x7f) << 16)
-#define WINDOW_B_THRESHOLD(x) (((x) & 0x7f) << 8)
-#define WINDOW_C_THRESHOLD(x) (((x) & 0xff) << 0)
+#define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24)
+#define WINDOW_A_THRESHOLD(x) (((x) & 0x7f) << 16)
+#define WINDOW_B_THRESHOLD(x) (((x) & 0x7f) << 8)
+#define WINDOW_C_THRESHOLD(x) (((x) & 0xff) << 0)
#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404
-#define CURSOR_DELAY(x) (((x) & 0x3f) << 24)
-#define WINDOW_A_DELAY(x) (((x) & 0x3f) << 16)
-#define WINDOW_B_DELAY(x) (((x) & 0x3f) << 8)
-#define WINDOW_C_DELAY(x) (((x) & 0x3f) << 0)
+#define CURSOR_DELAY(x) (((x) & 0x3f) << 24)
+#define WINDOW_A_DELAY(x) (((x) & 0x3f) << 16)
+#define WINDOW_B_DELAY(x) (((x) & 0x3f) << 8)
+#define WINDOW_C_DELAY(x) (((x) & 0x3f) << 0)
#define DC_DISP_DISP_TIMING_OPTIONS 0x405
-#define VSYNC_H_POSITION(x) ((x) & 0xfff)
+#define VSYNC_H_POSITION(x) ((x) & 0xfff)
#define DC_DISP_REF_TO_SYNC 0x406
#define DC_DISP_SYNC_WIDTH 0x407
@@ -373,99 +505,105 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_DISP_PP_SELECT_C 0x42c
#define DC_DISP_PP_SELECT_D 0x42d
-#define PULSE_MODE_NORMAL (0 << 3)
-#define PULSE_MODE_ONE_CLOCK (1 << 3)
-#define PULSE_POLARITY_HIGH (0 << 4)
-#define PULSE_POLARITY_LOW (1 << 4)
-#define PULSE_QUAL_ALWAYS (0 << 6)
-#define PULSE_QUAL_VACTIVE (2 << 6)
-#define PULSE_QUAL_VACTIVE1 (3 << 6)
-#define PULSE_LAST_START_A (0 << 8)
-#define PULSE_LAST_END_A (1 << 8)
-#define PULSE_LAST_START_B (2 << 8)
-#define PULSE_LAST_END_B (3 << 8)
-#define PULSE_LAST_START_C (4 << 8)
-#define PULSE_LAST_END_C (5 << 8)
-#define PULSE_LAST_START_D (6 << 8)
-#define PULSE_LAST_END_D (7 << 8)
-
-#define PULSE_START(x) (((x) & 0xfff) << 0)
-#define PULSE_END(x) (((x) & 0xfff) << 16)
+/* DC_DISP_H/V_PULSE_CONTROL */
+#define PULSE_MODE_NORMAL (0 << 3)
+#define PULSE_MODE_ONE_CLOCK BIT(3)
+#define PULSE_POLARITY_HIGH (0 << 4)
+#define PULSE_POLARITY_LOW BIT(4)
+#define PULSE_QUAL_ALWAYS (0 << 6)
+#define PULSE_QUAL_VACTIVE (2 << 6)
+#define PULSE_QUAL_VACTIVE1 (3 << 6)
+#define PULSE_LAST_START_A (0 << 8)
+#define PULSE_LAST_END_A (1 << 8)
+#define PULSE_LAST_START_B (2 << 8)
+#define PULSE_LAST_END_B (3 << 8)
+#define PULSE_LAST_START_C (4 << 8)
+#define PULSE_LAST_END_C (5 << 8)
+#define PULSE_LAST_START_D (6 << 8)
+#define PULSE_LAST_END_D (7 << 8)
+
+/* DC_DISP_H/V_PULSE_POSITION */
+#define PULSE_START(x) (((x) & 0xfff) << 0)
+#define PULSE_END(x) (((x) & 0xfff) << 16)
#define DC_DISP_DISP_CLOCK_CONTROL 0x42e
-#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8)
-#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8)
-#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8)
-#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8)
-#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8)
-#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8)
-#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8)
-#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8)
-#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8)
-#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8)
-#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8)
-#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8)
-#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8)
-#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff)
+#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8)
+#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8)
+#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8)
+#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8)
+#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8)
+#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8)
+#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8)
+#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8)
+#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8)
+#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8)
+#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8)
+#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8)
+#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8)
+#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff)
#define DC_DISP_DISP_INTERFACE_CONTROL 0x42f
-#define DISP_DATA_FORMAT_DF1P1C (0 << 0)
-#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0)
-#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0)
-#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0)
-#define DISP_DATA_FORMAT_DF2S (4 << 0)
-#define DISP_DATA_FORMAT_DF3S (5 << 0)
-#define DISP_DATA_FORMAT_DFSPI (6 << 0)
-#define DISP_DATA_FORMAT_DF1P3C24B (7 << 0)
-#define DISP_DATA_FORMAT_DF1P3C18B (8 << 0)
-#define DISP_ALIGNMENT_MSB (0 << 8)
-#define DISP_ALIGNMENT_LSB (1 << 8)
-#define DISP_ORDER_RED_BLUE (0 << 9)
-#define DISP_ORDER_BLUE_RED (1 << 9)
+#define DISP_DATA_FORMAT_DF1P1C 0
+#define DISP_DATA_FORMAT_DF1P2C24B 1
+#define DISP_DATA_FORMAT_DF1P2C18B 2
+#define DISP_DATA_FORMAT_DF1P2C16B 3
+#define DISP_DATA_FORMAT_DF2S 4
+#define DISP_DATA_FORMAT_DF3S 5
+#define DISP_DATA_FORMAT_DFSPI 6
+#define DISP_DATA_FORMAT_DF1P3C24B 7
+#define DISP_DATA_FORMAT_DF1P3C18B 8
+#define DISP_ALIGNMENT_MSB (0 << 8)
+#define DISP_ALIGNMENT_LSB BIT(8)
+#define DISP_ORDER_RED_BLUE (0 << 9)
+#define DISP_ORDER_BLUE_RED BIT(9)
#define DC_DISP_DISP_COLOR_CONTROL 0x430
-#define BASE_COLOR_SIZE666 ( 0 << 0)
-#define BASE_COLOR_SIZE111 ( 1 << 0)
-#define BASE_COLOR_SIZE222 ( 2 << 0)
-#define BASE_COLOR_SIZE333 ( 3 << 0)
-#define BASE_COLOR_SIZE444 ( 4 << 0)
-#define BASE_COLOR_SIZE555 ( 5 << 0)
-#define BASE_COLOR_SIZE565 ( 6 << 0)
-#define BASE_COLOR_SIZE332 ( 7 << 0)
-#define BASE_COLOR_SIZE888 ( 8 << 0)
-#define BASE_COLOR_SIZE101010 (10 << 0)
-#define BASE_COLOR_SIZE121212 (12 << 0)
-#define DITHER_CONTROL_MASK (3 << 8)
-#define DITHER_CONTROL_DISABLE (0 << 8)
-#define DITHER_CONTROL_ORDERED (2 << 8)
-#define DITHER_CONTROL_ERRDIFF (3 << 8)
-#define BASE_COLOR_SIZE_MASK (0xf << 0)
-#define BASE_COLOR_SIZE_666 ( 0 << 0)
-#define BASE_COLOR_SIZE_111 ( 1 << 0)
-#define BASE_COLOR_SIZE_222 ( 2 << 0)
-#define BASE_COLOR_SIZE_333 ( 3 << 0)
-#define BASE_COLOR_SIZE_444 ( 4 << 0)
-#define BASE_COLOR_SIZE_555 ( 5 << 0)
-#define BASE_COLOR_SIZE_565 ( 6 << 0)
-#define BASE_COLOR_SIZE_332 ( 7 << 0)
-#define BASE_COLOR_SIZE_888 ( 8 << 0)
-#define BASE_COLOR_SIZE_101010 ( 10 << 0)
-#define BASE_COLOR_SIZE_121212 ( 12 << 0)
-#define CMU_ENABLE_ENABLE (1 << 20)
+#define BASE_COLOR_SIZE_MASK 0xf
+#define BASE_COLOR_SIZE_666 0
+#define BASE_COLOR_SIZE_111 1
+#define BASE_COLOR_SIZE_222 2
+#define BASE_COLOR_SIZE_333 3
+#define BASE_COLOR_SIZE_444 4
+#define BASE_COLOR_SIZE_555 5
+#define BASE_COLOR_SIZE_565 6
+#define BASE_COLOR_SIZE_332 7
+#define BASE_COLOR_SIZE_888 8
+#define BASE_COLOR_SIZE_101010 10
+#define BASE_COLOR_SIZE_121212 12
+#define DITHER_CONTROL_MASK (3 << 8)
+#define DITHER_CONTROL_DISABLE (0 << 8)
+#define DITHER_CONTROL_ORDERED (2 << 8)
+#define DITHER_CONTROL_ERRDIFF (3 << 8)
+#define DISP_COLOR_SWAP_BGR BIT(16)
+#define CMU_ENABLE_ENABLE BIT(20)
#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
-#define SC1_H_QUALIFIER_NONE (1 << 16)
-#define SC0_H_QUALIFIER_NONE (1 << 0)
+#define SC0_H_QUALIFIER(x) (((x) & 0x7) << 0)
+#define SC1_H_QUALIFIER(x) (((x) & 0x7) << 16)
+#define SC_H_QUALIFIER_DISABLE 0
+#define SC_H_QUALIFIER_NONE 1
+#define SC_H_QUALIFIER_HACTIVE 2
+#define SC_H_QUALIFIER_EXT_HACTIVE 3
+#define SC_H_QUALIFIER_HPULSE 4
+#define SC_H_QUALIFIER_EXT_HPULSE 5
+#define SC0_V_QUALIFIER(x) (((x) & 0x7) << 3)
+#define SC1_V_QUALIFIER(x) (((x) & 0x7) << 19)
+#define SC_V_QUALIFIER_NONE 0
+#define SC_V_QUALIFIER_RSVD 1
+#define SC_V_QUALIFIER_VACTIVE 2
+#define SC_V_QUALIFIER_EXT_VACTIVE 3
+#define SC_V_QUALIFIER_VPULSE 4
+#define SC_V_QUALIFIER_EXT_VPULSE 5
#define DC_DISP_DATA_ENABLE_OPTIONS 0x432
-#define DE_SELECT_ACTIVE_BLANK (0 << 0)
-#define DE_SELECT_ACTIVE (1 << 0)
-#define DE_SELECT_ACTIVE_IS (2 << 0)
-#define DE_CONTROL_ONECLK (0 << 2)
-#define DE_CONTROL_NORMAL (1 << 2)
-#define DE_CONTROL_EARLY_EXT (2 << 2)
-#define DE_CONTROL_EARLY (3 << 2)
-#define DE_CONTROL_ACTIVE_BLANK (4 << 2)
+#define DE_SELECT_ACTIVE_BLANK 0
+#define DE_SELECT_ACTIVE 1
+#define DE_SELECT_ACTIVE_IS 2
+#define DE_CONTROL_ONECLK (0 << 2)
+#define DE_CONTROL_NORMAL (1 << 2)
+#define DE_CONTROL_EARLY_EXT (2 << 2)
+#define DE_CONTROL_EARLY (3 << 2)
+#define DE_CONTROL_ACTIVE_BLANK (4 << 2)
#define DC_DISP_SERIAL_INTERFACE_OPTIONS 0x433
#define DC_DISP_LCD_SPI_OPTIONS 0x434
@@ -479,20 +617,34 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_DISP_CURSOR_BACKGROUND 0x43d
#define DC_DISP_CURSOR_START_ADDR 0x43e
-#define CURSOR_CLIP_DISPLAY (0 << 28)
-#define CURSOR_CLIP_WIN_A (1 << 28)
-#define CURSOR_CLIP_WIN_B (2 << 28)
-#define CURSOR_CLIP_WIN_C (3 << 28)
-#define CURSOR_SIZE_32x32 (0 << 24)
-#define CURSOR_SIZE_64x64 (1 << 24)
-#define CURSOR_SIZE_128x128 (2 << 24)
-#define CURSOR_SIZE_256x256 (3 << 24)
+#define CURSOR_CLIP_DISPLAY (0 << 28)
+#define CURSOR_CLIP_WIN_A (1 << 28)
+#define CURSOR_CLIP_WIN_B (2 << 28)
+#define CURSOR_CLIP_WIN_C (3 << 28)
+#define CURSOR_SIZE_32x32 (0 << 24)
+#define CURSOR_SIZE_64x64 (1 << 24)
+#define CURSOR_SIZE_128x128 (2 << 24)
+#define CURSOR_SIZE_256x256 (3 << 24)
#define DC_DISP_CURSOR_START_ADDR_NS 0x43f
#define DC_DISP_CURSOR_POSITION 0x440
#define DC_DISP_CURSOR_POSITION_NS 0x441
#define DC_DISP_INIT_SEQ_CONTROL 0x442
+#define SEND_INIT_SEQUENCE BIT(0)
+#define INIT_SEQUENCE_MODE_SPI BIT(1)
+#define INIT_SEQUENCE_MODE_PLCD 0
+#define INIT_SEQ_DC_SIGNAL_SHIFT 4
+#define INIT_SEQ_DC_SIGNAL_MASK (0x7 << INIT_SEQ_DC_SIGNAL_SHIFT)
+#define NO_DC_SIGNAL 0
+#define DC_SIGNAL_VSYNC 1
+#define DC_SIGNAL_VPULSE0 2
+#define DC_SIGNAL_VPULSE1 3
+#define DC_SIGNAL_VPULSE2 4
+#define DC_SIGNAL_VPULSE3 5
+#define INIT_SEQ_DC_CONTROL_SHIFT 7
+#define FRAME_INIT_SEQ_CYCLES_SHIFT 8
+
#define DC_DISP_SPI_INIT_SEQ_DATA_A 0x443
#define DC_DISP_SPI_INIT_SEQ_DATA_B 0x444
#define DC_DISP_SPI_INIT_SEQ_DATA_C 0x445
@@ -519,22 +671,22 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_DISP_SD_MAN_K_VALUES 0x4de
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4e4
-#define BACKGROUND_COLOR_ALPHA(x) (((x) & 0xff) << 24)
-#define BACKGROUND_COLOR_BLUE(x) (((x) & 0xff) << 16)
-#define BACKGROUND_COLOR_GREEN(x) (((x) & 0xff) << 8)
-#define BACKGROUND_COLOR_RED(x) (((x) & 0xff) << 0)
+#define BACKGROUND_COLOR_ALPHA(x) (((x) & 0xff) << 24)
+#define BACKGROUND_COLOR_BLUE(x) (((x) & 0xff) << 16)
+#define BACKGROUND_COLOR_GREEN(x) (((x) & 0xff) << 8)
+#define BACKGROUND_COLOR_RED(x) ((x) & 0xff)
#define DC_DISP_INTERLACE_CONTROL 0x4e5
-#define INTERLACE_STATUS (1 << 2)
-#define INTERLACE_START (1 << 1)
-#define INTERLACE_ENABLE (1 << 0)
+#define INTERLACE_STATUS BIT(2)
+#define INTERLACE_START BIT(1)
+#define INTERLACE_ENABLE BIT(0)
#define DC_DISP_CURSOR_START_ADDR_HI 0x4ec
#define DC_DISP_BLEND_CURSOR_CONTROL 0x4f1
#define CURSOR_COMPOSITION_MODE_BLEND (0 << 25)
-#define CURSOR_COMPOSITION_MODE_XOR (1 << 25)
+#define CURSOR_COMPOSITION_MODE_XOR BIT(25)
#define CURSOR_MODE_LEGACY (0 << 24)
-#define CURSOR_MODE_NORMAL (1 << 24)
+#define CURSOR_MODE_NORMAL BIT(24)
#define CURSOR_DST_BLEND_ZERO (0 << 16)
#define CURSOR_DST_BLEND_K1 (1 << 16)
#define CURSOR_DST_BLEND_NEG_K1_TIMES_SRC (2 << 16)
@@ -544,34 +696,34 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define CURSOR_SRC_BLEND_MASK (3 << 8)
#define CURSOR_ALPHA 0xff
-#define DC_WIN_CORE_ACT_CONTROL 0x50e
-#define VCOUNTER (0 << 0)
-#define HCOUNTER (1 << 0)
+#define DC_WIN_CORE_ACT_CONTROL 0x50e
+#define VCOUNTER 0
+#define HCOUNTER BIT(0)
-#define DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA 0x543
-#define LATENCY_CTL_MODE_ENABLE (1 << 2)
+#define DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA 0x543
+#define LATENCY_CTL_MODE_ENABLE BIT(2)
-#define DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB 0x544
-#define WATERMARK_MASK 0x1fffffff
+#define DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB 0x544
+#define WATERMARK_MASK 0x1fffffff
-#define DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER 0x560
-#define PIPE_METER_INT(x) (((x) & 0xff) << 8)
-#define PIPE_METER_FRAC(x) (((x) & 0xff) << 0)
+#define DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER 0x560
+#define PIPE_METER_INT(x) (((x) & 0xff) << 8)
+#define PIPE_METER_FRAC(x) ((x) & 0xff)
-#define DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG 0x561
-#define MEMPOOL_ENTRIES(x) (((x) & 0xffff) << 0)
+#define DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG 0x561
+#define MEMPOOL_ENTRIES(x) ((x) & 0xffff)
-#define DC_WIN_CORE_IHUB_WGRP_FETCH_METER 0x562
-#define SLOTS(x) (((x) & 0xff) << 0)
+#define DC_WIN_CORE_IHUB_WGRP_FETCH_METER 0x562
+#define SLOTS(x) ((x) & 0xff)
-#define DC_WIN_CORE_IHUB_LINEBUF_CONFIG 0x563
-#define MODE_TWO_LINES (0 << 14)
-#define MODE_FOUR_LINES (1 << 14)
+#define DC_WIN_CORE_IHUB_LINEBUF_CONFIG 0x563
+#define MODE_TWO_LINES (0 << 14)
+#define MODE_FOUR_LINES BIT(14)
-#define DC_WIN_CORE_IHUB_THREAD_GROUP 0x568
-#define THREAD_NUM_MASK (0x1f << 1)
-#define THREAD_NUM(x) (((x) & 0x1f) << 1)
-#define THREAD_GROUP_ENABLE (1 << 0)
+#define DC_WIN_CORE_IHUB_THREAD_GROUP 0x568
+#define THREAD_NUM_MASK (0x1f << 1)
+#define THREAD_NUM(x) (((x) & 0x1f) << 1)
+#define THREAD_GROUP_ENABLE BIT(0)
#define DC_WIN_H_FILTER_P(p) (0x601 + (p))
#define DC_WIN_V_FILTER_P(p) (0x619 + (p))
@@ -586,115 +738,115 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_WIN_CSC_KVB 0x618
#define DC_WIN_WIN_OPTIONS 0x700
-#define H_DIRECTION (1 << 0)
-#define V_DIRECTION (1 << 2)
-#define COLOR_EXPAND (1 << 6)
-#define H_FILTER (1 << 8)
-#define V_FILTER (1 << 10)
-#define CSC_ENABLE (1 << 18)
-#define WIN_ENABLE (1 << 30)
+#define H_DIRECTION BIT(0)
+#define V_DIRECTION BIT(2)
+#define COLOR_EXPAND BIT(6)
+#define H_FILTER BIT(8)
+#define V_FILTER BIT(10)
+#define CSC_ENABLE BIT(18)
+#define WIN_ENABLE BIT(30)
#define DC_WIN_BYTE_SWAP 0x701
-#define BYTE_SWAP_NOSWAP (0 << 0)
-#define BYTE_SWAP_SWAP2 (1 << 0)
-#define BYTE_SWAP_SWAP4 (2 << 0)
-#define BYTE_SWAP_SWAP4HW (3 << 0)
+#define BYTE_SWAP_NOSWAP 0
+#define BYTE_SWAP_SWAP2 1
+#define BYTE_SWAP_SWAP4 2
+#define BYTE_SWAP_SWAP4HW 3
#define DC_WIN_BUFFER_CONTROL 0x702
-#define BUFFER_CONTROL_HOST (0 << 0)
-#define BUFFER_CONTROL_VI (1 << 0)
-#define BUFFER_CONTROL_EPP (2 << 0)
-#define BUFFER_CONTROL_MPEGE (3 << 0)
-#define BUFFER_CONTROL_SB2D (4 << 0)
+#define BUFFER_CONTROL_HOST 0
+#define BUFFER_CONTROL_VI 1
+#define BUFFER_CONTROL_EPP 2
+#define BUFFER_CONTROL_MPEGE 3
+#define BUFFER_CONTROL_SB2D 4
#define DC_WIN_COLOR_DEPTH 0x703
-#define WIN_COLOR_DEPTH_P1 0
-#define WIN_COLOR_DEPTH_P2 1
-#define WIN_COLOR_DEPTH_P4 2
-#define WIN_COLOR_DEPTH_P8 3
-#define WIN_COLOR_DEPTH_B4G4R4A4 4
-#define WIN_COLOR_DEPTH_B5G5R5A1 5
-#define WIN_COLOR_DEPTH_B5G6R5 6
-#define WIN_COLOR_DEPTH_A1B5G5R5 7
-#define WIN_COLOR_DEPTH_B8G8R8A8 12
-#define WIN_COLOR_DEPTH_R8G8B8A8 13
-#define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 14
-#define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 15
-#define WIN_COLOR_DEPTH_YCbCr422 16
-#define WIN_COLOR_DEPTH_YUV422 17
-#define WIN_COLOR_DEPTH_YCbCr420P 18
-#define WIN_COLOR_DEPTH_YUV420P 19
-#define WIN_COLOR_DEPTH_YCbCr422P 20
-#define WIN_COLOR_DEPTH_YUV422P 21
-#define WIN_COLOR_DEPTH_YCbCr422R 22
-#define WIN_COLOR_DEPTH_YUV422R 23
-#define WIN_COLOR_DEPTH_YCbCr422RA 24
-#define WIN_COLOR_DEPTH_YUV422RA 25
-#define WIN_COLOR_DEPTH_R4G4B4A4 27
-#define WIN_COLOR_DEPTH_R5G5B5A 28
-#define WIN_COLOR_DEPTH_AR5G5B5 29
-#define WIN_COLOR_DEPTH_B5G5R5X1 30
-#define WIN_COLOR_DEPTH_X1B5G5R5 31
-#define WIN_COLOR_DEPTH_R5G5B5X1 32
-#define WIN_COLOR_DEPTH_X1R5G5B5 33
-#define WIN_COLOR_DEPTH_R5G6B5 34
-#define WIN_COLOR_DEPTH_A8R8G8B8 35
-#define WIN_COLOR_DEPTH_A8B8G8R8 36
-#define WIN_COLOR_DEPTH_B8G8R8X8 37
-#define WIN_COLOR_DEPTH_R8G8B8X8 38
-#define WIN_COLOR_DEPTH_YCbCr444P 41
-#define WIN_COLOR_DEPTH_YCrCb420SP 42
-#define WIN_COLOR_DEPTH_YCbCr420SP 43
-#define WIN_COLOR_DEPTH_YCrCb422SP 44
-#define WIN_COLOR_DEPTH_YCbCr422SP 45
-#define WIN_COLOR_DEPTH_YCrCb444SP 48
-#define WIN_COLOR_DEPTH_YCbCr444SP 49
-#define WIN_COLOR_DEPTH_X8B8G8R8 65
-#define WIN_COLOR_DEPTH_X8R8G8B8 66
+#define WIN_COLOR_DEPTH_P1 0
+#define WIN_COLOR_DEPTH_P2 1
+#define WIN_COLOR_DEPTH_P4 2
+#define WIN_COLOR_DEPTH_P8 3
+#define WIN_COLOR_DEPTH_B4G4R4A4 4
+#define WIN_COLOR_DEPTH_B5G5R5A1 5
+#define WIN_COLOR_DEPTH_B5G6R5 6
+#define WIN_COLOR_DEPTH_A1B5G5R5 7
+#define WIN_COLOR_DEPTH_B8G8R8A8 12
+#define WIN_COLOR_DEPTH_R8G8B8A8 13
+#define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 14
+#define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 15
+#define WIN_COLOR_DEPTH_YCbCr422 16
+#define WIN_COLOR_DEPTH_YUV422 17
+#define WIN_COLOR_DEPTH_YCbCr420P 18
+#define WIN_COLOR_DEPTH_YUV420P 19
+#define WIN_COLOR_DEPTH_YCbCr422P 20
+#define WIN_COLOR_DEPTH_YUV422P 21
+#define WIN_COLOR_DEPTH_YCbCr422R 22
+#define WIN_COLOR_DEPTH_YUV422R 23
+#define WIN_COLOR_DEPTH_YCbCr422RA 24
+#define WIN_COLOR_DEPTH_YUV422RA 25
+#define WIN_COLOR_DEPTH_R4G4B4A4 27
+#define WIN_COLOR_DEPTH_R5G5B5A 28
+#define WIN_COLOR_DEPTH_AR5G5B5 29
+#define WIN_COLOR_DEPTH_B5G5R5X1 30
+#define WIN_COLOR_DEPTH_X1B5G5R5 31
+#define WIN_COLOR_DEPTH_R5G5B5X1 32
+#define WIN_COLOR_DEPTH_X1R5G5B5 33
+#define WIN_COLOR_DEPTH_R5G6B5 34
+#define WIN_COLOR_DEPTH_A8R8G8B8 35
+#define WIN_COLOR_DEPTH_A8B8G8R8 36
+#define WIN_COLOR_DEPTH_B8G8R8X8 37
+#define WIN_COLOR_DEPTH_R8G8B8X8 38
+#define WIN_COLOR_DEPTH_YCbCr444P 41
+#define WIN_COLOR_DEPTH_YCrCb420SP 42
+#define WIN_COLOR_DEPTH_YCbCr420SP 43
+#define WIN_COLOR_DEPTH_YCrCb422SP 44
+#define WIN_COLOR_DEPTH_YCbCr422SP 45
+#define WIN_COLOR_DEPTH_YCrCb444SP 48
+#define WIN_COLOR_DEPTH_YCbCr444SP 49
+#define WIN_COLOR_DEPTH_X8B8G8R8 65
+#define WIN_COLOR_DEPTH_X8R8G8B8 66
#define DC_WIN_POSITION 0x704
-#define H_POSITION(x) (((x) & 0x1fff) << 0) /* XXX 0x7fff on Tegra186 */
-#define V_POSITION(x) (((x) & 0x1fff) << 16) /* XXX 0x7fff on Tegra186 */
+#define H_POSITION(x) (((x) & 0x1fff) << 0) /* XXX 0x7fff on Tegra186 */
+#define V_POSITION(x) (((x) & 0x1fff) << 16) /* XXX 0x7fff on Tegra186 */
#define DC_WIN_SIZE 0x705
-#define H_SIZE(x) (((x) & 0x1fff) << 0) /* XXX 0x7fff on Tegra186 */
-#define V_SIZE(x) (((x) & 0x1fff) << 16) /* XXX 0x7fff on Tegra186 */
+#define H_SIZE(x) (((x) & 0x1fff) << 0) /* XXX 0x7fff on Tegra186 */
+#define V_SIZE(x) (((x) & 0x1fff) << 16) /* XXX 0x7fff on Tegra186 */
#define DC_WIN_PRESCALED_SIZE 0x706
-#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0)
-#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) /* XXX 0x7fff on Tegra186 */
+#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0)
+#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) /* XXX 0x7fff on Tegra186 */
#define DC_WIN_H_INITIAL_DDA 0x707
#define DC_WIN_V_INITIAL_DDA 0x708
#define DC_WIN_DDA_INC 0x709
-#define H_DDA_INC(x) (((x) & 0xffff) << 0)
-#define V_DDA_INC(x) (((x) & 0xffff) << 16)
+#define H_DDA_INC(x) (((x) & 0xffff) << 0)
+#define V_DDA_INC(x) (((x) & 0xffff) << 16)
#define DC_WIN_LINE_STRIDE 0x70a
#define DC_WIN_BUF_STRIDE 0x70b
#define DC_WIN_UV_BUF_STRIDE 0x70c
#define DC_WIN_BUFFER_ADDR_MODE 0x70d
-#define DC_WIN_BUFFER_ADDR_MODE_LINEAR (0 << 0)
-#define DC_WIN_BUFFER_ADDR_MODE_TILE (1 << 0)
-#define DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV (0 << 16)
-#define DC_WIN_BUFFER_ADDR_MODE_TILE_UV (1 << 16)
+#define DC_WIN_BUFFER_ADDR_MODE_LINEAR (0 << 0)
+#define DC_WIN_BUFFER_ADDR_MODE_TILE BIT(0)
+#define DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV (0 << 16)
+#define DC_WIN_BUFFER_ADDR_MODE_TILE_UV BIT(16)
#define DC_WIN_DV_CONTROL 0x70e
#define DC_WIN_BLEND_NOKEY 0x70f
-#define BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
-#define BLEND_WEIGHT0(x) (((x) & 0xff) << 8)
+#define BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
+#define BLEND_WEIGHT0(x) (((x) & 0xff) << 8)
#define DC_WIN_BLEND_1WIN 0x710
-#define BLEND_CONTROL_FIX (0 << 2)
-#define BLEND_CONTROL_ALPHA (1 << 2)
-#define BLEND_COLOR_KEY_NONE (0 << 0)
-#define BLEND_COLOR_KEY_0 (1 << 0)
-#define BLEND_COLOR_KEY_1 (2 << 0)
-#define BLEND_COLOR_KEY_BOTH (3 << 0)
+#define BLEND_CONTROL_FIX (0 << 2)
+#define BLEND_CONTROL_ALPHA BIT(2)
+#define BLEND_COLOR_KEY_NONE 0
+#define BLEND_COLOR_KEY_0 1
+#define BLEND_COLOR_KEY_1 2
+#define BLEND_COLOR_KEY_BOTH 3
#define DC_WIN_BLEND_2WIN_X 0x711
-#define BLEND_CONTROL_DEPENDENT (2 << 2)
+#define BLEND_CONTROL_DEPENDENT (2 << 2)
#define DC_WIN_BLEND_2WIN_Y 0x712
#define DC_WIN_BLEND_3WIN_XY 0x713
@@ -715,10 +867,10 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_WINBUF_UFLOW_STATUS 0x80a
#define DC_WINBUF_SURFACE_KIND 0x80b
-#define DC_WINBUF_SURFACE_KIND_PITCH (0 << 0)
-#define DC_WINBUF_SURFACE_KIND_TILED (1 << 0)
-#define DC_WINBUF_SURFACE_KIND_BLOCK (2 << 0)
-#define DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
+#define DC_WINBUF_SURFACE_KIND_PITCH 0
+#define DC_WINBUF_SURFACE_KIND_TILED 1
+#define DC_WINBUF_SURFACE_KIND_BLOCK 2
+#define DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
#define DC_WINBUF_START_ADDR_HI 0x80d
@@ -726,7 +878,7 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_WINBUF_START_ADDR_HI_V 0x811
#define DC_WINBUF_CDE_CONTROL 0x82f
-#define ENABLE_SURFACE (1 << 0)
+#define ENABLE_SURFACE BIT(0)
#define DC_WINBUF_AD_UFLOW_STATUS 0xbca
#define DC_WINBUF_BD_UFLOW_STATUS 0xdca
@@ -734,14 +886,14 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
/* Tegra186 and later */
#define DC_DISP_CORE_SOR_SET_CONTROL(x) (0x403 + (x))
-#define PROTOCOL_MASK (0xf << 8)
-#define PROTOCOL_SINGLE_TMDS_A (0x1 << 8)
+#define PROTOCOL_MASK (0xf << 8)
+#define PROTOCOL_SINGLE_TMDS_A (0x1 << 8)
#define DC_DISP_CORE_HEAD_SET_CONTROL_OUTPUT_LUT 0x431
-#define OUTPUT_LUT_MODE_MASK (3 << 5)
-#define OUTPUT_LUT_MODE_INTERPOLATE (1 << 5)
-#define OUTPUT_LUT_SIZE_MASK (3 << 1)
-#define OUTPUT_LUT_SIZE_SIZE_1025 (2 << 1)
+#define OUTPUT_LUT_MODE_MASK (3 << 5)
+#define OUTPUT_LUT_MODE_INTERPOLATE (1 << 5)
+#define OUTPUT_LUT_SIZE_MASK (3 << 1)
+#define OUTPUT_LUT_SIZE_SIZE_1025 (2 << 1)
#define DC_DISP_COREPVT_HEAD_SET_OUTPUT_LUT_BASE 0x432
#define DC_DISP_COREPVT_HEAD_SET_OUTPUT_LUT_BASE_HI 0x433
@@ -749,18 +901,18 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR 0x442
#define DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR 0x446
-#define DC_WINC_PRECOMP_WGRP_PIPE_CAPA 0x500
-#define DC_WINC_PRECOMP_WGRP_PIPE_CAPB 0x501
-#define DC_WINC_PRECOMP_WGRP_PIPE_CAPC 0x502
-#define MAX_PIXELS_5TAP444(x) ((x) & 0xffff)
-#define DC_WINC_PRECOMP_WGRP_PIPE_CAPD 0x503
-#define DC_WINC_PRECOMP_WGRP_PIPE_CAPE 0x504
-#define MAX_PIXELS_2TAP444(x) ((x) & 0xffff)
-#define DC_WINC_PRECOMP_WGRP_PIPE_CAPF 0x505
+#define DC_WINC_PRECOMP_WGRP_PIPE_CAPA 0x500
+#define DC_WINC_PRECOMP_WGRP_PIPE_CAPB 0x501
+#define DC_WINC_PRECOMP_WGRP_PIPE_CAPC 0x502
+#define MAX_PIXELS_5TAP444(x) ((x) & 0xffff)
+#define DC_WINC_PRECOMP_WGRP_PIPE_CAPD 0x503
+#define DC_WINC_PRECOMP_WGRP_PIPE_CAPE 0x504
+#define MAX_PIXELS_2TAP444(x) ((x) & 0xffff)
+#define DC_WINC_PRECOMP_WGRP_PIPE_CAPF 0x505
#define DC_WIN_CORE_WINDOWGROUP_SET_CONTROL 0x702
-#define OWNER_MASK (0xf << 0)
-#define OWNER(x) (((x) & 0xf) << 0)
+#define OWNER_MASK 0xf
+#define OWNER(x) ((x) & 0xf)
#define DC_WIN_CROPPED_SIZE 0x706
@@ -768,52 +920,52 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_WIN_SET_INPUT_SCALER_V_START_PHASE 0x708
#define DC_WIN_PLANAR_STORAGE 0x709
-#define PITCH(x) (((x) >> 6) & 0x1fff)
+#define PITCH(x) (((x) >> 6) & 0x1fff)
#define DC_WIN_PLANAR_STORAGE_UV 0x70a
-#define PITCH_U(x) ((((x) >> 6) & 0x1fff) << 0)
-#define PITCH_V(x) ((((x) >> 6) & 0x1fff) << 16)
+#define PITCH_U(x) ((((x) >> 6) & 0x1fff) << 0)
+#define PITCH_V(x) ((((x) >> 6) & 0x1fff) << 16)
#define DC_WIN_SET_INPUT_SCALER_HPHASE_INCR 0x70b
#define DC_WIN_SET_INPUT_SCALER_VPHASE_INCR 0x70c
#define DC_WIN_SET_PARAMS 0x70d
-#define CLAMP_BEFORE_BLEND (1 << 15)
-#define DEGAMMA_NONE (0 << 13)
-#define DEGAMMA_SRGB (1 << 13)
-#define DEGAMMA_YUV8_10 (2 << 13)
-#define DEGAMMA_YUV12 (3 << 13)
-#define INPUT_RANGE_BYPASS (0 << 10)
-#define INPUT_RANGE_LIMITED (1 << 10)
-#define INPUT_RANGE_FULL (2 << 10)
-#define COLOR_SPACE_RGB (0 << 8)
-#define COLOR_SPACE_YUV_601 (1 << 8)
-#define COLOR_SPACE_YUV_709 (2 << 8)
-#define COLOR_SPACE_YUV_2020 (3 << 8)
+#define CLAMP_BEFORE_BLEND BIT(15)
+#define DEGAMMA_NONE (0 << 13)
+#define DEGAMMA_SRGB (1 << 13)
+#define DEGAMMA_YUV8_10 (2 << 13)
+#define DEGAMMA_YUV12 (3 << 13)
+#define INPUT_RANGE_BYPASS (0 << 10)
+#define INPUT_RANGE_LIMITED (1 << 10)
+#define INPUT_RANGE_FULL (2 << 10)
+#define COLOR_SPACE_RGB (0 << 8)
+#define COLOR_SPACE_YUV_601 (1 << 8)
+#define COLOR_SPACE_YUV_709 (2 << 8)
+#define COLOR_SPACE_YUV_2020 (3 << 8)
#define DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER 0x70e
-#define HORIZONTAL_TAPS_2 (1 << 3)
-#define HORIZONTAL_TAPS_5 (4 << 3)
-#define VERTICAL_TAPS_2 (1 << 0)
-#define VERTICAL_TAPS_5 (4 << 0)
+#define HORIZONTAL_TAPS_2 (1 << 3)
+#define HORIZONTAL_TAPS_5 (4 << 3)
+#define VERTICAL_TAPS_2 1
+#define VERTICAL_TAPS_5 4
#define DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF 0x70f
-#define COEFF_INDEX(x) (((x) & 0xff) << 15)
-#define COEFF_DATA(x) (((x) & 0x3ff) << 0)
+#define COEFF_INDEX(x) (((x) & 0xff) << 15)
+#define COEFF_DATA(x) ((x) & 0x3ff)
#define DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE 0x711
-#define INPUT_SCALER_USE422 (1 << 2)
-#define INPUT_SCALER_VBYPASS (1 << 1)
-#define INPUT_SCALER_HBYPASS (1 << 0)
+#define INPUT_SCALER_USE422 BIT(2)
+#define INPUT_SCALER_VBYPASS BIT(1)
+#define INPUT_SCALER_HBYPASS BIT(0)
#define DC_WIN_BLEND_LAYER_CONTROL 0x716
-#define COLOR_KEY_NONE (0 << 25)
-#define COLOR_KEY_SRC (1 << 25)
-#define COLOR_KEY_DST (2 << 25)
-#define BLEND_BYPASS (1 << 24)
-#define K2(x) (((x) & 0xff) << 16)
-#define K1(x) (((x) & 0xff) << 8)
-#define WINDOW_LAYER_DEPTH(x) (((x) & 0xff) << 0)
+#define COLOR_KEY_NONE (0 << 25)
+#define COLOR_KEY_SRC (1 << 25)
+#define COLOR_KEY_DST (2 << 25)
+#define BLEND_BYPASS BIT(24)
+#define K2(x) (((x) & 0xff) << 16)
+#define K1(x) (((x) & 0xff) << 8)
+#define WINDOW_LAYER_DEPTH(x) ((x) & 0xff)
#define DC_WIN_BLEND_MATCH_SELECT 0x717
#define BLEND_FACTOR_DST_ALPHA_ZERO (0 << 12)
@@ -832,23 +984,23 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_DST (5 << 4)
#define BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC (6 << 4)
#define BLEND_FACTOR_DST_COLOR_NEG_K1 (7 << 4)
-#define BLEND_FACTOR_SRC_COLOR_ZERO (0 << 0)
-#define BLEND_FACTOR_SRC_COLOR_ONE (1 << 0)
-#define BLEND_FACTOR_SRC_COLOR_K1 (2 << 0)
-#define BLEND_FACTOR_SRC_COLOR_K1_TIMES_DST (3 << 0)
-#define BLEND_FACTOR_SRC_COLOR_NEG_K1_TIMES_DST (4 << 0)
-#define BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC (5 << 0)
+#define BLEND_FACTOR_SRC_COLOR_ZERO 0
+#define BLEND_FACTOR_SRC_COLOR_ONE 1
+#define BLEND_FACTOR_SRC_COLOR_K1 2
+#define BLEND_FACTOR_SRC_COLOR_K1_TIMES_DST 3
+#define BLEND_FACTOR_SRC_COLOR_NEG_K1_TIMES_DST 4
+#define BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC 5
#define DC_WIN_BLEND_NOMATCH_SELECT 0x718
#define DC_WIN_PRECOMP_WGRP_PARAMS 0x724
-#define SWAP_UV (1 << 0)
+#define SWAP_UV BIT(0)
#define DC_WIN_WINDOW_SET_CONTROL 0x730
-#define CONTROL_CSC_ENABLE (1 << 5)
+#define CONTROL_CSC_ENABLE BIT(5)
#define DC_WINBUF_CROPPED_POINT 0x806
-#define OFFSET_Y(x) (((x) & 0xffff) << 16)
-#define OFFSET_X(x) (((x) & 0xffff) << 0)
+#define OFFSET_Y(x) (((x) & 0xffff) << 16)
+#define OFFSET_X(x) ((x) & 0xffff)
#endif /* TEGRA_DC_H */
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index b6d09a8d8e5ea..addcecf8592b1 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -115,14 +115,14 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(1));
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- value |= LHS_OUTPUT_POLARITY_LOW;
+ value |= BIT(PIN_LHS);
else
- value &= ~LHS_OUTPUT_POLARITY_LOW;
+ value &= ~BIT(PIN_LHS);
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- value |= LVS_OUTPUT_POLARITY_LOW;
+ value |= BIT(PIN_LVS);
else
- value &= ~LVS_OUTPUT_POLARITY_LOW;
+ value &= ~BIT(PIN_LVS);
tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(1));
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 06/11] dt-bindings: display: tegra: Document Tegra20 DSI port
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (4 preceding siblings ...)
2026-10-29 15:29 ` [PATCH v5 05/11] drm/tegra: dc: Refactor and expand header Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 07/11] drm/tegra: Make panel parsing by tegra_output_probe() optional Svyatoslav Ryhel
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Document the optional port node, which is required for correctly modeling
a dual-mode panel.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
.../bindings/display/tegra/nvidia,tegra20-dsi.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dsi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dsi.yaml
index 59e1dc0813e73..0f4837648d179 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dsi.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dsi.yaml
@@ -83,6 +83,12 @@ properties:
gang up with in order to support up to 8 data lanes
$ref: /schemas/types.yaml#/definitions/phandle
+ port:
+ description: specifies the connection port for the dual-mode panel
+ and is required only when the panel is operating in dual-mode
+ configuration.
+ $ref: /schemas/graph.yaml#/properties/port
+
allOf:
- $ref: ../dsi-controller.yaml#
- if:
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 07/11] drm/tegra: Make panel parsing by tegra_output_probe() optional
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (5 preceding siblings ...)
2026-10-29 15:29 ` [PATCH v5 06/11] dt-bindings: display: tegra: Document Tegra20 DSI port Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 08/11] drm/tegra: Convert to use atomic versions of drm_encoder_helper_funcs Svyatoslav Ryhel
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
The tegra_output_probe() performs panel parsing unconditionally, even for
devices that do not require it (such as HDMI) or that handle panel parsing
on their own (like DSI). Make panel parsing configurable.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/tegra/drm.h | 2 +-
drivers/gpu/drm/tegra/dsi.c | 2 +-
drivers/gpu/drm/tegra/hdmi.c | 2 +-
drivers/gpu/drm/tegra/output.c | 52 ++++++++++++++++++----------------
drivers/gpu/drm/tegra/rgb.c | 2 +-
drivers/gpu/drm/tegra/sor.c | 2 +-
6 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index bc720ae8d95e1..e53fe68161cb8 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -156,7 +156,7 @@ static inline struct tegra_output *connector_to_output(struct drm_connector *c)
}
/* from output.c */
-int tegra_output_probe(struct tegra_output *output);
+int tegra_output_probe(struct tegra_output *output, bool get_panel);
void tegra_output_remove(struct tegra_output *output);
int tegra_output_init(struct drm_device *drm, struct tegra_output *output);
void tegra_output_exit(struct tegra_output *output);
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 7b595310e7379..a4c0c63bbe567 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -1618,7 +1618,7 @@ static int tegra_dsi_probe(struct platform_device *pdev)
if (err < 0)
return err;
- err = tegra_output_probe(&dsi->output);
+ err = tegra_output_probe(&dsi->output, false);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index 0d2c0ab0a63e9..c0845bb45bb15 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -1855,7 +1855,7 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
hdmi->output.dev = &pdev->dev;
- err = tegra_output_probe(&hdmi->output);
+ err = tegra_output_probe(&hdmi->output, false);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index d0ba3bd0aab8f..ff2e28a1e00b7 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -94,7 +94,7 @@ static irqreturn_t hpd_irq(int irq, void *data)
return IRQ_HANDLED;
}
-int tegra_output_probe(struct tegra_output *output)
+int tegra_output_probe(struct tegra_output *output, bool get_panel)
{
struct device_node *ddc, *panel;
const void *edid;
@@ -104,31 +104,33 @@ int tegra_output_probe(struct tegra_output *output)
if (!output->of_node)
output->of_node = output->dev->of_node;
- err = drm_of_find_panel_or_bridge(output->of_node, -1, -1,
- &output->panel, &output->bridge);
- if (err && err != -ENODEV)
- return err;
-
- panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
- if (panel) {
- /*
- * Don't mix nvidia,panel phandle with the graph in a
- * device-tree.
- */
- WARN_ON(output->panel || output->bridge);
-
- if (output->panel) {
- drm_panel_put(output->panel);
- output->panel = NULL;
- }
-
- output->panel = of_drm_find_panel(panel);
- of_node_put(panel);
-
- if (IS_ERR(output->panel)) {
- err = PTR_ERR(output->panel);
- output->panel = NULL;
+ if (get_panel) {
+ err = drm_of_find_panel_or_bridge(output->of_node, -1, -1,
+ &output->panel, &output->bridge);
+ if (err && err != -ENODEV)
return err;
+
+ panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
+ if (panel) {
+ /*
+ * Don't mix nvidia,panel phandle with the graph in a
+ * device-tree.
+ */
+ WARN_ON(output->panel || output->bridge);
+
+ if (output->panel) {
+ drm_panel_put(output->panel);
+ output->panel = NULL;
+ }
+
+ output->panel = of_drm_find_panel(panel);
+ of_node_put(panel);
+
+ if (IS_ERR(output->panel)) {
+ err = PTR_ERR(output->panel);
+ output->panel = NULL;
+ return err;
+ }
}
}
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index addcecf8592b1..01475995d9cc8 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -236,7 +236,7 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc)
rgb->output.of_node = np;
rgb->dc = dc;
- err = tegra_output_probe(&rgb->output);
+ err = tegra_output_probe(&rgb->output, true);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index e384cbd0cbf72..ab81e412e05f1 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -3806,7 +3806,7 @@ static int tegra_sor_probe(struct platform_device *pdev)
if (err < 0)
goto put_aux;
- err = tegra_output_probe(&sor->output);
+ err = tegra_output_probe(&sor->output, true);
if (err < 0) {
dev_err_probe(&pdev->dev, err, "failed to probe output\n");
goto put_aux;
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 08/11] drm/tegra: Convert to use atomic versions of drm_encoder_helper_funcs
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (6 preceding siblings ...)
2026-10-29 15:29 ` [PATCH v5 07/11] drm/tegra: Make panel parsing by tegra_output_probe() optional Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 09/11] drm/tegra: rgb: Parameterize configuration based on bus flags Svyatoslav Ryhel
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Switch to using the atomic versions of the enable() and disable()
operations.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/tegra/dsi.c | 20 +++++++++++++++-----
drivers/gpu/drm/tegra/hdmi.c | 20 +++++++++++++++-----
drivers/gpu/drm/tegra/rgb.c | 23 +++++++++++++++++------
drivers/gpu/drm/tegra/sor.c | 18 +++++++++++++-----
4 files changed, 60 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index a4c0c63bbe567..202aed6a6fc12 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -856,7 +856,8 @@ static void tegra_dsi_unprepare(struct tegra_dsi *dsi)
dev_err(dsi->dev, "failed to suspend: %d\n", err);
}
-static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
+static void tegra_dsi_encoder_disable(struct drm_encoder *encoder,
+ struct drm_atomic_commit *comm_state)
{
struct tegra_output *output = encoder_to_output(encoder);
struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
@@ -920,16 +921,25 @@ static int tegra_dsi_prepare(struct tegra_dsi *dsi)
return 0;
}
-static void tegra_dsi_encoder_enable(struct drm_encoder *encoder)
+static void tegra_dsi_encoder_enable(struct drm_encoder *encoder,
+ struct drm_atomic_commit *comm_state)
{
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct tegra_output *output = encoder_to_output(encoder);
struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+ struct drm_connector_state *conn_state;
struct tegra_dsi *dsi = to_dsi(output);
+ struct drm_crtc_state *crtc_state;
+ struct drm_connector *connector;
struct tegra_dsi_state *state;
+ struct drm_display_mode *mode;
u32 value;
int err;
+ connector = drm_atomic_get_new_connector_for_encoder(comm_state, encoder);
+ conn_state = drm_atomic_get_new_connector_state(comm_state, connector);
+ crtc_state = drm_atomic_get_new_crtc_state(comm_state, conn_state->crtc);
+ mode = &crtc_state->adjusted_mode;
+
err = tegra_dsi_prepare(dsi);
if (err < 0) {
dev_err(dsi->dev, "failed to prepare: %d\n", err);
@@ -1060,8 +1070,8 @@ static const struct drm_encoder_funcs tegra_dsi_encoder_funcs = {
};
static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
- .disable = tegra_dsi_encoder_disable,
- .enable = tegra_dsi_encoder_enable,
+ .atomic_disable = tegra_dsi_encoder_disable,
+ .atomic_enable = tegra_dsi_encoder_enable,
.atomic_check = tegra_dsi_encoder_atomic_check,
};
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index c0845bb45bb15..0a2420095d061 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -1166,7 +1166,8 @@ tegra_hdmi_connector_helper_funcs = {
.mode_valid = tegra_hdmi_connector_mode_valid,
};
-static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder)
+static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder,
+ struct drm_atomic_commit *comm_state)
{
struct tegra_output *output = encoder_to_output(encoder);
struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
@@ -1209,18 +1210,27 @@ static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder)
dev_err(hdmi->dev, "failed to suspend: %d\n", err);
}
-static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder)
+static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder,
+ struct drm_atomic_commit *comm_state)
{
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
unsigned int h_sync_width, h_front_porch, h_back_porch, i, rekey;
struct tegra_output *output = encoder_to_output(encoder);
struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
struct tegra_hdmi *hdmi = to_hdmi(output);
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
unsigned int pulse_start, div82;
+ struct drm_connector *connector;
+ struct drm_display_mode *mode;
int retries = 1000;
u32 value;
int err;
+ connector = drm_atomic_get_new_connector_for_encoder(comm_state, encoder);
+ conn_state = drm_atomic_get_new_connector_state(comm_state, connector);
+ crtc_state = drm_atomic_get_new_crtc_state(comm_state, conn_state->crtc);
+ mode = &crtc_state->adjusted_mode;
+
err = host1x_client_resume(&hdmi->client);
if (err < 0) {
dev_err(hdmi->dev, "failed to resume: %d\n", err);
@@ -1460,8 +1470,8 @@ tegra_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
}
static const struct drm_encoder_helper_funcs tegra_hdmi_encoder_helper_funcs = {
- .disable = tegra_hdmi_encoder_disable,
- .enable = tegra_hdmi_encoder_enable,
+ .atomic_disable = tegra_hdmi_encoder_disable,
+ .atomic_enable = tegra_hdmi_encoder_enable,
.atomic_check = tegra_hdmi_encoder_atomic_check,
};
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index 01475995d9cc8..7dea0cac61233 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -90,7 +90,8 @@ static void tegra_dc_write_regs(struct tegra_dc *dc,
tegra_dc_writel(dc, table[i].value, table[i].offset);
}
-static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
+static void tegra_rgb_encoder_disable(struct drm_encoder *encoder,
+ struct drm_atomic_commit *state)
{
struct tegra_output *output = encoder_to_output(encoder);
struct tegra_rgb *rgb = to_rgb(output);
@@ -99,12 +100,22 @@ static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
tegra_dc_commit(rgb->dc);
}
-static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
+static void tegra_rgb_encoder_enable(struct drm_encoder *encoder,
+ struct drm_atomic_commit *state)
{
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct tegra_output *output = encoder_to_output(encoder);
struct tegra_rgb *rgb = to_rgb(output);
- u32 value;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct drm_connector *connector;
+ struct drm_display_mode *mode;
+ u32 bus_flags, value;
+
+ /* Get mode flags */
+ connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+ mode = &crtc_state->adjusted_mode;
tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
@@ -201,8 +212,8 @@ static const struct drm_encoder_funcs tegra_rgb_encoder_funcs = {
};
static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = {
- .disable = tegra_rgb_encoder_disable,
- .enable = tegra_rgb_encoder_enable,
+ .atomic_disable = tegra_rgb_encoder_disable,
+ .atomic_enable = tegra_rgb_encoder_enable,
.atomic_check = tegra_rgb_encoder_atomic_check,
};
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index ab81e412e05f1..85cd5c8cbef4e 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -2206,7 +2206,8 @@ static void tegra_sor_hdmi_scdc_start(struct tegra_sor *sor)
}
}
-static void tegra_sor_hdmi_disable(struct drm_encoder *encoder)
+static void tegra_sor_hdmi_disable(struct drm_encoder *encoder,
+ struct drm_atomic_commit *comm_state)
{
struct tegra_output *output = encoder_to_output(encoder);
struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
@@ -2247,13 +2248,17 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder)
host1x_client_suspend(&sor->client);
}
-static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
+static void tegra_sor_hdmi_enable(struct drm_encoder *encoder,
+ struct drm_atomic_commit *comm_state)
{
struct tegra_output *output = encoder_to_output(encoder);
unsigned int h_ref_to_sync = 1, pulse_start, max_ac;
struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
struct tegra_sor_hdmi_settings *settings;
+ struct drm_connector_state *conn_state;
struct tegra_sor *sor = to_sor(output);
+ struct drm_crtc_state *crtc_state;
+ struct drm_connector *connector;
struct tegra_sor_state *state;
struct drm_display_mode *mode;
unsigned long rate, pclk;
@@ -2262,7 +2267,10 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
int err;
state = to_sor_state(output->connector.state);
- mode = &encoder->crtc->state->adjusted_mode;
+ connector = drm_atomic_get_new_connector_for_encoder(comm_state, encoder);
+ conn_state = drm_atomic_get_new_connector_state(comm_state, connector);
+ crtc_state = drm_atomic_get_new_crtc_state(comm_state, conn_state->crtc);
+ mode = &crtc_state->adjusted_mode;
pclk = mode->clock * 1000;
err = host1x_client_resume(&sor->client);
@@ -2660,8 +2668,8 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
}
static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = {
- .disable = tegra_sor_hdmi_disable,
- .enable = tegra_sor_hdmi_enable,
+ .atomic_disable = tegra_sor_hdmi_disable,
+ .atomic_enable = tegra_sor_hdmi_enable,
.atomic_check = tegra_sor_encoder_atomic_check,
};
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 09/11] drm/tegra: rgb: Parameterize configuration based on bus flags
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (7 preceding siblings ...)
2026-10-29 15:29 ` [PATCH v5 08/11] drm/tegra: Convert to use atomic versions of drm_encoder_helper_funcs Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 10/11] dt-bindings: display: tegra: Document 8-bit CPU parallel interface Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 11/11] drm/tegra: Add support for 8-bit CPU interface Svyatoslav Ryhel
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Parameterize configuration based on bus flags passed from the bridge or
panel. The list of supported flags includes now pixel clock polarity,
display enable (DE) polarity, and data alignment.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/tegra/rgb.c | 39 +++++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index 7dea0cac61233..d8f41d1ca350e 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -5,6 +5,7 @@
*/
#include <linux/clk.h>
+#include <linux/media-bus-format.h>
#include <linux/of.h>
#include <drm/drm_atomic_helper.h>
@@ -106,6 +107,7 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder,
struct tegra_output *output = encoder_to_output(encoder);
struct tegra_rgb *rgb = to_rgb(output);
struct drm_connector_state *conn_state;
+ struct drm_bridge_state *bridge_state;
struct drm_crtc_state *crtc_state;
struct drm_connector *connector;
struct drm_display_mode *mode;
@@ -117,12 +119,21 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder,
crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
mode = &crtc_state->adjusted_mode;
+ /* Get but flags from the bridge state. */
+ bridge_state = drm_atomic_get_new_bridge_state(state, output->bridge);
+ if (bridge_state)
+ bus_flags = bridge_state->input_bus_cfg.flags;
+ else
+ bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_DATA_MSB_TO_LSB;
+
tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
tegra_dc_writel(rgb->dc, value, DC_DISP_DATA_ENABLE_OPTIONS);
- /* configure H- and V-sync signal polarities */
+ /* configure H- and V-sync and pixel clock signal polarities */
value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(1));
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
@@ -135,11 +146,31 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder,
else
value &= ~BIT(PIN_LVS);
+ if (bus_flags & DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE)
+ value &= ~BIT(PIN_LSC0);
+ else
+ value |= BIT(PIN_LSC0);
+
tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(1));
- /* XXX: parameterize? */
- value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB |
- DISP_ORDER_RED_BLUE;
+ /* configure DE signal polarities */
+ value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(3));
+
+ if (bus_flags & DRM_BUS_FLAG_DE_LOW)
+ value |= BIT(PIN_LSPI);
+ else
+ value &= ~BIT(PIN_LSPI);
+
+ tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(3));
+
+ /* configure DATA order and alignment */
+ value = DISP_DATA_FORMAT_DF1P1C | DISP_ORDER_RED_BLUE;
+
+ if (bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
+ value |= DISP_ALIGNMENT_LSB;
+ else
+ value &= ~DISP_ALIGNMENT_LSB;
+
tegra_dc_writel(rgb->dc, value, DC_DISP_DISP_INTERFACE_CONTROL);
tegra_dc_commit(rgb->dc);
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 10/11] dt-bindings: display: tegra: Document 8-bit CPU parallel interface
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (8 preceding siblings ...)
2026-10-29 15:29 ` [PATCH v5 09/11] drm/tegra: rgb: Parameterize configuration based on bus flags Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
2026-10-29 15:29 ` [PATCH v5 11/11] drm/tegra: Add support for 8-bit CPU interface Svyatoslav Ryhel
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Document 8-bit CPU parallel MIPI DBI Type B interface provided by
Tegra20/30 SoCs display controller.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
.../display/tegra/nvidia,tegra20-dbi.yaml | 113 ++++++++++++++++++
.../display/tegra/nvidia,tegra20-dc.yaml | 22 ++++
2 files changed, 135 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dbi.yaml
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dbi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dbi.yaml
new file mode 100644
index 0000000000000..cd568d19c363a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dbi.yaml
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/tegra/nvidia,tegra20-dbi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nvidia Tegra Display Controller based MIPI DBI Type B interface
+
+maintainers:
+ - Svyatoslav Ryhel <clamor95@gmail.com>
+
+description: The display controller in Tegra20/30 SoCs features an
+ 8-bit SPI interface that closely resembles the MIPI DBI Type B
+ protocol and is referred to as '8-bit CPU'. Each display controller
+ provides two such interfaces, which can be used to send MIPI DCS
+ commands to initialize and control the panel while image data is
+ transmitted via 16/18/24-line RGB.
+
+properties:
+ reg:
+ maximum: 1
+ description: DBI interface used 0 - primary, 1 - secondary.
+
+ panel:
+ type: object
+ description: Node of supported panel driven by the bridge.
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: Video port for RGB input.
+
+ properties:
+ endpoint:
+ $ref: /schemas/graph.yaml#/$defs/endpoint-base
+ unevaluatedProperties: false
+
+ properties:
+ bus-width:
+ enum: [ 16, 18, 24 ]
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Video port for DBI output (panel or connector).
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - reg
+ - panel
+ - ports
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dc@54200000 {
+ reg = <0x54200000 0x00040000>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dbi@0 {
+ reg = <0>;
+
+ panel {
+ compatible = "hit,tx10d07vm0baa";
+
+ reset-gpios = <&gpio 175 GPIO_ACTIVE_LOW>;
+
+ avci-supply = <&vcc_2v8_lcd>;
+ iovcc-supply = <&iovcc_1v8_lcd>;
+
+ backlight = <&backlight>;
+
+ port {
+ panel_input: endpoint {
+ remote-endpoint = <&bridge_output>;
+ };
+ };
+ };
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ bridge_input: endpoint {
+ remote-endpoint = <&dpi_output>;
+ bus-width = <24>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ bridge_output: endpoint {
+ remote-endpoint = <&panel_input>;
+ };
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml
index 69be95afd5627..ffeb124905dbf 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml
@@ -79,6 +79,16 @@ properties:
rgb:
type: object
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+patternProperties:
+ "^dbi@[0-1]$":
+ $ref: /schemas/display/tegra/nvidia,tegra20-dbi.yaml#
+
allOf:
- if:
properties:
@@ -155,6 +165,18 @@ allOf:
- const: wind
- const: wint
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra114-dc
+ - nvidia,tegra124-dc
+ - nvidia,tegra210-dc
+ then:
+ patternProperties:
+ "^dbi@[0-1]$": false
+
additionalProperties: false
required:
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v5 11/11] drm/tegra: Add support for 8-bit CPU interface
2026-10-29 15:28 [PATCH v5 00/11] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (9 preceding siblings ...)
2026-10-29 15:29 ` [PATCH v5 10/11] dt-bindings: display: tegra: Document 8-bit CPU parallel interface Svyatoslav Ryhel
@ 2026-10-29 15:29 ` Svyatoslav Ryhel
10 siblings, 0 replies; 12+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-29 15:29 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
The display controller in Tegra20/30 SoCs features an 8-bit SPI interface
that closely resembles the MIPI DBI Type B protocol and is referred to as
'8-bit CPU'. Each display controller provides two such interfaces, which
can be used to send MIPI DCS commands to initialize and control the panel
while image data is transmitted via 16/18/24-line RGB.
The '8-bit CPU', although being the DC interface, is modeled using a
bridge framework for flexibility and convenience. This implementation does
not change the existing codebase besides registering the bus.
Suggested-by: Mikko Perttunen <mperttunen@nvidia.com> # DC command transfer
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/tegra/Makefile | 1 +
drivers/gpu/drm/tegra/dbi.c | 632 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/tegra/dc.c | 4 +
drivers/gpu/drm/tegra/dc.h | 3 +
4 files changed, 640 insertions(+)
create mode 100644 drivers/gpu/drm/tegra/dbi.c
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
index e399b40d64a1d..ae7fccb3d6421 100644
--- a/drivers/gpu/drm/tegra/Makefile
+++ b/drivers/gpu/drm/tegra/Makefile
@@ -18,6 +18,7 @@ tegra-drm-y := \
hdmi.o \
mipi-phy.o \
dsi.o \
+ dbi.o \
sor.o \
dpaux.o \
gr2d.o \
diff --git a/drivers/gpu/drm/tegra/dbi.c b/drivers/gpu/drm/tegra/dbi.c
new file mode 100644
index 0000000000000..e129be0f21da5
--- /dev/null
+++ b/drivers/gpu/drm/tegra/dbi.c
@@ -0,0 +1,632 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia Tegra20/30 MIPI-DBI Type B host driver
+ *
+ * Copyright (C) 2026 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_mipi_dbi.h>
+#include <drm/drm_mipi_dbi_bus.h>
+#include <drm/drm_of.h>
+
+#include <video/mipi_display.h>
+
+#include "dc.h"
+
+enum tegra_dbi_dc_signal {
+ TEGRA_DBI_COMMAND,
+ TEGRA_DBI_DATA
+};
+
+#define TEGRA_DBI_DATA_PINS_MAX 8
+#define TEGRA_DBI_INTERFACE_MAX 2
+
+struct reg_entry {
+ u32 offset;
+ u32 value;
+};
+
+static const struct reg_entry com_pin_output[] = {
+ { DC_COM_PIN_OUTPUT_ENABLE(0), 0 },
+ { DC_COM_PIN_OUTPUT_ENABLE(1), 0 },
+ { DC_COM_PIN_OUTPUT_ENABLE(2), 0 },
+ { DC_COM_PIN_OUTPUT_ENABLE(3), 0 },
+ { DC_COM_PIN_OUTPUT_POLARITY(0), 0 },
+ { DC_COM_PIN_OUTPUT_POLARITY(1), 0 },
+ { DC_COM_PIN_OUTPUT_POLARITY(2), 0 },
+ { DC_COM_PIN_OUTPUT_POLARITY(3), 0 },
+ { DC_COM_PIN_OUTPUT_DATA(0), 0 },
+ { DC_COM_PIN_OUTPUT_DATA(1), 0 },
+ { DC_COM_PIN_OUTPUT_DATA(2), 0 },
+ { DC_COM_PIN_OUTPUT_DATA(3), 0 },
+ { DC_COM_PIN_OUTPUT_SELECT(0), 0 },
+ { DC_COM_PIN_OUTPUT_SELECT(1), 0 },
+ { DC_COM_PIN_OUTPUT_SELECT(2), 0 },
+ { DC_COM_PIN_OUTPUT_SELECT(3), 0 },
+ { DC_COM_PIN_OUTPUT_SELECT(4), 0 },
+ { DC_COM_PIN_OUTPUT_SELECT(5), 0 },
+ { DC_COM_PIN_OUTPUT_SELECT(6), 0 },
+};
+
+struct tegra_dbi_priv {
+ struct device *dev;
+ struct tegra_dc *dc;
+
+ struct mipi_dbi dbi;
+ struct mipi_dbi_host dbi_host;
+
+ struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
+
+ const struct tegra_dbi_interface *index;
+ struct reg_entry com_pin_backup[ARRAY_SIZE(com_pin_output)];
+
+ u32 bus_width;
+ u32 reg;
+ bool active;
+};
+
+struct pin {
+ u32 reg;
+ u32 pos;
+};
+
+struct tegra_dbi_interface {
+ struct pin dc;
+ struct pin rw;
+ struct pin cs;
+ struct pin data[TEGRA_DBI_DATA_PINS_MAX];
+};
+
+static const struct tegra_dbi_interface tegra_dbi_idx[TEGRA_DBI_INTERFACE_MAX] = {
+ /* Nvidia Primary 8-bit CPU interface configuration */
+ {
+ .dc = { DC_COM_PIN_OUTPUT_DATA(3), PIN_LDC },
+ .rw = { DC_COM_PIN_OUTPUT_DATA(1), PIN_LSC0 },
+ .cs = { DC_COM_PIN_OUTPUT_DATA(3), PIN_LCSN },
+ .data = {
+ { DC_COM_PIN_OUTPUT_DATA(0), PIN_LD0 },
+ { DC_COM_PIN_OUTPUT_DATA(0), PIN_LD1 },
+ { DC_COM_PIN_OUTPUT_DATA(0), PIN_LD2 },
+ { DC_COM_PIN_OUTPUT_DATA(0), PIN_LD3 },
+ { DC_COM_PIN_OUTPUT_DATA(0), PIN_LD4 },
+ { DC_COM_PIN_OUTPUT_DATA(0), PIN_LD5 },
+ { DC_COM_PIN_OUTPUT_DATA(0), PIN_LD6 },
+ { DC_COM_PIN_OUTPUT_DATA(0), PIN_LD7 },
+ },
+ },
+ /* Nvidia Secondary 8-bit CPU interface configuration */
+ {
+ .dc = { DC_COM_PIN_OUTPUT_DATA(2), PIN_LVP0 },
+ .rw = { DC_COM_PIN_OUTPUT_DATA(1), PIN_LSC1 },
+ .cs = { DC_COM_PIN_OUTPUT_DATA(2), PIN_LM0 },
+ .data = {
+ { DC_COM_PIN_OUTPUT_DATA(2), PIN_LHP1 },
+ { DC_COM_PIN_OUTPUT_DATA(2), PIN_LM1 },
+ { DC_COM_PIN_OUTPUT_DATA(2), PIN_LDI },
+ { DC_COM_PIN_OUTPUT_DATA(2), PIN_LPP },
+ { DC_COM_PIN_OUTPUT_DATA(1), PIN_LPW0 },
+ { DC_COM_PIN_OUTPUT_DATA(1), PIN_LPW2 },
+ { DC_COM_PIN_OUTPUT_DATA(2), PIN_LVP1 },
+ { DC_COM_PIN_OUTPUT_DATA(2), PIN_LHP0 },
+ },
+ },
+};
+
+static inline struct tegra_dbi_priv *mipi_dbi_to_tegra_dbi(struct mipi_dbi *dbi)
+{
+ return container_of(dbi, struct tegra_dbi_priv, dbi);
+}
+
+static inline struct tegra_dbi_priv *dbi_host_to_tegra_dbi(struct mipi_dbi_host *host)
+{
+ return container_of(host, struct tegra_dbi_priv, dbi_host);
+}
+
+static inline struct tegra_dbi_priv *bridge_to_tegra_dbi(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct tegra_dbi_priv, bridge);
+}
+
+static void tegra_dbi_pin_set(struct tegra_dc *dc, const struct pin *pin, bool value)
+{
+ u32 val = BIT(pin->pos + 1); /* unmask is 1 bit above position */
+
+ if (value)
+ val |= BIT(pin->pos);
+
+ tegra_dc_writel(dc, val, pin->reg);
+}
+
+static void tegra_dbi_write(struct tegra_dbi_priv *priv,
+ enum tegra_dbi_dc_signal signal, u8 value)
+{
+ struct tegra_dc *dc = priv->dc;
+ const struct tegra_dbi_interface *idx = priv->index;
+
+ tegra_dbi_pin_set(dc, &idx->dc, signal);
+
+ tegra_dbi_pin_set(dc, &idx->cs, 0);
+ tegra_dbi_pin_set(dc, &idx->rw, 0);
+
+ for (int i = 0; i < TEGRA_DBI_DATA_PINS_MAX; i++)
+ tegra_dbi_pin_set(dc, &idx->data[i], field_get(BIT(i), value));
+
+ tegra_dbi_pin_set(dc, &idx->cs, 1);
+ tegra_dbi_pin_set(dc, &idx->rw, 1);
+
+ udelay(10);
+}
+
+static int tegra_dbi_dbi_command(struct mipi_dbi *dbi, u8 *cmd, u8 *param, size_t num)
+{
+ struct tegra_dbi_priv *priv = mipi_dbi_to_tegra_dbi(dbi);
+ u8 command = *cmd;
+
+ /* Blocks all commands when interface is not active */
+ if (!priv->active)
+ return -ENODEV;
+
+ tegra_dbi_write(priv, TEGRA_DBI_COMMAND, command);
+
+ for (int i = 0; i < num; i++)
+ tegra_dbi_write(priv, TEGRA_DBI_DATA, param[i]);
+
+ return 0;
+}
+
+static int tegra_dbi_host_attach(struct mipi_dbi_host *host, struct mipi_dbi_device *dbidev)
+{
+ struct tegra_dbi_priv *priv = dbi_host_to_tegra_dbi(host);
+ struct device *dev = priv->dev;
+ struct drm_bridge *bridge;
+ struct device_node *ep;
+ int ret;
+
+ bridge = of_drm_get_bridge_by_endpoint(dev_of_node(dev), 1, -1);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
+
+ bridge->type = DRM_MODE_CONNECTOR_DPI;
+ priv->next_bridge = bridge;
+
+ /* get input ep (port0/endpoint0) */
+ ret = -EINVAL;
+ ep = of_graph_get_endpoint_by_regs(dev_of_node(dev), 0, 0);
+ if (ep) {
+ ret = of_property_read_u32(ep, "bus-width", &priv->bus_width);
+ of_node_put(ep);
+ }
+
+ if (ret)
+ priv->bus_width = 24;
+
+ return devm_drm_bridge_add(dev, &priv->bridge);
+}
+
+static void tegra_dbi_host_detach(struct mipi_dbi_host *host, struct mipi_dbi_device *dbidev)
+{
+ struct tegra_dbi_priv *priv = dbi_host_to_tegra_dbi(host);
+
+ drm_bridge_remove(&priv->bridge);
+ drm_bridge_put(priv->next_bridge);
+}
+
+static const struct mipi_dbi_host_ops tegra_dbi_host_ops = {
+ .attach = tegra_dbi_host_attach,
+ .detach = tegra_dbi_host_detach,
+};
+
+static void tegra_dbi_init_primary_interface(struct tegra_dbi_priv *priv)
+{
+ struct tegra_dc *dc = priv->dc;
+ u32 value;
+
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_ENABLE(3));
+ value &= ~(BIT(PIN_LCSN) | BIT(PIN_LDC));
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_ENABLE(3));
+
+ /* Set LSC0/LCSN/LDC output polarity HIGH */
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY(1));
+ value &= ~BIT(PIN_LSC0);
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_POLARITY(1));
+
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY(3));
+ value &= ~(BIT(PIN_LCSN) | BIT(PIN_LDC));
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_POLARITY(3));
+
+ value = PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LD0) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LD1) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LD2) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LD3) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LD4) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LD5) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LD6) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LD7);
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_SELECT(0));
+
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT(3));
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LSC0);
+ value |= PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LSC0);
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_SELECT(3));
+
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT(6));
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LCSN);
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LDC);
+ value |= PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LCSN) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LDC);
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_SELECT(6));
+}
+
+static void tegra_dbi_init_secondary_interface(struct tegra_dbi_priv *priv)
+{
+ struct tegra_dc *dc = priv->dc;
+ u32 value;
+
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_ENABLE(2));
+ value &= ~(BIT(PIN_LDI) | BIT(PIN_LPP));
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_ENABLE(2));
+
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT(3));
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LPW0);
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LPW2);
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LSC1);
+ value |= PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LPW0) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LPW2) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LSC1);
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_SELECT(3));
+
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT(4));
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LHP0);
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LHP1);
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LVP0);
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LVP1);
+ value |= PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LHP0) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LHP1) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LVP0) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LVP1);
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_SELECT(4));
+
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT(5));
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LM0);
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LM1);
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LDI);
+ value &= ~PIN_OUTPUT_SELECT_MASK(PIN_OUTPUT_SELECT_LPP);
+ value |= PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LM0) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LM1) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LDI) |
+ PIN_OUTPUT_SELECT_OUT(PIN_OUTPUT_SELECT_LPP);
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_SELECT(5));
+}
+
+static void tegra_dbi_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *state)
+{
+ struct tegra_dbi_priv *priv = bridge_to_tegra_dbi(bridge);
+ struct drm_bridge *next_bridge = priv->next_bridge;
+ struct tegra_dc *dc = priv->dc;
+ u32 value;
+
+ value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+ value &= ~DISP_CTRL_MODE_MASK;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+ /* Disable all options except cursor if enabled */
+ value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+ value &= CURSOR_ENABLE;
+ tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+ tegra_dc_commit(dc);
+
+ tegra_dc_writel(dc, V_PULSE1_ENABLE, DC_DISP_DISP_SIGNAL_OPTIONS0);
+ tegra_dc_writel(dc, PULSE_POLARITY_LOW, DC_DISP_V_PULSE1_CONTROL);
+
+ tegra_dc_writel(dc, PULSE_END(1), DC_DISP_V_PULSE1_POSITION_A);
+ tegra_dc_writel(dc, 0, DC_DISP_V_PULSE1_POSITION_B);
+ tegra_dc_writel(dc, 0, DC_DISP_V_PULSE1_POSITION_C);
+
+ value = 1 << FRAME_INIT_SEQ_CYCLES_SHIFT |
+ DC_SIGNAL_VPULSE1 << INIT_SEQ_DC_SIGNAL_SHIFT |
+ INIT_SEQUENCE_MODE_PLCD | SEND_INIT_SEQUENCE;
+ tegra_dc_writel(dc, value, DC_DISP_INIT_SEQ_CONTROL);
+
+ /* Init cycle 1: WRITE_MEMORY_START, set LCD_PCLK and COMMAND */
+ tegra_dc_writel(dc, MIPI_DCS_WRITE_MEMORY_START, DC_DISP_SPI_INIT_SEQ_DATA_A);
+ tegra_dc_writel(dc, 0x0, DC_DISP_SPI_INIT_SEQ_DATA_B);
+ tegra_dc_writel(dc, 0x0, DC_DISP_SPI_INIT_SEQ_DATA_C);
+ tegra_dc_writel(dc, BIT(12) | BIT(14), DC_DISP_SPI_INIT_SEQ_DATA_D);
+
+ value = SC1_H_QUALIFIER(SC_H_QUALIFIER_NONE) |
+ SC0_V_QUALIFIER(SC_V_QUALIFIER_VACTIVE) |
+ SC0_H_QUALIFIER(SC_H_QUALIFIER_HACTIVE);
+ tegra_dc_writel(dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);
+
+ value = tegra_dc_readl(dc, DC_DISP_DISP_COLOR_CONTROL);
+ value &= ~BASE_COLOR_SIZE_MASK;
+
+ switch (priv->bus_width) {
+ case 16:
+ value |= BASE_COLOR_SIZE_565;
+ break;
+ case 18:
+ value |= BASE_COLOR_SIZE_666;
+ break;
+ case 24:
+ default:
+ value |= BASE_COLOR_SIZE_888;
+ break;
+ }
+
+ tegra_dc_writel(dc, value, DC_DISP_DISP_COLOR_CONTROL);
+
+ /*
+ * Backup registers before unshadowing since actual register values
+ * may differ and their state backed up now is the correct one.
+ */
+ for (int i = 0; i < ARRAY_SIZE(com_pin_output); i++)
+ priv->com_pin_backup[i].value = tegra_dc_readl(dc,
+ priv->com_pin_backup[i].offset);
+
+ /* Unshadow to set up command and data pins */
+ tegra_dc_writel(dc, WRITE_MUX | READ_MUX, DC_CMD_STATE_ACCESS);
+
+ if (priv->reg)
+ tegra_dbi_init_secondary_interface(priv);
+ else
+ tegra_dbi_init_primary_interface(priv);
+
+ priv->active = true;
+
+ /*
+ * DBI requires that the next bridge be enabled here in order to
+ * send DCS commands, since the interface pins will subsequently be
+ * reconfigured for video data.
+ */
+ if (next_bridge->funcs && next_bridge->funcs->atomic_enable)
+ next_bridge->funcs->atomic_enable(next_bridge, state);
+
+ tegra_dbi_pin_set(dc, &priv->index->cs, 0);
+
+ priv->active = false;
+
+ tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
+
+ for (int i = 0; i < ARRAY_SIZE(com_pin_output); i++)
+ tegra_dc_writel(dc, priv->com_pin_backup[i].value,
+ priv->com_pin_backup[i].offset);
+
+ tegra_dc_commit(dc);
+
+ /* Set LDC pin to V Pulse 1 */
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT(6));
+ value |= PIN_OUTPUT_SELECT_F4(PIN_OUTPUT_SELECT_LDC);
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_SELECT(6));
+
+ value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+ value &= ~DISP_CTRL_MODE_MASK;
+ value |= DISP_CTRL_MODE_C_DISPLAY;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+}
+
+static void tegra_dbi_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *state)
+{
+ struct tegra_dbi_priv *priv = bridge_to_tegra_dbi(bridge);
+ struct drm_bridge *next_bridge = priv->next_bridge;
+ struct tegra_dc *dc = priv->dc;
+
+ for (int i = 0; i < ARRAY_SIZE(com_pin_output); i++)
+ priv->com_pin_backup[i].value = tegra_dc_readl(dc,
+ priv->com_pin_backup[i].offset);
+
+ tegra_dc_writel(dc, WRITE_MUX, DC_CMD_STATE_ACCESS);
+
+ if (priv->reg)
+ tegra_dbi_init_secondary_interface(priv);
+ else
+ tegra_dbi_init_primary_interface(priv);
+
+ priv->active = true;
+
+ /*
+ * DBI requires that the next bridge be disabled here in order to
+ * send DCS commands, since the interface pins will subsequently be
+ * reconfigured for video data.
+ */
+ if (next_bridge->funcs && next_bridge->funcs->atomic_disable)
+ next_bridge->funcs->atomic_disable(next_bridge, state);
+
+ priv->active = false;
+
+ tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
+
+ for (int i = 0; i < ARRAY_SIZE(com_pin_output); i++)
+ tegra_dc_writel(dc, priv->com_pin_backup[i].value,
+ priv->com_pin_backup[i].offset);
+
+ tegra_dc_commit(dc);
+}
+
+static int tegra_dbi_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+
+ /* Set safe default bus flags if panel does not specify them */
+ if (!bridge_state->input_bus_cfg.flags)
+ bridge_state->input_bus_cfg.flags = bridge->timings->input_bus_flags;
+
+ /* Default to positive sync */
+ if (!(adjusted_mode->flags &
+ (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC)))
+ adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+
+ if (!(adjusted_mode->flags &
+ (DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
+ adjusted_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+
+ return 0;
+}
+
+static int tegra_dbi_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
+{
+ struct tegra_dbi_priv *priv = bridge_to_tegra_dbi(bridge);
+ struct device *dev = priv->dev;
+
+ priv->dc = dev_get_drvdata(dev->parent);
+ if (!priv->dc)
+ return -ENODEV;
+
+ return drm_bridge_attach(bridge->encoder, priv->next_bridge, bridge,
+ flags);
+}
+
+static enum drm_mode_status tegra_dbi_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ if (mode->hdisplay > 800)
+ return MODE_H_ILLEGAL;
+
+ if (mode->vdisplay > 800)
+ return MODE_V_ILLEGAL;
+
+ return MODE_OK;
+}
+
+static const struct drm_bridge_funcs tegra_dbi_funcs = {
+ .attach = tegra_dbi_attach,
+ .mode_valid = tegra_dbi_mode_valid,
+
+ .atomic_enable = tegra_dbi_atomic_enable,
+ .atomic_disable = tegra_dbi_atomic_disable,
+ .atomic_check = tegra_dbi_atomic_check,
+
+ .atomic_create_state = drm_atomic_helper_bridge_create_state,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+};
+
+static const struct drm_bridge_timings default_tegra_dbi_timings = {
+ .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_DE_HIGH,
+};
+
+static int tegra_dbi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mipi_dbi_device *dbidev;
+ struct tegra_dbi_priv *priv;
+ struct device_node *np;
+ int ret;
+
+ priv = devm_drm_bridge_alloc(dev, struct tegra_dbi_priv, bridge,
+ &tegra_dbi_funcs);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ priv->dev = dev;
+
+ /* Default to primaty */
+ ret = device_property_read_u32(dev, "reg", &priv->reg);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get reg\n");
+
+ if (priv->reg != 0 && priv->reg != 1)
+ return dev_err_probe(dev, -EINVAL, "Wrong reg value: %d\n", priv->reg);
+
+ priv->index = &tegra_dbi_idx[priv->reg];
+ memcpy(priv->com_pin_backup, com_pin_output, sizeof(com_pin_output));
+
+ /* Initialize MIPI DBI interface */
+ mutex_init(&priv->dbi.cmdlock);
+ priv->dbi.command = tegra_dbi_dbi_command;
+
+ priv->dbi_host.dev = dev;
+ priv->dbi_host.dbi = &priv->dbi;
+ priv->dbi_host.ops = &tegra_dbi_host_ops;
+
+ priv->bridge.of_node = dev_of_node(dev);
+ priv->bridge.timings = &default_tegra_dbi_timings;
+
+ np = of_graph_get_remote_node(dev_of_node(dev), 1, -1);
+ if (!np)
+ return -EINVAL;
+
+ dbidev = devm_mipi_dbi_device_register(dev, &priv->dbi_host, np);
+ of_node_put(np);
+ if (IS_ERR(dbidev))
+ return dev_err_probe(dev, PTR_ERR(dbidev),
+ "Failed to register DBI device\n");
+
+ return 0;
+}
+
+static struct platform_driver tegra_dbi_driver = {
+ .driver.name = "tegra-dbi",
+ .probe = tegra_dbi_probe,
+};
+
+static void tegra_dbi_release(void *pdev)
+{
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&tegra_dbi_driver);
+}
+
+int devm_tegra_dc_dbi_init(struct device *dev)
+{
+ struct device_node *dbi_np __free(device_node) =
+ of_get_available_child_by_name(dev_of_node(dev), "dbi");
+ struct platform_device_info dbi_info = { 0 };
+ struct platform_device *dbi;
+ int ret;
+
+ /* Missing node means that DBI is not used, continue */
+ if (!dbi_np)
+ return 0;
+
+ ret = platform_driver_register(&tegra_dbi_driver);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register DBI driver\n");
+
+ dbi_info.parent = dev;
+ dbi_info.name = "tegra-dbi";
+ dbi_info.id = PLATFORM_DEVID_AUTO;
+ dbi_info.fwnode = of_fwnode_handle(dbi_np);
+ dbi_info.of_node_reused = true;
+
+ dbi = platform_device_register_full(&dbi_info);
+ if (IS_ERR(dbi)) {
+ platform_driver_unregister(&tegra_dbi_driver);
+ return dev_err_probe(dev, PTR_ERR(dbi),
+ "Failed to create DBI device\n");
+ }
+
+ ret = devm_add_action_or_reset(dev, tegra_dbi_release, dbi);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 5bbf2c028edd8..768cf82776632 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -3382,6 +3382,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
}
}
+ err = devm_tegra_dc_dbi_init(&pdev->dev);
+ if (err)
+ return dev_err_probe(&pdev->dev, err, "failed to init DBI\n");
+
err = tegra_dc_rgb_probe(dc);
if (err < 0 && err != -ENODEV)
return dev_err_probe(&pdev->dev, err,
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 2b87bb675d4cf..3df49422a2bd1 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -177,6 +177,9 @@ void tegra_dc_rgb_remove(struct tegra_dc *dc);
int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
int tegra_dc_rgb_exit(struct tegra_dc *dc);
+/* from dbi.c */
+int devm_tegra_dc_dbi_init(struct device *dev);
+
#define DC_CMD_GENERAL_INCR_SYNCPT 0x000
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001
--
2.53.0
^ permalink raw reply [flat|nested] 12+ messages in thread