diff mbox series

[v2,04/15] soc: renesas: rz-sysc: Add SoC detection support

Message ID 20241126092050.1825607-5-claudiu.beznea.uj@bp.renesas.com
State New
Headers show
Series Add initial USB support for the Renesas RZ/G3S SoC | expand

Commit Message

Claudiu Beznea Nov. 26, 2024, 9:20 a.m. UTC
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The RZ SYSC controller has registers that keep the SoC ID data. Add
driver support to retrieve the SoC ID and register a SoC driver.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- this was patch 05/16 in v1
- changed patch title and description
- added SoC initialization code in its own function
- addressed the review comments
- introduced struct rz_sysc_soc_id_init_data and adjusted the code
  accordingly
- dropped the RZ/G3S SoC detection code (it will be introduced in
  a separate patch)

 drivers/soc/renesas/rz-sysc.c | 72 +++++++++++++++++++++++++++++++++--
 drivers/soc/renesas/rz-sysc.h | 18 +++++++++
 2 files changed, 86 insertions(+), 4 deletions(-)

Comments

Biju Das Nov. 26, 2024, 9:30 a.m. UTC | #1
Hi Claudiu,

Thanks for the patch.

> -----Original Message-----
> From: Claudiu <claudiu.beznea@tuxon.dev>
> Sent: 26 November 2024 09:21
> Subject: [PATCH v2 04/15] soc: renesas: rz-sysc: Add SoC detection support
> 
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> The RZ SYSC controller has registers that keep the SoC ID data. Add driver support to retrieve the SoC
> ID and register a SoC driver.
> 
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>

Cheers,
Biju

