[PATCH v5 1/2] soc: samsung: add exynos chipid driver support

Rob Herring robherring2 at gmail.com
Thu Dec 11 09:30:49 PST 2014


On Thu, Dec 11, 2014 at 2:07 AM, Pankaj Dubey <pankaj.dubey at samsung.com> wrote:
> Exynos SoCs have Chipid, for identification of product IDs
> and SoC revisions. This patch intendes to provide initialization
> code for all these functionalites.
>
> This driver usese existing binding for exnos-chipid.

s/usese/uses/
s/exnos/exynos/

>
> CC: Grant Likely <grant.likely at linaro.org>
> CC: Rob Herring <robh+dt at kernel.org>
> CC: Linus Walleij <linus.walleij at linaro.org>
> Signed-off-by: Pankaj Dubey <pankaj.dubey at samsung.com>
> ---
>  drivers/soc/Kconfig                    |   1 +
>  drivers/soc/Makefile                   |   1 +
>  drivers/soc/samsung/Kconfig            |  14 +++
>  drivers/soc/samsung/Makefile           |   1 +
>  drivers/soc/samsung/exynos-chipid.c    | 168 +++++++++++++++++++++++++++++++++
>  include/linux/soc/samsung/exynos-soc.h |  51 ++++++++++
>  6 files changed, 236 insertions(+)
>  create mode 100644 drivers/soc/samsung/Kconfig
>  create mode 100644 drivers/soc/samsung/Makefile
>  create mode 100644 drivers/soc/samsung/exynos-chipid.c
>  create mode 100644 include/linux/soc/samsung/exynos-soc.h
>
> diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
> index 76d6bd4..c3abfbe 100644
> --- a/drivers/soc/Kconfig
> +++ b/drivers/soc/Kconfig
> @@ -1,6 +1,7 @@
>  menu "SOC (System On Chip) specific Drivers"
>
>  source "drivers/soc/qcom/Kconfig"
> +source "drivers/soc/samsung/Kconfig"
>  source "drivers/soc/ti/Kconfig"
>  source "drivers/soc/versatile/Kconfig"
>
> diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
> index 063113d..620366f 100644
> --- a/drivers/soc/Makefile
> +++ b/drivers/soc/Makefile
> @@ -3,6 +3,7 @@
>  #
>
>  obj-$(CONFIG_ARCH_QCOM)                += qcom/
> +obj-$(CONFIG_SOC_SAMSUNG)      += samsung/
>  obj-$(CONFIG_ARCH_TEGRA)       += tegra/
>  obj-$(CONFIG_SOC_TI)           += ti/
>  obj-$(CONFIG_PLAT_VERSATILE)   += versatile/
> diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
> new file mode 100644
> index 0000000..2d83652
> --- /dev/null
> +++ b/drivers/soc/samsung/Kconfig
> @@ -0,0 +1,14 @@
> +#
> +# SAMSUNG SoC drivers
> +#
> +menu "Samsung SOC driver support"
> +
> +config SOC_SAMSUNG
> +       bool
> +
> +config EXYNOS_CHIPID
> +       bool
> +       depends on ARCH_EXYNOS
> +       select SOC_BUS

This is going to show an empty menu when ARCH_EXYNOS is not enabled.
The whole menu should probably have "if ARCH_EXYNOS" instead.

