diff options
Diffstat (limited to 'arch/arm/plat-mxc/sdma/iapi/src')
-rw-r--r-- | arch/arm/plat-mxc/sdma/iapi/src/Makefile | 18 | ||||
-rw-r--r-- | arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c | 110 | ||||
-rw-r--r-- | arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c | 2750 | ||||
-rw-r--r-- | arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c | 151 | ||||
-rw-r--r-- | arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c | 503 | ||||
-rw-r--r-- | arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c | 644 | ||||
-rw-r--r-- | arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c | 52 | ||||
-rw-r--r-- | arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c | 64 |
8 files changed, 4292 insertions, 0 deletions
diff --git a/arch/arm/plat-mxc/sdma/iapi/src/Makefile b/arch/arm/plat-mxc/sdma/iapi/src/Makefile new file mode 100644 index 000000000000..4c112bf22384 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/Makefile @@ -0,0 +1,18 @@ +# +# Makefile for I.API sources. +# +ifneq ($(KBUILD_SRC),) +ccflags-y += -I$(KBUILD_SRC)/arch/arm/plat-mxc/sdma/iapi/include \ + -I$(KBUILD_SRC)/include/linux \ + -DMCU -DOS=LINUX \ + -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \ + -DENDIANNESS=L_I_T_T_L_E_ENDIAN +else +ccflags-y += -Iarch/arm/plat-mxc/sdma/iapi/include \ + -Iinclude/linux \ + -DMCU -DOS=LINUX \ + -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \ + -DENDIANNESS=L_I_T_T_L_E_ENDIAN +endif + +obj-y += iapiLow.o iapiLowMcu.o iapiMiddle.o iapiMiddleMcu.o iapiHigh.o iapiDefaults.o iapiOS.o diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c new file mode 100644 index 000000000000..d7e75b543d8d --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c @@ -0,0 +1,110 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiDefaults.c + * + * $Id iapiDefaults.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * + * Usage: + * + * Files: + * + * +* / + * + * $Log iapiDefaults.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + ******************************************************************************/ +#include "iapiDefaults.h" + +/* **************************************************************************** + * Global Variable Section + ******************************************************************************/ + +/** + * @brief System Call-back ISRs Table + */ +void (*callbackIsrTable[CH_NUM]) (channelDescriptor *cd_p, void *arg); + +/** + * @brief User registered pointers table + */ +void *userArgTable[CH_NUM]; + +/** + * @brief Pointer to the first CCB in the CCB array + */ +channelControlBlock *iapi_CCBHead; + +/**Default channel description. + * + * Initialization values are:\n + * - channelNumber = 0 + * - bufferDescNumber = 1 + * - bufferSize = 8 + * - blocking = 0 + * - callbackSynch = DEFAULT_POLL + * - ownership = CD_DEFAULT_OWNERSHIP + * - priority = 1 + * - trust = TRUE + * - useDataSize = 0 + * - dataSize = 0 + * - forceClose = 0 + * - scriptId = 0 + * - watermarkLevel = 0 + * - eventMask1 = 0 + * - eventMask2 = 0 + * - peripheralAddr = NULL + * - callbackISR_ptr = NULL + * - iapi_channelControlBlock = NULL + */ +channelDescriptor iapi_ChannelDefaults = { 0, 1, 8, 0, DEFAULT_POLL, + CD_DEFAULT_OWNERSHIP, 1, TRUE, 0, 0, 0, 0, + 0, 0x00, 0x00, 0x00, NULL, NULL +}; + +/** + * Integrated error management + */ +unsigned int iapi_errno; +volatile unsigned long iapi_SDMAIntr; + +/* Default config register. + * Initialization values are: + * dspdma used + * Real-Time Debug pins disabled + * AHB freq / core freq = 2 + * dynamic context switch +*/ +configs_data iapi_ConfigDefaults = { 1, 0, 0, 3 }; + +#ifdef SDMA_SKYE +/* Default sdma State : UNDEF + *possible value are UNDEF, OPEN, LOCK, CLOSED, CLOSE_LOCK + */ + +sdmaState iapi_SdmaState = UNDEF; +#endif + +/* ***************************************************************************/ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c new file mode 100644 index 000000000000..f14d19d1bd60 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c @@ -0,0 +1,2750 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiHigh.c + * + * $Id iapiHigh.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the HIGH level functions of the I.API. + * + * + * / + * + * $Log iapiHigh.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include <stdarg.h> +#include <string.h> + +#include "epm.h" +#include "iapi.h" + +/* **************************************************************************** + * External Reference Section (for compatibility with already developed code) + *****************************************************************************/ +static void iapi_read_ipcv2_callback(struct iapi_channelDescriptor *cd_p, + void *data); + +/* **************************************************************************** + * Global Variable Section + *****************************************************************************/ +#define MAX_CHANNEL 32 + +static dataNodeDescriptor *dnd_read_control_struct[MAX_CHANNEL]; + +/* MASK to get Nullify all the bits of Status in Data Node descriptor apart from L, E and D*/ + +#define GET_LED_MASK 0xE0 + +/*Table defines mapping of Data Node Descriptor to Buffer Descriptor status*/ + +static unsigned char dnd_2_bd_status[] = { + 0x85, /*00 L = 0, E = 0, D = 0 */ + 0x00, /*01 */ + 0x00, /*02 */ + 0x00, /*03 */ + 0x00, /*04 */ + 0x00, /*05 */ + 0x00, /*06 */ + 0x00, /*07 */ + 0x00, /*08 */ + 0x00, /*09 */ + 0x00, /*0A */ + 0x00, /*0B */ + 0x00, /*0C */ + 0x00, /*0D */ + 0x00, /*0E */ + 0x00, /*0F */ + 0x00, /*10 */ + 0x00, /*11 */ + 0x00, /*12 */ + 0x00, /*13 */ + 0x00, /*14 */ + 0x00, /*15 */ + 0x00, /*16 */ + 0x00, /*17 */ + 0x00, /*18 */ + 0x00, /*19 */ + 0x00, /*1A */ + 0x00, /*1B */ + 0x00, /*1C */ + 0x00, /*1D */ + 0x00, /*1E */ + 0x00, /*1F */ + 0x84, /*20 L = 0, E = 0, D = 1 */ + 0x00, /*21 */ + 0x00, /*22 */ + 0x00, /*23 */ + 0x00, /*24 */ + 0x00, /*25 */ + 0x00, /*26 */ + 0x00, /*27 */ + 0x00, /*28 */ + 0x00, /*29 */ + 0x00, /*2A */ + 0x00, /*2B */ + 0x00, /*2C */ + 0x00, /*2D */ + 0x00, /*2E */ + 0x00, /*2F */ + 0x00, /*30 */ + 0x00, /*31 */ + 0x00, /*32 */ + 0x00, /*33 */ + 0x00, /*34 */ + 0x00, /*35 */ + 0x00, /*36 */ + 0x00, /*37 */ + 0x00, /*38 */ + 0x00, /*39 */ + 0x00, /*3A */ + 0x00, /*3B */ + 0x00, /*3C */ + 0x00, /*3D */ + 0x00, /*3E */ + 0x00, /*3F */ + 0xAB, /*40 L = 0, E = 1, D = 0 */ + 0x00, /*41 */ + 0x00, /*42 */ + 0x00, /*43 */ + 0x00, /*44 */ + 0x00, /*45 */ + 0x00, /*46 */ + 0x00, /*47 */ + 0x00, /*48 */ + 0x00, /*49 */ + 0x00, /*4A */ + 0x00, /*4B */ + 0x00, /*4C */ + 0x00, /*4D */ + 0x00, /*4E */ + 0x00, /*4F */ + 0x00, /*50 */ + 0x00, /*51 */ + 0x00, /*52 */ + 0x00, /*53 */ + 0x00, /*54 */ + 0x00, /*55 */ + 0x00, /*56 */ + 0x00, /*57 */ + 0x00, /*58 */ + 0x00, /*59 */ + 0x00, /*5A */ + 0x00, /*5B */ + 0x00, /*5C */ + 0x00, /*5D */ + 0x00, /*5E */ + 0x00, /*5F */ + 0xAA, /*60 L = 0, E = 1, D = 1 */ + 0x00, /*61 */ + 0x00, /*62 */ + 0x00, /*63 */ + 0x00, /*64 */ + 0x00, /*65 */ + 0x00, /*66 */ + 0x00, /*67 */ + 0x00, /*68 */ + 0x00, /*69 */ + 0x00, /*6A */ + 0x00, /*6B */ + 0x00, /*6C */ + 0x00, /*6D */ + 0x00, /*6E */ + 0x00, /*6F */ + 0x00, /*70 */ + 0x00, /*71 */ + 0x00, /*72 */ + 0x00, /*73 */ + 0x00, /*74 */ + 0x00, /*75 */ + 0x00, /*76 */ + 0x00, /*77 */ + 0x00, /*78 */ + 0x00, /*79 */ + 0x00, /*7A */ + 0x00, /*7B */ + 0x00, /*7C */ + 0x00, /*7D */ + 0x00, /*7E */ + 0x00, /*7F */ + 0xC5, /*80 L = 1, E = 0, D = 0 */ + 0x00, /*81 */ + 0x00, /*82 */ + 0x00, /*83 */ + 0x00, /*84 */ + 0x00, /*85 */ + 0x00, /*86 */ + 0x00, /*87 */ + 0x00, /*88 */ + 0x00, /*89 */ + 0x00, /*8A */ + 0x00, /*8B */ + 0x00, /*8C */ + 0x00, /*8D */ + 0x00, /*8E */ + 0x00, /*8F */ + 0x00, /*90 */ + 0x00, /*91 */ + 0x00, /*92 */ + 0x00, /*93 */ + 0x00, /*94 */ + 0x00, /*95 */ + 0x00, /*96 */ + 0x00, /*97 */ + 0x00, /*98 */ + 0x00, /*99 */ + 0x00, /*9A */ + 0x00, /*9B */ + 0x00, /*9C */ + 0x00, /*9D */ + 0x00, /*9E */ + 0x00, /*9F */ + 0xC4, /*A0 L = 1, E = 0, D = 1 */ + 0x00, /*A1 */ + 0x00, /*A2 */ + 0x00, /*A3 */ + 0x00, /*A4 */ + 0x00, /*A5 */ + 0x00, /*A6 */ + 0x00, /*A7 */ + 0x00, /*A8 */ + 0x00, /*A9 */ + 0x00, /*AA*/ 0x00, /*AB*/ 0x00, /*AC*/ 0x00, /*AD*/ 0x00, /*AE*/ 0x00, /*AF*/ 0x00, /*B0 */ + 0x00, /*B1 */ + 0x00, /*B2 */ + 0x00, /*B3 */ + 0x00, /*B4 */ + 0x00, /*B5 */ + 0x00, /*B6 */ + 0x00, /*B7 */ + 0x00, /*B8 */ + 0x00, /*B9 */ + 0x00, /*BA*/ 0x00, /*BB*/ 0x00, /*BC*/ 0x00, /*BD*/ 0x00, /*BE*/ 0x00, /*BF*/ 0xEB, /*C0 L = 1, E = 1, D = 0 */ + 0x00, /*C1 */ + 0x00, /*C2 */ + 0x00, /*C3 */ + 0x00, /*C4 */ + 0x00, /*C5 */ + 0x00, /*C6 */ + 0x00, /*C7 */ + 0x00, /*C8 */ + 0x00, /*C9 */ + 0x00, /*CA*/ 0x00, /*CB*/ 0x00, /*CC*/ 0x00, /*CD*/ 0x00, /*CE*/ 0x00, /*CF*/ 0x00, /*D0 */ + 0x00, /*D1 */ + 0x00, /*D2 */ + 0x00, /*D3 */ + 0x00, /*D4 */ + 0x00, /*D5 */ + 0x00, /*D6 */ + 0x00, /*D7 */ + 0x00, /*D8 */ + 0x00, /*D9 */ + 0x00, /*DA*/ 0x00, /*DB*/ 0x00, /*DC*/ 0x00, /*DD*/ 0x00, /*DE*/ 0x00, /*DF*/ 0xEA, /*E0 L = 1, E = 1, D = 1 */ + 0x00, /*E1 */ + 0x00, /*E2 */ + 0x00, /*E3 */ + 0x00, /*E4 */ + 0x00, /*E5 */ + 0x00, /*E6 */ + 0x00, /*E7 */ + 0x00, /*E8 */ + 0x00, /*E9 */ + 0x00, /*EA*/ 0x00, /*EB*/ 0x00, /*EC*/ 0x00, /*ED*/ 0x00, /*EE*/ 0x00, /*EF*/ 0x00, /*F0 */ + 0x00, /*F1 */ + 0x00, /*F2 */ + 0x00, /*F3 */ + 0x00, /*F4 */ + 0x00, /*F5 */ + 0x00, /*F6 */ + 0x00, /*F7 */ + 0x00, /*F8 */ + 0x00, /*F9 */ + 0x00, /*FA*/ + 0x00, /*FB*/ 0x00, /*FC*/ 0x00, /*FD*/ 0x00, /*FE*/ 0x00 /*FF*/ +}; + +/* **************************************************************************** + * Function Section + *****************************************************************************/ + +/* ***************************************************************************/ +/**Opens an SDMA channel to be used by the library. + * + * <b>Algorithm:</b>\n + * + * - Check if initialization is necessary. + * - Check that user initialized OS dependant functions. + * - Test validity of input parameters + * - Check whole channel control block data structure + * - Finish initializations (tables with default values) + * - Initialize channel 0 is dedicated to communications with SDMA + * - Check channel control block definition + * - if the channel descriptor is not initialized, initialize it with + * the default value + * - If buffer descriptor already allocated, exit with iapi_errno filled + * complete the lowest bits with the number of 'D' bits set + * - Buffer Descriptors allocation + * - Channel's configuration properties (mcu side only) + * - read/write direction => enable/disable channel setting + * + * @param *cd_p -If channelNumber is 0, it is pointer to channel descriptor for the channnel 0 to be opened and + * has default values. + * For other channels,this function should be called after channel 0 has been opened, and it is channel descriptor for + * channel 0.Must be allocated. + * @param channelNumber channel to be opened + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : close failed, return negated value of iapi_errno + */ +int iapi_Open(channelDescriptor *cd_p, unsigned char channelNumber) +{ + channelControlBlock *ccb_p; + channelControlBlock *local_ccb_p; + channelDescriptor *local_cd_p; + bufferDescriptor *bd_p; + unsigned char index = 0; + int result = IAPI_SUCCESS; +#ifdef MCU + volatile unsigned long *channelPriorityMatx; +#endif /* MCU */ + + /* + * 1. Check if initialization is necessary + */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED | + IAPI_ERR_CH_AVAILABLE | channelNumber; + iapi_errno = result; + return -result; + } + + /* Verify these functions every time */ + if ((iapi_GetChannel == NULL) || (iapi_ReleaseChannel == NULL)) { + result = IAPI_ERR_NO_OS_FN | channelNumber; + iapi_errno = result; + return -result; + } + + /* Try to aquire channel */ + if (iapi_GetChannel(channelNumber) != 0) { + result = IAPI_ERR_CH_IN_USE | channelNumber; + iapi_errno = result; + return -result; + } + + if (channelNumber == 0 && cd_p->ccb_ptr == NULL) { + /* Verify that the user initialized all OS dependant functions required + * by the library. + */ + if ((iapi_Malloc == NULL) || (iapi_Free == NULL) + || (iapi_Virt2Phys == NULL) || (iapi_Phys2Virt == NULL) + || (iapi_GotoSleep == NULL) || (iapi_WakeUp == NULL) + || (iapi_InitSleep == NULL) || (iapi_memset == NULL) + || (iapi_memcpy == NULL)) { + result = IAPI_ERR_NO_OS_FN | channelNumber; + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + /* Whole channel control block data structure */ + ccb_p = (channelControlBlock *) + MALLOC(CH_NUM * sizeof(channelControlBlock), SDMA_IRAM); + if (ccb_p == NULL) { + result = IAPI_ERR_CCB_ALLOC_FAILED | + IAPI_ERR_CH_AVAILABLE | channelNumber; + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + /* Zero-out the CCB structures array just allocated */ + iapi_memset(ccb_p, 0x00, CH_NUM * sizeof(channelControlBlock)); + /* Save the address of the CCB structures array */ + iapi_CCBHead = ccb_p; + + cd_p->ccb_ptr = (struct iapi_channelControlBlock *)ccb_p; + ccb_p->channelDescriptor = cd_p; +#ifdef MCU + /* finish initializations */ + iapi_InitChannelTables(); +#endif /* MCU */ + /* Channel 0 is dedicated to communications with SDMA */ + cd_p->ownership = ((DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + cd_p->bufferDescNumber = 1; + } + + /* + * 2. Check channel control block + */ + ccb_p = cd_p->ccb_ptr; + if (ccb_p == NULL) { + result = + IAPI_ERR_NO_CCB_DEFINED | IAPI_ERR_CH_AVAILABLE | + channelNumber; + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + + /* Control block & Descriptor associated with the channel being worked on */ + local_ccb_p = &ccb_p[channelNumber]; + local_cd_p = ccb_p[channelNumber].channelDescriptor; + + /* If the channel is not initialized, initialize it with the default value */ + if (local_cd_p == NULL) { + result = iapi_AllocChannelDesc(&local_cd_p, channelNumber); + if (result != IAPI_SUCCESS) { + iapi_ReleaseChannel(channelNumber); + /* is allready negated from iapi_AllocChannelDesc */ + return result; + } + + local_cd_p->ccb_ptr = + (struct iapi_channelControlBlock *)local_ccb_p; + local_ccb_p->channelDescriptor = local_cd_p; + } + + /* + * 3. If buffer descriptor already allocated, exit with iapi_errno filled + */ + if (local_ccb_p->baseBDptr != NULL) { + bd_p = + (bufferDescriptor *) iapi_Phys2Virt(local_ccb_p->baseBDptr); + result = IAPI_ERR_BD_ALLOCATED; + for (index = 1; index < local_cd_p->bufferDescNumber; index++) { + if ((bd_p->mode.status & BD_DONE) == BD_DONE) { + /* complete the lowest bits with the number of 'D' bits set */ + result++; + } + bd_p++; + } + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + + /* + * 4. Buffer Descriptors allocation + */ + iapi_InitializeMemory(local_ccb_p); + +#ifdef MCU + /* + * 5. Channel's configuration properties (mcu side only) + */ + iapi_ChannelConfig(channelNumber, + (local_cd_p->ownership >> CH_OWNSHP_OFFSET_EVT) & + 1UL, + (local_cd_p->ownership >> CH_OWNSHP_OFFSET_MCU) & + 1UL, + (local_cd_p->ownership >> CH_OWNSHP_OFFSET_DSP) & + 1UL); +#endif /* MCU */ + + /* Setting interrupt handling */ + iapi_ChangeCallbackISR(local_cd_p, local_cd_p->callbackISR_ptr); + + /* Call initialization fn for polling synch on this channel */ + INIT_SLEEP(channelNumber); + + /* No user arg pointer yet */ + userArgTable[cd_p->channelNumber] = NULL; + + /* + * 6. read/write direction => enable/disable channel + */ +#ifdef MCU + channelPriorityMatx = &SDMA_CHNPRI_0; + channelPriorityMatx[channelNumber] = 1; +#endif /* MCU */ + + local_ccb_p->status.openedInit = TRUE; + iapi_ReleaseChannel(channelNumber); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/** Attempts to read nbyte from the data buffer descriptor associated with the + * channel channelNumber, into the user's data buffer pointed to by buf. + * + * <b>Algorithm:</b>\n + * - Check data structures are properly initialized: + * - Channel descriptor validity + * - Control block & Descriptor associated with the channel being worked on + * - Check initialization has been done for trusted channels + * - If transfer data size is used, check validity of combination transfer + * size/requested bytes + * - Set the 'D' done bits on all buffer descriptors + * - Starting of the channel + * - Synchronization mechanism handling: + * - for callback: just exit function + * - for polling: call the synchronization function then read data from + * buffer until either nbyte parameter is reached or all buffer descriptors + * have been processed. + * + * <b>Notes:</b>\n + * 1) Virtual DMA SDMA channels are unidirectional, an iapi_Read authorized + * on a channel means that we are expecting to receive from the SDMA. The + * meaning of an interrupt received from the SDMA is therefore that the + * data has been copied from the SDMA to the host's data buffers and is + * already passed on upper layers of the application.\n + * + * @param *cd_p chanenl descriptor for the channel to read from + * @param *buf buffer to receive the data + * @param nbyte number of bytes to read from channel + * + * @return + * - number of bytes read + * - -iapi_errno : in case of failure return negated value of iapi_errno + */ +int iapi_Read(channelDescriptor *cd_p, void *buf, unsigned short nbyte) +{ + int index = 0; + int readBytes; + int toRead; + int result = IAPI_SUCCESS; + unsigned int copyFinished; + int bufsize; + bufferDescriptor *bd_p; + channelControlBlock *ccb_p; + unsigned char *local_buf; + unsigned char chNum; + unsigned char div; + + iapi_errno = IAPI_ERR_NO_ERROR; + + /* + * 1. Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + + /* Try to aquire channel */ + if (iapi_GetChannel(chNum) != 0) { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* Check if channel is already opened/initialized */ + if (ccb_p->status.openedInit == FALSE) { + result = + IAPI_ERR_CHANNEL_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | + chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + + /* Buffer descriptor validity */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + if (bd_p == NULL) { + result = + IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + + /* Check initialization has been done for trusted channels */ + if (cd_p->trust == TRUE) { + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if ((bd_p->bufferAddr == NULL) + || (bd_p->mode.count == 0)) { + result = + IAPI_ERR_BD_UNINITIALIZED | + IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + /*If transfer data size is used, check that the required read length is + * divisible by transfer data size expressed in bytes + */ + if (cd_p->useDataSize) { + /*Check for divisibility only if data size different then 8bit */ + if (cd_p->dataSize != TRANSFER_8BIT) { + switch (cd_p->dataSize) { + case TRANSFER_32BIT: + div = 4; + break; + case TRANSFER_16BIT: + div = 2; + break; + case TRANSFER_24BIT: + div = 3; + break; + /*we should not get to default */ + default: + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*check the total number of bytes requested */ + if ((nbyte % div) != 0) { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*now check the length of every BD */ + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if ((bd_p->mode.count % div) != 0) { + result = + IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + } + + /* + * 2. Set the 'D' done bits on all buffer descriptors + */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = 0; index < cd_p->bufferDescNumber; index++) { + bd_p->mode.status |= BD_DONE; + bd_p++; + } + + /* + * 3. Starting of the channel + */ + iapi_lowStartChannel(chNum); + ccb_p->status.execute = TRUE; + readBytes = 0; + + /* + * 4. Synchronization mechanism handling + */ + if (cd_p->callbackSynch == DEFAULT_POLL) { + iapi_SynchChannel(chNum); + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + toRead = nbyte; + copyFinished = FALSE; + local_buf = (unsigned char *)buf; + + /* + * Check the 'RROR' bit on all buffer descriptors, set error number + * and return IAPI_FAILURE if set. + */ + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if (bd_p->mode.status & BD_RROR) { + result = IAPI_ERR_RROR_BIT_READ | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + + /* + * 5. Read loop + */ + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + while (!copyFinished) { + if (!(bd_p->mode.status & BD_DONE)) { + if (cd_p->trust == FALSE) { + bufsize = cd_p->bufferSize; + } else { + bufsize = bd_p->mode.count; + } + /*if L bit is set, read only "count" bytes and exit the loop */ + if (bd_p->mode.status & BD_LAST) { + bufsize = bd_p->mode.count; + copyFinished = TRUE; + } + if (toRead > bufsize) { + if (cd_p->trust == FALSE) { + iapi_memcpy(local_buf, + iapi_Phys2Virt + (bd_p->bufferAddr), + bufsize); + local_buf += bufsize; + } + readBytes += bufsize; + toRead -= bufsize; + /*advance bd_p only if bit L is not set. The loop will exit anyway. */ + if (!(bd_p->mode.status & BD_LAST)) { + if (bd_p->mode.status & BD_WRAP) { + bd_p = + (bufferDescriptor *) + iapi_Phys2Virt + (ccb_p->baseBDptr); + } else if (((bufferDescriptor *) + iapi_Phys2Virt + (ccb_p->baseBDptr) + + + (cd_p->bufferDescNumber + - + 1) * + sizeof + (bufferDescriptor)) + != bd_p) { + bd_p++; + } else { + /* finished here : end of buffer descriptors */ + copyFinished = TRUE; + } + } + } else { + if (cd_p->trust == FALSE) { + iapi_memcpy(local_buf, + iapi_Phys2Virt + (bd_p->bufferAddr), + toRead); + local_buf += toRead; + } + readBytes += toRead; + toRead = 0; + /* finished successfully : readBytes = nbytes */ + copyFinished = TRUE; + } + } else { + /* finished here : buffer not already done */ + copyFinished = TRUE; + } + } + iapi_ReleaseChannel(chNum); + } + + /* + *If synchronization type is callback, the user of I.API must + *release the channel + */ + return readBytes; +} + +/* ***************************************************************************/ +/*Attempts to write nbyte from the buffer pointed to by buf to the channel + * data buffers associated with the opened channel number channelNumber + * + * <b>Algorithm:</b>\n + * + * - Check data structures are properly initialized: + * - Channel descriptor validity + * - Channel control block validity + * - Buffer descriptor validity + * - If transfer data size is used, check validity of combination transfer + * size/requested bytes + * - Write loop\n + * Write occurs in the buffer acceded form buffer descriptor and continues + * to the "next" buffer which can be:\n + * -# the last BD of the ring so re-start from beginning\n + * -# the last BD of the BD array but no ring so finish\n + * -# (general case) the next BD in the BD array\n + * And copy continues until data fit in the current buffer or the nbyte + * parameter is reached. + * - Starting of the channel + * + * <b>Notes:</b>\n + * 1) Virtual DMA SDMA channels are unidirectionnal, an iapi_Write authorized + * on a channel means that we are expecting to send to the SDMA. The + * meaning of an interrupt received from the SDMA is therfore that the + * data has been delivered to the SDMA. + * + * @param *cd_p chanenl descriptor for the channel to write to + * @param *buf buffer with data to be written + * @param nbyte number of bytes to write to channel + * + * @return + * - number of bytes written + * - -iapi_errno if failure + */ +int iapi_Write(channelDescriptor *cd_p, void *buf, unsigned short nbyte) +{ + unsigned int writtenBytes = 0; + unsigned int toWrite; + int result = IAPI_SUCCESS; + unsigned int copyFinished; + unsigned int buffsize; + unsigned int index = 0; + bufferDescriptor *bd_p; + channelControlBlock *ccb_p; + unsigned char *local_buf; + unsigned char chNum; + unsigned char div; + + iapi_errno = IAPI_ERR_NO_ERROR; + + /* + * 1. Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptpor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + + /* Try to aquire channel */ + if (iapi_GetChannel(chNum) != 0) { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* Buffer descriptor validity */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + if (bd_p == NULL) { + result = + IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + + /* Check initialization has been done for trusted channels */ + if (cd_p->trust == TRUE) { + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if ((bd_p->bufferAddr == NULL) + || (bd_p->mode.count == 0)) { + result = + IAPI_ERR_BD_UNINITIALIZED | + IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + /*If transfer data size is used, check that the required write length is + * divisible by transfer data size expressed in bytes + */ + if (cd_p->useDataSize) { + /*Check for divisibility only if data size different then 8bit */ + if (cd_p->dataSize != TRANSFER_8BIT) { + switch (cd_p->dataSize) { + case TRANSFER_32BIT: + div = 4; + break; + case TRANSFER_16BIT: + div = 2; + break; + case TRANSFER_24BIT: + div = 3; + break; + /*we should not get to default */ + default: + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*check the total number of bytes requested */ + if ((nbyte % div) != 0) { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*now check the length of every BD */ + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if ((bd_p->mode.count % div) != 0) { + result = + IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + } + + /* + * 2. Write loop + */ + + local_buf = (unsigned char *)buf; + toWrite = nbyte; + copyFinished = FALSE; + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + + while (!copyFinished) { + + /* variable buffsize contains the nb of bytes that the SDMA will transfer at each pass of the while loop */ + + /* in NON trusted mode, buffsize is copied from Channel descriptor bufferSize (same size for all transfers) */ + if (cd_p->trust == FALSE) { + buffsize = cd_p->bufferSize; + } + /* in TRUSTED mode, it's up to the user to specify the size of each buffer thru an IoCtl call */ + /* This IoCtl has directly modified the bd_p->mode.count */ + /* therefore, buffersize is copied from the bd_p->mode.count */ + else { + buffsize = bd_p->mode.count; + } + + /* in any mode (trusted or non trusted), the transfer size must be overridden by */ + /* "toWrite" when there is less remaining bytes to transfer than the current buffer size */ + if (toWrite < buffsize) { + buffsize = toWrite; + } + + if (!(bd_p->mode.status & BD_DONE)) { + /* More data to write than a single buffer can contain */ + if (cd_p->trust == FALSE) { + iapi_memcpy(iapi_Phys2Virt(bd_p->bufferAddr), + local_buf, buffsize); + local_buf += buffsize; + } + + /* update the BD count that will be used by the SDMA to transfer the proper nb of bytes */ + bd_p->mode.count = buffsize; + + bd_p->mode.status |= BD_DONE; + writtenBytes += buffsize; + toWrite -= buffsize; + /* Prepares access to the "next" buffer */ + /* - case 1 - finished successfully : writtenBytes = nbytes */ + if (toWrite == 0) { + copyFinished = TRUE; + } + /* - case 2 - Last BD and WRAP bit set so re-start from beginning */ + /*else if ((bd_p->mode.status & BD_WRAP)){ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + } */ + /* - case 3 - Last BD of the BD but nor ring */ + else if (((bufferDescriptor *) + iapi_Phys2Virt(ccb_p->baseBDptr) + + (cd_p->bufferDescNumber - + 1) * sizeof(bufferDescriptor)) == bd_p) { + copyFinished = TRUE; + } + /* - case 4 - general : next BD in the BD array */ + else { + bd_p++; + } + + } else { + /* finished here : buffer not already done */ + copyFinished = TRUE; + } + } + + ccb_p->currentBDptr = ccb_p->baseBDptr; + + /* + * 3. Starting of the channel + */ + iapi_lowStartChannel(chNum); + ccb_p->status.execute = TRUE; + + if (cd_p->callbackSynch == DEFAULT_POLL) { + iapi_SynchChannel(chNum); + /* + * Check the 'RROR' bit on all buffer descriptors, set error number + * and return IAPI_FAILURE if set. + */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if (bd_p->mode.status & BD_RROR) { + result = IAPI_ERR_RROR_BIT_WRITE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + iapi_ReleaseChannel(chNum); + } + + /* + *If synchronization type is callback, the user of I.API must + *release the channel + */ + return writtenBytes; +} + +/* ***************************************************************************/ +/* This function is used to receive data from the SDMA. + * + * <b>Algorithm:</b>\n + * + * The data control structure would be copied to IPCv1 complied Buffer + * Descriptor Array. This array shall be allocated from non cacheable memory. + * It would then provide this buffer descriptor array as an input to SDMA using + * channel control block and then configure the Host Enable (HE) or + * DSP enable (DE) bit of SDMA for the channel used for this transfer depending + * on the source. + * + * <b>Notes:</b>\n + * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized + * on a channel means that source processor is expecting to send to the destination + * processor. The meaning of an interrupt received from the SDMA notifies that the + * data has been delivered to the destination processor. + * + * @param *cd_p chanenl descriptor for the channel to receive from + * @param *data_control_struct_ipcv2 + + * Data Control structure: + * ------------------------- + * | Data Node Descriptor 1| + * ------------------------- + * | Data Node Descriptor 2| + * ------------------------- + * | : | + * | : | + * ------------------------- + * |Data Node Descriptor n | + * ------------------------- + * + * Data Node Descriptor (Buffer Descriptor): + *------------------------------------------------------------------------------ + *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 0| + *------------------------------------------------------------------------------ + *| L E D R R R R R |<---- Reserved ----> |<- Length-> | + *------------------------------------------------------------------------------ + *| <---------------------------- Data Ptr ----------------------------------->| + *------------------------------------------------------------------------------ + * + * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame + * E bit (END): If set, we reached the end of the buffers passed to the function + * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been + * filled by the SDMA. + * Length: Length of data pointed by this node in bytes + * Data Ptr: Pointer to the data pointed to by this node. + * The Function Shall not be called for the same channel unless the Read callback has been + * received for channel for which it has been called already. + * + * @return + * - IAPI_SUCCESS on success, IAPI_ERROR otherwise + * + *- -iapi_errno if failure + */ + +int iapi_Read_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2) +{ + channelControlBlock *ccb_p; + +/* The Parameters passed are considered to be validated by the upper layers*/ + + bufferDescriptor_ipcv1_v2 *bd_ipcv2_p; + dataNodeDescriptor *dnd_p = + (dataNodeDescriptor *) data_control_struct_ipcv2; + + ccb_p = cd_p->ccb_ptr; + iapi_errno = IAPI_ERR_NO_ERROR; + + if (ccb_p->baseBDptr == NULL) { + iapi_errno = IAPI_ERR_BD_UNINITIALIZED; + return -(IAPI_ERR_BD_UNINITIALIZED); + } + + ccb_p->currentBDptr = ccb_p->baseBDptr; + + /* Copy the data Node descriptor information to new BDs */ + bd_ipcv2_p = + (bufferDescriptor_ipcv1_v2 *) iapi_Phys2Virt(ccb_p->baseBDptr); + + while (1) { + bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr; + bd_ipcv2_p->mode.count = dnd_p->mode.count; +#ifdef MCU + bd_ipcv2_p->mode.endianness = 1; +#endif +#ifdef DSP + bd_ipcv2_p->mode.endianness = 0; +#endif + + bd_ipcv2_p->mode.status = + dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK]; + + if ((dnd_p->mode.status & DND_END_OF_XFER) != 0) { + /* Break the loop at End of Transfer */ + break; + + } + bd_ipcv2_p++; + dnd_p++; + + } + /* + * Store the buffer address + */ + dnd_read_control_struct[cd_p->channelNumber] = + (dataNodeDescriptor *) data_control_struct_ipcv2; + /* + * Register the Call Back + */ + + iapi_AttachCallbackISR(cd_p, iapi_read_ipcv2_callback); + + /* + * Starting of the channel + */ + iapi_lowStartChannel(cd_p->channelNumber); + ccb_p->status.execute = TRUE; + + return IAPI_SUCCESS; + +} + +/* ***************************************************************************/ +/* + * The function is used send a group of buffers to SDMA. + * <b>Algorithm:</b>\n + * + * The data control structure would be copied to IPCv1 complied Buffer + * Descriptor Array. This array shall be allocated from non cacheable memory. + * It would then provide this buffer descriptor array as an input to SDMA using + * channel control block and then configure the Host Enable (HE) or + * DSP enable (DE) bit of SDMA for the channel used for this transfer depending + * on the source. + * The Function Shall not be called for the same channel unless the Read callback has been + * received for channel for which it has been called already. + * + * <b>Notes:</b>\n + * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized + * on a channel means that source processor is expecting to send to the destination + * processor. The meaning of an interrupt received from the SDMA notifies that the + * data has been delivered to the destination processor. + * + * @param *cd_p chanenl descriptor for the channel to write to + * @param *data_control_struct_ipcv2 + + * Data Control structure: + * ------------------------- + * | Data Node Descriptor 1| + * ------------------------- + * | Data Node Descriptor 2| + * ------------------------- + * | : | + * | : | + * ------------------------- + * |Data Node Descriptor n | + * ------------------------- + * + * Data Node Descriptor (Buffer Descriptor): + *------------------------------------------------------------------------------ + *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 0| + *------------------------------------------------------------------------------ + *| L E D R R R R R |<---- Reserved ----> |<- Length-> | + *------------------------------------------------------------------------------ + *| <---------------------------- Data Ptr ----------------------------------->| + *------------------------------------------------------------------------------ + * + * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame + * E bit (END): If set, we reached the end of the buffers passed to the function + * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been + * filled by the SDMA. + * Length: Length of data pointed by this node in bytes + * Data Ptr: Pointer to the data pointed to by this node. + * + * + * @return + * - iapi sucess on success. + * - -iapi_errno if failure + */ + +int iapi_Write_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2) +{ + + channelControlBlock *ccb_p; + +/* The Parameters passed are considered to be validated by the upper layers*/ + + bufferDescriptor_ipcv1_v2 *bd_ipcv2_p; + dataNodeDescriptor *dnd_p = + (dataNodeDescriptor *) data_control_struct_ipcv2; + ccb_p = cd_p->ccb_ptr; + iapi_errno = IAPI_ERR_NO_ERROR; + + if (ccb_p->baseBDptr == NULL) { + iapi_errno = IAPI_ERR_BD_UNINITIALIZED; + return -(IAPI_ERR_BD_UNINITIALIZED); + } + + ccb_p->currentBDptr = ccb_p->baseBDptr; + + bd_ipcv2_p = + (bufferDescriptor_ipcv1_v2 *) iapi_Phys2Virt(ccb_p->currentBDptr); + /* Copy the data Node descriptor information to new BDs */ + while (1) { + bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr; + bd_ipcv2_p->mode.count = dnd_p->mode.count; + +#ifdef MCU + bd_ipcv2_p->mode.endianness = 1; +#endif +#ifdef DSP + bd_ipcv2_p->mode.endianness = 0; +#endif + + bd_ipcv2_p->mode.status = + dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK]; + + if ((dnd_p->mode.status & DND_END_OF_XFER) != 0) { + /* Break the loop at End of Transfer */ + break; + } + bd_ipcv2_p++; + dnd_p++; + + } + + /* + * Starting of the channel + */ + iapi_lowStartChannel(cd_p->channelNumber); + ccb_p->status.execute = TRUE; + + return IAPI_SUCCESS; + +} + +/* ***************************************************************************/ +/** Call back ISR for the IPCv2 Receive. + * + * <b>Algorithm:</b>\n + * - This would copy back the informationfrom IPCv1 BD to IPCv2 BD on + * the receiving processor + * + * @return + * - void + */ + +void iapi_read_ipcv2_callback(struct iapi_channelDescriptor *cd_p, void *data) +{ + /*cd_p->ccb_ptr->channelDNDBuffer; */ + dataNodeDescriptor *dnd_p = dnd_read_control_struct[cd_p->channelNumber]; + bufferDescriptor_ipcv1_v2 *bd_ipcv2_p = + (bufferDescriptor_ipcv1_v2 *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + int index = MAX_BD_NUM - 1; + + do { + dnd_p->mode.status = 0; + dnd_p->mode.count = bd_ipcv2_p->mode.count; + + dnd_p->mode.status |= + bd_ipcv2_p->mode.status & BD_DONE ? 0x00 : DND_DONE; + dnd_p->mode.status |= + bd_ipcv2_p-> + mode.status & BD_IPCV2_END_OF_FRAME ? DND_END_OF_FRAME : + 0x00; + dnd_p->mode.status |= + bd_ipcv2_p->mode.status & BD_LAST ? DND_END_OF_XFER : 0x00; + cd_p->ccb_ptr->currentBDptr = + (bufferDescriptor *) iapi_Virt2Phys(bd_ipcv2_p); + + if ((bd_ipcv2_p->mode.status & BD_LAST) != 0 || + (bd_ipcv2_p->mode.status & BD_CONT) == 0) + break; + dnd_p++; + bd_ipcv2_p++; + + } while (index--); + + /*Call back the Original ISR */ + cd_p->callbackISR_ptr(cd_p, data); +} + +/* ***************************************************************************/ +/**Terminates a channel. + * + * <b>Algorithm:</b>\n + * - Check input parameters ans data structures + * - Check that all buffes have been processed (test all 'D' bits) + * - Stop the channel execution + * - Free alocated memory structures + * - Re-instantiate default interrupt handling + * + * @param *cd_p chanenl descriptor for the channel to close + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : close failed + */ +int iapi_Close(channelDescriptor *cd_p) +{ + int index = 0; + int result = IAPI_SUCCESS; + unsigned char chNum; + bufferDescriptor *bd_p; + channelControlBlock *ccb_p; + + /* + * 1. Check input parameters ans data structures + */ + if (cd_p != NULL) { + if (cd_p->ccb_ptr != NULL) { + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + } else { + result = + IAPI_ERR_NO_CCB_DEFINED | IAPI_ERR_CH_AVAILABLE; + iapi_errno = result; + return -result; + } + } else { + result = IAPI_ERR_CD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE; + iapi_errno = result; + return -result; + } + /* Try to aquire channel */ + if (iapi_GetChannel(chNum) != 0) { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* + * 2. Check that all buffes have been processed (test all 'D' bits), + * only if the forceClose bit in channel descriptor is set to FALSE + */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + if (bd_p == NULL) { + result = + IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + return -result; + } + if (cd_p->forceClose == FALSE) { + for (index = cd_p->bufferDescNumber; index > 0; index--) { + if (bd_p->mode.status & BD_DONE) { + result = + IAPI_ERR_CLOSE | IAPI_ERR_CH_AVAILABLE | + chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + /*if the closing is forced,mark channel unused,set BD ownership to processor */ + else { + ccb_p->status.execute = FALSE; + for (index = cd_p->bufferDescNumber; index > 0; index--) { + bd_p->mode.status &= ~BD_DONE; + bd_p++; + } + } + + /* + * 3. Stop the channel execution + */ + iapi_lowStopChannel(chNum); + + /* + * 4. Free alocated memory structures + */ + if (cd_p->trust == FALSE) { + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = cd_p->bufferDescNumber; index > 0; index--) { + FREE(iapi_Phys2Virt(bd_p->bufferAddr)); + bd_p++; + } + } + + /* + * 5. Re-instantiate default interrupt handling + */ + iapi_DetachCallbackISR(cd_p); + FREE((bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr)); + FREE(cd_p); + ccb_p->baseBDptr = NULL; + ccb_p->currentBDptr = NULL; + ccb_p->channelDescriptor = NULL; + ccb_p->status.openedInit = FALSE; + + iapi_ReleaseChannel(chNum); + + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**The request argument selects the control function to be performed. + * + * <b>Algorithm:</b>\n + * + * - Check data structures are properly initialized: + * - Channel descriptor validity + * - Channel control block validity + * - The ctlRequest parameter contains in the lower 16 bits the control code of + * the change to be performed, and in the upper 16 bits, the BD to be + * modified if the change affects a BD od the channel. + * - Selection of the parameter to change and appropriate sanity checks: + * - Channel Descriptor: changes the pointer to the channel descriptor + * structure, the pointer to the new channel descriptor is given in the third + * argument call + * - Buffer Descriptor Number: changes the number of buffer descriptor for the + * channel + * - Buffer size: changes the size of the data buffers pointed to by the + * buffer descriptor; note that all buffer descriptors are assumed to have the + * same size for a given buffer descripotr chain + * - Blocking policy: changes the blocking policy for the read and write calls + * - Ownership: changes direction: turnaround + * - Synchronization method: changes the callback type, default or user. The* + * callback function table is set accordingly + * - Trust property: trust can only be changed through ChangeChannelDesc first + * request, this guarantees the close/open sequence for the channel + * - Callback Interrupt service routine pointer: changes the callback function + * pointer, when this method is used, to replace it with a new one + * - Channel control block pointer: not available + * - Priority: changes the channel priority directly in SDMA register + * - Watermark level: changes the value of the peripheral watermark level that + * passed to the script. The new value is passed in the third parameter call. + * - Wrap bit: changes to set to 1 the Wrap bit of the last buffer descriptor + * + * @param *cd_p channel descriptor for the channel to modify + * @param ctlRequest request control code and, if tha case, number of BD to be + * changed + * @param param parameter for the modification + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : operation failed + */ +int +iapi_IoCtl(channelDescriptor *cd_p, unsigned long ctlRequest, + unsigned long param) +{ + int retvalue; + int result = IAPI_SUCCESS; + unsigned char chNum; + unsigned long clean_ctlRequest; /* lower 16 bits of the ctlRequest */ + unsigned long bd_num; /* upper 16 bits of the ctlRequest */ + + /* + * 1. Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + + /* Remove, if exists, BD number specified in upper bits of ctlRequest */ + clean_ctlRequest = ctlRequest & (~BD_NUM_MASK); + + /* Extract, if exists, BD number specified in upper bits of ctlRequest */ + bd_num = (ctlRequest & BD_NUM_MASK) >> BD_NUM_OFFSET; + + /* Check that the bd_num is valid */ + if (bd_num > cd_p->bufferDescNumber) { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + return -result; + } + + /*All checks OK, try to aquire channel */ + if (iapi_GetChannel(chNum) != 0) { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* + * 2. Selection of the parameter to change and appropriate sanity checks + */ + switch (clean_ctlRequest) { + + /* + * Channel Descriptor + * --- Changes the pointer to the channel descriptor structure: the pointer + * to the new channel descriptor is given in the third argument call. + */ + case IAPI_CHANGE_CHANDESC: + if ((void *)param == NULL) { + result = IAPI_ERR_INVALID_PARAMETER; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } else { + channelDescriptor *chParam = + (channelDescriptor *) param; + if (chParam->channelNumber != chNum) { + /* Release ch so it can be aquired by the Close fn */ + iapi_ReleaseChannel(chNum); + result = iapi_Close(cd_p); + if (result == IAPI_SUCCESS) { + FREE((void *)cd_p); + iapi_AllocChannelDesc(&cd_p, + chParam->channelNumber); + iapi_memcpy((void *)cd_p, + (void *)chParam, + sizeof(channelDescriptor)); + /* Channel is released allready, so Open can get the channel */ + result = + iapi_Open(cd_p, + chParam->channelNumber); + if (result != IAPI_SUCCESS) { + return result; /* error code already set in iapi_Open */ + } + } else { + return result; /* error code already set in iapi_Close */ + } + } else { + result = + IAPI_ERR_CD_CHANGE | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_ReleaseChannel(chNum); + iapi_errno = result; + return -result; + } + return IAPI_SUCCESS; + } + + /* + * Buffer Descriptor Number + * --- Changes the number of buffer descriptor for the channel. + */ + case IAPI_CHANGE_BDNUM: + result = + iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Buffer size + * --- Changes the size of the data buffers pointed to by the buffer + * descriptor; note that all buffer descriptors are assumed to have the + * same size for a given buffer descripotr chain. + */ + case IAPI_CHANGE_BUFFSIZE: + result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Blocking policy + * --- Changes the blocking policy for the read and write calls. + */ + case IAPI_CHANGE_CHANBLOCK: + result = iapi_ChangeChannelDesc(cd_p, IAPI_BLOCKING, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Ownership + * --- Changes direction: turnaround + */ + case IAPI_CHANGE_OWNERSHIP: + result = iapi_ChangeChannelDesc(cd_p, IAPI_OWNERSHIP, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Synchronization method + * --- Changes the callback type, default or user. The callback function + * table is set accordingly. + */ + case IAPI_CHANGE_SYNCH: + result = + iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKSYNCH, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Trust property + * --- trust can only be changed through ChangeChannelDesc first request, + * this guarantees the close/open sequence for the channel. + */ + case IAPI_CHANGE_TRUST: + result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Callback Interrupt service routine pointer + * --- Cahnges the callback function pointer, when this method is used, to + * replace it with a new one. + */ + case IAPI_CHANGE_CALLBACKFUNC: + result = + iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKISR_PTR, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Channel control block pointer + * --- NA + */ + case IAPI_CHANGE_CHANCCB: + result = iapi_ChangeChannelDesc(cd_p, IAPI_CCB_PTR, param); + iapi_ReleaseChannel(chNum); + return result; + +#ifdef MCU + /* + * Priority + * --- Changes the channel priority directly in SDMA register + */ + case IAPI_CHANGE_PRIORITY: + { + volatile unsigned long *ChannelPriorities = + &SDMA_CHNPRI_0; + if (param < MAX_CH_PRIORITY) { + ChannelPriorities[cd_p->channelNumber] = param; + } else { + iapi_ReleaseChannel(chNum); + return IAPI_FAILURE; + } + } + break; +#endif /* MCU */ + + /* + * Wrap + * --- Set to 1 the wrap bit of the last buffer descriptor of the array. + * it provides the possibility to have a circular buffer structure. + */ + case IAPI_CHANGE_BDWRAP: + { + result = + iapi_ChangeChannelDesc(cd_p, IAPI_BDWRAP, param); + iapi_ReleaseChannel(chNum); + return result; + } + + /* + * Watermark + * --- Changes the value of the peripheral watermark level that triggers + * a DMA request. It impacts context of the channel, therefore channel 0 + * must be started to update the context with this new value. + */ + case IAPI_CHANGE_WATERMARK: + { + result = iapi_ChangeChannelDesc(cd_p, IAPI_WML, param); + iapi_ReleaseChannel(chNum); + return result; + } + /* + * INTR + * --- Set the INTR bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_SET_BDINTR: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status |= BD_INTR; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status |= BD_INTR; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * INTR + * --- Unset the INTR bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_UNSET_BDINTR: + { + bufferDescriptor *bde_p; + + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status &= ~BD_INTR; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status &= ~BD_INTR; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } +/* + * EventMask1 + * --- Changes the value of the eventMask1 + */ + case IAPI_CHANGE_EVTMASK1: + { + cd_p->eventMask1 = param; + } + break; + /* + * EventMask2 + * --- Changes the value of the eventMask2 + */ + case IAPI_CHANGE_EVTMASK2: + { + cd_p->eventMask2 = param; + } + break; + /* + * Peripheral Address + * --- Changes the value of the peripheralAddr + */ + case IAPI_CHANGE_PERIPHADDR: + { + cd_p->peripheralAddr = param; + } + break; + /* + * Cont + * --- Set the CONT bit on specified BD on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_SET_BDCONT: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status |= BD_CONT; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status |= BD_CONT; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * Cont + * --- Unset the CONT bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_UNSET_BDCONT: + { + bufferDescriptor *bde_p; + + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status &= ~BD_CONT; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status &= ~BD_CONT; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + + /* + * EXTD + * --- Set the EXTD bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_SET_BDEXTD: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status |= BD_EXTD; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status |= BD_EXTD; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * EXTD + * --- Unset the EXTD bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_UNSET_BDEXTD: + { + bufferDescriptor *bde_p; + + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status &= ~BD_EXTD; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status &= ~BD_EXTD; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + + /* + * TRANSFER SIZE to be used for this channel + * --- Set the transfer size used indicator and code for transfer size in + * the CD + */ + case IAPI_CHANGE_SET_TRANSFER_CD: + { + bufferDescriptor *bde_p; + int j = 0; + retvalue = IAPI_SUCCESS; + if ((param == TRANSFER_8BIT) + || (param == TRANSFER_16BIT) + || (param == TRANSFER_24BIT) + || (param == TRANSFER_32BIT)) { + cd_p->useDataSize = TRUE; + cd_p->dataSize = param; + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.command = param; + bde_p++; + } + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + + /* + * USER_ARG + * --- Set the user selectable pointer to be received by the callback + * function, if IRQ synch is used + */ + case IAPI_CHANGE_USER_ARG: + { + userArgTable[cd_p->channelNumber] = (void *)param; + iapi_ReleaseChannel(chNum); + return IAPI_SUCCESS; + } + /* + * FORCE_CLOSE + * --- Set the forceClose bit in channelDescriptor to value passed in param. + * If this bit is TRUE, the channel in closed even if some BD are still + * owned by the SDMA. + */ + case IAPI_CHANGE_FORCE_CLOSE: + { + retvalue = IAPI_SUCCESS; + if ((param == TRUE) || (param == FALSE)) { + cd_p->forceClose = param; + } else { + iapi_errno = + IAPI_ERR_INVALID_PARAMETER | + cd_p->channelNumber; + retvalue = -iapi_errno; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * TRANSFER type + * --- Set the last 2 bits in the command field of the BD to specify the + * transfer type 8, 16, 24, or 32 bits on all BD's, allready set in the CD + */ + case IAPI_CHANGE_SET_TRANSFER: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if ((param == TRANSFER_8BIT) + || (param == TRANSFER_16BIT) + || (param == TRANSFER_24BIT) + || (param == TRANSFER_32BIT)) { + bde_p = cd_p->ccb_ptr->baseBDptr; + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.command = param; + bde_p++; + } + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * BUFFER address + * --- Change buffer address in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_BUFFERADDR: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + + /* DO NOT translate address to physical */ + bde_p->bufferAddr = (void *)param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * BUFFER address + * --- Get the buffer address from the BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_GET_BUFFERADDR: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Translate to virtual */ + *((unsigned long *)param) = + (unsigned long)bde_p->bufferAddr; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * EXTENDED BUFFER address + * --- Change extended buffer address in BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_SET_EXTDBUFFERADDR: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + + /* DO NOT translate address to physical. The user might want something else + *here + */ + bde_p->extBufferAddr = (void *)param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * EXTENDED BUFFER address + * --- Get extended buffer address from the BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_GET_EXTDBUFFERADDR: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + + /* DO NOT translate address to vitual - user knows what is here. + */ + *((unsigned long *)param) = + (unsigned long)bde_p->extBufferAddr; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COMMAND field + * --- Change command field in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_COMMAND: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update command field */ + bde_p->mode.command = param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COMMAND field + * --- Get the command field from the BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_GET_COMMAND: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Get the command field */ + *((unsigned long *)param) = bde_p->mode.command; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COUNT field + * --- Change count field in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_COUNT: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update count field */ + bde_p->mode.count = param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COUNT field + * --- Get the count field of the BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_GET_COUNT: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update count field */ + *((unsigned long *)param) = bde_p->mode.count; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * STATUS field + * --- Change status field in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_STATUS: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update status field */ + bde_p->mode.status = param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * STATUS field + * --- Get the status field of the BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_GET_STATUS: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update status field */ + *((unsigned long *)param) = bde_p->mode.status; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + +#ifdef MCU + /* + * Endianness + * --- Set the ENDIANNESS indicator in the command filed of the specified BD + * or on all BD's if SET_BIT_ALL is passed as parameter. + */ + case IAPI_CHANGE_SET_ENDIANNESS: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.command = CHANGE_ENDIANNESS; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.command = CHANGE_ENDIANNESS; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } +#endif + +#ifdef SDMA_SKYE +#ifdef MCU + + /* + * SDMA State + * --- Enter the SDMA into LOCK Mode. No RAM updation allowed except same Context + * update with same PC Value. + */ + case IAPI_ENTER_LOCK_MODE: + { + if (param == RESET_CLEAR_LOCK) { + SDMA_SDMA_LOCK = (1 << RESET_CLR_BIT_OFFSET); + SDMA_SDMA_LOCK = (1 << LOCK_BIT_OFFSET); + iapi_SdmaState = LOCK; + } else if (param == RESET_NOCLEAR_LOCK) { + SDMA_SDMA_LOCK = (1 << LOCK_BIT_OFFSET); + iapi_SdmaState = LOCK; + } + + } + break; + +#endif +#endif + default: + retvalue = + IAPI_ERR_CD_CHANGE_UNKNOWN | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = retvalue; + iapi_ReleaseChannel(chNum); + return -retvalue; + } + + iapi_ReleaseChannel(chNum); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**Initialization of the SDMA - opening of channel 0, download RAM image. + * + * <b>Algorithm:</b>\n + * - open channel 0 + * - if ram_image pointer passed is not NULL, download RAM image to SDMA + * + * @param + * - cd_p channel descriptor pointer for channel 0 + * - ram_image pointer to RAM image to download, or NULL if this operation + * is not required + * - code_size size of the RAM image, in bytes + * - start_addr start address for the RAM image + * + * @return + * - IAPI_SUCCESS if all operations were successful + * - negated I.API error code if any operation failed + */ +#ifdef MCU +int +iapi_Init(channelDescriptor *cd_p, configs_data *config_p, + unsigned short *ram_image, unsigned short code_size, + unsigned long start_addr) +{ +#endif +#ifdef DSP + int + iapi_Init(channelDescriptor *cd_p) { +#endif + + int retvalue = IAPI_SUCCESS; /* Variable to store the results from I.API calls */ + + /* Check initialization not allredy done */ + if (iapi_CCBHead != NULL) { + retvalue = IAPI_ERR_NOT_ALLOWED; + iapi_errno = retvalue; + return -retvalue; + } + /* Be sure SDMA has not started yet */ +#ifdef MCU + SDMA_H_C0PTR = 0x0; +#endif +#ifdef DSP + SDMA_D_C0PTR = 0x0; +#endif + + /*Try to open channel 0 */ + retvalue = iapi_Open(cd_p, 0); + if (retvalue != IAPI_SUCCESS) { + return retvalue; + } +#ifdef MCU + /* Set Command Channel (Channel Zero) */ + SDMA_CHN0ADDR = 0x4050; + + /* Set bits of CONFIG register but with static context switching */ + SDMA_H_CONFIG = + (config_p-> + dspdma << 12) | (config_p->rtdobs << 11) | (config_p->acr + << 4) | (0); + + /* Send the address for the host channel table to the SDMA */ + SDMA_H_C0PTR = (unsigned long)iapi_Virt2Phys(iapi_CCBHead); + /* If required, download the RAM image for SDMA */ + if (ram_image != NULL) { + retvalue = + iapi_SetScript(cd_p, (void *)ram_image, code_size, + start_addr); + } + + /* Set bits of CONFIG register with given context switching mode */ + SDMA_H_CONFIG = + (config_p-> + dspdma << 12) | (config_p->rtdobs << 11) | (config_p->acr + << 4) | + (config_p->csm); + +#endif +#ifdef DSP + /* Send the address for the host channel table to the SDMA */ + SDMA_D_C0PTR = (unsigned long)iapi_Virt2Phys(iapi_CCBHead); +#endif + +#ifdef SDMA_SKYE + iapi_SdmaState = OPEN; +#endif + + return retvalue; + } + +/* ***************************************************************************/ +/**High layer interface for starting a channel + * + * <b>Algorithm:</b>\n + * - call low layer function for starting a channel + * + * @return + * - IAPI_SUCCESS + */ +int iapi_StartChannel(unsigned char channel) +{ + iapi_lowStartChannel(channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for stopping a channel + * + * <b>Algorithm:</b>\n + * - call low layer function for stopping a channel + * + * @return + * - IAPI_SUCCESS + */ +int iapi_StopChannel(unsigned char channel) +{ + iapi_lowStopChannel(channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for synchronising a channel + * + * <b>Algorithm:</b>\n + * - call low layer function for stopping a channel + * + * @return + * - IAPI_SUCCESS + */ +int iapi_SynchChannel(unsigned char channel) +{ + iapi_lowSynchChannel(channel); + return IAPI_SUCCESS; +} + +#ifdef MCU +/* ***************************************************************************/ +/**High layer interface for getting program memory data from SDMA + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_GetScript(channelDescriptor *cd_p, void *buf, + unsigned short size, unsigned long address) +{ + iapi_lowGetScript(cd_p, buf, size, address); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for getting data memory from SDMA + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_GetContext(channelDescriptor *cd_p, void *buf, + unsigned char channel) +{ + iapi_lowGetContext(cd_p, buf, channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for set program memory data to SDMA - e.g. scripts + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_SetScript(channelDescriptor *cd_p, void *buf, + unsigned short nbyte, unsigned long destAddr) +{ + iapi_lowSetScript(cd_p, buf, nbyte, destAddr); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for set data memory to SDMA - e.g. contexts. + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_SetContext(channelDescriptor *cd_p, void *buf, + unsigned char channel) +{ + iapi_lowSetContext(cd_p, buf, channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface used to associate specified channel with a script. + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_AssignScript(channelDescriptor *cd_p, script_data *data_p) +{ + /* VERIFY THAT THE CHANNEL IT IS OPENED !!!! */ + return iapi_lowAssignScript(cd_p, data_p); +} + +/* ***************************************************************************/ +/**High layer interface used to associate specified channel with a script. + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_SetChannelEventMapping(unsigned char event, + unsigned long channel_map) +{ + return iapi_lowSetChannelEventMapping(event, channel_map); +} +#endif + +#ifdef DSP +#define SDMA_DI SDMA_D_INTR + void IRQ_Handler(); +#pragma interrupt IRQ_Handler +#endif + +#ifdef MCU +#define SDMA_DI SDMA_H_INTR +#endif + +#ifndef IRQ_KEYWORD +#define IRQ_KEYWORD +#endif /* IRQ_KEYWORD */ + +/* ***************************************************************************/ +/** + *@brief Find the first set bit in data parameter. + * + * Find the first set bit in unsigned integer parameter data. Data is scanned + * from MSB to LSB, searching for the set bit. The value returned is the + * offset from the most significant bit of data. If bit 31 is set, the value + * returned is zero. If no bits are set, a value of 32 is returned. This is compliant + * with the MCore FF1 instruction. + * + * + * + * @param + * - data: variable to check + * + * @return + * - the offset of the most significant bit set from the MSB + */ +unsigned int quartz_FF1(unsigned int data) +{ + register unsigned int result = 0; + while ((result <= 31) && !(data & 0x80000000U)) { + data <<= 1U; + result++; + } + + return result; +} + +IRQ_KEYWORD void IRQ_Handler(void) +{ + unsigned int intrReg; /* interrupt register mask for clearing the interrupt bit */ + unsigned char chNum; /* SDMA channel number generating the a IRQ */ + + /* Disable interrupts */ + iapi_DisableInterrupts(); + /* + * Clear interrupt in SDMA DI register => ACK to the SDMA the IT request. + * Get each interrupt number, clear them one after the other. + */ + if (SDMA_DI != 0) { + chNum = + (unsigned char)(CH_NUM - 1 - quartz_FF1(SDMA_DI)); + intrReg = (unsigned int)(1 << chNum); + } else { + chNum = 32; + intrReg = 0; + } + + while (intrReg != 0) { + SDMA_DI &= intrReg; + iapi_SDMAIntr |= intrReg; + iapi_WakeUp(chNum); + if (callbackIsrTable[chNum] != NULL) { + /* release channel before callback, so IoCtl's are available */ + iapi_ReleaseChannel(chNum); + callbackIsrTable[chNum] (iapi_CCBHead + [chNum].channelDescriptor, + userArgTable[chNum]); + } + + chNum = + (unsigned char)(CH_NUM - 1 - quartz_FF1(SDMA_DI)); + intrReg = (unsigned int)(1 << chNum); + } + + /* Enable interrupts */ + iapi_EnableInterrupts(); +} + +/* ***************************************************************************/ +/** + *@brief Perform a memory copy operation, in the memory of the same processor + * + * Size bytes are copied from the src address to dest address. It is used + * the channel pointed by cd_p, which must be configured prior to this call: + * opened, associated with the script to perform the operation - DSP_2_DSP, + * or MCU_2_MCU - and have the synchronization option set. + * + * + * + * @param + * - cd_p: channel configured to perform DSP_2_DSP or MCU_2_MCU transfers + * - dest: destination memory address + * - src : source memory address + * - size: number of bytes to copy from src to dest + * + * @return + * - the offset of the most significant bit set from the MSB + */ + +int iapi_MemCopy(channelDescriptor *cd_p, void *dest, void *src, + unsigned long size) +{ + int result = IAPI_SUCCESS; + bufferDescriptor *bd_p; + + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Check and set correct parameter */ + if (cd_p->trust != TRUE) { + result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, TRUE); + } + + if (cd_p->bufferDescNumber != 1) { + result = + iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER, + 1); + if (result != IAPI_SUCCESS) { + return result; + } + } + + if (cd_p->bufferSize != size) { + result = + iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, size); + if (result != IAPI_SUCCESS) { + return result; + } + } + /* Set addresses */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bd_p->bufferAddr = iapi_Virt2Phys(src); + bd_p->extBufferAddr = iapi_Virt2Phys(dest); + + /* Set mode */ + bd_p->mode.count = size; + bd_p->mode.command = 0x00; + bd_p->mode.status = BD_INTR | BD_EXTD | BD_DONE | BD_WRAP; + + /*Decide if we sleep or not */ + if (cd_p->callbackSynch == DEFAULT_POLL) { + iapi_StartChannel(cd_p->channelNumber); + /* Call synchronization routine */ + iapi_SynchChannel(cd_p->channelNumber); + } else { + /* Just start the channel */ + iapi_StartChannel(cd_p->channelNumber); + } + + return result; +} + +/* ***************************************************************************/ +/**Return the channel number from the channel descriptor + * + * @param cd_p pointer to channel descriptor to obtain the channel number + * + * @return + * - the channel number + * + */ +int iapi_GetChannelNumber(channelDescriptor *cd_p) +{ + return cd_p->channelNumber; +} + +/* ***************************************************************************/ +/**Return the error bit from the current BD of the channel + * + * + * @param cd_p pointer to channel descriptor + * + * @return + * - 0 if no error detected + * - BD_RROR | DATA_ERROR if error detected + * + */ +unsigned long iapi_GetError(channelDescriptor *cd_p) +{ + return (cd_p->ccb_ptr->currentBDptr->mode.status & BD_RROR) | + (*(unsigned long *)&cd_p->ccb_ptr->status & DATA_ERROR); +} + +/* ***************************************************************************/ +/**Return the count from the current BD of the channel + * + * + * @param cd_p pointer to channel descriptor + * + * @return + * - count field of the current BD for the channel + * + */ +int iapi_GetCount(channelDescriptor *cd_p) +{ + return (int)(cd_p->ccb_ptr->currentBDptr->mode.count); +} + +/* ***************************************************************************/ +/**Return the sum of counts for all the BD's owned by the processor for + * the channel specified by the received parameter. + * + * + * @param cd_p pointer to channel descriptor + * + * @return + * - sum of count fields + * + */ +int iapi_GetCountAll(channelDescriptor *cd_p) +{ + int retval = 0; + int i = 0; + bufferDescriptor *bd_p; + + bd_p = cd_p->ccb_ptr->baseBDptr; + + while ((i < cd_p->bufferDescNumber) + && ((bd_p->mode.status & BD_DONE) == 0)) { + retval += bd_p->mode.count; + i++; + bd_p++; + } + return retval; +} diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c new file mode 100644 index 000000000000..47611fe52743 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLow.c + * + * $Id iapiLow.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the LOW level functions of the I.API. + * + * + * / + * + * $Log iapiLow.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include <linux/preempt.h> +#include <linux/hardirq.h> +#include "epm.h" +#include "iapiLow.h" + +/** + * Function Section + */ + +/* ***************************************************************************/ +/**Records an ISR callback function pointer into the ISR callback + * function table + * + * @param cd_p channel descriptor to attach callback to + * @param func_p pointer to the callback function to be registered + * + * @return none + */ +void +iapi_AttachCallbackISR(channelDescriptor *cd_p, + void (*func_p) (channelDescriptor *cd_p, void *arg)) +{ + if (cd_p->callbackSynch == CALLBACK_ISR) { + iapi_DisableInterrupts(); + callbackIsrTable[cd_p->channelNumber] = func_p; + iapi_EnableInterrupts(); + } else if (cd_p->callbackSynch == DEFAULT_POLL) { + callbackIsrTable[cd_p->channelNumber] = NULL; + } else { + iapi_errno = + IAPI_ERR_CALLBACKSYNCH_UNKNOWN | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + } +} + +/* ***************************************************************************/ +/**Detaches (removes) an ISR callback function pointer from the ISR callback + * function table + * + * <b>Algorithm:</b>\n + * - Attach a null function to replace the original one. + * + * @param cd_p channel descriptor to detach callback from + * + * @return none + */ +void iapi_DetachCallbackISR(channelDescriptor *cd_p) +{ + iapi_AttachCallbackISR(cd_p, NULL); +} + +/* ***************************************************************************/ +/**Updates an ISR callback function pointer into the ISR callback function + * table + * + * <b>Algorithm:</b>\n + * - Detach the old function pointer (if any) and attach the new one + * + * @param cd_p channel descriptor to attach callback to + * @param func_p pointer to the callback function to be registered + * + * @return none + */ +void +iapi_ChangeCallbackISR(channelDescriptor *cd_p, + void (*func_p) (channelDescriptor *cd_p, void *arg)) +{ + iapi_DetachCallbackISR(cd_p); + iapi_AttachCallbackISR(cd_p, func_p); +} + +/* ***************************************************************************/ +/**Loop while the channel is not done on the SDMA + * + * <b>Algorithm:</b>\n + * - Loop doing nothing but checking the I.API global variable to indicate + * that the channel has been completed (interrupt from SDMA) + * + * <b>Notes:</b>\n + * - The ISR must update the I.API global variable iapi_SDMAIntr. + * + * @param channel channel number to poll on + * + * @return none + */ +void iapi_lowSynchChannel(unsigned char channel) +{ + if (preempt_count() || in_interrupt()) { + while (!((1UL << channel) & iapi_SDMAIntr)) + ; + } else + GOTO_SLEEP(channel); + + iapi_SDMAIntr &= ~(1UL << channel); +} + +/* ***************************************************************************/ +/**Fill the buffer descriptor with the values given in parameter. + * + * @return none + */ +void +iapi_SetBufferDescriptor(bufferDescriptor *bd_p, unsigned char command, + unsigned char status, unsigned short count, + void *buffAddr, void *extBufferAddr) +{ + bd_p->mode.command = command; + bd_p->mode.status = status; + bd_p->mode.count = count; + if (buffAddr != NULL) { + bd_p->bufferAddr = iapi_Virt2Phys(buffAddr); + } else { + bd_p->bufferAddr = buffAddr; + } + bd_p->extBufferAddr = extBufferAddr; +} diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c new file mode 100644 index 000000000000..345d36433cf3 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c @@ -0,0 +1,503 @@ +/****************************************************************************** + * + * Copyright 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLowMcu.c + * + * $Id iapiLowMcu.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the LOW level functions of the I.API specific to MCU. + * + * + * http://compass/mot.com/go/115342679 + * + * $Log iapiLowMcu.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include <string.h> +#include <io.h> + +#include "epm.h" +#include "iapiLow.h" + +/* **************************************************************************** + * Function Section + *****************************************************************************/ +#ifdef MCU + +/* ***************************************************************************/ +/**Send a command on SDMA's channel zero. + * Check if buffer descriptor is already used by the sdma, if yes return + * an error as c0BDNum is wrong. + * + * <b>Notes</b>\n + * There is an upgrade in the script on the Context load command and + * the fact that the context structure has a fixed length of 20 or 24 + * depending on SDMA versions. + * + * @return + * - IAPI_SUCCESS + * - -iapi_errno if failure + */ +int +iapi_Channel0Command(channelDescriptor *cd_p, void *buf, + unsigned short nbyte, unsigned char command) +{ + channelControlBlock *ccb_p; + bufferDescriptor *bd_p; + int result = IAPI_SUCCESS; + unsigned char chNum; + + /* + * Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptpor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + + /* Is channel already in use ? */ + if (ccb_p->baseBDptr != NULL) { + result = IAPI_ERR_BD_ALLOCATED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + return -result; + } + + /* Allocation of buffer descriptors */ + bd_p = (bufferDescriptor *) MALLOC(sizeof(bufferDescriptor), SDMA_ERAM); + if (bd_p != NULL) { + ccb_p->baseBDptr = (bufferDescriptor *) iapi_Virt2Phys(bd_p); + } else { + result = IAPI_ERR_BD_ALLOCATION | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + return -result; + } + + /* Buffer descriptor setting */ + iapi_SetBufferDescriptor(bd_p, command, BD_WRAP | BD_DONE | BD_INTR, + nbyte, buf, NULL); + + /* Actually the transfer */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); + + /* Cleaning of allocation */ + FREE(bd_p); + ccb_p->baseBDptr = NULL; + + return IAPI_SUCCESS; + +} + +/* ***************************************************************************/ +/**Starts the channel (core specific register) + * + * <b>Algorithm:</b>\n + * - Bit numbered "channel" of HostEnStartReg register is set + * + * @param channel channel to start + * + * @return none + */ +void iapi_lowStartChannel(unsigned char channel) +{ + /* HSTART is a 'write-ones' register */ + writel(1UL << channel, SDMA_H_START_ADDR); +} + +/* ***************************************************************************/ +/**Stops the channel (core specific register) + * + * <b>Algorithm:</b> + * - Bit numbered "channel" of HostEnStopReg register is cleared + * + * <b>Notes:</b>\n + * - This is a write one to clear register + * + * @param channel channel to stop + * + * @return none + */ +void iapi_lowStopChannel(unsigned char channel) +{ + /* Another 'write-ones' register */ + writel(1UL << channel, SDMA_H_STATSTOP_ADDR); +} + +/* ***************************************************************************/ +/**Initialize the initial priority of registers and channel enable + * RAM from the MCU side. No channels are enabled, all priorities are set to 0. + * + * @return none + */ +void iapi_InitChannelTables(void) +{ + + /* No channel is enabled */ + iapi_memset((void *)&SDMA_CHNENBL_0, 0x00, + sizeof(unsigned long) * EVENTS_NUM); + /* All channels have priority 0 */ + iapi_memset((void *)&SDMA_CHNPRI_0, 0x00, + sizeof(unsigned long) * CH_NUM); +} + +/* ***************************************************************************/ +/** The host enable (HE), hosts override (HO), dsp enable (DE), dsp override + * (DO) registers are involved here. + * Host and Dsp enable registers are here to signify that the MCU or DSP side + * have prepared the appropriate buffers and are now ready. If the channel is + * owned by the MCU the override bit for that channel needs to be cleared : + * the host allows the channel to be used.\n + * + * Then the override bits can define (mcuOverride dspOverride):\n + * - 0 0 channel is public: transfer to/from MCU to DSP + * - 0 1 channel if owned by DSP + * - 1 0 channel if owned by MCU + * - 1 1 channel zero config + * + * See also :\n + * IAPI Table 1.1 "Channel configuration properties" + * + * @param channel channel to configure + * @param eventOverride event ownership + * @param mcuOverride ARM ownership + * @param dspOverride DSP ownership + * + * @return + * - -iapi_errno if the 3 override parameters are all set + * - IAPI_SUCCESS in other cases (valid cases) + */ +int +iapi_ChannelConfig(unsigned char channel, unsigned eventOverride, + unsigned mcuOverride, unsigned dspOverride) +{ + int result = IAPI_SUCCESS; + + if ((eventOverride == 1) && (mcuOverride == 1) && (dspOverride == 1)) { + result = IAPI_ERR_CONFIG_OVERRIDE; + iapi_errno = result; + return -result; + } else { + /* + * DSP side + */ + if (dspOverride) { + SDMA_H_DSPOVR &= ~(1 << channel); + } else { + SDMA_H_DSPOVR |= (1 << channel); + } + /* + * Event + */ + if (eventOverride) { + SDMA_H_EVTOVR &= ~(1 << channel); + } else { + SDMA_H_EVTOVR |= (1 << channel); + } + /* + * MCU side + */ + if (mcuOverride) { + SDMA_H_HOSTOVR &= ~(1 << channel); + } else { + SDMA_H_HOSTOVR |= (1 << channel); + } + } + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**Load the context data of a channel from SDMA + * + * <b>Algorithm:</b>\n + * - Setup BD with appropiate parameters + * - Start channel + * - Poll for answer + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to receive context data + * @param channel channel for which the context data is requested + * + * @return none + */ +void +iapi_lowGetContext(channelDescriptor *cd_p, void *buf, unsigned char channel) +{ + bufferDescriptor *bd_p; + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + /*Setup buffer descriptor with channel 0 command */ + iapi_SetBufferDescriptor(&bd_p[0], + C0_GETDM, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | + BD_EXTD), + (unsigned short)sizeof(contextData) / 4, buf, + (void *)(CHANNEL_CONTEXT_BASE_ADDRESS + + (sizeof(contextData) * channel / 4))); + /* Receive, polling method */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); +} + +/* ***************************************************************************/ +/**Read "size" byte /2 at SDMA address (address) and write them in buf + * + * <b>Algorithm:</b>\n + * - Setup BD with appropiate parameters (C0_GETPM) + * - Start channel + * - Poll for answer + * + * <b>Notes</b>\n + * - Parameter "size" is in bytes, it represents the size of "buf", e.g. + * the size in bytes of the script to be loaded. + * - Parameter "address" denotes the RAM address for the script in SDMA + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to receive the data + * @param size number of bytes to read + * @param address address in SDMA RAM to start reading from + * + * @return none + */ +void +iapi_lowGetScript(channelDescriptor *cd_p, void *buf, unsigned short size, + unsigned long address) +{ + bufferDescriptor *bd_p; + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + /*Setup buffer descriptor with channel 0 command */ + iapi_SetBufferDescriptor(&bd_p[0], C0_GETPM, (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | BD_EXTD), (unsigned short)size / 2, /*count in shorts */ + buf, (void *)address); + /* Receive, polling method */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); +} + +/* ***************************************************************************/ +/**Load a SDMA script to SDMA + * + * <b>Algorithm:</b>\n + * - Setup BD with appropiate parameters (C0_SETPM) + * - Start channel + * - Poll for answer + * + * <b>Notes</b>\b + * - Parameter "size" is in bytes, it represents the size of "buf", e.g. + * the size in bytes of the script to be uploaded. + * - Parameter "address" denotes the RAM address for the script in SDMA + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to the script + * @param size size of the script, in bytes + * @param address address in SDMA RAM to place the script + * + * @return none + */ +void +iapi_lowSetScript(channelDescriptor *cd_p, void *buf, unsigned short size, + unsigned long address) +{ + bufferDescriptor *bd_p; + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + /*Setup buffer descriptor with channel 0 command */ + iapi_SetBufferDescriptor(&bd_p[0], C0_SETPM, (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | BD_EXTD), (unsigned short)size / 2, /*count in shorts */ + buf, (void *)(address)); + /* Receive, polling method */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); +} + +/* ***************************************************************************/ +/**Load the context for a channel to SDMA + * + * <b>Algorithm:</b>\n + * - Send context and poll for answer. + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to context data + * @param channel channel to place the context for + * + * @return none + */ +void +iapi_lowSetContext(channelDescriptor *cd_p, void *buf, unsigned char channel) +{ + + bufferDescriptor *local_bd_p; +#ifdef SDMA_SKYE + + unsigned char command = 0; + + local_bd_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + command = channel << 3; + command = command | C0_SETCTX; + iapi_SetBufferDescriptor(&local_bd_p[0], + command, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP), + (unsigned short)(sizeof(contextData) / 4), + buf, NULL); +#else + + local_bd_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + iapi_SetBufferDescriptor(&local_bd_p[0], + C0_SETDM, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | + BD_EXTD), + (unsigned short)(sizeof(contextData) / 4), buf, + (void *)(2048 + + (sizeof(contextData) / 4) * channel)); +#endif + /* Send */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); + +} + +/* ***************************************************************************/ +/**Associate specified channel with the script starting at the + * specified address. Channel 0 command is used to load the set-up context + * for the channel. The address used must be generated by the GUI tool + * used to create RAM images for SDMA. + * + * <b>Algorithm:</b>\n + * - Set-up and load the context. + * + * @param *cd_p pointer to the channel descriptor of the channel + * @param *data_p: pointer to the data identifying the script to be associated + * with the channel + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : operation failed, return negated value of iapi_errno + */ + +int iapi_lowAssignScript(channelDescriptor *cd_p, script_data * data_p) +{ + contextData *chContext; /* context to be loaded for the channel */ + channelDescriptor *cd0_p; /* pointer to channel descriptor of channel 0 */ + int result = IAPI_SUCCESS; + + /*Verify passed data */ + if (cd_p == NULL || data_p == NULL) { + result = IAPI_ERR_INVALID_PARAMETER; + iapi_errno = result; + return -result; + } + + /* Allocate context and initialize PC to required script start adress */ + chContext = (contextData *) MALLOC(sizeof(contextData), SDMA_ERAM); + if (chContext == NULL) { + result = IAPI_ERR_B_ALLOC_FAILED | cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + iapi_memset(chContext, 0x00, sizeof(contextData)); + chContext->channelState.pc = data_p->load_address; + + /* Send by context the event mask,base address for peripheral + * and watermark level + */ + chContext->gReg[0] = data_p->event_mask2; + chContext->gReg[1] = data_p->event_mask1; + chContext->gReg[6] = data_p->shp_addr; + chContext->gReg[7] = data_p->wml; + if (data_p->per_addr) + chContext->gReg[2] = data_p->per_addr; + + /* Set transmited data to the CD */ + cd_p->watermarkLevel = data_p->wml; + cd_p->eventMask1 = data_p->event_mask1; + cd_p->eventMask2 = data_p->event_mask2; + + /* Get the cd0_p */ + cd0_p = (cd_p->ccb_ptr - cd_p->channelNumber)->channelDescriptor; + + /*load the context */ + iapi_lowSetContext(cd0_p, chContext, cd_p->channelNumber); + + /* release allocated memory */ + FREE(chContext); + + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/** Set the channels to be triggered by an event. The for every channel that + *must be triggered by the event, the corresponding bit from channel_map + *parameter must be set to 1. (e.g. for the event to trigger channels 31 and + *0 one must pass 0x80000001) + * + * + * <b>Algorithm:</b>\n + * - Update the register from Channel Enable RAM with the channel_map + * + * @param event event for which to set the channel association + * @param channel_map channels to be triggered by event. Put the corresponding + * bit from this 32-bit value to 1 for every channel that should be + * triggered by the event. + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : operation failed, return negated value of iapi_errno + */ +int +iapi_lowSetChannelEventMapping(unsigned char event, unsigned long channel_map) +{ + volatile unsigned long *channelEnableMatx; + int result = IAPI_SUCCESS; + + /* Check validity of event */ + if (event < EVENTS_NUM) { + channelEnableMatx = &SDMA_CHNENBL_0; + channelEnableMatx[event] |= channel_map; + return result; + } else { + result = IAPI_ERR_INVALID_PARAMETER | event; + iapi_errno = result; + return -result; + } +} + +#endif /* MCU */ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c new file mode 100644 index 000000000000..185489295523 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c @@ -0,0 +1,644 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddle.c + * + * $Id iapiMiddle.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the MIDDLE level functions of the I.API. + * + * + * + * + * $Log iapiMiddle.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include <string.h> + +#include "iapiLow.h" +#include "iapiMiddle.h" + +/* **************************************************************************** + * Global Variable Section + *****************************************************************************/ + +/* **************************************************************************** + * Function Section + *****************************************************************************/ + +/* ***************************************************************************/ +/**Allocates one Buffer Descriptor structure using information present in the + * channel descriptor. + * + * @param *ccb_p channel control block used to get the channel descriptor + * + * @return + * - pointer on the new Buffer Descriptor + * - NULL if allocation failed + * + */ +bufferDescriptor *iapi_AllocBD(channelControlBlock * ccb_p) +{ + bufferDescriptor *ptrBD = NULL; + + if (ccb_p->channelDescriptor->bufferDescNumber != 0) { +#ifdef CONFIG_SDMA_IRAM + channelDescriptor *cd_p = ccb_p->channelDescriptor; + if (cd_p->channelNumber >= MXC_DMA_CHANNEL_IRAM) { + ptrBD = (bufferDescriptor *) + MALLOC(ccb_p->channelDescriptor->bufferDescNumber * + sizeof(bufferDescriptor), SDMA_IRAM); + } else +#endif /*CONFIG_SDMA_IRAM */ + { + ptrBD = (bufferDescriptor *) + MALLOC(ccb_p->channelDescriptor->bufferDescNumber * + sizeof(bufferDescriptor), SDMA_ERAM); + } + } + if (ptrBD != NULL) { + ptrBD->mode.command = 0; + ptrBD->mode.status = 0; + ptrBD->mode.count = 0; + ptrBD->bufferAddr = NULL; + } + + return ptrBD; +} + +/* ***************************************************************************/ +/**Allocate one channel context data structure. + * + * @param **ctxd_p pointer to context data to be allocated + * @param channel channel number of context data structure + * + * @return + * - IAPI_SUCCESS + * - -iapi_errno if allocation failed + */ +int iapi_AllocContext(contextData **ctxd_p, unsigned char channel) +{ + contextData *ctxData; + int result = IAPI_SUCCESS; + + if (*ctxd_p != NULL) { + result = + IAPI_ERR_CC_ALREADY_DEFINED | IAPI_ERR_CH_AVAILABLE | + channel; + iapi_errno = result; + return -result; + } + + ctxData = (contextData *) MALLOC(sizeof(contextData), SDMA_ERAM); + + if (ctxData != NULL) { + *ctxd_p = ctxData; + return IAPI_SUCCESS; + + } else { + *ctxd_p = NULL; + result = + IAPI_ERR_CC_ALLOC_FAILED | IAPI_ERR_CH_AVAILABLE | channel; + iapi_errno = result; + return -result; + } +} + +/* ***************************************************************************/ +/**Allocates channel description and fill in with default values. + * + * <b>Algorithm:</b>\n + * - Check channel properties. + * - Then modifies the properties of the channel description with default + * + * @param **cd_p pointer to channel descriptor to be allocated + * @param channel channel number of channel descriptor + * + * @return + * - IAPI_SUCCESS + * - -iapi_errno if allocation failed + * + */ +int iapi_AllocChannelDesc(channelDescriptor **cd_p, unsigned char channel) +{ +#ifdef MCU + volatile unsigned long *chPriorities = &SDMA_CHNPRI_0; +#endif /* MCU */ + channelDescriptor *tmpCDptr; + int result = IAPI_SUCCESS; + + if (*cd_p != NULL) { + result = + IAPI_ERR_CD_ALREADY_DEFINED | IAPI_ERR_CH_AVAILABLE | + channel; + iapi_errno = result; + return -result; + } + + tmpCDptr = + (channelDescriptor *) MALLOC(sizeof(channelDescriptor), SDMA_ERAM); + + if (tmpCDptr != NULL) { + iapi_memcpy(tmpCDptr, &iapi_ChannelDefaults, + sizeof(channelDescriptor)); + tmpCDptr->channelNumber = channel; +#ifdef MCU + if (chPriorities[channel] != 0) { + tmpCDptr->priority = chPriorities[channel]; + } else { + chPriorities[channel] = tmpCDptr->priority; + } +#endif + *cd_p = tmpCDptr; + return IAPI_SUCCESS; + } else { + *cd_p = NULL; + result = + IAPI_ERR_CD_ALLOC_FAILED | IAPI_ERR_CH_AVAILABLE | channel; + iapi_errno = result; + return -result; + } +} + +/* ***************************************************************************/ +/**Changes channel description information after performing sanity checks. + * + * <b>Algorithm:</b>\n + * - Check channel properties. + * - Then modifies the properties of the channel description. + * + * @param *cd_p channel descriptor of the channel to change + * @param whatToChange control code indicating the desired change + * @param newval new value + * + * @return + * - IAPI_SUCCESS + * - IAPI_FAILURE if change failed + * + */ +int +iapi_ChangeChannelDesc(channelDescriptor *cd_p, unsigned char whatToChange, + unsigned long newval) +{ + bufferDescriptor *tmpBDptr; + unsigned char index = 0; + int result = IAPI_SUCCESS; + + /* verify parameter validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* verify channel descriptor initialization */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* verify channel is not in use */ + tmpBDptr = + (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (index = cd_p->bufferDescNumber; index > 0; index--) { + if (tmpBDptr->mode.status & BD_DONE) { + result = IAPI_ERR_CH_IN_USE | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + tmpBDptr++; + } + + /* Select the change accorded to the selector given in parameter */ + switch (whatToChange) { + + /* + * Channel Number + */ + case IAPI_CHANNELNUMBER: + /* Channel number can not be changed (description remains attached) */ + result = IAPI_ERR_CD_CHANGE_CH_NUMBER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + + /* + * Buffer Descriptor Number + */ + case IAPI_BUFFERDESCNUMBER: + if (newval < MAX_BD_NUM) { + if (newval != cd_p->bufferDescNumber) { + /* Free memory used for previous old data */ + if (cd_p->ccb_ptr->baseBDptr != NULL) { + tmpBDptr = (bufferDescriptor *) + iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + for (index = 0; + index < cd_p->bufferDescNumber; + index++) { + if (tmpBDptr->bufferAddr != + NULL) { + if (cd_p->trust == + FALSE) { + FREE(iapi_Phys2Virt(tmpBDptr->bufferAddr)); + } + } + tmpBDptr++; + } + FREE((bufferDescriptor *) + iapi_Phys2Virt((cd_p-> + ccb_ptr)->baseBDptr)); + } + (cd_p->ccb_ptr)->baseBDptr = NULL; + (cd_p->ccb_ptr)->currentBDptr = NULL; + /* Allocate and initialize structures */ + cd_p->bufferDescNumber = (unsigned char)newval; + cd_p->ccb_ptr->status.openedInit = FALSE; + if (IAPI_SUCCESS != + iapi_InitializeMemory(cd_p->ccb_ptr)) { + result = + IAPI_ERR_BD_ALLOCATION | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + cd_p->ccb_ptr->status.openedInit = TRUE; + } + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Buffer size + */ + case IAPI_BUFFERSIZE: + if (newval < MAX_BD_SIZE) { + if (newval != cd_p->bufferSize) { + /* Free memory used for previous old data */ + if (cd_p->ccb_ptr->baseBDptr != NULL) { + tmpBDptr = (bufferDescriptor *) + iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + for (index = 0; + index < cd_p->bufferDescNumber; + index++) { + if (cd_p->trust == FALSE) { + FREE(iapi_Phys2Virt + (tmpBDptr->bufferAddr)); + } + tmpBDptr++; + } + FREE((bufferDescriptor *) + iapi_Phys2Virt((cd_p-> + ccb_ptr)->baseBDptr)); + } + (cd_p->ccb_ptr)->baseBDptr = NULL; + (cd_p->ccb_ptr)->currentBDptr = NULL; + /* Allocate and initialize structures */ + cd_p->bufferSize = (unsigned short)newval; + cd_p->ccb_ptr->status.openedInit = FALSE; + if (IAPI_SUCCESS != + iapi_InitializeMemory(cd_p->ccb_ptr)) { + result = + IAPI_ERR_BD_ALLOCATION | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + cd_p->ccb_ptr->status.openedInit = TRUE; + } + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Blocking / non blocking feature + */ + case IAPI_BLOCKING: + if (newval < MAX_BLOCKING) { + cd_p->blocking = newval; + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Synchronization method + */ + case IAPI_CALLBACKSYNCH: + if (newval < MAX_SYNCH) { + cd_p->callbackSynch = newval; + iapi_ChangeCallbackISR(cd_p, cd_p->callbackISR_ptr); + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Ownership of the channel + */ + case IAPI_OWNERSHIP: +#ifdef DSP + result = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber; + iapi_errno = result; + return -result; +#endif /* DSP */ +#ifdef MCU + if (newval < MAX_OWNERSHIP) { + cd_p->ownership = newval; + iapi_ChannelConfig(cd_p->channelNumber, + (newval >> CH_OWNSHP_OFFSET_EVT) & 1, + (newval >> CH_OWNSHP_OFFSET_MCU) & 1, + (newval >> CH_OWNSHP_OFFSET_DSP) & + 1); + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + +#endif /* MCU */ + + /* + * Priority + */ + case IAPI_PRIORITY: +#ifdef DSP + result = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber; + iapi_errno = result; + return -result; +#endif /* DSP */ + +#ifdef MCU + if (newval < MAX_CH_PRIORITY) { + volatile unsigned long *ChannelPriorities = + &SDMA_CHNPRI_0; + ChannelPriorities[cd_p->channelNumber] = newval; + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } +#endif /* MCU */ + + /* + * "Trust" property + */ + case IAPI_TRUST: + if (newval < MAX_TRUST) { + if (cd_p->trust != newval) { + cd_p->trust = newval; + if (newval == FALSE) { + if (IAPI_SUCCESS != + iapi_InitializeMemory + (cd_p->ccb_ptr)) { + result = + IAPI_ERR_BD_ALLOCATION | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + } + } + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Callback function pointer + */ + case IAPI_CALLBACKISR_PTR: + if ((void *)newval != NULL) { + { + union { + void *voidstar; + void (*funcptr) (channelDescriptor * + cd_p, void *arg); + } value; + value.voidstar = (void *)newval; + cd_p->callbackISR_ptr = value.funcptr; + } + iapi_ChangeCallbackISR(cd_p, cd_p->callbackISR_ptr); + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Channel Control Block pointer + */ + case IAPI_CCB_PTR: + cd_p->ccb_ptr = (channelControlBlock *) newval; + cd_p->ccb_ptr->channelDescriptor = cd_p; + break; + + /* + * WRAP/UNWRAP + */ + case IAPI_BDWRAP: + /* point to first BD */ + tmpBDptr = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + /* to point to last BD */ + tmpBDptr += cd_p->bufferDescNumber - 1; + if (newval == TRUE) { + /* wrap last BD */ + tmpBDptr->mode.status |= BD_WRAP; + break; + } else if (newval == FALSE) { + /* unwrap last BD */ + tmpBDptr->mode.status &= ~BD_WRAP; + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Watermark level + */ + case IAPI_WML: +#ifdef DSP + result = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber; + iapi_errno = result; + return -result; +#endif /* DSP */ +#ifdef MCU + if (newval < MAX_WML) { + if (cd_p->watermarkLevel != newval) { + cd_p->watermarkLevel = newval; + } + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } +#endif /* MCU */ + + /* + * Detect errors + */ + default: + result = IAPI_ERR_CD_CHANGE_UNKNOWN | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**Initialize a table of function pointers that contain the interrupt Service + * Routine callback pointers for the SDMA channels with a default value + * + * <b>Algorithm:</b>\n + * - Loop on each element of the global IAPI variable callbackIsrTable + * + * @param *func_p default callback functon for all SDMA channels + * + * @return none + */ +void +iapi_InitializeCallbackISR(void (*func_p) (channelDescriptor *cd_p, void *arg)) +{ + unsigned long chCnt; + + for (chCnt = 0; chCnt < CH_NUM; chCnt++) { + callbackIsrTable[chCnt] = func_p; + } +} + +/* ***************************************************************************/ +/**For the specified channel control block, attach the array of buffer + * descriptors, the channel description structure and initialize channel's + * status using information in the channel descriptor. + * + * @param *ccb_p pointer to channel control block + * + * @return none + * + */ +int iapi_InitializeMemory(channelControlBlock *ccb_p) +{ + bufferDescriptor *bd_p; + unsigned char index; + int result = IAPI_SUCCESS; + + /* Attach the array of Buffer descriptors */ + bd_p = iapi_AllocBD(ccb_p); + if (bd_p != NULL) { + ccb_p->baseBDptr = (bufferDescriptor *) iapi_Virt2Phys(bd_p); + ccb_p->currentBDptr = ccb_p->baseBDptr; + for (index = 0; + index < ccb_p->channelDescriptor->bufferDescNumber - 1; + index++) { + if (ccb_p->channelDescriptor->trust == TRUE) { + iapi_SetBufferDescriptor(bd_p, + (unsigned char) + ccb_p->channelDescriptor->dataSize, + BD_CONT | BD_EXTD, + ccb_p->channelDescriptor->bufferSize, + NULL, NULL); + } else { + if (ccb_p->channelDescriptor->bufferSize != 0) { + iapi_SetBufferDescriptor(bd_p, + (unsigned char) + ccb_p->channelDescriptor->dataSize, BD_CONT | BD_EXTD, ccb_p->channelDescriptor->bufferSize, MALLOC(ccb_p->channelDescriptor->bufferSize, SDMA_ERAM), NULL); + } + } + bd_p++; + } + + if (ccb_p->channelDescriptor->trust == TRUE) { + iapi_SetBufferDescriptor(bd_p, + (unsigned char) + ccb_p->channelDescriptor-> + dataSize, + BD_EXTD | BD_WRAP | BD_INTR, + ccb_p-> + channelDescriptor->bufferSize, + NULL, NULL); + } else { + if (ccb_p->channelDescriptor->bufferSize != 0) { + iapi_SetBufferDescriptor(bd_p, + (unsigned char) + ccb_p->channelDescriptor->dataSize, + BD_EXTD | BD_WRAP | + BD_INTR, + ccb_p->channelDescriptor->bufferSize, + MALLOC + (ccb_p->channelDescriptor->bufferSize, + SDMA_ERAM), NULL); + } + } + } else { + result = IAPI_ERR_BD_ALLOCATION; + return -result; + } + return result; +} diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c new file mode 100644 index 000000000000..8e7a614fd76a --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddleMcu.c + * + * $Id iapiMiddleMcu.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the MIDDLE level functions of the I.API specific to MCU. + * + * + * + * + * $Log iapiMiddleMcu.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include <string.h> + +#include "iapiLow.h" +#include "iapiMiddle.h" + +/* **************************************************************************** + * Global Variable Section + *****************************************************************************/ + +/*extern void * __HEAP_START; +extern void * __HEAP_END; +*/ + +/* **************************************************************************** + * Function Section + *****************************************************************************/ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c new file mode 100644 index 000000000000..c188d36eda00 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiOS.c + * + * $Id iapiOS.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the OS level functions of the I.API - are OS dependant and must + * be provided by the user of I.API. + * + * + * / + * + * $Log iapiOS.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include "iapiLow.h" + +/** + * Function Section + */ +#ifdef CONFIG_SDMA_IRAM +void *(*iapi_iram_Malloc) (size_t size); +#endif /*CONFIG_SDMA_IRAM */ + +void *(*iapi_Malloc) (size_t size); +void (*iapi_Free) (void *ptr); + +void *(*iapi_Virt2Phys) (void *ptr); +void *(*iapi_Phys2Virt) (void *ptr); + +void (*iapi_WakeUp) (int); +void (*iapi_GotoSleep) (int); +void (*iapi_InitSleep) (int); + +void *(*iapi_memcpy) (void *dest, const void *src, size_t count); +void *(*iapi_memset) (void *dest, int c, size_t count); + +void (*iapi_EnableInterrupts) (void); +void (*iapi_DisableInterrupts) (void); + +int (*iapi_GetChannel) (int); +int (*iapi_ReleaseChannel) (int); |