mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 16:37:50 +00:00
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>
This commit is contained in:
parent
8f67da335d
commit
41e69778c8
7 changed files with 223 additions and 42 deletions
52
Documentation/devicetree/bindings/drm/msm/gpu.txt
Normal file
52
Documentation/devicetree/bindings/drm/msm/gpu.txt
Normal file
|
@ -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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
46
Documentation/devicetree/bindings/drm/msm/hdmi.txt
Normal file
46
Documentation/devicetree/bindings/drm/msm/hdmi.txt
Normal file
|
@ -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>;
|
||||||
|
};
|
||||||
|
};
|
48
Documentation/devicetree/bindings/drm/msm/mdp.txt
Normal file
48
Documentation/devicetree/bindings/drm/msm/mdp.txt
Normal file
|
@ -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>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -680,6 +680,8 @@ static int a3xx_remove(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id dt_match[] = {
|
static const struct of_device_id dt_match[] = {
|
||||||
|
{ .compatible = "qcom,adreno-3xx" },
|
||||||
|
/* for backwards compat w/ downstream kgsl DT files: */
|
||||||
{ .compatible = "qcom,kgsl-3d0" },
|
{ .compatible = "qcom,kgsl-3d0" },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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++) {
|
for (i = 0; i < config->hpd_reg_cnt; i++) {
|
||||||
struct regulator *reg;
|
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)) {
|
if (IS_ERR(reg)) {
|
||||||
ret = PTR_ERR(reg);
|
ret = PTR_ERR(reg);
|
||||||
dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n",
|
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++) {
|
for (i = 0; i < config->pwr_reg_cnt; i++) {
|
||||||
struct regulator *reg;
|
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)) {
|
if (IS_ERR(reg)) {
|
||||||
ret = PTR_ERR(reg);
|
ret = PTR_ERR(reg);
|
||||||
dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n",
|
dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n",
|
||||||
|
@ -265,23 +267,26 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||||
int get_gpio(const char *name)
|
int get_gpio(const char *name)
|
||||||
{
|
{
|
||||||
int gpio = of_get_named_gpio(of_node, name, 0);
|
int gpio = of_get_named_gpio(of_node, name, 0);
|
||||||
|
if (gpio < 0) {
|
||||||
|
char name2[32];
|
||||||
|
snprintf(name2, sizeof(name2), "%s-gpio", name);
|
||||||
|
gpio = of_get_named_gpio(of_node, name2, 0);
|
||||||
if (gpio < 0) {
|
if (gpio < 0) {
|
||||||
dev_err(dev, "failed to get gpio: %s (%d)\n",
|
dev_err(dev, "failed to get gpio: %s (%d)\n",
|
||||||
name, gpio);
|
name, gpio);
|
||||||
gpio = -1;
|
gpio = -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return gpio;
|
return gpio;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO actually use DT.. */
|
if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8074")) {
|
||||||
static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"};
|
static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"};
|
||||||
static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"};
|
static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"};
|
||||||
static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"};
|
static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"};
|
||||||
static unsigned long hpd_clk_freq[] = {0, 19200000, 0};
|
static unsigned long hpd_clk_freq[] = {0, 19200000, 0};
|
||||||
static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"};
|
static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"};
|
||||||
|
|
||||||
config.phy_init = hdmi_phy_8x74_init;
|
config.phy_init = hdmi_phy_8x74_init;
|
||||||
config.mmio_name = "core_physical";
|
|
||||||
config.hpd_reg_names = hpd_reg_names;
|
config.hpd_reg_names = hpd_reg_names;
|
||||||
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
|
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
|
||||||
config.pwr_reg_names = pwr_reg_names;
|
config.pwr_reg_names = pwr_reg_names;
|
||||||
|
@ -291,12 +296,27 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||||
config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
|
config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
|
||||||
config.pwr_clk_names = pwr_clk_names;
|
config.pwr_clk_names = pwr_clk_names;
|
||||||
config.pwr_clk_cnt = ARRAY_SIZE(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.mmio_name = "core_physical";
|
||||||
config.ddc_clk_gpio = get_gpio("qcom,hdmi-tx-ddc-clk");
|
config.ddc_clk_gpio = get_gpio("qcom,hdmi-tx-ddc-clk");
|
||||||
config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data");
|
config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data");
|
||||||
config.hpd_gpio = get_gpio("qcom,hdmi-tx-hpd");
|
config.hpd_gpio = get_gpio("qcom,hdmi-tx-hpd");
|
||||||
config.mux_en_gpio = get_gpio("qcom,hdmi-tx-mux-en");
|
config.mux_en_gpio = get_gpio("qcom,hdmi-tx-mux-en");
|
||||||
config.mux_sel_gpio = get_gpio("qcom,hdmi-tx-mux-sel");
|
config.mux_sel_gpio = get_gpio("qcom,hdmi-tx-mux-sel");
|
||||||
config.shared_irq = true;
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static const char *hpd_clk_names[] = {
|
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[] = {
|
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" },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -294,15 +294,17 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
|
||||||
goto fail;
|
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))
|
if (IS_ERR(mdp4_kms->dsi_pll_vdda))
|
||||||
mdp4_kms->dsi_pll_vdda = NULL;
|
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))
|
if (IS_ERR(mdp4_kms->dsi_pll_vddio))
|
||||||
mdp4_kms->dsi_pll_vddio = NULL;
|
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))
|
if (IS_ERR(mdp4_kms->vdd))
|
||||||
mdp4_kms->vdd = NULL;
|
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 = {};
|
static struct mdp4_platform_config config = {};
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
config.max_clk = 266667000;
|
||||||
|
config.iommu = iommu_domain_alloc(&platform_bus_type);
|
||||||
#else
|
#else
|
||||||
if (cpu_is_apq8064())
|
if (cpu_is_apq8064())
|
||||||
config.max_clk = 266667000;
|
config.max_clk = 266667000;
|
||||||
|
|
|
@ -905,6 +905,25 @@ static int compare_of(struct device *dev, void *data)
|
||||||
{
|
{
|
||||||
return dev->of_node == 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
|
#else
|
||||||
static int compare_dev(struct device *dev, void *data)
|
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;
|
struct component_match *match = NULL;
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
/* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx
|
add_components(&pdev->dev, &match, "connectors");
|
||||||
* (or probably any other).. so probably some room for some helpers
|
add_components(&pdev->dev, &match, "gpus");
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
/* For non-DT case, it kinda sucks. We don't actually have a way
|
/* 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
|
* 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[] = {
|
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);
|
MODULE_DEVICE_TABLE(of, dt_match);
|
||||||
|
|
Loading…
Reference in a new issue