This adds the plumbing for reading panel rotation from the devicetree
and sets up adding a panel property for the panel orientation on
Mediatek SoCs when a rotation is present.
Derek Basehore (5):
drm/panel: Add helper for reading DT rotation
dt-bindings: display/panel: Expand rotation documentation
drm/panel: Add attach/detach callbacks
drm/connector: Split out orientation quirk detection
drm/mtk: add panel orientation property
.../bindings/display/panel/panel.txt | 32 +++++++++++
drivers/gpu/drm/drm_connector.c | 16 ++----
drivers/gpu/drm/drm_panel.c | 55 +++++++++++++++++++
drivers/gpu/drm/i915/vlv_dsi.c | 13 +++--
drivers/gpu/drm/mediatek/mtk_dsi.c | 8 +++
include/drm/drm_connector.h | 2 +-
include/drm/drm_panel.h | 11 ++++
7 files changed, 120 insertions(+), 17 deletions(-)
--
2.22.0.rc2.383.gf4fbbf30c2-goog
This adds to the rotation documentation to explain how drivers should
use the property and gives an example of the property in a devicetree
node.
Signed-off-by: Derek Basehore <[email protected]>
---
.../bindings/display/panel/panel.txt | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/panel/panel.txt b/Documentation/devicetree/bindings/display/panel/panel.txt
index e2e6867852b8..f35d62d933fc 100644
--- a/Documentation/devicetree/bindings/display/panel/panel.txt
+++ b/Documentation/devicetree/bindings/display/panel/panel.txt
@@ -2,3 +2,35 @@ Common display properties
-------------------------
- rotation: Display rotation in degrees counter clockwise (0,90,180,270)
+
+Property read from the device tree using of of_drm_get_panel_orientation
+
+The panel driver may apply the rotation at the TCON level, which will
+make the panel look like it isn't rotated to the kernel and any other
+software.
+
+If not, a panel orientation property should be added through the SoC
+vendor DRM code using the drm_connector_init_panel_orientation_property
+function.
+
+Example:
+ panel: panel@0 {
+ compatible = "boe,himax8279d8p";
+ reg = <0>;
+ enable-gpios = <&pio 45 0>;
+ pp33-gpios = <&pio 35 0>;
+ pp18-gpios = <&pio 36 0>;
+ pinctrl-names = "default", "state_3300mv", "state_1800mv";
+ pinctrl-0 = <&panel_pins_default>;
+ pinctrl-1 = <&panel_pins_3300mv>;
+ pinctrl-2 = <&panel_pins_1800mv>;
+ backlight = <&backlight_lcd0>;
+ rotation = <180>;
+ status = "okay";
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+ };
--
2.22.0.rc2.383.gf4fbbf30c2-goog
This inits the panel orientation property for the mediatek dsi driver
if the panel orientation (connector.display_info.panel_orientation) is
not DRM_MODE_PANEL_ORIENTATION_UNKNOWN.
Signed-off-by: Derek Basehore <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dsi.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 4a0b9150a7bb..08ffdc7526dd 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -782,10 +782,18 @@ static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
DRM_ERROR("Failed to attach panel to drm\n");
goto err_connector_cleanup;
}
+
+ ret = drm_connector_init_panel_orientation_property(&dsi->conn);
+ if (ret) {
+ DRM_ERROR("Failed to init panel orientation\n");
+ goto err_panel_detach;
+ }
}
return 0;
+err_panel_detach:
+ drm_panel_detach(dsi->panel);
err_connector_cleanup:
drm_connector_cleanup(&dsi->conn);
return ret;
--
2.22.0.rc2.383.gf4fbbf30c2-goog
This adds a helper function for reading the rotation (panel
orientation) from the device tree.
Signed-off-by: Derek Basehore <[email protected]>
---
drivers/gpu/drm/drm_panel.c | 41 +++++++++++++++++++++++++++++++++++++
include/drm/drm_panel.h | 7 +++++++
2 files changed, 48 insertions(+)
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index dbd5b873e8f2..3b689ce4a51a 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -172,6 +172,47 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
return ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL(of_drm_find_panel);
+
+/**
+ * of_drm_get_panel_orientation - look up the rotation of the panel using a
+ * device tree node
+ * @np: device tree node of the panel
+ * @orientation: orientation enum to be filled in
+ *
+ * Looks up the rotation of a panel in the device tree. The rotation in the
+ * device tree is counter clockwise.
+ *
+ * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the
+ * rotation property doesn't exist. -EERROR otherwise.
+ */
+int of_drm_get_panel_orientation(const struct device_node *np, int *orientation)
+{
+ int rotation, ret;
+
+ ret = of_property_read_u32(np, "rotation", &rotation);
+ if (ret == -EINVAL) {
+ /* Don't return an error if there's no rotation property. */
+ *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+ return 0;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (rotation == 0)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
+ else if (rotation == 90)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
+ else if (rotation == 180)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
+ else if (rotation == 270)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL(of_drm_get_panel_orientation);
#endif
MODULE_AUTHOR("Thierry Reding <[email protected]>");
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 8c738c0e6e9f..13631b2efbaa 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -197,11 +197,18 @@ int drm_panel_detach(struct drm_panel *panel);
#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL)
struct drm_panel *of_drm_find_panel(const struct device_node *np);
+int of_drm_get_panel_orientation(const struct device_node *np,
+ int *orientation);
#else
static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
{
return ERR_PTR(-ENODEV);
}
+int of_drm_get_panel_orientation(const struct device_node *np,
+ int *orientation)
+{
+ return -ENODEV;
+}
#endif
#endif
--
2.22.0.rc2.383.gf4fbbf30c2-goog
This removes the orientation quirk detection from the code to add
an orientation property to a panel. This is used only for legacy x86
systems, yet we'd like to start using this on device tree systems
where quirk detection like this is not needed.
Signed-off-by: Derek Basehore <[email protected]>
---
drivers/gpu/drm/drm_connector.c | 16 ++++------------
drivers/gpu/drm/i915/vlv_dsi.c | 13 +++++++++----
include/drm/drm_connector.h | 2 +-
3 files changed, 14 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index e17586aaa80f..58a09b65028b 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1894,31 +1894,23 @@ EXPORT_SYMBOL(drm_connector_set_vrr_capable_property);
* drm_connector_init_panel_orientation_property -
* initialize the connecters panel_orientation property
* @connector: connector for which to init the panel-orientation property.
- * @width: width in pixels of the panel, used for panel quirk detection
- * @height: height in pixels of the panel, used for panel quirk detection
*
* This function should only be called for built-in panels, after setting
* connector->display_info.panel_orientation first (if known).
*
- * This function will check for platform specific (e.g. DMI based) quirks
- * overriding display_info.panel_orientation first, then if panel_orientation
- * is not DRM_MODE_PANEL_ORIENTATION_UNKNOWN it will attach the
- * "panel orientation" property to the connector.
+ * This function will check if the panel_orientation is not
+ * DRM_MODE_PANEL_ORIENTATION_UNKNOWN. If not, it will attach the "panel
+ * orientation" property to the connector.
*
* Returns:
* Zero on success, negative errno on failure.
*/
int drm_connector_init_panel_orientation_property(
- struct drm_connector *connector, int width, int height)
+ struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_display_info *info = &connector->display_info;
struct drm_property *prop;
- int orientation_quirk;
-
- orientation_quirk = drm_get_panel_orientation_quirk(width, height);
- if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
- info->panel_orientation = orientation_quirk;
if (info->panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
return 0;
diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c
index bfe2891eac37..113129996530 100644
--- a/drivers/gpu/drm/i915/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/vlv_dsi.c
@@ -1650,6 +1650,7 @@ static void intel_dsi_add_properties(struct intel_connector *connector)
if (connector->panel.fixed_mode) {
u32 allowed_scalers;
+ int orientation;
allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
if (!HAS_GMCH(dev_priv))
@@ -1660,12 +1661,16 @@ static void intel_dsi_add_properties(struct intel_connector *connector)
connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
- connector->base.display_info.panel_orientation =
- vlv_dsi_get_panel_orientation(connector);
- drm_connector_init_panel_orientation_property(
- &connector->base,
+ orientation = drm_get_panel_orientation_quirk(
connector->panel.fixed_mode->hdisplay,
connector->panel.fixed_mode->vdisplay);
+ if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+ connector->display_info.panel_orientation = orientation;
+ else
+ connector->display_info.panel_orientation =
+ intel_dsi_get_panel_orientation(connector);
+
+ drm_connector_init_panel_orientation_property(&connector->base);
}
}
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 47e749b74e5f..c2992f7a0dd5 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1370,7 +1370,7 @@ void drm_connector_set_link_status_property(struct drm_connector *connector,
void drm_connector_set_vrr_capable_property(
struct drm_connector *connector, bool capable);
int drm_connector_init_panel_orientation_property(
- struct drm_connector *connector, int width, int height);
+ struct drm_connector *connector);
int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
int min, int max);
--
2.22.0.rc2.383.gf4fbbf30c2-goog
This adds the attach/detach callbacks. These are for setting up
internal state for the connector/panel pair that can't be done at
probe (since the connector doesn't exist) and which don't need to be
repeatedly done for every get/modes, prepare, or enable callback.
Values such as the panel orientation, and display size can be filled
in for the connector.
Signed-off-by: Derek Basehore <[email protected]>
---
drivers/gpu/drm/drm_panel.c | 14 ++++++++++++++
include/drm/drm_panel.h | 4 ++++
2 files changed, 18 insertions(+)
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index 3b689ce4a51a..72f67678d9d5 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -104,12 +104,23 @@ EXPORT_SYMBOL(drm_panel_remove);
*/
int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector)
{
+ int ret;
+
if (panel->connector)
return -EBUSY;
panel->connector = connector;
panel->drm = connector->dev;
+ if (panel->funcs->attach) {
+ ret = panel->funcs->attach(panel);
+ if (ret < 0) {
+ panel->connector = NULL;
+ panel->drm = NULL;
+ return ret;
+ }
+ }
+
return 0;
}
EXPORT_SYMBOL(drm_panel_attach);
@@ -128,6 +139,9 @@ EXPORT_SYMBOL(drm_panel_attach);
*/
int drm_panel_detach(struct drm_panel *panel)
{
+ if (panel->funcs->detach)
+ panel->funcs->detach(panel);
+
panel->connector = NULL;
panel->drm = NULL;
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 13631b2efbaa..e136e3a3c996 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -37,6 +37,8 @@ struct display_timing;
* struct drm_panel_funcs - perform operations on a given panel
* @disable: disable panel (turn off back light, etc.)
* @unprepare: turn off panel
+ * @detach: detach panel->connector (clear internal state, etc.)
+ * @attach: attach panel->connector (update internal state, etc.)
* @prepare: turn on panel and perform set up
* @enable: enable panel (turn on back light, etc.)
* @get_modes: add modes to the connector that the panel is attached to and
@@ -70,6 +72,8 @@ struct display_timing;
struct drm_panel_funcs {
int (*disable)(struct drm_panel *panel);
int (*unprepare)(struct drm_panel *panel);
+ void (*detach)(struct drm_panel *panel);
+ int (*attach)(struct drm_panel *panel);
int (*prepare)(struct drm_panel *panel);
int (*enable)(struct drm_panel *panel);
int (*get_modes)(struct drm_panel *panel);
--
2.22.0.rc2.383.gf4fbbf30c2-goog
Hi, Derek:
On Mon, 2019-06-10 at 17:22 -0700, Derek Basehore wrote:
> This inits the panel orientation property for the mediatek dsi driver
> if the panel orientation (connector.display_info.panel_orientation) is
> not DRM_MODE_PANEL_ORIENTATION_UNKNOWN.
>
Looks good to me,
Acked-by: CK Hu <[email protected]>
> Signed-off-by: Derek Basehore <[email protected]>
> ---
> drivers/gpu/drm/mediatek/mtk_dsi.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 4a0b9150a7bb..08ffdc7526dd 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -782,10 +782,18 @@ static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
> DRM_ERROR("Failed to attach panel to drm\n");
> goto err_connector_cleanup;
> }
> +
> + ret = drm_connector_init_panel_orientation_property(&dsi->conn);
> + if (ret) {
> + DRM_ERROR("Failed to init panel orientation\n");
> + goto err_panel_detach;
> + }
> }
>
> return 0;
>
> +err_panel_detach:
> + drm_panel_detach(dsi->panel);
> err_connector_cleanup:
> drm_connector_cleanup(&dsi->conn);
> return ret;