mirror of
https://github.com/torvalds/linux.git
synced 2026-06-05 04:56:13 +02:00
soc: renesas: Add SYSC driver for Renesas RZ family
The RZ/G3S system controller (SYSC) has various registers that control different functionalities. One of the exposed register offers information about the SoC identification. Add a driver that identifies the SoC. Later the driver will be extended with other functionalities. Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Link: https://lore.kernel.org/20250128031342.52675-2-john.madieu.xa@bp.renesas.com Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
This commit is contained in:
parent
2014c95afe
commit
c1aca55882
|
|
@ -383,4 +383,7 @@ config PWC_RZV2M
|
|||
config RST_RCAR
|
||||
bool "Reset Controller support for R-Car" if COMPILE_TEST
|
||||
|
||||
config SYSC_RZ
|
||||
bool "System controller for RZ SoCs" if COMPILE_TEST
|
||||
|
||||
endif # SOC_RENESAS
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@ endif
|
|||
# Family
|
||||
obj-$(CONFIG_PWC_RZV2M) += pwc-rzv2m.o
|
||||
obj-$(CONFIG_RST_RCAR) += rcar-rst.o
|
||||
obj-$(CONFIG_SYSC_RZ) += rz-sysc.o
|
||||
|
|
|
|||
123
drivers/soc/renesas/rz-sysc.c
Normal file
123
drivers/soc/renesas/rz-sysc.c
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* RZ System controller driver
|
||||
*
|
||||
* Copyright (C) 2024 Renesas Electronics Corp.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.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
|
||||
* @dev: SYSC device pointer
|
||||
*/
|
||||
struct rz_sysc {
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
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};
|
||||
size_t size;
|
||||
|
||||
soc_id_start = strchr(match->compatible, ',') + 1;
|
||||
soc_id_end = strchr(match->compatible, '-');
|
||||
size = soc_id_end - soc_id_start + 1;
|
||||
if (size > 32)
|
||||
size = sizeof(soc_id);
|
||||
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 = devm_kstrdup(sysc->dev, soc_data->family, GFP_KERNEL);
|
||||
if (!soc_dev_attr->family)
|
||||
return -ENOMEM;
|
||||
|
||||
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->devid_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 const struct of_device_id rz_sysc_match[] = {
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rz_sysc_match);
|
||||
|
||||
static int rz_sysc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rz_sysc *sysc;
|
||||
|
||||
match = of_match_node(rz_sysc_match, dev->of_node);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
sysc = devm_kzalloc(dev, sizeof(*sysc), GFP_KERNEL);
|
||||
if (!sysc)
|
||||
return -ENOMEM;
|
||||
|
||||
sysc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(sysc->base))
|
||||
return PTR_ERR(sysc->base);
|
||||
|
||||
sysc->dev = dev;
|
||||
return rz_sysc_soc_init(sysc, match);
|
||||
}
|
||||
|
||||
static struct platform_driver rz_sysc_driver = {
|
||||
.driver = {
|
||||
.name = "renesas-rz-sysc",
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = rz_sysc_match
|
||||
},
|
||||
.probe = rz_sysc_probe
|
||||
};
|
||||
|
||||
static int __init rz_sysc_init(void)
|
||||
{
|
||||
return platform_driver_register(&rz_sysc_driver);
|
||||
}
|
||||
subsys_initcall(rz_sysc_init);
|
||||
|
||||
MODULE_DESCRIPTION("Renesas RZ System Controller Driver");
|
||||
MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
37
drivers/soc/renesas/rz-sysc.h
Normal file
37
drivers/soc/renesas/rz-sysc.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Renesas RZ System Controller
|
||||
*
|
||||
* Copyright (C) 2024 Renesas Electronics Corp.
|
||||
*/
|
||||
|
||||
#ifndef __SOC_RENESAS_RZ_SYSC_H__
|
||||
#define __SOC_RENESAS_RZ_SYSC_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* struct rz_syc_soc_id_init_data - RZ SYSC SoC identification initialization data
|
||||
* @family: RZ SoC family
|
||||
* @id: RZ SoC expected ID
|
||||
* @devid_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 devid_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
|
||||
*/
|
||||
struct rz_sysc_init_data {
|
||||
const struct rz_sysc_soc_id_init_data *soc_id_init_data;
|
||||
};
|
||||
|
||||
#endif /* __SOC_RENESAS_RZ_SYSC_H__ */
|
||||
Loading…
Reference in New Issue
Block a user