]> git.itanic.dy.fi Git - linux-stable/commitdiff
drm: renesas: shmobile: Add DT support
authorGeert Uytterhoeven <geert+renesas@glider.be>
Fri, 15 Sep 2023 08:53:56 +0000 (10:53 +0200)
committerGeert Uytterhoeven <geert+renesas@glider.be>
Mon, 16 Oct 2023 09:47:48 +0000 (11:47 +0200)
Add DT support, by:
  1. Creating a panel bridge from DT, and attaching it to the encoder,
  2. Replacing the custom connector with a bridge connector,
  3. Obtaining clock configuration based on the compatible value.

Note that for now the driver uses a fixed clock configuration selecting
the bus clock, as the current code to select other clock inputs needs
changes to support any other SoCs than SH7724.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/r/6185ab76aa300fa402e4f6610b2109665f2d8a1c.1694767209.git.geert+renesas@glider.be
drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c
drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.h
drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c
drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h

index 729028a15efae00c1616733f84e0b33222f12abb..2e2f37b9d0a4bafae4b5cc857baccf0e3d8fc724 100644 (file)
@@ -9,12 +9,16 @@
 
 #include <linux/clk.h>
 #include <linux/media-bus-format.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
 #include <linux/pm_runtime.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_atomic_uapi.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_dma_helper.h>
@@ -23,6 +27,7 @@
 #include <drm/drm_gem_dma_helper.h>
 #include <drm/drm_modeset_helper.h>
 #include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_panel.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
 #include <drm/drm_vblank.h>
 #include "shmob_drm_plane.h"
 #include "shmob_drm_regs.h"
 
-/*
- * TODO: panel support
- */
-
 /* -----------------------------------------------------------------------------
  * Page Flip
  */
