ppc405_dma.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 512 行 · 第 1/2 页

C
512
字号
/* * linux/arch/ppc/kernel/ppc405_dma.c * * BRIEF MODULE DESCRIPTION *	IBM 405 DMA Controller Functions * * Copyright 2000 MontaVista Software Inc. * Author: MontaVista Software, Inc. *         	ppopov@mvista.com or source@mvista.com * * *  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;  either version 2 of the  License, or (at your *  option) any later version. * *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *  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., *  675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/config.h>#include <linux/kernel.h>#include <asm/system.h>#include <asm/io.h>#include <linux/mm.h>#include <linux/miscdevice.h>#include <linux/init.h>#include <linux/module.h>#include <asm/ppc405_dma.h>/* * Function prototypes */int hw_init_dma_channel(unsigned int,  ppc_dma_ch_t *);int init_dma_channel(unsigned int);int get_channel_config(unsigned int, ppc_dma_ch_t *);int set_channel_priority(unsigned int, unsigned int);unsigned int get_peripheral_width(unsigned int);int alloc_dma_handle(sgl_handle_t *, unsigned int, unsigned int);void free_dma_handle(sgl_handle_t);ppc_dma_ch_t dma_channels[MAX_405GP_DMA_CHANNELS];/* * Configures a DMA channel, including the peripheral bus width, if a * peripheral is attached to the channel, the polarity of the DMAReq and * DMAAck signals, etc.  This information should really be setup by the boot  * code, since most likely the configuration won't change dynamically. * If the kernel has to call this function, it's recommended that it's * called from platform specific init code.  The driver should not need to  * call this function. */int hw_init_dma_channel(unsigned int dmanr,  ppc_dma_ch_t *p_init){    unsigned int polarity;    uint32_t control = 0;    ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];#ifdef DEBUG_405DMA    if (!p_init) {        printk("hw_init_dma_channel: NULL p_init\n");        return DMA_STATUS_NULL_POINTER;    }    if (dmanr >= MAX_405GP_DMA_CHANNELS) {        printk("hw_init_dma_channel: bad channel %d\n", dmanr);        return DMA_STATUS_BAD_CHANNEL;    }#endif#if DCRN_POL > 0    polarity = mfdcr(DCRN_POL);#else    polarity = 0;#endif    /* Setup the control register based on the values passed to     * us in p_init.  Then, over-write the control register with this     * new value.     */    control |= (                 SET_DMA_CIE_ENABLE(p_init->int_enable) | /* interrupt enable         */                SET_DMA_BEN(p_init->buffer_enable)     | /* buffer enable            */                 SET_DMA_ETD(p_init->etd_output)        | /* end of transfer pin      */                SET_DMA_TCE(p_init->tce_enable)        | /* terminal count enable    */                SET_DMA_PL(p_init->pl)                 | /* peripheral location      */                SET_DMA_DAI(p_init->dai)               | /* dest addr increment      */                SET_DMA_SAI(p_init->sai)               | /* src addr increment       */                SET_DMA_PRIORITY(p_init->cp)           |  /* channel priority        */                SET_DMA_PW(p_init->pwidth)             |  /* peripheral/bus width    */                SET_DMA_PSC(p_init->psc)               |  /* peripheral setup cycles */                SET_DMA_PWC(p_init->pwc)               |  /* peripheral wait cycles  */                SET_DMA_PHC(p_init->phc)               |  /* peripheral hold cycles  */                SET_DMA_PREFETCH(p_init->pf)              /* read prefetch           */                );    switch (dmanr) {        case 0:            /* clear all polarity signals and then "or" in new signal levels */            polarity &= ~(DMAReq0_ActiveLow | DMAAck0_ActiveLow | EOT0_ActiveLow);            polarity |= p_dma_ch->polarity;#if DCRN_POL > 0            mtdcr(DCRN_POL, polarity);#endif            mtdcr(DCRN_DMACR0, control);            break;        case 1:            polarity &= ~(DMAReq1_ActiveLow | DMAAck1_ActiveLow | EOT1_ActiveLow);            polarity |= p_dma_ch->polarity;#if DCRN_POL > 0            mtdcr(DCRN_POL, polarity);#endif            mtdcr(DCRN_DMACR1, control);            break;        case 2:            polarity &= ~(DMAReq2_ActiveLow | DMAAck2_ActiveLow | EOT2_ActiveLow);            polarity |= p_dma_ch->polarity;#if DCRN_POL > 0            mtdcr(DCRN_POL, polarity);#endif            mtdcr(DCRN_DMACR2, control);            break;        case 3:            polarity &= ~(DMAReq3_ActiveLow | DMAAck3_ActiveLow | EOT3_ActiveLow);            polarity |= p_dma_ch->polarity;#if DCRN_POL > 0            mtdcr(DCRN_POL, polarity);#endif            mtdcr(DCRN_DMACR3, control);            break;        default:            return DMA_STATUS_BAD_CHANNEL;    }        /* save these values in our dma channel structure */    memcpy(p_dma_ch, p_init, sizeof(ppc_dma_ch_t));    /*     * The peripheral width values written in the control register are:     *   PW_8                 0     *   PW_16                1     *   PW_32                2     *   PW_64                3     *     *   Since the DMA count register takes the number of "transfers",     *   we need to divide the count sent to us in certain     *   functions by the appropriate number.  It so happens that our     *   right shift value is equal to the peripheral width value.     */    p_dma_ch->shift = p_init->pwidth;    /*     * Save the control word for easy access.     */    p_dma_ch->control = control;    mtdcr(DCRN_DMASR, 0xffffffff); /* clear status register */    return DMA_STATUS_GOOD;}/* * This function returns the channel configuration. */int get_channel_config(unsigned int dmanr, ppc_dma_ch_t *p_dma_ch){    unsigned int polarity;    unsigned int control;#if DCRN_POL > 0    polarity = mfdcr(DCRN_POL);#else    polarity = 0;#endif    switch (dmanr) {        case 0:            p_dma_ch->polarity =                 polarity & (DMAReq0_ActiveLow | DMAAck0_ActiveLow | EOT0_ActiveLow);            control = mfdcr(DCRN_DMACR0);            break;        case 1:            p_dma_ch->polarity =                 polarity & (DMAReq1_ActiveLow | DMAAck1_ActiveLow | EOT1_ActiveLow);            control = mfdcr(DCRN_DMACR1);            break;        case 2:            p_dma_ch->polarity =                 polarity & (DMAReq2_ActiveLow | DMAAck2_ActiveLow | EOT2_ActiveLow);            control = mfdcr(DCRN_DMACR2);            break;        case 3:            p_dma_ch->polarity =                 polarity & (DMAReq3_ActiveLow | DMAAck3_ActiveLow | EOT3_ActiveLow);            control = mfdcr(DCRN_DMACR3);            break;        default:            return DMA_STATUS_BAD_CHANNEL;    }    p_dma_ch->cp = GET_DMA_PRIORITY(control);    p_dma_ch->pwidth = GET_DMA_PW(control);    p_dma_ch->psc = GET_DMA_PSC(control);    p_dma_ch->pwc = GET_DMA_PWC(control);    p_dma_ch->phc = GET_DMA_PHC(control);    p_dma_ch->pf = GET_DMA_PREFETCH(control);    p_dma_ch->int_enable = GET_DMA_CIE_ENABLE(control);    p_dma_ch->shift = GET_DMA_PW(control);    return DMA_STATUS_GOOD;}/* * Sets the priority for the DMA channel dmanr. * Since this is setup by the hardware init function, this function  * can be used to dynamically change the priority of a channel. * * Acceptable priorities: * * PRIORITY_LOW * PRIORITY_MID_LOW * PRIORITY_MID_HIGH * PRIORITY_HIGH * */int set_channel_priority(unsigned int dmanr, unsigned int priority){    unsigned int control;#ifdef DEBUG_405DMA    if ( (priority != PRIORITY_LOW) &&            (priority != PRIORITY_MID_LOW) &&            (priority != PRIORITY_MID_HIGH) &&            (priority != PRIORITY_HIGH)) {        printk("set_channel_priority: bad priority: 0x%x\n", priority);    }#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?