/******************************************************************************
|
*
|
* Copyright(c) 2019 - 2021 Realtek Corporation.
|
*
|
* This program is free software; you can redistribute it and/or modify it
|
* under the terms of version 2 of the GNU General Public License as
|
* published by the Free Software Foundation.
|
*
|
* 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 GNU General Public License for
|
* more details.
|
*
|
*****************************************************************************/
|
#define _RTW_SDIO_C_
|
|
/*#include "drv_types_sdio.h"*/ /* RTW_SDIO_ADDR_CMD52_GEN */
|
#include "drv_types.h" /* drv_types_sdio.h, struct dvobj_priv and etc. */
|
#include "sdio_ops.h" /* rtw_sdio_raw_read(), rtw_sdio_raw_write() */
|
|
/*
|
* Description:
|
* Use SDIO cmd52 or cmd53 to read/write data
|
*
|
* Parameters:
|
* d pointer of device object(struct dvobj_priv)
|
* addr SDIO address, 17 bits
|
* buf buffer for I/O
|
* len length
|
* write 0:read, 1:write
|
* cmd52 0:cmd52, 1:cmd53
|
*
|
* Return:
|
* _SUCCESS I/O ok.
|
* _FAIL I/O fail.
|
*/
|
static u8 sdio_io(struct dvobj_priv *d, u32 addr, void *buf, size_t len, u8 write, u8 cmd52)
|
{
|
#ifdef DBG_SDIO
|
#if (DBG_SDIO >= 3)
|
struct sdio_data *sdio = dvobj_to_sdio(d);
|
#endif /* DBG_SDIO >= 3 */
|
#endif /* DBG_SDIO */
|
u32 addr_drv; /* address with driver defined bit */
|
int err;
|
u8 retry = 0;
|
u8 stop_retry = _FALSE; /* flag for stopping retry or not */
|
|
if (dev_is_surprise_removed(d)) {
|
RTW_ERR("%s: bSurpriseRemoved, skip %s 0x%05x, %zu bytes\n",
|
__FUNCTION__, write?"write":"read", addr, len);
|
return _FAIL;
|
}
|
|
addr_drv = addr;
|
if (cmd52)
|
addr_drv = RTW_SDIO_ADDR_CMD52_GEN(addr_drv);
|
|
do {
|
if (write)
|
err = rtw_sdio_raw_write(d, addr_drv, buf, len, 0);
|
else
|
err = rtw_sdio_raw_read(d, addr_drv, buf, len, 0);
|
if (!err) {
|
if (retry) {
|
RTW_INFO("%s: Retry %s OK! addr=0x%05x %zu bytes, retry=%u,%u\n",
|
__FUNCTION__, write?"write":"read",
|
addr, len, retry, ATOMIC_READ(&d->continual_io_error));
|
RTW_INFO_DUMP("Data: ", buf, len);
|
}
|
rtw_reset_continual_io_error(d);
|
break;
|
}
|
RTW_ERR("%s: %s FAIL! error(%d) addr=0x%05x %zu bytes, retry=%u,%u\n",
|
__FUNCTION__, write?"write":"read", err, addr, len,
|
retry, ATOMIC_READ(&d->continual_io_error));
|
|
#ifdef DBG_SDIO
|
#if (DBG_SDIO >= 3)
|
if (sdio->dbg_enable) {
|
if (sdio->err_test && sdio->err_test_triggered)
|
sdio->err_test = 0;
|
|
if (sdio->err_stop) {
|
RTW_ERR("%s: I/O error! Set surprise remove flag ON!\n",
|
__FUNCTION__);
|
dev_set_surprise_removed(d);
|
return _FAIL;
|
}
|
}
|
#endif /* DBG_SDIO >= 3 */
|
#endif /* DBG_SDIO */
|
|
retry++;
|
stop_retry = rtw_inc_and_chk_continual_io_error(d);
|
if ((err == -1) || (stop_retry == _TRUE) || (retry > SD_IO_TRY_CNT)) {
|
/* critical error, unrecoverable */
|
RTW_ERR("%s: Fatal error! Set surprise remove flag ON! (retry=%u,%u)\n",
|
__FUNCTION__, retry, ATOMIC_READ(&d->continual_io_error));
|
dev_set_surprise_removed(d);
|
return _FAIL;
|
}
|
|
/* WLAN IOREG or SDIO Local */
|
if ((addr & 0x10000) || !(addr & 0xE000)) {
|
RTW_WARN("%s: Retry %s addr=0x%05x %zu bytes, retry=%u,%u\n",
|
__FUNCTION__, write?"write":"read", addr, len,
|
retry, ATOMIC_READ(&d->continual_io_error));
|
continue;
|
}
|
return _FAIL;
|
} while (1);
|
|
return _SUCCESS;
|
}
|
|
u8 rtw_sdio_read_cmd52(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
|
{
|
return sdio_io(d, addr, buf, len, 0, 1);
|
}
|
|
u8 rtw_sdio_read_cmd53(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
|
{
|
return sdio_io(d, addr, buf, len, 0, 0);
|
}
|
|
u8 rtw_sdio_write_cmd52(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
|
{
|
return sdio_io(d, addr, buf, len, 1, 1);
|
}
|
|
u8 rtw_sdio_write_cmd53(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
|
{
|
return sdio_io(d, addr, buf, len, 1, 0);
|
}
|
|
u8 rtw_sdio_f0_read(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
|
{
|
int err;
|
u8 ret;
|
|
|
ret = _SUCCESS;
|
addr = RTW_SDIO_ADDR_F0_GEN(addr);
|
|
err = rtw_sdio_raw_read(d, addr, buf, len, 0);
|
if (err)
|
ret = _FAIL;
|
|
return ret;
|
}
|
|
/**
|
* rtw_sdio_cmd53_align_size() - Align size to one CMD53 could complete
|
* @d struct dvobj_priv*
|
* @len length to align
|
*
|
* Adjust len to align block size, and the new size could be transfered by one
|
* CMD53.
|
* If len < block size, it would keep original value, otherwise the value
|
* would be rounded up by block size.
|
*
|
* Return adjusted length.
|
*/
|
size_t rtw_sdio_cmd53_align_size(struct dvobj_priv *d, size_t len)
|
{
|
u32 blk_sz;
|
|
|
blk_sz = rtw_sdio_get_block_size(d);
|
if (len <= blk_sz)
|
return len;
|
|
return _RND(len, blk_sz);
|
}
|
|
static s32 sdio_init_xmit_priv(struct _ADAPTER *a)
|
{
|
return _SUCCESS;
|
}
|
|
static void sdio_free_xmit_priv(_adapter *adapter)
|
{
|
}
|
|
static s32 sdio_init_recv_priv(struct dvobj_priv *dvobj)
|
{
|
return _SUCCESS;
|
}
|
|
static void sdio_free_recv_priv(struct dvobj_priv *dvobj)
|
{
|
}
|
|
struct rtw_intf_ops sdio_ops = {
|
/****************** xmit *********************/
|
.init_xmit_priv = sdio_init_xmit_priv,
|
.free_xmit_priv = sdio_free_xmit_priv,
|
|
/****************** recv *********************/
|
.init_recv_priv = sdio_init_recv_priv,
|
.free_recv_priv = sdio_free_recv_priv,
|
};
|