mbox series

[v2,0/9] Exynos Adaptive Supply Voltage support

Message ID 20190718143044.25066-1-s.nawrocki@samsung.com
Headers show
Series Exynos Adaptive Supply Voltage support | expand

Message

Sylwester Nawrocki July 18, 2019, 2:30 p.m. UTC
This is second iteration of patch series adding ASV (Adaptive Supply 
Voltage) support for Exynos SoCs. The first one can be found at:
https://lore.kernel.org/lkml/20190404171735.12815-1-s.nawrocki@samsung.com

The main changes comparing to the first (RFC) version are:
 - moving ASV data tables from DT to the driver,
 - converting the chipid and the ASV drivers to use regmap,
 - converting the ASV driver to proper platform driver.

I tried the opp-supported-hw bitmask approach as in the Qualcomm CPUFreq
DT bindings but it resulted in too many OPPs and DT nodes, around 200
per CPU cluster. So the ASV OPP tables are now in the ASV driver, as in
downstream kernels.  I might give it a try and restrucure these tables
to avoid data repetition.

This patch set includes Exynos CHIPID driver posted by Pankaj Dubey and
futher improved by Bartlomiej Zolnierkiewicz [1].

Tested on Odroid XU3, XU3 Lite, XU4.

One of the things on TODO list is support for the Adaptive Body Bias.
This will require modifications on the cpufreq driver side in order to 
support multiple voltage regulators and changes in the OPP framework 
to support adding OPPs with multiple voltages.

[1] https://lkml.org/lkml/2018/11/15/908

Pankaj Dubey (3):
  soc: samsung: Add exynos chipid driver support
  ARM: EXYNOS: enable exynos_chipid for ARCH_EXYNOS
  ARM64: EXYNOS: enable exynos_chipid for ARCH_EXYNOS

Sylwester Nawrocki (6):
  soc: samsung: Convert exynos-chipid driver to use the regmap API
  soc: samsung: Add Exynos Adaptive Supply Voltage driver
  ARM: EXYNOS: Enable exynos-asv driver for ARCH_EXYNOS
  soc: samsung: Update the CHIP ID DT binding documentation
  ARM: dts: Add "syscon" compatible string to chipid node
  ARM: dts: Add samsung,asv-bin property for odroidxu3-lite

 .../bindings/arm/samsung/exynos-chipid.txt    |  10 +-
 arch/arm/boot/dts/exynos5.dtsi                |   4 +-
 .../boot/dts/exynos5422-odroidxu3-lite.dts    |   4 +
 arch/arm/mach-exynos/Kconfig                  |   2 +
 arch/arm64/Kconfig.platforms                  |   1 +
 drivers/soc/samsung/Kconfig                   |  16 +
 drivers/soc/samsung/Makefile                  |   5 +
 drivers/soc/samsung/exynos-asv.c              | 185 +++++++
 drivers/soc/samsung/exynos-asv.h              |  82 +++
 drivers/soc/samsung/exynos-chipid.c           | 104 ++++
 drivers/soc/samsung/exynos5422-asv.c          | 499 ++++++++++++++++++
 drivers/soc/samsung/exynos5422-asv.h          |  25 +
 include/linux/soc/samsung/exynos-chipid.h     |  48 ++
 13 files changed, 981 insertions(+), 4 deletions(-)
 create mode 100644 drivers/soc/samsung/exynos-asv.c
 create mode 100644 drivers/soc/samsung/exynos-asv.h
 create mode 100644 drivers/soc/samsung/exynos-chipid.c
 create mode 100644 drivers/soc/samsung/exynos5422-asv.c
 create mode 100644 drivers/soc/samsung/exynos5422-asv.h
 create mode 100644 include/linux/soc/samsung/exynos-chipid.h

Comments

Viresh Kumar July 23, 2019, 2:04 a.m. UTC | #1
On 18-07-19, 16:30, Sylwester Nawrocki wrote:
> This is second iteration of patch series adding ASV (Adaptive Supply 
> Voltage) support for Exynos SoCs. The first one can be found at:
> https://lore.kernel.org/lkml/20190404171735.12815-1-s.nawrocki@samsung.com
> 
> The main changes comparing to the first (RFC) version are:
>  - moving ASV data tables from DT to the driver,
>  - converting the chipid and the ASV drivers to use regmap,
>  - converting the ASV driver to proper platform driver.
> 
> I tried the opp-supported-hw bitmask approach as in the Qualcomm CPUFreq
> DT bindings but it resulted in too many OPPs and DT nodes, around 200
> per CPU cluster. So the ASV OPP tables are now in the ASV driver, as in
> downstream kernels.

Hmm. Can you explain why do you have so many OPPs? How many
frequencies do you actually support per cluster and what all varies
per frequency based on hw ? How many hw version do u have ?

I am asking as the OPP core can be improved to support your case if
possible. But I need to understand the problem first.
Krzysztof Kozlowski July 23, 2019, 12:57 p.m. UTC | #2
On Thu, 18 Jul 2019 at 16:31, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
>
> From: Pankaj Dubey <pankaj.dubey@samsung.com>
>
> Exynos SoCs have Chipid, for identification of product IDs and SoC
> revisions. This patch intends to provide initialization code for all
> these functionalities, at the same time it provides some sysfs entries
> for accessing these information to user-space.
>
> This driver uses existing binding for exynos-chipid.
>
> Changes by Bartlomiej:
> - fixed return values on errors
> - removed bogus kfree_const()
> - added missing Exynos4210 EVT0 id
> - converted code to use EXYNOS_MASK define
> - fixed np use after of_node_put()
> - fixed too early use of dev_info()
> - made driver fail for unknown SoC-s
> - added SPDX tag
> - updated Copyrights
>
> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
> [m.szyprowski: for suggestion and code snippet of product_id_to_soc_id]
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> [s.nawrocki: updated copyright date]
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> ---
>  drivers/soc/samsung/Kconfig         |   5 ++
>  drivers/soc/samsung/Makefile        |   2 +
>  drivers/soc/samsung/exynos-chipid.c | 111 ++++++++++++++++++++++++++++
>  3 files changed, 118 insertions(+)
>  create mode 100644 drivers/soc/samsung/exynos-chipid.c
>
> diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
> index 2186285fda92..2905f5262197 100644
> --- a/drivers/soc/samsung/Kconfig
> +++ b/drivers/soc/samsung/Kconfig
> @@ -7,6 +7,11 @@ menuconfig SOC_SAMSUNG
>
>  if SOC_SAMSUNG
>
> +config EXYNOS_CHIPID
> +       bool "Exynos Chipid controller driver" if COMPILE_TEST
> +       depends on ARCH_EXYNOS || COMPILE_TEST
> +       select SOC_BUS
> +
>  config EXYNOS_PMU
>         bool "Exynos PMU controller driver" if COMPILE_TEST
>         depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST)
> diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
> index 29f294baac6e..3b6a8797416c 100644
> --- a/drivers/soc/samsung/Makefile
> +++ b/drivers/soc/samsung/Makefile
> @@ -1,4 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_EXYNOS_CHIPID)    += exynos-chipid.o
>  obj-$(CONFIG_EXYNOS_PMU)       += exynos-pmu.o
>
>  obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS)   += exynos3250-pmu.o exynos4-pmu.o \
> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
> new file mode 100644
> index 000000000000..78b123ee60c0
> --- /dev/null
> +++ b/drivers/soc/samsung/exynos-chipid.c
> @@ -0,0 +1,111 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2019 Samsung Electronics Co., Ltd.
> + *           http://www.samsung.com/
> + *
> + * EXYNOS - CHIP ID support
> + * Author: Pankaj Dubey <pankaj.dubey@samsung.com>
> + * Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> + */
> +
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>

Any changes here from my previous comments?

I have also one more new thought later.