> +
> +endmenu
> diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
> new file mode 100644
> index 0000000..855ca05
> --- /dev/null
> +++ b/drivers/soc/samsung/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_EXYNOS_CHIPID)    += exynos-chipid.o
> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
> new file mode 100644
> index 0000000..8968f83
> --- /dev/null
> +++ b/drivers/soc/samsung/exynos-chipid.c
> @@ -0,0 +1,168 @@
> +/*
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + *           http://www.samsung.com/
> + *
> + * EXYNOS - CHIP ID support
> + * Author: Pankaj Dubey <pankaj.dubey at samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/sys_soc.h>
> +#include <linux/soc/samsung/exynos-soc.h>
> +
> +#define EXYNOS_SUBREV_MASK     (0xF << 4)
> +#define EXYNOS_MAINREV_MASK    (0xF << 0)
> +#define EXYNOS_REV_MASK                (EXYNOS_SUBREV_MASK | EXYNOS_MAINREV_MASK)
> +
> +static void __iomem *exynos_chipid_base;
> +
> +struct exynos_chipid_info exynos_soc_info;
> +EXPORT_SYMBOL(exynos_soc_info);

The soc_device already has similar data. Why is this needed? Is it
temporary for compatibility? For early use? If for early use, then it
should not be exported.


> +
> +static const char * __init product_id_to_name(unsigned int product_id)
> +{
> +       const char *soc_name;
> +       unsigned int soc_id = product_id & EXYNOS_SOC_MASK;
> +
> +       switch (soc_id) {
> +       case EXYNOS3250_SOC_ID:
> +               soc_name = "EXYNOS3250";
> +               break;
> +       case EXYNOS4210_SOC_ID:
> +               soc_name = "EXYNOS4210";
> +               break;
> +       case EXYNOS4212_SOC_ID:
> +               soc_name = "EXYNOS4212";
> +               break;
> +       case EXYNOS4412_SOC_ID:
> +               soc_name = "EXYNOS4412";
> +               break;
> +       case EXYNOS4415_SOC_ID:
> +               soc_name = "EXYNOS4415";
> +               break;
> +       case EXYNOS5250_SOC_ID:
> +               soc_name = "EXYNOS5250";
> +               break;
> +       case EXYNOS5260_SOC_ID:
> +               soc_name = "EXYNOS5260";
> +               break;
> +       case EXYNOS5420_SOC_ID:
> +               soc_name = "EXYNOS5420";
> +               break;
> +       case EXYNOS5440_SOC_ID:
> +               soc_name = "EXYNOS5440";
> +               break;
> +       case EXYNOS5800_SOC_ID:
> +               soc_name = "EXYNOS5800";
> +               break;
> +       default:
> +               soc_name = "UNKNOWN";
> +       }
> +       return soc_name;
> +}
> +
> +static const struct of_device_id of_exynos_chipid_ids[] __initconst = {
> +       {
> +               .compatible     = "samsung,exynos4210-chipid",
> +       },
> +       {},
> +};
> +
> +/**
> + *  exynos_chipid_early_init: Early chipid initialization
> + *  @dev: pointer to chipid device
> + */
> +void __init exynos_chipid_early_init(struct device *dev)
> +{
> +       struct device_node *np;
> +       const struct of_device_id *match;
> +
> +       if (exynos_chipid_base)
> +               return;
> +
> +       if (!dev)
> +               np = of_find_matching_node_and_match(NULL,
> +                       of_exynos_chipid_ids, &match);
> +       else
> +               np = dev->of_node;
> +
> +       if (!np)
> +               panic("%s, failed to find chipid node\n", __func__);

Do you really want to halt booting here? Your console may not be up to
see the panic anyway.

> +
> +       exynos_chipid_base = of_iomap(np, 0);

Once you read the rev and product_id, do you need to keep the mapping?

> +
> +       if (!exynos_chipid_base)
> +               panic("%s: failed to map registers\n", __func__);
> +
> +       exynos_soc_info.product_id  = __raw_readl(exynos_chipid_base);
> +       exynos_soc_info.revision = exynos_soc_info.product_id & EXYNOS_REV_MASK;
> +}
> +
> +static int __init exynos_chipid_probe(struct platform_device *pdev)
> +{
> +       struct soc_device_attribute *soc_dev_attr;
> +       struct soc_device *soc_dev;
> +       struct device_node *root;
> +       int ret;
> +
> +       exynos_chipid_early_init(&pdev->dev);
> +
> +       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
> +       if (!soc_dev_attr)
> +               return -ENODEV;
> +
> +       soc_dev_attr->family = "Samsung Exynos";
> +
> +       root = of_find_node_by_path("/");
> +       ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
> +       of_node_put(root);
> +       if (ret)
> +               goto free_soc;

Should a lack of model really be a reason to not load the soc_device?

> +
> +       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d",
> +                                       exynos_soc_info.revision);
> +       if (!soc_dev_attr->revision)
> +               goto free_soc;
> +
> +       soc_dev_attr->soc_id = product_id_to_name(exynos_soc_info.product_id);
> +
> +       soc_dev = soc_device_register(soc_dev_attr);
> +       if (IS_ERR(soc_dev))
> +               goto free_rev;
> +
> +       soc_device_to_device(soc_dev);
> +
> +       dev_info(&pdev->dev, "Exynos: CPU[%s] CPU_REV[0x%x] Detected\n",
> +                       product_id_to_name(exynos_soc_info.product_id),
> +                       exynos_soc_info.revision);
> +       return 0;
> +free_rev:
> +       kfree(soc_dev_attr->revision);
> +free_soc:
> +       kfree(soc_dev_attr);
> +       return -EINVAL;
> +}
> +
> +static struct platform_driver exynos_chipid_driver __initdata = {
> +       .driver = {
> +               .name = "exynos-chipid",
> +               .of_match_table = of_exynos_chipid_ids,
> +       },
> +       .probe = exynos_chipid_probe,
> +};
> +
> +static int __init exynos_chipid_init(void)
> +{
> +       return platform_driver_register(&exynos_chipid_driver);
> +}
> +core_initcall(exynos_chipid_init);
> +
> diff --git a/include/linux/soc/samsung/exynos-soc.h b/include/linux/soc/samsung/exynos-soc.h
> new file mode 100644
> index 0000000..d2d9f05
> --- /dev/null
> +++ b/include/linux/soc/samsung/exynos-soc.h
> @@ -0,0 +1,51 @@
> +/*
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + *             http://www.samsung.com
> + *
> + * Header for EXYNOS SoC Chipid support
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __EXYNOS_SOC_H
> +#define __EXYNOS_SOC_H
> +
> +#define EXYNOS3250_SOC_ID      0xE3472000
> +#define EXYNOS4210_SOC_ID      0x43210000
> +#define EXYNOS4212_SOC_ID      0x43220000
> +#define EXYNOS4412_SOC_ID      0xE4412000
> +#define EXYNOS4415_SOC_ID      0xE4415000
> +#define EXYNOS5250_SOC_ID      0x43520000
> +#define EXYNOS5260_SOC_ID      0xE5260000
> +#define EXYNOS5410_SOC_ID      0xE5410000
> +#define EXYNOS5420_SOC_ID      0xE5420000
> +#define EXYNOS5440_SOC_ID      0xE5440000
> +#define EXYNOS5800_SOC_ID      0xE5422000
> +
> +#define EXYNOS_SOC_MASK                0xFFFFF000
> +
> +#define EXYNOS4210_REV_0       0x0
> +#define EXYNOS4210_REV_1_0     0x10
> +#define EXYNOS4210_REV_1_1     0x11
> +
> +/**
> + * Struct exynos_chipid_info
> + * @soc_product_id: product id allocated to exynos SoC
> + * @soc_revision: revision of exynos SoC
> + */
> +
> +struct exynos_chipid_info {
> +       u32 product_id;
> +       u32 revision;
> +};

Exposing this struct kernel wide in an SOC specific way concerns me. I
would not like to see this done on every SOC family. That would become
a mess.

Rob



More information about the linux-arm-kernel mailing list