rt-thread/bsp/phytium/libraries/standalone/drivers/mmc/fsdio/fsdio_cmd.c

259 lines
8.6 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: fsdio_cmd.c
* Date: 2022-06-01 14:23:59
* LastEditTime: 2022-06-01 14:24:00
* Description:  This file is for SDIO command related function
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.1 zhugengyu 2022/6/6 modify according to tech manual.
*/
/***************************** Include Files *********************************/
#include "fio.h"
#include "fdebug.h"
#include "fassert.h"
#include "ftypes.h"
#include "fcache.h"
#include "fswap.h"
#include "fsdio_hw.h"
#include "fsdio.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
#define FSDIO_EXT_APP_CMD 55U
/***************** Macros (Inline Functions) Definitions *********************/
#define FSDIO_DEBUG_TAG "FSDIO-CMD"
#define FSDIO_ERROR(format, ...) FT_DEBUG_PRINT_E(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDIO_WARN(format, ...) FT_DEBUG_PRINT_W(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDIO_INFO(format, ...) FT_DEBUG_PRINT_I(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDIO_DEBUG(format, ...) FT_DEBUG_PRINT_D(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
/************************** Function Prototypes ******************************/
extern FError FSdioPIOReadData(FSdio *const instance_p, FSdioData *data_p);
/*****************************************************************************/
FError FSdioSendPrivateCmd(uintptr base_addr, u32 cmd, u32 arg)
{
u32 reg_val;
int retries = FSDIO_TIMEOUT;
do
{
reg_val = FSDIO_READ_REG(base_addr, FSDIO_STATUS_OFFSET);
if (--retries <= 0)
{
break;
}
}
while (FSDIO_STATUS_DATA_BUSY & reg_val);
if (retries <= 0)
{
return FSDIO_ERR_BUSY;
}
FSDIO_WRITE_REG(base_addr, FSDIO_CMD_ARG_OFFSET, arg);
FSDIO_DATA_BARRIER(); /* drain writebuffer */
FSDIO_WRITE_REG(base_addr, FSDIO_CMD_OFFSET, FSDIO_CMD_START | cmd);
retries = FSDIO_TIMEOUT;
do
{
reg_val = FSDIO_READ_REG(base_addr, FSDIO_CMD_OFFSET);
if (--retries <= 0)
{
break;
}
}
while (FSDIO_CMD_START & reg_val); /* wait until command send done */
return (retries <= 0) ? FSDIO_ERR_TIMEOUT : FSDIO_SUCCESS;
}
/**
* @name: FSdioTransferCmd
* @msg: pack and transfer command
* @return {FError} FSDIO_SUCCESS if transfer success
* @param {FSdio} *instance_p, SDIO controller instance
* @param {FSdioCmdData} *cmd_data_p, contents of transfer command and data
*/
FError FSdioTransferCmd(FSdio *const instance_p, FSdioCmdData *const cmd_data_p)
{
FASSERT(cmd_data_p);
FError ret = FSDIO_SUCCESS;
uintptr base_addr = instance_p->config.base_addr;
u32 cmd_flag = cmd_data_p->flag;
u32 raw_cmd = FSDIO_CMD_USE_HOLD_REG; /* USE_HOLD_REG必须为1 */
/* 命令需要进行卡初始化如CMD-0 */
if (FSDIO_CMD_FLAG_NEED_INIT & cmd_flag)
{
raw_cmd |= FSDIO_CMD_INIT;
}
/* 命令涉及电压切换 */
if (FSDIO_CMD_FLAG_SWITCH_VOLTAGE & cmd_flag)
{
raw_cmd |= FSDIO_CMD_VOLT_SWITCH;
}
/* 命令传输过程伴随数据传输 */
if (FSDIO_CMD_FLAG_EXP_DATA & cmd_flag)
{
raw_cmd |= FSDIO_CMD_DAT_EXP;
if (FSDIO_CMD_FLAG_WRITE_DATA & cmd_flag) /* 写卡 */
{
raw_cmd |= FSDIO_CMD_DAT_WRITE;
}
}
/* 命令需要进行CRC校验 */
if (FSDIO_CMD_FLAG_NEED_RESP_CRC & cmd_flag)
{
raw_cmd |= FSDIO_CMD_RESP_CRC;
}
/* 命令需要响应回复 */
if (FSDIO_CMD_FLAG_EXP_RESP & cmd_flag)
{
raw_cmd |= FSDIO_CMD_RESP_EXP;
if (FSDIO_CMD_FLAG_EXP_LONG_RESP & cmd_flag) /* 命令需要136字节长回复 */
{
raw_cmd |= FSDIO_CMD_RESP_LONG;
}
}
raw_cmd |= FSDIO_CMD_INDX_SET(cmd_data_p->cmdidx);
FSDIO_DEBUG("============[%s-%d]@0x%x begin ============",
(FSDIO_EXT_APP_CMD == instance_p->prev_cmd) ? "ACMD" : "CMD", cmd_data_p->cmdidx,
base_addr);
FSDIO_DEBUG(" cmd: 0x%x", raw_cmd);
FSDIO_DEBUG(" arg: 0x%x", cmd_data_p->cmdarg);
/* enable related interrupt */
FSdioSetInterruptMask(instance_p, FSDIO_GENERAL_INTR,
FSDIO_INTS_CMD_MASK, TRUE);
ret = FSdioSendPrivateCmd(base_addr, raw_cmd, cmd_data_p->cmdarg);
FSDIO_INFO("cmd send done ...");
return ret;
}
static void FSdioFlipByteOrder(u32 *response, fsize_t size)
{
/*
swap response and convert byte order
resp[0] = bswap32(resp[3])
resp[1] = bswap32(resp[2])
resp[2] = bswap32(resp[1])
resp[3] = bswap32(resp[0])
*/
FASSERT(size % (2 * sizeof(u32)) == 0);
const fsize_t n_words = size / sizeof(uint32_t);
for (int i = 0; i < (int)n_words / 2; ++i)
{
u32 left = __builtin_bswap32(response[i]);
u32 right = __builtin_bswap32(response[n_words - i - 1]);
response[i] = right;
response[n_words - i - 1] = left;
}
}
/**
* @name: FSdioGetCmdResponse
* @msg: Get cmd response and received data after wait poll status or interrupt signal
* @return {FError} FSDIO_SUCCESS if get success
* @param {FSdio} *instance_p, SDIO controller instance
* @param {FSdioCmdData} *cmd_data_p, contents of transfer command and data
*/
FError FSdioGetCmdResponse(FSdio *const instance_p, FSdioCmdData *const cmd_data_p)
{
FASSERT(instance_p);
FASSERT(cmd_data_p);
FError ret = FSDIO_SUCCESS;
u32 reg_val;
const boolean read = cmd_data_p->flag & FSDIO_CMD_FLAG_READ_DATA;
uintptr base_addr = instance_p->config.base_addr;
if (FT_COMPONENT_IS_READY != instance_p->is_ready)
{
FSDIO_ERROR("Device is not yet initialized!!!");
return FSDIO_ERR_NOT_INIT;
}
if ((NULL != cmd_data_p->data_p) && (read))
{
if (FSDIO_PIO_TRANS_MODE == instance_p->config.trans_mode)
{
ret = FSdioPIOReadData(instance_p, cmd_data_p->data_p);
}
}
/* check response of cmd */
if (FSDIO_CMD_FLAG_EXP_RESP & cmd_data_p->flag)
{
if (FSDIO_CMD_FLAG_EXP_LONG_RESP & cmd_data_p->flag)
{
cmd_data_p->response[0] = FSDIO_READ_REG(base_addr, FSDIO_RESP0_OFFSET);
cmd_data_p->response[1] = FSDIO_READ_REG(base_addr, FSDIO_RESP1_OFFSET);
cmd_data_p->response[2] = FSDIO_READ_REG(base_addr, FSDIO_RESP2_OFFSET);
cmd_data_p->response[3] = FSDIO_READ_REG(base_addr, FSDIO_RESP3_OFFSET);
/* according to SD spec. 136 bits R2 is send-back in reverse order and big-end,
some SD protocol will do this reverse and ntol itself, other do not,
filp_resp_byte_order is to compilant with those not */
if (instance_p->config.filp_resp_byte_order)
{
FSdioFlipByteOrder(cmd_data_p->response, sizeof(u32) * 4);
}
FSDIO_DEBUG(" resp: 0x%x-0x%x-0x%x-0x%x",
cmd_data_p->response[0], cmd_data_p->response[1],
cmd_data_p->response[2], cmd_data_p->response[3]);
}
else
{
cmd_data_p->response[0] = FSDIO_READ_REG(base_addr, FSDIO_RESP0_OFFSET);
cmd_data_p->response[1] = 0U;
cmd_data_p->response[2] = 0U;
cmd_data_p->response[3] = 0U;
FSDIO_DEBUG(" resp: 0x%x", cmd_data_p->response[0]);
}
}
cmd_data_p->success = TRUE; /* cmd / data transfer finished successful */
FSDIO_DEBUG("============[%s-%d]@0x%x end ============",
(FSDIO_EXT_APP_CMD == instance_p->prev_cmd) ? "ACMD" : "CMD",
cmd_data_p->cmdidx, base_addr);
/* disable related interrupt */
FSdioSetInterruptMask(instance_p, FSDIO_GENERAL_INTR, FSDIO_INTS_CMD_MASK | FSDIO_INTS_DATA_MASK, FALSE);
FSdioSetInterruptMask(instance_p, FSDIO_IDMA_INTR, FSDIO_DMAC_INTS_MASK, FALSE);
instance_p->prev_cmd = cmd_data_p->cmdidx; /* record previous command */
return ret;
}