-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/ppc4xx_dma.h>
-
-ppc_dma_ch_t dma_channels[MAX_PPC4xx_DMA_CHANNELS];
-
-int
-ppc4xx_get_dma_status(void)
-{
- return (mfdcr(DCRN_DMASR));
-}
-
-void
-ppc4xx_set_src_addr(int dmanr, phys_addr_t src_addr)
-{
- if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
- printk("set_src_addr: bad channel: %d\n", dmanr);
- return;
- }
-
-#ifdef PPC4xx_DMA64BIT
- mtdcr(DCRN_DMASAH0 + dmanr*2, (u32)(src_addr >> 32));
-#else
- mtdcr(DCRN_DMASA0 + dmanr*2, (u32)src_addr);
-#endif
-}
-
-void
-ppc4xx_set_dst_addr(int dmanr, phys_addr_t dst_addr)
-{
- if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
- printk("set_dst_addr: bad channel: %d\n", dmanr);
- return;
- }
-
-#ifdef PPC4xx_DMA64BIT
- mtdcr(DCRN_DMADAH0 + dmanr*2, (u32)(dst_addr >> 32));
-#else
- mtdcr(DCRN_DMADA0 + dmanr*2, (u32)dst_addr);
-#endif
-}
-
-void
-ppc4xx_enable_dma(unsigned int dmanr)
-{
- unsigned int control;
- ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
- unsigned int status_bits[] = { DMA_CS0 | DMA_TS0 | DMA_CH0_ERR,
- DMA_CS1 | DMA_TS1 | DMA_CH1_ERR,
- DMA_CS2 | DMA_TS2 | DMA_CH2_ERR,
- DMA_CS3 | DMA_TS3 | DMA_CH3_ERR};
-
- if (p_dma_ch->in_use) {
- printk("enable_dma: channel %d in use\n", dmanr);
- return;
- }
-
- if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
- printk("enable_dma: bad channel: %d\n", dmanr);
- return;
- }
-
- if (p_dma_ch->mode == DMA_MODE_READ) {
- /* peripheral to memory */
- ppc4xx_set_src_addr(dmanr, 0);
- ppc4xx_set_dst_addr(dmanr, p_dma_ch->addr);
- } else if (p_dma_ch->mode == DMA_MODE_WRITE) {
- /* memory to peripheral */
- ppc4xx_set_src_addr(dmanr, p_dma_ch->addr);
- ppc4xx_set_dst_addr(dmanr, 0);
- }
-
- /* for other xfer modes, the addresses are already set */
- control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
-
- control &= ~(DMA_TM_MASK | DMA_TD); /* clear all mode bits */
- if (p_dma_ch->mode == DMA_MODE_MM) {
- /* software initiated memory to memory */
- control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;
- }
-
- mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
-
- /*
- * Clear the CS, TS, RI bits for the channel from DMASR. This
- * has been observed to happen correctly only after the mode and
- * ETD/DCE bits in DMACRx are set above. Must do this before
- * enabling the channel.
- */
-
- mtdcr(DCRN_DMASR, status_bits[dmanr]);
-
- /*
- * For device-paced transfers, Terminal Count Enable apparently
- * must be on, and this must be turned on after the mode, etc.
- * bits are cleared above (at least on Redwood-6).
- */
-
- if ((p_dma_ch->mode == DMA_MODE_MM_DEVATDST) ||
- (p_dma_ch->mode == DMA_MODE_MM_DEVATSRC))
- control |= DMA_TCE_ENABLE;
-
- /*
- * Now enable the channel.
- */
-
- control |= (p_dma_ch->mode | DMA_CE_ENABLE);
-
- mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
-
- p_dma_ch->in_use = 1;
-}
-
-void
-ppc4xx_disable_dma(unsigned int dmanr)
-{
- unsigned int control;
- ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
-
- if (!p_dma_ch->in_use) {
- printk("disable_dma: channel %d not in use\n", dmanr);
- return;
- }
-
- if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
- printk("disable_dma: bad channel: %d\n", dmanr);
- return;
- }
-
- control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
- control &= ~DMA_CE_ENABLE;
- mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
-
- p_dma_ch->in_use = 0;
-}
-
-/*
- * Sets the dma mode for single DMA transfers only.
- * For scatter/gather transfers, the mode is passed to the
- * alloc_dma_handle() function as one of the parameters.
- *
- * The mode is simply saved and used later. This allows
- * the driver to call set_dma_mode() and set_dma_addr() in
- * any order.
- *
- * Valid mode values are:
- *
- * DMA_MODE_READ peripheral to memory
- * DMA_MODE_WRITE memory to peripheral
- * DMA_MODE_MM memory to memory
- * DMA_MODE_MM_DEVATSRC device-paced memory to memory, device at src
- * DMA_MODE_MM_DEVATDST device-paced memory to memory, device at dst
- */
-int
-ppc4xx_set_dma_mode(unsigned int dmanr, unsigned int mode)
-{
- ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
-
- if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
- printk("set_dma_mode: bad channel 0x%x\n", dmanr);
- return DMA_STATUS_BAD_CHANNEL;
- }
-
- p_dma_ch->mode = mode;
-
- return DMA_STATUS_GOOD;
-}
-
-/*
- * Sets the DMA Count register. Note that 'count' is in bytes.
- * However, the DMA Count register counts the number of "transfers",
- * where each transfer is equal to the bus width. Thus, count
- * MUST be a multiple of the bus width.
- */
-void
-ppc4xx_set_dma_count(unsigned int dmanr, unsigned int count)
-{
- ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
-
-#ifdef DEBUG_4xxDMA
- {
- int error = 0;
- switch (p_dma_ch->pwidth) {
- case PW_8:
- break;
- case PW_16:
- if (count & 0x1)
- error = 1;
- break;
- case PW_32:
- if (count & 0x3)
- error = 1;
- break;
- case PW_64:
- if (count & 0x7)
- error = 1;
- break;
- default:
- printk("set_dma_count: invalid bus width: 0x%x\n",
- p_dma_ch->pwidth);
- return;
- }
- if (error)
- printk
- ("Warning: set_dma_count count 0x%x bus width %d\n",
- count, p_dma_ch->pwidth);
- }
-#endif