summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2015-06-17 07:03:57 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2015-06-17 07:03:56 -0700
commitcc8359109864d9b0f24ec5f613bc5a0f7c976198 (patch)
tree317a8c4a44909300dc6466c51e54095d8fb61314
parentb23bd9e3a9a83569b960b0fc3cbb6505e1b4cc46 (diff)
parentbb4b92f76176e4b390bdfac9ccf8f51cb979ecf2 (diff)
downloadqcom-cc8359109864d9b0f24ec5f613bc5a0f7c976198.tar.gz
Merge "msm: kgsl: Add GPU speed config support"
-rw-r--r--Documentation/devicetree/bindings/gpu/adreno.txt17
-rw-r--r--drivers/gpu/msm/adreno.c129
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)