Re: [v0 2/2] cpufreq: qcom-fw: Add support for QCOM cpufreq FW driver

2018-05-18 Thread kbuild test robot
Hi Taniya,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on pm/linux-next]
[also build test ERROR on v4.17-rc5 next-20180517]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/Taniya-Das/Add-support-for-QCOM-cpufreq-FW-driver/20180519-050902
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git 
linux-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget 
https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O 
~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm 

All errors (new ones prefixed by >>):

   drivers/cpufreq/qcom-cpufreq-fw.c: In function 'qcom_cpufreq_fw_cpu_init':
>> drivers/cpufreq/qcom-cpufreq-fw.c:77:8: error: 'struct cpufreq_policy' has 
>> no member named 'table'
 policy->table = c->table;
   ^~
   drivers/cpufreq/qcom-cpufreq-fw.c: In function 'qcom_cpu_resources_init':
>> drivers/cpufreq/qcom-cpufreq-fw.c:187:37: error: passing argument 1 of 
>> 'platform_get_resource_byname' from incompatible pointer type 
>> [-Werror=incompatible-pointer-types]
 res = platform_get_resource_byname(dev, IORESOURCE_MEM, "en_base");
^~~
   In file included from include/linux/of_device.h:6:0,
from include/linux/of_platform.h:12,
from drivers/cpufreq/qcom-cpufreq-fw.c:11:
   include/linux/platform_device.h:56:25: note: expected 'struct 
