123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- /*
- * Copyright (c) 2018 Google LLC.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include <device.h>
- #include <soc.h>
- #include <drivers/dma.h>
- #include <board_cfg.h>
- #include <logging/log.h>
- LOG_MODULE_REGISTER(dma_acts, CONFIG_DMA_LOG_LEVEL);
- #define DMA_INVALID_CHAN (0xff)
- #define DMA_ID_MEM 0
- #define MAX_DMA_CH CONFIG_DMA_0_PCHAN_NUM
- #define DMA_CHAN(base, ch) ((struct acts_dma_chan_reg*)((base) + (ch+1) * 0x100))
- /* Maximum data sent in single transfer (Bytes) */
- #define DMA_ACTS_MAX_DATA_ITEMS 0x7ffff
- /*dma ctl register*/
- #define DMA_CTL_SRC_TYPE_SHIFT 0
- #define DMA_CTL_SRC_TYPE(x) ((x) << DMA_CTL_SRC_TYPE_SHIFT)
- #define DMA_CTL_SRC_TYPE_MASK DMA_CTL_SRC_TYPE(0x3f)
- #define DMA_CTL_SAM_CONSTANT (0x1 << 7)
- #define DMA_CTL_DST_TYPE_SHIFT 8
- #define DMA_CTL_DST_TYPE(x) ((x) << DMA_CTL_DST_TYPE_SHIFT)
- #define DMA_CTL_DST_TYPE_MASK DMA_CTL_DST_TYPE(0x3f)
- #define DMA_CTL_DAM_CONSTANT (0x1 << 15)
- #define DMA_CTL_ADUDIO_TYPE_SHIFT 16
- #define DMA_CTL_ADUDIO_TYPE(x) ((x) << DMA_CTL_ADUDIO_TYPE_SHIFT)
- #define DMA_CTL_ADUDIO_TYPE_MASK DMA_CTL_ADUDIO_TYPE(0x1)
- #define DMA_CTL_ADUDIO_TYPE_INTER DMA_CTL_ADUDIO_TYPE(0)
- #define DMA_CTL_ADUDIO_TYPE_SEP DMA_CTL_ADUDIO_TYPE(1)
- #define DMA_CTL_TRM_SHIFT 17
- #define DMA_CTL_TRM(x) ((x) << DMA_CTL_TRM_SHIFT)
- #define DMA_CTL_TRM_MASK DMA_CTL_TRM(0x1)
- #define DMA_CTL_TRM_BURST8 DMA_CTL_TRM(0)
- #define DMA_CTL_TRM_SINGLE DMA_CTL_TRM(1)
- #define DMA_CTL_RELOAD (0x1 << 18)
- #define DMA_CTL_TWS_SHIFT 20
- #define DMA_CTL_TWS(x) ((x) << DMA_CTL_TWS_SHIFT)
- #define DMA_CTL_TWS_MASK DMA_CTL_TWS(0x3)
- #define DMA_CTL_TWS_8BIT DMA_CTL_TWS(2)
- #define DMA_CTL_TWS_16BIT DMA_CTL_TWS(1)
- #define DMA_CTL_TWS_32BIT DMA_CTL_TWS(0)
- /*dma pending register*/
- #define DMA_PD_TCIP(ch) (1 << ch)
- #define DMA_PD_HFIP(ch) (1 << (ch+16))
- /*dma irq enable register*/
- #define DMA_IE_TCIP(ch) (1 << ch)
- #define DMA_IE_HFIP(ch) (1 << (ch+16))
- #define DMA_START_START (0x1 << 0)
- /* dma channel registers */
- struct acts_dma_chan_reg {
- volatile uint32_t ctl;
- volatile uint32_t start;
- volatile uint32_t saddr0;
- volatile uint32_t saddr1;
- volatile uint32_t daddr0;
- volatile uint32_t daddr1;
- volatile uint32_t bc;
- volatile uint32_t rc;
- };
- struct acts_dma_reg {
- volatile uint32_t dma_ip;
- volatile uint32_t dma_ie;
- };
- struct dma_acts_channel {
- dma_callback_t cb;
- void *cb_arg;
- uint16_t reload_count;
- uint16_t complete_callback_en : 1;
- uint16_t hcom_callback_en : 1;
- uint16_t channel_direction : 3;
- uint16_t busy : 1;
- uint16_t reserved : 10;
- };
- struct dma_acts_data {
- uint32_t base;
- int chan_num;
- struct dma_acts_channel channels[MAX_DMA_CH];
- };
- #define DEV_DATA(dev) \
- ((struct dma_acts_data *const)(dev)->data)
- static struct dma_acts_data dmac_data;
- DEVICE_DECLARE(dma_acts_0);
- #if defined(CONFIG_DMA_DBG_DUMP)
- static void dma_acts_dump_reg(struct dma_acts_data *ddev, uint32_t id)
- {
- struct acts_dma_chan_reg *cregs = DMA_CHAN(ddev->base, id);
- LOG_INF("Using channel: %d", id);
- LOG_INF(" DMA_CTL: 0x%x", cregs->ctl);
- LOG_INF(" DMA_SADDR0: 0x%x", cregs->saddr0);
- LOG_INF(" DMA_SADDR1: 0x%x", cregs->saddr1);
- LOG_INF(" DMA_DADDR0: 0x%x", cregs->daddr0);
- LOG_INF(" DMA_DADDR1: 0x%x", cregs->daddr1);
- LOG_INF(" DMA_LEN: 0x%x", cregs->bc);
- LOG_INF(" DMA_RMAIN_LEN: 0x%x", cregs->rc);
- }
- void dma_dump_info(void)
- {
- int i;
- struct dma_acts_channel *pchan;
- struct dma_acts_data *ddev = &dmac_data;
- LOG_INF("----pchan= %d stauts:--------\n", ddev->chan_num);
- for(i= 0; i < ddev->chan_num; i++){
- pchan = &ddev->channels[i];
- printk("chan%d: isbusy=%d\n", i, pchan->busy);
- dma_acts_dump_reg(ddev, i);
- }
- }
- #endif
- /* Handles DMA interrupts and dispatches to the individual channel */
- static void dma_acts_isr(void *arg)
- {
- uint32_t id = (uint32_t) arg;
- const struct device *dev = DEVICE_GET(dma_acts_0);
- struct dma_acts_data *ddev = &dmac_data;
- struct acts_dma_chan_reg *cregs = DMA_CHAN(ddev->base, id);
- struct acts_dma_reg *gregs = (struct acts_dma_reg *)ddev->base;
- struct dma_acts_channel *chan = &ddev->channels[id];
- uint32_t hf_pending, tc_pending;
- if (id >= ddev->chan_num)
- return;
- hf_pending = DMA_PD_HFIP(id) &
- gregs->dma_ip & gregs->dma_ie;
- tc_pending = DMA_PD_TCIP(id) &
- gregs->dma_ip & gregs->dma_ie;
- /* clear pending */
- gregs->dma_ip = tc_pending | hf_pending;
- if((tc_pending|hf_pending) == 0)
- return;
- /* process full complete callback */
- if ( chan->complete_callback_en && chan->cb) {
- chan->cb(dev, chan->cb_arg, id, !!hf_pending);
- }
- if(cregs->ctl & DMA_CTL_RELOAD)
- chan->reload_count++;
- }
- /* Configure a channel */
- static int dma_acts_config(const struct device *dev, uint32_t channel,
- struct dma_config *config)
- {
- struct dma_acts_data *ddev = DEV_DATA(dev);
- struct dma_acts_channel *chan = &ddev->channels[channel];
- struct acts_dma_chan_reg *cregs = DMA_CHAN(ddev->base, channel);
- struct dma_block_config *head_block = config->head_block;
- uint32_t ctl;
- int data_width = 0;
- if (channel >= ddev->chan_num) {
- LOG_ERR("DMA error:ch=%d > dma max chan=%d\n",channel,
- ddev->chan_num);
- return -EINVAL;
- }
- if (head_block->block_size > DMA_ACTS_MAX_DATA_ITEMS) {
- LOG_ERR("DMA error: Data size too big: %d",
- head_block->block_size);
- return -EINVAL;
- }
- if (config->complete_callback_en || config->error_callback_en) {
- chan->cb = config->dma_callback;
- chan->cb_arg = config->user_data;
- chan->complete_callback_en = config->complete_callback_en;
- } else {
- chan->cb = NULL;
- chan->complete_callback_en = 0;
- }
- chan->hcom_callback_en = 0;
- cregs->saddr0 = (uint32_t)head_block->source_address;
- cregs->daddr0 = (uint32_t)head_block->dest_address;
- cregs->bc = (uint32_t)head_block->block_size;
- chan->channel_direction = config->channel_direction;
- chan->reload_count = 0;
- if (config->channel_direction == MEMORY_TO_PERIPHERAL) {
- ctl = DMA_CTL_SRC_TYPE(DMA_ID_MEM) |
- DMA_CTL_DST_TYPE(config->dma_slot) |
- DMA_CTL_DAM_CONSTANT;
- } else if (config->channel_direction == PERIPHERAL_TO_MEMORY) {
- ctl = DMA_CTL_SRC_TYPE(config->dma_slot) |
- DMA_CTL_SAM_CONSTANT |
- DMA_CTL_DST_TYPE(DMA_ID_MEM);
- } else {
- ctl = DMA_CTL_SRC_TYPE(DMA_ID_MEM) |
- DMA_CTL_DST_TYPE(DMA_ID_MEM);
- }
- /** extern for actions dma interleaved mode */
- if (config->reserved == 1 && config->channel_direction == MEMORY_TO_PERIPHERAL) {
- ctl |= DMA_CTL_ADUDIO_TYPE_SEP;
- }else if(config->reserved == 1 && config->channel_direction == PERIPHERAL_TO_MEMORY) {
- ctl |= DMA_CTL_ADUDIO_TYPE_SEP;
- }
- if (config->source_burst_length == 1 || config->dest_burst_length == 1) {
- ctl |= DMA_CTL_TRM_SINGLE;
- }
- if (config->source_data_size) {
- data_width = config->source_data_size;
- }
- if (config->dest_data_size) {
- data_width = config->dest_data_size;
- }
- if (head_block->source_reload_en || head_block->dest_reload_en) {
- ctl |= DMA_CTL_RELOAD;
- chan->hcom_callback_en = 1;
- }
- switch (data_width) {
- case 2:
- ctl |= DMA_CTL_TWS_16BIT;
- break;
- case 4:
- ctl |= DMA_CTL_TWS_32BIT;
- break;
- case 1:
- default:
- ctl |= DMA_CTL_TWS_8BIT;
- break;
- }
- cregs->ctl = ctl;
- return 0;
- }
- static int dma_acts_start(const struct device *dev, uint32_t channel)
- {
- struct dma_acts_data *ddev = DEV_DATA(dev);
- struct dma_acts_channel *chan = &ddev->channels[channel];
- struct acts_dma_chan_reg *cregs = DMA_CHAN(ddev->base, channel);
- struct acts_dma_reg *gregs = (struct acts_dma_reg *)ddev->base;
- uint32_t key;
- if (channel >= ddev->chan_num) {
- return -EINVAL;
- }
- key = irq_lock();
- /* clear old irq pending */
- gregs->dma_ip = DMA_PD_TCIP(channel) | DMA_PD_HFIP(channel);
- gregs->dma_ie &= ~( DMA_IE_TCIP(channel) | DMA_IE_HFIP(channel));
- /* enable dma channel full complete irq? */
- if (chan->complete_callback_en) {
- gregs->dma_ie |= DMA_IE_TCIP(channel) ;
- /*DMA_CTL_RELOAD use half complete irq*/
- if(chan->hcom_callback_en)
- gregs->dma_ie |= DMA_IE_HFIP(channel) ;
- }
- /* set memory type such as interleaved or seperated for audio */
- if (cregs->ctl & DMA_CTL_ADUDIO_TYPE_SEP) {
- if ((cregs->ctl & DMA_CTL_DST_TYPE_MASK) == 0) {
- /* PERIPHERAL_TO_MEMORY */
- cregs->daddr1 = cregs->saddr0;
- } else {
- /* MEMORY_TO_PERIPHERAL */
- cregs->saddr1 = cregs->daddr0;
- }
- }
- /* start dma transfer */
- cregs->start |= DMA_START_START;
- irq_unlock(key);
- return 0;
- }
- static int dma_acts_stop(const struct device *dev, uint32_t channel)
- {
- struct dma_acts_data *ddev = DEV_DATA(dev);
- struct acts_dma_chan_reg *cregs = DMA_CHAN(ddev->base, channel);
- struct acts_dma_reg *gregs = (struct acts_dma_reg *)ddev->base;
- uint32_t key;
- if (channel >= ddev->chan_num) {
- return -EINVAL;
- }
- key = irq_lock();
- gregs->dma_ie &= ~( DMA_IE_TCIP(channel) | DMA_IE_HFIP(channel));
- /* clear old irq pending */
- gregs->dma_ip = DMA_PD_TCIP(channel) | DMA_PD_HFIP(channel);
- /* disable reload brefore stop dma */
- cregs->ctl &= ~DMA_CTL_RELOAD;
- cregs->start &= ~DMA_START_START;
- irq_unlock(key);
- return 0;
- }
- static int dma_acts_reload(const struct device *dev, uint32_t channel,
- uint32_t src, uint32_t dst, size_t size)
- {
- struct dma_acts_data *ddev = DEV_DATA(dev);
- struct acts_dma_chan_reg *cregs = DMA_CHAN(ddev->base, channel);
- uint32_t key;
- if (channel >= ddev->chan_num) {
- return -EINVAL;
- }
- key = irq_lock();
- cregs->saddr0 = src;
- cregs->daddr0 = dst;
- cregs->bc = size;
- irq_unlock(key);
- return 0;
- }
- static int dma_acts_get_status(const struct device *dev, uint32_t channel,
- struct dma_status *stat)
- {
- struct dma_acts_data *ddev = DEV_DATA(dev);
- struct acts_dma_chan_reg *cregs = DMA_CHAN(ddev->base, channel);
- struct dma_acts_channel *chan = &ddev->channels[channel];
- if (channel >= ddev->chan_num || stat == NULL) {
- return -EINVAL;
- }
- if (cregs->start) {
- stat->busy = true;
- stat->pending_length = cregs->rc;
- } else {
- stat->busy = false;
- stat->pending_length = 0;
- }
- stat->dir = chan->channel_direction;
- return 0;
- }
- static int dma_acts_request(const struct device *dev, uint32_t channel)
- {
- struct dma_acts_data *ddev = DEV_DATA(dev);
- int i;
- uint32_t key;
- int ret = -EINVAL;
- //printk("-------requset:dma chan%d \n", channel);
- if (channel != DMA_INVALID_CHAN) {
- if(channel >= ddev->chan_num){
- printk("request chan=%d max err\n", channel);
- return -EINVAL;
- }
- key = irq_lock();
- if(ddev->channels[channel].busy){
- printk("request chan id%d already used\n", channel);
- ret = -EINVAL;
- }else{
- ret = channel;
- ddev->channels[channel].busy = 1;
- }
- irq_unlock(key);
- }else{
- key = irq_lock();
- for(i = ddev->chan_num-1; i >= 0; i--){
- if(!ddev->channels[i].busy)
- break;
- }
- if(i >= 0){
- ret = i;
- ddev->channels[i].busy = 1;
- }
- irq_unlock(key);
- }
- //printk("--- alloc dma chan%d \n", ret);
- return ret;
- }
- static void dma_acts_free(const struct device *dev, uint32_t channel)
- {
- struct dma_acts_data *ddev = DEV_DATA(dev);
- uint32_t key;
- key = irq_lock();
- if(!ddev->channels[channel].busy){
- printk("err:dma chan%d is free\n", channel);
- }else{
- ddev->channels[channel].busy = 0;
- }
- irq_unlock(key);
- }
- #define DMA_ACTS_IRQ_CONNECT(n) \
- do { \
- IRQ_CONNECT((IRQ_ID_DMA0+n), \
- CONFIG_DMA_IRQ_PRI, \
- dma_acts_isr, n, 0); \
- irq_enable((IRQ_ID_DMA0+n)); \
- } while (0)
- #define DMA_NOT_RESERVE(chan) ((CONFIG_DMA_LCD_RESEVER_CHAN!=chan) \
- && (CONFIG_DMA_SPINAND_RESEVER_CHAN!=chan) \
- && (CONFIG_DMA_SPINOR_RESEVER_CHAN!=chan))
- static int dma_acts_init(const struct device *dev)
- {
- struct dma_acts_data *data = DEV_DATA(dev);
- data->base = DMA_REG_BASE;
- acts_clock_peripheral_enable(CLOCK_ID_DMA);
- acts_reset_peripheral(RESET_ID_DMA);
- data->chan_num = MAX_DMA_CH;
- #if MAX_DMA_CH > 0
- #if DMA_NOT_RESERVE(0)
- DMA_ACTS_IRQ_CONNECT(0);
- #endif
- #endif
- #if MAX_DMA_CH > 1
- #if DMA_NOT_RESERVE(1)
- DMA_ACTS_IRQ_CONNECT(1);
- #endif
- #endif
- #if MAX_DMA_CH > 2
- #if DMA_NOT_RESERVE(2)
- DMA_ACTS_IRQ_CONNECT(2);
- #endif
- #endif
- #if MAX_DMA_CH > 3
- #if DMA_NOT_RESERVE(3)
- DMA_ACTS_IRQ_CONNECT(3);
- #endif
- #endif
- #if MAX_DMA_CH > 4
- #if DMA_NOT_RESERVE(4)
- DMA_ACTS_IRQ_CONNECT(4);
- #endif
- #endif
- #if MAX_DMA_CH > 5
- #if DMA_NOT_RESERVE(5)
- DMA_ACTS_IRQ_CONNECT(5);
- #endif
- #endif
- #if MAX_DMA_CH > 6
- #if DMA_NOT_RESERVE(6)
- DMA_ACTS_IRQ_CONNECT(6);
- #endif
- #endif
- #if MAX_DMA_CH > 7
- #if DMA_NOT_RESERVE(7)
- DMA_ACTS_IRQ_CONNECT(7);
- #endif
- #endif
- #if MAX_DMA_CH > 8
- #if DMA_NOT_RESERVE(8)
- DMA_ACTS_IRQ_CONNECT(8);
- #endif
- #endif
- #if MAX_DMA_CH > 9
- #if DMA_NOT_RESERVE(9)
- DMA_ACTS_IRQ_CONNECT(9);
- #endif
- #endif
- printk("dma-num=%d\n", data->chan_num);
- #if CONFIG_DMA_LCD_RESEVER_CHAN < MAX_DMA_CH
- data->channels[CONFIG_DMA_LCD_RESEVER_CHAN].busy = 1; //reserve for LCD
- #endif
- #if CONFIG_DMA_SPINAND_RESEVER_CHAN < MAX_DMA_CH
- data->channels[CONFIG_DMA_SPINAND_RESEVER_CHAN].busy = 1; //reserve for SPINAND
- #endif
- #if CONFIG_DMA_SPINOR_RESEVER_CHAN < MAX_DMA_CH
- data->channels[CONFIG_DMA_SPINOR_RESEVER_CHAN].busy = 1; // reserve for SPINOR
- #endif
- return 0;
- }
- static const struct dma_driver_api dma_acts_api = {
- .config = dma_acts_config,
- .start = dma_acts_start,
- .stop = dma_acts_stop,
- .reload = dma_acts_reload,
- .get_status = dma_acts_get_status,
- .request = dma_acts_request,
- .free = dma_acts_free,
- };
- DEVICE_DEFINE(dma_acts_0, CONFIG_DMA_0_NAME, &dma_acts_init, NULL,
- &dmac_data, NULL, POST_KERNEL,
- 1, &dma_acts_api);
|