Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

This commit is contained in:
Linus Torvalds 2005-09-21 07:53:38 -07:00
commit 2fe9f798ba
12 changed files with 276 additions and 206 deletions

View file

@ -42,19 +42,15 @@
* executing (see inherit_locked_prom_mappings() rant).
*/
sparc64_vpte_nucleus:
/* Load 0xf0000000, which is LOW_OBP_ADDRESS. */
mov 0xf, %g5
sllx %g5, 28, %g5
/* Is addr >= LOW_OBP_ADDRESS? */
/* Note that kvmap below has verified that the address is
* in the range MODULES_VADDR --> VMALLOC_END already. So
* here we need only check if it is an OBP address or not.
*/
sethi %hi(LOW_OBP_ADDRESS), %g5
cmp %g4, %g5
blu,pn %xcc, sparc64_vpte_patchme1
mov 0x1, %g5
/* Load 0x100000000, which is HI_OBP_ADDRESS. */
sllx %g5, 32, %g5
/* Is addr < HI_OBP_ADDRESS? */
cmp %g4, %g5
blu,pn %xcc, obp_iaddr_patch
nop
@ -156,26 +152,29 @@ obp_daddr_patch:
* rather, use information saved during inherit_prom_mappings() using 8k
* pagesize.
*/
.align 32
kvmap:
/* Load 0xf0000000, which is LOW_OBP_ADDRESS. */
mov 0xf, %g5
sllx %g5, 28, %g5
/* Is addr >= LOW_OBP_ADDRESS? */
sethi %hi(MODULES_VADDR), %g5
cmp %g4, %g5
blu,pn %xcc, vmalloc_addr
blu,pn %xcc, longpath
mov (VMALLOC_END >> 24), %g5
sllx %g5, 24, %g5
cmp %g4, %g5
bgeu,pn %xcc, longpath
nop
kvmap_check_obp:
sethi %hi(LOW_OBP_ADDRESS), %g5
cmp %g4, %g5
blu,pn %xcc, kvmap_vmalloc_addr
mov 0x1, %g5
/* Load 0x100000000, which is HI_OBP_ADDRESS. */
sllx %g5, 32, %g5
/* Is addr < HI_OBP_ADDRESS? */
cmp %g4, %g5
blu,pn %xcc, obp_daddr_patch
nop
vmalloc_addr:
/* If we get here, a vmalloc addr accessed, load kernel VPTE. */
kvmap_vmalloc_addr:
/* If we get here, a vmalloc addr was accessed, load kernel VPTE. */
ldxa [%g3 + %g6] ASI_N, %g5
brgez,pn %g5, longpath
nop

View file

@ -30,6 +30,7 @@
#include <asm/psrcompat.h>
#include <asm/visasm.h>
#include <asm/spitfire.h>
#include <asm/page.h>
/* Returning from ptrace is a bit tricky because the syscall return
* low level code assumes any value returned which is negative and
@ -128,20 +129,20 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
* is mapped to in the user's address space, we can skip the
* D-cache flush.
*/
if ((uaddr ^ kaddr) & (1UL << 13)) {
if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
unsigned long start = __pa(kaddr);
unsigned long end = start + len;
if (tlb_type == spitfire) {
for (; start < end; start += 32)
spitfire_put_dcache_tag(va & 0x3fe0, 0x0);
spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
} else {
for (; start < end; start += 32)
__asm__ __volatile__(
"stxa %%g0, [%0] %1\n\t"
"membar #Sync"
: /* no outputs */
: "r" (va),
: "r" (start),
"i" (ASI_DCACHE_INVALIDATE));
}
}

View file

@ -17,7 +17,7 @@ kernel_unaligned_trap_fault:
__do_int_store:
rd %asi, %o4
wr %o3, 0, %asi
ldx [%o2], %g3
mov %o2, %g3
cmp %o1, 2
be,pn %icc, 2f
cmp %o1, 4

View file

