获取cpu温度,频率等,信息,用户通过sysfs接口,会调用到scpi提供的接口drivers/firmware/arm_scpi.c : scpi_ops支持的功能。scpi需要提供对应的ops操作集合:
static struct scpi_ops scpi_ops = {
.get_version = scpi_get_version,
.clk_get_range = scpi_clk_get_range,
.clk_get_val = scpi_clk_get_val,
.clk_set_val = scpi_clk_set_val,
.dvfs_get_idx = scpi_dvfs_get_idx,
.dvfs_set_idx = scpi_dvfs_set_idx,
.dvfs_get_info = scpi_dvfs_get_info,
.device_domain_id = scpi_dev_domain_id,
.get_transition_latency = scpi_dvfs_get_transition_latency,
.add_opps_to_device = scpi_dvfs_add_opps_to_device,
.sensor_get_capability = scpi_sensor_get_capability,
.sensor_get_info = scpi_sensor_get_info,
.sensor_get_value = scpi_sensor_get_value,
.device_get_power_state = scpi_device_get_power_state,
.device_set_power_state = scpi_device_set_power_state,
};
比如通过scpi通过 cpu温度scpi_sensor_get_value的时候将调用scpi_send_message函数:
static int scpi_sensor_get_value(u16 sensor, u64 *val)
{
__le16 id = cpu_to_le16(sensor);
__le64 value;
int ret;
ret = scpi_send_message(CMD_SENSOR_VALUE, &id, sizeof(id),
&value, sizeof(value));
if (ret)
return ret;
if (scpi_info->is_legacy)
/* only 32-bits supported, upper 32 bits can be junk */
*val = le32_to_cpup((__le32 *)&value);
else
*val = le64_to_cpu(value);
return 0;
}
其中调用了scpi_send_message函数:
//idx 是scpi的标准cmd,参考
/* SCPI Standard commands */
enum scpi_std_cmd;
static int scpi_send_message(u8 idx, void *tx_buf, unsigned int tx_len,
void *rx_buf, unsigned int rx_len)
{
int ret;
u8 chan;
u8 cmd;
struct scpi_xfer *msg;
struct scpi_chan *scpi_chan;
if (scpi_info->commands[idx] < 0)
return -EOPNOTSUPP;
cmd = scpi_info->commands[idx]; //参考scpi_probe函数:scpi_info->commands = scpi_std_commands;
if (scpi_info->is_legacy)
chan = test_bit(cmd, scpi_info->cmd_priority) ? 1 : 0;
else
chan = atomic_inc_return(&scpi_info->next_chan) %
scpi_info->num_chans;
scpi_chan = scpi_info->channels + chan;
msg = get_scpi_xfer(scpi_chan);
if (!msg)
return -ENOMEM;
if (scpi_info->is_legacy) {
msg->cmd = PACK_LEGACY_SCPI_CMD(cmd, tx_len);
msg->slot = msg->cmd;
} else {
msg->slot = BIT(SCPI_SLOT);
msg->cmd = PACK_SCPI_CMD(cmd, tx_len);
}
msg->tx_buf = tx_buf;
msg->tx_len = tx_len;
msg->rx_buf = rx_buf;
msg->rx_len = rx_len;
reinit_completion(&msg->done);
ret = mbox_send_message(scpi_chan->chan, msg); //调用mailbox
if (ret < 0 || !rx_buf)
goto out;
if (!wait_for_completion_timeout(&msg->done, MAX_RX_TIMEOUT))
ret = -ETIMEDOUT;
else
/* first status word */
ret = msg->status;
out:
if (ret < 0 && rx_buf) /* remove entry from the list if timed-out */
scpi_process_cmd(scpi_chan, msg->cmd);
put_scpi_xfer(msg, scpi_chan);
/* SCPI error codes > 0, translate them to Linux scale*/
return ret > 0 ? scpi_to_linux_errno(ret) : ret;
}
最后通过mailbox的 mbox_send_message接口。
温度传感器的驱动:其获取scpi_ops:
调用scpi_ops的sensor_get_info接口:
通过mailbox的控制器发送数据:
cat /sys/class/hwmon/hwmon0/temp1_input 读取温度
FT的mailbox驱动。提供了scpi(System Control and Power Interface (SCPI) Message Protocol) 的数据发送和接受的功能。提供mailbox controller。注册为mbox-chan 。
cpi_sensors-isa-0000
Adapter: I[ 79.349342] ===phytium_mbox_send_data
SA adapter
[ 79.355582] CPU: 0 PID: 957 Comm: sensors Tainted: G E 4.19.0l+ #59
[ 79.364172] Hardware name: D2000 Development Board (DT)
[ 79.369390] Call trace:
[ 79.371840] dump_backtrace+0x0/0x1c0
[ 79.375501] show_stack+0x24/0x30
[ 79.378815] dump_stack+0x9c/0xbc
[ 79.382134] phytium_mbox_send_data+0x30/0x50 [phytium_mailbox]
[ 79.388051] msg_submit+0xc4/0x150
[ 79.391449] mbox_send_message+0xa0/0x148
[ 79.395456] scpi_send_message+0x130/0x2b0 drivers/firmware/arm_scpi.c
[ 79.399549] scpi_sensor_get_value+0x50/0xa0
[ 79.403817] scpi_show_sensor+0x50/0xc0 drivers/hwmon/scpi-hwmon.c
[ 79.407651] dev_attr_show+0x3c/0x78
[ 79.411227] sysfs_kf_seq_show+0xb4/0x130
[ 79.415234] kernfs_seq_show+0x44/0x50
[ 79.418982] seq_read+0x138/0x450
[ 79.422294] kernfs_fop_read+0x54/0x1e8
[ 79.426130] __vfs_read+0x60/0x180
[ 79.429528] vfs_read+0x98/0x150
[ 79.432754] ksys_read+0x6c/0xd0
[ 79.435980] __arm64_sys_read+0x24/0x30
[ 79.439814] el0_svc_handler+0xac/0xf8
[ 79.443559] el0_svc+0x8/0xc
: +42.3°C
[ 79.448688] ===phytium_mbox_send_data
[ 79.454516] CPU: 0 PID: 957 Comm: sensors Tainted: G E 4.19.0l+ #59
[ 79.462080] Hardware name: D2000 Development Board (DT)
[ 79.467298] Call trace:
[ 79.469742] dump_backtrace+0x0/0x1c0
[ 79.473401] show_stack+0x24/0x30
[ 79.476714] dump_stack+0x9c/0xbc
[ 79.480029] phytium_mbox_send_data+0x30/0x50 [phytium_mailbox]
[ 79.485945] msg_submit+0xc4/0x150
[ 79.489343] mbox_send_message+0xa0/0x148
[ 79.493349] scpi_send_message+0x130/0x2b0
[ 79.497442] scpi_sensor_get_value+0x50/0xa0
[ 79.501708] scpi_show_sensor+0x50/0xc0
[ 79.505541] dev_attr_show+0x3c/0x78
[ 79.509114] sysfs_kf_seq_show+0xb4/0x130
[ 79.513121] kernfs_seq_show+0x44/0x50
[ 79.516867] seq_read+0x138/0x450
[ 79.520180] kernfs_fop_read+0x54/0x1e8
[ 79.524013] __vfs_read+0x60/0x180
[ 79.527412] vfs_read+0x98/0x150
[ 79.530637] ksys_read+0x6c/0xd0
[ 79.533863] __arm64_sys_read+0x24/0x30
[ 79.537696] el0_svc_handler+0xac/0xf8
[ 79.541441] el0_svc+0x8/0xc
cpu频率驱动scpi-cpufreq和clk-scpi原理:
(1) drivers/clk/clk-scpi.c //platform_driver:scpi_clocks <-------> match:PHYT8001 匹配成功probe
(2)->platform_device_register_simple //platform_device: scpi-cpufreq 创建scpi-cpufreq设备
(3)drivers/cpufreq/scpi-cpufreq.c //platform_driver:scpi-cpufreq
(4)modprobe scpi-cpufreq
可以在cpu下面看到的cpufreq目录
[root@localhost cpufreq]# ls /sys/devices/system/cpu/cpu1/cpufreq
affected_cpus cpuinfo_max_freq cpuinfo_transition_latency scaling_available_frequencies scaling_cur_freq scaling_governor scaling_min_freq stats
cpuinfo_cur_freq cpuinfo_min_freq related_cpus scaling_available_governors scaling_driver scaling_max_freq scaling_setspeed
设置频率
[root@localhost cpufreq]# cat cpuinfo_cur_freq
575000
[root@localhost cpufreq]# cat scaling_governor
schedutil
[root@localhost cpufreq]# cat scaling_available_governors
ondemand userspace performance schedutil
[root@localhost cpufreq]# echo performance > scaling_governor
[root@localhost cpufreq]# cat scaling_cur_freq
2300000
设置cpu频率:节能模式
[ 1179.800575] ===scpi_send_message idx
[ 1179.800585] CPU: 5 PID: 1050 Comm: dde-system-daem Not tainted 4.19.0 #28
[ 1179.800591] Hardware name: Lenovo Lenovo KaiTian A740J Desktop/HANGZHOU, BIOS WA2KT16A 08/26/22 15:22:11
[ 1179.800594] Call trace:
[ 1179.800603] dump_backtrace+0x0/0x188
[ 1179.800608] show_stack+0x24/0x30
[ 1179.800616] dump_stack+0x9c/0xbc
[ 1179.800625] scpi_send_message+0x84/0x258
[ 1179.800633] scpi_dvfs_get_idx+0x2c/0x40
[ 1179.800640] scpi_dvfs_recalc_rate+0x28/0x58
[ 1179.800647] clk_recalc+0x50/0x78
[ 1179.800655] clk_change_rate+0xf8/0x410
[ 1179.800662] clk_core_set_rate_nolock+0x1b8/0x1d8
[ 1179.800670] clk_set_rate+0x38/0xb8
[ 1179.800676] scpi_cpufreq_set_target+0x50/0xb0
[ 1179.800685] __cpufreq_driver_target+0x28c/0x640
[ 1179.800695] cpufreq_gov_powersave_limits+0x2c/0x6c [cpufreq_powersave] //节能gov
[ 1179.800708] cpufreq_start_governor+0x74/0xc8
[ 1179.800716] cpufreq_set_policy+0x27c/0x328
[ 1179.800724] store_scaling_governor+0x78/0xb8
[ 1179.800731] store+0xa4/0xc0
[ 1179.800740] sysfs_kf_write+0x5c/0x70
[ 1179.800748] kernfs_fop_write+0xd8/0x1d0
[ 1179.800754] __vfs_write+0x48/0x160
[ 1179.800761] vfs_write+0xac/0x1b0
[ 1179.800767] ksys_write+0x54/0xb0
[ 1179.800774] __arm64_sys_write+0x24/0x30
[ 1179.800782] el0_svc_common+0x94/0xe8
[ 1179.800789] el0_svc_handler+0x38/0x80
[ 1179.800795] el0_svc+0x8/0xc