问题描述:
## Syscon框架的基本概念
Syscon框架是Linux内核提供的一种用于管理系统控制器寄存器的抽象层,它通过regmap接口为多个驱动程序提供对共享系统控制寄存器的统一访问方式。
Syscon框架封装了regmap接口,为驱动程序提供了简单、一致的寄存器访问接口。
## Syscon框架的使用场景
### 1. 多驱动共享系统控制器寄存器
当多个驱动程序需要访问同一组系统控制器寄存器时,syscon框架提供了统一的访问接口,避免了资源冲突。
示例场景 :
- 时钟控制器、电源管理器、复位控制器等多个驱动都需要访问系统控制寄存器
- 不同的外设驱动需要配置相同的系统控制寄存器中的不同位域
### 2. 系统级配置管理
系统启动和运行过程中的各种配置,如时钟 gating、电源域控制、复位控制等。
示例场景 :
- SoC系统初始化时的时钟配置
- 动态电源管理中的电源域开关控制
- 系统睡眠/唤醒过程中的寄存器配置日志
添加打印日志信息
分析步骤
第1步:
第2步:
...代码片段
设备树
/* 预留内存区域 */
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
/* 4KB内存用于模拟寄存器 */
syscon_mem: syscon-mem@10000000 {
reg = <0x70000000 0x400>;
no-map;
};
};
/* syscon控制器 */
syscon_ctrl: syscon@0 {
compatible = "syscon";
reg = <0x70000000 0x400>;
reg-io-width = <4>;
};
/* 测试设备 */
test_device0: test-device@0 {
compatible = "demo,syscon-test";
syscon = <&syscon_ctrl>; /* 引用syscon控制器 */
ctrl-reg = <0x00>; /* 控制寄存器偏移 */
data-reg = <0x04>; /* 数据寄存器偏移 */
};
test_device1: test-device@1 {
compatible = "demo,syscon-test1";
syscon = <&syscon_ctrl>; /* 引用syscon控制器 */
ctrl-reg = <0x00>; /* 控制寄存器偏移 */
data-reg = <0x04>; /* 数据寄存器偏移 */
};
设备驱动代码1:
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/of.h>
/* 寄存器位定义 */
#define CTRL_EN BIT(0)
#define CTRL_RST BIT(1)
/* 驱动私有数据 */
struct test_dev_data {
struct regmap *regmap; /* syscon提供的regmap */
u32 ctrl_reg; /* 控制寄存器偏移 */
u32 data_reg; /* 数据寄存器偏移 */
};
/* 寄存器测试函数 */
static void test_reg_operations(struct test_dev_data *data)
{
u32 val;
/* 复位操作 */
regmap_write(data->regmap, data->ctrl_reg, CTRL_RST);
// msleep(10);
/* 使能设备 */
regmap_write(data->regmap, data->ctrl_reg, CTRL_EN);
regmap_read(data->regmap, data->ctrl_reg, &val);
pr_info("控制寄存器值: 0x%x (预期: 0x%x)\n", val, CTRL_EN);
/* 数据读写测试 */
regmap_write(data->regmap, data->data_reg, 0x55AA55AA);
regmap_read(data->regmap, data->data_reg, &val);
pr_info("数据寄存器值: 0x%x (预期: 0x55AA55AA)\n", val);
}
static int syscon_test_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct test_dev_data *data;
int ret;
pr_info("syscon_test_probe\n");
/* 分配私有数据 */
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
/* 获取syscon的regmap(核心操作) */
data->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
if (IS_ERR(data->regmap)) {
ret = PTR_ERR(data->regmap);
dev_err(dev, "获取syscon regmap失败: %d\n", ret);
return ret;
}
/* 从设备树读取寄存器偏移 */
ret = of_property_read_u32(dev->of_node, "ctrl-reg", &data->ctrl_reg);
if (ret) {
dev_err(dev, "缺少ctrl-reg属性\n");
return ret;
}
ret = of_property_read_u32(dev->of_node, "data-reg", &data->data_reg);
if (ret) {
dev_err(dev, "缺少data-reg属性\n");
return ret;
}
/* 执行寄存器测试 */
test_reg_operations(data);
platform_set_drvdata(pdev, data);
dev_info(dev, "syscon测试驱动加载成功\n");
return 0;
}
static int syscon_test_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "syscon测试驱动卸载\n");
return 0;
}
/* 设备树匹配表 */
static const struct of_device_id syscon_test_of_match[] = {
{ .compatible = "demo,syscon-test" },
{ /* 哨兵 */ }
};
MODULE_DEVICE_TABLE(of, syscon_test_of_match);
static struct platform_driver syscon_test_driver = {
.probe = syscon_test_probe,
.remove = syscon_test_remove,
.driver = {
.name = "syscon-test-driver",
.of_match_table = syscon_test_of_match,
},
};
module_platform_driver(syscon_test_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("简化的syscon测试驱动");
设备驱动代码2:
/*
* @Author: your name
* @Date: 2025-09-12 18:30:03
* @LastEditTime: 2025-09-12 18:56:22
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \linux-4.4.159\drivers\gpu\drm\test\memsyscon copy.c
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/of.h>
/* 寄存器位定义 */
#define CTRL_EN BIT(0)
#define CTRL_RST BIT(1)
/* 驱动私有数据 */
struct test_dev_data {
struct regmap *regmap; /* syscon提供的regmap */
u32 ctrl_reg; /* 控制寄存器偏移 */
u32 data_reg; /* 数据寄存器偏移 */
};
/* 寄存器测试函数 */
static void test_reg_operations(struct test_dev_data *data)
{
u32 val;
/* 复位操作 */
regmap_write(data->regmap, data->ctrl_reg, CTRL_RST);
// msleep(10);
/* 使能设备 */
regmap_write(data->regmap, data->ctrl_reg, CTRL_EN);
regmap_read(data->regmap, data->ctrl_reg, &val);
pr_info("控制寄存器值: 0x%x (预期: 0x%x)\n", val, CTRL_EN);
/* 数据读写测试 */
regmap_write(data->regmap, data->data_reg, 0x55AA55AA);
regmap_read(data->regmap, data->data_reg, &val);
pr_info("数据寄存器值: 0x%x (预期: 0x55AA55AA)\n", val);
}
static int syscon_test_probe1(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct test_dev_data *data;
int ret;
pr_info("syscon_test_probe1\n");
/* 分配私有数据 */
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
/* 获取syscon的regmap(核心操作) */
data->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
if (IS_ERR(data->regmap)) {
ret = PTR_ERR(data->regmap);
dev_err(dev, "获取syscon regmap失败: %d\n", ret);
return ret;
}
/* 从设备树读取寄存器偏移 */
ret = of_property_read_u32(dev->of_node, "ctrl-reg", &data->ctrl_reg);
if (ret) {
dev_err(dev, "缺少ctrl-reg属性\n");
return ret;
}
ret = of_property_read_u32(dev->of_node, "data-reg", &data->data_reg);
if (ret) {
dev_err(dev, "缺少data-reg属性\n");
return ret;
}
/* 执行寄存器测试 */
test_reg_operations(data);
platform_set_drvdata(pdev, data);
dev_info(dev, "syscon测试驱动加载成功\n");
return 0;
}
static int syscon_test_remove1(struct platform_device *pdev)
{
dev_info(&pdev->dev, "syscon测试驱动卸载\n");
return 0;
}
/* 设备树匹配表 */
static const struct of_device_id syscon_test_of_match[] = {
{ .compatible = "demo,syscon-test1" },
{ /* 哨兵 */ }
};
MODULE_DEVICE_TABLE(of, syscon_test_of_match);
static struct platform_driver syscon_test_driver1 = {
.probe = syscon_test_probe1,
.remove = syscon_test_remove1,
.driver = {
.name = "syscon-test-driver1",
.of_match_table = syscon_test_of_match,
},
};
module_platform_driver(syscon_test_driver1);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("简化的syscon测试驱动");
日志如下:
/ko # insmod memsyscon.ko
syscon_test_probe
控制寄存器值: 0x1 (预期: 0x1)
数据寄存器值: 0x55aa55aa (预期: 0x55AA55AA)
syscon-test-driver test-device@0: syscon测试驱动加载成功
/ko # insmod memsyscon1.ko
syscon_test_probe1
控制寄存器值: 0x1 (预期: 0x1)
数据寄存器值: 0x55aa55aa (预期: 0x55AA55AA)
syscon-test-driver1 test-device@1: syscon测试驱动加载成功
/ko # devmem 0x70000000 32
0x00000001
/ko # devmem 0x70000004 32
0x55AA55AA图片
结论
输出结论待查资料问题
- 问题 1:?
- 问题 2:?
参考链接
- 官方文档