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

331 lines
11 KiB
C
Raw Normal View History

/*
* 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中断时注册FSdmmcCmdInterrupHandlerFSdmmcErrInterrupHandler
* 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;
}