获取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:

linux ARM64 平台获取cpu温度_Hardware

调用scpi_ops的sensor_get_info接口:

linux ARM64 平台获取cpu温度_Hardware_02


通过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