Sync Nuvoton porting.
1. NUC980 platform: USBH, INPUTCAPTURE, SPINAND. 2. Correct enter-quad-mode routine in board_dec.c. 3. Use RT_ASSERT to catch system-call-exceptions.
This commit is contained in:
parent
ef8b984fa1
commit
dfbeb9e88c
|
@ -44,8 +44,10 @@ static rt_uint32_t nu_crc_run(
|
|||
{
|
||||
uint32_t u32CalChecksum = 0;
|
||||
uint32_t i = 0;
|
||||
rt_err_t result;
|
||||
|
||||
rt_mutex_take(&s_CRC_mutex, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(&s_CRC_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Configure CRC controller */
|
||||
CRC_Open(u32OpMode, u32Attr, u32Seed, CRC_CPU_WDATA_8);
|
||||
|
@ -85,16 +87,22 @@ static rt_uint32_t nu_crc_run(
|
|||
|
||||
/* Get checksum value */
|
||||
u32CalChecksum = CRC_GetChecksum();
|
||||
rt_mutex_release(&s_CRC_mutex);
|
||||
|
||||
result = rt_mutex_release(&s_CRC_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return u32CalChecksum;
|
||||
}
|
||||
|
||||
rt_err_t nu_crc_init(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
SYS_ResetModule(CRC_RST);
|
||||
|
||||
rt_mutex_init(&s_CRC_mutex, NU_CRYPTO_CRC_NAME, RT_IPC_FLAG_FIFO);
|
||||
result = rt_mutex_init(&s_CRC_mutex, NU_CRYPTO_CRC_NAME, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,8 @@ static volatile int s_SHA_done;
|
|||
|
||||
static rt_err_t nu_crypto_init(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
/* Enable Crypto engine interrupt */
|
||||
NVIC_EnableIRQ(CRPT_IRQn);
|
||||
|
||||
|
@ -89,12 +91,19 @@ static rt_err_t nu_crypto_init(void)
|
|||
SHA_ENABLE_INT(CRPT);
|
||||
|
||||
//init cipher mutex
|
||||
rt_mutex_init(&s_AES_mutex, NU_HWCRYPTO_AES_NAME, RT_IPC_FLAG_FIFO);
|
||||
rt_mutex_init(&s_TDES_mutex, NU_HWCRYPTO_TDES_NAME, RT_IPC_FLAG_FIFO);
|
||||
rt_mutex_init(&s_SHA_mutex, NU_HWCRYPTO_SHA_NAME, RT_IPC_FLAG_FIFO);
|
||||
result = rt_mutex_init(&s_AES_mutex, NU_HWCRYPTO_AES_NAME, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
result = rt_mutex_init(&s_TDES_mutex, NU_HWCRYPTO_TDES_NAME, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
result = rt_mutex_init(&s_SHA_mutex, NU_HWCRYPTO_SHA_NAME, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
#if !defined(BSP_USING_TRNG)
|
||||
PRNG_ENABLE_INT(CRPT);
|
||||
rt_mutex_init(&s_PRNG_mutex, NU_HWCRYPTO_PRNG_NAME, RT_IPC_FLAG_FIFO);
|
||||
result = rt_mutex_init(&s_PRNG_mutex, NU_HWCRYPTO_PRNG_NAME, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
#endif
|
||||
|
||||
return RT_EOK;
|
||||
|
@ -146,6 +155,8 @@ static rt_err_t nu_aes_crypt_run(
|
|||
uint32_t u32DataLen
|
||||
)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
uint32_t au32SwapKey[8];
|
||||
uint32_t au32SwapIV[4];
|
||||
|
||||
|
@ -171,7 +182,8 @@ static rt_err_t nu_aes_crypt_run(
|
|||
au32SwapIV[2] = nu_get32_be(&pu8IV[8]);
|
||||
au32SwapIV[3] = nu_get32_be(&pu8IV[12]);
|
||||
|
||||
rt_mutex_take(&s_AES_mutex, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(&s_AES_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
//Using Channel 0
|
||||
AES_Open(CRPT, 0, bEncrypt, u32OpMode, u32KeySize, AES_IN_OUT_SWAP);
|
||||
|
@ -186,7 +198,8 @@ static rt_err_t nu_aes_crypt_run(
|
|||
AES_Start(CRPT, 0, CRYPTO_DMA_ONE_SHOT);
|
||||
while (!s_AES_done) {};
|
||||
|
||||
rt_mutex_release(&s_AES_mutex);
|
||||
result = rt_mutex_release(&s_AES_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
@ -195,19 +208,26 @@ static rt_err_t nu_aes_crypt_run(
|
|||
//Using PRNG instead of TRNG
|
||||
static void nu_prng_open(uint32_t u32Seed)
|
||||
{
|
||||
rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
//Open PRNG 64 bits. But always return 32 bits
|
||||
PRNG_Open(CRPT, PRNG_KEY_SIZE_64, PRNG_SEED_RELOAD, u32Seed);
|
||||
|
||||
rt_mutex_release(&s_PRNG_mutex);
|
||||
result = rt_mutex_release(&s_PRNG_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
}
|
||||
|
||||
static rt_uint32_t nu_prng_run(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
uint32_t au32RNGValue[2];
|
||||
|
||||
rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
s_PRNG_done = 0;
|
||||
PRNG_Start(CRPT);
|
||||
|
@ -215,7 +235,9 @@ static rt_uint32_t nu_prng_run(void)
|
|||
|
||||
PRNG_Read(CRPT, au32RNGValue);
|
||||
|
||||
rt_mutex_release(&s_PRNG_mutex);
|
||||
result = rt_mutex_release(&s_PRNG_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return au32RNGValue[0];
|
||||
}
|
||||
|
||||
|
@ -356,6 +378,8 @@ static rt_err_t nu_des_crypt_run(
|
|||
uint32_t u32DataLen
|
||||
)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
uint32_t au32SwapKey[3][2];
|
||||
uint32_t au32SwapIV[2];
|
||||
|
||||
|
@ -373,7 +397,8 @@ static rt_err_t nu_des_crypt_run(
|
|||
au32SwapIV[0] = nu_get32_be(&pu8IV[0]);
|
||||
au32SwapIV[1] = nu_get32_be(&pu8IV[4]);
|
||||
|
||||
rt_mutex_take(&s_TDES_mutex, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(&s_TDES_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
//Using Channel 0
|
||||
TDES_Open(CRPT, 0, bEncrypt, (u32OpMode & CRPT_TDES_CTL_TMODE_Msk), u32KeySize, u32OpMode, TDES_IN_OUT_WHL_SWAP);
|
||||
|
@ -388,7 +413,8 @@ static rt_err_t nu_des_crypt_run(
|
|||
TDES_Start(CRPT, 0, CRYPTO_DMA_ONE_SHOT);
|
||||
while (!s_TDES_done) {};
|
||||
|
||||
rt_mutex_release(&s_TDES_mutex);
|
||||
result = rt_mutex_release(&s_TDES_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
@ -534,7 +560,10 @@ static rt_err_t nu_sha_hash_run(
|
|||
uint32_t u32DataLen
|
||||
)
|
||||
{
|
||||
rt_mutex_take(&s_SHA_mutex, RT_WAITING_FOREVER);
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mutex_take(&s_SHA_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
uint8_t *pu8SrcAddr = (uint8_t *)pu8InData;
|
||||
uint32_t u32CopyLen = 0;
|
||||
|
@ -574,7 +603,10 @@ static rt_err_t nu_sha_hash_run(
|
|||
if (psSHACtx->pu8SHATempBuf == RT_NULL)
|
||||
{
|
||||
LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize);
|
||||
rt_mutex_release(&s_SHA_mutex);
|
||||
|
||||
result = rt_mutex_release(&s_SHA_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -602,7 +634,10 @@ static rt_err_t nu_sha_hash_run(
|
|||
if (psSHACtx->pu8SHATempBuf == RT_NULL)
|
||||
{
|
||||
LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize);
|
||||
rt_mutex_release(&s_SHA_mutex);
|
||||
|
||||
result = rt_mutex_release(&s_SHA_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -613,7 +648,8 @@ static rt_err_t nu_sha_hash_run(
|
|||
psSHACtx->u32SHATempBufLen += u32DataLen;
|
||||
}
|
||||
|
||||
rt_mutex_release(&s_SHA_mutex);
|
||||
result = rt_mutex_release(&s_SHA_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
|
|
@ -242,6 +242,8 @@ static void link_monitor(void *param)
|
|||
|
||||
static rt_err_t nu_emac_init(rt_device_t dev)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
nu_emac_t psNuEMAC = (nu_emac_t)dev;
|
||||
|
||||
EMAC_Close();
|
||||
|
@ -254,9 +256,12 @@ static rt_err_t nu_emac_init(rt_device_t dev)
|
|||
NVIC_SetPriority(EMAC_RX_IRQn, 1);
|
||||
NVIC_EnableIRQ(EMAC_RX_IRQn);
|
||||
|
||||
rt_sem_init(&psNuEMAC->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
result = rt_sem_init(&psNuEMAC->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
result = rt_thread_init(ð_tid, "eth", link_monitor, (void *)psNuEMAC, eth_stack, sizeof(eth_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
rt_thread_init(ð_tid, "eth", link_monitor, (void *)psNuEMAC, eth_stack, sizeof(eth_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
|
||||
rt_thread_startup(ð_tid);
|
||||
|
||||
#if defined(LWIP_IPV4) && defined(LWIP_IGMP)
|
||||
|
@ -310,6 +315,7 @@ static rt_err_t nu_emac_control(rt_device_t dev, int cmd, void *args)
|
|||
|
||||
static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p)
|
||||
{
|
||||
rt_err_t result;
|
||||
nu_emac_t psNuEMAC = (nu_emac_t)dev;
|
||||
struct pbuf *q;
|
||||
rt_uint32_t offset = 0;
|
||||
|
@ -319,14 +325,15 @@ static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p)
|
|||
/* Get free TX buffer */
|
||||
if (buf == RT_NULL)
|
||||
{
|
||||
rt_sem_control(&psNuEMAC->eth_sem, RT_IPC_CMD_RESET, 0);
|
||||
result = rt_sem_control(&psNuEMAC->eth_sem, RT_IPC_CMD_RESET, 0);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk);
|
||||
EMAC_ENABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk);
|
||||
|
||||
do
|
||||
{
|
||||
rt_sem_take(&psNuEMAC->eth_sem, 1);
|
||||
while (rt_sem_take(&psNuEMAC->eth_sem, 10) != RT_EOK) ;
|
||||
buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf();
|
||||
}
|
||||
while (buf == RT_NULL);
|
||||
|
@ -440,8 +447,11 @@ void EMAC_TX_IRQHandler(void)
|
|||
/* Wake-up suspended process to send */
|
||||
if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk))
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
EMAC_DISABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk);
|
||||
rt_sem_release(&nu_emac_dev.eth_sem);
|
||||
result = rt_sem_release(&nu_emac_dev.eth_sem);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
|
||||
if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_TXBEIF_Msk))
|
||||
|
|
|
@ -228,41 +228,4 @@ int rt_hw_epwm_init(void)
|
|||
|
||||
INIT_DEVICE_EXPORT(rt_hw_epwm_init);
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
|
||||
static int pwm_get(int argc, char **argv)
|
||||
{
|
||||
int result = 0;
|
||||
struct rt_device_pwm *device = RT_NULL;
|
||||
struct rt_pwm_configuration configuration = {0};
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
rt_kprintf("Usage: pwm_get pwm1 1\n");
|
||||
result = -RT_ERROR;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
device = (struct rt_device_pwm *)rt_device_find(argv[1]);
|
||||
if (!device)
|
||||
{
|
||||
result = -RT_EIO;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
configuration.channel = atoi(argv[2]);
|
||||
result = rt_device_control(&device->parent, PWM_CMD_GET, &configuration);
|
||||
|
||||
_exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
MSH_CMD_EXPORT(pwm_get, pwm_get epwm1 1);
|
||||
|
||||
#endif /* FINSH_USING_MSH */
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,10 +54,15 @@ const struct fal_flash_dev Onchip_ldrom_flash = { "OnChip_LDROM", FMC_LDROM_BASE
|
|||
|
||||
int nu_fmc_read(long addr, uint8_t *buf, size_t size)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
size_t read_size = 0;
|
||||
uint32_t addr_end = addr + size;
|
||||
uint32_t isp_rdata = 0;
|
||||
rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
|
||||
|
||||
result = rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
SYS_UnlockReg();
|
||||
|
||||
if (NU_GET_LSB2BIT(addr))
|
||||
|
@ -87,7 +92,9 @@ int nu_fmc_read(long addr, uint8_t *buf, size_t size)
|
|||
}
|
||||
|
||||
SYS_LockReg();
|
||||
rt_mutex_release(g_mutex_fmc);
|
||||
|
||||
result = rt_mutex_release(g_mutex_fmc);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return read_size;
|
||||
}
|
||||
|
@ -97,8 +104,11 @@ int nu_fmc_write(long addr, const uint8_t *buf, size_t size)
|
|||
size_t write_size = 0;
|
||||
uint32_t addr_end = addr + size;
|
||||
uint32_t isp_rdata = 0;
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
|
||||
SYS_UnlockReg();
|
||||
|
||||
if (addr < FMC_APROM_END)
|
||||
|
@ -144,9 +154,12 @@ int nu_fmc_write(long addr, const uint8_t *buf, size_t size)
|
|||
|
||||
FMC_DISABLE_AP_UPDATE();
|
||||
FMC_DISABLE_LD_UPDATE();
|
||||
|
||||
Exit2:
|
||||
SYS_LockReg();
|
||||
rt_mutex_release(g_mutex_fmc);
|
||||
|
||||
result = rt_mutex_release(g_mutex_fmc);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return write_size;
|
||||
|
||||
|
@ -157,12 +170,12 @@ int nu_fmc_erase(long addr, size_t size)
|
|||
size_t erased_size = 0;
|
||||
uint32_t addrptr;
|
||||
uint32_t addr_end = addr + size;
|
||||
rt_err_t result;
|
||||
|
||||
#if defined(NU_SUPPORT_NONALIGN)
|
||||
uint8_t *page_sdtemp = RT_NULL;
|
||||
uint8_t *page_edtemp = RT_NULL;
|
||||
|
||||
|
||||
addrptr = addr & (FMC_FLASH_PAGE_SIZE - 1);
|
||||
if (addrptr)
|
||||
{
|
||||
|
@ -205,7 +218,9 @@ int nu_fmc_erase(long addr, size_t size)
|
|||
}
|
||||
#endif
|
||||
|
||||
rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
SYS_UnlockReg();
|
||||
|
||||
if (addr <= FMC_APROM_END)
|
||||
|
@ -233,7 +248,9 @@ Exit1:
|
|||
FMC_DISABLE_LD_UPDATE();
|
||||
Exit2:
|
||||
SYS_LockReg();
|
||||
rt_mutex_release(g_mutex_fmc);
|
||||
|
||||
result = rt_mutex_release(g_mutex_fmc);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
#if defined(NU_SUPPORT_NONALIGN)
|
||||
|
||||
|
@ -315,6 +332,7 @@ static int nu_fmc_init(void)
|
|||
SYS_LockReg();
|
||||
|
||||
g_mutex_fmc = rt_mutex_create("nu_fmc_lock", RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(g_mutex_fmc != RT_NULL);
|
||||
|
||||
/* PKG_USING_FAL */
|
||||
#if defined(PKG_USING_FAL)
|
||||
|
|
|
@ -256,11 +256,13 @@ void nu_pdma_channel_terminate(int i32ChannID)
|
|||
int i;
|
||||
uint32_t u32EnabledChans;
|
||||
int ch_mask = 0;
|
||||
rt_err_t result;
|
||||
|
||||
if (!(nu_pdma_chn_mask & (1 << i32ChannID)))
|
||||
goto exit_pdma_channel_terminate;
|
||||
|
||||
rt_mutex_take(g_mutex_res, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(g_mutex_res, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
// Suspend all channels.
|
||||
u32EnabledChans = nu_pdma_chn_mask & NU_PDMA_CH_Msk;
|
||||
|
@ -299,7 +301,8 @@ void nu_pdma_channel_terminate(int i32ChannID)
|
|||
u32EnabledChans &= ~ch_mask;
|
||||
}
|
||||
|
||||
rt_mutex_release(g_mutex_res);
|
||||
result = rt_mutex_release(g_mutex_res);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
exit_pdma_channel_terminate:
|
||||
|
||||
|
@ -552,7 +555,7 @@ rt_err_t nu_pdma_desc_setup(int i32ChannID, nu_pdma_desc_t dma_desc, uint32_t u3
|
|||
goto exit_nu_pdma_desc_setup;
|
||||
else if ((u32AddrSrc % (u32DataWidth / 8)) || (u32AddrDst % (u32DataWidth / 8)))
|
||||
goto exit_nu_pdma_desc_setup;
|
||||
else if ( i32TransferCnt > NU_PDMA_MAX_TXCNT )
|
||||
else if (i32TransferCnt > NU_PDMA_MAX_TXCNT)
|
||||
goto exit_nu_pdma_desc_setup;
|
||||
|
||||
psPeriphCtl = &nu_pdma_chn_arr[i32ChannID - NU_PDMA_CH_Pos].m_spPeripCtl;
|
||||
|
@ -625,11 +628,13 @@ static void nu_pdma_sgtbls_token_free(nu_pdma_desc_t psSgtbls)
|
|||
rt_err_t nu_pdma_sgtbls_allocate(nu_pdma_desc_t *ppsSgtbls, int num)
|
||||
{
|
||||
int i, j, idx;
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(ppsSgtbls != NULL);
|
||||
RT_ASSERT(num <= NU_PDMA_SG_TBL_MAXSIZE);
|
||||
|
||||
rt_mutex_take(g_mutex_sg, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(g_mutex_sg, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
|
@ -644,7 +649,8 @@ rt_err_t nu_pdma_sgtbls_allocate(nu_pdma_desc_t *ppsSgtbls, int num)
|
|||
ppsSgtbls[i] = (nu_pdma_desc_t)&nu_pdma_sgtbl_arr[idx];
|
||||
}
|
||||
|
||||
rt_mutex_release(g_mutex_sg);
|
||||
result = rt_mutex_release(g_mutex_sg);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
|
@ -660,18 +666,22 @@ fail_nu_pdma_sgtbls_allocate:
|
|||
ppsSgtbls[j] = NULL;
|
||||
}
|
||||
|
||||
rt_mutex_release(g_mutex_sg);
|
||||
result = rt_mutex_release(g_mutex_sg);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
void nu_pdma_sgtbls_free(nu_pdma_desc_t *ppsSgtbls, int num)
|
||||
{
|
||||
int i;
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(ppsSgtbls != NULL);
|
||||
RT_ASSERT(num <= NU_PDMA_SG_TBL_MAXSIZE);
|
||||
|
||||
rt_mutex_take(g_mutex_sg, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(g_mutex_sg, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
|
@ -682,7 +692,8 @@ void nu_pdma_sgtbls_free(nu_pdma_desc_t *ppsSgtbls, int num)
|
|||
ppsSgtbls[i] = NULL;
|
||||
}
|
||||
|
||||
rt_mutex_release(g_mutex_sg);
|
||||
result = rt_mutex_release(g_mutex_sg);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
|
||||
static rt_err_t nu_pdma_sgtbls_valid(nu_pdma_desc_t head)
|
||||
|
@ -870,6 +881,7 @@ static void nu_pdma_memfun_actor_init(void)
|
|||
if (-(RT_ERROR) != (nu_pdma_memfun_actor_arr[i].m_i32ChannID = nu_pdma_channel_allocate(PDMA_MEM)))
|
||||
{
|
||||
nu_pdma_memfun_actor_arr[i].m_psSemMemFun = rt_sem_create("memactor_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(nu_pdma_memfun_actor_arr[i].m_psSemMemFun != RT_NULL);
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
@ -878,16 +890,23 @@ static void nu_pdma_memfun_actor_init(void)
|
|||
{
|
||||
nu_pdma_memfun_actor_maxnum = i;
|
||||
nu_pdma_memfun_actor_mask = ~(((1 << i) - 1));
|
||||
|
||||
nu_pdma_memfun_actor_pool_sem = rt_sem_create("mempool_sem", nu_pdma_memfun_actor_maxnum, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(nu_pdma_memfun_actor_pool_sem != RT_NULL);
|
||||
|
||||
nu_pdma_memfun_actor_pool_lock = rt_mutex_create("mempool_lock", RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(nu_pdma_memfun_actor_pool_lock != RT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void nu_pdma_memfun_cb(void *pvUserData, uint32_t u32Events)
|
||||
{
|
||||
rt_err_t result;
|
||||
nu_pdma_memfun_actor_t psMemFunActor = (nu_pdma_memfun_actor_t)pvUserData;
|
||||
|
||||
psMemFunActor->m_u32Result = u32Events;
|
||||
rt_sem_release(psMemFunActor->m_psSemMemFun);
|
||||
result = rt_sem_release(psMemFunActor->m_psSemMemFun);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
|
||||
static int nu_pdma_memfun_employ(void)
|
||||
|
@ -897,7 +916,10 @@ static int nu_pdma_memfun_employ(void)
|
|||
/* Headhunter */
|
||||
if (nu_pdma_memfun_actor_pool_sem && (rt_sem_take(nu_pdma_memfun_actor_pool_sem, RT_WAITING_FOREVER) == RT_EOK))
|
||||
{
|
||||
rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
|
||||
rt_err_t result;
|
||||
result = rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Find the position of first '0' in nu_pdma_memfun_actor_mask. */
|
||||
idx = nu_cto(nu_pdma_memfun_actor_mask);
|
||||
if (idx != 32)
|
||||
|
@ -908,7 +930,8 @@ static int nu_pdma_memfun_employ(void)
|
|||
{
|
||||
idx = -1;
|
||||
}
|
||||
rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
|
||||
result = rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
|
||||
return idx;
|
||||
|
@ -924,6 +947,8 @@ static rt_size_t nu_pdma_memfun(void *dest, void *src, uint32_t u32DataWidth, un
|
|||
|
||||
while (1)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
/* Employ actor */
|
||||
if ((idx = nu_pdma_memfun_employ()) < 0)
|
||||
continue;
|
||||
|
@ -952,7 +977,8 @@ static rt_size_t nu_pdma_memfun(void *dest, void *src, uint32_t u32DataWidth, un
|
|||
0);
|
||||
|
||||
/* Wait it done. */
|
||||
rt_sem_take(psMemFunActor->m_psSemMemFun, RT_WAITING_FOREVER);
|
||||
result = rt_sem_take(psMemFunActor->m_psSemMemFun, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Give result if get NU_PDMA_EVENT_TRANSFER_DONE.*/
|
||||
if (psMemFunActor->m_u32Result & NU_PDMA_EVENT_TRANSFER_DONE)
|
||||
|
@ -976,12 +1002,16 @@ static rt_size_t nu_pdma_memfun(void *dest, void *src, uint32_t u32DataWidth, un
|
|||
}
|
||||
while (u32TransferCnt > 0);
|
||||
|
||||
rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
nu_pdma_memfun_actor_mask &= ~(1 << idx);
|
||||
rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
|
||||
result = rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Fire actor */
|
||||
rt_sem_release(nu_pdma_memfun_actor_pool_sem);
|
||||
result = rt_sem_release(nu_pdma_memfun_actor_pool_sem);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ static struct nu_spi nu_qspi_arr [] =
|
|||
.name = "qspi0",
|
||||
.spi_base = (SPI_T *)QSPI0,
|
||||
|
||||
#if defined(BSP_USING_QSPI_PDMA)
|
||||
#if defined(BSP_USING_SPI_PDMA)
|
||||
#if defined(BSP_USING_QSPI0_PDMA)
|
||||
.pdma_perp_tx = PDMA_QSPI0_TX,
|
||||
.pdma_perp_rx = PDMA_QSPI0_RX,
|
||||
|
@ -77,7 +77,7 @@ static struct nu_spi nu_qspi_arr [] =
|
|||
.name = "qspi1",
|
||||
.spi_base = (SPI_T *)QSPI1,
|
||||
|
||||
#if defined(BSP_USING_QSPI_PDMA)
|
||||
#if defined(BSP_USING_SPI_PDMA)
|
||||
#if defined(BSP_USING_QSPI1_PDMA)
|
||||
.pdma_perp_tx = PDMA_QSPI1_TX,
|
||||
.pdma_perp_rx = PDMA_QSPI1_RX,
|
||||
|
|
|
@ -270,11 +270,13 @@ static rt_size_t nu_sdh_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz
|
|||
{
|
||||
rt_uint32_t ret = 0;
|
||||
nu_sdh_t sdh = (nu_sdh_t)dev;
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(buffer != RT_NULL);
|
||||
|
||||
rt_sem_take(&sdh->lock, RT_WAITING_FOREVER);
|
||||
result = rt_sem_take(&sdh->lock, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Check alignment. */
|
||||
if (((uint32_t)buffer & 0x03) != 0)
|
||||
|
@ -315,7 +317,8 @@ exit_nu_sdh_read:
|
|||
sdh->pbuf = RT_NULL;
|
||||
}
|
||||
|
||||
rt_sem_release(&sdh->lock);
|
||||
result = rt_sem_release(&sdh->lock);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
if (ret == Successful)
|
||||
return blk_nb;
|
||||
|
@ -329,11 +332,13 @@ static rt_size_t nu_sdh_write(rt_device_t dev, rt_off_t pos, const void *buffer,
|
|||
{
|
||||
rt_uint32_t ret = 0;
|
||||
nu_sdh_t sdh = (nu_sdh_t)dev;
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(buffer != RT_NULL);
|
||||
|
||||
rt_sem_take(&sdh->lock, RT_WAITING_FOREVER);
|
||||
result = rt_sem_take(&sdh->lock, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Check alignment. */
|
||||
if (((uint32_t)buffer & 0x03) != 0)
|
||||
|
@ -372,7 +377,8 @@ exit_nu_sdh_write:
|
|||
sdh->pbuf = RT_NULL;
|
||||
}
|
||||
|
||||
rt_sem_release(&sdh->lock);
|
||||
result = rt_sem_release(&sdh->lock);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
if (ret == Successful) return blk_nb;
|
||||
|
||||
|
@ -427,11 +433,13 @@ static int rt_hw_sdh_init(void)
|
|||
/* Private */
|
||||
nu_sdh_arr[i].dev.user_data = (void *)&nu_sdh_arr[i];
|
||||
|
||||
rt_sem_init(&nu_sdh_arr[i].lock, "sdhlock", 1, RT_IPC_FLAG_FIFO);
|
||||
ret = rt_sem_init(&nu_sdh_arr[i].lock, "sdhlock", 1, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
|
||||
SDH_Open(nu_sdh_arr[i].base, CardDetect_From_GPIO);
|
||||
|
||||
nu_sdh_arr[i].pbuf = RT_NULL;
|
||||
|
||||
ret = rt_device_register(&nu_sdh_arr[i].dev, nu_sdh_arr[i].name, flags);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
}
|
||||
|
@ -620,7 +628,11 @@ static void sdh_hotplugger(void *param)
|
|||
|
||||
int mnt_init_sdcard_hotplug(void)
|
||||
{
|
||||
rt_thread_init(&sdh_tid, "hotplug", sdh_hotplugger, NULL, sdh_stack, sizeof(sdh_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_thread_init(&sdh_tid, "hotplug", sdh_hotplugger, NULL, sdh_stack, sizeof(sdh_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
rt_thread_startup(&sdh_tid);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -241,11 +241,13 @@ exit_nu_spi_bus_configure:
|
|||
#if defined(BSP_USING_SPI_PDMA)
|
||||
static void nu_pdma_spi_rx_cb(void *pvUserData, uint32_t u32EventFilter)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct nu_spi *spi_bus = (struct nu_spi *)pvUserData;
|
||||
|
||||
RT_ASSERT(spi_bus != RT_NULL);
|
||||
|
||||
rt_sem_release(spi_bus->m_psSemBus);
|
||||
result = rt_sem_release(spi_bus->m_psSemBus);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
static rt_err_t nu_pdma_spi_rx_config(struct nu_spi *spi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word)
|
||||
{
|
||||
|
@ -362,7 +364,8 @@ static rt_size_t nu_spi_pdma_transmit(struct nu_spi *spi_bus, const uint8_t *sen
|
|||
SPI_TRIGGER_TX_RX_PDMA(spi_base);
|
||||
|
||||
/* Wait RX-PDMA transfer done */
|
||||
rt_sem_take(spi_bus->m_psSemBus, RT_WAITING_FOREVER);
|
||||
result = rt_sem_take(spi_bus->m_psSemBus, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Stop TX/RX DMA transfer. */
|
||||
SPI_DISABLE_TX_RX_PDMA(spi_base);
|
||||
|
@ -391,6 +394,7 @@ rt_err_t nu_hw_spi_pdma_allocate(struct nu_spi *spi_bus)
|
|||
}
|
||||
|
||||
spi_bus->m_psSemBus = rt_sem_create("spibus_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(spi_bus->m_psSemBus != RT_NULL);
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
|
|
|
@ -243,10 +243,11 @@ exit_nu_spii2s_capacity_check:
|
|||
static rt_err_t nu_spii2s_dai_setup(nu_i2s_t psNuSPII2s, struct rt_audio_configure *pconfig)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
nu_acodec_ops_t pNuACodecOps = RT_NULL;
|
||||
nu_acodec_ops_t pNuACodecOps;
|
||||
SPI_T *spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
|
||||
|
||||
RT_ASSERT(psNuSPII2s->AcodecOps != RT_NULL);
|
||||
pNuACodecOps = psNuSPII2s->AcodecOps;
|
||||
SPI_T *spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
|
||||
|
||||
/* Open SPII2S */
|
||||
if (nu_spii2s_capacity_check(pconfig) == RT_TRUE)
|
||||
|
@ -283,7 +284,7 @@ static rt_err_t nu_spii2s_dai_setup(nu_i2s_t psNuSPII2s, struct rt_audio_configu
|
|||
/* Set MCLK and enable MCLK */
|
||||
SPII2S_EnableMCLK(spii2s_base, __HXT);
|
||||
|
||||
/* Set unmute */
|
||||
/* Set un-mute */
|
||||
if (pNuACodecOps->nu_acodec_mixer_control)
|
||||
pNuACodecOps->nu_acodec_mixer_control(AUDIO_MIXER_MUTE, RT_FALSE);
|
||||
}
|
||||
|
@ -298,14 +299,11 @@ exit_nu_spii2s_dai_setup:
|
|||
static rt_err_t nu_spii2s_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
nu_i2s_t psNuSPII2s;
|
||||
nu_acodec_ops_t pNuACodecOps = RT_NULL;
|
||||
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
|
||||
nu_acodec_ops_t pNuACodecOps;
|
||||
|
||||
RT_ASSERT(audio != RT_NULL);
|
||||
RT_ASSERT(caps != RT_NULL);
|
||||
|
||||
psNuSPII2s = (nu_i2s_t)audio;
|
||||
|
||||
RT_ASSERT(psNuSPII2s->AcodecOps != RT_NULL);
|
||||
|
||||
pNuACodecOps = psNuSPII2s->AcodecOps;
|
||||
|
@ -367,6 +365,10 @@ static rt_err_t nu_spii2s_getcaps(struct rt_audio_device *audio, struct rt_audio
|
|||
} // switch (caps->sub_type)
|
||||
break;
|
||||
|
||||
default:
|
||||
result = -RT_ERROR;
|
||||
break;
|
||||
|
||||
} // switch (caps->main_type)
|
||||
|
||||
return result;
|
||||
|
@ -375,16 +377,14 @@ static rt_err_t nu_spii2s_getcaps(struct rt_audio_device *audio, struct rt_audio
|
|||
static rt_err_t nu_spii2s_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
nu_i2s_t psNuSPII2s;
|
||||
nu_acodec_ops_t pNuACodecOps = RT_NULL;
|
||||
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
|
||||
nu_acodec_ops_t pNuACodecOps;
|
||||
int stream = -1;
|
||||
|
||||
RT_ASSERT(audio != RT_NULL);
|
||||
RT_ASSERT(caps != RT_NULL);
|
||||
|
||||
psNuSPII2s = (nu_i2s_t)audio;
|
||||
|
||||
RT_ASSERT(psNuSPII2s->AcodecOps != RT_NULL);
|
||||
|
||||
pNuACodecOps = psNuSPII2s->AcodecOps;
|
||||
|
||||
switch (caps->main_type)
|
||||
|
@ -394,7 +394,6 @@ static rt_err_t nu_spii2s_configure(struct rt_audio_device *audio, struct rt_aud
|
|||
psNuSPII2s->AcodecOps->nu_acodec_mixer_control(caps->sub_type, caps->udata.value);
|
||||
break;
|
||||
|
||||
|
||||
case AUDIO_TYPE_INPUT:
|
||||
stream = AUDIO_STREAM_RECORD;
|
||||
case AUDIO_TYPE_OUTPUT:
|
||||
|
@ -445,6 +444,7 @@ static rt_err_t nu_spii2s_configure(struct rt_audio_device *audio, struct rt_aud
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
result = -RT_ERROR;
|
||||
break;
|
||||
|
@ -456,12 +456,10 @@ static rt_err_t nu_spii2s_configure(struct rt_audio_device *audio, struct rt_aud
|
|||
static rt_err_t nu_spii2s_init(struct rt_audio_device *audio)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
nu_i2s_t psNuSPII2s;
|
||||
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
|
||||
|
||||
RT_ASSERT(audio != RT_NULL);
|
||||
|
||||
psNuSPII2s = (nu_i2s_t)audio;
|
||||
|
||||
/* Reset this module */
|
||||
SYS_ResetModule(psNuSPII2s->i2s_rst);
|
||||
|
||||
|
@ -470,13 +468,12 @@ static rt_err_t nu_spii2s_init(struct rt_audio_device *audio)
|
|||
|
||||
static rt_err_t nu_spii2s_start(struct rt_audio_device *audio, int stream)
|
||||
{
|
||||
nu_i2s_t psNuSPII2s;
|
||||
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
|
||||
SPI_T *spii2s_base;
|
||||
|
||||
RT_ASSERT(audio != RT_NULL);
|
||||
|
||||
psNuSPII2s = (nu_i2s_t)audio;
|
||||
|
||||
SPI_T *spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
|
||||
spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
|
||||
|
||||
/* Restart all: SPII2S and codec. */
|
||||
nu_spii2s_stop(audio, stream);
|
||||
|
@ -512,6 +509,8 @@ static rt_err_t nu_spii2s_start(struct rt_audio_device *audio, int stream)
|
|||
LOG_I("Start record.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
@ -519,14 +518,13 @@ static rt_err_t nu_spii2s_start(struct rt_audio_device *audio, int stream)
|
|||
|
||||
static rt_err_t nu_spii2s_stop(struct rt_audio_device *audio, int stream)
|
||||
{
|
||||
nu_i2s_t psNuSPII2s;
|
||||
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
|
||||
nu_i2s_dai_t psNuSPII2sDai = RT_NULL;
|
||||
SPI_T *spii2s_base;
|
||||
|
||||
RT_ASSERT(audio != RT_NULL);
|
||||
|
||||
psNuSPII2s = (nu_i2s_t)audio;
|
||||
|
||||
SPI_T *spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
|
||||
spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
|
||||
|
||||
switch (stream)
|
||||
{
|
||||
|
@ -574,13 +572,11 @@ static rt_err_t nu_spii2s_stop(struct rt_audio_device *audio, int stream)
|
|||
|
||||
static void nu_spii2s_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info)
|
||||
{
|
||||
nu_i2s_t psNuSPII2s;
|
||||
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
|
||||
|
||||
RT_ASSERT(audio != RT_NULL);
|
||||
RT_ASSERT(info != RT_NULL);
|
||||
|
||||
psNuSPII2s = (nu_i2s_t)audio;
|
||||
|
||||
info->buffer = (rt_uint8_t *)psNuSPII2s->i2s_dais[NU_I2S_DAI_PLAYBACK].fifo ;
|
||||
info->total_size = NU_I2S_DMA_FIFO_SIZE;
|
||||
info->block_size = NU_I2S_DMA_BUF_BLOCK_SIZE;
|
||||
|
@ -618,12 +614,12 @@ nu_hw_spii2s_pdma_allocate:
|
|||
|
||||
int rt_hw_spii2s_init(void)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
int j = 0;
|
||||
nu_i2s_dai_t psNuSPII2sDai;
|
||||
|
||||
|
||||
for (j = (SPII2S_START + 1); j < SPII2S_CNT; j++)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < NU_I2S_DAI_CNT; i++)
|
||||
{
|
||||
uint8_t *pu8ptr = rt_malloc(NU_I2S_DMA_FIFO_SIZE);
|
||||
|
|
|
@ -72,7 +72,7 @@ void timer_interrupt_handler(nu_capture_t *nu_timer_capture)
|
|||
{
|
||||
TIMER_ClearCaptureIntFlag(nu_timer_capture->timer);
|
||||
|
||||
/* Frist event is rising edge */
|
||||
/* First event is rising edge */
|
||||
if (nu_timer_capture->first_edge == RT_TRUE)
|
||||
{
|
||||
nu_timer_capture->first_edge = RT_FALSE;
|
||||
|
|
|
@ -27,8 +27,10 @@ static int s_i32TRNGEnable = 0;
|
|||
static rt_uint32_t nu_trng_run(void)
|
||||
{
|
||||
uint32_t u32RNGValue;
|
||||
rt_err_t result;
|
||||
|
||||
rt_mutex_take(&s_TRNG_mutex, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(&s_TRNG_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
TRNG_Open();
|
||||
|
||||
|
@ -38,13 +40,18 @@ static rt_uint32_t nu_trng_run(void)
|
|||
u32RNGValue = rand();
|
||||
}
|
||||
|
||||
rt_mutex_release(&s_TRNG_mutex);
|
||||
result = rt_mutex_release(&s_TRNG_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return u32RNGValue;
|
||||
}
|
||||
|
||||
rt_err_t nu_trng_init(void)
|
||||
{
|
||||
rt_mutex_init(&s_TRNG_mutex, NU_CRYPTO_TRNG_NAME, RT_IPC_FLAG_FIFO);
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mutex_init(&s_TRNG_mutex, NU_CRYPTO_TRNG_NAME, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
if ((SYS->CSERVER & SYS_CSERVER_VERSION_Msk) == 0x0)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define DBG_ENABLE
|
||||
#define DBG_SECTION_NAME LOG_TAG
|
||||
#define DBG_LEVEL DBG_INFO
|
||||
#define DBG_COLOR
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define SLV_10BIT_ADDR (0x1E<<2) //1111+0xx+r/w
|
||||
|
@ -382,4 +383,4 @@ int rt_hw_ui2c_init(void)
|
|||
|
||||
INIT_DEVICE_EXPORT(rt_hw_ui2c_init);
|
||||
|
||||
#endif //#if (defined(BSP_USING_UI2C) && defined(RT_USING_I2C))
|
||||
#endif //#if defined(BSP_USING_UI2C)
|
||||
|
|
|
@ -288,7 +288,7 @@ __STATIC_INLINE void _USBD_IRQHandler(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
/* USB Un-plug */
|
||||
/* USB Unplug */
|
||||
USBD_DISABLE_USB();
|
||||
rt_usbd_disconnect_handler(&_rt_obj_udc);
|
||||
}
|
||||
|
@ -447,7 +447,6 @@ void USBD_IRQHandler(void)
|
|||
|
||||
_USBD_IRQHandler();
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
|
@ -523,7 +522,7 @@ int nu_usbd_register(void)
|
|||
|
||||
_rt_obj_udc.parent.user_data = &nu_usbd;
|
||||
_rt_obj_udc.ops = &_udc_ops;
|
||||
/* Register endpoint infomation */
|
||||
/* Register endpoint information */
|
||||
_rt_obj_udc.ep_pool = _ep_pool;
|
||||
_rt_obj_udc.ep0.id = &_ep_pool[0];
|
||||
|
||||
|
|
|
@ -446,7 +446,6 @@ static void int_xfer_done_cb(UTR_T *psUTR)
|
|||
free_utr(psUTR);
|
||||
}
|
||||
|
||||
|
||||
static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
|
||||
{
|
||||
S_NU_RH_PORT_CTRL *psPortCtrl;
|
||||
|
@ -505,7 +504,6 @@ static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//others xfer
|
||||
rt_completion_init(&(psPortDev->utr_completion));
|
||||
|
||||
|
@ -694,7 +692,6 @@ static void nu_hcd_disconnect_callback(
|
|||
rt_usbh_root_hub_disconnect_handler(s_sUSBHDev.uhcd, port_index);
|
||||
}
|
||||
|
||||
|
||||
/* USB host operations -----------------------------------------------------------*/
|
||||
static struct uhcd_ops nu_uhcd_ops =
|
||||
{
|
||||
|
@ -706,7 +703,7 @@ static struct uhcd_ops nu_uhcd_ops =
|
|||
|
||||
static rt_err_t nu_hcd_init(rt_device_t device)
|
||||
{
|
||||
struct nu_usbh_dev * pNuUSBHDev = (struct nu_usbh_dev *)device;
|
||||
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
|
||||
usbh_core_init();
|
||||
|
||||
//install connect/disconnect callback
|
||||
|
@ -716,11 +713,11 @@ static rt_err_t nu_hcd_init(rt_device_t device)
|
|||
//create thread for polling usbh port status
|
||||
/* create usb hub thread */
|
||||
pNuUSBHDev->polling_thread = rt_thread_create("usbh_drv", nu_usbh_rh_thread_entry, RT_NULL,
|
||||
NU_USBH_THREAD_STACK_SIZE, 8, 20);
|
||||
if ( pNuUSBHDev->polling_thread != RT_NULL)
|
||||
NU_USBH_THREAD_STACK_SIZE, 8, 20);
|
||||
if (pNuUSBHDev->polling_thread != RT_NULL)
|
||||
{
|
||||
/* startup usb host thread */
|
||||
rt_thread_startup( pNuUSBHDev->polling_thread );
|
||||
rt_thread_startup(pNuUSBHDev->polling_thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -751,15 +748,20 @@ uint32_t usbh_tick_from_millisecond(uint32_t msec)
|
|||
/* device pm suspend() entry. */
|
||||
static int usbhost_pm_suspend(const struct rt_device *device, rt_uint8_t mode)
|
||||
{
|
||||
struct nu_usbh_dev * pNuUSBHDev = (struct nu_usbh_dev *)device;
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(pNuUSBHDev!=RT_NULL);
|
||||
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
|
||||
|
||||
RT_ASSERT(pNuUSBHDev != RT_NULL);
|
||||
switch (mode)
|
||||
{
|
||||
case PM_SLEEP_MODE_LIGHT:
|
||||
case PM_SLEEP_MODE_DEEP:
|
||||
|
||||
pNuUSBHDev->polling_thread->stat = RT_THREAD_READY;
|
||||
rt_thread_suspend(pNuUSBHDev->polling_thread);
|
||||
result = rt_thread_suspend(pNuUSBHDev->polling_thread);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -772,14 +774,16 @@ static int usbhost_pm_suspend(const struct rt_device *device, rt_uint8_t mode)
|
|||
/* device pm resume() entry. */
|
||||
static void usbhost_pm_resume(const struct rt_device *device, rt_uint8_t mode)
|
||||
{
|
||||
struct nu_usbh_dev * pNuUSBHDev = (struct nu_usbh_dev *)device;
|
||||
RT_ASSERT(pNuUSBHDev!=RT_NULL);
|
||||
rt_err_t result;
|
||||
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
|
||||
RT_ASSERT(pNuUSBHDev != RT_NULL);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case PM_SLEEP_MODE_LIGHT:
|
||||
case PM_SLEEP_MODE_DEEP:
|
||||
rt_thread_resume(pNuUSBHDev->polling_thread);
|
||||
result = rt_thread_resume(pNuUSBHDev->polling_thread);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -846,7 +850,7 @@ int nu_usbh_register(void)
|
|||
#if defined(RT_USING_PM)
|
||||
rt_pm_device_register(&uhcd->parent, &device_pm_ops);
|
||||
#endif
|
||||
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(nu_usbh_register);
|
||||
|
|
|
@ -12,6 +12,14 @@
|
|||
#include <rtconfig.h>
|
||||
|
||||
#if defined(BSP_USING_USPI)
|
||||
|
||||
#define LOG_TAG "drv.uspi"
|
||||
#define DBG_ENABLE
|
||||
#define DBG_SECTION_NAME LOG_TAG
|
||||
#define DBG_LEVEL DBG_INFO
|
||||
#define DBG_COLOR
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rtdef.h>
|
||||
|
@ -56,7 +64,8 @@ typedef struct nu_uspi *uspi_t;
|
|||
/* Private functions ------------------------------------------------------------*/
|
||||
static rt_err_t nu_uspi_bus_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
|
||||
static rt_uint32_t nu_uspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message);
|
||||
static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus, uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
|
||||
static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
|
||||
uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
|
||||
static int nu_uspi_register_bus(struct nu_uspi *uspi_bus, const char *name);
|
||||
static void nu_uspi_drain_rxfifo(USPI_T *uspi_base);
|
||||
|
||||
|
@ -160,7 +169,7 @@ static rt_err_t nu_uspi_bus_configure(struct rt_spi_device *device,
|
|||
u32BusClock = USPI_SetBusClock(uspi_bus->uspi_base, configuration->max_hz);
|
||||
if (configuration->max_hz > u32BusClock)
|
||||
{
|
||||
rt_kprintf("%s clock max frequency is %dHz (!= %dHz)\n", uspi_bus->name, u32BusClock, configuration->max_hz);
|
||||
LOG_W("%s clock max frequency is %dHz (!= %dHz)\n", uspi_bus->name, u32BusClock, configuration->max_hz);
|
||||
configuration->max_hz = u32BusClock;
|
||||
}
|
||||
|
||||
|
@ -194,7 +203,7 @@ static rt_err_t nu_uspi_bus_configure(struct rt_spi_device *device,
|
|||
}
|
||||
}
|
||||
|
||||
/* Clear SPI RX FIFO */
|
||||
/* Clear USPI RX FIFO */
|
||||
nu_uspi_drain_rxfifo(uspi_bus->uspi_base);
|
||||
|
||||
exit_nu_uspi_bus_configure:
|
||||
|
@ -205,16 +214,18 @@ exit_nu_uspi_bus_configure:
|
|||
#if defined(BSP_USING_USPI_PDMA)
|
||||
static void nu_pdma_uspi_rx_cb(void *pvUserData, uint32_t u32EventFilter)
|
||||
{
|
||||
struct nu_uspi *uspi_bus;
|
||||
uspi_bus = (struct nu_uspi *)pvUserData;
|
||||
rt_err_t result;
|
||||
struct nu_uspi *uspi_bus = (struct nu_uspi *)pvUserData;
|
||||
|
||||
RT_ASSERT(uspi_bus != RT_NULL);
|
||||
|
||||
rt_sem_release(uspi_bus->m_psSemBus);
|
||||
result = rt_sem_release(uspi_bus->m_psSemBus);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
|
||||
static rt_err_t nu_pdma_uspi_rx_config(struct nu_uspi *uspi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word)
|
||||
{
|
||||
rt_err_t result = RT_ERROR;
|
||||
rt_err_t result;
|
||||
rt_uint8_t *dst_addr = NULL;
|
||||
nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
|
||||
|
||||
|
@ -263,7 +274,7 @@ exit_nu_pdma_uspi_rx_config:
|
|||
|
||||
static rt_err_t nu_pdma_uspi_tx_config(struct nu_uspi *uspi_bus, const uint8_t *pu8Buf, int32_t i32SndLen, uint8_t bytes_per_word)
|
||||
{
|
||||
rt_err_t result = RT_ERROR;
|
||||
rt_err_t result;
|
||||
rt_uint8_t *src_addr = NULL;
|
||||
nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
|
||||
|
||||
|
@ -304,11 +315,11 @@ exit_nu_pdma_uspi_tx_config:
|
|||
|
||||
|
||||
/**
|
||||
* SPI PDMA transfer
|
||||
*/
|
||||
* USPI PDMA transfer
|
||||
**/
|
||||
static rt_size_t nu_uspi_pdma_transmit(struct nu_uspi *uspi_bus, const uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
|
||||
{
|
||||
rt_err_t result = RT_ERROR;
|
||||
rt_err_t result;
|
||||
|
||||
/* Get base address of uspi register */
|
||||
USPI_T *uspi_base = uspi_bus->uspi_base;
|
||||
|
@ -322,7 +333,8 @@ static rt_size_t nu_uspi_pdma_transmit(struct nu_uspi *uspi_bus, const uint8_t *
|
|||
USPI_TRIGGER_TX_RX_PDMA(uspi_base);
|
||||
|
||||
/* Wait PDMA transfer done */
|
||||
rt_sem_take(uspi_bus->m_psSemBus, RT_WAITING_FOREVER);
|
||||
result = rt_sem_take(uspi_bus->m_psSemBus, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Stop DMA TX/RX transfer */
|
||||
USPI_DISABLE_TX_RX_PDMA(uspi_base);
|
||||
|
@ -345,6 +357,7 @@ static rt_err_t nu_hw_uspi_pdma_allocate(struct nu_uspi *uspi_bus)
|
|||
}
|
||||
|
||||
uspi_bus->m_psSemBus = rt_sem_create("uspibus_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(uspi_bus->m_psSemBus != RT_NULL);
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
|
@ -373,10 +386,10 @@ static int nu_uspi_read(USPI_T *uspi_base, uint8_t *recv_addr, uint8_t bytes_per
|
|||
// Read RX data
|
||||
if (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
|
||||
{
|
||||
uint32_t val;
|
||||
// Read data from USPI RX FIFO
|
||||
switch (bytes_per_word)
|
||||
{
|
||||
uint32_t val;
|
||||
case 2:
|
||||
val = USPI_READ_RX(uspi_base);
|
||||
nu_set16_le(recv_addr, val);
|
||||
|
@ -385,6 +398,7 @@ static int nu_uspi_read(USPI_T *uspi_base, uint8_t *recv_addr, uint8_t bytes_per
|
|||
*recv_addr = USPI_READ_RX(uspi_base);
|
||||
break;
|
||||
default:
|
||||
LOG_E("Data length is not supported.\n");
|
||||
break;
|
||||
}
|
||||
size = bytes_per_word;
|
||||
|
@ -397,7 +411,7 @@ static int nu_uspi_write(USPI_T *uspi_base, const uint8_t *send_addr, uint8_t by
|
|||
// Wait USPI TX send data
|
||||
while (USPI_GET_TX_FULL_FLAG(uspi_base));
|
||||
|
||||
// Input data to SPI TX
|
||||
// Input data to USPI TX
|
||||
switch (bytes_per_word)
|
||||
{
|
||||
case 2:
|
||||
|
@ -407,6 +421,7 @@ static int nu_uspi_write(USPI_T *uspi_base, const uint8_t *send_addr, uint8_t by
|
|||
USPI_WRITE_TX(uspi_base, *((uint8_t *)send_addr));
|
||||
break;
|
||||
default:
|
||||
LOG_E("Data length is not supported.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -414,8 +429,8 @@ static int nu_uspi_write(USPI_T *uspi_base, const uint8_t *send_addr, uint8_t by
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief SPI bus polling
|
||||
* @param dev : The pointer of the specified SPI module.
|
||||
* @brief USPI bus polling
|
||||
* @param dev : The pointer of the specified USPI module.
|
||||
* @param send_addr : Source address
|
||||
* @param recv_addr : Destination address
|
||||
* @param length : Data length
|
||||
|
@ -440,10 +455,10 @@ static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
|
|||
uspi_bus->dummy = 0;
|
||||
while (length > 0)
|
||||
{
|
||||
/* Input data to SPI TX FIFO */
|
||||
/* Input data to USPI TX FIFO */
|
||||
length -= nu_uspi_write(uspi_base, (const uint8_t *)&uspi_bus->dummy, bytes_per_word);
|
||||
|
||||
/* Read data from RX FIFO */
|
||||
/* Read data from USPI RX FIFO */
|
||||
while (USPI_GET_RX_EMPTY_FLAG(uspi_base));
|
||||
recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
|
||||
}
|
||||
|
@ -453,20 +468,20 @@ static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
|
|||
{
|
||||
while (length > 0)
|
||||
{
|
||||
/* Input data to SPI TX FIFO */
|
||||
/* Input data to USPI TX FIFO */
|
||||
send_addr += nu_uspi_write(uspi_base, send_addr, bytes_per_word);
|
||||
length -= bytes_per_word;
|
||||
|
||||
/* Read data from RX FIFO */
|
||||
/* Read data from USPI RX FIFO */
|
||||
while (USPI_GET_RX_EMPTY_FLAG(uspi_base));
|
||||
recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
|
||||
}
|
||||
} // else
|
||||
|
||||
/* Wait RX or drain RX-FIFO */
|
||||
/* Wait USPI RX or drain USPI RX-FIFO */
|
||||
if (recv_addr)
|
||||
{
|
||||
// Wait SPI transmission done
|
||||
// Wait USPI transmission done
|
||||
while (USPI_IS_BUSY(uspi_base))
|
||||
{
|
||||
while (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
|
||||
|
@ -482,7 +497,7 @@ static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* Clear SPI RX FIFO */
|
||||
/* Clear USPI RX FIFO */
|
||||
nu_uspi_drain_rxfifo(uspi_base);
|
||||
}
|
||||
}
|
||||
|
@ -490,10 +505,10 @@ static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
|
|||
static void nu_uspi_transfer(struct nu_uspi *uspi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word)
|
||||
{
|
||||
#if defined(BSP_USING_USPI_PDMA)
|
||||
/* DMA transfer constrains */
|
||||
/* PDMA transfer constrains */
|
||||
if ((uspi_bus->pdma_chanid_rx >= 0) &&
|
||||
!((uint32_t)tx % bytes_per_word) &&
|
||||
!((uint32_t)rx % bytes_per_word))
|
||||
(!((uint32_t)tx % bytes_per_word)) &&
|
||||
(!((uint32_t)rx % bytes_per_word)))
|
||||
nu_uspi_pdma_transmit(uspi_bus, tx, rx, length, bytes_per_word);
|
||||
else
|
||||
nu_uspi_transmission_with_poll(uspi_bus, tx, rx, length, bytes_per_word);
|
||||
|
@ -519,7 +534,7 @@ static rt_uint32_t nu_uspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
|
|||
if ((message->length % bytes_per_word) != 0)
|
||||
{
|
||||
/* Say bye. */
|
||||
rt_kprintf("%s: error payload length(%d%%%d != 0).\n", uspi_bus->name, message->length, bytes_per_word);
|
||||
LOG_E("%s: error payload length(%d%%%d != 0).\n", uspi_bus->name, message->length, bytes_per_word);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -578,7 +593,7 @@ static int rt_hw_uspi_init(void)
|
|||
{
|
||||
if (nu_hw_uspi_pdma_allocate(&nu_uspi_arr[i]) != RT_EOK)
|
||||
{
|
||||
rt_kprintf("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_uspi_arr[i].name);
|
||||
LOG_E("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_uspi_arr[i].name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -484,7 +484,7 @@ static int nu_hw_uuart_dma_allocate(nu_uuart_t puuart)
|
|||
static rt_err_t nu_uuart_control(struct rt_serial_device *serial, int cmd, void *arg)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_uint32_t flag;
|
||||
rt_uint32_t flag = 0;
|
||||
rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
|
|
@ -23,10 +23,10 @@
|
|||
- For record function: Run it w/o parameter.
|
||||
- For replay function: Run it with parameter.
|
||||
*/
|
||||
static void audio_test(int argc, char **argv)
|
||||
static int audio_test(int argc, char **argv)
|
||||
{
|
||||
#define DEF_MAX_ARGV_NUM 8
|
||||
int smplrate[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000};
|
||||
int smplrate[] = {8000, 16000, 44100, 48000};
|
||||
int smplbit[] = {16};
|
||||
int chnum[] = {1, 2};
|
||||
struct wavrecord_info info;
|
||||
|
@ -74,6 +74,8 @@ static void audio_test(int argc, char **argv)
|
|||
} // k
|
||||
} // j
|
||||
} // i
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-1-10 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(RT_USB_DEVICE_CDC) && (defined(BSP_USING_USBD) || defined(BSP_USING_HSUSBD))
|
||||
|
@ -6,7 +18,11 @@ static struct rt_semaphore rx_sem;
|
|||
|
||||
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
|
||||
{
|
||||
rt_sem_release(&rx_sem);
|
||||
rt_err_t result = 0;
|
||||
|
||||
result = rt_sem_release(&rx_sem);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
@ -21,10 +37,8 @@ static void serial_thread_entry(void *parameter)
|
|||
{
|
||||
if (rt_sem_take(&rx_sem, 3 * RT_TICK_PER_SECOND) == -RT_ETIMEOUT)
|
||||
{
|
||||
time_t now;
|
||||
/* output current time */
|
||||
now = time(RT_NULL);
|
||||
rt_snprintf(szStr, sizeof(szStr), "%.*s\n", 25, ctime(&now));
|
||||
/* output current tick */
|
||||
rt_snprintf(szStr, sizeof(szStr), "%d\n", rt_tick_get());
|
||||
rt_device_write(serial, 0, &szStr[0], rt_strlen(szStr));
|
||||
continue;
|
||||
}
|
||||
|
@ -35,7 +49,7 @@ static void serial_thread_entry(void *parameter)
|
|||
|
||||
static int vcom_echo_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
rt_err_t result = 0;
|
||||
rt_thread_t thread;
|
||||
rt_device_t serial;
|
||||
|
||||
|
@ -45,25 +59,33 @@ static int vcom_echo_init(void)
|
|||
rt_kprintf("find failed!\n");
|
||||
return RT_ERROR;
|
||||
}
|
||||
err = rt_device_init(serial);
|
||||
if (err)
|
||||
result = rt_device_init(serial);
|
||||
if (result)
|
||||
{
|
||||
rt_kprintf("find failed!\n");
|
||||
return -RT_ERROR;
|
||||
rt_kprintf("init failed!\n");
|
||||
return -1;
|
||||
}
|
||||
result = rt_device_open(serial, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX/* | RT_DEVICE_FLAG_DMA_TX */);
|
||||
if (result)
|
||||
{
|
||||
rt_kprintf("open failed!\n");
|
||||
return -1;
|
||||
}
|
||||
err = rt_device_open(serial, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX/* | RT_DEVICE_FLAG_DMA_TX */);
|
||||
|
||||
rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
result = rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
rt_device_set_rx_indicate(serial, uart_input);
|
||||
result = rt_device_set_rx_indicate(serial, uart_input);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
thread = rt_thread_create("serial", serial_thread_entry, (void *)serial, 1024, 25, 10);
|
||||
if (thread != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(thread);
|
||||
result = rt_thread_startup(thread);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
return 0;
|
||||
}
|
||||
INIT_APP_EXPORT(vcom_echo_init);
|
||||
|
||||
|
|
|
@ -35,15 +35,17 @@ static void usb_thread_entry(void *parameter)
|
|||
{
|
||||
int8_t i8MouseTable[] = { -16, -16, -16, 0, 16, 16, 16, 0};
|
||||
uint8_t u8MouseIdx = 0;
|
||||
uint8_t u8MoveLen=0, u8MouseMode = 1;
|
||||
uint8_t u8MoveLen = 0, u8MouseMode = 1;
|
||||
uint8_t pu8Buf[4];
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
rt_device_t device = (rt_device_t)parameter;
|
||||
|
||||
rt_sem_init(&tx_sem_complete, "tx_complete_sem_hid", 1, RT_IPC_FLAG_FIFO);
|
||||
result = rt_sem_init(&tx_sem_complete, "tx_complete_sem_hid", 1, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
rt_device_set_tx_complete(device, event_hid_in);
|
||||
result = rt_device_set_tx_complete(device, event_hid_in);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
LOG_I("Ready.\n");
|
||||
|
||||
|
@ -79,7 +81,7 @@ static void usb_thread_entry(void *parameter)
|
|||
{
|
||||
/* Wait it done. */
|
||||
result = rt_sem_take(&tx_sem_complete, RT_WAITING_FOREVER);
|
||||
RT_ASSERT( result== RT_EOK );
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
|
||||
} // while(1)
|
||||
|
@ -96,10 +98,10 @@ static int dance_mouse_init(void)
|
|||
RT_ASSERT(ret == RT_EOK);
|
||||
|
||||
ret = rt_thread_init(&usb_thread,
|
||||
"hidd",
|
||||
usb_thread_entry, device,
|
||||
usb_thread_stack, sizeof(usb_thread_stack),
|
||||
10, 20);
|
||||
"hidd",
|
||||
usb_thread_entry, device,
|
||||
usb_thread_stack, sizeof(usb_thread_stack),
|
||||
10, 20);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
|
||||
ret = rt_thread_startup(&usb_thread);
|
||||
|
|
|
@ -62,4 +62,10 @@ menu "Nuvoton Packages Config"
|
|||
|
||||
endif
|
||||
|
||||
config NU_PKG_USING_SPINAND
|
||||
bool "SPI NAND flash."
|
||||
select BSP_USING_QSPI
|
||||
select RT_USING_MTD_NAND
|
||||
default n
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
group = []
|
||||
if GetDepend('NU_PKG_USING_SPINAND'):
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
group = DefineGroup('nu_pkgs_spinand', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
|
@ -0,0 +1,912 @@
|
|||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-1-13 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(NU_PKG_USING_SPINAND) && defined(RT_USING_MTD_NAND)
|
||||
|
||||
#define LOG_TAG "drv_spinand"
|
||||
#define DBG_ENABLE
|
||||
#define DBG_SECTION_NAME LOG_TAG
|
||||
#define DBG_LEVEL DBG_INFO
|
||||
#define DBG_COLOR
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "spinand.h"
|
||||
|
||||
struct nu_spinand g_spinandflash_dev = {0};
|
||||
|
||||
rt_size_t nu_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct rt_spi_message *index;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(message != RT_NULL);
|
||||
|
||||
result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_set_errno(-RT_EBUSY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reset errno */
|
||||
rt_set_errno(RT_EOK);
|
||||
|
||||
/* configure SPI bus */
|
||||
if (device->parent.bus->owner != &device->parent)
|
||||
{
|
||||
/* not the same owner as current, re-configure SPI bus */
|
||||
result = device->parent.bus->ops->configure(&device->parent, &device->parent.config);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
/* set SPI bus owner */
|
||||
device->parent.bus->owner = &device->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure SPI bus failed */
|
||||
rt_set_errno(-RT_EIO);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* transmit each SPI message */
|
||||
index = &message->parent;
|
||||
while (index)
|
||||
{
|
||||
if (device->parent.bus->ops->xfer(&device->parent, index) == 0)
|
||||
{
|
||||
result = -RT_EIO;
|
||||
rt_set_errno(-RT_EIO);
|
||||
goto __exit;
|
||||
}
|
||||
index = index->next;
|
||||
}
|
||||
|
||||
result = RT_EOK;
|
||||
|
||||
__exit:
|
||||
/* release bus lock */
|
||||
rt_mutex_release(&(device->parent.bus->lock));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t nu_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length)
|
||||
{
|
||||
struct rt_qspi_message message[2] = {0};
|
||||
|
||||
RT_ASSERT(send_buf);
|
||||
RT_ASSERT(recv_buf);
|
||||
RT_ASSERT(send_length != 0);
|
||||
|
||||
/* Send message */
|
||||
message[0].qspi_data_lines = 1;
|
||||
|
||||
/* Set send buf and send size */
|
||||
message[0].parent.recv_buf = RT_NULL;
|
||||
message[0].parent.send_buf = send_buf;
|
||||
message[0].parent.length = send_length;
|
||||
message[0].parent.cs_take = 1;
|
||||
|
||||
message[0].parent.next = &message[1].parent;
|
||||
|
||||
/* Receive message */
|
||||
message[1].qspi_data_lines = 1;
|
||||
|
||||
/* Set recv buf and recv size */
|
||||
message[1].parent.recv_buf = recv_buf;
|
||||
message[1].parent.send_buf = RT_NULL;
|
||||
message[1].parent.length = recv_length;
|
||||
message[1].parent.cs_release = 1;
|
||||
|
||||
return nu_qspi_transfer_message(device, &message[0]);
|
||||
}
|
||||
|
||||
rt_err_t nu_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length)
|
||||
{
|
||||
RT_ASSERT(send_buf);
|
||||
RT_ASSERT(length != 0);
|
||||
|
||||
struct rt_qspi_message message = {0};
|
||||
char *ptr = (char *)send_buf;
|
||||
rt_size_t count = 0;
|
||||
|
||||
message.instruction.content = ptr[0];
|
||||
message.instruction.qspi_lines = 1;
|
||||
count++;
|
||||
|
||||
/* set send buf and send size */
|
||||
message.qspi_data_lines = 1;
|
||||
|
||||
message.parent.send_buf = ptr + count;
|
||||
message.parent.recv_buf = RT_NULL;
|
||||
message.parent.length = length - count;
|
||||
message.parent.cs_take = 1;
|
||||
message.parent.cs_release = 1;
|
||||
|
||||
return nu_qspi_transfer_message(device, &message);
|
||||
}
|
||||
|
||||
static void spinand_dump_buffer(int page, rt_uint8_t *buf, int len, const char *title)
|
||||
{
|
||||
if ((DBG_LEVEL) >= DBG_LOG)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Just print 64-bytes.*/
|
||||
len = (len < 64) ? len : 64;
|
||||
|
||||
LOG_I("[%s-Page-%d]", title, page);
|
||||
|
||||
for (i = 0; i < len; i ++)
|
||||
{
|
||||
rt_kprintf("%02X ", buf[i]);
|
||||
if (i % 32 == 31) rt_kprintf("\n");
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t spinand_read_id(struct rt_mtd_nand_device *device)
|
||||
{
|
||||
rt_err_t result = RT_EOK ;
|
||||
uint32_t id = 0;
|
||||
|
||||
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
SPINAND_FLASH_OPS->jedecid_get(SPINAND_FLASH_QSPI, &id);
|
||||
|
||||
result = rt_mutex_release(SPINAND_FLASH_LOCK);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return (id != 0x0) ? RT_EOK : -RT_ERROR;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_read_page(struct rt_mtd_nand_device *device,
|
||||
rt_off_t page,
|
||||
rt_uint8_t *data,
|
||||
rt_uint32_t data_len,
|
||||
rt_uint8_t *spare,
|
||||
rt_uint32_t spare_len)
|
||||
{
|
||||
rt_err_t result = RT_EOK ;
|
||||
|
||||
LOG_D("[R-%d]data: 0x%08x %d, spare: 0x%08x, %d", page, data, data_len, spare, spare_len);
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
|
||||
if (page / device->pages_per_block > device->block_end)
|
||||
{
|
||||
LOG_E("[EIO] read page:%d", page);
|
||||
return -RT_MTD_EIO;
|
||||
}
|
||||
|
||||
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Data load, Read data from flash to cache */
|
||||
result = SPINAND_FLASH_OPS->read_dataload(SPINAND_FLASH_QSPI, (page >> 16) & 0xFF, (page >> 8) & 0xFF, (page & 0xFF));
|
||||
if (result != RT_EOK)
|
||||
goto exit_spinand_read_page;
|
||||
|
||||
if (data && data_len)
|
||||
{
|
||||
/* Read data: 0~data_len, Read cache to data */
|
||||
result = SPINAND_FLASH_OPS->read_quadoutput(SPINAND_FLASH_QSPI, 0, 0, data, data_len);
|
||||
if (result != RT_EOK)
|
||||
goto exit_spinand_read_page;
|
||||
}
|
||||
|
||||
if (spare && spare_len)
|
||||
{
|
||||
/* Read data: 2048~spare_len, Read cache to spare */
|
||||
result = SPINAND_FLASH_OPS->read_quadoutput(SPINAND_FLASH_QSPI, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, spare, spare_len);
|
||||
if (result != RT_EOK)
|
||||
goto exit_spinand_read_page;
|
||||
}
|
||||
|
||||
exit_spinand_read_page:
|
||||
|
||||
rt_mutex_release(SPINAND_FLASH_LOCK);
|
||||
|
||||
spinand_dump_buffer(page, data, data_len, "Read Data");
|
||||
spinand_dump_buffer(page, spare, spare_len, "Read Spare");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_write_page(struct rt_mtd_nand_device *device,
|
||||
rt_off_t page,
|
||||
const rt_uint8_t *data,
|
||||
rt_uint32_t data_len,
|
||||
const rt_uint8_t *spare,
|
||||
rt_uint32_t spare_len)
|
||||
{
|
||||
rt_err_t result = RT_EOK ;
|
||||
|
||||
LOG_D("[W-%d]data: 0x%08x %d, spare: 0x%08x, %d", page, data, data_len, spare, spare_len);
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
|
||||
if (page / device->pages_per_block > device->block_end)
|
||||
{
|
||||
LOG_E("[EIO] write page:%d", page);
|
||||
return -RT_MTD_EIO;
|
||||
}
|
||||
|
||||
spinand_dump_buffer(page, (uint8_t *)data, data_len, "WRITE DATA");
|
||||
spinand_dump_buffer(page, (uint8_t *)spare, spare_len, "WRITE SPARE");
|
||||
|
||||
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
if (SPINAND_FLASH_MCP == 1)
|
||||
{
|
||||
/* Select die. */
|
||||
if ((result = SPINAND_FLASH_OPS->die_select(SPINAND_FLASH_QSPI, SPINAND_DIE_ID0)) != RT_EOK)
|
||||
goto exit_spinand_write_page;
|
||||
}
|
||||
|
||||
/* Read data: 0~2111, to cache */
|
||||
if (data && data_len)
|
||||
result = SPINAND_FLASH_OPS->program_dataload(SPINAND_FLASH_QSPI, 0, 0, (uint8_t *)data, data_len, (uint8_t *)spare, spare_len);
|
||||
else
|
||||
result = SPINAND_FLASH_OPS->program_dataload(SPINAND_FLASH_QSPI, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, RT_NULL, 0, (uint8_t *)spare, spare_len);
|
||||
|
||||
if (result != RT_EOK)
|
||||
goto exit_spinand_write_page;
|
||||
|
||||
/* Flush data in cache to flash */
|
||||
result = SPINAND_FLASH_OPS->program_execute(SPINAND_FLASH_QSPI, (((page) >> 16) & 0xFF), (((page) >> 8) & 0xFF), (page) & 0xFF);
|
||||
if (result != RT_EOK)
|
||||
goto exit_spinand_write_page;
|
||||
|
||||
result = RT_EOK;
|
||||
|
||||
exit_spinand_write_page:
|
||||
|
||||
rt_mutex_release(SPINAND_FLASH_LOCK);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_move_page(struct rt_mtd_nand_device *device, rt_off_t src_page, rt_off_t dst_page)
|
||||
{
|
||||
rt_err_t result = RT_EOK ;
|
||||
uint8_t u8WECmd;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
|
||||
if ((src_page / device->pages_per_block > device->block_end) ||
|
||||
(dst_page / device->pages_per_block > device->block_end))
|
||||
{
|
||||
LOG_E("EIO src:%08x, dst:%08x!", src_page, dst_page);
|
||||
return -RT_MTD_EIO;
|
||||
}
|
||||
|
||||
LOG_D("src_page: %d, dst_page: %d", src_page, dst_page);
|
||||
|
||||
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Data load, Read data from flash to cache */
|
||||
result = SPINAND_FLASH_OPS->read_dataload(SPINAND_FLASH_QSPI, (src_page >> 16) & 0xFF, (src_page >> 8) & 0xFF, (src_page & 0xFF));
|
||||
if (result != RT_EOK)
|
||||
goto exit_spinand_move_page;
|
||||
|
||||
/* Enable WE before writting. */
|
||||
u8WECmd = 0x06;
|
||||
if ((result = nu_qspi_send(SPINAND_FLASH_QSPI, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
|
||||
goto exit_spinand_move_page;
|
||||
|
||||
/* Flush cache to flash */
|
||||
result = SPINAND_FLASH_OPS->program_execute(SPINAND_FLASH_QSPI, (((dst_page) >> 16) & 0xFF), (((dst_page) >> 8) & 0xFF), (dst_page) & 0xFF);
|
||||
if (result != RT_EOK)
|
||||
goto exit_spinand_move_page;
|
||||
|
||||
result = RT_EOK;
|
||||
|
||||
exit_spinand_move_page:
|
||||
|
||||
rt_mutex_release(SPINAND_FLASH_LOCK);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_erase_block_force(struct rt_mtd_nand_device *device, rt_uint32_t block)
|
||||
{
|
||||
rt_err_t result = RT_EOK ;
|
||||
uint32_t page;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
|
||||
if (block > device->block_end)
|
||||
{
|
||||
LOG_E("[EIO] block:%d", block);
|
||||
return -RT_MTD_EIO;
|
||||
}
|
||||
|
||||
page = block * SPINAND_FLASH_PAGE_PER_BLOCK_NUM;
|
||||
|
||||
LOG_D("force erase block: %d -> page: %d", block, page);
|
||||
|
||||
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
result = SPINAND_FLASH_OPS->block_erase(SPINAND_FLASH_QSPI, (page >> 16) & 0xFF, (page >> 8) & 0xFF, page & 0xFF);
|
||||
if (result != RT_EOK)
|
||||
goto exit_spinand_erase_block_force;
|
||||
|
||||
result = RT_EOK;
|
||||
|
||||
exit_spinand_erase_block_force:
|
||||
|
||||
rt_mutex_release(SPINAND_FLASH_LOCK);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_erase_block(struct rt_mtd_nand_device *device, rt_uint32_t block)
|
||||
{
|
||||
rt_err_t result = RT_EOK ;
|
||||
uint32_t page;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
|
||||
if (block > device->block_end)
|
||||
{
|
||||
LOG_E("[EIO] block:%d", block);
|
||||
return -RT_MTD_EIO;
|
||||
}
|
||||
|
||||
page = block * SPINAND_FLASH_PAGE_PER_BLOCK_NUM;
|
||||
|
||||
LOG_D("erase block: %d -> page: %d", block, page);
|
||||
|
||||
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Erase block after checking it is bad or not. */
|
||||
if (SPINAND_FLASH_OPS->block_isbad(SPINAND_FLASH_QSPI, page) != 0)
|
||||
{
|
||||
LOG_W("Block %d is bad.\n", block);
|
||||
result = -RT_ERROR;
|
||||
goto exit_spinand_erase_block;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SPINAND_FLASH_OPS->block_erase(SPINAND_FLASH_QSPI, (page >> 16) & 0xFF, (page >> 8) & 0xFF, page & 0xFF);
|
||||
if (result != RT_EOK)
|
||||
goto exit_spinand_erase_block;
|
||||
}
|
||||
|
||||
result = RT_EOK;
|
||||
|
||||
exit_spinand_erase_block:
|
||||
|
||||
rt_mutex_release(SPINAND_FLASH_LOCK);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_check_block(struct rt_mtd_nand_device *device, rt_uint32_t block)
|
||||
{
|
||||
rt_err_t result = RT_EOK ;
|
||||
uint32_t page = 0;
|
||||
uint8_t isbad = 0;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
|
||||
if (block > device->block_end)
|
||||
{
|
||||
LOG_E("[EIO] block:%d", block);
|
||||
return -RT_MTD_EIO;
|
||||
}
|
||||
|
||||
page = block * SPINAND_FLASH_PAGE_PER_BLOCK_NUM;
|
||||
|
||||
LOG_D("check block status: %d -> page: %d", block, page);
|
||||
|
||||
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
isbad = SPINAND_FLASH_OPS->block_isbad(SPINAND_FLASH_QSPI, page);
|
||||
|
||||
result = rt_mutex_release(SPINAND_FLASH_LOCK);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return (isbad == 0) ? RT_EOK : -RT_ERROR ;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_mark_badblock(struct rt_mtd_nand_device *device, rt_uint32_t block)
|
||||
{
|
||||
rt_err_t result = RT_EOK ;
|
||||
uint32_t page = 0;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
|
||||
if (block > device->block_end)
|
||||
{
|
||||
LOG_E("[EIO] block:%d", block);
|
||||
return -RT_MTD_EIO;
|
||||
}
|
||||
|
||||
page = block * SPINAND_FLASH_PAGE_PER_BLOCK_NUM;
|
||||
|
||||
LOG_D("mark bad block: %d -> page: %d", block, page);
|
||||
|
||||
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Erase block after checking it is bad or not. */
|
||||
if (SPINAND_FLASH_OPS->block_isbad(SPINAND_FLASH_QSPI, page) != 0)
|
||||
{
|
||||
LOG_W("Block %d is bad.\n", block);
|
||||
result = RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SPINAND_FLASH_OPS->block_markbad(SPINAND_FLASH_QSPI, page);
|
||||
}
|
||||
|
||||
rt_mutex_release(SPINAND_FLASH_LOCK);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct rt_mtd_nand_driver_ops spinand_ops =
|
||||
{
|
||||
spinand_read_id,
|
||||
spinand_read_page,
|
||||
spinand_write_page,
|
||||
spinand_move_page,
|
||||
spinand_erase_block,
|
||||
spinand_check_block,
|
||||
spinand_mark_badblock
|
||||
};
|
||||
|
||||
static uint32_t u32IsInited = 0;
|
||||
rt_err_t rt_hw_mtd_spinand_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
rt_err_t result;
|
||||
char szTmp[8];
|
||||
|
||||
if (u32IsInited)
|
||||
return RT_EOK;
|
||||
|
||||
result = rt_mutex_init(SPINAND_FLASH_LOCK, "spinand", RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
result = spinand_flash_init(SPINAND_FLASH_QSPI);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
for (i = 0; i < MTD_SPINAND_PARTITION_NUM; i++)
|
||||
{
|
||||
mtd_partitions[i].page_size = SPINAND_FLASH_PAGE_SIZE; /* The Page size in the flash */
|
||||
mtd_partitions[i].pages_per_block = SPINAND_FLASH_PAGE_PER_BLOCK_NUM; /* How many page number in a block */
|
||||
|
||||
mtd_partitions[i].oob_size = SPINAND_FLASH_OOB_SIZE; /* Out of bank size */
|
||||
mtd_partitions[i].oob_free = 32; /* the free area in oob that flash driver not use */
|
||||
mtd_partitions[i].plane_num = SPINAND_FLASH_MCP ; /* the number of plane in the NAND Flash */
|
||||
mtd_partitions[i].ops = &spinand_ops;
|
||||
|
||||
rt_snprintf(szTmp, sizeof(szTmp), "nand%d", i);
|
||||
|
||||
result = rt_mtd_nand_register_device(szTmp, &mtd_partitions[i]);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
|
||||
u32IsInited = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_hw_mtd_spinand_register(const char *device_name)
|
||||
{
|
||||
rt_device_t pDev;
|
||||
rt_err_t result;
|
||||
|
||||
if ((pDev = rt_device_find(device_name)) == RT_NULL)
|
||||
return -RT_ERROR;
|
||||
|
||||
SPINAND_FLASH_QSPI = (struct rt_qspi_device *)pDev;
|
||||
|
||||
SPINAND_FLASH_QSPI->config.parent.mode = RT_SPI_MODE_0 | RT_SPI_MSB;
|
||||
SPINAND_FLASH_QSPI->config.parent.data_width = 8;
|
||||
SPINAND_FLASH_QSPI->config.parent.max_hz = 48000000;
|
||||
SPINAND_FLASH_QSPI->config.ddr_mode = 0;
|
||||
SPINAND_FLASH_QSPI->config.qspi_dl_width = 4;
|
||||
|
||||
result = rt_spi_configure(&SPINAND_FLASH_QSPI->parent, &SPINAND_FLASH_QSPI->config.parent);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return rt_hw_mtd_spinand_init();
|
||||
}
|
||||
|
||||
#if defined(RT_USING_DFS_UFFS)
|
||||
#include "dfs_uffs.h"
|
||||
void uffs_setup_storage(struct uffs_StorageAttrSt *attr,
|
||||
struct rt_mtd_nand_device *nand)
|
||||
{
|
||||
RT_ASSERT(attr != RT_NULL);
|
||||
RT_ASSERT(nand != RT_NULL);
|
||||
|
||||
rt_memset(attr, 0, sizeof(struct uffs_StorageAttrSt));
|
||||
|
||||
attr->page_data_size = nand->page_size; /* page data size */
|
||||
attr->pages_per_block = nand->pages_per_block; /* pages per block */
|
||||
attr->spare_size = nand->oob_size; /* page spare size */
|
||||
attr->ecc_opt = RT_CONFIG_UFFS_ECC_MODE; /* ecc option */
|
||||
attr->ecc_size = nand->oob_size - nand->oob_free; /* ecc size */
|
||||
attr->block_status_offs = 0; /* indicate block bad or good, offset in spare */
|
||||
attr->layout_opt = RT_CONFIG_UFFS_LAYOUT; /* let UFFS do the spare layout */
|
||||
|
||||
/* initialize _uffs_data_layout and _uffs_ecc_layout */
|
||||
rt_memcpy(attr->_uffs_data_layout, spinand_flash_data_layout, UFFS_SPARE_LAYOUT_SIZE);
|
||||
rt_memcpy(attr->_uffs_ecc_layout, spinand_flash_ecc_layout, UFFS_SPARE_LAYOUT_SIZE);
|
||||
|
||||
attr->data_layout = attr->_uffs_data_layout;
|
||||
attr->ecc_layout = attr->_uffs_ecc_layout;
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <finsh.h>
|
||||
static int nread(int argc, char **argv)
|
||||
{
|
||||
int ret = -1;
|
||||
rt_uint8_t *spare = RT_NULL;
|
||||
rt_uint8_t *data_ptr = RT_NULL;
|
||||
struct rt_mtd_nand_device *device;
|
||||
rt_uint32_t partition, page;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
LOG_E("Usage %s: %s <partition_no> <page>.\n", __func__, __func__);
|
||||
goto exit_nread;
|
||||
}
|
||||
|
||||
page = atoi(argv[2]);
|
||||
|
||||
partition = atoi(argv[1]);
|
||||
|
||||
if (partition >= MTD_SPINAND_PARTITION_NUM)
|
||||
goto exit_nread;
|
||||
|
||||
device = &mtd_partitions[partition];
|
||||
data_ptr = (rt_uint8_t *) rt_malloc(SPINAND_FLASH_PAGE_SIZE);
|
||||
if (data_ptr == RT_NULL)
|
||||
{
|
||||
LOG_E("data_ptr: no memory\n");
|
||||
goto exit_nread;
|
||||
}
|
||||
spare = (rt_uint8_t *) rt_malloc(SPINAND_FLASH_OOB_SIZE);
|
||||
if (spare == RT_NULL)
|
||||
{
|
||||
LOG_E("spare: no memory\n");
|
||||
goto exit_nread;
|
||||
}
|
||||
|
||||
rt_memset(spare, 0, SPINAND_FLASH_OOB_SIZE);
|
||||
rt_memset(data_ptr, 0, SPINAND_FLASH_PAGE_SIZE);
|
||||
|
||||
page = page + device->block_start * device->pages_per_block;
|
||||
|
||||
if (spinand_read_page(device, page, &data_ptr[0], SPINAND_FLASH_PAGE_SIZE, &spare[0], SPINAND_FLASH_OOB_SIZE) != RT_EOK)
|
||||
goto exit_nread;
|
||||
|
||||
LOG_I("Partion:%d page-%d", partition, page);
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit_nread:
|
||||
|
||||
/* release memory */
|
||||
if (data_ptr)
|
||||
rt_free(data_ptr);
|
||||
|
||||
if (spare)
|
||||
rt_free(spare);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nwrite(int argc, char **argv)
|
||||
{
|
||||
int i, ret = -1;
|
||||
rt_uint8_t *data_ptr = RT_NULL;
|
||||
struct rt_mtd_nand_device *device;
|
||||
rt_uint32_t partition, page;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
LOG_E("Usage %s: %s <partition_no> <page>.\n", __func__, __func__);
|
||||
goto exit_nwrite;
|
||||
}
|
||||
|
||||
partition = atoi(argv[1]);
|
||||
page = atoi(argv[2]);
|
||||
|
||||
if (partition >= MTD_SPINAND_PARTITION_NUM)
|
||||
goto exit_nwrite;
|
||||
|
||||
device = &mtd_partitions[partition];
|
||||
|
||||
data_ptr = (rt_uint8_t *) rt_malloc(SPINAND_FLASH_PAGE_SIZE);
|
||||
if (data_ptr == RT_NULL)
|
||||
{
|
||||
LOG_E("data_ptr: no memory\n");
|
||||
goto exit_nwrite;
|
||||
}
|
||||
|
||||
/* Need random data to test ECC */
|
||||
for (i = 0; i < SPINAND_FLASH_PAGE_SIZE; i ++)
|
||||
data_ptr[i] = i / 5 - i;
|
||||
|
||||
page = page + device->block_start * device->pages_per_block;
|
||||
spinand_write_page(device, page, &data_ptr[0], SPINAND_FLASH_PAGE_SIZE, NULL, 0);
|
||||
|
||||
LOG_I("Wrote data into %d in partition-index %d.", page, partition);
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit_nwrite:
|
||||
|
||||
/* release memory */
|
||||
if (data_ptr)
|
||||
rt_free(data_ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nmove(int argc, char **argv)
|
||||
{
|
||||
struct rt_mtd_nand_device *device;
|
||||
rt_uint32_t partition, src, dst;
|
||||
|
||||
if (argc != 4)
|
||||
{
|
||||
LOG_E("Usage %s: %s <partition_no> <src page> <dst page>.\n", __func__, __func__);
|
||||
goto exit_nmove;
|
||||
}
|
||||
|
||||
partition = atoi(argv[1]);
|
||||
src = atoi(argv[2]);
|
||||
dst = atoi(argv[3]);
|
||||
|
||||
if (partition >= MTD_SPINAND_PARTITION_NUM)
|
||||
return -1;
|
||||
|
||||
device = &mtd_partitions[partition];
|
||||
|
||||
spinand_move_page(device,
|
||||
src + device->block_start * device->pages_per_block,
|
||||
dst + device->block_start * device->pages_per_block);
|
||||
|
||||
LOG_I("Move data into %d from %d in partition-index %d.", dst, src, partition);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_nmove:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int nerase(int argc, char **argv)
|
||||
{
|
||||
struct rt_mtd_nand_device *device;
|
||||
int partition, block;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
LOG_E("Usage %s: %s <partition_no> <block_no>.\n", __func__, __func__);
|
||||
goto exit_nerase;
|
||||
}
|
||||
|
||||
partition = atoi(argv[1]);
|
||||
block = atoi(argv[2]);
|
||||
|
||||
if (partition >= MTD_SPINAND_PARTITION_NUM)
|
||||
goto exit_nerase;
|
||||
|
||||
device = &mtd_partitions[partition];
|
||||
|
||||
if (spinand_erase_block(device, block + device->block_start) != RT_EOK)
|
||||
goto exit_nerase;
|
||||
|
||||
LOG_I("Erased block %d in partition-index %d.", block + device->block_start, partition);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_nerase:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int nerase_force(int argc, char **argv)
|
||||
{
|
||||
struct rt_mtd_nand_device *device;
|
||||
int partition, block;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
LOG_E("Usage %s: %s <partition_no>\n", __func__, __func__);
|
||||
goto exit_nerase_force;
|
||||
}
|
||||
|
||||
partition = atoi(argv[1]);
|
||||
|
||||
if (partition >= MTD_SPINAND_PARTITION_NUM)
|
||||
goto exit_nerase_force;
|
||||
|
||||
device = &mtd_partitions[partition];
|
||||
|
||||
for (block = 0; block <= device->block_end; block++)
|
||||
{
|
||||
if (spinand_erase_block_force(device, block + device->block_start) != RT_EOK)
|
||||
goto exit_nerase_force;
|
||||
LOG_I("Erased block %d in partition-index %d. forcely", block + device->block_start, partition);
|
||||
}
|
||||
return 0;
|
||||
|
||||
exit_nerase_force:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static rt_err_t nmarkbad(int argc, char **argv)
|
||||
{
|
||||
struct rt_mtd_nand_device *device;
|
||||
int partition, block;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
LOG_E("Usage %s: %s <partition_no> <block_no>.\n", __func__, __func__);
|
||||
goto exit_nmarkbad;
|
||||
}
|
||||
|
||||
partition = atoi(argv[1]);
|
||||
block = atoi(argv[2]);
|
||||
|
||||
if (partition >= MTD_SPINAND_PARTITION_NUM)
|
||||
goto exit_nmarkbad;
|
||||
|
||||
device = &mtd_partitions[partition];
|
||||
|
||||
if (spinand_mark_badblock(device, block + device->block_start) != RT_EOK)
|
||||
goto exit_nmarkbad;
|
||||
|
||||
|
||||
LOG_I("Marked block %d in partition-index %d.", block + device->block_start, partition);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_nmarkbad:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int nerase_all(int argc, char **argv)
|
||||
{
|
||||
rt_uint32_t index;
|
||||
rt_uint32_t partition;
|
||||
struct rt_mtd_nand_device *device;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
LOG_E("Usage %s: %s <partition_no>.\n", __func__, __func__);
|
||||
goto exit_nerase_all;
|
||||
}
|
||||
|
||||
partition = atoi(argv[1]);
|
||||
|
||||
if (partition >= MTD_SPINAND_PARTITION_NUM)
|
||||
goto exit_nerase_all;
|
||||
|
||||
device = &mtd_partitions[partition];
|
||||
|
||||
for (index = 0; index < device->block_total; index ++)
|
||||
{
|
||||
spinand_erase_block(device, index);
|
||||
}
|
||||
|
||||
LOG_I("Erased all block in partition-index %d.", partition);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_nerase_all:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ncheck_all(int argc, char **argv)
|
||||
{
|
||||
rt_uint32_t index;
|
||||
rt_uint32_t partition;
|
||||
struct rt_mtd_nand_device *device;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
LOG_E("Usage %s: %s <partition_no>.\n", __func__, __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
partition = atoi(argv[1]);
|
||||
|
||||
if (partition >= MTD_SPINAND_PARTITION_NUM)
|
||||
return -1;
|
||||
|
||||
device = &mtd_partitions[partition];
|
||||
|
||||
for (index = 0; index < device->block_total; index ++)
|
||||
{
|
||||
LOG_I("Partion:%d Block-%d is %s", partition, index, spinand_check_block(device, index) ? "bad" : "good");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nid(int argc, char **argv)
|
||||
{
|
||||
spinand_read_id(RT_NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nlist(int argc, char **argv)
|
||||
{
|
||||
rt_uint32_t index;
|
||||
struct rt_mtd_nand_device *device;
|
||||
|
||||
rt_kprintf("\n");
|
||||
for (index = 0 ; index < MTD_SPINAND_PARTITION_NUM ; index++)
|
||||
{
|
||||
device = &mtd_partitions[index];
|
||||
rt_kprintf("[Partition #%d]\n", index);
|
||||
rt_kprintf("Name: %s\n", device->parent.parent.name);
|
||||
rt_kprintf("Start block: %d\n", device->block_start);
|
||||
rt_kprintf("End block: %d\n", device->block_end);
|
||||
rt_kprintf("Block number: %d\n", device->block_total);
|
||||
rt_kprintf("Plane number: %d\n", device->plane_num);
|
||||
rt_kprintf("Pages per Block: %d\n", device->pages_per_block);
|
||||
rt_kprintf("Page size: %d bytes\n", device->page_size);
|
||||
rt_kprintf("Spare size: %d bytes\n", device->oob_size);
|
||||
rt_kprintf("Total size: %d bytes (%d KB)\n", device->block_total * device->pages_per_block * device->page_size,
|
||||
device->block_total * device->pages_per_block * device->page_size / 1024);
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
MSH_CMD_EXPORT(nid, nand id);
|
||||
MSH_CMD_EXPORT(nlist, list all partition information on nand);
|
||||
MSH_CMD_EXPORT(nmove, nand copy page);
|
||||
MSH_CMD_EXPORT(nerase, nand erase a block of one partiton);
|
||||
MSH_CMD_EXPORT(nerase_force, nand erase a block of one partiton forcely);
|
||||
MSH_CMD_EXPORT(nerase_all, erase all blocks of a partition);
|
||||
MSH_CMD_EXPORT(ncheck_all, check all blocks of a partition);
|
||||
MSH_CMD_EXPORT(nmarkbad, nand mark bad block of one partition);
|
||||
MSH_CMD_EXPORT(nwrite, nand write page);
|
||||
MSH_CMD_EXPORT(nread, nand read page);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,693 @@
|
|||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-1-13 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(NU_PKG_USING_SPINAND)
|
||||
|
||||
#define LOG_TAG "spinand_flash"
|
||||
#define DBG_ENABLE
|
||||
#define DBG_SECTION_NAME LOG_TAG
|
||||
#define DBG_LEVEL DBG_INFO
|
||||
#define DBG_COLOR
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "spinand.h"
|
||||
|
||||
const struct nu_spinand_info g_spinandflash_list[] =
|
||||
{
|
||||
/* Winbond */
|
||||
{ 0xEFAA21, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "Winbond 128MB: 2048+64@64@1024" }, /* Only tested */
|
||||
|
||||
#if 0
|
||||
{ 0xEFAA22, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "Winbond 256MB: 2048+64@64@1024" },
|
||||
{ 0xEFAB21, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 1, "Winbond 256MB: 2048+64@64@1024, MCP" },
|
||||
|
||||
/* Not test and supporting yet. */
|
||||
/* MXIC */
|
||||
{ 0x00C212, 2048, 64, 0x6b, 0x05, 0x01, 0x40, 0x1, 1024, 64, 0, "MXIC 128MB: 2048+64@64@1024" },
|
||||
|
||||
/* XTX */
|
||||
{ 0x0BE20B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "XTX 256MB: 2048+64@64@2048" },
|
||||
{ 0x0BF20B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "XTX 256MB: 2048+64@64@2048" },
|
||||
{ 0x0BE10B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "XTX 256MB: 2048+64@64@1024" },
|
||||
{ 0x0BF10B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "XTX 256MB: 2048+64@64@1024" },
|
||||
|
||||
/* ATO */
|
||||
{ 0x9B129B, 2048, 64, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "ATO 128MB: 2048+64@64@1024" },
|
||||
|
||||
/* Micro */
|
||||
{ 0x2C242C, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 2048, 64, 0, "Micro 256MB: 2048+128@64@2048" },
|
||||
|
||||
/* GigaDevice */
|
||||
{ 0xB148C8, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "GD 128MB: 2048+128@64@1024" },
|
||||
|
||||
/* Unknown */
|
||||
{ 0x00C8D1, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" },
|
||||
{ 0x00C851, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" },
|
||||
{ 0x98E240, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" }
|
||||
#endif
|
||||
};
|
||||
#define SPINAND_LIST_ELEMENT_NUM ( sizeof(g_spinandflash_list)/sizeof(struct nu_spinand_info) )
|
||||
|
||||
|
||||
/*
|
||||
For 0xEFAA21 description:
|
||||
|
||||
Data Area(2048-Byte)
|
||||
-----------------------------
|
||||
|Sect-0|Sect-1|Sect-2|Sect-3|
|
||||
|(512B)|(512B)|(512B)|(512B)|
|
||||
-----------------------------
|
||||
|
||||
Spare Area(64-Byte)
|
||||
---------------------------------
|
||||
|Spare-0|Spare-1|Spare-2|Spare-3|
|
||||
| (16B) | (16B) | (16B) | (16B) |
|
||||
---------------------------------
|
||||
|
||||
----------------- Spare-0 -------------------
|
||||
/ \
|
||||
-------------------------------------------------
|
||||
| BBM | UD2 | UD1 | ECC Sect-0 | ECC Spare |
|
||||
| 0 1 | 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
|
||||
-------------------------------------------------
|
||||
| NO ECC | ECC PROTECTED | ECC 4-D |
|
||||
|
||||
BBM: Bad block marker.
|
||||
UD1: User Data 1.
|
||||
UD2: User Data 2.
|
||||
ECC Sect-n: ECC for sector-n.
|
||||
ECC Spare: ECC for spare 4-D.
|
||||
|
||||
---------------- Spare-1 -------------------
|
||||
/ \
|
||||
-----------------------------------------------
|
||||
| UD2 | UD1 | ECC Sect-1 | ECC Spare |
|
||||
| 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
|
||||
-----------------------------------------------
|
||||
| NO ECC | ECC PROTECTED | ECC 14-1D |
|
||||
|
||||
---------------- Spare-2 -------------------
|
||||
/ \
|
||||
-----------------------------------------------
|
||||
| UD2 | UD1 | ECC Sect-2 | ECC Spare |
|
||||
| 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
|
||||
-----------------------------------------------
|
||||
| NO ECC | ECC PROTECTED | ECC 24-2D |
|
||||
|
||||
---------------- Spare-3 -------------------
|
||||
/ \
|
||||
-----------------------------------------------
|
||||
| UD2 | UD1 | ECC Sect-3 | ECC Spare |
|
||||
| 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
|
||||
-----------------------------------------------
|
||||
| NO ECC | ECC PROTECTED | ECC 34-3D |
|
||||
*/
|
||||
|
||||
rt_uint8_t spinand_flash_data_layout[SPINAND_SPARE_LAYOUT_SIZE] =
|
||||
{
|
||||
#if defined(RT_USING_DFS_UFFS)
|
||||
/* For storing Seal-byte at 0x37. */
|
||||
0x04, 0x04, 0x14, 0x04, 0x24, 0x04, 0x34, 0x03, 0xFF, 0x00
|
||||
#else
|
||||
0x04, 0x04, 0x14, 0x04, 0x24, 0x04, 0x34, 0x04, 0xFF, 0x00
|
||||
#endif
|
||||
};
|
||||
|
||||
rt_uint8_t spinand_flash_ecc_layout[SPINAND_SPARE_LAYOUT_SIZE] =
|
||||
{
|
||||
#if defined(RT_USING_DFS_UFFS)
|
||||
/* For storing Seal-byte at 0x37 and not report latest ECC part in Spare-3 */
|
||||
0x08, 0x08, 0x18, 0x08, 0x28, 0x08, /*0x38, 0x08,*/ 0xFF, 0x00
|
||||
#else
|
||||
0x08, 0x08, 0x18, 0x08, 0x28, 0x08, 0x38, 0x08, 0xFF, 0x00
|
||||
#endif
|
||||
};
|
||||
|
||||
static rt_err_t spinand_info_read(struct rt_qspi_device *qspi);
|
||||
|
||||
static rt_err_t spinand_die_select(struct rt_qspi_device *qspi, uint8_t select_die)
|
||||
{
|
||||
uint8_t au8Cmd[2] = { 0xC2, 0x0 };
|
||||
au8Cmd[1] = select_die;
|
||||
|
||||
return nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd));
|
||||
}
|
||||
|
||||
static uint8_t spinand_isbusy(struct rt_qspi_device *qspi)
|
||||
{
|
||||
#define BUSY_CKECKING_TIMEOUT_MS 3000
|
||||
volatile uint8_t SR = 0xFF;
|
||||
rt_err_t result;
|
||||
uint8_t au8Cmd[2] = { 0x0F, 0xC0 };
|
||||
|
||||
uint32_t u32CheckingDuration = rt_tick_from_millisecond(BUSY_CKECKING_TIMEOUT_MS);
|
||||
uint32_t u32Start = rt_tick_get();
|
||||
|
||||
do
|
||||
{
|
||||
result = nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), (void *)&SR, 1);
|
||||
if (result != RT_EOK)
|
||||
goto timeout_spinand_isbusy;
|
||||
|
||||
if ((rt_tick_get() - u32Start) >= u32CheckingDuration)
|
||||
{
|
||||
goto timeout_spinand_isbusy;
|
||||
}
|
||||
|
||||
}
|
||||
while ((SR & 0x1) != 0x00);
|
||||
|
||||
return 0;
|
||||
|
||||
timeout_spinand_isbusy:
|
||||
|
||||
LOG_E("Error: spinand timeout.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_program_dataload(
|
||||
struct rt_qspi_device *qspi,
|
||||
uint8_t u8AddrH,
|
||||
uint8_t u8AddrL,
|
||||
uint8_t *pu8DataBuff,
|
||||
uint32_t u32DataCount,
|
||||
uint8_t *pu8SpareBuff,
|
||||
uint32_t u32SpareCount)
|
||||
{
|
||||
uint32_t volatile i = 0;
|
||||
uint8_t u8WECmd = 0x06;
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
struct rt_qspi_message qspi_messages[2] = {0};
|
||||
|
||||
/* 1-bit mode */
|
||||
qspi_messages[0].instruction.content = 0x32;
|
||||
qspi_messages[0].instruction.qspi_lines = 1;
|
||||
|
||||
qspi_messages[0].address.content = (u8AddrH << 8) | (u8AddrL);
|
||||
qspi_messages[0].address.size = 2 * 8;
|
||||
qspi_messages[0].address.qspi_lines = 1;
|
||||
|
||||
/* 4-bit mode */
|
||||
qspi_messages[0].qspi_data_lines = 4;
|
||||
qspi_messages[0].parent.cs_take = 1;
|
||||
qspi_messages[0].parent.cs_release = 0;
|
||||
qspi_messages[0].parent.send_buf = pu8DataBuff;
|
||||
qspi_messages[0].parent.length = u32DataCount;
|
||||
qspi_messages[0].parent.next = &qspi_messages[1].parent;
|
||||
|
||||
qspi_messages[1].qspi_data_lines = 4;
|
||||
qspi_messages[1].parent.cs_take = 0;
|
||||
qspi_messages[1].parent.cs_release = 1;
|
||||
qspi_messages[1].parent.send_buf = pu8SpareBuff;
|
||||
qspi_messages[1].parent.length = u32SpareCount;
|
||||
|
||||
if ((result = nu_qspi_send(qspi, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
|
||||
goto exit_spinand_program_dataload;
|
||||
|
||||
result = nu_qspi_transfer_message(qspi, (struct rt_qspi_message *)&qspi_messages[0]);
|
||||
|
||||
exit_spinand_program_dataload:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t spinand_status_register_read(struct rt_qspi_device *qspi, uint8_t u8SRSel)
|
||||
{
|
||||
uint8_t u8SR = 0;
|
||||
uint8_t au8Cmd[2];
|
||||
|
||||
switch (u8SRSel)
|
||||
{
|
||||
case 0x01:
|
||||
au8Cmd[0] = 0x05;
|
||||
au8Cmd[1] = 0xA0;
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
au8Cmd[0] = 0x0F;
|
||||
au8Cmd[1] = 0xB0;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
au8Cmd[0] = 0x05;
|
||||
au8Cmd[1] = 0xC0;
|
||||
break;
|
||||
|
||||
default:
|
||||
RT_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), &u8SR, 1) != RT_EOK)
|
||||
RT_ASSERT(0);
|
||||
|
||||
return u8SR;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_status_register_write(struct rt_qspi_device *qspi, uint8_t u8SRSel, uint8_t u8Value)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
uint8_t au8Cmd[3];
|
||||
|
||||
switch (u8SRSel)
|
||||
{
|
||||
case 0x01:
|
||||
au8Cmd[0] = 0x01;
|
||||
au8Cmd[1] = 0xA0;
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
au8Cmd[0] = 0x01;
|
||||
au8Cmd[1] = 0xB0;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
au8Cmd[0] = 0x01;
|
||||
au8Cmd[1] = 0xC0;
|
||||
break;
|
||||
|
||||
default:
|
||||
result = RT_EINVAL;
|
||||
goto exit_spinand_status_register_write;
|
||||
}
|
||||
|
||||
au8Cmd[2] = u8Value;
|
||||
|
||||
if ((result = nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd))) != RT_EOK)
|
||||
goto exit_spinand_status_register_write;
|
||||
|
||||
if (spinand_isbusy(qspi))
|
||||
{
|
||||
result = RT_EIO;
|
||||
goto exit_spinand_status_register_write;
|
||||
}
|
||||
|
||||
exit_spinand_status_register_write:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_program_execute(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
|
||||
{
|
||||
rt_err_t result;
|
||||
uint8_t au8Cmd[4], u8SR;
|
||||
|
||||
au8Cmd[0] = 0x10 ;
|
||||
au8Cmd[1] = u8Addr2;
|
||||
au8Cmd[2] = u8Addr1;
|
||||
au8Cmd[3] = u8Addr0;
|
||||
|
||||
if ((result = nu_qspi_send(qspi, &au8Cmd, sizeof(au8Cmd))) != RT_EOK)
|
||||
goto exit_spinand_program_execute;
|
||||
|
||||
if (spinand_isbusy(qspi))
|
||||
{
|
||||
result = -RT_MTD_EIO;
|
||||
goto exit_spinand_program_execute;
|
||||
}
|
||||
|
||||
u8SR = (spinand_status_register_read(SPINAND_FLASH_QSPI, 3) & 0x0C) >> 2;
|
||||
if (u8SR == 1)
|
||||
{
|
||||
result = -RT_MTD_EIO;
|
||||
LOG_E("Error write status!");
|
||||
}
|
||||
|
||||
exit_spinand_program_execute:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_normal_read(struct rt_qspi_device *qspi, uint8_t u8AddrH, uint8_t u8AddrL, uint8_t *pu8Buff, uint32_t u32Count)
|
||||
{
|
||||
uint8_t au8Cmd[4];
|
||||
|
||||
au8Cmd[0] = 0x03;
|
||||
au8Cmd[1] = u8AddrH;
|
||||
au8Cmd[2] = u8AddrL;
|
||||
au8Cmd[3] = 0x00;
|
||||
|
||||
return nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), pu8Buff, u32Count);
|
||||
}
|
||||
|
||||
static rt_err_t spinand_protect_set(struct rt_qspi_device *qspi, uint8_t u8Protect)
|
||||
{
|
||||
/* Read status register 1 */
|
||||
uint8_t u8SR = spinand_status_register_read(qspi, 1);
|
||||
|
||||
if (u8Protect)
|
||||
{
|
||||
/* protect */
|
||||
u8SR |= 0x7C;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unprotect */
|
||||
u8SR &= 0x83;
|
||||
}
|
||||
|
||||
return spinand_status_register_write(qspi, 1, u8SR);
|
||||
}
|
||||
|
||||
static uint8_t spinand_program_erase_isfail(struct rt_qspi_device *qspi)
|
||||
{
|
||||
/* Read status register 3 */
|
||||
uint8_t u8SR = spinand_status_register_read(qspi, 3);
|
||||
return (u8SR & 0x0C) >> 2; /* Check P-Fail, E-Fail bit */
|
||||
}
|
||||
|
||||
static uint8_t spinand_hwecc_status_get(struct rt_qspi_device *qspi)
|
||||
{
|
||||
/* Read status register 3 */
|
||||
uint8_t u8SR = spinand_status_register_read(qspi, 3);
|
||||
return (u8SR & 0x30) >> 4; /* ECC-1, ECC0 bit */
|
||||
}
|
||||
|
||||
static rt_err_t spinand_hwecc_set(struct rt_qspi_device *qspi, uint8_t u8Enable)
|
||||
{
|
||||
uint8_t u8SR = spinand_status_register_read(qspi, 2); // Read status register 2
|
||||
|
||||
if (u8Enable)
|
||||
{
|
||||
u8SR |= 0x10; // Enable ECC-E bit
|
||||
}
|
||||
else
|
||||
{
|
||||
u8SR &= 0xEF; // Disable ECC-E bit
|
||||
}
|
||||
|
||||
return spinand_status_register_write(qspi, 2, u8SR);
|
||||
}
|
||||
|
||||
static uint8_t spinand_hwecc_get(struct rt_qspi_device *qspi)
|
||||
{
|
||||
/* Read status register 2 */
|
||||
uint8_t u8SR = spinand_status_register_read(qspi, 2);
|
||||
return (u8SR & 0x10) >> 4;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_read_dataload(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
uint8_t au8Cmd[4];
|
||||
uint8_t u8SR;
|
||||
|
||||
au8Cmd[0] = 0x13 ;
|
||||
au8Cmd[1] = u8Addr2;
|
||||
au8Cmd[2] = u8Addr1;
|
||||
au8Cmd[3] = u8Addr0;
|
||||
|
||||
if ((result = nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd))) != RT_EOK)
|
||||
goto exit_spinand_read_dataload;
|
||||
|
||||
if (spinand_isbusy(qspi))
|
||||
{
|
||||
result = -RT_EIO;
|
||||
goto exit_spinand_read_dataload;
|
||||
}
|
||||
|
||||
u8SR = spinand_hwecc_status_get(SPINAND_FLASH_QSPI);
|
||||
if ((u8SR != 0x00) && (u8SR != 0x01))
|
||||
{
|
||||
result = -RT_MTD_EECC;
|
||||
LOG_E("Error ECC status error[0x%x].", u8SR);
|
||||
}
|
||||
|
||||
exit_spinand_read_dataload:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t spinand_block_isbad(struct rt_qspi_device *qspi, uint32_t u32PageAddr)
|
||||
{
|
||||
rt_err_t result;
|
||||
uint8_t read_buf;
|
||||
|
||||
again_spinand_block_isbad:
|
||||
|
||||
result = spinand_read_dataload(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF); // Read the first page of a block
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
result = spinand_normal_read(qspi, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, &read_buf, 1); // Read bad block mark at 0x800 update at v.1.0.8
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
if (read_buf != 0xFF)
|
||||
{
|
||||
// update at v.1.0.7
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (((u32PageAddr % (SPINAND_FLASH_PAGE_PER_BLOCK_NUM * SPINAND_FLASH_PAGE_SIZE)) == 0))
|
||||
{
|
||||
/* Need check second page again. */
|
||||
u32PageAddr++;
|
||||
goto again_spinand_block_isbad;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_buffermode_set(struct rt_qspi_device *qspi, uint8_t u8Enable)
|
||||
{
|
||||
uint8_t u8SR = spinand_status_register_read(qspi, 2); // Read status register 2
|
||||
|
||||
if (u8Enable)
|
||||
{
|
||||
u8SR |= 0x08; // Enable BUF bit
|
||||
}
|
||||
else
|
||||
{
|
||||
u8SR &= 0xF7; // Disable BUF bit
|
||||
}
|
||||
return spinand_status_register_write(qspi, 2, u8SR);
|
||||
}
|
||||
|
||||
static rt_err_t spinand_block_erase(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
|
||||
{
|
||||
rt_err_t result;
|
||||
uint8_t u8WECmd = 0x06;
|
||||
uint8_t au8EraseCmd[4], u8SR;
|
||||
|
||||
au8EraseCmd[0] = 0xD8;
|
||||
au8EraseCmd[1] = u8Addr2;
|
||||
au8EraseCmd[2] = u8Addr1;
|
||||
au8EraseCmd[3] = u8Addr0;
|
||||
|
||||
if ((result = nu_qspi_send(qspi, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
|
||||
goto exit_spinand_block_erase;
|
||||
|
||||
if ((result = nu_qspi_send(qspi, &au8EraseCmd[0], sizeof(au8EraseCmd))) != RT_EOK)
|
||||
goto exit_spinand_block_erase;
|
||||
|
||||
if (spinand_isbusy(qspi))
|
||||
return -RT_EIO;
|
||||
|
||||
u8SR = spinand_program_erase_isfail(SPINAND_FLASH_QSPI);
|
||||
if (u8SR != 0)
|
||||
{
|
||||
/* Fail to erase */
|
||||
LOG_E("Fail to erase. Will mark it bad.");
|
||||
result = -RT_ERROR;
|
||||
goto exit_spinand_block_erase;
|
||||
}
|
||||
|
||||
exit_spinand_block_erase:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_block_markbad(struct rt_qspi_device *qspi, uint32_t u32PageAddr)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
uint8_t u8BadBlockMarker = 0xF0;
|
||||
|
||||
result = spinand_block_erase(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF);
|
||||
if (result != RT_EOK)
|
||||
return result;
|
||||
|
||||
result = spinand_program_dataload(qspi, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, &u8BadBlockMarker, 1, 0, 0);
|
||||
if (result != RT_EOK)
|
||||
return result;
|
||||
|
||||
return spinand_program_execute(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF);
|
||||
}
|
||||
|
||||
static rt_err_t spinand_read_quadoutput(
|
||||
struct rt_qspi_device *qspi,
|
||||
uint8_t u8AddrH,
|
||||
uint8_t u8AddrL,
|
||||
uint8_t *pu8DataBuff,
|
||||
uint32_t u32DataCount
|
||||
)
|
||||
{
|
||||
struct rt_qspi_message qspi_messages = {0};
|
||||
|
||||
/* 1-bit mode */
|
||||
qspi_messages.instruction.content = SPINAND_FLASH_QUADREAD_CMDID;
|
||||
qspi_messages.instruction.qspi_lines = 1;
|
||||
|
||||
qspi_messages.address.content = (u8AddrH << 8) | (u8AddrL);
|
||||
qspi_messages.address.size = 2 * 8;
|
||||
qspi_messages.address.qspi_lines = 1;
|
||||
|
||||
qspi_messages.dummy_cycles = SPINAND_FLASH_DUMMYBYTE * 8; //In bit
|
||||
|
||||
/* 4-bit mode */
|
||||
qspi_messages.qspi_data_lines = 4;
|
||||
qspi_messages.parent.cs_take = 1;
|
||||
qspi_messages.parent.cs_release = 1;
|
||||
qspi_messages.parent.recv_buf = pu8DataBuff;
|
||||
qspi_messages.parent.length = u32DataCount;
|
||||
qspi_messages.parent.next = RT_NULL;
|
||||
|
||||
return nu_qspi_transfer_message(qspi, (struct rt_qspi_message *) &qspi_messages);
|
||||
}
|
||||
|
||||
static rt_err_t spinand_jedecid_get(struct rt_qspi_device *qspi, uint32_t *pu32ID)
|
||||
{
|
||||
uint32_t u32JedecId = 0;
|
||||
uint32_t u32JedecId_real = 0;
|
||||
uint8_t u8Cmd = 0x9F;
|
||||
|
||||
if (nu_qspi_send_then_recv(qspi, &u8Cmd, 1, &u32JedecId, 4) != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* Reverse order. */
|
||||
nu_set32_be((uint8_t *)&u32JedecId_real, u32JedecId);
|
||||
|
||||
/* Only keep 3-bytes. */
|
||||
u32JedecId_real &= 0x00ffffff;
|
||||
|
||||
*pu32ID = u32JedecId_real;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t spinand_reset(struct rt_qspi_device *qspi)
|
||||
{
|
||||
rt_err_t result;
|
||||
uint8_t u8Cmd = 0xFF;
|
||||
|
||||
if ((result = nu_qspi_send(qspi, &u8Cmd, 1)) != RT_EOK)
|
||||
goto exit_spinand_reset;
|
||||
|
||||
if (spinand_isbusy(qspi))
|
||||
{
|
||||
result = RT_EIO;
|
||||
goto exit_spinand_reset;
|
||||
}
|
||||
|
||||
exit_spinand_reset:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t spinand_flash_init(struct rt_qspi_device *qspi)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
if ((result = spinand_reset(qspi)) != RT_EOK)
|
||||
goto exit_spinand_init;
|
||||
|
||||
if ((result = spinand_info_read(qspi)) != RT_EOK)
|
||||
goto exit_spinand_init;
|
||||
|
||||
/* Un-protect */
|
||||
if ((result = spinand_protect_set(qspi, 0)) != RT_EOK)
|
||||
goto exit_spinand_init;
|
||||
|
||||
/* Enable BUF mode */
|
||||
if ((result = spinand_buffermode_set(qspi, 1)) != RT_EOK)
|
||||
goto exit_spinand_init;
|
||||
|
||||
/* Enable HWECC */
|
||||
if ((result = spinand_hwecc_set(qspi, 1)) != RT_EOK)
|
||||
goto exit_spinand_init;
|
||||
|
||||
/* Check HWECC */
|
||||
if (!(spinand_hwecc_get(qspi)))
|
||||
goto exit_spinand_init;
|
||||
|
||||
if (SPINAND_FLASH_MCP == 1)
|
||||
{
|
||||
/* Select die. */
|
||||
if ((result = spinand_die_select(qspi, SPINAND_DIE_ID1)) != RT_EOK)
|
||||
goto exit_spinand_init;
|
||||
|
||||
/* Unprotect */
|
||||
if ((result = spinand_protect_set(qspi, 0)) != RT_EOK)
|
||||
goto exit_spinand_init;
|
||||
}
|
||||
|
||||
LOG_I("Enabled BUF, HWECC. Unprotected.");
|
||||
|
||||
exit_spinand_init:
|
||||
|
||||
return -result;
|
||||
}
|
||||
|
||||
struct spinand_ops spinand_ops_wb =
|
||||
{
|
||||
.block_erase = spinand_block_erase,
|
||||
.block_isbad = spinand_block_isbad,
|
||||
.block_markbad = spinand_block_markbad,
|
||||
.die_select = spinand_die_select,
|
||||
.jedecid_get = spinand_jedecid_get,
|
||||
.program_dataload = spinand_program_dataload,
|
||||
.program_execute = spinand_program_execute,
|
||||
.read_dataload = spinand_read_dataload,
|
||||
.read_quadoutput = spinand_read_quadoutput
|
||||
};
|
||||
|
||||
static rt_err_t spinand_info_read(struct rt_qspi_device *qspi)
|
||||
{
|
||||
int i;
|
||||
uint32_t u32JedecId = 0;
|
||||
|
||||
if (spinand_jedecid_get(qspi, &u32JedecId) != RT_EOK)
|
||||
goto exit_spinand_info_read;
|
||||
|
||||
for (i = 0 ; i < SPINAND_LIST_ELEMENT_NUM; i++)
|
||||
{
|
||||
if (u32JedecId == g_spinandflash_list[i].u32JEDECID) /* Match JEDECID? */
|
||||
{
|
||||
rt_memcpy(SPINAND_FLASH_INFO, &g_spinandflash_list[i], sizeof(struct nu_spinand_info));
|
||||
LOG_I("Found: [%08X] %s.", u32JedecId, SPINAND_FLASH_DESCRIPTION);
|
||||
|
||||
switch (u32JedecId & 0xff0000)
|
||||
{
|
||||
case 0xEF0000: /* Winbond */
|
||||
SPINAND_FLASH_OPS = &spinand_ops_wb;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto exit_spinand_info_read;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
}
|
||||
|
||||
exit_spinand_info_read:
|
||||
|
||||
LOG_E("Can't find the flash[%08X] in supported list.", u32JedecId);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,95 @@
|
|||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-1-13 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __SPINAND_H__
|
||||
#define __SPINAND_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <drivers/mtd_nand.h>
|
||||
#include "drv_spi.h"
|
||||
#include <board.h>
|
||||
|
||||
/* SPI NAND flash information */
|
||||
struct nu_spinand_info
|
||||
{
|
||||
uint32_t u32JEDECID;
|
||||
uint16_t u16PageSize;
|
||||
uint16_t u16OOBSize;
|
||||
uint8_t u8QuadReadCmdId;
|
||||
uint8_t u8ReadStatusCmdId;
|
||||
uint8_t u8WriteStatusCmdid;
|
||||
uint8_t u8StatusValue;
|
||||
uint8_t u8DummyByte;
|
||||
uint32_t u32BlockPerFlash;
|
||||
uint32_t u32PagePerBlock;
|
||||
uint8_t u8IsDieSelect;
|
||||
const char *szDescription;
|
||||
};
|
||||
typedef struct nu_spinand_info *nu_spinand_info_t;
|
||||
|
||||
struct spinand_ops
|
||||
{
|
||||
rt_err_t (*block_erase)(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0);
|
||||
uint8_t (*block_isbad)(struct rt_qspi_device *qspi, uint32_t u32PageAddr);
|
||||
rt_err_t (*block_markbad)(struct rt_qspi_device *qspi, uint32_t u32PageAddr);
|
||||
rt_err_t (*die_select)(struct rt_qspi_device *qspi, uint8_t select_die);
|
||||
rt_err_t (*jedecid_get)(struct rt_qspi_device *qspi, uint32_t *pu32ID);
|
||||
rt_err_t (*program_dataload)(struct rt_qspi_device *qspi, uint8_t u8AddrH, uint8_t u8AddrL, uint8_t *pu8DataBuff,
|
||||
uint32_t u32DataCount, uint8_t *pu8SpareBuff, uint32_t u32SpareCount);
|
||||
|
||||
rt_err_t (*program_execute)(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0);
|
||||
rt_err_t (*read_dataload)(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0);
|
||||
rt_err_t (*read_quadoutput)(struct rt_qspi_device *qspi, uint8_t u8AddrH, uint8_t u8AddrL, uint8_t *pu8DataBuff, uint32_t u32DataCount);
|
||||
};
|
||||
typedef struct spinand_ops *nu_spinand_ops_t;
|
||||
|
||||
struct nu_spinand
|
||||
{
|
||||
struct nu_spinand_info info;
|
||||
struct rt_qspi_device *qspi_device;
|
||||
nu_spinand_ops_t ops;
|
||||
struct rt_mutex lock;
|
||||
};
|
||||
typedef struct nu_spinand *nu_spinand_t;
|
||||
|
||||
#define SPINAND_FLASH_JEDECID g_spinandflash_dev.info.u32JEDECID
|
||||
#define SPINAND_FLASH_PAGE_SIZE g_spinandflash_dev.info.u16PageSize
|
||||
#define SPINAND_FLASH_OOB_SIZE g_spinandflash_dev.info.u16OOBSize
|
||||
#define SPINAND_FLASH_QUADREAD_CMDID g_spinandflash_dev.info.u8QuadReadCmdId
|
||||
#define SPINAND_FLASH_DUMMYBYTE g_spinandflash_dev.info.u8DummyByte
|
||||
#define SPINAND_FLASH_BLOCK_NUM g_spinandflash_dev.info.u32BlockPerFlash
|
||||
#define SPINAND_FLASH_PAGE_PER_BLOCK_NUM g_spinandflash_dev.info.u32PagePerBlock
|
||||
#define SPINAND_FLASH_DESCRIPTION g_spinandflash_dev.info.szDescription
|
||||
#define SPINAND_FLASH_MCP g_spinandflash_dev.info.u8IsDieSelect
|
||||
|
||||
#define SPINAND_FLASH_INFO &g_spinandflash_dev.info
|
||||
#define SPINAND_FLASH_QSPI g_spinandflash_dev.qspi_device
|
||||
#define SPINAND_FLASH_LOCK &g_spinandflash_dev.lock
|
||||
#define SPINAND_FLASH_OPS g_spinandflash_dev.ops
|
||||
|
||||
#define SPINAND_DIE_ID0 (0)
|
||||
#define SPINAND_DIE_ID1 (1)
|
||||
|
||||
#define SPINAND_SPARE_LAYOUT_SIZE 16
|
||||
|
||||
rt_err_t rt_hw_mtd_spinand_register(const char *device_name);
|
||||
rt_size_t nu_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message);
|
||||
rt_err_t nu_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length);
|
||||
rt_err_t nu_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length);
|
||||
rt_err_t spinand_flash_init(struct rt_qspi_device *qspi);
|
||||
|
||||
extern struct nu_spinand g_spinandflash_dev;
|
||||
extern rt_uint8_t spinand_flash_data_layout[SPINAND_SPARE_LAYOUT_SIZE];
|
||||
extern rt_uint8_t spinand_flash_ecc_layout[SPINAND_SPARE_LAYOUT_SIZE];
|
||||
|
||||
#endif /* __SPINAND_H__ */
|
|
@ -46,45 +46,45 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t CREQ; /*!< [0x0020] IFn Command Request Register */
|
||||
uint32_t CMASK; /*!< [0x0024] IFn Command Mask Register */
|
||||
uint32_t MASK1; /*!< [0x0028] IFn Mask 1 Register */
|
||||
uint32_t MASK2; /*!< [0x002c] IFn Mask 2 Register */
|
||||
uint32_t ARB1; /*!< [0x0030] IFn Arbitration 1 Register */
|
||||
uint32_t ARB2; /*!< [0x0034] IFn Arbitration 2 Register */
|
||||
uint32_t MCON; /*!< [0x0038] IFn Message Control Register */
|
||||
uint32_t DAT_A1; /*!< [0x003c] IFn Data A1 Register */
|
||||
uint32_t DAT_A2; /*!< [0x0040] IFn Data A2 Register */
|
||||
uint32_t DAT_B1; /*!< [0x0044] IFn Data B1 Register */
|
||||
uint32_t DAT_B2; /*!< [0x0048] IFn Data B2 Register */
|
||||
uint32_t RESERVE0[13];
|
||||
__IO uint32_t CREQ; /*!< [0x0020] IFn Command Request Register */
|
||||
__IO uint32_t CMASK; /*!< [0x0024] IFn Command Mask Register */
|
||||
__IO uint32_t MASK1; /*!< [0x0028] IFn Mask 1 Register */
|
||||
__IO uint32_t MASK2; /*!< [0x002c] IFn Mask 2 Register */
|
||||
__IO uint32_t ARB1; /*!< [0x0030] IFn Arbitration 1 Register */
|
||||
__IO uint32_t ARB2; /*!< [0x0034] IFn Arbitration 2 Register */
|
||||
__IO uint32_t MCON; /*!< [0x0038] IFn Message Control Register */
|
||||
__IO uint32_t DAT_A1; /*!< [0x003c] IFn Data A1 Register */
|
||||
__IO uint32_t DAT_A2; /*!< [0x0040] IFn Data A2 Register */
|
||||
__IO uint32_t DAT_B1; /*!< [0x0044] IFn Data B1 Register */
|
||||
__IO uint32_t DAT_B2; /*!< [0x0048] IFn Data B2 Register */
|
||||
__I uint32_t RESERVE0[13];
|
||||
} CAN_IF_T;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t CON; /*!< [0x0000] Control Register */
|
||||
uint32_t STATUS; /*!< [0x0004] Status Register */
|
||||
uint32_t ERR; /*!< [0x0008] Error Counter Register */
|
||||
uint32_t BTIME; /*!< [0x000c] Bit Timing Register */
|
||||
uint32_t IIDR; /*!< [0x0010] Interrupt Identifier Register */
|
||||
uint32_t TEST; /*!< [0x0014] Test Register */
|
||||
uint32_t BRPE; /*!< [0x0018] Baud Rate Prescaler Extension Register */
|
||||
uint32_t RESERVE0[1];
|
||||
CAN_IF_T IF[2];
|
||||
uint32_t RESERVE2[8];
|
||||
uint32_t TXREQ1; /*!< [0x0100] Transmission Request Register 1 */
|
||||
uint32_t TXREQ2; /*!< [0x0104] Transmission Request Register 2 */
|
||||
uint32_t RESERVE3[6];
|
||||
uint32_t NDAT1; /*!< [0x0120] New Data Register 1 */
|
||||
uint32_t NDAT2; /*!< [0x0124] New Data Register 2 */
|
||||
uint32_t RESERVE4[6];
|
||||
uint32_t IPND1; /*!< [0x0140] Interrupt Pending Register 1 */
|
||||
uint32_t IPND2; /*!< [0x0144] Interrupt Pending Register 2 */
|
||||
uint32_t RESERVE5[6];
|
||||
uint32_t MVLD1; /*!< [0x0160] Message Valid Register 1 */
|
||||
uint32_t MVLD2; /*!< [0x0164] Message Valid Register 2 */
|
||||
uint32_t WU_EN; /*!< [0x0168] Wake-up Enable Control Register */
|
||||
uint32_t WU_STATUS; /*!< [0x016c] Wake-up Status Register */
|
||||
__IO uint32_t CON; /*!< [0x0000] Control Register */
|
||||
__IO uint32_t STATUS; /*!< [0x0004] Status Register */
|
||||
__I uint32_t ERR; /*!< [0x0008] Error Counter Register */
|
||||
__IO uint32_t BTIME; /*!< [0x000c] Bit Timing Register */
|
||||
__I uint32_t IIDR; /*!< [0x0010] Interrupt Identifier Register */
|
||||
__IO uint32_t TEST; /*!< [0x0014] Test Register */
|
||||
__IO uint32_t BRPE; /*!< [0x0018] Baud Rate Prescaler Extension Register */
|
||||
__I uint32_t RESERVE0[1];
|
||||
__IO CAN_IF_T IF[2];
|
||||
__I uint32_t RESERVE2[8];
|
||||
__I uint32_t TXREQ1; /*!< [0x0100] Transmission Request Register 1 */
|
||||
__I uint32_t TXREQ2; /*!< [0x0104] Transmission Request Register 2 */
|
||||
__I uint32_t RESERVE3[6];
|
||||
__I uint32_t NDAT1; /*!< [0x0120] New Data Register 1 */
|
||||
__I uint32_t NDAT2; /*!< [0x0124] New Data Register 2 */
|
||||
__I uint32_t RESERVE4[6];
|
||||
__I uint32_t IPND1; /*!< [0x0140] Interrupt Pending Register 1 */
|
||||
__I uint32_t IPND2; /*!< [0x0144] Interrupt Pending Register 2 */
|
||||
__I uint32_t RESERVE5[6];
|
||||
__I uint32_t MVLD1; /*!< [0x0160] Message Valid Register 1 */
|
||||
__I uint32_t MVLD2; /*!< [0x0164] Message Valid Register 2 */
|
||||
__IO uint32_t WU_EN; /*!< [0x0168] Wake-up Enable Control Register */
|
||||
__IO uint32_t WU_STATUS; /*!< [0x016c] Wake-up Status Register */
|
||||
|
||||
} CAN_T;
|
||||
|
||||
|
|
|
@ -647,6 +647,42 @@ static __inline void ETIMER_ClearCaptureIntFlag(UINT timer)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function gets the Timer capture falling edge flag.
|
||||
* @param[in] timer ETIMER number. Range from 0 ~ 5
|
||||
* @return None
|
||||
*/
|
||||
static __inline UINT8 ETIMER_GetCaptureFallingEdgeFlag(UINT timer)
|
||||
{
|
||||
UINT ret;
|
||||
|
||||
if (timer == 0)
|
||||
{
|
||||
ret = inpw(REG_ETMR0_ISR);
|
||||
}
|
||||
else if (timer == 1)
|
||||
{
|
||||
ret = inpw(REG_ETMR1_ISR);
|
||||
}
|
||||
else if (timer == 2)
|
||||
{
|
||||
ret = inpw(REG_ETMR2_ISR);
|
||||
}
|
||||
else if (timer == 3)
|
||||
{
|
||||
ret = inpw(REG_ETMR3_ISR);
|
||||
}
|
||||
else if (timer == 4)
|
||||
{
|
||||
ret = inpw(REG_ETMR4_ISR);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = inpw(REG_ETMR5_ISR);
|
||||
}
|
||||
return (ret & (1 << 6)) >> 6;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function indicates Timer has waked up system or not.
|
||||
* @param[in] timer ETIMER number. Range from 0 ~ 5
|
||||
|
|
|
@ -110,23 +110,23 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t INIT; /*!< [0x0000] RTC Initiation Register */
|
||||
uint32_t RWEN; /*!< [0x0004] RTC Access Enable Register */
|
||||
uint32_t FREQADJ; /*!< [0x0008] RTC Frequency Compensation Register */
|
||||
uint32_t TIME; /*!< [0x000c] RTC Time Loading Register */
|
||||
uint32_t CAL; /*!< [0x0010] RTC Calendar Loading Register */
|
||||
uint32_t CLKFMT; /*!< [0x0014] RTC Time Scale Selection Register */
|
||||
uint32_t WEEKDAY; /*!< [0x0018] RTC Day of the Week Register */
|
||||
uint32_t TALM; /*!< [0x001c] RTC Time Alarm Register */
|
||||
uint32_t CALM; /*!< [0x0020] RTC Calendar Alarm Register */
|
||||
uint32_t LEAPYEAR; /*!< [0x0024] RTC Leap Year Indicator Register */
|
||||
uint32_t INTEN; /*!< [0x0028] RTC Interrupt Enable Register */
|
||||
uint32_t INTSTS; /*!< [0x002c] RTC Interrupt Status Register */
|
||||
uint32_t TICK; /*!< [0x0030] RTC Time Tick Register */
|
||||
uint32_t PWRCTL; /*!< [0x0034] RTC Power Control Register */
|
||||
uint32_t PWRCNT; /*!< [0x0038] RTC Power Control Counter Register */
|
||||
uint32_t RESERVE0; /*!< [0x003c] RTC Spare Functional Control Register */
|
||||
uint32_t SPR[16]; /*!< [0x0040] ~ [0x007c] RTC Spare Register 0 ~ 15 */
|
||||
__IO uint32_t INIT; /*!< [0x0000] RTC Initiation Register */
|
||||
__IO uint32_t RWEN; /*!< [0x0004] RTC Access Enable Register */
|
||||
__IO uint32_t FREQADJ; /*!< [0x0008] RTC Frequency Compensation Register */
|
||||
__IO uint32_t TIME; /*!< [0x000c] RTC Time Loading Register */
|
||||
__IO uint32_t CAL; /*!< [0x0010] RTC Calendar Loading Register */
|
||||
__IO uint32_t CLKFMT; /*!< [0x0014] RTC Time Scale Selection Register */
|
||||
__IO uint32_t WEEKDAY; /*!< [0x0018] RTC Day of the Week Register */
|
||||
__IO uint32_t TALM; /*!< [0x001c] RTC Time Alarm Register */
|
||||
__IO uint32_t CALM; /*!< [0x0020] RTC Calendar Alarm Register */
|
||||
__I uint32_t LEAPYEAR; /*!< [0x0024] RTC Leap Year Indicator Register */
|
||||
__IO uint32_t INTEN; /*!< [0x0028] RTC Interrupt Enable Register */
|
||||
__IO uint32_t INTSTS; /*!< [0x002c] RTC Interrupt Status Register */
|
||||
__IO uint32_t TICK; /*!< [0x0030] RTC Time Tick Register */
|
||||
__IO uint32_t PWRCTL; /*!< [0x0034] RTC Power Control Register */
|
||||
__IO uint32_t PWRCNT; /*!< [0x0038] RTC Power Control Counter Register */
|
||||
__IO uint32_t RESERVE0; /*!< [0x003c] RTC Spare Functional Control Register */
|
||||
__I uint32_t SPR[16]; /*!< [0x0040] ~ [0x007c] RTC Spare Register 0 ~ 15 */
|
||||
} RTC_T;
|
||||
|
||||
#define RTC_INIT_ACTIVE_Pos (0) /*!< RTC_T::INIT: INIT_ACTIVE Position */
|
||||
|
|
|
@ -116,25 +116,25 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t DAT; /*!< [0x0000] UART Receive/Transmit Buffer Register */
|
||||
uint32_t INTEN; /*!< [0x0004] UART Interrupt Enable Register */
|
||||
uint32_t FIFO; /*!< [0x0008] UART FIFO Control Register */
|
||||
uint32_t LINE; /*!< [0x000c] UART Line Control Register */
|
||||
uint32_t MODEM; /*!< [0x0010] UART Modem Control Register */
|
||||
uint32_t MODEMSTS; /*!< [0x0014] UART Modem Status Register */
|
||||
uint32_t FIFOSTS; /*!< [0x0018] UART FIFO Status Register */
|
||||
uint32_t INTSTS; /*!< [0x001c] UART Interrupt Status Register */
|
||||
uint32_t TOUT; /*!< [0x0020] UART Time-out Register */
|
||||
uint32_t BAUD; /*!< [0x0024] UART Baud Rate Divider Register */
|
||||
uint32_t IRDA; /*!< [0x0028] UART IrDA Control Register */
|
||||
uint32_t ALTCTL; /*!< [0x002c] UART Alternate Control/Status Register */
|
||||
uint32_t FUNCSEL; /*!< [0x0030] UART Function Select Register */
|
||||
uint32_t LINCTL; /*!< [0x0034] UART LIN Control Register */
|
||||
uint32_t LINSTS; /*!< [0x0038] UART LIN Status Register */
|
||||
uint32_t BRCOMP; /*!< [0x003c] UART Baud Rate Compensation Register */
|
||||
uint32_t WKCTL; /*!< [0x0040] UART Wake-up Control Register */
|
||||
uint32_t WKSTS; /*!< [0x0044] UART Wake-up Status Register */
|
||||
uint32_t DWKCOMP; /*!< [0x0048] UART Incoming Data Wake-up Compensation Register */
|
||||
__IO uint32_t DAT; /*!< [0x0000] UART Receive/Transmit Buffer Register */
|
||||
__IO uint32_t INTEN; /*!< [0x0004] UART Interrupt Enable Register */
|
||||
__IO uint32_t FIFO; /*!< [0x0008] UART FIFO Control Register */
|
||||
__IO uint32_t LINE; /*!< [0x000c] UART Line Control Register */
|
||||
__IO uint32_t MODEM; /*!< [0x0010] UART Modem Control Register */
|
||||
__IO uint32_t MODEMSTS; /*!< [0x0014] UART Modem Status Register */
|
||||
__IO uint32_t FIFOSTS; /*!< [0x0018] UART FIFO Status Register */
|
||||
__IO uint32_t INTSTS; /*!< [0x001c] UART Interrupt Status Register */
|
||||
__IO uint32_t TOUT; /*!< [0x0020] UART Time-out Register */
|
||||
__IO uint32_t BAUD; /*!< [0x0024] UART Baud Rate Divider Register */
|
||||
__IO uint32_t IRDA; /*!< [0x0028] UART IrDA Control Register */
|
||||
__IO uint32_t ALTCTL; /*!< [0x002c] UART Alternate Control/Status Register */
|
||||
__IO uint32_t FUNCSEL; /*!< [0x0030] UART Function Select Register */
|
||||
__IO uint32_t LINCTL; /*!< [0x0034] UART LIN Control Register */
|
||||
__IO uint32_t LINSTS; /*!< [0x0038] UART LIN Status Register */
|
||||
__IO uint32_t BRCOMP; /*!< [0x003c] UART Baud Rate Compensation Register */
|
||||
__IO uint32_t WKCTL; /*!< [0x0040] UART Wake-up Control Register */
|
||||
__IO uint32_t WKSTS; /*!< [0x0044] UART Wake-up Status Register */
|
||||
__IO uint32_t DWKCOMP; /*!< [0x0048] UART Incoming Data Wake-up Compensation Register */
|
||||
|
||||
} UART_T;
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@ if not GetDepend('BSP_USE_STDDRIVER_SOURCE'):
|
|||
libs += ['libstddriver_gcc']
|
||||
|
||||
if not libs:
|
||||
group = DefineGroup('nuc980_driver', src, depend = [''], CPPPATH = cpppath)
|
||||
group = DefineGroup('Libraries', src, depend = [''], CPPPATH = cpppath)
|
||||
else:
|
||||
src = []
|
||||
group = DefineGroup('nuc980_driver', src, depend = [''], CPPPATH = cpppath, LIBS = libs, LIBPATH = libpath)
|
||||
group = DefineGroup('Libraries', src, depend = [''], CPPPATH = cpppath, LIBS = libs, LIBPATH = libpath)
|
||||
|
||||
Return('group')
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
| QSPI | RT_Device_Class_SPIBUS | ***qspi[0]*** |
|
||||
| RTC | RT_Device_Class_RTC | ***rtc*** |
|
||||
| PWM | RT_Device_Class_Miscellaneous (PWM) | ***pwm[0-1]*** |
|
||||
| USBH | RT_Device_Class_USBHost | ***usbh*** |
|
||||
| USBD | RT_Device_Class_USBDevice | ***usbd*** |
|
||||
| SC (UART function) | RT_Device_Class_Char | ***scuart[0-1]*** |
|
||||
| SDH | RT_Device_Class_Block | ***sdh[0-1]*** |
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
group = []
|
||||
if GetDepend('BSP_USING_HSUSBH') or GetDepend('BSP_USING_USBH'):
|
||||
src = Glob('*src/*.c') + Glob('src/*.cpp')
|
||||
CPPPATH = [cwd + '/inc']
|
||||
group = DefineGroup('nuc980_usbhostlib', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,279 @@
|
|||
/**************************************************************************//**
|
||||
* @file ehci.h
|
||||
* @version V1.00
|
||||
* @brief USB EHCI host controller driver header file.
|
||||
* @note
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _USBH_EHCI_H_
|
||||
#define _USBH_EHCI_H_
|
||||
|
||||
/// @cond HIDDEN_SYMBOLS
|
||||
|
||||
struct utr_t;
|
||||
struct udev_t;
|
||||
struct qh_t;
|
||||
struct iso_ep_t;
|
||||
struct ep_info_t;
|
||||
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* Periodic Frame List Size (256, 512, or 1024) */
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
#define FL_SIZE 1024 /* frame list size can be 256, 512, or 1024 */
|
||||
#define NUM_IQH 11 /* depends on FL_SIZE, 256:9, 512:10, 1024:11 */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* Interrupt Threshold Control (1, 2, 4, 6, .. 64) */
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
#define UCMDR_INT_THR_CTRL (0x1<<HSUSBH_UCMDR_ITC_Pos) /* 1 micro-frames */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* Queue Element Transfer Descriptor (qTD) */
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
typedef struct qTD_t
|
||||
{
|
||||
uint32_t Next_qTD; /* Next qTD Pointer */
|
||||
uint32_t Alt_Next_qTD; /* Alternate Next qTD Pointer */
|
||||
uint32_t Token; /* qTD Token */
|
||||
uint32_t Bptr[5]; /* qTD Buffer Page Pointer List */
|
||||
/*
|
||||
* The following members are used by USB Host libary.
|
||||
*/
|
||||
struct utr_t *utr; /* associated UTR */
|
||||
uint32_t xfer_len; /* assigned transfer transfer length */
|
||||
struct qh_t *qh; /* The QH that this qTD belong to. */
|
||||
struct qTD_t *next; /* link for <qtd_list> of QH */
|
||||
} qTD_T;
|
||||
|
||||
|
||||
#define QTD_LIST_END 0x1 /* Indicate the terminate of qTD list. */
|
||||
#define QTD_PTR(x) ((qTD_T *)((uint32_t)(x) & ~0x1F))
|
||||
|
||||
/*
|
||||
* Status: qTD Token[7:0]
|
||||
*/
|
||||
#define QTD_STS_PS_OUT (0<<0) /* directs the HC to issue an OUT PID */
|
||||
#define QTD_STS_PS_PING (1<<0) /* directs the HC to issue an PING PID */
|
||||
#define QTD_STS_SPLIT_STRAT (0<<1) /* directs the HC to issue an Start split */
|
||||
#define QTD_STS_SPLIT_COMPLETE (1<<1) /* directs the HC to issue an Complete split */
|
||||
#define QTD_STS_MISS_MF (1<<2) /* miss a required complete-split transaction */
|
||||
#define QTD_STS_XactErr (1<<3) /* Transaction Error occurred */
|
||||
#define QTD_STS_BABBLE (1<<4) /* Babble Detected */
|
||||
#define QTD_STS_DATA_BUFF_ERR (1<<5) /* Data Buffer Error */
|
||||
#define QTD_STS_HALT (1<<6) /* Halted */
|
||||
#define QTD_STS_ACTIVE (1<<7) /* Active */
|
||||
|
||||
/*
|
||||
* PID: qTD Token[9:8]
|
||||
*/
|
||||
#define QTD_PID_Msk (0x3<<8)
|
||||
#define QTD_PID_OUT (0<<8) /* generates token (E1H) */
|
||||
#define QTD_PID_IN (1<<8) /* generates token (69H) */
|
||||
#define QTD_PID_SETUP (2<<8) /* generates token (2DH) */
|
||||
|
||||
#define QTD_ERR_COUNTER (3<<10) /* Token[11:10] */
|
||||
#define QTD_IOC (1<<15) /* Token[15] - Interrupt On Complete */
|
||||
#define QTD_TODO_LEN_Pos 16 /* Token[31:16] - Total Bytes to Transfer */
|
||||
#define QTD_TODO_LEN(x) (((x)>>16) & 0x7FFF)
|
||||
#define QTD_DT (1UL<<31) /* Token[31] - Data Toggle */
|
||||
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* Queue Head (QH) */
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
typedef struct qh_t
|
||||
{
|
||||
/* OHCI spec. Endpoint descriptor */
|
||||
uint32_t HLink; /* Queue Head Horizontal Link Pointer */
|
||||
uint32_t Chrst; /* Endpoint Characteristics: QH DWord 1 */
|
||||
uint32_t Cap; /* Endpoint Capabilities: QH DWord 2 */
|
||||
uint32_t Curr_qTD; /* Current qTD Pointer */
|
||||
/*
|
||||
* The followings are qTD Transfer Overlay
|
||||
*/
|
||||
uint32_t OL_Next_qTD; /* Next qTD Pointer */
|
||||
uint32_t OL_Alt_Next_qTD; /* Alternate Next qTD Pointer */
|
||||
uint32_t OL_Token; /* qTD Token */
|
||||
uint32_t OL_Bptr[5]; /* qTD Buffer Page Pointer List */
|
||||
/*
|
||||
* The following members are used by USB Host libary.
|
||||
*/
|
||||
qTD_T *qtd_list; /* currently linked qTD transfers */
|
||||
qTD_T *done_list; /* currently linked qTD transfers */
|
||||
struct qh_t *next; /* point to the next QH in remove list */
|
||||
} QH_T;
|
||||
|
||||
/* HLink[0] T field of "Queue Head Horizontal Link Pointer" */
|
||||
#define QH_HLNK_END 0x1
|
||||
|
||||
/*
|
||||
* HLink[2:1] Typ field of "Queue Head Horizontal Link Pointer"
|
||||
*/
|
||||
#define QH_HLNK_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0)
|
||||
#define QH_HLNK_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2)
|
||||
#define QH_HLNK_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4)
|
||||
#define QH_HLNK_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6)
|
||||
#define QH_PTR(x) ((QH_T *)((uint32_t)(x) & ~0x1F))
|
||||
|
||||
/*
|
||||
* Bit fields of "Endpoint Characteristics"
|
||||
*/
|
||||
#define QH_NAK_RL (4L<<28) /* Chrst[31:28] - NAK Count Reload */
|
||||
#define QH_CTRL_EP_FLAG (1<<27) /* Chrst[27] - Control Endpoint Flag */
|
||||
#define QH_RCLM_LIST_HEAD (1<<15) /* Chrst[15] - Head of Reclamation List Flag */
|
||||
#define QH_DTC (1<<14) /* Chrst[14] - Data Toggle Control */
|
||||
#define QH_EPS_FULL (0<<12) /* Chrst[13:12] - Endpoint Speed (Full) */
|
||||
#define QH_EPS_LOW (1<<12) /* Chrst[13:12] - Endpoint Speed (Low) */
|
||||
#define QH_EPS_HIGH (2<<12) /* Chrst[13:12] - Endpoint Speed (High) */
|
||||
#define QH_I_NEXT (1<<7) /* Chrst[7] - Inactivate on Next Transaction */
|
||||
|
||||
/*
|
||||
* Bit fields of "Endpoint Capabilities"
|
||||
*/
|
||||
#define QH_MULT_Pos 30 /* Cap[31:30] - High-Bandwidth Pipe Multiplier */
|
||||
#define QH_HUB_PORT_Pos 23 /* Cap[29:23] - Hub Port Number */
|
||||
#define QH_HUB_ADDR_Pos 16 /* Cap[22:16] - Hub Addr */
|
||||
#define QH_C_MASK_Msk 0xFF00 /* Cap[15:8] - uFrame C-mask */
|
||||
#define QH_S_MASK_Msk 0x00FF /* Cap[7:0] - uFrame S-mask */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* Isochronous (High-Speed) Transfer Descriptor (iTD) */
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
typedef struct itd_t
|
||||
{
|
||||
uint32_t Next_Link; /* Next Link Pointer */
|
||||
uint32_t Transaction[8]; /* Transaction Status and Control */
|
||||
uint32_t Bptr[7]; /* Buffer Page Pointer List */
|
||||
/*
|
||||
* The following members are used by USB Host libary.
|
||||
*/
|
||||
struct iso_ep_t *iso_ep; /* associated isochronous information block */
|
||||
struct utr_t *utr; /* associated UTR */
|
||||
uint32_t buff_base; /* buffer base address */
|
||||
uint8_t fidx; /* iTD's first index to UTR iso frames */
|
||||
uint8_t trans_mask; /* mask of activated transactions in iTD */
|
||||
uint32_t sched_frnidx; /* scheduled frame index */
|
||||
struct itd_t *next; /* used by software to maintain iTD list */
|
||||
} iTD_T;
|
||||
|
||||
/*
|
||||
* Next_Link[2:1] Typ field of "Next Schedule Element Pointer" Typ field
|
||||
*/
|
||||
#define ITD_HLNK_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0)
|
||||
#define ITD_HLNK_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2)
|
||||
#define ITD_HLNK_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4)
|
||||
#define ITD_HLNK_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6)
|
||||
#define ITD_PTR(x) ((iTD_T *)((uint32_t)(x) & ~0x1F))
|
||||
|
||||
/*
|
||||
* Transaction[8]
|
||||
*/
|
||||
#define ITD_STATUS(x) (((x)>>28)&0xF)
|
||||
#define ITD_STATUS_ACTIVE (0x80000000UL) /* Active */
|
||||
#define ITD_STATUS_BUFF_ERR (0x40000000UL) /* Data Buffer Error */
|
||||
#define ITD_STATUS_BABBLE (0x20000000UL) /* Babble Detected */
|
||||
#define ITD_STATUS_XACT_ERR (0x10000000UL) /* Transcation Error */
|
||||
|
||||
#define ITD_XLEN_Pos 16
|
||||
#define ITD_XFER_LEN(x) (((x)>>16)&0xFFF)
|
||||
#define ITD_IOC (1<<15)
|
||||
#define ITD_PG_Pos 12
|
||||
#define ITD_XFER_OFF_Msk 0xFFF
|
||||
|
||||
/*
|
||||
* Bptr[7]
|
||||
*/
|
||||
#define ITD_BUFF_PAGE_Pos 12
|
||||
/* Bptr[0] */
|
||||
#define ITD_EP_NUM_Pos 8
|
||||
#define ITD_EP_NUM(itd) (((itd)->Bptr[0]>>8)&0xF)
|
||||
#define ITD_DEV_ADDR_Pos 0
|
||||
#define ITD_DEV_ADDR(itd) ((itd)->Bptr[0]&0x7F)
|
||||
/* Bptr[1] */
|
||||
#define ITD_DIR_IN (1<<11)
|
||||
#define ITD_DIR_OUT (0<<11)
|
||||
#define ITD_MAX_PKTSZ_Pos 0
|
||||
#define ITD_MAX_PKTSZ(itd) ((itd)->Bptr[1]&0x7FF)
|
||||
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* Split Isochronous (Full-Speed) Transfer Descriptor (siTD) */
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
typedef struct sitd_t
|
||||
{
|
||||
uint32_t Next_Link; /* Next Link Pointer */
|
||||
uint32_t Chrst; /* Endpoint and Transaction Translator Characteristics */
|
||||
uint32_t Sched; /* Micro-frame Schedule Control */
|
||||
uint32_t StsCtrl; /* siTD Transfer Status and Control */
|
||||
uint32_t Bptr[2]; /* Buffer Page Pointer List */
|
||||
uint32_t BackLink; /* siTD Back Link Pointer */
|
||||
/*
|
||||
* The following members are used by USB Host libary.
|
||||
*/
|
||||
struct iso_ep_t *iso_ep; /* associated isochronous information block */
|
||||
struct utr_t *utr; /* associated UTR */
|
||||
uint8_t fidx; /* iTD's first index to UTR iso frames */
|
||||
uint32_t sched_frnidx; /* scheduled frame index */
|
||||
struct sitd_t *next; /* used by software to maintain siTD list */
|
||||
} siTD_T;
|
||||
|
||||
#define SITD_LIST_END 0x1 /* Indicate the terminate of siTD list. */
|
||||
|
||||
#define SITD_XFER_IO_Msk (1UL<<31)
|
||||
#define SITD_XFER_IN (1UL<<31)
|
||||
#define SITD_XFER_OUT (0UL<<31)
|
||||
|
||||
#define SITD_PORT_NUM_Pos 24
|
||||
#define SITD_HUB_ADDR_Pos 16
|
||||
#define SITD_EP_NUM_Pos 8
|
||||
#define SITD_DEV_ADDR_Pos 0
|
||||
|
||||
#define SITD_IOC (1UL<<31)
|
||||
#define SITD_XFER_CNT_Pos 16
|
||||
#define SITD_XFER_CNT_Msk (0x3FF<<SITD_XFER_CNT_Pos)
|
||||
|
||||
#define SITD_STATUS(x) ((x)&0xFC)
|
||||
#define SITD_STATUS_ACTIVE 0x80
|
||||
#define SITD_STATUS_ERR 0x40
|
||||
#define SITD_STATUS_BUFF_ERR 0x20
|
||||
#define SITD_BABBLE_DETECTED 0x10
|
||||
#define SITD_STATUS_XFER_ERR 0x08
|
||||
#define SITD_STATUS_MISSED_MF 0x04
|
||||
#define SITD_STATUS_ERROR_MASK 0x78
|
||||
|
||||
|
||||
/*
|
||||
* Next_Link[2:1] Typ field of "Next Schedule Element Pointer" Typ field
|
||||
*/
|
||||
#define SITD_HLNK_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0)
|
||||
#define SITD_HLNK_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2)
|
||||
#define SITD_HLNK_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4)
|
||||
#define SITD_HLNK_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6)
|
||||
#define SITD_PTR(x) ((siTD_T *)((uint32_t)(x) & ~0x1F))
|
||||
|
||||
#define HLINK_IS_TERMINATED(x) (((uint32_t)(x) & 0x1) ? 1 : 0)
|
||||
#define HLINK_IS_SITD(x) ((((uint32_t)(x) & 0x6) == 0x4) ? 1 : 0)
|
||||
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* Isochronous endpoint transfer information block. (Software only) */
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
typedef struct iso_ep_t
|
||||
{
|
||||
struct ep_info_t *ep;
|
||||
uint32_t next_frame; /* frame number of next scheduling */
|
||||
iTD_T *itd_list; /* Reference to a list of installed iTDs */
|
||||
iTD_T *itd_done_list; /* Reference to a list of completed iTDs */
|
||||
siTD_T *sitd_list; /* Reference to a list of installed siTDs */
|
||||
siTD_T *sitd_done_list; /* Reference to a list of completed siTDs */
|
||||
struct iso_ep_t *next; /* used by software to maintain ISO EP list */
|
||||
} ISO_EP_T;
|
||||
|
||||
extern void scan_isochronous_list(void);
|
||||
|
||||
/// @endcond
|
||||
|
||||
#endif /* _USBH_EHCI_H_ */
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
/**************************************************************************//**
|
||||
* @file hub.h
|
||||
* @version V1.00
|
||||
* @brief USB Host hub class driver header file.
|
||||
* @note
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _USBH_HUB_H_
|
||||
#define _USBH_HUB_H_
|
||||
|
||||
|
||||
/// @cond HIDDEN_SYMBOLS
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Hub class feature selectors (Table 11-17) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
#define FS_C_HUB_LOCAL_POWER 0
|
||||
#define FS_C_HUB_OVER_CURRENT 1
|
||||
|
||||
#define FS_PORT_CONNECTION 0
|
||||
#define FS_PORT_ENABLE 1
|
||||
#define FS_PORT_SUSPEND 2
|
||||
#define FS_PORT_OVER_CURRENT 3
|
||||
#define FS_PORT_RESET 4
|
||||
#define FS_PORT_POWER 8
|
||||
#define FS_C_PORT_CONNECTION 16
|
||||
#define FS_C_PORT_ENABLE 17
|
||||
#define FS_C_PORT_SUSPEND 18
|
||||
#define FS_C_PORT_OVER_CURRENT 19
|
||||
#define FS_C_PORT_RESET 20
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Hub/Port staus and change bits */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
#define HUB_S_LOCAL_POWER (1UL << 0)
|
||||
#define HUB_S_OVERCURRENT (1UL << 1)
|
||||
|
||||
#define HUB_C_LOCAL_POWER (1UL << 0)
|
||||
#define HUB_C_OVERCURRENT (1UL << 1)
|
||||
|
||||
#define PORT_S_CONNECTION (1UL << 0)
|
||||
#define PORT_S_ENABLE (1UL << 1)
|
||||
#define PORT_S_SUSPEND (1UL << 2)
|
||||
#define PORT_S_OVERCURRENT (1UL << 3)
|
||||
#define PORT_S_RESET (1UL << 4)
|
||||
#define PORT_S_PORT_POWER (1UL << 8)
|
||||
#define PORT_S_LOW_SPEED (1UL << 9)
|
||||
#define PORT_S_HIGH_SPEED (1UL << 10)
|
||||
#define PORT_S_TEST (1UL << 11)
|
||||
#define PORT_S_INDICATOR (1UL << 12)
|
||||
|
||||
#define PORT_C_CONNECTION (1UL << 0)
|
||||
#define PORT_C_ENABLE (1UL << 1)
|
||||
#define PORT_C_SUSPEND (1UL << 2)
|
||||
#define PORT_C_OVERCURRENT (1UL << 3)
|
||||
#define PORT_C_RESET (1UL << 4)
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Hub descriptor */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
typedef struct __attribute__((__packed__))
|
||||
{
|
||||
uint8_t bDescLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bNbrPorts;
|
||||
uint16_t wHubCharacteristics;
|
||||
uint8_t bPwrOn2PwrGood;
|
||||
uint8_t bHubContrCurrent;
|
||||
uint8_t bDeviceRemovble;
|
||||
uint8_t PortPwrCtrlMask[16];
|
||||
}
|
||||
DESC_HUB_T;
|
||||
|
||||
/*
|
||||
* wHubCharacteristics bit field mask
|
||||
*/
|
||||
#define HUB_CHAR_LPSM 0x0003 /* 00b: global port power, 01b: per port power, 1x: reserved */
|
||||
#define HUB_CHAR_COMPOUND 0x0004 /* 1: is part of a compond device, 0: is not. */
|
||||
#define HUB_CHAR_OCPM 0x0018 /* 00b: global over-current protection, 01b: per port, 1x: reserved */
|
||||
#define HUB_CHAR_TTTT 0x0060 /* TT think time. 00b: 8FS, 01b: 16FS, 10b: 24FS, 11b: 32FS */
|
||||
#define HUB_CHAR_PORTIND 0x0080 /* 1: port indicator (LED) supported, 0: not */
|
||||
|
||||
/* port indicator status selectors */
|
||||
#define HUB_LED_AUTO 0
|
||||
#define HUB_LED_AMBER 1
|
||||
#define HUB_LED_GREEN 2
|
||||
#define HUB_LED_OFF 3
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Port reset retry and time-out settings */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
#define HUB_DEBOUNCE_TIME 800 /* Hub connect/disconnect de-bounce time in ms */
|
||||
#define PORT_RESET_RETRY 3 /* port reset retry times */
|
||||
#define PORT_RESET_TIME_MS 50 /* port reset time (ms) */
|
||||
#define PORT_RESET_RETRY_INC_MS 250 /* increased reset time (ms) after reset failed */
|
||||
|
||||
|
||||
#define HUB_STATUS_MAX_BYTE 2 /* maximum number of interrupt-in status bytes */
|
||||
/* 2 can support up to 16 port hubs */
|
||||
/* 4 can support up to 32 port hubs */
|
||||
/* Note!! If modeifed to 4, "uint16_t sc_bitmap" */
|
||||
/* MUST be changed as "uint32_t sc_bitmap" */
|
||||
typedef struct hub_dev_t
|
||||
{
|
||||
IFACE_T *iface; /*!< Interface device of this hub \hideinitializer */
|
||||
UTR_T *utr; /*!< Interrupt in UTR of this hub \hideinitializer */
|
||||
// uint8_t buff[HUB_STATUS_MAX_BYTE]; /*!< Interrupt in buffer \hideinitializer */
|
||||
uint16_t sc_bitmap; /*!< Hub and Port Status Change Bitmap \hideinitializer */
|
||||
uint8_t bNbrPorts; /*!< Number of ports \hideinitializer */
|
||||
uint8_t bPwrOn2PwrGood; /*!< Hub power on to power good time \hideinitializer */
|
||||
char pos_id[MAX_HUB_DEVICE + 1]; /*!< Hub position identifier \hideinitializer */
|
||||
int (*port_reset)(struct hub_dev_t *hub, int port); /*!< Port reset function \hideinitializer */
|
||||
UDEV_T *children; /*!< Child device list. \hideinitializer */
|
||||
} HUB_DEV_T;
|
||||
|
||||
|
||||
/// @endcond
|
||||
|
||||
#endif /* _USBH_HUB_H_ */
|
|
@ -0,0 +1,147 @@
|
|||
/**************************************************************************//**
|
||||
* @file ohci.h
|
||||
* @version V1.00
|
||||
* @brief USB OHCI host controller driver header file.
|
||||
* @note
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _USBH_OHCI_H_
|
||||
#define _USBH_OHCI_H_
|
||||
|
||||
/// @cond HIDDEN_SYMBOLS
|
||||
|
||||
struct utr_t;
|
||||
struct udev_t;
|
||||
|
||||
/* OHCI CONTROL AND STATUS REGISTER MASKS */
|
||||
|
||||
/*
|
||||
* Host controller functional state.
|
||||
* for HCFS(HcControl[7:6])
|
||||
*/
|
||||
#define HCFS_RESET (0UL << USBH_HcControl_HCFS_Pos)
|
||||
#define HCFS_RESUME (1UL << USBH_HcControl_HCFS_Pos)
|
||||
#define HCFS_OPER (2UL << USBH_HcControl_HCFS_Pos)
|
||||
#define HCFS_SUSPEND (3UL << USBH_HcControl_HCFS_Pos)
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* Endpoint descriptor */
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
typedef struct ed_t
|
||||
{
|
||||
/* OHCI spec. Endpoint descriptor */
|
||||
uint32_t Info;
|
||||
uint32_t TailP;
|
||||
uint32_t HeadP;
|
||||
uint32_t NextED;
|
||||
/* The following members are used by USB Host libary. */
|
||||
uint8_t bInterval;
|
||||
uint16_t next_sf; /* for isochronous transfer, recording the next SF */
|
||||
struct ed_t *next; /* point to the next ED in remove list */
|
||||
} ED_T;
|
||||
|
||||
#define ED_CTRL_FA_Pos 0 /* Info[6:0] - Function address */
|
||||
#define ED_CTRL_EN_Pos 7 /* Info[10:7] - Endpoint number */
|
||||
#define ED_CTRL_DIR_Pos 11 /* Info[12:11] - Direction */
|
||||
#define ED_CTRL_MPS_Pos 16 /* Info[26:16] - Maximum packet size */
|
||||
|
||||
#define ED_FUNC_ADDR_Msk (0x7f)
|
||||
#define ED_EP_ADDR_Msk (0xf<<7)
|
||||
#define ED_DIR_Msk (0x3<<11)
|
||||
#define ED_SPEED_Msk (1<<13)
|
||||
#define ED_MAX_PK_SIZE_Msk (0x7ff<<16)
|
||||
|
||||
#define ED_DIR_BY_TD (0<<ED_CTRL_DIR_Pos)
|
||||
#define ED_DIR_OUT (1<<ED_CTRL_DIR_Pos)
|
||||
#define ED_DIR_IN (2<<ED_CTRL_DIR_Pos)
|
||||
#define ED_SPEED_FULL (0<<13) /* Info[13] - 0: is full speed device */
|
||||
#define ED_SPEED_LOW (1<<13) /* Info[13] - 1: is low speed device */
|
||||
#define ED_SKIP (1<<14) /* Info[14] - 1: HC skip this ED */
|
||||
#define ED_FORMAT_GENERAL (0<<15) /* Info[15] - 0: is a general TD */
|
||||
#define ED_FORMAT_ISO (1<<15) /* Info[15] - 1: is an isochronous TD */
|
||||
#define ED_HEADP_HALT (1<<0) /* HeadP[0] - 1: Halt; 0: Not */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* Transfer descriptor */
|
||||
/*----------------------------------------------------------------------------------------*/
|
||||
/* general transfer descriptor */
|
||||
typedef struct td_t
|
||||
{
|
||||
uint32_t Info;
|
||||
uint32_t CBP; /* Current Buffer Pointer */
|
||||
uint32_t NextTD; /* Next TD */
|
||||
uint32_t BE; /* Buffer End */
|
||||
uint32_t PSW[4]; /* PSW 0~7 */
|
||||
/* The following members are used by USB Host libary. */
|
||||
uint32_t buff_start; /* Buffer Start */
|
||||
ED_T *ed; /* The ED that this TD belong to. */
|
||||
struct utr_t *utr; /* associated UTR */
|
||||
struct td_t *next; /* point to next TD of the same UTR */
|
||||
} TD_T;
|
||||
|
||||
#define TD_ADDR_MASK 0xFFFFFFFC
|
||||
|
||||
/* Completion codes */
|
||||
enum OCHI_CC_CODE
|
||||
{
|
||||
/* mapping of the OHCI CC status to error codes */
|
||||
CC_NOERROR, /* No Error */
|
||||
CC_CRC, /* CRC Error */
|
||||
CC_BITSTUFF, /* Bit Stuff */
|
||||
CC_DATA_TOGGLE, /* Data Toggle */
|
||||
CC_STALL, /* Stall */
|
||||
CC_NOTRESPONSE, /* DevNotResp */
|
||||
CC_PID_CHECK, /* PIDCheck */
|
||||
CC_UNEXPECTED_PID, /* UnExpPID */
|
||||
CC_DATA_OVERRUN, /* DataOver */
|
||||
CC_DATA_UNDERRUN, /* DataUnder */
|
||||
CC_RESERVED1, /* reserved */
|
||||
CC_RESERVED2, /* reserved */
|
||||
CC_BUFFER_OVERRUN, /* BufferOver */
|
||||
CC_BUFFER_UNDERRUN, /* BuffUnder */
|
||||
CC_NOT_ACCESS /* Not Access */
|
||||
};
|
||||
|
||||
/* TD control field */
|
||||
#define TD_CC 0xF0000000
|
||||
#define TD_CC_GET(td) ((td >>28) & 0x0F)
|
||||
#define TD_CC_SET(td, cc) (td) = ((td) & 0x0FFFFFFF) | (((cc) & 0x0F) << 28)
|
||||
#define TD_T_DATA0 0x02000000
|
||||
#define TD_T_DATA1 0x03000000
|
||||
#define TD_R 0x00040000
|
||||
#define TD_DP 0x00180000
|
||||
#define TD_DP_IN 0x00100000
|
||||
#define TD_DP_OUT 0x00080000
|
||||
#define MAXPSW 8
|
||||
/* steel TD reserved bits to keep driver data */
|
||||
#define TD_TYPE_Msk (0x3<<16)
|
||||
#define TD_TYPE_CTRL (0x0<<16)
|
||||
#define TD_TYPE_BULK (0x1<<16)
|
||||
#define TD_TYPE_INT (0x2<<16)
|
||||
#define TD_TYPE_ISO (0x3<<16)
|
||||
#define TD_CTRL_Msk (0x7<<15)
|
||||
#define TD_CTRL_DATA (1<<15)
|
||||
|
||||
|
||||
/*
|
||||
* The HCCA (Host Controller Communications Area) is a 256 byte
|
||||
* structure defined in the OHCI spec. that the host controller is
|
||||
* told the base address of. It must be 256-byte aligned.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t int_table[32]; /* Interrupt ED table */
|
||||
uint16_t frame_no; /* current frame number */
|
||||
uint16_t pad1; /* set to 0 on each frame_no change */
|
||||
uint32_t done_head; /* info returned for an interrupt */
|
||||
uint8_t reserved_for_hc[116];
|
||||
} HCCA_T;
|
||||
|
||||
|
||||
/// @endcond
|
||||
|
||||
#endif /* _USBH_OHCI_H_ */
|
|
@ -0,0 +1,394 @@
|
|||
/**************************************************************************//**
|
||||
* @file usb.h
|
||||
* @version V1.00
|
||||
* @brief USB Host library header file.
|
||||
* @note
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _USBH_H_
|
||||
#define _USBH_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "usbh_lib.h"
|
||||
#include "ehci.h"
|
||||
#include "ohci.h"
|
||||
|
||||
/// @cond HIDDEN_SYMBOLS
|
||||
|
||||
struct utr_t;
|
||||
struct udev_t;
|
||||
struct hub_dev_t;
|
||||
struct iface_t;
|
||||
struct ep_info_t;
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* USB device request setup packet */
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
typedef struct __attribute__((__packed__))
|
||||
{
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
}
|
||||
DEV_REQ_T;
|
||||
|
||||
/*
|
||||
* bmRequestType[7] - Data transfer direction
|
||||
*/
|
||||
#define REQ_TYPE_OUT 0x00
|
||||
#define REQ_TYPE_IN 0x80
|
||||
/*
|
||||
* bmRequestType[6:5] - Type
|
||||
*/
|
||||
#define REQ_TYPE_STD_DEV 0x00
|
||||
#define REQ_TYPE_CLASS_DEV 0x20
|
||||
#define REQ_TYPE_VENDOR_DEV 0x40
|
||||
/*
|
||||
* bmRequestType[4:0] - Recipient
|
||||
*/
|
||||
#define REQ_TYPE_TO_DEV 0x00
|
||||
#define REQ_TYPE_TO_IFACE 0x01
|
||||
#define REQ_TYPE_TO_EP 0x02
|
||||
#define REQ_TYPE_TO_OTHER 0x03
|
||||
/*
|
||||
* Standard Requests
|
||||
*/
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
#define USB_REQ_SET_FEATURE 0x03
|
||||
#define USB_REQ_SET_ADDRESS 0x05
|
||||
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||
#define USB_REQ_SET_INTERFACE 0x0B
|
||||
/*
|
||||
* Descriptor Types
|
||||
*/
|
||||
#define USB_DT_STANDARD 0x00
|
||||
#define USB_DT_CLASS 0x20
|
||||
#define USB_DT_VENDOR 0x40
|
||||
|
||||
#define USB_DT_DEVICE 0x01
|
||||
#define USB_DT_CONFIGURATION 0x02
|
||||
#define USB_DT_STRING 0x03
|
||||
#define USB_DT_INTERFACE 0x04
|
||||
#define USB_DT_ENDPOINT 0x05
|
||||
#define USB_DT_DEVICE_QUALIFIER 0x06
|
||||
#define USB_DT_OTHER_SPEED_CONF 0x07
|
||||
#define USB_DT_IFACE_POWER 0x08
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* USB standard descriptors */
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
/* Descriptor header */
|
||||
typedef struct __attribute__((__packed__))
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
}
|
||||
DESC_HDR_T;
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* USB device descriptor */
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
typedef struct __attribute__((__packed__)) /*!< device descriptor structure */
|
||||
{
|
||||
uint8_t bLength; /*!< Length of device descriptor */
|
||||
uint8_t bDescriptorType; /*!< Device descriptor type */
|
||||
uint16_t bcdUSB; /*!< USB version number */
|
||||
uint8_t bDeviceClass; /*!< Device class code */
|
||||
uint8_t bDeviceSubClass; /*!< Device subclass code */
|
||||
uint8_t bDeviceProtocol; /*!< Device protocol code */
|
||||
uint8_t bMaxPacketSize0; /*!< Maximum packet size of control endpoint*/
|
||||
uint16_t idVendor; /*!< Vendor ID */
|
||||
uint16_t idProduct; /*!< Product ID */
|
||||
uint16_t bcdDevice; /*!< Device ID */
|
||||
uint8_t iManufacturer; /*!< Manufacture description string ID */
|
||||
uint8_t iProduct; /*!< Product description string ID */
|
||||
uint8_t iSerialNumber; /*!< Serial number description string ID */
|
||||
uint8_t bNumConfigurations; /*!< Total number of configurations */
|
||||
}
|
||||
DESC_DEV_T; /*!< device descriptor structure */
|
||||
|
||||
/*
|
||||
* Configuration Descriptor
|
||||
*/
|
||||
typedef struct __attribute__((__packed__)) usb_config_descriptor /*!< Configuration descriptor structure */
|
||||
{
|
||||
uint8_t bLength; /*!< Length of configuration descriptor */
|
||||
uint8_t bDescriptorType; /*!< Descriptor type */
|
||||
uint16_t wTotalLength; /*!< Total length of this configuration */
|
||||
uint8_t bNumInterfaces; /*!< Total number of interfaces */
|
||||
uint8_t bConfigurationValue; /*!< Configuration descriptor number */
|
||||
uint8_t iConfiguration; /*!< String descriptor ID */
|
||||
uint8_t bmAttributes; /*!< Configuration characteristics */
|
||||
uint8_t MaxPower; /*!< Maximum power consumption */
|
||||
} DESC_CONF_T; /*!< Configuration descriptor structure */
|
||||
|
||||
/*
|
||||
* Interface Descriptor
|
||||
*/
|
||||
typedef struct __attribute__((__packed__))usb_interface_descriptor /*!< Interface descriptor structure */
|
||||
{
|
||||
uint8_t bLength; /*!< Length of interface descriptor */
|
||||
uint8_t bDescriptorType; /*!< Descriptor type */
|
||||
uint8_t bInterfaceNumber; /*!< Interface number */
|
||||
uint8_t bAlternateSetting; /*!< Alternate setting number */
|
||||
uint8_t bNumEndpoints; /*!< Number of endpoints */
|
||||
uint8_t bInterfaceClass; /*!< Interface class code */
|
||||
uint8_t bInterfaceSubClass; /*!< Interface subclass code */
|
||||
uint8_t bInterfaceProtocol; /*!< Interface protocol code */
|
||||
uint8_t iInterface; /*!< Interface ID */
|
||||
} DESC_IF_T; /*!< Interface descriptor structure */
|
||||
|
||||
/*
|
||||
* Endpoint Descriptor
|
||||
*/
|
||||
typedef struct __attribute__((__packed__)) usb_endpoint_descriptor /*!< Endpoint descriptor structure */
|
||||
{
|
||||
uint8_t bLength; /*!< Length of endpoint descriptor */
|
||||
uint8_t bDescriptorType; /*!< Descriptor type */
|
||||
uint8_t bEndpointAddress; /*!< Endpoint address */
|
||||
uint8_t bmAttributes; /*!< Endpoint attribute */
|
||||
uint16_t wMaxPacketSize; /*!< Maximum packet size */
|
||||
uint8_t bInterval; /*!< Synchronous transfer interval */
|
||||
uint8_t bRefresh; /*!< Refresh */
|
||||
uint8_t bSynchAddress; /*!< Sync address */
|
||||
} DESC_EP_T; /*!< Endpoint descriptor structure */
|
||||
|
||||
/*
|
||||
* Endpoint descriptor bEndpointAddress[7] - direction
|
||||
*/
|
||||
#define EP_ADDR_DIR_MASK 0x80
|
||||
#define EP_ADDR_DIR_IN 0x80
|
||||
#define EP_ADDR_DIR_OUT 0x00
|
||||
|
||||
/*
|
||||
* Endpoint descriptor bmAttributes[1:0] - transfer type
|
||||
*/
|
||||
#define EP_ATTR_TT_MASK 0x03
|
||||
#define EP_ATTR_TT_CTRL 0x00
|
||||
#define EP_ATTR_TT_ISO 0x01
|
||||
#define EP_ATTR_TT_BULK 0x02
|
||||
#define EP_ATTR_TT_INT 0x03
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* USB Host controller driver */
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
typedef struct
|
||||
{
|
||||
int (*init)(void);
|
||||
void (*shutdown)(void);
|
||||
void (*suspend)(void);
|
||||
void (*resume)(void);
|
||||
int (*ctrl_xfer)(struct utr_t *utr);
|
||||
int (*bulk_xfer)(struct utr_t *utr);
|
||||
int (*int_xfer)(struct utr_t *utr);
|
||||
int (*iso_xfer)(struct utr_t *utr);
|
||||
int (*quit_xfer)(struct utr_t *utr, struct ep_info_t *ep);
|
||||
|
||||
/* root hub support */
|
||||
int (*rthub_port_reset)(int port);
|
||||
int (*rthub_polling)(void);
|
||||
} HC_DRV_T;
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* USB device driver */
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
typedef struct
|
||||
{
|
||||
int (*probe)(struct iface_t *iface);
|
||||
void (*disconnect)(struct iface_t *iface);
|
||||
void (*suspend)(struct iface_t *iface);
|
||||
void (*resume)(struct iface_t *iface);
|
||||
} UDEV_DRV_T;
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* USB device */
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPEED_LOW,
|
||||
SPEED_FULL,
|
||||
SPEED_HIGH
|
||||
} SPEED_E;
|
||||
|
||||
typedef struct ep_info_t
|
||||
{
|
||||
uint8_t bEndpointAddress;
|
||||
uint8_t bmAttributes;
|
||||
uint8_t bInterval;
|
||||
uint8_t bToggle;
|
||||
uint16_t wMaxPacketSize;
|
||||
void *hw_pipe; /*!< point to the HC assocaied endpoint \hideinitializer */
|
||||
} EP_INFO_T;
|
||||
|
||||
typedef struct udev_t
|
||||
{
|
||||
DESC_DEV_T descriptor; /*!< Device descriptor. \hideinitializer */
|
||||
struct hub_dev_t *parent; /*!< parent hub device \hideinitializer */
|
||||
uint8_t port_num; /*!< The hub port this device connected on \hideinitializer */
|
||||
uint8_t dev_num; /*!< device number \hideinitializer */
|
||||
int8_t cur_conf; /*!< Currentll selected configuration \hideinitializer */
|
||||
SPEED_E speed; /*!< device speed (low/full/high) \hideinitializer */
|
||||
/*
|
||||
* The followings are lightweight USB stack internal used .
|
||||
*/
|
||||
uint8_t *cfd_buff; /*!< Configuration descriptor buffer. \hideinitializer */
|
||||
EP_INFO_T ep0; /*!< Endpoint 0 \hideinitializer */
|
||||
HC_DRV_T *hc_driver; /*!< host controller driver \hideinitializer */
|
||||
struct iface_t *iface_list; /*!< Working interface list \hideinitializer */
|
||||
struct udev_t *next; /*!< link for global usb device list \hideinitializer */
|
||||
} UDEV_T;
|
||||
|
||||
typedef struct alt_iface_t
|
||||
{
|
||||
DESC_IF_T *ifd; /*!< point to the location of this alternative interface descriptor in UDEV_T->cfd_buff */
|
||||
EP_INFO_T ep[MAX_EP_PER_IFACE]; /*!< endpoints of this alternative interface */
|
||||
} ALT_IFACE_T;
|
||||
|
||||
typedef struct iface_t
|
||||
{
|
||||
UDEV_T *udev; /*!< USB device \hideinitializer */
|
||||
uint8_t if_num; /*!< Interface number \hideinitializer */
|
||||
uint8_t num_alt; /*!< Number of alternative interface \hideinitializer */
|
||||
ALT_IFACE_T *aif; /*!< Point to the active alternative interface */
|
||||
ALT_IFACE_T alt[MAX_ALT_PER_IFACE]; /*!< List of alternative interface \hideinitializer */
|
||||
UDEV_DRV_T *driver; /*!< Interface associated driver \hideinitializer */
|
||||
void *context; /*!< Reference to device context \hideinitializer */
|
||||
struct iface_t *next; /*!< Point to next interface of the same device. Started from UDEV_T->iface_list \hideinitializer */
|
||||
} IFACE_T;
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* URB (USB Request Block) */
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
#define IF_PER_UTR 8 /* number of frames per UTR isochronous transfer (DO NOT modify it!) */
|
||||
|
||||
typedef void (*FUNC_UTR_T)(struct utr_t *);
|
||||
|
||||
typedef struct utr_t
|
||||
{
|
||||
UDEV_T *udev; /*!< point to associated USB device \hideinitializer */
|
||||
DEV_REQ_T setup; /*!< buffer for setup packet \hideinitializer */
|
||||
EP_INFO_T *ep; /*!< associated endpoint \hideinitializer */
|
||||
uint8_t *buff; /*!< transfer buffer \hideinitializer */
|
||||
uint8_t bIsTransferDone; /*!< tansfer done? \hideinitializer */
|
||||
uint32_t data_len; /*!< length of data to be transferred \hideinitializer */
|
||||
uint32_t xfer_len; /*!< length of transferred data \hideinitializer */
|
||||
uint8_t bIsoNewSched; /*!< New schedule isochronous transfer \hideinitializer */
|
||||
uint16_t iso_sf; /*!< Isochronous start frame number \hideinitializer */
|
||||
uint16_t iso_xlen[IF_PER_UTR]; /*!< transfer length of isochronous frames \hideinitializer */
|
||||
uint8_t *iso_buff[IF_PER_UTR]; /*!< transfer buffer address of isochronous frames \hideinitializer */
|
||||
int iso_status[IF_PER_UTR]; /*!< transfer status of isochronous frames \hideinitializer */
|
||||
int td_cnt; /*!< number of transfer descriptors \hideinitializer */
|
||||
int status; /*!< return status \hideinitializer */
|
||||
int interval; /*!< interrupt/isochronous interval \hideinitializer */
|
||||
void *context; /*!< point to deivce proprietary data area \hideinitializer */
|
||||
FUNC_UTR_T func; /*!< tansfer done call-back function \hideinitializer */
|
||||
struct utr_t *next; /* point to the next UTR of the same endpoint. \hideinitializer */
|
||||
} UTR_T;
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* Global variables */
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
extern USBH_T *_ohci;
|
||||
extern HSUSBH_T *_ehci;
|
||||
|
||||
extern HC_DRV_T ohci_driver;
|
||||
extern HC_DRV_T ehci_driver;
|
||||
|
||||
extern UDEV_T *g_udev_list;
|
||||
|
||||
extern volatile int _IsInUsbInterrupt;
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* USB stack exported functions */
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
extern void usbh_delay_ms(int msec);
|
||||
|
||||
extern void dump_ohci_regs(void);
|
||||
extern void dump_ohci_ports(void);
|
||||
extern void dump_ohci_int_table(void);
|
||||
extern void dump_ehci_regs(void);
|
||||
extern void dump_ehci_qtd(qTD_T *qtd);
|
||||
extern void dump_ehci_asynclist(void);
|
||||
extern void dump_ehci_period_frame_list_simple(void);
|
||||
extern void usbh_dump_buff_bytes(uint8_t *buff, int nSize);
|
||||
extern void usbh_dump_interface_descriptor(DESC_IF_T *if_desc);
|
||||
extern void usbh_dump_endpoint_descriptor(DESC_EP_T *ep_desc);
|
||||
extern void usbh_dump_iface(IFACE_T *iface);
|
||||
extern void usbh_dump_ep_info(EP_INFO_T *ep);
|
||||
|
||||
/*
|
||||
* Memory management functions
|
||||
*/
|
||||
extern void USB_InitializeMemoryPool(void);
|
||||
extern void *USB_malloc(int wanted_size, int boundary);
|
||||
extern void USB_free(void *);
|
||||
extern int USB_available_memory(void);
|
||||
extern int USB_allocated_memory(void);
|
||||
extern void usbh_memory_init(void);
|
||||
extern uint32_t usbh_memory_used(void);
|
||||
extern void *usbh_alloc_mem(int size);
|
||||
extern void usbh_free_mem(void *p, int size);
|
||||
extern int alloc_dev_address(void);
|
||||
extern void free_dev_address(int dev_addr);
|
||||
extern UDEV_T *alloc_device(void);
|
||||
extern void free_device(UDEV_T *udev);
|
||||
extern UTR_T *alloc_utr(UDEV_T *udev);
|
||||
extern void free_utr(UTR_T *utr);
|
||||
extern ED_T *alloc_ohci_ED(void);
|
||||
extern void free_ohci_ED(ED_T *ed);
|
||||
extern TD_T *alloc_ohci_TD(UTR_T *utr);
|
||||
extern void free_ohci_TD(TD_T *td);
|
||||
extern QH_T *alloc_ehci_QH(void);
|
||||
extern void free_ehci_QH(QH_T *qh);
|
||||
extern qTD_T *alloc_ehci_qTD(UTR_T *utr);
|
||||
extern void free_ehci_qTD(qTD_T *qtd);
|
||||
extern iTD_T *alloc_ehci_iTD(void);
|
||||
extern void free_ehci_iTD(iTD_T *itd);
|
||||
extern siTD_T *alloc_ehci_siTD(void);
|
||||
extern void free_ehci_siTD(siTD_T *sitd);
|
||||
|
||||
|
||||
extern void usbh_hub_init(void);
|
||||
extern int usbh_connect_device(UDEV_T *);
|
||||
extern void usbh_disconnect_device(UDEV_T *);
|
||||
extern int usbh_register_driver(UDEV_DRV_T *driver);
|
||||
extern EP_INFO_T *usbh_iface_find_ep(IFACE_T *iface, uint8_t ep_addr, uint8_t dir_type);
|
||||
extern int usbh_reset_device(UDEV_T *);
|
||||
extern int usbh_reset_port(UDEV_T *);
|
||||
|
||||
/*
|
||||
* USB Standard Request functions
|
||||
*/
|
||||
extern int usbh_get_device_descriptor(UDEV_T *udev, DESC_DEV_T *desc_buff);
|
||||
extern int usbh_get_config_descriptor(UDEV_T *udev, uint8_t *desc_buff, int buff_len);
|
||||
extern int usbh_set_configuration(UDEV_T *udev, uint8_t conf_val);
|
||||
extern int usbh_set_interface(IFACE_T *iface, uint16_t alt_setting);
|
||||
extern int usbh_clear_halt(UDEV_T *udev, uint16_t ep_addr);
|
||||
|
||||
extern int usbh_ctrl_xfer(UDEV_T *udev, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *buff, uint32_t *xfer_len, uint32_t timeout);
|
||||
extern int usbh_bulk_xfer(UTR_T *utr);
|
||||
extern int usbh_int_xfer(UTR_T *utr);
|
||||
extern int usbh_iso_xfer(UTR_T *utr);
|
||||
extern int usbh_quit_utr(UTR_T *utr);
|
||||
extern int usbh_quit_xfer(UDEV_T *udev, EP_INFO_T *ep);
|
||||
|
||||
|
||||
/// @endcond HIDDEN_SYMBOLS
|
||||
|
||||
#endif /* _USBH_H_ */
|
|
@ -0,0 +1,188 @@
|
|||
/**************************************************************************//**
|
||||
* @file usbh_lib.h
|
||||
* @version V1.10
|
||||
* $Revision: 4 $
|
||||
* $Date: 15/06/10 2:06p $
|
||||
* @brief USB Host library exported header file.
|
||||
*
|
||||
* @note
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
|
||||
******************************************************************************/
|
||||
#ifndef _USBH_LIB_H_
|
||||
#define _USBH_LIB_H_
|
||||
|
||||
#include "nuc980.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/** @addtogroup Library Library
|
||||
@{
|
||||
*/
|
||||
|
||||
/** @addtogroup USBH_Library USB Host Library
|
||||
@{
|
||||
*/
|
||||
|
||||
/** @addtogroup USBH_EXPORTED_CONSTANTS USB Host Exported Constants
|
||||
@{
|
||||
*/
|
||||
|
||||
#define USBH_OK 0 /*!< No error. */
|
||||
#define USBH_ERR_MEMORY_OUT -10 /*!< Out of memory. */
|
||||
#define USBH_ERR_IF_ALT_LIMIT -11 /*!< Number of alternative interface > MAX_ALT_PER_IFACE */
|
||||
#define USBH_ERR_IF_EP_LIMIT -15 /*!< Number of endpoints > MAX_EP_PER_IFACE */
|
||||
#define USBH_ERR_NOT_SUPPORTED -101 /*!< Device/Class/Transfer not supported */
|
||||
#define USBH_ERR_NOT_MATCHED -103 /*!< Not macthed */
|
||||
#define USBH_ERR_NOT_EXPECTED -104 /*!< Unknown or unexpected */
|
||||
#define USBH_ERR_INVALID_PARAM -105 /*!< Invalid parameter */
|
||||
#define USBH_ERR_NOT_FOUND -106 /*!< Device or interface not found */
|
||||
#define USBH_ERR_EP_NOT_FOUND -107 /*!< Endpoint not found */
|
||||
#define USBH_ERR_DESCRIPTOR -137 /*!< Failed to parse USB descriptors */
|
||||
#define USBH_ERR_SET_DEV_ADDR -139 /*!< Failed to set device address */
|
||||
#define USBH_ERR_SET_CONFIG -151 /*!< Failed to set device configuration */
|
||||
|
||||
#define USBH_ERR_TRANSFER -201 /*!< USB transfer error */
|
||||
#define USBH_ERR_TIMEOUT -203 /*!< USB transfer time-out */
|
||||
#define USBH_ERR_ABORT -205 /*!< USB transfer aborted due to disconnect or reset */
|
||||
#define USBH_ERR_PORT_RESET -255 /*!< Hub port reset failed */
|
||||
#define USBH_ERR_SCH_OVERRUN -257 /*!< USB isochronous schedule overrun */
|
||||
#define USBH_ERR_DISCONNECTED -259 /*!< USB device was disconnected */
|
||||
|
||||
#define USBH_ERR_TRANSACTION -271 /*!< USB transaction timeout, CRC, Bad PID, etc. */
|
||||
#define USBH_ERR_BABBLE_DETECTED -272 /*!< A ¡§babble¡¨ is detected during the transaction */
|
||||
#define USBH_ERR_DATA_BUFF -274 /*!< Data buffer overrun or underrun */
|
||||
|
||||
#define USBH_ERR_CC_NO_ERR -280 /*!< OHCI CC code - no error */
|
||||
#define USBH_ERR_CRC -281 /*!< USB trasfer CRC error */
|
||||
#define USBH_ERR_BIT_STUFF -282 /*!< USB transfer bit stuffing error */
|
||||
#define USBH_ERR_DATA_TOGGLE -283 /*!< USB trasfer data toggle error */
|
||||
#define USBH_ERR_STALL -284 /*!< USB trasfer STALL error */
|
||||
#define USBH_ERR_DEV_NO_RESP -285 /*!< USB trasfer device no response error */
|
||||
#define USBH_ERR_PID_CHECK -286 /*!< USB trasfer PID check failure */
|
||||
#define USBH_ERR_UNEXPECT_PID -287 /*!< USB trasfer unexpected PID error */
|
||||
#define USBH_ERR_DATA_OVERRUN -288 /*!< USB trasfer data overrun error */
|
||||
#define USBH_ERR_DATA_UNDERRUN -289 /*!< USB trasfer data underrun error */
|
||||
#define USBH_ERR_BUFF_OVERRUN -292 /*!< USB trasfer buffer overrun error */
|
||||
#define USBH_ERR_BUFF_UNDERRUN -293 /*!< USB trasfer buffer underrun error */
|
||||
#define USBH_ERR_NOT_ACCESS0 -294 /*!< USB trasfer not accessed error */
|
||||
#define USBH_ERR_NOT_ACCESS1 -295 /*!< USB trasfer not accessed error */
|
||||
|
||||
#define USBH_ERR_OHCI_INIT -301 /*!< Failed to initialize OHIC controller. */
|
||||
#define USBH_ERR_OHCI_EP_BUSY -303 /*!< The endpoint is under transfer. */
|
||||
|
||||
#define USBH_ERR_EHCI_INIT -501 /*!< Failed to initialize EHCI controller. */
|
||||
#define USBH_ERR_EHCI_QH_BUSY -503 /*!< the Queue Head is busy. */
|
||||
|
||||
#define UMAS_OK 0 /*!< No error. */
|
||||
#define UMAS_ERR_NO_DEVICE -1031 /*!< No Mass Stroage Device found. */
|
||||
#define UMAS_ERR_IO -1033 /*!< Device read/write failed. */
|
||||
#define UMAS_ERR_INIT_DEVICE -1035 /*!< failed to init MSC device */
|
||||
#define UMAS_ERR_CMD_STATUS -1037 /*!< SCSI command status failed */
|
||||
#define UMAS_ERR_IVALID_PARM -1038 /*!< Invalid parameter. */
|
||||
#define UMAS_ERR_DRIVE_NOT_FOUND -1039 /*!< drive not found */
|
||||
|
||||
#define HID_RET_OK 0 /*!< Return with no errors. */
|
||||
#define HID_RET_DEV_NOT_FOUND -1081 /*!< HID device not found or removed. */
|
||||
#define HID_RET_IO_ERR -1082 /*!< USB transfer failed. */
|
||||
#define HID_RET_INVALID_PARAMETER -1083 /*!< Invalid parameter. */
|
||||
#define HID_RET_OUT_OF_MEMORY -1084 /*!< Out of memory. */
|
||||
#define HID_RET_NOT_SUPPORTED -1085 /*!< Function not supported. */
|
||||
#define HID_RET_EP_NOT_FOUND -1086 /*!< Endpoint not found. */
|
||||
#define HID_RET_PARSING -1087 /*!< Failed to parse HID descriptor */
|
||||
#define HID_RET_XFER_IS_RUNNING -1089 /*!< The transfer has been enabled. */
|
||||
#define HID_RET_REPORT_NOT_FOUND -1090 /*!< The transfer has been enabled. */
|
||||
|
||||
#define UAC_RET_OK 0 /*!< Return with no errors. */
|
||||
#define UAC_RET_DEV_NOT_FOUND -2001 /*!< Audio Class device not found or removed. */
|
||||
#define UAC_RET_FUNC_NOT_FOUND -2002 /*!< Audio device has no this function. */
|
||||
#define UAC_RET_IO_ERR -2003 /*!< USB transfer failed. */
|
||||
#define UAC_RET_DATA_LEN -2004 /*!< Unexpected transfer length */
|
||||
#define UAC_RET_INVALID -2005 /*!< Invalid parameter or usage. */
|
||||
#define UAC_RET_OUT_OF_MEMORY -2007 /*!< Out of memory. */
|
||||
#define UAC_RET_DRV_NOT_SUPPORTED -2009 /*!< Function not supported by this UAC driver. */
|
||||
#define UAC_RET_DEV_NOT_SUPPORTED -2011 /*!< Function not supported by the UAC device. */
|
||||
#define UAC_RET_PARSER -2013 /*!< Failed to parse UAC descriptor */
|
||||
#define UAC_RET_IS_STREAMING -2015 /*!< Audio pipe is on streaming. */
|
||||
|
||||
|
||||
/*@}*/ /* end of group USBH_EXPORTED_CONSTANTS */
|
||||
|
||||
|
||||
/** @addtogroup USBH_EXPORTED_TYPEDEF USB Host Typedef
|
||||
@{
|
||||
*/
|
||||
struct udev_t;
|
||||
typedef void (CONN_FUNC)(struct udev_t *udev, int param);
|
||||
|
||||
struct line_coding_t;
|
||||
struct cdc_dev_t;
|
||||
typedef void (CDC_CB_FUNC)(struct cdc_dev_t *cdev, uint8_t *rdata, int data_len);
|
||||
|
||||
struct usbhid_dev;
|
||||
typedef void (HID_IR_FUNC)(struct usbhid_dev *hdev, uint16_t ep_addr, int status, uint8_t *rdata, uint32_t data_len); /*!< interrupt in callback function \hideinitializer */
|
||||
typedef void (HID_IW_FUNC)(struct usbhid_dev *hdev, uint16_t ep_addr, int status, uint8_t *wbuff, uint32_t *data_len); /*!< interrupt out callback function \hideinitializer */
|
||||
|
||||
struct uac_dev_t;
|
||||
typedef int (UAC_CB_FUNC)(struct uac_dev_t *dev, uint8_t *data, int len); /*!< audio in callback function \hideinitializer */
|
||||
|
||||
/*@}*/ /* end of group USBH_EXPORTED_STRUCT */
|
||||
|
||||
|
||||
|
||||
/** @addtogroup USBH_EXPORTED_FUNCTIONS USB Host Exported Functions
|
||||
@{
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* USB Core Library APIs */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
extern void usbh_core_init(void);
|
||||
extern int usbh_polling_root_hubs(void);
|
||||
extern void usbh_install_conn_callback(CONN_FUNC *conn_func, CONN_FUNC *disconn_func);
|
||||
extern void usbh_suspend(void);
|
||||
extern void usbh_resume(void);
|
||||
extern struct udev_t *usbh_find_device(char *hub_id, int port);
|
||||
|
||||
/**
|
||||
* @brief A function return current tick count.
|
||||
* @return Current tick.
|
||||
* @details User application must provide this function to return current tick.
|
||||
* The tick should increase by 1 for every 10 ms.
|
||||
*/
|
||||
extern uint32_t usbh_get_ticks(void); /* This function must be provided by user application. */
|
||||
extern uint32_t usbh_tick_from_millisecond(uint32_t msec); /* This function must be provided by user application. */
|
||||
|
||||
|
||||
/// @cond HIDDEN_SYMBOLS
|
||||
|
||||
extern void dump_ohci_regs(void);
|
||||
extern void dump_ehci_regs(void);
|
||||
extern void dump_ohci_ports(void);
|
||||
extern void dump_ehci_ports(void);
|
||||
extern uint32_t usbh_memory_used(void);
|
||||
|
||||
/// @endcond HIDDEN_SYMBOLS
|
||||
|
||||
|
||||
/*@}*/ /* end of group USBH_EXPORTED_FUNCTIONS */
|
||||
|
||||
/*@}*/ /* end of group USBH_Library */
|
||||
|
||||
/*@}*/ /* end of group LIBRARY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _USBH_LIB_H_ */
|
||||
|
||||
/*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,918 @@
|
|||
/**************************************************************************//**
|
||||
* @file ehci_iso.c
|
||||
* @version V1.10
|
||||
* $Revision: 11 $
|
||||
* $Date: 14/10/03 1:54p $
|
||||
* @brief USB EHCI isochornous transfer driver.
|
||||
*
|
||||
* @note
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nuc980.h"
|
||||
|
||||
#include "usb.h"
|
||||
#include "hub.h"
|
||||
|
||||
|
||||
/// @cond HIDDEN_SYMBOLS
|
||||
|
||||
uint32_t g_flr_cnt; /* frame list rollover counter */
|
||||
|
||||
ISO_EP_T *iso_ep_list; /* list of activated isochronous pipes */
|
||||
|
||||
extern uint32_t *_PFList; /* Periodic frame list */
|
||||
|
||||
static const uint16_t sitd_OUT_Smask [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
|
||||
|
||||
static int ehci_iso_split_xfer(UTR_T *utr, ISO_EP_T *iso_ep);
|
||||
|
||||
/*
|
||||
* Inspect the iTD can be reclaimed or not. If yes, collect the transaction results.
|
||||
* Return: 1 - reclaimed
|
||||
* 0 - not completed
|
||||
*/
|
||||
static int review_itd(iTD_T *itd)
|
||||
{
|
||||
UTR_T *utr;
|
||||
uint32_t frnidx = itd->sched_frnidx;
|
||||
uint32_t now_frame = (_ehci->UFINDR >> 3) & 0x3FF;
|
||||
int i, fidx;
|
||||
|
||||
// printf("R - %d %d, 0x%x\n", now_frame, frnidx, itd->Transaction[0]);
|
||||
|
||||
if (now_frame == frnidx)
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (itd->Transaction[i] & ITD_STATUS_ACTIVE)
|
||||
return 0; /* have any not completed frames */
|
||||
}
|
||||
}
|
||||
else if (now_frame > frnidx)
|
||||
{
|
||||
if ((now_frame - frnidx) > EHCI_ISO_RCLM_RANGE)
|
||||
return 0; /* don't touch it */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (now_frame + FL_SIZE - frnidx > EHCI_ISO_RCLM_RANGE)
|
||||
return 0; /* don't touch it */
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim this iTD
|
||||
*/
|
||||
utr = itd->utr;
|
||||
fidx = itd->fidx;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (!(itd->trans_mask & (0x1 << i)))
|
||||
continue; /* not scheduled micro-frame */
|
||||
|
||||
if (ITD_STATUS(itd->Transaction[i]))
|
||||
{
|
||||
if (itd->Transaction[i] & ITD_STATUS_ACTIVE)
|
||||
{
|
||||
utr->iso_status[fidx] = USBH_ERR_NOT_ACCESS0;
|
||||
utr->status = USBH_ERR_NOT_ACCESS0;
|
||||
}
|
||||
else if (itd->Transaction[i] & ITD_STATUS_BABBLE)
|
||||
{
|
||||
utr->iso_status[fidx] = USBH_ERR_BABBLE_DETECTED;
|
||||
utr->status = USBH_ERR_TRANSFER;
|
||||
}
|
||||
else if (itd->Transaction[i] & ITD_STATUS_BUFF_ERR)
|
||||
{
|
||||
utr->iso_status[fidx] = USBH_ERR_DATA_BUFF;
|
||||
utr->status = USBH_ERR_TRANSFER;
|
||||
}
|
||||
else
|
||||
{
|
||||
utr->iso_status[fidx] = USBH_ERR_TRANSACTION;
|
||||
utr->status = USBH_ERR_TRANSFER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
utr->iso_status[fidx] = 0;
|
||||
utr->iso_xlen[fidx] = ITD_XFER_LEN(itd->Transaction[i]);
|
||||
}
|
||||
fidx++;
|
||||
}
|
||||
utr->td_cnt--;
|
||||
|
||||
if (utr->td_cnt == 0) /* All iTD of this UTR done */
|
||||
{
|
||||
utr->bIsTransferDone = 1;
|
||||
if (utr->func)
|
||||
utr->func(utr);
|
||||
}
|
||||
|
||||
return 1; /* to be reclaimed */
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspect the siTD can be reclaimed or not. If yes, collect the transaction results.
|
||||
* Return: 1 - reclaimed
|
||||
* 0 - not completed
|
||||
*/
|
||||
static int review_sitd(siTD_T *sitd)
|
||||
{
|
||||
UTR_T *utr;
|
||||
uint32_t frnidx = sitd->sched_frnidx;
|
||||
uint32_t now_frame = (_ehci->UFINDR >> 3) & 0x3FF;
|
||||
int fidx;
|
||||
uint32_t TotalBytesToTransfer;
|
||||
|
||||
if (now_frame == frnidx)
|
||||
{
|
||||
if (SITD_STATUS(sitd->StsCtrl) == SITD_STATUS_ACTIVE)
|
||||
return 0;
|
||||
}
|
||||
else if (now_frame > frnidx)
|
||||
{
|
||||
if ((now_frame - frnidx) > EHCI_ISO_RCLM_RANGE)
|
||||
return 0; /* don't touch it */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (now_frame + FL_SIZE - frnidx > EHCI_ISO_RCLM_RANGE)
|
||||
return 0; /* don't touch it */
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim this siTD
|
||||
*/
|
||||
utr = sitd->utr;
|
||||
fidx = sitd->fidx;
|
||||
|
||||
if (SITD_STATUS(sitd->StsCtrl))
|
||||
{
|
||||
if (sitd->StsCtrl & SITD_STATUS_ACTIVE)
|
||||
{
|
||||
utr->iso_status[fidx] = USBH_ERR_NOT_ACCESS0;
|
||||
}
|
||||
else if (sitd->StsCtrl & SITD_BABBLE_DETECTED)
|
||||
{
|
||||
utr->iso_status[fidx] = USBH_ERR_BABBLE_DETECTED;
|
||||
utr->status = USBH_ERR_TRANSFER;
|
||||
}
|
||||
else if (sitd->StsCtrl & SITD_STATUS_BUFF_ERR)
|
||||
{
|
||||
utr->iso_status[fidx] = USBH_ERR_DATA_BUFF;
|
||||
utr->status = USBH_ERR_TRANSFER;
|
||||
}
|
||||
else
|
||||
{
|
||||
utr->iso_status[fidx] = USBH_ERR_TRANSACTION;
|
||||
utr->status = USBH_ERR_TRANSFER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TotalBytesToTransfer = (sitd->StsCtrl & SITD_XFER_CNT_Msk) >> SITD_XFER_CNT_Pos;
|
||||
utr->iso_xlen[fidx] = utr->iso_xlen[fidx] - TotalBytesToTransfer;
|
||||
utr->iso_status[fidx] = 0;
|
||||
}
|
||||
utr->td_cnt--;
|
||||
|
||||
if (utr->td_cnt == 0) /* All iTD of this UTR done */
|
||||
{
|
||||
utr->bIsTransferDone = 1;
|
||||
if (utr->func)
|
||||
utr->func(utr);
|
||||
}
|
||||
return 1; /* to be reclaimed */
|
||||
}
|
||||
|
||||
/*
|
||||
* Some iTD/siTD may be scheduled but not serviced due to time missed.
|
||||
* This function scan several earlier frames and drop unserviced iTD/siTD if found.
|
||||
*/
|
||||
void scan_isochronous_list(void)
|
||||
{
|
||||
ISO_EP_T *iso_ep = iso_ep_list;
|
||||
iTD_T *itd, *itd_pre, *p;
|
||||
siTD_T *sitd, *sitd_pre, *sp;
|
||||
uint32_t frnidx;
|
||||
|
||||
DISABLE_EHCI_IRQ();
|
||||
|
||||
while (iso_ep != NULL) /* Search all activated iso endpoints */
|
||||
{
|
||||
/*--------------------------------------------------------------------------------*/
|
||||
/* Scan all iTDs */
|
||||
/*--------------------------------------------------------------------------------*/
|
||||
itd = iso_ep->itd_list; /* get the first iTD from iso_ep's iTD list */
|
||||
itd_pre = NULL;
|
||||
while (itd != NULL) /* traverse all iTDs of itd list */
|
||||
{
|
||||
if (review_itd(itd)) /* inspect and reclaim iTD */
|
||||
{
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Remove this iTD from period frame list */
|
||||
/*------------------------------------------------------------------------*/
|
||||
frnidx = itd->sched_frnidx;
|
||||
if (_PFList[frnidx] == ITD_HLNK_ITD(itd))
|
||||
{
|
||||
/* is the first entry, just change to next */
|
||||
_PFList[frnidx] = itd->Next_Link;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = ITD_PTR(_PFList[frnidx]); /* find the preceding iTD */
|
||||
while ((ITD_PTR(p->Next_Link) != itd) && (p != NULL))
|
||||
{
|
||||
p = ITD_PTR(p->Next_Link);
|
||||
}
|
||||
|
||||
if (p == NULL) /* link list out of control! */
|
||||
{
|
||||
USB_error("An iTD lost refernece to periodic frame list! 0x%x -> %d\n", (int)itd, frnidx);
|
||||
}
|
||||
else /* remove iTD from list */
|
||||
{
|
||||
p->Next_Link = itd->Next_Link;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Remove this iTD from iso_ep's iTD list */
|
||||
/*------------------------------------------------------------------------*/
|
||||
if (itd_pre == NULL)
|
||||
{
|
||||
iso_ep->itd_list = itd->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
itd_pre->next = itd->next;
|
||||
}
|
||||
p = itd->next;
|
||||
free_ehci_iTD(itd);
|
||||
itd = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
itd_pre = itd;
|
||||
itd = itd->next; /* traverse to the next iTD of iTD list */
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------------*/
|
||||
/* Scan all siTDs */
|
||||
/*--------------------------------------------------------------------------------*/
|
||||
sitd = iso_ep->sitd_list; /* get the first siTD from iso_ep's siTD list */
|
||||
sitd_pre = NULL;
|
||||
while (sitd != NULL) /* traverse all siTDs of sitd list */
|
||||
{
|
||||
if (review_sitd(sitd)) /* inspect and reclaim siTD */
|
||||
{
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Remove this siTD from period frame list */
|
||||
/*------------------------------------------------------------------------*/
|
||||
frnidx = sitd->sched_frnidx;
|
||||
if (_PFList[frnidx] == SITD_HLNK_SITD(sitd))
|
||||
{
|
||||
/* is the first entry, just change to next */
|
||||
_PFList[frnidx] = sitd->Next_Link;
|
||||
}
|
||||
else
|
||||
{
|
||||
sp = SITD_PTR(_PFList[frnidx]); /* find the preceding siTD */
|
||||
while ((SITD_PTR(sp->Next_Link) != sitd) && (sp != NULL))
|
||||
{
|
||||
sp = SITD_PTR(sp->Next_Link);
|
||||
}
|
||||
|
||||
if (sp == NULL) /* link list out of control! */
|
||||
{
|
||||
USB_error("An siTD lost reference to periodic frame list! 0x%x -> %d\n", (int)sitd, frnidx);
|
||||
}
|
||||
else /* remove iTD from list */
|
||||
{
|
||||
sp->Next_Link = sitd->Next_Link;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Remove this siTD from iso_ep's siTD list */
|
||||
/*------------------------------------------------------------------------*/
|
||||
if (sitd_pre == NULL)
|
||||
{
|
||||
iso_ep->sitd_list = sitd->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
sitd_pre->next = sitd->next;
|
||||
}
|
||||
sp = sitd->next;
|
||||
free_ehci_siTD(sitd);
|
||||
sitd = sp;
|
||||
}
|
||||
else
|
||||
{
|
||||
sitd_pre = sitd;
|
||||
sitd = sitd->next; /* traverse to the next siTD of siTD list */
|
||||
}
|
||||
}
|
||||
|
||||
iso_ep = iso_ep->next;
|
||||
}
|
||||
|
||||
ENABLE_EHCI_IRQ();
|
||||
}
|
||||
|
||||
|
||||
static void write_itd_info(UTR_T *utr, iTD_T *itd)
|
||||
{
|
||||
UDEV_T *udev = utr->udev;
|
||||
EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
|
||||
uint32_t buff_page_addr;
|
||||
int i;
|
||||
|
||||
buff_page_addr = itd->buff_base & 0xFFFFF000; /* 4K page */
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
itd->Bptr[i] = buff_page_addr + (0x1000 * i);
|
||||
}
|
||||
/* EndPtr R Device Address */
|
||||
itd->Bptr[0] |= (udev->dev_num) | ((ep->bEndpointAddress & 0xF) << ITD_EP_NUM_Pos);
|
||||
itd->Bptr[1] |= ep->wMaxPacketSize; /* Maximum Packet Size */
|
||||
|
||||
if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN) /* I/O */
|
||||
itd->Bptr[1] |= ITD_DIR_IN;
|
||||
else
|
||||
itd->Bptr[1] |= ITD_DIR_OUT;
|
||||
|
||||
itd->Bptr[2] |= (ep->wMaxPacketSize + 1023) / 1024; /* Mult */
|
||||
}
|
||||
|
||||
static void write_itd_micro_frame(UTR_T *utr, int fidx, iTD_T *itd, int mf)
|
||||
{
|
||||
uint32_t buff_addr;
|
||||
|
||||
buff_addr = (uint32_t)(utr->iso_buff[fidx]); /* xfer buffer start address of this frame */
|
||||
|
||||
itd->Transaction[mf] = ITD_STATUS_ACTIVE | /* Status */
|
||||
((utr->iso_xlen[fidx] & 0xFFF) << ITD_XLEN_Pos) | /* Transaction Length */
|
||||
((buff_addr & 0xFFFFF000) - (itd->buff_base & 0xFFFFF000)) | /* PG */
|
||||
(buff_addr & 0xFFF); /* Transaction offset */
|
||||
}
|
||||
|
||||
|
||||
static void remove_iso_ep_from_list(ISO_EP_T *iso_ep)
|
||||
{
|
||||
ISO_EP_T *p;
|
||||
|
||||
if (iso_ep_list == iso_ep)
|
||||
{
|
||||
iso_ep_list = iso_ep->next; /* it's the first entry, remove it */
|
||||
return;
|
||||
}
|
||||
|
||||
p = iso_ep_list; /* find the previous entry of iso_ep */
|
||||
while (p->next != NULL)
|
||||
{
|
||||
if (p->next == iso_ep)
|
||||
{
|
||||
break;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (p->next == NULL)
|
||||
{
|
||||
return; /* not found */
|
||||
}
|
||||
p->next = iso_ep->next; /* remove iso_ep from list */
|
||||
}
|
||||
|
||||
|
||||
static __inline void add_itd_to_iso_ep(ISO_EP_T *iso_ep, iTD_T *itd)
|
||||
{
|
||||
iTD_T *p;
|
||||
|
||||
itd->next = NULL;
|
||||
|
||||
if (iso_ep->itd_list == NULL)
|
||||
{
|
||||
iso_ep->itd_list = itd;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the tail entry of iso_ep->itd_list
|
||||
*/
|
||||
p = iso_ep->itd_list;
|
||||
while (p->next != NULL)
|
||||
{
|
||||
p = p->next;
|
||||
}
|
||||
p->next = itd;
|
||||
}
|
||||
|
||||
int ehci_iso_xfer(UTR_T *utr)
|
||||
{
|
||||
EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
|
||||
ISO_EP_T *iso_ep; /* software iso endpoint descriptor */
|
||||
iTD_T *itd, *itd_next, *itd_list = NULL;
|
||||
int i, itd_cnt;
|
||||
int trans_mask; /* bit mask of used xfer in an iTD */
|
||||
int fidx; /* index to the 8 iso frames of UTR */
|
||||
int interval; /* frame interval of iTD */
|
||||
|
||||
if (ep->hw_pipe != NULL)
|
||||
{
|
||||
iso_ep = (ISO_EP_T *)ep->hw_pipe; /* get reference of the isochronous endpoint */
|
||||
|
||||
if (utr->bIsoNewSched)
|
||||
iso_ep->next_frame = (((_ehci->UFINDR + (EHCI_ISO_DELAY * 8)) & HSUSBH_UFINDR_FI_Msk) >> 3) & 0x3FF;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* first time transfer of this iso endpoint */
|
||||
iso_ep = usbh_alloc_mem(sizeof(*iso_ep));
|
||||
if (iso_ep == NULL)
|
||||
return USBH_ERR_MEMORY_OUT;
|
||||
|
||||
memset(iso_ep, 0, sizeof(*iso_ep));
|
||||
iso_ep->ep = ep;
|
||||
iso_ep->next_frame = (((_ehci->UFINDR + (EHCI_ISO_DELAY * 8)) & HSUSBH_UFINDR_FI_Msk) >> 3) & 0x3FF;
|
||||
|
||||
ep->hw_pipe = iso_ep;
|
||||
|
||||
/*
|
||||
* Add this iso_ep into iso_ep_list
|
||||
*/
|
||||
DISABLE_EHCI_IRQ();
|
||||
iso_ep->next = iso_ep_list;
|
||||
iso_ep_list = iso_ep;
|
||||
ENABLE_EHCI_IRQ();
|
||||
}
|
||||
|
||||
if (utr->udev->speed == SPEED_FULL)
|
||||
return ehci_iso_split_xfer(utr, iso_ep);
|
||||
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
/* Allocate iTDs */
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
|
||||
if (ep->bInterval < 2) /* transfer interval is 1 micro-frame */
|
||||
{
|
||||
trans_mask = 0xFF;
|
||||
itd_cnt = 1; /* required 1 iTD for one UTR */
|
||||
interval = 1; /* iTD frame interval of this endpoint */
|
||||
}
|
||||
else if (ep->bInterval < 4) /* transfer interval is 2 micro-frames */
|
||||
{
|
||||
trans_mask = 0x55;
|
||||
itd_cnt = 2; /* required 2 iTDs for one UTR */
|
||||
interval = 1; /* iTD frame interval of this endpoint */
|
||||
}
|
||||
else if (ep->bInterval < 8) /* transfer interval is 4 micro-frames */
|
||||
{
|
||||
trans_mask = 0x44;
|
||||
itd_cnt = 4; /* required 4 iTDs for one UTR */
|
||||
interval = 1; /* iTD frame interval of this endpoint */
|
||||
}
|
||||
else if (ep->bInterval < 16) /* transfer interval is 8 micro-frames */
|
||||
{
|
||||
trans_mask = 0x08; /* there's 1 transfer in one iTD */
|
||||
itd_cnt = 8; /* required 8 iTDs for one UTR */
|
||||
interval = 1; /* iTD frame interval of this endpoint */
|
||||
}
|
||||
else if (ep->bInterval < 32) /* transfer interval is 16 micro-frames */
|
||||
{
|
||||
trans_mask = 0x10; /* there's 1 transfer in one iTD */
|
||||
itd_cnt = 8; /* required 8 iTDs for one UTR */
|
||||
interval = 2; /* iTD frame interval of this endpoint */
|
||||
}
|
||||
else if (ep->bInterval < 64) /* transfer interval is 32 micro-frames */
|
||||
{
|
||||
trans_mask = 0x02; /* there's 1 transfer in one iTD */
|
||||
itd_cnt = 8; /* required 8 iTDs for one UTR */
|
||||
interval = 4; /* iTD frame interval of this endpoint */
|
||||
}
|
||||
else /* transfer interval is 64 micro-frames */
|
||||
{
|
||||
trans_mask = 0x04; /* there's 1 transfer in one iTD */
|
||||
itd_cnt = 8; /* required 8 iTDs for one UTR */
|
||||
interval = 8; /* iTD frame interval of this endpoint */
|
||||
}
|
||||
|
||||
for (i = 0; i < itd_cnt; i++) /* allocate all iTDs required by UTR */
|
||||
{
|
||||
itd = alloc_ehci_iTD();
|
||||
if (itd == NULL)
|
||||
goto malloc_failed;
|
||||
|
||||
if (itd_list == NULL) /* link all iTDs */
|
||||
{
|
||||
itd_list = itd;
|
||||
}
|
||||
else
|
||||
{
|
||||
itd->next = itd_list;
|
||||
itd_list = itd;
|
||||
}
|
||||
}
|
||||
|
||||
utr->td_cnt = itd_cnt;
|
||||
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
/* Fill and link all iTDs */
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
|
||||
utr->iso_sf = iso_ep->next_frame;
|
||||
fidx = 0; /* index to UTR iso frmes (total IF_PER_UTR) */
|
||||
|
||||
for (itd = itd_list; (itd != NULL);)
|
||||
{
|
||||
if (fidx >= IF_PER_UTR) /* unlikely */
|
||||
{
|
||||
USB_error("EHCI driver ITD bug!?\n");
|
||||
goto malloc_failed;
|
||||
}
|
||||
|
||||
itd->utr = utr;
|
||||
itd->fidx = fidx; /* index to UTR's n'th IF_PER_UTR frame */
|
||||
itd->buff_base = (uint32_t)(utr->iso_buff[fidx]); /* iTD buffer base is buffer of the first UTR iso frame serviced by this iTD */
|
||||
itd->trans_mask = trans_mask;
|
||||
|
||||
write_itd_info(utr, itd);
|
||||
|
||||
for (i = 0; i < 8; i++) /* settle xfer into micro-frames */
|
||||
{
|
||||
if (!(trans_mask & (0x1 << i)))
|
||||
{
|
||||
itd->Transaction[i] = 0; /* not accesed */
|
||||
continue; /* not scheduled micro-frame */
|
||||
}
|
||||
|
||||
write_itd_micro_frame(utr, fidx, itd, i);
|
||||
|
||||
fidx++; /* preceed to next UTR iso frame */
|
||||
|
||||
if (fidx == IF_PER_UTR) /* is the last scheduled micro-frame? */
|
||||
{
|
||||
/* raise interrupt on completed */
|
||||
itd->Transaction[i] |= ITD_IOC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
itd_next = itd->next; /* remember the next itd */
|
||||
|
||||
// USB_debug("Link iTD 0x%x, %d\n", (int)itd, iso_ep->next_frame);
|
||||
/*
|
||||
* Link iTD to period frame list
|
||||
*/
|
||||
DISABLE_EHCI_IRQ();
|
||||
itd->sched_frnidx = iso_ep->next_frame; /* remember it for reclamation scan */
|
||||
add_itd_to_iso_ep(iso_ep, itd); /* add to software itd list */
|
||||
itd->Next_Link = _PFList[itd->sched_frnidx]; /* keep the next link */
|
||||
_PFList[itd->sched_frnidx] = ITD_HLNK_ITD(itd);
|
||||
iso_ep->next_frame = (iso_ep->next_frame + interval) % FL_SIZE;
|
||||
ENABLE_EHCI_IRQ();
|
||||
|
||||
itd = itd_next;
|
||||
}
|
||||
|
||||
_ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */
|
||||
return 0;
|
||||
|
||||
malloc_failed:
|
||||
|
||||
while (itd_list != NULL)
|
||||
{
|
||||
itd = itd_list;
|
||||
itd_list = itd->next;
|
||||
free_ehci_iTD(itd);
|
||||
}
|
||||
return USBH_ERR_MEMORY_OUT;
|
||||
}
|
||||
|
||||
static __inline void add_sitd_to_iso_ep(ISO_EP_T *iso_ep, siTD_T *sitd)
|
||||
{
|
||||
siTD_T *p;
|
||||
|
||||
sitd->next = NULL;
|
||||
|
||||
if (iso_ep->sitd_list == NULL)
|
||||
{
|
||||
iso_ep->sitd_list = sitd;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the tail entry of iso_ep->itd_list
|
||||
*/
|
||||
p = iso_ep->sitd_list;
|
||||
while (p->next != NULL)
|
||||
{
|
||||
p = p->next;
|
||||
}
|
||||
p->next = sitd;
|
||||
}
|
||||
|
||||
static void write_sitd_info(UTR_T *utr, siTD_T *sitd)
|
||||
{
|
||||
UDEV_T *udev = utr->udev;
|
||||
EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
|
||||
uint32_t buff_page_addr;
|
||||
int xlen = utr->iso_xlen[sitd->fidx];
|
||||
int scnt;
|
||||
|
||||
sitd->Chrst = (udev->port_num << SITD_PORT_NUM_Pos) |
|
||||
(udev->parent->iface->udev->dev_num << SITD_HUB_ADDR_Pos) |
|
||||
((ep->bEndpointAddress & 0xF) << SITD_EP_NUM_Pos) |
|
||||
(udev->dev_num << SITD_DEV_ADDR_Pos);
|
||||
|
||||
buff_page_addr = ((uint32_t)utr->iso_buff[sitd->fidx]) & 0xFFFFF000;
|
||||
sitd->Bptr[0] = (uint32_t)(utr->iso_buff[sitd->fidx]);
|
||||
sitd->Bptr[1] = buff_page_addr + 0x1000;
|
||||
|
||||
scnt = (xlen + 187) / 188;
|
||||
|
||||
if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN) /* I/O */
|
||||
{
|
||||
sitd->Chrst |= SITD_XFER_IN;
|
||||
sitd->Sched = (1 << (scnt + 2)) - 1;
|
||||
sitd->Sched = (sitd->Sched << 10) | 0x1;
|
||||
//sitd->Sched <<= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sitd->Chrst |= SITD_XFER_OUT;
|
||||
sitd->Sched = sitd_OUT_Smask[scnt - 1];
|
||||
if (scnt > 1)
|
||||
{
|
||||
sitd->Bptr[1] |= (0x1 << 3); /* Transaction position (TP) 01b: Begin */
|
||||
}
|
||||
sitd->Bptr[1] |= scnt; /* Transaction count (T-Count) */
|
||||
}
|
||||
|
||||
if (sitd->fidx == IF_PER_UTR)
|
||||
{
|
||||
sitd->Sched |= SITD_IOC;
|
||||
}
|
||||
|
||||
sitd->StsCtrl = (xlen << SITD_XFER_CNT_Pos) | SITD_STATUS_ACTIVE;
|
||||
|
||||
sitd->BackLink = SITD_LIST_END;
|
||||
}
|
||||
|
||||
|
||||
static void ehci_sitd_adjust_schedule(siTD_T *sitd)
|
||||
{
|
||||
siTD_T *hlink = (siTD_T *)_PFList[sitd->sched_frnidx];
|
||||
uint32_t uframe_mask = 0x00;
|
||||
|
||||
while (hlink && !HLINK_IS_TERMINATED(hlink) && HLINK_IS_SITD(hlink))
|
||||
{
|
||||
hlink = SITD_PTR(hlink);
|
||||
if (hlink != sitd)
|
||||
{
|
||||
if ((hlink->Chrst & SITD_XFER_IO_Msk) == SITD_XFER_IN)
|
||||
{
|
||||
uframe_mask |= (hlink->Sched & 0xFF); /* mark micro-frames used by IN S-mask */
|
||||
uframe_mask |= ((hlink->Sched >> 8) & 0xFF); /* mark micro-frames used by IN C-mask */
|
||||
}
|
||||
else
|
||||
{
|
||||
uframe_mask |= (hlink->Sched & 0xFF); /* mark micro-frames used by OUT S-mask */
|
||||
}
|
||||
}
|
||||
hlink = SITD_PTR(hlink->Next_Link);
|
||||
}
|
||||
|
||||
uframe_mask = uframe_mask | (uframe_mask << 8); /* mark both S-mask and C-mask */
|
||||
|
||||
if (uframe_mask)
|
||||
{
|
||||
/*
|
||||
* Shift afterward one micro-frame until no conflicts.
|
||||
*/
|
||||
while (1)
|
||||
{
|
||||
if (sitd->Sched & uframe_mask)
|
||||
{
|
||||
sitd->Sched = (sitd->Sched & 0xFFFF0000) | ((sitd->Sched << 1) & 0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
break; /* no conflit, done. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ehci_iso_split_xfer(UTR_T *utr, ISO_EP_T *iso_ep)
|
||||
{
|
||||
EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
|
||||
siTD_T *sitd, *sitd_next, *sitd_list = NULL;
|
||||
int i;
|
||||
int fidx; /* index to the 8 iso frames of UTR */
|
||||
|
||||
if (utr->udev->parent == NULL)
|
||||
{
|
||||
USB_error("siso xfer - parent lost!\n");
|
||||
return USBH_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
/* Allocate siTDs */
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
for (i = 0; i < IF_PER_UTR; i++) /* allocate all siTDs required by UTR */
|
||||
{
|
||||
sitd = alloc_ehci_siTD();
|
||||
if (sitd == NULL)
|
||||
goto malloc_failed;
|
||||
|
||||
if (sitd_list == NULL) /* link all siTDs */
|
||||
{
|
||||
sitd_list = sitd;
|
||||
}
|
||||
else
|
||||
{
|
||||
sitd->next = sitd_list;
|
||||
sitd_list = sitd;
|
||||
}
|
||||
}
|
||||
|
||||
utr->td_cnt = IF_PER_UTR;
|
||||
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
/* Fill and link all siTDs */
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
|
||||
utr->iso_sf = iso_ep->next_frame;
|
||||
fidx = 0; /* index to UTR iso frmes (total IF_PER_UTR) */
|
||||
|
||||
for (sitd = sitd_list; (sitd != NULL); fidx++)
|
||||
{
|
||||
if (fidx >= IF_PER_UTR) /* unlikely */
|
||||
{
|
||||
USB_error("EHCI driver siTD bug!?\n");
|
||||
goto malloc_failed;
|
||||
}
|
||||
|
||||
sitd->utr = utr;
|
||||
sitd->fidx = fidx; /* index to UTR's n'th IF_PER_UTR frame */
|
||||
|
||||
write_sitd_info(utr, sitd);
|
||||
|
||||
sitd_next = sitd->next; /* remember the next itd */
|
||||
|
||||
// USB_debug("Link iTD 0x%x, %d\n", (int)itd, iso_ep->next_frame);
|
||||
/*
|
||||
* Link iTD to period frame list
|
||||
*/
|
||||
sitd->sched_frnidx = iso_ep->next_frame; /* remember it for reclamation scan */
|
||||
DISABLE_EHCI_IRQ();
|
||||
ehci_sitd_adjust_schedule(sitd);
|
||||
add_sitd_to_iso_ep(iso_ep, sitd); /* add to software itd list */
|
||||
sitd->Next_Link = _PFList[sitd->sched_frnidx];/* keep the next link */
|
||||
_PFList[sitd->sched_frnidx] = SITD_HLNK_SITD(sitd);
|
||||
iso_ep->next_frame = (iso_ep->next_frame + ep->bInterval) % FL_SIZE;
|
||||
ENABLE_EHCI_IRQ();
|
||||
|
||||
sitd = sitd_next;
|
||||
}
|
||||
|
||||
_ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */
|
||||
return 0;
|
||||
|
||||
malloc_failed:
|
||||
|
||||
while (sitd_list != NULL)
|
||||
{
|
||||
sitd = sitd_list;
|
||||
sitd_list = sitd->next;
|
||||
free_ehci_siTD(sitd);
|
||||
}
|
||||
return USBH_ERR_MEMORY_OUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* If it's an isochronous endpoint, quit current transfer via UTR or hardware EP.
|
||||
*/
|
||||
int ehci_quit_iso_xfer(UTR_T *utr, EP_INFO_T *ep)
|
||||
{
|
||||
ISO_EP_T *iso_ep;
|
||||
iTD_T *itd, *itd_next, *p;
|
||||
uint32_t frnidx;
|
||||
uint32_t now_frame;
|
||||
|
||||
if (ep == NULL)
|
||||
{
|
||||
if (utr == NULL)
|
||||
return USBH_ERR_NOT_FOUND;
|
||||
|
||||
if (utr->ep == NULL)
|
||||
return USBH_ERR_NOT_FOUND;
|
||||
|
||||
ep = utr->ep;
|
||||
}
|
||||
|
||||
if ((ep->bmAttributes & EP_ATTR_TT_MASK) != EP_ATTR_TT_ISO)
|
||||
return USBH_ERR_NOT_FOUND; /* not isochronous endpoint */
|
||||
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
/* It's an iso endpoint. Remove it as required. */
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
iso_ep = iso_ep_list;
|
||||
while (iso_ep != NULL) /* Search all activated iso endpoints */
|
||||
{
|
||||
if (iso_ep->ep == ep)
|
||||
break;
|
||||
iso_ep = iso_ep->next;
|
||||
}
|
||||
if (iso_ep == NULL)
|
||||
return 0; /* should have been removed */
|
||||
|
||||
itd = iso_ep->itd_list; /* get the first iTD from iso_ep's iTD list */
|
||||
|
||||
while (itd != NULL) /* traverse all iTDs of itd list */
|
||||
{
|
||||
itd_next = itd->next; /* remember the next iTD */
|
||||
utr = itd->utr;
|
||||
|
||||
/*--------------------------------------------------------------------------------*/
|
||||
/* Remove this iTD from period frame list */
|
||||
/*--------------------------------------------------------------------------------*/
|
||||
frnidx = itd->sched_frnidx;
|
||||
|
||||
/*
|
||||
* Prevent to race with Host Controller. If the iTD to be removed is located in
|
||||
* current or next frame, wait until HC passed through it.
|
||||
*/
|
||||
while (1)
|
||||
{
|
||||
now_frame = (_ehci->UFINDR >> 3) & 0x3FF;
|
||||
if ((now_frame == frnidx) || (((now_frame + 1) % 1024) == frnidx))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_PFList[frnidx] == ITD_HLNK_ITD(itd))
|
||||
{
|
||||
/* is the first entry, just change to next */
|
||||
_PFList[frnidx] = itd->Next_Link;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = ITD_PTR(_PFList[frnidx]); /* find the preceding iTD */
|
||||
while ((ITD_PTR(p->Next_Link) != itd) && (p != NULL))
|
||||
{
|
||||
p = ITD_PTR(p->Next_Link);
|
||||
}
|
||||
|
||||
if (p == NULL) /* link list out of control! */
|
||||
{
|
||||
USB_error("ehci_quit_iso_xfer - An iTD lost reference to periodic frame list! 0x%x on %d\n", (int)itd, frnidx);
|
||||
}
|
||||
else /* remove iTD from list */
|
||||
{
|
||||
p->Next_Link = itd->Next_Link;
|
||||
}
|
||||
}
|
||||
|
||||
utr->td_cnt--;
|
||||
|
||||
if (utr->td_cnt == 0) /* All iTD of this UTR done */
|
||||
{
|
||||
utr->bIsTransferDone = 1;
|
||||
if (utr->func)
|
||||
utr->func(utr);
|
||||
utr->status = USBH_ERR_ABORT;
|
||||
}
|
||||
free_ehci_iTD(itd);
|
||||
itd = itd_next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove iso_ep from iso_ep_list
|
||||
*/
|
||||
remove_iso_ep_from_list(iso_ep);
|
||||
usbh_free_mem(iso_ep, sizeof(*iso_ep)); /* free this iso_ep */
|
||||
ep->hw_pipe = NULL;
|
||||
|
||||
if (iso_ep_list == NULL)
|
||||
_ehci->UCMDR &= ~HSUSBH_UCMDR_PSEN_Msk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// @endcond HIDDEN_SYMBOLS
|
||||
|
||||
/*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/
|
|
@ -0,0 +1,540 @@
|
|||
/**************************************************************************//**
|
||||
* @file mem_alloc.c
|
||||
* @version V1.10
|
||||
* $Revision: 11 $
|
||||
* $Date: 14/10/03 1:54p $
|
||||
* @brief USB host library memory allocation functions.
|
||||
*
|
||||
* @note
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
|
||||
/// @cond HIDDEN_SYMBOLS
|
||||
|
||||
//#define MEM_DEBUG
|
||||
|
||||
#ifdef MEM_DEBUG
|
||||
#define mem_debug rt_kprintf
|
||||
#else
|
||||
#define mem_debug(...)
|
||||
#endif
|
||||
|
||||
#ifdef __ICCARM__
|
||||
#pragma data_alignment=1024
|
||||
uint8_t _mem_pool_buff[MEM_POOL_UNIT_NUM][MEM_POOL_UNIT_SIZE];
|
||||
#else
|
||||
uint8_t _mem_pool_buff[MEM_POOL_UNIT_NUM][MEM_POOL_UNIT_SIZE] __attribute__((aligned(1024)));
|
||||
#endif
|
||||
|
||||
static uint8_t *_mem_pool[MEM_POOL_UNIT_NUM];
|
||||
static uint8_t _unit_used[MEM_POOL_UNIT_NUM];
|
||||
|
||||
static volatile int _usbh_mem_used;
|
||||
static volatile int _usbh_max_mem_used;
|
||||
static volatile int _mem_pool_used;
|
||||
|
||||
|
||||
UDEV_T *g_udev_list;
|
||||
|
||||
uint8_t _dev_addr_pool[128];
|
||||
static volatile int _device_addr;
|
||||
|
||||
static int _sidx = 0;;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Memory alloc/free recording */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
void usbh_memory_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sizeof(TD_T) > MEM_POOL_UNIT_SIZE)
|
||||
{
|
||||
USB_error("TD_T - MEM_POOL_UNIT_SIZE too small!\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
if (sizeof(ED_T) > MEM_POOL_UNIT_SIZE)
|
||||
{
|
||||
USB_error("ED_T - MEM_POOL_UNIT_SIZE too small!\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
|
||||
{
|
||||
_unit_used[i] = 0;
|
||||
_mem_pool[i] = (uint8_t *)((uint32_t)&_mem_pool_buff[i] | NON_CACHE_MASK);
|
||||
}
|
||||
|
||||
_usbh_mem_used = 0L;
|
||||
_usbh_max_mem_used = 0L;
|
||||
|
||||
_mem_pool_used = 0;
|
||||
_sidx = 0;
|
||||
|
||||
g_udev_list = NULL;
|
||||
|
||||
memset(_dev_addr_pool, 0, sizeof(_dev_addr_pool));
|
||||
_device_addr = 1;
|
||||
|
||||
USB_InitializeMemoryPool();
|
||||
}
|
||||
|
||||
uint32_t usbh_memory_used(void)
|
||||
{
|
||||
mem_debug("USB static memory: %d/%d, heap used: %d\n", _mem_pool_used, MEM_POOL_UNIT_NUM, _usbh_mem_used);
|
||||
return _usbh_mem_used;
|
||||
}
|
||||
|
||||
static void memory_counter(int size)
|
||||
{
|
||||
_usbh_mem_used += size;
|
||||
if (_usbh_mem_used > _usbh_max_mem_used)
|
||||
_usbh_max_mem_used = _usbh_mem_used;
|
||||
}
|
||||
|
||||
void *usbh_alloc_mem(int size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = USB_malloc(size, 16);
|
||||
if (p == NULL)
|
||||
{
|
||||
USB_error("usbh_alloc_mem failed! %d\n", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(p, 0, size);
|
||||
memory_counter(size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void usbh_free_mem(void *p, int size)
|
||||
{
|
||||
USB_free(p);
|
||||
memory_counter(0 - size);
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* USB device allocate/free */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
UDEV_T *alloc_device(void)
|
||||
{
|
||||
UDEV_T *udev;
|
||||
|
||||
udev = (UDEV_T *)USB_malloc(sizeof(*udev), 16);
|
||||
if (udev == NULL)
|
||||
{
|
||||
USB_error("alloc_device failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(udev, 0, sizeof(*udev));
|
||||
memory_counter(sizeof(*udev));
|
||||
udev->cur_conf = -1; /* must! used to identify the first SET CONFIGURATION */
|
||||
udev->next = g_udev_list; /* chain to global device list */
|
||||
g_udev_list = udev;
|
||||
return udev;
|
||||
}
|
||||
|
||||
void free_device(UDEV_T *udev)
|
||||
{
|
||||
UDEV_T *d;
|
||||
|
||||
if (udev == NULL)
|
||||
return;
|
||||
|
||||
if (udev->cfd_buff != NULL)
|
||||
usbh_free_mem(udev->cfd_buff, MAX_DESC_BUFF_SIZE);
|
||||
|
||||
/*
|
||||
* Remove it from the global device list
|
||||
*/
|
||||
if (g_udev_list == udev)
|
||||
{
|
||||
g_udev_list = g_udev_list->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = g_udev_list;
|
||||
while (d != NULL)
|
||||
{
|
||||
if (d->next == udev)
|
||||
{
|
||||
d->next = udev->next;
|
||||
break;
|
||||
}
|
||||
d = d->next;
|
||||
}
|
||||
}
|
||||
USB_free(udev);
|
||||
memory_counter(-sizeof(*udev));
|
||||
}
|
||||
|
||||
int alloc_dev_address(void)
|
||||
{
|
||||
_device_addr++;
|
||||
|
||||
if (_device_addr >= 128)
|
||||
_device_addr = 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (_dev_addr_pool[_device_addr] == 0)
|
||||
{
|
||||
_dev_addr_pool[_device_addr] = 1;
|
||||
return _device_addr;
|
||||
}
|
||||
_device_addr++;
|
||||
if (_device_addr >= 128)
|
||||
_device_addr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void free_dev_address(int dev_addr)
|
||||
{
|
||||
if (dev_addr < 128)
|
||||
_dev_addr_pool[dev_addr] = 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* UTR (USB Transfer Request) allocate/free */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
UTR_T *alloc_utr(UDEV_T *udev)
|
||||
{
|
||||
#if 0
|
||||
UTR_T *utr, *utr_noncache;
|
||||
|
||||
utr = (UTR_T *)USB_malloc(sizeof(*utr), 16);
|
||||
if (utr == NULL)
|
||||
{
|
||||
USB_error("alloc_utr failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
utr_noncache = (UTR_T *)((uint32_t)utr | NONCACHEABLE);
|
||||
|
||||
memory_counter(sizeof(*utr));
|
||||
memset(utr_noncache, 0, sizeof(*utr));
|
||||
utr_noncache->udev = udev;
|
||||
mem_debug("[ALLOC] [UTR] - 0x%x\n", (int)utr_noncache);
|
||||
return utr_noncache;
|
||||
#else
|
||||
UTR_T *utr;
|
||||
|
||||
utr = (UTR_T *)USB_malloc(sizeof(*utr), 16);
|
||||
if (utr == NULL)
|
||||
{
|
||||
USB_error("alloc_utr failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memory_counter(sizeof(*utr));
|
||||
memset(utr, 0, sizeof(*utr));
|
||||
utr->udev = udev;
|
||||
mem_debug("[ALLOC] [UTR] - 0x%x\n", (int)utr_noncache);
|
||||
return utr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void free_utr(UTR_T *utr)
|
||||
{
|
||||
if (utr == NULL)
|
||||
return;
|
||||
|
||||
mem_debug("[FREE] [UTR] - 0x%x\n", (int)utr);
|
||||
|
||||
#if 0
|
||||
if ((uint32_t)utr & NONCACHEABLE)
|
||||
utr = (UTR_T *)((uint32_t)utr & ~NONCACHEABLE);
|
||||
#endif
|
||||
|
||||
USB_free(utr);
|
||||
memory_counter(0 - (int)sizeof(*utr));
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* OHCI ED allocate/free */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
ED_T *alloc_ohci_ED(void)
|
||||
{
|
||||
int i;
|
||||
ED_T *ed;
|
||||
|
||||
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
|
||||
{
|
||||
if (_unit_used[i] == 0)
|
||||
{
|
||||
_unit_used[i] = 1;
|
||||
_mem_pool_used++;
|
||||
ed = (ED_T *)_mem_pool[i];
|
||||
memset(ed, 0, sizeof(*ed));
|
||||
mem_debug("[ALLOC] [ED] - 0x%x\n", (int)ed);
|
||||
return ed;
|
||||
}
|
||||
}
|
||||
USB_error("alloc_ohci_ED failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_ohci_ED(ED_T *ed)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
|
||||
{
|
||||
if ((uint32_t)_mem_pool[i] == (uint32_t)ed)
|
||||
{
|
||||
mem_debug("[FREE] [ED] - 0x%x\n", (int)ed);
|
||||
_unit_used[i] = 0;
|
||||
_mem_pool_used--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
USB_debug("free_ohci_ED - not found! (ignored in case of multiple UTR)\n");
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* OHCI TD allocate/free */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
TD_T *alloc_ohci_TD(UTR_T *utr)
|
||||
{
|
||||
int i;
|
||||
TD_T *td;
|
||||
|
||||
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
|
||||
{
|
||||
if (_unit_used[i] == 0)
|
||||
{
|
||||
_unit_used[i] = 1;
|
||||
_mem_pool_used++;
|
||||
td = (TD_T *)_mem_pool[i];
|
||||
|
||||
memset(td, 0, sizeof(*td));
|
||||
td->utr = utr;
|
||||
mem_debug("[ALLOC] [TD] - 0x%x\n", (int)td);
|
||||
return td;
|
||||
}
|
||||
}
|
||||
USB_error("alloc_ohci_TD failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_ohci_TD(TD_T *td)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
|
||||
{
|
||||
if ((uint32_t)_mem_pool[i] == (uint32_t)td)
|
||||
{
|
||||
mem_debug("[FREE] [TD] - 0x%x\n", (int)td);
|
||||
_unit_used[i] = 0;
|
||||
_mem_pool_used--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
USB_error("free_ohci_TD - not found!\n");
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* EHCI QH allocate/free */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
QH_T *alloc_ehci_QH(void)
|
||||
{
|
||||
int i;
|
||||
QH_T *qh = NULL;
|
||||
|
||||
for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM)
|
||||
{
|
||||
if (_unit_used[i] == 0)
|
||||
{
|
||||
_unit_used[i] = 1;
|
||||
_sidx = i;
|
||||
_mem_pool_used++;
|
||||
qh = (QH_T *)_mem_pool[i];
|
||||
memset(qh, 0, sizeof(*qh));
|
||||
mem_debug("[ALLOC] [QH] - 0x%x\n", (int)qh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (qh == NULL)
|
||||
{
|
||||
USB_error("alloc_ehci_QH failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
qh->Curr_qTD = QTD_LIST_END;
|
||||
qh->OL_Next_qTD = QTD_LIST_END;
|
||||
qh->OL_Alt_Next_qTD = QTD_LIST_END;
|
||||
qh->OL_Token = QTD_STS_HALT;
|
||||
return qh;
|
||||
}
|
||||
|
||||
void free_ehci_QH(QH_T *qh)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
|
||||
{
|
||||
if ((uint32_t)_mem_pool[i] == (uint32_t)qh)
|
||||
{
|
||||
mem_debug("[FREE] [QH] - 0x%x\n", (int)qh);
|
||||
_unit_used[i] = 0;
|
||||
_mem_pool_used--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
USB_debug("free_ehci_QH - not found! (ignored in case of multiple UTR)\n");
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* EHCI qTD allocate/free */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
qTD_T *alloc_ehci_qTD(UTR_T *utr)
|
||||
{
|
||||
int i;
|
||||
qTD_T *qtd;
|
||||
|
||||
for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM)
|
||||
{
|
||||
if (_unit_used[i] == 0)
|
||||
{
|
||||
_unit_used[i] = 1;
|
||||
_sidx = i;
|
||||
_mem_pool_used++;
|
||||
qtd = (qTD_T *)_mem_pool[i];
|
||||
|
||||
memset(qtd, 0, sizeof(*qtd));
|
||||
qtd->Next_qTD = QTD_LIST_END;
|
||||
qtd->Alt_Next_qTD = QTD_LIST_END;
|
||||
qtd->Token = 0x1197B7F; // QTD_STS_HALT; visit_qtd() will not remove a qTD with this mark. It means the qTD still not ready for transfer.
|
||||
qtd->utr = utr;
|
||||
mem_debug("[ALLOC] [qTD] - 0x%x\n", (int)qtd);
|
||||
return qtd;
|
||||
}
|
||||
}
|
||||
USB_error("alloc_ehci_qTD failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_ehci_qTD(qTD_T *qtd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
|
||||
{
|
||||
if ((uint32_t)_mem_pool[i] == (uint32_t)qtd)
|
||||
{
|
||||
mem_debug("[FREE] [qTD] - 0x%x\n", (int)qtd);
|
||||
_unit_used[i] = 0;
|
||||
_mem_pool_used--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
USB_error("free_ehci_qTD 0x%x - not found!\n", (int)qtd);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* EHCI iTD allocate/free */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
iTD_T *alloc_ehci_iTD(void)
|
||||
{
|
||||
int i;
|
||||
iTD_T *itd;
|
||||
|
||||
for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM)
|
||||
{
|
||||
if (i + 2 >= MEM_POOL_UNIT_NUM)
|
||||
continue;
|
||||
|
||||
if ((_unit_used[i] == 0) && (_unit_used[i + 1] == 0))
|
||||
{
|
||||
_unit_used[i] = _unit_used[i + 1] = 1;
|
||||
_sidx = i + 1;
|
||||
_mem_pool_used += 2;
|
||||
itd = (iTD_T *)_mem_pool[i];
|
||||
memset(itd, 0, sizeof(*itd));
|
||||
mem_debug("[ALLOC] [iTD] - 0x%x\n", (int)itd);
|
||||
return itd;
|
||||
}
|
||||
}
|
||||
USB_error("alloc_ehci_iTD failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_ehci_iTD(iTD_T *itd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i + 1 < MEM_POOL_UNIT_NUM; i++)
|
||||
{
|
||||
if ((uint32_t)_mem_pool[i] == (uint32_t)itd)
|
||||
{
|
||||
mem_debug("[FREE] [iTD] - 0x%x\n", (int)itd);
|
||||
_unit_used[i] = _unit_used[i + 1] = 0;
|
||||
_mem_pool_used -= 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
USB_error("free_ehci_iTD 0x%x - not found!\n", (int)itd);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* EHCI iTD allocate/free */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
siTD_T *alloc_ehci_siTD(void)
|
||||
{
|
||||
int i;
|
||||
siTD_T *sitd;
|
||||
|
||||
for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM)
|
||||
{
|
||||
if (_unit_used[i] == 0)
|
||||
{
|
||||
_unit_used[i] = 1;
|
||||
_sidx = i;
|
||||
_mem_pool_used ++;
|
||||
sitd = (siTD_T *)_mem_pool[i];
|
||||
memset(sitd, 0, sizeof(*sitd));
|
||||
mem_debug("[ALLOC] [siTD] - 0x%x\n", (int)sitd);
|
||||
return sitd;
|
||||
}
|
||||
}
|
||||
USB_error("alloc_ehci_siTD failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_ehci_siTD(siTD_T *sitd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
|
||||
{
|
||||
if ((uint32_t)_mem_pool[i] == (uint32_t)sitd)
|
||||
{
|
||||
mem_debug("[FREE] [siTD] - 0x%x\n", (int)sitd);
|
||||
_unit_used[i] = 0;
|
||||
_mem_pool_used--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
USB_error("free_ehci_siTD 0x%x - not found!\n", (int)sitd);
|
||||
}
|
||||
|
||||
/// @endcond HIDDEN_SYMBOLS
|
||||
|
||||
/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,324 @@
|
|||
/**************************************************************************//**
|
||||
* @file support.c
|
||||
* @version V1.10
|
||||
* $Revision: 11 $
|
||||
* $Date: 14/10/03 1:54p $
|
||||
* @brief Functions to support USB host driver.
|
||||
*
|
||||
* @note
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
/// @cond HIDDEN_SYMBOLS
|
||||
|
||||
|
||||
#define USB_MEMORY_POOL_SIZE (32*1024)
|
||||
#define USB_MEM_BLOCK_SIZE 128
|
||||
|
||||
#define BOUNDARY_WORD 4
|
||||
|
||||
|
||||
static uint32_t _FreeMemorySize;
|
||||
uint32_t _AllocatedMemorySize;
|
||||
|
||||
|
||||
#define USB_MEM_ALLOC_MAGIC 0x19685788 /* magic number in leading block */
|
||||
|
||||
typedef struct USB_mhdr
|
||||
{
|
||||
uint32_t flag; /* 0:free, 1:allocated, 0x3:first block */
|
||||
uint32_t bcnt; /* if allocated, the block count of allocated memory block */
|
||||
uint32_t magic;
|
||||
uint32_t reserved;
|
||||
} USB_MHDR_T;
|
||||
|
||||
uint8_t _USBMemoryPool[USB_MEMORY_POOL_SIZE] __attribute__((aligned(USB_MEM_BLOCK_SIZE)));
|
||||
|
||||
|
||||
static USB_MHDR_T *_pCurrent;
|
||||
uint32_t *_USB_pCurrent = (uint32_t *) &_pCurrent;
|
||||
|
||||
static uint32_t _MemoryPoolBase, _MemoryPoolEnd;
|
||||
|
||||
|
||||
void USB_InitializeMemoryPool()
|
||||
{
|
||||
_MemoryPoolBase = (UINT32)&_USBMemoryPool[0] | NON_CACHE_MASK;
|
||||
_MemoryPoolEnd = _MemoryPoolBase + USB_MEMORY_POOL_SIZE;
|
||||
_FreeMemorySize = _MemoryPoolEnd - _MemoryPoolBase;
|
||||
_AllocatedMemorySize = 0;
|
||||
_pCurrent = (USB_MHDR_T *)_MemoryPoolBase;
|
||||
memset((char *)_MemoryPoolBase, 0, _FreeMemorySize);
|
||||
}
|
||||
|
||||
|
||||
int USB_available_memory()
|
||||
{
|
||||
return _FreeMemorySize;
|
||||
}
|
||||
|
||||
|
||||
int USB_allocated_memory()
|
||||
{
|
||||
return _AllocatedMemorySize;
|
||||
}
|
||||
|
||||
|
||||
void *USB_malloc(INT wanted_size, INT boundary)
|
||||
{
|
||||
USB_MHDR_T *pPrimitivePos = _pCurrent;
|
||||
USB_MHDR_T *pFound;
|
||||
INT found_size = -1;
|
||||
INT i, block_count;
|
||||
INT wrap = 0;
|
||||
int disable_ohci_irq, disable_ehci_irq;
|
||||
|
||||
if (IS_OHCI_IRQ_ENABLED())
|
||||
disable_ohci_irq = 1;
|
||||
else
|
||||
disable_ohci_irq = 0;
|
||||
|
||||
if (IS_EHCI_IRQ_ENABLED())
|
||||
disable_ehci_irq = 1;
|
||||
else
|
||||
disable_ehci_irq = 0;
|
||||
|
||||
if (disable_ohci_irq)
|
||||
DISABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
DISABLE_EHCI_IRQ();
|
||||
|
||||
if (wanted_size >= _FreeMemorySize)
|
||||
{
|
||||
rt_kprintf("USB_malloc - want=%d, free=%d\n", wanted_size, _FreeMemorySize);
|
||||
if (disable_ohci_irq)
|
||||
ENABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
ENABLE_EHCI_IRQ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((UINT32)_pCurrent >= _MemoryPoolEnd)
|
||||
_pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */
|
||||
|
||||
do
|
||||
{
|
||||
if (_pCurrent->flag) /* is not a free block */
|
||||
{
|
||||
if (_pCurrent->magic != USB_MEM_ALLOC_MAGIC)
|
||||
{
|
||||
rt_kprintf("\nUSB_malloc - incorrect magic number! C:%x F:%x, wanted:%d, Base:0x%x, End:0x%x\n", (UINT32)_pCurrent, _FreeMemorySize, wanted_size, (UINT32)_MemoryPoolBase, (UINT32)_MemoryPoolEnd);
|
||||
if (disable_ohci_irq)
|
||||
ENABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
ENABLE_EHCI_IRQ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_pCurrent->flag == 0x3)
|
||||
_pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + _pCurrent->bcnt * USB_MEM_BLOCK_SIZE);
|
||||
else
|
||||
{
|
||||
rt_kprintf("USB_malloc warning - not the first block!\n");
|
||||
_pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if ((UINT32)_pCurrent > _MemoryPoolEnd)
|
||||
rt_kprintf("USB_malloc - behind limit!!\n");
|
||||
|
||||
if ((UINT32)_pCurrent == _MemoryPoolEnd)
|
||||
{
|
||||
//rt_kprintf("USB_alloc - warp!!\n");
|
||||
wrap = 1;
|
||||
_pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */
|
||||
}
|
||||
|
||||
found_size = -1; /* reset the accumlator */
|
||||
}
|
||||
else /* is a free block */
|
||||
{
|
||||
if (found_size == -1) /* the leading block */
|
||||
{
|
||||
pFound = _pCurrent;
|
||||
block_count = 1;
|
||||
|
||||
if (boundary > BOUNDARY_WORD)
|
||||
found_size = 0; /* not use the data area of the leading block */
|
||||
else
|
||||
found_size = USB_MEM_BLOCK_SIZE - sizeof(USB_MHDR_T);
|
||||
|
||||
/* check boundary -
|
||||
* If boundary > BOUNDARY_WORD, the start of next block should
|
||||
* be the beginning address of allocated memory. Thus, we check
|
||||
* the boundary of the next block. The leading block will be
|
||||
* used as a header only.
|
||||
*/
|
||||
if ((boundary > BOUNDARY_WORD) &&
|
||||
((((UINT32)_pCurrent) + USB_MEM_BLOCK_SIZE >= _MemoryPoolEnd) ||
|
||||
((((UINT32)_pCurrent) + USB_MEM_BLOCK_SIZE) % boundary != 0)))
|
||||
found_size = -1; /* violate boundary, reset the accumlator */
|
||||
}
|
||||
else /* not the leading block */
|
||||
{
|
||||
found_size += USB_MEM_BLOCK_SIZE;
|
||||
block_count++;
|
||||
}
|
||||
|
||||
if (found_size >= wanted_size)
|
||||
{
|
||||
pFound->bcnt = block_count;
|
||||
pFound->magic = USB_MEM_ALLOC_MAGIC;
|
||||
_FreeMemorySize -= block_count * USB_MEM_BLOCK_SIZE;
|
||||
_AllocatedMemorySize += block_count * USB_MEM_BLOCK_SIZE;
|
||||
_pCurrent = pFound;
|
||||
for (i = 0; i < block_count; i++)
|
||||
{
|
||||
_pCurrent->flag = 1; /* allocate block */
|
||||
_pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE);
|
||||
}
|
||||
pFound->flag = 0x3;
|
||||
|
||||
if (boundary > BOUNDARY_WORD)
|
||||
{
|
||||
if (disable_ohci_irq)
|
||||
ENABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
ENABLE_EHCI_IRQ();
|
||||
//rt_kprintf("- 0x%x, %d\n", (int)pFound, wanted_size);
|
||||
return (void *)((UINT32)pFound + USB_MEM_BLOCK_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//USB_debug("USB_malloc(%d,%d):%x\tsize:%d, C:0x%x, %d\n", wanted_size, boundary, (UINT32)pFound + sizeof(USB_MHDR_T), block_count * USB_MEM_BLOCK_SIZE, _pCurrent, block_count);
|
||||
if (disable_ohci_irq)
|
||||
ENABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
ENABLE_EHCI_IRQ();
|
||||
//rt_kprintf("- 0x%x, %d\n", (int)pFound, wanted_size);
|
||||
return (void *)((UINT32)pFound + sizeof(USB_MHDR_T));
|
||||
}
|
||||
}
|
||||
|
||||
/* advance to the next block */
|
||||
_pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE);
|
||||
if ((UINT32)_pCurrent >= _MemoryPoolEnd)
|
||||
{
|
||||
wrap = 1;
|
||||
_pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */
|
||||
found_size = -1; /* reset accumlator */
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((wrap == 0) || (_pCurrent < pPrimitivePos));
|
||||
|
||||
rt_kprintf("USB_malloc - No free memory!\n");
|
||||
if (disable_ohci_irq)
|
||||
ENABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
ENABLE_EHCI_IRQ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void USB_free(void *alloc_addr)
|
||||
{
|
||||
USB_MHDR_T *pMblk;
|
||||
UINT32 addr = (UINT32)alloc_addr;
|
||||
INT i, count;
|
||||
int disable_ohci_irq, disable_ehci_irq;
|
||||
|
||||
if (IS_OHCI_IRQ_ENABLED())
|
||||
disable_ohci_irq = 1;
|
||||
else
|
||||
disable_ohci_irq = 0;
|
||||
|
||||
if (IS_EHCI_IRQ_ENABLED())
|
||||
disable_ehci_irq = 1;
|
||||
else
|
||||
disable_ehci_irq = 0;
|
||||
|
||||
//rt_kprintf("USB_free: 0x%x\n", (int)alloc_addr);
|
||||
|
||||
if ((addr < _MemoryPoolBase) || (addr >= _MemoryPoolEnd))
|
||||
{
|
||||
if (addr)
|
||||
{
|
||||
rt_kprintf("[%s]Wrong!!\n", __func__);
|
||||
//free(alloc_addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (disable_ohci_irq)
|
||||
DISABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
DISABLE_EHCI_IRQ();
|
||||
|
||||
//rt_kprintf("USB_free:%x\n", (INT)addr+USB_MEM_BLOCK_SIZE);
|
||||
|
||||
/* get the leading block address */
|
||||
if (addr % USB_MEM_BLOCK_SIZE == 0)
|
||||
addr -= USB_MEM_BLOCK_SIZE;
|
||||
else
|
||||
addr -= sizeof(USB_MHDR_T);
|
||||
|
||||
if (addr % USB_MEM_BLOCK_SIZE != 0)
|
||||
{
|
||||
rt_kprintf("USB_free fatal error on address: %x!!\n", (UINT32)alloc_addr);
|
||||
if (disable_ohci_irq)
|
||||
ENABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
ENABLE_EHCI_IRQ();
|
||||
return;
|
||||
}
|
||||
|
||||
pMblk = (USB_MHDR_T *)addr;
|
||||
if (pMblk->flag == 0)
|
||||
{
|
||||
rt_kprintf("USB_free(), warning - try to free a free block: %x\n", (UINT32)alloc_addr);
|
||||
if (disable_ohci_irq)
|
||||
ENABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
ENABLE_EHCI_IRQ();
|
||||
return;
|
||||
}
|
||||
if (pMblk->magic != USB_MEM_ALLOC_MAGIC)
|
||||
{
|
||||
rt_kprintf("USB_free(), warning - try to free an unknow block at address:%x.\n", addr);
|
||||
if (disable_ohci_irq)
|
||||
ENABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
ENABLE_EHCI_IRQ();
|
||||
return;
|
||||
}
|
||||
|
||||
//_pCurrent = pMblk;
|
||||
|
||||
//rt_kprintf("+ 0x%x, %d\n", (int)pMblk, pMblk->bcnt);
|
||||
|
||||
count = pMblk->bcnt;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
pMblk->flag = 0; /* release block */
|
||||
pMblk = (USB_MHDR_T *)((UINT32)pMblk + USB_MEM_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
_FreeMemorySize += count * USB_MEM_BLOCK_SIZE;
|
||||
_AllocatedMemorySize -= count * USB_MEM_BLOCK_SIZE;
|
||||
if (disable_ohci_irq)
|
||||
ENABLE_OHCI_IRQ();
|
||||
if (disable_ehci_irq)
|
||||
ENABLE_EHCI_IRQ();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/// @endcond HIDDEN_SYMBOLS
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
/**************************************************************************//**
|
||||
* @file usb_core.c
|
||||
* @version V1.10
|
||||
* $Revision: 11 $
|
||||
* $Date: 14/10/03 1:54p $
|
||||
* @brief USB Host library core.
|
||||
*
|
||||
* @note
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "hub.h"
|
||||
|
||||
|
||||
/// @cond HIDDEN_SYMBOLS
|
||||
|
||||
USBH_T *_ohci;
|
||||
HSUSBH_T *_ehci;
|
||||
|
||||
static UDEV_DRV_T *_drivers[MAX_UDEV_DRIVER];
|
||||
|
||||
static CONN_FUNC *g_conn_func, *g_disconn_func;
|
||||
|
||||
|
||||
//extern void EHCI_IRQHandler(void);
|
||||
//extern void OHCI_IRQHandler(void);
|
||||
extern void nu_ohci_isr(int vector, void *param);
|
||||
extern void nu_ehci_isr(int vector, void *param);
|
||||
|
||||
|
||||
/// @endcond HIDDEN_SYMBOLS
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize NUC980 USB Host controller and USB stack.
|
||||
*
|
||||
* @return None.
|
||||
*/
|
||||
void usbh_core_init()
|
||||
{
|
||||
DISABLE_EHCI_IRQ();
|
||||
DISABLE_OHCI_IRQ();
|
||||
|
||||
_ohci = USBH;
|
||||
_ehci = HSUSBH;
|
||||
|
||||
memset(_drivers, 0, sizeof(_drivers));
|
||||
|
||||
g_conn_func = NULL;
|
||||
g_disconn_func = NULL;
|
||||
|
||||
// usbh_hub_init();
|
||||
|
||||
_ehci->USBPCR0 = 0x160; /* enable PHY 0 */
|
||||
_ehci->USBPCR1 = 0x520; /* enable PHY 1 */
|
||||
usbh_memory_init();
|
||||
|
||||
//_ohci->HcMiscControl |= USBH_HcMiscControl_OCAL_Msk; /* Over-current active low */
|
||||
_ohci->HcMiscControl &= ~USBH_HcMiscControl_OCAL_Msk; /* Over-current active high */
|
||||
|
||||
#ifdef ENABLE_OHCI
|
||||
//sysInstallISR(IRQ_LEVEL_1, IRQ_OHCI, (PVOID)OHCI_IRQHandler);
|
||||
rt_hw_interrupt_install(IRQ_OHCI, nu_ohci_isr, NULL, "ohci");
|
||||
rt_hw_interrupt_set_priority(IRQ_OHCI, IRQ_LEVEL_1);
|
||||
|
||||
ohci_driver.init();
|
||||
ENABLE_OHCI_IRQ();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_EHCI
|
||||
//sysInstallISR(IRQ_LEVEL_1, IRQ_EHCI, (PVOID)EHCI_IRQHandler);
|
||||
rt_hw_interrupt_install(IRQ_EHCI, nu_ehci_isr, NULL, "ehci");
|
||||
rt_hw_interrupt_set_priority(IRQ_EHCI, IRQ_LEVEL_1);
|
||||
|
||||
ehci_driver.init();
|
||||
ENABLE_EHCI_IRQ();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Let USB stack polls all root hubs. If there's any hub port
|
||||
* change found, USB stack will manage the hub events in this function call.
|
||||
* In this function, USB stack enumerates newly connected devices and remove staff
|
||||
* of disconnected devices. User's application should periodically invoke this
|
||||
* function.
|
||||
* @return There's hub port change or not.
|
||||
* @retval 0 No any hub port status changes found.
|
||||
* @retval 1 There's hub port status changes.
|
||||
*/
|
||||
int usbh_polling_root_hubs(void)
|
||||
{
|
||||
int ret, change = 0;
|
||||
|
||||
#ifdef ENABLE_EHCI
|
||||
do
|
||||
{
|
||||
ret = ehci_driver.rthub_polling();
|
||||
if (ret)
|
||||
change = 1;
|
||||
}
|
||||
while (ret == 1);
|
||||
|
||||
// scan_isochronous_list();
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_OHCI
|
||||
do
|
||||
{
|
||||
ret = ohci_driver.rthub_polling();
|
||||
if (ret)
|
||||
change = 1;
|
||||
}
|
||||
while (ret == 1);
|
||||
#endif
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Force to quit an endpoint transfer.
|
||||
* @param[in] udev The USB device.
|
||||
* @param[in] ep The endpoint to be quit.
|
||||
* @retval 0 Transfer success
|
||||
* @retval < 0 Failed. Refer to error code definitions.
|
||||
*/
|
||||
int usbh_quit_xfer(UDEV_T *udev, EP_INFO_T *ep)
|
||||
{
|
||||
return udev->hc_driver->quit_xfer(NULL, ep);
|
||||
}
|
||||
|
||||
|
||||
int usbh_connect_device(UDEV_T *udev)
|
||||
{
|
||||
usbh_delay_ms(100); /* initially, give 100 ms delay */
|
||||
|
||||
if (g_conn_func)
|
||||
g_conn_func(udev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void usbh_disconnect_device(UDEV_T *udev)
|
||||
{
|
||||
USB_debug("disconnect device...\n");
|
||||
|
||||
if (g_disconn_func)
|
||||
g_disconn_func(udev, 0);
|
||||
|
||||
|
||||
#if 1 //CHECK: Maybe create a new API to quit_xfer and free udev for application
|
||||
usbh_quit_xfer(udev, &(udev->ep0)); /* Quit control transfer if hw_pipe is not NULL. */
|
||||
|
||||
/* remove device from global device list */
|
||||
// free_dev_address(udev->dev_num);
|
||||
free_device(udev);
|
||||
|
||||
// usbh_memory_used();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Install device connect and disconnect callback function.
|
||||
*
|
||||
* @param[in] conn_func Device connect callback function.
|
||||
* @param[in] disconn_func Device disconnect callback function.
|
||||
* @return None.
|
||||
*/
|
||||
void usbh_install_conn_callback(CONN_FUNC *conn_func, CONN_FUNC *disconn_func)
|
||||
{
|
||||
g_conn_func = conn_func;
|
||||
g_disconn_func = disconn_func;
|
||||
}
|
||||
|
||||
int usbh_reset_port(UDEV_T *udev)
|
||||
{
|
||||
if (udev->parent == NULL)
|
||||
{
|
||||
if (udev->hc_driver)
|
||||
return udev->hc_driver->rthub_port_reset(udev->port_num - 1);
|
||||
else
|
||||
return USBH_ERR_NOT_FOUND;
|
||||
}
|
||||
else
|
||||
{
|
||||
return udev->parent->port_reset(udev->parent, udev->port_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Force to quit an UTR transfer.
|
||||
* @param[in] utr The UTR transfer to be quit.
|
||||
* @retval 0 Transfer success
|
||||
* @retval < 0 Failed. Refer to error code definitions.
|
||||
*/
|
||||
int usbh_quit_utr(UTR_T *utr)
|
||||
{
|
||||
if (!utr || !utr->udev)
|
||||
return USBH_ERR_NOT_FOUND;
|
||||
|
||||
return utr->udev->hc_driver->quit_xfer(utr, NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Execute an USB request in control transfer. This function returns after the request
|
||||
* was done or aborted.
|
||||
* @param[in] udev The target USB device.
|
||||
* @param[in] bmRequestType Characteristics of request
|
||||
* @param[in] bRequest Specific request
|
||||
* @param[in] wValue Word-sized field that varies according to request
|
||||
* @param[in] wIndex Word-sized field that varies according to request
|
||||
* @param[in] wLength Number of bytes to transfer if there is a Data stage
|
||||
* @param[in] buff Data buffer used in data stage
|
||||
* @param[out] xfer_len Transmitted/received length of data
|
||||
* @param[in] timeout Time-out limit (in 10ms - timer tick) of this transfer
|
||||
* @retval 0 Transfer success
|
||||
* @retval < 0 Transfer failed. Refer to error code definitions.
|
||||
*/
|
||||
int usbh_ctrl_xfer(UDEV_T *udev, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
|
||||
uint16_t wLength, uint8_t *buff, uint32_t *xfer_len, uint32_t timeout)
|
||||
{
|
||||
UTR_T *utr;
|
||||
uint32_t t0, timeout_tick;
|
||||
int status;
|
||||
|
||||
*xfer_len = 0;
|
||||
|
||||
//if (check_device(udev))
|
||||
// return USBH_ERR_INVALID_PARAM;
|
||||
|
||||
utr = alloc_utr(udev);
|
||||
if (utr == NULL)
|
||||
return USBH_ERR_MEMORY_OUT;
|
||||
|
||||
utr->setup.bmRequestType = bmRequestType;
|
||||
utr->setup.bRequest = bRequest;
|
||||
utr->setup.wValue = wValue;
|
||||
utr->setup.wIndex = wIndex;
|
||||
utr->setup.wLength = wLength;
|
||||
|
||||
utr->buff = buff;
|
||||
utr->data_len = wLength;
|
||||
utr->bIsTransferDone = 0;
|
||||
status = udev->hc_driver->ctrl_xfer(utr);
|
||||
if (status < 0)
|
||||
{
|
||||
udev->ep0.hw_pipe = NULL;
|
||||
free_utr(utr);
|
||||
return status;
|
||||
}
|
||||
|
||||
timeout_tick = usbh_tick_from_millisecond(timeout);
|
||||
t0 = usbh_get_ticks();
|
||||
while (utr->bIsTransferDone == 0)
|
||||
{
|
||||
if (usbh_get_ticks() - t0 > timeout_tick)
|
||||
{
|
||||
usbh_quit_utr(utr);
|
||||
free_utr(utr);
|
||||
udev->ep0.hw_pipe = NULL;
|
||||
return USBH_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
status = utr->status;
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
*xfer_len = utr->xfer_len;
|
||||
}
|
||||
free_utr(utr);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Execute a bulk transfer request. This function will return immediately after
|
||||
* issued the bulk transfer. USB stack will later call back utr->func() once the bulk
|
||||
* transfer was done or aborted.
|
||||
* @param[in] utr The bulk transfer request.
|
||||
* @retval 0 Transfer success
|
||||
* @retval < 0 Failed. Refer to error code definitions.
|
||||
*/
|
||||
int usbh_bulk_xfer(UTR_T *utr)
|
||||
{
|
||||
return utr->udev->hc_driver->bulk_xfer(utr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Execute an interrupt transfer request. This function will return immediately after
|
||||
* issued the interrupt transfer. USB stack will later call back utr->func() once the
|
||||
* interrupt transfer was done or aborted.
|
||||
* @param[in] utr The interrupt transfer request.
|
||||
* @retval 0 Transfer success
|
||||
* @retval < 0 Failed. Refer to error code definitions.
|
||||
*/
|
||||
int usbh_int_xfer(UTR_T *utr)
|
||||
{
|
||||
return utr->udev->hc_driver->int_xfer(utr);
|
||||
}
|
||||
|
||||
|
|
@ -114,13 +114,6 @@ config SOC_SERIES_NUC980
|
|||
help
|
||||
Choose this option if you need TIMER function mode.
|
||||
|
||||
config BSP_USING_TPWM0
|
||||
select BSP_USING_TPWM
|
||||
select RT_USING_PWM
|
||||
bool "TIMER PWM"
|
||||
help
|
||||
Choose this option if you need PWM function mode.
|
||||
|
||||
config BSP_USING_TIMER0_CAPTURE
|
||||
select BSP_USING_TIMER_CAPTURE
|
||||
select RT_USING_INPUT_CAPTURE
|
||||
|
@ -146,13 +139,6 @@ config SOC_SERIES_NUC980
|
|||
help
|
||||
Choose this option if you need TIMER function mode.
|
||||
|
||||
config BSP_USING_TPWM1
|
||||
select BSP_USING_TPWM
|
||||
select RT_USING_PWM
|
||||
bool "TIMER PWM"
|
||||
help
|
||||
Choose this option if you need PWM function mode.
|
||||
|
||||
config BSP_USING_TIMER1_CAPTURE
|
||||
select BSP_USING_TIMER_CAPTURE
|
||||
select RT_USING_INPUT_CAPTURE
|
||||
|
@ -177,13 +163,6 @@ config SOC_SERIES_NUC980
|
|||
help
|
||||
Choose this option if you need TIMER function mode.
|
||||
|
||||
config BSP_USING_TPWM2
|
||||
select BSP_USING_TPWM
|
||||
select RT_USING_PWM
|
||||
bool "TIMER PWM"
|
||||
help
|
||||
Choose this option if you need PWM function mode.
|
||||
|
||||
config BSP_USING_TIMER2_CAPTURE
|
||||
select BSP_USING_TIMER_CAPTURE
|
||||
select RT_USING_INPUT_CAPTURE
|
||||
|
@ -208,13 +187,6 @@ config SOC_SERIES_NUC980
|
|||
help
|
||||
Choose this option if you need TIMER function mode.
|
||||
|
||||
config BSP_USING_TPWM3
|
||||
select BSP_USING_TPWM
|
||||
select RT_USING_PWM
|
||||
bool "TIMER PWM"
|
||||
help
|
||||
Choose this option if you need PWM function mode.
|
||||
|
||||
config BSP_USING_TIMER3_CAPTURE
|
||||
select BSP_USING_TIMER_CAPTURE
|
||||
select RT_USING_INPUT_CAPTURE
|
||||
|
@ -239,13 +211,6 @@ config SOC_SERIES_NUC980
|
|||
help
|
||||
Choose this option if you need TIMER function mode.
|
||||
|
||||
config BSP_USING_TPWM4
|
||||
select BSP_USING_TPWM
|
||||
select RT_USING_PWM
|
||||
bool "TIMER PWM"
|
||||
help
|
||||
Choose this option if you need PWM function mode.
|
||||
|
||||
config BSP_USING_TIMER4_CAPTURE
|
||||
select BSP_USING_TIMER_CAPTURE
|
||||
select RT_USING_INPUT_CAPTURE
|
||||
|
@ -634,9 +599,4 @@ config SOC_SERIES_NUC980
|
|||
config BSP_USING_USBH
|
||||
bool "Enable USB Host Controller(USBH)"
|
||||
select RT_USING_USB_HOST
|
||||
select RT_USBH_MSTORAGE
|
||||
|
||||
config BSP_USING_OTG
|
||||
bool "Enable USB On-The-Go(OTG)"
|
||||
select BSP_USING_USBH
|
||||
select BSP_USING_USBD
|
||||
select RT_USBH_MSTORAGE
|
|
@ -9,6 +9,6 @@ CPPPATH = [cwd]
|
|||
group = []
|
||||
|
||||
# USB driver constrain
|
||||
group = DefineGroup('nuc980_rttport', src, depend = [''], CPPPATH = CPPPATH)
|
||||
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
|
|
@ -22,22 +22,11 @@ static struct mem_desc hw_mem_desc[] =
|
|||
{ 0x00000000, 0xFFFFFFFF, 0x00000000, RW_NCNB }, /* None cached for 4G memory */
|
||||
{ 0x00000000, BOARD_SDRAM_SIZE - 1, 0x00000000, RW_CB }, /* 64M cached DDR memory */
|
||||
{ BIT31, (BIT31 | BOARD_SDRAM_SIZE) - 1, BIT31, RW_NCNB }, /* Shadow DDR Map */
|
||||
{ 0x3C000000, 0x3C00E000 - 1, 0x3C000000, RW_NCNB }, /* 56K SRAM memory */
|
||||
{ 0xBC000000, 0xBC00E000 - 1, 0xBC000000, RW_NCNB } /* 56K Shadow memory */
|
||||
{ 0x3C000000, 0x3C004000 - 1, 0x3C000000, RW_NCNB }, /* 16K SRAM memory */
|
||||
{ 0xBC000000, 0xBC004000 - 1, 0xBC000000, RW_NCNB } /* 16K Shadow memory */
|
||||
};
|
||||
#endif
|
||||
|
||||
void nu_clock_base_dump(void)
|
||||
{
|
||||
rt_kprintf("SYS_UPLL = %d\n", sysGetClock(SYS_UPLL));
|
||||
rt_kprintf("SYS_APLL = %d\n", sysGetClock(SYS_APLL));
|
||||
rt_kprintf("SYS_SYSTEM = %d\n", sysGetClock(SYS_SYSTEM));
|
||||
rt_kprintf("SYS_HCLK = %d\n", sysGetClock(SYS_HCLK));
|
||||
rt_kprintf("SYS_PCLK01 = %d\n", sysGetClock(SYS_PCLK01));
|
||||
rt_kprintf("SYS_PCLK2 = %d\n", sysGetClock(SYS_PCLK2));
|
||||
rt_kprintf("SYS_CPU = %d\n", sysGetClock(SYS_CPU));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will initial M487 board.
|
||||
*/
|
||||
|
@ -52,6 +41,12 @@ RT_WEAK void rt_hw_board_init(void)
|
|||
#if defined(BSP_USING_MMU)
|
||||
/* initialize mmu */
|
||||
rt_hw_mmu_init(&hw_mem_desc[0], sizeof(hw_mem_desc) / sizeof(hw_mem_desc[0]));
|
||||
#else
|
||||
/* disable I/D cache */
|
||||
mmu_disable_dcache();
|
||||
mmu_disable_icache();
|
||||
mmu_disable();
|
||||
mmu_invalidate_tlb();
|
||||
#endif
|
||||
|
||||
/* initialize hardware interrupt */
|
||||
|
@ -72,9 +67,6 @@ RT_WEAK void rt_hw_board_init(void)
|
|||
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
|
||||
#endif
|
||||
|
||||
nu_clock_base_dump();
|
||||
rt_kprintf("HEAP_START=0x%08x, HEAP_END=0x%08x\n", BOARD_HEAP_START, BOARD_HEAP_END);
|
||||
|
||||
#ifdef RT_USING_COMPONENTS_INIT
|
||||
rt_components_board_init();
|
||||
#endif
|
||||
|
|
|
@ -75,6 +75,7 @@ static rt_err_t nu_aes_crypt_run(
|
|||
{
|
||||
uint32_t au32SwapKey[8];
|
||||
uint32_t au32SwapIV[4];
|
||||
rt_err_t result;
|
||||
|
||||
au32SwapKey[0] = nu_get32_be(&pu8Key[0]);
|
||||
au32SwapKey[1] = nu_get32_be(&pu8Key[4]);
|
||||
|
@ -98,7 +99,8 @@ static rt_err_t nu_aes_crypt_run(
|
|||
au32SwapIV[2] = nu_get32_be(&pu8IV[8]);
|
||||
au32SwapIV[3] = nu_get32_be(&pu8IV[12]);
|
||||
|
||||
rt_mutex_take(&s_AES_mutex, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(&s_AES_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
AES_Open(CRPT, bEncrypt, u32OpMode, u32KeySize, AES_IN_OUT_SWAP);
|
||||
AES_SetKey(CRPT, (uint32_t *)&au32SwapKey[0], u32KeySize);
|
||||
|
@ -137,7 +139,8 @@ static rt_err_t nu_aes_crypt_run(
|
|||
/* Clear AES interrupt status */
|
||||
AES_CLR_INT_FLAG(CRPT);
|
||||
|
||||
rt_mutex_release(&s_AES_mutex);
|
||||
result = rt_mutex_release(&s_AES_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
@ -145,19 +148,25 @@ static rt_err_t nu_aes_crypt_run(
|
|||
//Using PRNG instead of TRNG
|
||||
static void nu_prng_open(uint32_t u32Seed)
|
||||
{
|
||||
rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
//Open PRNG 64 bits. But always return 32 bits
|
||||
PRNG_Open(CRPT, PRNG_KEY_SIZE_64, PRNG_SEED_RELOAD, u32Seed);
|
||||
|
||||
rt_mutex_release(&s_PRNG_mutex);
|
||||
result = rt_mutex_release(&s_PRNG_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
|
||||
static rt_uint32_t nu_prng_run(void)
|
||||
{
|
||||
uint32_t au32RNGValue[2];
|
||||
rt_err_t result;
|
||||
|
||||
rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
PRNG_Start(CRPT);
|
||||
while ((CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)) {};
|
||||
|
@ -167,7 +176,8 @@ static rt_uint32_t nu_prng_run(void)
|
|||
|
||||
PRNG_Read(CRPT, &au32RNGValue[0]);
|
||||
|
||||
rt_mutex_release(&s_PRNG_mutex);
|
||||
result = rt_mutex_release(&s_PRNG_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return au32RNGValue[0];
|
||||
}
|
||||
|
@ -340,10 +350,13 @@ static rt_err_t nu_sha_hash_run(
|
|||
uint32_t u32DataLen
|
||||
)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(psSHACtx != RT_NULL);
|
||||
RT_ASSERT(pu8InData != RT_NULL);
|
||||
|
||||
rt_mutex_take(&s_SHA_mutex, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(&s_SHA_mutex, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
uint8_t *pu8SrcAddr = (uint8_t *)pu8InData;
|
||||
uint32_t u32CopyLen = 0;
|
||||
|
@ -383,7 +396,8 @@ static rt_err_t nu_sha_hash_run(
|
|||
if (psSHACtx->pu8SHATempBuf == RT_NULL)
|
||||
{
|
||||
LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize);
|
||||
rt_mutex_release(&s_SHA_mutex);
|
||||
result = rt_mutex_release(&s_SHA_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -411,7 +425,8 @@ static rt_err_t nu_sha_hash_run(
|
|||
if (psSHACtx->pu8SHATempBuf == RT_NULL)
|
||||
{
|
||||
LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize);
|
||||
rt_mutex_release(&s_SHA_mutex);
|
||||
result = rt_mutex_release(&s_SHA_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -422,7 +437,8 @@ static rt_err_t nu_sha_hash_run(
|
|||
psSHACtx->u32SHATempBufLen += u32DataLen;
|
||||
}
|
||||
|
||||
rt_mutex_release(&s_SHA_mutex);
|
||||
result = rt_mutex_release(&s_SHA_mutex);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
|
|
@ -232,7 +232,6 @@ static void link_monitor(void *param)
|
|||
nu_emac_t psNuEmac = (nu_emac_t)param;
|
||||
EMAC_T *EMAC = psNuEmac->memmgr.psEmac;
|
||||
uint32_t LinkStatus_Last = EMAC_LINK_DOWN;
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
EMAC_PhyInit(EMAC);
|
||||
|
||||
|
@ -274,9 +273,6 @@ static void link_monitor(void *param)
|
|||
else
|
||||
{
|
||||
eth_device_linkchange(&psNuEmac->eth, RT_TRUE);
|
||||
|
||||
result = rt_sem_release(&psNuEmac->eth_sem);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
LinkStatus_Last = LinkStatus_Current;
|
||||
|
||||
|
@ -317,7 +313,8 @@ static rt_err_t nu_emac_init(rt_device_t dev)
|
|||
|
||||
snprintf(szTmp, sizeof(szTmp), "%sphy", psNuEmac->name);
|
||||
|
||||
rt_sem_init(&psNuEmac->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
ret = rt_sem_init(&psNuEmac->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
|
||||
EMAC_Reset(EMAC);
|
||||
|
||||
|
@ -402,26 +399,21 @@ static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p)
|
|||
rt_uint32_t offset = 0;
|
||||
rt_uint8_t *buf;
|
||||
|
||||
if (psNuEmac->eth.link_status == RT_FALSE)
|
||||
{
|
||||
rt_kprintf("[%s]Stand here.\n", psNuEmac->name);
|
||||
while (rt_sem_take(&psNuEmac->eth_sem, RT_WAITING_FOREVER) != RT_EOK);
|
||||
rt_kprintf("[%s]Leave.\n", psNuEmac->name);
|
||||
}
|
||||
|
||||
buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf(&psNuEmac->memmgr);
|
||||
|
||||
/* Get free TX buffer */
|
||||
if (buf == RT_NULL)
|
||||
{
|
||||
rt_sem_control(&psNuEmac->eth_sem, RT_IPC_CMD_RESET, 0);
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_sem_control(&psNuEmac->eth_sem, RT_IPC_CMD_RESET, 0);
|
||||
RT_ASSERT(result != RT_EOK);
|
||||
|
||||
EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk);
|
||||
EMAC_ENABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk);
|
||||
|
||||
do
|
||||
{
|
||||
rt_sem_take(&psNuEmac->eth_sem, 1);
|
||||
result = rt_sem_take(&psNuEmac->eth_sem, 10);
|
||||
buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf(&psNuEmac->memmgr);
|
||||
}
|
||||
while (buf == RT_NULL);
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-1-28 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#if defined(BSP_USING_TIMER_CAPTURE)
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <NuMicro.h>
|
||||
#include <drv_sys.h>
|
||||
|
||||
/* Private define ---------------------------------------------------------------*/
|
||||
|
||||
/* Timer prescale setting. Since it will affect the pulse width of measure, it is recommended to set to 2. */
|
||||
#define PSC_DIV (2)
|
||||
|
||||
#define NU_TCAP_DEVICE(etimer) (nu_capture_t*)(etimer)
|
||||
enum
|
||||
{
|
||||
TCAP_START = -1,
|
||||
#if defined(BSP_USING_TIMER0_CAPTURE)
|
||||
TCAP0_IDX,
|
||||
#endif
|
||||
#if defined(BSP_USING_TIMER1_CAPTURE)
|
||||
TCAP1_IDX,
|
||||
#endif
|
||||
#if defined(BSP_USING_TIMER2_CAPTURE)
|
||||
TCAP2_IDX,
|
||||
#endif
|
||||
#if defined(BSP_USING_TIMER3_CAPTURE)
|
||||
TCAP3_IDX,
|
||||
#endif
|
||||
#if defined(BSP_USING_TIMER4_CAPTURE)
|
||||
TCAP4_IDX,
|
||||
#endif
|
||||
/* BSP_USING_TIMER5 is reserved for Systick usage. */
|
||||
TCAP_CNT
|
||||
};
|
||||
|
||||
/* Private typedef --------------------------------------------------------------*/
|
||||
typedef struct _timer
|
||||
{
|
||||
struct rt_inputcapture_device parent;
|
||||
char *name;
|
||||
uint32_t idx;
|
||||
IRQn_Type irqn;
|
||||
E_SYS_IPRST rstidx;
|
||||
E_SYS_IPCLK clkidx;
|
||||
|
||||
uint32_t u32CurrentCnt;
|
||||
} nu_capture_t;
|
||||
|
||||
/* Private functions ------------------------------------------------------------*/
|
||||
static rt_err_t nu_capture_init(struct rt_inputcapture_device *inputcapture);
|
||||
static rt_err_t nu_capture_open(struct rt_inputcapture_device *inputcapture);
|
||||
static rt_err_t nu_capture_close(struct rt_inputcapture_device *inputcapture);
|
||||
static rt_err_t nu_capture_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us);
|
||||
|
||||
/* Public functions -------------------------------------------------------------*/
|
||||
|
||||
/* Private variables ------------------------------------------------------------*/
|
||||
static nu_capture_t nu_etcap_arr [] =
|
||||
{
|
||||
#if defined(BSP_USING_TIMER0_CAPTURE)
|
||||
{
|
||||
.name = "timer0i0",
|
||||
.idx = 0,
|
||||
.irqn = IRQ_TIMER0,
|
||||
.rstidx = TIMER0RST,
|
||||
.clkidx = TIMER0CKEN,
|
||||
},
|
||||
#endif
|
||||
#if defined(BSP_USING_TIMER1_CAPTURE)
|
||||
{
|
||||
.name = "timer1i0",
|
||||
.idx = 1,
|
||||
.irqn = IRQ_TIMER1,
|
||||
.rstidx = TIMER1RST,
|
||||
.clkidx = TIMER1CKEN,
|
||||
},
|
||||
#endif
|
||||
#if defined(BSP_USING_TIMER2_CAPTURE)
|
||||
{
|
||||
.name = "timer2i0",
|
||||
.idx = 2,
|
||||
.irqn = IRQ_TIMER2,
|
||||
.rstidx = TIMER2RST,
|
||||
.clkidx = TIMER2CKEN,
|
||||
},
|
||||
#endif
|
||||
#if defined(BSP_USING_TIMER3_CAPTURE)
|
||||
{
|
||||
.name = "timer3i0",
|
||||
.idx = 3,
|
||||
.irqn = IRQ_TIMER3,
|
||||
.rstidx = TIMER3RST,
|
||||
.clkidx = TIMER3CKEN,
|
||||
},
|
||||
#endif
|
||||
#if defined(BSP_USING_TIMER4_CAPTURE)
|
||||
{
|
||||
.name = "timer4i0",
|
||||
.idx = 4,
|
||||
.irqn = IRQ_TIMER4,
|
||||
.rstidx = TIMER4RST,
|
||||
.clkidx = TIMER4CKEN,
|
||||
},
|
||||
#endif
|
||||
/* BSP_USING_TIMER5 is reserved for Systick usage. */
|
||||
};
|
||||
|
||||
static struct rt_inputcapture_ops nu_capture_ops =
|
||||
{
|
||||
.init = nu_capture_init,
|
||||
.open = nu_capture_open,
|
||||
.close = nu_capture_close,
|
||||
.get_pulsewidth = nu_capture_get_pulsewidth,
|
||||
};
|
||||
|
||||
/* Functions define ------------------------------------------------------------*/
|
||||
static void nu_tcap_isr(int vector, void *param)
|
||||
{
|
||||
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(param);
|
||||
|
||||
RT_ASSERT(psNuTCap != RT_NULL);
|
||||
|
||||
ETIMER_ClearCaptureIntFlag(psNuTCap->idx);
|
||||
|
||||
/* Report caputring data and level. */
|
||||
psNuTCap->u32CurrentCnt = ETIMER_GetCaptureData(psNuTCap->idx);
|
||||
rt_hw_inputcapture_isr(&psNuTCap->parent, ETIMER_GetCaptureFallingEdgeFlag(psNuTCap->idx));
|
||||
}
|
||||
|
||||
static rt_err_t nu_capture_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us)
|
||||
{
|
||||
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture);
|
||||
|
||||
RT_ASSERT(inputcapture != RT_NULL);
|
||||
RT_ASSERT(pulsewidth_us != RT_NULL);
|
||||
|
||||
*pulsewidth_us = psNuTCap->u32CurrentCnt / PSC_DIV;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t nu_capture_init(struct rt_inputcapture_device *inputcapture)
|
||||
{
|
||||
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture);
|
||||
|
||||
RT_ASSERT(inputcapture != RT_NULL);
|
||||
|
||||
nu_sys_ipclk_enable(psNuTCap->clkidx);
|
||||
nu_sys_ip_reset(psNuTCap->rstidx);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static uint8_t cal_time_prescale(nu_capture_t *psNuTCap)
|
||||
{
|
||||
uint32_t u32Clk = ETIMER_GetModuleClock(psNuTCap->idx);
|
||||
|
||||
/* 1 tick = 1/PSC_DIV us */
|
||||
return (u32Clk / 1000000 / PSC_DIV) - 1;
|
||||
}
|
||||
|
||||
static rt_err_t nu_capture_open(struct rt_inputcapture_device *inputcapture)
|
||||
{
|
||||
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture);
|
||||
|
||||
RT_ASSERT(inputcapture != RT_NULL);
|
||||
|
||||
/* Enable Timer Interrupt */
|
||||
rt_hw_interrupt_umask(psNuTCap->irqn);
|
||||
|
||||
/* Clear counter before openning. */
|
||||
ETIMER_ClearCounter(psNuTCap->idx);
|
||||
|
||||
ETIMER_Open(psNuTCap->idx, ETIMER_CONTINUOUS_MODE, 1);
|
||||
|
||||
ETIMER_SET_PRESCALE_VALUE(psNuTCap->idx, cal_time_prescale(psNuTCap));
|
||||
|
||||
ETIMER_SET_CMP_VALUE(psNuTCap->idx, 0xFFFFFF);
|
||||
|
||||
ETIMER_EnableCapture(psNuTCap->idx, ETIMER_CAPTURE_COUNTER_RESET_MODE, ETIMER_CAPTURE_RISING_THEN_FALLING_EDGE);
|
||||
|
||||
ETIMER_EnableCaptureInt(psNuTCap->idx);
|
||||
|
||||
ETIMER_Start(psNuTCap->idx);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t nu_capture_close(struct rt_inputcapture_device *inputcapture)
|
||||
{
|
||||
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture);
|
||||
|
||||
RT_ASSERT(inputcapture != RT_NULL);
|
||||
|
||||
ETIMER_Stop(psNuTCap->idx);
|
||||
|
||||
ETIMER_DisableCaptureInt(psNuTCap->idx);
|
||||
|
||||
ETIMER_Close(psNuTCap->idx);
|
||||
|
||||
rt_hw_interrupt_mask(psNuTCap->irqn);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* Init and register timer capture */
|
||||
static int nu_timer_capture_device_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = (TCAP_START + 1); i < TCAP_CNT; i++)
|
||||
{
|
||||
/* Register operations */
|
||||
nu_etcap_arr[i].parent.ops = &nu_capture_ops;
|
||||
|
||||
/* Install ISR */
|
||||
rt_hw_interrupt_install(nu_etcap_arr[i].irqn, nu_tcap_isr, &nu_etcap_arr[i], nu_etcap_arr[i].name);
|
||||
|
||||
/* Register inputcapture device */
|
||||
rt_device_inputcapture_register(&nu_etcap_arr[i].parent, nu_etcap_arr[i].name, &nu_etcap_arr[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(nu_timer_capture_device_init);
|
||||
|
||||
#endif //#if defined(BSP_USING_TIMER_CAPTURE)
|
|
@ -968,8 +968,12 @@ static void nu_pdma_memfun_actor_init(void)
|
|||
{
|
||||
nu_pdma_memfun_actor_maxnum = i;
|
||||
nu_pdma_memfun_actor_mask = ~(((1 << i) - 1));
|
||||
|
||||
nu_pdma_memfun_actor_pool_sem = rt_sem_create("mempool_sem", nu_pdma_memfun_actor_maxnum, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(nu_pdma_memfun_actor_pool_sem != RT_NULL);
|
||||
|
||||
nu_pdma_memfun_actor_pool_lock = rt_mutex_create("mempool_lock", RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(nu_pdma_memfun_actor_pool_lock != RT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -987,13 +991,15 @@ static void nu_pdma_memfun_cb(void *pvUserData, uint32_t u32Events)
|
|||
static int nu_pdma_memfun_employ(void)
|
||||
{
|
||||
int idx = -1 ;
|
||||
rt_err_t result = 0;
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
/* Headhunter */
|
||||
if (nu_pdma_memfun_actor_pool_sem &&
|
||||
((result = rt_sem_take(nu_pdma_memfun_actor_pool_sem, RT_WAITING_FOREVER)) == RT_EOK))
|
||||
{
|
||||
rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
|
||||
result = rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* Find the position of first '0' in nu_pdma_memfun_actor_mask. */
|
||||
idx = nu_cto(nu_pdma_memfun_actor_mask);
|
||||
if (idx != 32)
|
||||
|
@ -1004,9 +1010,9 @@ static int nu_pdma_memfun_employ(void)
|
|||
{
|
||||
idx = -1;
|
||||
}
|
||||
rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
|
||||
result = rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
}
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
|
|
@ -301,42 +301,4 @@ int rt_hw_pwm_init(void)
|
|||
|
||||
INIT_DEVICE_EXPORT(rt_hw_pwm_init);
|
||||
|
||||
#if defined(RT_USING_FINSH)
|
||||
|
||||
#include <finsh.h>
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
|
||||
static int pwm_get(int argc, char **argv)
|
||||
{
|
||||
int result = 0;
|
||||
struct rt_device_pwm *device = RT_NULL;
|
||||
struct rt_pwm_configuration configuration = {0};
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
rt_kprintf("Usage: pwm_get pwm1 1\n");
|
||||
result = -RT_ERROR;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
device = (struct rt_device_pwm *)rt_device_find(argv[1]);
|
||||
if (!device)
|
||||
{
|
||||
result = -RT_EIO;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
configuration.channel = atoi(argv[2]);
|
||||
result = rt_device_control(&device->parent, PWM_CMD_GET, &configuration);
|
||||
|
||||
_exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
MSH_CMD_EXPORT(pwm_get, pwm_get pwm1 1);
|
||||
|
||||
#endif /* FINSH_USING_MSH */
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -60,7 +60,7 @@ static struct nu_spi nu_qspi_arr [] =
|
|||
.rstidx = QSPI0RST,
|
||||
.clkidx = QSPI0CKEN,
|
||||
|
||||
#if defined(BSP_USING_QSPI_PDMA)
|
||||
#if defined(BSP_USING_SPI_PDMA)
|
||||
#if defined(BSP_USING_QSPI0_PDMA)
|
||||
.pdma_perp_tx = PDMA_QSPI0_TX,
|
||||
.pdma_perp_rx = PDMA_QSPI0_RX,
|
||||
|
@ -153,7 +153,6 @@ exit_nu_qspi_bus_configure:
|
|||
return -(ret);
|
||||
}
|
||||
|
||||
#if defined(RT_SFUD_USING_QSPI)
|
||||
static int nu_qspi_mode_config(struct nu_spi *qspi_bus, rt_uint8_t *tx, rt_uint8_t *rx, int qspi_lines)
|
||||
{
|
||||
QSPI_T *qspi_base = (QSPI_T *)qspi_bus->spi_base;
|
||||
|
@ -197,16 +196,13 @@ static int nu_qspi_mode_config(struct nu_spi *qspi_bus, rt_uint8_t *tx, rt_uint8
|
|||
}
|
||||
return qspi_lines;
|
||||
}
|
||||
#endif
|
||||
|
||||
static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
|
||||
{
|
||||
struct nu_spi *qspi_bus;
|
||||
struct rt_qspi_configuration *qspi_configuration;
|
||||
#if defined(RT_SFUD_USING_QSPI)
|
||||
struct rt_qspi_message *qspi_message;
|
||||
rt_uint8_t u8last = 1;
|
||||
#endif
|
||||
rt_uint8_t bytes_per_word;
|
||||
QSPI_T *qspi_base;
|
||||
rt_uint32_t u32len = 0;
|
||||
|
@ -232,7 +228,6 @@ static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(RT_SFUD_USING_QSPI)
|
||||
qspi_message = (struct rt_qspi_message *)message;
|
||||
|
||||
/* Command + Address + Dummy + Data */
|
||||
|
@ -248,7 +243,7 @@ static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
|
|||
}
|
||||
|
||||
/* Address stage */
|
||||
if (qspi_message->address.size != 0)
|
||||
if (qspi_message->address.size > 0)
|
||||
{
|
||||
rt_uint32_t u32ReversedAddr = 0;
|
||||
rt_uint32_t u32AddrNumOfByte = qspi_message->address.size / 8;
|
||||
|
@ -278,8 +273,39 @@ static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
|
|||
1);
|
||||
}
|
||||
|
||||
/* alternate_bytes stage */
|
||||
if ((qspi_message->alternate_bytes.size > 0) && (qspi_message->alternate_bytes.size <= 4))
|
||||
{
|
||||
rt_uint32_t u32AlternateByte = 0;
|
||||
rt_uint32_t u32NumOfByte = qspi_message->alternate_bytes.size / 8;
|
||||
switch (u32NumOfByte)
|
||||
{
|
||||
case 1:
|
||||
u32AlternateByte = (qspi_message->alternate_bytes.content & 0xff);
|
||||
break;
|
||||
case 2:
|
||||
nu_set16_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
|
||||
break;
|
||||
case 3:
|
||||
nu_set24_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
|
||||
break;
|
||||
case 4:
|
||||
nu_set32_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
|
||||
break;
|
||||
default:
|
||||
RT_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *)&u32AlternateByte, RT_NULL, qspi_message->alternate_bytes.qspi_lines);
|
||||
nu_spi_transfer((struct nu_spi *)qspi_bus,
|
||||
(rt_uint8_t *) &u32AlternateByte,
|
||||
RT_NULL,
|
||||
u32NumOfByte,
|
||||
1);
|
||||
}
|
||||
|
||||
/* Dummy_cycles stage */
|
||||
if (qspi_message->dummy_cycles != 0)
|
||||
if (qspi_message->dummy_cycles > 0)
|
||||
{
|
||||
qspi_bus->dummy = 0x00;
|
||||
|
||||
|
@ -291,12 +317,10 @@ static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
|
|||
1);
|
||||
}
|
||||
|
||||
/* Data stage */
|
||||
nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) message->send_buf, (rt_uint8_t *) message->recv_buf, qspi_message->qspi_data_lines);
|
||||
#endif //#if defined(RT_SFUD_USING_QSPI)
|
||||
|
||||
if (message->length != 0)
|
||||
if (message->length > 0)
|
||||
{
|
||||
/* Data stage */
|
||||
nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) message->send_buf, (rt_uint8_t *) message->recv_buf, qspi_message->qspi_data_lines);
|
||||
nu_spi_transfer((struct nu_spi *)qspi_bus,
|
||||
(rt_uint8_t *) message->send_buf,
|
||||
(rt_uint8_t *) message->recv_buf,
|
||||
|
|
|
@ -412,7 +412,8 @@ static int rt_hw_sdh_init(void)
|
|||
rt_err_t ret = RT_EOK;
|
||||
rt_uint32_t flags = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE;
|
||||
|
||||
rt_event_init(&sdh_event, "sdh_event", RT_IPC_FLAG_FIFO);
|
||||
ret = rt_event_init(&sdh_event, "sdh_event", RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
|
||||
for (i = (SDH_START + 1); i < SDH_CNT; i++)
|
||||
{
|
||||
|
@ -428,7 +429,8 @@ static int rt_hw_sdh_init(void)
|
|||
/* Private */
|
||||
nu_sdh_arr[i].dev.user_data = (void *)&nu_sdh_arr[i];
|
||||
|
||||
rt_sem_init(&nu_sdh_arr[i].lock, "sdhlock", 1, RT_IPC_FLAG_FIFO);
|
||||
ret = rt_sem_init(&nu_sdh_arr[i].lock, "sdhlock", 1, RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
|
||||
rt_hw_interrupt_install(nu_sdh_arr[i].irqn, SDH_IRQHandler, (void *)&nu_sdh_arr[i], nu_sdh_arr[i].name);
|
||||
rt_hw_interrupt_umask(nu_sdh_arr[i].irqn);
|
||||
|
@ -437,9 +439,8 @@ static int rt_hw_sdh_init(void)
|
|||
|
||||
nu_sys_ip_reset(nu_sdh_arr[i].rstidx);
|
||||
|
||||
SDH_Open(nu_sdh_arr[i].base, CardDetect_From_GPIO);
|
||||
|
||||
nu_sdh_arr[i].pbuf = RT_NULL;
|
||||
|
||||
ret = rt_device_register(&nu_sdh_arr[i].dev, nu_sdh_arr[i].name, flags);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
}
|
||||
|
@ -591,7 +592,10 @@ static void sdh_hotplugger(void *param)
|
|||
|
||||
for (i = (SDH_START + 1); i < SDH_CNT; i++)
|
||||
{
|
||||
if (SDH_IS_CARD_PRESENT(nu_sdh_arr[i].base))
|
||||
/* Try to detect SD card on selected port. */
|
||||
SDH_Open(nu_sdh_arr[i].base, CardDetect_From_GPIO);
|
||||
if (!SDH_Probe(nu_sdh_arr[i].base) &&
|
||||
SDH_IS_CARD_PRESENT(nu_sdh_arr[i].base))
|
||||
{
|
||||
nu_sdh_hotplug_mount(&nu_sdh_arr[i]);
|
||||
}
|
||||
|
|
|
@ -287,6 +287,18 @@ void nu_sys_ipclk_disable(E_SYS_IPCLK eIPClkIdx)
|
|||
_nu_sys_ipclk(eIPClkIdx, 0);
|
||||
}
|
||||
|
||||
E_SYS_USB0_ID nu_sys_usb0_role(void)
|
||||
{
|
||||
/* Check Role on USB0 dual-role port. */
|
||||
/*
|
||||
[17] USB0_IDS
|
||||
USB0_ID Status
|
||||
0 = USB port 0 used as a USB device port.
|
||||
1 = USB port 0 used as a USB host port.
|
||||
*/
|
||||
return ((inpw(REG_SYS_MISCISR) & (1 << 17)) > 0) ? USB0_ID_HOST : USB0_ID_DEVICE;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
|
||||
#include <finsh.h>
|
||||
|
@ -308,6 +320,32 @@ int cmd_shutdown(int argc, char **argv)
|
|||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_reset, __cmd_reset, restart the system.);
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_shutdown, __cmd_shutdown, shutdown the system.);
|
||||
|
||||
int nu_clocks(int argc, char **argv)
|
||||
{
|
||||
rt_kprintf("SYS_UPLL = %d MHz\n", sysGetClock(SYS_UPLL));
|
||||
rt_kprintf("SYS_APLL = %d MHz\n", sysGetClock(SYS_APLL));
|
||||
rt_kprintf("SYS_SYSTEM = %d MHz\n", sysGetClock(SYS_SYSTEM));
|
||||
rt_kprintf("SYS_HCLK = %d MHz\n", sysGetClock(SYS_HCLK));
|
||||
rt_kprintf("SYS_PCLK01 = %d MHz\n", sysGetClock(SYS_PCLK01));
|
||||
rt_kprintf("SYS_PCLK2 = %d MHz\n", sysGetClock(SYS_PCLK2));
|
||||
rt_kprintf("SYS_CPU = %d MHz\n", sysGetClock(SYS_CPU));
|
||||
|
||||
rt_kprintf("CLK_HCLKEN = %08X\n", inpw(REG_CLK_HCLKEN));
|
||||
rt_kprintf("CLK_PCLKEN0 = %08X\n", inpw(REG_CLK_PCLKEN0));
|
||||
rt_kprintf("CLK_PCLKEN1 = %08X\n", inpw(REG_CLK_PCLKEN1));
|
||||
|
||||
rt_kprintf("AIC_INTMSK0 = %08X\n", inpw(REG_AIC_INTMSK0));
|
||||
rt_kprintf("AIC_INTMSK1 = %08X\n", inpw(REG_AIC_INTMSK1));
|
||||
|
||||
rt_kprintf("AIC_INTEN0 = %08X\n", inpw(REG_AIC_INTEN0));
|
||||
rt_kprintf("AIC_INTEN1 = %08X\n", inpw(REG_AIC_INTEN1));
|
||||
|
||||
rt_kprintf("AIC_INTDIS0 = %08X\n", inpw(REG_AIC_INTDIS0));
|
||||
rt_kprintf("AIC_INTDIS1 = %08X\n", inpw(REG_AIC_INTDIS1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(nu_clocks, Get all system clocks);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -243,6 +243,13 @@ typedef enum
|
|||
|
||||
} E_SYS_IPCLK;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USB0_ID_DEVICE,
|
||||
USB0_ID_HOST,
|
||||
USB0_ID_CNT
|
||||
} E_SYS_USB0_ID;
|
||||
|
||||
void rt_hw_interrupt_init(void);
|
||||
void rt_hw_interrupt_set_priority(int vector, int priority);
|
||||
void rt_hw_interrupt_set_type(int vector, int type);
|
||||
|
@ -255,5 +262,6 @@ void nu_systick_udelay(uint32_t delay_us);
|
|||
void nu_sys_ip_reset(E_SYS_IPRST eIPRstIdx);
|
||||
void nu_sys_ipclk_enable(E_SYS_IPCLK eIPClkIdx);
|
||||
void nu_sys_ipclk_disable(E_SYS_IPCLK eIPClkIdx);
|
||||
E_SYS_USB0_ID nu_sys_usb0_role(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -572,7 +572,6 @@ static void nu_pdma_uart_rx_cb(void *pvOwner, uint32_t u32Events)
|
|||
struct rt_serial_device *serial = (struct rt_serial_device *)pvOwner;
|
||||
nu_uart_t puart = (nu_uart_t)serial;
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
|
||||
|
||||
/* Get base address of uart register */
|
||||
UART_T *uart_base = puart->uart_base;
|
||||
|
@ -581,6 +580,9 @@ static void nu_pdma_uart_rx_cb(void *pvOwner, uint32_t u32Events)
|
|||
|
||||
if (u32Events & (NU_PDMA_EVENT_TRANSFER_DONE | NU_PDMA_EVENT_TIMEOUT))
|
||||
{
|
||||
#if defined(BSP_USING_MMU)
|
||||
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
|
||||
#endif
|
||||
if (u32Events & NU_PDMA_EVENT_TRANSFER_DONE)
|
||||
{
|
||||
transferred_rxbyte = puart->rxdma_trigger_len;
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
#include "drv_sys.h"
|
||||
|
||||
#define LOG_TAG "drv.usbd"
|
||||
#define DBG_ENABLE
|
||||
//#define DBG_ENABLE
|
||||
#define DBG_SECTION_NAME "drv.usbd"
|
||||
#define DBG_LEVEL DBG_INFO
|
||||
//#define DBG_LEVEL DBG_ERROR
|
||||
#define DBG_COLOR
|
||||
#include <rtdbg.h>
|
||||
|
||||
|
@ -124,7 +124,8 @@ typedef struct _nu_usbd_t
|
|||
IRQn_Type irqn;
|
||||
E_SYS_IPRST rstidx;
|
||||
E_SYS_IPCLK clkidx;
|
||||
uint8_t address_tmp; /* Keep assigned address for flow control */
|
||||
uint8_t address_tmp; /* Keep assigned address for flow control */
|
||||
uint8_t plugging_status; /* For debounce, 0: Unplug, 1: plug-in */
|
||||
} nu_usbd_t;
|
||||
|
||||
|
||||
|
@ -149,6 +150,7 @@ static nu_usbd_t nu_usbd =
|
|||
.rstidx = USBDRST,
|
||||
.clkidx = USBDCKEN,
|
||||
.address_tmp = 0,
|
||||
.plugging_status = 0,
|
||||
};
|
||||
|
||||
static struct udcd _rt_obj_udc;
|
||||
|
@ -278,6 +280,27 @@ static void NU_SetupStageCallback(nu_usbd_t *nu_udc)
|
|||
rt_usbd_ep0_setup_handler(&_rt_obj_udc, (struct urequest *)&setup_packet);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nu_udc_enable(void)
|
||||
{
|
||||
USBD_ENABLE_USB();
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nu_udc_disable(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
USBD_ENABLE_CEP_INT(0);
|
||||
USBD_CLR_CEP_INT_FLAG(0xffff);
|
||||
|
||||
USBD_SET_CEP_STATE(inpw(REG_USBD_CEPCTL) | USB_CEPCTL_FLUSH);
|
||||
|
||||
for (i = 0; i < USBD_MAX_EP; i++)
|
||||
USBD->EP[i].EPRSPCTL = USB_EP_RSPCTL_FLUSH | USB_EP_RSPCTL_TOGGLE;
|
||||
|
||||
USBD_DISABLE_USB();
|
||||
}
|
||||
|
||||
|
||||
static rt_err_t _ep_set_stall(rt_uint8_t address)
|
||||
{
|
||||
|
||||
|
@ -543,6 +566,9 @@ static void nu_usbd_isr(int vector, void *param)
|
|||
int i;
|
||||
int IrqStAllEP;
|
||||
|
||||
/* Igrone event if role is USBH*/
|
||||
if (nu_sys_usb0_role() != USB0_ID_DEVICE) return;
|
||||
|
||||
IrqStL = USBD->GINTSTS & USBD->GINTEN; /* get interrupt status */
|
||||
|
||||
if (!IrqStL) return;
|
||||
|
@ -635,17 +661,25 @@ static void nu_usbd_isr(int vector, void *param)
|
|||
{
|
||||
if (USBD_IS_ATTACHED())
|
||||
{
|
||||
LOG_I("PLUG IN");
|
||||
/* USB Plug In */
|
||||
USBD_ENABLE_USB();
|
||||
rt_usbd_connect_handler(&_rt_obj_udc);
|
||||
if (!nu_usbd.plugging_status)
|
||||
{
|
||||
LOG_I("PLUG IN");
|
||||
/* USB Plug In */
|
||||
nu_udc_enable();
|
||||
rt_usbd_connect_handler(&_rt_obj_udc);
|
||||
nu_usbd.plugging_status = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("Un-Plug");
|
||||
/* USB Un-plug */
|
||||
USBD_DISABLE_USB();
|
||||
rt_usbd_disconnect_handler(&_rt_obj_udc);
|
||||
if (nu_usbd.plugging_status)
|
||||
{
|
||||
LOG_I("Un-Plug");
|
||||
/* USB Un-plug */
|
||||
nu_udc_disable();
|
||||
rt_usbd_disconnect_handler(&_rt_obj_udc);
|
||||
nu_usbd.plugging_status = 0;
|
||||
}
|
||||
}
|
||||
USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_VBUSDETIF_Msk);
|
||||
}
|
||||
|
@ -791,29 +825,15 @@ static void nu_usbd_isr(int vector, void *param)
|
|||
|
||||
static rt_err_t _init(rt_device_t device)
|
||||
{
|
||||
#if !defined(BSP_USING_OTG)
|
||||
uint32_t volatile i;
|
||||
|
||||
/* Initialize USB PHY */
|
||||
SYS_UnlockReg();
|
||||
SYS->USBPHY &= ~SYS_USBPHY_HSUSBROLE_Msk; /* select USBD */
|
||||
|
||||
/* Enable USB PHY */
|
||||
SYS->USBPHY = (SYS->USBPHY & ~(SYS_USBPHY_HSUSBROLE_Msk | SYS_USBPHY_HSUSBACT_Msk)) | SYS_USBPHY_HSUSBEN_Msk;
|
||||
|
||||
for (i = 0; i < 0x1000; i++)
|
||||
__NOP(); // delay > 10 us
|
||||
|
||||
SYS->USBPHY |= SYS_USBPHY_HSUSBACT_Msk;
|
||||
SYS_LockReg();
|
||||
#endif
|
||||
|
||||
nu_sys_ipclk_enable(nu_usbd.clkidx);
|
||||
|
||||
nu_sys_ip_reset(nu_usbd.rstidx);
|
||||
|
||||
nu_systick_udelay(1000);
|
||||
|
||||
/* USBD Open */
|
||||
USBD->PHYCTL |= (USBD_PHYCTL_PHYEN_Msk | USBD_PHYCTL_DPPUEN_Msk);
|
||||
USBD_ENABLE_USB();
|
||||
|
||||
while (1)
|
||||
{
|
||||
USBD->EP[EPA].EPMPS = 0x20ul;
|
||||
|
@ -842,7 +862,11 @@ static rt_err_t _init(rt_device_t device)
|
|||
rt_hw_interrupt_umask(nu_usbd.irqn);
|
||||
|
||||
/* Start transaction */
|
||||
USBD_Start();
|
||||
USBD_CLR_SE0();
|
||||
|
||||
/* Get currect cable status */
|
||||
nu_usbd.plugging_status = USBD_IS_ATTACHED() >> USBD_PHYCTL_VBUSDET_Pos;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,893 @@
|
|||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-12-30 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
#include <rtconfig.h>
|
||||
|
||||
#if defined(BSP_USING_USBH)
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <rthw.h>
|
||||
#include <NuMicro.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "usbh_lib.h"
|
||||
|
||||
#if !defined(NU_USBHOST_HUB_POLLING_INTERVAL)
|
||||
#define NU_USBHOST_HUB_POLLING_INTERVAL (100)
|
||||
#endif
|
||||
|
||||
#define NU_MAX_USBH_PORT 2 //2* USB2.0 port
|
||||
#define NU_MAX_USBH_PIPE 16
|
||||
#define NU_USBH_THREAD_STACK_SIZE 2048
|
||||
|
||||
#define NU_MAX_USBH_HUB_PORT_DEV USB_HUB_PORT_NUM
|
||||
|
||||
/* Private typedef --------------------------------------------------------------*/
|
||||
typedef struct nu_port_dev
|
||||
{
|
||||
rt_bool_t bRHParent;
|
||||
UDEV_T *pUDev;
|
||||
EP_INFO_T *apsEPInfo[NU_MAX_USBH_PIPE];
|
||||
struct urequest asSetupReq[NU_MAX_USBH_PIPE];
|
||||
struct rt_completion utr_completion;
|
||||
int port_num;
|
||||
rt_bool_t bEnumDone;
|
||||
#if defined(BSP_USING_MMU)
|
||||
void *asPipePktBuf[NU_MAX_USBH_PIPE];
|
||||
#endif
|
||||
} S_NU_PORT_DEV;
|
||||
|
||||
|
||||
typedef struct nu_port_ctrl
|
||||
{
|
||||
S_NU_PORT_DEV sRHPortDev;
|
||||
S_NU_PORT_DEV asHubPortDev[NU_MAX_USBH_HUB_PORT_DEV];
|
||||
} S_NU_RH_PORT_CTRL;
|
||||
|
||||
|
||||
struct nu_usbh_dev
|
||||
{
|
||||
struct uhcd uhcd;
|
||||
E_SYS_IPRST rstidx;
|
||||
E_SYS_IPCLK clkidx;
|
||||
rt_thread_t polling_thread;
|
||||
S_NU_RH_PORT_CTRL asPortCtrl[NU_MAX_USBH_PORT];
|
||||
};
|
||||
|
||||
/* Private variables ------------------------------------------------------------*/
|
||||
static struct nu_usbh_dev s_sUSBHDev =
|
||||
{
|
||||
.rstidx = USBHRST,
|
||||
.clkidx = USBHCKEN,
|
||||
};
|
||||
|
||||
static S_NU_RH_PORT_CTRL *
|
||||
GetRHPortControlFromPipe(
|
||||
upipe_t pipe)
|
||||
{
|
||||
uinst_t inst;
|
||||
int port;
|
||||
if (pipe->inst->parent_hub->is_roothub)
|
||||
{
|
||||
//case: device ---> root hub
|
||||
inst = pipe->inst;
|
||||
port = inst->port;
|
||||
}
|
||||
else
|
||||
{
|
||||
//case: device ---> hub ---> root hub
|
||||
inst = pipe->inst->parent_hub->self;
|
||||
port = inst->port;
|
||||
}
|
||||
|
||||
if (port > NU_MAX_USBH_PORT)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: port index over NU_MAX_USBH_PORT\n"));
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
return &s_sUSBHDev.asPortCtrl[port - 1];;
|
||||
}
|
||||
|
||||
static S_NU_PORT_DEV *
|
||||
GetPortDevFromPipe(
|
||||
upipe_t pipe)
|
||||
{
|
||||
S_NU_RH_PORT_CTRL *psRHPortCtrl = GetRHPortControlFromPipe(pipe);
|
||||
int i;
|
||||
|
||||
if (psRHPortCtrl == RT_NULL)
|
||||
return RT_NULL;
|
||||
|
||||
if (pipe->inst->parent_hub->is_roothub)
|
||||
{
|
||||
//case: device ---> root hub
|
||||
return &psRHPortCtrl->sRHPortDev;
|
||||
}
|
||||
|
||||
//case: device ---> hub ---> root hub
|
||||
for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++)
|
||||
{
|
||||
if (psRHPortCtrl->asHubPortDev[i].port_num == pipe->inst->port)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= NU_MAX_USBH_HUB_PORT_DEV)
|
||||
return RT_NULL;
|
||||
|
||||
return &psRHPortCtrl->asHubPortDev[i];
|
||||
}
|
||||
|
||||
static rt_err_t nu_reset_port(rt_uint8_t port)
|
||||
{
|
||||
S_NU_RH_PORT_CTRL *psPortCtrl;
|
||||
|
||||
if (port > NU_MAX_USBH_PORT)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: port index over NU_MAX_USBH_PORT\n", __func__));
|
||||
return RT_EIO;
|
||||
}
|
||||
|
||||
psPortCtrl = &s_sUSBHDev.asPortCtrl[port - 1];
|
||||
if (psPortCtrl->sRHPortDev.pUDev == NULL)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__));
|
||||
return RT_EIO;
|
||||
}
|
||||
|
||||
usbh_reset_port(psPortCtrl->sRHPortDev.pUDev);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static EP_INFO_T *GetFreePipe(
|
||||
S_NU_RH_PORT_CTRL *psPortCtrl,
|
||||
S_NU_PORT_DEV *psPortDev,
|
||||
rt_uint8_t *pu8PipeIndex)
|
||||
{
|
||||
if (psPortCtrl != NULL)
|
||||
{
|
||||
int i;
|
||||
/* Find free Pipe */
|
||||
for (i = 0; i < NU_MAX_USBH_PIPE; i ++)
|
||||
{
|
||||
if (psPortDev->apsEPInfo[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < NU_MAX_USBH_PIPE)
|
||||
{
|
||||
EP_INFO_T *psEPInfo = rt_malloc(sizeof(EP_INFO_T));
|
||||
if (psEPInfo != RT_NULL)
|
||||
{
|
||||
psPortDev->apsEPInfo[i] = psEPInfo;
|
||||
*pu8PipeIndex = i;
|
||||
return psEPInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static void FreePipe(
|
||||
S_NU_RH_PORT_CTRL *psPortCtrl,
|
||||
S_NU_PORT_DEV *psPortDev,
|
||||
rt_uint8_t u8PipeIndex)
|
||||
{
|
||||
if ((psPortCtrl != RT_NULL) &&
|
||||
(u8PipeIndex < NU_MAX_USBH_PIPE) &&
|
||||
(psPortDev->apsEPInfo[u8PipeIndex] != RT_NULL))
|
||||
{
|
||||
rt_free(psPortDev->apsEPInfo[u8PipeIndex]);
|
||||
psPortDev->apsEPInfo[u8PipeIndex] = RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static S_NU_PORT_DEV *
|
||||
AllocateNewUDev(
|
||||
S_NU_RH_PORT_CTRL *psRHPortCtrl)
|
||||
{
|
||||
if (psRHPortCtrl != RT_NULL)
|
||||
{
|
||||
int i;
|
||||
/* Find free Dev */
|
||||
for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++)
|
||||
{
|
||||
if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < NU_MAX_USBH_HUB_PORT_DEV)
|
||||
{
|
||||
psRHPortCtrl->asHubPortDev[i].pUDev = alloc_device();
|
||||
if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return &psRHPortCtrl->asHubPortDev[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static rt_err_t nu_open_pipe(upipe_t pipe)
|
||||
{
|
||||
S_NU_RH_PORT_CTRL *psPortCtrl;
|
||||
S_NU_PORT_DEV *psPortDev;
|
||||
|
||||
psPortCtrl = GetRHPortControlFromPipe(pipe);
|
||||
if (psPortCtrl == RT_NULL)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: RHPort not found\n", __func__));
|
||||
goto exit_nu_open_pipe;
|
||||
}
|
||||
|
||||
if (psPortCtrl->sRHPortDev.pUDev == NULL)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__));
|
||||
goto exit_nu_open_pipe;
|
||||
}
|
||||
|
||||
psPortDev = GetPortDevFromPipe(pipe);
|
||||
|
||||
if ((psPortDev == NULL) || (psPortDev->pUDev == NULL))
|
||||
{
|
||||
//allocate new dev for hub device
|
||||
psPortDev = AllocateNewUDev(psPortCtrl);
|
||||
|
||||
if (psPortDev == RT_NULL)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: udev allocate failed\n"));
|
||||
goto exit_nu_open_pipe;
|
||||
}
|
||||
|
||||
if (pipe->inst->speed)
|
||||
{
|
||||
psPortDev->pUDev->speed = SPEED_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
psPortDev->pUDev->speed = SPEED_HIGH;
|
||||
}
|
||||
|
||||
psPortDev->pUDev->parent = NULL;
|
||||
psPortDev->pUDev->hc_driver = psPortCtrl->sRHPortDev.pUDev->hc_driver;
|
||||
psPortDev->port_num = pipe->inst->port;
|
||||
psPortDev->pUDev->port_num = pipe->inst->port;
|
||||
psPortDev->bEnumDone = FALSE;
|
||||
}
|
||||
|
||||
//For ep0 control transfer
|
||||
if ((pipe->ep.bEndpointAddress & 0x7F) == 0)
|
||||
{
|
||||
pipe->pipe_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int pksz;
|
||||
EP_INFO_T *psEPInfo = GetFreePipe(psPortCtrl, psPortDev, &pipe->pipe_index);
|
||||
if (psEPInfo == RT_NULL)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: get free pipe failed\n", __func__));
|
||||
goto exit_nu_open_pipe;
|
||||
}
|
||||
|
||||
psEPInfo->bEndpointAddress = pipe->ep.bEndpointAddress;
|
||||
psEPInfo->bmAttributes = pipe->ep.bmAttributes;
|
||||
|
||||
pksz = pipe->ep.wMaxPacketSize;
|
||||
pksz = (pksz & 0x07ff) * (1 + ((pksz >> 11) & 3));
|
||||
psEPInfo->wMaxPacketSize = pksz;
|
||||
|
||||
psEPInfo->bInterval = pipe->ep.bInterval;
|
||||
psEPInfo->hw_pipe = NULL;
|
||||
psEPInfo->bToggle = 0;
|
||||
}
|
||||
|
||||
#if defined(BSP_USING_MMU)
|
||||
if (!psPortDev->asPipePktBuf[pipe->pipe_index])
|
||||
{
|
||||
psPortDev->asPipePktBuf[pipe->pipe_index] = rt_malloc_align(512ul, CACHE_LINE_SIZE);
|
||||
RT_ASSERT(psPortDev->asPipePktBuf[pipe->pipe_index] != RT_NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
exit_nu_open_pipe:
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
static rt_err_t nu_close_pipe(upipe_t pipe)
|
||||
{
|
||||
S_NU_RH_PORT_CTRL *psPortCtrl;
|
||||
S_NU_PORT_DEV *psPortDev;
|
||||
|
||||
psPortCtrl = GetRHPortControlFromPipe(pipe);
|
||||
if (psPortCtrl == RT_NULL)
|
||||
{
|
||||
return RT_EIO;
|
||||
}
|
||||
|
||||
psPortDev = GetPortDevFromPipe(pipe);
|
||||
|
||||
//For ep0 control transfer
|
||||
if ((pipe->ep.bEndpointAddress & 0x7F) == 0)
|
||||
{
|
||||
if ((psPortDev) && (psPortDev->bRHParent == FALSE) && (psPortDev->bEnumDone == TRUE))
|
||||
{
|
||||
if (psPortDev->pUDev)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NU_MAX_USBH_PIPE; i++)
|
||||
{
|
||||
if (psPortDev->apsEPInfo[i] != NULL)
|
||||
{
|
||||
usbh_quit_xfer(psPortDev->pUDev, psPortDev->apsEPInfo[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free_device(psPortDev->pUDev);
|
||||
psPortDev->pUDev = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (psPortDev != NULL)
|
||||
{
|
||||
#if defined(BSP_USING_MMU)
|
||||
if (psPortDev->asPipePktBuf[pipe->pipe_index])
|
||||
{
|
||||
rt_free_align(psPortDev->asPipePktBuf[pipe->pipe_index]);
|
||||
psPortDev->asPipePktBuf[pipe->pipe_index] = RT_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
FreePipe(psPortCtrl, psPortDev, pipe->pipe_index);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int nu_ctrl_xfer(
|
||||
S_NU_PORT_DEV *psPortDev,
|
||||
struct urequest *psSetup,
|
||||
void *buffer,
|
||||
int timeouts)
|
||||
{
|
||||
uint32_t xfer_len = 0;
|
||||
int ret;
|
||||
|
||||
ret = usbh_ctrl_xfer(psPortDev->pUDev, psSetup->request_type, psSetup->bRequest, psSetup->wValue, psSetup->wIndex, psSetup->wLength, buffer, &xfer_len, timeouts * 10);
|
||||
if (ret < 0)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_ctrl_xfer ERROR: xfer failed %d\n", ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (xfer_len != psSetup->wLength)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_ctrl_xfer ERROR: xfer length %d %d\n", psSetup->wLength, xfer_len));
|
||||
}
|
||||
|
||||
if ((psSetup->bRequest == USB_REQ_SET_ADDRESS) && ((psSetup->request_type & 0x60) == REQ_TYPE_STD_DEV))
|
||||
psPortDev->pUDev->dev_num = psSetup->wValue;
|
||||
|
||||
if ((psSetup->bRequest == USB_REQ_SET_CONFIGURATION) && ((psSetup->request_type & 0x60) == REQ_TYPE_STD_DEV))
|
||||
{
|
||||
psPortDev->pUDev->cur_conf = psSetup->wValue;
|
||||
psPortDev->bEnumDone = TRUE;
|
||||
}
|
||||
|
||||
return xfer_len;
|
||||
}
|
||||
|
||||
static int nu_bulk_xfer(
|
||||
S_NU_PORT_DEV *psPortDev,
|
||||
UTR_T *psUTR,
|
||||
int timeouts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usbh_bulk_xfer(psUTR);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
//wait transfer done
|
||||
rt_completion_wait(&(psPortDev->utr_completion), timeouts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nu_int_xfer(
|
||||
upipe_t pipe,
|
||||
S_NU_PORT_DEV *psPortDev,
|
||||
UTR_T *psUTR,
|
||||
int timeouts)
|
||||
{
|
||||
int ret;
|
||||
int retry = 3;
|
||||
|
||||
while (retry > 0)
|
||||
{
|
||||
ret = usbh_int_xfer(psUTR);
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_int_xfer ERROR: failed to submit interrupt request\n"));
|
||||
rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
|
||||
retry --;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xfer_done_cb(UTR_T *psUTR)
|
||||
{
|
||||
S_NU_PORT_DEV *psPortDev = (S_NU_PORT_DEV *)psUTR->context;
|
||||
|
||||
//transfer done, signal utr_completion
|
||||
rt_completion_done(&(psPortDev->utr_completion));
|
||||
}
|
||||
|
||||
static void int_xfer_done_cb(UTR_T *psUTR)
|
||||
{
|
||||
upipe_t pipe = (upipe_t)psUTR->context;
|
||||
|
||||
if (psUTR->status != 0)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("Interrupt xfer failed %d\n", psUTR->status));
|
||||
goto exit_int_xfer_done_cb;
|
||||
}
|
||||
|
||||
if (pipe->callback != RT_NULL)
|
||||
{
|
||||
struct uhost_msg msg;
|
||||
msg.type = USB_MSG_CALLBACK;
|
||||
msg.content.cb.function = pipe->callback;
|
||||
msg.content.cb.context = pipe;
|
||||
rt_usbh_event_signal(&msg);
|
||||
}
|
||||
|
||||
exit_int_xfer_done_cb:
|
||||
|
||||
free_utr(psUTR);
|
||||
}
|
||||
|
||||
static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
|
||||
{
|
||||
S_NU_RH_PORT_CTRL *psPortCtrl;
|
||||
S_NU_PORT_DEV *psPortDev;
|
||||
UTR_T *psUTR = NULL;
|
||||
int i32XferLen = -1;
|
||||
|
||||
void *buffer_nonch = buffer;
|
||||
|
||||
psPortCtrl = GetRHPortControlFromPipe(pipe);
|
||||
if (psPortCtrl == RT_NULL)
|
||||
{
|
||||
goto exit_nu_pipe_xfer;
|
||||
}
|
||||
|
||||
psPortDev = GetPortDevFromPipe(pipe);
|
||||
if (psPortDev->pUDev == NULL)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: udev not found\n"));
|
||||
goto exit_nu_pipe_xfer;
|
||||
}
|
||||
|
||||
#if defined(BSP_USING_MMU)
|
||||
if (buffer_nonch && nbytes)
|
||||
{
|
||||
buffer_nonch = psPortDev->asPipePktBuf[pipe->pipe_index];
|
||||
rt_memcpy(buffer_nonch, buffer, nbytes);
|
||||
mmu_clean_invalidated_dcache((uint32_t)buffer_nonch, nbytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
//ctrl xfer
|
||||
if (pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL)
|
||||
{
|
||||
int ret;
|
||||
if (token == USBH_PID_SETUP)
|
||||
{
|
||||
struct urequest *psSetup = (struct urequest *)buffer_nonch;
|
||||
RT_ASSERT(buffer_nonch != RT_NULL);
|
||||
|
||||
/* Read data from USB device. */
|
||||
if (psSetup->request_type & USB_REQ_TYPE_DIR_IN)
|
||||
{
|
||||
//Store setup request
|
||||
rt_memcpy(&psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index], psSetup, sizeof(struct urequest));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write data to USB device. */
|
||||
//Trigger USBHostLib Ctril_Xfer
|
||||
ret = nu_ctrl_xfer(psPortDev, psSetup, NULL, timeouts);
|
||||
if (ret != psSetup->wLength)
|
||||
goto exit_nu_pipe_xfer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//token == USBH_PID_DATA
|
||||
if (buffer_nonch && ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN))
|
||||
{
|
||||
/* Read data from USB device. */
|
||||
//Trigger USBHostLib Ctril_Xfer
|
||||
ret = nu_ctrl_xfer(psPortDev, &psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index], buffer_nonch, timeouts);
|
||||
if (ret != nbytes)
|
||||
goto exit_nu_pipe_xfer;
|
||||
}
|
||||
else
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("%d == USBH_PID_DATA, nil buf-%d \n", token, nbytes));
|
||||
}
|
||||
|
||||
} //else
|
||||
i32XferLen = nbytes;
|
||||
goto exit_nu_pipe_xfer;
|
||||
} // if ( pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL )
|
||||
else
|
||||
{
|
||||
|
||||
psUTR = alloc_utr(psPortDev->pUDev);
|
||||
|
||||
if (!psUTR)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: unable alloc UTR\n"));
|
||||
goto exit_nu_pipe_xfer;
|
||||
}
|
||||
|
||||
psUTR->ep = psPortDev->apsEPInfo[pipe->pipe_index];
|
||||
psUTR->buff = buffer_nonch;
|
||||
psUTR->data_len = nbytes;
|
||||
psUTR->xfer_len = 0;
|
||||
psUTR->func = xfer_done_cb;
|
||||
psUTR->context = psPortDev;
|
||||
psUTR->bIsTransferDone = 0;
|
||||
psUTR->status = 0;
|
||||
|
||||
//others xfer
|
||||
rt_completion_init(&(psPortDev->utr_completion));
|
||||
|
||||
if (pipe->ep.bmAttributes == USB_EP_ATTR_BULK)
|
||||
{
|
||||
if (nu_bulk_xfer(psPortDev, psUTR, timeouts) < 0)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: bulk transfer failed\n"));
|
||||
goto exit_nu_pipe_xfer;
|
||||
}
|
||||
}
|
||||
else if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
|
||||
{
|
||||
psUTR->func = int_xfer_done_cb;
|
||||
psUTR->context = pipe;
|
||||
|
||||
if (nu_int_xfer(pipe, psPortDev, psUTR, timeouts) < 0)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: int transfer failed\n"));
|
||||
//goto exit_nu_pipe_xfer;
|
||||
}
|
||||
else
|
||||
{
|
||||
i32XferLen = nbytes;
|
||||
}
|
||||
return i32XferLen;
|
||||
}
|
||||
else if (pipe->ep.bmAttributes == USB_EP_ATTR_ISOC)
|
||||
{
|
||||
//TODO: ISO transfer
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: isoc transfer not support\n"));
|
||||
goto exit_nu_pipe_xfer;
|
||||
}
|
||||
|
||||
} //else
|
||||
|
||||
if (psUTR->bIsTransferDone == 0)
|
||||
{
|
||||
//Timeout
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: timeout\n"));
|
||||
pipe->status = UPIPE_STATUS_ERROR;
|
||||
usbh_quit_utr(psUTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transfer Done. Get status
|
||||
if (psUTR->status == 0)
|
||||
{
|
||||
pipe->status = UPIPE_STATUS_OK;
|
||||
}
|
||||
else if (psUTR->status == USBH_ERR_STALL)
|
||||
{
|
||||
pipe->status = UPIPE_STATUS_STALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pipe->status = UPIPE_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
i32XferLen = psUTR->xfer_len;
|
||||
|
||||
//Call callback
|
||||
if (pipe->callback != RT_NULL)
|
||||
{
|
||||
struct uhost_msg msg;
|
||||
msg.type = USB_MSG_CALLBACK;
|
||||
msg.content.cb.function = pipe->callback;
|
||||
msg.content.cb.context = pipe->user_data;
|
||||
rt_usbh_event_signal(&msg);
|
||||
}
|
||||
|
||||
if (pipe->status != UPIPE_STATUS_OK)
|
||||
goto exit_nu_pipe_xfer;
|
||||
|
||||
exit_nu_pipe_xfer:
|
||||
|
||||
#if defined(BSP_USING_MMU)
|
||||
if ((nbytes) &&
|
||||
(buffer_nonch != buffer))
|
||||
{
|
||||
mmu_invalidate_dcache((uint32_t)buffer_nonch, nbytes);
|
||||
rt_memcpy(buffer, buffer_nonch, nbytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (psUTR)
|
||||
free_utr(psUTR);
|
||||
|
||||
return i32XferLen;
|
||||
}
|
||||
|
||||
/* Polling USB root hub status task */
|
||||
static void nu_usbh_rh_thread_entry(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
usbh_polling_root_hubs();
|
||||
rt_thread_mdelay(NU_USBHOST_HUB_POLLING_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
static void nu_hcd_connect_callback(
|
||||
struct udev_t *udev,
|
||||
int param)
|
||||
{
|
||||
int i;
|
||||
int port_index;
|
||||
S_NU_RH_PORT_CTRL *psPortCtrl;
|
||||
|
||||
/* Igrone event if role is USBD*/
|
||||
if (nu_sys_usb0_role() == USB0_ID_HOST)
|
||||
{
|
||||
SYS_UnlockReg();
|
||||
outpw(REG_SYS_MISCFCR, (inpw(REG_SYS_MISCFCR) | (1 << 11))); /* Set USRHDSEN as 1; USB host/device role selection decided by USBID (SYS_PWRON[16]) */
|
||||
outpw(REG_SYS_PWRON, (inpw(REG_SYS_PWRON) | (1 << 16))); /* Set USB port 0 used for Host */
|
||||
SYS_LockReg();
|
||||
}
|
||||
|
||||
for (i = 0; i < NU_MAX_USBH_PORT; i++)
|
||||
{
|
||||
psPortCtrl = &s_sUSBHDev.asPortCtrl[i];
|
||||
if (psPortCtrl->sRHPortDev.pUDev == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= NU_MAX_USBH_PORT)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("ERROR: port connect slot is full\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
port_index = i + 1;
|
||||
psPortCtrl->sRHPortDev.pUDev = udev;
|
||||
psPortCtrl->sRHPortDev.bRHParent = TRUE;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb connected\n"));
|
||||
|
||||
if (udev->speed == SPEED_HIGH)
|
||||
rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_TRUE);
|
||||
else
|
||||
rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_FALSE);
|
||||
}
|
||||
|
||||
static void nu_hcd_disconnect_callback(
|
||||
struct udev_t *udev,
|
||||
int param)
|
||||
{
|
||||
int i;
|
||||
int port_index;
|
||||
S_NU_RH_PORT_CTRL *psPortCtrl;
|
||||
|
||||
for (i = 0; i < NU_MAX_USBH_PORT; i++)
|
||||
{
|
||||
psPortCtrl = &s_sUSBHDev.asPortCtrl[i];
|
||||
if (psPortCtrl->sRHPortDev.pUDev == udev)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= NU_MAX_USBH_PORT)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("ERROR: udev not found\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
port_index = i + 1;
|
||||
|
||||
for (i = 0; i < NU_MAX_USBH_PIPE; i++)
|
||||
{
|
||||
if (psPortCtrl->sRHPortDev.apsEPInfo[i] != NULL)
|
||||
{
|
||||
usbh_quit_xfer(psPortCtrl->sRHPortDev.pUDev, psPortCtrl->sRHPortDev.apsEPInfo[i]);
|
||||
}
|
||||
}
|
||||
|
||||
psPortCtrl->sRHPortDev.pUDev = NULL;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb disconnect\n"));
|
||||
|
||||
rt_usbh_root_hub_disconnect_handler(&s_sUSBHDev.uhcd, port_index);
|
||||
|
||||
if (nu_sys_usb0_role() != USB0_ID_HOST)
|
||||
{
|
||||
SYS_UnlockReg();
|
||||
outpw(REG_SYS_MISCFCR, (inpw(REG_SYS_MISCFCR) & (~(1 << 11))));
|
||||
outpw(REG_SYS_PWRON, (inpw(REG_SYS_PWRON) & (~(1 << 16))));
|
||||
SYS_LockReg();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* USB host operations -----------------------------------------------------------*/
|
||||
static struct uhcd_ops nu_uhcd_ops =
|
||||
{
|
||||
nu_reset_port,
|
||||
nu_pipe_xfer,
|
||||
nu_open_pipe,
|
||||
nu_close_pipe,
|
||||
};
|
||||
|
||||
static rt_err_t nu_hcd_init(rt_device_t device)
|
||||
{
|
||||
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
|
||||
usbh_core_init();
|
||||
|
||||
//install connect/disconnect callback
|
||||
usbh_install_conn_callback(nu_hcd_connect_callback, nu_hcd_disconnect_callback);
|
||||
usbh_polling_root_hubs();
|
||||
|
||||
//create thread for polling usbh port status
|
||||
/* create usb hub thread */
|
||||
pNuUSBHDev->polling_thread = rt_thread_create("usbh_drv", nu_usbh_rh_thread_entry, RT_NULL,
|
||||
NU_USBH_THREAD_STACK_SIZE, 8, 20);
|
||||
RT_ASSERT(pNuUSBHDev->polling_thread != RT_NULL);
|
||||
|
||||
/* startup usb host thread */
|
||||
rt_thread_startup(pNuUSBHDev->polling_thread);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* global function for USB host library -----------------------------*/
|
||||
uint32_t usbh_get_ticks(void)
|
||||
{
|
||||
return rt_tick_get();
|
||||
}
|
||||
|
||||
void usbh_delay_ms(int msec)
|
||||
{
|
||||
rt_thread_mdelay(msec);
|
||||
}
|
||||
|
||||
uint32_t usbh_tick_from_millisecond(uint32_t msec)
|
||||
{
|
||||
return rt_tick_from_millisecond(msec);
|
||||
}
|
||||
|
||||
#if defined(RT_USING_PM)
|
||||
|
||||
/* device pm suspend() entry. */
|
||||
static int usbhost_pm_suspend(const struct rt_device *device, rt_uint8_t mode)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
|
||||
|
||||
RT_ASSERT(pNuUSBHDev != RT_NULL);
|
||||
switch (mode)
|
||||
{
|
||||
case PM_SLEEP_MODE_LIGHT:
|
||||
case PM_SLEEP_MODE_DEEP:
|
||||
|
||||
pNuUSBHDev->polling_thread->stat = RT_THREAD_READY;
|
||||
result = rt_thread_suspend(pNuUSBHDev->polling_thread);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (int)RT_EOK;
|
||||
}
|
||||
|
||||
/* device pm resume() entry. */
|
||||
static void usbhost_pm_resume(const struct rt_device *device, rt_uint8_t mode)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
|
||||
RT_ASSERT(pNuUSBHDev != RT_NULL);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case PM_SLEEP_MODE_LIGHT:
|
||||
case PM_SLEEP_MODE_DEEP:
|
||||
result = rt_thread_resume(pNuUSBHDev->polling_thread);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct rt_device_pm_ops device_pm_ops =
|
||||
{
|
||||
.suspend = usbhost_pm_suspend,
|
||||
.resume = usbhost_pm_resume,
|
||||
.frequency_change = RT_NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
int nu_usbh_register(void)
|
||||
{
|
||||
rt_err_t res;
|
||||
uhcd_t psUHCD;
|
||||
|
||||
psUHCD = (uhcd_t)&s_sUSBHDev.uhcd;
|
||||
|
||||
psUHCD->parent.type = RT_Device_Class_USBHost;
|
||||
psUHCD->parent.init = nu_hcd_init;
|
||||
psUHCD->parent.user_data = &s_sUSBHDev;
|
||||
|
||||
psUHCD->ops = &nu_uhcd_ops;
|
||||
psUHCD->num_ports = NU_MAX_USBH_PORT;
|
||||
|
||||
res = rt_device_register(&psUHCD->parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE);
|
||||
RT_ASSERT(res == RT_EOK);
|
||||
|
||||
nu_sys_ipclk_enable(s_sUSBHDev.clkidx);
|
||||
nu_sys_ip_reset(s_sUSBHDev.rstidx);
|
||||
|
||||
|
||||
/*initialize the usb host function */
|
||||
res = rt_usb_host_init();
|
||||
RT_ASSERT(res == RT_EOK);
|
||||
|
||||
#if defined(RT_USING_PM)
|
||||
rt_pm_device_register(&psUHCD->parent, &device_pm_ops);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(nu_usbh_register);
|
||||
|
||||
#endif
|
|
@ -125,6 +125,11 @@ CONFIG_RT_DFS_ELM_WORD_ACCESS=y
|
|||
# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set
|
||||
CONFIG_RT_DFS_ELM_USE_LFN_3=y
|
||||
CONFIG_RT_DFS_ELM_USE_LFN=3
|
||||
CONFIG_RT_DFS_ELM_LFN_UNICODE_0=y
|
||||
# CONFIG_RT_DFS_ELM_LFN_UNICODE_1 is not set
|
||||
# CONFIG_RT_DFS_ELM_LFN_UNICODE_2 is not set
|
||||
# CONFIG_RT_DFS_ELM_LFN_UNICODE_3 is not set
|
||||
CONFIG_RT_DFS_ELM_LFN_UNICODE=0
|
||||
CONFIG_RT_DFS_ELM_MAX_LFN=255
|
||||
CONFIG_RT_DFS_ELM_DRIVES=8
|
||||
CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=4096
|
||||
|
@ -133,7 +138,12 @@ CONFIG_RT_DFS_ELM_REENTRANT=y
|
|||
CONFIG_RT_USING_DFS_DEVFS=y
|
||||
# CONFIG_RT_USING_DFS_ROMFS is not set
|
||||
# CONFIG_RT_USING_DFS_RAMFS is not set
|
||||
# CONFIG_RT_USING_DFS_UFFS is not set
|
||||
CONFIG_RT_USING_DFS_UFFS=y
|
||||
# CONFIG_RT_UFFS_ECC_MODE_0 is not set
|
||||
# CONFIG_RT_UFFS_ECC_MODE_1 is not set
|
||||
# CONFIG_RT_UFFS_ECC_MODE_2 is not set
|
||||
CONFIG_RT_UFFS_ECC_MODE_3=y
|
||||
CONFIG_RT_UFFS_ECC_MODE=3
|
||||
# CONFIG_RT_USING_DFS_JFFS2 is not set
|
||||
# CONFIG_RT_USING_DFS_NFS is not set
|
||||
|
||||
|
@ -162,7 +172,8 @@ CONFIG_RT_USING_ADC=y
|
|||
# CONFIG_RT_USING_DAC is not set
|
||||
CONFIG_RT_USING_PWM=y
|
||||
# CONFIG_RT_USING_MTD_NOR is not set
|
||||
# CONFIG_RT_USING_MTD_NAND is not set
|
||||
CONFIG_RT_USING_MTD_NAND=y
|
||||
CONFIG_RT_MTD_NAND_DEBUG=y
|
||||
# CONFIG_RT_USING_PM is not set
|
||||
CONFIG_RT_USING_RTC=y
|
||||
CONFIG_RT_USING_ALARM=y
|
||||
|
@ -174,12 +185,7 @@ CONFIG_RTC_NTP_SYNC_PERIOD=3600
|
|||
CONFIG_RT_USING_SPI=y
|
||||
CONFIG_RT_USING_QSPI=y
|
||||
# CONFIG_RT_USING_SPI_MSD is not set
|
||||
CONFIG_RT_USING_SFUD=y
|
||||
CONFIG_RT_SFUD_USING_SFDP=y
|
||||
CONFIG_RT_SFUD_USING_FLASH_INFO_TABLE=y
|
||||
CONFIG_RT_SFUD_USING_QSPI=y
|
||||
CONFIG_RT_SFUD_SPI_MAX_HZ=50000000
|
||||
# CONFIG_RT_DEBUG_SFUD is not set
|
||||
# CONFIG_RT_USING_SFUD is not set
|
||||
# CONFIG_RT_USING_ENC28J60 is not set
|
||||
# CONFIG_RT_USING_SPI_WIFI is not set
|
||||
CONFIG_RT_USING_WDT=y
|
||||
|
@ -222,7 +228,7 @@ CONFIG_RT_HWCRYPTO_USING_RNG=y
|
|||
#
|
||||
CONFIG_RT_USING_USB_HOST=y
|
||||
CONFIG_RT_USBH_MSTORAGE=y
|
||||
CONFIG_UDISK_MOUNTPOINT="/"
|
||||
CONFIG_UDISK_MOUNTPOINT="/mnt/udisk"
|
||||
CONFIG_RT_USING_USB_DEVICE=y
|
||||
CONFIG_RT_USBD_THREAD_STACK_SZ=4096
|
||||
CONFIG_USB_VENDOR_ID=0x0FFE
|
||||
|
@ -264,6 +270,7 @@ CONFIG_RT_USING_POSIX=y
|
|||
# Socket abstraction layer
|
||||
#
|
||||
CONFIG_RT_USING_SAL=y
|
||||
CONFIG_SAL_INTERNET_CHECK=y
|
||||
|
||||
#
|
||||
# protocol stack implement
|
||||
|
@ -523,21 +530,7 @@ CONFIG_PKG_NETUTILS_VER="v1.2.0"
|
|||
# CONFIG_PKG_USING_PIXMAN is not set
|
||||
# CONFIG_PKG_USING_LWEXT4 is not set
|
||||
# CONFIG_PKG_USING_PARTITION is not set
|
||||
CONFIG_PKG_USING_FAL=y
|
||||
CONFIG_PKG_FAL_PATH="/packages/system/fal"
|
||||
CONFIG_FAL_DEBUG_CONFIG=y
|
||||
CONFIG_FAL_DEBUG=1
|
||||
CONFIG_FAL_PART_HAS_TABLE_CFG=y
|
||||
CONFIG_FAL_USING_SFUD_PORT=y
|
||||
CONFIG_FAL_USING_NOR_FLASH_DEV_NAME="norflash0"
|
||||
# CONFIG_PKG_USING_FAL_V00500 is not set
|
||||
# CONFIG_PKG_USING_FAL_V00400 is not set
|
||||
# CONFIG_PKG_USING_FAL_V00300 is not set
|
||||
# CONFIG_PKG_USING_FAL_V00200 is not set
|
||||
# CONFIG_PKG_USING_FAL_V00100 is not set
|
||||
CONFIG_PKG_USING_FAL_LATEST_VERSION=y
|
||||
CONFIG_PKG_FAL_VER="latest"
|
||||
CONFIG_PKG_FAL_VER_NUM=0x99999
|
||||
# CONFIG_PKG_USING_FAL is not set
|
||||
# CONFIG_PKG_USING_FLASHDB is not set
|
||||
# CONFIG_PKG_USING_SQLITE is not set
|
||||
# CONFIG_PKG_USING_RTI is not set
|
||||
|
@ -707,6 +700,7 @@ CONFIG_NU_PKG_USING_DEMO=y
|
|||
# CONFIG_NU_PKG_USING_NAU88L25 is not set
|
||||
CONFIG_NU_PKG_USING_NAU8822=y
|
||||
# CONFIG_NU_PKG_USING_ILI9341 is not set
|
||||
CONFIG_NU_PKG_USING_SPINAND=y
|
||||
|
||||
#
|
||||
# Hardware Drivers Config
|
||||
|
@ -734,23 +728,18 @@ CONFIG_BSP_USING_TMR=y
|
|||
CONFIG_BSP_USING_TIMER=y
|
||||
CONFIG_BSP_USING_TMR0=y
|
||||
CONFIG_BSP_USING_TIMER0=y
|
||||
# CONFIG_BSP_USING_TPWM0 is not set
|
||||
# CONFIG_BSP_USING_TIMER0_CAPTURE is not set
|
||||
CONFIG_BSP_USING_TMR1=y
|
||||
CONFIG_BSP_USING_TIMER1=y
|
||||
# CONFIG_BSP_USING_TPWM1 is not set
|
||||
# CONFIG_BSP_USING_TIMER1_CAPTURE is not set
|
||||
CONFIG_BSP_USING_TMR2=y
|
||||
CONFIG_BSP_USING_TIMER2=y
|
||||
# CONFIG_BSP_USING_TPWM2 is not set
|
||||
# CONFIG_BSP_USING_TIMER2_CAPTURE is not set
|
||||
CONFIG_BSP_USING_TMR3=y
|
||||
CONFIG_BSP_USING_TIMER3=y
|
||||
# CONFIG_BSP_USING_TPWM3 is not set
|
||||
# CONFIG_BSP_USING_TIMER3_CAPTURE is not set
|
||||
CONFIG_BSP_USING_TMR4=y
|
||||
CONFIG_BSP_USING_TIMER4=y
|
||||
# CONFIG_BSP_USING_TPWM4 is not set
|
||||
# CONFIG_BSP_USING_TIMER4_CAPTURE is not set
|
||||
CONFIG_BSP_USING_UART=y
|
||||
CONFIG_BSP_USING_UART0=y
|
||||
|
@ -793,7 +782,7 @@ CONFIG_BSP_USING_I2S=y
|
|||
CONFIG_NU_I2S_DMA_FIFO_SIZE=4096
|
||||
CONFIG_BSP_USING_QSPI=y
|
||||
CONFIG_BSP_USING_QSPI0=y
|
||||
# CONFIG_BSP_USING_QSPI0_PDMA is not set
|
||||
CONFIG_BSP_USING_QSPI0_PDMA=y
|
||||
# CONFIG_BSP_USING_SCUART is not set
|
||||
CONFIG_BSP_USING_CRYPTO=y
|
||||
# CONFIG_NU_PRNG_USE_SEED is not set
|
||||
|
@ -802,7 +791,6 @@ CONFIG_BSP_USING_WDT=y
|
|||
# CONFIG_BSP_USING_EBI is not set
|
||||
CONFIG_BSP_USING_USBD=y
|
||||
CONFIG_BSP_USING_USBH=y
|
||||
CONFIG_BSP_USING_OTG=y
|
||||
|
||||
#
|
||||
# On-board Peripheral Drivers
|
||||
|
@ -811,11 +799,10 @@ CONFIG_BSP_USING_CONSOLE=y
|
|||
CONFIG_BOARD_USING_IP101GR=y
|
||||
CONFIG_BOARD_USING_NAU8822=y
|
||||
CONFIG_BOARD_USING_STORAGE_SDCARD=y
|
||||
CONFIG_BOARD_USING_STORAGE_SPIFLASH=y
|
||||
# CONFIG_BOARD_USING_USB_NONE is not set
|
||||
# CONFIG_BOARD_USING_USB_HOST is not set
|
||||
# CONFIG_BOARD_USING_USB_OTG is not set
|
||||
CONFIG_BOARD_USING_USB_OTG_HOST=y
|
||||
# CONFIG_BOARD_USING_STORAGE_SPIFLASH is not set
|
||||
CONFIG_BOARD_USING_STORAGE_SPINAND=y
|
||||
CONFIG_BOARD_USING_USB0_DEVICE_HOST=y
|
||||
CONFIG_BOARD_USING_USB1_HOST=y
|
||||
|
||||
#
|
||||
# Board extended module drivers
|
||||
|
|
|
@ -43,8 +43,8 @@ Nuvoton Technology provides industrial IoT development platform using NUC980DK61
|
|||
|LEDs | | Supported |
|
||||
|Audio Codec | NAU8822, Supports MIC and earphone | Supported |
|
||||
|USB Device | VCOM + MStorage | Supported |
|
||||
|2xUSB Host | MStorage | Not ready |
|
||||
|SPI NAND flash | W25N01GVZE1G | Not ready |
|
||||
|2xUSB Host | MStorage | Supported |
|
||||
|SPI NAND flash | W25N01GVZE1G | Supported |
|
||||
|VCOM | For console | Ready.(Need to install VCOM driver) |
|
||||
|
||||
## 2. Supported compiler
|
||||
|
@ -88,6 +88,43 @@ Execute Address: 0x0<br>
|
|||
Enjoy!! <br>
|
||||
<br>
|
||||
|
||||
### 3.3 SPI NAND flash using NuWriter
|
||||
You can use NuWriter to program rtthread.bin into SPI NAND flash.
|
||||
[![SPI NAND flash](https://i.imgur.com/p9LudBK.gif "SPI NAND flash")](https://i.imgur.com/p9LudBK.gif "SPI NAND flash using NuWriter")
|
||||
<br>
|
||||
Choose type: SPINAND<br>
|
||||
<< Press Re-Connect >><br>
|
||||
|
||||
<< Press Erase >><br>
|
||||
<< Select Erase All >><br>
|
||||
<< Press OK >><br>
|
||||
|
||||
Choose file: Specify your uboot-spl.bin file.<br>
|
||||
Image Type: Loader<br>
|
||||
Execute Address: 0x200<br>
|
||||
<< Press Program >><br>
|
||||
|
||||
Choose file: Specify your uboot.bin file.<br>
|
||||
Image Type: Data<br>
|
||||
Image start address: 0x100000<br>
|
||||
<< Press Program >><br>
|
||||
|
||||
Choose file: Specify your rtthread.bin file.<br>
|
||||
Image Type: Data<br>
|
||||
Image start address: 0x200000<br>
|
||||
<< Press Program >><br>
|
||||
|
||||
Choose file: Specify your env.txt file.<br>
|
||||
Image Type: Environment<br>
|
||||
Image start address: 0x80000<br>
|
||||
<< Press Program >><br>
|
||||
|
||||
<< Press OK & Wait it down >><br>
|
||||
<< Set Power-on setting to SPI NAND booting >><br>
|
||||
<< Press Reset button on board >><br>
|
||||
Enjoy!! <br>
|
||||
<br>
|
||||
|
||||
## 4. Test
|
||||
You can use Tera Term terminate emulator (or other software) to type commands of RTT. All parameters of serial communication are shown in below image. Here, you can find out the corresponding port number of Nuvoton Virtual Com Port in window device manager.
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
/* defined the LED_Y pin: PB8 */
|
||||
#define LED_Y NU_GET_PININDEX(NU_PB, 8)
|
||||
|
||||
#if !defined(BSP_USING_USBH)
|
||||
/* defined the Key1 pin: PE10 */
|
||||
#define KEY_1 NU_GET_PININDEX(NU_PE, 10)
|
||||
|
||||
|
@ -47,6 +48,8 @@ void nu_button_cb(void *args)
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if defined(RT_USING_PIN)
|
||||
|
@ -58,6 +61,7 @@ int main(int argc, char **argv)
|
|||
/* set LED_Y pin mode to output */
|
||||
rt_pin_mode(LED_Y, PIN_MODE_OUTPUT);
|
||||
|
||||
#if !defined(BSP_USING_USBH)
|
||||
/* set KEY_1 pin mode to input */
|
||||
rt_pin_mode(KEY_1, PIN_MODE_INPUT_PULLUP);
|
||||
|
||||
|
@ -69,6 +73,7 @@ int main(int argc, char **argv)
|
|||
|
||||
rt_pin_attach_irq(KEY_2, PIN_IRQ_MODE_FALLING, nu_button_cb, &u32Key2);
|
||||
rt_pin_irq_enable(KEY_2, PIN_IRQ_ENABLE);
|
||||
#endif
|
||||
|
||||
while (counter--)
|
||||
{
|
||||
|
|
|
@ -53,7 +53,10 @@ const void *data;
|
|||
|
||||
const struct dfs_mount_tbl mount_table[] =
|
||||
{
|
||||
{ RAMDISK_UDC, "/ramdisk_udc", "elm", 0, RT_NULL },
|
||||
{ RAMDISK_UDC, "/mnt/ram_usbd", "elm", 0, RT_NULL },
|
||||
#if defined(RT_USING_DFS_UFFS)
|
||||
{ "nand1", "/mnt/filesystem", "uffs", 0, RT_NULL },
|
||||
#endif
|
||||
{0},
|
||||
};
|
||||
#endif
|
||||
|
@ -171,10 +174,11 @@ int filesystem_init(void)
|
|||
LOG_I("ramdisk mounted on \"/\".");
|
||||
|
||||
/* now you can create dir dynamically. */
|
||||
mkdir_p("/ramdisk_udc", 0x777);
|
||||
mkdir_p("/mnt", 0x777);
|
||||
mkdir_p("/cache", 0x777);
|
||||
mkdir_p("/download", 0x777);
|
||||
mkdir_p("/mnt/ram_usbd", 0x777);
|
||||
mkdir_p("/mnt/filesystem", 0x777);
|
||||
#if defined(RT_USBH_MSTORAGE) && defined(UDISK_MOUNTPOINT)
|
||||
mkdir_p(UDISK_MOUNTPOINT, 0x777);
|
||||
#endif
|
||||
|
@ -219,11 +223,6 @@ int mnt_init_spiflash0(void)
|
|||
rt_kprintf("Failed to create block device for %s.\n", PARTITION_NAME_FILESYSTEM);
|
||||
goto exit_mnt_init_spiflash0;
|
||||
}
|
||||
else if (mkdir(MOUNT_POINT_SPIFLASH0, 0x777) < 0)
|
||||
{
|
||||
rt_kprintf("Failed to make folder for %s.\n", MOUNT_POINT_SPIFLASH0);
|
||||
goto exit_mnt_init_spiflash0;
|
||||
}
|
||||
else if (dfs_mount(psNorFlash->parent.name, MOUNT_POINT_SPIFLASH0, "elm", 0, 0) != 0)
|
||||
{
|
||||
rt_kprintf("Failed to mount elm on %s.\n", MOUNT_POINT_SPIFLASH0);
|
||||
|
|
|
@ -33,39 +33,31 @@ menu "Hardware Drivers Config"
|
|||
default y
|
||||
|
||||
config BOARD_USING_STORAGE_SPIFLASH
|
||||
bool "SPIFLASH supporting(over qspi0)"
|
||||
bool "SPI NOR FLASH supporting(over qspi0)"
|
||||
select BSP_USING_QSPI
|
||||
select BSP_USING_QSPI0
|
||||
default n
|
||||
|
||||
config BOARD_USING_STORAGE_SPINAND
|
||||
bool "SPI NAND FLASH supporting(over qspi0)"
|
||||
select BSP_USING_QSPI
|
||||
select BSP_USING_QSPI0
|
||||
select NU_PKG_USING_SPINAND
|
||||
default y
|
||||
|
||||
choice
|
||||
prompt "Select HS USB Ports"
|
||||
config BOARD_USING_USB0_DEVICE_HOST
|
||||
select BSP_USING_USBH
|
||||
select BSP_USING_USBD
|
||||
bool "Enable USB0 Device/Host"
|
||||
help
|
||||
Choose this option if you need USB device or host function mode.
|
||||
If you need USB host, please remember short to ground on JP1 jumper.
|
||||
|
||||
config BOARD_USING_USB_NONE
|
||||
bool "Without any USB function"
|
||||
help
|
||||
Choose this option if you need not USB functions.
|
||||
|
||||
config BOARD_USING_USB_HOST
|
||||
select BSP_USING_USBH
|
||||
bool "Enable USBH"
|
||||
help
|
||||
Choose this option if you need USB HOST function mode.
|
||||
|
||||
config BOARD_USING_USB_OTG
|
||||
select BSP_USING_OTG
|
||||
bool "Enable OTG"
|
||||
help
|
||||
Choose this option if you need USB HOST function mode.
|
||||
|
||||
config BOARD_USING_USB_OTG_HOST
|
||||
select BSP_USING_USBH
|
||||
select BSP_USING_OTG
|
||||
bool "Enable OTG AND USBH"
|
||||
help
|
||||
Choose this option if you need both USB ports function mode.
|
||||
|
||||
endchoice
|
||||
config BOARD_USING_USB1_HOST
|
||||
select BSP_USING_USBH
|
||||
bool "Enable USB1 Host"
|
||||
help
|
||||
Choose this option if you need USB1 HOST.
|
||||
|
||||
endmenu
|
||||
|
||||
|
|
|
@ -28,6 +28,12 @@
|
|||
#define BOARD_SDRAM_SIZE 0x04000000
|
||||
#define BOARD_HEAP_END ((void*)BOARD_SDRAM_SIZE)
|
||||
|
||||
#if defined(RT_USING_MTD_NAND)
|
||||
#include <drivers/mtd_nand.h>
|
||||
#define MTD_SPINAND_PARTITION_NUM 3
|
||||
extern struct rt_mtd_nand_device mtd_partitions[MTD_SPINAND_PARTITION_NUM];
|
||||
#endif
|
||||
|
||||
extern void rt_hw_board_init(void);
|
||||
extern void nu_clock_init(void);
|
||||
extern void nu_clock_deinit(void);
|
||||
|
|
|
@ -30,8 +30,11 @@
|
|||
static rt_uint8_t SpiFlash_ReadStatusReg(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_uint8_t u8Val;
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_uint8_t w25x_txCMD1 = W25X_REG_READSTATUS;
|
||||
rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
|
||||
result = rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
RT_ASSERT(result > 0);
|
||||
|
||||
return u8Val;
|
||||
}
|
||||
|
@ -39,24 +42,53 @@ static rt_uint8_t SpiFlash_ReadStatusReg(struct rt_qspi_device *qspi_device)
|
|||
static rt_uint8_t SpiFlash_ReadStatusReg2(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_uint8_t u8Val;
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_uint8_t w25x_txCMD1 = W25X_REG_READSTATUS2;
|
||||
rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
|
||||
result = rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
RT_ASSERT(result > 0);
|
||||
|
||||
return u8Val;
|
||||
}
|
||||
|
||||
static void SpiFlash_WriteStatusReg(struct rt_qspi_device *qspi_device, uint8_t u8Value1, uint8_t u8Value2)
|
||||
static rt_err_t SpiFlash_WriteStatusReg(struct rt_qspi_device *qspi_device, uint8_t u8Value1, uint8_t u8Value2)
|
||||
{
|
||||
rt_uint8_t w25x_txCMD1;
|
||||
rt_uint8_t u8Val[3];
|
||||
rt_uint8_t au8Val[2];
|
||||
rt_err_t result;
|
||||
struct rt_qspi_message qspi_message = {0};
|
||||
|
||||
/* Enable WE */
|
||||
w25x_txCMD1 = W25X_REG_WRITEENABLE;
|
||||
rt_qspi_send(qspi_device, &w25x_txCMD1, 1);
|
||||
result = rt_qspi_send(qspi_device, &w25x_txCMD1, sizeof(w25x_txCMD1));
|
||||
if (result != sizeof(w25x_txCMD1))
|
||||
goto exit_SpiFlash_WriteStatusReg;
|
||||
|
||||
u8Val[0] = W25X_REG_WRITESTATUS;
|
||||
u8Val[1] = u8Value1;
|
||||
u8Val[2] = u8Value2;
|
||||
rt_qspi_send(qspi_device, &u8Val, 3);
|
||||
/* Prepare status-1, 2 data */
|
||||
au8Val[0] = u8Value1;
|
||||
au8Val[1] = u8Value2;
|
||||
|
||||
/* 1-bit mode: Instruction+payload */
|
||||
qspi_message.instruction.content = W25X_REG_WRITESTATUS;
|
||||
qspi_message.instruction.qspi_lines = 1;
|
||||
|
||||
qspi_message.qspi_data_lines = 1;
|
||||
qspi_message.parent.cs_take = 1;
|
||||
qspi_message.parent.cs_release = 1;
|
||||
qspi_message.parent.send_buf = &au8Val[0];
|
||||
qspi_message.parent.length = sizeof(au8Val);
|
||||
qspi_message.parent.next = RT_NULL;
|
||||
|
||||
if (rt_qspi_transfer_message(qspi_device, &qspi_message) != sizeof(au8Val))
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
}
|
||||
|
||||
result = RT_EOK;
|
||||
|
||||
exit_SpiFlash_WriteStatusReg:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void SpiFlash_WaitReady(struct rt_qspi_device *qspi_device)
|
||||
|
@ -73,21 +105,30 @@ static void SpiFlash_WaitReady(struct rt_qspi_device *qspi_device)
|
|||
|
||||
static void SpiFlash_EnterQspiMode(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
uint8_t u8Status1 = SpiFlash_ReadStatusReg(qspi_device);
|
||||
uint8_t u8Status2 = SpiFlash_ReadStatusReg2(qspi_device);
|
||||
|
||||
u8Status2 |= W25X_REG_QUADENABLE;
|
||||
SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
|
||||
result = SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
SpiFlash_WaitReady(qspi_device);
|
||||
}
|
||||
|
||||
static void SpiFlash_ExitQspiMode(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
uint8_t u8Status1 = SpiFlash_ReadStatusReg(qspi_device);
|
||||
uint8_t u8Status2 = SpiFlash_ReadStatusReg2(qspi_device);
|
||||
|
||||
u8Status2 &= ~W25X_REG_QUADENABLE;
|
||||
SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
|
||||
result = SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
SpiFlash_WaitReady(qspi_device);
|
||||
}
|
||||
|
||||
|
@ -105,7 +146,49 @@ static int rt_hw_spiflash_init(void)
|
|||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(rt_hw_spiflash_init);
|
||||
#endif /* BOARD_USING_STORAGE_SPIFLASH */
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_USING_STORAGE_SPINAND) && defined(NU_PKG_USING_SPINAND)
|
||||
|
||||
#include "drv_qspi.h"
|
||||
#include "spinand.h"
|
||||
|
||||
struct rt_mtd_nand_device mtd_partitions[MTD_SPINAND_PARTITION_NUM] =
|
||||
{
|
||||
[0] =
|
||||
{
|
||||
.block_start = 0,
|
||||
.block_end = 23,
|
||||
.block_total = 24,
|
||||
},
|
||||
[1] =
|
||||
{
|
||||
.block_start = 24,
|
||||
.block_end = 1023,
|
||||
.block_total = 1000,
|
||||
},
|
||||
[2] =
|
||||
{
|
||||
.block_start = 0,
|
||||
.block_end = 1023,
|
||||
.block_total = 1024,
|
||||
}
|
||||
};
|
||||
|
||||
static int rt_hw_spinand_init(void)
|
||||
{
|
||||
if (nu_qspi_bus_attach_device("qspi0", "qspi01", 4, RT_NULL, RT_NULL) != RT_EOK)
|
||||
return -1;
|
||||
|
||||
if (rt_hw_mtd_spinand_register("qspi01") != RT_EOK)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
INIT_COMPONENT_EXPORT(rt_hw_spinand_init);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BOARD_USING_LCD_ILI9341) && defined(NU_PKG_USING_ILI9341_SPI)
|
||||
#include <lcd_ili9341.h>
|
||||
|
@ -161,9 +244,9 @@ static int rt_hw_esp8266_port(void)
|
|||
AT_DEVICE_CLASS_ESP8266,
|
||||
(void *) esp8266);
|
||||
}
|
||||
//INIT_APP_EXPORT(rt_hw_esp8266_port);
|
||||
INIT_APP_EXPORT(rt_hw_esp8266_port);
|
||||
|
||||
static void at_wifi_set(int argc, char **argv)
|
||||
static int at_wifi_set(int argc, char **argv)
|
||||
{
|
||||
struct at_device_ssid_pwd sATDConf;
|
||||
struct at_device *at_dev = RT_NULL;
|
||||
|
@ -173,7 +256,7 @@ static void at_wifi_set(int argc, char **argv)
|
|||
{
|
||||
rt_kprintf("\n");
|
||||
rt_kprintf("at_wifi_set <ssid> <password>\n");
|
||||
return ;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sATDConf.ssid = argv[1]; //ssid
|
||||
|
@ -185,6 +268,8 @@ static void at_wifi_set(int argc, char **argv)
|
|||
{
|
||||
rt_kprintf("Can't find any initialized AT device.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#ifdef FINSH_USING_MSH
|
||||
MSH_CMD_EXPORT(at_wifi_set, AT device wifi set ssid / password function);
|
||||
|
|
|
@ -78,10 +78,16 @@ static void nu_pin_can_init(void)
|
|||
|
||||
}
|
||||
|
||||
#if defined(BSP_USING_USBD)
|
||||
static void nu_pin_usbd_init(void)
|
||||
{
|
||||
/* USB0_VBUSVLD, PE.11 */
|
||||
//outpw(REG_SYS_GPE_MFPH, (inpw(REG_SYS_GPE_MFPH) & ~0x0000F000) | 0x00001000);
|
||||
outpw(REG_SYS_GPE_MFPH, (inpw(REG_SYS_GPE_MFPH) & ~0x0000F000) | 0x00001000);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void nu_pin_usbh_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void nu_pin_init(void)
|
||||
|
@ -95,7 +101,12 @@ void nu_pin_init(void)
|
|||
nu_pin_pwm_init();
|
||||
nu_pin_i2s_init();
|
||||
nu_pin_can_init();
|
||||
|
||||
#if defined(BSP_USING_USBD)
|
||||
nu_pin_usbd_init();
|
||||
#endif
|
||||
|
||||
nu_pin_usbh_init();
|
||||
}
|
||||
|
||||
void nu_pin_deinit(void)
|
||||
|
|
|
@ -50,7 +50,7 @@ SECTIONS
|
|||
. = ALIGN(4);
|
||||
|
||||
/* section information for utest */
|
||||
. = ALIGN(4);
|
||||
. = ALIGN(4);
|
||||
__rt_utest_tc_tab_start = .;
|
||||
KEEP(*(UtestTcTab))
|
||||
__rt_utest_tc_tab_end = .;
|
||||
|
|
|
@ -53,10 +53,10 @@ if PLATFORM == 'gcc':
|
|||
LPATH = ''
|
||||
|
||||
if BUILD == 'debug':
|
||||
CFLAGS += ' -O0 -gdwarf-2'
|
||||
CFLAGS += ' -O2 -gdwarf-2'
|
||||
AFLAGS += ' -gdwarf-2'
|
||||
else:
|
||||
CFLAGS += ' -O0'
|
||||
CFLAGS += ' -O2'
|
||||
|
||||
POST_ACTION = OBJCPY + ' -O binary $TARGET ' + TARGET_NAME + '\n'
|
||||
POST_ACTION += SIZE + ' $TARGET\n'
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
[Version]
|
||||
Nu_LinkVersion=V5.14
|
||||
[Process]
|
||||
ProcessID=0x00003a80
|
||||
ProcessCreationTime_L=0xac7abbce
|
||||
ProcessCreationTime_H=0x01d642ca
|
||||
ProcessID=0x00004840
|
||||
ProcessCreationTime_L=0xb55cd40e
|
||||
ProcessCreationTime_H=0x01d6e4e3
|
||||
NuLinkID=0x77885acd
|
||||
NuLinkIDs_Count=0x00000001
|
||||
NuLinkID0=0x77885acd
|
||||
|
|
|
@ -30,8 +30,11 @@
|
|||
static rt_uint8_t SpiFlash_ReadStatusReg(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_uint8_t u8Val;
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_uint8_t w25x_txCMD1 = W25X_REG_READSTATUS;
|
||||
rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
|
||||
result = rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
RT_ASSERT(result > 0);
|
||||
|
||||
return u8Val;
|
||||
}
|
||||
|
@ -39,24 +42,53 @@ static rt_uint8_t SpiFlash_ReadStatusReg(struct rt_qspi_device *qspi_device)
|
|||
static rt_uint8_t SpiFlash_ReadStatusReg2(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_uint8_t u8Val;
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_uint8_t w25x_txCMD1 = W25X_REG_READSTATUS2;
|
||||
rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
|
||||
result = rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
RT_ASSERT(result > 0);
|
||||
|
||||
return u8Val;
|
||||
}
|
||||
|
||||
static void SpiFlash_WriteStatusReg(struct rt_qspi_device *qspi_device, uint8_t u8Value1, uint8_t u8Value2)
|
||||
static rt_err_t SpiFlash_WriteStatusReg(struct rt_qspi_device *qspi_device, uint8_t u8Value1, uint8_t u8Value2)
|
||||
{
|
||||
rt_uint8_t w25x_txCMD1;
|
||||
rt_uint8_t u8Val[3];
|
||||
rt_uint8_t au8Val[2];
|
||||
rt_err_t result;
|
||||
struct rt_qspi_message qspi_message = {0};
|
||||
|
||||
/* Enable WE */
|
||||
w25x_txCMD1 = W25X_REG_WRITEENABLE;
|
||||
rt_qspi_send(qspi_device, &w25x_txCMD1, 1);
|
||||
result = rt_qspi_send(qspi_device, &w25x_txCMD1, sizeof(w25x_txCMD1));
|
||||
if (result != sizeof(w25x_txCMD1))
|
||||
goto exit_SpiFlash_WriteStatusReg;
|
||||
|
||||
u8Val[0] = W25X_REG_WRITESTATUS;
|
||||
u8Val[1] = u8Value1;
|
||||
u8Val[2] = u8Value2;
|
||||
rt_qspi_send(qspi_device, &u8Val, 3);
|
||||
/* Prepare status-1, 2 data */
|
||||
au8Val[0] = u8Value1;
|
||||
au8Val[1] = u8Value2;
|
||||
|
||||
/* 1-bit mode: Instruction+payload */
|
||||
qspi_message.instruction.content = W25X_REG_WRITESTATUS;
|
||||
qspi_message.instruction.qspi_lines = 1;
|
||||
|
||||
qspi_message.qspi_data_lines = 1;
|
||||
qspi_message.parent.cs_take = 1;
|
||||
qspi_message.parent.cs_release = 1;
|
||||
qspi_message.parent.send_buf = &au8Val[0];
|
||||
qspi_message.parent.length = sizeof(au8Val);
|
||||
qspi_message.parent.next = RT_NULL;
|
||||
|
||||
if (rt_qspi_transfer_message(qspi_device, &qspi_message) != sizeof(au8Val))
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
}
|
||||
|
||||
result = RT_EOK;
|
||||
|
||||
exit_SpiFlash_WriteStatusReg:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void SpiFlash_WaitReady(struct rt_qspi_device *qspi_device)
|
||||
|
@ -73,21 +105,30 @@ static void SpiFlash_WaitReady(struct rt_qspi_device *qspi_device)
|
|||
|
||||
static void SpiFlash_EnterQspiMode(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
uint8_t u8Status1 = SpiFlash_ReadStatusReg(qspi_device);
|
||||
uint8_t u8Status2 = SpiFlash_ReadStatusReg2(qspi_device);
|
||||
|
||||
u8Status2 |= W25X_REG_QUADENABLE;
|
||||
SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
|
||||
result = SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
SpiFlash_WaitReady(qspi_device);
|
||||
}
|
||||
|
||||
static void SpiFlash_ExitQspiMode(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
uint8_t u8Status1 = SpiFlash_ReadStatusReg(qspi_device);
|
||||
uint8_t u8Status2 = SpiFlash_ReadStatusReg2(qspi_device);
|
||||
|
||||
u8Status2 &= ~W25X_REG_QUADENABLE;
|
||||
SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
|
||||
result = SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
SpiFlash_WaitReady(qspi_device);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,11 @@
|
|||
static rt_uint8_t SpiFlash_ReadStatusReg(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_uint8_t u8Val;
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_uint8_t w25x_txCMD1 = W25X_REG_READSTATUS;
|
||||
rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
|
||||
result = rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
RT_ASSERT(result > 0);
|
||||
|
||||
return u8Val;
|
||||
}
|
||||
|
@ -39,24 +42,53 @@ static rt_uint8_t SpiFlash_ReadStatusReg(struct rt_qspi_device *qspi_device)
|
|||
static rt_uint8_t SpiFlash_ReadStatusReg2(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_uint8_t u8Val;
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_uint8_t w25x_txCMD1 = W25X_REG_READSTATUS2;
|
||||
rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
|
||||
result = rt_qspi_send_then_recv(qspi_device, &w25x_txCMD1, 1, &u8Val, 1);
|
||||
RT_ASSERT(result > 0);
|
||||
|
||||
return u8Val;
|
||||
}
|
||||
|
||||
static void SpiFlash_WriteStatusReg(struct rt_qspi_device *qspi_device, uint8_t u8Value1, uint8_t u8Value2)
|
||||
static rt_err_t SpiFlash_WriteStatusReg(struct rt_qspi_device *qspi_device, uint8_t u8Value1, uint8_t u8Value2)
|
||||
{
|
||||
rt_uint8_t w25x_txCMD1;
|
||||
rt_uint8_t u8Val[3];
|
||||
rt_uint8_t au8Val[2];
|
||||
rt_err_t result;
|
||||
struct rt_qspi_message qspi_message = {0};
|
||||
|
||||
/* Enable WE */
|
||||
w25x_txCMD1 = W25X_REG_WRITEENABLE;
|
||||
rt_qspi_send(qspi_device, &w25x_txCMD1, 1);
|
||||
result = rt_qspi_send(qspi_device, &w25x_txCMD1, sizeof(w25x_txCMD1));
|
||||
if (result != sizeof(w25x_txCMD1))
|
||||
goto exit_SpiFlash_WriteStatusReg;
|
||||
|
||||
u8Val[0] = W25X_REG_WRITESTATUS;
|
||||
u8Val[1] = u8Value1;
|
||||
u8Val[2] = u8Value2;
|
||||
rt_qspi_send(qspi_device, &u8Val, 3);
|
||||
/* Prepare status-1, 2 data */
|
||||
au8Val[0] = u8Value1;
|
||||
au8Val[1] = u8Value2;
|
||||
|
||||
/* 1-bit mode: Instruction+payload */
|
||||
qspi_message.instruction.content = W25X_REG_WRITESTATUS;
|
||||
qspi_message.instruction.qspi_lines = 1;
|
||||
|
||||
qspi_message.qspi_data_lines = 1;
|
||||
qspi_message.parent.cs_take = 1;
|
||||
qspi_message.parent.cs_release = 1;
|
||||
qspi_message.parent.send_buf = &au8Val[0];
|
||||
qspi_message.parent.length = sizeof(au8Val);
|
||||
qspi_message.parent.next = RT_NULL;
|
||||
|
||||
if (rt_qspi_transfer_message(qspi_device, &qspi_message) != sizeof(au8Val))
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
}
|
||||
|
||||
result = RT_EOK;
|
||||
|
||||
exit_SpiFlash_WriteStatusReg:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void SpiFlash_WaitReady(struct rt_qspi_device *qspi_device)
|
||||
|
@ -73,21 +105,30 @@ static void SpiFlash_WaitReady(struct rt_qspi_device *qspi_device)
|
|||
|
||||
static void SpiFlash_EnterQspiMode(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
uint8_t u8Status1 = SpiFlash_ReadStatusReg(qspi_device);
|
||||
uint8_t u8Status2 = SpiFlash_ReadStatusReg2(qspi_device);
|
||||
|
||||
u8Status2 |= W25X_REG_QUADENABLE;
|
||||
SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
|
||||
result = SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
SpiFlash_WaitReady(qspi_device);
|
||||
}
|
||||
|
||||
static void SpiFlash_ExitQspiMode(struct rt_qspi_device *qspi_device)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
uint8_t u8Status1 = SpiFlash_ReadStatusReg(qspi_device);
|
||||
uint8_t u8Status2 = SpiFlash_ReadStatusReg2(qspi_device);
|
||||
|
||||
u8Status2 &= ~W25X_REG_QUADENABLE;
|
||||
SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
|
||||
result = SpiFlash_WriteStatusReg(qspi_device, u8Status1, u8Status2);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
SpiFlash_WaitReady(qspi_device);
|
||||
}
|
||||
|
||||
|
@ -265,7 +306,7 @@ static void PlayRingTone(void)
|
|||
rt_pwm_set(bpwm_dev, BPWM_DEV_CHANNEL, period, period);
|
||||
rt_thread_mdelay(50);
|
||||
|
||||
rt_pwm_set(bpwm_dev, BPWM_DEV_CHANNEL, period, period/2);
|
||||
rt_pwm_set(bpwm_dev, BPWM_DEV_CHANNEL, period, period / 2);
|
||||
rt_thread_mdelay(50);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue