| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- /*
- * Copyright : (C) 2022 Phytium Information Technology, Inc.
- * All Rights Reserved.
- *
- * This program is OPEN SOURCE software: you can redistribute it and/or modify it
- * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
- * either version 1.0 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the Phytium Public License for more details.
- *
- *
- * FilePath: fddma.c
- * Date: 2022-02-10 14:53:42
- * LastEditTime: 2022-02-18 08:24:47
- * Description: This files is for ddma interface implementation
- *
- * Modify History:
- * Ver Who Date Changes
- * ----- ------ -------- --------------------------------------
- * 1.0 Zhugengyu 2022/5/13 init commit
- */
- /***************************** Include Files *********************************/
- #include <string.h>
- #include "fkernel.h"
- #include "fparameters.h"
- #include "fassert.h"
- #include "fdebug.h"
- #include "fddma_hw.h"
- #include "fddma.h"
- /************************** Constant Definitions *****************************/
- /**************************** Type Definitions *******************************/
- /************************** Variable Definitions *****************************/
- /***************** Macros (Inline Functions) Definitions *********************/
- #define FDDMA_DEBUG_TAG "DDMA"
- #define FDDMA_ERROR(format, ...) FT_DEBUG_PRINT_E(FDDMA_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FDDMA_WARN(format, ...) FT_DEBUG_PRINT_W(FDDMA_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FDDMA_INFO(format, ...) FT_DEBUG_PRINT_I(FDDMA_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FDDMA_DEBUG(format, ...) FT_DEBUG_PRINT_D(FDDMA_DEBUG_TAG, format, ##__VA_ARGS__)
- /************************** Function Prototypes ******************************/
- static FError FDdmaReset(FDdma *const instance);
- /****************************************************************************/
- /**
- * @name: FDdmaCfgInitialization
- * @msg: 初始化DDMA控制器
- * @return {FError} FDDMA_SUCCESS表示初始化成功,其它返回值表示初始化失败
- * @param {FDdma} *instance, DDMA控制器实例
- * @param {FDdmaConfig} *input_config, DDMA控制器配置
- */
- FError FDdmaCfgInitialization(FDdma *const instance, const FDdmaConfig *input_config)
- {
- FASSERT(instance && input_config);
- uintptr base_addr = input_config->base_addr;
- FError ret = FDDMA_SUCCESS;
- if (FT_COMPONENT_IS_READY == instance->is_ready)
- {
- FDDMA_WARN("device is already initialized!!!");
- }
- FDdmaDeInitialization(instance);
- instance->config = *input_config;
- ret = FDdmaReset(instance);
- if (FDDMA_SUCCESS == ret)
- {
- instance->is_ready = FT_COMPONENT_IS_READY;
- FDDMA_INFO("ddma@0x%x init success !!!", base_addr);
- }
- return ret;
- }
- /**
- * @name: FDdmaStart
- * @msg: 启动DDMA控制器,开始传输
- * @return {FError} FDDMA_SUCCESS表示启动成功,其它返回值表示启动失败
- * @param {FDdma} *instance, DDMA控制器实例
- */
- FError FDdmaStart(FDdma *const instance)
- {
- FASSERT(instance);
- FError ret = FDDMA_SUCCESS;
- uintptr base_addr = instance->config.base_addr;
- if (FT_COMPONENT_IS_READY != instance->is_ready)
- {
- FDDMA_ERROR("dma instance not init !!!");
- return FDDMA_ERR_NOT_INIT;
- }
- FDdmaEnableGlobalIrq(base_addr); /* enable ddma irq */
- FDdmaEnable(base_addr);
- return FDDMA_SUCCESS;
- }
- /**
- * @name: FDdmaStop
- * @msg: 停止DDMA控制器
- * @return {FError} FDDMA_SUCCESS表示停止成功,其它返回值表示停止失败
- * @param {FDdma} *instance, DDMA控制器实例
- */
- FError FDdmaStop(FDdma *const instance)
- {
- FASSERT(instance);
- FError ret = FDDMA_SUCCESS;
- uintptr base_addr = instance->config.base_addr;
- if (FT_COMPONENT_IS_READY != instance->is_ready)
- {
- FDDMA_ERROR("dma instance not init !!!");
- return FDDMA_ERR_NOT_INIT;
- }
- FDdmaDisableGlobalIrq(base_addr); /* enable ddma irq */
- FDdmaDisable(base_addr);
- return FDDMA_SUCCESS;
- }
- /**
- * @name: FDdmaDeInitialization
- * @msg: 去初始化DDMA控制器
- * @return {无}
- * @param {FDdma} *instance, DDMA控制器实例
- */
- void FDdmaDeInitialization(FDdma *const instance)
- {
- FASSERT(instance);
- u32 chan;
- for (chan = 0; chan < FDDMA_NUM_OF_CHAN; chan++)
- {
- if (instance->bind_status & BIT(chan))
- {
- FDDMA_WARN("channel %d has not been unbind", chan);
- }
- }
- memset(instance, 0, sizeof(*instance));
- return;
- }
- /**
- * @name: FDdmaAllocateChan
- * @msg: 按照配置分配DDMA通道
- * @return {FError} FDDMA_SUCCESS表示分配成功,其它返回值表示分配失败
- * @param {FDdma} *instance, DDMA控制器实例
- * @param {FDdmaChan} *dma_chan, DDMA通道实例
- * @param {FDdmaChanConfig} *dma_chan_config, DDMA通道配置
- */
- FError FDdmaAllocateChan(FDdma *const instance, FDdmaChan *const dma_chan, const FDdmaChanConfig *dma_chan_config)
- {
- FASSERT(instance && dma_chan && dma_chan_config);
- FError ret = FDDMA_SUCCESS;
- const FDdmaChanIndex chan_idx = dma_chan_config->id;
- u32 reg_val;
- uintptr base_addr = instance->config.base_addr;
- if (FT_COMPONENT_IS_READY != instance->is_ready)
- {
- FDDMA_ERROR("dma instance not init !!!");
- return FDDMA_ERR_NOT_INIT;
- }
- if ((TRUE == dma_chan->is_used) || (BIT(chan_idx) & instance->bind_status))
- {
- FDDMA_ERROR("chan-%d is already is use !!!", chan_idx);
- return FDDMA_ERR_CHAN_BINDED;
- }
- if (FDdmaIsChanRunning(base_addr, chan_idx))
- {
- FDDMA_ERROR("chan-%d is already running !!!", chan_idx);
- return FDDMA_ERR_CHAN_BINDED;
- }
- if (dma_chan_config->ddr_addr % FDDMA_DDR_ADDR_ALIGMENT)
- {
- FDDMA_ERROR("ddr addr 0x%x must align with %d bytes",
- dma_chan_config->ddr_addr, FDDMA_DDR_ADDR_ALIGMENT);
- return FDDMA_ERR_INVALID_DDR_ADDR;
- }
- if ((FDDMA_MAX_TRANSFER_LEN < dma_chan_config->trans_len) ||
- (FDDMA_MIN_TRANSFER_LEN > dma_chan_config->trans_len) ||
- (0 != dma_chan_config->trans_len % FDDMA_MIN_TRANSFER_LEN))
- {
- FDDMA_ERROR("invalid transfer size %d Bytes !!!", dma_chan_config->trans_len);
- return FDDMA_ERR_INVALID_TRANS_SIZE;
- }
- dma_chan->dma = instance;
- instance->chan[chan_idx] = dma_chan;
- if (&(dma_chan->config) != dma_chan_config)
- dma_chan->config = *dma_chan_config;
- FDdmaStop(instance); /* disable irq */
- if (FDDMA_SUCCESS != FDdmaDisableChan(base_addr, chan_idx))
- {
- FDDMA_ERROR("disable DDMA@0x%x channel %d failed !!!", base_addr, chan_idx);
- return FDDMA_ERR_WAIT_TIMEOUT;
- }
- FDdmaResetChan(base_addr, chan_idx); /* reset channel */
- FDdmaSetChanSelection(base_addr, chan_idx, dma_chan->config.slave_id); /* select channel */
- FDdmaSetChanBind(base_addr, chan_idx, TRUE); /* bind channel */
- /* setup transfer src and dst */
- /* dma_tx_req: ddr --> dev 从内存中读取数据,写入外设 */
- /* dma_rx_req: dev --> ddr 从外设读取数据到内存 */
- #ifdef __aarch64___
- FDdmaWriteReg(base_addr, FDDMA_CHAN_DDR_LOW_ADDR_OFFSET(chan_idx), LOWER_32_BITS(dma_chan_config->ddr_addr));
- FDdmaWriteReg(base_addr, FDDMA_CHAN_DDR_UP_ADDR_OFFSET(chan_idx), UPPER_32_BITS(dma_chan_config->ddr_addr));
- #else
- FDdmaWriteReg(base_addr, FDDMA_CHAN_DDR_LOW_ADDR_OFFSET(chan_idx), (u32)(dma_chan_config->ddr_addr));
- FDdmaWriteReg(base_addr, FDDMA_CHAN_DDR_UP_ADDR_OFFSET(chan_idx), 0);
- #endif
- FDdmaWriteReg(base_addr, FDDMA_CHAN_DEV_ADDR_OFFSET(chan_idx), dma_chan_config->dev_addr);
- FDdmaWriteReg(base_addr, FDDMA_CHAN_TS_OFFSET(chan_idx), dma_chan_config->trans_len); /* block size */
- /* set channel request direction */
- FDdmaSetChanDirection(base_addr, chan_idx,
- (FDDMA_CHAN_REQ_RX == dma_chan->config.req_mode) ? TRUE : FALSE);
- FDDMA_INFO("chan-%d ddr @0x%x", chan_idx, FDDMA_CHAN_DDR_LOW_ADDR_OFFSET(chan_idx));
- FDDMA_INFO("ddr addr: 0x%x", FDdmaReadReg(base_addr, FDDMA_CHAN_DDR_LOW_ADDR_OFFSET(chan_idx)));
- FDDMA_INFO("dev addr: 0x%x", FDdmaReadReg(base_addr, FDDMA_CHAN_DEV_ADDR_OFFSET(chan_idx)));
- FDDMA_INFO("trans len: %d", FDdmaReadReg(base_addr, FDDMA_CHAN_TS_OFFSET(chan_idx)));
- FDdmaSetChanTimeout(base_addr, chan_idx, 0xffff);
- FDdmaEnableChanIrq(base_addr, chan_idx);
- if (FDDMA_SUCCESS == ret)
- {
- instance->bind_status |= BIT(chan_idx);
- dma_chan->is_used = TRUE;
- FDDMA_INFO("allocate channel %d", chan_idx);
- }
- return ret;
- }
- /**
- * @name: FDdmaDellocateChan
- * @msg: 释放之前分配的DDMA通道
- * @return {FError} FDDMA_SUCCESS表示释放成功,其它返回值表示释放失败
- * @param {FDdmaChan} *dma_chan, DDMA控制器实例
- */
- FError FDdmaDellocateChan(FDdmaChan *const dma_chan)
- {
- FASSERT(dma_chan && dma_chan->dma);
- FDdma *const instance = dma_chan->dma;
- const FDdmaChanIndex chan_idx = dma_chan->config.id;
- uintptr base_addr = instance->config.base_addr;
- FError ret = FDDMA_SUCCESS;
- if (FT_COMPONENT_IS_READY != instance->is_ready)
- {
- FDDMA_ERROR("dma instance not init !!!");
- return FDDMA_ERR_NOT_INIT;
- }
- if (FDDMA_SUCCESS != FDdmaDisableChan(base_addr, chan_idx))
- {
- FDDMA_ERROR("disable DDMA@0x%x channel %d failed !!!", base_addr, chan_idx);
- return FDDMA_ERR_WAIT_TIMEOUT;
- }
- FDdmaResetChan(base_addr, chan_idx);
- FDdmaSetChanBind(base_addr, chan_idx, FALSE); /* unbind channel */
- ret = FDdmaDisableChan(base_addr, chan_idx);
- if (FDDMA_SUCCESS != ret) /* disable channel */
- {
- FDDMA_ERROR("disable ddma@%p channel %d failed !!!", base_addr, chan_idx);
- return ret;
- }
- FDdmaDisableChanIrq(base_addr, chan_idx); /* disable channel irq */
- instance->bind_status &= ~BIT(chan_idx); /* set bind status */
- instance->chan[chan_idx] = NULL;
- FDDMA_INFO("deallocate channel %d", chan_idx);
- memset(dma_chan, 0, sizeof(*dma_chan));
- return ret;
- }
- /**
- * @name: FDdmaActiveChan
- * @msg: 使能指定的DDMA通道
- * @note: 调用FDdmaAllocateChan后无需调用此函数
- * @return {FError} 返回FDDMA_SUCCESS表示成功,返回其它表示失败
- * @param FDdmaChan *const dma_chan, DDMA通道实例
- */
- FError FDdmaActiveChan(FDdmaChan *const dma_chan)
- {
- FASSERT(dma_chan && dma_chan->dma);
- FDdma *const instance = dma_chan->dma;
- uintptr base_addr = instance->config.base_addr;
- if (FT_COMPONENT_IS_READY != instance->is_ready)
- {
- FDDMA_ERROR("dma instance not init !!!");
- return FDDMA_ERR_NOT_INIT;
- }
- FDdmaEnableChan(base_addr, dma_chan->config.id);
- FDdmaClearChanIrq(base_addr, dma_chan->config.id); /* clear interrupt status */
- return FDDMA_SUCCESS;
- }
- FError FDdmaDeactiveChan(FDdmaChan *const dma_chan)
- {
- FASSERT(dma_chan && dma_chan->dma);
- FDdma *const instance = dma_chan->dma;
- uintptr base_addr = instance->config.base_addr;
- if (FT_COMPONENT_IS_READY != instance->is_ready)
- {
- FDDMA_ERROR("dma instance not init !!!");
- return FDDMA_ERR_NOT_INIT;
- }
- return FDdmaDisableChan(base_addr, dma_chan->config.id);
- }
- /**
- * @name: FDdmaReset
- * @msg: 重置DDMA控制器
- * @return {FError} FDDMA_SUCCESS表示重置成功,其它返回值表示失败
- * @param {FDdma} *instance, DDMA控制器实例
- */
- static FError FDdmaReset(FDdma *const instance)
- {
- FASSERT(instance);
- uintptr base_addr = instance->config.base_addr;
- FError ret = FDDMA_SUCCESS;
- u32 reg_val;
- u32 chan;
- if (0 != instance->bind_status)
- {
- FDDMA_WARN("some channel not yet un-bind !!!");
- }
- FDdmaDisable(base_addr); /* disable ddma */
- FDdmaSoftwareReset(base_addr); /* do software reset */
- FDdmaDisableGlobalIrq(base_addr);
- /* disable channel and its irq */
- for (u32 chan = FDDMA_CHAN_0; chan < FDDMA_NUM_OF_CHAN; chan++)
- {
- /* disable channel */
- ret = FDdmaDisableChan(base_addr, chan);
- if (FDDMA_SUCCESS != ret)
- {
- FDDMA_ERROR("disable ddma@%p channel %d failed !!!", base_addr, chan);
- break;
- }
- }
- FDdmaDumpRegisters(base_addr);
- return ret;
- }
|