rt-thread/bsp/phytium/libraries/standalone/drivers/scmi/fscmi_mhu/fscmi.c

348 lines
9.4 KiB
C

/*
* Copyright : (C) 2022 Phytium Information Technology, Inc.
* All Rights Reserved.
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
* either version 1.0 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Phytium Public License for more details.
*
*
* FilePath: fscmi.c
* Date: 2022-12-30 18:32:28
* LastEditTime: 2022-12-30 18:32:28
* Description: This file is for scmi protocol support
*
* Modify History:
* Ver Who Date Changes
* ----- ------ -------- --------------------------------------
* 1.0 liushengming 2023/01/30 init
*/
#include <string.h>
#include "fscmi.h"
#include "fmhu_hw.h"
#include "fio.h"
#include "fkernel.h"
#include "fdebug.h"
#include "fsleep.h"
#include "fassert.h"
#include "fscmi_base.h"
#include "fscmi_sensors.h"
#include "fscmi_perf.h"
#define FSCMI_DEBUG_TAG "FSCMI"
#define FSCMI_ERROR(format, ...) FT_DEBUG_PRINT_E(FSCMI_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSCMI_WARN(format, ...) FT_DEBUG_PRINT_W(FSCMI_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSCMI_INFO(format, ...) FT_DEBUG_PRINT_I(FSCMI_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSCMI_DEBUG(format, ...) FT_DEBUG_PRINT_D(FSCMI_DEBUG_TAG, format, ##__VA_ARGS__)
#define MSG_ID_MASK GENMASK(7, 0)
#define MSG_TYPE_MASK GENMASK(9, 8)
#define MSG_PROTOCOL_ID_MASK GENMASK(17, 10)
#define MSG_TOKEN_ID_MASK GENMASK(27, 18)
FError FScmiDoTransport(FScmi *instance_p,struct FScmiTransferInfo *info, u32 protocol_index)
{
FError ret;
u32 tx_done = 0;
u32 chan_status = 0;
u32 delay_out = 0;
FMhuConfig *mhu_config = &instance_p->scmi_mhu.mhu.config;
/* write data to share buffer */
ret = FScmiProtocolTxPrepare(instance_p,protocol_index);
if(ret != FT_SUCCESS)
{
FSCMI_ERROR("%s,FScmiProtocolTxPrepare is error", __FUNCTION__);
return ret;
}
if(instance_p->scmi_mhu.send_data)
{
instance_p->scmi_mhu.send_data(mhu_config->base_addr,mhu_config->mhu_chan_id);
}
chan_status = FMhuGetChanStatus(mhu_config->base_addr);
/* 等待发送完成 */
while (tx_done == 0)
{
tx_done = instance_p->scmi_mhu.last_tx_done(mhu_config->base_addr);
if (tx_done == 1)
{
break;
}
else
{
fsleep_millisec(10);
delay_out++;
if (delay_out == 10)
{
FSCMI_ERROR("Send error,addr:0x%x,last_tx_done:0x%x",mhu_config->base_addr,tx_done);
return FSCMI_ERROR_WAIT_MBOX_TIMEOUT;
}
}
}
/* 等待数据接收完成 */
/* poll way */
if(info->poll_completion)
{
while(FScmiProtocolPollDone(instance_p,protocol_index) != TRUE);
/* get data */
ret = FScmiFetchResponse(instance_p,protocol_index);
if(ret != FT_SUCCESS)
{
return FSCMI_ERROR_FETCH_RESPONSE;
}
}
else
{
/* interrupt way */
}
return FT_SUCCESS;
}
/**
* @name:
* @msg:
* @return {*}
* @param {u8} pro_id
* @param {u32} *protocol_index
*/
static FError FScmiProtocolMapping(const u8 pro_id,u32 *protocol_index)
{
switch (pro_id)
{
case SCMI_PROTOCOL_BASE:
{
*protocol_index = BASE_PROTOCOL_INDEX;
return FT_SUCCESS;
}
case SCMI_PROTOCOL_PERF:
{
*protocol_index = PERF_DOMAIN_INDEX;
return FT_SUCCESS;
}
case SCMI_PROTOCOL_SENSOR:
{
*protocol_index = SENSOR_MANAGEMENT_INDEX;
return FT_SUCCESS;
}
default:
return FSCMI_ERROR_NOT_FOUND;
}
return FT_SUCCESS;
}
struct FScmiTransferInfo *FScmiGetInfo(FScmi *instance_p, u8 pro_id)
{
u32 index_id = 0;
FError ret;
ret = FScmiProtocolMapping(pro_id, &index_id);
if (ret != FT_SUCCESS)
{
FSCMI_ERROR("%s,Protocol mapping error", __FUNCTION__);
return NULL;
}
return &instance_p->info[index_id];
}
FError FScmiFetchResponse(FScmi *instance_p, u8 pro_id)
{
struct FScmiSharedMem *mem =(struct FScmiSharedMem *) instance_p->config.share_mem;
struct FScmiTransferInfo *trans_info;
u32 index_id = 0;
FError ret;
ret = FScmiProtocolMapping(pro_id, &index_id);
if (ret != FT_SUCCESS)
{
FSCMI_ERROR("%s,Protocol mapping error", __FUNCTION__);
return ret;
}
trans_info = &instance_p->info[index_id];
trans_info->hdr.status = FtIn32((uintptr)mem->msg_payload);
/* Skip the length of header and statues in payload area i.e 8 bytes*/
trans_info->rx.len = min(trans_info->rx.len, FtIn32((uintptr)(&mem->length)) - 8);
/* Take a copy to the rx buffer.. */
if(trans_info->rx.len)
{
for (u32 i = 0; i < trans_info->rx.len; i++)
{
trans_info->rx.buf[i] = mem->msg_payload[i+4];
}
}
return FT_SUCCESS;
}
FError FScmiProtocolPollDone(FScmi *instance_p,u8 pro_id)
{
struct FScmiSharedMem *mem =(struct FScmiSharedMem *) instance_p->config.share_mem;
u32 index_id = 0;
FError ret;
ret = FScmiProtocolMapping(pro_id, &index_id);
if(ret != FT_SUCCESS)
{
FSCMI_ERROR("%s,Protocol mapping error",__FUNCTION__);
return FALSE;
}
return FtIn32((uintptr)(&mem->channel_status)) &
(SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR |
SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
}
static u32 FScmiPackHeader(struct FScmiMsgHdr *hdr_p)
{
return FIELD_PREP(MSG_ID_MASK, hdr_p->id) |
FIELD_PREP(MSG_TOKEN_ID_MASK, hdr_p->seq) |
FIELD_PREP(MSG_PROTOCOL_ID_MASK, hdr_p->protocol_id);
}
FError FScmiProtocolTxPrepare(FScmi *instance_p,u8 pro_id)
{
struct FScmiSharedMem *mem =(struct FScmiSharedMem *) instance_p->config.share_mem;
struct FScmiTransferInfo *trans_info;
u32 index_id = 0;
u32 time_out;
FError ret;
static int is_init = 0;
ret = FScmiProtocolMapping(pro_id, &index_id);
if(ret != FT_SUCCESS)
{
FSCMI_ERROR("Protocol mapping error");
return ret;
}
trans_info = &instance_p->info[index_id];
if(!is_init)
{
FtOut32((uintptr)&mem->channel_status,SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
is_init = 1;
}
while (0 == (FtIn32((uintptr)&mem->channel_status) &SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE))
{
time_out++;
fsleep_millisec(10);
if (time_out == 10)
{
FSCMI_ERROR("Memory of scmi status error,please check mhu channel set or memory addrs...");
return FSCMI_ERROR_WAIT_MEM_TIMEOUT;
}
}
FtOut32((uintptr)&mem->channel_status,0);
FtOut32((uintptr)&mem->flags, 0);
FtOut32((uintptr)&mem->length, sizeof(mem->msg_header) + trans_info->tx.len);
FtOut32((uintptr)&mem->msg_header,FScmiPackHeader(&trans_info->hdr));
if(trans_info->tx.len)
{
for (u32 i = 0; i < trans_info->tx.len; i++)
{
mem->msg_payload[i] = trans_info->tx.buf[i];
}
}
return FT_SUCCESS;
}
FError FScmiMessageInit(FScmi *instance_p,u8 msg_id,u8 pro_id,u32 tx_size,u32 rx_size,u8 *tx_buffer)
{
u32 index_id = 0;
FError ret;
struct FScmiTransferInfo *trans_info;
ret = FScmiProtocolMapping(pro_id, &index_id);
if(ret != FT_SUCCESS)
{
FSCMI_ERROR("Protocol mapping error");
return ret;
}
trans_info = &instance_p->info[index_id];
/* 检查 tx_size / rx_size 的长度*/
if(tx_size > FSCMI_MSG_SIZE || rx_size > FSCMI_MSG_SIZE)
{
return FSCMI_ERROR_RANGE;
}
if(tx_size > 0 && tx_buffer == NULL)
{
return FSCMI_ERROR_NULL_POINTER;
}
/* init hdr */
trans_info->hdr.seq = pro_id + msg_id ;
trans_info->hdr.id = msg_id;
trans_info->hdr.protocol_id = pro_id;
/* init buffer */
trans_info->tx.len = tx_size;
if(tx_size && tx_buffer)
{
memcpy(trans_info->tx.buf, tx_buffer, tx_size);
}
trans_info->rx.len = rx_size ? :FSCMI_MSG_SIZE;/* */
trans_info->poll_completion = TRUE;
return FT_SUCCESS;
}
FError FScmiCfgInitialize(FScmi *instance_p, const struct FScmiConfig *config)
{
/* first init */
instance_p->config = *config;
FError ret;
/* Second choice is the mbox driver */
if (instance_p->config.mbox_type == FSCMI_MBOX_MHU_TYPE)
{
FMhuChanProbe(&instance_p->scmi_mhu);
}
else
{
return FSCMI_ERROR_TYPE;
}
instance_p->config.share_mem = config->share_mem;
/* The third initializes the base protocol */
ret = FScmiBaseInit(instance_p);
if (instance_p->revision.version != FSCMI_VERSION)
{
return FSCMI_ERROR_VERSION;
}
ret = FScmiSensorInit(instance_p);
if(ret != FT_SUCCESS)
{
FSCMI_ERROR("FScmiSensorInit init error.Error code:0x%x.",ret);
return FSCMI_ERROR_INIT;
}
ret = FScmiPerfInit(instance_p);
if(ret != FT_SUCCESS)
{
FSCMI_ERROR("FScmiPerfInit init error.Error code:0x%x.",ret);
return FSCMI_ERROR_INIT;
}
/* Finally confirm the completion status */
instance_p->is_ready = FT_COMPONENT_IS_READY;
return FT_SUCCESS;
}