Loading Documentation/devicetree/bindings/gpu/adreno.txt +5 −2 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ Required properties: Current values of clock-names are: "src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk", "alt_mem_iface_clk", "rbbmtimer_clk", "alwayson_clk", "iref_clk" "iref_clk", "l3_vote" "core_clk" and "iface_clk" are required and others are optional - qcom,base-leakage-coefficient: Dynamic leakage coefficient. Loading Loading @@ -78,7 +78,10 @@ IOMMU Data: GPU Power levels: - qcom,gpu-pwrlevel-bins: Container for sets of GPU power levels (see adreno-pwrlevels.txt) L3 Power levels: - qcom,l3-pwrlevels: Container for sets of L3 power levels, the L3 frequency is adjusted according to the performance hint received from userspace. DCVS Core info - qcom,dcvs-core-info Container for the DCVS core info (see dcvs-core-info.txt) Loading drivers/gpu/msm/adreno.c +52 −0 Original line number Diff line number Diff line Loading @@ -2525,7 +2525,39 @@ int adreno_set_constraint(struct kgsl_device *device, context->pwr_constraint.sub_type); context->pwr_constraint.type = KGSL_CONSTRAINT_NONE; break; case KGSL_CONSTRAINT_L3_PWRLEVEL: { struct kgsl_device_constraint_pwrlevel pwr; if (constraint->size != sizeof(pwr)) { status = -EINVAL; break; } if (copy_from_user(&pwr, (void __user *)constraint->data, sizeof(pwr))) { status = -EFAULT; break; } if (pwr.level >= KGSL_CONSTRAINT_PWR_MAXLEVELS) pwr.level = KGSL_CONSTRAINT_PWR_MAXLEVELS-1; context->l3_pwr_constraint.type = KGSL_CONSTRAINT_L3_PWRLEVEL; context->l3_pwr_constraint.sub_type = pwr.level; trace_kgsl_user_pwrlevel_constraint(device, context->id, context->l3_pwr_constraint.type, context->l3_pwr_constraint.sub_type); } break; case KGSL_CONSTRAINT_L3_NONE: { unsigned int type = context->l3_pwr_constraint.type; if (type == KGSL_CONSTRAINT_L3_PWRLEVEL) trace_kgsl_user_pwrlevel_constraint(device, context->id, KGSL_CONSTRAINT_L3_NONE, context->l3_pwr_constraint.sub_type); context->l3_pwr_constraint.type = KGSL_CONSTRAINT_L3_NONE; } break; default: status = -EINVAL; break; Loading Loading @@ -2607,7 +2639,27 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv, status = adreno_set_constraint(device, context, &constraint); kgsl_context_put(context); } break; case KGSL_PROP_L3_PWR_CONSTRAINT: { struct kgsl_device_constraint constraint; struct kgsl_context *context; if (sizebytes != sizeof(constraint)) break; if (copy_from_user(&constraint, value, sizeof(constraint))) { status = -EFAULT; break; } context = kgsl_context_get_owner(dev_priv, constraint.context_id); if (context == NULL) break; status = adreno_set_constraint(device, context, &constraint); kgsl_context_put(context); } break; Loading drivers/gpu/msm/adreno_compat.c +32 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -187,6 +187,37 @@ int adreno_setproperty_compat(struct kgsl_device_private *dev_priv, kgsl_context_put(context); } break; case KGSL_PROP_L3_PWR_CONSTRAINT: { struct kgsl_device_constraint_compat constraint32; struct kgsl_device_constraint constraint; struct kgsl_context *context; if (sizebytes != sizeof(constraint32)) break; if (copy_from_user(&constraint32, value, sizeof(constraint32))) { status = -EFAULT; break; } constraint.type = constraint32.type; constraint.context_id = constraint32.context_id; constraint.data = compat_ptr(constraint32.data); constraint.size = (size_t)constraint32.size; context = kgsl_context_get_owner(dev_priv, constraint.context_id); if (context == NULL) break; status = adreno_set_constraint(device, context, &constraint); kgsl_context_put(context); } break; default: /* * Call adreno_setproperty in case the property type was Loading drivers/gpu/msm/adreno_ringbuffer.c +84 −0 Original line number Diff line number Diff line Loading @@ -762,10 +762,55 @@ adreno_ringbuffer_issue_internal_cmds(struct adreno_ringbuffer *rb, sizedwords, 0, NULL); } static int l3_pwrlevel_probe(struct kgsl_device *device, struct device_node *node) { struct device_node *pwrlevel_node, *child; pwrlevel_node = of_find_node_by_name(node, "qcom,l3-pwrlevels"); if (pwrlevel_node == NULL) { dev_err_once(&device->pdev->dev, "Unable to find 'qcom,l3-pwrlevels'\n"); return -EINVAL; } device->num_l3_pwrlevels = 0; for_each_child_of_node(pwrlevel_node, child) { unsigned int index; if (of_property_read_u32(child, "reg", &index)) return -EINVAL; if (index >= MAX_L3_LEVELS) { dev_err(&device->pdev->dev, "L3 pwrlevel %d is out of range\n", index); continue; } if (index >= device->num_l3_pwrlevels) device->num_l3_pwrlevels = index + 1; if (of_property_read_u32(child, "qcom,l3-freq", &device->l3_freq[index])) return -EINVAL; } return 0; } static void adreno_ringbuffer_set_constraint(struct kgsl_device *device, struct kgsl_drawobj *drawobj) { struct kgsl_context *context = drawobj->context; struct device *dev = &device->pdev->dev; unsigned long flags = drawobj->flags; struct device_node *node; node = device->pdev->dev.of_node; /* * Check if the context has a constraint and constraint flags are * set. Loading @@ -775,6 +820,45 @@ static void adreno_ringbuffer_set_constraint(struct kgsl_device *device, (drawobj->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) kgsl_pwrctrl_set_constraint(device, &context->pwr_constraint, context->id); if (IS_ERR_OR_NULL(device->l3_clk)) device->l3_clk = devm_clk_get(dev, "l3_vote"); if (IS_ERR_OR_NULL(device->l3_clk)) { KGSL_DEV_ERR_ONCE(device, "Unable to get the l3_vote clock. Cannot set the L3 constraint\n"); return; } if (context->l3_pwr_constraint.type && ((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) || (flags & KGSL_CONTEXT_PWR_CONSTRAINT))) { int ret = l3_pwrlevel_probe(device, node); if (ret) return; switch (context->l3_pwr_constraint.type) { case KGSL_CONSTRAINT_L3_PWRLEVEL: { unsigned int sub_type; sub_type = context->l3_pwr_constraint.sub_type; if (sub_type == KGSL_CONSTRAINT_L3_PWR_MED) clk_set_rate(device->l3_clk, device->l3_freq[1]); if (sub_type == KGSL_CONSTRAINT_L3_PWR_MAX) clk_set_rate(device->l3_clk, device->l3_freq[2]); } break; case KGSL_CONSTRAINT_L3_NONE: clk_set_rate(device->l3_clk, device->l3_freq[0]); break; } } } static inline int _get_alwayson_counter(struct adreno_device *adreno_dev, Loading drivers/gpu/msm/kgsl_device.h +5 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ enum kgsl_event_results { /* Allocate 600K for the snapshot static region*/ #define KGSL_SNAPSHOT_MEMSIZE (600 * 1024) #define MAX_L3_LEVELS 3 struct kgsl_device; struct platform_device; Loading Loading @@ -332,6 +333,9 @@ struct kgsl_device { /* Number of active contexts seen globally for this device */ int active_context_count; struct kobject *gpu_sysfs_kobj; struct clk *l3_clk; unsigned int l3_freq[MAX_L3_LEVELS]; unsigned int num_l3_pwrlevels; }; #define KGSL_MMU_DEVICE(_mmu) \ Loading Loading @@ -410,6 +414,7 @@ struct kgsl_context { struct kgsl_event_group events; unsigned int flags; struct kgsl_pwr_constraint pwr_constraint; struct kgsl_pwr_constraint l3_pwr_constraint; unsigned int fault_count; unsigned long fault_time; struct kgsl_mem_entry *user_ctxt_record; Loading Loading
Documentation/devicetree/bindings/gpu/adreno.txt +5 −2 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ Required properties: Current values of clock-names are: "src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk", "alt_mem_iface_clk", "rbbmtimer_clk", "alwayson_clk", "iref_clk" "iref_clk", "l3_vote" "core_clk" and "iface_clk" are required and others are optional - qcom,base-leakage-coefficient: Dynamic leakage coefficient. Loading Loading @@ -78,7 +78,10 @@ IOMMU Data: GPU Power levels: - qcom,gpu-pwrlevel-bins: Container for sets of GPU power levels (see adreno-pwrlevels.txt) L3 Power levels: - qcom,l3-pwrlevels: Container for sets of L3 power levels, the L3 frequency is adjusted according to the performance hint received from userspace. DCVS Core info - qcom,dcvs-core-info Container for the DCVS core info (see dcvs-core-info.txt) Loading
drivers/gpu/msm/adreno.c +52 −0 Original line number Diff line number Diff line Loading @@ -2525,7 +2525,39 @@ int adreno_set_constraint(struct kgsl_device *device, context->pwr_constraint.sub_type); context->pwr_constraint.type = KGSL_CONSTRAINT_NONE; break; case KGSL_CONSTRAINT_L3_PWRLEVEL: { struct kgsl_device_constraint_pwrlevel pwr; if (constraint->size != sizeof(pwr)) { status = -EINVAL; break; } if (copy_from_user(&pwr, (void __user *)constraint->data, sizeof(pwr))) { status = -EFAULT; break; } if (pwr.level >= KGSL_CONSTRAINT_PWR_MAXLEVELS) pwr.level = KGSL_CONSTRAINT_PWR_MAXLEVELS-1; context->l3_pwr_constraint.type = KGSL_CONSTRAINT_L3_PWRLEVEL; context->l3_pwr_constraint.sub_type = pwr.level; trace_kgsl_user_pwrlevel_constraint(device, context->id, context->l3_pwr_constraint.type, context->l3_pwr_constraint.sub_type); } break; case KGSL_CONSTRAINT_L3_NONE: { unsigned int type = context->l3_pwr_constraint.type; if (type == KGSL_CONSTRAINT_L3_PWRLEVEL) trace_kgsl_user_pwrlevel_constraint(device, context->id, KGSL_CONSTRAINT_L3_NONE, context->l3_pwr_constraint.sub_type); context->l3_pwr_constraint.type = KGSL_CONSTRAINT_L3_NONE; } break; default: status = -EINVAL; break; Loading Loading @@ -2607,7 +2639,27 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv, status = adreno_set_constraint(device, context, &constraint); kgsl_context_put(context); } break; case KGSL_PROP_L3_PWR_CONSTRAINT: { struct kgsl_device_constraint constraint; struct kgsl_context *context; if (sizebytes != sizeof(constraint)) break; if (copy_from_user(&constraint, value, sizeof(constraint))) { status = -EFAULT; break; } context = kgsl_context_get_owner(dev_priv, constraint.context_id); if (context == NULL) break; status = adreno_set_constraint(device, context, &constraint); kgsl_context_put(context); } break; Loading
drivers/gpu/msm/adreno_compat.c +32 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -187,6 +187,37 @@ int adreno_setproperty_compat(struct kgsl_device_private *dev_priv, kgsl_context_put(context); } break; case KGSL_PROP_L3_PWR_CONSTRAINT: { struct kgsl_device_constraint_compat constraint32; struct kgsl_device_constraint constraint; struct kgsl_context *context; if (sizebytes != sizeof(constraint32)) break; if (copy_from_user(&constraint32, value, sizeof(constraint32))) { status = -EFAULT; break; } constraint.type = constraint32.type; constraint.context_id = constraint32.context_id; constraint.data = compat_ptr(constraint32.data); constraint.size = (size_t)constraint32.size; context = kgsl_context_get_owner(dev_priv, constraint.context_id); if (context == NULL) break; status = adreno_set_constraint(device, context, &constraint); kgsl_context_put(context); } break; default: /* * Call adreno_setproperty in case the property type was Loading
drivers/gpu/msm/adreno_ringbuffer.c +84 −0 Original line number Diff line number Diff line Loading @@ -762,10 +762,55 @@ adreno_ringbuffer_issue_internal_cmds(struct adreno_ringbuffer *rb, sizedwords, 0, NULL); } static int l3_pwrlevel_probe(struct kgsl_device *device, struct device_node *node) { struct device_node *pwrlevel_node, *child; pwrlevel_node = of_find_node_by_name(node, "qcom,l3-pwrlevels"); if (pwrlevel_node == NULL) { dev_err_once(&device->pdev->dev, "Unable to find 'qcom,l3-pwrlevels'\n"); return -EINVAL; } device->num_l3_pwrlevels = 0; for_each_child_of_node(pwrlevel_node, child) { unsigned int index; if (of_property_read_u32(child, "reg", &index)) return -EINVAL; if (index >= MAX_L3_LEVELS) { dev_err(&device->pdev->dev, "L3 pwrlevel %d is out of range\n", index); continue; } if (index >= device->num_l3_pwrlevels) device->num_l3_pwrlevels = index + 1; if (of_property_read_u32(child, "qcom,l3-freq", &device->l3_freq[index])) return -EINVAL; } return 0; } static void adreno_ringbuffer_set_constraint(struct kgsl_device *device, struct kgsl_drawobj *drawobj) { struct kgsl_context *context = drawobj->context; struct device *dev = &device->pdev->dev; unsigned long flags = drawobj->flags; struct device_node *node; node = device->pdev->dev.of_node; /* * Check if the context has a constraint and constraint flags are * set. Loading @@ -775,6 +820,45 @@ static void adreno_ringbuffer_set_constraint(struct kgsl_device *device, (drawobj->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) kgsl_pwrctrl_set_constraint(device, &context->pwr_constraint, context->id); if (IS_ERR_OR_NULL(device->l3_clk)) device->l3_clk = devm_clk_get(dev, "l3_vote"); if (IS_ERR_OR_NULL(device->l3_clk)) { KGSL_DEV_ERR_ONCE(device, "Unable to get the l3_vote clock. Cannot set the L3 constraint\n"); return; } if (context->l3_pwr_constraint.type && ((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) || (flags & KGSL_CONTEXT_PWR_CONSTRAINT))) { int ret = l3_pwrlevel_probe(device, node); if (ret) return; switch (context->l3_pwr_constraint.type) { case KGSL_CONSTRAINT_L3_PWRLEVEL: { unsigned int sub_type; sub_type = context->l3_pwr_constraint.sub_type; if (sub_type == KGSL_CONSTRAINT_L3_PWR_MED) clk_set_rate(device->l3_clk, device->l3_freq[1]); if (sub_type == KGSL_CONSTRAINT_L3_PWR_MAX) clk_set_rate(device->l3_clk, device->l3_freq[2]); } break; case KGSL_CONSTRAINT_L3_NONE: clk_set_rate(device->l3_clk, device->l3_freq[0]); break; } } } static inline int _get_alwayson_counter(struct adreno_device *adreno_dev, Loading
drivers/gpu/msm/kgsl_device.h +5 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ enum kgsl_event_results { /* Allocate 600K for the snapshot static region*/ #define KGSL_SNAPSHOT_MEMSIZE (600 * 1024) #define MAX_L3_LEVELS 3 struct kgsl_device; struct platform_device; Loading Loading @@ -332,6 +333,9 @@ struct kgsl_device { /* Number of active contexts seen globally for this device */ int active_context_count; struct kobject *gpu_sysfs_kobj; struct clk *l3_clk; unsigned int l3_freq[MAX_L3_LEVELS]; unsigned int num_l3_pwrlevels; }; #define KGSL_MMU_DEVICE(_mmu) \ Loading Loading @@ -410,6 +414,7 @@ struct kgsl_context { struct kgsl_event_group events; unsigned int flags; struct kgsl_pwr_constraint pwr_constraint; struct kgsl_pwr_constraint l3_pwr_constraint; unsigned int fault_count; unsigned long fault_time; struct kgsl_mem_entry *user_ctxt_record; Loading