diff -Nur linux-2.6.16.11/arch/avr32/avr32b/entry-irq.S linux-2.6.16.11-avr32-20060626/arch/avr32/avr32b/entry-irq.S --- linux-2.6.16.11/arch/avr32/avr32b/entry-irq.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/avr32b/entry-irq.S 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * Low-level interrupt handler code. + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define __MASK(x) ((1 << (x)) - 1) +#define IRQ_MASK ((__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) | \ + (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)) + + .set rsr_int0, SYSREG_RSR_INT0 + .set rsr_int1, SYSREG_RSR_INT1 + .set rsr_int2, SYSREG_RSR_INT2 + .set rsr_int3, SYSREG_RSR_INT3 + .set rar_int0, SYSREG_RAR_INT0 + .set rar_int1, SYSREG_RAR_INT1 + .set rar_int2, SYSREG_RAR_INT2 + .set rar_int3, SYSREG_RAR_INT3 + + .macro IRQ_LEVEL level + .type irq_level\level, @function +irq_level\level: + stmts --sp,r0-lr + mfsr r8, rar_int\level + mfsr r9, rsr_int\level + pushm r8-r9 + + mov r11, sp + mov r12, \level + +#ifdef CONFIG_FRAME_POINTER + stm --sp,r7,r8 + mov r7, sp +#endif + + rcall do_IRQ + + /* Check for pending softirqs */ + mask_interrupts + get_thread_info r8 + ld.w r9, r8[TI_flags] + bld r9, TIF_SOFTIRQ + brcs process_softirqs + + /* + * Other kinds of work can only be performed before returning + * to application mode. This will change when preempt is + * implemented, though. + */ + mfsr r10, rsr_int\level + andh r10, hi(MODE_MASK), COH + breq 2f + +1: +#ifdef CONFIG_FRAME_POINTER + sub sp, -8 +#endif + popm r8-r9 + mtsr rar_int\level, r8 + mtsr rsr_int\level, r9 + ldmts sp++,r0-lr + + rete + +2: rcall irq_do_pending_work + rjmp 1b + .endm + + .section .irq.text,"ax",@progbits + + .global irq_level0 + .global irq_level1 + .global irq_level2 + .global irq_level3 + IRQ_LEVEL 0 + IRQ_LEVEL 1 + IRQ_LEVEL 2 + IRQ_LEVEL 3 + +process_softirqs: + cbr r9, TIF_SOFTIRQ + st.w r8[TI_flags], r9 + + /* + * Switch to interrupt level 0 mode. Saved registers, RSR and + * RAR stay on the stack. GM is cleared later. + * + * We might potentially lose all registers here... + */ + mov r8, 0 + orh r8, hi(SYSREG_BIT(GM) | SYSREG_BIT(M1)) + mtsr SYSREG_SR, r8 + + /* Flush the pipeline to ensure register file consistency */ + sub pc, -2 + + /* + * do_softirq() usually checks if there are any pending + * softirqs, but we shouldn't get here if there aren't... + */ + rcall __do_softirq + + /* + * If we're returning to application mode, check if there are + * pending work to do. + */ + mfsr r10, SYSREG_RSR_INT0 + andh r10, hi(MODE_MASK), COH + brne 1f + + rcall irq_do_pending_work + +1: +#ifdef CONFIG_FRAME_POINTER + sub sp, -8 +#endif + popm r8-r9 + mtsr SYSREG_RAR_INT0, r8 + mtsr SYSREG_RSR_INT0, r9 + ldmts sp++,r0-lr + + rete + + +irq_do_pending_work: + pushm lr + + get_thread_info r0 + + /* Now, check pending work */ +1: ld.w r1, r0[TI_flags] + bld r1, TIF_NEED_RESCHED + brcc 2f + unmask_interrupts + rcall schedule + mask_interrupts + rjmp 1b +2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK + tst r1, r2 + breq 3f + unmask_interrupts +#ifdef CONFIG_FRAME_POINTER + sub r12, sp, -12 +#else + sub r12, sp, -4 /* we push LR above */ +#endif + mov r11, r0 + rcall do_notify_resume + mask_interrupts + rjmp 1b +3: bld r1, TIF_BREAKPOINT + brcc 4f + mfsr r3, SYSREG_TLBEHI + lddsp r2, sp[REG_PC + 4] + andl r3, 0xff, COH + lsl r3, 1 + sbr r3, 30 + sbr r3, 0 + mtdr DBGREG_BWA2A, r2 + mtdr DBGREG_BWC2A, r3 + +4: popm pc + + .align 2 +irq_stat_addr: + .long irq_stat diff -Nur linux-2.6.16.11/arch/avr32/avr32b/entry.S linux-2.6.16.11-avr32-20060626/arch/avr32/avr32b/entry.S --- linux-2.6.16.11/arch/avr32/avr32b/entry.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/avr32b/entry.S 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,581 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This file contains the low-level entry-points into the kernel, that is, + * exception handlers, debug trap handlers and the system call handler. + * + * The low-level interrupt handling code is in entry-irq.S. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef RETS_WORKAROUND + +#ifdef CONFIG_PREEMPT +# define preempt_stop mask_interrupts +#else +# define preempt_stop +# define fault_resume_kernel fault_restore_all +#endif + + .section .ex.text,"ax",@progbits + .align 2 +exception_vectors: + bral handle_critical + .align 2 + bral handle_critical + .align 2 + bral do_bus_error_write + .align 2 + bral do_bus_error_read + .align 2 + bral do_nmi_ll + .align 2 + bral handle_address_fault + .align 2 + bral handle_protection_fault + .align 2 + bral handle_debug + .align 2 + bral do_illegal_opcode_ll + .align 2 + bral do_illegal_opcode_ll + .align 2 + bral do_illegal_opcode_ll + .align 2 + bral do_fpe_ll + .align 2 + bral do_illegal_opcode_ll + .align 2 + bral handle_address_fault + .align 2 + bral handle_address_fault + .align 2 + bral handle_protection_fault + .align 2 + bral handle_protection_fault + .align 2 + bral do_dtlb_modified + + /* + * r0 : PGD/PT/PTE + * r1 : Offending address + * r2 : Scratch register + * r3 : Cause (5, 12 or 13) + */ +#define tlbmiss_save pushm r0-r3 +#define tlbmiss_restore popm r0-r3 + + .section .tlbx.ex.text,"ax",@progbits + .global itlb_miss +itlb_miss: + tlbmiss_save + rjmp tlb_miss_common + + .section .tlbr.ex.text,"ax",@progbits +dtlb_miss_read: + tlbmiss_save + rjmp tlb_miss_common + + .section .tlbw.ex.text,"ax",@progbits +dtlb_miss_write: + tlbmiss_save + + .global tlb_miss_common +tlb_miss_common: + mfsr r0, SYSREG_PTBR + mfsr r1, SYSREG_TLBEAR + + /* Is it the vmalloc space? */ + bld r1, 31 + brcs handle_vmalloc_miss + + /* First level lookup */ +pgtbl_lookup: + lsr r2, r1, PGDIR_SHIFT + ld.w r0, r0[r2 << 2] + bld r0, _PAGE_BIT_PRESENT + brcc page_table_not_present + + /* TODO: Check access rights on page table if necessary */ + + /* Translate to virtual address in P1. */ + andl r0, 0xf000 + sbr r0, 31 + + /* Second level lookup */ + lsl r1, (32 - PGDIR_SHIFT) + lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT + add r2, r0, r1 << 2 + ld.w r1, r2[0] + bld r1, _PAGE_BIT_PRESENT + brcc page_not_present + + /* Mark the page as accessed */ + sbr r1, _PAGE_BIT_ACCESSED + st.w r2[0], r1 + + /* Drop software flags */ + andl r1, _PAGE_FLAGS_HARDWARE_MASK & 0xffff + mtsr SYSREG_TLBELO, r1 + + /* Figure out which entry we want to replace */ + mfsr r0, SYSREG_TLBARLO + clz r2, r0 + brcc 1f + mov r1, -1 /* All entries have been accessed, */ + mtsr SYSREG_TLBARLO, r1 /* so reset TLBAR */ + mov r2, 0 /* and start at 0 */ +1: mfsr r1, SYSREG_MMUCR + lsl r2, 14 + andl r1, 0x3fff, COH + or r1, r2 + mtsr SYSREG_MMUCR, r1 + + tlbw + + tlbmiss_restore + rete + +handle_vmalloc_miss: + /* Simply do the lookup in init's page table */ + mov r0, lo(swapper_pg_dir) + orh r0, hi(swapper_pg_dir) + rjmp pgtbl_lookup + + + /* --- System Call --- */ + + .section .scall.text,"ax",@progbits +system_call: + pushm r12 /* r12_orig */ + stmts --sp, r0-lr + zero_fp + mfsr r0, SYSREG_RAR_SUP + mfsr r1, SYSREG_RSR_SUP + stm --sp, r0-r1 + + /* check for syscall tracing */ + get_thread_info r0 + ld.w r1, r0[TI_flags] + bld r1, TIF_SYSCALL_TRACE + brcs syscall_trace_enter + +syscall_trace_cont: + cp.w r8, NR_syscalls + brhs syscall_badsys + + lddpc lr, syscall_table_addr + ld.w lr, lr[r8 << 2] + mov r8, r5 /* 5th argument (6th is pushed by stub) */ + icall lr + + .global syscall_return +syscall_return: + get_thread_info r0 + mask_interrupts /* make sure we don't miss an interrupt + setting need_resched or sigpending + between sampling and the rets */ + + /* Store the return value so that the correct value is loaded below */ + stdsp sp[REG_R12], r12 + + ld.w r1, r0[TI_flags] + andl r1, _TIF_ALLWORK_MASK, COH + brne syscall_exit_work + +syscall_exit_cont: + popm r8-r9 + mtsr SYSREG_RAR_SUP, r8 + mtsr SYSREG_RSR_SUP, r9 + ldmts sp++, r0-lr + sub sp, -4 /* r12_orig */ + rets + + .align 2 +syscall_table_addr: + .long sys_call_table + +syscall_badsys: + mov r12, -ENOSYS + rjmp syscall_return + + .global ret_from_fork +ret_from_fork: + rcall schedule_tail + + /* check for syscall tracing */ + get_thread_info r0 + ld.w r1, r0[TI_flags] + andl r1, _TIF_ALLWORK_MASK, COH + brne syscall_exit_work + rjmp syscall_exit_cont + +syscall_trace_enter: + pushm r8-r12 + rcall syscall_trace + popm r8-r12 + rjmp syscall_trace_cont + +syscall_exit_work: + bld r1, TIF_SYSCALL_TRACE + brcc 1f + unmask_interrupts + rcall syscall_trace + mask_interrupts + ld.w r1, r0[TI_flags] + +1: bld r1, TIF_NEED_RESCHED + brcc 2f + unmask_interrupts + rcall schedule + mask_interrupts + ld.w r1, r0[TI_flags] + rjmp 1b + +2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK + tst r1, r2 + breq 3f + unmask_interrupts + mov r12, sp + mov r11, r0 + rcall do_notify_resume + mask_interrupts + ld.w r1, r0[TI_flags] + rjmp 1b + +3: bld r1, TIF_BREAKPOINT + brcc syscall_exit_cont + mfsr r3, SYSREG_TLBEHI + lddsp r2, sp[REG_PC] + andl r3, 0xff, COH + lsl r3, 1 + sbr r3, 30 + sbr r3, 0 + mtdr DBGREG_BWA2A, r2 + mtdr DBGREG_BWC2A, r3 + rjmp syscall_exit_cont + + + /* The slow path of the TLB miss handler */ +page_table_not_present: +page_not_present: + tlbmiss_restore + sub sp, 4 + stmts --sp, r0-lr + rcall save_full_context_ex + mfsr r12, SYSREG_ECR + mov r11, sp + rcall do_page_fault + rjmp ret_from_exception + + /* This function expects to find offending PC in SYSREG_RAR_EX */ +save_full_context_ex: + mfsr r8, SYSREG_RSR_EX + mov r12, r8 + andh r8, (MODE_MASK >> 16), COH + mfsr r11, SYSREG_RAR_EX + brne 2f + +1: pushm r11, r12 /* PC and SR */ + unmask_exceptions + ret r12 + +2: sub r10, sp, -(FRAME_SIZE_FULL - REG_LR) + stdsp sp[4], r10 /* replace saved SP */ + rjmp 1b + + /* Low-level exception handlers */ +handle_critical: + pushm r12 + pushm r0-r12 + rcall save_full_context_ex + mfsr r12, SYSREG_ECR + mov r11, sp + rcall do_critical_exception + + /* We should never get here... */ +bad_return: + sub r12, pc, (. - 1f) + bral panic + .align 2 +1: .asciz "Return from critical exception!" + + .align 1 +do_bus_error_write: + sub sp, 4 + stmts --sp, r0-lr + rcall save_full_context_ex + mov r11, 1 + rjmp 1f + +do_bus_error_read: + sub sp, 4 + stmts --sp, r0-lr + rcall save_full_context_ex + mov r11, 0 +1: mfsr r12, SYSREG_BEAR + mov r10, sp + rcall do_bus_error + rjmp ret_from_exception + + .align 1 +do_nmi_ll: + sub sp, 4 + stmts --sp, r0-lr + /* FIXME: Make sure RAR_NMI and RSR_NMI are pushed instead of *_EX */ + rcall save_full_context_ex + mfsr r12, SYSREG_ECR + mov r11, sp + rcall do_nmi + rjmp bad_return + +handle_address_fault: + sub sp, 4 + stmts --sp, r0-lr + rcall save_full_context_ex + mfsr r12, SYSREG_ECR + mov r11, sp + rcall do_address_exception + rjmp ret_from_exception + +handle_protection_fault: + sub sp, 4 + stmts --sp, r0-lr + rcall save_full_context_ex + mfsr r12, SYSREG_ECR + mov r11, sp + rcall do_page_fault + rjmp ret_from_exception + + .align 1 +do_illegal_opcode_ll: + sub sp, 4 + stmts --sp, r0-lr + rcall save_full_context_ex + mfsr r12, SYSREG_ECR + mov r11, sp + rcall do_illegal_opcode + rjmp ret_from_exception + +do_dtlb_modified: + pushm r0-r3 + mfsr r1, SYSREG_TLBEAR + mfsr r0, SYSREG_PTBR + lsr r2, r1, PGDIR_SHIFT + ld.w r0, r0[r2 << 2] + lsl r1, (32 - PGDIR_SHIFT) + lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT + + /* Translate to virtual address in P1 */ + andl r0, 0xf000 + sbr r0, 31 + add r2, r0, r1 << 2 + ld.w r3, r2[0] + sbr r3, _PAGE_BIT_DIRTY + mov r0, r3 + st.w r2[0], r3 + + /* The page table is up-to-date. Update the TLB entry as well */ + andl r0, lo(_PAGE_FLAGS_HARDWARE_MASK) + mtsr SYSREG_TLBELO, r0 + + /* MMUCR[DRP] is updated automatically, so let's go... */ + tlbw + + popm r0-r3 + rete + +do_fpe_ll: + sub sp, 4 + stmts --sp, r0-lr + rcall save_full_context_ex + unmask_interrupts + mov r12, 26 + mov r11, sp + rcall do_fpe + rjmp ret_from_exception + +ret_from_exception: + mask_interrupts + lddsp r4, sp[REG_SR] + andh r4, (MODE_MASK >> 16), COH + brne fault_resume_kernel + + get_thread_info r0 + ld.w r1, r0[TI_flags] + andl r1, _TIF_WORK_MASK, COH + brne fault_exit_work + +fault_resume_user: + popm r8-r9 + mask_exceptions + mtsr SYSREG_RAR_EX, r8 + mtsr SYSREG_RSR_EX, r9 + ldmts sp++, r0-lr + sub sp, -4 + rete + +fault_resume_kernel: + /* TODO: prempt */ + popm r8-r9 + mask_exceptions + mfsr r1, SYSREG_SR + mtsr SYSREG_RAR_EX, r8 + mtsr SYSREG_RSR_EX, r9 + popm lr + sub sp, -4 /* ignore SP */ + popm r0-r12 + sub sp, -4 /* ignore r12_orig */ + rete + +fault_exit_work: + bld r1, TIF_NEED_RESCHED + brcc 1f + unmask_interrupts + rcall schedule + mask_interrupts + ld.w r1, r0[TI_flags] + rjmp fault_exit_work + +1: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK + tst r1, r2 + breq 2f + unmask_interrupts + mov r12, sp + mov r11, r0 + rcall do_notify_resume + mask_interrupts + ld.w r1, r0[TI_flags] + rjmp fault_exit_work + +2: bld r1, TIF_BREAKPOINT + brcc fault_resume_user + mfsr r3, SYSREG_TLBEHI + lddsp r2, sp[REG_PC] + andl r3, 0xff, COH + lsl r3, 1 + sbr r3, 30 + sbr r3, 0 + mtdr DBGREG_BWA2A, r2 + mtdr DBGREG_BWC2A, r3 + rjmp fault_resume_user + + /* If we get a debug trap from privileged context we end up here */ +handle_debug_priv: + /* Fix up LR and SP in regs. r11 contains the mode we came from */ + mfsr r8, SYSREG_SR + mov r9, r8 + andh r8, hi(~MODE_MASK) + or r8, r11 + mtsr SYSREG_SR, r8 + sub pc, -2 + stdsp sp[REG_LR], lr + mtsr SYSREG_SR, r9 + sub pc, -2 + sub r10, sp, -FRAME_SIZE_FULL + stdsp sp[REG_SP], r10 + mov r12, sp + rcall do_debug_priv + + /* Now, put everything back */ + ssrf SR_EM_BIT + popm r10, r11 + mtsr SYSREG_RAR_DBG, r10 + mtsr SYSREG_RSR_DBG, r11 + mfsr r8, SYSREG_SR + mov r9, r8 + andh r8, hi(~MODE_MASK) + andh r11, hi(MODE_MASK) + or r8, r11 + mtsr SYSREG_SR, r8 + sub pc, -2 + popm lr + mtsr SYSREG_SR, r9 + sub pc, -2 + sub sp, -4 /* skip SP */ + popm r0-r12 + sub sp, -4 + retd + + /* + * At this point, everything is masked, that is, interrupts, + * exceptions and debugging traps. We might get called from + * interrupt or exception context in some rare cases, but this + * will be taken care of by do_debug(), so we're not going to + * do a 100% correct context save here. + */ +handle_debug: + sub sp, 4 /* r12_orig */ + stmts --sp, r0-lr + mfsr r10, SYSREG_RAR_DBG + mfsr r11, SYSREG_RSR_DBG + unmask_exceptions + pushm r10,r11 + andh r11, (MODE_MASK >> 16), COH + brne handle_debug_priv + + mov r12, sp + rcall do_debug + + lddsp r10, sp[REG_SR] + andh r10, (MODE_MASK >> 16), COH + breq debug_resume_user + +debug_restore_all: + popm r10,r11 + mask_exceptions + mtsr SYSREG_RSR_DBG, r11 + mtsr SYSREG_RAR_DBG, r10 + ldmts sp++, r0-lr + sub sp, -4 + retd + +debug_resume_user: + get_thread_info r0 + mask_interrupts + + ld.w r1, r0[TI_flags] + andl r1, _TIF_DBGWORK_MASK, COH + breq debug_restore_all + +1: bld r1, TIF_NEED_RESCHED + brcc 2f + unmask_interrupts + rcall schedule + mask_interrupts + ld.w r1, r0[TI_flags] + rjmp 1b + +2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK + tst r1, r2 + breq 3f + unmask_interrupts + mov r12, sp + mov r11, r0 + rcall do_notify_resume + mask_interrupts + ld.w r1, r0[TI_flags] + rjmp 1b + +3: bld r1, TIF_SINGLE_STEP + brcc debug_restore_all + mfdr r2, DBGREG_DC + sbr r2, DC_SS_BIT + mtdr DBGREG_DC, r2 + rjmp debug_restore_all diff -Nur linux-2.6.16.11/arch/avr32/avr32b/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/avr32b/Makefile --- linux-2.6.16.11/arch/avr32/avr32b/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/avr32b/Makefile 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,5 @@ +# +# Makefile for the Linux/AVR32 kernel: AVR32B microarchitecture support +# + +obj-y := entry.o entry-irq.o diff -Nur linux-2.6.16.11/arch/avr32/boards/at32stk1000/at32stk1002-devices.c linux-2.6.16.11-avr32-20060626/arch/avr32/boards/at32stk1000/at32stk1002-devices.c --- linux-2.6.16.11/arch/avr32/boards/at32stk1000/at32stk1002-devices.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boards/at32stk1000/at32stk1002-devices.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,584 @@ +/* + * This file was automatically generated from ap7000.xml + * + * MMIO-, interrupt-, PIO- and clock-definitions for all relevant on-chip devices + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* FIXME: Move into Kconfig */ +#define CONFIG_LCDC_DEVICE 1 + +enum clock_domain_id { + CLK_CPU, + CLK_AHB, + CLK_APBA, + CLK_APBB, +}; + +enum pio_function { + PIO_FUNC_A = 0, + PIO_FUNC_B = 1, +}; + +enum pio_id { + PIOA, PIOB, PIOC, PIOD, PIOE, +}; + +enum { + CPUMASK_PICO = 0, + + AHBMASK_EBI = 0, + AHBMASK_APBA, + AHBMASK_APBB, + AHBMASK_HRAMC, + AHBMASK_HTOH, + AHBMASK_ISI, + AHBMASK_USB, + AHBMASK_LCDC, + AHBMASK_MACB0, + AHBMASK_MACB1, + AHBMASK_DMA, + + APBAMASK_SPI0 = 0, + APBAMASK_SPI1, + APBAMASK_TWI, + APBAMASK_USART0, + APBAMASK_USART1, + APBAMASK_USART2, + APBAMASK_USART3, + APBAMASK_SSC0, + APBAMASK_SSC1, + APBAMASK_SSC2, + APBAMASK_PIOA, + APBAMASK_PIOB, + APBAMASK_PIOC, + APBAMASK_PIOD, + APBAMASK_PIOE, + APBAMASK_PIOF, + APBAMASK_PDC, + + APBBMASK_SM = 0, + APBBMASK_INTC, + APBBMASK_HMATRIX, + APBBMASK_TC0, + APBBMASK_TC1, + APBBMASK_PWM, + APBBMASK_MACB0, + APBBMASK_MACB1, + APBBMASK_DAC, + APBBMASK_MCI, + APBBMASK_AC97C, + APBBMASK_ISI, + APBBMASK_USB, + APBBMASK_SMC, + APBBMASK_SDRAMC, + APBBMASK_ECC, +}; + +#define cpu_domain (&chip_domain[CLK_CPU]) +#define ahb_domain (&chip_domain[CLK_AHB]) +#define apba_domain (&chip_domain[CLK_APBA]) +#define apbb_domain (&chip_domain[CLK_APBB]) + +#define PP(pu_en, func, pio_id, index) \ + ((pu_en) << 15 | (func) << 14 | (pio_id) << 5 | (index)) + +#define D(_name, _id, _irq, _pfx) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = _irq, \ + .sclk_count = ARRAY_SIZE(_pfx##_sclk), \ + .sclk = _pfx##_sclk, \ + .num_resources = ARRAY_SIZE(_pfx##_resource), \ + .resource = _pfx##_resource, \ + .dev = { \ + .bus = &at32_bus_type, \ + .bus_id = _name#_id, \ + }, \ + } +#define DP(_name, _id, _irq, _pfx) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = _irq, \ + .sclk_count = ARRAY_SIZE(_pfx##_sclk), \ + .sclk = _pfx##_sclk, \ + .pin_count = ARRAY_SIZE(_pfx##_pin), \ + .pin = _pfx##_pin, \ + .num_resources = ARRAY_SIZE(_pfx##_resource), \ + .resource = _pfx##_resource, \ + .dev = { \ + .bus = &at32_bus_type, \ + .bus_id = _name#_id, \ + }, \ + } +#define DPD(_name, _id, _irq, _pfx) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = _irq, \ + .sclk_count = ARRAY_SIZE(_pfx##_sclk), \ + .sclk = _pfx##_sclk, \ + .pin_count = ARRAY_SIZE(_pfx##_pin), \ + .pin = _pfx##_pin, \ + .num_resources = ARRAY_SIZE(_pfx##_resource), \ + .resource = _pfx##_resource, \ + .dev = { \ + .bus = &at32_bus_type, \ + .bus_id = _name#_id, \ + .platform_data = &_pfx##_platform_data, \ + }, \ + } + +#define APBMEM(base) \ + { \ + .start = base, \ + .end = base + 0x3ff, \ + .flags = IORESOURCE_MEM, \ + } + +#define SCLK_AHB(name) { ahb_domain, AHBMASK_##name } +#define SCLK_APBA(name) { apba_domain, APBAMASK_##name } +#define SCLK_APBB(name) { apbb_domain, APBBMASK_##name } + +struct clock_domain chip_domain[] = { + [CLK_CPU] = { + .lock = SPIN_LOCK_UNLOCKED, + .id = CLK_CPU, + .count = 1, + /* I don't know a better way to enable the PiCo */ + .precious_mask = 1 << CPUMASK_PICO, + }, + [CLK_AHB] = { + .lock = SPIN_LOCK_UNLOCKED, + .id = CLK_AHB, + .count = 1, + /* We don't want to lose our RAM or the power manager */ + .precious_mask = ((1 << AHBMASK_EBI) + | (1 << AHBMASK_APBB) + | (1 << AHBMASK_HRAMC)), + }, + [CLK_APBA] = { + .lock = SPIN_LOCK_UNLOCKED, + .id = CLK_APBA, + .count = 0, + .sclk = SCLK_AHB(APBA), + }, + [CLK_APBB] = { + .lock = SPIN_LOCK_UNLOCKED, + .id = CLK_APBB, + .count = 1, + /* Never disable the power manager */ + .precious_mask = 1 << APBBMASK_SM, + .sclk = SCLK_AHB(APBB), + }, +}; + +const unsigned int nr_chip_domains = ARRAY_SIZE(chip_domain); + +/* + * The USARTs are mapped as follows on the AT32STK1002: + * USART1 -> UART_A + * USART2 -> IrDA + * USART3 -> UART_C + * + * PIOE is not included, as we shouldn't mess with it: it controls the + * SDRAM pins. + */ + +/* Bus clock connections (synchronous clocks) */ +static const struct sync_clock sm_sclk[] = { SCLK_APBB(SM), }; +static const struct sync_clock intc_sclk[] = { SCLK_APBB(INTC), }; +static const struct sync_clock pdc_sclk[] = { + SCLK_AHB(HTOH), + SCLK_APBA(PDC), +}; +static const struct sync_clock pioa_sclk[] = { SCLK_APBA(PIOA), }; +static const struct sync_clock piob_sclk[] = { SCLK_APBA(PIOB), }; +static const struct sync_clock pioc_sclk[] = { SCLK_APBA(PIOC), }; +static const struct sync_clock piod_sclk[] = { SCLK_APBA(PIOD), }; +static const struct sync_clock uarta_sclk[] = { SCLK_APBA(USART1), }; +static const struct sync_clock uartb_sclk[] = { SCLK_APBA(USART2), }; +static const struct sync_clock uartc_sclk[] = { SCLK_APBA(USART3), }; +static const struct sync_clock macb0_sclk[] = { + SCLK_AHB(MACB0), + SCLK_APBB(MACB0), +}; +static const struct sync_clock dmac_sclk[] = { SCLK_AHB(DMA), }; +static const struct sync_clock mci_sclk[] = { SCLK_APBB(MCI), }; +static const struct sync_clock spi0_sclk[] = { SCLK_APBA(SPI0), }; +static const struct sync_clock usb_sclk[] = { + SCLK_AHB(USB), + SCLK_APBB(USB), +}; +static const struct sync_clock dac_sclk[] = { + SCLK_APBB(DAC), +}; +static const struct sync_clock ac97c_sclk[] = { + SCLK_APBB(AC97C), +}; +static const struct sync_clock ssc0_sclk[] = { + SCLK_APBA(SSC0), +}; +static const struct sync_clock extint_sclk[] = { + SCLK_APBB(SM), +}; + +/* Portmux pin configurations */ +static const unsigned short uarta_pin[] = { + PP(0, PIO_FUNC_A, PIOA, 17), /* RXD */ + PP(0, PIO_FUNC_A, PIOA, 18), /* TXD */ +}; +static const unsigned short uartb_pin[] = { + PP(0, PIO_FUNC_B, PIOB, 26), /* RXD */ + PP(0, PIO_FUNC_B, PIOB, 27), /* TXD */ +}; +static const unsigned short uartc_pin[] = { + PP(0, PIO_FUNC_B, PIOB, 18), /* RXD */ + PP(0, PIO_FUNC_B, PIOB, 17), /* TXD */ +}; +static const unsigned short macb0_pin[] = { + PP(0, PIO_FUNC_A, PIOC, 0), /* COL */ + PP(0, PIO_FUNC_A, PIOC, 1), /* CRS */ + PP(0, PIO_FUNC_A, PIOC, 2), /* TX_ER */ + PP(0, PIO_FUNC_A, PIOC, 3), /* TXD[0] */ + PP(0, PIO_FUNC_A, PIOC, 4), /* TXD[1] */ + PP(0, PIO_FUNC_A, PIOC, 5), /* TXD[2] */ + PP(0, PIO_FUNC_A, PIOC, 6), /* TXD[3] */ + PP(0, PIO_FUNC_A, PIOC, 7), /* TX_EN */ + PP(0, PIO_FUNC_A, PIOC, 8), /* TX_CLK */ + PP(0, PIO_FUNC_A, PIOC, 9), /* RXD[0] */ + PP(0, PIO_FUNC_A, PIOC, 10), /* RXD[1] */ + PP(0, PIO_FUNC_A, PIOC, 11), /* RXD[2] */ + PP(0, PIO_FUNC_A, PIOC, 12), /* RXD[3] */ + PP(0, PIO_FUNC_A, PIOC, 13), /* RX_ER */ + PP(0, PIO_FUNC_A, PIOC, 14), /* RX_CLK */ + PP(0, PIO_FUNC_A, PIOC, 15), /* RX_DV */ + PP(0, PIO_FUNC_A, PIOC, 16), /* MDC */ + PP(0, PIO_FUNC_A, PIOC, 17), /* MDIO */ + PP(0, PIO_FUNC_A, PIOC, 18), /* SPEED */ +}; +static const unsigned short mci_pin[] = { + PP(0, PIO_FUNC_A, PIOA, 10), /* CLK */ + PP(0, PIO_FUNC_A, PIOA, 11), /* CMD */ + PP(0, PIO_FUNC_A, PIOA, 12), /* DATA[0] */ + PP(0, PIO_FUNC_A, PIOA, 13), /* DATA[1] */ + PP(0, PIO_FUNC_A, PIOA, 14), /* DATA[2] */ + PP(0, PIO_FUNC_A, PIOA, 15), /* DATA[3] */ +}; +static const unsigned short spi0_pin[] = { + PP(0, PIO_FUNC_A, PIOA, 0), /* MISO */ + PP(0, PIO_FUNC_A, PIOA, 1), /* MOSI */ + PP(0, PIO_FUNC_A, PIOA, 2), /* SCK */ + PP(1, PIO_FUNC_A, PIOA, 3), /* NPCS[0] */ + PP(1, PIO_FUNC_A, PIOA, 4), /* NPCS[1] */ + PP(1, PIO_FUNC_A, PIOA, 5), /* NPCS[2] */ + PP(1, PIO_FUNC_B, PIOA, 20), /* NPCS[3] */ +}; +static const unsigned short dac_pin[] = { + PP(0, PIO_FUNC_A, PIOB, 21), /* DATA[0] */ + PP(0, PIO_FUNC_A, PIOB, 20), /* DATA[1] */ + PP(0, PIO_FUNC_A, PIOB, 23), /* DATAN[0] */ + PP(0, PIO_FUNC_A, PIOB, 22), /* DATAN[1] */ +}; +static const unsigned short ac97c_pin[] = { + PP(0, PIO_FUNC_B, PIOB, 21), /* SDO */ + PP(0, PIO_FUNC_B, PIOB, 20), /* SYNC */ + PP(0, PIO_FUNC_B, PIOB, 23), /* SCLK */ + PP(0, PIO_FUNC_B, PIOB, 22), /* SDI */ +}; +static const unsigned short ssc0_pin[] = { + PP(0, PIO_FUNC_A, PIOA, 21), /* RX_FSYNC */ + PP(0, PIO_FUNC_A, PIOA, 22), /* RX_CLOCK */ + PP(0, PIO_FUNC_A, PIOA, 26), /* RX_DATA */ + PP(0, PIO_FUNC_A, PIOA, 24), /* TX_FSYNC */ + PP(0, PIO_FUNC_A, PIOA, 23), /* TX_CLOCK */ + PP(0, PIO_FUNC_A, PIOA, 25), /* TX_DATA */ +}; +static const unsigned short extint_pin[] = { + PP(1, PIO_FUNC_A, PIOB, 24), /* NMI */ + PP(1, PIO_FUNC_A, PIOB, 25), /* EXTINT0 */ + PP(1, PIO_FUNC_A, PIOB, 26), /* EXTINT1 */ + PP(1, PIO_FUNC_A, PIOB, 27), /* EXTINT2 */ + PP(1, PIO_FUNC_A, PIOB, 28), /* EXTINT3 */ +}; + +/* I/O memory and other resources */ +static const struct resource sm_resource[] = { + APBMEM(0xfff00000), +}; +static const struct resource intc_resource[] = { + APBMEM(0xfff00400), +}; +static const struct resource pioa_resource[] = { + APBMEM(0xffe02800), +}; +static const struct resource piob_resource[] = { + APBMEM(0xffe02c00), +}; +static const struct resource pioc_resource[] = { + APBMEM(0xffe03000), +}; +static const struct resource piod_resource[] = { + APBMEM(0xffe03400), +}; +static struct resource uarta_resource[] = { + APBMEM(0xffe01000), +}; +static struct resource uartb_resource[] = { + APBMEM(0xffe01400), +}; +static struct resource uartc_resource[] = { + APBMEM(0xffe01800), +}; +static struct resource macb0_resource[] = { + APBMEM(0xfff01800), +}; +static struct resource dmac_resource[] = { + { .start = 0xff200000, .end = 0xffe00fff, .flags = IORESOURCE_MEM, }, +}; +static struct resource mci_resource[] = { + APBMEM(0xfff02400), +}; +static struct resource spi0_resource[] = { + APBMEM(0xffe00000), +}; +static struct resource usb_resource[] = { + { .start = 0xff300000, .end = 0xff3fffff, .flags = IORESOURCE_MEM, }, + APBMEM(0xfff03000), +}; +static struct resource dac_resource[] = { + APBMEM(0xfff02000), +}; +static struct resource ac97c_resource[] = { + APBMEM(0xfff02800), +}; +static struct resource ssc0_resource[] = { + APBMEM(0xffe01c00), +}; +static struct resource extint_resource[] = { + APBMEM(0xfff00000), +}; + +/* Platform data */ +static struct eth_platform_data macb0_platform_data; +static struct spi_board_info ssc0_platform_data = { + .max_speed_hz = 200000, + .modalias = "at73c213", + .bus_num = 1, + .chip_select = 0, +}; + +/* Device definitions */ +static struct at32_device sm_device = D("sm", 0, 19, sm); +static struct at32_device intc_device = D("intc", 0, -1, intc); +static struct at32_device pioa_device = D("pio", 0, 13, pioa); +static struct at32_device piob_device = D("pio", 1, 14, piob); +static struct at32_device pioc_device = D("pio", 2, 15, pioc); +static struct at32_device piod_device = D("pio", 3, 16, piod); +static struct at32_device uarta_device = DP("usart", 0, 7, uarta); +static struct at32_device uartb_device = DP("usart", 1, 8, uartb); +static struct at32_device uartc_device = DP("usart", 2, 9, uartc); +static struct at32_device macb0_device = DPD("macb", 0, 25, macb0); +static struct at32_device dmac_device = D("dmac", 0, 2, dmac); +static struct at32_device mci_device = DP("mmci", 0, 28, mci); +static struct at32_device spi0_device = DP("spi", 0, 3, spi0); +static struct at32_device usb_device = D("usb", 0, 31, usb); +static struct at32_device dac_device = DP("dac", 0, 27, dac); +static struct at32_device ac97c_device = DP("ac97c", 0, 29, ac97c); +static struct at32_device ssc0_device = DPD("at73c213", 0, 10, ssc0); +static struct at32_device extint_device = DP("extint", 0, 64, extint); + +static struct at32_device pdc_device = { + .name = "pdc", + .id = 0, + .sclk_count = ARRAY_SIZE(pdc_sclk), + .sclk = pdc_sclk, + .dev = { + .bus = &at32_bus_type, + .bus_id = "pdc", + }, +}; + +/* Conditional stuff */ + +#ifdef CONFIG_MACB1_DEVICE +static const struct sync_clock macb1_sclk[] = { + SCLK_AHB(MACB1), + SCLK_APBB(MACB1), +}; +static const unsigned short macb1_pin[] = { + PP(0, PIO_FUNC_B, PIOC, 19), /* COL */ + PP(0, PIO_FUNC_B, PIOC, 23), /* CRS */ + PP(0, PIO_FUNC_B, PIOC, 26), /* TX_ER */ + PP(0, PIO_FUNC_B, PIOD, 13), /* TXD[0] */ + PP(0, PIO_FUNC_B, PIOD, 14), /* TXD[1] */ + PP(0, PIO_FUNC_B, PIOC, 27), /* TXD[2] */ + PP(0, PIO_FUNC_B, PIOC, 28), /* TXD[3] */ + PP(0, PIO_FUNC_B, PIOD, 11), /* TX_EN */ + PP(0, PIO_FUNC_B, PIOD, 12), /* TX_CLK */ + PP(0, PIO_FUNC_B, PIOD, 10), /* RXD[0] */ + PP(0, PIO_FUNC_B, PIOD, 6), /* RXD[1] */ + PP(0, PIO_FUNC_B, PIOC, 29), /* RXD[2] */ + PP(0, PIO_FUNC_B, PIOC, 30), /* RXD[3] */ + PP(0, PIO_FUNC_B, PIOD, 5), /* RX_ER */ + PP(0, PIO_FUNC_B, PIOC, 24), /* RX_CLK */ + PP(0, PIO_FUNC_B, PIOD, 4), /* RX_DV */ + PP(0, PIO_FUNC_B, PIOD, 3), /* MDC */ + PP(0, PIO_FUNC_B, PIOD, 2), /* MDIO */ + PP(0, PIO_FUNC_B, PIOD, 15), /* SPEED */ +}; +static struct resource macb1_resource[] = { + APBMEM(0xfff01c00), +}; +static struct eth_platform_data macb1_platform_data; +static struct at32_device macb1_device = DPD("macb", 1, 26, macb1); +#endif /* CONFIG_MACB1_DEVICE */ + +#ifdef CONFIG_LCDC_DEVICE +static const struct sync_clock lcdc_sclk[] = { + SCLK_AHB(LCDC), +}; +static const unsigned short lcdc_pin[] = { + PP(0, PIO_FUNC_A, PIOC, 19), /* CC */ + PP(0, PIO_FUNC_A, PIOC, 20), /* HSYNC */ + PP(0, PIO_FUNC_A, PIOC, 21), /* PCLK */ + PP(0, PIO_FUNC_A, PIOC, 22), /* VSYNC */ + PP(0, PIO_FUNC_A, PIOC, 23), /* DVAL */ + PP(0, PIO_FUNC_A, PIOC, 24), /* MODE */ + PP(0, PIO_FUNC_A, PIOC, 25), /* PWR */ + PP(0, PIO_FUNC_A, PIOC, 26), /* DATA[0] */ + PP(0, PIO_FUNC_A, PIOC, 27), /* DATA[1] */ + PP(0, PIO_FUNC_A, PIOC, 28), /* DATA[2] */ + PP(0, PIO_FUNC_A, PIOC, 29), /* DATA[3] */ + PP(0, PIO_FUNC_A, PIOC, 30), /* DATA[4] */ + PP(0, PIO_FUNC_A, PIOC, 31), /* DATA[5] */ + PP(0, PIO_FUNC_A, PIOD, 0), /* DATA[6] */ + PP(0, PIO_FUNC_A, PIOD, 1), /* DATA[7] */ + PP(0, PIO_FUNC_A, PIOD, 2), /* DATA[8] */ + PP(0, PIO_FUNC_A, PIOD, 3), /* DATA[9] */ + PP(0, PIO_FUNC_A, PIOD, 4), /* DATA[10] */ + PP(0, PIO_FUNC_A, PIOD, 5), /* DATA[11] */ + PP(0, PIO_FUNC_A, PIOD, 6), /* DATA[12] */ + PP(0, PIO_FUNC_A, PIOD, 7), /* DATA[13] */ + PP(0, PIO_FUNC_A, PIOD, 8), /* DATA[14] */ + PP(0, PIO_FUNC_A, PIOD, 9), /* DATA[15] */ + PP(0, PIO_FUNC_A, PIOD, 10), /* DATA[16] */ + PP(0, PIO_FUNC_A, PIOD, 11), /* DATA[17] */ + PP(0, PIO_FUNC_A, PIOD, 12), /* DATA[18] */ + PP(0, PIO_FUNC_A, PIOD, 13), /* DATA[19] */ + PP(0, PIO_FUNC_A, PIOD, 14), /* DATA[20] */ + PP(0, PIO_FUNC_A, PIOD, 15), /* DATA[21] */ + PP(0, PIO_FUNC_A, PIOD, 16), /* DATA[22] */ + PP(0, PIO_FUNC_A, PIOD, 17), /* DATA[23] */ +}; +static struct resource lcdc_resource[] = { + { .start = 0xff000000, .end = 0xff000fff, .flags = IORESOURCE_MEM }, +}; +static struct at32_device lcdc_device = DP("lcdc", 0, 1, lcdc); +#endif /* CONFIG_LCDC_DEVICE */ + +static struct at32_device *board_devices[] __initdata = { + &sm_device, + &pioa_device, + &piob_device, + &pioc_device, + &piod_device, + &uarta_device, +// &uartb_device, + &uartc_device, + &macb0_device, + &dmac_device, + &pdc_device, + &mci_device, + &spi0_device, + &usb_device, + &dac_device, + &ac97c_device, + &ssc0_device, + &extint_device, +#ifdef CONFIG_MACB1_DEVICE + &macb1_device, +#endif +#ifdef CONFIG_LCDC_DEVICE + &lcdc_device, +#endif +}; + +struct intc_device intc = { + .adev = &intc_device, + .irqs_per_group = 32, + .nr_groups = 33, +}; + +static int __init register_devices(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(board_devices); i++) + device_register(&board_devices[i]->dev); + + return 0; +} +postcore_initcall(register_devices); + +unsigned int __init at32_count_devices(const char *name) +{ + unsigned int count = 0; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(board_devices); i++) + if (!strcmp(board_devices[i]->name, name)) + count++; + + return count; +} + +struct at32_device * __init at32_find_device(const char *name, unsigned int id) +{ + struct at32_device *adev; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(board_devices); i++) { + adev = board_devices[i]; + + if (adev->id == id && !strcmp(adev->name, name)) + return adev; + } + + return NULL; +} + +void platform_init_clock_domain(unsigned int clock_id, + unsigned long long clock_hz) +{ + switch (clock_id) { + case CLOCK_BOOTCPU: + cpu_domain->hz = clock_hz; + break; + default: + /* TODO: Get more fine-grained parameters from u-boot */ + ahb_domain->hz = clock_hz; + apba_domain->hz = clock_hz / 2; + apbb_domain->hz = clock_hz; + break; + } +} diff -Nur linux-2.6.16.11/arch/avr32/boards/at32stk1000/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/boards/at32stk1000/Makefile --- linux-2.6.16.11/arch/avr32/boards/at32stk1000/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boards/at32stk1000/Makefile 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,2 @@ +obj-y += setup.o spi.o +obj-$(CONFIG_BOARD_AT32STK1002) += at32stk1002-devices.o diff -Nur linux-2.6.16.11/arch/avr32/boards/at32stk1000/setup.c linux-2.6.16.11-avr32-20060626/arch/avr32/boards/at32stk1000/setup.c --- linux-2.6.16.11/arch/avr32/boards/at32stk1000/setup.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boards/at32stk1000/setup.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,68 @@ +/* + * AT32STK1000 board-specific setup code. + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* Initialized by bootloader-specific startup code. */ +struct tag *bootloader_tags __initdata; + +static struct fb_platform_data fb_data; + +asmlinkage void __init board_early_init(void) +{ + extern void sdram_init(void); + +#ifdef CONFIG_LOADER_STANDALONE + sdram_init(); +#endif +} + +void __init board_setup_fbmem(unsigned long fbmem_start, + unsigned long fbmem_size) +{ + struct at32_device *lcdc; + + if (!fbmem_size) + return; + + lcdc = at32_find_device("lcdc", 0); + if (!lcdc) + return; + + if (!fbmem_start) { + void *fbmem; + + fbmem = alloc_bootmem_low_pages(fbmem_size); + fbmem_start = __pa(fbmem); + } else { + pg_data_t *pgdat; + + for_each_pgdat(pgdat) { + if (fbmem_start >= pgdat->bdata->node_boot_start + && fbmem_start <= pgdat->bdata->node_low_pfn) + reserve_bootmem_node(pgdat, fbmem_start, + fbmem_size); + } + } + + printk("%luKiB framebuffer memory at address 0x%08lx\n", + fbmem_size >> 10, fbmem_start); + fb_data.fbmem_start = fbmem_start; + fb_data.fbmem_size = fbmem_size; + lcdc->dev.platform_data = &fb_data; +} diff -Nur linux-2.6.16.11/arch/avr32/boards/at32stk1000/spi.c linux-2.6.16.11-avr32-20060626/arch/avr32/boards/at32stk1000/spi.c --- linux-2.6.16.11/arch/avr32/boards/at32stk1000/spi.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boards/at32stk1000/spi.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,28 @@ +/* + * ATSTK1000 SPI devices + * + * Copyright (C) 2005 Atmel Norway + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +static struct spi_board_info spi_board_info[] __initdata = { + { + .modalias = "ltv350qv", + .max_speed_hz = 16000000, + .bus_num = 1, /* really spi0 */ + .chip_select = 1, + }, +}; + +static int board_init_spi(void) +{ + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); + return 0; +} +arch_initcall(board_init_spi); diff -Nur linux-2.6.16.11/arch/avr32/boot/images/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/boot/images/Makefile --- linux-2.6.16.11/arch/avr32/boot/images/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boot/images/Makefile 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,62 @@ +# +# Copyright (C) 2004-2006 Atmel Corporation +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +MKIMAGE := $(srctree)/scripts/mkuboot.sh + +extra-y := vmlinux.bin vmlinux.gz + +OBJCOPYFLAGS_vmlinux.bin := -O binary +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +quiet_cmd_uimage = UIMAGE $@ + cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A avr32 -O linux -T kernel \ + -C gzip -a $(CONFIG_LOAD_ADDRESS) -e $(CONFIG_ENTRY_ADDRESS) \ + -n 'Linux-$(KERNELRELEASE)' -d $< $@ + +targets += uImage uImage.srec +$(obj)/uImage: $(obj)/vmlinux.gz + $(call if_changed,uimage) + @echo ' Image $@ is ready' + +OBJCOPYFLAGS_uImage.srec := -I binary -O srec +$(obj)/uImage.srec: $(obj)/uImage + $(call if_changed,objcopy) + +OBJCOPYFLAGS_vmlinux.elf := --change-section-lma .text-0x80000000 \ + --change-section-lma __ex_table-0x80000000 \ + --change-section-lma .rodata-0x80000000 \ + --change-section-lma .data-0x80000000 \ + --change-section-lma .init-0x80000000 \ + --change-section-lma .bss-0x80000000 \ + --change-section-lma .initrd-0x80000000 \ + --change-section-lma __param-0x80000000 \ + --change-section-lma __ksymtab-0x80000000 \ + --change-section-lma __ksymtab_gpl-0x80000000 \ + --change-section-lma __kcrctab-0x80000000 \ + --change-section-lma __kcrctab_gpl-0x80000000 \ + --change-section-lma __ksymtab_strings-0x80000000 \ + --change-section-lma .got-0x80000000 \ + --set-start 0xa0000000 +$(obj)/vmlinux.elf: vmlinux FORCE + $(call if_changed,objcopy) + +quiet_cmd_sfdwarf = SFDWARF $@ + cmd_sfdwarf = sfdwarf $< TO $@ GNUAVR IW $(SFDWARF_FLAGS) > $(obj)/sfdwarf.log + +$(obj)/vmlinux.cso: $(obj)/vmlinux.elf FORCE + $(call if_changed,sfdwarf) + +install: $(BOOTIMAGE) + sh $(srctree)/install-kernel.sh $< + +# Generated files to be removed upon make clean +clean-files := vmlinux* uImage uImage.srec diff -Nur linux-2.6.16.11/arch/avr32/boot/standalone/board-config.h linux-2.6.16.11-avr32-20060626/arch/avr32/boot/standalone/board-config.h --- linux-2.6.16.11/arch/avr32/boot/standalone/board-config.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boot/standalone/board-config.h 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,21 @@ +#ifndef __AVR32_STANDALONE_BOARD_CONFIG_H +#define __AVR32_STANDALONE_BOARD_CONFIG_H + +#include + +#if defined(CONFIG_CPU_AP7000x) +# define SDRAM_START 0x10000000 +# define SDRAM_SIZE 0x00800000 +# define TWI_BASE 0xffe00800 +# define HMATRIX_BASE 0xfff00800 +# define SDRAMC_BASE 0xfff03800 +#endif + +#if defined(CONFIG_PLATFORM_ATSTK1000x) +# define CPU_HZ 27000000 +# define BUS_HZ CPU_HZ +#else +# error Board-specific definitions missing +#endif + +#endif /* __AVR32_STANDALONE_BOOT_CONFIG_H */ diff -Nur linux-2.6.16.11/arch/avr32/boot/standalone/head.S linux-2.6.16.11-avr32-20060626/arch/avr32/boot/standalone/head.S --- linux-2.6.16.11/arch/avr32/boot/standalone/head.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boot/standalone/head.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Startup code for use when the kernel is loaded by an external + * debugger or something similar. + */ +#include +#include + + /* + * Standalone operation means that we're running from the + * reset vector (virtual 0xa0000000, physical 0x00000000). + */ + .section .init.text,"ax" + .global _start +_start: + /* Flush all caches and make sure the MMU is sane */ + mov r0, 0 + cache r0[4], 8 /* DCACHE clean/invalidate all */ + cache r0[0], 0 /* ICACHE flush all */ + sync 0 /* Flush write buffer */ + mov r0, 0x14 /* Segmentation on, paging off, invalidate */ + mtsr SYSREG_MMUCR, r0 + + lddpc pc, 1f /* Jump to cached memory */ + + .align 2 +1: .long cached_start + +cached_start: + /* TODO: Copy data sections so that we can survive a reboot */ + + lddpc r0, fake_tags_addr + lddpc r1, bootloader_tags_addr + st.w r1[0], r0 + + /* Initialize .bss */ + lddpc r2, bss_start_addr + lddpc r3, end_addr + mov r0, 0 + mov r1, 0 +2: st.d r2++, r0 + cp r2, r3 + brlo 2b + + /* Jump to loader-independent setup code */ + rjmp kernel_entry + + .align 2 +fake_tags_addr: + .long fake_bootloader_tags +bootloader_tags_addr: + .long bootloader_tags +bss_start_addr: + .long __bss_start +end_addr: + .long _end diff -Nur linux-2.6.16.11/arch/avr32/boot/standalone/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/boot/standalone/Makefile --- linux-2.6.16.11/arch/avr32/boot/standalone/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boot/standalone/Makefile 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,3 @@ +extra-y := head.o + +obj-y := tags.o diff -Nur linux-2.6.16.11/arch/avr32/boot/standalone/tags.c linux-2.6.16.11-avr32-20060626/arch/avr32/boot/standalone/tags.c --- linux-2.6.16.11/arch/avr32/boot/standalone/tags.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boot/standalone/tags.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include + +#include "board-config.h" + +extern char __initrd_start_phys, __initrd_size; + +struct init_tags { + struct tag_header hdr_core; + struct tag_core core; +#if !defined(CONFIG_SDRAM) || !defined(CONFIG_FLATMEM) + struct tag_header hdr_mem1; + struct tag_mem_range mem1; +#endif +#ifdef CONFIG_SDRAM + struct tag_header hdr_mem2; + struct tag_mem_range mem2; +#endif + struct tag_header hdr_cmdline; + char cmdline[COMMAND_LINE_SIZE]; +#ifdef CONFIG_BLK_DEV_INITRD + struct tag_header hdr_ramdisk; + struct tag_mem_range ramdisk; +#endif + struct tag_header hdr_cpuclock; + struct tag_clock cpuclock; + struct tag_header hdr_busclock; + struct tag_clock busclock; + struct tag_header hdr_end; +} fake_bootloader_tags __initdata = { + { tag_size(tag_core), ATAG_CORE }, + { 1, PAGE_SIZE, 0xff }, +#if !defined(CONFIG_SDRAM) || !defined(CONFIG_FLATMEM) + { tag_size(tag_mem_range), ATAG_MEM }, + { 0x00000000, 0x00200000, (void *)0xdeadbeef }, +#endif +#ifdef CONFIG_SDRAM + { tag_size(tag_mem_range), ATAG_MEM }, + { SDRAM_START, SDRAM_SIZE, (void *)0xdeadbeef }, +#endif + { COMMAND_LINE_SIZE / 4 + sizeof(struct tag_header) / 4, + ATAG_CMDLINE }, + { CONFIG_CMDLINE }, +#ifdef CONFIG_BLK_DEV_INITRD + { tag_size(tag_mem_range), ATAG_RDIMG }, + { (unsigned long)&__initrd_start_phys, + (unsigned long)&__initrd_size, + (void *)0xdeadbeef }, +#endif + { tag_size(tag_clock), ATAG_CLOCK }, + { CLOCK_BOOTCPU, 0, CPU_HZ }, + { tag_size(tag_clock), ATAG_CLOCK }, + { CLOCK_AMBA, 0, BUS_HZ }, + { 0, ATAG_NONE } +}; + +#ifdef CONFIG_SDRAM +void __init set_sdram_size(unsigned long size) +{ + fake_bootloader_tags.mem2.size = size; +} +#endif diff -Nur linux-2.6.16.11/arch/avr32/boot/u-boot/empty.S linux-2.6.16.11-avr32-20060626/arch/avr32/boot/u-boot/empty.S --- linux-2.6.16.11/arch/avr32/boot/u-boot/empty.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boot/u-boot/empty.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1 @@ +/* Empty file */ diff -Nur linux-2.6.16.11/arch/avr32/boot/u-boot/head.S linux-2.6.16.11-avr32-20060626/arch/avr32/boot/u-boot/head.S --- linux-2.6.16.11/arch/avr32/boot/u-boot/head.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boot/u-boot/head.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,60 @@ +/* + * Startup code for use with the u-boot bootloader. + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + + /* + * The kernel is loaded where we want it to be and all caches + * have just been flushed. We get two parameters from u-boot: + * + * r12 contains a magic number (ATAG_MAGIC) + * r11 points to a tag table providing information about + * the system. + */ + .section .init.text,"ax" + .global _start +_start: + /* Check if the boot loader actually provided a tag table */ + lddpc r0, magic_number + cp.w r12, r0 + brne no_tag_table + + /* Initialize .bss */ + lddpc r2, bss_start_addr + lddpc r3, end_addr + mov r0, 0 + mov r1, 0 +1: st.d r2++, r0 + cp r2, r3 + brlo 1b + + /* + * Save the tag table address for later use. This must be done + * _after_ .bss has been initialized... + */ + lddpc r0, tag_table_addr + st.w r0[0], r11 + + /* Jump to loader-independent setup code */ + rjmp kernel_entry + + .align 2 +magic_number: + .long ATAG_MAGIC +tag_table_addr: + .long bootloader_tags +bss_start_addr: + .long __bss_start +end_addr: + .long _end + +no_tag_table: + sub r12, pc, (. - 2f) + bral panic +2: .asciz "Boot loader didn't provide correct magic number\n" diff -Nur linux-2.6.16.11/arch/avr32/boot/u-boot/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/boot/u-boot/Makefile --- linux-2.6.16.11/arch/avr32/boot/u-boot/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/boot/u-boot/Makefile 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,3 @@ +extra-y := head.o + +obj-y := empty.o diff -Nur linux-2.6.16.11/arch/avr32/defconfig linux-2.6.16.11-avr32-20060626/arch/avr32/defconfig --- linux-2.6.16.11/arch/avr32/defconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/defconfig 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,761 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.16.1 +# Fri Apr 28 11:02:56 2006 +# +CONFIG_AVR32=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +# CONFIG_SYSVIPC is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_BASE_FULL is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=1 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=m +CONFIG_IOSCHED_DEADLINE=m +CONFIG_IOSCHED_CFQ=m +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" + +# +# System Type and features +# +CONFIG_SUBARCH_AVR32B=y +CONFIG_MMU=y +CONFIG_PERFORMANCE_COUNTERS=y +CONFIG_PLATFORM_AT32AP=y +CONFIG_CPU_AT32AP7000=y +CONFIG_BOARD_AT32STK1002=y +CONFIG_BOARD_AT32STK1000=y +# CONFIG_LOADER_STANDALONE is not set +CONFIG_LOADER_U_BOOT=y +CONFIG_LOAD_ADDRESS=0x10000000 +CONFIG_ENTRY_ADDRESS=0x90000000 +CONFIG_PHYS_OFFSET=0x10000000 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_MAX_NR_IRQ_GROUPS=32 +# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set +# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set +# CONFIG_NEED_NODE_MEMMAP_SIZE is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_OWNERSHIP_TRACE=y +CONFIG_DW_DMAC=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_CMDLINE="" + +# +# Bus options +# + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_FW_LOADER is not set +CONFIG_DEBUG_DRIVER=y + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_RAM is not set +CONFIG_BLK_DEV_RAM_COUNT=16 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_MACB=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_USART3=y +CONFIG_SERIAL_USART3_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +CONFIG_SPI_ATMEL=m + +# +# SPI Protocol Masters +# + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=m +CONFIG_FB_CFB_FILLRECT=m +CONFIG_FB_CFB_COPYAREA=m +CONFIG_FB_CFB_IMAGEBLIT=m +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set +CONFIG_FB_SIDSA=m +CONFIG_FB_SIDSA_DEFAULT_BPP=24 +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_DEVICE=y +CONFIG_LCD_LTV350QV=m + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +# CONFIG_SND_SEQUENCER is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_BUS=m +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# ALSA AVR32 devices +# +CONFIG_SND_ATMEL_AC97=m + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=m +# CONFIG_OBSOLETE_OSS_DRIVER is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_SOUND_AT32_DAC=m + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +CONFIG_USB_GADGET_HUSB2DEV=y +CONFIG_USB_HUSB2DEV=m +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m + +# +# MMC/SD Card support +# +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=m +CONFIG_MMC_ATMELMCI=m + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=m +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_FORCED_INLINING is not set +CONFIG_RCU_TORTURE_TEST=m +# CONFIG_KPROBES is not set +CONFIG_EARLY_PRINTK=y +CONFIG_EARLY_PRINTK_PORTID=0 +CONFIG_EARLY_PRINTK_BAUDRATE=115200 + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set diff -Nur linux-2.6.16.11/arch/avr32/drivers/dw-dmac.c linux-2.6.16.11-avr32-20060626/arch/avr32/drivers/dw-dmac.c --- linux-2.6.16.11/arch/avr32/drivers/dw-dmac.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/drivers/dw-dmac.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,747 @@ +/* + * Driver for the Synopsys DesignWare DMA Controller + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "dw-dmac.h" + +#define DMAC_NR_CHANNELS 3 +#define DMAC_MAX_BLOCKSIZE 4095 + +enum { + CH_STATE_FREE = 0, + CH_STATE_ALLOCATED, + CH_STATE_BUSY, +}; + +struct dw_dma_lli { + dma_addr_t sar; + dma_addr_t dar; + dma_addr_t llp; + u32 ctllo; + u32 ctlhi; + u32 sstat; + u32 dstat; +}; + +struct dw_dma_block { + struct dw_dma_lli *lli_vaddr; + dma_addr_t lli_dma_addr; +}; + +struct dw_dma_channel { + unsigned int state; + int is_cyclic; + struct dma_request_sg *req_sg; + struct dma_request_cyclic *req_cyclic; + unsigned int nr_blocks; + int direction; + struct dw_dma_block *block; +}; + +struct dw_dma_controller { + spinlock_t lock; + void * __iomem regs; + struct dma_pool *lli_pool; + struct dma_controller dma; + struct dw_dma_channel channel[DMAC_NR_CHANNELS]; +}; +#define to_dw_dmac(dmac) container_of(dmac, struct dw_dma_controller, dma) + +#define dmac_writel_hi(dmac, reg, value) \ + writel((value), (dmac)->regs + DW_DMAC_##reg + 4) +#define dmac_readl_hi(dmac, reg) \ + readl((dmac)->regs + DW_DMAC_##reg + 4) +#define dmac_writel_lo(dmac, reg, value) \ + writel((value), (dmac)->regs + DW_DMAC_##reg) +#define dmac_readl_lo(dmac, reg) \ + readl((dmac)->regs + DW_DMAC_##reg) +#define dmac_chan_writel_hi(dmac, chan, reg, value) \ + writel((value), (dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg + 4) +#define dmac_chan_readl_hi(dmac, chan, reg) \ + readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg + 4) +#define dmac_chan_writel_lo(dmac, chan, reg, value) \ + writel((value), (dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg) +#define dmac_chan_readl_lo(dmac, chan, reg) \ + readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg) +#define set_channel_bit(dmac, reg, chan) \ + dmac_writel_lo(dmac, reg, (1 << (chan)) | (1 << ((chan) + 8))) +#define clear_channel_bit(dmac, reg, chan) \ + dmac_writel_lo(dmac, reg, (0 << (chan)) | (1 << ((chan) + 8))) + +static int dmac_alloc_channel(struct dma_controller *_dmac) +{ + struct dw_dma_controller *dmac = to_dw_dmac(_dmac); + struct dw_dma_channel *chan; + unsigned long flags; + int i; + + spin_lock_irqsave(&dmac->lock, flags); + for (i = 0; i < DMAC_NR_CHANNELS; i++) + if (dmac->channel[i].state == CH_STATE_FREE) + break; + + if (i < DMAC_NR_CHANNELS) { + chan = &dmac->channel[i]; + chan->state = CH_STATE_ALLOCATED; + } else { + i = -EBUSY; + } + + spin_unlock_irqrestore(&dmac->lock, flags); + + return i; +} + +static void dmac_release_channel(struct dma_controller *_dmac, int channel) +{ + struct dw_dma_controller *dmac = to_dw_dmac(_dmac); + + BUG_ON(channel >= DMAC_NR_CHANNELS + || dmac->channel[channel].state != CH_STATE_ALLOCATED); + + dmac->channel[channel].state = CH_STATE_FREE; +} + +static struct dw_dma_block *allocate_blocks(struct dw_dma_controller *dmac, + unsigned int nr_blocks) +{ + struct dw_dma_block *block; + void *p; + unsigned int i; + + block = kmalloc(nr_blocks * sizeof(*block), + GFP_KERNEL); + if (unlikely(!block)) + return NULL; + + for (i = 0; i < nr_blocks; i++) { + p = dma_pool_alloc(dmac->lli_pool, GFP_KERNEL, + &block[i].lli_dma_addr); + block[i].lli_vaddr = p; + if (unlikely(!p)) + goto fail; + } + + return block; + +fail: + for (i = 0; i < nr_blocks; i++) { + if (!block[i].lli_vaddr) + break; + dma_pool_free(dmac->lli_pool, block[i].lli_vaddr, + block[i].lli_dma_addr); + } + kfree(block); + return NULL; +} + +static int dmac_prepare_request_sg(struct dma_controller *_dmac, + struct dma_request_sg *req) +{ + struct dw_dma_controller *dmac = to_dw_dmac(_dmac); + struct dw_dma_channel *chan; + unsigned long ctlhi, ctllo, cfghi, cfglo; + unsigned long block_size; + int ret, i, nr_blocks, direction; + unsigned long flags; + + spin_lock_irqsave(&dmac->lock, flags); + + ret = -EINVAL; + if (req->req.channel >= DMAC_NR_CHANNELS + || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED + || req->block_size > DMAC_MAX_BLOCKSIZE) { + spin_unlock_irqrestore(&dmac->lock, flags); + return -EINVAL; + } + + chan = &dmac->channel[req->req.channel]; + chan->state = CH_STATE_BUSY; + chan->req_sg = req; + chan->is_cyclic = 0; + + /* + * We have marked the channel as busy, so no need to keep the + * lock as long as we only touch the channel-specific + * registers + */ + spin_unlock_irqrestore(&dmac->lock, flags); + + /* + * There may be limitations in the driver and/or the DMA + * controller that prevents us from sending a whole + * scatterlist item in one go. Taking this into account, + * calculate the number of block transfers we need to set up. + * + * FIXME: Let the peripheral driver know about the maximum + * block size we support. We really don't want to use a + * different block size than what was suggested by the + * peripheral. + * + * Each block will get its own Linked List Item (LLI) below. + */ + block_size = req->block_size; + pr_debug("block_size = %lu, nr_sg = %u\n", block_size, req->nr_sg); + for (i = 0, nr_blocks = 0; i < req->nr_sg; i++) { + pr_debug("sg[i].length = %u\n", req->sg[i].length); + BUG_ON(req->sg[i].length % block_size); + nr_blocks += req->sg[i].length / block_size; + } + + BUG_ON(nr_blocks == 0); + chan->nr_blocks = nr_blocks; + + ret = -EINVAL; + cfglo = cfghi = 0; + switch (req->direction) { + case DMA_DIR_MEM_TO_PERIPH: + direction = DMA_TO_DEVICE; + cfghi = req->periph_id << (43 - 32); + break; + + case DMA_DIR_PERIPH_TO_MEM: + direction = DMA_FROM_DEVICE; + cfghi = req->periph_id << (39 - 32); + break; + default: + goto out_unclaim_channel; + } + + chan->direction = direction; + + dmac_chan_writel_hi(dmac, req->req.channel, CFG, cfghi); + dmac_chan_writel_lo(dmac, req->req.channel, CFG, cfglo); + + ctlhi = block_size >> req->width; + ctllo = ((req->direction << 20) + // | (1 << 14) | (1 << 11) // source/dest burst trans len + | (req->width << 4) | (req->width << 1) + | (1 << 0)); // interrupt enable + + if (nr_blocks == 1) { + /* Only one block: No need to use block chaining */ + if (direction == DMA_TO_DEVICE) { + dmac_chan_writel_lo(dmac, req->req.channel, SAR, + req->sg->dma_address); + dmac_chan_writel_lo(dmac, req->req.channel, DAR, + req->data_reg); + ctllo |= 2 << 7; // no dst increment + } else { + dmac_chan_writel_lo(dmac, req->req.channel, SAR, + req->data_reg); + dmac_chan_writel_lo(dmac, req->req.channel, DAR, + req->sg->dma_address); + ctllo |= 2 << 9; // no src increment + } + dmac_chan_writel_lo(dmac, req->req.channel, CTL, ctllo); + dmac_chan_writel_hi(dmac, req->req.channel, CTL, ctlhi); + } else { + struct dw_dma_lli *lli, *lli_prev = NULL; + int j = 0, offset = 0; + + ret = -ENOMEM; + chan->block = allocate_blocks(dmac, nr_blocks); + if (!chan->block) + goto out_unclaim_channel; + + if (direction == DMA_TO_DEVICE) + ctllo |= 1 << 28 | 1 << 27 | 2 << 7; + else + ctllo |= 1 << 28 | 1 << 27 | 2 << 9; + + /* + * Map scatterlist items to blocks. One scatterlist + * item may need more than one block for the reasons + * mentioned above. + */ + for (i = 0; i < nr_blocks; i++) { + lli = chan->block[i].lli_vaddr; + if (lli_prev) { + lli_prev->llp = chan->block[i].lli_dma_addr; + pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n", + i - 1, chan->block[i - 1].lli_vaddr, + chan->block[i - 1].lli_dma_addr, + lli_prev->sar, lli_prev->dar, lli_prev->llp, + lli_prev->ctllo, lli_prev->ctlhi); + } + lli->llp = 0; + lli->ctllo = ctllo; + lli->ctlhi = ctlhi; + if (direction == DMA_TO_DEVICE) { + lli->sar = req->sg[j].dma_address + offset; + lli->dar = req->data_reg; + } else { + lli->sar = req->data_reg; + lli->dar = req->sg[j].dma_address + offset; + } + lli_prev = lli; + + offset += block_size; + if (offset > req->sg[j].length) { + j++; + offset = 0; + } + } + + pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n", + i - 1, chan->block[i - 1].lli_vaddr, + chan->block[i - 1].lli_dma_addr, lli_prev->sar, + lli_prev->dar, lli_prev->llp, + lli_prev->ctllo, lli_prev->ctlhi); + + /* + * SAR, DAR and CTL are initialized from the LLI. We + * only have to enable the LLI bits in CTL. + */ + dmac_chan_writel_lo(dmac, req->req.channel, LLP, + chan->block[0].lli_dma_addr); + dmac_chan_writel_lo(dmac, req->req.channel, CTL, 1 << 28 | 1 << 27); + } + + set_channel_bit(dmac, MASK_XFER, req->req.channel); + set_channel_bit(dmac, MASK_ERROR, req->req.channel); + if (req->req.block_complete) + set_channel_bit(dmac, MASK_BLOCK, req->req.channel); + else + clear_channel_bit(dmac, MASK_BLOCK, req->req.channel); + + return 0; + +out_unclaim_channel: + chan->state = CH_STATE_ALLOCATED; + return ret; +} + +static int dmac_prepare_request_cyclic(struct dma_controller *_dmac, + struct dma_request_cyclic *req) +{ + struct dw_dma_controller *dmac = to_dw_dmac(_dmac); + struct dw_dma_channel *chan; + unsigned long ctlhi, ctllo, cfghi, cfglo; + unsigned long block_size; + int ret, i, direction; + unsigned long flags; + + spin_lock_irqsave(&dmac->lock, flags); + + block_size = (req->buffer_size/req->periods) >> req->width; + + ret = -EINVAL; + if (req->req.channel >= DMAC_NR_CHANNELS + || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED + || (req->periods == 0) + || block_size > DMAC_MAX_BLOCKSIZE) { + spin_unlock_irqrestore(&dmac->lock, flags); + return -EINVAL; + } + + chan = &dmac->channel[req->req.channel]; + chan->state = CH_STATE_BUSY; + chan->is_cyclic = 1; + chan->req_cyclic = req; + + /* + * We have marked the channel as busy, so no need to keep the + * lock as long as we only touch the channel-specific + * registers + */ + spin_unlock_irqrestore(&dmac->lock, flags); + + /* + Setup + */ + BUG_ON(req->buffer_size % req->periods); + /* printk(KERN_INFO "block_size = %lu, periods = %u\n", block_size, req->periods); */ + + chan->nr_blocks = req->periods; + + ret = -EINVAL; + cfglo = cfghi = 0; + switch (req->direction) { + case DMA_DIR_MEM_TO_PERIPH: + direction = DMA_TO_DEVICE; + cfghi = req->periph_id << (43 - 32); + break; + + case DMA_DIR_PERIPH_TO_MEM: + direction = DMA_FROM_DEVICE; + cfghi = req->periph_id << (39 - 32); + break; + default: + goto out_unclaim_channel; + } + + chan->direction = direction; + + dmac_chan_writel_hi(dmac, req->req.channel, CFG, cfghi); + dmac_chan_writel_lo(dmac, req->req.channel, CFG, cfglo); + + ctlhi = block_size; + ctllo = ((req->direction << 20) + | (req->width << 4) | (req->width << 1) + | (1 << 0)); // interrupt enable + + { + struct dw_dma_lli *lli = NULL, *lli_prev = NULL; + + ret = -ENOMEM; + chan->block = allocate_blocks(dmac, req->periods); + if (!chan->block) + goto out_unclaim_channel; + + if (direction == DMA_TO_DEVICE) + ctllo |= 1 << 28 | 1 << 27 | 2 << 7; + else + ctllo |= 1 << 28 | 1 << 27 | 2 << 9; + + /* + * Set up a linked list items where each period gets + * an item. The linked list item for the last period + * points back to the star of the buffer making a + * cyclic buffer. + */ + for (i = 0; i < req->periods; i++) { + lli = chan->block[i].lli_vaddr; + if (lli_prev) { + lli_prev->llp = chan->block[i].lli_dma_addr; + /* printk(KERN_INFO "lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n", + i - 1, chan->block[i - 1].lli_vaddr, + chan->block[i - 1].lli_dma_addr, + lli_prev->sar, lli_prev->dar, lli_prev->llp, + lli_prev->ctllo, lli_prev->ctlhi);*/ + } + lli->llp = 0; + lli->ctllo = ctllo; + lli->ctlhi = ctlhi; + if (direction == DMA_TO_DEVICE) { + lli->sar = req->buffer_start + i*(block_size << req->width); + lli->dar = req->data_reg; + } else { + lli->sar = req->data_reg; + lli->dar = req->buffer_start + i*(block_size << req->width); + } + lli_prev = lli; + } + lli->llp = chan->block[0].lli_dma_addr; + + /*printk(KERN_INFO "lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n", + i - 1, chan->block[i - 1].lli_vaddr, + chan->block[i - 1].lli_dma_addr, lli_prev->sar, + lli_prev->dar, lli_prev->llp, + lli_prev->ctllo, lli_prev->ctlhi); */ + + /* + * SAR, DAR and CTL are initialized from the LLI. We + * only have to enable the LLI bits in CTL. + */ + dmac_chan_writel_lo(dmac, req->req.channel, LLP, + chan->block[0].lli_dma_addr); + dmac_chan_writel_lo(dmac, req->req.channel, CTL, 1 << 28 | 1 << 27); + } + + clear_channel_bit(dmac, MASK_XFER, req->req.channel); + set_channel_bit(dmac, MASK_ERROR, req->req.channel); + if (req->req.block_complete) + set_channel_bit(dmac, MASK_BLOCK, req->req.channel); + else + clear_channel_bit(dmac, MASK_BLOCK, req->req.channel); + + return 0; + +out_unclaim_channel: + chan->state = CH_STATE_ALLOCATED; + return ret; +} + +static int dmac_start_request(struct dma_controller *_dmac, + unsigned int channel) +{ + struct dw_dma_controller *dmac = to_dw_dmac(_dmac); + + BUG_ON(channel >= DMAC_NR_CHANNELS); + + set_channel_bit(dmac, CH_EN, channel); + + return 0; +} + +static dma_addr_t dmac_get_current_pos(struct dma_controller *_dmac, + unsigned int channel) +{ + struct dw_dma_controller *dmac = to_dw_dmac(_dmac); + struct dw_dma_channel *chan; + dma_addr_t current_pos; + + BUG_ON(channel >= DMAC_NR_CHANNELS); + + chan = &dmac->channel[channel]; + + switch (chan->direction) { + case DMA_TO_DEVICE: + current_pos = dmac_chan_readl_lo(dmac, channel, SAR); + break; + case DMA_FROM_DEVICE: + current_pos = dmac_chan_readl_lo(dmac, channel, DAR); + break; + default: + return 0; + } + + + if (!current_pos) { + if (chan->is_cyclic) { + current_pos = chan->req_cyclic->buffer_start; + } else { + current_pos = chan->req_sg->sg->dma_address; + } + } + + return current_pos; +} + + +static void cleanup_channel(struct dw_dma_controller *dmac, + struct dw_dma_channel *chan) +{ + unsigned int i; + + if (chan->nr_blocks > 1) { + for (i = 0; i < chan->nr_blocks; i++) + dma_pool_free(dmac->lli_pool, chan->block[i].lli_vaddr, + chan->block[i].lli_dma_addr); + kfree(chan->block); + } + + chan->state = CH_STATE_ALLOCATED; +} + +static int dmac_stop_request(struct dma_controller *_dmac, + unsigned int channel) +{ + struct dw_dma_controller *dmac = to_dw_dmac(_dmac); + + BUG_ON(channel >= DMAC_NR_CHANNELS); + + BUG_ON(dmac->channel[channel].state != CH_STATE_BUSY); + + clear_channel_bit(dmac, CH_EN, channel); + + cleanup_channel(dmac, &dmac->channel[channel]); + + return 0; +} + + +static void dmac_block_complete(struct dw_dma_controller *dmac) +{ + struct dw_dma_channel *chan; + unsigned long status, chanid; + + status = dmac_readl_lo(dmac, STATUS_BLOCK); + + while (status) { + struct dma_request *req; + chanid = __ffs(status); + chan = &dmac->channel[chanid]; + + if (chan->is_cyclic) { + BUG_ON(!chan->req_cyclic + || !chan->req_cyclic->req.block_complete); + req = &chan->req_cyclic->req; + } else { + BUG_ON(!chan->req_sg || !chan->req_sg->req.block_complete); + req = &chan->req_sg->req; + } + dmac_writel_lo(dmac, CLEAR_BLOCK, 1 << chanid); + req->block_complete(req); + status = dmac_readl_lo(dmac, STATUS_BLOCK); + } +} + +static void dmac_xfer_complete(struct dw_dma_controller *dmac) +{ + struct dw_dma_channel *chan; + struct dma_request *req; + unsigned long status, chanid; + + status = dmac_readl_lo(dmac, STATUS_XFER); + + while (status) { + chanid = __ffs(status); + chan = &dmac->channel[chanid]; + + dmac_writel_lo(dmac, CLEAR_XFER, 1 << chanid); + + req = &chan->req_sg->req; + BUG_ON(!req); + cleanup_channel(dmac, chan); + if (req->xfer_complete) + req->xfer_complete(req); + + status = dmac_readl_lo(dmac, STATUS_XFER); + } +} + +static void dmac_error(struct dw_dma_controller *dmac) +{ + struct dw_dma_channel *chan; + unsigned long status, chanid; + + status = dmac_readl_lo(dmac, STATUS_ERROR); + + while (status) { + struct dma_request *req; + + chanid = __ffs(status); + chan = &dmac->channel[chanid]; + + dmac_writel_lo(dmac, CLEAR_ERROR, 1 << chanid); + clear_channel_bit(dmac, CH_EN, chanid); + + if (chan->is_cyclic) { + BUG_ON(!chan->req_cyclic); + req = &chan->req_cyclic->req; + } else { + BUG_ON(!chan->req_sg); + req = &chan->req_sg->req; + } + + cleanup_channel(dmac, chan); + if (req->error) + req->error(req); + + status = dmac_readl_lo(dmac, STATUS_XFER); + } +} + +static irqreturn_t dmac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct dw_dma_controller *dmac = dev_id; + unsigned long status; + int ret = IRQ_NONE; + + spin_lock(&dmac->lock); + + status = dmac_readl_lo(dmac, STATUS_INT); + + while (status) { + ret = IRQ_HANDLED; + if (status & 0x10) + dmac_error(dmac); + if (status & 0x02) + dmac_block_complete(dmac); + if (status & 0x01) + dmac_xfer_complete(dmac); + + status = dmac_readl_lo(dmac, STATUS_INT); + } + + spin_unlock(&dmac->lock); + return ret; +} + +static int __devinit dmac_probe(struct at32_device *adev) +{ + struct dw_dma_controller *dmac; + int ret; + + ret = at32_enable_device(adev); + if (ret) { + dev_err(&adev->dev, "failed to enable device\n"); + return ret; + } + + ret = -ENOMEM; + dmac = kmalloc(sizeof(*dmac), GFP_KERNEL); + if (!dmac) + goto out_disable_dev; + memset(dmac, 0, sizeof(*dmac)); + + dmac->lli_pool = dma_pool_create("dmac", &adev->dev, + sizeof(struct dw_dma_lli), 4, 0); + if (!dmac->lli_pool) + goto out_free_dmac; + + spin_lock_init(&dmac->lock); + dmac->dma.dev = &adev->dev; + dmac->dma.alloc_channel = dmac_alloc_channel; + dmac->dma.release_channel = dmac_release_channel; + dmac->dma.prepare_request_sg = dmac_prepare_request_sg; + dmac->dma.prepare_request_cyclic = dmac_prepare_request_cyclic; + dmac->dma.start_request = dmac_start_request; + dmac->dma.stop_request = dmac_stop_request; + dmac->dma.get_current_pos = dmac_get_current_pos; + + dmac->regs = at32_map_iomem(adev, 0); + if (!dmac->regs) + goto out_free_pool; + + ret = request_irq(at32_get_irq(adev), dmac_interrupt, + SA_SAMPLE_RANDOM, adev->name, dmac); + if (ret) + goto out_unmap_regs; + + /* Enable the DMA controller */ + dmac_writel_lo(dmac, CFG, 1); + + register_dma_controller(&dmac->dma); + + printk(KERN_INFO + "dmac%d: DesignWare DMA controller at 0x%p irq %d\n", + dmac->dma.id, dmac->regs, at32_get_irq(adev)); + + return 0; + +out_unmap_regs: + iounmap(dmac->regs); +out_free_pool: + dma_pool_destroy(dmac->lli_pool); +out_free_dmac: + kfree(dmac); +out_disable_dev: + at32_disable_device(adev); + return ret; +} + +static struct at32_driver dmac_driver = { + .probe = dmac_probe, + .driver = { + .name = "dmac", + }, +}; + +static int __init dmac_init(void) +{ + return at32_driver_register(&dmac_driver); +} +subsys_initcall(dmac_init); + +static void __exit dmac_exit(void) +{ + at32_driver_unregister(&dmac_driver); +} +module_exit(dmac_exit); + +MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver"); +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.16.11/arch/avr32/drivers/dw-dmac.h linux-2.6.16.11-avr32-20060626/arch/avr32/drivers/dw-dmac.h --- linux-2.6.16.11/arch/avr32/drivers/dw-dmac.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/drivers/dw-dmac.h 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,42 @@ +/* + * Driver for the Synopsys DesignWare DMA Controller + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __AVR32_DW_DMAC_H__ +#define __AVR32_DW_DMAC_H__ + +#define DW_DMAC_CFG 0x398 +#define DW_DMAC_CH_EN 0x3a0 + +#define DW_DMAC_STATUS_XFER 0x2e8 +#define DW_DMAC_STATUS_BLOCK 0x2f0 +#define DW_DMAC_STATUS_ERROR 0x308 + +#define DW_DMAC_MASK_XFER 0x310 +#define DW_DMAC_MASK_BLOCK 0x318 +#define DW_DMAC_MASK_ERROR 0x330 + +#define DW_DMAC_CLEAR_XFER 0x338 +#define DW_DMAC_CLEAR_BLOCK 0x340 +#define DW_DMAC_CLEAR_ERROR 0x358 + +#define DW_DMAC_STATUS_INT 0x360 + +#define DW_DMAC_CHAN_SAR 0x000 +#define DW_DMAC_CHAN_DAR 0x008 +#define DW_DMAC_CHAN_LLP 0x010 +#define DW_DMAC_CHAN_CTL 0x018 +#define DW_DMAC_CHAN_SSTAT 0x020 +#define DW_DMAC_CHAN_DSTAT 0x028 +#define DW_DMAC_CHAN_SSTATAR 0x030 +#define DW_DMAC_CHAN_DSTATAR 0x038 +#define DW_DMAC_CHAN_CFG 0x040 +#define DW_DMAC_CHAN_SGR 0x048 +#define DW_DMAC_CHAN_DSR 0x050 + +#endif /* __AVR32_DW_DMAC_H__ */ diff -Nur linux-2.6.16.11/arch/avr32/drivers/extint.c linux-2.6.16.11-avr32-20060626/arch/avr32/drivers/extint.c --- linux-2.6.16.11/arch/avr32/drivers/extint.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/drivers/extint.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,242 @@ +/* + * Driver for the at73c213 16-bit stereo DAC on Atmel ATSTK1000 + * + * Copyright (C) 2006 Atmel Norway + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * The full GNU General Public License is included in this + * distribution in the file called COPYING. + */ + +#include +#include +#include +#include + +#include +#include +#include + +/* register defines */ +#define EIM_EIR 0x100 +#define EIM_IDR 0x104 +#define EIM_IMR 0x108 +#define EIM_ISR 0x10C +#define EIM_ICR 0x110 +#define EIM_MODE 0x114 +#define EIM_EDGE 0x118 +#define EIM_LEVEL 0x11C + +struct extint { + int irqa; + int irqb; + int irqc; + int irqd; + void __iomem *regs; + spinlock_t lock; + struct at32_device *adev; +}; + +static irqreturn_t extint_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct extint *dev = dev_id; + spin_lock(&dev->lock); + if (irq == dev->irqa) { + printk(KERN_INFO "extint: INTA\n"); + } + else if (irq == dev->irqb) { + printk(KERN_INFO "extint: INTB\n"); + } + else if (irq == dev->irqc) { + printk(KERN_INFO "extint: INTC\n"); + } + else if (irq == dev->irqd) { + printk(KERN_INFO "extint: INTD\n"); + } else { + printk(KERN_WARNING "extint: spurious extint " + "interrupt, irq %d\n", irq); + } + spin_unlock(&dev->lock); + return IRQ_HANDLED; +} + +static int __devinit extint_probe(struct at32_device *adev) +{ + struct extint *dev; + int retval; + int irq; + + retval = at32_enable_device(adev); + if (retval) { + printk(KERN_ERR "extint: failed to enable device\n"); + goto out; + } + + retval = -ENOMEM; + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + goto out; + + spin_lock_init(&dev->lock); + dev->adev = adev; + dev->irqa = -1; + dev->irqb = -1; + dev->irqc = -1; + dev->irqd = -1; + + dev->regs = at32_map_iomem(adev, 0); + + if (!dev->regs) + goto out_free; + + irq = at32_get_irq(adev); + + /* TODO: get number of IRQs and do this in a for-loop + * replace dev->irqX with an array + */ + retval = request_irq(irq, extint_interrupt, 0, "extint", dev); + if (retval) { + printk(KERN_ERR "extint: unable to request irq %d\n", irq); + goto out_free; + } + dev->irqa = irq; + retval = irq_set_type(irq, IRQ_TYPE_EDGE|IRQ_EDGE_FALLING); + if (retval) { + printk(KERN_ERR "extint: unable to set type on irq %d\n", irq); + goto out_free; + } + + ++irq; + retval = request_irq(irq, extint_interrupt, 0, "extint", dev); + if (retval) { + printk(KERN_ERR "extint: unable to request irq %d\n", irq); + goto out_free; + } + dev->irqb = irq; + retval = irq_set_type(irq, IRQ_TYPE_EDGE|IRQ_EDGE_FALLING); + if (retval) { + printk(KERN_ERR "extint: unable to set type on irq %d\n", irq); + goto out_free; + } + + ++irq; + retval = request_irq(irq, extint_interrupt, 0, "extint", dev); + if (retval) { + printk(KERN_ERR "extint: unable to request irq %d\n", irq); + goto out_free; + } + dev->irqc = irq; + retval = irq_set_type(irq, IRQ_TYPE_EDGE|IRQ_EDGE_FALLING); + if (retval) { + printk(KERN_ERR "extint: unable to set type on irq %d\n", irq); + goto out_free; + } + + ++irq; + retval = request_irq(irq, extint_interrupt, 0, "extint", dev); + if (retval) { + printk(KERN_ERR "extint: unable to request irq %d\n", irq); + goto out_free; + } + dev->irqd = irq; + retval = irq_set_type(irq, IRQ_TYPE_EDGE|IRQ_EDGE_FALLING); + if (retval) { + printk(KERN_ERR "extint: unable to set type on irq %d\n", irq); + goto out_free; + } + + at32_set_drvdata(adev, dev); + + goto out; + +out_free: + kfree(dev); + if (dev->irqa >= 0) + free_irq(dev->irqa, dev); + if (dev->irqb >= 0) + free_irq(dev->irqb, dev); + if (dev->irqc >= 0) + free_irq(dev->irqc, dev); + if (dev->irqd >= 0) + free_irq(dev->irqd, dev); + if (dev->regs) + iounmap(dev->regs); + at32_disable_device(adev); +out: + return retval; +} + +static int __devexit extint_remove(struct at32_device *adev) +{ + struct extint *dev = at32_get_drvdata(adev); + + if (dev->regs) { + iounmap(dev->regs); + } + + if (dev->irqa >= 0) + { + free_irq(dev->irqa, dev); + } + if (dev->irqb >= 0) + { + free_irq(dev->irqb, dev); + } + if (dev->irqc >= 0) + { + free_irq(dev->irqc, dev); + } + if (dev->irqd >= 0) + { + free_irq(dev->irqd, dev); + } + + /* reset registers to sane values */ + + at32_disable_device(adev); + at32_set_drvdata(adev, NULL); + + return 0; +} + +/* Driver core initialization */ +static struct at32_driver extint_driver = { + .probe = extint_probe, + .remove = __devexit_p(extint_remove), + .driver = { + .name = "extint", + }, +}; + +static int __init init_extint(void) +{ + return at32_driver_register(&extint_driver); +} + +static void __exit exit_extint(void) +{ + at32_driver_unregister(&extint_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Hans-Christian Egtvedt "); +MODULE_DESCRIPTION("Enables INT A, B, C and D buttons on STK1000"); +MODULE_SUPPORTED_DEVICE("extint"); + +module_init(init_extint); +module_exit(exit_extint); diff -Nur linux-2.6.16.11/arch/avr32/drivers/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/drivers/Makefile --- linux-2.6.16.11/arch/avr32/drivers/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/drivers/Makefile 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,2 @@ +obj-$(CONFIG_DW_DMAC) += dw-dmac.o +obj-$(CONFIG_EXTINT) += extint.o diff -Nur linux-2.6.16.11/arch/avr32/Kconfig linux-2.6.16.11-avr32-20060626/arch/avr32/Kconfig --- linux-2.6.16.11/arch/avr32/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/Kconfig 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,210 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "Linux Kernel Configuration" + +config AVR32 + bool + default y + help + AVR32 is a high-performance 32-bit RISC microprocessor core, + designed for cost-sensitive embedded applications, with particular + emphasis on low power consumption and high code density. + + There is an AVR32 Linux project with a web page at + http://avr32linux.org/. + +config UID16 + bool + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + +config GENERIC_BUST_SPINLOCK + bool + +config GENERIC_ISA_DMA + bool + +config GENERIC_CALIBRATE_DELAY + bool + default y + +source "init/Kconfig" + +menu "System Type and features" + +config SUBARCH_AVR32B + bool +config MMU + bool +config PERFORMANCE_COUNTERS + bool + +config PLATFORM_AT32AP + bool + select SUBARCH_AVR32B + select MMU + select PERFORMANCE_COUNTERS + +choice + prompt "AVR32 CPU type" + default CPU_AT32AP7000 + +config CPU_AT32AP7000 + bool "AT32AP7000" + select PLATFORM_AT32AP +endchoice + +# +# CPU Daughterboards for AT32STK1000 +config BOARD_AT32STK1002 + bool + +choice + prompt "AVR32 board type" + default BOARD_AT32STK1000 + +config BOARD_AT32STK1000 + bool "AT32STK1000 evaluation board" + select BOARD_AT32STK1002 if CPU_AT32AP7000 +endchoice + +choice + prompt "Boot loader type" + default LOADER_STANDALONE + +config LOADER_STANDALONE + bool "No boot loader" + +config LOADER_U_BOOT + bool "U-Boot (or similar) bootloader" +endchoice + +config LOAD_ADDRESS + hex + default 0x00000000 if LOADER_STANDALONE=y + default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y + +config ENTRY_ADDRESS + hex + default 0x80000000 if LOADER_STANDALONE=y + default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y + +config PHYS_OFFSET + hex + default 0x10000000 if CPU_AT32AP7000=y + +config SDRAM + bool "SDRAM support" + depends on LOADER_STANDALONE + default y + +source "kernel/Kconfig.preempt" + +config MAX_NR_IRQ_GROUPS + int "Maximum number of interrupt groups" + default 32 + help + Specify the maximum number of interrupt groups to support. + Decrease this number to save some memory. + +config HAVE_ARCH_BOOTMEM_NODE + bool + default n + +config ARCH_HAVE_MEMORY_PRESENT + bool + default n + +config NEED_NODE_MEMMAP_SIZE + bool + default n + +config ARCH_FLATMEM_ENABLE + bool + default y + +config ARCH_DISCONTIGMEM_ENABLE + bool + default y + +config ARCH_SPARSEMEM_ENABLE + bool + depends on EXPERIMENTAL + default y + +source "mm/Kconfig" + +config OWNERSHIP_TRACE + bool "Ownership trace support" + default y + help + Say Y to generate an Ownership Trace message on every context switch, + enabling Nexus-compliant debuggers to keep track of the PID of the + currently executing task. + +config DW_DMAC + tristate "Synopsys DesignWare DMA Controller support" + default y if CPU_AT32AP7000 + +config EXTINT + tristate "AVR32 external interrupts support" + help + Say Y here if you want to enable the Atmel AVR32 external + interrupts support. This will enable usage of the INT A, + INT B, INT C and INT D buttons on the STK1000 in Linux. + + To compile this driver as a module, choose M here: the + module will be called extint. + +# FPU emulation goes here + +source "kernel/Kconfig.hz" + +config CMDLINE + string "Default kernel command line" + default "" + help + If you don't have a boot loader capable of passing a command line string + to the kernel, you may specify one here. As a minimum, you should specify + the memory size and the root device (e.g., mem=8M, root=/dev/nfs). + +endmenu + +menu "Bus options" + +config PCI + bool + +source "drivers/pci/Kconfig" + +source "drivers/pcmcia/Kconfig" + +endmenu + +menu "Executable file formats" +source "fs/Kconfig.binfmt" +endmenu + +source "net/Kconfig" + +source "drivers/Kconfig" + +source "fs/Kconfig" + +source "arch/avr32/oprofile/Kconfig" + +source "arch/avr32/Kconfig.debug" + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" diff -Nur linux-2.6.16.11/arch/avr32/Kconfig.debug linux-2.6.16.11-avr32-20060626/arch/avr32/Kconfig.debug --- linux-2.6.16.11/arch/avr32/Kconfig.debug 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/Kconfig.debug 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,38 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config KPROBES + bool "Kprobes" + depends on DEBUG_KERNEL + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". + +config EARLY_PRINTK + bool "Early printk support" + help + Initialize the serial console very early in the boot process. + This option is only useful porting the kernel to a new machine, + when the kernel may crash or hang before the serial console is + initialised. If unsure, say N. + +config EARLY_PRINTK_PORTID + int "Early prink USART ID" + default 0 + depends on EARLY_PRINTK + help + Specify which usart to use for early printk, e.g. '0' for USART0. + +config EARLY_PRINTK_BAUDRATE + int "Early printk USART baud rate" + default 115200 + depends on EARLY_PRINTK + help + Specify the initial baud rate of the early printk USART. Common + settings are 115200, 38400, 19200 and 9600. + +endmenu diff -Nur linux-2.6.16.11/arch/avr32/Kconfig.orig linux-2.6.16.11-avr32-20060626/arch/avr32/Kconfig.orig --- linux-2.6.16.11/arch/avr32/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/Kconfig.orig 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,198 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "Linux Kernel Configuration" + +config AVR32 + bool + default y + help + AVR32 is a high-performance 32-bit RISC microprocessor core, + designed for cost-sensitive embedded applications, with particular + emphasis on low power consumption and high code density. + + There is an AVR32 Linux project with a web page at + http://avr32linux.org/. + +config UID16 + bool + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + +config GENERIC_BUST_SPINLOCK + bool + +config GENERIC_ISA_DMA + bool + +config GENERIC_CALIBRATE_DELAY + bool + default y + +source "init/Kconfig" + +menu "System Type and features" + +config SUBARCH_AVR32B + bool +config MMU + bool +config PERFORMANCE_COUNTERS + bool + +config PLATFORM_AT32AP + bool + select SUBARCH_AVR32B + select MMU + select PERFORMANCE_COUNTERS + +choice + prompt "AVR32 CPU type" + default CPU_AT32AP7000 + +config CPU_AT32AP7000 + bool "AT32AP7000" + select PLATFORM_AT32AP +endchoice + +# +# CPU Daughterboards for AT32STK1000 +config BOARD_AT32STK1002 + bool + +choice + prompt "AVR32 board type" + default BOARD_AT32STK1000 + +config BOARD_AT32STK1000 + bool "AT32STK1000 evaluation board" + select BOARD_AT32STK1002 if CPU_AT32AP7000 +endchoice + +choice + prompt "Boot loader type" + default LOADER_STANDALONE + +config LOADER_STANDALONE + bool "No boot loader" + +config LOADER_U_BOOT + bool "U-Boot (or similar) bootloader" +endchoice + +config LOAD_ADDRESS + hex + default 0x00000000 if LOADER_STANDALONE=y + default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y + +config ENTRY_ADDRESS + hex + default 0x80000000 if LOADER_STANDALONE=y + default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y + +config PHYS_OFFSET + hex + default 0x10000000 if CPU_AT32AP7000=y + +config SDRAM + bool "SDRAM support" + depends on LOADER_STANDALONE + default y + +source "kernel/Kconfig.preempt" + +config MAX_NR_IRQ_GROUPS + int "Maximum number of interrupt groups" + default 32 + help + Specify the maximum number of interrupt groups to support. + Decrease this number to save some memory. + +config HAVE_ARCH_BOOTMEM_NODE + bool + default n + +config ARCH_HAVE_MEMORY_PRESENT + bool + default n + +config NEED_NODE_MEMMAP_SIZE + bool + default n + +config ARCH_FLATMEM_ENABLE + bool + default y + +config ARCH_DISCONTIGMEM_ENABLE + bool + default y + +config ARCH_SPARSEMEM_ENABLE + bool + depends on EXPERIMENTAL + default y + +source "mm/Kconfig" + +config OWNERSHIP_TRACE + bool "Ownership trace support" + default y + help + Say Y to generate an Ownership Trace message on every context switch, + enabling Nexus-compliant debuggers to keep track of the PID of the + currently executing task. + +config DW_DMAC + tristate "Synopsys DesignWare DMA Controller support" + default y if CPU_AT32AP7000 + +# FPU emulation goes here + +source "kernel/Kconfig.hz" + +config CMDLINE + string "Default kernel command line" + default "" + help + If you don't have a boot loader capable of passing a command line string + to the kernel, you may specify one here. As a minimum, you should specify + the memory size and the root device (e.g., mem=8M, root=/dev/nfs). + +endmenu + +menu "Bus options" + +config PCI + bool + +source "drivers/pci/Kconfig" + +source "drivers/pcmcia/Kconfig" + +endmenu + +menu "Executable file formats" +source "fs/Kconfig.binfmt" +endmenu + +source "net/Kconfig" + +source "drivers/Kconfig" + +source "fs/Kconfig" + +source "arch/avr32/Kconfig.debug" + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" diff -Nur linux-2.6.16.11/arch/avr32/kernel/asm-offsets.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/asm-offsets.c --- linux-2.6.16.11/arch/avr32/kernel/asm-offsets.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/asm-offsets.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,25 @@ +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed + * to extract and format the required data. + */ + +#include + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +#define OFFSET(sym, str, mem) \ + DEFINE(sym, offsetof(struct str, mem)); + +void foo(void) +{ + OFFSET(TI_task, thread_info, task); + OFFSET(TI_exec_domain, thread_info, exec_domain); + OFFSET(TI_flags, thread_info, flags); + OFFSET(TI_cpu, thread_info, cpu); + OFFSET(TI_preempt_count, thread_info, preempt_count); + OFFSET(TI_restart_block, thread_info, restart_block); +} diff -Nur linux-2.6.16.11/arch/avr32/kernel/avr32_ksyms.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/avr32_ksyms.c --- linux-2.6.16.11/arch/avr32/kernel/avr32_ksyms.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/avr32_ksyms.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,69 @@ +/* + * Export AVR32-specific functions for loadable modules. + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +#include +#include +#include + +/* + * GCC functions + */ +extern unsigned int __avr32_umod64(unsigned int u, unsigned int v); +extern unsigned int __avr32_udiv64(unsigned int n, unsigned int d); +extern unsigned long long __avr32_lsl64(unsigned long long u, unsigned long b); +extern unsigned long long __avr32_lsr64(unsigned long long u, unsigned long b); +extern unsigned long long __avr32_asr64(unsigned long long u, unsigned long b); +EXPORT_SYMBOL(__avr32_umod64); +EXPORT_SYMBOL(__avr32_udiv64); +EXPORT_SYMBOL(__avr32_lsl64); +EXPORT_SYMBOL(__avr32_lsr64); +EXPORT_SYMBOL(__avr32_asr64); + +/* + * String functions + */ +EXPORT_SYMBOL(memchr); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); + +EXPORT_SYMBOL(ext2_find_first_zero_bit); +EXPORT_SYMBOL(ext2_find_next_zero_bit); +EXPORT_SYMBOL(kernel_thread); + +/* + * Userspace access stuff. + */ +EXPORT_SYMBOL(copy_from_user); +EXPORT_SYMBOL(copy_to_user); +EXPORT_SYMBOL(__copy_user); +EXPORT_SYMBOL(strncpy_from_user); +EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(clear_user); +EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(csum_partial); +EXPORT_SYMBOL(csum_partial_copy_generic); + +/* Delay loops (lib/delay.S) */ +EXPORT_SYMBOL(__ndelay); +EXPORT_SYMBOL(__udelay); +EXPORT_SYMBOL(__const_udelay); diff -Nur linux-2.6.16.11/arch/avr32/kernel/cpu.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/cpu.c --- linux-2.6.16.11/arch/avr32/kernel/cpu.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/cpu.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static DEFINE_PER_CPU(struct cpu, cpu_devices); + +#ifdef CONFIG_PERFORMANCE_COUNTERS + +/* + * XXX: If/when a SMP-capable implementation of AVR32 will ever be + * made, we must make sure that the code executes on the correct CPU. + */ +static ssize_t show_pc0event(struct sys_device *dev, char *buf) +{ + unsigned long pccr; + + pccr = sysreg_read(PCCR); + return sprintf(buf, "0x%lx\n", (pccr >> 12) & 0x3f); +} +static ssize_t store_pc0event(struct sys_device *dev, const char *buf, + size_t count) +{ + unsigned long val; + char *endp; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf || val > 0x3f) + return -EINVAL; + val = (val << 12) | (sysreg_read(PCCR) & 0xfffc0fff); + sysreg_write(PCCR, val); + return count; +} +static ssize_t show_pc0count(struct sys_device *dev, char *buf) +{ + unsigned long pcnt0; + + pcnt0 = sysreg_read(PCNT0); + return sprintf(buf, "%lu\n", pcnt0); +} +static ssize_t store_pc0count(struct sys_device *dev, const char *buf, + size_t count) +{ + unsigned long val; + char *endp; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf) + return -EINVAL; + sysreg_write(PCNT0, val); + + return count; +} + +static ssize_t show_pc1event(struct sys_device *dev, char *buf) +{ + unsigned long pccr; + + pccr = sysreg_read(PCCR); + return sprintf(buf, "0x%lx\n", (pccr >> 18) & 0x3f); +} +static ssize_t store_pc1event(struct sys_device *dev, const char *buf, + size_t count) +{ + unsigned long val; + char *endp; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf || val > 0x3f) + return -EINVAL; + val = (val << 18) | (sysreg_read(PCCR) & 0xff03ffff); + sysreg_write(PCCR, val); + return count; +} +static ssize_t show_pc1count(struct sys_device *dev, char *buf) +{ + unsigned long pcnt1; + + pcnt1 = sysreg_read(PCNT1); + return sprintf(buf, "%lu\n", pcnt1); +} +static ssize_t store_pc1count(struct sys_device *dev, const char *buf, + size_t count) +{ + unsigned long val; + char *endp; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf) + return -EINVAL; + sysreg_write(PCNT1, val); + + return count; +} + +static ssize_t show_pccycles(struct sys_device *dev, char *buf) +{ + unsigned long pccnt; + + pccnt = sysreg_read(PCCNT); + return sprintf(buf, "%lu\n", pccnt); +} +static ssize_t store_pccycles(struct sys_device *dev, const char *buf, + size_t count) +{ + unsigned long val; + char *endp; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf) + return -EINVAL; + sysreg_write(PCCNT, val); + + return count; +} + +static ssize_t show_pcenable(struct sys_device *dev, char *buf) +{ + unsigned long pccr; + + pccr = sysreg_read(PCCR); + return sprintf(buf, "%c\n", (pccr & 1)?'1':'0'); +} +static ssize_t store_pcenable(struct sys_device *dev, const char *buf, + size_t count) +{ + unsigned long pccr, val; + char *endp; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf) + return -EINVAL; + if (val) + val = 1; + + pccr = sysreg_read(PCCR); + pccr = (pccr & ~1UL) | val; + sysreg_write(PCCR, pccr); + + return count; +} + +static SYSDEV_ATTR(pc0event, 0600, show_pc0event, store_pc0event); +static SYSDEV_ATTR(pc0count, 0600, show_pc0count, store_pc0count); +static SYSDEV_ATTR(pc1event, 0600, show_pc1event, store_pc1event); +static SYSDEV_ATTR(pc1count, 0600, show_pc1count, store_pc1count); +static SYSDEV_ATTR(pccycles, 0600, show_pccycles, store_pccycles); +static SYSDEV_ATTR(pcenable, 0600, show_pcenable, store_pcenable); + +#endif /* CONFIG_PERFORMANCE_COUNTERS */ + +static int __init topology_init(void) +{ + int cpu; + + for_each_cpu(cpu) { + struct cpu *c = &per_cpu(cpu_devices, cpu); + + register_cpu(c, cpu, NULL); + +#ifdef CONFIG_PERFORMANCE_COUNTERS + sysdev_create_file(&c->sysdev, &attr_pc0event); + sysdev_create_file(&c->sysdev, &attr_pc0count); + sysdev_create_file(&c->sysdev, &attr_pc1event); + sysdev_create_file(&c->sysdev, &attr_pc1count); + sysdev_create_file(&c->sysdev, &attr_pccycles); + sysdev_create_file(&c->sysdev, &attr_pcenable); +#endif + } + + return 0; +} + +subsys_initcall(topology_init); + +static const char *cpu_names[] = { + "Morgan", + "AP7000", +}; +#define NR_CPU_NAMES ARRAY_SIZE(cpu_names) + +static const char *arch_names[] = { + "AVR32A", + "AVR32B", +}; +#define NR_ARCH_NAMES ARRAY_SIZE(arch_names) + +static const char *mmu_types[] = { + "No MMU", + "ITLB and DTLB", + "Shared TLB", + "MPU" +}; + +void __init setup_processor(void) +{ + unsigned long config0, config1; + unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type; + unsigned tmp; + + if (boot_cpu_data.cpu_hz) { + printk("CPU: %llu.%03llu MHz CPU detected\n", + ((boot_cpu_data.cpu_hz + 500) / 1000) / 1000, + ((boot_cpu_data.cpu_hz + 500) / 1000) % 1000); + boot_cpu_data.loops_per_jiffy = boot_cpu_data.cpu_hz * 4; + } else { + printk(KERN_WARNING "Warning: Unknown CPU frequency.\n"); + } + + config0 = sysreg_read(CONFIG0); /* 0x0000013e; */ + config1 = sysreg_read(CONFIG1); /* 0x01f689a2; */ + printk ("config0: %08lx config1: %08lx\n", config0, config1); + cpu_id = config0 >> 24; + cpu_rev = (config0 >> 16) & 0xff; + arch_id = (config0 >> 13) & 0x07; + arch_rev = (config0 >> 10) & 0x07; + mmu_type = (config0 >> 7) & 0x03; + + boot_cpu_data.arch_type = arch_id; + boot_cpu_data.cpu_type = cpu_id; + boot_cpu_data.arch_revision = arch_rev; + boot_cpu_data.cpu_revision = cpu_rev; + boot_cpu_data.tlb_config = mmu_type; + + tmp = (config1 >> 13) & 0x07; + if (tmp) { + boot_cpu_data.icache.ways = 1 << ((config1 >> 10) & 0x07); + boot_cpu_data.icache.sets = 1 << ((config1 >> 16) & 0x0f); + boot_cpu_data.icache.linesz = 1 << (tmp + 1); + } + tmp = (config1 >> 3) & 0x07; + if (tmp) { + boot_cpu_data.dcache.ways = 1 << (config1 & 0x07); + boot_cpu_data.dcache.sets = 1 << ((config1 >> 6) & 0x0f); + boot_cpu_data.dcache.linesz = 1 << (tmp + 1); + } + + if ((cpu_id >= NR_CPU_NAMES) || (arch_id >= NR_ARCH_NAMES)) { + printk ("Unknown CPU configuration (ID %02x, arch %02x), " + "continuing anyway...\n", + cpu_id, arch_id); + return; + } + + printk ("CPU: %s [%02x] revision %d (%s revision %d)\n", + cpu_names[cpu_id], cpu_id, cpu_rev, + arch_names[arch_id], arch_rev); + printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]); + printk ("CPU: features:"); + if (config0 & (1 << 6)) + printk(" fpu"); + if (config0 & (1 << 5)) + printk(" java"); + if (config0 & (1 << 4)) + printk(" perfctr"); + if (config0 & (1 << 3)) + printk(" ocd"); + printk("\n"); +} + +#ifdef CONFIG_PROC_FS +static int c_show(struct seq_file *m, void *v) +{ + unsigned int icache_size, dcache_size; + unsigned int cpu = smp_processor_id(); + + icache_size = boot_cpu_data.icache.ways * + boot_cpu_data.icache.sets * + boot_cpu_data.icache.linesz; + dcache_size = boot_cpu_data.dcache.ways * + boot_cpu_data.dcache.sets * + boot_cpu_data.dcache.linesz; + + seq_printf(m, "processor\t: %d\n", cpu); + + if (boot_cpu_data.arch_type < NR_ARCH_NAMES) + seq_printf(m, "cpu family\t: %s revision %d\n", + arch_names[boot_cpu_data.arch_type], + boot_cpu_data.arch_revision); + if (boot_cpu_data.cpu_type < NR_CPU_NAMES) + seq_printf(m, "cpu type\t: %s revision %d\n", + cpu_names[boot_cpu_data.cpu_type], + boot_cpu_data.cpu_revision); + + seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n", + icache_size >> 10, + boot_cpu_data.icache.ways, + boot_cpu_data.icache.sets, + boot_cpu_data.icache.linesz); + seq_printf(m, "d-cache\t\t: %dK (%u ways x %u sets x %u)\n", + dcache_size >> 10, + boot_cpu_data.dcache.ways, + boot_cpu_data.dcache.sets, + boot_cpu_data.dcache.linesz); + seq_printf(m, "bogomips\t: %lu.%02lu\n", + boot_cpu_data.loops_per_jiffy / (500000/HZ), + (boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < 1 ? (void *)1 : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} + +static void c_stop(struct seq_file *m, void *v) +{ + +} + +struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = c_show +}; +#endif /* CONFIG_PROC_FS */ diff -Nur linux-2.6.16.11/arch/avr32/kernel/dma-controller.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/dma-controller.c --- linux-2.6.16.11/arch/avr32/kernel/dma-controller.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/dma-controller.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,34 @@ +/* + * Preliminary DMA controller framework for AVR32 + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + +static LIST_HEAD(controllers); + +int register_dma_controller(struct dma_controller *dmac) +{ + static int next_id; + + dmac->id = next_id++; + list_add_tail(&dmac->list, &controllers); + + return 0; +} +EXPORT_SYMBOL(register_dma_controller); + +struct dma_controller *find_dma_controller(int id) +{ + struct dma_controller *dmac; + + list_for_each_entry(dmac, &controllers, list) + if (dmac->id == id) + return dmac; + return NULL; +} +EXPORT_SYMBOL(find_dma_controller); diff -Nur linux-2.6.16.11/arch/avr32/kernel/head.S linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/head.S --- linux-2.6.16.11/arch/avr32/kernel/head.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/head.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,46 @@ +/* + * Non-board-specific low-level startup code + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +#include +#include +#include + + .section .init.text,"ax" + .global kernel_entry +kernel_entry: + /* Initialize status register */ + lddpc r0, init_sr + mtsr SYSREG_SR, r0 + + /* Set initial stack pointer */ + lddpc sp, stack_addr + sub sp, -THREAD_SIZE + +#ifdef CONFIG_FRAME_POINTER + /* Mark last stack frame */ + mov lr, 0 + mov r7, 0 +#endif + + /* Set up the PIO, SDRAM controller, early printk, etc. */ + rcall board_early_init + + /* Start the show */ + lddpc pc, kernel_start_addr + + .align 2 +init_sr: + .long 0x007f0000 /* Supervisor mode, everything masked */ +stack_addr: + .long init_thread_union +kernel_start_addr: + .long start_kernel diff -Nur linux-2.6.16.11/arch/avr32/kernel/init_task.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/init_task.c --- linux-2.6.16.11/arch/avr32/kernel/init_task.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/init_task.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +struct mm_struct init_mm = INIT_MM(init_mm); + +EXPORT_SYMBOL(init_mm); + +/* + * Initial thread structure. Must be aligned on an 8192-byte boundary. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); + +EXPORT_SYMBOL(init_task); diff -Nur linux-2.6.16.11/arch/avr32/kernel/irq.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/irq.c --- linux-2.6.16.11/arch/avr32/kernel/irq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/irq.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * Based on arch/i386/kernel/irq.c + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + * + * IRQ's are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static unsigned int intc_err_count; +static spinlock_t intc_lock = SPIN_LOCK_UNLOCKED; + +static irqreturn_t no_grp_handler(int irq, void *dev_id, struct pt_regs *regs); + +static struct intc_group_desc no_group = { + .ctrl = NULL, + .handle = no_grp_handler, + .flags = 0, + .dev_id = NULL, + .devname = NULL, +}; + +/* + * Must be allocated statically because timer.c calls + * setup_internal_irq() before kmalloc() is ready. + */ +static struct intc_group_desc *group_desc[INTC_NUM_INT_GRPS] = { + [0 ... (INTC_NUM_INT_GRPS - 1)] = &no_group, +}; + +/* External IRQ controllers */ +static LIST_HEAD(irq_controllers); + +static irqreturn_t no_grp_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + if (++intc_err_count > 20) + panic("INTC: Too many IRQ errors!\n"); + printk(KERN_ERR "INTC: group %d has no handler!\n", irq); + disable_irq(irq); + return IRQ_HANDLED; +} + +asmlinkage void do_IRQ(int level, struct pt_regs *regs) +{ + struct intc_group_desc *grp; + unsigned int grp_id; + + grp_id = intc_readl(&intc, INTCAUSE0 - 4 * level); + + irq_enter(); + + grp = group_desc[grp_id]; + kstat_this_cpu.irqs[grp_id]++; + + if (grp->flags & SA_INTERRUPT) + local_irq_disable(); + grp->handle(grp_id, grp->dev_id, regs); + local_irq_enable(); + if (grp->flags & SA_SAMPLE_RANDOM) + add_interrupt_randomness(grp_id); + + irq_exit(); +} + +int setup_internal_irq(unsigned int irq, struct intc_group_desc *new) +{ + int err; + unsigned long flags; + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + spin_lock_irqsave(&intc_lock, flags); + + err = -EBUSY; + if (likely(group_desc[irq] == &no_group)) { + err = 0; + group_desc[irq] = new; + } + + spin_unlock_irqrestore(&intc_lock, flags); + return err; +} + +int request_internal_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, void *dev_id) +{ + struct intc_group_desc *grp; + int err; + + if (irq > intc.nr_groups || !handler) + return -EINVAL; + + grp = kmalloc(sizeof(*grp), GFP_ATOMIC); + if (!grp) + return -ENOMEM; + + grp->handle = handler; + grp->flags = irqflags; + grp->dev_id = dev_id; + grp->devname = devname; + + err = setup_internal_irq(irq, grp); + if (err) + kfree(grp); + return err; +} + +void free_internal_irq(unsigned int irq) +{ + struct intc_group_desc *grp; + unsigned long flags; + + spin_lock_irqsave(&intc_lock, flags); + grp = group_desc[irq]; + group_desc[irq] = &no_group; + spin_unlock_irqrestore(&intc_lock, flags); + + if (grp == &no_group) { + printk(KERN_ERR "INTC: Trying to free free IRQ%d\n", irq); + dump_stack(); + } else { + kfree(grp); + } +} + +unsigned long intc_get_pending(unsigned int group) +{ + return intc_readl(&intc, INTREQ0 + 4 * group); +} + +static struct irq_controller *find_controller(unsigned int irq) +{ + struct irq_controller *ctrl; + + list_for_each_entry(ctrl, &irq_controllers, list) { + if (ctrl->first_irq <= irq + && (ctrl->first_irq + ctrl->nr_irqs) > irq) + break; + } + + if (&ctrl->list == &irq_controllers) + ctrl = NULL; + + return ctrl; +} + +static int setup_irq(unsigned int irq, struct irqaction *new) +{ + struct irq_controller *ctrl; + + ctrl = find_controller(irq); + + if (!ctrl) { + printk(KERN_ERR + "setup_irq: No controller for interrupt %u\n", irq); + return -EINVAL; + } + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + return ctrl->class->setup(ctrl, irq, new); +} + +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irq_flags, const char *devname, void *dev_id) +{ + struct irqaction *action; + int retval; + + if (irq >= NR_IRQS || !handler) + return -EINVAL; + + if (irq < NR_INTERNAL_IRQS) + return request_internal_irq(irq, handler, irq_flags, + devname, dev_id); + + action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irq_flags; + cpus_clear(action->mask); + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; +} +EXPORT_SYMBOL(request_irq); + +void free_irq(unsigned int irq, void *dev_id) +{ + if (irq < NR_INTERNAL_IRQS) { + free_internal_irq(irq); + } else { + /* TODO: is kfree needed for the action in request_irq? */ + struct irq_controller *ctrl; + + ctrl = find_controller(irq); + if (!ctrl) { + printk(KERN_ERR + "free_irq: IRQ%u has no controller\n", irq); + dump_stack(); + return; + } + + ctrl->class->free(ctrl, irq, dev_id); + } +} +EXPORT_SYMBOL(free_irq); + +int irq_set_type(unsigned int irq, unsigned int type) +{ + struct irq_controller *ctrl; + + ctrl = find_controller(irq); + if (ctrl && ctrl->class->set_type) + return ctrl->class->set_type(ctrl, irq, type); + return -EINVAL; +} +EXPORT_SYMBOL(irq_set_type); + +unsigned int irq_get_type(unsigned int irq) +{ + struct irq_controller *ctrl; + + ctrl = find_controller(irq); + if (ctrl && ctrl->class->get_type) + return ctrl->class->get_type(ctrl, irq); + + return IRQ_TYPE_LEVEL | IRQ_LEVEL_HIGH; +} +EXPORT_SYMBOL(irq_get_type); + +void disable_irq(unsigned int irq) +{ + struct irq_controller *ctrl; + + ctrl = find_controller(irq); + + if (ctrl && ctrl->class->mask) + ctrl->class->mask(ctrl, irq); + else + printk(KERN_WARNING "IRQ: cannot mask interrupt %u\n", irq); +} + +void enable_irq(unsigned int irq) +{ + struct irq_controller *ctrl; + + ctrl = find_controller(irq); + + if (ctrl && ctrl->class->unmask) + ctrl->class->unmask(ctrl, irq); + else + printk(KERN_WARNING "IRQ: cannot unmask interrupt %u\n", irq); +} + +unsigned long probe_irq_on(void) +{ + printk(KERN_WARNING "Warning: probe_irq_on() called\n"); + return 0; +} + +int probe_irq_off(unsigned long irqs) +{ + printk(KERN_WARNING "Warning: probe_irq_off() called\n"); + return -1; +} + +int intc_register_controller(struct irq_controller *ctrl) +{ + unsigned int next_irq; + unsigned long flags; + + spin_lock_irqsave(&intc_lock, flags); + next_irq = NR_INTERNAL_IRQS; + if (!list_empty(&irq_controllers)) { + struct irq_controller *last; + last = list_entry(irq_controllers.prev, + struct irq_controller, list); + next_irq = last->first_irq + last->nr_irqs; + } + + ctrl->first_irq = next_irq; + list_add_tail(&ctrl->list, &irq_controllers); + + spin_unlock_irqrestore(&intc_lock, flags); + + return request_internal_irq(ctrl->irq_group, ctrl->class->handle, + 0, ctrl->class->typename, ctrl); +} + +#if 0 +int irq_set_priority(unsigned int group, unsigned int priority) +{ + extern void _evba(void); + extern void irq_level0(void); + extern void irq_level1(void); + extern void irq_level2(void); + extern void irq_level3(void); + struct irq_group *grp; + unsigned long prio = ~0UL, readback; + int flags, err = 0; + + if (priority > 3 || group >= NR_IRQ_GROUPS) + return -EINVAL; + + switch (priority) { + case 0: + prio = (unsigned long)&irq_level0; + break; + case 1: + prio = (unsigned long)&irq_level1; + break; + case 2: + prio = (unsigned long)&irq_level2; + break; + case 3: + prio = (unsigned long)&irq_level3; + break; + } + + prio -= (unsigned long)&_evba; + prio |= (priority << 30); + + spin_lock_irqsave(&irq_lock, flags); + irqc_writel(prio, IRQ_INTPRI + 4 * group); + readback = irqc_readl(IRQ_INTPRI + 4 * group); + BUG_ON(prio != readback); + + grp = irq_group[group]; + BUG_ON(!grp); + grp->priority = priority; + + spin_unlock_irqrestore(&irq_lock, flags); + + return err; +} +#endif + +#ifdef CONFIG_PROC_FS +int show_interrupts(struct seq_file *p, void *v) +{ + int i = *(loff_t *)v, j; + unsigned long flags; + + if (i == 0) { + seq_puts(p, " "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "CPU%d ", j); + seq_putc(p, '\n'); + } + + if (i < intc.nr_groups) { + struct intc_group_desc *grp; + const char *name; + + spin_lock_irqsave(&intc_lock, flags); + grp = group_desc[i]; + + name = grp->devname; + if (!name) + goto unlock; + + seq_printf(p, "%3d: ", i); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); + seq_printf(p, " %-8s", grp->devname); + seq_putc(p, '\n'); + unlock: + spin_unlock_irqrestore(&intc_lock, flags); + } + + return 0; +} + +#ifdef CONFIG_SYSCTL +void init_irq_proc(void) +{ + +} +#endif +#endif diff -Nur linux-2.6.16.11/arch/avr32/kernel/kprobes.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/kprobes.c --- linux-2.6.16.11/arch/avr32/kernel/kprobes.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/kprobes.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,275 @@ +/* + * Kernel Probes (KProbes) + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * Based on arch/ppc64/kernel/kprobes.c + * Copyright (C) IBM Corporation, 2002, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include + +#include +#include +#include + +static struct kprobe *current_kprobe; +static unsigned long kprobe_status; +static struct pt_regs jprobe_saved_regs; + +int __kprobes arch_prepare_kprobe(struct kprobe *p) +{ + int ret = 0; + + if ((unsigned long)p->addr & 0x01) { + printk("Attempt to register kprobe at an unaligned address\n"); + ret = -EINVAL; + } + + /* XXX: Might be a good idea to check if p->addr is a valid + * kernel address as well... */ + + return ret; +} + +void __kprobes arch_copy_kprobe(struct kprobe *p) +{ + pr_debug("copy kprobe at %p\n", p->addr); + memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); + p->opcode = *p->addr; +} + +void __kprobes arch_arm_kprobe(struct kprobe *p) +{ + pr_debug("arming kprobe at %p\n", p->addr); + *p->addr = BREAKPOINT_INSTRUCTION; + flush_icache_range((unsigned long)p->addr, + (unsigned long)p->addr + sizeof(kprobe_opcode_t)); +} + +void __kprobes arch_disarm_kprobe(struct kprobe *p) +{ + pr_debug("disarming kprobe at %p\n", p->addr); + *p->addr = p->opcode; + flush_icache_range((unsigned long)p->addr, + (unsigned long)p->addr + sizeof(kprobe_opcode_t)); +} + +void __kprobes arch_remove_kprobe(struct kprobe *p) +{ + +} + +static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long dc; + + pr_debug("preparing to singlestep over %p (PC=%08lx)\n", + p->addr, regs->pc); + + BUG_ON(!(sysreg_read(SR) & SYSREG_BIT(SR_D))); + + dc = __mfdr(DBGREG_DC); + dc |= DC_SS; + __mtdr(DBGREG_DC, dc); + + /* + * We must run the instruction from its original location + * since it may actually reference PC. + * + * TODO: Do the instruction replacement directly in icache. + */ + *p->addr = p->opcode; + flush_icache_range((unsigned long)p->addr, + (unsigned long)p->addr + sizeof(kprobe_opcode_t)); +} + +static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long dc; + + pr_debug("resuming execution at PC=%08lx\n", regs->pc); + + dc = __mfdr(DBGREG_DC); + dc &= ~DC_SS; + __mtdr(DBGREG_DC, dc); + + *p->addr = BREAKPOINT_INSTRUCTION; + flush_icache_range((unsigned long)p->addr, + (unsigned long)p->addr + sizeof(kprobe_opcode_t)); +} + +static int __kprobes kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *p; + void *addr = (void *)regs->pc; + int ret = 0; + + pr_debug("kprobe_handler: kprobe_running=%d\n", + kprobe_running()); + + /* Check that we're not recursing */ + if (kprobe_running()) { + /* We *are* holding lock here, so this is safe. + Disarm the probe we just hit, and ignore it. */ + p = get_kprobe(addr); + if (p) { + if (kprobe_status == KPROBE_HIT_SS) { + printk("FIXME: kprobe hit while single-stepping!\n"); + goto no_kprobe; + } + + printk("FIXME: kprobe hit while handling another kprobe\n"); + goto no_kprobe; + } else { + p = current_kprobe; + if (p->break_handler && p->break_handler(p, regs)) + goto ss_probe; + } + /* If it's not ours, can't be delete race, (we hold lock). */ + goto no_kprobe; + } + + lock_kprobes(); + p = get_kprobe(addr); + if (!p) + goto unlock_no_kprobe; + + kprobe_status = KPROBE_HIT_ACTIVE; + current_kprobe = p; + if (p->pre_handler && p->pre_handler(p, regs)) + /* handler has already set things up, so skip ss setup */ + return 1; + +ss_probe: + prepare_singlestep(p, regs); + kprobe_status = KPROBE_HIT_SS; + /* + * This preempt_disable() matches the preempt_enable_no_resched() + * in post_kprobe_handler(). + */ + preempt_disable(); + return 1; + +unlock_no_kprobe: + unlock_kprobes(); +no_kprobe: + return ret; +} + +static int __kprobes post_kprobe_handler(struct pt_regs *regs) +{ + pr_debug("post_kprobe_handler, kprobe_running=%d\n", + kprobe_running()); + + if (!kprobe_running()) + return 0; + + if (current_kprobe->post_handler) { + kprobe_status = KPROBE_HIT_SSDONE; + current_kprobe->post_handler(current_kprobe, regs, 0); + } + + resume_execution(current_kprobe, regs); + unlock_kprobes(); + preempt_enable_no_resched(); + return 1; +} + +static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + pr_debug("kprobe_fault_handler: trapnr=%d\n", trapnr); + + if (current_kprobe->fault_handler + && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + return 1; + + if (kprobe_status & KPROBE_HIT_SS) { + resume_execution(current_kprobe, regs); + unlock_kprobes(); + preempt_enable_no_resched(); + } + return 0; +} + +/* + * Wrapper routine to for handling exceptions. + */ +int __kprobes kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + struct die_args *args = (struct die_args *)data; + int ret = NOTIFY_DONE; + + pr_debug("kprobe_exceptions_notify: val=%lu, data=%p\n", + val, data); + + switch (val) { + case DIE_BREAKPOINT: + if (kprobe_handler(args->regs)) + ret = NOTIFY_STOP; + break; + case DIE_SSTEP: + if (post_kprobe_handler(args->regs)) + ret = NOTIFY_STOP; + break; + case DIE_FAULT: + if (kprobe_running() + && kprobe_fault_handler(args->regs, args->trapnr)) + ret = NOTIFY_STOP; + break; + default: + break; + } + + return ret; +} + +int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct jprobe *jp = container_of(p, struct jprobe, kp); + + memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs)); + + /* + * TODO: We should probably save some of the stack here as + * well, since gcc may pass arguments on the stack for certain + * functions (lots of arguments, large aggregates, varargs) + */ + + /* setup return addr to the jprobe handler routine */ + regs->pc = (unsigned long)jp->entry; + return 1; +} + +void __kprobes jprobe_return(void) +{ + asm volatile("breakpoint" ::: "memory"); +} + +int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) +{ + /* + * FIXME - we should ideally be validating that we got here 'cos + * of the "trap" in jprobe_return() above, before restoring the + * saved regs... + */ + memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); + return 1; +} + +int __init arch_init_kprobes(void) +{ + printk("KPROBES: Enabling monitor mode (MM|DBE)...\n"); + __mtdr(DBGREG_DC, DC_MM | DC_DBE); + + /* TODO: Register kretprobe trampoline */ + return 0; +} diff -Nur linux-2.6.16.11/arch/avr32/kernel/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/Makefile --- linux-2.6.16.11/arch/avr32/kernel/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/Makefile 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,17 @@ +# +# Makefile for the Linux/AVR32 kernel. +# + +extra-y := head.o vmlinux.lds + +obj-y := syscall_table.o irq.o setup.o +obj-y += traps.o semaphore.o ptrace.o signal.o syscall-stubs.o +obj-y += sys_avr32.o process.o time.o init_task.o switch_to.o +obj-y += cpu.o dma-controller.o +obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o +obj-$(CONFIG_KPROBES) += kprobes.o + +USE_STANDARD_AS_RULE := true + +%.lds: %.lds.c FORCE + $(call if_changed_dep,cpp_lds_S) diff -Nur linux-2.6.16.11/arch/avr32/kernel/module.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/module.c --- linux-2.6.16.11/arch/avr32/kernel/module.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/module.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,325 @@ +/* + * AVR32-specific kernel module loader + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * GOT initialization parts are based on the s390 version + * Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH, + * IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + +void module_free(struct module *mod, void *module_region) +{ + vfree(mod->arch.syminfo); + mod->arch.syminfo = NULL; + + vfree(module_region); + /* FIXME: if module_region == mod->init_region, trim exception + * table entries. */ +} + +static inline int check_rela(Elf32_Rela *rela, struct module *module, + char *strings, Elf32_Sym *symbols) +{ + struct mod_arch_syminfo *info; + + info = module->arch.syminfo + ELF32_R_SYM(rela->r_info); + switch (ELF32_R_TYPE(rela->r_info)) { + case R_AVR32_GOT32: + case R_AVR32_GOT16: + case R_AVR32_GOT8: + case R_AVR32_GOT21S: + case R_AVR32_GOT18SW: /* mcall */ + case R_AVR32_GOT16S: /* ld.w */ + if (rela->r_addend != 0) { + printk(KERN_ERR + "GOT relocation against %s at offset %u with addend\n", + strings + symbols[ELF32_R_SYM(rela->r_info)].st_name, + rela->r_offset); + return -ENOEXEC; + } + if (info->got_offset == -1UL) { + info->got_offset = module->arch.got_size; + module->arch.got_size += sizeof(void *); + } + pr_debug("GOT[%3lu] %s\n", info->got_offset, + strings + symbols[ELF32_R_SYM(rela->r_info)].st_name); + break; + } + + return 0; +} + +int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, + char *secstrings, struct module *module) +{ + Elf32_Shdr *symtab; + Elf32_Sym *symbols; + Elf32_Rela *rela; + char *strings; + int nrela, i, j; + int ret; + + /* Find the symbol table */ + symtab = NULL; + for (i = 0; i < hdr->e_shnum; i++) + switch (sechdrs[i].sh_type) { + case SHT_SYMTAB: + symtab = &sechdrs[i]; + break; + } + if (!symtab) { + printk(KERN_ERR "module %s: no symbol table\n", module->name); + return -ENOEXEC; + } + + /* Allocate room for one syminfo structure per symbol. */ + module->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym); + module->arch.syminfo = vmalloc(module->arch.nsyms + * sizeof(struct mod_arch_syminfo)); + if (!module->arch.syminfo) + return -ENOMEM; + + symbols = (void *)hdr + symtab->sh_offset; + strings = (void *)hdr + sechdrs[symtab->sh_link].sh_offset; + for (i = 0; i < module->arch.nsyms; i++) { + if (symbols[i].st_shndx == SHN_UNDEF && + strcmp(strings + symbols[i].st_name, + "_GLOBAL_OFFSET_TABLE_") == 0) + /* "Define" it as absolute. */ + symbols[i].st_shndx = SHN_ABS; + module->arch.syminfo[i].got_offset = -1UL; + module->arch.syminfo[i].got_initialized = 0; + } + + /* Allocate GOT entries for symbols that need it. */ + module->arch.got_size = 0; + for (i = 0; i < hdr->e_shnum; i++) { + if (sechdrs[i].sh_type != SHT_RELA) + continue; + nrela = sechdrs[i].sh_size / sizeof(Elf32_Rela); + rela = (void *)hdr + sechdrs[i].sh_offset; + for (j = 0; j < nrela; j++) { + ret = check_rela(rela + j, module, + strings, symbols); + if (ret) + goto out_free_syminfo; + } + } + + /* + * Increase core size to make room for GOT and set start + * offset for GOT. + */ + module->core_size = ALIGN(module->core_size, 4); + module->arch.got_offset = module->core_size; + module->core_size += module->arch.got_size; + + return 0; + +out_free_syminfo: + vfree(module->arch.syminfo); + module->arch.syminfo = NULL; + + return ret; +} + +static inline int reloc_overflow(struct module *module, const char *reloc_name, + Elf32_Addr relocation) +{ + printk(KERN_ERR "module %s: Value %lx does not fit relocation %s\n", + module->name, (unsigned long)relocation, reloc_name); + return -ENOEXEC; +} + +#define get_u16(loc) (*((uint16_t *)loc)) +#define put_u16(loc, val) (*((uint16_t *)loc) = (val)) + +int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relindex, + struct module *module) +{ + Elf32_Shdr *symsec = sechdrs + symindex; + Elf32_Shdr *relsec = sechdrs + relindex; + Elf32_Shdr *dstsec = sechdrs + relsec->sh_info; + Elf32_Rela *rel = (void *)relsec->sh_addr; + unsigned int i; + int ret = 0; + + for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rela); i++, rel++) { + struct mod_arch_syminfo *info; + Elf32_Sym *sym; + Elf32_Addr relocation; + uint32_t *location; + uint32_t value; + + location = (void *)dstsec->sh_addr + rel->r_offset; + sym = (Elf32_Sym *)symsec->sh_addr + ELF32_R_SYM(rel->r_info); + relocation = sym->st_value + rel->r_addend; + + info = module->arch.syminfo + ELF32_R_SYM(rel->r_info); + + /* Initialize GOT entry if necessary */ + switch (ELF32_R_TYPE(rel->r_info)) { + case R_AVR32_GOT32: + case R_AVR32_GOT16: + case R_AVR32_GOT8: + case R_AVR32_GOT21S: + case R_AVR32_GOT18SW: + case R_AVR32_GOT16S: + if (!info->got_initialized) { + Elf32_Addr *gotent; + + gotent = (module->module_core + + module->arch.got_offset + + info->got_offset); + *gotent = relocation; + info->got_initialized = 1; + } + + relocation = info->got_offset; + break; + } + + switch (ELF32_R_TYPE(rel->r_info)) { + case R_AVR32_32: + case R_AVR32_32_CPENT: + *location = relocation; + break; + case R_AVR32_22H_PCREL: + relocation -= (Elf32_Addr)location; + if ((relocation & 0xffe00001) != 0 + && (relocation & 0xffc00001) != 0xffc00000) + return reloc_overflow(module, + "R_AVR32_22H_PCREL", + relocation); + relocation >>= 1; + + value = *location; + value = ((value & 0xe1ef0000) + | (relocation & 0xffff) + | ((relocation & 0x10000) << 4) + | ((relocation & 0x1e0000) << 8)); + *location = value; + break; + case R_AVR32_11H_PCREL: + relocation -= (Elf32_Addr)location; + if ((relocation & 0xfffffc01) != 0 + && (relocation & 0xfffff801) != 0xfffff800) + return reloc_overflow(module, + "R_AVR32_11H_PCREL", + relocation); + value = get_u16(location); + value = ((value & 0xf00c) + | ((relocation & 0x1fe) << 3) + | ((relocation & 0x600) >> 9)); + put_u16(location, value); + break; + case R_AVR32_9H_PCREL: + relocation -= (Elf32_Addr)location; + if ((relocation & 0xffffff01) != 0 + && (relocation & 0xfffffe01) != 0xfffffe00) + return reloc_overflow(module, + "R_AVR32_9H_PCREL", + relocation); + value = get_u16(location); + value = ((value & 0xf00f) + | ((relocation & 0x1fe) << 3)); + put_u16(location, value); + break; + case R_AVR32_9UW_PCREL: + relocation -= ((Elf32_Addr)location) & 0xfffffffc; + if ((relocation & 0xfffffc03) != 0) + return reloc_overflow(module, + "R_AVR32_9UW_PCREL", + relocation); + value = get_u16(location); + value = ((value & 0xf80f) + | ((relocation & 0x1fc) << 2)); + put_u16(location, value); + break; + case R_AVR32_GOTPC: + /* + * R6 = PC - (PC - GOT) + * + * At this point, relocation contains the + * value of PC. Just subtract the value of + * GOT, and we're done. + */ + pr_debug("GOTPC: PC=0x%lx, got_offset=0x%lx, core=0x%p\n", + relocation, module->arch.got_offset, + module->module_core); + relocation -= ((unsigned long)module->module_core + + module->arch.got_offset); + *location = relocation; + break; + case R_AVR32_GOT18SW: + if ((relocation & 0xfffe0003) != 0 + && (relocation & 0xfffc0003) != 0xffff0000) + return reloc_overflow(module, "R_AVR32_GOT18SW", + relocation); + relocation >>= 2; + /* fall through */ + case R_AVR32_GOT16S: + if ((relocation & 0xffff8000) != 0 + && (relocation & 0xffff0000) != 0xffff0000) + return reloc_overflow(module, "R_AVR32_GOT16S", + relocation); + pr_debug("GOT reloc @ 0x%lx -> %lu\n", + rel->r_offset, relocation); + value = *location; + value = ((value & 0xffff0000) + | (relocation & 0xffff)); + *location = value; + break; + + default: + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + module->name, ELF32_R_TYPE(rel->r_info)); + return -ENOEXEC; + } + } + + return ret; +} + +int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relindex, + struct module *module) +{ + printk(KERN_ERR "module %s: REL relocations are not supported\n", + module->name); + return -ENOEXEC; +} + +int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, + struct module *module) +{ + vfree(module->arch.syminfo); + module->arch.syminfo = NULL; + + return 0; +} + +void module_arch_cleanup(struct module *module) +{ + +} diff -Nur linux-2.6.16.11/arch/avr32/kernel/process.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/process.c --- linux-2.6.16.11/arch/avr32/kernel/process.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/process.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +void (*pm_power_off)(void) = NULL; +EXPORT_SYMBOL(pm_power_off); + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + while (1) { + /* TODO: Enter sleep mode */ + if (need_resched()) + schedule(); + } +} + +void machine_halt(void) +{ +} + +void machine_power_off(void) +{ +} + +void machine_restart(char *cmd) +{ + __mtdr(DBGREG_DC, 0x40002000); + while (1) ; +} + +/* + * PC is actually discarded when returning from a system call -- the + * return address must be stored in LR. This function will make sure + * LR points to do_exit before starting the thread. + * + * Also, when returning from fork(), r12 is 0, so we must copy the + * argument as well. + * + * r0 : The argument to the main thread function + * r1 : The address of do_exit + * r2 : The address of the main thread function + */ +asmlinkage extern void kernel_thread_helper(void); +__asm__(" .type kernel_thread_helper, @function\n" + "kernel_thread_helper:\n" + " mov r12, r0\n" + " mov lr, r2\n" + " mov pc, r1\n" + " .size kernel_thread_helper, . - kernel_thread_helper"); + +int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof(regs)); + + regs.r0 = (unsigned long)arg; + regs.r1 = (unsigned long)fn; + regs.r2 = (unsigned long)do_exit; + regs.lr = (unsigned long)kernel_thread_helper; + regs.pc = (unsigned long)kernel_thread_helper; + regs.sr = MODE_SUPERVISOR; + + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, + 0, ®s, 0, NULL, NULL); +} + +/* + * Free current thread data structures etc + */ +void exit_thread(void) +{ + /* nothing to do */ +} + +void flush_thread(void) +{ + /* nothing to do */ +} + +void release_thread(struct task_struct *dead_task) +{ + /* do nothing */ +} + +static const char *cpu_modes[] = { + "Application", "Supervisor", "Interrupt level 0", "Interrupt level 1", + "Interrupt level 2", "Interrupt level 3", "Exception", "NMI" +}; + +void show_regs(struct pt_regs *regs) +{ + unsigned long sp = regs->sp; + unsigned long lr = regs->lr; + unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT; + + if (!user_mode(regs)) + sp = (unsigned long)regs + FRAME_SIZE_FULL; + + print_symbol("PC is at %s\n", instruction_pointer(regs)); + print_symbol("LR is at %s\n", lr); + printk("pc : [<%08lx>] lr : [<%08lx>] %s\n" + "sp : %08lx r12: %08lx r11: %08lx\n", + instruction_pointer(regs), + lr, print_tainted(), sp, regs->r12, regs->r11); + printk("r10: %08lx r9 : %08lx r8 : %08lx\n", + regs->r10, regs->r9, regs->r8); + printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", + regs->r7, regs->r6, regs->r5, regs->r4); + printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", + regs->r3, regs->r2, regs->r1, regs->r0); + printk("Flags: %c%c%c%c%c\n", + regs->sr & SR_Q ? 'Q' : 'q', + regs->sr & SR_V ? 'V' : 'v', + regs->sr & SR_N ? 'N' : 'n', + regs->sr & SR_Z ? 'Z' : 'z', + regs->sr & SR_C ? 'C' : 'c'); + printk("Mode bits: %c%c%c%c%c%c%c%c%c\n", + regs->sr & SR_H ? 'H' : 'h', + regs->sr & SR_R ? 'R' : 'r', + regs->sr & SR_J ? 'J' : 'j', + regs->sr & SR_EM ? 'E' : 'e', + regs->sr & SR_I3M ? '3' : '.', + regs->sr & SR_I2M ? '2' : '.', + regs->sr & SR_I1M ? '1' : '.', + regs->sr & SR_I0M ? '0' : '.', + regs->sr & SR_GM ? 'G' : 'g'); + printk("CPU Mode: %s\n", cpu_modes[mode]); + + show_trace(NULL, (unsigned long *)sp, regs); +} +EXPORT_SYMBOL(show_regs); + +/* Fill in the fpu structure for a core dump. This is easy -- we don't have any */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) +{ + /* Not valid */ + return 0; +} + +asmlinkage void ret_from_fork(void); + +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct *p, struct pt_regs *regs) +{ + struct pt_regs *childregs; + + childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)p->thread_info)) - 1; + *childregs = *regs; + + if (user_mode(regs)) + childregs->sp = usp; + else + childregs->sp = (unsigned long)p->thread_info + THREAD_SIZE; + + childregs->r12 = 0; /* Set return value for child */ + + p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM; + p->thread.cpu_context.ksp = (unsigned long)childregs; + p->thread.cpu_context.pc = (unsigned long)ret_from_fork; + + return 0; +} + +/* r12-r8 are dummy parameters to force the compiler to use the stack */ +asmlinkage int sys_fork(struct pt_regs *regs) +{ + return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); +} + +asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, + unsigned long parent_tidptr, + unsigned long child_tidptr, struct pt_regs *regs) +{ + if (!newsp) + newsp = regs->sp; + return do_fork(clone_flags, newsp, regs, 0, + (int __user *)parent_tidptr, + (int __user *)child_tidptr); +} + +asmlinkage int sys_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, + 0, NULL, NULL); +} + +asmlinkage int sys_execve(char __user *ufilename, char __user *__user *uargv, + char __user *__user *uenvp, struct pt_regs *regs) +{ + int error; + char *filename; + + filename = getname(ufilename); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + + error = do_execve(filename, uargv, uenvp, regs); + if (error == 0) + current->ptrace &= ~PT_DTRACE; + putname(filename); + +out: + return error; +} + + +/* + * This function is supposed to answer the question "who called + * schedule()?" + */ +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long pc; + unsigned long stack_page; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)p->thread_info; + BUG_ON(!stack_page); + + /* + * The stored value of PC is either the address right after + * the call to __switch_to() or ret_from_fork. + */ + pc = thread_saved_pc(p); + if (in_sched_functions(pc)) { +#ifdef CONFIG_FRAME_POINTER + unsigned long fp = p->thread.cpu_context.r7; + BUG_ON(fp < stack_page || fp > (THREAD_SIZE + stack_page)); + pc = *(unsigned long *)fp; +#else + /* + * We depend on the frame size of schedule here, which + * is actually quite ugly. It might be possible to + * determine the frame size automatically at build + * time by doing this: + * - compile sched.c + * - disassemble the resulting sched.o + * - look for 'sub sp,??' shortly after ':' + */ + unsigned long sp = p->thread.cpu_context.ksp + 16; + BUG_ON(sp < stack_page || sp > (THREAD_SIZE + stack_page)); + pc = *(unsigned long *)sp; +#endif + } + + return pc; +} diff -Nur linux-2.6.16.11/arch/avr32/kernel/ptrace.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/ptrace.c --- linux-2.6.16.11/arch/avr32/kernel/ptrace.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/ptrace.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static struct pt_regs *get_user_regs(struct task_struct *tsk) +{ + return (struct pt_regs *)((unsigned long) tsk->thread_info + + THREAD_SIZE - sizeof(struct pt_regs)); +} + +static void ptrace_single_step(struct task_struct *tsk) +{ + pr_debug("ptrace_single_step: pid=%u, SR=0x%08lx\n", + tsk->pid, tsk->thread.cpu_context.sr); + if (!(tsk->thread.cpu_context.sr & SR_D)) { + /* + * Set a breakpoint at the current pc to force the + * process into debug mode. The syscall/exception + * exit code will set a breakpoint at the return + * address when this flag is set. + */ + pr_debug("ptrace_single_step: Setting TIF_BREAKPOINT\n"); + set_tsk_thread_flag(tsk, TIF_BREAKPOINT); + } + + /* The monitor code will do the actual step for us */ + set_tsk_thread_flag(tsk, TIF_SINGLE_STEP); +} + +/* + * Called by kernel/ptrace.c when detaching + * + * Make sure any single step bits, etc. are not set + */ +void ptrace_disable(struct task_struct *child) +{ + clear_tsk_thread_flag(child, TIF_SINGLE_STEP); +} + +/* + * Handle hitting a breakpoint + */ +static void ptrace_break(struct task_struct *tsk, struct pt_regs *regs) +{ + siginfo_t info; + + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void __user *)instruction_pointer(regs); + + pr_debug("ptrace_break: Sending SIGTRAP to PID %u (pc = 0x%p)\n", + tsk->pid, info.si_addr); + force_sig_info(SIGTRAP, &info, tsk); +} + +/* + * Read the word at offset "offset" into the task's "struct user". We + * actually access the pt_regs struct stored on the kernel stack. + */ +static int ptrace_read_user(struct task_struct *tsk, unsigned long offset, + unsigned long __user *data) +{ + unsigned long *regs; + unsigned long value; + + pr_debug("ptrace_read_user(%p, %#lx, %p)\n", + tsk, offset, data); + + if (offset & 3 || offset >= sizeof(struct user)) { + printk("ptrace_read_user: invalid offset 0x%08lx\n", offset); + return -EIO; + } + + regs = (unsigned long *)get_user_regs(tsk); + + value = 0; + if (offset < sizeof(struct pt_regs)) + value = regs[offset / sizeof(regs[0])]; + + return put_user(value, data); +} + +/* + * Write the word "value" to offset "offset" into the task's "struct + * user". We actually access the pt_regs struct stored on the kernel + * stack. + */ +static int ptrace_write_user(struct task_struct *tsk, unsigned long offset, + unsigned long value) +{ + unsigned long *regs; + + if (offset & 3 || offset >= sizeof(struct user)) { + printk("ptrace_write_user: invalid offset 0x%08lx\n", offset); + return -EIO; + } + + if (offset >= sizeof(struct pt_regs)) + return 0; + + regs = (unsigned long *)get_user_regs(tsk); + regs[offset / sizeof(regs[0])] = value; + + return 0; +} + +static int ptrace_getregs(struct task_struct *tsk, void __user *uregs) +{ + struct pt_regs *regs = get_user_regs(tsk); + + return copy_to_user(uregs, regs, sizeof(*regs)) ? -EFAULT : 0; +} + +static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs) +{ + struct pt_regs newregs; + int ret; + + ret = -EFAULT; + if (copy_from_user(&newregs, uregs, sizeof(newregs)) == 0) { + struct pt_regs *regs = get_user_regs(tsk); + + ret = -EINVAL; + if (valid_user_regs(&newregs)) { + *regs = newregs; + ret = 0; + } + } + + return ret; +} + +long arch_ptrace(struct task_struct *child, long request, long addr, long data) +{ + unsigned long tmp; + int ret; + + pr_debug("arch_ptrace(%ld, %ld, %#lx, %#lx)\n", + request, child->pid, addr, data); + + pr_debug("ptrace: Enabling monitor mode...\n"); + __mtdr(DBGREG_DC, __mfdr(DBGREG_DC) | DC_MM | DC_DBE); + + switch (request) { + /* Read the word at location addr in the child process */ + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + if (ret == sizeof(tmp)) + ret = put_user(tmp, (unsigned long __user *)data); + else + ret = -EIO; + break; + + case PTRACE_PEEKUSR: + ret = ptrace_read_user(child, addr, + (unsigned long __user *)data); + break; + + /* Write the word in data at location addr */ + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + ret = access_process_vm(child, addr, &data, sizeof(data), 1); + if (ret == sizeof(data)) + ret = 0; + else + ret = -EIO; + break; + + case PTRACE_POKEUSR: + ret = ptrace_write_user(child, addr, data); + break; + + /* continue and stop at next (return from) syscall */ + case PTRACE_SYSCALL: + /* restart after signal */ + case PTRACE_CONT: + ret = -EIO; + if (!valid_signal(data)) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + /* XXX: Are we sure no breakpoints are active here? */ + wake_up_process(child); + ret = 0; + break; + + /* + * Make the child exit. Best I can do is send it a + * SIGKILL. Perhaps it should be put in the status that it + * wants to exit. + */ + case PTRACE_KILL: + ret = 0; + if (child->exit_state == EXIT_ZOMBIE) + break; + child->exit_code = SIGKILL; + wake_up_process(child); + break; + + /* + * execute single instruction. + */ + case PTRACE_SINGLESTEP: + ret = -EIO; + if (!valid_signal(data)) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + ptrace_single_step(child); + child->exit_code = data; + wake_up_process(child); + ret = 0; + break; + + /* Detach a process that was attached */ + case PTRACE_DETACH: + ret = ptrace_detach(child, data); + break; + + case PTRACE_GETREGS: + ret = ptrace_getregs(child, (void __user *)data); + break; + + case PTRACE_SETREGS: + ret = ptrace_setregs(child, (const void __user *)data); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n", ret, __mfdr(DBGREG_DC)); + return ret; +} + +asmlinkage void syscall_trace(void) +{ + pr_debug("syscall_trace called\n"); + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + + pr_debug("syscall_trace: notifying parent\n"); + /* The 0x80 provides a way for the tracing parent to + * distinguish between a syscall stop and SIGTRAP delivery */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + + /* + * this isn't the same as continuing with a signal, but it + * will do for normal use. strace only continues with a + * signal if the stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + pr_debug("syscall_trace: sending signal %d to PID %u\n", + current->exit_code, current->pid); + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} + +asmlinkage void do_debug_priv(struct pt_regs *regs) +{ + unsigned long dc, ds; + unsigned long die_val; + + ds = __mfdr(DBGREG_DS); + + pr_debug("do_debug_priv: pc = %08lx, ds = %08lx\n", regs->pc, ds); + + if (ds & DS_SSS) + die_val = DIE_SSTEP; + else + die_val = DIE_BREAKPOINT; + + if (notify_die(die_val, regs, 0, SIGTRAP) == NOTIFY_STOP) + return; + + if (likely(ds & DS_SSS)) { + extern void itlb_miss(void); + extern void tlb_miss_common(void); + struct thread_info *ti; + + dc = __mfdr(DBGREG_DC); + dc &= ~DC_SS; + __mtdr(DBGREG_DC, dc); + + ti = current_thread_info(); + ti->flags |= _TIF_BREAKPOINT; + + /* The TLB miss handlers don't check thread flags */ + if ((regs->pc >= (unsigned long)&itlb_miss) + && (regs->pc <= (unsigned long)&tlb_miss_common)) { + __mtdr(DBGREG_BWA2A, sysreg_read(RAR_EX)); + __mtdr(DBGREG_BWC2A, 0x40000001 | (get_asid() << 1)); + } + + /* + * If we're running in supervisor mode, the breakpoint + * will take us where we want directly, no need to + * single step. + */ + if ((regs->sr & MODE_MASK) != MODE_SUPERVISOR) + ti->flags |= TIF_SINGLE_STEP; + } else { + panic("Unable to handle debug trap at pc = %08lx\n", + regs->pc); + } +} + +/* + * Handle breakpoints, single steps and other debuggy things. To keep + * things simple initially, we run with interrupts and exceptions + * disabled all the time. + */ +asmlinkage void do_debug(struct pt_regs *regs) +{ + unsigned long dc, ds; + + ds = __mfdr(DBGREG_DS); + pr_debug("do_debug: pc = %08lx, ds = %08lx\n", regs->pc, ds); + + if (test_thread_flag(TIF_BREAKPOINT)) { + pr_debug("TIF_BREAKPOINT set\n"); + /* We're taking care of it */ + clear_thread_flag(TIF_BREAKPOINT); + __mtdr(DBGREG_BWC2A, 0); + } + + if (test_thread_flag(TIF_SINGLE_STEP)) { + pr_debug("TIF_SINGLE_STEP set, ds = 0x%08lx\n", ds); + if (ds & DS_SSS) { + dc = __mfdr(DBGREG_DC); + dc &= ~DC_SS; + __mtdr(DBGREG_DC, dc); + + clear_thread_flag(TIF_SINGLE_STEP); + ptrace_break(current, regs); + } + } else { + /* regular breakpoint */ + ptrace_break(current, regs); + } +} diff -Nur linux-2.6.16.11/arch/avr32/kernel/semaphore.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/semaphore.c --- linux-2.6.16.11/arch/avr32/kernel/semaphore.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/semaphore.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,148 @@ +/* + * AVR32 sempahore implementation. + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * Based on linux/arch/i386/kernel/semaphore.c + * Copyright (C) 1999 Linus Torvalds + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include + +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to acquire the semaphore, while the "sleeping" + * variable is a count of such acquires. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * "sleeping" and the contention routine ordering is protected + * by the spinlock in the semaphore's waitqueue head. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ + +/* + * Logic: + * - only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - when we go from a non-negative count to a negative do we + * (a) synchronize with the "sleeper" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +void __up(struct semaphore *sem) +{ + wake_up(&sem->wait); +} +EXPORT_SYMBOL(__up); + +void __sched __down(struct semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + unsigned long flags; + + tsk->state = TASK_UNINTERRUPTIBLE; + spin_lock_irqsave(&sem->wait.lock, flags); + add_wait_queue_exclusive_locked(&sem->wait, &wait); + + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock in + * the wait_queue_head. + */ + if (atomic_add_return(sleepers - 1, &sem->count) >= 0) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irqrestore(&sem->wait.lock, flags); + + schedule(); + + spin_lock_irqsave(&sem->wait.lock, flags); + tsk->state = TASK_UNINTERRUPTIBLE; + } + remove_wait_queue_locked(&sem->wait, &wait); + wake_up_locked(&sem->wait); + spin_unlock_irqrestore(&sem->wait.lock, flags); + tsk->state = TASK_RUNNING; +} +EXPORT_SYMBOL(__down); + +int __sched __down_interruptible(struct semaphore *sem) +{ + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + unsigned long flags; + + tsk->state = TASK_INTERRUPTIBLE; + spin_lock_irqsave(&sem->wait.lock, flags); + add_wait_queue_exclusive_locked(&sem->wait, &wait); + + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into the trylock + * failure case - we won't be sleeping, and we can't + * get the lock as it has contention. Just correct the + * count and exit. + */ + if (signal_pending(current)) { + retval = -EINTR; + sem->sleepers = 0; + atomic_add(sleepers, &sem->count); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock in + * the wait_queue_head. + */ + if (atomic_add_return(sleepers - 1, &sem->count) >= 0) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irqrestore(&sem->wait.lock, flags); + + schedule(); + + spin_lock_irqsave(&sem->wait.lock, flags); + tsk->state = TASK_INTERRUPTIBLE; + } + remove_wait_queue_locked(&sem->wait, &wait); + wake_up_locked(&sem->wait); + spin_unlock_irqrestore(&sem->wait.lock, flags); + + tsk->state = TASK_RUNNING; + return retval; +} +EXPORT_SYMBOL(__down_interruptible); diff -Nur linux-2.6.16.11/arch/avr32/kernel/setup.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/setup.c --- linux-2.6.16.11/arch/avr32/kernel/setup.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/setup.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* FIXME: We dont' really want to depend on specific platforms here */ +#include +#include + +extern int root_mountflags; + +/* + * Bootloader-provided information about physical memory + */ +struct tag_mem_range *mem_phys; +struct tag_mem_range *mem_reserved; +struct tag_mem_range *mem_ramdisk; + +/* + * Initialize loops_per_jiffy as 5000000 (500MIPS). + * Better make it too large than too small... + */ +struct avr32_cpuinfo boot_cpu_data = { + .loops_per_jiffy = 5000000 +}; +EXPORT_SYMBOL(boot_cpu_data); + +static char command_line[COMMAND_LINE_SIZE]; + +/* + * Should be more than enough, but if you have a _really_ complex + * setup, you might need to increase the size of this... + */ +static struct tag_mem_range __initdata mem_range_cache[32]; +static unsigned mem_range_next_free; + +/* + * Standard memory resources + */ +static struct resource mem_res[] = { + { "Kernel code", 0, 0, IORESOURCE_MEM }, + { "Kernel data", 0, 0, IORESOURCE_MEM } +}; + +#define kernel_code mem_res[0] +#define kernel_data mem_res[1] + +/* + * Early framebuffer allocation. Works as follows: + * - If fbmem_size is zero, nothing will be allocated or reserved. + * - If fbmem_start is zero when setup_bootmem() is called, + * fbmem_size bytes will be allocated from the bootmem allocator. + * - If fbmem_start is nonzero, an area of size fbmem_size will be + * reserved at the physical address fbmem_start if necessary. If + * the area isn't in a memory region known to the kernel, it will + * be left alone. + * + * Board-specific code may use these variables to set up platform data + * for the framebuffer driver if fbmem_size is nonzero. + */ +static unsigned long __initdata fbmem_start; +static unsigned long __initdata fbmem_size; + +/* --- */ + +static void __init parse_cmdline_early(char **cmdline_p) +{ + char *to = command_line, *from = saved_command_line; + int len = 0; + char c = ' '; + + for (;;) { + if (c != ' ') + goto next_char; + + /* + * "fbmem=xxx[kKmM]" allocates the specified amount of + * boot memory for use as framebuffer. + * "fbmem=xxx[kKmM]@yyy" defines a memory region of + * size xxx and starting at yyy to be reserved for use + * as framebuffer. + * + * The kernel won't verify that the memory region + * starting at yyy actually contains usable RAM. + */ + if (!memcmp(from, "fbmem=", 6)) { + if (to != command_line) + to--; + fbmem_size = memparse(from + 6, &from); + if (*from == '@') + fbmem_start = memparse(from + 1, &from); + } + + next_char: + c = *(from++); + if (c == '\0') + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *(to++) = c; + } + + *to = '\0'; + *cmdline_p = command_line; +} + +static inline void __init resource_init(void) +{ + struct tag_mem_range *region; + + kernel_code.start = __pa(init_mm.start_code); + kernel_code.end = __pa(init_mm.end_code - 1); + kernel_data.start = __pa(init_mm.end_code); + kernel_data.end = __pa(init_mm.brk - 1); + + for (region = mem_phys; region; region = region->next) { + struct resource *res; + unsigned long phys_start, phys_end; + + if (region->size == 0) + continue; + + phys_start = region->addr; + phys_end = phys_start + region->size - 1; + + res = alloc_bootmem_low(sizeof(*res)); + res->name = "System RAM"; + res->start = phys_start; + res->end = phys_end; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + request_resource (&iomem_resource, res); + + if (kernel_code.start >= res->start && + kernel_code.end <= res->end) + request_resource (res, &kernel_code); + if (kernel_data.start >= res->start && + kernel_data.end <= res->end) + request_resource (res, &kernel_data); + } +} + +static int __init parse_tag_core(struct tag *tag) +{ + if (tag->hdr.size > 2) { + if ((tag->u.core.flags & 1) == 0) + root_mountflags &= ~MS_RDONLY; + ROOT_DEV = new_decode_dev(tag->u.core.rootdev); + } + return 0; +} +__tagtable(ATAG_CORE, parse_tag_core); + +static int __init parse_tag_mem_range(struct tag *tag, + struct tag_mem_range **root) +{ + struct tag_mem_range *cur, **pprev; + struct tag_mem_range *new; + + /* + * Ignore zero-sized entries. If we're running standalone, the + * SDRAM code may emit such entries if something goes + * wrong... + */ + if (tag->u.mem_range.size == 0) + return 0; + + /* + * Copy the data so the bootmem init code doesn't need to care + * about it. + */ + if (mem_range_next_free >= + (sizeof(mem_range_cache) / sizeof(mem_range_cache[0]))) + panic("Physical memory map too complex!\n"); + + new = &mem_range_cache[mem_range_next_free++]; + *new = tag->u.mem_range; + + pprev = root; + cur = *root; + while (cur) { + pprev = &cur->next; + cur = cur->next; + } + + *pprev = new; + new->next = NULL; + + return 0; +} + +static int __init parse_tag_mem(struct tag *tag) +{ + return parse_tag_mem_range(tag, &mem_phys); +} +__tagtable(ATAG_MEM, parse_tag_mem); + +static int __init parse_tag_cmdline(struct tag *tag) +{ + strlcpy(saved_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); + return 0; +} +__tagtable(ATAG_CMDLINE, parse_tag_cmdline); + +static int __init parse_tag_rdimg(struct tag *tag) +{ + return parse_tag_mem_range(tag, &mem_ramdisk); +} +__tagtable(ATAG_RDIMG, parse_tag_rdimg); + +static int __init parse_tag_clock(struct tag *tag) +{ + switch(tag->u.clock.clock_id) { + case CLOCK_BOOTCPU: + boot_cpu_data.cpu_hz = tag->u.clock.clock_hz; + /* fall through */ + default: + platform_init_clock_domain(tag->u.clock.clock_id, + tag->u.clock.clock_hz); + break; + } + return 0; +} +__tagtable(ATAG_CLOCK, parse_tag_clock); + +static int __init parse_tag_rsvd_mem(struct tag *tag) +{ + return parse_tag_mem_range(tag, &mem_reserved); +} +__tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem); + +static int __init parse_tag_ethernet(struct tag *tag) +{ + const struct at32_device *adev; + + /* + * We really need a bus type that supports "classes"...this + * will do for now (until we must handle other kinds of + * ethernet controllers) + */ + adev = at32_find_device("macb", tag->u.ethernet.mac_index); + if (adev && adev->dev.platform_data) { + struct eth_platform_data *data = adev->dev.platform_data; + + data->valid = 1; + data->mii_phy_addr = tag->u.ethernet.mii_phy_addr; + memcpy(data->hw_addr, tag->u.ethernet.hw_address, + sizeof(data->hw_addr)); + } + return 0; +} +__tagtable(ATAG_ETHERNET, parse_tag_ethernet); + +/* + * Scan the tag table for this tag, and call its parse function. The + * tag table is built by the linker from all the __tagtable + * declarations. + */ +static int __init parse_tag(struct tag *tag) +{ + extern struct tagtable __tagtable_begin, __tagtable_end; + struct tagtable *t; + + for (t = &__tagtable_begin; t < &__tagtable_end; t++) + if (tag->hdr.tag == t->tag) { + t->parse(tag); + break; + } + + return t < &__tagtable_end; +} + +/* + * Parse all tags in the list we got from the boot loader + */ +static void __init parse_tags(struct tag *t) +{ + for (; t->hdr.tag != ATAG_NONE; t = tag_next(t)) + if (!parse_tag(t)) + printk(KERN_WARNING + "Ignoring unrecognised tag 0x%08x\n", + t->hdr.tag); +} + +void __init setup_arch (char **cmdline_p) +{ + parse_tags(bootloader_tags); + + setup_processor(); + setup_platform(); + + init_mm.start_code = (unsigned long) &_text; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + + parse_cmdline_early(cmdline_p); + + setup_bootmem(); + + board_setup_fbmem(fbmem_start, fbmem_size); + +#ifdef CONFIG_VT + conswitchp = &dummy_con; +#endif + + paging_init(); + + resource_init(); +} diff -Nur linux-2.6.16.11/arch/avr32/kernel/signal.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/signal.c --- linux-2.6.16.11/arch/avr32/kernel/signal.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/signal.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * Based on linux/arch/sh/kernel/signal.c + * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, + struct pt_regs *regs) +{ + return do_sigaltstack(uss, uoss, regs->sp); +} + +struct rt_sigframe +{ + struct siginfo info; + struct ucontext uc; + unsigned long retcode; +}; + +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) +{ + int err = 0; + +#define COPY(x) err |= __get_user(regs->x, &sc->x) + COPY(sr); + COPY(pc); + COPY(lr); + COPY(sp); + COPY(r12); + COPY(r11); + COPY(r10); + COPY(r9); + COPY(r8); + COPY(r7); + COPY(r6); + COPY(r5); + COPY(r4); + COPY(r3); + COPY(r2); + COPY(r1); + COPY(r0); +#undef COPY + + /* + * Don't allow anyone to pretend they're running in supervisor + * mode or something... + */ + err |= !valid_user_regs(regs); + + return err; +} + + +asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + sigset_t set; + + frame = (struct rt_sigframe __user *)regs->sp; + pr_debug("SIG return: frame = %p\n", frame); + + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) + goto badframe; + + pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n", + regs->pc, regs->lr, regs->sp); + + return regs->r12; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +static int +setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) +{ + int err = 0; + +#define COPY(x) err |= __put_user(regs->x, &sc->x) + COPY(sr); + COPY(pc); + COPY(lr); + COPY(sp); + COPY(r12); + COPY(r11); + COPY(r10); + COPY(r9); + COPY(r8); + COPY(r7); + COPY(r6); + COPY(r5); + COPY(r4); + COPY(r3); + COPY(r2); + COPY(r1); + COPY(r0); +#undef COPY + + return err; +} + +static inline void __user * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize) +{ + unsigned long sp = regs->sp; + + if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void __user *)((sp - framesize) & ~3); +} + +static int +setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + err = -EFAULT; + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto out; + + /* + * Set up the return code: + * + * mov r8, __NR_rt_sigreturn + * scall + * + * Note: This will blow up since we're using a non-executable + * stack. Better use SA_RESTORER. + */ +#if __NR_rt_sigreturn > 127 +# error __NR_rt_sigreturn must be < 127 to fit in a short mov +#endif + err = __put_user(0x3008d733 | (__NR_rt_sigreturn << 20), + &frame->retcode); + + err |= copy_siginfo_to_user(&frame->info, info); + + /* Set up the ucontext */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(NULL, &frame->uc.uc_link); + err |= __put_user((void __user *)current->sas_ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->sp), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, + &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + if (err) + goto out; + + regs->r12 = sig; + regs->r11 = (unsigned long) &frame->info; + regs->r10 = (unsigned long) &frame->uc; + regs->sp = (unsigned long) frame; + if (ka->sa.sa_flags & SA_RESTORER) + regs->lr = (unsigned long)ka->sa.sa_restorer; + else { + printk(KERN_NOTICE "[%s:%d] did not set SA_RESTORER\n", + current->comm, current->pid); + regs->lr = (unsigned long) &frame->retcode; + } + + pr_debug("SIG deliver [%s:%d]: sig=%d sp=0x%lx pc=0x%lx->0x%p lr=0x%lx\n", + current->comm, current->pid, sig, regs->sp, + regs->pc, ka->sa.sa_handler, regs->lr); + + regs->pc = (unsigned long) ka->sa.sa_handler; + +out: + return err; +} + +static inline void restart_syscall(struct pt_regs *regs) +{ + if (regs->r12 == -ERESTART_RESTARTBLOCK) + regs->r8 = __NR_restart_syscall; + else + regs->r12 = regs->r12_orig; + regs->pc -= 2; +} + +static inline void +handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs, int syscall) +{ + int ret; + + /* + * Set up the stack frame + */ + ret = setup_rt_frame(sig, ka, info, oldset, regs); + + /* + * Check that the resulting registers are sane + */ + ret |= !valid_user_regs(regs); + + /* + * Block the signal if we were unsuccessful. + */ + if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, + &ka->sa.sa_mask); + sigaddset(¤t->blocked, sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + + if (ret == 0) + return; + + force_sigsegv(sig, current); +} + +/* + * Note that 'init' is a special process: it doesn't get signals it + * doesn't want to handle. Thus you cannot kill init even with a + * SIGKILL even by mistake. + */ +int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall) +{ + siginfo_t info; + int signr; + struct k_sigaction ka; + + /* + * We want the common case to go fast, which is why we may in + * certain cases get here from kernel mode. Just return + * without doing anything if so. + */ + if (!user_mode(regs)) + return 0; + + if (try_to_freeze()) { + signr = 0; + if (!signal_pending(current)) + goto no_signal; + } + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); +no_signal: + if (syscall) { + switch (regs->r12) { + case -ERESTART_RESTARTBLOCK: + case -ERESTARTNOHAND: + if (signr > 0) { + regs->r12 = -EINTR; + break; + } + /* fall through */ + case -ERESTARTSYS: + if (signr > 0 && !(ka.sa.sa_flags & SA_RESTART)) { + regs->r12 = -EINTR; + break; + } + /* fall through */ + case -ERESTARTNOINTR: + restart_syscall(regs); + } + } + + if (signr == 0) { + /* No signal to deliver -- put the saved sigmask back */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + return 0; + } + + handle_signal(signr, &ka, &info, oldset, regs, syscall); + return 1; +} + +asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) +{ + int syscall = 0; + + if ((sysreg_read(SR) & MODE_MASK) == MODE_SUPERVISOR) + syscall = 1; + + if (ti->flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + do_signal(regs, ¤t->blocked, syscall); +} diff -Nur linux-2.6.16.11/arch/avr32/kernel/switch_to.S linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/switch_to.S --- linux-2.6.16.11/arch/avr32/kernel/switch_to.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/switch_to.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + + .text + .global __switch_to + .type __switch_to, @function + + /* Switch thread context from "prev" to "next", returning "last" + * r12 : prev + * r11 : &prev->thread + 1 + * r10 : &next->thread + */ +__switch_to: + stm --r11, r0,r1,r2,r3,r4,r5,r6,r7,sp,lr + mfsr r9, SYSREG_SR + st.w --r11, r9 + ld.w r8, r10++ + /* + * schedule() may have been called from a mode with a different + * set of registers. Make sure we don't lose anything here. + */ + pushm r10,r12 + mtsr SYSREG_SR, r8 + frs /* flush the return stack */ + sub pc, -2 /* flush the pipeline */ + popm r10,r12 + ldm r10++, r0,r1,r2,r3,r4,r5,r6,r7,sp,pc + .size __switch_to, . - __switch_to diff -Nur linux-2.6.16.11/arch/avr32/kernel/sys_avr32.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/sys_avr32.c --- linux-2.6.16.11/arch/avr32/kernel/sys_avr32.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/sys_avr32.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include +#include + +asmlinkage int sys_pipe(unsigned long __user *filedes) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(filedes, fd, sizeof(fd))) + error = -EFAULT; + } + return error; +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset) +{ + int error = -EBADF; + struct file *file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + return error; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, offset); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); + return error; +} diff -Nur linux-2.6.16.11/arch/avr32/kernel/syscall-stubs.S linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/syscall-stubs.S --- linux-2.6.16.11/arch/avr32/kernel/syscall-stubs.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/syscall-stubs.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Stubs for syscalls that require access to pt_regs or that take more + * than five parameters. + */ + +#define ARG6 r3 + + .text + .global __sys_rt_sigsuspend + .type __sys_rt_sigsuspend,@function +__sys_rt_sigsuspend: + mov r10, sp + rjmp sys_rt_sigsuspend + + .global __sys_sigaltstack + .type __sys_sigaltstack,@function +__sys_sigaltstack: + mov r10, sp + rjmp sys_sigaltstack + + .global __sys_rt_sigreturn + .type __sys_rt_sigreturn,@function +__sys_rt_sigreturn: + mov r12, sp + rjmp sys_rt_sigreturn + + .global __sys_fork + .type __sys_fork,@function +__sys_fork: + mov r12, sp + rjmp sys_fork + + .global __sys_clone + .type __sys_clone,@function +__sys_clone: + mov r8, sp + rjmp sys_clone + + .global __sys_vfork + .type __sys_vfork,@function +__sys_vfork: + mov r12, sp + rjmp sys_vfork + + .global __sys_execve + .type __sys_execve,@function +__sys_execve: + mov r9, sp + rjmp sys_execve + + .global __sys_mmap2 + .type __sys_mmap2,@function +__sys_mmap2: + pushm lr + st.w --sp, ARG6 + rcall sys_mmap2 + sub sp, -4 + popm pc + + .global __sys_sendto + .type __sys_sendto,@function +__sys_sendto: + pushm lr + st.w --sp, ARG6 + rcall sys_sendto + sub sp, -4 + popm pc + + .global __sys_recvfrom + .type __sys_recvfrom,@function +__sys_recvfrom: + pushm lr + st.w --sp, ARG6 + rcall sys_recvfrom + sub sp, -4 + popm pc diff -Nur linux-2.6.16.11/arch/avr32/kernel/syscall_table.S linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/syscall_table.S --- linux-2.6.16.11/arch/avr32/kernel/syscall_table.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/syscall_table.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,260 @@ +/* + * AVR32 system call table + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + +#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE) +#define sys_nfsservctl sys_ni_syscall +#endif + +#if !defined(CONFIG_SYSV_IPC) +# define sys_ipc sys_ni_syscall +#endif + +#if !defined(CONFIG_AVR32_JAVA) +# define sys_avm_init sys_ni_syscall +# define sys_avm_invoke sys_ni_syscall +# define sys_avm_return sys_ni_syscall +#endif + + .section .rodata,"a",@progbits + .type sys_call_table,@object + .global sys_call_table + .align 2 +sys_call_table: + .long sys_restart_syscall + .long sys_exit + .long __sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_umask + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long __sys_execve + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_chown + .long sys_lchown + .long sys_lseek + .long sys_llseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_umount + .long sys_setuid + .long sys_getuid + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_pause + .long sys_utime + .long sys_newstat /* 30 */ + .long sys_newfstat + .long sys_newlstat + .long sys_access + .long sys_chroot + .long sys_sync /* 35 */ + .long sys_fsync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long __sys_clone + .long sys_brk /* 45 */ + .long sys_setgid + .long sys_getgid + .long sys_getcwd + .long sys_geteuid + .long sys_getegid /* 50 */ + .long sys_acct + .long sys_setfsuid + .long sys_setfsgid + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_setpgid + .long sys_mremap + .long sys_setresuid + .long sys_getresuid + .long sys_setreuid /* 60 */ + .long sys_setregid + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_rt_sigaction + .long __sys_rt_sigreturn + .long sys_rt_sigprocmask + .long sys_rt_sigpending /* 70 */ + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long __sys_rt_sigsuspend + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups /* 80 */ + .long sys_setgroups + .long sys_select + .long sys_symlink + .long sys_fchdir + .long sys_readlink /* 85 */ + .long sys_pread64 + .long sys_pwrite64 + .long sys_swapon + .long sys_reboot + .long __sys_mmap2 /* 90 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_wait4 + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_vhangup + .long __sys_sigaltstack + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_swapoff + .long sys_sysinfo + .long sys_ipc + .long sys_sendfile + .long sys_setdomainname /* 110 */ + .long sys_newuname + .long sys_adjtimex + .long sys_mprotect + .long __sys_vfork + .long sys_init_module /* 115 */ + .long sys_delete_module + .long sys_quotactl + .long sys_getpgid + .long sys_bdflush + .long sys_sysfs /* 120 */ + .long sys_personality + .long sys_ni_syscall /* reserved for afs_syscall */ + .long sys_getdents + .long sys_flock + .long sys_msync /* 125 */ + .long sys_readv + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl /* 130 */ + .long sys_mlock + .long sys_munlock + .long sys_mlockall + .long sys_munlockall + .long sys_sched_setparam /* 135 */ + .long sys_sched_getparam + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max /* 140 */ + .long sys_sched_get_priority_min + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_poll + .long sys_nfsservctl /* 145 */ + .long sys_setresgid + .long sys_getresgid + .long sys_prctl + .long sys_socket + .long sys_bind /* 150 */ + .long sys_connect + .long sys_listen + .long sys_accept + .long sys_getsockname + .long sys_getpeername /* 155 */ + .long sys_socketpair + .long sys_send + .long sys_recv + .long __sys_sendto + .long __sys_recvfrom /* 160 */ + .long sys_shutdown + .long sys_setsockopt + .long sys_getsockopt + .long sys_sendmsg + .long sys_recvmsg /* 165 */ + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 + .long sys_lstat64 + .long sys_fstat64 /* 170 */ + .long sys_pivot_root + .long sys_mincore + .long sys_madvise + .long sys_getdents64 + .long sys_fcntl64 /* 175 */ + .long sys_gettid + .long sys_readahead + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr /* 180 */ + .long sys_getxattr + .long sys_lgetxattr + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr /* 185 */ + .long sys_flistxattr + .long sys_removexattr + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_tkill /* 190 */ + .long sys_sendfile64 + .long sys_futex + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_capget /* 195 */ + .long sys_capset + .long sys_io_setup + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit /* 200 */ + .long sys_io_cancel + .long sys_fadvise64 + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create /* 205 */ + .long sys_epoll_ctl + .long sys_epoll_wait + .long sys_remap_file_pages + .long sys_set_tid_address + .long sys_timer_create /* 210 */ + .long sys_timer_settime + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime /* 215 */ + .long sys_clock_gettime + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 /* 220 */ + .long sys_tgkill + .long sys_ni_syscall /* reserved for TUX */ + .long sys_utimes + .long sys_fadvise64_64 + .long sys_cacheflush /* 225 */ + .long sys_avm_init + .long sys_avm_invoke + .long sys_avm_return + .long sys_ni_syscall /* r8 will be saturated at nr_syscalls */ diff -Nur linux-2.6.16.11/arch/avr32/kernel/time.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/time.c --- linux-2.6.16.11/arch/avr32/kernel/time.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/time.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * Based on MIPS implementation arch/mips/kernel/time.c + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern unsigned long wall_jiffies; + +#define USECS_PER_JIFFY (1000000 / HZ) + +/* + * By default we provide the null RTC ops + */ +static unsigned long null_rtc_get_time(void) +{ + return mktime(2004, 1, 1, 0, 0, 0); +} + +static int null_rtc_set_time(unsigned long sec) +{ + return 0; +} + +static unsigned long (*rtc_get_time)(void) = null_rtc_get_time; +static int (*rtc_set_time)(unsigned long) = null_rtc_set_time; + +/* usecs per counter cycle, shifted left by 32 bits */ +static unsigned int sll32_usecs_per_cycle; + +/* how many counter cycles in a jiffy? */ +static unsigned long cycles_per_jiffy; + +/* cycle counter value at the previous timer interrupt */ +static unsigned int timerhi, timerlo; + +/* the count value for the next timer interrupt */ +static unsigned int expirelo; + +static inline void avr32_timer_ack(void) +{ + unsigned int count; + + /* Ack this timer interrupt and set the next one */ + expirelo += cycles_per_jiffy; + if (expirelo == 0) { + printk(KERN_DEBUG "expirelo == 0\n"); + sysreg_write(COMPARE, expirelo + 1); + } else { + sysreg_write(COMPARE, expirelo); + } + + /* Check to see if we have missed any timer interrupts */ + count = sysreg_read(COUNT); + if ((count - expirelo) < 0x7fffffff) { + expirelo = count + cycles_per_jiffy; + sysreg_write(COMPARE, expirelo); + } +} + +static inline unsigned int avr32_hpt_read(void) +{ + return sysreg_read(COUNT); +} + +/* + * Taken from MIPS c0_hpt_timer_init(). + * + * Why is it so complicated, and what is "count"? My assumption is + * that `count' specifies the "reference cycle", i.e. the cycle since + * reset that should mean "zero". The reason COUNT is written twice is + * probably to make sure we don't get any timer interrupts while we + * are messing with the counter. + */ +static inline void avr32_hpt_init(unsigned int count) +{ + count = sysreg_read(COUNT) - count; + expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy; + sysreg_write(COUNT, expirelo - cycles_per_jiffy); + sysreg_write(COMPARE, expirelo); + sysreg_write(COUNT, count); +} + +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + /* There must be better ways...? */ + return (unsigned long long)jiffies * (1000000000 / HZ); +} + +/* Taken from MIPS fixed_rate_gettimeoffset */ +static unsigned long do_gettimeoffset(void) +{ + unsigned long long tmp; + unsigned long res; + u32 count; + + /* Get latest timer tick in absolute kernel time */ + count = avr32_hpt_read(); + + /* ... relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + /* Divide by cycles_per_usec */ + asm("mulu.d %0, %1, %2" + : "=r"(tmp) + : "r"(count), "r"(sll32_usecs_per_cycle)); + res = tmp >> 32; + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY - 1; + + return res; +} + +/* This one is taken from MIPS */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long seq; + unsigned long lost; + unsigned long usec, sec; + unsigned long max_ntp_tick = tick_usec - tickadj; + + do { + seq = read_seqbegin(&xtime_lock); + usec = do_gettimeoffset(); + lost = jiffies - wall_jiffies; + + /* + * If time_adjust is negative then NTP is slowing the + * clock, so make sure not to go into next possible + * interval. Better to lose some accuracy than have + * time go backwards.. + */ + if (unlikely(time_adjust < 0)) { + usec = min(usec, max_ntp_tick); + + if (lost) + usec += lost * max_ntp_tick; + } else if (unlikely(lost)) { + usec += lost * tick_usec; + } + + sec = xtime.tv_sec; + usec += xtime.tv_nsec / 1000; + } while (read_seqretry(&xtime_lock, seq)); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +EXPORT_SYMBOL(do_gettimeofday); + +int do_settimeofday(struct timespec *tv) +{ + time_t wtm_sec, sec = tv->tv_sec; + long wtm_nsec, nsec = tv->tv_nsec; + + if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + return -EINVAL; + + write_seqlock_irq(&xtime_lock); + + /* + * This is revolting. We need to set "xtime" correctly. + * However, the value in this location is the value at the + * most recent update of wall time. Discover what correction + * gettimeofday() would have made, and undo it! + */ + nsec -= do_gettimeoffset() * NSEC_PER_USEC; + nsec -= (jiffies - wall_jiffies) * tick_nsec; + + wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); + wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); + + set_normalized_timespec(&xtime, sec, nsec); + set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); + + time_adjust = 0; + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + + write_sequnlock_irq(&xtime_lock); + clock_was_set(); + + return 0; +} + +EXPORT_SYMBOL(do_settimeofday); + +/* + * local_timer_interrupt() does profiling and process accounting on a + * per-CPU basis. + * + * In UP mode, it is invoked from the (global) timer_interrupt. + */ +static void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (current->pid) + profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(regs)); +} + +static irqreturn_t +timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int count; + + /* ack timer interrupt and try to set next interrupt */ + count = avr32_hpt_read(); + avr32_timer_ack(); + + /* Update timerhi/timerlo for intra-jiffy calibration */ + timerhi += count < timerlo; /* Wrap around */ + timerlo = count; + + /* + * Call the generic timer interrupt handler + */ + write_seqlock(&xtime_lock); + do_timer(regs); + write_sequnlock(&xtime_lock); + + /* + * In UP mode, we call local_timer_interrupt() to do profiling + * and process accounting. + * + * SMP is not supported yet. + */ + local_timer_interrupt(irq, dev_id, regs); + + return IRQ_HANDLED; +} + +static unsigned int avr32_hpt_frequency; + +static struct intc_group_desc timer_group = { + .ctrl = NULL, + .handle = timer_interrupt, + .flags = SA_INTERRUPT, + .dev_id = NULL, + .devname = "timer", +}; + +void __init time_init(void) +{ + int ret; + + xtime.tv_sec = rtc_get_time(); + xtime.tv_nsec = 0; + + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); + + printk("Before time_init: count=%08lx, compare=%08lx\n", + (unsigned long)sysreg_read(COUNT), + (unsigned long)sysreg_read(COMPARE)); + + if (!avr32_hpt_frequency && boot_cpu_data.cpu_hz) + avr32_hpt_frequency = boot_cpu_data.cpu_hz; + + if (avr32_hpt_frequency) { + cycles_per_jiffy = (avr32_hpt_frequency + HZ / 2) / HZ; + + /* 10^6 * 2^32 / avr32_hpt_frequency */ + { + u64 tmp = 1000000ULL << 32; + tmp /= avr32_hpt_frequency; + sll32_usecs_per_cycle = tmp; + } + + printk("Using %u.%03u MHz high precision timer.\n", + ((avr32_hpt_frequency + 500) / 1000) / 1000, + ((avr32_hpt_frequency + 500) / 1000) % 1000); + } + + /* This sets up the high precision timer for the first interrupt. */ + avr32_hpt_init(avr32_hpt_read()); + + printk("After time_init: count=%08lx, compare=%08lx\n", + (unsigned long)sysreg_read(COUNT), + (unsigned long)sysreg_read(COMPARE)); + + ret = setup_internal_irq(0, &timer_group); + if (ret) + printk("timer: could not request IRQ 0: %d\n", ret); +} + +static struct sysdev_class timer_class = { + set_kset_name("timer"), +}; + +static struct sys_device timer_device = { + .id = 0, + .cls = &timer_class, +}; + +static int __init init_timer_sysfs(void) +{ + int err = sysdev_class_register(&timer_class); + if (!err) + err = sysdev_register(&timer_device); + return err; +} + +device_initcall(init_timer_sysfs); diff -Nur linux-2.6.16.11/arch/avr32/kernel/traps.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/traps.c --- linux-2.6.16.11/arch/avr32/kernel/traps.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/traps.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static void dump_mem(const char *str, unsigned long bottom, unsigned long top) +{ + unsigned long p; + int i; + + printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); + + for (p = bottom & ~31; p < top; ) { + printk("%04lx: ", p & 0xffff); + + for (i = 0; i < 8; i++, p += 4) { + unsigned int val; + + if (p < bottom || p >= top) + printk(" "); + else { + if (__get_user(val, (unsigned int __user *)p)) { + printk("\n"); + goto out; + } + printk("%08x ", val); + } + } + printk("\n"); + } + +out: + return; +} + +#ifdef CONFIG_FRAME_POINTER +static inline void __show_trace(struct task_struct *tsk, unsigned long *sp, + struct pt_regs *regs) +{ + unsigned long __user *fp; + unsigned long __user *last_fp = NULL; + + if (regs) { + fp = (unsigned long *)regs->r7; + } else if (tsk == current) { + register unsigned long *real_fp __asm__("r7"); + fp = real_fp; + } else { + fp = (unsigned long *)tsk->thread.cpu_context.r7; + } + + /* + * Walk the stack until (a) we get an exception, (b) the frame + * pointer becomes zero, or (c) the frame pointer gets stuck + * at the same value. + */ + while (fp && fp != last_fp) { + unsigned long lr, new_fp = 0; + + last_fp = fp; + if (__get_user(lr, fp)) + break; + if (fp && __get_user(new_fp, fp + 1)) + break; + fp = (unsigned long __user *)new_fp; + + printk(" [<%08lx>] ", lr); + print_symbol("%s\n", lr); + } + printk("\n"); +} +#else +static inline void __show_trace(struct task_struct *tsk, unsigned long *sp, + struct pt_regs *regs) +{ + unsigned long addr; + + while (!kstack_end(sp)) { + addr = *sp++; + if (kernel_text_address(addr)) { + printk(" [<%08lx>] ", addr); + print_symbol("%s\n", addr); + } + } +} +#endif + +void show_trace(struct task_struct *tsk, unsigned long *sp, + struct pt_regs *regs) +{ + if (regs && + (((regs->sr & MODE_MASK) == MODE_EXCEPTION) || + ((regs->sr & MODE_MASK) == MODE_USER))) + return; + + printk ("Call trace:"); +#ifdef CONFIG_KALLSYMS + printk("\n"); +#endif + + __show_trace(tsk, sp, regs); + printk("\n"); +} + +void show_stack(struct task_struct *tsk, unsigned long *sp) +{ + unsigned long stack; + + if (!tsk) + tsk = current; + if (sp == 0) { + if (tsk == current) { + register unsigned long *real_sp __asm__("sp"); + sp = real_sp; + } else { + sp = (unsigned long *)tsk->thread.cpu_context.ksp; + } + } + + stack = (unsigned long)sp; + dump_mem("Stack: ", stack, + THREAD_SIZE + (unsigned long)tsk->thread_info); + show_trace(tsk, sp, NULL); +} + +void dump_stack(void) +{ + show_stack(NULL, NULL); +} +EXPORT_SYMBOL(dump_stack); + +struct notifier_block *avr32_die_chain; +static DEFINE_SPINLOCK(die_notifier_lock); + +int register_die_notifier(struct notifier_block *nb) +{ + int err = 0; + unsigned long flags; + + pr_debug("register_die_notifier: %p\n", nb); + + spin_lock_irqsave(&die_notifier_lock, flags); + err = notifier_chain_register(&avr32_die_chain, nb); + spin_unlock_irqrestore(&die_notifier_lock, flags); + + return err; +} + +static DEFINE_SPINLOCK(die_lock); + +void __die(const char *str, struct pt_regs *regs, unsigned long err, + const char *file, const char *func, unsigned long line) +{ + struct task_struct *tsk = current; + static int die_counter; + + console_verbose(); + spin_lock_irq(&die_lock); + bust_spinlocks(1); + + printk(KERN_ALERT "%s", str); + if (file && func) + printk(" in %s:%s, line %ld", file, func, line); + printk("[#%d]:\n", ++die_counter); + print_modules(); + show_regs(regs); + printk("Process %s (pid: %d, stack limit = 0x%p)\n", + tsk->comm, tsk->pid, tsk->thread_info + 1); + + if (!user_mode(regs) || in_interrupt()) { + dump_mem("Stack: ", regs->sp, + THREAD_SIZE + (unsigned long)tsk->thread_info); + } + + bust_spinlocks(0); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} + +void __die_if_kernel(const char *str, struct pt_regs *regs, unsigned long err, + const char *file, const char *func, unsigned long line) +{ + if (!user_mode(regs)) + __die(str, regs, err, file, func, line); +} + +asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs) +{ +#ifdef CONFIG_SUBARCH_AVR32B + /* + * The exception entry always saves RSR_EX. For NMI, this is + * wrong; it should be RSR_NMI + */ + regs->sr = sysreg_read(RSR_NMI); +#endif + + printk("NMI taken!!!!\n"); + die("NMI", regs, ecr); + BUG(); +} + +asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs) +{ + printk("Unable to handle critical exception %lu at pc = %08lx!\n", + ecr, regs->pc); + die("Oops", regs, ecr); + BUG(); +} + +asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs) +{ + siginfo_t info; + + die_if_kernel("Oops: Address exception in kernel mode", regs, ecr); + +#ifdef DEBUG + if (ecr == ECR_ADDR_ALIGN_X) + pr_debug("Instruction Address Exception at pc = %08lx\n", + regs->pc); + else if (ecr == ECR_ADDR_ALIGN_R) + pr_debug("Data Address Exception (Read) at pc = %08lx\n", + regs->pc); + else if (ecr == ECR_ADDR_ALIGN_W) + pr_debug("Data Address Exception (Write) at pc = %08lx\n", + regs->pc); + else + BUG(); + + show_regs(regs); +#endif + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRALN; + info.si_addr = (void __user *)regs->pc; + + force_sig_info(SIGBUS, &info, current); +} + +/* This way of handling undefined instructions is stolen from ARM */ +static LIST_HEAD(undef_hook); +static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED; + +void register_undef_hook(struct undef_hook *hook) +{ + spin_lock_irq(&undef_lock); + list_add(&hook->node, &undef_hook); + spin_unlock_irq(&undef_lock); +} + +void unregister_undef_hook(struct undef_hook *hook) +{ + spin_lock_irq(&undef_lock); + list_del(&hook->node); + spin_unlock_irq(&undef_lock); +} + +static int do_cop_absent(u32 insn) +{ + int cop_nr; + u32 cpucr; + if ( (insn & 0xfdf00000) == 0xf1900000 ) + /* LDC0 */ + cop_nr = 0; + else + cop_nr = (insn >> 13) & 0x7; + + /* Try enabling the coprocessor */ + cpucr = sysreg_read(CPUCR); + cpucr |= (1 << (24 + cop_nr)); + sysreg_write(CPUCR, cpucr); + + cpucr = sysreg_read(CPUCR); + if ( !(cpucr & (1 << (24 + cop_nr))) ){ + printk("Coprocessor #%i not found!\n", cop_nr); + return -1; + } + + return 0; +} + +#ifdef CONFIG_BUG +#ifdef CONFIG_DEBUG_BUGVERBOSE +static inline void do_bug_verbose(struct pt_regs *regs, u32 insn) +{ + char *file; + u16 line; + char c; + + if (__get_user(line, (u16 __user *)(regs->pc + 2))) + return; + if (__get_user(file, (char * __user *)(regs->pc + 4)) + || (unsigned long)file < PAGE_OFFSET + || __get_user(c, file)) + file = ""; + + printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line); +} +#else +static inline void do_bug_verbose(struct pt_regs *regs, u32 insn) +{ + +} +#endif +#endif + +asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs) +{ + u32 insn; + struct undef_hook *hook; + siginfo_t info; + void __user *pc; + + if (!user_mode(regs)) + goto kernel_trap; + + local_irq_enable(); + + pc = (void __user *)instruction_pointer(regs); + if (__get_user(insn, (u32 __user *)pc)) + goto invalid_area; + + if (ecr == ECR_COPROC_ABSENT) { + if (do_cop_absent(insn) == 0) + return; + } + + spin_lock_irq(&undef_lock); + list_for_each_entry(hook, &undef_hook, node) { + if ((insn & hook->insn_mask) == hook->insn_val) { + if (hook->fn(regs, insn) == 0) { + spin_unlock_irq(&undef_lock); + return; + } + } + } + spin_unlock_irq(&undef_lock); + +invalid_area: + +#ifdef DEBUG + printk("Illegal instruction at pc = %08lx\n", regs->pc); + if (regs->pc < TASK_SIZE) { + unsigned long ptbr, pgd, pte, *p; + + ptbr = sysreg_read(PTBR); + p = (unsigned long *)ptbr; + pgd = p[regs->pc >> 22]; + p = (unsigned long *)((pgd & 0x1ffff000) | 0x80000000); + pte = p[(regs->pc >> 12) & 0x3ff]; + printk("page table: 0x%08lx -> 0x%08lx -> 0x%08lx\n", ptbr, pgd, pte); + } +#endif + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_addr = (void __user *)regs->pc; + switch (ecr) { + case ECR_ILLEGAL_OPCODE: + case ECR_UNIMPL_INSTRUCTION: + info.si_code = ILL_ILLOPC; + break; + case ECR_PRIVILEGE_VIOLATION: + info.si_code = ILL_PRVOPC; + break; + case ECR_COPROC_ABSENT: + info.si_code = ILL_COPROC; + break; + default: + BUG(); + } + + force_sig_info(SIGILL, &info, current); + return; + +kernel_trap: +#ifdef CONFIG_BUG + if (__kernel_text_address(instruction_pointer(regs))) { + insn = *(u16 *)instruction_pointer(regs); + if (insn == AVR32_BUG_OPCODE) { + do_bug_verbose(regs, insn); + die("Kernel BUG", regs, 0); + return; + } + } +#endif + + die("Oops: Illegal instruction in kernel code", regs, ecr); +} + +asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs) +{ + siginfo_t info; + + printk("Floating-point exception at pc = %08lx\n", regs->pc); + + /* We have no FPU... */ + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_addr = (void __user *)regs->pc; + info.si_code = ILL_COPROC; + + force_sig_info(SIGILL, &info, current); +} + + +void __init trap_init(void) +{ + +} diff -Nur linux-2.6.16.11/arch/avr32/kernel/vmlinux.lds.c linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/vmlinux.lds.c --- linux-2.6.16.11/arch/avr32/kernel/vmlinux.lds.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/kernel/vmlinux.lds.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,161 @@ +/* + * AVR32 linker script for the Linux kernel + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define LOAD_OFFSET 0x00000000 +#include +#include + +OUTPUT_FORMAT("elf32-avr32", "elf32-avr32", "elf32-avr32") +OUTPUT_ARCH(avr32) +ENTRY(_start) + +/* Big endian */ +jiffies = jiffies_64 + 4; + +SECTIONS +{ + . = CONFIG_ENTRY_ADDRESS; + .init : AT(ADDR(.init) - LOAD_OFFSET) { + _stext = .; + __init_begin = .; + _sinittext = .; + *(.text.reset) + *(.init.text) + _einittext = .; + . = ALIGN(4); + __tagtable_begin = .; + *(.taglist) + __tagtable_end = .; + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + . = ALIGN(4); + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + __security_initcall_start = .; + *(.security_initcall.init) + __security_initcall_end = .; + . = ALIGN(32); + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + . = ALIGN(4096); + __init_end = .; + } + + . = ALIGN(8192); + .text : AT(ADDR(.text) - LOAD_OFFSET) { + _evba = .; + _text = .; + *(.ex.text) + . = 0x50; + *(.tlbx.ex.text) + . = 0x60; + *(.tlbr.ex.text) + . = 0x70; + *(.tlbw.ex.text) + . = 0x100; + *(.scall.text) + *(.irq.text) + +#ifdef CONFIG_AVR32_JAVA + . = ALIGN(0x1000); + *(.java.trap) +#endif + *(.text) + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT + *(.fixup) + *(.gnu.warning) + _etext = .; + } = 0xd703d703 + + . = ALIGN(4); + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } + + RODATA + + . = ALIGN(8192); + + .data : AT(ADDR(.data) - LOAD_OFFSET) { + _data = .; + _sdata = .; + /* + * First, the init task union, aligned to an 8K boundary. + */ + *(.data.init_task) + + /* Then, the cacheline aligned data */ + . = ALIGN(32); + *(.data.cacheline_aligned) + + /* And the rest... */ + *(.data.rel*) + *(.data) + CONSTRUCTORS + + _edata = .; + } + + + . = ALIGN(8); + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { + __bss_start = .; + *(.bss) + *(COMMON) + . = ALIGN(8); + __bss_stop = .; + _end = .; + } + +#ifdef CONFIG_LOADER_STANDALONE + /* + * Include an initrd image directly into the kernel + * image. This is a temporary solution as it is really a job + * for the boot loader... + */ + . = ALIGN(4096); + .initrd : AT(ADDR(.initrd) - LOAD_OFFSET) { + __initrd_start_phys = . - 0x80000000; + __initrd_start_virt = .; + *(.initrd) + . = ALIGN(4096); + } + __initrd_size = . - __initrd_start_virt; +#endif + + /* When something in the kernel is NOT compiled as a module, the module + * cleanup code and data are put into these segments. Both can then be + * thrown away, as cleanup code is never called unless it's a module. + */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } + + DWARF_DEBUG +} diff -Nur linux-2.6.16.11/arch/avr32/lib/__avr32_asr64.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/__avr32_asr64.S --- linux-2.6.16.11/arch/avr32/lib/__avr32_asr64.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/__avr32_asr64.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + /* + * DWtype __avr32_asr64(DWtype u, word_type b) + */ + .text + .global __avr32_asr64 + .type __avr32_asr64,@function +__avr32_asr64: + cp.w r12, 0 + reteq r12 + + rsub r9, r12, 32 + brle 1f + + lsl r8, r11, r9 + asr r11, r11, r12 + asr r10, r10, r12 + or r10, r8 + retal r12 + +1: neg r9 + asr r10, r11, r9 + asr r11, 31 + retal r12 diff -Nur linux-2.6.16.11/arch/avr32/lib/__avr32_lsl64.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/__avr32_lsl64.S --- linux-2.6.16.11/arch/avr32/lib/__avr32_lsl64.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/__avr32_lsl64.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + /* + * DWtype __avr32_lsl64(DWtype u, word_type b) + */ + .text + .global __avr32_lsl64 + .type __avr32_lsl64,@function +__avr32_lsl64: + cp.w r12, 0 + reteq r12 + + rsub r9, r12, 32 + brle 1f + + lsr r8, r10, r9 + lsl r10, r10, r12 + lsl r11, r11, r12 + or r11, r8 + retal r12 + +1: neg r9 + lsl r11, r10, r9 + mov r10, 0 + retal r12 diff -Nur linux-2.6.16.11/arch/avr32/lib/__avr32_lsr64.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/__avr32_lsr64.S --- linux-2.6.16.11/arch/avr32/lib/__avr32_lsr64.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/__avr32_lsr64.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + /* + * DWtype __avr32_lsr64(DWtype u, word_type b) + */ + .text + .global __avr32_lsr64 + .type __avr32_lsr64,@function +__avr32_lsr64: + cp.w r12, 0 + reteq r12 + + rsub r9, r12, 32 + brle 1f + + lsl r8, r11, r9 + lsr r11, r11, r12 + lsr r10, r10, r12 + or r10, r8 + retal r12 + +1: neg r9 + lsr r10, r11, r9 + mov r11, 0 + retal r12 diff -Nur linux-2.6.16.11/arch/avr32/lib/clear_user.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/clear_user.S --- linux-2.6.16.11/arch/avr32/lib/clear_user.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/clear_user.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + + .text + .align 1 + .global clear_user + .type clear_user, "function" +clear_user: + branch_if_kernel r8, __clear_user + ret_if_privileged r8, r12, r11, r11 + + .global __clear_user + .type __clear_user, "function" +__clear_user: + mov r9, r12 + mov r8, 0 + andl r9, 3, COH + brne 5f + +1: sub r11, 4 + brlt 2f + +10: st.w r12++, r8 + sub r11, 4 + brge 10b + +2: sub r11, -4 + reteq 0 + + /* Unaligned count or address */ + bld r11, 1 + brcc 12f +11: st.h r12++, r8 + sub r11, 2 + reteq 0 +12: st.b r12++, r8 + retal 0 + + /* Unaligned address */ +5: cp.w r11, 4 + brlt 2b + + lsl r9, 2 + add pc, pc, r9 +13: st.b r12++, r8 + sub r11, 1 +14: st.b r12++, r8 + sub r11, 1 +15: st.b r12++, r8 + sub r11, 1 + rjmp 1b + + .size clear_user, . - clear_user + .size __clear_user, . - __clear_user + + .section .fixup, "ax" + .align 1 +18: sub r11, -4 +19: retal r11 + + .section __ex_table, "a" + .align 2 + .long 10b, 18b + .long 11b, 19b + .long 12b, 19b + .long 13b, 19b + .long 14b, 19b + .long 15b, 19b diff -Nur linux-2.6.16.11/arch/avr32/lib/copy_user.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/copy_user.S --- linux-2.6.16.11/arch/avr32/lib/copy_user.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/copy_user.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,119 @@ +/* + * Copy to/from userspace with optional address space checking. + * + * Copyright 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + + /* + * __kernel_size_t + * __copy_user(void *to, const void *from, __kernel_size_t n) + * + * Returns the number of bytes not copied. Might be off by + * max 3 bytes if we get a fault in the main loop. + * + * The address-space checking functions simply fall through to + * the non-checking version. + */ + .text + .align 1 + .global copy_from_user + .type copy_from_user, @function +copy_from_user: + branch_if_kernel r8, __copy_user + ret_if_privileged r8, r11, r10, r10 + rjmp __copy_user + .size copy_from_user, . - copy_from_user + + .global copy_to_user + .type copy_to_user, @function +copy_to_user: + branch_if_kernel r8, __copy_user + ret_if_privileged r8, r12, r10, r10 + .size copy_to_user, . - copy_to_user + + .global __copy_user + .type __copy_user, @function +__copy_user: + mov r9, r11 + andl r9, 3, COH + brne 6f + + /* At this point, from is word-aligned */ +1: sub r10, 4 + brlt 3f + +2: +10: ld.w r8, r11++ +11: st.w r12++, r8 + sub r10, 4 + brge 2b + +3: sub r10, -4 + reteq 0 + + /* + * Handle unaligned count. Need to be careful with r10 here so + * that we return the correct value even if we get a fault + */ +4: +20: ld.ub r8, r11++ +21: st.b r12++, r8 + sub r10, 1 + reteq 0 +22: ld.ub r8, r11++ +23: st.b r12++, r8 + sub r10, 1 + reteq 0 +24: ld.ub r8, r11++ +25: st.b r12++, r8 + retal 0 + + /* Handle unaligned from-pointer */ +6: cp.w r10, 4 + brlt 4b + rsub r9, r9, 4 + +30: ld.ub r8, r11++ +31: st.b r12++, r8 + sub r10, 1 + sub r9, 1 + breq 1b +32: ld.ub r8, r11++ +33: st.b r12++, r8 + sub r10, 1 + sub r9, 1 + breq 1b +34: ld.ub r8, r11++ +35: st.b r12++, r8 + sub r10, 1 + rjmp 1b + .size __copy_user, . - __copy_user + + .section .fixup,"ax" + .align 1 +19: sub r10, -4 +29: retal r10 + + .section __ex_table,"a" + .align 2 + .long 10b, 19b + .long 11b, 19b + .long 20b, 29b + .long 21b, 29b + .long 22b, 29b + .long 23b, 29b + .long 24b, 29b + .long 25b, 29b + .long 30b, 29b + .long 31b, 29b + .long 32b, 29b + .long 33b, 29b + .long 34b, 29b + .long 35b, 29b diff -Nur linux-2.6.16.11/arch/avr32/lib/csum_partial_copy_generic.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/csum_partial_copy_generic.S --- linux-2.6.16.11/arch/avr32/lib/csum_partial_copy_generic.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/csum_partial_copy_generic.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + + /* + * unsigned int csum_partial_copy_generic(const char *src, char *dst, int len + * int sum, int *src_err_ptr, + * int *dst_err_ptr) + * + * Copy src to dst while checksumming, otherwise like csum_partial. + */ + + .macro ld_src size, reg, ptr +9999: ld.\size \reg, \ptr + .section __ex_table, "a" + .long 9999b, fixup_ld_src + .previous + .endm + + .macro st_dst size, ptr, reg +9999: st.\size \ptr, \reg + .section __ex_table, "a" + .long 9999b, fixup_st_dst + .previous + .endm + + .text + .global csum_partial_copy_generic + .type csum_partial_copy_generic,"function" + .align 1 +csum_partial_copy_generic: + pushm r4-r7,lr + + /* The inner loop */ +1: sub r10, 4 + brlt 5f +2: ld_src w, r5, r12++ + st_dst w, r11++, r5 + add r9, r5 + acr r9 + sub r10, 4 + brge 2b + + /* return if we had a whole number of words */ +5: sub r10, -4 + brne 7f + +6: mov r12, r9 + popm r4-r7,pc + + /* handle additional bytes at the tail */ +7: mov r5, 0 + mov r4, 32 +8: ld_src ub, r6, r12++ + st_dst b, r11++, r6 + lsl r5, 8 + sub r4, 8 + bfins r5, r6, 0, 8 + sub r10, 1 + brne 8b + + lsl r5, r5, r4 + add r9, r5 + acr r9 + rjmp 6b + + /* Exception handler */ + .section .fixup,"ax" + .align 1 +fixup_ld_src: + mov r9, -EFAULT + cp.w r8, 0 + breq 1f + st.w r8[0], r9 + +1: /* + * TODO: zero the complete destination - computing the rest + * is too much work + */ + + mov r9, 0 + rjmp 6b + +fixup_st_dst: + mov r9, -EFAULT + lddsp r8, sp[20] + cp.w r8, 0 + breq 1f + st.w r8[0], r9 +1: mov r9, 0 + rjmp 6b + + .previous diff -Nur linux-2.6.16.11/arch/avr32/lib/csum_partial.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/csum_partial.S --- linux-2.6.16.11/arch/avr32/lib/csum_partial.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/csum_partial.S 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + /* + * unsigned int csum_partial(const unsigned char *buff, + * int len, unsigned int sum) + */ + .text + .global csum_partial + .type csum_partial,"function" + .align 1 +csum_partial: + /* checksum complete words, aligned or not */ +3: sub r11, 4 + brlt 5f +4: ld.w r9, r12++ + add r10, r9 + acr r10 + sub r11, 4 + brge 4b + + /* return if we had a whole number of words */ +5: sub r11, -4 + reteq r10 + + /* checksum any remaining bytes at the end */ + mov r9, 0 + mov r8, 0 + cp r11, 2 + brlt 6f + ld.uh r9, r12++ + sub r11, 2 + breq 7f + lsl r9, 16 +6: ld.ub r8, r12++ + lsl r8, 8 +7: or r9, r8 + add r10, r9 + acr r10 + + retal r10 + .size csum_partial, . - csum_partial diff -Nur linux-2.6.16.11/arch/avr32/lib/delay.c linux-2.6.16.11-avr32-20060626/arch/avr32/lib/delay.c --- linux-2.6.16.11/arch/avr32/lib/delay.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/delay.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,53 @@ +/* + * Precise Delay Loops for avr32 + * + * Copyright (C) 1993 Linus Torvalds + * Copyright (C) 1997 Martin Mares + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include + +#include +#include +#include + +int read_current_timer(unsigned long *timer_value) +{ + *timer_value = sysreg_read(COUNT); + return 0; +} + +void __delay(unsigned long loops) +{ + unsigned bclock, now; + + bclock = sysreg_read(COUNT); + do { + now = sysreg_read(COUNT); + } while ((now - bclock) < loops); +} + +inline void __const_udelay(unsigned long xloops) +{ + unsigned long long loops; + + loops = (current_cpu_data.loops_per_jiffy * HZ) * xloops; + __delay(loops >> 32); +} + +void __udelay(unsigned long usecs) +{ + __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ +} + +void __ndelay(unsigned long nsecs) +{ + __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */ +} diff -Nur linux-2.6.16.11/arch/avr32/lib/ext2-bitops.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/ext2-bitops.S --- linux-2.6.16.11/arch/avr32/lib/ext2-bitops.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/ext2-bitops.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + .text + .global ext2_find_first_zero_bit +ext2_find_first_zero_bit: + mov r10, 0 + mov r9, r11 +1: ldswp.w r8, r12[0] + com r8 + brne 2f + sub r12, -4 + sub r9, 32 + brge 1b + sub r9, -32 + com r10 + lsr r10, r10, r9 +2: brev r8 + or r8, r10 + clz r10, r8 + sub r11, r9 + add r11, r8 + retal r11 + + .global ext2_find_next_zero_bit +ext2_find_next_zero_bit: + lsr r8, r10, 5 // r8 = offset in # of words + sub r9, r11, r10 // r9 = size - offset + retle r11 // return size if offset >= size + + lsl r8, 2 // r8 = offset in # of bytes, word aligned + pushm lr + add r12, r8 // r12 -> first word + andl r10, 31, COH // r10 = offset into first word in bits + mov lr, 0 + breq 1f // no partial word at start? + + ldswp.w r8, r12[0] // r8 = first word + com r8 // r8 = ~(first word) + sub r12, -4 // r12 -> next word + lsr r8, r8, r10 // r8 = ~(first word) >> offset + brne 4f // at least one zero bit in first word? + + /* The number of bits just checked is 32 - (offset & 31) */ + rsub r8, r10, 32 // r8 = 32 - (offset & 31) + sub r9, r8 // r9 = size - (offset of second word) + brlt 3f // first word clipped in both ends? + + /* Main loop. Only checks whole words */ +1: ldswp.w r8, r12[0] + sub r9, 32 + brlt 5f // done yet? + sub r12, -4 + com r8 + brne 2f // at least one zero bit? + rjmp 1b + + /* Prepare to mask out bits beyond the end of the field */ +5: com lr // lr = 0xffffffff + com r8 + lsr lr, lr, r9 // bits beyond the end = 1 + +2: sub r9, -32 +6: brev r8 + or r8, lr // never return a value > size + clz r12, r8 // r12 = bit position of first set bit + sub r11, r9 // r11 = offset of matching word in bits + add r12, r11 // r12 = offset of matching bit (never >size) + popm pc + +4: /* we have a match, but is it inside the bitfield? */ + rsub r10, r10, 32 + cp.w r9, r10 + brge 6b + com lr + lsr lr, lr, r9 // bits beyond the end = 1 + rjmp 6b + +3: mov r12, r11 + popm pc diff -Nur linux-2.6.16.11/arch/avr32/lib/hsdramc.c linux-2.6.16.11-avr32-20060626/arch/avr32/lib/hsdramc.c --- linux-2.6.16.11/arch/avr32/lib/hsdramc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/hsdramc.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +struct hsdramc { + void __iomem *regs; +}; + +static void __init simple_udelay(unsigned long usecs) +{ + unsigned long count, expire; + + count = sysreg_read(COUNT); + expire = count + ((usecs * (boot_cpu_data.cpu_hz / 10000)) / 100); + + while (expire < count) + count = sysreg_read(COUNT); + + while (count < expire) + count = sysreg_read(COUNT); +} + +unsigned long __init sdram_init(struct at32_device *adev, + const struct sdram_info *info) +{ + struct hsdramc hsdramc; + unsigned long *sdram = phys_to_uncached(info->phys_addr); + unsigned long sdram_size; + unsigned long tmp; + unsigned int i; + + /* + * Do any part-specific initializations necessary to use the + * SDRAM (e.g. enable it in the HEBI mux). + */ + chip_enable_sdram(); + + if (at32_enable_device(adev)) { + printk(KERN_ERR "SDRAM: Failed to enable device\n"); + return 0; + } + + hsdramc.regs = at32_map_iomem(adev, 0); + if (!hsdramc.regs) { + printk(KERN_ERR "SDRAM: Failed to map control registers\n"); + return 0; + } + + sdram_size = 1 << (info->row_bits + info->col_bits + + info->bank_bits + 2); + + tmp = (HEBI_BF(NC, info->col_bits - 8) + | HEBI_BF(NR, info->row_bits - 11) + | HEBI_BF(NB, info->bank_bits - 1) + | HEBI_BF(CAS, info->cas) + | HEBI_BF(TWR, info->twr) + | HEBI_BF(TRC, info->trc) + | HEBI_BF(TRP, info->trp) + | HEBI_BF(TRCD, info->trcd) + | HEBI_BF(TRAS, info->tras) + | HEBI_BF(TXSR, info->txsr)); + hebi_writel(&hsdramc, SDRAMC_CR, tmp); + + /* + * Initialization sequence for SDRAM, from the data sheet: + * + * 1. A minimum pause of 200 us is provided to precede any + * signal toggle. + */ + simple_udelay(200); + + /* + * 2. A Precharge All command is issued to the SDRAM + */ + hebi_writel(&hsdramc, SDRAMC_MR, HEBI_MODE_PRECHARGE); + hebi_readl(&hsdramc, SDRAMC_MR); + writel(0, sdram); + + /* + * 3. Eight auto-refresh (CBR) cycles are provided + */ + hebi_writel(&hsdramc, SDRAMC_MR, HEBI_MODE_AUTO_REFRESH); + hebi_readl(&hsdramc, SDRAMC_MR); + for (i = 0; i < 8; i++) + writel(0, sdram); + + /* + * 4. A mode register set (MRS) cycle is issued to program + * SDRAM parameters, in particular CAS latency and burst + * length. + * + * CAS 2, burst length 1, serial burst type + */ + hebi_writel(&hsdramc, SDRAMC_MR, HEBI_MODE_LOAD_MODE); + hebi_readl(&hsdramc, SDRAMC_MR); + writel(0, sdram + 0x020); + + /* + * 5. A Normal Mode command is provided, 3 clocks after tMRD + * is met. + * + * From the timing diagram, it looks like tMRD is 3 + * cycles...try a dummy read from APB. + */ + hebi_readl(&hsdramc, SDRAMC_MR); + hebi_writel(&hsdramc, SDRAMC_MR, HEBI_MODE_NORMAL); + hebi_readl(&hsdramc, SDRAMC_MR); + writel(0, sdram); + + /* + * 6. Write refresh rate into SDRAMC refresh timer count + * register (refresh rate = timing between refresh cycles). + * + * 15.6 us is a typical value for a burst of length one + */ + hebi_writel(&hsdramc, SDRAMC_TR, + (156 * (at32_get_sclk_hz(adev, 0) / 1000)) / 10000); + + iounmap(hsdramc.regs); + + printk(KERN_INFO "SDRAM: %lu MB at address 0x%08lx\n", + sdram_size >> 20, info->phys_addr); + + printk(KERN_INFO "Testing SDRAM..."); + for (i = 0; i < sdram_size / 4; i++) + sdram[i] = i; + + for (i = 0; i < sdram_size / 4; i++) { + tmp = sdram[i]; + if (tmp != i) { + printk("FAILED at address 0x%08lx\n", + info->phys_addr + i * 4); + printk("SDRAM: read 0x%lx, expected 0x%x\n", tmp, i); + return 0; + } + } + + printk("OK\n"); + + return sdram_size; +} diff -Nur linux-2.6.16.11/arch/avr32/lib/io-readsl.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/io-readsl.S --- linux-2.6.16.11/arch/avr32/lib/io-readsl.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/io-readsl.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + .global __raw_readsl + .type __raw_readsl,@function +__raw_readsl: + cp.w r10, 0 + reteq r12 + + /* + * If r11 isn't properly aligned, we might get an exception on + * some implementations. But there's not much we can do about it. + */ +1: ld.w r8, r12[0] + sub r10, 1 + st.w r11++, r8 + brne 1b + + retal r12 diff -Nur linux-2.6.16.11/arch/avr32/lib/io-readsw.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/io-readsw.S --- linux-2.6.16.11/arch/avr32/lib/io-readsw.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/io-readsw.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +.Lnot_word_aligned: + /* + * Bad alignment will cause a hardware exception, which is as + * good as anything. No need for us to check for proper alignment. + */ + ld.uh r8, r12[0] + sub r10, 1 + st.h r11++, r8 + + /* fall through */ + + .global __raw_readsw + .type __raw_readsw,@function +__raw_readsw: + cp.w r10, 0 + reteq r12 + mov r9, 3 + tst r11, r9 + brne .Lnot_word_aligned + + sub r10, 2 + brlt 2f + +1: ldins.h r8:t, r12[0] + ldins.h r8:b, r12[0] + st.w r11++, r8 + sub r10, 2 + brge 1b + +2: sub r10, -2 + reteq r12 + + ld.uh r8, r12[0] + st.h r11++, r8 + retal r12 diff -Nur linux-2.6.16.11/arch/avr32/lib/io-writesl.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/io-writesl.S --- linux-2.6.16.11/arch/avr32/lib/io-writesl.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/io-writesl.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + .global __raw_writesl + .type __raw_writesl,@function +__raw_writesl: + cp.w r10, 0 + reteq r12 + +1: ld.w r8, r11++ + sub r10, 1 + st.w r12[0], r8 + brne 1b + + retal r12 diff -Nur linux-2.6.16.11/arch/avr32/lib/io-writesw.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/io-writesw.S --- linux-2.6.16.11/arch/avr32/lib/io-writesw.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/io-writesw.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +.Lnot_word_aligned: + ld.uh r8, r11++ + sub r10, 1 + st.h r12[0], r8 + + .global __raw_writesw + .type __raw_writesw,@function +__raw_writesw: + cp.w r10, 0 + mov r9, 3 + reteq r12 + tst r11, r9 + brne .Lnot_word_aligned + + sub r10, 2 + brlt 2f + +1: ld.w r8, r11++ + bfextu r9, r8, 16, 16 + st.h r12[0], r9 + st.h r12[0], r8 + sub r10, 2 + brge 1b + +2: sub r10, -2 + reteq r12 + + ld.uh r8, r11++ + st.h r12[0], r8 + retal r12 diff -Nur linux-2.6.16.11/arch/avr32/lib/libgcc.h linux-2.6.16.11-avr32-20060626/arch/avr32/lib/libgcc.h --- linux-2.6.16.11/arch/avr32/lib/libgcc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/libgcc.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,33 @@ +/* Definitions for various functions 'borrowed' from gcc-3.4.3 */ + +#define BITS_PER_UNIT 8 + +typedef int QItype __attribute__ ((mode (QI))); +typedef unsigned int UQItype __attribute__ ((mode (QI))); +typedef int HItype __attribute__ ((mode (HI))); +typedef unsigned int UHItype __attribute__ ((mode (HI))); +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); +typedef float SFtype __attribute__ ((mode (SF))); +typedef float DFtype __attribute__ ((mode (DF))); +typedef int word_type __attribute__ ((mode (__word__))); + +#define W_TYPE_SIZE (4 * BITS_PER_UNIT) +#define Wtype SItype +#define UWtype USItype +#define HWtype SItype +#define UHWtype USItype +#define DWtype DItype +#define UDWtype UDItype +#define __NW(a,b) __ ## a ## si ## b +#define __NDW(a,b) __ ## a ## di ## b + +struct DWstruct {Wtype high, low;}; + +typedef union +{ + struct DWstruct s; + DWtype ll; +} DWunion; diff -Nur linux-2.6.16.11/arch/avr32/lib/longlong.h linux-2.6.16.11-avr32-20060626/arch/avr32/lib/longlong.h --- linux-2.6.16.11/arch/avr32/lib/longlong.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/longlong.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,98 @@ +/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. + Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000 + Free Software Foundation, Inc. + + This definition file 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, or (at your option) any later version. + + This definition file is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Borrowed from gcc-3.4.3 */ + +#define __BITS4 (W_TYPE_SIZE / 4) +#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) + +#define count_leading_zeros(count, x) ((count) = __builtin_clz(x)) + +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0; \ + UWtype __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (UWtype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +#define udiv_qrnnd __udiv_qrnnd_c + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) - (bl); \ + (sh) = (ah) - (bh) - (__x > (al)); \ + (sl) = __x; \ + } while (0) + +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UWtype __x0, __x1, __x2, __x3; \ + UHWtype __ul, __vl, __uh, __vh; \ + \ + __ul = __ll_lowpart (u); \ + __uh = __ll_highpart (u); \ + __vl = __ll_lowpart (v); \ + __vh = __ll_highpart (v); \ + \ + __x0 = (UWtype) __ul * __vl; \ + __x1 = (UWtype) __ul * __vh; \ + __x2 = (UWtype) __uh * __vl; \ + __x3 = (UWtype) __uh * __vh; \ + \ + __x1 += __ll_highpart (__x0);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += __ll_B; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + __ll_highpart (__x1); \ + (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ + } while (0) diff -Nur linux-2.6.16.11/arch/avr32/lib/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/lib/Makefile --- linux-2.6.16.11/arch/avr32/lib/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/Makefile 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,13 @@ +# +# Makefile for AVR32-specific library files +# + +lib-y := copy_user.o clear_user.o +lib-y += strncpy_from_user.o strnlen_user.o +lib-y += delay.o memset.o memcpy.o +lib-y += csum_partial.o csum_partial_copy_generic.o +lib-y += ext2-bitops.o io-readsw.o io-readsl.o +lib-y += io-writesw.o io-writesl.o +lib-y += __udivdi3.o +lib-y += __avr32_lsl64.o __avr32_lsr64.o __avr32_asr64.o +lib-y += hsdramc.o spd.o diff -Nur linux-2.6.16.11/arch/avr32/lib/memcpy.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/memcpy.S --- linux-2.6.16.11/arch/avr32/lib/memcpy.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/memcpy.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + /* + * void *memcpy(void *to, const void *from, unsigned long n) + * + * This implementation does word-aligned loads in the main loop, + * possibly sacrificing alignment of stores. + * + * Hopefully, in most cases, both "to" and "from" will be + * word-aligned to begin with. + */ + .text + .global memcpy + .type memcpy, @function +memcpy: + mov r9, r11 + andl r9, 3, COH + brne 1f + + /* At this point, "from" is word-aligned */ +2: sub r10, 4 + mov r9, r12 + brlt 4f + +3: ld.w r8, r11++ + sub r10, 4 + st.w r12++, r8 + brge 3b + +4: neg r10 + reteq r9 + + /* Handle unaligned count */ + lsl r10, 2 + add pc, pc, r10 + ld.ub r8, r11++ + st.b r12++, r8 + ld.ub r8, r11++ + st.b r12++, r8 + ld.ub r8, r11++ + st.b r12++, r8 + retal r9 + + /* Handle unaligned "from" pointer */ +1: sub r10, 4 + brlt 4b + add r10, r9 + lsl r9, 2 + add pc, pc, r9 + ld.ub r8, r11++ + st.b r12++, r8 + ld.ub r8, r11++ + st.b r12++, r8 + ld.ub r8, r11++ + st.b r12++, r8 + rjmp 2b diff -Nur linux-2.6.16.11/arch/avr32/lib/memset.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/memset.S --- linux-2.6.16.11/arch/avr32/lib/memset.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/memset.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * Based on linux/arch/arm/lib/memset.S + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include + + /* + * r12: void *b + * r11: int c + * r10: size_t len + * + * Returns b in r12 + */ + .text + .global memset + .type memset, @function + .align 5 +memset: + mov r9, r12 + mov r8, r12 + or r11, r11, r11 << 8 + andl r9, 3, COH + brne 1f + +2: or r11, r11, r11 << 16 + sub r10, 4 + brlt 5f + + /* Let's do some real work */ +4: st.w r8++, r11 + sub r10, 4 + brge 4b + + /* + * When we get here, we've got less than 4 bytes to set. r10 + * might be negative. + */ +5: sub r10, -4 + reteq r12 + + /* Fastpath ends here, exactly 32 bytes from memset */ + + /* Handle unaligned count or pointer */ + bld r10, 1 + brcc 6f + st.b r8++, r11 + st.b r8++, r11 + bld r10, 0 + retcc r12 +6: st.b r8++, r11 + retal r12 + + /* Handle unaligned pointer */ +1: sub r10, 4 + brlt 5b + add r10, r9 + lsl r9, 1 + add pc, r9 + st.b r8++, r11 + st.b r8++, r11 + st.b r8++, r11 + rjmp 2b + + .size memset, . - memset diff -Nur linux-2.6.16.11/arch/avr32/lib/spd.c linux-2.6.16.11-avr32-20060626/arch/avr32/lib/spd.c --- linux-2.6.16.11/arch/avr32/lib/spd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/spd.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +struct twi { + void __iomem *regs; + struct at32_device *adev; + u8 chip; +}; + +#define SPD_BUS_SPEED 50000 +#define SPD_I2C_ADDR 0x50 + +static int __init ns_to_cycles(struct twi *twi, int ns) +{ + int cycles; + + cycles = (ns * (at32_get_sclk_hz(twi->adev, 0) / 1000) + + 999999) / 1000000; + return cycles; +} + +static void __init twi_set_speed(struct twi *twi, int speed) +{ + unsigned int cldiv; + unsigned int ckdiv = 0; + + cldiv = at32_get_sclk_hz(twi->adev, 0) / (speed * 2) - 4; + + while (cldiv > 255) { + ckdiv++; + cldiv /= 2; + } + + twi_writel(twi, CWGR, (TWI_BF(CLDIV, cldiv) + | TWI_BF(CHDIV, cldiv) + | TWI_BF(CKDIV, ckdiv))); +} + +static int __init twi_probe(struct twi *twi, u8 chip) +{ + u32 sr; + int ret = -ENODEV; + int timeout = 1000000; + + twi_writel(twi, MMR, TWI_BF(DADR, chip) | TWI_BIT(MREAD)); + twi_writel(twi, IADR, 0); + twi_writel(twi, CR, TWI_BIT(START) | TWI_BIT(STOP)); + + do { + sr = twi_readl(twi, SR); + if (sr & TWI_BIT(RXRDY)) { + ret = 0; + twi->chip = chip; + (void)twi_readl(twi, RHR); + } + if (--timeout == 0) { + printk("SPD: timed out probing chip address 0x%02x\n", + chip); + break; + } + } while (!(sr & TWI_BIT(TXCOMP))); + + return ret; +} + +static int __init spd_read_register(struct twi *twi, u8 reg) +{ + u32 sr; + int timeout; + int ret = -EIO; + + twi_writel(twi, MMR, (TWI_BF(DADR, twi->chip) + | TWI_BIT(MREAD) + | TWI_BF(IADRSZ, 1))); + twi_writel(twi, IADR, reg); + twi_writel(twi, CR, TWI_BIT(START) | TWI_BIT(STOP)); + + for (timeout = 100000; timeout > 0; timeout--) { + sr = twi_readl(twi, SR); + if (sr & TWI_BIT(RXRDY)) + ret = twi_readl(twi, RHR); + if (sr & TWI_BIT(TXCOMP)) + break; + } + + if (!(sr & TWI_BIT(TXCOMP))) { + printk("SPD: read from %02x:%02x timed out\n", + twi->chip, reg); + return -ETIMEDOUT; + } + + return ret; +} + +#define spd_read(twi, value, reg) \ + do { \ + ret = spd_read_register(twi, reg); \ + if (ret < 0) \ + goto out; \ + (value) = ret; \ + } while (0) + +int sdram_read_spd(struct at32_device *adev, + struct sdram_info *info) +{ + struct twi twi; + unsigned int nr_banks, ns; + int ret; + + twi.adev = adev; + if (at32_enable_device(adev)) { + printk(KERN_ERR "SPD: Failed to enable TWI device\n"); + return -ENOMEM; + } + + twi.regs = at32_map_iomem(adev, 0); + if (!twi.regs) { + printk(KERN_ERR "SPD: Failed to map TWI registers\n"); + return -ENOMEM; + } + + twi_writel(&twi, CR, TWI_BIT(SWRST)); + twi_writel(&twi, CR, TWI_BIT(MSEN) | TWI_BIT(SVDIS)); + twi_set_speed(&twi, SPD_BUS_SPEED); + + ret = twi_probe(&twi, SPD_I2C_ADDR); + if (ret < 0) + goto out; + + spd_read(&twi, info->row_bits, 3); + info->row_bits &= 0x0f; + spd_read(&twi, info->col_bits, 4); + info->col_bits &= 0x0f; + spd_read(&twi, nr_banks, 17); + spd_read(&twi, ns, 27); + if (ns) + info->trp = ns_to_cycles(&twi, ns); + spd_read(&twi, ns, 29); + if (ns) + info->trcd = ns_to_cycles(&twi, ns); + spd_read(&twi, ns, 30); + if (ns) + info->tras = ns_to_cycles(&twi, ns); + + switch (nr_banks) { + case 2: + info->bank_bits = 1; + break; + case 4: + info->bank_bits = 2; + break; + default: + printk("SPD: %u banks not supported; assuming 2 banks\n", + nr_banks); + info->bank_bits = 1; + break; + } + + printk("SPD: SDRAM parameters read successfully\n"); + ret = 0; + +out: + twi_writel(&twi, CR, TWI_BIT(SWRST)); + iounmap(twi.regs); + return ret; +} diff -Nur linux-2.6.16.11/arch/avr32/lib/strncpy_from_user.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/strncpy_from_user.S --- linux-2.6.16.11/arch/avr32/lib/strncpy_from_user.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/strncpy_from_user.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,60 @@ +/* + * Copy to/from userspace with optional address space checking. + * + * Copyright 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + +#include +#include +#include + + /* + * long strncpy_from_user(char *dst, const char *src, long count) + * + * On success, returns the length of the string, not including + * the terminating NUL. + * + * If the string is longer than count, returns count + * + * If userspace access fails, returns -EFAULT + */ + .text + .align 1 + .global strncpy_from_user + .type strncpy_from_user, "function" +strncpy_from_user: + mov r9, -EFAULT + branch_if_kernel r8, __strncpy_from_user + ret_if_privileged r8, r11, r10, r9 + + .global __strncpy_from_user + .type __strncpy_from_user, "function" +__strncpy_from_user: + cp.w r10, 0 + reteq 0 + + mov r9, r10 + +1: ld.ub r8, r11++ + st.b r12++, r8 + cp.w r8, 0 + breq 2f + sub r9, 1 + brne 1b + +2: sub r10, r9 + retal r10 + + .section .fixup, "ax" + .align 1 +3: mov r12, -EFAULT + retal r12 + + .section __ex_table, "a" + .align 2 + .long 1b, 3b diff -Nur linux-2.6.16.11/arch/avr32/lib/strnlen_user.S linux-2.6.16.11-avr32-20060626/arch/avr32/lib/strnlen_user.S --- linux-2.6.16.11/arch/avr32/lib/strnlen_user.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/strnlen_user.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,67 @@ +/* + * Copy to/from userspace with optional address space checking. + * + * Copyright 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include + + .text + .align 1 + .global strnlen_user + .type strnlen_user, "function" +strnlen_user: + branch_if_kernel r8, __strnlen_user + sub r8, r11, 1 + add r8, r12 + retcs 0 + brmi adjust_length /* do a closer inspection */ + + .global __strnlen_user + .type __strnlen_user, "function" +__strnlen_user: + mov r10, r12 + +10: ld.ub r8, r12++ + cp.w r8, 0 + breq 2f + sub r11, 1 + brne 10b + + sub r12, -1 +2: sub r12, r10 + retal r12 + + + .type adjust_length, "function" +adjust_length: + cp.w r12, 0 /* addr must always be < TASK_SIZE */ + retmi 0 + + pushm lr + lddpc lr, _task_size + sub r11, lr, r12 + mov r9, r11 + rcall __strnlen_user + cp.w r12, r9 + brgt 1f + popm pc +1: popm pc, r12=0 + + .align 2 +_task_size: + .long TASK_SIZE + + .section .fixup, "ax" + .align 1 +19: retal 0 + + .section __ex_table, "a" + .align 2 + .long 10b, 19b diff -Nur linux-2.6.16.11/arch/avr32/lib/__udivdi3.c linux-2.6.16.11-avr32-20060626/arch/avr32/lib/__udivdi3.c --- linux-2.6.16.11/arch/avr32/lib/__udivdi3.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/lib/__udivdi3.c 2006-06-26 11:33:51.000000000 +0200 @@ -0,0 +1,229 @@ +/* More subroutines needed by GCC output code on some machines. */ +/* Compile this one with gcc. */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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, or (at your option) any later +version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* This file is "borrowed" from gcc-3.4.3, hopefully only as a + temporary measure against ABI differences between kernel- and + user-space. */ + +#include "libgcc.h" +#include "longlong.h" + +static UDWtype +__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) +{ + const DWunion nn = {.ll = n}; + const DWunion dd = {.ll = d}; + DWunion rr; + UWtype d0, d1, n0, n1, n2; + UWtype q0, q1; + UWtype b, bm; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + count_leading_zeros (bm, d0); + + if (bm != 0) + { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros (bm, d0); + + if (bm == 0) + { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of W_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } + else + { + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + if (rp != 0) + { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + /* 0q = NN / dd */ + + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); + } + else + q0 = 0; + + q1 = 0; + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + UWtype m1, m0; + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + const DWunion ww = {{.low = q0, .high = q1}}; + return ww.ll; +} + +UDWtype +__avr32_umod64 (UDWtype u, UDWtype v) +{ + UDWtype w; + + (void) __udivmoddi4 (u, v, &w); + + return w; +} + +UDWtype +__avr32_udiv64 (UDWtype n, UDWtype d) +{ + return __udivmoddi4 (n, d, (UDWtype *) 0); +} diff -Nur linux-2.6.16.11/arch/avr32/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/Makefile --- linux-2.6.16.11/arch/avr32/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/Makefile 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,100 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2004-2006 Atmel Corporation. + +# Default target when executing plain make +.PHONY: all +all: uImage vmlinux.elf linux.lst + +CFLAGS += -pipe -fno-builtin -mno-pic +AFLAGS += -mrelax -mno-pic +CFLAGS_MODULE += -mno-relax +LDFLAGS_vmlinux += --relax + +cpuflags-$(CONFIG_CPU_AP7000) += -mcpu=ap7000 + +CFLAGS += $(cpuflags-y) +AFLAGS += $(cpuflags-y) + +CHECKFLAGS += -D__avr32__ + +LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +head-$(CONFIG_LOADER_STANDALONE) += arch/avr32/boot/standalone/head.o +head-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/head.o +head-y += arch/avr32/kernel/head.o +core-$(CONFIG_PLATFORM_AT32AP) += arch/avr32/platforms/at32ap/ +core-$(CONFIG_BOARD_AT32STK1000) += arch/avr32/boards/at32stk1000/ +core-$(CONFIG_LOADER_STANDALONE) += arch/avr32/boot/standalone/ +core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/ +core-$(CONFIG_SUBARCH_AVR32B) += arch/avr32/avr32b/ +core-y += arch/avr32/kernel/ +core-y += arch/avr32/mm/ +core-$(CONFIG_LOADER_STANDALONE) += arch/avr32/usr/ +drivers-$(CONFIG_OPROFILE) += arch/avr32/oprofile/ +drivers-y += arch/avr32/drivers/ +libs-y += arch/avr32/lib/ #$(LIBGCC) + +archincdir-$(CONFIG_SUBARCH_AVR32B) := arch-avr32b + +platincdir-$(CONFIG_PLATFORM_AT32AP) := platform-at32ap + +include/asm-avr32/.arch: $(wildcard include/config/subarch/*.h) include/config/MARKER + @echo ' SYMLINK include/asm-avr32/arch -> include/asm-avr32/$(archincdir-y)' +ifneq ($(KBUILD_SRC),) + $(Q)mkdir -p include/asm-avr32 + $(Q)ln -fsn $(srctree)/include/asm-avr32/$(archincdir-y) include/asm-avr32/arch +else + $(Q)ln -fsn $(archincdir-y) include/asm-avr32/arch +endif + @touch $@ + +include/asm-avr32/.platform: $(wildcard include/config/platform/*.h) include/config/MARKER + @echo ' SYMLINK include/asm-avr32/platform -> include/asm-avr32/$(platincdir-y)' +ifneq ($(KBUILD_SRC),) + $(Q)mkdir -p include/asm-avr32 + $(Q)ln -fsn $(srctree)/include/asm-avr32/$(platincdir-y) include/asm-avr32/platform +else + $(Q)ln -fsn $(platincdir-y) include/asm-avr32/platform +endif + @touch $@ + +archprepare: include/asm-avr32/.arch include/asm-avr32/.platform + +BOOT_TARGETS := vmlinux.elf vmlinux.bin uImage uImage.srec + +.PHONY: $(BOOT_TARGETS) install + +boot := arch/$(ARCH)/boot/images + + KBUILD_IMAGE := $(boot)/uImage +vmlinux.elf: KBUILD_IMAGE := $(boot)/vmlinux.elf +vmlinux.cso: KBUILD_IMAGE := $(boot)/vmlinux.cso +uImage.srec: KBUILD_IMAGE := $(boot)/uImage.srec +uImage: KBUILD_IMAGE := $(boot)/uImage + +quiet_cmd_listing = LST $@ + cmd_listing = avr32-linux-objdump $(OBJDUMPFLAGS) -lS $< > $@ +quiet_cmd_disasm = DIS $@ + cmd_disasm = avr32-linux-objdump $(OBJDUMPFLAGS) -d $< > $@ + +vmlinux.elf vmlinux.bin uImage.srec uImage vmlinux.cso: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +install: vmlinux + $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@ + +linux.s: vmlinux + $(call if_changed,disasm) + +linux.lst: vmlinux + $(call if_changed,listing) + +define archhelp + @echo '* vmlinux.elf - ELF image with load address 0' + @echo ' vmlinux.cso - PathFinder CSO image' + @echo ' uImage - Create a bootable image for U-Boot' +endef diff -Nur linux-2.6.16.11/arch/avr32/Makefile.orig linux-2.6.16.11-avr32-20060626/arch/avr32/Makefile.orig --- linux-2.6.16.11/arch/avr32/Makefile.orig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/Makefile.orig 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,98 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2004-2006 Atmel Corporation. + +# Default target when executing plain make +.PHONY: all +all: uImage vmlinux.elf linux.lst + +CFLAGS += -pipe -fno-builtin -mno-pic +AFLAGS += -mrelax -mno-pic +CFLAGS_MODULE += -mno-relax +LDFLAGS_vmlinux += --relax + +cpuflags-$(CONFIG_CPU_AP7000) += -mcpu=ap7000 + +CFLAGS += $(cpuflags-y) +AFLAGS += $(cpuflags-y) + +CHECKFLAGS += -D__avr32__ + +LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +head-$(CONFIG_LOADER_STANDALONE) += arch/avr32/boot/standalone/head.o +head-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/head.o +head-y += arch/avr32/kernel/head.o +core-$(CONFIG_PLATFORM_AT32AP) += arch/avr32/platforms/at32ap/ +core-$(CONFIG_BOARD_AT32STK1000) += arch/avr32/boards/at32stk1000/ +core-$(CONFIG_LOADER_STANDALONE) += arch/avr32/boot/standalone/ +core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/ +core-$(CONFIG_SUBARCH_AVR32B) += arch/avr32/avr32b/ +core-y += arch/avr32/kernel/ +core-y += arch/avr32/mm/ +core-$(CONFIG_LOADER_STANDALONE) += arch/avr32/usr/ +libs-y += arch/avr32/lib/ #$(LIBGCC) + +archincdir-$(CONFIG_SUBARCH_AVR32B) := arch-avr32b + +platincdir-$(CONFIG_PLATFORM_AT32AP) := platform-at32ap + +include/asm-avr32/.arch: $(wildcard include/config/subarch/*.h) include/config/MARKER + @echo ' SYMLINK include/asm-avr32/arch -> include/asm-avr32/$(archincdir-y)' +ifneq ($(KBUILD_SRC),) + $(Q)mkdir -p include/asm-avr32 + $(Q)ln -fsn $(srctree)/include/asm-avr32/$(archincdir-y) include/asm-avr32/arch +else + $(Q)ln -fsn $(archincdir-y) include/asm-avr32/arch +endif + @touch $@ + +include/asm-avr32/.platform: $(wildcard include/config/platform/*.h) include/config/MARKER + @echo ' SYMLINK include/asm-avr32/platform -> include/asm-avr32/$(platincdir-y)' +ifneq ($(KBUILD_SRC),) + $(Q)mkdir -p include/asm-avr32 + $(Q)ln -fsn $(srctree)/include/asm-avr32/$(platincdir-y) include/asm-avr32/platform +else + $(Q)ln -fsn $(platincdir-y) include/asm-avr32/platform +endif + @touch $@ + +archprepare: include/asm-avr32/.arch include/asm-avr32/.platform + +BOOT_TARGETS := vmlinux.elf vmlinux.bin uImage uImage.srec + +.PHONY: $(BOOT_TARGETS) install + +boot := arch/$(ARCH)/boot/images + + KBUILD_IMAGE := $(boot)/uImage +vmlinux.elf: KBUILD_IMAGE := $(boot)/vmlinux.elf +vmlinux.cso: KBUILD_IMAGE := $(boot)/vmlinux.cso +uImage.srec: KBUILD_IMAGE := $(boot)/uImage.srec +uImage: KBUILD_IMAGE := $(boot)/uImage + +quiet_cmd_listing = LST $@ + cmd_listing = avr32-linux-objdump $(OBJDUMPFLAGS) -lS $< > $@ +quiet_cmd_disasm = DIS $@ + cmd_disasm = avr32-linux-objdump $(OBJDUMPFLAGS) -d $< > $@ + +vmlinux.elf vmlinux.bin uImage.srec uImage vmlinux.cso: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +install: vmlinux + $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@ + +linux.s: vmlinux + $(call if_changed,disasm) + +linux.lst: vmlinux + $(call if_changed,listing) + +define archhelp + @echo '* vmlinux.elf - ELF image with load address 0' + @echo ' vmlinux.cso - PathFinder CSO image' + @echo ' uImage - Create a bootable image for U-Boot' +endef diff -Nur linux-2.6.16.11/arch/avr32/mm/cache.c linux-2.6.16.11-avr32-20060626/arch/avr32/mm/cache.c --- linux-2.6.16.11/arch/avr32/mm/cache.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/cache.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include +#include +#include + +/* + * If you attempt to flush anything more than this, you need superuser + * privileges. The value is completely arbitrary. + */ +#define CACHEFLUSH_MAX_LEN 1024 + +void invalidate_dcache_region(void *start, size_t size) +{ + unsigned long v, begin, end, linesz; + + linesz = boot_cpu_data.dcache.linesz; + + //printk("invalidate dcache: %p + %u\n", start, size); + + /* You asked for it, you got it */ + begin = (unsigned long)start & ~(linesz - 1); + end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); + + for (v = begin; v < end; v += linesz) + invalidate_dcache_line((void *)v); +} + +void clean_dcache_region(void *start, size_t size) +{ + unsigned long v, begin, end, linesz; + + linesz = boot_cpu_data.dcache.linesz; + begin = (unsigned long)start & ~(linesz - 1); + end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); + + for (v = begin; v < end; v += linesz) + clean_dcache_line((void *)v); + flush_write_buffer(); +} + +void flush_dcache_region(void *start, size_t size) +{ + unsigned long v, begin, end, linesz; + + linesz = boot_cpu_data.dcache.linesz; + begin = (unsigned long)start & ~(linesz - 1); + end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); + + for (v = begin; v < end; v += linesz) + flush_dcache_line((void *)v); + flush_write_buffer(); +} + +void invalidate_icache_region(void *start, size_t size) +{ + unsigned long v, begin, end, linesz; + + linesz = boot_cpu_data.icache.linesz; + begin = (unsigned long)start & ~(linesz - 1); + end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); + + for (v = begin; v < end; v += linesz) + invalidate_icache_line((void *)v); +} + +static inline void __flush_icache_range(unsigned long start, unsigned long end) +{ + unsigned long v, linesz; + + linesz = boot_cpu_data.dcache.linesz; + for (v = start; v < end; v += linesz) { + clean_dcache_line((void *)v); + invalidate_icache_line((void *)v); + } + + flush_write_buffer(); +} + +/* + * This one is called after a module has been loaded. + */ +void flush_icache_range(unsigned long start, unsigned long end) +{ + unsigned long linesz; + + linesz = boot_cpu_data.dcache.linesz; + __flush_icache_range(start & ~(linesz - 1), + (end + linesz - 1) & ~(linesz - 1)); +} + +/* + * This one is called from do_no_page(), do_swap_page() and install_page(). + */ +void flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + if (vma->vm_flags & VM_EXEC) { + void *v = kmap(page); + __flush_icache_range((unsigned long)v, (unsigned long)v + PAGE_SIZE); + kunmap(v); + } +} + +/* + * This one is used by copy_to_user_page() + */ +void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) +{ + if (vma->vm_flags & VM_EXEC) + flush_icache_range(addr, addr + len); +} + +asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len) +{ + int ret; + + if (len > CACHEFLUSH_MAX_LEN) { + ret = -EPERM; + if (!capable(CAP_SYS_ADMIN)) + goto out; + } + + ret = -EFAULT; + if (!access_ok(VERIFY_WRITE, addr, len)) + goto out; + + switch (operation) { + case CACHE_IFLUSH: + flush_icache_range((unsigned long)addr, + (unsigned long)addr + len); + ret = 0; + break; + default: + ret = -EINVAL; + } + +out: + return ret; +} diff -Nur linux-2.6.16.11/arch/avr32/mm/clear_page.S linux-2.6.16.11-avr32-20060626/arch/avr32/mm/clear_page.S --- linux-2.6.16.11/arch/avr32/mm/clear_page.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/clear_page.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +/* + * clear_page + * r12: P1 address (to) + */ + .text + .global clear_page +clear_page: + sub r9, r12, -PAGE_SIZE + mov r10, 0 + mov r11, 0 +0: st.d r12++, r10 + cp r12, r9 + brne 0b + mov pc, lr diff -Nur linux-2.6.16.11/arch/avr32/mm/copy_page.S linux-2.6.16.11-avr32-20060626/arch/avr32/mm/copy_page.S --- linux-2.6.16.11/arch/avr32/mm/copy_page.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/copy_page.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +/* + * copy_page + * + * r12 to (P1 address) + * r11 from (P1 address) + * r8-r10 scratch + */ + .text + .global copy_page +copy_page: + sub r10, r11, -(1 << PAGE_SHIFT) + /* pref r11[0] */ +1: /* pref r11[8] */ + ld.d r8, r11++ + st.d r12++, r8 + cp r11, r10 + brlo 1b + mov pc, lr diff -Nur linux-2.6.16.11/arch/avr32/mm/discontig.c linux-2.6.16.11-avr32-20060626/arch/avr32/mm/discontig.c --- linux-2.6.16.11/arch/avr32/mm/discontig.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/discontig.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#if MAX_NUMNODES != 4 +#error Fix Me Please +#endif + +static bootmem_data_t node_bootmem_data[MAX_NUMNODES]; +pg_data_t discontig_node_data[MAX_NUMNODES] = { + { .bdata = &node_bootmem_data[0] }, + { .bdata = &node_bootmem_data[1] }, + { .bdata = &node_bootmem_data[2] }, + { .bdata = &node_bootmem_data[3] } +}; + +EXPORT_SYMBOL(discontig_node_data); + diff -Nur linux-2.6.16.11/arch/avr32/mm/dma-coherent.c linux-2.6.16.11-avr32-20060626/arch/avr32/mm/dma-coherent.c --- linux-2.6.16.11/arch/avr32/mm/dma-coherent.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/dma-coherent.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include + +#include +#include + +void dma_cache_sync(void *vaddr, size_t size, int direction) +{ + /* + * No need to sync an uncached area + */ + if (PXSEG(vaddr) == P2SEG) + return; + + switch (direction) { + case DMA_FROM_DEVICE: /* invalidate only */ + dma_cache_inv(vaddr, size); + break; + case DMA_TO_DEVICE: /* writeback only */ + dma_cache_wback(vaddr, size); + break; + case DMA_BIDIRECTIONAL: /* writeback and invalidate */ + dma_cache_wback_inv(vaddr, size); + break; + default: + BUG(); + } +} +EXPORT_SYMBOL(dma_cache_sync); + +static struct page *__dma_alloc(struct device *dev, size_t size, + dma_addr_t *handle, int gfp) +{ + struct page *page, *end; + + int order; + + size = PAGE_ALIGN(size); + order = get_order(size); + + page = alloc_pages(gfp, order); + if (!page) + return NULL; + + /* + * When accessing physical memory with valid cache data, we + * get a cache hit even if the virtual memory region is marked + * as uncached. + * + * Since the memory is newly allocated, there is no point in + * doing a writeback. If the previous owner cares, he should + * have flushed the cache before releasing the memory. + */ + invalidate_dcache_region(phys_to_virt(page_to_phys(page)), size); + + *handle = page_to_bus(page); + end = page + (1 << order); + + /* + * Set page count to 1 on all pages so that we can free them + * individually. + */ + do { + set_page_count(page, 1); + SetPageReserved(page); + page++; + } while (size -= PAGE_SIZE); + + + /* + * Free any unused pages + */ + while (page < end) { + set_page_count(page, 1); + __free_page(page); + page++; + } + + return page - (1 << order); +} + +static void __dma_free(struct device *dev, size_t size, + struct page *page, dma_addr_t handle) +{ + struct page *end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT); + + while (page < end) { + if (page_count(page) != 1) + pr_debug("page %08lx has count %u\n", + page_to_phys(page), page_count(page)); + ClearPageReserved(page); + __free_page(page); + ++page; + } +} + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *handle, int gfp) +{ + struct page *page; + void *ret = NULL; + + page = __dma_alloc(dev, size, handle, gfp); + if (page) + ret = phys_to_uncached(page_to_phys(page)); + + return ret; +} +EXPORT_SYMBOL(dma_alloc_coherent); + +void dma_free_coherent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t handle) +{ + void *addr = phys_to_cached(uncached_to_phys(cpu_addr)); + struct page *page; + + pr_debug("dma_free_coherent addr %p (phys %08lx) size %u\n", + cpu_addr, (unsigned long)handle, (unsigned)size); + BUG_ON(!virt_addr_valid(addr)); + page = virt_to_page(addr); + __dma_free(dev, size, page, handle); +} +EXPORT_SYMBOL(dma_free_coherent); + +#if 0 +void *dma_alloc_writecombine(struct device *dev, size_t size, + dma_addr_t *handle, int gfp) +{ + struct page *page; + + page = __dma_alloc(dev, size, handle, gfp); + + /* Now, map the page into P3 with write-combining turned on */ + return __ioremap(page_to_phys(page), size, _PAGE_BUFFER); +} +EXPORT_SYMBOL(dma_alloc_writecombine); + +void dma_free_writecombine(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t handle) +{ + struct page *page; + + iounmap(cpu_addr); + + page = bus_to_page(handle); + __dma_free(dev, size, page, handle); +} +EXPORT_SYMBOL(dma_free_writecombine); +#endif diff -Nur linux-2.6.16.11/arch/avr32/mm/fault.c linux-2.6.16.11-avr32-20060626/arch/avr32/mm/fault.c --- linux-2.6.16.11/arch/avr32/mm/fault.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/fault.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * Based on linux/arch/sh/mm/fault.c: + * Copyright (C) 1999 Niibe Yutaka + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef DEBUG +static void dump_code(unsigned long pc) +{ + char *p = (char *)pc; + char val; + int i; + + + printk(KERN_DEBUG "Code:"); + for (i = 0; i < 16; i++) { + if (__get_user(val, p + i)) + break; + printk(" %02x", val); + } + printk("\n"); +} +#endif + +/* + * This routine handles page faults. It determines the address and the + * problem, and then passes it off to one of the appropriate routines. + * + * ecr is the Exception Cause Register. Possible values are: + * 5: Page not found (instruction access) + * 6: Protection fault (instruction access) + * 12: Page not found (read access) + * 13: Page not found (write access) + * 14: Protection fault (read access) + * 15: Protection fault (write access) + */ +asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) +{ + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct *vma; + const struct exception_table_entry *fixup; + unsigned long address; + unsigned long page; + int writeaccess = 0; + + address = sysreg_read(TLBEAR); + + tsk = current; + mm = tsk->mm; + + /* + * If we're in an interrupt or have no user context, we must + * not take the fault... + */ + if (in_atomic() || !mm || regs->sr & SYSREG_BIT(GM)) + goto no_context; + + local_irq_enable(); + + down_read(&mm->mmap_sem); + + vma = find_vma(mm, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (expand_stack(vma, address)) + goto bad_area; + + /* + * Ok, we have a good vm_area for this memory access, so we + * can handle it... + */ +good_area: + //pr_debug("good area: vm_flags = 0x%lx\n", vma->vm_flags); + switch (ecr) { + case ECR_PROTECTION_X: + case ECR_TLB_MISS_X: + if (!(vma->vm_flags & VM_EXEC)) + goto bad_area; + break; + case ECR_PROTECTION_R: + case ECR_TLB_MISS_R: + if (!(vma->vm_flags & VM_READ)) + goto bad_area; + break; + case ECR_PROTECTION_W: + case ECR_TLB_MISS_W: + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + writeaccess = 1; + break; + default: + panic("Unhandled case %lu in do_page_fault!", ecr); + } + + /* + * If for any reason at all we couldn't handle the fault, make + * sure we exit gracefully rather than endlessly redo the + * fault. + */ +survive: + switch (handle_mm_fault(mm, vma, address, writeaccess)) { + case VM_FAULT_MINOR: + tsk->min_flt++; + break; + case VM_FAULT_MAJOR: + tsk->maj_flt++; + break; + case VM_FAULT_SIGBUS: + goto do_sigbus; + case VM_FAULT_OOM: + goto out_of_memory; + default: + BUG(); + } + + up_read(&mm->mmap_sem); + return; + + /* + * Something tried to access memory that isn't in our memory + * map. Fix it, but check if it's kernel or user first... + */ +bad_area: + pr_debug("Bad area [%s:%u]: addr %08lx, ecr %lu\n", + tsk->comm, tsk->pid, address, ecr); + + up_read(&mm->mmap_sem); + + if (user_mode(regs)) { + /* Hmm...we have to pass address and ecr somehow... */ + /* tsk->thread.address = address; + tsk->thread.error_code = ecr; */ +#ifdef DEBUG + show_regs(regs); + dump_code(regs->pc); + + page = sysreg_read(PTBR); + printk("ptbr = %08lx", page); + if (page) { + page = ((unsigned long *)page)[address >> 22]; + printk(" pgd = %08lx", page); + if (page & _PAGE_PRESENT) { + page &= PAGE_MASK; + address &= 0x003ff000; + page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT]; + printk(" pte = %08lx\n", page); + } + } +#endif + pr_debug("Sending SIGSEGV to PID %d...\n", + tsk->pid); + force_sig(SIGSEGV, tsk); + return; + } + +no_context: + pr_debug("No context\n"); + + /* Are we prepared to handle this kernel fault? */ + fixup = search_exception_tables(regs->pc); + if (fixup) { + regs->pc = fixup->fixup; + pr_debug("Found fixup at %08lx\n", fixup->fixup); + return; + } + + /* + * Oops. The kernel tried to access some bad page. We'll have + * to terminate things with extreme prejudice. + */ + if (address < PAGE_SIZE) + printk(KERN_ALERT + "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT + "Unable to handle kernel paging request"); + printk(" at virtual address %08lx\n", address); + printk(KERN_ALERT "pc = %08lx\n", regs->pc); + + page = sysreg_read(PTBR); + printk(KERN_ALERT "ptbr = %08lx", page); + if (page) { + page = ((unsigned long *)page)[address >> 22]; + printk(" pgd = %08lx", page); + if (page & _PAGE_PRESENT) { + page &= PAGE_MASK; + address &= 0x003ff000; + page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT]; + printk(" pte = %08lx\n", page); + } + } + die("\nOops", regs, ecr); + do_exit(SIGKILL); + + /* + * We ran out of memory, or some other thing happened to us + * that made us unable to handle the page fault gracefully. + */ +out_of_memory: + printk("Out of memory\n"); + up_read(&mm->mmap_sem); + if (current->pid == 1) { + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + printk("VM: Killing process %s\n", tsk->comm); + if (user_mode(regs)) + do_exit(SIGKILL); + goto no_context; + +do_sigbus: + up_read(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel or + * user mode. + */ + /* address, error_code, trap_no, ... */ +#ifdef DEBUG + show_regs(regs); + dump_code(regs->pc); +#endif + pr_debug("Sending SIGBUS to PID %d...\n", tsk->pid); + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + goto no_context; +} + +asmlinkage void do_bus_error(unsigned long addr, int write_access, + struct pt_regs *regs) +{ + printk(KERN_ALERT + "Bus error at physical address 0x%08lx (%s access)\n", + addr, write_access ? "write" : "read"); + printk(KERN_INFO "DTLB dump:\n"); + dump_dtlb(); + die("Bus Error", regs, write_access); + do_exit(SIGKILL); +} + +/* + * This functionality is currently not possible to implement because + * we're using segmentation to ensure a fixed mapping of the kernel + * virtual address space. + * + * It would be possible to implement this, but it would require us to + * disable segmentation at startup and load the kernel mappings into + * the TLB like any other pages. There will be lots of trickery to + * avoid recursive invocation of the TLB miss handler, though... + */ +#ifdef CONFIG_DEBUG_PAGEALLOC +void kernel_map_pages(struct page *page, int numpages, int enable) +{ + +} +EXPORT_SYMBOL(kernel_map_pages); +#endif diff -Nur linux-2.6.16.11/arch/avr32/mm/init.c linux-2.6.16.11-avr32-20060626/arch/avr32/mm/init.c --- linux-2.6.16.11/arch/avr32/mm/init.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/init.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + +pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +struct page *empty_zero_page; + +/* + * Cache of MMU context last used. + */ +unsigned long mmu_context_cache = NO_CONTEXT; + +#if !defined(CONFIG_DISCONTIGMEM) +# define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT) +# define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn) +#endif + +void show_mem(void) +{ + int total = 0, reserved = 0, cached = 0; + int slab = 0, free = 0, shared = 0; + pg_data_t *pgdat; + + printk("Mem-info:\n"); + show_free_areas(); + + for_each_pgdat(pgdat) { + struct page *page, *end; + + page = pgdat->node_mem_map; + end = page + pgdat->node_spanned_pages; + + do { + total++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (PageSlab(page)) + slab++; + else if (!page_count(page)) + free++; + else + shared += page_count(page) - 1; + page++; + } while (page < end); + } + + printk ("%d pages of RAM\n", total); + printk ("%d free pages\n", free); + printk ("%d reserved pages\n", reserved); + printk ("%d slab pages\n", slab); + printk ("%d pages shared\n", shared); + printk ("%d pages swap cached\n", cached); +} + +static void __init print_memory_map(const char *what, + struct tag_mem_range *mem) +{ + printk ("%s:\n", what); + for (; mem; mem = mem->next) { + printk (" %08lx - %08lx\n", + (unsigned long)mem->addr, + (unsigned long)(mem->addr + mem->size)); + } +} + +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + +#define MAX_LOWMEM HIGHMEM_START +#define MAX_LOWMEM_PFN PFN_DOWN(MAX_LOWMEM) + +/* + * Sort a list of memory regions in-place by ascending address. + * + * We're using bubble sort because we only have singly linked lists + * with few elements. + */ +static void __init sort_mem_list(struct tag_mem_range **pmem) +{ + int done; + struct tag_mem_range **a, **b; + + if (!*pmem) + return; + + do { + done = 1; + a = pmem, b = &(*pmem)->next; + while (*b) { + if ((*a)->addr > (*b)->addr) { + struct tag_mem_range *tmp; + tmp = (*b)->next; + (*b)->next = *a; + *a = *b; + *b = tmp; + done = 0; + } + a = &(*a)->next; + b = &(*a)->next; + } + } while (!done); +} + +/* + * Find a free memory region large enough for storing the + * bootmem bitmap. + */ +static unsigned long __init +find_bootmap_pfn(const struct tag_mem_range *mem) +{ + unsigned long bootmap_pages, bootmap_len; + unsigned long node_pages = PFN_UP(mem->size); + unsigned long bootmap_addr = mem->addr; + struct tag_mem_range *reserved = mem_reserved; + struct tag_mem_range *ramdisk = mem_ramdisk; + unsigned long kern_start = virt_to_phys(_stext); + unsigned long kern_end = virt_to_phys(_end); + + bootmap_pages = bootmem_bootmap_pages(node_pages); + bootmap_len = bootmap_pages << PAGE_SHIFT; + + /* + * Find a large enough region without reserved pages for + * storing the bootmem bitmap. We can take advantage of the + * fact that all lists have been sorted. + * + * We have to check explicitly reserved regions as well as the + * kernel image and any RAMDISK images... + * + * Oh, and we have to make sure we don't overwrite the taglist + * since we're going to use it until the bootmem allocator is + * fully up and running. + */ + while (1) { + if ((bootmap_addr < kern_end) && + ((bootmap_addr + bootmap_len) > kern_start)) + bootmap_addr = kern_end; + + while (reserved && + (bootmap_addr >= (reserved->addr + reserved->size))) + reserved = reserved->next; + + if (reserved && + ((bootmap_addr + bootmap_len) >= reserved->addr)) { + bootmap_addr = reserved->addr + reserved->size; + continue; + } + + while (ramdisk && + (bootmap_addr >= (ramdisk->addr + ramdisk->size))) + ramdisk = ramdisk->next; + + if (!ramdisk || + ((bootmap_addr + bootmap_len) < ramdisk->addr)) + break; + + bootmap_addr = ramdisk->addr + ramdisk->size; + } + + if ((PFN_UP(bootmap_addr) + bootmap_len) >= (mem->addr + mem->size)) + return ~0UL; + + return PFN_UP(bootmap_addr); +} + +void __init setup_bootmem(void) +{ + unsigned bootmap_size; + unsigned long first_pfn, bootmap_pfn, pages; + unsigned long max_pfn, max_low_pfn; + unsigned long kern_start = virt_to_phys(_stext); + unsigned long kern_end = virt_to_phys(_end); + unsigned node = 0; + struct tag_mem_range *bank, *res; + + sort_mem_list(&mem_phys); + sort_mem_list(&mem_reserved); + + print_memory_map("Physical memory", mem_phys); + print_memory_map("Reserved memory", mem_reserved); + + nodes_clear(node_online_map); + + if (mem_ramdisk) { +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = __va(mem_ramdisk->addr); + initrd_end = initrd_start + mem_ramdisk->size; + + print_memory_map("RAMDISK images", mem_ramdisk); + if (mem_ramdisk->next) + printk(KERN_WARNING + "Warning: Only the first RAMDISK image " + "will be used\n"); + sort_mem_list(&mem_ramdisk); +#else + printk(KERN_WARNING "RAM disk image present, but " + "no initrd support in kernel!\n"); +#endif + } + +#ifndef CONFIG_DISCONTIGMEM + if (mem_phys->next) + printk(KERN_WARNING "Only using first memory bank " + "since CONFIG_DISCONTIGMEM is off\n"); + for (bank = mem_phys; bank; bank = NULL) { +#else + for (bank = mem_phys; bank; bank = bank->next, node++) { +#endif + first_pfn = PFN_UP(bank->addr); + max_low_pfn = max_pfn = PFN_DOWN(bank->addr + bank->size); + bootmap_pfn = find_bootmap_pfn(bank); + if (bootmap_pfn > max_pfn) { +#ifndef CONFIG_DISCONTIGMEM + panic("No space for bootmem bitmap!\n"); +#else + printk(KERN_WARNING + "Node %u: No space for bootmem bitmap\n", + node); + continue; +#endif + } + + if (max_low_pfn > MAX_LOWMEM_PFN) { + max_low_pfn = MAX_LOWMEM_PFN; +#ifndef CONFIG_HIGHMEM + /* + * Lowmem is memory that can be addressed + * directly through P1/P2 + */ + printk(KERN_WARNING + "Node %u: Only %ldMB of memory will be used.\n", + node, MAX_LOWMEM >> 20); + printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); +#else +#error HIGHMEM is not supported by AVR32 yet +#endif + } + + /* Initialize the boot-time allocator with low memory only. */ + bootmap_size = init_bootmem_node(NODE_DATA(node), bootmap_pfn, + first_pfn, max_low_pfn); + + printk("Node %u: bdata = %p, bdata->node_bootmem_map = %p\n", + node, NODE_DATA(node)->bdata, + NODE_DATA(node)->bdata->node_bootmem_map); + + /* + * Register fully available RAM pages with the bootmem + * allocator. + */ + pages = max_low_pfn - first_pfn; + free_bootmem_node (NODE_DATA(node), PFN_PHYS(first_pfn), + PFN_PHYS(pages)); + + /* + * Reserve space for the kernel image (if present in + * this node)... + */ + if ((kern_start >= PFN_PHYS(first_pfn)) && + (kern_start < PFN_PHYS(max_pfn))) { + printk("Node %u: Kernel image %08lx - %08lx\n", + node, kern_start, kern_end); + reserve_bootmem_node(NODE_DATA(node), kern_start, + kern_end - kern_start); + } + + /* ...the bootmem bitmap... */ + reserve_bootmem_node(NODE_DATA(node), + PFN_PHYS(bootmap_pfn), + bootmap_size); + + /* ...any RAMDISK images... */ + for (res = mem_ramdisk; res; res = res->next) { + if (res->addr > PFN_PHYS(max_pfn)) + break; + + if (res->addr >= PFN_PHYS(first_pfn)) { + printk("Node %u: RAMDISK %08lx - %08lx\n", + node, + (unsigned long)res->addr, + (unsigned long)(res->addr + res->size)); + reserve_bootmem_node(NODE_DATA(node), + res->addr, res->size); + } + } + + /* ...and any other reserved regions. */ + for (res = mem_reserved; res; res = res->next) { + if (res->addr > PFN_PHYS(max_pfn)) + break; + + if (res->addr >= PFN_PHYS(first_pfn)) { + printk("Node %u: Reserved %08lx - %08lx\n", + node, + (unsigned long)res->addr, + (unsigned long)(res->addr + res->size)); + reserve_bootmem_node(NODE_DATA(node), + res->addr, res->size); + } + } + + node_set_online(node); + } +} + +/* + * paging_init() sets up the page tables + * + * This routine also unmaps the page at virtual kernel address 0, so + * that we can trap those pesky NULL-reference errors in the kernel. + */ +void __init paging_init(void) +{ + extern unsigned long _evba; + void *zero_page; + int nid; + + /* + * Make sure we can handle exceptions before enabling + * paging. Not that we should ever _get_ any exceptions this + * early, but you never know... + */ + printk("Exception vectors start at %p\n", &_evba); + sysreg_write(EVBA, (unsigned long)&_evba); + + /* + * Since we are ready to handle exceptions now, we should let + * the CPU generate them... + */ + __asm__ __volatile__ ("csrf %0" : : "i"(SR_EM_BIT)); + + /* + * Allocate the zero page. The allocator will panic if it + * can't satisfy the request, so no need to check. + */ + zero_page = alloc_bootmem_low_pages_node(NODE_DATA(0), + PAGE_SIZE); + + { + pgd_t *pg_dir; + int i; + + pg_dir = swapper_pg_dir; + sysreg_write(PTBR, (unsigned long)pg_dir); + + for (i = 0; i < PTRS_PER_PGD; i++) + pgd_val(pg_dir[i]) = 0; + + enable_mmu(); + printk ("CPU: Paging enabled\n"); + } + + for_each_online_node(nid) { + pg_data_t *pgdat = NODE_DATA(nid); + unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0 }; + unsigned long low, start_pfn; + + start_pfn = pgdat->bdata->node_boot_start; + start_pfn >>= PAGE_SHIFT; + low = pgdat->bdata->node_low_pfn; + + /* All memory is DMA-able */ + zones_size[ZONE_DMA] = low - start_pfn; + zones_size[ZONE_NORMAL] = 0; + + printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n", + nid, start_pfn, low); + + free_area_init_node(nid, pgdat, zones_size, start_pfn, NULL); + + printk("Node %u: mem_map starts at %p\n", + pgdat->node_id, pgdat->node_mem_map); + } + +#ifndef CONFIG_DISCONTIGMEM + mem_map = NODE_DATA(0)->node_mem_map; +#endif + + memset(zero_page, 0, PAGE_SIZE); + empty_zero_page = virt_to_page(zero_page); + flush_dcache_page(empty_zero_page); +} + +void __init mem_init(void) +{ + int codesize, reservedpages, datasize, initsize; + int nid, i; + + reservedpages = 0; + high_memory = NULL; + + /* this will put all low memory onto the freelists */ + for_each_online_node(nid) { + pg_data_t *pgdat = NODE_DATA(nid); + unsigned long node_pages = 0; + void *node_high_memory; + + num_physpages += pgdat->node_present_pages; + + if (pgdat->node_spanned_pages != 0) + node_pages = free_all_bootmem_node(pgdat); + + totalram_pages += node_pages; + + for (i = 0; i < node_pages; i++) + if (PageReserved(pgdat->node_mem_map + i)) + reservedpages++; + + node_high_memory = (void *)((pgdat->node_start_pfn + + pgdat->node_spanned_pages) + << PAGE_SHIFT); + if (node_high_memory > high_memory) + high_memory = node_high_memory; + } + +#ifndef CONFIG_DISCONTIGMEM + max_mapnr = MAP_NR(high_memory); +#endif + + codesize = (unsigned long)_etext - (unsigned long)_text; + datasize = (unsigned long)_edata - (unsigned long)_data; + initsize = (unsigned long)__init_end - (unsigned long)__init_begin; + + printk ("Memory: %luk/%luk available (%dk kernel code, " + "%dk reserved, %dk data, %dk init)\n", + (unsigned long)nr_free_pages() << (PAGE_SHIFT - 10), + totalram_pages << (PAGE_SHIFT - 10), + codesize >> 10, + reservedpages << (PAGE_SHIFT - 10), + datasize >> 10, + initsize >> 10); +} + +static inline void free_area(unsigned long addr, unsigned long end, char *s) +{ + unsigned int size = (end - addr) >> 10; + + for (; addr < end; addr += PAGE_SIZE) { + struct page *page = virt_to_page(addr); + ClearPageReserved(page); + set_page_count(page, 1); + free_page(addr); + totalram_pages++; + } + + if (size && s) + printk(KERN_INFO "Freeing %s memory: %dK (%lx - %lx)\n", + s, size, end - (size << 10), end); +} + +void free_initmem(void) +{ + free_area((unsigned long)__init_begin, (unsigned long)__init_end, + "init"); +} + +#ifdef CONFIG_BLK_DEV_INITRD + +static int keep_initrd; + +void free_initrd_mem(unsigned long start, unsigned long end) +{ + if (!keep_initrd) + free_area(start, end, "initrd"); +} + +static int __init keepinitrd_setup(char *__unused) +{ + keep_initrd = 1; + return 1; +} + +__setup("keepinitrd", keepinitrd_setup); +#endif diff -Nur linux-2.6.16.11/arch/avr32/mm/ioremap.c linux-2.6.16.11-avr32-20060626/arch/avr32/mm/ioremap.c --- linux-2.6.16.11/arch/avr32/mm/ioremap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/ioremap.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +#include +#include +#include +#include +#include + +static inline int remap_area_pte(pte_t *pte, unsigned long address, + unsigned long end, unsigned long phys_addr, + pgprot_t prot) +{ + unsigned long pfn; + + pfn = phys_addr >> PAGE_SHIFT; + do { + WARN_ON(!pte_none(*pte)); + + set_pte(pte, pfn_pte(pfn, prot)); + address += PAGE_SIZE; + pfn++; + pte++; + } while (address && (address < end)); + + return 0; +} + +static inline int remap_area_pmd(pmd_t *pmd, unsigned long address, + unsigned long end, unsigned long phys_addr, + pgprot_t prot) +{ + unsigned long next; + + phys_addr -= address; + + do { + pte_t *pte = pte_alloc_kernel(pmd, address); + if (!pte) + return -ENOMEM; + + next = (address + PMD_SIZE) & PMD_MASK; + if (remap_area_pte(pte, address, next, + address + phys_addr, prot)) + return -ENOMEM; + + address = next; + pmd++; + } while (address && (address < end)); + return 0; +} + +static int remap_area_pud(pud_t *pud, unsigned long address, + unsigned long end, unsigned long phys_addr, + pgprot_t prot) +{ + unsigned long next; + + phys_addr -= address; + + do { + pmd_t *pmd = pmd_alloc(&init_mm, pud, address); + if (!pmd) + return -ENOMEM; + next = (address + PUD_SIZE) & PUD_MASK; + if (remap_area_pmd(pmd, address, next, + phys_addr + address, prot)) + return -ENOMEM; + + address = next; + pud++; + } while (address && address < end); + + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + size_t size, pgprot_t prot) +{ + unsigned long end = address + size; + unsigned long next; + pgd_t *pgd; + int err = 0; + + phys_addr -= address; + + pgd = pgd_offset_k(address); + flush_cache_all(); + BUG_ON(address >= end); + + spin_lock(&init_mm.page_table_lock); + do { + pud_t *pud = pud_alloc(&init_mm, pgd, address); + + err = -ENOMEM; + if (!pud) + break; + + next = (address + PGDIR_SIZE) & PGDIR_MASK; + if (next < address || next > end) + next = end; + err = remap_area_pud(pud, address, next, + phys_addr + address, prot); + if (err) + break; + + address = next; + pgd++; + } while (address && (address < end)); + + spin_unlock(&init_mm.page_table_lock); + flush_tlb_all(); + return err; +} + +/* + * Re-map an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access physical + * memory directly. + */ +void __iomem *__ioremap(unsigned long phys_addr, size_t size, + unsigned long flags) +{ + void *addr; + struct vm_struct *area; + unsigned long offset, last_addr; + pgprot_t prot; + + /* + * Check if we can simply use the P4 segment. This area is + * uncacheable, so if caching/buffering is requested, we can't + * use it. + */ + if ((phys_addr >= P4SEG) && (flags == 0)) + return (void __iomem *)phys_addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * XXX: When mapping regular RAM, we'd better make damn sure + * it's never used for anything else. But this is really the + * caller's responsibility... + */ + if (PHYSADDR(P2SEGADDR(phys_addr)) == phys_addr) + return (void __iomem *)P2SEGADDR(phys_addr); + + /* Mappings have to be page-aligned */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr + 1) - phys_addr; + + prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY + | _PAGE_ACCESSED | _PAGE_TYPE_SMALL | flags); + + /* + * Ok, go for it.. + */ + area = get_vm_area(size, VM_IOREMAP); + if (!area) + return NULL; + area->phys_addr = phys_addr; + addr = area->addr; + if (remap_area_pages((unsigned long)addr, phys_addr, size, prot)) { + vunmap(addr); + return NULL; + } + + return (void __iomem *)(offset + (char *)addr); +} +EXPORT_SYMBOL(__ioremap); + +void __iounmap(void __iomem *addr) +{ + struct vm_struct *p; + + if ((unsigned long)addr >= P4SEG) + return; + + p = remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr)); + if (unlikely(!p)) { + printk (KERN_ERR "iounmap: bad address %p\n", addr); + return; + } + + kfree (p); +} +EXPORT_SYMBOL(__iounmap); diff -Nur linux-2.6.16.11/arch/avr32/mm/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/mm/Makefile --- linux-2.6.16.11/arch/avr32/mm/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/Makefile 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,7 @@ +# +# Makefile for the Linux/AVR32 kernel. +# + +obj-y += init.o clear_page.o copy_page.o dma-coherent.o +obj-y += ioremap.o cache.o fault.o tlb.o +obj-$(CONFIG_DISCONTIGMEM) += discontig.o diff -Nur linux-2.6.16.11/arch/avr32/mm/tlb.c linux-2.6.16.11-avr32-20060626/arch/avr32/mm/tlb.c --- linux-2.6.16.11/arch/avr32/mm/tlb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/mm/tlb.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,378 @@ +/* + * AVR32 TLB operations + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + +#include + +#define _TLBEHI_I 0x100 + +void show_dtlb_entry(unsigned int index) +{ + unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save, flags; + + local_irq_save(flags); + mmucr_save = sysreg_read(MMUCR); + tlbehi_save = sysreg_read(TLBEHI); + mmucr = mmucr_save & 0x13; + mmucr |= index << 14; + sysreg_write(MMUCR, mmucr); + + asm volatile("tlbr" : : : "memory"); + cpu_sync_pipeline(); + + tlbehi = sysreg_read(TLBEHI); + tlbelo = sysreg_read(TLBELO); + + printk("%2u: %c %c %02x %05x %05x %o %o %c %c %c %c\n", + index, + (tlbehi & 0x200)?'1':'0', + (tlbelo & 0x100)?'1':'0', + (tlbehi & 0xff), + (tlbehi >> 12), (tlbelo >> 12), + (tlbelo >> 4) & 7, (tlbelo >> 2) & 3, + (tlbelo & 0x200)?'1':'0', + (tlbelo & 0x080)?'1':'0', + (tlbelo & 0x001)?'1':'0', + (tlbelo & 0x002)?'1':'0'); + + sysreg_write(MMUCR, mmucr_save); + sysreg_write(TLBEHI, tlbehi_save); + cpu_sync_pipeline(); + local_irq_restore(flags); +} + +void dump_dtlb(void) +{ + unsigned int i; + + printk("ID V G ASID VPN PFN AP SZ C B W D\n"); + for (i = 0; i < 32; i++) + show_dtlb_entry(i); +} + +static unsigned long last_mmucr; + +static inline void set_replacement_pointer(unsigned shift) +{ + unsigned long mmucr, mmucr_save; + + mmucr = mmucr_save = sysreg_read(MMUCR); + + /* Does this mapping already exist? */ + __asm__ __volatile__( + " tlbs\n" + " mfsr %0, %1" + : "=r"(mmucr) + : "i"(SYSREG_MMUCR)); + + if (mmucr & SYSREG_BIT(MMUCR_N)) { + /* Not found -- pick a not-recently-accessed entry */ + unsigned long rp; + unsigned long tlbar = sysreg_read(TLBARLO); + + rp = 32 - fls(tlbar); + if (rp == 32) { + rp = 0; + sysreg_write(TLBARLO, -1L); + } + + mmucr &= 0x13; + mmucr |= (rp << shift); + + sysreg_write(MMUCR, mmucr); + } + + last_mmucr = mmucr; +} + +static void update_dtlb(unsigned long address, pte_t pte, unsigned long asid) +{ + unsigned long vpn; + + vpn = (address & MMU_VPN_MASK) | _TLBEHI_VALID | asid; + sysreg_write(TLBEHI, vpn); + cpu_sync_pipeline(); + + set_replacement_pointer(14); + + sysreg_write(TLBELO, pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK); + + /* Let's go */ + asm volatile("nop\n\ttlbw" : : : "memory"); + cpu_sync_pipeline(); +} + +void update_mmu_cache(struct vm_area_struct *vma, + unsigned long address, pte_t pte) +{ + unsigned long flags; + + /* ptrace may call this routine */ + if (vma && current->active_mm != vma->vm_mm) + return; + + local_irq_save(flags); + update_dtlb(address, pte, get_asid()); + local_irq_restore(flags); +} + +void __flush_tlb_page(unsigned long asid, unsigned long page) +{ + unsigned long mmucr, tlbehi; + + page |= asid; + sysreg_write(TLBEHI, page); + cpu_sync_pipeline(); + asm volatile("tlbs"); + mmucr = sysreg_read(MMUCR); + + if (!(mmucr & SYSREG_BIT(MMUCR_N))) { + unsigned long tlbarlo; + unsigned long entry; + + /* Clear the "valid" bit */ + tlbehi = sysreg_read(TLBEHI); + tlbehi &= ~_TLBEHI_VALID; + sysreg_write(TLBEHI, tlbehi); + cpu_sync_pipeline(); + + /* mark the entry as "not accessed" */ + entry = (mmucr >> 14) & 0x3f; + tlbarlo = sysreg_read(TLBARLO); + tlbarlo |= (0x80000000 >> entry); + sysreg_write(TLBARLO, tlbarlo); + + /* update the entry with valid bit clear */ + asm volatile("tlbw"); + cpu_sync_pipeline(); + } +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) { + unsigned long flags, asid; + unsigned long saved_asid = MMU_NO_ASID; + + asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK; + page &= PAGE_MASK; + + local_irq_save(flags); + if (vma->vm_mm != current->mm) { + saved_asid = get_asid(); + set_asid(asid); + } + + __flush_tlb_page(asid, page); + + if (saved_asid != MMU_NO_ASID) + set_asid(saved_asid); + local_irq_restore(flags); + } +} + +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + + if (mm->context != NO_CONTEXT) { + unsigned long flags; + int size; + + local_irq_save(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */ + mm->context = NO_CONTEXT; + if (mm == current->mm) + activate_context(mm); + } else { + unsigned long asid = mm->context & MMU_CONTEXT_ASID_MASK; + unsigned long saved_asid = MMU_NO_ASID; + + start &= PAGE_MASK; + end += (PAGE_SIZE - 1); + end &= PAGE_MASK; + if (mm != current->mm) { + saved_asid = get_asid(); + set_asid(asid); + } + + while (start < end) { + __flush_tlb_page(asid, start); + start += PAGE_SIZE; + } + if (saved_asid != MMU_NO_ASID) + set_asid(saved_asid); + } + local_irq_restore(flags); + } +} + +/* + * TODO: If this is only called for addresses > TASK_SIZE, we can probably + * skip the ASID stuff and just use the Global bit... + */ +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + unsigned long flags; + int size; + + local_irq_save(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */ + flush_tlb_all(); + } else { + unsigned long asid = init_mm.context & MMU_CONTEXT_ASID_MASK; + unsigned long saved_asid = get_asid(); + + start &= PAGE_MASK; + end += (PAGE_SIZE - 1); + end &= PAGE_MASK; + set_asid(asid); + while (start < end) { + __flush_tlb_page(asid, start); + start += PAGE_SIZE; + } + set_asid(saved_asid); + } + local_irq_restore(flags); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + /* Invalidate all TLB entries of this process by getting a new ASID */ + if (mm->context != NO_CONTEXT) { + unsigned long flags; + + local_irq_save(flags); + mm->context = NO_CONTEXT; + if (mm == current->mm) + activate_context(mm); + local_irq_restore(flags); + } +} + +void flush_tlb_all(void) +{ + unsigned long flags; + + local_irq_save(flags); + sysreg_write(MMUCR, sysreg_read(MMUCR) | SYSREG_BIT(MMUCR_I)); + local_irq_restore(flags); +} + +#ifdef CONFIG_PROC_FS + +#include +#include +#include + +static void *tlb_start(struct seq_file *tlb, loff_t *pos) +{ + static unsigned long tlb_index; + + if (*pos >= 32) + return NULL; + + tlb_index = 0; + return &tlb_index; +} + +static void *tlb_next(struct seq_file *tlb, void *v, loff_t *pos) +{ + unsigned long *index = v; + + if (*index >= 31) + return NULL; + + ++*pos; + ++*index; + return index; +} + +static void tlb_stop(struct seq_file *tlb, void *v) +{ + +} + +static int tlb_show(struct seq_file *tlb, void *v) +{ + unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save, flags; + unsigned long *index = v; + + if (*index == 0) + seq_puts(tlb, "ID V G ASID VPN PFN AP SZ C B W D\n"); + + BUG_ON(*index >= 32); + + local_irq_save(flags); + mmucr_save = sysreg_read(MMUCR); + tlbehi_save = sysreg_read(TLBEHI); + mmucr = mmucr_save & 0x13; + mmucr |= *index << 14; + sysreg_write(MMUCR, mmucr); + + asm volatile("tlbr" : : : "memory"); + cpu_sync_pipeline(); + + tlbehi = sysreg_read(TLBEHI); + tlbelo = sysreg_read(TLBELO); + + sysreg_write(MMUCR, mmucr_save); + sysreg_write(TLBEHI, tlbehi_save); + cpu_sync_pipeline(); + local_irq_restore(flags); + + seq_printf(tlb, "%2lu: %c %c %02x %05x %05x %o %o %c %c %c %c\n", + *index, + (tlbehi & 0x200)?'1':'0', + (tlbelo & 0x100)?'1':'0', + (tlbehi & 0xff), + (tlbehi >> 12), (tlbelo >> 12), + (tlbelo >> 4) & 7, (tlbelo >> 2) & 3, + (tlbelo & 0x200)?'1':'0', + (tlbelo & 0x080)?'1':'0', + (tlbelo & 0x001)?'1':'0', + (tlbelo & 0x002)?'1':'0'); + + return 0; +} + +static struct seq_operations tlb_ops = { + .start = tlb_start, + .next = tlb_next, + .stop = tlb_stop, + .show = tlb_show, +}; + +static int tlb_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &tlb_ops); +} + +static struct file_operations proc_tlb_operations = { + .open = tlb_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init proctlb_init(void) +{ + struct proc_dir_entry *entry; + + entry = create_proc_entry("tlb", 0, NULL); + if (entry) + entry->proc_fops = &proc_tlb_operations; + return 0; +} +late_initcall(proctlb_init); +#endif /* CONFIG_PROC_FS */ diff -Nur linux-2.6.16.11/arch/avr32/oprofile/common.c linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/common.c --- linux-2.6.16.11/arch/avr32/oprofile/common.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/common.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Author: Ronny Pedersen + */ + +#define DEBUG +#include +#include +#include +#include +#include + +#include "op_avr32_model.h" +#include "op_counter.h" + +static struct op_avr32_model_spec *pc_model; +static int pc_enabled = 0; +static struct semaphore pc_sem; + + +static int pc_start(void); +static int pc_setup(void); +static void pc_stop(void); +static int pc_create_files(struct super_block *, struct dentry *); + + +struct op_counter_config counter_config[OP_MAX_COUNTER]; + +static int pc_suspend(struct sys_device *dev, u32 state) +{ + if (pc_enabled) + pc_stop(); + return 0; +} + +static int pc_resume(struct sys_device *dev) +{ + if (pc_enabled) + pc_start(); + return 0; +} + +static struct sysdev_class oprofile_sysclass = { + set_kset_name("oprofile"), + .resume = pc_resume, + .suspend = pc_suspend, +}; + +static struct sys_device device_oprofile = { + .id = 0, + .cls = &oprofile_sysclass, +}; + +static int __init init_driverfs(void) +{ + int ret; + + if (!(ret = sysdev_class_register(&oprofile_sysclass))) + ret = sysdev_register(&device_oprofile); + + return ret; +} + +static void exit_driverfs(void) +{ + sysdev_unregister(&device_oprofile); + sysdev_class_unregister(&oprofile_sysclass); +} + +static int pc_create_files(struct super_block *sb, struct dentry *root) +{ + unsigned int i; + + pr_debug("AVR32 Peformance Counters: create files\n"); + for (i = 0; i < pc_model->num_counters; i++) { + struct dentry *dir; + char buf[2]; + + snprintf(buf, sizeof buf, "%d", i); + dir = oprofilefs_mkdir(sb, root, buf); + oprofilefs_create_ulong(sb, dir, "enabled", + &counter_config[i].enabled); + oprofilefs_create_ulong(sb, dir, "event", + &counter_config[i].event); + oprofilefs_create_ulong(sb, dir, "count", + &counter_config[i].count); + oprofilefs_create_ulong(sb, dir, "unit_mask", + &counter_config[i].unit_mask); + oprofilefs_create_ulong(sb, dir, "kernel", + &counter_config[i].kernel); + oprofilefs_create_ulong(sb, dir, "user", + &counter_config[i].user); + } + + return 0; +} + +static int pc_setup(void) +{ + int ret; + + spin_lock(&oprofilefs_lock); + pr_debug("AVR32 Peformance Counters: setup\n"); + ret = pc_model->setup_ctrs(); + spin_unlock(&oprofilefs_lock); + return ret; +} + +static int pc_start(void) +{ + int ret = -EBUSY; + + down(&pc_sem); + if (!pc_enabled) { + pr_debug("AVR32 Peformance Counters: start\n"); + ret = pc_model->start(); + pc_enabled = !ret; + } + up(&pc_sem); + return ret; +} + +static void pc_stop(void) +{ + down(&pc_sem); + pr_debug("AVR32 Peformance Counters: stop\n"); + if (pc_enabled) + pc_model->stop(); + pc_enabled = 0; + up(&pc_sem); +} + +int __init pc_init(struct oprofile_operations *ops, + struct op_avr32_model_spec *spec) +{ + init_MUTEX(&pc_sem); + + if ( spec->init ) + if (spec->init() < 0) + return -ENODEV; + + pc_model = spec; + init_driverfs(); + ops->create_files = pc_create_files; + ops->setup = pc_setup; + ops->shutdown = pc_stop; + ops->start = pc_start; + ops->stop = pc_stop; + ops->cpu_type = pc_model->name; + printk(KERN_INFO "oprofile: using %s Performance Counters\n", + spec->name); + pr_debug("AVR32 Peformance Counters: pc_init\n"); + + return 0; +} + +void pc_exit(void) +{ + if (pc_model) { + pr_debug("AVR32 Peformance Counters: exit\n"); + exit_driverfs(); + pc_model = NULL; + } +} diff -Nur linux-2.6.16.11/arch/avr32/oprofile/init.c linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/init.c --- linux-2.6.16.11/arch/avr32/oprofile/init.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/init.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Author: Ronny Pedersen + */ + +#include +#include +#include +#include "op_avr32_model.h" +#include "op_model_avr32.h" + +int __init oprofile_arch_init(struct oprofile_operations *ops) +{ + int ret = -ENODEV; + + ret = pc_init(ops, &op_avr32_spec); + + return ret; +} + +void oprofile_arch_exit(void) +{ + pc_exit(); +} diff -Nur linux-2.6.16.11/arch/avr32/oprofile/Kconfig linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/Kconfig --- linux-2.6.16.11/arch/avr32/oprofile/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/Kconfig 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,23 @@ + +menu "Profiling support" + depends on EXPERIMENTAL + +config PROFILING + bool "Profiling support (EXPERIMENTAL)" + help + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + + +config OPROFILE + tristate "OProfile system profiling (EXPERIMENTAL)" + depends on PROFILING + help + OProfile is a profiling system capable of profiling the + whole system, including the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. + +endmenu + diff -Nur linux-2.6.16.11/arch/avr32/oprofile/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/Makefile --- linux-2.6.16.11/arch/avr32/oprofile/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/Makefile 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,10 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) init.o common.o +oprofile-y += op_model_avr32.o diff -Nur linux-2.6.16.11/arch/avr32/oprofile/op_avr32_model.h linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/op_avr32_model.h --- linux-2.6.16.11/arch/avr32/oprofile/op_avr32_model.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/op_avr32_model.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,25 @@ +/* + * interface to AVR32 machine specific operations + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Author: Ronny Pedersen + */ + +#ifndef OP_AVR32_MODEL_H +#define OP_AVR32_MODEL_H + +struct op_avr32_model_spec { + int (*init)(void); + unsigned int num_counters; + int (*setup_ctrs)(void); + int (*start)(void); + void (*stop)(void); + char *name; +}; + +#endif /* OP_AVR32_MODEL_H */ diff -Nur linux-2.6.16.11/arch/avr32/oprofile/op_counter.h linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/op_counter.h --- linux-2.6.16.11/arch/avr32/oprofile/op_counter.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/op_counter.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Author: Ronny Pedersen + */ +#ifndef OP_COUNTER_H +#define OP_COUNTER_H + +#define OP_MAX_COUNTER 3 + +/* Per performance monitor configuration as set via + * oprofilefs. + */ +struct op_counter_config { + unsigned long count; + unsigned long enabled; + unsigned long event; + unsigned long unit_mask; + unsigned long kernel; + unsigned long user; +}; + +extern struct op_counter_config counter_config[]; + +#endif /* OP_COUNTER_H */ diff -Nur linux-2.6.16.11/arch/avr32/oprofile/op_model_avr32.c linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/op_model_avr32.c --- linux-2.6.16.11/arch/avr32/oprofile/op_model_avr32.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/op_model_avr32.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,219 @@ +/* + * AVR32 Performance Counter Driver + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Author: Ronny Pedersen + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "op_counter.h" +#include "op_avr32_model.h" + + +#define PC_ENABLE 0x001 /* Enable counters */ +#define PCNT_RESET 0x002 /* Reset event counters */ +#define CCNT_RESET 0x004 /* Reset clock counter */ +#define PC_RESET (CCNT_RESET | PCNT_RESET) +#define PC_CNT64 0x008 /* Make CCNT count every 64th cycle */ + + +#define EVT_UNUSED 0xFF + +struct pc_counter { + volatile unsigned long ovf; + unsigned long reset_counter; +}; + +enum { PCCNT, PCNT0, PCNT1, MAX_COUNTERS }; + +#define PCCNT_IE (1 << 4) +#define PCNT0_IE (1 << 5) +#define PCNT1_IE (1 << 6) + +#define PCCNT_F (1 << 8) +#define PCNT0_F (1 << 9) +#define PCNT1_F (1 << 10) + +#define AVR32_PC_IRQ 1 + +static const u32 int_mask[MAX_COUNTERS] = { PCCNT_IE, PCNT0_IE, PCNT1_IE }; +static const u32 ovf_mask[MAX_COUNTERS] = { PCCNT_F, PCNT0_F, PCNT1_F }; + +static struct pc_counter results[MAX_COUNTERS]; + +static void write_pccr(u32 val) +{ + __builtin_mtsr(SYSREG_PCCR, val); +} + +static u32 read_pccr(void) +{ + return __builtin_mfsr(SYSREG_PCCR); +} + +static u32 read_counter(int counter) +{ + switch (counter) { + case PCCNT: + return __builtin_mfsr(SYSREG_PCCNT); + case PCNT0: + return __builtin_mfsr(SYSREG_PCNT0); + case PCNT1: + return __builtin_mfsr(SYSREG_PCNT0); + default: + return 0; + } +} + + +static void write_counter(int counter, u32 val) +{ + switch (counter) { + case PCCNT: + __builtin_mtsr(SYSREG_PCCNT, val); + case PCNT0: + __builtin_mtsr(SYSREG_PCNT0, val); + case PCNT1: + __builtin_mtsr(SYSREG_PCNT0, val); + default: + break; + } +} + +static int avr32_setup_ctrs(void) +{ + u32 pccr; + int i; + + for (i = PCCNT; i < MAX_COUNTERS; i++) { + if (counter_config[i].enabled) + continue; + + counter_config[i].event = EVT_UNUSED; + } + + pccr = ((counter_config[PCNT1].event << 18) + | (counter_config[PCNT0].event << 12)); + pr_debug("avr32_setup_ctrs: pccr: %#08x\n", pccr); + write_pccr(pccr); + + for (i = PCCNT; i < MAX_COUNTERS; i++) { + if (counter_config[i].event == EVT_UNUSED) { + counter_config[i].event = 0; + continue; + } + + results[i].reset_counter = counter_config[i].count; + write_counter(i, -(u32)counter_config[i].count); + pr_debug("avr32_setup_ctrs: counter%d %#08x from %#08lx\n", + i, read_counter(i), counter_config[i].count); + } + + return 0; +} + +static void inline check_ctrs(void) +{ + int i; + u32 pccr = read_pccr(); + + /* Writeback clears overflow flag */ + write_pccr(pccr & ~PC_ENABLE); + + for (i = PCCNT; i < MAX_COUNTERS; i++) { + if (!(int_mask[i] & pccr)) + continue; + + if (pccr & ovf_mask[i]) + results[i].ovf++; + } +} + + +static irqreturn_t avr32_pc_interrupt(int irq, void *arg, + struct pt_regs *regs) +{ + int i; + + check_ctrs(); + + for (i = PCCNT; i < MAX_COUNTERS; i++) { + if (!results[i].ovf) + continue; + + write_counter(i, -(u32)results[i].reset_counter); + oprofile_add_sample(regs, i); + results[i].ovf--; + } + + /* Enable Performance Counter */ + write_pccr(read_pccr() | PC_ENABLE); + + return IRQ_HANDLED; +} + +static void avr32_pc_stop(void) +{ + write_pccr(read_pccr() & ~PC_ENABLE); + + free_irq(AVR32_PC_IRQ, results); +} + +static int avr32_pc_start(void) +{ + int i, ret; + u32 pccr = read_pccr(); + + ret = request_irq(AVR32_PC_IRQ, avr32_pc_interrupt, SA_INTERRUPT, + "AVR32 Performance Counter", (void *)results); + + if (ret < 0) { + printk(KERN_ERR + "oprofile: unable to request IRQ%d for AVR32" + " Performance Counter\n", + AVR32_PC_IRQ); + return ret; + } + + /* Enable interrupts */ + for (i = PCCNT; i < MAX_COUNTERS; i++) { + if (counter_config[i].enabled) + pccr |= int_mask[i]; + } + + /* Disable scaler */ + pccr &= ~PC_CNT64; + + /* Enable Performance Counter */ + pccr |= PC_ENABLE; + + write_pccr(pccr); + pr_debug("avr32_pc_start: pc: %#08x\n", pccr); + return 0; +} + + +struct op_avr32_model_spec op_avr32_spec = { + .init = 0, + .setup_ctrs = avr32_setup_ctrs, + .start = avr32_pc_start, + .stop = avr32_pc_stop, + .num_counters = MAX_COUNTERS, + .name = "avr32", +}; + diff -Nur linux-2.6.16.11/arch/avr32/oprofile/op_model_avr32.h linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/op_model_avr32.h --- linux-2.6.16.11/arch/avr32/oprofile/op_model_avr32.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/oprofile/op_model_avr32.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,21 @@ +/** + * AVR32 Machine Specific Operations + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Author: Ronny Pedersen + */ +#ifndef OP_MODEL_AVR32_H +#define OP_MODEL_AVR32_H + +extern struct op_avr32_model_spec op_avr32_spec; +extern int pc_init(struct oprofile_operations *ops, + struct op_avr32_model_spec *spec); +extern void pc_exit(void); + + +#endif diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/at32ap7000.c linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/at32ap7000.c --- linux-2.6.16.11/arch/avr32/platforms/at32ap/at32ap7000.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/at32ap7000.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + +#include +#include +#include +#include + +#define HMATRIX2_HEBI_SFR HMATRIX2_SFR4 +#define HEBI_SFR_SDRAM_ENABLE (1 << 1) + +#ifdef CONFIG_SDRAM +void __init chip_enable_sdram(void) +{ + struct platform_device *hmatrix_dev; + struct { + void __iomem *regs; + } hmatrix; + u32 sfr; + + hmatrix_dev = platform_get_device("hmatrix", 0); + if (!hmatrix_dev) { + printk(KERN_ERR "HMATRIX platform device not available.\n"); + return; + } + + hmatrix.regs = ioremap(platform_resource_start(hmatrix_dev, 0), + platform_resource_len(hmatrix_dev, 0)); + + sfr = hmatrix2_readl(&hmatrix, HEBI_SFR); + sfr |= HEBI_SFR_SDRAM_ENABLE; + hmatrix2_writel(&hmatrix, HEBI_SFR, sfr); + + iounmap(hmatrix.regs); +} +#endif diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/at32ap.c linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/at32ap.c --- linux-2.6.16.11/arch/avr32/platforms/at32ap/at32ap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/at32ap.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +#include +#include + +void __init setup_platform(void) +{ + at32_sm_init(); + at32_portmux_init(); +} + +static int __init pdc_probe(struct at32_device *adev) +{ + int ret; + + ret = at32_enable_device(adev); + if (ret) { + dev_err(&adev->dev, "failed to enable device: %d\n", ret); + return ret; + } + + dev_info(&adev->dev, "Atmel Peripheral DMA Controller enabled\n"); + return 0; +} + +static struct at32_driver pdc_driver = { + .probe = pdc_probe, + .driver = { + .name = "pdc", + }, +}; + +static int __init pdc_init(void) +{ + return at32_driver_register(&pdc_driver); +} +arch_initcall(pdc_init); diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/at32_bus.c linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/at32_bus.c --- linux-2.6.16.11/arch/avr32/platforms/at32ap/at32_bus.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/at32_bus.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,181 @@ +/* + * AT32 bus type. This driver handles the on-chip AHB and APB busses. + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include + +#include +#include + +#define to_at32_driver(x) container_of((x), struct at32_driver, driver) + +struct bus_type at32_bus_type; + +const struct resource *at32_find_resource(struct at32_device *adev, + unsigned int id, + unsigned long flags) +{ + unsigned int i; + + for (i = 0; i < adev->num_resources; i++) { + if (adev->resource[i].flags & flags) { + if (id == 0) + return &adev->resource[i]; + id--; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(at32_find_resource); + +unsigned long at32_get_iomem_base(struct at32_device *adev, unsigned int id) +{ + const struct resource *res; + + res = at32_find_resource(adev, id, IORESOURCE_MEM); + if (!res) + return ~0UL; + + return res->start; +} +EXPORT_SYMBOL_GPL(at32_get_iomem_base); + +void __iomem *at32_map_iomem(struct at32_device *adev, unsigned int id) +{ + const struct resource *res; + + res = at32_find_resource(adev, id, IORESOURCE_MEM); + if (!res) + return NULL; + + return ioremap(res->start, res->end - res->start + 1); +} +EXPORT_SYMBOL_GPL(at32_map_iomem); + +int at32_enable_device(struct at32_device *adev) +{ + unsigned int i; + int ret; + + for (i = 0; i < adev->sclk_count; i++) + sm_unmask_sclk(&adev->sclk[i]); + + ret = portmux_enable_device(adev); + if (ret) + for (i = 0; i < adev->sclk_count; i++) + sm_mask_sclk(&adev->sclk[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(at32_enable_device); + +void at32_disable_device(struct at32_device *adev) +{ + unsigned int i; + + for (i = 0; i < adev->sclk_count; i++) + sm_mask_sclk(&adev->sclk[i]); + + portmux_disable_device(adev); +} +EXPORT_SYMBOL_GPL(at32_disable_device); + +int at32_driver_register(struct at32_driver *adrv) +{ + adrv->driver.bus = &at32_bus_type; + return driver_register(&adrv->driver); +} +EXPORT_SYMBOL_GPL(at32_driver_register); + +void at32_driver_unregister(struct at32_driver *adrv) +{ + driver_unregister(&adrv->driver); +} +EXPORT_SYMBOL_GPL(at32_driver_unregister); + +static int at32_bus_match(struct device *dev, struct device_driver *drv) +{ + struct at32_device *adev = to_at32_device(dev); + + return strcmp(adev->name, drv->name) == 0; +} + +static int at32_device_probe(struct device *dev) +{ + struct at32_device *adev = to_at32_device(dev); + struct at32_driver *adrv = to_at32_driver(dev->driver); + int ret = -ENODEV; + + if (adrv->probe) + ret = adrv->probe(adev); + return ret; +} + +static int at32_device_remove(struct device *dev) +{ + struct at32_device *adev = to_at32_device(dev); + struct at32_driver *adrv = to_at32_driver(dev->driver); + int ret = 0; + + if (dev->driver && adrv->remove) + ret = adrv->remove(adev); + return ret; +} + +static void at32_device_shutdown(struct device *dev) +{ + struct at32_device *adev = to_at32_device(dev); + struct at32_driver *adrv = to_at32_driver(dev->driver); + + if (dev->driver && adrv->shutdown) + adrv->shutdown(adev); +} + +static int at32_device_suspend(struct device *dev, pm_message_t state) +{ + struct at32_device *adev = to_at32_device(dev); + struct at32_driver *adrv = to_at32_driver(dev->driver); + int ret = 0; + + if (dev->driver && adrv->suspend) + ret = adrv->suspend(adev, state); + return ret; +} + +static int at32_device_resume(struct device *dev) +{ + struct at32_device *adev = to_at32_device(dev); + struct at32_driver *adrv = to_at32_driver(dev->driver); + int ret = 0; + + if (dev->driver && adrv->resume) + ret = adrv->resume(adev); + return ret; +} + +struct bus_type at32_bus_type = { + .name = "at32", + .match = at32_bus_match, + .probe = at32_device_probe, + .remove = at32_device_remove, + .shutdown = at32_device_shutdown, + .suspend = at32_device_suspend, + .resume = at32_device_resume, +}; + +static int __init at32_bus_init(void) +{ + return bus_register(&at32_bus_type); +} + +postcore_initcall(at32_bus_init); diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/early_printk.c linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/early_printk.c --- linux-2.6.16.11/arch/avr32/platforms/at32ap/early_printk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/early_printk.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,132 @@ +/* + * Early printk support for AT32AP CPUs with on-chip USART. + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include + +#include +#include + +struct early_usart { + void __iomem *regs; + const struct at32_device *adev; +} early_usart; + +static int __initdata keep_early; +static struct console *early_console; + +static void early_usart_putc(struct console *co, unsigned char ch) +{ + struct early_usart *us = co->data; + + if (ch == '\n') + early_usart_putc(co, '\r'); + + while (!(usart3_readl(us, CSR) & USART3_BIT(TXRDY))) + cpu_relax(); + + usart3_writel(us, THR, ch); +} + +static void early_usart_write(struct console *co, const char *s, + unsigned int n) +{ + while (*s && n--) + early_usart_putc(co, *s++); +} + +static int early_usart_setup(struct console *co, char *options) +{ + struct at32_device *adev; + struct early_usart *us; + unsigned long baudrate = CONFIG_EARLY_PRINTK_BAUDRATE; + + us = &early_usart; + + adev = at32_find_device("usart", CONFIG_EARLY_PRINTK_PORTID); + if (!adev) + adev = at32_find_device("usart", 0); + if (!adev) { + printk(KERN_ERR "early_printk: could not find USART device\n"); + return -ENODEV; + } + + at32_enable_device(adev); + us->regs = at32_map_iomem(adev, 0); + + usart3_writel(us, BRGR, + ((at32_get_sclk_hz(adev, 0) + 8 * baudrate) + / (16 * baudrate))); + usart3_writel(us, MR, (USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL) + | USART3_BF(CHRL, USART3_CHRL_8) + | USART3_BF(PAR, USART3_PAR_NONE) + | USART3_BF(NBSTOP, USART3_NBSTOP_1))); + usart3_writel(us, IDR, ~0UL); + usart3_writel(us, CR, (USART3_BIT(RSTRX) + | USART3_BIT(RSTTX) + | USART3_BIT(RSTSTA))); + usart3_writel(us, CR, USART3_BIT(TXEN)); + + co->data = us; + + return 0; +} + +static struct console early_usart_console = { + .name = "eusart", + .write = early_usart_write, + .setup = early_usart_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +int __init setup_early_printk(char *opt) +{ + char *space; + char buf[256]; + + if (early_console) + return -1; + + strlcpy(buf, opt, sizeof(buf)); + space = strchr(buf, ' '); + if (space) + *space = 0; + + if (strstr(buf, "keep")) + keep_early = 1; + + if (!strncmp(buf, "usart", 5)) + early_console = &early_usart_console; + + if (early_console) + register_console(early_console); + + return 0; +} +__setup("earlyprintk=", setup_early_printk); + +void __init disable_early_printk(void) +{ + if (!early_console) + return; + + if (!keep_early) { + printk("disabling early console\n"); + unregister_console(early_console); + early_console = NULL; + } else { + printk("keeping early console\n"); + } +} diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/intc.c linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/intc.c --- linux-2.6.16.11/arch/avr32/platforms/at32ap/intc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/intc.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +#include +#include + +#include + +#include "intc.h" + +void __init init_IRQ(void) +{ + extern void _evba(void); + extern void irq_level0(void); + unsigned int i; + u32 offset, readback; + + if (at32_enable_device(intc.adev)) { + printk(KERN_EMERG "INTC: Failed to enable device %s%u\n", + intc.adev->name, intc.adev->id); + goto fail; + } + + intc.regs = at32_map_iomem(intc.adev, 0); + if (!intc.regs) { + printk(KERN_EMERG "INTC: Failed to map registers (0x%08lx)\n", + at32_get_iomem_base(intc.adev, 0)); + goto fail; + } + + /* + * Initialize all interrupts to level 0 (lowest priority). The + * priority level may be changed by calling + * irq_set_priority(). + * + */ + offset = (unsigned long)&irq_level0 - (unsigned long)&_evba; + for (i = 0; i < intc.nr_groups; i++) { + intc_writel(&intc, INTPR0 + 4 * i, offset); + readback = intc_readl(&intc, INTPR0 + 4 * i); + if (readback != offset) + printk(KERN_INFO + "IRQ: interrupt group %u seems to be unused\n", + i); + } + + /* Unmask all interrupt levels */ + sysreg_write(SR, (sysreg_read(SR) + & ~(SR_I3M | SR_I2M | SR_I1M | SR_I0M))); + + return; + +fail: + panic("Interrupt controller initialization failed!\n"); +} + diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/intc.h linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/intc.h --- linux-2.6.16.11/arch/avr32/platforms/at32ap/intc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/intc.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,327 @@ +/* + * Automatically generated by gen-header.xsl + */ +#ifndef __ASM_AVR32_PERIHP_INTC_H__ +#define __ASM_AVR32_PERIHP_INTC_H__ + +#define INTC_NUM_INT_GRPS 33 + +#define INTC_INTPR0 0x0 +# define INTC_INTPR0_INTLEV_OFFSET 30 +# define INTC_INTPR0_INTLEV_SIZE 2 +# define INTC_INTPR0_OFFSET_OFFSET 0 +# define INTC_INTPR0_OFFSET_SIZE 24 +#define INTC_INTREQ0 0x100 +# define INTC_INTREQ0_IREQUEST0_OFFSET 0 +# define INTC_INTREQ0_IREQUEST0_SIZE 1 +# define INTC_INTREQ0_IREQUEST1_OFFSET 1 +# define INTC_INTREQ0_IREQUEST1_SIZE 1 +#define INTC_INTPR1 0x4 +# define INTC_INTPR1_INTLEV_OFFSET 30 +# define INTC_INTPR1_INTLEV_SIZE 2 +# define INTC_INTPR1_OFFSET_OFFSET 0 +# define INTC_INTPR1_OFFSET_SIZE 24 +#define INTC_INTREQ1 0x104 +# define INTC_INTREQ1_IREQUEST32_OFFSET 0 +# define INTC_INTREQ1_IREQUEST32_SIZE 1 +# define INTC_INTREQ1_IREQUEST33_OFFSET 1 +# define INTC_INTREQ1_IREQUEST33_SIZE 1 +# define INTC_INTREQ1_IREQUEST34_OFFSET 2 +# define INTC_INTREQ1_IREQUEST34_SIZE 1 +# define INTC_INTREQ1_IREQUEST35_OFFSET 3 +# define INTC_INTREQ1_IREQUEST35_SIZE 1 +# define INTC_INTREQ1_IREQUEST36_OFFSET 4 +# define INTC_INTREQ1_IREQUEST36_SIZE 1 +# define INTC_INTREQ1_IREQUEST37_OFFSET 5 +# define INTC_INTREQ1_IREQUEST37_SIZE 1 +#define INTC_INTPR2 0x8 +# define INTC_INTPR2_INTLEV_OFFSET 30 +# define INTC_INTPR2_INTLEV_SIZE 2 +# define INTC_INTPR2_OFFSET_OFFSET 0 +# define INTC_INTPR2_OFFSET_SIZE 24 +#define INTC_INTREQ2 0x108 +# define INTC_INTREQ2_IREQUEST64_OFFSET 0 +# define INTC_INTREQ2_IREQUEST64_SIZE 1 +# define INTC_INTREQ2_IREQUEST65_OFFSET 1 +# define INTC_INTREQ2_IREQUEST65_SIZE 1 +# define INTC_INTREQ2_IREQUEST66_OFFSET 2 +# define INTC_INTREQ2_IREQUEST66_SIZE 1 +# define INTC_INTREQ2_IREQUEST67_OFFSET 3 +# define INTC_INTREQ2_IREQUEST67_SIZE 1 +# define INTC_INTREQ2_IREQUEST68_OFFSET 4 +# define INTC_INTREQ2_IREQUEST68_SIZE 1 +#define INTC_INTPR3 0xc +# define INTC_INTPR3_INTLEV_OFFSET 30 +# define INTC_INTPR3_INTLEV_SIZE 2 +# define INTC_INTPR3_OFFSET_OFFSET 0 +# define INTC_INTPR3_OFFSET_SIZE 24 +#define INTC_INTREQ3 0x10c +# define INTC_INTREQ3_IREQUEST96_OFFSET 0 +# define INTC_INTREQ3_IREQUEST96_SIZE 1 +#define INTC_INTPR4 0x10 +# define INTC_INTPR4_INTLEV_OFFSET 30 +# define INTC_INTPR4_INTLEV_SIZE 2 +# define INTC_INTPR4_OFFSET_OFFSET 0 +# define INTC_INTPR4_OFFSET_SIZE 24 +#define INTC_INTREQ4 0x110 +# define INTC_INTREQ4_IREQUEST128_OFFSET 0 +# define INTC_INTREQ4_IREQUEST128_SIZE 1 +#define INTC_INTPR5 0x14 +# define INTC_INTPR5_INTLEV_OFFSET 30 +# define INTC_INTPR5_INTLEV_SIZE 2 +# define INTC_INTPR5_OFFSET_OFFSET 0 +# define INTC_INTPR5_OFFSET_SIZE 24 +#define INTC_INTREQ5 0x114 +# define INTC_INTREQ5_IREQUEST160_OFFSET 0 +# define INTC_INTREQ5_IREQUEST160_SIZE 1 +#define INTC_INTPR6 0x18 +# define INTC_INTPR6_INTLEV_OFFSET 30 +# define INTC_INTPR6_INTLEV_SIZE 2 +# define INTC_INTPR6_OFFSET_OFFSET 0 +# define INTC_INTPR6_OFFSET_SIZE 24 +#define INTC_INTREQ6 0x118 +# define INTC_INTREQ6_IREQUEST192_OFFSET 0 +# define INTC_INTREQ6_IREQUEST192_SIZE 1 +#define INTC_INTPR7 0x1c +# define INTC_INTPR7_INTLEV_OFFSET 30 +# define INTC_INTPR7_INTLEV_SIZE 2 +# define INTC_INTPR7_OFFSET_OFFSET 0 +# define INTC_INTPR7_OFFSET_SIZE 24 +#define INTC_INTREQ7 0x11c +# define INTC_INTREQ7_IREQUEST224_OFFSET 0 +# define INTC_INTREQ7_IREQUEST224_SIZE 1 +#define INTC_INTPR8 0x20 +# define INTC_INTPR8_INTLEV_OFFSET 30 +# define INTC_INTPR8_INTLEV_SIZE 2 +# define INTC_INTPR8_OFFSET_OFFSET 0 +# define INTC_INTPR8_OFFSET_SIZE 24 +#define INTC_INTREQ8 0x120 +# define INTC_INTREQ8_IREQUEST256_OFFSET 0 +# define INTC_INTREQ8_IREQUEST256_SIZE 1 +#define INTC_INTPR9 0x24 +# define INTC_INTPR9_INTLEV_OFFSET 30 +# define INTC_INTPR9_INTLEV_SIZE 2 +# define INTC_INTPR9_OFFSET_OFFSET 0 +# define INTC_INTPR9_OFFSET_SIZE 24 +#define INTC_INTREQ9 0x124 +# define INTC_INTREQ9_IREQUEST288_OFFSET 0 +# define INTC_INTREQ9_IREQUEST288_SIZE 1 +#define INTC_INTPR10 0x28 +# define INTC_INTPR10_INTLEV_OFFSET 30 +# define INTC_INTPR10_INTLEV_SIZE 2 +# define INTC_INTPR10_OFFSET_OFFSET 0 +# define INTC_INTPR10_OFFSET_SIZE 24 +#define INTC_INTREQ10 0x128 +# define INTC_INTREQ10_IREQUEST320_OFFSET 0 +# define INTC_INTREQ10_IREQUEST320_SIZE 1 +#define INTC_INTPR11 0x2c +# define INTC_INTPR11_INTLEV_OFFSET 30 +# define INTC_INTPR11_INTLEV_SIZE 2 +# define INTC_INTPR11_OFFSET_OFFSET 0 +# define INTC_INTPR11_OFFSET_SIZE 24 +#define INTC_INTREQ11 0x12c +# define INTC_INTREQ11_IREQUEST352_OFFSET 0 +# define INTC_INTREQ11_IREQUEST352_SIZE 1 +#define INTC_INTPR12 0x30 +# define INTC_INTPR12_INTLEV_OFFSET 30 +# define INTC_INTPR12_INTLEV_SIZE 2 +# define INTC_INTPR12_OFFSET_OFFSET 0 +# define INTC_INTPR12_OFFSET_SIZE 24 +#define INTC_INTREQ12 0x130 +# define INTC_INTREQ12_IREQUEST384_OFFSET 0 +# define INTC_INTREQ12_IREQUEST384_SIZE 1 +#define INTC_INTPR13 0x34 +# define INTC_INTPR13_INTLEV_OFFSET 30 +# define INTC_INTPR13_INTLEV_SIZE 2 +# define INTC_INTPR13_OFFSET_OFFSET 0 +# define INTC_INTPR13_OFFSET_SIZE 24 +#define INTC_INTREQ13 0x134 +# define INTC_INTREQ13_IREQUEST416_OFFSET 0 +# define INTC_INTREQ13_IREQUEST416_SIZE 1 +#define INTC_INTPR14 0x38 +# define INTC_INTPR14_INTLEV_OFFSET 30 +# define INTC_INTPR14_INTLEV_SIZE 2 +# define INTC_INTPR14_OFFSET_OFFSET 0 +# define INTC_INTPR14_OFFSET_SIZE 24 +#define INTC_INTREQ14 0x138 +# define INTC_INTREQ14_IREQUEST448_OFFSET 0 +# define INTC_INTREQ14_IREQUEST448_SIZE 1 +#define INTC_INTPR15 0x3c +# define INTC_INTPR15_INTLEV_OFFSET 30 +# define INTC_INTPR15_INTLEV_SIZE 2 +# define INTC_INTPR15_OFFSET_OFFSET 0 +# define INTC_INTPR15_OFFSET_SIZE 24 +#define INTC_INTREQ15 0x13c +# define INTC_INTREQ15_IREQUEST480_OFFSET 0 +# define INTC_INTREQ15_IREQUEST480_SIZE 1 +#define INTC_INTPR16 0x40 +# define INTC_INTPR16_INTLEV_OFFSET 30 +# define INTC_INTPR16_INTLEV_SIZE 2 +# define INTC_INTPR16_OFFSET_OFFSET 0 +# define INTC_INTPR16_OFFSET_SIZE 24 +#define INTC_INTREQ16 0x140 +# define INTC_INTREQ16_IREQUEST512_OFFSET 0 +# define INTC_INTREQ16_IREQUEST512_SIZE 1 +#define INTC_INTPR17 0x44 +# define INTC_INTPR17_INTLEV_OFFSET 30 +# define INTC_INTPR17_INTLEV_SIZE 2 +# define INTC_INTPR17_OFFSET_OFFSET 0 +# define INTC_INTPR17_OFFSET_SIZE 24 +#define INTC_INTREQ17 0x144 +# define INTC_INTREQ17_IREQUEST544_OFFSET 0 +# define INTC_INTREQ17_IREQUEST544_SIZE 1 +#define INTC_INTPR18 0x48 +# define INTC_INTPR18_INTLEV_OFFSET 30 +# define INTC_INTPR18_INTLEV_SIZE 2 +# define INTC_INTPR18_OFFSET_OFFSET 0 +# define INTC_INTPR18_OFFSET_SIZE 24 +#define INTC_INTREQ18 0x148 +# define INTC_INTREQ18_IREQUEST576_OFFSET 0 +# define INTC_INTREQ18_IREQUEST576_SIZE 1 +#define INTC_INTPR19 0x4c +# define INTC_INTPR19_INTLEV_OFFSET 30 +# define INTC_INTPR19_INTLEV_SIZE 2 +# define INTC_INTPR19_OFFSET_OFFSET 0 +# define INTC_INTPR19_OFFSET_SIZE 24 +#define INTC_INTREQ19 0x14c +# define INTC_INTREQ19_IREQUEST608_OFFSET 0 +# define INTC_INTREQ19_IREQUEST608_SIZE 1 +# define INTC_INTREQ19_IREQUEST609_OFFSET 1 +# define INTC_INTREQ19_IREQUEST609_SIZE 1 +# define INTC_INTREQ19_IREQUEST610_OFFSET 2 +# define INTC_INTREQ19_IREQUEST610_SIZE 1 +# define INTC_INTREQ19_IREQUEST611_OFFSET 3 +# define INTC_INTREQ19_IREQUEST611_SIZE 1 +#define INTC_INTPR20 0x50 +# define INTC_INTPR20_INTLEV_OFFSET 30 +# define INTC_INTPR20_INTLEV_SIZE 2 +# define INTC_INTPR20_OFFSET_OFFSET 0 +# define INTC_INTPR20_OFFSET_SIZE 24 +#define INTC_INTREQ20 0x150 +# define INTC_INTREQ20_IREQUEST640_OFFSET 0 +# define INTC_INTREQ20_IREQUEST640_SIZE 1 +#define INTC_INTPR21 0x54 +# define INTC_INTPR21_INTLEV_OFFSET 30 +# define INTC_INTPR21_INTLEV_SIZE 2 +# define INTC_INTPR21_OFFSET_OFFSET 0 +# define INTC_INTPR21_OFFSET_SIZE 24 +#define INTC_INTREQ21 0x154 +# define INTC_INTREQ21_IREQUEST672_OFFSET 0 +# define INTC_INTREQ21_IREQUEST672_SIZE 1 +#define INTC_INTPR22 0x58 +# define INTC_INTPR22_INTLEV_OFFSET 30 +# define INTC_INTPR22_INTLEV_SIZE 2 +# define INTC_INTPR22_OFFSET_OFFSET 0 +# define INTC_INTPR22_OFFSET_SIZE 24 +#define INTC_INTREQ22 0x158 +# define INTC_INTREQ22_IREQUEST704_OFFSET 0 +# define INTC_INTREQ22_IREQUEST704_SIZE 1 +# define INTC_INTREQ22_IREQUEST705_OFFSET 1 +# define INTC_INTREQ22_IREQUEST705_SIZE 1 +# define INTC_INTREQ22_IREQUEST706_OFFSET 2 +# define INTC_INTREQ22_IREQUEST706_SIZE 1 +#define INTC_INTPR23 0x5c +# define INTC_INTPR23_INTLEV_OFFSET 30 +# define INTC_INTPR23_INTLEV_SIZE 2 +# define INTC_INTPR23_OFFSET_OFFSET 0 +# define INTC_INTPR23_OFFSET_SIZE 24 +#define INTC_INTREQ23 0x15c +# define INTC_INTREQ23_IREQUEST736_OFFSET 0 +# define INTC_INTREQ23_IREQUEST736_SIZE 1 +# define INTC_INTREQ23_IREQUEST737_OFFSET 1 +# define INTC_INTREQ23_IREQUEST737_SIZE 1 +# define INTC_INTREQ23_IREQUEST738_OFFSET 2 +# define INTC_INTREQ23_IREQUEST738_SIZE 1 +#define INTC_INTPR24 0x60 +# define INTC_INTPR24_INTLEV_OFFSET 30 +# define INTC_INTPR24_INTLEV_SIZE 2 +# define INTC_INTPR24_OFFSET_OFFSET 0 +# define INTC_INTPR24_OFFSET_SIZE 24 +#define INTC_INTREQ24 0x160 +# define INTC_INTREQ24_IREQUEST768_OFFSET 0 +# define INTC_INTREQ24_IREQUEST768_SIZE 1 +#define INTC_INTPR25 0x64 +# define INTC_INTPR25_INTLEV_OFFSET 30 +# define INTC_INTPR25_INTLEV_SIZE 2 +# define INTC_INTPR25_OFFSET_OFFSET 0 +# define INTC_INTPR25_OFFSET_SIZE 24 +#define INTC_INTREQ25 0x164 +# define INTC_INTREQ25_IREQUEST800_OFFSET 0 +# define INTC_INTREQ25_IREQUEST800_SIZE 1 +#define INTC_INTPR26 0x68 +# define INTC_INTPR26_INTLEV_OFFSET 30 +# define INTC_INTPR26_INTLEV_SIZE 2 +# define INTC_INTPR26_OFFSET_OFFSET 0 +# define INTC_INTPR26_OFFSET_SIZE 24 +#define INTC_INTREQ26 0x168 +# define INTC_INTREQ26_IREQUEST832_OFFSET 0 +# define INTC_INTREQ26_IREQUEST832_SIZE 1 +#define INTC_INTPR27 0x6c +# define INTC_INTPR27_INTLEV_OFFSET 30 +# define INTC_INTPR27_INTLEV_SIZE 2 +# define INTC_INTPR27_OFFSET_OFFSET 0 +# define INTC_INTPR27_OFFSET_SIZE 24 +#define INTC_INTREQ27 0x16c +# define INTC_INTREQ27_IREQUEST864_OFFSET 0 +# define INTC_INTREQ27_IREQUEST864_SIZE 1 +#define INTC_INTPR28 0x70 +# define INTC_INTPR28_INTLEV_OFFSET 30 +# define INTC_INTPR28_INTLEV_SIZE 2 +# define INTC_INTPR28_OFFSET_OFFSET 0 +# define INTC_INTPR28_OFFSET_SIZE 24 +#define INTC_INTREQ28 0x170 +# define INTC_INTREQ28_IREQUEST896_OFFSET 0 +# define INTC_INTREQ28_IREQUEST896_SIZE 1 +#define INTC_INTPR29 0x74 +# define INTC_INTPR29_INTLEV_OFFSET 30 +# define INTC_INTPR29_INTLEV_SIZE 2 +# define INTC_INTPR29_OFFSET_OFFSET 0 +# define INTC_INTPR29_OFFSET_SIZE 24 +#define INTC_INTREQ29 0x174 +# define INTC_INTREQ29_IREQUEST928_OFFSET 0 +# define INTC_INTREQ29_IREQUEST928_SIZE 1 +#define INTC_INTPR30 0x78 +# define INTC_INTPR30_INTLEV_OFFSET 30 +# define INTC_INTPR30_INTLEV_SIZE 2 +# define INTC_INTPR30_OFFSET_OFFSET 0 +# define INTC_INTPR30_OFFSET_SIZE 24 +#define INTC_INTREQ30 0x178 +# define INTC_INTREQ30_IREQUEST960_OFFSET 0 +# define INTC_INTREQ30_IREQUEST960_SIZE 1 +#define INTC_INTPR31 0x7c +# define INTC_INTPR31_INTLEV_OFFSET 30 +# define INTC_INTPR31_INTLEV_SIZE 2 +# define INTC_INTPR31_OFFSET_OFFSET 0 +# define INTC_INTPR31_OFFSET_SIZE 24 +#define INTC_INTREQ31 0x17c +# define INTC_INTREQ31_IREQUEST992_OFFSET 0 +# define INTC_INTREQ31_IREQUEST992_SIZE 1 +#define INTC_INTPR32 0x80 +# define INTC_INTPR32_INTLEV_OFFSET 30 +# define INTC_INTPR32_INTLEV_SIZE 2 +# define INTC_INTPR32_OFFSET_OFFSET 0 +# define INTC_INTPR32_OFFSET_SIZE 24 +#define INTC_INTREQ32 0x180 +# define INTC_INTREQ32_IREQUEST1024_OFFSET 0 +# define INTC_INTREQ32_IREQUEST1024_SIZE 1 +#define INTC_INTCAUSE0 0x20c +# define INTC_INTCAUSE0_CAUSEGRP_OFFSET 0 +# define INTC_INTCAUSE0_CAUSEGRP_SIZE 6 +#define INTC_INTCAUSE1 0x208 +# define INTC_INTCAUSE1_CAUSEGRP_OFFSET 0 +# define INTC_INTCAUSE1_CAUSEGRP_SIZE 6 +#define INTC_INTCAUSE2 0x204 +# define INTC_INTCAUSE2_CAUSEGRP_OFFSET 0 +# define INTC_INTCAUSE2_CAUSEGRP_SIZE 6 +#define INTC_INTCAUSE3 0x200 +# define INTC_INTCAUSE3_CAUSEGRP_OFFSET 0 +# define INTC_INTCAUSE3_CAUSEGRP_SIZE 6 + +#define INTC_BIT(name) (1 << INTC_##name##_OFFSET) +#define INTC_MKBF(name, value) (((value) & ((1 << INTC_##name##_SIZE) - 1)) << INTC_##name##_OFFSET) +#define INTC_GETBF(name, value) (((value) >> INTC_##name##_OFFSET) & ((1 << INTC_##name##_SIZE) - 1)) + +#define intc_readl(port,reg) readl((port)->regs + INTC_##reg) +#define intc_writel(port,reg,value) writel((value), (port)->regs + INTC_##reg) + +#endif /* __ASM_AVR32_PERIHP_INTC_H__ */ diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/Makefile --- linux-2.6.16.11/arch/avr32/platforms/at32ap/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/Makefile 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,3 @@ +obj-y += at32_bus.o sm.o pio.o intc.o at32ap.o +obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/pio.c linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/pio.c --- linux-2.6.16.11/arch/avr32/platforms/at32ap/pio.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/pio.c 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,213 @@ +/* + * Atmel PIO2 Port Multiplexer support + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include + +#include + +#include +#include + +#include "pio.h" + +#define MAX_PIO_DEVICES 8 + +struct pio_device { + void __iomem *regs; + const struct at32_device *adev; + u32 alloc_mask; + char name[32]; +}; + +static struct pio_device pio_dev[MAX_PIO_DEVICES]; +static int nr_pio_devices; +static spinlock_t devlist_lock = SPIN_LOCK_UNLOCKED; + +#define PIN_GET_INDEX(x) (((x) & 0x001f) >> 0) +#define PIN_GET_PIO(x) (((x) & 0x3fe0) >> 5) +#define PIN_GET_FUNCTION(x) (((x) & 0x4000) >> 14) +#define PIN_GET_PULLUP(x) (((x) & 0x8000) >> 15) + +void portmux_disable_device(const struct at32_device *adev) +{ + struct pio_device *pio; + unsigned int i, pio_id, index; + u16 pin; + + for (i = 0; i < adev->pin_count; i++) { + pin = adev->pin[i]; + + pio_id = PIN_GET_PIO(pin); + index = PIN_GET_INDEX(pin); + + pio = &pio_dev[pio_id]; + + if (unlikely(!test_and_clear_bit(index, &pio->alloc_mask))) + BUG(); + + pio_writel(pio, ODR, 1 << index); + pio_writel(pio, PER, 1 << index); + } +} +EXPORT_SYMBOL(portmux_disable_device); + +int portmux_enable_device(const struct at32_device *adev) +{ + struct pio_device *pio; + unsigned int i, pio_id, index; + u16 pin; + + dev_dbg(&adev->dev, "portmux: enabling device (%u pins)\n", + adev->pin_count); + + for (i = 0; i < adev->pin_count; i++) { + pin = adev->pin[i]; + + pio_id = PIN_GET_PIO(pin); + index = PIN_GET_INDEX(pin); + + if (pio_id >= nr_pio_devices) { + dev_dbg(&adev->dev, "Nonexistent PIO %u requested\n", + pio_id); + goto fail; + } + + pio = &pio_dev[pio_id]; + if (test_and_set_bit(index, &pio->alloc_mask)) { + dev_dbg(&adev->dev, "PIO pin %u:%u is busy\n", + pio_id, index); + goto fail; + } + + /* + * No need to lock as we're modifying the bits we just + * allocated atomically. + */ + dev_dbg(&adev->dev, "PIO %u, index %u, func %c,%s pullup\n", + pio_id, index, PIN_GET_FUNCTION(pin)?'B':'A', + PIN_GET_PULLUP(pin)?"":" no"); + + if (PIN_GET_PULLUP(pin)) + pio_writel(pio, PUER, 1 << index); + else + pio_writel(pio, PUDR, 1 << index); + + if (!PIN_GET_FUNCTION(pin)) + pio_writel(pio, ASR, 1 << index); + else + pio_writel(pio, BSR, 1 << index); + + pio_writel(pio, PDR, 1 << index); + } + + /* TODO: Do some basic resource management to avoid conflicts */ + return 0; + +fail: + while (i > 0) { + pin = adev->pin[--i]; + + pio_id = PIN_GET_PIO(pin); + index = PIN_GET_INDEX(pin); + pio = &pio_dev[pio_id]; + + clear_bit(1 << index, &pio->alloc_mask); + pio_writel(pio, ODR, 1 << index); + pio_writel(pio, PER, 1 << index); + } + + return -EBUSY; +} +EXPORT_SYMBOL(portmux_enable_device); + +static int __init pio_probe(struct at32_device *adev) +{ + struct pio_device *pio = NULL; + + BUG_ON(adev->id >= nr_pio_devices); + pio = &pio_dev[adev->id]; + + /* TODO: Interrupts */ + + at32_set_drvdata(adev, pio); + + printk(KERN_INFO "%s: Atmel Port Multiplexer at 0x%08lx (irq %d)\n", + pio->name, at32_get_iomem_base(adev, 0), at32_get_irq(adev)); + + return 0; +} + +static struct at32_driver pio_driver = { + .probe = pio_probe, + .driver = { + .name = "pio", + }, +}; + +static int __init pio_init(void) +{ + return at32_driver_register(&pio_driver); +} +subsys_initcall(pio_init); + +static void __init initialize_pio(struct at32_device *adev) +{ + struct pio_device *pio; + int ret; + + ret = at32_enable_device(adev); + if (ret) + /* + * This is a fatal error, but if we continue we might + * be so lucky that we manage to initialize the + * console and display this message... + */ + printk(KERN_ERR "Unable to enable PIO device %d: %d\n", + adev->id, ret); + + pio = &pio_dev[adev->id]; + + pio->adev = adev; + pio->regs = at32_map_iomem(adev, 0); + snprintf(pio->name, sizeof(pio->name), "pio%d", adev->id); + + pio_writel(pio, ODR, ~0UL); + pio_writel(pio, PER, ~0UL); +} + +int __init at32_portmux_init(void) +{ + struct at32_device *adev; + unsigned int i; + + /* + * This is called from board-specific setup code so that + * things like SDRAM and early printk initialization can use + * pio_enable_device(). In other words, we're going to + * initialize the PIO driver here instead of in probe(). + */ + spin_lock(&devlist_lock); + nr_pio_devices = at32_count_devices("pio"); + + for (i = 0; i < nr_pio_devices; i++) { + adev = at32_find_device("pio", i); + if (!adev) { + printk(KERN_WARNING "Warning: PIO%d device not found\n", + i); + continue; + } + initialize_pio(adev); + } + spin_unlock(&devlist_lock); + + return 0; +} diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/pio.h linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/pio.h --- linux-2.6.16.11/arch/avr32/platforms/at32ap/pio.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/pio.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,176 @@ +/* + * Atmel PIO2 Port Multiplexer support + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ARCH_AVR32_AT32AP_PIO_H__ +#define __ARCH_AVR32_AT32AP_PIO_H__ + +/* PIO register offsets */ +#define PIO_PER 0x0000 +#define PIO_PDR 0x0004 +#define PIO_PSR 0x0008 +#define PIO_OER 0x0010 +#define PIO_ODR 0x0014 +#define PIO_OSR 0x0018 +#define PIO_IFER 0x0020 +#define PIO_IFDR 0x0024 +#define PIO_ISFR 0x0028 +#define PIO_SODR 0x0030 +#define PIO_CODR 0x0034 +#define PIO_ODSR 0x0038 +#define PIO_PDSR 0x003c +#define PIO_IER 0x0040 +#define PIO_IDR 0x0044 +#define PIO_IMR 0x0048 +#define PIO_ISR 0x004c +#define PIO_MDER 0x0050 +#define PIO_MDDR 0x0054 +#define PIO_MDSR 0x0058 +#define PIO_PUDR 0x0060 +#define PIO_PUER 0x0064 +#define PIO_PUSR 0x0068 +#define PIO_ASR 0x0070 +#define PIO_BSR 0x0074 +#define PIO_ABSR 0x0078 +#define PIO_OWER 0x00a0 +#define PIO_OWDR 0x00a4 +#define PIO_OWSR 0x00a8 + +/* Bitfields in PER */ + +/* Bitfields in PDR */ + +/* Bitfields in PSR */ + +/* Bitfields in OER */ + +/* Bitfields in ODR */ + +/* Bitfields in OSR */ + +/* Bitfields in IFER */ + +/* Bitfields in IFDR */ + +/* Bitfields in ISFR */ + +/* Bitfields in SODR */ + +/* Bitfields in CODR */ + +/* Bitfields in ODSR */ + +/* Bitfields in PDSR */ + +/* Bitfields in IER */ + +/* Bitfields in IDR */ + +/* Bitfields in IMR */ + +/* Bitfields in ISR */ + +/* Bitfields in MDER */ + +/* Bitfields in MDDR */ + +/* Bitfields in MDSR */ + +/* Bitfields in PUDR */ + +/* Bitfields in PUER */ + +/* Bitfields in PUSR */ + +/* Bitfields in ASR */ + +/* Bitfields in BSR */ + +/* Bitfields in ABSR */ +#define PIO_P0_OFFSET 0 +#define PIO_P0_SIZE 1 +#define PIO_P1_OFFSET 1 +#define PIO_P1_SIZE 1 +#define PIO_P2_OFFSET 2 +#define PIO_P2_SIZE 1 +#define PIO_P3_OFFSET 3 +#define PIO_P3_SIZE 1 +#define PIO_P4_OFFSET 4 +#define PIO_P4_SIZE 1 +#define PIO_P5_OFFSET 5 +#define PIO_P5_SIZE 1 +#define PIO_P6_OFFSET 6 +#define PIO_P6_SIZE 1 +#define PIO_P7_OFFSET 7 +#define PIO_P7_SIZE 1 +#define PIO_P8_OFFSET 8 +#define PIO_P8_SIZE 1 +#define PIO_P9_OFFSET 9 +#define PIO_P9_SIZE 1 +#define PIO_P10_OFFSET 10 +#define PIO_P10_SIZE 1 +#define PIO_P11_OFFSET 11 +#define PIO_P11_SIZE 1 +#define PIO_P12_OFFSET 12 +#define PIO_P12_SIZE 1 +#define PIO_P13_OFFSET 13 +#define PIO_P13_SIZE 1 +#define PIO_P14_OFFSET 14 +#define PIO_P14_SIZE 1 +#define PIO_P15_OFFSET 15 +#define PIO_P15_SIZE 1 +#define PIO_P16_OFFSET 16 +#define PIO_P16_SIZE 1 +#define PIO_P17_OFFSET 17 +#define PIO_P17_SIZE 1 +#define PIO_P18_OFFSET 18 +#define PIO_P18_SIZE 1 +#define PIO_P19_OFFSET 19 +#define PIO_P19_SIZE 1 +#define PIO_P20_OFFSET 20 +#define PIO_P20_SIZE 1 +#define PIO_P21_OFFSET 21 +#define PIO_P21_SIZE 1 +#define PIO_P22_OFFSET 22 +#define PIO_P22_SIZE 1 +#define PIO_P23_OFFSET 23 +#define PIO_P23_SIZE 1 +#define PIO_P24_OFFSET 24 +#define PIO_P24_SIZE 1 +#define PIO_P25_OFFSET 25 +#define PIO_P25_SIZE 1 +#define PIO_P26_OFFSET 26 +#define PIO_P26_SIZE 1 +#define PIO_P27_OFFSET 27 +#define PIO_P27_SIZE 1 +#define PIO_P28_OFFSET 28 +#define PIO_P28_SIZE 1 +#define PIO_P29_OFFSET 29 +#define PIO_P29_SIZE 1 +#define PIO_P30_OFFSET 30 +#define PIO_P30_SIZE 1 +#define PIO_P31_OFFSET 31 +#define PIO_P31_SIZE 1 + +/* Bitfields in OWER */ + +/* Bitfields in OWDR */ + +/* Bitfields in OWSR */ + +/* Bit manipulation macros */ +#define PIO_BIT(name) (1 << PIO_##name##_OFFSET) +#define PIO_BF(name,value) (((value) & ((1 << PIO_##name##_SIZE) - 1)) << PIO_##name##_OFFSET) +#define PIO_BFEXT(name,value) (((value) >> PIO_##name##_OFFSET) & ((1 << PIO_##name##_SIZE) - 1)) +#define PIO_BFINS(name,value,old) (((old) & ~(((1 << PIO_##name##_SIZE) - 1) << PIO_##name##_OFFSET)) | PIO_BF(name,value)) + +/* Register access macros */ +#define pio_readl(port,reg) readl((port)->regs + PIO_##reg) +#define pio_writel(port,reg,value) writel((value), (port)->regs + PIO_##reg) + +#endif /* __ARCH_AVR32_AT32AP_PIO_H__ */ diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/sm.c linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/sm.c --- linux-2.6.16.11/arch/avr32/platforms/at32ap/sm.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/sm.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,372 @@ +/* + * System Manager driver for AT32AP CPUs + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "sm.h" + +#define SM_EIM_IRQ(base) ((base) + 0) +#define SM_PM_IRQ(base) ((base) + 1) +#define SM_RTC_IRQ(base) ((base) + 2) + +struct at32_sm { + spinlock_t lock; + void __iomem *regs; + struct irq_controller irqc; + struct irqaction **action; + struct at32_device *adev; +}; +#define to_eim(irqc) container_of(irqc, struct at32_sm, irqc) + +static struct at32_sm system_manager; + +static struct clock_domain *clock_domain_get(struct clock_domain *domain) +{ + unsigned long flags; + + pr_debug("SM: clock_domain_get: id=%u, count=%u\n", + domain->id, domain->count); + + spin_lock_irqsave(&domain->lock, flags); + if (!domain->count++ && domain->sclk.domain) + sm_unmask_sclk(&domain->sclk); + spin_unlock_irqrestore(&domain->lock, flags); + + return domain; +} + +static void clock_domain_put(struct clock_domain *domain) +{ + unsigned long flags; + + pr_debug("SM: clock_domain_put: count=%u\n", domain->count); + + spin_lock_irqsave(&domain->lock, flags); + domain->count--; + if (!domain->count && domain->sclk.domain) + sm_mask_sclk(&domain->sclk); + spin_unlock_irqrestore(&domain->lock, flags); +} + +void sm_unmask_sclk(const struct sync_clock *sclk) +{ + struct at32_sm *sm = &system_manager; + struct clock_domain *domain; + unsigned long flags; + u32 mask; + + domain = clock_domain_get(sclk->domain); + + pr_debug("SM: unmasking sclk for domain %u, bit %u\n", + domain->id, sclk->bit); + + spin_lock_irqsave(&sm->lock, flags); + mask = sm_readl(sm, PM_CPU_MASK + 4 * domain->id); + mask |= 1 << sclk->bit; + sm_writel(sm, PM_CPU_MASK + 4 * domain->id, mask); + spin_unlock_irqrestore(&sm->lock, flags); +} + +void sm_mask_sclk(const struct sync_clock *sclk) +{ + struct at32_sm *sm = &system_manager; + struct clock_domain *domain = sclk->domain; + unsigned long flags; + u32 mask; + + /* Don't mask a precious clock */ + if (domain->precious_mask & (1<bit)) + return; + + spin_lock_irqsave(&sm->lock, flags); + mask = sm_readl(sm, PM_CPU_MASK + 4 * domain->id); + mask &= ~(1 << sclk->bit); + sm_writel(sm, PM_CPU_MASK + 4 * domain->id, mask); + spin_unlock_irqrestore(&sm->lock, flags); + + clock_domain_put(sclk->domain); +} + +int __init at32_sm_init(void) +{ + struct at32_sm *sm = &system_manager; + unsigned int i; + int ret; + + spin_lock_init(&sm->lock); + + ret = -ENODEV; + sm->adev = at32_find_device("sm", 0); + if (!sm->adev) + goto fail; + + ret = -ENOMEM; + sm->regs = at32_map_iomem(sm->adev, 0); + if (!sm->regs) + goto fail; + + /* Mask all sclocks that aren't essential */ + for (i = 0; i < nr_chip_domains; i++) { + struct clock_domain *domain = &chip_domain[i]; + + sm_writel(sm, PM_CPU_MASK + 4 * domain->id, + domain->precious_mask); + } + + return 0; + +fail: + printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret); + return ret; +} + +/* + * External Interrupt Module (EIM). + * + * EIM gets level- or edge-triggered interrupts of either polarity + * from the outside and converts it to active-high level-triggered + * interrupts that the internal interrupt controller can handle. EIM + * also provides masking/unmasking of interrupts, as well as + * acknowledging of edge-triggered interrupts. + */ + +static irqreturn_t spurious_eim_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + printk(KERN_WARNING "Spurious EIM interrupt %d\n", irq); + disable_irq(irq); + return IRQ_NONE; +} + +static struct irqaction eim_spurious_action = { + .handler = spurious_eim_interrupt, +}; + +static irqreturn_t eim_handle_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct irq_controller * irqc = dev_id; + struct at32_sm *sm = to_eim(irqc); + unsigned long pending; + + /* + * No need to disable interrupts globally. The interrupt + * level relevant to this group must be masked all the time, + * so we know that this particular EIM instance will not be + * re-entered. + */ + spin_lock(&sm->lock); + + pending = intc_get_pending(sm->irqc.irq_group); + if (unlikely(!pending)) { + printk(KERN_ERR "EIM (group %u): No interrupts pending!\n", + sm->irqc.irq_group); + goto unlock; + } + + do { + struct irqaction *action; + unsigned int i; + + i = fls(pending) - 1; + pending &= ~(1 << i); + action = sm->action[i]; + + /* Acknowledge the interrupt */ + sm_writel(sm, EIM_ICR, 1 << i); + + spin_unlock(&sm->lock); + + if (action->flags & SA_INTERRUPT) + local_irq_disable(); + action->handler(sm->irqc.first_irq + i, action->dev_id, regs); + local_irq_enable(); + spin_lock(&sm->lock); + if (action->flags & SA_SAMPLE_RANDOM) + add_interrupt_randomness(sm->irqc.first_irq + i); + } while (pending); + +unlock: + spin_unlock(&sm->lock); + return IRQ_HANDLED; +} + +static void eim_mask(struct irq_controller *irqc, unsigned int irq) +{ + struct at32_sm *sm = to_eim(irqc); + unsigned int i; + + i = irq - sm->irqc.first_irq; + sm_writel(sm, EIM_IDR, 1 << i); +} + +static void eim_unmask(struct irq_controller *irqc, unsigned int irq) +{ + struct at32_sm *sm = to_eim(irqc); + unsigned int i; + + i = irq - sm->irqc.first_irq; + sm_writel(sm, EIM_IER, 1 << i); +} + +static int eim_setup(struct irq_controller *irqc, unsigned int irq, + struct irqaction *action) +{ + struct at32_sm *sm = to_eim(irqc); + sm->action[irq - sm->irqc.first_irq] = action; + /* Acknowledge earlier interrupts */ + sm_writel(sm, EIM_ICR, (1<<(irq - sm->irqc.first_irq))); + eim_unmask(irqc, irq); + return 0; +} + +static void eim_free(struct irq_controller *irqc, unsigned int irq, + void *dev) +{ + struct at32_sm *sm = to_eim(irqc); + eim_mask(irqc, irq); + sm->action[irq - sm->irqc.first_irq] = &eim_spurious_action; +} + +static int eim_set_type(struct irq_controller *irqc, unsigned int irq, + unsigned int type) +{ + struct at32_sm *sm = to_eim(irqc); + unsigned long flags; + u32 value, pattern; + + spin_lock_irqsave(&sm->lock, flags); + + pattern = 1 << (irq - sm->irqc.first_irq); + + value = sm_readl(sm, EIM_MODE); + if (type & IRQ_TYPE_LEVEL) + value |= pattern; + else + value &= ~pattern; + sm_writel(sm, EIM_MODE, value); + value = sm_readl(sm, EIM_EDGE); + if (type & IRQ_EDGE_RISING) + value |= pattern; + else + value &= ~pattern; + sm_writel(sm, EIM_EDGE, value); + value = sm_readl(sm, EIM_LEVEL); + if (type & IRQ_LEVEL_HIGH) + value |= pattern; + else + value &= ~pattern; + sm_writel(sm, EIM_LEVEL, value); + + spin_unlock_irqrestore(&sm->lock, flags); + + return 0; +} + +static unsigned int eim_get_type(struct irq_controller *irqc, + unsigned int irq) +{ + struct at32_sm *sm = to_eim(irqc); + unsigned long flags; + unsigned int type = 0; + u32 mode, edge, level, pattern; + + pattern = 1 << (irq - sm->irqc.first_irq); + + spin_lock_irqsave(&sm->lock, flags); + mode = sm_readl(sm, EIM_MODE); + edge = sm_readl(sm, EIM_EDGE); + level = sm_readl(sm, EIM_LEVEL); + spin_unlock_irqrestore(&sm->lock, flags); + + if (mode & pattern) + type |= IRQ_TYPE_LEVEL; + if (edge & pattern) + type |= IRQ_EDGE_RISING; + if (level & pattern) + type |= IRQ_LEVEL_HIGH; + + return type; +} + +static struct irq_controller_class eim_irq_class = { + .typename = "EIM", + .handle = eim_handle_irq, + .setup = eim_setup, + .free = eim_free, + .mask = eim_mask, + .unmask = eim_unmask, + .set_type = eim_set_type, + .get_type = eim_get_type, +}; + +static int __init eim_init(void) +{ + struct at32_sm *sm = &system_manager; + unsigned int i; + u32 pattern; + int ret; + + /* + * The EIM is really the same module as SM, so register + * mapping, etc. has been taken care of already. + */ + + /* + * Find out how many interrupt lines that are actually + * implemented in hardware. + */ + sm_writel(sm, EIM_IDR, ~0UL); + sm_writel(sm, EIM_MODE, ~0UL); + pattern = sm_readl(sm, EIM_MODE); + sm->irqc.nr_irqs = fls(pattern); + + ret = -ENOMEM; + sm->action = kmalloc(sizeof(*sm->action) * sm->irqc.nr_irqs, + GFP_KERNEL); + if (!sm->action) + goto out; + + for (i = 0; i < sm->irqc.nr_irqs; i++) + sm->action[i] = &eim_spurious_action; + + spin_lock_init(&sm->lock); + sm->irqc.irq_group = SM_EIM_IRQ(at32_get_irq(sm->adev)); + sm->irqc.class = &eim_irq_class; + + ret = intc_register_controller(&sm->irqc); + if (ret < 0) + goto out_free_actions; + + printk("EIM: External Interrupt Module at 0x%08lx, IRQ group %u\n", + at32_get_iomem_base(sm->adev, 0), sm->irqc.irq_group); + printk("EIM: Handling %u external IRQs, starting with IRQ%u\n", + sm->irqc.nr_irqs, sm->irqc.first_irq); + + return 0; + +out_free_actions: + kfree(sm->action); +out: + return ret; +} +arch_initcall(eim_init); diff -Nur linux-2.6.16.11/arch/avr32/platforms/at32ap/sm.h linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/sm.h --- linux-2.6.16.11/arch/avr32/platforms/at32ap/sm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/platforms/at32ap/sm.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,240 @@ +/* + * Register definitions for SM + * + * System Manager + */ +#ifndef __ASM_AVR32_SM_H__ +#define __ASM_AVR32_SM_H__ + +/* SM register offsets */ +#define SM_PM_MCCTRL 0x0000 +#define SM_PM_CKSEL 0x0004 +#define SM_PM_CPU_MASK 0x0008 +#define SM_PM_AHB_MASK 0x000c +#define SM_PM_APBA_MASK 0x0010 +#define SM_PM_APBB_MASK 0x0014 +#define SM_PM_PLL0 0x0020 +#define SM_PM_PLL1 0x0024 +#define SM_PM_VCTRL 0x0030 +#define SM_PM_VMREF 0x0034 +#define SM_PM_VMV 0x0038 +#define SM_PM_IER 0x0040 +#define SM_PM_IDR 0x0044 +#define SM_PM_IMR 0x0048 +#define SM_PM_ISR 0x004c +#define SM_PM_ICR 0x0050 +#define SM_PM_GCCTRL 0x0060 +#define SM_RTC_CTRL 0x0080 +#define SM_RTC_VAL 0x0084 +#define SM_RTC_TOP 0x0088 +#define SM_RTC_IER 0x0090 +#define SM_RTC_IDR 0x0094 +#define SM_RTC_IMR 0x0098 +#define SM_RTC_ISR 0x009c +#define SM_RTC_ICR 0x00a0 +#define SM_WDT_CTRL 0x00b0 +#define SM_WDT_CLR 0x00b4 +#define SM_WDT_EXT 0x00b8 +#define SM_RC_RCAUSE 0x00c0 +#define SM_EIM_IER 0x0100 +#define SM_EIM_IDR 0x0104 +#define SM_EIM_IMR 0x0108 +#define SM_EIM_ISR 0x010c +#define SM_EIM_ICR 0x0110 +#define SM_EIM_MODE 0x0114 +#define SM_EIM_EDGE 0x0118 +#define SM_EIM_LEVEL 0x011c +#define SM_EIM_TEST 0x0120 +#define SM_EIM_NMIC 0x0124 + +/* Bitfields in PM_MCCTRL */ + +/* Bitfields in PM_CKSEL */ +#define SM_CPUSEL_OFFSET 0 +#define SM_CPUSEL_SIZE 3 +#define SM_CPUDIV_OFFSET 7 +#define SM_CPUDIV_SIZE 1 +#define SM_AHBSEL_OFFSET 8 +#define SM_AHBSEL_SIZE 3 +#define SM_AHBDIV_OFFSET 15 +#define SM_AHBDIV_SIZE 1 +#define SM_APBASEL_OFFSET 16 +#define SM_APBASEL_SIZE 3 +#define SM_APBADIV_OFFSET 23 +#define SM_APBADIV_SIZE 1 +#define SM_APBBSEL_OFFSET 24 +#define SM_APBBSEL_SIZE 3 +#define SM_APBBDIV_OFFSET 31 +#define SM_APBBDIV_SIZE 1 + +/* Bitfields in PM_CPU_MASK */ + +/* Bitfields in PM_AHB_MASK */ + +/* Bitfields in PM_APBA_MASK */ + +/* Bitfields in PM_APBB_MASK */ + +/* Bitfields in PM_PLL0 */ +#define SM_PLLEN_OFFSET 0 +#define SM_PLLEN_SIZE 1 +#define SM_PLLOSC_OFFSET 1 +#define SM_PLLOSC_SIZE 1 +#define SM_PLLOPT_OFFSET 2 +#define SM_PLLOPT_SIZE 3 +#define SM_PLLDIV_OFFSET 8 +#define SM_PLLDIV_SIZE 8 +#define SM_PLLMUL_OFFSET 16 +#define SM_PLLMUL_SIZE 8 +#define SM_PLLCOUNT_OFFSET 24 +#define SM_PLLCOUNT_SIZE 6 +#define SM_PLLTEST_OFFSET 31 +#define SM_PLLTEST_SIZE 1 + +/* Bitfields in PM_PLL1 */ + +/* Bitfields in PM_VCTRL */ +#define SM_VAUTO_OFFSET 0 +#define SM_VAUTO_SIZE 1 +#define SM_PM_VCTRL_VAL_OFFSET 8 +#define SM_PM_VCTRL_VAL_SIZE 7 + +/* Bitfields in PM_VMREF */ +#define SM_REFSEL_OFFSET 0 +#define SM_REFSEL_SIZE 4 + +/* Bitfields in PM_VMV */ +#define SM_PM_VMV_VAL_OFFSET 0 +#define SM_PM_VMV_VAL_SIZE 8 + +/* Bitfields in PM_IER */ + +/* Bitfields in PM_IDR */ + +/* Bitfields in PM_IMR */ + +/* Bitfields in PM_ISR */ + +/* Bitfields in PM_ICR */ +#define SM_LOCK0_OFFSET 0 +#define SM_LOCK0_SIZE 1 +#define SM_LOCK1_OFFSET 1 +#define SM_LOCK1_SIZE 1 +#define SM_WAKE_OFFSET 2 +#define SM_WAKE_SIZE 1 +#define SM_VOK_OFFSET 3 +#define SM_VOK_SIZE 1 +#define SM_VMRDY_OFFSET 4 +#define SM_VMRDY_SIZE 1 +#define SM_CKRDY_OFFSET 5 +#define SM_CKRDY_SIZE 1 + +/* Bitfields in PM_GCCTRL */ +#define SM_OSCSEL_OFFSET 0 +#define SM_OSCSEL_SIZE 1 +#define SM_PLLSEL_OFFSET 1 +#define SM_PLLSEL_SIZE 1 +#define SM_CEN_OFFSET 2 +#define SM_CEN_SIZE 1 +#define SM_CPC_OFFSET 3 +#define SM_CPC_SIZE 1 +#define SM_DIVEN_OFFSET 4 +#define SM_DIVEN_SIZE 1 +#define SM_DIV_OFFSET 8 +#define SM_DIV_SIZE 8 + +/* Bitfields in RTC_CTRL */ +#define SM_PCLR_OFFSET 1 +#define SM_PCLR_SIZE 1 +#define SM_TOPEN_OFFSET 2 +#define SM_TOPEN_SIZE 1 +#define SM_CLKEN_OFFSET 3 +#define SM_CLKEN_SIZE 1 +#define SM_PSEL_OFFSET 8 +#define SM_PSEL_SIZE 16 + +/* Bitfields in RTC_VAL */ +#define SM_RTC_VAL_VAL_OFFSET 0 +#define SM_RTC_VAL_VAL_SIZE 31 + +/* Bitfields in RTC_TOP */ +#define SM_RTC_TOP_VAL_OFFSET 0 +#define SM_RTC_TOP_VAL_SIZE 32 + +/* Bitfields in RTC_IER */ + +/* Bitfields in RTC_IDR */ + +/* Bitfields in RTC_IMR */ + +/* Bitfields in RTC_ISR */ + +/* Bitfields in RTC_ICR */ +#define SM_TOPI_OFFSET 0 +#define SM_TOPI_SIZE 1 + +/* Bitfields in WDT_CTRL */ +#define SM_KEY_OFFSET 24 +#define SM_KEY_SIZE 8 + +/* Bitfields in WDT_CLR */ + +/* Bitfields in WDT_EXT */ + +/* Bitfields in RC_RCAUSE */ +#define SM_POR_OFFSET 0 +#define SM_POR_SIZE 1 +#define SM_BOD_OFFSET 1 +#define SM_BOD_SIZE 1 +#define SM_EXT_OFFSET 2 +#define SM_EXT_SIZE 1 +#define SM_WDT_OFFSET 3 +#define SM_WDT_SIZE 1 +#define SM_NTAE_OFFSET 4 +#define SM_NTAE_SIZE 1 +#define SM_SERP_OFFSET 5 +#define SM_SERP_SIZE 1 + +/* Bitfields in EIM_IER */ + +/* Bitfields in EIM_IDR */ + +/* Bitfields in EIM_IMR */ + +/* Bitfields in EIM_ISR */ + +/* Bitfields in EIM_ICR */ + +/* Bitfields in EIM_MODE */ + +/* Bitfields in EIM_EDGE */ +#define SM_INT0_OFFSET 0 +#define SM_INT0_SIZE 1 +#define SM_INT1_OFFSET 1 +#define SM_INT1_SIZE 1 +#define SM_INT2_OFFSET 2 +#define SM_INT2_SIZE 1 +#define SM_INT3_OFFSET 3 +#define SM_INT3_SIZE 1 + +/* Bitfields in EIM_LEVEL */ + +/* Bitfields in EIM_TEST */ +#define SM_TESTEN_OFFSET 31 +#define SM_TESTEN_SIZE 1 + +/* Bitfields in EIM_NMIC */ +#define SM_EN_OFFSET 0 +#define SM_EN_SIZE 1 + +/* Bit manipulation macros */ +#define SM_BIT(name) (1 << SM_##name##_OFFSET) +#define SM_BF(name,value) (((value) & ((1 << SM_##name##_SIZE) - 1)) << SM_##name##_OFFSET) +#define SM_BFEXT(name,value) (((value) >> SM_##name##_OFFSET) & ((1 << SM_##name##_SIZE) - 1)) +#define SM_BFINS(name,value,old) (((old) & ~(((1 << SM_##name##_SIZE) - 1) << SM_##name##_OFFSET)) | SM_BF(name,value)) + +/* Register access macros */ +#define sm_readl(port,reg) readl((port)->regs + SM_##reg) +#define sm_writel(port,reg,value) writel((value), (port)->regs + SM_##reg) + +#endif /* __ASM_AVR32_SM_H__ */ diff -Nur linux-2.6.16.11/arch/avr32/usr/initrd_image.S linux-2.6.16.11-avr32-20060626/arch/avr32/usr/initrd_image.S --- linux-2.6.16.11/arch/avr32/usr/initrd_image.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/usr/initrd_image.S 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,4 @@ +/* Include the initrd image as a binary file */ + + .section .initrd,"a",@progbits + .incbin "arch/avr32/usr/initrd_image.romfs.gz" diff -Nur linux-2.6.16.11/arch/avr32/usr/Makefile linux-2.6.16.11-avr32-20060626/arch/avr32/usr/Makefile --- linux-2.6.16.11/arch/avr32/usr/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/arch/avr32/usr/Makefile 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,15 @@ + +obj-$(CONFIG_BLK_DEV_INITRD) := initrd_image.o + +clean-files += initrd_image.cpio.gz initrd_image.romfs.gz + +# initrd_image.o contains the initrd_image.romfs image. +# The image is included using .incbin, a dependency which is not +# tracked automatically. +$(obj)/initrd_image.o: $(obj)/initrd_image.romfs.gz FORCE + +$(obj)/initrd_image.cpio.gz: $(obj)/initrd_image.cpio FORCE + $(call if_changed,gzip) + +$(obj)/initrd_image.romfs.gz: $(obj)/initrd_image.romfs FORCE + $(call if_changed,gzip) diff -Nur linux-2.6.16.11/Documentation/serial/driver linux-2.6.16.11-avr32-20060626/Documentation/serial/driver --- linux-2.6.16.11/Documentation/serial/driver 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/Documentation/serial/driver 2006-06-26 11:33:51.000000000 +0200 @@ -172,6 +172,17 @@ Locking: port_sem taken. Interrupts: caller dependent. + flush_buffer(port) + Flush any write buffers, reset any DMA state and stop any + ongoing DMA transfers. + + This will be called whenever the port->info->xmit circular + buffer is cleared. + + Locking: port->lock taken. + Interrupts: locally disabled. + This call must not sleep + set_termios(port,termios,oldtermios) Change the port parameters, including word length, parity, stop bits. Update read_status_mask and ignore_status_mask to indicate diff -Nur linux-2.6.16.11/drivers/char/mem.c linux-2.6.16.11-avr32-20060626/drivers/char/mem.c --- linux-2.6.16.11/drivers/char/mem.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/char/mem.c 2006-06-26 11:33:53.000000000 +0200 @@ -534,7 +534,7 @@ return virtr + wrote; } -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if defined(CONFIG_ISA) || (!defined(__mc68000__) && !defined(__avr32__)) static ssize_t read_port(struct file * file, char __user * buf, size_t count, loff_t *ppos) { @@ -795,7 +795,7 @@ .write = write_null, }; -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if defined(CONFIG_ISA) || (!defined(__mc68000__) && !defined(__avr32__)) static struct file_operations port_fops = { .llseek = memory_lseek, .read = read_port, @@ -865,7 +865,7 @@ case 3: filp->f_op = &null_fops; break; -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if defined(CONFIG_ISA) || (!defined(__mc68000__) && !defined(__avr32__)) case 4: filp->f_op = &port_fops; break; @@ -912,7 +912,7 @@ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, {3, "null", S_IRUGO | S_IWUGO, &null_fops}, -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if defined(CONFIG_ISA) || (!defined(__mc68000__) && !defined(__avr32__)) {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, #endif {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, diff -Nur linux-2.6.16.11/drivers/mmc/atmel-mci.c linux-2.6.16.11-avr32-20060626/drivers/mmc/atmel-mci.c --- linux-2.6.16.11/drivers/mmc/atmel-mci.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/mmc/atmel-mci.c 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,606 @@ +/* + * Atmel MultiMedia Card Interface driver + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#undef TRACK_STATE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "atmel-mci.h" + +#define DRIVER_NAME "mmci" + +static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data, + u32 flags); + +/* For debugging purposes. Optimized away when TRACK_STATE is not set */ +enum { + STATE_IDLE = 0, + STATE_CMD, + STATE_ERR, + STATE_READ_SINGLE, + STATE_READ_MULTI, + STATE_READ_LAST, + STATE_WRITE_SINGLE, + STATE_WRITE_MULTI, + STATE_WRITE_LAST, +}; + +#ifdef TRACK_STATE +static struct { + int state; + int blocknum; + int current_sg; + int num_sg; + int sg_len; + int bytes_xfered; +} mci_state; +#define set_state(x) do { mci_state.state = (x); } while(0) +#define set_nextblock(x) do { mci_state.blocknum = (x); } while(0) +#define set_current_sg(x) do { mci_state.current_sg = (x); } while(0) +#define set_num_sg(x) do { mci_state.num_sg = (x); } while(0) +#define set_sg_len(x) do { mci_state.sg_len = (x); } while(0) +#define set_bytes_xfered(x) do { mci_state.bytes_xfered = (x); } while(0) +#define check_idle() BUG_ON(mci_state.state != STATE_IDLE) +#else +#define set_state(x) do { } while(0) +#define set_nextblock(x) do { } while(0) +#define set_current_sg(x) do { } while(0) +#define set_num_sg(x) do { } while(0) +#define set_sg_len(x) do { } while(0) +#define set_bytes_xfered(x) do { } while(0) +#define check_idle() do { } while(0) +#define trace_byteswap(f,t,l) do { } while(0) +#define trace_cache(a) do { } while(0) +#endif + +/* Those printks take an awful lot of time... */ +#ifndef DEBUG +static unsigned int fmax = 2000000; +#else +static unsigned int fmax = 50000; +#endif + +static inline void mci_writel(struct atmci_host *port, u32 offset, u32 value) +{ + writel(value, port->mmio + offset); +} + +static inline u32 mci_readl(struct atmci_host *port, u32 offset) +{ + u32 value; + value = readl(port->mmio + offset); + return value; +} + +static inline unsigned int ns_to_clocks(struct atmci_host *host, + unsigned int ns) +{ + return (ns * (host->bus_hz / 1000000) + 999) / 1000; +} + +static void atmci_set_timeout(struct atmci_host *host, + struct mmc_data *data) +{ + static unsigned dtomul_to_shift[] = { + 0, 4, 7, 8, 10, 12, 16, 20 + }; + unsigned timeout; + unsigned dtocyc, dtomul; + + timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks; + + for (dtomul = 0; dtomul < 8; dtomul++) { + unsigned shift = dtomul_to_shift[dtomul]; + dtocyc = (timeout + (1 << shift) - 1) >> shift; + if (dtocyc < 15) + break; + } + + if (dtomul >= 8) { + dtomul = 7; + dtocyc = 15; + } + + pr_debug("%s: setting timeout to %u cycles\n", + mmc_hostname(host->mmc), + dtocyc << dtomul_to_shift[dtomul]); + mci_writel(host, MCI_DTOR, (dtomul << 4) | dtocyc); +} + +static void atmci_set_blklen(struct atmci_host *host, + unsigned blksz_bits) +{ + unsigned blklen = 1 << blksz_bits; + u32 value; + + pr_debug("%s: setting blklen to %u\n", + mmc_hostname(host->mmc), blklen); + + host->dma.req.block_size = 1 << blksz_bits; + + value = mci_readl(host, MCI_MR); + value &= 0xffff; + value |= blklen << 16; + mci_writel(host, MCI_MR, value); +} + +static void atmci_start_command(struct mmc_host *mmc, + struct mmc_command *cmd, + u32 cmdflags) +{ + struct atmci_host *host = mmc_priv(mmc); + + WARN_ON(host->cmd); + + /* Don't mess with the opcode */ + BUG_ON(cmdflags & 0x3f); + cmdflags &= ~0x3fUL; + + cmdflags |= cmd->opcode; + + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) + cmdflags |= MCI_CMDR_RSPTYP_136BIT; + else + cmdflags |= MCI_CMDR_RSPTYP_48BIT; + } + + /* + * This should really be MAXLAT_5 for CMD2 and ACMD41, but + * it's too difficult to determine whether this is an ACMD or + * not... + */ + cmdflags |= MCI_CMDR_MAXLAT_64; + + if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) + cmdflags |= MCI_CMDR_OPDCMD; + + pr_debug("%s: cmd: op %02x arg %08x flags %08x, cmdflags %08lx\n", + mmc_hostname(mmc), cmd->opcode, cmd->arg, cmd->flags, + (unsigned long)cmdflags); + + host->cmd = cmd; + + mci_writel(host, MCI_ARGR, cmd->arg); + mci_writel(host, MCI_CMDR, cmdflags); + mci_writel(host, MCI_IER, MCI_SR_CMDRDY); +} + +static void atmci_start_read(struct mmc_host *mmc, struct mmc_data *data) +{ + struct atmci_host *host = mmc_priv(mmc); + + host->dma.req.nr_sg = dma_map_sg(&host->adev->dev, data->sg, + data->sg_len, DMA_FROM_DEVICE); + host->dma.req.sg = data->sg; + host->dma.req.periph_id = host->dma.rx_periph_id; + host->dma.req.direction = DMA_DIR_PERIPH_TO_MEM; + host->dma.req.data_reg = host->mapbase + MCI_RDR; + host->dma.blocks_left = data->blocks; + + dma_prepare_request_sg(host->dma.req.req.dmac, &host->dma.req); + mci_writel(host, MCI_IER, MCI_SR_BLKE); +} + +static void atmci_start_write(struct mmc_host *mmc, struct mmc_data *data) +{ + struct atmci_host *host = mmc_priv(mmc); + + host->dma.req.nr_sg = dma_map_sg(&host->adev->dev, data->sg, + data->sg_len, DMA_TO_DEVICE); + host->dma.req.sg = data->sg; + host->dma.req.periph_id = host->dma.tx_periph_id; + host->dma.req.direction = DMA_DIR_MEM_TO_PERIPH; + host->dma.req.data_reg = host->mapbase + MCI_TDR; + host->dma.blocks_left = data->blocks; + + dma_prepare_request_sg(host->dma.req.req.dmac, &host->dma.req); + mci_writel(host, MCI_IER, MCI_SR_BLKE); +} + +static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct atmci_host *host = mmc_priv(mmc); + u32 cmd_flags = 0; + + check_idle(); + + BUG_ON(host->mrq != NULL); + + host->mrq = mrq; + host->sent_stop = 0; + + if (mrq->data) { + struct mmc_data *data = mrq->data; + + host->data = data; + + atmci_set_timeout(host, data); + atmci_set_blklen(host, data->blksz_bits); + + cmd_flags |= MCI_CMDR_TRCMD_START; + if (data->flags & MMC_DATA_STREAM) + cmd_flags |= MCI_CMDR_TRTYP_STREAM; + else if (data->blocks > 1) + cmd_flags |= MCI_CMDR_TRTYP_MULTBLK; + else + cmd_flags |= MCI_CMDR_TRTYP_BLOCK; + + if (data->flags & MMC_DATA_READ) { + cmd_flags |= MCI_CMDR_TRDIR_READ; + atmci_start_read(mmc, data); + } else { + cmd_flags |= MCI_CMDR_TRDIR_WRITE; + atmci_start_write(mmc, data); + } + } else { + set_state(STATE_CMD); + } + + atmci_start_command(mmc, mrq->cmd, cmd_flags); + + if (mrq->data) + dma_start_request(host->dma.req.req.dmac, + host->dma.req.req.channel); +} + +static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct atmci_host *host = mmc_priv(mmc); + + if (ios->clock) { + u32 clkdiv; + + clkdiv = host->bus_hz / (2 * ios->clock) - 1; + if (clkdiv > 255) + clkdiv = 255; + mci_writel(host, MCI_MR, clkdiv); + } + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + mci_writel(host, MCI_SDCR, 0); + break; + case MMC_BUS_WIDTH_4: + mci_writel(host, MCI_SDCR, MCI_SDCR_SDCBUS); + break; + } + + switch (ios->power_mode) { + case MMC_POWER_OFF: + mci_writel(host, MCI_CR, MCI_CR_MCIDIS); + break; + case MMC_POWER_UP: + mci_writel(host, MCI_CR, MCI_CR_SWRST); + break; + case MMC_POWER_ON: + mci_writel(host, MCI_CR, MCI_CR_MCIEN); + break; + } +} + +static struct mmc_host_ops atmci_ops = { + .request = atmci_request, + .set_ios = atmci_set_ios, +}; + +static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct atmci_host *host = mmc_priv(mmc); + + WARN_ON(host->cmd); + + mci_writel(host, PDC_PTCR, PDC_PTCR_TXTDIS); + + if (mrq->data) { + if (mrq->data->error != MMC_ERR_NONE) + pr_debug("%s: Data transmission failed: Error %d\n", + mmc_hostname(mmc), mrq->data->error); + } + + host->mrq = NULL; + + set_state(STATE_IDLE); + + /* + * Need to drop the host lock here; mmc_request_done may call + * back into the driver... + */ + spin_unlock(&mmc->lock); + mmc_request_done(mmc, mrq); + spin_lock(&mmc->lock); +} + +static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data, + u32 flags) +{ + struct atmci_host *host = mmc_priv(mmc); + /* pr_debug("sending stop cmd\n"); */ + + BUG_ON(host->sent_stop); + + flags |= MCI_CMDR_TRCMD_STOP; + if (data->flags & MMC_DATA_WRITE) + flags |= MCI_CMDR_TRDIR_WRITE; + else + flags |= MCI_CMDR_TRDIR_READ; + if (data->flags & MMC_DATA_STREAM) + flags |= MCI_CMDR_TRTYP_STREAM; + else + flags |= MCI_CMDR_TRTYP_MULTBLK; + + atmci_start_command(mmc, data->stop, flags); + host->sent_stop = 1; +} + +static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status) +{ + struct atmci_host *host = mmc_priv(mmc); + struct mmc_command *cmd = host->cmd; + + host->cmd = NULL; + cmd->resp[0] = mci_readl(host, MCI_RSPR); + cmd->resp[1] = mci_readl(host, MCI_RSPR); + cmd->resp[2] = mci_readl(host, MCI_RSPR); + cmd->resp[3] = mci_readl(host, MCI_RSPR); + + cmd->error = MMC_ERR_NONE; + if (status & MCI_SR_RTOE) + cmd->error = MMC_ERR_TIMEOUT; + else if (status & MCI_SR_RCRCE && cmd->flags & MMC_RSP_CRC) + cmd->error = MMC_ERR_BADCRC; + + mci_writel(host, MCI_IDR, MCI_SR_CMDRDY); + + if (cmd->error != MMC_ERR_NONE) + printk(KERN_DEBUG "%s: Command %02u failed: Error %d\n", + mmc_hostname(mmc), cmd->opcode, cmd->error); + else + pr_debug("%s: Command %02u completed successfully (%s)\n", + mmc_hostname(mmc), cmd->opcode, + cmd->data ? "data" : "no data"); + + host->cmd = NULL; + + if (!cmd->data || cmd->error != MMC_ERR_NONE) + atmci_request_end(mmc, cmd->mrq); + + if (cmd->data && cmd->data->blocks == 1 && cmd->data->stop) + send_stop_cmd(mmc, cmd->data, MCI_CMDR_SPCMD_SYNC); +} + +static void atmci_xfer_complete(struct dma_request *_req) +{ + struct dma_request_sg *req = to_dma_request_sg(_req); + struct atmci_dma_info *dma; + struct atmci_host *host; + + dma = container_of(req, struct atmci_dma_info, req); + host = container_of(dma, struct atmci_host, dma); + + dma_unmap_sg(&host->adev->dev, host->data->sg, dma->req.nr_sg, + ((host->data->flags & MMC_DATA_WRITE) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); +} + +static void atmci_dma_error(struct dma_request *req) +{ + BUG(); +} + +static void atmci_blke_interrupt(struct mmc_host *mmc, u32 status, u32 pending) +{ + struct atmci_host *host = mmc_priv(mmc); + struct mmc_data *data = host->data; + + if (status & (MCI_SR_DCRCE | MCI_SR_DTOE | MCI_SR_OVRE | MCI_SR_UNRE)) { + set_state(STATE_ERR); + if (status & MCI_SR_DCRCE) + data->error = MMC_ERR_BADCRC; + else if (status & MCI_SR_DTOE) + data->error = MMC_ERR_TIMEOUT; + else if (status & MCI_SR_OVRE) { + pr_debug("%s: DMA overrun\n", mmc_hostname(mmc)); + data->error = MMC_ERR_FIFO; + } else if (status & MCI_SR_UNRE) { + pr_debug("%s: DMA underrun\n", mmc_hostname(mmc)); + data->error = MMC_ERR_FIFO; + } + } + + data->bytes_xfered += 1 << data->blksz_bits; + if (data->bytes_xfered == ((data->blocks - 1) << data->blksz_bits) + || data->error) + if (data->stop && !host->sent_stop) + send_stop_cmd(mmc, data, MCI_CMDR_SPCMD_SYNC); + pr_debug("mmci: BLKE interrupt: %d blocks left\n", host->dma.blocks_left); + + if ((data->bytes_xfered == (data->blocks << data->blksz_bits) + || data->error) && !data->stop) + atmci_request_end(mmc, data->mrq); +} + +static irqreturn_t atmci_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mmc_host *mmc = dev_id; + struct atmci_host *host = mmc_priv(mmc); + u32 status, mask, pending; + + spin_lock(&mmc->lock); + + status = mci_readl(host, MCI_SR); + mask = mci_readl(host, MCI_IMR); + pending = status & mask; + + do { + pr_debug("mci: interrupt, status = %08x, mask = %08x\n", + status, mask); + + if (pending & MCI_SR_BLKE) + atmci_blke_interrupt(mmc, status, pending); + if (pending & MCI_SR_CMDRDY) + atmci_cmd_interrupt(mmc, status); + + status = mci_readl(host, MCI_SR); + mask = mci_readl(host, MCI_IMR); + pending = status & mask; + } while (pending); + + spin_unlock(&mmc->lock); + + return IRQ_HANDLED; +} + +static int __devinit atmci_probe(struct at32_device *adev) +{ + struct atmci_host *host; + struct mmc_host *mmc; + int ret; + + ret = at32_enable_device(adev); + if (ret) { + dev_err(&adev->dev, "failed to enable device\n"); + goto out; + } + + mmc = mmc_alloc_host(sizeof(struct atmci_host), &adev->dev); + if (!mmc) + goto out_disable_dev; + + host = mmc_priv(mmc); + host->adev = adev; + host->mmc = mmc; + host->mmio = at32_map_iomem(adev, 0); + host->bus_hz = at32_get_sclk_hz(adev, 0); + host->mapbase = at32_get_iomem_base(adev, 0); + + mmc->ops = &atmci_ops; + mmc->f_min = (host->bus_hz + 511) / 512; + mmc->f_max = min((unsigned int)(host->bus_hz / 2), fmax); + mmc->ocr_avail = 0x00100000; + + if (!host->mmio) { + ret = -ENOMEM; + goto out_free_host; + } + + ret = request_irq(at32_get_irq(adev), atmci_interrupt, + 0, "mmci", mmc); + if (ret) + goto out_unmap; + + /* TODO: Get this information from the at32 device */ + ret = -ENOMEM; + host->dma.req.req.dmac = find_dma_controller(0); + if (!host->dma.req.req.dmac) { + printk(KERN_ERR + "mmci: No DMA controller available, aborting\n"); + goto out_free_irq; + } + ret = dma_alloc_channel(host->dma.req.req.dmac); + if (ret < 0) { + printk(KERN_ERR + "mmci: Unable to allocate DMA channel, aborting\n"); + goto out_free_irq; + } + host->dma.req.req.channel = ret; + host->dma.req.width = DMA_WIDTH_32BIT; + host->dma.req.req.xfer_complete = atmci_xfer_complete; + host->dma.req.req.block_complete = NULL; // atmci_block_complete; + host->dma.req.req.error = atmci_dma_error; + host->dma.rx_periph_id = 0; + host->dma.tx_periph_id = 1; + + mci_writel(host, MCI_CR, MCI_CR_SWRST); + mci_writel(host, MCI_IDR, ~0UL); + mci_writel(host, MCI_CR, MCI_CR_MCIEN); + + at32_set_drvdata(adev, host); + + mmc_add_host(mmc); + + printk(KERN_INFO "%s: Atmel MCI controller at 0x%08lx irq %d\n", + mmc_hostname(mmc), at32_get_iomem_base(adev, 0), + at32_get_irq(adev)); + + return 0; + +out_free_irq: + free_irq(at32_get_irq(adev), mmc); +out_unmap: + iounmap(host->mmio); +out_free_host: + mmc_free_host(mmc); +out_disable_dev: + at32_disable_device(adev); +out: + return ret; +} + +static int __devexit atmci_remove(struct at32_device *adev) +{ + struct atmci_host *host = at32_get_drvdata(adev); + + at32_set_drvdata(adev, NULL); + + if (host) { + mmc_remove_host(host->mmc); + + mci_writel(host, MCI_IDR, ~0UL); + mci_writel(host, MCI_CR, MCI_CR_MCIDIS); + mci_readl(host, MCI_SR); + + free_irq(at32_get_irq(adev), host); + iounmap(host->mmio); + + at32_disable_device(adev); + + mmc_free_host(host->mmc); + } + return 0; +} + +static struct at32_driver atmci_driver = { + .probe = atmci_probe, + .remove = __devexit_p(atmci_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init atmci_init(void) +{ + return at32_driver_register(&atmci_driver); +} + +static void __exit atmci_exit(void) +{ + at32_driver_unregister(&atmci_driver); +} + +module_init(atmci_init); +module_exit(atmci_exit); + +MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.16.11/drivers/mmc/atmel-mci.h linux-2.6.16.11-avr32-20060626/drivers/mmc/atmel-mci.h --- linux-2.6.16.11/drivers/mmc/atmel-mci.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/mmc/atmel-mci.h 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,113 @@ +/* + * Atmel MultiMedia Card Interface driver + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ATMEL_MCI_H +#define __ATMEL_MCI_H + +#include + +/* Atmel MultiMedia Card Interface (MCI) registers */ +#define MCI_CR 0x00 +#define MCI_MR 0x04 +#define MCI_DTOR 0x08 +#define MCI_SDCR 0x0c +#define MCI_ARGR 0x10 +#define MCI_CMDR 0x14 +#define MCI_RSPR MCI_RSPR0 +#define MCI_RSPR0 0x20 +#define MCI_RSPR1 0x24 +#define MCI_RSPR2 0x28 +#define MCI_RSPR3 0x2c +#define MCI_RDR 0x30 +#define MCI_TDR 0x34 +#define MCI_SR 0x40 +#define MCI_IER 0x44 +#define MCI_IDR 0x48 +#define MCI_IMR 0x4c + +/* MCI Control Register */ +#define MCI_CR_MCIEN (1 << 0) +#define MCI_CR_MCIDIS (1 << 1) +#define MCI_CR_PWSEN (1 << 2) +#define MCI_CR_PWSDIS (1 << 3) +#define MCI_CR_SWRST (1 << 7) + +/* MCI Mode Register */ +#define MCI_MR_PDCPADV (1 << 14) +#define MCI_MR_PDCMODE (1 << 15) + +/* MCI SD Card Register */ +#define MCI_SDCR_SDCBUS (1 << 7) + +/* MCI Command Register */ +#define MCI_CMDR_RSPTYP_NONE (0 << 6) +#define MCI_CMDR_RSPTYP_48BIT (1 << 6) +#define MCI_CMDR_RSPTYP_136BIT (2 << 6) +#define MCI_CMDR_RSPTYP_MASK (3 << 6) +#define MCI_CMDR_SPCMD_NONE (0 << 8) +#define MCI_CMDR_SPCMD_INIT (1 << 8) +#define MCI_CMDR_SPCMD_SYNC (2 << 8) +#define MCI_CMDR_SPCMD_INTCMD (4 << 8) +#define MCI_CMDR_SPCMD_INTRESP (5 << 8) +#define MCI_CMDR_OPDCMD (1 << 11) +#define MCI_CMDR_MAXLAT_5 (0 << 12) +#define MCI_CMDR_MAXLAT_64 (1 << 12) +#define MCI_CMDR_TRCMD_NONE (0 << 16) +#define MCI_CMDR_TRCMD_START (1 << 16) +#define MCI_CMDR_TRCMD_STOP (2 << 16) +#define MCI_CMDR_TRDIR_WRITE (0 << 18) +#define MCI_CMDR_TRDIR_READ (1 << 18) +#define MCI_CMDR_TRTYP_BLOCK (0 << 19) +#define MCI_CMDR_TRTYP_MULTBLK (1 << 19) +#define MCI_CMDR_TRTYP_STREAM (2 << 19) + +/* MCI Status Register + Interrupt Enable/Disable/Mask */ +#define MCI_SR_CMDRDY (1 << 0) +#define MCI_SR_RXRDY (1 << 1) +#define MCI_SR_TXRDY (1 << 2) +#define MCI_SR_BLKE (1 << 3) +#define MCI_SR_DTIP (1 << 4) +#define MCI_SR_NOTBUSY (1 << 5) +#define MCI_SR_ENDRX (1 << 6) +#define MCI_SR_ENDTX (1 << 7) +#define MCI_SR_RXBUFF (1 << 14) +#define MCI_SR_TXBUFE (1 << 15) +#define MCI_SR_RINDE (1 << 16) +#define MCI_SR_RDIRE (1 << 17) +#define MCI_SR_RCRCE (1 << 18) +#define MCI_SR_RENDE (1 << 19) +#define MCI_SR_RTOE (1 << 20) +#define MCI_SR_DCRCE (1 << 21) +#define MCI_SR_DTOE (1 << 22) +#define MCI_SR_OVRE (1 << 30) +#define MCI_SR_UNRE (1 << 31) + +#define MCI_SR_ERROR 0x007b0000 + +struct atmci_dma_info { + struct dma_request_sg req; + unsigned short rx_periph_id; + unsigned short tx_periph_id; + int blocks_left; +}; + +struct atmci_host { + struct mmc_host *mmc; + void __iomem *mmio; + struct atmci_dma_info dma; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + int sent_stop; + unsigned long long bus_hz; + unsigned long mapbase; + struct at32_device *adev; +}; + +#endif /* __ATMEL_MCI_H */ diff -Nur linux-2.6.16.11/drivers/mmc/Kconfig linux-2.6.16.11-avr32-20060626/drivers/mmc/Kconfig --- linux-2.6.16.11/drivers/mmc/Kconfig 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/mmc/Kconfig 2006-06-26 11:33:53.000000000 +0200 @@ -49,6 +49,16 @@ If unsure, say N. +config MMC_ATMELMCI + tristate "Atmel Multimedia Card Interface support" + depends on AVR32 && MMC + help + This selects the Atmel Multimedia Card Interface. If you have + a AT91 (ARM) or AT32 (AVR32) platform with a Multimedia Card + slot, say Y or M here. + + If unsure, say N. + config MMC_WBSD tristate "Winbond W83L51xD SD/MMC Card Interface support" depends on MMC && ISA_DMA_API diff -Nur linux-2.6.16.11/drivers/mmc/Makefile linux-2.6.16.11-avr32-20060626/drivers/mmc/Makefile --- linux-2.6.16.11/drivers/mmc/Makefile 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/mmc/Makefile 2006-06-26 11:33:53.000000000 +0200 @@ -17,6 +17,7 @@ # obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o +obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o diff -Nur linux-2.6.16.11/drivers/net/Kconfig linux-2.6.16.11-avr32-20060626/drivers/net/Kconfig --- linux-2.6.16.11/drivers/net/Kconfig 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/net/Kconfig 2006-06-26 11:33:53.000000000 +0200 @@ -185,6 +185,17 @@ or internal device. It is safe to say Y or M here even if your ethernet card lack MII. +config MACB + tristate "Atmel/Cadence MACB support" + depends on NET_ETHERNET && AVR32 + select MII + help + The Atmel MACB ethernet interface is found on many AT32 and AT91 + parts. Say Y to include support for the MACB chip. + + To compile this driver as a module, choose M here: the module + will be called macb. + source "drivers/net/arm/Kconfig" config MACE diff -Nur linux-2.6.16.11/drivers/net/macb.c linux-2.6.16.11-avr32-20060626/drivers/net/macb.c --- linux-2.6.16.11/drivers/net/macb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/net/macb.c 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,1144 @@ +/* + * Cadence/Atmel MACB Ethernet Controller driver + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "macb.h" + +#define to_net_dev(class) container_of(class, struct net_device, class_dev) + +/* My laptop's address + 1 */ +static char default_macaddr[] = { 0x00, 0x03, 0x93, 0xb2, 0xc3, 0x33 }; + +#define RX_BUFFER_SIZE 128 +#define RX_RING_SIZE 512 +#define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE) + +/* Make the IP header word-aligned (the ethernet header is 14 bytes) */ +#define RX_OFFSET 2 + +#define TX_RING_SIZE 128 +#define DEF_TX_RING_PENDING (TX_RING_SIZE - 1) +#define TX_RING_BYTES (sizeof(struct dma_desc) * TX_RING_SIZE) + +#define TX_RING_GAP(bp) \ + (TX_RING_SIZE - (bp)->tx_pending) +#define TX_BUFFS_AVAIL(bp) \ + (((bp)->tx_tail <= (bp)->tx_head) ? \ + (bp)->tx_tail + (bp)->tx_pending - (bp)->tx_head : \ + (bp)->tx_tail - (bp)->tx_head - TX_RING_GAP(bp)) +#define NEXT_TX(n) (((n) + 1) & (TX_RING_SIZE - 1)) + +#define NEXT_RX(n) (((n) + 1) & (RX_RING_SIZE - 1)) + +/* minimum number of free TX descriptors before waking up TX process */ +#define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4) + +static void __macb_set_hwaddr(struct macb *bp) +{ + u32 bottom; + u16 top; + + bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr)); + macb_writel(bp, MACB_ADDR1_BOT, bottom); + top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4))); + macb_writel(bp, MACB_ADDR1_TOP, top); +} + +static void macb_enable_mdio(struct macb *bp) +{ + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&bp->lock, flags); + reg = macb_readl(bp, MACB_NETCTRL); + reg |= MACB_NCTL_MDIOEN; + macb_writel(bp, MACB_NETCTRL, reg); + macb_writel(bp, MACB_INTENA, MACB_ISR_MDIO); + spin_unlock_irqrestore(&bp->lock, flags); +} + +static void macb_disable_mdio(struct macb *bp) +{ + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&bp->lock, flags); + reg = macb_readl(bp, MACB_NETCTRL); + reg &= ~MACB_NCTL_MDIOEN; + macb_writel(bp, MACB_NETCTRL, reg); + macb_writel(bp, MACB_INTDIS, MACB_ISR_MDIO); + spin_unlock_irqrestore(&bp->lock, flags); +} + +static int macb_mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct macb *bp = netdev_priv(dev); + u32 reg; + int value; + + down(&bp->mdio_sem); + + macb_enable_mdio(bp); + reg = 0x60020000; + reg |= (phy_id & 0x1f) << 23; + reg |= (location & 0x1f) << 18; + macb_writel(bp, MACB_MDIO, reg); + + wait_for_completion(&bp->mdio_complete); + + value = macb_readl(bp, MACB_MDIO) & 0xffff; + macb_disable_mdio(bp); + up(&bp->mdio_sem); + + return value; +} + +static void macb_mdio_write(struct net_device *dev, int phy_id, + int location, int val) +{ + struct macb *bp = netdev_priv(dev); + u32 reg; + + dev_dbg(&bp->adev->dev, "mdio_write %02x:%02x <- %04x\n", + phy_id, location, val); + + down(&bp->mdio_sem); + macb_enable_mdio(bp); + + reg = 0x50020000; + reg |= (phy_id & 0x1f) << 23; + reg |= (location & 0x1f) << 18; + reg |= val & 0xffff; + macb_writel(bp, MACB_MDIO, reg); + + wait_for_completion(&bp->mdio_complete); + + macb_disable_mdio(bp); + up(&bp->mdio_sem); +} + +static void macb_set_media(struct macb *bp, int media) +{ + u32 reg; + + spin_lock_irq(&bp->lock); + reg = macb_readl(bp, MACB_NETCFG); + reg &= ~(MACB_NCFG_100M | MACB_NCFG_FDPL); + if (media & (ADVERTISE_100HALF | ADVERTISE_100FULL)) + reg |= MACB_NCFG_100M; + if (media & ADVERTISE_FULL) + reg |= MACB_NCFG_FDPL; + macb_writel(bp, MACB_NETCFG, reg); + spin_unlock_irq(&bp->lock); +} + +static void macb_check_media(struct macb *bp, int ok_to_print, int init_media) +{ + struct mii_if_info *mii = &bp->mii; + unsigned int old_carrier, new_carrier; + int advertise, lpa, media, duplex; + + /* if forced media, go no further */ + if (mii->force_media) + return; + + /* check current and old link status */ + old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0; + new_carrier = (unsigned int) mii_link_ok(mii); + + /* if carrier state did not change, assume nothing else did */ + if (!init_media && old_carrier == new_carrier) + return; + + /* no carrier, nothing much to do */ + if (!new_carrier) { + netif_carrier_off(mii->dev); + printk(KERN_INFO "%s: link down\n", mii->dev->name); + return; + } + + /* + * we have carrier, see who's on the other end + */ + netif_carrier_on(mii->dev); + + /* get MII advertise and LPA values */ + if (!init_media && mii->advertising) + advertise = mii->advertising; + else { + advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE); + mii->advertising = advertise; + } + lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA); + + /* figure out media and duplex from advertise and LPA values */ + media = mii_nway_result(lpa & advertise); + duplex = (media & ADVERTISE_FULL) ? 1 : 0; + + if (ok_to_print) + printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n", + mii->dev->name, + media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? "100" : "10", + duplex ? "full" : "half", lpa); + + mii->full_duplex = duplex; + + /* Let the MAC know about the new link state */ + macb_set_media(bp, media); +} + +static void macb_update_stats(struct macb *bp) +{ + regoff_t reg = MACB_COUNT_RXPAUSE; + u32 *p = &bp->hw_stats.rx_pause_frames; + u32 *end = &bp->hw_stats.tx_pause_frames + 1; + + BUG_ON((unsigned long)(end - p - 1) + != (MACB_COUNT_TXPAUSE.off - MACB_COUNT_RXPAUSE.off) / 4); + + for(; p < end; p++, reg = NEXT_REG(reg)) + *p += macb_readl(bp, reg); +} + +static void macb_periodic_task(void *arg) +{ + struct macb *bp = arg; + + macb_update_stats(bp); + macb_check_media(bp, 1, 0); + + schedule_delayed_work(&bp->periodic_task, HZ); +} + +static void macb_tx(struct macb *bp) +{ + unsigned int tail; + unsigned int head; + u32 status; + + status = macb_readl(bp, MACB_TXSTAT); + macb_writel(bp, MACB_TXSTAT, status); + + dev_dbg(&bp->adev->dev, "macb_tx status = %02lx\n", + (unsigned long)status); + + if (status & MACB_TXSTAT_UNR) { + printk(KERN_ERR "%s: TX underrun, resetting buffers\n", + bp->dev->name); + bp->tx_head = bp->tx_tail = 0; + } + + if (!(status & MACB_TXSTAT_COMPLETE)) { + dev_warn(&bp->adev->dev, + "No TX buffers complete, status = %02lx\n", + (unsigned long)status); + return; + } + + head = bp->tx_head; + for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { + struct ring_info *rp = &bp->tx_skb[tail]; + struct sk_buff *skb = rp->skb; + u32 bufstat; + + BUG_ON(skb == NULL); + + rmb(); + bufstat = bp->tx_ring[tail].ctrl; + + if (!(bufstat & TXBUF_USED)) + break; + + dev_dbg(&bp->adev->dev, "skb %u (data %p) TX complete\n", + tail, skb->data); + dma_unmap_single(&bp->adev->dev, rp->mapping, skb->len, + DMA_TO_DEVICE); + bp->stats.tx_packets++; + bp->stats.tx_bytes += skb->len; + rp->skb = NULL; + dev_kfree_skb_irq(skb); + } + + bp->tx_tail = tail; + if (netif_queue_stopped(bp->dev) && + TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH) + netif_wake_queue(bp->dev); +} + +static int macb_rx_frame(struct macb *bp, unsigned int first_frag, + unsigned int last_frag) +{ + unsigned int len; + unsigned int frag; + unsigned int offset = 0; + struct sk_buff *skb; + + len = bp->rx_ring[last_frag].ctrl & RXBUF_FRMLEN_MASK; + + dev_dbg(&bp->adev->dev, "macb_rx_frame frags %u - %u (len %u)\n", + first_frag, last_frag, len); + + skb = dev_alloc_skb(len + RX_OFFSET); + if (!skb) { + bp->stats.rx_dropped++; + for (frag = first_frag; ; frag = NEXT_RX(frag)) { + bp->rx_ring[frag].addr &= ~RXADDR_USED; + if (frag == last_frag) + break; + } + wmb(); + return 1; + } + + skb_reserve(skb, RX_OFFSET); + skb->dev = bp->dev; + skb->ip_summed = CHECKSUM_NONE; + skb_put(skb, len); + + for (frag = first_frag; ; frag = NEXT_RX(frag)) { + unsigned int frag_len = RX_BUFFER_SIZE; + + if (offset + frag_len > len) { + BUG_ON(frag != last_frag); + frag_len = len - offset; + } + memcpy(skb->data + offset, + bp->rx_buffers + (RX_BUFFER_SIZE * frag), + frag_len); + offset += RX_BUFFER_SIZE; + bp->rx_ring[frag].addr &= ~RXADDR_USED; + wmb(); + + if (frag == last_frag) + break; + } + + skb->protocol = eth_type_trans(skb, bp->dev); + + bp->stats.rx_packets++; + bp->stats.rx_bytes += len; + bp->dev->last_rx = jiffies; + dev_dbg(&bp->adev->dev, "received skb of length %u, csum: %08x\n", + skb->len, skb->csum); + netif_receive_skb(skb); + + return 0; +} + +/* Mark DMA descriptors from begin up to and not including end as unused */ +static void discard_partial_frame(struct macb *bp, unsigned int begin, + unsigned int end) +{ + unsigned int frag; + + for (frag = begin; frag != end; frag = NEXT_RX(frag)) + bp->rx_ring[frag].addr &= ~RXADDR_USED; + wmb(); + + /* + * When this happens, the hardware stats registers for + * whatever caused this is updated, so we don't have to record + * anything. + */ +} + +static int macb_rx(struct macb *bp, int budget) +{ + int received = 0; + unsigned int tail = bp->rx_tail; + int first_frag = -1; + + for (; budget > 0; tail = NEXT_RX(tail)) { + u32 addr, ctrl; + + rmb(); + addr = bp->rx_ring[tail].addr; + ctrl = bp->rx_ring[tail].ctrl; + + if (!(addr & RXADDR_USED)) + break; + + if (ctrl & RXBUF_FRAME_START) { + if (first_frag != -1) + discard_partial_frame(bp, first_frag, tail); + first_frag = tail; + } + + if (ctrl & RXBUF_FRAME_END) { + int dropped; + BUG_ON(first_frag == -1); + + dropped = macb_rx_frame(bp, first_frag, tail); + first_frag = -1; + if (!dropped) { + received++; + budget--; + } + } + } + + if (first_frag != -1) + bp->rx_tail = first_frag; + else + bp->rx_tail = tail; + + return received; +} + +static int macb_poll(struct net_device *dev, int *budget) +{ + struct macb *bp = netdev_priv(dev); + int orig_budget, work_done, retval = 0; + u32 status; + + status = macb_readl(bp, MACB_RXSTAT); + macb_writel(bp, MACB_RXSTAT, status); + + if (!status) { + /* + * This may happen if an interrupt was pending before + * this function was called last time, and no packets + * have been received since. + */ + netif_rx_complete(dev); + goto out; + } + + dev_dbg(&bp->adev->dev, "poll: status = %08lx, budget = %d\n", + (unsigned long)status, *budget); + + if (!(status & MACB_RXSTAT_COMPLETE)) { + dev_warn(&bp->adev->dev, + "No RX buffers complete, status = %02lx\n", + (unsigned long)status); + netif_rx_complete(dev); + goto out; + } + + orig_budget = *budget; + if (orig_budget > dev->quota) + orig_budget = dev->quota; + + work_done = macb_rx(bp, orig_budget); + if (work_done < orig_budget) { + netif_rx_complete(dev); + retval = 0; + } else { + retval = 1; + } + + /* + * We've done what we can to clean the buffers. Make sure we + * get notified when new packets arrive. + */ +out: + macb_writel(bp, MACB_INTENA, MACB_ISR_RX_FLAGS); + + /* TODO: Handle errors */ + + return retval; +} + +static irqreturn_t macb_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct macb *bp = netdev_priv(dev); + u32 status; + + status = macb_readl(bp, MACB_INTSTAT); + + if (unlikely(!status)) + return IRQ_NONE; + + spin_lock(&bp->lock); + + /* close possible race with dev_close */ + if (unlikely(!netif_running(dev))) { + macb_writel(bp, MACB_INTDIS, ~0UL); + spin_unlock(&bp->lock); + return IRQ_HANDLED; + } + + while (status) { + if (status & MACB_ISR_MDIO) + complete(&bp->mdio_complete); + + if (status & MACB_ISR_RX_FLAGS) { + if (netif_rx_schedule_prep(dev)) { + /* + * There's no point taking any more interrupts + * until we have processed the buffers + */ + macb_writel(bp, MACB_INTDIS, MACB_ISR_RX_FLAGS); + dev_dbg(&bp->adev->dev, "scheduling RX softirq\n"); + __netif_rx_schedule(dev); + } + } + + if (status & (MACB_ISR_TXCOMP | MACB_ISR_TXUNR)) + macb_tx(bp); + + /* + * Link change detection isn't possible with RMII, so we'll + * add that if/when we get our hands on a full-blown MII PHY. + */ + + if (status & MACB_ISR_HRESP) { + /* + * TODO: Reset the hardware, and maybe move the printk + * to a lower-priority context as well (work queue?) + */ + printk(KERN_ERR "%s: AHB bus error: HRESP not OK\n", + dev->name); + } + + status = macb_readl(bp, MACB_INTSTAT); + } + + spin_unlock(&bp->lock); + + return IRQ_HANDLED; +} + +static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + dma_addr_t mapping; + unsigned int len, entry; + u32 ctrl; + +#ifdef DEBUG + int i; + dev_dbg(&bp->adev->dev, + "start_xmit: len %u head %p data %p tail %p end %p\n", + skb->len, skb->head, skb->data, skb->tail, skb->end); + dev_dbg(&bp->adev->dev, + "data:"); + for (i = 0; i < 16; i++) + printk(" %02x", (unsigned int)skb->data[i]); + printk("\n"); +#endif + + len = skb->len; + spin_lock_irq(&bp->lock); + + /* This is a hard error, log it. */ + if (TX_BUFFS_AVAIL(bp) < 1) { + netif_stop_queue(dev); + spin_unlock_irq(&bp->lock); + dev_err(&bp->adev->dev, + "BUG! Tx Ring full when queue awake!\n"); + dev_dbg(&bp->adev->dev, "tx_head = %u, tx_tail = %u\n", + bp->tx_head, bp->tx_tail); + return 1; + } + + entry = bp->tx_head; + dev_dbg(&bp->adev->dev, "Allocated ring entry %u\n", entry); + mapping = dma_map_single(&bp->adev->dev, skb->data, + len, DMA_TO_DEVICE); + bp->tx_skb[entry].skb = skb; + bp->tx_skb[entry].mapping = mapping; + dev_dbg(&bp->adev->dev, "Mapped skb data %p to DMA addr %08lx\n", + skb->data, (unsigned long)mapping); + + BUG_ON(skb->ip_summed == CHECKSUM_HW); + + ctrl = (len & TXBUF_FRMLEN_MASK); + ctrl |= TXBUF_FRAME_END; + if (entry == (TX_RING_SIZE - 1)) + ctrl |= TXBUF_WRAP; + + wmb(); + bp->tx_ring[entry].addr = mapping; + bp->tx_ring[entry].ctrl = ctrl; + + entry = NEXT_TX(entry); + bp->tx_head = entry; + + macb_writel(bp, MACB_NETCTRL, + macb_readl(bp, MACB_NETCTRL) | MACB_NCTL_TXSTART); + + if (TX_BUFFS_AVAIL(bp) < 1) + netif_stop_queue(dev); + + spin_unlock_irq(&bp->lock); + + dev->trans_start = jiffies; + + return 0; +} + +static void macb_free_consistent(struct macb *bp) +{ + if (bp->tx_skb) { + kfree(bp->tx_skb); + bp->tx_skb = NULL; + } + if (bp->rx_ring) { + dma_free_coherent(&bp->adev->dev, RX_RING_BYTES, + bp->rx_ring, bp->rx_ring_dma); + bp->rx_ring = NULL; + } + if (bp->tx_ring) { + dma_free_coherent(&bp->adev->dev, TX_RING_BYTES, + bp->tx_ring, bp->tx_ring_dma); + bp->tx_ring = NULL; + } + if (bp->rx_buffers) { + dma_free_coherent(&bp->adev->dev, + RX_RING_SIZE * RX_BUFFER_SIZE, + bp->rx_buffers, bp->rx_buffers_dma); + bp->rx_buffers = NULL; + } +} + +static int macb_alloc_consistent(struct macb *bp) +{ + int size; + + size = TX_RING_SIZE * sizeof(struct ring_info); + bp->tx_skb = kmalloc(size, GFP_KERNEL); + if (!bp->tx_skb) + goto out_err; + + size = RX_RING_BYTES; + bp->rx_ring = dma_alloc_coherent(&bp->adev->dev, size, + &bp->rx_ring_dma, GFP_KERNEL); + if (!bp->rx_ring) + goto out_err; + dev_dbg(&bp->adev->dev, + "Allocated RX ring of %d bytes at %08lx (mapped %p)\n", + size, (unsigned long)bp->rx_ring_dma, bp->rx_ring); + + size = TX_RING_BYTES; + bp->tx_ring = dma_alloc_coherent(&bp->adev->dev, size, + &bp->tx_ring_dma, GFP_KERNEL); + if (!bp->tx_ring) + goto out_err; + dev_dbg(&bp->adev->dev, + "Allocated TX ring of %d bytes at %08lx (mapped %p)\n", + size, (unsigned long)bp->tx_ring_dma, bp->tx_ring); + + size = RX_RING_SIZE * RX_BUFFER_SIZE; + bp->rx_buffers = dma_alloc_coherent(&bp->adev->dev, size, + &bp->rx_buffers_dma, GFP_KERNEL); + if (!bp->rx_buffers) + goto out_err; + dev_dbg(&bp->adev->dev, + "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n", + size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers); + + return 0; + +out_err: + macb_free_consistent(bp); + return -ENOMEM; +} + +static void macb_init_rings(struct macb *bp) +{ + int i; + dma_addr_t addr; + + addr = bp->rx_buffers_dma; + for (i = 0; i < RX_RING_SIZE; i++) { + bp->rx_ring[i].addr = addr; + bp->rx_ring[i].ctrl = 0; + addr += RX_BUFFER_SIZE; + } + bp->rx_ring[RX_RING_SIZE - 1].addr |= RXADDR_WRAP; + + for (i = 0; i < TX_RING_SIZE; i++) { + bp->tx_ring[i].addr = 0; + bp->tx_ring[i].ctrl = TXBUF_USED; + } + bp->tx_ring[TX_RING_SIZE - 1].ctrl |= TXBUF_WRAP; + + bp->rx_tail = bp->tx_head = bp->tx_tail = 0; +} + +static void macb_reset_hw(struct macb *bp) +{ + /* Make sure we have the write buffer for ourselves */ + wmb(); + + /* + * Disable RX and TX (XXX: Should we halt the transmission + * more gracefully?) + */ + macb_writel(bp, MACB_NETCTRL, 0); + + /* Clear the stats registers (XXX: Update stats first?) */ + macb_writel(bp, MACB_NETCTRL, MACB_NCTL_CLRSTAT); + + /* Clear all status flags */ + macb_writel(bp, MACB_TXSTAT, 0xffffffff); + macb_writel(bp, MACB_RXSTAT, 0xffffffff); + + /* Disable all interrupts */ + macb_writel(bp, MACB_INTDIS, 0xffffffff); + (void)macb_readl(bp, MACB_INTSTAT); +} + +static void macb_init_hw(struct macb *bp) +{ + u32 config; + + macb_reset_hw(bp); + __macb_set_hwaddr(bp); + + /* Set MII mode */ + macb_writel(bp, MACB_USERIO, 1); + + /* Initialize Network Configuration Register */ + config = MACB_NCFG_PCLK40 | MACB_NCFG_PAUSE | MACB_NCFG_NORXFCS; + if (bp->dev->flags & IFF_PROMISC) + config |= MACB_NCFG_PROMISC; + if (!(bp->dev->flags & IFF_BROADCAST)) + config |= MACB_NCFG_NOBRD; + macb_writel(bp, MACB_NETCFG, config); + + /* Initialize TX and RX buffers */ + macb_writel(bp, MACB_RXBQP, bp->rx_ring_dma); + macb_writel(bp, MACB_TXBQP, bp->tx_ring_dma); + + /* Enable local loopback (temporary) */ + /* macb_writel(bp, MACB_NETCTRL, MACB_NCTL_LOOP); */ + + /* Enable TX and RX */ + macb_writel(bp, MACB_NETCTRL, + /* MACB_NCTL_LOOP |*/ MACB_NCTL_RXEN | MACB_NCTL_TXEN); + + /* Enable interrupts */ + macb_writel(bp, MACB_INTENA, + MACB_ISR_RXCOMP + | MACB_ISR_RXUSED + | MACB_ISR_TXUNR + | MACB_ISR_MAXRETRY + | MACB_ISR_TXEXHAUST + | MACB_ISR_TXCOMP + | MACB_ISR_RXOVR + | MACB_ISR_HRESP); +} + +static void macb_init_phy(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + + /* Set some reasonable default settings */ + macb_mdio_write(dev, bp->mii.phy_id, MII_ADVERTISE, + ADVERTISE_CSMA | ADVERTISE_ALL); + macb_mdio_write(dev, bp->mii.phy_id, MII_BMCR, + (BMCR_SPEED100 | BMCR_ANENABLE + | BMCR_ANRESTART | BMCR_FULLDPLX)); +} + +static int macb_open(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + int err; + + dev_dbg(&bp->adev->dev, "open\n"); + + err = macb_alloc_consistent(bp); + if (err) { + printk(KERN_ERR + "%s: Unable to allocate DMA memory (error %d)\n", + dev->name, err); + return err; + } + + macb_init_rings(bp); + macb_init_hw(bp); + macb_init_phy(dev); + + macb_check_media(bp, 1, 1); + netif_start_queue(dev); + + schedule_delayed_work(&bp->periodic_task, HZ); + + return 0; +} + +static int macb_close(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + unsigned long flags; + + cancel_rearming_delayed_work(&bp->periodic_task); + + netif_stop_queue(dev); + + spin_lock_irqsave(&bp->lock, flags); + macb_reset_hw(bp); + netif_carrier_off(dev); + spin_unlock_irqrestore(&bp->lock, flags); + + macb_free_consistent(bp); + + return 0; +} + +static struct net_device_stats *macb_get_stats(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + struct net_device_stats *nstat = &bp->stats; + struct macb_stats *hwstat = &bp->hw_stats; + + /* Convert HW stats into netdevice stats */ + nstat->rx_errors = (hwstat->rx_fcs_errors + + hwstat->rx_align_errors + + hwstat->rx_resource_errors + + hwstat->rx_overruns + + hwstat->rx_oversize_pkts + + hwstat->rx_jabbers + + hwstat->rx_undersize_pkts + + hwstat->sqe_test_errors + + hwstat->rx_length_mismatch); + nstat->tx_errors = (hwstat->tx_late_cols + + hwstat->tx_excessive_cols + + hwstat->tx_underruns + + hwstat->tx_carrier_errors); + nstat->collisions = (hwstat->tx_single_cols + + hwstat->tx_multiple_cols + + hwstat->tx_excessive_cols); + nstat->rx_length_errors = (hwstat->rx_oversize_pkts + + hwstat->rx_jabbers + + hwstat->rx_undersize_pkts + + hwstat->rx_length_mismatch); + nstat->rx_over_errors = hwstat->rx_resource_errors; + nstat->rx_crc_errors = hwstat->rx_fcs_errors; + nstat->rx_frame_errors = hwstat->rx_align_errors; + nstat->rx_fifo_errors = hwstat->rx_overruns; + /* XXX: What does "missed" mean? */ + nstat->tx_aborted_errors = hwstat->tx_excessive_cols; + nstat->tx_carrier_errors = hwstat->tx_carrier_errors; + nstat->tx_fifo_errors = hwstat->tx_underruns; + /* Don't know about heartbeat or window errors... */ + + return nstat; +} + +static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct macb *bp = netdev_priv(dev); + int ret; + unsigned long flags; + + spin_lock_irqsave(&bp->lock, flags); + ret = mii_ethtool_gset(&bp->mii, cmd); + spin_unlock_irqrestore(&bp->lock, flags); + + return ret; +} + +static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct macb *bp = netdev_priv(dev); + int ret; + unsigned long flags; + + spin_lock_irqsave(&bp->lock, flags); + ret = mii_ethtool_sset(&bp->mii, cmd); + spin_unlock_irqrestore(&bp->lock, flags); + + return ret; +} + +static void macb_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct macb *bp = netdev_priv(dev); + + strcpy(info->driver, bp->adev->dev.driver->name); + strcpy(info->version, "$Revision: 1.14 $"); + strcpy(info->bus_info, bp->adev->dev.bus_id); +} + +static int macb_nway_reset(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + return mii_nway_restart(&bp->mii); +} + +static struct ethtool_ops macb_ethtool_ops = { + .get_settings = macb_get_settings, + .set_settings = macb_set_settings, + .get_drvinfo = macb_get_drvinfo, + .nway_reset = macb_nway_reset, + .get_link = ethtool_op_get_link, +}; + +static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct macb *bp = netdev_priv(dev); + int ret; + unsigned long flags; + + if (!netif_running(dev)) + return -EINVAL; + + spin_lock_irqsave(&bp->lock, flags); + ret = generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL); + spin_unlock_irqrestore(&bp->lock, flags); + + return ret; +} + +static ssize_t macb_mii_show(const struct class_device *cd, char *buf, + unsigned long addr) +{ + struct net_device *dev = to_net_dev(cd); + struct macb *bp = netdev_priv(dev); + ssize_t ret = -EINVAL; + + if (netif_running(dev)) { + int value; + value = macb_mdio_read(dev, bp->mii.phy_id, addr); + ret = sprintf(buf, "0x%04x\n", (uint16_t)value); + } + + return ret; +} + +#define MII_ENTRY(name, addr) \ +static ssize_t show_##name(struct class_device *cd, char *buf) \ +{ \ + return macb_mii_show(cd, buf, addr); \ +} \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + +MII_ENTRY(bmcr, MII_BMCR); +MII_ENTRY(bmsr, MII_BMSR); +MII_ENTRY(physid1, MII_PHYSID1); +MII_ENTRY(physid2, MII_PHYSID2); +MII_ENTRY(advertise, MII_ADVERTISE); +MII_ENTRY(lpa, MII_LPA); +MII_ENTRY(expansion, MII_EXPANSION); + +static struct attribute *macb_mii_attrs[] = { + &class_device_attr_bmcr.attr, + &class_device_attr_bmsr.attr, + &class_device_attr_physid1.attr, + &class_device_attr_physid2.attr, + &class_device_attr_advertise.attr, + &class_device_attr_lpa.attr, + &class_device_attr_expansion.attr, + NULL, +}; + +static struct attribute_group macb_mii_group = { + .name = "mii", + .attrs = macb_mii_attrs, +}; + +static void macb_unregister_sysfs(struct net_device *net) +{ + struct class_device *class_dev = &net->class_dev; + + sysfs_remove_group(&class_dev->kobj, &macb_mii_group); +} + +static int macb_register_sysfs(struct net_device *net) +{ + struct class_device *class_dev = &net->class_dev; + int ret; + + ret = sysfs_create_group(&class_dev->kobj, &macb_mii_group); + if (ret) + printk(KERN_WARNING + "%s: sysfs mii attribute registration failed: %d\n", + net->name, ret); + return ret; +} +static int __devinit macb_probe(struct at32_device *adev) +{ + struct eth_platform_data *pdata; + struct net_device *dev; + struct macb *bp; + unsigned int revision; + int err; + + err = at32_enable_device(adev); + if (err) { + dev_err(&adev->dev, "failed to enable device\n"); + goto err_out; + } + + err = -ENOMEM; + dev = alloc_etherdev(sizeof(*bp)); + if (!dev) { + dev_err(&adev->dev, "etherdev alloc failed, aborting.\n"); + goto err_out_disable_pio; + } + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &adev->dev); + + /* TODO: Actually, we have some interesting features... */ + dev->features |= 0; + + bp = netdev_priv(dev); + bp->adev = adev; + bp->dev = dev; + + spin_lock_init(&bp->lock); + + bp->mmio = at32_map_iomem(adev, 0); + if (!bp->mmio) { + dev_err(&adev->dev, "failed to map registers, aborting.\n"); + err = -ENOMEM; + goto err_out_free_dev; + } + + dev->irq = at32_get_irq(adev); + err = request_irq(dev->irq, macb_interrupt, SA_SAMPLE_RANDOM, + dev->name, dev); + if (err) { + printk(KERN_ERR + "%s: Unable to request IRQ %d (error %d)\n", + dev->name, dev->irq, err); + goto err_out_iounmap; + } + + dev->open = macb_open; + dev->stop = macb_close; + dev->hard_start_xmit = macb_start_xmit; + dev->get_stats = macb_get_stats; + dev->do_ioctl = macb_ioctl; + dev->poll = macb_poll; + dev->weight = 64; + dev->ethtool_ops = &macb_ethtool_ops; + + dev->base_addr = at32_get_iomem_base(adev, 0); + + INIT_WORK(&bp->periodic_task, macb_periodic_task, bp); + init_MUTEX(&bp->mdio_sem); + init_completion(&bp->mdio_complete); + + bp->mii.dev = dev; + bp->mii.mdio_read = macb_mdio_read; + bp->mii.mdio_write = macb_mdio_write; + + pdata = adev->dev.platform_data; + if (pdata && pdata->valid) { + bp->mii.phy_id = pdata->mii_phy_addr; + memcpy(dev->dev_addr, pdata->hw_addr, dev->addr_len); + } else { + dev_warn(&adev->dev, "Using default MAC address\n"); + memcpy(dev->dev_addr, default_macaddr, dev->addr_len); + +#if defined(CONFIG_BOARD_ATSTK1000) + bp->mii.phy_id = 0x10 + adev->id; +#else + dev_err(&adev->dev, "Cannot determine PHY address\n"); + goto err_out_free_irq; +#endif + } + bp->mii.phy_id_mask = 0x1f; + bp->mii.reg_num_mask = 0x1f; + + bp->tx_pending = DEF_TX_RING_PENDING; + + err = register_netdev(dev); + if (err) { + dev_err(&adev->dev, "Cannot register net device, aborting.\n"); + goto err_out_free_irq; + } + + at32_set_drvdata(adev, dev); + + macb_register_sysfs(dev); + + revision = macb_readl(bp, MACB_REV); + printk(KERN_INFO "%s: Atmel MACB rev %u.%u at 0x%08lx irq %d " + "(%02x:%02x:%02x:%02x:%02x:%02x)\n", dev->name, + (revision >> 8) & 0xff, revision & 0xff, + dev->base_addr, dev->irq, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + return 0; + +err_out_free_irq: + free_irq(dev->irq, dev); +err_out_iounmap: + iounmap(bp->mmio); +err_out_free_dev: + free_netdev(dev); +err_out_disable_pio: + at32_disable_device(adev); +err_out: + at32_set_drvdata(adev, NULL); + return err; +} + +static int __devexit macb_remove(struct at32_device *adev) +{ + struct net_device *dev; + struct macb *bp; + + dev = at32_get_drvdata(adev); + + if (dev) { + bp = netdev_priv(dev); + macb_unregister_sysfs(dev); + unregister_netdev(dev); + free_irq(dev->irq, dev); + iounmap(bp->mmio); + free_netdev(dev); + at32_disable_device(adev); + at32_set_drvdata(adev, NULL); + } + + return 0; +} + +static struct at32_driver macb_driver = { + .probe = macb_probe, + .remove = __devexit_p(macb_remove), + .driver = { + .name = "macb", + }, +}; + +static int __init macb_init(void) +{ + return at32_driver_register(&macb_driver); +} + +static void __exit macb_exit(void) +{ + at32_driver_unregister(&macb_driver); +} + +module_init(macb_init); +module_exit(macb_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Atmel/Cadence MACB Ethernet driver"); +MODULE_AUTHOR("Haavard Skinnemoen "); diff -Nur linux-2.6.16.11/drivers/net/macb.h linux-2.6.16.11-avr32-20060626/drivers/net/macb.h --- linux-2.6.16.11/drivers/net/macb.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/net/macb.h 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,226 @@ +/* + * Cadence/Atmel MACB Ethernet Controller driver + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _MACB_H +#define _MACB_H + +/* Give an error if we happen to switch offset and value */ +#ifdef __ASSEMBLY__ +# define REGOFF(x) (x) +#else +typedef struct regoff { unsigned long off; } regoff_t; +# define REGOFF(x) ((regoff_t){ x }) +# define NEXT_REG(reg) ((regoff_t){ reg.off + 4 }) +#endif + +#define MACB_NETCTRL REGOFF(0x00) /* Network control */ +# define MACB_NCTL_PHYLOOP 0x00000001 +# define MACB_NCTL_LOOP 0x00000002 +# define MACB_NCTL_RXEN 0x00000004 +# define MACB_NCTL_TXEN 0x00000008 +# define MACB_NCTL_MDIOEN 0x00000010 +# define MACB_NCTL_CLRSTAT 0x00000020 +# define MACB_NCTL_TXSTART 0x00000200 +# define MACB_NCTL_TXHALT 0x00000400 +#define MACB_NETCFG REGOFF(0x04) /* Network configuration */ +# define MACB_NCFG_100M 0x00000001 +# define MACB_NCFG_FDPL 0x00000002 +# define MACB_NCFG_PROMISC 0x00000010 +# define MACB_NCFG_NOBRD 0x00000020 +# define MACB_NCFG_MCHASH 0x00000040 +# define MACB_NCFG_UCHASH 0x00000080 +# define MACB_NCFG_PCLK20 0x00000000 +# define MACB_NCFG_PCLK40 0x00000400 +# define MACB_NCFG_PCLK80 0x00000800 +# define MACB_NCFG_PCLK160 0x00000c00 +# define MACB_NCFG_PAUSE 0x00002000 +# define MACB_NCFG_RXFCE 0x00010000 +# define MACB_NCFG_NORXFCS 0x00020000 +#define MACB_NETSTAT REGOFF(0x08) /* Network status */ +# define MACB_NS_LINK 0x00000001 +# define MACB_NS_MDIO_IDLE 0x00000004 +#define MACB_TXSTAT REGOFF(0x14) /* Transmit status */ +# define MACB_TXSTAT_USED 0x00000001 /* "used" bit set in desc */ +# define MACB_TXSTAT_COLL 0x00000002 /* Collision occurred */ +# define MACB_TXSTAT_MAXRETRY 0x00000004 /* Retry limit exceeeded */ +# define MACB_TXSTAT_TXGO 0x00000008 /* Transmit active */ +# define MACB_TXSTAT_EXHAUST 0x00000010 /* Bufs exhausted mid frame */ +# define MACB_TXSTAT_COMPLETE 0x00000020 /* Transmit complete */ +# define MACB_TXSTAT_UNR 0x00000040 /* Transmit underrun */ +#define MACB_RXBQP REGOFF(0x18) /* RX buffer queue pointer */ +#define MACB_TXBQP REGOFF(0x1c) /* TX buffer queue pointer */ +#define MACB_RXSTAT REGOFF(0x20) /* RX status */ +# define MACB_RXSTAT_USED 0x00000001 +# define MACB_RXSTAT_COMPLETE 0x00000002 +# define MACB_RXSTAT_OVR 0x00000004 +#define MACB_INTSTAT REGOFF(0x24) /* Interrupt status */ +# define MACB_ISR_MDIO 0x00000001 +# define MACB_ISR_RXCOMP 0x00000002 +# define MACB_ISR_RXUSED 0x00000004 +# define MACB_ISR_TXUSED 0x00000008 +# define MACB_ISR_TXUNR 0x00000010 +# define MACB_ISR_MAXRETRY 0x00000020 +# define MACB_ISR_TXEXHAUST 0x00000040 +# define MACB_ISR_TXCOMP 0x00000080 +# define MACB_ISR_LINKCHG 0x00000200 +# define MACB_ISR_RXOVR 0x00000400 +# define MACB_ISR_HRESP 0x00000800 +# define MACB_ISR_PAUSE 0x00001000 +# define MACB_ISR_PAUSE0 0x00002000 +# define MACB_ISR_RX_FLAGS (MACB_ISR_RXCOMP \ + | MACB_ISR_RXUSED \ + | MACB_ISR_RXOVR) +#define MACB_INTENA REGOFF(0x28) /* Interrupt enable */ +#define MACB_INTDIS REGOFF(0x2c) /* Interrupt disable */ +#define MACB_INTMASK REGOFF(0x30) /* Interrupt mask */ +#define MACB_MDIO REGOFF(0x34) /* PHY maintenance */ +#define MACB_PAUSE_TIME REGOFF(0x38) /* Pause time */ +#define MACB_COUNT_RXPAUSE REGOFF(0x3c) /* Pause frames received */ +#define MACB_COUNT_TXOK REGOFF(0x40) /* Frames transmitted OK */ +#define MACB_COUNT_SINGCOLL REGOFF(0x44) /* Single collision frames */ +#define MACB_COUNT_MULTCOLL REGOFF(0x48) /* Multiple coll. frames */ +#define MACB_COUNT_RXOK REGOFF(0x4c) /* Frames received OK */ +#define MACB_COUNT_SEQERR REGOFF(0x50) /* Frame check seq errors */ +#define MACB_COUNT_ALGNERR REGOFF(0x54) /* Alignment errors */ +#define MACB_COUNT_DEFERTX REGOFF(0x58) /* Deferred TX frames */ +#define MACB_COUNT_LATECOLL REGOFF(0x5c) /* Late collisions */ +#define MACB_COUNT_EXCOLL REGOFF(0x60) /* Excessive collisions */ +#define MACB_COUNT_TXUNR REGOFF(0x64) /* TX underrun errors */ +#define MACB_COUNT_SENSE REGOFF(0x68) /* Carrier sense errors */ +#define MACB_COUNT_RXRES REGOFF(0x6c) /* RX resource errors */ +#define MACB_COUNT_RXOVR REGOFF(0x70) /* RX overrun errors */ +#define MACB_COUNT_RXSYM REGOFF(0x74) /* RX symbol errors */ +#define MACB_COUNT_EXLEN REGOFF(0x78) /* Excessive length errors */ +#define MACB_COUNT_RXJAB REGOFF(0x7c) /* Receive jabbers */ +#define MACB_COUNT_UNSZF REGOFF(0x80) /* Undersize frames */ +#define MACB_COUNT_SQE REGOFF(0x84) /* SQE test errors */ +#define MACB_COUNT_RXLEN REGOFF(0x88) /* RX length field mismatch */ +#define MACB_COUNT_TXPAUSE REGOFF(0x8c) /* Transmitted pause frames */ +#define MACB_HASH_BOT REGOFF(0x90) /* Hash reg bottom [31: 0] */ +#define MACB_HASH_TOP REGOFF(0x94) /* Hash reg top [63:32] */ +#define MACB_ADDR1_BOT REGOFF(0x98) /* Specific addr 1 bottom */ +#define MACB_ADDR1_TOP REGOFF(0x9c) /* Specific addr 1 top */ +#define MACB_ADDR2_BOT REGOFF(0xa0) /* Specific addr 2 bottom */ +#define MACB_ADDR2_TOP REGOFF(0xa4) /* Specific addr 2 top */ +#define MACB_ADDR3_BOT REGOFF(0xa8) /* Specific addr 3 bottom */ +#define MACB_ADDR3_TOP REGOFF(0xac) /* Specific addr 3 top */ +#define MACB_ADDR4_BOT REGOFF(0xb0) /* Specific addr 4 bottom */ +#define MACB_ADDR4_TOP REGOFF(0xb4) /* Specific addr 4 top */ +#define MACB_TYPE_ID_CHK REGOFF(0xb8) /* Type ID checking */ +#define MACB_TX_PAUSEQ REGOFF(0xbc) /* TX pause quantum */ +#define MACB_USERIO REGOFF(0xc0) /* User input/output */ +#define MACB_WOL REGOFF(0xc4) /* Wake on LAN */ +#define MACB_REV REGOFF(0xfc) /* Revision */ + +#ifndef __ASSEMBLY__ +struct dma_desc { + u32 addr; + u32 ctrl; +}; +#endif + +#define RXADDR_USED 0x00000001 +#define RXADDR_WRAP 0x00000002 + +#define RXBUF_FRMLEN_MASK 0x00000fff +#define RXBUF_FRAME_START 0x00004000 +#define RXBUF_FRAME_END 0x00008000 +#define RXBUF_TYPEID_MATCH 0x00400000 +#define RXBUF_ADDR4_MATCH 0x00800000 +#define RXBUF_ADDR3_MATCH 0x01000000 +#define RXBUF_ADDR2_MATCH 0x02000000 +#define RXBUF_ADDR1_MATCH 0x04000000 +#define RXBUF_BROADCAST 0x80000000 + +#define TXBUF_FRMLEN_MASK 0x000007ff +#define TXBUF_FRAME_END 0x00008000 +#define TXBUF_NOCRC 0x00010000 +#define TXBUF_EXHAUSTED 0x08000000 +#define TXBUF_UNDERRUN 0x10000000 +#define TXBUF_MAXRETRY 0x20000000 +#define TXBUF_WRAP 0x40000000 +#define TXBUF_USED 0x80000000 + +#ifndef __ASSEMBLY__ +struct ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +/* + * Hardware-collected statistics. Used when updating the network + * device stats by a periodic timer. + */ +struct macb_stats { + u32 rx_pause_frames; + u32 tx_ok; + u32 tx_single_cols; + u32 tx_multiple_cols; + u32 rx_ok; + u32 rx_fcs_errors; + u32 rx_align_errors; + u32 tx_deferred; + u32 tx_late_cols; + u32 tx_excessive_cols; + u32 tx_underruns; + u32 tx_carrier_errors; + u32 rx_resource_errors; + u32 rx_overruns; + u32 rx_symbol_errors; + u32 rx_oversize_pkts; + u32 rx_jabbers; + u32 rx_undersize_pkts; + u32 sqe_test_errors; + u32 rx_length_mismatch; + u32 tx_pause_frames; +}; + +struct macb { + void __iomem *mmio; + + unsigned int rx_tail; + struct dma_desc *rx_ring; + void *rx_buffers; + + unsigned int tx_head, tx_tail; + struct dma_desc *tx_ring; + struct ring_info *tx_skb; + + spinlock_t lock; + struct at32_device *adev; + struct net_device *dev; + struct net_device_stats stats; + struct macb_stats hw_stats; + + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + dma_addr_t rx_buffers_dma; + + unsigned int rx_pending, tx_pending; + + struct work_struct periodic_task; + + struct semaphore mdio_sem; + struct completion mdio_complete; + struct mii_if_info mii; +}; + +static inline u32 macb_readl(struct macb *bp, regoff_t reg) +{ + return readl(bp->mmio + reg.off); +} + +static inline void macb_writel(struct macb *bp, regoff_t reg, u32 value) +{ + writel(value, bp->mmio + reg.off); +} + +#endif + +#endif /* _MACB_H */ diff -Nur linux-2.6.16.11/drivers/net/Makefile linux-2.6.16.11-avr32-20060626/drivers/net/Makefile --- linux-2.6.16.11/drivers/net/Makefile 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/net/Makefile 2006-06-26 11:33:53.000000000 +0200 @@ -196,6 +196,8 @@ obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_FEC_8XX) += fec_8xx/ +obj-$(CONFIG_MACB) += macb.o + obj-$(CONFIG_ARM) += arm/ obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_TR) += tokenring/ diff -Nur linux-2.6.16.11/drivers/serial/Kconfig linux-2.6.16.11-avr32-20060626/drivers/serial/Kconfig --- linux-2.6.16.11/drivers/serial/Kconfig 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/serial/Kconfig 2006-06-26 11:33:53.000000000 +0200 @@ -227,6 +227,27 @@ comment "Non-8250 serial port support" +config SERIAL_USART3 + tristate "Atmel USART3 serial port support" + depends on AVR32 + select SERIAL_CORE + default y + help + Support for the Atmel USART3 on-chip USART found in most + AT32 and AT91 parts from Atmel. + + If unsure, say Y. + +config SERIAL_USART3_CONSOLE + bool "Support for console on USART3 serial port" + depends on SERIAL_USART3=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use an Atmel USART3 serial port as + the system console (the system console is the device which + receives all kernel messages and warnings and which allows + logins in single user mode). + config SERIAL_AMBA_PL010 tristate "ARM AMBA PL010 serial port support" depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE) diff -Nur linux-2.6.16.11/drivers/serial/Makefile linux-2.6.16.11-avr32-20060626/drivers/serial/Makefile --- linux-2.6.16.11/drivers/serial/Makefile 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/serial/Makefile 2006-06-26 11:33:53.000000000 +0200 @@ -23,6 +23,7 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o obj-$(CONFIG_SERIAL_8250_AU1X00) += 8250_au1x00.o +obj-$(CONFIG_SERIAL_USART3) += serial_usart3.o obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o diff -Nur linux-2.6.16.11/drivers/serial/serial_core.c linux-2.6.16.11-avr32-20060626/drivers/serial/serial_core.c --- linux-2.6.16.11/drivers/serial/serial_core.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/serial/serial_core.c 2006-06-26 11:33:51.000000000 +0200 @@ -551,6 +551,8 @@ spin_lock_irqsave(&port->lock, flags); uart_circ_clear(&state->info->xmit); + if (port->ops->flush_buffer) + port->ops->flush_buffer(port); spin_unlock_irqrestore(&port->lock, flags); tty_wakeup(tty); } diff -Nur linux-2.6.16.11/drivers/serial/serial_usart3.c linux-2.6.16.11-avr32-20060626/drivers/serial/serial_usart3.c --- linux-2.6.16.11/drivers/serial/serial_usart3.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/serial/serial_usart3.c 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,1070 @@ +/* + * Driver for Atmel USART3 Serial ports + * + * Based on AT91RM9200 serial driver by Rick Bronson + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Based on drivers/serial/sa1100.c by Deep Blue Solutions Ltd. + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#if defined(CONFIG_SERIAL_USART3_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#include +#endif + +#include +#include +#include + +/* + * TODO: Move this definition into linux/serial_core.h + */ +#define PORT_USART3 60 + +/* + * Use the same major/minor numbers as the AT91 USART, which is + * actually the same chip + */ +#define SERIAL_USART3_MAJOR TTY_MAJOR +#define MINOR_START 64 +#define NR_PORTS 4 + +#define ERROR_FLAGS (USART3_BIT(CSR_PARE) \ + | USART3_BIT(CSR_FRAME) \ + | USART3_BIT(CSR_OVRE)) + +/* Must be a power of two, or everything will break */ +#define RX_BUFFER_SIZE 32 +struct usart3_port { + void __iomem *regs; + int break_active; + unsigned int tx_dma_head; + int rx_tail; + char *rx_buffer; + dma_addr_t rx_dma; + dma_addr_t tx_dma; + struct uart_port uart; +}; +#define to_usart3_port(port) container_of(port, struct usart3_port, uart) + +static void tx_dma_sync(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + struct circ_buf *xmit = &port->info->xmit; + + if (xmit->head < up->tx_dma_head) { + dma_sync_single_for_device(port->dev, + up->tx_dma + up->tx_dma_head, + UART_XMIT_SIZE - up->tx_dma_head, + DMA_TO_DEVICE); + dma_sync_single_for_device(port->dev, up->tx_dma, + xmit->head, DMA_TO_DEVICE); + } else { + dma_sync_single_for_device(port->dev, + up->tx_dma + up->tx_dma_head, + xmit->head - up->tx_dma_head, + DMA_TO_DEVICE); + } +} + +static void tx_dma_update_tail(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + struct circ_buf *xmit = &port->info->xmit; + unsigned long status, remaining; + unsigned int new_tail; + + /* Account for the characters DMA'ed since last update */ + remaining = pdc_readl(up, TCR); + + if (up->tx_dma_head < xmit->tail) { + /* + * We have wrapped around, and there's a chunk at the + * beginning of the buffer that has been submitted for + * DMA. If the ENDTX bit is set, it means that the + * DMA controller also has wrapped around and copied + * TNPR/TNCR into TPR/TCR. + */ + status = usart3_readl(up, CSR); + BUG_ON((up->tx_dma_head != 0) + && (pdc_readl(up, TNCR) == 0) + && !(status & USART3_BIT(ENDTX))); + if (status & USART3_BIT(ENDTX)) { + BUG_ON(pdc_readl(up, TNCR) != 0); + + /* The ENDTX bit might be set after we read TCR */ + remaining = pdc_readl(up, TCR); + + pdc_writel(up, TNCR, 0); + port->icount.tx += UART_XMIT_SIZE - xmit->tail; + xmit->tail = 0; + + BUG_ON(remaining > up->tx_dma_head); + new_tail = up->tx_dma_head - remaining; + } else { + /* + * The DMA controller hasn't switched yet, so + * TCR indicates the number of bytes left + * until this happens. + */ + new_tail = UART_XMIT_SIZE - remaining; + } + } else { + /* No wraparound, move the tail closer to dma_head. */ + BUG_ON(remaining > up->tx_dma_head); + new_tail = up->tx_dma_head - remaining; + } + + BUG_ON(new_tail < xmit->tail); + port->icount.tx += new_tail - xmit->tail; + xmit->tail = new_tail; +} + +static inline void tx_dma_start(struct usart3_port *up) +{ + /* Start the PDC and enable interrupts */ + pdc_writel(up, PTCR, PDC_BIT(PTCR_TXTEN)); + usart3_writel(up, IER, USART3_BIT(ENDTX)); +} + +static inline void tx_dma_stop(struct usart3_port *up) +{ + pdc_writel(up, PTCR, PDC_BIT(PTCR_TXTDIS)); + usart3_writel(up, IDR, USART3_BIT(ENDTX)); +} + +static inline unsigned int rx_dma_get_head(struct usart3_port *up) +{ + unsigned int head; + u32 status; + + head = RX_BUFFER_SIZE - pdc_readl(up, RCR); + status = usart3_readl(up, CSR); + if (status & USART3_BIT(ENDRX)) + head = RX_BUFFER_SIZE; + + return head; +} + +static inline int rx_dma_update_tail(struct usart3_port *up, + unsigned int tail) +{ + int again = 0; + + if (!(tail & (RX_BUFFER_SIZE - 1))) { + u32 rnpr = up->rx_dma; + + tail &= RX_BUFFER_SIZE; + if (!tail) + rnpr += RX_BUFFER_SIZE; + + pdc_writel(up, RNPR, rnpr); + pdc_writel(up, RNCR, RX_BUFFER_SIZE); + + again = 1; + } else + BUG_ON(usart3_readl(up, CSR) & USART3_BIT(ENDRX)); + + up->rx_tail = tail; + + return again; +} + +static void usart3_stop_tx(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + + tx_dma_stop(up); + tx_dma_update_tail(port); +} + +static void usart3_start_tx(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + struct circ_buf *xmit = &port->info->xmit; + + BUG_ON(!irqs_disabled()); + + /* + * Stop the DMA engine so that we don't have to worry about race + * conditions when updating the various pointers and counters. + */ + tx_dma_stop(up); + + tx_dma_sync(port); + tx_dma_update_tail(port); + + if (uart_circ_empty(xmit)) + return; + + pdc_writel(up, TPR, up->tx_dma + xmit->tail); + + if (xmit->head > xmit->tail) { + pdc_writel(up, TCR, xmit->head - xmit->tail); + } else { + pdc_writel(up, TCR, UART_XMIT_SIZE - xmit->tail); + pdc_writel(up, TNPR, up->tx_dma); + pdc_writel(up, TNCR, xmit->head); + } + + /* Keep track of what we've submitted for DMA */ + up->tx_dma_head = xmit->head; + + /* Resume operation of DMA engine. */ + tx_dma_start(up); +} + +static void usart3_stop_rx(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + + pr_debug("usart3: stop_rx\n"); + + pdc_writel(up, PTCR, PDC_BIT(PTCR_RXTDIS)); + usart3_writel(up, IDR, (USART3_BIT(TIMEOUT) + | USART3_BIT(ENDRX) + | USART3_BIT(RXBRK) + | USART3_BIT(OVRE) + | USART3_BIT(FRAME) + | USART3_BIT(PARE))); +} + +static void usart3_flush_buffer(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + + /* + * Reset TX DMA state. Note that we must _always_ update TNCR + * before TCR, since the value in TNCR will automatically move + * to TCR when TCR is 0. + */ + pdc_writel(up, TNCR, 0); + pdc_writel(up, TCR, 0); + up->tx_dma_head = port->info->xmit.tail; +} + +/* + * Enable modem status interrupts + */ +static void usart3_enable_ms(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + + pr_debug("usart3: enable_ms\n"); + usart3_writel(up, IER, (USART3_BIT(RIIC) + | USART3_BIT(DSRIC) + | USART3_BIT(DCDIC) + | USART3_BIT(CTSIC))); +} + +static inline void handle_rx_error(struct uart_port *port, u32 status) +{ + /* + * FIXME: Errors should affect the flag buffer, but due to the + * PDC, we don't really know which char they belong to... + */ + if (status & USART3_BIT(PARE)) { + printk(KERN_NOTICE "usart%u: Parity error\n", port->line); + port->icount.parity++; + } else if (status & USART3_BIT(FRAME)) { + printk(KERN_NOTICE "usart%u: Frame error\n", port->line); + port->icount.frame++; + } + if (status & USART3_BIT(OVRE)) { + printk(KERN_NOTICE "usart%u: Overrun\n", port->line); + port->icount.overrun++; + } + +#ifdef SUPPORT_SYSRQ + port->sysrq = 0; +#endif +} + +static inline void handle_pdc_endtx(struct uart_port *port, unsigned long status) +{ + struct usart3_port *up = to_usart3_port(port); + struct circ_buf *xmit = &port->info->xmit; + + tx_dma_update_tail(port); + + if (uart_tx_stopped(port)) { + usart3_stop_tx(port); + printk("usart3: stopped\n"); + return; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + usart3_stop_tx(port); + + /* + * It could be that xmit is being updated right now. If so, + * start_tx() will be called shortly. + */ + if (status & USART3_BIT(TXBUFE)) + usart3_writel(up, IDR, USART3_BIT(ENDTX)); +} + +static void consume_rx_buffer(struct uart_port *port, struct pt_regs *regs) +{ + struct usart3_port *up = to_usart3_port(port); + struct tty_struct *tty = port->info->tty; + unsigned long head, tail; + int len; + int again; + + do { + /* + * Re-arm the timeout before we decide how many + * characters to read. + */ + usart3_writel(up, CR, USART3_BIT(STTTO)); + + head = rx_dma_get_head(up); + + tail = up->rx_tail; + if (tail & RX_BUFFER_SIZE) + head += RX_BUFFER_SIZE; + + if (head == tail) + break; + + dma_sync_single_for_cpu(port->dev, up->rx_dma + tail, + head - tail, DMA_FROM_DEVICE); + + if (uart_handle_sysrq_char(port, up->rx_buffer[tail], + regs)) { + tail++; + if (head == tail) + goto update_tail; + } + + len = tty_insert_flip_string(tty, up->rx_buffer + tail, + head - tail); + port->icount.rx += len; + tail += len; + if (!(head & (RX_BUFFER_SIZE - 1)) && tail != head) { + /* + * head has wrapped, but there isn't enough + * room in the buffer to handle all the + * characters. We must recycle this buffer in + * order to clear the interrupt. + */ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tail = head; + } + + update_tail: + again = rx_dma_update_tail(up, tail); + } while (again); + + tty_flip_buffer_push(tty); +} + +/* + * This is the serial driver's interrupt routine + */ +static irqreturn_t usart3_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + struct usart3_port *up = to_usart3_port(port); + u32 status, mask, pending; + irqreturn_t ret = IRQ_NONE; + + spin_lock(&port->lock); + + status = usart3_readl(up, CSR); + mask = usart3_readl(up, IMR); + pending = status & mask; + if (unlikely(!pending)) + goto out; + + ret = IRQ_HANDLED; + + do { + /* + * Consume the buffer and flip buffers if necessary. + */ + consume_rx_buffer(port, regs); + + /* Clear any break and error flags */ + usart3_writel(up, CR, USART3_BIT(RSTSTA)); + + if (pending & (USART3_BIT(OVRE) + | USART3_BIT(FRAME) + | USART3_BIT(PARE))) + handle_rx_error(port, status); + + if (pending & USART3_BIT(RXBRK)) { + if (up->break_active) { + up->break_active = 0; + } else { + up->break_active = 1; + port->icount.brk++; + uart_handle_break(port); + } + } + + if (pending & USART3_BIT(RIIC)) + port->icount.rng++; + if (pending & USART3_BIT(DSRIC)) + port->icount.dsr++; + if (pending & USART3_BIT(DCDIC)) { + port->icount.dcd++; + uart_handle_dcd_change + (port, status & USART3_BIT(DCD)); + } + if (pending & USART3_BIT(CTSIC)) { + port->icount.cts++; + uart_handle_cts_change + (port, status & USART3_BIT(CTS)); + } + if (pending & (USART3_BIT(RIIC) + | USART3_BIT(DSRIC) + | USART3_BIT(DCDIC) + | USART3_BIT(CTSIC))) + wake_up_interruptible(&port->info->delta_msr_wait); + + if (pending & USART3_BIT(ENDTX)) + handle_pdc_endtx(port, status); + + status = usart3_readl(up, CSR); + pending = status & usart3_readl(up, IMR); + } while (pending); + +out: + spin_unlock(&port->lock); + return ret; +} + +/* + * Return TIOCSER_TEMT when transmitter is not busy + */ +static unsigned int usart3_tx_empty(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + unsigned int ret = 0; + + if (usart3_readl(up, CSR) & USART3_BIT(TXEMPTY)) + ret = TIOCSER_TEMT; + + pr_debug("usart3: tx_empty returned %x\n", ret); + + return ret; +} + +static unsigned int usart3_get_mctrl(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + unsigned int ret = 0; + unsigned int status; + + status = usart3_readl(up, CSR); + if (status & USART3_BIT(DCD)) + ret |= TIOCM_CD; + if (status & USART3_BIT(CTS)) + ret |= TIOCM_CTS; + if (status & USART3_BIT(DSR)) + ret |= TIOCM_DSR; + if (status & USART3_BIT(RI)) + ret |= TIOCM_RI; + + pr_debug("usart3: get_mctrl returned %x\n", ret); + + return ret; +} + +static void usart3_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct usart3_port *up = to_usart3_port(port); + unsigned int control = 0; + + pr_debug("usart3: set_mctrl %x\n", mctrl); + + if (mctrl & TIOCM_RTS) + control |= USART3_BIT(RTSEN); + else + control |= USART3_BIT(RTSDIS); + + if (mctrl & TIOCM_DTR) + control |= USART3_BIT(DTREN); + else + control |= USART3_BIT(DTRDIS); + + usart3_writel(up, CR, control); +} + +static void usart3_break_ctl(struct uart_port *port, int break_state) +{ + struct usart3_port *up = to_usart3_port(port); + + pr_debug("usart3: break_ctl %u\n", break_state); + if (break_state != 0) + usart3_writel(up, CR, USART3_BIT(STTBRK)); + else + usart3_writel(up, CR, USART3_BIT(STPBRK)); +} + +static int usart3_startup(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + int ret; + + pr_debug("usart3: startup\n"); + + up->break_active = 0; + + /* Set up interrupt handler */ + ret = request_irq(port->irq, usart3_interrupt, 0, + port->info->tty->name, port); + if (ret) { + printk(KERN_ERR "usart3: Unable to request irq %d\n", + port->irq); + return ret; + } + + up->rx_dma = dma_map_single(port->dev, up->rx_buffer, + 2 * RX_BUFFER_SIZE, DMA_FROM_DEVICE); + up->tx_dma = dma_map_single(port->dev, port->info->xmit.buf, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + /* Initialize the PDC for RX (TX is done in start_tx) */ + up->rx_tail = 0; + pdc_writel(up, RPR, up->rx_dma); + pdc_writel(up, RCR, RX_BUFFER_SIZE); + pdc_writel(up, RNPR, up->rx_dma + RX_BUFFER_SIZE); + pdc_writel(up, RNCR, RX_BUFFER_SIZE); + pdc_writel(up, PTCR, PDC_BIT(PTCR_RXTEN)); + + /* Reset DMA state */ + pdc_writel(up, TNCR, 0); + pdc_writel(up, TCR, 0); + up->tx_dma_head = port->info->xmit.tail; + + /* + * Set a suitable timeout. 2000 bit periods corresponds to + * about 17 ms at 115200 bps + */ + usart3_writel(up, RTOR, 2000); + + /* Reset and enable receiver and transmitter */ + usart3_writel(up, CR, (USART3_BIT(RSTRX) + | USART3_BIT(RSTTX) + | USART3_BIT(RSTSTA))); + usart3_writel(up, CR, (USART3_BIT(RXEN) + | USART3_BIT(TXEN))); + + /* Enable timeout, end of rx, break and error interrupts */ + usart3_writel(up, IER, (USART3_BIT(TIMEOUT) + | USART3_BIT(ENDRX) + | USART3_BIT(RXBRK) + | USART3_BIT(OVRE) + | USART3_BIT(FRAME) + | USART3_BIT(PARE))); + + /* Arm the timeout counter */ + usart3_writel(up, CR, USART3_BIT(STTTO)); + + return 0; +} + +static void usart3_shutdown(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + + pr_debug("usart3: shutdown\n"); + + /* Disable all interrupts and reset any error flags */ + usart3_writel(up, IDR, -1L); + usart3_writel(up, CR, USART3_BIT(RSTSTA)); + + dma_unmap_single(port->dev, up->rx_dma, 2 * RX_BUFFER_SIZE, + DMA_FROM_DEVICE); + dma_unmap_single(port->dev, up->tx_dma, UART_XMIT_SIZE, + DMA_TO_DEVICE); + + free_irq(port->irq, port); +} + +static void usart3_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old) +{ + struct usart3_port *up = to_usart3_port(port); + unsigned int baud, quot, mode = 0; + unsigned int imr, flags; + + pr_debug("usart3: set_termios\n"); + + switch (termios->c_cflag & CSIZE) { + case CS5: + mode |= USART3_BF(CHRL, USART3_CHRL_5); + break; + case CS6: + mode |= USART3_BF(CHRL, USART3_CHRL_6); + break; + case CS7: + mode |= USART3_BF(CHRL, USART3_CHRL_7); + break; + default: + mode |= USART3_BF(CHRL, USART3_CHRL_8); + break; + } + + if (termios->c_cflag & CSTOPB) + mode |= USART3_BF(NBSTOP, USART3_NBSTOP_2); + + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & PARODD) + mode |= USART3_BF(PAR, USART3_PAR_ODD); + else + mode |= USART3_BF(PAR, USART3_PAR_EVEN); + } else { + mode |= USART3_BF(PAR, USART3_PAR_NONE); + } + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + quot = uart_get_divisor(port, baud); + + /* Bits to ignore, timeout, etc. TBD */ + + /* + * Save and disable interrupts + */ + spin_lock_irqsave(&port->lock, flags); + imr = usart3_readl(up, IMR); + usart3_writel(up, IDR, -1L); + spin_unlock_irqrestore(&port->lock, flags); + + /* + * Make sure transmitter is empty. If BRGR == 0, it is safest + * to do a reset, since waiting for the transmitter to be + * empty will take forever. + */ + if (usart3_readl(up, BRGR) != 0) { + while (!(usart3_readl(up, CSR) & USART3_BIT(TXRDY))) + barrier(); + } else { + usart3_writel(up, CR, (USART3_BIT(RSTTX) + | USART3_BIT(RSTRX))); + } + + pr_debug("usart3: Setting BRGR to %u (baud rate %u)...\n", quot, baud); + + /* Disable receiver and transmitter */ + usart3_writel(up, CR, (USART3_BIT(TXDIS) + | USART3_BIT(RXDIS))); + + /* Set the parity, stop bits and data size */ + usart3_writel(up, MR, mode); + + /* Set the baud rate and enable receiver and transmitter */ + usart3_writel(up, BRGR, quot); + usart3_writel(up, CR, (USART3_BIT(TXEN) + | USART3_BIT(RXEN))); + + /* Restore interrupts */ + usart3_writel(up, IER, imr); +} + +static const char *usart3_type(struct uart_port *port) +{ + return "USART3"; +} + +static void usart3_release_port(struct uart_port *port) +{ + pr_debug("usart3: release_port\n"); + iounmap(port->membase); + port->flags |= UPF_IOREMAP; +} + +static int usart3_request_port(struct uart_port *port) +{ + struct usart3_port *up = to_usart3_port(port); + + /* TODO: remove this */ + pr_debug("usart3: request_port\n"); + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, 0x400); + up->regs = port->membase; + port->flags &= ~UPF_IOREMAP; + } + return 0; +} + +static void usart3_config_port(struct uart_port *port, int flags) +{ + pr_debug("usart3: config_port\n"); + if (flags & UART_CONFIG_TYPE) { + if (usart3_request_port(port) == 0) + port->type = PORT_USART3; + } +} + +static int usart3_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_USART3) + ret = -EINVAL; + if (port->irq != ser->irq) + ret = -EINVAL; + if (ser->io_type != SERIAL_IO_MEM) + ret = -EINVAL; + if (port->uartclk / 16 != ser->baud_base) + ret = -EINVAL; + if ((void *)port->mapbase != ser->iomem_base) + ret = -EINVAL; + if (ser->hub6 != 0) + ret = -EINVAL; + + pr_debug("usart3_verify_port returned %d\n", ret); + + return ret; +} + +static struct uart_ops usart3_pops = { + .tx_empty = usart3_tx_empty, + .set_mctrl = usart3_set_mctrl, + .get_mctrl = usart3_get_mctrl, + .stop_tx = usart3_stop_tx, + .start_tx = usart3_start_tx, + .stop_rx = usart3_stop_rx, + .enable_ms = usart3_enable_ms, + .break_ctl = usart3_break_ctl, + .startup = usart3_startup, + .shutdown = usart3_shutdown, + .flush_buffer = usart3_flush_buffer, + .set_termios = usart3_set_termios, + .type = usart3_type, + .release_port = usart3_release_port, + .request_port = usart3_request_port, + .config_port = usart3_config_port, + .verify_port = usart3_verify_port, +}; + +static void __devinit initialize_port(struct usart3_port *up, + struct at32_device *adev) +{ + struct uart_port *port = &up->uart; + + spin_lock_init(&port->lock); + + port->mapbase = at32_get_iomem_base(adev, 0); + port->irq = at32_get_irq(adev); + + port->uartclk = at32_get_sclk_hz(adev, 0); + port->iotype = SERIAL_IO_MEM; + port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; + port->ops = &usart3_pops; + port->line = adev->id; + port->dev = &adev->dev; +} + +static struct usart3_port usart3_ports[NR_PORTS]; + +#ifdef CONFIG_SERIAL_USART3_CONSOLE + +static void usart3_console_write(struct console *console, const char *string, + unsigned int len) +{ + struct usart3_port *up = &usart3_ports[console->index]; + unsigned int imr, i; + unsigned long flags, ptsr; + + /* + * Save IMR, then disable interrupts + */ + local_irq_save(flags); + imr = usart3_readl(up, IMR); + usart3_writel(up, IDR, ~0UL); + local_irq_restore(flags); + + /* + * Save PDC state and disable PDC transmission + */ + ptsr = pdc_readl(up, PTSR); + pdc_writel(up, PTCR, PDC_BIT(PTCR_TXTDIS)); + + /* + * Now, do each character + */ + for (i = 0; i < len; i++, string++) { + char c = *string; + + /* + * If we're sending LF, send CR first... + */ + if (c == '\n') { + while (!(usart3_readl(up, CSR) + & USART3_BIT(TXRDY))) + ; + usart3_writel(up, THR, '\r'); + } + while (!(usart3_readl(up, CSR) & USART3_BIT(TXRDY))) + ; + usart3_writel(up, THR, c); + } + + /* + * Wait for transmitter to become empty and restore the IMR + * and PDC state. + */ + while (!(usart3_readl(up, CSR) & USART3_BIT(TXRDY))) + ; + + pdc_writel(up, PTCR, ptsr & PDC_BIT(PTCR_TXTEN)); + usart3_writel(up, IER, imr); +} + +static int __init usart3_console_setup(struct console *console, + char *options) +{ + struct at32_device *adev; + struct usart3_port *up; + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + if (console->index >= NR_PORTS) { + printk(KERN_ERR + "Can't use USART%u for console: index >= NR_PORTS\n", + console->index); + return -ENODEV; + } + + adev = at32_find_device("usart", console->index); + if (!adev) + return -ENXIO; + + up = &usart3_ports[console->index]; + port = &up->uart; + + ret = at32_enable_device(adev); + if (ret) + return ret; + + initialize_port(up, adev); + + port->membase = at32_map_iomem(adev, 0); + if (!port->membase) + return -ENOMEM; + + up->regs = port->membase; + + /* Set a fixed baud rate for now */ + usart3_writel(up, BRGR, 2); + + /* Make sure all interrupts are disabled and reset/enable the USART */ + usart3_writel(up, IDR, -1L); + usart3_writel(up, CR, (USART3_BIT(RSTRX) + | USART3_BIT(RSTTX) + | USART3_BIT(RSTSTA))); + usart3_writel(up, CR, (USART3_BIT(RXEN) + | USART3_BIT(TXEN))); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, console, baud, parity, bits, flow); +} + +static struct uart_driver usart3_reg; +static struct console usart3_console = { + .name = "ttyUS", + .write = usart3_console_write, + .device = uart_console_device, + .setup = usart3_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &usart3_reg, +}; + +static int __init usart3_console_init(void) +{ + register_console(&usart3_console); + return 0; +} +console_initcall(usart3_console_init); + +#define USART3_CONSOLE &usart3_console + +#else +#define USART3_CONSOLE NULL +#endif + +static struct uart_driver usart3_reg = { + .owner = THIS_MODULE, + .driver_name = "serial", + .devfs_name = "ttus/", + .dev_name = "ttyUS", + .major = SERIAL_USART3_MAJOR, + .minor = MINOR_START, + .nr = NR_PORTS, + .cons = USART3_CONSOLE, +}; + +static int usart3_serial_suspend(struct at32_device *adev, + pm_message_t state) +{ + struct usart3_port *port = at32_get_drvdata(adev); + int retval = 0; + + if (port) + retval = uart_suspend_port(&usart3_reg, &port->uart); + + return retval; +} + +static int usart3_serial_resume(struct at32_device *adev) +{ + struct usart3_port *port = at32_get_drvdata(adev); + int retval = 0; + + if (port) + retval = uart_resume_port(&usart3_reg, &port->uart); + + return retval; +} + +static int __devinit usart3_serial_probe(struct at32_device *adev) +{ + struct usart3_port *up; + int ret; + + if (adev->id >= NR_PORTS) { + printk(KERN_WARNING + "Ignoring USART%u, as NR_PORTS is only %u\n", + adev->id, NR_PORTS); + return -ENOMEM; + } + + up = &usart3_ports[adev->id]; + + /* + * If the port has already been set up as a console, we + * shouldn't enable it again. + */ + if (!up->uart.uartclk) { + ret = at32_enable_device(adev); + if (ret) + goto out; + + initialize_port(up, adev); + } + + /* + * The RX buffer must be cacheline aligned. If it's not, + * invalidating the cache could be disastrous... + * + * Fortunately, kmalloc() always returns cache-aligned memory. + */ + ret = -ENOMEM; + up->rx_buffer = kmalloc(2 * RX_BUFFER_SIZE, GFP_KERNEL); + if (!up->rx_buffer) + goto out_disable_dev; + + ret = uart_add_one_port(&usart3_reg, &up->uart); + if (ret) + goto out_free_rx_buffer; + + at32_set_drvdata(adev, up); + + return 0; + +out_free_rx_buffer: + kfree(up->rx_buffer); +out_disable_dev: + at32_disable_device(adev); +out: + return ret; +} + +static int __devexit usart3_serial_remove(struct at32_device *adev) +{ + struct usart3_port *port = at32_get_drvdata(adev); + int retval = 0; + + at32_set_drvdata(adev, NULL); + + if (port) { + retval = uart_remove_one_port(&usart3_reg, &port->uart); + at32_disable_device(adev); + kfree(port->rx_buffer); + kfree(port); + } + + return retval; +} + +static struct at32_driver usart3_serial_driver = { + .probe = usart3_serial_probe, + .remove = __devexit_p(usart3_serial_remove), + .suspend = usart3_serial_suspend, + .resume = usart3_serial_resume, + .driver = { + .name = "usart", + }, +}; + +static int __init usart3_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: USART3 driver $Revision: 1.6 $\n"); + + ret = uart_register_driver(&usart3_reg); + if (ret) + return ret; + + ret = at32_driver_register(&usart3_serial_driver); + if (ret) + uart_unregister_driver(&usart3_reg); + + return ret; +} + +static void __exit usart3_exit(void) +{ + at32_driver_unregister(&usart3_serial_driver); + uart_unregister_driver(&usart3_reg); +} + +module_init(usart3_init); +module_exit(usart3_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Atmel USART3 serial driver"); +MODULE_AUTHOR("Haavard Skinnemoen "); diff -Nur linux-2.6.16.11/drivers/spi/Kconfig linux-2.6.16.11-avr32-20060626/drivers/spi/Kconfig --- linux-2.6.16.11/drivers/spi/Kconfig 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/spi/Kconfig 2006-06-26 11:33:53.000000000 +0200 @@ -65,6 +65,13 @@ need it. You only need to select this explicitly to support driver modules that aren't part of this kernel tree. +config SPI_ATMEL + tristate "Atmel SPI Controller" + depends on AVR32 && SPI_MASTER + help + This selects a driver for the Atmel SPI Controller, present on + many AT32 (AVR32) and AT91 (ARM) chips. + config SPI_BUTTERFLY tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)" depends on SPI_MASTER && PARPORT && EXPERIMENTAL diff -Nur linux-2.6.16.11/drivers/spi/Makefile linux-2.6.16.11-avr32-20060626/drivers/spi/Makefile --- linux-2.6.16.11/drivers/spi/Makefile 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/spi/Makefile 2006-06-26 11:33:53.000000000 +0200 @@ -12,6 +12,7 @@ # SPI master controller drivers (bus) obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o +obj-$(CONFIG_SPI_ATMEL) += spi_atmel.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o # ... add above this line ... diff -Nur linux-2.6.16.11/drivers/spi/spi_atmel.c linux-2.6.16.11-avr32-20060626/drivers/spi/spi_atmel.c --- linux-2.6.16.11/drivers/spi/spi_atmel.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/spi/spi_atmel.c 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,407 @@ +/* + * Driver for Atmel AT32 and AT91 SPI Controllers + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "spi_atmel.h" + +struct atmel_spi { + spinlock_t lock; + void __iomem *regs; + struct list_head queue; + struct spi_transfer *current_transfer; + unsigned long long bus_hz; + struct at32_device *adev; +}; + +/* + * Submit current_transfer for DMA. + */ +static void spi_atmel_dma_start(struct spi_master *master) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_message *msg; + struct spi_transfer *xfer; + u32 mr; + + BUG_ON(list_empty(&as->queue)); + + msg = list_entry(as->queue.next, struct spi_message, queue); + xfer = as->current_transfer; + if (xfer->tx_buf) + spi_writel(as, TPR, xfer->tx_dma); + else + /* Send undefined data. rx_dma is as good as anything. */ + spi_writel(as, TPR, xfer->rx_dma); + + if (xfer->rx_buf) { + spi_writel(as, RPR, xfer->rx_dma); + spi_writel(as, RCR, xfer->len); + spi_writel(as, PTCR, SPI_BIT(RXTEN)); + } else { + /* + * Don't bother to set up a buffer for RX if it wasn't + * provided by the caller. We'll just ignore the + * overrun bit. + */ + spi_writel(as, RCR, 0); + } + + /* Select the chip */ + mr = spi_readl(as, MR); + mr = SPI_BFINS(PCS, ~(1 << msg->spi->chip_select), mr); + spi_writel(as, MR, mr); + + /* Start the transfer and enable interrupts */ + dev_dbg(&as->adev->dev, "starting transfer with len %u (%p/%p)\n", + xfer->len, xfer->tx_buf, xfer->rx_buf); + + wmb(); + spi_writel(as, TCR, xfer->len); + spi_writel(as, PTCR, SPI_BIT(TXTEN)); + spi_writel(as, IER, SPI_BIT(ENDTX)); +} + +static irqreturn_t spi_atmel_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct spi_master *master = dev_id; + struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_message *msg; + struct spi_transfer *xfer; + u32 status, pending; + int ret = IRQ_NONE; + +restart: + status = spi_readl(as, SR); + pending = status & spi_readl(as, IMR); + + if (pending & SPI_BIT(ENDTX)) { + ret = IRQ_HANDLED; + + /* + * Wait until the TX register is empty before + * submitting the next message. + */ + spi_writel(as, IDR, SPI_BIT(ENDTX)); + spi_writel(as, IER, SPI_BIT(TXEMPTY)); + goto restart; + } + + if (pending & SPI_BIT(TXEMPTY)) { + ret = IRQ_HANDLED; + + spi_writel(as, IDR, SPI_BIT(TXEMPTY)); + + xfer = as->current_transfer; + msg = list_entry(as->queue.next, struct spi_message, queue); + msg->actual_length += xfer->len; + + if (!msg->is_dma_mapped) { + if (xfer->tx_buf) + dma_unmap_single(&as->adev->dev, + xfer->tx_dma, xfer->len, + DMA_TO_DEVICE); + if (xfer->rx_buf) + dma_unmap_single(&as->adev->dev, + xfer->rx_dma, xfer->len, + DMA_FROM_DEVICE); + } + + if (msg->transfers.prev == &xfer->transfer_list) { + + /* + * We're done with this message. Submit the + * next one if any. + */ + spin_lock(&as->lock); + + msg->status = 0; + list_del(&msg->queue); + + if (list_empty(&as->queue)) { + as->current_transfer = NULL; + spi_writel(as, PTCR, (SPI_BIT(RXTDIS) + | SPI_BIT(TXTDIS))); + } else { + msg = list_entry(as->queue.next, + struct spi_message, queue); + xfer = list_entry(msg->transfers.next, + struct spi_transfer, + transfer_list); + as->current_transfer = xfer; + spi_atmel_dma_start(master); + } + + spin_unlock(&as->lock); + + dev_dbg(&as->adev->dev, + "xfer complete: %u bytes transferred\n", + msg->actual_length); + msg->complete(msg->context); + } else { + /* + * Not done yet. Submit the next transfer in + * the message. + */ + xfer = list_entry(xfer->transfer_list.next, + struct spi_transfer, + transfer_list); + as->current_transfer = xfer; + spi_atmel_dma_start(master); + } + } + + return ret; +} + +static int spi_atmel_setup(struct spi_device *spi) +{ + struct atmel_spi *as; + u32 scbr, csr; + + as = spi_master_get_devdata(spi->master); + + if (!spi->max_speed_hz) { + dev_dbg(&as->adev->dev, "setup: invalid speed %u\n", + spi->max_speed_hz); + return -EINVAL; + } + else if (spi->chip_select > spi->master->num_chipselect) { + dev_dbg(&as->adev->dev, "setup: invalid chipselect %u (%u defined)\n", + spi->chip_select, spi->master->num_chipselect); + return -EINVAL; + } + else if (spi->bits_per_word < 8 || spi->bits_per_word > 16) { + dev_dbg(&as->adev->dev, "setup: invalid bits_per_word %u (8 to 16)\n", + spi->bits_per_word); + return -EINVAL; + } + else if (spi->mode & SPI_CS_HIGH) { + dev_dbg(&as->adev->dev, "setup: invalid mode %u\n", spi->mode); + return -EINVAL; + } + + scbr = ((as->bus_hz / 2 + spi->max_speed_hz - 1) / spi->max_speed_hz); + if (scbr >= 1 << SPI_SCBR_SIZE) { + dev_dbg(&as->adev->dev, "scbr out of range: %u\n", scbr); + return -EINVAL; + } + + csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, spi->bits_per_word - 8); + if (spi->mode & SPI_CPOL) + csr |= SPI_BIT(CPOL); + if (!(spi->mode & SPI_CPHA)) + csr |= SPI_BIT(NCPHA); + + /* TODO: DLYBS and DLYBCT */ + csr |= SPI_BF(DLYBS, 10); + csr |= SPI_BF(DLYBCT, 10); + + dev_dbg(&as->adev->dev, + "setup: speed %u cs %u bpw %u mode 0x%x -> 0x%x\n", + spi->max_speed_hz, spi->chip_select, spi->bits_per_word, + spi->mode, csr); + + spi_writel(as, CSR0 + 4 * spi->chip_select, csr); + + return 0; +} + +static int spi_atmel_transfer(struct spi_device *spi, + struct spi_message *msg) +{ + struct atmel_spi *as; + struct spi_transfer *xfer; + unsigned long flags; + + as = spi_master_get_devdata(spi->master); + + dev_dbg(&as->adev->dev, "new message submitted from %s\n", + spi->dev.bus_id); + +#ifdef DEBUG + list_for_each_entry(xfer, &msg->transfers, transfer_list) + dev_dbg(&as->adev->dev, " transfer: len %u [%p/%p]\n", + xfer->len, xfer->tx_buf, xfer->rx_buf); +#endif + + if (unlikely(list_empty(&msg->transfers))) + return -EINVAL; + + if (!msg->is_dma_mapped) { + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (xfer->tx_buf) + xfer->tx_dma = dma_map_single(&as->adev->dev, + (void *)xfer->tx_buf, + xfer->len, + DMA_TO_DEVICE); + if (xfer->rx_buf) + xfer->rx_dma = dma_map_single(&as->adev->dev, + xfer->rx_buf, + xfer->len, + DMA_FROM_DEVICE); + } + } + + msg->status = -EINPROGRESS; + msg->actual_length = 0; + + spin_lock_irqsave(&as->lock, flags); + list_add_tail(&msg->queue, &as->queue); + if (!as->current_transfer) { + dev_dbg(&as->adev->dev, + "controller is idle, starting transfer\n"); + as->current_transfer = list_entry(msg->transfers.next, + struct spi_transfer, + transfer_list); + spi_atmel_dma_start(spi->master); + } + spin_unlock_irqrestore(&as->lock, flags); + + return 0; +} + +static int __devinit spi_atmel_probe(struct at32_device *adev) +{ + struct spi_master *master; + struct atmel_spi *as; + int ret; + + ret = at32_enable_device(adev); + if (ret) + goto out; + + ret = -ENOMEM; + master = spi_alloc_master(&adev->dev, sizeof(struct atmel_spi)); + if (!spi_master_get(master)) + goto out_disable_device; + + as = spi_master_get_devdata(master); + + as->regs = at32_map_iomem(adev, 0); + if (!as->regs) + goto out_put_master; + + ret = request_irq(at32_get_irq(adev), spi_atmel_interrupt, 0, + adev->dev.bus_id, master); + if (ret) + goto out_unmap_regs; + + spin_lock_init(&as->lock); + INIT_LIST_HEAD(&as->queue); + as->bus_hz = at32_get_sclk_hz(adev, 0); + as->adev = adev; + + /* Hmm...why isn't zero a valid ID? */ + master->bus_num = adev->id + 1; + master->num_chipselect = 4; + master->setup = spi_atmel_setup; + master->transfer = spi_atmel_transfer; + + /* Initialize the hardware */ + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_writel(as, MR, SPI_BIT(MSTR)); + spi_writel(as, CR, SPI_BIT(SPIEN)); + + ret = spi_register_master(master); + if (ret) + goto out_reset_hw; + + dev_info(&adev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n", + at32_get_iomem_base(adev, 0), at32_get_irq(adev)); + + at32_set_drvdata(adev, master); + + return 0; + +out_reset_hw: + spi_writel(as, CR, SPI_BIT(SWRST)); + free_irq(at32_get_irq(adev), master); +out_unmap_regs: + iounmap(as->regs); +out_put_master: + spi_master_put(master); +out_disable_device: + at32_disable_device(adev); +out: + return ret; +} + +static int __devexit spi_atmel_remove(struct at32_device *adev) +{ + struct spi_master *master = at32_get_drvdata(adev); + struct spi_message *msg; + struct atmel_spi *as; + + BUG_ON(irqs_disabled()); + + if (master) { + as = spi_master_get_devdata(master); + + /* + * Reset the hardware and make sure all pending IRQs + * are processed. + */ + spin_lock_irq(&as->lock); + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_readl(as, SR); + spin_unlock_irq(&as->lock); + + /* Terminate all queued transfers */ + list_for_each_entry(msg, &as->queue, queue) { + msg->status = -ESHUTDOWN; + msg->complete(msg->context); + } + + spi_unregister_master(master); + free_irq(at32_get_irq(adev), master); + iounmap(as->regs); + spi_master_put(master); + at32_disable_device(adev); + } + + return 0; +} + +static struct at32_driver spi_atmel_driver = { + .probe = spi_atmel_probe, + .remove = __devexit_p(spi_atmel_remove), + .driver = { + .name = "spi", + }, +}; + +static int __init spi_atmel_init(void) +{ + return at32_driver_register(&spi_atmel_driver); +} +module_init(spi_atmel_init); + +static void __exit spi_atmel_exit(void) +{ + at32_driver_unregister(&spi_atmel_driver); +} +module_exit(spi_atmel_exit); + +MODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver"); +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.16.11/drivers/spi/spi_atmel.h linux-2.6.16.11-avr32-20060626/drivers/spi/spi_atmel.h --- linux-2.6.16.11/drivers/spi/spi_atmel.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/spi/spi_atmel.h 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,178 @@ +/* + * Register definitions for SPI + * + * Serial Peripheral Interface + */ +#ifndef __ASM_AVR32_SPI_H__ +#define __ASM_AVR32_SPI_H__ + +/* SPI register offsets */ +#define SPI_CR 0x0000 +#define SPI_MR 0x0004 +#define SPI_RDR 0x0008 +#define SPI_TDR 0x000c +#define SPI_SR 0x0010 +#define SPI_IER 0x0014 +#define SPI_IDR 0x0018 +#define SPI_IMR 0x001c +#define SPI_CSR0 0x0030 +#define SPI_CSR1 0x0034 +#define SPI_CSR2 0x0038 +#define SPI_CSR3 0x003c +#define SPI_RPR 0x0100 +#define SPI_RCR 0x0104 +#define SPI_TPR 0x0108 +#define SPI_TCR 0x010c +#define SPI_RNPR 0x0110 +#define SPI_RNCR 0x0114 +#define SPI_TNPR 0x0118 +#define SPI_TNCR 0x011c +#define SPI_PTCR 0x0120 +#define SPI_PTSR 0x0124 + +/* Bitfields in CR */ +#define SPI_SPIEN_OFFSET 0 +#define SPI_SPIEN_SIZE 1 +#define SPI_SPIDIS_OFFSET 1 +#define SPI_SPIDIS_SIZE 1 +#define SPI_SWRST_OFFSET 7 +#define SPI_SWRST_SIZE 1 +#define SPI_LASTXFER_OFFSET 24 +#define SPI_LASTXFER_SIZE 1 + +/* Bitfields in MR */ +#define SPI_MSTR_OFFSET 0 +#define SPI_MSTR_SIZE 1 +#define SPI_PS_OFFSET 1 +#define SPI_PS_SIZE 1 +#define SPI_PCSDEC_OFFSET 2 +#define SPI_PCSDEC_SIZE 1 +#define SPI_FDIV_OFFSET 3 +#define SPI_FDIV_SIZE 1 +#define SPI_MODFDIS_OFFSET 4 +#define SPI_MODFDIS_SIZE 1 +#define SPI_LLB_OFFSET 7 +#define SPI_LLB_SIZE 1 +#define SPI_PCS_OFFSET 16 +#define SPI_PCS_SIZE 4 +#define SPI_DLYBCS_OFFSET 24 +#define SPI_DLYBCS_SIZE 8 + +/* Bitfields in RDR */ +#define SPI_RD_OFFSET 0 +#define SPI_RD_SIZE 16 + +/* Bitfields in TDR */ +#define SPI_TD_OFFSET 0 +#define SPI_TD_SIZE 16 + +/* Bitfields in SR */ +#define SPI_SPIENS_OFFSET 16 +#define SPI_SPIENS_SIZE 1 + +/* Bitfields in IER */ + +/* Bitfields in IDR */ +#define SPI_RDRF_OFFSET 0 +#define SPI_RDRF_SIZE 1 +#define SPI_TDRE_OFFSET 1 +#define SPI_TDRE_SIZE 1 +#define SPI_MODF_OFFSET 2 +#define SPI_MODF_SIZE 1 +#define SPI_OVRES_OFFSET 3 +#define SPI_OVRES_SIZE 1 +#define SPI_ENDRX_OFFSET 4 +#define SPI_ENDRX_SIZE 1 +#define SPI_ENDTX_OFFSET 5 +#define SPI_ENDTX_SIZE 1 +#define SPI_RXBUFF_OFFSET 6 +#define SPI_RXBUFF_SIZE 1 +#define SPI_TXBUFE_OFFSET 7 +#define SPI_TXBUFE_SIZE 1 +#define SPI_NSSR_OFFSET 8 +#define SPI_NSSR_SIZE 1 +#define SPI_TXEMPTY_OFFSET 9 +#define SPI_TXEMPTY_SIZE 1 + +/* Bitfields in IMR */ + +/* Bitfields in CSR0 */ +#define SPI_CPOL_OFFSET 0 +#define SPI_CPOL_SIZE 1 +#define SPI_NCPHA_OFFSET 1 +#define SPI_NCPHA_SIZE 1 +#define SPI_CSAAT_OFFSET 3 +#define SPI_CSAAT_SIZE 1 +#define SPI_BITS_OFFSET 4 +#define SPI_BITS_SIZE 4 +#define SPI_SCBR_OFFSET 8 +#define SPI_SCBR_SIZE 8 +#define SPI_DLYBS_OFFSET 16 +#define SPI_DLYBS_SIZE 8 +#define SPI_DLYBCT_OFFSET 24 +#define SPI_DLYBCT_SIZE 8 + +/* Bitfields in CSR1 */ + +/* Bitfields in CSR2 */ + +/* Bitfields in CSR3 */ + +/* Bitfields in RPR */ + +/* Bitfields in RCR */ +#define SPI_RXCTR_OFFSET 0 +#define SPI_RXCTR_SIZE 16 + +/* Bitfields in TPR */ + +/* Bitfields in TCR */ +#define SPI_TXCTR_OFFSET 0 +#define SPI_TXCTR_SIZE 16 + +/* Bitfields in RNPR */ + +/* Bitfields in RNCR */ +#define SPI_RXNCR_OFFSET 0 +#define SPI_RXNCR_SIZE 16 + +/* Bitfields in TNPR */ + +/* Bitfields in TNCR */ +#define SPI_TXNCR_OFFSET 0 +#define SPI_TXNCR_SIZE 16 + +/* Bitfields in PTCR */ +#define SPI_RXTEN_OFFSET 0 +#define SPI_RXTEN_SIZE 1 +#define SPI_RXTDIS_OFFSET 1 +#define SPI_RXTDIS_SIZE 1 +#define SPI_TXTEN_OFFSET 8 +#define SPI_TXTEN_SIZE 1 +#define SPI_TXTDIS_OFFSET 9 +#define SPI_TXTDIS_SIZE 1 + +/* Bitfields in PTSR */ + +/* Constants for BITS */ +#define SPI_BITS_8_BPT 0 +#define SPI_BITS_9_BPT 1 +#define SPI_BITS_10_BPT 2 +#define SPI_BITS_11_BPT 3 +#define SPI_BITS_12_BPT 4 +#define SPI_BITS_13_BPT 5 +#define SPI_BITS_14_BPT 6 +#define SPI_BITS_15_BPT 7 +#define SPI_BITS_16_BPT 8 + +/* Bit manipulation macros */ +#define SPI_BIT(name) (1 << SPI_##name##_OFFSET) +#define SPI_BF(name,value) (((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET) +#define SPI_BFEXT(name,value) (((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1)) +#define SPI_BFINS(name,value,old) (((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) | SPI_BF(name,value)) + +/* Register access macros */ +#define spi_readl(port,reg) readl((port)->regs + SPI_##reg) +#define spi_writel(port,reg,value) writel((value), (port)->regs + SPI_##reg) + +#endif /* __ASM_AVR32_SPI_H__ */ diff -Nur linux-2.6.16.11/drivers/spi/spi.c linux-2.6.16.11-avr32-20060626/drivers/spi/spi.c --- linux-2.6.16.11/drivers/spi/spi.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/spi/spi.c 2006-06-26 11:33:53.000000000 +0200 @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - +#define DEBUG #include #include #include @@ -223,6 +223,11 @@ proxy->controller_state = NULL; proxy->dev.release = spidev_release; + /* + * why is setup being called here, long before we know what + * parameters to use? + */ +#if 0 /* drivers may modify this default i/o setup */ status = master->setup(proxy); if (status < 0) { @@ -230,6 +235,7 @@ "setup", proxy->dev.bus_id, status); goto fail; } +#endif /* driver core catches callers that misbehave by defining * devices that already exist. @@ -366,6 +372,7 @@ class_device_initialize(&master->cdev); master->cdev.class = &spi_master_class; + kobj_set_kset_s(&master->cdev, spi_master_class.subsys); master->cdev.dev = get_device(dev); spi_master_set_devdata(master, &master[1]); diff -Nur linux-2.6.16.11/drivers/spi/spi.c.orig linux-2.6.16.11-avr32-20060626/drivers/spi/spi.c.orig --- linux-2.6.16.11/drivers/spi/spi.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/spi/spi.c.orig 2006-03-20 06:53:29.000000000 +0100 @@ -0,0 +1,641 @@ +/* + * spi.c - SPI init/core code + * + * Copyright (C) 2005 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + + +/* SPI bustype and spi_master class are registered after board init code + * provides the SPI device tables, ensuring that both are present by the + * time controller driver registration causes spi_devices to "enumerate". + */ +static void spidev_release(struct device *dev) +{ + const struct spi_device *spi = to_spi_device(dev); + + /* spi masters may cleanup for released devices */ + if (spi->master->cleanup) + spi->master->cleanup(spi); + + spi_master_put(spi->master); + kfree(dev); +} + +static ssize_t +modalias_show(struct device *dev, struct device_attribute *a, char *buf) +{ + const struct spi_device *spi = to_spi_device(dev); + + return snprintf(buf, BUS_ID_SIZE + 1, "%s\n", spi->modalias); +} + +static struct device_attribute spi_dev_attrs[] = { + __ATTR_RO(modalias), + __ATTR_NULL, +}; + +/* modalias support makes "modprobe $MODALIAS" new-style hotplug work, + * and the sysfs version makes coldplug work too. + */ + +static int spi_match_device(struct device *dev, struct device_driver *drv) +{ + const struct spi_device *spi = to_spi_device(dev); + + return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0; +} + +static int spi_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + const struct spi_device *spi = to_spi_device(dev); + + envp[0] = buffer; + snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias); + envp[1] = NULL; + return 0; +} + +#ifdef CONFIG_PM + +/* + * NOTE: the suspend() method for an spi_master controller driver + * should verify that all its child devices are marked as suspended; + * suspend requests delivered through sysfs power/state files don't + * enforce such constraints. + */ +static int spi_suspend(struct device *dev, pm_message_t message) +{ + int value; + struct spi_driver *drv = to_spi_driver(dev->driver); + + if (!drv || !drv->suspend) + return 0; + + /* suspend will stop irqs and dma; no more i/o */ + value = drv->suspend(to_spi_device(dev), message); + if (value == 0) + dev->power.power_state = message; + return value; +} + +static int spi_resume(struct device *dev) +{ + int value; + struct spi_driver *drv = to_spi_driver(dev->driver); + + if (!drv || !drv->resume) + return 0; + + /* resume may restart the i/o queue */ + value = drv->resume(to_spi_device(dev)); + if (value == 0) + dev->power.power_state = PMSG_ON; + return value; +} + +#else +#define spi_suspend NULL +#define spi_resume NULL +#endif + +struct bus_type spi_bus_type = { + .name = "spi", + .dev_attrs = spi_dev_attrs, + .match = spi_match_device, + .uevent = spi_uevent, + .suspend = spi_suspend, + .resume = spi_resume, +}; +EXPORT_SYMBOL_GPL(spi_bus_type); + + +static int spi_drv_probe(struct device *dev) +{ + const struct spi_driver *sdrv = to_spi_driver(dev->driver); + + return sdrv->probe(to_spi_device(dev)); +} + +static int spi_drv_remove(struct device *dev) +{ + const struct spi_driver *sdrv = to_spi_driver(dev->driver); + + return sdrv->remove(to_spi_device(dev)); +} + +static void spi_drv_shutdown(struct device *dev) +{ + const struct spi_driver *sdrv = to_spi_driver(dev->driver); + + sdrv->shutdown(to_spi_device(dev)); +} + +int spi_register_driver(struct spi_driver *sdrv) +{ + sdrv->driver.bus = &spi_bus_type; + if (sdrv->probe) + sdrv->driver.probe = spi_drv_probe; + if (sdrv->remove) + sdrv->driver.remove = spi_drv_remove; + if (sdrv->shutdown) + sdrv->driver.shutdown = spi_drv_shutdown; + return driver_register(&sdrv->driver); +} +EXPORT_SYMBOL_GPL(spi_register_driver); + +/*-------------------------------------------------------------------------*/ + +/* SPI devices should normally not be created by SPI device drivers; that + * would make them board-specific. Similarly with SPI master drivers. + * Device registration normally goes into like arch/.../mach.../board-YYY.c + * with other readonly (flashable) information about mainboard devices. + */ + +struct boardinfo { + struct list_head list; + unsigned n_board_info; + struct spi_board_info board_info[0]; +}; + +static LIST_HEAD(board_list); +static DECLARE_MUTEX(board_lock); + + +/* On typical mainboards, this is purely internal; and it's not needed + * after board init creates the hard-wired devices. Some development + * platforms may not be able to use spi_register_board_info though, and + * this is exported so that for example a USB or parport based adapter + * driver could add devices (which it would learn about out-of-band). + */ +struct spi_device *__init_or_module +spi_new_device(struct spi_master *master, struct spi_board_info *chip) +{ + struct spi_device *proxy; + struct device *dev = master->cdev.dev; + int status; + + /* NOTE: caller did any chip->bus_num checks necessary */ + + if (!spi_master_get(master)) + return NULL; + + proxy = kzalloc(sizeof *proxy, GFP_KERNEL); + if (!proxy) { + dev_err(dev, "can't alloc dev for cs%d\n", + chip->chip_select); + goto fail; + } + proxy->master = master; + proxy->chip_select = chip->chip_select; + proxy->max_speed_hz = chip->max_speed_hz; + proxy->irq = chip->irq; + proxy->modalias = chip->modalias; + + snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, + "%s.%u", master->cdev.class_id, + chip->chip_select); + proxy->dev.parent = dev; + proxy->dev.bus = &spi_bus_type; + proxy->dev.platform_data = (void *) chip->platform_data; + proxy->controller_data = chip->controller_data; + proxy->controller_state = NULL; + proxy->dev.release = spidev_release; + + /* drivers may modify this default i/o setup */ + status = master->setup(proxy); + if (status < 0) { + dev_dbg(dev, "can't %s %s, status %d\n", + "setup", proxy->dev.bus_id, status); + goto fail; + } + + /* driver core catches callers that misbehave by defining + * devices that already exist. + */ + status = device_register(&proxy->dev); + if (status < 0) { + dev_dbg(dev, "can't %s %s, status %d\n", + "add", proxy->dev.bus_id, status); + goto fail; + } + dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id); + return proxy; + +fail: + spi_master_put(master); + kfree(proxy); + return NULL; +} +EXPORT_SYMBOL_GPL(spi_new_device); + +/* + * Board-specific early init code calls this (probably during arch_initcall) + * with segments of the SPI device table. Any device nodes are created later, + * after the relevant parent SPI controller (bus_num) is defined. We keep + * this table of devices forever, so that reloading a controller driver will + * not make Linux forget about these hard-wired devices. + * + * Other code can also call this, e.g. a particular add-on board might provide + * SPI devices through its expansion connector, so code initializing that board + * would naturally declare its SPI devices. + * + * The board info passed can safely be __initdata ... but be careful of + * any embedded pointers (platform_data, etc), they're copied as-is. + */ +int __init +spi_register_board_info(struct spi_board_info const *info, unsigned n) +{ + struct boardinfo *bi; + + bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL); + if (!bi) + return -ENOMEM; + bi->n_board_info = n; + memcpy(bi->board_info, info, n * sizeof *info); + + down(&board_lock); + list_add_tail(&bi->list, &board_list); + up(&board_lock); + return 0; +} +EXPORT_SYMBOL_GPL(spi_register_board_info); + +/* FIXME someone should add support for a __setup("spi", ...) that + * creates board info from kernel command lines + */ + +static void __init_or_module +scan_boardinfo(struct spi_master *master) +{ + struct boardinfo *bi; + struct device *dev = master->cdev.dev; + + down(&board_lock); + list_for_each_entry(bi, &board_list, list) { + struct spi_board_info *chip = bi->board_info; + unsigned n; + + for (n = bi->n_board_info; n > 0; n--, chip++) { + if (chip->bus_num != master->bus_num) + continue; + /* some controllers only have one chip, so they + * might not use chipselects. otherwise, the + * chipselects are numbered 0..max. + */ + if (chip->chip_select >= master->num_chipselect + && master->num_chipselect) { + dev_dbg(dev, "cs%d > max %d\n", + chip->chip_select, + master->num_chipselect); + continue; + } + (void) spi_new_device(master, chip); + } + } + up(&board_lock); +} + +/*-------------------------------------------------------------------------*/ + +static void spi_master_release(struct class_device *cdev) +{ + struct spi_master *master; + + master = container_of(cdev, struct spi_master, cdev); + kfree(master); +} + +static struct class spi_master_class = { + .name = "spi_master", + .owner = THIS_MODULE, + .release = spi_master_release, +}; + + +/** + * spi_alloc_master - allocate SPI master controller + * @dev: the controller, possibly using the platform_bus + * @size: how much driver-private data to preallocate; the pointer to this + * memory is in the class_data field of the returned class_device, + * accessible with spi_master_get_devdata(). + * + * This call is used only by SPI master controller drivers, which are the + * only ones directly touching chip registers. It's how they allocate + * an spi_master structure, prior to calling spi_add_master(). + * + * This must be called from context that can sleep. It returns the SPI + * master structure on success, else NULL. + * + * The caller is responsible for assigning the bus number and initializing + * the master's methods before calling spi_add_master(); and (after errors + * adding the device) calling spi_master_put() to prevent a memory leak. + */ +struct spi_master * __init_or_module +spi_alloc_master(struct device *dev, unsigned size) +{ + struct spi_master *master; + + if (!dev) + return NULL; + + master = kzalloc(size + sizeof *master, SLAB_KERNEL); + if (!master) + return NULL; + + class_device_initialize(&master->cdev); + master->cdev.class = &spi_master_class; + master->cdev.dev = get_device(dev); + spi_master_set_devdata(master, &master[1]); + + return master; +} +EXPORT_SYMBOL_GPL(spi_alloc_master); + +/** + * spi_register_master - register SPI master controller + * @master: initialized master, originally from spi_alloc_master() + * + * SPI master controllers connect to their drivers using some non-SPI bus, + * such as the platform bus. The final stage of probe() in that code + * includes calling spi_register_master() to hook up to this SPI bus glue. + * + * SPI controllers use board specific (often SOC specific) bus numbers, + * and board-specific addressing for SPI devices combines those numbers + * with chip select numbers. Since SPI does not directly support dynamic + * device identification, boards need configuration tables telling which + * chip is at which address. + * + * This must be called from context that can sleep. It returns zero on + * success, else a negative error code (dropping the master's refcount). + * After a successful return, the caller is responsible for calling + * spi_unregister_master(). + */ +int __init_or_module +spi_register_master(struct spi_master *master) +{ + static atomic_t dyn_bus_id = ATOMIC_INIT(0); + struct device *dev = master->cdev.dev; + int status = -ENODEV; + int dynamic = 0; + + if (!dev) + return -ENODEV; + + /* convention: dynamically assigned bus IDs count down from the max */ + if (master->bus_num == 0) { + master->bus_num = atomic_dec_return(&dyn_bus_id); + dynamic = 1; + } + + /* register the device, then userspace will see it. + * registration fails if the bus ID is in use. + */ + snprintf(master->cdev.class_id, sizeof master->cdev.class_id, + "spi%u", master->bus_num); + status = class_device_add(&master->cdev); + if (status < 0) + goto done; + dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, + dynamic ? " (dynamic)" : ""); + + /* populate children from any spi device tables */ + scan_boardinfo(master); + status = 0; +done: + return status; +} +EXPORT_SYMBOL_GPL(spi_register_master); + + +static int __unregister(struct device *dev, void *unused) +{ + /* note: before about 2.6.14-rc1 this would corrupt memory: */ + spi_unregister_device(to_spi_device(dev)); + return 0; +} + +/** + * spi_unregister_master - unregister SPI master controller + * @master: the master being unregistered + * + * This call is used only by SPI master controller drivers, which are the + * only ones directly touching chip registers. + * + * This must be called from context that can sleep. + */ +void spi_unregister_master(struct spi_master *master) +{ + (void) device_for_each_child(master->cdev.dev, NULL, __unregister); + class_device_unregister(&master->cdev); +} +EXPORT_SYMBOL_GPL(spi_unregister_master); + +/** + * spi_busnum_to_master - look up master associated with bus_num + * @bus_num: the master's bus number + * + * This call may be used with devices that are registered after + * arch init time. It returns a refcounted pointer to the relevant + * spi_master (which the caller must release), or NULL if there is + * no such master registered. + */ +struct spi_master *spi_busnum_to_master(u16 bus_num) +{ + if (bus_num) { + char name[8]; + struct kobject *bus; + + snprintf(name, sizeof name, "spi%u", bus_num); + bus = kset_find_obj(&spi_master_class.subsys.kset, name); + if (bus) + return container_of(bus, struct spi_master, cdev.kobj); + } + return NULL; +} +EXPORT_SYMBOL_GPL(spi_busnum_to_master); + + +/*-------------------------------------------------------------------------*/ + +static void spi_complete(void *arg) +{ + complete(arg); +} + +/** + * spi_sync - blocking/synchronous SPI data transfers + * @spi: device with which data will be exchanged + * @message: describes the data transfers + * + * This call may only be used from a context that may sleep. The sleep + * is non-interruptible, and has no timeout. Low-overhead controller + * drivers may DMA directly into and out of the message buffers. + * + * Note that the SPI device's chip select is active during the message, + * and then is normally disabled between messages. Drivers for some + * frequently-used devices may want to minimize costs of selecting a chip, + * by leaving it selected in anticipation that the next message will go + * to the same chip. (That may increase power usage.) + * + * Also, the caller is guaranteeing that the memory associated with the + * message will not be freed before this call returns. + * + * The return value is a negative error code if the message could not be + * submitted, else zero. When the value is zero, then message->status is + * also defined: it's the completion code for the transfer, either zero + * or a negative error code from the controller driver. + */ +int spi_sync(struct spi_device *spi, struct spi_message *message) +{ + DECLARE_COMPLETION(done); + int status; + + message->complete = spi_complete; + message->context = &done; + status = spi_async(spi, message); + if (status == 0) + wait_for_completion(&done); + message->context = NULL; + return status; +} +EXPORT_SYMBOL_GPL(spi_sync); + +#define SPI_BUFSIZ (SMP_CACHE_BYTES) + +static u8 *buf; + +/** + * spi_write_then_read - SPI synchronous write followed by read + * @spi: device with which data will be exchanged + * @txbuf: data to be written (need not be dma-safe) + * @n_tx: size of txbuf, in bytes + * @rxbuf: buffer into which data will be read + * @n_rx: size of rxbuf, in bytes (need not be dma-safe) + * + * This performs a half duplex MicroWire style transaction with the + * device, sending txbuf and then reading rxbuf. The return value + * is zero for success, else a negative errno status code. + * This call may only be used from a context that may sleep. + * + * Parameters to this routine are always copied using a small buffer; + * performance-sensitive or bulk transfer code should instead use + * spi_{async,sync}() calls with dma-safe buffers. + */ +int spi_write_then_read(struct spi_device *spi, + const u8 *txbuf, unsigned n_tx, + u8 *rxbuf, unsigned n_rx) +{ + static DECLARE_MUTEX(lock); + + int status; + struct spi_message message; + struct spi_transfer x[2]; + u8 *local_buf; + + /* Use preallocated DMA-safe buffer. We can't avoid copying here, + * (as a pure convenience thing), but we can keep heap costs + * out of the hot path ... + */ + if ((n_tx + n_rx) > SPI_BUFSIZ) + return -EINVAL; + + spi_message_init(&message); + memset(x, 0, sizeof x); + if (n_tx) { + x[0].len = n_tx; + spi_message_add_tail(&x[0], &message); + } + if (n_rx) { + x[1].len = n_rx; + spi_message_add_tail(&x[1], &message); + } + + /* ... unless someone else is using the pre-allocated buffer */ + if (down_trylock(&lock)) { + local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); + if (!local_buf) + return -ENOMEM; + } else + local_buf = buf; + + memcpy(local_buf, txbuf, n_tx); + x[0].tx_buf = local_buf; + x[1].rx_buf = local_buf + n_tx; + + /* do the i/o */ + status = spi_sync(spi, &message); + if (status == 0) { + memcpy(rxbuf, x[1].rx_buf, n_rx); + status = message.status; + } + + if (x[0].tx_buf == buf) + up(&lock); + else + kfree(local_buf); + + return status; +} +EXPORT_SYMBOL_GPL(spi_write_then_read); + +/*-------------------------------------------------------------------------*/ + +static int __init spi_init(void) +{ + int status; + + buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL); + if (!buf) { + status = -ENOMEM; + goto err0; + } + + status = bus_register(&spi_bus_type); + if (status < 0) + goto err1; + + status = class_register(&spi_master_class); + if (status < 0) + goto err2; + return 0; + +err2: + bus_unregister(&spi_bus_type); +err1: + kfree(buf); + buf = NULL; +err0: + return status; +} + +/* board_info is normally registered in arch_initcall(), + * but even essential drivers wait till later + * + * REVISIT only boardinfo really needs static linking. the rest (device and + * driver registration) _could_ be dynamically linked (modular) ... costs + * include needing to have boardinfo data structures be much more public. + */ +subsys_initcall(spi_init); + diff -Nur linux-2.6.16.11/drivers/usb/gadget/ether.c linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/ether.c --- linux-2.6.16.11/drivers/usb/gadget/ether.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/ether.c 2006-06-26 11:33:54.000000000 +0200 @@ -253,6 +253,10 @@ #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define DEV_CONFIG_CDC +#endif + /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. @@ -414,7 +418,7 @@ #define DEV_RNDIS_CONFIG_VALUE 2 /* rndis; optional */ static struct usb_device_descriptor -device_desc = { +device_desc __attribute__((aligned(2))) = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, @@ -440,7 +444,7 @@ }; static struct usb_config_descriptor -eth_config = { +eth_config __attribute__((aligned(2))) = { .bLength = sizeof eth_config, .bDescriptorType = USB_DT_CONFIG, @@ -454,7 +458,7 @@ #ifdef CONFIG_USB_ETH_RNDIS static struct usb_config_descriptor -rndis_config = { +rndis_config __attribute__((aligned(2))) = { .bLength = sizeof rndis_config, .bDescriptorType = USB_DT_CONFIG, @@ -510,7 +514,7 @@ #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) -static const struct usb_cdc_header_desc header_desc = { +static const struct usb_cdc_header_desc __attribute__((aligned(2))) header_desc = { .bLength = sizeof header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_HEADER_TYPE, @@ -552,7 +556,8 @@ #ifdef DEV_CONFIG_CDC -static const struct usb_cdc_ether_desc ether_desc = { +static const struct usb_cdc_ether_desc +ether_desc __attribute__((aligned(2))) = { .bLength = sizeof ether_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ETHERNET_TYPE, @@ -587,7 +592,7 @@ #define STATUS_BYTECOUNT 16 /* 8 byte header + data */ static struct usb_endpoint_descriptor -fs_status_desc = { +fs_status_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -678,7 +683,7 @@ static struct usb_endpoint_descriptor -fs_source_desc = { +fs_source_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -687,7 +692,7 @@ }; static struct usb_endpoint_descriptor -fs_sink_desc = { +fs_sink_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -753,7 +758,7 @@ #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) static struct usb_endpoint_descriptor -hs_status_desc = { +hs_status_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -764,7 +769,7 @@ #endif /* DEV_CONFIG_CDC */ static struct usb_endpoint_descriptor -hs_source_desc = { +hs_source_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -773,7 +778,7 @@ }; static struct usb_endpoint_descriptor -hs_sink_desc = { +hs_sink_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -782,7 +787,7 @@ }; static struct usb_qualifier_descriptor -dev_qualifier = { +dev_qualifier __attribute__((aligned(2))) = { .bLength = sizeof dev_qualifier, .bDescriptorType = USB_DT_DEVICE_QUALIFIER, diff -Nur linux-2.6.16.11/drivers/usb/gadget/file_storage.c linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/file_storage.c --- linux-2.6.16.11/drivers/usb/gadget/file_storage.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/file_storage.c 2006-06-26 11:33:54.000000000 +0200 @@ -841,7 +841,7 @@ #define CONFIG_VALUE 1 static struct usb_device_descriptor -device_desc = { +device_desc __attribute__((aligned(2))) = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, @@ -860,7 +860,7 @@ }; static struct usb_config_descriptor -config_desc = { +config_desc __attribute__((aligned(2))) = { .bLength = sizeof config_desc, .bDescriptorType = USB_DT_CONFIG, @@ -898,7 +898,7 @@ * and interrupt-in. */ static struct usb_endpoint_descriptor -fs_bulk_in_desc = { +fs_bulk_in_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -908,7 +908,7 @@ }; static struct usb_endpoint_descriptor -fs_bulk_out_desc = { +fs_bulk_out_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -918,7 +918,7 @@ }; static struct usb_endpoint_descriptor -fs_intr_in_desc = { +fs_intr_in_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -950,7 +950,7 @@ * for the config descriptor. */ static struct usb_qualifier_descriptor -dev_qualifier = { +dev_qualifier __attribute__((aligned(2))) = { .bLength = sizeof dev_qualifier, .bDescriptorType = USB_DT_DEVICE_QUALIFIER, @@ -961,7 +961,7 @@ }; static struct usb_endpoint_descriptor -hs_bulk_in_desc = { +hs_bulk_in_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -971,7 +971,7 @@ }; static struct usb_endpoint_descriptor -hs_bulk_out_desc = { +hs_bulk_out_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -982,7 +982,7 @@ }; static struct usb_endpoint_descriptor -hs_intr_in_desc = { +hs_intr_in_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, diff -Nur linux-2.6.16.11/drivers/usb/gadget/gadget_chips.h linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/gadget_chips.h --- linux-2.6.16.11/drivers/usb/gadget/gadget_chips.h 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/gadget_chips.h 2006-06-26 11:33:54.000000000 +0200 @@ -75,6 +75,12 @@ #define gadget_is_pxa27x(g) 0 #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name) +#else +#define gadget_is_husb2dev(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_S3C2410 #define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name) #else @@ -143,5 +149,7 @@ return 0x13; else if (gadget_is_imx(gadget)) return 0x14; + else if (gadget_is_husb2dev(gadget)) + return 0x80; return -ENOENT; } diff -Nur linux-2.6.16.11/drivers/usb/gadget/husb2_udc.c linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/husb2_udc.c --- linux-2.6.16.11/drivers/usb/gadget/husb2_udc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/husb2_udc.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,1626 @@ +/* + * Driver for the Atmel HUSB2device high speed USB device controller + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "husb2_udc.h" + +#define DRIVER_VERSION "0.9" + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +#define FIFO_IOMEM_ID 0 +#define CTRL_IOMEM_ID 1 + +#ifdef DEBUG +#define DBG_ERR 0x0001 /* report all error returns */ +#define DBG_HW 0x0002 /* debug hardware initialization */ +#define DBG_GADGET 0x0004 /* calls to/from gadget driver */ +#define DBG_INT 0x0008 /* interrupts */ +#define DBG_BUS 0x0010 /* report changes in bus state */ +#define DBG_QUEUE 0x0020 /* debug request queue processing */ +#define DBG_FIFO 0x0040 /* debug FIFO contents */ +#define DBG_DMA 0x0080 /* debug DMA handling */ +#define DBG_ALL 0xffff +#define DBG_NONE 0x0000 + +#define DEBUG_LEVEL (DBG_ERR) +#define DBG(level, fmt, ...) \ + do { \ + if ((level) & DEBUG_LEVEL) \ + printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \ + } while (0) +#else +#define DBG(level, fmt...) +#endif + +static struct husb2_udc the_udc; + +static void __iomem *ep_fifo(struct husb2_udc *udc, struct husb2_ep *ep) +{ + return udc->fifo + ep->index * 0x10000; +} + +static void copy_to_fifo(void __iomem *fifo, void *buf, int len) +{ + unsigned long tmp; + + DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); + for (; len > 0; len -= 4, buf += 4, fifo += 4) { + tmp = *(unsigned long *)buf; + if (len >= 4) { + DBG(DBG_FIFO, " -> %08lx\n", tmp); + writel(tmp, fifo); + } else { + do { + DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24); + writeb(tmp >> 24, fifo); + fifo++; + tmp <<= 8; + } while (--len); + break; + } + } +} + +static void copy_from_fifo(void *buf, void __iomem *fifo, int len) +{ + union { + unsigned long *w; + unsigned char *b; + } p; + unsigned long tmp; + + DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len); + for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) { + if (len >= 4) { + tmp = readl(fifo); + *p.w = tmp; + DBG(DBG_FIFO, " -> %08lx\n", tmp); + } else { + do { + tmp = readb(fifo); + *p.b = tmp; + DBG(DBG_FIFO, " -> %02lx\n", tmp); + fifo++, p.b++; + } while (--len); + } + } +} + +static void submit_transaction(struct husb2_ep *ep, + struct husb2_request *req) +{ + struct husb2_udc *udc = ep->udc; + unsigned int transaction_len; + + transaction_len = req->req.length - req->req.actual; + req->last_transaction = 1; + if (transaction_len > ep->ep.maxpacket) { + transaction_len = ep->ep.maxpacket; + req->last_transaction = 0; + } else if (transaction_len == ep->ep.maxpacket + && req->req.zero) { + req->last_transaction = 0; + } + DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)\n", + ep_name(ep), req, transaction_len); + + copy_to_fifo(ep_fifo(udc, ep), req->req.buf + req->req.actual, + transaction_len); + husb2_writel(ep->udc, EPT_SET_STA(ep->index), EPTSR_TX_BK_RDY); + req->req.actual += transaction_len; +} + +static void submit_request(struct husb2_ep *ep, struct husb2_request *req) +{ + DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n", + ep_name(ep), req, req->req.length); + + req->req.actual = 0; + req->submitted = 1; + + submit_transaction(ep, req); +} + +static void refill_queue(struct husb2_ep *ep) +{ + struct husb2_udc *udc = ep->udc; + struct husb2_request *req; + unsigned long status; + unsigned int nr_busy; + + if (list_empty(&ep->queue)) { + DBG(DBG_QUEUE, "refill_queue (%s): queue empty\n", + ep_name(ep)); + return; + } + + status = husb2_readl(udc, EPT_STA(ep->index)); + nr_busy = (status >> 18) & 3; + + if (nr_busy < ep->nr_banks) { + list_for_each_entry(req, &ep->queue, queue) { + if (!req->submitted) + break; + } + if (&req->queue == &ep->queue) { + DBG(DBG_QUEUE, + "refill_queue (%s): all requests " + "have been submitted\n", ep_name(ep)); + return; + } + + submit_request(ep, req); + } else { + DBG(DBG_QUEUE, "refill_queue (%s): no available banks\n", + ep_name(ep)); + } +} + +static void send_status(struct husb2_udc *udc, struct husb2_ep *ep) +{ + ep->state = STATUS_STAGE_IN; + husb2_writel(udc, EPT_SET_STA(ep->index), + EPTSR_TX_BK_RDY); +} + + +static void receive_data(struct husb2_ep *ep) +{ + struct husb2_udc *udc = ep->udc; + struct husb2_request *req; + unsigned long status; + unsigned int bytecount, nr_busy; + int is_complete = 0; + + status = husb2_readl(udc, EPT_STA(ep->index)); + nr_busy = (status >> 18) & 3; + + DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy); + + while (nr_busy > 0) { + bytecount = (status >> 20) & 0x3ff; + req = list_entry(ep->queue.next, + struct husb2_request, queue); + + if (status & (1 << 31)) + is_complete = 1; + if (req->req.actual + bytecount >= req->req.length) { + is_complete = 1; + bytecount = req->req.length - req->req.actual; + } + + copy_from_fifo(req->req.buf + req->req.actual, + ep_fifo(udc, ep), bytecount); + req->req.actual += bytecount; + + husb2_writel(udc, EPT_CLR_STA(ep->index), EPTSR_RXRDY); + + if (is_complete) { + DBG(DBG_QUEUE, "%s: request done\n", ep_name(ep)); + req->req.status = 0; + list_del_init(&req->queue); + req->req.complete(&ep->ep, &req->req); + } + + status = husb2_readl(udc, EPT_STA(ep->index)); + nr_busy = (status >> 18) & 3; + + if (is_complete && ep_is_control(ep)) { + BUG_ON(nr_busy != 0); + send_status(udc, ep); + break; + } + } +} + +static void request_complete(struct husb2_ep *ep, + struct husb2_request *req, + int status) +{ + struct husb2_udc *udc = ep->udc; + int i; + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + + if (req->packet) { + for (i = 0; i < req->nr_pkts; i++) + dma_pool_free(udc->desc_pool, req->packet[i].desc, + req->packet[i].desc_dma); + kfree(req->packet); + req->packet = NULL; + dma_unmap_single(&udc->adev->dev, + req->req.dma, req->req.length, + (ep_is_in(ep) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); + req->req.dma = DMA_ADDR_INVALID; + } + + DBG(DBG_GADGET, "%s: request complete: status %d\n", + ep_name(ep), req->req.status); + req->req.complete(&ep->ep, &req->req); +} + +static int husb2_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct husb2_ep *ep = to_husb2_ep(_ep); + struct husb2_udc *udc = ep->udc; + unsigned long flags, ept_cfg, maxpacket; + int ret; + + DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep_name(ep), desc); + + maxpacket = le16_to_cpu(desc->wMaxPacketSize); + + if (ep->index == 0 + || desc->bDescriptorType != USB_DT_ENDPOINT + || ((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) + != ep->index) + || maxpacket == 0 + || maxpacket > ep->fifo_size) { + DBG(DBG_ERR, "ep_enable: Invalid argument"); + return -EINVAL; + } + + if (((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_ISOC) + && !(ep->capabilities & HUSB2_EP_CAP_ISOC)) { + DBG(DBG_ERR, "ep_enable: EP is not isoc capable\n"); + return -EINVAL; + } + + if (maxpacket <= 8) + ept_cfg = 0; + else + /* LSB is bit 1, not 0 */ + ept_cfg = fls(maxpacket - 1) - 3; + DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", + ep_name(ep), ept_cfg, maxpacket); + BUG_ON(ept_cfg > 7); + + if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + ept_cfg |= EPT_DIR_IN; + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + ept_cfg |= EPT_TYPE_CONTROL; + break; + case USB_ENDPOINT_XFER_ISOC: + ept_cfg |= EPT_TYPE_ISOC; + break; + case USB_ENDPOINT_XFER_BULK: + ept_cfg |= EPT_TYPE_BULK; + break; + case USB_ENDPOINT_XFER_INT: + ept_cfg |= EPT_TYPE_INT; + break; + } + ept_cfg |= BK_NUMBER(ep->nr_banks); + + spin_lock_irqsave(&ep->udc->lock, flags); + + ret = -EBUSY; + if (ep->desc) { + DBG(DBG_ERR, "ep_enable: EP already enabled\n"); + goto out; + } + + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + husb2_writel(udc, EPT_CFG(ep->index), ept_cfg); + DBG(DBG_HW, "EPT_CFG(%d) after init: %#08lx\n", ep->index, + (unsigned long)husb2_readl(udc, EPT_CFG(ep->index))); + husb2_writel(udc, EPT_CTL_ENB(ep->index), EPTCR_ENABLE); + + if (ep_can_dma(ep)) { + husb2_writel(udc, USB_IEN, + (husb2_readl(udc, USB_IEN) + | (1 << (ep->index + UDCSR_DMA_INT_SHIFT)))); + husb2_writel(udc, EPT_CTL_ENB(ep->index), EPTCR_AUTO_VALID); + } else { + husb2_writel(udc, USB_IEN, + (husb2_readl(udc, USB_IEN) + | (1 << (ep->index + UDCSR_EPT_INT_SHIFT)))); + husb2_writel(udc, EPT_CTL_ENB(ep->index), EPTSR_TX_COMPLETE); + } + + DBG(DBG_HW, "USB_IEN after init: %#08lx\n", + (unsigned long)husb2_readl(udc, USB_IEN)); + ret = 0; + +out: + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int husb2_ep_disable(struct usb_ep *_ep) +{ + struct husb2_ep *ep = to_husb2_ep(_ep); + struct husb2_udc *udc = ep->udc; + struct husb2_request *req; + unsigned long flags; + int ret; + + DBG(DBG_GADGET, "ep_disable: %p\n", _ep); + + spin_lock_irqsave(&udc->lock, flags); + + ret = -EINVAL; + if (!ep->desc) { + DBG(DBG_ERR, "ep_disable: EP not enabled\n"); + goto out; + } + + ep->desc = NULL; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct husb2_request, queue); + list_del_init(&req->queue); + request_complete(ep, req, -ESHUTDOWN); + } + + husb2_writel(udc, EPT_CTL_DIS(ep->index), EPTCR_ENABLE); + husb2_writel(udc, USB_IEN, (husb2_readl(udc, USB_IEN) + & ~(1 << (ep->index + UDCSR_EPT_INT_SHIFT)))); + ret = 0; + +out: + spin_unlock_irqrestore(&udc->lock, flags); + return ret; +} + +static struct usb_request * +husb2_ep_alloc_request(struct usb_ep *_ep, unsigned gfp_flags) +{ + struct husb2_request *req; + + DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags); + + req = kmalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + memset(req, 0, sizeof(*req)); + INIT_LIST_HEAD(&req->queue); + req->req.dma = DMA_ADDR_INVALID; + + return &req->req; +} + +static void +husb2_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct husb2_request *req = to_husb2_req(_req); + + DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req); + + kfree(req); +} + +static void *husb2_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, + dma_addr_t *dma, unsigned gfp_flags) +{ + struct husb2_ep *ep = to_husb2_ep(_ep); + void *buf; + + /* + * We depend on kmalloc() returning cache-aligned memory. This + * is normally guaranteed as long as we allocate a whole + * cacheline or more. + * + * When CONFIG_DEBUG_SLAB is enabled, however, the slab + * allocator inserts red zones and ownership information, + * causing the slab objects to be misaligned. + * + * One alternative would be to use dma_alloc_coherent, but + * that would make us unable to allocate anything less than a + * page at a time. + */ +#ifdef CONFIG_DEBUG_SLAB +# error The HUSB2 UDC driver breaks with SLAB debugging enabled +#endif + + if (bytes < L1_CACHE_BYTES) + bytes = L1_CACHE_BYTES; + + buf = kmalloc(bytes, gfp_flags); + + /* + * Seems like we have to map the buffer any chance we get. + * ether.c wants us to initialize the dma member of a + * different request than the one receiving the buffer, so one + * never knows... + * + * Ah, screw it. The ether driver is probably wrong, and this + * is not the right place to do the mapping. The driver + * shouldn't mess with our DMA mappings anyway. + */ + *dma = DMA_ADDR_INVALID; + + DBG(DBG_GADGET, "ep_alloc_buffer: %s, %u, 0x%x -> %p\n", + ep_name(ep), bytes, gfp_flags, buf); + + return buf; +} + +static void husb2_ep_free_buffer(struct usb_ep *_ep, void *buf, + dma_addr_t dma, unsigned bytes) +{ + DBG(DBG_GADGET, "ep_free_buffer: %s, buf %p (size %u)\n", + _ep->name, buf, bytes); + kfree(buf); +} + +static void start_dma_queue(struct husb2_ep *ep, int gfp_flags) +{ + struct husb2_udc *udc = ep->udc; + struct husb2_request *req; + struct husb2_packet *pkt = NULL, *prev_pkt = NULL; + dma_addr_t addr; + unsigned long flags; + unsigned int pkt_size, nr_pkts, i; + unsigned int residue; + + DBG(DBG_QUEUE, "%s: start_dma_queue: list %s\n", + ep_name(ep), list_empty(&ep->queue) ? "empty" : "not empty"); + + if (list_empty(&ep->queue)) + return; + + req = list_entry(ep->queue.next, struct husb2_request, queue); + if (req->packet) { + /* already submitted */ + DBG(DBG_QUEUE, "%s: request already submitted\n", + ep_name(ep)); + return; + } + + pkt_size = ep->ep.maxpacket; + nr_pkts = req->req.length / pkt_size; + residue = req->req.length % pkt_size; + if (req->req.zero || (residue != 0)) + /* ensure last packet is short */ + nr_pkts++; + + req->nr_pkts = nr_pkts; + + req->packet = kmalloc(sizeof(*req->packet) * nr_pkts, gfp_flags); + if (!req->packet) + goto oom; + memset(req->packet, 0, sizeof(*req->packet) * nr_pkts); + + addr = req->req.dma; + flags = HUSB2_DMA_LINK | HUSB2_DMA_CH_EN; + if (!ep_is_in(ep)) + flags |= HUSB2_DMA_XFER_END | HUSB2_DMA_BUF_CLOSE_IE; + + DBG(DBG_DMA, "DMA descriptors:\n"); + for (i = 0; i < nr_pkts; i++) { + pkt = &req->packet[i]; + pkt->desc = dma_pool_alloc(udc->desc_pool, gfp_flags, + &pkt->desc_dma); + if (!pkt->desc) + goto oom; + + if (prev_pkt) { + prev_pkt->desc->next = pkt->desc_dma; + DBG(DBG_DMA, "[%d] n%08x a%08x l%u f%04x\n", + i - 1, prev_pkt->desc->next, prev_pkt->desc->addr, + prev_pkt->desc->length, prev_pkt->desc->flags); + } + prev_pkt = pkt; + + pkt->desc->addr = addr; + pkt->desc->length = pkt_size; + pkt->desc->flags = flags; + addr += pkt_size; + } + + /* special care is needed for the last packet... */ + flags = (HUSB2_DMA_CH_END | HUSB2_DMA_CH_EN); + if (ep_is_in(ep)) + flags |= HUSB2_DMA_BUF_END_OE; + else + flags |= HUSB2_DMA_XFER_END | HUSB2_DMA_BUF_CLOSE_IE; + pkt->desc->flags = flags; + if (req->req.zero || residue) + pkt->desc->length = residue; + + DBG(DBG_DMA, "[%d] n%08x a%08x l%u f%04x\n", + i - 1, prev_pkt->desc->next, prev_pkt->desc->addr, + prev_pkt->desc->length, prev_pkt->desc->flags); + + /* Load the first descriptor */ + /* DBG(DBG_DMA, "DMA control/status before descriptor load: %08lx/%08lx\n", + husb2_readl(udc, DMA_CONTROL(ep->index)), + husb2_readl(udc, DMA_STATUS(ep->index)));*/ + + husb2_writel(udc, DMA_NXT_DSC(ep->index), req->packet[0].desc_dma); + husb2_writel(udc, DMA_CONTROL(ep->index), HUSB2_DMA_LINK); + /* DBG(DBG_DMA, "Loaded descriptor: %08lx %08lx %04x %04x (addr %08lx)\n", + (unsigned long)req->packet[0].desc->next, + (unsigned long)req->packet[0].desc->addr, + (unsigned int)req->packet[0].desc->length, + (unsigned int)req->packet[0].desc->flags, + (unsigned long)req->packet[0].desc_dma); */ + + /* DBG(DBG_DMA, "DMA control/status after descriptor load: %08lx/%08lx\n", + husb2_readl(udc, DMA_CONTROL(ep->index)), + husb2_readl(udc, DMA_STATUS(ep->index))); */ + + return; + +oom: + printk(KERN_ERR "ERROR: Could not allocate DMA memory for endpoint %s\n", + ep_name(ep)); + if (req->packet) { + for (i = 0; i < nr_pkts; i++) + if (req->packet[i].desc) + dma_pool_free(udc->desc_pool, + req->packet[i].desc, + req->packet[i].desc_dma); + kfree(req->packet); + } +} + +static int husb2_ep_queue(struct usb_ep *_ep, struct usb_request *_req, + unsigned gfp_flags) +{ + struct husb2_request *req = to_husb2_req(_req); + struct husb2_ep *ep = to_husb2_ep(_ep); + struct husb2_udc *udc = ep->udc; + unsigned long flags; + int direction_in = 0; + + DBG(DBG_GADGET | DBG_QUEUE, "ep_queue: %s, req %p\n", ep_name(ep), _req); + + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + if (!ep->desc) + return -ENODEV; + + req->submitted = 0; + BUG_ON(req->packet); + + if (ep_is_control(ep) && (ep->state == DATA_STAGE_IN + || ep->state == STATUS_STAGE_IN)) + direction_in = 1; + else if (ep_is_in(ep)) + direction_in = 1; + + if (ep_can_dma(ep)) { + /* + * Caller may already have done the DMA mapping, or we + * may have done it ourselves in ep_alloc_buffer(). + * But how do we know that? + */ + if (_req->dma == DMA_ADDR_INVALID) + _req->dma = dma_map_single(&udc->adev->dev, + _req->buf, _req->length, + (direction_in + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE)); + else + dma_sync_single_for_device(&udc->adev->dev, + _req->dma, _req->length, + (direction_in + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE)); + req->using_dma = 1; + } + + _req->status = -EINPROGRESS; + _req->actual = 0; + + spin_lock_irqsave(&udc->lock, flags); + + // BUG_ON(!list_empty(&req->queue)); + + list_add_tail(&req->queue, &ep->queue); + + if (ep_can_dma(ep)) + start_dma_queue(ep, gfp_flags); + else if (direction_in) + refill_queue(ep); + else + receive_data(ep); + + if (!direction_in && !ep_can_dma(ep)) + husb2_writel(udc, EPT_CTL_ENB(ep->index), EPTSR_RXRDY); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int husb2_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct husb2_ep *ep = to_husb2_ep(_ep); + struct husb2_udc *udc = ep->udc; + struct husb2_request *req = to_husb2_req(_req); + unsigned long flags; + int timeout; + + DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n", ep_name(ep), req); + + spin_lock_irqsave(&udc->lock, flags); + list_del_init(&req->queue); + if (req->packet) { + /* + * This request has been submitted to the DMA + * controller. Try to cancel the transaction. + */ + husb2_writel(udc, DMA_CONTROL(ep->index), 0); + + for (timeout = 40; timeout; --timeout) { + if (!(husb2_readl(udc, DMA_STATUS(ep->index)) + & HUSB2_DMA_CH_EN)) + break; + udelay(1); + } + + if (timeout == 0) { + printk(KERN_WARNING + "udc: %s: Timed out trying to dequeue request %p (DMA)\n", + ep_name(ep), req); + + /* Ok, now what? */ + BUG(); + } + } + if (req->packet || req->submitted) { + struct husb2_request *r; + + /* Kill all banks and resubmit the first request later */ + list_for_each_entry(r, &ep->queue, queue) { + if (!r->submitted) + break; + husb2_writel(udc, EPT_SET_STA(ep->index), + EPTSR_KILL_BANK); + for (timeout = 10; timeout; --timeout) { + if (!(husb2_readl(udc, EPT_STA(ep->index)) + & EPTSR_KILL_BANK)) + break; + } + + if (timeout == 0) { + printk(KERN_WARNING + "udc: %s: Timed out trying to dequeue request %p\n", + ep_name(ep), req); + BUG(); + } + } + } + + spin_unlock_irqrestore(&udc->lock, flags); + + if (ep_can_dma(ep)) + start_dma_queue(ep, GFP_KERNEL); + else if (ep_is_in(ep)) + refill_queue(ep); + + request_complete(ep, req, -ECONNRESET); + + return 0; +} + +static int husb2_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct husb2_ep *ep = to_husb2_ep(_ep); + struct husb2_udc *udc = ep->udc; + unsigned long flags; + int ret; + + if (!ep->desc) { + DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", + ep_name(ep)); + return -ENODEV; + } + if (ep_is_isochronous(ep)) { + DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n", + ep_name(ep)); + return -ENOTTY; + } + + spin_lock_irqsave(&udc->lock, flags); + + /* + * We can't halt IN endpoints while there are still data to be + * transferred + */ + ret = -EAGAIN; + if (value && ep_is_in(ep) + && (husb2_readl(udc, EPT_STA(ep->index)) & (3 << 18))) { + DBG(DBG_ERR, "halt: ep %s is still transferring data\n", + ep_name(ep)); + goto out; + } + + if (value) + husb2_writel(udc, EPT_SET_STA(ep->index), EPTSR_FORCE_STALL); + else + husb2_writel(udc, EPT_CLR_STA(ep->index), EPTSR_FORCE_STALL); + ret = 0; + + DBG(DBG_GADGET, "endpoint %s: HALT %s\n", ep_name(ep), + value ? "set" : "cleared"); + +out: + spin_unlock_irqrestore(&udc->lock, flags); + return ret; +} + +static int husb2_ep_fifo_status(struct usb_ep *_ep) +{ + struct husb2_ep *ep = to_husb2_ep(_ep); + int ret; + + ret = husb2_readl(ep->udc, EPT_STA(ep->index)); + ret >>= EPTSR_BYTE_COUNT_SHIFT; + ret &= EPTSR_BYTE_COUNT_MASK >> EPTSR_BYTE_COUNT_SHIFT; + return ret; +} + +static void husb2_ep_fifo_flush(struct usb_ep *_ep) +{ + struct husb2_ep *ep = to_husb2_ep(_ep); + struct husb2_udc *udc = ep->udc; + + husb2_writel(udc, USB_EPT_RST, 1 << ep->index); +} + +struct usb_ep_ops husb2_ep_ops = { + .enable = husb2_ep_enable, + .disable = husb2_ep_disable, + .alloc_request = husb2_ep_alloc_request, + .free_request = husb2_ep_free_request, + .alloc_buffer = husb2_ep_alloc_buffer, + .free_buffer = husb2_ep_free_buffer, + .queue = husb2_ep_queue, + .dequeue = husb2_ep_dequeue, + .set_halt = husb2_ep_set_halt, + .fifo_status = husb2_ep_fifo_status, + .fifo_flush = husb2_ep_fifo_flush, +}; + +static int husb2_udc_get_frame(struct usb_gadget *gadget) +{ + struct husb2_udc *udc = to_husb2_udc(gadget); + + return (husb2_readl(udc, USB_FNUM) >> 3) & 0x7ff; +} + +struct usb_gadget_ops husb2_udc_ops = { + .get_frame = husb2_udc_get_frame, +}; + +#define EP(nam, type, idx, caps) { \ + .ep = { \ + .ops = &husb2_ep_ops, \ + .name = nam, \ + .maxpacket = type##_FIFO_SIZE, \ + }, \ + .udc = &the_udc, \ + .queue = LIST_HEAD_INIT(husb2_ep[idx].queue), \ + .fifo_size = type##_FIFO_SIZE, \ + .nr_banks = type##_NR_BANKS, \ + .index = idx, \ + .capabilities = caps, \ +} + +static struct husb2_ep husb2_ep[] = { + EP("ep0", EP0, 0, 0), + EP("ep1in-bulk", BULK, 1, HUSB2_EP_CAP_DMA), + EP("ep2out-bulk", BULK, 2, HUSB2_EP_CAP_DMA), + EP("ep3in-iso", ISO, 3, HUSB2_EP_CAP_DMA | HUSB2_EP_CAP_ISOC), + EP("ep4out-iso", ISO, 4, HUSB2_EP_CAP_DMA | HUSB2_EP_CAP_ISOC), + EP("ep5in-int", INT, 5, HUSB2_EP_CAP_DMA), + EP("ep6out-int", INT, 6, HUSB2_EP_CAP_DMA), +}; +#undef EP + +static struct usb_endpoint_descriptor husb2_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = __constant_cpu_to_le16(64), + /* FIXME: I have no idea what to put here */ + .bInterval = 1, +}; + +static void nop_release(struct device *dev) +{ + +} + +static struct husb2_udc the_udc = { + .gadget = { + .ops = &husb2_udc_ops, + .ep0 = &husb2_ep[0].ep, + .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), + .is_dualspeed = 1, + .name = "husb2_udc", + .dev = { + .bus_id = "gadget", + .release = nop_release, + }, + }, + + .lock = SPIN_LOCK_UNLOCKED, +}; + +static void ep0_enable(struct husb2_udc *udc) +{ + husb2_ep[0].desc = &husb2_ep0_desc; + + /* Configure endpoint 0 */ + husb2_writel(udc, EPT_CTL_ENB(0), EPTCR_ENABLE); + husb2_writel(udc, EPT_CFG(0), (NB_TRANS_1 + | BK_NUMBER_1 + | EPT_TYPE_CONTROL + | EP0_EPT_SIZE)); + + if (!(husb2_readl(udc, EPT_CFG(0)) & EPT_MAPPED)) + printk(KERN_WARNING + "WARNING: EP0 configuration is invalid!\n"); + + husb2_writel(udc, EPT_CTL_ENB(0), (EPTSR_RXSETUP + | EPTSR_RXRDY + | EPTSR_TX_COMPLETE)); + husb2_writel(udc, USB_IEN, (husb2_readl(udc, USB_IEN) + | (1 << UDCSR_EPT_INT_SHIFT))); +} + +static void udc_enable(struct husb2_udc *udc) +{ + /* Enable the controller */ + husb2_writel(udc, USB_CTRL, UDCCR_ENABLE); + + /* Reset all endpoints and disable interrupts */ + husb2_writel(udc, USB_EPT_RST, ~0UL); + husb2_writel(udc, USB_IEN, 0UL); + + ep0_enable(udc); + + /* Enable interrupts */ + husb2_writel(udc, USB_IEN, (husb2_readl(udc, USB_IEN) + | UDCSR_RESUME + /* | UDCSR_WAKE_UP */ + | UDCSR_RESET + /* | UDCSR_SUSPEND */)); +} + +static void udc_disable(struct husb2_udc *udc) +{ + udc->gadget.speed = USB_SPEED_UNKNOWN; + + husb2_writel(udc, USB_CTRL, 0); +} + +static void reset_all_endpoints(struct husb2_udc *udc) +{ + struct husb2_ep *ep; + + ep = to_husb2_ep(udc->gadget.ep0); + if (!list_empty(&ep->queue)) { + struct husb2_request *req; + + req = list_entry(ep->queue.next, struct husb2_request, queue); + list_del_init(&req->queue); + request_complete(ep, req, -ECONNRESET); + } + BUG_ON(!list_empty(&ep->queue)); + + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) + husb2_ep_disable(&ep->ep); + } + + husb2_writel(udc, USB_EPT_RST, ~0UL); +} + +static struct husb2_ep *get_ep_by_addr(struct husb2_udc *udc, u16 wIndex) +{ + struct husb2_ep *ep; + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) + return to_husb2_ep(udc->gadget.ep0); + + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { + u8 bEndpointAddress; + + if (!ep->desc) + continue; + bEndpointAddress = ep->desc->bEndpointAddress; + if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) + continue; + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) + == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) + return ep; + } + + return NULL; +} + +static inline void set_protocol_stall(struct husb2_udc *udc, + struct husb2_ep *ep) +{ + husb2_writel(udc, EPT_SET_STA(ep->index), EPTSR_FORCE_STALL); + ep->state = WAIT_FOR_SETUP; +} + +static inline int is_stalled(struct husb2_udc *udc, + struct husb2_ep *ep) +{ + if (husb2_readl(udc, EPT_STA(ep->index)) & EPTSR_FORCE_STALL) + return 1; + return 0; +} + +static int handle_ep0_setup(struct husb2_udc *udc, struct husb2_ep *ep, + struct usb_ctrlrequest *crq) +{ + switch (crq->bRequest) { + case USB_REQ_GET_STATUS: { + u16 status; + + if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { + /* Self-powered, no remote wakeup */ + status = __constant_cpu_to_le16(1 << 0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_INTERFACE)) { + status = __constant_cpu_to_le16(0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_ENDPOINT)) { + struct husb2_ep *target; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + status = 0; + if (is_stalled(udc, target)) + status |= __constant_cpu_to_le16(1); + } else { + goto delegate; + } + + /* Write directly to the FIFO. No queueing is done. */ + if(crq->wLength != __constant_cpu_to_le16(sizeof(status))) + goto stall; + ep->state = DATA_STAGE_IN; + writew(status, ep_fifo(udc, ep)); + husb2_writel(udc, EPT_SET_STA(ep->index), + EPTSR_TX_BK_RDY); + break; + } + + case USB_REQ_CLEAR_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + /* We don't support TEST_MODE */ + goto stall; + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct husb2_ep *target; + + if (crq->wValue != __constant_cpu_to_le16(USB_ENDPOINT_HALT) + || crq->wLength != __constant_cpu_to_le16(0)) + goto stall; + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + husb2_writel(udc, EPT_CLR_STA(target->index), + EPTSR_FORCE_STALL); + } else { + goto delegate; + } + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + /* We don't support TEST_MODE */ + goto stall; + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct husb2_ep *target; + + if (crq->wValue != __constant_cpu_to_le16(USB_ENDPOINT_HALT) + || crq->wLength != __constant_cpu_to_le16(0)) + goto stall; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + husb2_writel(udc, EPT_SET_STA(target->index), + EPTSR_FORCE_STALL); + } else + goto delegate; + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_ADDRESS: + if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) + goto delegate; + + DBG(DBG_BUS, "setting address %u...\n", le16_to_cpu(crq->wValue)); + husb2_writel(udc, USB_CTRL, + ((husb2_readl(udc, USB_CTRL) + & ~UDCCR_DEVADDR_MASK) + | (le16_to_cpu(crq->wValue) & UDCCR_DEVADDR_MASK))); + send_status(udc, ep); + ep->state = STATUS_STAGE_ADDR; + break; + + default: + delegate: + return udc->driver->setup(&udc->gadget, crq); + } + + return 0; + +stall: + printk(KERN_ERR + "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " + "halting endpoint...\n", + ep_name(ep), crq->bRequestType, crq->bRequest, + le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), + le16_to_cpu(crq->wLength)); + set_protocol_stall(udc, ep); + return -1; +} + +static void husb2_control_irq(struct husb2_udc *udc, struct husb2_ep *ep) +{ + struct husb2_request *req; + unsigned long epstatus; + +restart: + epstatus = husb2_readl(udc, EPT_STA(ep->index)); + + DBG(DBG_INT, "%s: interrupt, status: 0x%08lx\n", + ep_name(ep), epstatus); + + if (epstatus & EPTSR_TX_COMPLETE) { + husb2_writel(udc, EPT_CLR_STA(ep->index), EPTSR_TX_COMPLETE); + DBG(DBG_BUS, "txc: %d\n", ep->state); + + switch (ep->state) { + case DATA_STAGE_IN: + if (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct husb2_request, + queue); + if (req->last_transaction) + ep->state = STATUS_STAGE_OUT; + else + submit_transaction(ep, req); + } else { + ep->state = STATUS_STAGE_OUT; + } + break; + case STATUS_STAGE_ADDR: + /* Activate our new address */ + husb2_writel(udc, USB_CTRL, + (husb2_readl(udc, USB_CTRL) + | UDCCR_FADDR_EN)); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_IN: + if (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct husb2_request, + queue); + list_del_init(&req->queue); + refill_queue(ep); + request_complete(ep, req, 0); + } + ep->state = WAIT_FOR_SETUP; + break; + default: + printk(KERN_ERR + "udc: %s: TXCOMP: Invalid endpoint state %d, " + "halting endpoint...\n", + ep_name(ep), ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if (epstatus & EPTSR_RXRDY) { + DBG(DBG_BUS, "rxc: %d\n", ep->state); + + switch (ep->state) { + case STATUS_STAGE_OUT: + husb2_writel(udc, EPT_CLR_STA(ep->index), EPTSR_RXRDY); + + if (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct husb2_request, + queue); + list_del_init(&req->queue); + request_complete(ep, req, 0); + } + ep->state = WAIT_FOR_SETUP; + break; + + case DATA_STAGE_OUT: + if (list_empty(&ep->queue)) + break; + + receive_data(ep); + break; + + default: + husb2_writel(udc, EPT_CLR_STA(ep->index), + EPTSR_RXRDY); + set_protocol_stall(udc, ep); + printk(KERN_ERR + "udc: %s: RXRDY: Invalid endpoint state %d, " + "halting endpoint...\n", + ep_name(ep), ep->state); + break; + } + + goto restart; + } + if (epstatus & EPTSR_RXSETUP) { + union { + struct usb_ctrlrequest crq; + unsigned long data[2]; + } crq; + unsigned int pkt_len; + int ret; + + if (ep->state != WAIT_FOR_SETUP) { + /* + * Didn't expect a SETUP packet at this + * point. Clean up any pending requests (which + * may be successful). + */ + int status = -EPROTO; + struct husb2_request *r; + + /* + * RXRDY is dropped when SETUP packets arrive. + * Just pretend we received the status packet. + */ + if (ep->state == STATUS_STAGE_OUT) + status = 0; + + if (!list_empty(&ep->queue)) { + r = list_entry(ep->queue.next, + struct husb2_request, + queue); + list_del_init(&r->queue); + request_complete(ep, r, status); + } + BUG_ON(!list_empty(&ep->queue)); + } + + pkt_len = (husb2_readl(udc, EPT_STA(ep->index)) + & EPTSR_BYTE_COUNT_MASK) >> EPTSR_BYTE_COUNT_SHIFT; + DBG(DBG_HW, "Packet length: %u\n", pkt_len); + BUG_ON(pkt_len != sizeof(crq)); + + DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", + ep_fifo(udc, ep)); + copy_from_fifo(crq.data, ep_fifo(udc, ep), sizeof(crq)); + + /* Free up one bank in the FIFO so that we can + * generate or receive a reply right away. */ + husb2_writel(udc, EPT_CLR_STA(ep->index), EPTSR_RXSETUP); + + /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n", + ep->state, crq.crq.bRequestType, + crq.crq.bRequest); */ + + if (crq.crq.bRequestType & USB_DIR_IN) { + /* + * The USB 2.0 spec states that "if wLength is + * zero, there is no data transfer phase." + * However, testusb #14 seems to actually + * expect a data phase even if wLength = 0... + */ + ep->state = DATA_STAGE_IN; + } else { + if (crq.crq.wLength != __constant_cpu_to_le16(0)) + ep->state = DATA_STAGE_OUT; + else + ep->state = STATUS_STAGE_IN; + } + + ret = -1; + if (ep->index == 0) + ret = handle_ep0_setup(udc, ep, &crq.crq); + else + ret = udc->driver->setup(&udc->gadget, &crq.crq); + + DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n", + crq.crq.bRequestType, crq.crq.bRequest, + le16_to_cpu(crq.crq.wLength), ep->state, ret); + + if (ret < 0) { + /* Let the host know that we failed */ + set_protocol_stall(udc, ep); + } + } +} + +static void husb2_ep_irq(struct husb2_udc *udc, struct husb2_ep *ep) +{ + unsigned long epstatus; + struct husb2_request *req; + + epstatus = husb2_readl(udc, EPT_STA(ep->index)); + + DBG(DBG_INT, "%s: interrupt, status: 0x%08lx\n", + ep_name(ep), epstatus); + + if (epstatus & EPTSR_TX_COMPLETE) { + BUG_ON(!ep_is_in(ep)); + BUG_ON(list_empty(&ep->queue)); + + DBG(DBG_BUS, "%s: TX complete\n", ep_name(ep)); + + husb2_writel(udc, EPT_CLR_STA(ep->index), EPTSR_TX_COMPLETE); + + req = list_entry(ep->queue.next, struct husb2_request, queue); + if (req->last_transaction) { + list_del_init(&req->queue); + refill_queue(ep); + request_complete(ep, req, 0); + } else { + submit_transaction(ep, req); + } + } + if (epstatus & EPTSR_RXRDY) { + BUG_ON(ep_is_in(ep)); + + DBG(DBG_BUS, "%s: RX data ready\n", ep_name(ep)); + receive_data(ep); + husb2_writel(udc, EPT_CLR_STA(ep->index), EPTSR_RXRDY); + } +} + +static void husb2_dma_irq(struct husb2_udc *udc, struct husb2_ep *ep) +{ + struct husb2_request *req; + struct husb2_packet *pkt = NULL; + unsigned long dma_status, dma_addr, flags; + unsigned int i; + + dma_status = husb2_readl(udc, DMA_STATUS(ep->index)); + dma_addr = husb2_readl(udc, DMA_ADDRESS(ep->index)); + + DBG(DBG_DMA, "%s: DMA request complete, status: 0x%08lx, dma addr: 0x%08lx\n", + ep_name(ep), dma_status, dma_addr); + + spin_lock_irqsave(&udc->lock, flags); + req = list_entry(ep->queue.next, struct husb2_request, queue); + BUG_ON(list_empty(&req->queue)); + list_del_init(&req->queue); + spin_unlock_irqrestore(&udc->lock, flags); + + /* + * The request has been removed from the queue. Submit the + * next one as soon as possible. + */ + start_dma_queue(ep, GFP_ATOMIC); + + /* Figure out how many bytes that was transfered. */ + req->req.actual = 0; + for (i = 0; i < req->nr_pkts; i++) { + pkt = &req->packet[i]; + DBG(DBG_DMA, "end of packet? dma addr: 0x%08lx\n", pkt->desc->addr); + req->req.actual += pkt->desc->length; + if (pkt->desc->addr <= dma_addr + && (pkt->desc->addr + pkt->desc->length) >= dma_addr) + break; + } + BUG_ON(i == req->nr_pkts); + req->req.actual -= dma_status >> 16; + + request_complete(ep, req, 0); +} + +static irqreturn_t husb2_udc_irq(int irq, void *devid, struct pt_regs *regs) +{ + struct husb2_udc *udc = devid; + unsigned long status; + + spin_lock(&udc->lock); + + status = husb2_readl(udc, USB_INT_STA); + DBG(DBG_INT, "irq, status=%#08lx\n", status); + + if (status & UDCSR_SUSPEND) { + husb2_writel(udc, USB_CLR_INT, UDCSR_SUSPEND); + //DBG(DBG_BUS, "Suspend detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->suspend) + udc->driver->suspend(&udc->gadget); + } + + if (status & UDCSR_WAKE_UP) { + husb2_writel(udc, USB_CLR_INT, UDCSR_WAKE_UP); + //DBG(DBG_BUS, "Wake Up CPU detected\n"); + } + + if (status & UDCSR_RESUME) { + husb2_writel(udc, USB_CLR_INT, UDCSR_RESUME); + DBG(DBG_BUS, "Resume detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->resume) + udc->driver->resume(&udc->gadget); + } + + if (status & UDCSR_DMA_INTx) { + int i; + + for (i = 1; i < HUSB2_NR_ENDPOINTS; i++) + if (status & (1 << (i + UDCSR_DMA_INT_SHIFT))) + husb2_dma_irq(udc, &husb2_ep[i]); + } + + if (status & UDCSR_EPT_INTx) { + int i; + + for (i = 0; i < HUSB2_NR_ENDPOINTS; i++) + if (status & (1 << (i + UDCSR_EPT_INT_SHIFT))) { + if (ep_is_control(&husb2_ep[i])) + husb2_control_irq(udc, &husb2_ep[i]); + else + husb2_ep_irq(udc, &husb2_ep[i]); + } + } + + if (status & UDCSR_RESET) { + husb2_writel(udc, USB_CLR_INT, UDCSR_RESET); + if (status & UDCSR_HIGH_SPEED) { + DBG(DBG_BUS, "High-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_HIGH; + } else { + DBG(DBG_BUS, "Full-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_FULL; + } + /* Better start from scratch... */ + reset_all_endpoints(udc); + husb2_ep[0].state = WAIT_FOR_SETUP; + udc_enable(udc); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct husb2_udc *udc = &the_udc; + int ret; + + spin_lock(&udc->lock); + + ret = -ENODEV; + if (!udc->adev) + goto out; + ret = -EBUSY; + if (udc->driver) + goto out; + + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + + device_add(&udc->gadget.dev); + ret = driver->bind(&udc->gadget); + if (ret) { + DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", + driver->driver.name, ret); + device_del(&udc->gadget.dev); + + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + goto out; + } + + /* TODO: Create sysfs files */ + + DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); + udc_enable(udc); + +out: + spin_unlock(&udc->lock); + return ret; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct husb2_udc *udc = &the_udc; + int ret; + + spin_lock(&udc->lock); + + ret = -ENODEV; + if (!udc->adev) + goto out; + ret = -EINVAL; + if (driver != udc->driver) + goto out; + + local_irq_disable(); + udc_disable(udc); + local_irq_enable(); + + driver->unbind(&udc->gadget); + udc->driver = NULL; + + device_del(&udc->gadget.dev); + + /* TODO: Remove sysfs files */ + + DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); + +out: + spin_unlock(&udc->lock); + return ret; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +static int __devinit husb2_udc_probe(struct at32_device *adev) +{ + struct husb2_udc *udc = &the_udc; + int irq, ret, i; + + ret = at32_enable_device(adev); + if (ret) { + dev_err(&adev->dev, "failed to enable device\n"); + return ret; + } + + udc->adev = adev; + + ret = -ENOMEM; + udc->regs = at32_map_iomem(adev, CTRL_IOMEM_ID); + if (!udc->regs) { + dev_err(&adev->dev, "Unable to map I/O memory, aborting.\n"); + goto out_disable_dev; + } + dev_info(&adev->dev, "MMIO registers at 0x%08lx mapped at %p\n", + at32_get_iomem_base(adev, CTRL_IOMEM_ID), + udc->regs); + udc->fifo = at32_map_iomem(adev, FIFO_IOMEM_ID); + if (!udc->fifo) { + dev_err(&adev->dev, "Unable to map FIFO, aborting.\n"); + goto out_unmap_regs; + } + dev_info(&adev->dev, "FIFO at 0x%08lx mapped at %p\n", + at32_get_iomem_base(adev, FIFO_IOMEM_ID), + udc->fifo); + + device_initialize(&udc->gadget.dev); + udc->gadget.dev.parent = &adev->dev; + udc->gadget.dev.dma_mask = adev->dev.dma_mask; + + /* The 3-word descriptors must be 4-word aligned... */ + udc->desc_pool = dma_pool_create("husb2-desc", &adev->dev, + sizeof(struct husb2_dma_desc), + 16, 0); + if (!udc->desc_pool) { + dev_err(&adev->dev, "Cannot create descriptor DMA pool\n"); + goto out_unmap_fifo; + } + + at32_set_drvdata(adev, udc); + + udc_disable(udc); + + INIT_LIST_HEAD(&husb2_ep[0].ep.ep_list); + for (i = 1; i < ARRAY_SIZE(husb2_ep); i++) { + struct husb2_ep *ep = &husb2_ep[i]; + + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + } + + irq = at32_get_irq(adev); + ret = request_irq(irq, husb2_udc_irq, SA_SAMPLE_RANDOM, + "husb2_udc", udc); + if (ret) { + dev_err(&adev->dev, "Cannot request irq %d (error %d)\n", + irq, ret); + goto out_free_pool; + } + + return 0; + +out_free_pool: + dma_pool_destroy(udc->desc_pool); +out_unmap_fifo: + iounmap(udc->fifo); +out_unmap_regs: + iounmap(udc->regs); +out_disable_dev: + at32_disable_device(adev); + + at32_set_drvdata(adev, NULL); + + return ret; +} + +static int __devexit husb2_udc_remove(struct at32_device *adev) +{ + struct husb2_udc *udc; + + udc = at32_get_drvdata(adev); + if (!udc) + return 0; + + free_irq(at32_get_irq(adev), udc); + dma_pool_destroy(udc->desc_pool); + iounmap(udc->fifo); + iounmap(udc->regs); + at32_disable_device(adev); + at32_set_drvdata(adev, NULL); + + return 0; +} + +static struct at32_driver udc_driver = { + .probe = husb2_udc_probe, + .remove = __devexit_p(husb2_udc_remove), + .driver = { + .name = "usb", + }, +}; + +static int __init udc_init(void) +{ + printk(KERN_INFO "husb2device: Driver version %s\n", DRIVER_VERSION); + return at32_driver_register(&udc_driver); +} +module_init(udc_init); + +static void __exit udc_exit(void) +{ + at32_driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION("Atmel HUSB2 Device Controller driver"); +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.16.11/drivers/usb/gadget/husb2_udc.h linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/husb2_udc.h --- linux-2.6.16.11/drivers/usb/gadget/husb2_udc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/husb2_udc.h 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,228 @@ +/* + * Driver for the Atmel HUSB2device high speed USB device controller + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __LINUX_USB_GADGET_HUSB2_H +#define __LINUX_USB_GADGET_HUSB2_H + +#ifdef __ASSEMBLY__ +# define __R(x) (x) +#else +typedef struct regoff { unsigned long off; } regoff_t; +# define __R(x) ((regoff_t){ x }) +#endif + +#define USB_CTRL __R(0x000) +#define USB_FNUM __R(0x004) +#define USB_IEN __R(0x010) +#define USB_INT_STA __R(0x014) +#define USB_CLR_INT __R(0x018) +#define USB_EPT_RST __R(0x01c) + +#define HUSB2DEV_VERSION __R(0x0fc) + +/* Endpoint registers */ +#define EPT_CFG(x) __R(0x20 * (x) + 0x100) +#define EPT_CTL_ENB(x) __R(0x20 * (x) + 0x104) +#define EPT_CTL_DIS(x) __R(0x20 * (x) + 0x108) +#define EPT_CTL(x) __R(0x20 * (x) + 0x10c) +#define EPT_SET_STA(x) __R(0x20 * (x) + 0x114) +#define EPT_CLR_STA(x) __R(0x20 * (x) + 0x118) +#define EPT_STA(x) __R(0x20 * (x) + 0x11c) + +/* DMA channel registers (endpoint 0 does not support DMA) */ +#define DMA_NXT_DSC(x) __R(0x10 * (x) + 0x300) +#define DMA_ADDRESS(x) __R(0x10 * (x) + 0x304) +#define DMA_CONTROL(x) __R(0x10 * (x) + 0x308) +#define DMA_STATUS(x) __R(0x10 * (x) + 0x30c) + +/* Bit definitions */ +#define UDCCR_ENABLE 0x00000100 +#define UDCCR_FADDR_EN 0x00000080 +#define UDCCR_DEVADDR_MASK 0x0000007f + +#define UDCSR_DMA_INTx 0x7e000000 +#define UDCSR_DMA_INT_SHIFT 24 +#define UDCSR_EPT_INTx 0x00007f00 +#define UDCSR_EPT_INT_SHIFT 8 +#define UDCSR_RESUME 0x00000040 +#define UDCSR_WAKE_UP 0x00000020 +#define UDCSR_RESET 0x00000010 +#define UDCSR_SUSPEND 0x00000002 +#define UDCSR_HIGH_SPEED 0x00000001 + +#define RESET_EPT_0 0x00000001 +#define RESET_EPT_1 0x00000002 +#define RESET_EPT_2 0x00000004 +#define RESET_EPT_3 0x00000008 +#define RESET_EPT_4 0x00000010 +#define RESET_EPT_5 0x00000020 +#define RESET_EPT_6 0x00000040 + +#define EPT_MAPPED 0x80000000 +#define NB_TRANS_0 0x00000000 +#define NB_TRANS_1 0x00000100 +#define NB_TRANS_2 0x00000200 +#define NB_TRANS_3 0x00000300 +#define BK_NUMBER_1 0x00000040 +#define BK_NUMBER_2 0x00000080 +#define BK_NUMBER(x) (((x) & 3) << 6) +#define EPT_TYPE_CONTROL 0x00000000 +#define EPT_TYPE_ISOC 0x00000010 +#define EPT_TYPE_BULK 0x00000020 +#define EPT_TYPE_INT 0x00000030 +#define EPT_DIR_IN 0x00000008 +#define EPT_SIZE_8 0x00000000 +#define EPT_SIZE_16 0x00000001 +#define EPT_SIZE_32 0x00000002 +#define EPT_SIZE_64 0x00000003 +#define EPT_SIZE_128 0x00000004 +#define EPT_SIZE_256 0x00000005 +#define EPT_SIZE_512 0x00000006 +#define EPT_SIZE_1024 0x00000007 + +#define EPTCR_AUTO_VALID 0x00000002 +#define EPTCR_ENABLE 0x00000001 + +#define EPTSR_BYTE_COUNT_MASK 0x7ff00000 +#define EPTSR_BYTE_COUNT_SHIFT 20 +#define EPTSR_RXSETUP 0x00001000 +#define EPTSR_TX_BK_RDY 0x00000800 +#define EPTSR_TX_COMPLETE 0x00000400 +#define EPTSR_KILL_BANK 0x00000200 +#define EPTSR_RXRDY 0x00000200 +#define EPTSR_FORCE_STALL 0x00000020 + +/* Synth parameters */ +#define HUSB2_NR_ENDPOINTS 7 + +#define EP0_FIFO_SIZE 64 +#define EP0_EPT_SIZE EPT_SIZE_64 +#define EP0_NR_BANKS 1 +#define BULK_FIFO_SIZE 512 +#define BULK_EPT_SIZE EPT_SIZE_512 +#define BULK_NR_BANKS 2 +#define ISO_FIFO_SIZE 1024 +#define ISO_EPT_SIZE EPT_SIZE_1024 +#define ISO_NR_BANKS 3 +#define INT_FIFO_SIZE 64 +#define INT_EPT_SIZE EPT_SIZE_64 +#define INT_NR_BANKS 3 + +#ifndef __ASSEMBLY__ +enum husb2_ctrl_state { + WAIT_FOR_SETUP, + DATA_STAGE_IN, + DATA_STAGE_OUT, + STATUS_STAGE_IN, + STATUS_STAGE_OUT, + STATUS_STAGE_ADDR, +}; +/* + EP_STATE_IDLE, + EP_STATE_SETUP, + EP_STATE_IN_DATA, + EP_STATE_OUT_DATA, + EP_STATE_SET_ADDR_STATUS, + EP_STATE_RX_STATUS, + EP_STATE_TX_STATUS, + EP_STATE_HALT, +*/ + +struct husb2_dma_desc { + dma_addr_t next; + dma_addr_t addr; + u16 length; + u16 flags; +}; +#define HUSB2_DMA_BURST_LOCK_EN (1 << 7) +#define HUSB2_DMA_DESC_LOADED (1 << 6) +#define HUSB2_DMA_CH_END (1 << 5) +#define HUSB2_DMA_XFER_END (1 << 4) +#define HUSB2_DMA_BUF_END_OE (1 << 3) +#define HUSB2_DMA_BUF_CLOSE_IE (1 << 2) +#define HUSB2_DMA_LINK (1 << 1) +#define HUSB2_DMA_CH_ACTIVE (1 << 1) +#define HUSB2_DMA_CH_EN (1 << 0) + +struct husb2_ep { + int state; + struct usb_ep ep; + struct husb2_udc *udc; + + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + + u16 fifo_size; + u8 nr_banks; + u8 index; + u8 capabilities; +}; +#define HUSB2_EP_CAP_ISOC 0x0001 +#define HUSB2_EP_CAP_DMA 0x0002 + +struct husb2_packet { + struct husb2_dma_desc *desc; + dma_addr_t desc_dma; +}; + +struct husb2_request { + struct usb_request req; + struct list_head queue; + + struct husb2_packet *packet; + unsigned int nr_pkts; + + unsigned int submitted:1; + unsigned int using_dma:1; + unsigned int last_transaction:1; +}; + +struct husb2_udc { + spinlock_t lock; + + void __iomem *regs; + void __iomem *fifo; + + struct dma_pool *desc_pool; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct at32_device *adev; +}; + +#define to_husb2_ep(x) container_of((x), struct husb2_ep, ep) +#define to_husb2_req(x) container_of((x), struct husb2_request, req) +#define to_husb2_udc(x) container_of((x), struct husb2_udc, gadget) + +static inline u32 husb2_readl(struct husb2_udc *udc, regoff_t reg) +{ + return readl(udc->regs + reg.off); +} + +static inline void husb2_writel(struct husb2_udc *udc, + regoff_t reg, u32 value) +{ + writel(value, udc->regs + reg.off); +} + +#define ep_index(ep) ((ep)->index) +#define ep_can_dma(ep) ((ep)->capabilities & HUSB2_EP_CAP_DMA) +#define ep_is_in(ep) (((ep)->desc->bEndpointAddress \ + & USB_ENDPOINT_DIR_MASK) \ + == USB_DIR_IN) +#define ep_is_isochronous(ep) \ + (((ep)->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ + == USB_ENDPOINT_XFER_ISOC) +#define ep_is_control(ep) (ep_index(ep) == 0) +#define ep_name(ep) ((ep)->ep.name) +#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE) + +#endif /* !__ASSEMBLY__ */ + +#endif /* __LINUX_USB_GADGET_HUSB2_H */ diff -Nur linux-2.6.16.11/drivers/usb/gadget/Kconfig linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/Kconfig --- linux-2.6.16.11/drivers/usb/gadget/Kconfig 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/Kconfig 2006-06-26 11:33:54.000000000 +0200 @@ -187,6 +187,16 @@ Select this only if your OMAP board has a Mini-AB connector. +config USB_GADGET_HUSB2DEV + boolean "Atmel HUSB2DEVICE" + select USB_GADGET_DUALSPEED + depends on AVR32 + +config USB_HUSB2DEV + tristate + depends on USB_GADGET_HUSB2DEV + default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" diff -Nur linux-2.6.16.11/drivers/usb/gadget/Makefile linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/Makefile --- linux-2.6.16.11/drivers/usb/gadget/Makefile 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/Makefile 2006-06-26 11:33:54.000000000 +0200 @@ -7,6 +7,7 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o +obj-$(CONFIG_USB_HUSB2DEV) += husb2_udc.o # # USB gadget drivers diff -Nur linux-2.6.16.11/drivers/usb/gadget/serial.c linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/serial.c --- linux-2.6.16.11/drivers/usb/gadget/serial.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/serial.c 2006-06-26 11:33:54.000000000 +0200 @@ -406,7 +406,7 @@ .strings = gs_strings, }; -static struct usb_device_descriptor gs_device_desc = { +static struct usb_device_descriptor __attribute__((aligned(2))) gs_device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = __constant_cpu_to_le16(0x0200), @@ -426,7 +426,7 @@ .bmAttributes = USB_OTG_SRP, }; -static struct usb_config_descriptor gs_bulk_config_desc = { +static struct usb_config_descriptor __attribute__((aligned(2))) gs_bulk_config_desc = { .bLength = USB_DT_CONFIG_SIZE, .bDescriptorType = USB_DT_CONFIG, /* .wTotalLength computed dynamically */ @@ -437,7 +437,7 @@ .bMaxPower = 1, }; -static struct usb_config_descriptor gs_acm_config_desc = { +static struct usb_config_descriptor __attribute__((aligned(2))) gs_acm_config_desc = { .bLength = USB_DT_CONFIG_SIZE, .bDescriptorType = USB_DT_CONFIG, /* .wTotalLength computed dynamically */ @@ -481,7 +481,7 @@ .iInterface = GS_DATA_STR_ID, }; -static const struct usb_cdc_header_desc gs_header_desc = { +static const struct usb_cdc_header_desc __attribute__((aligned(2))) gs_header_desc = { .bLength = sizeof(gs_header_desc), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_HEADER_TYPE, @@ -511,7 +511,7 @@ .bSlaveInterface0 = 1, /* index of data interface */ }; -static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = { +static struct usb_endpoint_descriptor __attribute__((aligned(2))) gs_fullspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, @@ -520,14 +520,14 @@ .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL, }; -static struct usb_endpoint_descriptor gs_fullspeed_in_desc = { +static struct usb_endpoint_descriptor __attribute__((aligned(2))) gs_fullspeed_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_endpoint_descriptor gs_fullspeed_out_desc = { +static struct usb_endpoint_descriptor __attribute__((aligned(2))) gs_fullspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, @@ -557,7 +557,7 @@ }; #ifdef CONFIG_USB_GADGET_DUALSPEED -static struct usb_endpoint_descriptor gs_highspeed_notify_desc = { +static struct usb_endpoint_descriptor __attribute__((aligned(2))) gs_highspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, @@ -566,21 +566,21 @@ .bInterval = GS_LOG2_NOTIFY_INTERVAL+4, }; -static struct usb_endpoint_descriptor gs_highspeed_in_desc = { +static struct usb_endpoint_descriptor __attribute__((aligned(2))) gs_highspeed_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static struct usb_endpoint_descriptor gs_highspeed_out_desc = { +static struct usb_endpoint_descriptor __attribute__((aligned(2))) gs_highspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static struct usb_qualifier_descriptor gs_qualifier_desc = { +static struct usb_qualifier_descriptor __attribute__((aligned(2))) gs_qualifier_desc = { .bLength = sizeof(struct usb_qualifier_descriptor), .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16 (0x0200), diff -Nur linux-2.6.16.11/drivers/usb/gadget/zero.c linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/zero.c --- linux-2.6.16.11/drivers/usb/gadget/zero.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/usb/gadget/zero.c 2006-06-26 11:33:54.000000000 +0200 @@ -296,7 +296,7 @@ /* two full speed bulk endpoints; their use is config-dependent */ static struct usb_endpoint_descriptor -fs_source_desc = { +fs_source_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -305,7 +305,7 @@ }; static struct usb_endpoint_descriptor -fs_sink_desc = { +fs_sink_desc __attribute__((aligned(2))) = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, diff -Nur linux-2.6.16.11/drivers/video/backlight/Kconfig linux-2.6.16.11-avr32-20060626/drivers/video/backlight/Kconfig --- linux-2.6.16.11/drivers/video/backlight/Kconfig 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/video/backlight/Kconfig 2006-06-26 11:33:53.000000000 +0200 @@ -42,6 +42,18 @@ depends on LCD_CLASS_DEVICE default y +config LCD_LTV350QV + tristate "Samsung LTV350QV LCD Panel" + depends on LCD_DEVICE && SPI + default n + help + If you have a Samsung LTV350QV LCD panel, say y to include a + power control driver for it. The panel starts up in power + off state, so you need this driver in order to see any + output. + + The LTV350QV panel is present on most ATSTK1000 boards. + config BACKLIGHT_CORGI tristate "Sharp Corgi Backlight Driver (SL-C7xx Series)" depends on BACKLIGHT_DEVICE && PXA_SHARPSL diff -Nur linux-2.6.16.11/drivers/video/backlight/ltv350qv.c linux-2.6.16.11-avr32-20060626/drivers/video/backlight/ltv350qv.c --- linux-2.6.16.11/drivers/video/backlight/ltv350qv.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/video/backlight/ltv350qv.c 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,301 @@ +/* + * Power control for Samsung LTV350QV Quarter VGA LCD Panel + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) + +struct ltv350qv { + struct spi_device *spi; + u8 *buffer; + int power; + struct semaphore lock; + struct lcd_device *ld; + struct list_head list; + int halt_done; +}; + +static LIST_HEAD(lcd_list); + +static int ltv350qv_write_reg(struct ltv350qv *lcd, u8 reg, u16 val) +{ + struct spi_message msg; + struct spi_transfer index_xfer = { + .len = 3, + .cs_change = 1, + }; + struct spi_transfer value_xfer = { + .len = 3, + .cs_change = 1, + }; + + spi_message_init(&msg); + + /* register index */ + lcd->buffer[0] = 0x74; + lcd->buffer[1] = 0x00; + lcd->buffer[2] = reg & 0x7f; + index_xfer.tx_buf = lcd->buffer; + spi_message_add_tail(&index_xfer, &msg); + + /* register value */ + lcd->buffer[4] = 0x76; + lcd->buffer[5] = val >> 8; + lcd->buffer[6] = val; + value_xfer.tx_buf = lcd->buffer + 4; + spi_message_add_tail(&value_xfer, &msg); + + return spi_sync(lcd->spi, &msg); +} + +#define write_reg(_spi, reg, val) \ + do { \ + ret = ltv350qv_write_reg(_spi, reg, val); \ + if (ret) \ + goto out; \ + } while (0) + +static int ltv350qv_power_on(struct ltv350qv *lcd) +{ + int ret; + + write_reg(lcd, 9, 0x0000); + msleep(15); + write_reg(lcd, 9, 0x4000); + write_reg(lcd, 10, 0x2000); + write_reg(lcd, 9, 0x4055); + msleep(55); + write_reg(lcd, 1, 0x409d); + write_reg(lcd, 2, 0x0204); + write_reg(lcd, 3, 0x0100); + write_reg(lcd, 4, 0x3000); + write_reg(lcd, 5, 0x4003); + write_reg(lcd, 6, 0x000a); + write_reg(lcd, 7, 0x0021); + write_reg(lcd, 8, 0x0c00); + write_reg(lcd, 10, 0x0103); + write_reg(lcd, 11, 0x0301); + write_reg(lcd, 12, 0x1f0f); + write_reg(lcd, 13, 0x1f0f); + write_reg(lcd, 14, 0x0707); + write_reg(lcd, 15, 0x0307); + write_reg(lcd, 16, 0x0707); + write_reg(lcd, 17, 0x0000); + write_reg(lcd, 18, 0x0004); + write_reg(lcd, 19, 0x0000); + + msleep(20); + write_reg(lcd, 9, 0x4a55); + write_reg(lcd, 5, 0x5003); + +out: + return ret; +} + +static int ltv350qv_power_off(struct ltv350qv *lcd) +{ + int ret; + + /* GON -> 0, POC -> 0 */ + write_reg(lcd, 9, 0x4055); + /* DSC -> 0 */ + write_reg(lcd, 5, 0x4003); + /* VCOMG -> 0 */ + write_reg(lcd, 10, 0x2103); + + msleep(1); + + /* AP[2:0] -> 000 */ + write_reg(lcd, 9, 0x4050); + +out: + return ret; +} + +static int ltv350qv_power(struct ltv350qv *lcd, int power) +{ + int ret = 0; + + down(&lcd->lock); + + if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) + ret = ltv350qv_power_on(lcd); + else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) + ret = ltv350qv_power_off(lcd); + + if (!ret) + lcd->power = power; + + up(&lcd->lock); + + return ret; +} + +static int ltv350qv_set_power(struct lcd_device *ld, int power) +{ + struct ltv350qv *lcd; + + lcd = class_get_devdata(&ld->class_dev); + return ltv350qv_power(lcd, power); +} + +static int ltv350qv_get_power(struct lcd_device *ld) +{ + struct ltv350qv *lcd; + + lcd = class_get_devdata(&ld->class_dev); + return lcd->power; +} + +static struct lcd_properties lcd_properties = { + .owner = THIS_MODULE, + .get_power = ltv350qv_get_power, + .set_power = ltv350qv_set_power, +}; + +static int __devinit ltv350qv_probe(struct spi_device *spi) +{ + struct ltv350qv *lcd; + struct lcd_device *ld; + int ret; + + lcd = kzalloc(sizeof(struct ltv350qv), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + lcd->spi = spi; + lcd->power = FB_BLANK_POWERDOWN; + init_MUTEX(&lcd->lock); + lcd->buffer = kzalloc(8, GFP_KERNEL); + + spi->mode = SPI_MODE_3; + spi->bits_per_word = 8; + ret = spi_setup(spi); + if (ret) + goto out_free_lcd; + + ld = lcd_device_register("ltv350qv", lcd, &lcd_properties); + if (IS_ERR(ld)) { + ret = PTR_ERR(ld); + goto out_free_lcd; + } + lcd->ld = ld; + + list_add(&lcd->list, &lcd_list); + + ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK); + if (ret) + goto out_unregister; + + dev_set_drvdata(&spi->dev, lcd); + + return 0; + +out_unregister: + lcd_device_unregister(ld); +out_free_lcd: + kfree(lcd); + return ret; +} + +static int __devexit ltv350qv_remove(struct spi_device *spi) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + ltv350qv_power(lcd, FB_BLANK_POWERDOWN); + list_del(&lcd->list); + lcd_device_unregister(lcd->ld); + kfree(lcd); + + return 0; +} + +#ifdef CONFIG_PM +static int ltv350qv_suspend(struct spi_device *spi, + pm_message_t state, u32 level) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + if (level == SUSPEND_POWER_DOWN) + return ltv350qv_power(lcd, FB_BLANK_POWERDOWN); + + return 0; +} + +static int ltv350qv_resume(struct spi_device *spi, u32 level) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + if (level == RESUME_POWER_ON) + return ltv350qv_power(lcd, FB_BLANK_UNBLANK); + + return 0; +} +#else +#define ltv350qv_suspend NULL +#define ltv350qv_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt */ +static int ltv350qv_halt(struct notifier_block *nb, unsigned long event, + void *p) +{ + struct ltv350qv *lcd; + + list_for_each_entry(lcd, &lcd_list, list) { + if (!lcd->halt_done) + ltv350qv_power(lcd, FB_BLANK_POWERDOWN); + lcd->halt_done = 1; + } + + return NOTIFY_OK; +} + +static struct spi_driver ltv350qv_driver = { + .driver = { + .name = "ltv350qv", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = ltv350qv_probe, + .remove = __devexit_p(ltv350qv_remove), + .suspend = ltv350qv_suspend, + .resume = ltv350qv_resume, +}; + +static struct notifier_block ltv350qv_notifier = { + .notifier_call = ltv350qv_halt, +}; + +static int __init ltv350qv_init(void) +{ + register_reboot_notifier(<v350qv_notifier); + return spi_register_driver(<v350qv_driver); +} + +static void __exit ltv350qv_exit(void) +{ + unregister_reboot_notifier(<v350qv_notifier); + spi_unregister_driver(<v350qv_driver); +} +module_init(ltv350qv_init); +module_exit(ltv350qv_exit); + +MODULE_AUTHOR("Atmel Norway"); +MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver"); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.16.11/drivers/video/backlight/Makefile linux-2.6.16.11-avr32-20060626/drivers/video/backlight/Makefile --- linux-2.6.16.11/drivers/video/backlight/Makefile 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/video/backlight/Makefile 2006-06-26 11:33:53.000000000 +0200 @@ -5,3 +5,4 @@ obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_SHARP_LOCOMO) += locomolcd.o +obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o \ No newline at end of file diff -Nur linux-2.6.16.11/drivers/video/fbmem.c linux-2.6.16.11-avr32-20060626/drivers/video/fbmem.c --- linux-2.6.16.11/drivers/video/fbmem.c 2006-06-26 11:34:38.000000000 +0200 +++ linux-2.6.16.11-avr32-20060626/drivers/video/fbmem.c 2006-06-26 11:33:53.000000000 +0200 @@ -1157,6 +1157,7 @@ /* frame buffer memory */ start = info->fix.smem_start; len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); + pr_debug("fb_mmap: start = 0x%08lx, len = 0x%08lx\n", start, len); if (off >= len) { /* memory mapped io */ off -= len; @@ -1172,6 +1173,7 @@ if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; off += start; + pr_debug("fb_mmap: off = 0x%08lx\n", off); vma->vm_pgoff = off >> PAGE_SHIFT; /* This is an IO map - tell maydump to skip this VMA */ vma->vm_flags |= VM_IO | VM_RESERVED; @@ -1207,6 +1209,10 @@ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; #elif defined(__arm__) || defined(__sh__) || defined(__m32r__) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#elif defined(__avr32__) + vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot) + & ~_PAGE_CACHABLE) + | (_PAGE_BUFFER | _PAGE_DIRTY)); #elif defined(__ia64__) if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); @@ -1219,6 +1225,7 @@ vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; #endif /* !__sparc_v9__ */ + pr_debug("fb_mmap: vm_page_prot = 0x%08lx\n", vma->vm_page_prot); return 0; #endif /* !sparc32 */ } diff -Nur linux-2.6.16.11/drivers/video/Kconfig linux-2.6.16.11-avr32-20060626/drivers/video/Kconfig --- linux-2.6.16.11/drivers/video/Kconfig 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/video/Kconfig 2006-06-26 11:33:53.000000000 +0200 @@ -186,6 +186,28 @@ If you plan to use the LCD display with your SA-1100 system, say Y here. +config FB_SIDSA + tristate "SIDSA LCDC support" + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + depends on FB && AVR32 + help + This enables support for the SIDSA LCD Controller. + +config FB_SIDSA_DEFAULT_BPP + int "SIDSA LCDC default color depth" + default 24 + depends on FB_SIDSA + help + Specify the maximum color depth you want to be able to + support. This, together with the resolution of the LCD + panel, determines the amount of framebuffer memory allocated + when the driver is initialized. + + Allowable values are 1, 2, 4, 8, 16, 24 and 32. If unsure, + say 24. + config FB_IMX tristate "Motorola i.MX LCD support" depends on FB && ARM && ARCH_IMX diff -Nur linux-2.6.16.11/drivers/video/Makefile linux-2.6.16.11-avr32-20060626/drivers/video/Makefile --- linux-2.6.16.11/drivers/video/Makefile 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/video/Makefile 2006-06-26 11:33:53.000000000 +0200 @@ -74,6 +74,7 @@ obj-$(CONFIG_FB_G364) += g364fb.o obj-$(CONFIG_FB_SA1100) += sa1100fb.o obj-$(CONFIG_FB_SUN3) += sun3fb.o +obj-$(CONFIG_FB_SIDSA) += sidsafb.o obj-$(CONFIG_FB_HIT) += hitfb.o obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o obj-$(CONFIG_FB_PVR2) += pvr2fb.o diff -Nur linux-2.6.16.11/drivers/video/sidsafb.c linux-2.6.16.11-avr32-20060626/drivers/video/sidsafb.c --- linux-2.6.16.11/drivers/video/sidsafb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/drivers/video/sidsafb.c 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,790 @@ +/* + * Framebuffer Driver for Atmel/SIDSA LCD Controller + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* More or less configurable parameters */ +#define SIDSAFB_FIFO_SIZE 512 +#define SIDSAFB_DMA_BURST_LEN 8 + +/* TODO: These should be autogenerated from part description file */ +#define LCDC_DISTYPE_STN_MONO 0 +#define LCDC_DISTYPE_STN_COLOR 1 +#define LCDC_DISTYPE_TFT 2 +#define LCDC_LUT 0xc00 + +struct sidsafb_info { + spinlock_t lock; + struct fb_info * info; + void __iomem * regs; + unsigned long irq_base; + wait_queue_head_t vsync_wait; + unsigned int guard_time; + struct at32_device *adev; + u32 pseudo_palette[16]; +}; + +/* + * How large framebuffer to allocate if none was provided by the + * platform. This default is the smallest we can possibly get away + * with. + */ +static unsigned long fb_size = (320 * 240); + +#if 0 +static struct fb_videomode sony_modes[] = { + { + .refresh = 48, + .xres = 240, .yres = 160, + .pixclock = 520833, + + .left_margin = 7, .right_margin = 9, + .upper_margin = 19, .lower_margin = 20, + .hsync_len = 9, .vsync_len = 2, + + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, +}; +#endif + +#if 0 +static struct fb_videomode vga_modes[] = { + { + .refresh = 122, + .xres = 320, .yres = 240, + .pixclock = 80000, + + .left_margin = 10, .right_margin = 20, + .upper_margin = 30, .lower_margin = 5, + .hsync_len = 20, .vsync_len = 3, + + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + { + .refresh = 70, + .xres = 640, .yres = 480, + .pixclock = 40000, + + .left_margin = 10, .right_margin = 20, + .upper_margin = 30, .lower_margin = 5, + .hsync_len = 20, .vsync_len = 3, + + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, +}; +#else +static struct fb_videomode samsung_modes[] = { + { + .refresh = 75, + .xres = 320, .yres = 240, + .pixclock = 145111, + + .left_margin = 17, .right_margin = 33, + .upper_margin = 8, .lower_margin = 10, + .hsync_len = 16, .vsync_len = 1, + + .sync = FB_SYNC_PCLK_RISING, + .vmode = FB_VMODE_NONINTERLACED, + }, +}; +#endif + +#if 1 +static struct fb_monspecs default_monspecs = { + .modedb = samsung_modes, + .manufacturer = "SNG", + .monitor = "LCD panel", + .serial_no = "xxxx", + .ascii = "yyyy", + .modedb_len = ARRAY_SIZE(samsung_modes), + .hfmin = 14820, + .hfmax = 22230, + .vfmin = 60, + .vfmax = 90, + .dclkmax = 30000000, +}; +#endif + +#if 0 +static struct fb_monspecs default_monspecs = { + .modedb = sony_modes, + .manufacturer = "SNY", /* 4 chars?!? */ + .monitor = "LCD panel", + .serial_no = "xxxx", + .ascii = "yyyy", + .modedb_len = ARRAY_SIZE(sony_modes), + .hfmin = 7000, + .hfmax = 8000, + .vfmin = 45, + .vfmax = 50, +}; +// #else +static struct fb_monspecs default_monspecs = { + .modedb = vga_modes, + .manufacturer = "VGA", + .monitor = "Generic VGA", + .serial_no = "xxxx", + .ascii = "yyyy", + .modedb_len = ARRAY_SIZE(vga_modes), + .hfmin = 30000, + .hfmax = 64000, + .vfmin = 50, + .vfmax = 150, +}; +#endif + +/* Driver defaults */ +static struct fb_fix_screeninfo sidsafb_fix __devinitdata = { + .id = "sidsafb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 1, + .ypanstep = 1, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static void sidsafb_update_dma(struct fb_info *info, + struct fb_var_screeninfo *var) +{ + struct sidsafb_info *sinfo = info->par; + struct fb_fix_screeninfo *fix = &info->fix; + unsigned long dma_addr; + unsigned long pixeloff; + unsigned long dma2dcfg; + + dma_addr = (fix->smem_start + var->yoffset * fix->line_length + + var->xoffset * var->bits_per_pixel / 8); + + dma_addr &= ~3UL; + pixeloff = LCDC_MKBF(DMA2DCFG_PIXELOFF, var->xoffset * var->bits_per_pixel); + + /* Set framebuffer DMA base address and pixel offset */ + lcdc_writel(sinfo, DMABADDR1, dma_addr); + dma2dcfg = lcdc_readl(sinfo, DMA2DCFG); + dma2dcfg = LCDC_INSBF(DMA2DCFG_PIXELOFF, pixeloff, dma2dcfg); + lcdc_writel(sinfo, DMA2DCFG, dma2dcfg); + + /* Update configuration */ + lcdc_writel(sinfo, DMACON, (lcdc_readl(sinfo, DMACON) + | LCDC_BIT(DMACON_DMAUPDT))); +} + +/** + * sidsafb_check_var - Validates a var passed in. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer + * + * Checks to see if the hardware supports the state requested by + * var passed in. This function does not alter the hardware + * state!!! This means the data stored in struct fb_info and + * struct sidsafb_info do not change. This includes the var + * inside of struct fb_info. Do NOT change these. This function + * can be called on its own if we intent to only test a mode and + * not actually set it. The stuff in modedb.c is a example of + * this. If the var passed in is slightly off by what the + * hardware can support then we alter the var PASSED in to what + * we can do. If the hardware doesn't support mode change a + * -EINVAL will be returned by the upper layers. You don't need + * to implement this function then. If you hardware doesn't + * support changing the resolution then this function is not + * needed. In this case the driver would just provide a var that + * represents the static state the screen is in. + * + * Returns negative errno on error, or zero on success. + */ +static int sidsafb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + unsigned long new_fb_size; + + pr_debug("sidsafb_check_var:\n"); + pr_debug(" resolution: %ux%u\n", var->xres, var->yres); + pr_debug(" pixclk: %llu Hz\n", 1000000000000ULL / var->pixclock); + pr_debug(" bpp: %u\n", var->bits_per_pixel); + + new_fb_size = (var->xres_virtual * var->yres_virtual + * ((var->bits_per_pixel + 7) / 8)); + if (new_fb_size > info->fix.smem_len) { + printk(KERN_NOTICE + "sidsafb: %uB framebuffer too small for %ux%ux%u\n", + info->fix.smem_len, var->xres_virtual, + var->yres_virtual, var->bits_per_pixel); + return -EINVAL; + } + + /* Force same alignment for each line */ + var->xres = (var->xres + 3) & ~3UL; + var->xres_virtual = (var->xres_virtual + 3) & ~3UL; + + var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; + var->transp.offset = var->transp.length = 0; + + switch (var->bits_per_pixel) { + case 2: + case 4: + case 8: + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length + = var->bits_per_pixel; + break; + case 15: + case 16: + /* + * Bit 16 is the "intensity" bit, I think. Not sure + * what we're going to use that for... + */ + var->red.offset = 0; + var->green.offset = 5; + var->blue.offset = 10; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + break; + case 24: + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + break; + default: + printk(KERN_NOTICE "sidsafb: color depth %d not supported\n", + var->bits_per_pixel); + return -EINVAL; + } + + var->xoffset = var->yoffset = 0; + var->red.msb_right = var->green.msb_right = var->blue.msb_right = + var->transp.msb_right = 0; + + return 0; +} + +/** + * sidsafb_set_par - Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer + * + * Using the fb_var_screeninfo in fb_info we set the resolution + * of the this particular framebuffer. This function alters the + * par AND the fb_fix_screeninfo stored in fb_info. It doesn't + * not alter var in fb_info since we are using that data. This + * means we depend on the data in var inside fb_info to be + * supported by the hardware. sidsafb_check_var is always called + * before sidsafb_set_par to ensure this. Again if you can't + * change the resolution you don't need this function. + * + */ +static int sidsafb_set_par(struct fb_info *info) +{ + struct sidsafb_info *sinfo = info->par; + unsigned long value; + + pr_debug("sidsafb_set_par:\n"); + pr_debug(" * resolution: %ux%u (%ux%u virtual)\n", + info->var.xres, info->var.yres, + info->var.xres_virtual, info->var.yres_virtual); + + /* Turn off the LCD controller and the DMA controller */ + pr_debug("writing 0x%08x to %p\n", + LCDC_MKBF(PWRCON_GUARD_TIME, sinfo->guard_time), + sinfo->regs + LCDC_PWRCON); + lcdc_writel(sinfo, PWRCON, + LCDC_MKBF(PWRCON_GUARD_TIME, sinfo->guard_time)); + pr_debug("writing 0 to %p\n", sinfo->regs + LCDC_DMACON); + lcdc_writel(sinfo, DMACON, 0); + + info->fix.line_length = (info->var.xres_virtual + * (info->var.bits_per_pixel / 8)); + + if (info->var.bits_per_pixel <= 8) + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + else + info->fix.visual = FB_VISUAL_TRUECOLOR; + + /* Re-initialize the DMA engine... */ + pr_debug(" * update DMA engine\n"); + sidsafb_update_dma(info, &info->var); + + /* ...set frame size and burst length = 8 words (?) */ + value = LCDC_MKBF(DMAFRMCFG_FRMSIZE, + (info->var.yres * info->fix.line_length + 3) / 4); + value |= LCDC_MKBF(DMAFRMCFG_BRSTLEN, (SIDSAFB_DMA_BURST_LEN - 1)); + lcdc_writel(sinfo, DMAFRMCFG, value); + + /* ...set 2D configuration (necessary for xres_virtual != xres) */ + value = LCDC_MKBF(DMA2DCFG_ADDRINC, + info->var.xres_virtual - info->var.xres); + lcdc_writel(sinfo, DMA2DCFG, value); + + /* ...wait for DMA engine to become idle... */ + while (lcdc_readl(sinfo, DMACON) & LCDC_BIT(DMACON_DMABUSY)) + msleep(10); + + pr_debug(" * re-enable DMA engine\n"); + /* ...and enable it with updated configuration */ + lcdc_writel(sinfo, DMACON, (LCDC_BIT(DMACON_DMAEN) + | LCDC_BIT(DMACON_DMAUPDT) + | LCDC_BIT(DMACON_DMA2DEN))); + + /* Now, the LCD core... */ + + /* Set pixel clock */ + value = (at32_get_sclk_hz(sinfo->adev, 0) / 100000) * info->var.pixclock; + value /= 10000000; + value = (value + 1) / 2; + if (value == 0) { + printk("sidsafb: Bypassing lcdc_pclk divider\n"); + lcdc_writel(sinfo, LCDCON1, LCDC_BIT(LCDCON1_BYPASS)); + } else { + lcdc_writel(sinfo, LCDCON1, LCDC_MKBF(LCDCON1_CLKVAL, value - 1)); + } + + /* Initialize control register 2 */ + value = (LCDC_BIT(LCDCON2_CLKMOD) + | LCDC_MKBF(LCDCON2_DISTYPE, LCDC_DISTYPE_TFT)); + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) + value |= LCDC_BIT(LCDCON2_INVLINE); + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) + value |= LCDC_BIT(LCDCON2_INVFRAME); + if (info->var.sync & FB_SYNC_PCLK_RISING) + value |= LCDC_BIT(LCDCON2_INVCLK); + + switch (info->var.bits_per_pixel) { + case 1: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 0); break; + case 2: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 1); break; + case 4: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 2); break; + case 8: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 3); break; + case 15: /* fall through */ + case 16: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 4); break; + case 24: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 5); break; + case 32: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 6); break; + default: BUG(); break; + } + pr_debug(" * LCDCON2 = %08lx\n", value); + lcdc_writel(sinfo, LCDCON2, value); + + /* Vertical timing */ + value = LCDC_MKBF(LCDTIM1_VPW, info->var.vsync_len - 1); + value |= LCDC_MKBF(LCDTIM1_VBP, info->var.upper_margin); + value |= LCDC_MKBF(LCDTIM1_VFP, info->var.lower_margin); + pr_debug(" * LCDTIM1 = %08lx\n", value); + lcdc_writel(sinfo, LCDTIM1, value); + + /* Horizontal timing */ + value = LCDC_MKBF(LCDTIM2_HFP, info->var.right_margin - 1); + value |= LCDC_MKBF(LCDTIM2_HPW, info->var.hsync_len - 1); + value |= LCDC_MKBF(LCDTIM2_HBP, info->var.left_margin - 1); + pr_debug(" * LCDTIM2 = %08lx\n", value); + lcdc_writel(sinfo, LCDTIM2, value); + + /* Display size */ + value = LCDC_MKBF(LCDFRMCFG_LINESIZE, info->var.xres - 1); + value |= LCDC_MKBF(LCDFRMCFG_LINEVAL, info->var.yres - 1); + lcdc_writel(sinfo, LCDFRMCFG, value); + + /* FIFO Threshold: Use formula from data sheet */ + value = SIDSAFB_FIFO_SIZE - (2 * SIDSAFB_DMA_BURST_LEN + 3); + lcdc_writel(sinfo, LCDFIFO, value); + + /* Toggle LCD_MODE every frame */ + lcdc_writel(sinfo, LCDMVAL, 0); + + /* Disable all interrupts */ + lcdc_writel(sinfo, LCD_IDR, ~0UL); + + /* Wait for the LCDC core to become idle and enable it */ + while(lcdc_readl(sinfo, PWRCON) & LCDC_BIT(PWRCON_LCD_BUSY)) + msleep(10); + + pr_debug(" * re-enable LCD core\n"); + lcdc_writel(sinfo, PWRCON, + LCDC_MKBF(PWRCON_GUARD_TIME, sinfo->guard_time) + | LCDC_BIT(PWRCON_LCD_PWR)); + + pr_debug(" * DONE\n"); + return 0; +} + +static inline u_int chan_to_field(u_int chan, const struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +/** + * sidsafb_setcolreg - Optional function. Sets a color register. + * @regno: Which register in the CLUT we are programming + * @red: The red value which can be up to 16 bits wide + * @green: The green value which can be up to 16 bits wide + * @blue: The blue value which can be up to 16 bits wide. + * @transp: If supported the alpha value which can be up to 16 bits wide. + * @info: frame buffer info structure + * + * Set a single color register. The values supplied have a 16 bit + * magnitude which needs to be scaled in this function for the hardware. + * Things to take into consideration are how many color registers, if + * any, are supported with the current color visual. With truecolor mode + * no color palettes are supported. Here a psuedo palette is created + * which we store the value in pseudo_palette in struct fb_info. For + * pseudocolor mode we have a limited color palette. To deal with this + * we can program what color is displayed for a particular pixel value. + * DirectColor is similar in that we can program each color field. If + * we have a static colormap we don't need to implement this function. + * + * Returns negative errno on error, or zero on success. In an + * ideal world, this would have been the case, but as it turns + * out, the other drivers return 1 on failure, so that's what + * we're going to do. + */ +static int sidsafb_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) +{ + struct sidsafb_info *sinfo = info->par; + unsigned int val; + u32 *pal; + int ret = 1; + + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + if (regno < 16) { + pal = info->pseudo_palette; + + val = chan_to_field(red, &info->var.red); + val |= chan_to_field(green, &info->var.green); + val |= chan_to_field(blue, &info->var.blue); + + pal[regno] = val; + ret = 0; + } + break; + + case FB_VISUAL_PSEUDOCOLOR: + if (regno < 256) { + val = ((red >> 11) & 0x001f); + val |= ((green >> 6) & 0x03e0); + val |= ((blue >> 1) & 0x7c00); + + /* + * TODO: intensity bit. Maybe something like + * ~(red[10] ^ green[10] ^ blue[10]) & 1 + */ + + lcdc_writel(sinfo, LUT + regno * 4, val); + ret = 0; + } + break; + } + + return ret; +} + +static int sidsafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + pr_debug("sidsafb_pan_display\n"); + + sidsafb_update_dma(info, var); + + return 0; +} + +static struct fb_ops sidsafb_ops = { + .owner = THIS_MODULE, + .fb_check_var = sidsafb_check_var, + .fb_set_par = sidsafb_set_par, + .fb_setcolreg = sidsafb_setcolreg, + .fb_pan_display = sidsafb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +static irqreturn_t sidsafb_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct fb_info *info = dev_id; + struct sidsafb_info *sinfo = info->par; + u32 status; + + status = lcdc_readl(sinfo, LCD_ISR); + while (status) { + if (status & LCDC_BIT(LCD_ISR_EOFIS)) { + pr_debug("sidsafb: DMA End Of Frame interrupt\n"); + + lcdc_writel(sinfo, LCD_ICR, LCDC_BIT(LCD_ICR_EOFIC)); + status &= ~LCDC_BIT(LCD_ISR_EOFIS); + wake_up(&sinfo->vsync_wait); + } + + if (status) { + printk(KERN_ERR + "LCDC: Interrupts still pending: 0x%x\n", + status); + lcdc_writel(sinfo, LCD_IDR, status); + } + + status = lcdc_readl(sinfo, LCD_ISR); + } + + return IRQ_HANDLED; +} + +static void __devinit init_pseudo_palette(u32 *palette) +{ + static const u32 init_palette[16] = { + 0x000000, + 0xaa0000, + 0x00aa00, + 0xaa5500, + 0x0000aa, + 0xaa00aa, + 0x00aaaa, + 0xaaaaaa, + 0x555555, + 0xff5555, + 0x55ff55, + 0xffff55, + 0x5555ff, + 0xff55ff, + 0x55ffff, + 0xffffff + }; + + memcpy(palette, init_palette, sizeof(init_palette)); +} + +static int __devinit sidsafb_set_fbinfo(struct sidsafb_info *sinfo) +{ + struct fb_info *info = sinfo->info; + + init_pseudo_palette(sinfo->pseudo_palette); + + info->flags = (FBINFO_DEFAULT + | FBINFO_PARTIAL_PAN_OK + | FBINFO_HWACCEL_XPAN + | FBINFO_HWACCEL_YPAN); + memcpy(&info->fix, &sidsafb_fix, sizeof(info->fix)); + memcpy(&info->monspecs, &default_monspecs, sizeof(info->monspecs)); + info->fbops = &sidsafb_ops; + info->pseudo_palette = sinfo->pseudo_palette; + + init_waitqueue_head(&sinfo->vsync_wait); + + return 0; +} + +static int __devinit sidsafb_probe(struct at32_device *adev) +{ + struct fb_platform_data *fb_data = adev->dev.platform_data; + struct fb_info *info; + struct sidsafb_info *sinfo; + const struct resource *mmio_resource; + int ret; + + pr_debug("sidsafb_probe BEGIN\n"); + + mmio_resource = at32_find_resource(adev, 0, IORESOURCE_MEM); + if (!mmio_resource) { + dev_err(&adev->dev, "no MMIO resource found\n"); + return -ENXIO; + } + + ret = at32_enable_device(adev); + if (ret) { + dev_err(&adev->dev, "failed to enable device\n"); + goto out; + } + + ret = -ENOMEM; + info = framebuffer_alloc(sizeof(struct sidsafb_info), &adev->dev); + if (!info) { + dev_err(&adev->dev, "failed to allocate memory\n"); + goto disable_dev; + } + + sinfo = info->par; + sinfo->info = info; + sinfo->adev = adev; + sinfo->guard_time = 1; + + spin_lock_init(&sinfo->lock); + sidsafb_set_fbinfo(sinfo); + info->fix.mmio_start = mmio_resource->start; + info->fix.mmio_len = mmio_resource->end - mmio_resource->start + 1; + sinfo->irq_base = at32_get_irq(adev); + + /* Use platform-supplied framebuffer memory if available */ + if (fb_data) { + info->fix.smem_start = fb_data->fbmem_start; + info->fix.smem_len = fb_data->fbmem_size; + info->screen_base = ioremap(info->fix.smem_start, + info->fix.smem_len); + } else { + dma_addr_t paddr; + + info->fix.smem_len = fb_size; + info->screen_base = dma_alloc_coherent(&adev->dev, fb_size, + &paddr, GFP_KERNEL); + info->fix.smem_start = paddr; + } + + if (!info->screen_base) { + printk(KERN_ERR "sidsafb: Could not allocate framebuffer\n"); + goto free_info; + } + + sinfo->regs = ioremap(info->fix.mmio_start, info->fix.mmio_len); + if (!sinfo->regs) { + printk(KERN_ERR "sidsafb: Could not map LCDC registers\n"); + goto free_fb; + } + + /* HACK: Set up GCLK7 for the LCDC. We'll just use the same + * divider as the AHB clock to simplify things a bit. */ + writel(0x016, (void *)0xfff0007c); + + ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb, + info->monspecs.modedb_len, info->monspecs.modedb, + CONFIG_FB_SIDSA_DEFAULT_BPP); + if (!ret) { + printk(KERN_ERR "sidsafb: No suitable video mode found\n"); + goto free_info; + } + + ret = request_irq(sinfo->irq_base, sidsafb_interrupt, 0, + "sidsafb", info); + if (ret) + goto unmap_regs; + + /* Allocate colormap */ + if (fb_alloc_cmap(&info->cmap, 256, 0)) { + ret = -ENOMEM; + goto unregister_irqs; + } + + /* + * Tell the world that we're ready to go + */ + ret = register_framebuffer(info); + if (ret) + goto free_cmap; + + printk("fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n", + info->node, info->fix.mmio_start, sinfo->regs, sinfo->irq_base); + + at32_set_drvdata(adev, info); + + memset_io(info->screen_base, 0, info->fix.smem_len); + info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; + ret = fb_set_var(info, &info->var); + if (ret) + printk(KERN_WARNING + "sidsafb: Unable to set display parameters\n"); + info->var.activate &= ~(FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW); + + pr_debug("sidsafb_probe SUCCESS\n"); + return 0; + + +free_cmap: + fb_dealloc_cmap(&info->cmap); +unregister_irqs: + free_irq(sinfo->irq_base, info); +unmap_regs: + iounmap(sinfo->regs); +free_fb: + if (!fb_data) + dma_free_coherent(&adev->dev, info->fix.smem_len, + (void __force *)info->screen_base, + info->fix.smem_start); +free_info: + framebuffer_release(info); +disable_dev: + at32_disable_device(adev); +out: + pr_debug("sidsafb_probe FAILED\n"); + return ret; +} + +static int __devexit sidsafb_remove(struct at32_device *adev) +{ + struct fb_info *info = at32_get_drvdata(adev); + struct sidsafb_info *sinfo; + + if (!info) + return 0; + sinfo = info->par; + + /* TODO: Restore original state */ + unregister_framebuffer(info); + + fb_dealloc_cmap(&info->cmap); + free_irq(sinfo->irq_base, info); + iounmap(sinfo->regs); + if (!adev->dev.platform_data) + dma_free_coherent(&adev->dev, info->fix.smem_len, + (void __force *)info->screen_base, + info->fix.smem_start); + at32_set_drvdata(adev, NULL); + framebuffer_release(info); + at32_disable_device(adev); + + return 0; +} + +static struct at32_driver sidsafb_driver = { + .probe = sidsafb_probe, + .remove = __devexit_p(sidsafb_remove), + .driver = { + .name = "lcdc", + }, +}; + +int __init sidsafb_init(void) +{ + return at32_driver_register(&sidsafb_driver); +} + +static void __exit sidsafb_exit(void) +{ + at32_driver_unregister(&sidsafb_driver); +} + +module_init(sidsafb_init); +module_exit(sidsafb_exit); + +module_param(fb_size, ulong, 0644); +MODULE_PARM_DESC(fb_size, "Minimum framebuffer size to allocate"); + +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_DESCRIPTION("Atmel/SIDSA LCD Controller framebuffer driver"); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.16.11/include/asm-avr32/addrspace.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/addrspace.h --- linux-2.6.16.11/include/asm-avr32/addrspace.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/addrspace.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,43 @@ +/* + * Defitions for the address spaces of the AVR32 CPUs. Heavily based on + * include/asm-sh/addrspace.h + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_ADDRSPACE_H +#define __ASM_AVR32_ADDRSPACE_H + +#ifdef CONFIG_MMU + +/* Memory segments when segmentation is enabled */ +#define P0SEG 0x00000000 +#define P1SEG 0x80000000 +#define P2SEG 0xa0000000 +#define P3SEG 0xc0000000 +#define P4SEG 0xe0000000 + +/* Returns the privileged segment base of a given address */ +#define PXSEG(a) (((unsigned long)(a)) & 0xe0000000) + +/* Returns the physical address of a PnSEG (n=1,2) address */ +#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff) + +/* + * Map an address to a certain privileged segment + */ +#define P1SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) \ + | P1SEG)) +#define P2SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) \ + | P2SEG)) +#define P3SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) \ + | P3SEG)) +#define P4SEGADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) \ + | P4SEG)) + +#endif /* CONFIG_MMU */ + +#endif /* __ASM_AVR32_ADDRSPACE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/a.out.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/a.out.h --- linux-2.6.16.11/include/asm-avr32/a.out.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/a.out.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,26 @@ +#ifndef __ASM_AVR32_A_OUT_H +#define __ASM_AVR32_A_OUT_H + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#define N_TRSIZE(a) ((a).a_trsize) +#define N_DRSIZE(a) ((a).a_drsize) +#define N_SYMSIZE(a) ((a).a_syms) + +#ifdef __KERNEL__ + +#define STACK_TOP TASK_SIZE + +#endif + +#endif /* __ASM_AVR32_A_OUT_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/arch-avr32b/sysreg.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/arch-avr32b/sysreg.h --- linux-2.6.16.11/include/asm-avr32/arch-avr32b/sysreg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/arch-avr32b/sysreg.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,336 @@ +/* + * AVR32 System Registers + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_SYSREG_H__ +#define __ASM_AVR32_SYSREG_H__ + +/* sysreg register offsets */ +#define SYSREG_SR 0x0000 +#define SYSREG_EVBA 0x0004 +#define SYSREG_ACBA 0x0008 +#define SYSREG_CPUCR 0x000c +#define SYSREG_ECR 0x0010 +#define SYSREG_RSR_SUP 0x0014 +#define SYSREG_RSR_INT0 0x0018 +#define SYSREG_RSR_INT1 0x001c +#define SYSREG_RSR_INT2 0x0020 +#define SYSREG_RSR_INT3 0x0024 +#define SYSREG_RSR_EX 0x0028 +#define SYSREG_RSR_NMI 0x002c +#define SYSREG_RSR_DBG 0x0030 +#define SYSREG_RAR_SUP 0x0034 +#define SYSREG_RAR_INT0 0x0038 +#define SYSREG_RAR_INT1 0x003c +#define SYSREG_RAR_INT2 0x0040 +#define SYSREG_RAR_INT3 0x0044 +#define SYSREG_RAR_EX 0x0048 +#define SYSREG_RAR_NMI 0x004c +#define SYSREG_RAR_DBG 0x0050 +#define SYSREG_JECR 0x0054 +#define SYSREG_JOSP 0x0058 +#define SYSREG_JAVA_LV0 0x005c +#define SYSREG_JAVA_LV1 0x0060 +#define SYSREG_JAVA_LV2 0x0064 +#define SYSREG_JAVA_LV3 0x0068 +#define SYSREG_JAVA_LV4 0x006c +#define SYSREG_JAVA_LV5 0x0070 +#define SYSREG_JAVA_LV6 0x0074 +#define SYSREG_JAVA_LV7 0x0078 +#define SYSREG_JTBA 0x007c +#define SYSREG_JBCR 0x0080 +#define SYSREG_CONFIG0 0x0100 +#define SYSREG_CONFIG1 0x0104 +#define SYSREG_COUNT 0x0108 +#define SYSREG_COMPARE 0x010c +#define SYSREG_TLBEHI 0x0110 +#define SYSREG_TLBELO 0x0114 +#define SYSREG_PTBR 0x0118 +#define SYSREG_TLBEAR 0x011c +#define SYSREG_MMUCR 0x0120 +#define SYSREG_TLBARLO 0x0124 +#define SYSREG_TLBARHI 0x0128 +#define SYSREG_PCCNT 0x012c +#define SYSREG_PCNT0 0x0130 +#define SYSREG_PCNT1 0x0134 +#define SYSREG_PCCR 0x0138 +#define SYSREG_BEAR 0x013c +#define SYSREG_SABAL 0x0300 +#define SYSREG_SABAH 0x0304 +#define SYSREG_SABD 0x0308 + +/* Bitfields in SR */ +#define SYSREG_SR_C_OFFSET 0 +#define SYSREG_SR_C_SIZE 1 +#define SYSREG_Z_OFFSET 1 +#define SYSREG_Z_SIZE 1 +#define SYSREG_SR_N_OFFSET 2 +#define SYSREG_SR_N_SIZE 1 +#define SYSREG_SR_V_OFFSET 3 +#define SYSREG_SR_V_SIZE 1 +#define SYSREG_Q_OFFSET 4 +#define SYSREG_Q_SIZE 1 +#define SYSREG_GM_OFFSET 16 +#define SYSREG_GM_SIZE 1 +#define SYSREG_I0M_OFFSET 17 +#define SYSREG_I0M_SIZE 1 +#define SYSREG_I1M_OFFSET 18 +#define SYSREG_I1M_SIZE 1 +#define SYSREG_I2M_OFFSET 19 +#define SYSREG_I2M_SIZE 1 +#define SYSREG_I3M_OFFSET 20 +#define SYSREG_I3M_SIZE 1 +#define SYSREG_EM_OFFSET 21 +#define SYSREG_EM_SIZE 1 +#define SYSREG_M0_OFFSET 22 +#define SYSREG_M0_SIZE 1 +#define SYSREG_M1_OFFSET 23 +#define SYSREG_M1_SIZE 1 +#define SYSREG_M2_OFFSET 24 +#define SYSREG_M2_SIZE 1 +#define SYSREG_SR_D_OFFSET 26 +#define SYSREG_SR_D_SIZE 1 +#define SYSREG_DM_OFFSET 27 +#define SYSREG_DM_SIZE 1 +#define SYSREG_SR_J_OFFSET 28 +#define SYSREG_SR_J_SIZE 1 +#define SYSREG_R_OFFSET 29 +#define SYSREG_R_SIZE 1 +#define SYSREG_H_OFFSET 30 +#define SYSREG_H_SIZE 1 + +/* Bitfields in EVBA */ + +/* Bitfields in ACBA */ + +/* Bitfields in CPUCR */ +#define SYSREG_BI_OFFSET 0 +#define SYSREG_BI_SIZE 1 +#define SYSREG_BE_OFFSET 1 +#define SYSREG_BE_SIZE 1 +#define SYSREG_FE_OFFSET 2 +#define SYSREG_FE_SIZE 1 +#define SYSREG_RE_OFFSET 3 +#define SYSREG_RE_SIZE 1 +#define SYSREG_IBE_OFFSET 4 +#define SYSREG_IBE_SIZE 1 +#define SYSREG_IEE_OFFSET 5 +#define SYSREG_IEE_SIZE 1 + +/* Bitfields in ECR */ +#define SYSREG_ECR_OFFSET 0 +#define SYSREG_ECR_SIZE 32 + +/* Bitfields in RSR_SUP */ + +/* Bitfields in RSR_INT0 */ + +/* Bitfields in RSR_INT1 */ + +/* Bitfields in RSR_INT2 */ + +/* Bitfields in RSR_INT3 */ + +/* Bitfields in RSR_EX */ + +/* Bitfields in RSR_NMI */ + +/* Bitfields in RSR_DBG */ + +/* Bitfields in RAR_SUP */ + +/* Bitfields in RAR_INT0 */ + +/* Bitfields in RAR_INT1 */ + +/* Bitfields in RAR_INT2 */ + +/* Bitfields in RAR_INT3 */ + +/* Bitfields in RAR_EX */ + +/* Bitfields in RAR_NMI */ + +/* Bitfields in RAR_DBG */ + +/* Bitfields in JECR */ + +/* Bitfields in JOSP */ + +/* Bitfields in JAVA_LV0 */ + +/* Bitfields in JAVA_LV1 */ + +/* Bitfields in JAVA_LV2 */ + +/* Bitfields in JAVA_LV3 */ + +/* Bitfields in JAVA_LV4 */ + +/* Bitfields in JAVA_LV5 */ + +/* Bitfields in JAVA_LV6 */ + +/* Bitfields in JAVA_LV7 */ + +/* Bitfields in JTBA */ + +/* Bitfields in JBCR */ + +/* Bitfields in CONFIG0 */ +#define SYSREG_CONFIG0_D_OFFSET 1 +#define SYSREG_CONFIG0_D_SIZE 1 +#define SYSREG_CONFIG0_S_OFFSET 2 +#define SYSREG_CONFIG0_S_SIZE 1 +#define SYSREG_O_OFFSET 3 +#define SYSREG_O_SIZE 1 +#define SYSREG_P_OFFSET 4 +#define SYSREG_P_SIZE 1 +#define SYSREG_CONFIG0_J_OFFSET 5 +#define SYSREG_CONFIG0_J_SIZE 1 +#define SYSREG_F_OFFSET 6 +#define SYSREG_F_SIZE 1 +#define SYSREG_MMUT_OFFSET 7 +#define SYSREG_MMUT_SIZE 3 +#define SYSREG_AR_OFFSET 10 +#define SYSREG_AR_SIZE 3 +#define SYSREG_AT_OFFSET 13 +#define SYSREG_AT_SIZE 3 +#define SYSREG_PROCESSORREVISION_OFFSET 16 +#define SYSREG_PROCESSORREVISION_SIZE 8 +#define SYSREG_PROCESSORID_OFFSET 24 +#define SYSREG_PROCESSORID_SIZE 8 + +/* Bitfields in CONFIG1 */ +#define SYSREG_DASS_OFFSET 0 +#define SYSREG_DASS_SIZE 3 +#define SYSREG_DLSZ_OFFSET 3 +#define SYSREG_DLSZ_SIZE 3 +#define SYSREG_DSET_OFFSET 6 +#define SYSREG_DSET_SIZE 4 +#define SYSREG_IASS_OFFSET 10 +#define SYSREG_IASS_SIZE 2 +#define SYSREG_ILSZ_OFFSET 13 +#define SYSREG_ILSZ_SIZE 3 +#define SYSREG_ISET_OFFSET 16 +#define SYSREG_ISET_SIZE 4 +#define SYSREG_DMMUSZ_OFFSET 20 +#define SYSREG_DMMUSZ_SIZE 6 +#define SYSREG_IMMUSZ_OFFSET 26 +#define SYSREG_IMMUSZ_SIZE 6 + +/* Bitfields in COUNT */ + +/* Bitfields in COMPARE */ + +/* Bitfields in TLBEHI */ +#define SYSREG_ASID_OFFSET 0 +#define SYSREG_ASID_SIZE 8 +#define SYSREG_TLBEHI_I_OFFSET 8 +#define SYSREG_TLBEHI_I_SIZE 1 +#define SYSREG_TLBEHI_V_OFFSET 9 +#define SYSREG_TLBEHI_V_SIZE 1 +#define SYSREG_VPN_OFFSET 10 +#define SYSREG_VPN_SIZE 22 + +/* Bitfields in TLBELO */ +#define SYSREG_W_OFFSET 0 +#define SYSREG_W_SIZE 1 +#define SYSREG_TLBELO_D_OFFSET 1 +#define SYSREG_TLBELO_D_SIZE 1 +#define SYSREG_SZ_OFFSET 2 +#define SYSREG_SZ_SIZE 2 +#define SYSREG_AP_OFFSET 4 +#define SYSREG_AP_SIZE 3 +#define SYSREG_B_OFFSET 7 +#define SYSREG_B_SIZE 1 +#define SYSREG_G_OFFSET 8 +#define SYSREG_G_SIZE 1 +#define SYSREG_TLBELO_C_OFFSET 9 +#define SYSREG_TLBELO_C_SIZE 1 +#define SYSREG_PFN_OFFSET 10 +#define SYSREG_PFN_SIZE 22 + +/* Bitfields in PTBR */ + +/* Bitfields in TLBEAR */ + +/* Bitfields in MMUCR */ +#define SYSREG_E_OFFSET 0 +#define SYSREG_E_SIZE 1 +#define SYSREG_M_OFFSET 1 +#define SYSREG_M_SIZE 1 +#define SYSREG_MMUCR_I_OFFSET 2 +#define SYSREG_MMUCR_I_SIZE 1 +#define SYSREG_MMUCR_N_OFFSET 3 +#define SYSREG_MMUCR_N_SIZE 1 +#define SYSREG_MMUCR_S_OFFSET 4 +#define SYSREG_MMUCR_S_SIZE 1 +#define SYSREG_DLA_OFFSET 8 +#define SYSREG_DLA_SIZE 6 +#define SYSREG_DRP_OFFSET 14 +#define SYSREG_DRP_SIZE 6 +#define SYSREG_ILA_OFFSET 20 +#define SYSREG_ILA_SIZE 6 +#define SYSREG_IRP_OFFSET 26 +#define SYSREG_IRP_SIZE 6 + +/* Bitfields in TLBARLO */ + +/* Bitfields in TLBARHI */ + +/* Bitfields in PCCNT */ + +/* Bitfields in PCNT0 */ + +/* Bitfields in PCNT1 */ + +/* Bitfields in PCCR */ + +/* Bitfields in BEAR */ + +/* Bitfields in SABAL */ + +/* Bitfields in SABAH */ + +/* Bitfields in SABD */ + +/* Constants for ECR */ +#define ECR_UNRECOVERABLE 0 +#define ECR_TLB_MULTIPLE 1 +#define ECR_BUS_ERROR_WRITE 2 +#define ECR_BUS_ERROR_READ 3 +#define ECR_NMI 4 +#define ECR_ADDR_ALIGN_X 5 +#define ECR_PROTECTION_X 6 +#define ECR_DEBUG 7 +#define ECR_ILLEGAL_OPCODE 8 +#define ECR_UNIMPL_INSTRUCTION 9 +#define ECR_PRIVILEGE_VIOLATION 10 +#define ECR_FPE 11 +#define ECR_COPROC_ABSENT 12 +#define ECR_ADDR_ALIGN_R 13 +#define ECR_ADDR_ALIGN_W 14 +#define ECR_PROTECTION_R 15 +#define ECR_PROTECTION_W 16 +#define ECR_DTLB_MODIFIED 17 +#define ECR_TLB_MISS_X 20 +#define ECR_TLB_MISS_R 24 +#define ECR_TLB_MISS_W 28 + +/* Bit manipulation macros */ +#define SYSREG_BIT(name) (1 << SYSREG_##name##_OFFSET) +#define SYSREG_BF(name,value) (((value) & ((1 << SYSREG_##name##_SIZE) - 1)) << SYSREG_##name##_OFFSET) +#define SYSREG_BFEXT(name,value) (((value) >> SYSREG_##name##_OFFSET) & ((1 << SYSREG_##name##_SIZE) - 1)) +#define SYSREG_BFINS(name,value,old) (((old) & ~(((1 << SYSREG_##name##_SIZE) - 1) << SYSREG_##name##_OFFSET)) | SYSREG_BF(name,value)) + +/* Register access macros */ +#define sysreg_read(reg) __builtin_mfsr(SYSREG_##reg) +#define sysreg_write(reg, value) __builtin_mtsr(SYSREG_##reg, value) + +#endif /* __ASM_AVR32_SYSREG_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/asm.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/asm.h --- linux-2.6.16.11/include/asm-avr32/asm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/asm.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_ASM_H__ +#define __ASM_AVR32_ASM_H__ + +#include +#include +#include + +#define mask_interrupts ssrf SR_GM_BIT +#define mask_exceptions ssrf SR_EM_BIT +#define unmask_interrupts csrf SR_GM_BIT +#define unmask_exceptions csrf SR_EM_BIT + +#ifdef CONFIG_FRAME_POINTER + .macro save_fp + st.w --sp, r7 + .endm + .macro restore_fp + ld.w r7, sp++ + .endm + .macro zero_fp + mov r7, 0 + .endm +#else + .macro save_fp + .endm + .macro restore_fp + .endm + .macro zero_fp + .endm +#endif + .macro get_thread_info reg + mov \reg, sp + andl \reg, ~(THREAD_SIZE - 1) & 0xffff + .endm + + /* Save and restore registers */ + .macro save_min sr, tmp=lr + pushm lr + mfsr \tmp, \sr + zero_fp + st.w --sp, \tmp + .endm + + .macro restore_min sr, tmp=lr + ld.w \tmp, sp++ + mtsr \sr, \tmp + popm lr + .endm + + .macro save_half sr, tmp=lr + save_fp + pushm r8-r9,r10,r11,r12,lr + zero_fp + mfsr \tmp, \sr + st.w --sp, \tmp + .endm + + .macro restore_half sr, tmp=lr + ld.w \tmp, sp++ + mtsr \sr, \tmp + popm r8-r9,r10,r11,r12,lr + restore_fp + .endm + + .macro save_full_user sr, tmp=lr + stmts --sp, r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,sp,lr + st.w --sp, lr + zero_fp + mfsr \tmp, \sr + st.w --sp, \tmp + .endm + + .macro restore_full_user sr, tmp=lr + ld.w \tmp, sp++ + mtsr \sr, \tmp + ld.w lr, sp++ + ldmts sp++, r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,sp,lr + .endm + + /* uaccess macros */ + .macro branch_if_kernel scratch, label + get_thread_info \scratch + ld.w \scratch, \scratch[TI_flags] + bld \scratch, TIF_USERSPACE + brcc \label + .endm + + .macro ret_if_privileged scratch, addr, size, ret + sub \scratch, \size, 1 + add \scratch, \addr + retcs \ret + retmi \ret + .endm + +#endif /* __ASM_AVR32_ASM_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/atomic.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/atomic.h --- linux-2.6.16.11/include/asm-avr32/atomic.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/atomic.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,203 @@ +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc. + * + * But use these as seldom as possible since they are slower than + * regular operations. + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_ATOMIC_H +#define __ASM_AVR32_ATOMIC_H + +#include + +typedef struct { volatile int counter; } atomic_t; +#define ATOMIC_INIT(i) { (i) } + +#ifdef __KERNEL__ + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v, i) (((v)->counter) = i) + +/* + * atomic_sub_return - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. Returns the resulting value. + */ +static inline int atomic_sub_return(int i, atomic_t *v) +{ + int result; + + asm volatile( + "/* atomic_sub_return */\n" + "1: ssrf 5\n" + " ld.w %0, %2\n" + " sub %0, %3\n" + " stcond %1, %0\n" + " brne 1b" + : "=&r"(result), "=m"(v->counter) + : "m"(v->counter), "ir"(i) + : "cc"); + + return result; +} + +/* + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. Returns the resulting value. + */ +static inline int atomic_add_return(int i, atomic_t *v) +{ + int result; + + if (__builtin_constant_p(i)) + result = atomic_sub_return(-i, v); + else + asm volatile( + "/* atomic_add_return */\n" + "1: ssrf 5\n" + " ld.w %0, %1\n" + " add %0, %3\n" + " stcond %2, %0\n" + " brne 1b" + : "=&r"(result), "=m"(v->counter) + : "m"(v->counter), "r"(i) + : "cc", "memory"); + + return result; +} + +/* + * atomic_sub_unless - sub unless the number is a given value + * @v: pointer of type atomic_t + * @a: the amount to add to v... + * @u: ...unless v is equal to u. + * + * If the atomic value v is not equal to u, this function subtracts a + * from v, and returns non zero. If v is equal to u then it returns + * zero. This is done as an atomic operation. +*/ +static inline int atomic_sub_unless(atomic_t *v, int a, int u) +{ + int tmp, result = 0; + + asm volatile( + "/* atomic_sub_unless */\n" + "1: ssrf 5\n" + " ld.w %0, %3\n" + " cp.w %0, %5\n" + " breq 1f\n" + " sub %0, %4\n" + " stcond %2, %0\n" + " brne 1b\n" + " mov %1, 1\n" + "1:" + : "=&r"(tmp), "=&r"(result), "=m"(v->counter) + : "m"(v->counter), "ir"(a), "ir"(u) + : "cc", "memory"); + + return result; +} + +/* + * atomic_add_unless - add unless the number is a given value + * @v: pointer of type atomic_t + * @a: the amount to add to v... + * @u: ...unless v is equal to u. + * + * If the atomic value v is not equal to u, this function adds a to v, + * and returns non zero. If v is equal to u then it returns zero. This + * is done as an atomic operation. +*/ +static inline int atomic_add_unless(atomic_t *v, int a, int u) +{ + int tmp, result; + + if (__builtin_constant_p(a)) + result = atomic_sub_unless(v, -a, u); + else { + result = 0; + asm volatile( + "/* atomic_add_unless */\n" + "1: ssrf 5\n" + " ld.w %0, %3\n" + " cp.w %0, %5\n" + " breq 1f\n" + " add %0, %4\n" + " stcond %2, %0\n" + " brne 1b\n" + " mov %1, 1\n" + "1:" + : "=&r"(tmp), "=&r"(result), "=m"(v->counter) + : "m"(v->counter), "r"(a), "ir"(u) + : "cc", "memory"); + } + + return result; +} + +/* + * atomic_sub_if_positive - conditionally subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically test @v and subtract @i if @v is greater or equal than @i. + * The function returns the old value of @v minus @i. + */ +static inline int atomic_sub_if_positive(int i, atomic_t *v) +{ + int result; + + asm volatile( + "/* atomic_sub_if_positive */\n" + "1: ssrf 5\n" + " ld.w %0, %2\n" + " sub %0, %3\n" + " brlt 1f\n" + " stcond %1, %0\n" + " brne 1b\n" + "1:" + : "=&r"(result), "=m"(v->counter) + : "m"(v->counter), "ir"(i) + : "cc", "memory"); + + return result; +} + +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) +#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) + +#define atomic_sub(i, v) (void)atomic_sub_return(i, v) +#define atomic_add(i, v) (void)atomic_add_return(i, v) +#define atomic_dec(v) atomic_sub(1, (v)) +#define atomic_inc(v) atomic_add(1, (v)) + +#define atomic_dec_return(v) atomic_sub_return(1, v) +#define atomic_inc_return(v) atomic_add_return(1, v) + +#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) +#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) +#define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0) + +#define atomic_inc_not_zero(v) atomic_add_unless(v, 1, 0) +#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) + +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + +#endif /* __KERNEL__ */ + +#endif /* __ASM_AVR32_ATOMIC_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/auxvec.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/auxvec.h --- linux-2.6.16.11/include/asm-avr32/auxvec.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/auxvec.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,4 @@ +#ifndef __ASM_AVR32_AUXVEC_H +#define __ASM_AVR32_AUXVEC_H + +#endif /* __ASM_AVR32_AUXVEC_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/bitops.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/bitops.h --- linux-2.6.16.11/include/asm-avr32/bitops.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/bitops.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_BITOPS_H +#define __ASM_AVR32_BITOPS_H + +#ifdef __KERNEL__ +#include +#include + +static inline void set_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + *a |= mask; + local_irq_restore(flags); +} + +static inline void __set_bit(int nr, volatile void *addr) +{ + int mask; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a |= mask; +} + +/* + * clear_bit() doesn't provide any barrier for the compiler (?) + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +static inline void clear_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + *a &= ~mask; + local_irq_restore(flags); +} + +static inline void __clear_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a &= ~mask; +} + +static inline void change_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + *a ^= mask; + local_irq_restore(flags); +} + +static inline void __change_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a ^= mask; +} + +static inline int test_and_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + retval = (mask & *a) != 0; + *a |= mask; + local_irq_restore(flags); + + return retval; +} + +static inline int __test_and_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a |= mask; + + return retval; +} + +static inline int test_and_clear_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + retval = (mask & *a) != 0; + *a &= ~mask; + local_irq_restore(flags); + + return retval; +} + +static inline int __test_and_clear_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a &= ~mask; + + return retval; +} + +static inline int test_and_change_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + retval = (mask & *a) != 0; + *a ^= mask; + local_irq_restore(flags); + + return retval; +} + +static inline int __test_and_change_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a ^= mask; + + return retval; +} + +static inline int test_bit(int nr, const volatile void * addr) +{ + return 1UL & (((const volatile unsigned int *)addr)[nr >> 5] >> (nr & 31)); +} + +/* Find First bit Set */ +static inline unsigned long __ffs(unsigned long word) +{ + unsigned long result; + + asm("brev %1\n\t" + "clz %0,%1" + : "=r"(result), "=r"(word) + : "1"(word)); + return result; +} + +/* Find First Zero */ +static inline unsigned long ffz(unsigned long word) +{ + return __ffs(~word); +} + +/* Find Last bit Set */ +static inline int fls(unsigned long word) +{ + unsigned long result; + + asm("clz %0,%1" : "=r"(result) : "r"(word)); + return 32 - result; +} + +/** + * find_next_bit - find the next set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +static inline int find_next_bit(const unsigned long *addr, + unsigned long size, + unsigned long offset) +{ + unsigned int *p = ((unsigned int *) addr) + (offset >> 5); + unsigned int result = offset & ~31UL; + unsigned int tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if (offset) { + tmp = *p++; + tmp &= ~0UL << offset; + if (size < 32) + goto found_first; + if (tmp) + goto found_middle; + size -= 32; + result += 32; + } + while (size >= 32) { + if ((tmp = *p++) != 0) + goto found_middle; + result += 32; + size -= 32; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp &= ~0UL >> (32 - size); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found_middle: + return result + __ffs(tmp); +} + +/** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first set bit, not the number of the byte + * containing a bit. + */ +#define find_first_bit(addr, size) \ + find_next_bit((addr), (size), 0) + +/* TODO: Review and optimize. This is entirely stolen from SH */ +static inline int find_next_zero_bit(const unsigned long *addr, + int size, int offset) +{ + const unsigned long *p = addr + (offset >> 5); + unsigned long result = offset & ~31UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if (offset) { + tmp = *(p++); + tmp |= ~0UL >> (32 - offset); + if (size < 32) + goto found_first; + if (~tmp) + goto found_middle; + size -= 32; + result += 32; + } + while (size & ~31UL) { + if (~(tmp = *(p++))) + goto found_middle; + result += 32; + size -= 32; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp |= ~0UL << size; +found_middle: + return result + ffz(tmp); +} + +#define find_first_zero_bit(addr, size) \ + find_next_zero_bit((addr), (size), 0) + +/* + * ffs: find first bit set. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + * + * The difference is that bit numbering starts at 1, and if no bit is set, + * the function returns 0. + */ +static inline int ffs(unsigned long word) +{ + if(word == 0) + return 0; + return __ffs(word) + 1; +} + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) + +/* + * Every architecture must define this function. It's the fastest + * way of searching a 140-bit bitmap where the first 100 bits are + * unlikely to be set. It's guaranteed that at least one of the 140 + * bits is cleared. + */ +static inline int sched_find_first_bit(unsigned long *b) +{ + if (unlikely(b[0])) + return __ffs(b[0]); + if (unlikely(b[1])) + return __ffs(b[1]) + 32; + if (unlikely(b[2])) + return __ffs(b[2]) + 64; + if (b[3]) + return __ffs(b[3]) + 96; + return __ffs(b[4]) + 128; +} + +/* + * Ext2 is defined to use little-endian byte ordering. + * These do not need to be atomic. + */ +static inline int ext2_set_bit(unsigned int nr, void *p) +{ + int ret, tmp; + u32 *word = (u32 *)p + (nr >> 5); + + tmp = le32_to_cpu(*word); + ret = (tmp >> nr) & 1; + tmp |= (1 << nr); + *word = cpu_to_le32(tmp); + + return ret; +} + +#define ext2_set_bit_atomic(lock, nr, p) \ + ({ \ + int flags, ret; \ + spin_lock_irqsave(lock, flags); \ + ret = ext2_set_bit(nr, p); \ + spin_unlock_irqrestore(lock, flags); \ + ret; \ + }) + +static inline int ext2_clear_bit(unsigned int nr, void *p) +{ + int ret, tmp; + u32 *word = (u32 *)p + (nr >> 5); + + tmp = le32_to_cpu(*word); + ret = (tmp >> nr) & 1; + tmp &= ~(1 << nr); + *word = cpu_to_le32(tmp); + + return ret; +} + +#define ext2_clear_bit_atomic(lock, nr, p) \ + ({ \ + int flags, ret; \ + spin_lock_irqsave(lock, flags); \ + ret = ext2_clear_bit(nr, p); \ + spin_unlock_irqrestore(lock, flags); \ + ret; \ + }) + +static inline int ext2_test_bit(unsigned int nr, void *p) +{ + int ret; + u32 *word = (u32 *)p + (nr >> 5); + + ret = le32_to_cpu(*word); + return ret & (1 << (nr & 0x1f)); +} + +extern int ext2_find_first_zero_bit(void *addr, unsigned size); +extern int ext2_find_next_zero_bit(void *addr, unsigned size, unsigned offset); + +/* + * Minix is defined to use little-endian byte ordering. + * These do not need to be atomic. + */ +static inline void minix_set_bit(unsigned int nr, void *p) +{ + u32 *word = (u32 *)p + (nr >> 5); + u32 tmp; + + tmp = le32_to_cpu(*word); + tmp |= (1 << nr); + *word = cpu_to_le32(tmp); +} + +#define minix_test_bit(nr, p) ext2_test_bit(nr, p) +#define minix_test_and_set_bit(nr, p) ext2_set_bit(nr, p) +#define minix_test_and_clear_bit(nr, p) ext2_clear_bit(nr, p) +#define minix_find_first_zero_bit(addr, size) \ + ext2_find_first_zero_bit(addr, size) + +#endif /* __KERNEL__ */ + + +#endif /* __ASM_AVR32_BITOPS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/bug.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/bug.h --- linux-2.6.16.11/include/asm-avr32/bug.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/bug.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_BUG_H +#define __ASM_AVR32_BUG_H + +#include + +#ifdef CONFIG_BUG + +/* + * According to our Chief Architect, this compact opcode is very + * unlikely to ever be implemented. + */ +#define AVR32_BUG_OPCODE 0x5df0 + +#ifdef CONFIG_DEBUG_BUGVERBOSE + +#define BUG() \ + do { \ + asm volatile(".hword %0\n\t" \ + ".hword %1\n\t" \ + ".long %2" \ + : \ + : "n"(AVR32_BUG_OPCODE), \ + "i"(__LINE__), "X"(__FILE__)); \ + } while (0) + +#else + +#define BUG() \ + do { \ + asm volatile(".hword %0\n\t" \ + : : "n"(AVR32_BUG_OPCODE)); \ + } while (0) + +#endif /* CONFIG_DEBUG_BUGVERBOSE */ + +#define HAVE_ARCH_BUG + +#endif /* CONFIG_BUG */ + +#include + +#endif /* __ASM_AVR32_BUG_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/bugs.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/bugs.h --- linux-2.6.16.11/include/asm-avr32/bugs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/bugs.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,15 @@ +/* + * This is included by init/main.c to check for architecture-dependent bugs. + * + * Needs: + * void check_bugs(void); + */ +#ifndef __ASM_AVR32_BUGS_H +#define __ASM_AVR32_BUGS_H + +static void __init check_bugs(void) +{ + cpu_data->loops_per_jiffy = loops_per_jiffy; +} + +#endif /* __ASM_AVR32_BUGS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/byteorder.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/byteorder.h --- linux-2.6.16.11/include/asm-avr32/byteorder.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/byteorder.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,25 @@ +/* + * AVR32 endian-conversion functions. + */ +#ifndef __ASM_AVR32_BYTEORDER_H +#define __ASM_AVR32_BYTEORDER_H + +#include +#include + +#ifdef __CHECKER__ +extern unsigned long __builtin_bswap_32(unsigned long x); +extern unsigned short __builtin_bswap_16(unsigned short x); +#endif + +#define __arch__swab32(x) __builtin_bswap_32(x) +#define __arch__swab16(x) __builtin_bswap_16(x) + +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#include + +#endif /* __ASM_AVR32_BYTEORDER_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/cachectl.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/cachectl.h --- linux-2.6.16.11/include/asm-avr32/cachectl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/cachectl.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,11 @@ +#ifndef __ASM_AVR32_CACHECTL_H +#define __ASM_AVR32_CACHECTL_H + +/* + * Operations that can be performed through the cacheflush system call + */ + +/* Clean the data cache, then invalidate the icache */ +#define CACHE_IFLUSH 0 + +#endif /* __ASM_AVR32_CACHECTL_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/cacheflush.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/cacheflush.h --- linux-2.6.16.11/include/asm-avr32/cacheflush.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/cacheflush.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_CACHEFLUSH_H +#define __ASM_AVR32_CACHEFLUSH_H + +/* Keep includes the same across arches. */ +#include + +#define CACHE_OP_ICACHE_INVALIDATE 0x01 +#define CACHE_OP_DCACHE_INVALIDATE 0x0b +#define CACHE_OP_DCACHE_CLEAN 0x0c +#define CACHE_OP_DCACHE_CLEAN_INVAL 0x0d + +/* + * Invalidate any cacheline containing virtual address vaddr without + * writing anything back to memory. + * + * Note that this function may corrupt unrelated data structures when + * applied on buffers that are not cacheline aligned in both ends. + */ +static inline void invalidate_dcache_line(void *vaddr) +{ + asm volatile("cache %0[0], %1" + : + : "r"(vaddr), "n"(CACHE_OP_DCACHE_INVALIDATE) + : "memory"); +} + +/* + * Make sure any cacheline containing virtual address vaddr is written + * to memory. + */ +static inline void clean_dcache_line(void *vaddr) +{ + asm volatile("cache %0[0], %1" + : + : "r"(vaddr), "n"(CACHE_OP_DCACHE_CLEAN) + : "memory"); +} + +/* + * Make sure any cacheline containing virtual address vaddr is written + * to memory and then invalidate it. + */ +static inline void flush_dcache_line(void *vaddr) +{ + asm volatile("cache %0[0], %1" + : + : "r"(vaddr), "n"(CACHE_OP_DCACHE_CLEAN_INVAL) + : "memory"); +} + +/* + * Invalidate any instruction cacheline containing virtual address + * vaddr. + */ +static inline void invalidate_icache_line(void *vaddr) +{ + asm volatile("cache %0[0], %1" + : + : "r"(vaddr), "n"(CACHE_OP_ICACHE_INVALIDATE) + : "memory"); +} + +/* + * Applies the above functions on all lines that are touched by the + * specified virtual address range. + */ +void invalidate_dcache_region(void *start, size_t len); +void clean_dcache_region(void *start, size_t len); +void flush_dcache_region(void *start, size_t len); +void invalidate_icache_region(void *start, size_t len); + +/* + * Make sure any pending writes are completed before continuing. + */ +#define flush_write_buffer() asm volatile("sync 0" : : : "memory") + +/* + * The following functions are called when a virtual mapping changes. + * We do not need to flush anything in this case. + */ +#define flush_cache_all() do { } while (0) +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_range(vma, start, end) do { } while (0) +#define flush_cache_page(vma, vmaddr, pfn) do { } while (0) +#define flush_cache_vmap(start, end) do { } while (0) +#define flush_cache_vunmap(start, end) do { } while (0) + +/* + * I think we need to implement this one to be able to reliably + * execute pages from RAMDISK. However, if we implement the + * flush_dcache_*() functions, it might not be needed anymore. + * + * #define flush_icache_page(vma, page) do { } while (0) + */ +extern void flush_icache_page(struct vm_area_struct *vma, struct page *page); + +/* + * These are (I think) related to D-cache aliasing. We might need to + * do something here, but only for certain configurations. No such + * configurations exist at this time. + */ +#define flush_dcache_page(page) do { } while (0) +#define flush_dcache_mmap_lock(page) do { } while (0) +#define flush_dcache_mmap_unlock(page) do { } while (0) + +/* + * These are for I/D cache coherency. In this case, we do need to + * flush with all configurations. + */ +extern void flush_icache_range(unsigned long start, unsigned long end); +extern void flush_icache_user_range(struct vm_area_struct *vma, + struct page *page, + unsigned long addr, int len); + +#define copy_to_user_page(vma, page, vaddr, dst, src, len) do { \ + memcpy(dst, src, len); \ + flush_icache_user_range(vma, page, vaddr, len); \ +} while(0) +#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ + memcpy(dst, src, len) + +#endif /* __ASM_AVR32_CACHEFLUSH_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/cache.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/cache.h --- linux-2.6.16.11/include/asm-avr32/cache.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/cache.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,29 @@ +#ifndef __ASM_AVR32_CACHE_H +#define __ASM_AVR32_CACHE_H + +#define L1_CACHE_SHIFT 5 +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#ifndef __ASSEMBLER__ +struct cache_info { + unsigned int ways; + unsigned int sets; + unsigned int linesz; +}; +#endif /* __ASSEMBLER */ + +/* Cache operation constants */ +#define ICACHE_FLUSH 0x00 +#define ICACHE_INVALIDATE 0x01 +#define ICACHE_LOCK 0x02 +#define ICACHE_UNLOCK 0x03 +#define ICACHE_PREFETCH 0x04 + +#define DCACHE_FLUSH 0x08 +#define DCACHE_LOCK 0x09 +#define DCACHE_UNLOCK 0x0a +#define DCACHE_INVALIDATE 0x0b +#define DCACHE_CLEAN 0x0c +#define DCACHE_CLEAN_INVAL 0x0d + +#endif /* __ASM_AVR32_CACHE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/checksum.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/checksum.h --- linux-2.6.16.11/include/asm-avr32/checksum.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/checksum.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_CHECKSUM_H +#define __ASM_AVR32_CHECKSUM_H + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char * buff, int len, + unsigned int sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums, and handles user-space pointer exceptions correctly, when needed. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ +unsigned int csum_partial_copy_generic(const char *src, char *dst, int len, + int sum, int *src_err_ptr, + int *dst_err_ptr); + +/* + * Note: when you get a NULL pointer exception here this means someone + * passed in an incorrect kernel address to one of these functions. + * + * If you use these functions directly please don't forget the + * verify_area(). + */ +static inline +unsigned int csum_partial_copy_nocheck(const char *src, char *dst, + int len, int sum) +{ + return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL); +} + +static inline +unsigned int csum_partial_copy_from_user (const char __user *src, char *dst, + int len, int sum, int *err_ptr) +{ + return csum_partial_copy_generic((const char __force *)src, dst, len, + sum, err_ptr, NULL); +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +static inline unsigned short ip_fast_csum(unsigned char *iph, + unsigned int ihl) +{ + unsigned int sum, tmp; + + __asm__ __volatile__( + " ld.w %0, %1++\n" + " ld.w %3, %1++\n" + " sub %2, 4\n" + " add %0, %3\n" + " ld.w %3, %1++\n" + " adc %0, %0, %3\n" + " ld.w %3, %1++\n" + " adc %0, %0, %3\n" + " acr %0\n" + "1: ld.w %3, %1++\n" + " add %0, %3\n" + " acr %0\n" + " sub %2, 1\n" + " brne 1b\n" + " lsl %3, %0, 16\n" + " andl %0, 0\n" + " mov %2, 0xffff\n" + " add %0, %3\n" + " adc %0, %0, %2\n" + " com %0\n" + " lsr %0, 16\n" + : "=r"(sum), "=r"(iph), "=r"(ihl), "=r"(tmp) + : "1"(iph), "2"(ihl) + : "memory", "cc"); + return sum; +} + +/* + * Fold a partial checksum + */ + +static inline unsigned int csum_fold(unsigned int sum) +{ + unsigned int tmp; + + asm(" bfextu %1, %0, 0, 16\n" + " lsr %0, 16\n" + " add %0, %1\n" + " bfextu %1, %0, 16, 16\n" + " add %0, %1" + : "=&r"(sum), "=&r"(tmp) + : "0"(sum)); + + return ~sum; +} + +static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + asm(" add %0, %1\n" + " adc %0, %0, %2\n" + " adc %0, %0, %3\n" + " acr %0" + : "=r"(sum) + : "r"(daddr), "r"(saddr), "r"(ntohs(len) | (proto << 16)), + "0"(sum) + : "cc"); + + return sum; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ + +static inline unsigned short ip_compute_csum(unsigned char * buff, int len) +{ + return csum_fold(csum_partial(buff, len, 0)); +} + +#endif /* __ASM_AVR32_CHECKSUM_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/cputime.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/cputime.h --- linux-2.6.16.11/include/asm-avr32/cputime.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/cputime.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_CPUTIME_H +#define __ASM_AVR32_CPUTIME_H + +#include + +#endif /* __ASM_AVR32_CPUTIME_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/current.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/current.h --- linux-2.6.16.11/include/asm-avr32/current.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/current.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,15 @@ +#ifndef __ASM_AVR32_CURRENT_H +#define __ASM_AVR32_CURRENT_H + +#include + +struct task_struct; + +inline static struct task_struct * get_current(void) +{ + return current_thread_info()->task; +} + +#define current get_current() + +#endif /* __ASM_AVR32_CURRENT_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/delay.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/delay.h --- linux-2.6.16.11/include/asm-avr32/delay.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/delay.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,26 @@ +#ifndef __ASM_AVR32_DELAY_H +#define __ASM_AVR32_DELAY_H + +/* + * Copyright (C) 1993 Linus Torvalds + * + * Delay routines calling functions in arch/avr32/lib/delay.c + */ + +extern void __bad_udelay(void); +extern void __bad_ndelay(void); + +extern void __udelay(unsigned long usecs); +extern void __ndelay(unsigned long nsecs); +extern void __const_udelay(unsigned long usecs); +extern void __delay(unsigned long loops); + +#define udelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \ + __udelay(n)) + +#define ndelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ + __ndelay(n)) + +#endif /* __ASM_AVR32_DELAY_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/div64.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/div64.h --- linux-2.6.16.11/include/asm-avr32/div64.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/div64.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_DIV64_H +#define __ASM_AVR32_DIV64_H + +#include + +#endif /* __ASM_AVR32_DIV64_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/dma-controller.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/dma-controller.h --- linux-2.6.16.11/include/asm-avr32/dma-controller.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/dma-controller.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_DMA_CONTROLLER_H +#define __ASM_AVR32_DMA_CONTROLLER_H + +#include + +#define DMA_DIR_MEM_TO_MEM 0x0000 +#define DMA_DIR_MEM_TO_PERIPH 0x0001 +#define DMA_DIR_PERIPH_TO_MEM 0x0002 +#define DMA_DIR_PERIPH_TO_PERIPH 0x0003 + +#define DMA_WIDTH_8BIT 0 +#define DMA_WIDTH_16BIT 1 +#define DMA_WIDTH_32BIT 2 + +struct dma_request { + struct dma_controller *dmac; + struct list_head list; + + unsigned short channel; + + void (*xfer_complete)(struct dma_request *req); + void (*block_complete)(struct dma_request *req); + void (*error)(struct dma_request *req); +}; + +struct dma_request_sg { + struct dma_request req; + + int nr_sg; + struct scatterlist *sg; + unsigned long block_size; + + dma_addr_t data_reg; + unsigned short periph_id; + + unsigned char direction; + unsigned char width; +}; +#define to_dma_request_sg(_req) \ + container_of(_req, struct dma_request_sg, req) + +struct dma_request_cyclic { + struct dma_request req; + + int periods; + unsigned long buffer_size; + + dma_addr_t buffer_start; + dma_addr_t data_reg; + + unsigned short periph_id; + unsigned char direction; + unsigned char width; + + void *dev_id; +}; +#define to_dma_request_cyclic(_req) \ + container_of(_req, struct dma_request_cyclic, req) + +struct dma_request_memcpy { + struct dma_request req; + + dma_addr_t src_addr; + unsigned int src_width; + unsigned int src_stride; + + dma_addr_t dst_addr; + unsigned int dst_width; + unsigned int dst_stride; + + size_t length; + + unsigned short src_reverse:1; + unsigned short dst_reverse:1; +}; +#define to_dma_request_memcpy(_req) \ + container_of(_req, struct dma_request_memcpy, req) + +struct dma_controller { + struct list_head list; + int id; + struct device *dev; + + int (*alloc_channel)(struct dma_controller *dmac); + void (*release_channel)(struct dma_controller *dmac, + int channel); + int (*prepare_request_sg)(struct dma_controller *dmac, + struct dma_request_sg *req); + int (*prepare_request_cyclic)(struct dma_controller *dmac, + struct dma_request_cyclic *req); + int (*prepare_request_memcpy)(struct dma_controller *dmac, + struct dma_request_memcpy *req); + int (*start_request)(struct dma_controller *dmac, + unsigned int channel); + int (*stop_request)(struct dma_controller *dmac, + unsigned int channel); + dma_addr_t (*get_current_pos)(struct dma_controller *dmac, + unsigned int channel); +}; + +static inline int +dma_alloc_channel(struct dma_controller *dmac) +{ + return dmac->alloc_channel(dmac); +} + +static inline void +dma_release_channel(struct dma_controller *dmac, int chan) +{ + dmac->release_channel(dmac, chan); +} + +static inline int +dma_prepare_request_sg(struct dma_controller *dmac, + struct dma_request_sg *req) +{ + return dmac->prepare_request_sg(dmac, req); +} + +static inline int +dma_prepare_request_cyclic(struct dma_controller *dmac, + struct dma_request_cyclic *req) +{ + return dmac->prepare_request_cyclic(dmac, req); +} + +static inline int +dma_prepare_request_memcpy(struct dma_controller *dmac, + struct dma_request_memcpy *req) +{ + return dmac->prepare_request_memcpy(dmac, req); +} + +static inline int +dma_start_request(struct dma_controller *dmac, + unsigned int channel) +{ + return dmac->start_request(dmac, channel); +} + +static inline int +dma_stop_request(struct dma_controller *dmac, + unsigned int channel) +{ + return dmac->stop_request(dmac, channel); +} + +static inline dma_addr_t +dma_get_current_pos(struct dma_controller *dmac, + unsigned int channel) +{ + return dmac->get_current_pos(dmac, channel); +} + +extern int register_dma_controller(struct dma_controller *dmac); +extern struct dma_controller *find_dma_controller(int id); + +#endif /* __ASM_AVR32_DMA_CONTROLLER_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/dma.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/dma.h --- linux-2.6.16.11/include/asm-avr32/dma.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/dma.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,8 @@ +#ifndef __ASM_AVR32_DMA_H +#define __ASM_AVR32_DMA_H + +/* The maximum address that we can perform a DMA transfer to on this platform. + * Not really applicable to AVR32, but some functions need it. */ +#define MAX_DMA_ADDRESS 0xffffffff + +#endif /* __ASM_AVR32_DMA_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/dma-mapping.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/dma-mapping.h --- linux-2.6.16.11/include/asm-avr32/dma-mapping.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/dma-mapping.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,324 @@ +#ifndef __ASM_AVR32_DMA_MAPPING_H +#define __ASM_AVR32_DMA_MAPPING_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include + +extern void dma_cache_sync(void *vaddr, size_t size, int direction); + +/* + * Return whether the given device DMA address mask can be supported + * properly. For example, if your device can only drive the low 24-bits + * during bus mastering, then you would pass 0x00ffffff as the mask + * to this function. + */ +static inline int dma_supported(struct device *dev, u64 mask) +{ + /* Fix when needed. I really don't know of any limitations */ + return 1; +} + +static inline int dma_set_mask(struct device *dev, u64 dma_mask) +{ + if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + return -EIO; + + *dev->dma_mask = dma_mask; + return 0; +} + +/** + * dma_alloc_coherent - allocate consistent memory for DMA + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @size: required memory size + * @handle: bus-specific DMA address + * + * Allocate some uncached, unbuffered memory for a device for + * performing DMA. This function allocates pages, and will + * return the CPU-viewed address, and sets @handle to be the + * device-viewed address. + */ +extern void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *handle, int gfp); + +/** + * dma_free_coherent - free memory allocated by dma_alloc_coherent + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @size: size of memory originally requested in dma_alloc_coherent + * @cpu_addr: CPU-view address returned from dma_alloc_coherent + * @handle: device-view address returned from dma_alloc_coherent + * + * Free (and unmap) a DMA buffer previously allocated by + * dma_alloc_coherent(). + * + * References to memory and mappings associated with cpu_addr/handle + * during and after this call executing are illegal. + */ +extern void dma_free_coherent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t handle); + +/** + * dma_alloc_writecombine - allocate write-combining memory for DMA + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @size: required memory size + * @handle: bus-specific DMA address + * + * Allocate some uncached, buffered memory for a device for + * performing DMA. This function allocates pages, and will + * return the CPU-viewed address, and sets @handle to be the + * device-viewed address. + */ +extern void *dma_alloc_writecombine(struct device *dev, size_t size, + dma_addr_t *handle, int gfp); + +/** + * dma_free_coherent - free memory allocated by dma_alloc_writecombine + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @size: size of memory originally requested in dma_alloc_writecombine + * @cpu_addr: CPU-view address returned from dma_alloc_writecombine + * @handle: device-view address returned from dma_alloc_writecombine + * + * Free (and unmap) a DMA buffer previously allocated by + * dma_alloc_writecombine(). + * + * References to memory and mappings associated with cpu_addr/handle + * during and after this call executing are illegal. + */ +extern void dma_free_writecombine(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t handle); + +/** + * dma_map_single - map a single buffer for streaming DMA + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @cpu_addr: CPU direct mapped address of buffer + * @size: size of buffer to map + * @dir: DMA transfer direction + * + * Ensure that any data held in the cache is appropriately discarded + * or written back. + * + * The device owns this memory once this call has completed. The CPU + * can regain ownership by calling dma_unmap_single() or dma_sync_single(). + */ +static inline dma_addr_t +dma_map_single(struct device *dev, void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + dma_cache_sync(cpu_addr, size, direction); + return virt_to_bus(cpu_addr); +} + +/** + * dma_unmap_single - unmap a single buffer previously mapped + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @handle: DMA address of buffer + * @size: size of buffer to map + * @dir: DMA transfer direction + * + * Unmap a single streaming mode DMA translation. The handle and size + * must match what was provided in the previous dma_map_single() call. + * All other usages are undefined. + * + * After this call, reads by the CPU to the buffer are guaranteed to see + * whatever the device wrote there. + */ +static inline void +dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + +} + +/** + * dma_map_page - map a portion of a page for streaming DMA + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @page: page that buffer resides in + * @offset: offset into page for start of buffer + * @size: size of buffer to map + * @dir: DMA transfer direction + * + * Ensure that any data held in the cache is appropriately discarded + * or written back. + * + * The device owns this memory once this call has completed. The CPU + * can regain ownership by calling dma_unmap_page() or dma_sync_single(). + */ +static inline dma_addr_t +dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + return dma_map_single(dev, page_address(page) + offset, + size, direction); +} + +/** + * dma_unmap_page - unmap a buffer previously mapped through dma_map_page() + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @handle: DMA address of buffer + * @size: size of buffer to map + * @dir: DMA transfer direction + * + * Unmap a single streaming mode DMA translation. The handle and size + * must match what was provided in the previous dma_map_single() call. + * All other usages are undefined. + * + * After this call, reads by the CPU to the buffer are guaranteed to see + * whatever the device wrote there. + */ +static inline void +dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + dma_unmap_single(dev, dma_address, size, direction); +} + +/** + * dma_map_sg - map a set of SG buffers for streaming mode DMA + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @sg: list of buffers + * @nents: number of buffers to map + * @dir: DMA transfer direction + * + * Map a set of buffers described by scatterlist in streaming + * mode for DMA. This is the scatter-gather version of the + * above pci_map_single interface. Here the scatter gather list + * elements are each tagged with the appropriate dma address + * and length. They are obtained via sg_dma_{address,length}(SG). + * + * NOTE: An implementation may be able to use a smaller number of + * DMA address/length pairs than there are SG table elements. + * (for example via virtual mapping capabilities) + * The routine returns the number of addr/length pairs actually + * used, at most nents. + * + * Device ownership issues as mentioned above for pci_map_single are + * the same here. + */ +static inline int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + int i; + + for (i = 0; i < nents; i++) { + char *virt; + + sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset; + virt = page_address(sg[i].page) + sg[i].offset; + dma_cache_sync(virt, sg[i].length, direction); + } + + return nents; +} + +/** + * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @sg: list of buffers + * @nents: number of buffers to map + * @dir: DMA transfer direction + * + * Unmap a set of streaming mode DMA translations. + * Again, CPU read rules concerning calls here are the same as for + * pci_unmap_single() above. + */ +static inline void +dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + +} + +/** + * dma_sync_single_for_cpu + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @handle: DMA address of buffer + * @size: size of buffer to map + * @dir: DMA transfer direction + * + * Make physical memory consistent for a single streaming mode DMA + * translation after a transfer. + * + * If you perform a dma_map_single() but wish to interrogate the + * buffer using the cpu, yet do not wish to teardown the DMA mapping, + * you must call this function before doing so. At the next point you + * give the DMA address back to the card, you must first perform a + * dma_sync_single_for_device, and then the device again owns the + * buffer. + */ +static inline void +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction) +{ + dma_cache_sync(bus_to_virt(dma_handle), size, direction); +} + +static inline void +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction) +{ + dma_cache_sync(bus_to_virt(dma_handle), size, direction); +} + +/** + * dma_sync_sg_for_cpu + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @sg: list of buffers + * @nents: number of buffers to map + * @dir: DMA transfer direction + * + * Make physical memory consistent for a set of streaming + * mode DMA translations after a transfer. + * + * The same as dma_sync_single_for_* but for a scatter-gather list, + * same rules and usage. + */ +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + int i; + + for (i = 0; i < nents; i++) { + dma_cache_sync(page_address(sg[i].page) + sg[i].offset, + sg[i].length, direction); + } +} + +static inline void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + int i; + + for (i = 0; i < nents; i++) { + dma_cache_sync(page_address(sg[i].page) + sg[i].offset, + sg[i].length, direction); + } +} + +/* Now for the API extensions over the pci_ one */ + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) + +static inline int dma_is_consistent(dma_addr_t dma_addr) +{ + return 1; +} + +static inline int dma_get_cache_alignment(void) +{ + return boot_cpu_data.dcache.linesz; +} + +#endif /* __KERNEL__ */ + +#endif /* __ASM_AVR32_DMA_MAPPING_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/elf.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/elf.h --- linux-2.6.16.11/include/asm-avr32/elf.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/elf.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,110 @@ +#ifndef __ASM_AVR32_ELF_H +#define __ASM_AVR32_ELF_H + +/* AVR32 relocation numbers */ +#define R_AVR32_NONE 0 +#define R_AVR32_32 1 +#define R_AVR32_16 2 +#define R_AVR32_8 3 +#define R_AVR32_32_PCREL 4 +#define R_AVR32_16_PCREL 5 +#define R_AVR32_8_PCREL 6 +#define R_AVR32_DIFF32 7 +#define R_AVR32_DIFF16 8 +#define R_AVR32_DIFF8 9 +#define R_AVR32_GOT32 10 +#define R_AVR32_GOT16 11 +#define R_AVR32_GOT8 12 +#define R_AVR32_21S 13 +#define R_AVR32_16U 14 +#define R_AVR32_16S 15 +#define R_AVR32_8S 16 +#define R_AVR32_8S_EXT 17 +#define R_AVR32_22H_PCREL 18 +#define R_AVR32_18W_PCREL 19 +#define R_AVR32_16B_PCREL 20 +#define R_AVR32_16N_PCREL 21 +#define R_AVR32_14UW_PCREL 22 +#define R_AVR32_11H_PCREL 23 +#define R_AVR32_10UW_PCREL 24 +#define R_AVR32_9H_PCREL 25 +#define R_AVR32_9UW_PCREL 26 +#define R_AVR32_HI16 27 +#define R_AVR32_LO16 28 +#define R_AVR32_GOTPC 29 +#define R_AVR32_GOTCALL 30 +#define R_AVR32_LDA_GOT 31 +#define R_AVR32_GOT21S 32 +#define R_AVR32_GOT18SW 33 +#define R_AVR32_GOT16S 34 +#define R_AVR32_GOT7UW 35 +#define R_AVR32_32_CPENT 36 +#define R_AVR32_CPCALL 37 +#define R_AVR32_16_CP 38 +#define R_AVR32_9W_CP 39 +#define R_AVR32_RELATIVE 40 +#define R_AVR32_GLOB_DAT 41 +#define R_AVR32_JMP_SLOT 42 +#define R_AVR32_ALIGN 43 + +/* + * ELF register definitions.. + */ + +#include +#include + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct pt_regs) / sizeof (elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_fpu_struct elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( (x)->e_machine == EM_AVR32 ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#ifdef __LITTLE_ENDIAN__ +#define ELF_DATA ELFDATA2LSB +#else +#define ELF_DATA ELFDATA2MSB +#endif +#define ELF_ARCH EM_AVR32 + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + + +/* This yields a mask that user programs can use to figure out what + instruction set this CPU supports. This could be done in user space, + but it's not easy, and we've already done it here. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. + + For the moment, we have only optimizations for the Intel generations, + but that could change... */ + +#define ELF_PLATFORM (NULL) + +#ifdef __KERNEL__ +#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT) +#endif + +#endif /* __ASM_AVR32_ELF_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/emergency-restart.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/emergency-restart.h --- linux-2.6.16.11/include/asm-avr32/emergency-restart.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/emergency-restart.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_EMERGENCY_RESTART_H +#define __ASM_AVR32_EMERGENCY_RESTART_H + +#include + +#endif /* __ASM_AVR32_EMERGENCY_RESTART_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/errno.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/errno.h --- linux-2.6.16.11/include/asm-avr32/errno.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/errno.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_ERRNO_H +#define __ASM_AVR32_ERRNO_H + +#include + +#endif /* __ASM_AVR32_ERRNO_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/fcntl.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/fcntl.h --- linux-2.6.16.11/include/asm-avr32/fcntl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/fcntl.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_FCNTL_H +#define __ASM_AVR32_FCNTL_H + +#include + +#endif /* __ASM_AVR32_FCNTL_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/hardirq.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/hardirq.h --- linux-2.6.16.11/include/asm-avr32/hardirq.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/hardirq.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,33 @@ +#ifndef __ASM_AVR32_HARDIRQ_H +#define __ASM_AVR32_HARDIRQ_H + +#include +#include +#include + +#ifndef __ASSEMBLY__ + +#include + +/* entry.S is sensitive to the offsets of these fields */ +typedef struct { + unsigned int __softirq_pending; +} ____cacheline_aligned irq_cpustat_t; + +/* Standard mappings for irq_cpustat_t above */ +#include + +#endif /* __ASSEMBLY__ */ + +#define HARDIRQ_BITS 12 + +/* + * The hardirq mask has to be large enough to have + * space for potentially all IRQ sources in the system + * nesting on a single CPU: + */ +#if (1 << HARDIRQ_BITS) < NR_IRQS +# error HARDIRQ_BITS is too low! +#endif + +#endif /* __ASM_AVR32_HARDIRQ_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/hardware/pdc.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/hardware/pdc.h --- linux-2.6.16.11/include/asm-avr32/hardware/pdc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/hardware/pdc.h 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * TODO: This file is only used by the Atmel MMCI driver. It should be + * removed as soon as that driver is converted to use the same headers + * as everyone else. + */ +#ifndef __ASM_AVR32_HARDWARE_PDC_H +#define __ASM_AVR32_HARDWARE_PDC_H + +#define PDC_RPR 0x100 +#define PDC_RCR 0x104 +#define PDC_TPR 0x108 +#define PDC_TCR 0x10c +#define PDC_RNPR 0x110 +#define PDC_RNCR 0x114 +#define PDC_TNPR 0x118 +#define PDC_TNCR 0x11c +#define PDC_PTCR 0x120 +#define PDC_PTSR 0x124 + +#define PDC_PTCR_RXTEN (1 << 0) +#define PDC_PTCR_RXTDIS (1 << 1) +#define PDC_PTCR_TXTEN (1 << 8) +#define PDC_PTCR_TXTDIS (1 << 9) + +#endif /* __ASM_AVR32_HARDWARE_PDC_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/hw_irq.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/hw_irq.h --- linux-2.6.16.11/include/asm-avr32/hw_irq.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/hw_irq.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,9 @@ +#ifndef __ASM_AVR32_HW_IRQ_H +#define __ASM_AVR32_HW_IRQ_H + +static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) +{ + /* Nothing to do */ +} + +#endif /* __ASM_AVR32_HW_IRQ_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/intc.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/intc.h --- linux-2.6.16.11/include/asm-avr32/intc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/intc.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,129 @@ +#ifndef __ASM_AVR32_INTC_H +#define __ASM_AVR32_INTC_H + +#include +#include +#include + +struct irq_controller; +struct irqaction; +struct pt_regs; + +struct at32_device; + +/* Information about the internal interrupt controller */ +struct intc_device { + /* ioremapped address of configuration block */ + void __iomem *regs; + + /* the physical device */ + struct at32_device *adev; + + /* Number of interrupt lines per group. */ + unsigned int irqs_per_group; + + /* The highest group ID + 1 */ + unsigned int nr_groups; + + /* + * Bitfield indicating which groups are actually in use. The + * size of the array is + * ceil(group_max / (8 * sizeof(unsigned int))). + */ + unsigned int group_mask[]; +}; + +struct irq_controller_class { + /* + * A short name identifying this kind of controller. + */ + const char *typename; + /* + * Handle the IRQ. Must do any necessary acking and masking. + */ + irqreturn_t (*handle)(int irq, void *dev_id, struct pt_regs *regs); + /* + * Register a new IRQ handler. + */ + int (*setup)(struct irq_controller *ctrl, unsigned int irq, + struct irqaction *action); + /* + * Unregister a IRQ handler. + */ + void (*free)(struct irq_controller *ctrl, unsigned int irq, + void *dev_id); + /* + * Mask the IRQ in the interrupt controller. + */ + void (*mask)(struct irq_controller *ctrl, unsigned int irq); + /* + * Unmask the IRQ in the interrupt controller. + */ + void (*unmask)(struct irq_controller *ctrl, unsigned int irq); + /* + * Set the type of the IRQ. See below for possible types. + * Return -EINVAL if a given type is not supported + */ + int (*set_type)(struct irq_controller *ctrl, unsigned int irq, + unsigned int type); + /* + * Return the IRQ type currently set + */ + unsigned int (*get_type)(struct irq_controller *ctrl, unsigned int irq); +}; + +struct irq_controller { + struct irq_controller_class *class; + unsigned int irq_group; + unsigned int first_irq; + unsigned int nr_irqs; + struct list_head list; +}; + +struct intc_group_desc { + struct irq_controller *ctrl; + irqreturn_t (*handle)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; +}; + +/* + * The internal interrupt controller. Defined in board/part-specific + * devices.c. + * TODO: Should probably be defined per-cpu. + */ +extern struct intc_device intc; + +extern int request_internal_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, void *dev_id); +extern void free_internal_irq(unsigned int irq); + +/* Only used by time_init() */ +extern int setup_internal_irq(unsigned int irq, struct intc_group_desc *desc); + +/* + * Set interrupt priority for a given group. `group' can be found by + * using irq_to_group(irq). Priority can be from 0 (lowest) to 3 + * (highest). Higher-priority interrupts will preempt lower-priority + * interrupts (unless interrupts are masked globally). + * + * This function does not check for conflicts within a group. + */ +extern int intc_set_priority(unsigned int group, + unsigned int priority); + +/* + * Returns a bitmask of pending interrupts in a group. + */ +extern unsigned long intc_get_pending(unsigned int group); + +/* + * Register a new external interrupt controller. Returns the first + * external IRQ number that is assigned to the new controller. + */ +extern int intc_register_controller(struct irq_controller *ctrl); + +#endif /* __ASM_AVR32_INTC_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/ioctl.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/ioctl.h --- linux-2.6.16.11/include/asm-avr32/ioctl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/ioctl.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_IOCTL_H +#define __ASM_AVR32_IOCTL_H + +#include + +#endif /* __ASM_AVR32_IOCTL_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/ioctls.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/ioctls.h --- linux-2.6.16.11/include/asm-avr32/ioctls.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/ioctls.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,83 @@ +#ifndef __ASM_AVR32_IOCTLS_H +#define __ASM_AVR32_IOCTLS_H + +#include + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +/* #define TIOCTTYGSTRUCT 0x5426 - Former debugging-only ioctl */ +#define TIOCSBRK 0x5427 /* BSD compatibility */ +#define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +#endif /* __ASM_AVR32_IOCTLS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/io.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/io.h --- linux-2.6.16.11/include/asm-avr32/io.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/io.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,246 @@ +#ifndef __ASM_AVR32_IO_H +#define __ASM_AVR32_IO_H + +#include + +#ifdef __KERNEL__ + +/* + * Generic IO read/write. These perform native-endian accesses. Note + * that some architectures will want to re-define __raw_{read,write}w. + */ +extern void __raw_writesb(unsigned int addr, const void *data, int bytelen); +extern void __raw_writesw(unsigned int addr, const void *data, int wordlen); +extern void __raw_writesl(unsigned int addr, const void *data, int longlen); + +extern void __raw_readsb(unsigned int addr, void *data, int bytelen); +extern void __raw_readsw(unsigned int addr, void *data, int wordlen); +extern void __raw_readsl(unsigned int addr, void *data, int longlen); + +#ifdef PCMCIA_HSMC_IO_HACK +#error Needs updating +/* The HMATRIX tries to byteswap the address for us, so we have to swap it back. */ +#define __raw_writeb(v,a) (*(volatile unsigned char *)((unsigned long)(a) ^ 3UL) = (v)) +#define __raw_writew(v,a) (*(volatile unsigned short *)((unsigned long)(a) ^ 2UL) = (v)) +#define __raw_writel(v,a) (*(volatile unsigned int *)(a) = (v)) + +#define __raw_readb(a) (*(volatile unsigned char *)((unsigned long)(a) ^ 3UL)) +#define __raw_readw(a) (*(volatile unsigned short *)((unsigned long)(a) ^ 2UL)) +#define __raw_readl(a) (*(volatile unsigned int *)(a)) +#else +static inline void writeb(unsigned char b, volatile void __iomem *addr) +{ + *(volatile unsigned char __force *)addr = b; +} +static inline void writew(unsigned short b, volatile void __iomem *addr) +{ + *(volatile unsigned short __force *)addr = b; +} +static inline void writel(unsigned int b, volatile void __iomem *addr) +{ + *(volatile unsigned int __force *)addr = b; +} +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel + +static inline unsigned char readb(const volatile void __iomem *addr) +{ + return *(const volatile unsigned char __force *)addr; +} +static inline unsigned short readw(const volatile void __iomem *addr) +{ + return *(const volatile unsigned short __force *)addr; +} +static inline unsigned int readl(const volatile void __iomem *addr) +{ + return *(const volatile unsigned int __force *)addr; +} +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl +#endif + +#define writesb(p, d, l) __raw_writesb((unsigned int)p, d, l) +#define writesw(p, d, l) __raw_writesw((unsigned int)p, d, l) +#define writesl(p, d, l) __raw_writesl((unsigned int)p, d, l) + +#define readsb(p, d, l) __raw_readsb((unsigned int)p, d, l) +#define readsw(p, d, l) __raw_readsw((unsigned int)p, d, l) +#define readsl(p, d, l) __raw_readsl((unsigned int)p, d, l) + +/* + * These two are only here because ALSA _thinks_ it needs them... + */ +static inline void memcpy_fromio(void * to, const volatile void __iomem *from, + unsigned long count) +{ + char *p = to; + while (count) { + count--; + *p = readb(from); + p++; + from++; + } +} + +static inline void memcpy_toio(volatile void __iomem *to, const void * from, + unsigned long count) +{ + const char *p = from; + while (count) { + count--; + writeb(*p, to); + p++; + to++; + } +} + +static inline void memset_io(volatile void __iomem *addr, unsigned char val, + unsigned long count) +{ + memset((void __force *)addr, val, count); +} + +/* + * Bad read/write accesses... + */ +extern void __readwrite_bug(const char *fn); + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * All I/O is memory mapped, so these macros don't make very much + * sense. They are needed for PCMCIA support, however, so we'll have + * to implement them somehow. For now, they will cause linker errors. + */ +extern void outb(unsigned char value, unsigned long port); +extern void outw(unsigned short value, unsigned long port); +extern void outl(unsigned long value, unsigned long port); + +extern unsigned char inb(unsigned long port); +extern unsigned short inw(unsigned long port); +extern unsigned long inl(unsigned long port); + +static inline void __outsb(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + outb(*(u8 *)addr, port); + addr++; + } +} + +static inline void __insb(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + *(u8 *)addr = inb(port); + addr++; + } +} + +static inline void __outsw(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + outw(*(u16 *)addr, port); + addr += 2; + } +} + +static inline void __insw(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + *(u16 *)addr = inw(port); + addr += 2; + } +} + +static inline void __outsl(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + outl(*(u32 *)addr, port); + addr += 4; + } +} + +static inline void __insl(unsigned long port, void *addr, unsigned int count) +{ + while (count--) { + *(u32 *)addr = inl(port); + addr += 4; + } +} + +#define outsb(port, addr, count) __outsb(port, addr, count) +#define insb(port, addr, count) __insb(port, addr, count) +#define outsw(port, addr, count) __outsw(port, addr, count) +#define insw(port, addr, count) __insw(port, addr, count) +#define outsl(port, addr, count) __outsl(port, addr, count) +#define insl(port, addr, count) __insl(port, addr, count) + +extern void __iomem *__ioremap(unsigned long offset, size_t size, + unsigned long flags); +extern void __iounmap(void __iomem *addr); + +/* + * ioremap - map bus memory into CPU space + * @offset bus address of the memory + * @size size of the resource to map + * + * ioremap performs a platform specific sequence of operations to make + * bus memory CPU accessible via the readb/.../writel functions and + * the other mmio helpers. The returned address is not guaranteed to + * be usable directly as a virtual address. + */ +#define ioremap(offset, size) \ + __ioremap((offset), (size), 0) + +#define iounmap(addr) \ + __iounmap(addr) + +#include + +/* virt_to_phys will only work when address is in P1 or P2 */ +static __inline__ unsigned long virt_to_phys(volatile void *address) +{ + return PHYSADDR(address); +} + +static __inline__ void * phys_to_virt(unsigned long address) +{ + return (void *)P1SEGADDR(address); +} + +#define cached_to_phys(addr) ((unsigned long)PHYSADDR(addr)) +#define uncached_to_phys(addr) ((unsigned long)PHYSADDR(addr)) +#define phys_to_cached(addr) ((void *)P1SEGADDR(addr)) +#define phys_to_uncached(addr) ((void *)P2SEGADDR(addr)) + +#define cached(addr) P1SEGADDR(addr) +#define uncached(addr) P2SEGADDR(addr) + +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt +#define page_to_bus page_to_phys +#define bus_to_page phys_to_page + +#define dma_cache_wback_inv(_start, _size) \ + flush_dcache_region(_start, _size) +#define dma_cache_inv(_start, _size) \ + invalidate_dcache_region(_start, _size) +#define dma_cache_wback(_start, _size) \ + clean_dcache_region(_start, _size) + +/* + * Convert a physical pointer to a virtual kernel pointer for /dev/mem + * access + */ +#define xlate_dev_mem_ptr(p) __va(p) + +/* + * Convert a virtual cached pointer to an uncached pointer + */ +#define xlate_dev_kmem_ptr(p) p + +#endif /* __KERNEL__ */ + +#endif /* __ASM_AVR32_IO_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/ipcbuf.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/ipcbuf.h --- linux-2.6.16.11/include/asm-avr32/ipcbuf.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/ipcbuf.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,29 @@ +#ifndef __ASM_AVR32_IPCBUF_H +#define __ASM_AVR32_IPCBUF_H + +/* +* The user_ipc_perm structure for AVR32 architecture. +* Note extra padding because this structure is passed back and forth +* between kernel and user space. +* +* Pad space is left for: +* - 32-bit mode_t and seq +* - 2 miscellaneous 32-bit values +*/ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __ASM_AVR32_IPCBUF_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/irq.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/irq.h --- linux-2.6.16.11/include/asm-avr32/irq.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/irq.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,44 @@ +#ifndef __ASM_AVR32_IRQ_H +#define __ASM_AVR32_IRQ_H + +#include +#include + +#define NR_INTERNAL_IRQS 64 +#define NR_EXTERNAL_IRQS 64 +#define NR_IRQS (NR_INTERNAL_IRQS + NR_EXTERNAL_IRQS) + +/* + * IRQ line status + */ +#define IRQ_INPROGRESS 1 +#define IRQ_DISABLED 2 +#define IRQ_PENDING 4 +#define IRQ_REPLAY 8 +#define IRQ_WAITING 32 + +#define IRQ_TYPE_EDGE (0 << 0) +#define IRQ_TYPE_LEVEL (1 << 0) +#define IRQ_EDGE_FALLING (0 << 1) +#define IRQ_EDGE_RISING (1 << 1) +#define IRQ_LEVEL_LOW (1 << 2) +#define IRQ_LEVEL_HIGH (0 << 2) + +#define irq_canonicalize(i) (i) + +#ifndef __ASSEMBLY__ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/* AVR32 specific functions */ +struct pt_regs; +asmlinkage void do_IRQ(int level, struct pt_regs *regs); + +/* Set/get the interrupt type, i.e. edge/level and polarity */ +extern int irq_set_type(unsigned int irq, unsigned int type); +extern unsigned int irq_get_type(unsigned int irq); + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_AVR32_IOCTLS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/kdebug.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/kdebug.h --- linux-2.6.16.11/include/asm-avr32/kdebug.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/kdebug.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,39 @@ +#ifndef __ASM_AVR32_KDEBUG_H +#define __ASM_AVR32_KDEBUG_H + +#include + +struct pt_regs; + +struct die_args { + struct pt_regs *regs; + int trapnr; +}; + +/* + Note - you should never unregister because that can race with NMIs. + If you really want to do it first unregister - then synchronize_sched - + then free. + */ +int register_die_notifier(struct notifier_block *nb); +extern struct notifier_block *avr32_die_chain; + +/* Grossly misnamed. */ +enum die_val { + DIE_FAULT, + DIE_BREAKPOINT, + DIE_SSTEP, +}; + +static inline int notify_die(enum die_val val, struct pt_regs *regs, + int trap, int sig) +{ + struct die_args args = { + .regs = regs, + .trapnr = trap, + }; + + return notifier_call_chain(&avr32_die_chain, val, &args); +} + +#endif /* __ASM_AVR32_KDEBUG_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/kmap_types.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/kmap_types.h --- linux-2.6.16.11/include/asm-avr32/kmap_types.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/kmap_types.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,32 @@ +#ifndef __ASM_AVR32_KMAP_TYPES_H +#define __ASM_AVR32_KMAP_TYPES_H + +#include + +#ifdef CONFIG_DEBUG_HIGHMEM +# define D(n) __KM_FENCE_##n , +#else +# define D(n) +#endif + +enum km_type { +D(0) KM_BOUNCE_READ, +D(1) KM_SKB_SUNRPC_DATA, +D(2) KM_SKB_DATA_SOFTIRQ, +D(3) KM_USER0, +D(4) KM_USER1, +D(5) KM_BIO_SRC_IRQ, +D(6) KM_BIO_DST_IRQ, +D(7) KM_PTE0, +D(8) KM_PTE1, +D(9) KM_PTE2, +D(10) KM_IRQ0, +D(11) KM_IRQ1, +D(12) KM_SOFTIRQ0, +D(13) KM_SOFTIRQ1, +D(14) KM_TYPE_NR +}; + +#undef D + +#endif /* __ASM_AVR32_KMAP_TYPES_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/kprobes.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/kprobes.h --- linux-2.6.16.11/include/asm-avr32/kprobes.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/kprobes.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,36 @@ +/* + * Kernel Probes (KProbes) + * + * Copyright (C) 2005-2006 Atmel Corporation + * Copyright (C) IBM Corporation, 2002, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_KPROBES_H +#define __ASM_AVR32_KPROBES_H + +#include + +typedef u16 kprobe_opcode_t; +#define BREAKPOINT_INSTRUCTION 0xd673 /* breakpoint */ +#define MAX_INSN_SIZE 2 + +/* Architecture specific copy of original instruction */ +struct arch_specific_insn { + kprobe_opcode_t insn[MAX_INSN_SIZE]; +}; + +#ifdef CONFIG_KPROBES +extern int kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data); +#else +static inline int kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + return 0; +} +#endif + +#endif /* __ASM_AVR32_KPROBES_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/linkage.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/linkage.h --- linux-2.6.16.11/include/asm-avr32/linkage.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/linkage.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,7 @@ +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +#define __ALIGN .balign 2 +#define __ALIGN_STR ".balign 2" + +#endif /* __ASM_LINKAGE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/local.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/local.h --- linux-2.6.16.11/include/asm-avr32/local.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/local.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_LOCAL_H +#define __ASM_AVR32_LOCAL_H + +#include + +#endif /* __ASM_AVR32_LOCAL_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/mman.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/mman.h --- linux-2.6.16.11/include/asm-avr32/mman.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/mman.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,17 @@ +#ifndef __ASM_AVR32_MMAN_H__ +#define __ASM_AVR32_MMAN_H__ + +#include + +#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define MAP_LOCKED 0x2000 /* pages are locked */ +#define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) page tables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ + +#define MCL_CURRENT 1 /* lock all current mappings */ +#define MCL_FUTURE 2 /* lock all future mappings */ + +#endif /* __ASM_AVR32_MMAN_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/mmu_context.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/mmu_context.h --- linux-2.6.16.11/include/asm-avr32/mmu_context.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/mmu_context.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * ASID handling taken from SH implementation. + * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 2003 Paul Mundt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_MMU_CONTEXT_H +#define __ASM_AVR32_MMU_CONTEXT_H + +#ifdef __KERNEL__ + +#include +#include +#include + +/* + * The MMU "context" consists of two things: + * (a) TLB cache version + * (b) ASID (Address Space IDentifier) + */ +#define MMU_CONTEXT_ASID_MASK 0x000000ff +#define MMU_CONTEXT_VERSION_MASK 0xffffff00 +#define MMU_CONTEXT_FIRST_VERSION 0x00000100 +#define NO_CONTEXT 0 + +#define MMU_NO_ASID 0x100 + +/* Virtual Page Number mask */ +#define MMU_VPN_MASK 0xfffff000 + +/* Cache of MMU context last used */ +extern unsigned long mmu_context_cache; + +/* + * Get MMU context if needed + */ +static inline void +get_mmu_context(struct mm_struct *mm) +{ + unsigned long mc = mmu_context_cache; + + if (((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0) + /* It's up to date, do nothing */ + return; + + /* It's old, we need to get new context with new version */ + mc = ++mmu_context_cache; + if (!(mc & MMU_CONTEXT_ASID_MASK)) { + /* + * We have exhausted all ASIDs of this version. + * Flush the TLB and start new cycle. + */ + flush_tlb_all(); + /* + * Fix version. Note that we avoid version #0 + * to distinguish NO_CONTEXT. + */ + if (!mc) + mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION; + } + mm->context = mc; +} + +/* + * Initialize the context related info for a new mm_struct + * instance. + */ +static inline int init_new_context(struct task_struct *tsk, + struct mm_struct *mm) +{ + mm->context = NO_CONTEXT; + return 0; +} + +/* + * Destroy context related info for an mm_struct that is about + * to be put to rest. + */ +static inline void destroy_context(struct mm_struct *mm) +{ + /* Do nothing */ +} + +static inline void set_asid(unsigned long asid) +{ + /* XXX: We're destroying TLBEHI[8:31] */ + sysreg_write(TLBEHI, asid & MMU_CONTEXT_ASID_MASK); + cpu_sync_pipeline(); +} + +static inline unsigned long get_asid(void) +{ + unsigned long asid; + + asid = sysreg_read(TLBEHI); + return asid & MMU_CONTEXT_ASID_MASK; +} + +static inline void activate_context(struct mm_struct *mm) +{ + get_mmu_context(mm); + set_asid(mm->context & MMU_CONTEXT_ASID_MASK); +} + +static inline void switch_mm(struct mm_struct *prev, + struct mm_struct *next, + struct task_struct *tsk) +{ + if (likely(prev != next)) { + unsigned long __pgdir = (unsigned long)next->pgd; + + sysreg_write(PTBR, __pgdir); + activate_context(next); + } +} + +#define deactivate_mm(tsk,mm) do { } while(0) + +#define activate_mm(prev, next) switch_mm((prev), (next), NULL) + +static inline void +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ +} + + +static inline void enable_mmu(void) +{ + sysreg_write(MMUCR, (SYSREG_BIT(MMUCR_S) + | SYSREG_BIT(E) + | SYSREG_BIT(MMUCR_I))); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + + if (mmu_context_cache == NO_CONTEXT) + mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; + + set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK); +} + +static inline void disable_mmu(void) +{ + sysreg_write(MMUCR, SYSREG_BIT(MMUCR_S)); +} + +#endif /* __KERNEL__ */ + +#endif /* __ASM_AVR32_MMU_CONTEXT_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/mmu.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/mmu.h --- linux-2.6.16.11/include/asm-avr32/mmu.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/mmu.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,12 @@ +#ifndef __ASM_AVR32_MMU_H +#define __ASM_AVR32_MMU_H + +#include + +/* Default "unsigned long" context */ +typedef unsigned long mm_context_t; + +#define MMU_ITLB_ENTRIES 64 +#define MMU_DTLB_ENTRIES 64 + +#endif /* __ASM_AVR32_MMU_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/mmzone.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/mmzone.h --- linux-2.6.16.11/include/asm-avr32/mmzone.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/mmzone.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_MMZONE_H +#define __ASM_AVR32_MMZONE_H + +#include + +#ifdef CONFIG_DISCONTIGMEM + +extern pg_data_t discontig_node_data[]; + +/* + * Return a pointer to the node data for node n. + */ +#define NODE_DATA(nid) (&discontig_node_data[nid]) + +/* + * NODE_MEM_MAP gives the kaddr for the mem_map of the node. + */ +#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map) + +static inline pg_data_t *pfn_to_pgdat(unsigned long pfn) +{ + pg_data_t *pgdat; + + for_each_pgdat(pgdat) { + unsigned long start = pgdat->node_start_pfn; + unsigned long end = start + pgdat->node_spanned_pages; + if ((pfn >= start) && (pfn < end)) + return pgdat; + } + + return NULL; +} + +static inline int pfn_valid(unsigned long pfn) +{ + return pfn_to_pgdat(pfn) != NULL; +} + +#define pfn_to_page(pfn) \ + ({ \ + unsigned long __pfn = (pfn); \ + pg_data_t *pgdat = pfn_to_pgdat(__pfn); \ + __pfn -= pgdat->node_start_pfn; \ + (pgdat->node_mem_map + __pfn); \ + }) + +#define page_to_pfn(pg) \ + ({ \ + struct page *__page = (pg); \ + struct zone *__zone = page_zone(__page); \ + ((__page - __zone->zone_mem_map) \ + + __zone->zone_start_pfn); \ + }) + +#endif /* !CONFIG_DISCONTIGMEM */ + +#endif /* __ASM_AVR32_MMZONE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/module.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/module.h --- linux-2.6.16.11/include/asm-avr32/module.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/module.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,28 @@ +#ifndef __ASM_AVR32_MODULE_H +#define __ASM_AVR32_MODULE_H + +struct mod_arch_syminfo { + unsigned long got_offset; + int got_initialized; +}; + +struct mod_arch_specific { + /* Starting offset of got in the module core memory. */ + unsigned long got_offset; + /* Size of the got. */ + unsigned long got_size; + /* Number of symbols in syminfo. */ + int nsyms; + /* Additional symbol information (got offsets). */ + struct mod_arch_syminfo *syminfo; +}; + +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr + +#define MODULE_PROC_FAMILY "AVR32v1" + +#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY + +#endif /* __ASM_AVR32_MODULE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/msgbuf.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/msgbuf.h --- linux-2.6.16.11/include/asm-avr32/msgbuf.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/msgbuf.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,31 @@ +#ifndef __ASM_AVR32_MSGBUF_H +#define __ASM_AVR32_MSGBUF_H + +/* + * The msqid64_ds structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_time_t msg_stime; /* last msgsnd time */ + unsigned long __unused1; + __kernel_time_t msg_rtime; /* last msgrcv time */ + unsigned long __unused2; + __kernel_time_t msg_ctime; /* last change time */ + unsigned long __unused3; + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* __ASM_AVR32_MSGBUF_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/mutex.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/mutex.h --- linux-2.6.16.11/include/asm-avr32/mutex.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/mutex.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,9 @@ +/* + * Pull in the generic implementation for the mutex fastpath. + * + * TODO: implement optimized primitives instead, or leave the generic + * implementation in place, or pick the atomic_xchg() based generic + * implementation. (see asm-generic/mutex-xchg.h for details) + */ + +#include diff -Nur linux-2.6.16.11/include/asm-avr32/namei.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/namei.h --- linux-2.6.16.11/include/asm-avr32/namei.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/namei.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,7 @@ +#ifndef __ASM_AVR32_NAMEI_H +#define __ASM_AVR32_NAMEI_H + +/* This dummy routine may be changed to something useful */ +#define __emul_prefix() NULL + +#endif /* __ASM_AVR32_NAMEI_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/numnodes.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/numnodes.h --- linux-2.6.16.11/include/asm-avr32/numnodes.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/numnodes.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,7 @@ +#ifndef __ASM_AVR32_NUMNODES_H +#define __ASM_AVR32_NUMNODES_H + +/* Max 4 nodes */ +#define NODES_SHIFT 2 + +#endif /* __ASM_AVR32_NUMNODES_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/ocd.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/ocd.h --- linux-2.6.16.11/include/asm-avr32/ocd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/ocd.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,77 @@ +/* + * AVR32 OCD Registers + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_OCD_H +#define __ASM_AVR32_OCD_H + +/* Debug Registers */ +#define DBGREG_DID 0 +#define DBGREG_DC 8 +#define DBGREG_DS 16 +#define DBGREG_RWCS 28 +#define DBGREG_RWA 36 +#define DBGREG_RWD 40 +#define DBGREG_WT 44 +#define DBGREG_DTC 52 +#define DBGREG_DTSA0 56 +#define DBGREG_DTSA1 60 +#define DBGREG_DTEA0 72 +#define DBGREG_DTEA1 76 +#define DBGREG_BWC0A 88 +#define DBGREG_BWC0B 92 +#define DBGREG_BWC1A 96 +#define DBGREG_BWC1B 100 +#define DBGREG_BWC2A 104 +#define DBGREG_BWC2B 108 +#define DBGREG_BWC3A 112 +#define DBGREG_BWC3B 116 +#define DBGREG_BWA0A 120 +#define DBGREG_BWA0B 124 +#define DBGREG_BWA1A 128 +#define DBGREG_BWA1B 132 +#define DBGREG_BWA2A 136 +#define DBGREG_BWA2B 140 +#define DBGREG_BWA3A 144 +#define DBGREG_BWA3B 148 +#define DBGREG_BWD3A 153 +#define DBGREG_BWD3B 156 + +#define DBGREG_PID 284 + +#define SABAH_OCD 0x01 +#define SABAH_ICACHE 0x02 +#define SABAH_MEM_CACHED 0x04 +#define SABAH_MEM_UNCACHED 0x05 + +/* Fields in the Development Control register */ +#define DC_SS_BIT 8 + +#define DC_SS (1 << DC_SS_BIT) +#define DC_DBE (1 << 13) +#define DC_RID (1 << 27) +#define DC_ORP (1 << 28) +#define DC_MM (1 << 29) + +/* Fields in the Development Status register */ +#define DS_SSS (1 << 0) +#define DS_SWB (1 << 1) +#define DS_HWB (1 << 2) +#define DS_BP_SHIFT 8 +#define DS_BP_MASK (0xff << DS_BP_SHIFT) + +#define __mfdr(addr) \ +({ \ + register unsigned long value; \ + asm volatile("mfdr %0, %1" : "=r"(value) : "i"(addr)); \ + value; \ +}) +#define __mtdr(addr, value) \ + asm volatile("mtdr %0, %1" : : "i"(addr), "r"(value)) + +#endif /* __ASM_AVR32_OCD_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/page.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/page.h --- linux-2.6.16.11/include/asm-avr32/page.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/page.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PAGE_H +#define __ASM_AVR32_PAGE_H + +#include + +/* PAGE_SHIFT determines the page size */ +#define PAGE_SHIFT 12 +#ifdef __ASSEMBLY__ +#define PAGE_SIZE (1 << PAGE_SHIFT) +#else +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#endif +#define PAGE_MASK (~(PAGE_SIZE-1)) +#define PTE_MASK PAGE_MASK + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ + +#include + +extern void clear_page(void *to); +extern void copy_page(void *to, void *from); + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +/* + * These are used to make use of C type-checking.. + */ +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pgprot; } pgprot_t; + +#define pte_val(x) ((x).pte) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) }) +#define __pgd(x) ((pgd_t) { (x) }) +#define __pgprot(x) ((pgprot_t) { (x) }) + +/* FIXME: These should be removed soon */ +extern unsigned long memory_start, memory_end; + +/* Pure 2^n version of get_order */ +static inline int get_order(unsigned long size) +{ + unsigned lz; + + size = (size - 1) >> PAGE_SHIFT; + asm("clz %0, %1" : "=r"(lz) : "r"(size)); + return 32 - lz; +} + +#endif /* !__ASSEMBLY__ */ + +/* Align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) + +/* + * The hardware maps the virtual addresses 0x80000000 -> 0x9fffffff + * permanently to the physical addresses 0x00000000 -> 0x1fffffff when + * segmentation is enabled. We want to make use of this in order to + * minimize TLB pressure. + */ +#define PAGE_OFFSET (0x80000000UL) + +/* + * ALSA uses virt_to_page() on DMA pages, which I'm not entirely sure + * is a good idea. Anyway, we can't simply subtract PAGE_OFFSET here + * in that case, so we'll have to mask out the three most significant + * bits of the address instead... + * + * What's the difference between __pa() and virt_to_phys() anyway? + */ +#define __pa(x) PHYSADDR(x) +#define __va(x) ((void *)(P1SEGADDR(x))) + +#define MAP_NR(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT) + +#define phys_to_page(phys) (pfn_to_page(phys >> PAGE_SHIFT)) +#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) + +#ifndef CONFIG_NEED_MULTIPLE_NODES + +#define PHYS_PFN_OFFSET (CONFIG_PHYS_OFFSET >> PAGE_SHIFT) + +#define pfn_to_page(pfn) (mem_map + ((pfn) - PHYS_PFN_OFFSET)) +#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PHYS_PFN_OFFSET) +#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) +#endif /* CONFIG_NEED_MULTIPLE_NODES */ + +#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) + +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +/* + * Memory above this physical address will be considered highmem. + */ +#define HIGHMEM_START 0x20000000UL + +#endif /* __KERNEL__ */ + +#endif /* __ASM_AVR32_PAGE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/param.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/param.h --- linux-2.6.16.11/include/asm-avr32/param.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/param.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,24 @@ +#ifndef __ASM_AVR32_PARAM_H +#define __ASM_AVR32_PARAM_H + +#ifdef __KERNEL__ +# include +# define HZ CONFIG_HZ +# define USER_HZ 100 /* User interfaces are in "ticks" */ +# define CLOCKS_PER_SEC (USER_HZ) /* frequency at which times() counts */ +#endif + +#ifndef HZ +# define HZ 100 +#endif + +/* TODO: Should be configurable */ +#define EXEC_PAGESIZE 4096 + +#ifndef NOGROUP +# define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 + +#endif /* __ASM_AVR32_PARAM_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/pci.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/pci.h --- linux-2.6.16.11/include/asm-avr32/pci.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/pci.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,8 @@ +#ifndef __ASM_AVR32_PCI_H__ +#define __ASM_AVR32_PCI_H__ + +/* We don't support PCI yet, but some drivers require this file anyway */ + +#define PCI_DMA_BUS_IS_PHYS (1) + +#endif /* __ASM_AVR32_PCI_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/percpu.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/percpu.h --- linux-2.6.16.11/include/asm-avr32/percpu.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/percpu.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_PERCPU_H +#define __ASM_AVR32_PERCPU_H + +#include + +#endif /* __ASM_AVR32_PERCPU_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/periph/hebi.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/hebi.h --- linux-2.6.16.11/include/asm-avr32/periph/hebi.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/hebi.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,316 @@ +/* + * Register definitions for HEBI + * + * External Bus Interface + */ +#ifndef __ASM_AVR32_HEBI_H__ +#define __ASM_AVR32_HEBI_H__ + +/* HEBI register offsets */ +#define HEBI_SMC_SETUP0 0x0000 +#define HEBI_SMC_PULSE0 0x0004 +#define HEBI_SMC_CYCLE0 0x0008 +#define HEBI_SMC_MODE0 0x000c +#define HEBI_SMC_SETUP1 0x0010 +#define HEBI_SMC_PULSE1 0x0014 +#define HEBI_SMC_CYCLE1 0x0018 +#define HEBI_SMC_MODE1 0x001c +#define HEBI_SMC_SETUP2 0x0020 +#define HEBI_SMC_PULSE2 0x0024 +#define HEBI_SMC_CYCLE2 0x0028 +#define HEBI_SMC_MODE2 0x002c +#define HEBI_SMC_SETUP3 0x0030 +#define HEBI_SMC_PULSE3 0x0034 +#define HEBI_SMC_CYCLE3 0x0038 +#define HEBI_SMC_MODE3 0x003c +#define HEBI_SMC_SETUP4 0x0040 +#define HEBI_SMC_PULSE4 0x0044 +#define HEBI_SMC_CYCLE4 0x0048 +#define HEBI_SMC_MODE4 0x004c +#define HEBI_SMC_SETUP5 0x0050 +#define HEBI_SMC_PULSE5 0x0054 +#define HEBI_SMC_CYCLE5 0x0058 +#define HEBI_SMC_MODE5 0x005c +#define HEBI_SDRAMC_MR 0x0400 +#define HEBI_SDRAMC_TR 0x0404 +#define HEBI_SDRAMC_CR 0x0408 +#define HEBI_SDRAMC_HSR 0x040c +#define HEBI_SDRAMC_LPR 0x0410 +#define HEBI_SDRAMC_IER 0x0414 +#define HEBI_SDRAMC_IDR 0x0418 +#define HEBI_SDRAMC_IMR 0x041c +#define HEBI_SDRAMC_ISR 0x0420 +#define HEBI_SDRAMC_MDR 0x0424 +#define HEBI_ECC_CR 0x0800 +#define HEBI_ECC_MR 0x0804 +#define HEBI_ECC_SR 0x0808 +#define HEBI_ECC_PR 0x080c +#define HEBI_ECC_NPR 0x0810 + +/* Bitfields in SMC_SETUP0 */ +#define HEBI_NWE_SETUP_OFFSET 0 +#define HEBI_NWE_SETUP_SIZE 6 +#define HEBI_NCS_WR_SETUP_OFFSET 8 +#define HEBI_NCS_WR_SETUP_SIZE 6 +#define HEBI_NRD_SETUP_OFFSET 16 +#define HEBI_NRD_SETUP_SIZE 6 +#define HEBI_NCS_RD_SETUP_OFFSET 24 +#define HEBI_NCS_RD_SETUP_SIZE 6 + +/* Bitfields in SMC_PULSE0 */ +#define HEBI_NWE_PULSE_OFFSET 0 +#define HEBI_NWE_PULSE_SIZE 7 +#define HEBI_NCS_WR_PULSE_OFFSET 8 +#define HEBI_NCS_WR_PULSE_SIZE 7 +#define HEBI_NRD_PULSE_OFFSET 16 +#define HEBI_NRD_PULSE_SIZE 7 +#define HEBI_NCS_RD_PULSE_OFFSET 24 +#define HEBI_NCS_RD_PULSE_SIZE 7 + +/* Bitfields in SMC_CYCLE0 */ +#define HEBI_NWE_CYCLE_OFFSET 0 +#define HEBI_NWE_CYCLE_SIZE 9 +#define HEBI_NRD_CYCLE_OFFSET 16 +#define HEBI_NRD_CYCLE_SIZE 9 + +/* Bitfields in SMC_MODE0 */ +#define HEBI_READ_MODE_OFFSET 0 +#define HEBI_READ_MODE_SIZE 1 +#define HEBI_WRITE_MODE_OFFSET 1 +#define HEBI_WRITE_MODE_SIZE 1 +#define HEBI_EXNW_MODE_OFFSET 4 +#define HEBI_EXNW_MODE_SIZE 2 +#define HEBI_BAT_OFFSET 8 +#define HEBI_BAT_SIZE 1 +#define HEBI_SMC_MODE0_DBW_OFFSET 12 +#define HEBI_SMC_MODE0_DBW_SIZE 2 +#define HEBI_TDF_CYCLES_OFFSET 16 +#define HEBI_TDF_CYCLES_SIZE 4 +#define HEBI_TDF_MODE_OFFSET 20 +#define HEBI_TDF_MODE_SIZE 1 +#define HEBI_PMEN_OFFSET 24 +#define HEBI_PMEN_SIZE 1 +#define HEBI_PS_OFFSET 28 +#define HEBI_PS_SIZE 2 + +/* Bitfields in SMC_SETUP1 */ + +/* Bitfields in SMC_PULSE1 */ + +/* Bitfields in SMC_CYCLE1 */ + +/* Bitfields in SMC_MODE1 */ +#define HEBI_SMC_MODE1_DBW_OFFSET 12 +#define HEBI_SMC_MODE1_DBW_SIZE 2 + +/* Bitfields in SMC_SETUP2 */ + +/* Bitfields in SMC_PULSE2 */ + +/* Bitfields in SMC_CYCLE2 */ + +/* Bitfields in SMC_MODE2 */ +#define HEBI_SMC_MODE2_DBW_OFFSET 12 +#define HEBI_SMC_MODE2_DBW_SIZE 2 + +/* Bitfields in SMC_SETUP3 */ + +/* Bitfields in SMC_PULSE3 */ + +/* Bitfields in SMC_CYCLE3 */ + +/* Bitfields in SMC_MODE3 */ +#define HEBI_SMC_MODE3_DBW_OFFSET 12 +#define HEBI_SMC_MODE3_DBW_SIZE 2 + +/* Bitfields in SMC_SETUP4 */ + +/* Bitfields in SMC_PULSE4 */ + +/* Bitfields in SMC_CYCLE4 */ + +/* Bitfields in SMC_MODE4 */ +#define HEBI_SMC_MODE4_DBW_OFFSET 12 +#define HEBI_SMC_MODE4_DBW_SIZE 2 + +/* Bitfields in SMC_SETUP5 */ + +/* Bitfields in SMC_PULSE5 */ + +/* Bitfields in SMC_CYCLE5 */ + +/* Bitfields in SMC_MODE5 */ +#define HEBI_SMC_MODE5_DBW_OFFSET 12 +#define HEBI_SMC_MODE5_DBW_SIZE 2 + +/* Bitfields in SDRAMC_MR */ +#define HEBI_MODE_OFFSET 0 +#define HEBI_MODE_SIZE 3 + +/* Bitfields in SDRAMC_TR */ +#define HEBI_COUNT_OFFSET 0 +#define HEBI_COUNT_SIZE 12 + +/* Bitfields in SDRAMC_CR */ +#define HEBI_NC_OFFSET 0 +#define HEBI_NC_SIZE 2 +#define HEBI_NR_OFFSET 2 +#define HEBI_NR_SIZE 2 +#define HEBI_NB_OFFSET 4 +#define HEBI_NB_SIZE 1 +#define HEBI_CAS_OFFSET 5 +#define HEBI_CAS_SIZE 2 +#define HEBI_SDRAMC_CR_DBW_OFFSET 7 +#define HEBI_SDRAMC_CR_DBW_SIZE 1 +#define HEBI_TWR_OFFSET 8 +#define HEBI_TWR_SIZE 4 +#define HEBI_TRC_OFFSET 12 +#define HEBI_TRC_SIZE 4 +#define HEBI_TRP_OFFSET 16 +#define HEBI_TRP_SIZE 4 +#define HEBI_TRCD_OFFSET 20 +#define HEBI_TRCD_SIZE 4 +#define HEBI_TRAS_OFFSET 24 +#define HEBI_TRAS_SIZE 4 +#define HEBI_TXSR_OFFSET 28 +#define HEBI_TXSR_SIZE 4 + +/* Bitfields in SDRAMC_HSR */ +#define HEBI_DA_OFFSET 0 +#define HEBI_DA_SIZE 1 + +/* Bitfields in SDRAMC_LPR */ +#define HEBI_LPCB_OFFSET 0 +#define HEBI_LPCB_SIZE 2 +#define HEBI_PASR_OFFSET 4 +#define HEBI_PASR_SIZE 3 +#define HEBI_TCSR_OFFSET 8 +#define HEBI_TCSR_SIZE 2 +#define HEBI_DS_OFFSET 10 +#define HEBI_DS_SIZE 2 +#define HEBI_TIMEOUT_OFFSET 12 +#define HEBI_TIMEOUT_SIZE 2 + +/* Bitfields in SDRAMC_IER */ + +/* Bitfields in SDRAMC_IDR */ +#define HEBI_RES_OFFSET 0 +#define HEBI_RES_SIZE 1 + +/* Bitfields in SDRAMC_IMR */ + +/* Bitfields in SDRAMC_ISR */ + +/* Bitfields in SDRAMC_MDR */ +#define HEBI_MD_OFFSET 0 +#define HEBI_MD_SIZE 2 + +/* Bitfields in ECC_CR */ +#define HEBI_RST_OFFSET 0 +#define HEBI_RST_SIZE 1 + +/* Bitfields in ECC_MR */ +#define HEBI_PAGESIZE_OFFSET 0 +#define HEBI_PAGESIZE_SIZE 2 + +/* Bitfields in ECC_SR */ +#define HEBI_RECERR_OFFSET 0 +#define HEBI_RECERR_SIZE 1 +#define HEBI_ECCERR_OFFSET 1 +#define HEBI_ECCERR_SIZE 1 +#define HEBI_MULERR_OFFSET 2 +#define HEBI_MULERR_SIZE 1 + +/* Bitfields in ECC_PR */ +#define HEBI_BITADDR_OFFSET 0 +#define HEBI_BITADDR_SIZE 4 +#define HEBI_WORDADDR_OFFSET 4 +#define HEBI_WORDADDR_SIZE 12 + +/* Bitfields in ECC_NPR */ + +/* Constants for EXNW_MODE */ +#define HEBI_EXNW_MODE_DISABLED 0 +#define HEBI_EXNW_MODE_FROZEN 2 +#define HEBI_EXNW_MODE_READY 3 + +/* Constants for DBW */ +#define HEBI_SMC_MODE0_DBW_8_BITS 0 +#define HEBI_SMC_MODE0_DBW_16_BITS 1 +#define HEBI_SMC_MODE0_DBW_32_BITS 2 + +/* Constants for DBW */ +#define HEBI_SMC_MODE1_DBW_8_BITS 0 +#define HEBI_SMC_MODE1_DBW_16_BITS 1 +#define HEBI_SMC_MODE1_DBW_32_BITS 2 + +/* Constants for DBW */ +#define HEBI_SMC_MODE2_DBW_8_BITS 0 +#define HEBI_SMC_MODE2_DBW_16_BITS 1 +#define HEBI_SMC_MODE2_DBW_32_BITS 2 + +/* Constants for DBW */ +#define HEBI_SMC_MODE3_DBW_8_BITS 0 +#define HEBI_SMC_MODE3_DBW_16_BITS 1 +#define HEBI_SMC_MODE3_DBW_32_BITS 2 + +/* Constants for DBW */ +#define HEBI_SMC_MODE4_DBW_8_BITS 0 +#define HEBI_SMC_MODE4_DBW_16_BITS 1 +#define HEBI_SMC_MODE4_DBW_32_BITS 2 + +/* Constants for DBW */ +#define HEBI_SMC_MODE5_DBW_8_BITS 0 +#define HEBI_SMC_MODE5_DBW_16_BITS 1 +#define HEBI_SMC_MODE5_DBW_32_BITS 2 + +/* Constants for MODE */ +#define HEBI_MODE_NORMAL 0 +#define HEBI_MODE_NOP 1 +#define HEBI_MODE_PRECHARGE 2 +#define HEBI_MODE_LOAD_MODE 3 +#define HEBI_MODE_AUTO_REFRESH 4 +#define HEBI_MODE_EXTENDED_LOAD_MODE 5 +#define HEBI_MODE_POWER_DOWN 6 + +/* Constants for NC */ +#define HEBI_NC_8_BITS 0 +#define HEBI_NC_9_BITS 1 +#define HEBI_NC_10_BITS 2 +#define HEBI_NC_11_BITS 3 + +/* Constants for NR */ +#define HEBI_NR_11_BITS 0 +#define HEBI_NR_12_BITS 1 +#define HEBI_NR_13_BITS 2 + +/* Constants for CAS */ +#define HEBI_CAS_1_CYCLE 1 +#define HEBI_CAS_2_CYCLES 2 + +/* Constants for LPCB */ +#define HEBI_LPCB_LOW_POWER 0 +#define HEBI_LPCB_SELF_REFRESH 1 +#define HEBI_LPCB_POWER_DOWN 2 +#define HEBI_LPCB_DEPP_POWER_DOWN 3 + +/* Constants for TIMEOUT */ +#define HEBI_TIMEOUT_IMMEDIATELY 0 +#define HEBI_TIMEOUT_64_CYCLES 1 +#define HEBI_TIMEOUT_128_CYCLES 2 + +/* Constants for MD */ +#define HEBI_MD_SDRAM 0 +#define HEBI_MD_LOW_POWER_SDRAM 1 + +/* Bit manipulation macros */ +#define HEBI_BIT(name) (1 << HEBI_##name##_OFFSET) +#define HEBI_BF(name,value) (((value) & ((1 << HEBI_##name##_SIZE) - 1)) << HEBI_##name##_OFFSET) +#define HEBI_BFEXT(name,value) (((value) >> HEBI_##name##_OFFSET) & ((1 << HEBI_##name##_SIZE) - 1)) +#define HEBI_BFINS(name,value,old) (((old) & ~(((1 << HEBI_##name##_SIZE) - 1) << HEBI_##name##_OFFSET)) | HEBI_BF(name,value)) + +/* Register access macros */ +#define hebi_readl(port,reg) readl((port)->regs + HEBI_##reg) +#define hebi_writel(port,reg,value) writel((value), (port)->regs + HEBI_##reg) + +#endif /* __ASM_AVR32_HEBI_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/periph/hmatrix2.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/hmatrix2.h --- linux-2.6.16.11/include/asm-avr32/periph/hmatrix2.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/hmatrix2.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,372 @@ +/* + * Register definitions for HMATRIX2 + * + * AHB Matrix + */ +#ifndef __ASM_AVR32_HMATRIX2_H__ +#define __ASM_AVR32_HMATRIX2_H__ + +/* HMATRIX2 register offsets */ +#define HMATRIX2_MCFG0 0x0000 +#define HMATRIX2_MCFG1 0x0004 +#define HMATRIX2_MCFG2 0x0008 +#define HMATRIX2_MCFG3 0x000c +#define HMATRIX2_MCFG4 0x0010 +#define HMATRIX2_MCFG5 0x0014 +#define HMATRIX2_MCFG6 0x0018 +#define HMATRIX2_MCFG7 0x001c +#define HMATRIX2_MCFG8 0x0020 +#define HMATRIX2_MCFG9 0x0024 +#define HMATRIX2_MCFG10 0x0028 +#define HMATRIX2_MCFG11 0x002c +#define HMATRIX2_MCFG12 0x0030 +#define HMATRIX2_MCFG13 0x0034 +#define HMATRIX2_MCFG14 0x0038 +#define HMATRIX2_MCFG15 0x003c +#define HMATRIX2_SCFG0 0x0040 +#define HMATRIX2_SCFG1 0x0044 +#define HMATRIX2_SCFG2 0x0048 +#define HMATRIX2_SCFG3 0x004c +#define HMATRIX2_SCFG4 0x0050 +#define HMATRIX2_SCFG5 0x0054 +#define HMATRIX2_SCFG6 0x0058 +#define HMATRIX2_SCFG7 0x005c +#define HMATRIX2_SCFG8 0x0060 +#define HMATRIX2_SCFG9 0x0064 +#define HMATRIX2_SCFG10 0x0068 +#define HMATRIX2_SCFG11 0x006c +#define HMATRIX2_SCFG12 0x0070 +#define HMATRIX2_SCFG13 0x0074 +#define HMATRIX2_SCFG14 0x0078 +#define HMATRIX2_SCFG15 0x007c +#define HMATRIX2_PRAS 0x0080 +#define HMATRIX2_PRBS 0x0084 +#define HMATRIX2_PRAS1 0x0088 +#define HMATRIX2_PRBS1 0x008c +#define HMATRIX2_PRAS2 0x0090 +#define HMATRIX2_PRBS2 0x0094 +#define HMATRIX2_PRAS3 0x0098 +#define HMATRIX2_PRBS3 0x009c +#define HMATRIX2_PRAS4 0x00a0 +#define HMATRIX2_PRBS4 0x00a4 +#define HMATRIX2_PRAS5 0x00a8 +#define HMATRIX2_PRBS5 0x00ac +#define HMATRIX2_PRAS6 0x00b0 +#define HMATRIX2_PRBS6 0x00b4 +#define HMATRIX2_PRAS7 0x00b8 +#define HMATRIX2_PRBS7 0x00bc +#define HMATRIX2_PRAS8 0x00c0 +#define HMATRIX2_PRBS8 0x00c4 +#define HMATRIX2_PRAS9 0x00c8 +#define HMATRIX2_PRBS9 0x00cc +#define HMATRIX2_PRAS10 0x00d0 +#define HMATRIX2_PRBS10 0x00d4 +#define HMATRIX2_PRAS11 0x00d8 +#define HMATRIX2_PRBS11 0x00dc +#define HMATRIX2_PRAS12 0x00e0 +#define HMATRIX2_PRBS12 0x00e4 +#define HMATRIX2_PRAS13 0x00e8 +#define HMATRIX2_PRBS13 0x00ec +#define HMATRIX2_PRAS14 0x00f0 +#define HMATRIX2_PRBS14 0x00f4 +#define HMATRIX2_PRAS15 0x00f8 +#define HMATRIX2_PRBS15 0x00fc +#define HMATRIX2_MRCR 0x0100 +#define HMATRIX2_SFR0 0x0110 +#define HMATRIX2_SFR1 0x0114 +#define HMATRIX2_SFR2 0x0118 +#define HMATRIX2_SFR3 0x011c +#define HMATRIX2_SFR4 0x0120 +#define HMATRIX2_SFR5 0x0124 +#define HMATRIX2_SFR6 0x0128 +#define HMATRIX2_SFR7 0x012c +#define HMATRIX2_SFR8 0x0130 +#define HMATRIX2_SFR9 0x0134 +#define HMATRIX2_SFR10 0x0138 +#define HMATRIX2_SFR11 0x013c +#define HMATRIX2_SFR12 0x0140 +#define HMATRIX2_SFR13 0x0144 +#define HMATRIX2_SFR14 0x0148 +#define HMATRIX2_SFR15 0x014c +#define HMATRIX2_VERSION 0x01fc + +/* Bitfields in MCFG0 */ +#define HMATRIX2_ULBT_OFFSET 0 +#define HMATRIX2_ULBT_SIZE 3 + +/* Bitfields in MCFG1 */ + +/* Bitfields in MCFG2 */ + +/* Bitfields in MCFG3 */ + +/* Bitfields in MCFG4 */ + +/* Bitfields in MCFG5 */ + +/* Bitfields in MCFG6 */ + +/* Bitfields in MCFG7 */ + +/* Bitfields in MCFG8 */ + +/* Bitfields in MCFG9 */ + +/* Bitfields in MCFG10 */ + +/* Bitfields in MCFG11 */ + +/* Bitfields in MCFG12 */ + +/* Bitfields in MCFG13 */ + +/* Bitfields in MCFG14 */ + +/* Bitfields in MCFG15 */ + +/* Bitfields in SCFG0 */ +#define HMATRIX2_SLOT_CYCLE_OFFSET 0 +#define HMATRIX2_SLOT_CYCLE_SIZE 8 +#define HMATRIX2_DEFMSTR_TYPE_OFFSET 16 +#define HMATRIX2_DEFMSTR_TYPE_SIZE 2 +#define HMATRIX2_FIXED_DEFMSTR_OFFSET 18 +#define HMATRIX2_FIXED_DEFMSTR_SIZE 4 +#define HMATRIX2_ARBT_OFFSET 24 +#define HMATRIX2_ARBT_SIZE 2 + +/* Bitfields in SCFG1 */ + +/* Bitfields in SCFG2 */ + +/* Bitfields in SCFG3 */ + +/* Bitfields in SCFG4 */ + +/* Bitfields in SCFG5 */ + +/* Bitfields in SCFG6 */ + +/* Bitfields in SCFG7 */ + +/* Bitfields in SCFG8 */ + +/* Bitfields in SCFG9 */ + +/* Bitfields in SCFG10 */ + +/* Bitfields in SCFG11 */ + +/* Bitfields in SCFG12 */ + +/* Bitfields in SCFG13 */ + +/* Bitfields in SCFG14 */ + +/* Bitfields in SCFG15 */ + +/* Bitfields in PRAS */ +#define HMATRIX2_M0PR_OFFSET 0 +#define HMATRIX2_M0PR_SIZE 4 +#define HMATRIX2_M1PR_OFFSET 4 +#define HMATRIX2_M1PR_SIZE 4 +#define HMATRIX2_M2PR_OFFSET 8 +#define HMATRIX2_M2PR_SIZE 4 +#define HMATRIX2_M3PR_OFFSET 12 +#define HMATRIX2_M3PR_SIZE 4 +#define HMATRIX2_M4PR_OFFSET 16 +#define HMATRIX2_M4PR_SIZE 4 +#define HMATRIX2_M5PR_OFFSET 20 +#define HMATRIX2_M5PR_SIZE 4 +#define HMATRIX2_M6PR_OFFSET 24 +#define HMATRIX2_M6PR_SIZE 4 +#define HMATRIX2_M7PR_OFFSET 28 +#define HMATRIX2_M7PR_SIZE 4 + +/* Bitfields in PRBS */ +#define HMATRIX2_M8PR_OFFSET 0 +#define HMATRIX2_M8PR_SIZE 4 +#define HMATRIX2_M9PR_OFFSET 4 +#define HMATRIX2_M9PR_SIZE 4 +#define HMATRIX2_M10PR_OFFSET 8 +#define HMATRIX2_M10PR_SIZE 4 +#define HMATRIX2_M11PR_OFFSET 12 +#define HMATRIX2_M11PR_SIZE 4 +#define HMATRIX2_M12PR_OFFSET 16 +#define HMATRIX2_M12PR_SIZE 4 +#define HMATRIX2_M13PR_OFFSET 20 +#define HMATRIX2_M13PR_SIZE 4 +#define HMATRIX2_M14PR_OFFSET 24 +#define HMATRIX2_M14PR_SIZE 4 +#define HMATRIX2_M15PR_OFFSET 28 +#define HMATRIX2_M15PR_SIZE 4 + +/* Bitfields in PRAS1 */ + +/* Bitfields in PRBS1 */ + +/* Bitfields in PRAS2 */ + +/* Bitfields in PRBS2 */ + +/* Bitfields in PRAS3 */ + +/* Bitfields in PRBS3 */ + +/* Bitfields in PRAS4 */ + +/* Bitfields in PRBS4 */ + +/* Bitfields in PRAS5 */ + +/* Bitfields in PRBS5 */ + +/* Bitfields in PRAS6 */ + +/* Bitfields in PRBS6 */ + +/* Bitfields in PRAS7 */ + +/* Bitfields in PRBS7 */ + +/* Bitfields in PRAS8 */ + +/* Bitfields in PRBS8 */ + +/* Bitfields in PRAS9 */ + +/* Bitfields in PRBS9 */ + +/* Bitfields in PRAS10 */ + +/* Bitfields in PRBS10 */ + +/* Bitfields in PRAS11 */ + +/* Bitfields in PRBS11 */ + +/* Bitfields in PRAS12 */ + +/* Bitfields in PRBS12 */ + +/* Bitfields in PRAS13 */ + +/* Bitfields in PRBS13 */ + +/* Bitfields in PRAS14 */ + +/* Bitfields in PRBS14 */ + +/* Bitfields in PRAS15 */ + +/* Bitfields in PRBS15 */ + +/* Bitfields in MRCR */ +#define HMATRIX2_RBC0_OFFSET 0 +#define HMATRIX2_RBC0_SIZE 1 +#define HMATRIX2_RBC1_OFFSET 1 +#define HMATRIX2_RBC1_SIZE 1 +#define HMATRIX2_RBC2_OFFSET 2 +#define HMATRIX2_RBC2_SIZE 1 +#define HMATRIX2_RBC3_OFFSET 3 +#define HMATRIX2_RBC3_SIZE 1 +#define HMATRIX2_RBC4_OFFSET 4 +#define HMATRIX2_RBC4_SIZE 1 +#define HMATRIX2_RBC5_OFFSET 5 +#define HMATRIX2_RBC5_SIZE 1 +#define HMATRIX2_RBC6_OFFSET 6 +#define HMATRIX2_RBC6_SIZE 1 +#define HMATRIX2_RBC7_OFFSET 7 +#define HMATRIX2_RBC7_SIZE 1 +#define HMATRIX2_RBC8_OFFSET 8 +#define HMATRIX2_RBC8_SIZE 1 +#define HMATRIX2_RBC9_OFFSET 9 +#define HMATRIX2_RBC9_SIZE 1 +#define HMATRIX2_RBC10_OFFSET 10 +#define HMATRIX2_RBC10_SIZE 1 +#define HMATRIX2_RBC11_OFFSET 11 +#define HMATRIX2_RBC11_SIZE 1 +#define HMATRIX2_RBC12_OFFSET 12 +#define HMATRIX2_RBC12_SIZE 1 +#define HMATRIX2_RBC13_OFFSET 13 +#define HMATRIX2_RBC13_SIZE 1 +#define HMATRIX2_RBC14_OFFSET 14 +#define HMATRIX2_RBC14_SIZE 1 +#define HMATRIX2_RBC15_OFFSET 15 +#define HMATRIX2_RBC15_SIZE 1 + +/* Bitfields in SFR0 */ +#define HMATRIX2_SFR_OFFSET 0 +#define HMATRIX2_SFR_SIZE 32 + +/* Bitfields in SFR1 */ + +/* Bitfields in SFR2 */ + +/* Bitfields in SFR3 */ + +/* Bitfields in SFR4 */ +#define HMATRIX2_CS1A_OFFSET 1 +#define HMATRIX2_CS1A_SIZE 1 +#define HMATRIX2_CS3A_OFFSET 3 +#define HMATRIX2_CS3A_SIZE 1 +#define HMATRIX2_CS4A_OFFSET 4 +#define HMATRIX2_CS4A_SIZE 1 +#define HMATRIX2_CS5A_OFFSET 5 +#define HMATRIX2_CS5A_SIZE 1 +#define HMATRIX2_DBPUC_OFFSET 8 +#define HMATRIX2_DBPUC_SIZE 1 + +/* Bitfields in SFR5 */ + +/* Bitfields in SFR6 */ + +/* Bitfields in SFR7 */ + +/* Bitfields in SFR8 */ + +/* Bitfields in SFR9 */ + +/* Bitfields in SFR10 */ + +/* Bitfields in SFR11 */ + +/* Bitfields in SFR12 */ + +/* Bitfields in SFR13 */ + +/* Bitfields in SFR14 */ + +/* Bitfields in SFR15 */ + +/* Bitfields in VERSION */ +#define HMATRIX2_VERSION_OFFSET 0 +#define HMATRIX2_VERSION_SIZE 12 +#define HMATRIX2_MFN_OFFSET 16 +#define HMATRIX2_MFN_SIZE 3 + +/* Constants for ULBT */ +#define HMATRIX2_ULBT_INFINITE 0 +#define HMATRIX2_ULBT_SINGLE 1 +#define HMATRIX2_ULBT_FOUR_BEAT 2 +#define HMATRIX2_ULBT_SIXTEEN_BEAT 4 + +/* Constants for DEFMSTR_TYPE */ +#define HMATRIX2_DEFMSTR_TYPE_NO_DEFAULT 0 +#define HMATRIX2_DEFMSTR_TYPE_LAST_DEFAULT 1 +#define HMATRIX2_DEFMSTR_TYPE_FIXED_DEFAULT 2 + +/* Constants for ARBT */ +#define HMATRIX2_ARBT_ROUND_ROBIN 0 +#define HMATRIX2_ARBT_FIXED_PRIORITY 1 + +/* Bit manipulation macros */ +#define HMATRIX2_BIT(name) (1 << HMATRIX2_##name##_OFFSET) +#define HMATRIX2_BF(name,value) (((value) & ((1 << HMATRIX2_##name##_SIZE) - 1)) << HMATRIX2_##name##_OFFSET) +#define HMATRIX2_BFEXT(name,value) (((value) >> HMATRIX2_##name##_OFFSET) & ((1 << HMATRIX2_##name##_SIZE) - 1)) +#define HMATRIX2_BFINS(name,value,old) (((old) & ~(((1 << HMATRIX2_##name##_SIZE) - 1) << HMATRIX2_##name##_OFFSET)) | HMATRIX2_BF(name,value)) + +/* Register access macros */ +#define hmatrix2_readl(port,reg) readl((port)->regs + HMATRIX2_##reg) +#define hmatrix2_writel(port,reg,value) writel((value), (port)->regs + HMATRIX2_##reg) + +#endif /* __ASM_AVR32_HMATRIX2_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/periph/hsdramc1.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/hsdramc1.h --- linux-2.6.16.11/include/asm-avr32/periph/hsdramc1.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/hsdramc1.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,141 @@ +/* + * Register definitions for HSDRAMC1 + * + * SDRAM Controller + */ +#ifndef __ASM_AVR32_PERIPH_HSDRAMC1_H__ +#define __ASM_AVR32_PERIPH_HSDRAMC1_H__ + +/* HSDRAMC1 register offsets */ +#define HSDRAMC1_SDRAMC_MR 0x0000 +#define HSDRAMC1_SDRAMC_TR 0x0004 +#define HSDRAMC1_SDRAMC_CR 0x0008 +#define HSDRAMC1_SDRAMC_HSR 0x000c +#define HSDRAMC1_SDRAMC_LPR 0x0010 +#define HSDRAMC1_SDRAMC_IER 0x0014 +#define HSDRAMC1_SDRAMC_IDR 0x0018 +#define HSDRAMC1_SDRAMC_IMR 0x001c +#define HSDRAMC1_SDRAMC_ISR 0x0020 +#define HSDRAMC1_SDRAMC_MDR 0x0024 +#define HSDRAMC1_SDRAMC_VERSION 0x00fc + +/* Bitfields in SDRAMC_MR */ +#define HSDRAMC1_MODE_OFFSET 0 +#define HSDRAMC1_MODE_SIZE 3 + +/* Bitfields in SDRAMC_TR */ +#define HSDRAMC1_COUNT_OFFSET 0 +#define HSDRAMC1_COUNT_SIZE 12 + +/* Bitfields in SDRAMC_CR */ +#define HSDRAMC1_NC_OFFSET 0 +#define HSDRAMC1_NC_SIZE 2 +#define HSDRAMC1_NR_OFFSET 2 +#define HSDRAMC1_NR_SIZE 2 +#define HSDRAMC1_NB_OFFSET 4 +#define HSDRAMC1_NB_SIZE 1 +#define HSDRAMC1_CAS_OFFSET 5 +#define HSDRAMC1_CAS_SIZE 2 +#define HSDRAMC1_DBW_OFFSET 7 +#define HSDRAMC1_DBW_SIZE 1 +#define HSDRAMC1_TWR_OFFSET 8 +#define HSDRAMC1_TWR_SIZE 4 +#define HSDRAMC1_TRC_OFFSET 12 +#define HSDRAMC1_TRC_SIZE 4 +#define HSDRAMC1_TRP_OFFSET 16 +#define HSDRAMC1_TRP_SIZE 4 +#define HSDRAMC1_TRCD_OFFSET 20 +#define HSDRAMC1_TRCD_SIZE 4 +#define HSDRAMC1_TRAS_OFFSET 24 +#define HSDRAMC1_TRAS_SIZE 4 +#define HSDRAMC1_TXSR_OFFSET 28 +#define HSDRAMC1_TXSR_SIZE 4 + +/* Bitfields in SDRAMC_HSR */ +#define HSDRAMC1_DA_OFFSET 0 +#define HSDRAMC1_DA_SIZE 1 + +/* Bitfields in SDRAMC_LPR */ +#define HSDRAMC1_LPCB_OFFSET 0 +#define HSDRAMC1_LPCB_SIZE 2 +#define HSDRAMC1_PASR_OFFSET 4 +#define HSDRAMC1_PASR_SIZE 3 +#define HSDRAMC1_TCSR_OFFSET 8 +#define HSDRAMC1_TCSR_SIZE 2 +#define HSDRAMC1_DS_OFFSET 10 +#define HSDRAMC1_DS_SIZE 2 +#define HSDRAMC1_TIMEOUT_OFFSET 12 +#define HSDRAMC1_TIMEOUT_SIZE 2 + +/* Bitfields in SDRAMC_IER */ + +/* Bitfields in SDRAMC_IDR */ +#define HSDRAMC1_RES_OFFSET 0 +#define HSDRAMC1_RES_SIZE 1 + +/* Bitfields in SDRAMC_IMR */ + +/* Bitfields in SDRAMC_ISR */ + +/* Bitfields in SDRAMC_MDR */ +#define HSDRAMC1_MD_OFFSET 0 +#define HSDRAMC1_MD_SIZE 2 + +/* Bitfields in SDRAMC_VERSION */ +#define HSDRAMC1_VERSION_OFFSET 0 +#define HSDRAMC1_VERSION_SIZE 12 +#define HSDRAMC1_MFN_OFFSET 16 +#define HSDRAMC1_MFN_SIZE 3 + +/* Constants for MODE */ +#define HSDRAMC1_MODE_NORMAL 0 +#define HSDRAMC1_MODE_NOP 1 +#define HSDRAMC1_MODE_BANKS_PRECHARGE 2 +#define HSDRAMC1_MODE_LOAD_MODE 3 +#define HSDRAMC1_MODE_AUTO_REFRESH 4 +#define HSDRAMC1_MODE_EXT_LOAD_MODE 5 +#define HSDRAMC1_MODE_POWER_DOWN 6 + +/* Constants for NC */ +#define HSDRAMC1_NC_8_COLUMN_BITS 0 +#define HSDRAMC1_NC_9_COLUMN_BITS 1 +#define HSDRAMC1_NC_10_COLUMN_BITS 2 +#define HSDRAMC1_NC_11_COLUMN_BITS 3 + +/* Constants for NR */ +#define HSDRAMC1_NR_11_ROW_BITS 0 +#define HSDRAMC1_NR_12_ROW_BITS 1 +#define HSDRAMC1_NR_13_ROW_BITS 2 + +/* Constants for NB */ +#define HSDRAMC1_NB_TWO_BANKS 0 +#define HSDRAMC1_NB_FOUR_BANKS 1 + +/* Constants for CAS */ +#define HSDRAMC1_CAS_ONE_CYCLE 1 +#define HSDRAMC1_CAS_TWO_CYCLES 2 + +/* Constants for DBW */ +#define HSDRAMC1_DBW_32_BITS 0 +#define HSDRAMC1_DBW_16_BITS 1 + +/* Constants for TIMEOUT */ +#define HSDRAMC1_TIMEOUT_AFTER_END 0 +#define HSDRAMC1_TIMEOUT_64_CYC_AFTER_END 1 +#define HSDRAMC1_TIMEOUT_128_CYC_AFTER_END 2 + +/* Constants for MD */ +#define HSDRAMC1_MD_SDRAM 0 +#define HSDRAMC1_MD_LOW_POWER_SDRAM 1 + +/* Bit manipulation macros */ +#define HSDRAMC1_BIT(name) (1 << HSDRAMC1_##name##_OFFSET) +#define HSDRAMC1_BF(name,value) (((value) & ((1 << HSDRAMC1_##name##_SIZE) - 1)) << HSDRAMC1_##name##_OFFSET) +#define HSDRAMC1_BFEXT(name,value) (((value) >> HSDRAMC1_##name##_OFFSET) & ((1 << HSDRAMC1_##name##_SIZE) - 1)) +#define HSDRAMC1_BFINS(name,value,old) (((old) & ~(((1 << HSDRAMC1_##name##_SIZE) - 1) << HSDRAMC1_##name##_OFFSET)) | HSDRAMC1_BF(name,value)) + +/* Register access macros */ +#define hsdramc1_readl(port,reg) readl((port)->regs + HSDRAMC1_##reg) +#define hsdramc1_writel(port,reg,value) writel((value), (port)->regs + HSDRAMC1_##reg) + +#endif /* __ASM_AVR32_PERIPH_HSDRAMC1_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/periph/intc.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/intc.h --- linux-2.6.16.11/include/asm-avr32/periph/intc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/intc.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,327 @@ +/* + * Automatically generated by gen-header.xsl + */ +#ifndef __ASM_AVR32_PERIHP_INTC_H__ +#define __ASM_AVR32_PERIHP_INTC_H__ + +#define INTC_NUM_INT_GRPS 33 + +#define INTC_INTPR0 0x0 +# define INTC_INTPR0_INTLEV_OFFSET 30 +# define INTC_INTPR0_INTLEV_SIZE 2 +# define INTC_INTPR0_OFFSET_OFFSET 0 +# define INTC_INTPR0_OFFSET_SIZE 24 +#define INTC_INTREQ0 0x100 +# define INTC_INTREQ0_IREQUEST0_OFFSET 0 +# define INTC_INTREQ0_IREQUEST0_SIZE 1 +# define INTC_INTREQ0_IREQUEST1_OFFSET 1 +# define INTC_INTREQ0_IREQUEST1_SIZE 1 +#define INTC_INTPR1 0x4 +# define INTC_INTPR1_INTLEV_OFFSET 30 +# define INTC_INTPR1_INTLEV_SIZE 2 +# define INTC_INTPR1_OFFSET_OFFSET 0 +# define INTC_INTPR1_OFFSET_SIZE 24 +#define INTC_INTREQ1 0x104 +# define INTC_INTREQ1_IREQUEST32_OFFSET 0 +# define INTC_INTREQ1_IREQUEST32_SIZE 1 +# define INTC_INTREQ1_IREQUEST33_OFFSET 1 +# define INTC_INTREQ1_IREQUEST33_SIZE 1 +# define INTC_INTREQ1_IREQUEST34_OFFSET 2 +# define INTC_INTREQ1_IREQUEST34_SIZE 1 +# define INTC_INTREQ1_IREQUEST35_OFFSET 3 +# define INTC_INTREQ1_IREQUEST35_SIZE 1 +# define INTC_INTREQ1_IREQUEST36_OFFSET 4 +# define INTC_INTREQ1_IREQUEST36_SIZE 1 +# define INTC_INTREQ1_IREQUEST37_OFFSET 5 +# define INTC_INTREQ1_IREQUEST37_SIZE 1 +#define INTC_INTPR2 0x8 +# define INTC_INTPR2_INTLEV_OFFSET 30 +# define INTC_INTPR2_INTLEV_SIZE 2 +# define INTC_INTPR2_OFFSET_OFFSET 0 +# define INTC_INTPR2_OFFSET_SIZE 24 +#define INTC_INTREQ2 0x108 +# define INTC_INTREQ2_IREQUEST64_OFFSET 0 +# define INTC_INTREQ2_IREQUEST64_SIZE 1 +# define INTC_INTREQ2_IREQUEST65_OFFSET 1 +# define INTC_INTREQ2_IREQUEST65_SIZE 1 +# define INTC_INTREQ2_IREQUEST66_OFFSET 2 +# define INTC_INTREQ2_IREQUEST66_SIZE 1 +# define INTC_INTREQ2_IREQUEST67_OFFSET 3 +# define INTC_INTREQ2_IREQUEST67_SIZE 1 +# define INTC_INTREQ2_IREQUEST68_OFFSET 4 +# define INTC_INTREQ2_IREQUEST68_SIZE 1 +#define INTC_INTPR3 0xc +# define INTC_INTPR3_INTLEV_OFFSET 30 +# define INTC_INTPR3_INTLEV_SIZE 2 +# define INTC_INTPR3_OFFSET_OFFSET 0 +# define INTC_INTPR3_OFFSET_SIZE 24 +#define INTC_INTREQ3 0x10c +# define INTC_INTREQ3_IREQUEST96_OFFSET 0 +# define INTC_INTREQ3_IREQUEST96_SIZE 1 +#define INTC_INTPR4 0x10 +# define INTC_INTPR4_INTLEV_OFFSET 30 +# define INTC_INTPR4_INTLEV_SIZE 2 +# define INTC_INTPR4_OFFSET_OFFSET 0 +# define INTC_INTPR4_OFFSET_SIZE 24 +#define INTC_INTREQ4 0x110 +# define INTC_INTREQ4_IREQUEST128_OFFSET 0 +# define INTC_INTREQ4_IREQUEST128_SIZE 1 +#define INTC_INTPR5 0x14 +# define INTC_INTPR5_INTLEV_OFFSET 30 +# define INTC_INTPR5_INTLEV_SIZE 2 +# define INTC_INTPR5_OFFSET_OFFSET 0 +# define INTC_INTPR5_OFFSET_SIZE 24 +#define INTC_INTREQ5 0x114 +# define INTC_INTREQ5_IREQUEST160_OFFSET 0 +# define INTC_INTREQ5_IREQUEST160_SIZE 1 +#define INTC_INTPR6 0x18 +# define INTC_INTPR6_INTLEV_OFFSET 30 +# define INTC_INTPR6_INTLEV_SIZE 2 +# define INTC_INTPR6_OFFSET_OFFSET 0 +# define INTC_INTPR6_OFFSET_SIZE 24 +#define INTC_INTREQ6 0x118 +# define INTC_INTREQ6_IREQUEST192_OFFSET 0 +# define INTC_INTREQ6_IREQUEST192_SIZE 1 +#define INTC_INTPR7 0x1c +# define INTC_INTPR7_INTLEV_OFFSET 30 +# define INTC_INTPR7_INTLEV_SIZE 2 +# define INTC_INTPR7_OFFSET_OFFSET 0 +# define INTC_INTPR7_OFFSET_SIZE 24 +#define INTC_INTREQ7 0x11c +# define INTC_INTREQ7_IREQUEST224_OFFSET 0 +# define INTC_INTREQ7_IREQUEST224_SIZE 1 +#define INTC_INTPR8 0x20 +# define INTC_INTPR8_INTLEV_OFFSET 30 +# define INTC_INTPR8_INTLEV_SIZE 2 +# define INTC_INTPR8_OFFSET_OFFSET 0 +# define INTC_INTPR8_OFFSET_SIZE 24 +#define INTC_INTREQ8 0x120 +# define INTC_INTREQ8_IREQUEST256_OFFSET 0 +# define INTC_INTREQ8_IREQUEST256_SIZE 1 +#define INTC_INTPR9 0x24 +# define INTC_INTPR9_INTLEV_OFFSET 30 +# define INTC_INTPR9_INTLEV_SIZE 2 +# define INTC_INTPR9_OFFSET_OFFSET 0 +# define INTC_INTPR9_OFFSET_SIZE 24 +#define INTC_INTREQ9 0x124 +# define INTC_INTREQ9_IREQUEST288_OFFSET 0 +# define INTC_INTREQ9_IREQUEST288_SIZE 1 +#define INTC_INTPR10 0x28 +# define INTC_INTPR10_INTLEV_OFFSET 30 +# define INTC_INTPR10_INTLEV_SIZE 2 +# define INTC_INTPR10_OFFSET_OFFSET 0 +# define INTC_INTPR10_OFFSET_SIZE 24 +#define INTC_INTREQ10 0x128 +# define INTC_INTREQ10_IREQUEST320_OFFSET 0 +# define INTC_INTREQ10_IREQUEST320_SIZE 1 +#define INTC_INTPR11 0x2c +# define INTC_INTPR11_INTLEV_OFFSET 30 +# define INTC_INTPR11_INTLEV_SIZE 2 +# define INTC_INTPR11_OFFSET_OFFSET 0 +# define INTC_INTPR11_OFFSET_SIZE 24 +#define INTC_INTREQ11 0x12c +# define INTC_INTREQ11_IREQUEST352_OFFSET 0 +# define INTC_INTREQ11_IREQUEST352_SIZE 1 +#define INTC_INTPR12 0x30 +# define INTC_INTPR12_INTLEV_OFFSET 30 +# define INTC_INTPR12_INTLEV_SIZE 2 +# define INTC_INTPR12_OFFSET_OFFSET 0 +# define INTC_INTPR12_OFFSET_SIZE 24 +#define INTC_INTREQ12 0x130 +# define INTC_INTREQ12_IREQUEST384_OFFSET 0 +# define INTC_INTREQ12_IREQUEST384_SIZE 1 +#define INTC_INTPR13 0x34 +# define INTC_INTPR13_INTLEV_OFFSET 30 +# define INTC_INTPR13_INTLEV_SIZE 2 +# define INTC_INTPR13_OFFSET_OFFSET 0 +# define INTC_INTPR13_OFFSET_SIZE 24 +#define INTC_INTREQ13 0x134 +# define INTC_INTREQ13_IREQUEST416_OFFSET 0 +# define INTC_INTREQ13_IREQUEST416_SIZE 1 +#define INTC_INTPR14 0x38 +# define INTC_INTPR14_INTLEV_OFFSET 30 +# define INTC_INTPR14_INTLEV_SIZE 2 +# define INTC_INTPR14_OFFSET_OFFSET 0 +# define INTC_INTPR14_OFFSET_SIZE 24 +#define INTC_INTREQ14 0x138 +# define INTC_INTREQ14_IREQUEST448_OFFSET 0 +# define INTC_INTREQ14_IREQUEST448_SIZE 1 +#define INTC_INTPR15 0x3c +# define INTC_INTPR15_INTLEV_OFFSET 30 +# define INTC_INTPR15_INTLEV_SIZE 2 +# define INTC_INTPR15_OFFSET_OFFSET 0 +# define INTC_INTPR15_OFFSET_SIZE 24 +#define INTC_INTREQ15 0x13c +# define INTC_INTREQ15_IREQUEST480_OFFSET 0 +# define INTC_INTREQ15_IREQUEST480_SIZE 1 +#define INTC_INTPR16 0x40 +# define INTC_INTPR16_INTLEV_OFFSET 30 +# define INTC_INTPR16_INTLEV_SIZE 2 +# define INTC_INTPR16_OFFSET_OFFSET 0 +# define INTC_INTPR16_OFFSET_SIZE 24 +#define INTC_INTREQ16 0x140 +# define INTC_INTREQ16_IREQUEST512_OFFSET 0 +# define INTC_INTREQ16_IREQUEST512_SIZE 1 +#define INTC_INTPR17 0x44 +# define INTC_INTPR17_INTLEV_OFFSET 30 +# define INTC_INTPR17_INTLEV_SIZE 2 +# define INTC_INTPR17_OFFSET_OFFSET 0 +# define INTC_INTPR17_OFFSET_SIZE 24 +#define INTC_INTREQ17 0x144 +# define INTC_INTREQ17_IREQUEST544_OFFSET 0 +# define INTC_INTREQ17_IREQUEST544_SIZE 1 +#define INTC_INTPR18 0x48 +# define INTC_INTPR18_INTLEV_OFFSET 30 +# define INTC_INTPR18_INTLEV_SIZE 2 +# define INTC_INTPR18_OFFSET_OFFSET 0 +# define INTC_INTPR18_OFFSET_SIZE 24 +#define INTC_INTREQ18 0x148 +# define INTC_INTREQ18_IREQUEST576_OFFSET 0 +# define INTC_INTREQ18_IREQUEST576_SIZE 1 +#define INTC_INTPR19 0x4c +# define INTC_INTPR19_INTLEV_OFFSET 30 +# define INTC_INTPR19_INTLEV_SIZE 2 +# define INTC_INTPR19_OFFSET_OFFSET 0 +# define INTC_INTPR19_OFFSET_SIZE 24 +#define INTC_INTREQ19 0x14c +# define INTC_INTREQ19_IREQUEST608_OFFSET 0 +# define INTC_INTREQ19_IREQUEST608_SIZE 1 +# define INTC_INTREQ19_IREQUEST609_OFFSET 1 +# define INTC_INTREQ19_IREQUEST609_SIZE 1 +# define INTC_INTREQ19_IREQUEST610_OFFSET 2 +# define INTC_INTREQ19_IREQUEST610_SIZE 1 +# define INTC_INTREQ19_IREQUEST611_OFFSET 3 +# define INTC_INTREQ19_IREQUEST611_SIZE 1 +#define INTC_INTPR20 0x50 +# define INTC_INTPR20_INTLEV_OFFSET 30 +# define INTC_INTPR20_INTLEV_SIZE 2 +# define INTC_INTPR20_OFFSET_OFFSET 0 +# define INTC_INTPR20_OFFSET_SIZE 24 +#define INTC_INTREQ20 0x150 +# define INTC_INTREQ20_IREQUEST640_OFFSET 0 +# define INTC_INTREQ20_IREQUEST640_SIZE 1 +#define INTC_INTPR21 0x54 +# define INTC_INTPR21_INTLEV_OFFSET 30 +# define INTC_INTPR21_INTLEV_SIZE 2 +# define INTC_INTPR21_OFFSET_OFFSET 0 +# define INTC_INTPR21_OFFSET_SIZE 24 +#define INTC_INTREQ21 0x154 +# define INTC_INTREQ21_IREQUEST672_OFFSET 0 +# define INTC_INTREQ21_IREQUEST672_SIZE 1 +#define INTC_INTPR22 0x58 +# define INTC_INTPR22_INTLEV_OFFSET 30 +# define INTC_INTPR22_INTLEV_SIZE 2 +# define INTC_INTPR22_OFFSET_OFFSET 0 +# define INTC_INTPR22_OFFSET_SIZE 24 +#define INTC_INTREQ22 0x158 +# define INTC_INTREQ22_IREQUEST704_OFFSET 0 +# define INTC_INTREQ22_IREQUEST704_SIZE 1 +# define INTC_INTREQ22_IREQUEST705_OFFSET 1 +# define INTC_INTREQ22_IREQUEST705_SIZE 1 +# define INTC_INTREQ22_IREQUEST706_OFFSET 2 +# define INTC_INTREQ22_IREQUEST706_SIZE 1 +#define INTC_INTPR23 0x5c +# define INTC_INTPR23_INTLEV_OFFSET 30 +# define INTC_INTPR23_INTLEV_SIZE 2 +# define INTC_INTPR23_OFFSET_OFFSET 0 +# define INTC_INTPR23_OFFSET_SIZE 24 +#define INTC_INTREQ23 0x15c +# define INTC_INTREQ23_IREQUEST736_OFFSET 0 +# define INTC_INTREQ23_IREQUEST736_SIZE 1 +# define INTC_INTREQ23_IREQUEST737_OFFSET 1 +# define INTC_INTREQ23_IREQUEST737_SIZE 1 +# define INTC_INTREQ23_IREQUEST738_OFFSET 2 +# define INTC_INTREQ23_IREQUEST738_SIZE 1 +#define INTC_INTPR24 0x60 +# define INTC_INTPR24_INTLEV_OFFSET 30 +# define INTC_INTPR24_INTLEV_SIZE 2 +# define INTC_INTPR24_OFFSET_OFFSET 0 +# define INTC_INTPR24_OFFSET_SIZE 24 +#define INTC_INTREQ24 0x160 +# define INTC_INTREQ24_IREQUEST768_OFFSET 0 +# define INTC_INTREQ24_IREQUEST768_SIZE 1 +#define INTC_INTPR25 0x64 +# define INTC_INTPR25_INTLEV_OFFSET 30 +# define INTC_INTPR25_INTLEV_SIZE 2 +# define INTC_INTPR25_OFFSET_OFFSET 0 +# define INTC_INTPR25_OFFSET_SIZE 24 +#define INTC_INTREQ25 0x164 +# define INTC_INTREQ25_IREQUEST800_OFFSET 0 +# define INTC_INTREQ25_IREQUEST800_SIZE 1 +#define INTC_INTPR26 0x68 +# define INTC_INTPR26_INTLEV_OFFSET 30 +# define INTC_INTPR26_INTLEV_SIZE 2 +# define INTC_INTPR26_OFFSET_OFFSET 0 +# define INTC_INTPR26_OFFSET_SIZE 24 +#define INTC_INTREQ26 0x168 +# define INTC_INTREQ26_IREQUEST832_OFFSET 0 +# define INTC_INTREQ26_IREQUEST832_SIZE 1 +#define INTC_INTPR27 0x6c +# define INTC_INTPR27_INTLEV_OFFSET 30 +# define INTC_INTPR27_INTLEV_SIZE 2 +# define INTC_INTPR27_OFFSET_OFFSET 0 +# define INTC_INTPR27_OFFSET_SIZE 24 +#define INTC_INTREQ27 0x16c +# define INTC_INTREQ27_IREQUEST864_OFFSET 0 +# define INTC_INTREQ27_IREQUEST864_SIZE 1 +#define INTC_INTPR28 0x70 +# define INTC_INTPR28_INTLEV_OFFSET 30 +# define INTC_INTPR28_INTLEV_SIZE 2 +# define INTC_INTPR28_OFFSET_OFFSET 0 +# define INTC_INTPR28_OFFSET_SIZE 24 +#define INTC_INTREQ28 0x170 +# define INTC_INTREQ28_IREQUEST896_OFFSET 0 +# define INTC_INTREQ28_IREQUEST896_SIZE 1 +#define INTC_INTPR29 0x74 +# define INTC_INTPR29_INTLEV_OFFSET 30 +# define INTC_INTPR29_INTLEV_SIZE 2 +# define INTC_INTPR29_OFFSET_OFFSET 0 +# define INTC_INTPR29_OFFSET_SIZE 24 +#define INTC_INTREQ29 0x174 +# define INTC_INTREQ29_IREQUEST928_OFFSET 0 +# define INTC_INTREQ29_IREQUEST928_SIZE 1 +#define INTC_INTPR30 0x78 +# define INTC_INTPR30_INTLEV_OFFSET 30 +# define INTC_INTPR30_INTLEV_SIZE 2 +# define INTC_INTPR30_OFFSET_OFFSET 0 +# define INTC_INTPR30_OFFSET_SIZE 24 +#define INTC_INTREQ30 0x178 +# define INTC_INTREQ30_IREQUEST960_OFFSET 0 +# define INTC_INTREQ30_IREQUEST960_SIZE 1 +#define INTC_INTPR31 0x7c +# define INTC_INTPR31_INTLEV_OFFSET 30 +# define INTC_INTPR31_INTLEV_SIZE 2 +# define INTC_INTPR31_OFFSET_OFFSET 0 +# define INTC_INTPR31_OFFSET_SIZE 24 +#define INTC_INTREQ31 0x17c +# define INTC_INTREQ31_IREQUEST992_OFFSET 0 +# define INTC_INTREQ31_IREQUEST992_SIZE 1 +#define INTC_INTPR32 0x80 +# define INTC_INTPR32_INTLEV_OFFSET 30 +# define INTC_INTPR32_INTLEV_SIZE 2 +# define INTC_INTPR32_OFFSET_OFFSET 0 +# define INTC_INTPR32_OFFSET_SIZE 24 +#define INTC_INTREQ32 0x180 +# define INTC_INTREQ32_IREQUEST1024_OFFSET 0 +# define INTC_INTREQ32_IREQUEST1024_SIZE 1 +#define INTC_INTCAUSE0 0x20c +# define INTC_INTCAUSE0_CAUSEGRP_OFFSET 0 +# define INTC_INTCAUSE0_CAUSEGRP_SIZE 6 +#define INTC_INTCAUSE1 0x208 +# define INTC_INTCAUSE1_CAUSEGRP_OFFSET 0 +# define INTC_INTCAUSE1_CAUSEGRP_SIZE 6 +#define INTC_INTCAUSE2 0x204 +# define INTC_INTCAUSE2_CAUSEGRP_OFFSET 0 +# define INTC_INTCAUSE2_CAUSEGRP_SIZE 6 +#define INTC_INTCAUSE3 0x200 +# define INTC_INTCAUSE3_CAUSEGRP_OFFSET 0 +# define INTC_INTCAUSE3_CAUSEGRP_SIZE 6 + +#define INTC_BIT(name) (1 << INTC_##name##_OFFSET) +#define INTC_MKBF(name, value) (((value) & ((1 << INTC_##name##_SIZE) - 1)) << INTC_##name##_OFFSET) +#define INTC_GETBF(name, value) (((value) >> INTC_##name##_OFFSET) & ((1 << INTC_##name##_SIZE) - 1)) + +#define intc_readl(port,reg) readl((port)->regs + INTC_##reg) +#define intc_writel(port,reg,value) writel((value), (port)->regs + INTC_##reg) + +#endif /* __ASM_AVR32_PERIHP_INTC_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/periph/lcdc.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/lcdc.h --- linux-2.6.16.11/include/asm-avr32/periph/lcdc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/lcdc.h 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,269 @@ +/* + * Register definitions for Atmel/SIDSA LCD Controller + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PERIPH_LCDC_H__ +#define __ASM_AVR32_PERIPH_LCDC_H__ + +#define LCDC_CONTRAST_CTR 0x00000840 +# define LCDC_CONTRAST_CTR_ENA_OFFSET 3 +# define LCDC_CONTRAST_CTR_ENA_SIZE 1 +# define LCDC_CONTRAST_CTR_POL_OFFSET 2 +# define LCDC_CONTRAST_CTR_POL_SIZE 1 +# define LCDC_CONTRAST_CTR_PS_OFFSET 0 +# define LCDC_CONTRAST_CTR_PS_SIZE 2 +#define LCDC_CONTRAST_VAL 0x00000844 +# define LCDC_CONTRAST_VAL_CVAL_OFFSET 0 +# define LCDC_CONTRAST_VAL_CVAL_SIZE 8 +#define LCDC_DMABADDR1 0x00000000 +# define LCDC_DMABADDR1_BADDR_U_OFFSET 0 +# define LCDC_DMABADDR1_BADDR_U_SIZE 32 +#define LCDC_DMABADDR2 0x00000004 +# define LCDC_DMABADDR2_BADDR_L_OFFSET 0 +# define LCDC_DMABADDR2_BADDR_L_SIZE 32 +#define LCDC_DMACON 0x0000001C +# define LCDC_DMACON_DMABUSY_OFFSET 2 +# define LCDC_DMACON_DMABUSY_SIZE 1 +# define LCDC_DMACON_DMAEN_OFFSET 0 +# define LCDC_DMACON_DMAEN_SIZE 1 +# define LCDC_DMACON_DMARST_OFFSET 1 +# define LCDC_DMACON_DMARST_SIZE 1 +# define LCDC_DMACON_DMAUPDT_OFFSET 3 +# define LCDC_DMACON_DMAUPDT_SIZE 1 +# define LCDC_DMACON_DMA2DEN_OFFSET 4 +# define LCDC_DMACON_DMA2DEN_SIZE 1 +#define LCDC_DMAFRMADD1 0x00000010 +# define LCDC_DMAFRMADD1_FRMADD_U_OFFSET 0 +# define LCDC_DMAFRMADD1_FRMADD_U_SIZE 32 +#define LCDC_DMAFRMADD2 0x00000014 +# define LCDC_DMAFRMADD2_FRMADD_L_OFFSET 0 +# define LCDC_DMAFRMADD2_FRMADD_L_SIZE 32 +#define LCDC_DMAFRMCFG 0x00000018 +# define LCDC_DMAFRMCFG_BRSTLEN_OFFSET 24 +# define LCDC_DMAFRMCFG_BRSTLEN_SIZE 7 +# define LCDC_DMAFRMCFG_FRMSIZE_OFFSET 0 +# define LCDC_DMAFRMCFG_FRMSIZE_SIZE 23 +#define LCDC_DMAFRMPT1 0x00000008 +# define LCDC_DMAFRMPT1_FRMPT_U_OFFSET 0 +# define LCDC_DMAFRMPT1_FRMPT_U_SIZE 23 +#define LCDC_DMAFRMPT2 0x0000000C +# define LCDC_DMAFRMPT2_FRMPT_L_OFFSET 0 +# define LCDC_DMAFRMPT2_FRMPT_L_SIZE 23 +#define LCDC_DMA2DCFG 0x00000020 +# define LCDC_DMA2DCFG_ADDRINC_OFFSET 0 +# define LCDC_DMA2DCFG_ADDRINC_SIZE 16 +# define LCDC_DMA2DCFG_PIXELOFF_OFFSET 24 +# define LCDC_DMA2DCFG_PIXELOFF_SIZE 5 +#define LCDC_DP1_2 0x0000081C +# define LCDC_DP1_2_DP1_2_OFFSET 0 +# define LCDC_DP1_2_DP1_2_SIZE 8 +#define LCDC_DP2_3 0x00000828 +# define LCDC_DP2_3_DP2_3_OFFSET 0 +# define LCDC_DP2_3_DP2_3_SIZE 12 +#define LCDC_DP3_4 0x00000830 +# define LCDC_DP3_4_DP3_4_OFFSET 0 +# define LCDC_DP3_4_DP3_4_SIZE 16 +#define LCDC_DP3_5 0x00000824 +# define LCDC_DP3_5_DP3_5_OFFSET 0 +# define LCDC_DP3_5_DP3_5_SIZE 20 +#define LCDC_DP4_5 0x00000834 +# define LCDC_DP4_5_DP4_5_OFFSET 0 +# define LCDC_DP4_5_DP4_5_SIZE 20 +#define LCDC_DP4_7 0x00000820 +# define LCDC_DP4_7_DP4_7_OFFSET 0 +# define LCDC_DP4_7_DP4_7_SIZE 28 +#define LCDC_DP5_7 0x0000082C +# define LCDC_DP5_7_DP5_7_OFFSET 0 +# define LCDC_DP5_7_DP5_7_SIZE 28 +#define LCDC_DP6_7 0x00000838 +# define LCDC_DP6_7_DP6_7_OFFSET 0 +# define LCDC_DP6_7_DP6_7_SIZE 28 +#define LCDC_LCDCON1 0x00000800 +# define LCDC_LCDCON1_BYPASS_OFFSET 0 +# define LCDC_LCDCON1_BYPASS_SIZE 1 +# define LCDC_LCDCON1_CLKVAL_OFFSET 12 +# define LCDC_LCDCON1_CLKVAL_SIZE 9 +# define LCDC_LCDCON1_LINECNT_OFFSET 21 +# define LCDC_LCDCON1_LINECNT_SIZE 11 +#define LCDC_LCDCON2 0x00000804 +# define LCDC_LCDCON2_CLKMOD_OFFSET 15 +# define LCDC_LCDCON2_CLKMOD_SIZE 1 +# define LCDC_LCDCON2_DISTYPE_OFFSET 0 +# define LCDC_LCDCON2_DISTYPE_SIZE 2 +# define LCDC_LCDCON2_IFWIDTH_OFFSET 3 +# define LCDC_LCDCON2_IFWIDTH_SIZE 2 +# define LCDC_LCDCON2_INVCLK_OFFSET 11 +# define LCDC_LCDCON2_INVCLK_SIZE 1 +# define LCDC_LCDCON2_INVDVAL_OFFSET 12 +# define LCDC_LCDCON2_INVDVAL_SIZE 1 +# define LCDC_LCDCON2_INVFRAME_OFFSET 9 +# define LCDC_LCDCON2_INVFRAME_SIZE 1 +# define LCDC_LCDCON2_INVLINE_OFFSET 10 +# define LCDC_LCDCON2_INVLINE_SIZE 1 +# define LCDC_LCDCON2_INVVD_OFFSET 8 +# define LCDC_LCDCON2_INVVD_SIZE 1 +# define LCDC_LCDCON2_MEMOR_OFFSET 30 +# define LCDC_LCDCON2_MEMOR_SIZE 2 +# define LCDC_LCDCON2_PIXELSIZE_OFFSET 5 +# define LCDC_LCDCON2_PIXELSIZE_SIZE 3 +# define LCDC_LCDCON2_SCANMOD_OFFSET 2 +# define LCDC_LCDCON2_SCANMOD_SIZE 1 +#define LCDC_LCDFIFO 0x00000814 +# define LCDC_LCDFIFO_FIFOTH_OFFSET 0 +# define LCDC_LCDFIFO_FIFOTH_SIZE 16 +#define LCDC_LCDFRMCFG 0x00000810 +# define LCDC_LCDFRMCFG_LINESIZE_OFFSET 21 +# define LCDC_LCDFRMCFG_LINESIZE_SIZE 11 +# define LCDC_LCDFRMCFG_LINEVAL_OFFSET 0 +# define LCDC_LCDFRMCFG_LINEVAL_SIZE 11 +#define LCDC_LCDMVAL 0x00000818 +# define LCDC_LCDMVAL_MMODE_OFFSET 31 +# define LCDC_LCDMVAL_MMODE_SIZE 1 +# define LCDC_LCDMVAL_MVAL_OFFSET 0 +# define LCDC_LCDMVAL_MVAL_SIZE 8 +#define LCDC_LCDTIM1 0x00000808 +# define LCDC_LCDTIM1_VBP_OFFSET 8 +# define LCDC_LCDTIM1_VBP_SIZE 8 +# define LCDC_LCDTIM1_VFP_OFFSET 0 +# define LCDC_LCDTIM1_VFP_SIZE 8 +# define LCDC_LCDTIM1_VHDLY_OFFSET 24 +# define LCDC_LCDTIM1_VHDLY_SIZE 4 +# define LCDC_LCDTIM1_VPW_OFFSET 16 +# define LCDC_LCDTIM1_VPW_SIZE 6 +#define LCDC_LCDTIM2 0x0000080C +# define LCDC_LCDTIM2_HBP_OFFSET 0 +# define LCDC_LCDTIM2_HBP_SIZE 8 +# define LCDC_LCDTIM2_HFP_OFFSET 21 +# define LCDC_LCDTIM2_HFP_SIZE 11 +# define LCDC_LCDTIM2_HPW_OFFSET 8 +# define LCDC_LCDTIM2_HPW_SIZE 6 +#define LCDC_LCD_GPR 0x0000085C +# define LCDC_LCD_GPR_GPRB0_OFFSET 0 +# define LCDC_LCD_GPR_GPRB0_SIZE 1 +# define LCDC_LCD_GPR_GPRB1_OFFSET 1 +# define LCDC_LCD_GPR_GPRB1_SIZE 1 +# define LCDC_LCD_GPR_GPRB2_OFFSET 2 +# define LCDC_LCD_GPR_GPRB2_SIZE 1 +# define LCDC_LCD_GPR_GPRB3_OFFSET 3 +# define LCDC_LCD_GPR_GPRB3_SIZE 1 +# define LCDC_LCD_GPR_GPRB4_OFFSET 4 +# define LCDC_LCD_GPR_GPRB4_SIZE 1 +# define LCDC_LCD_GPR_GPRB5_OFFSET 5 +# define LCDC_LCD_GPR_GPRB5_SIZE 1 +# define LCDC_LCD_GPR_GPRB6_OFFSET 6 +# define LCDC_LCD_GPR_GPRB6_SIZE 1 +# define LCDC_LCD_GPR_GPRB7_OFFSET 7 +# define LCDC_LCD_GPR_GPRB7_SIZE 1 +#define LCDC_LCD_ICR 0x00000858 +# define LCDC_LCD_ICR_EOFIC_OFFSET 2 +# define LCDC_LCD_ICR_EOFIC_SIZE 1 +# define LCDC_LCD_ICR_LNIC_OFFSET 0 +# define LCDC_LCD_ICR_LNIC_SIZE 1 +# define LCDC_LCD_ICR_LSTLNIC_OFFSET 1 +# define LCDC_LCD_ICR_LSTLNIC_SIZE 1 +# define LCDC_LCD_ICR_MERIC_OFFSET 6 +# define LCDC_LCD_ICR_MERIC_SIZE 1 +# define LCDC_LCD_ICR_OWRIC_OFFSET 5 +# define LCDC_LCD_ICR_OWRIC_SIZE 1 +# define LCDC_LCD_ICR_UFLWIC_OFFSET 4 +# define LCDC_LCD_ICR_UFLWIC_SIZE 1 +#define LCDC_LCD_IDR 0x0000084C +# define LCDC_LCD_IDR_EOFID_OFFSET 2 +# define LCDC_LCD_IDR_EOFID_SIZE 1 +# define LCDC_LCD_IDR_LNID_OFFSET 0 +# define LCDC_LCD_IDR_LNID_SIZE 1 +# define LCDC_LCD_IDR_LSTLNID_OFFSET 1 +# define LCDC_LCD_IDR_LSTLNID_SIZE 1 +# define LCDC_LCD_IDR_MERID_OFFSET 6 +# define LCDC_LCD_IDR_MERID_SIZE 1 +# define LCDC_LCD_IDR_OWRID_OFFSET 5 +# define LCDC_LCD_IDR_OWRID_SIZE 1 +# define LCDC_LCD_IDR_UFLWID_OFFSET 4 +# define LCDC_LCD_IDR_UFLWID_SIZE 1 +#define LCDC_LCD_IER 0x00000848 +# define LCDC_LCD_IER_EOFIE_OFFSET 2 +# define LCDC_LCD_IER_EOFIE_SIZE 1 +# define LCDC_LCD_IER_LNIE_OFFSET 0 +# define LCDC_LCD_IER_LNIE_SIZE 1 +# define LCDC_LCD_IER_LSTLNIE_OFFSET 1 +# define LCDC_LCD_IER_LSTLNIE_SIZE 1 +# define LCDC_LCD_IER_MERIE_OFFSET 6 +# define LCDC_LCD_IER_MERIE_SIZE 1 +# define LCDC_LCD_IER_OWRIE_OFFSET 5 +# define LCDC_LCD_IER_OWRIE_SIZE 1 +# define LCDC_LCD_IER_UFLWIE_OFFSET 4 +# define LCDC_LCD_IER_UFLWIE_SIZE 1 +#define LCDC_LCD_IMR 0x00000850 +# define LCDC_LCD_IMR_EOFIM_OFFSET 2 +# define LCDC_LCD_IMR_EOFIM_SIZE 1 +# define LCDC_LCD_IMR_LNIM_OFFSET 0 +# define LCDC_LCD_IMR_LNIM_SIZE 1 +# define LCDC_LCD_IMR_LSTLNIM_OFFSET 1 +# define LCDC_LCD_IMR_LSTLNIM_SIZE 1 +# define LCDC_LCD_IMR_MERIM_OFFSET 6 +# define LCDC_LCD_IMR_MERIM_SIZE 1 +# define LCDC_LCD_IMR_OWRIM_OFFSET 5 +# define LCDC_LCD_IMR_OWRIM_SIZE 1 +# define LCDC_LCD_IMR_UFLWIM_OFFSET 4 +# define LCDC_LCD_IMR_UFLWIM_SIZE 1 +#define LCDC_LCD_IRR 0x00000864 +# define LCDC_LCD_IRR_EOFIR_OFFSET 2 +# define LCDC_LCD_IRR_EOFIR_SIZE 1 +# define LCDC_LCD_IRR_LNIR_OFFSET 0 +# define LCDC_LCD_IRR_LNIR_SIZE 1 +# define LCDC_LCD_IRR_LSTLNIR_OFFSET 1 +# define LCDC_LCD_IRR_LSTLNIR_SIZE 1 +# define LCDC_LCD_IRR_MERIR_OFFSET 6 +# define LCDC_LCD_IRR_MERIR_SIZE 1 +# define LCDC_LCD_IRR_OWRIR_OFFSET 5 +# define LCDC_LCD_IRR_OWRIR_SIZE 1 +# define LCDC_LCD_IRR_UFLWIR_OFFSET 4 +# define LCDC_LCD_IRR_UFLWIR_SIZE 1 +#define LCDC_LCD_ISR 0x00000854 +# define LCDC_LCD_ISR_EOFIS_OFFSET 2 +# define LCDC_LCD_ISR_EOFIS_SIZE 1 +# define LCDC_LCD_ISR_LNIS_OFFSET 0 +# define LCDC_LCD_ISR_LNIS_SIZE 1 +# define LCDC_LCD_ISR_LSTLNIS_OFFSET 1 +# define LCDC_LCD_ISR_LSTLNIS_SIZE 1 +# define LCDC_LCD_ISR_MERIS_OFFSET 6 +# define LCDC_LCD_ISR_MERIS_SIZE 1 +# define LCDC_LCD_ISR_OWRIS_OFFSET 5 +# define LCDC_LCD_ISR_OWRIS_SIZE 1 +# define LCDC_LCD_ISR_UFLWIS_OFFSET 4 +# define LCDC_LCD_ISR_UFLWIS_SIZE 1 +#define LCDC_LCD_ITR 0x00000860 +# define LCDC_LCD_ITR_EOFIT_OFFSET 2 +# define LCDC_LCD_ITR_EOFIT_SIZE 1 +# define LCDC_LCD_ITR_LNIT_OFFSET 0 +# define LCDC_LCD_ITR_LNIT_SIZE 1 +# define LCDC_LCD_ITR_LSTLNIT_OFFSET 1 +# define LCDC_LCD_ITR_LSTLNIT_SIZE 1 +# define LCDC_LCD_ITR_MERIT_OFFSET 6 +# define LCDC_LCD_ITR_MERIT_SIZE 1 +# define LCDC_LCD_ITR_OWRIT_OFFSET 5 +# define LCDC_LCD_ITR_OWRIT_SIZE 1 +# define LCDC_LCD_ITR_UFLWIT_OFFSET 4 +# define LCDC_LCD_ITR_UFLWIT_SIZE 1 +#define LCDC_PWRCON 0x0000083C +# define LCDC_PWRCON_GUARD_TIME_OFFSET 1 +# define LCDC_PWRCON_GUARD_TIME_SIZE 7 +# define LCDC_PWRCON_LCD_BUSY_OFFSET 31 +# define LCDC_PWRCON_LCD_BUSY_SIZE 1 +# define LCDC_PWRCON_LCD_PWR_OFFSET 0 +# define LCDC_PWRCON_LCD_PWR_SIZE 1 + +#define LCDC_BIT(name) (1 << LCDC_##name##_OFFSET) +#define LCDC_MKBF(name,value) (((value) & ((1 << LCDC_##name##_SIZE) - 1)) << LCDC_##name##_OFFSET) +#define LCDC_GETBF(name,value) (((value) >> LCDC_##name##_OFFSET) & ((1 << LCDC_##name##_SIZE) - 1)) +#define LCDC_INSBF(name,value,old) (((old) & ~(((1 << LCDC_##name##_SIZE) - 1) << LCDC_##name##_OFFSET)) | LCDC_MKBF(name, value)) + +#define lcdc_readl(port,reg) readl((port)->regs + LCDC_##reg) +#define lcdc_writel(port,reg,value) writel((value), (port)->regs + LCDC_##reg) + +#endif /* __ASM_AVR32_PERIPH_LCDC_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/periph/pdc.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/pdc.h --- linux-2.6.16.11/include/asm-avr32/periph/pdc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/pdc.h 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PERIPH_PDC_H +#define __ASM_AVR32_PERIPH_PDC_H + +#define PDC_RPR 0x100 +#define PDC_RCR 0x104 +#define PDC_TPR 0x108 +#define PDC_TCR 0x10c +#define PDC_RNPR 0x110 +#define PDC_RNCR 0x114 +#define PDC_TNPR 0x118 +#define PDC_TNCR 0x11c +#define PDC_PTCR 0x120 +# define PDC_PTCR_RXTEN_OFFSET 0 +# define PDC_PTCR_RXTEN_SIZE 1 +# define PDC_PTCR_RXTDIS_OFFSET 1 +# define PDC_PTCR_RXTDIS_SIZE 1 +# define PDC_PTCR_TXTEN_OFFSET 8 +# define PDC_PTCR_TXTEN_SIZE 1 +# define PDC_PTCR_TXTDIS_OFFSET 9 +# define PDC_PTCR_TXTDIS_SIZE 1 +#define PDC_PTSR 0x124 + + +#define PDC_BIT(name) (1 << PDC_##name##_OFFSET) +#define PDC_MKBF(name, value) (((value) & ((1 << PDC_##name##_SIZE) - 1)) << PDC_##name##_OFFSET) +#define PDC_GETBF(name, value) (((value) >> PDC_##name##_OFFSET) & ((1 << PDC_##name##_SIZE) - 1)) +#define PDC_INSBF(name, value, old) (((old) & ~(((1 << PDC_##name##_SIZE) - 1) << PDC_##name##_OFFSET)) | PDC_MKBF(name, value)) + +#define pdc_readl(port,reg) readl((port)->regs + PDC_##reg) +#define pdc_writel(port,reg,value) writel((value), (port)->regs + PDC_##reg) + +#endif /* __ASM_AVR32_PERIPH_PDC_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/periph/twi.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/twi.h --- linux-2.6.16.11/include/asm-avr32/periph/twi.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/twi.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,114 @@ +/* + * Register definitions for TWI + * + * Two-wire Interface + */ +#ifndef __ASM_AVR32_TWI_H__ +#define __ASM_AVR32_TWI_H__ + +/* TWI register offsets */ +#define TWI_CR 0x0000 +#define TWI_MMR 0x0004 +#define TWI_SMR 0x0008 +#define TWI_IADR 0x000c +#define TWI_CWGR 0x0010 +#define TWI_SR 0x0020 +#define TWI_IER 0x0024 +#define TWI_IDR 0x0028 +#define TWI_IMR 0x002c +#define TWI_RHR 0x0030 +#define TWI_THR 0x0034 + +/* Bitfields in CR */ +#define TWI_START_OFFSET 0 +#define TWI_START_SIZE 1 +#define TWI_STOP_OFFSET 1 +#define TWI_STOP_SIZE 1 +#define TWI_MSEN_OFFSET 2 +#define TWI_MSEN_SIZE 1 +#define TWI_MSDIS_OFFSET 3 +#define TWI_MSDIS_SIZE 1 +#define TWI_SVEN_OFFSET 4 +#define TWI_SVEN_SIZE 1 +#define TWI_SVDIS_OFFSET 5 +#define TWI_SVDIS_SIZE 1 +#define TWI_SWRST_OFFSET 7 +#define TWI_SWRST_SIZE 1 + +/* Bitfields in MMR */ +#define TWI_IADRSZ_OFFSET 8 +#define TWI_IADRSZ_SIZE 2 +#define TWI_MREAD_OFFSET 12 +#define TWI_MREAD_SIZE 1 +#define TWI_DADR_OFFSET 16 +#define TWI_DADR_SIZE 7 + +/* Bitfields in SMR */ +#define TWI_SADR_OFFSET 16 +#define TWI_SADR_SIZE 7 + +/* Bitfields in IADR */ +#define TWI_IADR_OFFSET 0 +#define TWI_IADR_SIZE 24 + +/* Bitfields in CWGR */ +#define TWI_CLDIV_OFFSET 0 +#define TWI_CLDIV_SIZE 8 +#define TWI_CHDIV_OFFSET 8 +#define TWI_CHDIV_SIZE 8 +#define TWI_CKDIV_OFFSET 16 +#define TWI_CKDIV_SIZE 3 + +/* Bitfields in SR */ + +/* Bitfields in IER */ + +/* Bitfields in IDR */ +#define TWI_TXCOMP_OFFSET 0 +#define TWI_TXCOMP_SIZE 1 +#define TWI_RXRDY_OFFSET 1 +#define TWI_RXRDY_SIZE 1 +#define TWI_TXRDY_OFFSET 2 +#define TWI_TXRDY_SIZE 1 +#define TWI_SVREAD_OFFSET 3 +#define TWI_SVREAD_SIZE 1 +#define TWI_SVACC_OFFSET 4 +#define TWI_SVACC_SIZE 1 +#define TWI_GCACC_OFFSET 5 +#define TWI_GCACC_SIZE 1 +#define TWI_OVRE_OFFSET 6 +#define TWI_OVRE_SIZE 1 +#define TWI_UNRE_OFFSET 7 +#define TWI_UNRE_SIZE 1 +#define TWI_NACK_OFFSET 8 +#define TWI_NACK_SIZE 1 +#define TWI_ARBLST_OFFSET 9 +#define TWI_ARBLST_SIZE 1 + +/* Bitfields in IMR */ + +/* Bitfields in RHR */ +#define TWI_RXDATA_OFFSET 0 +#define TWI_RXDATA_SIZE 8 + +/* Bitfields in THR */ +#define TWI_TXDATA_OFFSET 0 +#define TWI_TXDATA_SIZE 8 + +/* Constants for IADRSZ */ +#define TWI_IADRSZ_NO_ADDR 0 +#define TWI_IADRSZ_ONE_BYTE 1 +#define TWI_IADRSZ_TWO_BYTES 2 +#define TWI_IADRSZ_THREE_BYTES 3 + +/* Bit manipulation macros */ +#define TWI_BIT(name) (1 << TWI_##name##_OFFSET) +#define TWI_BF(name,value) (((value) & ((1 << TWI_##name##_SIZE) - 1)) << TWI_##name##_OFFSET) +#define TWI_BFEXT(name,value) (((value) >> TWI_##name##_OFFSET) & ((1 << TWI_##name##_SIZE) - 1)) +#define TWI_BFINS(name,value,old) (((old) & ~(((1 << TWI_##name##_SIZE) - 1) << TWI_##name##_OFFSET)) | TWI_BF(name,value)) + +/* Register access macros */ +#define twi_readl(port,reg) readl((port)->regs + TWI_##reg) +#define twi_writel(port,reg,value) writel((value), (port)->regs + TWI_##reg) + +#endif /* __ASM_AVR32_TWI_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/periph/usart3.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/usart3.h --- linux-2.6.16.11/include/asm-avr32/periph/usart3.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/periph/usart3.h 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,264 @@ +/* + * Register definitions for USART3 + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_USART3_H__ +#define __ASM_AVR32_USART3_H__ + +/* USART3 register offsets */ +#define USART3_CR 0x0000 +#define USART3_MR 0x0004 +#define USART3_IER 0x0008 +#define USART3_IDR 0x000c +#define USART3_IMR 0x0010 +#define USART3_CSR 0x0014 +#define USART3_RHR 0x0018 +#define USART3_THR 0x001c +#define USART3_BRGR 0x0020 +#define USART3_RTOR 0x0024 +#define USART3_TTGR 0x0028 +#define USART3_FIDI 0x0040 +#define USART3_NER 0x0044 +#define USART3_XXR 0x0048 +#define USART3_IFR 0x004c + +/* Bitfields in CR */ +#define USART3_RSTRX_OFFSET 2 +#define USART3_RSTRX_SIZE 1 +#define USART3_RSTTX_OFFSET 3 +#define USART3_RSTTX_SIZE 1 +#define USART3_RXEN_OFFSET 4 +#define USART3_RXEN_SIZE 1 +#define USART3_RXDIS_OFFSET 5 +#define USART3_RXDIS_SIZE 1 +#define USART3_TXEN_OFFSET 6 +#define USART3_TXEN_SIZE 1 +#define USART3_TXDIS_OFFSET 7 +#define USART3_TXDIS_SIZE 1 +#define USART3_RSTSTA_OFFSET 8 +#define USART3_RSTSTA_SIZE 1 +#define USART3_STTBRK_OFFSET 9 +#define USART3_STTBRK_SIZE 1 +#define USART3_STPBRK_OFFSET 10 +#define USART3_STPBRK_SIZE 1 +#define USART3_STTTO_OFFSET 11 +#define USART3_STTTO_SIZE 1 +#define USART3_SENDA_OFFSET 12 +#define USART3_SENDA_SIZE 1 +#define USART3_RSTIT_OFFSET 13 +#define USART3_RSTIT_SIZE 1 +#define USART3_RSTNACK_OFFSET 14 +#define USART3_RSTNACK_SIZE 1 +#define USART3_RETTO_OFFSET 15 +#define USART3_RETTO_SIZE 1 +#define USART3_DTREN_OFFSET 16 +#define USART3_DTREN_SIZE 1 +#define USART3_DTRDIS_OFFSET 17 +#define USART3_DTRDIS_SIZE 1 +#define USART3_RTSEN_OFFSET 18 +#define USART3_RTSEN_SIZE 1 +#define USART3_RTSDIS_OFFSET 19 +#define USART3_RTSDIS_SIZE 1 +#define USART3_COMM_TX_OFFSET 30 +#define USART3_COMM_TX_SIZE 1 +#define USART3_COMM_RX_OFFSET 31 +#define USART3_COMM_RX_SIZE 1 + +/* Bitfields in MR */ +#define USART3_USART_MODE_OFFSET 0 +#define USART3_USART_MODE_SIZE 4 +#define USART3_USCLKS_OFFSET 4 +#define USART3_USCLKS_SIZE 2 +#define USART3_CHRL_OFFSET 6 +#define USART3_CHRL_SIZE 2 +#define USART3_SYNC_OFFSET 8 +#define USART3_SYNC_SIZE 1 +#define USART3_PAR_OFFSET 9 +#define USART3_PAR_SIZE 3 +#define USART3_NBSTOP_OFFSET 12 +#define USART3_NBSTOP_SIZE 2 +#define USART3_CHMODE_OFFSET 14 +#define USART3_CHMODE_SIZE 2 +#define USART3_MSBF_OFFSET 16 +#define USART3_MSBF_SIZE 1 +#define USART3_MODE9_OFFSET 17 +#define USART3_MODE9_SIZE 1 +#define USART3_CLKO_OFFSET 18 +#define USART3_CLKO_SIZE 1 +#define USART3_OVER_OFFSET 19 +#define USART3_OVER_SIZE 1 +#define USART3_INACK_OFFSET 20 +#define USART3_INACK_SIZE 1 +#define USART3_DSNACK_OFFSET 21 +#define USART3_DSNACK_SIZE 1 +#define USART3_MAX_ITERATION_OFFSET 24 +#define USART3_MAX_ITERATION_SIZE 3 +#define USART3_FILTER_OFFSET 28 +#define USART3_FILTER_SIZE 1 + +/* Bitfields in IER */ + +/* Bitfields in IDR */ + +/* Bitfields in IMR */ + +/* Bitfields in CSR */ +#define USART3_RXRDY_OFFSET 0 +#define USART3_RXRDY_SIZE 1 +#define USART3_TXRDY_OFFSET 1 +#define USART3_TXRDY_SIZE 1 +#define USART3_RXBRK_OFFSET 2 +#define USART3_RXBRK_SIZE 1 +#define USART3_ENDRX_OFFSET 3 +#define USART3_ENDRX_SIZE 1 +#define USART3_ENDTX_OFFSET 4 +#define USART3_ENDTX_SIZE 1 +#define USART3_OVRE_OFFSET 5 +#define USART3_OVRE_SIZE 1 +#define USART3_FRAME_OFFSET 6 +#define USART3_FRAME_SIZE 1 +#define USART3_PARE_OFFSET 7 +#define USART3_PARE_SIZE 1 +#define USART3_TIMEOUT_OFFSET 8 +#define USART3_TIMEOUT_SIZE 1 +#define USART3_TXEMPTY_OFFSET 9 +#define USART3_TXEMPTY_SIZE 1 +#define USART3_ITERATION_OFFSET 10 +#define USART3_ITERATION_SIZE 1 +#define USART3_TXBUFE_OFFSET 11 +#define USART3_TXBUFE_SIZE 1 +#define USART3_RXBUFF_OFFSET 12 +#define USART3_RXBUFF_SIZE 1 +#define USART3_NACK_OFFSET 13 +#define USART3_NACK_SIZE 1 +#define USART3_RIIC_OFFSET 16 +#define USART3_RIIC_SIZE 1 +#define USART3_DSRIC_OFFSET 17 +#define USART3_DSRIC_SIZE 1 +#define USART3_DCDIC_OFFSET 18 +#define USART3_DCDIC_SIZE 1 +#define USART3_CTSIC_OFFSET 19 +#define USART3_CTSIC_SIZE 1 +#define USART3_RI_OFFSET 20 +#define USART3_RI_SIZE 1 +#define USART3_DSR_OFFSET 21 +#define USART3_DSR_SIZE 1 +#define USART3_DCD_OFFSET 22 +#define USART3_DCD_SIZE 1 +#define USART3_CTS_OFFSET 23 +#define USART3_CTS_SIZE 1 + +/* Bitfields in RHR */ +#define USART3_RXCHR_OFFSET 0 +#define USART3_RXCHR_SIZE 9 + +/* Bitfields in THR */ +#define USART3_TXCHR_OFFSET 0 +#define USART3_TXCHR_SIZE 9 + +/* Bitfields in BRGR */ +#define USART3_CD_OFFSET 0 +#define USART3_CD_SIZE 16 + +/* Bitfields in RTOR */ +#define USART3_TO_OFFSET 0 +#define USART3_TO_SIZE 16 + +/* Bitfields in TTGR */ +#define USART3_TG_OFFSET 0 +#define USART3_TG_SIZE 8 + +/* Bitfields in FIDI */ +#define USART3_FI_DI_RATIO_OFFSET 0 +#define USART3_FI_DI_RATIO_SIZE 11 + +/* Bitfields in NER */ +#define USART3_NB_ERRORS_OFFSET 0 +#define USART3_NB_ERRORS_SIZE 8 + +/* Bitfields in XXR */ +#define USART3_XOFF_OFFSET 0 +#define USART3_XOFF_SIZE 8 +#define USART3_XON_OFFSET 8 +#define USART3_XON_SIZE 8 + +/* Bitfields in IFR */ +#define USART3_IRDA_FILTER_OFFSET 0 +#define USART3_IRDA_FILTER_SIZE 8 + +/* Constants for USART_MODE */ +#define USART3_USART_MODE_NORMAL 0 +#define USART3_USART_MODE_RS485 1 +#define USART3_USART_MODE_HARDWARE 2 +#define USART3_USART_MODE_MODEM 3 +#define USART3_USART_MODE_ISO7816_T0 4 +#define USART3_USART_MODE_ISO7816_T1 6 +#define USART3_USART_MODE_IRDA 8 + +/* Constants for USCLKS */ +#define USART3_USCLKS_MCK 0 +#define USART3_USCLKS_MCK_DIV 1 +#define USART3_USCLKS_SCK 3 + +/* Constants for CHRL */ +#define USART3_CHRL_5 0 +#define USART3_CHRL_6 1 +#define USART3_CHRL_7 2 +#define USART3_CHRL_8 3 + +/* Constants for PAR */ +#define USART3_PAR_EVEN 0 +#define USART3_PAR_ODD 1 +#define USART3_PAR_SPACE 2 +#define USART3_PAR_MARK 3 +#define USART3_PAR_NONE 4 +#define USART3_PAR_MULTI 6 + +/* Constants for NBSTOP */ +#define USART3_NBSTOP_1 0 +#define USART3_NBSTOP_1_5 1 +#define USART3_NBSTOP_2 2 + +/* Constants for CHMODE */ +#define USART3_CHMODE_NORMAL 0 +#define USART3_CHMODE_ECHO 1 +#define USART3_CHMODE_LOCAL_LOOP 2 +#define USART3_CHMODE_REMOTE_LOOP 3 + +/* Constants for MSBF */ +#define USART3_MSBF_LSBF 0 +#define USART3_MSBF_MSBF 1 + +/* Constants for OVER */ +#define USART3_OVER_X16 0 +#define USART3_OVER_X8 1 + +/* Constants for CD */ +#define USART3_CD_DISABLE 0 +#define USART3_CD_BYPASS 1 + +/* Constants for TO */ +#define USART3_TO_DISABLE 0 + +/* Constants for TG */ +#define USART3_TG_DISABLE 0 + +/* Constants for FI_DI_RATIO */ +#define USART3_FI_DI_RATIO_DISABLE 0 + +/* Bit manipulation macros */ +#define USART3_BIT(name) (1 << USART3_##name##_OFFSET) +#define USART3_BF(name,value) (((value) & ((1 << USART3_##name##_SIZE) - 1)) << USART3_##name##_OFFSET) +#define USART3_BFEXT(name,value) (((value) >> USART3_##name##_OFFSET) & ((1 << USART3_##name##_SIZE) - 1)) +#define USART3_BFINS(name,value,old) (((old) & ~(((1 << USART3_##name##_SIZE) - 1) << USART3_##name##_OFFSET)) | USART3_BF(name,value)) + +/* Register access macros */ +#define usart3_readl(port,reg) readl((port)->regs + USART3_##reg) +#define usart3_writel(port,reg,value) writel((value), (port)->regs + USART3_##reg) + +#endif /* __ASM_AVR32_USART3_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/pgalloc.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/pgalloc.h --- linux-2.6.16.11/include/asm-avr32/pgalloc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/pgalloc.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PGALLOC_H +#define __ASM_AVR32_PGALLOC_H + +#include +#include +#include +#include + +#define pmd_populate_kernel(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) + +static __inline__ void pmd_populate(struct mm_struct *mm, pmd_t *pmd, + struct page *pte) +{ + set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte))); +} + +/* + * Allocate and free page tables + */ +static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm) +{ + unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t)); + pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL); + + if (pgd) + memset(pgd, 0, pgd_size); + + return pgd; +} + +static inline void pgd_free(pgd_t *pgd) +{ + kfree(pgd); +} + +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) +{ + int count = 0; + pte_t *pte; + + do { + pte = (pte_t *) __get_free_page(GFP_KERNEL | __GFP_REPEAT); + if (pte) + clear_page(pte); + else { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + } + } while (!pte && (count++ < 10)); + + return pte; +} + +static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long address) +{ + int count = 0; + struct page *pte; + + do { + pte = alloc_pages(GFP_KERNEL, 0); + if (pte) + clear_page(page_address(pte)); + else { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + } + } while (!pte && (count++ < 10)); + + return pte; +} + +static inline void pte_free_kernel(pte_t *pte) +{ + free_page((unsigned long)pte); +} + +static inline void pte_free(struct page *pte) +{ + __free_page(pte); +} + +#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) + +#define check_pgt_cache() do { } while(0) + +#endif /* __ASM_AVR32_PGALLOC_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/pgtable-2level.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/pgtable-2level.h --- linux-2.6.16.11/include/asm-avr32/pgtable-2level.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/pgtable-2level.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PGTABLE_2LEVEL_H +#define __ASM_AVR32_PGTABLE_2LEVEL_H + +#include + +/* + * Traditional 2-level paging structure + */ +#define PGDIR_SHIFT 22 +#define PTRS_PER_PGD 1024 + +#define PTRS_PER_PTE 1024 + +#ifndef __ASSEMBLY__ +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) + +/* + * Certain architectures need to do special things when PTEs + * within a page table are directly modified. Thus, the following + * hook is made available. + */ +#define set_pte(pteptr, pteval) (*(pteptr) = pteval) +#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep, pteval) + +/* + * (pmds are folded into pgds so this doesn't get actually called, + * but the define is needed for a generic inline function.) + */ +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) + +#define pte_pfn(x) ((unsigned long)(((x).pte >> PAGE_SHIFT))) +#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) +#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_AVR32_PGTABLE_2LEVEL_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/pgtable.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/pgtable.h --- linux-2.6.16.11/include/asm-avr32/pgtable.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/pgtable.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PGTABLE_H +#define __ASM_AVR32_PGTABLE_H + +#include +#include + +#ifndef __ASSEMBLY__ +#include + +#endif /* !__ASSEMBLY__ */ + +/* + * Use two-level page tables just as the i386 (without PAE) + */ +#include + +/* + * The following code might need some cleanup when the values are + * final... + */ +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) +#define FIRST_USER_ADDRESS 0 + +#define PTE_PHYS_MASK 0x1ffff000 + +#ifndef __ASSEMBLY__ +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern void paging_init(void); + +/* + * ZERO_PAGE is a global shared page that is always zero: used for + * zero-mapped memory areas etc. + */ +extern struct page *empty_zero_page; +#define ZERO_PAGE(vaddr) (empty_zero_page) + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after + * the uncached physical memory (P2 segment) until the vmalloc area + * starts. That means that any out-of-bounds memory accesses will + * hopefully be caught; we don't know if the end of the P1/P2 segments + * are actually used for anything, but it is anyway safer to let the + * MMU catch these kinds of errors than to rely on the memory bus. + * + * A "hole" of the same size is added to the end of the P3 segment as + * well. It might seem wasteful to use 16 MB of virtual address space + * on this, but we do have 512 MB of it... + * + * The vmalloc() routines leave a hole of 4kB between each vmalloced + * area for the same reason. + */ +#define VMALLOC_OFFSET (8 * 1024 * 1024) +#define VMALLOC_START (P3SEG + VMALLOC_OFFSET) +#define VMALLOC_END (P4SEG - VMALLOC_OFFSET) +#endif /* !__ASSEMBLY__ */ + +/* + * Page flags. Some of these flags are not directly supported by + * hardware, so we have to emulate them. + */ +#define _TLBEHI_BIT_VALID 9 +#define _TLBEHI_VALID (1 << _TLBEHI_BIT_VALID) + +#define _PAGE_BIT_WT 0 /* W-bit : write-through */ +#define _PAGE_BIT_DIRTY 1 /* D-bit : page changed */ +#define _PAGE_BIT_SZ0 2 /* SZ0-bit : Size of page */ +#define _PAGE_BIT_SZ1 3 /* SZ1-bit : Size of page */ +#define _PAGE_BIT_EXECUTE 4 /* X-bit : execute access allowed */ +#define _PAGE_BIT_RW 5 /* AP0-bit : write access allowed */ +#define _PAGE_BIT_USER 6 /* AP1-bit : user space access allowed */ +#define _PAGE_BIT_BUFFER 7 /* B-bit : bufferable */ +#define _PAGE_BIT_GLOBAL 8 /* G-bit : global (ignore ASID) */ +#define _PAGE_BIT_CACHABLE 9 /* C-bit : cachable */ + +/* If we drop support for 1K pages, we get two extra bits */ +#define _PAGE_BIT_PRESENT 10 +#define _PAGE_BIT_ACCESSED 11 /* software: page was accessed */ + +/* The following flags are only valid when !PRESENT */ +#define _PAGE_BIT_FILE 0 /* software: pagecache or swap? */ + +#define _PAGE_WT (1 << _PAGE_BIT_WT) +#define _PAGE_DIRTY (1 << _PAGE_BIT_DIRTY) +#define _PAGE_EXECUTE (1 << _PAGE_BIT_EXECUTE) +#define _PAGE_RW (1 << _PAGE_BIT_RW) +#define _PAGE_USER (1 << _PAGE_BIT_USER) +#define _PAGE_BUFFER (1 << _PAGE_BIT_BUFFER) +#define _PAGE_GLOBAL (1 << _PAGE_BIT_GLOBAL) +#define _PAGE_CACHABLE (1 << _PAGE_BIT_CACHABLE) + +/* Software flags */ +#define _PAGE_ACCESSED (1 << _PAGE_BIT_ACCESSED) +#define _PAGE_PRESENT (1 << _PAGE_BIT_PRESENT) +#define _PAGE_FILE (1 << _PAGE_BIT_FILE) + +/* + * Page types, i.e. sizes. _PAGE_TYPE_NONE corresponds to what is + * usually called _PAGE_PROTNONE on other architectures. + * + * XXX: Find out if _PAGE_PROTNONE is equivalent with !_PAGE_USER. If + * so, we can encode all possible page sizes (although we can't really + * support 1K pages anyway due to the _PAGE_PRESENT and _PAGE_ACCESSED + * bits) + * + */ +#define _PAGE_TYPE_MASK ((1 << _PAGE_BIT_SZ0) | (1 << _PAGE_BIT_SZ1)) +#define _PAGE_TYPE_NONE (0 << _PAGE_BIT_SZ0) +#define _PAGE_TYPE_SMALL (1 << _PAGE_BIT_SZ0) +#define _PAGE_TYPE_MEDIUM (2 << _PAGE_BIT_SZ0) +#define _PAGE_TYPE_LARGE (3 << _PAGE_BIT_SZ0) + +/* + * Mask which drop software flags. We currently can't handle more than + * 512MB of physical memory, so we can use bits 29-31 for other stuff. + * With a fixed 4K page size, we can use bits 10-11 as well as bits + * 2-3 (SZ) + */ +#define _PAGE_FLAGS_HARDWARE_MASK 0xfffff3ff + +#define _PAGE_FLAGS_CACHE_MASK (_PAGE_CACHABLE | _PAGE_BUFFER | _PAGE_WT) + +/* TODO: Check for saneness */ +/* User-mode page table flags (to be set in a pgd or pmd entry) */ +#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \ + | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) +/* Kernel-mode page table flags */ +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \ + | _PAGE_ACCESSED | _PAGE_DIRTY) +/* Flags that may be modified by software */ +#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY \ + | _PAGE_FLAGS_CACHE_MASK) + +#define _PAGE_FLAGS_READ (_PAGE_CACHABLE | _PAGE_BUFFER) +#define _PAGE_FLAGS_WRITE (_PAGE_FLAGS_READ | _PAGE_RW | _PAGE_DIRTY) + +#define _PAGE_NORMAL(x) __pgprot((x) | _PAGE_PRESENT | _PAGE_TYPE_SMALL \ + | _PAGE_ACCESSED) + +#define PAGE_NONE (_PAGE_ACCESSED | _PAGE_TYPE_NONE) +#define PAGE_READ (_PAGE_FLAGS_READ | _PAGE_USER) +#define PAGE_EXEC (_PAGE_FLAGS_READ | _PAGE_EXECUTE | _PAGE_USER) +#define PAGE_WRITE (_PAGE_FLAGS_WRITE | _PAGE_USER) +#define PAGE_KERNEL _PAGE_NORMAL(_PAGE_FLAGS_WRITE | _PAGE_EXECUTE | _PAGE_GLOBAL) +#define PAGE_KERNEL_RO _PAGE_NORMAL(_PAGE_FLAGS_READ | _PAGE_EXECUTE | _PAGE_GLOBAL) + +#define _PAGE_P(x) _PAGE_NORMAL((x) & ~(_PAGE_RW | _PAGE_DIRTY)) +#define _PAGE_S(x) _PAGE_NORMAL(x) + +#define PAGE_COPY _PAGE_P(PAGE_WRITE | PAGE_READ) + +#ifndef __ASSEMBLY__ +/* + * The hardware supports flags for write- and execute access. Read is + * always allowed if the page is loaded into the TLB, so the "-w-", + * "--x" and "-wx" mappings are implemented as "rw-", "r-x" and "rwx", + * respectively. + * + * The "---" case is handled by software; the page will simply not be + * loaded into the TLB if the page type is _PAGE_TYPE_NONE. + */ + +#define __P000 __pgprot(PAGE_NONE) +#define __P001 _PAGE_P(PAGE_READ) +#define __P010 _PAGE_P(PAGE_WRITE) +#define __P011 _PAGE_P(PAGE_WRITE | PAGE_READ) +#define __P100 _PAGE_P(PAGE_EXEC) +#define __P101 _PAGE_P(PAGE_EXEC | PAGE_READ) +#define __P110 _PAGE_P(PAGE_EXEC | PAGE_WRITE) +#define __P111 _PAGE_P(PAGE_EXEC | PAGE_WRITE | PAGE_READ) + +#define __S000 __pgprot(PAGE_NONE) +#define __S001 _PAGE_S(PAGE_READ) +#define __S010 _PAGE_S(PAGE_WRITE) +#define __S011 _PAGE_S(PAGE_WRITE | PAGE_READ) +#define __S100 _PAGE_S(PAGE_EXEC) +#define __S101 _PAGE_S(PAGE_EXEC | PAGE_READ) +#define __S110 _PAGE_S(PAGE_EXEC | PAGE_WRITE) +#define __S111 _PAGE_S(PAGE_EXEC | PAGE_WRITE | PAGE_READ) + +#define pte_none(x) (!pte_val(x)) +#define pte_present(x) (pte_val(x) & _PAGE_PRESENT) + +#define pte_clear(mm,addr,xp) \ + do { \ + set_pte_at(mm, addr, xp, __pte(0)); \ + } while (0) + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +static inline int pte_read(pte_t pte) +{ + return pte_val(pte) & _PAGE_USER; +} +static inline int pte_write(pte_t pte) +{ + return pte_val(pte) & _PAGE_RW; +} +static inline int pte_exec(pte_t pte) +{ + return pte_val(pte) & _PAGE_EXECUTE; +} +static inline int pte_dirty(pte_t pte) +{ + return pte_val(pte) & _PAGE_DIRTY; +} +static inline int pte_young(pte_t pte) +{ + return pte_val(pte) & _PAGE_ACCESSED; +} + +/* + * The following only work if pte_present() is not true. + */ +static inline int pte_file(pte_t pte) +{ + return pte_val(pte) & _PAGE_FILE; +} + +/* Mutator functions for PTE bits */ +static inline pte_t pte_rdprotect(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); + return pte; +} +static inline pte_t pte_wrprotect(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW)); + return pte; +} +static inline pte_t pte_exprotect(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_EXECUTE)); + return pte; +} +static inline pte_t pte_mkclean(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); + return pte; +} +static inline pte_t pte_mkold(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); + return pte; +} +static inline pte_t pte_mkread(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); + return pte; +} +static inline pte_t pte_mkwrite(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); + return pte; +} +static inline pte_t pte_mkexec(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) | _PAGE_EXECUTE)); + return pte; +} +static inline pte_t pte_mkdirty(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); + return pte; +} +static inline pte_t pte_mkyoung(pte_t pte) +{ + set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); + return pte; +} + +#define pmd_none(x) (!pmd_val(x)) +#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) +#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) +#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) \ + != _KERNPG_TABLE) + +/* + * Permanent address of a page. We don't support highmem, so this is + * trivial. + */ +#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) +#define pte_page(x) phys_to_page(pte_val(x) & PTE_PHYS_MASK) + +/* + * Mark the prot value as uncacheable and unbufferable + */ +#define pgprot_noncached(prot) \ + __pgprot(pgprot_val(prot) & ~(_PAGE_BUFFER | _PAGE_CACHABLE)) + +/* + * Mark the prot value as uncacheable but bufferable + */ +#define pgprot_writecombine(prot) \ + __pgprot((pgprot_val(prot) & ~_PAGE_CACHABLE) | _PAGE_BUFFER) + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + * + * extern pte_t mk_pte(struct page *page, pgprot_t pgprot) + */ +#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) + | pgprot_val(newprot))); + return pte; +} + +#define page_pte(page) page_pte_prot(page, __pgprot(0)) + +#define pmd_page_kernel(pmd) \ + ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + +#define pmd_page(pmd) (phys_to_page(pmd_val(pmd))) + +/* to find an entry in a page-table-directory. */ +#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) +#define pgd_offset_current(address) \ + ((pgd_t *)__mfsr(SYSREG_PTBR) + pgd_index(address)) + +/* to find an entry in a kernel page-table-directory */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +/* Find an entry in the third-level page table.. */ +#define pte_index(address) \ + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset(dir, address) \ + ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address)) +#define pte_offset_kernel(dir, address) \ + ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address)) +#define pte_offset_map(dir, address) pte_offset_kernel(dir, address) +#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address) +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) do { } while (0) + +struct vm_area_struct; +extern void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte); + +/* + * Encode and decode a swap entry + * + * Constraints: + * _PAGE_FILE at bit 0 + * _PAGE_TYPE_* at bits 2-3 (for emulating _PAGE_PROTNONE) + * _PAGE_PRESENT at bit 10 + * + * We encode the type into bits 4-9 and offset into bits 11-31. This + * gives us a 21 bits offset, or 2**21 * 4K = 8G usable swap space per + * device, and 64 possible types. + * + * NOTE: We should set ZEROs at the position of _PAGE_PRESENT + * and _PAGE_PROTNONE bits + */ +#define __swp_type(x) (((x).val >> 4) & 0x3f) +#define __swp_offset(x) ((x).val >> 11) +#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 4) | ((offset) << 11) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +/* + * Encode and decode a nonlinear file mapping entry. We have to + * preserve _PAGE_FILE and _PAGE_PRESENT here. _PAGE_TYPE_* isn't + * necessary, since _PAGE_FILE implies !_PAGE_PROTNONE (?) + */ +#define PTE_FILE_MAX_BITS 30 +#define pte_to_pgoff(pte) (((pte_val(pte) >> 1) & 0x1ff) \ + | ((pte_val(pte) >> 11) << 9)) +#define pgoff_to_pte(off) ((pte_t) { ((((off) & 0x1ff) << 1) \ + | (((off) >> 9) << 11) \ + | _PAGE_FILE) }) + +typedef pte_t *pte_addr_t; + +#define kern_addr_valid(addr) (1) + +#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ + remap_pfn_range(vma, vaddr, pfn, size, prot) + +#define MK_IOSPACE_PFN(space, pfn) (pfn) +#define GET_IOSPACE(pfn) 0 +#define GET_PFN(pfn) (pfn) + +/* No page table caches to initialize (?) */ +#define pgtable_cache_init() do { } while(0) + +#include + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_AVR32_PGTABLE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/platform-at32ap/at32_device.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform-at32ap/at32_device.h --- linux-2.6.16.11/include/asm-avr32/platform-at32ap/at32_device.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform-at32ap/at32_device.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,72 @@ +/* + * AT32 bus type. This driver handles the on-chip AHB and APB busses. + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_AT32_DEVICE_H__ +#define __ASM_AVR32_AT32_DEVICE_H__ + +#include +#include + +extern struct bus_type at32_bus_type; + +struct at32_device { + const char *name; + unsigned int id; + int irq; + unsigned int sclk_count; + const struct sync_clock *sclk; + unsigned int pin_count; + const u16 *pin; + unsigned int num_resources; + const struct resource *resource; + struct device dev; +}; + +#define to_at32_device(x) container_of((x), struct at32_device, dev) + +int at32_enable_device(struct at32_device *adev); +void at32_disable_device(struct at32_device *adev); + +unsigned int at32_count_devices(const char *name); +struct at32_device *at32_find_device(const char *name, unsigned int id); + +const struct resource *at32_find_resource(struct at32_device *adev, + unsigned int id, + unsigned long flags); + +unsigned long at32_get_iomem_base(struct at32_device *adev, unsigned int id); +void __iomem *at32_map_iomem(struct at32_device *adev, unsigned int id); + +static inline int at32_get_irq(struct at32_device *adev) +{ + return adev->irq; +} + +static inline unsigned long long at32_get_sclk_hz(struct at32_device *adev, + unsigned int id) +{ + return adev->sclk[id].domain->hz; +} + +struct at32_driver { + int (*probe)(struct at32_device *adev); + int (*remove)(struct at32_device *adev); + void (*shutdown)(struct at32_device *adev); + int (*suspend)(struct at32_device *adev, pm_message_t state); + int (*resume)(struct at32_device *adev); + struct device_driver driver; +}; + +int at32_driver_register(struct at32_driver *adrv); +void at32_driver_unregister(struct at32_driver *adrv); + +#define at32_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev) +#define at32_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data)) + +#endif /* __ASM_AVR32_AT32_DEVICE_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/platform-at32ap/init.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform-at32ap/init.h --- linux-2.6.16.11/include/asm-avr32/platform-at32ap/init.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform-at32ap/init.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,21 @@ +/* + * AT32AP platform initialization calls. + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_AT32AP_INIT_H__ +#define __ASM_AVR32_AT32AP_INIT_H__ + +void setup_platform(void); +void platform_init_clock_domain(unsigned int clock_id, + unsigned long long clock_hz); + +/* Called by setup_platform */ +void at32_sm_init(void); +void at32_portmux_init(void); + +#endif /* __ASM_AVR32_AT32AP_INIT_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/platform-at32ap/portmux.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform-at32ap/portmux.h --- linux-2.6.16.11/include/asm-avr32/platform-at32ap/portmux.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform-at32ap/portmux.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,16 @@ +/* + * AT32 portmux interface. + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_AT32_PORTMUX_H__ +#define __ASM_AVR32_AT32_PORTMUX_H__ + +int portmux_enable_device(const struct at32_device *adev); +void portmux_disable_device(const struct at32_device *adev); + +#endif /* __ASM_AVR32_AT32_PORTMUX_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/platform-at32ap/sm.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform-at32ap/sm.h --- linux-2.6.16.11/include/asm-avr32/platform-at32ap/sm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform-at32ap/sm.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,35 @@ +/* + * AT32 System Manager interface. + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_AT32_SM_H__ +#define __ASM_AVR32_AT32_SM_H__ + +struct clock_domain; + +struct sync_clock { + struct clock_domain *domain; + unsigned int bit; +}; + +struct clock_domain { + spinlock_t lock; + unsigned int id; + unsigned int count; + unsigned long long hz; + u32 precious_mask; + struct sync_clock sclk; +}; + +void sm_unmask_sclk(const struct sync_clock *sclk); +void sm_mask_sclk(const struct sync_clock *sclk); + +extern struct clock_domain chip_domain[]; +extern const unsigned int nr_chip_domains; + +#endif /* __ASM_AVR32_AT32_SM_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/platform.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform.h --- linux-2.6.16.11/include/asm-avr32/platform.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/platform.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PLATFORM_H +#define __ASM_AVR32_PLATFORM_H + +#include + +#define IORESOURCE_PIOA 0x01 +#define IORESOURCE_PIOB 0x02 + +#ifndef __ASSEMBLY__ + +extern int platform_add_devices(struct platform_device **devs, int num); +extern int platform_add_device(struct platform_device *dev); + +/* + * The serial console needs to know the address and IRQ of the serial + * ports before the driver core has been initialized. This function + * allows the driver to get a sneak preview of what we have... + */ +extern struct platform_device * +platform_get_device(const char *name, int id); + +extern unsigned int platform_count_devices(const char *name); + +#define platform_num_resources(dev) ((dev)->num_resources) +#define platform_resource_start(dev, i) ((dev)->resource[(i)].start) +#define platform_resource_end(dev, i) ((dev)->resource[(i)].end) +#define platform_resource_flags(dev, i) ((dev)->resource[(i)].flags) +#define platform_resource_len(dev, i) \ + (platform_resource_end((dev), (i)) - \ + platform_resource_start((dev), (i)) + 1) + +struct eth_platform_data { + u8 valid; + u8 mii_phy_addr; + u8 hw_addr[6]; +}; + +struct fb_platform_data { + unsigned long fbmem_start; + unsigned long fbmem_size; +}; + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_AVR32_PLATFORM_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/poll.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/poll.h --- linux-2.6.16.11/include/asm-avr32/poll.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/poll.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,26 @@ +#ifndef __ASM_AVR32_POLL_H +#define __ASM_AVR32_POLL_H + +/* These are specified by iBCS2 */ +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 + +/* The rest seem to be more-or-less nonstandard. Check them! */ +#define POLLRDNORM 0x0040 +#define POLLRDBAND 0x0080 +#define POLLWRNORM 0x0100 +#define POLLWRBAND 0x0200 +#define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 + +struct pollfd { + int fd; + short events; + short revents; +}; + +#endif /* __ASM_AVR32_POLL_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/posix_types.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/posix_types.h --- linux-2.6.16.11/include/asm-avr32/posix_types.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/posix_types.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_POSIX_TYPES_H +#define __ASM_AVR32_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned int __kernel_uid_t; +typedef unsigned int __kernel_gid_t; +typedef unsigned long __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +typedef unsigned short __kernel_old_dev_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp) +{ + unsigned long __tmp = __fd / __NFDBITS; + unsigned long __rem = __fd % __NFDBITS; + __fdsetp->fds_bits[__tmp] |= (1UL<<__rem); +} + +#undef __FD_CLR +static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp) +{ + unsigned long __tmp = __fd / __NFDBITS; + unsigned long __rem = __fd % __NFDBITS; + __fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem); +} + + +#undef __FD_ISSET +static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p) +{ + unsigned long __tmp = __fd / __NFDBITS; + unsigned long __rem = __fd % __NFDBITS; + return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0; +} + +/* + * This will unroll the loop for the normal constant case (8 ints, + * for a 256-bit fd_set) + */ +#undef __FD_ZERO +static __inline__ void __FD_ZERO(__kernel_fd_set *__p) +{ + unsigned long *__tmp = __p->fds_bits; + int __i; + + if (__builtin_constant_p(__FDSET_LONGS)) { + switch (__FDSET_LONGS) { + case 16: + __tmp[ 0] = 0; __tmp[ 1] = 0; + __tmp[ 2] = 0; __tmp[ 3] = 0; + __tmp[ 4] = 0; __tmp[ 5] = 0; + __tmp[ 6] = 0; __tmp[ 7] = 0; + __tmp[ 8] = 0; __tmp[ 9] = 0; + __tmp[10] = 0; __tmp[11] = 0; + __tmp[12] = 0; __tmp[13] = 0; + __tmp[14] = 0; __tmp[15] = 0; + return; + + case 8: + __tmp[ 0] = 0; __tmp[ 1] = 0; + __tmp[ 2] = 0; __tmp[ 3] = 0; + __tmp[ 4] = 0; __tmp[ 5] = 0; + __tmp[ 6] = 0; __tmp[ 7] = 0; + return; + + case 4: + __tmp[ 0] = 0; __tmp[ 1] = 0; + __tmp[ 2] = 0; __tmp[ 3] = 0; + return; + } + } + __i = __FDSET_LONGS; + while (__i) { + __i--; + *__tmp = 0; + __tmp++; + } +} + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + +#endif /* __ASM_AVR32_POSIX_TYPES_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/processor.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/processor.h --- linux-2.6.16.11/include/asm-avr32/processor.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/processor.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PROCESSOR_H +#define __ASM_AVR32_PROCESSOR_H + +#include +#include + +#define TASK_SIZE 0x80000000 + +#ifndef __ASSEMBLY__ + +static inline void *current_text_addr(void) +{ + register void *pc asm("pc"); + return pc; +} + +enum arch_type { + ARCH_AVR32A, + ARCH_AVR32B, + ARCH_MAX +}; + +enum cpu_type { + CPU_MORGAN, + CPU_AT32AP, + CPU_MAX +}; + +enum tlb_config { + TLB_NONE, + TLB_SPLIT, + TLB_UNIFIED, + TLB_INVALID +}; + +struct avr32_cpuinfo { + unsigned long long cpu_hz; + unsigned long loops_per_jiffy; + enum arch_type arch_type; + enum cpu_type cpu_type; + unsigned short arch_revision; + unsigned short cpu_revision; + enum tlb_config tlb_config; + + struct cache_info icache; + struct cache_info dcache; +}; + +extern struct avr32_cpuinfo boot_cpu_data; + +#ifdef CONFIG_SMP +extern struct avr32_cpuinfo cpu_data[]; +#define current_cpu_data cpu_data[smp_processor_id()] +#else +#define cpu_data (&boot_cpu_data) +#define current_cpu_data boot_cpu_data +#endif + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's + */ +#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) + +#define cpu_relax() barrier() +#define cpu_sync_pipeline() asm volatile("sub pc, -2" : : : "memory") + +struct cpu_context { + unsigned long sr; + unsigned long pc; + unsigned long ksp; /* Kernel stack pointer */ + unsigned long r7; + unsigned long r6; + unsigned long r5; + unsigned long r4; + unsigned long r3; + unsigned long r2; + unsigned long r1; + unsigned long r0; +}; + +struct java_thread_context; + +/* This struct contains the CPU context as stored by switch_to() */ +struct thread_struct { + struct cpu_context cpu_context; +#ifdef CONFIG_AVR32_JAVA + /* + * I'm not sure if this is the right place because it's not + * really thread-specific. + */ + struct java_thread_context *java_context; +#endif + unsigned long single_step_addr; + u16 single_step_insn; +}; + +#define INIT_THREAD { \ + .cpu_context = { \ + .ksp = sizeof(init_stack) + (long)&init_stack, \ + }, \ +} + +/* + * Do necessary setup to start up a newly executed thread. + */ +#define start_thread(regs, new_pc, new_sp) \ + do { \ + set_fs(USER_DS); \ + memset(regs, 0, sizeof(*regs)); \ + regs->sr = MODE_USER; \ + regs->pc = new_pc & ~1; \ + regs->sp = new_sp; \ + } while(0) + +struct task_struct; + +/* Free all resources held by a thread */ +extern void release_thread(struct task_struct *); + +/* Create a kernel thread without removing it from tasklists */ +extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); + +/* Prepare to copy thread state - unlazy all lazy status */ +#define prepare_to_copy(tsk) do { } while(0) + +/* Return saved PC of a blocked thread */ +#define thread_saved_pc(tsk) ((tsk)->thread.cpu_context.pc) + +struct pt_regs; +void show_trace(struct task_struct *task, unsigned long *stack, + struct pt_regs *regs); + +extern unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) ((tsk)->thread.cpu_context.pc) +#define KSTK_ESP(tsk) ((tsk)->thread.cpu_context.ksp) + +#define ARCH_HAS_PREFETCH + +static inline void prefetch(const void *x) +{ + const char *c = x; + asm volatile("pref %0" : : "r"(c)); +} +#define PREFETCH_STRIDE L1_CACHE_BYTES + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_AVR32_PROCESSOR_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/processor.h.orig linux-2.6.16.11-avr32-20060626/include/asm-avr32/processor.h.orig --- linux-2.6.16.11/include/asm-avr32/processor.h.orig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/processor.h.orig 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PROCESSOR_H +#define __ASM_AVR32_PROCESSOR_H + +#include +#include + +#define TASK_SIZE 0x80000000 + +#ifndef __ASSEMBLY__ + +static inline void *current_text_addr(void) +{ + register void *pc asm("pc"); + return pc; +} + +enum arch_type { + ARCH_AVR32A, + ARCH_AVR32B, + ARCH_MAX +}; + +enum cpu_type { + CPU_MORGAN, + CPU_AT32AP, + CPU_MAX +}; + +enum tlb_config { + TLB_NONE, + TLB_SPLIT, + TLB_UNIFIED, + TLB_INVALID +}; + +struct avr32_cpuinfo { + unsigned long long cpu_hz; + unsigned long long bus_hz; + unsigned long loops_per_jiffy; + enum arch_type arch_type; + enum cpu_type cpu_type; + unsigned short arch_revision; + unsigned short cpu_revision; + enum tlb_config tlb_config; + + struct cache_info icache; + struct cache_info dcache; +}; + +extern struct avr32_cpuinfo boot_cpu_data; + +#ifdef CONFIG_SMP +extern struct avr32_cpuinfo cpu_data[]; +#define current_cpu_data cpu_data[smp_processor_id()] +#else +#define cpu_data (&boot_cpu_data) +#define current_cpu_data boot_cpu_data +#endif + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's + */ +#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) + +#define cpu_relax() barrier() +#define cpu_sync_pipeline() asm volatile("sub pc, -2" : : : "memory") + +struct cpu_context { + unsigned long sr; + unsigned long pc; + unsigned long ksp; /* Kernel stack pointer */ + unsigned long r7; + unsigned long r6; + unsigned long r5; + unsigned long r4; + unsigned long r3; + unsigned long r2; + unsigned long r1; + unsigned long r0; +}; + +struct java_thread_context; + +/* This struct contains the CPU context as stored by switch_to() */ +struct thread_struct { + struct cpu_context cpu_context; +#ifdef CONFIG_AVR32_JAVA + /* + * I'm not sure if this is the right place because it's not + * really thread-specific. + */ + struct java_thread_context *java_context; +#endif + unsigned long single_step_addr; + u16 single_step_insn; +}; + +#define INIT_THREAD { \ + .cpu_context = { \ + .ksp = sizeof(init_stack) + (long)&init_stack, \ + }, \ +} + +/* + * Do necessary setup to start up a newly executed thread. + */ +#define start_thread(regs, new_pc, new_sp) \ + do { \ + set_fs(USER_DS); \ + memset(regs, 0, sizeof(*regs)); \ + regs->sr = MODE_USER; \ + regs->pc = new_pc & ~1; \ + regs->sp = new_sp; \ + } while(0) + +struct task_struct; + +/* Free all resources held by a thread */ +extern void release_thread(struct task_struct *); + +/* Create a kernel thread without removing it from tasklists */ +extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); + +/* Prepare to copy thread state - unlazy all lazy status */ +#define prepare_to_copy(tsk) do { } while(0) + +/* Return saved PC of a blocked thread */ +#define thread_saved_pc(tsk) ((tsk)->thread.cpu_context.pc) + +struct pt_regs; +void show_trace(struct task_struct *task, unsigned long *stack, + struct pt_regs *regs); + +extern unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) ((tsk)->thread.cpu_context.pc) +#define KSTK_ESP(tsk) ((tsk)->thread.cpu_context.ksp) + +#define ARCH_HAS_PREFETCH + +static inline void prefetch(const void *x) +{ + const char *c = x; + asm volatile("pref %0" : : "r"(c)); +} +#define PREFETCH_STRIDE L1_CACHE_BYTES + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_AVR32_PROCESSOR_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/ptrace.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/ptrace.h --- linux-2.6.16.11/include/asm-avr32/ptrace.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/ptrace.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_PTRACE_H +#define __ASM_AVR32_PTRACE_H + +#include + +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 + +/* + * Status Register bits + */ +#define SR_H 0x40000000 +#define SR_R 0x20000000 +#define SR_J 0x10000000 +#define SR_DM 0x08000000 +#define SR_D 0x04000000 +#define MODE_NMI 0x01c00000 +#define MODE_EXCEPTION 0x01800000 +#define MODE_INT3 0x01400000 +#define MODE_INT2 0x01000000 +#define MODE_INT1 0x00c00000 +#define MODE_INT0 0x00800000 +#define MODE_SUPERVISOR 0x00400000 +#define MODE_USER 0x00000000 +#define MODE_MASK 0x01c00000 +#define SR_EM 0x00200000 +#define SR_I3M 0x00100000 +#define SR_I2M 0x00080000 +#define SR_I1M 0x00040000 +#define SR_I0M 0x00020000 +#define SR_GM 0x00010000 + +#define SR_H_BIT 30 +#define SR_R_BIT 29 +#define SR_J_BIT 28 +#define SR_DM_BIT 27 +#define SR_D_BIT 26 +#define MODE_SHIFT 22 +#define SR_EM_BIT 21 +#define SR_I3M_BIT 20 +#define SR_I2M_BIT 19 +#define SR_I1M_BIT 18 +#define SR_I0M_BIT 17 +#define SR_GM_BIT 16 + +/* The user-visible part */ +#define SR_L 0x00000020 +#define SR_Q 0x00000010 +#define SR_V 0x00000008 +#define SR_N 0x00000004 +#define SR_Z 0x00000002 +#define SR_C 0x00000001 + +#define SR_L_BIT 5 +#define SR_Q_BIT 4 +#define SR_V_BIT 3 +#define SR_N_BIT 2 +#define SR_Z_BIT 1 +#define SR_C_BIT 0 + +/* + * The order is defined by the stmts instruction. r0 is stored first, + * so it gets the highest address. + * + * Registers 0-12 are general-purpose registers (r12 is normally used for + * the function return value). + * Register 13 is the stack pointer + * Register 14 is the link register + * Register 15 is the program counter (retrieved from the RAR sysreg) + */ +#define FRAME_SIZE_FULL 72 +#define REG_R12_ORIG 68 +#define REG_R0 64 +#define REG_R1 60 +#define REG_R2 56 +#define REG_R3 52 +#define REG_R4 48 +#define REG_R5 44 +#define REG_R6 40 +#define REG_R7 36 +#define REG_R8 32 +#define REG_R9 28 +#define REG_R10 24 +#define REG_R11 20 +#define REG_R12 16 +#define REG_SP 12 +#define REG_LR 8 + +#define FRAME_SIZE_MIN 8 +#define REG_PC 4 +#define REG_SR 0 + +#ifndef __ASSEMBLY__ +struct pt_regs { + /* These are always saved */ + unsigned long sr; + unsigned long pc; + + /* These are sometimes saved */ + unsigned long lr; + unsigned long sp; + unsigned long r12; + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long r7; + unsigned long r6; + unsigned long r5; + unsigned long r4; + unsigned long r3; + unsigned long r2; + unsigned long r1; + unsigned long r0; + + /* Only saved on system call */ + unsigned long r12_orig; +}; + +#ifdef __KERNEL__ +# define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER) +extern void show_regs (struct pt_regs *); + +static __inline__ int valid_user_regs(struct pt_regs *regs) +{ + /* + * Some of the Java bits might be acceptable if/when we + * implement some support for that stuff... + */ + if ((regs->sr & 0xffff0000) == 0) + return 1; + + /* + * Force status register flags to be sane and report this + * illegal behaviour... + */ + regs->sr &= 0x0000ffff; + return 0; +} + +#define instruction_pointer(regs) ((regs)->pc) + +#define profile_pc(regs) instruction_pointer(regs) + +#endif /* __KERNEL__ */ + +#endif /* ! __ASSEMBLY__ */ + +#endif /* __ASM_AVR32_PTRACE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/resource.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/resource.h --- linux-2.6.16.11/include/asm-avr32/resource.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/resource.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_RESOURCE_H +#define __ASM_AVR32_RESOURCE_H + +#include + +#endif /* __ASM_AVR32_RESOURCE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/scatterlist.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/scatterlist.h --- linux-2.6.16.11/include/asm-avr32/scatterlist.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/scatterlist.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,21 @@ +#ifndef __ASM_AVR32_SCATTERLIST_H +#define __ASM_AVR32_SCATTERLIST_H + +struct scatterlist { + struct page *page; + unsigned int offset; + dma_addr_t dma_address; + unsigned int length; +}; + +/* These macros should be used after a pci_map_sg call has been done + * to get bus addresses of each of the SG entries and their lengths. + * You should only work with the number of sg entries pci_map_sg + * returns. + */ +#define sg_dma_address(sg) ((sg)->dma_address) +#define sg_dma_len(sg) ((sg)->length) + +#define ISA_DMA_THRESHOLD (0xffffffff) + +#endif /* __ASM_AVR32_SCATTERLIST_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/sdram.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/sdram.h --- linux-2.6.16.11/include/asm-avr32/sdram.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/sdram.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_SDRAM_H +#define __ASM_AVR32_SDRAM_H + +struct at32_device; + +struct sdram_info { + unsigned long phys_addr; + unsigned int row_bits, col_bits, bank_bits; + unsigned int cas, twr, trc, trp, trcd, tras, txsr; +}; + +int sdram_read_spd(struct at32_device *twi_dev, + struct sdram_info *info); +unsigned long sdram_init(struct at32_device *sdramc_dev, + const struct sdram_info *info); + +#endif /* __ASM_AVR32_SDRAM_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/sections.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/sections.h --- linux-2.6.16.11/include/asm-avr32/sections.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/sections.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_SECTIONS_H +#define __ASM_AVR32_SECTIONS_H + +#include + +#endif /* __ASM_AVR32_SECTIONS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/semaphore.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/semaphore.h --- linux-2.6.16.11/include/asm-avr32/semaphore.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/semaphore.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,112 @@ +/* + * SMP- and interrupt-safe semaphores. + * + * Copyright (C) 2006 Atmel Corporation + * + * Based on include/asm-i386/semaphore.h + * Copyright (C) 1996 Linus Torvalds + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_SEMAPHORE_H +#define __ASM_AVR32_SEMAPHORE_H + +#include + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +struct semaphore { + atomic_t count; + int sleepers; + wait_queue_head_t wait; +}; + +#define __SEMAPHORE_INITIALIZER(name, n) \ +{ \ + .count = ATOMIC_INIT(n), \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ +} + +#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) + +#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) +#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) + +static inline void sema_init (struct semaphore *sem, int val) +{ + atomic_set(&sem->count, val); + sem->sleepers = 0; + init_waitqueue_head(&sem->wait); +} + +static inline void init_MUTEX (struct semaphore *sem) +{ + sema_init(sem, 1); +} + +static inline void init_MUTEX_LOCKED (struct semaphore *sem) +{ + sema_init(sem, 0); +} + +void __down(struct semaphore * sem); +int __down_interruptible(struct semaphore * sem); +void __up(struct semaphore * sem); + +/* + * This is ugly, but we want the default case to fall through. + * "__down_failed" is a special asm handler that calls the C + * routine that actually waits. See arch/i386/kernel/semaphore.c + */ +static inline void down(struct semaphore * sem) +{ + might_sleep(); + if (unlikely(atomic_dec_return (&sem->count) < 0)) + __down (sem); +} + +/* + * Interruptible try to acquire a semaphore. If we obtained + * it, return zero. If we were interrupted, returns -EINTR + */ +static inline int down_interruptible(struct semaphore * sem) +{ + int ret = 0; + + might_sleep(); + if (unlikely(atomic_dec_return (&sem->count) < 0)) + ret = __down_interruptible (sem); + return ret; +} + +/* + * Non-blockingly attempt to down() a semaphore. + * Returns zero if we acquired it + */ +static inline int down_trylock(struct semaphore * sem) +{ + return atomic_dec_if_positive(&sem->count) < 0; +} + +/* + * Note! This is subtle. We jump to wake people up only if + * the semaphore was negative (== somebody was waiting on it). + * The default case (no contention) will result in NO + * jumps for both down() and up(). + */ +static inline void up(struct semaphore * sem) +{ + if (unlikely(atomic_inc_return (&sem->count) <= 0)) + __up (sem); +} + +#endif /* __KERNEL__ */ +#endif /*__ASM_AVR32_SEMAPHORE_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/sembuf.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/sembuf.h --- linux-2.6.16.11/include/asm-avr32/sembuf.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/sembuf.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,25 @@ +#ifndef __ASM_AVR32_SEMBUF_H +#define __ASM_AVR32_SEMBUF_H + +/* +* The semid64_ds structure for AVR32 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t sem_otime; /* last semop time */ + unsigned long __unused1; + __kernel_time_t sem_ctime; /* last change time */ + unsigned long __unused2; + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* __ASM_AVR32_SEMBUF_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/setup.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/setup.h --- linux-2.6.16.11/include/asm-avr32/setup.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/setup.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * Based on linux/include/asm-arm/setup.h + * Copyright (C) 1997-1999 Russel King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_SETUP_H__ +#define __ASM_AVR32_SETUP_H__ + +#define COMMAND_LINE_SIZE 256 + +/* Magic number indicating that a tag table is present */ +#define ATAG_MAGIC 0xa2a25441 + +#ifndef __ASSEMBLY__ + +/* + * Generic memory range, used by several tags. + * + * addr is always physical. + * size is measured in bytes. + * next is for use by the OS, e.g. for grouping regions into + * linked lists. + */ +struct tag_mem_range { + u32 addr; + u32 size; + struct tag_mem_range * next; +}; + +/* The list ends with an ATAG_NONE node. */ +#define ATAG_NONE 0x00000000 + +struct tag_header { + u32 size; + u32 tag; +}; + +/* The list must start with an ATAG_CORE node */ +#define ATAG_CORE 0x54410001 + +struct tag_core { + u32 flags; + u32 pagesize; + u32 rootdev; +}; + +/* it is allowed to have multiple ATAG_MEM nodes */ +#define ATAG_MEM 0x54410002 +/* ATAG_MEM uses tag_mem_range */ + +/* command line: \0 terminated string */ +#define ATAG_CMDLINE 0x54410003 + +struct tag_cmdline { + char cmdline[1]; /* this is the minimum size */ +}; + +/* Ramdisk image (may be compressed) */ +#define ATAG_RDIMG 0x54410004 +/* ATAG_RDIMG uses tag_mem_range */ + +/* Information about various clocks present in the system */ +#define ATAG_CLOCK 0x54410005 + +struct tag_clock { + u32 clock_id; /* Which clock are we talking about? */ + u32 clock_flags; /* Special features */ + u64 clock_hz; /* Clock speed in Hz */ +}; + +/* The clock types we know about */ +#define CLOCK_BOOTCPU 0 +#define CLOCK_AMBA 1 + +/* Memory reserved for the system (e.g. the bootloader) */ +#define ATAG_RSVD_MEM 0x54410006 +/* ATAG_RSVD_MEM uses tag_mem_range */ + +/* Ethernet information */ + +#define ATAG_ETHERNET 0x54410007 + +struct tag_ethernet { + u8 mac_index; + u8 mii_phy_addr; + u8 hw_address[6]; +}; + +#define ETH_INVALID_PHY 0xff + +struct tag { + struct tag_header hdr; + union { + struct tag_core core; + struct tag_mem_range mem_range; + struct tag_cmdline cmdline; + struct tag_clock clock; + struct tag_ethernet ethernet; + } u; +}; + +struct tagtable { + u32 tag; + int (*parse)(struct tag *); +}; + +#define __tag __attribute_used__ __attribute__((__section__(".taglist"))) +#define __tagtable(tag, fn) \ + static struct tagtable __tagtable_##fn __tag = { tag, fn } + +#define tag_member_present(tag,member) \ + ((unsigned long)(&((struct tag *)0L)->member + 1) \ + <= (tag)->hdr.size * 4) + +#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) +#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) + +#define for_each_tag(t,base) \ + for (t = base; t->hdr.size; t = tag_next(t)) + +extern struct tag_mem_range *mem_phys; +extern struct tag_mem_range *mem_reserved; +extern struct tag_mem_range *mem_ramdisk; + +extern struct tag *bootloader_tags; + +extern void setup_bootmem(void); +extern void setup_processor(void); +extern void board_setup_fbmem(unsigned long fbmem_start, + unsigned long fbmem_size); + +/* Chip-specific hook to enable the use of SDRAM */ +void chip_enable_sdram(void); + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_AVR32_SETUP_H__ */ diff -Nur linux-2.6.16.11/include/asm-avr32/shmbuf.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/shmbuf.h --- linux-2.6.16.11/include/asm-avr32/shmbuf.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/shmbuf.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,42 @@ +#ifndef __ASM_AVR32_SHMBUF_H +#define __ASM_AVR32_SHMBUF_H + +/* + * The shmid64_ds structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + unsigned long __unused1; + __kernel_time_t shm_dtime; /* last detach time */ + unsigned long __unused2; + __kernel_time_t shm_ctime; /* last change time */ + unsigned long __unused3; + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused4; + unsigned long __unused5; +}; + +struct shminfo64 { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* __ASM_AVR32_SHMBUF_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/shmparam.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/shmparam.h --- linux-2.6.16.11/include/asm-avr32/shmparam.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/shmparam.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_SHMPARAM_H +#define __ASM_AVR32_SHMPARAM_H + +#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ + +#endif /* __ASM_AVR32_SHMPARAM_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/sigcontext.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/sigcontext.h --- linux-2.6.16.11/include/asm-avr32/sigcontext.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/sigcontext.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_SIGCONTEXT_H +#define __ASM_AVR32_SIGCONTEXT_H + +struct sigcontext { + unsigned long oldmask; + + /* CPU registers */ + unsigned long sr; + unsigned long pc; + unsigned long lr; + unsigned long sp; + unsigned long r12; + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long r7; + unsigned long r6; + unsigned long r5; + unsigned long r4; + unsigned long r3; + unsigned long r2; + unsigned long r1; + unsigned long r0; +}; + +#endif /* __ASM_AVR32_SIGCONTEXT_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/siginfo.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/siginfo.h --- linux-2.6.16.11/include/asm-avr32/siginfo.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/siginfo.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef _AVR32_SIGINFO_H +#define _AVR32_SIGINFO_H + +#include + +#endif diff -Nur linux-2.6.16.11/include/asm-avr32/signal.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/signal.h --- linux-2.6.16.11/include/asm-avr32/signal.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/signal.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_SIGNAL_H +#define __ASM_AVR32_SIGNAL_H + +#include + +/* Avoid too many header ordering problems. */ +struct siginfo; + +#ifdef __KERNEL__ +/* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +#define NSIG 32 +typedef unsigned long sigset_t; + +#endif /* __KERNEL__ */ + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX (_NSIG-1) + +/* + * SA_FLAGS values: + * + * SA_ONSTACK indicates that a registered stack_t will be used. + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 +#define SA_SIGINFO 0x00000004 +#define SA_RESTORER 0x04000000 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND +#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 + +#include + +#ifdef __KERNEL__ +/* + * These values of sa_flags are used only by the kernel as part of the + * irq handling routines. + * + * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. + */ +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 + +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + __sigrestore_t sa_restorer; +}; + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; + __sigrestore_t sa_restorer; + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; +}; +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +struct sigaction { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +#define sa_handler _u._sa_handler +#define sa_sigaction _u._sa_sigaction + +#endif /* __KERNEL__ */ + +typedef struct sigaltstack { + void __user *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +#ifdef __KERNEL__ + +#include +#undef __HAVE_ARCH_SIG_BITOPS + +#define ptrace_signal_deliver(regs, cookie) do { } while (0) + +#endif /* __KERNEL__ */ + +#endif diff -Nur linux-2.6.16.11/include/asm-avr32/socket.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/socket.h --- linux-2.6.16.11/include/asm-avr32/socket.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/socket.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,52 @@ +#ifndef __ASM_AVR32_SOCKET_H +#define __ASM_AVR32_SOCKET_H + +#include + +/* For setsockopt(2) */ +#define SOL_SOCKET 1 + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +/* To add :#define SO_REUSEPORT 15 */ +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +/* Security levels - as per NRL IPv6 - don't actually do anything */ +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +/* Socket filtering */ +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 + +#define SO_PEERNAME 28 +#define SO_TIMESTAMP 29 +#define SCM_TIMESTAMP SO_TIMESTAMP + +#define SO_ACCEPTCONN 30 + +#define SO_PEERSEC 31 + +#endif /* __ASM_AVR32_SOCKET_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/sockios.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/sockios.h --- linux-2.6.16.11/include/asm-avr32/sockios.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/sockios.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,12 @@ +#ifndef __ASM_AVR32_SOCKIOS_H +#define __ASM_AVR32_SOCKIOS_H + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp */ + +#endif /* __ASM_AVR32_SOCKIOS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/statfs.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/statfs.h --- linux-2.6.16.11/include/asm-avr32/statfs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/statfs.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_STATFS_H +#define __ASM_AVR32_STATFS_H + +#include + +#endif /* __ASM_AVR32_STATFS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/stat.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/stat.h --- linux-2.6.16.11/include/asm-avr32/stat.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/stat.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_STAT_H +#define __ASM_AVR32_STAT_H + +struct __old_kernel_stat { + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; +}; + +struct stat { + unsigned long st_dev; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned long st_rdev; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned long st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + unsigned long __unused4; + unsigned long __unused5; +}; + +#define STAT_HAVE_NSEC 1 + +struct stat64 { + unsigned long long st_dev; + + unsigned long long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned long long st_rdev; + + long long st_size; + unsigned long __pad1; /* align 64-bit st_blocks */ + unsigned long st_blksize; + + unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ + + unsigned long st_atime; + unsigned long st_atime_nsec; + + unsigned long st_mtime; + unsigned long st_mtime_nsec; + + unsigned long st_ctime; + unsigned long st_ctime_nsec; + + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __ASM_AVR32_STAT_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/string.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/string.h --- linux-2.6.16.11/include/asm-avr32/string.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/string.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_STRING_H +#define __ASM_AVR32_STRING_H + +#define __HAVE_ARCH_MEMSET +extern void *memset(void *b, int c, size_t len); + +#define __HAVE_ARCH_MEMCPY +extern void *memcpy(void *to, const void *from, size_t len); + +#endif /* __ASM_AVR32_STRING_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/sysreg.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/sysreg.h --- linux-2.6.16.11/include/asm-avr32/sysreg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/sysreg.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_SYSREG_WRAPPER_H +#define __ASM_AVR32_SYSREG_WRAPPER_H + +#include + +#endif /* __ASM_AVR32_SYSREG_WRAPPER_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/system.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/system.h --- linux-2.6.16.11/include/asm-avr32/system.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/system.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_SYSTEM_H +#define __ASM_AVR32_SYSTEM_H + +#include +#include + +#include +#include + +#define xchg(ptr,x) \ + ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + +#define nop() asm volatile("nop") + +#define mb() asm volatile("" : : : "memory") +#define rmb() mb() +#define wmb() asm volatile("sync 0" : : : "memory") +#define read_barrier_depends() do { } while(0) +#define set_mb(var, value) do { var = value; mb(); } while(0) +#define set_wmb(var, value) do { var = value; wmb(); } while(0) + +/* + * Help PathFinder and other Nexus-compliant debuggers keep track of + * the current PID by emitting an Ownership Trace Message each time we + * switch task. + */ +#ifdef CONFIG_OWNERSHIP_TRACE +#include +#define finish_arch_switch(prev) \ + do { \ + __mtdr(DBGREG_PID, prev->pid); \ + __mtdr(DBGREG_PID, current->pid); \ + } while(0) +#endif + +/* + * switch_to(prev, next, last) should switch from task `prev' to task + * `next'. `prev' will never be the same as `next'. + * + * We just delegate everything to the __switch_to assembly function, + * which is implemented in arch/avr32/kernel/switch_to.S + * + * mb() tells GCC not to cache `current' across this call. + */ +struct cpu_context; +struct task_struct; +extern struct task_struct *__switch_to(struct task_struct *, + struct cpu_context *, + struct cpu_context *); +#define switch_to(prev, next, last) \ + do { \ + last = __switch_to(prev, &prev->thread.cpu_context + 1, \ + &next->thread.cpu_context); \ + } while (0) + +#ifdef CONFIG_SMP +# error "The AVR32 port does not support SMP" +#else +# define smp_mb() barrier() +# define smp_rmb() barrier() +# define smp_wmb() barrier() +# define smp_read_barrier_depends() do { } while(0) +#endif + +/* Interrupt Control */ + +#define local_irq_enable() \ + asm volatile("csrf %0" : : "n"(SR_GM_BIT) : "memory") +#define local_irq_disable() \ + asm volatile ("ssrf %0" : : "n"(SR_GM_BIT) : "memory") +#define local_save_flags(x) ((x) = sysreg_read(SR)) +#define irqs_disabled() \ + ({ \ + unsigned long flags; \ + local_save_flags(flags); \ + ((flags & SR_GM) != 0); \ + }) + +/* + * This will restore ALL status register flags, not only the interrupt + * mask flag. + * + * The empty asm statement informs the compiler of this fact (it also + * serves as a barrier). + */ +#define local_irq_restore(x) \ + do { \ + sysreg_write(SR, (x)); \ + asm volatile("" : : : "memory", "cc"); \ + } while(0) +#define local_irq_save(flags) \ + do { \ + local_save_flags(flags); \ + local_irq_disable(); \ + } while(0) + +extern void __xchg_called_with_bad_pointer(void); + +#ifdef __CHECKER__ +extern unsigned long __builtin_xchg(void *ptr, unsigned long x); +#endif + +#define xchg_u32(val, m) __builtin_xchg((void *)m, val) + +static inline unsigned long __xchg(unsigned long x, + volatile void *ptr, + int size) +{ + switch(size) { + case 4: + return xchg_u32(x, ptr); + default: + __xchg_called_with_bad_pointer(); + return x; + } +} + +static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old, + unsigned long new) +{ + __u32 ret; + + asm volatile( + "1: ssrf 5\n" + " ld.w %[ret], %[m]\n" + " cp.w %[ret], %[old]\n" + " brne 2f\n" + " stcond %[m], %[new]\n" + " brne 1b\n" + "2:\n" + : [ret] "=&r"(ret), [m] "=m"(*m) + : "m"(m), [old] "ir"(old), [new] "r"(new) + : "memory", "cc"); + return ret; +} + +extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels( + volatile int * m, unsigned long old, unsigned long new); +#define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels + +/* This function doesn't exist, so you'll get a linker error + if something tries to do an invalid cmpxchg(). */ +extern void __cmpxchg_called_with_bad_pointer(void); + +#define __HAVE_ARCH_CMPXCHG 1 + +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, + unsigned long new, int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32(ptr, old, new); + case 8: + return __cmpxchg_u64(ptr, old, new); + } + + __cmpxchg_called_with_bad_pointer(); + return old; +} + +#define cmpxchg(ptr, old, new) \ + ((typeof(*(ptr)))__cmpxchg((ptr), (unsigned long)(old), \ + (unsigned long)(new), \ + sizeof(*(ptr)))) + +struct pt_regs; +extern void __die(const char *, struct pt_regs *, unsigned long, + const char *, const char *, unsigned long); +extern void __die_if_kernel(const char *, struct pt_regs *, unsigned long, + const char *, const char *, unsigned long); + +#define die(msg, regs, err) \ + __die(msg, regs, err, __FILE__ ":", __FUNCTION__, __LINE__) +#define die_if_kernel(msg, regs, err) \ + __die_if_kernel(msg, regs, err, __FILE__ ":", __FUNCTION__, __LINE__) + +#define arch_align_stack(x) (x) + +#endif /* __ASM_AVR32_SYSTEM_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/termbits.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/termbits.h --- linux-2.6.16.11/include/asm-avr32/termbits.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/termbits.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,173 @@ +#ifndef __ASM_AVR32_TERMBITS_H +#define __ASM_AVR32_TERMBITS_H + +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag bit meaning */ +#define CBAUD 0010017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 +#define CIBAUD 002003600000 /* input baud rate (not used) */ +#define CMSPAR 010000000000 /* mark or space (stick) parity */ +#define CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#endif /* __ASM_AVR32_TERMBITS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/termios.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/termios.h --- linux-2.6.16.11/include/asm-avr32/termios.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/termios.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_TERMIOS_H +#define __ASM_AVR32_TERMIOS_H + +#include +#include + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 /* X.25 async */ +#define N_6PACK 7 +#define N_MASC 8 /* Reserved for Mobitex module */ +#define N_R3964 9 /* Reserved for Simatic R3964 module */ +#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ +#define N_HDLC 13 /* synchronous HDLC */ +#define N_SYNC_PPP 14 /* synchronous PPP */ +#define N_HCI 15 /* Bluetooth HCI UART */ + +#ifdef __KERNEL__ +/* intr=^C quit=^\ erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" + +#include + +#endif /* __KERNEL__ */ + +#endif /* __ASM_AVR32_TERMIOS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/thread_info.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/thread_info.h --- linux-2.6.16.11/include/asm-avr32/thread_info.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/thread_info.h 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_THREAD_INFO_H +#define __ASM_AVR32_THREAD_INFO_H + +#ifdef __KERNEL__ + +#include + +#define THREAD_SIZE_ORDER 1 +#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) + +#ifndef __ASSEMBLY__ +#include + +struct task_struct; +struct exec_domain; + +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + __u32 cpu; + __s32 preempt_count; /* 0 => preemptable, <0 => BUG */ + struct restart_block restart_block; + __u8 supervisor_stack[0]; +}; + +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = 1, \ + .restart_block = { \ + .fn = do_no_restart_syscall \ + } \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +/* + * Get the thread information struct from C. + * We do the usual trick and use the lower end of the stack for this + */ +static inline struct thread_info *current_thread_info(void) +{ + unsigned long addr = ~(THREAD_SIZE - 1); + + asm("and %0, sp" : "=r"(addr) : "0"(addr)); + return (struct thread_info *)addr; +} + +/* thread information allocation */ +#define alloc_thread_info(ti) \ + ((struct thread_info *) __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER)) +#define free_thread_info(ti) free_pages((unsigned long)(ti), 1) +#define get_thread_info(ti) get_task_struct((ti)->task) +#define put_thread_info(ti) put_task_struct((ti)->task) + +#endif /* !__ASSEMBLY__ */ + +#define PREEMPT_ACTIVE 0x40000000 + +/* + * Thread information flags + * - these are process state flags that various assembly files may need to access + * - pending work-to-be-done flags are in LSW + * - other flags in MSW + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling + TIF_NEED_RESCHED */ +#define TIF_BREAKPOINT 5 /* true if we should break after return */ +#define TIF_SINGLE_STEP 6 /* single step after next break */ +#define TIF_MEMDIE 7 +#define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal */ +#define TIF_SOFTIRQ 16 /* process softirqs before irq return */ +#define TIF_USERSPACE 31 /* true if FS sets userspace */ + +#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) +#define _TIF_BREAKPOINT (1 << TIF_BREAKPOINT) +#define _TIF_SINGLE_STEP (1 << TIF_SINGLE_STEP) +#define _TIF_MEMDIE (1 << TIF_MEMDIE) +#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) +#define _TIF_SOFTIRQ (1 << TIF_SOFTIRQ) + +/* XXX: These two masks must never span more than 16 bits! */ +/* work to do on interrupt/exception return */ +#define _TIF_WORK_MASK 0x0000013e +/* work to do on any return to userspace */ +#define _TIF_ALLWORK_MASK 0x0000013f +/* work to do on return from debug mode */ +#define _TIF_DBGWORK_MASK 0x0000017e + +#endif /* __KERNEL__ */ + +#endif /* __ASM_AVR32_THREAD_INFO_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/timex.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/timex.h --- linux-2.6.16.11/include/asm-avr32/timex.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/timex.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_TIMEX_H +#define __ASM_AVR32_TIMEX_H + +/* FIXME: I really have no idea... */ +#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ +#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ +#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ + (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ + << (SHIFT_SCALE-SHIFT_HZ)) / HZ) + +typedef unsigned long cycles_t; + +extern cycles_t cacheflush_time; + +static inline cycles_t get_cycles (void) +{ + return 0; +} + +extern int read_current_timer(unsigned long *timer_value); +#define ARCH_HAS_READ_CURRENT_TIMER 1 + +#endif /* __ASM_AVR32_TIMEX_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/tlbflush.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/tlbflush.h --- linux-2.6.16.11/include/asm-avr32/tlbflush.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/tlbflush.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_TLBFLUSH_H +#define __ASM_AVR32_TLBFLUSH_H + +#include + +/* + * TLB flushing: + * + * - flush_tlb() flushes the current mm struct TLBs + * - flush_tlb_all() flushes all processes' TLB entries + * - flush_tlb_mm(mm) flushes the specified mm context TLBs + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(vma, start, end) flushes a range of pages + * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages + * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables + */ +extern void flush_tlb(void); +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page); +extern void __flush_tlb_page(unsigned long asid, unsigned long page); + +static inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + /* Nothing to do */ +} + +extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); + +#endif /* __ASM_AVR32_TLBFLUSH_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/tlb.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/tlb.h --- linux-2.6.16.11/include/asm-avr32/tlb.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/tlb.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_TLB_H +#define __ASM_AVR32_TLB_H + +#define tlb_start_vma(tlb, vma) \ + flush_cache_range(vma, vma->vm_start, vma->vm_end) + +#define tlb_end_vma(tlb, vma) \ + flush_tlb_range(vma, vma->vm_start, vma->vm_end) + +#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while(0) + +/* + * Flush whole TLB for MM + */ +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) + +#include + +/* + * For debugging purposes + */ +extern void show_dtlb_entry(unsigned int index); +extern void dump_dtlb(void); + +#endif /* __ASM_AVR32_TLB_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/topology.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/topology.h --- linux-2.6.16.11/include/asm-avr32/topology.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/topology.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,6 @@ +#ifndef __ASM_AVR32_TOPOLOGY_H +#define __ASM_AVR32_TOPOLOGY_H + +#include + +#endif /* __ASM_AVR32_TOPOLOGY_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/traps.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/traps.h --- linux-2.6.16.11/include/asm-avr32/traps.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/traps.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_TRAPS_H +#define __ASM_AVR32_TRAPS_H + +#include + +struct undef_hook { + struct list_head node; + u32 insn_mask; + u32 insn_val; + int (*fn)(struct pt_regs *regs, u32 insn); +}; + +void register_undef_hook(struct undef_hook *hook); +void unregister_undef_hook(struct undef_hook *hook); + +#endif /* __ASM_AVR32_TRAPS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/types.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/types.h --- linux-2.6.16.11/include/asm-avr32/types.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/types.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_TYPES_H +#define __ASM_AVR32_TYPES_H + +#ifndef __ASSEMBLY__ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +#endif /* __ASSEMBLY__ */ + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +#define BITS_PER_LONG 32 + +#ifndef __ASSEMBLY__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; + +#ifdef CONFIG_LBD +typedef u64 sector_t; +#define HAVE_SECTOR_T +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + + +#endif /* __ASM_AVR32_TYPES_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/uaccess.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/uaccess.h --- linux-2.6.16.11/include/asm-avr32/uaccess.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/uaccess.h 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_UACCESS_H +#define __ASM_AVR32_UACCESS_H + +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +typedef struct { + unsigned int is_user_space; +} mm_segment_t; + +/* + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons (Data Segment Register?), these macros are misnamed. + */ +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) +#define segment_eq(a,b) ((a).is_user_space == (b).is_user_space) + +#define USER_ADDR_LIMIT 0x80000000 + +#define KERNEL_DS MAKE_MM_SEG(0) +#define USER_DS MAKE_MM_SEG(1) + +#define get_ds() (KERNEL_DS) + +static inline mm_segment_t get_fs(void) +{ + return MAKE_MM_SEG(test_thread_flag(TIF_USERSPACE)); +} + +static inline void set_fs(mm_segment_t s) +{ + if (s.is_user_space) + set_thread_flag(TIF_USERSPACE); + else + clear_thread_flag(TIF_USERSPACE); +} + +/* + * Test whether a block of memory is a valid user space address. + * Returns 0 if the range is valid, nonzero otherwise. + * + * We do the following checks: + * 1. Is the access from kernel space? + * 2. Does (addr + size) set the carry bit? + * 3. Is (addr + size) a negative number (i.e. >= 0x80000000)? + * + * If yes on the first check, access is granted. + * If no on any of the others, access is denied. + */ +#define __range_ok(addr, size) \ + (test_thread_flag(TIF_USERSPACE) \ + && (((unsigned long)(addr) >= 0x80000000) \ + || ((unsigned long)(size) > 0x80000000) \ + || (((unsigned long)(addr) + (unsigned long)(size)) > 0x80000000))) + +#define access_ok(type, addr, size) (likely(__range_ok(addr, size) == 0)) + +static inline int +verify_area(int type, const void __user *addr, unsigned long size) +{ + return access_ok(type, addr, size) ? 0 : -EFAULT; +} + +/* Generic arbitrary sized copy. Return the number of bytes NOT copied */ +extern __kernel_size_t __copy_user(void *to, const void *from, + __kernel_size_t n); + +extern __kernel_size_t copy_to_user(void __user *to, const void *from, + __kernel_size_t n); +extern __kernel_size_t copy_from_user(void *to, const void __user *from, + __kernel_size_t n); + +static inline __kernel_size_t __copy_to_user(void __user *to, const void *from, + __kernel_size_t n) +{ + return __copy_user((void __force *)to, from, n); +} +static inline __kernel_size_t __copy_from_user(void *to, + const void __user *from, + __kernel_size_t n) +{ + return __copy_user(to, (const void __force *)from, n); +} + +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + +/* + * put_user: - Write a simple value into user space. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Returns zero on success, or -EFAULT on error. + */ +#define put_user(x,ptr) \ + __put_user_check((x),(ptr),sizeof(*(ptr))) + +/* + * get_user: - Get a simple variable from user space. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ +#define get_user(x,ptr) \ + __get_user_check((x),(ptr),sizeof(*(ptr))) + +/* + * __put_user: - Write a simple value into user space, with less checking. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Caller must check the pointer with access_ok() before calling this + * function. + * + * Returns zero on success, or -EFAULT on error. + */ +#define __put_user(x,ptr) \ + __put_user_nocheck((x),(ptr),sizeof(*(ptr))) + +/* + * __get_user: - Get a simple variable from user space, with less checking. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Caller must check the pointer with access_ok() before calling this + * function. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ +#define __get_user(x,ptr) \ + __get_user_nocheck((x),(ptr),sizeof(*(ptr))) + +extern int __get_user_bad(void); +extern int __put_user_bad(void); + +#define __get_user_nocheck(x, ptr, size) \ +({ \ + typeof(*(ptr)) __gu_val = (typeof(*(ptr)) __force)0; \ + int __gu_err = 0; \ + \ + switch (size) { \ + case 1: __get_user_asm("ub", __gu_val, ptr, __gu_err); break; \ + case 2: __get_user_asm("uh", __gu_val, ptr, __gu_err); break; \ + case 4: __get_user_asm("w", __gu_val, ptr, __gu_err); break; \ + case 8: __get_user_asm("d", __gu_val, ptr, __gu_err); break; \ + default: __gu_err = __get_user_bad(); break; \ + } \ + \ + x = __gu_val; \ + __gu_err; \ +}) + +#define __get_user_check(x, ptr, size) \ +({ \ + typeof(*(ptr)) __gu_val = (typeof(*(ptr)) __force)0; \ + const typeof(*(ptr)) __user * __gu_addr = (ptr); \ + int __gu_err = 0; \ + \ + if (access_ok(VERIFY_READ, __gu_addr, size)) { \ + switch (size) { \ + case 1: \ + __get_user_asm("ub", __gu_val, __gu_addr, \ + __gu_err); \ + break; \ + case 2: \ + __get_user_asm("uh", __gu_val, __gu_addr, \ + __gu_err); \ + break; \ + case 4: \ + __get_user_asm("w", __gu_val, __gu_addr, \ + __gu_err); \ + break; \ + case 8: \ + __get_user_asm("d", __gu_val, __gu_addr, \ + __gu_err); \ + break; \ + default: \ + __gu_err = __get_user_bad(); \ + break; \ + } \ + } else { \ + __gu_err = -EFAULT; \ + } \ + x = __gu_val; \ + __gu_err; \ +}) + +#define __get_user_asm(suffix, __gu_val, ptr, __gu_err) \ + asm volatile( \ + "1: ld." suffix " %1, %3 \n" \ + "2: \n" \ + " .section .fixup, \"ax\" \n" \ + "3: mov %0, %4 \n" \ + " rjmp 2b \n" \ + " .previous \n" \ + " .section __ex_table, \"a\" \n" \ + " .long 1b, 3b \n" \ + " .previous \n" \ + : "=r"(__gu_err), "=r"(__gu_val) \ + : "0"(__gu_err), "m"(*(ptr)), "i"(-EFAULT)) + +#define __put_user_nocheck(x, ptr, size) \ +({ \ + typeof(*(ptr)) __pu_val; \ + int __pu_err = 0; \ + \ + __pu_val = (x); \ + switch (size) { \ + case 1: __put_user_asm("b", ptr, __pu_val, __pu_err); break; \ + case 2: __put_user_asm("h", ptr, __pu_val, __pu_err); break; \ + case 4: __put_user_asm("w", ptr, __pu_val, __pu_err); break; \ + case 8: __put_user_asm("d", ptr, __pu_val, __pu_err); break; \ + default: __pu_err = __put_user_bad(); break; \ + } \ + __pu_err; \ +}) + +#define __put_user_check(x, ptr, size) \ +({ \ + typeof(*(ptr)) __pu_val; \ + typeof(*(ptr)) __user *__pu_addr = (ptr); \ + int __pu_err = 0; \ + \ + __pu_val = (x); \ + if (access_ok(VERIFY_WRITE, __pu_addr, size)) { \ + switch (size) { \ + case 1: \ + __put_user_asm("b", __pu_addr, __pu_val, \ + __pu_err); \ + break; \ + case 2: \ + __put_user_asm("h", __pu_addr, __pu_val, \ + __pu_err); \ + break; \ + case 4: \ + __put_user_asm("w", __pu_addr, __pu_val, \ + __pu_err); \ + break; \ + case 8: \ + __put_user_asm("d", __pu_addr, __pu_val, \ + __pu_err); \ + break; \ + default: \ + __pu_err = __put_user_bad(); \ + break; \ + } \ + } else { \ + __pu_err = -EFAULT; \ + } \ + __pu_err; \ +}) + +#define __put_user_asm(suffix, ptr, __pu_val, __gu_err) \ + asm volatile( \ + "1: st." suffix " %1, %3 \n" \ + "2: \n" \ + " .section .fixup, \"ax\" \n" \ + "3: mov %0, %4 \n" \ + " rjmp 2b \n" \ + " .previous \n" \ + " .section __ex_table, \"a\" \n" \ + " .long 1b, 3b \n" \ + " .previous \n" \ + : "=r"(__gu_err), "=m"(*(ptr)) \ + : "0"(__gu_err), "r"(__pu_val), "i"(-EFAULT)) + +extern __kernel_size_t clear_user(void __user *addr, __kernel_size_t size); +extern __kernel_size_t __clear_user(void __user *addr, __kernel_size_t size); + +extern long strncpy_from_user(char *dst, const char __user *src, long count); +extern long __strncpy_from_user(char *dst, const char __user *src, long count); + +extern long strnlen_user(const char __user *__s, long __n); +extern long __strnlen_user(const char __user *__s, long __n); + +#define strlen_user(s) strnlen_user(s, ~0UL >> 1) + +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +#endif /* __ASM_AVR32_UACCESS_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/ucontext.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/ucontext.h --- linux-2.6.16.11/include/asm-avr32/ucontext.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/ucontext.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,12 @@ +#ifndef __ASM_AVR32_UCONTEXT_H +#define __ASM_AVR32_UCONTEXT_H + +struct ucontext { + unsigned long uc_flags; + struct ucontext * uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; +}; + +#endif /* __ASM_AVR32_UCONTEXT_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/unaligned.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/unaligned.h --- linux-2.6.16.11/include/asm-avr32/unaligned.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/unaligned.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,25 @@ +#ifndef __ASM_AVR32_UNALIGNED_H +#define __ASM_AVR32_UNALIGNED_H + +/* + * AVR32 can handle some unaligned accesses, depending on the + * implementation. The AVR32 AP implementation can handle unaligned + * words, but halfwords must be halfword-aligned, and doublewords must + * be word-aligned. + * + * TODO: Make all this CPU-specific and optimize. + */ + +#include + +/* Use memmove here, so gcc does not insert a __builtin_memcpy. */ + +#define get_unaligned(ptr) \ + ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; }) + +#define put_unaligned(val, ptr) \ + ({ __typeof__(*(ptr)) __tmp = (val); \ + memmove((ptr), &__tmp, sizeof(*(ptr))); \ + (void)0; }) + +#endif /* __ASM_AVR32_UNALIGNED_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/unistd.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/unistd.h --- linux-2.6.16.11/include/asm-avr32/unistd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/unistd.h 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,462 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_UNISTD_H +#define __ASM_AVR32_UNISTD_H + +/* + * This file contains the system call numbers. + */ + +#define __NR_restart_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_umask 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_lchown 17 +#define __NR_lseek 18 +#define __NR__llseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount2 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_pause 28 +#define __NR_utime 29 +#define __NR_stat 30 +#define __NR_fstat 31 +#define __NR_lstat 32 +#define __NR_access 33 +#define __NR_chroot 34 +#define __NR_sync 35 +#define __NR_fsync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_clone 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_getcwd 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_setfsuid 52 +#define __NR_setfsgid 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_setpgid 56 +#define __NR_mremap 57 +#define __NR_setresuid 58 +#define __NR_getresuid 59 +#define __NR_setreuid 60 +#define __NR_setregid 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_rt_sigaction 67 +#define __NR_rt_sigreturn 68 +#define __NR_rt_sigprocmask 69 +#define __NR_rt_sigpending 70 +#define __NR_rt_sigtimedwait 71 +#define __NR_rt_sigqueueinfo 72 +#define __NR_rt_sigsuspend 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 /* SuS compliant getrlimit */ +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_fchdir 84 +#define __NR_readlink 85 +#define __NR_pread 86 +#define __NR_pwrite 87 +#define __NR_swapon 88 +#define __NR_reboot 89 +#define __NR_mmap2 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_wait4 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_vhangup 101 +#define __NR_sigaltstack 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_swapoff 106 +#define __NR_sysinfo 107 +#define __NR_ipc 108 +#define __NR_sendfile 109 +#define __NR_setdomainname 110 +#define __NR_uname 111 +#define __NR_adjtimex 112 +#define __NR_mprotect 113 +#define __NR_vfork 114 +#define __NR_init_module 115 +#define __NR_delete_module 116 +#define __NR_quotactl 117 +#define __NR_getpgid 118 +#define __NR_bdflush 119 +#define __NR_sysfs 120 +#define __NR_personality 121 +#define __NR_afs_syscall 122 /* Syscall for Andrew File System */ +#define __NR_getdents 123 +#define __NR_flock 124 +#define __NR_msync 125 +#define __NR_readv 126 +#define __NR_writev 127 +#define __NR_getsid 128 +#define __NR_fdatasync 129 +#define __NR__sysctl 130 +#define __NR_mlock 131 +#define __NR_munlock 132 +#define __NR_mlockall 133 +#define __NR_munlockall 134 +#define __NR_sched_setparam 135 +#define __NR_sched_getparam 136 +#define __NR_sched_setscheduler 137 +#define __NR_sched_getscheduler 138 +#define __NR_sched_yield 139 +#define __NR_sched_get_priority_max 140 +#define __NR_sched_get_priority_min 141 +#define __NR_sched_rr_get_interval 142 +#define __NR_nanosleep 143 +#define __NR_poll 144 +#define __NR_nfsservctl 145 +#define __NR_setresgid 146 +#define __NR_getresgid 147 +#define __NR_prctl 148 +#define __NR_socket 149 +#define __NR_bind 150 +#define __NR_connect 151 +#define __NR_listen 152 +#define __NR_accept 153 +#define __NR_getsockname 154 +#define __NR_getpeername 155 +#define __NR_socketpair 156 +#define __NR_send 157 +#define __NR_recv 158 +#define __NR_sendto 159 +#define __NR_recvfrom 160 +#define __NR_shutdown 161 +#define __NR_setsockopt 162 +#define __NR_getsockopt 163 +#define __NR_sendmsg 164 +#define __NR_recvmsg 165 +#define __NR_truncate64 166 +#define __NR_ftruncate64 167 +#define __NR_stat64 168 +#define __NR_lstat64 169 +#define __NR_fstat64 170 +#define __NR_pivot_root 171 +#define __NR_mincore 172 +#define __NR_madvise 173 +#define __NR_getdents64 174 +#define __NR_fcntl64 175 +#define __NR_gettid 176 +#define __NR_readahead 177 +#define __NR_setxattr 178 +#define __NR_lsetxattr 179 +#define __NR_fsetxattr 180 +#define __NR_getxattr 181 +#define __NR_lgetxattr 182 +#define __NR_fgetxattr 183 +#define __NR_listxattr 184 +#define __NR_llistxattr 185 +#define __NR_flistxattr 186 +#define __NR_removexattr 187 +#define __NR_lremovexattr 188 +#define __NR_fremovexattr 189 +#define __NR_tkill 190 +#define __NR_sendfile64 191 +#define __NR_futex 192 +#define __NR_sched_setaffinity 193 +#define __NR_sched_getaffinity 194 +#define __NR_capget 195 +#define __NR_capset 196 +#define __NR_io_setup 197 +#define __NR_io_destroy 198 +#define __NR_io_getevents 199 +#define __NR_io_submit 200 +#define __NR_io_cancel 201 +#define __NR_fadvise64 202 +#define __NR_exit_group 203 +#define __NR_lookup_dcookie 204 +#define __NR_epoll_create 205 +#define __NR_epoll_ctl 206 +#define __NR_epoll_wait 207 +#define __NR_remap_file_pages 208 +#define __NR_set_tid_address 209 + +#define __NR_timer_create 210 +#define __NR_timer_settime 211 +#define __NR_timer_gettime 212 +#define __NR_timer_getoverrun 213 +#define __NR_timer_delete 214 +#define __NR_clock_settime 215 +#define __NR_clock_gettime 216 +#define __NR_clock_getres 217 +#define __NR_clock_nanosleep 218 +#define __NR_statfs64 219 +#define __NR_fstatfs64 220 +#define __NR_tgkill 221 + /* 222 reserved for tux */ +#define __NR_utimes 223 +#define __NR_fadvise64_64 224 + +/* AVR32-specific syscalls */ +#define __NR_cacheflush 225 +#define __NR_avm_init 226 +#define __NR_avm_invoke 227 +#define __NR_avm_return 228 + +#define NR_syscalls 229 + + +/* + * AVR32 calling convention for system calls: + * - System call number in r8 + * - Parameters in r12 and downwards to r9 as well as r6 and r5. + * - Return value in r12 + */ + +/* + * user-visible error numbers are in the range -1 - -124: see + * + */ + +#define __syscall_return(type, res) do { \ + if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + errno = -(res); \ + res = -1; \ + } \ + return (type) (res); \ + } while (0) + +/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ +#define _syscall0(type,name) \ + type name(void) \ + { \ + register long __scno __asm__ ("r8") = __NR_##name; \ + register long __sc1 __asm__ ("r12"); \ + long __res; \ + __asm__ __volatile__ ("scall" \ + : "=r" (__sc1) \ + : "r" (__scno) \ + : "lr", "memory"); \ + __res = __sc1; \ + __syscall_return (type, __res); \ + } + +#define _syscall1(type,name,type1,arg1) \ + type name(type1 arg1) \ + { \ + register long __scno __asm__ ("r8") = __NR_##name; \ + register long __sc1 __asm__ ("r12") = (long)arg1; \ + long __res; \ + __asm__ __volatile__ ("scall" \ + : "=r" (__sc1) \ + : "r" (__scno), "0" (__sc1) \ + : "lr", "memory"); \ + __res = __sc1; \ + __syscall_return (type, __res); \ + } + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ + type name(type1 arg1,type2 arg2) \ + { \ + register long __scno __asm__ ("r8") = __NR_##name; \ + register long __sc1 __asm__ ("r12") = (long)arg1; \ + register long __sc2 __asm__ ("r11") = (long)arg2; \ + long __res; \ + __asm__ __volatile__ ("scall" \ + : "=r" (__sc1) \ + : "r" (__scno), "0" (__sc1), \ + "r" (__sc2) \ + : "lr", "memory"); \ + __res = __sc1; \ + __syscall_return (type, __res); \ + } + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ + type name(type1 arg1,type2 arg2,type3 arg3) \ + { \ + register long __scno __asm__ ("r8") = __NR_##name; \ + register long __sc1 __asm__ ("r12") = (long)arg1; \ + register long __sc2 __asm__ ("r11") = (long)arg2; \ + register long __sc3 __asm__ ("r10") = (long)arg3; \ + long __res; \ + __asm__ __volatile__ ("scall" \ + : "=r" (__sc1) \ + : "r" (__scno), "0" (__sc1), \ + "r" (__sc2), "r" (__sc3) \ + : "lr", "memory"); \ + __res = __sc1; \ + __syscall_return (type, __res); \ + } + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ + { \ + register long __scno __asm__ ("r8") = __NR_##name; \ + register long __sc1 __asm__ ("r12") = (long)arg1; \ + register long __sc2 __asm__ ("r11") = (long)arg2; \ + register long __sc3 __asm__ ("r10") = (long)arg3; \ + register long __sc4 __asm__ ("r9") = (long)arg4; \ + long __res; \ + __asm__ __volatile__ ("scall" \ + : "=r" (__sc1) \ + : "r" (__scno), "r" (__sc1), \ + "r" (__sc2), "r" (__sc3), \ + "r" (__sc4) \ + : "lr", "memory"); \ + __res = __sc1; \ + __syscall_return (type, __res); \ + } + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3, \ + type4,arg4,type5,arg5) \ + type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ + { \ + register long __scno __asm__ ("r8") = __NR_##name; \ + register long __sc1 __asm__ ("r12") = (long)arg1; \ + register long __sc2 __asm__ ("r11") = (long)arg2; \ + register long __sc3 __asm__ ("r10") = (long)arg3; \ + register long __sc4 __asm__ ("r9") = (long)arg4; \ + register long __sc5 __asm__ ("r5") = (long)arg5; \ + long __res; \ + __asm__ __volatile__ ("scall" \ + : "=r" (__sc1) \ + : "r" (__scno), "0" (__sc1), \ + "r" (__sc2), "r" (__sc3), \ + "r" (__sc4), "r" (__sc5) \ + : "lr", "memory"); \ + __res = __sc1; \ + __syscall_return (type, __res); \ + } + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3, \ + type4,arg4,type5,arg5,type6,arg6) \ + type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ + { \ + register long __scno __asm__ ("r8"); \ + register long __sc1 __asm__ ("r12") = (long)arg1; \ + register long __sc2 __asm__ ("r11") = (long)arg2; \ + register long __sc3 __asm__ ("r10") = (long)arg3; \ + register long __sc4 __asm__ ("r9") = (long)arg4; \ + register long __sc5 __asm__ ("r5") = (long)arg5; \ + register long __sc6 __asm__ ("r3") = (long)arg6; \ + long __res; \ + __asm__ __volatile__ ("scall" \ + : "=r" (__sc1) \ + : "r" (__scno), "0" (__sc1), \ + "r" (__sc2), "r" (__sc3), \ + "r" (__sc4), "r" (__sc5), \ + "r" (__sc6) \ + : "lr", "memory"); \ + __res = __sc1; \ + __syscall_return (type, __res); \ + } + +#ifdef __KERNEL__ +#define __ARCH_WANT_STAT64 +#define __ARCH_WANT_SYS_ALARM +#define __ARCH_WANT_SYS_GETHOSTNAME +#define __ARCH_WANT_SYS_PAUSE +#define __ARCH_WANT_SYS_TIME +#define __ARCH_WANT_SYS_UTIME +#define __ARCH_WANT_SYS_WAITPID +#define __ARCH_WANT_SYS_FADVISE64 +#define __ARCH_WANT_SYS_GETPGRP +#define __ARCH_WANT_SYS_LLSEEK +#define __ARCH_WANT_SYS_GETPGRP +#define __ARCH_WANT_SYS_RT_SIGACTION +#define __ARCH_WANT_SYS_RT_SIGSUSPEND +#endif + +#if defined(__KERNEL_SYSCALLS__) || defined(__CHECKER__) + +#include +#include +#include + +struct pt_regs; + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) + +asmlinkage int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, + struct pt_regs *regs); +asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, + struct pt_regs *regs); +asmlinkage int sys_rt_sigreturn(struct pt_regs *regs); +asmlinkage int sys_pipe(unsigned long __user *filedes); +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset); +asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len); +asmlinkage int sys_fork(struct pt_regs *regs); +asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, + unsigned long parent_tidptr, + unsigned long child_tidptr, struct pt_regs *regs); +asmlinkage int sys_vfork(struct pt_regs *regs); +asmlinkage int sys_execve(char __user *ufilename, char __user *__user *uargv, + char __user *__user *uenvp, struct pt_regs *regs); + +#endif + +/* + * "Conditional" syscalls + * + * What we want is __attribute__((weak,alias("sys_ni_syscall"))), + * but it doesn't work on all toolchains, so we just do it by hand + */ +#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); + +#endif /* __ASM_AVR32_UNISTD_H */ diff -Nur linux-2.6.16.11/include/asm-avr32/user.h linux-2.6.16.11-avr32-20060626/include/asm-avr32/user.h --- linux-2.6.16.11/include/asm-avr32/user.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/asm-avr32/user.h 2006-06-26 11:33:52.000000000 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Note: We may not need these definitions for AVR32, as we don't + * support a.out. + */ +#ifndef __ASM_AVR32_USER_H +#define __ASM_AVR32_USER_H + +#include +#include +#include +#include + +/* + * Core file format: The core file is written in such a way that gdb + * can understand it and provide useful information to the user (under + * linux we use the `trad-core' bfd). The file contents are as follows: + * + * upage: 1 page consisting of a user struct that tells gdb + * what is present in the file. Directly after this is a + * copy of the task_struct, which is currently not used by gdb, + * but it may come in handy at some point. All of the registers + * are stored as part of the upage. The upage should always be + * only one page long. + * data: The data segment follows next. We use current->end_text to + * current->brk to pick up all of the user variables, plus any memory + * that may have been sbrk'ed. No attempt is made to determine if a + * page is demand-zero or if a page is totally unused, we just cover + * the entire range. All of the addresses are rounded in such a way + * that an integral number of pages is written. + * stack: We need the stack information in order to get a meaningful + * backtrace. We need to write the data from usp to + * current->start_stack, so we round each of these in order to be able + * to write an integer number of pages. + */ + +struct user_fpu_struct { + /* We have no FPU (yet) */ +}; + +struct user { + struct pt_regs regs; /* entire machine state */ + size_t u_tsize; /* text size (pages) */ + size_t u_dsize; /* data size (pages) */ + size_t u_ssize; /* stack size (pages) */ + unsigned long start_code; /* text starting address */ + unsigned long start_data; /* data starting address */ + unsigned long start_stack; /* stack starting address */ + long int signal; /* signal causing core dump */ + struct regs * u_ar0; /* help gdb find registers */ + unsigned long magic; /* identifies a core file */ + char u_comm[32]; /* user command name */ +}; + +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_DATA_START_ADDR (u.start_data) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif /* __ASM_AVR32_USER_H */ diff -Nur linux-2.6.16.11/include/linux/elf.h linux-2.6.16.11-avr32-20060626/include/linux/elf.h --- linux-2.6.16.11/include/linux/elf.h 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/linux/elf.h 2006-06-26 11:33:53.000000000 +0200 @@ -111,6 +111,9 @@ */ #define EM_S390_OLD 0xA390 +/* AVR32 magic number from the ELF/DWARF AVR32 Addendum (IAR Systems). */ +#define EM_AVR32 0x18ad + #define EM_FRV 0x5441 /* Fujitsu FR-V */ /* This is the info that is needed to parse the dynamic section of the file */ diff -Nur linux-2.6.16.11/include/linux/fb.h linux-2.6.16.11-avr32-20060626/include/linux/fb.h --- linux-2.6.16.11/include/linux/fb.h 2006-06-26 11:34:39.000000000 +0200 +++ linux-2.6.16.11-avr32-20060626/include/linux/fb.h 2006-06-26 11:33:53.000000000 +0200 @@ -191,6 +191,7 @@ /* vtotal = 144d/288n/576i => PAL */ /* vtotal = 121d/242n/484i => NTSC */ #define FB_SYNC_ON_GREEN 32 /* sync on green */ +#define FB_SYNC_PCLK_RISING 64 /* pixel data sampled on rising pclk */ #define FB_VMODE_NONINTERLACED 0 /* non interlaced */ #define FB_VMODE_INTERLACED 1 /* interlaced */ @@ -809,7 +810,7 @@ #define fb_writeq sbus_writeq #define fb_memset sbus_memset_io -#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) +#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) || defined(__avr32__) #define fb_readb __raw_readb #define fb_readw __raw_readw diff -Nur linux-2.6.16.11/include/linux/serial_core.h linux-2.6.16.11-avr32-20060626/include/linux/serial_core.h --- linux-2.6.16.11/include/linux/serial_core.h 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/include/linux/serial_core.h 2006-06-26 11:33:51.000000000 +0200 @@ -159,6 +159,7 @@ void (*break_ctl)(struct uart_port *, int ctl); int (*startup)(struct uart_port *); void (*shutdown)(struct uart_port *); + void (*flush_buffer)(struct uart_port *); void (*set_termios)(struct uart_port *, struct termios *new, struct termios *old); void (*pm)(struct uart_port *, unsigned int state, diff -Nur linux-2.6.16.11/kernel/softirq.c linux-2.6.16.11-avr32-20060626/kernel/softirq.c --- linux-2.6.16.11/kernel/softirq.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/kernel/softirq.c 2006-06-26 11:33:51.000000000 +0200 @@ -152,10 +152,14 @@ } EXPORT_SYMBOL(local_bh_enable); -#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED -# define invoke_softirq() __do_softirq() +#ifdef CONFIG_AVR32 +# define invoke_softirq() set_thread_flag(TIF_SOFTIRQ) #else -# define invoke_softirq() do_softirq() +# ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED +# define invoke_softirq() __do_softirq() +# else +# define invoke_softirq() do_softirq() +# endif #endif /* diff -Nur linux-2.6.16.11/lib/Kconfig.debug linux-2.6.16.11-avr32-20060626/lib/Kconfig.debug --- linux-2.6.16.11/lib/Kconfig.debug 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/lib/Kconfig.debug 2006-06-26 11:33:53.000000000 +0200 @@ -136,7 +136,7 @@ config DEBUG_BUGVERBOSE bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED depends on BUG - depends on ARM || ARM26 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV + depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV default !EMBEDDED help Say Y here to make BUG() panics output the file name and line number @@ -187,7 +187,7 @@ config FRAME_POINTER bool "Compile the kernel with frame pointers" - depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML) + depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || AVR32) default y if DEBUG_INFO && UML help If you say Y here the resulting kernel image will be slightly larger diff -Nur linux-2.6.16.11/scripts/checkstack.pl linux-2.6.16.11-avr32-20060626/scripts/checkstack.pl --- linux-2.6.16.11/scripts/checkstack.pl 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/scripts/checkstack.pl 2006-06-26 11:33:53.000000000 +0200 @@ -12,6 +12,7 @@ # sh64 port by Paul Mundt # Random bits by Matt Mackall # M68k port by Geert Uytterhoeven and Andreas Schwab +# AVR32 port by Haavard Skinnemoen # # Usage: # objdump -d vmlinux | stackcheck.pl [arch] @@ -37,6 +38,10 @@ if ($arch eq 'arm') { #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'avr32') { + #8000008a: 20 1d sub sp,4 + #80000ca8: fa cd 05 b0 sub sp,sp,1456 + $re = qr/^.*sub.*sp.*,([0-9]{1,8})/o; } elsif ($arch =~ /^i[3456]86$/) { #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o; diff -Nur linux-2.6.16.11/sound/avr32/ac97c.c linux-2.6.16.11-avr32-20060626/sound/avr32/ac97c.c --- linux-2.6.16.11/sound/avr32/ac97c.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/avr32/ac97c.c 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,1244 @@ +/* + * Driver for the Atmel AC97 Controller + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifndef SND_ATMEL_AC97_USE_ALSA_MALLOC_CALLS +#include +#endif + +#include +#include +#include + +#include + +#include "ac97c.h" + +static DEFINE_MUTEX(opened_mutex); + +/* module parameters */ +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for AC97 controller"); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for AC97 controller"); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable AC97 controller"); + +#ifndef CONFIG_SND_ATMEL_AC97C_USE_PDC +#include + +struct atmel_ac97_dma_info { + struct dma_request_cyclic req_tx; + struct dma_request_cyclic req_rx; + unsigned short rx_periph_id; + unsigned short tx_periph_id; +}; +#endif + + +typedef struct atmel_ac97 { + spinlock_t lock; + void __iomem *regs; + int period; + + snd_pcm_substream_t *playback_substream; + snd_pcm_substream_t *capture_substream; + snd_card_t *card; + snd_pcm_t *pcm; + ac97_t *ac97; + ac97_bus_t *ac97_bus; + int irq; + char opened; + u64 cur_format; + unsigned int cur_rate; + struct at32_device *adev; + struct atmel_ac97_dma_info dma; +} atmel_ac97_t; +#define get_chip(card) ((atmel_ac97_t *)(card)->private_data) + +#define ac97c_writel(chip, reg, val) \ + writel((val), (chip)->regs + AC97C_##reg) +#define ac97c_readl(chip, reg) \ + readl((chip)->regs + AC97C_##reg) + +/* PCM part */ +static snd_pcm_hardware_t snd_atmel_ac97_playback_hw = { + .info = (SNDRV_PCM_INFO_INTERLEAVED + |SNDRV_PCM_INFO_MMAP + |SNDRV_PCM_INFO_MMAP_VALID + |SNDRV_PCM_INFO_BLOCK_TRANSFER + |SNDRV_PCM_INFO_JOINT_DUPLEX), + .formats = (SNDRV_PCM_FMTBIT_S16_BE|SNDRV_PCM_FMTBIT_S16_LE), + .rates = (SNDRV_PCM_RATE_CONTINUOUS), + .rate_min = 4000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 6, + .buffer_bytes_max = 64*1024, + .period_bytes_min = 512, +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + .period_bytes_max = 64*1024, +#else + .period_bytes_max = 4095, +#endif + .periods_min = 8, + .periods_max = 1024, +}; + +static snd_pcm_hardware_t snd_atmel_ac97_capture_hw = { + .info = (SNDRV_PCM_INFO_INTERLEAVED + |SNDRV_PCM_INFO_MMAP + |SNDRV_PCM_INFO_MMAP_VALID + |SNDRV_PCM_INFO_BLOCK_TRANSFER + |SNDRV_PCM_INFO_JOINT_DUPLEX), + .formats = (SNDRV_PCM_FMTBIT_S16_BE|SNDRV_PCM_FMTBIT_S16_LE), + .rates = (SNDRV_PCM_RATE_CONTINUOUS), + .rate_min = 4000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = 64*1024, + .period_bytes_min = 512, +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + .period_bytes_max = 64*1024, +#else + .period_bytes_max = 4095, +#endif + .periods_min = 8, + .periods_max = 1024, +}; + +/* Joint full duplex variables */ +unsigned int hw_rates[1]; +unsigned int hw_formats[1]; +struct snd_pcm_hw_constraint_list hw_constraint_rates; +struct snd_pcm_hw_constraint_list hw_constraint_formats; + +/* + * PCM functions + */ +static int +snd_atmel_ac97_playback_open(snd_pcm_substream_t *substream) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + mutex_lock(&opened_mutex); + chip->opened++; + runtime->hw = snd_atmel_ac97_playback_hw; + if (chip->cur_rate) { + runtime->hw.rate_min = chip->cur_rate; + runtime->hw.rate_max = chip->cur_rate; + } + if (chip->cur_format) + runtime->hw.formats = (1ULL<cur_format); + mutex_unlock(&opened_mutex); + chip->playback_substream = substream; + chip->period = 0; + return 0; +} + +static int +snd_atmel_ac97_capture_open(snd_pcm_substream_t *substream) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + mutex_lock(&opened_mutex); + chip->opened++; + runtime->hw = snd_atmel_ac97_capture_hw; + if (chip->cur_rate) { + runtime->hw.rate_min = chip->cur_rate; + runtime->hw.rate_max = chip->cur_rate; + } + if (chip->cur_format) + runtime->hw.formats = (1ULL<cur_format); + mutex_unlock(&opened_mutex); + chip->capture_substream = substream; + chip->period = 0; + return 0; +} + +static int snd_atmel_ac97_playback_close(snd_pcm_substream_t *substream) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + mutex_lock(&opened_mutex); + chip->opened--; + if (!chip->opened) { + chip->cur_rate = 0; + chip->cur_format = 0; + } + mutex_unlock(&opened_mutex); + return 0; +} + +static int snd_atmel_ac97_capture_close(snd_pcm_substream_t *substream) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + mutex_lock(&opened_mutex); + chip->opened--; + if (!chip->opened) { + chip->cur_rate = 0; + chip->cur_format = 0; + } + mutex_unlock(&opened_mutex); + return 0; +} + +static int snd_atmel_ac97_playback_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *hw_params) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); +#ifdef SND_ATMEL_AC97_USE_ALSA_MALLOC_CALLS + int err; + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + + if (err < 0) + return err; + + /* Set restrictions to params */ + mutex_lock(&opened_mutex); + chip->cur_rate = params_rate(hw_params); + chip->cur_format = params_format(hw_params); + mutex_unlock(&opened_mutex); + + return err; +#else + int pg; + size_t size = params_buffer_bytes(hw_params); + struct snd_pcm_runtime *runtime; + struct snd_dma_buffer *dmab = NULL; + + substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV; + snd_assert(substream != NULL, return -EINVAL); + runtime = substream->runtime; + snd_assert(runtime != NULL, return -EINVAL); + + /* Set restrictions to params */ + mutex_lock(&opened_mutex); + chip->cur_rate = params_rate(hw_params); + chip->cur_format = params_format(hw_params); + mutex_unlock(&opened_mutex); + + /* check if buffer is already allocated */ + if (runtime->dma_buffer_p) { + size_t size_previouse; + int pg_previouse; + + /* new buffer is smaler than previouse allocated buffer */ + if (runtime->dma_buffer_p->bytes >= size) { + runtime->dma_bytes = size; + return 0; /* don't change buffer size */ + } + + size_previouse = runtime->dma_buffer_p->bytes; + pg_previouse = get_order(size_previouse); + + dma_free_coherent(runtime->dma_buffer_p->dev.dev, + PAGE_SIZE << pg_previouse, + runtime->dma_buffer_p->area, + runtime->dma_buffer_p->addr); + + kfree(runtime->dma_buffer_p); + } + + dmab = kzalloc(sizeof(*dmab), GFP_KERNEL); + if (!dmab) + return -ENOMEM; + + dmab->dev = substream->dma_buffer.dev; + dmab->bytes = 0; + + pg = get_order(size); + + dmab->area = dma_alloc_coherent( + substream->dma_buffer.dev.dev, + PAGE_SIZE << pg, + (dma_addr_t *)&dmab->addr, + GFP_KERNEL); + + if (!dmab->area) { + kfree(dmab); + return -ENOMEM; + } + + dmab->bytes = size; + + snd_pcm_set_runtime_buffer(substream, dmab); + runtime->dma_bytes = size; + return 1; +#endif +} + +static int snd_atmel_ac97_capture_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *hw_params) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); +#ifdef SND_ATMEL_AC97_USE_ALSA_MALLOC_CALLS + int err; + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + + if (err < 0) + return err; + + /* Set restrictions to params */ + mutex_lock(&opened_mutex); + chip->cur_rate = params_rate(hw_params); + chip->cur_format = params_format(hw_params); + mutex_unlock(&opened_mutex); + + return err; +#else + int pg; + size_t size = params_buffer_bytes(hw_params); + struct snd_pcm_runtime *runtime; + struct snd_dma_buffer *dmab = NULL; + + substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV; + snd_assert(substream != NULL, return -EINVAL); + runtime = substream->runtime; + snd_assert(runtime != NULL, return -EINVAL); + + /* Set restrictions to params */ + mutex_lock(&opened_mutex); + chip->cur_rate = params_rate(hw_params); + chip->cur_format = params_format(hw_params); + mutex_unlock(&opened_mutex); + + /* check if buffer is already allocated */ + if (runtime->dma_buffer_p) { + size_t size_previouse; + int pg_previouse; + + /* new buffer is smaler than previouse allocated buffer */ + if (runtime->dma_buffer_p->bytes >= size) { + runtime->dma_bytes = size; + return 0; /* don't change buffer size */ + } + + size_previouse = runtime->dma_buffer_p->bytes; + pg_previouse = get_order(size_previouse); + + dma_free_coherent(runtime->dma_buffer_p->dev.dev, + PAGE_SIZE << pg_previouse, + runtime->dma_buffer_p->area, + runtime->dma_buffer_p->addr); + + kfree(runtime->dma_buffer_p); + } + + dmab = kzalloc(sizeof(*dmab), GFP_KERNEL); + if (!dmab) + return -ENOMEM; + + dmab->dev = substream->dma_buffer.dev; + dmab->bytes = 0; + + pg = get_order(size); + + dmab->area = dma_alloc_coherent( + substream->dma_buffer.dev.dev, + PAGE_SIZE << pg, + (dma_addr_t *)&dmab->addr, + GFP_KERNEL); + + if (!dmab->area) { + kfree(dmab); + return -ENOMEM; + } + + dmab->bytes = size; + + snd_pcm_set_runtime_buffer(substream, dmab); + runtime->dma_bytes = size; + return 1; +#endif +} + +static int snd_atmel_ac97_playback_hw_free(snd_pcm_substream_t *substream) +{ + +#ifdef SND_ATMEL_AC97_USE_ALSA_MALLOC_CALLS + return snd_pcm_lib_free_pages(substream); +#else + int pg; + struct snd_pcm_runtime *runtime; + struct snd_dma_buffer *dmab = NULL; + + snd_assert(substream != NULL, return -EINVAL); + runtime = substream->runtime; + snd_assert(runtime != NULL, return -EINVAL); + dmab = runtime->dma_buffer_p; + + if (!dmab) + return 0; + + if (!dmab->area) + return 0; + + pg = get_order(dmab->bytes); + dma_free_coherent(dmab->dev.dev, PAGE_SIZE << pg, dmab->area, dmab->addr); + kfree(runtime->dma_buffer_p); + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +#endif +} + +static int snd_atmel_ac97_capture_hw_free(snd_pcm_substream_t *substream) +{ + +#ifdef SND_ATMEL_AC97_USE_ALSA_MALLOC_CALLS + return snd_pcm_lib_free_pages(substream); +#else + int pg; + struct snd_pcm_runtime *runtime; + struct snd_dma_buffer *dmab = NULL; + + snd_assert(substream != NULL, return -EINVAL); + runtime = substream->runtime; + snd_assert(runtime != NULL, return -EINVAL); + dmab = runtime->dma_buffer_p; + + if (!dmab) + return 0; + + if (!dmab->area) + return 0; + + pg = get_order(dmab->bytes); + dma_free_coherent(dmab->dev.dev, PAGE_SIZE << pg, dmab->area, dmab->addr); + kfree(runtime->dma_buffer_p); + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +#endif +} + +static int snd_atmel_ac97_playback_prepare(snd_pcm_substream_t *substream) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + struct at32_device *adev = chip->adev; + snd_pcm_runtime_t *runtime = substream->runtime; + int block_size = frames_to_bytes(runtime, runtime->period_size); + unsigned long word = 0; + unsigned long buffer_size = 0; + + dma_sync_single_for_device(&adev->dev, runtime->dma_addr, + block_size * 2, DMA_TO_DEVICE); + + /* Assign slots to channels */ + switch (substream->runtime->channels) { + case 1: + word |= AC97C_CH_ASSIGN(PCM_LEFT, A); + break; + case 2: + /* Assign Left and Right slot to Channel A */ + word |= AC97C_CH_ASSIGN(PCM_LEFT, A) + | AC97C_CH_ASSIGN(PCM_RIGHT, A); + break; + default: + /* TODO: support more than two channels */ + return -EINVAL; + break; + } + ac97c_writel(chip, OCA, word); + + /* Configure sample format and size */ + word = AC97C_CMR_PDCEN | AC97C_CMR_SIZE_16; + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + word |= AC97C_CMR_CEM_LITTLE; + break; + case SNDRV_PCM_FORMAT_S16_BE: + default: + word &= ~(AC97C_CMR_CEM_LITTLE); + break; + } + + ac97c_writel(chip, CAMR, word); + + /* Set variable rate if needed */ + if (runtime->rate != 48000) { + word = ac97c_readl(chip, MR); + word |= AC97C_MR_VRA; + ac97c_writel(chip, MR, word); + } else { + /* Clear Variable Rate Bit */ + word = ac97c_readl(chip, MR); + word &= ~(AC97C_MR_VRA); + ac97c_writel(chip, MR, word); + } + + /* Set rate */ + snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); + +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + /* Initialize and start the PDC */ + ac97c_writel(chip, CATPR, runtime->dma_addr); + ac97c_writel(chip, CATCR, block_size / 4); + ac97c_writel(chip, CATNPR, runtime->dma_addr + block_size); + ac97c_writel(chip, CATNCR, block_size / 4); + ac97c_writel(chip, PTCR, PDC_PTCR_TXTEN); + /* Enable Channel A interrupts */ + ac97c_writel(chip, IER, AC97C_SR_CAEVT); +#else + buffer_size = frames_to_bytes(runtime, runtime->period_size) * + runtime->periods; + + chip->dma.req_tx.buffer_size = buffer_size; + chip->dma.req_tx.periods = runtime->periods; + + BUG_ON(chip->dma.req_tx.buffer_size != + (chip->dma.req_tx.periods * + frames_to_bytes(runtime, runtime->period_size))); + + chip->dma.req_tx.buffer_start = runtime->dma_addr; + chip->dma.req_tx.data_reg = (dma_addr_t)(chip->regs + AC97C_CATHR + 2); + chip->dma.req_tx.periph_id = chip->dma.tx_periph_id; + chip->dma.req_tx.direction = DMA_DIR_MEM_TO_PERIPH; + chip->dma.req_tx.width = DMA_WIDTH_16BIT; + chip->dma.req_tx.dev_id = chip; +#endif + + return 0; +} + +static int snd_atmel_ac97_capture_prepare(snd_pcm_substream_t *substream) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + struct at32_device *adev = chip->adev; + snd_pcm_runtime_t *runtime = substream->runtime; + int block_size = frames_to_bytes(runtime, runtime->period_size); + unsigned long word = 0; + unsigned long buffer_size = 0; + + dma_sync_single_for_device(&adev->dev, runtime->dma_addr, + block_size * 2, DMA_FROM_DEVICE); + + /* Assign slots to channels */ + switch (substream->runtime->channels) { + case 1: + word |= AC97C_CH_ASSIGN(PCM_LEFT, A); + break; + case 2: + /* Assign Left and Right slot to Channel A */ + word |= AC97C_CH_ASSIGN(PCM_LEFT, A) + | AC97C_CH_ASSIGN(PCM_RIGHT, A); + break; + default: + /* TODO: support more than two channels */ + return -EINVAL; + break; + } + ac97c_writel(chip, ICA, word); + + /* Configure sample format and size */ + word = AC97C_CMR_PDCEN | AC97C_CMR_SIZE_16; + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + word |= AC97C_CMR_CEM_LITTLE; + break; + case SNDRV_PCM_FORMAT_S16_BE: + default: + word &= ~(AC97C_CMR_CEM_LITTLE); + break; + } + + ac97c_writel(chip, CAMR, word); + + /* Set variable rate if needed */ + if (runtime->rate != 48000) { + word = ac97c_readl(chip, MR); + word |= AC97C_MR_VRA; + ac97c_writel(chip, MR, word); + } else { + /* Clear Variable Rate Bit */ + word = ac97c_readl(chip, MR); + word &= ~(AC97C_MR_VRA); + ac97c_writel(chip, MR, word); + } + + /* Set rate */ + snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); + +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + /* Initialize and start the PDC */ + ac97c_writel(chip, CARPR, runtime->dma_addr); + ac97c_writel(chip, CARCR, block_size / 4); + ac97c_writel(chip, CARNPR, runtime->dma_addr + block_size); + ac97c_writel(chip, CARNCR, block_size / 4); + ac97c_writel(chip, PTCR, PDC_PTCR_RXEN); + /* Enable Channel A interrupts */ + ac97c_writel(chip, IER, AC97C_SR_CAEVT); +#else + buffer_size = frames_to_bytes(runtime, runtime->period_size) * + runtime->periods; + + chip->dma.req_rx.buffer_size = buffer_size; + chip->dma.req_rx.periods = runtime->periods; + + BUG_ON(chip->dma.req_rx.buffer_size != + (chip->dma.req_rx.periods * + frames_to_bytes(runtime, runtime->period_size))); + + chip->dma.req_rx.buffer_start = runtime->dma_addr; + chip->dma.req_rx.data_reg = (dma_addr_t)(chip->regs + AC97C_CARHR + 2); + chip->dma.req_rx.periph_id = chip->dma.rx_periph_id; + chip->dma.req_rx.direction = DMA_DIR_PERIPH_TO_MEM; + chip->dma.req_rx.width = DMA_WIDTH_16BIT; + chip->dma.req_rx.dev_id = chip; +#endif + + return 0; +} + + +static int snd_atmel_ac97_playback_trigger(snd_pcm_substream_t *substream, int cmd) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + unsigned long camr; + int flags, err = 0; + + spin_lock_irqsave(&chip->lock, flags); + camr = ac97c_readl(chip, CAMR); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + err = dma_prepare_request_cyclic(chip->dma.req_tx.req.dmac, + &chip->dma.req_tx); + dma_start_request(chip->dma.req_tx.req.dmac, + chip->dma.req_tx.req.channel); + camr |= (AC97C_CMR_CENA +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + | AC97C_CSR_TXRDY +#endif + ); + break; + case SNDRV_PCM_TRIGGER_STOP: + err = dma_stop_request(chip->dma.req_tx.req.dmac, + chip->dma.req_tx.req.channel); + mutex_lock(&opened_mutex); + if (chip->opened <= 1) { + camr &= ~(AC97C_CMR_CENA +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + | AC97C_CMR_TXRDY +#endif + ); + } +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + else { + camr &= ~(AC97C_CMR_TXRDY); + } +#endif + mutex_unlock(&opened_mutex); + break; + default: + err = -EINVAL; + break; + } + + ac97c_writel(chip, CAMR, camr); + + spin_unlock_irqrestore(&chip->lock, flags); + return err; +} + + +static int snd_atmel_ac97_capture_trigger(snd_pcm_substream_t *substream, int cmd) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + unsigned long camr; + int flags, err = 0; + + spin_lock_irqsave(&chip->lock, flags); + camr = ac97c_readl(chip, CAMR); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + err = dma_prepare_request_cyclic(chip->dma.req_rx.req.dmac, + &chip->dma.req_rx); + dma_start_request(chip->dma.req_rx.req.dmac, + chip->dma.req_rx.req.channel); + camr |= (AC97C_CMR_CENA +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + | AC97C_CMR_RXRDY +#endif + ); + break; + case SNDRV_PCM_TRIGGER_STOP: + err = dma_stop_request(chip->dma.req_rx.req.dmac, + chip->dma.req_rx.req.channel); + mutex_lock(&opened_mutex); + if (chip->opened <= 1) { + camr &= ~(AC97C_CMR_CENA +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + | AC97C_CMR_RXRDY +#endif + ); + } +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + else { + camr &= ~(AC97C_CSR_RXRDY); + } +#endif + mutex_unlock(&opened_mutex); + break; + default: + err = -EINVAL; + break; + } + + ac97c_writel(chip, CAMR, camr); + + spin_unlock_irqrestore(&chip->lock, flags); + return err; +} + + +static snd_pcm_uframes_t snd_atmel_ac97_playback_pointer(snd_pcm_substream_t *substream) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + snd_pcm_uframes_t pos; + unsigned long bytes; + +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + bytes = ac97c_readl(chip, CATPR) - runtime->dma_addr; +#else + bytes = (dma_get_current_pos + (chip->dma.req_tx.req.dmac,chip->dma.req_tx.req.channel) - + runtime->dma_addr); +#endif + pos = bytes_to_frames(runtime, bytes); + if (pos >= runtime->buffer_size) + pos -= runtime->buffer_size; + + + return pos; +} + +static snd_pcm_uframes_t snd_atmel_ac97_capture_pointer(snd_pcm_substream_t *substream) +{ + atmel_ac97_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + snd_pcm_uframes_t pos; + unsigned long bytes; + +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + bytes = ac97c_readl(chip, CARPR) - runtime->dma_addr; +#else + bytes = (dma_get_current_pos + (chip->dma.req_rx.req.dmac,chip->dma.req_rx.req.channel) - + runtime->dma_addr); +#endif + pos = bytes_to_frames(runtime, bytes); + if (pos >= runtime->buffer_size) + pos -= runtime->buffer_size; + + + return pos; +} + +static snd_pcm_ops_t atmel_ac97_playback_ops = { + .open = snd_atmel_ac97_playback_open, + .close = snd_atmel_ac97_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_atmel_ac97_playback_hw_params, + .hw_free = snd_atmel_ac97_playback_hw_free, + .prepare = snd_atmel_ac97_playback_prepare, + .trigger = snd_atmel_ac97_playback_trigger, + .pointer = snd_atmel_ac97_playback_pointer, +}; + +static snd_pcm_ops_t atmel_ac97_capture_ops = { + .open = snd_atmel_ac97_capture_open, + .close = snd_atmel_ac97_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_atmel_ac97_capture_hw_params, + .hw_free = snd_atmel_ac97_capture_hw_free, + .prepare = snd_atmel_ac97_capture_prepare, + .trigger = snd_atmel_ac97_capture_trigger, + .pointer = snd_atmel_ac97_capture_pointer, +}; + +static struct ac97_pcm atmel_ac97_pcm_defs[] __devinitdata = { + /* Playback */ + { + .exclusive = 1, + .r = { { + .slots = ((1 << AC97_SLOT_PCM_LEFT) + | (1 << AC97_SLOT_PCM_RIGHT) + | (1 << AC97_SLOT_PCM_CENTER) + | (1 << AC97_SLOT_PCM_SLEFT) + | (1 << AC97_SLOT_PCM_SRIGHT) + | (1 << AC97_SLOT_LFE)), + } } + }, + /* PCM in */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = ((1 << AC97_SLOT_PCM_LEFT) + | (1 << AC97_SLOT_PCM_RIGHT)), + } } + }, + /* Mic in */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1<ac97_bus, + ARRAY_SIZE(atmel_ac97_pcm_defs), + atmel_ac97_pcm_defs); + if (err) + return err; + + err = snd_pcm_new(chip->card, "Atmel AC97", 0, 1, 1, &pcm); + if (err) + return err; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &atmel_ac97_playback_ops); + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &atmel_ac97_capture_ops); + +#ifdef SND_ATMEL_AC97_USE_ALSA_MALLOC_CALLS + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + &chip->adev->dev, + 128 * 1024, 128 * 1024); +#endif + pcm->private_data = chip; + pcm->info_flags = 0; + strcpy(pcm->name, "Atmel AC97"); + chip->pcm = pcm; + + return 0; +} + +/* Mixer part */ +static int snd_atmel_ac97_mixer_new(atmel_ac97_t *chip) +{ + int err; + ac97_template_t template; + + memset(&template, 0, sizeof(template)); + template.private_data = chip; + err = snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97); + + return err; +} + +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC +static irqreturn_t snd_atmel_ac97_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + atmel_ac97_t *chip = dev_id; + unsigned long status; + + status = ac97c_readl(chip, SR); + + if (status & AC97C_SR_CAEVT) { + snd_pcm_runtime_t *runtime; + int offset, next_period, block_size; + unsigned long casr; + + /* FIXME: separate playback from capture */ + runtime = chip->playback_substream->runtime; + block_size = frames_to_bytes(runtime, runtime->period_size); + + casr = ac97c_readl(chip, CASR); + + if (casr & AC97C_CSR_ENDTX) { + chip->period++; + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + ac97c_writel(chip, CATNPR, + runtime->dma_addr + offset); + ac97c_writel(chip, CATNCR, block_size / 4); + + snd_pcm_period_elapsed(chip->playback_substream); + } + else if (casr & AC97C_CSR_ENDRX) { + chip->period++; + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + ac97c_writel(chip, CARNPR, + runtime->dma_addr + offset); + ac97c_writel(chip, CARNCR, block_size / 4); + + snd_pcm_period_elapsed(chip->capture_substream); + } else { + snd_printk(KERN_INFO + "atmel-ac97: spurious interrupt, status = 0x%08lx\n", + (unsigned long)casr); + } + } else { + snd_printk(KERN_INFO + "atmel-ac97: spurious interrupt, status = 0x%08lx\n", + status); + } + + (volatile int)ac97c_readl(chip, SR); + + return IRQ_HANDLED; +} + +#else + +static void atmel_ac97_error(struct dma_request_cyclic *req) +{ + snd_printk(KERN_INFO + "atmel-ac97: DMA Controller error, channel %d\n", + req->req.channel); +} + +static void atmel_ac97_block_complete(struct dma_request_cyclic *req) +{ + atmel_ac97_t *chip = req->dev_id; + if (req->periph_id == chip->dma.tx_periph_id) + snd_pcm_period_elapsed(chip->playback_substream); + else + snd_pcm_period_elapsed(chip->capture_substream); +} + +#endif + +/* CODEC part */ + +static void snd_atmel_ac97_write(ac97_t *ac97, unsigned short reg, + unsigned short val) +{ + atmel_ac97_t *chip = ac97->private_data; + unsigned long word; + int timeout = 40; + + word = (reg & 0x7f) << 16 | val; + + do { + if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) { + ac97c_writel(chip, COTHR, word); + return; + } + mdelay(10); + } while (--timeout); + + snd_printk(KERN_INFO "atmel-ac97: codec write timeout\n"); +} + +static unsigned short snd_atmel_ac97_read(ac97_t *ac97, + unsigned short reg) +{ + atmel_ac97_t *chip = ac97->private_data; + unsigned long word; + int timeout = 40; + int write = 10; + + word = (0x80 | (reg & 0x7f)) << 16; + + if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0) + ac97c_readl(chip, CORHR); + +retry_write: + timeout = 40; + + do { + if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0) + goto read_reg; + + if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) { + ac97c_writel(chip, COTHR, word); + goto read_reg; + } + mdelay(10); + } while (--timeout); + + if (!--write) + goto timed_out; + goto retry_write; + +read_reg: + do { + if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0){ + unsigned short val = ac97c_readl(chip, CORHR); + return val; + } + mdelay(10); + } while (--timeout); + + if (!--write) + goto timed_out; + goto retry_write; + +timed_out: + snd_printk(KERN_INFO "atmel-ac97: codec read timeout\n"); + return 0xffff; +} + +static void snd_atmel_ac97_reset(atmel_ac97_t *chip) +{ + /* TODO: Perform hard reset of codec as well */ + ac97c_writel(chip, MR, AC97C_MR_WRST); + mdelay(1); + ac97c_writel(chip, MR, AC97C_MR_ENA); +} + +static void snd_atmel_ac97_destroy(snd_card_t *card) +{ + atmel_ac97_t *chip = get_chip(card); + +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + if (chip->irq != -1) + free_irq(chip->irq, chip); +#endif + if (chip->regs) + iounmap(chip->regs); + +#ifndef CONFIG_SND_ATMEL_AC97C_USE_PDC + if (chip->dma.req_tx.req.dmac) { + dma_release_channel(chip->dma.req_tx.req.dmac, + chip->dma.req_tx.req.channel); + } + if (chip->dma.req_rx.req.dmac) { + dma_release_channel(chip->dma.req_rx.req.dmac, + chip->dma.req_rx.req.channel); + } +#endif +} + +static int __devinit snd_atmel_ac97_create(snd_card_t *card, + struct at32_device *adev) +{ + static ac97_bus_ops_t ops = { + .write = snd_atmel_ac97_write, + .read = snd_atmel_ac97_read, + }; + atmel_ac97_t *chip = get_chip(card); +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + int irq; +#endif + int err; + + card->private_free = snd_atmel_ac97_destroy; + + spin_lock_init(&chip->lock); + chip->card = card; + chip->adev = adev; + chip->irq = -1; + chip->opened = 0; + +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + irq = at32_get_irq(adev); + + err = request_irq(irq, snd_atmel_ac97_interrupt, 0, + "ac97", chip); + if (err) { + snd_printk(KERN_ERR "atmel-ac97: unable to request IRQ%d\n", irq); + return err; + } + chip->irq = irq; +#endif + + chip->regs = at32_map_iomem(adev, 0); + if (!chip->regs) + return -ENOMEM; + + snd_card_set_dev(card, &adev->dev); + + err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus); + + return err; +} + +static int __devinit snd_atmel_ac97_probe(struct at32_device *adev) +{ + static int dev; + snd_card_t *card; + atmel_ac97_t *chip; + int err; + int ch; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + err = at32_enable_device(adev); + if (err) { + dev_err(&adev->dev, "failed to enable device\n"); + return err; + } + + mutex_init(&opened_mutex); + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, + sizeof(atmel_ac97_t)); + if (!card) + goto out_disable_dev; + chip = get_chip(card); + + err = snd_atmel_ac97_create(card, adev); + if (err) + goto out_free_card; + + snd_atmel_ac97_reset(chip); + + err = snd_atmel_ac97_mixer_new(chip); + if (err) + goto out_free_card; + + err = snd_atmel_ac97_pcm_new(chip); + if (err) + goto out_free_card; + +#ifndef CONFIG_SND_ATMEL_AC97C_USE_PDC + /* TODO: Get this information from the at32 device */ + chip->dma.req_tx.req.dmac = find_dma_controller(0); + if (!chip->dma.req_tx.req.dmac) { + snd_printk(KERN_ERR + "atmel-ac97c: No DMA controller available for TX, aborting\n"); + goto out_free_card; + } + chip->dma.req_rx.req.dmac = find_dma_controller(0); + if (!chip->dma.req_rx.req.dmac) { + snd_printk(KERN_ERR + "atmel-ac97c: No DMA controller available for RX, aborting\n"); + goto out_free_card; + } + + chip->dma.rx_periph_id = 3; + chip->dma.tx_periph_id = 4; + + ch = dma_alloc_channel(chip->dma.req_tx.req.dmac); + if (ch < 0) { + snd_printk(KERN_ERR + "atmel-ac97c: Unable to allocate TX DMA channel, aborting\n"); + goto out_free_card; + } + chip->dma.req_tx.req.channel = ch; + chip->dma.req_tx.width = DMA_WIDTH_16BIT; + chip->dma.req_tx.req.block_complete = (void(*)(struct dma_request *))atmel_ac97_block_complete; + chip->dma.req_tx.req.error = (void(*)(struct dma_request *))atmel_ac97_error; + + ch = dma_alloc_channel(chip->dma.req_rx.req.dmac); + if (ch < 0) { + snd_printk(KERN_ERR + "atmel-ac97c: Unable to allocate RX DMA channel, aborting\n"); + goto out_free_card; + } + chip->dma.req_rx.req.channel = ch; + chip->dma.req_rx.width = DMA_WIDTH_16BIT; + chip->dma.req_rx.req.block_complete = (void(*)(struct dma_request *))atmel_ac97_block_complete; + chip->dma.req_rx.req.error = (void(*)(struct dma_request *))atmel_ac97_error; +#endif + + strcpy(card->driver, "snd-atmel-ac97"); + strcpy(card->shortname, "Atmel AVR32 AC97"); +#ifdef CONFIG_SND_ATMEL_AC97C_USE_PDC + sprintf(card->longname, "Atmel AVR32 AC97 Controller at %#lx, irq %i", + at32_get_iomem_base(adev, 0), chip->irq); +#else + sprintf(card->longname, "Atmel AVR32 AC97 Controller at %#lx, dma rx %i and tx %i", + at32_get_iomem_base(adev, 0), + chip->dma.rx_periph_id, chip->dma.tx_periph_id); +#endif + + err = snd_card_register(card); + if (err) + goto out_free_card; + + at32_set_drvdata(adev, card); + dev++; + return 0; + +out_free_card: + snd_card_free(card); +out_disable_dev: + at32_disable_device(adev); + return err; +} + +static int __devexit snd_atmel_ac97_remove(struct at32_device *adev) +{ + snd_card_free(at32_get_drvdata(adev)); + at32_disable_device(adev); + at32_set_drvdata(adev, NULL); + return 0; +} + +static struct at32_driver atmel_ac97_driver = { + .probe = snd_atmel_ac97_probe, + .remove = __devexit_p(snd_atmel_ac97_remove), + .driver = { + .name = "ac97c", + }, +}; + +static int __init atmel_ac97_init(void) +{ + return at32_driver_register(&atmel_ac97_driver); +} + +static void __exit atmel_ac97_exit(void) +{ + at32_driver_unregister(&atmel_ac97_driver); +} + +module_init(atmel_ac97_init); +module_exit(atmel_ac97_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Driver for Atmel AC97 Controller"); +MODULE_AUTHOR("Haavard Skinnemoen "); diff -Nur linux-2.6.16.11/sound/avr32/ac97c.h linux-2.6.16.11-avr32-20060626/sound/avr32/ac97c.h --- linux-2.6.16.11/sound/avr32/ac97c.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/avr32/ac97c.h 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,73 @@ +/* + * Register definitions for the Atmel AC97 Controller. + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __SOUND_AVR32_AC97C_H +#define __SOUND_AVR32_AC97C_H + +#include + +#define AC97C_MR 0x08 +#define AC97C_ICA 0x10 +#define AC97C_OCA 0x14 +#define AC97C_CARHR 0x20 +#define AC97C_CATHR 0x24 +#define AC97C_CASR 0x28 +#define AC97C_CAMR 0x2c +#define AC97C_CBRHR 0x30 +#define AC97C_CBTHR 0x34 +#define AC97C_CBSR 0x38 +#define AC97C_CBMR 0x3c +#define AC97C_CORHR 0x40 +#define AC97C_COTHR 0x44 +#define AC97C_COSR 0x48 +#define AC97C_COMR 0x4c +#define AC97C_SR 0x50 +#define AC97C_IER 0x54 +#define AC97C_IDR 0x58 +#define AC97C_IMR 0x5c +#define AC97C_VERSION 0xfc + +#define AC97C_CATPR PDC_TPR +#define AC97C_CATCR PDC_TCR +#define AC97C_CATNPR PDC_TNPR +#define AC97C_CATNCR PDC_TNCR +#define AC97C_CARPR PDC_RPR +#define AC97C_CARCR PDC_RCR +#define AC97C_CARNPR PDC_RNPR +#define AC97C_CARNCR PDC_RNCR +#define AC97C_PTCR PDC_PTCR + +#define AC97C_MR_ENA (1 << 0) +#define AC97C_MR_WRST (1 << 1) +#define AC97C_MR_VRA (1 << 2) + +#define AC97C_CSR_TXRDY (1 << 0) +#define AC97C_CSR_UNRUN (1 << 2) +#define AC97C_CSR_RXRDY (1 << 4) +#define AC97C_CSR_ENDTX (1 << 10) +#define AC97C_CSR_ENDRX (1 << 14) + +#define AC97C_CMR_SIZE_20 (0 << 16) +#define AC97C_CMR_SIZE_18 (1 << 16) +#define AC97C_CMR_SIZE_16 (2 << 16) +#define AC97C_CMR_SIZE_10 (3 << 16) +#define AC97C_CMR_CEM_LITTLE (1 << 18) +#define AC97C_CMR_CEM_BIG (0 << 18) +#define AC97C_CMR_CENA (1 << 21) +#define AC97C_CMR_PDCEN (1 << 22) + +#define AC97C_SR_CAEVT (1 << 3) + +#define AC97C_CH_ASSIGN(slot, channel) \ + (AC97C_CHANNEL_##channel << (3 * (AC97_SLOT_##slot - 3))) +#define AC97C_CHANNEL_NONE 0x0 +#define AC97C_CHANNEL_A 0x1 +#define AC97C_CHANNEL_B 0x2 + +#endif /* __SOUND_AVR32_AC97C_H */ diff -Nur linux-2.6.16.11/sound/avr32/at73c213.c linux-2.6.16.11-avr32-20060626/sound/avr32/at73c213.c --- linux-2.6.16.11/sound/avr32/at73c213.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/avr32/at73c213.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,1267 @@ +/* + * Driver for the at73c213 16-bit stereo DAC on Atmel ATSTK1000 + * + * Copyright (C) 2006 Atmel Norway + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * The full GNU General Public License is included in this + * distribution in the file called COPYING. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifndef SND_AT73C213_USE_ALSA_MALLOC_CALLS +#include +#endif + +#include +#include +#include +#include + +#include "at73c213.h" + +/* module parameters */ +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + +/* Register defines */ +#define PIOA_BASE 0xFFE02800 +#define SSC0_BASE 0xFFE01C00 +#define PM_BASE 0xFFF00000 + +#define PM_CKSEL 0x04 +#define PM_APBAMASK 0x10 +#define PM_GCCTRL 0x60 + +#define PIO_PER 0x00 +#define PIO_PDR 0x04 +#define PIO_PUER 0x64 +#define PIO_ASR 0x70 +#define PIO_BSR 0x74 + +#define SSC_CMR 0x04 +#define SSC_CR 0x00 +#define SSC_TCMR 0x18 +#define SSC_TFMR 0x1C + +/* SSC register definitions */ +#define SSC_CR 0x00 +#define SSC_CMR 0x04 +#define SSC_TCMR 0x18 +#define SSC_TFMR 0x1C +#define SSC_THR 0x24 +#define SSC_SR 0x40 +#define SSC_IER 0x44 +#define SSC_IDR 0x48 +#define SSC_IMR 0x4C + +/* SSC fields definitions */ +#define SSC_CR_TXEN 0x00000100 +#define SSC_CR_TXDIS 0x00000200 +#define SSC_CR_SWRST 0x00008000 + +/* SSC interrupt definitions */ +#define SSC0_IRQ 10 +#define SSC_INT_ENDTX 0x00000004 +#define SSC_INT_TXBUFE 0x00000008 + +static int bitrate; +static int gclk_div; +static int ssc_div; +static int spi = 1; +static int ssc = 1; + +module_param(spi, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(spi, "Which SPI interface to use to communicate with the at73c213"); +module_param(ssc, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(ssc, "Which SSC interface to use to communicate with the at73c213"); + +/* Initial AT73C213 register values */ +static unsigned char snd_at73c213_original_image[18] = +{ + 0x00, /* 00 - CTRL */ + 0x05, /* 01 - LLIG */ + 0x05, /* 02 - RLIG */ + 0x08, /* 03 - LPMG */ + 0x08, /* 04 - RPMG */ + 0x00, /* 05 - LLOG */ + 0x00, /* 06 - RLOG */ + 0x22, /* 07 - OLC */ + 0x09, /* 08 - MC */ + 0x00, /* 09 - CSFC */ + 0x00, /* 0A - MISC */ + 0x00, /* 0B - */ + 0x00, /* 0C - PRECH */ + 0x05, /* 0D - AUXG */ + 0x00, /* 0E - */ + 0x00, /* 0F - */ + 0x00, /* 10 - RST */ + 0x00, /* 11 - PA_CTRL */ +}; + +/* chip-specific data */ +struct snd_at73c213 { + snd_card_t *card; + snd_pcm_t *pcm; + snd_pcm_substream_t *substream; + int irq; + int period; + void __iomem *regs; + struct spi_device *spi; + u8 spi_wbuffer[2]; + u8 spi_rbuffer[2]; + /* image of the SPI registers in AT73C213 */ + u8 image[18]; + spinlock_t lock; + struct at32_device *adev; +}; + +#define get_chip(card) ((struct snd_at73c213 *)card->private_data) + +static int +snd_at73c213_write_reg(struct snd_at73c213 *chip, u8 reg, u8 val) +{ + struct spi_message msg; + struct spi_transfer msg_xfer = { + .len = 2, + .cs_change = 0, + }; + + spi_message_init(&msg); + + chip->spi_wbuffer[0] = reg; + chip->spi_wbuffer[1] = val; + + msg_xfer.tx_buf = chip->spi_wbuffer; + msg_xfer.rx_buf = chip->spi_rbuffer; + spi_message_add_tail(&msg_xfer, &msg); + + return spi_sync(chip->spi, &msg); +} + +#define write_reg(_spi, reg, val) \ + do { \ + retval = snd_at73c213_write_reg(_spi, reg, val); \ + if (retval) \ + goto out; \ + } while (0) + +static snd_pcm_hardware_t snd_at73c213_playback_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_BE, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, /* This will be overwritten with bitrate */ + .rate_max = 50000, /* This will be overwritten with bitrate */ + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 64 * 1024 - 1, + .period_bytes_min = 512, + .period_bytes_max = 64 * 1024 - 1, + .periods_min = 4, + .periods_max = 1024, +}; + +/* calculate and set bitrate and divisions */ +static int snd_at73c213_set_bitrate_and_div(void) +{ + extern struct avr32_cpuinfo boot_cpu_data; + unsigned long long pll0_hz, apba_hz; + unsigned long apba_realdiv, gclk_realdiv, ssc_realdiv, wanted_bitrate; + char cpusel, ahbsel, apbasel; + int regval; + + regval = readl((void __iomem *)PM_BASE + PM_CKSEL); + wanted_bitrate = 48000; + + cpusel = regval & 0x07; + ahbsel = (regval>>8) & 0x07; + apbasel = (regval>>16) & 0x07; + + if ((regval&(1<<7)) != 0) { + pll0_hz = boot_cpu_data.cpu_hz/(1<<(cpusel+1)); + } else { + pll0_hz = boot_cpu_data.cpu_hz; + } + + if ((regval&(1<<23)) != 0) { + apba_hz = pll0_hz/(1<<(apbasel+1)); + apba_realdiv = (1<<(apbasel+1)); + } else { + apba_hz = pll0_hz; + apba_realdiv = 1; + } + +calculate: + /* Adjust bitrate as close as possible to 48000 Hz */ + gclk_realdiv = pll0_hz/(wanted_bitrate*256); + ssc_realdiv = 2 * apba_realdiv * gclk_realdiv; + + if ((gclk_realdiv % 2) == 0) + goto setbitrates; + + if(wanted_bitrate >= 22050 && wanted_bitrate <= 48000) + wanted_bitrate -= 50; + else if (wanted_bitrate < 22050) + wanted_bitrate = 48050; + else if (wanted_bitrate <= 50000) + wanted_bitrate += 50; + else { + printk(KERN_ERR "at73c213 could not set dividers for a valid bitrate\n"); + return -EINVAL; + } + + goto calculate; + +setbitrates: + bitrate = pll0_hz/(gclk_realdiv*256); + gclk_div = (gclk_realdiv/2)-1; + ssc_realdiv = 2*apba_realdiv*gclk_realdiv; + ssc_div = ssc_realdiv/(2*apba_realdiv); + + printk(KERN_INFO "at73c213: bitrate is %d Hz\n", bitrate); + + return 0; +} + +/* open callback */ +static int snd_at73c213_pcm_open(snd_pcm_substream_t *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + snd_at73c213_playback_hw.rate_min = bitrate; + snd_at73c213_playback_hw.rate_max = bitrate; + runtime->hw = snd_at73c213_playback_hw; + chip->substream = substream; + + return 0; +} + +/* close callback */ +static int snd_at73c213_pcm_close(snd_pcm_substream_t *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + chip->substream = NULL; + return 0; +} + +/* hw_params callback */ +static int snd_at73c213_pcm_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *hw_params) +{ +#ifdef SND_AT73C213_USE_ALSA_MALLOC_CALLS + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +#else + int pg; + size_t size = params_buffer_bytes(hw_params); + struct snd_pcm_runtime *runtime; + struct snd_dma_buffer *dmab = NULL; + + substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV; + snd_assert(substream != NULL, return -EINVAL); + runtime = substream->runtime; + snd_assert(runtime != NULL, return -EINVAL); + + /* check if buffer is already allocated */ + if (runtime->dma_buffer_p) { + size_t size_previouse; + int pg_previouse; + + /* new buffer is smaler than previouse allocated buffer */ + if (runtime->dma_buffer_p->bytes >= size) { + runtime->dma_bytes = size; + return 0; /* don't change buffer size */ + } + + size_previouse = runtime->dma_buffer_p->bytes; + pg_previouse = get_order(size_previouse); + + dma_free_coherent(runtime->dma_buffer_p->dev.dev, + PAGE_SIZE << pg_previouse, + runtime->dma_buffer_p->area, + runtime->dma_buffer_p->addr); + + kfree(runtime->dma_buffer_p); + } + + dmab = kzalloc(sizeof(*dmab), GFP_KERNEL); + if (!dmab) + return -ENOMEM; + + dmab->dev = substream->dma_buffer.dev; + dmab->bytes = 0; + + pg = get_order(size); + + dmab->area = dma_alloc_coherent( + substream->dma_buffer.dev.dev, + PAGE_SIZE << pg, + (dma_addr_t *)&dmab->addr, + GFP_KERNEL); + + if (!dmab->area) { + kfree(dmab); + return -ENOMEM; + } + + dmab->bytes = size; + snd_pcm_set_runtime_buffer(substream, dmab); + runtime->dma_bytes = size; + return 1; +#endif +} + +/* hw_free callback */ +static int snd_at73c213_pcm_hw_free(snd_pcm_substream_t *substream) +{ +#ifdef SND_AT73C213_USE_ALSA_MALLOC_CALLS + return snd_pcm_lib_free_pages(substream); +#else + int pg; + struct snd_pcm_runtime *runtime; + struct snd_dma_buffer *dmab = NULL; + + snd_assert(substream != NULL, return -EINVAL); + runtime = substream->runtime; + snd_assert(runtime != NULL, return -EINVAL); + dmab = runtime->dma_buffer_p; + + if (!dmab) + return 0; + + if (!dmab->area) + return 0; + + pg = get_order(dmab->bytes); + dma_free_coherent(dmab->dev.dev, PAGE_SIZE << pg, dmab->area, dmab->addr); + kfree(runtime->dma_buffer_p); + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +#endif +} + +/* prepare callback */ +static int snd_at73c213_pcm_prepare(snd_pcm_substream_t *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + struct at32_device *adev = chip->adev; + snd_pcm_runtime_t *runtime = substream->runtime; + int block_size; + + block_size = frames_to_bytes(runtime, runtime->period_size); + + chip->period = 0; + + /* Make sure that our data are actually readable by the SSC */ + dma_sync_single_for_device(&adev->dev, runtime->dma_addr, + block_size, DMA_TO_DEVICE); + dma_sync_single_for_device(&adev->dev, runtime->dma_addr + block_size, + block_size, DMA_TO_DEVICE); + + writel(runtime->dma_addr, chip->regs + PDC_TPR); + writel(runtime->period_size * 2, chip->regs + PDC_TCR); + writel(runtime->dma_addr + block_size, chip->regs + PDC_TNPR); + writel(runtime->period_size * 2, chip->regs + PDC_TNCR); + + return 0; +} + +/* trigger callback */ +static int snd_at73c213_pcm_trigger(snd_pcm_substream_t *substream, + int cmd) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + int retval = 0; + int flags = 0; + + spin_lock_irqsave(&chip->lock, flags); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + writel(SSC_INT_ENDTX, chip->regs + SSC_IER); + writel(PDC_PTCR_TXTEN, chip->regs + PDC_PTCR); + break; + case SNDRV_PCM_TRIGGER_STOP: + writel(PDC_PTCR_TXTDIS, chip->regs + PDC_PTCR); + writel(SSC_INT_ENDTX, chip->regs + SSC_IDR); + break; + default: + printk(KERN_WARNING "at73c213: spuriouse command %x\n", cmd); + retval = -EINVAL; + break; + } + + spin_unlock_irqrestore(&chip->lock, flags); + + return retval; +} + +/* pointer callback */ +static snd_pcm_uframes_t snd_at73c213_pcm_pointer(snd_pcm_substream_t *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + snd_pcm_uframes_t pos; + unsigned long bytes; + + bytes = readl(chip->regs + PDC_TPR) - runtime->dma_addr; + + pos = bytes_to_frames(runtime, bytes); + if (pos >= runtime->buffer_size) + pos -= runtime->buffer_size; + + return pos; +} + +/* operators */ +static snd_pcm_ops_t at73c213_playback_ops = { + .open = snd_at73c213_pcm_open, + .close = snd_at73c213_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_at73c213_pcm_hw_params, + .hw_free = snd_at73c213_pcm_hw_free, + .prepare = snd_at73c213_pcm_prepare, + .trigger = snd_at73c213_pcm_trigger, + .pointer = snd_at73c213_pcm_pointer, +}; + +/* free a pcm device */ +static void snd_at73c213_pcm_free(snd_pcm_t *pcm) +{ + struct snd_at73c213 *chip = snd_pcm_chip(pcm); + if (chip->pcm != 0 ) { +#ifdef SND_AT73C213_USE_ALSA_MALLOC_CALLS + snd_pcm_lib_preallocate_free_for_all(chip->pcm); +#endif + chip->pcm = NULL; + } +} + +/* create a new pcm device */ +static int __devinit snd_at73c213_new_pcm(struct snd_at73c213 *chip, int device) +{ + snd_pcm_t *pcm; + int retval; + + retval = snd_pcm_new(chip->card, chip->card->shortname, device, 1, 0, &pcm); + if (retval < 0) + return retval; + + pcm->private_data = chip; + pcm->private_free = snd_at73c213_pcm_free; + pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER; + strcpy(pcm->name, "at73c213"); + chip->pcm = pcm; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops); + +#ifdef SND_AT73C213_USE_ALSA_MALLOC_CALLS + snd_pcm_lib_preallocate_pages_for_all(chip->pcm, SNDRV_DMA_TYPE_DEV, + &chip->adev->dev, 64 * 1024, 64 * 1024); +#endif + + return 0; +} + +static irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct snd_at73c213 *chip = dev_id; + struct at32_device *adev = chip->adev; + snd_pcm_runtime_t *runtime = chip->substream->runtime; + u32 status; + int offset, next_period, block_size; + + spin_lock(&chip->lock); + + block_size = frames_to_bytes(runtime, runtime->period_size); + + status = readl(chip->regs + SSC_IMR); + + if (status & SSC_INT_ENDTX) { + chip->period++; + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + /* Make sure that our data are actually readable by the SSC */ + dma_sync_single_for_device(&adev->dev, runtime->dma_addr + offset, + block_size, DMA_TO_DEVICE); + writel(runtime->dma_addr + offset, chip->regs + PDC_TNPR); + writel(runtime->period_size * 2, chip->regs + PDC_TNCR); + + if (next_period == 0) { + (void)readl(chip->regs + PDC_TPR); + (void)readl(chip->regs + PDC_TCR); + } + } else { + printk(KERN_WARNING + "Spurious SSC interrupt, status = 0x%08lx\n", + (unsigned long)status); + writel(status, chip->regs + SSC_IDR); + } + + (void)readl(chip->regs + SSC_IMR); + spin_unlock(&chip->lock); + + if (status & SSC_INT_ENDTX) + snd_pcm_period_elapsed(chip->substream); + + return IRQ_HANDLED; +} + +/* + * Mixer functions + */ +#if 0 /* Function not in use */ +static int snd_at73c213_mono_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned long mask = (kcontrol->private_value >> 16) & 0xff; + + uinfo->type = (mask == 1) ? + SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + + return 0; +} +#endif + +static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + + spin_lock_irqsave(&chip->lock, flags); + + ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; + + if (invert) + ucontrol->value.integer.value[0] = + (mask - ucontrol->value.integer.value[0]); + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + int change, retval; + unsigned short val; + + val = (ucontrol->value.integer.value[0] & mask); + if (invert) + val = mask - val; + val <<= shift; + + spin_lock_irqsave(&chip->lock, flags); + + val = (chip->image[reg] & ~(mask << shift)) | val; + change = val != chip->image[reg]; + write_reg(chip, reg, val); + + chip->image[reg] = val; + + spin_unlock_irqrestore(&chip->lock, flags); + + return change; + +out: + return retval; +} + +static int snd_at73c213_stereo_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int mask = (kcontrol->private_value >> 24) & 0xFF; + + uinfo->type = mask == 1 ? + SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + + return 0; +} + +static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int left_reg = kcontrol->private_value & 0xff; + int right_reg = (kcontrol->private_value >> 8) & 0xff; + int shift_left = (kcontrol->private_value >> 16) & 0x07; + int shift_right = (kcontrol->private_value >> 19) & 0x07; + int mask = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 22) & 1; + + spin_lock_irqsave(&chip->lock, flags); + + ucontrol->value.integer.value[0] = + (chip->image[left_reg] >> shift_left) & mask; + ucontrol->value.integer.value[1] = + (chip->image[right_reg] >> shift_right) & mask; + + if (invert) { + ucontrol->value.integer.value[0] = + (mask - ucontrol->value.integer.value[0]); + ucontrol->value.integer.value[1] = + (mask - ucontrol->value.integer.value[1]); + } + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int left_reg = kcontrol->private_value & 0xff; + int right_reg = (kcontrol->private_value >> 8) & 0xff; + int shift_left = (kcontrol->private_value >> 16) & 0x07; + int shift_right = (kcontrol->private_value >> 19) & 0x07; + int mask = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 22) & 1; + int change, retval; + unsigned short val1, val2; + + val1 = ucontrol->value.integer.value[0] & mask; + val2 = ucontrol->value.integer.value[1] & mask; + if (invert) { + val1 = mask - val1; + val2 = mask - val2; + } + val1 <<= shift_left; + val2 <<= shift_right; + + spin_lock_irqsave(&chip->lock, flags); + + val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; + val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; + change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; + write_reg(chip, left_reg, val1); + write_reg(chip, right_reg, val2); + + chip->image[left_reg] = val1; + chip->image[right_reg] = val2; + + spin_unlock_irqrestore(&chip->lock, flags); + + return change; + +out: + return retval; +} + +static int snd_at73c213_mono_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + + spin_lock_irqsave(&chip->lock, flags); + + ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & 0x01; + + if (invert) + ucontrol->value.integer.value[0] = + (0x01 - ucontrol->value.integer.value[0]); + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + int change, retval; + unsigned short val; + + if (ucontrol->value.integer.value[0]) + val = mask; + else + val = 0; + + if (invert) + val = mask - val; + val <<= shift; + + spin_lock_irqsave(&chip->lock, flags); + + val |= (chip->image[reg] & ~(mask << shift)); + change = val != chip->image[reg]; + + write_reg(chip, reg, val); + + chip->image[reg] = val; + + spin_unlock_irqrestore(&chip->lock, flags); + + return change; + +out: + return retval; +} + +static int snd_at73c213_pa_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = ((kcontrol->private_value >> 16) & 0xFF) - 1; + + return 0; +} + +static int snd_at73c213_line_capture_volume_info( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 14; + uinfo->value.integer.max = 31; + + return 0; +} + +static int snd_at73c213_aux_capture_volume_info( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 14; + uinfo->value.integer.max = 31; + + return 0; +} + +#define AT73C213_MONO(xname, xindex, reg, shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .info = snd_at73c213_mono_info, \ + .get = snd_at73c213_mono_get, .put = snd_at73c213_mono_put, \ + .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } + +#define AT73C213_MONO_SWITCH(xname, xindex, reg, shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .info = snd_at73c213_mono_switch_info, \ + .get = snd_at73c213_mono_switch_get, .put = snd_at73c213_mono_switch_put, \ + .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } + +#define AT73C213_STEREO(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .info = snd_at73c213_stereo_info, \ + .get = snd_at73c213_stereo_get, .put = snd_at73c213_stereo_put, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } + +static struct snd_kcontrol_new snd_at73c213_controls[] __initdata = { +AT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1F, 1), +AT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1), +AT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1F, 1), +AT73C213_STEREO("PCM Playback Switch", 0, DAC_LLOG, DAC_RLOG, 5, 5, 1, 1), +AT73C213_MONO_SWITCH("Mono PA Playback Switch", 0, DAC_CTRL, DAC_CTRL_ONPADRV, 0x01, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PA Playback Volume", + .index = 0, + .info = snd_at73c213_pa_volume_info, + .get = snd_at73c213_mono_get, + .put = snd_at73c213_mono_put, + .private_value = PA_CTRL|(PA_CTRL_APAGAIN<<8)|(0x0F<<16)|(1<<24), +}, +AT73C213_MONO_SWITCH("PA High Gain Playback Switch", 0, PA_CTRL, PA_CTRL_APALP, 0x01, 1), +AT73C213_MONO_SWITCH("PA Playback Switch", 0, PA_CTRL, PA_CTRL_APAON, 0x01, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Aux Capture Volume", + .index = 0, + .info = snd_at73c213_aux_capture_volume_info, + .get = snd_at73c213_mono_get, + .put = snd_at73c213_mono_put, + .private_value = DAC_AUXG|(0<<8)|(0x1F<<16)|(1<<24), +}, +AT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN, 0x01, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line Capture Volume", + .index = 0, + .info = snd_at73c213_line_capture_volume_info, + .get = snd_at73c213_stereo_get, + .put = snd_at73c213_stereo_put, + .private_value = DAC_LLIG|(DAC_RLIG<<8)|(0<<16)|(0<<19)|(0x1F<<24)|(1<<22), +}, +AT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0), +}; + +static int __init snd_at73c213_mixer(struct snd_at73c213 *chip) +{ + struct snd_card *card; + int errval, idx; + + if (chip == NULL || chip->pcm == NULL) + return -EINVAL; + + card = chip->card; + + strcpy(card->mixername, chip->pcm->name); + + for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) { + if ((errval = snd_ctl_add(card, + snd_ctl_new1(&snd_at73c213_controls[idx], + chip))) < 0) + return errval; + } + + return 0; +} + +/* + * Device functions + */ +static int snd_at73c213_chip_init(struct snd_at73c213 *chip) +{ + int retval; + unsigned char dac_ctrl = 0; + + /* XXX: Unmask the APB clock for SSC0 */ + writel(readl((void __iomem *)PM_BASE + PM_APBAMASK)|(1<<7), + (void __iomem *)PM_BASE + PM_APBAMASK); + + /* Wait for clock to be stable */ + msleep(10); + + retval = snd_at73c213_set_bitrate_and_div(); + if (retval) + goto out; + + /* Reset the SSC */ + writel(SSC_CR_SWRST, chip->regs + SSC_CR); + + /* Enable GCLK0 */ + writel((1<<30), (void __iomem *)(PIOA_BASE + PIO_PDR)); + writel((1<<30), (void __iomem *)(PIOA_BASE + PIO_ASR)); + writel(((gclk_div<<8)|0x10|0x04|0x02), (void __iomem *)(PM_BASE + PM_GCCTRL)); + + /* Enable SSC and setup for I2S */ + writel(ssc_div, chip->regs + SSC_CMR); + + /* CKO, START, STTDLY, PERIOD */ + writel((1<<2)|(4<<8)|(1<<16)|(15<<24), chip->regs + SSC_TCMR); + + /* DATLEN, MSBF, DATNB, FSLEN, FSOS */ + writel((15<<0)|(1<<7)|(1<<8)|(15<<16)|(1<<20), chip->regs + SSC_TFMR); + + /* Initialize at73c213 on SPI bus */ + /* Reset the device */ + write_reg(chip, DAC_RST, 0x04); + msleep(1); + write_reg(chip, DAC_RST, 0x03); + + /* Turn on precharge */ + write_reg(chip, DAC_PRECH, 0xFF); + write_reg(chip, PA_CTRL, (1<image[PA_CTRL] = (1<image[DAC_PRECH] = (1<image[DAC_CTRL] = dac_ctrl; + + /* Mute sound */ + write_reg(chip, DAC_LMPG, 0x3F); + chip->image[DAC_LMPG] = 0x3F; + write_reg(chip, DAC_RMPG, 0x3F); + chip->image[DAC_RMPG] = 0x3F; + write_reg(chip, DAC_LLOG, 0x3F); + chip->image[DAC_LLOG] = 0x3F; + write_reg(chip, DAC_RLOG, 0x3F); + chip->image[DAC_RLOG] = 0x3F; + write_reg(chip, DAC_LLIG, 0x11); + chip->image[DAC_LLIG] = 0x11; + write_reg(chip, DAC_RLIG, 0x11); + chip->image[DAC_RLIG] = 0x11; + write_reg(chip, DAC_AUXG, 0x11); + chip->image[DAC_AUXG] = 0x11; + + /* Turn on SSC transmitter */ + writel(SSC_CR_TXEN, chip->regs + SSC_CR); + +out: + return retval; +} + +static int snd_at73c213_dev_free(snd_device_t *device) +{ + struct snd_at73c213 *chip = device->device_data; + + if (chip->regs) { + writel(SSC_CR_TXDIS, chip->regs + SSC_CR); + iounmap(chip->regs); + } + + if (chip->irq >= 0) + free_irq(chip->irq, chip); + + return 0; +} + +static int __devinit snd_at73c213_create(snd_card_t *card, + struct at32_device *adev) +{ + static snd_device_ops_t ops = { + .dev_free = snd_at73c213_dev_free, + }; + struct snd_at73c213 *chip = get_chip(card); + int irq, retval; + + spin_lock_init(&chip->lock); + chip->card = card; + chip->adev = adev; + chip->irq = -1; + + retval = -ENOMEM; + + retval = spi_setup(chip->spi); + if (retval) + goto out; + + chip->regs = at32_map_iomem(adev, 0); + + if (!chip->regs) + goto out; + + irq = at32_get_irq(adev); + + retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip); + if (retval) { + snd_printk("unable to request IRQ%d\n", irq); + goto out; + } + chip->irq = irq; + + memcpy(&chip->image, &snd_at73c213_original_image, + sizeof(snd_at73c213_original_image)); + + retval = snd_at73c213_chip_init(chip); + if (retval) + goto out; + + retval = snd_at73c213_new_pcm(chip, 0); + if (retval) + goto out; + + retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (retval) + goto out; + + retval = snd_at73c213_mixer(chip); + if (retval) + goto out; + + snd_card_set_dev(card, &adev->dev); + +out: + return retval; +} + +static int __devinit snd_at73c213_probe(struct at32_device *adev) +{ + static int dev; + struct spi_board_info *binfo; + struct spi_master *smaster; + struct snd_at73c213 *chip; + snd_card_t *card; + int retval; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + if (spi < 0 || ssc < 0) + return -ENODEV; + + retval = at32_enable_device(adev); + if (retval) { + printk(KERN_ERR "at73c213: failed to enable device\n"); + goto out; + } + + retval = -ENOMEM; + card = snd_card_new(index[dev], id[dev], THIS_MODULE, + sizeof(struct snd_at73c213)); + if (!card) + goto out; + + chip = card->private_data; + + retval = -ENODEV; + + /* Get the SPI bus */ + binfo = adev->dev.platform_data; + if (!binfo) { + printk(KERN_WARNING "at73c213: could not get platform data\n"); + goto out; + } + + smaster = spi_busnum_to_master(spi); + if (!smaster) { + request_module("spi1"); + smaster = spi_busnum_to_master(spi); + if (!smaster) { + printk(KERN_WARNING + "at73c213: could not get " + "SPI bus %d, remembered to load " + "the spi_atmel module?\n", spi); + goto out; + } + } + + chip->spi = spi_new_device(smaster, binfo); + if (!chip->spi) { + printk(KERN_WARNING "at73c213: could not get SPI device %d\n", spi); + goto out; + } + + chip->spi->mode = SPI_MODE_1; + chip->spi->bits_per_word = 8; + + retval = snd_at73c213_create(card, adev); + if (retval) + goto out_free_card; + + strcpy(card->driver, "at73c213"); + strcpy(card->shortname, "at73c213 (AVR32 STK1000)"); + sprintf(card->longname, "%s at %p (irq %i)", card->shortname, chip->regs, chip->irq); + + retval = snd_card_register(card); + if (retval) + goto out_free_card; + + at32_set_drvdata(adev, card); + dev++; + return 0; + +out_free_card: + snd_card_free(card); +out: + at32_disable_device(adev); + return retval; +} + +static int __devexit snd_at73c213_remove(struct at32_device *adev) +{ + struct snd_card *card = at32_get_drvdata(adev); + struct snd_at73c213 *chip = card->private_data; + int retval; + + /* Stop playback */ + writel(SSC_CR_TXDIS, chip->regs + SSC_CR); + + /* Stop GLCK0 */ + writel(0, (void __iomem *)PM_BASE + PM_GCCTRL); + + /* Mute sound */ + write_reg(chip, DAC_LMPG, 0x3F); + chip->image[DAC_LMPG] = 0x3F; + write_reg(chip, DAC_RMPG, 0x3F); + chip->image[DAC_RMPG] = 0x3F; + write_reg(chip, DAC_LLOG, 0x3F); + chip->image[DAC_LLOG] = 0x3F; + write_reg(chip, DAC_RLOG, 0x3F); + chip->image[DAC_RLOG] = 0x3F; + write_reg(chip, DAC_LLIG, 0x11); + chip->image[DAC_LLIG] = 0x11; + write_reg(chip, DAC_RLIG, 0x11); + chip->image[DAC_RLIG] = 0x11; + write_reg(chip, DAC_AUXG, 0x11); + chip->image[DAC_AUXG] = 0x11; + + /* Turn off PA */ + write_reg(chip, PA_CTRL, (chip->image[PA_CTRL]|0x0F)); + chip->image[PA_CTRL] |= 0x0F; + msleep(10); + write_reg(chip, PA_CTRL, (1<image[PA_CTRL] = (1<image[DAC_CTRL] = 0x0C; + msleep(2); + write_reg(chip, DAC_CTRL, 0x00); + chip->image[DAC_CTRL] = 0x00; + + /* Turn off master power */ + write_reg(chip, DAC_PRECH, 0x00); + chip->image[DAC_PRECH] = 0x00; + + msleep(10); + +out: + if (chip->spi) + spi_unregister_device(chip->spi); + + if (card) { + snd_card_free(card); + at32_disable_device(adev); + at32_set_drvdata(adev, NULL); + } + + return 0; +} + +#ifdef CONFIG_PM +static int snd_at73c213_suspend(struct at32_device *adev, pm_message_t state, u32 level) +{ + struct snd_card *card = at32_get_drvdata(adev); + struct snd_at73c213 *chip = card->private_data; + + printk(KERN_DEBUG "at73c213: suspending\n"); + + /* Stop SSC and GCLK0 */ + + spi_suspend(chip->spi, state); + + return 0; +} + +static int snd_at73c213_resume(struct at32_device *adev, u32 level) +{ + struct snd_card *card = at32_get_drvdata(adev); + struct snd_at73c213 *chip = card->private_data; + + printk(KERN_DEBUG "at73c213: resuming\n"); + + /* Start GLCK0 and SSC */ + + spi_resume(chip->spi); + + return 0; +} +#endif /* CONFIG_PM */ + +/* Driver core initialization */ +static struct at32_driver at73c213_driver = { + .probe = snd_at73c213_probe, + .remove = __devexit_p(snd_at73c213_remove), + .driver = { + .name = "at73c213", + } +#ifdef CONFIG_PM + .resume = snd_at73c213_resume, + .suspend = snd_at73c213_suspend, +#endif +}; + +static int __init at73c213_init(void) +{ + return at32_driver_register(&at73c213_driver); +} + +static void __exit at73c213_exit(void) +{ + at32_driver_unregister(&at73c213_driver); +} + +MODULE_AUTHOR("Hans-Christian Egtvedt "); +MODULE_DESCRIPTION("Sound driver for at73c213 on STK1000"); +MODULE_LICENSE("GPL"); + +module_init(at73c213_init); +module_exit(at73c213_exit); + diff -Nur linux-2.6.16.11/sound/avr32/at73c213.h linux-2.6.16.11-avr32-20060626/sound/avr32/at73c213.h --- linux-2.6.16.11/sound/avr32/at73c213.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/avr32/at73c213.h 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,120 @@ +/* + * Driver for the AT73C213 16-bit stereo DAC on Atmel ATSTK1000 + * + * Copyright (C) 2006 Atmel Norway + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * The full GNU General Public License is included in this + * distribution in the file called COPYING. + */ + +#ifndef _SND_AT73C213_MIXER_H_ +#define _SND_AT73C213_MIXER_H_ + +/* DAC control register */ +#define DAC_CTRL 0x00 +#define DAC_CTRL_ONPADRV 7 +#define DAC_CTRL_ONAUXIN 6 +#define DAC_CTRL_ONDACR 5 +#define DAC_CTRL_ONDACL 4 +#define DAC_CTRL_ONLNOR 3 +#define DAC_CTRL_ONLNOL 2 +#define DAC_CTRL_ONLNIR 1 +#define DAC_CTRL_ONLNIL 0 + +/* DAC left line in gain register */ +#define DAC_LLIG 0x01 +#define DAC_LLIG_LLIG 0 + +/* DAC right line in gain register */ +#define DAC_RLIG 0x02 +#define DAC_RLIG_RLIG 0 + +/* DAC Left Master Playback Gain Register */ +#define DAC_LMPG 0x03 +#define DAC_LMPG_LMPG 0 + +/* DAC Right Master Playback Gain Register */ +#define DAC_RMPG 0x04 +#define DAC_RMPG_RMPG 0 + +/* DAC Left Line Out Gain Register */ +#define DAC_LLOG 0x05 +#define DAC_LLOG_LLOG 0 + +/* DAC Right Line Out Gain Register */ +#define DAC_RLOG 0x06 +#define DAC_RLOG_RLOG 0 + +/* DAC Output Level Control Register */ +#define DAC_OLC 0x07 +#define DAC_OLC_RSHORT 7 +#define DAC_OLC_ROLC 4 +#define DAC_OLC_LSHORT 3 +#define DAC_OLC_LOLC 0 + +/* DAC Mixer Control Register */ +#define DAC_MC 0x08 +#define DAC_MC_INVR 5 +#define DAC_MC_INVL 4 +#define DAC_MC_RMSMIN2 3 +#define DAC_MC_RMSMIN1 2 +#define DAC_MC_LMSMIN2 1 +#define DAC_MC_LMSMIN1 0 + +/* DAC Clock and Sampling Frequency Control Register */ +#define DAC_CSFC 0x09 +#define DAC_CSFC_OVRSEL 4 + +/* DAC Miscellaneous Register */ +#define DAC_MISC 0x0A +#define DAC_MISC_VCMCAPSEL 7 +#define DAC_MISC_DINTSEL 4 +#define DAC_MISC_DITHEN 3 +#define DAC_MISC_DEEMPEN 2 +#define DAC_MISC_NBITS 0 + +/* DAC Precharge Control Register */ +#define DAC_PRECH 0x0C +#define DAC_PRECH_PRCHGPDRV 7 +#define DAC_PRECH_PRCHGAUX1 6 +#define DAC_PRECH_PRCHGLNOR 5 +#define DAC_PRECH_PRCHGLNOL 4 +#define DAC_PRECH_PRCHGLNIR 3 +#define DAC_PRECH_PRCHGLNIL 2 +#define DAC_PRECH_PRCHG 1 +#define DAC_PRECH_ONMSTR 0 + +/* DAC Auxiliary Input Gain Control Register */ +#define DAC_AUXG 0x0D +#define DAC_AUXG_AUXG 0 + +/* DAC Reset Register */ +#define DAC_RST 0x10 +#define DAC_RST_RESMASK 2 +#define DAC_RST_RESFILZ 1 +#define DAC_RST_RSTZ 0 + +/* Power Amplifier Control Register */ +#define PA_CTRL 0x11 +#define PA_CTRL_APAON 6 +#define PA_CTRL_APAPRECH 5 +#define PA_CTRL_APALP 4 +#define PA_CTRL_APAGAIN 0 + +#endif + diff -Nur linux-2.6.16.11/sound/avr32/Kconfig linux-2.6.16.11-avr32-20060626/sound/avr32/Kconfig --- linux-2.6.16.11/sound/avr32/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/avr32/Kconfig 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,51 @@ +# ALSA AVR32 drivers + +menu "ALSA AVR32 devices" + depends on SND != n && AVR32 + +config SND_ATMEL_AC97 + tristate "Atmel AC97 Controller Driver" + depends on SND + select SND_PCM + select SND_AC97_CODEC + help + ALSA sound driver for the Atmel AC97 controller. + +config SND_ATMEL_AC97_USE_ALSA_MALLOC_CALLS + bool "Use the built-in malloc calls in the alsa driver" + default n + depends on SND_ATMEL_AC97 + help + Say Y if the built-in malloc calls in the alsa driver should be + used instead of the native dma_alloc_coherent and dma_free_coherent + function calls. Enabling this feature may brake the rmmod feature. + +config SND_ATMEL_AC97C_USE_PDC + bool "Use PDC for DMA transfers to/from the Atmel AC97 Controller" + default n + depends on SND_ATMEL_AC97 + help + Say Y if PDC (Peripheral DMA Controller) is used for DMA transfers + to/from the Atmel AC97C instead of using the generic DMA framework. + +config SND_AT73C213 + tristate "Atmel AT73C213 DAC driver" + depends on SND && SPI_ATMEL + select SND_PCM + help + Say Y here if you want to use the Atmel AT73C213 external + DAC on the ATSTK1000 development board. + + To compile this driver as a module, choose M here: the + module will be called snd-at73c213. + +config SND_AT73C213_USE_ALSA_MALLOC_CALLS + bool "Use the built-in malloc calls in the alsa driver" + default n + depends on SND_AT73C213 + help + Say Y if the built-in malloc calls in the alsa driver should be + used instead of the native dma_alloc_coherent and dma_free_coherent + function calls. Enabling this feature may brake the rmmod feature. + +endmenu diff -Nur linux-2.6.16.11/sound/avr32/Kconfig.orig linux-2.6.16.11-avr32-20060626/sound/avr32/Kconfig.orig --- linux-2.6.16.11/sound/avr32/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/avr32/Kconfig.orig 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,42 @@ +# ALSA AVR32 drivers + +menu "ALSA AVR32 devices" + depends on SND != n && AVR32 + +config SND_ATMEL_AC97 + tristate "Atmel AC97 Controller Driver" + depends on SND + select SND_PCM + select SND_AC97_CODEC + help + ALSA sound driver for the Atmel AC97 controller. + +config SND_ATMEL_AC97_USE_ALSA_MALLOC_CALLS + bool "Use the built-in malloc calls in the alsa driver" + default n + depends on SND_ATMEL_AC97 + help + Say Y if the built-in malloc calls in the alsa driver should be + used instead of the native dma_alloc_coherent and dma_free_coherent + function calls. Enabling this feature may brake the rmmod feature. + +config SND_ATMEL_AC97C_USE_PDC + bool "Use PDC for DMA transfers to/from the Atmel AC97 Controller" + default n + depends on SND_ATMEL_AC97 + help + Say Y if PDC (Peripheral DMA Controller) is used for DMA transfers + to/from the Atmel AC97C instead of using the generic DMA framework. + +config SND_AT73C213 + tristate "Atmel AT73C213 DAC driver" + depends on SND && SPI_ATMEL + select SND_PCM + help + Say Y here if you want to use the Atmel AT73C213 external + DAC on the ATSTK1000 development board. + + To compile this driver as a module, choose M here: the + module will be called snd-at73c213. + +endmenu diff -Nur linux-2.6.16.11/sound/avr32/Makefile linux-2.6.16.11-avr32-20060626/sound/avr32/Makefile --- linux-2.6.16.11/sound/avr32/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/avr32/Makefile 2006-06-26 11:33:53.000000000 +0200 @@ -0,0 +1,9 @@ +# +# Makefile for ALSA +# + +snd-atmel-ac97-objs := ac97c.o +snd-at73c213-objs := at73c213.o + +obj-$(CONFIG_SND_ATMEL_AC97) += snd-atmel-ac97.o +obj-$(CONFIG_SND_AT73C213) += snd-at73c213.o diff -Nur linux-2.6.16.11/sound/Kconfig linux-2.6.16.11-avr32-20060626/sound/Kconfig --- linux-2.6.16.11/sound/Kconfig 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/Kconfig 2006-06-26 11:33:53.000000000 +0200 @@ -60,6 +60,8 @@ source "sound/arm/Kconfig" +source "sound/avr32/Kconfig" + source "sound/mips/Kconfig" # the following will depenend on the order of config. diff -Nur linux-2.6.16.11/sound/Makefile linux-2.6.16.11-avr32-20060626/sound/Makefile --- linux-2.6.16.11/sound/Makefile 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/Makefile 2006-06-26 11:33:53.000000000 +0200 @@ -5,6 +5,7 @@ obj-$(CONFIG_SOUND_PRIME) += oss/ obj-$(CONFIG_DMASOUND) += oss/ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ +obj-$(CONFIG_SND) += avr32/ ifeq ($(CONFIG_SND),y) obj-y += last.o diff -Nur linux-2.6.16.11/sound/oss/at32dac.c linux-2.6.16.11-avr32-20060626/sound/oss/at32dac.c --- linux-2.6.16.11/sound/oss/at32dac.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/oss/at32dac.c 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,696 @@ +/* + * OSS Sound Driver for the Atmel AT32 on-chip DAC. + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* We want to use the "bizarre" swap-bytes-in-each-halfword macro */ +#include + +#include "at32dac.h" + +#define DMA_BUFFER_SIZE 32768 +#define DMA_PERIOD_SHIFT 10 +#define DMA_PERIOD_SIZE (1 << DMA_PERIOD_SHIFT) +#define DMA_WRITE_THRESHOLD DMA_PERIOD_SIZE + +struct sound_settings { + unsigned int format; + unsigned int channels; + unsigned int sample_rate; + /* log2(bytes per sample) */ + unsigned int input_order; +}; + +struct at32_dac { + spinlock_t lock; + void __iomem *regs; + + /* head and tail refer to number of words */ + struct { + u32 *buf; + int head; + int tail; + } dma; + + struct semaphore sem; + wait_queue_head_t write_wait; + + /* + * Read at most ucount bytes from ubuf, translate to 2-channel + * signed 16-bit big endian format and write to the DMA buffer + * as long as there is room left. Return the number of bytes + * successfully copied from ubuf, or -EFAULT if the first + * sample from ubuf couldn't be read. This function is not + * called unless there is room for at least one sample (4 + * bytes) in the DMA buffer. + */ + int (*trans)(struct at32_dac *dac, const char __user *ubuf, + size_t ucount); + + struct sound_settings dsp_settings; + struct dma_request_cyclic req; + + struct at32_device *adev; + int busy; + int playing; + int dev_dsp; +}; +static struct at32_dac *the_dac; + +static inline unsigned int at32dac_get_head(struct at32_dac *dac) +{ + return dac->dma.head & ((DMA_BUFFER_SIZE / 4) - 1); +} + +static inline unsigned int at32dac_get_tail(struct at32_dac *dac) +{ + return dac->dma.tail & ((DMA_BUFFER_SIZE / 4) - 1); +} + +static inline unsigned int at32dac_dma_space(struct at32_dac *dac) +{ + unsigned int space; + + space = ((dac->dma.tail - dac->dma.head - 1) + & ((DMA_BUFFER_SIZE / 4) - 1)); + return space; +} + +static void at32dac_update_dma_tail(struct at32_dac *dac) +{ + dma_addr_t dma_addr; + unsigned int new_tail; + + if (dac->playing) { + dma_addr = dma_get_current_pos(dac->req.req.dmac, + dac->req.req.channel); + new_tail = (dma_addr - dac->req.buffer_start) / 4; + if (new_tail >= dac->dma.head + && (dac->dma.tail < dac->dma.head + || dac->dma.tail > new_tail)) + printk(KERN_NOTICE "at32dac: underrun\n"); + dac->dma.tail = new_tail; + pr_debug("update tail: 0x%x - 0x%x = %u\n", + dma_addr, dac->req.buffer_start, dac->dma.tail); + } +} + +static int at32dac_start_genclock(struct at32_dac *dac) +{ + unsigned int div; + + div = ((boot_cpu_data.cpu_hz + 256 * dac->dsp_settings.sample_rate) + / (512 * dac->dsp_settings.sample_rate) - 1); + pr_debug("Real sample rate: %llu (div=%u)\n", + boot_cpu_data.cpu_hz / (512 * (div + 1)), div); + writel((div << 8) | 0x16, (void __iomem *)(0xfff00060 + 4 * 6)); + + return 0; +} + +static void at32dac_stop_genclock(struct at32_dac *dac) +{ + writel(0, (void __iomem *)(0xfff00060 + 4 * 6)); +} + +static int at32dac_start(struct at32_dac *dac) +{ + int ret; + + if (dac->playing) + return 0; + + memset(dac->dma.buf, 0, DMA_BUFFER_SIZE); + + ret = at32dac_start_genclock(dac); + if (ret) + return ret; + + ret = dma_prepare_request_cyclic(dac->req.req.dmac, &dac->req); + if (ret) + goto out_stop_genclock; + + pr_debug("Starting DMA...\n"); + ret = dma_start_request(dac->req.req.dmac, dac->req.req.channel); + if (ret) + goto out_stop_request; + + dac_writel(dac, CTRL, DAC_BIT(EN)); + dac->playing = 1; + + return 0; + +out_stop_request: + dma_stop_request(dac->req.req.dmac, + dac->req.req.channel); +out_stop_genclock: + at32dac_stop_genclock(dac); + return ret; +} + +static int at32dac_stop(struct at32_dac *dac) +{ + if (dac->playing) { + dma_stop_request(dac->req.req.dmac, dac->req.req.channel); + dac_writel(dac, DATA, 0); + dac_writel(dac, CTRL, 0); + dac->playing = 0; + at32dac_stop_genclock(dac); + } + + return 0; +} + +static int at32dac_dma_prepare(struct at32_dac *dac) +{ + dac->dma.buf = dma_alloc_coherent(&dac->adev->dev, DMA_BUFFER_SIZE, + &dac->req.buffer_start, GFP_KERNEL); + if (!dac->dma.buf) + return -ENOMEM; + + dac->dma.head = dac->dma.tail = 0; + dac->req.periods = DMA_BUFFER_SIZE / DMA_PERIOD_SIZE; + dac->req.buffer_size = DMA_BUFFER_SIZE; + + return 0; +} + +static void at32dac_dma_cleanup(struct at32_dac *dac) +{ + if (dac->dma.buf) + dma_free_coherent(&dac->adev->dev, DMA_BUFFER_SIZE, + dac->dma.buf, dac->req.buffer_start); + dac->dma.buf = NULL; +} + +static void at32dac_dma_block_complete(struct dma_request *req) +{ + struct dma_request_cyclic *creq = to_dma_request_cyclic(req); + struct at32_dac *dac = container_of(creq, struct at32_dac, req); + + wake_up(&dac->write_wait); +} + +static void at32dac_dma_error(struct dma_request *req) +{ + printk(KERN_ERR "at32dac: DMA error\n"); +} + +static irqreturn_t at32dac_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct at32_dac *dac = dev_id; + u32 status; + + status = dac_readl(dac, INT_STATUS); + if (status & DAC_BIT(UNDERRUN)) { + printk(KERN_ERR "at32dac: Underrun detected\n"); + dac_writel(dac, INT_CLR, DAC_BIT(UNDERRUN)); + } else { + printk(KERN_ERR "at32dac: Spurious interrupt: status=0x%x\n", + status); + dac_writel(dac, INT_CLR, status); + } + + return IRQ_HANDLED; +} + +static ssize_t trans_s16be(struct at32_dac *dac, const char __user *ubuf, + size_t ucount) +{ + ssize_t ret; + + if (dac->dsp_settings.channels == 2) { + const u32 __user *up = (const u32 __user *)ubuf; + u32 sample; + + for (ret = 0; ret < (ssize_t)(ucount - 3); ret += 4) { + if (!at32dac_dma_space(dac)) + break; + + if (unlikely(__get_user(sample, up++))) { + if (ret == 0) + ret = -EFAULT; + break; + } + dac->dma.buf[at32dac_get_head(dac)] = sample; + dac->dma.head++; + } + } else { + const u16 __user *up = (const u16 __user *)ubuf; + u16 sample; + + for (ret = 0; ret < (ssize_t)(ucount - 1); ret += 2) { + if (!at32dac_dma_space(dac)) + break; + + if (unlikely(__get_user(sample, up++))) { + if (ret == 0) + ret = -EFAULT; + break; + } + dac->dma.buf[at32dac_get_head(dac)] + = (sample << 16) | sample; + dac->dma.head++; + } + } + + return ret; +} + +static ssize_t trans_s16le(struct at32_dac *dac, const char __user *ubuf, + size_t ucount) +{ + ssize_t ret; + + if (dac->dsp_settings.channels == 2) { + const u32 __user *up = (const u32 __user *)ubuf; + u32 sample; + + for (ret = 0; ret < (ssize_t)(ucount - 3); ret += 4) { + if (!at32dac_dma_space(dac)) + break; + + if (unlikely(__get_user(sample, up++))) { + if (ret == 0) + ret = -EFAULT; + break; + } + /* Swap bytes in each halfword */ + dac->dma.buf[at32dac_get_head(dac)] = swahb32(sample); + dac->dma.head++; + } + } else { + const u16 __user *up = (const u16 __user *)ubuf; + u16 sample; + + for (ret = 0; ret < (ssize_t)(ucount - 1); ret += 2) { + if (!at32dac_dma_space(dac)) + break; + + if (unlikely(__get_user(sample, up++))) { + if (ret == 0) + ret = -EFAULT; + break; + } + sample = swab16(sample); + dac->dma.buf[at32dac_get_head(dac)] + = (sample << 16) | sample; + dac->dma.head++; + } + } + + return ret; +} + +static ssize_t at32dac_dma_translate_from_user(struct at32_dac *dac, + const char __user *buffer, + size_t count) +{ + /* At least one buffer must be available at this point */ + pr_debug("at32dac: Copying %zu bytes from user...\n", count); + + return dac->trans(dac, buffer, count); +} + +static int at32dac_set_format(struct at32_dac *dac, int format) +{ + unsigned int order; + + switch (format) { + case AFMT_S16_BE: + order = 1; + dac->trans = trans_s16be; + break; + case AFMT_S16_LE: + order = 1; + dac->trans = trans_s16le; + break; + default: + printk("at32dac: Unsupported format: %d\n", format); + return -EINVAL; + } + + if (dac->dsp_settings.channels == 2) + order++; + + dac->dsp_settings.input_order = order; + dac->dsp_settings.format = format; + return 0; +} + +static ssize_t at32dac_dsp_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct at32_dac *dac = file->private_data; + DECLARE_WAITQUEUE(wait, current); + unsigned int avail; + ssize_t copied; + ssize_t ret; + + /* Avoid address space checking in the translation functions */ + if (!access_ok(buffer, count, VERIFY_READ)) + return -EFAULT; + + down(&dac->sem); + + if (!dac->dma.buf) { + ret = at32dac_dma_prepare(dac); + if (ret) + goto out; + } + + add_wait_queue(&dac->write_wait, &wait); + ret = 0; + while (count > 0) { + do { + at32dac_update_dma_tail(dac); + avail = at32dac_dma_space(dac); + set_current_state(TASK_INTERRUPTIBLE); + if (avail >= DMA_WRITE_THRESHOLD) + break; + + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + goto out; + } + + pr_debug("Going to wait (avail = %u, count = %zu)\n", + avail, count); + + up(&dac->sem); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + goto out_nosem; + } + down(&dac->sem); + } while (1); + + copied = at32dac_dma_translate_from_user(dac, buffer, count); + if (copied < 0) { + if (!ret) + ret = -EFAULT; + goto out; + } + + at32dac_start(dac); + + count -= copied; + ret += copied; + } + +out: + up(&dac->sem); +out_nosem: + remove_wait_queue(&dac->write_wait, &wait); + set_current_state(TASK_RUNNING); + return ret; +} + +static int at32dac_dsp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct at32_dac *dac = file->private_data; + int __user *up = (int __user *)arg; + struct audio_buf_info abinfo; + int val, ret; + + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, up); + + case SNDCTL_DSP_SPEED: + if (get_user(val, up)) + return -EFAULT; + if (val >= 0) { + at32dac_stop(dac); + dac->dsp_settings.sample_rate = val; + } + return put_user(dac->dsp_settings.sample_rate, up); + + case SNDCTL_DSP_STEREO: + if (get_user(val, up)) + return -EFAULT; + at32dac_stop(dac); + if (val && dac->dsp_settings.channels == 1) + dac->dsp_settings.input_order++; + else if (!val && dac->dsp_settings.channels != 1) + dac->dsp_settings.input_order--; + dac->dsp_settings.channels = val ? 2 : 1; + return 0; + + case SNDCTL_DSP_CHANNELS: + if (get_user(val, up)) + return -EFAULT; + + if (val) { + if (val < 0 || val > 2) + return -EINVAL; + + at32dac_stop(dac); + dac->dsp_settings.input_order + += val - dac->dsp_settings.channels; + dac->dsp_settings.channels = val; + } + return put_user(val, (int *)arg); + + case SNDCTL_DSP_GETFMTS: + return put_user(AFMT_S16_BE | AFMT_S16_BE, up); + + case SNDCTL_DSP_SETFMT: + if (get_user(val, up)) + return -EFAULT; + + if (val == AFMT_QUERY) { + val = dac->dsp_settings.format; + } else { + ret = at32dac_set_format(dac, val); + if (ret) + return ret; + } + return put_user(val, up); + + case SNDCTL_DSP_GETOSPACE: + at32dac_update_dma_tail(dac); + abinfo.fragsize = ((1 << dac->dsp_settings.input_order) + * (DMA_PERIOD_SIZE / 4)); + abinfo.bytes = (at32dac_dma_space(dac) + << dac->dsp_settings.input_order); + abinfo.fragstotal = ((DMA_BUFFER_SIZE * 4) + >> (DMA_PERIOD_SHIFT + + dac->dsp_settings.input_order)); + abinfo.fragments = ((abinfo.bytes + >> dac->dsp_settings.input_order) + / (DMA_PERIOD_SIZE / 4)); + pr_debug("fragments=%d fragstotal=%d fragsize=%d bytes=%d\n", + abinfo.fragments, abinfo.fragstotal, abinfo.fragsize, + abinfo.bytes); + return copy_to_user(up, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + default: + printk("at32dac: Unimplemented ioctl cmd: 0x%x\n", cmd); + return -EINVAL; + } +} + +static int at32dac_dsp_open(struct inode *inode, struct file *file) +{ + struct at32_dac *dac = the_dac; + int ret; + + if (file->f_mode & FMODE_READ) + return -ENXIO; + + down(&dac->sem); + ret = -EBUSY; + if (dac->busy) + goto out; + + dac->dma.head = dac->dma.tail = 0; + + /* FIXME: What are the correct defaults? */ + dac->dsp_settings.format = AFMT_S16_BE; + dac->dsp_settings.channels = 2; + dac->dsp_settings.sample_rate = 8000; + dac->dsp_settings.input_order = 2; + + file->private_data = dac; + dac->busy = 1; + + ret = 0; + +out: + up(&dac->sem); + return ret; +} + +static int at32dac_dsp_release(struct inode *inode, struct file *file) +{ + struct at32_dac *dac = file->private_data; + + down(&dac->sem); + + at32dac_stop(dac); + at32dac_dma_cleanup(dac); + dac->busy = 0; + + up(&dac->sem); + + return 0; +} + +static struct file_operations at32dac_dsp_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = at32dac_dsp_write, + .ioctl = at32dac_dsp_ioctl, + .open = at32dac_dsp_open, + .release = at32dac_dsp_release, +}; + +static int __devinit at32dac_probe(struct at32_device *adev) +{ + struct at32_dac *dac; + int ret; + + if (the_dac) + return -EBUSY; + + ret = at32_enable_device(adev); + if (ret) + goto out; + + ret = -ENOMEM; + dac = kzalloc(sizeof(struct at32_dac), GFP_KERNEL); + if (!dac) + goto out_disable_dev; + + spin_lock_init(&dac->lock); + init_MUTEX(&dac->sem); + init_waitqueue_head(&dac->write_wait); + dac->adev = adev; + + dac->regs = at32_map_iomem(adev, 0); + if (!dac->regs) + goto out_free_dac; + + ret = request_irq(at32_get_irq(adev), at32dac_interrupt, + 0, "dac", dac); + if (ret) + goto out_unmap_regs; + + /* FIXME */ + dac->req.req.dmac = find_dma_controller(0); + if (!dac->req.req.dmac) + goto out_free_irq; + + ret = dma_alloc_channel(dac->req.req.dmac); + if (ret < 0) + goto out_free_irq; + + dac->req.req.channel = ret; + dac->req.req.block_complete = at32dac_dma_block_complete; + dac->req.req.error = at32dac_dma_error; + dac->req.data_reg = at32_get_iomem_base(adev, 0) + DAC_DATA; + dac->req.periph_id = 2; /* FIXME */ + dac->req.direction = DMA_DIR_MEM_TO_PERIPH; + dac->req.width = DMA_WIDTH_32BIT; + + /* Make sure the DAC is silent and disabled */ + dac_writel(dac, DATA, 0); + dac_writel(dac, CTRL, 0); + + ret = register_sound_dsp(&at32dac_dsp_fops, -1); + if (ret < 0) + goto out_free_dma; + dac->dev_dsp = ret; + + /* TODO: Register mixer */ + + the_dac = dac; + at32_set_drvdata(adev, dac); + + return 0; + +out_free_dma: + dma_release_channel(dac->req.req.dmac, dac->req.req.channel); +out_free_irq: + free_irq(at32_get_irq(adev), dac); +out_unmap_regs: + iounmap(dac->regs); +out_free_dac: + kfree(dac); +out_disable_dev: + at32_disable_device(adev); +out: + return ret; +} + +static int __devexit at32dac_remove(struct at32_device *adev) +{ + struct at32_dac *dac; + + dac = at32_get_drvdata(adev); + if (dac) { + unregister_sound_dsp(dac->dev_dsp); + dma_release_channel(dac->req.req.dmac, dac->req.req.channel); + free_irq(at32_get_irq(adev), dac); + iounmap(dac->regs); + kfree(dac); + at32_disable_device(adev); + at32_set_drvdata(adev, NULL); + the_dac = NULL; + } + + return 0; +} + +static struct at32_driver at32dac_driver = { + .probe = at32dac_probe, + .remove = __devexit_p(at32dac_remove), + .driver = { + .name = "dac", + }, +}; + +static int __init at32dac_init(void) +{ + return at32_driver_register(&at32dac_driver); +} +module_init(at32dac_init); + +static void __exit at32dac_exit(void) +{ + at32_driver_unregister(&at32dac_driver); +} +module_exit(at32dac_exit); + +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_DESCRIPTION("DMA Sound Driver for the Atmel AT32 on-chip DAC"); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.16.11/sound/oss/at32dac.h linux-2.6.16.11-avr32-20060626/sound/oss/at32dac.h --- linux-2.6.16.11/sound/oss/at32dac.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/oss/at32dac.h 2006-06-26 11:33:54.000000000 +0200 @@ -0,0 +1,63 @@ +/* + * Register definitions for the Atmel AT32 on-chip DAC. + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_AVR32_DAC_H__ +#define __ASM_AVR32_DAC_H__ + +/* DAC register offsets */ +#define DAC_DATA 0x0000 +#define DAC_CTRL 0x0008 +#define DAC_INT_MASK 0x000c +#define DAC_INT_EN 0x0010 +#define DAC_INT_DIS 0x0014 +#define DAC_INT_CLR 0x0018 +#define DAC_INT_STATUS 0x001c +#define DAC_PDC_DATA 0x0020 + +/* Bitfields in DATA */ +#define DAC_DATA_OFFSET 0 +#define DAC_DATA_SIZE 32 + +/* Bitfields in CTRL */ +#define DAC_SWAP_OFFSET 30 +#define DAC_SWAP_SIZE 1 +#define DAC_EN_OFFSET 31 +#define DAC_EN_SIZE 1 + +/* Bitfields in INT_MASK */ + +/* Bitfields in INT_EN */ + +/* Bitfields in INT_DIS */ +#define DAC_TX_READY_OFFSET 29 +#define DAC_TX_READY_SIZE 1 +#define DAC_TX_BUFFER_EMPTY_OFFSET 30 +#define DAC_TX_BUFFER_EMPTY_SIZE 1 +#define DAC_CHANNEL_TX_END_OFFSET 31 +#define DAC_CHANNEL_TX_END_SIZE 1 + +/* Bitfields in INT_CLR */ +#define DAC_UNDERRUN_OFFSET 28 +#define DAC_UNDERRUN_SIZE 1 + +/* Bitfields in INT_STATUS */ + +/* Bitfields in PDC_DATA */ + +/* Bit manipulation macros */ +#define DAC_BIT(name) (1 << DAC_##name##_OFFSET) +#define DAC_BF(name,value) (((value) & ((1 << DAC_##name##_SIZE) - 1)) << DAC_##name##_OFFSET) +#define DAC_BFEXT(name,value) (((value) >> DAC_##name##_OFFSET) & ((1 << DAC_##name##_SIZE) - 1)) +#define DAC_BFINS(name,value,old) (((old) & ~(((1 << DAC_##name##_SIZE) - 1) << DAC_##name##_OFFSET)) | DAC_BF(name,value)) + +/* Register access macros */ +#define dac_readl(port,reg) readl((port)->regs + DAC_##reg) +#define dac_writel(port,reg,value) writel((value), (port)->regs + DAC_##reg) + +#endif /* __ASM_AVR32_DAC_H__ */ diff -Nur linux-2.6.16.11/sound/oss/Kconfig linux-2.6.16.11-avr32-20060626/sound/oss/Kconfig --- linux-2.6.16.11/sound/oss/Kconfig 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/oss/Kconfig 2006-06-26 11:33:54.000000000 +0200 @@ -1133,3 +1133,7 @@ int " DAC channel" default "1" depends on SOUND_SH_DAC_AUDIO + +config SOUND_AT32_DAC + tristate "Atmel AT32 On-chip DAC support" + depends on SOUND_PRIME && AVR32 diff -Nur linux-2.6.16.11/sound/oss/Makefile linux-2.6.16.11-avr32-20060626/sound/oss/Makefile --- linux-2.6.16.11/sound/oss/Makefile 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.11-avr32-20060626/sound/oss/Makefile 2006-06-26 11:33:54.000000000 +0200 @@ -10,6 +10,7 @@ # Please leave it as is, cause the link order is significant ! +obj-$(CONFIG_SOUND_AT32_DAC) += at32dac.o obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o obj-$(CONFIG_SOUND_HAL2) += hal2.o obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o