12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513 |
- /*****************************************************************************
- *
- * Copyright Andes Technology Corporation 2007-2008
- * All Rights Reserved.
- *
- * Revision History:
- *
- * Aug.21.2007 Created.
- ****************************************************************************/
- /*****************************************************************************
- *
- * FILE NAME VERSION
- *
- * dmad.c
- *
- * DESCRIPTION
- *
- * DMA controller driver internal supplement library.
- *
- * DATA STRUCTURES
- *
- * None
- *
- * DEPENDENCIES
- *
- * dmad.h
- *
- ****************************************************************************/
- #include "dmad.h"
- #include "cache.h"
- #include "bsp_hal.h"
- // #define DMAD_POLLING
- #define DMAD_AHB_MAX_CHANNELS DMAC_MAX_CHANNELS
- #define DMAD_APB_MAX_CHANNELS APBBR_DMA_MAX_CHANNELS
- #define DMAD_DRB_POOL_SIZE 128 /* 64 // 128*/
- //#define DMAD_HISR_PRIORITY 0 // 0: highest, 2: lowest
- #define DMAD_HISR_STACK_SIZE 4096 // Please align to 32-bit
- #ifdef CONFIG_PLAT_AG101P_4GB
- #define NTC0_BONDER_START 0x00000000
- #define NTC0_BONDER_END 0x40000000
- #else
- #define NTC0_BONDER_START 0x00000000
- #define NTC0_BONDER_END 0x00400000
- #endif
- /*
- * DMA module is shared between drivers and has no specific
- * initialization entry point. For this reason, it's stack
- * pool is declared in the global data or bss section.
- */
- static uint32_t dmad_hisr_stack[DMAD_HISR_STACK_SIZE];
- /* Driver data structure, one instance per system */
- typedef struct DMAD_DATA_STRUCT{
- /* Driver data initialization flag */
- uint32_t init; /* init flag for this object */
- uint32_t drq_pool_mutex_init; /* init flag for DMA queue pool access control object */
- uint32_t ahb_lisr_registered; /* init flag for AHB DMA LISR */
- uint32_t apb_lisr_registered; /* init flag for APB DMA LISR */
- uint32_t hisr_registered; /* init flag for HISR */
- /* DMA queue pool access control object */
- hal_mutex_t drq_pool_mutex; /* Mutex for access control of DRQ (DMA Request Queue) pool between tasks */
- /* DMA HISR resources */
- hal_bh_t hisr; /* HISR kernel object, used to perform deffered tasks of DMA LISR */
- uint32_t hisr_as; /* HISR activation state (for the single HISR to identify who activated it) */
- } DMAD_DATA;
- /* Driver data structure instance, one instance per system */
- static DMAD_DATA dmad;
- /* DMA request queue, one instance per channel */
- typedef struct DMAD_DRQ_STRUCT{
- uint32_t allocated; /* Flag to indicate the channel allocation status */
- DMAD_DATA *dmad; /* Pointer to driver object (DMAD_DATA) */
- uint32_t channel_base; /* DMA channel register base address */
- hal_mutex_t drb_pool_mutex; /* Mutex for access control of DRB (DMA Request Block) pool between tasks */
- DMAD_DRB drb_pool[DMAD_DRB_POOL_SIZE]; /* DRB (DMA Request Block) pool for this channel */
- hal_semaphore_t drb_sem;
- uint32_t fre_head; /* Free(un-allocated, completed) DRB linked list head */
- uint32_t fre_tail; /* Free(un-allocated, completed) DRB linked list tail */
- uint32_t rdy_head; /* Ready(allocated, un-submitted) DRB linked list head */
- uint32_t rdy_tail; /* Ready(allocated, un-submitted) DRB linked list tail */
- uint32_t sbt_head; /* Submitted DRB linked list head */
- uint32_t sbt_tail; /* Submitted DRB linked list tail */
- uint32_t cpl_head; /* Completed (those need to notify client) DRB linked list head */
- uint32_t cpl_tail; /* Completed (those need to notify client) DRB linked list tail */
- /*
- * cache writeback function
- *
- * source destination writeback invalidate function
- * ---------------------------------------------------------------------------------------------------
- * memory -> memory v (for src data) v (for dest readback) NDS_DCache_Invalidate_Flush()
- * device -> memory v (for invalidate) v (for dest readback) NDS_DCache_Invalidate_Flush()
- * memory -> device v (for src data) x NDS_DCache_Flush()
- * device -> device x x null
- */
- void (*dc_writeback)(unsigned long start, unsigned long end);
- void (*dc_invalidate)(unsigned long start, unsigned long end);
- } DMAD_DRQ;
- /* DMA queue for AHB DMA channels */
- static DMAD_DRQ ahb_drq_pool[DMAD_AHB_MAX_CHANNELS];
- /* DMA queue for APB DMA channels */
- static DMAD_DRQ apb_drq_pool[DMAD_APB_MAX_CHANNELS];
- /* AHB DMAC channel re-route table structure */
- typedef struct _DMAD_AHB_CH_ROUTE {
- // uint32_t dev_reqn; /* device req/gnt number */
- uint32_t route_cr; /* routing control register address */
- } DMAD_AHB_CH_ROUTE;
- /* AHB DMAC channel re-route table. Indexed by AHB DMAC req/ack number. */
- static DMAD_AHB_CH_ROUTE dmad_ahb_ch_route_table[] = {
- { 0 },
- { PMU_CFC_REQACK_CFG }, /* CFC REQ/ACK connection configuration register */
- { PMU_SSP1_REQACK_CFG }, /* SSP1 REQ/ACK connection configuration register */
- { PMU_UART1TX_REQACK_CFG }, /* UART1 TX REQ/ACK connection configuration register */
- { PMU_UART1RX_REQACK_CFG }, /* UART1 RX REQ/ACK connection configuration register */
- { PMU_UART2TX_REQACK_CFG }, /* UART2 TX REQ/ACK connection configuration register */
- { PMU_UART2RX_REQACK_CFG }, /* UART2 RX REQ/ACK connection configuration register */
- { PMU_SDC_REQACK_CFG }, /* SDC REQ/ACK connection configuration register */
- { PMU_I2SAC97_REQACK_CFG }, /* I2S/AC97 REQ/ACK connection configuration register */
- { 0 },
- { 0 },
- { PMU_USB_REQACK_CFG }, /* USB 2.0 REQ/ACK connection configuration register */
- { 0 },
- { 0 },
- { PMU_EXT0_REQACK_CFG }, /* External device0 REQ/ACK connection configuration register */
- { PMU_EXT1_REQACK_CFG }, /* External device1 REQ/ACK connection configuration register */
- };
- /* APB Bridge DMA request number re-route table */
- typedef struct _DMAD_APB_REQN_ROUTE{
- // uint32_t apb_reqn; /* APB device req/gnt number */
- uint32_t ahb_reqn; /* AHB DMAC req/ack number */
- uint32_t bus_sel; /* Address selection: APBBR_ADDRSEL_APB(0) or APBBR_ADDRSEL_AHB(1) */
- } DMAD_APB_REQN_ROUTE;
- /* APB Bridge DMA request number re-route table. Indexed by APB DMA req/gnt number. */
- static DMAD_APB_REQN_ROUTE dmad_apb_reqn_route_table[] = {
- { 0x00, APBBR_ADDRSEL_AHB }, /* APBBR_REQN_NONE */
- { 0x01, APBBR_ADDRSEL_APB }, /* APBBR_REQN_CFC */
- { 0x02, APBBR_ADDRSEL_APB }, /* APBBR_REQN_SSP */
- { 0x00, APBBR_ADDRSEL_AHB }, /* APB reserved */
- { 0x05, APBBR_ADDRSEL_APB }, /* APBBR_REQN_BTUART (AHB TX reqn: 5, AHB RX reqn: 6) */
- { 0x07, APBBR_ADDRSEL_APB }, /* APBBR_REQN_SDC */
- { 0x08, APBBR_ADDRSEL_APB }, /* APBBR_REQN_I2SAC97 */
- { 0x00, APBBR_ADDRSEL_AHB }, /* APB reserved */
- { 0x03, APBBR_ADDRSEL_APB }, /* APBBR_REQN_STUART (AHB TX reqn: 3, AHB RX reqn: 4) */
- { 0x00, APBBR_ADDRSEL_AHB }, /* APB reserved (comment out following fields to save code size) */
- { 0x00, APBBR_ADDRSEL_AHB }, /* APB reserved */
- { 0x00, APBBR_ADDRSEL_AHB }, /* APB reserved */
- { 0x00, APBBR_ADDRSEL_AHB }, /* APB reserved */
- { 0x00, APBBR_ADDRSEL_AHB }, /* APB reserved */
- { 0x00, APBBR_ADDRSEL_AHB }, /* APB reserved */
- { 0x00, APBBR_ADDRSEL_AHB }, /* APB reserved */
- };
- /* AHB DMA Request number */
- /* Used to record DMA request numbers in different platform */
- typedef struct _APB_DMA_REQN {
- uint32_t xc5_reqn;
- uint32_t xc7_reqn;
- } APB_DMA_REQN;
- static APB_DMA_REQN apb_dma_reqn_table[] = {
- {APBBR_REQN_NONE, APBBR_REQN_NONE},//APB_REQN_NONE
- /* REQN in XC5 */
- {XC5_APBBR_REQN_CFC, APBBR_REQN_RESERVED},//APB_REQN_CFC
- {XC5_APBBR_REQN_SSP, APBBR_REQN_RESERVED},//APB_REQN_SSP
- {XC5_APBBR_REQN_BTUART, APBBR_REQN_RESERVED},//APBBR_REQN_BTUART
- {XC5_APBBR_REQN_I2SAC97, XC7_APBBR_REQN_I2SAC97},//APB_REQN_I2SAC97
- {XC5_APBBR_REQN_STUART, APBBR_REQN_RESERVED},//APB_REQN_STUART
- {XC5_APBBR_REQN_I2S, APBBR_REQN_RESERVED},//APB_REQN_I2S
- {XC5_APBBR_REQN_SSP2, APBBR_REQN_RESERVED},//APB_REQN_SSP2
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_EXTREQ0},//APB_REQN_EXT0
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_EXTREQ1},//APB_REQN_EXT1
- /* REQN in XC7 */
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_SSP1TX},//APB_REQN_SSP1TX
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_SSP1RX},//APB_REQN_SSP1RX
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_UART2TX},//APB_REQN_UART2TX
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_UART2RX},//APB_REQN_UART2RX
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_UART4TX},//APB_REQN_UART4TX
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_UART4RX},//APB_REQN_UART4RX
- {XC5_APBBR_REQN_SDC, XC7_APBBR_REQN_SDC},//APB_REQN_SDC
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_SSP2TX},//APB_REQN_SSP2TX
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_SSP2RX},//APB_REQN_SSP2RX
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_USB_2_0},//APB_REQN_USB_2_0
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_USB_1_1_EP1},//APB_REQN_USB_1_1_EP1
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_USB_1_1_EP2},//APB_REQN_USB_1_1_EP2
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_USB_1_1_EP3},//APB_REQN_USB_1_1_EP3
- {APBBR_REQN_RESERVED, XC7_APBBR_REQN_USB_1_1_EP4},//AHB_REQN_USB_1_1_EP4
- {XC5_APBBR_REQN_MAX, XC7_APBBR_REQN_MAX},//APB_REQN_MAX
- };
- /* AHB DMA Request number */
- /* Used to record DMA request numbers in different platform */
- typedef struct _AHB_DMA_REQN {
- uint32_t xc5_reqn;
- uint32_t xc7_reqn;
- } AHB_DMA_REQN;
- static AHB_DMA_REQN ahb_dma_reqn_table[] = {
- {AHB_REQN_NONE, AHB_REQN_NONE},//AHB_REQN_NONE
- /* REQN in XC5 */
- {XC5_AHB_REQN_CFC, AHB_REQN_RESERVED},//AHB_REQN_CFC
- {XC5_AHB_REQN_SSP, AHB_REQN_RESERVED},//AHB_REQN_SSP
- {XC5_AHB_REQN_UART1TX, AHB_REQN_RESERVED},//AHB_REQN_UART1TX
- {XC5_AHB_REQN_UART1RX, AHB_REQN_RESERVED},//AHB_REQN_UART1RX
- {XC5_AHB_REQN_I2SAC97, XC7_AHB_REQN_I2SAC97},//AHB_REQN_I2SAC97
- {XC5_AHB_REQN_USB, AHB_REQN_RESERVED},//AHB_REQN_USB
- {XC5_AHB_REQN_EXT0, XC7_AHB_REQN_EXTREQ0},//AHB_REQN_EXT0
- {XC5_AHB_REQN_EXT1, XC7_AHB_REQN_EXTREQ1},//AHB_REQN_EXT1
- /* REQN in XC7 */
- {AHB_REQN_RESERVED, XC7_AHB_REQN_SSP1TX},//AHB_REQN_SSP1TX
- {AHB_REQN_RESERVED, XC7_AHB_REQN_SSP1RX},//AHB_REQN_SSP1RX
- {AHB_REQN_RESERVED, XC7_AHB_REQN_UART2TX},//AHB_REQN_UART2TX
- {AHB_REQN_RESERVED, XC7_AHB_REQN_UART2RX},//AHB_REQN_UART2RX
- {AHB_REQN_RESERVED, XC7_AHB_REQN_UART4TX},//AHB_REQN_UART4TX
- {AHB_REQN_RESERVED, XC7_AHB_REQN_UART4RX},//AHB_REQN_UART4RX
- {XC5_AHB_REQN_SDC, XC7_AHB_REQN_SDC},//AHB_REQN_SDC
- {AHB_REQN_RESERVED, XC7_AHB_REQN_SSP2TX},//AHB_REQN_SSP2TX
- {AHB_REQN_RESERVED, XC7_AHB_REQN_SSP2RX},//AHB_REQN_SSP2RX
- {AHB_REQN_RESERVED, XC7_AHB_REQN_USB_2_0},//AHB_REQN_USB_2_0
- {AHB_REQN_RESERVED, XC7_AHB_REQN_USB_1_1_EP1},//AHB_REQN_USB_1_1_EP1
- {AHB_REQN_RESERVED, XC7_AHB_REQN_USB_1_1_EP2},//AHB_REQN_USB_1_1_EP2
- {AHB_REQN_RESERVED, XC7_AHB_REQN_USB_1_1_EP3},//AHB_REQN_USB_1_1_EP3
- {AHB_REQN_RESERVED, XC7_AHB_REQN_USB_1_1_EP4},//AHB_REQN_USB_1_1_EP4
- };
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_get_reqn
- *
- * DESCRIPTION
- *
- * Get DMA request number from various platform.
- *
- * INPUTS
- *
- * dma_controller : (in) AHB or APB
- * device : (in) Device and peripheral.
- *
- * OUTPUTS
- *
- * none
- *
- ****************************************************************************/
- uint32_t _dmad_get_reqn(uint32_t dma_controller, uint32_t device){
- uint32_t reqn;
- uint32_t platform_id = IN32(PMU_IDNMBR0);
- if (dma_controller == DMAD_DMAC_APB_CORE){ /* APB */
- if ((platform_id & PRODUCT_ID_MASK) == AG101P_EMERALD)
- reqn = apb_dma_reqn_table[device].xc7_reqn;
- else
- reqn = apb_dma_reqn_table[device].xc5_reqn;
- } else { /* AHB */
- if ((platform_id & PRODUCT_ID_MASK) == AG101P_EMERALD)
- reqn = ahb_dma_reqn_table[device].xc7_reqn;
- else
- reqn = ahb_dma_reqn_table[device].xc5_reqn;
- }
-
- return reqn;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_detach_node
- *
- * DESCRIPTION
- *
- * Detach a DRB node from a specified list. The list is acknowledged in the
- * form of a head node and a tail one.
- *
- * INPUTS
- *
- * drb_pool : (in) The DRB pool of a DMA queue for a DMA channel
- * head : (in/out) Pointer to the head node of the list
- * tail : (in/out) Pointer to the tail node of the list
- * node : (in) The node to detach from the list
- *
- * OUTPUTS
- *
- * none
- *
- ****************************************************************************/
- static void _dmad_detach_node(DMAD_DRB *drb_pool, uint32_t *head, uint32_t *tail, uint32_t node){
- if (drb_pool[node].prev != 0){
- /* prev->next = this->next (= 0, if this is a tail) */
- drb_pool[drb_pool[node].prev].next = drb_pool[node].next;
- }
- else {
- /* this node is head, move head to next node (= 0, if this is the only one node) */
- *head = drb_pool[node].next;
- }
- if (drb_pool[node].next != 0){
- /* next->prev = this->prev (= 0, if this is a head) */
- drb_pool[drb_pool[node].next].prev = drb_pool[node].prev;
- }
- else {
- /* this node is tail, move tail to previous node (= 0, if this is the only one node) */
- *tail = drb_pool[node].prev;
- }
- drb_pool[node].prev = drb_pool[node].next = 0;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_detach_head
- *
- * DESCRIPTION
- *
- * Detach a DRB node from the head of a specified list. The list is
- * acknowledged in the form of a head node and a tail one.
- *
- * INPUTS
- *
- * drb_pool : (in) The DRB pool of a DMA queue for a DMA channel
- * head : (in/out) Pointer to the head node of the list
- * tail : (in/out) Pointer to the tail node of the list
- * drb : (out) Reference to the detached node pointer
- *
- * OUTPUTS
- *
- * none
- *
- ****************************************************************************/
- static void _dmad_detach_head(DMAD_DRB *drb_pool, uint32_t *head, uint32_t *tail, DMAD_DRB **drb){
- if (*head == 0){
- *drb = HAL_NULL;
- return;
- }
- *drb = &drb_pool[*head];
- if ((*drb)->next != 0){
- /* next->prev = this->prev (= 0, if this is a head) */
- drb_pool[(*drb)->next].prev = 0;
- /* prev->next = this->next (do nothing, if this is a head) */
- /* head = this->next */
- *head = (*drb)->next;
- }
- else {
- /* head = tail = 0 */
- *head = 0;
- *tail = 0;
- }
- /* this->prev = this->next = 0 (do nothing, if save code size) */
- (*drb)->prev = (*drb)->next = 0;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_detach_tail
- *
- * DESCRIPTION
- *
- * Detach a DRB node from the tail of a specified list. The list is
- * acknowledged in the form of a head node and a tail one.
- *
- * INPUTS
- *
- * drb_pool : (in) The DRB pool of a DMA queue for a DMA channel
- * head : (in/out) Pointer to the head node of the list
- * tail : (in/out) Pointer to the tail node of the list
- * drb : (out) Reference to the detached node pointer
- *
- * OUTPUTS
- *
- * none
- *
- ****************************************************************************/
- static inline void _dmad_detach_tail(DMAD_DRB *drb_pool, uint32_t *head, uint32_t *tail, DMAD_DRB **drb){
- if (*tail == 0){
- *drb = HAL_NULL;
- return;
- }
- *drb = &drb_pool[*tail];
- if ((*drb)->prev != 0){
- /* prev->next = this->next (= 0, if this is a tail) */
- drb_pool[(*drb)->prev].next = 0;
- /* next->prev = this->prev (do nothing, if this is a tail) */
- /* tail = this->prev */
- *tail = (*drb)->prev;
- }
- else {
- /* head = tail = 0 */
- *head = 0;
- *tail = 0;
- }
- /* this->next = this->prev = 0 (do nothing, if save code size) */
- (*drb)->prev = (*drb)->next = 0;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_attach_head
- *
- * DESCRIPTION
- *
- * Attach a DRB node to the head of a specified list. The list is
- * acknowledged in the form of a head node and a tail one.
- *
- * INPUTS
- *
- * drb_pool : (in) The DRB pool of a DMA queue for a DMA channel
- * head : (in/out) Pointer to the head node of the list
- * tail : (in/out) Pointer to the tail node of the list
- * drb : (in) The node number of the node to attach
- *
- * OUTPUTS
- *
- * none
- *
- ****************************************************************************/
- static inline void _dmad_attach_head(DMAD_DRB *drb_pool, uint32_t *head, uint32_t *tail, uint32_t node){
- if (*head != 0){
- drb_pool[*head].prev = node; /* head->prev = this */
- drb_pool[node].next = *head; /* this->next = head */
- drb_pool[node].prev = 0; /* this->prev = 0 */
- *head = node; /* head = node */
- }
- else {
- *head = *tail = node; /* head = tail = node */
- drb_pool[node].prev = drb_pool[node].next = 0;
- }
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_attach_tail
- *
- * DESCRIPTION
- *
- * Attach a DRB node to the tail of a specified list. The list is
- * acknowledged in the form of a head node and a tail one.
- *
- * INPUTS
- *
- * drb_pool : (in) The DRB pool of a DMA queue for a DMA channel
- * head : (in/out) Pointer to the head node of the list
- * tail : (in/out) Pointer to the tail node of the list
- * drb : (in) The node number of the node to attach
- *
- * OUTPUTS
- *
- * none
- *
- ****************************************************************************/
- static void _dmad_attach_tail(DMAD_DRB *drb_pool, uint32_t *head, uint32_t *tail, uint32_t node){
- if (*tail != 0){
- drb_pool[*tail].next = node; /* tail->next = this */
- drb_pool[node].prev = *tail; /* this->prev = tail */
- drb_pool[node].next = 0; /* this->next = 0 */
- *tail = node; /* tail = node */
- }
- else {
- *head = *tail = node; /* head = tail = node */
- drb_pool[node].prev = drb_pool[node].next = 0;
- }
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_ahb_lisr
- *
- * DESCRIPTION
- *
- * This is the ISR that services all AHB DMA channels on the NDS32
- * Integrator.
- *
- * NOTE
- * Currently this ISR processes one channel at a time. This replies the
- * assumption that the ISR will be invoked again as long as it's status
- * bit remains not-cleared, if interrupts for multiple channels happens
- * simultaneously.
- *
- * [todo] Above assumption may not be the real world case. Check it and
- * implement processing of multiple channels at once in the ISR, if
- * necessary.
- *
- * INPUTS
- *
- * vector : Interrupt vector number
- *
- * OUTPUTS
- *
- * none
- *
- ****************************************************************************/
- static void _dmad_ahb_lisr(int vector){
- DMAD_DRQ *drq;
- DMAD_DRB *drb;
- uint32_t channel; /* interrupt channel number */
- uint8_t tc_int = 0; /* interrupt reason is terminal count */
- uint8_t err_int = 0; /* interrupt reason is DMA error */
- //uint8_t abt_int = 0; /* interrupt reason is abort DMA transfer of this channel */
- uint32_t prv_msk = 0;
- if (vector != INTC_DMA_BIT)
- hal_system_error(HAL_ERR_UNHANDLED_INTERRUPT);
- prv_msk = hal_intc_irq_mask(IRQ_DMA_VECTOR);
- /* Check DMA status register to get channel number */
- for (channel = 0; channel < DMAD_AHB_MAX_CHANNELS; ++channel){
- if (GETB32(DMAC_INT_TC, channel)){
- tc_int = 1; /* Mark as TC int */
- SETB32(DMAC_INT_TC_CLR, channel); /* DMAC INT TC status clear */
- hal_intc_irq_clean(IRQ_DMA_VECTOR);
- break;
- }
- }
- /* Perform DMA error checking if no valid channel was found who assert the TC signal. */
- if (channel == DMAD_AHB_MAX_CHANNELS){
- for (channel = 0; channel < DMAD_AHB_MAX_CHANNELS; ++channel){
- if (GETB32(DMAC_INT_ERRABT, channel + DMAC_INT_ERR_SHIFT)){
- err_int = 1; /* Mark as ERR int */
- SETB32(DMAC_INT_ERRABT_CLR, channel + DMAC_INT_ERR_CLR_SHIFT); /* DMAC INT ERR status clear */
- hal_intc_irq_clean(IRQ_DMA_VECTOR);
- break;
- }
- }
- if (channel == DMAD_AHB_MAX_CHANNELS){
- for (channel = 0; channel < DMAD_AHB_MAX_CHANNELS; ++channel){
- if (GETB32(DMAC_INT_ERRABT, channel + DMAC_INT_ABT_SHIFT)){
- //abt_int = 1; /* Mark as ABT int */
- SETB32(DMAC_INT_ERRABT_CLR, channel + DMAC_INT_ABT_CLR_SHIFT); /* DMAC INT ABT status clear */
- hal_intc_irq_clean(IRQ_DMA_VECTOR);
- break;
- }
- }
- if (channel == DMAD_AHB_MAX_CHANNELS){
- /* Unknown reason ... (check why) */
- hal_system_error(HAL_ERR_UNHANDLED_INTERRUPT); /*return; */
- }
- }
- }
- /* Lookup channel's DRQ (DMA Request Queue) */
- drq = (DMAD_DRQ *)&ahb_drq_pool[channel];
- /* DMAC */
- /* Stop DMA channel temporarily */
- CLRB32(drq->channel_base + DMAC_CSR_OFFSET, DMAC_CSR_CH_EN_BIT);
- /*
- * Lookup/detach latest submitted DRB (DMA Request Block) from
- * the DRQ (DMA Request Queue), so ISR could kick off next DRB
- */
- _dmad_detach_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, &drb);
- if (drb == HAL_NULL){
- /* Check why DMA is triggered while submitted list is empty. */
- hal_system_error(HAL_ERR_UNHANDLED_INTERRUPT); /*return; */
- }
- /* Enable nested interrupt */
- GIE_ENABLE();
- /* Notify that new node is going to be available in the free list */
- if (drb->completion_sem != HAL_NULL){
- dmad.hisr_as |= (1 << channel); /* [15:0] AHB channel indicator */
- hal_raise_bh(&dmad.hisr); /* Call HISR to complete deferred tasks */
- }
- /* Process DRBs according to interrupt reason */
- if (tc_int){
- /* Mark DRB state as completed */
- drb->state = DMAD_DRB_STATE_COMPLETED;
- /* destination is memory */
- if (drq->dc_invalidate != HAL_NULL && drb->dst_index == DMAC_REQN_NONE)
- drq->dc_invalidate((unsigned long)(drb->dst_addr),
- (unsigned long)(drb->dst_addr) + (unsigned long)(drb->transfer_size));
-
- _dmad_attach_tail(drq->drb_pool, &drq->cpl_head, &drq->cpl_tail, drb->node);
- /* Check whether there are pending requests in the DRQ */
- if (drq->sbt_head != 0){
- drb = &drq->drb_pool[drq->sbt_head]; /* Lookup next DRB (DMA Request Block) */
- /* pre-submission-programming */
- if (drb->psp)
- drb->psp(drb->data);
- /* Kick-off DMA for next DRB */
- /* - Source and destination address */
- OUT32(drq->channel_base + DMAC_SRC_ADDR_OFFSET, drb->src_addr);
- OUT32(drq->channel_base + DMAC_DST_ADDR_OFFSET, drb->dst_addr);
- /* - Transfer size (in units of source width) */
- OUT32(drq->channel_base + DMAC_SIZE_OFFSET, drb->req_size);
- /* - Re-enable DMA channel */
- SETB32(drq->channel_base + DMAC_CSR_OFFSET, DMAC_CSR_CH_EN_BIT);
- }
- }
- else if (err_int){
- /* Mark DRB state as error */
- drb->state = DMAD_DRB_STATE_ERROR;
- _dmad_attach_tail(drq->drb_pool, &drq->cpl_head, &drq->cpl_tail, drb->node);
- /* Check whether there are pending requests in the DRQ */
- if (drq->sbt_head != 0){
- /* Lookup next DRB (DMA Request Block) */
- drb = &drq->drb_pool[drq->sbt_head];
- /* pre-submission-programming */
- if (drb->psp)
- drb->psp(drb->data);
- /*
- * Kick-off DMA for next DRB
- */
- /* Source and destination address */
- OUT32(drq->channel_base + DMAC_SRC_ADDR_OFFSET, drb->src_addr);
- OUT32(drq->channel_base + DMAC_DST_ADDR_OFFSET, drb->dst_addr);
- /* Transfer size (in units of source width) */
- OUT32(drq->channel_base + DMAC_SIZE_OFFSET, drb->req_size);
- /* Re-enable DMA channel */
- SETB32(drq->channel_base + DMAC_CSR_OFFSET, DMAC_CSR_CH_EN_BIT);
- }
- }
- else { /* abt_int */
- /* Remove all pending requests in the queue */
- while (1){
- /* Mark DRB state as abort */
- drb->state = DMAD_DRB_STATE_ABORT;
- _dmad_attach_tail(drq->drb_pool, &drq->cpl_head, &drq->cpl_tail, drb->node);
- /* Detach next submitted DRB (DMA Request Block) from the DRQ (DMA Request Queue) */
- _dmad_detach_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, &drb);
- if (drb == HAL_NULL)
- break;
- }
- }
- #ifdef DMAD_POLLING
- if (dmad.hisr_as & 0x0000ffff){
- while (drq->cpl_head != 0){
- _dmad_detach_head(drq->drb_pool, &drq->cpl_head, &drq->cpl_tail, &drb);
- _dmad_attach_tail(drq->drb_pool, &drq->fre_head, &drq->fre_tail, drb->node);
- /* completion-of-submission-programming */
- if (drb->rcp)
- drb->rcp(drb->data);
- }
- }
- #endif
- GIE_DISABLE();
- hal_intc_irq_unmask(prv_msk);
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_apb_lisr
- *
- * DESCRIPTION
- *
- * This is the ISR that services all APB DMA channels on the NDS32
- * Integrator.
- *
- * NOTE
- * Currently this ISR processes one channel at a time. This replies the
- * assumption that the ISR will be invoked again as long as it's status
- * bit remains not-cleared, if interrupts for multiple channels happens
- * simultaneously.
- *
- * [todo] Above assumption may not be the real world case. Check it and
- * implement processing of multiple channels at once in the ISR, if
- * necessary.
- *
- * INPUTS
- *
- * vector : Interrupt vector number
- *
- * OUTPUTS
- *
- * none
- *
- ****************************************************************************/
- static void _dmad_apb_lisr(int vector){
- DMAD_DRQ *drq;
- DMAD_DRB *drb;
- uint32_t channel; /* interrupt channel number */
- uint8_t finish_int = 0; /* interrupt reason is transfer completed */
- uint8_t err_int = 0; /* interrupt reason is DMA error */
- uint32_t prv_msk = 0;
- if (vector != INTC_APB_BIT)
- hal_system_error(HAL_ERR_UNHANDLED_INTERRUPT);
- /* Mask priority <= apb_bridge's interrupt */
- prv_msk = hal_intc_irq_mask(IRQ_APBBRIDGE_VECTOR);
- /* Check DMA status register to get channel number & clean pending */
- for (channel = 0; channel < DMAD_APB_MAX_CHANNELS; ++channel){
- uint32_t channel_base = APBBR_DMA_BASE_CH(channel);
- if (GETB32(channel_base + APBBR_DMA_CMD_OFFSET, APBBR_DMA_FINTST_BIT)){
- /* Mark as finish int */
- finish_int = 1;
- /* APB DMA finish int status clear */
- CLRB32(channel_base + APBBR_DMA_CMD_OFFSET, APBBR_DMA_FINTST_BIT);
- hal_intc_irq_clean(IRQ_APBBRIDGE_VECTOR);
- break;
- }
- }
- /* Perform DMA error checking if no valid channel was found who assert the finish signal
- * & clean pending
- */
- if (channel == DMAD_APB_MAX_CHANNELS){
- for (channel = 0; channel < DMAD_APB_MAX_CHANNELS; ++channel){
- uint32_t channel_base = APBBR_DMA_BASE_CH(channel);
- if (GETB32(channel_base + APBBR_DMA_CMD_OFFSET, APBBR_DMA_ERRINTST_BIT)){
- /* Mark as error int */
- err_int = 1;
- /* APB DMA error int status clear */
- CLRB32(channel_base + APBBR_DMA_CMD_OFFSET, APBBR_DMA_ERRINTST_BIT);
- hal_intc_irq_clean(IRQ_APBBRIDGE_VECTOR);
- break;
- }
- }
- if (channel == DMAD_AHB_MAX_CHANNELS)
- hal_system_error(HAL_ERR_UNHANDLED_INTERRUPT);
- }
- /* Lookup channel's DRQ (DMA Request Queue) */
- drq = (DMAD_DRQ *)&apb_drq_pool[channel];
- /*
- * APB
- */
- /* Stop DMA channel temporarily */
- CLRB32(drq->channel_base + APBBR_DMA_CMD_OFFSET, APBBR_DMA_CHEN_BIT);
- /*
- * Lookup/detach latest submitted DRB (DMA Request Block) from
- * the DRQ (DMA Request Queue), so ISR could kick off next DRB
- */
- _dmad_detach_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, &drb);
- if (drb == HAL_NULL){
- /* Check why DMA is triggered while submitted list is empty. */
- hal_system_error(HAL_ERR_UNHANDLED_INTERRUPT);
- }
- GIE_ENABLE();
- /* Notify that new node is going to be available in the free list */
- dmad.hisr_as |= (0x00010000 << channel); /* [31:16] APB channel indicator */
- hal_raise_bh(&dmad.hisr); /* Call HISR to complete deferred tasks */
- /* Process DRBs according to the cause of this interrupt */
- if (finish_int){
- /* Mark DRB state as completed */
- drb->state = DMAD_DRB_STATE_COMPLETED;
- _dmad_attach_tail(drq->drb_pool, &drq->cpl_head, &drq->cpl_tail, drb->node);
- /* destination is memory */
- if (drq->dc_invalidate != HAL_NULL && drb->dst_index == DMAC_REQN_NONE)
- drq->dc_invalidate((unsigned long)(drb->dst_addr),
- (unsigned long)(drb->dst_addr) + (unsigned long)(drb->transfer_size));
-
- /* Check whether there are pending requests in the DRQ */
- if (drq->sbt_head != 0){
- /* Lookup next DRB (DMA Request Block) */
- drb = &drq->drb_pool[drq->sbt_head];
- /* pre-submission-programming */
- if (drb->psp)
- drb->psp(drb->data);
- /*
- * Kick-off DMA for next DRB
- */
- /* Source and destination address */
- OUT32(drq->channel_base + APBBR_DMA_SAD_OFFSET, drb->src_addr);
- OUT32(drq->channel_base + APBBR_DMA_DAD_OFFSET, drb->dst_addr);
- /* - Transfer size (in units of source width) */
- OUT32(drq->channel_base + APBBR_DMA_CYC_OFFSET, drb->req_size & APBBR_DMA_CYC_MASK);
- /* - Re-enable DMA channel */
- SETB32(drq->channel_base + APBBR_DMA_CMD_OFFSET, APBBR_DMA_CHEN_BIT);
- }
- }
- else if (err_int){
- /* Remove all pending requests in the queue */
- while (1){
- /* Mark DRB state as abort */
- drb->state = DMAD_DRB_STATE_ABORT;
- _dmad_attach_tail(drq->drb_pool, &drq->cpl_head, &drq->cpl_tail, drb->node);
- _dmad_detach_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, &drb);
- if (drb == HAL_NULL)
- break;
- }
- }
-
- #ifdef DMAD_POLLING
- if (dmad.hisr_as & 0xffff0000){
- while (drq->cpl_head != 0){
- _dmad_detach_head(drq->drb_pool, &drq->cpl_head, &drq->cpl_tail, &drb);
- _dmad_attach_tail(drq->drb_pool, &drq->fre_head, &drq->fre_tail, drb->node);
- /* completion-of-submission-programming */
- if (drb->rcp)
- drb->rcp(drb->data);
- }
- dmad.hisr_as &= ~(0x00010000 << channel);
- }
- #endif
- GIE_DISABLE();
- hal_intc_irq_unmask(prv_msk);
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_hisr
- *
- * DESCRIPTION
- *
- * This HISR performs the defferred tasks from LISR.
- *
- * NOTE
- *
- * Current task list of this HISR
- *
- * - Signal DRQ available event for waiting DRQ allocations.
- *
- * INPUTS
- *
- * vector : Interrupt vector number
- *
- * OUTPUTS
- *
- * none
- *
- ****************************************************************************/
- static inline void _dmad_hisr(void *param){
- DMAD_DRQ *drq;
- DMAD_DRB *drb = NULL;
- //uint32_t core_intl;
- uint32_t channel;
- while(1){
- hal_bh_t *bh = (hal_bh_t *)param;
- hal_pend_semaphore(&bh->sem, HAL_SUSPEND);
- //core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
-
- /* Signal free-list available event */
- if ((dmad.hisr_as & 0xffff0000) != 0){
-
- /* Disable apb_bridge interrupt to avoid race condition */
- HAL_INTC_IRQ_ATOMIC_DISABLE(IRQ_APBBRIDGE_VECTOR);
- /* APB LISR */
- for (channel = 0; channel < DMAD_APB_MAX_CHANNELS; ++channel){
-
- if (dmad.hisr_as & (0x00010000 << channel)){
- drq = (DMAD_DRQ *)&apb_drq_pool[channel];
- while (drq->cpl_head != 0){
-
- _dmad_detach_head(drq->drb_pool, &drq->cpl_head, &drq->cpl_tail, &drb);
- _dmad_attach_tail(drq->drb_pool, &drq->fre_head, &drq->fre_tail, drb->node);
- hal_post_semaphore(&drq->drb_sem);
- /* completion-of-submission-programming */
- if (drb->rcp)
- drb->rcp(drb->data);
- if(drb->completion_sem != HAL_NULL)
- {
- // puts("APB DMA HISR Complete!!!\r\n");
- hal_post_semaphore(drb->completion_sem);
-
- }
- }
- dmad.hisr_as &= ~(0x00010000 << channel);
- }
- }
- /* Re-enable apb_bridge interrupt */
- HAL_INTC_IRQ_ATOMIC_ENABLE(IRQ_APBBRIDGE_VECTOR);
- }
- else if ((dmad.hisr_as & 0x0000ffff) != 0){
- /* Disable AHB_DMA interrupt to avoid race condition */
- HAL_INTC_IRQ_ATOMIC_DISABLE(IRQ_DMA_VECTOR);
- /* AHB LISR */
- for (channel = 0; channel < DMAD_AHB_MAX_CHANNELS; ++channel){
- if (dmad.hisr_as & (1 << channel)){
- drq = (DMAD_DRQ *)&ahb_drq_pool[channel];
- while (drq->cpl_head != 0){
- _dmad_detach_head(drq->drb_pool, &drq->cpl_head, &drq->cpl_tail, &drb);
- _dmad_attach_tail(drq->drb_pool, &drq->fre_head, &drq->fre_tail, drb->node);
-
- hal_post_semaphore(&drq->drb_sem);
- /* completion-of-submission-programming */
- if (drb->rcp)
- drb->rcp(drb->data);
- }
- if (drb->completion_sem != HAL_NULL)
- hal_post_semaphore(drb->completion_sem);
- dmad.hisr_as &= ~(1 << channel);
- }
- }
- HAL_INTC_IRQ_ATOMIC_ENABLE(IRQ_DMA_VECTOR);
- }
- // hal_global_int_ctl(core_intl);
- }
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_channel_alloc
- *
- * DESCRIPTION
- *
- * This function allocates a DMA channel for client's request. If the
- * channel is already used by other clients, then this function will
- * fail the allocation.
- *
- * INPUTS
- *
- * ch_req : Pointer to the DMA request descriptor structure
- * init : Specify whether to initialize the DMA channel HW if the
- * allocation is successfull. Clients could also postpone
- * the initialization task to the _dmad_channel_init()
- * routine.
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful allocation,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- uint32_t _dmad_channel_alloc(DMAD_CHANNEL_REQUEST_DESC *ch_req, uint8_t init){
- uint32_t status;
- DMAD_DRQ *drq_iter;
- DMAD_DRB *drb_iter;
- uint32_t i = 0;
- if (ch_req == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- if (ch_req->controller == DMAD_DMAC_AHB_CORE)
- drq_iter = ahb_drq_pool;
- else if (ch_req->controller == DMAD_DMAC_APB_CORE)
- drq_iter = apb_drq_pool;
- else
- return HAL_ERR_NOT_PRESENT;
- /* First-time initialization for DMA queue pool access control object */
- if (dmad.drq_pool_mutex_init == 0){
- status = hal_create_mutex(&dmad.drq_pool_mutex, "drqpool");
- if (status != HAL_SUCCESS){
- DMAD_TRACE(("[dmad] failed to create drq_pool mutex!\r\n"));
- return status;
- }
- dmad.drq_pool_mutex_init = 1;
- }
- /* Obtain exclusive access to the pool of channel queues */
- if (hal_current() != HAL_NULL){
- /* Suspending is only valid to the current task -- no need to lock if invoked from HISR. */
- status = hal_wait_for_mutex(&dmad.drq_pool_mutex, HAL_SUSPEND);
- if (status != HAL_SUCCESS){
- DMAD_TRACE(("[dmad] failed to lock drq_pool! status(0x%08lx)\r\n", status));
- return status;
- }
- }
- /* Locate an available DMA channel */
- if (ch_req->controller == DMAD_DMAC_AHB_CORE){
- #if 0
- /* UART - TX/RX channel is limitted */
- if ((ch_req->ahbch_req.src_index == DMAC_REQN_UART1TX) ||
- (ch_req->ahbch_req.dst_index == DMAC_REQN_UART1TX) ||
- (ch_req->ahbch_req.src_index == DMAC_REQN_UART2TX) ||
- (ch_req->ahbch_req.dst_index == DMAC_REQN_UART2TX))
- {
- /* TX channel is limitied to C/D */
- drq_iter = &ahb_drq_pool[2];
- for (i = 2; i < 4; ++i, ++drq_iter){
- if (drq_iter->allocated == 0)
- break;
- }
- }
- else if ((ch_req->ahbch_req.src_index == DMAC_REQN_UART1RX) ||
- (ch_req->ahbch_req.dst_index == DMAC_REQN_UART1RX) ||
- (ch_req->ahbch_req.src_index == DMAC_REQN_UART2RX) ||
- (ch_req->ahbch_req.dst_index == DMAC_REQN_UART2RX)){
- /* RX channel is limitied to A/B */
- for (i = 0; i < 2; ++i, ++drq_iter){
- if (drq_iter->allocated == 0)
- break;
- }
- }
- else
- #endif
- {
- if ((ch_req->ahbch_req.src_index != DMAC_REQN_NONE) ||
- (ch_req->ahbch_req.dst_index != DMAC_REQN_NONE)){
- /*
- * [2007-12-03] It looks current board have problem to do dma
- * traffic for APB devices on DMAC channel 0/1. Redirect all
- * APB devices to start from channel 2.
- * [todo] include USB controller ?
- */
- drq_iter = &ahb_drq_pool[2];
- for (i = 2; i < DMAD_AHB_MAX_CHANNELS; ++i, ++drq_iter){
- if (drq_iter->allocated == 0)
- break;
- }
- }
- else {
- /* channel for other devices is free to allocate */
- for (i = 0; i < DMAD_AHB_MAX_CHANNELS; ++i, ++drq_iter){
- if (drq_iter->allocated == 0)
- break;
- }
- }
- }
- if (i == DMAD_AHB_MAX_CHANNELS){
- DMAD_TRACE(("out of available channels (AHB DMAC)!\r\n"));
- return HAL_ERR_UNAVAILABLE;
- }
- DMAD_TRACE(("allocated channel: %d (AHB DMAC)\r\n"));
- }
- else if (ch_req->controller == DMAD_DMAC_APB_CORE){
- for (i = 0; i < DMAD_APB_MAX_CHANNELS; ++i, ++drq_iter){
- if (drq_iter->allocated == 0)
- break;
- }
- if (i == DMAD_APB_MAX_CHANNELS){
- DMAD_TRACE(("out of available channels (APB DMAC)!\r\n"));
- return HAL_ERR_UNAVAILABLE;
- }
- DMAD_TRACE(("allocated channel: %d (APB DMAC)\r\n", i));
- }
- /* Allocate the DMA channel */
- drq_iter->allocated = 1;
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR.
- * Release exclusive access to the pool of channel queues
- */
- status = hal_release_mutex(&dmad.drq_pool_mutex);
- if (status != HAL_SUCCESS){
- DMAD_TRACE(("[dmad] failed to unlock drq_pool!\r\n"));
- return status;
- }
- }
- /* Create mutex object for DMA queue access control */
- status = hal_create_mutex(&drq_iter->drb_pool_mutex, "drq");
- if (status != HAL_SUCCESS){
- DEBUG(1, 1, "failed to create mutex for drb_pool!\n");
- return status;
- }
- /* Create semaphores for free-list allocation operation */
- status = hal_create_semaphore(&drq_iter->drb_sem, DMAD_DRB_POOL_SIZE - 1, (void*)0);
- if (status != HAL_SUCCESS){
- DEBUG(1, 1, "failed to create semaphores for drb_pool!\n");
- return status;
- }
- /* Record the channel number in client's struct */
- ch_req->channel = i;
- /* Record the channel's queue handle in client's struct */
- ch_req->drq = drq_iter;
- if (ch_req->controller == DMAD_DMAC_AHB_CORE){
- //drq_iter->controller_base = DMAC_BASE;
- drq_iter->channel_base = DMAC_BASE_CH(i);
- }
- else {
- //drq_iter->controller_base = APBBR_BASE;
- drq_iter->channel_base = APBBR_DMA_BASE_CH(i);
- }
- /* Initialize DMA channel's DRB pool as list of free DRBs */
- drb_iter = &drq_iter->drb_pool[0];
- drb_iter->prev = 0;
- drb_iter->next = 0;
- drb_iter->node = 0;
- //drb_iter->src_addr = 0;
- //drb_iter->dst_addr = 0;
- //drb_iter->req_size = 0;
- ++drb_iter;
- for (i = 1; i < DMAD_DRB_POOL_SIZE; ++i, ++drb_iter){
- drb_iter->prev = i - 1;
- drb_iter->next = i + 1;
- drb_iter->node = i;
- //drb_iter->src_addr = 0;
- //drb_iter->dst_addr = 0;
- //drb_iter->req_size = 0;
- }
- drq_iter->drb_pool[DMAD_DRB_POOL_SIZE - 1].next = 0;
- /* Initialize DMA channel's DRB free-list, ready-list, and submitted-list */
- drq_iter->fre_head = 1;
- drq_iter->fre_tail = DMAD_DRB_POOL_SIZE - 1;
- drq_iter->rdy_head = drq_iter->rdy_tail = 0;
- drq_iter->sbt_head = drq_iter->sbt_tail = 0;
- drq_iter->cpl_head = drq_iter->cpl_tail = 0;
- /* Initialize the channel */
- if (init)
- _dmad_channel_init(ch_req);
- /* Initialize cache writeback function */
- #ifndef CONFIG_CPU_DCACHE_ENABLE
- drq_iter->dc_writeback = HAL_NULL;
- drq_iter->dc_invalidate = HAL_NULL;
- #else
- drq_iter->dc_writeback = nds32_dma_flush_range;
- drq_iter->dc_invalidate = nds32_dma_inv_range;
- #endif
- return HAL_SUCCESS;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_channel_free
- *
- * DESCRIPTION
- *
- * This function frees a DMA channel for future clients' request.
- *
- * INPUTS
- *
- * ch_req : Pointer to the DMA request descriptor structure
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful channel free,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- uint32_t _dmad_channel_free(const DMAD_CHANNEL_REQUEST_DESC *ch_req){
- uint32_t status;
- DMAD_DRQ *drq;
- if (ch_req == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- drq = (DMAD_DRQ *)ch_req->drq;
- if (drq == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- if (drq->allocated == 0)
- return HAL_ERR_INVALID_POINTER;
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR.
- * Obtain exclusive access to the pool of channel queues
- */
- status = hal_wait_for_mutex(&dmad.drq_pool_mutex, HAL_SUSPEND);
- if (status != HAL_SUCCESS)
- return status;
- }
- /* Todo: Stop/abort channel I/O if it's busy ? */
- /* Delete mutex object of DMA queue access control */
- status = hal_destroy_mutex(&drq->drb_pool_mutex);
- if (status != HAL_SUCCESS)
- return status;
- /* Delete semaphores of free-list allocation operation */
- status = hal_destroy_semaphore(&drq->drb_sem);
- if (status != HAL_SUCCESS)
- return status;
- /* Reset HISR activation state */
- if (ch_req->controller == DMAD_DMAC_AHB_CORE)
- dmad.hisr_as &= ~(1 << ch_req->channel);
- else
- dmad.hisr_as &= ~(1 << (ch_req->channel + 16));
- /* Set released flag. */
- drq->allocated = 0;
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR.
- * Release exclusive access to the pool of channel queues
- */
- status = hal_release_mutex(&dmad.drq_pool_mutex);
- if (status != HAL_SUCCESS)
- return status;
- }
- return HAL_SUCCESS;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_ahb_init
- *
- * DESCRIPTION
- *
- * This function performs the AHB DMAC channel initialization.
- *
- * INPUTS
- *
- * ch_req : Pointer to the DMA request descriptor structure
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful initialization,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- static uint32_t _dmad_ahb_init(const DMAD_CHANNEL_REQUEST_DESC *ch_req){
- uint32_t status = HAL_SUCCESS;
- DMAD_DRQ *drq = (DMAD_DRQ *)ch_req->drq;
- DMAD_AHBCH_REQUEST *ahb_req = (DMAD_AHBCH_REQUEST *)(&ch_req->ahbch_req);
- uint32_t channel = (uint32_t)ch_req->channel;
- uint32_t channel_base = drq->channel_base;
- uint32_t core_intl;
- /* Register LISR */
- if (dmad.ahb_lisr_registered == 0){
- status = hal_register_isr(IRQ_DMA_VECTOR, _dmad_ahb_lisr, (void*)0);
- // status = hal_register_isr(INTC_DMA_BIT, _dmad_ahb_lisr, (void*)0);
-
- if (status != HAL_SUCCESS)
- return status;
- dmad.ahb_lisr_registered = 1;
- }
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- /* Following code require _safe_exit return path */
- /* INTC */
- /* Disable DMAC interrupt */
- hal_intc_irq_disable(IRQ_DMA_VECTOR);
-
- /* Clear DMAC interrupt status */
- hal_intc_irq_clean(IRQ_DMA_VECTOR);
- /* Setup DMAC interrupt trigger mode - level trigger */
- /* Setup DMAC interrupt trigger level - assert high */
- hal_intc_irq_config(IRQ_DMA_VECTOR, IRQ_LEVEL_TRIGGER, IRQ_ACTIVE_HIGH);
-
- /* Enable DMAC interrupt */
- hal_intc_irq_enable(IRQ_DMA_VECTOR);
- #if 0
- #if ( NO_EXTERNAL_INT_CTL == 1 )
- /*
- * IVIC without INTC
- */
- /* FIXME add trigger mode */
- /* Enable DMAC interupt */
- SR_SETB32(NDS32_SR_INT_MASK2,IRQ_DMA_VECTOR);
-
- #else
- /*
- * INTC
- */
- /* Clear DMAC interrupt status */
- SETB32(INTC_HW1_CLR, INTC_DMA_BIT);
- /* Setup DMAC interrupt trigger mode - level trigger */
- CLRB32(INTC_HW1_TMR, INTC_DMA_BIT);
- /* Setup DMAC interrupt trigger level - assert high */
- CLRB32(INTC_HW1_TLR, INTC_DMA_BIT);
- /* Enable DMAC interrupt */
- SETB32(INTC_HW1_ER, INTC_DMA_BIT);
- #endif
- #endif
- /*
- * PMU
- */
- /*
- * Route APB device DMA to an AHB DMAC channel and specify the channel
- * number. (connection status could be read back from PMU_AHBDMA_REQACK
- * register)
- * Note: Only one device is routed per AHB DMA channel, the other target
- * should be either (1) the same device (same reqn), or (2) the AHB
- * device (reqn = 0).
- */
- if (ahb_req->dst_index != PMU_REQN_NONE){
- /* DMA transfer to device */
- if ((ahb_req->dst_index > PMU_REQN_EXT1) ||
- (dmad_ahb_ch_route_table[ahb_req->dst_index].route_cr == 0)){
- status = HAL_ERR_NOT_PRESENT;
- goto _safe_exit;
- }
- OUT32(dmad_ahb_ch_route_table[ahb_req->dst_index].route_cr,
- PMU_DMACUSED_MASK | ((ahb_req->dst_reqn << PMU_CHANNEL_SHIFT) & PMU_CHANNEL_MASK));
- }
- else if (ahb_req->src_index != PMU_REQN_NONE){
- /* DMA transfer from device */
- if ((ahb_req->src_index > PMU_REQN_EXT1) ||
- (dmad_ahb_ch_route_table[ahb_req->src_index].route_cr == 0)){
- status = HAL_ERR_NOT_PRESENT;
- goto _safe_exit;
- }
- OUT32(dmad_ahb_ch_route_table[ahb_req->src_index].route_cr,
- PMU_DMACUSED_MASK | ((ahb_req->src_reqn << PMU_CHANNEL_SHIFT) & PMU_CHANNEL_MASK));
- }
- /*
- * DMAC (Controller Setting)
- * Note: Controller global setting actually should not placed in this channel
- * specific setup routine. However, currently the only global setting
- * is a fixed value, so it is ok to set it here. In this way, we save
- * the effert to setup the global parameters elsewhere.
- */
- /* INT TC/ERR/ABT status clear */
- SETB32(DMAC_INT_TC_CLR, channel); /* TC clear */
- SETB32(DMAC_INT_ERRABT_CLR, channel + DMAC_INT_ERR_CLR_SHIFT); /* ERR clear */
- SETB32(DMAC_INT_ERRABT_CLR, channel + DMAC_INT_ABT_CLR_SHIFT); /* ABT clear */
- /* CSR (enable DMAC, set M0 & M1 endian default to little endian transfer) */
- OUT32(DMAC_CSR, DMAC_DMACEN_MASK |
- ((DMAC_ENDIAN_LITTLE << DMAC_M0ENDIAN_BIT) & DMAC_M0ENDIAN_MASK) |
- ((DMAC_ENDIAN_LITTLE << DMAC_M1ENDIAN_BIT) & DMAC_M1ENDIAN_MASK));
- /* DMAC (Channel-Specific Setting) */
- /* SYNC */
- if (ahb_req->sync)
- SETB32(DMAC_SYNC, channel);
- else
- CLRB32(DMAC_SYNC, channel);
- /*
- * Channel CSR
- * CH_EN : 0 (disable)
- * DST_SEL : 0 (Master 0)
- * SRC_SEL : 0 (Master 0)
- * DSTAD_CTL : ahb_req->dst_addr_ctrl
- * SRCAD_CTL : ahb_req->src_addr_ctrl
- * MODE : 0 (normal)
- * DST_WIDTH : ahb_req->dst_width
- * SRC_WIDTH : ahb_req->src_width
- * ABT : 0 (not abort)
- * SRC_SIZE : 0 (burst size = 1 byte)
- * PROT1 : 0 (user mode)
- * PROT2 : 0 (bot bufferable)
- * PROT3 : 0 (not cacheable)
- * CHPRI : ahb_req->priority
- * DMA_FF_TH : 0 (FIA320 only, threshold = 1)
- * TC_MSK : 0 (TC counter status enable)
- */
- OUT32(channel_base + DMAC_CSR_OFFSET,
- ((ahb_req->src_width << DMAC_CSR_SRC_WIDTH_SHIFT) & DMAC_CSR_SRC_WIDTH_MASK) |
- ((ahb_req->src_addr_ctrl << DMAC_CSR_SRCAD_CTL_SHIFT) & DMAC_CSR_SRCAD_CTL_MASK) |
- ((ahb_req->dst_width << DMAC_CSR_DST_WIDTH_SHIFT) & DMAC_CSR_DST_WIDTH_MASK) |
- ((ahb_req->dst_addr_ctrl << DMAC_CSR_DSTAD_CTL_SHIFT) & DMAC_CSR_DSTAD_CTL_MASK) |
- ((ahb_req->priority << DMAC_CSR_CHPRI_SHIFT) & DMAC_CSR_CHPRI_MASK));
- /* Channel CFG
- * INT_TC_MSK : 0 (enable TC int)
- * INT_ERR_MSK : 0 (enable ERR int)
- * INT_ABT_MSK : 0 (enable ABT int)
- * SRC_RS : 0
- * SRC_HE : 0
- * BUSY : r/o
- * DST_RS : 0
- * DST_HE : 0
- * LLP_CNT : r/o
- */
- OUT32(channel_base + DMAC_CFG_OFFSET, 0);
- /*(DMAC_CFG_INT_TC_MSK | DMAC_CFG_INT_ERR_MSK | DMAC_CFG_INT_ABT_MSK)); */
- #if 1 /* (Not found in AG101 spec -- has removed this setting?) */
- /* - HW handshake mode: CSR & CFG */
- if (ahb_req->hw_handshake != 0){
- /* Channel CFG - Device REQN and HW-handshake mode */
- uint32_t cfg = IN32(channel_base + DMAC_CFG_OFFSET);
- if (ahb_req->src_index != DMAC_REQN_NONE){
- OUT32(channel_base + DMAC_CFG_OFFSET, cfg |
- ((ahb_req->src_reqn << DMAC_CFG_INT_SRC_RS_SHIFT) & DMAC_CFG_INT_SRC_RS_MASK) |
- ((1 << DMAC_CFG_INT_SRC_HE_BIT) & DMAC_CFG_INT_SRC_HE_MASK) |
- ((0 << DMAC_CFG_INT_DST_RS_SHIFT) & DMAC_CFG_INT_DST_RS_MASK) |
- ((0 << DMAC_CFG_INT_DST_HE_BIT) & DMAC_CFG_INT_DST_HE_MASK));
- }
- else {
- OUT32(channel_base + DMAC_CFG_OFFSET, cfg |
- ((0 << DMAC_CFG_INT_SRC_RS_SHIFT) & DMAC_CFG_INT_SRC_RS_MASK) |
- ((0 << DMAC_CFG_INT_SRC_HE_BIT) & DMAC_CFG_INT_SRC_HE_MASK) |
- ((ahb_req->dst_reqn << DMAC_CFG_INT_DST_RS_SHIFT) & DMAC_CFG_INT_DST_RS_MASK) |
- ((1 << DMAC_CFG_INT_DST_HE_BIT) & DMAC_CFG_INT_DST_HE_MASK));
- }
- /* Channel CSR - Enable HW-handshake mode */
- SETB32(channel_base + DMAC_CSR_OFFSET, DMAC_CSR_MODE_BIT);
- }
- #endif
- /* SRC_ADDR and DST_ADDR - not now */
- /* LLP */
- OUT32(channel_base + DMAC_LLP_OFFSET, 0);
- /* TOT_SIZE - not now */
- _safe_exit:
- hal_global_int_ctl(core_intl);
- return status;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_apb_init
- *
- * DESCRIPTION
- *
- * This function performs the APB bridge DMA channel initialization.
- *
- * INPUTS
- *
- * ch_req : Pointer to the DMA request descriptor structure
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful initialization,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- static uint32_t _dmad_apb_init(const DMAD_CHANNEL_REQUEST_DESC *ch_req){
- uint32_t status = HAL_SUCCESS;
- DMAD_DRQ *drq = (DMAD_DRQ *)ch_req->drq;
- DMAD_APBCH_REQUEST *apb_req = (DMAD_APBCH_REQUEST *)(&ch_req->apbch_req);
- uint32_t channel = (uint32_t)ch_req->channel;
- uint32_t channel_base = drq->channel_base;
- uint32_t channel_cmd = 0;
- uint32_t core_intl;
- uint32_t dst_bus_sel;
- uint32_t src_bus_sel;
- /* Register LISR */
- if (dmad.apb_lisr_registered == 0){
- status = hal_register_isr(IRQ_APBBRIDGE_VECTOR , _dmad_apb_lisr, (void*)0);
-
- if (status != HAL_SUCCESS)
- return status;
- dmad.apb_lisr_registered = 1;
- }
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- /* Following code require _safe_exit return path */
- /* INTC */
- /* Disable APB Bridge interrupt */
- hal_intc_irq_disable(IRQ_APBBRIDGE_VECTOR);
-
- /* Clear APB Bridge interrupt status */
- hal_intc_irq_clean(IRQ_APBBRIDGE_VECTOR);
- /* Setup APB Bridge interrupt trigger mode - level trigger */
- /* Setup APB Bridge interrupt trigger level - assert high */
- hal_intc_irq_config(IRQ_APBBRIDGE_VECTOR, IRQ_LEVEL_TRIGGER, IRQ_ACTIVE_HIGH);
- /* Enable APB Bridge interrupt */
- hal_intc_irq_enable(IRQ_APBBRIDGE_VECTOR);
- #if 0
- #if ( NO_EXTERNAL_INT_CTL == 1 )
- /*
- * IVIC without INTC
- */
- /* FIXME add trigger mode */
- /* Enable APB Bridge interrupt */
- SR_SETB32(NDS32_SR_INT_MASK2,IRQ_APBBRIDGE_VECTOR);
- #else
- /*
- * INTC
- */
- /* Clear APB Bridge interrupt status */
- SETB32(INTC_HW1_CLR, INTC_APB_BIT);
- /* Setup APB Bridge interrupt trigger mode - level trigger */
- CLRB32(INTC_HW1_TMR, INTC_APB_BIT);
- /* Setup APB Bridge interrupt trigger level - assert high */
- CLRB32(INTC_HW1_TLR, INTC_APB_BIT);
- /* Enable APB Bridge interrupt */
- SETB32(INTC_HW1_ER, INTC_APB_BIT);
- #endif
- #endif
- /* PMU */
- /* Check platform version */
- uint32_t max_reqn = _dmad_get_reqn(DMAD_DMAC_APB_CORE, APB_MAX);
- /*
- * Undo APB device DMA to AHB DMAC channel routing. (connection status
- * is obtained from reading back the PMU_AHBDMA_REQACK register)
- */
- if ((apb_req->src_index > max_reqn) ||
- (apb_req->dst_index > max_reqn)){
- status = HAL_ERR_NOT_PRESENT;
- goto _safe_exit;
- }
- if (apb_req->src_index != APBBR_REQN_NONE){ /* quick filter out non-APB reqn */
- uint32_t ahb_ch;
- /* Search for source device whether it is re-routed to AHB DMA channel */
- for (ahb_ch = 0; ahb_ch < DMAD_AHB_MAX_CHANNELS; ++ahb_ch){
- uint32_t ahb_reqn = (IN32(PMU_AHBDMA_REQACK) >> (ahb_ch << 2)) & 0x0000000f;
- if ((ahb_reqn != APBBR_REQN_NONE) &&
- (ahb_reqn == dmad_apb_reqn_route_table[apb_req->src_index].ahb_reqn)){
- DMAD_TRACE(("src: re-route DMAC ch %2d to APB.\r\n", ahb_ch));
- /* got it! un-route from AHB back to APB */
- OUT32(dmad_ahb_ch_route_table[ahb_reqn].route_cr,
- ((channel << PMU_CHANNEL_SHIFT) & PMU_CHANNEL_MASK));
- break;
- }
- }
- }
- if (apb_req->dst_index != APBBR_REQN_NONE){ /* quick filter out non-APB reqn */
- uint32_t ahb_ch;
- /* Search for source device whether it is re-routed to AHB DMA channel */
- for (ahb_ch = 0; ahb_ch < DMAD_AHB_MAX_CHANNELS; ++ahb_ch){
- uint32_t ahb_reqn = (IN32(PMU_AHBDMA_REQACK) >> (ahb_ch << 2)) & 0x0000000f;
- if ((ahb_reqn != APBBR_REQN_NONE) &&
- (ahb_reqn == dmad_apb_reqn_route_table[apb_req->dst_index].ahb_reqn)){
- DMAD_TRACE(("dst: re-route DMAC ch %2d to APB.\r\n", ahb_ch));
- /* got it! un-route from AHB back to APB */
- OUT32(dmad_ahb_ch_route_table[ahb_reqn].route_cr,
- ((channel << PMU_CHANNEL_SHIFT) & PMU_CHANNEL_MASK));
- break;
- }
- }
- }
- /* APB Bridge DMA (Channel Setting) */
- /*
- * - CMD
- * ENBDIS : 0 (disable for now)
- * FININTSTS : 0 (clear finishing interrupt status)
- * FININTENB : 1 (enable finishing interrupt)
- * BURMOD : apb_req->burst_mode
- * ERRINTSTS : 0 (clear error interrupt status)
- * ERRINTENB : 1 (enable error interrupt)
- * SRCADRSEL : AHB/APB, driver auto-conf according to apb_req->src_index
- * DESADRSEL : AHB/APB, driver auto-conf according to apb_req->dst_index
- * SRCADR : apb_req->src_addr_ctrl
- * DESADR : apb_req->dst_addr_ctrl
- * REQSEL : apb_req->src_index (? a "req/gnt" device looks to be a src... check to use reqn of src or dst)
- * DATAWIDTH : apb_req->data_width
- */
- /*
- * - CMD
- * ENBDIS
- * FININTSTS
- * FININTENB
- * BURMOD
- * ERRINTSTS
- * ERRINTENB
- * SRCADR
- * DESADR
- * DATAWIDTH
- */
- channel_cmd = ((uint32_t)APBBR_DMA_FINTEN_MASK | APBBR_DMA_ERRINTEN_MASK |
- ((apb_req->burst_mode << APBBR_DMA_BURST_BIT) & APBBR_DMA_BURST_MASK) |
- ((apb_req->src_addr_ctrl << APBBR_DMA_SRCADDRINC_SHIFT) & APBBR_DMA_SRCADDRINC_MASK) |
- ((apb_req->dst_addr_ctrl << APBBR_DMA_DSTADDRINC_SHIFT) & APBBR_DMA_DSTADDRINC_MASK) |
- ((apb_req->data_width << APBBR_DMA_DATAWIDTH_SHIFT) & APBBR_DMA_DATAWIDTH_MASK));
- /*
- * - CMD
- * DSTADRSEL
- * DREQSEL (todo: this is FIA320 bit-mask, check AG101 bit-mask location)
- */
- if (apb_req->dst_index != APBBR_REQN_NONE)
- dst_bus_sel = APBBR_ADDRSEL_APB;
- else
- dst_bus_sel = APBBR_ADDRSEL_AHB;
- channel_cmd |= ((uint32_t)(APBBR_DMA_DSTADDRSEL_MASK &
- (dst_bus_sel << APBBR_DMA_DSTADDRSEL_BIT)) |
- (((uint32_t)apb_req->dst_index << APBBR_DMA_DREQSEL_SHIFT) & APBBR_DMA_DREQSEL_MASK));
- /*
- * - CMD
- * SRCADRSEL
- * SREQSEL (todo: this is FIA320 bit-mask, check AG101 bit-mask location)
- */
- if (apb_req->src_index != APBBR_REQN_NONE)
- src_bus_sel = APBBR_ADDRSEL_APB;
- else
- src_bus_sel = APBBR_ADDRSEL_AHB;
- channel_cmd |= ((uint32_t)(APBBR_DMA_SRCADDRSEL_MASK &
- (src_bus_sel << APBBR_DMA_SRCADDRSEL_BIT)) |
- (((uint32_t)apb_req->src_index << APBBR_DMA_SREQSEL_SHIFT) & APBBR_DMA_SREQSEL_MASK));
- /* - CMD outport */
- OUT32(channel_base + APBBR_DMA_CMD_OFFSET, channel_cmd);
- /* SRCADR and DESADR - not now */
- /* CYC - not now */
- _safe_exit:
- hal_global_int_ctl(core_intl);
- return status;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_channel_init
- *
- * DESCRIPTION
- *
- * This function performs the DMA channel HW initialization abstraction.
- * The real initialization task is dispatched according to the requested
- * DMA controller type (AHB DMAC or APB bridge DMA controller).
- *
- * INPUTS
- *
- * ch_req : Pointer to the DMA request descriptor structure
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful initialization,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- uint32_t _dmad_channel_init(const DMAD_CHANNEL_REQUEST_DESC *ch_req){
- uint32_t status;
- DMAD_TRACE(("_dmad_channel_init\r\n"));
- if (ch_req == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- if (ch_req->drq == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- /* Initialize DMA controller */
- if (ch_req->controller == DMAD_DMAC_AHB_CORE)
- status = _dmad_ahb_init(ch_req);
- else
- status = _dmad_apb_init(ch_req);
- /* Register HISR to perform deffered DMA ISR tasks */
- if (dmad.hisr_registered == 0){
- printf("_dmad_channel_init Register HISR\n");
- dmad.hisr.th.fn = _dmad_hisr;
- dmad.hisr.th.arg = &dmad.hisr;
- dmad.hisr.th.prio = CONFIG_DMAD_HISR_PRIORITY;
- dmad.hisr.th.ptos = &dmad_hisr_stack[DMAD_HISR_STACK_SIZE];
- dmad.hisr.th.stack_size = sizeof(dmad_hisr_stack);
- dmad.hisr.th.name = "DMA BH";
- status = hal_create_bh(&dmad.hisr);
- if (status != HAL_SUCCESS)
- return status;
-
- dmad.hisr_registered = 1;
- }
- return status;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_channel_enable
- *
- * DESCRIPTION
- *
- * This function is a abstraction routine to enable or disable a DMA
- * channel.
- *
- * INPUTS
- *
- * ch_req : Pointer to the DMA request descriptor structure
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful enable/disable,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- uint32_t _dmad_channel_enable(const DMAD_CHANNEL_REQUEST_DESC *ch_req, uint8_t enable){
- DMAD_DRQ *drq;
- if (ch_req == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- drq = (DMAD_DRQ *)ch_req->drq;
- if (drq == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- /* Enable/disable DMA channel */
- if (ch_req->controller == DMAD_DMAC_AHB_CORE){
- if (enable)
- SETB32(drq->channel_base + DMAC_CSR_OFFSET, DMAC_CSR_CH_EN_BIT);
- else
- CLRB32(drq->channel_base + DMAC_CSR_OFFSET, DMAC_CSR_CH_EN_BIT);
- }
- else { /* APB */
- if (enable)
- SETB32(drq->channel_base + APBBR_DMA_CMD_OFFSET, APBBR_DMA_CHEN_BIT);
- else
- CLRB32(drq->channel_base + APBBR_DMA_CMD_OFFSET, APBBR_DMA_CHEN_BIT);
- }
- return HAL_SUCCESS;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_alloc_drb
- *
- * DESCRIPTION
- *
- * This function is used to allocate a DRB (DMA request block) within a DMA
- * channel. DRB is used to queue all DMA submission requests for the
- * channel. Allocated DRB node is moved from the free-list to the ready-
- * list.
- *
- * INPUTS
- *
- * ch_req : (in) Pointer to the DMA request descriptor structure
- * drb : (out) Reference to the pointer of allocated DRB.
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful allocation,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- volatile int taskId=0;
- uint32_t _dmad_alloc_drb(DMAD_CHANNEL_REQUEST_DESC *ch_req, DMAD_DRB **drb){
- uint32_t status = HAL_SUCCESS;
- DMAD_DRQ *drq;
- uint32_t core_intl;
- if (ch_req == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- drq = (DMAD_DRQ *)ch_req->drq;
- if (drq == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- /* Obtain exclusive access to the drq from other tasks */
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR.
- * Lock DMA queue to prevent been updated by other tasks
- */
- status = hal_wait_for_mutex(&drq->drb_pool_mutex, HAL_SUSPEND);
- if (status != HAL_SUCCESS)
- return status;
- }
- /* Initialize drb ptr in case of fail allocation */
- *drb = HAL_NULL;
- #ifdef DMAD_POLLING
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- while (drq->fre_head == 0){
- /* Wait for free urbs. Sleep for 50 ms before polling again. */
- hal_global_int_ctl(core_intl);
- hal_sleep(50);
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- }
- #else
- status = hal_pend_semaphore(&drq->drb_sem, HAL_SUSPEND);
- if (status == HAL_ERR_TIMEOUT){
- status = HAL_ERR_NO_MEMORY;
- goto _safe_exit;
- }
- else if (status != HAL_SUCCESS){
- goto _safe_exit;
- }
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- #endif
- _dmad_detach_head(drq->drb_pool, &drq->fre_head, &drq->fre_tail, drb);
- hal_global_int_ctl(core_intl);
- _dmad_attach_tail(drq->drb_pool, &drq->rdy_head, &drq->rdy_tail, (*drb)->node);
- (*drb)->state = DMAD_DRB_STATE_READY;
- (*drb)->completion_sem = HAL_NULL;
- (*drb)->psp = HAL_NULL;
- (*drb)->rcp = HAL_NULL;
- if (ch_req->controller == DMAD_DMAC_AHB_CORE) {
- (*drb)->src_index = ch_req->ahbch_req.src_index;
- (*drb)->dst_index = ch_req->ahbch_req.dst_index;
- } else if (ch_req->controller == DMAD_DMAC_APB_CORE) {
- (*drb)->src_index = ch_req->apbch_req.src_index;
- (*drb)->dst_index = ch_req->apbch_req.dst_index;
- } else
- status = HAL_ERR_NOT_PRESENT;
- goto _safe_exit;
- _safe_exit:
- /* Release locking of this function from other tasks */
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR.
- * Unlock DMA queue to allow its access from other tasks
- */
- hal_release_mutex(&drq->drb_pool_mutex);
- }
- return status;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_free_drb
- *
- * DESCRIPTION
- *
- * This function is used to free a DRB (DMA request block) within a DMA
- * channel. DRB is used to queue all DMA submission requests for the
- * channel. Freed DRB node is moved from the ready-list to the free-
- * list.
- *
- * INPUTS
- *
- * ch_req : (in) Pointer to the DMA request descriptor structure
- * drb : (in) Pointer of a DRB struct to be freed.
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful freeing,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- uint32_t _dmad_free_drb(DMAD_CHANNEL_REQUEST_DESC *ch_req, DMAD_DRB *drb){
- uint32_t status = HAL_SUCCESS;
- DMAD_DRQ *drq;
- uint32_t core_intl;
- if (ch_req == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- drq = (DMAD_DRQ *)ch_req->drq;
- if (drq == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- /* Obtain exclusive access to the drq from other tasks */
- if (hal_current() != HAL_NULL){
- /* Suspending is only valid to the current task -- no need to lock if invoked from HISR. */
- status = hal_wait_for_mutex(&drq->drb_pool_mutex, HAL_SUSPEND);
- if (status != HAL_SUCCESS)
- return status;
- }
- /* Following code require _safe_exit return path */
- if ((drq->rdy_head == 0) || (drb->node == 0) ||
- (drb->node >= DMAD_DRB_POOL_SIZE)){
- DMAD_TRACE(("Ready-queue is empty or invalid node!\r\n"));
- /* Unlock DMA queue to allow its access from other tasks */
- status = HAL_ERR_INVALID_ENTRY;
- goto _safe_exit;
- }
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- _dmad_detach_node(drq->drb_pool, &drq->rdy_head, &drq->rdy_tail, drb->node);
- _dmad_attach_tail(drq->drb_pool, &drq->fre_head, &drq->fre_tail, drb->node);
- hal_global_int_ctl(core_intl);
- drb->state = DMAD_DRB_STATE_FREE;
- drb->completion_sem = HAL_NULL;
- _safe_exit:
- /* Release locking of this function from other tasks */
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR
- * Unlock DMA queue to allow its access from other tasks
- */
- hal_release_mutex(&drq->drb_pool_mutex);
- }
- return status;
- }
- int dmad_apb_config_dir(const DMAD_CHANNEL_REQUEST_DESC *ch_req, uint8_t dir)
- {
- uint32_t status = HAL_SUCCESS;
- DMAD_DRQ *drq = (DMAD_DRQ *)ch_req->drq;
- DMAD_APBCH_REQUEST *apb_req = (DMAD_APBCH_REQUEST *)(&ch_req->apbch_req);
- uint32_t channel_base = drq->channel_base;
- uint32_t channel_cmd = 0;
- uint32_t dst_bus_sel;
- uint32_t src_bus_sel;
- channel_cmd = IN32(channel_base + APBBR_DMA_CMD_OFFSET);
- channel_cmd &= ~(uint32_t)
- (APBBR_DMA_SRCADDRINC_MASK | APBBR_DMA_DSTADDRINC_MASK |
- APBBR_DMA_DSTADDRSEL_MASK | APBBR_DMA_DREQSEL_MASK |
- APBBR_DMA_SRCADDRSEL_MASK | APBBR_DMA_SREQSEL_MASK);
- if( dir == 0){
- channel_cmd = ((uint32_t)APBBR_DMA_FINTEN_MASK | APBBR_DMA_ERRINTEN_MASK |
- ((apb_req->src_addr_ctrl << APBBR_DMA_SRCADDRINC_SHIFT) & APBBR_DMA_SRCADDRINC_MASK) |
- ((apb_req->dst_addr_ctrl << APBBR_DMA_DSTADDRINC_SHIFT) & APBBR_DMA_DSTADDRINC_MASK));
- /*
- * - CMD
- * DSTADRSEL
- * DREQSEL (todo: this is FIA320 bit-mask, check AG101 bit-mask location)
- */
- if (apb_req->dst_index != APBBR_REQN_NONE)
- dst_bus_sel = APBBR_ADDRSEL_APB;
- else
- dst_bus_sel = APBBR_ADDRSEL_AHB;
- channel_cmd |= ((uint32_t)(APBBR_DMA_DSTADDRSEL_MASK &
- (dst_bus_sel << APBBR_DMA_DSTADDRSEL_BIT)) |
- (((uint32_t)apb_req->dst_index << APBBR_DMA_DREQSEL_SHIFT) & APBBR_DMA_DREQSEL_MASK));
- /*
- * - CMD
- * SRCADRSEL
- * SREQSEL (todo: this is FIA320 bit-mask, check AG101 bit-mask location)
- */
- if (apb_req->src_index != APBBR_REQN_NONE)
- src_bus_sel = APBBR_ADDRSEL_APB;
- else
- src_bus_sel = APBBR_ADDRSEL_AHB;
- channel_cmd |= ((uint32_t)(APBBR_DMA_SRCADDRSEL_MASK &
- (src_bus_sel << APBBR_DMA_SRCADDRSEL_BIT)) |
- (((uint32_t)apb_req->src_index << APBBR_DMA_SREQSEL_SHIFT) & APBBR_DMA_SREQSEL_MASK));
- /* - CMD outport */
- OUT32(channel_base + APBBR_DMA_CMD_OFFSET, channel_cmd);
- } else {
- channel_cmd = ((uint32_t)APBBR_DMA_FINTEN_MASK | APBBR_DMA_ERRINTEN_MASK |
- ((apb_req->dst_addr_ctrl << APBBR_DMA_SRCADDRINC_SHIFT) & APBBR_DMA_SRCADDRINC_MASK) |
- ((apb_req->src_addr_ctrl << APBBR_DMA_DSTADDRINC_SHIFT) & APBBR_DMA_DSTADDRINC_MASK));
- /*
- * - CMD
- * DSTADRSEL
- * DREQSEL (todo: this is FIA320 bit-mask, check AG101 bit-mask location)
- */
- if (apb_req->src_index != APBBR_REQN_NONE)
- src_bus_sel = APBBR_ADDRSEL_APB;
- else
- src_bus_sel = APBBR_ADDRSEL_AHB;
- channel_cmd |= ((uint32_t)(APBBR_DMA_DSTADDRSEL_MASK &
- (src_bus_sel << APBBR_DMA_DSTADDRSEL_BIT)) |
- (((uint32_t)apb_req->src_index << APBBR_DMA_DREQSEL_SHIFT) & APBBR_DMA_DREQSEL_MASK));
- /*
- * - CMD
- * SRCADRSEL
- * SREQSEL (todo: this is FIA320 bit-mask, check AG101 bit-mask location)
- */
- if (apb_req->dst_index != APBBR_REQN_NONE)
- dst_bus_sel = APBBR_ADDRSEL_APB;
- else
- dst_bus_sel = APBBR_ADDRSEL_AHB;
- channel_cmd |= ((uint32_t)(APBBR_DMA_SRCADDRSEL_MASK &
- (dst_bus_sel << APBBR_DMA_SRCADDRSEL_BIT)) |
- (((uint32_t)apb_req->dst_index << APBBR_DMA_SREQSEL_SHIFT) & APBBR_DMA_SREQSEL_MASK));
- /* - CMD outport */
- OUT32(channel_base + APBBR_DMA_CMD_OFFSET, channel_cmd);
- }
- return status;
- }
- void set_drq_transfer_size(DMAD_CHANNEL_REQUEST_DESC *ch_req, DMAD_DRB *drb)
- {
- int data_width = -1;
- if (ch_req->controller == DMAD_DMAC_AHB_CORE) {
- /* AHB DMA */
- DMAD_AHBCH_REQUEST *ahb_req = (DMAD_AHBCH_REQUEST *)(&ch_req->ahbch_req);
- if (drb->src_index == DMAC_REQN_NONE && drb->src_index == DMAC_REQN_NONE)
- data_width = 0;
- else {
- if (drb->src_index != DMAC_REQN_NONE)
- data_width = 2 - ahb_req->src_width;
- else if (drb->dst_index != DMAC_REQN_NONE)
- data_width = 2 - ahb_req->dst_width;
- }
- } else {
- /* APB DMA */
- DMAD_APBCH_REQUEST *apb_req = (DMAD_APBCH_REQUEST *)(&ch_req->apbch_req);
- data_width = 2 - apb_req->data_width;
- }
- if (data_width < 0)
- KASSERT(1);
- drb->transfer_size = drb->req_size << data_width;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_submit_request
- *
- * DESCRIPTION
- *
- * This function is used to submit a DRB (DMA request block) to a DMA
- * channel. DRB is used to queue all DMA submission requests for the
- * channel. Submitted DRB node is moved from the ready-list to the
- * submitted-list. DMA kick-off is performed automatically if the DMA
- * transaction has not started. When the DRB is completed, it will be
- * removed from the submittied-list to the free-list in the DMA ISR.
- *
- * INPUTS
- *
- * ch_req : (in) Pointer to the DMA request descriptor structure
- * drb : (in) Pointer of a DRB struct to be submitted.
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful submission,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- uint32_t _dmad_submit_request(DMAD_CHANNEL_REQUEST_DESC *ch_req, DMAD_DRB *drb){
- uint32_t status = HAL_SUCCESS;
- DMAD_DRQ *drq;
- uint32_t core_intl;
- if (ch_req == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- drq = (DMAD_DRQ *)ch_req->drq;
- if (drq == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- /* Obtain exclusive access to the drq from other tasks */
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR
- * Lock DMA queue to prevent been updated by other tasks
- */
- status = hal_wait_for_mutex(&drq->drb_pool_mutex, HAL_SUSPEND);
- if (status != HAL_SUCCESS)
- return status;
- }
- /* Following code require _safe_exit return path */
- if ((drq->rdy_head == 0) || (drb->node == 0) || (drb->node >= DMAD_DRB_POOL_SIZE)){
- status = HAL_ERR_INVALID_ENTRY;
- goto _safe_exit;
- }
- _dmad_detach_node(drq->drb_pool, &drq->rdy_head, &drq->rdy_tail, drb->node);
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- /*
- * writeback d-cache if necessary
- *
- * Note: Here we take the assumption that, after writeback, the memory
- * contents is in physical ram and valid for for dma transfer.
- * Hence, we only need to do writeback at the beginning of the drb
- * submission, and ignore the writeback before kicking off every
- * drb in isr.
- *
- * Place writeback code before interrupt-disable to shorten the
- * disable time. This might generate a penalty of cache-miss
- * if the writeback routine also invalidated the cache contents.
- */
- set_drq_transfer_size(ch_req, drb);
- #if ( defined(CONFIG_CPU_DCACHE_ENABLE) && !defined(CONFIG_CPU_DCACHE_WRITETHROUGH) )
- /* source is memory */
- //if (drq->dc_writeback != HAL_NULL && drb->src_index == DMAC_REQN_NONE)
- if ( (unsigned long)drb->src_addr >= NTC0_BONDER_START && (unsigned long)drb->src_addr < NTC0_BONDER_END )//JUNIOR@2013/05/16
- drq->dc_writeback((unsigned long)(drb->src_addr),(unsigned long)(drb->src_addr) + (unsigned long)(drb->transfer_size));
- #endif
- /* Check if submission is performed to an empty queue */
- if (drq->sbt_head == 0){
- _dmad_attach_tail(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, drb->node);
- drb->state = DMAD_DRB_STATE_SUBMITTED;
- hal_global_int_ctl(core_intl);
- /* pre-submission-programming */
- if (drb->psp)
- drb->psp(drb->data);
- /* DMA is not running, so kick off transmission */
- if (ch_req->controller == DMAD_DMAC_AHB_CORE){ /* AHB */
- /* Source and destination address */
- OUT32(drq->channel_base + DMAC_SRC_ADDR_OFFSET, drb->src_addr);
- OUT32(drq->channel_base + DMAC_DST_ADDR_OFFSET, drb->dst_addr);
- /* Transfer size (in units of source width) */
- OUT32(drq->channel_base + DMAC_SIZE_OFFSET, drb->req_size);
- /* Enable DMA channel (Kick off transmission when client enable it's transfer state) */
- SETB32(drq->channel_base + DMAC_CSR_OFFSET, DMAC_CSR_CH_EN_BIT);
- }
- else { /* APB */
- /* Source and destination address */
- OUT32(drq->channel_base + APBBR_DMA_SAD_OFFSET, drb->src_addr);
- OUT32(drq->channel_base + APBBR_DMA_DAD_OFFSET, drb->dst_addr);
- /* Transfer size (in units of source width) */
- OUT32(drq->channel_base + APBBR_DMA_CYC_OFFSET, drb->req_size & APBBR_DMA_CYC_MASK);
- /* Enable DMA channel (Kick off transmission when client enable it's transfer state) */
- SETB32(drq->channel_base + APBBR_DMA_CMD_OFFSET, APBBR_DMA_CHEN_BIT);
- }
- }
- else {
- /* DMA is already running, so only queue DRB to the end of the list */
- _dmad_attach_tail(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, drb->node);
- drb->state = DMAD_DRB_STATE_SUBMITTED;
- hal_global_int_ctl(core_intl);
- }
- _safe_exit:
- /* Release locking of this function from other tasks */
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR
- * Unlock DMA queue to allow its access from other tasks
- */
- hal_release_mutex(&drq->drb_pool_mutex);
- }
- return status;
- }
- /*****************************************************************************
- * FUNCTION
- *
- * _dmad_cancel_request
- *
- * DESCRIPTION
- *
- * This function is used to cancel a submitted DRB (DMA request block)
- * of a DMA channel. DRB is used to queue all DMA submission requests for
- * the channel. Submitted DRB node is moved from the ready-list to the
- * submitted-list. Cancellation will fail if the DRB has already been
- * kicked off and is waiting to be completed.
- *
- * INPUTS
- *
- * ch_req : (in) Pointer to the DMA request descriptor structure
- * drb : (in) Pointer of a DRB struct to be cancelled.
- *
- * OUTPUTS
- *
- * uint32_t : Returns HAL_SUCCESS if successful cancellation,
- * else positive value is DMAD-specific error code,
- * else negative value is NU system error code.
- *
- ****************************************************************************/
- uint32_t _dmad_cancel_request(DMAD_CHANNEL_REQUEST_DESC *ch_req, DMAD_DRB *drb){
- DMAD_DRQ *drq;;
- if (ch_req == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- drq = (DMAD_DRQ *)ch_req->drq;
- if (drq == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- if (drq->sbt_head == 0)
- return HAL_ERR_INVALID_ENTRY;
- if ((drb->node == 0) || (drb->node >= DMAD_DRB_POOL_SIZE))
- return HAL_ERR_INVALID_ENTRY;
- if (drb->completion_sem != HAL_NULL)
- hal_destroy_semaphore(drb->completion_sem);
- // NDS_DCache_Enable();
- return HAL_ERR_UNAVAILABLE;
- }
- uint32_t _dmad_wait(DMAD_CHANNEL_REQUEST_DESC *ch_req){
- uint32_t status = HAL_SUCCESS;
- DMAD_DRQ *drq;
- uint32_t core_intl;
- if (ch_req == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- drq = (DMAD_DRQ *)ch_req->drq;
- if (drq == HAL_NULL)
- return HAL_ERR_INVALID_POINTER;
- /* Obtain exclusive access to the drq from other tasks */
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR.
- * Lock DMA queue to prevent been updated by other tasks
- */
- status = hal_wait_for_mutex(&drq->drb_pool_mutex, HAL_SUSPEND);
- if (status != HAL_SUCCESS)
- return status;
- }
- #ifdef DMAD_POLLING
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- while (drq->sbt_head != 0){
- hal_global_int_ctl(core_intl);
- hal_sleep(50);
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- }
- #else
- status = hal_pend_semaphore(&drq->drb_sem, 300);
- if (status == HAL_ERR_TIMEOUT){
- status = HAL_ERR_NO_MEMORY;
- goto _safe_exit;
- }
- else if (status != HAL_SUCCESS){
- goto _safe_exit;
- }
- core_intl = hal_global_int_ctl(HAL_DISABLE_INTERRUPTS);
- #endif
- hal_global_int_ctl(core_intl);
- goto _safe_exit;
- _safe_exit:
- /* Release locking of this function from other tasks */
- if (hal_current() != HAL_NULL){
- /*
- * Suspending is only valid to the current task -- no need to lock if invoked from HISR.
- * Unlock DMA queue to allow its access from other tasks
- */
- hal_release_mutex(&drq->drb_pool_mutex);
- }
- return status;
- }
|