]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c
linux-2.6.35.3-fsl-10.3.2.txt.gz patch applied
[linux-imx.git] / arch / arm / plat-mxc / sdma / iapi / src / iapiLowMcu.c
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 (file)
index 0000000..345d364
--- /dev/null
@@ -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 */