@@ -201,7 +202,7 @@ static void shmob_drm_crtc_atomic_enable(struct drm_crtc *crtc,
 {
        struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
        struct shmob_drm_device *sdev = to_shmob_device(crtc->dev);
-       const struct shmob_drm_interface_data *idata = &sdev->pdata->iface;
+       unsigned int clk_div = sdev->config.clk_div;
        struct device *dev = sdev->dev;
        u32 value;
        int ret;
@@ -223,17 +224,17 @@ static void shmob_drm_crtc_atomic_enable(struct drm_crtc *crtc,
        lcdc_write(sdev, LDPMR, 0);
 
        value = sdev->lddckr;
-       if (idata->clk_div) {
+       if (clk_div) {
                /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
                 * denominator.
                 */
                lcdc_write(sdev, LDDCKPAT1R, 0);
-               lcdc_write(sdev, LDDCKPAT2R, (1 << (idata->clk_div / 2)) - 1);
+               lcdc_write(sdev, LDDCKPAT2R, (1 << (clk_div / 2)) - 1);
 
-               if (idata->clk_div == 1)
+               if (clk_div == 1)
                        value |= LDDCKR_MOSEL;
                else
-                       value |= idata->clk_div;
+                       value |= clk_div;
        }
 
        lcdc_write(sdev, LDDCKR, value);
@@ -406,7 +407,7 @@ int shmob_drm_crtc_create(struct shmob_drm_device *sdev)
 }
 
 /* -----------------------------------------------------------------------------
- * Encoder
+ * Legacy Encoder
  */
 
 static bool shmob_drm_encoder_mode_fixup(struct drm_encoder *encoder,
@@ -435,9 +436,14 @@ static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
        .mode_fixup = shmob_drm_encoder_mode_fixup,
 };
 
+/* -----------------------------------------------------------------------------
+ * Encoder
+ */
+
 int shmob_drm_encoder_create(struct shmob_drm_device *sdev)
 {
        struct drm_encoder *encoder = &sdev->encoder;
+       struct drm_bridge *bridge;
        int ret;
 
        encoder->possible_crtcs = 1;
@@ -447,13 +453,30 @@ int shmob_drm_encoder_create(struct shmob_drm_device *sdev)
        if (ret < 0)
                return ret;
 
-       drm_encoder_helper_add(encoder, &encoder_helper_funcs);
+       if (sdev->pdata) {
+               drm_encoder_helper_add(encoder, &encoder_helper_funcs);
+               return 0;
+       }
+
+       /* Create a panel bridge */
+       bridge = devm_drm_of_get_bridge(sdev->dev, sdev->dev->of_node, 0, 0);
+       if (IS_ERR(bridge))
+               return PTR_ERR(bridge);
+
+       /* Attach the bridge to the encoder */
+       ret = drm_bridge_attach(encoder, bridge, NULL,
+                               DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+       if (ret) {
+               dev_err(sdev->dev, "failed to attach bridge: %pe\n",
+                       ERR_PTR(ret));
+               return ret;
+       }
 
        return 0;
 }
 
 /* -----------------------------------------------------------------------------
- * Connector
+ * Legacy Connector
  */
 
 static inline struct shmob_drm_connector *to_shmob_connector(struct drm_connector *connector)
@@ -563,13 +586,20 @@ shmob_drm_connector_init(struct shmob_drm_device *sdev,
        return connector;
 }
 
+/* -----------------------------------------------------------------------------
+ * Connector
+ */
+
 int shmob_drm_connector_create(struct shmob_drm_device *sdev,
                               struct drm_encoder *encoder)
 {
        struct drm_connector *connector;
        int ret;
 
-       connector = shmob_drm_connector_init(sdev, encoder);
+       if (sdev->pdata)
+               connector = shmob_drm_connector_init(sdev, encoder);
+       else
+               connector = drm_bridge_connector_init(&sdev->ddev, encoder);
        if (IS_ERR(connector)) {
                dev_err(sdev->dev, "failed to created connector: %pe\n",
                        connector);
index 89a0746f9a35807df647ac45ec08f036089b764e..16e1712dd04e0f2baf411de41cafb90d58af2418 100644 (file)
@@ -29,6 +29,7 @@ struct shmob_drm_crtc {
        wait_queue_head_t flip_wait;
 };
 
+/* Legacy connector */
 struct shmob_drm_connector {
        struct drm_connector base;
        struct drm_encoder *encoder;
index c498d0d9b4fc4fc5565fabf7a6061fa08e81110c..e83c3e52251dedf9843685484beb7a29d2408fdd 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
@@ -173,11 +174,13 @@ static void shmob_drm_remove(struct platform_device *pdev)
 static int shmob_drm_probe(struct platform_device *pdev)
 {
        struct shmob_drm_platform_data *pdata = pdev->dev.platform_data;
+       const struct shmob_drm_config *config;
        struct shmob_drm_device *sdev;
        struct drm_device *ddev;
        int ret;
 
-       if (pdata == NULL) {
+       config = of_device_get_match_data(&pdev->dev);
+       if (!config && !pdata) {
                dev_err(&pdev->dev, "no platform data\n");
                return -EINVAL;
        }
@@ -193,7 +196,13 @@ static int shmob_drm_probe(struct platform_device *pdev)
 
        ddev = &sdev->ddev;
        sdev->dev = &pdev->dev;
-       sdev->pdata = pdata;
+       if (config) {
+               sdev->config = *config;
+       } else {
+               sdev->pdata = pdata;
+               sdev->config.clk_source = pdata->clk_source;
+               sdev->config.clk_div = pdata->iface.clk_div;
+       }
        spin_lock_init(&sdev->irq_lock);
 
        platform_set_drvdata(pdev, sdev);
@@ -202,7 +211,7 @@ static int shmob_drm_probe(struct platform_device *pdev)
        if (IS_ERR(sdev->mmio))
                return PTR_ERR(sdev->mmio);
 
-       ret = shmob_drm_setup_clocks(sdev, pdata->clk_source);
+       ret = shmob_drm_setup_clocks(sdev, sdev->config.clk_source);
        if (ret < 0)
                return ret;
 
@@ -250,11 +259,23 @@ static int shmob_drm_probe(struct platform_device *pdev)
        return ret;
 }
 
+static const struct shmob_drm_config shmob_arm_config = {
+       .clk_source = SHMOB_DRM_CLK_BUS,
+       .clk_div = 5,
+};
+
+static const struct of_device_id shmob_drm_of_table[] __maybe_unused = {
+       { .compatible = "renesas,r8a7740-lcdc", .data = &shmob_arm_config, },
+       { .compatible = "renesas,sh73a0-lcdc",  .data = &shmob_arm_config, },
+       { /* sentinel */ }
+};
+
 static struct platform_driver shmob_drm_platform_driver = {
        .probe          = shmob_drm_probe,
        .remove_new     = shmob_drm_remove,
        .driver         = {
                .name   = "shmob-drm",
+               .of_match_table = of_match_ptr(shmob_drm_of_table),
                .pm     = &shmob_drm_pm_ops,
        },
 };
index 18907e5ace51c681a62a04c62c7e8dbd2345ecfe..088ac5381e91e61a8196f2c3d2fb609e4abc4dac 100644 (file)
@@ -20,9 +20,15 @@ struct clk;
 struct device;
 struct drm_device;
 
+struct shmob_drm_config {
+       enum shmob_drm_clk_source clk_source;
+       unsigned int clk_div;
+};
+
 struct shmob_drm_device {
        struct device *dev;
        const struct shmob_drm_platform_data *pdata;
+       struct shmob_drm_config config;
 
        void __iomem *mmio;
        struct clk *clock;