diff mbox

[v3,5/7] PM / devfreq: exynos5250: migrate to common-clock

Message ID 1405449332-26350-1-git-send-email-a.kesavan@samsung.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Abhilash Kesavan July 15, 2014, 6:35 p.m. UTC
From: Andrew Bresticker <abrestic@chromium.org>

Use the common-clock framework to scale frequencies for the various
peripheral clocks on the Exynos5250.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
---
 drivers/devfreq/exynos/exynos5_bus.c |  131 ++++++++++++++++++++++++++++++----
 1 file changed, 119 insertions(+), 12 deletions(-)

Comments

Tomasz Figa July 16, 2014, 11:03 a.m. UTC | #1
Hi Abhilash, Andrew,

Please see my comments inline.

On 15.07.2014 20:35, Abhilash Kesavan wrote:
> From: Andrew Bresticker <abrestic@chromium.org>
> 
> Use the common-clock framework to scale frequencies for the various
> peripheral clocks on the Exynos5250.
> 
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> ---
>  drivers/devfreq/exynos/exynos5_bus.c |  131 ++++++++++++++++++++++++++++++----
>  1 file changed, 119 insertions(+), 12 deletions(-)

[snip]

> +
>  static struct int_bus_opp_table exynos5_int_opp_table[] = {
>  	{LV_0, 266000, 1025000},
>  	{LV_1, 200000, 1025000},
> @@ -75,6 +85,98 @@ static struct int_bus_opp_table exynos5_int_opp_table[] = {
>  	{0, 0, 0},
>  };
>  
> +static struct int_clk_table aclk_166[] = {
> +	{LV_0, 167000},
> +	{LV_1, 111000},
> +	{LV_2,  84000},
> +	{LV_3,  84000},
> +	{LV_4,  42000},
> +};

[snip]

> +static struct int_clk_table aclk_300_gscl[] = {
> +	{LV_0, 267000},
> +	{LV_1, 267000},
> +	{LV_2, 267000},
> +	{LV_3, 200000},
> +	{LV_4, 100000},
> +};

Shouldn't you manage this using OPP framework and parse this from DT?

> +
> +#define EXYNOS5_INT_CLK(name, tbl) {		\
> +	.clk_name = name,			\
> +	.freq_table = tbl,			\
> +}

[snip]

> @@ -320,16 +427,16 @@ static int exynos5_busfreq_int_probe(struct platform_device *pdev)
>  	rcu_read_unlock();
>  	data->curr_freq = initial_freq;
>  
> -	err = clk_set_rate(data->int_clk, initial_freq * 1000);
> +	err = exynos5_int_setvolt(data, initial_volt);
> +	if (err)
> +		return err;
> +
> +	err = exynos5_int_set_rate(data, initial_freq);
>  	if (err) {
>  		dev_err(dev, "Failed to set initial frequency\n");
>  		return err;
>  	}
>  
> -	err = exynos5_int_setvolt(data, initial_volt);
> -	if (err)
> -		return err;
> -

Whether voltage or rate should be set first depends on current settings
and initial_{freq,volt}. Also it might be more convenient to simply call
exynos5_busfreq_int_target() here.

Best regards,
Tomasz
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Abhilash Kesavan July 16, 2014, 6 p.m. UTC | #2
Hi Tomasz,