@ -184,13 +184,14 @@ extern void do_int_load(unsigned long *dest_reg, int size,
unsigned long *saddr, int is_signed, int asi);
extern void __do_int_store(unsigned long *dst_addr, int size,
unsigned long *src_val, int asi);
unsigned long src_val, int asi);
static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr,
struct pt_regs *regs, int asi)
struct pt_regs *regs, int asi, int orig_asi)
{
unsigned long zero = 0;
unsigned long *src_val = &zero;
unsigned long *src_val_p = &zero;
unsigned long src_val;
if (size == 16) {
size = 8;
@ -198,7 +199,25 @@ static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr,
(unsigned)fetch_reg(reg_num, regs) : 0)) << 32) |
(unsigned)fetch_reg(reg_num + 1, regs);
} else if (reg_num) {
src_val = fetch_reg_addr(reg_num, regs);
src_val_p = fetch_reg_addr(reg_num, regs);
}
src_val = *src_val_p;
if (unlikely(asi != orig_asi)) {
switch (size) {
case 2:
src_val = swab16(src_val);
break;
case 4:
src_val = swab32(src_val);
break;
case 8:
src_val = swab64(src_val);
break;
case 16:
default:
BUG();
break;
};
}
__do_int_store(dst_addr, size, src_val, asi);
}
@ -276,6 +295,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
kernel_mna_trap_fault();
} else {
unsigned long addr;
int orig_asi, asi;
addr = compute_effective_address(regs, insn,
((insn >> 25) & 0x1f));
@ -285,18 +305,48 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
regs->tpc, dirstrings[dir], addr, size,
regs->u_regs[UREG_RETPC]);
#endif
orig_asi = asi = decode_asi(insn, regs);
switch (asi) {
case ASI_NL:
case ASI_AIUPL:
case ASI_AIUSL:
case ASI_PL:
case ASI_SL:
case ASI_PNFL:
case ASI_SNFL:
asi &= ~0x08;
break;
};
switch (dir) {
case load:
do_int_load(fetch_reg_addr(((insn>>25)&0x1f), regs),
size, (unsigned long *) addr,
decode_signedness(insn),
decode_asi(insn, regs));
decode_signedness(insn), asi);
if (unlikely(asi != orig_asi)) {
unsigned long val_in = *(unsigned long *) addr;
switch (size) {
case 2:
val_in = swab16(val_in);
break;
case 4:
val_in = swab32(val_in);
break;
case 8:
val_in = swab64(val_in);
break;
case 16:
default:
BUG();
break;
};
*(unsigned long *) addr = val_in;
}
break;
case store:
do_int_store(((insn>>25)&0x1f), size,
(unsigned long *) addr, regs,
decode_asi(insn, regs));
asi, orig_asi);
break;
default:

View file

@ -174,7 +174,7 @@ int atyfb_xl_init(struct fb_info *info)
const struct xl_card_cfg_t * card = &card_cfg[xl_card];
struct atyfb_par *par = (struct atyfb_par *) info->par;
union aty_pll pll;
int i, err;
int err;
u32 temp;
aty_st_8(CONFIG_STAT0, 0x85, par);
@ -252,9 +252,12 @@ int atyfb_xl_init(struct fb_info *info)
aty_st_le32(0xEC, 0x00000000, par);
aty_st_le32(0xFC, 0x00000000, par);
#if defined (CONFIG_FB_ATY_GENERIC_LCD)
int i;
for (i=0; i<sizeof(lcd_tbl)/sizeof(lcd_tbl_t); i++) {
aty_st_lcd(lcd_tbl[i].lcd_reg, lcd_tbl[i].val, par);
}
#endif
aty_st_le16(CONFIG_STAT0, 0x00A4, par);
mdelay(10);

View file

@ -4,13 +4,6 @@
#include <linux/config.h>
#include <asm/page.h>
/* Flushing for D-cache alias handling is only needed if
* the page size is smaller than 16K.
*/
#if PAGE_SHIFT < 14
#define DCACHE_ALIASING_POSSIBLE
#endif
#ifndef __ASSEMBLY__
#include <linux/mm.h>

View file

@ -15,6 +15,7 @@
#include <asm/io.h>
#include <asm/spitfire.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#ifndef MAX_HWIFS
# ifdef CONFIG_BLK_DEV_IDEPCI

View file

