2025-04-08 18:46:12 +08:00

611 lines
17 KiB
C

#include <rtthread.h>
#include <rthw.h>
#include <rtdevice.h>
#include <data_node.h>
#include <string.h>
#include "typedef.h"
#include "sys_config.h"
#include "rtos_pub.h"
#include "i2s_pub.h"
#include "i2s.h"
#include "drv_i2s.h"
#include "general_dma_pub.h"
#include "board.h"
#if(CFG_USE_I2S == 1)
#define I2S_RX_BUFFER_SIZE 2048
#define I2S_TX_BUFFER_SIZE 2048
#define I2S_RX_DMA_CHANNEL GDMA_CHANNEL_1
#define I2S_TX_DMA_CHANNEL GDMA_CHANNEL_3
#define I2S_TX_NODE_COUNT 12
#define I2S_SAMPLE_RATE (44100)
#define I2S_BIT_LENGTH (32)
#define PAUSE_EN 1
//#define I2S_RX_CALLBACK
#if (CFG_SOC_NAME == SOC_BK7252N)
#define FIFO_LEVEL_32 FIFO_LEVEL_24
#endif
#define I2S_DEFAULT_MODE (I2S_MODE| I2S_LRCK_NO_TURN| I2S_SCK_NO_TURN| I2S_MSB_FIRST| (0<<I2S_SYNC_LENGTH_BIT)| (0<<I2S_PCM_DATA_LENGTH_BIT))
#define RT_I2S_TRANS_DEBUG
#ifdef RT_I2S_TRANS_DEBUG
#define i2s_trans_dbg(fmt, ...) rt_kprintf(fmt, ##__VA_ARGS__)
#else
#define i2s_trans_dbg(fmt, ...)
#endif
#define REG_READ(addr) (*((volatile UINT32 *)(addr)))
#define REG_WRITE(addr, _data) (*((volatile UINT32 *)(addr)) = (_data))
static struct rt_i2s_bus_device g_i2s_bus;
#if 0
static void i2s_dma_mode_isr(void)
{
uint32_t tx_done;
uint32_t i2s_status;
i2s_status= REG_READ(PCM_STAT);
tx_done = i2s_status & TX_FIFO0_EMPTY;
if (i2s_status & TX_FIFO0_EMPTY)
{
i2s_status = i2s_status ^ TX_FIFO0_EMPTY;
if (g_i2s_bus.tx_paused)
{
bk_printf("#\r\n");
i2s_dma_master_enable(0);
}
}
REG_WRITE(PCM_STAT,i2s_status);
}
#endif
static void i2s_tx_node_read_complete(struct rt_data_node *node, void *user_data)
{
struct rt_device *dev = (struct rt_device *)user_data;
// i2s_trans_dbg("<func:%s> <line:%d>, read complete \n", __FUNCTION__, __LINE__);
if (dev->tx_complete != RT_NULL)
{
dev->tx_complete(dev, node->data_ptr);
}
}
static void i2s_dma_tx_pause_addr_set(UINT32 addr)
{
GDMA_CFG_ST en_cfg;
memset(&en_cfg, 0, sizeof(GDMA_CFG_ST));
en_cfg.channel = I2S_TX_DMA_CHANNEL;
en_cfg.param = addr;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_SRC_PAUSE_ADDR, &en_cfg);
}
static void i2s_dma_rx_pause_addr_set(UINT32 addr)
{
GDMA_CFG_ST en_cfg;
memset(&en_cfg, 0, sizeof(GDMA_CFG_ST));
en_cfg.channel = I2S_RX_DMA_CHANNEL;
en_cfg.param = addr;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DST_PAUSE_ADDR, &en_cfg);
}
static void i2s_dma_master_enable(rt_uint32_t enable)
{
sddev_control(I2S_DEV_NAME, I2S_CMD_DMA_MASTER_ENABLE, (void *)&enable);
}
static void i2s_enable(rt_uint32_t enable)
{
if (enable)
{
sddev_control(I2S_DEV_NAME, I2S_CMD_UNIT_ENABLE, NULL);
}
else
{
sddev_control(I2S_DEV_NAME, I2S_CMD_DISABLE_I2S, NULL);
}
}
static void i2s_dma_tx_enable(rt_uint32_t enable)
{
struct rt_i2s_bus_device *i2s = &g_i2s_bus;
GDMA_CFG_ST en_cfg;
i2s_trans_dbg("%s:%d tx_enabled=%d,enable=%d\r\n", __FUNCTION__, __LINE__, i2s->tx_enabled, enable);
if ((i2s->tx_enabled && enable) || (!i2s->tx_enabled && !enable))
{
i2s_trans_dbg("%s:%d already enable tx dma\r\n", __FUNCTION__, __LINE__);
return;
}
en_cfg.channel = I2S_TX_DMA_CHANNEL;
if (enable)
en_cfg.param = 1;
else
en_cfg.param = 0;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DMA_ENABLE, &en_cfg);
i2s->tx_enabled = enable ? 1 : 0;
}
static void i2s_dma_rx_enable(rt_uint32_t enable)
{
struct rt_i2s_bus_device *i2s = &g_i2s_bus;
GDMA_CFG_ST en_cfg;
i2s_trans_dbg("%s:%d rx_enabled=%d,enable=%d\r\n", __FUNCTION__, __LINE__, i2s->rx_enabled, enable);
if ((i2s->rx_enabled && enable) || (!i2s->rx_enabled && !enable))
{
i2s_trans_dbg("%s:%d already enable rx dma\r\n", __FUNCTION__, __LINE__);
return;
}
en_cfg.channel = I2S_RX_DMA_CHANNEL;
if (enable)
en_cfg.param = 1;
else
en_cfg.param = 0;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DMA_ENABLE, &en_cfg);
i2s->rx_enabled = enable ? 1 : 0;
}
void i2s_dma_tx_half_handler(UINT32 flag)
{
int result;
struct rt_i2s_bus_device *i2s = &g_i2s_bus;
rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__);
//rt_kprintf("%s:%d PCM_CTRL=0x%x,PCM_CN=0x%x,PCM_STAT=0x%x\r\n", __FUNCTION__, __LINE__, REG_READ(PCM_CTRL), REG_READ(PCM_CN), REG_READ(PCM_STAT));
result = rt_data_node_is_empty(i2s->tx_list);
if (result)
{
#ifdef PAUSE_EN
i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo + (I2S_TX_BUFFER_SIZE -4));
i2s->tx_paused = 1;
//i2s_dma_master_enable(!i2s->tx_paused);
i2s->tx_fill_pos = (UINT32)i2s->tx_fifo;
i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2;
#endif
memset(i2s->tx_fifo, 0, I2S_TX_BUFFER_SIZE / 2);
}
else
{
memset(i2s->tx_fifo, 0, I2S_TX_BUFFER_SIZE / 2);
result = rt_data_node_read(i2s->tx_list, i2s->tx_fifo, I2S_TX_BUFFER_SIZE / 2);
#ifdef PAUSE_EN
if (result < (I2S_TX_BUFFER_SIZE / 2))
{
i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo + (I2S_TX_BUFFER_SIZE -4));
i2s->tx_paused = 1;
//i2s_dma_master_enable(!i2s->tx_paused);
i2s->tx_fill_pos = (UINT32)i2s->tx_fifo + result;
i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2 - result;
}
#endif
}
}
void i2s_dma_tx_finish_handler(UINT32 flag)
{
int result;
struct rt_i2s_bus_device *i2s = &g_i2s_bus;
rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__);
//rt_kprintf("%s:%d PCM_CTRL=0x%x,PCM_CN=0x%x,PCM_STAT=0x%x\r\n", __FUNCTION__, __LINE__, REG_READ(PCM_CTRL), REG_READ(PCM_CN), REG_READ(PCM_STAT));
i2s->tx_dma_irq_cnt ++;
result = rt_data_node_is_empty(i2s->tx_list);
if (result)
{
#ifdef PAUSE_EN
i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2 -4));
i2s->tx_paused = 1;
//i2s_dma_master_enable(!i2s->tx_paused);
i2s->tx_fill_pos = (UINT32)i2s->tx_fifo + I2S_TX_BUFFER_SIZE / 2;
i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2;
#endif
//rt_kprintf("* ");
memset(i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2), 0, I2S_TX_BUFFER_SIZE / 2);
}
else
{
memset(i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2), 0, I2S_TX_BUFFER_SIZE / 2);
result = rt_data_node_read(i2s->tx_list, i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2), I2S_TX_BUFFER_SIZE / 2);
#ifdef PAUSE_EN
if (result < (I2S_TX_BUFFER_SIZE / 2))
{
i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2 -4));
i2s->tx_paused = 1;
//i2s_dma_master_enable(!i2s->tx_paused);
i2s->tx_fill_pos = (UINT32)i2s->tx_fifo + I2S_TX_BUFFER_SIZE / 2 + result;
i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2 - result;
}
#endif
}
}
int i2s_dma_tx_init(struct rt_i2s_bus_device *i2s)
{
GDMACFG_TPYES_ST init_cfg;
GDMA_CFG_ST en_cfg;
memset(&init_cfg, 0, sizeof(GDMACFG_TPYES_ST));
memset(&en_cfg, 0, sizeof(GDMA_CFG_ST));
init_cfg.dstdat_width = i2s->bits_length;
init_cfg.srcdat_width = 32;
init_cfg.dstptr_incr = 0;
init_cfg.srcptr_incr = 1;
init_cfg.src_start_addr = i2s->tx_fifo;
init_cfg.dst_start_addr = (void *)PCM_DAT0;
init_cfg.channel = I2S_TX_DMA_CHANNEL;
init_cfg.prio = 0;
init_cfg.u.type4.src_loop_start_addr = i2s->tx_fifo;
init_cfg.u.type4.src_loop_end_addr = i2s->tx_fifo + I2S_TX_BUFFER_SIZE;
init_cfg.half_fin_handler = i2s_dma_tx_half_handler;
init_cfg.fin_handler = i2s_dma_tx_finish_handler;
init_cfg.src_module = GDMA_X_SRC_DTCM_RD_REQ;
init_cfg.dst_module = GDMA_X_DST_I2S_TX_REQ;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_TYPE4, (void *)&init_cfg);
en_cfg.channel = I2S_TX_DMA_CHANNEL;
en_cfg.param = I2S_TX_BUFFER_SIZE; // dma translen
sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_TRANS_LENGTH, (void *)&en_cfg);
return 0;
}
#if defined(I2S_RX_CALLBACK)
void i2s_dma_rx_half_handler(UINT32 flag)
{
int result;
struct rt_i2s_bus_device *i2s = &g_i2s_bus;
rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__);
//rt_kprintf("%s:%d PCM_CTRL=0x%x,PCM_CN=0x%x,PCM_STAT=0x%x\r\n", __FUNCTION__, __LINE__, REG_READ(PCM_CTRL), REG_READ(PCM_CN), REG_READ(PCM_STAT));
#ifdef PAUSE_EN
//i2s_dma_rx_pause_addr_set((UINT32)i2s->rx_fifo + (I2S_RX_BUFFER_SIZE -4));
#endif
int index;
int *ptr = (int *)i2s->rx_fifo;
for (index = 0; index < I2S_RX_BUFFER_SIZE / 8; index++, ptr++)
{
if (*ptr != 0)
{
rt_kprintf("rx[%d]=0x%x\r\n", index, *ptr);
}
}
}
void i2s_dma_rx_finish_handler(UINT32 flag)
{
int result;
struct rt_i2s_bus_device *i2s = &g_i2s_bus;
rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__);
//rt_kprintf("%s:%d PCM_CTRL=0x%x,PCM_CN=0x%x,PCM_STAT=0x%x\r\n", __FUNCTION__, __LINE__, REG_READ(PCM_CTRL), REG_READ(PCM_CN), REG_READ(PCM_STAT));
#ifdef PAUSE_EN
//i2s_dma_rx_pause_addr_set((UINT32)i2s->rx_fifo + (I2S_RX_BUFFER_SIZE / 2 -4));
#endif
int index;
int *ptr = (int *)i2s->rx_fifo + I2S_RX_BUFFER_SIZE / 8;
for (index = I2S_RX_BUFFER_SIZE / 8; index < I2S_RX_BUFFER_SIZE / 4; index++, ptr++)
{
if (*ptr != 0)
{
rt_kprintf("rx[%d]=0x%x\r\n", index, *ptr);
}
}
}
#endif
int i2s_dma_rx_init(struct rt_i2s_bus_device *i2s)
{
GDMACFG_TPYES_ST init_cfg;
GDMA_CFG_ST en_cfg;
memset(&init_cfg, 0, sizeof(GDMACFG_TPYES_ST));
memset(&en_cfg, 0, sizeof(GDMA_CFG_ST));
init_cfg.dstdat_width = 32;
init_cfg.srcdat_width = i2s->bits_length;
init_cfg.dstptr_incr = 1;
init_cfg.srcptr_incr = 0;
init_cfg.src_start_addr = (void *)PCM_DAT0;
init_cfg.dst_start_addr = i2s->rx_fifo;
init_cfg.channel = I2S_RX_DMA_CHANNEL;
init_cfg.prio = 0;
init_cfg.u.type5.dst_loop_start_addr = i2s->rx_fifo;
init_cfg.u.type5.dst_loop_end_addr = i2s->rx_fifo + I2S_RX_BUFFER_SIZE;
#if defined(I2S_RX_CALLBACK)
init_cfg.half_fin_handler = i2s_dma_rx_half_handler;
init_cfg.fin_handler = i2s_dma_rx_finish_handler;
#endif
init_cfg.src_module = GDMA_X_SRC_I2S_RX_REQ;
init_cfg.dst_module = GDMA_X_DST_DTCM_WR_REQ;
sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_TYPE5, (void *)&init_cfg);
en_cfg.channel = I2S_RX_DMA_CHANNEL;
en_cfg.param = I2S_RX_BUFFER_SIZE; // dma translen
sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_TRANS_LENGTH, (void *)&en_cfg);
#if !defined(I2S_RX_CALLBACK)
rb_init_dma_write(&i2s->rb_dma_wr, (UINT8*)i2s->rx_fifo, I2S_RX_BUFFER_SIZE, I2S_RX_DMA_CHANNEL);
#endif
return 0;
}
static rt_err_t rt_i2s_init(rt_device_t dev)
{
rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__);
i2s_init(0);
return RT_EOK;
}
static rt_err_t rt_i2s_open(rt_device_t dev, rt_uint16_t oflag)
{
struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev;
/* open audio , set fifo level set sample rate/datawidth */
if (!oflag)
{
return -RT_EINVAL;
}
if (!i2s->open_flag)
{
i2s->open_flag = oflag;
i2s->tx_dma_irq_cnt = 0;
#if 1
i2s->tx_paused = 1;
i2s->tx_fill_pos = (UINT32)i2s->tx_fifo;
i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2;
#endif
i2s->sample_rate = I2S_SAMPLE_RATE;
i2s->bits_length = I2S_BIT_LENGTH;
//sddev_control(I2S_DEV_NAME, I2S_CMD_DMA_ISR, (void *)i2s_dma_mode_isr);
/* rate=8/16/44.4/48 * 1000 bitlength=8/16/24/32 */
i2s_configure(FIFO_LEVEL_32, i2s->sample_rate, i2s->bits_length, I2S_DEFAULT_MODE);
if (oflag & RT_DEVICE_OFLAG_RDONLY)
{
rt_kprintf("%s:%d read with DMA\r\n", __FUNCTION__, __LINE__);
i2s_dma_rx_init(i2s);
i2s_dma_rx_pause_addr_set(0);
}
if (oflag & RT_DEVICE_OFLAG_WRONLY)
{
rt_kprintf("%s:%d write with DMA\r\n", __FUNCTION__, __LINE__);
i2s_dma_tx_init(i2s);
i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo);
}
i2s_trans_dbg("[i2s]:open device\r\n");
}
return RT_EOK;
}
static rt_err_t rt_i2s_close(rt_device_t dev)
{
struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev;
if (i2s->open_flag)
{
// wait_node_free(i2s->tx_list);
rt_data_node_empty(i2s->tx_list);
i2s_dma_rx_enable(0);
i2s_dma_tx_enable(0);
//i2s_dma_enable(0);
i2s->open_flag = 0;
i2s->tx_paused = 0;
i2s_enable(0);
}
i2s_trans_dbg("[i2s]:close device\r\n");
return RT_EOK;
}
static rt_size_t rt_i2s_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev;
int fill_size;
if (!(i2s->open_flag & RT_DEVICE_OFLAG_RDONLY))
{
return 0;
}
#if !defined(I2S_RX_CALLBACK)
#if CFG_GENERAL_DMA
fill_size = rb_get_fill_size_dma_write(&i2s->rb_dma_wr);
if(fill_size > size)
fill_size = size;
rb_read_dma_write(&i2s->rb_dma_wr, (UINT8 *)buffer + pos, fill_size, 1);
#endif
#endif
return fill_size;
}
static rt_size_t rt_i2s_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size )
{
int ret;
struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev;
rt_uint32_t result;
if (!(i2s->open_flag & RT_DEVICE_OFLAG_WRONLY))
{
return 0;
}
rt_kprintf("%s:%d size=%d\r\n", __FUNCTION__, __LINE__, size);
ret = rt_data_node_write(i2s->tx_list, (void *)((UINT8 *)buffer + pos), size);
#ifdef PAUSE_EN
if (i2s->tx_paused)
{
result = rt_data_node_read(i2s->tx_list, (void*)i2s->tx_fill_pos, i2s->tx_fill_size);
rt_kprintf("%s:%d result=%d,fill_size=%d\r\n", __FUNCTION__, __LINE__, result, i2s->tx_fill_size);
if (result == i2s->tx_fill_size)
{
i2s->tx_paused = 0;
//i2s_dma_master_enable(1);
i2s_dma_tx_pause_addr_set(0);
}
else
{
i2s->tx_fill_pos += result;
i2s->tx_fill_size -= result;
}
}
#endif
return ret;
}
static rt_err_t rt_i2s_cotrol(rt_device_t dev, int cmd, void *args)
{
struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev;
switch (cmd)
{
case RT_DEVICE_CTRL_I2S_DMA_RX_ENABLE:
i2s_dma_rx_enable(*(rt_int32_t *)args);
break;
case RT_DEVICE_CTRL_I2S_DMA_TX_ENABLE:
i2s_dma_tx_enable(*(rt_int32_t *)args);
break;
case RT_DEVICE_CTRL_I2S_DMA_MASTER_ENABLE:
i2s_dma_master_enable(*(rt_int32_t *)args);
break;
case RT_DEVICE_CTRL_I2S_SAMPLE_RATE_SET:
if (i2s->sample_rate != *(rt_int32_t *)args)
{
i2s->sample_rate = *(rt_int32_t *)args;
i2s_configure(FIFO_LEVEL_32, i2s->sample_rate, i2s->bits_length, I2S_DEFAULT_MODE);
}
break;
case RT_DEVICE_CTRL_I2S_BIT_LENGTH_SET:
if (i2s->bits_length != *(rt_int32_t *)args)
{
i2s->bits_length = *(rt_int32_t *)args;
i2s_configure(FIFO_LEVEL_32, i2s->sample_rate, i2s->bits_length, I2S_DEFAULT_MODE);
if (i2s->open_flag & RT_DEVICE_OFLAG_RDONLY)
{
i2s_dma_rx_init(i2s);
i2s_dma_rx_pause_addr_set(0);
}
if (i2s->open_flag & RT_DEVICE_OFLAG_WRONLY)
{
i2s_dma_tx_init(i2s);
i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo);
}
}
break;
}
return RT_ERROR;
}
#ifdef RT_USING_DEVICE_OPS
static const struct rt_device_ops i2s_ops =
{
rt_i2s_init,
rt_i2s_open,
rt_i2s_close,
rt_i2s_read,
rt_i2s_write,
rt_i2s_cotrol
};
#endif /* RT_USING_DEVICE_OPS */
int rt_i2s_hw_init(void)
{
struct rt_i2s_bus_device *i2s = &g_i2s_bus;
struct rt_device *device = &i2s->parent;
/* set device type */
device->type = RT_Device_Class_I2SBUS;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
device->user_data = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
device->ops = &i2s_ops;
#else
device->control = rt_i2s_cotrol;
device->init = rt_i2s_init;
device->open = rt_i2s_open;
device->close = rt_i2s_close;
device->read = rt_i2s_read;
device->write = rt_i2s_write;
#endif /* RT_USING_DEVICE_OPS */
i2s->tx_fifo = (char *)sdram_malloc(I2S_TX_BUFFER_SIZE);
if (i2s->tx_fifo == RT_NULL)
{
rt_kprintf("%s:%d malloc tx_fifo failed\r\n", __FUNCTION__, __LINE__);
return -RT_ENOMEM;
}
memset(i2s->tx_fifo, 0, I2S_TX_BUFFER_SIZE);
#if 1
i2s->rx_fifo = (char *)sdram_malloc(I2S_RX_BUFFER_SIZE);
if (i2s->rx_fifo == RT_NULL)
{
rt_kprintf("%s:%d malloc rx_fifo failed\r\n", __FUNCTION__, __LINE__);
free(i2s->tx_fifo);
return -RT_ENOMEM;
}
memset(i2s->rx_fifo, 0, I2S_RX_BUFFER_SIZE);
#endif
rt_data_node_init(&i2s->tx_list, I2S_TX_NODE_COUNT);
i2s->tx_list->read_complete = i2s_tx_node_read_complete;
i2s->tx_list->user_data = i2s;
/* register to device manager */
rt_device_register(device, I2S_DEV_NAME, RT_DEVICE_FLAG_RDWR);
rt_kprintf("---i2s register over---\r\n");
return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_i2s_hw_init);
#endif