Commit dad4cc58 authored by David S. Miller's avatar David S. Miller

[SPARC64]: Rework all EBUS DMA support.

- Add EBUS DMA layer so the same code does not need to
be debugged/duplicated several times.
- Convert Parport/Floppy/CS4231 to use new EBUS DMA layer.
parent 25757a5a
...@@ -8,7 +8,7 @@ EXTRA_AFLAGS := -ansi ...@@ -8,7 +8,7 @@ EXTRA_AFLAGS := -ansi
EXTRA_TARGETS := head.o init_task.o EXTRA_TARGETS := head.o init_task.o
export-objs := sparc64_ksyms.o export-objs := sparc64_ksyms.o ebus.o
obj-y := process.o setup.o cpu.o idprom.o \ obj-y := process.o setup.o cpu.o idprom.o \
traps.o devices.o auxio.o \ traps.o devices.o auxio.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -20,6 +21,220 @@ ...@@ -20,6 +21,220 @@
#include <asm/bpp.h> #include <asm/bpp.h>
#include <asm/irq.h> #include <asm/irq.h>
/* EBUS dma library. */
#define EBDMA_CSR 0x00UL /* Control/Status */
#define EBDMA_ADDR 0x04UL /* DMA Address */
#define EBDMA_COUNT 0x08UL /* DMA Count */
#define EBDMA_CSR_INT_PEND 0x00000001
#define EBDMA_CSR_ERR_PEND 0x00000002
#define EBDMA_CSR_DRAIN 0x00000004
#define EBDMA_CSR_INT_EN 0x00000010
#define EBDMA_CSR_RESET 0x00000080
#define EBDMA_CSR_WRITE 0x00000100
#define EBDMA_CSR_EN_DMA 0x00000200
#define EBDMA_CSR_CYC_PEND 0x00000400
#define EBDMA_CSR_DIAG_RD_DONE 0x00000800
#define EBDMA_CSR_DIAG_WR_DONE 0x00001000
#define EBDMA_CSR_EN_CNT 0x00002000
#define EBDMA_CSR_TC 0x00004000
#define EBDMA_CSR_DIS_CSR_DRN 0x00010000
#define EBDMA_CSR_BURST_SZ_MASK 0x000c0000
#define EBDMA_CSR_BURST_SZ_1 0x00080000
#define EBDMA_CSR_BURST_SZ_4 0x00000000
#define EBDMA_CSR_BURST_SZ_8 0x00040000
#define EBDMA_CSR_BURST_SZ_16 0x000c0000
#define EBDMA_CSR_DIAG_EN 0x00100000
#define EBDMA_CSR_DIS_ERR_PEND 0x00400000
#define EBDMA_CSR_TCI_DIS 0x00800000
#define EBDMA_CSR_EN_NEXT 0x01000000
#define EBDMA_CSR_DMA_ON 0x02000000
#define EBDMA_CSR_A_LOADED 0x04000000
#define EBDMA_CSR_NA_LOADED 0x08000000
#define EBDMA_CSR_DEV_ID_MASK 0xf0000000
#define EBUS_DMA_RESET_TIMEOUT 10000
static void __ebus_dma_reset(struct ebus_dma_info *p)
{
int i;
u32 val = 0;
writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR);
for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) {
val = readl(p->regs + EBDMA_CSR);
if (!(val & (EBDMA_CSR_DRAIN | EBDMA_CSR_CYC_PEND)))
break;
udelay(10);
}
}
static void ebus_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
{
struct ebus_dma_info *p = dev_id;
unsigned long flags;
u32 csr;
spin_lock_irqsave(&p->lock, flags);
csr = readl(p->regs + EBDMA_CSR);
writel(csr, p->regs + EBDMA_CSR);
spin_unlock_irqrestore(&p->lock, flags);
if (csr & EBDMA_CSR_ERR_PEND) {
printk(KERN_CRIT "ebus_dma(%s): DMA error!\n", p->name);
p->callback(p, EBUS_DMA_EVENT_ERROR, p->client_cookie);
} else if (csr & EBDMA_CSR_INT_PEND) {
p->callback(p,
(csr & EBDMA_CSR_TC) ?
EBUS_DMA_EVENT_DMA : EBUS_DMA_EVENT_DEVICE,
p->client_cookie);
}
}
int ebus_dma_register(struct ebus_dma_info *p)
{
if (!p->regs)
return -EINVAL;
if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER))
return -EINVAL;
if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback)
return -EINVAL;
if (!strlen(p->name))
return -EINVAL;
__ebus_dma_reset(p);
return 0;
}
EXPORT_SYMBOL(ebus_dma_register);
int ebus_dma_irq_enable(struct ebus_dma_info *p, int on)
{
unsigned long flags;
u32 csr;
if (on) {
if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
if (request_irq(p->irq, ebus_dma_irq, SA_SHIRQ, p->name, p))
return -EBUSY;
}
spin_lock_irqsave(&p->lock, flags);
csr = readl(p->regs + EBDMA_CSR);
csr |= EBDMA_CSR_INT_EN;
writel(csr, p->regs + EBDMA_CSR);
spin_unlock_irqrestore(&p->lock, flags);
} else {
spin_lock_irqsave(&p->lock, flags);
csr = readl(p->regs + EBDMA_CSR);
csr &= ~EBDMA_CSR_INT_EN;
writel(csr, p->regs + EBDMA_CSR);
spin_unlock_irqrestore(&p->lock, flags);
if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
free_irq(p->irq, p);
}
}
return 0;
}
EXPORT_SYMBOL(ebus_dma_irq_enable);
void ebus_dma_unregister(struct ebus_dma_info *p)
{
unsigned long flags;
u32 csr;
int irq_on = 0;
spin_lock_irqsave(&p->lock, flags);
csr = readl(p->regs + EBDMA_CSR);
if (csr & EBDMA_CSR_INT_EN) {
csr &= ~EBDMA_CSR_INT_EN;
writel(csr, p->regs + EBDMA_CSR);
irq_on = 1;
}
spin_unlock_irqrestore(&p->lock, flags);
if (irq_on)
free_irq(p->irq, p);
}
EXPORT_SYMBOL(ebus_dma_unregister);
int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len)
{
unsigned long flags;
u32 csr;
int err;
if (len >= (1 << 24))
return -EINVAL;
spin_lock_irqsave(&p->lock, flags);
csr = readl(p->regs + EBDMA_CSR);
err = -EINVAL;
if (!(csr & EBDMA_CSR_EN_DMA))
goto out;
err = -EBUSY;
if (csr & EBDMA_CSR_NA_LOADED)
goto out;
writel(len, p->regs + EBDMA_COUNT);
writel(bus_addr, p->regs + EBDMA_ADDR);
err = 0;
out:
spin_unlock_irqrestore(&p->lock, flags);
return err;
}
EXPORT_SYMBOL(ebus_dma_request);
void ebus_dma_prepare(struct ebus_dma_info *p, int write)
{
unsigned long flags;
spin_lock_irqsave(&p->lock, flags);
__ebus_dma_reset(p);
writel(EBDMA_CSR_INT_EN |
((write) ? EBDMA_CSR_WRITE : 0) |
EBDMA_CSR_EN_CNT |
EBDMA_CSR_BURST_SZ_16 |
EBDMA_CSR_EN_NEXT, p->regs + EBDMA_CSR);
spin_unlock_irqrestore(&p->lock, flags);
}
EXPORT_SYMBOL(ebus_dma_prepare);
unsigned int ebus_dma_residue(struct ebus_dma_info *p)
{
return readl(p->regs + EBDMA_COUNT);
}
EXPORT_SYMBOL(ebus_dma_residue);
unsigned int ebus_dma_addr(struct ebus_dma_info *p)
{
return readl(p->regs + EBDMA_ADDR);
}
EXPORT_SYMBOL(ebus_dma_addr);
void ebus_dma_enable(struct ebus_dma_info *p, int on)
{
unsigned long flags;
u32 csr;
spin_lock_irqsave(&p->lock, flags);
csr = readl(p->regs + EBDMA_CSR);
if (on)
csr |= EBDMA_CSR_EN_DMA;
else
csr &= ~EBDMA_CSR_EN_DMA;
writel(csr, p->regs + EBDMA_CSR);
spin_unlock_irqrestore(&p->lock, flags);
}
EXPORT_SYMBOL(ebus_dma_enable);
struct linux_ebus *ebus_chain = 0; struct linux_ebus *ebus_chain = 0;
#ifdef CONFIG_SUN_AUXIO #ifdef CONFIG_SUN_AUXIO
......
...@@ -51,38 +51,34 @@ struct linux_ebus { ...@@ -51,38 +51,34 @@ struct linux_ebus {
struct linux_prom_ebus_intmask ebus_intmask; struct linux_prom_ebus_intmask ebus_intmask;
}; };
struct linux_ebus_dma { struct ebus_dma_info {
unsigned int dcsr; spinlock_t lock;
unsigned int dacr; unsigned long regs;
unsigned int dbcr;
unsigned int flags;
#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER 0x00000001
/* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
* set.
*/
void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
void *client_cookie;
unsigned int irq;
#define EBUS_DMA_EVENT_ERROR 1
#define EBUS_DMA_EVENT_DMA 2
#define EBUS_DMA_EVENT_DEVICE 4
unsigned char name[64];
}; };
#define EBUS_DCSR_INT_PEND 0x00000001 extern int ebus_dma_register(struct ebus_dma_info *p);
#define EBUS_DCSR_ERR_PEND 0x00000002 extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
#define EBUS_DCSR_DRAIN 0x00000004 extern void ebus_dma_unregister(struct ebus_dma_info *p);
#define EBUS_DCSR_INT_EN 0x00000010 extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
#define EBUS_DCSR_RESET 0x00000080 size_t len);
#define EBUS_DCSR_WRITE 0x00000100 extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
#define EBUS_DCSR_EN_DMA 0x00000200 extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
#define EBUS_DCSR_CYC_PEND 0x00000400 extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
#define EBUS_DCSR_DIAG_RD_DONE 0x00000800
#define EBUS_DCSR_DIAG_WR_DONE 0x00001000
#define EBUS_DCSR_EN_CNT 0x00002000
#define EBUS_DCSR_TC 0x00004000
#define EBUS_DCSR_DIS_CSR_DRN 0x00010000
#define EBUS_DCSR_BURST_SZ_MASK 0x000c0000
#define EBUS_DCSR_BURST_SZ_1 0x00080000
#define EBUS_DCSR_BURST_SZ_4 0x00000000
#define EBUS_DCSR_BURST_SZ_8 0x00040000
#define EBUS_DCSR_BURST_SZ_16 0x000c0000
#define EBUS_DCSR_DIAG_EN 0x00100000
#define EBUS_DCSR_DIS_ERR_PEND 0x00400000
#define EBUS_DCSR_TCI_DIS 0x00800000
#define EBUS_DCSR_EN_NEXT 0x01000000
#define EBUS_DCSR_DMA_ON 0x02000000
#define EBUS_DCSR_A_LOADED 0x04000000
#define EBUS_DCSR_NA_LOADED 0x08000000
#define EBUS_DCSR_DEV_ID_MASK 0xf0000000
extern struct linux_ebus *ebus_chain; extern struct linux_ebus *ebus_chain;
......
...@@ -264,7 +264,7 @@ static int sun_fd_eject(int drive) ...@@ -264,7 +264,7 @@ static int sun_fd_eject(int drive)
#include <asm/isa.h> #include <asm/isa.h>
#include <asm/ns87303.h> #include <asm/ns87303.h>
static struct linux_ebus_dma *sun_pci_fd_ebus_dma; static struct ebus_dma_info sun_pci_fd_ebus_dma;
static struct pci_dev *sun_pci_ebus_dev; static struct pci_dev *sun_pci_ebus_dev;
static int sun_pci_broken_drive = -1; static int sun_pci_broken_drive = -1;
...@@ -330,26 +330,12 @@ static void sun_pci_fd_lde_broken_outb(unsigned char val, unsigned long port) ...@@ -330,26 +330,12 @@ static void sun_pci_fd_lde_broken_outb(unsigned char val, unsigned long port)
} }
#endif /* PCI_FDC_SWAP_DRIVES */ #endif /* PCI_FDC_SWAP_DRIVES */
static void sun_pci_fd_reset_dma(void)
{
unsigned int dcsr;
writel(EBUS_DCSR_RESET, &sun_pci_fd_ebus_dma->dcsr);
udelay(1);
dcsr = EBUS_DCSR_BURST_SZ_16 | EBUS_DCSR_TCI_DIS |
EBUS_DCSR_EN_CNT;
writel(dcsr, (unsigned long)&sun_pci_fd_ebus_dma->dcsr);
}
static void sun_pci_fd_enable_dma(void) static void sun_pci_fd_enable_dma(void)
{ {
unsigned int dcsr; if ((NULL == sun_pci_dma_pending.buf) ||
(0 == sun_pci_dma_pending.len) ||
if((NULL == sun_pci_dma_pending.buf) || (0 == sun_pci_dma_pending.direction))
(0 == sun_pci_dma_pending.len) || BUG();
(0 == sun_pci_dma_pending.direction)) {
goto enable; /* TODO: BUG() */
}
sun_pci_dma_current.buf = sun_pci_dma_pending.buf; sun_pci_dma_current.buf = sun_pci_dma_pending.buf;
sun_pci_dma_current.len = sun_pci_dma_pending.len; sun_pci_dma_current.len = sun_pci_dma_pending.len;
...@@ -361,36 +347,22 @@ static void sun_pci_fd_enable_dma(void) ...@@ -361,36 +347,22 @@ static void sun_pci_fd_enable_dma(void)
sun_pci_dma_pending.addr = -1U; sun_pci_dma_pending.addr = -1U;
sun_pci_dma_current.addr = sun_pci_dma_current.addr =
pci_map_single( sun_pci_ebus_dev, pci_map_single(sun_pci_ebus_dev,
sun_pci_dma_current.buf, sun_pci_dma_current.buf,
sun_pci_dma_current.len, sun_pci_dma_current.len,
sun_pci_dma_current.direction); sun_pci_dma_current.direction);
writel(sun_pci_dma_current.addr, &sun_pci_fd_ebus_dma->dacr);
if (ebus_dma_request(&sun_pci_fd_ebus_dma,
sun_pci_dma_current.addr,
sun_pci_dma_current.len))
BUG();
enable: ebus_dma_enable(&sun_pci_fd_ebus_dma, 1);
dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
dcsr |= EBUS_DCSR_EN_DMA;
writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
} }
static void sun_pci_fd_disable_dma(void) static void sun_pci_fd_disable_dma(void)
{ {
unsigned int dcsr; ebus_dma_enable(&sun_pci_fd_ebus_dma, 0);
dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
if (dcsr & EBUS_DCSR_EN_DMA) {
while (dcsr & EBUS_DCSR_DRAIN) {
udelay(1);
dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
}
dcsr &= ~(EBUS_DCSR_EN_DMA);
writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
if (dcsr & EBUS_DCSR_ERR_PEND) {
sun_pci_fd_reset_dma();
dcsr &= ~(EBUS_DCSR_ERR_PEND);
writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
}
}
if (sun_pci_dma_current.addr != -1U) if (sun_pci_dma_current.addr != -1U)
pci_unmap_single(sun_pci_ebus_dev, pci_unmap_single(sun_pci_ebus_dev,
sun_pci_dma_current.addr, sun_pci_dma_current.addr,
...@@ -401,33 +373,12 @@ static void sun_pci_fd_disable_dma(void) ...@@ -401,33 +373,12 @@ static void sun_pci_fd_disable_dma(void)
static void sun_pci_fd_set_dma_mode(int mode) static void sun_pci_fd_set_dma_mode(int mode)
{ {
unsigned int dcsr; ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
if (readl(&sun_pci_fd_ebus_dma->dbcr)) {
sun_pci_fd_reset_dma();
writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
}
dcsr |= EBUS_DCSR_EN_CNT | EBUS_DCSR_TC;
/*
* For EBus WRITE means to system memory, which is
* READ for us.
*/
if (mode == DMA_MODE_WRITE) {
dcsr &= ~(EBUS_DCSR_WRITE);
sun_pci_dma_pending.direction = PCI_DMA_TODEVICE;
} else {
dcsr |= EBUS_DCSR_WRITE;
sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE;
}
writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
} }
static void sun_pci_fd_set_dma_count(int length) static void sun_pci_fd_set_dma_count(int length)
{ {
sun_pci_dma_pending.len = length; sun_pci_dma_pending.len = length;
writel(length, &sun_pci_fd_ebus_dma->dbcr);
} }
static void sun_pci_fd_set_dma_addr(char *buffer) static void sun_pci_fd_set_dma_addr(char *buffer)
...@@ -437,51 +388,28 @@ static void sun_pci_fd_set_dma_addr(char *buffer) ...@@ -437,51 +388,28 @@ static void sun_pci_fd_set_dma_addr(char *buffer)
static unsigned int sun_pci_get_dma_residue(void) static unsigned int sun_pci_get_dma_residue(void)
{ {
unsigned int dcsr, res; return ebus_dma_residue(&sun_pci_fd_ebus_dma);
res = readl(&sun_pci_fd_ebus_dma->dbcr);
if (res != 0) {
dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
sun_pci_fd_reset_dma();
writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
}
return res;
} }
static void sun_pci_fd_enable_irq(void) static void sun_pci_fd_enable_irq(void)
{ {
unsigned int dcsr; ebus_dma_irq_enable(&sun_pci_fd_ebus_dma, 1);
dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
dcsr |= EBUS_DCSR_INT_EN;
writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
} }
static void sun_pci_fd_disable_irq(void) static void sun_pci_fd_disable_irq(void)
{ {
unsigned int dcsr; ebus_dma_irq_enable(&sun_pci_fd_ebus_dma, 0);
dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
dcsr &= ~(EBUS_DCSR_INT_EN);
writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
} }
static int sun_pci_fd_request_irq(void) static int sun_pci_fd_request_irq(void)
{ {
int err; /* Done by enable/disable irq */
err = request_irq(FLOPPY_IRQ, floppy_interrupt, SA_SHIRQ,
"floppy", sun_fdc);
if (err)
return -1;
sun_pci_fd_enable_irq();
return 0; return 0;
} }
static void sun_pci_fd_free_irq(void) static void sun_pci_fd_free_irq(void)
{ {
sun_pci_fd_disable_irq(); /* Done by enable/disable irq */
free_irq(FLOPPY_IRQ, sun_fdc);
} }
static int sun_pci_fd_eject(int drive) static int sun_pci_fd_eject(int drive)
...@@ -489,6 +417,10 @@ static int sun_pci_fd_eject(int drive) ...@@ -489,6 +417,10 @@ static int sun_pci_fd_eject(int drive)
return -EINVAL; return -EINVAL;
} }
void sun_pci_fd_dma_callback(struct ebus_dma_info *p, int event, void *cookie)
{
floppy_interrupt(0, NULL, NULL);
}
/* /*
* Floppy probing, we'd like to use /dev/fd0 for a single Floppy on PCI, * Floppy probing, we'd like to use /dev/fd0 for a single Floppy on PCI,
...@@ -724,6 +656,7 @@ static unsigned long __init sun_floppy_init(void) ...@@ -724,6 +656,7 @@ static unsigned long __init sun_floppy_init(void)
if(!strncmp(state, "disabled", 8)) if(!strncmp(state, "disabled", 8))
return 0; return 0;
/* XXX ioremap */
sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start; sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start;
FLOPPY_IRQ = edev->irqs[0]; FLOPPY_IRQ = edev->irqs[0];
...@@ -735,9 +668,18 @@ static unsigned long __init sun_floppy_init(void) ...@@ -735,9 +668,18 @@ static unsigned long __init sun_floppy_init(void)
sun_pci_ebus_dev = ebus->self; sun_pci_ebus_dev = ebus->self;
sun_pci_fd_ebus_dma = (struct linux_ebus_dma *) spin_lock_init(&sun_pci_fd_ebus_dma.lock);
edev->resource[1].start; /* XXX ioremap */
sun_pci_fd_reset_dma(); sun_pci_fd_ebus_dma.regs = edev->resource[1].start;
if (!sun_pci_fd_ebus_dma.regs)
return 0;
sun_pci_fd_ebus_dma.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
sun_pci_fd_ebus_dma.callback = sun_pci_fd_dma_callback;
sun_pci_fd_ebus_dma.client_cookie = NULL;
sun_pci_fd_ebus_dma.irq = FLOPPY_IRQ;
strcpy(sun_pci_fd_ebus_dma.name, "floppy");
if (ebus_dma_register(&sun_pci_fd_ebus_dma))
return 0;
sun_fdops.fd_inb = sun_pci_fd_inb; sun_fdops.fd_inb = sun_pci_fd_inb;
sun_fdops.fd_outb = sun_pci_fd_outb; sun_fdops.fd_outb = sun_pci_fd_outb;
......
...@@ -13,91 +13,50 @@ ...@@ -13,91 +13,50 @@
#define PARPORT_PC_MAX_PORTS PARPORT_MAX #define PARPORT_PC_MAX_PORTS PARPORT_MAX
static struct linux_ebus_dma *sparc_ebus_dmas[PARPORT_PC_MAX_PORTS]; static struct sparc_ebus_info {
struct ebus_dma_info info;
unsigned int addr;
unsigned int count;
} sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
static __inline__ void static __inline__ void enable_dma(unsigned int dmanr)
reset_dma(unsigned int dmanr)
{ {
unsigned int dcsr; if (ebus_dma_request(&sparc_ebus_dmas[dmanr].info,
sparc_ebus_dmas[dmanr].addr,
sparc_ebus_dmas[dmanr].count))
BUG();
writel(EBUS_DCSR_RESET, &sparc_ebus_dmas[dmanr]->dcsr); ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1);
udelay(1);
dcsr = EBUS_DCSR_BURST_SZ_16 | EBUS_DCSR_TCI_DIS |
EBUS_DCSR_EN_CNT | EBUS_DCSR_INT_EN;
writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
} }
static __inline__ void static __inline__ void disable_dma(unsigned int dmanr)
enable_dma(unsigned int dmanr)
{ {
unsigned int dcsr; ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 0);
dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
dcsr |= EBUS_DCSR_EN_DMA;
writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
} }
static __inline__ void static __inline__ void clear_dma_ff(unsigned int dmanr)
disable_dma(unsigned int dmanr)
{
unsigned int dcsr;
dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
if (dcsr & EBUS_DCSR_EN_DMA) {
while (dcsr & EBUS_DCSR_DRAIN) {
udelay(1);
dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
}
dcsr &= ~(EBUS_DCSR_EN_DMA);
writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
if (dcsr & EBUS_DCSR_ERR_PEND)
reset_dma(dmanr);
}
}
static __inline__ void
clear_dma_ff(unsigned int dmanr)
{ {
/* nothing */ /* nothing */
} }
static __inline__ void static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
set_dma_mode(unsigned int dmanr, char mode)
{ {
unsigned int dcsr; ebus_dma_prepare(&sparc_ebus_dmas[dmanr].info, (mode != DMA_MODE_WRITE));
dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
dcsr |= EBUS_DCSR_EN_CNT | EBUS_DCSR_TC;
if (mode == DMA_MODE_WRITE)
dcsr &= ~(EBUS_DCSR_WRITE);
else
dcsr |= EBUS_DCSR_WRITE;
writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
} }
static __inline__ void static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int addr)
set_dma_addr(unsigned int dmanr, unsigned int addr)
{ {
writel(addr, &sparc_ebus_dmas[dmanr]->dacr); sparc_ebus_dmas[dmanr].addr = addr;
} }
static __inline__ void static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
set_dma_count(unsigned int dmanr, unsigned int count)
{ {
writel(count, &sparc_ebus_dmas[dmanr]->dbcr); sparc_ebus_dmas[dmanr].count = count;
} }
static __inline__ int static __inline__ unsigned int get_dma_residue(unsigned int dmanr)
get_dma_residue(unsigned int dmanr)
{ {
int res; return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
res = readl(&sparc_ebus_dmas[dmanr]->dbcr);
if (res != 0)
reset_dma(dmanr);
return res;
} }
static int ebus_ecpp_p(struct linux_ebus_device *edev) static int ebus_ecpp_p(struct linux_ebus_device *edev)
...@@ -171,10 +130,19 @@ static int parport_pc_find_nonpci_ports (int autoirq, int autodma) ...@@ -171,10 +130,19 @@ static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
unsigned long base = edev->resource[0].start; unsigned long base = edev->resource[0].start;
unsigned long config = edev->resource[1].start; unsigned long config = edev->resource[1].start;
sparc_ebus_dmas[count] = spin_lock_init(&sparc_ebus_dmas[count].info);
(struct linux_ebus_dma *) sparc_ebus_dmas[count].info.regs =
edev->resource[2].start; edev->resource[2].start;
reset_dma(count); if (!sparc_ebus_dmas[count].info.regs)
continue;
sparc_ebus_dmas[count].info.flags = 0;
sparc_ebus_dmas[count].info.callback = NULL;
sparc_ebus_dmas[count].info.client_cookie = NULL;
sparc_ebus_dmas[count].info.irq = 0xdeadbeef;
strcpy(sparc_ebus_dmas[count].info.name, "parport");
if (ebus_dma_register(&sparc_ebus_dmas[count].info))
continue;
ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1);
/* Configure IRQ to Push Pull, Level Low */ /* Configure IRQ to Push Pull, Level Low */
/* Enable ECP, set bit 2 of the CTR first */ /* Enable ECP, set bit 2 of the CTR first */
......
...@@ -66,8 +66,10 @@ MODULE_DEVICES("{{Sun,CS4231}}"); ...@@ -66,8 +66,10 @@ MODULE_DEVICES("{{Sun,CS4231}}");
typedef struct snd_cs4231 { typedef struct snd_cs4231 {
spinlock_t lock; spinlock_t lock;
unsigned long port; unsigned long port;
unsigned long eb2c; #ifdef EBUS_SUPPORT
unsigned long eb2p; struct ebus_dma_info eb2c;
struct ebus_dma_info eb2p;
#endif
u32 flags; u32 flags;
#define CS4231_FLAG_EBUS 0x00000001 #define CS4231_FLAG_EBUS 0x00000001
...@@ -77,7 +79,9 @@ typedef struct snd_cs4231 { ...@@ -77,7 +79,9 @@ typedef struct snd_cs4231 {
snd_card_t *card; snd_card_t *card;
snd_pcm_t *pcm; snd_pcm_t *pcm;
snd_pcm_substream_t *playback_substream; snd_pcm_substream_t *playback_substream;
unsigned int p_periods_sent;
snd_pcm_substream_t *capture_substream; snd_pcm_substream_t *capture_substream;
unsigned int c_periods_sent;
snd_timer_t *timer; snd_timer_t *timer;
unsigned short mode; unsigned short mode;
...@@ -87,13 +91,11 @@ typedef struct snd_cs4231 { ...@@ -87,13 +91,11 @@ typedef struct snd_cs4231 {
#define CS4231_MODE_TIMER 0x0004 #define CS4231_MODE_TIMER 0x0004
#define CS4231_MODE_OPEN (CS4231_MODE_PLAY|CS4231_MODE_RECORD|CS4231_MODE_TIMER) #define CS4231_MODE_OPEN (CS4231_MODE_PLAY|CS4231_MODE_RECORD|CS4231_MODE_TIMER)
unsigned char image[32]; /* registers image */ unsigned char image[32]; /* registers image */
int mce_bit; int mce_bit;
int calibrate_mute; int calibrate_mute;
unsigned int p_dma_size; struct semaphore mce_mutex;
unsigned int c_dma_size; struct semaphore open_mutex;
struct semaphore mce_mutex;
struct semaphore open_mutex;
union { union {
#ifdef SBUS_SUPPORT #ifdef SBUS_SUPPORT
...@@ -119,6 +121,7 @@ static cs4231_t *cs4231_list; ...@@ -119,6 +121,7 @@ static cs4231_t *cs4231_list;
#define CS4231P(chip, x) ((chip)->port + c_d_c_CS4231##x) #define CS4231P(chip, x) ((chip)->port + c_d_c_CS4231##x)
/* XXX offsets are different than PC ISA chips... */
#define c_d_c_CS4231REGSEL 0x0 #define c_d_c_CS4231REGSEL 0x0
#define c_d_c_CS4231REG 0x4 #define c_d_c_CS4231REG 0x4
#define c_d_c_CS4231STATUS 0x8 #define c_d_c_CS4231STATUS 0x8
...@@ -336,7 +339,7 @@ static unsigned char snd_cs4231_original_image[32] = ...@@ -336,7 +339,7 @@ static unsigned char snd_cs4231_original_image[32] =
0x00, /* 0a/10 - pc */ 0x00, /* 0a/10 - pc */
0x00, /* 0b/11 - ti */ 0x00, /* 0b/11 - ti */
CS4231_MODE2, /* 0c/12 - mi */ CS4231_MODE2, /* 0c/12 - mi */
0xfc, /* 0d/13 - lbc */ 0x00, /* 0d/13 - lbc */
0x00, /* 0e/14 - pbru */ 0x00, /* 0e/14 - pbru */
0x00, /* 0f/15 - pbrl */ 0x00, /* 0f/15 - pbrl */
0x80, /* 10/16 - afei */ 0x80, /* 10/16 - afei */
...@@ -349,7 +352,7 @@ static unsigned char snd_cs4231_original_image[32] = ...@@ -349,7 +352,7 @@ static unsigned char snd_cs4231_original_image[32] =
0x00, /* 17/23 - ra3mic/reserved */ 0x00, /* 17/23 - ra3mic/reserved */
0x00, /* 18/24 - afs */ 0x00, /* 18/24 - afs */
0x00, /* 19/25 - lamoc/version */ 0x00, /* 19/25 - lamoc/version */
0xcf, /* 1a/26 - mioc */ 0x00, /* 1a/26 - mioc */
0x00, /* 1b/27 - ramoc/reserved */ 0x00, /* 1b/27 - ramoc/reserved */
0x20, /* 1c/28 - cdfr */ 0x20, /* 1c/28 - cdfr */
0x00, /* 1d/29 - res4 */ 0x00, /* 1d/29 - res4 */
...@@ -425,7 +428,7 @@ static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char val ...@@ -425,7 +428,7 @@ static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char val
for (timeout = 250; for (timeout = 250;
timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
timeout--) timeout--)
udelay(10); udelay(100);
__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
__cs4231_writeb(chip, value, CS4231P(chip, REG)); __cs4231_writeb(chip, value, CS4231P(chip, REG));
mb(); mb();
...@@ -511,8 +514,8 @@ void snd_cs4231_debug(cs4231_t *chip) ...@@ -511,8 +514,8 @@ void snd_cs4231_debug(cs4231_t *chip)
printk(" 0x0d: loopback = 0x%02x ", snd_cs4231_in(chip, 0x0d)); printk(" 0x0d: loopback = 0x%02x ", snd_cs4231_in(chip, 0x0d));
printk(" 0x1d: var freq (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x1d)); printk(" 0x1d: var freq (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x1d));
printk(" 0x0e: ply upr count = 0x%02x ", snd_cs4231_in(chip, 0x0e)); printk(" 0x0e: ply upr count = 0x%02x ", snd_cs4231_in(chip, 0x0e));
printk(" 0x1e: ply lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1e)); printk(" 0x1e: rec upr count = 0x%02x\n", snd_cs4231_in(chip, 0x1e));
printk(" 0x0f: rec upr count = 0x%02x ", snd_cs4231_in(chip, 0x0f)); printk(" 0x0f: ply lwr count = 0x%02x ", snd_cs4231_in(chip, 0x0f));
printk(" 0x1f: rec lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1f)); printk(" 0x1f: rec lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1f));
} }
...@@ -533,7 +536,7 @@ static void snd_cs4231_busy_wait(cs4231_t *chip) ...@@ -533,7 +536,7 @@ static void snd_cs4231_busy_wait(cs4231_t *chip)
for (timeout = 250; for (timeout = 250;
timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
timeout--) timeout--)
udelay(10); udelay(100);
} }
static void snd_cs4231_mce_up(cs4231_t *chip) static void snd_cs4231_mce_up(cs4231_t *chip)
...@@ -586,7 +589,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip) ...@@ -586,7 +589,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
/* calibration process */ /* calibration process */
for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--) for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--)
udelay(10); udelay(100);
if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) { if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) {
snd_printd("cs4231_mce_down - auto calibration time out (1)\n"); snd_printd("cs4231_mce_down - auto calibration time out (1)\n");
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
...@@ -627,6 +630,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip) ...@@ -627,6 +630,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
#endif #endif
} }
#if 0 /* Unused for now... */
static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size) static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size)
{ {
switch (format & 0xe0) { switch (format & 0xe0) {
...@@ -641,15 +645,70 @@ static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size ...@@ -641,15 +645,70 @@ static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size
size >>= 1; size >>= 1;
return size; return size;
} }
#endif
static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd) #ifdef EBUS_SUPPORT
static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime;
int result = 0;
while (1) {
unsigned int dma_size = snd_pcm_lib_period_bytes(substream);
unsigned int offset = dma_size * (*periods_sent);
if (dma_size >= (1 << 24))
BUG();
if (ebus_dma_request(p, runtime->dma_addr + offset, dma_size))
return;
#if 0 #if 0
printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, __cs4231_readb(chip, CS4231P(card, STATUS))); printk("ebus_advance: Sent period %u (size[%x] offset[%x])\n",
(*periods_sent), dma_size, offset);
#endif
(*periods_sent) = ((*periods_sent) + 1) % runtime->periods;
}
}
#endif
static void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on)
{
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
if (what & CS4231_PLAYBACK_ENABLE) {
if (on) {
ebus_dma_prepare(&chip->eb2p, 0);
ebus_dma_enable(&chip->eb2p, 1);
snd_cs4231_ebus_advance_dma(&chip->eb2p,
chip->playback_substream,
&chip->p_periods_sent);
} else {
ebus_dma_enable(&chip->eb2p, 0);
}
}
if (what & CS4231_RECORD_ENABLE) {
if (on) {
ebus_dma_prepare(&chip->eb2c, 1);
ebus_dma_enable(&chip->eb2c, 1);
snd_cs4231_ebus_advance_dma(&chip->eb2c,
chip->capture_substream,
&chip->c_periods_sent);
} else {
ebus_dma_enable(&chip->eb2c, 0);
}
}
} else {
#endif
#ifdef SBUS_SUPPORT
#endif #endif
#ifdef EBUS_SUPPORT
}
#endif
}
static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
int result = 0;
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
...@@ -657,6 +716,8 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd) ...@@ -657,6 +716,8 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
{ {
unsigned int what = 0; unsigned int what = 0;
snd_pcm_substream_t *s = substream; snd_pcm_substream_t *s = substream;
unsigned long flags;
do { do {
if (s == chip->playback_substream) { if (s == chip->playback_substream) {
what |= CS4231_PLAYBACK_ENABLE; what |= CS4231_PLAYBACK_ENABLE;
...@@ -667,13 +728,31 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd) ...@@ -667,13 +728,31 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
} }
s = s->link_next; s = s->link_next;
} while (s != substream); } while (s != substream);
spin_lock(&chip->lock);
if (cmd == SNDRV_PCM_TRIGGER_START) #if 0
printk("TRIGGER: what[%x] on(%d)\n",
what, (cmd == SNDRV_PCM_TRIGGER_START));
#endif
spin_lock_irqsave(&chip->lock, flags);
if (cmd == SNDRV_PCM_TRIGGER_START) {
cs4231_dma_trigger(chip, what, 1);
chip->image[CS4231_IFACE_CTRL] |= what; chip->image[CS4231_IFACE_CTRL] |= what;
else if (what & CS4231_PLAYBACK_ENABLE) {
snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, 0xff);
snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, 0xff);
}
if (what & CS4231_RECORD_ENABLE) {
snd_cs4231_out(chip, CS4231_REC_LWR_CNT, 0xff);
snd_cs4231_out(chip, CS4231_REC_UPR_CNT, 0xff);
}
} else {
cs4231_dma_trigger(chip, what, 0);
chip->image[CS4231_IFACE_CTRL] &= ~what; chip->image[CS4231_IFACE_CTRL] &= ~what;
snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); }
spin_unlock(&chip->lock); snd_cs4231_out(chip, CS4231_IFACE_CTRL,
chip->image[CS4231_IFACE_CTRL]);
spin_unlock_irqrestore(&chip->lock, flags);
break; break;
} }
default: default:
...@@ -942,8 +1021,7 @@ static int snd_cs4231_open(cs4231_t *chip, unsigned int mode) ...@@ -942,8 +1021,7 @@ static int snd_cs4231_open(cs4231_t *chip, unsigned int mode)
snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
__cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
__cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
CS4231_RECORD_IRQ | CS4231_RECORD_IRQ |
CS4231_TIMER_IRQ); CS4231_TIMER_IRQ);
...@@ -972,8 +1050,6 @@ static void snd_cs4231_close(cs4231_t *chip, unsigned int mode) ...@@ -972,8 +1050,6 @@ static void snd_cs4231_close(cs4231_t *chip, unsigned int mode)
snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
__cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
__cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
/* now disable record & playback */ /* now disable record & playback */
...@@ -1064,48 +1140,13 @@ static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream) ...@@ -1064,48 +1140,13 @@ static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream)
static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream) static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long flags; unsigned long flags;
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
chip->p_dma_size = size;
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
CS4231_PLAYBACK_PIO); CS4231_PLAYBACK_PIO);
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
writel(EBUS_DCSR_RESET, chip->eb2p + EBDMA_CSR);
writel(EBUS_DCSR_BURST_SZ_16, chip->eb2p + EBDMA_CSR);
writel(size, chip->eb2p + EBDMA_COUNT);
writel(runtime->dma_addr, chip->eb2p + EBDMA_ADDR);
writel((EBUS_DCSR_BURST_SZ_16 |
EBUS_DCSR_EN_DMA |
EBUS_DCSR_INT_EN), chip->eb2p + EBDMA_CSR);
} else {
#endif
#ifdef SBUS_SUPPORT
sbus_writel(runtime->dma_addr, chip->port + APCPNVA);
sbus_writel(size, chip->port + APCPNC);
sbus_writel(((sbus_readl(chip->port + APCCSR)
& ~APC_PPAUSE)
| APC_PDMA_READY), chip->port + APCCSR);
#endif
#ifdef EBUS_SUPPORT
}
#endif
count = snd_cs4231_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;
snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
#if 0
snd_cs4231_debug(chip);
#endif
return 0; return 0;
} }
...@@ -1135,43 +1176,11 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream) ...@@ -1135,43 +1176,11 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream)
static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream) static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long flags; unsigned long flags;
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
chip->c_dma_size = size; chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); CS4231_RECORD_PIO);
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
writel(EBUS_DCSR_RESET, chip->eb2c + EBDMA_CSR);
writel(EBUS_DCSR_BURST_SZ_16, chip->eb2c + EBDMA_CSR);
writel(size, chip->eb2c + EBDMA_COUNT);
writel(runtime->dma_addr, chip->eb2c + EBDMA_ADDR);
writel((EBUS_DCSR_BURST_SZ_16 |
EBUS_DCSR_EN_DMA |
EBUS_DCSR_WRITE |
EBUS_DCSR_INT_EN), chip->eb2c + EBDMA_CSR);
} else {
#endif
#ifdef SBUS_SUPPORT
sbus_writel(runtime->dma_addr, chip->port + APCCNVA);
sbus_writel(size, chip->port + APCCNC);
sbus_writel(((sbus_readl(chip->port + APCCSR)
& ~APC_CPAUSE) |
APC_CDMA_READY), chip->port + APCCSR);
#endif
#ifdef EBUS_SUPPORT
}
#endif
count = snd_cs4231_get_count(chip->image[CS4231_REC_FORMAT], count) - 1;
snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count);
snd_cs4231_out(chip, CS4231_REC_UPR_CNT, (unsigned char) (count >> 8));
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
...@@ -1193,9 +1202,13 @@ static void snd_cs4231_overrange(cs4231_t *chip) ...@@ -1193,9 +1202,13 @@ static void snd_cs4231_overrange(cs4231_t *chip)
static void snd_cs4231_generic_interrupt(cs4231_t *chip) static void snd_cs4231_generic_interrupt(cs4231_t *chip)
{ {
unsigned long flags;
unsigned char status; unsigned char status;
status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
if (!status)
return;
if (status & CS4231_TIMER_IRQ) { if (status & CS4231_TIMER_IRQ) {
if (chip->timer) if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks); snd_timer_interrupt(chip->timer, chip->timer->sticks);
...@@ -1208,9 +1221,9 @@ static void snd_cs4231_generic_interrupt(cs4231_t *chip) ...@@ -1208,9 +1221,9 @@ static void snd_cs4231_generic_interrupt(cs4231_t *chip)
} }
/* ACK the CS4231 interrupt. */ /* ACK the CS4231 interrupt. */
spin_lock(&chip->lock); spin_lock_irqsave(&chip->lock, flags);
snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
spin_unlock(&chip->lock); spin_unlock_irqrestore(&chip->lock, flags);
} }
#ifdef SBUS_SUPPORT #ifdef SBUS_SUPPORT
...@@ -1236,47 +1249,41 @@ static void snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *reg ...@@ -1236,47 +1249,41 @@ static void snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *reg
#endif #endif
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
static void snd_cs4231_ebus_play_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie)
{ {
cs4231_t *chip = snd_magic_cast(cs4231_t, dev_id, return); cs4231_t *chip = snd_magic_cast(cs4231_t, cookie, return);
u32 csr;
csr = readl(chip->eb2p + EBDMA_CSR);
if (!(csr & EBUS_DCSR_INT_PEND))
return;
/* ACK the EBUS playback DMA interrupt. */
writel(csr, chip->eb2p + EBDMA_CSR);
snd_cs4231_generic_interrupt(chip); if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) {
snd_pcm_period_elapsed(chip->playback_substream);
snd_cs4231_ebus_advance_dma(p, chip->playback_substream,
&chip->p_periods_sent);
}
} }
static void snd_cs4231_ebus_capture_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie)
{ {
cs4231_t *chip = snd_magic_cast(cs4231_t, dev_id, return); cs4231_t *chip = snd_magic_cast(cs4231_t, cookie, return);
u32 csr;
csr = readl(chip->eb2c + EBDMA_CSR);
if (!(csr & EBUS_DCSR_INT_PEND))
return;
/* ACK the EBUS capture DMA interrupt. */
writel(csr, chip->eb2c + EBDMA_CSR);
snd_cs4231_generic_interrupt(chip); if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) {
snd_pcm_period_elapsed(chip->capture_substream);
snd_cs4231_ebus_advance_dma(p, chip->capture_substream,
&chip->c_periods_sent);
}
} }
#endif #endif
static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream) static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
size_t ptr, residue; size_t ptr, residue, period_bytes;
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
return 0; return 0;
period_bytes = snd_pcm_lib_period_bytes(substream);
ptr = period_bytes * chip->p_periods_sent;
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) { if (chip->flags & CS4231_FLAG_EBUS) {
residue = readl(chip->eb2p + EBDMA_COUNT); residue = ebus_dma_residue(&chip->eb2p);
} else { } else {
#endif #endif
#ifdef SBUS_SUPPORT #ifdef SBUS_SUPPORT
...@@ -1285,20 +1292,22 @@ static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substr ...@@ -1285,20 +1292,22 @@ static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substr
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
} }
#endif #endif
ptr = chip->p_dma_size - residue; ptr += (period_bytes - residue);
return bytes_to_frames(substream->runtime, ptr); return bytes_to_frames(substream->runtime, ptr);
} }
static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream) static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
size_t ptr, residue; size_t ptr, residue, period_bytes;
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
return 0; return 0;
period_bytes = snd_pcm_lib_period_bytes(substream);
ptr = period_bytes * chip->c_periods_sent;
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) { if (chip->flags & CS4231_FLAG_EBUS) {
residue = readl(chip->eb2c + EBDMA_COUNT); residue = ebus_dma_residue(&chip->eb2c);
} else { } else {
#endif #endif
#ifdef SBUS_SUPPORT #ifdef SBUS_SUPPORT
...@@ -1307,7 +1316,7 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substr ...@@ -1307,7 +1316,7 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substr
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
} }
#endif #endif
ptr = chip->c_dma_size - residue; ptr += (period_bytes - residue);
return bytes_to_frames(substream->runtime, ptr); return bytes_to_frames(substream->runtime, ptr);
} }
...@@ -1318,13 +1327,13 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substr ...@@ -1318,13 +1327,13 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substr
static int snd_cs4231_probe(cs4231_t *chip) static int snd_cs4231_probe(cs4231_t *chip)
{ {
unsigned long flags; unsigned long flags;
int i, id; int i, id, vers;
unsigned char *ptr; unsigned char *ptr;
#if 0 #if 0
snd_cs4231_debug(chip); snd_cs4231_debug(chip);
#endif #endif
id = 0; id = vers = 0;
for (i = 0; i < 50; i++) { for (i = 0; i < 50; i++) {
mb(); mb();
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
...@@ -1333,6 +1342,7 @@ static int snd_cs4231_probe(cs4231_t *chip) ...@@ -1333,6 +1342,7 @@ static int snd_cs4231_probe(cs4231_t *chip)
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2); snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f; id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;
vers = snd_cs4231_in(chip, CS4231_VERSION);
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
if (id == 0x0a) if (id == 0x0a)
break; /* this is valid value */ break; /* this is valid value */
...@@ -1344,15 +1354,11 @@ static int snd_cs4231_probe(cs4231_t *chip) ...@@ -1344,15 +1354,11 @@ static int snd_cs4231_probe(cs4231_t *chip)
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
/* Reset DMA engine. */ /* Reset DMA engine. */
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) { if (chip->flags & CS4231_FLAG_EBUS) {
writel(EBUS_DCSR_RESET, chip->eb2p + EBDMA_CSR); /* Done by ebus_dma_register */
writel(EBUS_DCSR_RESET, chip->eb2c + EBDMA_CSR);
writel(EBUS_DCSR_BURST_SZ_16 |
EBUS_DCSR_INT_EN, chip->eb2p + EBDMA_CSR);
writel(EBUS_DCSR_BURST_SZ_16 |
EBUS_DCSR_INT_EN, chip->eb2c + EBDMA_CSR);
} else { } else {
#endif #endif
#ifdef SBUS_SUPPORT #ifdef SBUS_SUPPORT
...@@ -1385,6 +1391,8 @@ static int snd_cs4231_probe(cs4231_t *chip) ...@@ -1385,6 +1391,8 @@ static int snd_cs4231_probe(cs4231_t *chip)
chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA; chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA;
chip->image[CS4231_ALT_FEATURE_1] = 0x80; chip->image[CS4231_ALT_FEATURE_1] = 0x80;
chip->image[CS4231_ALT_FEATURE_2] = 0x01; chip->image[CS4231_ALT_FEATURE_2] = 0x01;
if (vers & 0x20)
chip->image[CS4231_ALT_FEATURE_2] |= 0x02;
ptr = (unsigned char *) &chip->image; ptr = (unsigned char *) &chip->image;
...@@ -1419,9 +1427,9 @@ static snd_pcm_hardware_t snd_cs4231_playback = ...@@ -1419,9 +1427,9 @@ static snd_pcm_hardware_t snd_cs4231_playback =
rate_max: 48000, rate_max: 48000,
channels_min: 1, channels_min: 1,
channels_max: 2, channels_max: 2,
buffer_bytes_max: (128*1024), buffer_bytes_max: (32*1024),
period_bytes_min: 64, period_bytes_min: 4096,
period_bytes_max: (128*1024), period_bytes_max: (32*1024),
periods_min: 1, periods_min: 1,
periods_max: 1024, periods_max: 1024,
fifo_size: 0, fifo_size: 0,
...@@ -1440,9 +1448,9 @@ static snd_pcm_hardware_t snd_cs4231_capture = ...@@ -1440,9 +1448,9 @@ static snd_pcm_hardware_t snd_cs4231_capture =
rate_max: 48000, rate_max: 48000,
channels_min: 1, channels_min: 1,
channels_max: 2, channels_max: 2,
buffer_bytes_max: (128*1024), buffer_bytes_max: (32*1024),
period_bytes_min: 64, period_bytes_min: 4096,
period_bytes_max: (128*1024), period_bytes_max: (32*1024),
periods_min: 1, periods_min: 1,
periods_max: 1024, periods_max: 1024,
fifo_size: 0, fifo_size: 0,
...@@ -1461,6 +1469,7 @@ static int snd_cs4231_playback_open(snd_pcm_substream_t *substream) ...@@ -1461,6 +1469,7 @@ static int snd_cs4231_playback_open(snd_pcm_substream_t *substream)
return err; return err;
} }
chip->playback_substream = substream; chip->playback_substream = substream;
chip->p_periods_sent = 0;
snd_pcm_set_sync(substream); snd_pcm_set_sync(substream);
snd_cs4231_xrate(runtime); snd_cs4231_xrate(runtime);
...@@ -1480,6 +1489,7 @@ static int snd_cs4231_capture_open(snd_pcm_substream_t *substream) ...@@ -1480,6 +1489,7 @@ static int snd_cs4231_capture_open(snd_pcm_substream_t *substream)
return err; return err;
} }
chip->capture_substream = substream; chip->capture_substream = substream;
chip->c_periods_sent = 0;
snd_pcm_set_sync(substream); snd_pcm_set_sync(substream);
snd_cs4231_xrate(runtime); snd_cs4231_xrate(runtime);
...@@ -2035,18 +2045,17 @@ static int cs4231_sbus_attach(struct sbus_dev *sdev) ...@@ -2035,18 +2045,17 @@ static int cs4231_sbus_attach(struct sbus_dev *sdev)
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
static int snd_cs4231_ebus_free(cs4231_t *chip) static int snd_cs4231_ebus_free(cs4231_t *chip)
{ {
if (chip->irq[0]) if (chip->eb2c.regs) {
free_irq(chip->irq[0], chip); ebus_dma_unregister(&chip->eb2c);
if (chip->irq[1]) iounmap(chip->eb2c.regs);
free_irq(chip->irq[1], chip); }
if (chip->eb2p.regs) {
ebus_dma_unregister(&chip->eb2p);
iounmap(chip->eb2p.regs);
}
if (chip->port) if (chip->port)
iounmap(chip->port); iounmap(chip->port);
if (chip->eb2p)
iounmap(chip->eb2p);
if (chip->eb2c)
iounmap(chip->eb2c);
if (chip->timer) if (chip->timer)
snd_device_free(chip->card, chip->timer); snd_device_free(chip->card, chip->timer);
...@@ -2080,6 +2089,8 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card, ...@@ -2080,6 +2089,8 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card,
return -ENOMEM; return -ENOMEM;
spin_lock_init(&chip->lock); spin_lock_init(&chip->lock);
spin_lock_init(&chip->eb2c.lock);
spin_lock_init(&chip->eb2p.lock);
init_MUTEX(&chip->mce_mutex); init_MUTEX(&chip->mce_mutex);
init_MUTEX(&chip->open_mutex); init_MUTEX(&chip->open_mutex);
chip->flags |= CS4231_FLAG_EBUS; chip->flags |= CS4231_FLAG_EBUS;
...@@ -2087,35 +2098,47 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card, ...@@ -2087,35 +2098,47 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card,
chip->dev_u.pdev = edev->bus->self; chip->dev_u.pdev = edev->bus->self;
memcpy(&chip->image, &snd_cs4231_original_image, memcpy(&chip->image, &snd_cs4231_original_image,
sizeof(snd_cs4231_original_image)); sizeof(snd_cs4231_original_image));
strcpy(chip->eb2c.name, "cs4231(capture)");
chip->eb2c.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->eb2c.callback = snd_cs4231_ebus_capture_callback;
chip->eb2c.client_cookie = chip;
chip->eb2c.irq = edev->irqs[0];
strcpy(chip->eb2p.name, "cs4231(play)");
chip->eb2p.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->eb2p.callback = snd_cs4231_ebus_play_callback;
chip->eb2p.client_cookie = chip;
chip->eb2p.irq = edev->irqs[1];
chip->port = (unsigned long) ioremap(edev->resource[0].start, 0x10); chip->port = (unsigned long) ioremap(edev->resource[0].start, 0x10);
chip->eb2p = (unsigned long) ioremap(edev->resource[1].start, 0x10); chip->eb2p.regs = (unsigned long) ioremap(edev->resource[1].start, 0x10);
chip->eb2c = (unsigned long) ioremap(edev->resource[2].start, 0x10); chip->eb2c.regs = (unsigned long) ioremap(edev->resource[2].start, 0x10);
if (!chip->port || !chip->eb2p || !chip->eb2c) { if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) {
snd_cs4231_ebus_free(chip); snd_cs4231_ebus_free(chip);
snd_printk("cs4231-%d: Unable to map chip registers.\n", dev); snd_printk("cs4231-%d: Unable to map chip registers.\n", dev);
return -EIO; return -EIO;
} }
if (request_irq(edev->irqs[0], snd_cs4231_ebus_capture_interrupt, if (ebus_dma_register(&chip->eb2c)) {
SA_SHIRQ, "cs4231(capture)", chip)) {
snd_cs4231_ebus_free(chip); snd_cs4231_ebus_free(chip);
snd_printk("cs4231-%d: Unable to grab EBUS capture IRQ %s\n", snd_printk("cs4231-%d: Unable to register EBUS capture DMA\n", dev);
dev, return -EBUSY;
__irq_itoa(edev->irqs[0])); }
if (ebus_dma_irq_enable(&chip->eb2c, 1)) {
snd_cs4231_ebus_free(chip);
snd_printk("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev);
return -EBUSY; return -EBUSY;
} }
chip->irq[0] = edev->irqs[0];
if (request_irq(edev->irqs[1], snd_cs4231_ebus_play_interrupt, if (ebus_dma_register(&chip->eb2p)) {
SA_SHIRQ, "cs4231(play)", chip)) {
snd_cs4231_ebus_free(chip); snd_cs4231_ebus_free(chip);
snd_printk("cs4231-%d: Unable to grab EBUS play IRQ %s\n", snd_printk("cs4231-%d: Unable to register EBUS play DMA\n", dev);
dev, return -EBUSY;
__irq_itoa(edev->irqs[0])); }
if (ebus_dma_irq_enable(&chip->eb2p, 1)) {
snd_cs4231_ebus_free(chip);
snd_printk("cs4231-%d: Unable to enable EBUS play IRQ\n", dev);
return -EBUSY; return -EBUSY;
} }
chip->irq[1] = edev->irqs[1];
if (snd_cs4231_probe(chip) < 0) { if (snd_cs4231_probe(chip) < 0) {
snd_cs4231_ebus_free(chip); snd_cs4231_ebus_free(chip);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment