diff options
Diffstat (limited to 'arch/frv/kernel/dma.c')
-rw-r--r-- | arch/frv/kernel/dma.c | 463 |
1 files changed, 0 insertions, 463 deletions
diff --git a/arch/frv/kernel/dma.c b/arch/frv/kernel/dma.c deleted file mode 100644 index 370dc9fa0b11..000000000000 --- a/arch/frv/kernel/dma.c +++ /dev/null @@ -1,463 +0,0 @@ -/* dma.c: DMA controller management on FR401 and the like - * - * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.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. - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <asm/dma.h> -#include <asm/gpio-regs.h> -#include <asm/irc-regs.h> -#include <asm/cpu-irqs.h> - -struct frv_dma_channel { - uint8_t flags; -#define FRV_DMA_FLAGS_RESERVED 0x01 -#define FRV_DMA_FLAGS_INUSE 0x02 -#define FRV_DMA_FLAGS_PAUSED 0x04 - uint8_t cap; /* capabilities available */ - int irq; /* completion IRQ */ - uint32_t dreqbit; - uint32_t dackbit; - uint32_t donebit; - const unsigned long ioaddr; /* DMA controller regs addr */ - const char *devname; - dma_irq_handler_t handler; - void *data; -}; - - -#define __get_DMAC(IO,X) ({ *(volatile unsigned long *)((IO) + DMAC_##X##x); }) - -#define __set_DMAC(IO,X,V) \ -do { \ - *(volatile unsigned long *)((IO) + DMAC_##X##x) = (V); \ - mb(); \ -} while(0) - -#define ___set_DMAC(IO,X,V) \ -do { \ - *(volatile unsigned long *)((IO) + DMAC_##X##x) = (V); \ -} while(0) - - -static struct frv_dma_channel frv_dma_channels[FRV_DMA_NCHANS] = { - [0] = { - .cap = FRV_DMA_CAP_DREQ | FRV_DMA_CAP_DACK | FRV_DMA_CAP_DONE, - .irq = IRQ_CPU_DMA0, - .dreqbit = SIR_DREQ0_INPUT, - .dackbit = SOR_DACK0_OUTPUT, - .donebit = SOR_DONE0_OUTPUT, - .ioaddr = 0xfe000900, - }, - [1] = { - .cap = FRV_DMA_CAP_DREQ | FRV_DMA_CAP_DACK | FRV_DMA_CAP_DONE, - .irq = IRQ_CPU_DMA1, - .dreqbit = SIR_DREQ1_INPUT, - .dackbit = SOR_DACK1_OUTPUT, - .donebit = SOR_DONE1_OUTPUT, - .ioaddr = 0xfe000980, - }, - [2] = { - .cap = FRV_DMA_CAP_DREQ | FRV_DMA_CAP_DACK, - .irq = IRQ_CPU_DMA2, - .dreqbit = SIR_DREQ2_INPUT, - .dackbit = SOR_DACK2_OUTPUT, - .ioaddr = 0xfe000a00, - }, - [3] = { - .cap = FRV_DMA_CAP_DREQ | FRV_DMA_CAP_DACK, - .irq = IRQ_CPU_DMA3, - .dreqbit = SIR_DREQ3_INPUT, - .dackbit = SOR_DACK3_OUTPUT, - .ioaddr = 0xfe000a80, - }, - [4] = { - .cap = FRV_DMA_CAP_DREQ, - .irq = IRQ_CPU_DMA4, - .dreqbit = SIR_DREQ4_INPUT, - .ioaddr = 0xfe001000, - }, - [5] = { - .cap = FRV_DMA_CAP_DREQ, - .irq = IRQ_CPU_DMA5, - .dreqbit = SIR_DREQ5_INPUT, - .ioaddr = 0xfe001080, - }, - [6] = { - .cap = FRV_DMA_CAP_DREQ, - .irq = IRQ_CPU_DMA6, - .dreqbit = SIR_DREQ6_INPUT, - .ioaddr = 0xfe001100, - }, - [7] = { - .cap = FRV_DMA_CAP_DREQ, - .irq = IRQ_CPU_DMA7, - .dreqbit = SIR_DREQ7_INPUT, - .ioaddr = 0xfe001180, - }, -}; - -static DEFINE_RWLOCK(frv_dma_channels_lock); - -unsigned int frv_dma_inprogress; - -#define frv_clear_dma_inprogress(channel) \ - (void)__atomic32_fetch_and(~(1 << (channel)), &frv_dma_inprogress); - -#define frv_set_dma_inprogress(channel) \ - (void)__atomic32_fetch_or(1 << (channel), &frv_dma_inprogress); - -/*****************************************************************************/ -/* - * DMA irq handler - determine channel involved, grab status and call real handler - */ -static irqreturn_t dma_irq_handler(int irq, void *_channel) -{ - struct frv_dma_channel *channel = _channel; - - frv_clear_dma_inprogress(channel - frv_dma_channels); - return channel->handler(channel - frv_dma_channels, - __get_DMAC(channel->ioaddr, CSTR), - channel->data); - -} /* end dma_irq_handler() */ - -/*****************************************************************************/ -/* - * Determine which DMA controllers are present on this CPU - */ -void __init frv_dma_init(void) -{ - unsigned long psr = __get_PSR(); - int num_dma, i; - - /* First, determine how many DMA channels are available */ - switch (PSR_IMPLE(psr)) { - case PSR_IMPLE_FR405: - case PSR_IMPLE_FR451: - case PSR_IMPLE_FR501: - case PSR_IMPLE_FR551: - num_dma = FRV_DMA_8CHANS; - break; - - case PSR_IMPLE_FR401: - default: - num_dma = FRV_DMA_4CHANS; - break; - } - - /* Now mark all of the non-existent channels as reserved */ - for(i = num_dma; i < FRV_DMA_NCHANS; i++) - frv_dma_channels[i].flags = FRV_DMA_FLAGS_RESERVED; - -} /* end frv_dma_init() */ - -/*****************************************************************************/ -/* - * allocate a DMA controller channel and the IRQ associated with it - */ -int frv_dma_open(const char *devname, - unsigned long dmamask, - int dmacap, - dma_irq_handler_t handler, - unsigned long irq_flags, - void *data) -{ - struct frv_dma_channel *channel; - int dma, ret; - uint32_t val; - - write_lock(&frv_dma_channels_lock); - - ret = -ENOSPC; - - for (dma = FRV_DMA_NCHANS - 1; dma >= 0; dma--) { - channel = &frv_dma_channels[dma]; - - if (!test_bit(dma, &dmamask)) - continue; - - if ((channel->cap & dmacap) != dmacap) - continue; - - if (!frv_dma_channels[dma].flags) - goto found; - } - - goto out; - - found: - ret = request_irq(channel->irq, dma_irq_handler, irq_flags, devname, channel); - if (ret < 0) - goto out; - - /* okay, we've allocated all the resources */ - channel = &frv_dma_channels[dma]; - - channel->flags |= FRV_DMA_FLAGS_INUSE; - channel->devname = devname; - channel->handler = handler; - channel->data = data; - - /* Now make sure we are set up for DMA and not GPIO */ - /* SIR bit must be set for DMA to work */ - __set_SIR(channel->dreqbit | __get_SIR()); - /* SOR bits depend on what the caller requests */ - val = __get_SOR(); - if(dmacap & FRV_DMA_CAP_DACK) - val |= channel->dackbit; - else - val &= ~channel->dackbit; - if(dmacap & FRV_DMA_CAP_DONE) - val |= channel->donebit; - else - val &= ~channel->donebit; - __set_SOR(val); - - ret = dma; - out: - write_unlock(&frv_dma_channels_lock); - return ret; -} /* end frv_dma_open() */ - -EXPORT_SYMBOL(frv_dma_open); - -/*****************************************************************************/ -/* - * close a DMA channel and its associated interrupt - */ -void frv_dma_close(int dma) -{ - struct frv_dma_channel *channel = &frv_dma_channels[dma]; - unsigned long flags; - - write_lock_irqsave(&frv_dma_channels_lock, flags); - - free_irq(channel->irq, channel); - frv_dma_stop(dma); - - channel->flags &= ~FRV_DMA_FLAGS_INUSE; - - write_unlock_irqrestore(&frv_dma_channels_lock, flags); -} /* end frv_dma_close() */ - -EXPORT_SYMBOL(frv_dma_close); - -/*****************************************************************************/ -/* - * set static configuration on a DMA channel - */ -void frv_dma_config(int dma, unsigned long ccfr, unsigned long cctr, unsigned long apr) -{ - unsigned long ioaddr = frv_dma_channels[dma].ioaddr; - - ___set_DMAC(ioaddr, CCFR, ccfr); - ___set_DMAC(ioaddr, CCTR, cctr); - ___set_DMAC(ioaddr, APR, apr); - mb(); - -} /* end frv_dma_config() */ - -EXPORT_SYMBOL(frv_dma_config); - -/*****************************************************************************/ -/* - * start a DMA channel - */ -void frv_dma_start(int dma, - unsigned long sba, unsigned long dba, - unsigned long pix, unsigned long six, unsigned long bcl) -{ - unsigned long ioaddr = frv_dma_channels[dma].ioaddr; - - ___set_DMAC(ioaddr, SBA, sba); - ___set_DMAC(ioaddr, DBA, dba); - ___set_DMAC(ioaddr, PIX, pix); - ___set_DMAC(ioaddr, SIX, six); - ___set_DMAC(ioaddr, BCL, bcl); - ___set_DMAC(ioaddr, CSTR, 0); - mb(); - - __set_DMAC(ioaddr, CCTR, __get_DMAC(ioaddr, CCTR) | DMAC_CCTRx_ACT); - frv_set_dma_inprogress(dma); - -} /* end frv_dma_start() */ - -EXPORT_SYMBOL(frv_dma_start); - -/*****************************************************************************/ -/* - * restart a DMA channel that's been stopped in circular addressing mode by comparison-end - */ -void frv_dma_restart_circular(int dma, unsigned long six) -{ - unsigned long ioaddr = frv_dma_channels[dma].ioaddr; - - ___set_DMAC(ioaddr, SIX, six); - ___set_DMAC(ioaddr, CSTR, __get_DMAC(ioaddr, CSTR) & ~DMAC_CSTRx_CE); - mb(); - - __set_DMAC(ioaddr, CCTR, __get_DMAC(ioaddr, CCTR) | DMAC_CCTRx_ACT); - frv_set_dma_inprogress(dma); - -} /* end frv_dma_restart_circular() */ - -EXPORT_SYMBOL(frv_dma_restart_circular); - -/*****************************************************************************/ -/* - * stop a DMA channel - */ -void frv_dma_stop(int dma) -{ - unsigned long ioaddr = frv_dma_channels[dma].ioaddr; - uint32_t cctr; - - ___set_DMAC(ioaddr, CSTR, 0); - cctr = __get_DMAC(ioaddr, CCTR); - cctr &= ~(DMAC_CCTRx_IE | DMAC_CCTRx_ACT); - cctr |= DMAC_CCTRx_FC; /* fifo clear */ - __set_DMAC(ioaddr, CCTR, cctr); - __set_DMAC(ioaddr, BCL, 0); - frv_clear_dma_inprogress(dma); -} /* end frv_dma_stop() */ - -EXPORT_SYMBOL(frv_dma_stop); - -/*****************************************************************************/ -/* - * test interrupt status of DMA channel - */ -int is_frv_dma_interrupting(int dma) -{ - unsigned long ioaddr = frv_dma_channels[dma].ioaddr; - - return __get_DMAC(ioaddr, CSTR) & (1 << 23); - -} /* end is_frv_dma_interrupting() */ - -EXPORT_SYMBOL(is_frv_dma_interrupting); - -/*****************************************************************************/ -/* - * dump data about a DMA channel - */ -void frv_dma_dump(int dma) -{ - unsigned long ioaddr = frv_dma_channels[dma].ioaddr; - unsigned long cstr, pix, six, bcl; - - cstr = __get_DMAC(ioaddr, CSTR); - pix = __get_DMAC(ioaddr, PIX); - six = __get_DMAC(ioaddr, SIX); - bcl = __get_DMAC(ioaddr, BCL); - - printk("DMA[%d] cstr=%lx pix=%lx six=%lx bcl=%lx\n", dma, cstr, pix, six, bcl); - -} /* end frv_dma_dump() */ - -EXPORT_SYMBOL(frv_dma_dump); - -/*****************************************************************************/ -/* - * pause all DMA controllers - * - called by clock mangling routines - * - caller must be holding interrupts disabled - */ -void frv_dma_pause_all(void) -{ - struct frv_dma_channel *channel; - unsigned long ioaddr; - unsigned long cstr, cctr; - int dma; - - write_lock(&frv_dma_channels_lock); - - for (dma = FRV_DMA_NCHANS - 1; dma >= 0; dma--) { - channel = &frv_dma_channels[dma]; - - if (!(channel->flags & FRV_DMA_FLAGS_INUSE)) - continue; - - ioaddr = channel->ioaddr; - cctr = __get_DMAC(ioaddr, CCTR); - if (cctr & DMAC_CCTRx_ACT) { - cctr &= ~DMAC_CCTRx_ACT; - __set_DMAC(ioaddr, CCTR, cctr); - - do { - cstr = __get_DMAC(ioaddr, CSTR); - } while (cstr & DMAC_CSTRx_BUSY); - - if (cstr & DMAC_CSTRx_FED) - channel->flags |= FRV_DMA_FLAGS_PAUSED; - frv_clear_dma_inprogress(dma); - } - } - -} /* end frv_dma_pause_all() */ - -EXPORT_SYMBOL(frv_dma_pause_all); - -/*****************************************************************************/ -/* - * resume paused DMA controllers - * - called by clock mangling routines - * - caller must be holding interrupts disabled - */ -void frv_dma_resume_all(void) -{ - struct frv_dma_channel *channel; - unsigned long ioaddr; - unsigned long cstr, cctr; - int dma; - - for (dma = FRV_DMA_NCHANS - 1; dma >= 0; dma--) { - channel = &frv_dma_channels[dma]; - - if (!(channel->flags & FRV_DMA_FLAGS_PAUSED)) - continue; - - ioaddr = channel->ioaddr; - cstr = __get_DMAC(ioaddr, CSTR); - cstr &= ~(DMAC_CSTRx_FED | DMAC_CSTRx_INT); - __set_DMAC(ioaddr, CSTR, cstr); - - cctr = __get_DMAC(ioaddr, CCTR); - cctr |= DMAC_CCTRx_ACT; - __set_DMAC(ioaddr, CCTR, cctr); - - channel->flags &= ~FRV_DMA_FLAGS_PAUSED; - frv_set_dma_inprogress(dma); - } - - write_unlock(&frv_dma_channels_lock); - -} /* end frv_dma_resume_all() */ - -EXPORT_SYMBOL(frv_dma_resume_all); - -/*****************************************************************************/ -/* - * dma status clear - */ -void frv_dma_status_clear(int dma) -{ - unsigned long ioaddr = frv_dma_channels[dma].ioaddr; - uint32_t cctr; - ___set_DMAC(ioaddr, CSTR, 0); - - cctr = __get_DMAC(ioaddr, CCTR); -} /* end frv_dma_status_clear() */ - -EXPORT_SYMBOL(frv_dma_status_clear); |