rt-thread/bsp/phytium/libraries/standalone/drivers/mmc/fsdmmc/fsdmmc_intr.c

331 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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: fsdmmc_intr.c
* Date: 2022-02-10 14:53:42
* LastEditTime: 2022-02-18 08:54:53
* Description:  This file contains the functions that are related to interrupt processing
* for the fsdmmc device.
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.0 zhugengyu 2021/12/2 init
*/
/***************************** Include Files *********************************/
#include "fassert.h"
#include "fio.h"
#include "fdebug.h"
#include "fsdmmc_hw.h"
#include "fsdmmc.h"
/************************** Constant Definitions *****************************/
#define FSDMMC_DEBUG_TAG "FSDMMC-INTR"
#define FSDMMC_ERROR(format, ...) FT_DEBUG_PRINT_E(FSDMMC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDMMC_WARN(format, ...) FT_DEBUG_PRINT_W(FSDMMC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDMMC_INFO(format, ...) FT_DEBUG_PRINT_I(FSDMMC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDMMC_DEBUG(format, ...) FT_DEBUG_PRINT_D(FSDMMC_DEBUG_TAG, format, ##__VA_ARGS__)
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
static void FSdmmcCallEvtHandler(FSdmmcEventHandler handler, void *arg)
{
if (NULL != handler)
{
handler(arg);
}
}
/************************** Function Prototypes ******************************/
extern u32 FSdmmcMakeRawCmd(FSdmmcCmd *cmd_p);
extern void FSdmmcSendCmd(uintptr base_addr, FSdmmcCmd *cmd_p);
extern FError FSdmmcSendData(uintptr base_addr, boolean read, FSdmmcCmd *cmd_p);
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/**
* @name: FSdmmcGetInterruptMask
* @msg: 获取FSDMMC的中断掩码
* @return {u32} 中断掩码
* @param {uintptr} base_addr FSDMMC控制器基地址
* @param {u32} intr_type FSDMMC中断类型, 参考FSDMMC_INTR_NUM
* @note FSDMMC控制器初始化后才能调用此函数
*/
u32 FSdmmcGetInterruptMask(uintptr base_addr, u32 intr_type)
{
u32 mask;
switch (intr_type)
{
case FSDMMC_CMD_INTR:
mask = FSDMMC_READ_REG(base_addr, FSDMMC_NORMAL_INT_EN_REG_OFFSET);
break;
case FSDMMC_ERROR_INTR:
mask = FSDMMC_READ_REG(base_addr, FSDMMC_ERROR_INT_EN_REG_OFFSET);
break;
case FSDMMC_DMA_BD_INTR:
mask = FSDMMC_READ_REG(base_addr, FSDMMC_BD_ISR_EN_REG_OFFSET);
break;
default:
FASSERT(0);
break;
}
return mask;
}
/**
* @name: FSdmmcSetInterruptMask
* @msg: 设置FSDMMC的中断掩码
* @param {uintptr} base_addr FSDMMC控制器基地址
* @param {u32} intr_type FSDMMC中断类型, 参考FSDMMC_INTR_NUM
* @param {u32} mask 中断掩码
* @param {boolean} enable TRUE:打开中断, FALSE:关闭中断
* @note FSDMMC控制器初始化后才能调用此函数
*/
void FSdmmcSetInterruptMask(uintptr base_addr, u32 intr_type, u32 mask, boolean enable)
{
u32 old_mask = FSdmmcGetInterruptMask(base_addr, intr_type);
u32 new_mask = 0;
if (TRUE == enable)
{
new_mask = old_mask | mask;
}
else
{
new_mask = old_mask & (~mask);
}
switch (intr_type)
{
case FSDMMC_CMD_INTR:
FSDMMC_WRITE_REG(base_addr, FSDMMC_NORMAL_INT_EN_REG_OFFSET, new_mask);
break;
case FSDMMC_ERROR_INTR:
FSDMMC_WRITE_REG(base_addr, FSDMMC_ERROR_INT_EN_REG_OFFSET, new_mask);
break;
case FSDMMC_DMA_BD_INTR:
FSDMMC_WRITE_REG(base_addr, FSDMMC_BD_ISR_EN_REG_OFFSET, new_mask);
break;
default:
FASSERT(0);
break;
}
return;
}
/**
* @name: FSdmmcCmdInterrupHandler
* @msg: 命令中断响应函数
* @return {*} 无
* @param {s32} vector 中断向量号
* @param {void} *param 中断响应输入参数
* @note 此函数用于设置FSDMMC中断时注册用户可以自定义一个中断响应函数替换此函数
*/
void FSdmmcCmdInterrupHandler(s32 vector, void *param)
{
FASSERT(param);
u32 status;
FSdmmc *instance_p = (FSdmmc *)param;
uintptr base_addr = instance_p->config.base_addr;
/* clear interrupts */
status = FSDMMC_READ_REG(base_addr, FSDMMC_NORMAL_INT_STATUS_REG_OFFSET);
if (status & FSDMMC_NORMAL_INT_STATUS_CR) /* 卡移除中断 */
{
FSdmmcCallEvtHandler(instance_p->evt_handler[FSDMMC_EVT_CARD_REMOVED],
instance_p->evt_args[FSDMMC_EVT_CARD_REMOVED]);
}
if (status & FSDMMC_NORMAL_INT_STATUS_CC) /* 命令完成中断 */
{
FSdmmcCallEvtHandler(instance_p->evt_handler[FSDMMC_EVT_CMD_DONE],
instance_p->evt_args[FSDMMC_EVT_CMD_DONE]);
}
if (status & FSDMMC_NORMAL_INT_STATUS_EI) /* 命令错误中断 */
{
FSdmmcCallEvtHandler(instance_p->evt_handler[FSDMMC_EVT_CMD_ERROR],
instance_p->evt_args[FSDMMC_EVT_CMD_ERROR]);
}
FSdmmcClearNormalInterruptStatus(base_addr);
}
/**
* @name: FSdmmcDmaInterrupHandler
* @msg: DMA中断响应函数
* @return {*}
* @param {s32} vector 中断向量号
* @param {void} *param 中断响应输入参数
* @note 此函数用于设置FSDMMC中断时注册用户可以自定义一个中断响应函数替换此函数
*/
void FSdmmcDmaInterrupHandler(s32 vector, void *param)
{
FASSERT(param);
u32 status;
FSdmmc *instance_p = (FSdmmc *)param;
uintptr base_addr = instance_p->config.base_addr;
/* clear interrupts */
status = FSDMMC_READ_REG(base_addr, FSDMMC_BD_ISR_REG_OFFSET);
if (status & FSDMMC_BD_ISR_REG_DAIS) /* DMA 错误中断 */
{
FSdmmcCallEvtHandler(instance_p->evt_handler[FSDMMC_EVT_DATA_ERROR],
instance_p->evt_args[FSDMMC_EVT_DATA_ERROR]);
}
if (status & FSDMMC_BD_ISR_REG_RESPE) /* 读 SD 卡操作AXI BR 通道完成中断 */
{
FSdmmcCallEvtHandler(instance_p->evt_handler[FSDMMC_EVT_DATA_READ_DONE],
instance_p->evt_args[FSDMMC_EVT_DATA_READ_DONE]);
}
if (status & FSDMMC_BD_ISR_REG_DATFRAX) /* AXI 总线强制释放中断*/
{
FSDMMC_ERROR("FSDMMC_BD_ISR_REG_DATFRAX");
}
if (status & FSDMMC_BD_ISR_REG_NRCRC) /* 无 CRC 响应中断*/
{
FSDMMC_ERROR("FSDMMC_BD_ISR_REG_NRCRC");
}
if (status & FSDMMC_BD_ISR_REG_TRE) /* CRC 响应错误中断*/
{
FSDMMC_ERROR("FSDMMC_BD_ISR_REG_TRE");
}
if (status & FSDMMC_BD_ISR_REG_CMDE) /* 命令响应错误中断*/
{
FSDMMC_ERROR("FSDMMC_BD_ISR_REG_CMDE");
}
if (status & FSDMMC_BD_ISR_REG_DTE) /* 超时中断*/
{
FSDMMC_ERROR("FSDMMC_BD_ISR_REG_DTE");
}
if (status & FSDMMC_BD_ISR_REG_TRS) /* DMA 传输完成中断*/
{
FSdmmcCallEvtHandler(instance_p->evt_handler[FSDMMC_EVT_DATA_WRITE_DONE],
instance_p->evt_args[FSDMMC_EVT_DATA_WRITE_DONE]);
}
FSdmmcClearBDInterruptStatus(base_addr);
}
/**
* @name: FSdmmcErrInterrupHandler
* @msg: 错误中断响应函数
* @return {*}
* @param {s32} vector 中断向量号
* @param {void} *param 中断响应输入参数
* @note 此函数用于设置FSDMMC中断时注册用户可以自定义一个中断响应函数替换此函数
*/
void FSdmmcErrInterrupHandler(s32 vector, void *param)
{
FASSERT(param);
u32 status;
FSdmmc *instance_p = (FSdmmc *)param;
uintptr base_addr = instance_p->config.base_addr;
status = FSDMMC_READ_REG(base_addr, FSDMMC_ERROR_INT_STATUS_REG_OFFSET);
if (status & FSDMMC_ERROR_INT_STATUS_CNR) /* 命令响应错误中断 */
{
FSdmmcCallEvtHandler(instance_p->evt_handler[FSDMMC_EVT_CMD_RESP_ERROR],
instance_p->evt_args[FSDMMC_EVT_CMD_RESP_ERROR]);
}
if (status & FSDMMC_ERROR_INT_STATUS_CIR) /* 命令索引错误中断 */
{
FSDMMC_ERROR("FSDMMC_ERROR_INT_STATUS_CIR");
}
if (status & FSDMMC_ERROR_INT_STATUS_CCRCE) /* 命令 CRC 错误中断 */
{
FSDMMC_ERROR("FSDMMC_ERROR_INT_STATUS_CCRCE");
}
if (status & FSDMMC_ERROR_INT_STATUS_CTE) /* 命令超时错误中断 */
{
FSDMMC_ERROR("FSDMMC_ERROR_INT_STATUS_CTE");
}
/* clear command error status */
FSdmmcClearErrorInterruptStatus(base_addr);
}
/**
* @name: FSdmmcRegisterInterruptHandler
* @msg: 注册中断事件响应函数
* @return {*}
* @param {FSdmmc} *instance_p FSDMMC驱动控制数据
* @param {u32} event FSDMMC中断事件类型参考FSDMMC_EVT_NUM
* @param {FSdmmcEventHandler} handler, FSDMMC中断事件响应函数
* @note 此函数用于设置FSDMMC中断时注册被注册的函数被FSdmmcCmdInterrupHandler、FSdmmcErrInterrupHandler
* 和FSdmmcDmaInterrupHandler调用
*/
void FSdmmcRegisterInterruptHandler(FSdmmc *instance_p, u32 event, FSdmmcEventHandler handler, void *args)
{
FASSERT(instance_p);
instance_p->evt_handler[event] = handler;
instance_p->evt_args[event] = args;
}
/**
* @name: FSdmmcInterruptTransfer
* @msg: 通过FSDMMC中断方式发送/接收数据和命令
* @return {FError} 驱动初始化的错误码信息FSDMMC_SUCCESS 表示发送/接收成功,其它返回值表示发送/接收失败
* @param {FSdmmc} *instance_p FSDMMC驱动控制数据
* @param {FSdmmcCmd} *cmd_data_p FSDMMC数据和命令
* @note FSDMMC控制器初始化后才能调用此函数使用前需要确保FSDMMC中断设置完成
*/
FError FSdmmcInterruptTransfer(FSdmmc *instance_p, FSdmmcCmd *cmd_data_p)
{
FASSERT(instance_p && cmd_data_p);
uintptr base_addr = instance_p->config.base_addr;
FError ret = FSDMMC_SUCCESS;
if (FALSE == FSdmmcCheckIfCardExists(base_addr))
{
FSDMMC_ERROR("Card not found !!! fsdio ctrl base 0x%x", base_addr);
return FSDMMC_ERR_CARD_NO_FOUND;
}
if (cmd_data_p->flag & FSDMMC_CMD_FLAG_EXP_DATA)
{
/* transfer data */
FSDMMC_INFO("====DATA [%d] START: buf: %p=====", cmd_data_p->cmdidx, cmd_data_p->data_p);
ret = FSdmmcSendData(base_addr,
(FSDMMC_CMD_FLAG_READ_DATA == (cmd_data_p->flag & FSDMMC_CMD_FLAG_READ_DATA)),
cmd_data_p);
}
else
{
/* transfer command */
FSDMMC_INFO("=====CMD [%d] START=====", cmd_data_p->cmdidx);
FSdmmcSendCmd(base_addr, cmd_data_p);
}
return ret;
}