platform_device *' but argument is of type 'struct device *'
extern struct resource *platform_get_resource_byname(struct platform_device 
*,
^~~~
>> drivers/cpufreq/qcom-cpufreq-fw.c:187:6: error: incompatible types when 
>> assigning to type 'struct resource' from type 'struct resource *'
 res = platform_get_resource_byname(dev, IORESOURCE_MEM, "en_base");
 ^
>> drivers/cpufreq/qcom-cpufreq-fw.c:188:6: error: wrong type argument to unary 
>> exclamation mark
 if (!res) {
 ^
>> drivers/cpufreq/qcom-cpufreq-fw.c:193:33: error: invalid type argument of 
>> '->' (have 'struct resource')
 en_base = devm_ioremap(dev, res->start, resource_size(res));
^~
>> drivers/cpufreq/qcom-cpufreq-fw.c:193:56: error: incompatible type for 
>> argument 1 of 'resource_size'
 en_base = devm_ioremap(dev, res->start, resource_size(res));
   ^~~
   In file included from include/linux/of_address.h:4:0,
from drivers/cpufreq/qcom-cpufreq-fw.c:10:
   include/linux/ioport.h:196:31: note: expected 'const struct resource *' but 
argument is of type 'struct resource'
static inline resource_size_t resource_size(const struct resource *res)
  ^
   cc1: some warnings being treated as errors

vim +77 drivers/cpufreq/qcom-cpufreq-fw.c

  > 11  #include 
12  
13  #define INIT_RATE   3UL
14  #define XO_RATE 1920UL
15  #define LUT_MAX_ENTRIES 40U
16  #define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16)
17  #define LUT_ROW_SIZE32
18  
19  struct cpufreq_qcom {
20  struct cpufreq_frequency_table *table;
21  struct device *dev;
22  void __iomem *perf_base;
23  void __iomem *lut_base;
24  cpumask_t related_cpus;
25  unsigned int max_cores;
26  };
27  
28  static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS];
29  
30  static int
31  qcom_cpufreq_fw_target_index(struct cpufreq_policy *policy, unsigned 
int index)
32  {
33  struct cpufreq_qcom *c = policy->driver_data;
34  
35  if (index >= LUT_MAX_ENTRIES) {
36  dev_err(c->dev,
37  "Passing an index (%u) that's greater than max (%d)\n",
38  index, LUT_MAX_ENTRIES - 1);
39  return -EINVAL;
40  }
41  
42  writel_relaxed(index, c->perf_base);
43  
44  /* Make sure the write goes through before proceeding */
45  mb();
46  return 0;
47  }
48  
49  static unsigned int qcom_cpufreq_fw_get(unsigned int cpu)
50  {
51  struct cpufreq_qcom *c;
52  unsigned int index;
53  
54  c = qcom_freq_domain_map[cpu];
55  if (!c)
56  return -ENODEV;
57  
58  index = readl_relaxed(c->perf_base);
59  index = min(index, LUT_MAX_ENTRIES - 1);
60  
61  return c->t

Re: [v0 2/2] cpufreq: qcom-fw: Add support for QCOM cpufreq FW driver

2018-05-17 Thread Saravana Kannan

On 05/17/2018 03:14 AM, Viresh Kumar wrote:

On 17-05-18, 15:00, Taniya Das wrote:

The CPUfreq FW present in some QCOM chipsets offloads the steps necessary
for hanging the frequency of CPUs. The driver implements the cpufreq driver
interface for this firmware.

Signed-off-by: Taniya Das 
---

  
##
diff --git a/drivers/cpufreq/qcom-cpufreq-fw.c 
b/drivers/cpufreq/qcom-cpufreq-fw.c



+
+static int qcom_read_lut(struct platform_device *pdev,
+   struct cpufreq_qcom *c)
+{
+   struct device *dev = &pdev->dev;
+   u32 data, src, lval, i, core_count, prev_cc = 0;
+
+   c->table = devm_kcalloc(dev, LUT_MAX_ENTRIES + 1,
+   sizeof(*c->table), GFP_KERNEL);
+   if (!c->table)
+   return -ENOMEM;
+
+   for (i = 0; i < LUT_MAX_ENTRIES; i++) {
+   data = readl_relaxed(c->lut_base + i * LUT_ROW_SIZE);
+   src = ((data & GENMASK(31, 30)) >> 30);
+   lval = (data & GENMASK(7, 0));
+   core_count = CORE_COUNT_VAL(data);


Why do you need this here ? And why do below in case this doesn't
match max-cores count ?


This is how we detect boost frequencies.


+
+   if (!src)
+   c->table[i].frequency = INIT_RATE / 1000;
+   else
+   c->table[i].frequency = XO_RATE * lval / 1000;
+
+   c->table[i].driver_data = c->table[i].frequency;
+
+   dev_dbg(dev, "index=%d freq=%d, core_count %d\n",
+   i, c->table[i].frequency, core_count);
+
+   if (core_count != c->max_cores)
+   c->table[i].frequency = CPUFREQ_ENTRY_INVALID;


The FW might has some frequencies marked as "boost frequencies" when 
there are higher non-boost frequencies. So, we mark them as invalid.



+
+   /*
+* Two of the same frequencies with the same core counts means
+* end of table.
+*/
+   if (i > 0 && c->table[i - 1].driver_data ==
+   c->table[i].driver_data
+   && prev_cc == core_count) {
+   struct cpufreq_frequency_table *prev = &c->table[i - 1];
+
+   if (prev->frequency == CPUFREQ_ENTRY_INVALID) {
+   prev->flags = CPUFREQ_BOOST_FREQ;
+   prev->frequency = prev->driver_data;
+   }
+
+   break;
+   }
+   prev_cc = core_count;
+   }
+   c->table[i].frequency = CPUFREQ_TABLE_END;
+
+   return 0;
+}
+
+static int qcom_get_related_cpus(struct device_node *np, struct cpumask *m)
+{
+   struct device_node *dev_phandle;
+   struct device *cpu_dev;
+   int cpu, i = 0, ret = -ENOENT;
+
+   dev_phandle = of_parse_phandle(np, "qcom,cpulist", i++);


TBH, I am not a great fan of the CPU phandle list you have created
here. Lets see what Rob has to say on this.



Neither do we, but this is the only real way of mapping the logical CPU 
numbers to the real CPUs in HW that belong to the same freq domain. 
Because boot CPU is always going to be CPU0 if I'm not mistaken.



+   while (dev_phandle) {
+   for_each_possible_cpu(cpu) {
+   cpu_dev = get_cpu_device(cpu);
+   if (cpu_dev && cpu_dev->of_node == dev_phandle) {
+   cpumask_set_cpu(cpu, m);
+   ret = 0;


Maybe just remove this line ...


+   break;
+   }
+   }
+   dev_phandle = of_parse_phandle(np, "qcom,cpulist", i++);
+   }
+
+   return ret;



--
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


Re: [v0 2/2] cpufreq: qcom-fw: Add support for QCOM cpufreq FW driver

2018-05-17 Thread Taniya Das

Hi Viresh,

Thanks for the review comments, I have already fixed the resource 
comment in the v1 series which I sent across. I will fix the rest of the 
comments and send it for review.


On 5/17/2018 3:44 PM, Viresh Kumar wrote:

On 17-05-18, 15:00, Taniya Das wrote:

The CPUfreq FW present in some QCOM chipsets offloads the steps necessary
for hanging the frequency of CPUs. The driver implements the cpufreq driver
interface for this firmware.

Signed-off-by: Taniya Das 
---
  drivers/cpufreq/Kconfig.arm   |   9 ++
  drivers/cpufreq/Makefile  |   1 +
  drivers/cpufreq/qcom-cpufreq-fw.c | 318 ++
  3 files changed, 328 insertions(+)
  create mode 100644 drivers/cpufreq/qcom-cpufreq-fw.c

diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 96b35b8..a50aa6e 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -301,3 +301,12 @@ config ARM_PXA2xx_CPUFREQ
  This add the CPUFreq driver support for Intel PXA2xx SOCs.

  If in doubt, say N.
+
+config ARM_QCOM_CPUFREQ_FW
+   tristate "QCOM CPUFreq FW driver"
+   help
+Support for the CPUFreq FW driver.
+The CPUfreq FW preset in some QCOM chipsets offloads the steps
+necessary for changing the frequency of CPUs. The driver
+implements the cpufreq driver interface for this firmware.
+Say Y if you want to support CPUFreq FW.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 8d24ade..a3edbce 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)+= tegra124-cpufreq.o
  obj-$(CONFIG_ARM_TEGRA186_CPUFREQ)+= tegra186-cpufreq.o
  obj-$(CONFIG_ARM_TI_CPUFREQ)  += ti-cpufreq.o
  obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ)+= vexpress-spc-cpufreq.o
+obj-$(CONFIG_ARM_QCOM_CPUFREQ_FW)  += qcom-cpufreq-fw.o


  
##
diff --git a/drivers/cpufreq/qcom-cpufreq-fw.c 
b/drivers/cpufreq/qcom-cpufreq-fw.c
new file mode 100644
index 000..67996d5
--- /dev/null
+++ b/drivers/cpufreq/qcom-cpufreq-fw.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define INIT_RATE  3UL
+#define XO_RATE1920UL
+#define LUT_MAX_ENTRIES40U
+#define CORE_COUNT_VAL(val)((val & GENMASK(18, 16)) >> 16)
+#define LUT_ROW_SIZE   32
+
+struct cpufreq_qcom {
+   struct cpufreq_frequency_table *table;
+   struct device *dev;
+   void __iomem *perf_base;
+   void __iomem *lut_base;
+   cpumask_t related_cpus;
+   unsigned int max_cores;
+};
+
+static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS];
+
+static int
+qcom_cpufreq_fw_target_index(struct cpufreq_policy *policy, unsigned int index)
+{
+   struct cpufreq_qcom *c = policy->driver_data;
+
+   if (index >= LUT_MAX_ENTRIES) {
+   dev_err(c->dev,
+   "Passing an index (%u) that's greater than max (%d)\n",


Alignment issues here. Run checkpatch --strict.


+   index, LUT_MAX_ENTRIES - 1);
+   return -EINVAL;
+   }
+
+   writel_relaxed(index, c->perf_base);
+
+   /* Make sure the write goes through before proceeding */
+   mb();
+   return 0;
+}
+
+static unsigned int qcom_cpufreq_fw_get(unsigned int cpu)
+{
+   struct cpufreq_qcom *c;
+   unsigned int index;
+
+   c = qcom_freq_domain_map[cpu];
+   if (!c)
+   return -ENODEV;
+
+   index = readl_relaxed(c->perf_base);
+   index = min(index, LUT_MAX_ENTRIES - 1);
+
+   return c->table[index].frequency;
+}
+
+static int qcom_cpufreq_fw_cpu_init(struct cpufreq_policy *policy)
+{
+   struct cpufreq_qcom *c;
+   int ret;
+
+   c = qcom_freq_domain_map[policy->cpu];
+   if (!c) {
+   pr_err("No scaling support for CPU%d\n", policy->cpu);
+   return -ENODEV;
+   }
+
+   cpumask_copy(policy->cpus, &c->related_cpus);
+
+   policy->table = c->table;
+   policy->driver_data = c;
+
+   return ret;
+}
+
+static struct freq_attr *qcom_cpufreq_fw_attr[] = {
+   &cpufreq_freq_attr_scaling_available_freqs,
+   &cpufreq_freq_attr_scaling_boost_freqs,
+   NULL
+};
+
+static struct cpufreq_driver cpufreq_qcom_fw_driver = {
+   .flags  = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+ CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
+   .verify = cpufreq_generic_frequency_table_verify,
+   .target_index   = qcom_cpufreq_fw_target_index,
+   .get= qcom_cpufreq_fw_get,
+   .init   = qcom_cpufreq_fw_cpu_init,
+   .name 

Re: [v0 2/2] cpufreq: qcom-fw: Add support for QCOM cpufreq FW driver

2018-05-17 Thread Amit Kucheria
On Thu, May 17, 2018 at 12:30 PM, Taniya Das  wrote:
> The CPUfreq FW present in some QCOM chipsets offloads the steps necessary
> for hanging the frequency of CPUs. The driver implements the cpufreq driver

s/hanging/changing :-)

