linux 中怎么使用scp呢?
首先在arm_scpi.c中export了 get_scpi_ops 这样其他驱动可以调用get_scpi_ops来使用spci
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,
};
struct scpi_ops *get_scpi_ops(void)
{
return scpi_info ? scpi_info->scpi_ops : NULL;
}
例如clk_get_val的使用如下:
drivers/clk/clk-scpi.c return clk->scpi_ops->clk_get_val(clk->id)
在scpi_clk_get_val 中直接调用scpi_send_message 发送命令
static unsigned long scpi_clk_get_val(u16 clk_id)
{
int ret;
__le32 rate;
__le16 le_clk_id = cpu_to_le16(clk_id);
ret = scpi_send_message(CMD_GET_CLOCK_VALUE, &le_clk_id,
sizeof(le_clk_id), &rate, sizeof(rate));
return ret ? ret : le32_to_cpu(rate);
}
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;
msg->tx_buf = tx_buf;
msg->tx_len = tx_len;
msg->rx_buf = rx_buf;
msg->rx_len = rx_len;
reinit_completion(&msg->done);
#调用mbox 发送命令
ret = mbox_send_message(scpi_chan->chan, msg);
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;
return ret > 0 ? scpi_to_linux_errno(ret) : ret;
}
那什么地方释放完成量呢?
答案是在scpi_probe 中有为mbox_client 注册一个scpi_handle_remote_msg;
cl->dev = dev;
cl->rx_callback = scpi_handle_remote_msg;
cl->tx_prepare = scpi_tx_prepare;
cl->tx_block = true;
cl->tx_tout = 20;
cl->knows_txdone = false; /* controller can't ack */
完成量就是在scpi_handle_remote_msg->scpi_process_cmd中释放的
static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
{
/* check if wait_for_completion is in progress or timed-out */
if (match && !completion_done(&match->done)) {
unsigned int len;
if (scpi_info->is_legacy) {
struct legacy_scpi_shared_mem __iomem *mem =
ch->rx_payload;
/* RX Length is not replied by the legacy Firmware */
len = match->rx_len;
match->status = ioread32(&mem->status);
memcpy_fromio(match->rx_buf, mem->payload, len);
} else {
struct scpi_shared_mem __iomem *mem = ch->rx_payload;
len = min_t(unsigned int, match->rx_len, CMD_SIZE(cmd));
match->status = ioread32(&mem->status);
memcpy_fromio(match->rx_buf, mem->payload, len);
}
if (match->rx_len > len)
memset(match->rx_buf + len, 0, match->rx_len - len);
#释放完成量
complete(&match->done);
}
spin_unlock_irqrestore(&ch->rx_lock, flags);
}