721 lines
16 KiB
C
721 lines
16 KiB
C
|
#include <common/bk_include.h>
|
||
|
#include "bk_arm_arch.h"
|
||
|
|
||
|
#include "bk_sdio.h"
|
||
|
#include "sdio.h"
|
||
|
#include "sutil.h"
|
||
|
#include "sdma_pub.h"
|
||
|
#include "bk_drv_model.h"
|
||
|
#include "bk_uart.h"
|
||
|
#include "bk_icu.h"
|
||
|
#include <os/mem.h>
|
||
|
//#include "co_math.h"
|
||
|
#include "bk_gpio.h"
|
||
|
#include "sdma.h"
|
||
|
//#include "mac.h"
|
||
|
#include"icu_driver.h"
|
||
|
#if CFG_WMM_PATCH
|
||
|
//#include "mm_timer.h"
|
||
|
//#include "ke_timer.h"
|
||
|
#endif
|
||
|
|
||
|
#if CONFIG_SDIO || CONFIG_SDIO_TRANS
|
||
|
#if CONFIG_SDIO_BLOCK_512
|
||
|
#include "sdio_intf.h"
|
||
|
UINT8 beken_tx_sdio_s = 1;
|
||
|
UINT8 da_hd_err = 0;
|
||
|
#endif
|
||
|
STATIC SDIO_S sdio;
|
||
|
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
#define SDIO_MAGIC_TAIL_STR "\xAA\xBB\xCC\xDD\xEE\xFF"
|
||
|
#endif
|
||
|
|
||
|
int sdio_ac_credits[AC_MAX];
|
||
|
|
||
|
STATIC const DD_OPERATIONS sdio_op = {
|
||
|
sdio_open,
|
||
|
sdio_close,
|
||
|
sdio_read,
|
||
|
sdio_write,
|
||
|
sdio_ctrl
|
||
|
};
|
||
|
|
||
|
SDIO_NODE_PTR sdio_alloc_valid_node(UINT32 buf_size)
|
||
|
{
|
||
|
SDIO_NODE_PTR temp_node_ptr;
|
||
|
SDIO_NODE_PTR mem_node_ptr = 0;
|
||
|
|
||
|
if (0 == buf_size)
|
||
|
goto av_exit;
|
||
|
|
||
|
#ifdef SUPPORT_STM32
|
||
|
buf_size = su_align_power2(buf_size);
|
||
|
#endif
|
||
|
|
||
|
temp_node_ptr = su_pop_node(&sdio.free_nodes);
|
||
|
if (temp_node_ptr) {
|
||
|
#ifdef SDIO_PREALLOC
|
||
|
BK_ASSERT(buf_size <= 1600);
|
||
|
temp_node_ptr->addr = temp_node_ptr->orig_addr + CONFIG_MSDU_RESV_HEAD_LENGTH;
|
||
|
temp_node_ptr->length = buf_size;
|
||
|
mem_node_ptr = temp_node_ptr;
|
||
|
#else
|
||
|
UINT8 *buff_ptr = (UINT8 *)os_malloc(CONFIG_MSDU_RESV_HEAD_LENGTH + buf_size
|
||
|
+ CONFIG_MSDU_RESV_TAIL_LEN
|
||
|
+ MALLOC_MAGIC_LEN);
|
||
|
if (buff_ptr) {
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
if ((UINT32)buff_ptr > 0x00400020 + 262112)
|
||
|
BK_ASSERT(0);
|
||
|
#endif
|
||
|
//if(MALLOC_MAGIC_LEN)
|
||
|
//{
|
||
|
//buff_ptr[(buf_size + MALLOC_MAGIC_LEN) - 1] = magic_byte0 ++; // MALLOC_MAGIC_BYTE0;
|
||
|
//}
|
||
|
|
||
|
temp_node_ptr->orig_addr = buff_ptr;
|
||
|
temp_node_ptr->addr = (UINT8 *)((UINT32)buff_ptr + CONFIG_MSDU_RESV_HEAD_LENGTH);
|
||
|
temp_node_ptr->length = buf_size;
|
||
|
|
||
|
temp_node_ptr->ac = -1;
|
||
|
mem_node_ptr = temp_node_ptr;
|
||
|
} else {
|
||
|
fatal_prf("alloc_null:%d\n", buf_size);
|
||
|
su_push_node(&sdio.free_nodes, temp_node_ptr);
|
||
|
}
|
||
|
#endif
|
||
|
} else
|
||
|
fatal_prf("*");
|
||
|
|
||
|
av_exit:
|
||
|
return mem_node_ptr;
|
||
|
}
|
||
|
|
||
|
|
||
|
void sdio_free_valid_node(SDIO_NODE_PTR node_ptr)
|
||
|
{
|
||
|
//UINT8 *buff_ptr;
|
||
|
|
||
|
//buff_ptr = node_ptr->addr;
|
||
|
if (MALLOC_MAGIC_LEN) {
|
||
|
//BK_ASSERT(buff_ptr[node_ptr->length + MALLOC_MAGIC_LEN - 1] == (magic_byte00 ++)/*MALLOC_MAGIC_BYTE0*/);
|
||
|
//buff_ptr[node_ptr->length + MALLOC_MAGIC_LEN - 1] = MALLOC_MAGIC_BYTE1;
|
||
|
//os_memset(node_ptr->addr, MALLOC_MAGIC_BYTE1, node_ptr->length + MALLOC_MAGIC_LEN - 1);
|
||
|
}
|
||
|
|
||
|
#ifndef SDIO_PREALLOC
|
||
|
os_free(node_ptr->orig_addr);
|
||
|
node_ptr->orig_addr = 0;
|
||
|
#endif
|
||
|
node_ptr->addr = 0;
|
||
|
node_ptr->length = 0;
|
||
|
|
||
|
su_push_node(&sdio.free_nodes, node_ptr);
|
||
|
}
|
||
|
|
||
|
#define SDIO_PATCH
|
||
|
#ifdef SDIO_PATCH
|
||
|
static UINT8 null_data[8] = {0};
|
||
|
#endif
|
||
|
|
||
|
/* in IRQ */
|
||
|
void sdio_cmd_handler(void *buf, UINT32 len)
|
||
|
{
|
||
|
UINT32 count;
|
||
|
UINT32 txlen;
|
||
|
SDIO_PTR sdio_ptr;
|
||
|
SDIO_DCMD_PTR cmd_ptr;
|
||
|
SDIO_CMD_PTR reg_cmd_ptr;
|
||
|
SDIO_NODE_PTR mem_node_ptr = NULL;
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
int tnf = 0, rnf = 0;
|
||
|
UINT8 *end;
|
||
|
#endif
|
||
|
|
||
|
BK_ASSERT(NULL != buf);
|
||
|
BK_ASSERT(buf == &sdio.cmd);
|
||
|
cmd_ptr = (SDIO_DCMD_PTR)buf;
|
||
|
reg_cmd_ptr = (SDIO_CMD_PTR)buf;
|
||
|
|
||
|
//BK_LOG_RAW("C\n");
|
||
|
|
||
|
if (sdio_debug_level) {
|
||
|
int pl;
|
||
|
u8 *cbuf;
|
||
|
cbuf = buf;
|
||
|
|
||
|
pl = len;
|
||
|
if (pl > 16)
|
||
|
pl = 16;
|
||
|
print_hex_dump("CMD: ", cbuf, pl);
|
||
|
}
|
||
|
|
||
|
sdma_fake_stop_dma();
|
||
|
|
||
|
sdio_ptr = &sdio;
|
||
|
switch (cmd_ptr->op_code) {
|
||
|
|
||
|
/* Host -> Target */
|
||
|
case OPC_WR_DTCM : {
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
if (sdio_ptr->rx_len) {
|
||
|
BK_LOG_RAW("RnF\n");
|
||
|
rnf = 1;
|
||
|
}
|
||
|
#endif
|
||
|
sdio_ptr->rx_len = cmd_ptr->data_len;
|
||
|
count = su_get_node_count(&sdio.rxing_list);
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
if (rnf)
|
||
|
os_printf("rc %d\n", count);
|
||
|
#endif
|
||
|
|
||
|
if (count) {
|
||
|
mem_node_ptr = su_pop_node(&sdio.rxing_list);
|
||
|
/* Delete current node */
|
||
|
sdio_free_valid_node(mem_node_ptr);
|
||
|
}
|
||
|
|
||
|
mem_node_ptr = sdio_alloc_valid_node(cmd_ptr->data_len + 20/* dummy len*/);
|
||
|
|
||
|
sdio_ptr->rc_len = 0;
|
||
|
sdio_ptr->rx_transaction_len = 0;
|
||
|
if (mem_node_ptr) {
|
||
|
sdio_ptr->next_seq = 0;
|
||
|
//sdio_ptr->rc_len = 0;
|
||
|
sdio_ptr->rx_status = RX_NODE_OK;
|
||
|
//BK_ASSERT(cmd_ptr->size == cmd_ptr->data_len);
|
||
|
sdio_ptr->rx_transaction_len = MIN(BLOCK_LEN - SDIO_TAIL_LEN, cmd_ptr->data_len);
|
||
|
|
||
|
su_push_node(&sdio.rxing_list, mem_node_ptr);
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
end = mem_node_ptr->addr + cmd_ptr->data_len + SDIO_TAIL_LEN + 2;
|
||
|
os_memcpy(end, SDIO_MAGIC_TAIL_STR, 6);
|
||
|
#endif
|
||
|
sdio_ptr->rx_addr = (UINT32)mem_node_ptr->addr;
|
||
|
sdma_start_rx(mem_node_ptr->addr, sdio_ptr->rx_transaction_len);
|
||
|
} else
|
||
|
sdio_ptr->rx_status = RX_NO_NODE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case OPC_RD_DTCM : {
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
if (sdio_ptr->tx_len) {
|
||
|
BK_LOG_RAW("TnF %d\n", sdio_ptr->tx_len);
|
||
|
tnf = 1;
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef SDIO_PATCH
|
||
|
if (su_get_node_count(&sdio.tx_dat) == 0)
|
||
|
sdio_ctrl(SDIO_CMD_CLEAR_TX_VALID, 0);
|
||
|
#else
|
||
|
if (su_get_node_count(&sdio.tx_dat) <= 1)
|
||
|
sdio_ctrl(SDIO_CMD_CLEAR_TX_VALID, 0);
|
||
|
#endif
|
||
|
//sdio_ptr->tx_len = cmd_ptr->data_len;
|
||
|
|
||
|
count = su_get_node_count(&sdio.txing_list);
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
if (tnf)
|
||
|
BK_LOG_RAW("tc %d\n", count);
|
||
|
#endif
|
||
|
|
||
|
if (count >= 2)
|
||
|
SDIO_WPRT("txing_list:%d\n", count);
|
||
|
BK_ASSERT(count < 2);
|
||
|
|
||
|
if (count) {
|
||
|
mem_node_ptr = su_pop_node(&sdio.txing_list);
|
||
|
sdio_free_valid_node(mem_node_ptr);
|
||
|
}
|
||
|
|
||
|
mem_node_ptr = su_pop_node(&sdio.tx_dat);
|
||
|
|
||
|
if (mem_node_ptr) {
|
||
|
#if CONFIG_SDIO_CREDITS
|
||
|
int ac = mem_node_ptr->ac;
|
||
|
if (ac >= 0)
|
||
|
sdio_ac_credits[ac]++;
|
||
|
#endif
|
||
|
|
||
|
sdio_ptr->tc_len = 0;
|
||
|
sdio_ptr->tx_status = TX_NODE_OK;
|
||
|
//BK_LOG_RAW("l:%d/%d\n", sdio_ptr->tx_len, mem_node_ptr->length);
|
||
|
|
||
|
//if (mem_node_ptr->length < sdio_ptr->tx_len)
|
||
|
sdio_ptr->tx_len = mem_node_ptr->length;
|
||
|
txlen = sdio_ptr->tx_len;
|
||
|
|
||
|
sdio_ctrl(SDIO_CMD_SET_TX_LEN, &txlen);
|
||
|
|
||
|
sdio_ptr->tx_transaction_len = MIN(BLOCK_LEN, txlen);
|
||
|
su_push_node(&sdio.txing_list, mem_node_ptr);
|
||
|
sdma_start_tx(mem_node_ptr->addr, sdio_ptr->tx_transaction_len);
|
||
|
} else {
|
||
|
#ifdef SDIO_PATCH
|
||
|
txlen = sizeof(null_data);
|
||
|
sdio_ctrl(SDIO_CMD_SET_TX_LEN, &txlen);
|
||
|
sdma_start_tx(null_data, sizeof(null_data));
|
||
|
#endif
|
||
|
sdio_ptr->tx_status = TX_NO_NODE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case OPC_WR_REG : {
|
||
|
UINT8 reg_numb = (reg_cmd_ptr->len - 4) >> 3;
|
||
|
UINT8 i;
|
||
|
UINT32 reg_addr, reg_val;
|
||
|
for (i = 0; i < reg_numb; i++) {
|
||
|
reg_addr = reg_cmd_ptr->content[i];
|
||
|
reg_val = reg_cmd_ptr->content[i + reg_numb];
|
||
|
*((UINT32 *)reg_addr) = reg_val;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case OPC_RD_REG : {
|
||
|
UINT8 reg_numb = (reg_cmd_ptr->len - 4) >> 2;
|
||
|
UINT8 i;
|
||
|
UINT32 reg_addr, reg_val[16];
|
||
|
for (i = 0; i < reg_numb; i++) {
|
||
|
reg_addr = reg_cmd_ptr->content[i];
|
||
|
reg_val[i] = *((UINT32 *)reg_addr);
|
||
|
}
|
||
|
|
||
|
sdio_ptr->transaction_len = MIN(64, reg_numb << 2);
|
||
|
sdma_start_tx((UINT8 *)reg_val, sdio_ptr->transaction_len);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default: {
|
||
|
SDIO_WPRT("Exceptional cmd of sdio\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void sdio_tx_cb(void)
|
||
|
{
|
||
|
UINT32 remain;
|
||
|
SDIO_PTR sdio_ptr;
|
||
|
SDIO_NODE_PTR mem_node_ptr;
|
||
|
sdio_ptr = &sdio;
|
||
|
|
||
|
//BK_LOG_RAW("T\n");
|
||
|
mem_node_ptr = su_pop_node(&sdio.txing_list);
|
||
|
if (0 == mem_node_ptr && (TX_NO_NODE == sdio_ptr->tx_status)) {
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
UINT32 addr = REG_READ(REG_SDMA_ADDR);
|
||
|
#ifdef SDIO_PATCH
|
||
|
if (addr == (UINT32)null_data)
|
||
|
sdio_ptr->tx_len = 0;
|
||
|
#endif
|
||
|
#endif
|
||
|
SDIO_PRT("tx_cb_no_node\n");
|
||
|
sdio_ptr->tx_status = TX_NODE_OK;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
BK_ASSERT(mem_node_ptr);
|
||
|
sdio_ptr->tc_len += sdio_ptr->tx_transaction_len;
|
||
|
|
||
|
if (sdio_ptr->tc_len >= mem_node_ptr->length) {
|
||
|
/* all data are sent */
|
||
|
if (mem_node_ptr->callback)
|
||
|
(mem_node_ptr->callback)(mem_node_ptr->Lparam, mem_node_ptr->Rparam);
|
||
|
|
||
|
mem_node_ptr->callback = NULLPTR;
|
||
|
mem_node_ptr->Lparam = NULL;
|
||
|
mem_node_ptr->Rparam = NULL;
|
||
|
sdma_fake_stop_dma();
|
||
|
sdio_ptr->tx_len = 0;
|
||
|
|
||
|
sdio_free_valid_node(mem_node_ptr);
|
||
|
} else {
|
||
|
remain = sdio_ptr->tx_len - sdio_ptr->tc_len;
|
||
|
sdio_ptr->tx_transaction_len = MIN(BLOCK_LEN, remain);
|
||
|
|
||
|
su_push_node(&sdio.txing_list, mem_node_ptr);
|
||
|
sdma_start_tx(mem_node_ptr->addr + sdio_ptr->tc_len, sdio_ptr->tx_transaction_len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* SDMA has received packets.
|
||
|
*
|
||
|
* @count: SDIO/DMA receive data counter.
|
||
|
*/
|
||
|
void sdio_rx_cb(UINT32 count)
|
||
|
{
|
||
|
UINT32 remain;
|
||
|
SDIO_PTR sdio_ptr;
|
||
|
SDIO_NODE_PTR mem_node_ptr;
|
||
|
struct stm32_frame_hdr *hdr;
|
||
|
sdio_ptr = &sdio;
|
||
|
UINT32 addr;
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
UINT8 *buf;
|
||
|
#endif
|
||
|
|
||
|
mem_node_ptr = su_pop_node(&sdio.rxing_list);
|
||
|
if (!mem_node_ptr && sdio_ptr->rx_status == RX_NO_NODE) {
|
||
|
SDIO_WPRT("rx_cb_no_node\n");
|
||
|
sdio_ptr->rx_status = RX_NODE_OK;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!mem_node_ptr) {
|
||
|
SDIO_WPRT("rx_no_nd %d\n", sdio_ptr->rc_len);
|
||
|
SDIO_WPRT("rxing_list:%d txing_list:%d\n", su_get_node_count(&sdio.rxing_list),
|
||
|
su_get_node_count(&sdio.txing_list));
|
||
|
|
||
|
sdio_ptr->rx_status = RX_NODE_OK;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (unlikely(sdio_ptr->rc_len > 2000))
|
||
|
BK_ASSERT(0);
|
||
|
|
||
|
if (unlikely(sdio_ptr->rx_transaction_len > 512))
|
||
|
BK_ASSERT(0);
|
||
|
|
||
|
addr = REG_READ(REG_SDMA_ADDR);
|
||
|
|
||
|
if (unlikely(sdio_ptr->rx_addr != addr)) {
|
||
|
BK_LOG_RAW("rx_addr 0x%x, tx_addr 0x%x, hw addr 0x%x\n",
|
||
|
sdio_ptr->rx_addr, sdio_ptr->tx_addr, addr);
|
||
|
BK_ASSERT(0);
|
||
|
}
|
||
|
|
||
|
/* check data */
|
||
|
hdr = (struct stm32_frame_hdr *)(mem_node_ptr->addr + sdio_ptr->rc_len + sdio_ptr->rx_transaction_len);
|
||
|
if (unlikely(hdr->seq != sdio_ptr->next_seq)) {
|
||
|
BK_LOG_RAW("se %d %d\n", hdr->seq, sdio_ptr->next_seq);
|
||
|
return;
|
||
|
}
|
||
|
if (unlikely(hdr->type != 0xAB)) {
|
||
|
BK_LOG_RAW("te\n");
|
||
|
return;
|
||
|
}
|
||
|
if (unlikely(hdr->len != sdio_ptr->rx_transaction_len)) {
|
||
|
BK_LOG_RAW("le %d %d\n", hdr->len, sdio_ptr->rx_transaction_len);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sdio_ptr->next_seq++;
|
||
|
|
||
|
//sdio_ptr->rc_len += count; count is function 1's data len
|
||
|
sdio_ptr->rc_len += sdio_ptr->rx_transaction_len;
|
||
|
if (unlikely(sdio_ptr->rc_len > 2000))
|
||
|
BK_ASSERT(0);
|
||
|
|
||
|
#if 0
|
||
|
if (hdr->remain > sdio_ptr->rx_len - sdio_ptr->rc_len) {
|
||
|
BK_LOG_RAW("ex: %d %d\n", hdr->remain > sdio_ptr->rx_len, sdio_ptr->rc_len);
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (sdio_ptr->rc_len >= sdio_ptr->rx_len) {
|
||
|
#ifdef SDIO_MEM_DEBUG
|
||
|
buf = mem_node_ptr->addr + sdio_ptr->rx_len + SDIO_TAIL_LEN + 2;
|
||
|
if (os_memcmp(buf, SDIO_MAGIC_TAIL_STR, 6)) {
|
||
|
BK_LOG_RAW("sdma corrupt memory\n");
|
||
|
BK_ASSERT(0);
|
||
|
}
|
||
|
os_memcpy(buf, "\xEE\xEE\xEE\xEE", 4);
|
||
|
buf += 4;
|
||
|
REG_PL_WR(buf, mem_node_ptr);
|
||
|
//buf += 4;
|
||
|
//REG_PL_WR(buf, mem_node_ptr->addr);
|
||
|
buf += 4;
|
||
|
REG_PL_WR(buf, sdio_ptr->rx_len);
|
||
|
buf += 4;
|
||
|
REG_PL_WR(buf, sdio_ptr->rc_len);
|
||
|
//buf += 4;
|
||
|
//REG_PL_WR(buf, sdio_ptr->rx_transaction_len);
|
||
|
mm_magic_match(mem_node_ptr->orig_addr);
|
||
|
#endif
|
||
|
|
||
|
su_push_node(&sdio.rx_dat, mem_node_ptr);
|
||
|
if (sdio_ptr->rx_cb)
|
||
|
(sdio_ptr->rx_cb)();
|
||
|
sdma_fake_stop_dma();
|
||
|
|
||
|
sdio_ptr->rx_len = 0;
|
||
|
sdio_ptr->rx_addr = 0;
|
||
|
} else {
|
||
|
remain = sdio_ptr->rx_len - sdio_ptr->rc_len;
|
||
|
sdio_ptr->rx_transaction_len = MIN(BLOCK_LEN - SDIO_TAIL_LEN, remain);
|
||
|
su_push_node(&sdio.rxing_list, mem_node_ptr);
|
||
|
sdio_ptr->rx_addr = (UINT32)(mem_node_ptr->addr + sdio_ptr->rc_len);
|
||
|
sdma_start_rx(mem_node_ptr->addr + sdio_ptr->rc_len, sdio_ptr->rx_transaction_len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void sdio_register_rx_cb(FUNCPTR func)
|
||
|
{
|
||
|
sdio.rx_cb = func; // sdio_rxed_trigger_evt
|
||
|
}
|
||
|
|
||
|
static void sdio_intfer_gpio_config(void)
|
||
|
{
|
||
|
UINT32 param;
|
||
|
|
||
|
param = GFUNC_MODE_SD_DMA;
|
||
|
sddev_control(DD_DEV_TYPE_GPIO, CMD_GPIO_ENABLE_SECOND, ¶m);
|
||
|
}
|
||
|
|
||
|
/**********************************************************************/
|
||
|
void sdio_init(void)
|
||
|
{
|
||
|
sdio_intfer_gpio_config();
|
||
|
|
||
|
os_memset(&sdio, 0, sizeof(sdio));
|
||
|
|
||
|
INIT_LIST_HEAD(&sdio.tx_dat);
|
||
|
INIT_LIST_HEAD(&sdio.rx_dat);
|
||
|
INIT_LIST_HEAD(&sdio.txing_list);
|
||
|
INIT_LIST_HEAD(&sdio.rxing_list);
|
||
|
|
||
|
su_init(&sdio);
|
||
|
|
||
|
#if CONFIG_SDIO_BLOCK_512
|
||
|
sdio.rc_len = 0;
|
||
|
sdio.tc_len = 0;
|
||
|
#endif
|
||
|
sdma_register_handler(sdio_tx_cb, sdio_rx_cb, sdio_cmd_handler);
|
||
|
sdma_init();
|
||
|
|
||
|
ddev_register_dev(DD_DEV_TYPE_SDIO, (DD_OPERATIONS *)&sdio_op);
|
||
|
|
||
|
//sdio.int_gpio = GPIO32;
|
||
|
sdio.int_gpio = GPIO24;
|
||
|
BkGpioInitialize(sdio.int_gpio, OUTPUT_NORMAL);
|
||
|
|
||
|
sdio_ac_credits[AC_BK] = 8;
|
||
|
sdio_ac_credits[AC_BE] = 10;
|
||
|
sdio_ac_credits[AC_VI] = 12;
|
||
|
sdio_ac_credits[AC_VO] = 14;
|
||
|
|
||
|
SDIO_PRT("sdio_init\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
void sdio_exit(void)
|
||
|
{
|
||
|
BkGpioFinalize(sdio.int_gpio);
|
||
|
|
||
|
sdma_uninit();
|
||
|
|
||
|
ddev_unregister_dev(DD_DEV_TYPE_SDIO);
|
||
|
}
|
||
|
|
||
|
UINT32 sdio_open(UINT32 op_flag)
|
||
|
{
|
||
|
UINT32 reg;
|
||
|
|
||
|
sdma_open();
|
||
|
sdma_start_cmd((UINT8 *)&sdio.cmd, sizeof(sdio.cmd));
|
||
|
|
||
|
reg = *((volatile UINT32 *)((0x00802000 + 16 * 4)));
|
||
|
if (reg & (1 << FIQ_SDIO_DMA)) {
|
||
|
//BK_ASSERT(0);
|
||
|
os_printf("already enabled sdio fiq\n");
|
||
|
}
|
||
|
|
||
|
icu_enable_sdio_dma_interrupt();
|
||
|
|
||
|
return SDIO_SUCCESS;
|
||
|
}
|
||
|
|
||
|
UINT32 sdio_close(void)
|
||
|
{
|
||
|
sdma_close();
|
||
|
|
||
|
return SDIO_SUCCESS;
|
||
|
}
|
||
|
|
||
|
UINT32 sdio_read(char *user_buf, UINT32 count, UINT32 op_flag)
|
||
|
{
|
||
|
UINT32 ret;
|
||
|
UINT32 len;
|
||
|
SDIO_NODE_PTR mem_node_ptr;
|
||
|
|
||
|
ret = SDIO_FAILURE;
|
||
|
if (H2S_RD_SYNC == op_flag) {
|
||
|
if (!user_buf || !count)
|
||
|
goto rd_exit;
|
||
|
|
||
|
mem_node_ptr = su_pop_node(&sdio.rx_dat);
|
||
|
if (mem_node_ptr) {
|
||
|
len = MIN(count, mem_node_ptr->length);
|
||
|
os_memcpy(user_buf, mem_node_ptr->addr, len);
|
||
|
ret = mem_node_ptr->length;
|
||
|
|
||
|
sdio_free_valid_node(mem_node_ptr);
|
||
|
} else
|
||
|
ret = SDIO_FAILURE;
|
||
|
} else if (H2S_RD_SPECIAL == op_flag) {
|
||
|
mem_node_ptr = su_pop_node(&sdio.rx_dat);
|
||
|
if (mem_node_ptr) {
|
||
|
mem_node_ptr->Lparam = &sdio.free_nodes;
|
||
|
mem_node_ptr->Rparam = mem_node_ptr;
|
||
|
|
||
|
ret = (UINT32)mem_node_ptr;
|
||
|
} else
|
||
|
ret = SDIO_FAILURE;
|
||
|
}
|
||
|
|
||
|
rd_exit:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void sdio_set_interrupt_host()
|
||
|
{
|
||
|
BkGpioOutputHigh(sdio.int_gpio);
|
||
|
}
|
||
|
|
||
|
static void sdio_clear_interrupt_host()
|
||
|
{
|
||
|
BkGpioOutputLow(sdio.int_gpio);
|
||
|
}
|
||
|
|
||
|
UINT32 sdio_write(char *user_buf, UINT32 count, UINT32 op_flag)
|
||
|
{
|
||
|
UINT32 ret;
|
||
|
SDIO_NODE_PTR mem_node_ptr;
|
||
|
|
||
|
ret = SDIO_FAILURE;
|
||
|
|
||
|
if (S2H_WR_SYNC == op_flag) {
|
||
|
if (!user_buf || !count)
|
||
|
goto exit_wr;
|
||
|
|
||
|
mem_node_ptr = sdio_alloc_valid_node(count);
|
||
|
if (mem_node_ptr) {
|
||
|
//strcpy(mem_node_ptr->caller, "sdio_write");
|
||
|
os_memcpy(mem_node_ptr->addr, user_buf, count);
|
||
|
//BK_LOG_RAW("%s %d: len %d\n", __func__, __LINE__, mem_node_ptr->length);
|
||
|
su_push_node(&sdio.tx_dat, mem_node_ptr);
|
||
|
sdio_ctrl(SDIO_CMD_SET_TX_VALID, 0);
|
||
|
|
||
|
ret = SDIO_SUCCESS;
|
||
|
} else
|
||
|
ret = SDIO_FAILURE;
|
||
|
} else if (S2H_WR_SPECIAL == op_flag) {
|
||
|
if (!user_buf || !count)
|
||
|
goto exit_wr;
|
||
|
|
||
|
mem_node_ptr = (SDIO_NODE_PTR)user_buf;
|
||
|
su_push_node(&sdio.tx_dat, mem_node_ptr);
|
||
|
sdio_ctrl(SDIO_CMD_SET_TX_VALID, 0);
|
||
|
|
||
|
ret = SDIO_SUCCESS;
|
||
|
}
|
||
|
|
||
|
exit_wr:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
UINT32 sdio_ctrl(UINT32 cmd, void *param)
|
||
|
{
|
||
|
UINT32 ret;
|
||
|
SDIO_NODE_PTR mem_node_ptr;
|
||
|
|
||
|
ret = SDIO_SUCCESS;
|
||
|
|
||
|
switch (cmd) {
|
||
|
case SDIO_CMD_PUSH_FREE_NODE:
|
||
|
mem_node_ptr = (SDIO_NODE_PTR)param;
|
||
|
|
||
|
sdio_free_valid_node(mem_node_ptr);
|
||
|
break;
|
||
|
|
||
|
case SDIO_CMD_GET_FREE_NODE: {
|
||
|
struct get_free_node_param *_param = (struct get_free_node_param *)param;
|
||
|
#if CONFIG_SDIO_CREDITS
|
||
|
int ac = mac_tid2ac[_param->tid];
|
||
|
int credits;
|
||
|
GLOBAL_INT_DECLARATION();
|
||
|
|
||
|
GLOBAL_INT_DISABLE();
|
||
|
credits = sdio_ac_credits[ac];
|
||
|
GLOBAL_INT_RESTORE();
|
||
|
|
||
|
if (credits <= 0)
|
||
|
mem_node_ptr = 0;
|
||
|
else {
|
||
|
mem_node_ptr = sdio_alloc_valid_node(_param->size);
|
||
|
if (mem_node_ptr) {
|
||
|
mem_node_ptr->ac = ac;
|
||
|
GLOBAL_INT_DISABLE();
|
||
|
sdio_ac_credits[ac]--;
|
||
|
GLOBAL_INT_RESTORE();
|
||
|
}
|
||
|
}
|
||
|
#else /* !CONFIG_SDIO_CREDITS */
|
||
|
mem_node_ptr = sdio_alloc_valid_node(_param->size);
|
||
|
#endif
|
||
|
#if 0
|
||
|
if (su_get_node_count(&sdio.tx_dat) > (CELL_COUNT >> 1))
|
||
|
mem_node_ptr = NULL;
|
||
|
else
|
||
|
mem_node_ptr = sdio_alloc_valid_node(_param->size, _param->force);
|
||
|
#endif
|
||
|
//if (mem_node_ptr)
|
||
|
// strcpy(mem_node_ptr->caller, "rw");
|
||
|
|
||
|
ret = (UINT32)mem_node_ptr;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SDIO_CMD_REG_RX_CALLBACK:
|
||
|
sdio_register_rx_cb((FUNCPTR)param);
|
||
|
break;
|
||
|
|
||
|
case SDIO_CMD_GET_CNT_FREE_NODE:
|
||
|
*((UINT32 *)param) = su_get_node_count(&sdio.free_nodes);
|
||
|
break;
|
||
|
|
||
|
case SDIO_CMD_CLEAR_TX_VALID:
|
||
|
sdma_clr_tx_valid();
|
||
|
sdio_clear_interrupt_host();
|
||
|
break;
|
||
|
|
||
|
case SDIO_CMD_PEEK_S2H_COUNT:
|
||
|
ret = su_get_node_count(&sdio.tx_dat);
|
||
|
break;
|
||
|
|
||
|
case SDIO_CMD_PEEK_H2S_COUNT:
|
||
|
ret = su_get_node_count(&sdio.rx_dat);
|
||
|
break;
|
||
|
|
||
|
case SDIO_CMD_SET_TX_VALID:
|
||
|
sdma_set_tx_valid();
|
||
|
sdio_set_interrupt_host();
|
||
|
break;
|
||
|
|
||
|
case SDIO_CMD_SET_TX_LEN:
|
||
|
sdma_set_tx_dat_count(*(UINT32 *)param);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|