msm: kgsl: Use bulk clock functions for GMU

Instead of using a bespoke function to get the list of clocks, use the
built in functions instead. To do this, we'll need a local function
to get a clock pointer by name from the list so this is a great time to
add a file just for general purpose driver functions.

Change-Id: Ic0dedbad96f478afc1a416a94df7c0e203ecca8a
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
This commit is contained in:
Jordan Crouse 2019-10-14 10:41:06 -06:00
commit ada604f08f
5 changed files with 55 additions and 74 deletions

View file

@ -4,6 +4,7 @@
*/
#include <dt-bindings/regulator/qcom,rpmh-regulator-levels.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/io.h>
@ -942,34 +943,6 @@ static int gmu_reg_probe(struct kgsl_device *device)
return 0;
}
static int gmu_clocks_probe(struct gmu_device *gmu, struct device_node *node)
{
const char *cname;
struct property *prop;
struct clk *c;
int i = 0;
of_property_for_each_string(node, "clock-names", prop, cname) {
c = devm_clk_get(&gmu->pdev->dev, cname);
if (IS_ERR(c)) {
dev_err(&gmu->pdev->dev,
"dt: Couldn't get GMU clock: %s\n", cname);
return PTR_ERR(c);
}
if (i >= MAX_GMU_CLKS) {
dev_err(&gmu->pdev->dev,
"dt: too many GMU clocks defined\n");
return -EINVAL;
}
gmu->clks[i++] = c;
}
return 0;
}
static int gmu_regulators_probe(struct gmu_device *gmu,
struct device_node *node)
{
@ -1206,11 +1179,20 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
if (ret)
goto error;
/* Set up GMU clocks */
ret = gmu_clocks_probe(gmu, node);
if (ret)
ret = devm_clk_bulk_get_all(&gmu->pdev->dev, &gmu->clks);
if (ret < 0)
goto error;
gmu->num_clks = ret;
/* Get a pointer to the GMU clock */
gmu->gmu_clk = kgsl_of_clk_by_name(gmu->clks, gmu->num_clks, "gmu_clk");
if (!gmu->gmu_clk) {
dev_err(&gmu->pdev->dev, "Couldn't get gmu_clk\n");
ret = -ENODEV;
goto error;
}
/* Set up GMU IOMMU and shared memory with GMU */
ret = gmu_iommu_init(gmu, node);
if (ret)
@ -1304,48 +1286,30 @@ error:
static int gmu_enable_clks(struct kgsl_device *device)
{
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
int ret, j = 0;
int ret;
if (IS_ERR_OR_NULL(gmu->clks[0]))
return -EINVAL;
ret = clk_set_rate(gmu->clks[0], GMU_FREQUENCY);
ret = clk_set_rate(gmu->gmu_clk, GMU_FREQUENCY);
if (ret) {
dev_err(&gmu->pdev->dev, "fail to set default GMU clk freq %d\n",
GMU_FREQUENCY);
dev_err(&gmu->pdev->dev, "Unable to set GMU clock\n");
return ret;
}
while ((j < MAX_GMU_CLKS) && gmu->clks[j]) {
ret = clk_prepare_enable(gmu->clks[j]);
if (ret) {
dev_err(&gmu->pdev->dev,
"fail to enable gpucc clk idx %d\n",
j);
return ret;
}
j++;
ret = clk_bulk_prepare_enable(gmu->num_clks, gmu->clks);
if (ret) {
dev_err(&gmu->pdev->dev, "Cannot enable GMU clocks\n");
return ret;
}
set_bit(GMU_CLK_ON, &device->gmu_core.flags);
return 0;
}
static int gmu_disable_clks(struct kgsl_device *device)
static void gmu_disable_clks(struct kgsl_device *device)
{
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
int j = 0;
if (IS_ERR_OR_NULL(gmu->clks[0]))
return 0;
while ((j < MAX_GMU_CLKS) && gmu->clks[j]) {
clk_disable_unprepare(gmu->clks[j]);
j++;
}
clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks);
clear_bit(GMU_CLK_ON, &device->gmu_core.flags);
return 0;
}
@ -1592,7 +1556,6 @@ static void gmu_remove(struct kgsl_device *device)
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
struct kgsl_hfi *hfi;
int i = 0;
if (gmu == NULL || gmu->pdev == NULL)
return;
@ -1608,11 +1571,6 @@ static void gmu_remove(struct kgsl_device *device)
clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag);
while ((i < MAX_GMU_CLKS) && gmu->clks[i]) {
gmu->clks[i] = NULL;
i++;
}
icc_put(gmu->icc_path);
if (gmu->fw_image) {
@ -1622,13 +1580,6 @@ static void gmu_remove(struct kgsl_device *device)
gmu_memory_close(gmu);
for (i = 0; i < MAX_GMU_CLKS; i++) {
if (gmu->clks[i]) {
devm_clk_put(&gmu->pdev->dev, gmu->clks[i]);
gmu->clks[i] = NULL;
}
}
if (gmu->gx_gdsc) {
devm_regulator_put(gmu->gx_gdsc);
gmu->gx_gdsc = NULL;

View file

@ -206,7 +206,11 @@ struct gmu_device {
struct rpmh_votes_t rpmh_votes;
struct regulator *cx_gdsc;
struct regulator *gx_gdsc;
struct clk *clks[MAX_GMU_CLKS];
struct clk_bulk_data *clks;
/** @num_clks: Number of entries in the @clks array */
int num_clks;
/** @gmu_clk: Pointer to the core GMU clock */
struct clk *gmu_clk;
enum gmu_load_mode load_mode;
unsigned int wakeup_pwrlevel;
unsigned int pcl;

View file

@ -21,8 +21,6 @@
#error "CNOC levels cannot exceed GX levels"
#endif
#define MAX_GMU_CLKS 6
/*
* These are the different ways the GMU can boot. GMU_WARM_BOOT is waking up
* from slumber. GMU_COLD_BOOT is booting for the first time. GMU_RESET

View file

@ -3,9 +3,13 @@
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/regulator/consumer.h>
#include <linux/string.h>
#include "kgsl_util.h"
@ -25,3 +29,15 @@ bool kgsl_regulator_disable_wait(struct regulator *reg, u32 timeout)
usleep_range((100 >> 2) + 1, 100);
}
}
struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count,
const char *id)
{
int i;
for (i = 0; clks && i < count; i++)
if (!strcmp(clks[i].id, id))
return clks[i].clk;
return NULL;
}

View file

@ -7,6 +7,7 @@
#define _KGSL_UTIL_H_
struct regulator;
struct clk_bulk_data;
/**
* kgsl_regulator_disable_wait - Disable a regulator and wait for it
@ -20,4 +21,15 @@ struct regulator;
*/
bool kgsl_regulator_disable_wait(struct regulator *reg, u32 timeout);
/**
* kgsl_of_clk_by_name - Return a clock device for a given name
* @clks: Pointer to an array of bulk clk data
* @count: Number of entries in the array
* @id: Name of the clock to search for
*
* Returns: A pointer to the clock device for the given name or NULL if not
* found
*/
struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count,
const char *id);
#endif