diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2015-06-17 07:03:57 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2015-06-17 07:03:56 -0700 |
commit | cc8359109864d9b0f24ec5f613bc5a0f7c976198 (patch) | |
tree | 317a8c4a44909300dc6466c51e54095d8fb61314 | |
parent | b23bd9e3a9a83569b960b0fc3cbb6505e1b4cc46 (diff) | |
parent | bb4b92f76176e4b390bdfac9ccf8f51cb979ecf2 (diff) | |
download | qcom-cc8359109864d9b0f24ec5f613bc5a0f7c976198.tar.gz |
Merge "msm: kgsl: Add GPU speed config support"
-rw-r--r-- | Documentation/devicetree/bindings/gpu/adreno.txt | 17 | ||||
-rw-r--r-- | drivers/gpu/msm/adreno.c | 129 |
2 files changed, 133 insertions, 13 deletions
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 47bbbf84724..061a7e61a1a 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -8,9 +8,12 @@ Required properties: - reg: Specifies the register base address and size. The second interval specifies the shader memory base address and size. - reg-names: Resource names used for the physical address of device registers - and shader memory. "kgsl_3d0_reg_memory" gives the physical address - and length of device registers while "kgsl_3d0_shader_memory" gives - physical address and length of device shader memory. + and shader memory. + "kgsl_3d0_reg_memory" gives the physical address and length of device + registers. + "kgsl_3d0_shader_memory" gives the physical address and length of + device shader memory. + "efuse_memory" gives the physical address and length of core PTE memory. - interrupts: Interrupt mapping for GPU IRQ. - interrupt-names: String property to describe the name of the interrupt. - qcom,id: An integer used as an identification number for the device. @@ -100,6 +103,9 @@ Optional Properties: - qcom,pm-qos-wakeup-latency: Similar to the above. Driver votes against deep low power modes right before GPU wakes up from sleep. +- qcom,gpu-speed-config: + This property enables support for dynamic GPU powerlevel + configuration based on the efuse register. The following properties are optional as collecting data via coresight might not be supported for every chipset. The documentation for coresight @@ -122,8 +128,9 @@ Example of A330 GPU in MSM8916: label = "kgsl-3d0"; compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; reg = <0x01c00000 0x10000 - 0x01c20000 0x20000>; - reg-names = "kgsl_3d0_reg_memory" , "kgsl_3d0_shader_memory"; + 0x01c20000 0x20000 + 0x0005c00c 0x8>; + reg-names = "kgsl_3d0_reg_memory" , "kgsl_3d0_shader_memory" , "efuse_memory"; interrupts = <0 33 0>; interrupt-names = "kgsl_3d0_irq"; qcom,id = <0>; diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index bf63114824e..2fabf2515c3 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -548,6 +548,77 @@ static struct device_node *adreno_of_find_subnode(struct device_node *parent, return NULL; } +/* + * Get bus data based on the GPU speed configuration. If GPU speed config is + * not valid it will get normal bus data, otherwise it will get speed config + * bus data. + */ +static int adreno_of_get_bus_data(struct platform_device *pdev, + struct device_node *node, + struct kgsl_device_platform_data *pdata) +{ + struct device_node *parent = pdev->dev.of_node; + int ret, num_usecases = 0, num_paths, len; + const uint32_t *vec_arr = NULL; + const char *name; + + if (node != parent) { + ret = of_property_read_string(node, "qcom,msm-bus,name", + &name); + if (ret) + goto use_parent; + + ret = of_property_read_u32(node, "qcom,msm-bus,num-cases", + &num_usecases); + if (ret) + goto use_parent; + + ret = of_property_read_u32(node, "qcom,msm-bus,num-paths", + &num_paths); + if (ret) + goto use_parent; + + vec_arr = of_get_property(node, "qcom,msm-bus,vectors-KBps", + &len); + if (vec_arr == NULL) + goto use_parent; + /* + * All bus scale properties are valid, get all bus data from + * the child node. + */ + pdev->dev.of_node = node; + } + + pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev); + + /* + * Set node back to parent if it's updated. We don't need any + * data from child. + */ + if (node != parent) + pdev->dev.of_node = parent; + + if (IS_ERR_OR_NULL(pdata->bus_scale_table)) { + ret = PTR_ERR(pdata->bus_scale_table); + if (!ret) + ret = -EINVAL; + } + + return ret; + +use_parent: + ret = 0; + pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev); + + if (IS_ERR_OR_NULL(pdata->bus_scale_table)) { + ret = PTR_ERR(pdata->bus_scale_table); + if (!ret) + ret = -EINVAL; + } + + return ret; +} + static int adreno_of_get_pwrlevels(struct device_node *parent, struct kgsl_device_platform_data *pdata) { @@ -718,9 +789,51 @@ err: return result; } +/* + * Read the Speed bin data and return device node. + */ +static struct device_node *get_gpu_speed_config_data(struct platform_device + *pdev) +{ + struct resource *res; + void __iomem *base; + u32 pte_reg_val; + int speed_bin, speed_config; + char prop_name[32]; + + /* Load defualt configuration, if speed config is not required */ + if (of_property_read_u32(pdev->dev.of_node, + "qcom,gpu-speed-config", &speed_config)) + return pdev->dev.of_node; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "efuse_memory"); + if (!res) + return NULL; + + base = ioremap(res->start, resource_size(res)); + + if (!base) + return NULL; + + pte_reg_val = __raw_readl(base); + + iounmap(base); + + speed_bin = (pte_reg_val >> 0x2) & 0x7; + if (speed_bin == speed_config) { + snprintf(prop_name, ARRAY_SIZE(prop_name), "%s%d", + "gpu-speed-config@", speed_config); + return adreno_of_find_subnode(pdev->dev.of_node, prop_name); + } + + return pdev->dev.of_node; +} + static int adreno_of_get_pdata(struct platform_device *pdev) { struct kgsl_device_platform_data *pdata = NULL; + struct device_node *node; int ret = -EINVAL; if (of_property_read_string(pdev->dev.of_node, "label", &pdev->name)) { @@ -737,8 +850,13 @@ static int adreno_of_get_pdata(struct platform_device *pdev) goto err; } + /* Get Speed Bin Data */ + node = get_gpu_speed_config_data(pdev); + if (node == NULL) + goto err; + /* pwrlevel Data */ - ret = adreno_of_get_pwrlevels(pdev->dev.of_node, pdata); + ret = adreno_of_get_pwrlevels(node, pdata); if (ret) goto err; @@ -769,14 +887,9 @@ static int adreno_of_get_pdata(struct platform_device *pdev) goto err; /* Bus Scale Data */ - - pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev); - if (IS_ERR_OR_NULL(pdata->bus_scale_table)) { - ret = PTR_ERR(pdata->bus_scale_table); - if (!ret) - ret = -EINVAL; + ret = adreno_of_get_bus_data(pdev, node, pdata); + if (ret) goto err; - } ret = adreno_of_get_iommu(pdev, pdata); if (ret) |