drm/msm: DT support for 8960/8064 (v3)
authorRob Clark <robdclark@gmail.com>
Sun, 15 Dec 2013 21:23:05 +0000 (16:23 -0500)
committerRob Clark <robdclark@gmail.com>
Mon, 4 Aug 2014 15:55:28 +0000 (11:55 -0400)
Now that we (almost) have enough dependencies in place (MMCC, RPM, etc),
add necessary DT support so that we can use drm/msm on upstream kernel.

v2: update for review comments
v3: rebase on component helper changes

Signed-off-by: Rob Clark <robdclark@gmail.com>
Documentation/devicetree/bindings/drm/msm/gpu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/drm/msm/hdmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/drm/msm/mdp.txt [new file with mode: 0644]
drivers/gpu/drm/msm/adreno/a3xx_gpu.c
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/msm_drv.c

diff --git a/Documentation/devicetree/bindings/drm/msm/gpu.txt b/Documentation/devicetree/bindings/drm/msm/gpu.txt
new file mode 100644 (file)
index 0000000..67d0a58
--- /dev/null
@@ -0,0 +1,52 @@
+Qualcomm adreno/snapdragon GPU
+
+Required properties:
+- compatible: "qcom,adreno-3xx"
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The interrupt signal from the gpu.
+- clocks: device clocks
+  See ../clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+  * "core_clk"
+  * "iface_clk"
+  * "mem_iface_clk"
+- qcom,chipid: gpu chip-id.  Note this may become optional for future
+  devices if we can reliably read the chipid from hw
+- qcom,gpu-pwrlevels: list of operating points
+  - compatible: "qcom,gpu-pwrlevels"
+  - for each qcom,gpu-pwrlevel:
+    - qcom,gpu-freq: requested gpu clock speed
+    - NOTE: downstream android driver defines additional parameters to
+      configure memory bandwidth scaling per OPP.
+
+Example:
+
+/ {
+       ...
+
+       gpu: qcom,kgsl-3d0@4300000 {
+               compatible = "qcom,adreno-3xx";
+               reg = <0x04300000 0x20000>;
+               reg-names = "kgsl_3d0_reg_memory";
+               interrupts = <GIC_SPI 80 0>;
+               interrupt-names = "kgsl_3d0_irq";
+               clock-names =
+                   "core_clk",
+                   "iface_clk",
+                   "mem_iface_clk";
+               clocks =
+                   <&mmcc GFX3D_CLK>,
+                   <&mmcc GFX3D_AHB_CLK>,
+                   <&mmcc MMSS_IMEM_AHB_CLK>;
+               qcom,chipid = <0x03020100>;
+               qcom,gpu-pwrlevels {
+                       compatible = "qcom,gpu-pwrlevels";
+                       qcom,gpu-pwrlevel@0 {
+                               qcom,gpu-freq = <450000000>;
+                       };
+                       qcom,gpu-pwrlevel@1 {
+                               qcom,gpu-freq = <27000000>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/drm/msm/hdmi.txt b/Documentation/devicetree/bindings/drm/msm/hdmi.txt
new file mode 100644 (file)
index 0000000..aca917f
--- /dev/null
@@ -0,0 +1,46 @@
+Qualcomm adreno/snapdragon hdmi output
+
+Required properties:
+- compatible: one of the following
+   * "qcom,hdmi-tx-8660"
+   * "qcom,hdmi-tx-8960"
+- reg: Physical base address and length of the controller's registers
+- reg-names: "core_physical"
+- interrupts: The interrupt signal from the hdmi block.
+- clocks: device clocks
+  See ../clocks/clock-bindings.txt for details.
+- qcom,hdmi-tx-ddc-clk-gpio: ddc clk pin
+- qcom,hdmi-tx-ddc-data-gpio: ddc data pin
+- qcom,hdmi-tx-hpd-gpio: hpd pin
+- core-vdda-supply: phandle to supply regulator
+- hdmi-mux-supply: phandle to mux regulator
+
+Optional properties:
+- qcom,hdmi-tx-mux-en-gpio: hdmi mux enable pin
+- qcom,hdmi-tx-mux-sel-gpio: hdmi mux select pin
+
+Example:
+
+/ {
+       ...
+
+       hdmi: qcom,hdmi-tx-8960@4a00000 {
+               compatible = "qcom,hdmi-tx-8960";
+               reg-names = "core_physical";
+               reg = <0x04a00000 0x1000>;
+               interrupts = <GIC_SPI 79 0>;
+               clock-names =
+                   "core_clk",
+                   "master_iface_clk",
+                   "slave_iface_clk";
+               clocks =
+                   <&mmcc HDMI_APP_CLK>,
+                   <&mmcc HDMI_M_AHB_CLK>,
+                   <&mmcc HDMI_S_AHB_CLK>;
+               qcom,hdmi-tx-ddc-clk = <&msmgpio 70 GPIO_ACTIVE_HIGH>;
+               qcom,hdmi-tx-ddc-data = <&msmgpio 71 GPIO_ACTIVE_HIGH>;
+               qcom,hdmi-tx-hpd = <&msmgpio 72 GPIO_ACTIVE_HIGH>;
+               core-vdda-supply = <&pm8921_hdmi_mvs>;
+               hdmi-mux-supply = <&ext_3p3v>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/drm/msm/mdp.txt b/Documentation/devicetree/bindings/drm/msm/mdp.txt
new file mode 100644 (file)
index 0000000..1a0598e
--- /dev/null
@@ -0,0 +1,48 @@
+Qualcomm adreno/snapdragon display controller
+
+Required properties:
+- compatible:
+  * "qcom,mdp" - mdp4
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The interrupt signal from the display controller.
+- connectors: array of phandles for output device(s)
+- clocks: device clocks
+  See ../clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+  * "core_clk"
+  * "iface_clk"
+  * "lut_clk"
+  * "src_clk"
+  * "hdmi_clk"
+  * "mpd_clk"
+
+Optional properties:
+- gpus: phandle for gpu device
+
+Example:
+
+/ {
+       ...
+
+       mdp: qcom,mdp@5100000 {
+               compatible = "qcom,mdp";
+               reg = <0x05100000 0xf0000>;
+               interrupts = <GIC_SPI 75 0>;
+               connectors = <&hdmi>;
+               gpus = <&gpu>;
+               clock-names =
+                   "core_clk",
+                   "iface_clk",
+                   "lut_clk",
+                   "src_clk",
+                   "hdmi_clk",
+                   "mdp_clk";
+               clocks =
+                   <&mmcc MDP_SRC>,
+                   <&mmcc MDP_AHB_CLK>,
+                   <&mmcc MDP_LUT_CLK>,
+                   <&mmcc TV_SRC>,
+                   <&mmcc HDMI_TV_CLK>,
+                   <&mmcc MDP_TV_CLK>;
+       };
+};
index a2cee0645336dacda616d6d6f31c6b22be19d10a..2773600c94888c180c76100dd1848ad395bc596a 100644 (file)
@@ -680,6 +680,8 @@ static int a3xx_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id dt_match[] = {
+       { .compatible = "qcom,adreno-3xx" },
+       /* for backwards compat w/ downstream kgsl DT files: */
        { .compatible = "qcom,kgsl-3d0" },
        {}
 };
index 7f7aadef8a8258101a63e57a14ed09b7ecc09893..041c2fca2225d7e8a899d90f8123aebba9fdb0d5 100644 (file)
@@ -123,7 +123,8 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
        for (i = 0; i < config->hpd_reg_cnt; i++) {
                struct regulator *reg;
 
-               reg = devm_regulator_get(&pdev->dev, config->hpd_reg_names[i]);
+               reg = devm_regulator_get_exclusive(&pdev->dev,
+                               config->hpd_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
                        dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n",
@@ -138,7 +139,8 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
        for (i = 0; i < config->pwr_reg_cnt; i++) {
                struct regulator *reg;
 
-               reg = devm_regulator_get(&pdev->dev, config->pwr_reg_names[i]);
+               reg = devm_regulator_get_exclusive(&pdev->dev,
+                               config->pwr_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
                        dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n",
@@ -266,37 +268,55 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
        {
                int gpio = of_get_named_gpio(of_node, name, 0);
                if (gpio < 0) {
-                       dev_err(dev, "failed to get gpio: %s (%d)\n",
-                                       name, gpio);
-                       gpio = -1;
+                       char name2[32];
+                       snprintf(name2, sizeof(name2), "%s-gpio", name);
+                       gpio = of_get_named_gpio(of_node, name2, 0);
+                       if (gpio < 0) {
+                               dev_err(dev, "failed to get gpio: %s (%d)\n",
+                                               name, gpio);
+                               gpio = -1;
+                       }
                }
                return gpio;
        }
 
-       /* TODO actually use DT.. */
-       static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"};
-       static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"};
-       static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"};
-       static unsigned long hpd_clk_freq[] = {0, 19200000, 0};
-       static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"};
+       if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8074")) {
+               static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"};
+               static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"};
+               static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"};
+               static unsigned long hpd_clk_freq[] = {0, 19200000, 0};
+               static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"};
+               config.phy_init      = hdmi_phy_8x74_init;
+               config.hpd_reg_names = hpd_reg_names;
+               config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
+               config.pwr_reg_names = pwr_reg_names;
+               config.pwr_reg_cnt   = ARRAY_SIZE(pwr_reg_names);
+               config.hpd_clk_names = hpd_clk_names;
+               config.hpd_freq      = hpd_clk_freq;
+               config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
+               config.pwr_clk_names = pwr_clk_names;
+               config.pwr_clk_cnt   = ARRAY_SIZE(pwr_clk_names);
+               config.shared_irq    = true;
+       } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8960")) {
+               static const char *hpd_clk_names[] = {"core_clk", "master_iface_clk", "slave_iface_clk"};
+               static const char *hpd_reg_names[] = {"core-vdda", "hdmi-mux"};
+               config.phy_init      = hdmi_phy_8960_init;
+               config.hpd_reg_names = hpd_reg_names;
+               config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
+               config.hpd_clk_names = hpd_clk_names;
+               config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
+       } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8660")) {
+               config.phy_init      = hdmi_phy_8x60_init;
+       } else {
+               dev_err(dev, "unknown phy: %s\n", of_node->name);
+       }
 
-       config.phy_init      = hdmi_phy_8x74_init;
        config.mmio_name     = "core_physical";
-       config.hpd_reg_names = hpd_reg_names;
-       config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
-       config.pwr_reg_names = pwr_reg_names;
-       config.pwr_reg_cnt   = ARRAY_SIZE(pwr_reg_names);
-       config.hpd_clk_names = hpd_clk_names;
-       config.hpd_freq      = hpd_clk_freq;
-       config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
-       config.pwr_clk_names = pwr_clk_names;
-       config.pwr_clk_cnt   = ARRAY_SIZE(pwr_clk_names);
        config.ddc_clk_gpio  = get_gpio("qcom,hdmi-tx-ddc-clk");
        config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data");
        config.hpd_gpio      = get_gpio("qcom,hdmi-tx-hpd");
        config.mux_en_gpio   = get_gpio("qcom,hdmi-tx-mux-en");
        config.mux_sel_gpio  = get_gpio("qcom,hdmi-tx-mux-sel");
-       config.shared_irq    = true;
 
 #else
        static const char *hpd_clk_names[] = {
@@ -373,7 +393,9 @@ static int hdmi_dev_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id dt_match[] = {
-       { .compatible = "qcom,hdmi-tx" },
+       { .compatible = "qcom,hdmi-tx-8074" },
+       { .compatible = "qcom,hdmi-tx-8960" },
+       { .compatible = "qcom,hdmi-tx-8660" },
        {}
 };
 
index 0bb4faa17523e0862d7f32df0939976424e82d6a..5a7bfd452252e5e76ef91446d4f814141fd6ab21 100644 (file)
@@ -294,15 +294,17 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
                goto fail;
        }
 
-       mdp4_kms->dsi_pll_vdda = devm_regulator_get(&pdev->dev, "dsi_pll_vdda");
+       mdp4_kms->dsi_pll_vdda =
+                       devm_regulator_get_optional(&pdev->dev, "dsi_pll_vdda");
        if (IS_ERR(mdp4_kms->dsi_pll_vdda))
                mdp4_kms->dsi_pll_vdda = NULL;
 
-       mdp4_kms->dsi_pll_vddio = devm_regulator_get(&pdev->dev, "dsi_pll_vddio");
+       mdp4_kms->dsi_pll_vddio =
+                       devm_regulator_get_optional(&pdev->dev, "dsi_pll_vddio");
        if (IS_ERR(mdp4_kms->dsi_pll_vddio))
                mdp4_kms->dsi_pll_vddio = NULL;
 
-       mdp4_kms->vdd = devm_regulator_get(&pdev->dev, "vdd");
+       mdp4_kms->vdd = devm_regulator_get_exclusive(&pdev->dev, "vdd");
        if (IS_ERR(mdp4_kms->vdd))
                mdp4_kms->vdd = NULL;
 
@@ -406,6 +408,8 @@ static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev)
        static struct mdp4_platform_config config = {};
 #ifdef CONFIG_OF
        /* TODO */
+       config.max_clk = 266667000;
+       config.iommu = iommu_domain_alloc(&platform_bus_type);
 #else
        if (cpu_is_apq8064())
                config.max_clk = 266667000;
index a322029983ce14f21149b1c41bf92b51456cf5aa..a2f5bf6da6f3d10c07efc06afb825a040d4ea674 100644 (file)
@@ -905,6 +905,25 @@ static int compare_of(struct device *dev, void *data)
 {
        return dev->of_node == data;
 }
+
+static int add_components(struct device *dev, struct component_match **matchptr,
+               const char *name)
+{
+       struct device_node *np = dev->of_node;
+       unsigned i;
+
+       for (i = 0; ; i++) {
+               struct device_node *node;
+
+               node = of_parse_phandle(np, name, i);
+               if (!node)
+                       break;
+
+               component_match_add(dev, matchptr, compare_of, node);
+       }
+
+       return 0;
+}
 #else
 static int compare_dev(struct device *dev, void *data)
 {
@@ -935,21 +954,8 @@ static int msm_pdev_probe(struct platform_device *pdev)
 {
        struct component_match *match = NULL;
 #ifdef CONFIG_OF
-       /* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx
-        * (or probably any other).. so probably some room for some helpers
-        */
-       struct device_node *np = pdev->dev.of_node;
-       unsigned i;
-
-       for (i = 0; ; i++) {
-               struct device_node *node;
-
-               node = of_parse_phandle(np, "connectors", i);
-               if (!node)
-                       break;
-
-               component_match_add(&pdev->dev, &match, compare_of, node);
-       }
+       add_components(&pdev->dev, &match, "connectors");
+       add_components(&pdev->dev, &match, "gpus");
 #else
        /* For non-DT case, it kinda sucks.  We don't actually have a way
         * to know whether or not we are waiting for certain devices (or if
@@ -995,7 +1001,8 @@ static const struct platform_device_id msm_id[] = {
 };
 
 static const struct of_device_id dt_match[] = {
-       { .compatible = "qcom,mdss_mdp" },
+       { .compatible = "qcom,mdp" },      /* mdp4 */
+       { .compatible = "qcom,mdss_mdp" }, /* mdp5 */
        {}
 };
 MODULE_DEVICE_TABLE(of, dt_match);