> interface for this firmware.
>
> Signed-off-by: Taniya Das 
> ---
>  drivers/cpufreq/Kconfig.arm   |   9 ++
>  drivers/cpufreq/Makefile  |   1 +
>  drivers/cpufreq/qcom-cpufreq-fw.c | 318 
> ++
>  3 files changed, 328 insertions(+)
>  create mode 100644 drivers/cpufreq/qcom-cpufreq-fw.c
>
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 96b35b8..a50aa6e 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -301,3 +301,12 @@ config ARM_PXA2xx_CPUFREQ
>   This add the CPUFreq driver support for Intel PXA2xx SOCs.
>
>   If in doubt, say N.
> +
> +config ARM_QCOM_CPUFREQ_FW
> +   tristate "QCOM CPUFreq FW driver"
> +   help
> +Support for the CPUFreq FW driver.
> +The CPUfreq FW preset in some QCOM chipsets offloads the steps
> +necessary for changing the frequency of CPUs. The driver
> +implements the cpufreq driver interface for this firmware.
> +Say Y if you want to support CPUFreq FW.
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 8d24ade..a3edbce 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -85,6 +85,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)+= tegra124-cpufreq.o
>  obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o
>  obj-$(CONFIG_ARM_TI_CPUFREQ)   += ti-cpufreq.o
>  obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
> +obj-$(CONFIG_ARM_QCOM_CPUFREQ_FW)  += qcom-cpufreq-fw.o
>
>
>  
> ##
> diff --git a/drivers/cpufreq/qcom-cpufreq-fw.c 
> b/drivers/cpufreq/qcom-cpufreq-fw.c
> new file mode 100644
> index 000..67996d5
> --- /dev/null
> +++ b/drivers/cpufreq/qcom-cpufreq-fw.c
> @@ -0,0 +1,318 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018, The Linux Foundation. All rights reserved.
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#define INIT_RATE  3UL
> +#define XO_RATE1920UL
> +#define LUT_MAX_ENTRIES40U
> +#define CORE_COUNT_VAL(val)((val & GENMASK(18, 16)) >> 16)
> +#define LUT_ROW_SIZE   32
> +
> +struct cpufreq_qcom {
> +   struct cpufreq_frequency_table *table;
> +   struct device *dev;
> +   void __iomem *perf_base;
> +   void __iomem *lut_base;
> +   cpumask_t related_cpus;
> +   unsigned int max_cores;
> +};
> +
> +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS];
> +
> +static int
> +qcom_cpufreq_fw_target_index(struct cpufreq_policy *policy, unsigned int 
> index)
> +{
> +   struct cpufreq_qcom *c = policy->driver_data;
> +
> +   if (index >= LUT_MAX_ENTRIES) {
> +   dev_err(c->dev,
> +   "Passing an index (%u) that's greater than max (%d)\n",
> +   index, LUT_MAX_ENTRIES - 1);
> +   return -EINVAL;
> +   }
> +
> +   writel_relaxed(index, c->perf_base);
> +
> +   /* Make sure the write goes through before proceeding */
> +   mb();
> +   return 0;
> +}
> +
> +static unsigned int qcom_cpufreq_fw_get(unsigned int cpu)
> +{
> +   struct cpufreq_qcom *c;
> +   unsigned int index;
> +
> +   c = qcom_freq_domain_map[cpu];
> +   if (!c)
> +   return -ENODEV;
> +
> +   index = readl_relaxed(c->perf_base);
> +   index = min(index, LUT_MAX_ENTRIES - 1);
> +
> +   return c->table[index].frequency;
> +}
> +
> +static int qcom_cpufreq_fw_cpu_init(struct cpufreq_policy *policy)
> +{
> +   struct cpufreq_qcom *c;
> +   int ret;
> +
> +   c = qcom_freq_domain_map[policy->cpu];
> +   if (!c) {
> +   pr_err("No scaling support for CPU%d\n", policy->cpu);
> +   return -ENODEV;
> +   }
> +
> +   cpumask_copy(policy->cpus, &c->related_cpus);
> +
> +   policy->table = c->table;
> +   policy->driver_data = c;
> +
> +   return ret;
> +}
> +
> +static struct freq_attr *qcom_cpufreq_fw_attr[] = {
> +   &cpufreq_freq_attr_scaling_available_freqs,
> +   &cpufreq_freq_attr_scaling_boost_freqs,
> +   NULL
> +};
> +
> +static struct cpufreq_driver cpufreq_qcom_fw_driver = {
> +   .flags  = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
> + CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
> +   .verify = cpufreq_generic_frequency_table_verify,
> +   .target_index   = qcom_cpufreq_fw_target_index,
> +   .get= qcom_cpufreq_fw_get,
> +   .init   = qcom_cpufr

Re: [v0 2/2] cpufreq: qcom-fw: Add support for QCOM cpufreq FW driver

2018-05-17 Thread Viresh Kumar
On 17-05-18, 15:00, Taniya Das wrote:
> The CPUfreq FW present in some QCOM chipsets offloads the steps necessary
> for hanging the frequency of CPUs. The driver implements the cpufreq driver
> interface for this firmware.
> 
> Signed-off-by: Taniya Das 
> ---
>  drivers/cpufreq/Kconfig.arm   |   9 ++
>  drivers/cpufreq/Makefile  |   1 +
>  drivers/cpufreq/qcom-cpufreq-fw.c | 318 
> ++
>  3 files changed, 328 insertions(+)
>  create mode 100644 drivers/cpufreq/qcom-cpufreq-fw.c
> 
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 96b35b8..a50aa6e 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -301,3 +301,12 @@ config ARM_PXA2xx_CPUFREQ
> This add the CPUFreq driver support for Intel PXA2xx SOCs.
> 
> If in doubt, say N.
> +
> +config ARM_QCOM_CPUFREQ_FW
> + tristate "QCOM CPUFreq FW driver"
> + help
> +  Support for the CPUFreq FW driver.
> +  The CPUfreq FW preset in some QCOM chipsets offloads the steps
> +  necessary for changing the frequency of CPUs. The driver
> +  implements the cpufreq driver interface for this firmware.
> +  Say Y if you want to support CPUFreq FW.
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 8d24ade..a3edbce 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -85,6 +85,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)  += tegra124-cpufreq.o
>  obj-$(CONFIG_ARM_TEGRA186_CPUFREQ)   += tegra186-cpufreq.o
>  obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o
>  obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ)   += vexpress-spc-cpufreq.o
> +obj-$(CONFIG_ARM_QCOM_CPUFREQ_FW)+= qcom-cpufreq-fw.o
> 
> 
>  
> ##
> diff --git a/drivers/cpufreq/qcom-cpufreq-fw.c 
> b/drivers/cpufreq/qcom-cpufreq-fw.c
> new file mode 100644
> index 000..67996d5
> --- /dev/null
> +++ b/drivers/cpufreq/qcom-cpufreq-fw.c
> @@ -0,0 +1,318 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018, The Linux Foundation. All rights reserved.
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#define INIT_RATE3UL
> +#define XO_RATE  1920UL
> +#define LUT_MAX_ENTRIES  40U
> +#define CORE_COUNT_VAL(val)  ((val & GENMASK(18, 16)) >> 16)
> +#define LUT_ROW_SIZE 32
> +
> +struct cpufreq_qcom {
> + struct cpufreq_frequency_table *table;
> + struct device *dev;
> + void __iomem *perf_base;
> + void __iomem *lut_base;
> + cpumask_t related_cpus;
> + unsigned int max_cores;
> +};
> +
> +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS];
> +
> +static int
> +qcom_cpufreq_fw_target_index(struct cpufreq_policy *policy, unsigned int 
> index)
> +{
> + struct cpufreq_qcom *c = policy->driver_data;
> +
> + if (index >= LUT_MAX_ENTRIES) {
> + dev_err(c->dev,
> + "Passing an index (%u) that's greater than max (%d)\n",

Alignment issues here. Run checkpatch --strict.

> + index, LUT_MAX_ENTRIES - 1);
> + return -EINVAL;
> + }
> +
> + writel_relaxed(index, c->perf_base);
> +
> + /* Make sure the write goes through before proceeding */
> + mb();
> + return 0;
> +}
> +
> +static unsigned int qcom_cpufreq_fw_get(unsigned int cpu)
> +{
> + struct cpufreq_qcom *c;
> + unsigned int index;
> +
> + c = qcom_freq_domain_map[cpu];
> + if (!c)
> + return -ENODEV;
> +
> + index = readl_relaxed(c->perf_base);
> + index = min(index, LUT_MAX_ENTRIES - 1);
> +
> + return c->table[index].frequency;
> +}
> +
> +static int qcom_cpufreq_fw_cpu_init(struct cpufreq_policy *policy)
> +{
> + struct cpufreq_qcom *c;
> + int ret;
> +
> + c = qcom_freq_domain_map[policy->cpu];
> + if (!c) {
> + pr_err("No scaling support for CPU%d\n", policy->cpu);
> + return -ENODEV;
> + }
> +
> + cpumask_copy(policy->cpus, &c->related_cpus);
> +
> + policy->table = c->table;
> + policy->driver_data = c;
> +
> + return ret;
> +}
> +
> +static struct freq_attr *qcom_cpufreq_fw_attr[] = {
> + &cpufreq_freq_attr_scaling_available_freqs,
> + &cpufreq_freq_attr_scaling_boost_freqs,
> + NULL
> +};
> +
> +static struct cpufreq_driver cpufreq_qcom_fw_driver = {
> + .flags  = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
> +   CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
> + .verify = cpufreq_generic_frequency_table_verify,
> + .target_index   = qcom_cpufreq_fw_target_index,
> + .get= qcom_cpufreq_fw_get,
> + .init   = qcom_cpufreq_fw_cpu_init,
> + .name   = "qcom-cpufreq-fw",
> + .attr   = qcom_cpufreq_fw_at

[v0 2/2] cpufreq: qcom-fw: Add support for QCOM cpufreq FW driver

2018-05-17 Thread Taniya Das
The CPUfreq FW present in some QCOM chipsets offloads the steps necessary
for hanging the frequency of CPUs. The driver implements the cpufreq driver
interface for this firmware.

Signed-off-by: Taniya Das 
---
 drivers/cpufreq/Kconfig.arm   |   9 ++
 drivers/cpufreq/Makefile  |   1 +
 drivers/cpufreq/qcom-cpufreq-fw.c | 318 ++
 3 files changed, 328 insertions(+)
 create mode 100644 drivers/cpufreq/qcom-cpufreq-fw.c

diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 96b35b8..a50aa6e 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -301,3 +301,12 @@ config ARM_PXA2xx_CPUFREQ
  This add the CPUFreq driver support for Intel PXA2xx SOCs.

  If in doubt, say N.
+
+config ARM_QCOM_CPUFREQ_FW
+   tristate "QCOM CPUFreq FW driver"
+   help
+Support for the CPUFreq FW driver.
+The CPUfreq FW preset in some QCOM chipsets offloads the steps
+necessary for changing the frequency of CPUs. The driver
+implements the cpufreq driver interface for this firmware.
+Say Y if you want to support CPUFreq FW.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 8d24ade..a3edbce 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)+= tegra124-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o
 obj-$(CONFIG_ARM_TI_CPUFREQ)   += ti-cpufreq.o
 obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