> +#include <linux/slab.h>
> +#include <linux/sys_soc.h>
> +
> +#define EXYNOS_SUBREV_MASK     (0xF << 4)
> +#define EXYNOS_MAINREV_MASK    (0xF << 0)
> +#define EXYNOS_REV_MASK                (EXYNOS_SUBREV_MASK | EXYNOS_MAINREV_MASK)
> +#define EXYNOS_MASK            0xFFFFF000
> +
> +static const struct exynos_soc_id {
> +       const char *name;
> +       unsigned int id;
> +} soc_ids[] = {
> +       { "EXYNOS3250", 0xE3472000 },
> +       { "EXYNOS4210", 0x43200000 },   /* EVT0 revision */
> +       { "EXYNOS4210", 0x43210000 },
> +       { "EXYNOS4212", 0x43220000 },
> +       { "EXYNOS4412", 0xE4412000 },
> +       { "EXYNOS5250", 0x43520000 },
> +       { "EXYNOS5260", 0xE5260000 },
> +       { "EXYNOS5410", 0xE5410000 },
> +       { "EXYNOS5420", 0xE5420000 },
> +       { "EXYNOS5440", 0xE5440000 },
> +       { "EXYNOS5800", 0xE5422000 },
> +       { "EXYNOS7420", 0xE7420000 },
> +       { "EXYNOS5433", 0xE5433000 },
> +};
> +
> +static const char * __init product_id_to_soc_id(unsigned int product_id)
> +{
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(soc_ids); i++)
> +               if ((product_id & EXYNOS_MASK) == soc_ids[i].id)
> +                       return soc_ids[i].name;
> +       return NULL;
> +}
> +
> +int __init exynos_chipid_early_init(void)
> +{
> +       struct soc_device_attribute *soc_dev_attr;
> +       void __iomem *exynos_chipid_base;
> +       struct soc_device *soc_dev;
> +       struct device_node *root;
> +       struct device_node *np;
> +       u32 product_id;
> +       u32 revision;
> +
> +       /* look up for chipid node */
> +       np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-chipid");
> +       if (!np)
> +               return -ENODEV;
> +
> +       exynos_chipid_base = of_iomap(np, 0);
> +       of_node_put(np);
> +
> +       if (!exynos_chipid_base) {
> +               pr_err("Failed to map SoC chipid\n");
> +               return -ENXIO;
> +       }
> +
> +       product_id = readl_relaxed(exynos_chipid_base);
> +       revision = product_id & EXYNOS_REV_MASK;
> +       iounmap(exynos_chipid_base);
> +
> +       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
> +       if (!soc_dev_attr)
> +               return -ENOMEM;
> +
> +       soc_dev_attr->family = "Samsung Exynos";
> +
> +       root = of_find_node_by_path("/");
> +       of_property_read_string(root, "model", &soc_dev_attr->machine);
> +       of_node_put(root);
> +
> +       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x", revision);
> +       soc_dev_attr->soc_id = product_id_to_soc_id(product_id);
> +       if (!soc_dev_attr->soc_id) {
> +               pr_err("Unknown SoC\n");

In case of running old kernel on unknown SoC (new revision of existing
one or older design not longer supported like 4415), the device will
not bind. This was added by Bartlomiej. Why? I imagine that soc driver
could be still matched and just report "Unknown". I am not sure if
this changes anything, though.

Best regards,
Krzysztof


> +               return -ENODEV;
> +       }
> +
> +       /* please note that the actual registration will be deferred */
> +       soc_dev = soc_device_register(soc_dev_attr);
> +       if (IS_ERR(soc_dev)) {
> +               kfree(soc_dev_attr->revision);
> +               kfree(soc_dev_attr);
> +               return PTR_ERR(soc_dev);
> +       }
> +
> +       /* it is too early to use dev_info() here (soc_dev is NULL) */
> +       pr_info("soc soc0: Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
> +               soc_dev_attr->soc_id, product_id, revision);
> +
> +       return 0;
> +}
> +early_initcall(exynos_chipid_early_init);
> --
> 2.17.1
>
Krzysztof Kozlowski July 23, 2019, 1:01 p.m. UTC | #3
On Thu, 18 Jul 2019 at 16:31, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
>
> Convert the driver to use regmap API in order to allow other
> drivers, like ASV, to access the CHIPID registers.
>
> This patch adds definition of selected CHIPID register offsets
> and register bit fields for Exynos5422 SoC.
>
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> ---
> Changes since v1 (RFC):
>  - new patch
> ---
>  drivers/soc/samsung/exynos-chipid.c       | 33 ++++++----------
>  include/linux/soc/samsung/exynos-chipid.h | 48 +++++++++++++++++++++++
>  2 files changed, 61 insertions(+), 20 deletions(-)
>  create mode 100644 include/linux/soc/samsung/exynos-chipid.h
>
> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
> index 78b123ee60c0..594b00488013 100644
> --- a/drivers/soc/samsung/exynos-chipid.c
> +++ b/drivers/soc/samsung/exynos-chipid.c
> @@ -9,18 +9,16 @@
>   */
>
>  #include <linux/io.h>
> +#include <linux/mfd/syscon.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
> +#include <linux/regmap.h>
>  #include <linux/slab.h>
> +#include <linux/soc/samsung/exynos-chipid.h>
>  #include <linux/sys_soc.h>
>
> -#define EXYNOS_SUBREV_MASK     (0xF << 4)
> -#define EXYNOS_MAINREV_MASK    (0xF << 0)
> -#define EXYNOS_REV_MASK                (EXYNOS_SUBREV_MASK | EXYNOS_MAINREV_MASK)
> -#define EXYNOS_MASK            0xFFFFF000
> -
>  static const struct exynos_soc_id {
>         const char *name;
>         unsigned int id;
> @@ -53,29 +51,24 @@ static const char * __init product_id_to_soc_id(unsigned int product_id)
>  int __init exynos_chipid_early_init(void)
>  {
>         struct soc_device_attribute *soc_dev_attr;
> -       void __iomem *exynos_chipid_base;
>         struct soc_device *soc_dev;
>         struct device_node *root;
> -       struct device_node *np;
> +       struct regmap *regmap;
>         u32 product_id;
>         u32 revision;
> +       int ret;
>
> -       /* look up for chipid node */
> -       np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-chipid");
> -       if (!np)
> -               return -ENODEV;
> -
> -       exynos_chipid_base = of_iomap(np, 0);
> -       of_node_put(np);
> -
> -       if (!exynos_chipid_base) {
> -               pr_err("Failed to map SoC chipid\n");
> -               return -ENXIO;
> +       regmap = syscon_regmap_lookup_by_compatible("samsung,exynos4210-chipid");
> +       if (IS_ERR(regmap)) {
> +               pr_err("%s: failed to get regmap\n", __func__);

Other places do not use __func__ prefix so make it consistent. Add it
in patch #1?

> +               return PTR_ERR(regmap);
>         }
>
> -       product_id = readl_relaxed(exynos_chipid_base);
> +       ret = regmap_read(regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id);
> +       if (ret < 0)
> +               return ret;
> +
>         revision = product_id & EXYNOS_REV_MASK;
> -       iounmap(exynos_chipid_base);
>
>         soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
>         if (!soc_dev_attr)
> diff --git a/include/linux/soc/samsung/exynos-chipid.h b/include/linux/soc/samsung/exynos-chipid.h
> new file mode 100644
> index 000000000000..25359d70d617
> --- /dev/null
> +++ b/include/linux/soc/samsung/exynos-chipid.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2018 Samsung Electronics Co., Ltd.
> + *           http://www.samsung.com/
> + *
> + * Exynos - CHIPID support
> + */
> +
> +#define EXYNOS_CHIPID_REG_PRO_ID       0x00
> + #define EXYNOS_SUBREV_MASK            (0xf << 4)

" #define" is unusual syntax. I think not used anywhere else. Stick to
regular one.

Best regards,
Krzysztof
Krzysztof Kozlowski July 23, 2019, 1:38 p.m. UTC | #4
On Thu, 18 Jul 2019 at 16:31, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
>
> The Adaptive Supply Voltage (ASV) driver adjusts CPU cluster operating
> points depending on exact revision of an SoC retrieved from the CHIPID
> block or the OTP memory.  This allows for some power saving as for some
> CPU clock frequencies we can lower CPU cluster supply voltage comparing
> to safe values common to the all chip revisions.
>
> This patch adds support for Exynos5422/5800 SoC, it is partially based
> on code from https://github.com/hardkernel/linux repository,
> branch odroidxu4-4.14.y, files: arch/arm/mach-exynos/exynos5422-asv.[ch].
>
> Tested on Odroid XU3, XU4, XU3 Lite.
>
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> ---
> Changes since v1 (RFC):
>  - removed code for parsing the ASV OPP tables from DT, the ASV OPP tables
>    moved to the driver;
>  - converted to use the regmap API;
>  - converted to normal platform driver.
> ---
>  drivers/soc/samsung/Kconfig          |  11 +
>  drivers/soc/samsung/Makefile         |   3 +
>  drivers/soc/samsung/exynos-asv.c     | 185 ++++++++++
>  drivers/soc/samsung/exynos-asv.h     |  82 +++++
>  drivers/soc/samsung/exynos5422-asv.c | 499 +++++++++++++++++++++++++++
>  drivers/soc/samsung/exynos5422-asv.h |  25 ++
>  6 files changed, 805 insertions(+)
>  create mode 100644 drivers/soc/samsung/exynos-asv.c
>  create mode 100644 drivers/soc/samsung/exynos-asv.h
>  create mode 100644 drivers/soc/samsung/exynos5422-asv.c
>  create mode 100644 drivers/soc/samsung/exynos5422-asv.h
>
> diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
> index 2905f5262197..539cd95dd176 100644
> --- a/drivers/soc/samsung/Kconfig
> +++ b/drivers/soc/samsung/Kconfig
> @@ -7,6 +7,17 @@ menuconfig SOC_SAMSUNG
>
>  if SOC_SAMSUNG
>
> +config EXYNOS_ASV
> +       bool "Exynos Adaptive Supply Voltage support" if COMPILE_TEST
> +       depends on ARCH_EXYNOS || COMPILE_TEST
> +       depends on EXYNOS_CHIPID

(ARCH_EXYNOS && EXYNOS_CHIPID) || COMPILE_TEST

> +       select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS
> +
> +# There is no need to enable these drivers for ARMv8
> +config EXYNOS_ASV_ARM
> +       bool "Exynos ASV ARMv7-specific driver extensions" if COMPILE_TEST
> +       depends on EXYNOS_ASV
> +
>  config EXYNOS_CHIPID
>         bool "Exynos Chipid controller driver" if COMPILE_TEST
>         depends on ARCH_EXYNOS || COMPILE_TEST
> diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
> index 3b6a8797416c..edd1d6ea064d 100644
> --- a/drivers/soc/samsung/Makefile
> +++ b/drivers/soc/samsung/Makefile
> @@ -1,5 +1,8 @@
>  # SPDX-License-Identifier: GPL-2.0
>
> +obj-$(CONFIG_EXYNOS_ASV)       += exynos-asv.o
> +obj-$(CONFIG_EXYNOS_ASV_ARM)   += exynos5422-asv.o
> +
>  obj-$(CONFIG_EXYNOS_CHIPID)    += exynos-chipid.o
>  obj-$(CONFIG_EXYNOS_PMU)       += exynos-pmu.o
>
> diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c
> new file mode 100644
> index 000000000000..b1a7e0ba8870
> --- /dev/null
> +++ b/drivers/soc/samsung/exynos-asv.c
> @@ -0,0 +1,185 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2019 Samsung Electronics Co., Ltd.
> + *           http://www.samsung.com/
> + * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
> + *
> + * Samsung Exynos SoC Adaptive Supply Voltage support
> + */
> +
> +#include <linux/cpu.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_opp.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/soc/samsung/exynos-chipid.h>
> +
> +#include "exynos-asv.h"
> +#include "exynos5422-asv.h"
> +
> +#define MHZ 1000000U
> +
> +static int exynos_asv_update_cpu_opps(struct exynos_asv *asv,
> +                                     struct device *cpu)
> +{
> +       struct exynos_asv_subsys *subsys = NULL;
> +       struct dev_pm_opp *opp;
> +       unsigned int opp_freq;
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(asv->subsys); i++) {
> +               if (of_device_is_compatible(cpu->of_node,
> +                                           asv->subsys[i].cpu_dt_compat)) {
> +                       subsys = &asv->subsys[i];
> +                       break;
> +               }
> +       }
> +       if (!subsys)
> +               return -EINVAL;
> +
> +       for (i = 0; i < subsys->table.num_rows; i++) {
> +               unsigned int new_voltage;
> +               unsigned int voltage;
> +               int timeout = 1000;
> +               int err;
> +
> +               opp_freq = exynos_asv_opp_get_frequency(subsys, i);
> +
> +               opp = dev_pm_opp_find_freq_exact(cpu, opp_freq * MHZ, true);
> +               if (IS_ERR(opp)) {
> +                       dev_info(asv->dev, "cpu%d opp%d, freq: %u missing\n",
> +                                cpu->id, i, opp_freq);
> +
> +                       continue;
> +               }
> +
> +               voltage = dev_pm_opp_get_voltage(opp);
> +               new_voltage = asv->opp_get_voltage(subsys, i, voltage);
> +               dev_pm_opp_put(opp);
> +
> +               opp_freq *= MHZ;
> +               dev_pm_opp_remove(cpu, opp_freq);
> +
> +               while (--timeout) {
> +                       opp = dev_pm_opp_find_freq_exact(cpu, opp_freq, true);
> +                       if (IS_ERR(opp))
> +                               break;
> +                       dev_pm_opp_put(opp);
> +                       msleep(1);
> +               }
> +
> +               err = dev_pm_opp_add(cpu, opp_freq, new_voltage);
> +               if (err < 0)
> +                       dev_err(asv->dev,
> +                               "Failed to add OPP %u Hz/%u uV for cpu%d\n",
> +                               opp_freq, new_voltage, cpu->id);
> +       }
> +
> +       return 0;
> +}
> +
> +static int exynos_asv_update_opps(struct exynos_asv *asv)
> +{
> +       struct opp_table *last_opp_table = NULL;
> +       struct device *cpu;
> +       int ret, cpuid;
> +
> +       for_each_possible_cpu(cpuid) {
> +               struct opp_table *opp_table;
> +
> +               cpu = get_cpu_device(cpuid);
> +               if (!cpu)
> +                       continue;
> +
> +               opp_table = dev_pm_opp_get_opp_table(cpu);
> +               if (IS_ERR(opp_table))
> +                       continue;
> +
> +               if (!last_opp_table || opp_table != last_opp_table) {
> +                       last_opp_table = opp_table;
> +
> +                       ret = exynos_asv_update_cpu_opps(asv, cpu);
> +                       if (ret < 0)
> +                               dev_err(asv->dev, "Couldn't udate OPPs for cpu%d\n",
> +                                       cpuid);
> +               }
> +
> +               dev_pm_opp_put_opp_table(opp_table);
> +       }
> +
> +       return  0;
> +}
> +
> +static int exynos_asv_probe(struct platform_device *pdev)
> +{
> +       int (*probe_func)(struct exynos_asv *asv);
> +       struct exynos_asv *asv;
> +       struct device *cpu_dev;
> +       u32 product_id = 0;
> +       int ret, i;
> +
> +       cpu_dev = get_cpu_device(0);
> +       ret = dev_pm_opp_get_opp_count(cpu_dev);
> +       if (ret < 0)
> +               return -EPROBE_DEFER;
> +
> +       asv = kcalloc(1, sizeof(*asv), GFP_KERNEL);
> +       if (!asv)
> +               return -ENOMEM;
> +
> +       asv->chipid_regmap = syscon_node_to_regmap(pdev->dev.of_node);
> +       if (IS_ERR(asv->chipid_regmap)) {
> +               dev_err(&pdev->dev, "Could not find syscon regmap\n");

Here and in following error-paths - kfree().

> +               return PTR_ERR(asv->chipid_regmap);
> +       }
> +
> +       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id);
> +
> +       switch (product_id & EXYNOS_MASK) {
> +       case 0xE5422000:
> +               probe_func = exynos5422_asv_init;
> +               break;
> +       default:
> +               dev_err(&pdev->dev, "Unsupported product ID: %#x", product_id);
> +               return -ENODEV;
> +       }
> +
> +       ret = of_property_read_u32(pdev->dev.of_node, "samsung,asv-bin",
> +                                  &asv->of_bin);
> +       if (ret < 0)
> +               asv->of_bin = -EINVAL;
> +
> +       asv->dev = &pdev->dev;
> +       dev_set_drvdata(&pdev->dev, asv);
> +
> +       for (i = 0; i < ARRAY_SIZE(asv->subsys); i++)
> +               asv->subsys[i].asv = asv;
> +
> +       ret = probe_func(asv);
> +       if (ret < 0)
> +               return ret;
> +
> +       return exynos_asv_update_opps(asv);
> +}
> +
> +static const struct of_device_id exynos_asv_of_device_ids[] = {
> +       { .compatible = "samsung,exynos4210-chipid" },
> +       {}
> +};
> +
> +static struct platform_driver exynos_asv_driver = {
> +       .driver = {
> +               .name = "exynos-asv",
> +               .of_match_table = exynos_asv_of_device_ids,
> +       },
> +       .probe  = exynos_asv_probe,
> +};
> +module_platform_driver(exynos_asv_driver);
> diff --git a/drivers/soc/samsung/exynos-asv.h b/drivers/soc/samsung/exynos-asv.h
> new file mode 100644
> index 000000000000..d0a5d603093d
> --- /dev/null
> +++ b/drivers/soc/samsung/exynos-asv.h
> @@ -0,0 +1,82 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2019 Samsung Electronics Co., Ltd.
> + *           http://www.samsung.com/
> + * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
> + *
> + * Samsung Exynos SoC Adaptive Supply Voltage support
> + */
> +#ifndef _EXYNOS_ASV_H
> +#define _EXYNOS_ASV_H

Here and in other header use prefix:
__LINUX_SOC_
(just like the existing exynos-pmu.h)

> +
> +enum {
> +       EXYNOS_ASV_SUBSYS_ID_ARM,
> +       EXYNOS_ASV_SUBSYS_ID_EGL = EXYNOS_ASV_SUBSYS_ID_ARM,
> +       EXYNOS_ASV_SUBSYS_ID_KFC,
> +       EXYNOS_ASV_SUBSYS_ID_INT,
> +       EXYNOS_ASV_SUBSYS_ID_MIF,
> +       EXYNOS_ASV_SUBSYS_ID_G3D,
> +       EXYNOS_ASV_SUBSYS_ID_CAM,
> +       EXYNOS_ASV_SUBSYS_ID_MAX
> +};
> +
> +struct regmap;
> +
> +/* HPM, IDS values to select target group */
> +struct asv_limit_entry {
> +       unsigned int hpm;
> +       unsigned int ids;
> +};
> +
> +struct exynos_asv_table {
> +       unsigned int num_rows;
> +       unsigned int num_cols;
> +       u32 *buf;
> +};
> +
> +struct exynos_asv_subsys {
> +       struct exynos_asv *asv;
> +       char *cpu_dt_compat;

const char *

> +       int id;
> +       struct exynos_asv_table table;
> +
> +       unsigned int base_volt;
> +       unsigned int offset_volt_h;
> +       unsigned int offset_volt_l;
> +};
> +
> +struct exynos_asv {
> +       struct device *dev;
> +       struct regmap *chipid_regmap;
> +       struct exynos_asv_subsys subsys[2];
> +
> +       int (*opp_get_voltage)(struct exynos_asv_subsys *subs, int level,
> +                              unsigned int voltage);
> +       unsigned int group;
> +       unsigned int table;
> +
> +       /* True if SG fields from PKG_ID register should be used */
> +       bool use_sg;
> +       /* ASV bin read from DT */
> +       int of_bin;
> +};
> +
> +static inline u32 __asv_get_table_entry(struct exynos_asv_table *table,
> +                                       unsigned int row, unsigned int col)
> +{
> +       return table->buf[row * (table->num_cols) + col];
> +}
> +
> +static inline u32 exynos_asv_opp_get_voltage(struct exynos_asv_subsys *subsys,
> +                                       unsigned int level, unsigned int group)
> +{
> +       return __asv_get_table_entry(&subsys->table, level, group + 1);
> +}
> +
> +static inline u32 exynos_asv_opp_get_frequency(struct exynos_asv_subsys *subsys,
> +                                       unsigned int level)
> +{
> +       return __asv_get_table_entry(&subsys->table, level, 0);
> +}
> +
> +#endif /* _EXYNOS_ASV_H */
> diff --git a/drivers/soc/samsung/exynos5422-asv.c b/drivers/soc/samsung/exynos5422-asv.c
> new file mode 100644
> index 000000000000..5fd673a6a733
> --- /dev/null
> +++ b/drivers/soc/samsung/exynos5422-asv.c
> @@ -0,0 +1,499 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2019 Samsung Electronics Co., Ltd.
> + *           http://www.samsung.com/
> + *
> + * Samsung Exynos 5422 SoC Adaptive Supply Voltage support
> + */
> +
> +#include <linux/bitrev.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>

Looks unused.

> +#include <linux/of.h>
> +#include <linux/regmap.h>
> +#include <linux/soc/samsung/exynos-chipid.h>
> +#include <linux/slab.h>
> +
> +#include "exynos-asv.h"
> +
> +#define ASV_GROUPS_NUM         14
> +#define ASV_ARM_DVFS_NUM       20
> +#define ASV_ARM_BIN2_DVFS_NUM  17
> +#define ASV_KFC_DVFS_NUM       14
> +#define ASV_KFC_BIN2_DVFS_NUM  12
> +
> +static const u32 asv_arm_table[][ASV_ARM_DVFS_NUM][ASV_GROUPS_NUM + 1] = {
> +{
> +       /* ARM 0, 1 */
> +       { 2100,    1362500, 1362500, 1350000, 1337500, 1325000, 1312500, 1300000,
> +         1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000 },
> +       { 2000,    1312500, 1312500, 1300000, 1287500, 1275000, 1262500, 1250000,
> +         1237500, 1225000, 1237500, 1225000, 1212500, 1200000, 1187500 },
> +       { 1900,    1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000,
> +         1162500, 1150000, 1162500, 1150000, 1137500, 1125000, 1112500 },
> +       { 1800,    1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000,
> +         1112500, 1100000, 1112500, 1100000, 1087500, 1075000, 1062500 },
> +       { 1700,    1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500,
> +         1075000, 1062500, 1075000, 1062500, 1050000, 1037500, 1025000 },
> +       { 1600,    1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000,
> +         1037500, 1025000, 1037500, 1025000, 1012500, 1000000, 987500 },
> +       { 1500,    1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500,
> +         1000000, 987500,  1000000, 987500,  975000,  962500,  950000 },
> +       { 1400,    1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
> +         975000,  962500,  975000,  962500,  950000,  937500,  925000 },
> +       { 1300,    1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000,
> +         962500,  950000,  962500,  950000,  937500,  925000,  912500 },
> +       { 1200,    1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
> +         937500,  925000,  937500,  925000,  912500,  900000,  900000 },
> +       { 1100,    1000000, 987500,  975000,  962500,  950000,  937500,  925000,
> +         912500,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 1000,    975000,  962500,  950000,  937500,  925000,  912500,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 900,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 800,     925000,  912500,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 700,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 600,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 500,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +}, {
> +       /* ARM 2 */
> +       { 2100,    1362500, 1362500, 1350000, 1337500, 1325000, 1312500, 1300000,
> +         1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000 },
> +       { 2000,    1312500, 1312500, 1312500, 1300000, 1275000, 1262500, 1250000,
> +         1237500, 1225000, 1237500, 1225000, 1212500, 1200000, 1187500 },
> +       { 1900,    1262500, 1250000, 1250000, 1237500, 1212500, 1200000, 1187500,
> +         1175000, 1162500, 1175000, 1162500, 1150000, 1137500, 1125000 },
> +       { 1800,    1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500,
> +         1125000, 1112500, 1125000, 1112500, 1100000, 1087500, 1075000 },
> +       { 1700,    1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
> +         1087500, 1075000, 1087500, 1075000, 1062500, 1050000, 1037500 },
> +       { 1600,    1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
> +         1050000, 1037500, 1050000, 1037500, 1025000, 1012500, 1000000 },
> +       { 1500,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
> +         1012500, 1000000, 1012500, 1000000, 987500,  975000,  962500 },
> +       { 1400,    1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000,
> +         987500,  975000,  987500,  975000,  962500,  950000,  937500 },
> +       { 1300,    1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000,
> +         962500,  950000,  962500,  950000,  937500,  925000,  912500 },
> +       { 1200,    1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
> +         937500,  925000,  937500,  925000,  912500,  900000,  900000 },
> +       { 1100,    1000000, 987500,  975000,  962500,  950000,  937500,  925000,
> +         912500,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 1000,    975000,  962500,  950000,  937500,  925000,  912500,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 900,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 800,     925000,  912500,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 700,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 600,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 500,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +}, {
> +       /* ARM 3 */
> +       { 2100,    1362500, 1362500, 1350000, 1337500, 1325000, 1312500, 1300000,
> +         1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000 },
> +       { 2000,    1312500, 1312500, 1300000, 1287500, 1275000, 1262500, 1250000,
> +         1237500, 1225000, 1237500, 1225000, 1212500, 1200000, 1187500 },
> +       { 1900,    1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500,
> +         1175000, 1162500, 1175000, 1162500, 1150000, 1137500, 1125000 },
> +       { 1800,    1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500,
> +         1125000, 1112500, 1125000, 1112500, 1100000, 1087500, 1075000 },
> +       { 1700,    1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
> +         1087500, 1075000, 1087500, 1075000, 1062500, 1050000, 1037500 },
> +       { 1600,    1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
> +         1050000, 1037500, 1050000, 1037500, 1025000, 1012500, 1000000 },
> +       { 1500,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
> +         1012500, 1000000, 1012500, 1000000, 987500,  975000,  962500 },
> +       { 1400,    1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000,
> +         987500,  975000,  987500,  975000,  962500,  950000,  937500 },
> +       { 1300,    1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000,
> +         962500,  950000,  962500,  950000,  937500,  925000,  912500 },
> +       { 1200,    1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
> +         937500,  925000,  937500,  925000,  912500,  900000,  900000 },
> +       { 1100,    1000000, 987500,  975000,  962500,  950000,  937500,  925000,
> +         912500,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 1000,    975000,  962500,  950000,  937500,  925000,  912500,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 900,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 800,     925000,  912500,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 700,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 600,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 500,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +}, {
> +       /* ARM bin 2 */
> +       { 1800,    1237500, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500,
> +         1150000, 1137500, 1150000, 1137500, 1125000, 1112500, 1100000 },
> +       { 1700,    1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000,
> +         1112500, 1100000, 1112500, 1100000, 1087500, 1075000, 1062500 },
> +       { 1600,    1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500,
> +         1075000, 1062500, 1075000, 1062500, 1050000, 1037500, 1025000 },
> +       { 1500,    1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000,
> +         1037500, 1025000, 1037500, 1025000, 1012500, 1000000, 987500 },
> +       { 1400,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
> +         1012500, 1000000, 1012500, 1000000, 987500,  975000,  962500 },
> +       { 1300,    1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500,
> +         1000000, 987500,  1000000, 987500,  975000,  962500,  950000 },
> +       { 1200,    1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
> +         975000,  962500,  975000,  962500,  950000,  937500,  925000 },
> +       { 1100,    1037500, 1025000, 1012500, 1000000, 987500,  975000,  962500,
> +         950000,  937500,  950000,  937500,  925000,  912500,  900000 },
> +       { 1000,    1012500, 1000000, 987500,  975000,  962500,  950000,  937500,
> +         925000,  912500,  925000,  912500,  900000,  900000,  900000 },
> +       { 900,     987500,  975000,  962500,  950000,  937500,  925000,  912500,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 800,     962500,  950000,  937500,  925000,  912500,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 700,     937500,  925000,  912500,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 600,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 500,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +}
> +};
> +
> +static const u32 asv_kfc_table[][ASV_KFC_DVFS_NUM][ASV_GROUPS_NUM + 1] = {
> +{
> +       /* KFC 0, 1 */
> +       { 1500000, 1300000, 1300000, 1300000, 1287500, 1287500, 1287500, 1275000,
> +         1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500 },
> +       { 1400000, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000,
> +         1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500 },
> +       { 1300000, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000,
> +         1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 },
> +       { 1200000, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
> +         1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500 },
> +       { 1100000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
> +         1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000 },
> +       { 1000000, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
> +         1012500, 1000000, 987500,  975000,  962500,  950000,  937500 },
> +       { 900000,  1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
> +         975000,  962500,  950000,  937500,  925000,  912500,  900000 },
> +       { 800000,  1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
> +         937500,  925000,  912500,  900000,  900000,  900000,  900000 },
> +       { 700000,  987500,  975000,  962500,  950000,  937500,  925000,  912500,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 600000,  950000,  937500,  925000,  912500,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 500000,  912500,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 400000,  900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 300000,  900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 200000,  900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +}, {
> +       /* KFC 2 */
> +       { 1500,    1300000, 1300000, 1300000, 1287500, 1287500, 1287500, 1275000,
> +         1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500 },
> +       { 1400,    1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000,
> +         1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500 },
> +       { 1300,    1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000,
> +         1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 },
> +       { 1200,    1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
> +         1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500 },
> +       { 1100,    1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
> +         1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000 },
> +       { 1000,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
> +         1012500, 1000000, 987500,  975000,  962500,  950000,  937500 },
> +       { 900,     1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
> +         975000,  962500,  950000,  937500,  925000,  912500,  900000 },
> +       { 800,     1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
> +         937500,  925000,  912500,  900000,  900000,  900000,  900000 },
> +       { 700,     987500,  975000,  962500,  950000,  937500,  925000,  912500,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 600,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 500,     912500,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +}, {
> +       /* KFC 3 */
> +       { 1500,    1300000, 1300000, 1300000, 1287500, 1287500, 1287500, 1275000,
> +         1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500 },
> +       { 1400,    1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000,
> +         1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500 },
> +       { 1300,    1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000,
> +         1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 },
> +       { 1200,    1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000,
> +         1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500 },
> +       { 1100,    1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500,
> +         1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000 },
> +       { 1000,    1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000,
> +         1012500, 1000000, 987500,  975000,  962500,  950000,  937500 },
> +       { 900,     1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500,
> +         975000,  962500,  950000,  937500,  925000,  912500,  900000 },
> +       { 800,     1025000, 1012500, 1000000, 987500,  975000,  962500,  950000,
> +         937500,  925000,  912500,  900000,  900000,  900000,  900000 },
> +       { 700,     987500,  975000,  962500,  950000,  937500,  925000,  912500,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 600,     950000,  937500,  925000,  912500,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 500,     912500,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 400,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +}, {
> +       /* KFC bin 2 */
> +       { 1300,    1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000,
> +         1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500 },
> +       { 1200,    1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000,
> +         1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500 },
> +       { 1100,    1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500,
> +         1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000 },
> +       { 1000,    1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000,
> +         1037500, 1025000, 1012500, 1000000, 987500,  975000,  962500 },
> +       { 900,     1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500,
> +         1000000, 987500,  975000,  962500,  950000,  937500,  925000 },
> +       { 800,     1050000, 1037500, 1025000, 1012500, 1000000, 987500,  975000,
> +         962500,  950000,  937500,  925000,  912500,  900000,  900000 },
> +       { 700,     1012500, 1000000, 987500,  975000,  962500,  950000,  937500,
> +         925000,  912500,  900000,  900000,  900000,  900000,  900000 },
> +       { 600,     975000,  962500,  950000,  937500,  925000,  912500,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 500,     937500,  925000,  912500,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 400,     925000,  912500,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 300,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +       { 200,     900000,  900000,  900000,  900000,  900000,  900000,  900000,
> +         900000,  900000,  900000,  900000,  900000,  900000,  900000 },
> +}
> +};
> +
> +static const struct asv_limit_entry __asv_limits[ASV_GROUPS_NUM] = {
> +       { 13, 55 },
> +       { 21, 65 },
> +       { 25, 69 },
> +       { 30, 72 },
> +       { 36, 74 },
> +       { 43, 76 },
> +       { 51, 78 },
> +       { 65, 80 },
> +       { 81, 82 },
> +       { 98, 84 },
> +       { 119, 87 },
> +       { 135, 89 },
> +       { 150, 92 },
> +       { 999, 999 },
> +};
> +
> +static int exynos5422_asv_get_group(struct exynos_asv *asv)
> +{
> +       unsigned int pkgid_reg, auxi_reg;
> +       int hpm, ids, i;
> +
> +       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PKG_ID, &pkgid_reg);
> +       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_AUX_INFO, &auxi_reg);
> +
> +       if (asv->use_sg) {
> +               u32 sga = (pkgid_reg >> EXYNOS5422_SG_A_OFFSET) &
> +                          EXYNOS5422_SG_A_MASK;
> +
> +               u32 sgb = (pkgid_reg >> EXYNOS5422_SG_B_OFFSET) &
> +                          EXYNOS5422_SG_B_MASK;
> +
> +               if ((pkgid_reg >> EXYNOS5422_SG_BSIGN_OFFSET) &
> +                    EXYNOS5422_SG_BSIGN_MASK)
> +                       return sga + sgb;
> +               else
> +                       return sga - sgb;
> +       }
> +
> +       hpm = (auxi_reg >> EXYNOS5422_TMCB_OFFSET) & EXYNOS5422_TMCB_MASK;
> +       ids = (pkgid_reg >> EXYNOS5422_IDS_OFFSET) & EXYNOS5422_IDS_MASK;
> +
> +       for (i = 0; i < ASV_GROUPS_NUM; i++) {
> +               if (ids <= __asv_limits[i].ids)
> +                       break;
> +               if (hpm <= __asv_limits[i].hpm)
> +                       break;
> +       }
> +       if (i < ASV_GROUPS_NUM)
> +               return i;
> +
> +       return 0;
> +}
> +
> +static int __asv_offset_voltage(unsigned int index)
> +{
> +       switch (index) {
> +       case 1:
> +               return 12500;
> +       case 2:
> +               return 50000;
> +       case 3:
> +               return 25000;
> +       default:
> +               return 0;
> +       };
> +}
> +
> +static void exynos5422_asv_offset_voltage_setup(struct exynos_asv *asv)
> +{
> +       struct exynos_asv_subsys *subsys;
> +       unsigned int reg, value;
> +
> +       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_AUX_INFO, &reg);
> +
> +       /* ARM offset voltage setup */
> +       subsys = &asv->subsys[EXYNOS_ASV_SUBSYS_ID_ARM];
> +
> +       subsys->base_volt = 1000000;
> +
> +       value = (reg >> EXYNOS5422_ARM_UP_OFFSET) & EXYNOS5422_ARM_UP_MASK;
> +       subsys->offset_volt_h = __asv_offset_voltage(value);
> +
> +       value = (reg >> EXYNOS5422_ARM_DN_OFFSET) & EXYNOS5422_ARM_DN_MASK;
> +       subsys->offset_volt_l = __asv_offset_voltage(value);
> +
> +       /* KFC offset voltage setup */
> +       subsys = &asv->subsys[EXYNOS_ASV_SUBSYS_ID_KFC];
> +
> +       subsys->base_volt = 1000000;
> +
> +       value = (reg >> EXYNOS5422_KFC_UP_OFFSET) & EXYNOS5422_KFC_UP_MASK;
> +       subsys->offset_volt_h = __asv_offset_voltage(value);
> +
> +       value = (reg >> EXYNOS5422_KFC_DN_OFFSET) & EXYNOS5422_KFC_DN_MASK;
> +       subsys->offset_volt_l = __asv_offset_voltage(value);
> +}
> +
> +static int exynos5422_asv_opp_get_voltage(struct exynos_asv_subsys *subsys,
> +                               int level, unsigned int volt)
> +{
> +       unsigned int asv_volt;
> +
> +       if (level >= subsys->table.num_rows)
> +               return volt;
> +
> +       asv_volt = exynos_asv_opp_get_voltage(subsys, level,
> +                                             subsys->asv->group);
> +
> +       if (volt > subsys->base_volt)
> +               asv_volt += subsys->offset_volt_h;
> +       else
> +               asv_volt += subsys->offset_volt_l;
> +
> +       return asv_volt;
> +}
> +
> +static unsigned int exynos5422_asv_parse_table(struct exynos_asv *asv,
> +                                     unsigned int pkg_id)
> +{
> +       return (pkg_id >> EXYNOS5422_TABLE_OFFSET) & EXYNOS5422_TABLE_MASK;
> +}
> +
> +static bool exynos5422_asv_parse_bin2(struct exynos_asv *asv,
> +                                    unsigned int pkg_id)
> +{
> +       return (pkg_id >> EXYNOS5422_BIN2_OFFSET) & EXYNOS5422_BIN2_MASK;

return !!() for converting to boolean.

> +}
> +
> +static bool exynos5422_asv_parse_sg(struct exynos_asv *asv,
> +                                       unsigned int pkg_id)
> +{
> +       return ((pkg_id >> EXYNOS5422_USESG_OFFSET) & EXYNOS5422_USESG_MASK);

Unneeded () over entire statement.

Best regards,
Krzysztof
Bartlomiej Zolnierkiewicz July 23, 2019, 2:10 p.m. UTC | #5
Hi Krzysztof,

On 7/23/19 2:57 PM, Krzysztof Kozlowski wrote:
> On Thu, 18 Jul 2019 at 16:31, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
>>
>> From: Pankaj Dubey <pankaj.dubey@samsung.com>
>>
>> Exynos SoCs have Chipid, for identification of product IDs and SoC
>> revisions. This patch intends to provide initialization code for all
>> these functionalities, at the same time it provides some sysfs entries
>> for accessing these information to user-space.
>>
>> This driver uses existing binding for exynos-chipid.
>>
>> Changes by Bartlomiej:
>> - fixed return values on errors
>> - removed bogus kfree_const()
>> - added missing Exynos4210 EVT0 id
>> - converted code to use EXYNOS_MASK define
>> - fixed np use after of_node_put()
>> - fixed too early use of dev_info()
>> - made driver fail for unknown SoC-s
>> - added SPDX tag
>> - updated Copyrights
>>
>> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
>> [m.szyprowski: for suggestion and code snippet of product_id_to_soc_id]
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
>> [s.nawrocki: updated copyright date]
>> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
>> ---
>>  drivers/soc/samsung/Kconfig         |   5 ++
>>  drivers/soc/samsung/Makefile        |   2 +
>>  drivers/soc/samsung/exynos-chipid.c | 111 ++++++++++++++++++++++++++++
>>  3 files changed, 118 insertions(+)
>>  create mode 100644 drivers/soc/samsung/exynos-chipid.c
>>
>> diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
>> index 2186285fda92..2905f5262197 100644
>> --- a/drivers/soc/samsung/Kconfig
>> +++ b/drivers/soc/samsung/Kconfig
>> @@ -7,6 +7,11 @@ menuconfig SOC_SAMSUNG
>>
>>  if SOC_SAMSUNG
>>
>> +config EXYNOS_CHIPID
>> +       bool "Exynos Chipid controller driver" if COMPILE_TEST
>> +       depends on ARCH_EXYNOS || COMPILE_TEST
>> +       select SOC_BUS
>> +
>>  config EXYNOS_PMU
>>         bool "Exynos PMU controller driver" if COMPILE_TEST
>>         depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST)
>> diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
>> index 29f294baac6e..3b6a8797416c 100644
>> --- a/drivers/soc/samsung/Makefile
>> +++ b/drivers/soc/samsung/Makefile
>> @@ -1,4 +1,6 @@
>>  # SPDX-License-Identifier: GPL-2.0
>> +
>> +obj-$(CONFIG_EXYNOS_CHIPID)    += exynos-chipid.o
>>  obj-$(CONFIG_EXYNOS_PMU)       += exynos-pmu.o
>>
>>  obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS)   += exynos3250-pmu.o exynos4-pmu.o \
>> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
>> new file mode 100644
>> index 000000000000..78b123ee60c0
>> --- /dev/null
>> +++ b/drivers/soc/samsung/exynos-chipid.c
>> @@ -0,0 +1,111 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2019 Samsung Electronics Co., Ltd.
>> + *           http://www.samsung.com/
>> + *
>> + * EXYNOS - CHIP ID support
>> + * Author: Pankaj Dubey <pankaj.dubey@samsung.com>
>> + * Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
>> + */
>> +
>> +#include <linux/io.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/platform_device.h>
> 
> Any changes here from my previous comments?
> 
> I have also one more new thought later.
> 
>> +#include <linux/slab.h>
>> +#include <linux/sys_soc.h>
>> +
>> +#define EXYNOS_SUBREV_MASK     (0xF << 4)
>> +#define EXYNOS_MAINREV_MASK    (0xF << 0)
>> +#define EXYNOS_REV_MASK                (EXYNOS_SUBREV_MASK | EXYNOS_MAINREV_MASK)
>> +#define EXYNOS_MASK            0xFFFFF000
>> +
>> +static const struct exynos_soc_id {
>> +       const char *name;
>> +       unsigned int id;
>> +} soc_ids[] = {
>> +       { "EXYNOS3250", 0xE3472000 },
>> +       { "EXYNOS4210", 0x43200000 },   /* EVT0 revision */
>> +       { "EXYNOS4210", 0x43210000 },
>> +       { "EXYNOS4212", 0x43220000 },
>> +       { "EXYNOS4412", 0xE4412000 },
>> +       { "EXYNOS5250", 0x43520000 },
>> +       { "EXYNOS5260", 0xE5260000 },
>> +       { "EXYNOS5410", 0xE5410000 },
>> +       { "EXYNOS5420", 0xE5420000 },
>> +       { "EXYNOS5440", 0xE5440000 },
>> +       { "EXYNOS5800", 0xE5422000 },
>> +       { "EXYNOS7420", 0xE7420000 },
>> +       { "EXYNOS5433", 0xE5433000 },
>> +};
>> +
>> +static const char * __init product_id_to_soc_id(unsigned int product_id)
>> +{
>> +       int i;
>> +
>> +       for (i = 0; i < ARRAY_SIZE(soc_ids); i++)
>> +               if ((product_id & EXYNOS_MASK) == soc_ids[i].id)
>> +                       return soc_ids[i].name;
>> +       return NULL;
>> +}
>> +
>> +int __init exynos_chipid_early_init(void)
>> +{
>> +       struct soc_device_attribute *soc_dev_attr;
>> +       void __iomem *exynos_chipid_base;
>> +       struct soc_device *soc_dev;
>> +       struct device_node *root;
>> +       struct device_node *np;
>> +       u32 product_id;
>> +       u32 revision;
>> +
>> +       /* look up for chipid node */
>> +       np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-chipid");
>> +       if (!np)
>> +               return -ENODEV;
>> +
>> +       exynos_chipid_base = of_iomap(np, 0);
>> +       of_node_put(np);
>> +
>> +       if (!exynos_chipid_base) {
>> +               pr_err("Failed to map SoC chipid\n");
>> +               return -ENXIO;
>> +       }
>> +
>> +       product_id = readl_relaxed(exynos_chipid_base);
>> +       revision = product_id & EXYNOS_REV_MASK;
>> +       iounmap(exynos_chipid_base);
>> +
>> +       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
>> +       if (!soc_dev_attr)
>> +               return -ENOMEM;
>> +
>> +       soc_dev_attr->family = "Samsung Exynos";
>> +
>> +       root = of_find_node_by_path("/");
>> +       of_property_read_string(root, "model", &soc_dev_attr->machine);
>> +       of_node_put(root);
>> +
>> +       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x", revision);
>> +       soc_dev_attr->soc_id = product_id_to_soc_id(product_id);
>> +       if (!soc_dev_attr->soc_id) {
>> +               pr_err("Unknown SoC\n");
> 
> In case of running old kernel on unknown SoC (new revision of existing
> one or older design not longer supported like 4415), the device will
> not bind. This was added by Bartlomiej. Why? I imagine that soc driver
> could be still matched and just report "Unknown". I am not sure if
> this changes anything, though.

I was thinking that we shouldn't be pretending that we know how to
handle unsupported SoCs, i.e. that we know how to correctly read its
product_id and revision.

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

> Best regards,
> Krzysztof
> 
> 
>> +               return -ENODEV;
>> +       }
>> +
>> +       /* please note that the actual registration will be deferred */
>> +       soc_dev = soc_device_register(soc_dev_attr);
>> +       if (IS_ERR(soc_dev)) {
>> +               kfree(soc_dev_attr->revision);
>> +               kfree(soc_dev_attr);
>> +               return PTR_ERR(soc_dev);
>> +       }
>> +
>> +       /* it is too early to use dev_info() here (soc_dev is NULL) */
>> +       pr_info("soc soc0: Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
>> +               soc_dev_attr->soc_id, product_id, revision);
>> +
>> +       return 0;
>> +}
>> +early_initcall(exynos_chipid_early_init);
>> --
>> 2.17.1
Krzysztof Kozlowski July 24, 2019, 10:47 a.m. UTC | #6
On Tue, 23 Jul 2019 at 16:10, Bartlomiej Zolnierkiewicz
<b.zolnierkie@samsung.com> wrote:
>
>
> Hi Krzysztof,
>
> On 7/23/19 2:57 PM, Krzysztof Kozlowski wrote:
> > On Thu, 18 Jul 2019 at 16:31, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
> >>
> >> From: Pankaj Dubey <pankaj.dubey@samsung.com>
> >>
> >> Exynos SoCs have Chipid, for identification of product IDs and SoC
> >> revisions. This patch intends to provide initialization code for all
> >> these functionalities, at the same time it provides some sysfs entries
> >> for accessing these information to user-space.
> >>
> >> This driver uses existing binding for exynos-chipid.
> >>
> >> Changes by Bartlomiej:
> >> - fixed return values on errors
> >> - removed bogus kfree_const()
> >> - added missing Exynos4210 EVT0 id
> >> - converted code to use EXYNOS_MASK define
> >> - fixed np use after of_node_put()
> >> - fixed too early use of dev_info()
> >> - made driver fail for unknown SoC-s
> >> - added SPDX tag
> >> - updated Copyrights
> >>
> >> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
> >> [m.szyprowski: for suggestion and code snippet of product_id_to_soc_id]
> >> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> >> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> >> [s.nawrocki: updated copyright date]
> >> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> >> ---
> >>  drivers/soc/samsung/Kconfig         |   5 ++
> >>  drivers/soc/samsung/Makefile        |   2 +
> >>  drivers/soc/samsung/exynos-chipid.c | 111 ++++++++++++++++++++++++++++
> >>  3 files changed, 118 insertions(+)
> >>  create mode 100644 drivers/soc/samsung/exynos-chipid.c
> >>
> >> diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
> >> index 2186285fda92..2905f5262197 100644
> >> --- a/drivers/soc/samsung/Kconfig
> >> +++ b/drivers/soc/samsung/Kconfig
> >> @@ -7,6 +7,11 @@ menuconfig SOC_SAMSUNG
> >>
> >>  if SOC_SAMSUNG
> >>
> >> +config EXYNOS_CHIPID
> >> +       bool "Exynos Chipid controller driver" if COMPILE_TEST
> >> +       depends on ARCH_EXYNOS || COMPILE_TEST
> >> +       select SOC_BUS
> >> +
> >>  config EXYNOS_PMU
> >>         bool "Exynos PMU controller driver" if COMPILE_TEST
> >>         depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST)
> >> diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
> >> index 29f294baac6e..3b6a8797416c 100644
> >> --- a/drivers/soc/samsung/Makefile
> >> +++ b/drivers/soc/samsung/Makefile
> >> @@ -1,4 +1,6 @@
> >>  # SPDX-License-Identifier: GPL-2.0
> >> +
> >> +obj-$(CONFIG_EXYNOS_CHIPID)    += exynos-chipid.o
> >>  obj-$(CONFIG_EXYNOS_PMU)       += exynos-pmu.o
> >>
> >>  obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS)   += exynos3250-pmu.o exynos4-pmu.o \
> >> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
> >> new file mode 100644
> >> index 000000000000..78b123ee60c0
> >> --- /dev/null
> >> +++ b/drivers/soc/samsung/exynos-chipid.c
> >> @@ -0,0 +1,111 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Copyright (c) 2019 Samsung Electronics Co., Ltd.
> >> + *           http://www.samsung.com/
> >> + *
> >> + * EXYNOS - CHIP ID support
> >> + * Author: Pankaj Dubey <pankaj.dubey@samsung.com>
> >> + * Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> >> + */
> >> +
> >> +#include <linux/io.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/of_platform.h>
> >> +#include <linux/platform_device.h>
> >
> > Any changes here from my previous comments?
> >
> > I have also one more new thought later.
> >
> >> +#include <linux/slab.h>
> >> +#include <linux/sys_soc.h>
> >> +
> >> +#define EXYNOS_SUBREV_MASK     (0xF << 4)
> >> +#define EXYNOS_MAINREV_MASK    (0xF << 0)
> >> +#define EXYNOS_REV_MASK                (EXYNOS_SUBREV_MASK | EXYNOS_MAINREV_MASK)
> >> +#define EXYNOS_MASK            0xFFFFF000
> >> +
> >> +static const struct exynos_soc_id {
> >> +       const char *name;
> >> +       unsigned int id;
> >> +} soc_ids[] = {
> >> +       { "EXYNOS3250", 0xE3472000 },
> >> +       { "EXYNOS4210", 0x43200000 },   /* EVT0 revision */
> >> +       { "EXYNOS4210", 0x43210000 },
> >> +       { "EXYNOS4212", 0x43220000 },
> >> +       { "EXYNOS4412", 0xE4412000 },
> >> +       { "EXYNOS5250", 0x43520000 },
> >> +       { "EXYNOS5260", 0xE5260000 },
> >> +       { "EXYNOS5410", 0xE5410000 },
> >> +       { "EXYNOS5420", 0xE5420000 },
> >> +       { "EXYNOS5440", 0xE5440000 },
> >> +       { "EXYNOS5800", 0xE5422000 },
> >> +       { "EXYNOS7420", 0xE7420000 },
> >> +       { "EXYNOS5433", 0xE5433000 },
> >> +};
> >> +
> >> +static const char * __init product_id_to_soc_id(unsigned int product_id)
> >> +{
> >> +       int i;
> >> +
> >> +       for (i = 0; i < ARRAY_SIZE(soc_ids); i++)
> >> +               if ((product_id & EXYNOS_MASK) == soc_ids[i].id)
> >> +                       return soc_ids[i].name;
> >> +       return NULL;
> >> +}
> >> +
> >> +int __init exynos_chipid_early_init(void)
> >> +{
> >> +       struct soc_device_attribute *soc_dev_attr;
> >> +       void __iomem *exynos_chipid_base;
> >> +       struct soc_device *soc_dev;
> >> +       struct device_node *root;
> >> +       struct device_node *np;
> >> +       u32 product_id;
> >> +       u32 revision;
> >> +
> >> +       /* look up for chipid node */
> >> +       np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-chipid");
> >> +       if (!np)
> >> +               return -ENODEV;
> >> +
> >> +       exynos_chipid_base = of_iomap(np, 0);
> >> +       of_node_put(np);
> >> +
> >> +       if (!exynos_chipid_base) {
> >> +               pr_err("Failed to map SoC chipid\n");
> >> +               return -ENXIO;
> >> +       }
> >> +
> >> +       product_id = readl_relaxed(exynos_chipid_base);
> >> +       revision = product_id & EXYNOS_REV_MASK;
> >> +       iounmap(exynos_chipid_base);
> >> +
> >> +       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
> >> +       if (!soc_dev_attr)
> >> +               return -ENOMEM;
> >> +
> >> +       soc_dev_attr->family = "Samsung Exynos";
> >> +
> >> +       root = of_find_node_by_path("/");
> >> +       of_property_read_string(root, "model", &soc_dev_attr->machine);
> >> +       of_node_put(root);
> >> +
> >> +       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x", revision);
> >> +       soc_dev_attr->soc_id = product_id_to_soc_id(product_id);
> >> +       if (!soc_dev_attr->soc_id) {
> >> +               pr_err("Unknown SoC\n");
> >
> > In case of running old kernel on unknown SoC (new revision of existing
> > one or older design not longer supported like 4415), the device will
> > not bind. This was added by Bartlomiej. Why? I imagine that soc driver
> > could be still matched and just report "Unknown". I am not sure if
> > this changes anything, though.
>
> I was thinking that we shouldn't be pretending that we know how to
> handle unsupported SoCs, i.e. that we know how to correctly read its
> product_id and revision.

Reasonable, thanks for explanation.
Best regards,
Krzysztof
Marek Szyprowski July 24, 2019, 1:10 p.m. UTC | #7
Hi Viresh,

On 2019-07-23 04:04, Viresh Kumar wrote:
> On 18-07-19, 16:30, Sylwester Nawrocki wrote:
>> This is second iteration of patch series adding ASV (Adaptive Supply
>> Voltage) support for Exynos SoCs. The first one can be found at:
>> https://lore.kernel.org/lkml/20190404171735.12815-1-s.nawrocki@samsung.com
>>
>> The main changes comparing to the first (RFC) version are:
>>   - moving ASV data tables from DT to the driver,
>>   - converting the chipid and the ASV drivers to use regmap,
>>   - converting the ASV driver to proper platform driver.
>>
>> I tried the opp-supported-hw bitmask approach as in the Qualcomm CPUFreq
>> DT bindings but it resulted in too many OPPs and DT nodes, around 200
>> per CPU cluster. So the ASV OPP tables are now in the ASV driver, as in
>> downstream kernels.
> Hmm. Can you explain why do you have so many OPPs? How many
> frequencies do you actually support per cluster and what all varies
> per frequency based on hw ? How many hw version do u have ?

For big cores there are 20 frequencies (2100MHz .. 200MHz). Each SoC 
might belong to one of the 3 production 'sets' and each set contains 14 
so called 'asv groups', which assign the certain voltage values for each 
of those 20 frequencies (the lower asv group means lower voltage needed 
for given frequency).

> I am asking as the OPP core can be improved to support your case if
> possible. But I need to understand the problem first.


Best regards
Viresh Kumar July 25, 2019, 2:23 a.m. UTC | #8
On 24-07-19, 15:10, Marek Szyprowski wrote:
> Hi Viresh,
> 
> On 2019-07-23 04:04, Viresh Kumar wrote:
> > On 18-07-19, 16:30, Sylwester Nawrocki wrote:
> >> This is second iteration of patch series adding ASV (Adaptive Supply
> >> Voltage) support for Exynos SoCs. The first one can be found at:
> >> https://lore.kernel.org/lkml/20190404171735.12815-1-s.nawrocki@samsung.com
> >>
> >> The main changes comparing to the first (RFC) version are:
> >>   - moving ASV data tables from DT to the driver,
> >>   - converting the chipid and the ASV drivers to use regmap,
> >>   - converting the ASV driver to proper platform driver.
> >>
> >> I tried the opp-supported-hw bitmask approach as in the Qualcomm CPUFreq
> >> DT bindings but it resulted in too many OPPs and DT nodes, around 200
> >> per CPU cluster. So the ASV OPP tables are now in the ASV driver, as in
> >> downstream kernels.
> > Hmm. Can you explain why do you have so many OPPs? How many
> > frequencies do you actually support per cluster and what all varies
> > per frequency based on hw ? How many hw version do u have ?
> 
> For big cores there are 20 frequencies (2100MHz .. 200MHz). Each SoC 
> might belong to one of the 3 production 'sets' and each set contains 14 
> so called 'asv groups', which assign the certain voltage values for each 
> of those 20 frequencies (the lower asv group means lower voltage needed 
> for given frequency).

There is another property which might be useful in this case:
"opp-microvolt-<name>" and then you can use API
dev_pm_opp_set_prop_name() to choose which voltage value to apply to
all OPPs.

opp-supported-hw property is more useful for the cases where only a
subset of frequencies will be supported for different versions of the
SoC. And what you need is a different voltage value for all
frequencies based on some h/w version.
Sylwester Nawrocki Aug. 8, 2019, 12:07 p.m. UTC | #9
On 7/23/19 14:57, Krzysztof Kozlowski wrote:
>> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c

>> --- /dev/null
>> +++ b/drivers/soc/samsung/exynos-chipid.c
>> @@ -0,0 +1,111 @@
>> +// SPDX-License-Identifier: GPL-2.0

>> +#include <linux/io.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/platform_device.h>
>
> Any changes here from my previous comments?

Oops, I tried hard to not miss any of the comments but probably not hard enough.
The two above platform header files will be removed in v3.
Sylwester Nawrocki Aug. 8, 2019, 12:07 p.m. UTC | #10
On 7/23/19 15:01, Krzysztof Kozlowski wrote:
> On Thu, 18 Jul 2019 at 16:31, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
>>
>> Convert the driver to use regmap API in order to allow other
>> drivers, like ASV, to access the CHIPID registers.
>>
>> This patch adds definition of selected CHIPID register offsets
>> and register bit fields for Exynos5422 SoC.
>>
>> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>

>> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
>> index 78b123ee60c0..594b00488013 100644
>> --- a/drivers/soc/samsung/exynos-chipid.c
>> +++ b/drivers/soc/samsung/exynos-chipid.c
>> @@ -9,18 +9,16 @@
>>   */
>> @@ -53,29 +51,24 @@ static const char * __init product_id_to_soc_id(unsigned int product_id)
>>  int __init exynos_chipid_early_init(void)
>>  {

>> +       regmap = syscon_regmap_lookup_by_compatible("samsung,exynos4210-chipid");
>> +       if (IS_ERR(regmap)) {
>> +               pr_err("%s: failed to get regmap\n", __func__);
> 
> Other places do not use __func__ prefix so make it consistent. Add it
> in patch #1?

I would rather drop the function name prefix here, there should be 
no problem in finding those error messages with grep. I'll just make
the above log a bit more specific.

>> +               return PTR_ERR(regmap);
>>         }

>> diff --git a/include/linux/soc/samsung/exynos-chipid.h b/include/linux/soc/samsung/exynos-chipid.h
>> new file mode 100644
>> index 000000000000..25359d70d617
>> --- /dev/null
>> +++ b/include/linux/soc/samsung/exynos-chipid.h
>> @@ -0,0 +1,48 @@

>> +#define EXYNOS_CHIPID_REG_PRO_ID       0x00
>> + #define EXYNOS_SUBREV_MASK            (0xf << 4)
> 
> " #define" is unusual syntax. I think not used anywhere else. Stick to
> regular one.

Indeed it's almost not used anywhere, I will drop those leading spaces.

git grep "^\ #define" *.[ch] | wc -l
Sylwester Nawrocki Aug. 8, 2019, 12:07 p.m. UTC | #11
On 7/23/19 15:38, Krzysztof Kozlowski wrote:
> On Thu, 18 Jul 2019 at 16:31, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
>>
>> The Adaptive Supply Voltage (ASV) driver adjusts CPU cluster operating
>> points depending on exact revision of an SoC retrieved from the CHIPID
>> block or the OTP memory.  This allows for some power saving as for some
>> CPU clock frequencies we can lower CPU cluster supply voltage comparing
>> to safe values common to the all chip revisions.
>>
>> This patch adds support for Exynos5422/5800 SoC, it is partially based
>> on code from https://github.com/hardkernel/linux repository,
>> branch odroidxu4-4.14.y, files: arch/arm/mach-exynos/exynos5422-asv.[ch].
>>
>> Tested on Odroid XU3, XU4, XU3 Lite.
>>
>> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
>> ---
>> Changes since v1 (RFC):
>>  - removed code for parsing the ASV OPP tables from DT, the ASV OPP tables
>>    moved to the driver;
>>  - converted to use the regmap API;
>>  - converted to normal platform driver.
>> ---
>>  drivers/soc/samsung/Kconfig          |  11 +
>>  drivers/soc/samsung/Makefile         |   3 +
>>  drivers/soc/samsung/exynos-asv.c     | 185 ++++++++++
>>  drivers/soc/samsung/exynos-asv.h     |  82 +++++
>>  drivers/soc/samsung/exynos5422-asv.c | 499 +++++++++++++++++++++++++++
>>  drivers/soc/samsung/exynos5422-asv.h |  25 ++
>>  6 files changed, 805 insertions(+)
>>  create mode 100644 drivers/soc/samsung/exynos-asv.c
>>  create mode 100644 drivers/soc/samsung/exynos-asv.h
>>  create mode 100644 drivers/soc/samsung/exynos5422-asv.c
>>  create mode 100644 drivers/soc/samsung/exynos5422-asv.h
>>
>> diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
>> index 2905f5262197..539cd95dd176 100644
>> --- a/drivers/soc/samsung/Kconfig
>> +++ b/drivers/soc/samsung/Kconfig
>> @@ -7,6 +7,17 @@ menuconfig SOC_SAMSUNG
>>
>>  if SOC_SAMSUNG
>>
>> +config EXYNOS_ASV
>> +       bool "Exynos Adaptive Supply Voltage support" if COMPILE_TEST
>> +       depends on ARCH_EXYNOS || COMPILE_TEST
>> +       depends on EXYNOS_CHIPID
> 
> (ARCH_EXYNOS && EXYNOS_CHIPID) || COMPILE_TEST

OK
>> +       select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS
>> +
>> +# There is no need to enable these drivers for ARMv8
>> +config EXYNOS_ASV_ARM
>> +       bool "Exynos ASV ARMv7-specific driver extensions" if COMPILE_TEST
>> +       depends on EXYNOS_ASV

>> diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c
>> new file mode 100644
>> index 000000000000..b1a7e0ba8870
>> --- /dev/null
>> +++ b/drivers/soc/samsung/exynos-asv.c
>> @@ -0,0 +1,185 @@

>> +static int exynos_asv_probe(struct platform_device *pdev)
>> +{
>> +       int (*probe_func)(struct exynos_asv *asv);
>> +       struct exynos_asv *asv;
>> +       struct device *cpu_dev;
>> +       u32 product_id = 0;
>> +       int ret, i;
>> +
>> +       cpu_dev = get_cpu_device(0);
>> +       ret = dev_pm_opp_get_opp_count(cpu_dev);
>> +       if (ret < 0)
>> +               return -EPROBE_DEFER;
>> +
>> +       asv = kcalloc(1, sizeof(*asv), GFP_KERNEL);
>> +       if (!asv)
>> +               return -ENOMEM;
>> +
>> +       asv->chipid_regmap = syscon_node_to_regmap(pdev->dev.of_node);
>> +       if (IS_ERR(asv->chipid_regmap)) {
>> +               dev_err(&pdev->dev, "Could not find syscon regmap\n");
> 
> Here and in following error-paths - kfree().

Thanks, I will fix that.

>> +               return PTR_ERR(asv->chipid_regmap);
>> +       }
>> +
>> +       regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id);

>> +module_platform_driver(exynos_asv_driver);
>> diff --git a/drivers/soc/samsung/exynos-asv.h b/drivers/soc/samsung/exynos-asv.h
>> new file mode 100644
>> index 000000000000..d0a5d603093d
>> --- /dev/null
>> +++ b/drivers/soc/samsung/exynos-asv.h
>> @@ -0,0 +1,82 @@

>> +#ifndef _EXYNOS_ASV_H
>> +#define _EXYNOS_ASV_H
> 
> Here and in other header use prefix:
> __LINUX_SOC_
> (just like the existing exynos-pmu.h)

OK, I will change that.

>> +struct exynos_asv_subsys {
>> +       struct exynos_asv *asv;
>> +       char *cpu_dt_compat;
> 
> const char *

OK
>> +       int id;

>> +#endif /* _EXYNOS_ASV_H */
>> diff --git a/drivers/soc/samsung/exynos5422-asv.c b/drivers/soc/samsung/exynos5422-asv.c
>> new file mode 100644
>> index 000000000000..5fd673a6a733
>> --- /dev/null
>> +++ b/drivers/soc/samsung/exynos5422-asv.c
>> @@ -0,0 +1,499 @@

>> +#include <linux/bitrev.h>
>> +#include <linux/device.h>
>> +#include <linux/errno.h>
>> +#include <linux/init.h>
> 
> Looks unused.

Indeed, I will drop it.

>> +static unsigned int exynos5422_asv_parse_table(struct exynos_asv *asv,
>> +                                     unsigned int pkg_id)
>> +{
>> +       return (pkg_id >> EXYNOS5422_TABLE_OFFSET) & EXYNOS5422_TABLE_MASK;
>> +}
>> +
>> +static bool exynos5422_asv_parse_bin2(struct exynos_asv *asv,
>> +                                    unsigned int pkg_id)
>> +{
>> +       return (pkg_id >> EXYNOS5422_BIN2_OFFSET) & EXYNOS5422_BIN2_MASK;
> 
> return !!() for converting to boolean.

I'm not convinced it is needed, the return type of the function is bool
and value of the expression will be implicitly converted to that type.
Is there any compiler warning related to that?

>> +}
>> +
>> +static bool exynos5422_asv_parse_sg(struct exynos_asv *asv,
>> +                                       unsigned int pkg_id)
>> +{
>> +       return ((pkg_id >> EXYNOS5422_USESG_OFFSET) & EXYNOS5422_USESG_MASK);
> 
> Unneeded () over entire statement.

Will drop it.
Krzysztof Kozlowski Aug. 8, 2019, 12:31 p.m. UTC | #12
On Thu, 8 Aug 2019 at 14:07, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
> >> +static unsigned int exynos5422_asv_parse_table(struct exynos_asv *asv,
> >> +                                     unsigned int pkg_id)
> >> +{
> >> +       return (pkg_id >> EXYNOS5422_TABLE_OFFSET) & EXYNOS5422_TABLE_MASK;
> >> +}
> >> +
> >> +static bool exynos5422_asv_parse_bin2(struct exynos_asv *asv,
> >> +                                    unsigned int pkg_id)
> >> +{
> >> +       return (pkg_id >> EXYNOS5422_BIN2_OFFSET) & EXYNOS5422_BIN2_MASK;
> >
> > return !!() for converting to boolean.
>
> I'm not convinced it is needed, the return type of the function is bool
> and value of the expression will be implicitly converted to that type.
> Is there any compiler warning related to that?

Yeah, but bool is int so there will be no implicit conversion... I
guess it is a convention. In theory !! is the proper conversion to
bool but if bool==int then it's essentially conversion to 1. I am not
sure what's the benefit, maybe for some wrong code which would do
comparisons on result like if (exynos5422_asv_parse_bin2() == TRUE)...

Best regards,
Krzysztof
Robin Murphy Aug. 8, 2019, 12:48 p.m. UTC | #13
On 08/08/2019 13:31, Krzysztof Kozlowski wrote:
> On Thu, 8 Aug 2019 at 14:07, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
>>>> +static unsigned int exynos5422_asv_parse_table(struct exynos_asv *asv,
>>>> +                                     unsigned int pkg_id)
>>>> +{
>>>> +       return (pkg_id >> EXYNOS5422_TABLE_OFFSET) & EXYNOS5422_TABLE_MASK;
>>>> +}
>>>> +
>>>> +static bool exynos5422_asv_parse_bin2(struct exynos_asv *asv,
>>>> +                                    unsigned int pkg_id)
>>>> +{
>>>> +       return (pkg_id >> EXYNOS5422_BIN2_OFFSET) & EXYNOS5422_BIN2_MASK;
>>>
>>> return !!() for converting to boolean.
>>
>> I'm not convinced it is needed, the return type of the function is bool
>> and value of the expression will be implicitly converted to that type.
>> Is there any compiler warning related to that?
> 
> Yeah, but bool is int so there will be no implicit conversion... I
> guess it is a convention. In theory !! is the proper conversion to
> bool but if bool==int then it's essentially conversion to 1. I am not
> sure what's the benefit, maybe for some wrong code which would do
> comparisons on result like if (exynos5422_asv_parse_bin2() == TRUE)...

Not so - since we use "-std=gnu89", we have C99-like _Bool, which our 
bool is a typedef of. Conversions, either implicit or explicit, are 
well-defined:

"6.3.1.2 Boolean type

When any scalar value is converted to _Bool, the result is 0 if the 
value compares equal
to 0; otherwise, the result is 1."

This is even called out in Documentation/process/coding-style.rst:

"When using bool types the !! construction is not needed, which 
eliminates a class of bugs."

Robin.
Krzysztof Kozlowski Aug. 8, 2019, 1:14 p.m. UTC | #14
On Thu, 8 Aug 2019 at 14:48, Robin Murphy <robin.murphy@arm.com> wrote:
>
> On 08/08/2019 13:31, Krzysztof Kozlowski wrote:
> > On Thu, 8 Aug 2019 at 14:07, Sylwester Nawrocki <s.nawrocki@samsung.com> wrote:
> >>>> +static unsigned int exynos5422_asv_parse_table(struct exynos_asv *asv,
> >>>> +                                     unsigned int pkg_id)
> >>>> +{
> >>>> +       return (pkg_id >> EXYNOS5422_TABLE_OFFSET) & EXYNOS5422_TABLE_MASK;
> >>>> +}
> >>>> +
> >>>> +static bool exynos5422_asv_parse_bin2(struct exynos_asv *asv,
> >>>> +                                    unsigned int pkg_id)
> >>>> +{
> >>>> +       return (pkg_id >> EXYNOS5422_BIN2_OFFSET) & EXYNOS5422_BIN2_MASK;
> >>>
> >>> return !!() for converting to boolean.
> >>
> >> I'm not convinced it is needed, the return type of the function is bool
> >> and value of the expression will be implicitly converted to that type.
> >> Is there any compiler warning related to that?
> >
> > Yeah, but bool is int so there will be no implicit conversion... I
> > guess it is a convention. In theory !! is the proper conversion to
> > bool but if bool==int then it's essentially conversion to 1. I am not
> > sure what's the benefit, maybe for some wrong code which would do
> > comparisons on result like if (exynos5422_asv_parse_bin2() == TRUE)...
>
> Not so - since we use "-std=gnu89", we have C99-like _Bool, which our
> bool is a typedef of. Conversions, either implicit or explicit, are
> well-defined:
>
> "6.3.1.2 Boolean type
>
> When any scalar value is converted to _Bool, the result is 0 if the
> value compares equal
> to 0; otherwise, the result is 1."
>
> This is even called out in Documentation/process/coding-style.rst:
>
> "When using bool types the !! construction is not needed, which
> eliminates a class of bugs."

Good point, thanks!

Best regards,
Krzysztof
Sylwester Nawrocki Aug. 9, 2019, 3:58 p.m. UTC | #15
Hi Viresh,

On 7/25/19 04:23, Viresh Kumar wrote:
> On 24-07-19, 15:10, Marek Szyprowski wrote:
>> On 2019-07-23 04:04, Viresh Kumar wrote:
>>> On 18-07-19, 16:30, Sylwester Nawrocki wrote:
>>>> This is second iteration of patch series adding ASV (Adaptive Supply
>>>> Voltage) support for Exynos SoCs. The first one can be found at:
>>>> https://lore.kernel.org/lkml/20190404171735.12815-1-s.nawrocki@samsung.com
>>>>
>>>> The main changes comparing to the first (RFC) version are:
>>>>   - moving ASV data tables from DT to the driver,
>>>>   - converting the chipid and the ASV drivers to use regmap,
>>>>   - converting the ASV driver to proper platform driver.
>>>>
>>>> I tried the opp-supported-hw bitmask approach as in the Qualcomm CPUFreq
>>>> DT bindings but it resulted in too many OPPs and DT nodes, around 200
>>>> per CPU cluster. So the ASV OPP tables are now in the ASV driver, as in
>>>> downstream kernels.
>>> 
>>> Hmm. Can you explain why do you have so many OPPs? How many
>>> frequencies do you actually support per cluster and what all varies
>>> per frequency based on hw ? How many hw version do u have ?
>>
>> For big cores there are 20 frequencies (2100MHz .. 200MHz). Each SoC 
>> might belong to one of the 3 production 'sets' and each set contains 14 
>> so called 'asv groups', which assign the certain voltage values for each 
>> of those 20 frequencies (the lower asv group means lower voltage needed 
>> for given frequency).
>
> There is another property which might be useful in this case:
> "opp-microvolt-<name>" and then you can use API
> dev_pm_opp_set_prop_name() to choose which voltage value to apply to
> all OPPs.

Thank you for your suggestions.

For some Exynos SoC variants the algorithm of selecting CPU voltage supply
is a bit more complex than just selecting a column in the frequency/voltage 
matrix, i.e. selecting a set of voltage values for whole frequency range.

Frequency range could be divided into sub-ranges and to each such a sub-range 
part of different column could be assigned, depending on data fused in 
the CHIPID block registers.

We could create OPP node for each frequency and specify all needed voltages 
as a list of "opp-microvolt-<name>" properties but apart from the fact that 
it would have been quite many properties, e.g. 42 (3 tables * 14 columns), 
only for some SoC types the dev_pm_opp_set_prop_name() approach could be 
used. We would need to be able to set opp-microvolt-* property name 
separately for each frequency (OPP).

Probably most future proof would be a DT binding where we could still 
re-create those Exynos-specific ASV tables from DT. For example add named 
opp-microvolt-* properties or something similar to hold rows of each ASV 
table. But that conflicts with "operating-points-v2" binding, where 
multiple OPP voltage values are described by just named properties and 
multiple entries correspond to min/target/max.

opp_table0 {
	compatible = "...", "operating-points-v2";
	opp-shared;
	opp-2100000000 {
		opp-hz = /bits/ 64 <1800000000>;
		opp-microvolt = <...>;
		opp-microvolt-t1 = <1362500>, <1350000>, ....;
		opp-microvolt-t2 = <1362500>, <1360000>, ....;
		opp-microvolt-t3 = <1362500>, <1340000>, ....;
	};
	...
	opp-200000000 {
		opp-hz = /bits/ 64 <200000000>;
		opp-microvolt = <...>;
		opp-microvolt-t1 = <900000>, <900000>, ....;
		opp-microvolt-t2 = <900000>, <900000>, ....;
		opp-microvolt-t3 = <900000>, <900000>, ....;
	};
};

I might be missing some information now on how those Exynos ASV tables 
are used on other SoCs that would need to be supported.

There will be even more data to include when adding support for the Body
Bias voltage, for each CPU supply voltage we could possibly have 
corresponding Body Bias voltage.
Viresh Kumar Aug. 19, 2019, 9:09 a.m. UTC | #16
On 09-08-19, 17:58, Sylwester Nawrocki wrote:
> Thank you for your suggestions.
> 
> For some Exynos SoC variants the algorithm of selecting CPU voltage supply
> is a bit more complex than just selecting a column in the frequency/voltage 
> matrix, i.e. selecting a set of voltage values for whole frequency range.
> 
> Frequency range could be divided into sub-ranges and to each such a sub-range 
> part of different column could be assigned, depending on data fused in 
> the CHIPID block registers.
> 
> We could create OPP node for each frequency and specify all needed voltages 
> as a list of "opp-microvolt-<name>" properties but apart from the fact that 
> it would have been quite many properties, e.g. 42 (3 tables * 14 columns), 
> only for some SoC types the dev_pm_opp_set_prop_name() approach could be 
> used. We would need to be able to set opp-microvolt-* property name 
> separately for each frequency (OPP).
> 
> Probably most future proof would be a DT binding where we could still 
> re-create those Exynos-specific ASV tables from DT. For example add named 
> opp-microvolt-* properties or something similar to hold rows of each ASV 
> table. But that conflicts with "operating-points-v2" binding, where 
> multiple OPP voltage values are described by just named properties and 
> multiple entries correspond to min/target/max.
> 
> opp_table0 {
> 	compatible = "...", "operating-points-v2";
> 	opp-shared;
> 	opp-2100000000 {
> 		opp-hz = /bits/ 64 <1800000000>;
> 		opp-microvolt = <...>;
> 		opp-microvolt-t1 = <1362500>, <1350000>, ....;
> 		opp-microvolt-t2 = <1362500>, <1360000>, ....;
> 		opp-microvolt-t3 = <1362500>, <1340000>, ....;
> 	};
> 	...
> 	opp-200000000 {
> 		opp-hz = /bits/ 64 <200000000>;
> 		opp-microvolt = <...>;
> 		opp-microvolt-t1 = <900000>, <900000>, ....;
> 		opp-microvolt-t2 = <900000>, <900000>, ....;
> 		opp-microvolt-t3 = <900000>, <900000>, ....;
> 	};
> };
> 
> I might be missing some information now on how those Exynos ASV tables 
> are used on other SoCs that would need to be supported.
> 
> There will be even more data to include when adding support for the Body
> Bias voltage, for each CPU supply voltage we could possibly have 
> corresponding Body Bias voltage.

Will something like this help ?

https://lore.kernel.org/lkml/1442623929-4507-3-git-send-email-sboyd@codeaurora.org/

This never got merged but the idea was AVS only.
Viresh Kumar Aug. 19, 2019, 10:06 a.m. UTC | #17
On 19-08-19, 14:39, Viresh Kumar wrote:
> On 09-08-19, 17:58, Sylwester Nawrocki wrote:
> > Thank you for your suggestions.
> > 
> > For some Exynos SoC variants the algorithm of selecting CPU voltage supply
> > is a bit more complex than just selecting a column in the frequency/voltage 
> > matrix, i.e. selecting a set of voltage values for whole frequency range.
> > 
> > Frequency range could be divided into sub-ranges and to each such a sub-range 
> > part of different column could be assigned, depending on data fused in 
> > the CHIPID block registers.
> > 
> > We could create OPP node for each frequency and specify all needed voltages 
> > as a list of "opp-microvolt-<name>" properties but apart from the fact that 
> > it would have been quite many properties, e.g. 42 (3 tables * 14 columns), 
> > only for some SoC types the dev_pm_opp_set_prop_name() approach could be 
> > used. We would need to be able to set opp-microvolt-* property name 
> > separately for each frequency (OPP).
> > 
> > Probably most future proof would be a DT binding where we could still 
> > re-create those Exynos-specific ASV tables from DT. For example add named 
> > opp-microvolt-* properties or something similar to hold rows of each ASV 
> > table. But that conflicts with "operating-points-v2" binding, where 
> > multiple OPP voltage values are described by just named properties and 
> > multiple entries correspond to min/target/max.
> > 
> > opp_table0 {
> > 	compatible = "...", "operating-points-v2";
> > 	opp-shared;
> > 	opp-2100000000 {
> > 		opp-hz = /bits/ 64 <1800000000>;
> > 		opp-microvolt = <...>;
> > 		opp-microvolt-t1 = <1362500>, <1350000>, ....;
> > 		opp-microvolt-t2 = <1362500>, <1360000>, ....;
> > 		opp-microvolt-t3 = <1362500>, <1340000>, ....;
> > 	};
> > 	...
> > 	opp-200000000 {
> > 		opp-hz = /bits/ 64 <200000000>;
> > 		opp-microvolt = <...>;
> > 		opp-microvolt-t1 = <900000>, <900000>, ....;
> > 		opp-microvolt-t2 = <900000>, <900000>, ....;
> > 		opp-microvolt-t3 = <900000>, <900000>, ....;
> > 	};
> > };
> > 
> > I might be missing some information now on how those Exynos ASV tables 
> > are used on other SoCs that would need to be supported.
> > 
> > There will be even more data to include when adding support for the Body
> > Bias voltage, for each CPU supply voltage we could possibly have 
> > corresponding Body Bias voltage.
> 
> Will something like this help ?
> 
> https://lore.kernel.org/lkml/1442623929-4507-3-git-send-email-sboyd@codeaurora.org/
> 
> This never got merged but the idea was AVS only.

Here is a recent version under review.

https://lore.kernel.org/lkml/1565703113-31479-1-git-send-email-andrew-sh.cheng@mediatek.com
Sylwester Nawrocki Aug. 19, 2019, 11:16 a.m. UTC | #18
On 8/19/19 11:09, Viresh Kumar wrote:
> Will something like this help ?
> 
> https://lore.kernel.org/lkml/1442623929-4507-3-git-send-email-sboyd@codeaurora.org/
> 
> This never got merged but the idea was AVS only.

It's quite interesting work, it seems to be for a more advanced use case 
where OPP voltage is being adjusted at runtime.

We could use it instead of removing an OPP and then adding with updated 
voltage. On Exynos there is there is just a need to update OPPs once at boot 
time, so it is more "static". However the requirements could presumably 
change in future.

If that's your preference I could switch to that notifier approach.
AFAICS the API would still need to be extended to support multiple voltages,
when in future we add support for the Body Bias regulator.
Viresh Kumar Aug. 19, 2019, 11:25 a.m. UTC | #19
On 19-08-19, 13:16, Sylwester Nawrocki wrote:
> On 8/19/19 11:09, Viresh Kumar wrote:
> > Will something like this help ?
> > 
> > https://lore.kernel.org/lkml/1442623929-4507-3-git-send-email-sboyd@codeaurora.org/
> > 
> > This never got merged but the idea was AVS only.
> 
> It's quite interesting work, it seems to be for a more advanced use case 
> where OPP voltage is being adjusted at runtime.
> 
> We could use it instead of removing an OPP and then adding with updated 
> voltage. On Exynos there is there is just a need to update OPPs once at boot 
> time, so it is more "static". However the requirements could presumably 
> change in future.

The API is about changing the values after they are parsed once from DT. You can
change it once or multiple times depending on the use case.

> If that's your preference I could switch to that notifier approach.

You shouldn't be required to use the notifier. Just add the OPP table and update
the values right after that. So no one would be using the values at that time.

> AFAICS the API would still need to be extended to support multiple voltages,
> when in future we add support for the Body Bias regulator. 

Right.

Will this patchset solve the problems for you and make your DT light weight ?
Sylwester Nawrocki Aug. 19, 2019, 1:39 p.m. UTC | #20
On 8/19/19 13:25, Viresh Kumar wrote:
> On 19-08-19, 13:16, Sylwester Nawrocki wrote:
>> On 8/19/19 11:09, Viresh Kumar wrote:
>>> Will something like this help ?
>>>
>>> https://lore.kernel.org/lkml/1442623929-4507-3-git-send-email-sboyd@codeaurora.org/
>>>
>>> This never got merged but the idea was AVS only.
>>
>> It's quite interesting work, it seems to be for a more advanced use case 
>> where OPP voltage is being adjusted at runtime.
>>
>> We could use it instead of removing an OPP and then adding with updated 
>> voltage. On Exynos there is there is just a need to update OPPs once at boot 
>> time, so it is more "static". However the requirements could presumably 
>> change in future.
> 
> The API is about changing the values after they are parsed once from DT. You can
> change it once or multiple times depending on the use case.
> 
>> If that's your preference I could switch to that notifier approach.
> 
> You shouldn't be required to use the notifier. Just add the OPP table and update
> the values right after that. So no one would be using the values at that time.

OK, now I see dev_pm_opp_adjust_voltage() actually changes OPP's voltage 
and the notifier is optional.

> Will this patchset solve the problems for you and make your DT light weight ?

Unfortunately not, the patch set as I see it is another way of updating 
an OPP after it was parsed from DT.  OPP remove/add could work equally 
well in our use case.
 
The problem is that we have the information on how to translate the 
common OPP voltage to a voltage specific to given silicon encoded jointly 
in the ASV tables and the CHIPID registers (efuse/OTP memory). 
Additionally, algorithm of selecting ASV data (OPP voltage) based on 
the "key" data from registers is not generic, it is usually different 
per each SoC type.

I tried to identify some patterns in those tables in order to simplify 
possible DT binding, but that was not really successful. I ended up just 
keeping whole tables.

--
Regards, 
Sylwester
Viresh Kumar Aug. 20, 2019, 3:01 a.m. UTC | #21
On 19-08-19, 15:39, Sylwester Nawrocki wrote:
> Unfortunately not, the patch set as I see it is another way of updating 
> an OPP after it was parsed from DT.  OPP remove/add could work equally 
> well in our use case.

Adding OPPs dynamically has limitations, you can't set many values which are
otherwise possible with DT. And removing/adding is not the right thing to do
technically.

> The problem is that we have the information on how to translate the 
> common OPP voltage to a voltage specific to given silicon encoded jointly 
> in the ASV tables and the CHIPID registers (efuse/OTP memory). 
> Additionally, algorithm of selecting ASV data (OPP voltage) based on 
> the "key" data from registers is not generic, it is usually different 
> per each SoC type.
> 
> I tried to identify some patterns in those tables in order to simplify 
> possible DT binding, but that was not really successful. I ended up just 
> keeping whole tables.

Sorry but I am unable to understand the difficulty you are facing now. So what I
suggest is something like this.

- Use DT to get a frequency and voltage for each frequency.
- At runtime, based on SoC, registers, efuses, etc, update the voltage of the
  OPPs.
- This algo can be different for each SoC, no one is stopping you from doing
  that.

Am I missing something ?
Sylwester Nawrocki Aug. 20, 2019, 9:03 a.m. UTC | #22
On 8/20/19 05:01, Viresh Kumar wrote:
> On 19-08-19, 15:39, Sylwester Nawrocki wrote:
>> Unfortunately not, the patch set as I see it is another way of updating 
>> an OPP after it was parsed from DT.  OPP remove/add could work equally 
>> well in our use case.
> 
> Adding OPPs dynamically has limitations, you can't set many values which are
> otherwise possible with DT. And removing/adding is not the right thing to do
> technically.

Thanks for explanation, I was not aware of that.

>> The problem is that we have the information on how to translate the 
>> common OPP voltage to a voltage specific to given silicon encoded jointly 
>> in the ASV tables and the CHIPID registers (efuse/OTP memory). 
>> Additionally, algorithm of selecting ASV data (OPP voltage) based on 
>> the "key" data from registers is not generic, it is usually different 
>> per each SoC type.
>>
>> I tried to identify some patterns in those tables in order to simplify 
>> possible DT binding, but that was not really successful. I ended up just 
>> keeping whole tables.
> 
> Sorry but I am unable to understand the difficulty you are facing now. So what I
> suggest is something like this.

The difficulty was about representing data from tables asv_{arm,kfc}_table[][]
added in patch 3/9 of the series in devicetree.  If you have no objections
about keeping those tables in the driver then I can't see any difficulties. 
 
> - Use DT to get a frequency and voltage for each frequency.

Yes, this is what happens now, we have common OPPs in DT that work for each SoC
revision. 

> - At runtime, based on SoC, registers, efuses, etc, update the voltage of the
>   OPPs.
> - This algo can be different for each SoC, no one is stopping you from doing
>   that.
> 
> Am I missing something ?

Not really, this is basically what happens in the $subject patch series. 

Then IIUC what I would need to change is to modify exynos_asv_update_cpu_opps() 
function in patch 3/9 to use dev_pm_opp_adjust_voltage() rather than 
dev_pm_opp_remove(), dev_pm_opp_add().
Viresh Kumar Aug. 20, 2019, 9:21 a.m. UTC | #23
On 20-08-19, 11:03, Sylwester Nawrocki wrote:
> On 8/20/19 05:01, Viresh Kumar wrote:
> > Sorry but I am unable to understand the difficulty you are facing now. So what I
> > suggest is something like this.
> 
> The difficulty was about representing data from tables asv_{arm,kfc}_table[][]
> added in patch 3/9 of the series in devicetree.  If you have no objections
> about keeping those tables in the driver then I can't see any difficulties. 

The problem with keeping such tables in kernel is that they contain too much
magic values which very few people understand. And after some amount of time,
even they don't remember any of it.

What I was expecting was to remove as much of these tables as possible and do
the calculations to get them at runtime with some logical code which people can
understand later on.

> > - Use DT to get a frequency and voltage for each frequency.
> 
> Yes, this is what happens now, we have common OPPs in DT that work for each SoC
> revision. 
> 
> > - At runtime, based on SoC, registers, efuses, etc, update the voltage of the
> >   OPPs.
> > - This algo can be different for each SoC, no one is stopping you from doing
> >   that.
> > 
> > Am I missing something ?
> 
> Not really, this is basically what happens in the $subject patch series. 
> 
> Then IIUC what I would need to change is to modify exynos_asv_update_cpu_opps() 
> function in patch 3/9 to use dev_pm_opp_adjust_voltage() rather than 
> dev_pm_opp_remove(), dev_pm_opp_add().

That and somehow add code to get those tables if possible.
Sylwester Nawrocki Sept. 4, 2019, 12:37 p.m. UTC | #24
Hi,

On 8/20/19 11:21, Viresh Kumar wrote:
> On 20-08-19, 11:03, Sylwester Nawrocki wrote:
>> On 8/20/19 05:01, Viresh Kumar wrote:
>>> Sorry but I am unable to understand the difficulty you are facing now. So what I
>>> suggest is something like this.
>>
>> The difficulty was about representing data from tables asv_{arm,kfc}_table[][]
>> added in patch 3/9 of the series in devicetree.  If you have no objections
>> about keeping those tables in the driver then I can't see any difficulties. 
> 
> The problem with keeping such tables in kernel is that they contain too much
> magic values which very few people understand. And after some amount of time,
> even they don't remember any of it.
>
> What I was expecting was to remove as much of these tables as possible and do
> the calculations to get them at runtime with some logical code which people can
> understand later on.

It might be indeed far from a good design but this is all what we get from the 
SoC vendor. AFAIU those tables are generated based on data from the production
process, likely from some measurements.

I am afraid I will not get more information for that fairly old SoCs in order to 
replace those tables with some sensible code generating the data programmatically,
I'm not sure it would be at all possible to do.

I could add some more comments, similar to description as in my previous RFC 
DT binding (https://patchwork.kernel.org/patch/10886013).

The tables are rather simple, it's mostly all voltage values, only selecting 
values per each frequency and chip revision might get a bit complex. 
I'm not sure we could change that now though.
>> Then IIUC what I would need to change is to modify exynos_asv_update_cpu_opps() 
>> function in patch 3/9 to use dev_pm_opp_adjust_voltage() rather than 
>> dev_pm_opp_remove(), dev_pm_opp_add().
> 
> That and somehow add code to get those tables if possible.

I have changed the code to use dev_pm_opp_adjust_voltage(). I was wondering 
though, what did you mean by "triplet" when commenting on this patch
https://patchwork.kernel.org/patch/11092245 ?
Viresh Kumar Sept. 5, 2019, 5:01 a.m. UTC | #25
On 04-09-19, 14:37, Sylwester Nawrocki wrote:
> I have changed the code to use dev_pm_opp_adjust_voltage(). I was wondering 
> though, what did you mean by "triplet" when commenting on this patch
> https://patchwork.kernel.org/patch/11092245 ?

The voltage value in the OPP core is stored as a triplet,
min/max/target kind of stuff. You can check DT binding for OPPs and
see the details. That's called as triplet.