4134 lines
123 KiB
Diff
4134 lines
123 KiB
Diff
---
|
|
drivers/dma/Kconfig | 9
|
|
drivers/dma/Makefile | 1
|
|
drivers/dma/pch_dma/Makefile | 5
|
|
drivers/dma/pch_dma/pch_common.h | 146 ++++
|
|
drivers/dma/pch_dma/pch_debug.h | 60 +
|
|
drivers/dma/pch_dma/pch_dma_hal.c | 1203 +++++++++++++++++++++++++++++++++++++
|
|
drivers/dma/pch_dma/pch_dma_hal.h | 594 ++++++++++++++++++
|
|
drivers/dma/pch_dma/pch_dma_main.c | 1026 +++++++++++++++++++++++++++++++
|
|
drivers/dma/pch_dma/pch_dma_main.h | 264 ++++++++
|
|
drivers/dma/pch_dma/pch_dma_pci.c | 694 +++++++++++++++++++++
|
|
drivers/dma/pch_dma/pch_dma_pci.h | 74 ++
|
|
11 files changed, 4076 insertions(+)
|
|
|
|
--- a/drivers/dma/Kconfig
|
|
+++ b/drivers/dma/Kconfig
|
|
@@ -51,6 +51,15 @@ config LNW_DMA_DEBUG
|
|
help
|
|
Enable logging in the LNW DMA drivers
|
|
|
|
+config PCH_UART_DMA
|
|
+ tristate "PCH DMA Controller"
|
|
+ depends on PCI && SERIAL_8250_PCH_DMA
|
|
+ select DMA_ENGINE
|
|
+ default y
|
|
+ help
|
|
+ This value must equal to SERIAL_8250_PCH. This config PCH_UART_DMA is
|
|
+ referred by PCH UART.
|
|
+
|
|
config INTEL_IOATDMA
|
|
tristate "Intel I/OAT DMA support"
|
|
depends on PCI && X86
|
|
--- a/drivers/dma/Makefile
|
|
+++ b/drivers/dma/Makefile
|
|
@@ -14,4 +14,5 @@ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
|
|
obj-$(CONFIG_SH_DMAE) += shdma.o
|
|
obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
|
|
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
|
|
+obj-$(CONFIG_PCH_UART_DMA) += pch_dma/
|
|
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
|
|
--- /dev/null
|
|
+++ b/drivers/dma/pch_dma/Makefile
|
|
@@ -0,0 +1,5 @@
|
|
+#enable for debug;this can be added in Kconfig
|
|
+#EXTRA_CFLAGS += -DDEBUG
|
|
+
|
|
+obj-$(CONFIG_PCH_UART_DMA) += pch_dma.o
|
|
+pch_dma-objs := pch_dma_pci.o pch_dma_hal.o pch_dma_main.o
|
|
--- /dev/null
|
|
+++ b/drivers/dma/pch_dma/pch_common.h
|
|
@@ -0,0 +1,146 @@
|
|
+/*!
|
|
+ * @file ioh_common.h
|
|
+ * @brief Provides the macro definitions used by all files.
|
|
+ * @version 1.0.0.0
|
|
+ * @section
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * History:
|
|
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * created:
|
|
+ * WIPRO 03/07/2009
|
|
+ * modified:
|
|
+ * WIPRO 05/08/2009
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __IOH_COMMON_H__
|
|
+#define __IOH_COMMON_H__
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_WRITE8
|
|
+@brief Macro for writing 8 bit data to an io/mem address
|
|
+*/
|
|
+#define IOH_WRITE8(val, addr) iowrite8((val), (void __iomem *)(addr))
|
|
+/*! @ingroup Global
|
|
+@def IOH_LOG
|
|
+@brief Macro for writing 16 bit data to an io/mem address
|
|
+*/
|
|
+#define IOH_WRITE16(val, addr) iowrite16((val), (void __iomem *)(addr))
|
|
+/*! @ingroup Global
|
|
+@def IOH_LOG
|
|
+@brief Macro for writing 32 bit data to an io/mem address
|
|
+*/
|
|
+#define IOH_WRITE32(val, addr) iowrite32((val), (void __iomem *)(addr))
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ8
|
|
+@brief Macro for reading 8 bit data from an io/mem address
|
|
+*/
|
|
+#define IOH_READ8(addr) ioread8((void __iomem *)(addr))
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ16
|
|
+@brief Macro for reading 16 bit data from an io/mem address
|
|
+*/
|
|
+#define IOH_READ16(addr) ioread16((void __iomem *)(addr))
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ32
|
|
+@brief Macro for reading 32 bit data from an io/mem address
|
|
+*/
|
|
+#define IOH_READ32(addr) ioread32((void __iomem *)(addr))
|
|
+/*! @ingroup Global
|
|
+@def IOH_WRITE32_F
|
|
+@brief Macro for writing 32 bit data to an io/mem address
|
|
+*/
|
|
+#define IOH_WRITE32_F(val, addr) do \
|
|
+ { IOH_WRITE32((val), (addr)); (void)IOH_READ32((addr)); } while (0);
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_WRITE_BYTE
|
|
+@brief Macro for writing 1 byte data to an io/mem address
|
|
+*/
|
|
+#define IOH_WRITE_BYTE IOH_WRITE8
|
|
+/*! @ingroup Global
|
|
+@def IOH_WRITE_WORD
|
|
+@brief Macro for writing 1 word data to an io/mem address
|
|
+*/
|
|
+#define IOH_WRITE_WORD IOH_WRITE16
|
|
+/*! @ingroup Global
|
|
+@def IOH_WRITE_LONG
|
|
+@brief Macro for writing long data to an io/mem address
|
|
+*/
|
|
+#define IOH_WRITE_LONG IOH_WRITE32
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ_BYTE
|
|
+@brief Macro for reading 1 byte data from an io/mem address
|
|
+*/
|
|
+#define IOH_READ_BYTE IOH_READ8
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ_WORD
|
|
+@brief Macro for reading 1 word data from an io/mem address
|
|
+*/
|
|
+#define IOH_READ_WORD IOH_READ16
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ_LONG
|
|
+@brief Macro for reading long data from an io/mem address
|
|
+*/
|
|
+#define IOH_READ_LONG IOH_READ32
|
|
+
|
|
+/* Bit Manipulation Macros */
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ_LONG
|
|
+@brief macro to set a specified bit(mask) at the
|
|
+ specified address
|
|
+*/
|
|
+#define IOH_SET_ADDR_BIT(addr, bitmask) IOH_WRITE_LONG((IOH_READ_LONG(addr) |\
|
|
+ (bitmask)), (addr))
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ_LONG
|
|
+@brief macro to clear a specified bit(mask) at the specified address
|
|
+*/
|
|
+#define IOH_CLR_ADDR_BIT(addr, bitmask) IOH_WRITE_LONG((IOH_READ_LONG(addr) &\
|
|
+ ~(bitmask)), (addr))
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ_LONG
|
|
+@brief macro to set a specified bitmask for a variable
|
|
+*/
|
|
+#define IOH_SET_BITMSK(var, bitmask) ((var) |= (bitmask))
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ_LONG
|
|
+@brief macro to clear a specified bitmask for a variable
|
|
+*/
|
|
+#define IOH_CLR_BITMSK(var, bitmask) ((var) &= (~(bitmask)))
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ_LONG
|
|
+@brief macro to set a specified bit for a variable
|
|
+*/
|
|
+#define IOH_SET_BIT(var, bit) ((var) |= (1<<(bit)))
|
|
+
|
|
+/*! @ingroup Global
|
|
+@def IOH_READ_LONG
|
|
+@brief macro to clear a specified bit for a variable
|
|
+*/
|
|
+#define IOH_CLR_BIT(var, bit) ((var) &= ~(1<<(bit)))
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/drivers/dma/pch_dma/pch_debug.h
|
|
@@ -0,0 +1,60 @@
|
|
+/*!
|
|
+ * @file ioh_debug.h
|
|
+ * @brief Provides the macro definitions used for debugging.
|
|
+ * @version 1.0.0.0
|
|
+ * @section
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * History:
|
|
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * created:
|
|
+ * WIPRO 03/07/2009
|
|
+ * modified:
|
|
+ * WIPRO 05/08/2009
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __IOH_DEBUG_H__
|
|
+#define __IOH_DEBUG_H__
|
|
+
|
|
+#ifdef MODULE
|
|
+#define IOH_LOG(level, fmt, args...) printk(level "%s:" fmt "\n",\
|
|
+ THIS_MODULE->name, ##args)
|
|
+#else
|
|
+#define IOH_LOG(level, fmt, args...) printk(level "%s:" fmt "\n" ,\
|
|
+ __FILE__, ##args)
|
|
+#endif
|
|
+
|
|
+
|
|
+#ifdef DEBUG
|
|
+ #define IOH_DEBUG(fmt, args...) IOH_LOG(KERN_DEBUG, fmt, ##args)
|
|
+#else
|
|
+ #define IOH_DEBUG(fmt, args...)
|
|
+#endif
|
|
+
|
|
+#ifdef IOH_TRACE_ENABLED
|
|
+ #define IOH_TRACE IOH_DEBUG
|
|
+#else
|
|
+ #define IOH_TRACE(fmt, args...)
|
|
+#endif
|
|
+
|
|
+#define IOH_TRACE_ENTER IOH_TRACE("Enter %s", __func__)
|
|
+#define IOH_TRACE_EXIT IOH_TRACE("Exit %s", __func__)
|
|
+
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/drivers/dma/pch_dma/pch_dma_hal.c
|
|
@@ -0,0 +1,1203 @@
|
|
+/**
|
|
+ * @file ioh_dma_hal.c
|
|
+ *
|
|
+ * @brief
|
|
+ * This file defines the IOH_DMA_CONTROLLER HAL API functions.
|
|
+ *
|
|
+ * @version 0.90
|
|
+ * @section
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
+ *
|
|
+ * <hr>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * History:
|
|
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * created:
|
|
+ * WIPRO 03/07/2009
|
|
+ * modified:
|
|
+ * WIPRO 08/14/2009
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/module.h>
|
|
+
|
|
+#include "pch_common.h"
|
|
+#include "pch_debug.h"
|
|
+#include "pch_dma_hal.h"
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def IOH_DMA_BIT_SET
|
|
+ @brief Macro for setting selected bits of a register.
|
|
+ @remarks This macro is used to set the selected bits
|
|
+ at a given 32 bit location. Normally it is
|
|
+ used to set the bits of given register.
|
|
+*/
|
|
+#define IOH_DMA_BIT_SET(reg, bitmask) \
|
|
+ IOH_WRITE_LONG(((IOH_READ_LONG((reg)) | bitmask)), (reg))
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def IOH_DMA_BIT_CLEAR
|
|
+ @brief Macro for re-setting selected bits of a register.
|
|
+ @remarks This macro is used to reset the selected bits
|
|
+ at a given 32 bit location. Normally it is
|
|
+ used to reset the bits of given register.
|
|
+*/
|
|
+#define IOH_DMA_BIT_CLEAR(regAddr, bitMask) \
|
|
+ IOH_WRITE_LONG((IOH_READ_LONG((regAddr)) & (~(bitMask))), \
|
|
+ (regAddr))
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DEFAULT_CONTROL_REGISTER_VALUE
|
|
+ @brief Macro for setting selected bits of control register.
|
|
+ @remarks This macro is used to set the mode and direction
|
|
+ bit of the control register of a specific
|
|
+ channel without affecting the settings of other
|
|
+ channels.
|
|
+*/
|
|
+#define DEFAULT_CONTROL_REGISTER_VALUE (0x33333333)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def dma_clear_interrupt_status
|
|
+ @brief Macro for clearing the interrupt status of the
|
|
+ DMA.
|
|
+ @remarks This macro is used to clear the interrupt status
|
|
+ bits of the DMA during handling of interrupts.
|
|
+*/
|
|
+#define dma_clear_interrupt_status(addr, stat0, stat2) \
|
|
+do { \
|
|
+ IOH_WRITE_LONG((stat0), ((addr) + DMA_STS0_OFFSET)); \
|
|
+ IOH_WRITE_LONG((stat2), ((addr) + DMA_STS2_OFFSET)); \
|
|
+} while (0)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def dma_get_interrupt_status
|
|
+ @brief Macro for getting the interrupt status of a
|
|
+ specific channel
|
|
+ @remarks This macro is used to get the interrupt status
|
|
+ of the DMA during handling of interrupts.
|
|
+*/
|
|
+#define dma_get_interrupt_status(ch, stat0, stat2) \
|
|
+( \
|
|
+ ((ch) < 8) ? \
|
|
+ (((stat0) & (DMA_INTERRUPT_OCCUR << ch)) != 0) \
|
|
+ : \
|
|
+ (((stat2) & (DMA_INTERRUPT_OCCUR << (ch - 8))) != 0) \
|
|
+)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def dma_get_abort_status
|
|
+ @brief Macro for getting the abort status of a specific
|
|
+ channel.
|
|
+ @remarks This macro is used to get the abort status
|
|
+ of the DMA during handling of interrupts.
|
|
+*/
|
|
+#define dma_get_abort_status(ch, stat0, stat2) \
|
|
+( \
|
|
+ ((ch) < 8) ? \
|
|
+ (((stat0) & (DMA_ABORT_OCCUR << ch)) != 0) \
|
|
+ : \
|
|
+ (((stat2) & (DMA_ABORT_OCCUR << (ch - 8))) != 0) \
|
|
+)
|
|
+
|
|
+/* Global Varibles */
|
|
+/*! @ingroup Global
|
|
+ @var ioh_dma_channel_info
|
|
+ @brief Retains the specific channel information.
|
|
+*/
|
|
+struct ioh_dma_controller_info ioh_dma_channel_info[IOH_DMA_CHANNELS_MAX];
|
|
+
|
|
+/* Channel Allocation Table for DMA */
|
|
+/*! @ingroup Global
|
|
+ @var ioh_dma_channel_table
|
|
+ @brief Retains the specific channel allocation
|
|
+ information.
|
|
+*/
|
|
+struct ioh_dma_channel_alloc_table ioh_dma_channel_table[IOH_DMA_CHANNELS_MAX]
|
|
+= {
|
|
+ /* 4 channel DMA device0 (Reserved for GE.) */
|
|
+ {IOH_DMA_4CH0, IOH_DMA_TX_DATA_REQ0, PCI_DEVICE_ID_IOH_SPI, 0, 0, 0, 0},
|
|
+ {IOH_DMA_4CH0, IOH_DMA_RX_DATA_REQ0, PCI_DEVICE_ID_IOH_SPI, 1, 0, 0, 0},
|
|
+ {IOH_DMA_4CH0, 0, 0, 2, 0, 0, 0},
|
|
+ {IOH_DMA_4CH0, 0, 0, 3, 0, 0, 0},
|
|
+
|
|
+ /* 4 channel DMA device1 (Not reserved.) */
|
|
+ {IOH_DMA_4CH1, 0, 0, 0, 0, 0, 0},
|
|
+ {IOH_DMA_4CH1, 0, 0, 1, 0, 0, 0},
|
|
+ {IOH_DMA_4CH1, 0, 0, 2, 0, 0, 0},
|
|
+ {IOH_DMA_4CH1, 0, 0, 3, 0, 0, 0},
|
|
+
|
|
+ /* 4 channel DMA device2 (Not reserved.) */
|
|
+ {IOH_DMA_4CH2, 0, 0, 0, 0, 0, 0},
|
|
+ {IOH_DMA_4CH2, 0, 0, 1, 0, 0, 0},
|
|
+ {IOH_DMA_4CH2, 0, 0, 2, 0, 0, 0},
|
|
+ {IOH_DMA_4CH2, 0, 0, 3, 0, 0, 0},
|
|
+
|
|
+ /* 4 channel DMA device3 (Not reserved.) */
|
|
+ {IOH_DMA_4CH3, 0, 0, 0, 0, 0, 0},
|
|
+ {IOH_DMA_4CH3, 0, 0, 1, 0, 0, 0},
|
|
+ {IOH_DMA_4CH3, 0, 0, 2, 0, 0, 0},
|
|
+ {IOH_DMA_4CH3, 0, 0, 3, 0, 0, 0},
|
|
+
|
|
+ /* 4 channel DMA device4 (Not reserved.) */
|
|
+ {IOH_DMA_4CH4, 0, 0, 0, 0, 0, 0},
|
|
+ {IOH_DMA_4CH4, 0, 0, 1, 0, 0, 0},
|
|
+ {IOH_DMA_4CH4, 0, 0, 2, 0, 0, 0},
|
|
+ {IOH_DMA_4CH4, 0, 0, 3, 0, 0, 0},
|
|
+
|
|
+ /* 8 channel DMA device0 (Reserved for GE.) */
|
|
+ {IOH_DMA_8CH0, IOH_DMA_TX_DATA_REQ0, PCI_DEVICE_ID_IOH_UART0, 0, 0, 0,
|
|
+ 0},
|
|
+ {IOH_DMA_8CH0, IOH_DMA_RX_DATA_REQ0, PCI_DEVICE_ID_IOH_UART0, 1, 0, 0,
|
|
+ 0},
|
|
+ {IOH_DMA_8CH0, IOH_DMA_TX_DATA_REQ0, PCI_DEVICE_ID_IOH_UART1, 2, 0, 0,
|
|
+ 0},
|
|
+ {IOH_DMA_8CH0, IOH_DMA_RX_DATA_REQ0, PCI_DEVICE_ID_IOH_UART1, 3, 0, 0,
|
|
+ 0},
|
|
+ {IOH_DMA_8CH0, IOH_DMA_TX_DATA_REQ0, PCI_DEVICE_ID_IOH_UART2, 4, 0, 0,
|
|
+ 0},
|
|
+ {IOH_DMA_8CH0, IOH_DMA_RX_DATA_REQ0, PCI_DEVICE_ID_IOH_UART2, 5, 0, 0,
|
|
+ 0},
|
|
+ {IOH_DMA_8CH0, IOH_DMA_TX_DATA_REQ0, PCI_DEVICE_ID_IOH_UART3, 6, 0, 0,
|
|
+ 0},
|
|
+ {IOH_DMA_8CH0, IOH_DMA_RX_DATA_REQ0, PCI_DEVICE_ID_IOH_UART3, 7, 0, 0,
|
|
+ 0},
|
|
+
|
|
+ /* 8 channel DMA device1 */
|
|
+ {IOH_DMA_8CH1, 0, 0, 0, 0, 0, 0},
|
|
+ {IOH_DMA_8CH1, 0, 0, 1, 0, 0, 0},
|
|
+ {IOH_DMA_8CH1, 0, 0, 2, 0, 0, 0},
|
|
+ {IOH_DMA_8CH1, 0, 0, 3, 0, 0, 0},
|
|
+ {IOH_DMA_8CH1, 0, 0, 4, 0, 0, 0},
|
|
+ {IOH_DMA_8CH1, 0, 0, 5, 0, 0, 0},
|
|
+ {IOH_DMA_8CH1, 0, 0, 6, 0, 0, 0},
|
|
+ {IOH_DMA_8CH1, 0, 0, 7, 0, 0, 0},
|
|
+
|
|
+ /* 8 channel DMA device2 */
|
|
+ {IOH_DMA_8CH2, 0, 0, 0, 0, 0, 0},
|
|
+ {IOH_DMA_8CH2, 0, 0, 1, 0, 0, 0},
|
|
+ {IOH_DMA_8CH2, 0, 0, 2, 0, 0, 0},
|
|
+ {IOH_DMA_8CH2, 0, 0, 3, 0, 0, 0},
|
|
+ {IOH_DMA_8CH2, 0, 0, 4, 0, 0, 0},
|
|
+ {IOH_DMA_8CH2, 0, 0, 5, 0, 0, 0},
|
|
+ {IOH_DMA_8CH2, 0, 0, 6, 0, 0, 0},
|
|
+ {IOH_DMA_8CH2, 0, 0, 7, 0, 0, 0},
|
|
+
|
|
+ /* 8 channel DMA device3 (Doubts in allocating.) */
|
|
+ {IOH_DMA_8CH3, 0, 0, 0, 0, 0, 0},
|
|
+ {IOH_DMA_8CH3, 0, 0, 1, 0, 0, 0},
|
|
+ {IOH_DMA_8CH3, 0, 0, 2, 0, 0, 0},
|
|
+ {IOH_DMA_8CH3, 0, 0, 3, 0, 0, 0},
|
|
+ {IOH_DMA_8CH3, 0, 0, 4, 0, 0, 0},
|
|
+ {IOH_DMA_8CH3, 0, 0, 5, 0, 0, 0},
|
|
+ {IOH_DMA_8CH3, 0, 0, 6, 0, 0, 0},
|
|
+ {IOH_DMA_8CH3, 0, 0, 7, 0, 0, 0},
|
|
+
|
|
+ /* 12 channel DMA device0 */
|
|
+ {IOH_DMA_12CH0, 0, 0, 0, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 1, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 2, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 3, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 4, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 5, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 6, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 7, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 8, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 9, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 10, 0, 0, 0},
|
|
+ {IOH_DMA_12CH0, 0, 0, 11, 0, 0, 0}
|
|
+};
|
|
+
|
|
+/* Function Definitions */
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn void __init dma_init(u32 base, u32 dev_type)
|
|
+ @brief Initializes local data structures for the DMAC device.
|
|
+ @remarks This function is called when a DMA device is detected.
|
|
+ It initializes the data structures associated
|
|
+ with the obtained device. The main tasks
|
|
+ performed by this function are:
|
|
+ - Waits until the status of a DMA channel
|
|
+ becomes idle and then disables it.
|
|
+ - Initializes the data structures that can
|
|
+ be used further.
|
|
+
|
|
+ @param base [@ref IN] The base address.
|
|
+ @param dev_type [@ref IN] The type of the device.
|
|
+
|
|
+ @return None.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_probe
|
|
+ */
|
|
+
|
|
+void __init dma_init(u32 base, u32 dev_type)
|
|
+{
|
|
+ int i;
|
|
+ u32 counter;
|
|
+ u16 DMAStatus;
|
|
+
|
|
+ for (i = 0; i < IOH_DMA_CHANNELS_MAX; i++) {
|
|
+ if (ioh_dma_channel_table[i].dma_dev_id == dev_type) {
|
|
+ counter = COUNTER_LIMIT;
|
|
+
|
|
+ ioh_dma_channel_table[i].ch_found = 1;
|
|
+ ioh_dma_channel_table[i].ch_alloced = 0;
|
|
+ ioh_dma_channel_table[i].base = base;
|
|
+
|
|
+ do {
|
|
+ get_dma_status(i, &DMAStatus);
|
|
+ } while ((counter--) && (DMAStatus != DMA_STATUS_IDLE));
|
|
+
|
|
+ (void)dma_disable_ch(i);
|
|
+ IOH_DEBUG("dma_init -> Channel %d disabled.\n", i);
|
|
+
|
|
+ (void)dma_enable_disable_interrupt
|
|
+ (i, IOH_DMA_INTERRUPT_DISABLE);
|
|
+ IOH_DEBUG
|
|
+ ("dma_init -> Interrupt disabled for channel %d.\n",
|
|
+ i);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function dma_init invoked successfully.\n");
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn void dma_exit(u32 dev_type)
|
|
+ @brief De-initializes the DMA device.
|
|
+ @remarks The main tasks performed by this function are:
|
|
+ - Waits for a small interval for each channel
|
|
+ if the channel is not idle so that it can
|
|
+ complete its transfer.
|
|
+ - Disables the channel.
|
|
+ - Disables the concerned interrupt.
|
|
+
|
|
+ @param dev_type [@ref IN] The type of the device.
|
|
+
|
|
+ @return None
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_remove
|
|
+ - ioh_dma_suspend
|
|
+*/
|
|
+void dma_exit(u32 dev_type)
|
|
+{
|
|
+ int i;
|
|
+ u32 counter;
|
|
+ u16 DMAStatus;
|
|
+
|
|
+ for (i = 0; i < IOH_DMA_CHANNELS_MAX; i++) {
|
|
+ if (ioh_dma_channel_table[i].dma_dev_id == dev_type &&
|
|
+ ioh_dma_channel_table[i].ch_found == 1) {
|
|
+ counter = COUNTER_LIMIT;
|
|
+ get_dma_status(i, &DMAStatus);
|
|
+
|
|
+ while ((counter > 0) &&
|
|
+ (DMAStatus != DMA_STATUS_IDLE)) {
|
|
+ counter--;
|
|
+ get_dma_status(i, &DMAStatus);
|
|
+ }
|
|
+
|
|
+ (void)dma_disable_ch(i);
|
|
+ IOH_DEBUG("dma_exit -> Channel %d disabled.\n", i);
|
|
+
|
|
+ (void)dma_enable_disable_interrupt
|
|
+ (i, IOH_DMA_INTERRUPT_DISABLE);
|
|
+ IOH_DEBUG("dma_exit -> Interrupt disabled for channel "
|
|
+ "%d.\n", i);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function dma_exit invoked successfully.\n");
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_set_mode(int channel,
|
|
+ struct ioh_dma_mode_param stModeParam)
|
|
+ @brief Sets the Mode of transfer for DMA.
|
|
+ @remarks Does the setting of direction of transfer, access size
|
|
+ type and transfer mode. This function does not
|
|
+ perform any register write. The main tasks
|
|
+ performed by this function are:
|
|
+ - Set the DMATransferDirection field of @ref
|
|
+ ioh_dma_channel_info with the direction of
|
|
+ transfer specified.
|
|
+ - Set the DMAAccessSize field of @ref
|
|
+ ioh_dma_channel_info with the Access Size Type
|
|
+ specified.
|
|
+ - Set the DMATransferMode field of @ref
|
|
+ ioh_dma_channel_info structure with the DMA mode
|
|
+ specified.
|
|
+
|
|
+ @param channel [@ref IN] The channel for which mode is to be set.
|
|
+ @param stModeParam [@ref IN] Structure which contains the
|
|
+ parameters for the setting of Mode.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+
|
|
+ @see
|
|
+ - ioh_set_dma_mode
|
|
+ */
|
|
+int dma_set_mode(int channel, struct ioh_dma_mode_param stModeParam)
|
|
+{
|
|
+ ioh_dma_channel_info[channel].DMAAccessSize = stModeParam.DMASizeType;
|
|
+ ioh_dma_channel_info[channel].DMATransferMode =
|
|
+ stModeParam.DMATransferMode;
|
|
+ ioh_dma_channel_info[channel].DMATransferDirection =
|
|
+ stModeParam.TransferDirection;
|
|
+
|
|
+ IOH_DEBUG("Function dma_set_mode returns %d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_set_addr(int channel, u32 iaddr, u32 oaddr)
|
|
+ @brief Sets the Inside and Outside address in the case
|
|
+ of ONE SHOT MODE
|
|
+ @remarks This function updates Inside address and outside
|
|
+ address to be set in ONE SHOT mode. The main
|
|
+ tasks performed by this function are:
|
|
+ - Set the field in_addr of the @ref
|
|
+ ioh_dma_channel_info structure of the
|
|
+ corresponding channel to the value of the
|
|
+ argument iaddr.
|
|
+ - Set the field out_addr of the @ref
|
|
+ ioh_dma_channle_info structure of the
|
|
+ corresponding channel to the value of the
|
|
+ argument oaddr.
|
|
+
|
|
+ @param channel [@ref IN] Channel for which addresses is
|
|
+ to be set.
|
|
+ @param iaddr [@ref IN] Inside address to be set
|
|
+ @param oaddr [@ref IN] Outside address to be set
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On Success.
|
|
+
|
|
+ @see
|
|
+ - ioh_set_dma_addr
|
|
+
|
|
+ */
|
|
+int dma_set_addr(int channel, u32 iaddr, u32 oaddr)
|
|
+{
|
|
+ ioh_dma_channel_info[channel].in_addr = iaddr;
|
|
+ ioh_dma_channel_info[channel].out_addr = oaddr;
|
|
+
|
|
+ IOH_DEBUG("Function dma_set_addr returns %d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_enable_ch(int channel)
|
|
+ @brief Enables the DMA channel specified.
|
|
+ @remarks This function sets the entire DMA settings such as
|
|
+ the transfer direction, transfer mode and
|
|
+ enables the channel. The main tasks performed by
|
|
+ this function are:
|
|
+ - Sets the transfer direction.
|
|
+ - Sets the transfer mode.
|
|
+ - Enabling the channel.
|
|
+
|
|
+ @param channel [@ref IN] Channel number that
|
|
+ is to be enabled.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+
|
|
+ @see
|
|
+ - ioh_enable_dma
|
|
+ */
|
|
+int dma_enable_ch(int channel)
|
|
+{
|
|
+ u32 base_address;
|
|
+ u16 transfer_mode;
|
|
+ u32 ctl0;
|
|
+ u32 ctrl_val = DEFAULT_CONTROL_REGISTER_VALUE;
|
|
+ int ch;
|
|
+
|
|
+ /* Marking the channel as enabled. */
|
|
+ ioh_dma_channel_info[channel].bChEnabled = 1;
|
|
+
|
|
+ ch = ioh_dma_channel_table[channel].channel;
|
|
+ base_address = ioh_dma_channel_table[channel].base;
|
|
+
|
|
+ ctl0 = 0;
|
|
+
|
|
+ /* Setting of transfer direction. */
|
|
+ if (ioh_dma_channel_info[channel].DMATransferDirection ==
|
|
+ IOH_DMA_DIR_OUT_TO_IN) {
|
|
+ ctl0 |= IOH_DMA_DIR_OUT_TO_IN;
|
|
+ }
|
|
+
|
|
+ /* Setting the transfer mode features. */
|
|
+ transfer_mode = ioh_dma_channel_info[channel].DMATransferMode;
|
|
+
|
|
+ /* If scatter gather mode. */
|
|
+ if (transfer_mode == DMA_SCATTER_GATHER_MODE) {
|
|
+ u32 next_desc;
|
|
+
|
|
+ next_desc = ((u32) ioh_dma_channel_info[channel].pHeadOfList);
|
|
+ IOH_WRITE_LONG(next_desc, (base_address + (DMA_NX_AD_OFFSET +
|
|
+ (ch * 0x10))));
|
|
+
|
|
+ ctl0 |= DMA_SCATTER_GATHER_MODE;
|
|
+ }
|
|
+ /* If one shot mode. */
|
|
+ else {
|
|
+ u32 in_address = ioh_dma_channel_info[channel].in_addr;
|
|
+ u32 out_address = ioh_dma_channel_info[channel].out_addr;
|
|
+ u32 access_size = ioh_dma_channel_info[channel].DMAAccessSize;
|
|
+ u32 count = ioh_dma_channel_info[channel].DMATransferSize;
|
|
+
|
|
+ ctl0 |= DMA_ONE_SHOT_MODE;
|
|
+
|
|
+ count |= access_size;
|
|
+
|
|
+ IOH_WRITE_LONG(in_address,
|
|
+ (base_address +
|
|
+ (DMA_IN_AD_OFFSET + (ch * 0x10))));
|
|
+ IOH_WRITE_LONG(out_address,
|
|
+ (base_address +
|
|
+ (DMA_OUT_AD_OFFSET + (ch * 0x10))));
|
|
+ IOH_WRITE_LONG(count,
|
|
+ (base_address + (DMA_SZ_OFFSET + (ch * 0x10))));
|
|
+ }
|
|
+
|
|
+ /* Enabling the interrupts. */
|
|
+ (void)dma_enable_disable_interrupt(channel, IOH_DMA_INTERRUPT_ENABLE);
|
|
+
|
|
+ /* Updating Control register. */
|
|
+ if (ch < 8) {
|
|
+ /* Clearing the three bits corresponding
|
|
+ to the mode and transfer direction of
|
|
+ specific channel.
|
|
+ */
|
|
+ ctrl_val &= ~((MSK_ALL_THREE) << (ch * DMA_SHIFT_MODE_BITS));
|
|
+
|
|
+ /* Setting the transfer mode and direction. */
|
|
+ ctrl_val |= (ctl0 << (ch * DMA_SHIFT_MODE_BITS));
|
|
+
|
|
+ /* Updating to the register. */
|
|
+ IOH_WRITE_LONG(ctrl_val, (base_address + DMA_CTL0_OFFSET));
|
|
+
|
|
+ IOH_DEBUG("dma_enable -> Control register(0) value: "
|
|
+ "%x.\n",
|
|
+ IOH_READ_LONG((base_address + DMA_CTL0_OFFSET)));
|
|
+ } else {
|
|
+ /* Clearing the three bits corresponding
|
|
+ to the mode and transfer direction of
|
|
+ specific channel.
|
|
+ */
|
|
+ ctrl_val &=
|
|
+ ~((MSK_ALL_THREE) << ((ch - 8) * DMA_SHIFT_MODE_BITS));
|
|
+
|
|
+ /* Setting the transfer mode and direction. */
|
|
+ ctrl_val |= (ctl0 << ((ch - 8) * DMA_SHIFT_MODE_BITS));
|
|
+
|
|
+ /* Updating to the register. */
|
|
+ IOH_WRITE_LONG(ctrl_val, (base_address + DMA_CTL3_OFFSET));
|
|
+
|
|
+ IOH_DEBUG("dma_enable -> Control register(3) value: "
|
|
+ "%x.\n",
|
|
+ IOH_READ_LONG((base_address + DMA_CTL3_OFFSET)));
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function dma_enable_ch returns %d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_disable_ch(int channel)
|
|
+ @brief Disables the DMA channel specified.
|
|
+ @remarks This function performs the necessary
|
|
+ register updation in-order to disable
|
|
+ the DMA channel.
|
|
+
|
|
+ @param channel [@ref IN] Channel to be disabled.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS
|
|
+
|
|
+ @see
|
|
+ - ioh_disable_dma
|
|
+ */
|
|
+int dma_disable_ch(int channel)
|
|
+{
|
|
+ u32 base_address;
|
|
+ u16 ch;
|
|
+
|
|
+ ch = ioh_dma_channel_table[channel].channel;
|
|
+ base_address = ioh_dma_channel_table[channel].base;
|
|
+
|
|
+ if (channel < 8) {
|
|
+ /* Clearing the mode bits of the channel */
|
|
+ IOH_DMA_BIT_CLEAR((base_address + DMA_CTL0_OFFSET),
|
|
+ (DMA_MASK_MODE_BITS <<
|
|
+ (ch * DMA_SHIFT_MODE_BITS)));
|
|
+ } else {
|
|
+ /* Clearing the mode bits of the channel */
|
|
+ IOH_DMA_BIT_CLEAR((base_address + DMA_CTL3_OFFSET),
|
|
+ (DMA_MASK_MODE_BITS <<
|
|
+ ((ch - 8) * DMA_SHIFT_MODE_BITS)));
|
|
+ }
|
|
+
|
|
+ /* Updating the enable variable. */
|
|
+ ioh_dma_channel_info[channel].bChEnabled = (u16) 0;
|
|
+
|
|
+ IOH_DEBUG("Function dma_disable_ch returns " "%d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_set_count (int channel, u32 count)
|
|
+ @brief Sets the count value .
|
|
+ @remarks Updates the transfer size for ONE_SHOT_MODE
|
|
+ of DMA Transfer. The main tasks performed by
|
|
+ this function are:
|
|
+ - Set the DMATransferSize field of the
|
|
+ @ref ioh_dma_channel_info structure to the
|
|
+ value of the argument count.
|
|
+
|
|
+ @param channel [@ref IN] Channel number for
|
|
+ which value is to be set
|
|
+ @param count [@ref IN] Transfer Size value.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS
|
|
+
|
|
+ @see
|
|
+ - ioh_set_dma_count
|
|
+ */
|
|
+int dma_set_count(int channel, u32 count)
|
|
+{
|
|
+ ioh_dma_channel_info[channel].DMATransferSize = count;
|
|
+
|
|
+ IOH_DEBUG("Function dma_set_count returns %d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_add_desc(int channel,
|
|
+ struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end)
|
|
+ @brief Adds descriptors to the existing list of descriptors.
|
|
+ @remarks This function accepts the descriptor list and appends
|
|
+ it to the existing list of descriptors. The main
|
|
+ tasks performed by this function are:
|
|
+ - Obtains the virtual address of the end of the
|
|
+ currently set descriptor list. If it is not
|
|
+ successful returns with an error.
|
|
+ - Appends the value of the argument start to the
|
|
+ nextDesc field of the descriptor pointed by the
|
|
+ pTailOfList field of the
|
|
+ @ref ioh_dma_channel_info structure with the
|
|
+ value of the argument start after appropriately
|
|
+ setting the last two bits to denote
|
|
+ Follow_Next_Descriptor_Without_Interrupt.
|
|
+ - Updates the value of the argument end to the
|
|
+ pTailOfList field of the @ref
|
|
+ ioh_dma_channel_info structure for the
|
|
+ corresponding channel.
|
|
+
|
|
+ @param channel [@ref IN] Channel number.
|
|
+ @param start [@ref IN] Reference to first
|
|
+ descriptor of list.
|
|
+ @param end [@ref IN] Reference to last
|
|
+ descriptor of list.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> If appending of the
|
|
+ descriptor is successful.
|
|
+
|
|
+ @see
|
|
+ - ioh_add_dma_desc
|
|
+*/
|
|
+int dma_add_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end)
|
|
+{
|
|
+ struct ioh_dma_desc *desc_addr;
|
|
+
|
|
+ desc_addr = ioh_dma_channel_info[channel].pTailOfList;
|
|
+
|
|
+ /* Obtaining the virtual address. */
|
|
+ desc_addr = (struct ioh_dma_desc *) phys_to_virt((u32) desc_addr);
|
|
+
|
|
+ /* If virtual address calculation successful. */
|
|
+ desc_addr->nextDesc = (u32) start;
|
|
+ ioh_dma_channel_info[channel].pTailOfList = end;
|
|
+
|
|
+ IOH_DEBUG("Function dma_add_desc returns %d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn void dma_set_callback (int channel, void (*ioh_dma_cbr)
|
|
+ ( int value,unsigned long data1),unsigned long data)
|
|
+ @brief To set callback function.
|
|
+ @remarks Sets the callback function to be called for a channel.
|
|
+ The main task performed by this function is:
|
|
+ - Updates the callback pointer for the channel
|
|
+ in the structure ioh_dma_channel_info with the
|
|
+ parameter passed.
|
|
+
|
|
+ @param channel [@ref IN] Channel number.
|
|
+ @param ioh_dma_cbr [@ref IN] Function pointer
|
|
+ to call back function.
|
|
+ @param data [@ref IN] The data to be passed to
|
|
+ the callback function during
|
|
+ invoking.
|
|
+
|
|
+ @return None.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_set_callback
|
|
+ */
|
|
+void dma_set_callback(int channel,
|
|
+ void (*ioh_dma_cbr) (int value, unsigned long data1),
|
|
+ unsigned long data)
|
|
+{
|
|
+ ioh_dma_channel_info[channel].call_back_func_ptr = ioh_dma_cbr;
|
|
+ ioh_dma_channel_info[channel].callback_data = data;
|
|
+
|
|
+ IOH_DEBUG("Function dma_set_callback invoked successfully.\n");
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn irqreturn_t dma_interrupt (int irq, void *dev_id)
|
|
+ @brief Interrupt handler.
|
|
+ @remarks Handles the interrupt for the DMA. The main tasks
|
|
+ performed by this function are:
|
|
+ - Checks each DMA channels whether a DMA
|
|
+ transmission end or DMA status interrupt has
|
|
+ occurred.
|
|
+ - If a transmission end interrupt has occurred,
|
|
+ then invoke the callback function with @ref
|
|
+ IOH_DMA_END, denoting that the DMA transmission
|
|
+ has end.
|
|
+ - If a DMA abort interrupt has occurred, then
|
|
+ invoke the callback function with @ref
|
|
+ IOH_DMA_ABORT, denoting that a DMA abort has
|
|
+ occurred.
|
|
+
|
|
+ @param irq [@ref IN] Interrupt Request number
|
|
+ @param dev_id [@ref IN] dev_id of device for which
|
|
+ interrupt is raised .
|
|
+
|
|
+ @return irqreturn_t
|
|
+ - IRQ_HANDLED --> If interrupt has been processed.
|
|
+ - IRQ_NONE --> If no interrupt has been processed.
|
|
+
|
|
+ */
|
|
+irqreturn_t dma_interrupt(int irq, void *dev_id)
|
|
+{
|
|
+ irqreturn_t retval = IRQ_NONE;
|
|
+ u32 status_reg0;
|
|
+ u32 status_reg2;
|
|
+ u32 base_address;
|
|
+ u32 dev_type;
|
|
+ u32 i;
|
|
+ u16 status;
|
|
+
|
|
+ base_address = ((struct ioh_dma_devices *) dev_id)->base_addr;
|
|
+ dev_type = ((struct ioh_dma_devices *) dev_id)->dev_typ;
|
|
+
|
|
+ /* Reading the status registers. */
|
|
+ status_reg0 = IOH_READ_LONG((base_address + DMA_STS0_OFFSET));
|
|
+ status_reg2 = IOH_READ_LONG((base_address + DMA_STS2_OFFSET));
|
|
+ IOH_DEBUG("dma_interrupt -> Status register STS0: %x STS2: "
|
|
+ "%x.\n", status_reg0, status_reg2);
|
|
+
|
|
+ /* Clearing the interrupts. */
|
|
+ dma_clear_interrupt_status(base_address, status_reg0, status_reg2);
|
|
+
|
|
+ /* Handling the interrupts. */
|
|
+ for (i = 0; i < IOH_DMA_CHANNELS_MAX; i++) {
|
|
+ if ((ioh_dma_channel_table[i].dma_dev_id == dev_type) &&
|
|
+ (ioh_dma_channel_table[i].ch_alloced == 1) &&
|
|
+ (ioh_dma_channel_info[i].bChEnabled == 1)
|
|
+ ) {
|
|
+ status =
|
|
+ dma_get_interrupt_status(ioh_dma_channel_table
|
|
+ [i].channel, status_reg0,
|
|
+ status_reg2);
|
|
+ IOH_DEBUG
|
|
+ ("dma_interrupt -> Interrupt status for ch: %d is "
|
|
+ "%x.\n", i, status);
|
|
+
|
|
+ if (status == 1) {
|
|
+ int value = IOH_DMA_END;
|
|
+
|
|
+ status =
|
|
+ dma_get_abort_status(ioh_dma_channel_table
|
|
+ [i].channel,
|
|
+ status_reg0,
|
|
+ status_reg2);
|
|
+
|
|
+ if (status == 1) {
|
|
+ value = IOH_DMA_ABORT;
|
|
+
|
|
+ IOH_DEBUG
|
|
+ ("dma_interrupt -> DMA Abort "
|
|
+ "interrupt from channel%d.\n", i);
|
|
+ }
|
|
+#ifdef DEBUG
|
|
+ else {
|
|
+ IOH_DEBUG
|
|
+ ("dma_interrupt -> DMA Completion "
|
|
+ "interrupt "
|
|
+ "from channel%d.\n", i);
|
|
+ }
|
|
+#endif
|
|
+ if (ioh_dma_channel_info[i].
|
|
+ call_back_func_ptr) {
|
|
+ u32 data =
|
|
+ ioh_dma_channel_info
|
|
+ [i].callback_data;
|
|
+ (ioh_dma_channel_info
|
|
+ [i].call_back_func_ptr) (value, data);
|
|
+ }
|
|
+
|
|
+ /* Determining whether the channel has been
|
|
+ disabled. */
|
|
+ {
|
|
+ u32 ctrl_val;
|
|
+ s32 ch =
|
|
+ ioh_dma_channel_table[i].channel;
|
|
+ u32 base_address =
|
|
+ ioh_dma_channel_table[i].base;
|
|
+
|
|
+ if (ch < 8) {
|
|
+ ctrl_val =
|
|
+ IOH_READ_LONG((base_address
|
|
+ + DMA_CTL0_OFFSET));
|
|
+
|
|
+ ctrl_val &=
|
|
+ ((0x3) <<
|
|
+ (ch * DMA_SHIFT_MODE_BITS));
|
|
+ } else {
|
|
+ ctrl_val =
|
|
+ IOH_READ_LONG((base_address
|
|
+ + DMA_CTL3_OFFSET));
|
|
+ ctrl_val &=
|
|
+ ((0x3) <<
|
|
+ ((ch - 8) *
|
|
+ DMA_SHIFT_MODE_BITS));
|
|
+ }
|
|
+
|
|
+ ioh_dma_channel_info[i].bChEnabled =
|
|
+ (ctrl_val != 0) ? 1 : 0;
|
|
+
|
|
+ } /* End */
|
|
+
|
|
+ retval = IRQ_HANDLED;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function dma_interrupt returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_direct_start (int channel)
|
|
+ @brief To generate the DMA request which each Function-IP
|
|
+ transmits.
|
|
+ @remarks This function is used to initiate the DMA
|
|
+ transfer process. The main task performed by
|
|
+ this function is:
|
|
+ - Sets the value of DMAn Direct Start bit in the
|
|
+ Control register 2 to start DMA transfer on
|
|
+ channel n.
|
|
+
|
|
+ @param channel [@ref IN] Channel number for which DMA
|
|
+ transfer is to be started.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On Success.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_direct_start
|
|
+ */
|
|
+int dma_direct_start(int channel)
|
|
+{
|
|
+ int ch;
|
|
+ u32 base_address;
|
|
+
|
|
+ ch = ioh_dma_channel_table[channel].channel;
|
|
+ base_address = ioh_dma_channel_table[channel].base;
|
|
+
|
|
+ if (ch < 8) {
|
|
+ IOH_DMA_BIT_SET((base_address + DMA_CTL2_OFFSET),
|
|
+ (DMA_DIR_START << ch));
|
|
+ } else {
|
|
+ IOH_DMA_BIT_SET((base_address + DMA_CTL2_OFFSET),
|
|
+ (DMA_DIR_START << (ch + 6)));
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("dma_direct_start -> Direct2 RegValue: "
|
|
+ "%x.\n", IOH_READ_LONG((base_address + DMA_CTL2_OFFSET)));
|
|
+
|
|
+ IOH_DEBUG("Function dma_direct_start returns "
|
|
+ "%d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_set_priority (int channel, int priority)
|
|
+ @brief Set the priority.
|
|
+ @remarks Sets the priority for a channel. The main task
|
|
+ performed by this function is:
|
|
+ - Set the value of DMAn Priority Level bits for
|
|
+ the channel in the Control register1.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number.
|
|
+ @param priority [@ref IN] Priority to be set for
|
|
+ the DMA channel.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On Success.
|
|
+
|
|
+ @see
|
|
+ - ioh_set_dma_priority
|
|
+ */
|
|
+int dma_set_priority(int channel, int priority)
|
|
+{
|
|
+ int ch;
|
|
+ u32 base_address;
|
|
+ u32 reg_val;
|
|
+
|
|
+ ch = ioh_dma_channel_table[channel].channel;
|
|
+ base_address = ioh_dma_channel_table[channel].base;
|
|
+
|
|
+ reg_val = IOH_READ_LONG((base_address + DMA_CTL1_OFFSET));
|
|
+
|
|
+ if (ch < 8) {
|
|
+ reg_val &=
|
|
+ ~(DMA_MASK_PRIORITY_BITS << (ch * DMA_SHIFT_PRIORITY_BITS));
|
|
+ reg_val |= (((u32) priority) << (ch * DMA_SHIFT_PRIORITY_BITS));
|
|
+ } else {
|
|
+ reg_val &=
|
|
+ ~(DMA_MASK_PRIORITY_BITS <<
|
|
+ (((ch - 8) * DMA_SHIFT_PRIORITY_BITS) + 2));
|
|
+ reg_val |=
|
|
+ (((u32) priority) <<
|
|
+ (((ch - 8) * DMA_SHIFT_PRIORITY_BITS) + 2));
|
|
+ }
|
|
+
|
|
+ IOH_WRITE_LONG(reg_val, (base_address + DMA_CTL1_OFFSET));
|
|
+
|
|
+ IOH_DEBUG("Function dma_set_priority returns "
|
|
+ "%d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_enable_disable_interrupt (int channel, int bEnable)
|
|
+ @brief Enables or Disables Interrupts .
|
|
+ @remarks Writes the corresponding register to either
|
|
+ enable or disable interrupts. The main tasks
|
|
+ performed by this function are:
|
|
+ - If bEnable is DMA_INTERRUPT_ENABLE (1),
|
|
+ sets the DMAn Interrupt Enable bit in control
|
|
+ register2.
|
|
+ - If bEnable is DMA_INTERRUPT_DISABLE (0),
|
|
+ clears the DMAn Interrupt Enable bit in control
|
|
+ register2.
|
|
+
|
|
+ @param channel [@ref IN] Channel number
|
|
+ @param bEnable [@ref IN] Flag to indicate whether
|
|
+ to enable or disable interrupt.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On Success.
|
|
+
|
|
+ @see
|
|
+ - dma_init
|
|
+ - dma_exit
|
|
+ */
|
|
+int dma_enable_disable_interrupt(int channel, int bEnable)
|
|
+{
|
|
+ u32 base_address;
|
|
+ u16 ch;
|
|
+
|
|
+ ch = ioh_dma_channel_table[channel].channel;
|
|
+ base_address = ioh_dma_channel_table[channel].base;
|
|
+
|
|
+ if (ch < 8) {
|
|
+ if (IOH_DMA_INTERRUPT_ENABLE == bEnable) {
|
|
+ IOH_DMA_BIT_SET((base_address + DMA_CTL2_OFFSET),
|
|
+ (DMA_INTERRUPT_BIT << ch));
|
|
+ } else { /* if(bEnable == IOH_DMA_INTERRUPT_DISABLE) */
|
|
+
|
|
+ IOH_DMA_BIT_CLEAR((base_address + DMA_CTL2_OFFSET),
|
|
+ (DMA_INTERRUPT_BIT << ch));
|
|
+ }
|
|
+
|
|
+ } else {
|
|
+ if (IOH_DMA_INTERRUPT_ENABLE == bEnable) {
|
|
+ IOH_DMA_BIT_SET((base_address + DMA_CTL2_OFFSET),
|
|
+ (DMA_INTERRUPT_BIT << (ch + 8)));
|
|
+ } else { /* if(bEnable == IOH_DMA_INTERRUPT_DISABLE) */
|
|
+
|
|
+ IOH_DMA_BIT_CLEAR((base_address + DMA_CTL2_OFFSET),
|
|
+ (DMA_INTERRUPT_BIT << (ch + 8)));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("dma_enable_disable_interrupt -> CTL2 Register Value: "
|
|
+ "%x.\n", IOH_READ_LONG((base_address + DMA_CTL2_OFFSET)));
|
|
+
|
|
+ IOH_DEBUG("Function dma_enable_disable_interrupt returns "
|
|
+ "%d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn void get_dma_status(int channel, u16 *pDMAStatus)
|
|
+ @brief Gets the Status of DMA.
|
|
+ @remarks Gets the status of the specified DMA Channel. The
|
|
+ main task performed by this function is:
|
|
+ - Reads the data in the DMAn (for channel .n.)
|
|
+ Status bit of Status register0 (4ch or 8ch) or
|
|
+ Status register2 (12ch) and copy the value into
|
|
+ pDMAStatus.
|
|
+
|
|
+ @param channel [@ref IN] Channel number.
|
|
+ @param pDMAStatus [@ref INOUT] Address of variable to
|
|
+ which
|
|
+ status information is copied.
|
|
+
|
|
+ @return None.
|
|
+
|
|
+ @see
|
|
+ - dma_exit
|
|
+ - dma_init
|
|
+ - ioh_set_dma_mode
|
|
+ - ioh_set_dma_addr
|
|
+ - ioh_set_dma_count
|
|
+ - ioh_set_dma_desc
|
|
+ - ioh_add_dma_desc
|
|
+ - ioh_enable_dma
|
|
+ - ioh_disable_dma
|
|
+ - ioh_set_dma_priority
|
|
+ - ioh_dma_direct_start
|
|
+
|
|
+ */
|
|
+
|
|
+void get_dma_status(int channel, u16 *pDMAStatus)
|
|
+{
|
|
+ u32 status_val;
|
|
+ u32 base_address;
|
|
+ u16 ch;
|
|
+
|
|
+ ch = ioh_dma_channel_table[channel].channel;
|
|
+ base_address = ioh_dma_channel_table[channel].base;
|
|
+
|
|
+ if (ch < 8) {
|
|
+ status_val = IOH_READ_LONG(base_address + DMA_STS0_OFFSET);
|
|
+ *pDMAStatus = (u16) ((status_val >> (DMA_SHIFT_STATUS_BITS +
|
|
+ (ch *
|
|
+ DMA_SIZE_STATUS_BITS))) &
|
|
+ (DMA_MASK_STATUS_BITS));
|
|
+ } else {
|
|
+ status_val = IOH_READ_LONG(base_address + DMA_STS2_OFFSET);
|
|
+ *pDMAStatus = (u16) ((status_val >> (DMA_SHIFT_STATUS_BITS +
|
|
+ ((ch -
|
|
+ 8) *
|
|
+ DMA_SIZE_STATUS_BITS))) &
|
|
+ (DMA_MASK_STATUS_BITS));
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function get_dma_status invoked successfully.\n");
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_set_desc(int channel,
|
|
+ struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end)
|
|
+ @brief Sets descriptors .
|
|
+ @remarks This functions sets the descriptor settings for
|
|
+ SCATTER GATHER mode. It does not perform any
|
|
+ register settings, instead retains the data for
|
|
+ further use. The main tasks performed by this
|
|
+ function are:
|
|
+ - Sets the pHeadOfList field of the @ref
|
|
+ ioh_dma_channel_info structure to the value of
|
|
+ the argument start.
|
|
+ - Set the pTailOfList field of the @ref
|
|
+ ioh_dma_channel_info structure to the value of
|
|
+ the argument end.
|
|
+
|
|
+ @param channel [@ref IN] Channel number.
|
|
+ @param start [@ref IN] Reference to first descriptor
|
|
+ of list.
|
|
+ @param end [@ref IN] Reference to last descriptor
|
|
+ of list.
|
|
+
|
|
+ @see
|
|
+ - ioh_set_dma_desc
|
|
+ */
|
|
+
|
|
+int dma_set_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end)
|
|
+{
|
|
+ ioh_dma_channel_info[channel].pHeadOfList = start;
|
|
+ ioh_dma_channel_info[channel].pTailOfList = end;
|
|
+
|
|
+ IOH_DEBUG("Function dma_set_desc returns %d.\n", IOH_DMA_SUCCESS);
|
|
+ return IOH_DMA_SUCCESS;
|
|
+}
|
|
+
|
|
+/*! @ingroup InternalFunction
|
|
+ @fn void get_free_ch(int index)
|
|
+ @brief Get a free channel info entry and populate the entry.
|
|
+ @remarks Reset all the entries within the array
|
|
+ ioh_dma_channel_info[index]
|
|
+
|
|
+ @param index [@ref IN] Index in the
|
|
+ ioh_dma_channel_table
|
|
+
|
|
+ @return None
|
|
+
|
|
+ @see
|
|
+ - dma_request_ch
|
|
+ */
|
|
+void get_free_ch(int index)
|
|
+{
|
|
+ memset((void *)&ioh_dma_channel_info[index], 0,
|
|
+ sizeof(struct ioh_dma_controller_info));
|
|
+ IOH_DEBUG("Function get_free_ch invoked successfully.\n");
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_request_ch(u32 req_dev_id, int dreq)
|
|
+ @brief Reserves a channel based on request.
|
|
+ @remarks This function is invoked when a kernel module requests
|
|
+ to reserve a DMA channel. The main tasks
|
|
+ performed by this function are:
|
|
+ - Checks the @ref ioh_dma_channel_table for a
|
|
+ matching entry corresponding to the dev_id of
|
|
+ the requesting device and dreq signal.
|
|
+ - If there is a matching entry, checks if this
|
|
+ channel is already allocated.
|
|
+ - If no invoke get_free_ch to reset the entries
|
|
+ for the corresponding channel and return the
|
|
+ entry index.
|
|
+ - If no matching entry is found return -EBUSY.
|
|
+
|
|
+ @param req_dev_id [@ref IN] Device id of the device
|
|
+ that requests DMA .
|
|
+ @param dreq [@ref IN] DMA request signal number.
|
|
+
|
|
+ @return int
|
|
+ - DMA channel number (>=0) --> On Success.
|
|
+ - -EBUSY --> DMA channel cannot be allocated..
|
|
+
|
|
+ @see
|
|
+ - ioh_request_dma
|
|
+ */
|
|
+
|
|
+int dma_request_ch(u32 req_dev_id, int dreq)
|
|
+{
|
|
+ int retval;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < IOH_DMA_CHANNELS_MAX; i++) {
|
|
+ if ((ioh_dma_channel_table[i].req_device_id == req_dev_id) &&
|
|
+ (ioh_dma_channel_table[i].request_signal == dreq)) {
|
|
+ if ((1 == ioh_dma_channel_table[i].ch_found) &&
|
|
+ (0 == ioh_dma_channel_table[i].ch_alloced)) {
|
|
+ get_free_ch(i);
|
|
+ IOH_DEBUG
|
|
+ ("dma_request_ch -> Function get_free_ch "
|
|
+ "invoked successfully.\n");
|
|
+ ioh_dma_channel_table[i].ch_alloced = 1;
|
|
+ retval = i;
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (IOH_DMA_CHANNELS_MAX == i) {
|
|
+ retval = -EBUSY;
|
|
+ IOH_LOG(KERN_ERR, "dma_request_ch -> Not able to allocate "
|
|
+ "channel.\n");
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function dma_request_ch returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+/*! @ingroup HALLayerAPI
|
|
+ @fn int dma_free_ch(int channel)
|
|
+ @brief Frees the requested channel.
|
|
+ @remarks This function is invoked when a kernel
|
|
+ module requests to free a DMA channel. The main
|
|
+ tasks performed by this function are:
|
|
+ - If the channel is already free return
|
|
+ IOH_DMA_SUCCESS.
|
|
+ - Else disable the channel by invoking
|
|
+ @ref dma_disable_ch API.
|
|
+ - Disable the channel interrupt by invoking
|
|
+ @ref dma_enable_disable_interrupt
|
|
+ - Mark the channel as free in the structures
|
|
+ @ref ioh_dma_channel_info and @ref
|
|
+ ioh_dma_channel_table and return @ref
|
|
+ IOH_DMA_SUCCESS.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number to be freed.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+
|
|
+ @see
|
|
+ - ioh_free_dma
|
|
+ */
|
|
+
|
|
+int dma_free_ch(int channel)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_DEBUG("dma_free_ch -> Channel is already free\n");
|
|
+ retval = IOH_DMA_SUCCESS;
|
|
+ } else {
|
|
+ /* To stop any active transfer on DMA, disable DMA */
|
|
+ (void)dma_disable_ch(channel);
|
|
+ IOH_DEBUG("dma_free_ch -> Function dma_disable_ch invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ (void)dma_enable_disable_interrupt(channel,
|
|
+ IOH_DMA_INTERRUPT_DISABLE);
|
|
+ IOH_DEBUG
|
|
+ ("dma_free_ch -> Function dma_enable_disable_interrupt "
|
|
+ "invoked successfully.\n");
|
|
+
|
|
+ ioh_dma_channel_table[channel].ch_alloced = 0;
|
|
+
|
|
+ retval = IOH_DMA_SUCCESS;
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function dma_free_ch returns %d.\n", IOH_DMA_SUCCESS);
|
|
+ return retval;
|
|
+}
|
|
--- /dev/null
|
|
+++ b/drivers/dma/pch_dma/pch_dma_hal.h
|
|
@@ -0,0 +1,594 @@
|
|
+/**
|
|
+ * @file ioh_dma_hal.h
|
|
+ *
|
|
+ * @brief
|
|
+ * This file declares the structures & data types used by the HAL
|
|
+ * functions of IOH_DMA_CONTROLLER driver.
|
|
+ *
|
|
+ * @version 0.90
|
|
+ * @section
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
+ *
|
|
+ * <hr>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * History:
|
|
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * created:
|
|
+ * WIPRO 03/07/2009
|
|
+ * modified:
|
|
+ * WIPRO 08/14/2009
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __IOH_DMA_HAL_H__
|
|
+#define __IOH_DMA_HAL_H__
|
|
+
|
|
+#include <linux/interrupt.h>
|
|
+#include "pch_dma_main.h"
|
|
+
|
|
+/*!
|
|
+ @defgroup DMA
|
|
+*/
|
|
+
|
|
+/*! @defgroup Global
|
|
+ @ingroup DMA
|
|
+ @brief This group contains all the global data
|
|
+ structures used by the DMA module.
|
|
+*/
|
|
+
|
|
+/*! defgroup InternalFunction
|
|
+ @ingroup DMA
|
|
+ @brief This group contains all the function which
|
|
+ are used by other APIs for performing some
|
|
+ small tasks for facilitating the logic
|
|
+ of the driver.
|
|
+*/
|
|
+
|
|
+/*! @defgroup PCILayer
|
|
+ @ingroup DMA
|
|
+ @brief This group contains all the utilities
|
|
+ used to interface the DMA module with
|
|
+ the PCI subsystem of the Kernel.
|
|
+*/
|
|
+
|
|
+/*! @defgroup InterfaceLayer
|
|
+ @ingroup DMA
|
|
+ @brief This group contains all the utilities
|
|
+ used by the DMA module to interface with
|
|
+ the other modules.
|
|
+*/
|
|
+
|
|
+/*! @defgroup HALLayer
|
|
+ @ingroup DMA
|
|
+ @brief This group contains all the utilities
|
|
+ used to DMA module to interact with the
|
|
+ hardware.
|
|
+*/
|
|
+
|
|
+/*! @defgroup PCILayerAPI
|
|
+ @ingroup PCILayer
|
|
+ @brief This group contains the APIs used to
|
|
+ interface the DMA module with the PCI
|
|
+ subsystem of the Kernel.
|
|
+*/
|
|
+
|
|
+/*! @defgroup PCILayerFacilitators
|
|
+ @ingroup PCILayer
|
|
+ @brief This group contains the data structures
|
|
+ used by the PCILayerAPIs for their
|
|
+ functioning.
|
|
+*/
|
|
+
|
|
+/*! @defgroup HALLayerAPI
|
|
+ @ingroup HALLayer
|
|
+ @brief This group contains the APIs used to
|
|
+ communicate with the hardware.
|
|
+*/
|
|
+
|
|
+/*! @defgroup HALLayerFacilitators
|
|
+ @ingroup HALLayer
|
|
+ @brief This group contains the data structures
|
|
+ used to communicate with the hardware.
|
|
+*/
|
|
+
|
|
+/*! @defgroup InterfaceLayerAPI
|
|
+ @ingroup InterfaceLayer
|
|
+ @brief This group contains the APIs used by the
|
|
+ DMA module to interface with other modules.
|
|
+*/
|
|
+
|
|
+/*! @defgroup InterfaceLayerFacilitators
|
|
+ @ingroup InterfaceLayer
|
|
+ @brief This group contains the data structures
|
|
+ used by the DMA module to interface with
|
|
+ other modules.
|
|
+*/
|
|
+
|
|
+/*** Device specific limitations and properties. ***/
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def IOH_DMA_CHANNELS_MAX
|
|
+ @brief The maximum number of channels allowed
|
|
+ in any of the IOH device.
|
|
+*/
|
|
+#define IOH_DMA_CHANNELS_MAX (64)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def IOH_DMA_MAX_DEVS
|
|
+ @brief The no. of DMA devices allowable.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_devices
|
|
+*/
|
|
+#define IOH_DMA_MAX_DEVS (4)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def IOH_DMA_8BIT_SIZE_MAX
|
|
+ @brief The maximum number of transfer size in
|
|
+ bytes for a channel if access size is set
|
|
+ to 8BIT.
|
|
+*/
|
|
+#define IOH_DMA_8BIT_SIZE_MAX (2047)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def IOH_DMA_16BIT_SIZE_MAX
|
|
+ @brief The maximum number of transfer size in
|
|
+ bytes for a channel if access size is set
|
|
+ to 16BIT.
|
|
+*/
|
|
+#define IOH_DMA_16BIT_SIZE_MAX (4094)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def IOH_DMA_32BIT_SIZE_MAX
|
|
+ @brief The maximum number of transfer size in
|
|
+ bytes for a channel if access size is set
|
|
+ to 32BIT.
|
|
+*/
|
|
+#define IOH_DMA_32BIT_SIZE_MAX (4096)
|
|
+
|
|
+/********/
|
|
+
|
|
+/*** Device IDs of DMA requesting devices. ***/
|
|
+/*! @ingroup DMA
|
|
+ @def PCI_DEVICE_ID_IOH_UART0
|
|
+ @brief The deviceID of the IOH GE UART
|
|
+ device 0 which can use the DMA features.
|
|
+*/
|
|
+#define PCI_DEVICE_ID_IOH_UART0 (0x8811)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def PCI_DEVICE_ID_IOH_UART1
|
|
+ @brief The deviceID of the IOH GE UART
|
|
+ device 1 which can use the DMA features.
|
|
+*/
|
|
+#define PCI_DEVICE_ID_IOH_UART1 (0x8812)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def PCI_DEVICE_ID_IOH_UART2
|
|
+ @brief The deviceID of the IOH GE UART
|
|
+ device 2 which can use the DMA features.
|
|
+*/
|
|
+#define PCI_DEVICE_ID_IOH_UART2 (0x8813)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def PCI_DEVICE_ID_IOH_UART3
|
|
+ @brief The deviceID of the IOH GE UART
|
|
+ device 3 which can use the DMA features.
|
|
+*/
|
|
+#define PCI_DEVICE_ID_IOH_UART3 (0x8814)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def PCI_DEVICE_ID_IOH_SPI
|
|
+ @brief The deviceID of the IOH GE SPI
|
|
+ device which can use the DMA features.
|
|
+*/
|
|
+#define PCI_DEVICE_ID_IOH_SPI (0x8816)
|
|
+
|
|
+/*** Internal device IDs used for identifing the DMAC . ***/
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_4CH0
|
|
+ @brief The device ID for the first DMA device
|
|
+ with 4 channels.
|
|
+*/
|
|
+#define IOH_DMA_4CH0 (0x40)
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_4CH1
|
|
+ @brief The device ID for the second DMA device
|
|
+ with 4 channels.
|
|
+*/
|
|
+#define IOH_DMA_4CH1 (0x41)
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_4CH2
|
|
+ @brief The device ID for the third DMA device
|
|
+ with 4 channels.
|
|
+*/
|
|
+#define IOH_DMA_4CH2 (0x42)
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_4CH3
|
|
+ @brief The device ID for the fourth DMA device
|
|
+ with 4 channels.
|
|
+*/
|
|
+#define IOH_DMA_4CH3 (0x43)
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_4CH4
|
|
+ @brief The device ID for the fifth DMA device
|
|
+ with 4 channels.
|
|
+*/
|
|
+#define IOH_DMA_4CH4 (0x44)
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_8CH0
|
|
+ @brief The device ID for the first DMA device
|
|
+ with 8 channels.
|
|
+*/
|
|
+#define IOH_DMA_8CH0 (0x80)
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_8CH1
|
|
+ @brief The device ID for the second DMA device
|
|
+ with 8 channels.
|
|
+*/
|
|
+#define IOH_DMA_8CH1 (0x81)
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_8CH2
|
|
+ @brief The device ID for the third DMA device
|
|
+ with 8 channels.
|
|
+*/
|
|
+#define IOH_DMA_8CH2 (0x82)
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_8CH3
|
|
+ @brief The device ID for the fourth DMA device
|
|
+ with 8 channels.
|
|
+*/
|
|
+#define IOH_DMA_8CH3 (0x83)
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @def IOH_DMA_12CH0
|
|
+ @brief The device ID for the first DMA device
|
|
+ with 12 channels.
|
|
+*/
|
|
+#define IOH_DMA_12CH0 (0xC0)
|
|
+
|
|
+/******/
|
|
+
|
|
+/*** DMA Controller Register Offsets. ***/
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_CTL0_OFFSET
|
|
+ @brief DMA Control register 0 offset.
|
|
+*/
|
|
+#define DMA_CTL0_OFFSET (0x00UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_CTL1_OFFSET
|
|
+ @brief DMA Control register 1 offset.
|
|
+*/
|
|
+#define DMA_CTL1_OFFSET (0x04UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_CTL2_OFFSET
|
|
+ @brief DMA Control register 2 offset.
|
|
+*/
|
|
+#define DMA_CTL2_OFFSET (0x08UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_CTL3_OFFSET
|
|
+ @brief DMA Control register 3 offset.
|
|
+*/
|
|
+#define DMA_CTL3_OFFSET (0x0CUL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_STS0_OFFSET
|
|
+ @brief DMA Status register 0 offset.
|
|
+*/
|
|
+#define DMA_STS0_OFFSET (0x10UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_STS1_OFFSET
|
|
+ @brief DMA Status register 1 offset.
|
|
+*/
|
|
+#define DMA_STS1_OFFSET (0x14UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_STS2_OFFSET
|
|
+ @brief DMA Status register 2 offset.
|
|
+*/
|
|
+#define DMA_STS2_OFFSET (0x18UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_IN_AD_OFFSET
|
|
+ @brief DMA IN Address register offset.
|
|
+*/
|
|
+#define DMA_IN_AD_OFFSET (0x20UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_OUT_AD_OFFSET
|
|
+ @brief DMA Out Address register offset.
|
|
+*/
|
|
+#define DMA_OUT_AD_OFFSET (0x24UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_SZ_OFFSET
|
|
+ @brief DMA Size register offset.
|
|
+*/
|
|
+#define DMA_SZ_OFFSET (0x28UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_NX_AD_OFFSET
|
|
+ @brief DMA Next Address register offset.
|
|
+*/
|
|
+#define DMA_NX_AD_OFFSET (0x2CUL)
|
|
+
|
|
+/**********/
|
|
+
|
|
+/*** Individual register bits. ***/
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_SIZE_TYPE_BITS
|
|
+ @brief The DMA size bits.
|
|
+*/
|
|
+#define DMA_SIZE_TYPE_BITS (0x00003000UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_SET_OR_CLEAR_DIR_BIT
|
|
+ @brief Mask for direction bit.
|
|
+*/
|
|
+#define DMA_SET_OR_CLEAR_DIR_BIT (0x00000004UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_MASK_MODE_BITS
|
|
+ @brief Mask for mode bits.
|
|
+*/
|
|
+#define DMA_MASK_MODE_BITS (0x00000003UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_SHIFT_MODE_BITS
|
|
+ @brief DMA shift mode bits.
|
|
+*/
|
|
+#define DMA_SHIFT_MODE_BITS (4)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_MASK_PRIORITY_BITS
|
|
+ @brief Mask for priority bits.
|
|
+*/
|
|
+#define DMA_MASK_PRIORITY_BITS (0x3UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_SHIFT_PRIORITY_BITS
|
|
+ @brief Shift value for DMA priority bits.
|
|
+*/
|
|
+#define DMA_SHIFT_PRIORITY_BITS (4)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_SHIFT_SIZE_TYPE_BITS
|
|
+ @brief Shift value for the DMA size bit.
|
|
+*/
|
|
+#define DMA_SHIFT_SIZE_TYPE_BITS (12)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_DIR_START
|
|
+ @brief Direct Start Bit Setting values.
|
|
+*/
|
|
+#define DMA_DIR_START (0x00000100UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_INTERRUPT_BIT
|
|
+ @brief Interrupt Enable Bit setting values.
|
|
+*/
|
|
+#define DMA_INTERRUPT_BIT (0x00000001UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_ABORT_OCCUR
|
|
+ @brief Abort notify Bit Setting Values
|
|
+*/
|
|
+#define DMA_ABORT_OCCUR (0x00000100UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_INTERRUPT_OCCUR
|
|
+ @brief Interrupt notify Bit Setting Values
|
|
+*/
|
|
+#define DMA_INTERRUPT_OCCUR (0x00000001UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_MASK_STATUS_BITS
|
|
+ @brief Mask for status bits.
|
|
+*/
|
|
+#define DMA_MASK_STATUS_BITS (0x3UL)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_SIZE_STATUS_BITS
|
|
+ @brief The DMA size status bits.
|
|
+*/
|
|
+#define DMA_SIZE_STATUS_BITS (2)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_SHIFT_STATUS_BITS
|
|
+ @brief The shift value for DMA status bits.
|
|
+*/
|
|
+#define DMA_SHIFT_STATUS_BITS (16)
|
|
+
|
|
+/*********/
|
|
+
|
|
+/*** Status denoting macros. ***/
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_STATUS_IDLE
|
|
+ @brief Constant used to denote the transfer status as IDLE.
|
|
+ @note This constant is used by DMA modules to make the
|
|
+ other module aware of the DMA status.
|
|
+*/
|
|
+#define DMA_STATUS_IDLE (0)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_STATUS_DESC_READ
|
|
+ @brief Constant used to denote the transfer status as
|
|
+ DESCRIPTOR_READ.
|
|
+ @note This constant is used by DMA modules to make the
|
|
+ other module aware of the DMA status.
|
|
+*/
|
|
+#define DMA_STATUS_DESC_READ (1)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_STATUS_WAIT
|
|
+ @brief Constant used to denote the transfer status as WAIT.
|
|
+ @note This constant is used by DMA modules to make the
|
|
+ other module aware of the DMA status.
|
|
+*/
|
|
+#define DMA_STATUS_WAIT (2)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def DMA_STATUS_ACCESS
|
|
+ @brief Constant used to denote the transfer status as ACCESS
|
|
+ @note This constant is used by DMA modules to make the
|
|
+ other module aware of the DMA status.
|
|
+*/
|
|
+#define DMA_STATUS_ACCESS (3)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def IOH_DMA_INTERRUPT_DISABLE
|
|
+ @brief Constant used to denote disable interrupt.
|
|
+*/
|
|
+#define IOH_DMA_INTERRUPT_DISABLE (0)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def IOH_DMA_INTERRUPT_ENABLE
|
|
+ @brief Constant used to denote enable interrupt.
|
|
+*/
|
|
+#define IOH_DMA_INTERRUPT_ENABLE (1)
|
|
+
|
|
+/************/
|
|
+
|
|
+/*** Other Macros. ***/
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def COUNTER_LIMIT
|
|
+ @brief The counter limit.
|
|
+*/
|
|
+#define COUNTER_LIMIT (0xFFFF)
|
|
+
|
|
+/*! @ingroup HALLayer
|
|
+ @def MSK_ALL_THREE
|
|
+ @brief Value used for masking the 3 LSB bits.
|
|
+*/
|
|
+#define MSK_ALL_THREE (0x7)
|
|
+
|
|
+/*******/
|
|
+/*** Data Structures for stroing device specific information. ***/
|
|
+
|
|
+/*! @ingroup HALLayerFacilitators
|
|
+ @struct __ioh_dma_devices
|
|
+ @brief Format for maintaining the device information.
|
|
+ @note This structure is used by the DMA module to retain
|
|
+ the information about the device.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_devices
|
|
+*/
|
|
+
|
|
+struct ioh_dma_devices {
|
|
+ u32 base_addr; /**< The remapped base address. */
|
|
+ u32 dev_typ; /**< The device type indicating number of DMA
|
|
+ channels */
|
|
+ void *dev; /**< The void pointer for storing any references
|
|
+ if required */
|
|
+};
|
|
+
|
|
+/*! @ingroup HALLayerFacilitators
|
|
+ @struct __ioh_dma_controller_info_t
|
|
+ @brief Format for storing the details of the
|
|
+ DMA channels.
|
|
+*/
|
|
+
|
|
+struct ioh_dma_controller_info {
|
|
+ u16 DMATransferMode; /**< DMA Transfer Mode */
|
|
+ u16 bChEnabled; /**< To know if channel is enabled or
|
|
+ not */
|
|
+ struct ioh_dma_desc *pHeadOfList; /**< Pointer to start
|
|
+ descriptor */
|
|
+ struct ioh_dma_desc *pTailOfList; /**< Pointer to last
|
|
+ descriptor */
|
|
+ void (*call_back_func_ptr) (int, unsigned long);/**< Address of the call
|
|
+ back function that is to be called when
|
|
+ an interrupt occurs */
|
|
+ u32 callback_data; /**< The data to passed to the callback
|
|
+ function during invocation */
|
|
+ u16 DMAAccessSize; /**< To store the access size (8bit,
|
|
+ 16bit or 32bit) */
|
|
+ u16 DMATransferSize; /**< To store the value of Transfer
|
|
+ Size */
|
|
+ u16 DMATransferDirection; /**< To store the Direction of Transfer
|
|
+ (IN to OUT or OUT to IN) */
|
|
+ u32 in_addr; /**< The in_address */
|
|
+ u32 out_addr; /**< The out_address */
|
|
+};
|
|
+
|
|
+/*! @ingroup HALLayerFacilitators
|
|
+ @struct ioh_dma_channel_alloc_table
|
|
+ @brief Format for storing the details of the
|
|
+ allocation details of the DMA channels.
|
|
+*/
|
|
+
|
|
+struct ioh_dma_channel_alloc_table {
|
|
+ u32 dma_dev_id; /**< The DMA device ID. */
|
|
+ enum ioh_channel_request_id request_signal; /**< The request type.*/
|
|
+ u32 req_device_id; /**< The device ID of the requested device */
|
|
+ u16 channel; /**< The channel number. */
|
|
+ u16 ch_found:1; /**< The flag variable for channel in use */
|
|
+ u16 ch_alloced:1; /**< The flag variable for channel allocate. */
|
|
+ u32 base; /**< The base address of the DMA device. */
|
|
+};
|
|
+
|
|
+ /*****/
|
|
+
|
|
+extern struct ioh_dma_channel_alloc_table
|
|
+ ioh_dma_channel_table[IOH_DMA_CHANNELS_MAX];
|
|
+extern struct ioh_dma_controller_info
|
|
+ ioh_dma_channel_info[IOH_DMA_CHANNELS_MAX];
|
|
+
|
|
+void dma_init(u32 base, u32 dev_type);
|
|
+int dma_free_ch(int channel);
|
|
+int dma_request_ch(u32 req_dev_id, int dreq);
|
|
+int dma_set_mode(int channel, struct ioh_dma_mode_param stModeParam);
|
|
+int dma_set_addr(int channel, u32 iaddr, u32 oaddr);
|
|
+int dma_enable_ch(int channel);
|
|
+int dma_disable_ch(int channel);
|
|
+int dma_set_count(int channel, u32 count);
|
|
+int dma_add_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end);
|
|
+int dma_set_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end);
|
|
+void dma_set_callback(int channel,
|
|
+ void (*ioh_dma_cbr) (int value, unsigned long data1),
|
|
+ unsigned long data);
|
|
+irqreturn_t dma_interrupt(int irq, void *dev_id);
|
|
+int dma_set_priority(int channel, int priority);
|
|
+int dma_direct_start(int channel);
|
|
+int dma_enable_disable_interrupt(int channel, int bEnable);
|
|
+void dma_get_abort_status(int channel, u16 *pAbortStatus);
|
|
+void dma_get_interrupt_status(int channel, u16 *pInterruptStatus);
|
|
+void get_dma_status(int channel, u16 *pDMAStatus);
|
|
+void get_free_ch(int index);
|
|
+void dma_exit(u32 dev_type);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/drivers/dma/pch_dma/pch_dma_main.c
|
|
@@ -0,0 +1,1026 @@
|
|
+/**
|
|
+ * @file ioh_dma_main.c
|
|
+ *
|
|
+ * @brief
|
|
+ * This file defines the methods of IOH_DMA driver.
|
|
+ *
|
|
+ *
|
|
+ * @version 0.90
|
|
+ * @section
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
+ *
|
|
+ * <hr>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * History:
|
|
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * created:
|
|
+ * WIPRO 03/07/2009
|
|
+ * modified:
|
|
+ * WIPRO 08/14/2009
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/pci.h>
|
|
+
|
|
+#include "pch_debug.h"
|
|
+#include "pch_dma_hal.h"
|
|
+#include "pch_dma_pci.h"
|
|
+
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_request_dma(struct pci_dev *pdev, int dreq)
|
|
+ @brief Used to request a DMA channel.
|
|
+ @remarks Requests to reserve a DMA channel that connects
|
|
+ to number 'dreq' (DMA request signal) of PCI
|
|
+ device 'pdev' to the appropriate DMA channel
|
|
+ allocated for it within the DMA Controller. This
|
|
+ function is called by functions from other
|
|
+ kernel modules. The tasks performed by this
|
|
+ function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid,
|
|
+ if not suitable error status codes are returned
|
|
+ to the called function.
|
|
+ - If valid interacts with the HAL API and
|
|
+ returns the status code returned by the HAL API.
|
|
+
|
|
+ @note This function is accessible by other kernel modules.
|
|
+
|
|
+ @param dev [@ref IN] PCI device that requires the DMA
|
|
+ channel.
|
|
+ @param dreq [@ref IN] DMA request signal number.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> Device is in suspend mode.
|
|
+ - -EINVAL --> pdev does not have a DMA request
|
|
+ type or number 'dreq' or 'pdev'
|
|
+ is NULL.
|
|
+*/
|
|
+int ioh_request_dma(struct pci_dev *pdev, int dreq)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* Attaining the lock. */
|
|
+ spin_lock(&ioh_device_lock);
|
|
+
|
|
+ /* If device suspended. */
|
|
+ if (1 == ioh_device_suspended) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_request_dma -> Device is in suspend mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Invalid device structure. */
|
|
+ else if (NULL == pdev) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_request_dma -> Obtained device structure "
|
|
+ "is NULL.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Invalid request signal. */
|
|
+ else if ((dreq < IOH_DMA_TX_DATA_REQ0) ||
|
|
+ (dreq > IOH_DMA_RX_DATA_REQ5)) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_request_dma -> Invalid request signal.\n");
|
|
+ retval = -EINVAL;
|
|
+ } else {
|
|
+ /* Requesting for reserving a DMA channel. */
|
|
+ retval = dma_request_ch((u32) (pdev->device), dreq);
|
|
+ IOH_DEBUG("ioh_request_dma -> Function dma_request_ch returned "
|
|
+ "%d.\n", retval);
|
|
+ }
|
|
+
|
|
+ /* Releasing the lock. */
|
|
+ spin_unlock(&ioh_device_lock);
|
|
+
|
|
+ IOH_DEBUG("Function ioh_request_dma returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_request_dma);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_free_dma(int channel)
|
|
+ @brief Used to free a DMA channel.
|
|
+ @remarks Frees the allocated DMA channel that is provided
|
|
+ as the argument to the function. This function
|
|
+ is called by the functions from other kernel
|
|
+ modules. The main tasks performed by this
|
|
+ function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API for
|
|
+ freeing the channel and returns the status code
|
|
+ returned by the HAL API.
|
|
+ @note This function is accessible by other kernel
|
|
+ modules.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> Device is in suspend mode.
|
|
+ - -ENODEV --> Specified DMA channel does
|
|
+ not exist.
|
|
+*/
|
|
+int ioh_free_dma(int channel)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ if (1 == ioh_device_suspended) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_free_dma -> Device is in suspend mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ } else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_free_dma -> Invalid Channel number: "
|
|
+ "%d.\n", channel);
|
|
+ retval = -ENODEV;
|
|
+ } else {
|
|
+ retval = dma_free_ch(channel);
|
|
+ IOH_DEBUG("ioh_free_dma -> Function dma_free_ch "
|
|
+ "returned %d.\n", retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_free_dma returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_free_dma);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_set_dma_mode(int channel,struct
|
|
+ ioh_dma_mode_param stModeParam)
|
|
+ @brief Used to set the mode of the DMA.
|
|
+ @remarks Sets the mode of DMA transfer - One shot mode
|
|
+ or Scatter/gather mode. In addition to this,
|
|
+ the function also sets the direction of DMA
|
|
+ transfer and DMA Size type. This function is
|
|
+ called by functions from other kernel modules.
|
|
+ The main tasks performed by this function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API to set the
|
|
+ required settings and returns the status code
|
|
+ returned by the HAL API.
|
|
+
|
|
+ @note This function is accessible by other kernel modules.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number
|
|
+ @param stModeParam [@ref IN] Contains info about
|
|
+ direction of DMA transfer, mode
|
|
+ and Size type
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> The device is in suspend
|
|
+ mode.
|
|
+ - -ENODEV --> Specified DMA channel does
|
|
+ not exist.
|
|
+ - -EINVAL --> Parameter passed is invalid.
|
|
+ - -EBUSY --> DMA channel is already
|
|
+ enabled.
|
|
+*/
|
|
+int ioh_set_dma_mode(int channel, struct ioh_dma_mode_param stModeParam)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* Checking if device suspended. */
|
|
+ if (1 == ioh_device_suspended) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_mode -> Device is in suspend mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number. */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_mode -> Invalid Channel number : " "%d.\n",
|
|
+ channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel not allocated. */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_mode -> Channel not allocated.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking if channel already enabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == 1) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_mode -> Channel already enabled.\n");
|
|
+ retval = -EBUSY;
|
|
+ }
|
|
+ /* Checking for validity of DMA Transfer MODE. */
|
|
+ else if ((stModeParam.DMATransferMode != (u16) DMA_ONE_SHOT_MODE) &&
|
|
+ (stModeParam.DMATransferMode !=
|
|
+ (u16) DMA_SCATTER_GATHER_MODE)) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_mode -> Invalid DMA Transfer mode.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking for validity of Transfer Direction. */
|
|
+ else if ((stModeParam.TransferDirection != (u16) IOH_DMA_DIR_OUT_TO_IN)
|
|
+ && (stModeParam.TransferDirection !=
|
|
+ (u16) IOH_DMA_DIR_IN_TO_OUT)) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_mode -> Invalid DMA Transfer Direction." \
|
|
+ "\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking for validity of Transfer Size Type. */
|
|
+ else if ((stModeParam.DMASizeType != (u16) IOH_DMA_SIZE_TYPE_8BIT) &&
|
|
+ (stModeParam.DMASizeType != (u16) IOH_DMA_SIZE_TYPE_16BIT) &&
|
|
+ (stModeParam.DMASizeType != (u16) IOH_DMA_SIZE_TYPE_32BIT)) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_mode -> Invalid DMA Size Type.\n");
|
|
+ retval = -EINVAL;
|
|
+ } else {
|
|
+ /* Setting the required DMA mode. */
|
|
+ retval = dma_set_mode(channel, stModeParam);
|
|
+ IOH_DEBUG("ioh_set_dma_mode -> Function dma_set_mode "
|
|
+ "returned %d.\n", retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_set_dma_mode returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_set_dma_mode);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_set_dma_addr(int channel, unsigned int iaddr,
|
|
+ unsigned int oaddr)
|
|
+ @brief Used to set the in and out address of the DMA channel.
|
|
+ @remarks Sets the address of the inside bridge and the outside
|
|
+ bridge for the 'One Shot Mode' of DMA Transfer.
|
|
+ This function is invoked by functions from other
|
|
+ modules. The main tasks performed by this
|
|
+ function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API to set the
|
|
+ inside and outside address and returns the
|
|
+ status code returned by the HAL API.
|
|
+ @note This function is accessible by other kernel modules. The
|
|
+ following points has to be noted while passing
|
|
+ the in-address and out-address paramter.
|
|
+ - The address passed should be valid physical
|
|
+ address within the memory space.
|
|
+ - It should not be a configuration space or IO
|
|
+ space address.
|
|
+ - If the transfer is for large data, the address
|
|
+ should point to contagious alligned memory space
|
|
+ .
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number .
|
|
+ @param iaddr [@ref IN] Address of inside bridge.
|
|
+ @param oaddr [@ref IN] Address of outside bridge.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> The device is in suspend mode.
|
|
+ - -ENODEV --> Specified DMA channel does not exist.
|
|
+ - -EINVAL --> Parameter passed is invalid.
|
|
+ - -EBUSY --> DMA transfer in progress or channel is
|
|
+ already enabled.
|
|
+
|
|
+*/
|
|
+int ioh_set_dma_addr(int channel, unsigned int iaddr, unsigned int oaddr)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* If the device is in suspend mode. */
|
|
+ if (1 == ioh_device_suspended) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_addr -> Device is in suspend mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_addr -> Invalid Channel "
|
|
+ "number: %d.\n", channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel is not allocated. */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_addr -> Channel not "
|
|
+ "allocated.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether the channel is already enabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == 1) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_addr -> Channel already "
|
|
+ "enabled.\n");
|
|
+ retval = -EBUSY;
|
|
+ }
|
|
+ /*Checking if addresses specified are NULL or not */
|
|
+ else if ((iaddr == 0) || (oaddr == 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_addr -> Invalid address.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking if the mode of transfer is other than ONE_SHOT. */
|
|
+ else if (ioh_dma_channel_info[channel].DMATransferMode !=
|
|
+ (u16) DMA_ONE_SHOT_MODE) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_addr -> Current Mode is "
|
|
+ "not DMA_ONE_SHOT_MODE.\n");
|
|
+ retval = -EINVAL;
|
|
+ } else {
|
|
+ /* setting the in and out address. */
|
|
+ retval = dma_set_addr(channel, iaddr, oaddr);
|
|
+ IOH_DEBUG("ioh_set_dma_addr -> Function dma_set_addr invoked "
|
|
+ "successfully returned %d.\n", retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_set_dma_addr returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_set_dma_addr);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_set_dma_count(int channel, unsigned int count)
|
|
+ @brief Used to set the DMA transfer count for a DMA channel.
|
|
+ @remarks Sets the value of DMA transfer count. This function
|
|
+ sets the count value only for the 'One Shot
|
|
+ Mode' of DMA Transfer. This function is invoked
|
|
+ by functions from other modules. The main tasks
|
|
+ performed by this function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API to set the
|
|
+ access count settings and returns the status
|
|
+ code returned by the HAL API.
|
|
+ @note This function is accessible by other kernel modules.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number.
|
|
+ @param count [@ref IN] The number of bytes to transfer.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> The device is in suspend mode.
|
|
+ - -ENODEV --> Specified DMA channel does not
|
|
+ exist.
|
|
+ - -EBUSY --> DMA transfer in progress or channel
|
|
+ is already enabled.
|
|
+ - -EINVAL --> Parameter passed is invalid.
|
|
+
|
|
+ */
|
|
+int ioh_set_dma_count(int channel, unsigned int count)
|
|
+{
|
|
+ int retval = IOH_DMA_SUCCESS;
|
|
+
|
|
+ /* Checking if the device is in suspend mode. */
|
|
+ if (1 == ioh_device_suspended) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_count -> The device is in "
|
|
+ "suspend mode.");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number. */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_count -> Invalid Channel "
|
|
+ "number : %d.\n", channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel is not allocated. */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_count -> Channel is not "
|
|
+ "allocated.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether the channel is enabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == 1) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_count -> Channel already "
|
|
+ "enabled.\n");
|
|
+ retval = -EBUSY;
|
|
+ }
|
|
+ /* Checking if the mode of transfer is other than ONE_SHOT. */
|
|
+ else if (ioh_dma_channel_info[channel].DMATransferMode !=
|
|
+ (u16) DMA_ONE_SHOT_MODE) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_count -> Current Mode is "
|
|
+ "not DMA_ONE_SHOT_MODE.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking the limits of count value. */
|
|
+ else {
|
|
+ unsigned int max_count;
|
|
+
|
|
+ switch (ioh_dma_channel_info[channel].DMAAccessSize) {
|
|
+ case IOH_DMA_SIZE_TYPE_8BIT:
|
|
+ max_count = IOH_DMA_8BIT_COUNT_MAX;
|
|
+ break;
|
|
+
|
|
+ case IOH_DMA_SIZE_TYPE_16BIT:
|
|
+ max_count = IOH_DMA_16BIT_COUNT_MAX;
|
|
+ break;
|
|
+
|
|
+ case IOH_DMA_SIZE_TYPE_32BIT:
|
|
+ max_count = IOH_DMA_32BIT_COUNT_MAX;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_count -> Invalid Access "
|
|
+ "Size.\n");
|
|
+ max_count = 0;
|
|
+ retval = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if ((retval == IOH_DMA_SUCCESS) && (count > max_count)) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_count -> Count (%d) exceeds "
|
|
+ "limit the maximum expected count (%d).\n",
|
|
+ count, max_count);
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (IOH_DMA_SUCCESS == retval) {
|
|
+ /* Setting the count. */
|
|
+ retval = dma_set_count(channel, count);
|
|
+ IOH_DEBUG
|
|
+ ("ioh_set_dma_count -> Function dma_set_count returned "
|
|
+ "%d.\n", retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_set_dma_count returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_set_dma_count);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_set_dma_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end)
|
|
+ @brief Used to set the DMA channel descriptors.
|
|
+ @remarks Sets the DMA descriptor for the 'Scatter/Gather mode'
|
|
+ of DMA transfer. This function is invoked by
|
|
+ functions from other kernel modules. The main
|
|
+ tasks performed by this function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API to set the
|
|
+ descriptor settings and returns the status code
|
|
+ returned by the HAL API.
|
|
+ @note This function is accessible by other kernel modules. The
|
|
+ following points have to be noted while passing
|
|
+ the "start" and "end" pointer of the descriptor.
|
|
+ - The address pointed by them should be physical
|
|
+ address with valid virtual address.
|
|
+ - The space should be alligned and accessible by
|
|
+ the DMA hardware.
|
|
+ - An easy way to perform this is to allocate the
|
|
+ descriptor memory using kmalloc.
|
|
+ - The last two bits of the physical address
|
|
+ should be suitably set so as to perform suitable
|
|
+ action after completion of each descriptor
|
|
+ action.
|
|
+ - The in-address and out-address within each
|
|
+ descriptor should be a valid memory space
|
|
+ physical address.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number
|
|
+ @param start [@ref IN] A pointer to the first descriptor.
|
|
+ @param end [@ref IN] A pointer to the last descriptor.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> The device is in suspend.
|
|
+ - -EINVAL --> For invalid parameters.
|
|
+ - -ENODEV --> Specified DMA channel is not exist.
|
|
+ - -EBUSY --> If DMA transfer is in progress or
|
|
+ channel is already enabled.
|
|
+*/
|
|
+int ioh_set_dma_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* Checking if the device is in suspend mode. */
|
|
+ if (1 == ioh_device_suspended) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_desc -> The device is in "
|
|
+ "suspend mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_desc -> Invalid Channel number "
|
|
+ ": %d.\n", channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel is not allocated. */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_desc -> Channel not allocated.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether the channel is enabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == 1) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_desc -> Channel already enabled.\n");
|
|
+ retval = -EBUSY;
|
|
+ }
|
|
+ /* Checking if the mode is other than SCATTER_GATHER. */
|
|
+ else if (ioh_dma_channel_info[channel].DMATransferMode !=
|
|
+ (u16) DMA_SCATTER_GATHER_MODE) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_desc -> Current mode id is not "
|
|
+ "SCATTER GATHER.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether start and end pointers are NULL or not */
|
|
+ else if ((start == NULL) || (end == NULL)) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_set_dma_desc -> NULL pointer parameter.\n");
|
|
+ retval = -EINVAL;
|
|
+ } else {
|
|
+ /* Setting the descriptors. */
|
|
+ retval = dma_set_desc(channel, start, end);
|
|
+ IOH_DEBUG("ioh_set_dma_desc -> Function dma_set_desc "
|
|
+ "returned %d.\n", retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_set_dma_desc returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_set_dma_desc);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_add_dma_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end)
|
|
+ @brief Used to append the DMA descriptors for a channel.
|
|
+ @remarks Used when a new chain of descriptors is to be appended
|
|
+ to the existing chain of descriptors. This
|
|
+ function is invoked by functions from other
|
|
+ modules. The main tasks performed by this
|
|
+ function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API to append
|
|
+ the descriptor settings and returns the status
|
|
+ code returned by the HAL API.
|
|
+ @note This function is accessible by other kernel modules.
|
|
+ The following points have to be noted while
|
|
+ passing the "start" and "end" pointer of the
|
|
+ descriptor.
|
|
+ - The address pointer by them should be physical
|
|
+ address with valid virtual address.
|
|
+ - The space should be alligned and accessible by
|
|
+ the DMA hardware.
|
|
+ - An easy way to perform this is to allocate the
|
|
+ descriptor memory using kmalloc.
|
|
+ - The last two bits of the physical address
|
|
+ should be suitably set so as to perform suitable
|
|
+ action after completion of each descriptor
|
|
+ action.
|
|
+ - The in-address and out-address within each
|
|
+ descriptor should be a valid memory space
|
|
+ physical address.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number
|
|
+ @param start [@ref IN] A pointer to the first descriptor.
|
|
+ @param end [@ref IN] A pointer to the last descriptor.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> The device is in suspend mode.
|
|
+ - -ENODEV --> Specified DMA channel does not
|
|
+ exist.
|
|
+ - -EINVAL --> Invalid parameters passed.
|
|
+ - -EBUSY --> If DMA Transfer in progress or
|
|
+ channel is already enabled.
|
|
+ */
|
|
+int ioh_add_dma_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* Checking whether the device is in suspend mode. */
|
|
+ if (1 == ioh_device_suspended) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_add_dma_desc -> The device is in suspend "
|
|
+ "mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_add_dma_desc -> Invalid Channel "
|
|
+ "number : %d", channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel is not allocated. */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_add_dma_desc -> Channel not alloctaed.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether the channel is enabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == 1) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_add_dma_desc -> Channel already enabled.\n");
|
|
+ retval = -EBUSY;
|
|
+ }
|
|
+ /* Checking whether the mode is other than SCATTER_GATHER. */
|
|
+ else if (ioh_dma_channel_info[channel].DMATransferMode !=
|
|
+ (u16) DMA_SCATTER_GATHER_MODE) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_add_dma_desc -> Current mode id is not "
|
|
+ "SCATTER_GATHER.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking if descriptor field of the channel is set earlier. */
|
|
+ else if ((ioh_dma_channel_info[channel].pHeadOfList == NULL) ||
|
|
+ (ioh_dma_channel_info[channel].pTailOfList == NULL)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_add_dma_desc -> Descriptor list not "
|
|
+ "set earlier.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether start and end pointers are NULL or not */
|
|
+ else if ((start == NULL) || (end == NULL)) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_add_dma_desc -> NULL pointer parameter.\n");
|
|
+ retval = -EINVAL;
|
|
+ } else {
|
|
+ /* Appending the descriptors to the available list. */
|
|
+ retval = dma_add_desc(channel, start, end);
|
|
+ IOH_DEBUG
|
|
+ ("ioh_add_dma_desc -> Function dma_add_desc returned %d.\n",
|
|
+ retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_add_dma_desc returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_add_dma_desc);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_enable_dma(int channel)
|
|
+ @brief Used to enable a DMA channel.
|
|
+ @remarks Used when a DMA channel has to be enabled. This
|
|
+ function is invoked by functions from other
|
|
+ kernel modules. The main tasks performed by this
|
|
+ function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API to enable
|
|
+ the channel and returns the status code returned
|
|
+ by the HAL API.
|
|
+ @note This function is accessible by other kernel modules.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number .
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> Device is in suspend mode.
|
|
+ - -ENODEV --> Specified DMA channel does
|
|
+ not exist.
|
|
+ - -EINVAL --> Specified channel is not
|
|
+ allocated.
|
|
+ - -EBUSY --> DMA Transfer already in
|
|
+ progress or channel is
|
|
+ already enabled.
|
|
+ */
|
|
+int ioh_enable_dma(int channel)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* Checking whether the device is in suspend mode. */
|
|
+ if (ioh_device_suspended == 1) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_enable_dma -> Device is in suspend "
|
|
+ "mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_enable_dma ->Invalid Channel number "
|
|
+ ": %d.\n", channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel is allocated. */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_enable_dma -> Channel not allocated.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether the channel is already enabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == 1) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_enable_dma -> Channel already enabled.\n");
|
|
+ retval = -EBUSY;
|
|
+ } else {
|
|
+ /* Enabling the channel. */
|
|
+ retval = dma_enable_ch(channel);
|
|
+ IOH_DEBUG("ioh_enable_dma -> Function dma_enable_ch returned "
|
|
+ "%d.\n", retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_enable_dma returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_enable_dma);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_disable_dma(int channel)
|
|
+ @brief Used to disable a DMA channel.
|
|
+ @remarks Used when a DMA channel has to be disabled. This
|
|
+ function is invoked by functions from other
|
|
+ kernel modules. The main tasks performed by this
|
|
+ function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API to disable
|
|
+ the channel and returns the status code returned
|
|
+ by the HAL API.
|
|
+ @note This function is accessible by other kernel modules.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number .
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -ENODEV --> Specified DMA channel does not
|
|
+ exist.
|
|
+ - -EINVAL --> Specified channel is not allocated.
|
|
+
|
|
+ */
|
|
+int ioh_disable_dma(int channel)
|
|
+{
|
|
+ int retval;
|
|
+ u16 statusInfo;
|
|
+
|
|
+ /* Checking whether the device is in suspend mode. */
|
|
+ if (ioh_device_suspended == 1) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_disable_dma -> Device is in "
|
|
+ "suspend mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number. */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_disable_dma -> Invalid Channel "
|
|
+ "number : %d", channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel is allocated. */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_disable_dma -> Channel not "
|
|
+ "allocated.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Check whether channel is already disabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == (u16) 0) {
|
|
+ retval = IOH_DMA_SUCCESS;
|
|
+ } else {
|
|
+ u32 counter = COUNTER_LIMIT;
|
|
+
|
|
+ /* Wait for any DMA for certain interval transfer to end
|
|
+ before disabling the channel */
|
|
+ do {
|
|
+ get_dma_status(channel, &statusInfo);
|
|
+ } while ((counter--) && (statusInfo != (u16) DMA_STATUS_IDLE));
|
|
+
|
|
+ /* Disabling the channel. */
|
|
+ retval = dma_disable_ch(channel);
|
|
+ IOH_DEBUG("ioh_disable_dma -> Function dma_disable_ch "
|
|
+ "returned %d.\n", retval);
|
|
+
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_disable_dma returns " "%d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_disable_dma);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_dma_set_callback(int channel,
|
|
+ void (*ioh_dma_cbr)( int value,unsigned long data1),
|
|
+ unsigned long data)
|
|
+ @brief Used to set the callback function for particular DMA channel.
|
|
+ @remarks Sets the callback function to be called when an
|
|
+ interrupt occurs. This function is invoked by
|
|
+ functions from other kernel modules. The main
|
|
+ tasks performed by this function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API to set the
|
|
+ callback function settings and returns the
|
|
+ status code returned by the HAL API.
|
|
+ @note This function is accessible by other kernel modules.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number .
|
|
+ @param ioh_dma_cbr [@ref IN] Pointer to the call-back
|
|
+ function.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> Device is in suspend mode.
|
|
+ - -EINVAL --> Parameter passed is invalid.
|
|
+ - -ENODEV --> Specified DMA channel does
|
|
+ not exist.
|
|
+ - -EBUSY --> If the channel is already
|
|
+ enabled.
|
|
+ */
|
|
+int ioh_dma_set_callback(int channel,
|
|
+ void (*ioh_dma_cbr) (int value, unsigned long data1),
|
|
+ unsigned long data)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* Checking whether the device is in suspend mode. */
|
|
+ if (ioh_device_suspended == 1) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_dma_set_callback -> The device is "
|
|
+ "in suspend mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_dma_set_callback -> Invalid Channel "
|
|
+ "number : %d.\n", channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel is not allocated. */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_set_callback -> Channel not allocated.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether the channel is already enabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == 1) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_set_callback -> Channel already enabled.\n");
|
|
+ retval = -EBUSY;
|
|
+ }
|
|
+ /* Checking whether function pointer is NULL or not */
|
|
+ else if (ioh_dma_cbr == NULL) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_set_callback -> NULL pointer parameter.\n");
|
|
+ retval = -EINVAL;
|
|
+ } else {
|
|
+ /* Setting the callback. */
|
|
+ dma_set_callback(channel, ioh_dma_cbr, data);
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_set_callback -> Function dma_set_callback invoked"
|
|
+ " successfully.\n");
|
|
+
|
|
+ retval = IOH_DMA_SUCCESS;
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_dma_set_callback " "returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_dma_set_callback);
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @fn int ioh_set_dma_priority (int channel, int priority)
|
|
+ @brief Sets the priority of the DMA channel.
|
|
+ @remarks Sets the priority that has to be assigned for a
|
|
+ particular channel. This function is invoked by
|
|
+ functions from other kernel modules. The main
|
|
+ tasks performed by this function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not, suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid, interacts with the HAL API to set
|
|
+ the DMA channel priority settings and returns
|
|
+ the status code returned by the HAL API.
|
|
+ @note This function is accessible by other kernel modules.
|
|
+
|
|
+ @param channel [@ref IN] DMA channel number.
|
|
+ @param priority [@ref IN] Priority to be set for the
|
|
+ DMA channel.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> Device is in suspend mode.
|
|
+ - -EINVAL --> Parameter passed is invalid.
|
|
+ - -EBUSY --> If channel is in use.
|
|
+ - -ENODEV --> Specified DMA channel does not
|
|
+ exist.
|
|
+
|
|
+ */
|
|
+int ioh_set_dma_priority(int channel, int priority)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* Checking whether the device is in suspend mode. */
|
|
+ if (ioh_device_suspended == 1) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_priority -> The device is "
|
|
+ "in suspend mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_priority -> Invalid Channel "
|
|
+ "number : %d", channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel is not allocated. */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_priority -> Channel not "
|
|
+ "allocated.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether the device is enabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == 1) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_priority -> Channel already "
|
|
+ "enabled.\n");
|
|
+ retval = -EBUSY;
|
|
+ }
|
|
+ /* Check for validity of priority value */
|
|
+ else if ((priority > 3) || (priority < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_set_dma_priority -> Invalid value "
|
|
+ "priority (%d)", priority);
|
|
+ retval = -EINVAL;
|
|
+ } else {
|
|
+ retval = dma_set_priority(channel, priority);
|
|
+ IOH_DEBUG("ioh_set_dma_priority -> Function dma_set_priority "
|
|
+ "returns %d.\n", retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_set_dma_priority returns " "%d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_set_dma_priority);
|
|
+
|
|
+/*! @ingroup InterfaceLayerAPI
|
|
+ @fn int ioh_dma_direct_start (int channel)
|
|
+ @brief Used to initiate a DMA transfer.
|
|
+ @remarks Generates the DMA request to begin DMA transfer
|
|
+ on a particular channel. This function is
|
|
+ invoked by functions from other kernel modules.
|
|
+ The main tasks performed by this function are:
|
|
+ - Verifies whether the obtained parameters are
|
|
+ valid, if not suitable error status codes are
|
|
+ returned to the called function.
|
|
+ - If valid interacts with the HAL API to
|
|
+ initiate the DMA process and returns the status
|
|
+ code returned by the HAL API.
|
|
+ @note This function is accessible by other kernel modules.
|
|
+
|
|
+ @param channel DMA channel number.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EAGAIN --> Device is in suspend mode.
|
|
+ - -EBUSY --> Specified DMA channel is not idle.
|
|
+ - -ENODEV --> Specified DMA channel does not
|
|
+ exist.
|
|
+ - -EINVAL --> Specified channel is not allocated.
|
|
+
|
|
+ */
|
|
+int ioh_dma_direct_start(int channel)
|
|
+{
|
|
+ int retval = 0;
|
|
+
|
|
+ /* Checking whether the device is in suspend mode. */
|
|
+ if (ioh_device_suspended == 1) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_dma_direct_start -> The device is in "
|
|
+ "suspend mode.\n");
|
|
+ retval = -EAGAIN;
|
|
+ }
|
|
+ /* Checking for validity of channel number */
|
|
+ else if ((channel >= IOH_DMA_CHANNELS_MAX) || (channel < 0)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_dma_direct_start -> Invalid Channel "
|
|
+ "number : %d.\n", channel);
|
|
+ retval = -ENODEV;
|
|
+ }
|
|
+ /* Checking whether channel is reserved or not */
|
|
+ else if (ioh_dma_channel_table[channel].ch_alloced == (u16) 0) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_dma_direct_start -> Channel not "
|
|
+ "allocated.\n");
|
|
+ retval = -EINVAL;
|
|
+ }
|
|
+ /* Checking whether the device is not enabled. */
|
|
+ else if (ioh_dma_channel_info[channel].bChEnabled == 0) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_dma_direct_start -> Channel not "
|
|
+ "enabled.\n");
|
|
+ retval = -EBUSY;
|
|
+ } else {
|
|
+ /* Initiating the DMA transfer */
|
|
+ retval = dma_direct_start(channel);
|
|
+ IOH_DEBUG("ioh_dma_direct_start -> Function dma_direct_start "
|
|
+ "returned %d.\n", retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_dma_direct_start returns " "%d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+EXPORT_SYMBOL(ioh_dma_direct_start);
|
|
--- /dev/null
|
|
+++ b/drivers/dma/pch_dma/pch_dma_main.h
|
|
@@ -0,0 +1,264 @@
|
|
+/**
|
|
+ * @file ioh_dma_main.h
|
|
+ *
|
|
+ * @brief
|
|
+ * This file declares the structures & data types used by the
|
|
+ * IOH_DMA driver.
|
|
+ *
|
|
+ * @version 0.90
|
|
+ * @section
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
+ *
|
|
+ * <hr>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * History:
|
|
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * created:
|
|
+ * WIPRO 03/07/2009
|
|
+ * modified:
|
|
+ * WIPRO 08/14/2009
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __IOH_DMA_H__
|
|
+#define __IOH_DMA_H__
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def DMA_ONE_SHOT_MODE
|
|
+ @brief Constant used to denote the mode as ONE_SHOT.
|
|
+ @note This constant is used by other modules to make the
|
|
+ DMA module aware of the mode it requires.
|
|
+*/
|
|
+#define DMA_ONE_SHOT_MODE (0x2U)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def DMA_SCATTER_GATHER_MODE
|
|
+ @brief Constant used to denote the mode as SCATTER_GATHER.
|
|
+ @note This constant is used by other modules to make the
|
|
+ DMA module aware of the mode it requires.
|
|
+*/
|
|
+#define DMA_SCATTER_GATHER_MODE (0x1U)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_SIZE_TYPE_8BIT
|
|
+ @brief Constant used to denote the access size as 8BIT.
|
|
+ @note This constant is used by other modules to make the
|
|
+ DMA module aware of the access size it requires.
|
|
+*/
|
|
+#define IOH_DMA_SIZE_TYPE_8BIT ((0x3U << 12))
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_SIZE_TYPE_16BIT
|
|
+ @brief Constant used to denote the access size as 16BIT.
|
|
+ @note This constant is used by other modules to make the
|
|
+ DMA module aware of the access size it requires.
|
|
+*/
|
|
+#define IOH_DMA_SIZE_TYPE_16BIT ((0x2U << 12))
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_SIZE_TYPE_32BIT
|
|
+ @brief Constant used to denote the access size as 32BIT.
|
|
+ @note This constant is used by other modules to make the
|
|
+ DMA module aware of the access size it requires.
|
|
+*/
|
|
+#define IOH_DMA_SIZE_TYPE_32BIT (0x0U)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_DIR_OUT_TO_IN
|
|
+ @brief Constant used to denote the transfer direction as
|
|
+ OUT_TO_IN.
|
|
+ @note This constant is used by other modules to make the
|
|
+ DMA module aware of the transfer direction it
|
|
+ requires.
|
|
+*/
|
|
+#define IOH_DMA_DIR_OUT_TO_IN (0x4)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_DIR_IN_TO_OUT
|
|
+ @brief Constant used to denote the transfer direction as
|
|
+ IN_TO_OUT.
|
|
+ @note This constant is used by other modules to make the
|
|
+ DMA module aware of the transfer direction it
|
|
+ requires.
|
|
+*/
|
|
+#define IOH_DMA_DIR_IN_TO_OUT (0x0)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_END
|
|
+ @brief Constant used to denote the transfer status as ACCESS
|
|
+ @note This constant is used by DMA modules to make the
|
|
+ other module aware that the DMA operation ended
|
|
+ normally.
|
|
+*/
|
|
+#define IOH_DMA_END (0)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_ABORT
|
|
+ @brief Constant used to denote the transfer status as ACCESS
|
|
+ @note This constant is used by DMA modules to make the
|
|
+ other module aware that the DMA abort has
|
|
+ occurred.
|
|
+*/
|
|
+#define IOH_DMA_ABORT (-1)
|
|
+
|
|
+/* Bits to be sit as LSB2 bits of descriptor address. */
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def DMA_DESC_END_WITH_INTERRUPT
|
|
+ @brief Mask value for modifying the next descriptor
|
|
+ address, so that the descriptor end with
|
|
+ interrupt.
|
|
+*/
|
|
+#define DMA_DESC_END_WITH_INTERRUPT (0x00000001UL)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def DMA_DESC_FOLLOW_WITH_INTERRUPT
|
|
+ @brief Mask value for modifying the next descriptor
|
|
+ address, so that the descriptor follow with
|
|
+ interrupt.
|
|
+
|
|
+*/
|
|
+#define DMA_DESC_FOLLOW_WITH_INTERRUPT (0x00000003UL)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def DMA_DESC_END_WITHOUT_INTERRUPT
|
|
+ @brief Mask value for modifying the next descriptor
|
|
+ address, so that the descriptor end without
|
|
+ interrupt.
|
|
+*/
|
|
+#define DMA_DESC_END_WITHOUT_INTERRUPT (0x00000000UL)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def DMA_DESC_FOLLOW_WITHOUT_INTERRUPT
|
|
+ @brief Mask value for modifying the next descriptor
|
|
+ address, so that the descriptor follow without
|
|
+ interrupt.
|
|
+
|
|
+*/
|
|
+#define DMA_DESC_FOLLOW_WITHOUT_INTERRUPT (0x00000002UL)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_8BIT_COUNT_MAX
|
|
+ @brief The maximun transfer count that can be set for
|
|
+ a 8Bit Access.
|
|
+
|
|
+*/
|
|
+#define IOH_DMA_8BIT_COUNT_MAX (0x3FF)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_16BIT_COUNT_MAX
|
|
+ @brief The maximun transfer count that can be set for
|
|
+ a 16Bit Access.
|
|
+
|
|
+*/
|
|
+#define IOH_DMA_16BIT_COUNT_MAX (0x3FF)
|
|
+
|
|
+/*! @ingroup InterfaceLayer
|
|
+ @def IOH_DMA_32BIT_COUNT_MAX
|
|
+ @brief The maximun transfer count that can be set for
|
|
+ a 32Bit Access.
|
|
+
|
|
+*/
|
|
+#define IOH_DMA_32BIT_COUNT_MAX (0x7FF)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def IOH_DMA_SUCCESS
|
|
+ @brief The value indicating a success.
|
|
+*/
|
|
+#define IOH_DMA_SUCCESS (0)
|
|
+
|
|
+/*! @ingroup DMA
|
|
+ @def IOH_DMA_FAILURE
|
|
+ @brief The value indicating a failure.
|
|
+*/
|
|
+#define IOH_DMA_FAILURE (-1)
|
|
+
|
|
+/*! @ingroup InterfaceLayerFacilitators
|
|
+ @enum ioh_channel_request_id
|
|
+ @brief Constant used to denote the channel request type.
|
|
+ @note These constants are used by other modules to make the
|
|
+ DMA module aware of the channel type it
|
|
+ requires.
|
|
+*/
|
|
+enum ioh_channel_request_id {
|
|
+ IOH_DMA_TX_DATA_REQ0 = 1, /**< Transmission channel 0. */
|
|
+ IOH_DMA_RX_DATA_REQ0, /**< Reception channel 0. */
|
|
+ IOH_DMA_TX_DATA_REQ1, /**< Transmission channel 1. */
|
|
+ IOH_DMA_RX_DATA_REQ1, /**< Reception channel 1. */
|
|
+ IOH_DMA_TX_DATA_REQ2, /**< Transmission channel 2. */
|
|
+ IOH_DMA_RX_DATA_REQ2, /**< Reception channel 2. */
|
|
+ IOH_DMA_TX_DATA_REQ3, /**< Transmission channel 3. */
|
|
+ IOH_DMA_RX_DATA_REQ3, /**< Reception channel 3. */
|
|
+ IOH_DMA_TX_DATA_REQ4, /**< Transmission channel 4. */
|
|
+ IOH_DMA_RX_DATA_REQ4, /**< Reception channel 4. */
|
|
+ IOH_DMA_TX_DATA_REQ5, /**< Transmission channel 5. */
|
|
+ IOH_DMA_RX_DATA_REQ5 /**< Reception channel 5. */
|
|
+};
|
|
+
|
|
+/*! @ingroup InterfaceLayerFacilitators
|
|
+ @struct __ioh_dma_mode_param
|
|
+ @brief Format for specifying the mode characteristics of
|
|
+ a channel.
|
|
+ @note This structure is used by other modules to make the
|
|
+ DMA module aware of the channel mode
|
|
+ characteristics.
|
|
+*/
|
|
+
|
|
+struct ioh_dma_mode_param {
|
|
+ u16 TransferDirection; /**< Direction of Transfer(IN to OUT or OUT to
|
|
+ IN). */
|
|
+ u16 DMASizeType; /**< Type of DMA Transfer size (8bit, 16bit or
|
|
+ 32bit). */
|
|
+ u16 DMATransferMode; /**< Mode of Transfer (ONE_SHOT_MODE or
|
|
+ SCATTER_GATHER_MODE). */
|
|
+};
|
|
+
|
|
+/*! @ingroup InterfaceLayerFacilitators
|
|
+ @struct __ioh_dma_desc
|
|
+ @brief Format for specifying the descriptors.
|
|
+ @note This structure is used by other modules to make the
|
|
+ DMA module aware of the channel descriptors in
|
|
+ SCATTER_GATHER_MODE.
|
|
+*/
|
|
+
|
|
+struct ioh_dma_desc {
|
|
+ u32 insideAddress; /**< Inside address. */
|
|
+ u32 outsideAddress; /**< Outside address. */
|
|
+ u32 size; /**< Size. */
|
|
+ u32 nextDesc; /**< Next Descriptor address.*/
|
|
+};
|
|
+
|
|
+extern int ioh_request_dma(struct pci_dev *dev, int dreq);
|
|
+extern int ioh_free_dma(int channel);
|
|
+extern int ioh_set_dma_mode(int channel, struct ioh_dma_mode_param stModeParam);
|
|
+extern int ioh_set_dma_addr(int channel, unsigned int iaddr,
|
|
+ unsigned int oaddr);
|
|
+extern int ioh_set_dma_count(int channel, unsigned int count);
|
|
+extern int ioh_set_dma_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end);
|
|
+extern int ioh_add_dma_desc(int channel, struct ioh_dma_desc *start,
|
|
+ struct ioh_dma_desc *end);
|
|
+extern int ioh_enable_dma(int channel);
|
|
+extern int ioh_disable_dma(int channel);
|
|
+extern int ioh_dma_set_callback(int channel,
|
|
+ void (*ioh_dma_cbr) (int value,
|
|
+ unsigned long data1),
|
|
+ unsigned long data);
|
|
+extern int ioh_set_dma_priority(int channel, int priority);
|
|
+extern int ioh_dma_direct_start(int channel);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/drivers/dma/pch_dma/pch_dma_pci.c
|
|
@@ -0,0 +1,694 @@
|
|
+/**
|
|
+ * @file ioh_dma_pci.c
|
|
+ *
|
|
+ * @brief
|
|
+ * This file defines the methods of IOH_DMA_CONTROLLER driver.
|
|
+ *
|
|
+ * @version 0.90
|
|
+ * @section
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
+ *
|
|
+ * <hr>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * History:
|
|
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * created:
|
|
+ * WIPRO 03/07/2009
|
|
+ * modified:
|
|
+ * WIPRO 08/14/2009
|
|
+ *
|
|
+ */
|
|
+
|
|
+/* inclusion of system specific header files. */
|
|
+#include <linux/module.h>
|
|
+#include <linux/pci.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/spinlock.h>
|
|
+
|
|
+/* inclusion of module specific header files. */
|
|
+#include "pch_debug.h"
|
|
+#include "pch_dma_pci.h"
|
|
+#include "pch_dma_hal.h"
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
+/* Global variables */
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @var MODULE_NAME
|
|
+ @brief The module name variable.
|
|
+ @remarks This variable is used as the module name.
|
|
+*/
|
|
+#define MODULE_NAME "pch_dma"
|
|
+/*! @ingroup Global
|
|
+ @var ioh_device_suspended
|
|
+ @brief Device suspend flag.
|
|
+ @remarks This variable is used as a flag variable
|
|
+ for denoting the device suspend state.
|
|
+ @see
|
|
+ - ioh_dma_suspend
|
|
+ - ioh_dma_resume
|
|
+*/
|
|
+unsigned char ioh_device_suspended;
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @var ioh_device_lock
|
|
+ @brief Device lock variable.
|
|
+ @remarks This variable is used as a lock variable
|
|
+ for accessing the DMA channel.
|
|
+ @see
|
|
+ - ioh_request_dma
|
|
+*/
|
|
+spinlock_t ioh_device_lock;
|
|
+
|
|
+/*! @ingroup Global
|
|
+ @var ioh_dma_devices
|
|
+ @brief Stores the details of the DMA devices.
|
|
+ @remarks This variable is the instance of the structure
|
|
+ struct ioh_dma_devices, which includes fields
|
|
+ for storing the details of the detected DMA
|
|
+ devices. This variable facilitates easy transfer
|
|
+ of information among the different functions of
|
|
+ the DMA module.
|
|
+*/
|
|
+struct ioh_dma_devices ioh_dma_devices[IOH_DMA_MAX_DEVS];
|
|
+
|
|
+/*! @ingroup PCILayerFacilitators
|
|
+ @struct ioh_dma_pcidev_id
|
|
+ @brief The structure for specifying the supported
|
|
+ device IDs to the PCI Kernel subsystem.
|
|
+ @remarks This structure is the instance of the
|
|
+ kernel provided structure pci_device_id,
|
|
+ which is used to store the PCI devices
|
|
+ Vendor and Device ID. This structure is
|
|
+ used during the registration of the DMA module
|
|
+ as PCI Driver. This structure makes the Kernel
|
|
+ aware of the PCI devices supported by this
|
|
+ module.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_controller_driver
|
|
+*/
|
|
+
|
|
+static const struct pci_device_id ioh_dma_pcidev_id[] __devinitdata = {
|
|
+ /* 4 Channel DMA device IDs */
|
|
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOH1_DMA4_0)},
|
|
+
|
|
+ /* 8 Channel DMA device IDs */
|
|
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOH1_DMA8_0)},
|
|
+
|
|
+ /* 12 Channel DMA device IDs */
|
|
+ {}
|
|
+};
|
|
+
|
|
+/* Function prototypes */
|
|
+static int __devinit ioh_dma_probe(struct pci_dev *pdev,
|
|
+ const struct pci_device_id *id);
|
|
+static void __devexit ioh_dma_remove(struct pci_dev *pdev);
|
|
+static int ioh_dma_suspend(struct pci_dev *pdev, pm_message_t state);
|
|
+static int ioh_dma_resume(struct pci_dev *pdev);
|
|
+static __init int ioh_dma_pci_init(void);
|
|
+static __exit void ioh_dma_pci_exit(void);
|
|
+static inline u32 get_dev_type(u32 devid);
|
|
+
|
|
+/*! @ingroup PCILayer
|
|
+ @def IOH_INVALID_DEVICE
|
|
+ @brief The return value of @ref get_dev_type for invalid
|
|
+ device type.
|
|
+
|
|
+ @see
|
|
+ - get_dev_type
|
|
+*/
|
|
+#define IOH_INVALID_DEVICE (0xFFFF)
|
|
+
|
|
+/*! @ingroup InternalFunction
|
|
+ @fn static inline u32 get_dev_type (u32 devid)
|
|
+ @brief Returns the IOH device type for given PCI device id.
|
|
+ @remarks This function returns the type of the detected DMA
|
|
+ device. The type specifies the number of DMA
|
|
+ channels contained within the detected device.
|
|
+ The tasks performed by this function include:
|
|
+ - Matches the PCI device ID passed to it with a
|
|
+ set of known device IDs.
|
|
+ - If a match is found it returns a constant
|
|
+ which indicates the device type (number of DMA
|
|
+ channels) within the device.
|
|
+ - If no match is found it returns @ref
|
|
+ IOH_INVALID_DEVICE.
|
|
+
|
|
+ @param devid [@ref IN] The device ID to be verified.
|
|
+
|
|
+ @return u32
|
|
+ - Values other than @ref IOH_INVALID_DEVICE
|
|
+ --> Detected device is valid and
|
|
+ supported.
|
|
+ - @ref IOH_INVALID_DEVICE --> Invalid device
|
|
+ detected.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_probe
|
|
+
|
|
+*/
|
|
+static inline u32 get_dev_type(u32 devid)
|
|
+{
|
|
+ u32 dev_type;
|
|
+
|
|
+ switch (devid) {
|
|
+ case PCI_DEVICE_ID_INTEL_IOH1_DMA4_0:
|
|
+ dev_type = IOH_DMA_4CH0;
|
|
+ break;
|
|
+
|
|
+ case PCI_DEVICE_ID_INTEL_IOH1_DMA8_0:
|
|
+ dev_type = IOH_DMA_8CH0;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ IOH_LOG(KERN_ERR, "get_dev_type -> Unknown PCI "
|
|
+ "device 0x%x\n", devid);
|
|
+ dev_type = IOH_INVALID_DEVICE;
|
|
+ break;
|
|
+
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function get_dev_type returns %x.\n", dev_type);
|
|
+ return dev_type;
|
|
+}
|
|
+
|
|
+/*! @ingroup PCILayerAPI
|
|
+ @fn static int __devinit ioh_dma_probe(struct pci_dev* pdev,
|
|
+ const struct pci_device_id* id)
|
|
+ @brief Implements the probe function for the PCI driver.
|
|
+ @remarks This function acts as the probe function for
|
|
+ the PCI driver. The PCI core will be invoking
|
|
+ this function once it determines that this
|
|
+ driver is suitable for handling a particular
|
|
+ hardware. The main tasks performed by this
|
|
+ function are:
|
|
+ - Confirms whether the detected device is
|
|
+ supported by the driver.
|
|
+ - Enables the PCi device.
|
|
+ - Attains the device specific resources and
|
|
+ store it for further use.
|
|
+ - Enables the device and registers the handler
|
|
+ for handling the device interrupts.
|
|
+ - Initializes the device specific data
|
|
+ structures.
|
|
+
|
|
+ @param pdev [@ref INOUT] Reference to the pci_device
|
|
+ structure.
|
|
+ @param id [@ref IN] Reference to the pci_device_id
|
|
+ for which this device matches.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EIO --> pci_enable_device error status code.
|
|
+ - -EBUSY: --> pci_request_regions/request_irq
|
|
+ error status code.
|
|
+ - -EINVAL --> pci_enable_device/request_irq error
|
|
+ status code/invalid device ID.
|
|
+ - -ENOMEM --> request_irq/pci_iomap error status
|
|
+ code.
|
|
+ - -ENOSYS --> request_irq error status code.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_controller_driver
|
|
+ */
|
|
+static int __devinit ioh_dma_probe(struct pci_dev *pdev,
|
|
+ const struct pci_device_id *id)
|
|
+{
|
|
+ static unsigned int ioh_dma_dcount;
|
|
+ int retval;
|
|
+ u32 dev_type;
|
|
+ u32 base_addr = 0;
|
|
+ u8 device_enabled = 0;
|
|
+ u8 regions_requested = 0;
|
|
+ u8 irq_registered = 0;
|
|
+
|
|
+ do {
|
|
+ /* Getting the internally used device ID of the detected
|
|
+ device. */
|
|
+ dev_type = get_dev_type(id->device);
|
|
+ /* If invalid device. */
|
|
+ if ((IOH_INVALID_DEVICE == dev_type)) {
|
|
+ IOH_LOG(KERN_ERR, "ioh_dma_probe -> Invalid device ID "
|
|
+ "%x.\n", id->device);
|
|
+ retval = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+ IOH_DEBUG("ioh_dma_probe -> Valid device ID detected %x.\n",
|
|
+ id->device);
|
|
+
|
|
+ /* Enabling the detected device */
|
|
+ retval = pci_enable_device(pdev);
|
|
+ if (0 != retval) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_probe -> Function pci_enable_device "
|
|
+ "failed, returned %d.\n", retval);
|
|
+ break;
|
|
+ }
|
|
+ device_enabled = 1;
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_probe -> Function pci_enable_device invoked "
|
|
+ "successfully returned %d.\n", retval);
|
|
+
|
|
+ pci_set_master(pdev);
|
|
+ IOH_DEBUG("ioh_dma_probe -> Function pci_set_master invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ /* Requesting the PCI device regions. */
|
|
+ retval = pci_request_regions(pdev, MODULE_NAME);
|
|
+ if (0 != retval) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_probe -> Function pci_request_regions "
|
|
+ "failed, returned %d.\n", retval);
|
|
+ break;
|
|
+ }
|
|
+ regions_requested = 1;
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_probe -> Function pci_request_regions invoked "
|
|
+ "successfully returned %d.\n", retval);
|
|
+
|
|
+ /* Remapping the device space to kernel space. */
|
|
+ /* Wipro 1/13/2010 Use Mem BAR */
|
|
+ base_addr = (u32) pci_iomap(pdev, 1, 0);
|
|
+ if (0 == base_addr) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_probe -> Function pci_iomap failed "
|
|
+ "returned %x.\n", base_addr);
|
|
+ retval = -ENOMEM;
|
|
+ break;
|
|
+ }
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_probe -> Function pci_iomap invoked successfully."
|
|
+ "\n");
|
|
+
|
|
+ /* Filling in the details within the device structure. */
|
|
+ ioh_dma_devices[ioh_dma_dcount].dev_typ = dev_type;
|
|
+ ioh_dma_devices[ioh_dma_dcount].base_addr = base_addr;
|
|
+ ioh_dma_devices[ioh_dma_dcount].dev = (void *)pdev;
|
|
+
|
|
+ /* Registering the interrupt handler. */
|
|
+ retval =
|
|
+ request_irq(pdev->irq, dma_interrupt, IRQF_SHARED,
|
|
+ MODULE_NAME, &ioh_dma_devices[ioh_dma_dcount]);
|
|
+ if (0 != retval) {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_probe -> Function request_irq failed, "
|
|
+ "returned %d.\n", retval);
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ irq_registered = 1;
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_probe -> Function request_irq invoked "
|
|
+ "successfully returned %d.\n", retval);
|
|
+
|
|
+ /* Initializing the DMA device. */
|
|
+ dma_init(base_addr, dev_type);
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_probe -> Function dma_init invoked successfully."
|
|
+ "\n");
|
|
+
|
|
+ /* Stroing the device structure reference for further use. */
|
|
+ pci_set_drvdata(pdev, &ioh_dma_devices[ioh_dma_dcount]);
|
|
+
|
|
+ /* Initializing the suspend flag and lock variable. */
|
|
+ if (0 == ioh_dma_dcount) { /* Initialize only once. */
|
|
+ ioh_device_suspended = 0;
|
|
+ spin_lock_init(&ioh_device_lock);
|
|
+ }
|
|
+
|
|
+ /* Incrementing the device structure index. */
|
|
+ ioh_dma_dcount++;
|
|
+
|
|
+ /* Probe successful. */
|
|
+ retval = IOH_DMA_SUCCESS;
|
|
+ IOH_DEBUG("ioh_dma_probe -> Probe successful.\n");
|
|
+
|
|
+ } while (0);
|
|
+
|
|
+ if (IOH_DMA_SUCCESS != retval) {
|
|
+ /* Un-registering the interrupt handler. */
|
|
+ if (1 == irq_registered) {
|
|
+ free_irq(pdev->irq, &ioh_dma_devices[ioh_dma_dcount]);
|
|
+ IOH_DEBUG("ioh_dma_probe -> Function free_irq invoked "
|
|
+ "successfully.\n");
|
|
+ }
|
|
+ /* Unmapping the remapped region. */
|
|
+ if (0 != base_addr) {
|
|
+ pci_iounmap(pdev, (void *)base_addr);
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_probe -> Function pci_iounmap invoked "
|
|
+ "successfully.\n");
|
|
+ }
|
|
+ /* Releasing the requested regions. */
|
|
+ if (1 == regions_requested) {
|
|
+ pci_release_regions(pdev);
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_probe -> Function pci_release_regions "
|
|
+ "invoked successfully.\n");
|
|
+ }
|
|
+ /* Disabling the device. */
|
|
+ if (1 == device_enabled) {
|
|
+ pci_disable_device(pdev);
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_probe -> Function pci_disable_device "
|
|
+ "invoked successfully.\n");
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("ioh_dma_probe -> Probe failed.\n");
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_dma_probe returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+/*! @ingroup PCILayerAPI
|
|
+ @fn static void __devexit ioh_dma_remove(struct pci_dev* pdev)
|
|
+ @brief Implements the remove function for the PCi driver.
|
|
+ @remarks This function is invoked by the PCI subsystem of the
|
|
+ Kernel when the DMA device is removed or the
|
|
+ module is unloaded.
|
|
+ It de-initializes and releases all the resources
|
|
+ attained during device detection. The main tasks
|
|
+ performed by this function are:
|
|
+ - De-initializes the DMA device.
|
|
+ - De-initializes the device specific data
|
|
+ structures.
|
|
+ - Releases all the resources attained during the
|
|
+ device detection phase.
|
|
+
|
|
+ @param pdev [@ref INOUT] Reference to the pci_device structure.
|
|
+
|
|
+ @return None.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_controller_driver
|
|
+ */
|
|
+static void __devexit ioh_dma_remove(struct pci_dev *pdev)
|
|
+{
|
|
+ struct ioh_dma_devices *dev;
|
|
+
|
|
+ /* Getting the driver data. */
|
|
+ dev = pci_get_drvdata(pdev);
|
|
+ /* Re-setting the driver data. */
|
|
+ pci_set_drvdata(pdev, NULL);
|
|
+
|
|
+ /* De-initializing the device. */
|
|
+ dma_exit(dev->dev_typ);
|
|
+ IOH_DEBUG("ioh_dma_remove -> Function dma_exit invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ /* Un-registering the interrupt handler. */
|
|
+ free_irq(pdev->irq, dev);
|
|
+ IOH_DEBUG("ioh_dma_remove -> Function free_irq invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ /* Un-mapping the remapped memory address. */
|
|
+ pci_iounmap(pdev, (void *)dev->base_addr);
|
|
+ dev->base_addr = 0;
|
|
+ IOH_DEBUG("ioh_dma_remove -> Function pci_iounmap invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ /* Releasing the requested regions. */
|
|
+ pci_release_regions(pdev);
|
|
+ IOH_DEBUG("ioh_dma_remove -> Function pci_release_regions "
|
|
+ "invoked successfully.\n");
|
|
+
|
|
+ /* Disabling the device. */
|
|
+ pci_disable_device(pdev);
|
|
+ IOH_DEBUG("ioh_dma_remove -> Function pci_disable_device "
|
|
+ "invoked successfully.\n");
|
|
+
|
|
+ IOH_DEBUG("Function ioh_dma_remove invoked "
|
|
+ "successfully for device %x.\n", pdev->device);
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_PM
|
|
+/*! @ingroup PCILayerAPI
|
|
+ @fn static int ioh_dma_suspend(struct pci_dev* pdev,
|
|
+ pm_message_t state)
|
|
+ @brief Implements the suspend function for the pci_driver.
|
|
+ @remarks This function is used as the suspend function of the PCI
|
|
+ Driver.
|
|
+ The PCI core will be invoking this function once
|
|
+ it receives a suspend event from the PM layer.
|
|
+ The main tasks performed by this functions are:
|
|
+ - Prepares the device so that it can enter the
|
|
+ suspend state by saving the current state.
|
|
+ - Disables all the DMA channels and the
|
|
+ associated interrupts.
|
|
+ - Changes the power state of the device to low
|
|
+ power state.
|
|
+
|
|
+ @param pdev [@ref INOUT] Reference to the pci_device structure.
|
|
+ @param state [@ref IN] The state of the device.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -ENOMEM --> pci_save_state error status code.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_controller_driver
|
|
+ */
|
|
+static int ioh_dma_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
+{
|
|
+ int retval;
|
|
+ struct ioh_dma_devices *dev;
|
|
+
|
|
+ /* Setting flag for denoting Suspension. */
|
|
+ ioh_device_suspended = 1;
|
|
+
|
|
+ /* Getting the driver data. */
|
|
+ dev = pci_get_drvdata(pdev);
|
|
+
|
|
+ /* Saving the current state of the device. */
|
|
+ retval = pci_save_state(pdev);
|
|
+ if (retval == 0) {
|
|
+ IOH_DEBUG("ioh_dma_suspend -> Function pci_save_state invoked "
|
|
+ "successfully (returned %d).\n", retval);
|
|
+
|
|
+ /* De-initializing the device for suspension. */
|
|
+ dma_exit(dev->dev_typ);
|
|
+ IOH_DEBUG("ioh_dma_suspend -> Function dma_exit invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ /* Disabling the wake-up feature. */
|
|
+ pci_enable_wake(pdev, PCI_D3hot, 0);
|
|
+ IOH_DEBUG("ioh_dma_suspend -> Function pci_enable_wake "
|
|
+ "invoked successfully.\n");
|
|
+
|
|
+ /* Setting the device to new state. */
|
|
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
|
+ IOH_DEBUG("ioh_dma_suspend -> Function pci_set_power_state "
|
|
+ "invoked successfully.\n");
|
|
+
|
|
+ /* Disabling the device. */
|
|
+ pci_disable_device(pdev);
|
|
+ IOH_DEBUG("ioh_dma_suspend -> Function pci_disable_device "
|
|
+ "invoked successfully.\n");
|
|
+
|
|
+ retval = IOH_DMA_SUCCESS;
|
|
+ IOH_DEBUG("ioh_dma_suspend -> Suspension successful for "
|
|
+ "the device %x.\n", pdev->device);
|
|
+ } else {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_suspend -> Function pci_save_state failed"
|
|
+ "returned %d.\n", retval);
|
|
+
|
|
+ /* De-setting the flag on Suspend failure. */
|
|
+ ioh_device_suspended = 0;
|
|
+
|
|
+ IOH_DEBUG("ioh_dma_suspend -> Suspension un-successful for "
|
|
+ "the device %x.\n", pdev->device);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_dma_suspend returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+/*! @ingroup PCILayerAPI
|
|
+ @fn static int ioh_dma_resume(struct pci_dev* pdev)
|
|
+ @brief Implements the resume function for the pci_driver.
|
|
+ @remarks This function is used as the resume function of the
|
|
+ PCI driver. The PCI core will be invoking this
|
|
+ function once it receives a resume event from
|
|
+ the PM layer. The main tasks performed by this
|
|
+ function are:
|
|
+ - Restores the power state of the device to
|
|
+ normal state.
|
|
+ - Enables the device so that it returns to its
|
|
+ normal state.
|
|
+
|
|
+ @param pdev [@ref INOUT] Pointer to the pci_device
|
|
+ structure.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EIO --> pci_enable_device error status code.
|
|
+ - -EINVAL --> pci_enable_device .
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_controller_driver
|
|
+
|
|
+ */
|
|
+static int ioh_dma_resume(struct pci_dev *pdev)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* Setting the device to normal power state. */
|
|
+ (void)pci_set_power_state(pdev, PCI_D0);
|
|
+ IOH_DEBUG("ioh_dma_resume -> Function pci_set_power_state invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ /* Restoring the device state. */
|
|
+ (void)pci_restore_state(pdev);
|
|
+ IOH_DEBUG("ioh_dma_resume -> Function pci_restore_state invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ /* Enabling the device. */
|
|
+ retval = pci_enable_device(pdev);
|
|
+
|
|
+ if (0 == retval) {
|
|
+ IOH_DEBUG("ioh_dma_resume -> Function pci_enable_device "
|
|
+ "invoked successfully returned %d.\n", retval);
|
|
+
|
|
+ pci_set_master(pdev);
|
|
+ IOH_DEBUG("ioh_dma_resume -> Function pci_set_master invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ (void)pci_enable_wake(pdev, PCI_D3hot, 0);
|
|
+ IOH_DEBUG("ioh_dma_resume -> Function pci_enable_wake invoked "
|
|
+ "successfully.\n");
|
|
+
|
|
+ retval = IOH_DMA_SUCCESS;
|
|
+
|
|
+ /* De-setting the suspend flag to denote resumption
|
|
+ successful. */
|
|
+ ioh_device_suspended = 0;
|
|
+
|
|
+ IOH_DEBUG("ioh_dma_resume -> Resume successful for the "
|
|
+ "device %x.\n", pdev->device);
|
|
+ } else {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_resume -> Function pci_enable_device failed "
|
|
+ "returned %d.\n", retval);
|
|
+
|
|
+ IOH_DEBUG("ioh_dma_resume -> Resume failed for the device "
|
|
+ "%x.\n", pdev->device);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_dma_resume returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/*! @ingroup PCILayerFacilitators
|
|
+ @struct ioh_dma_controller_driver
|
|
+ @brief Used for registering the PCI driver functionalities.
|
|
+ @remarks This is an instance of the structure pci_driver which
|
|
+ stores references to the PCI Driver
|
|
+ functionalities.
|
|
+ It is used during PCI driver registration for
|
|
+ interfacing the DMA module functionalities with
|
|
+ that of the Kernel subsystem.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_pci_init
|
|
+ - ioh_dma_pci_exit
|
|
+*/
|
|
+
|
|
+static struct pci_driver ioh_dma_controller_driver = {
|
|
+ .name = "ioh_dma", /**< Name of the module. */
|
|
+ .id_table = ioh_dma_pcidev_id, /**< The list of supported devices. */
|
|
+ .probe = ioh_dma_probe, /**< The probe function. */
|
|
+ .remove = __devexit_p(ioh_dma_remove), /**< The remove function. */
|
|
+#ifdef CONFIG_PM
|
|
+ .suspend = ioh_dma_suspend, /**< The suspend function. */
|
|
+ .resume = ioh_dma_resume /**< The resume function. */
|
|
+#endif
|
|
+};
|
|
+
|
|
+/*! @ingroup PCILayerAPI
|
|
+ @fn static __init int ioh_dma_pci_init(void)
|
|
+ @brief Module initialization routine.
|
|
+ @remarks This function is invoked when the module is
|
|
+ loaded. The main tasks performed by this
|
|
+ function are:
|
|
+ - Initializes the module.
|
|
+ - Initializes the local structures
|
|
+ and registers the module as PCI Driver
|
|
+ with the kernel subsystem.
|
|
+
|
|
+ @return int
|
|
+ - @ref IOH_DMA_SUCCESS --> On success.
|
|
+ - -EEXIST --> pci_register_driver error status
|
|
+ code.
|
|
+ - -EINVAL --> pci_register_driver error status
|
|
+ code.
|
|
+ - -ENOMEM --> pci_register_driver error status
|
|
+ code.
|
|
+
|
|
+ */
|
|
+static __init int ioh_dma_pci_init(void)
|
|
+{
|
|
+ int retval;
|
|
+
|
|
+ /* Registering the module as PCI Driver. */
|
|
+ retval = pci_register_driver(&ioh_dma_controller_driver);
|
|
+
|
|
+ if (0 == retval) {
|
|
+ IOH_DEBUG
|
|
+ ("ioh_dma_pci_init -> Function pci_register_driver invoked "
|
|
+ "successfully returned %d.\n", retval);
|
|
+
|
|
+ retval = IOH_DMA_SUCCESS;
|
|
+ } else {
|
|
+ IOH_LOG(KERN_ERR,
|
|
+ "ioh_dma_pci_init -> Function pci_register_driver "
|
|
+ "failed returned %d.\n", retval);
|
|
+ }
|
|
+
|
|
+ IOH_DEBUG("Function ioh_dma_pci_init returns %d.\n", retval);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+/*! @ingroup PCILayerAPI
|
|
+ @fn static __exit void ioh_dma_pci_exit(void)
|
|
+ @brief Module exit handler.
|
|
+ @remarks Kernel subsystem will be invoking this routine
|
|
+ once the module gets unloaded. The main tasks
|
|
+ performed by this function are:
|
|
+ - Un-registers the PCI driver.
|
|
+ - Unloads the module.
|
|
+
|
|
+ @return None.
|
|
+ */
|
|
+static __exit void ioh_dma_pci_exit(void)
|
|
+{
|
|
+ /* Un-registering the module as PCI Driver. */
|
|
+ pci_unregister_driver(&ioh_dma_controller_driver);
|
|
+ IOH_DEBUG("ioh_dma_pci_exit -> Function pci_unregister_driver "
|
|
+ "invoked successfully.\n");
|
|
+
|
|
+ IOH_DEBUG("Function ioh_dma_pci_exit invoked successfully.\n");
|
|
+}
|
|
+
|
|
+MODULE_DEVICE_TABLE(pci, ioh_dma_pcidev_id);
|
|
+module_init(ioh_dma_pci_init);
|
|
+module_exit(ioh_dma_pci_exit);
|
|
--- /dev/null
|
|
+++ b/drivers/dma/pch_dma/pch_dma_pci.h
|
|
@@ -0,0 +1,74 @@
|
|
+/**
|
|
+ * @file ioh_dma_pci.h
|
|
+ *
|
|
+ * @brief
|
|
+ * This file declares the constants & functions used by the
|
|
+ * IOH_DMA_CONTROLLER driver.
|
|
+ *
|
|
+ * @version 0.90
|
|
+ * @section
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
+ *
|
|
+ * <hr>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * History:
|
|
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * created:
|
|
+ * WIPRO 03/07/2009
|
|
+ * modified:
|
|
+ * WIPRO 08/14/2009
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __IOH_DMA_PCI_H__
|
|
+#define __IOH_DMA_PCI_H__
|
|
+
|
|
+/*! @ingroup PCILayer
|
|
+ @def PCI_DEVICE_ID_INTEL_IOH1_DMA4_0
|
|
+ @brief The Device ID of one of the DMA device
|
|
+ with 4 channels used for the GE devices.
|
|
+ @note This is used for registering the DMA module
|
|
+ with the PCI subsystem of the Kernel, so that
|
|
+ the module is loaded when the required device
|
|
+ is detected.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_pcidev_id
|
|
+ - get_dev_type
|
|
+*/
|
|
+#define PCI_DEVICE_ID_INTEL_IOH1_DMA4_0 (0x8815UL)
|
|
+
|
|
+/*! @ingroup PCILayer
|
|
+ @def PCI_DEVICE_ID_DMA8_0_CONTROLLER
|
|
+ @brief The Device ID of one of the DMA device
|
|
+ with 8 channels used for the GE devcies.
|
|
+ @note This is used for registering the DMA module
|
|
+ with the PCI subsystem of the Kernel, so that
|
|
+ the module is loaded when the required device
|
|
+ is detected.
|
|
+
|
|
+ @see
|
|
+ - ioh_dma_pcidev_id
|
|
+ - get_dev_type
|
|
+*/
|
|
+#define PCI_DEVICE_ID_INTEL_IOH1_DMA8_0 (0x8810UL)
|
|
+
|
|
+extern unsigned char ioh_device_suspended; /* The device suspend flag. */
|
|
+extern spinlock_t ioh_device_lock; /* The device lock variable. */
|
|
+
|
|
+#endif
|