MTK 平台sensor arch 介绍-scp
阅读原文时间:2022年06月02日阅读:1

架构介绍

路径:vendor/mediatek/proprietary/tinysys/scp


1.[build]编译相关
2.[driver]scp 的driver,I2C,power,eint
3.[middleware]Audio VOW,contexhub 相关 lib 和driver
4.[project]不同项目的配置文件,例如编译,eint num 等

运行环境

在scp,MTK 的sensorhub 是在Google 的CHRE 下开发的,所有的sensor driver 的实现可以称为一个 CHRE app CHRE APP 的框架如下图:

每一份在CHRE 下的sensor driver 的实现,必须要有如上几个模块:sensorinfo,sensorops,以及处理event的handler

common层

scp 支持的sensor,被分为了一下几类
1.accgyro
2.alps
3.barometer
4.Magneteometer
5.sar
不同的vendor driver 根据如上划分,将driver 的实现放置到对应的path下,每一个sensor 的control 和 Data flow 必须经过此common层,统一处理,示
意图如下:

通过这样的方式,规定好不同vendor driver 的具体实现接口,driver 在对应方法上,只在意处理逻辑和寄存器操作即可

实现流程

从AP 侧kernel 下发enable_cmd 的地方看起:

路径:
kernel-4.14/drivers/misc/mediatek/sensor/2.0/mtk_nanohub/


int mtk_nanohub_enable_to_hub(uint8_t sensor_id, int enabledisable)
{
    uint8_t sensor_type = id_to_type(sensor_id);
    struct ConfigCmd cmd;
    int ret = 0;
    ...
    sensor_state[sensor_type].enable = enabledisable;
    init_sensor_config_cmd(&cmd, sensor_type); //cmd
    if (atomic_read(&power_status) == SENSOR_POWER_UP) {
        ret = nanohub_external_write((const uint8_t *)&cmd,
            sizeof(struct ConfigCmd)); //cmd hostintf
        if (ret < 0)
            pr_err("fail enable: [%d,%d]\n", sensor_id, cmd.cmd);
}
    ...
    return ret < 0 ? ret : 0;
}

填充cmd:

static void init_sensor_config_cmd(struct ConfigCmd *cmd,
                int sensor_type)
{
        uint8_t alt = sensor_state[sensor_type].alt;
        bool enable = 0;
        memset(cmd, 0x00, sizeof(*cmd));
        cmd->evtType = EVT_NO_SENSOR_CONFIG_EVENT; //evtype
        cmd->sensorType = sensor_state[sensor_type].sensorType;//sensor type
        if (alt && sensor_state[alt].enable &&
                    sensor_state[sensor_type].enable) {
                cmd->cmd = CONFIG_CMD_ENABLE; //cmd
                if (sensor_state[alt].rate > sensor_state[sensor_type].rate)
                        cmd->rate = sensor_state[alt].rate; //
                else
                        cmd->rate = sensor_state[sensor_type].rate;
                if (sensor_state[alt].latency <
                            sensor_state[sensor_type].latency)
                    cmd->latency = sensor_state[alt].latency;
                else
                        cmd->latency = sensor_state[sensor_type].latency;
    }
}

以上是AP侧的最后一步,接下来cmd 会在hostintf 接收到,再解析:

路径:
vendor/mediatek/proprietary/hardware/contexthub/firmware/src/hostIntf.c

hostintf 也是是CHRE APP:

INTERNAL_APP_INIT(APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 0), 0, hostIntfRequest, hostIntfRelease, hostIntfHandleEvent);

再其处理event 的函数:hostintfhandleevent 内

