Skip to contentSkip to conversation

drm/panel: Add Magnachip D53E6EA8966 Panel Controller

PATCH Superseded Chris Morgan 2 participants 8 messages Jan 12, 2023 – Jan 18, 2023

Subsystems (5)

v10 of 12 Superseded Latest is v12 →

lore
Share & tools
lore
#0 lore raw

v10 cover drm/panel: Add Magnachip D53E6EA8966 Panel Controller

From: Chris Morgan <[email protected]>

Add the Magnachip D53E6EA8966 panel IC controller for display panels such as the Samsung AMS495QA01 panel as found on the Anbernic RG503. This panel uses DSI to receive video signals, but 3-wire SPI to receive command signals using DBI.

Changes since V9:
- Set an ifdef to not add the drm_of_get_dsi_bus when MIPI_DSI is not part of the current kernel config.
- Made "info" optional in the drm_of_get_dsi_bus() function.

Changes since V8:
- Set "placeholder" drm_of_get_dsi_bus in drm_of.h to static inline to hopefully eliminate the reported errors once and for all. Tested with 4 different kernel configurations provided by Intel's kernel test robot and no new warnings or errors were introduced.

Changes since V7:
- Removed Linus Walleij review note due to substantial changes.
- Corrected documentation of drm_of_get_dsi_bus function.
- Updated the drm_of_get_dsi_bus function to return pointer to mipi_dsi_host and use ERR_PTR macros.
- Refactored drm_panel_funcs so that the prepare function calls panel specific function for init sequence and uses generic functions otherwise.
- Renamed non-panel specific functions.
- Changed backlight value to int instead of u32.
- Corrected brightness function to use backlight_get_brightness().
- Fix an error reported when CONFIG_OF is selected but CONFIG_DRM_MIPI_DSI is not. Add an if function to drm_of_get_dsi_bus function to return -EINVAL in this instance.

Changes since V6:
- Fixed a trivial error with definition of drm_of_get_dsi_bus().

Changes since V5:
- Reverted dt binding documentation name back to samsung,ams495qa01.yaml.
- Removed no longer needed of_graph.h header file.
- Added backlight as a dependency.

Changes since V4:
- Renamed driver from the panel model to the panel IC controller per DRM team.
- Added a drm_of helper function of drm_of_get_dsi_bus() to handle finding and populating the DSI node when the DSI node is not the parent of the DSI controlled display.
- Converted the documented commands to constants to make it more readable.
- Reset GPIO is now required and documented as GPIO_ACTIVE_LOW.
- Removed "prepared" logic from panel.

Changes since V3:
- Updated documentation to add spi-peripheral-props.yaml per updates
made for similar devices. Note that I removed a "Reviewed-by" tag
from Rob Herring since this change probably needs to be confirmed.
- Added binding for RG503, since this device is now accepted with this
request: https://lore.kernel.org/linux-rockchip/[email protected]/

Changes since V2:
- Added 50hz mode at request of userspace devs.
- Renamed "dupa" to panel name. Good catch Maya.
- Added Maya's Signed-off-by.
- Removed check for max backlight, since it is already done by backlight_device_set_brightness.
- Fixed minor formatting issues on devicetree binding documentation and added port to provided example.

Changes since V1:
- Removed errant reference to backlight in documentation. This is an OLED panel.
- Made elvss regulator optional. In my case its hard wired and not controllable.
- Added "prepared" enum to track panel status to prevent unbalanced regulator enable/disable.

Chris Morgan (4):
drm: of: Add drm_of_get_dsi_bus helper function
dt-bindings: display: panel: Add Samsung AMS495QA01 drm/panel: Add Magnachip D53E6EA8966 Panel Driver
arm64: dts: rockchip: add display to RG503

 .../display/panel/samsung,ams495qa01.yaml     |  57 ++
 .../dts/rockchip/rk3566-anbernic-rg503.dts    |  55 ++
 drivers/gpu/drm/drm_of.c                      |  70 +++
 drivers/gpu/drm/panel/Kconfig                 |  11 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-magnachip-d53e6ea8966.c   | 522 ++++++++++++++++++
 include/drm/drm_of.h                          |  10 +
 7 files changed, 726 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/samsung,ams495qa01.yaml
 create mode 100644 drivers/gpu/drm/panel/panel-magnachip-d53e6ea8966.c
Signature · 1 line
2.34.1
#1 lore raw