> ---
> 
> Changes in v2:
> - this was patch 05/16 in v1
> - changed patch title and description
> - added SoC initialization code in its own function
> - addressed the review comments
> - introduced struct rz_sysc_soc_id_init_data and adjusted the code
>   accordingly
> - dropped the RZ/G3S SoC detection code (it will be introduced in
>   a separate patch)
> 
>  drivers/soc/renesas/rz-sysc.c | 72 +++++++++++++++++++++++++++++++++--
>  drivers/soc/renesas/rz-sysc.h | 18 +++++++++
>  2 files changed, 86 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c index
> dc0edacd7170..d34d295831b8 100644
> --- a/drivers/soc/renesas/rz-sysc.c
> +++ b/drivers/soc/renesas/rz-sysc.c
> @@ -14,9 +14,12 @@
>  #include <linux/refcount.h>
>  #include <linux/regmap.h>
>  #include <linux/seq_file.h>
> +#include <linux/sys_soc.h>
> 
>  #include "rz-sysc.h"
> 
> +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
> +
>  /**
>   * struct rz_sysc - RZ SYSC private data structure
>   * @base: SYSC base address
> @@ -211,6 +214,59 @@ static int rz_sysc_signals_init(struct rz_sysc *sysc,
>  	return 0;
>  }
> 
> +static int rz_sysc_soc_init(struct rz_sysc *sysc, const struct
> +of_device_id *match) {
> +	const struct rz_sysc_init_data *sysc_data = match->data;
> +	const struct rz_sysc_soc_id_init_data *soc_data = sysc_data->soc_id_init_data;
> +	struct soc_device_attribute *soc_dev_attr;
> +	const char *soc_id_start, *soc_id_end;
> +	u32 val, revision, specific_id;
> +	struct soc_device *soc_dev;
> +	char soc_id[32] = {0};
> +	u8 size;
> +
> +	if (!soc_data || !soc_data->family || !soc_data->offset ||
> +	    !soc_data->revision_mask)
> +		return -EINVAL;
> +
> +	soc_id_start = strchr(match->compatible, ',') + 1;
> +	soc_id_end = strchr(match->compatible, '-');
> +	size = soc_id_end - soc_id_start;
> +	if (size > 32)
> +		size = 32;
> +	strscpy(soc_id, soc_id_start, size);
> +
> +	soc_dev_attr = devm_kzalloc(sysc->dev, sizeof(*soc_dev_attr), GFP_KERNEL);
> +	if (!soc_dev_attr)
> +		return -ENOMEM;
> +
> +	soc_dev_attr->family = soc_data->family;
> +	soc_dev_attr->soc_id = devm_kstrdup(sysc->dev, soc_id, GFP_KERNEL);
> +	if (!soc_dev_attr->soc_id)
> +		return -ENOMEM;
> +
> +	val = readl(sysc->base + soc_data->offset);
> +	revision = field_get(soc_data->revision_mask, val);
> +	specific_id = field_get(soc_data->specific_id_mask, val);
> +	soc_dev_attr->revision = devm_kasprintf(sysc->dev, GFP_KERNEL, "%u", revision);
> +	if (!soc_dev_attr->revision)
> +		return -ENOMEM;
> +
> +	if (soc_data->id && specific_id != soc_data->id) {
> +		dev_warn(sysc->dev, "SoC mismatch (product = 0x%x)\n", specific_id);
> +		return -ENODEV;
> +	}
> +
> +	dev_info(sysc->dev, "Detected Renesas %s %s Rev %s\n", soc_dev_attr->family,
> +		 soc_dev_attr->soc_id, soc_dev_attr->revision);
> +
> +	soc_dev = soc_device_register(soc_dev_attr);
> +	if (IS_ERR(soc_dev))
> +		return PTR_ERR(soc_dev);
> +
> +	return 0;
> +}
> +
>  static struct regmap_config rz_sysc_regmap = {
>  	.name = "rz_sysc_regs",
>  	.reg_bits = 32,
> @@ -235,14 +291,15 @@ MODULE_DEVICE_TABLE(of, rz_sysc_match);  static int rz_sysc_probe(struct
> platform_device *pdev)  {
>  	const struct rz_sysc_init_data *data;
> +	const struct of_device_id *match;
>  	struct device *dev = &pdev->dev;
> -	struct rz_sysc *sysc;
>  	struct regmap *regmap;
> +	struct rz_sysc *sysc;
>  	int ret;
> 
> -	data = device_get_match_data(dev);
> -	if (!data || !data->max_register_offset)
> -		return -EINVAL;
> +	match = of_match_node(rz_sysc_match, dev->of_node);
> +	if (!match || !match->data)
> +		return -ENODEV;
> 
>  	sysc = devm_kzalloc(dev, sizeof(*sysc), GFP_KERNEL);
>  	if (!sysc)
> @@ -253,6 +310,13 @@ static int rz_sysc_probe(struct platform_device *pdev)
>  		return PTR_ERR(sysc->base);
> 
>  	sysc->dev = dev;
> +	ret = rz_sysc_soc_init(sysc, match);
> +	if (ret)
> +		return ret;
> +
> +	data = match->data;
> +	if (!data->max_register_offset)
> +		return -EINVAL;
> 
>  	ret = rz_sysc_signals_init(sysc, data->signals_init_data, data->num_signals);
>  	if (ret)
> diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h index
> bb850310c931..babca9c743c7 100644
> --- a/drivers/soc/renesas/rz-sysc.h
> +++ b/drivers/soc/renesas/rz-sysc.h
> @@ -35,13 +35,31 @@ struct rz_sysc_signal {
>  	refcount_t refcnt;
>  };
> 
> +/**
> + * struct rz_syc_soc_id_init_data - RZ SYSC SoC identification
> +initialization data
> + * @family: RZ SoC family
> + * @id: RZ SoC expected ID
> + * @offset: SYSC SoC ID register offset
> + * @revision_mask: SYSC SoC ID revision mask
> + * @specific_id_mask: SYSC SoC ID specific ID mask  */ struct
> +rz_sysc_soc_id_init_data {
> +	const char * const family;
> +	u32 id;
> +	u32 offset;
> +	u32 revision_mask;
> +	u32 specific_id_mask;
> +};
> +
>  /**
>   * struct rz_sysc_init_data - RZ SYSC initialization data
> + * @soc_id_init_data: RZ SYSC SoC ID initialization data
>   * @signals_init_data: RZ SYSC signals initialization data
>   * @num_signals: number of SYSC signals
>   * @max_register_offset: Maximum SYSC register offset to be used by the regmap config
>   */
>  struct rz_sysc_init_data {
> +	const struct rz_sysc_soc_id_init_data *soc_id_init_data;
>  	const struct rz_sysc_signal_init_data *signals_init_data;
>  	u32 num_signals;
>  	u32 max_register_offset;
> --
> 2.39.2
>
diff mbox series

Patch

diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c
index dc0edacd7170..d34d295831b8 100644
--- a/drivers/soc/renesas/rz-sysc.c
+++ b/drivers/soc/renesas/rz-sysc.c
@@ -14,9 +14,12 @@ 
 #include <linux/refcount.h>
 #include <linux/regmap.h>
 #include <linux/seq_file.h>
+#include <linux/sys_soc.h>
 
 #include "rz-sysc.h"
 
+#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
+
 /**
  * struct rz_sysc - RZ SYSC private data structure
  * @base: SYSC base address
@@ -211,6 +214,59 @@  static int rz_sysc_signals_init(struct rz_sysc *sysc,
 	return 0;
 }
 
+static int rz_sysc_soc_init(struct rz_sysc *sysc, const struct of_device_id *match)
+{
+	const struct rz_sysc_init_data *sysc_data = match->data;
+	const struct rz_sysc_soc_id_init_data *soc_data = sysc_data->soc_id_init_data;
+	struct soc_device_attribute *soc_dev_attr;
+	const char *soc_id_start, *soc_id_end;
+	u32 val, revision, specific_id;
+	struct soc_device *soc_dev;
+	char soc_id[32] = {0};
+	u8 size;
+
+	if (!soc_data || !soc_data->family || !soc_data->offset ||
+	    !soc_data->revision_mask)
+		return -EINVAL;
+
+	soc_id_start = strchr(match->compatible, ',') + 1;
+	soc_id_end = strchr(match->compatible, '-');
+	size = soc_id_end - soc_id_start;
+	if (size > 32)
+		size = 32;
+	strscpy(soc_id, soc_id_start, size);
+
+	soc_dev_attr = devm_kzalloc(sysc->dev, sizeof(*soc_dev_attr), GFP_KERNEL);
+	if (!soc_dev_attr)
+		return -ENOMEM;
+
+	soc_dev_attr->family = soc_data->family;
+	soc_dev_attr->soc_id = devm_kstrdup(sysc->dev, soc_id, GFP_KERNEL);
+	if (!soc_dev_attr->soc_id)
+		return -ENOMEM;
+
+	val = readl(sysc->base + soc_data->offset);
+	revision = field_get(soc_data->revision_mask, val);
+	specific_id = field_get(soc_data->specific_id_mask, val);
+	soc_dev_attr->revision = devm_kasprintf(sysc->dev, GFP_KERNEL, "%u", revision);
+	if (!soc_dev_attr->revision)
+		return -ENOMEM;
+
+	if (soc_data->id && specific_id != soc_data->id) {
+		dev_warn(sysc->dev, "SoC mismatch (product = 0x%x)\n", specific_id);
+		return -ENODEV;
+	}
+
+	dev_info(sysc->dev, "Detected Renesas %s %s Rev %s\n", soc_dev_attr->family,
+		 soc_dev_attr->soc_id, soc_dev_attr->revision);
+
+	soc_dev = soc_device_register(soc_dev_attr);
+	if (IS_ERR(soc_dev))
+		return PTR_ERR(soc_dev);
+
+	return 0;
+}
+
 static struct regmap_config rz_sysc_regmap = {
 	.name = "rz_sysc_regs",
 	.reg_bits = 32,
@@ -235,14 +291,15 @@  MODULE_DEVICE_TABLE(of, rz_sysc_match);
 static int rz_sysc_probe(struct platform_device *pdev)
 {
 	const struct rz_sysc_init_data *data;
+	const struct of_device_id *match;
 	struct device *dev = &pdev->dev;
-	struct rz_sysc *sysc;
 	struct regmap *regmap;
+	struct rz_sysc *sysc;
 	int ret;
 
-	data = device_get_match_data(dev);
-	if (!data || !data->max_register_offset)
-		return -EINVAL;
+	match = of_match_node(rz_sysc_match, dev->of_node);
+	if (!match || !match->data)
+		return -ENODEV;
 
 	sysc = devm_kzalloc(dev, sizeof(*sysc), GFP_KERNEL);
 	if (!sysc)
@@ -253,6 +310,13 @@  static int rz_sysc_probe(struct platform_device *pdev)
 		return PTR_ERR(sysc->base);
 
 	sysc->dev = dev;
+	ret = rz_sysc_soc_init(sysc, match);
+	if (ret)
+		return ret;
+
+	data = match->data;
+	if (!data->max_register_offset)
+		return -EINVAL;
 
 	ret = rz_sysc_signals_init(sysc, data->signals_init_data, data->num_signals);
 	if (ret)
diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h
index bb850310c931..babca9c743c7 100644
--- a/drivers/soc/renesas/rz-sysc.h
+++ b/drivers/soc/renesas/rz-sysc.h
@@ -35,13 +35,31 @@  struct rz_sysc_signal {
 	refcount_t refcnt;
 };
 
+/**
+ * struct rz_syc_soc_id_init_data - RZ SYSC SoC identification initialization data
+ * @family: RZ SoC family
+ * @id: RZ SoC expected ID
+ * @offset: SYSC SoC ID register offset
+ * @revision_mask: SYSC SoC ID revision mask
+ * @specific_id_mask: SYSC SoC ID specific ID mask
+ */
+struct rz_sysc_soc_id_init_data {
+	const char * const family;
+	u32 id;
+	u32 offset;
+	u32 revision_mask;
+	u32 specific_id_mask;
+};
+
 /**
  * struct rz_sysc_init_data - RZ SYSC initialization data
+ * @soc_id_init_data: RZ SYSC SoC ID initialization data
  * @signals_init_data: RZ SYSC signals initialization data
  * @num_signals: number of SYSC signals
  * @max_register_offset: Maximum SYSC register offset to be used by the regmap config
  */
 struct rz_sysc_init_data {
+	const struct rz_sysc_soc_id_init_data *soc_id_init_data;
 	const struct rz_sysc_signal_init_data *signals_init_data;
 	u32 num_signals;
 	u32 max_register_offset;