Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm: DT support for 8960/8064 (v3)

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>

Rob Clark 41e69778 8f67da33

+223 -42
+52
Documentation/devicetree/bindings/drm/msm/gpu.txt
··· 1 + Qualcomm adreno/snapdragon GPU 2 + 3 + Required properties: 4 + - compatible: "qcom,adreno-3xx" 5 + - reg: Physical base address and length of the controller's registers. 6 + - interrupts: The interrupt signal from the gpu. 7 + - clocks: device clocks 8 + See ../clocks/clock-bindings.txt for details. 9 + - clock-names: the following clocks are required: 10 + * "core_clk" 11 + * "iface_clk" 12 + * "mem_iface_clk" 13 + - qcom,chipid: gpu chip-id. Note this may become optional for future 14 + devices if we can reliably read the chipid from hw 15 + - qcom,gpu-pwrlevels: list of operating points 16 + - compatible: "qcom,gpu-pwrlevels" 17 + - for each qcom,gpu-pwrlevel: 18 + - qcom,gpu-freq: requested gpu clock speed 19 + - NOTE: downstream android driver defines additional parameters to 20 + configure memory bandwidth scaling per OPP. 21 + 22 + Example: 23 + 24 + / { 25 + ... 26 + 27 + gpu: qcom,kgsl-3d0@4300000 { 28 + compatible = "qcom,adreno-3xx"; 29 + reg = <0x04300000 0x20000>; 30 + reg-names = "kgsl_3d0_reg_memory"; 31 + interrupts = <GIC_SPI 80 0>; 32 + interrupt-names = "kgsl_3d0_irq"; 33 + clock-names = 34 + "core_clk", 35 + "iface_clk", 36 + "mem_iface_clk"; 37 + clocks = 38 + <&mmcc GFX3D_CLK>, 39 + <&mmcc GFX3D_AHB_CLK>, 40 + <&mmcc MMSS_IMEM_AHB_CLK>; 41 + qcom,chipid = <0x03020100>; 42 + qcom,gpu-pwrlevels { 43 + compatible = "qcom,gpu-pwrlevels"; 44 + qcom,gpu-pwrlevel@0 { 45 + qcom,gpu-freq = <450000000>; 46 + }; 47 + qcom,gpu-pwrlevel@1 { 48 + qcom,gpu-freq = <27000000>; 49 + }; 50 + }; 51 + }; 52 + };
+46
Documentation/devicetree/bindings/drm/msm/hdmi.txt
··· 1 + Qualcomm adreno/snapdragon hdmi output 2 + 3 + Required properties: 4 + - compatible: one of the following 5 + * "qcom,hdmi-tx-8660" 6 + * "qcom,hdmi-tx-8960" 7 + - reg: Physical base address and length of the controller's registers 8 + - reg-names: "core_physical" 9 + - interrupts: The interrupt signal from the hdmi block. 10 + - clocks: device clocks 11 + See ../clocks/clock-bindings.txt for details. 12 + - qcom,hdmi-tx-ddc-clk-gpio: ddc clk pin 13 + - qcom,hdmi-tx-ddc-data-gpio: ddc data pin 14 + - qcom,hdmi-tx-hpd-gpio: hpd pin 15 + - core-vdda-supply: phandle to supply regulator 16 + - hdmi-mux-supply: phandle to mux regulator 17 + 18 + Optional properties: 19 + - qcom,hdmi-tx-mux-en-gpio: hdmi mux enable pin 20 + - qcom,hdmi-tx-mux-sel-gpio: hdmi mux select pin 21 + 22 + Example: 23 + 24 + / { 25 + ... 26 + 27 + hdmi: qcom,hdmi-tx-8960@4a00000 { 28 + compatible = "qcom,hdmi-tx-8960"; 29 + reg-names = "core_physical"; 30 + reg = <0x04a00000 0x1000>; 31 + interrupts = <GIC_SPI 79 0>; 32 + clock-names = 33 + "core_clk", 34 + "master_iface_clk", 35 + "slave_iface_clk"; 36 + clocks = 37 + <&mmcc HDMI_APP_CLK>, 38 + <&mmcc HDMI_M_AHB_CLK>, 39 + <&mmcc HDMI_S_AHB_CLK>; 40 + qcom,hdmi-tx-ddc-clk = <&msmgpio 70 GPIO_ACTIVE_HIGH>; 41 + qcom,hdmi-tx-ddc-data = <&msmgpio 71 GPIO_ACTIVE_HIGH>; 42 + qcom,hdmi-tx-hpd = <&msmgpio 72 GPIO_ACTIVE_HIGH>; 43 + core-vdda-supply = <&pm8921_hdmi_mvs>; 44 + hdmi-mux-supply = <&ext_3p3v>; 45 + }; 46 + };
+48
Documentation/devicetree/bindings/drm/msm/mdp.txt
··· 1 + Qualcomm adreno/snapdragon display controller 2 + 3 + Required properties: 4 + - compatible: 5 + * "qcom,mdp" - mdp4 6 + - reg: Physical base address and length of the controller's registers. 7 + - interrupts: The interrupt signal from the display controller. 8 + - connectors: array of phandles for output device(s) 9 + - clocks: device clocks 10 + See ../clocks/clock-bindings.txt for details. 11 + - clock-names: the following clocks are required: 12 + * "core_clk" 13 + * "iface_clk" 14 + * "lut_clk" 15 + * "src_clk" 16 + * "hdmi_clk" 17 + * "mpd_clk" 18 + 19 + Optional properties: 20 + - gpus: phandle for gpu device 21 + 22 + Example: 23 + 24 + / { 25 + ... 26 + 27 + mdp: qcom,mdp@5100000 { 28 + compatible = "qcom,mdp"; 29 + reg = <0x05100000 0xf0000>; 30 + interrupts = <GIC_SPI 75 0>; 31 + connectors = <&hdmi>; 32 + gpus = <&gpu>; 33 + clock-names = 34 + "core_clk", 35 + "iface_clk", 36 + "lut_clk", 37 + "src_clk", 38 + "hdmi_clk", 39 + "mdp_clk"; 40 + clocks = 41 + <&mmcc MDP_SRC>, 42 + <&mmcc MDP_AHB_CLK>, 43 + <&mmcc MDP_LUT_CLK>, 44 + <&mmcc TV_SRC>, 45 + <&mmcc HDMI_TV_CLK>, 46 + <&mmcc MDP_TV_CLK>; 47 + }; 48 + };
+2
drivers/gpu/drm/msm/adreno/a3xx_gpu.c
··· 680 680 } 681 681 682 682 static const struct of_device_id dt_match[] = { 683 + { .compatible = "qcom,adreno-3xx" }, 684 + /* for backwards compat w/ downstream kgsl DT files: */ 683 685 { .compatible = "qcom,kgsl-3d0" }, 684 686 {} 685 687 };
+45 -23
drivers/gpu/drm/msm/hdmi/hdmi.c
··· 123 123 for (i = 0; i < config->hpd_reg_cnt; i++) { 124 124 struct regulator *reg; 125 125 126 - reg = devm_regulator_get(&pdev->dev, config->hpd_reg_names[i]); 126 + reg = devm_regulator_get_exclusive(&pdev->dev, 127 + config->hpd_reg_names[i]); 127 128 if (IS_ERR(reg)) { 128 129 ret = PTR_ERR(reg); 129 130 dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n", ··· 139 138 for (i = 0; i < config->pwr_reg_cnt; i++) { 140 139 struct regulator *reg; 141 140 142 - reg = devm_regulator_get(&pdev->dev, config->pwr_reg_names[i]); 141 + reg = devm_regulator_get_exclusive(&pdev->dev, 142 + config->pwr_reg_names[i]); 143 143 if (IS_ERR(reg)) { 144 144 ret = PTR_ERR(reg); 145 145 dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n", ··· 268 266 { 269 267 int gpio = of_get_named_gpio(of_node, name, 0); 270 268 if (gpio < 0) { 271 - dev_err(dev, "failed to get gpio: %s (%d)\n", 272 - name, gpio); 273 - gpio = -1; 269 + char name2[32]; 270 + snprintf(name2, sizeof(name2), "%s-gpio", name); 271 + gpio = of_get_named_gpio(of_node, name2, 0); 272 + if (gpio < 0) { 273 + dev_err(dev, "failed to get gpio: %s (%d)\n", 274 + name, gpio); 275 + gpio = -1; 276 + } 274 277 } 275 278 return gpio; 276 279 } 277 280 278 - /* TODO actually use DT.. */ 279 - static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"}; 280 - static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"}; 281 - static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"}; 282 - static unsigned long hpd_clk_freq[] = {0, 19200000, 0}; 283 - static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"}; 281 + if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8074")) { 282 + static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"}; 283 + static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"}; 284 + static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"}; 285 + static unsigned long hpd_clk_freq[] = {0, 19200000, 0}; 286 + static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"}; 287 + config.phy_init = hdmi_phy_8x74_init; 288 + config.hpd_reg_names = hpd_reg_names; 289 + config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 290 + config.pwr_reg_names = pwr_reg_names; 291 + config.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names); 292 + config.hpd_clk_names = hpd_clk_names; 293 + config.hpd_freq = hpd_clk_freq; 294 + config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 295 + config.pwr_clk_names = pwr_clk_names; 296 + config.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names); 297 + config.shared_irq = true; 298 + } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8960")) { 299 + static const char *hpd_clk_names[] = {"core_clk", "master_iface_clk", "slave_iface_clk"}; 300 + static const char *hpd_reg_names[] = {"core-vdda", "hdmi-mux"}; 301 + config.phy_init = hdmi_phy_8960_init; 302 + config.hpd_reg_names = hpd_reg_names; 303 + config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 304 + config.hpd_clk_names = hpd_clk_names; 305 + config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 306 + } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8660")) { 307 + config.phy_init = hdmi_phy_8x60_init; 308 + } else { 309 + dev_err(dev, "unknown phy: %s\n", of_node->name); 310 + } 284 311 285 - config.phy_init = hdmi_phy_8x74_init; 286 312 config.mmio_name = "core_physical"; 287 - config.hpd_reg_names = hpd_reg_names; 288 - config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 289 - config.pwr_reg_names = pwr_reg_names; 290 - config.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names); 291 - config.hpd_clk_names = hpd_clk_names; 292 - config.hpd_freq = hpd_clk_freq; 293 - config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 294 - config.pwr_clk_names = pwr_clk_names; 295 - config.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names); 296 313 config.ddc_clk_gpio = get_gpio("qcom,hdmi-tx-ddc-clk"); 297 314 config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data"); 298 315 config.hpd_gpio = get_gpio("qcom,hdmi-tx-hpd"); 299 316 config.mux_en_gpio = get_gpio("qcom,hdmi-tx-mux-en"); 300 317 config.mux_sel_gpio = get_gpio("qcom,hdmi-tx-mux-sel"); 301 - config.shared_irq = true; 302 318 303 319 #else 304 320 static const char *hpd_clk_names[] = { ··· 393 373 } 394 374 395 375 static const struct of_device_id dt_match[] = { 396 - { .compatible = "qcom,hdmi-tx" }, 376 + { .compatible = "qcom,hdmi-tx-8074" }, 377 + { .compatible = "qcom,hdmi-tx-8960" }, 378 + { .compatible = "qcom,hdmi-tx-8660" }, 397 379 {} 398 380 }; 399 381
+7 -3
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
··· 294 294 goto fail; 295 295 } 296 296 297 - mdp4_kms->dsi_pll_vdda = devm_regulator_get(&pdev->dev, "dsi_pll_vdda"); 297 + mdp4_kms->dsi_pll_vdda = 298 + devm_regulator_get_optional(&pdev->dev, "dsi_pll_vdda"); 298 299 if (IS_ERR(mdp4_kms->dsi_pll_vdda)) 299 300 mdp4_kms->dsi_pll_vdda = NULL; 300 301 301 - mdp4_kms->dsi_pll_vddio = devm_regulator_get(&pdev->dev, "dsi_pll_vddio"); 302 + mdp4_kms->dsi_pll_vddio = 303 + devm_regulator_get_optional(&pdev->dev, "dsi_pll_vddio"); 302 304 if (IS_ERR(mdp4_kms->dsi_pll_vddio)) 303 305 mdp4_kms->dsi_pll_vddio = NULL; 304 306 305 - mdp4_kms->vdd = devm_regulator_get(&pdev->dev, "vdd"); 307 + mdp4_kms->vdd = devm_regulator_get_exclusive(&pdev->dev, "vdd"); 306 308 if (IS_ERR(mdp4_kms->vdd)) 307 309 mdp4_kms->vdd = NULL; 308 310 ··· 408 406 static struct mdp4_platform_config config = {}; 409 407 #ifdef CONFIG_OF 410 408 /* TODO */ 409 + config.max_clk = 266667000; 410 + config.iommu = iommu_domain_alloc(&platform_bus_type); 411 411 #else 412 412 if (cpu_is_apq8064()) 413 413 config.max_clk = 266667000;
+23 -16
drivers/gpu/drm/msm/msm_drv.c
··· 905 905 { 906 906 return dev->of_node == data; 907 907 } 908 + 909 + static int add_components(struct device *dev, struct component_match **matchptr, 910 + const char *name) 911 + { 912 + struct device_node *np = dev->of_node; 913 + unsigned i; 914 + 915 + for (i = 0; ; i++) { 916 + struct device_node *node; 917 + 918 + node = of_parse_phandle(np, name, i); 919 + if (!node) 920 + break; 921 + 922 + component_match_add(dev, matchptr, compare_of, node); 923 + } 924 + 925 + return 0; 926 + } 908 927 #else 909 928 static int compare_dev(struct device *dev, void *data) 910 929 { ··· 954 935 { 955 936 struct component_match *match = NULL; 956 937 #ifdef CONFIG_OF 957 - /* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx 958 - * (or probably any other).. so probably some room for some helpers 959 - */ 960 - struct device_node *np = pdev->dev.of_node; 961 - unsigned i; 962 - 963 - for (i = 0; ; i++) { 964 - struct device_node *node; 965 - 966 - node = of_parse_phandle(np, "connectors", i); 967 - if (!node) 968 - break; 969 - 970 - component_match_add(&pdev->dev, &match, compare_of, node); 971 - } 938 + add_components(&pdev->dev, &match, "connectors"); 939 + add_components(&pdev->dev, &match, "gpus"); 972 940 #else 973 941 /* For non-DT case, it kinda sucks. We don't actually have a way 974 942 * to know whether or not we are waiting for certain devices (or if ··· 1001 995 }; 1002 996 1003 997 static const struct of_device_id dt_match[] = { 1004 - { .compatible = "qcom,mdss_mdp" }, 998 + { .compatible = "qcom,mdp" }, /* mdp4 */ 999 + { .compatible = "qcom,mdss_mdp" }, /* mdp5 */ 1005 1000 {} 1006 1001 }; 1007 1002 MODULE_DEVICE_TABLE(of, dt_match);