On Wed, Jul 16, 2014 at 4:33 PM, Tomasz Figa <t.figa@samsung.com> wrote:
> Hi Abhilash, Andrew,
>
> Please see my comments inline.
>
> On 15.07.2014 20:35, Abhilash Kesavan wrote:
>> From: Andrew Bresticker <abrestic@chromium.org>
>>
>> Use the common-clock framework to scale frequencies for the various
>> peripheral clocks on the Exynos5250.
>>
>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
>> ---
>>  drivers/devfreq/exynos/exynos5_bus.c |  131 ++++++++++++++++++++++++++++++----
>>  1 file changed, 119 insertions(+), 12 deletions(-)
>
> [snip]
>
>> +
>>  static struct int_bus_opp_table exynos5_int_opp_table[] = {
>>       {LV_0, 266000, 1025000},
>>       {LV_1, 200000, 1025000},
>> @@ -75,6 +85,98 @@ static struct int_bus_opp_table exynos5_int_opp_table[] = {
>>       {0, 0, 0},
>>  };
>>
>> +static struct int_clk_table aclk_166[] = {
>> +     {LV_0, 167000},
>> +     {LV_1, 111000},
>> +     {LV_2,  84000},
>> +     {LV_3,  84000},
>> +     {LV_4,  42000},
>> +};
>
> [snip]
>
>> +static struct int_clk_table aclk_300_gscl[] = {
>> +     {LV_0, 267000},
>> +     {LV_1, 267000},
>> +     {LV_2, 267000},
>> +     {LV_3, 200000},
>> +     {LV_4, 100000},
>> +};
>
> Shouldn't you manage this using OPP framework and parse this from DT?
OK, one of the questions I had was about the handling of virtual INT
bus levels (frequencies and voltages). I have consolidated my
understanding of how the bindings should look and questions I had in
the driver thread.
>
>> +
>> +#define EXYNOS5_INT_CLK(name, tbl) {         \
>> +     .clk_name = name,                       \
>> +     .freq_table = tbl,                      \
>> +}
>
> [snip]
>
>> @@ -320,16 +427,16 @@ static int exynos5_busfreq_int_probe(struct platform_device *pdev)
>>       rcu_read_unlock();
>>       data->curr_freq = initial_freq;
>>
>> -     err = clk_set_rate(data->int_clk, initial_freq * 1000);
>> +     err = exynos5_int_setvolt(data, initial_volt);
>> +     if (err)
>> +             return err;
>> +
>> +     err = exynos5_int_set_rate(data, initial_freq);
>>       if (err) {
>>               dev_err(dev, "Failed to set initial frequency\n");
>>               return err;
>>       }
>>
>> -     err = exynos5_int_setvolt(data, initial_volt);
>> -     if (err)
>> -             return err;
>> -
>
> Whether voltage or rate should be set first depends on current settings
> and initial_{freq,volt}. Also it might be more convenient to simply call
> exynos5_busfreq_int_target() here.
Wouldn't setting voltage first always be safe ? Yes, just calling
target would be better. Will modify.