PATCH v10 1/4 drm: of: Add drm_of_get_dsi_bus helper function

From: Chris Morgan <[email protected]>

Add helper function to find DSI host for devices where DSI panel is not a minor of a DSI bus (such as the Samsung AMS495QA01 panel or the official Raspberry Pi touchscreen display).

---
 drivers/gpu/drm/drm_of.c | 70 ++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_of.h     | 10 ++++++
 2 files changed, 80 insertions(+)
drivers/gpu/drm/drm_of.c +70 -0
index 7bbcb999bb75..6c2c97a716fe 100644
@@ -10,6 +10,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_encoder.h>
+#include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 
@@ -493,3 +494,72 @@ int drm_of_get_data_lanes_count_ep(const struct device_node *port,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(drm_of_get_data_lanes_count_ep);
+
+#if IS_ENABLED(CONFIG_DRM_MIPI_DSI)
+
+/**
+ * drm_of_get_dsi_bus - find the DSI bus for a given device
+ * @dev: parent device of display (SPI, I2C)
+ * @info: DSI device info to be updated with DSI node. This is optional
+ * and if not needed can be NULL.
+ *
+ * Gets parent DSI bus for a DSI device controlled through a bus other
+ * than MIPI-DCS (SPI, I2C, etc.) using the Device Tree.
+ *
+ * Returns pointer to mipi_dsi_host if successful, -EINVAL if the
+ * request is unsupported, -EPROBE_DEFER if the DSI host is found but
+ * not available, or -ENODEV otherwise.
+ */
+struct mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info)
+{
+	struct mipi_dsi_host *dsi_host;
+	struct device_node *endpoint, *dsi_host_node;
+
+	/*
+	 * Get first endpoint child from device.
+	 */
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (!endpoint)
+		return ERR_PTR(-ENODEV);
+
+	/*
+	 * Follow the first endpoint to get the DSI host node.
+	 */
+	dsi_host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!dsi_host_node)
+		goto error;
+
+	/*
+	 * Get the DSI host from the DSI host node. If we get an error
+	 * or the return is null assume we're not ready to probe just
+	 * yet. Release the DSI host node since we're done with it.
+	 */
+	dsi_host = of_find_mipi_dsi_host_by_node(dsi_host_node);
+	of_node_put(dsi_host_node);
+	if (IS_ERR_OR_NULL(dsi_host)) {
+		of_node_put(endpoint);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	/*
+	 * Set the node of the mipi_dsi_device_info to the correct node
+	 * and then release the endpoint node since we're done with it.
+	 * since this is optional, check if the info is NULL first.
+	 */
+	if (info) {
+		info->node = of_graph_get_remote_port(endpoint);
+		if (IS_ERR_OR_NULL(info->node))
+			goto error;
+	}
+
+	of_node_put(endpoint);
+	return dsi_host;
+
+error:
+	of_node_put(endpoint);
+	return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(drm_of_get_dsi_bus);
+
+#endif /* CONFIG_DRM_MIPI_DSI */
include/drm/drm_of.h +10 -0
index 10ab58c40746..705ea2caa494 100644
@@ -15,6 +15,8 @@ struct drm_encoder;
 struct drm_panel;
 struct drm_bridge;
 struct device_node;
+struct mipi_dsi_device_info;
+struct mipi_dsi_host;
 
 /**
  * enum drm_lvds_dual_link_pixels - Pixel order of an LVDS dual-link connection
@@ -56,6 +58,8 @@ int drm_of_get_data_lanes_count_ep(const struct device_node *port,
 				   int port_reg, int reg,
 				   const unsigned int min,
 				   const unsigned int max);
+struct mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info);
 #else
 static inline uint32_t drm_of_crtc_port_mask(struct drm_device *dev,
 					  struct device_node *port)
@@ -127,6 +131,12 @@ drm_of_get_data_lanes_count_ep(const struct device_node *port,
 {
 	return -EINVAL;
 }
+static inline struct
+mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info)
+{
+	return ERR_PTR(-EINVAL);
+}
 #endif
 
 /*
Signature · 1 line
2.34.1
#2 lore raw

Re: [PATCH V10 1/4] drm: of: Add drm_of_get_dsi_bus helper function

Hi,

Quoted 74 lines · Chris Morgan

From: Chris Morgan <[email protected]>

Add helper function to find DSI host for devices where DSI panel is not a minor of a DSI bus (such as the Samsung AMS495QA01 panel or the official Raspberry Pi touchscreen display).

---
 drivers/gpu/drm/drm_of.c | 70 ++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_of.h     | 10 ++++++
 2 files changed, 80 insertions(+)
drivers/gpu/drm/drm_of.c +46 -0
index 7bbcb999bb75..6c2c97a716fe 100644
@@ -10,6 +10,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_encoder.h>
+#include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 
@@ -493,3 +494,72 @@ int drm_of_get_data_lanes_count_ep(const struct device_node *port,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(drm_of_get_data_lanes_count_ep);
+
+#if IS_ENABLED(CONFIG_DRM_MIPI_DSI)
+
+/**
+ * drm_of_get_dsi_bus - find the DSI bus for a given device
+ * @dev: parent device of display (SPI, I2C)
+ * @info: DSI device info to be updated with DSI node. This is optional
+ * and if not needed can be NULL.
+ *
+ * Gets parent DSI bus for a DSI device controlled through a bus other
+ * than MIPI-DCS (SPI, I2C, etc.) using the Device Tree.
+ *
+ * Returns pointer to mipi_dsi_host if successful, -EINVAL if the
+ * request is unsupported, -EPROBE_DEFER if the DSI host is found but
+ * not available, or -ENODEV otherwise.
+ */
+struct mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info)
+{
+	struct mipi_dsi_host *dsi_host;
+	struct device_node *endpoint, *dsi_host_node;
+
+	/*
+	 * Get first endpoint child from device.
+	 */
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (!endpoint)
+		return ERR_PTR(-ENODEV);
+
+	/*
+	 * Follow the first endpoint to get the DSI host node.
+	 */
+	dsi_host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!dsi_host_node)
+		goto error;
+
+	/*
+	 * Get the DSI host from the DSI host node. If we get an error
+	 * or the return is null assume we're not ready to probe just
+	 * yet. Release the DSI host node since we're done with it.
+	 */
+	dsi_host = of_find_mipi_dsi_host_by_node(dsi_host_node);
+	of_node_put(dsi_host_node);
+	if (IS_ERR_OR_NULL(dsi_host)) {
+		of_node_put(endpoint);

drivers/gpu/drm/drm_of.c int drm_of_get_data_lanes_count_ep(const struct device_node *port, · line 551

Quoted 10 lines
drivers/gpu/drm/drm_of.c +10 -0
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	/*
+	 * Set the node of the mipi_dsi_device_info to the correct node
+	 * and then release the endpoint node since we're done with it.
+	 * since this is optional, check if the info is NULL first.
+	 */
+	if (info) {
+		info->node = of_graph_get_remote_port(endpoint);

it looks to me that the info->node is actually the DSI device OF node, not its host port. Which begs the question, why should we even return it there, since there's a pretty big chance that dev->of.node == info->node, and you obviously don't care about the channel and type fields.

I've had a look and node of the current users of mipi_dsi_device_register_full actually register a mipi_dsi_device_info with a node pointer set to !NULL, including the driver in this series.

So, why do we care about the device info at all?

drivers/gpu/drm/drm_of.c int drm_of_get_data_lanes_count_ep(const struct device_node *port, · line 552

Quoted 1 line
drivers/gpu/drm/drm_of.c +1 -0
+		if (IS_ERR_OR_NULL(info->node))

of_graph_get_remote_port doesn't return an error pointer.

Quoted 21 lines
include/drm/drm_of.h +4 -0
@@ -15,6 +15,8 @@ struct drm_encoder;
 struct drm_panel;
 struct drm_bridge;
 struct device_node;
+struct mipi_dsi_device_info;
+struct mipi_dsi_host;
 
 /**
  * enum drm_lvds_dual_link_pixels - Pixel order of an LVDS dual-link connection
@@ -56,6 +58,8 @@ int drm_of_get_data_lanes_count_ep(const struct device_node *port,
 				   int port_reg, int reg,
 				   const unsigned int min,
 				   const unsigned int max);
+struct mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info);
 #else
 static inline uint32_t drm_of_crtc_port_mask(struct drm_device *dev,
 					  struct device_node *port)

include/drm/drm_of.h drm_of_get_data_lanes_count_ep(const struct device_node *port, · line 140

Quoted 10 lines
include/drm/drm_of.h +6 -0
@@ -127,6 +131,12 @@ drm_of_get_data_lanes_count_ep(const struct device_node *port,
 {
 	return -EINVAL;
 }
+static inline struct
+mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info)
+{
+	return ERR_PTR(-EINVAL);
+}
 #endif

So it looks to me that if CONFIG_OF is defined, we'll define an external symbol declared for drm_of_get_dsi_bus, but that function will only be compiled if CONFIG_DRM_MIPI_DSI is enabled.

What happens if we have CONFIG_OF but not CONFIG_DRM_MIPI_DSI?

If think you need to have here something like:

#ifdef IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_MIPI_DSI) struct mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,

       					 struct mipi_dsi_device_info *info);

#else
static inline struct
mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
struct mipi_dsi_device_info *info)

{
	return ERR_PTR(-EINVAL);
}

#endif

Maxime

#3 lore raw

Re: [PATCH V10 1/4] drm: of: Add drm_of_get_dsi_bus helper function

Quoted 93 lines · Maxime Ripard

Hi,

Quoted 74 lines · Chris Morgan

From: Chris Morgan <[email protected]>

Add helper function to find DSI host for devices where DSI panel is not a minor of a DSI bus (such as the Samsung AMS495QA01 panel or the official Raspberry Pi touchscreen display).

---
 drivers/gpu/drm/drm_of.c | 70 ++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_of.h     | 10 ++++++
 2 files changed, 80 insertions(+)
drivers/gpu/drm/drm_of.c +46 -0
index 7bbcb999bb75..6c2c97a716fe 100644
@@ -10,6 +10,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_encoder.h>
+#include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 
@@ -493,3 +494,72 @@ int drm_of_get_data_lanes_count_ep(const struct device_node *port,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(drm_of_get_data_lanes_count_ep);
+
+#if IS_ENABLED(CONFIG_DRM_MIPI_DSI)
+
+/**
+ * drm_of_get_dsi_bus - find the DSI bus for a given device
+ * @dev: parent device of display (SPI, I2C)
+ * @info: DSI device info to be updated with DSI node. This is optional
+ * and if not needed can be NULL.
+ *
+ * Gets parent DSI bus for a DSI device controlled through a bus other
+ * than MIPI-DCS (SPI, I2C, etc.) using the Device Tree.
+ *
+ * Returns pointer to mipi_dsi_host if successful, -EINVAL if the
+ * request is unsupported, -EPROBE_DEFER if the DSI host is found but
+ * not available, or -ENODEV otherwise.
+ */
+struct mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info)
+{
+	struct mipi_dsi_host *dsi_host;
+	struct device_node *endpoint, *dsi_host_node;
+
+	/*
+	 * Get first endpoint child from device.
+	 */
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (!endpoint)
+		return ERR_PTR(-ENODEV);
+
+	/*
+	 * Follow the first endpoint to get the DSI host node.
+	 */
+	dsi_host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!dsi_host_node)
+		goto error;
+
+	/*
+	 * Get the DSI host from the DSI host node. If we get an error
+	 * or the return is null assume we're not ready to probe just
+	 * yet. Release the DSI host node since we're done with it.
+	 */
+	dsi_host = of_find_mipi_dsi_host_by_node(dsi_host_node);
+	of_node_put(dsi_host_node);
+	if (IS_ERR_OR_NULL(dsi_host)) {
+		of_node_put(endpoint);

drivers/gpu/drm/drm_of.c int drm_of_get_data_lanes_count_ep(const struct device_node *port, · line 551

Quoted 10 lines
drivers/gpu/drm/drm_of.c +10 -0
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	/*
+	 * Set the node of the mipi_dsi_device_info to the correct node
+	 * and then release the endpoint node since we're done with it.
+	 * since this is optional, check if the info is NULL first.
+	 */
+	if (info) {
+		info->node = of_graph_get_remote_port(endpoint);

it looks to me that the info->node is actually the DSI device OF node, not its host port. Which begs the question, why should we even return it there, since there's a pretty big chance that dev->of.node == info->node, and you obviously don't care about the channel and type fields.

Quoted 6 lines

I've had a look and node of the current users of mipi_dsi_device_register_full actually register a mipi_dsi_device_info with a node pointer set to !NULL, including the driver in this series.

So, why do we care about the device info at all?

I honestly thought it might be useful, but I can try without it.

Quoted 40 lines

drivers/gpu/drm/drm_of.c int drm_of_get_data_lanes_count_ep(const struct device_node *port, · line 552

Quoted 1 line
drivers/gpu/drm/drm_of.c +1 -0
+		if (IS_ERR_OR_NULL(info->node))

of_graph_get_remote_port doesn't return an error pointer.

Quoted 21 lines
include/drm/drm_of.h +4 -0
@@ -15,6 +15,8 @@ struct drm_encoder;
 struct drm_panel;
 struct drm_bridge;
 struct device_node;
+struct mipi_dsi_device_info;
+struct mipi_dsi_host;
 
 /**
  * enum drm_lvds_dual_link_pixels - Pixel order of an LVDS dual-link connection
@@ -56,6 +58,8 @@ int drm_of_get_data_lanes_count_ep(const struct device_node *port,
 				   int port_reg, int reg,
 				   const unsigned int min,
 				   const unsigned int max);
+struct mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info);
 #else
 static inline uint32_t drm_of_crtc_port_mask(struct drm_device *dev,
 					  struct device_node *port)

include/drm/drm_of.h drm_of_get_data_lanes_count_ep(const struct device_node *port, · line 140

Quoted 10 lines
include/drm/drm_of.h +6 -0
@@ -127,6 +131,12 @@ drm_of_get_data_lanes_count_ep(const struct device_node *port,
 {
 	return -EINVAL;
 }
+static inline struct
+mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info)
+{
+	return ERR_PTR(-EINVAL);
+}
 #endif

So it looks to me that if CONFIG_OF is defined, we'll define an external symbol declared for drm_of_get_dsi_bus, but that function will only be compiled if CONFIG_DRM_MIPI_DSI is enabled.

Quoted 2 lines

What happens if we have CONFIG_OF but not CONFIG_DRM_MIPI_DSI?

Will do, thank you.

Quoted 15 lines

If think you need to have here something like:

#ifdef IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_MIPI_DSI) struct mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,

       					 struct mipi_dsi_device_info *info);

#else
static inline struct
mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
struct mipi_dsi_device_info *info)

{
	return ERR_PTR(-EINVAL);
}

#endif

Maxime

#4 lore raw

Re: [PATCH V10 1/4] drm: of: Add drm_of_get_dsi_bus helper function

Quoted 94 lines · Chris Morgan
Quoted 93 lines · Maxime Ripard

Hi,

Quoted 74 lines · Chris Morgan

From: Chris Morgan <[email protected]>

Add helper function to find DSI host for devices where DSI panel is not a minor of a DSI bus (such as the Samsung AMS495QA01 panel or the official Raspberry Pi touchscreen display).

---
 drivers/gpu/drm/drm_of.c | 70 ++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_of.h     | 10 ++++++
 2 files changed, 80 insertions(+)
drivers/gpu/drm/drm_of.c +46 -0
index 7bbcb999bb75..6c2c97a716fe 100644
@@ -10,6 +10,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_encoder.h>
+#include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 
@@ -493,3 +494,72 @@ int drm_of_get_data_lanes_count_ep(const struct device_node *port,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(drm_of_get_data_lanes_count_ep);
+
+#if IS_ENABLED(CONFIG_DRM_MIPI_DSI)
+
+/**
+ * drm_of_get_dsi_bus - find the DSI bus for a given device
+ * @dev: parent device of display (SPI, I2C)
+ * @info: DSI device info to be updated with DSI node. This is optional
+ * and if not needed can be NULL.
+ *
+ * Gets parent DSI bus for a DSI device controlled through a bus other
+ * than MIPI-DCS (SPI, I2C, etc.) using the Device Tree.
+ *
+ * Returns pointer to mipi_dsi_host if successful, -EINVAL if the
+ * request is unsupported, -EPROBE_DEFER if the DSI host is found but
+ * not available, or -ENODEV otherwise.
+ */
+struct mipi_dsi_host *drm_of_get_dsi_bus(struct device *dev,
+					 struct mipi_dsi_device_info *info)
+{
+	struct mipi_dsi_host *dsi_host;
+	struct device_node *endpoint, *dsi_host_node;
+
+	/*
+	 * Get first endpoint child from device.
+	 */
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (!endpoint)
+		return ERR_PTR(-ENODEV);
+
+	/*
+	 * Follow the first endpoint to get the DSI host node.
+	 */
+	dsi_host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!dsi_host_node)
+		goto error;
+
+	/*
+	 * Get the DSI host from the DSI host node. If we get an error
+	 * or the return is null assume we're not ready to probe just
+	 * yet. Release the DSI host node since we're done with it.
+	 */
+	dsi_host = of_find_mipi_dsi_host_by_node(dsi_host_node);
+	of_node_put(dsi_host_node);
+	if (IS_ERR_OR_NULL(dsi_host)) {
+		of_node_put(endpoint);

drivers/gpu/drm/drm_of.c int drm_of_get_data_lanes_count_ep(const struct device_node *port, · line 551

Quoted 10 lines
drivers/gpu/drm/drm_of.c +10 -0
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	/*
+	 * Set the node of the mipi_dsi_device_info to the correct node
+	 * and then release the endpoint node since we're done with it.
+	 * since this is optional, check if the info is NULL first.
+	 */
+	if (info) {
+		info->node = of_graph_get_remote_port(endpoint);

it looks to me that the info->node is actually the DSI device OF node, not its host port. Which begs the question, why should we even return it there, since there's a pretty big chance that dev->of.node == info->node, and you obviously don't care about the channel and type fields.

Quoted 7 lines
Quoted 5 lines

I've had a look and node of the current users of mipi_dsi_device_register_full actually register a mipi_dsi_device_info with a node pointer set to !NULL, including the driver in this series.

So, why do we care about the device info at all?

I honestly thought it might be useful, but I can try without it.

It might tbh, but it doesn't look like you use it in your driver. You have:

struct mipi_dsi_device_info info = {
	.type = "d53e6ea8966",
	.channel = 0,
	.node = NULL,
};

...

// info.node is NULL so far
dsi_host = drm_of_get_dsi_bus(dev, &info);

...

// info.node has been filled to the port node by drm_of_get_dsi_bus() db->dsi_dev = devm_mipi_dsi_device_register_full(dev, dsi_host, &info);

// db->dsi_dev.dev.of_node is now set to the port node

But if we grep through drm_mipi_dsi.c, we can see that the of_node is only really useful if we're using of_find_mipi_dsi_device_by_node, and it looks like you don't.

So nothing uses info->node, which also explains why not reporting the proper node has been working.

Looking more into the code, it really looks to me that info->node should be equal to the your panel device tree node, that's what of_mipi_dsi_device_add does at least.

if info->node == dev->of_node, and if info->node is the only thing filled by drm_of_get_dsi_bus(), then it doesn't need to fill it at all because it's already accessible easily to the caller (and even more easily than to the callee).

So yeah, until we have a real-world need to retrieve the info function I think we should leave it aside for now, and we can always change the API later if we need to.

Maxime

#5 lore raw

PATCH v10 2/4 dt-bindings: display: panel: Add Samsung AMS495QA01

In reply to Chris Morgan

From: Chris Morgan <[email protected]>

Add documentation for Samsung AMS495QA01 panel (with Magnachip D53E6EA8966 controller IC).

---
 .../display/panel/samsung,ams495qa01.yaml     | 57 +++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/samsung,ams495qa01.yaml
Documentation/devicetree/bindings/display/panel/samsung,ams495qa01.yaml new file +57 -0
new file mode 100644
index 000000000000..58fa073ce258
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/samsung,ams495qa01.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung AMS495QA01 panel with Magnachip D53E6EA8966 controller
+
+maintainers:
+  - Chris Morgan <[email protected]>
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    const: samsung,ams495qa01
+
+  reg: true
+  reset-gpios:
+    description: reset gpio, must be GPIO_ACTIVE_LOW
+  elvdd-supply:
+    description: regulator that supplies voltage to the panel display
+  enable-gpios: true
+  port: true
+  vdd-supply:
+    description: regulator that supplies voltage to panel logic
+
+required:
+  - compatible
+  - reg
+  - reset-gpios
+  - vdd-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        panel@0 {
+            compatible = "samsung,ams495qa01";
+            reg = <0>;
+            reset-gpios = <&gpio4 0 GPIO_ACTIVE_LOW>;
+            vdd-supply = <&vcc_3v3>;
+
+            port {
+                mipi_in_panel: endpoint {
+                  remote-endpoint = <&mipi_out_panel>;
+                };
+            };
+        };
+    };
+
+...
Signature · 1 line
2.34.1
#6 lore raw

PATCH v10 3/4 drm/panel: Add Magnachip D53E6EA8966 Panel Driver

In reply to Chris Morgan

From: Chris Morgan <[email protected]>

Support Magnachip D53E6EA8966 based panels such as the Samsung AMS495QA01 panel as found on the Anbernic RG503. Note this driver supports only the AMS495QA01 today which receives video signals via DSI, however it receives commands via 3-wire SPI using DBI.

---
 drivers/gpu/drm/panel/Kconfig                 |  11 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-magnachip-d53e6ea8966.c   | 522 ++++++++++++++++++
 3 files changed, 534 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-magnachip-d53e6ea8966.c
drivers/gpu/drm/panel/Kconfig +11 -0
index 737edcdf9eef..204b84a83604 100644
@@ -298,6 +298,17 @@ 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_MAGNACHIP_D53E6EA8966
+	tristate "Magnachip D53E6EA8966 DSI panel"
+	depends on OF && SPI
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	select DRM_MIPI_DBI
+	help
+	  DRM panel driver for the Samsung AMS495QA01 panel controlled
+	  with the Magnachip D53E6EA8966 panel IC. This panel receives
+	  video data via DSI but commands via 9-bit SPI using DBI.
+
 config DRM_PANEL_NEC_NL8048HL11
 	tristate "NEC NL8048HL11 RGB panel"
 	depends on GPIOLIB && OF && SPI
drivers/gpu/drm/panel/Makefile +1 -0
index f8f9d9f6a307..20de312aa5e9 100644
@@ -27,6 +27,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
 obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
 obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
 obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
+obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
 obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
 obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o
 obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3052C) += panel-newvision-nv3052c.o
drivers/gpu/drm/panel/panel-magnachip-d53e6ea8966.c new file +522 -0

522 lines not on this page · raw message

Signature · 1 line
2.34.1
#7 lore raw

PATCH v10 4/4 arm64: dts: rockchip: add display to RG503

In reply to Chris Morgan

From: Chris Morgan <[email protected]>

Add Samsung AMS495QA01 panel to RG503.

---
 .../dts/rockchip/rk3566-anbernic-rg503.dts    | 55 +++++++++++++++++++
 1 file changed, 55 insertions(+)
arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts +55 -0
index 5dafcc86296b..b4b2df821cba 100644
@@ -47,6 +47,21 @@ gpio_spi: spi {
 		mosi-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>;
 		cs-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>;
 		num-chipselects = <0>;
+
+		panel@0 {
+			compatible = "samsung,ams495qa01";
+			reg = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&lcd_reset>;
+			reset-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>;
+			vdd-supply = <&vcc_3v3>;
+
+			port {
+				mipi_in_panel: endpoint {
+					remote-endpoint = <&mipi_out_panel>;
+				};
+			};
+		};
 	};
 
 	/* Channels reversed for both headphones and speakers. */
@@ -94,6 +109,32 @@ &cru {
 	assigned-clock-rates = <1200000000>, <200000000>, <500000000>;
 };
 
+&dsi_dphy0 {
+	status = "okay";
+};
+
+&dsi0 {
+	status = "okay";
+
+	ports {
+		dsi0_in: port@0 {
+			reg = <0>;
+
+			dsi0_in_vp1: endpoint {
+				remote-endpoint = <&vp1_out_dsi0>;
+			};
+		};
+
+		dsi0_out: port@1 {
+			reg = <1>;
+
+			mipi_out_panel: endpoint {
+				remote-endpoint = <&mipi_in_panel>;
+			};
+		};
+	};
+};
+
 &gpio_keys_control {
 	button-a {
 		gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
@@ -146,6 +187,13 @@ spk_amp_enable_h: spk-amp-enable-h {
 		};
 	};
 
+	gpio-lcd {
+		lcd_reset: lcd-reset {
+			rockchip,pins =
+				<4 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
 	gpio-spi {
 		spi_pins: spi-pins {
 			rockchip,pins =
@@ -164,3 +212,10 @@ rk817_charger: charger {
 		rockchip,sleep-filter-current-microamp = <100000>;
 	};
 };
+
+&vp1 {
+	vp1_out_dsi0: endpoint@ROCKCHIP_VOP2_EP_MIPI0 {
+		reg = <ROCKCHIP_VOP2_EP_MIPI0>;
+		remote-endpoint = <&dsi0_in_vp1>;
+	};
+};
Signature · 1 line
2.34.1