static void hostIntfHandleEvent(uint32_t evtType, const void* evtData)
{
        struct ConfigCmd *cmd;
        uint32_t i, cnt;
        uint64_t rtcTime;
        struct ActiveSensor *sensor;
        uint32_t tempSensorHandle;
        const struct HostHubRawPacket *hostMsg;
        struct HostIntfDataBuffer *data;
        const struct NanohubHalCommand *halCmd;
        const uint8_t *halMsg;
        uint32_t reason;
        //uint32_t interrupt = HOSTINTF_MAX_INTERRUPTS;
        if (evtType == EVT_APP_START) {
            ...
        } else if (evtType == EVT_APP_TO_HOST) {
            ...
        } else if (evtType == EVT_APP_FROM_HOST) {
            ...
        }else if (evtType == EVT_LATENCY_TIMER) {
            ...
        }else if (evtType == EVT_NO_SENSOR_CONFIG_EVENT) { // config
            cmd = (struct ConfigCmd *)evtData;
    #ifdef CFG_CONTEXTHUB_FW_SUPPORT
            if (cmd->cmd == CONFIG_CMD_ENABLE)
                registerDownSampleInfo(cmd->sensType, cmd->rate);
            // mtk add for remapping sensorType to chreType
            cmd->sensType = mtkTypeToChreType(cmd->sensType); //MTK sensor type CHRE type
    #endif
            osLog(LOG_INFO, "hostintf: %lld, chreType:%u, rate:%" PRIu32 ", latency:%lld, cmd:%d!\n",
rtcGetTime(), cmd->sensType, cmd->rate, cmd->latency, cmd->cmd)
            if (cmd->cmd == CONFIG_CMD_FLUSH) {
sensorFlush(sensor->sensorHandle);
    }
}

hostinf 会调用对应APP 的sensorops:
比如Accgyro.c

static const struct SensorOps mSensorOps[MAX_HANDLE] = {
    { DEC_OPS_ALL(sensorPowerAcc, sensorFirmwareAcc, sensorRateAcc, sensorFlushAcc, sensorCaliAcc, sensorCfgAcc,
sensorSelfTestAcc) },
    { DEC_OPS_ALL(sensorPowerGyro, sensorFirmwareGyro, sensorRateGyro, sensorFlushGyro, sensorCaliGyro,
sensorCfgGyro, sensorSelfTestGyro) },
    { DEC_OPS(anyMotionPower, anyMotionFirmwareUpload, anyMotionSetRate, anyMotionFlush) },
    { DEC_OPS(noMotionPower, noMotionFirmwareUpload, noMotionSetRate, noMotionFlush) },
};

如上的宏都是再填充SensorOps的具体方法:
以Acc的power_on 为例子

至此 kernel 到common 层的control flow 就结束了,接下来就是vendor 根据平台实现自己的逻辑。
目前common 和driver 的实现,分为两种,第一种就是FSM 状态机,另一种是MTK arch 2 新的架构,广播机制

FSM:

MSE:


以alps 为例子梳理下enable 流程:
与acc 一样,hostintf 通过调用APP 提供的sensorops:

对alps common 层下发sensorpower

通过函数sensor_broadcast_event 发出event,挂载的als app会在处理event 的函数内处理 对应的event type
以bu27030 为例:
init 时候会注册自己接收event 的函数

Data Flow

以Acc 为例子:
Data flow 无论是中断还是polling 都是从common 层下第一个FSM


最后上报data 的函数是:

MSE:

以Als为例子:
Data flow 依靠driver init后注册的timer ,当power 后根据下发的rate 启动timer:

这个是和power_on 后下发的,用来设置rate,在driver 通过timer 实现
回到driver:



至此,acc 和 als 都调用函数: osEnqueueEvt 发送data 给上层:
以下上报流程不区分FSM/MSE ,完全一致,接着分析:
common层发从的data 从code 流程上全部到了contexthub_fw.c

路径:
vendor/mediatek/proprietary/tinysys/scp/middleware/contexthub/contexthub_fw.
c



需要注意的是这里面填充的struct data_unit_t 就是AP 侧kernel mtk_nonahub 处理的数据类型。所以contexhub_fw.c 这里填充的dummy 的log 也就是
平时debug AP 与SCP 界限的 分割点。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章