soc: starfive: Add socinfo driver for JHB100 SoC

Add a socinfo driver for the JHB100 SoC, exposing the SoC family, ID and
revision through the SoC bus. It is currently used to distinguish the two
revisions, A0 and A1.

The driver binds to the sys0 system controller node. That region only
contains the PLL controls, this revision ID register and a few debug
registers, so rather than describing an extra child node in the
devicetree, the sys0 PLL device is instantiated from here as an MFD cell.
The PLL driver then picks up the regmap from its parent's DT node.

Note that CONFIG_STARFIVE_JHB100_SOCINFO is therefore a build-time
prerequisite for the sys0 PLL clocks; see CLK_STARFIVE_JHB100_PLL.

Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
This commit is contained in:
Changhuang Liang 2026-08-28 02:56:07 -07:00 committed by Conor Dooley
parent c4a545d3e4
commit 96b35a1251
7 changed files with 130 additions and 0 deletions

View File

@ -24,6 +24,7 @@ source "drivers/soc/renesas/Kconfig"
source "drivers/soc/rockchip/Kconfig"
source "drivers/soc/samsung/Kconfig"
source "drivers/soc/sophgo/Kconfig"
source "drivers/soc/starfive/Kconfig"
source "drivers/soc/sunxi/Kconfig"
source "drivers/soc/tegra/Kconfig"
source "drivers/soc/ti/Kconfig"

View File

@ -30,6 +30,7 @@ obj-y += renesas/
obj-y += rockchip/
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
obj-y += sophgo/
obj-y += starfive/
obj-y += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += ti/

View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "StarFive SoC (System On Chip) specific Drivers"
source "drivers/soc/starfive/socinfo/Kconfig"
endmenu

View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += socinfo/

View File

@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
config STARFIVE_JHB100_SOCINFO
bool "StarFive JHB100 SoC Information"
depends on ARCH_STARFIVE || COMPILE_TEST
select SOC_BUS
select MFD_CORE
select MFD_SYSCON
default y
help
Include support for the SoC bus socinfo for the StarFive JHB100 SoC
platforms to provide information about the SoC family and variant
to user space.

View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_STARFIVE_JHB100_SOCINFO) += jhb100-socinfo.o

View File

@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2025 StarFive Technology Co., Ltd.
*
* Author: Changhuang Liang <changhuang.liang@starfivetech.com>
*/
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/sys_soc.h>
#define JHB100_REV_ID 0x38
#define JHB100_REV_ID_CHAR GENMASK(3, 2)
#define JHB100_REV_ID_NUM GENMASK(1, 0)
/*
* The sys0 system controller region only contains the PLL controls, this
* revision ID register and a few debug registers, so instead of describing
* a child node in the devicetree the PLL device is instantiated from here.
*/
static const struct mfd_cell jhb100_sys0_syscon_cells[] = {
{ .name = "jhb100-sys0-pll", },
};
static void jhb100_socinfo_unregister(void *data)
{
soc_device_unregister(data);
}
static int jhb100_socinfo_probe(struct platform_device *pdev)
{
struct soc_device_attribute *attrs;
struct device *dev = &pdev->dev;
struct soc_device *soc_dev;
struct regmap *regmap;
char rev_char;
u32 rev_id;
int ret;
regmap = syscon_node_to_regmap(dev->of_node);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"failed to get syscon regmap\n");
ret = regmap_read(regmap, JHB100_REV_ID, &rev_id);
if (ret)
return dev_err_probe(dev, ret, "failed to read revision ID\n");
attrs = devm_kzalloc(dev, sizeof(*attrs), GFP_KERNEL);
if (!attrs)
return -ENOMEM;
rev_char = FIELD_GET(JHB100_REV_ID_CHAR, rev_id) + 'A';
attrs->family = "JH";
attrs->soc_id = "JHB100";
attrs->revision = devm_kasprintf(dev, GFP_KERNEL, "%c%lu", rev_char,
FIELD_GET(JHB100_REV_ID_NUM, rev_id));
if (!attrs->revision)
return -ENOMEM;
soc_dev = soc_device_register(attrs);
if (IS_ERR(soc_dev))
return dev_err_probe(dev, PTR_ERR(soc_dev),
"failed to register SoC device\n");
ret = devm_add_action_or_reset(dev, jhb100_socinfo_unregister, soc_dev);
if (ret)
return ret;
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
jhb100_sys0_syscon_cells,
ARRAY_SIZE(jhb100_sys0_syscon_cells),
NULL, 0, NULL);
if (ret)
return dev_err_probe(dev, ret, "failed to add mfd cells\n");
dev_info(dev, "StarFive %s SoC rev(%s)\n", attrs->soc_id, attrs->revision);
return 0;
}
static const struct of_device_id jhb100_socinfo_of_match[] = {
{ .compatible = "starfive,jhb100-sys0-syscon" },
{ /* sentinel */ }
};
static struct platform_driver jhb100_socinfo_driver = {
.probe = jhb100_socinfo_probe,
.driver = {
.name = "jhb100-socinfo",
.of_match_table = jhb100_socinfo_of_match,
},
};
static int __init jhb100_socinfo_init(void)
{
return platform_driver_register(&jhb100_socinfo_driver);
}
subsys_initcall(jhb100_socinfo_init);