Regards,
Abhilash
>
> Best regards,
> Tomasz
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/devfreq/exynos/exynos5_bus.c b/drivers/devfreq/exynos/exynos5_bus.c
index 6cd0392..1196653 100644
--- a/drivers/devfreq/exynos/exynos5_bus.c
+++ b/drivers/devfreq/exynos/exynos5_bus.c
@@ -57,7 +57,6 @@  struct busfreq_data_int {
 	struct notifier_block pm_notifier;
 	struct mutex lock;
 	struct pm_qos_request int_req;
-	struct clk *int_clk;
 };
 
 struct int_bus_opp_table {
@@ -66,6 +65,17 @@  struct int_bus_opp_table {
 	unsigned long volt;
 };
 
+struct int_clk_table {
+	unsigned int idx;
+	unsigned long freq;
+};
+
+struct int_clk {
+	const char *clk_name;
+	struct clk *clk;
+	struct int_clk_table *freq_table;
+};
+
 static struct int_bus_opp_table exynos5_int_opp_table[] = {
 	{LV_0, 266000, 1025000},
 	{LV_1, 200000, 1025000},
@@ -75,6 +85,98 @@  static struct int_bus_opp_table exynos5_int_opp_table[] = {
 	{0, 0, 0},
 };
 
+static struct int_clk_table aclk_166[] = {
+	{LV_0, 167000},
+	{LV_1, 111000},
+	{LV_2,  84000},
+	{LV_3,  84000},
+	{LV_4,  42000},
+};
+
+static struct int_clk_table aclk_200[] = {
+	{LV_0, 200000},
+	{LV_1, 160000},
+	{LV_2, 160000},
+	{LV_3, 134000},
+	{LV_4, 100000},
+};
+
+static struct int_clk_table aclk_266[] = {
+	{LV_0, 267000},
+	{LV_1, 200000},
+	{LV_2, 160000},
+	{LV_3, 134000},
+	{LV_4, 100000},
+};
+
+static struct int_clk_table aclk_333[] = {
+	{LV_0, 333000},
+	{LV_1, 167000},
+	{LV_2, 111000},
+	{LV_3, 111000},
+	{LV_4,  42000},
+};
+
+static struct int_clk_table aclk_300_disp1[] = {
+	{LV_0, 267000},
+	{LV_1, 267000},
+	{LV_2, 267000},
+	{LV_3, 267000},
+	{LV_4, 200000},
+};
+
+static struct int_clk_table aclk_300_gscl[] = {
+	{LV_0, 267000},
+	{LV_1, 267000},
+	{LV_2, 267000},
+	{LV_3, 200000},
+	{LV_4, 100000},
+};
+
+#define EXYNOS5_INT_CLK(name, tbl) {		\
+	.clk_name = name,			\
+	.freq_table = tbl,			\
+}
+
+static struct int_clk exynos5_int_clks[] = {
+	EXYNOS5_INT_CLK("aclk166_d", aclk_166),
+	EXYNOS5_INT_CLK("aclk200_d", aclk_200),
+	EXYNOS5_INT_CLK("aclk266_d", aclk_266),
+	EXYNOS5_INT_CLK("aclk333_d", aclk_333),
+	EXYNOS5_INT_CLK("aclk300_disp1_d", aclk_300_disp1),
+	EXYNOS5_INT_CLK("aclk300_gscl_d", aclk_300_gscl),
+};
+
+static int exynos5_int_set_rate(struct busfreq_data_int *data,
+				unsigned long rate)
+{
+	int index, i;
+
+	for (index = 0; index < ARRAY_SIZE(exynos5_int_opp_table); index++) {
+		if (exynos5_int_opp_table[index].clk == rate)
+			break;
+	}
+
+	if (index >= _LV_END)
+		return -EINVAL;
+
+	/* Change the system clock divider values */
+	for (i = 0; i < ARRAY_SIZE(exynos5_int_clks); i++) {
+		struct int_clk *clk_info = &exynos5_int_clks[i];
+		int ret;
+
+		ret = clk_set_rate(clk_info->clk,
+				clk_info->freq_table[index].freq * 1000);
+		if (ret) {
+			dev_err(data->dev, "Failed to set %s rate: %d\n",
+				clk_info->clk_name, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 static int exynos5_int_setvolt(struct busfreq_data_int *data,
 				unsigned long volt)
 {
@@ -126,7 +228,7 @@  static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq,
 	if (err)
 		goto out;
 
-	err = clk_set_rate(data->int_clk, freq * 1000);
+	err = exynos5_int_set_rate(data, freq);
 
 	if (err)
 		goto out;
@@ -220,7 +322,7 @@  static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block *this,
 		if (err)
 			goto unlock;
 
-		err = clk_set_rate(data->int_clk, freq * 1000);
+		err = exynos5_int_set_rate(data, freq);
 
 		if (err)
 			goto unlock;
@@ -300,10 +402,15 @@  static int exynos5_busfreq_int_probe(struct platform_device *pdev)
 		return PTR_ERR(data->vdd_int);
 	}
 
-	data->int_clk = devm_clk_get(dev, "int_clk");
-	if (IS_ERR(data->int_clk)) {
-		dev_err(dev, "Cannot get clock \"int_clk\"\n");
-		return PTR_ERR(data->int_clk);
+	for (i = 0; i < ARRAY_SIZE(exynos5_int_clks); i++) {
+		struct int_clk *clk_info = &exynos5_int_clks[i];
+
+		clk_info->clk = devm_clk_get(dev, clk_info->clk_name);
+		if (IS_ERR(clk_info->clk)) {
+			dev_err(dev, "Failed to get clock %s\n",
+				clk_info->clk_name);
+			return PTR_ERR(clk_info->clk);
+		}
 	}
 
 	rcu_read_lock();
@@ -320,16 +427,16 @@  static int exynos5_busfreq_int_probe(struct platform_device *pdev)
 	rcu_read_unlock();
 	data->curr_freq = initial_freq;
 
-	err = clk_set_rate(data->int_clk, initial_freq * 1000);
+	err = exynos5_int_setvolt(data, initial_volt);
+	if (err)
+		return err;
+
+	err = exynos5_int_set_rate(data, initial_freq);
 	if (err) {
 		dev_err(dev, "Failed to set initial frequency\n");
 		return err;
 	}
 
-	err = exynos5_int_setvolt(data, initial_volt);
-	if (err)
-		return err;
-
 	platform_set_drvdata(pdev, data);
 
 	busfreq_mon_reset(ppmu_data);