--- 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. + * + *
+ */ + +/* + * History: + * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD. + * All rights reserved. + * + * created: + * WIPRO 03/07/2009 + * modified: + * WIPRO 08/14/2009 + * + */ + +#include +#include +#include +#include + +#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. + * + *
+ */ + +/* + * 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 +#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. + * + *
+ */ + +/* + * History: + * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD. + * All rights reserved. + * + * created: + * WIPRO 03/07/2009 + * modified: + * WIPRO 08/14/2009 + * + */ + +#include +#include +#include + +#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. + * + *
+ */ + +/* + * 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. + * + *
+ */ + +/* + * 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 +#include +#include +#include + +/* 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. + * + *
+ */ + +/* + * 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