soc: Add VIA/WonderMedia SoC identification driver

Add a small SOC bus driver to parse the chip ID and revision made
available on VIA/WonderMedia SoCs via their system configuration
controller's SCC_ID register.

This is intended to select appropriate sets of on-chip device quirks
at runtime, as it has been found that even within the same SoC
version there can be register-incompatible differences, such as
with the SDMMC controller on WM8505 rev. A0-A1 vs. rev. A2.

The list of SoC versions is compiled from various vendor source dumps
and not all of them have corresponding mainline driver support.
Some of them also have been seen with varying on-chip markings while
sharing the same hardware chip ID's (as is the case with e.g. WM8850
vs. WM8950). In such cases the selection of names to use here among
those seen in various source dumps and chip markings was arbitrary.

Suggested by Krzysztof at [1] - thanks a lot!

[1] https://lore.kernel.org/all/14de236b-e2a7-4bde-986d-1e5ffddd01b4@kernel.org/

Signed-off-by: Alexey Charkov <alchark@gmail.com>
Link: https://lore.kernel.org/r/20250503-wmt-soc-driver-v3-2-2daa9056fa10@gmail.com
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
This commit is contained in:
Alexey Charkov
2025-05-03 15:52:32 +04:00
committed by Krzysztof Kozlowski
parent 04e394d6e2
commit 96f94587d7
5 changed files with 148 additions and 0 deletions

View File

@@ -28,6 +28,7 @@ source "drivers/soc/tegra/Kconfig"
source "drivers/soc/ti/Kconfig"
source "drivers/soc/ux500/Kconfig"
source "drivers/soc/versatile/Kconfig"
source "drivers/soc/vt8500/Kconfig"
source "drivers/soc/xilinx/Kconfig"
endmenu

View File

@@ -34,4 +34,5 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-y += versatile/
obj-y += vt8500/
obj-y += xilinx/

View File

@@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-only
if ARCH_VT8500 || COMPILE_TEST
menu "VIA/WonderMedia SoC drivers"
config WMT_SOCINFO
bool "VIA/WonderMedia SoC Information driver"
default ARCH_VT8500
select SOC_BUS
help
Say yes to support decoding of VIA/WonderMedia system configuration
register information. This currently includes just the chip ID register
which helps identify the exact hardware revision of the SoC the kernel
is running on (to know if any revision-specific quirks are required)
endmenu
endif

View File

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

View File

@@ -0,0 +1,125 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2025 Alexey Charkov <alchark@gmail.com>
* Based on aspeed-socinfo.c
*/
#include <linux/dev_printk.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/sys_soc.h>
static const struct {
const char *name;
const u32 id;
} chip_id_table[] = {
/* VIA */
{ "VT8420", 0x3300 },
{ "VT8430", 0x3357 },
{ "VT8500", 0x3400 },
/* WonderMedia */
{ "WM8425", 0x3429 },
{ "WM8435", 0x3437 },
{ "WM8440", 0x3451 },
{ "WM8505", 0x3426 },
{ "WM8650", 0x3465 },
{ "WM8750", 0x3445 },
{ "WM8850", 0x3481 },
{ "WM8880", 0x3498 },
};
static const char *sccid_to_name(u32 sccid)
{
u32 id = sccid >> 16;
unsigned int i;
for (i = 0 ; i < ARRAY_SIZE(chip_id_table) ; ++i) {
if (chip_id_table[i].id == id)
return chip_id_table[i].name;
}
return "Unknown";
}
static int wmt_socinfo_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct soc_device_attribute *attrs;
struct soc_device *soc_dev;
char letter, digit;
void __iomem *reg;
u32 sccid;
reg = devm_of_iomap(&pdev->dev, np, 0, NULL);
if (IS_ERR(reg))
return PTR_ERR(reg);
sccid = readl(reg);
attrs = devm_kzalloc(&pdev->dev, sizeof(*attrs), GFP_KERNEL);
if (!attrs)
return -ENOMEM;
/*
* Machine: VIA APC Rock
* Family: WM8850
* Revision: A2
* SoC ID: raw silicon revision id (34810103 in hexadecimal)
*/
attrs->family = sccid_to_name(sccid);
letter = (sccid >> 8) & 0xf;
letter = (letter - 1) + 'A';
digit = sccid & 0xff;
digit = (digit - 1) + '0';
attrs->revision = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%c%c", letter, digit);
attrs->soc_id = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%08x", sccid);
if (!attrs->revision || !attrs->soc_id)
return -ENOMEM;
soc_dev = soc_device_register(attrs);
if (IS_ERR(soc_dev))
return PTR_ERR(soc_dev);
dev_info(&pdev->dev,
"VIA/WonderMedia %s rev %s (%s)\n",
attrs->family,
attrs->revision,
attrs->soc_id);
platform_set_drvdata(pdev, soc_dev);
return 0;
}
static void wmt_socinfo_remove(struct platform_device *pdev)
{
struct soc_device *soc_dev = platform_get_drvdata(pdev);
soc_device_unregister(soc_dev);
}
static const struct of_device_id wmt_socinfo_ids[] = {
{ .compatible = "via,vt8500-scc-id" },
{ /* Sentinel */ },
};
static struct platform_driver wmt_socinfo = {
.probe = wmt_socinfo_probe,
.remove = wmt_socinfo_remove,
.driver = {
.name = "wmt-socinfo",
.of_match_table = wmt_socinfo_ids,
},
};
module_platform_driver(wmt_socinfo);
MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
MODULE_DESCRIPTION("VIA/WonderMedia socinfo driver");
MODULE_LICENSE("GPL");