[PATCH 1/3] soc: mediatek: mtk-socinfo: Add driver for getting chip information

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add driver for socinfo retrieval. This patch includes the following:
1. mtk-socinfo driver for chip info retrieval
2. Related changes to Makefile and Kconfig

Signed-off-by: William-tw Lin <william-tw.lin@xxxxxxxxxxxx>
---
 drivers/soc/mediatek/Kconfig       |  18 +++
 drivers/soc/mediatek/Makefile      |   1 +
 drivers/soc/mediatek/mtk-socinfo.c | 203 +++++++++++++++++++++++++++
 drivers/soc/mediatek/mtk-socinfo.h | 213 +++++++++++++++++++++++++++++
 4 files changed, 435 insertions(+)
 create mode 100644 drivers/soc/mediatek/mtk-socinfo.c
 create mode 100644 drivers/soc/mediatek/mtk-socinfo.h

diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index a88cf04fc803..50bd9ec75ca5 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -91,4 +91,22 @@ config MTK_SVS
 	  chip process corner, temperatures and other factors. Then DVFS
 	  driver could apply SVS bank voltage to PMIC/Buck.
 
+config MTK_SOCINFO
+	tristate "MediaTek SOCINFO"
+	depends on MTK_EFUSE && NVMEM
+	help
+	  Say y here to enable mtk socinfo information.
+	  This enables a sysfs node which shows attributes of MTK soc info.
+	  Information of soc info includes the manufacturer, the marketing
+	  name, and the soc used.
+
+config MTK_SOCINFO_DEBUG
+	tristate "MediaTek SOCINFO debug"
+	depends on MTK_SOCINFO
+	help
+	  Say y here to enables a debug node which shows MTK SOC information.
+	  This enables a debug node that gives details on MTK soc info attributes.
+	  Information included in this debug node includes the manufacturer, the marketing
+	  name, the soc used, as well as the segment of the soc.
+
 endmenu
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index 8c0ddacbcde8..c900e5f13a35 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
 obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
 obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
 obj-$(CONFIG_MTK_SVS) += mtk-svs.o