@ -21,6 +21,13 @@
#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
/* Flushing for D-cache alias handling is only needed if
* the page size is smaller than 16K.
*/
#if PAGE_SHIFT < 14
#define DCACHE_ALIASING_POSSIBLE
#endif
#ifdef __KERNEL__
#ifndef __ASSEMBLY__

View file

@ -10,6 +10,7 @@
#include <asm/spitfire.h>
#include <asm/cpudata.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
/* Page table allocation/freeing. */
#ifdef CONFIG_SMP

View file

@ -24,21 +24,23 @@
#include <asm/processor.h>
#include <asm/const.h>
/* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 16MB).
* The page copy blockops use 0x1000000 to 0x18000000 (16MB --> 24MB).
/* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 32MB).
* The page copy blockops can use 0x2000000 to 0x10000000.
* The PROM resides in an area spanning 0xf0000000 to 0x100000000.
* The vmalloc area spans 0x140000000 to 0x200000000.
* The vmalloc area spans 0x100000000 to 0x200000000.
* Since modules need to be in the lowest 32-bits of the address space,
* we place them right before the OBP area from 0x10000000 to 0xf0000000.
* There is a single static kernel PMD which maps from 0x0 to address
* 0x400000000.
*/
#define TLBTEMP_BASE _AC(0x0000000001000000,UL)
#define MODULES_VADDR _AC(0x0000000002000000,UL)
#define MODULES_LEN _AC(0x000000007e000000,UL)
#define MODULES_END _AC(0x0000000080000000,UL)
#define VMALLOC_START _AC(0x0000000140000000,UL)
#define VMALLOC_END _AC(0x0000000200000000,UL)
#define TLBTEMP_BASE _AC(0x0000000002000000,UL)
#define MODULES_VADDR _AC(0x0000000010000000,UL)
#define MODULES_LEN _AC(0x00000000e0000000,UL)
#define MODULES_END _AC(0x00000000f0000000,UL)
#define LOW_OBP_ADDRESS _AC(0x00000000f0000000,UL)
#define HI_OBP_ADDRESS _AC(0x0000000100000000,UL)
#define VMALLOC_START _AC(0x0000000100000000,UL)
#define VMALLOC_END _AC(0x0000000200000000,UL)
/* XXX All of this needs to be rethought so we can take advantage
* XXX cheetah's full 64-bit virtual address space, ie. no more hole

View file

@ -5,6 +5,10 @@
* linux/byteorder_generic.h
* Generic Byte-reordering support
*
* The "... p" macros, like le64_to_cpup, can be used with pointers
* to unaligned data, but there will be a performance penalty on
* some architectures. Use get_unaligned for unaligned data.
*
* Francois-Rene Rideau <fare@tunes.org> 19970707
* gathered all the good ideas from all asm-foo/byteorder.h into one file,
* cleaned them up.

View file

@ -173,7 +173,7 @@ static cs4231_t *cs4231_list;
#define CS4231_GLOBALIRQ 0x01 /* IRQ is active */
/* definitions for codec irq status */
/* definitions for codec irq status - CS4231_IRQ_STATUS */
#define CS4231_PLAYBACK_IRQ 0x10
#define CS4231_RECORD_IRQ 0x20
@ -402,7 +402,7 @@ static void snd_cs4231_outm(cs4231_t *chip, unsigned char reg,
udelay(100);
#ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
snd_printdd("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
#endif
if (chip->calibrate_mute) {
chip->image[reg] &= mask;
@ -425,6 +425,10 @@ static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char val
timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
timeout--)
udelay(100);
#ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
#endif
__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
__cs4231_writeb(chip, value, CS4231P(chip, REG));
mb();
@ -440,15 +444,12 @@ static void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char valu
udelay(100);
#ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
#endif
__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
__cs4231_writeb(chip, value, CS4231P(chip, REG));
chip->image[reg] = value;
mb();
#if 0
printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value);
#endif
}
static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
@ -462,61 +463,14 @@ static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
udelay(100);
#ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
snd_printdd("in: auto calibration time out - reg = 0x%x\n", reg);
#endif
__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
mb();
ret = __cs4231_readb(chip, CS4231P(chip, REG));
#if 0
printk("codec in - reg 0x%x = 0x%x\n", chip->mce_bit | reg, ret);
#endif
return ret;
}
#if 0
static void snd_cs4231_debug(cs4231_t *chip)
{
printk("CS4231 REGS: INDEX = 0x%02x ",
__cs4231_readb(chip, CS4231P(chip, REGSEL)));
printk(" STATUS = 0x%02x\n",
__cs4231_readb(chip, CS4231P(chip, STATUS)));
printk(" 0x00: left input = 0x%02x ", snd_cs4231_in(chip, 0x00));
printk(" 0x10: alt 1 (CFIG 2) = 0x%02x\n", snd_cs4231_in(chip, 0x10));
printk(" 0x01: right input = 0x%02x ", snd_cs4231_in(chip, 0x01));
printk(" 0x11: alt 2 (CFIG 3) = 0x%02x\n", snd_cs4231_in(chip, 0x11));
printk(" 0x02: GF1 left input = 0x%02x ", snd_cs4231_in(chip, 0x02));
printk(" 0x12: left line in = 0x%02x\n", snd_cs4231_in(chip, 0x12));
printk(" 0x03: GF1 right input = 0x%02x ", snd_cs4231_in(chip, 0x03));
printk(" 0x13: right line in = 0x%02x\n", snd_cs4231_in(chip, 0x13));
printk(" 0x04: CD left input = 0x%02x ", snd_cs4231_in(chip, 0x04));
printk(" 0x14: timer low = 0x%02x\n", snd_cs4231_in(chip, 0x14));
printk(" 0x05: CD right input = 0x%02x ", snd_cs4231_in(chip, 0x05));
printk(" 0x15: timer high = 0x%02x\n", snd_cs4231_in(chip, 0x15));
printk(" 0x06: left output = 0x%02x ", snd_cs4231_in(chip, 0x06));
printk(" 0x16: left MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x16));
printk(" 0x07: right output = 0x%02x ", snd_cs4231_in(chip, 0x07));
printk(" 0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17));
printk(" 0x08: playback format = 0x%02x ", snd_cs4231_in(chip, 0x08));
printk(" 0x18: IRQ status = 0x%02x\n", snd_cs4231_in(chip, 0x18));
printk(" 0x09: iface (CFIG 1) = 0x%02x ", snd_cs4231_in(chip, 0x09));
printk(" 0x19: left line out = 0x%02x\n", snd_cs4231_in(chip, 0x19));
printk(" 0x0a: pin control = 0x%02x ", snd_cs4231_in(chip, 0x0a));
printk(" 0x1a: mono control = 0x%02x\n", snd_cs4231_in(chip, 0x1a));
printk(" 0x0b: init & status = 0x%02x ", snd_cs4231_in(chip, 0x0b));
printk(" 0x1b: right line out = 0x%02x\n", snd_cs4231_in(chip, 0x1b));
printk(" 0x0c: revision & mode = 0x%02x ", snd_cs4231_in(chip, 0x0c));
printk(" 0x1c: record format = 0x%02x\n", snd_cs4231_in(chip, 0x1c));
printk(" 0x0d: loopback = 0x%02x ", snd_cs4231_in(chip, 0x0d));
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(" 0x1e: rec upr count = 0x%02x\n", snd_cs4231_in(chip, 0x1e));
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));
}
#endif
/*
* CS4231 detection / MCE routines
*/
@ -528,11 +482,12 @@ static void snd_cs4231_busy_wait(cs4231_t *chip)
/* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
for (timeout = 5; timeout > 0; timeout--)
__cs4231_readb(chip, CS4231P(chip, REGSEL));
/* end of cleanup sequence */
for (timeout = 250;
for (timeout = 500;
timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
timeout--)
udelay(100);
udelay(1000);
}
static void snd_cs4231_mce_up(cs4231_t *chip)
@ -545,12 +500,12 @@ static void snd_cs4231_mce_up(cs4231_t *chip)
udelay(100);
#ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
snd_printk("mce_up - auto calibration time out (0)\n");
snd_printdd("mce_up - auto calibration time out (0)\n");
#endif
chip->mce_bit |= CS4231_MCE;
timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
if (timeout == 0x80)
snd_printk("mce_up [%p]: serious init problem - codec still busy\n", chip->port);
snd_printdd("mce_up [%p]: serious init problem - codec still busy\n", chip->port);
if (!(timeout & CS4231_MCE))
__cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
spin_unlock_irqrestore(&chip->lock, flags);
@ -563,18 +518,15 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
spin_lock_irqsave(&chip->lock, flags);
snd_cs4231_busy_wait(chip);
#if 0
printk("(1) timeout = %i\n", timeout);
#endif
#ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
snd_printk("mce_down [%p] - auto calibration time out (0)\n", CS4231P(chip, REGSEL));
snd_printdd("mce_down [%p] - auto calibration time out (0)\n", CS4231P(chip, REGSEL));
#endif
chip->mce_bit &= ~CS4231_MCE;
timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
__cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
if (timeout == 0x80)
snd_printk("mce_down [%p]: serious init problem - codec still busy\n", chip->port);
snd_printdd("mce_down [%p]: serious init problem - codec still busy\n", chip->port);
if ((timeout & CS4231_MCE) == 0) {
spin_unlock_irqrestore(&chip->lock, flags);
return;
@ -590,9 +542,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
spin_unlock_irqrestore(&chip->lock, flags);
return;
}
#if 0
printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);
#endif
/* in 10ms increments, check condition, up to 250ms */
timeout = 25;
while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) {
@ -604,9 +554,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
msleep(10);
spin_lock_irqsave(&chip->lock, flags);
}
#if 0
printk("(3) jiffies = %li\n", jiffies);
#endif
/* in 10ms increments, check condition, up to 100ms */
timeout = 10;
while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) {
@ -619,54 +567,58 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
spin_lock_irqsave(&chip->lock, flags);
}
spin_unlock_irqrestore(&chip->lock, flags);
#if 0
printk("(4) jiffies = %li\n", jiffies);
snd_printk("mce_down - exit = 0x%x\n", __cs4231_readb(chip, CS4231P(chip, REGSEL)));
#endif
}
#if 0 /* Unused for now... */
static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size)
{
switch (format & 0xe0) {
case CS4231_LINEAR_16:
case CS4231_LINEAR_16_BIG:
size >>= 1;
break;
case CS4231_ADPCM_16:
return size >> 2;
}
if (format & CS4231_STEREO)
size >>= 1;
return size;
}
#endif
#ifdef EBUS_SUPPORT
static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent)
{
snd_pcm_runtime_t *runtime = substream->runtime;
while (1) {
unsigned int dma_size = snd_pcm_lib_period_bytes(substream);
unsigned int offset = dma_size * (*periods_sent);
unsigned int period_size = snd_pcm_lib_period_bytes(substream);
unsigned int offset = period_size * (*periods_sent);
if (dma_size >= (1 << 24))
if (period_size >= (1 << 24))
BUG();
if (ebus_dma_request(p, runtime->dma_addr + offset, dma_size))
if (ebus_dma_request(p, runtime->dma_addr + offset, period_size))
return;
#if 0
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 SBUS_SUPPORT
static void snd_cs4231_sbus_advance_dma(snd_pcm_substream_t *substream, unsigned int *periods_sent)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned int period_size = snd_pcm_lib_period_bytes(substream);
unsigned int offset = period_size * (*periods_sent % runtime->periods);
if (runtime->period_size > 0xffff + 1)
BUG();
switch (substream->stream) {
case SNDRV_PCM_STREAM_PLAYBACK:
sbus_writel(runtime->dma_addr + offset, chip->port + APCPNVA);
sbus_writel(period_size, chip->port + APCPNC);
break;
case SNDRV_PCM_STREAM_CAPTURE:
sbus_writel(runtime->dma_addr + offset, chip->port + APCCNVA);
sbus_writel(period_size, chip->port + APCCNC);
break;
}
(*periods_sent) = (*periods_sent + 1) % runtime->periods;
}
#endif
static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what, int on)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
if (what & CS4231_PLAYBACK_ENABLE) {
@ -694,6 +646,60 @@ static void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on)
} else {
#endif
#ifdef SBUS_SUPPORT
u32 csr = sbus_readl(chip->port + APCCSR);
/* I don't know why, but on sbus the period counter must
* only start counting after the first period is sent.
* Therefore this dummy thing.
*/
unsigned int dummy = 0;
switch (what) {
case CS4231_PLAYBACK_ENABLE:
if (on) {
csr &= ~APC_XINT_PLAY;
sbus_writel(csr, chip->port + APCCSR);
csr &= ~APC_PPAUSE;
sbus_writel(csr, chip->port + APCCSR);
snd_cs4231_sbus_advance_dma(substream, &dummy);
csr |= APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL |
APC_XINT_PENA | APC_PDMA_READY;
sbus_writel(csr, chip->port + APCCSR);
} else {
csr |= APC_PPAUSE;
sbus_writel(csr, chip->port + APCCSR);
csr &= ~APC_PDMA_READY;
sbus_writel(csr, chip->port + APCCSR);
}
break;
case CS4231_RECORD_ENABLE:
if (on) {
csr &= ~APC_XINT_CAPT;
sbus_writel(csr, chip->port + APCCSR);
csr &= ~APC_CPAUSE;
sbus_writel(csr, chip->port + APCCSR);
snd_cs4231_sbus_advance_dma(substream, &dummy);
csr |= APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL |
APC_CDMA_READY;
sbus_writel(csr, chip->port + APCCSR);
} else {
csr |= APC_CPAUSE;
sbus_writel(csr, chip->port + APCCSR);
csr &= ~APC_CDMA_READY;
sbus_writel(csr, chip->port + APCCSR);
}
break;
}
#endif
#ifdef EBUS_SUPPORT
}
@ -725,25 +731,12 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
}
}
#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);
cs4231_dma_trigger(substream, what, 1);
chip->image[CS4231_IFACE_CTRL] |= what;
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);
cs4231_dma_trigger(substream, what, 0);
chip->image[CS4231_IFACE_CTRL] &= ~what;
}
snd_cs4231_out(chip, CS4231_IFACE_CTRL,
@ -755,9 +748,7 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
result = -EINVAL;
break;
}
#if 0
snd_cs4231_debug(chip);
#endif
return result;
}
@ -790,9 +781,6 @@ static unsigned char snd_cs4231_get_format(cs4231_t *chip, int format, int chann
}
if (channels > 1)
rformat |= CS4231_STEREO;
#if 0
snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
#endif
return rformat;
}
@ -944,7 +932,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
snd_printk("init: (1)\n");
snd_printdd("init: (1)\n");
#endif
snd_cs4231_mce_up(chip);
spin_lock_irqsave(&chip->lock, flags);
@ -957,7 +945,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
snd_printk("init: (2)\n");
snd_printdd("init: (2)\n");
#endif
snd_cs4231_mce_up(chip);
@ -967,7 +955,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
snd_printdd("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
#endif
spin_lock_irqsave(&chip->lock, flags);
@ -981,7 +969,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
snd_printk("init: (4)\n");
snd_printdd("init: (4)\n");
#endif
snd_cs4231_mce_up(chip);
@ -991,7 +979,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
snd_printk("init: (5)\n");
snd_printdd("init: (5)\n");
#endif
}
@ -1022,6 +1010,7 @@ static int snd_cs4231_open(cs4231_t *chip, unsigned int mode)
CS4231_RECORD_IRQ |
CS4231_TIMER_IRQ);
snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
spin_unlock_irqrestore(&chip->lock, flags);
chip->mode = mode;
@ -1136,11 +1125,21 @@ static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream)
static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
CS4231_PLAYBACK_PIO);
if (runtime->period_size > 0xffff + 1)
BUG();
snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
chip->p_periods_sent = 0;
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
@ -1172,12 +1171,16 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream)
static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
CS4231_RECORD_PIO);
snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
@ -1196,53 +1199,61 @@ static void snd_cs4231_overrange(cs4231_t *chip)
chip->capture_substream->runtime->overrange++;
}
static void snd_cs4231_generic_interrupt(cs4231_t *chip)
static irqreturn_t snd_cs4231_generic_interrupt(cs4231_t *chip)
{
unsigned long flags;
unsigned char status;
/*This is IRQ is not raised by the cs4231*/
if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ))
return IRQ_NONE;
status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
if (!status)
return;
if (status & CS4231_TIMER_IRQ) {
if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
}
if (status & CS4231_PLAYBACK_IRQ)
snd_pcm_period_elapsed(chip->playback_substream);
if (status & CS4231_RECORD_IRQ) {
if (status & CS4231_RECORD_IRQ)
snd_cs4231_overrange(chip);
snd_pcm_period_elapsed(chip->capture_substream);
}
/* ACK the CS4231 interrupt. */
spin_lock_irqsave(&chip->lock, flags);
snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
#ifdef SBUS_SUPPORT
static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
cs4231_t *chip = dev_id;
u32 csr;
csr = sbus_readl(chip->port + APCCSR);
if (!(csr & (APC_INT_PENDING |
APC_PLAY_INT |
APC_CAPT_INT |
APC_GENL_INT |
APC_XINT_PEMP |
APC_XINT_CEMP)))
return IRQ_NONE;
/* ACK the APC interrupt. */
u32 csr = sbus_readl(chip->port + APCCSR);
sbus_writel(csr, chip->port + APCCSR);
snd_cs4231_generic_interrupt(chip);
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) &&
(csr & APC_PLAY_INT) &&
(csr & APC_XINT_PNVA) &&
!(csr & APC_XINT_EMPT)) {
snd_cs4231_sbus_advance_dma(chip->playback_substream,
&chip->p_periods_sent);
snd_pcm_period_elapsed(chip->playback_substream);
}
return IRQ_HANDLED;
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) &&
(csr & APC_CAPT_INT) &&
(csr & APC_XINT_CNVA)) {
snd_cs4231_sbus_advance_dma(chip->capture_substream,
&chip->c_periods_sent);
snd_pcm_period_elapsed(chip->capture_substream);
}
return snd_cs4231_generic_interrupt(chip);
}
#endif
@ -1290,7 +1301,8 @@ static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substr
#ifdef EBUS_SUPPORT
}
#endif
ptr += (period_bytes - residue);
ptr += period_bytes - residue;
return bytes_to_frames(substream->runtime, ptr);
}
@ -1314,7 +1326,7 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substr
#ifdef EBUS_SUPPORT
}
#endif
ptr += (period_bytes - residue);
ptr += period_bytes - residue;
return bytes_to_frames(substream->runtime, ptr);
}
@ -1328,9 +1340,6 @@ static int snd_cs4231_probe(cs4231_t *chip)
int i, id, vers;
unsigned char *ptr;
#if 0
snd_cs4231_debug(chip);
#endif
id = vers = 0;
for (i = 0; i < 50; i++) {
mb();
@ -1985,13 +1994,13 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card,
chip->port = sbus_ioremap(&sdev->resource[0], 0,
chip->regs_size, "cs4231");
if (!chip->port) {
snd_printk("cs4231-%d: Unable to map chip registers.\n", dev);
snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
return -EIO;
}
if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
SA_SHIRQ, "cs4231", chip)) {
snd_printk("cs4231-%d: Unable to grab SBUS IRQ %s\n",
snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n",
dev,
__irq_itoa(sdev->irqs[0]));
snd_cs4231_sbus_free(chip);
@ -2113,29 +2122,29 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card,
chip->eb2c.regs = ioremap(edev->resource[2].start, 0x10);
if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) {
snd_cs4231_ebus_free(chip);
snd_printk("cs4231-%d: Unable to map chip registers.\n", dev);
snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
return -EIO;
}
if (ebus_dma_register(&chip->eb2c)) {
snd_cs4231_ebus_free(chip);
snd_printk("cs4231-%d: Unable to register EBUS capture DMA\n", dev);
snd_printdd("cs4231-%d: Unable to register EBUS capture DMA\n", dev);
return -EBUSY;
}
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);
snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev);
return -EBUSY;
}
if (ebus_dma_register(&chip->eb2p)) {
snd_cs4231_ebus_free(chip);
snd_printk("cs4231-%d: Unable to register EBUS play DMA\n", dev);
snd_printdd("cs4231-%d: Unable to register EBUS play DMA\n", dev);
return -EBUSY;
}
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);
snd_printdd("cs4231-%d: Unable to enable EBUS play IRQ\n", dev);
return -EBUSY;
}