+obj-$(CONFIG_ARM_QCOM_CPUFREQ_FW)  += qcom-cpufreq-fw.o


 
##
diff --git a/drivers/cpufreq/qcom-cpufreq-fw.c 
b/drivers/cpufreq/qcom-cpufreq-fw.c
new file mode 100644
index 000..67996d5
--- /dev/null
+++ b/drivers/cpufreq/qcom-cpufreq-fw.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define INIT_RATE  3UL
+#define XO_RATE1920UL
+#define LUT_MAX_ENTRIES40U
+#define CORE_COUNT_VAL(val)((val & GENMASK(18, 16)) >> 16)
+#define LUT_ROW_SIZE   32
+
+struct cpufreq_qcom {
+   struct cpufreq_frequency_table *table;
+   struct device *dev;
+   void __iomem *perf_base;
+   void __iomem *lut_base;
+   cpumask_t related_cpus;
+   unsigned int max_cores;
+};
+
+static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS];
+
+static int
+qcom_cpufreq_fw_target_index(struct cpufreq_policy *policy, unsigned int index)
+{
+   struct cpufreq_qcom *c = policy->driver_data;
+
+   if (index >= LUT_MAX_ENTRIES) {
+   dev_err(c->dev,
+   "Passing an index (%u) that's greater than max (%d)\n",
+   index, LUT_MAX_ENTRIES - 1);
+   return -EINVAL;
+   }
+
+   writel_relaxed(index, c->perf_base);
+
+   /* Make sure the write goes through before proceeding */
+   mb();
+   return 0;
+}
+
+static unsigned int qcom_cpufreq_fw_get(unsigned int cpu)
+{
+   struct cpufreq_qcom *c;
+   unsigned int index;
+
+   c = qcom_freq_domain_map[cpu];
+   if (!c)
+   return -ENODEV;
+
+   index = readl_relaxed(c->perf_base);
+   index = min(index, LUT_MAX_ENTRIES - 1);
+
+   return c->table[index].frequency;
+}
+
+static int qcom_cpufreq_fw_cpu_init(struct cpufreq_policy *policy)
+{
+   struct cpufreq_qcom *c;
+   int ret;
+
+   c = qcom_freq_domain_map[policy->cpu];
+   if (!c) {
+   pr_err("No scaling support for CPU%d\n", policy->cpu);
+   return -ENODEV;
+   }
+
+   cpumask_copy(policy->cpus, &c->related_cpus);
+
+   policy->table = c->table;
+   policy->driver_data = c;
+
+   return ret;
+}
+
+static struct freq_attr *qcom_cpufreq_fw_attr[] = {
+   &cpufreq_freq_attr_scaling_available_freqs,
+   &cpufreq_freq_attr_scaling_boost_freqs,
+   NULL
+};
+
+static struct cpufreq_driver cpufreq_qcom_fw_driver = {
+   .flags  = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+ CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
+   .verify = cpufreq_generic_frequency_table_verify,
+   .target_index   = qcom_cpufreq_fw_target_index,
+   .get= qcom_cpufreq_fw_get,
+   .init   = qcom_cpufreq_fw_cpu_init,
+   .name   = "qcom-cpufreq-fw",
+   .attr   = qcom_cpufreq_fw_attr,
+   .boost_enabled  = true,
+};
+
+static int qcom_read_lut(struct platform_device *pdev,
+   struct cpufreq_qcom *c)
+{
+   struct device *dev = &pdev->dev;
+   u32 data, src, lval, i, core_count, prev_cc = 0;
+
+   c->ta