+obj-$(CONFIG_MTK_SOCINFO) += mtk-socinfo.o
diff --git a/drivers/soc/mediatek/mtk-socinfo.c b/drivers/soc/mediatek/mtk-socinfo.c
new file mode 100644
index 000000000000..8c8964eb4670
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-socinfo.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+#include <linux/slab.h>
+#include "mtk-socinfo.h"
+
+
+#if IS_ENABLED(CONFIG_MTK_SOCINFO_DEBUG)
+static int mtk_socinfo_socinfo_debug_show(struct seq_file *m, void *p)
+{
+	struct mtk_socinfo *mtk_socinfop = (struct mtk_socinfo *)m->private;
+
+	seq_printf(m, "SOC Manufacturer:   %s\n", soc_manufacturer);
+	seq_printf(m, "SOC Name:           %s\n", mtk_socinfop->name_data->soc_name);
+	seq_printf(m, "SOC segment Name:   %s\n", mtk_socinfop->name_data->soc_segment_name);
+	seq_printf(m, "Marketing Name:     %s\n", mtk_socinfop->name_data->marketing_name);
+
+	return 0;
+}
+DEBUG_FOPS_RO(socinfo);
+
+static int mtk_socinfo_create_debug_cmds(struct mtk_socinfo *mtk_socinfop)
+{
+	const char *d = "mtk-socinfo";
+
+	struct mtk_socinfo_dentry {
+		const char *name;
+		const struct file_operations *fops;
+	};
+
+	struct mtk_socinfo_dentry mtk_socinfo_entries[] = {
+		MTK_SOCINFO_DENTRY_DATA(socinfo),
+	};
+
+	mtk_socinfo_dir = debugfs_create_dir(d, NULL);
+	if (IS_ERR(mtk_socinfo_dir)) {
+		dev_err(mtk_socinfop->dev, "Cannot create %s\n", d);
+		return 0;
+	}
+
+	file_entry = debugfs_create_file(mtk_socinfo_entries[0].name, 0664,
+					mtk_socinfo_dir, mtk_socinfop,
+					mtk_socinfo_entries[0].fops);
+	if (IS_ERR(file_entry)) {
+		dev_err(mtk_socinfop->dev, "Cannot create %s/%s\n", d, mtk_socinfo_entries[0].name);
+		return PTR_ERR(file_entry);
+	}
+	return 0;
+}
+#endif
+
+static int mtk_socinfo_create_socinfo_node(struct mtk_socinfo *mtk_socinfop)
+{
+	struct soc_device_attribute *attrs;
+	static char machine[30] = {0};
+
+	attrs = devm_kzalloc(mtk_socinfop->dev, sizeof(*attrs), GFP_KERNEL);
+	if (!attrs) {
+		return -ENOMEM;
+	}
+
+	snprintf(machine, 30, "%s (%s)", mtk_socinfop->name_data->marketing_name,
+		mtk_socinfop->name_data->soc_name);
+	attrs->family = soc_manufacturer;
+	attrs->machine = machine;
+
+	soc_dev = soc_device_register(attrs);
+	if (IS_ERR(soc_dev)) {
+		dev_err(mtk_socinfop->dev, "Cannot create soc node, soc_device_register failed\n");
+		return PTR_ERR(soc_dev);
+	}
+
+	dev_info(mtk_socinfop->dev, "%s %s SoC detected.\n", MODULE_NAME, attrs->machine);
+	return 0;
+}
+
+static int mtk_socinfo_get_socinfo_data(struct mtk_socinfo *mtk_socinfop)
+{
+	struct efuse_data *soc_efuse_data_infop = mtk_socinfop->soc_data->efuse_data;
+	struct name_data *soc_name_data_infop = mtk_socinfop->soc_data->name_data;
+	unsigned int soc_efuse_data_count = mtk_socinfop->soc_data->efuse_data_count;
+	unsigned int soc_segment_count = mtk_socinfop->soc_data->efuse_segment_count;
+	unsigned int i = 0, j = 0;
+	struct efuse_data *temp_efuse_datap;
+	struct nvmem_cell *cell;
+	size_t efuse_bytes;
+	char *nvmem_cell_name = "";
+	u32 *efuse_temp_bufp;
+	int match_segment_index = -1;
+
+	for (i = 0; i < soc_segment_count; i++) {
+		bool match_segment = true;
+
+		for (j = 0; j < soc_efuse_data_count; j++) {
+			temp_efuse_datap = soc_efuse_data_infop + (i * soc_efuse_data_count + j);
+			nvmem_cell_name = temp_efuse_datap->nvmem_cell_name;
+			cell = nvmem_cell_get(mtk_socinfop->dev, nvmem_cell_name);
+			if (IS_ERR_OR_NULL(cell)) {
+				dev_err(mtk_socinfop->dev, "%s cell not found\n", nvmem_cell_name);
+				goto out;
+			}
+			efuse_temp_bufp = (u32 *)nvmem_cell_read(cell, &efuse_bytes);
+			nvmem_cell_put(cell);
+			if (*efuse_temp_bufp != temp_efuse_datap->efuse_data) {
+				match_segment = false;
+				break;
+			}
+		}
+		if (match_segment) {
+			match_segment_index = i;
+			mtk_socinfop->name_data = soc_name_data_infop + i;
+		}
+	}
+
+out:
+	kfree(efuse_temp_bufp);
+	return match_segment_index;
+}
+
+static const struct of_device_id mtk_socinfo_id_table[] = {
+	{ .compatible = "mediatek,mt8173-socinfo", .data = &socinfo_data_table[INDEX_MT8173]},
+	{ .compatible = "mediatek,mt8183-socinfo", .data = &socinfo_data_table[INDEX_MT8183]},
+	{ .compatible = "mediatek,mt8186-socinfo", .data = &socinfo_data_table[INDEX_MT8186]},
+	{ .compatible = "mediatek,mt8188-socinfo", .data = &socinfo_data_table[INDEX_MT8188]},
+	{ .compatible = "mediatek,mt8192-socinfo", .data = &socinfo_data_table[INDEX_MT8192]},
+	{ .compatible = "mediatek,mt8195-socinfo", .data = &socinfo_data_table[INDEX_MT8195]},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, mtk_socinfo_id_table);
+
+static int mtk_socinfo_probe(struct platform_device *pdev)
+{
+	struct mtk_socinfo *mtk_socinfop;
+	int ret = 0;
+
+	mtk_socinfop = devm_kzalloc(&pdev->dev, sizeof(*mtk_socinfop), GFP_KERNEL);
+	if (!mtk_socinfop)
+		return -ENOMEM;
+
+	mtk_socinfop->dev = &pdev->dev;
+	mtk_socinfop->soc_data = (struct socinfo_data *)of_device_get_match_data(mtk_socinfop->dev);
+	if (!mtk_socinfop->soc_data) {
+		dev_err(mtk_socinfop->dev, "No mtk-socinfo platform data found\n");
+		return -EPERM;
+	}
+
+	ret = mtk_socinfo_get_socinfo_data(mtk_socinfop);
+	if (ret < 0) {
+		dev_err(mtk_socinfop->dev, "Failed to get socinfo data (ret = %d)\n", ret);
+		return -EINVAL;
+	}
+
+	ret = mtk_socinfo_create_socinfo_node(mtk_socinfop);
+	if (ret != 0) {
+		dev_err(mtk_socinfop->dev, "Failed to create socinfo node (ret = %d)\n", ret);
+		return ret;
+	}
+
+#if IS_ENABLED(CONFIG_MTK_SOCINFO_DEBUG)
+	ret = mtk_socinfo_create_debug_cmds(mtk_socinfop);
+	if (ret != 0) {
+		dev_err(mtk_socinfop->dev, "Failed to create socinfo debug node (ret = %d)\n", ret);
+		return ret;
+	}
+#endif
+	return 0;
+}
+
+static int mtk_socinfo_remove(struct platform_device *pdev)
+{
+	if (soc_dev)
+		soc_device_unregister(soc_dev);
+#if IS_ENABLED(CONFIG_MTK_SOCINFO_DEBUG)
+	debugfs_remove(file_entry);
+#endif
+	return 0;
+}
+
+static struct platform_driver mtk_socinfo = {
+	.probe          = mtk_socinfo_probe,
+	.remove         = mtk_socinfo_remove,
+	.driver         = {
+		.name   = "mtk_socinfo",
+		.owner  = THIS_MODULE,
+		.of_match_table = mtk_socinfo_id_table,
+	},
+};
+module_platform_driver(mtk_socinfo);
+MODULE_AUTHOR("William-TW LIN <william-tw.lin@xxxxxxxxxxxx>");
+MODULE_DESCRIPTION("Mediatek socinfo driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mtk-socinfo.h b/drivers/soc/mediatek/mtk-socinfo.h
new file mode 100644
index 000000000000..8fd490311c8b
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-socinfo.h
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ */
+
+#ifndef __MTK_SOCINFO_H__
+#define __MTK_SOCINFO_H__
+
+#define MODULE_NAME	"[mtk-socinfo]"
+
+#define DEBUG_FOPS_RO(name)						\
+	static int mtk_socinfo_##name##_debug_open(struct inode *inode,		\
+					   struct file *filp)		\
+	{								\
+		return single_open(filp, mtk_socinfo_##name##_debug_show,	\
+				   inode->i_private);			\
+	}								\
+	static const struct file_operations mtk_socinfo_##name##_debug_fops = {	\
+		.owner = THIS_MODULE,					\
+		.open = mtk_socinfo_##name##_debug_open,			\
+		.read = seq_read,					\
+		.llseek = seq_lseek,					\
+		.release = single_release,				\
+	}
+
+#define MTK_SOCINFO_DENTRY_DATA(name)	{__stringify(name), &mtk_socinfo_##name##_debug_fops}
+
+const char *soc_manufacturer = "MediaTek";
+
+struct soc_device *soc_dev;
+struct dentry *mtk_socinfo_dir, *file_entry;
+
+struct mtk_socinfo {
+	struct device *dev;
+	struct name_data *name_data;
+	struct socinfo_data *soc_data;
+};
+
+struct efuse_data {
+	char *nvmem_cell_name;
+	u32 efuse_data;
+};
+
+struct name_data {
+	char *soc_name;
+	char *soc_segment_name;
+	char *marketing_name;
+};
+
+struct socinfo_data {
+	char *soc_name;
+	struct efuse_data *efuse_data;
+	struct name_data *name_data;
+	unsigned int efuse_segment_count;
+	unsigned int efuse_data_count;
+};
+
+enum socinfo_data_index {
+	INDEX_MT8186 = 0,
+	INDEX_MT8188,
+	INDEX_MT8195,
+	INDEX_MT8192,
+	INDEX_MT8183,
+	INDEX_MT8173,
+	SOCINFO_DATA_LAST_INDEX
+};
+
+/* begin 8186 info */
+#define mtk_mt8186_EFUSE_DATA_COUNT 1
+static struct efuse_data mtk_mt8186_efuse_data_info[][mtk_mt8186_EFUSE_DATA_COUNT] = {
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x81861001}},
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x81862001}},
+};
+
+static struct name_data mtk_mt8186_name_data_info[] = {
+	{.soc_name = "MT8186",
+	 .soc_segment_name = "MT8186GV/AZA",
+	 .marketing_name = "Kompanio 520"},
+	{.soc_name = "MT8186T",
+	 .soc_segment_name = "MT8186TV/AZA",
+	 .marketing_name = "Kompanio 528"},
+};
+/* end 8186 info */
+
+/* begin 8188 info */
+#define mtk_mt8188_EFUSE_DATA_COUNT 2
+static struct efuse_data mtk_mt8188_efuse_data_info[][mtk_mt8188_EFUSE_DATA_COUNT] = {
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x81880000},
+	 {.nvmem_cell_name = "socinfo-data2", .efuse_data = 0x00000010}},
+	 {{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x81880000},
+	 {.nvmem_cell_name = "socinfo-data2", .efuse_data = 0x00000011}},
+};
+
+static struct name_data mtk_mt8188_name_data_info[] = {
+	{.soc_name = "MT8188",
+	 .soc_segment_name = "MT8188GV/AZA",
+	 .marketing_name = "Kompanio 830"},
+	{.soc_name = "MT8188",
+	 .soc_segment_name = "MT8188GV/HZA",
+	 .marketing_name = "Kompanio 830"},
+};
+/* end 8188 info */
+
+/* begin 8195 info */
+#define mtk_mt8195_EFUSE_DATA_COUNT 1
+static struct efuse_data mtk_mt8195_efuse_data_info[][mtk_mt8195_EFUSE_DATA_COUNT] = {
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x81950300}},
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x81950304}},
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x81950400}},
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x81950404}},
+};
+
+static struct name_data mtk_mt8195_name_data_info[] = {
+	{.soc_name = "MT8195",
+	 .soc_segment_name = "MT8195GV/EZA",
+	 .marketing_name = "Kompanio 1200"},
+	{.soc_name = "MT8195",
+	 .soc_segment_name = "MT8195GV/EHZA",
+	 .marketing_name = "Kompanio 1200"},
+	{.soc_name = "MT8195T",
+	 .soc_segment_name = "MT8195TV/EZA",
+	 .marketing_name = "Kompanio 1380"},
+	{.soc_name = "MT8195T",
+	 .soc_segment_name = "MT8195TV/EHZA",
+	 .marketing_name = "Kompanio 1380"},
+};
+/* end 8195 info */
+
+/* begin 8192 info */
+#define mtk_mt8192_EFUSE_DATA_COUNT 2
+static struct efuse_data mtk_mt8192_efuse_data_info[][mtk_mt8192_EFUSE_DATA_COUNT] = {
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x00001100},
+	 {.nvmem_cell_name = "socinfo-data2", .efuse_data = 0x00040080}},
+	 {{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x00000100},
+	 {.nvmem_cell_name = "socinfo-data2", .efuse_data = 0x000400C0}},
+};
+
+static struct name_data mtk_mt8192_name_data_info[] = {
+	{.soc_name = "MT8192",
+	 .soc_segment_name = "MT8192V/AZA",
+	 .marketing_name = "Kompanio 820"},
+	{.soc_name = "MT8192T",
+	 .soc_segment_name = "MT8192V/ATZA",
+	 .marketing_name = "Kompanio 828"},
+};
+/* end 8192 info */
+
+/* begin 8183 info */
+#define mtk_mt8183_EFUSE_DATA_COUNT 2
+static struct efuse_data mtk_mt8183_efuse_data_info[][mtk_mt8183_EFUSE_DATA_COUNT] = {
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x00010043},
+	 {.nvmem_cell_name = "socinfo-data2", .efuse_data = 0x00000840}},
+};
+
+static struct name_data mtk_mt8183_name_data_info[] = {
+	{.soc_name = "MT8183",
+	 .soc_segment_name = "MT8183V/AZA",
+	 .marketing_name = "Kompanio 500"},
+};
+/* end 8183 info */
+
+/* begin 8173 info */
+#define mtk_mt8173_EFUSE_DATA_COUNT 2
+static struct efuse_data mtk_mt8173_efuse_data_info[][mtk_mt8173_EFUSE_DATA_COUNT] = {
+	{{.nvmem_cell_name = "socinfo-data1", .efuse_data = 0x6CA20004},
+	 {.nvmem_cell_name = "socinfo-data2", .efuse_data = 0x10000000}},
+};
+
+static struct name_data mtk_mt8173_name_data_info[] = {
+	{.soc_name = "MT8173",
+	 .soc_segment_name = "MT8173V/AC",
+	 .marketing_name = "MT8173"},
+};
+/* end 8173 info */
+
+/* begin socinfo_data table */
+/* for get_soc_data lookup purposes */
+static struct socinfo_data socinfo_data_table[] = {
+	[INDEX_MT8186] = {.soc_name = "mt8186",
+			  .efuse_data = &(mtk_mt8186_efuse_data_info[0][0]),
+			  .name_data = mtk_mt8186_name_data_info,
+			  .efuse_segment_count = ARRAY_SIZE(mtk_mt8186_name_data_info),
+			  .efuse_data_count = mtk_mt8186_EFUSE_DATA_COUNT},
+	[INDEX_MT8188] = {.soc_name = "mt8188",
+			  .efuse_data = &(mtk_mt8188_efuse_data_info[0][0]),
+			  .name_data = mtk_mt8188_name_data_info,
+			  .efuse_segment_count = ARRAY_SIZE(mtk_mt8188_name_data_info),
+			  .efuse_data_count = mtk_mt8188_EFUSE_DATA_COUNT},
+	[INDEX_MT8195] = {.soc_name = "mt8195",
+			  .efuse_data = &(mtk_mt8195_efuse_data_info[0][0]),
+			  .name_data = mtk_mt8195_name_data_info,
+			  .efuse_segment_count = ARRAY_SIZE(mtk_mt8195_name_data_info),
+			  .efuse_data_count = mtk_mt8195_EFUSE_DATA_COUNT},
+	[INDEX_MT8192] = {.soc_name = "mt8192",
+			  .efuse_data = &(mtk_mt8192_efuse_data_info[0][0]),
+			  .name_data = mtk_mt8192_name_data_info,
+			  .efuse_segment_count = ARRAY_SIZE(mtk_mt8192_name_data_info),
+			  .efuse_data_count = mtk_mt8192_EFUSE_DATA_COUNT},
+	[INDEX_MT8183] = {.soc_name = "mt8183",
+			  .efuse_data = &(mtk_mt8183_efuse_data_info[0][0]),
+			  .name_data = mtk_mt8183_name_data_info,
+			  .efuse_segment_count = ARRAY_SIZE(mtk_mt8183_name_data_info),
+			  .efuse_data_count = mtk_mt8183_EFUSE_DATA_COUNT},
+	[INDEX_MT8173] = {.soc_name = "mt8173",
+			  .efuse_data = &(mtk_mt8173_efuse_data_info[0][0]),
+			  .name_data = mtk_mt8173_name_data_info,
+			  .efuse_segment_count = ARRAY_SIZE(mtk_mt8173_name_data_info),
+			  .efuse_data_count = mtk_mt8173_EFUSE_DATA_COUNT},
+};
+/* end socinfo_data table */
+
+
+#endif /* __MTK_SOCINFO_H__ */
-- 
2.18.0




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux