--- /dev/null +++ b/arch/m68k/coldfire/cache.c @@ -0,0 +1,43 @@ +/* + * linux/arch/m68k/coldfire/cache.c + * + * Matt Waddel Matt.Waddel@freescale.com + * Kurt Mahan kmahan@freescale.com + * Copyright Freescale Semiconductor, Inc. 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include + +/* Cache Control Reg shadow reg */ +unsigned long shadow_cacr; + +/** + * cacr_set - Set the Cache Control Register + * @x Value to set + */ +void cacr_set(unsigned long x) +{ + shadow_cacr = x; + + __asm__ __volatile__ ("movec %0, %%cacr" + : /* no outputs */ + : "r" (shadow_cacr)); +} + +/** + * cacr_get - Get the current value of the Cache Control Register + * + * @return CACR value + */ +unsigned long cacr_get(void) +{ + return shadow_cacr; +} --- /dev/null +++ b/arch/m68k/coldfire/config.c @@ -0,0 +1,483 @@ +/* + * linux/arch/m68k/coldfire/config.c + * + * Kurt Mahan kmahan@freescale.com + * Matt Waddel Matt.Waddel@freescale.com + * Copyright Freescale Semiconductor, Inc. 2007, 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(CONFIG_M5445X) +#define UBOOT_EXTRA_CLOCKS +#elif defined(CONFIG_M547X_8X) +#define UBOOT_PCI +#endif +#include + +#ifdef CONFIG_M5445X +#include +#include +#include +#include +#include +#endif + +#ifdef CONFIG_M547X_8X +#include +#endif + +extern int get_irq_list(struct seq_file *p, void *v); +extern char _text, _end; +extern char _etext, _edata, __init_begin, __init_end; +extern struct console mcfrs_console; +extern char m68k_command_line[CL_SIZE]; +extern unsigned long availmem; + +static int irq_enable[NR_IRQS]; +unsigned long num_pages; + +/* ethernet mac addresses from uboot */ +unsigned char uboot_enet0[6]; +unsigned char uboot_enet1[6]; + +void coldfire_sort_memrec(void) +{ + int i, j; + + /* Sort the m68k_memory records by address */ + for (i = 0; i < m68k_num_memory; ++i) { + for (j = i + 1; j < m68k_num_memory; ++j) { + if (m68k_memory[i].addr > m68k_memory[j].addr) { + struct mem_info tmp; + tmp = m68k_memory[i]; + m68k_memory[i] = m68k_memory[j]; + m68k_memory[j] = tmp; + } + } + } + /* Trim off discontiguous bits */ + for (i = 1; i < m68k_num_memory; ++i) { + if ((m68k_memory[i-1].addr + m68k_memory[i-1].size) != + m68k_memory[i].addr) { + printk(KERN_DEBUG "m68k_parse_bootinfo: addr gap between \ + 0x%lx & 0x%lx\n", + m68k_memory[i-1].addr+m68k_memory[i-1].size, + m68k_memory[i].addr); + m68k_num_memory = i; + break; + } + } +} + +/* + * UBoot Handler + */ +int __init uboot_commandline(char *bootargs) +{ + int len = 0, cmd_line_len; + static struct uboot_record uboot_info; + u32 offset = PAGE_OFFSET_RAW - PHYS_OFFSET; + + extern unsigned long uboot_info_stk; + + /* validate address */ + if ((uboot_info_stk < PAGE_OFFSET_RAW) || + (uboot_info_stk >= (PAGE_OFFSET_RAW + CONFIG_SDRAM_SIZE))) + return 0; + + /* Add offset to get post-remapped kernel memory location */ + uboot_info.bdi = (struct bd_info *)((*(u32 *)(uboot_info_stk)) + offset); + uboot_info.initrd_start = (*(u32 *)(uboot_info_stk+4)) + offset; + uboot_info.initrd_end = (*(u32 *)(uboot_info_stk+8)) + offset; + uboot_info.cmd_line_start = (*(u32 *)(uboot_info_stk+12)) + offset; + uboot_info.cmd_line_stop = (*(u32 *)(uboot_info_stk+16)) + offset; + + /* copy over mac addresses */ + memcpy(uboot_enet0, uboot_info.bdi->bi_enet0addr, 6); + memcpy(uboot_enet1, uboot_info.bdi->bi_enet1addr, 6); + + /* copy command line */ + cmd_line_len = uboot_info.cmd_line_stop - uboot_info.cmd_line_start; + if ((cmd_line_len > 0) && (cmd_line_len < CL_SIZE-1)) + len = (int)strncpy(bootargs, (char *)uboot_info.cmd_line_start,\ + cmd_line_len); + + return len; +} + +/* + * This routine does things not done in the bootloader. + */ +#if defined(CONFIG_M54451) +#define DEFAULT_COMMAND_LINE "debug root=/dev/nfs rw nfsroot=172.27.155.1:/tftpboot/redstripe/rootfs/ ip=172.27.155.51:172.27.155.1" +#elif defined(CONFIG_M54455) +#define MTD_DEFAULT_COMMAND_LINE "root=/dev/mtdblock1 rw rootfstype=jffs2 ip=none mtdparts=physmap-flash.0:5M(kernel)ro,-(jffs2)" +#define DEFAULT_COMMAND_LINE "debug root=/dev/nfs rw nfsroot=172.27.155.1:/tftpboot/redstripe/rootfs/ ip=172.27.155.55:172.27.155.1" +#elif defined(CONFIG_M547X_8X) +#define DEFAULT_COMMAND_LINE "debug root=/dev/nfs rw nfsroot=172.27.155.1:/tftpboot/rigo/rootfs/ ip=172.27.155.75:172.27.155.1" +#endif +asmlinkage void __init cf_early_init(void) +{ + struct bi_record *record = (struct bi_record *) &_end; + + extern char _end; + +#if defined(CONFIG_M5445X) + SET_VBR((void *)MCF_RAMBAR1); +#elif defined(CONFIG_M547X_8X) + SET_VBR((void *)MCF_RAMBAR0); +#endif + + /* Mask all interrupts */ +#if defined(CONFIG_M5445X) + MCF_INTC0_IMRL = 0xFFFFFFFF; + MCF_INTC0_IMRH = 0xFFFFFFFF; + MCF_INTC1_IMRL = 0xFFFFFFFF; + MCF_INTC1_IMRH = 0xFFFFFFFF; +#elif defined(CONFIG_M547X_8X) + MCF_IMRL = 0xFFFFFFFF; + MCF_IMRH = 0xFFFFFFFF; +#endif + +#if defined(CONFIG_M5445X) +#if defined(CONFIG_NOR_FLASH_BASE) + MCF_FBCS_CSAR(1) = CONFIG_NOR_FLASH_BASE; +#else + MCF_FBCS_CSAR(1) = 0x00000000; +#endif + +#if CONFIG_SDRAM_SIZE > (256*1024*1024) + /* Init optional SDRAM chip select */ + MCF_SDRAMC_SDCS(1) = (256*1024*1024) | 0x1B; +#endif +#endif /* CONFIG_M5445X */ + +#if defined(CONFIG_M5445X) + /* Setup SDRAM crossbar(XBS) priorities */ + MCF_XBS_PRS2 = (MCF_XBS_PRS_M0(MCF_XBS_PRI_2) | + MCF_XBS_PRS_M1(MCF_XBS_PRI_3) | + MCF_XBS_PRS_M2(MCF_XBS_PRI_4) | + MCF_XBS_PRS_M3(MCF_XBS_PRI_5) | + MCF_XBS_PRS_M5(MCF_XBS_PRI_6) | + MCF_XBS_PRS_M6(MCF_XBS_PRI_1) | + MCF_XBS_PRS_M7(MCF_XBS_PRI_7)); +#endif + + m68k_machtype = MACH_CFMMU; + m68k_fputype = FPU_CFV4E; + m68k_mmutype = MMU_CFV4E; + m68k_cputype = CPU_CFV4E; + + m68k_num_memory = 0; + m68k_memory[m68k_num_memory].addr = CONFIG_SDRAM_BASE; + m68k_memory[m68k_num_memory++].size = CONFIG_SDRAM_SIZE; + + if (!uboot_commandline(m68k_command_line)) { +#if defined(CONFIG_BOOTPARAM) + strncpy(m68k_command_line, CONFIG_BOOTPARAM_STRING, CL_SIZE-1); +#else + strcpy(m68k_command_line, DEFAULT_COMMAND_LINE); +#endif + } + +#if defined(CONFIG_BLK_DEV_INITRD) + /* add initrd image */ + record = (struct bi_record *) ((void *)record + record->size); + record->tag = BI_RAMDISK; + record->size = sizeof(record->tag) + sizeof(record->size) + + sizeof(record->data[0]) + sizeof(record->data[1]); +#endif + + /* Mark end of tags. */ + record = (struct bi_record *) ((void *) record + record->size); + record->tag = 0; + record->data[0] = 0; + record->data[1] = 0; + record->size = sizeof(record->tag) + sizeof(record->size) + + sizeof(record->data[0]) + sizeof(record->data[1]); + + /* Invalidate caches via CACR */ + flush_bcache(); + cacr_set(CACHE_DISABLE_MODE); + + /* Turn on caches via CACR, enable EUSP */ + cacr_set(CACHE_INITIAL_MODE); + +} + +#if defined(CONFIG_M5445X) +void settimericr(unsigned int timer, unsigned int level) +{ + volatile unsigned char *icrp; + unsigned int icr; + unsigned char irq; + + if (timer <= 2) { + switch (timer) { + case 2: irq = 33; icr = MCFSIM_ICR_TIMER2; break; + default: irq = 32; icr = MCFSIM_ICR_TIMER1; break; + } + + icrp = (volatile unsigned char *) (icr); + *icrp = level; + coldfire_enable_irq0(irq); + } +} +#endif + +/* Assembler routines */ +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void system_call(void); +asmlinkage void inthandler(void); + +void __init coldfire_trap_init(void) +{ + int i = 0; + e_vector *vectors; + +#if defined(CONFIG_M5445X) + vectors = (e_vector *)MCF_RAMBAR1; +#elif defined(CONFIG_M547X_8X) + vectors = (e_vector *)MCF_RAMBAR0; +#endif + /* + * There is a common trap handler and common interrupt + * handler that handle almost every vector. We treat + * the system call and bus error special, they get their + * own first level handlers. + */ + for (i = 3; (i <= 23); i++) + vectors[i] = trap; + for (i = 33; (i <= 63); i++) + vectors[i] = trap; + for (i = 24; (i <= 31); i++) + vectors[i] = inthandler; + for (i = 64; (i < 255); i++) + vectors[i] = inthandler; + + vectors[255] = 0; + vectors[2] = buserr; + vectors[32] = system_call; +} + +#if defined(CONFIG_M5445X) + +void coldfire_tick(void) +{ + /* Reset the ColdFire timer */ + __raw_writeb(MCF_DTIM_DTER_CAP | MCF_DTIM_DTER_REF, MCF_DTIM0_DTER); +} + +void __init coldfire_sched_init(irq_handler_t handler) +{ + unsigned int mcf_timerlevel = 5; + unsigned int mcf_timervector = 64+32; + + __raw_writew(MCF_DTIM_DTMR_RST_RST, MCF_DTIM0_DTMR); + __raw_writel(((MCF_BUSCLK / 16) / HZ), MCF_DTIM0_DTRR); + __raw_writew(MCF_DTIM_DTMR_ORRI | MCF_DTIM_DTMR_CLK_DIV16 | + MCF_DTIM_DTMR_FRR | MCF_DTIM_DTMR_RST_EN, \ + MCF_DTIM0_DTMR); + + request_irq(mcf_timervector, handler, IRQF_DISABLED, \ + "timer", (void *)MCF_DTIM0_DTMR); + + settimericr(1, mcf_timerlevel); +} + +int timerirqpending(int timer) +{ + unsigned int imr = 0; + + switch (timer) { + case 1: imr = 0x1; break; + case 2: imr = 0x2; break; + default: break; + } + + return (getiprh() & imr); +} + +unsigned long coldfire_gettimeoffset(void) +{ + volatile unsigned long trr, tcn, offset; + + tcn = __raw_readw(MCF_DTIM0_DTCN); + trr = __raw_readl(MCF_DTIM0_DTRR); + offset = (tcn * (1000000 / HZ)) / trr; + + /* Check if we just wrapped the counters and maybe missed a tick */ + if ((offset < (1000000 / HZ / 2)) && timerirqpending(1)) + offset += 1000000 / HZ; + return offset; +} + +#elif defined(CONFIG_M547X_8X) + +void coldfire_tick(void) +{ + /* Reset the ColdFire timer */ + MCF_SSR(0) = MCF_SSR_ST; +} + +void __init coldfire_sched_init(irq_handler_t handler) +{ + int irq = ISC_SLTn(0); + + MCF_SCR(0) = 0; + MCF_ICR(irq) = ILP_SLT0; + request_irq(64 + irq, handler, IRQF_DISABLED, "ColdFire Timer 0", NULL); + MCF_SLTCNT(0) = MCF_BUSCLK / HZ; + MCF_SCR(0) |= MCF_SCR_TEN | MCF_SCR_IEN | MCF_SCR_RUN; +} + +unsigned long coldfire_gettimeoffset(void) +{ + volatile unsigned long trr, tcn, offset; + trr = MCF_SLTCNT(0); + tcn = MCF_SCNT(0); + + offset = (trr - tcn) * ((1000000 >> 3) / HZ) / (trr >> 3); + if (MCF_SSR(0) & MCF_SSR_ST) + offset += 1000000 / HZ; + + return offset; +} + +#endif + +void coldfire_reboot(void) +{ +#if defined(CONFIG_M5445X) + /* disable interrupts and do a software reset */ + asm("movew #0x2700, %%sr\n\t" + "moveb #0x80, %%d0\n\t" + "moveb %%d0, 0xfc0a0000\n\t" + : : : "%d0"); +#elif defined(CONFIG_M547X_8X) + /* disable interrupts and enable the watchdog */ + printk(KERN_INFO "Rebooting\n"); + asm("movew #0x2700, %sr\n"); + MCF_GPT_GMS0 = MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4); +#endif +} + +static void coldfire_get_model(char *model) +{ + sprintf(model, "Version 4 ColdFire"); +} + +static void __init +coldfire_bootmem_alloc(unsigned long memory_start, unsigned long memory_end) +{ + unsigned long base_pfn; + + /* compute total pages in system */ + num_pages = PAGE_ALIGN(memory_end - PAGE_OFFSET) >> PAGE_SHIFT; + + /* align start/end to page boundries */ + memory_start = PAGE_ALIGN(memory_start); + memory_end = memory_end & PAGE_MASK; + + /* page numbers */ + base_pfn = __pa(PAGE_OFFSET) >> PAGE_SHIFT; + min_low_pfn = __pa(memory_start) >> PAGE_SHIFT; + max_low_pfn = __pa(memory_end) >> PAGE_SHIFT; + + high_memory = (void *)memory_end; + availmem = memory_start; + + /* setup bootmem data */ + m68k_setup_node(0); + availmem += init_bootmem_node(NODE_DATA(0), min_low_pfn, + base_pfn, max_low_pfn); + availmem = PAGE_ALIGN(availmem); + free_bootmem(__pa(availmem), memory_end - (availmem)); +} + +void __init config_coldfire(void) +{ + unsigned long endmem, startmem; + int i; + + /* + * Calculate endmem from m68k_memory, assume all are contiguous + */ + startmem = ((((int) &_end) + (PAGE_SIZE - 1)) & PAGE_MASK); + endmem = PAGE_OFFSET; + for (i = 0; i < m68k_num_memory; ++i) + endmem += m68k_memory[i].size; + + printk(KERN_INFO "starting up linux startmem 0x%lx, endmem 0x%lx, \ + size %luMB\n", startmem, endmem, (endmem - startmem) >> 20); + + memset(irq_enable, 0, sizeof(irq_enable)); + + /* + * Setup coldfire mach-specific handlers + */ + mach_max_dma_address = 0xffffffff; + mach_sched_init = coldfire_sched_init; + mach_tick = coldfire_tick; + mach_gettimeoffset = coldfire_gettimeoffset; + mach_reset = coldfire_reboot; +/* mach_hwclk = coldfire_hwclk; to be done */ + mach_get_model = coldfire_get_model; + + coldfire_bootmem_alloc(startmem, endmem-1); + + /* + * initrd setup + */ +/* #ifdef CONFIG_BLK_DEV_INITRD + if (m68k_ramdisk.size) { + reserve_bootmem (__pa(m68k_ramdisk.addr), m68k_ramdisk.size); + initrd_start = (unsigned long) m68k_ramdisk.addr; + initrd_end = initrd_start + m68k_ramdisk.size; + printk (KERN_DEBUG "initrd: %08lx - %08lx\n", initrd_start, + initrd_end); + } +#endif */ + +#if defined(CONFIG_DUMMY_CONSOLE) || defined(CONFIG_FRAMEBUFFER_CONSOLE) + conswitchp = &dummy_con; +#endif + +#if defined(CONFIG_SERIAL_COLDFIRE) + /* + * This causes trouble when it is re-registered later. + * Currently this is fixed by conditionally commenting + * out the register_console in mcf_serial.c + */ + register_console(&mcfrs_console); +#endif +} --- /dev/null +++ b/arch/m68k/coldfire/entry.S @@ -0,0 +1,711 @@ +/* + * arch/m68k/coldfire/entry.S + * + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * Copyright (C) 2004-2006 Macq Electronique SA. (www.macqel.com) + * Matt Waddel Matt.Waddel@freescale.com + * Kurt Mahan kmahan@freescale.com + * Copyright Freescale Semiconductor, Inc. 2007 + * + * Modify irq status in buserr -- (c) Copyright 2008, SYSTEM electronic Gmbh + * + * Based on: + * + * arch/m68knommu/platform/5307/entry.S & + * arch/m68k/kernel/entry.S + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * Linux/m68k support by Hamish Macdonald + * + * ColdFire support by Greg Ungerer (gerg@snapgear.com) + * 5307 fixes by David W. Miller + * linux 2.4 support David McCullough + * Bug, speed and maintainability fixes by Philippe De Muyter + * Ported to mmu Coldfire by Matt Waddel + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * TASK_INFO: + * + * - TINFO_PREEMPT (struct thread_info / preempt_count) + * Used to keep track of preemptability + * - TINFO_FLAGS (struct thread_info / flags - include/asm-m68k/thread_info.h) + * Various bit flags that are checked for scheduling/tracing + * Bits 0-7 are checked every exception exit + * 8-15 are checked every syscall exit + * + * TIF_SIGPENDING 6 + * TIF_NEED_RESCHED 7 + * TIF_DELAYED_TRACE 14 + * TIF_SYSCALL_TRACE 15 + * TIF_MEMDIE 16 (never checked here) + */ + +.bss + +sw_ksp: +.long 0 + +sw_usp: +.long 0 + +.text + +.globl system_call +.globl buserr +.globl trap +.globl resume +.globl ret_from_exception +.globl ret_from_signal +.globl sys_call_table +.globl ret_from_interrupt +.globl inthandler + +ENTRY(buserr) +#ifdef CONFIG_COLDFIRE_FOO + movew #0x2700,%sr /* lock interrupts */ +#endif + SAVE_ALL_INT +#ifdef CONFIG_COLDFIRE_FOO + movew PT_SR(%sp),%d3 /* get original %sr */ + oril #0x2000,%d3 /* set supervisor mode in it */ + movew %d3,%sr /* recover irq state */ +#endif + GET_CURRENT(%d0) + movel %sp,%sp@- /* stack frame pointer argument */ + jsr buserr_c + addql #4,%sp + jra .Lret_from_exception + +ENTRY(trap) + SAVE_ALL_INT + GET_CURRENT(%d0) + movel %sp,%sp@- /* stack frame pointer argument */ + jsr trap_c + addql #4,%sp + jra .Lret_from_exception + + /* After a fork we jump here directly from resume, + %d1 contains the previous task schedule_tail */ +ENTRY(ret_from_fork) + movel %d1,%sp@- + jsr schedule_tail + addql #4,%sp + jra .Lret_from_exception + +do_trace_entry: + movel #-ENOSYS,%d1 /* needed for strace */ + movel %d1,%sp@(PT_D0) + subql #4,%sp + SAVE_SWITCH_STACK + jbsr syscall_trace + RESTORE_SWITCH_STACK + addql #4,%sp + movel %sp@(PT_ORIG_D0),%d0 + cmpl #NR_syscalls,%d0 + jcs syscall +badsys: + movel #-ENOSYS,%d1 + movel %d1,%sp@(PT_D0) + jra ret_from_exception + +do_trace_exit: + subql #4,%sp + SAVE_SWITCH_STACK + jbsr syscall_trace + RESTORE_SWITCH_STACK + addql #4,%sp + jra .Lret_from_exception + +ENTRY(ret_from_signal) + RESTORE_SWITCH_STACK + addql #4,%sp + jra .Lret_from_exception + +ENTRY(system_call) + SAVE_ALL_SYS + + GET_CURRENT(%d1) + /* save top of frame */ + movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) + + /* syscall trace */ + tstb %curptr@(TASK_INFO+TINFO_FLAGS+2) + jmi do_trace_entry /* SYSCALL_TRACE is set */ + cmpl #NR_syscalls,%d0 + jcc badsys +syscall: + movel #sys_call_table,%a0 + asll #2,%d0 + addl %d0,%a0 + movel %a0@,%a0 + jsr %a0@ + movel %d0,%sp@(PT_D0) /* save the return value */ +ret_from_syscall: + movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0 + jne syscall_exit_work /* flags set so process */ +1: RESTORE_ALL + +syscall_exit_work: + btst #5,%sp@(PT_SR) /* check if returning to kernel */ + bnes 1b /* if so, skip resched, signals */ + + btstl #15,%d0 /* check if SYSCALL_TRACE */ + jne do_trace_exit + btstl #14,%d0 /* check if DELAYED_TRACE */ + jne do_delayed_trace + btstl #6,%d0 /* check if SIGPENDING */ + jne do_signal_return + pea resume_userspace + jra schedule + +ENTRY(ret_from_exception) +.Lret_from_exception: + btst #5,%sp@(PT_SR) /* check if returning to kernel */ + bnes 1f /* if so, skip resched, signals */ + movel %d0,%sp@- /* Only allow interrupts when we are */ + move %sr,%d0 /* last one on the kernel stack, */ + andl #ALLOWINT,%d0 /* otherwise stack overflow can occur */ + move %d0,%sr /* during heavy interrupt load. */ + movel %sp@+,%d0 + +resume_userspace: + moveb %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0 + jne exit_work /* SIGPENDING and/or NEED_RESCHED set */ +1: RESTORE_ALL + +exit_work: + /* save top of frame */ + movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) + btstl #6,%d0 /* check for SIGPENDING in flags */ + jne do_signal_return + pea resume_userspace + jra schedule + +do_signal_return: + subql #4,%sp /* dummy return address */ + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + clrl %sp@- + bsrl do_signal + addql #8,%sp + RESTORE_SWITCH_STACK + addql #4,%sp + jbra resume_userspace + +do_delayed_trace: + bclr #7,%sp@(PT_SR) /* clear trace bit in SR */ + pea 1 /* send SIGTRAP */ + movel %curptr,%sp@- + pea LSIGTRAP + jbsr send_sig + addql #8,%sp + addql #4,%sp + jbra resume_userspace + +/* + * This is the interrupt handler (for all hardware interrupt + * sources). It figures out the vector number and calls the appropriate + * interrupt service routine directly. + */ +ENTRY(inthandler) + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,%curptr@(TASK_INFO+TINFO_PREEMPT) + /* put exception # in d0 */ + movel %sp@(PT_VECTOR),%d0 + swap %d0 /* extract bits 25:18 */ + lsrl #2,%d0 + andl #0x0ff,%d0 + + movel %sp,%sp@- + movel %d0,%sp@- /* put vector # on stack */ +auto_irqhandler_fixup = . + 2 + jbsr process_int /* process the IRQ */ + addql #8,%sp /* pop parameters off stack */ + +ENTRY(ret_from_interrupt) +ret_from_interrupt: + + subql #1,%curptr@(TASK_INFO+TINFO_PREEMPT) + jeq ret_from_last_interrupt +2: RESTORE_ALL + + ALIGN +ret_from_last_interrupt: + moveb %sp@(PT_SR),%d0 + andl #(~ALLOWINT>>8)&0xff,%d0 + jne 2b + + /* check if we need to do software interrupts */ + tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING + jeq .Lret_from_exception + pea ret_from_exception + jra do_softirq + +ENTRY(user_inthandler) + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,%curptr@(TASK_INFO+TINFO_PREEMPT) + /* put exception # in d0 */ + movel %sp@(PT_VECTOR),%d0 +user_irqvec_fixup = . + 2 + swap %d0 /* extract bits 25:18 */ + lsrl #2,%d0 + andl #0x0ff,%d0 + + movel %sp,%sp@- + movel %d0,%sp@- /* put vector # on stack */ +user_irqhandler_fixup = . + 2 + jbsr process_int /* process the IRQ */ + addql #8,%sp /* pop parameters off stack */ + + subql #1,%curptr@(TASK_INFO+TINFO_PREEMPT) + jeq ret_from_last_interrupt + RESTORE_ALL + +/* Handler for uninitialized and spurious interrupts */ + +ENTRY(bad_inthandler) + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,%curptr@(TASK_INFO+TINFO_PREEMPT) + + movel %sp,%sp@- + jsr handle_badint + addql #4,%sp + + subql #1,%curptr@(TASK_INFO+TINFO_PREEMPT) + jeq ret_from_last_interrupt + RESTORE_ALL + +ENTRY(sys_fork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_fork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_clone) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_clone + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_vfork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_vfork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr do_sigsuspend + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_rt_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr do_rt_sigsuspend + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigreturn) + SAVE_SWITCH_STACK + jbsr do_sigreturn + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_rt_sigreturn) + SAVE_SWITCH_STACK + jbsr do_rt_sigreturn + RESTORE_SWITCH_STACK + rts + +resume: + /* + * Beware - when entering resume, prev (the current task) is + * in a0, next (the new task) is in a1,so don't change these + * registers until their contents are no longer needed. + */ + + /* save sr */ + movew %sr,%d0 + movew %d0,%a0@(TASK_THREAD+THREAD_SR) + + /* save usp */ + /* Save USP via %a1 (which is saved/restored from %d0) */ + movel %a1,%d0 + movel %usp,%a1 + movel %a1,%a0@(TASK_THREAD+THREAD_USP) + movel %d0,%a1 + + /* save non-scratch registers on stack */ + SAVE_SWITCH_STACK + + /* save current kernel stack pointer */ + movel %sp,%a0@(TASK_THREAD+THREAD_KSP) + + /* Return previous task in %d1 */ + movel %curptr,%d1 + + /* switch to new task (a1 contains new task) */ + movel %a1,%curptr + + /* restore the kernel stack pointer */ + movel %a1@(TASK_THREAD+THREAD_KSP),%sp + + /* restore non-scratch registers */ + RESTORE_SWITCH_STACK + + /* restore user stack pointer */ + movel %a1@(TASK_THREAD+THREAD_USP),%a0 + movel %a0,%usp + + /* restore status register */ + movew %a1@(TASK_THREAD+THREAD_SR),%d0 + movew %d0,%sr + + rts + +.data +ALIGN +sys_call_table: + .long sys_ni_syscall /* 0 - old "setup()" system call*/ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .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_chown16 + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid16 + .long sys_getuid16 + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid16 + .long sys_getgid16 + .long sys_signal + .long sys_geteuid16 + .long sys_getegid16 /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid16 /* 70 */ + .long sys_setregid16 + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_old_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups16 /* 80 */ + .long sys_setgroups16 + .long old_select + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_swapon + .long sys_reboot + .long old_readdir + .long old_mmap /* 90 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown16 /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ni_syscall /* ioperm for i386 */ + .long sys_socketcall + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_ni_syscall + .long sys_ni_syscall /* 110 */ /* iopl for i386 */ + .long sys_vhangup + .long sys_ni_syscall /* obsolete idle() syscall */ + .long sys_ni_syscall /* vm86old for i386 */ + .long sys_wait4 + .long sys_swapoff /* 115 */ + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn + .long sys_clone /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_cacheflush /* modify_ldt for i386 */ + .long sys_adjtimex + .long sys_mprotect /* 125 */ + .long sys_sigprocmask + .long sys_ni_syscall /* old "create_module" */ + .long sys_init_module + .long sys_delete_module + .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* for afs_syscall */ + .long sys_setfsuid16 + .long sys_setfsgid16 + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_msync + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_mremap + .long sys_setresuid16 + .long sys_getresuid16 /* 165 */ + .long sys_getpagesize + .long sys_ni_syscall /* old sys_query_module */ + .long sys_poll + .long sys_nfsservctl + .long sys_setresgid16 /* 170 */ + .long sys_getresgid16 + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_lchown16; + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_chown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_lchown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_ni_syscall + .long sys_ni_syscall + .long sys_getdents64 /* 220 */ + .long sys_gettid + .long sys_tkill + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr /* 225 */ + .long sys_getxattr + .long sys_lgetxattr + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr /* 230 */ + .long sys_flistxattr + .long sys_removexattr + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_futex /* 235 */ + .long sys_sendfile64 + .long sys_mincore + .long sys_madvise + .long sys_fcntl64 + .long sys_readahead /* 240 */ + .long sys_io_setup + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel /* 245 */ + .long sys_fadvise64 + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 250 */ + .long sys_epoll_wait + .long sys_remap_file_pages + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 255 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 260 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + .long sys_tgkill /* 265 */ + .long sys_utimes + .long sys_fadvise64_64 + .long sys_mbind + .long sys_get_mempolicy + .long sys_set_mempolicy /* 270 */ + .long sys_mq_open + .long sys_mq_unlink + .long sys_mq_timedsend + .long sys_mq_timedreceive + .long sys_mq_notify /* 275 */ + .long sys_mq_getsetattr + .long sys_waitid + .long sys_ni_syscall /* for sys_vserver */ + .long sys_add_key + .long sys_request_key /* 280 */ + .long sys_keyctl + .long sys_ioprio_set + .long sys_ioprio_get + .long sys_inotify_init + .long sys_inotify_add_watch /* 285 */ + .long sys_inotify_rm_watch + .long sys_migrate_pages + .long sys_openat + .long sys_mkdirat + .long sys_mknodat /* 290 */ + .long sys_fchownat + .long sys_futimesat + .long sys_fstatat64 + .long sys_unlinkat + .long sys_renameat /* 295 */ + .long sys_linkat + .long sys_symlinkat + .long sys_readlinkat + .long sys_fchmodat + .long sys_faccessat /* 300 */ + .long sys_ni_syscall /* Reserved for pselect6 */ + .long sys_ni_syscall /* Reserved for ppoll */ + .long sys_unshare + .long sys_set_robust_list + .long sys_get_robust_list /* 305 */ + .long sys_splice + .long sys_sync_file_range + .long sys_tee + .long sys_vmsplice + .long sys_move_pages /* 310 */ + --- /dev/null +++ b/arch/m68k/coldfire/head.S @@ -0,0 +1,661 @@ +/* + * head.S is the MMU enabled ColdFire specific initial boot code + * + * Ported to ColdFire by + * Matt Waddel Matt.Waddel@freescale.com + * Kurt Mahan kmahan@freescale.com + * Copyright Freescale Semiconductor, Inc. 2007, 2008 + * Phys kernel mapping Copyright Daniel Krueger, SYSTEC electornic GmbH 2008 + * + * 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. + * + * Parts of this code came from arch/m68k/kernel/head.S + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG + +.globl kernel_pg_dir +.globl availmem +.globl set_context +.globl set_fpga + +#ifdef DEBUG +/* When debugging use readable names for labels */ +#ifdef __STDC__ +#define L(name) .head.S.##name +#else +#define L(name) .head.S./**/name +#endif +#else +#ifdef __STDC__ +#define L(name) .L##name +#else +#define L(name) .L/**/name +#endif +#endif + +/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */ +#ifndef __INITDATA +#define __INITDATA .data +#define __FINIT .previous +#endif + +#if CONFIG_SDRAM_BASE != PAGE_OFFSET +/* + * Kernel mapped to virtual ram address. + * + * M5445x: + * Data[0]: 0xF0000000 -> 0xFFFFFFFF System regs + * Data[1]: 0xA0000000 -> 0xAFFFFFFF PCI + * Code[0]: Not Mapped + * Code[1]: Not Mapped + * + * M547x/M548x + * Data[0]: 0xF0000000 -> 0xFFFFFFFF System regs + * Data[1]: Not Mapped + * Code[0]: Not Mapped + * Code[1]: Not Mapped + */ +#if defined(CONFIG_M5445X) +#define ACR0_DEFAULT #0xF00FA048 /* System regs */ +#define ACR1_DEFAULT #0xA00FA048 /* PCI */ +#define ACR2_DEFAULT #0x00000000 /* Not Mapped */ +#define ACR3_DEFAULT #0x00000000 /* Not Mapped */ +#elif defined(CONFIG_M547X_8X) +#define ACR0_DEFAULT #0xF00FA048 /* System Regs */ +#define ACR1_DEFAULT #0x00000000 /* Not Mapped */ +#define ACR2_DEFAULT #0x00000000 /* Not Mapped */ +#define ACR3_DEFAULT #0x00000000 /* Not Mapped */ +#endif + +#else /* CONFIG_SDRAM_BASE = PAGE_OFFSET */ +/* + * Kernel mapped to physical ram address. + * + * M5445x: + * Data[0]: 0xF0000000 -> 0xFFFFFFFF System regs + * Data[1]: 0x40000000 -> 0x4FFFFFFF SDRAM - uncached + * Code[0]: Not Mapped + * Code[1]: 0x40000000 -> 0x4FFFFFFF SDRAM - cached + * + * M547x/M548x + * Data[0]: 0xF0000000 -> 0xFFFFFFFF System regs + * Data[1]: 0x00000000 -> 0x0FFFFFFF SDRAM - uncached + * Code[0]: Not Mapped + * Code[1]: 0x00000000 -> 0x0FFFFFFF SDRAM - cached + */ +#if defined(CONFIG_M5445X) +#define ACR0_DEFAULT #0xF00FA048 /* System Regs */ +#define ACR1_DEFAULT #0x400FA048 /* SDRAM uncached */ +#define ACR2_DEFAULT #0x00000000 /* Not mapped */ +#define ACR3_DEFAULT #0x400FA008 /* SDRAM cached */ +#elif defined(CONFIG_M547X_8X) +#define ACR0_DEFAULT #0xF00FA048 /* System Regs */ +#define ACR1_DEFAULT #0x000FA048 /* SDRAM uncached */ +#define ACR2_DEFAULT #0x00000000 /* Not mapped */ +#define ACR3_DEFAULT #0x000FA008 /* SDRAM cached */ +#endif +#endif + +/* Several macros to make the writing of subroutines easier: + * - func_start marks the beginning of the routine which setups the frame + * register and saves the registers, it also defines another macro + * to automatically restore the registers again. + * - func_return marks the end of the routine and simply calls the prepared + * macro to restore registers and jump back to the caller. + * - func_define generates another macro to automatically put arguments + * onto the stack call the subroutine and cleanup the stack again. + */ + +.macro load_symbol_address symbol,register + movel #\symbol,\register +.endm + +.macro func_start name,saveregs,savesize,stack=0 +L(\name): + linkw %a6,#-\stack + subal #(\savesize),%sp + moveml \saveregs,%sp@ +.set stackstart,-\stack + +.macro func_return_\name + moveml %sp@,\saveregs + addal #(\savesize),%sp + unlk %a6 + rts +.endm +.endm + +.macro func_return name + func_return_\name +.endm + +.macro func_call name + jbsr L(\name) +.endm + +.macro move_stack nr,arg1,arg2,arg3,arg4 +.if \nr + move_stack "(\nr-1)",\arg2,\arg3,\arg4 + movel \arg1,%sp@- +.endif +.endm + +.macro func_define name,nr=0 +.macro \name arg1,arg2,arg3,arg4 + move_stack \nr,\arg1,\arg2,\arg3,\arg4 + func_call \name +.if \nr + lea %sp@(\nr*4),%sp +.endif +.endm +.endm + +func_define serial_putc,1 + +.macro putc ch + pea \ch + func_call serial_putc + addql #4,%sp +.endm + +.macro dputc ch +#ifdef DEBUG + putc \ch +#endif +.endm + +func_define putn,1 + +.macro dputn nr +#ifdef DEBUG + putn \nr +#endif +.endm + +#if CONFIG_SDRAM_BASE != PAGE_OFFSET +/* + mmu_map - creates a new TLB entry + + virt_addr Must be on proper boundary + phys_addr Must be on proper boundary + itlb MMUOR_ITLB if instruction TLB or 0 + asid address space ID + shared_global MMUTR_SG if shared between different ASIDs or 0 + size_code MMUDR_SZ1M 1 MB + MMUDR_SZ4K 4 KB + MMUDR_SZ8K 8 KB + MMUDR_SZ16M 16 MB + cache_mode MMUDR_INC instruction non-cacheable + MMUDR_IC instruction cacheable + MMUDR_DWT data writethrough + MMUDR_DCB data copyback + MMUDR_DNCP data non-cacheable, precise + MMUDR_DNCIP data non-cacheable, imprecise + super_prot MMUDR_SP if user mode generates exception or 0 + readable MMUDR_R if permits read access (data TLB) or 0 + writable MMUDR_W if permits write access (data TLB) or 0 + executable MMUDR_X if permits execute access (instruction TLB) or 0 + locked MMUDR_LK prevents TLB entry from being replaced or 0 + temp_data_reg a data register to use for temporary values +*/ +.macro mmu_map virt_addr,phys_addr,itlb,asid,shared_global,size_code,cache_mode,super_prot,readable,writable,executable,locked,temp_data_reg + /* Set up search of TLB. */ + movel #(\virt_addr+1), \temp_data_reg + movel \temp_data_reg, MMUAR + /* Search. */ + movel #(MMUOR_STLB + MMUOR_ADR +\itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) + /* Set up tag value. */ + movel #(\virt_addr + \asid + \shared_global + MMUTR_V), \temp_data_reg + movel \temp_data_reg, MMUTR + /* Set up data value. */ + movel #(\phys_addr + \size_code + \cache_mode + \super_prot + \readable + \writable + \executable + \locked), \temp_data_reg + movel \temp_data_reg, MMUDR + /* Save it. */ + movel #(MMUOR_ACC + MMUOR_UAA + \itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) +.endm /* mmu_map */ + +.macro mmu_unmap virt_addr,itlb,temp_data_reg + /* Set up search of TLB. */ + movel #(\virt_addr+1), \temp_data_reg + movel \temp_data_reg, MMUAR + /* Search. */ + movel #(MMUOR_STLB + MMUOR_ADR +\itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) + /* Test for hit. */ + movel MMUSR,\temp_data_reg + btst #MMUSR_HITN,\temp_data_reg + beq 1f + /* Read the TLB. */ + movel #(MMUOR_RW + MMUOR_ACC +\itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) + movel MMUSR,\temp_data_reg + /* Set up tag value. */ + movel #0, \temp_data_reg + movel \temp_data_reg, MMUTR + /* Set up data value. */ + movel #0, \temp_data_reg + movel \temp_data_reg, MMUDR + /* Save it. */ + movel #(MMUOR_ACC + MMUOR_UAA + \itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) +1: +.endm /* mmu_unmap */ +#endif /* CONFIG_SDRAM_BASE != PAGE_OFFSET */ + +/* .text */ +.section ".text.head","ax" +ENTRY(_stext) +/* Version numbers of the bootinfo interface -- if we later pass info + * from boot ROM we might want to put something real here. + * + * The area from _stext to _start will later be used as kernel pointer table + */ + bras 1f /* Jump over bootinfo version numbers */ + + .long BOOTINFOV_MAGIC + .long 0 +#if CONFIG_SDRAM_BASE != PAGE_OFFSET +1: jmp __start-(0xc0000000-CONFIG_SDRAM_BASE) +#else +1: jmp __start +#endif + +.equ kernel_pg_dir,_stext +.equ .,_stext+0x1000 + +ENTRY(_start) + jra __start +__INIT +ENTRY(__start) +/* Save the location of u-boot info - cmd line, bd_info, etc. */ + movel %a7,%a4 /* Don't use %a4 before cf_early_init */ + addl #0x00000004,%a4 /* offset past top */ + addl #(PAGE_OFFSET-CONFIG_SDRAM_BASE),%a4 /* high mem offset */ + +/* Setup initial stack pointer */ + movel #CONFIG_SDRAM_BASE+0x1000,%sp + +/* Setup usp */ + subl %a0,%a0 + movel %a0,%usp + +#if defined(CONFIG_M5445X) + movel #0x80000000, %d0 + movec %d0, %rambar1 +#elif defined(CONFIG_M547X_8X) + movel #MCF_MBAR, %d0 + movec %d0, %mbar + move.l #(MCF_RAMBAR0 + 0x21), %d0 + movec %d0, %rambar0 + move.l #(MCF_RAMBAR1 + 0x21), %d0 + movec %d0, %rambar1 +#endif + + movew #0x2700,%sr + +/* reset cache */ + movel #(CF_CACR_ICINVA + CF_CACR_DCINVA),%d0 + movecl %d0,%cacr + + movel #(MMU_BASE+1),%d0 + movecl %d0,%mmubar + movel #MMUOR_CA,%a0 /* Clear tlb entries */ + movew %a0,(MMUOR) + movel #(MMUOR_CA + MMUOR_ITLB),%a0 /* Use ITLB for searches */ + movew %a0,(MMUOR) + movel #0,%a0 /* Clear Addr Space User ID */ + movecl %a0,%asid + +/* setup ACRs */ + movel ACR0_DEFAULT, %d0 /* ACR0 (DATA) setup */ + movec %d0, %acr0 + nop + movel ACR1_DEFAULT, %d0 /* ACR1 (DATA) setup */ + movec %d0, %acr1 + nop + movel ACR2_DEFAULT, %d0 /* ACR2 (CODE) setup */ + movec %d0, %acr2 + nop + movel ACR3_DEFAULT, %d0 /* ACR3 (CODE) setup */ + movec %d0, %acr3 + nop + + /* If you change the memory size to another value make a matching + change in paging_init(cf-mmu.c) to zones_size[]. */ + +#if CONFIG_SDRAM_BASE != PAGE_OFFSET +#if defined(CONFIG_M5445X) + /* Map 256MB as code */ + mmu_map (PAGE_OFFSET+0*0x1000000), (PHYS_OFFSET+0*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+1*0x1000000), (PHYS_OFFSET+1*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+2*0x1000000), (PHYS_OFFSET+2*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+3*0x1000000), (PHYS_OFFSET+3*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+4*0x1000000), (PHYS_OFFSET+4*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+5*0x1000000), (PHYS_OFFSET+5*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+6*0x1000000), (PHYS_OFFSET+6*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+7*0x1000000), (PHYS_OFFSET+7*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+8*0x1000000), (PHYS_OFFSET+8*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+9*0x1000000), (PHYS_OFFSET+9*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+10*0x1000000), (PHYS_OFFSET+10*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+11*0x1000000), (PHYS_OFFSET+11*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+12*0x1000000), (PHYS_OFFSET+12*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+13*0x1000000), (PHYS_OFFSET+13*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+14*0x1000000), (PHYS_OFFSET+14*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+15*0x1000000), (PHYS_OFFSET+15*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_IC, MMUDR_SP, \ + 0, 0, MMUDR_X, MMUDR_LK, %d0 + + /* Map 256MB as data also */ + mmu_map (PAGE_OFFSET+0*0x1000000), (PHYS_OFFSET+0*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+1*0x1000000), (PHYS_OFFSET+1*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+2*0x1000000), (PHYS_OFFSET+2*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+3*0x1000000), (PHYS_OFFSET+3*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+4*0x1000000), (PHYS_OFFSET+4*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+5*0x1000000), (PHYS_OFFSET+5*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+6*0x1000000), (PHYS_OFFSET+6*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+7*0x1000000), (PHYS_OFFSET+7*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+8*0x1000000), (PHYS_OFFSET+8*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+9*0x1000000), (PHYS_OFFSET+9*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+10*0x1000000), (PHYS_OFFSET+10*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+11*0x1000000), (PHYS_OFFSET+11*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+12*0x1000000), (PHYS_OFFSET+12*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+13*0x1000000), (PHYS_OFFSET+13*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+14*0x1000000), (PHYS_OFFSET+14*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+15*0x1000000), (PHYS_OFFSET+15*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + + /* Map ATA registers -- sacrifice a data TLB due to the hw design */ + mmu_map (0x90000000), (0x90000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 + +#elif defined(CONFIG_M547X_8X) + + /* Map first 8 MB as code */ + mmu_map (PAGE_OFFSET+0*1024*1024), (0*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, MMUDR_X, \ + MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+1*1024*1024), (1*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, MMUDR_X, \ + MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+2*1024*1024), (2*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, MMUDR_X, \ + MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+3*1024*1024), (3*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, MMUDR_X, \ + MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+4*1024*1024), (4*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, MMUDR_X, \ + MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+5*1024*1024), (5*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, MMUDR_X, \ + MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+6*1024*1024), (6*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, MMUDR_X, \ + MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+7*1024*1024), (7*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, MMUDR_X, \ + MMUDR_LK, %d0 + + /* Map first 8 MB as data */ + mmu_map (PAGE_OFFSET+0*1024*1024), (0*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+1*1024*1024), (1*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+2*1024*1024), (2*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+3*1024*1024), (3*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+4*1024*1024), (4*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+5*1024*1024), (5*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+6*1024*1024), (6*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (PAGE_OFFSET+7*1024*1024), (7*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 +#endif + /* + * Do unity mapping to enable the MMU. Map first chunk of memory + * in place as code/data. The TLBs will be deleted after the MMU is + * enabled and we are executing in high memory. + */ + +#if defined(CONFIG_M5445X) + /* Map first 16 MB as code */ + mmu_map (PHYS_OFFSET+0*0x1000000), (PHYS_OFFSET+0*0x1000000), \ + MMUOR_ITLB, 0, MMUTR_SG, MMUDR_SZ16M, MMUDR_INC, MMUDR_SP, 0, \ + 0, MMUDR_X, 0, %d0 + /* Map first 16 MB as data too */ + mmu_map (PHYS_OFFSET+0*0x1000000), (PHYS_OFFSET+0*0x1000000), 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, 0, %d0 +#elif defined(CONFIG_M547X_8X) + /* Map first 4 MB as code */ + mmu_map (0*1024*1024), (0*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, \ + MMUDR_X, 0, %d0 + mmu_map (1*1024*1024), (1*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, \ + MMUDR_X, 0, %d0 + mmu_map (2*1024*1024), (2*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, \ + MMUDR_X, 0, %d0 + mmu_map (3*1024*1024), (3*1024*1024), MMUOR_ITLB, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_IC, MMUDR_SP, 0, 0, \ + MMUDR_X, 0, %d0 + + /* Map first 4 MB as data too */ + mmu_map (0*1024*1024), (0*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DCB, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, 0, %d0 + mmu_map (1*1024*1024), (1*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DCB, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, 0, %d0 + mmu_map (2*1024*1024), (2*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DCB, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, 0, %d0 + mmu_map (3*1024*1024), (3*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DCB, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, 0, %d0 +#endif +#endif /* CONFIG_SDRAM_BASE != PAGE_OFFSET */ + + /* Turn on MMU */ + movel #(MMUCR_EN),%a0 + movel %a0,MMUCR + nop /* This synchs the pipeline after a write to MMUCR */ + + movel #__running_high,%a0 /* Get around PC-relative addressing. */ + jmp %a0@ + +ENTRY(__running_high) + load_symbol_address _stext,%sp + movel L(memory_start),%a0 + movel %a0,availmem + load_symbol_address L(phys_kernel_start),%a0 + load_symbol_address _stext,%a1 + subl #_stext,%a1 + addl #PAGE_OFFSET,%a1 + movel %a1,%a0@ + +/* zero bss */ + lea _sbss,%a0 + lea _ebss,%a1 + clrl %d0 +_loop_bss: + movel %d0,(%a0)+ + cmpl %a0,%a1 + bne _loop_bss + + /* Unmap unity mappings */ +#if CONFIG_SDRAM_BASE != PAGE_OFFSET +#if defined(CONFIG_M5445X) + mmu_unmap (PHYS_OFFSET+0*0x1000000), MMUOR_ITLB, %d0 + mmu_unmap (PHYS_OFFSET+0*0x1000000), 0, %d0 +#elif defined(CONFIG_M547X_8X) + mmu_unmap (PHYS_OFFSET+0*0x1000000), MMUOR_ITLB, %d0 + mmu_unmap (PHYS_OFFSET+1*0x1000000), MMUOR_ITLB, %d0 + mmu_unmap (PHYS_OFFSET+2*0x1000000), MMUOR_ITLB, %d0 + mmu_unmap (PHYS_OFFSET+3*0x1000000), MMUOR_ITLB, %d0 + mmu_unmap (PHYS_OFFSET+0*0x1000000), 0, %d0 + mmu_unmap (PHYS_OFFSET+1*0x1000000), 0, %d0 + mmu_unmap (PHYS_OFFSET+2*0x1000000), 0, %d0 + mmu_unmap (PHYS_OFFSET+3*0x1000000), 0, %d0 +#endif +#endif /* CONFIG_SDRAM_BASE != PAGE_OFFSET */ + +/* Setup initial stack pointer */ + lea init_task,%a2 + lea init_thread_union+THREAD_SIZE,%sp + subl %a6,%a6 /* clear a6 for gdb */ + +#ifdef CONFIG_MCF_USER_HALT +/* Setup debug control reg to allow halts from user space */ + lea wdbg_uhe,%a0 + wdebug (%a0) +#endif + + movel %a4,uboot_info_stk /* save uboot info to variable */ + jsr cf_early_init + jmp start_kernel + +.section ".text.head","ax" +set_context: +func_start set_context,%d0,(1*4) + movel 12(%sp),%d0 + movec %d0,%asid +func_return set_context + +#ifdef CONFIG_M5445X +/* + * set_fpga(addr,val) on the M5445X + * + * Map in 0x00000000 -> 0x0fffffff and then do the write. + */ +set_fpga: +#if 0 + movew %sr,%d1 + movew #0x2700,%sr + movel ACR0_FPGA, %d0 + movec %d0, %acr0 + nop + moveal 4(%sp),%a0 + movel 8(%sp),%a0@ + movel ACR0_DEFAULT, %d0 + movec %d0, %acr0 + nop + movew %d1,%sr +#endif + rts +#endif + + .data + .align 4 + +availmem: + .long 0 +L(phys_kernel_start): + .long PAGE_OFFSET +L(kernel_end): + .long 0 +L(memory_start): + .long PAGE_OFFSET_RAW + +#ifdef CONFIG_MCF_USER_HALT +/* + * Enable User Halt Enable in the debug control register. + */ +wdbg_uhe: + .word 0x2c80 /* DR0 */ + .word 0x00b0 /* 31:16 */ + .word 0x0400 /* 15:0 -- enable UHE */ + .word 0x0000 /* unused */ +#endif + + --- /dev/null +++ b/arch/m68k/coldfire/ints.c @@ -0,0 +1,463 @@ +/* + * linux/arch/m68k/coldfire/ints.c -- General interrupt handling code + * + * Copyright (C) 1999-2002 Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * + * Copyright Freescale Semiconductor, Inc. 2007, 2008 + * Kurt Mahan kmahan@freescale.com + * Matt Waddel Matt.Waddel@freescale.com + * + * Based on: + * linux/arch/m68k/kernel/ints.c & + * linux/arch/m68knommu/5307/ints.c + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* + * IRQ Handler lists. + */ +static struct irq_node *irq_list[SYS_IRQS]; +static struct irq_controller *irq_controller[SYS_IRQS]; +static int irq_depth[SYS_IRQS]; + +/* + * IRQ Controller + */ +#if defined(CONFIG_M5445X) +void m5445x_irq_enable(unsigned int irq); +void m5445x_irq_disable(unsigned int irq); +static struct irq_controller m5445x_irq_controller = { + .name = "M5445X", + .lock = SPIN_LOCK_UNLOCKED, + .enable = m5445x_irq_enable, + .disable = m5445x_irq_disable, +}; +#elif defined(CONFIG_M547X_8X) +void m547x_8x_irq_enable(unsigned int irq); +void m547x_8x_irq_disable(unsigned int irq); +static struct irq_controller m547x_8x_irq_controller = { + .name = "M547X_8X", + .lock = SPIN_LOCK_UNLOCKED, + .enable = m547x_8x_irq_enable, + .disable = m547x_8x_irq_disable, +}; +#else +# error No IRQ controller defined +#endif + +#define POOL_SIZE SYS_IRQS +static struct irq_node pool[POOL_SIZE]; +static struct irq_node *get_irq_node(void); + +/* The number of spurious interrupts */ +unsigned int num_spurious; +asmlinkage void handle_badint(struct pt_regs *regs); + +/* + * void init_IRQ(void) + * + * This function should be called during kernel startup to initialize + * the IRQ handling routines. + */ +void __init init_IRQ(void) +{ + int i; + +#if defined(CONFIG_M5445X) + for (i = 0; i < SYS_IRQS; i++) + irq_controller[i] = &m5445x_irq_controller; +#elif defined(CONFIG_M547X_8X) + for (i = 0; i < SYS_IRQS; i++) + irq_controller[i] = &m547x_8x_irq_controller; +#endif +} + +/* + * process_int(unsigned long vec, struct pt_regs *fp) + * + * Process an interrupt. Called from entry.S. + */ +asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) +{ + struct pt_regs *old_regs; + struct irq_node *node; + old_regs = set_irq_regs(fp); + kstat_cpu(0).irqs[vec]++; + + node = irq_list[vec]; + if (!node) + handle_badint(fp); + else { + do { + node->handler(vec, node->dev_id); + node = node->next; + } while (node); + } + + set_irq_regs(old_regs); +} + +/* + * show_interrupts( struct seq_file *p, void *v) + * + * Called to show all the current interrupt information. + */ +int show_interrupts(struct seq_file *p, void *v) +{ + struct irq_controller *contr; + struct irq_node *node; + int i = *(loff_t *) v; + + if ((i < NR_IRQS) && (irq_list[i])) { + contr = irq_controller[i]; + node = irq_list[i]; + seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, + kstat_cpu(0).irqs[i], node->devname); + while ((node = node->next)) + seq_printf(p, ", %s", node->devname); + + seq_printf(p, "\n"); + } + + return 0; +} + +/* + * get_irq_node(void) + * + * Get an irq node from the pool. + */ +struct irq_node *get_irq_node(void) +{ + struct irq_node *p = pool; + int i; + + for (i = 0; i < POOL_SIZE; i++, p++) { + if (!p->handler) { + memset(p, 0, sizeof(struct irq_node)); + return p; + } + } + printk(KERN_INFO "%s(%s:%d): No more irq nodes, I suggest you \ + increase POOL_SIZE", __FUNCTION__, __FILE__, __LINE__); + return NULL; +} + +void init_irq_proc(void) +{ + /* Insert /proc/irq driver here */ +} + +int setup_irq(unsigned int irq, struct irq_node *node) +{ + struct irq_controller *contr; + struct irq_node **prev; + unsigned long flags; + + if (irq >= NR_IRQS || !irq_controller[irq]) { + printk("%s: Incorrect IRQ %d from %s\n", + __FUNCTION__, irq, node->devname); + return -ENXIO; + } + + contr = irq_controller[irq]; + spin_lock_irqsave(&contr->lock, flags); + + prev = irq_list + irq; + if (*prev) { + /* Can't share interrupts unless both agree to */ + if (!((*prev)->flags & node->flags & IRQF_SHARED)) { + spin_unlock_irqrestore(&contr->lock, flags); + printk(KERN_INFO "%s: -BUSY-Incorrect IRQ %d \n", + __FUNCTION__, irq); + return -EBUSY; + } + while (*prev) + prev = &(*prev)->next; + } + + if (!irq_list[irq]) { + if (contr->startup) + contr->startup(irq); + else + contr->enable(irq); + } + node->next = NULL; + *prev = node; + + spin_unlock_irqrestore(&contr->lock, flags); + + return 0; +} + +int request_irq(unsigned int irq, + irq_handler_t handler, + unsigned long flags, const char *devname, void *dev_id) +{ + struct irq_node *node = get_irq_node(); + int res; + + if (!node) { + printk(KERN_INFO "%s:get_irq_node error %x\n", + __FUNCTION__,(unsigned int) node); + return -ENOMEM; + } + node->handler = handler; + node->flags = flags; + node->dev_id = dev_id; + node->devname = devname; + + res = setup_irq(irq, node); + if (res) + node->handler = NULL; + + return res; +} +EXPORT_SYMBOL(request_irq); + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irq_controller *contr; + struct irq_node **p, *node; + unsigned long flags; + + if (irq >= NR_IRQS || !irq_controller[irq]) { + printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + + contr = irq_controller[irq]; + spin_lock_irqsave(&contr->lock, flags); + + p = irq_list + irq; + while ((node = *p)) { + if (node->dev_id == dev_id) + break; + p = &node->next; + } + + if (node) { + *p = node->next; + node->handler = NULL; + } else + printk(KERN_DEBUG "%s: Removing probably wrong IRQ %d\n", + __FUNCTION__, irq); + + if (!irq_list[irq]) { + if (contr->shutdown) + contr->shutdown(irq); + else + contr->disable(irq); + } + + spin_unlock_irqrestore(&contr->lock, flags); +} +EXPORT_SYMBOL(free_irq); + +void enable_irq(unsigned int irq) +{ + struct irq_controller *contr; + unsigned long flags; + + if (irq >= NR_IRQS || !irq_controller[irq]) { + printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + + contr = irq_controller[irq]; + spin_lock_irqsave(&contr->lock, flags); + if (irq_depth[irq]) { + if (!--irq_depth[irq]) { + if (contr->enable) + contr->enable(irq); + } + } else + WARN_ON(1); + spin_unlock_irqrestore(&contr->lock, flags); +} +EXPORT_SYMBOL(enable_irq); + +void disable_irq(unsigned int irq) +{ + struct irq_controller *contr; + unsigned long flags; + + if (irq >= NR_IRQS || !irq_controller[irq]) { + printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + + contr = irq_controller[irq]; + spin_lock_irqsave(&contr->lock, flags); + if (!irq_depth[irq]++) { + if (contr->disable) + contr->disable(irq); + } + spin_unlock_irqrestore(&contr->lock, flags); +} +EXPORT_SYMBOL(disable_irq); + +void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq"))); +EXPORT_SYMBOL(disable_irq_nosync); + + +unsigned long probe_irq_on(void) +{ + return 0; +} +EXPORT_SYMBOL(probe_irq_on); + +int probe_irq_off(unsigned long irqs) +{ + return 0; +} +EXPORT_SYMBOL(probe_irq_off); + +asmlinkage void handle_badint(struct pt_regs *regs) +{ + kstat_cpu(0).irqs[0]++; + num_spurious++; + printk(KERN_DEBUG "unexpected interrupt from %u\n", regs->vector); +} +EXPORT_SYMBOL(handle_badint); + +#ifdef CONFIG_M5445X +/* + * M5445X Implementation + */ +void m5445x_irq_enable(unsigned int irq) +{ + /* enable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* enable eport */ + MCF_EPORT_EPPAR &= ~(3 << (irq*2)); /* level */ + MCF_EPORT_EPDDR &= ~(1 << irq); /* input */ + MCF_EPORT_EPIER |= 1 << irq; /* irq enabled */ + } + + if (irq < 64) { + /* controller 0 */ + MCF_INTC0_ICR(irq) = 0x02; + MCF_INTC0_CIMR = irq; + } else { + /* controller 1 */ + irq -= 64; + MCF_INTC1_ICR(irq) = 0x02; + MCF_INTC1_CIMR = irq; + } +} + +void m5445x_irq_disable(unsigned int irq) +{ + /* disable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* disable eport */ + MCF_EPORT_EPIER &= ~(1 << irq); + } + + if (irq < 64) { + /* controller 0 */ + MCF_INTC0_ICR(irq) = 0x00; + MCF_INTC0_SIMR = irq; + } else { + /* controller 1 */ + irq -= 64; + MCF_INTC1_ICR(irq) = 0x00; + MCF_INTC1_SIMR = irq; + } +} +#elif defined(CONFIG_M547X_8X) +/* + * M547X_8X Implementation + */ +void m547x_8x_irq_enable(unsigned int irq) +{ + /* enable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + +/* JKM -- re-add EPORT later */ +#if 0 + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* enable eport */ + MCF_EPORT_EPPAR &= ~(3 << (irq*2)); /* level */ + MCF_EPORT_EPDDR &= ~(1 << irq); /* input */ + MCF_EPORT_EPIER |= 1 << irq; /* irq enabled */ + } +#endif + + if (irq < 32) { + /* *grumble* don't set low bit of IMRL */ + MCF_IMRL &= (~(1 << irq) & 0xfffffffe); + } + else { + MCF_IMRH &= ~(1 << (irq - 32)); + } +} + +void m547x_8x_irq_disable(unsigned int irq) +{ + /* disable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + +/* JKM -- re-add EPORT later */ +#if 0 + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* disable eport */ + MCF_EPORT_EPIER &= ~(1 << irq); + } +#endif + + if (irq < 32) + MCF_IMRL |= (1 << irq); + else + MCF_IMRH |= (1 << (irq - 32)); +} +#endif --- /dev/null +++ b/arch/m68k/coldfire/iomap.c @@ -0,0 +1,56 @@ +/* + * arch/m68k/coldfire/iomap.c + * + * Generic coldfire iomap interface + * + * Based on the sh64 iomap.c by Paul Mundt. + * + * 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. + */ +#include +#include + +#if 0 +void __iomem *__attribute__ ((weak)) +ioport_map(unsigned long port, unsigned int len) +{ + return (void __iomem *)port; +} +EXPORT_SYMBOL(pci_iomap); + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing .. */ +} +EXPORT_SYMBOL(pci_iounmap); + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); +printk(KERN_INFO "PCI_IOMAP: BAR=%d START=0x%lx LEN=0x%lx FLAGS=0x%lx\n", + bar, start, len, flags); + + if (!len) + return NULL; + if (max && len > max) + len = max; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) + return (void __iomem *)start; + + /* What? */ + return NULL; +} +EXPORT_SYMBOL(ioport_map); + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + /* Nothing .. */ +} +EXPORT_SYMBOL(ioport_unmap); +#endif --- /dev/null +++ b/arch/m68k/coldfire/m547x_8x-devices.c @@ -0,0 +1,163 @@ +/* + * arch/m68k/coldfire/m547x_8x-devices.c + * + * Coldfire M547x/M548x Platform Device Configuration + * + * Copyright (c) 2008 Freescale Semiconductor, Inc. + * Kurt Mahan + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#ifdef CONFIG_SPI +/* + * + * DSPI + * + */ + +/* number of supported SPI selects */ +#define SPI_NUM_CHIPSELECTS 8 + +void coldfire_spi_cs_control(u8 cs, u8 command) +{ + /* nothing special required */ +} + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct coldfire_spi_chip spidev_chip_info = { + .bits_per_word = 8, +}; +#endif + +static struct spi_board_info spi_board_info[] = { +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) + { + .modalias = "spidev", + .max_speed_hz = 16000000, /* max clk (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 0, /* CS0 */ + .controller_data = &spidev_chip_info, + } +#endif +}; + +static int spi_irq_list[] = { + /* IRQ, ICR Offset, ICR Val,Mask */ + 64 + ISC_DSPI_OVRFW, ISC_DSPI_OVRFW, 0x18, 0, + 64 + ISC_DSPI_RFOF, ISC_DSPI_RFOF, 0x18, 0, + 64 + ISC_DSPI_RFDF, ISC_DSPI_RFDF, 0x18, 0, + 64 + ISC_DSPI_TFUF, ISC_DSPI_TFUF, 0x18, 0, + 64 + ISC_DSPI_TCF, ISC_DSPI_TCF, 0x18, 0, + 64 + ISC_DSPI_TFFF, ISC_DSPI_TFFF, 0x18, 0, + 64 + ISC_DSPI_EOQF, ISC_DSPI_EOQF, 0x18, 0, + 0,0,0,0, +}; + +static struct coldfire_spi_master coldfire_master_info = { + .bus_num = 1, + .num_chipselect = SPI_NUM_CHIPSELECTS, + .irq_list = spi_irq_list, + .irq_source = 0, /* not used */ + .irq_vector = 0, /* not used */ + .irq_mask = 0, /* not used */ + .irq_lp = 0, /* not used */ + .par_val = 0, /* not used */ + .cs_control = coldfire_spi_cs_control, +}; + +static struct resource coldfire_spi_resources[] = { + [0] = { + .name = "spi-par", + .start = MCF_MBAR + 0x00000a50, /* PAR_DSPI */ + .end = MCF_MBAR + 0x00000a50, /* PAR_DSPI */ + .flags = IORESOURCE_MEM + }, + + [1] = { + .name = "spi-module", + .start = MCF_MBAR + 0x00008a00, /* DSPI MCR Base */ + .end = MCF_MBAR + 0x00008ab8, /* DSPI mem map end */ + .flags = IORESOURCE_MEM + }, + + [2] = { + .name = "spi-int-level", + .start = MCF_MBAR + 0x740, /* ICR start */ + .end = MCF_MBAR + 0x740 + ISC_DSPI_EOQF, /* ICR end */ + .flags = IORESOURCE_MEM + }, + + [3] = { + .name = "spi-int-mask", + .start = MCF_MBAR + 0x70c, /* IMRL */ + .end = MCF_MBAR + 0x70c, /* IMRL */ + .flags = IORESOURCE_MEM + } +}; + +static struct platform_device coldfire_spi = { + .name = "spi_coldfire", + .id = -1, + .resource = coldfire_spi_resources, + .num_resources = ARRAY_SIZE(coldfire_spi_resources), + .dev = { + .platform_data = &coldfire_master_info, + } +}; + +/** + * m547x_8x_spi_init - Initialize SPI + */ +static int __init m547x_8x_spi_init(void) +{ + int retval; + + /* initialize the DSPI PAR */ + MCF_GPIO_PAR_DSPI = (MCF_GPIO_PAR_DSPI_PAR_CS5 | + MCF_GPIO_PAR_DSPI_PAR_CS3_DSPICS | + MCF_GPIO_PAR_DSPI_PAR_CS2_DSPICS | + MCF_GPIO_PAR_DSPI_PAR_CS0_DSPICS | + MCF_GPIO_PAR_DSPI_PAR_SCK_SCK | + MCF_GPIO_PAR_DSPI_PAR_SIN_SIN | + MCF_GPIO_PAR_DSPI_PAR_SOUT_SOUT); + + /* register device */ + retval = platform_device_register(&coldfire_spi); + if (retval < 0) { + goto out; + } + + /* register board info */ + if (ARRAY_SIZE(spi_board_info)) + retval = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); + +out: + return retval; +} +#endif + + +/** + * m547x_8x_init_devices - Initialize M547X_8X devices + * + * Returns 0 on success. + */ +static int __init m547x_8x_init_devices(void) +{ +#ifdef CONFIG_SPI + m547x_8x_spi_init(); +#endif + + return 0; +} +arch_initcall(m547x_8x_init_devices); --- /dev/null +++ b/arch/m68k/coldfire/m547x_8x-dma.c @@ -0,0 +1,516 @@ +/* + * arch/m68k/coldfire/m547x_8x-dma.c + * + * Coldfire M547x/M548x DMA + * + * Copyright (c) 2008 Freescale Semiconductor, Inc. + * Kurt Mahan + * + * This code is based on patches from the Freescale M547x_8x BSP + * release mcf547x_8x-20070107-ltib.iso + * + * 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 +#include +#include +#include +#include +#include + +/* + * This global keeps track of which initiators have been + * used of the available assignments. Initiators 0-15 are + * hardwired. Initiators 16-31 are multiplexed and controlled + * via the Initiatior Mux Control Registe (IMCR). The + * assigned requestor is stored with the associated initiator + * number. + */ +static int used_reqs[32] = { + DMA_ALWAYS, DMA_DSPI_RX, DMA_DSPI_TX, DMA_DREQ0, + DMA_PSC0_RX, DMA_PSC0_TX, DMA_USBEP0, DMA_USBEP1, + DMA_USBEP2, DMA_USBEP3, DMA_PCI_TX, DMA_PCI_RX, + DMA_PSC1_RX, DMA_PSC1_TX, DMA_I2C_RX, DMA_I2C_TX, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +/* + * This global keeps track of which channels have been assigned + * to tasks. This methology assumes that no single initiator + * will be tied to more than one task/channel + */ +static char used_channel[16] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + +unsigned int connected_channel[16] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/** + * dma_set_initiator - enable initiator + * @initiator: initiator identifier + * + * Returns 0 of successful, non-zero otherwise + * + * Attempt to enable the provided Initiator in the Initiator + * Mux Control Register. + */ +int dma_set_initiator(int initiator) +{ + switch (initiator) { + case DMA_ALWAYS: + case DMA_DSPI_RX: + case DMA_DSPI_TX: + case DMA_DREQ0: + case DMA_PSC0_RX: + case DMA_PSC0_TX: + case DMA_USBEP0: + case DMA_USBEP1: + case DMA_USBEP2: + case DMA_USBEP3: + case DMA_PCI_TX: + case DMA_PCI_RX: + case DMA_PSC1_RX: + case DMA_PSC1_TX: + case DMA_I2C_RX: + case DMA_I2C_TX: + /* + * These initiators are always active + */ + break; + + case DMA_FEC0_RX: + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC16(3)) + | MCF_DMA_IMCR_SRC16_FEC0RX; + used_reqs[16] = DMA_FEC0_RX; + break; + + case DMA_FEC0_TX: + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC17(3)) + | MCF_DMA_IMCR_SRC17_FEC0TX; + used_reqs[17] = DMA_FEC0_TX; + break; + + case DMA_FEC1_RX: + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC20(3)) + | MCF_DMA_IMCR_SRC20_FEC1RX; + used_reqs[20] = DMA_FEC1_RX; + break; + + case DMA_FEC1_TX: + if (used_reqs[21] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC21(3)) + | MCF_DMA_IMCR_SRC21_FEC1TX; + used_reqs[21] = DMA_FEC1_TX; + } else if (used_reqs[25] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC25(3)) + | MCF_DMA_IMCR_SRC25_FEC1TX; + used_reqs[25] = DMA_FEC1_TX; + } else if (used_reqs[31] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC31(3)) + | MCF_DMA_IMCR_SRC31_FEC1TX; + used_reqs[31] = DMA_FEC1_TX; + } else /* No empty slots */ + return 1; + break; + + case DMA_DREQ1: + if (used_reqs[29] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC29(3)) + | MCF_DMA_IMCR_SRC29_DREQ1; + used_reqs[29] = DMA_DREQ1; + } else if (used_reqs[21] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC21(3)) + | MCF_DMA_IMCR_SRC21_DREQ1; + used_reqs[21] = DMA_DREQ1; + } else /* No empty slots */ + return 1; + break; + + case DMA_CTM0: + if (used_reqs[24] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC24(3)) + | MCF_DMA_IMCR_SRC24_CTM0; + used_reqs[24] = DMA_CTM0; + } else /* No empty slots */ + return 1; + break; + + case DMA_CTM1: + if (used_reqs[25] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC25(3)) + | MCF_DMA_IMCR_SRC25_CTM1; + used_reqs[25] = DMA_CTM1; + } else /* No empty slots */ + return 1; + break; + + case DMA_CTM2: + if (used_reqs[26] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC26(3)) + | MCF_DMA_IMCR_SRC26_CTM2; + used_reqs[26] = DMA_CTM2; + } else /* No empty slots */ + return 1; + break; + + case DMA_CTM3: + if (used_reqs[27] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC27(3)) + | MCF_DMA_IMCR_SRC27_CTM3; + used_reqs[27] = DMA_CTM3; + } else /* No empty slots */ + return 1; + break; + + case DMA_CTM4: + if (used_reqs[28] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC28(3)) + | MCF_DMA_IMCR_SRC28_CTM4; + used_reqs[28] = DMA_CTM4; + } else /* No empty slots */ + return 1; + break; + + case DMA_CTM5: + if (used_reqs[29] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC29(3)) + | MCF_DMA_IMCR_SRC29_CTM5; + used_reqs[29] = DMA_CTM5; + } else /* No empty slots */ + return 1; + break; + + case DMA_CTM6: + if (used_reqs[30] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC30(3)) + | MCF_DMA_IMCR_SRC30_CTM6; + used_reqs[30] = DMA_CTM6; + } else /* No empty slots */ + return 1; + break; + + case DMA_CTM7: + if (used_reqs[31] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC31(3)) + | MCF_DMA_IMCR_SRC31_CTM7; + used_reqs[31] = DMA_CTM7; + } else /* No empty slots */ + return 1; + break; + + case DMA_USBEP4: + if (used_reqs[26] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC26(3)) + | MCF_DMA_IMCR_SRC26_USBEP4; + used_reqs[26] = DMA_USBEP4; + } else /* No empty slots */ + return 1; + break; + + case DMA_USBEP5: + if (used_reqs[27] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC27(3)) + | MCF_DMA_IMCR_SRC27_USBEP5; + used_reqs[27] = DMA_USBEP5; + } else /* No empty slots */ + return 1; + break; + + case DMA_USBEP6: + if (used_reqs[28] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC28(3)) + | MCF_DMA_IMCR_SRC28_USBEP6; + used_reqs[28] = DMA_USBEP6; + } else /* No empty slots */ + return 1; + break; + + case DMA_PSC2_RX: + if (used_reqs[28] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC28(3)) + | MCF_DMA_IMCR_SRC28_PSC2RX; + used_reqs[28] = DMA_PSC2_RX; + } else /* No empty slots */ + return 1; + break; + + case DMA_PSC2_TX: + if (used_reqs[29] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC29(3)) + | MCF_DMA_IMCR_SRC29_PSC2TX; + used_reqs[29] = DMA_PSC2_TX; + } else /* No empty slots */ + return 1; + break; + + case DMA_PSC3_RX: + if (used_reqs[30] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC30(3)) + | MCF_DMA_IMCR_SRC30_PSC3RX; + used_reqs[30] = DMA_PSC3_RX; + } else /* No empty slots */ + return 1; + break; + + case DMA_PSC3_TX: + if (used_reqs[31] == 0) { + MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC31(3)) + | MCF_DMA_IMCR_SRC31_PSC3TX; + used_reqs[31] = DMA_PSC3_TX; + } else /* No empty slots */ + return 1; + break; + + default: + return 1; + } + return 0; +} + +/** + * dma_get_initiator - get the initiator for the given requestor + * @requestor: initiator identifier + * + * Returns initiator number (0-31) if assigned or just 0 + */ +unsigned int dma_get_initiator(int requestor) +{ + u32 i; + + for (i = 0; i < sizeof(used_reqs); ++i) { + if (used_reqs[i] == requestor) + return i; + } + return 0; +} + +/** + * dma_remove_initiator - remove the given initiator from active list + * @requestor: requestor to remove + */ +void dma_remove_initiator(int requestor) +{ + u32 i; + + for (i = 0; i < sizeof(used_reqs); ++i) { + if (used_reqs[i] == requestor) { + used_reqs[i] = -1; + break; + } + } +} + +/** + * dma_set_channel_fec: find available channel for fec and mark + * @requestor: initiator/requestor identifier + * + * Returns first avaialble channel (0-5) or -1 if all occupied + */ +int dma_set_channel_fec(int requestor) +{ + u32 i, t; + +#ifdef CONFIG_FEC_548x_ENABLE_FEC2 + t = 4; +#else + t = 2; +#endif + + for (i = 0; i < t ; ++i) { + if (used_channel[i] == -1) { + used_channel[i] = requestor; + return i; + } + } + /* All channels taken */ + return -1; +} + +/** + * dma_set_channel - find an available channel and mark as used + * @requestor: initiator/requestor identifier + * + * Returns first available channel (6-15) or -1 if all occupied + */ +int dma_set_channel(int requestor) +{ + u32 i; +#ifdef CONFIG_NET_FEC2 + i = 4; +#else + i = 2; +#endif + + for (; i < 16; ++i) + if (used_channel[i] == -1) { + used_channel[i] = requestor; + return i; + } + + /* All channels taken */ + return -1; +} + +/** + * dma_get_channel - get the channel being initiated by the requestor + * @requestor: initiator/requestor identifier + * + * Returns Initiator for requestor or -1 if not found + */ +int dma_get_channel(int requestor) +{ + u32 i; + + for (i = 0; i < sizeof(used_channel); ++i) { + if (used_channel[i] == requestor) + return i; + } + return -1; +} + +/** + * dma_connect - connect a channel with reference on data + * @channel: channel number + * @address: reference address of data + * + * Returns 0 if success or -1 if invalid channel + */ +int dma_connect(int channel, int address) +{ + if ((channel < 16) && (channel >= 0)) { + connected_channel[channel] = address; + return 0; + } + return -1; +} + +/** + * dma_disconnect - disconnect a channel + * @channel: channel number + * + * Returns 0 if success or -1 if invalid channel + */ +int dma_disconnect(int channel) +{ + if ((channel < 16) && (channel >= 0)) { + connected_channel[channel] = 0; + return 0; + } + return -1; +} + +/** + * dma_remove_channel - remove channel from the active list + * @requestor: initiator/requestor identifier + */ +void dma_remove_channel(int requestor) +{ + u32 i; + + for (i = 0; i < sizeof(used_channel); ++i) { + if (used_channel[i] == requestor) { + used_channel[i] = -1; + break; + } + } +} + +/** + * dma_interrupt_handler - dma interrupt handler + * @irq: interrupt number + * @dev_id: data + * + * Returns IRQ_HANDLED + */ +irqreturn_t dma_interrupt_handler(int irq, void *dev_id) +{ + u32 i, interrupts; + + /* + * Determine which interrupt(s) triggered by AND'ing the + * pending interrupts with those that aren't masked. + */ + interrupts = MCF_DMA_DIPR; + MCF_DMA_DIPR = interrupts; + + for (i = 0; i < 16; ++i, interrupts >>= 1) { + if (interrupts & 0x1) + if (connected_channel[i] != 0) + ((void (*)(void)) (connected_channel[i])) (); + } + + return IRQ_HANDLED; +} + +/** + * dma_remove_channel_by_number - clear dma channel + * @channel: channel number to clear + */ +void dma_remove_channel_by_number(int channel) +{ + if ((channel < sizeof(used_channel)) && (channel >= 0)) + used_channel[channel] = -1; +} + +/** + * dma_init - initialize the dma subsystem + * + * Returns 0 if success non-zero if failure + * + * Handles the DMA initialization during device setup. + */ +int __devinit dma_init() +{ + int result; + char *dma_version_str; + + MCD_getVersion(&dma_version_str); + printk(KERN_INFO "m547x_8x DMA: Initialize %s\n", dma_version_str); + + /* attempt to setup dma interrupt handler */ + if (request_irq(64 + ISC_DMA, dma_interrupt_handler, IRQF_DISABLED, + "MCD-DMA", NULL)) { + printk(KERN_ERR "MCD-DMA: Cannot allocate the DMA IRQ(48)\n"); + return 1; + } + + MCF_DMA_DIMR = 0; + MCF_DMA_DIPR = 0xFFFFFFFF; + + MCF_ICR(ISC_DMA) = ILP_DMA; + + result = MCD_initDma((dmaRegs *) (MCF_MBAR + 0x8000), + (void *) SYS_SRAM_DMA_START, MCD_RELOC_TASKS); + if (result != MCD_OK) { + printk(KERN_ERR "MCD-DMA: Cannot perform DMA initialization\n"); + free_irq(64 + ISC_DMA, NULL); + return 1; + } + + return 0; +} +device_initcall(dma_init); --- /dev/null +++ b/arch/m68k/coldfire/Makefile @@ -0,0 +1,20 @@ +# +# Makefile for Linux arch/m68k/coldfire source directory +# + +obj-y:= entry.o config.o cache.o signal.o muldi3.o traps.o ints.o +ifdef CONFIG_M5445X +ifneq ($(strip $(CONFIG_USB) $(CONFIG_USB_GADGET_MCF5445X)),) + obj-y += usb.o usb/ +endif +endif + +ifdef CONFIG_M547X_8X +obj-$(CONFIG_PCI) += mcf548x-pci.o +else +obj-$(CONFIG_PCI) += pci.o mcf5445x-pci.o iomap.o +endif +obj-$(CONFIG_M5445X) += mcf5445x-devices.o +obj-$(CONFIG_M547X_8X) += m547x_8x-devices.o +obj-$(CONFIG_M547X_8X) += mcf548x-devices.o +obj-$(CONFIG_MCD_DMA) += m547x_8x-dma.o --- /dev/null +++ b/arch/m68k/coldfire/mcf5445x-devices.c @@ -0,0 +1,136 @@ +/* + * arch/m68k/coldfire/mcf5445x-devices.c + * + * Coldfire M5445x Platform Device Configuration + * + * Based on the Freescale MXC devices.c + * + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * Kurt Mahan + */ +#include +#include +#include +#include +#include + +#include +#include + +/* ATA Interrupt */ +#define IRQ_ATA (64 + 64 + 54) + +/* ATA Base */ +#define BASE_IO_ATA 0x90000000 + +#define ATA_IER MCF_REG08(BASE_IO_ATA+0x2c) /* int enable reg */ +#define ATA_ICR MCF_REG08(BASE_IO_ATA+0x30) /* int clear reg */ + +/* + * On-chip PATA + */ +#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE) +static int ata_init(struct platform_device *pdev) +{ + /* clear ints */ + ATA_IER = 0x00; + ATA_ICR = 0xff; + + /* setup shared pins */ + MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC & MCF_GPIO_PAR_FEC_FEC1_MASK) | + MCF_GPIO_PAR_FEC_FEC1_ATA; + + MCF_GPIO_PAR_FECI2C = (MCF_GPIO_PAR_FECI2C & + (MCF_GPIO_PAR_FECI2C_MDC1_MASK & + MCF_GPIO_PAR_FECI2C_MDIO1_MASK)) | + MCF_GPIO_PAR_FECI2C_MDC1_ATA_DIOR | + MCF_GPIO_PAR_FECI2C_MDIO1_ATA_DIOW; + + MCF_GPIO_PAR_ATA = MCF_GPIO_PAR_ATA_BUFEN | + MCF_GPIO_PAR_ATA_CS1 | + MCF_GPIO_PAR_ATA_CS0 | + MCF_GPIO_PAR_ATA_DA2 | + MCF_GPIO_PAR_ATA_DA1 | + MCF_GPIO_PAR_ATA_DA0 | + MCF_GPIO_PAR_ATA_RESET_RESET | + MCF_GPIO_PAR_ATA_DMARQ_DMARQ | + MCF_GPIO_PAR_ATA_IORDY_IORDY; + + MCF_GPIO_PAR_PCI = (MCF_GPIO_PAR_PCI & + (MCF_GPIO_PAR_PCI_GNT3_MASK & + MCF_GPIO_PAR_PCI_REQ3_MASK)) | + MCF_GPIO_PAR_PCI_GNT3_ATA_DMACK | + MCF_GPIO_PAR_PCI_REQ3_ATA_INTRQ; + + return 0; +} + +static void ata_exit(void) +{ + printk(KERN_INFO "** ata_exit\n"); +} + +static int ata_get_clk_rate(void) +{ + return MCF_BUSCLK; +} + +/* JKM -- move these to a header file */ +#define MCF_IDE_DMA_WATERMARK 32 /* DMA watermark level in bytes */ +#define MCF_IDE_DMA_BD_NR (512/3/4) /* number of BDs per channel */ + +static struct fsl_ata_platform_data ata_data = { + .init = ata_init, + .exit = ata_exit, + .get_clk_rate = ata_get_clk_rate, +#ifdef CONFIG_PATA_FSL_USE_DMA + .udma_mask = 0x0F, /* the board handles up to UDMA3 */ + .fifo_alarm = MCF_IDE_DMA_WATERMARK / 2, + .max_sg = MCF_IDE_DMA_BD_NR, +#endif +}; + +static struct resource pata_fsl_resources[] = { + [0] = { /* I/O */ + .start = BASE_IO_ATA, + .end = BASE_IO_ATA + 0x000000d8, + .flags = IORESOURCE_MEM, + }, + [2] = { /* IRQ */ + .start = IRQ_ATA, + .end = IRQ_ATA, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pata_fsl_device = { + .name = "pata_fsl", + .id = -1, + .num_resources = ARRAY_SIZE(pata_fsl_resources), + .resource = pata_fsl_resources, + .dev = { + .platform_data = &ata_data, + .coherent_dma_mask = ~0, /* $$$ REVISIT */ + }, +}; + +static inline void mcf5445x_init_pata(void) +{ + (void)platform_device_register(&pata_fsl_device); +} +#else +static inline void mcf5445x_init_pata(void) +{ +} +#endif + +static int __init mcf5445x_init_devices(void) +{ + printk(KERN_INFO "MCF5445x INIT_DEVICES\n"); +#if 0 + mcf5445x_init_pata(); +#endif + + return 0; +} +arch_initcall(mcf5445x_init_devices); --- /dev/null +++ b/arch/m68k/coldfire/mcf5445x-pci.c @@ -0,0 +1,431 @@ +/* + * arch/m68k/coldfire/mcf5445x-pci.c + * + * Coldfire M5445x specific PCI implementation. + * + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * Kurt Mahan + */ + +#include +#include +#include + +#include +#include +#include + +/* + * Layout MCF5445x to PCI memory mappings: + * + * WIN MCF5445x PCI TYPE + * --- -------- --- ---- + * [0] 0xA0000000 -> 0xA7FFFFFF 0xA0000000 -> 0xA7FFFFFF MEM + * [1] 0xA8000000 -> 0xABFFFFFF 0xA8000000 -> 0xABFFFFFF MEM + * [2] 0xAC000000 -> 0xAFFFFFFF 0xAC000000 -> 0xAFFFFFFF IO + */ + +#define MCF5445X_PCI_MEM_BASE 0xA0000000 +#define MCF5445X_PCI_MEM_SIZE 0x0C000000 + +#define MCF5445X_PCI_CONFIG_BASE 0xAC000000 +#define MCF5445X_PCI_CONFIG_SIZE 0x04000000 + +#define MCF5445X_PCI_IO_BASE 0xAC000000 +#define MCF5445X_PCI_IO_SIZE 0x04000000 + +/* PCI Bus memory resource block */ +struct resource pci_iomem_resource = { + .name = "PCI memory space", + .start = MCF5445X_PCI_MEM_BASE, + .flags = IORESOURCE_MEM, + .end = MCF5445X_PCI_MEM_BASE + MCF5445X_PCI_MEM_SIZE - 1 +}; + +/* PCI Bus ioport resource block */ +struct resource pci_ioport_resource = { + .name = "PCI I/O space", + .start = MCF5445X_PCI_IO_BASE, + .flags = IORESOURCE_IO, + .end = MCF5445X_PCI_IO_BASE + MCF5445X_PCI_IO_SIZE - 1 +}; + +/* + * The M54455EVB multiplexes all the PCI interrupts via + * the FPGA and routes them to a single interrupt. The + * PCI spec requires all PCI interrupt routines be smart + * enough to sort out their own interrupts. + * The interrupt source from the FPGA is configured + * to EPORT 3. + */ +#define MCF5445X_PCI_IRQ 0x43 + +#define PCI_SLOTS 4 + +/* + * FPGA Info + */ +#define FPGA_PCI_IRQ_ENABLE (u32 *)0x09000000 +#define FPGA_PCI_IRQ_STATUS (u32 *)0x09000004 +#define FPGA_PCI_IRQ_ROUTE (u32 *)0x0900000c +#define FPGA_SEVEN_LED (u32 *)0x09000014 + +extern void set_fpga(u32 *addr, u32 val); + +#ifdef DEBUG +void mcf5445x_pci_dumpregs(void); +#endif + +/* + * mcf5445x_conf_device(struct pci_dev *dev) + * + * Machine dependent Configure the given device. + * + * Parameters: + * + * dev - the pci device. + */ +void +mcf5445x_conf_device(struct pci_dev *dev) +{ + set_fpga(FPGA_PCI_IRQ_ENABLE, 0x0f); +} + +/* + * int mcf5445x_pci_config_read(unsigned int seg, unsigned int bus, + * unsigned int devfn, int reg, + * u32 *value) + * + * Read from PCI configuration space. + * + */ +int mcf5445x_pci_config_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) +{ + u32 addr = MCF_PCI_PCICAR_BUSNUM(bus) | + MCF_PCI_PCICAR_DEVNUM(PCI_SLOT(devfn)) | + MCF_PCI_PCICAR_FUNCNUM(PCI_FUNC(devfn)) | + MCF_PCI_PCICAR_DWORD(reg) | + MCF_PCI_PCICAR_E; + + if ((bus > 255) || (devfn > 255) || (reg > 255)) { + *value = -1; + return -EINVAL; + } + + /* setup for config mode */ + MCF_PCI_PCICAR = addr; + __asm__ __volatile__("nop"); + + switch (len) { + case 1: + *value = *(volatile u8 *)(MCF5445X_PCI_CONFIG_BASE+(reg&3)); + break; + case 2: + *value = le16_to_cpu(*(volatile u16 *) + (MCF5445X_PCI_CONFIG_BASE + (reg&2))); + break; + case 4: + *value = le32_to_cpu(*(volatile u32 *) + (MCF5445X_PCI_CONFIG_BASE)); + break; + } + + /* clear config mode */ + MCF_PCI_PCICAR = ~MCF_PCI_PCICAR_E; + __asm__ __volatile__("nop"); + + return 0; +} + +/* + * int mcf5445x_pci_config_write(unsigned int seg, unsigned int bus, + * unsigned int devfn, int reg, + * u32 *value) + * + * Write to PCI configuration space + */ +int mcf5445x_pci_config_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) +{ + u32 addr = MCF_PCI_PCICAR_BUSNUM(bus) | + MCF_PCI_PCICAR_DEVNUM(PCI_SLOT(devfn)) | + MCF_PCI_PCICAR_FUNCNUM(PCI_FUNC(devfn)) | + MCF_PCI_PCICAR_DWORD(reg) | + MCF_PCI_PCICAR_E; + + if ((bus > 255) || (devfn > 255) || (reg > 255)) + return -EINVAL; + + /* setup for config mode */ + MCF_PCI_PCICAR = addr; + __asm__ __volatile__("nop"); + + switch (len) { + case 1: + *(volatile u8 *)(MCF5445X_PCI_CONFIG_BASE+(reg&3)) = (u8)value; + break; + case 2: + *(volatile u16 *)(MCF5445X_PCI_CONFIG_BASE+(reg&2)) = + cpu_to_le16((u16)value); + break; + case 4: + *(volatile u32 *)(MCF5445X_PCI_CONFIG_BASE) = + cpu_to_le32(value); + break; + } + + /* clear config mode */ + MCF_PCI_PCICAR = ~MCF_PCI_PCICAR_E; + __asm__ __volatile__("nop"); + + return 0; +} + +/* hardware operations */ +static struct pci_raw_ops mcf5445x_pci_ops = { + .read = mcf5445x_pci_config_read, + .write = mcf5445x_pci_config_write, +}; + +/* + * irqreturn_t mcf5445x_pci_interrupt( int irq, void *dev) + * + * PCI controller interrupt handler. + */ +static irqreturn_t +mcf5445x_pci_interrupt(int irq, void *dev) +{ + u32 status = MCF_PCI_PCIGSCR; +#ifdef DEBUG + printk(KERN_INFO "PCI: Controller irq status=0x%08x\n", status); +#endif + /* clear */ + MCF_PCI_PCIGSCR = status; + + return IRQ_HANDLED; +} + +/* + * irqreturn_t mcf5445x_pci_arb_interrupt( int irq, void *dev) + * + * PCI Arbiter interrupt handler. + */ +static irqreturn_t +mcf5445x_pci_arb_interrupt(int irq, void *dev) +{ + u32 status = MCF_PCIARB_PASR; +#ifdef DEBUG + printk(KERN_INFO "PCI: Arbiter irq status=0x%08x\n", status); +#endif + /* clear */ + MCF_PCIARB_PASR = status; + return IRQ_HANDLED; +} + +/* + * struct pci_bus_info *init_mcf5445x_pci(void) + * + * Machine specific initialisation: + * + * - Allocate and initialise a 'pci_bus_info' structure + * - Initialize hardware + * + * Result: pointer to 'pci_bus_info' structure. + */ +int __init +init_mcf5445x_pci(void) +{ + return 0; +#if 0 + /* + * Initialize the PCI core + */ + + /* arbitration controller */ + MCF_PCIARB_PACR = MCF_PCIARB_PACR_INTMPRI | + MCF_PCIARB_PACR_EXTMPRI(0x0f) | + MCF_PCIARB_PACR_INTMINTEN | + MCF_PCIARB_PACR_EXTMINTEN(0x0f); + + /* pci pin assignment regs */ + MCF_GPIO_PAR_PCI = MCF_GPIO_PAR_PCI_GNT0 | + MCF_GPIO_PAR_PCI_GNT1 | + MCF_GPIO_PAR_PCI_GNT2 | + MCF_GPIO_PAR_PCI_GNT3_GNT3 | + MCF_GPIO_PAR_PCI_REQ0 | + MCF_GPIO_PAR_PCI_REQ1 | + MCF_GPIO_PAR_PCI_REQ2 | + MCF_GPIO_PAR_PCI_REQ3_REQ3; + + /* target control reg */ + MCF_PCI_PCITCR = MCF_PCI_PCITCR_P | + MCF_PCI_PCITCR_WCT(8); + + /* PCI MEM address */ + MCF_PCI_PCIIW0BTAR = 0xA007A000; + + /* PCI MEM address */ + MCF_PCI_PCIIW1BTAR = 0xA803A800; + + /* PCI IO address */ + MCF_PCI_PCIIW2BTAR = 0xAC03AC00; + + /* window control */ + MCF_PCI_PCIIWCR = MCF_PCI_PCIIWCR_WINCTRL0_ENABLE | + MCF_PCI_PCIIWCR_WINCTRL0_MEMREAD | + MCF_PCI_PCIIWCR_WINCTRL1_ENABLE | + MCF_PCI_PCIIWCR_WINCTRL1_MEMREAD | + MCF_PCI_PCIIWCR_WINCTRL2_ENABLE | + MCF_PCI_PCIIWCR_WINCTRL2_IO; + + /* initiator control reg */ + MCF_PCI_PCIICR = 0x00ff; + + /* type 0 - command */ + MCF_PCI_PCISCR = MCF_PCI_PCISCR_MW | /* mem write/inval */ + MCF_PCI_PCISCR_B | /* bus master enable */ + MCF_PCI_PCISCR_M; /* mem access enable */ + + /* type 0 - config reg */ + MCF_PCI_PCICR1 = MCF_PCI_PCICR1_CACHELINESIZE(8) | + MCF_PCI_PCICR1_LATTIMER(0xff); + + /* type 0 - config 2 reg */ + MCF_PCI_PCICR2 = 0; + + /* target control reg */ + MCF_PCI_PCITCR2 = MCF_PCI_PCITCR2_B0E | + MCF_PCI_PCITCR2_B4E; + + /* translate addresses from PCI[0] to CF[SDRAM] */ + MCF_PCI_PCITBATR0 = MCF_RAMBAR1 | MCF_PCI_PCITBATR0_EN; + MCF_PCI_PCITBATR4 = MCF_RAMBAR1 | MCF_PCI_PCITBATR4_EN; + + /* setup controller interrupt handlers */ + if (request_irq(55+128, mcf5445x_pci_interrupt, IRQF_SHARED, + "PCI Controller", NULL)) + printk(KERN_ERR "PCI: Unable to register controller irq\n"); + + if (request_irq (56+128, mcf5445x_pci_arb_interrupt, IRQF_SHARED, "PCI Arbiter", NULL)) + printk(KERN_ERR "PCI: Unable to register arbiter irq\n"); + + /* global control - clear reset bit */ + MCF_PCI_PCIGSCR = MCF_PCI_PCIGSCR_SEE | + MCF_PCI_PCIGSCR_PEE; + + /* let everything settle */ + udelay(1000); + + /* allocate bus ioport resource */ + if (request_resource(&ioport_resource, &pci_ioport_resource) < 0) + printk(KERN_ERR "PCI: Unable to alloc ioport resource\n"); + + /* allocate bus iomem resource */ + if (request_resource(&iomem_resource, &pci_iomem_resource) < 0) + printk(KERN_ERR "PCI: Unable to alloc iomem resource\n"); + + /* setup FPGA to route PCI to IRQ3(67), SW7 to IRQ7, SW6 to IRQ4 */ + set_fpga(FPGA_PCI_IRQ_ENABLE, 0x00000000); + set_fpga(FPGA_PCI_IRQ_ROUTE, 0x00000039); + set_fpga(FPGA_SEVEN_LED, 0x000000FF); + + raw_pci_ops = &mcf5445x_pci_ops; + + return 0; +#endif +} + +/* + * DEBUGGING + */ + +#ifdef DEBUG +struct regdump { + u32 addr; + char regname[16]; +}; + +struct regdump type0regs[] = { + { 0xfc0a8000, "PCIIDR" }, + { 0xfc0a8004, "PCISCR" }, + { 0xfc0a8008, "PCICCRIR" }, + { 0xfc0a800c, "PCICR1" }, + { 0xfc0a8010, "PCIBAR0" }, + { 0xfc0a8014, "PCIBAR1" }, + { 0xfc0a8018, "PCIBAR2" }, + { 0xfc0a801c, "PCIBAR3" }, + { 0xfc0a8020, "PCIBAR4" }, + { 0xfc0a8024, "PCIBAR5" }, + { 0xfc0a8028, "PCICCPR" }, + { 0xfc0a802c, "PCISID" }, + { 0xfc0a8030, "PCIERBAR" }, + { 0xfc0a8034, "PCICPR" }, + { 0xfc0a803c, "PCICR2" }, + { 0, "" } +}; + +struct regdump genregs[] = { + { 0xfc0a8060, "PCIGSCR" }, + { 0xfc0a8064, "PCITBATR0" }, + { 0xfc0a8068, "PCITBATR1" }, + { 0xfc0a806c, "PCITCR1" }, + { 0xfc0a8070, "PCIIW0BTAR" }, + { 0xfc0a8074, "PCIIW1BTAR" }, + { 0xfc0a8078, "PCIIW2BTAR" }, + { 0xfc0a8080, "PCIIWCR" }, + { 0xfc0a8084, "PCIICR" }, + { 0xfc0a8088, "PCIISR" }, + { 0xfc0a808c, "PCITCR2" }, + { 0xfc0a8090, "PCITBATR0" }, + { 0xfc0a8094, "PCITBATR1" }, + { 0xfc0a8098, "PCITBATR2" }, + { 0xfc0a809c, "PCITBATR3" }, + { 0xfc0a80a0, "PCITBATR4" }, + { 0xfc0a80a4, "PCITBATR5" }, + { 0xfc0a80a8, "PCIINTR" }, + { 0xfc0a80f8, "PCICAR" }, + { 0, "" } +}; + +struct regdump arbregs[] = { + { 0xfc0ac000, "PACR" }, + { 0xfc0ac004, "PASR" }, /* documentation error */ + { 0, "" } +}; + +/* + * void mcf5445x_pci_dumpregs() + * + * Dump out all the PCI registers + */ +void +mcf5445x_pci_dumpregs(void) +{ + struct regdump *reg; + + printk(KERN_INFO "*** MCF5445x PCI TARGET 0 REGISTERS ***\n"); + + reg = type0regs; + while (reg->addr) { + printk(KERN_INFO "0x%08x 0x%08x %s\n", reg->addr, + *((u32 *)reg->addr), reg->regname); + reg++; + } + + printk(KERN_INFO "\n*** MCF5445x PCI GENERAL REGISTERS ***\n"); + reg = genregs; + while (reg->addr) { + printk(KERN_INFO "0x%08x 0x%08x %s\n", reg->addr, + *((u32 *)reg->addr), reg->regname); + reg++; + } + printk(KERN_INFO "\n*** MCF5445x PCI ARBITER REGISTERS ***\n"); + reg = arbregs; + while (reg->addr) { + printk(KERN_INFO "0x%08x 0x%08x %s\n", reg->addr, + *((u32 *)reg->addr), reg->regname); + reg++; + } +} +#endif /* DEBUG */ --- /dev/null +++ b/arch/m68k/coldfire/mcf548x-devices.c @@ -0,0 +1,94 @@ +/* + * arch/m68k/coldfire/mcf5445x-devices.c + * + * Coldfire M5445x Platform Device Configuration + * + * Based on the Freescale MXC devices.c + * + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * Kurt Mahan + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct resource coldfire_i2c_resources[] = { + [0] = { /* I/O */ + .start = MCF_MBAR + 0x008F00, + .end = MCF_MBAR + 0x008F20, + .flags = IORESOURCE_MEM, + }, + [2] = { /* IRQ */ + .start = 40, + .end = 40, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device coldfire_i2c_device = { + .name = "MCF548X-i2c", + .id = -1, + .num_resources = ARRAY_SIZE(coldfire_i2c_resources), + .resource = coldfire_i2c_resources, +}; + +static struct resource coldfire_sec_resources[] = { + [0] = { /* I/O */ + .start = MCF_MBAR + 0x00020000, + .end = MCF_MBAR + 0x00033000, + .flags = IORESOURCE_MEM, + }, + [2] = { /* IRQ */ + .start = ISC_SEC, + .end = ISC_SEC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device coldfire_sec_device = { + .name = "fsl-sec1", + .id = -1, + .num_resources = ARRAY_SIZE(coldfire_sec_resources), + .resource = coldfire_sec_resources, +}; + +#if defined(CONFIG_MTD_PHYSMAP) +static struct physmap_flash_data mcf5485_flash_data = { + .width = 2, +}; + +static struct resource mcf5485_flash_resource = { + .start = 0xf8000000, + .end = 0xf80fffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device mcf5485_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &mcf5485_flash_data, + }, + .num_resources = 1, + .resource = &mcf5485_flash_resource, +}; +#endif + +static int __init mcf5485_init_devices(void) +{ + printk(KERN_INFO "MCF5485x INIT_DEVICES\n"); + + platform_device_register(&coldfire_i2c_device); + platform_device_register(&coldfire_sec_device); +/*#if defined(CONFIG_MTD_PHYSMAP) + platform_device_register(&mcf5485_flash_device); +#endif*/ + return 0; +} +arch_initcall(mcf5485_init_devices); --- /dev/null +++ b/arch/m68k/coldfire/mcf548x-pci.c @@ -0,0 +1,959 @@ +/* + * ColdFire 547x/548x PCI Host Controller functions + * + * Copyright (c) 2005-2008 Freescale Semiconductor, Inc. + * + * This code is based on the 2.6.10 version of pci.c + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#undef DEBUG +//#define DEBUG + +#ifdef DEBUG +//#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,75)) +# define irqreturn_t void +# define IRQ_HANDLED +# define IRQ_NONE +#endif + +/* + * Bridge configration dafaults + */ +#define PCI_RETRIES 0 +#define PCI_CACHE_LINE 8 +#define PCI_MINGNT 1 +#define PCI_MAXLAT 42 + + +/* + * Initiator windows setting + */ +#define HOST_MEM_BASE 0xD0000000 /* ColdFire Memory window base */ +#define PCI_MEM_BASE 0xD0000000 /* PCI Memory window base */ +#define PCI_MEM_SIZE 0x08000000 /* Memory window size (128M) */ +#define HOST_IO_BASE 0xD8000000 /* ColdFire I/O window base */ +#define PCI_IO_BASE_ADDR 0x00000000 /* PCI I/O window base */ +#define PCI_IO_SIZE 0x00010000 /* I/O window size (64K) */ +#define HOST_CFG_BASE 0xD8000000 /* ColdFire config window base */ +#define HOST_DMA_BASE CONFIG_SDRAM_BASE /* ColdFire PCI-DMA window base */ +#define PCI_HDR_BASE (MCF_MBAR+0xB00)/* ColdFire config registers */ + +#define PCI_MEM_MASK (PCI_MEM_SIZE-1) +#define PCI_IO_MASK (PCI_IO_SIZE-1) + +/* Macro to set initiator window */ +#define WxBAR(host_address, pci_address, size) \ + (((host_address) & 0xff000000) | \ + ((((size)-1) & 0xff000000) >> 8) | \ + ((pci_address) & 0xff000000) >> 16) + +/* + * BIOS internal data + */ +static u8 revision; /* controller revision */ + +/* + * Board specific setting + */ +const unsigned int irq_lines[] = { 5, 7 }; + +#define N_SLOTS (sizeof(board_info) / sizeof(board_info[0])) +#define N_IRQS (sizeof(irq_lines) / sizeof(irq_lines[0])) +#define BRIDGE_SLOT 0 + +const struct slotinfo { + unsigned char idsel; /* device number */ + unsigned char irq; /* external IRQ */ + unsigned char req; /* REQ line number */ + unsigned char gnt; /* GNT line number */ +} board_info[] = { + {0, 0, 0, 0}, /* Bridge */ + {17, 5, 1, 1}, /* Slot #1 */ + {18, 5, 2, 2}, /* Slot #2 */ + {20, 7, 3, 3}, /* Slot #3 */ + {21, 7, 4, 4}, /* Slot #4 */ +}; + +/************************************************************************/ + +/* + * static int mk_conf_addr() + * + * Return type0 or type1 configuration address + * by the means of device address and PCI dword location + * 0 - for not existing slots + */ +static int mk_conf_addr(/*struct pci_dev *dev*/struct pci_bus *bus, unsigned int devfn, int where) +{ + int slot, func, address, idsel, dev_fn; + + if (bus->number) { + address = MCF_PCICAR_E | (bus->number << 16) | + (devfn << 8) | (where & 0xfc); + } else { + slot = PCI_SLOT(devfn); + if (slot > N_SLOTS || slot == BRIDGE_SLOT) + return 0; + else { + func = PCI_FUNC(devfn); + idsel = board_info[slot].idsel; + + dev_fn = PCI_DEVFN(idsel, func); + address = MCF_PCICAR_E | (bus->number << 16) | + (dev_fn << 8) | (where & 0xfc); + } + } + + return (address); +} + +/* + * static int read_config_byte() + * + * Read a byte from configuration space of specified device + */ +static int read_config_byte(/*struct pci_dev *dev*/struct pci_bus *bus, unsigned int devfn, int where, u8 *value) +{ + int slot; + int address; + int result; + + *value = 0xff; + result = PCIBIOS_SUCCESSFUL; + + slot = PCI_SLOT(devfn); + if (slot == BRIDGE_SLOT) { + if (where <= 0x40) + *value = *(volatile u8 *) (PCI_HDR_BASE + (where ^ 3)); + else + *value = 0; + } else { + address = mk_conf_addr(bus, devfn, where); + if (!address) + result = PCIBIOS_DEVICE_NOT_FOUND; + else { + MCF_PCICAR = address; + *value = *(volatile u8 *) (HOST_CFG_BASE + (where & 3)); + } + } + __asm__ __volatile__("nop"); + __asm__ __volatile__("nop"); + MCF_PCICAR &= ~MCF_PCICAR_E; + + DBG("PCI: read_config_byte bus=%d, devfn=%d, addr=0x%02X, val=0x%02X, ret=%02X\n", + bus->number, devfn, where, *value, result); + + return (result); +} + +/* + * static int read_config_word() + * + * Read a word from configuration space of specified device + */ +static int read_config_word(/*struct pci_dev *dev*/struct pci_bus *bus, unsigned int devfn, int where, u16 *value) +{ + int slot; + int address; + int result; + + *value = 0xffff; + result = PCIBIOS_SUCCESSFUL; + + if (where & 0x1) + result = PCIBIOS_BAD_REGISTER_NUMBER; + else { + slot = PCI_SLOT(devfn); + if (slot == BRIDGE_SLOT) { + if (where <= 0x3f) + *value = + *(volatile u16 *) (PCI_HDR_BASE + + (where ^ 2)); + else + *value = 0; + } else { + address = mk_conf_addr(bus, devfn, where); + if (!address) + result = PCIBIOS_DEVICE_NOT_FOUND; + else { + MCF_PCICAR = address; + *value = le16_to_cpu(*(volatile u16 *) + (HOST_CFG_BASE + + (where & 2))); + } + } + } + __asm__ __volatile__("nop"); + __asm__ __volatile__("nop"); + MCF_PCICAR &= ~MCF_PCICAR_E; + + DBG("PCI: read_config_word bus=%d, devfn=%d, addr=0x%02X, val=0x%04X ret=%02X\n", + bus->number, devfn, where, *value, result); + + return (result); +} + +/* + * static int read_config_dword() + * + * Read a long word from configuration space of specified device + */ +static int read_config_dword(/*struct pci_dev *dev*/struct pci_bus *bus, unsigned int devfn, int where, u32 *value) +{ + int slot; + int address; + int result; + + *value = 0xffffffff; + result = PCIBIOS_SUCCESSFUL; + + if (where & 0x3) + result = PCIBIOS_BAD_REGISTER_NUMBER; + else { + slot = PCI_SLOT(devfn); + if (slot == BRIDGE_SLOT) { + if (where <= 0x3d) + *value = + *(volatile u32 *) (PCI_HDR_BASE + where); + else + *value = 0; + __asm__ __volatile__("nop"); + __asm__ __volatile__("nop"); + } else { + address = mk_conf_addr(bus, devfn, where); + if (!address) + result = PCIBIOS_DEVICE_NOT_FOUND; + else { + MCF_PCICAR = address; + *value = le32_to_cpu(*(volatile u32 *) + (HOST_CFG_BASE)); + __asm__ __volatile__("nop"); + __asm__ __volatile__("nop"); + if (bus->number != 0 && revision < 1) { + volatile u32 temp; + + MCF_PCICAR |= 0xff0000; + temp = *(volatile u32 *) (HOST_CFG_BASE); + } + } + } + } + + MCF_PCICAR &= ~MCF_PCICAR_E; + + DBG("PCI: read_config_dword bus=%d, devfn=%d, addr=0x%02X, value=0x%08X ret=%02X\n", + bus->number, devfn, where, *value, result); + + return (result); +} + +/* + * static int write_config_byte() + * + * Write a byte to configuration space of specified device + */ +static int write_config_byte(/*struct pci_dev *dev*/struct pci_bus *bus, unsigned int devfn, int where, u8 value) +{ + int slot; + int address; + int result; + + result = PCIBIOS_SUCCESSFUL; + + slot = PCI_SLOT(devfn); + if (slot == BRIDGE_SLOT) { + if (where <= 0x40) + *(volatile u8 *) (PCI_HDR_BASE + (where ^ 3)) = value; + } else { + address = mk_conf_addr(bus, devfn, where); + if (!address) + result = PCIBIOS_DEVICE_NOT_FOUND; + else { + MCF_PCICAR = address; + *(volatile u8 *) (HOST_CFG_BASE + (where & 3)) = value; + } + } + __asm__ __volatile__("nop"); + __asm__ __volatile__("nop"); + MCF_PCICAR &= ~MCF_PCICAR_E; + + DBG("PCI: write_config_byte bus=%d, devfn=%d, addr=0x%02X, value=0x%02X ret=%02X\n", + bus->number, devfn, where, value, result); + + return (result); +} + +/* + * static int write_config_word() + * + * Write a word to configuration space of specified device + */ +static int write_config_word(/*struct pci_dev *dev*/struct pci_bus *bus, unsigned int devfn, int where, u16 value) +{ + int slot; + int address; + int result; + + result = PCIBIOS_SUCCESSFUL; + + if (where & 0x1) + result = PCIBIOS_BAD_REGISTER_NUMBER; + else { + slot = PCI_SLOT(devfn); + if (slot == BRIDGE_SLOT) { + if (where <= 0x3f) + *(volatile u16 *) (PCI_HDR_BASE + (where ^ 2)) = + value; + } else { + address = mk_conf_addr(bus, devfn, where); + if (!address) + result = PCIBIOS_DEVICE_NOT_FOUND; + else { + MCF_PCICAR = address; + *(volatile u16 *) (HOST_CFG_BASE + (where & 2)) = + cpu_to_le16(value); + } + } + } + __asm__ __volatile__("nop"); + __asm__ __volatile__("nop"); + MCF_PCICAR &= ~MCF_PCICAR_E; + + DBG("PCI: write_config_word bus=%d, devfn=%d, addr=0x%02X, value=0x%04X ret=%02X\n", + bus->number, devfn, where, value, result); + + return (result); +} + +/* + * static int write_config_dword() + * + * Write a long word to configuration space of specified device + */ +static int write_config_dword(/*struct pci_dev *dev*/struct pci_bus *bus, unsigned int devfn, int where, u32 value) +{ + int slot; + int address; + int result; + + result = PCIBIOS_SUCCESSFUL; + + if (where & 0x3) + result = PCIBIOS_BAD_REGISTER_NUMBER; + else { + slot = PCI_SLOT(devfn); + if (slot == BRIDGE_SLOT) { + if (where <= 0x3d) + *(volatile u32 *) (PCI_HDR_BASE + where) = + value; + } else { + address = mk_conf_addr(bus, devfn, where); + if (!address) + result = PCIBIOS_DEVICE_NOT_FOUND; + else { + MCF_PCICAR = address; + *(volatile u32 *) (HOST_CFG_BASE) = + cpu_to_le32(value); + } + } + } + __asm__ __volatile__("nop"); + __asm__ __volatile__("nop"); + MCF_PCICAR &= ~MCF_PCICAR_E; + + DBG("PCI: write_config_dword dev=%d, fn=%d, addr=0x%02X, value=0x%08X ret=%02X\n", + PCI_SLOT(devfn), PCI_FUNC(devfn), where, value, result); + + return (result); +} + +static int config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 * val) +{ + switch (size) { + case 1: + return read_config_byte(bus, devfn, where, (u8 *) val); + case 2: + return read_config_word(bus, devfn, where, (u16 *) val); + default: + return read_config_dword(bus, devfn, where, val); + } +} + +static int config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + switch (size) { + case 1: + return write_config_byte(bus, devfn, where, (u8) val); + case 2: + return write_config_word(bus, devfn, where, (u16) val); + default: + return write_config_dword(bus, devfn, where, val); + } +} + +/* + * configuration routines entry points + */ +static struct pci_ops bus_ops = { + read: config_read, + write: config_write +}; + +/************************************************************************/ + +/* + * u8 pci_inb() + * + * Read a byte at specified address from I/O space + */ +unsigned char pci_inb(long addr) +{ + char value; + + value = *(volatile unsigned char *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); + DBG("PCI: inb addr=0x%08X, value=0x%02X\n", addr, value); + + return (unsigned char) value; +} + + +/* + * u16 pci_inw() + * + * Read a word at specified address from I/O space + */ +unsigned short pci_inw(long addr) +{ + short value; + volatile unsigned short *ptr; + + ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); + value = le16_to_cpu(*ptr); + + DBG("PCI: inw addr=0x%08X, value=0x%04X\n", addr, value); + return (unsigned short) value; +} + +/* + * u16 pci_raw_inw() + * + * Read a raw word at specified address from I/O space + */ +unsigned short pci_raw_inw(long addr) +{ + short value; + volatile unsigned short *ptr; + + ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); + value = *ptr; + + DBG("PCI: raw_inw addr=0x%08X, value=0x%04X\n", addr, value); + return (unsigned short) value; +} + +/* + * u32 pci_inl() + * + * Read a dword at specified address from I/O space + */ +unsigned long pci_inl(long addr) +{ + long value; + volatile unsigned long *ptr; + + ptr = (volatile unsigned long *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); + value = le32_to_cpu(*ptr); + + DBG("PCI: inl addr=0x%08X, value=0x%08X\n", addr, value); + return (unsigned long) value; +} + +/* + * u32 pci_raw_inl() + * + * Read a raw dword at specified address from I/O space + */ +unsigned long pci_raw_inl(long addr) +{ + long value; + volatile unsigned long *ptr; + + ptr = (volatile unsigned long *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); + value = *ptr; + + DBG("PCI: raw_inl addr=0x%08X, value=0x%08X\n", addr, value); + return (unsigned long) value; +} + +/* + * void pci_outb() + * + * Write a byte value at specified address to I/O space + */ +void pci_outb( unsigned char value, long addr) +{ + + *(volatile unsigned char *) (HOST_IO_BASE | (addr & PCI_IO_MASK)) = value; + DBG("PCI: outb addr=0x%08X, value=0x%02X\n", addr, value); +} + + +/* + * void pci_outw() + * + * Write a word value at specified address to I/O space + */ +void pci_outw(volatile unsigned short value, volatile long addr) +{ + volatile unsigned short *ptr; + + ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); + *ptr = cpu_to_le16(value); + DBG("PCI: outw addr=0x%08X, value=0x%04X\n", addr, value); +} + +/* + * void pci_raw_outw() + * + * Write a raw word value at specified address to I/O space + */ +void pci_raw_outw(volatile unsigned short value, volatile long addr) +{ + volatile unsigned short *ptr; + + ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); + *ptr = value; + DBG("PCI: raw_outw addr=0x%08X, value=0x%04X\n", addr, value); +} + +/* + * void pci_outl() + * + * Write a long word value at specified address to I/O space + */ +void pci_outl(volatile unsigned long value, volatile long addr) +{ + volatile unsigned long *ptr; + + ptr = (volatile unsigned long *)(HOST_IO_BASE | (addr & PCI_IO_MASK)); + *ptr = cpu_to_le32(value); + DBG("PCI: outl addr=0x%08X, value=0x%08X\n", addr, value); +} + +/* + * void pci_raw_outl() + * + * Write a raw long word value at specified address to I/O space + */ +void pci_raw_outl(volatile unsigned long value, volatile long addr) +{ + volatile unsigned long *ptr; + + ptr = (volatile unsigned long *)(HOST_IO_BASE | (addr & PCI_IO_MASK)); + *ptr = value; + DBG("PCI: raw_outl addr=0x%08X, value=0x%08X\n", addr, value); +} + +/* + * void pci_insb() + * + * Read several byte values from specified I/O port + */ +void pci_insb(volatile unsigned char *addr, unsigned char *buf, int len) +{ + for (; len--; buf++) + *buf = pci_inb((unsigned long)addr); + DBG("PCI: pci_insb addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); +} + + +/* + * void pci_insw() + * + * Read several word values from specified I/O port + */ +void pci_insw(volatile unsigned short *addr, unsigned short *buf, int len) +{ + for (; len--; buf++) + *buf = pci_inw((unsigned long)addr); + DBG("PCI: pci_insw addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); +} + +/* + * void pci_insl() + * + * Read several dword values from specified I/O port + */ +void pci_insl(volatile unsigned long *addr, unsigned long *buf, int len) +{ + for (; len--; buf++) + *buf = pci_inl((unsigned long)addr); + DBG("PCI: pci_insl addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); +} + +/* + * void pci_outsb() + * + * Write several byte values to specified I/O port + */ +void pci_outsb(volatile unsigned char *addr, const unsigned char *buf, int len) +{ + for (; len--; buf++) + pci_outb((unsigned long)addr, *buf); + DBG("PCI: pci_outsb addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); +} + +/* + * void pci_outsw() + * + * Write several word values to specified I/O port + */ +void pci_outsw(volatile unsigned short *addr, const unsigned short *buf, int len) +{ + for (; len--; buf++) + pci_outw((unsigned long)addr, *buf); + DBG("PCI: pci_outsw addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); +} + +/* + * void pci_outsl() + * + * Write several dword values to specified I/O port + */ +void pci_outsl(volatile unsigned long *addr, const unsigned long *buf, int len) +{ + for (; len--; buf++) + pci_outl((unsigned long)addr, *buf); + DBG("PCI: pci_outsl addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); +} + +/* + * void pci_xlb_handler() + * + * PCI XLB interrupt handler + */ +irqreturn_t xlb_interrupt(int irq, void *dev) +{ + volatile int xlb_error = MCF_PCIISR; + + /* Acknowlege interrupt */ + MCF_PCIISR = xlb_error; + + /* Dump interrupt reason */ + if (xlb_error & MCF_PCIISR_RE) + DBG("PCI: Retry Error Received\n"); + + if (xlb_error & MCF_PCIISR_IA) + DBG("PCI: Initiator Abort Received\n"); + + if (xlb_error & MCF_PCIISR_TA) + DBG("PCI: Target Abort Received\n"); + + return IRQ_HANDLED; +} + + +/* + * void pci_arbiter_handler() + * + * PCI arbiter interrupt handler + */ +irqreturn_t arb_interrupt(int irq, void *dev) +{ + volatile unsigned long arb_error = MCF_PCIARB_PASR; + + /* Acknowlege interrupt */ + printk("%s\n",__FUNCTION__); + MCF_PCIARB_PASR = arb_error; + + if (arb_error & MCF_PCIARB_PASR_ITLMBK) { + DBG("PCI: coldfire master time-out\n"); + + /* Set infinite number of retries */ + MCF_PCIICR &= ~0xFF; + } + + if (arb_error & MCF_PCIARB_PASR_EXTMBK(0x1F)) { + arb_error >>= 17; + DBG("PCI: external master time-out (mask = 0x%X)\n", arb_error); + + /* raise arbitration priority level */ + MCF_PCIARB_PACR = MCF_PCIARB_PACR_EXTMPRI(arb_error); + } + + return IRQ_HANDLED; +} + + +/* + * void pci_eint_handler() + * + * Eport interrupt handler + */ +irqreturn_t eint_handler(int irq, void *dev) +{ + /* Just acknowlege interrupt and exit */ + MCF_EPFR = 0x1 << (irq - 64); + return IRQ_HANDLED; +} + + +/* + * void __init coldfire_fixup(int pci_modify) + * + * Assign IRQ numbers as used by Linux to the interrupt pins + * of the PCI cards. + */ +static void __init coldfire_fixup(int pci_modify) +{ + struct pci_dev *dev; + unsigned char slot, pin; + + DBG("%s\n",__FUNCTION__); +#ifdef NL_ORIGINAL + pci_for_each_dev(dev) { +#else + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { +#endif + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) { + slot = PCI_SLOT(dev->devfn); + dev->irq = 64 + board_info[slot].irq; + + /* Check if device needs interrupt */ +#ifdef NL_ORIGINAL + pcibios_read_config_byte( + dev->bus->number, dev->devfn, + PCI_INTERRUPT_PIN, &pin); + + if ( pin ) { + pcibios_write_config_byte( + dev->bus->number, dev->devfn, + PCI_INTERRUPT_LINE, dev->irq); + } +#else + pci_read_config_byte(dev, + PCI_INTERRUPT_PIN, &pin); + + if ( pin ) { + pci_write_config_byte(dev, + PCI_INTERRUPT_LINE, dev->irq); + } +#endif + } + } +} + +static void __init configure_device(struct pci_dev *dev) +{ + /* TODO: This should depend from disable_pci_burst setting */ + DBG("%s\n",__FUNCTION__); +#ifdef NL_ORIGINAL + pcibios_write_config_byte(bus, devfn, PCI_CACHE_LINE_SIZE, PCI_CACHE_LINE); +#else + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, PCI_CACHE_LINE); +#endif +} + +struct pci_bus_info *__init init_coldfire_pci(void) +{ + static struct pci_bus_info bus; + int i; + int pci_mem_va; + static char irq_name[N_IRQS][15]; + + /* Get controller revision */ + revision = MCF_PCICCRIR; + printk("ColdFire PCI Host Bridge (Rev. %d) detected:" + "MEMBase %x,MEMLen %x,IOBase %x,IOLen %x\n", + revision, HOST_MEM_BASE, PCI_MEM_SIZE - 1, 0, PCI_IO_SIZE - 1); + + /* Setup bus info structure. */ + memset(&bus, 0, sizeof (struct pci_bus_info)); + + /* Request intiator memory resource */ + bus.mem_space.start = PCI_MEM_BASE;//HOST_MEM_BASE; + bus.mem_space.end = bus.mem_space.start + PCI_MEM_SIZE - 1; + bus.mem_space.name = "PCI Bus #0"; + if (request_resource(&iomem_resource, &bus.mem_space) != 0) + { + printk("Failed to request bridge iomem resource\n"); + return NULL; + } + + /* Request intiator memory resource */ + bus.io_space.start = 0; + bus.io_space.end = bus.io_space.start + PCI_IO_SIZE - 1; + bus.io_space.name = "PCI Bus #0"; + if (request_resource(&ioport_resource, &bus.io_space) != 0) + { + printk("Failed to request bridge ioport resource\n"); + return NULL; + } + + /* Must Reset!!! If bootloader has PCI enabled, it will cause + * problem in linux when it tries to configure/find resources + * for the pci devices. Both registers need to be reset. + */ + MCF_PCIGSCR = 0x1; + MCF_PCITCR = 0x00000000; + + /* Set up the arbiter */ + MCF_PCIARB_PACR = 0 /*MCF_PCIARB_PACR_PKMD*/ + | MCF_PCIARB_PACR_INTMPRI + | MCF_PCIARB_PACR_INTMINTEN + | MCF_PCIARB_PACR_EXTMPRI(0x1F) + | MCF_PCIARB_PACR_EXTMINTEN(0x1F); + + /* GNT and REQ */ + MCF_PAR_PCIBG = 0x3FF; + MCF_PAR_PCIBR = 0x3FF; + + /* Enable bus mastering, memory access and MWI */ + MCF_PCISCR = MCF_PCISCR_B | MCF_PCISCR_M | MCF_PCISCR_MW; + + /* Setup burst parameters */ + MCF_PCICR1 = MCF_PCICR1_LATTIMER(32) | + MCF_PCICR1_CACHELINESIZE(PCI_CACHE_LINE); + + MCF_PCICR2 = 0; + /*MCF_PCICR2_MINGNT(PCI_MINGNT) | + MCF_PCICR2_MAXLAT(PCI_MAXLAT); + */ + /* Turn on error signaling */ + MCF_PCIICR = MCF_PCIICR_TAE | MCF_PCIICR_IAE | PCI_RETRIES; + MCF_PCIGSCR |= MCF_PCIGSCR_SEE; + /* + * Configure Initiator Windows + * Window 0: 128M PCI Memory @ HOST_MEM_BASE, 1:1 mapping + * Window 1: 64K I/O Memory @ HOST_IO_BASE, 1:0 mapping + */ + MCF_PCIIW0BTAR = WxBAR(HOST_MEM_BASE, PCI_MEM_BASE, PCI_MEM_SIZE); + MCF_PCIIW1BTAR = WxBAR(HOST_IO_BASE, PCI_IO_BASE_ADDR, PCI_IO_SIZE); + + MCF_PCIIWCR = MCF_PCIIWCR_WINCTRL1_IO | + MCF_PCIIWCR_WINCTRL0_MEMRDLINE; + + /* Target PCI DMA Windows */ + MCF_PCIBAR1 = PCI_DMA_BASE; + MCF_PCITBATR1 = HOST_DMA_BASE | MCF_PCITBATR1_EN; + MCF_PCIBAR0 = MCF_RAMBAR0;; + MCF_PCITBATR0 = MCF_RAMBAR0 | MCF_PCITBATR0_EN; + DBG("PCI TCR %x,MCF_PCIBAR1 %x,MCF_PCITBATR1 %x." + "MCF_PCIBAR0 %x,MCF_PCITBATR9 %x\n", MCF_PCITCR, MCF_PCIBAR1, + MCF_PCITBATR1, MCF_PCIBAR0, MCF_PCITBATR0); + /* Enable internal PCI controller interrupts */ + MCF_ICR(ISC_PCI_XLB) = ILP_PCI_XLB; + /*request_irq(64+ISC_PCI_XLB, xlb_interrupt, + SA_INTERRUPT, "PCI XL Bus", (void*)-1); + enable_irq (64+ISC_PCI_XLB); + */ + if(request_irq(64+ISC_PCI_XLB, xlb_interrupt, + IRQF_DISABLED, "PCI XL Bus", (void*)-1)){ + printk("Cannot allocate ISC_PCI_XLB IRQ\n"); + return (struct pci_bus_info *)-EBUSY; + } + + MCF_ICR(ISC_PCI_ARB) = ILP_PCI_ARB; + /*request_irq(64+ISC_PCI_ARB, arb_interrupt, + SA_INTERRUPT, "PCI Arbiter", (void*)-1); + enable_irq (64+ISC_PCI_ARB); + */ + if(request_irq(64+ISC_PCI_ARB, arb_interrupt, + IRQF_DISABLED, "PCI Arbiter", (void*)-1)){ + printk("Cannot allocate ISC_PCI_ARB IRQ\n"); + return (struct pci_bus_info *)-EBUSY; + } + + /* Set slots interrupt setting */ + for (i = 0; i < N_IRQS; i++) + { + /* Set trailing edge for PCI interrupts */ + MCF_EPPAR &= ~MCF_EPPAR_EPPA(irq_lines[i], 0x3); + if (irq_lines[i] == 5) + MCF_EPPAR |= MCF_EPPAR_EPPA(irq_lines[i], MCF_EPPAR_EPPAx_FALLING); + else + MCF_EPPAR |= MCF_EPPAR_EPPA(irq_lines[i], 0/*MCF_EPPAR_EPPAx_FALLING*/); + /* Turn on irq line in eport */ + MCF_EPIER |= MCF_EPIER_EPIE(irq_lines[i]); + + /* Enable irq in gpio */ + if (irq_lines[i] == 5) + MCF_PAR_FECI2CIRQ |= 1; + + if (irq_lines[i] == 6) + MCF_PAR_FECI2CIRQ |= 2; + + /* Register external interrupt handlers */ + sprintf(irq_name[i], "PCI IRQ%d", irq_lines[i]); + /*request_irq(64 + irq_lines[i], eint_handler, + SA_SHIRQ, irq_name[i], (void*)-1); + enable_irq(64 + irq_lines[i]);*/ + if(request_irq(64 + irq_lines[i], eint_handler, + IRQF_SHARED, irq_name[i], (void*)-1)){ + printk("Cannot allocate irq_lines[%d] IRQ\n", irq_lines[i]); + return (struct pci_bus_info *)-EBUSY; + } + } + + /* Clear PCI Reset and wait for devices to reset */ + MCF_PCIGSCR &= ~MCF_PCIGSCR_PR; + schedule_timeout((5 * HZ) / 10); + /* Remap initiator windows (should be 1:1 to the physical memory) */ + pci_mem_va = (int) ioremap_nocache(HOST_MEM_BASE, PCI_MEM_SIZE + PCI_IO_SIZE); +#if 1 + printk("%s: MEMBase_phy %x, Virt %x, len %x\n",__FUNCTION__, + HOST_MEM_BASE,pci_mem_va,PCI_MEM_SIZE + PCI_IO_SIZE); +#endif + BUG_ON(pci_mem_va != HOST_MEM_BASE); + + /* Setup bios32 and pci bus driver callbacks */ + bus.m68k_pci_ops = &bus_ops; + bus.fixup = coldfire_fixup; + bus.conf_device = configure_device; + + return &bus; +} + --- /dev/null +++ b/arch/m68k/coldfire/muldi3.S @@ -0,0 +1,64 @@ +/* + * Coldfire muldi3 assembly verion + */ + +#include +.globl __muldi3 + +ENTRY(__muldi3) + linkw %fp,#0 + lea %sp@(-32),%sp + moveml %d2-%d7/%a2-%a3,%sp@ + moveal %fp@(8), %a2 + moveal %fp@(12), %a3 + moveal %fp@(16), %a0 + moveal %fp@(20),%a1 + movel %a3,%d2 + andil #65535,%d2 + movel %a3,%d3 + clrw %d3 + swap %d3 + movel %a1,%d0 + andil #65535,%d0 + movel %a1,%d1 + clrw %d1 + swap %d1 + movel %d2,%d7 + mulsl %d0,%d7 + movel %d2,%d4 + mulsl %d1,%d4 + movel %d3,%d2 + mulsl %d0,%d2 + mulsl %d1,%d3 + movel %d7,%d0 + clrw %d0 + swap %d0 + addl %d0,%d4 + addl %d2,%d4 + cmpl %d4,%d2 + blss 1f + addil #65536,%d3 +1: + movel %d4,%d0 + clrw %d0 + swap %d0 + movel %d3,%d5 + addl %d0,%d5 + movew %d4,%d6 + swap %d6 + movew %d7,%d6 + movel %d5,%d0 + movel %d6,%d1 + movel %a3,%d2 + movel %a0,%d3 + mulsl %d3,%d2 + movel %a2,%d3 + movel %a1,%d4 + mulsl %d4,%d3 + addl %d3,%d2 + movel %d2,%d0 + addl %d5,%d0 + moveml %sp@, %d2-%d7/%a2-%a3 + lea %sp@(32),%sp + unlk %fp + rts --- /dev/null +++ b/arch/m68k/coldfire/pci.c @@ -0,0 +1,245 @@ +/* + * linux/arch/m68k/coldfire/pci.c + * + * PCI initialization for Coldfire architectures. + * + * Currently Supported: + * M5445x + * + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * Kurt Mahan + */ + +#include +#include +#include + +#include +#include + +/* pci ops for reading/writing config */ +struct pci_raw_ops *raw_pci_ops; + +/* pci debug flag */ +static int debug_pci; + +#ifdef CONFIG_M54455 +extern int init_mcf5445x_pci(void); +extern void mcf5445x_conf_device(struct pci_dev *dev); +extern void mcf5445x_pci_dumpregs(void); + +extern struct resource pci_ioport_resource; +extern struct resource pci_iomem_resource; +#endif + +static int +pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + return raw_pci_ops->read(0, bus->number, devfn, where, size, value); +} + +static int +pci_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + return raw_pci_ops->write(0, bus->number, devfn, where, size, value); +} + +struct pci_ops pci_root_ops = { + .read = pci_read, + .write = pci_write, +}; + +/* + * pcibios_setup(char *) + * + * Initialize the pcibios based on cmd line params. + */ +char * +pcibios_setup(char *str) +{ + if (!strcmp(str, "debug")) { + debug_pci = 1; + return NULL; + } + return str; +} + +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ +void +pcibios_align_resource(void *data, struct resource *res, resource_size_t size, + resource_size_t align) +{ + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + resource_size_t start = res->start; + + if (size > 0x100) + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", pci_name(dev), + dev->resource - res, (long int)size); + + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } +} + +/* + * Swizzle the device pin each time we cross a bridge + * and return the slot number. + */ +static u8 __devinit +pcibios_swizzle(struct pci_dev *dev, u8 *pin) +{ + return 0; +} + +/* + * Map a slot/pin to an IRQ. + */ +static int +pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return 0x43; +} + +/* + * pcibios_update_irq(struct pci_dev *dev, int irq) + * + * Update a PCI interrupt. + */ +void +pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +/* + * pcibios_enable_device(struct pci_dev *dev, int mask) + * + * Enable a device on the PCI bus. + */ +int +pcibios_enable_device(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because " + "of resource collisions\n", pci_name(dev)); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", + pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); +#ifdef CONFIG_M54455 + mcf5445x_conf_device(dev); +#endif + } + + return 0; +} + +/* + * pcibios_fixup_bus(struct pci_bus *bus) + */ +void +pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev = bus->self; + + if (!dev) { + /* Root bus. */ +#ifdef CONFIG_M54455 + bus->resource[0] = &pci_ioport_resource; + bus->resource[1] = &pci_iomem_resource; +#endif + } +} + +/* + * pcibios_init(void) + * + * Allocate/initialize low level pci bus/devices. + */ +static int __init +pcibios_init(void) +{ + struct pci_bus *bus; + + if (!raw_pci_ops) { + printk(KERN_WARNING "PCIBIOS: FATAL: NO PCI Hardware found\n"); + return 0; + } + + /* allocate and scan the (only) bus */ + bus = pci_scan_bus_parented(NULL, 0, &pci_root_ops, NULL); + + /* setup everything */ + if (bus) { + /* compute the bridge window sizes */ + pci_bus_size_bridges(bus); + + /* (re)assign device resources */ + pci_bus_assign_resources(bus); + + /* add the bus to the system */ + pci_bus_add_devices(bus); + + /* fixup irqs */ + pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); + } + + return 0; +} + +/* + * pci_init(void) + * + * Initialize the PCI Hardware. + */ +static int __init +pci_init(void) +{ +#if defined(CONFIG_M54455) + init_mcf5445x_pci(); +#endif + if (!raw_pci_ops) + printk(KERN_ERR "PCI: FATAL: NO PCI Detected\n"); + + return 0; +} + +/* low level hardware (first) */ +arch_initcall(pci_init); + +/* basic bios init (second) */ +subsys_initcall(pcibios_init); --- /dev/null +++ b/arch/m68k/coldfire/signal.c @@ -0,0 +1,871 @@ +/* + * linux/arch/m68k/kernel/signal.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * 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. + */ + +/* + * Derived from m68k/kernel/signal.c and the original authors are credited + * there. + * + * Coldfire support by: + * Matt Waddel Matt.Waddel@freescale.com + * Copyright Freescale Semiconductor, Inc 2007 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); + +const int frame_extra_sizes[16] = { + [1] = -1, + [2] = sizeof(((struct frame *)0)->un.fmt2), + [3] = sizeof(((struct frame *)0)->un.fmt3), + [4] = 0, + [5] = -1, + [6] = -1, + [7] = sizeof(((struct frame *)0)->un.fmt7), + [8] = -1, + [9] = sizeof(((struct frame *)0)->un.fmt9), + [10] = sizeof(((struct frame *)0)->un.fmta), + [11] = sizeof(((struct frame *)0)->un.fmtb), + [12] = -1, + [13] = -1, + [14] = -1, + [15] = -1, +}; + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int do_sigsuspend(struct pt_regs *regs) +{ + old_sigset_t mask = regs->d3; + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->d0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +do_rt_sigsuspend(struct pt_regs *regs) +{ + sigset_t __user *unewset = (sigset_t __user *)regs->d1; + size_t sigsetsize = (size_t)regs->d2; + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->d0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (!access_ok(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage int +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) +{ + return do_sigaltstack(uss, uoss, rdusp()); +} + + +/* + * Do a signal return; undo the signal stack. + * + * Keep the return code on the stack quadword aligned! + * That makes the cache flush below easier. + */ + +struct sigframe +{ + char __user *pretcode; + int sig; + int code; + struct sigcontext __user *psc; + char retcode[16]; + unsigned long extramask[_NSIG_WORDS-1]; + struct sigcontext sc; +}; + +struct rt_sigframe +{ + char __user *pretcode; + int sig; + struct siginfo __user *pinfo; + void __user *puc; + char retcode[16]; + struct siginfo info; + struct ucontext uc; +}; + +#define FPCONTEXT_SIZE 216 +#define uc_fpstate uc_filler[0] +#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] +#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] + +#ifdef CONFIG_FPU +static unsigned char fpu_version; /* version num of fpu, set by setup_frame */ + +static inline int restore_fpu_state(struct sigcontext *sc) +{ + int err = 1; + + if (FPU_IS_EMU) { + /* restore registers */ + memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); + memcpy(current->thread.fp, sc->sc_fpregs, 24); + return 0; + } + + if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { + /* Verify the frame format. */ + if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) + goto out; + if (CPU_IS_020_OR_030) { + if (m68k_fputype & FPU_68881 && + !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4)) + goto out; + if (m68k_fputype & FPU_68882 && + !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4)) + goto out; + } else if (CPU_IS_040) { + if (!(sc->sc_fpstate[1] == 0x00 || + sc->sc_fpstate[1] == 0x28 || + sc->sc_fpstate[1] == 0x60)) + goto out; + } else if (CPU_IS_060) { + if (!(sc->sc_fpstate[3] == 0x00 || + sc->sc_fpstate[3] == 0x60 || + sc->sc_fpstate[3] == 0xe0)) + goto out; + } else + goto out; + + } + err = 0; + +out: + return err; +} + +static inline int rt_restore_fpu_state(struct ucontext __user *uc) +{ + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = CPU_IS_060 ? 8 : 0; + fpregset_t fpregs; + int err = 1; + + if (FPU_IS_EMU) { + /* restore fpu control register */ + if (__copy_from_user(current->thread.fpcntl, + uc->uc_mcontext.fpregs.f_fpcntl, 12)) + goto out; + /* restore all other fpu register */ + if (__copy_from_user(current->thread.fp, + uc->uc_mcontext.fpregs.f_fpregs, 96)) + goto out; + return 0; + } + + if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate)) + goto out; + if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { + if (!CPU_IS_060) + context_size = fpstate[1]; + /* Verify the frame format. */ + if (!CPU_IS_060 && (fpstate[0] != fpu_version)) + goto out; + if (CPU_IS_020_OR_030) { + if (m68k_fputype & FPU_68881 && + !(context_size == 0x18 || context_size == 0xb4)) + goto out; + if (m68k_fputype & FPU_68882 && + !(context_size == 0x38 || context_size == 0xd4)) + goto out; + } else if (CPU_IS_040) { + if (!(context_size == 0x00 || + context_size == 0x28 || + context_size == 0x60)) + goto out; + } else if (CPU_IS_060) { + if (!(fpstate[3] == 0x00 || + fpstate[3] == 0x60 || + fpstate[3] == 0xe0)) + goto out; + } else + goto out; + if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, + sizeof(fpregs))) + goto out; + } + if (context_size && + __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1, + context_size)) + goto out; + err = 0; + +out: + return err; +} +#endif + +static inline int +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, + void __user *fp, int *pd0) +{ + int fsize, formatvec; + struct sigcontext context; + int err = 0; + + /* get previous context */ + if (copy_from_user(&context, usc, sizeof(context))) + goto badframe; + + /* restore passed registers */ + regs->d1 = context.sc_d1; + regs->a0 = context.sc_a0; + regs->a1 = context.sc_a1; + regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); + regs->pc = context.sc_pc; + regs->orig_d0 = -1; /* disable syscall checks */ + wrusp(context.sc_usp); + formatvec = context.sc_formatvec; + regs->format = formatvec >> 12; + regs->vector = formatvec & 0xfff; + +#ifdef CONFIG_FPU + err = restore_fpu_state(&context); +#endif + + fsize = frame_extra_sizes[regs->format]; + if (fsize < 0) { + /* + * user process trying to return with weird frame format + */ +#ifdef DEBUG + printk(KERN_DEBUG "user process returning with weird \ + frame format\n"); +#endif + goto badframe; + } + + /* OK. Make room on the supervisor stack for the extra junk, + * if necessary. + */ + + { + struct switch_stack *sw = (struct switch_stack *)regs - 1; + regs->d0 = context.sc_d0; +#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) + __asm__ __volatile__ + (" movel %0,%/sp\n\t" + " bra ret_from_signal\n" + "4:\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,4b\n" + ".previous" + : /* no outputs, it doesn't ever return */ + : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), + "n" (frame_offset), "a" (fp) + : "a0"); +#undef frame_offset + /* + * If we ever get here an exception occurred while + * building the above stack-frame. + */ + goto badframe; + } + + *pd0 = context.sc_d0; + return err; + +badframe: + return 1; +} + +static inline int +rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, + struct ucontext __user *uc, int *pd0) +{ + int fsize, temp; + greg_t __user *gregs = uc->uc_mcontext.gregs; + unsigned long usp; + int err; + + err = __get_user(temp, &uc->uc_mcontext.version); + if (temp != MCONTEXT_VERSION) + goto badframe; + /* restore passed registers */ + err |= __get_user(regs->d0, &gregs[0]); + err |= __get_user(regs->d1, &gregs[1]); + err |= __get_user(regs->d2, &gregs[2]); + err |= __get_user(regs->d3, &gregs[3]); + err |= __get_user(regs->d4, &gregs[4]); + err |= __get_user(regs->d5, &gregs[5]); + err |= __get_user(sw->d6, &gregs[6]); + err |= __get_user(sw->d7, &gregs[7]); + err |= __get_user(regs->a0, &gregs[8]); + err |= __get_user(regs->a1, &gregs[9]); + err |= __get_user(regs->a2, &gregs[10]); + err |= __get_user(sw->a3, &gregs[11]); + err |= __get_user(sw->a4, &gregs[12]); + err |= __get_user(sw->a5, &gregs[13]); + err |= __get_user(sw->a6, &gregs[14]); + err |= __get_user(usp, &gregs[15]); + wrusp(usp); + err |= __get_user(regs->pc, &gregs[16]); + err |= __get_user(temp, &gregs[17]); + regs->sr = (regs->sr & 0xff00) | (temp & 0xff); + regs->orig_d0 = -1; /* disable syscall checks */ + err |= __get_user(temp, &uc->uc_formatvec); + regs->format = temp >> 12; + regs->vector = temp & 0xfff; + +#ifdef CONFIG_FPU + err |= rt_restore_fpu_state(uc); +#endif + + if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) + goto badframe; + + fsize = frame_extra_sizes[regs->format]; + if (fsize < 0) { + /* + * user process trying to return with weird frame format + */ +#ifdef DEBUG + printk(KERN_DEBUG "user process returning with weird \ + frame format\n"); +#endif + goto badframe; + } + + /* OK. Make room on the supervisor stack for the extra junk, + * if necessary. + */ + + { +#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) + __asm__ __volatile__ + (" movel %0,%/sp\n\t" + " bra ret_from_signal\n" + "4:\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,4b\n" + ".previous" + : /* no outputs, it doesn't ever return */ + : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), + "n" (frame_offset), "a" (&uc->uc_extra) + : "a0"); +#undef frame_offset + /* + * If we ever get here an exception occurred while + * building the above stack-frame. + */ + goto badframe; + } + + *pd0 = regs->d0; + return err; + +badframe: + return 1; +} + +asmlinkage int do_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); + sigset_t set; + int d0; + + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.sc_mask) || + (_NSIG_WORDS > 1 && + __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + 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->sc, frame + 1, &d0)) + goto badframe; + return d0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int do_rt_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct rt_sigframe __user *frame = + (struct rt_sigframe __user *)(usp - 4); + sigset_t set; + int d0; + + 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 (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) + goto badframe; + return d0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +#ifdef CONFIG_FPU +/* + * Set up a signal frame. + */ + +static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) +{ + if (FPU_IS_EMU) { + /* save registers */ + memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); + memcpy(sc->sc_fpregs, current->thread.fp, 24); + return; + } +} + +static inline int rt_save_fpu_state(struct ucontext __user *uc, + struct pt_regs *regs) +{ + int err = 0; + + if (FPU_IS_EMU) { + /* save fpu control register */ + err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl, + current->thread.fpcntl, 12); + /* save all other fpu register */ + err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, + current->thread.fp, 96); + return err; + } + + return err; +} +#endif + +static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + unsigned long mask) +{ + sc->sc_mask = mask; + sc->sc_usp = rdusp(); + sc->sc_d0 = regs->d0; + sc->sc_d1 = regs->d1; + sc->sc_a0 = regs->a0; + sc->sc_a1 = regs->a1; + sc->sc_sr = regs->sr; + sc->sc_pc = regs->pc; + sc->sc_formatvec = regs->format << 12 | regs->vector; +#ifdef CONFIG_FPU + save_fpu_state(sc, regs); +#endif +} + +static inline int rt_setup_ucontext(struct ucontext __user *uc, + struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + greg_t __user *gregs = uc->uc_mcontext.gregs; + int err = 0; + + err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); + err |= __put_user(regs->d0, &gregs[0]); + err |= __put_user(regs->d1, &gregs[1]); + err |= __put_user(regs->d2, &gregs[2]); + err |= __put_user(regs->d3, &gregs[3]); + err |= __put_user(regs->d4, &gregs[4]); + err |= __put_user(regs->d5, &gregs[5]); + err |= __put_user(sw->d6, &gregs[6]); + err |= __put_user(sw->d7, &gregs[7]); + err |= __put_user(regs->a0, &gregs[8]); + err |= __put_user(regs->a1, &gregs[9]); + err |= __put_user(regs->a2, &gregs[10]); + err |= __put_user(sw->a3, &gregs[11]); + err |= __put_user(sw->a4, &gregs[12]); + err |= __put_user(sw->a5, &gregs[13]); + err |= __put_user(sw->a6, &gregs[14]); + err |= __put_user(rdusp(), &gregs[15]); + err |= __put_user(regs->pc, &gregs[16]); + err |= __put_user(regs->sr, &gregs[17]); + err |= __put_user((regs->format << 12) | regs->vector, + &uc->uc_formatvec); +#ifdef CONFIG_FPU + err |= rt_save_fpu_state(uc, regs); +#endif + return err; +} + +static inline void push_cache(unsigned long vaddr) +{ +#if 0 +// JKM -- need to add into the old cpushl cache stuff + cf_cache_push(__pa(vaddr), 8); +#endif +} + +static inline void __user * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + unsigned long usp; + + /* Default to using normal stack. */ + usp = rdusp(); + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (!sas_ss_flags(usp)) + usp = current->sas_ss_sp + current->sas_ss_size; + } + return (void __user *)((usp - frame_size) & -8UL); +} + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe __user *frame; + int fsize = frame_extra_sizes[regs->format]; + struct sigcontext context; + int err = 0; + + if (fsize < 0) { +#ifdef DEBUG + printk(KERN_DEBUG "setup_frame: Unknown frame format %#x\n", + regs->format); +#endif + goto give_sigsegv; + } + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + err |= __put_user((current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + + err |= __put_user(regs->vector, &frame->code); + err |= __put_user(&frame->sc, &frame->psc); + + if (_NSIG_WORDS > 1) + err |= copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + + setup_sigcontext(&context, regs, set->sig[0]); + err |= copy_to_user(&frame->sc, &context, sizeof(context)); + + /* Set up to return from userspace. */ + err |= __put_user(frame->retcode, &frame->pretcode); + /* moveq #,d0; trap #0 */ + err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), + (long __user *)(frame->retcode)); + + if (err) + goto give_sigsegv; + + push_cache((unsigned long) &frame->retcode); + + /* Set up registers for signal handler */ + wrusp((unsigned long) frame); + regs->pc = (unsigned long) ka->sa.sa_handler; + +adjust_stack: + /* Prepare to skip over the extra stuff in the exception frame. */ + if (regs->stkadj) { + struct pt_regs *tregs = + (struct pt_regs *)((ulong)regs + regs->stkadj); +#ifdef DEBUG + printk(KERN_DEBUG "Performing stackadjust=%04x\n", + regs->stkadj); +#endif + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->vector = 0; + tregs->format = 0; + tregs->pc = regs->pc; + tregs->sr = regs->sr; + } + return; + +give_sigsegv: + force_sigsegv(sig, current); + goto adjust_stack; +} + +static void 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 fsize = frame_extra_sizes[regs->format]; + int err = 0; + + if (fsize < 0) { +#ifdef DEBUG + printk(KERN_DEBUG "setup_frame: Unknown frame format %#x\n", + regs->format); +#endif + goto give_sigsegv; + } + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (fsize) { + err |= copy_to_user(&frame->uc.uc_extra, regs + 1, fsize); + regs->stkadj = fsize; + } + + err |= __put_user((current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Create 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(rdusp()), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= rt_setup_ucontext(&frame->uc, regs); + err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. */ + err |= __put_user(frame->retcode, &frame->pretcode); + + /* moveq #,d0; andi.l #,D0; trap #0 */ + err |= __put_user(0x70AD0280, (long *)(frame->retcode + 0)); + err |= __put_user(0x000000ff, (long *)(frame->retcode + 4)); + err |= __put_user(0x4e400000, (long *)(frame->retcode + 8)); + + if (err) + goto give_sigsegv; + + push_cache((unsigned long) &frame->retcode); + + /* Set up registers for signal handler */ + wrusp((unsigned long) frame); + regs->pc = (unsigned long) ka->sa.sa_handler; + +adjust_stack: + /* Prepare to skip over the extra stuff in the exception frame. */ + if (regs->stkadj) { + struct pt_regs *tregs = + (struct pt_regs *)((ulong)regs + regs->stkadj); +#ifdef DEBUG + printk(KERN_DEBUG "Performing stackadjust=%04x\n", + regs->stkadj); +#endif + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->vector = 0; + tregs->format = 0; + tregs->pc = regs->pc; + tregs->sr = regs->sr; + } + return; + +give_sigsegv: + force_sigsegv(sig, current); + goto adjust_stack; +} + +static inline void +handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) +{ + switch (regs->d0) { + case -ERESTARTNOHAND: + if (!has_handler) + goto do_restart; + regs->d0 = -EINTR; + break; + + case -ERESTARTSYS: + if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { + regs->d0 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: +do_restart: + regs->d0 = regs->orig_d0; + regs->pc -= 2; + break; + } +} + +/* + * OK, we're invoking a handler + */ +static void +handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) +{ + /* are we from a system call? */ + if (regs->orig_d0 >= 0) + /* If so, check system call restarting.. */ + handle_restart(regs, ka, 1); + + /* set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); +} + +/* + * 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. + */ +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +{ + siginfo_t info; + struct k_sigaction ka; + int signr; + + current->thread.esp0 = (unsigned long) regs; + + if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + if (signr > 0) { + /* Whee! Actually deliver the signal. */ + handle_signal(signr, &ka, &info, oldset, regs); + return 1; + } + + /* Did we come from a system call? */ + if (regs->orig_d0 >= 0) + /* Restart the system call - no handlers present */ + handle_restart(regs, NULL, 0); + + return 0; +} --- /dev/null +++ b/arch/m68k/coldfire/traps.c @@ -0,0 +1,455 @@ +/* + * linux/arch/m68knommu/kernel/traps.c + * + * Copyright (C) 1993, 1994 by Hamish Macdonald + * + * 68040 fixes by Michael Rausch + * 68040 fixes by Martin Apel + * 68060 fixes by Roman Hodek + * 68060 fixes by Jesper Skov + * Coldfire fixes by Kurt Mahan + * + * 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. + */ + +/* + * Sets up all exception vectors + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static char const * const vec_names[] = { + "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR", + "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc", + "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111", + "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION", + "FORMAT ERROR", "UNINITIALIZED INTERRUPT", + "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17", + "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19", + "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21", + "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23", + "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT", + "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT", + "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3", + "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7", + "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11", + "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15", + "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW", + "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN", + "FPCP UNSUPPORTED OPERATION", + "MMU CONFIGURATION ERROR" +}; + +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code); +asmlinkage void trap_c(struct frame *fp); +extern void __init coldfire_trap_init(void); + +void __init trap_init(void) +{ + coldfire_trap_init(); +} + +/* The following table converts the FS encoding of a ColdFire + exception stack frame into the error_code value needed by + do_fault. */ + +static const unsigned char fs_err_code[] = { + 0, /* 0000 */ + 0, /* 0001 */ + 0, /* 0010 */ + 0, /* 0011 */ + 1, /* 0100 */ + 0, /* 0101 */ + 0, /* 0110 */ + 0, /* 0111 */ + 2, /* 1000 */ + 3, /* 1001 */ + 2, /* 1010 */ + 0, /* 1011 */ + 1, /* 1100 */ + 1, /* 1101 */ + 0, /* 1110 */ + 0 /* 1111 */ +}; + +#ifdef DEBUG +static const char *fs_err_msg[16] = { + "Normal", + "Reserved", + "Interrupt during debug service routine", + "Reserved", + "X Protection", + "TLB X miss (opword)", + "TLB X miss (ext. word)", + "IFP in emulator mode", + "W Protection", + "Write error", + "TLB W miss", + "Reserved", + "R Protection", + "R/RMW Protection", + "TLB R miss", + "OEP in emulator mode", +}; +#endif + +static inline void access_errorCF(struct frame *fp) +{ + unsigned long int mmusr, complainingAddress; + unsigned int err_code, fs; + int need_page_fault; + + mmusr = fp->ptregs.mmusr; + complainingAddress = fp->ptregs.mmuar; +#ifdef DEBUG + printk(KERN_DEBUG "pc %#lx, mmusr %#lx, complainingAddress %#lx\n", \ + fp->ptregs.pc, mmusr, complainingAddress); +#endif + + /* + * error_code: + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + */ + + fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1; + switch (fs) { + case 5: /* 0101 TLB opword X miss */ + need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 0, 0); + complainingAddress = fp->ptregs.pc; + break; + case 6: /* 0110 TLB extension word X miss */ + need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 0, 1); + complainingAddress = fp->ptregs.pc + sizeof(long); + break; + case 10: /* 1010 TLB W miss */ + need_page_fault = cf_tlb_miss(&fp->ptregs, 1, 1, 0); + break; + case 14: /* 1110 TLB R miss */ + need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 1, 0); + break; + default: + /* 0000 Normal */ + /* 0001 Reserved */ + /* 0010 Interrupt during debug service routine */ + /* 0011 Reserved */ + /* 0100 X Protection */ + /* 0111 IFP in emulator mode */ + /* 1000 W Protection*/ + /* 1001 Write error*/ + /* 1011 Reserved*/ + /* 1100 R Protection*/ + /* 1101 R Protection*/ + /* 1111 OEP in emulator mode*/ + need_page_fault = 1; + break; + } + + if (need_page_fault) { + err_code = fs_err_code[fs]; + if ((fs == 13) && (mmusr & MMUSR_WF)) /* rd-mod-wr access */ + err_code |= 2; /* bit1 - write, bit0 - protection */ + do_page_fault(&fp->ptregs, complainingAddress, err_code); + } +} + +void die_if_kernel(char *str, struct pt_regs *fp, int nr) +{ + if (!(fp->sr & PS_S)) + return; + + console_verbose(); + printk(KERN_EMERG "%s: %08x\n", str, nr); + printk(KERN_EMERG "PC: [<%08lx>]", fp->pc); + print_symbol(" %s", fp->pc); + printk(KERN_EMERG "\nSR: %04x SP: %p a2: %08lx\n", + fp->sr, fp, fp->a2); + printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", + fp->d0, fp->d1, fp->d2, fp->d3); + printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", + fp->d4, fp->d5, fp->a0, fp->a1); + + printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, PAGE_SIZE+(unsigned long)current); + show_stack(NULL, (unsigned long *)fp); + do_exit(SIGSEGV); +} + +asmlinkage void buserr_c(struct frame *fp) +{ + unsigned int fs; + + /* Only set esp0 if coming from user mode */ + if (user_mode(&fp->ptregs)) + current->thread.esp0 = (unsigned long) fp; + + fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1; +#if defined(DEBUG) + printk(KERN_DEBUG "*** Bus Error *** (%x)%s\n", fs, + fs_err_msg[fs & 0xf]); +#endif + switch (fs) { + case 0x5: + case 0x6: + case 0x7: + case 0x9: + case 0xa: + case 0xd: + case 0xe: + case 0xf: + access_errorCF(fp); + break; + default: + die_if_kernel("bad frame format", &fp->ptregs, 0); +#if defined(DEBUG) + printk(KERN_DEBUG "Unknown SIGSEGV - 4\n"); +#endif + force_sig(SIGSEGV, current); + } +} + + +int kstack_depth_to_print = 48; + +void show_stack(struct task_struct *task, unsigned long *stack) +{ + unsigned long *endstack, addr, symaddr; + extern char _start, _etext; + int i; + + if (!stack) { + if (task) + stack = (unsigned long *)task->thread.ksp; + else + stack = (unsigned long *)&stack; + } + + addr = (unsigned long) stack; + endstack = (unsigned long *) PAGE_ALIGN(addr); + + printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); + for (i = 0; i < kstack_depth_to_print; i++) { + if (stack + 1 > endstack) + break; + if (i % 8 == 0) + printk("\n" KERN_EMERG " "); + symaddr = *stack; + printk(KERN_EMERG " %08lx", *stack++); + if ((symaddr >= 0xc0000000) && (symaddr < 0xc1000000)) + print_symbol("(%s)", symaddr); + } + printk("\n"); + + printk(KERN_EMERG "Call Trace:"); + i = 0; + while (stack + 1 <= endstack) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_start) && + (addr <= (unsigned long) &_etext))) { + if (i % 4 == 0) + printk("\n" KERN_EMERG " "); + printk(KERN_EMERG " [<%08lx>]", addr); + i++; + } + } + printk("\n"); +} + +void bad_super_trap(struct frame *fp) +{ + console_verbose(); + if (fp->ptregs.vector < sizeof(vec_names)/sizeof(vec_names[0])) + printk(KERN_WARNING "*** %s *** FORMAT=%X\n", + vec_names[fp->ptregs.vector], + fp->ptregs.format); + else + printk(KERN_WARNING "*** Exception %d *** FORMAT=%X\n", + fp->ptregs.vector, + fp->ptregs.format); + printk(KERN_WARNING "Current process id is %d\n", current->pid); + die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); +} + +asmlinkage void trap_c(struct frame *fp) +{ + int sig; + siginfo_t info; + + if (fp->ptregs.sr & PS_S) { + if (fp->ptregs.vector == VEC_TRACE) { + /* traced a trapping instruction */ + current->ptrace |= PT_DTRACE; + } else + bad_super_trap(fp); + return; + } + + /* send the appropriate signal to the user program */ + switch (fp->ptregs.vector) { + case VEC_ADDRERR: + info.si_code = BUS_ADRALN; + sig = SIGBUS; + break; + case VEC_ILLEGAL: + case VEC_LINE10: + case VEC_LINE11: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + case VEC_PRIV: + info.si_code = ILL_PRVOPC; + sig = SIGILL; + break; + case VEC_COPROC: + info.si_code = ILL_COPROC; + sig = SIGILL; + break; + case VEC_TRAP1: /* gdbserver breakpoint */ + fp->ptregs.pc -= 2; + info.si_code = TRAP_TRACE; + sig = SIGTRAP; + break; + case VEC_TRAP2: + case VEC_TRAP3: + case VEC_TRAP4: + case VEC_TRAP5: + case VEC_TRAP6: + case VEC_TRAP7: + case VEC_TRAP8: + case VEC_TRAP9: + case VEC_TRAP10: + case VEC_TRAP11: + case VEC_TRAP12: + case VEC_TRAP13: + case VEC_TRAP14: + info.si_code = ILL_ILLTRP; + sig = SIGILL; + break; + case VEC_FPBRUC: + case VEC_FPOE: + case VEC_FPNAN: + info.si_code = FPE_FLTINV; + sig = SIGFPE; + break; + case VEC_FPIR: + info.si_code = FPE_FLTRES; + sig = SIGFPE; + break; + case VEC_FPDIVZ: + info.si_code = FPE_FLTDIV; + sig = SIGFPE; + break; + case VEC_FPUNDER: + info.si_code = FPE_FLTUND; + sig = SIGFPE; + break; + case VEC_FPOVER: + info.si_code = FPE_FLTOVF; + sig = SIGFPE; + break; + case VEC_ZERODIV: + info.si_code = FPE_INTDIV; + sig = SIGFPE; + break; + case VEC_CHK: + case VEC_TRAP: + info.si_code = FPE_INTOVF; + sig = SIGFPE; + break; + case VEC_TRACE: /* ptrace single step */ + info.si_code = TRAP_TRACE; + sig = SIGTRAP; + break; + case VEC_TRAP15: /* breakpoint */ + info.si_code = TRAP_BRKPT; + sig = SIGTRAP; + break; + default: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + } + info.si_signo = sig; + info.si_errno = 0; + switch (fp->ptregs.format) { + default: + info.si_addr = (void *) fp->ptregs.pc; + break; + case 2: + info.si_addr = (void *) fp->un.fmt2.iaddr; + break; + case 7: + info.si_addr = (void *) fp->un.fmt7.effaddr; + break; + case 9: + info.si_addr = (void *) fp->un.fmt9.iaddr; + break; + case 10: + info.si_addr = (void *) fp->un.fmta.daddr; + break; + case 11: + info.si_addr = (void *) fp->un.fmtb.daddr; + break; + } + force_sig_info(sig, &info, current); +} + +asmlinkage void set_esp0(unsigned long ssp) +{ + current->thread.esp0 = ssp; +} + +/* + * The architecture-independent backtrace generator + */ +void dump_stack(void) +{ + unsigned long stack; + + show_stack(current, &stack); +} +EXPORT_SYMBOL(dump_stack); + +#ifdef CONFIG_M68KFPU_EMU +asmlinkage void fpemu_signal(int signal, int code, void *addr) +{ + siginfo_t info; + + info.si_signo = signal; + info.si_errno = 0; + info.si_code = code; + info.si_addr = addr; + force_sig_info(signal, &info, current); +} +#endif --- /dev/null +++ b/arch/m68k/coldfire/usb/Makefile @@ -0,0 +1,28 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +ifneq ($(CONFIG_USB_EHCI_HCD),) + obj-y += otg_host.o +endif + +ifneq ($(CONFIG_USB_GADGET_MCF5445X),) + obj-y += otg_device.o +endif + +ifneq ($(strip $(CONFIG_USB_GADGET_MCF5445X) $(CONFIG_USB_EHCI_HCD)),) + obj-y += otg_cmn.o +endif + +ifneq ($(CONFIG_USB_OTG),) + obj-y += otg_otg.o +endif + + +# USB Transceiver driver: +ifneq ($(strip $(CONFIG_USB) $(CONFIG_USB_GADGET_MCF5445X)),) + obj-y += xcvr.o +endif + --- /dev/null +++ b/arch/m68k/coldfire/usb/otg_cmn.c @@ -0,0 +1,106 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern void fsl_usb_enable_clk(void); +extern void fsl_usb_disable_clk(void); +extern int fsl_usb_mem_init(struct platform_device *pdev); + +extern struct fsl_xcvr_ops *xc_ops[]; + +static int otg_used; + +int usbotg_init(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata; + struct fsl_xcvr_ops *xops = xc_ops[USB_CTRLR_OTG]; + int rc; + + pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; + + pr_debug("%s: pdev=0x%p pdata=0x%p\n", __FUNCTION__, pdev, pdata); + + if (!xops) { + printk(KERN_ERR "OTG transceiver ops missing\n"); + return -EINVAL; + } + pdata->xcvr_ops = xops; + pdata->xcvr_type = xops->xcvr_type; + + if (!otg_used) { + /* request_mem_region and ioremap registers */ + rc = fsl_usb_mem_init(pdev); + if (rc) + return rc; + + fsl_usb_enable_clk(); + + if (xops->init) + xops->init(pdev); + } + + otg_used++; + pr_debug("%s: success\n", __FUNCTION__); + return 0; +} + +void usbotg_uninit(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata; + pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; + + pr_debug("%s\n", __FUNCTION__); + + otg_used--; + if (!otg_used) { + if (pdata->xcvr_ops && pdata->xcvr_ops->uninit) + pdata->xcvr_ops->uninit(pdev); + + iounmap(pdata->regs); + release_mem_region(pdata->r_start, pdata->r_len); + + pdata->regs = NULL; + pdata->r_start = pdata->r_len = 0; + + fsl_usb_disable_clk(); + } +} + +struct fsl_usb2_platform_data mxc_otg_config = { + .name = "OTG", + .platform_init = usbotg_init, + .platform_uninit = usbotg_uninit, + .es = 1, + .big_endian_mmio = 1, + .big_endian_desc = 1, + .le_setup_buf = 1, + .does_otg = 1, + .power_budget = 500, /* 500 mA max power */ + .max_ep_nr = 4, /* DDD read from a register ? */ + .phy_mode = FSL_USB2_PHY_ULPI, /* DDD redundant with xcvr_type */ +}; --- /dev/null +++ b/arch/m68k/coldfire/usb/otg_device.c @@ -0,0 +1,89 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define USB_OTGREGS_BASE MCF_REG32(0xFC0B0000) +#define INT_USB (64 + 64 + 47) /* INTC1:47 16.2.9.1 */ +#define INT_UOCSR (64 + 64 + 53) /* INTC1:53 16.2.9.1 */ + +extern int usbotg_init(struct platform_device *pdev); +extern void usbotg_uninit(struct fsl_usb2_platform_data *pdata); +extern struct fsl_usb2_platform_data mxc_otg_config; + +struct platform_device otg_udc_device; + +/*! + * OTG Gadget device + */ + +static void usb_release(struct device *dev) +{ + /* normally not freed */ +} + +static u64 udc_dmamask = ~(u32) 0; +static struct resource otg_udc_resources[] = { + [0] = { + .start = (u32) (&USB_OTGREGS_BASE), + .end = (u32) (&USB_OTGREGS_BASE + 0x1ff), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_USB, + .flags = IORESOURCE_IRQ, + }, +}; + + +struct platform_device otg_udc_device = { + .name = "fsl-usb2-udc", + .id = -1, + .dev = { + .release = usb_release, + .dma_mask = &udc_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &mxc_otg_config, + }, + .resource = otg_udc_resources, + .num_resources = ARRAY_SIZE(otg_udc_resources), +}; + +static int __init udc_init(void) +{ + int rc __attribute((unused)); + + rc = platform_device_register(&otg_udc_device); + if (rc) + printk(KERN_ERR "usb: can't register OTG Gadget, rc=%d\n", rc); + else + printk(KERN_INFO "usb: OTG Gadget registered\n"); + return rc; +} + +subsys_initcall(udc_init); --- /dev/null +++ b/arch/m68k/coldfire/usb/otg_host.c @@ -0,0 +1,68 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define USB_OTGREGS_BASE MCF_REG32(0xFC0B0000) +#define INT_USB (64 + 64 + 47) /* INTC1:47 16.2.9.1 */ +#define INT_UOCSR (64 + 64 + 53) /* INTC1:53 16.2.9.1 */ + +struct platform_device *otg_host_device; + +extern struct platform_device *host_pdev_register(struct resource *res, + int n_res, + struct fsl_usb2_platform_data + *config); + +extern int usbotg_init(struct platform_device *pdev); +extern void usbotg_uninit(struct fsl_usb2_platform_data *pdata); +extern struct fsl_usb2_platform_data mxc_otg_config; + +/*! + * OTG host config + */ +static struct resource otg_host_resources[] = { + [0] = { + .start = (u32) (&USB_OTGREGS_BASE), + .end = (u32) (&USB_OTGREGS_BASE + 0x1ff), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_USB, + .flags = IORESOURCE_IRQ, + }, +}; + +static int __init otg_host_init(void) +{ + otg_host_device = host_pdev_register(otg_host_resources, + ARRAY_SIZE(otg_host_resources), + &mxc_otg_config); + return 0; +} + +subsys_initcall(otg_host_init); --- /dev/null +++ b/arch/m68k/coldfire/usb/otg_otg.c @@ -0,0 +1,96 @@ +/* + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* + * platform_device registration for ULPI OTG device + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define USB_OTGREGS_BASE MCF_REG32(0xFC0B0000) +#define INT_USB (64 + 64 + 47) /* INTC1:47 16.2.9.1 */ +#define INT_UOCSR (64 + 64 + 53) /* INTC1:53 16.2.9.1 */ + +extern int usbotg_init(struct platform_device *pdev); +extern void usbotg_uninit(struct fsl_usb2_platform_data *pdata); +extern struct fsl_usb2_platform_data mxc_otg_config; + +static void otg_otg_release(struct device *dev) +{ + /* normally not freed */ +} + +/* *INDENT-OFF* */ +static struct resource otg_otg_resources[] = { + [0] = { + .start = (u32) (&USB_OTGREGS_BASE), + .end = (u32) (&USB_OTGREGS_BASE + 0x1ff), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_USB, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! + * OTG device + */ +static u64 otg_otg_dmamask = ~(u32) 0; +static struct platform_device otg_otg_device = { + .name = "fsl-usb2-otg", + .id = -1, + .dev = { + .release = otg_otg_release, + .dma_mask = &otg_otg_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &mxc_otg_config, + }, + .resource = otg_otg_resources, + .num_resources = ARRAY_SIZE(otg_otg_resources), +}; +/* *INDENT-ON* */ + +static int __init mx31_otg_otg_init(void) +{ + int rc = 0; + + pr_debug("register OTG otg res=0x%p, size=%d\n", + otg_otg_device.resource, otg_otg_device.num_resources); + + rc = platform_device_register(&otg_otg_device); + if (rc) { + pr_debug("can't register ULPI OTG dvc, %d\n", rc); + } else { + printk(KERN_INFO "usb: OTG ULPI transceiver registered\n"); + pr_debug("otg_otg_device=0x%p resources=0x%p.\n", + &otg_otg_device, otg_otg_device.resource); + } + + return rc; +} + +subsys_initcall(mx31_otg_otg_init); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("ULPI OTG device registration"); +MODULE_LICENSE("GPL"); --- /dev/null +++ b/arch/m68k/coldfire/usb/xcvr.c @@ -0,0 +1,156 @@ +/* + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops); +extern void fsl_usb_xcvr_unregister(enum fsl_usb_ctrlr ctrlr); + +#define MCF_SCM_BCR MCF_REG32(0xFC040024) +#define MCF_SCM_BCR_GBR (1 << 9) /* global bursts for read */ +#define MCF_SCM_BCR_GBW (1 << 8) /* global bursts for write */ +#define MCF_SCM_BCR_SBE_ALL (0xff << 0) /* slave burst enable */ + + +#ifdef ULPI_DEBUG +void print_ulpi_regs(void) +{ + pr_debug("MCF_SCM_BCR=0x%08lx MCF_CCM_MISCCR=0x%08x " + "MCF_GPIO_PAR_DMA=0x%08x MCF_GPIO_PAR_USB=08%08x " + "MCF_GPIO_PAR_FEC=08%08x\n", + MCF_SCM_BCR, MCF_CCM_MISCCR, MCF_GPIO_PAR_DMA, + MCF_GPIO_PAR_USB, MCF_GPIO_PAR_FEC); +} +EXPORT_SYMBOL(print_ulpi_regs); +#endif + + +static void xcvr_init(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_xcvr_ops *this = pdata->xcvr_ops; + struct fsl_usb_host_regs *regs = pdata->regs; + + pr_debug("%s: ctrlr=%d pdata=0x%p regs=0x%p\n", __FUNCTION__, + this->ctrlr, pdata, pdata->regs); + + /* enable USB read, write and slave bursts */ + MCF_SCM_BCR = MCF_SCM_BCR_GBR | MCF_SCM_BCR_GBW | MCF_SCM_BCR_SBE_ALL; + + /* Use external clock source if PLL isn't a multiple of 60MHz */ + MCF_CCM_MISCCR &= ~MCF_CCM_MISCCR_USBSRC; + + /* Initialize the USB Clock: use USB input clock */ + MCF_GPIO_PAR_DMA = (MCF_GPIO_PAR_DMA & MCF_GPIO_PAR_DMA_DREQ1_MASK) | + MCF_GPIO_PAR_DMA_DREQ1_USB_CLKIN; + + switch (this->xcvr_type) { + case PORTSCX_PTS_ULPI: + /* Enable the required ULPI signals */ + MCF_GPIO_PAR_DMA = (MCF_GPIO_PAR_DMA & + MCF_GPIO_PAR_DMA_DACK1_MASK) | + MCF_GPIO_PAR_DMA_DACK1_ULPI_DIR; + + MCF_GPIO_PAR_USB = MCF_GPIO_PAR_USB_VBUSEN_ULPI_NXT | + MCF_GPIO_PAR_USB_VBUSOC_ULPI_STP; + + MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC & + MCF_GPIO_PAR_FEC_FEC0_MASK) | + MCF_GPIO_PAR_FEC_FEC0_RMII_ULPI; + break; + case PORTSCX_PTS_ONCHIP: + /* Enable VBUS_EN and VBUS_OC signals */ + MCF_GPIO_PAR_USB = MCF_GPIO_PAR_USB_VBUSEN_VBUSEN | + MCF_GPIO_PAR_USB_VBUSOC_VBUSOC; + + /* Setup USB_VBUS_OC signal to be active-low */ + MCF_CCM_MISCCR |= MCF_CCM_MISCCR_USBOC; + + break; + } + + pr_debug("®s->portsc1=0x%p old portsc1=0x%x \n", ®s->portsc1, + regs->portsc1); + + regs->portsc1 &= ~PORTSCX_PTS_MASK; + regs->portsc1 |= this->xcvr_type; + + /* + * need to reset the controller here so that the ID pin + * is correctly detected. + */ + regs->usbcmd |= USB_CMD_CTRL_RESET; + + /* + * allow controller to reset, and leave time for + * the ULPI transceiver to reset too. + */ + mdelay(10); + + pr_debug("DDD %s: done. portsc1=0x%x\n", __FUNCTION__, regs->portsc1); +} + +static void xcvr_uninit(struct platform_device *pdev) +{ + pr_debug("%s: pdev=0x%p\n", __FUNCTION__, pdev); +} + + +struct fsl_xcvr_ops xcvr_ops_otg = { + .ctrlr = USB_CTRLR_OTG, + .init = xcvr_init, + .uninit = xcvr_uninit, + +#ifdef CONFIG_USB_M5445X_ULPI + .xcvr_type = PORTSCX_PTS_ULPI, +#elif defined CONFIG_USB_M5445X_FSLS + .xcvr_type = PORTSCX_PTS_ONCHIP, +#else +#error "Invalid USB transceiver selection." +#endif +}; + +static int __init usb_xcvr_init(void) +{ + pr_debug("%s\n", __FUNCTION__); + + fsl_usb_xcvr_register(&xcvr_ops_otg); + + pr_debug("%s done\n", __FUNCTION__); + return 0; +} + +static void __exit usb_xcvr_exit(void) +{ + fsl_usb_xcvr_unregister(USB_CTRLR_OTG); +} + +module_init(usb_xcvr_init); +module_exit(usb_xcvr_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("External ULPI xcvr driver"); +MODULE_LICENSE("GPL"); + --- /dev/null +++ b/arch/m68k/coldfire/usb.c @@ -0,0 +1,182 @@ +/* + * + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * otg_{get,set}_transceiver() are from arm/plat-omap/usb.c. + * which is Copyright (C) 2004 Texas Instruments, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* The dmamask must be set for EHCI to work */ +static u64 ehci_dmamask = ~(u32) 0; + +struct fsl_xcvr_ops *xc_ops[3] = { NULL }; + +void fsl_usb_enable_clk(void) +{ +} +EXPORT_SYMBOL(fsl_usb_enable_clk); + +void fsl_usb_disable_clk(void) +{ +} +EXPORT_SYMBOL(fsl_usb_disable_clk); + +void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops) +{ + pr_debug("%s ctrlr=%d\n", __FUNCTION__, xcvr_ops->ctrlr); + xc_ops[xcvr_ops->ctrlr] = xcvr_ops; + +} +EXPORT_SYMBOL(fsl_usb_xcvr_register); + +void fsl_usb_xcvr_unregister(enum fsl_usb_ctrlr ctrlr) +{ + pr_debug("%s ctrlr=%d\n", __FUNCTION__, ctrlr); + xc_ops[ctrlr] = NULL; +} +EXPORT_SYMBOL(fsl_usb_xcvr_unregister); + +/*! + * Register an instance of a USB host platform device. + * + * @param res: resource pointer + * @param n_res: number of resources + * @param config: config pointer + * + * @return newly-registered platform_device + * + * DDD fix this comment: + * The USB controller supports 3 host interfaces, and the + * kernel can be configured to support some number of them. + * Each supported host interface is registered as an instance + * of the "fsl-ehci" device. Call this function multiple times + * to register each host interface. + */ +static int instance_id; +struct platform_device *host_pdev_register(struct resource *res, int n_res, + struct fsl_usb2_platform_data *config) +{ + struct platform_device *pdev; + + pr_debug("register host res=0x%p, size=%d\n", res, n_res); + + pdev = platform_device_register_simple("fsl-ehci", + instance_id, res, n_res); + if (IS_ERR(pdev)) { + printk(KERN_ERR "usb: can't register %s Host, %ld\n", + config->name, PTR_ERR(pdev)); + return NULL; + } + + pdev->dev.coherent_dma_mask = 0xffffffff; + pdev->dev.dma_mask = &ehci_dmamask; + + /* + * platform_device_add_data() makes a copy of + * the platform_data passed in. That makes it + * impossible to share the same config struct for + * all OTG devices (host,gadget,otg). So, just + * set the platform_data pointer ourselves. + */ + pdev->dev.platform_data = config; + + printk(KERN_INFO "usb: %s Host registered\n", config->name); + pr_debug("pdev=0x%p dev=0x%p resources=0x%p pdata=0x%p\n", + pdev, &pdev->dev, pdev->resource, pdev->dev.platform_data); + + instance_id++; + + return pdev; +} + + +int fsl_usb_mem_init(struct platform_device *pdev) +{ + struct resource *res; + struct fsl_usb2_platform_data *pdata; + + pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; + + pr_debug("%s: pdev=0x%p pdata=0x%p\n", __FUNCTION__, pdev, pdata); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no MEM resource.\n"); + return -ENODEV; + } + + pdata->r_start = res->start; + pdata->r_len = res->end - res->start + 1; + pr_debug("%s: MEM resource start=0x%x len=0x%x\n", pdata->name, + res->start, pdata->r_len); + + if (!request_mem_region(pdata->r_start, pdata->r_len, "OTG")) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + return -EBUSY; + } + pdata->regs = ioremap(pdata->r_start, pdata->r_len); + pr_debug("ioremapped to 0x%p\n", pdata->regs); + + if (pdata->regs == NULL) { + dev_err(&pdev->dev, "ioremap failed\n"); + release_mem_region(pdata->r_start, pdata->r_len); + return -EFAULT; + } + + pr_debug("%s: success\n", __FUNCTION__); + return 0; +} + + +#if defined(CONFIG_USB_OTG) +static struct otg_transceiver *xceiv; + +/** + * otg_get_transceiver - find the (single) OTG transceiver driver + * + * Returns the transceiver driver, after getting a refcount to it; or + * null if there is no such transceiver. The caller is responsible for + * releasing that count. + */ +struct otg_transceiver *otg_get_transceiver(void) +{ + pr_debug("%s xceiv=0x%p\n", __FUNCTION__, xceiv); + if (xceiv) + get_device(xceiv->dev); + return xceiv; +} +EXPORT_SYMBOL(otg_get_transceiver); + +int otg_set_transceiver(struct otg_transceiver *x) +{ + pr_debug("%s xceiv=0x%p x=0x%p\n", __FUNCTION__, xceiv, x); + if (xceiv && x) + return -EBUSY; + xceiv = x; + return 0; +} +EXPORT_SYMBOL(otg_set_transceiver); +#endif --- /dev/null +++ b/arch/m68k/coldfire/vmlinux-cf.lds @@ -0,0 +1,130 @@ +/* ld script to make m68k Coldfire Linux kernel + * + * Derived from arch/m68k/kernel/vmlinux-std.lds + * + * Updated 11/26/2007 for new CodeSourcery toolset + * by Kurt Mahan + */ + +#define LOAD_OFFSET 0x00000000 + +#include +#include + +#define START_OFFSET 0x00020000 +#define IMAGE_START PAGE_OFFSET_RAW + START_OFFSET + +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") +OUTPUT_ARCH(m68k) +ENTRY(_stext) +jiffies = jiffies_64 + 4; + +SECTIONS +{ + . = IMAGE_START; + .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) { + _text = .; /* Text and read-only data */ + *(.text.head) + } :text = 0x4e75 + + .text : AT(ADDR(.text) - LOAD_OFFSET) { + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + *(.fixup) + *(.gnu.warning) + } :text = 0x4e75 + _etext = .; /* End of text section */ + + . = ALIGN(16); + __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 */ + DATA_DATA + CONSTRUCTORS + } :data + + + . = ALIGN(16); + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET ) { + *(.data.cacheline_aligned) + } :data + + _edata = .; /* End of data section */ + + NOTES /* support ld --build-id */ + + . = ALIGN(8192); /* Initrd */ + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { + __init_begin = .; + _sinittext = .; + *(.init.text) + _einittext = .; + } + + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { + *(.init.data) + } + + . = ALIGN(16); + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { + __setup_start = .; + *(.init.setup) + __setup_end = .; + } + + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { + __initcall_start = .; + INITCALLS + __initcall_end = .; + } + + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + } + + SECURITY_INIT + +#ifdef CONFIG_BLK_DEV_INITRD + . = ALIGN(8192); + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } +#endif + + . = ALIGN(8192); + __init_end = .; + + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) /* The initial task and kernel stack */ + } + + _sbss = .; + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { /* BSS */ + *(.bss) + } + _ebss = .; + + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + STABS_DEBUG +} --- /dev/null +++ b/arch/m68k/configs/55_defconfig @@ -0,0 +1,830 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.25 +# Thu Jun 26 16:17:41 2008 +# +CONFIG_M68K=y +CONFIG_MMU=y +# CONFIG_GENERIC_TIME is not set +# CONFIG_GENERIC_CLOCKEVENTS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_TIME_LOW_RES=y +CONFIG_GENERIC_IOMAP=y +# CONFIG_NO_IOPORT is not set +# CONFIG_NO_DMA is not set +CONFIG_ARCH_SUPPORTS_AOUT=y +CONFIG_HZ=100 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_CGROUPS is not set +CONFIG_GROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_RT_GROUP_SCHED is not set +CONFIG_USER_SCHED=y +# CONFIG_CGROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +# CONFIG_HAVE_OPROFILE is not set +# CONFIG_HAVE_KPROBES is not set +# CONFIG_HAVE_KRETPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_CLASSIC_RCU=y + +# +# Platform dependent setup +# +# CONFIG_SUN3 is not set +CONFIG_COLDFIRE=y +CONFIG_CFV4E=y +# CONFIG_AMIGA is not set +# CONFIG_ATARI is not set +# CONFIG_PCI is not set +# CONFIG_MAC is not set +# CONFIG_APOLLO is not set +# CONFIG_VME is not set +# CONFIG_HP300 is not set +# CONFIG_SUN3X is not set +# CONFIG_Q40 is not set + +# +# Processor type +# +# CONFIG_M68020 is not set +# CONFIG_M68030 is not set +# CONFIG_M68040 is not set +# CONFIG_M68060 is not set +CONFIG_M5445X=y +# CONFIG_M54451 is not set +CONFIG_M54455=y +# CONFIG_M54451EVB is not set +CONFIG_M54455EVB=y +# CONFIG_M547X_8X is not set +CONFIG_MCFCLK=266666666 +# CONFIG_MCF_USER_HALT is not set +CONFIG_MMU_CFV4E=y +CONFIG_SDRAM_BASE=0x40000000 +CONFIG_SDRAM_SIZE=0x10000000 +CONFIG_NOR_FLASH_BASE=0x00000000 +# CONFIG_M68KFPU_EMU is not set +CONFIG_ADVANCED=y +# CONFIG_RMW_INSNS is not set +CONFIG_SINGLE_MEMORY_CHUNK=y +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +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_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y + +# +# General setup +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_PROC_HARDWARE=y +CONFIG_ZONE_DMA=y +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# 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=y +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# 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_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=64000 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_COLDFIRE_SEC is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_B44 is not set +CONFIG_FEC=y +# CONFIG_FEC2 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_COLDFIRE=y +# CONFIG_SERIAL_MCF is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_MCF548x is not set +CONFIG_I2C_MCF=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_TPS65010 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_COLDFIRE_EDMA is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_RTC_CLASS is not set + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# Character devices +# +# CONFIG_SERIAL_CONSOLE is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +CONFIG_FS_MBCACHE=y +# 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_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_DNOTIFY=y +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA 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=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE 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_MINIX_FS=y +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 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_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# 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 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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=y +# 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=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SLAB_LEAK is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SAMPLES is not set +CONFIG_BOOTPARAM=y +CONFIG_BOOTPARAM_STRING="root=/dev/nfs rw nfsroot=172.27.155.1:/tftpboot/redstripe ip=172.27.155.55:172.27.155.1:172.27.255.254:255.255.0.0::eth0:off mtdparts=phys_mapped_flash:16m(User)" + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_BLKCIPHER=y +# CONFIG_CRYPTO_SEQIV is not set +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=m +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_MCFCAU is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y --- /dev/null +++ b/arch/m68k/configs/m54455evb_defconfig @@ -0,0 +1,1037 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23 +# Thu Dec 6 12:14:18 2007 +# +CONFIG_M68K=y +CONFIG_MMU=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_TIME_LOW_RES=y +CONFIG_GENERIC_IOMAP=y +CONFIG_NO_IOPORT=y +# CONFIG_NO_DMA is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# +# Platform dependent setup +# +# CONFIG_SUN3 is not set +CONFIG_COLDFIRE=y +CONFIG_CFV4E=y +# CONFIG_AMIGA is not set +# CONFIG_ATARI is not set +# CONFIG_MAC is not set +# CONFIG_APOLLO is not set +# CONFIG_VME is not set +# CONFIG_HP300 is not set +# CONFIG_SUN3X is not set +# CONFIG_Q40 is not set + +# +# Processor type +# +# CONFIG_M68020 is not set +# CONFIG_M68030 is not set +# CONFIG_M68040 is not set +# CONFIG_M68060 is not set +CONFIG_M54455=y +CONFIG_MCFCLK=266666666 +# CONFIG_MCF_USER_HALT is not set +CONFIG_MMU_CFV4E=y +CONFIG_SDRAM_BASE=0x40000000 +CONFIG_SDRAM_SIZE=0x0FFFFFFF +CONFIG_NOR_FLASH_BASE=0x00000000 +# CONFIG_M68KFPU_EMU is not set +CONFIG_ADVANCED=y +# CONFIG_RMW_INSNS is not set +CONFIG_SINGLE_MEMORY_CHUNK=y +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +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_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y + +# +# General setup +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_PROC_HARDWARE=y +CONFIG_ZONE_DMA=y +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# 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=y +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# 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_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_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=0 +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +# CONFIG_MTD_CFI_I2 is not set +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x00000000 +CONFIG_MTD_PHYSMAP_LEN=0x1000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=1 +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=64000 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_ATA=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_PATA_FSL=m +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_FEC=y +# CONFIG_FEC2 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET_MII=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# 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 +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_COLDFIRE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_COLDFIRE_EDMA=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +CONFIG_SPI_COLDFIRE=y +CONFIG_SPI_COLDFIRE_DSPI_EDMA=y + +# +# SPI Protocol Masters +# +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +CONFIG_SPI_COLDFIRE_SSI_AUDIO=y +# CONFIG_SSIAUDIO_USE_EDMA is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y +# CONFIG_USB_DABUSB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +CONFIG_HID_DEBUG=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y +CONFIG_USB_EHCI_BIG_ENDIAN_DESC=y +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +CONFIG_USB_M5445X_ULPI=y +# CONFIG_USB_M5445X_FSLS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MON is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_M66592 is not set +CONFIG_USB_GADGET_MCF5445X=y +CONFIG_USB_MCF5445X=m +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +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 is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# Character devices +# +# CONFIG_SERIAL_CONSOLE is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# 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_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# 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=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# 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_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN 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 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_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# 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 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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=y +# 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=y + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SLAB_LEAK is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_BOOTPARAM=y +CONFIG_BOOTPARAM_STRING="root=/dev/nfs rw nfsroot=172.27.155.1:/tftpboot/redstripe ip=172.27.155.55:172.27.155.1:172.27.255.254:255.255.0.0::eth0:off mtdparts=phys_mapped_flash:16m(User)" + +# +# CodeTEST Setup +# +# CONFIG_CODETEST is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=m +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_MCFCAU=y +CONFIG_CRYPTO_DEV_MCFCAU_DES=y +CONFIG_CRYPTO_DEV_MCFCAU_AES=y +CONFIG_CRYPTO_DEV_MCFCAU_MD5=y +CONFIG_CRYPTO_DEV_MCFCAU_SHA1=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y --- /dev/null +++ b/arch/m68k/configs/m5475evb_defconfig @@ -0,0 +1,954 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.25 +# Wed Jul 9 16:09:19 2008 +# +CONFIG_M68K=y +CONFIG_MMU=y +# CONFIG_GENERIC_TIME is not set +# CONFIG_GENERIC_CLOCKEVENTS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_TIME_LOW_RES=y +CONFIG_GENERIC_IOMAP=y +# CONFIG_NO_IOPORT is not set +# CONFIG_NO_DMA is not set +CONFIG_ARCH_SUPPORTS_AOUT=y +CONFIG_HZ=100 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_CGROUPS is not set +CONFIG_GROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_RT_GROUP_SCHED is not set +CONFIG_USER_SCHED=y +# CONFIG_CGROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +# CONFIG_HAVE_OPROFILE is not set +# CONFIG_HAVE_KPROBES is not set +# CONFIG_HAVE_KRETPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_CLASSIC_RCU=y + +# +# Platform dependent setup +# +# CONFIG_SUN3 is not set +CONFIG_COLDFIRE=y +CONFIG_CFV4E=y +CONFIG_MCD_DMA=y +# CONFIG_AMIGA is not set +# CONFIG_ATARI is not set +CONFIG_PCI=y +# CONFIG_MAC is not set +# CONFIG_APOLLO is not set +# CONFIG_VME is not set +# CONFIG_HP300 is not set +# CONFIG_SUN3X is not set +# CONFIG_Q40 is not set + +# +# Processor type +# +# CONFIG_M68020 is not set +# CONFIG_M68030 is not set +# CONFIG_M68040 is not set +# CONFIG_M68060 is not set +# CONFIG_M5445X is not set +CONFIG_M547X_8X=y +CONFIG_M547X=y +# CONFIG_M548X is not set +# CONFIG_M5475AFE is not set +# CONFIG_M5475BFE is not set +CONFIG_M5475CFE=y +# CONFIG_M5475DFE is not set +# CONFIG_M5475EFE is not set +# CONFIG_M5475FFE is not set +# CONFIG_M5485AFE is not set +# CONFIG_M5485BFE is not set +# CONFIG_M5485CFE is not set +# CONFIG_M5485DFE is not set +# CONFIG_M5485EFE is not set +# CONFIG_M5485FFE is not set +CONFIG_MCFCLK=266000000 +# CONFIG_MCF_USER_HALT is not set +CONFIG_MMU_CFV4E=y +CONFIG_SDRAM_BASE=0x00000000 +CONFIG_SDRAM_SIZE=0x04000000 +CONFIG_NOR_FLASH_BASE=0xE0000000 +# CONFIG_M68KFPU_EMU is not set +CONFIG_ADVANCED=y +# CONFIG_RMW_INSNS is not set +CONFIG_SINGLE_MEMORY_CHUNK=y +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +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_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y + +# +# General setup +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_PROC_HARDWARE=y +CONFIG_ZONE_DMA=y +# CONFIG_ARCH_SUPPORTS_MSI is not set +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_DEBUG is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# 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=y +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# 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_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +CONFIG_CAN=y +CONFIG_CAN_RAW=y +# CONFIG_CAN_BCM is not set + +# +# CAN Device Drivers +# +# CONFIG_CAN_VCAN is not set +CONFIG_CAN_FLEXCAN=y +CONFIG_CAN_MCF547X_8X=y +# CONFIG_CAN_DEBUG_DEVICES is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +# CONFIG_MTD_CHAR is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_RAM=y +CONFIG_MTD_ROM=y +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=64000 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +CONFIG_COLDFIRE_SEC=y +CONFIG_SEC_DEVICE=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ENCLOSURE_SERVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_ARCNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_FEC_548x=y +CONFIG_FEC_548x_AUTO_NEGOTIATION=y +# CONFIG_FEC_548x_ENABLE_FEC2 is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_ENC28J60 is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_NET_PCI is not set +# CONFIG_B44 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_COLDFIRE=y +CONFIG_SERIAL_COLDFIRE_IRDA=y +# CONFIG_SERIAL_MCF is not set +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +CONFIG_SPI=y +CONFIG_SPI_DEBUG=y +# CONFIG_COLDFIRE_EDMA is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +CONFIG_SPI_COLDFIRE=y + +# +# SPI Protocol Masters +# +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_COLDFIRE_SSI_AUDIO is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_COLDFIRE_WATCHDOG=m + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +CONFIG_HID_DEBUG=y +# CONFIG_HIDRAW is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +# CONFIG_RTC_CLASS is not set + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# Character devices +# +# CONFIG_SERIAL_CONSOLE is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +CONFIG_FS_MBCACHE=y +# 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_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_DNOTIFY=y +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA 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=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE 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_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 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_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# 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 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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=y +# 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=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SLAB_LEAK is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SAMPLES is not set +CONFIG_BOOTPARAM=y +CONFIG_BOOTPARAM_STRING="root=/dev/nfs rw nfsroot=172.27.163.2:/tftpboot/ltib ip=172.27.163.3:172.27.163.2:172.27.255.254:255.255.0.0::eth0:off mtdparts=phys_mapped_flash:16m(User)" + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_BLKCIPHER=y +# CONFIG_CRYPTO_SEQIV is not set +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_ECB is not set +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_HW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y --- /dev/null +++ b/arch/m68k/configs/m5485evb_defconfig @@ -0,0 +1,859 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.25 +# Thu Jul 10 16:12:53 2008 +# +CONFIG_M68K=y +CONFIG_MMU=y +# CONFIG_GENERIC_TIME is not set +# CONFIG_GENERIC_CLOCKEVENTS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_TIME_LOW_RES=y +CONFIG_GENERIC_IOMAP=y +# CONFIG_NO_IOPORT is not set +# CONFIG_NO_DMA is not set +CONFIG_ARCH_SUPPORTS_AOUT=y +CONFIG_HZ=100 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_CGROUPS is not set +CONFIG_GROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_RT_GROUP_SCHED is not set +CONFIG_USER_SCHED=y +# CONFIG_CGROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +# CONFIG_HAVE_OPROFILE is not set +# CONFIG_HAVE_KPROBES is not set +# CONFIG_HAVE_KRETPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_CLASSIC_RCU=y + +# +# Platform dependent setup +# +# CONFIG_SUN3 is not set +CONFIG_COLDFIRE=y +CONFIG_CFV4E=y +CONFIG_MCD_DMA=y +# CONFIG_AMIGA is not set +# CONFIG_ATARI is not set +# CONFIG_MAC is not set +# CONFIG_APOLLO is not set +# CONFIG_VME is not set +# CONFIG_HP300 is not set +# CONFIG_SUN3X is not set +# CONFIG_Q40 is not set + +# +# Processor type +# +# CONFIG_M68020 is not set +# CONFIG_M68030 is not set +# CONFIG_M68040 is not set +# CONFIG_M68060 is not set +# CONFIG_M5445X is not set +CONFIG_M547X_8X=y +# CONFIG_M547X is not set +CONFIG_M548X=y +# CONFIG_M5475AFE is not set +# CONFIG_M5475BFE is not set +# CONFIG_M5475CFE is not set +# CONFIG_M5475DFE is not set +# CONFIG_M5475EFE is not set +# CONFIG_M5475FFE is not set +# CONFIG_M5485AFE is not set +# CONFIG_M5485BFE is not set +CONFIG_M5485CFE=y +# CONFIG_M5485DFE is not set +# CONFIG_M5485EFE is not set +# CONFIG_M5485FFE is not set +CONFIG_MCFCLK=200000000 +# CONFIG_MCF_USER_HALT is not set +CONFIG_MMU_CFV4E=y +CONFIG_SDRAM_BASE=0x00000000 +CONFIG_SDRAM_SIZE=0x04000000 +CONFIG_NOR_FLASH_BASE=0xE0000000 +# CONFIG_M68KFPU_EMU is not set +CONFIG_ADVANCED=y +# CONFIG_RMW_INSNS is not set +CONFIG_SINGLE_MEMORY_CHUNK=y +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +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_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y + +# +# General setup +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_PROC_HARDWARE=y +CONFIG_ZONE_DMA=y +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# 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=y +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# 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_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=64000 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +CONFIG_COLDFIRE_SEC=y +CONFIG_SEC_DEVICE=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_FEC_548x=y +CONFIG_FEC_548x_AUTO_NEGOTIATION=y +# CONFIG_FEC_548x_ENABLE_FEC2 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_B44 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_COLDFIRE=y +# CONFIG_SERIAL_COLDFIRE_IRDA is not set +# CONFIG_SERIAL_MCF is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +CONFIG_I2C_MCF548x=y +# CONFIG_I2C_MCF is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_TPS65010 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +CONFIG_SPI_DEBUG=y +# CONFIG_COLDFIRE_EDMA is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +CONFIG_SPI_COLDFIRE=y + +# +# SPI Protocol Masters +# +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_COLDFIRE_SSI_AUDIO is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +CONFIG_HID_DEBUG=y +# CONFIG_HIDRAW is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_RTC_CLASS is not set + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# Character devices +# +# CONFIG_SERIAL_CONSOLE is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +CONFIG_FS_MBCACHE=y +# 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_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_DNOTIFY=y +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA 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=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE 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_MINIX_FS=y +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 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_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# 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 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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=y +# 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=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SLAB_LEAK is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SAMPLES is not set +CONFIG_BOOTPARAM=y +CONFIG_BOOTPARAM_STRING="root=/dev/nfs rw nfsroot=172.27.163.2:/tftpboot/ltib ip=172.27.163.3:172.27.163.2:172.27.255.254:255.255.0.0::eth0:off mtdparts=phys_mapped_flash:16m(User)" + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_BLKCIPHER=y +# CONFIG_CRYPTO_SEQIV is not set +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_ECB is not set +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_HW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -11,6 +11,14 @@ config MMU bool default y +config GENERIC_TIME + bool + default n + +config GENERIC_CLOCKEVENTS + bool + default n + config RWSEM_GENERIC_SPINLOCK bool default y @@ -48,7 +56,7 @@ config ARCH_MAY_HAVE_PC_FDC default y config NO_IOPORT - def_bool y + def_bool !(M5445X || M547X_8X) config NO_DMA def_bool SUN3 @@ -119,6 +127,29 @@ config SUN3 If you don't want to compile a kernel exclusively for a Sun 3, say N. +config COLDFIRE + bool "ColdFire V4e support" + default y + select CFV4E + help + Say Y if you want to build a kernel to run on one of the ColdFire + V4e boards. + +config CFV4E + bool + depends on COLDFIRE + select MMU_CFV4E if MMU + default y + +config MCD_DMA + bool "ColdFire MCD DMA support" + depends on M547X_8X + default y + help + This enables support for the ColdFire 547x/548x family + multichannel DMA support. Many drivers need it. + If you want it, say Y + config AMIGA bool "Amiga support" depends on !MMU_SUN3 @@ -144,9 +175,9 @@ config HADES to use this kernel on a Hades, say Y here; otherwise say N. config PCI - bool - depends on HADES - default y + bool "PCI bus support" + depends on HADES || M54455 || M547X_8X + default n help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside @@ -294,14 +325,142 @@ config M68060 If you anticipate running this kernel on a computer with a MC68060 processor, say Y. Otherwise, say N. +config M5445X + bool "MCF5445x support" + depends on COLDFIRE + help + This option will add support for the MCF5445 processor with mmu. + +config M54451 + bool + depends on M5445X + default n + +config M54455 + bool + depends on M5445X + default n + +choice + prompt "Model" + depends on M5445X + default M54451EVB + config M54451EVB + bool "M54451EVB" + select M54451 + config M54455EVB + bool "M54455EVB" + select M54455 +endchoice + + +config M547X_8X + bool "MCF547x/MCF548x support" + depends on COLDFIRE + help + This option will add support for the MCF547x/MCF548x processor with mmu. + +config M547X + bool + depends on M547X_8X + default n + +config M548X + bool + depends on M547X_8X + default n + +choice + prompt "Model" + depends on M547X_8X + default M5485CFE + config M5475AFE + bool "MCF5475AFE" + select M547X + config M5475BFE + bool "MCF5475BFE" + select M547X + config M5475CFE + bool "MCF5475CFE" + select M547X + config M5475DFE + bool "MCF5475DFE" + select M547X + config M5475EFE + bool "MCF5475EFE" + select M547X + config M5475FFE + bool "MCF5475FFE" + select M547X + + config M5485AFE + bool "MCF5485AFE" + select M548X + config M5485BFE + bool "MCF5485BFE" + select M548X + config M5485CFE + bool "MCF5485CFE" + select M548X + config M5485DFE + bool "MCF5485DFE" + select M548X + config M5485EFE + bool "MCF5485EFE" + select M548X + config M5485FFE + bool "MCF5485FFE" + select M548X + +endchoice + +config MCFCLK + int + default 266666666 if M54455EVB + default 240000000 if M54451EVB + default 266000000 if M547X + default 200000000 if M548X + help + Coldfire System clock. + +config MCF_USER_HALT + bool "Coldfire User Halt Enable" + depends on M5445X || M547X_8X + default n + help + Enables the HALT instruction in User Mode. + config MMU_MOTOROLA bool - depends on MMU && !MMU_SUN3 + depends on MMU && !MMU_SUN3 && !COLDFIRE default y config MMU_SUN3 bool +config MMU_CFV4E + bool + +config SDRAM_BASE + hex + depends on COLDFIRE + default 0x40000000 if M5445X + default 0x00000000 if M547X_8X + +config SDRAM_SIZE + hex + depends on COLDFIRE + default 0x08000000 if M54451EVB + default 0x10000000 if M54455EVB + default 0x04000000 if M547X_8X + +config NOR_FLASH_BASE + hex "NOR Flash Base Address" + depends on COLDFIRE + default 0x00000000 if M54451EVB + default 0x00000000 if M54455EVB + default 0xE0000000 if M547X_8X + config M68KFPU_EMU bool "Math emulation support (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -468,6 +627,14 @@ config ZONE_DMA source "drivers/pci/Kconfig" source "drivers/zorro/Kconfig" +endmenu + +menu "Power management options" + +config PM + bool "Power Management support" + help + Support processor power management modes endmenu @@ -647,7 +814,7 @@ config DN_SERIAL config SERIAL_CONSOLE bool "Support for serial port console" - depends on (AMIGA || ATARI || MAC || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL) + depends on (AMIGA || ATARI || MAC || SUN3 || SUN3X || VME || APOLLO || COLDFIRE) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL || SERIAL_COLDFIRE) ---help--- If you say Y here, it will be possible to use a serial port as the system console (the system console is the device which receives all --- a/arch/m68k/Kconfig.debug +++ b/arch/m68k/Kconfig.debug @@ -2,4 +2,13 @@ menu "Kernel hacking" source "lib/Kconfig.debug" +config BOOTPARAM + bool 'Compiled-in Kernel Boot Parameter' + depends on COLDFIRE + +config BOOTPARAM_STRING + string 'Kernel Boot Parameter' + default 'console=ttyS0,115200' + depends on BOOTPARAM + endmenu --- a/arch/m68k/kernel/asm-offsets.c +++ b/arch/m68k/kernel/asm-offsets.c @@ -58,8 +58,15 @@ int main(void) DEFINE(PT_A2, offsetof(struct pt_regs, a2)); DEFINE(PT_PC, offsetof(struct pt_regs, pc)); DEFINE(PT_SR, offsetof(struct pt_regs, sr)); +#ifdef CONFIG_COLDFIRE + /* Need to get the context out of struct mm for ASID setting */ + DEFINE(MM_CONTEXT, offsetof(struct mm_struct, context)); + /* Coldfire exception frame has vector *before* pc */ + DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) - 4); +#else /* bitfields are a bit difficult */ DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4); +#endif /* offsets into the irq_handler struct */ DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler)); --- /dev/null +++ b/arch/m68k/kernel/bios32_mcf548x.c @@ -0,0 +1,631 @@ +/* + * bios32.c - PCI BIOS functions for m68k systems. + * + * Written by Wout Klaren. + * + * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger. + */ +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#ifdef CONFIG_PCI + +/* + * PCI support for Linux/m68k. Currently only the Hades is supported. + * + * The support for PCI bridges in the DEC Alpha version has + * been removed in this version. + */ + +#include +#include +#include + +#include +#include +#include + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +#define MAJOR_REV 0 +#define MINOR_REV 5 + +/* + * Align VAL to ALIGN, which must be a power of two. + */ + +#define MAX(val1, val2) (((val1) > (val2)) ? val1 : val2) + +/* + * Offsets relative to the I/O and memory base addresses from where resources + * are allocated. + */ + +#ifdef CONFIG_COLDFIRE +#define IO_ALLOC_OFFSET 0x00000100 +#define MEM_ALLOC_OFFSET 0x00000000 +#else /* CONFIG_COLDFIRE */ +#define IO_ALLOC_OFFSET 0x00004000 +#define MEM_ALLOC_OFFSET 0x04000000 +#endif /* CONFIG_COLDFIRE */ + +/* + * Declarations of hardware specific initialisation functions. + */ + +extern struct pci_bus_info *init_hades_pci(void); + +/* + * Bus info structure of the PCI bus. A pointer to this structure is + * put in the sysdata member of the pci_bus structure. + */ + +static struct pci_bus_info *bus_info; + +static int pci_modify = 1; /* If set, layout the PCI bus ourself. */ +static int skip_vga; /* If set do not modify base addresses + of vga cards.*/ +static int disable_pci_burst; /* If set do not allow PCI bursts. */ + +static unsigned int io_base; +static unsigned int mem_base; + +/* + * static void disable_dev(struct pci_dev *dev) + * + * Disable PCI device DEV so that it does not respond to I/O or memory + * accesses. + * + * Parameters: + * + * dev - device to disable. + */ + +static void __init disable_dev(struct pci_dev *dev) +{ + unsigned short cmd; + + if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) || + (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) || + (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga) + return; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + + cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); + pci_write_config_word(dev, PCI_COMMAND, cmd); +} + +/* Stolen from pcibios_enable_resources/i386 */ +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1<resource[idx]; + if (!r->start && r->end) { + printk("PCI: Device %s not available because" + " of resource collisions\n", dev->dev.bus_id); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->dev.bus_id, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +/* + * static void layout_dev(struct pci_dev *dev) + * + * Layout memory and I/O for a device. + * + * Parameters: + * + * device - device to layout memory and I/O for. + */ + +static void __init layout_dev(struct pci_dev *dev) +{ + unsigned short cmd; + unsigned int base, mask, size, reg; + unsigned int alignto; + int i; + + /* + * Skip video cards if requested. + */ + if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) || + (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) || + (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga){ + printk("%s: VGA\n",__FUNCTION__); + return; + } + pci_read_config_word(dev, PCI_COMMAND, &cmd); + + for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++) + { + /* + * Figure out how much space and of what type this + * device wants. + */ + + pci_write_config_dword(dev, reg, 0xffffffff); + pci_read_config_dword(dev, reg, &base); + if (!base) + { + /* this base-address register is unused */ + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + continue; + } + + /* + * We've read the base address register back after + * writing all ones and so now we must decode it. + */ + + if (base & PCI_BASE_ADDRESS_SPACE_IO) + { + /* + * I/O space base address register. + */ + + cmd |= PCI_COMMAND_IO; + + base &= PCI_BASE_ADDRESS_IO_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + + /* + * Align to multiple of size of minimum base. + */ + +#ifdef CONFIG_COLDFIRE + alignto = MAX(PAGE_SIZE, size) ; +#else /* CONFIG_COLDFIRE */ + alignto = MAX(0x040, size) ; +#endif /* CONFIG_COLDFIRE */ + base = ALIGN(io_base, alignto); + io_base = base + size; + pci_write_config_dword(dev, reg, base | PCI_BASE_ADDRESS_SPACE_IO); + + dev->resource[i].start = base; + dev->resource[i].end = dev->resource[i].start + size - 1; + dev->resource[i].flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO; + + DBG_DEVS(("layout_dev: IO address: %x\n", base)); + } + else + { + unsigned int type; + + /* + * Memory space base address register. + */ + + cmd |= PCI_COMMAND_MEMORY; + type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK; + base &= PCI_BASE_ADDRESS_MEM_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + switch (type) + { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + case PCI_BASE_ADDRESS_MEM_TYPE_64: + break; + + case PCI_BASE_ADDRESS_MEM_TYPE_1M: + printk("bios32 WARNING: slot %d, function %d " + "requests memory below 1MB---don't " + "know how to do that.\n", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + continue; + } + DBG_DEVS(("%s MEM: base %x,type %x,mask %x,size %x\n", + __FUNCTION__, base, type, mask, size)); + /* + * Align to multiple of size of minimum base. + */ + + alignto = max_t(unsigned int, 0x1000, size); + base = ALIGN(mem_base, alignto); + mem_base = base + size; + pci_write_config_dword(dev, reg, base); + + dev->resource[i].start = base; + dev->resource[i].end = dev->resource[i].start + size - 1; + dev->resource[i].flags = IORESOURCE_MEM; + DBG_DEVS(("%s MEM :base %x,size %x\n", + __FUNCTION__, base, size)); + if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) + { + /* + * 64-bit address, set the highest 32 bits + * to zero. + */ + + reg += 4; + pci_write_config_dword(dev, reg, 0); + + i++; + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + printk("%s:type == 64\n",__FUNCTION__); + } + } + } + + /* + * Enable device: + */ + + if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED || + dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) + { + /* + * All of these (may) have I/O scattered all around + * and may not use i/o-base address registers at all. + * So we just have to always enable I/O to these + * devices. + */ + cmd |= PCI_COMMAND_IO; + } + + pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); + + pci_write_config_byte(dev, PCI_LATENCY_TIMER, (disable_pci_burst) ? 0 : 32); + + if (bus_info != NULL) + bus_info->conf_device(dev); /* Machine dependent configuration. */ + + printk(KERN_INFO "layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n", + dev->bus->number, PCI_SLOT(dev->devfn), + dev->vendor, dev->device, dev->class); +} + +/* + * static void layout_bus(struct pci_bus *bus) + * + * Layout memory and I/O for all devices on the given bus. + * + * Parameters: + * + * bus - bus. + */ + +static void __init layout_bus(struct pci_bus *bus) +{ + unsigned int bio, bmem; + struct pci_dev *dev; + + DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); + + if (list_empty(&bus->devices) && list_empty(&bus->children)) + return; + + /* + * Align the current bases on appropriate boundaries (4K for + * IO and 1MB for memory). + */ + + bio = io_base = ALIGN(io_base, 4*KB); + bmem = mem_base = ALIGN(mem_base, 1*MB); + + /* + * PCI devices might have been setup by a PCI BIOS emulation + * running under TOS. In these cases there is a + * window during which two devices may have an overlapping + * address range. To avoid this causing trouble, we first + * turn off the I/O and memory address decoders for all PCI + * devices. They'll be re-enabled only once all address + * decoders are programmed consistently. + */ + + DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number)); + +#ifdef NL_ORIGINAL + for (dev = bus->devices; dev; dev = dev->sibling) +#else + dev = NULL; + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) +#endif + { + if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || + (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) + disable_dev(dev); + } + + /* + * Allocate space to each device: + */ + + DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number)); + +#ifdef NL_ORIGINAL + for (dev = bus->devices; dev; dev = dev->sibling) +#else + dev = NULL; + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) +#endif + { + if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || + (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) + layout_dev(dev); + } + + DBG_DEVS(("layout_bus: bus %d finished\n", bus->number)); +} + +/* + * static void pcibios_fixup(void) + * + * Layout memory and I/O of all devices on the PCI bus if 'pci_modify' is + * true. This might be necessary because not every m68k machine with a PCI + * bus has a PCI BIOS. This function should be called right after + * pci_scan_bus() in pcibios_init(). + */ + +static void __init pcibios_fixup(void) +{ + DBG_DEVS(("%s\n", __FUNCTION__)); + if (pci_modify) + { + /* + * Set base addresses for allocation of I/O and memory space. + */ + + io_base = bus_info->io_space.start + IO_ALLOC_OFFSET; + mem_base = bus_info->mem_space.start + MEM_ALLOC_OFFSET; + + /* + * Scan the tree, allocating PCI memory and I/O space. + */ + +#ifdef NL_ORIGINAL + layout_bus(pci_bus_b(pci_root.next)); +#else + layout_bus(pci_bus_b(pci_root_buses.next)); +#endif + } + + /* + * Fix interrupt assignments, etc. + */ + + bus_info->fixup(pci_modify); +} + +/* + * static void pcibios_claim_resources(struct pci_bus *bus) + * + * Claim all resources that are assigned to devices on the given bus. + * + * Parameters: + * + * bus - bus. + */ + +static void __init pcibios_claim_resources(struct pci_bus *bus) +{ + struct pci_dev *dev; + int i; + DBG_DEVS(("%s\n", __FUNCTION__)); +#ifdef NL_ORIGINAL + while (bus) +#else + while ((bus = pci_find_next_bus(bus)) != NULL) +#endif + { + +#ifdef NL_ORIGINAL + for (dev = bus->devices; (dev != NULL); dev = dev->sibling) +#else + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) +#endif + { + for (i = 0; i < PCI_NUM_RESOURCES; i++) + { + struct resource *r = &dev->resource[i]; + struct resource *pr; + struct pci_bus_info *bus_info = + (struct pci_bus_info *) dev->sysdata; + + if ((r->start == 0) || (r->parent != NULL)) + continue; + +#ifdef CONFIG_COLDFIRE + if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) + continue; +#endif /* CONFIG_COLDFIRE */ +#if 1 + if (r->flags & IORESOURCE_IO) + pr = &bus_info->io_space; + else + pr = &bus_info->mem_space; +#else + if (r->flags & IORESOURCE_IO) + pr = &ioport_resource; + else + pr = &iomem_resource; +#endif + if (request_resource(pr, r) < 0) + { +#ifdef NL_ORIGINAL + DBG_DEVS(("PCI: Address space collision on " + "region %d of device %s\n", i, dev->name)); +#else + printk("PCI: Address space collision on region %d of device %s\n", i, dev->dev.bus_id); +#endif + } + } + } + +#ifdef NL_ORIGINAL + if (bus->children) + pcibios_claim_resources(bus->children); +#else + if (!list_empty(&bus->children)) + pcibios_claim_resources(pci_bus_b(bus->children.next)); +#endif + +#ifdef NL_ORIGINAL + bus = bus->next; +#endif + } +} + +/* + * int pcibios_assign_resource(struct pci_dev *dev, int i) + * + * Assign a new address to a PCI resource. + * + * Parameters: + * + * dev - device. + * i - resource. + * + * Result: 0 if successful. + */ + +int __init pcibios_assign_resource(struct pci_dev *dev, int i) +{ + struct resource *r = &dev->resource[i]; + struct resource *pr = pci_find_parent_resource(dev, r); + unsigned long size = r->end + 1; + DBG_DEVS(("%s:IO_ALLOC_OFFSET %x\n", __FUNCTION__, IO_ALLOC_OFFSET)); + if (!pr) + return -EINVAL; + + if (r->flags & IORESOURCE_IO) + { + DBG_DEVS(("%s:IORESOURCE_IO:start %x, size %lx\n", + __FUNCTION__, bus_info->io_space.start, size)); + if (size > 0x100) + return -EFBIG; + +#ifdef NL_ORIGINAL + if (allocate_resource(pr, r, size, bus_info->io_space.start + + IO_ALLOC_OFFSET, bus_info->io_space.end, 1024)) +#else + if (allocate_resource(pr, r, size, bus_info->io_space.start + + IO_ALLOC_OFFSET, bus_info->io_space.end, 1024, NULL, NULL)) +#endif + return -EBUSY; + } + else + { + DBG_DEVS(("%s:IORESOURCE_MEM:start %x, size %lx\n", + __FUNCTION__, bus_info->mem_space.start, size)); +#ifdef NL_ORIGINAL + if (allocate_resource(pr, r, size, bus_info->mem_space.start + + MEM_ALLOC_OFFSET, bus_info->mem_space.end, size)) +#else + if (allocate_resource(pr, r, size, bus_info->io_space.start + + IO_ALLOC_OFFSET, bus_info->io_space.end, 1024, NULL, NULL)) +#endif + return -EBUSY; + } + + if (i < 6) + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, r->start); + + return 0; +} + +void pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev; + void *sysdata; + + sysdata = (bus->parent) ? bus->parent->sysdata : bus->sysdata; + +#ifdef NL_ORIGINAL + for (dev = bus->devices; (dev != NULL); dev = dev->sibling) +#else + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) +#endif + dev->sysdata = sysdata; +} + +int __init pcibios_init(void) +{ + printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); + + bus_info = NULL; +#ifdef CONFIG_COLDFIRE + bus_info = init_coldfire_pci(); +#endif /* CONFIG_COLDFIRE */ +#ifdef CONFIG_HADES + if (MACH_IS_HADES) + bus_info = init_hades_pci(); +#endif + if (bus_info != NULL) + { + printk("PCI: Probing PCI hardware\n"); + pci_scan_bus(0, bus_info->m68k_pci_ops, bus_info); + pcibios_fixup(); +#ifdef NL_ORIGINAL + pcibios_claim_resources(pci_root); +#else + pcibios_claim_resources(pci_bus_b(pci_root_buses.next)); +#endif + } + else + printk("PCI: No PCI bus detected\n"); + return 0; +} + +subsys_initcall(pcibios_init); + +char * pcibios_setup(char *str) +{ + if (!strcmp(str, "nomodify")) + { + pci_modify = 0; + return NULL; + } + else if (!strcmp(str, "skipvga")) + { + skip_vga = 1; + return NULL; + } + else if (!strcmp(str, "noburst")) + { + disable_pci_burst = 1; + return NULL; + } + + return str; +} +#endif /* CONFIG_PCI */ --- a/arch/m68k/kernel/dma.c +++ b/arch/m68k/kernel/dma.c @@ -11,12 +11,24 @@ #include #include #include - +#include #include void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t flag) { +#if defined(CONFIG_M547X_8X) | defined(CONFIG_M54455) + /* + * On the M5445x platform the memory allocated with GFP_DMA + * is guaranteed to be DMA'able. + */ + void *addr; + + size = PAGE_ALIGN(size); + addr = kmalloc(size, GFP_DMA); + *handle = virt_to_phys(addr); + return addr; +#else struct page *page, **map; pgprot_t pgprot; void *addr; @@ -55,6 +67,7 @@ void *dma_alloc_coherent(struct device * kfree(map); return addr; +#endif } EXPORT_SYMBOL(dma_alloc_coherent); @@ -62,7 +75,11 @@ void dma_free_coherent(struct device *de void *addr, dma_addr_t handle) { pr_debug("dma_free_coherent: %p, %x\n", addr, handle); +#if defined(CONFIG_M547X_8X) | defined(CONFIG_M54455) + kfree(addr); +#else vfree(addr); +#endif } EXPORT_SYMBOL(dma_free_coherent); --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -2,19 +2,27 @@ # Makefile for the linux kernel. # -ifndef CONFIG_SUN3 - extra-y := head.o +ifdef CONFIG_SUN3 + extra-y := sun3-head.o vmlinux.lds + obj-y := entry.o signal.o ints.o else - extra-y := sun3-head.o +ifndef CONFIG_COLDFIRE + extra-y := head.o vmlinux.lds + obj-y := entry.o signal.o traps.o ints.o + obj-$(CONFIG_PCI) += bios32.o +else # CONFIG_COLDFIRE + extra-y := ../coldfire/head.o vmlinux.lds +ifdef CONFIG_M547X_8X + obj-$(CONFIG_PCI) += bios32_mcf548x.o +endif +endif endif -extra-y += vmlinux.lds -obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ +obj-y += process.o ptrace.o module.o \ sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o devres.o devres-y = ../../../kernel/irq/devres.o -obj-$(CONFIG_PCI) += bios32.o obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo EXTRA_AFLAGS := -traditional --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -191,6 +191,7 @@ EXPORT_SYMBOL(kernel_thread); void flush_thread(void) { +#if !defined(CONFIG_COLDFIRE) unsigned long zero = 0; set_fs(USER_DS); current->thread.fs = __USER_DS; @@ -198,6 +199,14 @@ void flush_thread(void) asm volatile (".chip 68k/68881\n\t" "frestore %0@\n\t" ".chip 68k" : : "a" (&zero)); +#else + set_fs(USER_DS); + current->thread.fs = USER_DS; +#if defined(CONFIG_FPU) + if (!FPU_IS_EMU) + asm volatile ("frestore %0@\n\t" : : "a" (&zero)); +#endif +#endif } /* @@ -261,6 +270,7 @@ int copy_thread(int nr, unsigned long cl * Must save the current SFC/DFC value, NOT the value when * the parent was last descheduled - RGH 10-08-96 */ +#if !defined(CONFIG_COLDFIRE) p->thread.fs = get_fs().seg; if (!FPU_IS_EMU) { @@ -272,9 +282,34 @@ int copy_thread(int nr, unsigned long cl "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) : "memory"); +#else + p->thread.fs = get_fs(); + +#if defined(CONFIG_FPU) + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) + : "memory"); + + if (p->thread.fpstate[0]) { + asm volatile ("fmovemd %/fp0-%/fp7,%0" + : : "m" (p->thread.fp[0]) + : "memory"); + asm volatile ("fmovel %/fpiar,%0" + : : "m" (p->thread.fpcntl[0]) + : "memory"); + asm volatile ("fmovel %/fpcr,%0" + : : "m" (p->thread.fpcntl[1]) + : "memory"); + asm volatile ("fmovel %/fpsr,%0" + : : "m" (p->thread.fpcntl[2]) + : "memory"); + } /* Restore the state in case the fpu was busy */ asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); } +#endif +#endif return 0; } @@ -283,7 +318,9 @@ int copy_thread(int nr, unsigned long cl int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) { +#if !defined(CONFIG_COLDFIRE) || defined(CONFIG_FPU) char fpustate[216]; +#endif if (FPU_IS_EMU) { int i; @@ -300,6 +337,7 @@ int dump_fpu (struct pt_regs *regs, stru } /* First dump the fpu context to avoid protocol violation. */ +#if !defined(CONFIG_COLDFIRE) asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) return 0; @@ -310,6 +348,25 @@ int dump_fpu (struct pt_regs *regs, stru asm volatile ("fmovemx %/fp0-%/fp7,%0" :: "m" (fpu->fpregs[0]) : "memory"); +#elif defined(CONFIG_FPU) + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) + return 0; + + asm volatile ("fmovel %/fpiar,%0" + : : "m" (fpu->fpcntl[0]) + : "memory"); + asm volatile ("fmovel %/fpcr,%0" + : : "m" (fpu->fpcntl[1]) + : "memory"); + asm volatile ("fmovel %/fpsr,%0" + : : "m" (fpu->fpcntl[2]) + : "memory"); + asm volatile ("fmovemd %/fp0-%/fp7,%0" + : : "m" (fpu->fpregs[0]) + : "memory"); +#endif + return 1; } EXPORT_SYMBOL(dump_fpu); --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -67,13 +67,22 @@ EXPORT_SYMBOL(m68k_memory); struct mem_info m68k_ramdisk; +#if !defined(CONFIG_COLDFIRE) static char m68k_command_line[CL_SIZE]; +#else +char m68k_command_line[CL_SIZE]; +unsigned long uboot_info_stk; +EXPORT_SYMBOL(uboot_info_stk); +#endif void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata = NULL; void (*mach_get_model) (char *model); int (*mach_get_hardware_list) (char *buffer); +#ifdef CONFIG_COLDFIRE +void (*mach_tick)(void); +#endif /* machine dependent timer functions */ unsigned long (*mach_gettimeoffset) (void); int (*mach_hwclk) (int, struct rtc_time*); @@ -128,13 +137,17 @@ extern void config_hp300(void); extern void config_q40(void); extern void config_sun3x(void); +#ifdef CONFIG_COLDFIRE +void coldfire_sort_memrec(void); +#endif + #define MASK_256K 0xfffc0000 extern void paging_init(void); static void __init m68k_parse_bootinfo(const struct bi_record *record) { - while (record->tag != BI_LAST) { + while ((record->tag != BI_LAST) && !(CONFIG_COLDFIRE)) { int unknown = 0; const unsigned long *data = record->data; @@ -192,7 +205,11 @@ static void __init m68k_parse_bootinfo(c record->size); } - m68k_realnum_memory = m68k_num_memory; +#ifdef CONFIG_COLDFIRE + coldfire_sort_memrec(); +#endif + + m68k_realnum_memory = m68k_num_memory; #ifdef CONFIG_SINGLE_MEMORY_CHUNK if (m68k_num_memory > 1) { printk("Ignoring last %i chunks of physical memory\n", @@ -205,7 +222,9 @@ static void __init m68k_parse_bootinfo(c void __init setup_arch(char **cmdline_p) { extern int _etext, _edata, _end; +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) int i; +#endif /* The bootinfo is located right after the kernel bss */ m68k_parse_bootinfo((const struct bi_record *)&_end); @@ -220,9 +239,10 @@ void __init setup_arch(char **cmdline_p) * We should really do our own FPU check at startup. * [what do we do with buggy 68LC040s? if we have problems * with them, we should add a test to check_bugs() below] */ -#ifndef CONFIG_M68KFPU_EMU_ONLY +#if !defined(CONFIG_M68KFPU_EMU_ONLY) && defined(CONFIG_FPU) /* clear the fpu if we have one */ - if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { + if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060| + FPU_CFV4E)) { volatile int zero = 0; asm volatile ("frestore %0" : : "m" (zero)); } @@ -310,13 +330,18 @@ void __init setup_arch(char **cmdline_p) config_sun3x(); break; #endif +#ifdef CONFIG_COLDFIRE + case MACH_CFMMU: + config_coldfire(); + break; +#endif default: panic("No configuration setup"); } paging_init(); -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) for (i = 1; i < m68k_num_memory; i++) free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr, m68k_memory[i].size); @@ -343,6 +368,10 @@ void __init setup_arch(char **cmdline_p) #endif /* !CONFIG_SUN3 */ +#ifdef CONFIG_COLDFIRE + mmu_context_init(); +#endif + /* set ISA defs early as possible */ #if defined(CONFIG_ISA) && defined(MULTI_ISA) #if defined(CONFIG_Q40) @@ -373,6 +402,7 @@ static int show_cpuinfo(struct seq_file #define LOOP_CYCLES_68030 (8) #define LOOP_CYCLES_68040 (3) #define LOOP_CYCLES_68060 (1) +#define LOOP_CYCLES_COLDFIRE (2) if (CPU_IS_020) { cpu = "68020"; @@ -386,6 +416,9 @@ static int show_cpuinfo(struct seq_file } else if (CPU_IS_060) { cpu = "68060"; clockfactor = LOOP_CYCLES_68060; + } else if (CPU_IS_CFV4E) { + cpu = "ColdFire V4e"; + clockfactor = LOOP_CYCLES_COLDFIRE; } else { cpu = "680x0"; clockfactor = 0; @@ -404,6 +437,8 @@ static int show_cpuinfo(struct seq_file fpu = "68060"; else if (m68k_fputype & FPU_SUNFPA) fpu = "Sun FPA"; + else if (m68k_fputype & FPU_CFV4E) + fpu = "ColdFire V4e"; else fpu = "none"; #endif @@ -420,6 +455,8 @@ static int show_cpuinfo(struct seq_file mmu = "Sun-3"; else if (m68k_mmutype & MMU_APOLLO) mmu = "Apollo"; + else if (m68k_mmutype & MMU_CFV4E) + mmu = "ColdFire"; else mmu = "unknown"; @@ -482,7 +519,7 @@ int get_hardware_list(char *buffer) void check_bugs(void) { -#ifndef CONFIG_M68KFPU_EMU +#if !defined(CONFIG_M68KFPU_EMU) && !defined(CONFIG_M5445X) if (m68k_fputype == 0) { printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " "WHICH IS REQUIRED BY LINUX/M68K ***\n"); --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -29,6 +29,9 @@ #include #include #include +#ifdef CONFIG_COLDFIRE +#include +#endif /* * sys_pipe() is the normal C calling standard for creating @@ -257,6 +260,7 @@ asmlinkage int sys_ipc (uint call, int f return -EINVAL; } +#ifndef CONFIG_COLDFIRE /* Convert virtual (user) address VADDR to physical address PADDR */ #define virt_to_phys_040(vaddr) \ ({ \ @@ -580,6 +584,7 @@ cache_flush_060 (unsigned long addr, int } return 0; } +#endif /* CONFIG_COLDFIRE */ /* sys_cacheflush -- flush (part of) the processor cache. */ asmlinkage int @@ -612,6 +617,7 @@ sys_cacheflush (unsigned long addr, int goto out; } +#ifndef CONFIG_COLDFIRE if (CPU_IS_020_OR_030) { if (scope == FLUSH_SCOPE_LINE && len < 256) { unsigned long cacr; @@ -656,6 +662,16 @@ sys_cacheflush (unsigned long addr, int ret = cache_flush_060 (addr, scope, cache, len); } } +#else /* CONFIG_COLDFIRE */ + if ((cache & FLUSH_CACHE_INSN) && (cache & FLUSH_CACHE_DATA)) + flush_bcache(); + else if (cache & FLUSH_CACHE_INSN) + flush_icache(); + else + flush_dcache(); + + ret = 0; +#endif /* CONFIG_COLDFIRE */ out: unlock_kernel(); return ret; --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -40,6 +40,11 @@ static inline int set_rtc_mmss(unsigned */ static irqreturn_t timer_interrupt(int irq, void *dummy) { +#ifdef CONFIG_COLDFIRE + /* kick hardware timer if necessary */ + if (mach_tick) + mach_tick(); +#endif do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(get_irq_regs())); --- a/arch/m68k/kernel/vmlinux.lds.S +++ b/arch/m68k/kernel/vmlinux.lds.S @@ -1,10 +1,13 @@ PHDRS { - text PT_LOAD FILEHDR PHDRS FLAGS (7); + headers PT_PHDR PHDRS ; + text PT_LOAD FILEHDR PHDRS FLAGS (5); data PT_LOAD FLAGS (7); } #ifdef CONFIG_SUN3 #include "vmlinux-sun3.lds" +#elif CONFIG_COLDFIRE +#include "../coldfire/vmlinux-cf.lds" #else #include "vmlinux-std.lds" #endif --- a/arch/m68k/lib/checksum.c +++ b/arch/m68k/lib/checksum.c @@ -39,8 +39,131 @@ * computes a partial checksum, e.g. for TCP/UDP fragments */ +#ifdef CONFIG_COLDFIRE + +static inline unsigned short from32to16(unsigned long x) +{ + /* add up 16-bit and 16-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +static unsigned long do_csum(const unsigned char *buff, int len) +{ + int odd, count; + unsigned long result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = *buff; + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + count--; + buff += 4; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += (*buff << 8); + result = from32to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +__sum16 ip_fast_csum(const void *iph, unsigned int ihl) +{ + return ~do_csum(iph, ihl*4); +} +EXPORT_SYMBOL(ip_fast_csum); + +/* + * 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 + */ __wsum csum_partial(const void *buff, int len, __wsum sum) { + unsigned int result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + if (sum > result) + result += 1; + return result; +} +EXPORT_SYMBOL(csum_partial); + +/* + * copy from fs while checksumming, otherwise like csum_partial + */ + +__wsum +csum_partial_copy_from_user(const void __user *src, void *dst, int len, + __wsum sum, int *csum_err) +{ + if (csum_err) *csum_err = 0; + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} +EXPORT_SYMBOL(csum_partial_copy_from_user); + +/* + * copy from ds while checksumming, otherwise like csum_partial + */ + +__wsum +csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) +{ + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} +EXPORT_SYMBOL(csum_partial_copy_nocheck); + +#else /* !CONFIG_COLDFIRE */ + +unsigned int +csum_partial(const unsigned char *buff, int len, unsigned int sum) +{ unsigned long tmp1, tmp2; /* * Experiments with ethernet and slip connections show that buff @@ -423,3 +546,4 @@ csum_partial_copy_nocheck(const void *sr return(sum); } EXPORT_SYMBOL(csum_partial_copy_nocheck); +#endif /* CONFIG_COLDFIRE */ --- a/arch/m68k/lib/muldi3.c +++ b/arch/m68k/lib/muldi3.c @@ -21,12 +21,22 @@ Boston, MA 02111-1307, USA. */ #define BITS_PER_UNIT 8 +#ifdef CONFIG_COLDFIRE +#define umul_ppmm(w1, w0, u, v) \ + do { \ + unsigned long long x; \ + x = (unsigned long long)u * v; \ + w0 = (unsigned long)(x & 0x00000000ffffffff); \ + w1 = (unsigned long)(x & 0xffffffff00000000) >> 32; \ + } while (0) +#else /* CONFIG_COLDFIRE */ #define umul_ppmm(w1, w0, u, v) \ __asm__ ("mulu%.l %3,%1:%0" \ : "=d" ((USItype)(w0)), \ "=d" ((USItype)(w1)) \ : "%0" ((USItype)(u)), \ "dmi" ((USItype)(v))) +#endif /* CONFIG_COLDFIRE */ #define __umulsidi3(u, v) \ ({DIunion __w; \ --- a/arch/m68k/lib/semaphore.S +++ b/arch/m68k/lib/semaphore.S @@ -16,11 +16,24 @@ * there is contention on the semaphore. */ ENTRY(__down_failed) +#ifndef CONFIG_COLDFIRE moveml %a0/%d0/%d1,-(%sp) +#else + movel %a0,-(%sp) + movel %d0,-(%sp) + movel %d1,-(%sp) +#endif movel %a1,-(%sp) jbsr __down movel (%sp)+,%a1 +#ifndef CONFIG_COLDFIRE moveml (%sp)+,%a0/%d0/%d1 +#else + movel (%sp)+,%d1 + movel (%sp)+,%d0 + movel (%sp)+,%a0 +#endif + rts ENTRY(__down_failed_interruptible) @@ -44,10 +57,22 @@ ENTRY(__down_failed_trylock) rts ENTRY(__up_wakeup) +#ifndef CONFIG_COLDFIRE moveml %a0/%d0/%d1,-(%sp) +#else + movel %a0,-(%sp) + movel %d0,-(%sp) + movel %d1,-(%sp) +#endif movel %a1,-(%sp) jbsr __up movel (%sp)+,%a1 +#ifndef CONFIG_COLDFIRE moveml (%sp)+,%a0/%d0/%d1 +#else + movel (%sp)+,%d1 + movel (%sp)+,%d0 + movel (%sp)+,%a0 +#endif rts --- a/arch/m68k/lib/string.c +++ b/arch/m68k/lib/string.c @@ -15,6 +15,7 @@ char *strcpy(char *dest, const char *src } EXPORT_SYMBOL(strcpy); +#ifndef CONFIG_COLDFIRE void *memset(void *s, int c, size_t count) { void *xs = s; @@ -143,6 +144,69 @@ void *memcpy(void *to, const void *from, } EXPORT_SYMBOL(memcpy); +#else /* CONFIG_COLDFIRE */ + +void *memset(void *s, int c, size_t count) +{ + unsigned long x; + void *originalTo; + + for (x = 0; x < count; x++) + *(unsigned char *)s++ = (unsigned char)c; + + return originalTo; +} +EXPORT_SYMBOL(memset); + +void *memcpy(void *to, const void *from, size_t n) +{ + void *xto = to; + size_t temp; + + if (!n) + return xto; + if ((long) to & 1) { + char *cto = to; + const char *cfrom = from; + *cto++ = *cfrom++; + to = cto; + from = cfrom; + n--; + } + if (n > 2 && (long) to & 2) { + short *sto = to; + const short *sfrom = from; + *sto++ = *sfrom++; + to = sto; + from = sfrom; + n -= 2; + } + temp = n >> 2; + if (temp) { + long *lto = to; + const long *lfrom = from; + for (; temp; temp--) + *lto++ = *lfrom++; + to = lto; + from = lfrom; + } + if (n & 2) { + short *sto = to; + const short *sfrom = from; + *sto++ = *sfrom++; + to = sto; + from = sfrom; + } + if (n & 1) { + char *cto = to; + const char *cfrom = from; + *cto = *cfrom; + } + return xto; +} +EXPORT_SYMBOL(memcpy); +#endif /* CONFIG_COLDFIRE */ + void *memmove(void *dest, const void *src, size_t n) { void *xdest = dest; --- a/arch/m68k/lib/uaccess.c +++ b/arch/m68k/lib/uaccess.c @@ -5,6 +5,7 @@ */ #include +#ifndef CONFIG_COLDFIRE #include unsigned long __generic_copy_from_user(void *to, const void __user *from, @@ -220,3 +221,244 @@ unsigned long __clear_user(void __user * return res; } EXPORT_SYMBOL(__clear_user); + +#else /* CONFIG_COLDFIRE */ + +#include + +unsigned long __generic_copy_from_user(void *to, const void *from, + unsigned long n) +{ + unsigned long tmp; + __asm__ __volatile__ + (" tstl %2\n" + " jeq 2f\n" + "1: movel (%1)+,%3\n" + " movel %3,(%0)+\n" + " subql #1,%2\n" + " jne 1b\n" + "2: movel %4,%2\n" + " bclr #1,%2\n" + " jeq 4f\n" + "3: movew (%1)+,%3\n" + " movew %3,(%0)+\n" + "4: bclr #0,%2\n" + " jeq 6f\n" + "5: moveb (%1)+,%3\n" + " moveb %3,(%0)+\n" + "6:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "7: movel %2,%%d0\n" + "71:clrl (%0)+\n" + " subql #1,%%d0\n" + " jne 71b\n" + " lsll #2,%2\n" + " addl %4,%2\n" + " btst #1,%4\n" + " jne 81f\n" + " btst #0,%4\n" + " jne 91f\n" + " jra 6b\n" + "8: addql #2,%2\n" + "81:clrw (%0)+\n" + " btst #0,%4\n" + " jne 91f\n" + " jra 6b\n" + "9: addql #1,%2\n" + "91:clrb (%0)+\n" + " jra 6b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,7b\n" + " .long 3b,8b\n" + " .long 5b,9b\n" + ".previous" + : "=a"(to), "=a"(from), "=d"(n), "=&d"(tmp) + : "d"(n & 3), "0"(to), "1"(from), "2"(n/4) + : "d0", "memory"); + return n; +} +EXPORT_SYMBOL(__generic_copy_from_user); + + +unsigned long __generic_copy_to_user(void *to, const void *from, + unsigned long n) +{ + unsigned long tmp; + __asm__ __volatile__ + (" tstl %2\n" + " jeq 3f\n" + "1: movel (%1)+,%3\n" + "22:movel %3,(%0)+\n" + "2: subql #1,%2\n" + " jne 1b\n" + "3: movel %4,%2\n" + " bclr #1,%2\n" + " jeq 4f\n" + " movew (%1)+,%3\n" + "24:movew %3,(%0)+\n" + "4: bclr #0,%2\n" + " jeq 5f\n" + " moveb (%1)+,%3\n" + "25:moveb %3,(%0)+\n" + "5:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "60:addql #1,%2\n" + "6: lsll #2,%2\n" + " addl %4,%2\n" + " jra 5b\n" + "7: addql #2,%2\n" + " jra 5b\n" + "8: addql #1,%2\n" + " jra 5b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,60b\n" + " .long 22b,6b\n" + " .long 2b,6b\n" + " .long 24b,7b\n" + " .long 3b,60b\n" + " .long 4b,7b\n" + " .long 25b,8b\n" + " .long 5b,8b\n" + ".previous" + : "=a"(to), "=a"(from), "=d"(n), "=&d"(tmp) + : "r"(n & 3), "0"(to), "1"(from), "2"(n / 4) + : "memory"); + return n; +} +EXPORT_SYMBOL(__generic_copy_to_user); + +/* + * Copy a null terminated string from userspace. + */ + +long strncpy_from_user(char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (!(access_ok(VERIFY_READ, src, 1))) /* --tym-- */ + return res; + if (count == 0) return count; + __asm__ __volatile__ + ("1: moveb (%2)+,%%d0\n" + "12:moveb %%d0,(%1)+\n" + " jeq 2f\n" + " subql #1,%3\n" + " jne 1b\n" + "2: subl %3,%0\n" + "3:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "4: movel %4,%0\n" + " jra 3b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,4b\n" + " .long 12b,4b\n" + ".previous" + : "=d"(res), "=a"(dst), "=a"(src), "=d"(count) + : "i"(-EFAULT), "0"(count), "1"(dst), "2"(src), "3"(count) + : "d0", "memory"); + return res; +} +EXPORT_SYMBOL(strncpy_from_user); + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ +long strnlen_user(const char *src, long n) +{ + long res = -EFAULT; + if (!(access_ok(VERIFY_READ, src, 1))) /* --tym-- */ + return res; + + res = -(long)src; + __asm__ __volatile__ + ("1:\n" + " tstl %2\n" + " jeq 3f\n" + "2: moveb (%1)+,%%d0\n" + "22:\n" + " subql #1,%2\n" + " tstb %%d0\n" + " jne 1b\n" + " jra 4f\n" + "3:\n" + " addql #1,%0\n" + "4:\n" + " addl %1,%0\n" + "5:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "6: moveq %3,%0\n" + " jra 5b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,6b\n" + " .long 22b,6b\n" + ".previous" + : "=d"(res), "=a"(src), "=d"(n) + : "i"(0), "0"(res), "1"(src), "2"(n) + : "d0"); + return res; +} +EXPORT_SYMBOL(strnlen_user); + + +/* + * Zero Userspace + */ + +unsigned long __clear_user(void *to, unsigned long n) +{ + __asm__ __volatile__ + (" tstl %1\n" + " jeq 3f\n" + "1: movel %3,(%0)+\n" + "2: subql #1,%1\n" + " jne 1b\n" + "3: movel %2,%1\n" + " bclr #1,%1\n" + " jeq 4f\n" + "24:movew %3,(%0)+\n" + "4: bclr #0,%1\n" + " jeq 5f\n" + "25:moveb %3,(%0)+\n" + "5:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "61:addql #1,%1\n" + "6: lsll #2,%1\n" + " addl %2,%1\n" + " jra 5b\n" + "7: addql #2,%1\n" + " jra 5b\n" + "8: addql #1,%1\n" + " jra 5b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,61b\n" + " .long 2b,6b\n" + " .long 3b,61b\n" + " .long 24b,7b\n" + " .long 4b,7b\n" + " .long 25b,8b\n" + " .long 5b,8b\n" + ".previous" + : "=a"(to), "=d"(n) + : "r"(n & 3), "d"(0), "0"(to), "1"(n/4)); + return n; +} +EXPORT_SYMBOL(__clear_user); + +#endif /* CONFIG_COLDFIRE */ + --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -16,7 +16,9 @@ KBUILD_DEFCONFIG := amiga_defconfig # override top level makefile +ifndef CONFIG_COLDFIRE AS += -m68020 +endif LDFLAGS := -m m68kelf LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds ifneq ($(SUBARCH),$(ARCH)) @@ -30,12 +32,18 @@ ifdef CONFIG_SUN3 LDFLAGS_vmlinux = -N endif +ifdef CONFIG_COLDFIRE +# OBJCOPYFLAGS := -R .note -R .note.gnu.build-id -R .comment -S +# LDFLAGS_vmlinux = --verbose +endif + CHECKFLAGS += -D__mc68000__ # without -fno-strength-reduce the 53c7xx.c driver fails ;-( KBUILD_CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 # enable processor switch if compiled only for a single cpu +ifndef CONFIG_COLDFIRE ifndef CONFIG_M68020 ifndef CONFIG_M68030 @@ -49,6 +57,16 @@ endif endif endif +endif + +ifdef CONFIG_M5445X +KBUILD_CFLAGS += -march=isac -mcpu=54455 -msoft-float -g +KBUILD_AFLAGS += -march=isac -mcpu=54455 -msoft-float +endif +ifdef CONFIG_M547X_8X +KBUILD_CFLAGS += -mcfv4e -g +KBUILD_AFLAGS += -mcfv4e +endif ifdef CONFIG_KGDB # If configured for kgdb support, include debugging infos and keep the @@ -57,8 +75,12 @@ KBUILD_CFLAGS := $(subst -fomit-frame-po endif ifndef CONFIG_SUN3 +ifndef CONFIG_COLDFIRE head-y := arch/m68k/kernel/head.o else +head-y := arch/m68k/coldfire/head.o +endif +else head-y := arch/m68k/kernel/sun3-head.o endif @@ -79,6 +101,7 @@ core-$(CONFIG_SUN3) += arch/m68k/sun3/ core-$(CONFIG_M68040) += arch/m68k/fpsp040/ core-$(CONFIG_M68060) += arch/m68k/ifpsp060/ core-$(CONFIG_M68KFPU_EMU) += arch/m68k/math-emu/ +core-$(CONFIG_COLDFIRE) += arch/m68k/coldfire/ all: zImage --- a/arch/m68k/mm/cache.c +++ b/arch/m68k/mm/cache.c @@ -10,7 +10,11 @@ #include #include +#ifdef CONFIG_COLDFIRE +#include +#endif /* CONFIG_COLDFIRE */ +#ifndef CONFIG_COLDFIRE static unsigned long virt_to_phys_slow(unsigned long vaddr) { if (CPU_IS_060) { @@ -69,11 +73,18 @@ static unsigned long virt_to_phys_slow(u } return 0; } +#endif /* CONFIG_COLDFIRE */ + /* Push n pages at kernel virtual address and clear the icache */ /* RZ: use cpush %bc instead of cpush %dc, cinv %ic */ void flush_icache_range(unsigned long address, unsigned long endaddr) { +#ifdef CONFIG_COLDFIRE +// JKM -- hack until new cpushl stuff is in +// cf_icache_flush_range(address, endaddr); + flush_icache(); +#else /* !CONFIG_COLDFIRE */ if (CPU_IS_040_OR_060) { address &= PAGE_MASK; @@ -94,9 +105,11 @@ void flush_icache_range(unsigned long ad : "=&d" (tmp) : "di" (FLUSH_I)); } +#endif /* CONFIG_COLDFIRE */ } EXPORT_SYMBOL(flush_icache_range); +#ifndef CONFIG_COLDFIRE void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, unsigned long addr, int len) { @@ -115,4 +128,5 @@ void flush_icache_user_range(struct vm_a : "di" (FLUSH_I)); } } +#endif /* CONFIG_COLDFIRE */ --- /dev/null +++ b/arch/m68k/mm/cf-mmu.c @@ -0,0 +1,260 @@ +/* + * linux/arch/m68k/mm/cf-mmu.c + * + * Based upon linux/arch/m68k/mm/sun3mmu.c + * Based upon linux/arch/ppc/mm/mmu_context.c + * + * Implementations of mm routines specific to the Coldfire MMU. + * + * Copyright (c) 2008 Freescale Semiconductor, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define KMAPAREA(x) ((x >= VMALLOC_START) && ( x < KMAP_END)) + +#undef DEBUG + +mm_context_t next_mmu_context; +unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; + +atomic_t nr_free_contexts; +struct mm_struct *context_mm[LAST_CONTEXT+1]; +void steal_context(void); + + +const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; + +extern unsigned long empty_bad_page_table; +extern unsigned long empty_bad_page; +extern unsigned long num_pages; + +extern char __init_begin, __init_end; + +void free_initmem(void) +{ +#if 0 + unsigned long addr; + unsigned long start = (unsigned long)&__init_begin; + unsigned long end = (unsigned long)&__init_end; + + printk(KERN_INFO "free_initmem: __init_begin = 0x%lx __init_end = 0x%lx\n", start, end); + + addr = (unsigned long)&__init_begin; + for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) { + /* not currently used */ + virt_to_page(addr)->flags &= ~(1 << PG_reserved); + init_page_count(virt_to_page(addr)); + free_page(addr); + totalram_pages++; + } +#endif +} + +/* Coldfire paging_init derived from sun3 */ +void __init paging_init(void) +{ + pgd_t * pg_dir; + pte_t * pg_table; + int i; + unsigned long address; + unsigned long next_pgtable; + unsigned long bootmem_end; + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long size; + enum zone_type zone; + + empty_zero_page = (void *)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + pg_dir = swapper_pg_dir; + memset(swapper_pg_dir, 0, sizeof (swapper_pg_dir)); + + size = num_pages * sizeof(pte_t); + size = (size + PAGE_SIZE) & ~(PAGE_SIZE-1); + next_pgtable = (unsigned long)alloc_bootmem_pages(size); + + bootmem_end = (next_pgtable + size + PAGE_SIZE) & PAGE_MASK; + pg_dir += PAGE_OFFSET >> PGDIR_SHIFT; + + address = PAGE_OFFSET; + while (address < (unsigned long)high_memory) + { + pg_table = (pte_t *)next_pgtable; + next_pgtable += PTRS_PER_PTE * sizeof (pte_t); + pgd_val(*pg_dir) = (unsigned long) pg_table; + pg_dir++; + + /* now change pg_table to kernel virtual addresses */ + for (i=0; i= (unsigned long)high_memory) + pte_val (pte) = 0; + + set_pte (pg_table, pte); + address += PAGE_SIZE; + } + } + + current->mm = NULL; + + /* clear zones */ + for (zone = 0; zone < MAX_NR_ZONES; zone++) + zones_size[zone] = 0x0; + + /* allocate the bottom 32M (0x40x 0x41x) to DMA - head.S marks them NO CACHE */ + /* JKM - this should be changed to allocate from the TOP (0x4f,0x4e) but the + * allocator is being a bit challenging */ + zones_size[ZONE_DMA] = (32*1024*1024) >> PAGE_SHIFT; + + /* allocate the rest to NORMAL - head.S marks them CACHE */ + zones_size[ZONE_NORMAL] = (((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT) - zones_size[0]; + + free_area_init(zones_size); +} + + +int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word) +{ + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long mmuar; + int asid; + int flags; + + local_save_flags(flags); + local_irq_disable(); + + mmuar = ( dtlb ) ? regs->mmuar + : regs->pc + (extension_word * sizeof(long)); + + mm = (!user_mode(regs) && KMAPAREA(mmuar)) ? &init_mm : current->mm; + + if (!mm) { + local_irq_restore(flags); + return (-1); + } + + pgd = pgd_offset(mm, mmuar); + if (pgd_none(*pgd)) { + local_irq_restore(flags); + return (-1); + } + + pmd = pmd_offset(pgd, mmuar); + if (pmd_none(*pmd)) { + local_irq_restore(flags); + return (-1); + } + + pte = (KMAPAREA(mmuar)) ? pte_offset_kernel(pmd, mmuar) + : pte_offset_map(pmd, mmuar); + if (pte_none(*pte) || !pte_present(*pte)) { + local_irq_restore(flags); + return (-1); + } + + if (write) { + if (!pte_write(*pte)) { + local_irq_restore(flags); + return (-1); + } + set_pte(pte, pte_mkdirty(*pte)); + } + + set_pte(pte, pte_mkyoung(*pte)); + asid = mm->context & 0xff; + if (!pte_dirty(*pte) && !KMAPAREA(mmuar)) + set_pte(pte, pte_wrprotect(*pte)); + + *MMUTR = (mmuar & PAGE_MASK) | (asid << CF_ASID_MMU_SHIFT) + | (((int)(pte->pte) & (int)CF_PAGE_MMUTR_MASK ) >> CF_PAGE_MMUTR_SHIFT) + | MMUTR_V; + + *MMUDR = (pte_val(*pte) & PAGE_MASK) + | ((pte->pte) & CF_PAGE_MMUDR_MASK) + | MMUDR_SZ8K | MMUDR_X; + + if ( dtlb ) + *MMUOR = MMUOR_ACC | MMUOR_UAA; + else + *MMUOR = MMUOR_ITLB | MMUOR_ACC | MMUOR_UAA; + + asm("nop"); + +#ifdef DEBUG + printk("cf_tlb_miss: va=%lx, pa=%lx\n", (mmuar & PAGE_MASK), + (pte_val(*pte) & PAGE_MASK)); +#endif + local_irq_restore(flags); + return (0); +} + + +/* The following was taken from arch/ppc/mmu_context.c + * + * Initialize the context management stuff. + */ +void __init mmu_context_init(void) +{ + /* + * Some processors have too few contexts to reserve one for + * init_mm, and require using context 0 for a normal task. + * Other processors reserve the use of context zero for the kernel. + * This code assumes FIRST_CONTEXT < 32. + */ + context_map[0] = (1 << FIRST_CONTEXT) - 1; + next_mmu_context = FIRST_CONTEXT; + atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1); +} + +/* + * Steal a context from a task that has one at the moment. + * This is only used on 8xx and 4xx and we presently assume that + * they don't do SMP. If they do then thicfpgalloc.hs will have to check + * whether the MM we steal is in use. + * We also assume that this is only used on systems that don't + * use an MMU hash table - this is true for 8xx and 4xx. + * This isn't an LRU system, it just frees up each context in + * turn (sort-of pseudo-random replacement :). This would be the + * place to implement an LRU scheme if anyone was motivated to do it. + * -- paulus + */ +void steal_context(void) +{ + struct mm_struct *mm; + /* free up context `next_mmu_context' */ + /* if we shouldn't free context 0, don't... */ + if (next_mmu_context < FIRST_CONTEXT) + next_mmu_context = FIRST_CONTEXT; + mm = context_mm[next_mmu_context]; + flush_tlb_mm(mm); + destroy_context(mm); +} --- /dev/null +++ b/arch/m68k/mm/cf-mmu.c.orig @@ -0,0 +1,265 @@ +/* + * linux/arch/m68k/mm/cf-mmu.c + * + * Based upon linux/arch/m68k/mm/sun3mmu.c + * Based upon linux/arch/ppc/mm/mmu_context.c + * + * Implementations of mm routines specific to the Coldfire MMU. + * + * Copyright (c) 2008 Freescale Semiconductor, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if PAGE_OFFSET == CONFIG_SDRAM_BASE +#define KERNRAM(x) ((x >= PAGE_OFFSET) && (x < (PAGE_OFFSET + CONFIG_SDRAM_SIZE))) +#else +#define KERNRAM(x) (x >= PAGE_OFFSET) +#endif + +mm_context_t next_mmu_context; +unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; + +atomic_t nr_free_contexts; +struct mm_struct *context_mm[LAST_CONTEXT+1]; +void steal_context(void); + + +const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; + +extern unsigned long empty_bad_page_table; +extern unsigned long empty_bad_page; +extern unsigned long num_pages; + +extern char __init_begin, __init_end; + +void free_initmem(void) +{ +#if 0 + unsigned long addr; + unsigned long start = (unsigned long)&__init_begin; + unsigned long end = (unsigned long)&__init_end; + +/* + * JKM -- revisit -- the latest round of vmlinux.lds changes has caused + * a little grief with how init areas are handled. With the new toolchain + * release I'll fix this. + */ + printk(KERN_INFO "free_initmem: __init_begin = 0x%lx __init_end = 0x%lx\n", start, end); + + addr = (unsigned long)&__init_begin; + for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) { + /* not currently used */ + virt_to_page(addr)->flags &= ~(1 << PG_reserved); + init_page_count(virt_to_page(addr)); + free_page(addr); + totalram_pages++; + } +#endif +} + +/* Coldfire paging_init derived from sun3 */ +void __init paging_init(void) +{ + pgd_t * pg_dir; + pte_t * pg_table; + int i; + unsigned long address; + unsigned long next_pgtable; + unsigned long bootmem_end; + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long size; + enum zone_type zone; + + empty_zero_page = (void *)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + pg_dir = swapper_pg_dir; + memset(swapper_pg_dir, 0, sizeof (swapper_pg_dir)); + + size = num_pages * sizeof(pte_t); + size = (size + PAGE_SIZE) & ~(PAGE_SIZE-1); + next_pgtable = (unsigned long)alloc_bootmem_pages(size); + + bootmem_end = (next_pgtable + size + PAGE_SIZE) & PAGE_MASK; + pg_dir += PAGE_OFFSET >> PGDIR_SHIFT; + + address = PAGE_OFFSET; + while (address < (unsigned long)high_memory) + { + pg_table = (pte_t *)next_pgtable; + next_pgtable += PTRS_PER_PTE * sizeof (pte_t); + pgd_val(*pg_dir) = (unsigned long) pg_table; + pg_dir++; + + /* now change pg_table to kernel virtual addresses */ + for (i=0; i= (unsigned long)high_memory) + pte_val (pte) = 0; + + set_pte (pg_table, pte); + address += PAGE_SIZE; + } + } + + current->mm = NULL; + + /* clear zones */ + for (zone = 0; zone < MAX_NR_ZONES; zone++) + zones_size[zone] = 0x0; + + /* allocate the bottom 32M (0x40x 0x41x) to DMA - head.S marks them NO CACHE */ + /* JKM - this should be changed to allocate from the TOP (0x4f,0x4e) but the + * allocator is being a bit challenging */ + zones_size[ZONE_DMA] = (32*1024*1024) >> PAGE_SHIFT; + + /* allocate the rest to NORMAL - head.S marks them CACHE */ + zones_size[ZONE_NORMAL] = (((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT) - zones_size[0]; + + free_area_init(zones_size); +} + + +int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word) +{ + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long mmuar; + int asid; + int flags; + + local_save_flags(flags); + local_irq_disable(); + + mmuar = ( dtlb ) ? regs->mmuar + : regs->pc + (extension_word * sizeof(long)); + + mm = (!user_mode(regs) && KERNRAM(mmuar)) ? &init_mm : current->mm; + + if (!mm) { + local_irq_restore(flags); + return (-1); + } + + pgd = pgd_offset(mm, mmuar); + if (pgd_none(*pgd)) { + local_irq_restore(flags); + return (-1); + } + + pmd = pmd_offset(pgd, mmuar); + if (pmd_none(*pmd)) { + local_irq_restore(flags); + return (-1); + } + + pte = (KERNRAM(mmuar)) ? pte_offset_kernel(pmd, mmuar) + : pte_offset_map(pmd, mmuar); + if (pte_none(*pte) || !pte_present(*pte)) { + local_irq_restore(flags); + return (-1); + } + + if (write) { + if (!pte_write(*pte)) { + local_irq_restore(flags); + return (-1); + } + set_pte(pte, pte_mkdirty(*pte)); + } + + set_pte(pte, pte_mkyoung(*pte)); + asid = mm->context & 0xff; + if (!pte_dirty(*pte) && !KERNRAM(mmuar)) + set_pte(pte, pte_wrprotect(*pte)); + + *MMUTR = (mmuar & PAGE_MASK) | (asid << CF_ASID_MMU_SHIFT) + | (((int)(pte->pte) & (int)CF_PAGE_MMUTR_MASK ) >> CF_PAGE_MMUTR_SHIFT) + | MMUTR_V; + + *MMUDR = (pte_val(*pte) & PAGE_MASK) + | ((pte->pte) & CF_PAGE_MMUDR_MASK) + | MMUDR_SZ8K | MMUDR_X; + + if ( dtlb ) + *MMUOR = MMUOR_ACC | MMUOR_UAA; + else + *MMUOR = MMUOR_ITLB | MMUOR_ACC | MMUOR_UAA; + + asm("nop"); + + /*printk("cf_tlb_miss: va=%lx, pa=%lx\n", (mmuar & PAGE_MASK), + (pte_val(*pte) & PAGE_MASK));*/ + local_irq_restore(flags); + return (0); +} + + +/* The following was taken from arch/ppc/mmu_context.c + * + * Initialize the context management stuff. + */ +void __init mmu_context_init(void) +{ + /* + * Some processors have too few contexts to reserve one for + * init_mm, and require using context 0 for a normal task. + * Other processors reserve the use of context zero for the kernel. + * This code assumes FIRST_CONTEXT < 32. + */ + context_map[0] = (1 << FIRST_CONTEXT) - 1; + next_mmu_context = FIRST_CONTEXT; + atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1); +} + +/* + * Steal a context from a task that has one at the moment. + * This is only used on 8xx and 4xx and we presently assume that + * they don't do SMP. If they do then thicfpgalloc.hs will have to check + * whether the MM we steal is in use. + * We also assume that this is only used on systems that don't + * use an MMU hash table - this is true for 8xx and 4xx. + * This isn't an LRU system, it just frees up each context in + * turn (sort-of pseudo-random replacement :). This would be the + * place to implement an LRU scheme if anyone was motivated to do it. + * -- paulus + */ +void steal_context(void) +{ + struct mm_struct *mm; + /* free up context `next_mmu_context' */ + /* if we shouldn't free context 0, don't... */ + if (next_mmu_context < FIRST_CONTEXT) + next_mmu_context = FIRST_CONTEXT; + mm = context_mm[next_mmu_context]; + flush_tlb_mm(mm); + destroy_context(mm); +} --- a/arch/m68k/mm/hwtest.c +++ b/arch/m68k/mm/hwtest.c @@ -25,6 +25,7 @@ #include +#ifndef CONFIG_COLDFIRE int hwreg_present( volatile void *regp ) { int ret = 0; @@ -82,4 +83,5 @@ int hwreg_write( volatile void *regp, un return( ret ); } EXPORT_SYMBOL(hwreg_write); +#endif --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -122,7 +122,6 @@ void __init mem_init(void) if (MACH_IS_ATARI) atari_stram_mem_init_hook(); #endif - /* this will put all memory onto the freelists */ totalram_pages = num_physpages = 0; for_each_online_pgdat(pgdat) { @@ -146,7 +145,7 @@ void __init mem_init(void) } } -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) /* insert pointer tables allocated so far into the tablelist */ init_pointer_table((unsigned long)kernel_pg_dir); for (i = 0; i < PTRS_PER_PGD; i++) { --- a/arch/m68k/mm/kmap.c +++ b/arch/m68k/mm/kmap.c @@ -24,7 +24,11 @@ #undef DEBUG +#ifndef CONFIG_COLDFIRE #define PTRTREESIZE (256*1024) +#else +#define PTRTREESIZE PAGE_SIZE +#endif /* * For 040/060 we can use the virtual memory area like other architectures, @@ -50,7 +54,11 @@ static inline void free_io_area(void *ad #else +#ifdef CONFIG_COLDFIRE +#define IO_SIZE PAGE_SIZE +#else #define IO_SIZE (256*1024) +#endif static struct vm_struct *iolist; @@ -125,8 +133,34 @@ void __iomem *__ioremap(unsigned long ph } #endif +#ifdef CONFIG_M5445X + if (physaddr >= 0xf0000000) { + /* + * On the M5445x processors an ACR is setup to map + * the 0xF0000000 range into kernel memory as + * non-cacheable. + */ + return (void __iomem *)physaddr; + } +#endif + +#ifdef CONFIG_M547X_8X + if (physaddr >= 0xf0000000) { + /* + * On the M547x/M548x processors an ACR is setup to map + * the 0xF0000000 range into kernel memory as + * non-cacheable. + */ + return (void __iomem *)physaddr; + } + if ((physaddr >= 0xd0000000) && (physaddr + size < 0xd800ffff)) { + printk("ioremap:PCI 0x%lx,0x%lx(%d) - PCI area hit\n", physaddr, size, cacheflag); + return (void *)physaddr; + } +#endif + #ifdef DEBUG - printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag); + printk("ioremap: paddr=0x%lx,size=0x%lx(%d) - ", physaddr, size, cacheflag); #endif /* * Mappings have to be aligned @@ -145,7 +179,7 @@ void __iomem *__ioremap(unsigned long ph virtaddr = (unsigned long)area->addr; retaddr = virtaddr + offset; #ifdef DEBUG - printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr); + printk(" paddr=0x%lx,vaddr=0x%lx,retaddr=0x%lx", physaddr, virtaddr, retaddr); #endif /* @@ -170,7 +204,12 @@ void __iomem *__ioremap(unsigned long ph break; } } else { +#ifndef CONFIG_COLDFIRE physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); +#else + physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | \ + _PAGE_READWRITE); +#endif switch (cacheflag) { case IOMAP_NOCACHE_SER: case IOMAP_NOCACHE_NONSER: @@ -249,7 +288,12 @@ void __iounmap(void *addr, unsigned long pgd_t *pgd_dir; pmd_t *pmd_dir; pte_t *pte_dir; - +#ifdef CONFIG_M547X_8X + if ((addr >= (void*)0xd0000000) && (addr + size < (void*)0xd800ffff)) { + printk("%s: PCI address\n",__FUNCTION__); + return; + } +#endif while ((long)size > 0) { pgd_dir = pgd_offset_k(virtaddr); if (pgd_bad(*pgd_dir)) { --- a/arch/m68k/mm/Makefile +++ b/arch/m68k/mm/Makefile @@ -6,3 +6,4 @@ obj-y := cache.o init.o fault.o hwtest. obj-$(CONFIG_MMU_MOTOROLA) += kmap.o memory.o motorola.o obj-$(CONFIG_MMU_SUN3) += sun3kmap.o sun3mmu.o +obj-$(CONFIG_MMU_CFV4E) += cf-mmu.o kmap.o memory.o --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -127,6 +127,7 @@ int free_pointer_table (pmd_t *ptable) return 0; } +#ifndef CONFIG_COLDFIRE /* invalidate page in both caches */ static inline void clear040(unsigned long paddr) { @@ -173,6 +174,7 @@ static inline void pushcl040(unsigned lo clear040(paddr); local_irq_restore(flags); } +#endif /* CONFIG_COLDFIRE */ /* * 040: Hit every page containing an address in the range paddr..paddr+len-1. @@ -203,6 +205,11 @@ static inline void pushcl040(unsigned lo void cache_clear (unsigned long paddr, int len) { +#ifdef CONFIG_COLDFIRE +// JKM -- revise to use proper caching +// cf_cache_clear(paddr, len); + flush_bcache(); +#else if (CPU_IS_040_OR_060) { int tmp; @@ -237,6 +244,7 @@ void cache_clear (unsigned long paddr, i if(mach_l2_flush) mach_l2_flush(0); #endif +#endif /* CONFIG_COLDFIRE */ } EXPORT_SYMBOL(cache_clear); @@ -250,6 +258,11 @@ EXPORT_SYMBOL(cache_clear); void cache_push (unsigned long paddr, int len) { +#ifdef CONFIG_COLDFIRE +// JKM -- revise to use proper caching +// cf_cache_push(paddr, len); + flush_bcache(); +#else if (CPU_IS_040_OR_060) { int tmp = PAGE_SIZE; @@ -290,6 +303,7 @@ void cache_push (unsigned long paddr, in if(mach_l2_flush) mach_l2_flush(1); #endif +#endif /* CONFIG_COLDFIRE */ } EXPORT_SYMBOL(cache_push); --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -6,7 +6,7 @@ menuconfig ATA tristate "Serial ATA (prod) and Parallel ATA (experimental) drivers" depends on HAS_IOMEM depends on BLOCK - depends on !(M32R || M68K) || BROKEN + depends on !M32R || BROKEN depends on !SUN4 || BROKEN select SCSI ---help--- @@ -679,4 +679,13 @@ config PATA_BF54X If unsure, say N. +config PATA_FSL + tristate "Freescale on-chip PATA support" + depends on (ARCH_MX3 || ARCH_MX27 || PPC_512x || M54455) + help + On Freescale processors, say Y here if you wish to use the on-chip + ATA interface. + + If you are unsure, say N to this. + endif # ATA --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -1,4 +1,3 @@ - obj-$(CONFIG_ATA) += libata.o obj-$(CONFIG_SATA_AHCI) += ahci.o @@ -71,6 +70,7 @@ obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o +obj-$(CONFIG_PATA_FSL) += pata_fsl.o # Should be last but two libata driver obj-$(CONFIG_PATA_ACPI) += pata_acpi.o # Should be last but one libata driver --- /dev/null +++ b/drivers/ata/pata_fsl.c @@ -0,0 +1,814 @@ +/* + * Freescale integrated PATA driver + */ + +/* + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FSL_PATA_USE_DMA +#include +#endif + +#define DRV_NAME "pata_fsl" +#define DRV_VERSION "1.0" + +#ifdef CONFIG_M54455 +#define WRITE_ATA8(val, reg) \ + __raw_writeb(val, (ata_regs + reg)); +#define WRITE_ATA16(val, reg) \ + __raw_writew(val, (ata_regs + reg)); +#else +#define WRITE_ATA8(val, reg) \ + __raw_writel(val, (ata_regs + reg)); +#define WRITE_ATA16(val, reg) \ + __raw_writel(val, (ata_regs + reg)); +#endif + +struct pata_fsl_priv { +#ifdef CONFIG_FSL_PATA_USE_DMA + int ultra; +#endif + u8 *fsl_ata_regs; +#ifdef CONFIG_FSL_PATA_USE_DMA + int dma_rchan; + int dma_wchan; + int dma_done; + int dma_dir; +#endif +}; + +enum { + /* various constants */ + +#ifdef CONFIG_FSL_PATA_USE_DMA + FSL_ATA_MAX_SG_LEN = 65534, +#endif + + /* offsets to registers */ + + FSL_ATA_TIMING_REGS = 0x00, + FSL_ATA_FIFO_FILL = 0x20, + FSL_ATA_CONTROL = 0x24, + FSL_ATA_INT_PEND = 0x28, + FSL_ATA_INT_EN = 0x2C, + FSL_ATA_INT_CLEAR = 0x30, + FSL_ATA_FIFO_ALARM = 0x34, + FSL_ATA_DRIVE_DATA = 0xA0, + FSL_ATA_DRIVE_CONTROL = 0xD8, + + /* bits within FSL_ATA_CONTROL */ + + FSL_ATA_CTRL_FIFO_RST_B = 0x80, + FSL_ATA_CTRL_ATA_RST_B = 0x40, + FSL_ATA_CTRL_FIFO_TX_EN = 0x20, + FSL_ATA_CTRL_FIFO_RCV_EN = 0x10, + FSL_ATA_CTRL_DMA_PENDING = 0x08, + FSL_ATA_CTRL_DMA_ULTRA = 0x04, + FSL_ATA_CTRL_DMA_WRITE = 0x02, + FSL_ATA_CTRL_IORDY_EN = 0x01, + + /* bits within the interrupt control registers */ + + FSL_ATA_INTR_ATA_INTRQ1 = 0x80, + FSL_ATA_INTR_FIFO_UNDERFLOW = 0x40, + FSL_ATA_INTR_FIFO_OVERFLOW = 0x20, + FSL_ATA_INTR_CTRL_IDLE = 0x10, + FSL_ATA_INTR_ATA_INTRQ2 = 0x08, +}; + +/* + * This structure contains the timing parameters for + * ATA bus timing in the 5 PIO modes. The timings + * are in nanoseconds, and are converted to clock + * cycles before being stored in the ATA controller + * timing registers. + */ +static struct { + short t0, t1, t2_8, t2_16, t2i, t4, t9, tA; +} pio_specs[] = { + [0] = { + .t0 = 600, .t1 = 70, .t2_8 = 290, .t2_16 = 165, .t2i = 0, + .t4 = 30,.t9 = 20,.tA = 50 + }, + [1] = { + .t0 = 383, .t1 = 50, .t2_8 = 290, .t2_16 = 125, .t2i = 0, + .t4 = 20, .t9 = 15, .tA = 50 + }, + [2] = { + .t0 = 240, .t1 = 30, .t2_8 = 290, .t2_16 = 100, .t2i = 0, + .t4 = 15, .t9 = 10, .tA = 50 + }, + [3] = { + .t0 = 180, .t1 = 30, .t2_8 = 80, .t2_16 = 80, .t2i = 0, + .t4 = 10, .t9 = 10, .tA = 50 + }, + [4] = { + .t0 = 120, .t1 = 25, .t2_8 = 70, .t2_16 = 70, .t2i = 0, + .t4 = 10, .t9 = 10, .tA = 50 + }, +}; + +#define NR_PIO_SPECS (sizeof pio_specs / sizeof pio_specs[0]) + +/* + * This structure contains the timing parameters for + * ATA bus timing in the 3 MDMA modes. The timings + * are in nanoseconds, and are converted to clock + * cycles before being stored in the ATA controller + * timing registers. + */ +static struct { + short t0M, tD, tH, tJ, tKW, tM, tN, tJNH; +} mdma_specs[] = { + [0] = { + .t0M = 480, .tD = 215, .tH = 20, .tJ = 20, .tKW = 215, + .tM = 50, .tN = 15, .tJNH = 20 + }, + [1] = { + .t0M = 150, .tD = 80, .tH = 15, .tJ = 5, .tKW = 50, + .tM = 30, .tN = 10, .tJNH = 15 + }, + [2] = { + .t0M = 120, .tD = 70, .tH = 10, .tJ = 5, .tKW = 25, + .tM = 25, .tN = 10, .tJNH = 10 + }, +}; + +#define NR_MDMA_SPECS (sizeof mdma_specs / sizeof mdma_specs[0]) + +/* + * This structure contains the timing parameters for + * ATA bus timing in the 6 UDMA modes. The timings + * are in nanoseconds, and are converted to clock + * cycles before being stored in the ATA controller + * timing registers. + */ +static struct { + short t2CYC, tCYC, tDS, tDH, tDVS, tDVH, tCVS, tCVH, tFS_min, tLI_max, + tMLI, tAZ, tZAH, tENV_min, tSR, tRFS, tRP, tACK, tSS, tDZFS; +} udma_specs[] = { + [0] = { + .t2CYC = 235, .tCYC = 114, .tDS = 15, .tDH = 5, .tDVS = 70, + .tDVH = 6, .tCVS = 70, .tCVH = 6, .tFS_min = 0, + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, + .tENV_min = 20, .tSR = 50, .tRFS = 75, .tRP = 160, + .tACK = 20, .tSS = 50, .tDZFS = 80 + }, + [1] = { + .t2CYC = 156, .tCYC = 75, .tDS = 10, .tDH = 5, .tDVS = 48, + .tDVH = 6, .tCVS = 48, .tCVH = 6, .tFS_min = 0, + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, + .tENV_min = 20, .tSR = 30, .tRFS = 70, .tRP = 125, + .tACK = 20, .tSS = 50, .tDZFS = 63 + }, + [2] = { + .t2CYC = 117, .tCYC = 55, .tDS = 7, .tDH = 5, .tDVS = 34, + .tDVH = 6, .tCVS = 34, .tCVH = 6, .tFS_min = 0, + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, + .tENV_min = 20, .tSR = 20, .tRFS = 60, .tRP = 100, + .tACK = 20, .tSS = 50, .tDZFS = 47 + }, + [3] = { + .t2CYC = 86, .tCYC = 39, .tDS = 7, .tDH = 5, .tDVS = 20, + .tDVH = 6, .tCVS = 20, .tCVH = 6, .tFS_min = 0, + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, + .tENV_min = 20, .tSR = 20, .tRFS = 60, .tRP = 100, + .tACK = 20, .tSS = 50, .tDZFS = 35 + }, + [4] = { + .t2CYC = 57, .tCYC = 25, .tDS = 5, .tDH = 5, .tDVS = 7, + .tDVH = 6, .tCVS = 7, .tCVH = 6, .tFS_min = 0, + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, + .tENV_min = 20, .tSR = 50, .tRFS = 60, .tRP = 100, + .tACK = 20, .tSS = 50, .tDZFS = 25 + }, + [5] = { + .t2CYC = 38, .tCYC = 17, .tDS = 4, .tDH = 5, .tDVS = 5, + .tDVH = 6, .tCVS = 10, .tCVH = 10, .tFS_min = 0, + .tLI_max = 75, .tMLI = 20, .tAZ = 10, .tZAH = 20, + .tENV_min = 20, .tSR = 20, .tRFS = 50, .tRP = 85, + .tACK = 20, .tSS = 50, .tDZFS = 40 + }, +}; + +#define NR_UDMA_SPECS (sizeof udma_specs / sizeof udma_specs[0]) + +struct fsl_ata_time_regs { + u8 time_off, time_on, time_1, time_2w; + u8 time_2r, time_ax, time_pio_rdx, time_4; + u8 time_9, time_m, time_jn, time_d; + u8 time_k, time_ack, time_env, time_rpx; + u8 time_zah, time_mlix, time_dvh, time_dzfs; + u8 time_dvs, time_cvh, time_ss, time_cyc; +}; + +static void update_timing_config(struct fsl_ata_time_regs *tp, struct ata_host *host) +{ + u32 *lp = (u32 *)tp; + struct pata_fsl_priv *priv = host->private_data; + u32 *ctlp = (u32 *)priv->fsl_ata_regs; + int i; + + /* + * JKM - this could have endianess issues on BE depending + * on how the controller is glued to the bus -- probably + * should rewrite this to write byte at a time. + */ + for (i = 0; i < 5; i++) { + __raw_writel(*lp, ctlp); + lp++; + ctlp++; + } + mb(); +} + +/*! + * Calculate values for the ATA bus timing registers and store + * them into the hardware. + * + * @param xfer_mode specifies XFER xfer_mode + * @param pdev specifies platform_device + * + * @return EINVAL speed out of range, or illegal mode + */ +static int set_ata_bus_timing(u8 xfer_mode, struct platform_device *pdev) +{ + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) + pdev->dev.platform_data; + struct ata_host *host = dev_get_drvdata(&pdev->dev); + + /* get the bus clock cycle time, in ns */ + int T = 1 * 1000 * 1000 * 1000 / plat->get_clk_rate(); + struct fsl_ata_time_regs tr = {0}; + DPRINTK("clk_rate = %d T = %d\n",plat->get_clk_rate(), T); + + /* + * every mode gets the same t_off and t_on + */ + tr.time_off = 3; + tr.time_on = 3; + + if (xfer_mode >= XFER_UDMA_0) { + int speed = xfer_mode - XFER_UDMA_0; + if (speed >= NR_UDMA_SPECS) { + return -EINVAL; + } + tr.time_ack = (udma_specs[speed].tACK + T) / T; + tr.time_env = (udma_specs[speed].tENV_min + T) / T; + tr.time_rpx = (udma_specs[speed].tRP + T) / T + 2; + + tr.time_zah = (udma_specs[speed].tZAH + T) / T; + tr.time_mlix = (udma_specs[speed].tMLI + T) / T; + tr.time_dvh = (udma_specs[speed].tDVH + T) / T + 1; + tr.time_dzfs = (udma_specs[speed].tDZFS + T) / T; + + tr.time_dvs = (udma_specs[speed].tDVS + T) / T; + tr.time_cvh = (udma_specs[speed].tCVH + T) / T; + tr.time_ss = (udma_specs[speed].tSS + T) / T; + tr.time_cyc = (udma_specs[speed].tCYC + T) / T; + } else if (xfer_mode >= XFER_MW_DMA_0) { + int speed = xfer_mode - XFER_MW_DMA_0; + if (speed >= NR_MDMA_SPECS) { + return -EINVAL; + } + tr.time_m = (mdma_specs[speed].tM + T) / T; + tr.time_jn = (mdma_specs[speed].tJNH + T) / T; + tr.time_d = (mdma_specs[speed].tD + T) / T; + + tr.time_k = (mdma_specs[speed].tKW + T) / T; + } else { + int speed = xfer_mode - XFER_PIO_0; + if (speed >= NR_PIO_SPECS) { + return -EINVAL; + } + tr.time_1 = (pio_specs[speed].t1 + T) / T; + tr.time_2w = (pio_specs[speed].t2_8 + T) / T; + + tr.time_2r = (pio_specs[speed].t2_8 + T) / T; + tr.time_ax = (pio_specs[speed].tA + T) / T + 2; + tr.time_pio_rdx = 1; + tr.time_4 = (pio_specs[speed].t4 + T) / T; + + tr.time_9 = (pio_specs[speed].t9 + T) / T; + } + + update_timing_config(&tr, host); + + return 0; +} + +static void pata_fsl_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + set_ata_bus_timing(adev->pio_mode, to_platform_device(ap->dev)); +} + +#ifdef CONFIG_FSL_PATA_USE_DMA +static void pata_fsl_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + struct pata_fsl_priv *priv = ap->host->private_data; + + priv->ultra = adev->dma_mode >= XFER_UDMA_0; + + set_ata_bus_timing(adev->dma_mode, to_platform_device(ap->dev)); +} +#endif + +static int pata_fsl_port_start(struct ata_port *ap) +{ + return 0; +} + +#ifdef CONFIG_FSL_PATA_USE_DMA +static void dma_callback(void *arg, int error_status, unsigned int count) +{ + struct ata_port *ap = arg; + struct pata_fsl_priv *priv = ap->host->private_data; + u8 *ata_regs = priv->fsl_ata_regs; + + priv->dma_done = 1; + /* + * DMA is finished, so unmask INTRQ from the drive to allow the + * normal ISR to fire. + */ +#if 0 + __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN); +#else + WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN); +#endif + mb(); +} + +static void pata_fsl_bmdma_setup(struct ata_queued_cmd *qc) +{ + int nr_sg = 0; + int chan; + int dma_mode = 0, dma_ultra; + u8 ata_control; + struct ata_port *ap = qc->ap; + struct pata_fsl_priv *priv = ap->host->private_data; + u8 *ata_regs = priv->fsl_ata_regs; + struct fsl_ata_platform_data *plat = ap->dev->platform_data; + struct scatterlist tmp[plat->max_sg], *tsg, *sg; + int err; + + DPRINTK("ENTER\n"); + + priv->dma_dir = qc->dma_dir; + + /* + * Configure the on-chip ATA interface hardware. + */ + dma_ultra = priv->ultra ? + FSL_ATA_CTRL_DMA_ULTRA : 0; + + ata_control = FSL_ATA_CTRL_FIFO_RST_B | + FSL_ATA_CTRL_ATA_RST_B | + FSL_ATA_CTRL_DMA_PENDING | + dma_ultra; + + if (qc->dma_dir == DMA_TO_DEVICE) { + chan = priv->dma_wchan; + ata_control |= FSL_ATA_CTRL_FIFO_TX_EN | + FSL_ATA_CTRL_DMA_WRITE; + dma_mode = DMA_MODE_WRITE; + } else { + chan = priv->dma_rchan; + ata_control |= FSL_ATA_CTRL_FIFO_RCV_EN; + dma_mode = DMA_MODE_READ; + } +#if 0 + __raw_writel(ata_control, ata_regs + FSL_ATA_CONTROL); + __raw_writel(plat->fifo_alarm, ata_regs + FSL_ATA_FIFO_ALARM); + __raw_writel(FSL_ATA_INTR_ATA_INTRQ1, ata_regs + FSL_ATA_INT_EN); +#else + WRITE_ATA8(ata_control, FSL_ATA_CONTROL); + WRITE_ATA8(plat->fifo_alarm, FSL_ATA_FIFO_ALARM); + WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ1, FSL_ATA_INT_EN); +#endif + mb(); + + /* + * Set up the DMA completion callback. + */ + mxc_dma_callback_set(chan, dma_callback, (void *)ap); + + /* + * Copy the sg list to an array. + */ + tsg = tmp; + ata_for_each_sg(sg, qc) { + memcpy(tsg, sg, sizeof *sg); + tsg++; + nr_sg++; + } + + err = mxc_dma_sg_config(chan, tmp, nr_sg, 0, dma_mode); + if (err) { + printk(KERN_ERR "pata_fsl_bmdma_setup: error %d\n", err); + } + DPRINTK("EXIT\n"); +} + +static void pata_fsl_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_fsl_priv *priv = ap->host->private_data; + int chan; + int err; + + /* + * Start the channel. + */ + chan = qc->dma_dir == DMA_TO_DEVICE ? priv->dma_wchan : priv->dma_rchan; + + priv->dma_done = 0; + + err = mxc_dma_enable(chan); + if (err) { + printk(KERN_ERR "%s: : error %d\n", __func__, err); + } + + ap->ops->exec_command(ap, &qc->tf); +} + +static void pata_fsl_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + /* do a dummy read as in ata_bmdma_stop */ + ata_altstatus(ap); +} + +static u8 pata_fsl_bmdma_status(struct ata_port *ap) +{ + struct pata_fsl_priv *priv = ap->host->private_data; + + return priv->dma_done ? ATA_DMA_INTR : 0; +} + +static void pata_fsl_dma_init(struct ata_port *ap) +{ + struct pata_fsl_priv *priv = ap->host->private_data; + + priv->dma_rchan = -1; + priv->dma_wchan = -1; + + priv->dma_rchan = mxc_dma_request(MXC_DMA_ATA_RX, "MXC ATA RX"); + if (priv->dma_rchan < 0) { + dev_printk(KERN_ERR, ap->dev, "couldn't get RX DMA channel\n"); + goto err_out; + } + + priv->dma_wchan = mxc_dma_request(MXC_DMA_ATA_TX, "MXC ATA TX"); + if (priv->dma_wchan < 0) { + dev_printk(KERN_ERR, ap->dev, "couldn't get TX DMA channel\n"); + goto err_out; + } + + dev_printk(KERN_ERR, ap->dev, "rchan=%d wchan=%d\n", priv->dma_rchan, + priv->dma_wchan); + return; + +err_out: + ap->mwdma_mask = 0; + ap->udma_mask = 0; + mxc_dma_free(priv->dma_rchan); + mxc_dma_free(priv->dma_wchan); + kfree(priv); +} +#endif /* CONFIG_FSL_PATA_USE_DMA */ + +static void ata_dummy_noret(struct ata_port *ap) { return; } + +static struct scsi_host_template pata_fsl_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, +#ifdef CONFIG_FSL_PATA_USE_DMA + .dma_boundary = FSL_ATA_MAX_SG_LEN, +#endif + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations pata_fsl_port_ops = { + .set_piomode = pata_fsl_set_piomode, +#ifdef CONFIG_FSL_PATA_USE_DMA + .set_dmamode = pata_fsl_set_dmamode, +#endif + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_unknown, + +#ifdef CONFIG_FSL_PATA_USE_DMA + .bmdma_setup = pata_fsl_bmdma_setup, + .bmdma_start = pata_fsl_bmdma_start, +#endif + + .qc_prep = ata_noop_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_data_xfer_noirq, + + .irq_clear = ata_dummy_noret, + .irq_on = ata_irq_on, + + .port_start = pata_fsl_port_start, + +#ifdef CONFIG_FSL_PATA_USE_DMA + .bmdma_stop = pata_fsl_bmdma_stop, + .bmdma_status = pata_fsl_bmdma_status, +#endif +}; + +static void fsl_setup_port(struct ata_ioports *ioaddr) +{ + unsigned int shift = 2; + + ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift); + ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift); + ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift); + ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift); + ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift); + ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift); + ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift); + ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift); + ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift); + ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift); +} + +/** + * pata_fsl_probe - attach a platform interface + * @pdev: platform device + * + * Register a platform bus integrated ATA host controller + * + * The 3 platform device resources are used as follows: + * + * - I/O Base (IORESOURCE_MEM) virt. addr. of ATA controller regs + * - CTL Base (IORESOURCE_MEM) unused + * - IRQ (IORESOURCE_IRQ) platform IRQ assigned to ATA + * + */ +static int __devinit pata_fsl_probe(struct platform_device *pdev) +{ + struct resource *io_res; + struct ata_host *host; + struct ata_port *ap; + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) + pdev->dev.platform_data; + struct pata_fsl_priv *priv; + u8 *ata_regs; + int ret; + + DPRINTK("ENTER\n"); + /* + * Get an ata_host structure for this device + */ + host = ata_host_alloc(&pdev->dev, 1); + if (!host) + return -ENOMEM; + ap = host->ports[0]; + + /* + * Allocate private data + */ + priv = kzalloc(sizeof (struct pata_fsl_priv), GFP_KERNEL); + if(priv == NULL) { + /* free(host); */ + return -ENOMEM; + } + host->private_data = priv; + + /* + * Set up resources + */ + if (unlikely(pdev->num_resources != 3)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ata_regs = (u8 *)io_res->start; + priv->fsl_ata_regs = ata_regs; + ap->ioaddr.cmd_addr = (void *)(ata_regs + FSL_ATA_DRIVE_DATA); + ap->ioaddr.ctl_addr = (void *)(ata_regs + FSL_ATA_DRIVE_CONTROL); + ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; + ap->ops = &pata_fsl_port_ops; + ap->pio_mask = 0x7F; +#ifdef CONFIG_FSL_PATA_USE_DMA + ap->mwdma_mask = 0x7F; + ap->udma_mask = plat->udma_mask; + pata_fsl_sht.sg_tablesize = plat->max_sg; +#else + ap->mwdma_mask = 0x00; + ap->udma_mask = 0x00; +#endif + fsl_setup_port(&ap->ioaddr); + + /* + * Do platform-specific initialization (e.g. allocate pins, + * turn on clock). After this call it is assumed that + * plat->get_clk_rate() can be called to calculate + * timing. + */ + if (plat->init && plat->init(pdev)) { + /* REVISIT: don't leak what ata_host_alloc() allocated */ + return -ENODEV; + } + + /* Deassert the reset bit to enable the interface */ + WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL); + mb(); + + /* Set initial timing and mode */ + set_ata_bus_timing(XFER_PIO_4, pdev); + +#ifdef CONFIG_FSL_PATA_USE_DMA + /* get DMA ready */ + pata_fsl_dma_init(ap); +#endif + + /* + * Enable the ATA INTRQ interrupt from the bus, but + * only allow the CPU to see it (INTRQ2) at this point. + * INTRQ1, which goes to the DMA, will be enabled later. + */ +#if 0 + __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN); +#else + WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN); +#endif + mb(); + + /* activate */ + ret = ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt, + 0, &pata_fsl_sht); + DPRINTK("EXIT ret=%d\n", ret); + return ret; +} + +/** + * pata_fsl_remove - unplug a platform interface + * @pdev: platform device + * + * A platform bus ATA device has been unplugged. Perform the needed + * cleanup. Also called on module unload for any active devices. + */ +static int __devexit pata_fsl_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + struct pata_fsl_priv *priv = host->private_data; + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) + pdev->dev.platform_data; + u8 *ata_regs = priv->fsl_ata_regs; + +#if 0 + __raw_writel(0, ata_regs + FSL_ATA_INT_EN); /* Disable interrupts */ +#else + WRITE_ATA8(0, FSL_ATA_INT_EN); /* Disable interrupts */ +#endif + mb(); + + ata_host_detach(host); + + if (plat->exit) + plat->exit(); + + kfree(priv); + + return 0; +} + +#ifdef CONFIG_PM +static int pata_fsl_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct pata_fsl_priv *priv = host->private_data; + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) + pdev->dev.platform_data; + u8 *ata_regs = priv->fsl_ata_regs; + + /* Disable interrupts. */ +#if 0 + __raw_writel(0, ata_regs + FSL_ATA_INT_EN); +#else + WRITE_ATA8(0, FSL_ATA_INT_EN); +#endif + mb(); + + if (plat->exit) + plat->exit(); + + return 0; +} + +static int pata_fsl_resume(struct platform_device *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct pata_fsl_priv *priv = host->private_data; + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) + pdev->dev.platform_data; + u8 *ata_regs = priv->fsl_ata_regs; + + if (plat->init && plat->init(pdev)) { + return -ENODEV; + } + + /* Deassert the reset bit to enable the interface */ +#if 0 + __raw_writel(FSL_ATA_CTRL_ATA_RST_B, ata_regs + FSL_ATA_CONTROL); +#else + WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL); +#endif + mb(); + + /* Set initial timing and mode */ + set_ata_bus_timing(XFER_PIO_4, pdev); + + /* + * Enable hardware interrupts. + */ +#if 0 + __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN); +#else + WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN); +#endif + mb(); + + return 0; +} +#endif + +static struct platform_driver pata_fsl_driver = { + .probe = pata_fsl_probe, + .remove = __devexit_p(pata_fsl_remove), +#ifdef CONFIG_PM + .suspend = pata_fsl_suspend, + .resume = pata_fsl_resume, +#endif + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init pata_fsl_init(void) +{ + int ret; + + DPRINTK("ENTER\n"); + ret = platform_driver_register(&pata_fsl_driver); + DPRINTK("EXIT ret=%d\n", ret); + return ret; +} + +static void __exit pata_fsl_exit(void) +{ + platform_driver_unregister(&pata_fsl_driver); +} +module_init(pata_fsl_init); +module_exit(pata_fsl_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("low-level driver for Freescale ATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -60,6 +60,69 @@ config CRYPTO_DEV_GEODE To compile this driver as a module, choose M here: the module will be called geode-aes. +config CRYPTO_DEV_MCFCAU + bool "Support for Freescale Coldfire Cryptographic Acceleration Unit (CAU)" + depends on M5445X + select CRYPTO_ALGAPI + help + The cryptographic acceleration unit (CAU) is a ColdFire coprocessor + implementing a set of specialized operations in hardware. For example, you can + find it on MCF5445X. + +config CRYPTO_DEV_MCFCAU_DES + tristate "DES and Triple DES cipher algorithms (MCF5445X)" + depends on CRYPTO_DEV_MCFCAU + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + + Say 'Y' here to use the CAU coprocessor for + the CryptoAPI DES and 3DES alogrithms. + + To compile this driver as a module, choose M here: the module + will be called mcfcau-des. + +config CRYPTO_DEV_MCFCAU_AES + tristate "AES cipher algorithm (MCF5445X)" + depends on CRYPTO_DEV_MCFCAU + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + AES cipher algorithm (FIPS 197). + + Say 'Y' here to use the CAU coprocessor for + the CryptoAPI AES alogrithm. + + To compile this driver as a module, choose M here: the module + will be called mcfcau-aes. + +config CRYPTO_DEV_MCFCAU_MD5 + tristate "MD5 digest algorithm (MCF5445X)" + depends on CRYPTO_DEV_MCFCAU + select CRYPTO_ALGAPI + help + MD5 message digest algorithm (RFC1321). + + Say 'Y' here to use the CAU coprocessor for + the CryptoAPI MD5 alogrithm. + + To compile this driver as a module, choose M here: the module + will be called mcfcau-md5. + +config CRYPTO_DEV_MCFCAU_SHA1 + tristate "SHA1 digest algorithm (MCF5445X)" + depends on CRYPTO_DEV_MCFCAU + select CRYPTO_ALGAPI + help + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). + + Say 'Y' here to use the CAU coprocessor for + the CryptoAPI SHA1 alogrithm. + + To compile this driver as a module, choose M here: the module + will be called mcfcau-sha1. + config ZCRYPT tristate "Support for PCI-attached cryptographic adapters" depends on S390 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -2,3 +2,8 @@ obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o +obj-$(CONFIG_CRYPTO_DEV_MCFCAU) += mcfcau.o +obj-$(CONFIG_CRYPTO_DEV_MCFCAU_DES) += mcfcau-des.o +obj-$(CONFIG_CRYPTO_DEV_MCFCAU_AES) += mcfcau-aes.o +obj-$(CONFIG_CRYPTO_DEV_MCFCAU_MD5) += mcfcau-md5.o +obj-$(CONFIG_CRYPTO_DEV_MCFCAU_SHA1) += mcfcau-sha1.o --- /dev/null +++ b/drivers/crypto/mcfcau-aes.c @@ -0,0 +1,311 @@ + /*************************************************************************** + * mcfcau-aes.c - Implementation of AES Cipher Algorithm + * for Freescale ColdFire Cryptographic Acceleration Unit (CAU). + * + * Author: Andrey Butok + * Copyright Freescale Semiconductor Inc. 2007 + * + * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235. + * + * 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. + * + *************************************************************************** + * Changes: + * v0.01 17 September 2007 Andrey Butok + * Initial Release - developed on 2.6.20 Linux kernel. + */ + +#include +#include +#include +#include +#include + +/* +#undef DEBUG +#define DEBUG 1 +*/ + +#include "mcfcau.h" + +#define MCFCAU_AES_MIN_KEY_SIZE (16) +#define MCFCAU_AES_MAX_KEY_SIZE (32) +#define MCFCAU_AES_BLOCK_SIZE (16) + +#define MCFCAU_AES_DRIVER_DESC "AES ColdFire CAU driver" +#define MCFCAU_AES_DRIVER_VERSION "v0.01" + +struct mcfcau_aes_ctx { + int Nr_1; + u32 buf[120]; + u32 buf_tmp[16]; +}; + +static u32 mcfcau_rco_tab[10]={ 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1b000000, 0x36000000}; + +int mcfcau_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct mcfcau_aes_ctx *ctx = crypto_tfm_ctx(tfm); + const u32 * key = (const u32 *)in_key; + u32 *flags = &tfm->crt_flags; + u32 i; + u32* key_sch = (&ctx->buf[0]); + u32 * temp_p, * rcon_p; + u32 Nx; + u32 Nk; + unsigned long iflags; + + DBG("\n"); + + if (key_len % 8) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + Nk = key_len>>2; + + for(i=0;iNr_1 = Nk+5; + + /* Key Expansion */ + temp_p=&key_sch[Nk-1]; + rcon_p=&mcfcau_rco_tab[0]; + + spin_lock_irqsave(&mcfcau_lock, iflags); + + asm volatile ("move.l %0, %%a1"::"m"(temp_p):"a1"); + asm volatile ("move.l %0, %%a3"::"m"(rcon_p):"a3"); + asm volatile ("move.l %0, %%a4"::"m"(key_sch):"a4"); + + Nx=(Nk+7)<<2; /* (Nr+1)*Nb */ + + for(i=Nk; i6) && (i%Nk ==4)){ + /* SubWord(ACC) */ + asm volatile ("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_AESS+MCFCAU_CAA)); + } + + /* key_sch[i]^=key_sch[i-Nk]; store ACC to key_sch[i] */ + asm volatile ("cp0ld.l (%%a4)+,%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CAA):"a4"); + asm volatile ("cp0st.l %%d0,(%%a1),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CAA)); + } + spin_unlock_irqrestore(&mcfcau_lock, iflags); + + return 0; +} + + +/* encrypt a block of text */ +static void mcfcau_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + struct mcfcau_aes_ctx *ctx = crypto_tfm_ctx(tfm); + const int Nr_1 = ctx->Nr_1; + + u32* key_sch = &(ctx->buf[0]); + u32 i; + unsigned long iflags; + + DBG("\n"); + + spin_lock_irqsave(&mcfcau_lock, iflags); + asm("move.l %0, %%a1"::"m"(in):"a1"); + asm("move.l %0, %%a0"::"m"(key_sch):"a0"); + /* state=in */ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1):"a1"); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA2):"a1"); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA3):"a1"); + /* AddRoundKey() */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA0):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA1):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA2):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA3):"a0"); + + for(i=Nr_1;i>0;i--){ + /* SubBytes(state) */ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESS+MCFCAU_CA0)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESS+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESS+MCFCAU_CA2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESS+MCFCAU_CA3)); + /* ShiftRows(state) */ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESR)); + /* MixColumns(state); AddRoundKey() */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_AESC+MCFCAU_CA0):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_AESC+MCFCAU_CA1):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_AESC+MCFCAU_CA2):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_AESC+MCFCAU_CA3):"a0"); + } + /* SubBytes(state)*/ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESS+MCFCAU_CA0)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESS+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESS+MCFCAU_CA2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESS+MCFCAU_CA3)); + /* ShiftRows(state) */ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESR)); + /* AddRoundKey() */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA0):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA1):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA2):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA3):"a0"); + /* out = state */ + asm("move.l %0, %%a1" ::"m"(out):"a1"); + asm("cp0st.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA0):"d0"); + asm("cp0st.l %%d0,%%d1,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA1):"d1"); + + asm("move.l %%d0,(%%a1)+":::"a1"); + asm("move.l %%d1,(%%a1)+":::"a1"); + + asm("cp0st.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA2):"d0"); + asm("cp0st.l %%d0,%%d1,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA3):"d1"); + + asm("move.l %%d0,(%%a1)+":::"a1"); + asm("move.l %%d1,(%%a1)+":::"a1"); + spin_unlock_irqrestore(&mcfcau_lock, iflags); +} + + +/* decrypt a block of text */ +static void mcfcau_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + struct mcfcau_aes_ctx *ctx = crypto_tfm_ctx(tfm); + u32* key_sch = &(ctx->buf[0]); + u32 i; + unsigned long iflags; + const int Nr_1 = ctx->Nr_1; + key_sch=&key_sch[(Nr_1+2)*4]; + + DBG("\n"); + + spin_lock_irqsave(&mcfcau_lock, iflags); + + asm("move.l %0, %%a1"::"m"(in):"a1"); + asm("move.l %0, %%a0"::"m"(key_sch):"a0"); + /* state=in */ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1):"a1"); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA2):"a1"); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA3):"a1"); + /* AddRoundKey() */ + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA3):"a0"); + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA2):"a0"); + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA1):"a0"); + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA0):"a0"); + + for(i=Nr_1;i>0;i--){ + /* InvShiftRows(state) */ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIR)); + /* InvSubBytes(state) */ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIS+MCFCAU_CA3)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIS+MCFCAU_CA2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIS+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIS+MCFCAU_CA0)); + /* InvMixColumns(state); AddRoundKey() */ + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_AESIC+MCFCAU_CA3):"a0"); + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_AESIC+MCFCAU_CA2):"a0"); + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_AESIC+MCFCAU_CA1):"a0"); + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_AESIC+MCFCAU_CA0):"a0"); + } + /* InvShiftRows(state) */ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIR)); + /* InvSubBytes(state)*/ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIS+MCFCAU_CA3)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIS+MCFCAU_CA2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIS+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_AESIS+MCFCAU_CA0)); + /* AddRoundKey() */ + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA3):"a0"); + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA2):"a0"); + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA1):"a0"); + asm("cp0ld.l -(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA0):"a0"); + /* out = state */ + asm("move.l %0, %%a1" ::"m"(out):"a1"); + asm("cp0st.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA0):"d0"); + asm("cp0st.l %%d0,%%d1,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA1):"d1"); + + asm("move.l %%d0,(%%a1)+":::"a1"); + asm("move.l %%d1,(%%a1)+":::"a1"); + + asm("cp0st.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA2):"d0"); + asm("cp0st.l %%d0,%%d1,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA3):"d1"); + + asm("move.l %%d0,(%%a1)+":::"a1"); + asm("move.l %%d1,(%%a1)+":::"a1"); + spin_unlock_irqrestore(&mcfcau_lock, iflags); + +} + + +static struct crypto_alg mcfcau_aes_alg = { + .cra_name = "aes", + .cra_driver_name = "aes-mcfcau", + .cra_priority = MCFCAU_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = MCFCAU_AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct mcfcau_aes_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(mcfcau_aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = MCFCAU_AES_MIN_KEY_SIZE, + .cia_max_keysize = MCFCAU_AES_MAX_KEY_SIZE, + .cia_setkey = mcfcau_aes_setkey, + .cia_encrypt = mcfcau_aes_encrypt, + .cia_decrypt = mcfcau_aes_decrypt + } + } +}; + +static int __init mcfcau_aes_init(void) +{ + int ret = crypto_register_alg(&mcfcau_aes_alg); + + printk(KERN_INFO MCFCAU_AES_DRIVER_DESC " " + MCFCAU_AES_DRIVER_VERSION " %s.\n",ret?"failed":"registered"); + return ret; +} + +static void __exit mcfcau_aes_fini(void) +{ + crypto_unregister_alg(&mcfcau_aes_alg); + printk(KERN_INFO MCFCAU_AES_DRIVER_DESC " " + MCFCAU_AES_DRIVER_VERSION " unregistered.\n"); +} + +module_init(mcfcau_aes_init); +module_exit(mcfcau_aes_fini); + +MODULE_DESCRIPTION(MCFCAU_AES_DRIVER_DESC); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Andrey Butok"); --- /dev/null +++ b/drivers/crypto/mcfcau.c @@ -0,0 +1,32 @@ +/*************************************************************************** + * mcfcau.c - Implementation of DES & Triple DES EDE Cipher Algorithms + * for Freescale ColdFire Cryptographic Acceleration Unit (CAU). + * + * Author: Andrey Butok + * Copyright Freescale Semiconductor Inc. 2007 + * + * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235. + * + * 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. + * + *************************************************************************** + * Changes: + * v0.01 28 September 2006 Andrey Butok + * Initial Release - developed on 2.6.20 Linux kernel. + */ +#include + +DEFINE_SPINLOCK(mcfcau_lock); +EXPORT_SYMBOL(mcfcau_lock); --- /dev/null +++ b/drivers/crypto/mcfcau-des.c @@ -0,0 +1,437 @@ +/*************************************************************************** + * mcfcau-des.c - Implementation of DES & Triple DES EDE Cipher Algorithms + * for Freescale ColdFire Cryptographic Acceleration Unit (CAU). + * + * Author: Andrey Butok + * Copyright Freescale Semiconductor Inc. 2007 + * + * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235. + * + * 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. + * + *************************************************************************** + * Changes: + * v0.01 14 August 2007 Andrey Butok + * Initial Release - developed on 2.6.20 Linux kernel. + */ + +#include +#include +#include +#include +#include + +/* +#undef DEBUG +#define DEBUG 1 +*/ + +#include "mcfcau.h" + +#define MCFCAU_DES_KEY_SIZE (8) +#define MCFCAU_DES_EXPKEY_WORDS (32) +#define MCFCAU_DES_BLOCK_SIZE (8) + +#define MCFCAU_DES3_EDE_KEY_SIZE (3 * MCFCAU_DES_KEY_SIZE) +#define MCFCAU_DES3_EDE_EXPKEY_WORDS (3 * MCFCAU_DES_EXPKEY_WORDS) +#define MCFCAU_DES3_EDE_BLOCK_SIZE (MCFCAU_DES_BLOCK_SIZE) + +#define MCFCAU_DES_DRIVER_DESC "DES & 3DES ColdFire CAU driver" +#define MCFCAU_DES_DRIVER_VERSION "v0.01" + +struct mcfcau_des_ctx { + u32 expkey[MCFCAU_DES_EXPKEY_WORDS]; +}; + +struct mcfcau_des3_ede_ctx { + u32 expkey[MCFCAU_DES3_EDE_EXPKEY_WORDS]; +}; + +/* DES round operations */ +static inline void mcfcau_des_encipher(void) +{ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESK)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_IP+MCFCAU_KSL1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSL1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_FP+MCFCAU_KSL1)); +} + +static inline void mcfcau_des_decipher(void) +{ + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESK+MCFCAU_DC)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_IP+MCFCAU_KSR1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR2)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_KSR1)); + asm("cp0ld.l %%d0,%%d0,#1,%0"::"n"(MCFCAU_DESR+MCFCAU_FP+MCFCAU_KSL1)); +} + + +static int mcfcau_des_setkey(struct crypto_tfm *tfm, const u8 *key_p, + unsigned int keylen) +{ + struct mcfcau_des_ctx *dctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + u32 * key = (u32 *) key_p; + + DBG("\n"); + + /* + * RFC2451: Weak key checks SHOULD be performed. + * + * FIPS 74: + * Keys having duals are keys which produce all zeros, all ones, or + * alternating zero-one patterns in the C and D registers after Permuted + * Choice 1 has operated on the key. + * + */ + if(*flags & CRYPTO_TFM_REQ_WEAK_KEY){ /* FIPS 74 */ + if(key[0]<0xE001E00l){ + if(key[0]<0x1FE01FE0){ + if(key[0]<0x01E001E0){ + if(((key[0]==0x01010101)&&(key[1]==0x01010101))|| + ((key[0]==0x011F011F)&&(key[1]==0x010E010E)) ) + goto WEAK_KEY; + } + else{ + if(((key[0]==0x01E001E0)&&(key[1]==0x01F101F1))|| + ((key[0]==0x01FE01FE)&&(key[1]==0x01FE01FE)) ) + goto WEAK_KEY; + } + } + else{ + if(key[0]<0x1F1F1F1F){ + if(((key[0]==0x1FE01FE0)&&(key[1]==0x0EF10EF1))|| + ((key[0]==0x1F011F0l)&&(key[1]==0x0E010E01)) ) + goto WEAK_KEY; + } + else{ + if(((key[0]==0x1F1F1F1F)&&(key[1]==0x0E0E0E0E))|| + ((key[0]==0x1FFE1FFE)&&(key[1]==0x0EFE0EFE)) ) + goto WEAK_KEY; + } + } + } else { + if(key[0]<0xFE01FE01){ + if(key[0]<0xE0E0E0E0){ + if(((key[0]==0xE001E00l)&&(key[1]==0xF101F101))|| + ((key[0]==0xE01FE01F)&&(key[1]==0xF10EF10E)) ) + goto WEAK_KEY; + } + else{ + if(((key[0]==0xE0E0E0E0)&&(key[1]==0xF1F1F1F1))|| + ((key[0]==0xE0FEE0FE)&&(key[1]==0xF1FEF1FE)) ) + goto WEAK_KEY; + } + } + else{ + if(key[0]<0xFEE0FEE0){ + if(((key[0]==0xFE01FE01)&&(key[1]==0xFE01FE01))|| + ((key[0]==0xFE1FFE1F)&&(key[1]==0xFE0EFE0E)) ) + goto WEAK_KEY; + } + else{ + if(((key[0]==0xFEE0FEE0)&&(key[1]==0xFEF1FEF1))|| + ((key[0]==0xFEFEFEFE)&&(key[1]==0xFEFEFEFE)) ) + goto WEAK_KEY; + } + } + } + } + memcpy(dctx->expkey, key_p, keylen); + return 0; +WEAK_KEY: + *flags |= CRYPTO_TFM_RES_WEAK_KEY; + return -EINVAL; +} + + +void mcfcau_des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct mcfcau_des_ctx *ctx = crypto_tfm_ctx(tfm); + u32 * des_key_tmp = ctx->expkey; + unsigned long iflags; + + DBG("\n"); + + spin_lock_irqsave(&mcfcau_lock, iflags); + + asm("move.l %0, %%a0"::"m"(src):"a0"); + asm("move.l %0, %%a1"::"m"(des_key_tmp):"a1"); + + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA2):"a0"); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA3)); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1)); + + mcfcau_des_encipher(); + + asm("cp0st.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA2):"d0"); + asm("cp0st.l %%d0,%%d1,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA3):"d1"); + asm("move.l %0, %%a1" ::"m"(dst):"a1"); + asm("move.l %d0,(%a1)+"); + asm("move.l %d1,(%a1)"); + + spin_unlock_irqrestore(&mcfcau_lock, iflags); +} + + +void mcfcau_des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct mcfcau_des_ctx *ctx = crypto_tfm_ctx(tfm); + u32 * des_key_tmp = ctx->expkey; + unsigned long iflags; + + DBG("\n"); + + spin_lock_irqsave(&mcfcau_lock, iflags); + + asm("move.l %0, %%a0"::"m"(src):"a0"); + asm("move.l %0, %%a1"::"m"(des_key_tmp):"a1"); + + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA2):"a0"); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA3)); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1)); + + mcfcau_des_decipher(); + + asm("move.l %0, %%a1" ::"m"(dst):"a1"); + asm("cp0st.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA2):"d0"); + asm("cp0st.l %%d0,%%d1,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA3):"d1"); + asm("move.l %d0,(%a1)+"); + asm("move.l %d1,(%a1)"); + + spin_unlock_irqrestore(&mcfcau_lock, iflags); +} + + +/* + * RFC2451: + * + * For DES-EDE3, there is no known need to reject weak or + * complementation keys. Any weakness is obviated by the use of + * multiple keys. + * + * However, if the first two or last two independent 64-bit keys are + * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the + * same as DES. Implementers MUST reject keys that exhibit this + * property. + * + */ + +static int mcfcau_des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key_p, unsigned int keylen) +{ + const u32 *key = (const u32 *)key_p; + struct mcfcau_des3_ede_ctx *dctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + +DBG("\n"); + + if (unlikely(!((key[0] ^ key[2]) | (key[1] ^ key[3])) || + !((key[2] ^ key[4]) | (key[3] ^ key[5])))) + { + *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; + return -EINVAL; + } + + memcpy(dctx->expkey,key_p,keylen); + + return 0; +} + +static void mcfcau_des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct mcfcau_des3_ede_ctx *dctx = crypto_tfm_ctx(tfm); + const u32 * des_key_tmp = dctx->expkey; + unsigned long iflags; + + DBG("\n"); + + spin_lock_irqsave(&mcfcau_lock, iflags); + + /*EK1*/ + asm("move.l %0, %%a0"::"m"(src):"a0"); + asm("move.l %0, %%a1"::"m"(des_key_tmp):"a1"); + + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA2):"a0"); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA3)); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1):"a1"); + + mcfcau_des_encipher(); + + /*DK2*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1):"a1"); + + mcfcau_des_decipher(); + + /*EK3*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1)); + + mcfcau_des_encipher(); + + asm("move.l %0, %%a1" ::"m"(dst):"a1"); + asm("cp0st.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA2):"d0"); + asm("cp0st.l %%d0,%%d1,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA3):"d1"); + asm("move.l %d0,(%a1)+"); + asm("move.l %d1,(%a1)"); + + spin_unlock_irqrestore(&mcfcau_lock, iflags); +} + +static void mcfcau_des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct mcfcau_des3_ede_ctx *dctx = crypto_tfm_ctx(tfm); + const u32 * des_key_tmp = dctx->expkey + 6 - 2; + unsigned long iflags; + + DBG("\n"); + + spin_lock_irqsave(&mcfcau_lock, iflags); + + /*DK3*/ + asm("move.l %0, %%a0"::"m"(src):"a0"); + asm("move.l %0, %%a1"::"m"(des_key_tmp):"a1"); + + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA2):"a0"); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA3)); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1)); + + mcfcau_des_decipher(); + + /*EK2*/ + asm("suba.l #12,%a1"); /*dec key pointer*/ + + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1)); + + mcfcau_des_encipher(); + + /*DK1*/ + asm("suba.l #12,%a1"); /*dec key pointer*/ + + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a1"); + asm("cp0ld.l (%%a1),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1)); + + mcfcau_des_decipher(); + + asm("move.l %0, %%a1" ::"m"(dst):"a1"); + asm("cp0st.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA2):"d0"); + asm("cp0st.l %%d0,%%d1,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA3):"d1"); + asm("move.l %d0,(%a1)+"); + asm("move.l %d1,(%a1)"); + + spin_unlock_irqrestore(&mcfcau_lock, iflags); +} + + +static struct crypto_alg mcfcau_des_alg = { + .cra_name = "des", + .cra_driver_name = "des-mcfcau", + .cra_priority = MCFCAU_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = MCFCAU_DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct mcfcau_des_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(mcfcau_des_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = MCFCAU_DES_KEY_SIZE, + .cia_max_keysize = MCFCAU_DES_KEY_SIZE, + .cia_setkey = mcfcau_des_setkey, + .cia_encrypt = mcfcau_des_encrypt, + .cia_decrypt = mcfcau_des_decrypt } } +}; + +static struct crypto_alg mcfcau_des3_ede_alg = { + .cra_name = "des3_ede", + .cra_driver_name = "des3_ede-mcfcau", + .cra_priority = MCFCAU_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = MCFCAU_DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct mcfcau_des3_ede_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(mcfcau_des3_ede_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = MCFCAU_DES3_EDE_KEY_SIZE, + .cia_max_keysize = MCFCAU_DES3_EDE_KEY_SIZE, + .cia_setkey = mcfcau_des3_ede_setkey, + .cia_encrypt = mcfcau_des3_ede_encrypt, + .cia_decrypt = mcfcau_des3_ede_decrypt } } +}; + +MODULE_ALIAS("mcfcau_des3_ede"); + +static int __init mcfcau_des_init(void) +{ + int ret; + + ret = crypto_register_alg(&mcfcau_des_alg); + if (ret < 0) + goto out; + + ret = crypto_register_alg(&mcfcau_des3_ede_alg); + if (ret < 0) + crypto_unregister_alg(&mcfcau_des_alg); +out: + printk(KERN_INFO MCFCAU_DES_DRIVER_DESC " " + MCFCAU_DES_DRIVER_VERSION " %s.\n",ret?"failed":"registered"); + return ret; +} + +static void __exit mcfcau_des_exit(void) +{ + crypto_unregister_alg(&mcfcau_des3_ede_alg); + crypto_unregister_alg(&mcfcau_des_alg); + + printk(KERN_INFO MCFCAU_DES_DRIVER_DESC " " + MCFCAU_DES_DRIVER_VERSION " unregistered.\n"); +} + +module_init(mcfcau_des_init); +module_exit(mcfcau_des_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms for ColdFire CAU"); +MODULE_AUTHOR("Andrey Butok"); --- /dev/null +++ b/drivers/crypto/mcfcau.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * mcfcau.h - Common header file for Freescale ColdFire + * Cryptographic Acceleration Unit (CAU) drivers. + * + * Author: Andrey Butok + * Copyright Freescale Semiconductor Inc. 2007 + * + * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235. + * + * 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. + * + *************************************************************************** + * Changes: + * v0.01 14 August 2007 Andrey Butok + */ + +#ifndef MCFCAU_H +#define MCFCAU_H + +#include + +/* CAU Registers (CAx) */ +#define MCFCAU_CASR (0x0) +#define MCFCAU_CAA (0x1) +#define MCFCAU_CA0 (0x2) +#define MCFCAU_CA1 (0x3) +#define MCFCAU_CA2 (0x4) +#define MCFCAU_CA3 (0x5) +#define MCFCAU_CA4 (0x6) +#define MCFCAU_CA5 (0x7) + + /* CAU Commands */ +#define MCFCAU_CNOP (0x000) +#define MCFCAU_LDR (0x010) +#define MCFCAU_STR (0x020) +#define MCFCAU_ADR (0x030) +#define MCFCAU_RADR (0x040) +#define MCFCAU_ADRA (0x050) +#define MCFCAU_XOR (0x060) +#define MCFCAU_ROTL (0x070) +#define MCFCAU_MVRA (0x080) +#define MCFCAU_MVAR (0x090) +#define MCFCAU_AESS (0x0A0) +#define MCFCAU_AESIS (0x0B0) +#define MCFCAU_AESC (0x0C0) +#define MCFCAU_AESIC (0x0D0) +#define MCFCAU_AESR (0x0E0) +#define MCFCAU_AESIR (0x0F0) +#define MCFCAU_DESR (0x100) +#define MCFCAU_DESK (0x110) +#define MCFCAU_HASH (0x120) +#define MCFCAU_SHS (0x130) +#define MCFCAU_MDS (0x140) +#define MCFCAU_ILL (0x1F0) + +/* DESR Fields */ +#define MCFCAU_IP (0x08) /* initial permutation */ +#define MCFCAU_FP (0x04) /* final permutation */ +#define MCFCAU_KSL1 (0x00) /* key schedule left 1 bit */ +#define MCFCAU_KSL2 (0x01) /* key schedule left 2 bits */ +#define MCFCAU_KSR1 (0x02) /* key schedule right 1 bit */ +#define MCFCAU_KSR2 (0x03) /* key schedule right 2 bits */ + +/* DESK Field */ +#define MCFCAU_DC (0x01) /* decrypt key schedule */ +#define MCFCAU_CP (0x02) /* check parity */ + +/* HASH Functions Codes */ +#define MCFCAU_HFF (0x0) /* MD5 F() CA1&CA2 | ~CA1&CA3 */ +#define MCFCAU_HFG (0x1) /* MD5 G() CA1&CA3 | CA2&~CA3 */ +#define MCFCAU_HFH (0x2) /* MD5 H(), SHA Parity() CA1^CA2^CA3 */ +#define MCFCAU_HFI (0x3) /* MD5 I() CA2^(CA1|~CA3) */ +#define MCFCAU_HFC (0x4) /* SHA Ch() CA1&CA2 ^ ~CA1&CA3 */ +#define MCFCAU_HFM (0x5) /* SHA Maj() CA1&CA2 ^ CA1&CA3 ^ CA2&CA3 */ + +#define MCFCAU_CRA_PRIORITY (300) + +extern spinlock_t mcfcau_lock; + +#ifdef DEBUG +#define DBG(fmt, args...) printk( "[%s] " fmt , __FUNCTION__, ## args) +#else +#define DBG(fmt, args...) do{}while(0) +#endif + +#endif --- /dev/null +++ b/drivers/crypto/mcfcau-md5.c @@ -0,0 +1,654 @@ + /*************************************************************************** + * mcfcau-md5.c - Implementation of MD5 Message Digest Algorithm (RFC1321) + * for Freescale ColdFire Cryptographic Acceleration Unit (CAU). + * + * Author: Andrey Butok + * Copyright Freescale Semiconductor Inc. 2007 + * + * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235. + * + * 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. + * + *************************************************************************** + * Changes: + * v0.01 30 September 2007 Andrey Butok + * Initial Release - developed on 2.6.20 Linux kernel. + */ +#include +#include +#include +#include +#include +#include + +/* +#undef DEBUG +#define DEBUG 1 +*/ + +#include "mcfcau.h" + + +#define MCFCAU_MD5_DIGEST_SIZE (16) +#define MCFCAU_MD5_HMAC_BLOCK_SIZE (64) +#define MCFCAU_MD5_BLOCK_WORDS (16) +#define MCFCAU_MD5_HASH_WORDS (4) + +#define MCFCAU_MD5_DRIVER_DESC "MD5 ColdFire CAU driver" +#define MCFCAU_MD5_DRIVER_VERSION "v0.01" + + +struct mcfcau_md5_ctx { + u32 hash[MCFCAU_MD5_HASH_WORDS]; + u32 block[MCFCAU_MD5_BLOCK_WORDS]; + u64 byte_count; +}; + +u32 mcfcau_md5_t[64]={0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; + + + +static void mcfcau_md5_transform(u32 *hash, u32 const *in) +{ + int i; + u32 * md5_t_p=&mcfcau_md5_t[0]; + unsigned long iflags; + + spin_lock_irqsave(&mcfcau_lock, iflags); + asm("move.l %0, %%a1"::"m"(hash):"a1"); + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CAA):"a1");/*a*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1):"a1");/*b*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA2):"a1");/*c*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA3):"a1");/*d*/ + asm("move.l %0, %%a0"::"m"(in):"a0"); /* X[] */ + asm("move.l %0, %%a3"::"m"(md5_t_p):"a3"); /* T[] */ + + + /* Round 1 */ + asm("moveq.l #7, %%d4":::"d4"); /* for rotating by 7 */ + asm("moveq.l #12, %%d5":::"d5"); /* for rotating by 12 */ + asm("moveq.l #17, %%d6":::"d6"); /* for rotating by 17 */ + asm("moveq.l #22, %%d7":::"d7"); /* for rotating by 22 */ + + for(i=0; i<4;i++){ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFF)); /* a+F(b,c,d) */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); /* add byterev x[i] */ + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); /* add t[i] */ + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); /* rotate by 7 */ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); /* add b */ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); /* register to register shift */ + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFF)); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFF)); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFF)); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + }; + + + /* Round 2 */ + asm("moveq.l #5, %%d4":::"d4"); /* for rotating by 5 */ + asm("moveq.l #9, %%d5":::"d5"); /* for rotating by 9 */ + asm("moveq.l #14, %%d6":::"d6"); /* for rotating by 14 */ + asm("moveq.l #20, %%d7":::"d7"); /* for rotating by 20 */ + + asm("lea -60(%%a0),%%a0":::"a0"); + + for(i=0; i<2;i++){ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 20(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 20(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -44(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 20(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + }; + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 20(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -44(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 20(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 20(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -44(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 20(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 20(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFG)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + /* Round 3 */ + asm("moveq.l #4, %%d4":::"d4"); /* for rotating by 5 */ + asm("moveq.l #11, %%d5":::"d5"); /* for rotating by 9 */ + asm("moveq.l #16, %%d6":::"d6"); /* for rotating by 14 */ + asm("moveq.l #23, %%d7":::"d7"); /* for rotating by 20 */ + + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -52(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -52(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 12(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -52(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -8(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + /* Round 4 */ + asm("moveq.l #6, %%d4":::"d4"); /* for rotating by 6 */ + asm("moveq.l #10, %%d5":::"d5"); /* for rotating by 10 */ + asm("moveq.l #15, %%d6":::"d6"); /* for rotating by 15 */ + asm("moveq.l #21, %%d7":::"d7"); /* for rotating by 21 */ + + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -36(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -36(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -36(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -36(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -36(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d4,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea -36(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d5,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d6,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFI)); + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_RADR+MCFCAU_CAA):"a0"); + asm("lea 28(%%a0),%%a0" :::"a0"); + asm("cp0ld.l (%%a3)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a3"); + asm("cp0ld.l %%d7,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA1)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MDS)); + + + asm("move.l %0, %%a1"::"m"(hash):"a1"); + + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a1");/*a*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CA1):"a1");/*b*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CA2):"a1");/*c*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CA3):"a1");/*d*/ + + asm("cp0st.l %%d0,-(%%a1),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA3):"a1");/*d*/ + asm("cp0st.l %%d0,-(%%a1),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA2):"a1");/*c*/ + asm("cp0st.l %%d0,-(%%a1),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA1):"a1");/*b*/ + asm("cp0st.l %%d0,-(%%a1),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CAA):"a1");/*a*/ + spin_unlock_irqrestore(&mcfcau_lock, iflags); +} + +static inline void le32_to_cpu_array(u32 *buf, unsigned int words) +{ + while (words--) { + __le32_to_cpus(buf); + buf++; + } +} + +static inline void cpu_to_le32_array(u32 *buf, unsigned int words) +{ + while (words--) { + __cpu_to_le32s(buf); + buf++; + } +} + +static void mcfcau_md5_initialization(struct crypto_tfm *tfm) +{ + struct mcfcau_md5_ctx *mctx = crypto_tfm_ctx(tfm); + + DBG("\n"); + mctx->hash[0] = 0x67452301; + mctx->hash[1] = 0xefcdab89; + mctx->hash[2] = 0x98badcfe; + mctx->hash[3] = 0x10325476; + mctx->byte_count = 0; +} + +static void mcfcau_md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) +{ + struct mcfcau_md5_ctx *mctx = crypto_tfm_ctx(tfm); + const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); + + DBG("\n"); + mctx->byte_count += len; + + if (avail > len) { + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, len); + } + else { + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data, avail); + + mcfcau_md5_transform(mctx->hash, mctx->block); + data += avail; + len -= avail; + + while (len >= sizeof(mctx->block)) { + memcpy(mctx->block, data, sizeof(mctx->block)); + mcfcau_md5_transform(mctx->hash, mctx->block); + data += sizeof(mctx->block); + len -= sizeof(mctx->block); + } + + memcpy(mctx->block, data, len); + } +} + +static void mcfcau_md5_final(struct crypto_tfm *tfm, u8 *out) +{ + struct mcfcau_md5_ctx *mctx = crypto_tfm_ctx(tfm); + const unsigned int offset = mctx->byte_count & 0x3f; + char *p = (char *)mctx->block + offset; + int padding = 56 - (offset + 1); + + DBG("\n"); + + *p++ = 0x80; + if (padding < 0) { + memset(p, 0x00, padding + sizeof (u64)); + mcfcau_md5_transform(mctx->hash, mctx->block); + p = (char *)mctx->block; + padding = 56; + } + + memset(p, 0, padding); + mctx->block[14] = mctx->byte_count << 3; + mctx->block[15] = mctx->byte_count >> 29; + le32_to_cpu_array(&mctx->block[14], 2); + + mcfcau_md5_transform(mctx->hash, mctx->block); + + cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32)); + memcpy(out, mctx->hash, sizeof(mctx->hash)); + memset(mctx, 0, sizeof(*mctx)); +} + +static struct crypto_alg mcfcau_md5_alg = { + .cra_name = "md5", + .cra_driver_name = "md5-mcfcau", + .cra_priority = MCFCAU_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = MCFCAU_MD5_HMAC_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct mcfcau_md5_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(mcfcau_md5_alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = MCFCAU_MD5_DIGEST_SIZE, + .dia_init = mcfcau_md5_initialization, + .dia_update = mcfcau_md5_update, + .dia_final = mcfcau_md5_final } } +}; + +static int __init mcfcau_md5_init(void) +{ + int ret = crypto_register_alg(&mcfcau_md5_alg); + printk(KERN_INFO MCFCAU_MD5_DRIVER_DESC " " + MCFCAU_MD5_DRIVER_VERSION " %s.\n",ret?"failed":"registered"); + return ret; +} + +static void __exit mcfcau_md5_exit(void) +{ + crypto_unregister_alg(&mcfcau_md5_alg); + printk(KERN_INFO MCFCAU_MD5_DRIVER_DESC " " + MCFCAU_MD5_DRIVER_VERSION " unregistered.\n"); +} + +module_init(mcfcau_md5_init); +module_exit(mcfcau_md5_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(MCFCAU_MD5_DRIVER_DESC); +MODULE_AUTHOR("Andrey Butok"); --- /dev/null +++ b/drivers/crypto/mcfcau-sha1.c @@ -0,0 +1,280 @@ + /*************************************************************************** + * mcfcau-sha1.c - Implementation of SHA1 Secure Hash Algorithm + * for Freescale ColdFire Cryptographic Acceleration Unit (CAU). + * + * Author: Andrey Butok + * Copyright Freescale Semiconductor Inc. 2007 + * + * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235. + * + * 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. + * + *************************************************************************** + * Changes: + * v0.01 15 October 2007 Andrey Butok + * Initial Release - developed on 2.6.20 Linux kernel. + */ + +#include +#include +#include +#include +#include + + +/* +#undef DEBUG +#define DEBUG 1 +*/ + +#include "mcfcau.h" + +#define MCFCAU_SHA1_DIGEST_WORDS (5) +#define MCFCAU_SHA1_WORKSPACE_WORDS (80) + +#define MCFCAU_SHA1_DIGEST_SIZE (20) +#define MCFCAU_SHA1_HMAC_BLOCK_SIZE (64) + +#define MCFCAU_SHA1_DRIVER_DESC "SHA1 ColdFire CAU driver" +#define MCFCAU_SHA1_DRIVER_VERSION "v0.01" + +struct mcfcau_sha1_ctx { + u64 count; + u32 state[5]; + u8 buffer[64]; +}; + +const static u32 K[4]={0x5A827999L, /* Rounds 0-19: sqrt(2) * 2^30 */ + 0x6ED9EBA1L, /* Rounds 20-39: sqrt(3) * 2^30 */ + 0x8F1BBCDCL, /* Rounds 40-59: sqrt(5) * 2^30 */ + 0xCA62C1D6L}; /* Rounds 60-79: sqrt(10) * 2^30 */ + +static void noinline mcfcau_sha1_transform(__u32 *digest, const char *in, __u32 *W) +{ + int i; + u32 * tmp_p; + unsigned long iflags; + + /* (a) Devide M(i) into 16 words W */ + for (i = 0; i < 16; i++) + W[i] = ((const u32 *)in)[i]; + + /* (b) W[i+16] = S^1(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i]) */ + tmp_p=&W[16]; + + spin_lock_irqsave(&mcfcau_lock, iflags); + asm("move.l %0, %%a0"::"m"(tmp_p):"a0"); + asm("moveq.l #1, %%d3":::"d3"); + + for (i = 0; i < 64; i++){ + asm("cp0ld.l -64(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0)); + asm("cp0ld.l -56(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA0)); + asm("cp0ld.l -32(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA0)); + asm("cp0ld.l -12(%%a0),%%d0,#1,%0" ::"n"(MCFCAU_XOR+MCFCAU_CA0)); + asm("cp0ld.l %%d3,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CA0):"d3"); + asm("cp0st.l %%d0,(%%a0)+,#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA0)); + } + + /* (c) */ + asm("move.l %0, %%a0"::"m"(digest):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA0):"a0"); /* a */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA1):"a0"); /* b */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA2):"a0"); /* c */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA3):"a0"); /* d */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_LDR+MCFCAU_CA4):"a0"); /* e */ + + /* (d) */ + asm("moveq.l #5, %%d0":::"d0"); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_MVRA+MCFCAU_CA0)); + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ROTL+MCFCAU_CAA)); /*S^5(A)*/ + + tmp_p=(u32*)K; + asm("move.l %0, %%a0"::"m"(tmp_p):"a0"); + asm("move.l %0, %%a1"::"m"(W):"a1"); + + for (i = 0; i < 20; i++) { + /* t = f1(b, c, d) + K1 + rol32(a, 5) + e + W[i]; */ + /* e = d; d = c; c = rol32(b, 30); b = a; a = t; */ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFC)); /*f(b,c,d)*/ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA4)); /*+e*/ + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA)); /*+K*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a1"); /*+W*/ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_SHS)); + } + + asm("add.l #4,%%a0" :::"a0"); /* update K */ + + for (; i < 40; i ++) { + /* t = f2(b, c, d) + K2 + rol32(a, 5) + e + W[i]; */ + /* e = d; d = c; c = rol32(b, 30); b = a; a = t; */ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); /*f(b,c,d)*/ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA4)); /*+e*/ + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA)); /*+K*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a1"); /*+W*/ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_SHS)); + } + + asm("add.l #4,%%a0" :::"a0"); /* update K */ + + for (; i < 60; i ++) { + /* t = f3(b, c, d) + K3 + rol32(a, 5) + e + W[i]; */ + /* e = d; d = c; c = rol32(b, 30); b = a; a = t; */ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFM)); /*f(b,c,d)*/ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA4)); /*+e*/ + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA)); /*+K*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a1"); /*+W*/ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_SHS)); + } + + asm("add.l #4,%%a0" :::"a0"); /* update K */ + + for (; i < 80; i ++) { + /* t = f2(b, c, d) + K4 + rol32(a, 5) + e + W[i]; */ + /* e = d; d = c; c = rol32(b, 30); b = a; a = t; */ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_HASH+MCFCAU_HFH)); /*f(b,c,d)*/ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_ADRA+MCFCAU_CA4)); /*+e*/ + asm("cp0ld.l (%%a0),%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA)); /*+K*/ + asm("cp0ld.l (%%a1)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CAA):"a1"); /*+W*/ + asm("cp0ld.l %%d0,%%d0,#1,%0" ::"n"(MCFCAU_SHS)); + } + + /* (e) */ + asm("move.l %0, %%a0"::"m"(digest):"a0"); + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CA0):"a0"); /* +a */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CA1):"a0"); /* +b */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CA2):"a0"); /* +c */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CA3):"a0"); /* +d */ + asm("cp0ld.l (%%a0)+,%%d0,#1,%0" ::"n"(MCFCAU_ADR+MCFCAU_CA4):"a0"); /* +e */ + + asm("cp0st.l %%d0,-(%%a0),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA4):"a0"); + asm("cp0st.l %%d0,-(%%a0),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA3):"a0"); + asm("cp0st.l %%d0,-(%%a0),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA2):"a0"); + asm("cp0st.l %%d0,-(%%a0),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA1):"a0"); + asm("cp0st.l %%d0,-(%%a0),#1,%0" ::"n"(MCFCAU_STR+MCFCAU_CA0):"a0"); + spin_unlock_irqrestore(&mcfcau_lock, iflags); +} + +static void mcfcau_sha1_init(struct crypto_tfm *tfm) +{ + struct mcfcau_sha1_ctx *sctx = crypto_tfm_ctx(tfm); + static const struct mcfcau_sha1_ctx initstate = { + 0, + { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }, + { 0, } + }; + + *sctx = initstate; +} + +static void mcfcau_sha1_update(struct crypto_tfm *tfm, const u8 *data, + unsigned int len) +{ + struct mcfcau_sha1_ctx *sctx = crypto_tfm_ctx(tfm); + unsigned int partial, done; + const u8 *src; + + partial = sctx->count & 0x3f; + sctx->count += len; + done = 0; + src = data; + + if ((partial + len) > 63) { + u32 temp[MCFCAU_SHA1_WORKSPACE_WORDS]; + + if (partial) { + done = -partial; + memcpy(sctx->buffer + partial, data, done + 64); + src = sctx->buffer; + } + + do { + mcfcau_sha1_transform(sctx->state, src, temp); + done += 64; + src = data + done; + } while (done + 63 < len); + + memset(temp, 0, sizeof(temp)); + partial = 0; + } + memcpy(sctx->buffer + partial, src, len - done); +} + + +/* Add padding and return the message digest. */ +static void mcfcau_sha1_final(struct crypto_tfm *tfm, u8 *out) +{ + struct mcfcau_sha1_ctx *sctx = crypto_tfm_ctx(tfm); + u32 *dst = (u32 *)out; + u32 i, index, padlen; + u64 bits; + static const u8 padding[64] = { 0x80, }; + + bits = sctx->count << 3; + + /* Pad out to 56 mod 64 */ + index = sctx->count & 0x3f; + padlen = (index < 56) ? (56 - index) : ((64+56) - index); + mcfcau_sha1_update(tfm, padding, padlen); + + /* Append length */ + mcfcau_sha1_update(tfm, (const u8 *)&bits, sizeof(bits)); + + /* Store state in digest */ + for (i = 0; i < 5; i++) + dst[i] = sctx->state[i]; + + + /* Wipe context */ + memset(sctx, 0, sizeof *sctx); +} + +static struct crypto_alg mcfcau_sha1_alg = { + .cra_name = "sha1", + .cra_driver_name= "sha1-mcfcau", + .cra_priority = MCFCAU_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = MCFCAU_SHA1_HMAC_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct mcfcau_sha1_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(mcfcau_sha1_alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = MCFCAU_SHA1_DIGEST_SIZE, + .dia_init = mcfcau_sha1_init, + .dia_update = mcfcau_sha1_update, + .dia_final = mcfcau_sha1_final } } +}; + +static int __init init(void) +{ + int ret = crypto_register_alg(&mcfcau_sha1_alg); + printk(KERN_INFO MCFCAU_SHA1_DRIVER_DESC " " + MCFCAU_SHA1_DRIVER_VERSION " %s.\n",ret?"failed":"registered"); + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&mcfcau_sha1_alg); + printk(KERN_INFO MCFCAU_SHA1_DRIVER_DESC " " + MCFCAU_SHA1_DRIVER_VERSION " unregistered.\n"); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(MCFCAU_SHA1_DRIVER_DESC); +MODULE_AUTHOR("Andrey Butok"); --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -4,3 +4,5 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o ioatdma-objs := ioat.o ioat_dma.o ioat_dca.o obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o obj-$(CONFIG_FSL_DMA) += fsldma.o +obj-$(CONFIG_MCD_DMA) += mcddma.o +mcddma-objs := MCD_dmaApi.o MCD_tasks.o MCD_tasksInit.o --- /dev/null +++ b/drivers/dma/MCD_dmaApi.c @@ -0,0 +1,965 @@ +/* + * drivers/dma/MCD_dmaApi.c + * + * Copyright (C) 2004-2008 Freescale Semiconductor, Inc. + * Kurt Mahan + * + * 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 + */ + +#include "MCD_dma.h" +#include "MCD_tasksInit.h" +#include "MCD_progCheck.h" + +/********************************************************************/ +/* + * This is an API-internal pointer to the DMA's registers + */ +dmaRegs *MCD_dmaBar; + +/* + * These are the real and model task tables as generated by the + * build process + */ +extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS]; +extern TaskTableEntry MCD_modelTaskTableSrc[NUMOFVARIANTS]; + +/* + * However, this (usually) gets relocated to on-chip SRAM, at which + * point we access them as these tables + */ +volatile TaskTableEntry *MCD_taskTable; +TaskTableEntry *MCD_modelTaskTable; + + +/* + * MCD_chStatus[] is an array of status indicators for remembering + * whether a DMA has ever been attempted on each channel, pausing + * status, etc. + */ +static int MCD_chStatus[NCHANNELS] = +{ + MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, + MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, + MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, + MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA +}; + +/* + * Prototypes for local functions + */ +static void MCD_memcpy (int *dest, int *src, u32 size); +static void MCD_resmActions (int channel); + +/* + * Buffer descriptors used for storage of progress info for single Dmas + * Also used as storage for the DMA for CRCs for single DMAs + * Otherwise, the DMA does not parse these buffer descriptors + */ +#ifdef MCD_INCLUDE_EU +extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS]; +#else +MCD_bufDesc MCD_singleBufDescs[NCHANNELS]; +#endif +MCD_bufDesc *MCD_relocBuffDesc; + + +/* + * Defines for the debug control register's functions + */ +#define DBG_CTL_COMP1_TASK (0x00002000) /* have comparator 1 look for a task # */ +#define DBG_CTL_ENABLE (DBG_CTL_AUTO_ARM | \ + DBG_CTL_BREAK | \ + DBG_CTL_INT_BREAK | \ + DBG_CTL_COMP1_TASK) +#define DBG_CTL_DISABLE (DBG_CTL_AUTO_ARM | \ + DBG_CTL_INT_BREAK | \ + DBG_CTL_COMP1_TASK) +#define DBG_KILL_ALL_STAT (0xFFFFFFFF) + +/* + * Offset to context save area where progress info is stored + */ +#define CSAVE_OFFSET 10 + +/* + * Defines for Byte Swapping + */ +#define MCD_BYTE_SWAP_KILLER 0xFFF8888F +#define MCD_NO_BYTE_SWAP_ATALL 0x00040000 + +/* + * Execution Unit Identifiers + */ +#define MAC 0 /* legacy - not used */ +#define LUAC 1 /* legacy - not used */ +#define CRC 2 /* legacy - not used */ +#define LURC 3 /* Logic Unit with CRC */ + +/* + * Task Identifiers + */ +#define TASK_CHAINNOEU 0 +#define TASK_SINGLENOEU 1 +#ifdef MCD_INCLUDE_EU +#define TASK_CHAINEU 2 +#define TASK_SINGLEEU 3 +#define TASK_FECRX 4 +#define TASK_FECTX 5 +#else +#define TASK_CHAINEU 0 +#define TASK_SINGLEEU 1 +#define TASK_FECRX 2 +#define TASK_FECTX 3 +#endif + +/* + * Structure to remember which variant is on which channel + */ +typedef struct MCD_remVariants_struct MCD_remVariant; +struct MCD_remVariants_struct +{ + int remDestRsdIncr[NCHANNELS]; /* -1,0,1 */ + int remSrcRsdIncr[NCHANNELS]; /* -1,0,1 */ + s16 remDestIncr[NCHANNELS]; /* DestIncr */ + s16 remSrcIncr[NCHANNELS]; /* srcIncr */ + u32 remXferSize[NCHANNELS]; /* xferSize */ +}; + +/* + * Structure to remember the startDma parameters for each channel + */ +MCD_remVariant MCD_remVariants; + +/********************************************************************/ +/* + * Function: MCD_initDma + * Purpose: Initializes the DMA API by setting up a pointer to the DMA + * registers, relocating and creating the appropriate task + * structures, and setting up some global settings + * Arguments: + * dmaBarAddr - pointer to the multichannel DMA registers + * taskTableDest - location to move DMA task code and structs to + * flags - operational parameters + * Return Value: + * MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned + * MCD_OK otherwise + */ +extern u32 MCD_funcDescTab0[]; + +int MCD_initDma (dmaRegs *dmaBarAddr, void *taskTableDest, u32 flags) +{ + int i; + TaskTableEntry *entryPtr; + + /* Setup the local pointer to register set */ + MCD_dmaBar = dmaBarAddr; + + /* Do we need to move/create a task table */ + if ((flags & MCD_RELOC_TASKS) != 0) + { + int fixedSize; + u32 *fixedPtr; + int varTabsOffset, funcDescTabsOffset, contextSavesOffset; + int taskDescTabsOffset; + int taskTableSize, varTabsSize, funcDescTabsSize, contextSavesSize; + int taskDescTabSize; + + int i; + + /* Check if physical address is aligned on 512 byte boundary */ + if (((u32)taskTableDest & 0x000001ff) != 0) + return(MCD_TABLE_UNALIGNED); + + MCD_taskTable = taskTableDest; /* set up local pointer to task Table */ + + /* + * Create a task table: + * - compute aligned base offsets for variable tables and + * function descriptor tables, then + * - loop through the task table and setup the pointers + * - copy over model task table with the the actual task descriptor + * tables + */ + taskTableSize = NCHANNELS * sizeof(TaskTableEntry); + /* Align variable tables to size */ + varTabsOffset = taskTableSize + (u32)taskTableDest; + if ((varTabsOffset & (VAR_TAB_SIZE - 1)) != 0) + varTabsOffset = (varTabsOffset + VAR_TAB_SIZE) & (~VAR_TAB_SIZE); + /* Align function descriptor tables */ + varTabsSize = NCHANNELS * VAR_TAB_SIZE; + funcDescTabsOffset = varTabsOffset + varTabsSize; + + if ((funcDescTabsOffset & (FUNCDESC_TAB_SIZE - 1)) != 0) + funcDescTabsOffset = (funcDescTabsOffset + FUNCDESC_TAB_SIZE) & + (~FUNCDESC_TAB_SIZE); + + funcDescTabsSize = FUNCDESC_TAB_NUM * FUNCDESC_TAB_SIZE; + contextSavesOffset = funcDescTabsOffset + funcDescTabsSize; + contextSavesSize = (NCHANNELS * CONTEXT_SAVE_SIZE); + fixedSize = taskTableSize + varTabsSize + funcDescTabsSize + + contextSavesSize; + + /* Zero the thing out */ + fixedPtr = (u32 *)taskTableDest; + for (i = 0;i<(fixedSize/4);i++) + fixedPtr[i] = 0; + + entryPtr = (TaskTableEntry*)MCD_taskTable; + /* Set up fixed pointers */ + for (i = 0; i < NCHANNELS; i++) + { + entryPtr[i].varTab = (u32)varTabsOffset; /* update ptr to local value */ + entryPtr[i].FDTandFlags = (u32)funcDescTabsOffset | MCD_TT_FLAGS_DEF; + entryPtr[i].contextSaveSpace = (u32)contextSavesOffset; + varTabsOffset += VAR_TAB_SIZE; +#ifdef MCD_INCLUDE_EU /* if not there is only one, just point to the same one */ + funcDescTabsOffset += FUNCDESC_TAB_SIZE; +#endif + contextSavesOffset += CONTEXT_SAVE_SIZE; + } + /* Copy over the function descriptor table */ + for ( i = 0; i < FUNCDESC_TAB_NUM; i++) + { + MCD_memcpy((void*)(entryPtr[i].FDTandFlags & ~MCD_TT_FLAGS_MASK), + (void*)MCD_funcDescTab0, FUNCDESC_TAB_SIZE); + } + + /* Copy model task table to where the context save stuff leaves off */ + MCD_modelTaskTable = (TaskTableEntry*)contextSavesOffset; + + MCD_memcpy ((void*)MCD_modelTaskTable, (void*)MCD_modelTaskTableSrc, + NUMOFVARIANTS * sizeof(TaskTableEntry)); + + /* Point to local version of model task table */ + entryPtr = MCD_modelTaskTable; + taskDescTabsOffset = (u32)MCD_modelTaskTable + + (NUMOFVARIANTS * sizeof(TaskTableEntry)); + + /* Copy actual task code and update TDT ptrs in local model task table */ + for (i = 0; i < NUMOFVARIANTS; i++) + { + taskDescTabSize = entryPtr[i].TDTend - entryPtr[i].TDTstart + 4; + MCD_memcpy ((void*)taskDescTabsOffset, (void*)entryPtr[i].TDTstart, taskDescTabSize); + entryPtr[i].TDTstart = (u32)taskDescTabsOffset; + taskDescTabsOffset += taskDescTabSize; + entryPtr[i].TDTend = (u32)taskDescTabsOffset - 4; + } +#ifdef MCD_INCLUDE_EU + /* + * Tack single DMA BDs onto end of code so API controls where + * they are since DMA might write to them + */ + MCD_relocBuffDesc = (MCD_bufDesc*)(entryPtr[NUMOFVARIANTS - 1].TDTend + 4); +#else + /* + * DMA does not touch them so they can be wherever and we don't need to + * waste SRAM on them + */ + MCD_relocBuffDesc = MCD_singleBufDescs; +#endif + } + else + { + /* + * Point the would-be relocated task tables and the buffer descriptors + * to the ones the linker generated + */ + if (((u32)MCD_realTaskTableSrc & 0x000001ff) != 0) + return(MCD_TABLE_UNALIGNED); + + entryPtr = MCD_realTaskTableSrc; + for (i = 0; i < NCHANNELS; i++) + { + if (((entryPtr[i].varTab & (VAR_TAB_SIZE - 1)) != 0) || + ((entryPtr[i].FDTandFlags & (FUNCDESC_TAB_SIZE - 1)) != 0)) + return(MCD_TABLE_UNALIGNED); + } + + MCD_taskTable = MCD_realTaskTableSrc; + MCD_modelTaskTable = MCD_modelTaskTableSrc; + MCD_relocBuffDesc = MCD_singleBufDescs; + } + + /* Make all channels inactive, and remember them as such: */ + MCD_dmaBar->taskbar = (u32) MCD_taskTable; + for (i = 0; i < NCHANNELS; i++) + { + MCD_dmaBar->taskControl[i] = 0x0; + MCD_chStatus[i] = MCD_NO_DMA; + } + + /* Set up pausing mechanism to inactive state: */ + MCD_dmaBar->debugComp1 = 0; + MCD_dmaBar->debugComp2 = 0; + MCD_dmaBar->debugControl = DBG_CTL_DISABLE; + MCD_dmaBar->debugStatus = DBG_KILL_ALL_STAT; + + /* Enable or disable commbus prefetch */ + if ((flags & MCD_COMM_PREFETCH_EN) != 0) + MCD_dmaBar->ptdControl &= ~PTD_CTL_COMM_PREFETCH; + else + MCD_dmaBar->ptdControl |= PTD_CTL_COMM_PREFETCH; + + return(MCD_OK); +} +/*********************** End of MCD_initDma() ***********************/ + +/********************************************************************/ +/* Function: MCD_dmaStatus + * Purpose: Returns the status of the DMA on the requested channel + * Arguments: channel - channel number + * Returns: Predefined status indicators + */ +int MCD_dmaStatus (int channel) +{ + u16 tcrValue; + + if((channel < 0) || (channel >= NCHANNELS)) + return(MCD_CHANNEL_INVALID); + + tcrValue = MCD_dmaBar->taskControl[channel]; + if ((tcrValue & TASK_CTL_EN) == 0) + { /* Nothing running if last reported with task enabled */ + if ( MCD_chStatus[channel] == MCD_RUNNING + || MCD_chStatus[channel] == MCD_IDLE) + MCD_chStatus[channel] = MCD_DONE; + } + else /* something is running */ + { + /* There are three possibilities: paused, running or idle. */ + if ( MCD_chStatus[channel] == MCD_RUNNING + || MCD_chStatus[channel] == MCD_IDLE) + { + MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT; + /* Determine which initiator is asserted. */ + if ((MCD_dmaBar->ptdDebug >> channel ) & 0x1 ) + MCD_chStatus[channel] = MCD_RUNNING; + else + MCD_chStatus[channel] = MCD_IDLE; + /* Do not change the status if it is already paused */ + } + } + return MCD_chStatus[channel]; +} +/******************** End of MCD_dmaStatus() ************************/ + +/********************************************************************/ +/* Function: MCD_startDma + * Ppurpose: Starts a particular kind of DMA + * Arguments: see below + * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK + */ + +int MCD_startDma ( + int channel, /* the channel on which to run the DMA */ + s8 *srcAddr, /* the address to move data from, or physical buffer-descriptor address */ + s16 srcIncr, /* the amount to increment the source address per transfer */ + s8 *destAddr, /* the address to move data to */ + s16 destIncr, /* the amount to increment the destination address per transfer */ + u32 dmaSize, /* the number of bytes to transfer independent of the transfer size */ + u32 xferSize, /* the number bytes in of each data movement (1, 2, or 4) */ + u32 initiator, /* what device initiates the DMA */ + int priority, /* priority of the DMA */ + u32 flags, /* flags describing the DMA */ + u32 funcDesc /* a description of byte swapping, bit swapping, and CRC actions */ +#ifdef MCD_NEED_ADDR_TRANS + s8 *srcAddrVirt /* virtual buffer descriptor address TBD*/ +#endif +) +{ + int srcRsdIncr, destRsdIncr; + int *cSave; + short xferSizeIncr; + int tcrCount = 0; +#ifdef MCD_INCLUDE_EU + u32 *realFuncArray; +#endif + + if((channel < 0) || (channel >= NCHANNELS)) + return(MCD_CHANNEL_INVALID); + +#ifndef MCD_INCLUDE_EU + funcDesc = MCD_FUNC_NOEU1; +#endif + +#ifdef MCD_DEBUG +printf("startDma:Setting up params\n"); +#endif + + /* Enable task-wise priority */ + MCD_dmaBar->ptdControl |= (u16) 0x8000; + + /* Calculate additional parameters to the regular DMA calls. */ + srcRsdIncr = srcIncr < 0 ? -1 : (srcIncr > 0 ? 1 : 0); + destRsdIncr = destIncr < 0 ? -1 : (destIncr > 0 ? 1 : 0); + xferSizeIncr = (xferSize & 0xffff) | 0x20000000; + + /* Remember which variant is running for each channel */ + MCD_remVariants.remSrcRsdIncr[channel] = srcRsdIncr; + MCD_remVariants.remDestRsdIncr[channel] = destRsdIncr; + MCD_remVariants.remDestIncr[channel] = destIncr; + MCD_remVariants.remSrcIncr[channel] = srcIncr; + MCD_remVariants.remXferSize[channel] = xferSize; + + cSave = (int*)(MCD_taskTable[channel].contextSaveSpace) + + CSAVE_OFFSET + + CURRBD; + +#ifdef MCD_INCLUDE_EU + realFuncArray = (u32 *) (MCD_taskTable[channel].FDTandFlags & 0xffffff00); + + /* + * Modify the LURC's normal and byte-residue-loop functions + * according to parameter. + */ + switch (xferSize) + { + case 4: + realFuncArray[(LURC*16)] = funcDesc; + break; + case 2: + realFuncArray[(LURC*16)] = funcDesc & 0xfffff00f; + break; + case 1: + default: + realFuncArray[(LURC*16)] = funcDesc & 0xffff000f; + break; + } + + realFuncArray[(LURC*16+1)] = 0 + | (funcDesc & MCD_BYTE_SWAP_KILLER) + | MCD_NO_BYTE_SWAP_ATALL; +#endif + + /* Write the initiator field in the TCR and set the initiator-hold bit*/ + MCD_dmaBar->taskControl[channel] = 0 + | (initiator << 8) + | TASK_CTL_HIPRITSKEN + | TASK_CTL_HLDINITNUM; + + /* + * Current versions of the MPC8220 MCD have a hardware quirk that could + * cause the write to the TCR to collide with an MDE access to the + * initiator-register file, so we have to verify that the write occurred + * correctly by reading back the value. On MCF547x/8x devices and any + * future revisions of the MPC8220, this loop will not be entered. + */ + while(((MCD_dmaBar->taskControl[channel] & 0x1fff) != + ((initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM)) && + (tcrCount < 1000)) + { + tcrCount++; + MCD_dmaBar->taskControl[channel] = 0 + | (initiator << 8) + | TASK_CTL_HIPRITSKEN + | TASK_CTL_HLDINITNUM; + } + + MCD_dmaBar->priority[channel] = (u8)priority & PRIORITY_PRI_MASK; + + if (channel < 8 && channel >= 0) + { + MCD_dmaBar->taskSize0 &= ~(0xf << (7-channel)*4); + MCD_dmaBar->taskSize0 |= (xferSize & 3) << (((7 - channel)*4) + 2); + MCD_dmaBar->taskSize0 |= (xferSize & 3) << ((7 - channel)*4); + } + else + { + MCD_dmaBar->taskSize1 &= ~(0xf << (15-channel)*4); + MCD_dmaBar->taskSize1 |= (xferSize & 3) << (((15 - channel)*4) + 2); + MCD_dmaBar->taskSize1 |= (xferSize & 3) << ((15 - channel)*4); + } + + /* Setup task table flags/options */ + MCD_taskTable[channel].FDTandFlags &= ~MCD_TT_FLAGS_MASK; + MCD_taskTable[channel].FDTandFlags |= (MCD_TT_FLAGS_MASK & flags); + + if (flags & MCD_FECTX_DMA) + { + /* TDTStart and TDTEnd */ + MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_FECTX].TDTstart; + MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_FECTX].TDTend; + MCD_startDmaENetXmit(srcAddr, srcAddr, destAddr, MCD_taskTable, channel); + } + else if (flags & MCD_FECRX_DMA) + { + /* TDTStart and TDTEnd */ + MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_FECRX].TDTstart; + MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_FECRX].TDTend; + MCD_startDmaENetRcv(srcAddr, srcAddr, destAddr, MCD_taskTable, channel); + } + else if(flags & MCD_SINGLE_DMA) + { + /* + * This buffer descriptor is used for storing off initial parameters + * for later progress query calculation and for the DMA to write the + * resulting checksum. The DMA does not use this to determine how to + * operate, that info is passed with the init routine + */ + MCD_relocBuffDesc[channel].srcAddr = srcAddr; + MCD_relocBuffDesc[channel].destAddr = destAddr; + MCD_relocBuffDesc[channel].lastDestAddr = destAddr; + MCD_relocBuffDesc[channel].dmaSize = dmaSize; + MCD_relocBuffDesc[channel].flags = 0; /* not used */ + MCD_relocBuffDesc[channel].csumResult = 0; /* not used */ + MCD_relocBuffDesc[channel].next = 0; /* not used */ + + /* Initialize the progress-querying stuff to show no progress:*/ + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET] + = (int)srcAddr; + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET] + = (int)destAddr; + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET] + = 0; + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET] + = (u32) &(MCD_relocBuffDesc[channel]); + + if( funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) + { + /* TDTStart and TDTEnd */ + MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_SINGLENOEU].TDTstart; + MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_SINGLENOEU].TDTend; + MCD_startDmaSingleNoEu(srcAddr, srcIncr, destAddr, destIncr, dmaSize, + xferSizeIncr, flags, (int *)&(MCD_relocBuffDesc[channel]), + cSave, MCD_taskTable, channel); + } + else + { + /* TDTStart and TDTEnd */ + MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_SINGLEEU].TDTstart; + MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_SINGLEEU].TDTend; + MCD_startDmaSingleEu(srcAddr, srcIncr, destAddr, destIncr, dmaSize, + xferSizeIncr, flags, (int *)&(MCD_relocBuffDesc[channel]), + cSave, MCD_taskTable, channel); + } + } + else /* Chained DMA */ + { + /* Initialize the progress-querying stuff to show no progress:*/ +#if 1 /* (!defined(MCD_NEED_ADDR_TRANS)) */ + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET] + = (int)((MCD_bufDesc*) srcAddr)->srcAddr; + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET] + = (int)((MCD_bufDesc*) srcAddr)->destAddr; +#else /* if using address translation, need the virtual addr of the first buffdesc */ + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET] + = (int)((MCD_bufDesc*) srcAddrVirt)->srcAddr; + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET] + = (int)((MCD_bufDesc*) srcAddrVirt)->destAddr; +#endif + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET] + = 0; + ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET] + = (u32) srcAddr; + + if( funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) + { + /* TDTStart and TDTEnd */ + MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_CHAINNOEU].TDTstart; + MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_CHAINNOEU].TDTend; + MCD_startDmaChainNoEu((int *)srcAddr, srcIncr, destIncr, xferSize, + xferSizeIncr, cSave, MCD_taskTable, channel); + } + else + { + /* TDTStart and TDTEnd */ + MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_CHAINEU].TDTstart; + MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_CHAINEU].TDTend; + MCD_startDmaChainEu((int *)srcAddr, srcIncr, destIncr, xferSize, + xferSizeIncr, cSave, MCD_taskTable, channel); + } + } + + MCD_chStatus[channel] = MCD_IDLE; + return(MCD_OK); +} + +/************************ End of MCD_startDma() *********************/ + +/********************************************************************/ +/* Function: MCD_XferProgrQuery + * Purpose: Returns progress of DMA on requested channel + * Arguments: channel - channel to retrieve progress for + * progRep - pointer to user supplied MCD_XferProg struct + * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK + * + * Notes: + * MCD_XferProgrQuery() upon completing or after aborting a DMA, or + * while the DMA is in progress, this function returns the first + * DMA-destination address not (or not yet) used in the DMA. When + * encountering a non-ready buffer descriptor, the information for + * the last completed descriptor is returned. + * + * MCD_XferProgQuery() has to avoid the possibility of getting + * partially-updated information in the event that we should happen + * to query DMA progress just as the DMA is updating it. It does that + * by taking advantage of the fact context is not saved frequently for + * the most part. We therefore read it at least twice until we get the + * same information twice in a row. + * + * Because a small, but not insignificant, amount of time is required + * to write out the progress-query information, especially upon + * completion of the DMA, it would be wise to guarantee some time lag + * between successive readings of the progress-query information. + */ + +/* + * How many iterations of the loop below to execute to stabilize values + */ +#define STABTIME 0 + +int MCD_XferProgrQuery (int channel, MCD_XferProg *progRep) +{ + MCD_XferProg prevRep; + int again; /* true if we are to try again to get consistent results */ + int i; /* used as a time-waste counter */ + int destDiffBytes; /* Total number of bytes that we think actually got xfered. */ + int numIterations; /* number of iterations */ + int bytesNotXfered; /* bytes that did not get xfered. */ + s8 *LWAlignedInitDestAddr, *LWAlignedCurrDestAddr; + int subModVal, addModVal; /* Mode values to added and subtracted from the + final destAddr */ + + if((channel < 0) || (channel >= NCHANNELS)) + return(MCD_CHANNEL_INVALID); + + /* Read a trial value for the progress-reporting values*/ + prevRep.lastSrcAddr = + (s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET]; + prevRep.lastDestAddr = + (s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET]; + prevRep.dmaSize = ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET]; + prevRep.currBufDesc = + (MCD_bufDesc*) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET]; + + /* Repeatedly reread those values until they match previous values: */ + do { + /* Take a little bit of time to ensure stability: */ + for (i = 0; i < STABTIME; i++) + i += i >> 2; /* make sure this loop does something so that it + doesn't get optimized out */ + /* Check them again: */ + progRep->lastSrcAddr = + (s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET]; + progRep->lastDestAddr = + (s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET]; + progRep->dmaSize = ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET]; + progRep->currBufDesc = + (MCD_bufDesc*) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET]; + + /* See if they match: */ + if ( prevRep.lastSrcAddr != progRep->lastSrcAddr + || prevRep.lastDestAddr != progRep->lastDestAddr + || prevRep.dmaSize != progRep->dmaSize + || prevRep.currBufDesc != progRep->currBufDesc) + { + /* If they don't match, remember previous values and try again:*/ + prevRep.lastSrcAddr = progRep->lastSrcAddr; + prevRep.lastDestAddr = progRep->lastDestAddr; + prevRep.dmaSize = progRep->dmaSize; + prevRep.currBufDesc = progRep->currBufDesc; + again = MCD_TRUE; + } + else + again = MCD_FALSE; + } while (again == MCD_TRUE); + + + /* Update dmaSize and lastDestAddr */ + switch(MCD_remVariants.remDestRsdIncr[channel]) + { + case MINUS1: + subModVal = ((int)progRep->lastDestAddr) + & ((MCD_remVariants.remXferSize[channel]) - 1); + addModVal = ((int)progRep->currBufDesc->destAddr) + & ((MCD_remVariants.remXferSize[channel]) - 1); + LWAlignedInitDestAddr = (progRep->currBufDesc->destAddr) - addModVal; + LWAlignedCurrDestAddr = (progRep->lastDestAddr) - subModVal; + destDiffBytes = LWAlignedInitDestAddr - LWAlignedCurrDestAddr; + bytesNotXfered = (destDiffBytes/MCD_remVariants.remDestIncr[channel]) * + ( MCD_remVariants.remDestIncr[channel] + + MCD_remVariants.remXferSize[channel]); + progRep->dmaSize = destDiffBytes - bytesNotXfered + addModVal - subModVal; + break; + case ZERO: + progRep->lastDestAddr = progRep->currBufDesc->destAddr; + break; + case PLUS1: + /* This value has to be subtracted from the final calculated dmaSize. */ + subModVal = ((int)progRep->currBufDesc->destAddr) + & ((MCD_remVariants.remXferSize[channel]) - 1); + /* These bytes are already in lastDestAddr. */ + addModVal = ((int)progRep->lastDestAddr) + & ((MCD_remVariants.remXferSize[channel]) - 1); + LWAlignedInitDestAddr = (progRep->currBufDesc->destAddr) - subModVal; + LWAlignedCurrDestAddr = (progRep->lastDestAddr) - addModVal; + destDiffBytes = (progRep->lastDestAddr - LWAlignedInitDestAddr); + numIterations = ( LWAlignedCurrDestAddr - LWAlignedInitDestAddr)/MCD_remVariants.remDestIncr[channel]; + bytesNotXfered = numIterations * + (MCD_remVariants.remDestIncr[channel] + - MCD_remVariants.remXferSize[channel]); + progRep->dmaSize = destDiffBytes - bytesNotXfered - subModVal; + break; + default: + break; + } + + /* This covers M1,P1,Z for source */ + switch(MCD_remVariants.remSrcRsdIncr[channel]) + { + case MINUS1: + progRep->lastSrcAddr = + progRep->currBufDesc->srcAddr + + ( MCD_remVariants.remSrcIncr[channel] * + (progRep->dmaSize/MCD_remVariants.remXferSize[channel])); + break; + case ZERO: + progRep->lastSrcAddr = progRep->currBufDesc->srcAddr; + break; + case PLUS1: + progRep->lastSrcAddr = + progRep->currBufDesc->srcAddr + + ( MCD_remVariants.remSrcIncr[channel] * + (progRep->dmaSize/MCD_remVariants.remXferSize[channel])); + break; + default: + break; + } + + return(MCD_OK); +} +/******************* End of MCD_XferProgrQuery() ********************/ + +/********************************************************************/ +/* MCD_resmActions() does the majority of the actions of a DMA resume. + * It is called from MCD_killDma() and MCD_resumeDma(). It has to be + * a separate function because the kill function has to negate the task + * enable before resuming it, but the resume function has to do nothing + * if there is no DMA on that channel (i.e., if the enable bit is 0). + */ +static void MCD_resmActions (int channel) +{ + MCD_dmaBar->debugControl = DBG_CTL_DISABLE; + MCD_dmaBar->debugStatus = MCD_dmaBar->debugStatus; + + /* Determine which initiators are asserted */ + MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT; + + if((MCD_dmaBar->ptdDebug >> channel ) & 0x1) + MCD_chStatus[channel] = MCD_RUNNING; + else + MCD_chStatus[channel] = MCD_IDLE; +} +/********************* End of MCD_resmActions() *********************/ + +/********************************************************************/ +/* Function: MCD_killDma + * Purpose: Halt the DMA on the requested channel, without any + * intention of resuming the DMA. + * Arguments: channel - requested channel + * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK + * + * Notes: + * A DMA may be killed from any state, including paused state, and it + * always goes to the MCD_HALTED state even if it is killed while in + * the MCD_NO_DMA or MCD_IDLE states. + */ +int MCD_killDma (int channel) +{ + if((channel < 0) || (channel >= NCHANNELS)) + return(MCD_CHANNEL_INVALID); + + MCD_dmaBar->taskControl[channel] = 0x0; + + /* Clean up after a paused task */ + if (MCD_chStatus[channel] == MCD_PAUSED) + { + MCD_dmaBar->debugControl = DBG_CTL_DISABLE; + MCD_dmaBar->debugStatus = MCD_dmaBar->debugStatus; + } + + MCD_chStatus[channel] = MCD_HALTED; + + return(MCD_OK); +} +/************************ End of MCD_killDma() **********************/ + +/********************************************************************/ +/* Function: MCD_continDma + * Purpose: Continue a DMA which as stopped due to encountering an + * unready buffer descriptor. + * Arguments: channel - channel to continue the DMA on + * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK + * + * Notes: + * This routine does not check to see if there is a task which can + * be continued. Also this routine should not be used with single DMAs. + */ +int MCD_continDma (int channel) +{ + if((channel < 0) || (channel >= NCHANNELS)) + return(MCD_CHANNEL_INVALID); + + MCD_dmaBar->taskControl[channel] |= TASK_CTL_EN; + MCD_chStatus[channel] = MCD_RUNNING; + + return(MCD_OK); +} +/********************** End of MCD_continDma() **********************/ + +/********************************************************************* + * MCD_pauseDma() and MCD_resumeDma() below use the DMA's debug unit + * to freeze a task and resume it. We freeze a task by breakpointing + * on the stated task. That is, not any specific place in the task, + * but any time that task executes. In particular, when that task + * executes, we want to freeze that task and only that task. + * + * The bits of the debug control register influence interrupts vs. + * breakpoints as follows: + * - Bits 14 and 0 enable or disable debug functions. If enabled, you + * will get the interrupt but you may or may not get a breakpoint. + * - Bits 2 and 1 decide whether you also get a breakpoint in addition + * to an interrupt. + * + * The debug unit can do these actions in response to either internally + * detected breakpoint conditions from the comparators, or in response + * to the external breakpoint pin, or both. + * - Bits 14 and 1 perform the above-described functions for + * internally-generated conditions, i.e., the debug comparators. + * - Bits 0 and 2 perform the above-described functions for external + * conditions, i.e., the breakpoint external pin. + * + * Note that, although you "always" get the interrupt when you turn + * the debug functions, the interrupt can nevertheless, if desired, be + * masked by the corresponding bit in the PTD's IMR. Note also that + * this means that bits 14 and 0 must enable debug functions before + * bits 1 and 2, respectively, have any effect. + * + * NOTE: It's extremely important to not pause more than one DMA channel + * at a time. + ********************************************************************/ + +/********************************************************************/ +/* Function: MCD_pauseDma + * Purpose: Pauses the DMA on a given channel (if any DMA is running + * on that channel). + * Arguments: channel + * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK + */ +int MCD_pauseDma (int channel) +{ + if((channel < 0) || (channel >= NCHANNELS)) + return(MCD_CHANNEL_INVALID); + + if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN) + { + MCD_dmaBar->debugComp1 = channel; + MCD_dmaBar->debugControl = DBG_CTL_ENABLE | (1 << (channel + 16)); + MCD_chStatus[channel] = MCD_PAUSED; + } + return(MCD_OK); +} +/************************* End of MCD_pauseDma() ********************/ + +/********************************************************************/ +/* Function: MCD_resumeDma + * Purpose: Resumes the DMA on a given channel (if any DMA is + * running on that channel). + * Arguments: channel - channel on which to resume DMA + * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK + */ +int MCD_resumeDma (int channel) +{ + if((channel < 0) || (channel >= NCHANNELS)) + return(MCD_CHANNEL_INVALID); + + if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN) + MCD_resmActions (channel); + + return(MCD_OK); +} +/************************ End of MCD_resumeDma() ********************/ + +/********************************************************************/ +/* Function: MCD_csumQuery + * Purpose: Provide the checksum after performing a non-chained DMA + * Arguments: channel - channel to report on + * csum - pointer to where to write the checksum/CRC + * Returns: MCD_ERROR if the channel is invalid, else MCD_OK + * + * Notes: + * + */ +int MCD_csumQuery (int channel, u32 *csum) +{ +#ifdef MCD_INCLUDE_EU + if((channel < 0) || (channel >= NCHANNELS)) + return(MCD_CHANNEL_INVALID); + + *csum = MCD_relocBuffDesc[channel].csumResult; + return(MCD_OK); +#else + return(MCD_ERROR); +#endif +} +/*********************** End of MCD_resumeDma() *********************/ + +/********************************************************************/ +/* Function: MCD_getCodeSize + * Purpose: Provide the size requirements of the microcoded tasks + * Returns: Size in bytes + */ +int MCD_getCodeSize(void) +{ +#ifdef MCD_INCLUDE_EU + return(0x2b64); +#else + return(0x1744); +#endif +} +/********************** End of MCD_getCodeSize() ********************/ + +/********************************************************************/ +/* Function: MCD_getVersion + * Purpose: Provide the version string and number + * Arguments: longVersion - user supplied pointer to a pointer to a char + * which points to the version string + * Returns: Version number and version string (by reference) + */ +char MCD_versionString[] = "Multi-channel DMA API v1.0"; +#define MCD_REV_MAJOR 0x01 +#define MCD_REV_MINOR 0x00 + +int MCD_getVersion(char **longVersion) +{ + *longVersion = MCD_versionString; + return((MCD_REV_MAJOR << 8) | MCD_REV_MINOR); +} +/********************** End of MCD_getVersion() *********************/ + +/********************************************************************/ +/* Private version of memcpy() + * Note that everything this is used for is longword-aligned. + */ +static void MCD_memcpy (int *dest, int *src, u32 size) +{ + u32 i; + + for (i = 0; i < size; i += sizeof(int), dest++, src++) + *dest = *src; +} +/********************************************************************/ --- /dev/null +++ b/drivers/dma/MCD_dma.h @@ -0,0 +1,378 @@ +/* + * drivers/dma/MCD_dma.h + * + * Copyright (C) 2004-2008 Freescale Semiconductor, Inc. + * Kurt Mahan + * + * 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 + */ +#ifndef _MCD_API_H +#define _MCD_API_H + +/* + * Turn Execution Unit tasks ON (#define) or OFF (#undef) + */ +#undef MCD_INCLUDE_EU + +/* + * Number of DMA channels + */ +#define NCHANNELS 16 + +/* + * Total number of variants + */ +#ifdef MCD_INCLUDE_EU +#define NUMOFVARIANTS 6 +#else +#define NUMOFVARIANTS 4 +#endif + +/* + * Define sizes of the various tables + */ +#define TASK_TABLE_SIZE (NCHANNELS*32) +#define VAR_TAB_SIZE (128) +#define CONTEXT_SAVE_SIZE (128) +#define FUNCDESC_TAB_SIZE (256) + +#ifdef MCD_INCLUDE_EU +#define FUNCDESC_TAB_NUM 16 +#else +#define FUNCDESC_TAB_NUM 1 +#endif + + +#ifndef DEFINESONLY + +/* + * Portability typedefs + */ +typedef int s32; +typedef unsigned int u32; +typedef short s16; +typedef unsigned short u16; +typedef char s8; +typedef unsigned char u8; + +/* + * These structures represent the internal registers of the + * multi-channel DMA + */ +struct dmaRegs_s { + u32 taskbar; /* task table base address register */ + u32 currPtr; + u32 endPtr; + u32 varTablePtr; + u16 dma_rsvd0; + u16 ptdControl; /* ptd control */ + u32 intPending; /* interrupt pending register */ + u32 intMask; /* interrupt mask register */ + u16 taskControl[16]; /* task control registers */ + u8 priority[32]; /* priority registers */ + u32 initiatorMux; /* initiator mux control */ + u32 taskSize0; /* task size control register 0. */ + u32 taskSize1; /* task size control register 1. */ + u32 dma_rsvd1; /* reserved */ + u32 dma_rsvd2; /* reserved */ + u32 debugComp1; /* debug comparator 1 */ + u32 debugComp2; /* debug comparator 2 */ + u32 debugControl; /* debug control */ + u32 debugStatus; /* debug status */ + u32 ptdDebug; /* priority task decode debug */ + u32 dma_rsvd3[31]; /* reserved */ +}; +typedef volatile struct dmaRegs_s dmaRegs; + +#endif + +/* + * PTD contrl reg bits + */ +#define PTD_CTL_TSK_PRI 0x8000 +#define PTD_CTL_COMM_PREFETCH 0x0001 + +/* + * Task Control reg bits and field masks + */ +#define TASK_CTL_EN 0x8000 +#define TASK_CTL_VALID 0x4000 +#define TASK_CTL_ALWAYS 0x2000 +#define TASK_CTL_INIT_MASK 0x1f00 +#define TASK_CTL_ASTRT 0x0080 +#define TASK_CTL_HIPRITSKEN 0x0040 +#define TASK_CTL_HLDINITNUM 0x0020 +#define TASK_CTL_ASTSKNUM_MASK 0x000f + +/* + * Priority reg bits and field masks + */ +#define PRIORITY_HLD 0x80 +#define PRIORITY_PRI_MASK 0x07 + +/* + * Debug Control reg bits and field masks + */ +#define DBG_CTL_BLOCK_TASKS_MASK 0xffff0000 +#define DBG_CTL_AUTO_ARM 0x00008000 +#define DBG_CTL_BREAK 0x00004000 +#define DBG_CTL_COMP1_TYP_MASK 0x00003800 +#define DBG_CTL_COMP2_TYP_MASK 0x00000070 +#define DBG_CTL_EXT_BREAK 0x00000004 +#define DBG_CTL_INT_BREAK 0x00000002 + +/* + * PTD Debug reg selector addresses + * This reg must be written with a value to show the contents of + * one of the desired internal register. + */ +#define PTD_DBG_REQ 0x00 /* shows the state of 31 initiators */ +#define PTD_DBG_TSK_VLD_INIT 0x01 /* shows which 16 tasks are valid and + have initiators asserted */ + + +/* + * General return values + */ +#define MCD_OK 0 +#define MCD_ERROR -1 +#define MCD_TABLE_UNALIGNED -2 +#define MCD_CHANNEL_INVALID -3 + +/* + * MCD_initDma input flags + */ +#define MCD_RELOC_TASKS 0x00000001 +#define MCD_NO_RELOC_TASKS 0x00000000 +#define MCD_COMM_PREFETCH_EN 0x00000002 /* Commbus Prefetching - MCF547x/548x ONLY */ + +/* + * MCD_dmaStatus Status Values for each channel + */ +#define MCD_NO_DMA 1 /* No DMA has been requested since reset */ +#define MCD_IDLE 2 /* DMA active, but the initiator is currently inactive */ +#define MCD_RUNNING 3 /* DMA active, and the initiator is currently active */ +#define MCD_PAUSED 4 /* DMA active but it is currently paused */ +#define MCD_HALTED 5 /* the most recent DMA has been killed with MCD_killTask() */ +#define MCD_DONE 6 /* the most recent DMA has completed. */ + + +/* + * MCD_startDma parameter defines + */ + +/* + * Constants for the funcDesc parameter + */ +/* Byte swapping: */ +#define MCD_NO_BYTE_SWAP 0x00045670 /* to disable byte swapping. */ +#define MCD_BYTE_REVERSE 0x00076540 /* to reverse the bytes of each u32 of the DMAed data. */ +#define MCD_U16_REVERSE 0x00067450 /* to reverse the 16-bit halves of + each 32-bit data value being DMAed.*/ +#define MCD_U16_BYTE_REVERSE 0x00054760 /* to reverse the byte halves of each + 16-bit half of each 32-bit data value DMAed */ +#define MCD_NO_BIT_REV 0x00000000 /* do not reverse the bits of each byte DMAed. */ +#define MCD_BIT_REV 0x00088880 /* reverse the bits of each byte DMAed */ +/* CRCing: */ +#define MCD_CRC16 0xc0100000 /* to perform CRC-16 on DMAed data. */ +#define MCD_CRCCCITT 0xc0200000 /* to perform CRC-CCITT on DMAed data. */ +#define MCD_CRC32 0xc0300000 /* to perform CRC-32 on DMAed data. */ +#define MCD_CSUMINET 0xc0400000 /* to perform internet checksums on DMAed data.*/ +#define MCD_NO_CSUM 0xa0000000 /* to perform no checksumming. */ + +#define MCD_FUNC_NOEU1 (MCD_NO_BYTE_SWAP | MCD_NO_BIT_REV | MCD_NO_CSUM) +#define MCD_FUNC_NOEU2 (MCD_NO_BYTE_SWAP | MCD_NO_CSUM) + +/* + * Constants for the flags parameter + */ +#define MCD_TT_FLAGS_RL 0x00000001 /* Read line */ +#define MCD_TT_FLAGS_CW 0x00000002 /* Combine Writes */ +#define MCD_TT_FLAGS_SP 0x00000004 /* Speculative prefetch(XLB) MCF547x/548x ONLY */ +#define MCD_TT_FLAGS_PI 0x00000040 /* Precise Increment */ +#define MCD_TT_FLAGS_MASK 0x000000ff +#define MCD_TT_FLAGS_DEF (MCD_TT_FLAGS_RL | MCD_TT_FLAGS_CW) + +#define MCD_SINGLE_DMA 0x00000100 /* Unchained DMA */ +#define MCD_CHAIN_DMA /* TBD */ +#define MCD_EU_DMA /* TBD */ +#define MCD_FECTX_DMA 0x00001000 /* FEC TX ring DMA */ +#define MCD_FECRX_DMA 0x00002000 /* FEC RX ring DMA */ + + +/* these flags are valid for MCD_startDma and the chained buffer descriptors */ +#define MCD_BUF_READY 0x80000000 /* indicates that this buffer is now under the DMA's control */ +#define MCD_WRAP 0x20000000 /* to tell the FEC Dmas to wrap to the first BD */ +#define MCD_INTERRUPT 0x10000000 /* to generate an interrupt after completion of the DMA. */ +#define MCD_END_FRAME 0x08000000 /* tell the DMA to end the frame when transferring + last byte of data in buffer */ +#define MCD_CRC_RESTART 0x40000000 /* to empty out the accumulated checksum + prior to performing the DMA. */ + +/* Defines for the FEC buffer descriptor control/status word*/ +#define MCD_FEC_BUF_READY 0x8000 +#define MCD_FEC_WRAP 0x2000 +#define MCD_FEC_INTERRUPT 0x1000 +#define MCD_FEC_END_FRAME 0x0800 + + +/* + * Defines for general intuitiveness + */ + +#define MCD_TRUE 1 +#define MCD_FALSE 0 + +/* + * Three different cases for destination and source. + */ +#define MINUS1 -1 +#define ZERO 0 +#define PLUS1 1 + +#ifndef DEFINESONLY + +/* Task Table Entry struct*/ +typedef struct { + u32 TDTstart; /* task descriptor table start */ + u32 TDTend; /* task descriptor table end */ + u32 varTab; /* variable table start */ + u32 FDTandFlags; /* function descriptor table start and flags */ + volatile u32 descAddrAndStatus; + volatile u32 modifiedVarTab; + u32 contextSaveSpace; /* context save space start */ + u32 literalBases; +} TaskTableEntry; + + +/* Chained buffer descriptor */ +typedef volatile struct MCD_bufDesc_struct MCD_bufDesc; +struct MCD_bufDesc_struct { + u32 flags; /* flags describing the DMA */ + u32 csumResult; /* checksum from checksumming performed since last checksum reset */ + s8 *srcAddr; /* the address to move data from */ + s8 *destAddr; /* the address to move data to */ + s8 *lastDestAddr; /* the last address written to */ + u32 dmaSize; /* the number of bytes to transfer independent of the transfer size */ + MCD_bufDesc *next; /* next buffer descriptor in chain */ + u32 info; /* private information about this descriptor; DMA does not affect it */ +}; + +/* Progress Query struct */ +typedef volatile struct MCD_XferProg_struct { + s8 *lastSrcAddr; /* the most-recent or last, post-increment source address */ + s8 *lastDestAddr; /* the most-recent or last, post-increment destination address */ + u32 dmaSize; /* the amount of data transferred for the current buffer */ + MCD_bufDesc *currBufDesc;/* pointer to the current buffer descriptor being DMAed */ +} MCD_XferProg; + + +/* FEC buffer descriptor */ +typedef volatile struct MCD_bufDescFec_struct { + u16 statCtrl; + u16 length; + u32 dataPointer; +} MCD_bufDescFec; + + +/*************************************************************************/ +/* + * API function Prototypes - see MCD_dmaApi.c for further notes + */ + +/* + * MCD_startDma starts a particular kind of DMA . + */ +int MCD_startDma ( + int channel, /* the channel on which to run the DMA */ + s8 *srcAddr, /* the address to move data from, or buffer-descriptor address */ + s16 srcIncr, /* the amount to increment the source address per transfer */ + s8 *destAddr, /* the address to move data to */ + s16 destIncr, /* the amount to increment the destination address per transfer */ + u32 dmaSize, /* the number of bytes to transfer independent of the transfer size */ + u32 xferSize, /* the number bytes in of each data movement (1, 2, or 4) */ + u32 initiator, /* what device initiates the DMA */ + int priority, /* priority of the DMA */ + u32 flags, /* flags describing the DMA */ + u32 funcDesc /* a description of byte swapping, bit swapping, and CRC actions */ +); + +/* + * MCD_initDma() initializes the DMA API by setting up a pointer to the DMA + * registers, relocating and creating the appropriate task structures, and + * setting up some global settings + */ +int MCD_initDma (dmaRegs *sDmaBarAddr, void *taskTableDest, u32 flags); + +/* + * MCD_dmaStatus() returns the status of the DMA on the requested channel. + */ +int MCD_dmaStatus (int channel); + +/* + * MCD_XferProgrQuery() returns progress of DMA on requested channel + */ +int MCD_XferProgrQuery (int channel, MCD_XferProg *progRep); + +/* + * MCD_killDma() halts the DMA on the requested channel, without any + * intention of resuming the DMA. + */ +int MCD_killDma (int channel); + +/* + * MCD_continDma() continues a DMA which as stopped due to encountering an + * unready buffer descriptor. + */ +int MCD_continDma (int channel); + +/* + * MCD_pauseDma() pauses the DMA on the given channel ( if any DMA is + * running on that channel). + */ +int MCD_pauseDma (int channel); + +/* + * MCD_resumeDma() resumes the DMA on a given channel (if any DMA is + * running on that channel). + */ +int MCD_resumeDma (int channel); + +/* + * MCD_csumQuery provides the checksum/CRC after performing a non-chained DMA + */ +int MCD_csumQuery (int channel, u32 *csum); + +/* + * MCD_getCodeSize provides the packed size required by the microcoded task + * and structures. + */ +int MCD_getCodeSize(void); + +/* + * MCD_getVersion provides a pointer to a version string and returns a + * version number. + */ +int MCD_getVersion(char **longVersion); + +/* macro for setting a location in the variable table */ +#define MCD_SET_VAR(taskTab,idx,value) ((u32 *)(taskTab)->varTab)[idx] = value + /* Note that MCD_SET_VAR() is invoked many times in firing up a DMA function, + so I'm avoiding surrounding it with "do {} while(0)" */ + +#endif /* DEFINESONLY */ + +#endif /* _MCD_API_H */ --- /dev/null +++ b/drivers/dma/MCD_progCheck.h @@ -0,0 +1,28 @@ +/* + * drivers/dma/MCD_progCheck.h + * + * Copyright (C) 2004-2008 Freescale Semiconductor, Inc. + * Kurt Mahan + * + * 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 + */ + +/* This file is autogenerated. Do not change */ + +#define CURRBD 4 +#define DCOUNT 6 +#define DESTPTR 5 +#define SRCPTR 7 --- /dev/null +++ b/drivers/dma/MCD_tasks.c @@ -0,0 +1,2465 @@ +/* + * drivers/dma/MCD_tasks.c + * + * Copyright (C) 2004-2008 Freescale Semiconductor, Inc. + * Kurt Mahan + * + * 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 + */ + +#include "MCD_dma.h" + +u32 MCD_varTab0[]; +u32 MCD_varTab1[]; +u32 MCD_varTab2[]; +u32 MCD_varTab3[]; +u32 MCD_varTab4[]; +u32 MCD_varTab5[]; +u32 MCD_varTab6[]; +u32 MCD_varTab7[]; +u32 MCD_varTab8[]; +u32 MCD_varTab9[]; +u32 MCD_varTab10[]; +u32 MCD_varTab11[]; +u32 MCD_varTab12[]; +u32 MCD_varTab13[]; +u32 MCD_varTab14[]; +u32 MCD_varTab15[]; + +u32 MCD_funcDescTab0[]; +#ifdef MCD_INCLUDE_EU +u32 MCD_funcDescTab1[]; +u32 MCD_funcDescTab2[]; +u32 MCD_funcDescTab3[]; +u32 MCD_funcDescTab4[]; +u32 MCD_funcDescTab5[]; +u32 MCD_funcDescTab6[]; +u32 MCD_funcDescTab7[]; +u32 MCD_funcDescTab8[]; +u32 MCD_funcDescTab9[]; +u32 MCD_funcDescTab10[]; +u32 MCD_funcDescTab11[]; +u32 MCD_funcDescTab12[]; +u32 MCD_funcDescTab13[]; +u32 MCD_funcDescTab14[]; +u32 MCD_funcDescTab15[]; +#endif + +u32 MCD_contextSave0[]; +u32 MCD_contextSave1[]; +u32 MCD_contextSave2[]; +u32 MCD_contextSave3[]; +u32 MCD_contextSave4[]; +u32 MCD_contextSave5[]; +u32 MCD_contextSave6[]; +u32 MCD_contextSave7[]; +u32 MCD_contextSave8[]; +u32 MCD_contextSave9[]; +u32 MCD_contextSave10[]; +u32 MCD_contextSave11[]; +u32 MCD_contextSave12[]; +u32 MCD_contextSave13[]; +u32 MCD_contextSave14[]; +u32 MCD_contextSave15[]; + +u32 MCD_realTaskTableSrc[] = +{ + 0x00000000, + 0x00000000, + (u32)MCD_varTab0, /* Task 0 Variable Table */ + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ + 0x00000000, + 0x00000000, + (u32)MCD_contextSave0, /* Task 0 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab1, /* Task 1 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab1, /* Task 1 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave1, /* Task 1 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab2, /* Task 2 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab2, /* Task 2 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave2, /* Task 2 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab3, /* Task 3 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab3, /* Task 3 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave3, /* Task 3 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab4, /* Task 4 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab4, /* Task 4 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave4, /* Task 4 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab5, /* Task 5 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab5, /* Task 5 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave5, /* Task 5 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab6, /* Task 6 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab6, /* Task 6 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave6, /* Task 6 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab7, /* Task 7 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab7, /* Task 7 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave7, /* Task 7 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab8, /* Task 8 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab8, /* Task 8 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave8, /* Task 8 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab9, /* Task 9 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab9, /* Task 9 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave9, /* Task 9 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab10, /* Task 10 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab10, /* Task 10 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave10, /* Task 10 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab11, /* Task 11 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab11, /* Task 11 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave11, /* Task 11 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab12, /* Task 12 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab12, /* Task 12 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave12, /* Task 12 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab13, /* Task 13 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab13, /* Task 13 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave13, /* Task 13 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab14, /* Task 14 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab14, /* Task 14 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave14, /* Task 14 context save space */ + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_varTab15, /* Task 15 Variable Table */ +#ifdef MCD_INCLUDE_EU + (u32)MCD_funcDescTab15, /* Task 15 Function Descriptor Table & Flags */ +#else + (u32)MCD_funcDescTab0, /* Task 0 Function Descriptor Table & Flags */ +#endif + 0x00000000, + 0x00000000, + (u32)MCD_contextSave15, /* Task 15 context save space */ + 0x00000000, +}; + + +u32 MCD_varTab0[] = +{ /* Task 0 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + + +u32 MCD_varTab1[] = +{ /* Task 1 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab2[]= +{ /* Task 2 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab3[]= +{ /* Task 3 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab4[]= +{ /* Task 4 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab5[]= +{ /* Task 5 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab6[]= +{ /* Task 6 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab7[]= +{ /* Task 7 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab8[]= +{ /* Task 8 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab9[]= +{ /* Task 9 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab10[]= +{ /* Task 10 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab11[]= +{ /* Task 11 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab12[]= +{ /* Task 12 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab13[]= +{ /* Task 13 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab14[]= +{ /* Task 14 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_varTab15[]= +{ /* Task 15 Variable Table */ + 0x00000000, /* var[0] */ + 0x00000000, /* var[1] */ + 0x00000000, /* var[2] */ + 0x00000000, /* var[3] */ + 0x00000000, /* var[4] */ + 0x00000000, /* var[5] */ + 0x00000000, /* var[6] */ + 0x00000000, /* var[7] */ + 0x00000000, /* var[8] */ + 0x00000000, /* var[9] */ + 0x00000000, /* var[10] */ + 0x00000000, /* var[11] */ + 0x00000000, /* var[12] */ + 0x00000000, /* var[13] */ + 0x00000000, /* var[14] */ + 0x00000000, /* var[15] */ + 0x00000000, /* var[16] */ + 0x00000000, /* var[17] */ + 0x00000000, /* var[18] */ + 0x00000000, /* var[19] */ + 0x00000000, /* var[20] */ + 0x00000000, /* var[21] */ + 0x00000000, /* var[22] */ + 0x00000000, /* var[23] */ + 0xe0000000, /* inc[0] */ + 0x20000000, /* inc[1] */ + 0x2000ffff, /* inc[2] */ + 0x00000000, /* inc[3] */ + 0x00000000, /* inc[4] */ + 0x00000000, /* inc[5] */ + 0x00000000, /* inc[6] */ + 0x00000000, /* inc[7] */ +}; + +u32 MCD_funcDescTab0[]= +{ /* Task 0 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +#ifdef MCD_INCLUDE_EU +u32 MCD_funcDescTab1[]= +{ /* Task 1 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab2[]= +{ /* Task 2 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab3[]= +{ /* Task 3 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab4[]= +{ /* Task 4 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab5[]= +{ /* Task 5 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab6[]= +{ /* Task 6 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab7[]= +{ /* Task 7 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab8[]= +{ /* Task 8 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab9[]= +{ /* Task 9 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab10[]= +{ /* Task 10 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab11[]= +{ /* Task 11 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab12[]= +{ /* Task 12 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab13[]= +{ /* Task 13 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab14[]= +{ /* Task 14 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; + +u32 MCD_funcDescTab15[]= +{ /* Task 15 Function Descriptor Table */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xa0045670, /* mainFunc(), EU# 3 */ + 0xa0000000, /* rsduFunc(), EU# 3 */ + 0xa0000000, /* crcAccumVal(), EU# 3 */ + 0x20000000, /* setCrcAccum(), EU# 3 */ + 0x21800000, /* and(), EU# 3 */ + 0x21e00000, /* or(), EU# 3 */ + 0x20400000, /* add(), EU# 3 */ + 0x20500000, /* sub(), EU# 3 */ + 0x205a0000, /* andNot(), EU# 3 */ + 0x20a00000, /* shiftR(), EU# 3 */ + 0x202fa000, /* andReadyBit(), EU# 3 */ + 0x202f9000, /* andNotReadyBit(), EU# 3 */ + 0x202ea000, /* andWrapBit(), EU# 3 */ + 0x202da000, /* andLastBit(), EU# 3 */ + 0x202e2000, /* andInterruptBit(), EU# 3 */ + 0x202f2000, /* andCrcRestartBit(), EU# 3 */ +}; +#endif /*MCD_INCLUDE_EU*/ + +u32 MCD_contextSave0[128]; /* Task 0 context save space */ +u32 MCD_contextSave1[128]; /* Task 1 context save space */ +u32 MCD_contextSave2[128]; /* Task 2 context save space */ +u32 MCD_contextSave3[128]; /* Task 3 context save space */ +u32 MCD_contextSave4[128]; /* Task 4 context save space */ +u32 MCD_contextSave5[128]; /* Task 5 context save space */ +u32 MCD_contextSave6[128]; /* Task 6 context save space */ +u32 MCD_contextSave7[128]; /* Task 7 context save space */ +u32 MCD_contextSave8[128]; /* Task 8 context save space */ +u32 MCD_contextSave9[128]; /* Task 9 context save space */ +u32 MCD_contextSave10[128]; /* Task 10 context save space */ +u32 MCD_contextSave11[128]; /* Task 11 context save space */ +u32 MCD_contextSave12[128]; /* Task 12 context save space */ +u32 MCD_contextSave13[128]; /* Task 13 context save space */ +u32 MCD_contextSave14[128]; /* Task 14 context save space */ +u32 MCD_contextSave15[128]; /* Task 15 context save space */ + +u32 MCD_ChainNoEu_TDT[]; +u32 MCD_SingleNoEu_TDT[]; +#ifdef MCD_INCLUDE_EU +u32 MCD_ChainEu_TDT[]; +u32 MCD_SingleEu_TDT[]; +#endif +u32 MCD_ENetRcv_TDT[]; +u32 MCD_ENetXmit_TDT[]; + +u32 MCD_modelTaskTableSrc[]= +{ + (u32)MCD_ChainNoEu_TDT, + (u32)&((u8*)MCD_ChainNoEu_TDT)[0x0000016c], + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_SingleNoEu_TDT, + (u32)&((u8*)MCD_SingleNoEu_TDT)[0x000000d4], + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +#ifdef MCD_INCLUDE_EU + (u32)MCD_ChainEu_TDT, + (u32)&((u8*)MCD_ChainEu_TDT)[0x000001b4], + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_SingleEu_TDT, + (u32)&((u8*)MCD_SingleEu_TDT)[0x00000124], + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +#endif + (u32)MCD_ENetRcv_TDT, + (u32)&((u8*)MCD_ENetRcv_TDT)[0x000000a4], + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + (u32)MCD_ENetXmit_TDT, + (u32)&((u8*)MCD_ENetXmit_TDT)[0x000000d0], + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; +u32 MCD_ChainNoEu_TDT[]= +{ + 0x80004000, /* 0000(:370): LCDEXT: idx0 = 0x00000000; ; */ + 0x8118801b, /* 0004(:370): LCD: idx1 = var2; idx1 once var0; idx1 += inc3 */ + 0xb8c60018, /* 0008(:371): LCD: idx2 = *(idx1 + var12); idx2 once var0; idx2 += inc3 */ + 0x10002b10, /* 000C(:372): DRD1A: var10 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x7000000d, /* 0010(:373): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */ + 0x018cf89f, /* 0014(:373): DRD2B1: var6 = EU3(); EU3(idx2) */ + 0x6000000a, /* 0018(:374): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */ + 0x080cf89f, /* 001C(:374): DRD2B1: idx0 = EU3(); EU3(idx2) */ + 0x000001f8, /* 0020(:0): NOP */ + 0x98180364, /* 0024(:378): LCD: idx0 = idx0; idx0 == var13; idx0 += inc4 */ + 0x8118801b, /* 0028(:380): LCD: idx1 = var2; idx1 once var0; idx1 += inc3 */ + 0xf8c6001a, /* 002C(:381): LCDEXT: idx2 = *(idx1 + var12 + 8); idx2 once var0; idx2 += inc3 */ + 0xb8c6601b, /* 0030(:382): LCD: idx3 = *(idx1 + var12 + 12); ; idx3 += inc3 */ + 0x10002710, /* 0034(:384): DRD1A: var9 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x00000f18, /* 0038(:385): DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */ + 0xb8c6001d, /* 003C(:387): LCD: idx2 = *(idx1 + var12 + 20); idx2 once var0; idx2 += inc3 */ + 0x10001310, /* 0040(:388): DRD1A: var4 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x60000007, /* 0044(:389): DRD2A: EU0=0 EU1=0 EU2=0 EU3=7 EXT init=0 WS=0 RS=0 */ + 0x014cf88b, /* 0048(:389): DRD2B1: var5 = EU3(); EU3(idx2,var11) */ + 0x98c6001c, /* 004C(:391): LCD: idx2 = idx1 + var12 + 4; idx2 once var0; idx2 += inc3 */ + 0x00000710, /* 0050(:392): DRD1A: var1 = idx2; FN=0 init=0 WS=0 RS=0 */ + 0x98c70018, /* 0054(:393): LCD: idx2 = idx1 + var14; idx2 once var0; idx2 += inc3 */ + 0x10001f10, /* 0058(:394): DRD1A: var7 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x0000c818, /* 005C(:395): DRD1A: *idx2 = var3; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 0060(:0): NOP */ + 0xc1476018, /* 0064(:399): LCDEXT: idx1 = var2 + var14; ; idx1 += inc3 */ + 0xc003231d, /* 0068(:399): LCDEXT: idx2 = var0, idx3 = var6; idx3 == var12; idx2 += inc3, idx3 += inc5 */ + 0x811a601b, /* 006C(:400): LCD: idx4 = var2; ; idx4 += inc3 */ + 0xc1862102, /* 0070(:403): LCDEXT: idx5 = var3, idx6 = var12; idx6 < var4; idx5 += inc0, idx6 += inc2 */ + 0x849be009, /* 0074(:403): LCD: idx7 = var9; ; idx7 += inc1 */ + 0x03fed7b8, /* 0078(:406): DRD1A: *idx7; FN=0 init=31 WS=3 RS=3 */ + 0xda9b001b, /* 007C(:408): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 0080(:408): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x1000cb20, /* 0084(:409): DRD1A: *idx2 = idx4; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 0088(:410): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88f, /* 008C(:410): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */ + 0x1000cb28, /* 0090(:411): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 0094(:412): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88f, /* 0098(:412): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */ + 0x1000cb30, /* 009C(:413): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00A0(:414): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88f, /* 00A4(:414): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */ + 0x1000cb38, /* 00A8(:415): DRD1A: *idx2 = idx7; FN=0 MORE init=0 WS=0 RS=0 */ + 0x0000c728, /* 00AC(:416): DRD1A: *idx1 = idx5; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 00B0(:0): NOP */ + 0xc1476018, /* 00B4(:420): LCDEXT: idx1 = var2 + var14; ; idx1 += inc3 */ + 0xc003241d, /* 00B8(:420): LCDEXT: idx2 = var0, idx3 = var6; idx3 == var16; idx2 += inc3, idx3 += inc5 */ + 0x811a601b, /* 00BC(:421): LCD: idx4 = var2; ; idx4 += inc3 */ + 0xda9b001b, /* 00C0(:424): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 00C4(:424): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x0000d3a0, /* 00C8(:425): DRD1A: *idx4; FN=0 init=0 WS=0 RS=0 */ + 0xc1862102, /* 00CC(:427): LCDEXT: idx5 = var3, idx6 = var12; idx6 < var4; idx5 += inc0, idx6 += inc2 */ + 0x849be009, /* 00D0(:427): LCD: idx7 = var9; ; idx7 += inc1 */ + 0x0bfed7b8, /* 00D4(:430): DRD1A: *idx7; FN=0 TFD init=31 WS=3 RS=3 */ + 0xda9b001b, /* 00D8(:432): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 00DC(:432): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x1000cb20, /* 00E0(:433): DRD1A: *idx2 = idx4; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00E4(:434): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88f, /* 00E8(:434): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */ + 0x1000cb28, /* 00EC(:435): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00F0(:436): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88f, /* 00F4(:436): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */ + 0x1000cb30, /* 00F8(:437): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00FC(:438): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88f, /* 0100(:438): DRD2B1: idx2 = EU3(); EU3(idx2,var15) */ + 0x1000cb38, /* 0104(:439): DRD1A: *idx2 = idx7; FN=0 MORE init=0 WS=0 RS=0 */ + 0x0000c728, /* 0108(:440): DRD1A: *idx1 = idx5; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 010C(:0): NOP */ + 0x8118801b, /* 0110(:444): LCD: idx1 = var2; idx1 once var0; idx1 += inc3 */ + 0xd8c60018, /* 0114(:446): LCDEXT: idx2 = idx1 + var12; idx2 once var0; idx2 += inc3 */ + 0x98c6601c, /* 0118(:446): LCD: idx3 = idx1 + var12 + 4; ; idx3 += inc3 */ + 0x6000000b, /* 011C(:447): DRD2A: EU0=0 EU1=0 EU2=0 EU3=11 EXT init=0 WS=0 RS=0 */ + 0x0c8cfc9f, /* 0120(:447): DRD2B1: *idx2 = EU3(); EU3(*idx2) */ + 0x000001f8, /* 0124(:0): NOP */ + 0xa146001e, /* 0128(:450): LCD: idx1 = *(var2 + var12 + 24); idx1 once var0; idx1 += inc3 */ + 0x10000b08, /* 012C(:451): DRD1A: var2 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x10002050, /* 0130(:452): DRD1A: var8 = var10; FN=0 MORE init=0 WS=0 RS=0 */ + 0xb8c60018, /* 0134(:453): LCD: idx2 = *(idx1 + var12); idx2 once var0; idx2 += inc3 */ + 0x10002b10, /* 0138(:454): DRD1A: var10 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x7000000a, /* 013C(:455): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT MORE init=0 WS=0 RS=0 */ + 0x080cf89f, /* 0140(:455): DRD2B1: idx0 = EU3(); EU3(idx2) */ + 0x6000000d, /* 0144(:456): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT init=0 WS=0 RS=0 */ + 0x018cf89f, /* 0148(:456): DRD2B1: var6 = EU3(); EU3(idx2) */ + 0x000001f8, /* 014C(:0): NOP */ + 0x8618801b, /* 0150(:462): LCD: idx1 = var12; idx1 once var0; idx1 += inc3 */ + 0x7000000e, /* 0154(:463): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT MORE init=0 WS=0 RS=0 */ + 0x084cf21f, /* 0158(:463): DRD2B1: idx1 = EU3(); EU3(var8) */ + 0xd8990336, /* 015C(:464): LCDEXT: idx2 = idx1; idx2 > var12; idx2 += inc6 */ + 0x8019801b, /* 0160(:464): LCD: idx3 = var0; idx3 once var0; idx3 += inc3 */ + 0x040001f8, /* 0164(:465): DRD1A: FN=0 INT init=0 WS=0 RS=0 */ + 0x000001f8, /* 0168(:0): NOP */ + 0x000001f8, /* 016C(:0): NOP */ +}; +u32 MCD_SingleNoEu_TDT[]= +{ + 0x8198001b, /* 0000(:657): LCD: idx0 = var3; idx0 once var0; idx0 += inc3 */ + 0x7000000d, /* 0004(:658): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */ + 0x080cf81f, /* 0008(:658): DRD2B1: idx0 = EU3(); EU3(idx0) */ + 0x8198801b, /* 000C(:659): LCD: idx1 = var3; idx1 once var0; idx1 += inc3 */ + 0x6000000e, /* 0010(:660): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT init=0 WS=0 RS=0 */ + 0x084cf85f, /* 0014(:660): DRD2B1: idx1 = EU3(); EU3(idx1) */ + 0x000001f8, /* 0018(:0): NOP */ + 0x8298001b, /* 001C(:664): LCD: idx0 = var5; idx0 once var0; idx0 += inc3 */ + 0x7000000d, /* 0020(:665): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */ + 0x010cf81f, /* 0024(:665): DRD2B1: var4 = EU3(); EU3(idx0) */ + 0x6000000e, /* 0028(:666): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT init=0 WS=0 RS=0 */ + 0x018cf81f, /* 002C(:666): DRD2B1: var6 = EU3(); EU3(idx0) */ + 0xc202601b, /* 0030(:669): LCDEXT: idx0 = var4, idx1 = var4; ; idx0 += inc3, idx1 += inc3 */ + 0xc002221c, /* 0034(:669): LCDEXT: idx2 = var0, idx3 = var4; idx3 == var8; idx2 += inc3, idx3 += inc4 */ + 0x809a601b, /* 0038(:670): LCD: idx4 = var1; ; idx4 += inc3 */ + 0xc10420c2, /* 003C(:673): LCDEXT: idx5 = var2, idx6 = var8; idx6 < var3; idx5 += inc0, idx6 += inc2 */ + 0x839be009, /* 0040(:673): LCD: idx7 = var7; ; idx7 += inc1 */ + 0x03fed7b8, /* 0044(:676): DRD1A: *idx7; FN=0 init=31 WS=3 RS=3 */ + 0xda9b001b, /* 0048(:678): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 004C(:678): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x70000006, /* 0050(:680): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf889, /* 0054(:680): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */ + 0x1000cb28, /* 0058(:681): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 005C(:682): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf889, /* 0060(:682): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */ + 0x1000cb30, /* 0064(:683): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 0068(:684): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf889, /* 006C(:684): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */ + 0x0000cb38, /* 0070(:685): DRD1A: *idx2 = idx7; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 0074(:0): NOP */ + 0xc202601b, /* 0078(:689): LCDEXT: idx0 = var4, idx1 = var4; ; idx0 += inc3, idx1 += inc3 */ + 0xc002229c, /* 007C(:689): LCDEXT: idx2 = var0, idx3 = var4; idx3 == var10; idx2 += inc3, idx3 += inc4 */ + 0x809a601b, /* 0080(:690): LCD: idx4 = var1; ; idx4 += inc3 */ + 0xda9b001b, /* 0084(:693): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 0088(:693): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x0000d3a0, /* 008C(:694): DRD1A: *idx4; FN=0 init=0 WS=0 RS=0 */ + 0xc10420c2, /* 0090(:696): LCDEXT: idx5 = var2, idx6 = var8; idx6 < var3; idx5 += inc0, idx6 += inc2 */ + 0x839be009, /* 0094(:696): LCD: idx7 = var7; ; idx7 += inc1 */ + 0x0bfed7b8, /* 0098(:699): DRD1A: *idx7; FN=0 TFD init=31 WS=3 RS=3 */ + 0xda9b001b, /* 009C(:701): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 00A0(:701): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x70000006, /* 00A4(:703): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf889, /* 00A8(:703): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */ + 0x1000cb28, /* 00AC(:704): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00B0(:705): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf889, /* 00B4(:705): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */ + 0x1000cb30, /* 00B8(:706): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00BC(:707): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf889, /* 00C0(:707): DRD2B1: idx2 = EU3(); EU3(idx2,var9) */ + 0x0000cb38, /* 00C4(:708): DRD1A: *idx2 = idx7; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 00C8(:0): NOP */ + 0xc318022d, /* 00CC(:712): LCDEXT: idx0 = var6; idx0 > var8; idx0 += inc5 */ + 0x8018801b, /* 00D0(:712): LCD: idx1 = var0; idx1 once var0; idx1 += inc3 */ + 0x040001f8, /* 00D4(:713): DRD1A: FN=0 INT init=0 WS=0 RS=0 */ +}; +#ifdef MCD_INCLUDE_EU +u32 MCD_ChainEu_TDT[]= +{ + 0x80004000, /* 0000(:947): LCDEXT: idx0 = 0x00000000; ; */ + 0x8198801b, /* 0004(:947): LCD: idx1 = var3; idx1 once var0; idx1 += inc3 */ + 0xb8c68018, /* 0008(:948): LCD: idx2 = *(idx1 + var13); idx2 once var0; idx2 += inc3 */ + 0x10002f10, /* 000C(:949): DRD1A: var11 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x7000000d, /* 0010(:950): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */ + 0x01ccf89f, /* 0014(:950): DRD2B1: var7 = EU3(); EU3(idx2) */ + 0x6000000a, /* 0018(:951): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */ + 0x080cf89f, /* 001C(:951): DRD2B1: idx0 = EU3(); EU3(idx2) */ + 0x000001f8, /* 0020(:0): NOP */ + 0x981803a4, /* 0024(:955): LCD: idx0 = idx0; idx0 == var14; idx0 += inc4 */ + 0x8198801b, /* 0028(:957): LCD: idx1 = var3; idx1 once var0; idx1 += inc3 */ + 0xf8c6801a, /* 002C(:958): LCDEXT: idx2 = *(idx1 + var13 + 8); idx2 once var0; idx2 += inc3 */ + 0xb8c6e01b, /* 0030(:959): LCD: idx3 = *(idx1 + var13 + 12); ; idx3 += inc3 */ + 0x10002b10, /* 0034(:961): DRD1A: var10 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x00001318, /* 0038(:962): DRD1A: var4 = idx3; FN=0 init=0 WS=0 RS=0 */ + 0xb8c6801d, /* 003C(:964): LCD: idx2 = *(idx1 + var13 + 20); idx2 once var0; idx2 += inc3 */ + 0x10001710, /* 0040(:965): DRD1A: var5 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x60000007, /* 0044(:966): DRD2A: EU0=0 EU1=0 EU2=0 EU3=7 EXT init=0 WS=0 RS=0 */ + 0x018cf88c, /* 0048(:966): DRD2B1: var6 = EU3(); EU3(idx2,var12) */ + 0x98c6801c, /* 004C(:968): LCD: idx2 = idx1 + var13 + 4; idx2 once var0; idx2 += inc3 */ + 0x00000b10, /* 0050(:969): DRD1A: var2 = idx2; FN=0 init=0 WS=0 RS=0 */ + 0x98c78018, /* 0054(:970): LCD: idx2 = idx1 + var15; idx2 once var0; idx2 += inc3 */ + 0x10002310, /* 0058(:971): DRD1A: var8 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x0000c820, /* 005C(:972): DRD1A: *idx2 = var4; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 0060(:0): NOP */ + 0x8698801b, /* 0064(:976): LCD: idx1 = var13; idx1 once var0; idx1 += inc3 */ + 0x7000000f, /* 0068(:977): DRD2A: EU0=0 EU1=0 EU2=0 EU3=15 EXT MORE init=0 WS=0 RS=0 */ + 0x084cf2df, /* 006C(:977): DRD2B1: idx1 = EU3(); EU3(var11) */ + 0xd899042d, /* 0070(:978): LCDEXT: idx2 = idx1; idx2 >= var16; idx2 += inc5 */ + 0x8019801b, /* 0074(:978): LCD: idx3 = var0; idx3 once var0; idx3 += inc3 */ + 0x60000003, /* 0078(:979): DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */ + 0x2cd7c7df, /* 007C(:979): DRD2B2: EU3(var13) */ + 0xd8990364, /* 0080(:980): LCDEXT: idx2 = idx1; idx2 == var13; idx2 += inc4 */ + 0x8019801b, /* 0084(:980): LCD: idx3 = var0; idx3 once var0; idx3 += inc3 */ + 0x60000003, /* 0088(:981): DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */ + 0x2c17c7df, /* 008C(:981): DRD2B2: EU3(var1) */ + 0x000001f8, /* 0090(:0): NOP */ + 0xc1c7e018, /* 0094(:984): LCDEXT: idx1 = var3 + var15; ; idx1 += inc3 */ + 0xc003a35e, /* 0098(:984): LCDEXT: idx2 = var0, idx3 = var7; idx3 == var13; idx2 += inc3, idx3 += inc6 */ + 0x819a601b, /* 009C(:985): LCD: idx4 = var3; ; idx4 += inc3 */ + 0xc206a142, /* 00A0(:988): LCDEXT: idx5 = var4, idx6 = var13; idx6 < var5; idx5 += inc0, idx6 += inc2 */ + 0x851be009, /* 00A4(:988): LCD: idx7 = var10; ; idx7 += inc1 */ + 0x63fe0000, /* 00A8(:991): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=31 WS=3 RS=3 */ + 0x0d4cfddf, /* 00AC(:991): DRD2B1: *idx5 = EU3(); EU3(*idx7) */ + 0xda9b001b, /* 00B0(:993): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 00B4(:993): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x70000002, /* 00B8(:994): DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ + 0x004cf81f, /* 00BC(:994): DRD2B1: var1 = EU3(); EU3(idx0) */ + 0x1000cb20, /* 00C0(:995): DRD1A: *idx2 = idx4; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00C4(:996): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf891, /* 00C8(:996): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */ + 0x1000cb28, /* 00CC(:997): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00D0(:998): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf891, /* 00D4(:998): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */ + 0x1000cb30, /* 00D8(:999): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00DC(:1000): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf891, /* 00E0(:1000): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */ + 0x1000cb38, /* 00E4(:1001): DRD1A: *idx2 = idx7; FN=0 MORE init=0 WS=0 RS=0 */ + 0x0000c728, /* 00E8(:1002): DRD1A: *idx1 = idx5; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 00EC(:0): NOP */ + 0xc1c7e018, /* 00F0(:1006): LCDEXT: idx1 = var3 + var15; ; idx1 += inc3 */ + 0xc003a49e, /* 00F4(:1006): LCDEXT: idx2 = var0, idx3 = var7; idx3 == var18; idx2 += inc3, idx3 += inc6 */ + 0x819a601b, /* 00F8(:1007): LCD: idx4 = var3; ; idx4 += inc3 */ + 0xda9b001b, /* 00FC(:1010): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 0100(:1010): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x0000d3a0, /* 0104(:1011): DRD1A: *idx4; FN=0 init=0 WS=0 RS=0 */ + 0xc206a142, /* 0108(:1013): LCDEXT: idx5 = var4, idx6 = var13; idx6 < var5; idx5 += inc0, idx6 += inc2 */ + 0x851be009, /* 010C(:1013): LCD: idx7 = var10; ; idx7 += inc1 */ + 0x6bfe0000, /* 0110(:1016): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 TFD EXT init=31 WS=3 RS=3 */ + 0x0d4cfddf, /* 0114(:1016): DRD2B1: *idx5 = EU3(); EU3(*idx7) */ + 0xda9b001b, /* 0118(:1018): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 011C(:1018): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x70000002, /* 0120(:1019): DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ + 0x004cf81f, /* 0124(:1019): DRD2B1: var1 = EU3(); EU3(idx0) */ + 0x1000cb20, /* 0128(:1020): DRD1A: *idx2 = idx4; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 012C(:1021): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf891, /* 0130(:1021): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */ + 0x1000cb28, /* 0134(:1022): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 0138(:1023): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf891, /* 013C(:1023): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */ + 0x1000cb30, /* 0140(:1024): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 0144(:1025): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf891, /* 0148(:1025): DRD2B1: idx2 = EU3(); EU3(idx2,var17) */ + 0x1000cb38, /* 014C(:1026): DRD1A: *idx2 = idx7; FN=0 MORE init=0 WS=0 RS=0 */ + 0x0000c728, /* 0150(:1027): DRD1A: *idx1 = idx5; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 0154(:0): NOP */ + 0x8198801b, /* 0158(:1031): LCD: idx1 = var3; idx1 once var0; idx1 += inc3 */ + 0xd8c68018, /* 015C(:1033): LCDEXT: idx2 = idx1 + var13; idx2 once var0; idx2 += inc3 */ + 0x98c6e01c, /* 0160(:1033): LCD: idx3 = idx1 + var13 + 4; ; idx3 += inc3 */ + 0x6000000b, /* 0164(:1034): DRD2A: EU0=0 EU1=0 EU2=0 EU3=11 EXT init=0 WS=0 RS=0 */ + 0x0c8cfc9f, /* 0168(:1034): DRD2B1: *idx2 = EU3(); EU3(*idx2) */ + 0x0000cc08, /* 016C(:1035): DRD1A: *idx3 = var1; FN=0 init=0 WS=0 RS=0 */ + 0xa1c6801e, /* 0170(:1038): LCD: idx1 = *(var3 + var13 + 24); idx1 once var0; idx1 += inc3 */ + 0x10000f08, /* 0174(:1039): DRD1A: var3 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x10002458, /* 0178(:1040): DRD1A: var9 = var11; FN=0 MORE init=0 WS=0 RS=0 */ + 0xb8c68018, /* 017C(:1041): LCD: idx2 = *(idx1 + var13); idx2 once var0; idx2 += inc3 */ + 0x10002f10, /* 0180(:1042): DRD1A: var11 = idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x7000000a, /* 0184(:1043): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT MORE init=0 WS=0 RS=0 */ + 0x080cf89f, /* 0188(:1043): DRD2B1: idx0 = EU3(); EU3(idx2) */ + 0x6000000d, /* 018C(:1044): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT init=0 WS=0 RS=0 */ + 0x01ccf89f, /* 0190(:1044): DRD2B1: var7 = EU3(); EU3(idx2) */ + 0x000001f8, /* 0194(:0): NOP */ + 0x8698801b, /* 0198(:1050): LCD: idx1 = var13; idx1 once var0; idx1 += inc3 */ + 0x7000000e, /* 019C(:1051): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT MORE init=0 WS=0 RS=0 */ + 0x084cf25f, /* 01A0(:1051): DRD2B1: idx1 = EU3(); EU3(var9) */ + 0xd899037f, /* 01A4(:1052): LCDEXT: idx2 = idx1; idx2 > var13; idx2 += inc7 */ + 0x8019801b, /* 01A8(:1052): LCD: idx3 = var0; idx3 once var0; idx3 += inc3 */ + 0x040001f8, /* 01AC(:1053): DRD1A: FN=0 INT init=0 WS=0 RS=0 */ + 0x000001f8, /* 01B0(:0): NOP */ + 0x000001f8, /* 01B4(:0): NOP */ +}; +u32 MCD_SingleEu_TDT[]= +{ + 0x8218001b, /* 0000(:1248): LCD: idx0 = var4; idx0 once var0; idx0 += inc3 */ + 0x7000000d, /* 0004(:1249): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */ + 0x080cf81f, /* 0008(:1249): DRD2B1: idx0 = EU3(); EU3(idx0) */ + 0x8218801b, /* 000C(:1250): LCD: idx1 = var4; idx1 once var0; idx1 += inc3 */ + 0x6000000e, /* 0010(:1251): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT init=0 WS=0 RS=0 */ + 0x084cf85f, /* 0014(:1251): DRD2B1: idx1 = EU3(); EU3(idx1) */ + 0x000001f8, /* 0018(:0): NOP */ + 0x8318001b, /* 001C(:1255): LCD: idx0 = var6; idx0 once var0; idx0 += inc3 */ + 0x7000000d, /* 0020(:1256): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */ + 0x014cf81f, /* 0024(:1256): DRD2B1: var5 = EU3(); EU3(idx0) */ + 0x6000000e, /* 0028(:1257): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT init=0 WS=0 RS=0 */ + 0x01ccf81f, /* 002C(:1257): DRD2B1: var7 = EU3(); EU3(idx0) */ + 0x8498001b, /* 0030(:1260): LCD: idx0 = var9; idx0 once var0; idx0 += inc3 */ + 0x7000000f, /* 0034(:1261): DRD2A: EU0=0 EU1=0 EU2=0 EU3=15 EXT MORE init=0 WS=0 RS=0 */ + 0x080cf19f, /* 0038(:1261): DRD2B1: idx0 = EU3(); EU3(var6) */ + 0xd81882a4, /* 003C(:1262): LCDEXT: idx1 = idx0; idx1 >= var10; idx1 += inc4 */ + 0x8019001b, /* 0040(:1262): LCD: idx2 = var0; idx2 once var0; idx2 += inc3 */ + 0x60000003, /* 0044(:1263): DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */ + 0x2c97c7df, /* 0048(:1263): DRD2B2: EU3(var9) */ + 0xd818826d, /* 004C(:1264): LCDEXT: idx1 = idx0; idx1 == var9; idx1 += inc5 */ + 0x8019001b, /* 0050(:1264): LCD: idx2 = var0; idx2 once var0; idx2 += inc3 */ + 0x60000003, /* 0054(:1265): DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */ + 0x2c17c7df, /* 0058(:1265): DRD2B2: EU3(var1) */ + 0x000001f8, /* 005C(:0): NOP */ + 0xc282e01b, /* 0060(:1268): LCDEXT: idx0 = var5, idx1 = var5; ; idx0 += inc3, idx1 += inc3 */ + 0xc002a25e, /* 0064(:1268): LCDEXT: idx2 = var0, idx3 = var5; idx3 == var9; idx2 += inc3, idx3 += inc6 */ + 0x811a601b, /* 0068(:1269): LCD: idx4 = var2; ; idx4 += inc3 */ + 0xc184a102, /* 006C(:1272): LCDEXT: idx5 = var3, idx6 = var9; idx6 < var4; idx5 += inc0, idx6 += inc2 */ + 0x841be009, /* 0070(:1272): LCD: idx7 = var8; ; idx7 += inc1 */ + 0x63fe0000, /* 0074(:1275): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=31 WS=3 RS=3 */ + 0x0d4cfddf, /* 0078(:1275): DRD2B1: *idx5 = EU3(); EU3(*idx7) */ + 0xda9b001b, /* 007C(:1277): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 0080(:1277): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x70000002, /* 0084(:1279): DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ + 0x004cf99f, /* 0088(:1279): DRD2B1: var1 = EU3(); EU3(idx6) */ + 0x70000006, /* 008C(:1280): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88b, /* 0090(:1280): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */ + 0x1000cb28, /* 0094(:1281): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 0098(:1282): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88b, /* 009C(:1282): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */ + 0x1000cb30, /* 00A0(:1283): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00A4(:1284): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88b, /* 00A8(:1284): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */ + 0x0000cb38, /* 00AC(:1285): DRD1A: *idx2 = idx7; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 00B0(:0): NOP */ + 0xc282e01b, /* 00B4(:1289): LCDEXT: idx0 = var5, idx1 = var5; ; idx0 += inc3, idx1 += inc3 */ + 0xc002a31e, /* 00B8(:1289): LCDEXT: idx2 = var0, idx3 = var5; idx3 == var12; idx2 += inc3, idx3 += inc6 */ + 0x811a601b, /* 00BC(:1290): LCD: idx4 = var2; ; idx4 += inc3 */ + 0xda9b001b, /* 00C0(:1293): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 00C4(:1293): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x0000d3a0, /* 00C8(:1294): DRD1A: *idx4; FN=0 init=0 WS=0 RS=0 */ + 0xc184a102, /* 00CC(:1296): LCDEXT: idx5 = var3, idx6 = var9; idx6 < var4; idx5 += inc0, idx6 += inc2 */ + 0x841be009, /* 00D0(:1296): LCD: idx7 = var8; ; idx7 += inc1 */ + 0x6bfe0000, /* 00D4(:1299): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 TFD EXT init=31 WS=3 RS=3 */ + 0x0d4cfddf, /* 00D8(:1299): DRD2B1: *idx5 = EU3(); EU3(*idx7) */ + 0xda9b001b, /* 00DC(:1301): LCDEXT: idx5 = idx5, idx6 = idx6; idx5 once var0; idx5 += inc3, idx6 += inc3 */ + 0x9b9be01b, /* 00E0(:1301): LCD: idx7 = idx7; ; idx7 += inc3 */ + 0x70000002, /* 00E4(:1303): DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ + 0x004cf99f, /* 00E8(:1303): DRD2B1: var1 = EU3(); EU3(idx6) */ + 0x70000006, /* 00EC(:1304): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88b, /* 00F0(:1304): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */ + 0x1000cb28, /* 00F4(:1305): DRD1A: *idx2 = idx5; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 00F8(:1306): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88b, /* 00FC(:1306): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */ + 0x1000cb30, /* 0100(:1307): DRD1A: *idx2 = idx6; FN=0 MORE init=0 WS=0 RS=0 */ + 0x70000006, /* 0104(:1308): DRD2A: EU0=0 EU1=0 EU2=0 EU3=6 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf88b, /* 0108(:1308): DRD2B1: idx2 = EU3(); EU3(idx2,var11) */ + 0x0000cb38, /* 010C(:1309): DRD1A: *idx2 = idx7; FN=0 init=0 WS=0 RS=0 */ + 0x000001f8, /* 0110(:0): NOP */ + 0x8144801c, /* 0114(:1312): LCD: idx0 = var2 + var9 + 4; idx0 once var0; idx0 += inc3 */ + 0x0000c008, /* 0118(:1313): DRD1A: *idx0 = var1; FN=0 init=0 WS=0 RS=0 */ + 0xc398027f, /* 011C(:1315): LCDEXT: idx0 = var7; idx0 > var9; idx0 += inc7 */ + 0x8018801b, /* 0120(:1315): LCD: idx1 = var0; idx1 once var0; idx1 += inc3 */ + 0x040001f8, /* 0124(:1316): DRD1A: FN=0 INT init=0 WS=0 RS=0 */ +}; +#endif +u32 MCD_ENetRcv_TDT[]= +{ + 0x80004000, /* 0000(:1389): LCDEXT: idx0 = 0x00000000; ; */ + 0x81988000, /* 0004(:1389): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ + 0x10000788, /* 0008(:1390): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x6000000a, /* 000C(:1391): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */ + 0x080cf05f, /* 0010(:1391): DRD2B1: idx0 = EU3(); EU3(var1) */ + 0x98180209, /* 0014(:1394): LCD: idx0 = idx0; idx0 != var8; idx0 += inc1 */ + 0x81c40004, /* 0018(:1396): LCD: idx1 = var3 + var8 + 4; idx1 once var0; idx1 += inc0 */ + 0x7000000e, /* 001C(:1397): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT MORE init=0 WS=0 RS=0 */ + 0x010cf05f, /* 0020(:1397): DRD2B1: var4 = EU3(); EU3(var1) */ + 0x7000000c, /* 0024(:1398): DRD2A: EU0=0 EU1=0 EU2=0 EU3=12 EXT MORE init=0 WS=0 RS=0 */ + 0x01ccf05f, /* 0028(:1398): DRD2B1: var7 = EU3(); EU3(var1) */ + 0x70000004, /* 002C(:1399): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT MORE init=0 WS=0 RS=0 */ + 0x014cf049, /* 0030(:1399): DRD2B1: var5 = EU3(); EU3(var1,var9) */ + 0x70000004, /* 0034(:1400): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT MORE init=0 WS=0 RS=0 */ + 0x004cf04a, /* 0038(:1400): DRD2B1: var1 = EU3(); EU3(var1,var10) */ + 0x00000b88, /* 003C(:1403): DRD1A: var2 = *idx1; FN=0 init=0 WS=0 RS=0 */ + 0xc4030150, /* 0040(:1406): LCDEXT: idx1 = var8, idx2 = var6; idx1 < var5; idx1 += inc2, idx2 += inc0 */ + 0x8119e012, /* 0044(:1406): LCD: idx3 = var2; ; idx3 += inc2 */ + 0x03e0cf90, /* 0048(:1409): DRD1A: *idx3 = *idx2; FN=0 init=31 WS=0 RS=0 */ + 0x81188000, /* 004C(:1412): LCD: idx1 = var2; idx1 once var0; idx1 += inc0 */ + 0x000ac788, /* 0050(:1413): DRD1A: *idx1 = *idx1; FN=0 init=0 WS=1 RS=1 */ + 0xc4030000, /* 0054(:1415): LCDEXT: idx1 = var8, idx2 = var6; idx1 once var0; idx1 += inc0, idx2 += inc0 */ + 0x8199e000, /* 0058(:1415): LCD: idx3 = var3; ; idx3 += inc0 */ + 0x63e00004, /* 005C(:1418): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT init=31 WS=0 RS=0 */ + 0x084cfc8b, /* 0060(:1418): DRD2B1: idx1 = EU3(); EU3(*idx2,var11) */ + 0xd8990000, /* 0064(:1421): LCDEXT: idx1 = idx1, idx2 = idx2; idx1 once var0; idx1 += inc0, idx2 += inc0 */ + 0x9999e000, /* 0068(:1421): LCD: idx3 = idx3; ; idx3 += inc0 */ + 0x60000005, /* 006C(:1422): DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ + 0x0cccf841, /* 0070(:1422): DRD2B1: *idx3 = EU3(); EU3(idx1,var1) */ + 0x81c60000, /* 0074(:1427): LCD: idx1 = var3 + var12; idx1 once var0; idx1 += inc0 */ + 0xc399021b, /* 0078(:1429): LCDEXT: idx2 = var7; idx2 > var8; idx2 += inc3 */ + 0x80198000, /* 007C(:1429): LCD: idx3 = var0; idx3 once var0; idx3 += inc0 */ + 0x00008400, /* 0080(:1430): DRD1A: idx1 = var0; FN=0 init=0 WS=0 RS=0 */ + 0x00000f08, /* 0084(:1431): DRD1A: var3 = idx1; FN=0 init=0 WS=0 RS=0 */ + 0x81988000, /* 0088(:1434): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ + 0x10000788, /* 008C(:1435): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x6000000a, /* 0090(:1436): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */ + 0x080cf05f, /* 0094(:1436): DRD2B1: idx0 = EU3(); EU3(var1) */ + 0xc2188209, /* 0098(:1439): LCDEXT: idx1 = var4; idx1 != var8; idx1 += inc1 */ + 0x80190000, /* 009C(:1439): LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */ + 0x040001f8, /* 00A0(:1440): DRD1A: FN=0 INT init=0 WS=0 RS=0 */ + 0x000001f8, /* 00A4(:0): NOP */ +}; +u32 MCD_ENetXmit_TDT[]= +{ + 0x80004000, /* 0000(:1515): LCDEXT: idx0 = 0x00000000; ; */ + 0x81988000, /* 0004(:1515): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ + 0x10000788, /* 0008(:1516): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x6000000a, /* 000C(:1517): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */ + 0x080cf05f, /* 0010(:1517): DRD2B1: idx0 = EU3(); EU3(var1) */ + 0x98180309, /* 0014(:1520): LCD: idx0 = idx0; idx0 != var12; idx0 += inc1 */ + 0x80004003, /* 0018(:1522): LCDEXT: idx1 = 0x00000003; ; */ + 0x81c60004, /* 001C(:1522): LCD: idx2 = var3 + var12 + 4; idx2 once var0; idx2 += inc0 */ + 0x7000000e, /* 0020(:1523): DRD2A: EU0=0 EU1=0 EU2=0 EU3=14 EXT MORE init=0 WS=0 RS=0 */ + 0x014cf05f, /* 0024(:1523): DRD2B1: var5 = EU3(); EU3(var1) */ + 0x7000000c, /* 0028(:1524): DRD2A: EU0=0 EU1=0 EU2=0 EU3=12 EXT MORE init=0 WS=0 RS=0 */ + 0x028cf05f, /* 002C(:1524): DRD2B1: var10 = EU3(); EU3(var1) */ + 0x7000000d, /* 0030(:1525): DRD2A: EU0=0 EU1=0 EU2=0 EU3=13 EXT MORE init=0 WS=0 RS=0 */ + 0x018cf05f, /* 0034(:1525): DRD2B1: var6 = EU3(); EU3(var1) */ + 0x70000004, /* 0038(:1526): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT MORE init=0 WS=0 RS=0 */ + 0x01ccf04d, /* 003C(:1526): DRD2B1: var7 = EU3(); EU3(var1,var13) */ + 0x10000b90, /* 0040(:1527): DRD1A: var2 = *idx2; FN=0 MORE init=0 WS=0 RS=0 */ + 0x60000004, /* 0044(:1528): DRD2A: EU0=0 EU1=0 EU2=0 EU3=4 EXT init=0 WS=0 RS=0 */ + 0x020cf0a1, /* 0048(:1528): DRD2B1: var8 = EU3(); EU3(var2,idx1) */ + 0xc3188312, /* 004C(:1531): LCDEXT: idx1 = var6; idx1 > var12; idx1 += inc2 */ + 0x83c70000, /* 0050(:1531): LCD: idx2 = var7 + var14; idx2 once var0; idx2 += inc0 */ + 0x00001f10, /* 0054(:1532): DRD1A: var7 = idx2; FN=0 init=0 WS=0 RS=0 */ + 0xc583a3c3, /* 0058(:1534): LCDEXT: idx1 = var11, idx2 = var7; idx2 >= var15; idx1 += inc0, idx2 += inc3 */ + 0x81042325, /* 005C(:1534): LCD: idx3 = var2, idx4 = var8; idx4 == var12; idx3 += inc4, idx4 += inc5 */ + 0x03e0c798, /* 0060(:1539): DRD1A: *idx1 = *idx3; FN=0 init=31 WS=0 RS=0 */ + 0xd8990000, /* 0064(:1542): LCDEXT: idx1 = idx1, idx2 = idx2; idx1 once var0; idx1 += inc0, idx2 += inc0 */ + 0x9999e000, /* 0068(:1542): LCD: idx3 = idx3; ; idx3 += inc0 */ + 0x000acf98, /* 006C(:1543): DRD1A: *idx3 = *idx3; FN=0 init=0 WS=1 RS=1 */ + 0xd8992306, /* 0070(:1545): LCDEXT: idx1 = idx1, idx2 = idx2; idx2 > var12; idx1 += inc0, idx2 += inc6 */ + 0x9999e03f, /* 0074(:1545): LCD: idx3 = idx3; ; idx3 += inc7 */ + 0x03eac798, /* 0078(:1548): DRD1A: *idx1 = *idx3; FN=0 init=31 WS=1 RS=1 */ + 0xd8990000, /* 007C(:1551): LCDEXT: idx1 = idx1, idx2 = idx2; idx1 once var0; idx1 += inc0, idx2 += inc0 */ + 0x9999e000, /* 0080(:1551): LCD: idx3 = idx3; ; idx3 += inc0 */ + 0x000acf98, /* 0084(:1552): DRD1A: *idx3 = *idx3; FN=0 init=0 WS=1 RS=1 */ + 0xd8990000, /* 0088(:1554): LCDEXT: idx1 = idx1, idx2 = idx2; idx1 once var0; idx1 += inc0, idx2 += inc0 */ + 0x99832302, /* 008C(:1554): LCD: idx3 = idx3, idx4 = var6; idx4 > var12; idx3 += inc0, idx4 += inc2 */ + 0x0beac798, /* 0090(:1557): DRD1A: *idx1 = *idx3; FN=0 TFD init=31 WS=1 RS=1 */ + 0x81988000, /* 0094(:1559): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ + 0x6000000b, /* 0098(:1560): DRD2A: EU0=0 EU1=0 EU2=0 EU3=11 EXT init=0 WS=0 RS=0 */ + 0x0c4cfc5f, /* 009C(:1560): DRD2B1: *idx1 = EU3(); EU3(*idx1) */ + 0x81c80000, /* 00A0(:1562): LCD: idx1 = var3 + var16; idx1 once var0; idx1 += inc0 */ + 0xc5190312, /* 00A4(:1564): LCDEXT: idx2 = var10; idx2 > var12; idx2 += inc2 */ + 0x80198000, /* 00A8(:1564): LCD: idx3 = var0; idx3 once var0; idx3 += inc0 */ + 0x00008400, /* 00AC(:1565): DRD1A: idx1 = var0; FN=0 init=0 WS=0 RS=0 */ + 0x00000f08, /* 00B0(:1566): DRD1A: var3 = idx1; FN=0 init=0 WS=0 RS=0 */ + 0x81988000, /* 00B4(:1569): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ + 0x10000788, /* 00B8(:1570): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x6000000a, /* 00BC(:1571): DRD2A: EU0=0 EU1=0 EU2=0 EU3=10 EXT init=0 WS=0 RS=0 */ + 0x080cf05f, /* 00C0(:1571): DRD2B1: idx0 = EU3(); EU3(var1) */ + 0xc2988309, /* 00C4(:1574): LCDEXT: idx1 = var5; idx1 != var12; idx1 += inc1 */ + 0x80190000, /* 00C8(:1574): LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */ + 0x040001f8, /* 00CC(:1575): DRD1A: FN=0 INT init=0 WS=0 RS=0 */ + 0x000001f8, /* 00D0(:0): NOP */ +}; + +#ifdef MCD_INCLUDE_EU +MCD_bufDesc MCD_singleBufDescs[NCHANNELS]; +#endif --- /dev/null +++ b/drivers/dma/MCD_tasksInit.c @@ -0,0 +1,238 @@ +/* + * drivers/dma/MCD_tasksInit.c + * + * Copyright (C) 2004-2008 Freescale Semiconductor, Inc. + * Kurt Mahan + * + * 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 + */ + +/* + * Autogenerated - Do not edit! + */ + +#include "MCD_dma.h" + +extern dmaRegs *MCD_dmaBar; + + +/* + * Task 0 + */ + +void MCD_startDmaChainNoEu(int *currBD, short srcIncr, short destIncr, int xferSize, short xferSizeIncr, int *cSave, volatile TaskTableEntry *taskTable, int channel) +{ + + MCD_SET_VAR(taskTable+channel, 2, (u32)currBD); /* var[2] */ + MCD_SET_VAR(taskTable+channel, 25, (u32)(0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */ + MCD_SET_VAR(taskTable+channel, 24, (u32)(0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */ + MCD_SET_VAR(taskTable+channel, 11, (u32)xferSize); /* var[11] */ + MCD_SET_VAR(taskTable+channel, 26, (u32)(0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */ + MCD_SET_VAR(taskTable+channel, 0, (u32)cSave); /* var[0] */ + MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */ + MCD_SET_VAR(taskTable+channel, 3, (u32)0x00000000); /* var[3] */ + MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */ + MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */ + MCD_SET_VAR(taskTable+channel, 6, (u32)0x00000000); /* var[6] */ + MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */ + MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */ + MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000000); /* var[9] */ + MCD_SET_VAR(taskTable+channel, 10, (u32)0x00000000); /* var[10] */ + MCD_SET_VAR(taskTable+channel, 12, (u32)0x00000000); /* var[12] */ + MCD_SET_VAR(taskTable+channel, 13, (u32)0x80000000); /* var[13] */ + MCD_SET_VAR(taskTable+channel, 14, (u32)0x00000010); /* var[14] */ + MCD_SET_VAR(taskTable+channel, 15, (u32)0x00000004); /* var[15] */ + MCD_SET_VAR(taskTable+channel, 16, (u32)0x08000000); /* var[16] */ + MCD_SET_VAR(taskTable+channel, 27, (u32)0x00000000); /* inc[3] */ + MCD_SET_VAR(taskTable+channel, 28, (u32)0x80000000); /* inc[4] */ + MCD_SET_VAR(taskTable+channel, 29, (u32)0x80000001); /* inc[5] */ + MCD_SET_VAR(taskTable+channel, 30, (u32)0x40000000); /* inc[6] */ + + /* Set the task's Enable bit in its Task Control Register */ + MCD_dmaBar->taskControl[channel] |= (u16)0x8000; +} + + +/* + * Task 1 + */ + +void MCD_startDmaSingleNoEu(char *srcAddr, short srcIncr, char *destAddr, short destIncr, int dmaSize, short xferSizeIncr, int flags, int *currBD, int *cSave, volatile TaskTableEntry *taskTable, int channel) +{ + + MCD_SET_VAR(taskTable+channel, 7, (u32)srcAddr); /* var[7] */ + MCD_SET_VAR(taskTable+channel, 25, (u32)(0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */ + MCD_SET_VAR(taskTable+channel, 2, (u32)destAddr); /* var[2] */ + MCD_SET_VAR(taskTable+channel, 24, (u32)(0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */ + MCD_SET_VAR(taskTable+channel, 3, (u32)dmaSize); /* var[3] */ + MCD_SET_VAR(taskTable+channel, 26, (u32)(0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */ + MCD_SET_VAR(taskTable+channel, 5, (u32)flags); /* var[5] */ + MCD_SET_VAR(taskTable+channel, 1, (u32)currBD); /* var[1] */ + MCD_SET_VAR(taskTable+channel, 0, (u32)cSave); /* var[0] */ + MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */ + MCD_SET_VAR(taskTable+channel, 6, (u32)0x00000000); /* var[6] */ + MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */ + MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000004); /* var[9] */ + MCD_SET_VAR(taskTable+channel, 10, (u32)0x08000000); /* var[10] */ + MCD_SET_VAR(taskTable+channel, 27, (u32)0x00000000); /* inc[3] */ + MCD_SET_VAR(taskTable+channel, 28, (u32)0x80000001); /* inc[4] */ + MCD_SET_VAR(taskTable+channel, 29, (u32)0x40000000); /* inc[5] */ + + /* Set the task's Enable bit in its Task Control Register */ + MCD_dmaBar->taskControl[channel] |= (u16)0x8000; +} + + +/* + * Task 2 + */ + +void MCD_startDmaChainEu(int *currBD, short srcIncr, short destIncr, int xferSize, short xferSizeIncr, int *cSave, volatile TaskTableEntry *taskTable, int channel) +{ + + MCD_SET_VAR(taskTable+channel, 3, (u32)currBD); /* var[3] */ + MCD_SET_VAR(taskTable+channel, 25, (u32)(0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */ + MCD_SET_VAR(taskTable+channel, 24, (u32)(0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */ + MCD_SET_VAR(taskTable+channel, 12, (u32)xferSize); /* var[12] */ + MCD_SET_VAR(taskTable+channel, 26, (u32)(0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */ + MCD_SET_VAR(taskTable+channel, 0, (u32)cSave); /* var[0] */ + MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */ + MCD_SET_VAR(taskTable+channel, 2, (u32)0x00000000); /* var[2] */ + MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */ + MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */ + MCD_SET_VAR(taskTable+channel, 6, (u32)0x00000000); /* var[6] */ + MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */ + MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */ + MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000000); /* var[9] */ + MCD_SET_VAR(taskTable+channel, 10, (u32)0x00000000); /* var[10] */ + MCD_SET_VAR(taskTable+channel, 11, (u32)0x00000000); /* var[11] */ + MCD_SET_VAR(taskTable+channel, 13, (u32)0x00000000); /* var[13] */ + MCD_SET_VAR(taskTable+channel, 14, (u32)0x80000000); /* var[14] */ + MCD_SET_VAR(taskTable+channel, 15, (u32)0x00000010); /* var[15] */ + MCD_SET_VAR(taskTable+channel, 16, (u32)0x00000001); /* var[16] */ + MCD_SET_VAR(taskTable+channel, 17, (u32)0x00000004); /* var[17] */ + MCD_SET_VAR(taskTable+channel, 18, (u32)0x08000000); /* var[18] */ + MCD_SET_VAR(taskTable+channel, 27, (u32)0x00000000); /* inc[3] */ + MCD_SET_VAR(taskTable+channel, 28, (u32)0x80000000); /* inc[4] */ + MCD_SET_VAR(taskTable+channel, 29, (u32)0xc0000000); /* inc[5] */ + MCD_SET_VAR(taskTable+channel, 30, (u32)0x80000001); /* inc[6] */ + MCD_SET_VAR(taskTable+channel, 31, (u32)0x40000000); /* inc[7] */ + + /* Set the task's Enable bit in its Task Control Register */ + MCD_dmaBar->taskControl[channel] |= (u16)0x8000; +} + + +/* + * Task 3 + */ + +void MCD_startDmaSingleEu(char *srcAddr, short srcIncr, char *destAddr, short destIncr, int dmaSize, short xferSizeIncr, int flags, int *currBD, int *cSave, volatile TaskTableEntry *taskTable, int channel) +{ + + MCD_SET_VAR(taskTable+channel, 8, (u32)srcAddr); /* var[8] */ + MCD_SET_VAR(taskTable+channel, 25, (u32)(0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */ + MCD_SET_VAR(taskTable+channel, 3, (u32)destAddr); /* var[3] */ + MCD_SET_VAR(taskTable+channel, 24, (u32)(0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */ + MCD_SET_VAR(taskTable+channel, 4, (u32)dmaSize); /* var[4] */ + MCD_SET_VAR(taskTable+channel, 26, (u32)(0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */ + MCD_SET_VAR(taskTable+channel, 6, (u32)flags); /* var[6] */ + MCD_SET_VAR(taskTable+channel, 2, (u32)currBD); /* var[2] */ + MCD_SET_VAR(taskTable+channel, 0, (u32)cSave); /* var[0] */ + MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */ + MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */ + MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */ + MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000000); /* var[9] */ + MCD_SET_VAR(taskTable+channel, 10, (u32)0x00000001); /* var[10] */ + MCD_SET_VAR(taskTable+channel, 11, (u32)0x00000004); /* var[11] */ + MCD_SET_VAR(taskTable+channel, 12, (u32)0x08000000); /* var[12] */ + MCD_SET_VAR(taskTable+channel, 27, (u32)0x00000000); /* inc[3] */ + MCD_SET_VAR(taskTable+channel, 28, (u32)0xc0000000); /* inc[4] */ + MCD_SET_VAR(taskTable+channel, 29, (u32)0x80000000); /* inc[5] */ + MCD_SET_VAR(taskTable+channel, 30, (u32)0x80000001); /* inc[6] */ + MCD_SET_VAR(taskTable+channel, 31, (u32)0x40000000); /* inc[7] */ + + /* Set the task's Enable bit in its Task Control Register */ + MCD_dmaBar->taskControl[channel] |= (u16)0x8000; +} + + +/* + * Task 4 + */ + +void MCD_startDmaENetRcv(char *bDBase, char *currBD, char *rcvFifoPtr, volatile TaskTableEntry *taskTable, int channel) +{ + + MCD_SET_VAR(taskTable+channel, 0, (u32)bDBase); /* var[0] */ + MCD_SET_VAR(taskTable+channel, 3, (u32)currBD); /* var[3] */ + MCD_SET_VAR(taskTable+channel, 6, (u32)rcvFifoPtr); /* var[6] */ + MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */ + MCD_SET_VAR(taskTable+channel, 2, (u32)0x00000000); /* var[2] */ + MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */ + MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */ + MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */ + MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */ + MCD_SET_VAR(taskTable+channel, 9, (u32)0x0000ffff); /* var[9] */ + MCD_SET_VAR(taskTable+channel, 10, (u32)0x30000000); /* var[10] */ + MCD_SET_VAR(taskTable+channel, 11, (u32)0x0fffffff); /* var[11] */ + MCD_SET_VAR(taskTable+channel, 12, (u32)0x00000008); /* var[12] */ + MCD_SET_VAR(taskTable+channel, 24, (u32)0x00000000); /* inc[0] */ + MCD_SET_VAR(taskTable+channel, 25, (u32)0x60000000); /* inc[1] */ + MCD_SET_VAR(taskTable+channel, 26, (u32)0x20000004); /* inc[2] */ + MCD_SET_VAR(taskTable+channel, 27, (u32)0x40000000); /* inc[3] */ + + /* Set the task's Enable bit in its Task Control Register */ + MCD_dmaBar->taskControl[channel] |= (u16)0x8000; +} + + +/* + * Task 5 + */ + +void MCD_startDmaENetXmit(char *bDBase, char *currBD, char *xmitFifoPtr, volatile TaskTableEntry *taskTable, int channel) +{ + + MCD_SET_VAR(taskTable+channel, 0, (u32)bDBase); /* var[0] */ + MCD_SET_VAR(taskTable+channel, 3, (u32)currBD); /* var[3] */ + MCD_SET_VAR(taskTable+channel, 11, (u32)xmitFifoPtr); /* var[11] */ + MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */ + MCD_SET_VAR(taskTable+channel, 2, (u32)0x00000000); /* var[2] */ + MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */ + MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */ + MCD_SET_VAR(taskTable+channel, 6, (u32)0x00000000); /* var[6] */ + MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */ + MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */ + MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000000); /* var[9] */ + MCD_SET_VAR(taskTable+channel, 10, (u32)0x00000000); /* var[10] */ + MCD_SET_VAR(taskTable+channel, 12, (u32)0x00000000); /* var[12] */ + MCD_SET_VAR(taskTable+channel, 13, (u32)0x0000ffff); /* var[13] */ + MCD_SET_VAR(taskTable+channel, 14, (u32)0xffffffff); /* var[14] */ + MCD_SET_VAR(taskTable+channel, 15, (u32)0x00000004); /* var[15] */ + MCD_SET_VAR(taskTable+channel, 16, (u32)0x00000008); /* var[16] */ + MCD_SET_VAR(taskTable+channel, 24, (u32)0x00000000); /* inc[0] */ + MCD_SET_VAR(taskTable+channel, 25, (u32)0x60000000); /* inc[1] */ + MCD_SET_VAR(taskTable+channel, 26, (u32)0x40000000); /* inc[2] */ + MCD_SET_VAR(taskTable+channel, 27, (u32)0xc000fffc); /* inc[3] */ + MCD_SET_VAR(taskTable+channel, 28, (u32)0xe0000004); /* inc[4] */ + MCD_SET_VAR(taskTable+channel, 29, (u32)0x80000000); /* inc[5] */ + MCD_SET_VAR(taskTable+channel, 30, (u32)0x4000ffff); /* inc[6] */ + MCD_SET_VAR(taskTable+channel, 31, (u32)0xe0000001); /* inc[7] */ + + /* Set the task's Enable bit in its Task Control Register */ + MCD_dmaBar->taskControl[channel] |= (u16)0x8000; +} --- /dev/null +++ b/drivers/dma/MCD_tasksInit.h @@ -0,0 +1,64 @@ +/* + * drivers/dma/MCD_tasksInit.h + * + * Copyright (C) 2004-2008 Freescale Semiconductor, Inc. + * Kurt Mahan + * + * 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 + */ +#ifndef MCD_TSK_INIT_H +#define MCD_TSK_INIT_H 1 + +/* + * Autogenerated - Do not edit! + */ + +/* + * Task 0 + */ +void MCD_startDmaChainNoEu(int *currBD, short srcIncr, short destIncr, int xferSize, short xferSizeIncr, int *cSave, volatile TaskTableEntry *taskTable, int channel); + + +/* + * Task 1 + */ +void MCD_startDmaSingleNoEu(char *srcAddr, short srcIncr, char *destAddr, short destIncr, int dmaSize, short xferSizeIncr, int flags, int *currBD, int *cSave, volatile TaskTableEntry *taskTable, int channel); + + +/* + * Task 2 + */ +void MCD_startDmaChainEu(int *currBD, short srcIncr, short destIncr, int xferSize, short xferSizeIncr, int *cSave, volatile TaskTableEntry *taskTable, int channel); + + +/* + * Task 3 + */ +void MCD_startDmaSingleEu(char *srcAddr, short srcIncr, char *destAddr, short destIncr, int dmaSize, short xferSizeIncr, int flags, int *currBD, int *cSave, volatile TaskTableEntry *taskTable, int channel); + + +/* + * Task 4 + */ +void MCD_startDmaENetRcv(char *bDBase, char *currBD, char *rcvFifoPtr, volatile TaskTableEntry *taskTable, int channel); + + +/* + * Task 5 + */ +void MCD_startDmaENetXmit(char *bDBase, char *currBD, char *xmitFifoPtr, volatile TaskTableEntry *taskTable, int channel); + +#endif /* MCD_TSK_INIT_H */ --- /dev/null +++ b/drivers/i2c/busses/i2c-algo-mcf.h @@ -0,0 +1,23 @@ +#ifndef I2C_ALGO_MCF_H +#define I2C_ALGO_MCF_H 1 + +/* --- Defines for pcf-adapters --------------------------------------- */ +#include + +struct i2c_algo_mcf_data { + void *data; /* private data for lolevel routines */ + void (*setmcf) (void *data, int ctl, int val); + int (*getmcf) (void *data, int ctl); + int (*getown) (void *data); + int (*getclock) (void *data); + void (*waitforpin) (void); + /* local settings */ + int udelay; + int mdelay; + int timeout; +}; + +int i2c_mcf_add_bus(struct i2c_adapter *); +int i2c_mcf_del_bus(struct i2c_adapter *); + +#endif /* I2C_ALGO_MCF_H */ --- /dev/null +++ b/drivers/i2c/busses/i2c-mcf548x.c @@ -0,0 +1,595 @@ +/* + * Performance and stability improvements: (C) Copyright 2008, + * Adrian Cox + * ColdFire 547x/548x I2C master support + * Shrek Wu (b16972@freescale.com )moved the code driver/i2c/alg/mcf.c + * into driver/i2c/busses.And changed the driver to a platform driver. + */ +#include +#include "i2c-algo-mcf.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define get_clock(adap) (clock) +#define get_own(adap) (own) + +static int clock = 0x3b; /*50000 / 1024 ~ 49 KHz*/ +module_param(clock, int, 0); +MODULE_PARM_DESC(clock, + "Set I2C clock in kHz: 400=fast mode (default == 49khz)"); + +static int own = 0x78; +module_param(own, int, 0); +MODULE_PARM_DESC(clock, "Set I2C Master controller address(0x78)"); + +static struct i2c_algo_mcf_data i2c_mcf_board_data = { + .timeout = 10000, +}; + +static struct i2c_adapter i2c_mcf_board_adapter = { + .owner = THIS_MODULE, + .name = "MCF5485 adapter", + .id = I2C_HW_MPC107, + .algo_data = &i2c_mcf_board_data, + .class = I2C_CLASS_HWMON, + .timeout = 100, + .retries = 2 +}; +/* + * static void i2c_start() + * + * Generates START signal + */ +static void +i2c_start( + struct i2c_algo_mcf_data *adap +) { + MCF_I2CR |= MCF_I2CR_MSTA; +} + + +/* + * static void i2c_stop() + * + * Generates STOP signal + */ +static void +i2c_stop( + struct i2c_algo_mcf_data *adap +) { + MCF_I2CR &= ~MCF_I2CR_MSTA; +} + +static int +i2c_getack( + struct i2c_algo_mcf_data *adap +) { + return !(MCF_I2SR & MCF_I2SR_RXAK); +} + +/* + * static void i2c_repstart() + * + * Generates repeated start signal (without STOP while mastering the bus) + */ +static void +i2c_repstart( + struct i2c_algo_mcf_data *adap +) { + MCF_I2CR |= MCF_I2CR_RSTA; + MCF_I2CR |= MCF_I2CR_MTX; +} + + +/* + * static void wait_for_bb() + * + * Wait for bus idle state + */ +static int +wait_for_bb( + struct i2c_algo_mcf_data *adap +) { + int i; + for (i = 0; i < adap->timeout; i++) { + if (!(MCF_I2SR & MCF_I2SR_IBB)) + return 0; + udelay(100); + } + printk(KERN_ERR "%s: timeout", __FUNCTION__); + return -ETIMEDOUT; +} + +/* + * static void wait_for_not_bb() + * + * Wait for bus busy state + */ +static int +wait_for_not_bb( + struct i2c_algo_mcf_data *adap +) { + int i; + for (i = 0; i < adap->timeout; i++) { + if (MCF_I2SR & MCF_I2SR_IBB) + return 0; + udelay(100); + } + printk(KERN_ERR "%s: timeout", __FUNCTION__); + return -ETIMEDOUT; +} + +/* + * static void wait_xfer_done() + * + * Wait for transfer to complete + */ +static int +wait_xfer_done( + struct i2c_algo_mcf_data *adap +) { + int i; + + for (i = 0; i < adap->timeout; i++) { + if (MCF_I2SR & MCF_I2SR_IIF) { + MCF_I2SR &= ~MCF_I2SR_IIF; + return 0; + } + udelay(10); + } + printk(KERN_ERR "%s: timeout", __FUNCTION__); + return -ETIMEDOUT; +} + + +/* + * static void i2c_set_addr() + * + * Sets slave address to communicate + */ +static int +i2c_set_addr( + struct i2c_algo_mcf_data *adap, + struct i2c_msg *msg, + int retries +) { + unsigned short flags = msg->flags; + unsigned char addr; + MCF_I2CR |= MCF_I2CR_MTX; + if ((flags & I2C_M_TEN)) { + /* 10 bit address not supported yet */ + return -EIO; + } else { + /* normal 7bit address */ + addr = (msg->addr << 1); + if (flags & I2C_M_RD) + addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + + MCF_I2DR = addr; + } + return 0; +} + + +/* + * static void mcf_i2c_init() + * + * Perform ColdFire i2c initialization + */ +static void +mcf_i2c_init(struct i2c_algo_mcf_data *adap) +{ + u8 dummy; + /* Setup GPIO lines */ + MCF_PAR_FECI2CIRQ |= MCF_PAR_SDA; + MCF_PAR_FECI2CIRQ |= MCF_PAR_SCL; + + /* Ensure slaves are in idle state */ + if (MCF_I2SR & MCF_I2SR_IBB) { + MCF_I2ICR = 0x00; + MCF_I2CR = 0x00; + MCF_I2CR = 0x0A; + dummy = MCF_I2DR; + MCF_I2SR = 0x00; + MCF_I2CR = 0x00; + MCF_I2ICR = 0x01; + } + + /* setup SCL clock */ + MCF_I2FDR = get_clock(adap); + + /* set slave address */ + MCF_I2AR = get_own(adap); + + /* enable I2C module */ + MCF_I2CR = MCF_I2CR_IEN; +} + +static int i2c_outb( + struct i2c_adapter *i2c_adap, + char c +) { + + struct i2c_algo_mcf_data *adap = i2c_adap->algo_data; + int timeout; + /* Put data to be sent */ + MCF_I2DR = c; + /* Wait for xfer completed*/ + timeout = wait_xfer_done(adap); + if (timeout) { + i2c_stop(adap); + wait_for_bb(adap); + printk(KERN_ERR "i2c-algo-mcf: %s i2c_write: " + "error - timeout.\n", i2c_adap->name); + return -EREMOTEIO; /* got a better one ?? */ + } + + return 0; +} + + +/* + * static void mcf_sendbytes() + * + * Perform tx data transfer + */ +static int +mcf_sendbytes( + struct i2c_adapter *i2c_adap, + const char *buf, + int count, int last +) { + struct i2c_algo_mcf_data *adap = i2c_adap->algo_data; + int ret, i; + + /* Set master TX mode */ + MCF_I2CR |= MCF_I2CR_MTX; + + for (i = 0; i < count; ++i) { + printk(KERN_DEBUG "i2c-algo-mcf: %s i2c_write: writing %2.2X\n", + i2c_adap->name, buf[i]&0xff); + ret = i2c_outb(i2c_adap, buf[i]); + if (ret < 0) + return ret; + } + if (last) { + i2c_stop(adap); + wait_for_bb(adap); + } else { + /* i2c_repstart(adap);*/ + } + + return (i); +} + + +/* + * static void mcf_readbytes() + * + * Perform rx data transfer + */ +static int +mcf_readbytes( + struct i2c_adapter *i2c_adap, + char *buf, + int count, int last +) { + int i; + struct i2c_algo_mcf_data *adap = i2c_adap->algo_data; + u8 dummy; + + /* Set master RX mode */ + MCF_I2CR &= ~MCF_I2CR_MTX; + MCF_I2CR &= ~MCF_I2CR_TXAK; + dummy = MCF_I2DR; + + for (i = 0; i < count-1; i++) { + if (wait_xfer_done(adap)) { + i2c_stop(adap); + wait_for_bb(adap); + printk(KERN_DEBUG + "i2c-algo-mcf: mcf_readbytes timed out.\n"); + return (-1); + } + + /* store next data byte */ + buf[i] = MCF_I2DR; + } + + if (wait_xfer_done(adap)) { + i2c_stop(adap); + wait_for_bb(adap); + printk(KERN_DEBUG "i2c-algo-mcf: mcf_readbytes timed out.\n"); + return (-1); + } + + /* Disable acknowlege (set I2CR.TXAK) */ + MCF_I2CR |= MCF_I2CR_TXAK; + buf[i] = MCF_I2DR; + if (wait_xfer_done(adap)) { + i2c_stop(adap); + wait_for_bb(adap); + printk(KERN_DEBUG "i2c-algo-mcf: mcf_readbytes timed out.\n"); + return (-1); + } + + if (last) { + i2c_stop(adap); + wait_for_bb(adap); + } else { + /* i2c_repstart(adap);*/ + } + + return (i+1); +} + + +/* + * static void mcf_xfer() + * + * Perform master data I/O transfer + */ +static int +mcf_xfer( + struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, + int num +) { + struct i2c_algo_mcf_data *adap = i2c_adap->algo_data; + struct i2c_msg *pmsg; + int i; + int ret = 0, timeout; + + /* Skip own address */ + if (get_own(adap) == (msgs[0].addr << 1)) + return -EIO; + + /* Ensure slaves are in idle state */ + if (MCF_I2SR & MCF_I2SR_IBB) { + MCF_I2ICR = 0x00; + MCF_I2CR = 0x00; + MCF_I2CR = 0x0A; + timeout = MCF_I2DR; + MCF_I2SR = 0x00; + MCF_I2CR = 0x00; + MCF_I2ICR = 0x01; + } + /* setup SCL clock */ + MCF_I2FDR = get_clock(adap); + /* set slave address */ + MCF_I2AR = get_own(adap); + /* enable I2C module */ + MCF_I2CR = MCF_I2CR_IEN; + + MCF_I2CR |= MCF_I2CR_TXAK; + + /* Check for bus busy */ + wait_for_bb(adap); + + for (i = 0; ret >= 0 && i < num; i++) { + if (MCF_I2SR & MCF_I2SR_IBB) { + MCF_I2ICR = 0x00; + MCF_I2CR = 0x00; + MCF_I2CR = 0x0A; + timeout = MCF_I2DR; + MCF_I2SR = 0x00; + MCF_I2CR = 0x00; + MCF_I2ICR = 0x01; + } + /* setup SCL clock */ + MCF_I2FDR = get_clock(adap); + /* set slave address */ + MCF_I2AR = get_own(adap); + /* enable I2C module */ + MCF_I2CR = MCF_I2CR_IEN; + + MCF_I2CR |= MCF_I2CR_TXAK; + + /* Check for bus busy */ + wait_for_bb(adap); + + pmsg = &msgs[i]; + + printk(KERN_DEBUG "i2c-algo-mcf: Doing %s %d bytes " + "to 0x%02x - %d of %d messages\n", + pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->len, pmsg->addr, i + 1, num); + + /* Send START */ + /*if (i == 0)*/ + i2c_start(adap); + + /* Wait for Bus Busy */ + wait_for_not_bb(adap); + + MCF_I2CR |= MCF_I2CR_MTX; + + ret = i2c_set_addr(adap, pmsg, i2c_adap->retries); + if (ret < 0) + return ret; + + /* Wait for address transfer completion */ + wait_xfer_done(adap); + + /* Check for ACK */ + if (!i2c_getack(adap)) { + i2c_stop(adap); + wait_for_bb(adap); + printk(KERN_DEBUG "i2c-algo-mcf: No ack after " + "send address in mcf_xfer\n"); + return (-EREMOTEIO); + } + + printk(KERN_DEBUG "i2c-algo-mcf: Msg %d, " + "addr = 0x%x, flags = 0x%x, len = %d\n", + i, msgs[i].addr, msgs[i].flags, msgs[i].len); + /* Read */ + if (pmsg->flags & I2C_M_RD) { + /* read bytes into buffer*/ + ret = mcf_readbytes(i2c_adap, pmsg->buf, pmsg->len, + (i + 1 == num)); + + if (ret != pmsg->len) { + printk(KERN_DEBUG "i2c-algo-mcf: fail: " + "only read %d bytes.\n", ret); + } else { + printk(KERN_DEBUG "i2c-algo-mcf: " + "read %d bytes.\n", ret); + } + } else { + /* write bytes into buffer*/ + ret = mcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len, + (i + 1 == num)); + if (ret != pmsg->len) { + printk(KERN_DEBUG "i2c-algo-mcf: fail: " + "only wrote %d bytes.\n", ret); + } else { + printk(KERN_DEBUG "i2c-algo-mcf: wrote" + "%d bytes.\n", ret); + } + } + MCF_I2CR = 0; + } + + /* Disable I2C module */ + MCF_I2CR = 0; + return (i); +} + + +/* + * static void mcf_func() + * + * Return algorithm funtionality + */ +static u32 +mcf_func( + struct i2c_adapter *i2c_adap +) { + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; +} + +/* + * ColdFire bus algorithm callbacks + */ +static struct i2c_algorithm mcf_algo = { + .master_xfer = mcf_xfer, + .functionality = mcf_func, +}; + +/***********************************************************/ +struct coldfire_i2c { + void __iomem *base; + struct resource *irqarea; + struct resource *ioarea; + u32 irq; + struct i2c_adapter *adap; + u32 flags; +}; + +/* + * registering functions to load algorithms at runtime + */ +int i2c_mcf_add_bus(struct i2c_adapter *adap) +{ + struct i2c_algo_mcf_data *mcf_adap = adap->algo_data; + + /*adap->id |= mcf_algo.id;*/ + adap->algo = &mcf_algo; + adap->timeout = 100; + + mcf_i2c_init(mcf_adap); + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + i2c_add_adapter(adap); + + return 0; +} + +static int mcf548x_i2c_probe(struct platform_device *pdev) +{ + struct coldfire_i2c *i2c; + int rc = 0; + + /************************************************************/ + i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); + if (!i2c) { + printk(KERN_ERR "%s kzalloc coldfire_i2c faile\n", + __FUNCTION__); + return -ENOMEM; + } + /****************************************************************/ + platform_set_drvdata(pdev, i2c); + + i2c->adap = &i2c_mcf_board_adapter; + i2c->adap->dev.parent = &pdev->dev; + rc = i2c_mcf_add_bus(i2c->adap); + if (rc < 0) { + printk(KERN_ERR "%s - failed to add adapter\n", __FUNCTION__); + rc = -ENODEV; + goto fail_add; + } + + printk(KERN_INFO "i2c-algo-mcf.o: I2C ColdFire algorithm" + " module is loaded.\n"); + return rc; + +fail_add: + kfree(i2c); + return rc; +}; + +static int mcf548x_i2c_remove(struct platform_device *pdev) +{ + struct coldfire_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(i2c->adap); + platform_set_drvdata(pdev, NULL); + iounmap(i2c->base); + kfree(i2c); + return 0; +}; + +/* Structure for a device driver */ +static struct platform_driver mcf548x_i2c_driver = { + .probe = mcf548x_i2c_probe, + .remove = mcf548x_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = "MCF548X-i2c", + }, +}; + +static int __init coldfire_i2c_init(void) +{ + return platform_driver_register(&mcf548x_i2c_driver); +} + +static void __exit coldfire_i2c_exit(void) +{ + platform_driver_unregister(&mcf548x_i2c_driver); +} + +module_init(coldfire_i2c_init); +module_exit(coldfire_i2c_exit); + +MODULE_AUTHOR("Adrian Cox "); +MODULE_DESCRIPTION + ("I2C-Bus adapter for MCF547x and MCF548x processors"); +MODULE_LICENSE("GPL"); --- /dev/null +++ b/drivers/i2c/busses/i2c-mcf.c @@ -0,0 +1,573 @@ +/* + i2c-mcf.c - Part of lm_sensors, Linux kernel modules for hardware monitoring + + Copyright (c) 2005, Derek CL Cheung + + + Copyright (c) 2006-2007, emlix + Sebastian Hess + + Copyright (c) 2006-2007 Freescale Semiconductor, Inc + Yaroslav Vinogradov + Matt Waddel + + 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. + + Changes: + v0.1 26 March 2005 + Initial Release - developed on uClinux with 2.6.9 kernel + + v0.2 29 May 2006 + Modified to be more generic and added support for + i2c_master_xfer + + This I2C adaptor supports the ColdFire CPU I2C module. Since most Coldfire + CPUs' I2C module use the same register set (e.g., MCF5249), the code is very + portable and re-usable to other Coldfire CPUs. + + The transmission frequency is set at about 100KHz for the CPU board with + 8MHz crystal. If the CPU board uses different system clock frequency, you + should change the following line: + static int __init i2c_coldfire_init(void) + { + ......... + // Set transmission frequency 0x15 = ~100kHz + *MCF_I2C_I2FDR = 0x15; + ........ + } + + Remember to perform a dummy read to set the ColdFire CPU's I2C module for + read before reading the actual byte from a device + + The I2C_SM_BUS_BLOCK_DATA function are not yet ready but most lm_senors + do not care +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c-mcf.h" + + +static struct i2c_algorithm coldfire_algorithm = { + /*.name = "ColdFire I2C algorithm", + .id = I2C_ALGO_SMBUS,*/ + .smbus_xfer = coldfire_i2c_access, + .master_xfer = coldfire_i2c_master, + .functionality = coldfire_func, +}; + + +static struct i2c_adapter coldfire_adapter = { + .owner = THIS_MODULE, + .class = I2C_CLASS_HWMON, + .algo = &coldfire_algorithm, + .name = "ColdFire I2C adapter", +}; + + +__u16 lastaddr; +__u16 lastop; + +static inline int coldfire_do_first_start(__u16 addr,__u16 flags) +{ + int err; + /* + * Generate a stop and put the I2C module into slave mode + */ + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; + + /* + * Generate a new Start signal + */ + err = coldfire_i2c_start(flags & I2C_M_RD ? I2C_SMBUS_READ : I2C_SMBUS_WRITE, + addr, FIRST_START); + if(err) return err; + + lastaddr = addr; + lastop = flags & I2C_M_RD; /* Ensure everything for new start */ + return 0; +} + + +/* + * read one byte data from the I2C bus + */ +static int coldfire_read_data(u8 * const rxData, const enum I2C_ACK_TYPE ackType) { + + int timeout; + + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MTX; /* master receive mode*/ + + if (ackType == NACK) + *MCF_I2C_I2CR |= MCF_I2C_I2CR_TXAK; /* generate NA */ + else + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; /* generate ACK */ + + + /* read data from the I2C bus */ + *rxData = *MCF_I2C_I2DR; + + /* printk(">>> %s I2DR data is %.2x \n", __FUNCTION__, *rxData); */ + + /* wait for data transfer to complete */ + timeout = 500; + while (timeout-- && !(*MCF_I2C_I2SR & MCF_I2C_I2SR_IIF)) + udelay(1); + if (timeout <= 0) + printk("%s - I2C IIF never set. Timeout is %d \n", __FUNCTION__, + timeout); + + + /* reset the interrupt bit */ + *MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; + + if (timeout <= 0 ) + return -1; + else + return 0; + +}; + + +/* + * write one byte data onto the I2C bus + */ +static int coldfire_write_data(const u8 txData) { + + int timeout; + + timeout = 500; + + *MCF_I2C_I2CR |= MCF_I2C_I2CR_MTX; /* I2C module into TX mode */ + *MCF_I2C_I2DR = txData; /* send the data */ + + /* wait for data transfer to complete */ + /* rely on the interrupt handling bit */ + timeout = 500; + while (timeout-- && !(*MCF_I2C_I2SR & MCF_I2C_I2SR_IIF)) + udelay(1); + if (timeout <=0) + printk("%s - I2C IIF never set. Timeout is %d \n", __FUNCTION__, + timeout); + + + /* reset the interrupt bit */ + *MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; + + if (timeout <= 0 ) + return -1; + else + return 0; + +}; + + + + +/* + * Generate I2C start or repeat start signal + * Combine the 7 bit target_address and the R/W bit and put it onto the I2C bus + */ +static int coldfire_i2c_start(const char read_write, const u16 target_address, const enum I2C_START_TYPE start_type) { + + int timeout; + + /* printk(">>> %s START TYPE %s \n", __FUNCTION__, + start_type == FIRST_START ? "FIRST_START":"REPEAT_START");*/ + + *MCF_I2C_I2CR |= MCF_I2C_I2CR_IEN; + + if (start_type == FIRST_START) { + /* Make sure the I2C bus is idle */ + timeout = 500; /* 500us timeout */ + while (timeout-- && (*MCF_I2C_I2SR & MCF_I2C_I2SR_IBB)) + udelay(1); + if (timeout <= 0) { + printk("%s - I2C bus always busy in the past 500us timeout is %d \n", __FUNCTION__, timeout); + goto check_rc; + } + /* generate a START and put the I2C module into MASTER TX mode*/ + *MCF_I2C_I2CR |= (MCF_I2C_I2CR_MSTA | MCF_I2C_I2CR_MTX); + + /* wait for bus busy to be set */ + timeout = 500; + while (timeout-- && !(*MCF_I2C_I2SR & MCF_I2C_I2SR_IBB)) + udelay(1); + if (timeout <= 0) { + printk("%s - I2C bus is never busy after START. Timeout is %d \n", __FUNCTION__, timeout); + goto check_rc; + } + + } else { + /* this is repeat START */ + udelay(500); /* need some delay before repeat start */ + *MCF_I2C_I2CR |= (MCF_I2C_I2CR_MSTA | MCF_I2C_I2CR_RSTA); + } + + + /* combine the R/W bit and the 7 bit target address and put it onto + the I2C bus */ + *MCF_I2C_I2DR = ((target_address & 0x7F) << 1) | (read_write == I2C_SMBUS_WRITE ? 0x00 : 0x01); + + /* wait for bus transfer to complete */ + /* when one byte transfer is completed, IIF set at the faling edge of + the 9th clock */ + timeout = 500; + while (timeout-- && !(*MCF_I2C_I2SR & MCF_I2C_I2SR_IIF)) + udelay(1); + if (timeout <= 0) + printk("%s - I2C IIF never set. Timeout is %d \n", __FUNCTION__, timeout); + + +check_rc: + /* reset the interrupt bit */ + *MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; + + if (timeout <= 0) + return -1; + else + return 0; +}; + + +/* + * 5282 SMBUS supporting functions + */ + +static s32 coldfire_i2c_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + int rc = 0; + u8 rxData, tempRxData[2]; + + switch (size) { + case I2C_SMBUS_QUICK: + rc = coldfire_i2c_start(read_write, addr, FIRST_START); /* generate START */ + break; + case I2C_SMBUS_BYTE: + rc = coldfire_i2c_start(read_write, addr, FIRST_START); + *MCF_I2C_I2CR |= MCF_I2C_I2CR_TXAK; /*generate NA */ + if (read_write == I2C_SMBUS_WRITE) + rc += coldfire_write_data(command); + else { + coldfire_read_data(&rxData, NACK);/*dummy read*/ + rc += coldfire_read_data(&rxData, NACK); + data->byte = rxData; + } + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; /* reset ACK bit */ + break; + case I2C_SMBUS_BYTE_DATA: + rc = coldfire_i2c_start(I2C_SMBUS_WRITE, addr, FIRST_START); + rc += coldfire_write_data(command); + if (read_write == I2C_SMBUS_WRITE) + rc += coldfire_write_data(data->byte); + else { + /* This is SMBus READ Byte Data Request. + Perform REPEAT START */ + rc += coldfire_i2c_start(I2C_SMBUS_READ, addr, + REPEAT_START); + coldfire_read_data(&rxData, ACK);/* dummy read*/ + /* Disable Acknowledge, generate STOP after + next byte transfer */ + rc += coldfire_read_data(&rxData, NACK); + data->byte = rxData; + } + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK;/* reset to normal ACk */ + break; + case I2C_SMBUS_PROC_CALL: + case I2C_SMBUS_WORD_DATA: + dev_info(&adap->dev, "size = I2C_SMBUS_WORD_DATA \n"); + rc = coldfire_i2c_start(I2C_SMBUS_WRITE, addr, + FIRST_START); + rc += coldfire_write_data(command); + if (read_write == I2C_SMBUS_WRITE) { + rc += coldfire_write_data(data->word & 0x00FF); + rc += coldfire_write_data((data->word & 0x00FF) >> 8); + } else { + /* This is SMBUS READ WORD request. + Peform REPEAT START */ + rc += coldfire_i2c_start(I2C_SMBUS_READ, addr, + REPEAT_START); + coldfire_read_data(&rxData, ACK);/* dummy read*/ + /* Disable Acknowledge, generate STOP after + next byte transfer */ + /* read the MS byte from the device */ + rc += coldfire_read_data(&rxData, NACK); + tempRxData[1] = rxData; + /* read the LS byte from the device */ + rc += coldfire_read_data(&rxData, NACK); + tempRxData[0] = rxData; + /* the host driver expect little endian + convention. Swap the byte */ + data->word = (tempRxData[0] << 8)|tempRxData[1]; + } + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; + break; + case I2C_SMBUS_BLOCK_DATA: + /* Not done yet */ + break; + default: + printk("Unsupported I2C size \n"); + rc = -1; + break; + }; + + /* Generate a STOP and put I2C module into slave mode */ + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; + + /* restore interrupt */ + *MCF_I2C_I2CR |= MCF_I2C_I2CR_IIEN; + + if (rc < 0) + return -1; + else + return 0; +}; + + +/* + * List the SMBUS functions supported by this I2C adaptor + * Also tell the I2C Subsystem that we are able of master_xfer() + */ +static u32 coldfire_func(struct i2c_adapter *adapter) +{ + return(I2C_FUNC_SMBUS_QUICK | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_I2C | + I2C_FUNC_SMBUS_BLOCK_DATA); +}; + +static int coldfire_i2c_master(struct i2c_adapter *adap,struct i2c_msg *msgs, + int num) +{ + u8 dummyRead; + struct i2c_msg *p; + int i, err = 0; + int ic=0; + + lastaddr = 0; + lastop = 8; + + /* disable the IRQ, we are doing polling */ + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_IIEN; + + dev_dbg(&adap->dev,"Num of actions: %d\n", num); + + for (i = 0; !err && i < num; i++) { + p = &msgs[i]; + + + if (!p->len) + { + dev_dbg(&adap->dev,"p->len == 0!\n"); + continue; + } + /* + * Generate a new Start, if the target address differs from + * the last target, generate a stop in this case first + */ + if(p->addr != lastaddr) + { + err = coldfire_do_first_start(p->addr,p->flags); + if(err) + { + dev_dbg(&adap->dev,"First Init failed!\n"); + break; + } + } + + else if((p->flags & I2C_M_RD) != lastop) + { + /* + * If the Operational Mode changed, we need to do this + * here ... + */ + dev_dbg(&adap->dev,"%s(): Direction changed, was: %d; is now: %d\n", __FUNCTION__, lastop, p->flags & I2C_M_RD); + + /* Last op was an read, now it's write: complete stop + and reinit */ + if (lastop & I2C_M_RD) + { + dev_dbg(&adap->dev,"%s(): The device is in read state, we must reset!\n", __FUNCTION__); + if((err = coldfire_do_first_start(p->addr,p->flags))) + break; + } + else + { + dev_dbg(&adap->dev,"%s(): We switchted to read mode\n",__FUNCTION__); + if((err = coldfire_i2c_start((p->flags & I2C_M_RD) ? I2C_SMBUS_READ : I2C_SMBUS_WRITE, + p->addr, REPEAT_START))) + break; + } + + lastop = p->flags & I2C_M_RD; /* Save the last op */ + } + + if (p->flags & I2C_M_RD) + { + /* + * When ever we get here, a new session was activated, + * so read a dummy byte + */ + coldfire_read_data(&dummyRead, ACK); + /* + * read p->len -1 bytes with ACK to the slave, + * read the last byte without the ACK, to inform him + * about the stop afterwards + */ + ic = 0; + while(!err && (ic < p->len-1 )) + { + err = coldfire_read_data(p->buf+ic, ACK ); + ic++; + } + if(!err) + err = coldfire_read_data(p->buf+ic, NACK); + dev_dbg(&coldfire_adapter.dev,"read: %2x\n",p->buf[ic]); + } + else + { + if(p->len == 2) + dev_dbg(&coldfire_adapter.dev,"writing: 0x %2x %2x\n", p->buf[0], p->buf[1]); + + /* + * Write data to the slave + */ + for(ic=0; !err && ic < p->len; ic++) + { + err = coldfire_write_data(p->buf[ic]); + if(err) + { + dev_dbg(&coldfire_adapter.dev, "Failed to write data\n"); + } + } + } + } + + /* + * Put the device into slave mode to enable the STOP Generation + * (the RTC needs this) + */ + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; + + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; /* reset the ACK bit */ + + /* restore interrupt */ + *MCF_I2C_I2CR |= MCF_I2C_I2CR_IIEN; + + /* Return the number of messages processed, or the error code. */ + if (err == 0) + err = num; + return err; +} + + +/* + * Initalize the 5282 I2C module + * Disable the 5282 I2C interrupt capability. Just use callback + */ + +static int __init i2c_coldfire_init(void) +{ + int retval; + u8 dummyRead; + +#if defined(CONFIG_M532x) || defined(CONFIG_M5445X) + /* + * Initialize the GPIOs for I2C + */ + MCF_GPIO_PAR_FECI2C |= (0 + | MCF_GPIO_PAR_FECI2C_PAR_SDA(3) + | MCF_GPIO_PAR_FECI2C_PAR_SCL(3)); +#elif defined(CONFIG_M5253) + { + volatile u32 *reg; + /* GPIO Bit 41 = SCL0, Bit 42 = SDA0 */ + reg = (volatile u32 *)(MCF_MBAR2 + MCFSIM2_GPIO1FUNC); + *reg &= 0xFFFFF9FF; + } +#else + /* Initialize PASP0 and PASP1 to I2C functions, 5282 user guide 26-19 */ + /* Port AS Pin Assignment Register (PASPAR) */ + /* PASPA1 = 11 = AS1 pin is I2C SDA */ + /* PASPA0 = 11 = AS0 pin is I2C SCL */ + *MCF_GPIO_PASPAR |= 0x000F; /* u16 declaration */ +#endif + + + /* Set transmission frequency 0x15 = ~100kHz */ + *MCF_I2C_I2FDR = 0x15; + + /* set the 5282 I2C slave address though we never use it */ + *MCF_I2C_I2ADR = 0x6A; + + /* Enable I2C module and if IBB is set, do the special initialzation */ + /* procedures as are documented at the 5282 User Guide page 24-11 */ + *MCF_I2C_I2CR |= MCF_I2C_I2CR_IEN; + if ((*MCF_I2C_I2SR & MCF_I2C_I2SR_IBB) == 1) { + printk("%s - do special 5282 I2C init procedures \n", + __FUNCTION__); + *MCF_I2C_I2CR = 0x00; + *MCF_I2C_I2CR = 0xA0; + dummyRead = *MCF_I2C_I2DR; + *MCF_I2C_I2SR = 0x00; + *MCF_I2C_I2CR = 0x00; + } + + /* default I2C mode is - slave and receive */ + *MCF_I2C_I2CR &= ~(MCF_I2C_I2CR_MSTA | MCF_I2C_I2CR_MTX); + + coldfire_adapter.dev.parent = &platform_bus; + retval = i2c_add_adapter(&coldfire_adapter); + + if (retval < 0) + printk("%s - return code is: %d \n", __FUNCTION__, retval); + + return retval; +}; + + +/* + * I2C module exit function + */ + +static void __exit i2c_coldfire_exit(void) +{ + /* disable I2C and Interrupt */ + *MCF_I2C_I2CR &= ~(MCF_I2C_I2CR_IEN | MCF_I2C_I2CR_IIEN); + i2c_del_adapter(&coldfire_adapter); + +}; + + +MODULE_AUTHOR("Derek CL Cheung "); +MODULE_DESCRIPTION("MCF5282 I2C adaptor"); +MODULE_LICENSE("GPL"); + +module_init(i2c_coldfire_init); +module_exit(i2c_coldfire_exit); --- /dev/null +++ b/drivers/i2c/busses/i2c-mcf.h @@ -0,0 +1,75 @@ +/* + i2c-mcf.h - header file for i2c-mcf.c + + Copyright (c) 2005, Derek CL Cheung + + + Copyright (c) 2006-2007, emlix + Sebastian Hess + + Copyright (c) 2006-2007 Freescale Semiconductor, Inc + Yaroslav Vinogradov + Matt Waddel + + 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. + + Changes: + v0.1 26 March 2005 + Initial Release - developed on uClinux with 2.6.9 kernel + v0.2 29 May 2006 + Modified to be more generic and added support for + i2c_master_xfer +*/ + + +#ifndef __I2C_MCF_H__ +#define __I2C_MCF_H__ + +enum I2C_START_TYPE { FIRST_START, REPEAT_START }; +enum I2C_ACK_TYPE { ACK, NACK}; + +/* Function prototypes */ +static u32 coldfire_func(struct i2c_adapter *adapter); +static s32 coldfire_i2c_access(struct i2c_adapter *adap, u16 address, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data); +static int coldfire_write_data(const u8 data); +static int coldfire_i2c_start(const char read_write, const u16 target_address, const enum I2C_START_TYPE i2c_start); +static int coldfire_read_data(u8 * const rxData, const enum I2C_ACK_TYPE ackType); +static int coldfire_i2c_master(struct i2c_adapter *adap,struct i2c_msg *msgs, int num); +void dumpReg(char *, u16 addr, u8 data); + +#define MCF_I2C_I2ADR_ADDR(x) (((x)&0x7F)<<0x01) +#define MCF_I2C_I2FDR_IC(x) (((x)&0x3F)) + +/* I2C Control Register */ +#define MCF_I2C_I2CR_IEN (0x80) /* I2C enable */ +#define MCF_I2C_I2CR_IIEN (0x40) /* interrupt enable */ +#define MCF_I2C_I2CR_MSTA (0x20) /* master/slave mode */ +#define MCF_I2C_I2CR_MTX (0x10) /* transmit/receive mode */ +#define MCF_I2C_I2CR_TXAK (0x08) /* transmit acknowledge enable */ +#define MCF_I2C_I2CR_RSTA (0x04) /* repeat start */ + +/* I2C Status Register */ +#define MCF_I2C_I2SR_ICF (0x80) /* data transfer bit */ +#define MCF_I2C_I2SR_IAAS (0x40) /* I2C addressed as a slave */ +#define MCF_I2C_I2SR_IBB (0x20) /* I2C bus busy */ +#define MCF_I2C_I2SR_IAL (0x10) /* aribitration lost */ +#define MCF_I2C_I2SR_SRW (0x04) /* slave read/write */ +#define MCF_I2C_I2SR_IIF (0x02) /* I2C interrupt */ +#define MCF_I2C_I2SR_RXAK (0x01) /* received acknowledge */ + +/********************************************************************/ +#endif /* __I2C_MCF_H__ */ --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -4,6 +4,18 @@ menu "I2C Hardware Bus support" +config I2C_MCF548x + tristate "I2C MCF547x/548x interfaces" + depends on I2C + help + This allows you to use the I2C adapters found on the Freescale + MCF547x/548x microcontrollers. + Say Y if you own an I2C adapter belonging to this class and then say + Y to the specific driver for you adapter below. + + This support is also available as a module. If so, the module + will be called i2c-algo-mcf. + config I2C_ALI1535 tristate "ALI 1535" depends on PCI @@ -290,6 +302,16 @@ config I2C_POWERMAC This support is also available as a module. If so, the module will be called i2c-powermac. +config I2C_MCF + tristate "MCF ColdFire" + depends on I2C && EXPERIMENTAL + help + If you say yes to this option, support will be included for the + I2C on most ColdFire CPUs + + This driver can also be built as a module. If so, the module + will be called i2c-mcf. + config I2C_MPC tristate "MPC107/824x/85xx/52xx/86xx" depends on PPC32 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -52,6 +52,8 @@ obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o +obj-$(CONFIG_I2C_MCF548x) += i2c-mcf548x.o +obj-$(CONFIG_I2C_MCF) += i2c-mcf.o ifeq ($(CONFIG_I2C_DEBUG_BUS),y) EXTRA_CFLAGS += -DDEBUG --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -118,7 +118,6 @@ config PMAC_SMU config PMAC_APM_EMU tristate "APM emulation" - select APM_EMULATION depends on ADB_PMU && PM && PPC32 config PMAC_MEDIABAY --- a/drivers/Makefile +++ b/drivers/Makefile @@ -93,3 +93,5 @@ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ obj-$(CONFIG_VIRTIO) += virtio/ + +obj-$(CONFIG_MCD_DMA) += dma/ --- /dev/null +++ b/drivers/net/can/flexcan/flexcan.c @@ -0,0 +1,378 @@ +/* + * flexcan.c + * + * DESCRIPTION: + * CAN bus driver for the alone generic (as possible as) FLEXCAN controller. + * + * AUTHOR: + * Andrey Volkov + * + * COPYRIGHT: + * 2005-2006, Varma Electronics Oy + * + * LICENCE: + * 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 + * + * HISTORY: + * 2008-06-23 Support for MCF548x's FlexCAN + * Huan, Wang + */ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "flexcan.h" +#include +#include +#include /* for RCSID. Removed by mkpatch script */ +RCSID("$Id$"); + +struct flexcan_priv { + struct can_priv can; + volatile unsigned long flags; + u8 shadow_statflg; + u8 shadow_canrier; + u8 cur_pri; + u8 tx_active; + + struct list_head tx_head; + struct napi_struct napi; + struct net_device *dev; +}; + + +static int flexcan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct can_frame *frame = (struct can_frame *)skb->data; + struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; + int i, len; + int txbuf = 0; + u32 can_id, can_ext, tmp, tmp1; + + /* Transmission inactive */ + regs->cantxfg[txbuf].can_dlc = MB_CNT_CODE(0x08); + + can_ext = frame->can_id; + if (can_ext & CAN_EFF_FLAG) { + /* Frame format is extended */ + regs->cantxfg[txbuf].can_dlc |= (1 << 21); + regs->cantxfg[txbuf].can_dlc |= (1 << 22); + can_id = frame->can_id & MB_ID_EXT; + if (frame->can_id & CAN_RTR_FLAG) + regs->cantxfg[txbuf].can_dlc |= (1 << 20); + + tmp = (can_id & CAN_SFF_MASK) << 18; + tmp1 = can_id >> 11; + can_id = tmp | tmp1; + regs->cantxfg[txbuf].can_id = can_id; + } else { + /* Frame format is standard */ + can_id = frame->can_id & MB_ID_EXT; + if (frame->can_id & CAN_RTR_FLAG) + regs->cantxfg[txbuf].can_dlc |= (1 << 20); + + regs->cantxfg[txbuf].can_id = can_id << 18; + } + + len = 8; + for (i = 0; i < len; i++) + regs->cantxfg[txbuf].data[i] = frame->data[i]; + + regs->cantxfg[txbuf].can_dlc |= len << 16; + /* Transmission active */ + regs->cantxfg[txbuf].can_dlc |= MB_CNT_CODE(0x0c); + kfree_skb(skb); + return NETDEV_TX_OK; +} + +static void flexcan_tx_timeout(struct net_device *dev) +{ + struct sk_buff *skb; + struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; + struct can_frame *frame; + int length = 8; + + /* Diable the interrupts */ + regs->imask = IMASK_BUFF_DISABLE_ALL; + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (!skb) { + if (printk_ratelimit()) + dev_notice(ND2D(dev), "TIMEOUT packet dropped.\n"); + return; + } + frame = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + + frame->can_dlc = length; + + skb->dev = dev; + skb->protocol = __constant_htons(ETH_P_CAN); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + + netif_rx(skb); +} + +static irqreturn_t flexcan_isr(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; + struct net_device_stats *stats = dev->get_stats(dev); + struct sk_buff *skb; + struct can_frame *frame; + u32 iflags, oflags; + int i, k; + int retval = 1; + + iflags = regs->iflag; + oflags = iflags; + for (i = 0; i < 16; i++) { + if (iflags & (0x01 << i)) { + struct flexcan_mb *mb = ®s->cantxfg[i]; + int ctrl = mb->can_dlc; + int code = (ctrl >> 24) & 0x0f; + int length = (ctrl >> 16) & 0x0f; + u32 tmp, tmp1; + + if (code < 8 && (length > 0)) { + /* receive frame */ + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (!skb) + dev_notice(ND2D(dev), + "Packets dropped.\n"); + skb->dev = dev; + frame = (struct can_frame *)skb_put(skb, + sizeof(struct can_frame)); + + frame->can_id &= 0x0; + frame->can_dlc = length; + tmp1 = mb->can_id & MB_ID_EXT; + if (ctrl & MB_CNT_IDE) { + tmp = tmp1; + tmp = (tmp >> 18) & CAN_SFF_MASK; + frame->can_id = (tmp1 << 11) | tmp; + frame->can_id &= CAN_EFF_MASK; + frame->can_id |= CAN_EFF_FLAG; + if (ctrl & MB_CNT_RTR) + frame->can_id |= CAN_RTR_FLAG; + } else { + frame->can_id = tmp1 >> 18; + if (ctrl & MB_CNT_RTR) + frame->can_id |= CAN_RTR_FLAG; + } + + for (k = 0; k < 8; k++) + frame->data[k] = mb->data[k]; + + mb->can_dlc &= MB_CODE_MASK; + mb->can_dlc |= MB_CNT_CODE(0x04); + + stats->rx_packets++; + stats->rx_bytes += frame->can_dlc; + skb->dev = dev; + skb->protocol = __constant_htons(ETH_P_CAN); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + retval = netif_rx(skb); + if (retval == NET_RX_DROP) + dev_notice(ND2D(dev), + "Packets dropped.\n"); + } else { + /* transmit frame */ + mb->can_dlc = MB_CNT_CODE(0x04); + } + } + } + regs->iflag = oflags; + + return IRQ_HANDLED; +} + +static int flexcan_do_set_bit_time(struct net_device *dev, + struct can_bittime *bt) +{ + struct flexcan_priv *priv = netdev_priv(dev); + struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; + int ret = 0; + u32 reg; + + if (bt->type != CAN_BITTIME_STD) + return -EINVAL; + + spin_lock_irq(&priv->can.irq_lock); + + reg = CANCTRL_PRESDIV(bt->std.brp) | CANCTRL_PSEG1(bt->std.phase_seg1 + - 1) | CANCTRL_PSEG2(bt->std.phase_seg2 - 1); + regs->canctrl &= CANCTRL_BITTIME; + regs->canctrl |= (reg | CANCTRL_SAMP(bt->std.sam) | + CANCTRL_PROPSEG(bt->std.prop_seg - 1)); + + spin_unlock_irq(&priv->can.irq_lock); + return ret; +} + + +static int flexcan_open(struct net_device *dev) +{ + int ret, i, j; + struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; + +#if defined(CONFIG_M547X_8X) + MCF_PAR_TIMER = MCF_PAR_TIMER | 0x28; + MCF_PAR_TIMER = MCF_PAR_TIMER & 0xf8; + MCF_PAR_DSPI = MCF_PAR_DSPI | 0x0a00; + MCF_PAR_FECI2CIRQ = MCF_PAR_FECI2CIRQ | 0x0283; + MCF_PAR_PSCn(2) = MCF_PAR_PSCn(2) & 0x0f; + MCF_PAR_PSCn(2) = MCF_PAR_PSCn(2) | 0x50; +#endif + + regs->canmcr |= CANMCR_SOFTRST; + regs->canmcr |= CANMCR_MDIS; + udelay(10); + + if ((regs->canmcr & CANMCR_SOFTRST) != 0x0) { + dev_err(ND2D(dev), "Failed to softreset can module.\n"); + return -1; + } + + /* Enable error and bus off interrupt */ + regs->canctrl |= (CANCTRL_RJW(3) | CANCTRL_ERRMSK | + CANCTRL_BOFFMSK); + + /* Set lowest buffer transmitted first */ + regs->canctrl |= CANCTRL_LBUF; + + for (i = 0; i < 16; i++) { + regs->cantxfg[i].can_dlc = 0; + regs->cantxfg[i].can_id = 0; + for (j = 0; j < 8; j++) + regs->cantxfg[i].data[j] = 0; + + /* Put MB into rx queue */ + regs->cantxfg[i].can_dlc = MB_CNT_CODE(0x04); + } + + /* acceptance mask/acceptance code (accept everything) */ + regs->rxgmask = 0x00000000; + regs->rx14mask = 0x00000000; + regs->rx15mask = 0x00000000; + /* extended frame */ + regs->cantxfg[14].can_dlc |= 0x600000; + /* Enable flexcan module */ + regs->canmcr &= ~CANMCR_MDIS; + /* Synchronize with the can bus */ + regs->canmcr &= ~CANMCR_HALT; + +#if defined(CONFIG_M547X_8X) + for (i = 0; i < 2; i++) { + MCF_ICR(ISC_CANn_MBOR(i)) = 0x33; + MCF_ICR(ISC_CANn_ERR(i)) = 0x33; + MCF_ICR(ISC_CANn_BUSOFF(i)) = 0x33; + } + + ret = request_irq(dev->irq + 64, flexcan_isr, IRQF_DISABLED, + dev->name, dev); + ret = request_irq(dev->irq + 1 + 64, flexcan_isr, IRQF_DISABLED, + dev->name, dev); + ret = request_irq(dev->irq + 2 + 64, flexcan_isr, IRQF_DISABLED, + dev->name, dev); + if (ret < 0) { + printk(KERN_ERR "%s - failed to attach interrupt.\n", + dev->name); + return ret; + } +#endif + + /* Enable all interrupts */ + regs->imask = IMASK_BUFF_ENABLE_ALL; + netif_start_queue(dev); + return 0; +} + +static int flexcan_close(struct net_device *dev) +{ + struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; + + netif_stop_queue(dev); + + /* Disable all interrupts */ + regs->imask = IMASK_BUFF_DISABLE_ALL; + free_irq(dev->irq + 64, dev); + free_irq(dev->irq + 1 + 64, dev); + free_irq(dev->irq + 2 + 64, dev); + + /* Disable module */ + regs->canmcr |= CANMCR_MDIS; + return 0; +} + +int register_flexcandev(struct net_device *dev, int clock_src) +{ + struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; + + regs->canmcr &= ~CANMCR_MDIS; + udelay(100); + regs->canmcr |= (CANMCR_FRZ | CANMCR_HALT); + return register_netdev(dev); +} +EXPORT_SYMBOL(register_flexcandev); + +void unregister_flexcandev(struct net_device *dev) +{ + struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; + + regs->canmcr |= (CANMCR_FRZ | CANMCR_HALT); + regs->canmcr |= CANMCR_MDIS; + + unregister_netdev(dev); +} +EXPORT_SYMBOL(unregister_flexcandev); + +struct net_device *alloc_flexcandev(void) +{ + struct net_device *dev; + struct flexcan_priv *priv; + + dev = alloc_candev(sizeof(struct flexcan_priv)); + if (!dev) + return NULL; + + priv = netdev_priv(dev); + priv->dev = dev; + dev->open = flexcan_open; + dev->stop = flexcan_close; + dev->hard_start_xmit = flexcan_hard_start_xmit; + dev->tx_timeout = flexcan_tx_timeout; + dev->flags |= IFF_NOARP; + priv->can.do_set_bit_time = flexcan_do_set_bit_time; + return dev; +} +EXPORT_SYMBOL(alloc_flexcandev); + +MODULE_AUTHOR("Andrey Volkov "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CAN port driver for flexcan based chip"); --- /dev/null +++ b/drivers/net/can/flexcan/flexcan.h @@ -0,0 +1,148 @@ +/* + * flexcan.h + * + * DESCRIPTION: + * Definitions of consts/structs to drive the Freescale FLEXCAN. + * + */ + +#ifndef __FLEXCAN_H__ +#define __FLEXCAN_H__ + +#include +#include + +/* FLEXCAN module configuration register (CANMCR) bits */ +#define CANMCR_MDIS 0x80000000 +#define CANMCR_FRZ 0x40000000 +#define CANMCR_HALT 0x10000000 +#define CANMCR_SOFTRST 0x02000000 +#define CANMCR_FRZACK 0x01000000 +#define CANMCR_SUPV 0x00800000 +#define CANMCR_MAXMB(x) ((x)&0x0f) + +/* FLEXCAN control register (CANCTRL) bits */ +#define CANCTRL_PRESDIV(x) (((x)&0xff)<<24) +#define CANCTRL_RJW(x) (((x)&0x03)<<22) +#define CANCTRL_PSEG1(x) (((x)&0x07)<<19) +#define CANCTRL_PSEG2(x) (((x)&0x07)<<16) +#define CANCTRL_BOFFMSK 0x00008000 +#define CANCTRL_ERRMSK 0x00004000 +#define CANCTRL_LPB 0x00001000 +#define CANCTRL_SAMP(x) (((x)&0x1)<<7) +#define CANCTRL_BOFFREC 0x00000040 +#define CANCTRL_TSYNC 0x00000020 +#define CANCTRL_LBUF 0x00000010 +#define CANCTRL_LOM 0x00000008 +#define CANCTRL_PROPSEG(x) ((x)&0x07) +#define CANCTRL_BITTIME 0x00c0d078 + +/* FLEXCAN error counter register (ERRCNT) bits */ +#define ERRCNT_REXECTR(x) (((x)&0xff)<<8) +#define ERRCNT_TXECTR(x) ((x)&0xff) + +/* FLEXCAN error and status register (ERRSTAT) bits */ +#define ERRSTAT_BITERR(x) (((x)&0x03)<<14) +#define ERRSTAT_ACKERR 0x00002000 +#define ERRSTAT_CRCERR 0x00001000 +#define ERRSTAT_FRMERR 0x00000800 +#define ERRSTAT_STFERR 0x00000400 +#define ERRSTAT_TXWRN 0x00000200 +#define ERRSTAT_RXWRN 0x00000100 +#define ERRSTAT_IDLE 0x00000080 +#define ERRSTAT_TXRX 0x00000040 +#define ERRSTAT_FLTCONF(x) (((x)&0x03)<<4) +#define ERRSTAT_BOFFINT 0x00000004 +#define ERRSTAT_ERRINT 0x00000002 + +/* FLEXCAN interrupt mask register (IMASK) bits */ +#define IMASK_BUF15M 0x8000 +#define IMASK_BUF14M 0x4000 +#define IMASK_BUF13M 0x2000 +#define IMASK_BUF12M 0x1000 +#define IMASK_BUF11M 0x0800 +#define IMASK_BUF10M 0x0400 +#define IMASK_BUF9M 0x0200 +#define IMASK_BUF8M 0x0100 +#define IMASK_BUF7M 0x0080 +#define IMASK_BUF6M 0x0040 +#define IMASK_BUF5M 0x0020 +#define IMASK_BUF4M 0x0010 +#define IMASK_BUF3M 0x0008 +#define IMASK_BUF2M 0x0004 +#define IMASK_BUF1M 0x0002 +#define IMASK_BUF0M 0x0001 +#define IMASK_BUFnM(x) (0x1<<(x)) +#define IMASK_BUFF_ENABLE_ALL 0xffff +#define IMASK_BUFF_DISABLE_ALL 0x0000 + +/* FLEXCAN interrupt flag register (IFLAG) bits */ +#define IFLAG_BUF15M 0x8000 +#define IFLAG_BUF14M 0x4000 +#define IFLAG_BUF13M 0x2000 +#define IFLAG_BUF12M 0x1000 +#define IFLAG_BUF11M 0x0800 +#define IFLAG_BUF10M 0x0400 +#define IFLAG_BUF9M 0x0200 +#define IFLAG_BUF8M 0x0100 +#define IFLAG_BUF7M 0x0080 +#define IFLAG_BUF6M 0x0040 +#define IFLAG_BUF5M 0x0020 +#define IFLAG_BUF4M 0x0010 +#define IFLAG_BUF3M 0x0008 +#define IFLAG_BUF2M 0x0004 +#define IFLAG_BUF1M 0x0002 +#define IFLAG_BUF0M 0x0001 +#define IFLAG_BUFnM(x) (0x1<<(x)) +#define IFLAG_BUFF_SET_ALL 0xffff +#define IFLAG_BUFF_DISABLE_ALL 0x0000 + +/* FLEXCAN message buffers */ +#define MB_CNT_CODE(x) (((x)&0x0f)<<24) +#define MB_CNT_SRR 0x00400000 +#define MB_CNT_IDE 0x00200000 +#define MB_CNT_RTR 0x00100000 +#define MB_CNT_LENGTH(x) (((x)&0x0f)<<16) +#define MB_CNT_TIMESTAMP(x) ((x)&0xffff) + +#define MB_ID_STD ((0x7ff)<<18) +#define MB_ID_EXT 0x1fffffff +#define MB_CODE_MASK 0xf0ffffff + +/* Structure of the message buffer */ +struct flexcan_mb { + u32 can_dlc; + u32 can_id; + u8 data[8]; +}; + +/* Structure of the hardware registers */ +struct flexcan_regs { + u32 canmcr; + u32 canctrl; + u32 timer; + u32 reserved1; + u32 rxgmask; + u32 rx14mask; + u32 rx15mask; + u32 errcnt; + u32 errstat; + u32 reserved2; + u32 imask; + u32 reserved3; + u32 iflag; + u32 reserved4[19]; + struct flexcan_mb cantxfg[16]; +}; + +struct flexcan_platform_data { + u8 clock_src; /* FLEXCAN clock source CRIN or SYSCLK */ + u32 clock_frq; /* can ref. clock, in Hz */ +}; + +struct net_device *alloc_flexcandev(void); + +extern int register_flexcandev(struct net_device *dev, int clock_src); +extern void unregister_flexcandev(struct net_device *dev); + +#endif /* __FLEXCAN_H__ */ --- /dev/null +++ b/drivers/net/can/flexcan/Makefile @@ -0,0 +1,5 @@ + +obj-$(CONFIG_CAN_MCF547X_8X) += flexcan-mcf548x.o + +flexcan-mcf548x-objs := flexcan.o mcf548x_can.o + --- /dev/null +++ b/drivers/net/can/flexcan/mcf548x_can.c @@ -0,0 +1,213 @@ +/* + * DESCRIPTION: + * CAN bus driver for the Freescale MCF548x embedded CPU. + * + * AUTHOR: + * Andrey Volkov + * + * COPYRIGHT: + * 2004-2005, Varma Electronics Oy + * + * LICENCE: + * 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 + * + * HISTORY: + * 2008-06-23 support for MCF548x's FlexCAN + * Huan, Wang + * 2005-02-03 created + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flexcan.h" +#include +#include +#include /* for RCSID. Removed by mkpatch script */ + +RCSID("$Id$"); + +#define PDEV_MAX 2 + +struct platform_device *pdev[PDEV_MAX]; + +static int __devinit mcf548x_can_probe(struct platform_device *pdev) +{ + struct resource *mem; + struct net_device *dev; + struct flexcan_platform_data *pdata = pdev->dev.platform_data; + struct can_priv *can; + u32 mem_size; + int ret = -ENODEV; + + if (!pdata) + return ret; + + dev = alloc_flexcandev(); + if (!dev) + return -ENOMEM; + can = netdev_priv(dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + dev->irq = platform_get_irq(pdev, 0); + if (!mem || !dev->irq) + goto req_error; + + mem_size = mem->end - mem->start + 1; + if (!request_mem_region(mem->start, mem_size, pdev->dev.driver->name)) { + dev_err(&pdev->dev, "resource unavailable\n"); + goto req_error; + } + SET_NETDEV_DEV(dev, &pdev->dev); + + dev->base_addr = (unsigned long)ioremap_nocache(mem->start, mem_size); + if (!dev->base_addr) { + dev_err(&pdev->dev, "failed to map can port\n"); + ret = -ENOMEM; + goto fail_map; + } + can->can_sys_clock = pdata->clock_frq; + platform_set_drvdata(pdev, dev); + ret = register_flexcandev(dev, pdata->clock_src); + if (ret >= 0) { + dev_info(&pdev->dev, "probe for port 0x%lX done\n", + dev->base_addr); + return ret; + } + + iounmap((unsigned long *)dev->base_addr); +fail_map: + release_mem_region(mem->start, mem_size); +req_error: + free_candev(dev); + dev_err(&pdev->dev, "probe failed\n"); + return ret; +} + +static int __devexit mcf548x_can_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct resource *mem; + + platform_set_drvdata(pdev, NULL); + unregister_flexcandev(dev); + iounmap((unsigned long *)dev->base_addr); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, mem->end - mem->start + 1); + free_candev(dev); + return 0; +} + +static struct platform_driver mcf548x_can_driver = { + .driver = { + .name = "mcf548x-flexcan", + }, + .probe = mcf548x_can_probe, + .remove = __devexit_p(mcf548x_can_remove), +}; + +static struct resource mcf548x_can0_resources[] = { + [0] = { + .start = MCF_MBAR + 0x0000A000, + .end = MCF_MBAR + 0x0000A7FF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 49, + .end = 49, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource mcf548x_can1_resources[] = { + [0] = { + .start = MCF_MBAR + 0x0000A800, + .end = MCF_MBAR + 0x0000AFFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 55, + .end = 55, + .flags = IORESOURCE_IRQ, + }, +}; + + +static int __init mcf548x_of_to_pdev(void) +{ + unsigned int i; + int err = -ENODEV; + struct flexcan_platform_data pdata; + + pdev[0] = platform_device_register_simple("mcf548x-flexcan", 0, + mcf548x_can0_resources, 2); + if (IS_ERR(pdev[0])) { + err = PTR_ERR(pdev[0]); + return err; + } + pdev[1] = platform_device_register_simple("mcf548x-flexcan", 1, + mcf548x_can1_resources, 2); + if (IS_ERR(pdev[1])) { + err = PTR_ERR(pdev[1]); + return err; + } + + /* FlexCAN clock */ + pdata.clock_frq = 100000000; + + for (i = 0; i < PDEV_MAX; i++) { + err = platform_device_add_data(pdev[i], &pdata, sizeof(pdata)); + if (err) + return err; + } + return err; +} + +int __init mcf548x_can_init(void) +{ + int err = mcf548x_of_to_pdev(); + + if (err) { + printk(KERN_ERR "%s init failed with err=%d\n", + mcf548x_can_driver.driver.name, err); + return err; + } + + return platform_driver_register(&mcf548x_can_driver); +} + +void __exit mcf548x_can_exit(void) +{ + int i; + platform_driver_unregister(&mcf548x_can_driver); + for (i = 0; i < PDEV_MAX; i++) + platform_device_unregister(pdev[i]); +} + +module_init(mcf548x_can_init); +module_exit(mcf548x_can_exit); + +MODULE_AUTHOR("Andrey Volkov "); +MODULE_DESCRIPTION("Freescale MCF548x CAN driver"); +MODULE_LICENSE("GPL v2"); --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -12,6 +12,19 @@ config CAN_VCAN This driver can also be built as a module. If so, the module will be called vcan. +config CAN_FLEXCAN + tristate "Support for Freescale FLEXCAN based chips" + depends on CAN && (PPC || M68K || M68KNOMMU) + ---help--- + Say Y here if you want to support for Freescale FlexCAN. + +config CAN_MCF547X_8X + tristate "Freescale MCF547X/MCF548X onboard CAN controller" + depends on CAN_FLEXCAN && (M547X || M548X) + ---help--- + Say Y here if you want to support for Freescale MCF547x/MCF548x + onboard dualCAN controller. + config CAN_DEBUG_DEVICES bool "CAN devices debugging messages" depends on CAN --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_CAN_VCAN) += vcan.o +obj-$(CONFIG_CAN_FLEXCAN) += flexcan/ --- /dev/null +++ b/drivers/net/fec/fec.c @@ -0,0 +1,1306 @@ +/* + * Performance and stability improvements: (C) Copyright 2008, + * Daniel Krueger, SYSTEC electronic GmbH + * + * Code crunched to get it to work on 2.6.24 -- FEC cleanup coming + * soon -- Kurt Mahan + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "fec.h" +#include "ks8721.h" + +#ifdef CONFIG_FEC_548x_ENABLE_FEC2 +#define FEC_MAX_PORTS 2 +#define FEC_2 +#else +#define FEC_MAX_PORTS 1 +#undef FEC_2 +#endif + +#define VERSION "0.20" +MODULE_DESCRIPTION( "DMA Fast Ethernet Controller driver ver " VERSION); + +/* fec private */ +struct fec_priv { + struct net_device *netdev; /* owning net device */ + void* fecpriv_txbuf[FEC_TX_BUF_NUMBER]; /* tx buffer ptrs */ + MCD_bufDescFec *fecpriv_txdesc; /* tx descriptor ptrs */ + volatile unsigned int fecpriv_current_tx; /* current tx desc index */ + volatile unsigned int fecpriv_next_tx; /* next tx desc index */ + unsigned int fecpriv_current_rx; /* current rx desc index */ + MCD_bufDescFec *fecpriv_rxdesc; /* rx descriptor ptrs */ + struct sk_buff *askb_rx[FEC_RX_BUF_NUMBER]; /* rx SKB ptrs */ + unsigned int fecpriv_initiator_rx; /* rx dma initiator */ + unsigned int fecpriv_initiator_tx; /* tx dma initiator */ + int fecpriv_fec_rx_channel; /* rx dma channel */ + int fecpriv_fec_tx_channel; /* tx dma channel */ + int fecpriv_rx_requestor; /* rx dma requestor */ + int fecpriv_tx_requestor; /* tx dma requestor */ + void *fecpriv_interrupt_fec_rx_handler; /* dma rx handler */ + void *fecpriv_interrupt_fec_tx_handler; /* dma tx handler */ + unsigned char *fecpriv_mac_addr; /* private fec mac addr */ + struct net_device_stats fecpriv_stat; /* stats ptr */ + spinlock_t fecpriv_lock; + int fecpriv_rxflag; + struct tasklet_struct fecpriv_tasklet_reinit; + int index; /* fec hw number */ +}; + +struct net_device *fec_dev[FEC_MAX_PORTS]; + +/* FEC functions */ +int __init fec_init(void); +struct net_device_stats *fec_get_stat(struct net_device *dev); +int fec_open(struct net_device *dev); +int fec_close(struct net_device *nd); +int fec_tx(struct sk_buff *skb, struct net_device *dev); +void fec_set_multicast_list(struct net_device *nd); +int fec_set_mac_address(struct net_device *dev, void *p); +void fec_tx_timeout(struct net_device *dev); +void fec_interrupt_fec_tx_handler(struct net_device *dev); +void fec_interrupt_fec_rx_handler(struct net_device *dev); +irqreturn_t fec_interrupt_handler(int irq, void *dev_id); +void fec_interrupt_fec_tx_handler_fec0(void); +void fec_interrupt_fec_rx_handler_fec0(void); +void fec_interrupt_fec_reinit(unsigned long data); + +/* default fec0 address */ +unsigned char fec_mac_addr_fec0[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x50 }; + +#ifdef FEC_2 +/* default fec1 address */ +unsigned char fec_mac_addr_fec1[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x51 }; +#endif + +extern unsigned char uboot_enet0[]; +extern unsigned char uboot_enet1[]; + +#ifndef MODULE +int fec_str_to_mac( char *str_mac, unsigned char* addr); +int __init fec_mac_setup0 (char *s); +#endif + + +#ifdef FEC_2 +void fec_interrupt_fec_tx_handler_fec1(void); +void fec_interrupt_fec_rx_handler_fec1(void); +#endif + +#ifndef MODULE +int __init fec_mac_setup1 (char *s); +#endif + +int fec_read_mii(unsigned int base_addr, unsigned int pa, unsigned int ra, unsigned int *data); +int fec_write_mii(unsigned int base_addr, unsigned int pa, unsigned int ra, unsigned int data); + +module_init(fec_init); +/* module_exit(fec_cleanup); */ + +__setup("mac0=", fec_mac_setup0); + +#ifdef FEC_2 +__setup("mac1=", fec_mac_setup1); +#endif + +/* + * Initialize a FEC device + */ +int fec_enet_init(struct net_device *dev) +{ + static int index = 0; + struct fec_priv *fp = netdev_priv(dev); + int i; + + fp->index = index; + fp->netdev = dev; + fec_dev[ index ] = dev; + + if (index == 0) { + /* disable fec0 */ + FEC_ECR(FEC_BASE_ADDR_FEC0) = FEC_ECR_DISABLE; + + /* setup the interrupt handler */ + dev->irq = 64 + ISC_FEC0; + + if (request_irq(dev->irq, fec_interrupt_handler, + IRQF_DISABLED, "ColdFire FEC 0", dev)) { + dev->irq = 0; + printk("Cannot allocate FEC0 IRQ\n"); + } else { + /* interrupt priority and level */ + MCF_ICR(ISC_FEC0) = ILP_FEC0; + } + + /* fec base address */ + dev->base_addr = FEC_BASE_ADDR_FEC0; + + /* requestor numbers */ + fp->fecpriv_rx_requestor = DMA_FEC0_RX; + fp->fecpriv_tx_requestor = DMA_FEC0_TX; + + /* fec0 handlers */ + fp->fecpriv_interrupt_fec_rx_handler = fec_interrupt_fec_rx_handler_fec0; + fp->fecpriv_interrupt_fec_tx_handler = fec_interrupt_fec_tx_handler_fec0; + + /* tx descriptors */ + fp->fecpriv_txdesc = (void*)FEC_TX_DESC_FEC0; + + /* rx descriptors */ + fp->fecpriv_rxdesc = (void*)FEC_RX_DESC_FEC0; + + /* mac addr */ + if (uboot_enet0[0] || uboot_enet0[1] || uboot_enet0[2] || + uboot_enet0[3] || uboot_enet0[4] || uboot_enet0[5]) { + /* use uboot enet 0 addr */ + memcpy(fec_mac_addr_fec0, uboot_enet0, 6); + } + + fp->fecpriv_mac_addr = fec_mac_addr_fec0; + } + else { + /* disable fec1 */ + FEC_ECR(FEC_BASE_ADDR_FEC1) = FEC_ECR_DISABLE; +#ifdef FEC_2 + /* setup the interrupt handler */ + dev->irq = 64 + ISC_FEC1; + + if (request_irq(dev->irq, fec_interrupt_handler, + IRQF_DISABLED, "ColdFire FEC 1", dev)) { + dev->irq = 0; + printk("Cannot allocate FEC1 IRQ\n"); + } else { + /* interrupt priority and level */ + MCF_ICR(ISC_FEC1) = ILP_FEC1; + } + + /* fec base address */ + dev->base_addr = FEC_BASE_ADDR_FEC1; + + /* requestor numbers */ + fp->fecpriv_rx_requestor = DMA_FEC1_RX; + fp->fecpriv_tx_requestor = DMA_FEC1_TX; + + /* fec1 handlers */ + fp->fecpriv_interrupt_fec_rx_handler = fec_interrupt_fec_rx_handler_fec1; + fp->fecpriv_interrupt_fec_tx_handler = fec_interrupt_fec_tx_handler_fec1; + + /* tx descriptors */ + fp->fecpriv_txdesc = (void*)FEC_TX_DESC_FEC1; + + /* rx descriptors */ + fp->fecpriv_rxdesc = (void*)FEC_RX_DESC_FEC1; + + /* mac addr */ + if (uboot_enet1[0] || uboot_enet1[1] || uboot_enet1[2] || + uboot_enet1[3] || uboot_enet1[4] || uboot_enet1[5]) { + /* use uboot enet 1 addr */ + memcpy(fec_mac_addr_fec1, uboot_enet1, 6); + } + fp->fecpriv_mac_addr = fec_mac_addr_fec1; +#endif + } + + /* clear MIB */ + memset((void *) (dev->base_addr + 0x200), 0, FEC_MIB_LEN); + + /* clear the statistics structure */ + memset((void *) &(fp->fecpriv_stat), 0, + sizeof(struct net_device_stats)); + + /* grab the FEC initiators */ + dma_set_initiator(fp->fecpriv_tx_requestor); + fp->fecpriv_initiator_tx = dma_get_initiator(fp->fecpriv_tx_requestor); + dma_set_initiator(fp->fecpriv_rx_requestor); + fp->fecpriv_initiator_rx = dma_get_initiator(fp->fecpriv_rx_requestor); + + /* reset the DMA channels */ + fp->fecpriv_fec_rx_channel = -1; + fp->fecpriv_fec_tx_channel = -1; + + for (i = 0; i < FEC_RX_BUF_NUMBER; i++) + fp->askb_rx[i] = NULL; + + /* initialize the pointers to the socket buffers */ + for (i = 0; i < FEC_TX_BUF_NUMBER; i++) + fp->fecpriv_txbuf[i] = NULL; + + ether_setup(dev); + + dev->open = fec_open; + dev->stop = fec_close; + dev->hard_start_xmit = fec_tx; + dev->get_stats = fec_get_stat; + dev->set_multicast_list = fec_set_multicast_list; + dev->set_mac_address = fec_set_mac_address; + dev->tx_timeout = fec_tx_timeout; + dev->watchdog_timeo = FEC_TX_TIMEOUT * HZ; + + memcpy(dev->dev_addr, fp->fecpriv_mac_addr, ETH_ALEN); + + spin_lock_init(&fp->fecpriv_lock); + + // Initialize FEC/I2C/IRQ Pin Assignment Register + FEC_GPIO_PAR_FECI2CIRQ &= 0xF; + FEC_GPIO_PAR_FECI2CIRQ |= FEC_FECI2CIRQ; + + index++; + return 0; +} + +/* + * Module Initialization + */ +int __init fec_init(void) +{ + struct net_device *dev; + int i; + int err; + DECLARE_MAC_BUF(mac); + + printk(KERN_INFO "FEC ENET (DMA) Version %s\n", VERSION); + + for (i = 0; i < FEC_MAX_PORTS; i++) { + dev = alloc_etherdev(sizeof(struct fec_priv)); + if (!dev) + return -ENOMEM; + err = fec_enet_init(dev); + if (err) { + free_netdev(dev); + continue; + } + if (register_netdev(dev) != 0) { + free_netdev(dev); + return -EIO; + } + + printk(KERN_INFO "%s: ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); + } + return 0; +} + +/* + * Stop a device + */ +void fec_stop(struct net_device *dev) +{ + struct fec_priv *fp = netdev_priv(dev); + + dma_remove_initiator(fp->fecpriv_initiator_tx); + dma_remove_initiator(fp->fecpriv_initiator_rx); + + if (dev->irq) + free_irq(dev->irq, dev); +} + +/************************************************************************ +* NAME: fec_open +* +* DESCRIPTION: This function performs the initialization of +* of FEC and corresponding KS8721 transiver +* +* RETURNS: If no error occurs, this function returns zero. +*************************************************************************/ +int fec_open(struct net_device *dev) +{ + struct fec_priv *fp = netdev_priv(dev); + unsigned long base_addr = (unsigned long) dev->base_addr; + int fduplex; + int i; + int channel; + int error_code = -EBUSY; + + /* Receive the DMA channels */ + channel = dma_set_channel_fec(fp->fecpriv_rx_requestor); + + if (channel == -1) { + printk("Dma channel cannot be reserved\n"); + goto ERRORS; + } + + fp->fecpriv_fec_rx_channel = channel; + + dma_connect(channel, (int) fp->fecpriv_interrupt_fec_rx_handler); + + channel = dma_set_channel_fec(fp->fecpriv_tx_requestor); + + if (channel == -1) { + printk("Dma channel cannot be reserved\n"); + goto ERRORS; + } + + fp->fecpriv_fec_tx_channel = channel; + + dma_connect(channel, (int) fp->fecpriv_interrupt_fec_tx_handler); + + /* init tasklet for controller reinitialization */ + tasklet_init(&fp->fecpriv_tasklet_reinit, fec_interrupt_fec_reinit, (unsigned long) dev); + + /* Reset FIFOs */ + FEC_FECFRST(base_addr) |= FEC_SW_RST | FEC_RST_CTL; + FEC_FECFRST(base_addr) &= ~FEC_SW_RST; + + /* Reset and disable FEC */ + FEC_ECR(base_addr) = FEC_ECR_RESET; + + udelay(10); + + /* Clear all events */ + FEC_EIR(base_addr) = FEC_EIR_CLEAR; + + /* Reset FIFO status */ + FEC_FECTFSR(base_addr) = FEC_FECTFSR_MSK; + FEC_FECRFSR(base_addr) = FEC_FECRFSR_MSK; + + /* Set the default address */ + FEC_PALR(base_addr) = (fp->fecpriv_mac_addr[0] << 24) | + (fp->fecpriv_mac_addr[1] << 16) | + (fp->fecpriv_mac_addr[2] << 8) | + fp->fecpriv_mac_addr[3]; + FEC_PAUR(base_addr) = (fp->fecpriv_mac_addr[4] << 24) | + (fp->fecpriv_mac_addr[5] << 16) | 0x8808; + + /* Reset the group address descriptor */ + FEC_GALR(base_addr) = 0x00000000; + FEC_GAUR(base_addr) = 0x00000000; + + /* Reset the individual address descriptor */ + FEC_IALR(base_addr) = 0x00000000; + FEC_IAUR(base_addr) = 0x00000000; + + /* Set the receive control register */ + FEC_RCR(base_addr) = FEC_RCR_MAX_FRM_SIZE | FEC_RCR_MII; + + /* Set the receive FIFO control register */ +// FEC_FECRFCR(base_addr) = FEC_FECRFCR_FRM | FEC_FECRFCR_GR | FEC_FECRFCR_MSK; + FEC_FECRFCR(base_addr) = FEC_FECRFCR_FRM | FEC_FECRFCR_GR + | (FEC_FECRFCR_MSK // disable all but ... + & ~FEC_FECRFCR_FAE // enable frame accept error + & ~FEC_FECRFCR_RXW // enable receive wait condition +// & ~FEC_FECRFCR_UF // enable FIFO underflow + ); + + /* Set the receive FIFO alarm register */ + FEC_FECRFAR(base_addr) = FEC_FECRFAR_ALARM; + + /* Set the transmit FIFO control register */ +// FEC_FECTFCR(base_addr) = FEC_FECTFCR_FRM | FEC_FECTFCR_GR | FEC_FECTFCR_MSK; + FEC_FECTFCR(base_addr) = FEC_FECTFCR_FRM | FEC_FECTFCR_GR + | (FEC_FECTFCR_MSK // disable all but ... + & ~FEC_FECTFCR_FAE // enable frame accept error +// & ~FEC_FECTFCR_TXW // enable transmit wait condition +// & ~FEC_FECTFCR_UF // enable FIFO underflow + & ~FEC_FECTFCR_OF); // enable FIFO overflow + + /* Set the transmit FIFO alarm register */ + FEC_FECTFAR(base_addr) = FEC_FECTFAR_ALARM; + + /* Set the Tx FIFO watermark */ + FEC_FECTFWR(base_addr) = FEC_FECTFWR_XWMRK; + + /* Enable the transmitter to append the CRC */ + FEC_CTCWR(base_addr) = FEC_CTCWR_TFCW_CRC; + + /* Enable the ethernet interrupts */ +// FEC_EIMR(base_addr) = FEC_EIMR_MASK; + FEC_EIMR(base_addr) = FEC_EIMR_DISABLE + | FEC_EIR_LC + | FEC_EIR_RL + | FEC_EIR_HBERR + | FEC_EIR_XFUN + | FEC_EIR_XFERR + | FEC_EIR_RFERR + ; + +/* + * JKM -- + * + * There's a problem with the PHY initialization code -- + * for now assume uboot left it in an initialized state. + */ +// printk(KERN_INFO "FECOPEN: starting auto-negotiation\n"); +// #ifdef CONFIG_FEC_548x_AUTO_NEGOTIATION +#if 0 + if ((error_code = init_transceiver(base_addr, &fduplex)) != 0) + { + printk("Initialization of the transceiver is failed\n"); + goto ERRORS; + } +#else + fduplex = 1; +#endif +// printk(KERN_INFO "FECOPEN: done with auto-negotiation\n"); + + if (fduplex) + /* Enable the full duplex mode */ + FEC_TCR(base_addr) = FEC_TCR_FDEN | FEC_TCR_HBC; + else + /* Disable reception of frames while transmitting */ + FEC_RCR(base_addr) |= FEC_RCR_DRT; + + /* Enable MIB */ + FEC_MIBC(base_addr) = FEC_MIBC_ENABLE; + + /* Enable FEC */ + FEC_ECR(base_addr) |= FEC_ECR_ETHEREN; + + /* Initialize tx descriptors and start DMA for the transmission */ + for (i = 0; i < FEC_TX_BUF_NUMBER; i++) + fp->fecpriv_txdesc[i].statCtrl = MCD_FEC_INTERRUPT; + + fp->fecpriv_txdesc[i - 1].statCtrl |= MCD_FEC_WRAP; + + fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0; + + MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) fp->fecpriv_txdesc, 0, + (unsigned char *) &(FEC_FECTFDR(base_addr)), 0, + FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx, + FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT, + MCD_NO_CSUM | MCD_NO_BYTE_SWAP); + + /* Initialize rx descriptors and start DMA for the reception */ + for (i = 0; i < FEC_RX_BUF_NUMBER; i++) { + fp->askb_rx[i] = alloc_skb(FEC_MAXBUF_SIZE + 16, GFP_DMA); + if (!fp->askb_rx[i]) { + fp->fecpriv_rxdesc[i].dataPointer = 0; + fp->fecpriv_rxdesc[i].statCtrl = 0; + fp->fecpriv_rxdesc[i].length = 0; + } + else { + skb_reserve(fp->askb_rx[i], 16); + fp->askb_rx[i]->dev = dev; + fp->fecpriv_rxdesc[i].dataPointer = (unsigned int) virt_to_phys(fp->askb_rx[i]->tail); + fp->fecpriv_rxdesc[i].statCtrl = MCD_FEC_BUF_READY | MCD_FEC_INTERRUPT; + fp->fecpriv_rxdesc[i].length = FEC_MAXBUF_SIZE; + } + } + + fp->fecpriv_rxdesc[i - 1].statCtrl |= MCD_FEC_WRAP; + fp->fecpriv_current_rx = 0; + + /* flush entire data cache before restarting the DMA */ +#if 0 +/* JKM -- currently running with cache turned off */ + DcacheFlushInvalidate(); +#endif + + MCD_startDma(fp->fecpriv_fec_rx_channel, (char *) fp->fecpriv_rxdesc, 0, + (unsigned char *) &(FEC_FECRFDR(base_addr)), 0, + FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_rx, + FEC_RX_DMA_PRI, MCD_FECRX_DMA | MCD_INTERRUPT, + MCD_NO_CSUM | MCD_NO_BYTE_SWAP); + + netif_start_queue(dev); + return 0; + +ERRORS: + + /* Remove the channels and return with the error code */ + if (fp->fecpriv_fec_rx_channel != -1) { + dma_disconnect(fp->fecpriv_fec_rx_channel); + dma_remove_channel_by_number(fp->fecpriv_fec_rx_channel); + fp->fecpriv_fec_rx_channel = -1; + } + + if (fp->fecpriv_fec_tx_channel != -1) { + dma_disconnect(fp->fecpriv_fec_tx_channel); + dma_remove_channel_by_number(fp->fecpriv_fec_tx_channel); + fp->fecpriv_fec_tx_channel = -1; + } + + return error_code; +} + +/************************************************************************ +* NAME: fec_close +* +* DESCRIPTION: This function performs the graceful stop of the +* transmission and disables FEC +* +* RETURNS: This function always returns zero. +*************************************************************************/ +int fec_close(struct net_device *dev) +{ + struct fec_priv *fp = netdev_priv(dev); + unsigned long base_addr = (unsigned long) dev->base_addr; + unsigned long time; + int i; + + netif_stop_queue(dev); + + /* Perform the graceful stop */ + FEC_TCR(base_addr) |= FEC_TCR_GTS; + + time = jiffies; + + /* Wait for the graceful stop */ + while (!(FEC_EIR(base_addr) & FEC_EIR_GRA) && jiffies - time < FEC_GR_TIMEOUT * HZ) + schedule(); + + /* Disable FEC */ + FEC_ECR(base_addr) = FEC_ECR_DISABLE; + + /* Reset the DMA channels */ + spin_lock_irq(&fp->fecpriv_lock); + MCD_killDma(fp->fecpriv_fec_tx_channel); + spin_unlock_irq(&fp->fecpriv_lock); + dma_remove_channel_by_number(fp->fecpriv_fec_tx_channel); + dma_disconnect(fp->fecpriv_fec_tx_channel); + fp->fecpriv_fec_tx_channel = -1; + + for (i = 0; i < FEC_TX_BUF_NUMBER; i++) { + if (fp->fecpriv_txbuf[i]) { + kfree(fp->fecpriv_txbuf[i]); + fp->fecpriv_txbuf[i] = NULL; + } + } + + spin_lock_irq(&fp->fecpriv_lock); + MCD_killDma(fp->fecpriv_fec_rx_channel); + spin_unlock_irq(&fp->fecpriv_lock); + + dma_remove_channel_by_number(fp->fecpriv_fec_rx_channel); + dma_disconnect(fp->fecpriv_fec_rx_channel); + fp->fecpriv_fec_rx_channel = -1; + + for (i = 0; i < FEC_RX_BUF_NUMBER; i++) { + if (fp->askb_rx[i]) { + kfree_skb(fp->askb_rx[i]); + fp->askb_rx[i] = NULL; + } + } + + return 0; +} + +/************************************************************************ +* +NAME: fec_get_stat +* +* RETURNS: This function returns the statistical information. +*************************************************************************/ +struct net_device_stats * fec_get_stat(struct net_device *dev) +{ + struct fec_priv *fp = netdev_priv(dev); + unsigned long base_addr = dev->base_addr; + + /* Receive the statistical information */ + fp->fecpriv_stat.rx_packets = FECSTAT_RMON_R_PACKETS(base_addr); + fp->fecpriv_stat.tx_packets = FECSTAT_RMON_T_PACKETS(base_addr); + fp->fecpriv_stat.rx_bytes = FECSTAT_RMON_R_OCTETS(base_addr); + fp->fecpriv_stat.tx_bytes = FECSTAT_RMON_T_OCTETS(base_addr); + + fp->fecpriv_stat.multicast = FECSTAT_RMON_R_MC_PKT(base_addr); + fp->fecpriv_stat.collisions = FECSTAT_RMON_T_COL(base_addr); + + fp->fecpriv_stat.rx_length_errors = FECSTAT_RMON_R_UNDERSIZE(base_addr) + + FECSTAT_RMON_R_OVERSIZE(base_addr) + + FECSTAT_RMON_R_FRAG(base_addr) + + FECSTAT_RMON_R_JAB(base_addr); + fp->fecpriv_stat.rx_crc_errors = FECSTAT_IEEE_R_CRC(base_addr); + fp->fecpriv_stat.rx_frame_errors = FECSTAT_IEEE_R_ALIGN(base_addr); + fp->fecpriv_stat.rx_over_errors = FECSTAT_IEEE_R_MACERR(base_addr); + + fp->fecpriv_stat.tx_carrier_errors = FECSTAT_IEEE_T_CSERR(base_addr); + fp->fecpriv_stat.tx_fifo_errors = FECSTAT_IEEE_T_MACERR(base_addr); + fp->fecpriv_stat.tx_window_errors = FECSTAT_IEEE_T_LCOL(base_addr); + + /* I hope that one frame doesn't have more than one error */ + fp->fecpriv_stat.rx_errors = fp->fecpriv_stat.rx_length_errors + + fp->fecpriv_stat.rx_crc_errors + + fp->fecpriv_stat.rx_frame_errors + + fp->fecpriv_stat.rx_over_errors + + fp->fecpriv_stat.rx_dropped; + fp->fecpriv_stat.tx_errors = fp->fecpriv_stat.tx_carrier_errors + + fp->fecpriv_stat.tx_fifo_errors + + fp->fecpriv_stat.tx_window_errors + + fp->fecpriv_stat.tx_aborted_errors + + fp->fecpriv_stat.tx_heartbeat_errors + + fp->fecpriv_stat.tx_dropped; + + return &fp->fecpriv_stat; +} + +/************************************************************************ +* NAME: fec_set_multicast_list +* +* DESCRIPTION: This function sets the frame filtering parameters +*************************************************************************/ +void fec_set_multicast_list(struct net_device *dev) +{ + struct dev_mc_list *dmi; + unsigned int crc, data; + int i, j, k; + unsigned long base_addr = (unsigned long) dev->base_addr; + + if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI) { + /* Allow all incoming frames */ + FEC_GALR(base_addr) = 0xFFFFFFFF; + FEC_GAUR(base_addr) = 0xFFFFFFFF; + return; + } + + /* Reset the group address register */ + FEC_GALR(base_addr) = 0x00000000; + FEC_GAUR(base_addr) = 0x00000000; + + /* Process all addresses */ + for (i = 0, dmi = dev->mc_list; i < dev->mc_count; i++, dmi = dmi->next) { + /* Processing must be only for the group addresses */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* Calculate crc value for the current address */ + crc = 0xFFFFFFFF; + for (j = 0; j < dmi->dmi_addrlen; j++) { + for (k = 0, data = dmi->dmi_addr[j]; k < 8; k++, data >>= 1) { + if ((crc ^ data) & 1) + crc = (crc >> 1) ^ FEC_CRCPOL; + else + crc >>= 1; + } + } + + /* Add this value */ + crc >>= 26; + crc &= 0x3F; + if (crc > 31) + FEC_GAUR(base_addr) |= 0x1 << (crc - 32); + else + FEC_GALR(base_addr) |= 0x1 << crc; + } +} + +/************************************************************************ +* NAME: fec_set_mac_address +* +* DESCRIPTION: This function sets the MAC address +*************************************************************************/ +int fec_set_mac_address(struct net_device *dev, void *p) +{ + struct fec_priv *fp = netdev_priv(dev); + unsigned long base_addr = (unsigned long) dev->base_addr; + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + + /* Copy a new address to the device structure */ + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* Copy a new address to the private structure */ + memcpy(fp->fecpriv_mac_addr, addr->sa_data, 6); + + /* Set the address to the registers */ + FEC_PALR(base_addr) = (fp->fecpriv_mac_addr[0] << 24) | + (fp->fecpriv_mac_addr[1] << 16) | + (fp->fecpriv_mac_addr[2] << 8) | + fp->fecpriv_mac_addr[3]; + FEC_PAUR(base_addr) = (fp->fecpriv_mac_addr[4] << 24) | + (fp->fecpriv_mac_addr[5] << 16) | + 0x8808; + + return 0; +} + +/************************************************************************ +* NAME: fec_tx +* +* DESCRIPTION: This function starts transmission of the frame using DMA +* +* RETURNS: This function always returns zero. +*************************************************************************/ +int fec_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct fec_priv *fp = netdev_priv(dev); + void *data, *data_aligned; + int offset; + + data = kmalloc(skb->len + 15, GFP_DMA | GFP_ATOMIC); + + if (!data) { + fp->fecpriv_stat.tx_dropped++; + dev_kfree_skb(skb); + return 0; + } + + offset = (((unsigned long)virt_to_phys(data) + 15) & 0xFFFFFFF0) - + (unsigned long)virt_to_phys(data); + data_aligned = (void*)((unsigned long)data + offset); + memcpy(data_aligned, skb->data, skb->len); + + /* flush data cache before initializing the descriptor and starting DMA */ +#if 0 +/* JKM -- currently running with cache turned off */ + DcacheFlushInvalidateCacheBlock((void*)virt_to_phys(data_aligned), skb->len); +#endif + + spin_lock_irq(&fp->fecpriv_lock); + + /* Initialize the descriptor */ + fp->fecpriv_txbuf[fp->fecpriv_next_tx] = data; + fp->fecpriv_txdesc[fp->fecpriv_next_tx].dataPointer = (unsigned int) virt_to_phys(data_aligned); + fp->fecpriv_txdesc[fp->fecpriv_next_tx].length = skb->len; + fp->fecpriv_txdesc[fp->fecpriv_next_tx].statCtrl |= (MCD_FEC_END_FRAME | MCD_FEC_BUF_READY); + fp->fecpriv_next_tx = (fp->fecpriv_next_tx + 1) & FEC_TX_INDEX_MASK; + + if (fp->fecpriv_txbuf[fp->fecpriv_current_tx] && fp->fecpriv_current_tx == fp->fecpriv_next_tx) + netif_stop_queue(dev); + + spin_unlock_irq(&fp->fecpriv_lock); + + /* Tell the DMA to continue the transmission */ + MCD_continDma(fp->fecpriv_fec_tx_channel); + + dev_kfree_skb(skb); + + dev->trans_start = jiffies; + + return 0; +} + +/************************************************************************ +* NAME: fec_tx_timeout +* +* DESCRIPTION: If the interrupt processing of received frames was lost +* and DMA stopped the reception, this function clears +* the transmission descriptors and starts DMA +* +*************************************************************************/ +void fec_tx_timeout(struct net_device *dev) +{ + int i; + struct fec_priv *fp = netdev_priv(dev); + unsigned long base_addr = (unsigned long) dev->base_addr; + + spin_lock_irq(&fp->fecpriv_lock); + MCD_killDma(fp->fecpriv_fec_tx_channel); + for (i = 0; i < FEC_TX_BUF_NUMBER; i++) { + if (fp->fecpriv_txbuf[i]) { + kfree(fp->fecpriv_txbuf[i]); + fp->fecpriv_txbuf[i] = NULL; + } + fp->fecpriv_txdesc[i].statCtrl = MCD_FEC_INTERRUPT; + } + fp->fecpriv_txdesc[i - 1].statCtrl |= MCD_FEC_WRAP; + + fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0; + + /* Reset FIFOs */ + FEC_FECFRST(base_addr) |= FEC_SW_RST; + FEC_FECFRST(base_addr) &= ~FEC_SW_RST; + + /* Reset and disable FEC */ +// FEC_ECR(base_addr) = FEC_ECR_RESET; + + /* Enable FEC */ + FEC_ECR(base_addr) |= FEC_ECR_ETHEREN; + + MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) fp->fecpriv_txdesc, 0, + (unsigned char *) &(FEC_FECTFDR(base_addr)), 0, + FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx, + FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT, + MCD_NO_CSUM | MCD_NO_BYTE_SWAP); + + spin_unlock_irq(&fp->fecpriv_lock); + + netif_wake_queue(dev); + +} + +/************************************************************************ +* NAME: fec_read_mii +* +* DESCRIPTION: This function reads the value from the MII register +* +* RETURNS: If no error occurs, this function returns zero. +*************************************************************************/ +int fec_read_mii(unsigned int base_addr, unsigned int pa, unsigned int ra, unsigned int *data) +{ + unsigned long time; + + /* Clear the MII interrupt bit */ + FEC_EIR(base_addr) = FEC_EIR_MII; + + /* Write to the MII management frame register */ + FEC_MMFR(base_addr) = FEC_MMFR_READ | (pa << 23) | (ra << 18); + + time = jiffies; + + /* Wait for the reading */ + while (!(FEC_EIR(base_addr) & FEC_EIR_MII)) { + if (jiffies - time > FEC_MII_TIMEOUT * HZ) + return -ETIME; + schedule(); + } + + /* Clear the MII interrupt bit */ + FEC_EIR(base_addr) = FEC_EIR_MII; + + *data = FEC_MMFR(base_addr) & 0x0000FFFF; + + return 0; +} + +/************************************************************************ +* NAME: fec_write_mii +* +* DESCRIPTION: This function writes the value to the MII register +* +* RETURNS: If no error occurs, this function returns zero. +*************************************************************************/ +int fec_write_mii(unsigned int base_addr, unsigned int pa, unsigned int ra, unsigned int data) +{ + unsigned long time; + + /* Clear the MII interrupt bit */ + FEC_EIR(base_addr) = FEC_EIR_MII; + + /* Write to the MII management frame register */ + FEC_MMFR(base_addr) = FEC_MMFR_WRITE | (pa << 23) | (ra << 18) | data; + + time = jiffies; + + /* Wait for the writing */ + while (!(FEC_EIR(base_addr) & FEC_EIR_MII)) { + if (jiffies - time > FEC_MII_TIMEOUT * HZ) + return -ETIME; + schedule(); + } + + /* Clear the MII interrupt bit */ + FEC_EIR(base_addr) = FEC_EIR_MII; + + return 0; +} + +/************************************************************************ +* NAME: fec_interrupt_tx_handler +* +* DESCRIPTION: This function is called when the data +* transmission from the buffer to the FEC is completed. +* +*************************************************************************/ +void fec_interrupt_fec_tx_handler(struct net_device *dev) +{ + struct fec_priv *fp = netdev_priv(dev); + + /* Release the socket buffer */ + if(fp->fecpriv_txbuf[fp->fecpriv_current_tx]) { + kfree(fp->fecpriv_txbuf[fp->fecpriv_current_tx]); + fp->fecpriv_txbuf[fp->fecpriv_current_tx] = NULL; + } + fp->fecpriv_current_tx = (fp->fecpriv_current_tx + 1) & FEC_TX_INDEX_MASK; + + if (MCD_dmaStatus(fp->fecpriv_fec_tx_channel) == MCD_DONE) { + for (; fp->fecpriv_current_tx != fp->fecpriv_next_tx; fp->fecpriv_current_tx = (fp->fecpriv_current_tx + 1) & FEC_TX_INDEX_MASK) { + if(fp->fecpriv_txbuf[fp->fecpriv_current_tx]) { + kfree(fp->fecpriv_txbuf[fp->fecpriv_current_tx]); + fp->fecpriv_txbuf[fp->fecpriv_current_tx] = NULL; + } + } + } + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); +} + +/************************************************************************ +* NAME: fec_interrupt_rx_handler +* +* DESCRIPTION: This function is called when the data +* reception from the FEC to the reception buffer is completed. +* +*************************************************************************/ +void fec_interrupt_fec_rx_handler(struct net_device *dev) +{ + struct fec_priv *fp = netdev_priv(dev); + struct sk_buff *skb; + int i; + + fp->fecpriv_rxflag = 1; + // Some buffers can be missed + if(!(fp->fecpriv_rxdesc[fp->fecpriv_current_rx].statCtrl & MCD_FEC_END_FRAME)) + { + // Find a valid index + for(i = 0; i < FEC_RX_BUF_NUMBER && !(fp->fecpriv_rxdesc[fp->fecpriv_current_rx].statCtrl & MCD_FEC_END_FRAME); i++, fp->fecpriv_current_rx = (fp->fecpriv_current_rx + 1) & FEC_RX_INDEX_MASK); + + if(i == FEC_RX_BUF_NUMBER) + { + // There are no data to process + // Tell the DMA to continue the reception + MCD_continDma(fp->fecpriv_fec_rx_channel); + + fp->fecpriv_rxflag = 0; + + return; + } + } + + for (; fp->fecpriv_rxdesc[fp->fecpriv_current_rx].statCtrl & MCD_FEC_END_FRAME; fp->fecpriv_current_rx = (fp->fecpriv_current_rx + 1) & FEC_RX_INDEX_MASK) { + if( (fp->fecpriv_rxdesc[fp->fecpriv_current_rx].length <= FEC_MAXBUF_SIZE) && + (fp->fecpriv_rxdesc[fp->fecpriv_current_rx].length > 4)) { /* --tym-- */ + skb = fp->askb_rx[fp->fecpriv_current_rx]; + if (!skb) + fp->fecpriv_stat.rx_dropped++; + else { + /* flush data cache before initializing the descriptor and starting DMA */ +// DcacheFlushInvalidateCacheBlock((void*)virt_to_phys(fp->askb_rx[fp->fecpriv_current_rx]->tail), fp->askb_rx[fp->fecpriv_current_rx]->len); + + skb_put(skb, fp->fecpriv_rxdesc[fp->fecpriv_current_rx].length - 4); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + } + fp->fecpriv_rxdesc[fp->fecpriv_current_rx].statCtrl &= ~MCD_FEC_END_FRAME; + /* allocate new skbuff */ + fp->askb_rx[fp->fecpriv_current_rx] = alloc_skb(FEC_MAXBUF_SIZE + 16, /*GFP_ATOMIC |*/ GFP_DMA); + if (!fp->askb_rx[fp->fecpriv_current_rx]) { + fp->fecpriv_rxdesc[fp->fecpriv_current_rx].dataPointer = 0; + fp->fecpriv_rxdesc[fp->fecpriv_current_rx].length = 0; + fp->fecpriv_stat.rx_dropped++; + } + else { + skb_reserve(fp->askb_rx[fp->fecpriv_current_rx], 16); + fp->askb_rx[fp->fecpriv_current_rx]->dev = dev; + + /* flush data cache before initializing the descriptor and starting DMA */ +#if 0 +/* JKM -- currently running with cache turned off */ + DcacheFlushInvalidateCacheBlock((void*)virt_to_phys(fp->askb_rx[fp->fecpriv_current_rx]->tail), FEC_MAXBUF_SIZE); +#endif + + fp->fecpriv_rxdesc[fp->fecpriv_current_rx].dataPointer = (unsigned int) virt_to_phys(fp->askb_rx[fp->fecpriv_current_rx]->tail); + fp->fecpriv_rxdesc[fp->fecpriv_current_rx].length = FEC_MAXBUF_SIZE; + fp->fecpriv_rxdesc[fp->fecpriv_current_rx].statCtrl |= MCD_FEC_BUF_READY; + + // flush data cache before initializing the descriptor and starting DMA +// DcacheFlushInvalidateCacheBlock((void*)virt_to_phys(fp->askb_rx[fp->fecpriv_current_rx]->tail), FEC_MAXBUF_SIZE); + } + } + + } + + /* Tell the DMA to continue the reception */ + MCD_continDma(fp->fecpriv_fec_rx_channel); + + fp->fecpriv_rxflag = 0; +} + +/************************************************************************ +* NAME: fec_interrupt_handler +* +* DESCRIPTION: This function is called when some special errors occur +* +*************************************************************************/ +irqreturn_t fec_interrupt_handler(int irq, void *dev_id) +{ + + struct net_device *dev = (struct net_device *)dev_id; + struct fec_priv *fp = netdev_priv(dev); + unsigned long base_addr = (unsigned long) dev->base_addr; + unsigned long events; + + /* Read and clear the events */ + events = FEC_EIR(base_addr) & FEC_EIMR(base_addr); + + if (events & FEC_EIR_HBERR) { + fp->fecpriv_stat.tx_heartbeat_errors++; + FEC_EIR(base_addr) = FEC_EIR_HBERR; + } + + /* receive/transmit FIFO error */ + if (((events & FEC_EIR_RFERR) != 0) || ((events & FEC_EIR_XFERR) != 0)) { + /* kill DMA receive channel */ + MCD_killDma (fp->fecpriv_fec_rx_channel); + + /* kill running transmission by DMA */ + MCD_killDma (fp->fecpriv_fec_tx_channel); + + /* Reset FIFOs */ + FEC_FECFRST(base_addr) |= FEC_SW_RST; + FEC_FECFRST(base_addr) &= ~FEC_SW_RST; + + /* reset receive FIFO status register */ + FEC_FECRFSR(base_addr) = FEC_FECRFSR_FAE | + FEC_FECRFSR_RXW | + FEC_FECRFSR_UF; + + /* reset transmit FIFO status register */ + FEC_FECTFSR(base_addr) = FEC_FECTFSR_FAE | + FEC_FECTFSR_TXW | + FEC_FECTFSR_UF | + FEC_FECTFSR_OF; + + /* reset RFERR and XFERR event */ + FEC_EIR(base_addr) = FEC_EIR_RFERR | FEC_EIR_XFERR; + + /* stop queue */ + netif_stop_queue(dev); + + /* execute reinitialization as tasklet */ + tasklet_schedule(&fp->fecpriv_tasklet_reinit); + + fp->fecpriv_stat.rx_dropped++; + } + + /* transmit FIFO underrun */ + if ((events & FEC_EIR_XFUN) != 0) { + /* reset XFUN event */ + FEC_EIR(base_addr) = FEC_EIR_XFUN; + fp->fecpriv_stat.tx_aborted_errors++; + } + + /* late collision */ + if ((events & FEC_EIR_LC) != 0) { + /* reset LC event */ + FEC_EIR(base_addr) = FEC_EIR_LC; + fp->fecpriv_stat.tx_aborted_errors++; + } + + /* collision retry limit */ + if ((events & FEC_EIR_RL) != 0) { + /* reset RL event */ + FEC_EIR(base_addr) = FEC_EIR_RL; + fp->fecpriv_stat.tx_aborted_errors++; + } + return 0; +} + +/************************************************************************ +* NAME: fec_interrupt_reinit +* +* DESCRIPTION: This function is called from interrupt handler +* when controller must be reinitialized. +* +*************************************************************************/ +void fec_interrupt_fec_reinit(unsigned long data) +{ + int i; + struct net_device *dev = (struct net_device*)data; + struct fec_priv *fp = netdev_priv(dev); + unsigned long base_addr = (unsigned long) dev->base_addr; + + /* Initialize reception descriptors and start DMA for the reception */ + for (i = 0; i < FEC_RX_BUF_NUMBER; i++) { + if (!fp->askb_rx[i]) { + fp->askb_rx[i] = alloc_skb(FEC_MAXBUF_SIZE + 16, GFP_ATOMIC | GFP_DMA); + if (!fp->askb_rx[i]) { + fp->fecpriv_rxdesc[i].dataPointer = 0; + fp->fecpriv_rxdesc[i].statCtrl = 0; + fp->fecpriv_rxdesc[i].length = 0; + continue; + } + fp->askb_rx[i]->dev = dev; + skb_reserve(fp->askb_rx[i], 16); + } + fp->fecpriv_rxdesc[i].dataPointer = (unsigned int) virt_to_phys(fp->askb_rx[i]->tail); + fp->fecpriv_rxdesc[i].statCtrl = MCD_FEC_BUF_READY | MCD_FEC_INTERRUPT; + fp->fecpriv_rxdesc[i].length = FEC_MAXBUF_SIZE; + } + + fp->fecpriv_rxdesc[i - 1].statCtrl |= MCD_FEC_WRAP; + fp->fecpriv_current_rx = 0; + + /* restart frame transmission */ + for (i = 0; i < FEC_TX_BUF_NUMBER; i++) { + if (fp->fecpriv_txbuf[i]) { + kfree(fp->fecpriv_txbuf[i]); + fp->fecpriv_txbuf[i] = NULL; + fp->fecpriv_stat.tx_dropped++; + } + fp->fecpriv_txdesc[i].statCtrl = MCD_FEC_INTERRUPT; + } + fp->fecpriv_txdesc[i - 1].statCtrl |= MCD_FEC_WRAP; + fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0; + + /* flush entire data cache before restarting the DMA */ +#if 0 +/* JKM -- currently running with cache turned off */ + DcacheFlushInvalidate(); +#endif + + /* restart DMA from beginning */ + MCD_startDma(fp->fecpriv_fec_rx_channel, + (char *) fp->fecpriv_rxdesc, 0, + (unsigned char *) &(FEC_FECRFDR(base_addr)), 0, + FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_rx, + FEC_RX_DMA_PRI, MCD_FECRX_DMA | MCD_INTERRUPT, + MCD_NO_CSUM | MCD_NO_BYTE_SWAP); + + MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) fp->fecpriv_txdesc, 0, + (unsigned char *) &(FEC_FECTFDR(base_addr)), 0, + FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx, + FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT, + MCD_NO_CSUM | MCD_NO_BYTE_SWAP); + + /* Enable FEC */ + FEC_ECR(base_addr) |= FEC_ECR_ETHEREN; + + netif_wake_queue(dev); +} + +/************************************************************************ +* NAME: fec_interrupt_tx_handler_fec0 +* +* DESCRIPTION: This is the DMA interrupt handler using for FEC0 +* transmission. +* +*************************************************************************/ +void fec_interrupt_fec_tx_handler_fec0(void) +{ + fec_interrupt_fec_tx_handler(fec_dev[0]); +} + +#ifdef FEC_2 +/************************************************************************ +* NAME: fec_interrupt_tx_handler_fec1 +* +* DESCRIPTION: This is the DMA interrupt handler using for the FEC1 +* transmission. +* +*************************************************************************/ +void fec_interrupt_fec_tx_handler_fec1(void) +{ + fec_interrupt_fec_tx_handler(fec_dev[1]); +} +#endif + +/************************************************************************ +* NAME: fec_interrupt_rx_handler_fec0 +* +* DESCRIPTION: This is the DMA interrupt handler using for the FEC0 +* reception. +* +*************************************************************************/ +void fec_interrupt_fec_rx_handler_fec0(void) +{ + fec_interrupt_fec_rx_handler(fec_dev[0]); +} + +#ifdef FEC_2 +/************************************************************************ +* NAME: fec_interrupt_rx_handler_fec1 +* +* DESCRIPTION: This is the DMA interrupt handler using for the FEC1 +* reception. +* +*************************************************************************/ +void fec_interrupt_fec_rx_handler_fec1(void) +{ + fec_interrupt_fec_rx_handler(fec_dev[1]); +} + +#endif + +#ifndef MODULE +/************************************************************************ +* NAME: fec_mac_setup0 +* +* DESCRIPTION: This function sets the MAC address of FEC0 from command line +* +*************************************************************************/ +int __init fec_mac_setup0(char *s) +{ + if(!s || !*s) + return 1; + + if(fec_str_to_mac(s, fec_mac_addr_fec0)) + printk("The MAC address of FEC0 cannot be set from command line"); + return 1; +} + +#ifdef FEC_2 + +/************************************************************************ +* NAME: fec_mac_setup1 +* +* DESCRIPTION: This function sets the MAC address of FEC1 from command line +* +*************************************************************************/ +int __init fec_mac_setup1(char *s) +{ + if(!s || !*s) + return 1; + + if(fec_str_to_mac(s, fec_mac_addr_fec1)) + printk("The MAC address of FEC1 cannot be set from command line"); + return 1; +} +#endif + +/************************************************************************ +* NAME: fec_str_to_mac +* +* DESCRIPTION: This function interprets the character string into MAC addr +* +*************************************************************************/ +int fec_str_to_mac( char *str_mac, unsigned char* addr) +{ + unsigned long val; + char c; + unsigned long octet[6], *octetptr = octet; + int i; + +again: + val = 0; + while ((c = *str_mac) != '\0') { + if ((c>='0')&&(c<='9')) { + val = (val * 16) + (c - '0'); + str_mac++; + continue; + } + else if (((c>='a')&&(c<='f'))||((c>='A')&&(c<='F'))) { + val = (val << 4) + (c + 10 - (((c>='a')&&(c<='f')) ? 'a' : 'A')); + str_mac++; + continue; + } + break; + } + if (*str_mac == ':') { + *octetptr++ = val, str_mac++; + if (octetptr >= octet + 6) + return 1; + goto again; + } + + /* Check for trailing characters */ + if (*str_mac && !(*str_mac==' ')) + return 1; + + *octetptr++ = val; + + if ((octetptr - octet)==6) { + for(i=0;i<=6;i++) + addr[i]=octet[i]; + } + else + return 1; + + return 0; +} +#endif --- /dev/null +++ b/drivers/net/fec/fec.h @@ -0,0 +1,162 @@ + +#define FEC_BASE_ADDR_FEC0 ((unsigned int)MCF_MBAR + 0x9000) +#define FEC_BASE_ADDR_FEC1 ((unsigned int)MCF_MBAR + 0x9800) + +//#define FEC_INTC_IMRH_INT_MASK38 (0x00000040) +//#define FEC_INTC_IMRH_INT_MASK39 (0x00000080) +//#define FEC_INTC_ICR_FEC0 (0x30) +//#define FEC_INTC_ICR_FEC1 (0x31) +#define FEC_FECI2CIRQ (0xFFC0) +#define FEC_GPIO_PAR_FECI2CIRQ *(volatile unsigned short*)((unsigned int)MCF_MBAR + 0xA44) +//#define FEC_INTC_ICRn(x) (*(volatile unsigned char *)(void*)((unsigned int) MCF_MBAR + 0x000740+((x)*0x001))) +//#define FEC_INTC_IMRH *(volatile unsigned int*)((unsigned int)MCF_MBAR + 0x000708) + +#define FEC_ECR_DISABLE (0x00000000) + +#define FEC_ECR(x) *(volatile unsigned int *)(x + 0x024) +#define FEC_EIR(x) *(volatile unsigned int*)(x + 0x004) +#define FEC_PALR(x) *(volatile unsigned int*)(x + 0x0E4) +#define FEC_PAUR(x) *(volatile unsigned int*)(x + 0x0E8) +#define FEC_IALR(x) *(volatile unsigned int*)(x + 0x11C) +#define FEC_IAUR(x) *(volatile unsigned int*)(x + 0x118) +#define FEC_GALR(x) *(volatile unsigned int*)(x + 0x124) +#define FEC_GAUR(x) *(volatile unsigned int*)(x + 0x120) +#define FEC_RCR(x) *(volatile unsigned int*)(x + 0x084) +#define FEC_FECRFCR(x) *(volatile unsigned int*)(x + 0x18C) +#define FEC_FECRFAR(x) *(volatile unsigned int*)(x + 0x198) +#define FEC_FECTFCR(x) *(volatile unsigned int*)(x + 0x1AC) +#define FEC_FECTFAR(x) *(volatile unsigned int*)(x + 0x1B8) +#define FEC_FECTFWR(x) *(volatile unsigned int*)(x + 0x144) +#define FEC_CTCWR(x) *(volatile unsigned int*)(x + 0x1C8) +#define FEC_EIMR(x) *(volatile unsigned int*)(x + 0x008) +#define FEC_TCR(x) *(volatile unsigned int*)(x + 0x0C4) +#define FEC_MIBC(x) *(volatile unsigned int*)(x + 0x064) +#define FEC_MSCR(x) *(volatile unsigned int*)(x + 0x044) +#define FEC_FECTFDR(x) *(volatile unsigned int*)(x + 0x1A4) +#define FEC_FECRFDR(x) *(volatile unsigned int*)(x + 0x184) +#define FEC_FECTFSR(x) *(volatile unsigned int*)(x + 0x1A8) +#define FEC_FECRFSR(x) *(volatile unsigned int*)(x + 0x188) +#define FECSTAT_RMON_R_PACKETS(x) *(volatile unsigned int*)(x + 0x284) +#define FECSTAT_RMON_T_PACKETS(x) *(volatile unsigned int*)(x + 0x204) +#define FECSTAT_RMON_R_OCTETS(x) *(volatile unsigned int*)(x + 0x2C4) +#define FECSTAT_RMON_T_OCTETS(x) *(volatile unsigned int*)(x + 0x244) +#define FECSTAT_RMON_R_UNDERSIZE(x) *(volatile unsigned int*)(x + 0x294) +#define FECSTAT_RMON_R_OVERSIZE(x) *(volatile unsigned int*)(x + 0x298) +#define FECSTAT_RMON_R_FRAG(x) *(volatile unsigned int*)(x + 0x29C) +#define FECSTAT_RMON_R_JAB(x) *(volatile unsigned int*)(x + 0x2A0) +#define FECSTAT_RMON_R_MC_PKT(x) *(volatile unsigned int*)(x + 0x28C) +#define FECSTAT_RMON_T_COL(x) *(volatile unsigned int*)(x + 0x224) +#define FECSTAT_IEEE_R_ALIGN(x) *(volatile unsigned int*)(x + 0x2D4) +#define FECSTAT_IEEE_R_CRC(x) *(volatile unsigned int*)(x + 0x2D0) +#define FECSTAT_IEEE_R_MACERR(x) *(volatile unsigned int*)(x + 0x2D8) +#define FECSTAT_IEEE_T_CSERR(x) *(volatile unsigned int*)(x + 0x268) +#define FECSTAT_IEEE_T_MACERR(x) *(volatile unsigned int*)(x + 0x264) +#define FECSTAT_IEEE_T_LCOL(x) *(volatile unsigned int*)(x + 0x25C) +#define FECSTAT_IEEE_R_OCTETS_OK(x) *(volatile unsigned int*)(x + 0x2E0) +#define FECSTAT_IEEE_T_OCTETS_OK(x) *(volatile unsigned int*)(x + 0x274) +#define FECSTAT_IEEE_R_DROP(x) *(volatile unsigned int*)(x + 0x2C8) +#define FECSTAT_IEEE_T_DROP(x) *(volatile unsigned int*)(x + 0x248) +#define FECSTAT_IEEE_R_FRAME_OK(x) *(volatile unsigned int*)(x + 0x2CC) +#define FECSTAT_IEEE_T_FRAME_OK(x) *(volatile unsigned int*)(x + 0x24C) +#define FEC_MMFR(x) *(volatile unsigned int*)(x + 0x040) +#define FEC_FECFRST(x) *(volatile unsigned int*)(x + 0x1C4) + +#define FEC_MAX_FRM_SIZE (1518) +#define FEC_MAXBUF_SIZE (1520) + +// Register values +#define FEC_ECR_RESET (0x00000001) +#define FEC_EIR_CLEAR (0xFFFFFFFF) +#define FEC_EIR_RL (0x00100000) +#define FEC_EIR_HBERR (0x80000000) +#define FEC_EIR_BABR (0x40000000) // babbling receive error +#define FEC_EIR_BABT (0x20000000) // babbling transmit error +#define FEC_EIR_TXF (0x08000000) // transmit frame interrupt +#define FEC_EIR_MII (0x00800000) // MII interrupt +#define FEC_EIR_LC (0x00200000) // late collision +#define FEC_EIR_XFUN (0x00080000) // transmit FIFO underrun +#define FEC_EIR_XFERR (0x00040000) // transmit FIFO error +#define FEC_EIR_RFERR (0x00020000) // receive FIFO error +#define FEC_RCR_MAX_FRM_SIZE (FEC_MAX_FRM_SIZE << 16) +#define FEC_RCR_MII (0x00000004) +#define FEC_FECRFCR_FAE (0x00400000) // frame accept error +#define FEC_FECRFCR_RXW (0x00200000) // receive wait condition +#define FEC_FECRFCR_UF (0x00100000) // receive FIFO underflow +#define FEC_FECRFCR_FRM (0x08000000) +#define FEC_FECRFCR_GR (0x7 << 24) + +#define FEC_EIMR_DISABLE (0x00000000) + +#define FEC_FECRFAR_ALARM (0x300) +#define FEC_FECTFCR_FRM (0x08000000) +#define FEC_FECTFCR_GR (0x7 << 24) +#define FEC_FECTFCR_FAE (0x00400000) // frame accept error +#define FEC_FECTFCR_TXW (0x00040000) // transmit wait condition +#define FEC_FECTFCR_UF (0x00100000) // transmit FIFO underflow +#define FEC_FECTFCR_OF (0x00080000) // transmit FIFO overflow + +#define FEC_FECTFAR_ALARM (0x100) +#define FEC_FECTFWR_XWMRK (0x00000000) + +#define FEC_FECTFSR_MSK (0xC0B00000) +#define FEC_FECTFSR_TXW (0x40000000) // transmit wait condition +#define FEC_FECTFSR_FAE (0x00800000) // frame accept error +#define FEC_FECTFSR_UF (0x00200000) // transmit FIFO underflow +#define FEC_FECTFSR_OF (0x00100000) // transmit FIFO overflow + +#define FEC_FECRFSR_MSK (0x80F00000) +#define FEC_FECRFSR_FAE (0x00800000) // frame accept error +#define FEC_FECRFSR_RXW (0x00400000) // receive wait condition +#define FEC_FECRFSR_UF (0x00200000) // receive FIFO underflow + +#define FEC_CTCWR_TFCW_CRC (0x03000000) +#define FEC_TCR_FDEN (0x00000004) +#define FEC_TCR_HBC (0x00000002) +#define FEC_RCR_DRT (0x00000002) +#define FEC_EIMR_MASK (FEC_EIR_RL | FEC_EIR_HBERR) +#define FEC_ECR_ETHEREN (0x00000002) +#define FEC_FECTFCR_MSK (0x00FC0000) +#define FEC_FECRFCR_MSK (0x00F80000) +#define FEC_EIR_GRA (0x10000000) +#define FEC_TCR_GTS (0x00000001) +#define FEC_MIBC_ENABLE (0x00000000) +#define FEC_MIB_LEN (228) +#define FEC_PHY_ADDR (0x01) + +#define FEC_RX_DMA_PRI (6) +#define FEC_TX_DMA_PRI (6) + +#define FEC_TX_BUF_NUMBER (8) +#define FEC_RX_BUF_NUMBER (64) + +#define FEC_TX_INDEX_MASK (0x7) +#define FEC_RX_INDEX_MASK (0x3f) + +#define FEC_RX_DESC_FEC0 SYS_SRAM_FEC_START +#define FEC_TX_DESC_FEC0 FEC_RX_DESC_FEC0 + FEC_RX_BUF_NUMBER * sizeof(MCD_bufDescFec) + +#define FEC_RX_DESC_FEC1 SYS_SRAM_FEC_START + SYS_SRAM_FEC_SIZE/2 +#define FEC_TX_DESC_FEC1 FEC_RX_DESC_FEC1 + FEC_RX_BUF_NUMBER * sizeof(MCD_bufDescFec) + +#define FEC_EIR_MII (0x00800000) +#define FEC_MMFR_READ (0x60020000) +#define FEC_MMFR_WRITE (0x50020000) + +#define FEC_FLAGS_RX (0x00000001) + +#define FEC_CRCPOL (0xEDB88320) + +#define FEC_MII_TIMEOUT (2) +#define FEC_GR_TIMEOUT (1) +#define FEC_TX_TIMEOUT (1) +#define FEC_RX_TIMEOUT (1) + +#define FEC_SW_RST 0x2000000 +#define FEC_RST_CTL 0x1000000 + +int fec_read_mii(unsigned int base_addr, unsigned int pa, unsigned int ra, + unsigned int *data); +int fec_write_mii(unsigned int base_addr, unsigned int pa, unsigned int ra, + unsigned int data); + +#define init_transceiver ks8721_init_transceiver --- /dev/null +++ b/drivers/net/fec/Kconfig @@ -0,0 +1,25 @@ +config FEC_548x + tristate "MCF547x/MCF548x Fast Ethernet Controller support" + depends on M547X_8X + help + The MCF547x and MCF548x have a built-in Fast Ethernet Controller. + Saying Y here will include support for this device in the kernel. + + To compile this driver as a module, choose M here: the module + will be called fecm. + +config FEC_548x_AUTO_NEGOTIATION + bool "Enable Auto-Negotiation" + depends on FEC_548x + help + This option enables the FEC to automatically detect the + half/full duplex mode and the network speed at initialization + If you want this, say Y. + +config FEC_548x_ENABLE_FEC2 + bool "Enable the second FEC" + depends on FEC_548x + help + This enables the second FEC on the 547x/548x. If you want to use + it, say Y. + --- /dev/null +++ b/drivers/net/fec/ks8721.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#include +#include +#include +#include +#endif +#include +#include + +#include "fec.h" +#include "ks8721.h" + +#ifdef CONFIG_FEC_548x_AUTO_NEGOTIATION +#define KS8721_AUTO_NEGOTIATION_ENABLE +#endif + +/************************************************************************ +* +NAME: ks8721_init_transceiver +* +* DESCRIPTION: This function initializes the transceiver +* +* RETURNS: If no error occurs, this function returns zero. +* Otherwise, it returns 1 +*************************************************************************/ + +int ks8721_init_transceiver(unsigned long base_addr, int *fduplex) +{ + + int data; + unsigned long time; + int flag = 1; + + int result; + + // Set the frequency of MII + FEC_MSCR(base_addr) = FEC_MII_SPEED; + + // Reset + if ((result = fec_write_mii(base_addr, FEC_PHY_ADDR, KS8721_CTRL, KS8721_CTRL_RESET))) + return result; + + // Read back + if ((result = fec_read_mii(base_addr, FEC_PHY_ADDR, KS8721_CTRL, &data)) != 0) + return result; + + // If reset bit is set, return + if (data & KS8721_CTRL_RESET) + return -ETIME; + +#ifdef KS8721_AUTO_NEGOTIATION_ENABLE + + // Disable the auto-negotiation + if ((result = fec_write_mii(base_addr, FEC_PHY_ADDR, KS8721_CTRL, 0)) != 0) + return result; + + // Set the auto-negotiation advertisement register + if ((result = fec_write_mii(base_addr, FEC_PHY_ADDR, KS8721_ANADV, KS8721_ANADV_ADV_ALL)) != 0) + return result; + + // Enable the auto-negotiation + if ((result = fec_write_mii(base_addr, FEC_PHY_ADDR, KS8721_CTRL, KS8721_CTRL_AN_ENABLE)) != 0) + return result; + + // Read PHY status register + if ((result = fec_read_mii(base_addr, FEC_PHY_ADDR, KS8721_STAT, &data)) != 0) + return result; + // Set the current time + time = jiffies; + + // Wait for the auto-negotiation completion + while (!(data & KS8721_STAT_ANCOMPLETE)) + { + + if (jiffies - time > KS8721_TIMEOUT * HZ) + { + flag = 0; + break; + } + + schedule(); + + // Read PHY status register + if ((result = fec_read_mii(base_addr, FEC_PHY_ADDR, KS8721_STAT, &data)) != 0) + return result; + } + + if (flag) + { + // Set the duplex flag + if (data & KS8721_STAT_FDUPLEX) + *fduplex = 1; + else + *fduplex = 0; + + return 0; + } + +#endif + + // Set the default mode (Full duplex, 100 Mbps) + if ((result = fec_write_mii(base_addr, FEC_PHY_ADDR, KS8721_CTRL, KS8721_CTRL_DEFAULT_MODE)) != 0) + return result; + *fduplex = KS8721_CTRL_DEFAULT_MODE & 0x100; + + return 0; + +} --- /dev/null +++ b/drivers/net/fec/ks8721.h @@ -0,0 +1,21 @@ + +#define FEC_MII_SPEED (((unsigned int)(MCF_BUSCLK / 5000000)) << 1) + +// Numbers of the transceiver registers +#define KS8721_CTRL 0x00 +#define KS8721_ANADV 0x04 +#define KS8721_STAT 0x01 + +// Register values +#define KS8721_CTRL_RESET 0x8000 +#define KS8721_ANADV_ADV_ALL 0x01E1 +#define KS8721_CTRL_AN_ENABLE 0x1280 +#define KS8721_CTRL_DEFAULT_MODE 0x2100 +#define KS8721_STAT_ANCOMPLETE 0x0020 +#define KS8721_STAT_LINK 0x0004 +#define KS8721_STAT_FDUPLEX 0x5000 + +// Timeout for the auto-negotiation mode +#define KS8721_TIMEOUT 5 + +int ks8721_init_transceiver(unsigned long base_addr, int *fduplex); --- /dev/null +++ b/drivers/net/fec/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the FEC ethernet driver +# + +obj-$(CONFIG_FEC_548x) += fecm.o + +fecm-objs := fec.o ks8721.o --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -23,6 +23,9 @@ * * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) * Copyright (c) 2004-2006 Macq Electronique SA. + * + * Coldfire bug fixes and cleanup by Kurt Mahan (kmahan@freescale.com) + * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved. */ #include @@ -51,7 +54,9 @@ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ defined(CONFIG_M5272) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) + defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ + defined(CONFIG_M5445X) + #include #include #include "fec.h" @@ -82,6 +87,11 @@ static unsigned int fec_hw[] = { (MCF_MBAR+0x30000), #elif defined(CONFIG_M532x) (MCF_MBAR+0xfc030000), +#elif defined(CONFIG_M5445X) + (MCF_MBAR+0xfc030000), +#if defined(CONFIG_FEC2) + (MCF_MBAR+0xfc034000), +#endif #else &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), #endif @@ -172,7 +182,7 @@ typedef struct { * account when setting it. */ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) + defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M5445X) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #else #define OPT_FRAME_SIZE 0 @@ -213,6 +223,7 @@ struct fec_enet_private { uint phy_speed; phy_info_t const *phy; struct work_struct phy_task; + volatile fec_t *phy_hwp; uint sequence_done; uint mii_phy_task_queued; @@ -349,7 +360,8 @@ fec_enet_start_xmit(struct sk_buff *skb, if (bdp->cbd_bufaddr & 0x3) { unsigned int index; index = bdp - fep->tx_bd_base; - memcpy(fep->tx_bounce[index], (void *) bdp->cbd_bufaddr, bdp->cbd_datlen); + memcpy(fep->tx_bounce[index], + (void *)skb->data, bdp->cbd_datlen); bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]); } @@ -702,7 +714,7 @@ fec_enet_mii(struct net_device *dev) uint mii_reg; fep = netdev_priv(dev); - ep = fep->hwp; + ep = fep->phy_hwp; mii_reg = ep->fec_mii_data; spin_lock(&fep->lock); @@ -753,7 +765,7 @@ mii_queue(struct net_device *dev, int re mii_tail = mip; } else { mii_head = mii_tail = mip; - fep->hwp->fec_mii_data = regval; + fep->phy_hwp->fec_mii_data = regval; } } else { retval = 1; @@ -1151,8 +1163,7 @@ static phy_info_t const phy_info_ks8721b }; /* ------------------------------------------------------------------------- */ -/* register definitions for the DP83848 */ - +/* register definitions for the DP83848 and DP83849 */ #define MII_DP8384X_PHYSTST 16 /* PHY Status Register */ static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) @@ -1186,27 +1197,50 @@ static void mii_parse_dp8384x_sr2(uint m *s |= PHY_STAT_FAULT; } +static phy_cmd_t const phy_cmd_dp8384x_ack_int[] = { + { mk_mii_end, } + }; + +static phy_cmd_t const phy_cmd_dp8384x_shutdown[] = { + { mk_mii_end, } + }; + static phy_info_t phy_info_dp83848= { - 0x020005c9, - "DP83848", + .id = 0x020005c9, + .name = "DP83848", - (const phy_cmd_t []) { /* config */ + .config = (const phy_cmd_t []) { /* config */ { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 }, { mk_mii_end, } }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + .startup = (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } }, - (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */ + .ack_int = phy_cmd_dp8384x_ack_int, + .shutdown = phy_cmd_dp8384x_shutdown, +}; + +static phy_info_t phy_info_dp83849 = { + .id = 0x020005ca, + .name = "DP83849", + + .config = (const phy_cmd_t []) { /* config */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 }, { mk_mii_end, } }, - (const phy_cmd_t []) { /* shutdown */ + .startup = (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } }, + .ack_int = phy_cmd_dp8384x_ack_int, + .shutdown = phy_cmd_dp8384x_shutdown, }; /* ------------------------------------------------------------------------- */ @@ -1218,6 +1252,7 @@ static phy_info_t const * const phy_info &phy_info_am79c874, &phy_info_ks8721bl, &phy_info_dp83848, + &phy_info_dp83849, NULL }; @@ -1799,6 +1834,138 @@ static void __inline__ fec_uncache(unsig /* ------------------------------------------------------------------------- */ +#elif defined(CONFIG_M5445X) +/* + * Code specific for M5445X + */ + +static void __inline__ fec_request_intrs(struct net_device *dev) +{ + struct fec_enet_private *fep; + int b; + static const struct idesc { + char *name; + unsigned short irq; + } *idp, id[] = { + { "fec(TXF)", 36 }, + { "fec(TXB)", 37 }, + { "fec(TXFIFO)", 38 }, + { "fec(TXCR)", 39 }, + { "fec(RXF)", 40 }, + { "fec(RXB)", 41 }, + { "fec(MII)", 42 }, + { "fec(LC)", 43 }, + { "fec(HBERR)", 44 }, + { "fec(GRA)", 45 }, + { "fec(EBERR)", 46 }, + { "fec(BABT)", 47 }, + { "fec(BABR)", 48 }, + { NULL }, + }; + + fep = netdev_priv(dev); + b = (fep->index) ? 77 : 64; + + /* Setup interrupt handlers. */ + for (idp = id; idp->name; idp++) { + if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, + idp->name, dev) != 0) + printk(KERN_ERR "FEC: Could not alloc %s IRQ(%d)!\n", + idp->name, b+idp->irq); + } + + if (fep->index) { + /* Configure RMII */ + MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC & + MCF_GPIO_PAR_FEC_FEC1_MASK) | + MCF_GPIO_PAR_FEC_FEC1_RMII_GPIO; + } else { + /* Configure RMII */ + MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC & + MCF_GPIO_PAR_FEC_FEC0_MASK) | + MCF_GPIO_PAR_FEC_FEC0_RMII_GPIO; + } + + /* Set up gpio outputs for MII lines on FEC0 */ + MCF_GPIO_PAR_FECI2C |= (0 | + MCF_GPIO_PAR_FECI2C_MDIO0_MDIO0 | + MCF_GPIO_PAR_FECI2C_MDC0_MDC0); +} + +static void __inline__ fec_set_mii(struct net_device *dev, + struct fec_enet_private *fep) +{ + volatile fec_t *fecp; + + fecp = fep->hwp; + fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; + fecp->fec_x_cntrl = 0x00; + + /* + * Set MII speed to 2.5 MHz + */ + fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2; + fecp->fec_mii_speed = fep->phy_speed; + + fec_restart(dev, 0); +} + +static void __inline__ fec_get_mac(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + volatile fec_t *fecp; + unsigned char *iap, tmpaddr[ETH_ALEN]; + + fecp = fep->hwp; + + if (FEC_FLASHMAC) { + /* + * Get MAC address from FLASH. + * If it is all 1's or 0's, use the default. + */ + iap = FEC_FLASHMAC; + if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && + (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) + iap = fec_mac_default; + if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && + (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = fec_mac_default; + } else { + *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; + *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + + memcpy(dev->dev_addr, iap, ETH_ALEN); + + /* Adjust MAC if using default MAC address */ + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + + fep->index; +} + +static void __inline__ fec_enable_phy_intr(void) +{ +} + +static void __inline__ fec_disable_phy_intr(void) +{ +} + +static void __inline__ fec_phy_ack_intr(void) +{ +} + +static void __inline__ fec_localhw_setup(void) +{ +} + +static void __inline__ fec_uncache(unsigned long addr) +{ +} + +/* ------------------------------------------------------------------------- */ + #else @@ -2305,7 +2472,7 @@ fec_set_mac_address(struct net_device *d } -/* Initialize the FEC Ethernet on 860T (or ColdFire 5272). +/* Initialize the FEC Ethernet. */ /* * XXX: We need to clean up on failure exits here. @@ -2326,7 +2493,7 @@ int __init fec_enet_init(struct net_devi /* Allocate memory for buffer descriptors. */ - mem_addr = __get_free_page(GFP_KERNEL); + mem_addr = __get_free_page(GFP_DMA); if (mem_addr == 0) { printk("FEC: allocate descriptor memory failed?\n"); return -ENOMEM; @@ -2339,6 +2506,11 @@ int __init fec_enet_init(struct net_devi fep->index = index; fep->hwp = fecp; fep->netdev = dev; +#ifdef CONFIG_FEC_SHARED_PHY + fep->phy_hwp = (volatile fec_t *) fec_hw[index & ~1]; +#else + fep->phy_hwp = fecp; +#endif /* Whack a reset. We should wait for this. */ @@ -2375,7 +2547,7 @@ int __init fec_enet_init(struct net_devi /* Allocate a page. */ - mem_addr = __get_free_page(GFP_KERNEL); + mem_addr = __get_free_page(GFP_DMA); /* XXX: missing check for allocation failure */ fec_uncache(mem_addr); @@ -2400,7 +2572,7 @@ int __init fec_enet_init(struct net_devi bdp = fep->tx_bd_base; for (i=0, j=FEC_ENET_TX_FRPPG; i= FEC_ENET_TX_FRPPG) { - mem_addr = __get_free_page(GFP_KERNEL); + mem_addr = __get_free_page(GFP_DMA); j = 1; } else { mem_addr += FEC_ENET_TX_FRSIZE; @@ -2462,7 +2634,11 @@ int __init fec_enet_init(struct net_devi * remainder of the interface. */ fep->phy_id_done = 0; +#ifndef CONFIG_FEC_SHARED_PHY fep->phy_addr = 0; +#else + fep->phy_addr = fep->index; +#endif mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); index++; --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -14,7 +14,7 @@ /****************************************************************************/ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) + defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M5445X) /* * Just figures, Motorola would have to change the offsets for * registers in the same peripheral device on different models --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -351,6 +351,8 @@ config MACB source "drivers/net/arm/Kconfig" +source "drivers/net/fec/Kconfig" + config AX88796 tristate "ASIX AX88796 NE2000 clone support" depends on ARM || MIPS || SUPERH @@ -1973,7 +1975,7 @@ config 68360_ENET config FEC bool "FEC ethernet controller (of ColdFire CPUs)" - depends on M523x || M527x || M5272 || M528x || M520x + depends on M523x || M527x || M5272 || M528x || M520x || M5445X help Say Y here if you want to use the built-in 10/100 Fast ethernet controller on some Motorola ColdFire processors. @@ -1985,6 +1987,12 @@ config FEC2 Say Y here if you want to use the second built-in 10/100 Fast ethernet controller on some Motorola ColdFire processors. +config FEC_SHARED_PHY + bool "Shared PHY interface(on some ColdFire designs)" + depends on FEC2 + help + Say Y here if both PHYs are controlled via a single channel. + config FEC_MPC52xx tristate "MPC52xx FEC driver" depends on PPC_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -226,6 +226,8 @@ obj-$(CONFIG_ENC28J60) += enc28j60.o obj-$(CONFIG_MACB) += macb.o +obj-$(CONFIG_FEC_548x) += fec/ + obj-$(CONFIG_ARM) += arm/ obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_TR) += tokenring/ --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -23,6 +23,7 @@ static DEFINE_SPINLOCK(pci_lock); #define PCI_word_BAD (pos & 1) #define PCI_dword_BAD (pos & 3) +#ifdef NL_ORIGINAL #define PCI_OP_READ(size,type,len) \ int pci_bus_read_config_##size \ (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ @@ -37,7 +38,20 @@ int pci_bus_read_config_##size \ spin_unlock_irqrestore(&pci_lock, flags); \ return res; \ } - +#else /* NL_ORIGINAL */ +#define PCI_OP_READ(size,type,len) \ +int pci_bus_read_config_##size \ + (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ +{ \ + int res; \ + unsigned long flags; \ + if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + spin_lock_irqsave(&pci_lock, flags); \ + res = bus->ops->read(bus, devfn, pos, len, (u32 *)value); \ + spin_unlock_irqrestore(&pci_lock, flags); \ + return res; \ +} +#endif /* NL_ORIGINAL */ #define PCI_OP_WRITE(size,type,len) \ int pci_bus_write_config_##size \ (struct pci_bus *bus, unsigned int devfn, int pos, type value) \ --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_PPC) += setup-bus.o obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_MN10300) += setup-bus.o +obj-$(CONFIG_M54455) += setup-bus.o setup-irq.o # # ACPI Related PCI FW Functions --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -15,7 +15,6 @@ #define DRV_VERSION "0.5" - /* * Ricoh has a family of I2C based RTCs, which differ only slightly from * each other. Differences center on pinout (e.g. how many interrupts, @@ -60,6 +59,15 @@ /* to read (style 1) or write registers starting at R */ #define RS5C_ADDR(R) (((R) << 4) | 0) +#ifdef CONFIG_M547X_8X +#define DRV_NAME "rv5c387a" +/* i2c configuration */ +#define RV5C387_I2C_ADDR 0x32 +static unsigned short normal_i2c[] = { + RV5C387_I2C_ADDR, I2C_CLIENT_END +}; +I2C_CLIENT_INSMOD; /* defines addr_data */ +#endif enum rtc_type { rtc_undef = 0, @@ -506,14 +514,14 @@ static int rs5c372_probe(struct i2c_clie err = -ENODEV; goto exit; } - - if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) { + rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL); + if (!rs5c372) { err = -ENOMEM; goto exit; } /* we read registers 0x0f then 0x00-0x0f; skip the first one */ - rs5c372->regs=&rs5c372->buf[1]; + rs5c372->regs = &rs5c372->buf[1]; rs5c372->client = client; i2c_set_clientdata(client, rs5c372); @@ -605,7 +613,7 @@ static int rs5c372_probe(struct i2c_clie case rtc_rv5c386: s = "rv5c386"; break; case rtc_rv5c387a: s = "rv5c387a"; break; default: s = "chip"; break; - }; s;}), + }; s; }), rs5c372->time24 ? "24hr" : "am/pm" ); @@ -645,12 +653,61 @@ static int rs5c372_remove(struct i2c_cli return 0; } +#ifdef CONFIG_M547X_8X +static int rv5c387_probe(struct i2c_adapter *adapter, int addr, int kind) +{ + int rc = 0; + struct i2c_client *new_client = NULL; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + rc = -ENODEV; + printk(KERN_DEBUG "%s i2c_check_functionality\n", __FUNCTION__); + goto failout; + } + + new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (new_client == NULL) { + rc = -ENOMEM; + printk(KERN_DEBUG "%s kzalloc new_client\n", __FUNCTION__); + goto failout; + } + + new_client->addr = addr; + new_client->adapter = adapter; + new_client->driver = &rs5c372_driver; + new_client->flags = 0; + strcpy(new_client->name, DRV_NAME); + + rc = i2c_attach_client(new_client); + if (rc < 0) { + printk(KERN_DEBUG "%s i2c_attach_client\n", __FUNCTION__); + goto failout; + } + + rs5c372_probe(new_client); + return 0; +failout: + kfree(new_client); + return rc; +} + +static int +rv5c387_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_probe(adapter, &addr_data, rv5c387_probe); +} +#endif + static struct i2c_driver rs5c372_driver = { .driver = { .name = "rtc-rs5c372", }, +#ifdef CONFIG_M547X_8X + .attach_adapter = &rv5c387_attach_adapter, +#else .probe = rs5c372_probe, .remove = rs5c372_remove, +#endif }; static __init int rs5c372_init(void) --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -979,6 +979,12 @@ config SERIAL_COLDFIRE This driver supports the built-in serial ports of the Motorola ColdFire family of CPUs. +config SERIAL_COLDFIRE_IRDA + bool "ColdFire IRDA support" + depends on SERIAL_COLDFIRE + help + This driver supports IRDA on the Motorola ColdFire. + config SERIAL_MCF bool "Coldfire serial support (new style driver)" depends on COLDFIRE --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -45,7 +45,14 @@ #include #include #include +#if defined(CONFIG_M547X_8X) +#include +#include +#include +#endif +#ifdef CONFIG_NETtel #include +#endif #include #include "mcfserial.h" @@ -61,7 +68,8 @@ struct timer_list mcfrs_timer_struct; #define CONSOLE_BAUD_RATE 38400 #define DEFAULT_CBAUD B38400 #elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \ - defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO) + defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO) || \ + defined(CONFIG_M5445X) || defined(CONFIG_M547X_8X) #define CONSOLE_BAUD_RATE 115200 #define DEFAULT_CBAUD B115200 #elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \ @@ -94,12 +102,17 @@ static struct tty_driver *mcfrs_serial_d #undef SERIAL_DEBUG_FLOW #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) + defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M5445X) || \ + defined(CONFIG_M547X_8X) #define IRQBASE (MCFINT_VECBASE+MCFINT_UART0) #else #define IRQBASE 73 #endif +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA +#define SERIAL_IRDA_LINE (2) +#endif + /* * Configuration table, UARTs to look for at startup. */ @@ -114,7 +127,11 @@ static struct mcf_serial mcfrs_table[] = { /* ttyS1 */ .magic = 0, .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2), +#if defined(CONFIG_M547X_8X) + .irq = IRQBASE-1, +#else .irq = IRQBASE+1, +#endif .flags = ASYNC_BOOT_AUTOCONF, }, #endif @@ -122,7 +139,11 @@ static struct mcf_serial mcfrs_table[] = { /* ttyS2 */ .magic = 0, .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3), +#if defined(CONFIG_M547X_8X) + .irq = IRQBASE-2, +#else .irq = IRQBASE+2, +#endif .flags = ASYNC_BOOT_AUTOCONF, }, #endif @@ -130,7 +151,11 @@ static struct mcf_serial mcfrs_table[] = { /* ttyS3 */ .magic = 0, .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4), +#if defined(CONFIG_M547X_8X) + .irq = IRQBASE-3, +#else .irq = IRQBASE+3, +#endif .flags = ASYNC_BOOT_AUTOCONF, }, #endif @@ -372,6 +397,9 @@ static inline void receive_chars(struct static inline void transmit_chars(struct mcf_serial *info) { volatile unsigned char *uartp; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + int i; +#endif uartp = info->addr; @@ -383,13 +411,36 @@ static inline void transmit_chars(struct } if ((info->xmit_cnt <= 0) || info->tty->stopped) { +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (info->line == SERIAL_IRDA_LINE) { + /* Enable receiver for IRDA */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; + /* reset RX */ + uartp[MCFUART_UCR] = MCFUART_UCR_TXENABLE | MCFUART_UCR_RXENABLE; + } +#endif info->imr &= ~MCFUART_UIR_TXREADY; uartp[MCFUART_UIMR] = info->imr; return; } while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) { +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (info->line == SERIAL_IRDA_LINE) { + while (!(uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)); + i = 0; + /* delay for settle */ +#if defined(CONFIG_M548X) + udelay(1); +#elif defined(CONFIG_M547X) + udelay(2); +#else + while (i++ < 25000) udelay(1); +#endif + } +#endif uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->stats.tx++; if (--info->xmit_cnt <= 0) @@ -409,7 +460,12 @@ irqreturn_t mcfrs_interrupt(int irq, voi struct mcf_serial *info; unsigned char isr; +/* JKM -- revisit! IRQ compute */ +#if defined(CONFIG_M547X_8X) + info = &mcfrs_table[(IRQBASE - irq)]; +#else info = &mcfrs_table[(irq - IRQBASE)]; +#endif isr = info->addr[MCFUART_UISR] & info->imr; if (isr & MCFUART_UIR_RXREADY) @@ -541,6 +597,28 @@ static int startup(struct mcf_serial * i */ mcfrs_change_speed(info); +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (info->line == SERIAL_IRDA_LINE) { + /* Put PSC in IrDA mode */ + MCF_PSC_SICR(info->line) = MCF_PSC_SICR_SIM_SIR; + + /* Set pulse width to 1.6 uS */ + MCF_PSC_IRSDR(info->line) = (uint8_t) + (16 * (CONFIG_MCFCLK / 10000000)); + MCF_PSC_IRCR1(info->line) = MCF_PSC_IRCR1_SPUL; + MCF_PSC_IRCR2(info->line) = 0; + + /* Enable RTS to send */ + MCF_PSC_OPSET(info->line) = MCF_PSC_OPSET_RTS; + + /* Setup FIFO Alarms */ + MCF_PSC_RFAR(info->line) = MCF_PSC_RFAR_ALARM(248); + MCF_PSC_TFAR(info->line) = MCF_PSC_TFAR_ALARM(248); + + MCF_PSC_RFCR(info->line) = MCF_PSC_RFCR_FRMEN | MCF_PSC_RFCR_GR(4); + MCF_PSC_TFCR(info->line) = MCF_PSC_TFCR_FRMEN | MCF_PSC_RFCR_GR(4); + } +#endif /* * Lastly enable the UART transmitter and receiver, and * interrupt enables. @@ -562,10 +640,20 @@ static void shutdown(struct mcf_serial * { volatile unsigned char *uartp; unsigned long flags; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + unsigned long delay_counter = 0; +#endif if (!(info->flags & ASYNC_INITIALIZED)) return; - +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + uartp = (volatile unsigned char *) info->addr; + while (!(uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)) { + if(delay_counter++ > 25000) + break; + udelay(10); + } +#endif #ifdef SERIAL_DEBUG_OPEN printk("Shutting down serial port %d (irq %d)....\n", info->line, info->irq); @@ -794,10 +882,19 @@ static int mcfrs_write(struct tty_struct local_irq_disable(); uartp = info->addr; + +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (info->line == SERIAL_IRDA_LINE) { + /* Disable IRDA receiver*/ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ + + uartp[MCFUART_UCR] = MCFUART_UCR_TXENABLE; + } +#endif info->imr |= MCFUART_UIR_TXREADY; uartp[MCFUART_UIMR] = info->imr; local_irq_restore(flags); - return total; } @@ -858,9 +955,21 @@ static void mcfrs_throttle(struct tty_st if (serial_paranoia_check(info, tty->name, "mcfrs_throttle")) return; - +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (I_IXOFF(tty)) { + /* Force STOP_CHAR (xoff) out */ + volatile unsigned char *uartp; + unsigned long flags; + uartp = (volatile unsigned char *) info->addr; + local_irq_save(flags); + info->imr |= MCFUART_UIR_TXREADY; + uartp[MCFUART_UIMR] = info->imr; + local_irq_restore(flags); + } +#else if (I_IXOFF(tty)) info->x_char = STOP_CHAR(tty); +#endif /* Turn off RTS line (do this atomic) */ } @@ -881,8 +990,22 @@ static void mcfrs_unthrottle(struct tty_ if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + else { + /* Force START_CHAR (xon) out */ + volatile unsigned char *uartp; + unsigned long flags; + info->x_char = START_CHAR(tty); + uartp = (volatile unsigned char *) info->addr; + local_irq_save(flags); + info->imr |= MCFUART_UIR_TXREADY; + uartp[MCFUART_UIMR] = info->imr; + local_irq_restore(flags); + } +#else else info->x_char = START_CHAR(tty); +#endif } /* Assert RTS line (do this atomic) */ @@ -1130,12 +1253,17 @@ static int mcfrs_ioctl(struct tty_struct static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + int i = 0; /* hush GCC */ +#endif if (tty->termios->c_cflag == old_termios->c_cflag) return; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + while (i++ < 35000) udelay(1); +#endif mcfrs_change_speed(info); - if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; @@ -1604,6 +1732,36 @@ static void mcfrs_irqinit(struct mcf_ser /* GPIOs also must be initalized, depends on board */ break; } +#elif defined(CONFIG_M5445X) + volatile unsigned char *uartp; + uartp = info->addr; + switch (info->line) { + case 0: + MCF_GPIO_PAR_UART |= 0x000F; + break; + case 1: + MCF_GPIO_PAR_UART |= 0x0FF0; + break; + case 2: + /* GPIOs also must be initalized, depends on board */ + break; + } +#elif defined(CONFIG_M547X_8X) + volatile unsigned char *uartp; + uartp = (volatile unsigned char *)info->addr; + + if (info->line > 3) { + printk("SERIAL: don't know how to handle UART %d interrupt?\n", + info->line); + return; + } + + /* Set GPIO port register to enable PSC(port) signals */ + MCF_PAR_PSCn(info->line) = (0 + | MCF_PAR_PSC_TXD + | MCF_PAR_PSC_RXD); + + MCF_ICR(info->irq - 64) = ILP_PSCn(info->line); #else volatile unsigned char *icrp, *uartp; @@ -1966,7 +2124,9 @@ struct console mcfrs_console = { static int __init mcfrs_console_init(void) { +#if !(defined(CONFIG_M5445X) || defined(CONFIG_M547X_8X)) register_console(&mcfrs_console); +#endif return 0; } --- /dev/null +++ b/drivers/spi/coldfire_edma.c @@ -0,0 +1,446 @@ +/* + * + * coldfire_edma.c - eDMA driver for Coldfire MCF5445x + * + * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com + * + * Copyright Freescale Semiconductor, Inc. 2007 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_M5445X +#include +#include +#endif /* CONFIG_M5445X */ +#include + +/* + * Callback handler data for each TCD + */ +struct edma_isr_record { + edma_irq_handler irq_handler; /* interrupt handler */ + edma_error_handler error_handler; /* error interrupt handler */ + void *arg; /* argument to pass back */ + int allocated; /* busy flag */ + spinlock_t *lock; /* spin lock (optional) */ + const char *device_id; /* dev id string, used in procfs */ +}; + +/* + * Device structure + */ +struct coldfire_edma_dev { + struct cdev cdev; /* character device */ + struct edma_isr_record dma_interrupt_handlers[EDMA_CHANNELS]; +}; + +/* allocated major device number */ +static int coldfire_dma_major; + +/* device driver structure */ +static struct coldfire_edma_dev *devp = NULL; + +/* device driver file operations */ +struct file_operations coldfire_edma_fops = { + .owner = THIS_MODULE, +}; + +/** + * dmaisr - eDMA channel interrupt handler + * @irq: interrupt number + * @dev_id: argument + */ +static int dmaisr(int irq, void *dev_id) +{ + int channel = irq - EDMA_INT_CONTROLLER_BASE - EDMA_INT_CHANNEL_BASE; + int result = IRQ_HANDLED; + + if ((devp != NULL) && + (devp->dma_interrupt_handlers[channel].irq_handler)) { + /* call user irq handler */ + if (devp->dma_interrupt_handlers[channel].lock) + spin_lock(devp->dma_interrupt_handlers[channel].lock); + + result = devp->dma_interrupt_handlers[channel].irq_handler( + channel, devp->dma_interrupt_handlers[channel].arg); + + if (devp->dma_interrupt_handlers[channel].lock) + spin_unlock(devp->dma_interrupt_handlers[channel].lock); + } else { + /* no irq handler so just ack it */ + confirm_edma_interrupt_handled(channel); + printk(EDMA_DRIVER_NAME ": No handler for DMA channel %d\n", + channel); + } + + return result; +} + +/** + * dma_error_isr - eDMA error interrupt handler + * @irq: interrupt number + * @dev_id: argument + */ +static int dma_error_isr(int irq, void* dev_id) +{ + u16 err; + int i; + + err = MCF_EDMA_ERR; + for (i=0; idma_interrupt_handlers[i].error_handler) + devp->dma_interrupt_handlers[i].error_handler(i, devp->dma_interrupt_handlers[i].arg); + else + printk(KERN_WARNING EDMA_DRIVER_NAME ": DMA error on channel %d\n", i); + } + } + + MCF_EDMA_CERR = MCF_EDMA_CERR_CAER; + return IRQ_HANDLED; +} + +/** + * set_edma_params - Set transfer control descriptor (TCD) + * @channel: channel number + * @source: source address + * @dest: destination address + * @attr: attributes + * @soff: source offset + * @nbytes: number of bytes to be transfered in minor loop + * @slast: last source address adjustment + * @citer: major loop count + * @biter: beginning minor loop count + * @doff: destination offset + * @dlast_sga: last destination address adjustment + * @major_int: generate interrupt after each major loop + * @disable_req: disable DMA request after major loop + */ +void set_edma_params(int channel, u32 source, u32 dest, + u32 attr, u32 soff, u32 nbytes, u32 slast, + u32 citer, u32 biter, u32 doff, u32 dlast_sga, + int major_int, int disable_req) +{ + + if (channel<0 || channel>EDMA_CHANNELS) + return; + + MCF_EDMA_TCD_SADDR(channel) = source; + MCF_EDMA_TCD_DADDR(channel) = dest; + MCF_EDMA_TCD_ATTR(channel) = attr; + MCF_EDMA_TCD_SOFF(channel) = MCF_EDMA_TCD_SOFF_SOFF(soff); + MCF_EDMA_TCD_NBYTES(channel) = MCF_EDMA_TCD_NBYTES_NBYTES(nbytes); + MCF_EDMA_TCD_SLAST(channel) = MCF_EDMA_TCD_SLAST_SLAST(slast); + MCF_EDMA_TCD_CITER(channel) = MCF_EDMA_TCD_CITER_CITER(citer); + MCF_EDMA_TCD_BITER(channel)=MCF_EDMA_TCD_BITER_BITER(biter); + MCF_EDMA_TCD_DOFF(channel) = MCF_EDMA_TCD_DOFF_DOFF(doff); + MCF_EDMA_TCD_DLAST_SGA(channel) = MCF_EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga); + + /* interrupt at the end of major loop */ + if (major_int) + MCF_EDMA_TCD_CSR(channel) |= MCF_EDMA_TCD_CSR_INT_MAJOR; + else + MCF_EDMA_TCD_CSR(channel) &= ~MCF_EDMA_TCD_CSR_INT_MAJOR; + + /* disable request at the end of major loop of transfer or not*/ + if (disable_req) + MCF_EDMA_TCD_CSR(channel) |= MCF_EDMA_TCD_CSR_D_REQ; + else + MCF_EDMA_TCD_CSR(channel) &= ~MCF_EDMA_TCD_CSR_D_REQ; +} +EXPORT_SYMBOL(set_edma_params); + +/** + * init_edma - Initialize the eDMA controller + */ +void init_edma(void) +{ + MCF_EDMA_CR = 0; +} +EXPORT_SYMBOL(init_edma); + +/** + * request_edma_channel - Request an eDMA channel + * @channel: channel number + * @handler: dma handler + * @error_handler: dma error handler + * @arg: argument to pass back + * @lock: optional spinlock to hold over interrupt + * @device_id: device id + * + * Returns 0 if success or a negative value if failure + */ +int request_edma_channel(int channel, + edma_irq_handler handler, + edma_error_handler error_handler, + void *arg, + spinlock_t *lock, + const char *device_id ) +{ + if (devp!=NULL && channel>=0 && channel<=EDMA_CHANNELS) { + if (devp->dma_interrupt_handlers[channel].allocated) + return -EBUSY; + + devp->dma_interrupt_handlers[channel].allocated = 1; + devp->dma_interrupt_handlers[channel].irq_handler = handler; + devp->dma_interrupt_handlers[channel].error_handler = error_handler; + devp->dma_interrupt_handlers[channel].arg = arg; + devp->dma_interrupt_handlers[channel].lock = lock; + devp->dma_interrupt_handlers[channel].device_id = device_id; + return 0; + } + return -EINVAL; +} +EXPORT_SYMBOL(request_edma_channel); + +/** + * set_edma_callback - Update the channel callback/arg + * @channel: channel number + * @handler: dma handler + * @error_handler: dma error handler + * @arg: argument to pass back + * + * Returns 0 if success or a negative value if failure + */ +int set_edma_callback(int channel, + edma_irq_handler handler, + edma_error_handler error_handler, + void *arg ) +{ + if (devp!=NULL && channel>=0 && channel<=EDMA_CHANNELS && + devp->dma_interrupt_handlers[channel].allocated) { + devp->dma_interrupt_handlers[channel].irq_handler = handler; + devp->dma_interrupt_handlers[channel].error_handler = error_handler; + devp->dma_interrupt_handlers[channel].arg = arg; + return 0; + } + return -EINVAL; +} +EXPORT_SYMBOL(set_edma_callback); + +/** + * free_edma_channel - Free the edma channel + * @channel: channel number + * @arg: argument created with + * + * Returns 0 if success or a negative value if failure + */ +int free_edma_channel(int channel, void *arg) +{ + if (devp!=NULL && channel>=0 && channel<=EDMA_CHANNELS) { + if (devp->dma_interrupt_handlers[channel].allocated) { +#if 0 + if (devp->dma_interrupt_handlers[channel].arg != arg) + return -EBUSY; +#endif + + devp->dma_interrupt_handlers[channel].allocated = 0; + devp->dma_interrupt_handlers[channel].arg = NULL; + devp->dma_interrupt_handlers[channel].irq_handler = NULL; + devp->dma_interrupt_handlers[channel].error_handler = NULL; + devp->dma_interrupt_handlers[channel].lock = NULL; + } + return 0; + } + return -EINVAL; +} +EXPORT_SYMBOL(free_edma_channel); + +/** + * coldfire_edma_cleanup - cleanup driver allocated resources + */ +static void coldfire_edma_cleanup(void) +{ + dev_t devno; + int i; + + /* free interrupts/memory */ + if (devp) { + for (i=0; icdev); + kfree(devp); + } + + /* unregister character device */ + devno = MKDEV(coldfire_dma_major, 0); + unregister_chrdev_region(devno, 1); +} + +#ifdef CONFIG_PROC_FS +/* + * proc file system support + */ + +#define FREE_CHANNEL "free" +#define DEVICE_UNKNOWN "device unknown" + +/** + * proc_edma_show - print out proc info + * @m: seq_file + * @v: + */ +static int proc_edma_show(struct seq_file *m, void *v) +{ + int i; + + if (devp == NULL) + return 0; + + for (i = 0 ; i < EDMA_CHANNELS ; i++) { + if (devp->dma_interrupt_handlers[i].allocated) { + if (devp->dma_interrupt_handlers[i].device_id) + seq_printf(m, "%2d: %s\n", i, devp->dma_interrupt_handlers[i].device_id); + else + seq_printf(m, "%2d: %s\n", i, DEVICE_UNKNOWN); + } else + seq_printf(m, "%2d: %s\n", i, FREE_CHANNEL); + } + return 0; +} + +/** + * proc_edma_open - open the proc file + * @inode: inode ptr + * @file: file ptr + */ +static int proc_edma_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_edma_show, NULL); +} + +static const struct file_operations proc_edma_operations = { + .open = proc_edma_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** + * proc_edma_init - initialize proc filesystem + */ +static int __init proc_edma_init(void) +{ + struct proc_dir_entry *e; + + e = create_proc_entry("edma", 0, NULL); + if (e) + e->proc_fops = &proc_edma_operations; + + return 0; +} + +#endif + +/** + * coldfire_edma_init - eDMA module init + */ +static int __init coldfire_edma_init(void) +{ + dev_t dev; + int result; + int i; + + /* allocate free major number */ + result = alloc_chrdev_region(&dev, DMA_DEV_MINOR, 1, EDMA_DRIVER_NAME); + if (result < 0) { + printk(KERN_WARNING EDMA_DRIVER_NAME": can't get major %d\n", + result); + return result; + } + coldfire_dma_major = MAJOR(dev); + + /* allocate device driver structure */ + devp = kmalloc(sizeof(struct coldfire_edma_dev), GFP_KERNEL); + if (!devp) { + result = -ENOMEM; + goto fail; + } + + /* init handlers (no handlers for beginning) */ + for (i = 0; i < EDMA_CHANNELS; i++) { + devp->dma_interrupt_handlers[i].irq_handler = NULL; + devp->dma_interrupt_handlers[i].error_handler = NULL; + devp->dma_interrupt_handlers[i].arg = NULL; + devp->dma_interrupt_handlers[i].allocated = 0; + devp->dma_interrupt_handlers[i].lock = NULL; + devp->dma_interrupt_handlers[i].device_id = NULL; + } + + /* register char device */ + cdev_init(&devp->cdev, &coldfire_edma_fops); + devp->cdev.owner = THIS_MODULE; + devp->cdev.ops = &coldfire_edma_fops; + result = cdev_add(&devp->cdev, dev, 1); + if (result) { + printk(KERN_NOTICE EDMA_DRIVER_NAME + ": Error %d adding coldfire-dma device\n", result); + result = -ENODEV; + goto fail; + } + + /* request/enable irq for each eDMA channel */ + for (i = 0; i < EDMA_CHANNELS;i++) { + result = request_irq(EDMA_INT_BASE + i, + dmaisr, IRQF_DISABLED, + EDMA_DRIVER_NAME, devp); + if (result) { + printk(KERN_WARNING EDMA_DRIVER_NAME + ": Cannot request irq %d\n", + (EDMA_INT_BASE + EDMA_INT_ERR+i)); + result = -EBUSY; + goto fail; + } + } + + /* request error interrupt */ + result = request_irq(EDMA_INT_BASE + EDMA_INT_ERR, + dma_error_isr, IRQF_DISABLED, + EDMA_DRIVER_NAME, devp); + if (result) { + printk(KERN_WARNING EDMA_DRIVER_NAME + ": Cannot request irq %d\n", + (EDMA_INT_BASE + EDMA_INT_ERR)); + result = -EBUSY; + goto fail; + } + +#ifdef CONFIG_PROC_FS + proc_edma_init(); +#endif + + printk(EDMA_DRIVER_NAME ": initialized successfully\n"); + return 0; +fail: + coldfire_edma_cleanup(); + return result; +} + +/** + * coldfire_edma_exit - eDMA module exit + */ +static void __exit coldfire_edma_exit(void) +{ + coldfire_edma_cleanup(); +} + +module_init(coldfire_edma_init); +module_exit(coldfire_edma_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("eDMA library for Coldfire M5445x"); --- /dev/null +++ b/drivers/spi/dspi_mcf.c @@ -0,0 +1,1217 @@ +/* + * dspi_mcf.c - DSPI controller for ColdFire processors + * + * + * Matt Waddel Matt.Waddel@freescale.com + * Copyright Freescale Semiconductor, Inc. 2008 + * + * M547x/M548x changes by Kurt Mahan kmahan@freescale.com + * Copyright Freescale Semiconductor, Inc. 2008 + * + * Based on spi_coldfire.c done by: + * Andrey Butok + * Yaroslav Vinogradov + * Copyright Freescale Semiconductor, Inc. 2006-2007 + * Mike Lavender (mike@steroidmicros) + * (C) Copyright 2005, Intec Automation, + * + * 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 + * + *************************************************************************** + * Changes: + * v0.002 M547x/M548x support. + * v0.001 Initial version. Coldfire DSPI master driver. + ****************************************************************************/ + +/* + * Includes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DSPI_COLDFIRE_DEBUG + +#ifdef DSPI_COLDFIRE_DEBUG +#define DBG(fmt, args...) \ + printk(KERN_INFO "[%s] " fmt , __FUNCTION__, ## args) +#else +#define DBG(fmt, args...) do {} while (0) +#endif + +#if defined(CONFIG_M54455) +#include +#if defined(CONFIG_SPI_COLDFIRE_DSPI_EDMA) + #include +#endif +#endif + +#if defined(CONFIG_M547X_8X) +#include +#include +#endif + +#if defined(CONFIG_SPI_COLDFIRE_DSPI_EDMA) +#include +#define SPI_DSPI_EDMA +#define EDMA_BUFSIZE_KMALLOC (DSPI_FIFO_SIZE*4) +#define DSPI_DMA_RX_TCD MCF_EDMA_CHAN_DSPI_RX +#define DSPI_DMA_TX_TCD MCF_EDMA_CHAN_DSPI_TX +#endif + +#define DSPI_BITS MCF_DSPI_DCTAR_FMSZ(0xF) +#define DSPI_BITS_16 MCF_DSPI_DCTAR_FMSZ(0xF) +#define DSPI_BITS_8 MCF_DSPI_DCTAR_FMSZ(0x7) +#define DSPI_FIFO_SIZE 16 + +#define DRIVER_NAME "Coldfire DSPI" + +/****************************************************************************/ + +/* + * Local constants and macros + */ + +#define START_STATE ((void *)0) +#define RUNNING_STATE ((void *)1) +#define DONE_STATE ((void *)2) +#define ERROR_STATE ((void *)-1) + +#define QUEUE_RUNNING 0 +#define QUEUE_STOPPED 1 + +/****************************************************************************/ + +/* + * Local Data Structures + */ + +struct DSPI_MCR { + unsigned master:1; + unsigned cont_scke:1; + unsigned dconf:2; + unsigned frz:1; + unsigned mtfe:1; + unsigned pcsse:1; + unsigned rooe:1; + unsigned pcsis:8; + unsigned reserved15:1; + unsigned mdis:1; + unsigned dis_tx:1; + unsigned dis_rxf:1; + unsigned clr_tx:1; + unsigned clr_rxf:1; + unsigned smpl_pt:2; + unsigned reserved71:7; + unsigned halt:1; +}; + +struct DSPI_CTAR { + unsigned dbr:1; + unsigned fmsz:4; + unsigned cpol:1; + unsigned cpha:1; + unsigned lsbfe:1; + unsigned pcssck:2; + unsigned pasc:2; + unsigned pdt:2; + unsigned pbr:2; + unsigned cssck:4; + unsigned asc:4; + unsigned dt:4; + unsigned br:4; +}; + +struct chip_data { + /* dspi data */ + union { + u32 mcr_val; + struct DSPI_MCR mcr; + }; + union { + u32 ctar_val; + struct DSPI_CTAR ctar; + }; + u16 void_write_data; +}; + + +struct driver_data { + /* Driver model hookup */ + struct platform_device *pdev; + + /* SPI framework hookup */ + struct spi_master *master; + + /* Driver message queue */ + struct workqueue_struct *workqueue; + struct work_struct pump_messages; + spinlock_t lock; /* lock */ + struct list_head queue; + int busy; + int run; + + /* Message Transfer pump */ + struct tasklet_struct pump_transfers; + + /* Current message transfer state info */ + struct spi_message *cur_msg; + struct spi_transfer *cur_transfer; + struct chip_data *cur_chip; + size_t len; + void *tx; + void *tx_end; + void *rx; + void *rx_end; + char flags; +#define TRAN_STATE_RX_VOID 0x01 +#define TRAN_STATE_TX_VOID 0x02 +#define TRAN_STATE_WORD_ODD_NUM 0x04 + u8 cs; + u16 void_write_data; + unsigned cs_change:1; + + u32 trans_cnt; + u32 wce_cnt; + u32 abrt_cnt; + u32 *mcr; /* DSPI MCR register */ + u32 *ctar; /* DSPI CTAR register */ + u32 *dspi_dtfr; /* DSPI DTFR register */ + u32 *dspi_drfr; /* DSPI DRFR register */ + u32 *dspi_rser; /* DSPI RSER register */ + u32 *dspi_sr; /* DSPI status register */ + +#if defined(SPI_DSPI_EDMA) + void *edma_tx_buf; + void *edma_rx_buf; +#endif + +#if defined(CONFIG_M532x) || defined(CONFIG_M537x) + u16 *par; /* Pin assignment register */ +#else + u8 *par; /* Pin assignment register */ +#endif + u8 *int_icr; /* Interrupt level and priority register */ + u32 *int_mr; /* Interrupt mask register */ + void (*cs_control)(u8 cs, u8 command); +}; + +#define DSPI_CS(cs) ((1<<(cs))<<16) + +/****************************************************************************/ + +/* + * SPI local functions + */ + +static void *next_transfer(struct driver_data *drv_data) +{ + struct spi_message *msg = drv_data->cur_msg; + struct spi_transfer *trans = drv_data->cur_transfer; + + DBG("\n"); + /* Move to next transfer */ + if (trans->transfer_list.next != &msg->transfers) { + drv_data->cur_transfer = list_entry(trans->transfer_list.next, + struct spi_transfer, + transfer_list); + + if (drv_data->cur_transfer->transfer_list.next + == &msg->transfers) /* last transfer */ + drv_data->cur_transfer->cs_change = 1; + + return RUNNING_STATE; + } else + return DONE_STATE; +} + + +static inline int is_word_transfer(struct driver_data *drv_data) +{ + return ((*(drv_data->ctar+drv_data->cs) & DSPI_BITS_16) == + DSPI_BITS_8) ? 0 : 1; +} + +static inline void set_8bit_transfer_mode(struct driver_data *drv_data) +{ + DBG("\n"); + *(drv_data->ctar+drv_data->cs) = + (*(drv_data->ctar + drv_data->cs) & ~DSPI_BITS) | DSPI_BITS_8; +} + +static inline void set_16bit_transfer_mode(struct driver_data *drv_data) +{ + DBG("\n"); + *(drv_data->ctar+drv_data->cs) = + (*(drv_data->ctar + drv_data->cs) & ~DSPI_BITS) | DSPI_BITS_16; +} + +static unsigned char hz_to_spi_baud(int pbr, int dbr, int speed_hz) +{ + int pbr_tbl[4] = {2, 3, 5, 7}; /* Valid baud rate pre-scaler values */ + int brs[16] = { 2, 4, 6, 8, + 16, 32, 64, 128, + 256, 512, 1024, 2048, + 4096, 8192, 16384, 32768 }; + int temp, index = 0; + + if ((pbr < 0) || (pbr > 3) || + (dbr < 0) || (dbr > 1)) + return 15; /* table indexes out of range, go slow */ + + temp = ((((MCF_CLK / 2) / pbr_tbl[pbr]) * (1 + dbr)) / speed_hz); + + while (temp >= brs[index]) + if (index++ >= 15) + break; + + DBG("baud rate scaler = 0x%x - %d\n", index, brs[index]); + return(index); +} + +static int write(struct driver_data *drv_data) +{ + int tx_count = 0; + int tx_word = is_word_transfer(drv_data); + u16 d16; + u8 d8; + u32 dspi_pushr = 0; + int first = 1; +#if defined(SPI_DSPI_EDMA) + u32 *edma_wr = (u32 *)(drv_data->edma_tx_buf); +#endif + + /* If we are in word mode, but only have a single byte to transfer + * then switch to byte mode temporarily. Will switch back at the + * end of the transfer. */ + if (tx_word && ((drv_data->tx_end - drv_data->tx) == 1)) { + drv_data->flags |= TRAN_STATE_WORD_ODD_NUM; + set_8bit_transfer_mode(drv_data); + tx_word = 0; + } + + while ((drv_data->tx < drv_data->tx_end) && (tx_count < DSPI_FIFO_SIZE)) { +// DBG("while\n"); + if (tx_word) { + if ((drv_data->tx_end - drv_data->tx) == 1) + break; + + if (!(drv_data->flags & TRAN_STATE_TX_VOID)) + d16 = *(u16 *)drv_data->tx; + else + d16 = drv_data->void_write_data; + + dspi_pushr = MCF_DSPI_DTFR_TXDATA(d16) | + DSPI_CS(drv_data->cs) | + MCF_DSPI_DTFR_CTAS(drv_data->cs) | + MCF_DSPI_DTFR_CONT; + + drv_data->tx += 2; + } else { + if (!(drv_data->flags & TRAN_STATE_TX_VOID)) + d8 = *(u8 *)drv_data->tx; + else + d8 = *(u8 *)&drv_data->void_write_data; + + dspi_pushr = MCF_DSPI_DTFR_TXDATA(d8) | + DSPI_CS(drv_data->cs) | + MCF_DSPI_DTFR_CTAS(drv_data->cs) | + MCF_DSPI_DTFR_CONT; + + drv_data->tx++; + } + + if (drv_data->tx == drv_data->tx_end + || tx_count == DSPI_FIFO_SIZE-1) { + /* last transfer in the queue */ + dspi_pushr |= MCF_DSPI_DTFR_EOQ; + if ((drv_data->cs_change) + && (drv_data->tx == drv_data->tx_end)) + dspi_pushr &= ~MCF_DSPI_DTFR_CONT; +#ifdef CONFIG_M547X_8X + /* EOQ gets missed if we don't delay */ + udelay(100); +#endif + } else if (tx_word && ((drv_data->tx_end - drv_data->tx) == 1)) + dspi_pushr |= MCF_DSPI_DTFR_EOQ; + + if (first) { + first = 0; + dspi_pushr |= MCF_DSPI_DTFR_CTCNT; /* clear counter */ + } +#if defined(SPI_DSPI_EDMA) + *edma_wr = dspi_pushr; + edma_wr++; +#else + *drv_data->dspi_dtfr = dspi_pushr; +#endif + tx_count++; + } + +#if defined(SPI_DSPI_EDMA) + if (tx_count > 0) { + + mcf_edma_set_tcd_params(DSPI_DMA_TX_TCD, + virt_to_phys(drv_data->edma_tx_buf), + (u32)drv_data->dspi_dtfr, + MCF_EDMA_TCD_ATTR_SSIZE_32BIT + | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, + 4, /* soff */ + 4 * tx_count, /* nbytes */ + 0, /* slast */ + 1, /* citer */ + 1, /* biter */ + 0, /* doff */ + 0, /* dlastsga */ + 0, /* major_int */ + 1); /* disable_req */ + + mcf_edma_set_tcd_params(DSPI_DMA_RX_TCD, + (u32)drv_data->dspi_drfr, + virt_to_phys(drv_data->edma_rx_buf), + MCF_EDMA_TCD_ATTR_SSIZE_32BIT + | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, + 0, /* soff */ + 4 * tx_count, /* nbytes */ + 0, /* slast */ + 1, /* citer */ + 1, /* biter */ + 4, /* doff */ + 0, /* dlastsga */ + 0, /* major_int */ + 1); /* disable_req */ + + mcf_edma_start_transfer(DSPI_DMA_TX_TCD); + } +#endif + return (tx_count * (tx_word + 1)); +} + +static int read(struct driver_data *drv_data) +{ + int rx_count = 0; + int rx_word = is_word_transfer(drv_data); + u16 d; +#if defined(SPI_DSPI_EDMA) + u32 *rx_edma = (u32 *) drv_data->edma_rx_buf; + + /* receive SPI data */ + mcf_edma_start_transfer(DSPI_DMA_RX_TCD); +#endif + while ((drv_data->rx < drv_data->rx_end) + && (rx_count < DSPI_FIFO_SIZE)) { + + if (rx_word) { + if ((drv_data->rx_end - drv_data->rx) == 1) + break; +#if defined(SPI_DSPI_EDMA) + d = MCF_DSPI_DRFR_RXDATA(*rx_edma); + rx_edma++; +#else + d = MCF_DSPI_DRFR_RXDATA(*drv_data->dspi_drfr); +#endif + if (!(drv_data->flags & TRAN_STATE_RX_VOID)) + *(u16 *)drv_data->rx = d; + drv_data->rx += 2; + + } else { +#if defined(SPI_DSPI_EDMA) + d = MCF_DSPI_DRFR_RXDATA(*rx_edma); + rx_edma++; +#else + d = MCF_DSPI_DRFR_RXDATA(*drv_data->dspi_drfr); +#endif + if (!(drv_data->flags & TRAN_STATE_RX_VOID)) + *(u8 *)drv_data->rx = d; + drv_data->rx++; + } + rx_count++; + DBG("rxd=0x%x\n", d); + } + return rx_count; +} + + +static inline void dspi_setup_chip(struct driver_data *drv_data) +{ + struct chip_data *chip = drv_data->cur_chip; + + DBG("\n"); + *drv_data->mcr = chip->mcr_val; + *(drv_data->ctar+drv_data->cs) = chip->ctar_val; + *drv_data->dspi_rser = MCF_DSPI_DRSER_EOQFE; +} + +#if defined(SPI_DSPI_EDMA) +static int edma_tx_handler(int channel, void *dev) +{ + DBG("\n"); + if (channel == DSPI_DMA_TX_TCD) + mcf_edma_stop_transfer(DSPI_DMA_TX_TCD); + return IRQ_HANDLED; +} + +static int edma_rx_handler(int channel, void *dev) +{ + DBG("\n"); + if (channel == DSPI_DMA_RX_TCD) + mcf_edma_stop_transfer(DSPI_DMA_RX_TCD); + return IRQ_HANDLED; +} +#endif + +static irqreturn_t dspi_interrupt(int irq, void *dev_id) +{ + struct driver_data *drv_data = (struct driver_data *)dev_id; + struct spi_message *msg = drv_data->cur_msg; + + /* Clear all flags immediately */ + *drv_data->dspi_sr = MCF_DSPI_DSR_EOQF; + + if (!drv_data->cur_msg || !drv_data->cur_msg->state) { +#if !defined(SPI_DSPI_EDMA) + u32 irq_status = *drv_data->dspi_sr; + /* if eDMA is used it happens some time (at least once)*/ + printk(KERN_ERR "Bad message or transfer state handler. \ + IRQ status = %x\n", irq_status); +#endif + return IRQ_NONE; + } + + DBG("\n"); + /* + * Read the data into the buffer and reload and start + * queue with new data if not finished. If finished + * then setup the next transfer + */ + read(drv_data); + + if (drv_data->rx == drv_data->rx_end) { + /* + * Finished now - fall through and schedule next + * transfer tasklet + */ + if (drv_data->flags & TRAN_STATE_WORD_ODD_NUM) + set_16bit_transfer_mode(drv_data); + + msg->state = next_transfer(drv_data); + } else { + /* not finished yet - keep going */ + msg->actual_length += write(drv_data); + return IRQ_HANDLED; + } + + tasklet_schedule(&drv_data->pump_transfers); + + return IRQ_HANDLED; +} + +/* caller already set message->status; dma and pio irqs are blocked */ +static void giveback(struct driver_data *drv_data) +{ + struct spi_transfer *last_transfer; + unsigned long flags; + struct spi_message *msg; + DBG("\n"); + + spin_lock_irqsave(&drv_data->lock, flags); + msg = drv_data->cur_msg; + drv_data->cur_msg = NULL; + drv_data->cur_transfer = NULL; + drv_data->cur_chip = NULL; + queue_work(drv_data->workqueue, &drv_data->pump_messages); + spin_unlock_irqrestore(&drv_data->lock, flags); + + last_transfer = list_entry(msg->transfers.prev, + struct spi_transfer, transfer_list); + + if (!last_transfer->cs_change) + drv_data->cs_control(drv_data->cs, QSPI_CS_DROP); + + msg->state = NULL; + if (msg->complete) + msg->complete(msg->context); +} + + +static void pump_transfers(unsigned long data) +{ + struct driver_data *drv_data = (struct driver_data *)data; + struct spi_message *message = NULL; + struct spi_transfer *transfer = NULL; + struct spi_transfer *previous = NULL; + struct chip_data *chip = NULL; + unsigned long flags; + DBG("\n"); + /* Get current state information */ + message = drv_data->cur_msg; + transfer = drv_data->cur_transfer; + chip = drv_data->cur_chip; + + /* Handle for abort */ + if (message->state == ERROR_STATE) { + message->status = -EIO; + giveback(drv_data); + return; + } + + /* Handle end of message */ + if (message->state == DONE_STATE) { + message->status = 0; + giveback(drv_data); + return; + } + + if (message->state == START_STATE) { + dspi_setup_chip(drv_data); + + if (drv_data->cs_control) + drv_data->cs_control(message->spi->chip_select, + QSPI_CS_ASSERT); + } + + /* Delay if requested at end of transfer*/ + if (message->state == RUNNING_STATE) { + previous = list_entry(transfer->transfer_list.prev, + struct spi_transfer, + transfer_list); + + if (drv_data->cs_control && transfer->cs_change) + drv_data->cs_control(message->spi->chip_select, + QSPI_CS_DROP); + + if (previous->delay_usecs) + udelay(previous->delay_usecs); + + if (drv_data->cs_control && transfer->cs_change) + drv_data->cs_control(message->spi->chip_select, + QSPI_CS_ASSERT); + } + + drv_data->flags = 0; + drv_data->tx = (void *)transfer->tx_buf; + drv_data->tx_end = drv_data->tx + transfer->len; + drv_data->rx = transfer->rx_buf; + drv_data->rx_end = drv_data->rx + transfer->len; + + if (!drv_data->rx) + drv_data->flags |= TRAN_STATE_RX_VOID; + if (!drv_data->tx) + drv_data->flags |= TRAN_STATE_TX_VOID; + drv_data->cs = message->spi->chip_select; + drv_data->cs_change = transfer->cs_change; + drv_data->void_write_data = chip->void_write_data; + if (transfer->speed_hz) { + *(drv_data->ctar + drv_data->cs) = \ + ((chip->ctar_val & ~0xF) | \ + hz_to_spi_baud(chip->ctar.pbr, \ + chip->ctar.dbr, \ + transfer->speed_hz)); + } + + message->state = RUNNING_STATE; + /* Go baby, go */ + local_irq_save(flags); + message->actual_length += write(drv_data); + local_irq_restore(flags); +} + + +static void pump_messages(struct work_struct *work) +{ + struct driver_data *drv_data; + unsigned long flags; + DBG("\n"); + + drv_data = container_of(work, struct driver_data, pump_messages); + + /* Lock queue and check for queue work */ + spin_lock_irqsave(&drv_data->lock, flags); + if (list_empty(&drv_data->queue) + || drv_data->run == QUEUE_STOPPED) { + drv_data->busy = 0; + spin_unlock_irqrestore(&drv_data->lock, flags); + return; + } + + /* Make sure we are not already running a message */ + if (drv_data->cur_msg) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return; + } + + /* Extract head of queue */ + drv_data->cur_msg = list_entry(drv_data->queue.next, + struct spi_message, queue); + list_del_init(&drv_data->cur_msg->queue); + + /* Initial message state*/ + drv_data->cur_msg->state = START_STATE; + drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, + struct spi_transfer, + transfer_list); + + if (drv_data->cur_transfer->transfer_list.next + == &drv_data->cur_msg->transfers) + drv_data->cur_transfer->cs_change = 1; /* last */ + + + /* Setup the SPI Registers using the per chip configuration */ + drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); + + /* Mark as busy and launch transfers */ + tasklet_schedule(&drv_data->pump_transfers); + + drv_data->busy = 1; + spin_unlock_irqrestore(&drv_data->lock, flags); +} + +/****************************************************************************/ + +/* + * SPI master implementation + */ + +static int transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct driver_data *drv_data = spi_master_get_devdata(spi->master); + unsigned long flags; + + DBG("\n"); + spin_lock_irqsave(&drv_data->lock, flags); + + if (drv_data->run == QUEUE_STOPPED) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return -ESHUTDOWN; + } + + msg->actual_length = 0; + msg->status = -EINPROGRESS; + msg->state = START_STATE; + + list_add_tail(&msg->queue, &drv_data->queue); + + if (drv_data->run == QUEUE_RUNNING && !drv_data->busy) + queue_work(drv_data->workqueue, &drv_data->pump_messages); + + spin_unlock_irqrestore(&drv_data->lock, flags); + + return 0; +} + + +static int setup(struct spi_device *spi) +{ + + struct chip_data *chip; + struct coldfire_dspi_chip *chip_info + = (struct coldfire_dspi_chip *)spi->controller_data; + DBG("\n"); + + /* Only alloc on first setup */ + chip = spi_get_ctldata(spi); + if (chip == NULL) { + chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL); + if (!chip) + return -ENOMEM; + spi->mode = chip_info->mode; + spi->bits_per_word = chip_info->bits_per_word; + } + + chip->mcr.master = 1; + chip->mcr.cont_scke = 0; + chip->mcr.dconf = 0; + chip->mcr.frz = 0; + chip->mcr.mtfe = 0; + chip->mcr.pcsse = 0; + chip->mcr.rooe = 0; + chip->mcr.pcsis = 0xFF; + chip->mcr.reserved15 = 0; + chip->mcr.mdis = 0; + chip->mcr.dis_tx = 0; + chip->mcr.dis_rxf = 0; + chip->mcr.clr_tx = 1; + chip->mcr.clr_rxf = 1; + chip->mcr.smpl_pt = 0; + chip->mcr.reserved71 = 0; + chip->mcr.halt = 0; + + if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) { + chip->ctar.fmsz = spi->bits_per_word-1; + } else { + printk(KERN_ERR "Invalid wordsize\n"); + kfree(chip); + return -ENODEV; + } + + chip->void_write_data = chip_info->void_write_data; + + if (spi->max_speed_hz != 0) + chip_info->br = hz_to_spi_baud(chip_info->pbr, chip_info->dbr, \ + spi->max_speed_hz); + + chip->ctar.cpha = (spi->mode & SPI_CPHA) ? 1 : 0; + chip->ctar.cpol = (spi->mode & SPI_CPOL) ? 1 : 0; + chip->ctar.lsbfe = (spi->mode & SPI_LSB_FIRST) ? 1 : 0; + chip->ctar.dbr = chip_info->dbr; + chip->ctar.pbr = chip_info->pbr; + chip->ctar.br = chip_info->br; + chip->ctar.pcssck = chip_info->pcssck; + chip->ctar.pasc = chip_info->pasc; + chip->ctar.pdt = chip_info->pdt; + chip->ctar.cssck = chip_info->cssck; + chip->ctar.asc = chip_info->asc; + chip->ctar.dt = chip_info->dt; + + spi_set_ctldata(spi, chip); + + return 0; +} + +static int init_queue(struct driver_data *drv_data) +{ + INIT_LIST_HEAD(&drv_data->queue); + spin_lock_init(&drv_data->lock); + + drv_data->run = QUEUE_STOPPED; + drv_data->busy = 0; + + tasklet_init(&drv_data->pump_transfers, + pump_transfers, (unsigned long)drv_data); + + INIT_WORK(&drv_data->pump_messages, pump_messages); + + drv_data->workqueue = create_singlethread_workqueue( + drv_data->master->dev.parent->bus_id); + if (drv_data->workqueue == NULL) + return -EBUSY; + + return 0; +} + +static int start_queue(struct driver_data *drv_data) +{ + unsigned long flags; + + spin_lock_irqsave(&drv_data->lock, flags); + + if (drv_data->run == QUEUE_RUNNING || drv_data->busy) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return -EBUSY; + } + + drv_data->run = QUEUE_RUNNING; + drv_data->cur_msg = NULL; + drv_data->cur_transfer = NULL; + drv_data->cur_chip = NULL; + spin_unlock_irqrestore(&drv_data->lock, flags); + + queue_work(drv_data->workqueue, &drv_data->pump_messages); + + return 0; +} + +static int stop_queue(struct driver_data *drv_data) +{ + unsigned long flags; + unsigned limit = 500; + int status = 0; + + spin_lock_irqsave(&drv_data->lock, flags); + + /* This is a bit lame, but is optimized for the common execution path. + * A wait_queue on the drv_data->busy could be used, but then the common + * execution path (pump_messages) would be required to call wake_up or + * friends on every SPI message. Do this instead */ + drv_data->run = QUEUE_STOPPED; + while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { + spin_unlock_irqrestore(&drv_data->lock, flags); + msleep(10); + spin_lock_irqsave(&drv_data->lock, flags); + } + + if (!list_empty(&drv_data->queue) || drv_data->busy) + status = -EBUSY; + + spin_unlock_irqrestore(&drv_data->lock, flags); + + return status; +} + +static int destroy_queue(struct driver_data *drv_data) +{ + int status; + + status = stop_queue(drv_data); + if (status != 0) + return status; + + destroy_workqueue(drv_data->workqueue); + + return 0; +} + + +static void cleanup(struct spi_device *spi) +{ + struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi); + + dev_dbg(&spi->dev, "spi_device %u.%u cleanup\n", + spi->master->bus_num, spi->chip_select); + + kfree(chip); +} + + +/****************************************************************************/ + +/* + * Generic Device driver routines and interface implementation + */ + +static int coldfire_spi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct coldfire_spi_master *platform_info; + struct spi_master *master; + struct driver_data *drv_data = 0; + struct resource *memory_resource; + int irq; + int status = 0; + int i; +#if defined(SPI_DSPI_EDMA) + dma_addr_t dma_handle; +#endif + + platform_info = (struct coldfire_spi_master *)dev->platform_data; + + master = spi_alloc_master(dev, sizeof(struct driver_data)); + if (!master) + return -ENOMEM; + + drv_data = spi_master_get_devdata(master); + drv_data->master = master; + + INIT_LIST_HEAD(&drv_data->queue); + spin_lock_init(&drv_data->lock); + + master->bus_num = platform_info->bus_num; + master->num_chipselect = platform_info->num_chipselect; + master->cleanup = cleanup; + master->setup = setup; + master->transfer = transfer; + + drv_data->cs_control = platform_info->cs_control; + if (drv_data->cs_control) + for (i = 0; i < master->num_chipselect; i++) + drv_data->cs_control(i, QSPI_CS_INIT | QSPI_CS_DROP); + + /* Setup register addresses */ + memory_resource = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "spi-module"); + if (!memory_resource) { + dev_dbg(dev, "can not find platform module memory\n"); + goto out_error_master_alloc; + } + +#if defined(SPI_DSPI_EDMA) + drv_data->edma_tx_buf = dma_alloc_coherent(NULL, EDMA_BUFSIZE_KMALLOC, \ + &dma_handle, GFP_DMA); + if (!drv_data->edma_tx_buf) { + dev_dbg(dev, "cannot allocate eDMA TX memory\n"); + goto out_error_master_alloc; + } + drv_data->edma_rx_buf = dma_alloc_coherent(NULL, EDMA_BUFSIZE_KMALLOC, \ + &dma_handle, GFP_DMA); + if (!drv_data->edma_rx_buf) { + dma_free_coherent(NULL, EDMA_BUFSIZE_KMALLOC, \ + drv_data->edma_tx_buf, dma_handle); + kfree(drv_data->edma_tx_buf); + dev_dbg(dev, "cannot allocate eDMA RX memory\n"); + goto out_error_master_alloc; + } +#endif + + drv_data->mcr = (void *)&MCF_DSPI_DMCR; + drv_data->ctar = (void *)&MCF_DSPI_DCTAR0; + drv_data->dspi_sr = (void *)&MCF_DSPI_DSR; + drv_data->dspi_rser = (void *)&MCF_DSPI_DRSER; + drv_data->dspi_dtfr = (void *)&MCF_DSPI_DTFR; + drv_data->dspi_drfr = (void *)&MCF_DSPI_DRFR; + + memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "spi-par"); + if (!memory_resource) { + dev_dbg(dev, "No spi-par memory\n"); + goto out_error_master_alloc; + } + drv_data->par = (void *)memory_resource->start; + + memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "spi-int-level"); + if (!memory_resource) { + dev_dbg(dev, "No spi-int-level memory\n"); + goto out_error_master_alloc; + } + drv_data->int_icr = (void *)memory_resource->start; + + memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "spi-int-mask"); + if (!memory_resource) { + dev_dbg(dev, "No spi-int-mask memory\n"); + goto out_error_master_alloc; + } + drv_data->int_mr = (void *)memory_resource->start; + + if (platform_info->irq_list) { + /* multiple IRQs */ + int *irqlist = platform_info->irq_list; + while ((irq = *irqlist++)) { + int off = *irqlist++; + int lvl = *irqlist++; + int msk = *irqlist++; + status = request_irq(irq, dspi_interrupt, IRQF_DISABLED, + dev->bus_id, drv_data); + if (status < 0) { + dev_err(&pdev->dev, + "Unable to attach ColdFire DSPI interrupt\n"); + goto out_error_master_alloc; + } + + if (lvl) + *(drv_data->int_icr + off) = lvl; + + if (msk) + *drv_data->int_mr &= ~msk; + } + } + else { + irq = platform_info->irq_vector; + + status = request_irq(platform_info->irq_vector, dspi_interrupt, + IRQF_DISABLED, dev->bus_id, drv_data); + if (status < 0) { + dev_err(&pdev->dev, "Unable to attach ColdFire DSPI interrupt\n"); + goto out_error_master_alloc; + } + + *drv_data->int_icr = platform_info->irq_lp; + *drv_data->int_mr &= ~platform_info->irq_mask; + } + + /* Now that we have all the addresses etc. Let's set it up */ + if (platform_info->par_val) + *drv_data->par = platform_info->par_val; + + /* Initial and start queue */ + status = init_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "Problem initializing DSPI queue\n"); + goto out_error_irq_alloc; + } + status = start_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "Problem starting DSPI queue\n"); + goto out_error_irq_alloc; + } + + /* Register with the SPI framework */ + platform_set_drvdata(pdev, drv_data); + status = spi_register_master(master); + if (status != 0) { + dev_err(&pdev->dev, "Problem registering DSPI master\n"); + status = -EINVAL; + goto out_error_queue_alloc; + } + +#if defined(SPI_DSPI_EDMA) + if (mcf_edma_request_channel(DSPI_DMA_TX_TCD, + edma_tx_handler, + NULL, + 0x0, + pdev, + NULL, /* spinlock */ + DRIVER_NAME) < 0){ + dev_err(&pdev->dev, "eDMA transmit channel request\n"); + status = -EINVAL; + goto out_error_queue_alloc; + } + + if (mcf_edma_request_channel(DSPI_DMA_RX_TCD, + edma_rx_handler, + NULL, + 0x0, + pdev, + NULL, /* spinlock */ + DRIVER_NAME) < 0){ + dev_err(&pdev->dev, "eDAM receive channel request\n"); + status = -EINVAL; + mcf_edma_free_channel(DSPI_DMA_TX_TCD, pdev); + goto out_error_queue_alloc; + } +#endif + + printk(KERN_INFO "DSPI: Coldfire master initialized\n"); + return status; + +out_error_queue_alloc: + destroy_queue(drv_data); + +out_error_irq_alloc: + free_irq(platform_info->irq_vector, drv_data); + +out_error_master_alloc: + spi_master_put(master); + return status; + +} + +static int coldfire_spi_remove(struct platform_device *pdev) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int irq; + int status = 0; + + if (!drv_data) + return 0; + +#if defined(SPI_DSPI_EDMA) + mcf_edma_free_channel(DSPI_DMA_TX_TCD, pdev); + mcf_edma_free_channel(DSPI_DMA_RX_TCD, pdev); +#endif + + /* Remove the queue */ + status = destroy_queue(drv_data); + if (status != 0) + return status; + + /* Release IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq >= 0) + free_irq(irq, drv_data); + + /* Disconnect from the SPI framework */ + spi_unregister_master(drv_data->master); + + /* Prevent double remove */ + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static void coldfire_spi_shutdown(struct platform_device *pdev) +{ + int status = coldfire_spi_remove(pdev); + + if (status != 0) + dev_err(&pdev->dev, "shutdown failed with %d\n", status); +} + + +#ifdef CONFIG_PM +static int suspend_devices(struct device *dev, void *pm_message) +{ + pm_message_t *state = pm_message; + + if (dev->power.power_state.event != state->event) { + dev_warn(dev, "pm state does not match request\n"); + return -1; + } + + return 0; +} + +static int coldfire_spi_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int status = 0; + + /* Check all childern for current power state */ + if (device_for_each_child(&pdev->dev, + &state, suspend_devices) != 0) { + dev_warn(&pdev->dev, "suspend aborted\n"); + return -1; + } + + status = stop_queue(drv_data); + if (status != 0) + return status; + + return 0; +} + +static int coldfire_spi_resume(struct platform_device *pdev) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int status = 0; + + /* Start the queue running */ + status = start_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "problem starting queue (%d)\n", status); + return status; + } + + return 0; +} +#else +#define coldfire_spi_suspend NULL +#define coldfire_spi_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver driver = { + .driver = { + .name = "spi_coldfire", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + }, + .probe = coldfire_spi_probe, + .remove = __devexit_p(coldfire_spi_remove), + .shutdown = coldfire_spi_shutdown, + .suspend = coldfire_spi_suspend, + .resume = coldfire_spi_resume, +}; + +static int __init coldfire_spi_init(void) +{ + platform_driver_register(&driver); + + return 0; +} +module_init(coldfire_spi_init); + +static void __exit coldfire_spi_exit(void) +{ + platform_driver_unregister(&driver); +} +module_exit(coldfire_spi_exit); + +MODULE_AUTHOR("Matt Waddel"); +MODULE_DESCRIPTION("ColdFire DSPI Contoller"); +MODULE_LICENSE("GPL"); --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -35,6 +35,15 @@ config SPI_DEBUG Say "yes" to enable debug messaging (like dev_dbg and pr_debug), sysfs, and debugfs support in SPI controller and protocol drivers. +config COLDFIRE_EDMA + tristate "Coldfire eDMA" + depends on COLDFIRE && EXPERIMENTAL + help + Support for Coldfire eDMA controller. Required for example + by SSI audio device driver. + + + # # MASTER side ... talking to discrete SPI slave chips including microcontrollers # @@ -113,6 +122,27 @@ config SPI_GPIO If unsure, say N. +config SPI_COLDFIRE + tristate "Coldfire QSPI/DSPI SPI Master" + depends on SPI_MASTER && COLDFIRE && EXPERIMENTAL + help + SPI driver for Freescale Coldfire QSPI module in master mode. + Tested with the 5282 processor, but should also work with other + Coldfire variants. + +config SPI_DSPI + tristate "Coldfire DSPI" + depends on SPI_MASTER && COLDFIRE + help + SPI driver for Coldfire DSPI driver only. + +config SPI_COLDFIRE_DSPI_EDMA + boolean "Coldfire DSPI master driver uses eDMA" + depends on SPI_MASTER && COLDFIRE && SPI_COLDFIRE && EXPERIMENTAL && COLDFIRE_EDMA + default n + help + Say "yes" if you want DSPI master driver to use eDMA for transfers. + config SPI_IMX tristate "Freescale iMX SPI controller" depends on SPI_MASTER && ARCH_IMX && EXPERIMENTAL @@ -255,6 +285,18 @@ config SPI_TLE62X0 # # Add new SPI protocol masters in alphabetical order above this line # +config SPI_COLDFIRE_SSI_AUDIO + tristate "Coldfire SSI AUDIO" + depends on SPI_MASTER && SPI_COLDFIRE && EXPERIMENTAL + help + SSI audio device driver + +config SSIAUDIO_USE_EDMA + boolean "Coldfire DSPI master driver uses eDMA" + default y + depends on EXPERIMENTAL && COLDFIRE_EDMA && SPI_COLDFIRE_SSI_AUDIO + help + Say "yes" if you want SSI audio driver to use eDMA for SSI transfers. # (slave support would go here) --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -6,6 +6,8 @@ ifeq ($(CONFIG_SPI_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif +obj-$(CONFIG_COLDFIRE_EDMA) += coldfire_edma.o + # small core, mostly translating board-specific # config declarations into driver model code obj-$(CONFIG_SPI_MASTER) += spi.o @@ -16,6 +18,8 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx. obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_AU1550) += au1550_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o +# obj-$(CONFIG_SPI_COLDFIRE) += spi_coldfire.o spi-m5445x.o +obj-$(CONFIG_SPI_DSPI) += dspi_mcf.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o @@ -35,6 +39,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci. obj-$(CONFIG_SPI_AT25) += at25.o obj-$(CONFIG_SPI_SPIDEV) += spidev.o obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o +obj-$(CONFIG_SPI_COLDFIRE_SSI_AUDIO) += ssi_audio.o # ... add above this line ... # SPI slave controller drivers (upstream link) --- /dev/null +++ b/drivers/spi/spi_coldfire.c @@ -0,0 +1,1542 @@ +/* + * spi_coldfire.c - Master QSPI/DSPI controller for the ColdFire processors + * + * + * (C) Copyright 2005, Intec Automation, + * Mike Lavender (mike@steroidmicros) + * + * (C) Copyright 2007-2008, Freescale Inc, + * Yaroslav Vinogradov + * Andrey Butok + * Kurt Mahan + * + * 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 + * + *************************************************************************** + * Changes: + * v0.003 12 February 2008 Andrey Butok, Freescale Semiconductor + * Added suport of MCF5227x DSPI module. + * v0.002 2007 Yaroslav Vinogradov, Freescale Semiconductor + * Added suport of MCF5445x DSPI module. + * v0.001 2005 Mike Lavender, Intec Automation, + * Intial version. Coldfire QSPI master driver. + * + */ + + +/****************************************************************************/ + +/* + * Includes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(CONFIG_M5445X) + #include + + #define SPI_DSPI + #if defined(CONFIG_SPI_COLDFIRE_DSPI_EDMA) + #define SPI_DSPI_EDMA + #ifdef CONFIG_MMU + #define SPI_USE_MMU + #endif + #include + #endif + + #include +#endif + +#if defined(CONFIG_M547X_8X) + #define SPI_DSPI + + #include + #include +#endif + +#ifdef CONFIG_M5227x + #define SPI_DSPI + + #if defined(CONFIG_SPI_COLDFIRE_DSPI_EDMA) + #define SPI_DSPI_EDMA + #endif +#endif + + +#if defined(SPI_DSPI_EDMA) + +/* edma buffer size in transfer units (32bits) */ +#define EDMA_BUFFER_SIZE (PAGE_SIZE/4) +#define EDMA_BUFSIZE_KMALLOC (EDMA_BUFFER_SIZE*4) + +#define DSPI_DMA_RX_TCD MCF_EDMA_CHAN_DSPI_RX +#define DSPI_DMA_TX_TCD MCF_EDMA_CHAN_DSPI_TX + +#include +#endif + +MODULE_AUTHOR("Mike Lavender"); +MODULE_DESCRIPTION("ColdFire SPI Contoller"); +MODULE_LICENSE("GPL"); + +#define DRIVER_NAME "Coldfire QSPI/DSPI" + +/****************************************************************************/ + +/* + * Local constants and macros + */ + +#define QSPI_RAM_SIZE 0x10 /* 16 word table */ +#define QSPI_TRANSMIT_RAM 0x00 +#define QSPI_RECEIVE_RAM 0x10 +#define QSPI_COMMAND_RAM 0x20 + +#define QSPI_COMMAND 0x7000 /* 15: X = Continuous CS + * 14: 1 = Get BITSE from QMR[BITS] + * 13: 1 = Get DT from QDLYR[DTL] + * 12: 1 = Get DSK from QDLYR[QCD] + * 8-11: XXXX = next 4 bytes for CS + * 0-7: 0000 0000 Reserved + */ + +#define QIR_WCEF 0x0008 /* write collison */ +#define QIR_ABRT 0x0004 /* abort */ +#define QIR_SPIF 0x0001 /* finished */ + +#define QIR_WCEFE 0x0800 +#define QIR_ABRTE 0x0400 +#define QIR_SPIFE 0x0100 + +#define QIR_WCEFB 0x8000 +#define QIR_ABRTB 0x4000 +#define QIR_ABRTL 0x1000 + +#define QMR_BITS 0x3C00 +#define QMR_BITS_8 0x2000 + +#define QCR_CONT 0x8000 + +#define QDLYR_SPE 0x8000 + +#define QWR_ENDQP_MASK 0x0F00 +#define QWR_CSIV 0x1000 /* 1 = active low chip selects */ + + +#define START_STATE ((void*)0) +#define RUNNING_STATE ((void*)1) +#define DONE_STATE ((void*)2) +#define ERROR_STATE ((void*)-1) + +#define QUEUE_RUNNING 0 +#define QUEUE_STOPPED 1 + +/****************************************************************************/ + +/* + * Local Data Structures + */ + +struct transfer_state { + u32 index; + u32 len; + void *tx; + void *tx_end; + void *rx; + void *rx_end; + char flags; +#define TRAN_STATE_RX_VOID 0x01 +#define TRAN_STATE_TX_VOID 0x02 +#define TRAN_STATE_WORD_ODD_NUM 0x04 + u8 cs; + u16 void_write_data; + unsigned cs_change:1; +}; + +typedef struct { + unsigned master:1; + unsigned dohie:1; + unsigned bits:4; + unsigned cpol:1; + unsigned cpha:1; + unsigned baud:8; +} QMR; + +typedef struct { + unsigned spe:1; + unsigned qcd:7; + unsigned dtl:8; +} QDLYR; + +typedef struct { + unsigned halt:1; + unsigned wren:1; + unsigned wrto:1; + unsigned csiv:1; + unsigned endqp:4; + unsigned cptqp:4; + unsigned newqp:4; +} QWR; + + +typedef struct { + unsigned master:1; + unsigned cont_scke:1; + unsigned dconf:2; + unsigned frz:1; + unsigned mtfe:1; + unsigned pcsse:1; + unsigned rooe:1; + unsigned pcsis:8; + unsigned reserved15:1; + unsigned mdis:1; + unsigned dis_tx:1; + unsigned dis_rxf:1; + unsigned clr_tx:1; + unsigned clr_rxf:1; + unsigned smpl_pt:2; + unsigned reserved71:7; + unsigned halt:1; +} DSPI_MCR; + +typedef struct { + unsigned dbr:1; + unsigned fmsz:4; + unsigned cpol:1; + unsigned cpha:1; + unsigned lsbfe:1; + unsigned pcssck:2; + unsigned pasc:2; + unsigned pdt:2; + unsigned pbr:2; + unsigned cssck:4; + unsigned asc:4; + unsigned dt:4; + unsigned br:4; +} DSPI_CTAR; + +struct chip_data { +#if defined(SPI_DSPI) + /* dspi data */ + union { + u32 mcr_val; + DSPI_MCR mcr; + }; + union { + u32 ctar_val; + DSPI_CTAR ctar; + }; +#else + union { + u16 qmr_val; + QMR qmr; + }; + union { + u16 qdlyr_val; + QDLYR qdlyr; + }; + union { + u16 qwr_val; + QWR qwr; + }; +#endif + + u16 void_write_data; +}; + + +struct driver_data { + /* Driver model hookup */ + struct platform_device *pdev; + + /* SPI framework hookup */ + struct spi_master *master; + + /* Driver message queue */ + struct workqueue_struct *workqueue; + struct work_struct pump_messages; + spinlock_t lock; + struct list_head queue; + int busy; + int run; + + /* Message Transfer pump */ + struct tasklet_struct pump_transfers; + + /* Current message transfer state info */ + struct spi_message* cur_msg; + struct spi_transfer* cur_transfer; + struct chip_data *cur_chip; + size_t len; + void *tx; + void *tx_end; + void *rx; + void *rx_end; + char flags; +#define TRAN_STATE_RX_VOID 0x01 +#define TRAN_STATE_TX_VOID 0x02 +#define TRAN_STATE_WORD_ODD_NUM 0x04 + u8 cs; + u16 void_write_data; + unsigned cs_change:1; + + u32 trans_cnt; + u32 wce_cnt; + u32 abrt_cnt; +#if defined(SPI_DSPI) + u32 *mcr; /* DSPI MCR register */ + u32 *ctar; /* DSPI CTAR register */ + u32 *dspi_dtfr; /* DSPI DTFR register */ + u32 *dspi_drfr; /* DSPI DRFR register */ + u32 *dspi_rser; /* DSPI RSER register */ + u32 *dspi_sr; /* DSPI status register */ + u8 dspi_ctas; /* DSPI CTAS value*/ +#if defined(SPI_DSPI_EDMA) + void* edma_tx_buf; + void* edma_rx_buf; +#endif +#else + u16 *qmr; /* QSPI mode register */ + u16 *qdlyr; /* QSPI delay register */ + u16 *qwr; /* QSPI wrap register */ + u16 *qir; /* QSPI interrupt register */ + u16 *qar; /* QSPI address register */ + u16 *qdr; /* QSPI data register */ + u16 *qcr; /* QSPI command register */ +#endif +#if defined(CONFIG_M532x) || defined(CONFIG_M537x) + u16 *par; /* Pin assignment register */ +#else + u8 *par; /* Pin assignment register */ +#endif + u8 *int_icr; /* Interrupt level and priority register */ + u32 *int_mr; /* Interrupt mask register */ + void (*cs_control)(u8 cs, u8 command); +}; + +#define DSPI_CS(cs) ((1<<(cs))<<16) + + +/****************************************************************************/ + +/* + * SPI local functions + */ + +static void *next_transfer(struct driver_data *drv_data) +{ + struct spi_message *msg = drv_data->cur_msg; + struct spi_transfer *trans = drv_data->cur_transfer; + + /* Move to next transfer */ + if (trans->transfer_list.next != &msg->transfers) { + drv_data->cur_transfer = + list_entry(trans->transfer_list.next, + struct spi_transfer, + transfer_list); + return RUNNING_STATE; + } else + return DONE_STATE; +} + + +#define DSPI_BITS MCF_DSPI_DCTAR_FMSZ(15) +#define DSPI_BITS_16 MCF_DSPI_DCTAR_FMSZ(15) +#define DSPI_BITS_8 MCF_DSPI_DCTAR_FMSZ(7) +#define DSPI_FIFO_SIZE 16 + +static inline int is_word_transfer(struct driver_data *drv_data) +{ +#if defined(SPI_DSPI) + return ((*drv_data->ctar & DSPI_BITS_16) == DSPI_BITS_8) ? 0 : 1; +#else + return ((*drv_data->qmr & QMR_BITS) == QMR_BITS_8) ? 0 : 1; +#endif +} + +static void inline set_8bit_transfer_mode(struct driver_data *drv_data) +{ +#if defined(SPI_DSPI) + *drv_data->ctar |= (*drv_data->ctar & ~DSPI_BITS) | DSPI_BITS_8; +#else + *drv_data->qmr |= (*drv_data->qmr & ~QMR_BITS) | QMR_BITS_8; +#endif +} + +static void inline set_16bit_transfer_mode(struct driver_data *drv_data) +{ +#if defined(SPI_DSPI) + *drv_data->ctar |= (*drv_data->ctar & ~DSPI_BITS) | DSPI_BITS_16; +#else + *drv_data->qmr |= (*drv_data->qmr & ~QMR_BITS); +#endif +} + +static int write(struct driver_data *drv_data) +{ + int tx_count = 0; +#ifndef SPI_DSPI + int cmd_count = 0; +#endif + int tx_word; + +#if defined(SPI_DSPI) +#if defined(SPI_DSPI_EDMA) + u32* edma_wr; +#endif + u16 d16; + u8 d8; + u32 dspi_pushr; + int first = 1; +#endif + + tx_word = is_word_transfer(drv_data); + + /* If we are in word mode, but only have a single byte to transfer + * then switch to byte mode temporarily. Will switch back at the + * end of the transfer. */ + if (tx_word && ((drv_data->tx_end - drv_data->tx) == 1)) { + drv_data->flags |= TRAN_STATE_WORD_ODD_NUM; + set_8bit_transfer_mode(drv_data); + tx_word = 0; + } + + +#if defined(SPI_DSPI) +#if defined(SPI_DSPI_EDMA) + edma_wr = (u32*)(drv_data->edma_tx_buf); +#endif + +#if defined(SPI_DSPI_EDMA) + while ((drv_data->tx < drv_data->tx_end) && (tx_count < EDMA_BUFFER_SIZE)) { +#else + while ((drv_data->tx < drv_data->tx_end) && (tx_count < DSPI_FIFO_SIZE)) { +#endif + if (tx_word) { + if ((drv_data->tx_end - drv_data->tx) == 1) + break; + if (!(drv_data->flags & TRAN_STATE_TX_VOID)) { + d16 = *(u16 *)drv_data->tx; + } else { + d16 = drv_data->void_write_data; + } + + dspi_pushr = MCF_DSPI_DTFR_TXDATA(d16) + | DSPI_CS(drv_data->cs) + | MCF_DSPI_DTFR_CTAS(drv_data->dspi_ctas); + drv_data->tx += 2; + +#if defined(SPI_DSPI_EDMA) + if (drv_data->tx == drv_data->tx_end || tx_count==EDMA_BUFFER_SIZE-1) { +#else + if (drv_data->tx == drv_data->tx_end || tx_count==DSPI_FIFO_SIZE-1) { +#endif + /* last transfer in the queue */ + dspi_pushr |= MCF_DSPI_DTFR_EOQ; + if (drv_data->cs_change) { + dspi_pushr &= ~MCF_DSPI_DTFR_CONT; + } + } + + if (first) { + first = 0; + dspi_pushr |= MCF_DSPI_DTFR_CTCNT; /* clear counter */ + } +#if defined(SPI_DSPI_EDMA) + *edma_wr = dspi_pushr; + edma_wr++; +#else + *drv_data->dspi_dtfr = dspi_pushr; +#endif + + + } else { + if (!(drv_data->flags & TRAN_STATE_TX_VOID)) { + d8 = *(u8 *)drv_data->tx; + } else { + d8 = *(u8 *)&drv_data->void_write_data; + } + + dspi_pushr = MCF_DSPI_DTFR_TXDATA(d8) + | DSPI_CS(drv_data->cs) + | MCF_DSPI_DTFR_CTAS(drv_data->dspi_ctas) + | MCF_DSPI_DTFR_CONT; + + drv_data->tx++; + + if (drv_data->tx == drv_data->tx_end || tx_count==DSPI_FIFO_SIZE-1) { + /* last transfer in the queue */ + dspi_pushr |= MCF_DSPI_DTFR_EOQ; + if (drv_data->cs_change) { + dspi_pushr &= ~MCF_DSPI_DTFR_CONT; + } + } + + if (first) { + first = 0; + dspi_pushr |= MCF_DSPI_DTFR_CTCNT; /* clear counter */ + } + +#if defined(SPI_DSPI_EDMA) + *edma_wr = dspi_pushr; + edma_wr++; +#else + *drv_data->dspi_dtfr = dspi_pushr; +#endif + + } + tx_count++; + } + +#if defined(SPI_DSPI_EDMA) + + if (tx_count>0) { + + /* TBD: initiate eDMA transfer */ + mcf_edma_set_tcd_params(DSPI_DMA_TX_TCD, +#ifdef SPI_USE_MMU + virt_to_phys(drv_data->edma_tx_buf), +#else + drv_data->edma_tx_buf, +#endif + (u32)drv_data->dspi_dtfr, + MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, + 4, /* soff */ + 4, /* nbytes */ + 0, /* slast */ + tx_count, /* citer */ + tx_count, /* biter */ + 0, /* doff */ + 0, /* dlastsga */ + 0, /* major_int */ + 1 /* disable_req */ + ); + + mcf_edma_set_tcd_params(DSPI_DMA_RX_TCD, + (u32)drv_data->dspi_drfr, +#ifdef SPI_USE_MMU + virt_to_phys(drv_data->edma_rx_buf), +#else + drv_data->edma_rx_buf, +#endif + MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, + 0, /* soff */ + 4, /* nbytes */ + 0, /* slast */ + tx_count, /* citer */ + tx_count, /* biter */ + 4, /* doff */ + 0, /* dlastsga */ + 0, /* major_int */ + 1 /* disable_req */ + ); + + + start_edma_transfer(DSPI_DMA_TX_TCD); /* transmit SPI data */ + start_edma_transfer(DSPI_DMA_RX_TCD); /* receive SPI data */ + } +#endif + +#else + + *drv_data->qar = QSPI_TRANSMIT_RAM; + while ((drv_data->tx < drv_data->tx_end) && (tx_count < QSPI_RAM_SIZE)) { + if (tx_word) { + if ((drv_data->tx_end - drv_data->tx) == 1) + break; + + if (!(drv_data->flags & TRAN_STATE_TX_VOID)) + *drv_data->qdr = *(u16 *)drv_data->tx; + else + *drv_data->qdr = drv_data->void_write_data; + drv_data->tx += 2; + } else { + if (!(drv_data->flags & TRAN_STATE_TX_VOID)) + *drv_data->qdr = *(u8 *)drv_data->tx; + else + *drv_data->qdr = *(u8 *)&drv_data->void_write_data; + drv_data->tx++; + } + tx_count++; + } + + + *drv_data->qar = QSPI_COMMAND_RAM; + while (cmd_count < tx_count) { + u16 qcr = QSPI_COMMAND + | QCR_CONT + | (~((0x01 << drv_data->cs) << 8) & 0x0F00); + + if ( (cmd_count == tx_count - 1) + && (drv_data->tx == drv_data->tx_end) + && (drv_data->cs_change) ) { + qcr &= ~QCR_CONT; + } + *drv_data->qcr = qcr; + cmd_count++; + } + + *drv_data->qwr = (*drv_data->qwr & ~QWR_ENDQP_MASK) | ((cmd_count - 1) << 8); + + /* Fire it up! */ + *drv_data->qdlyr |= QDLYR_SPE; +#endif + + return tx_count; +} + + +static int read(struct driver_data *drv_data) +{ + int rx_count = 0; + int rx_word; +#if defined(SPI_DSPI_EDMA) + u32* rx_edma; +#endif + u16 d; + rx_word = is_word_transfer(drv_data); + +#if defined(SPI_DSPI) +#if defined(SPI_DSPI_EDMA) + rx_edma = (u32*) drv_data->edma_tx_buf; + while ((drv_data->rx < drv_data->rx_end) && (rx_count < EDMA_BUFFER_SIZE)) { +#else + while ((drv_data->rx < drv_data->rx_end) && (rx_count < DSPI_FIFO_SIZE)) { +#endif + if (rx_word) { + if ((drv_data->rx_end - drv_data->rx) == 1) + break; +#if defined(SPI_DSPI_EDMA) + d = MCF_DSPI_DRFR_RXDATA(*rx_edma); + rx_edma++; +#else + d = MCF_DSPI_DRFR_RXDATA(*drv_data->dspi_drfr); +#endif + + if (!(drv_data->flags & TRAN_STATE_RX_VOID)) + *(u16 *)drv_data->rx = d; + drv_data->rx += 2; + } else { +#if defined(SPI_DSPI_EDMA) + d = MCF_DSPI_DRFR_RXDATA(*rx_edma); + rx_edma++; +#else + d = MCF_DSPI_DRFR_RXDATA(*drv_data->dspi_drfr); +#endif + if (!(drv_data->flags & TRAN_STATE_RX_VOID)) + *(u8 *)drv_data->rx = d; + drv_data->rx++; + } + rx_count++; + } +#else + *drv_data->qar = QSPI_RECEIVE_RAM; + while ((drv_data->rx < drv_data->rx_end) && (rx_count < QSPI_RAM_SIZE)) { + if (rx_word) { + if ((drv_data->rx_end - drv_data->rx) == 1) + break; + + if (!(drv_data->flags & TRAN_STATE_RX_VOID)) + *(u16 *)drv_data->rx = *drv_data->qdr; + drv_data->rx += 2; + } else { + if (!(drv_data->flags & TRAN_STATE_RX_VOID)) + *(u8 *)drv_data->rx = *drv_data->qdr; + drv_data->rx++; + } + rx_count++; + } +#endif + + return rx_count; +} + + +static inline void qspi_setup_chip(struct driver_data *drv_data) +{ + struct chip_data *chip = drv_data->cur_chip; + +#if defined(SPI_DSPI) + + *drv_data->mcr = chip->mcr_val; + + /* TBD: remove later */ +/* JKM -- validate */ + chip->ctar_val = 0x78560118; + + *drv_data->ctar = chip->ctar_val; + *drv_data->dspi_rser = 0 + | MCF_DSPI_DRSER_EOQFE +#if defined(SPI_DSPI_EDMA) + | MCF_DSPI_DRSER_TFFFE + | MCF_DSPI_DRSER_TFFFS +#endif + ; +#else + *drv_data->qmr = chip->qmr_val; + *drv_data->qdlyr = chip->qdlyr_val; + *drv_data->qwr = chip->qwr_val; + + /* + * Enable all the interrupts and clear all the flags + */ + *drv_data->qir = (QIR_SPIFE | QIR_ABRTE | QIR_WCEFE) + | (QIR_WCEFB | QIR_ABRTB | QIR_ABRTL) + | (QIR_SPIF | QIR_ABRT | QIR_WCEF); +#endif +} + +#if defined(SPI_DSPI_EDMA) +static int edma_tx_handler(int channel, void* dev) +{ + if (channel == DSPI_DMA_TX_TCD) { + stop_edma_transfer(DSPI_DMA_TX_TCD); + } + return IRQ_HANDLED; +} + +static int edma_rx_handler(int channel, void* dev) +{ + if (channel == DSPI_DMA_RX_TCD) { + stop_edma_transfer(DSPI_DMA_RX_TCD); + } + + return IRQ_HANDLED; +} +#endif + +static irqreturn_t qspi_interrupt(int irq, void *dev_id) +{ + struct driver_data *drv_data = (struct driver_data *)dev_id; + struct spi_message *msg = drv_data->cur_msg; +#if defined(SPI_DSPI) +#if !defined(SPI_DSPI_EDMA) + u32 irq_status = *drv_data->dspi_sr; +#endif +#else + u16 irq_status = *drv_data->qir; +#endif + + /* Clear all flags immediately */ +#if defined(SPI_DSPI) + *drv_data->dspi_sr = MCF_DSPI_DSR_EOQF; +#else + *drv_data->qir |= (QIR_SPIF | QIR_ABRT | QIR_WCEF); +#endif + + if (!drv_data->cur_msg || !drv_data->cur_msg->state) { +#if !defined(SPI_DSPI_EDMA) + /* if eDMA is used it happens some time (at least once)*/ + printk(KERN_ERR "coldfire-qspi: bad message or transfer " + "state in interrupt handler. IRQ status=%x\n", irq_status); +#endif + return IRQ_NONE; + } + +#if !defined(SPI_DSPI) + if (irq_status & QIR_SPIF) { +#endif + /* + * Read the data into the buffer and reload and start + * queue with new data if not finished. If finished + * then setup the next transfer + */ + read(drv_data); + + if (drv_data->rx == drv_data->rx_end) { + /* + * Finished now - fall through and schedule next + * transfer tasklet + */ + if (drv_data->flags & TRAN_STATE_WORD_ODD_NUM) { + set_16bit_transfer_mode(drv_data); + } + + msg->state = next_transfer(drv_data); + msg->actual_length += drv_data->len; + } else { + /* not finished yet - keep going */ + write(drv_data); + return IRQ_HANDLED; + } +#if !defined(SPI_DSPI) + } else { + if (irq_status & QIR_WCEF) + drv_data->wce_cnt++; + + if (irq_status & QIR_ABRT) + drv_data->abrt_cnt++; + + msg->state = ERROR_STATE; + } +#endif + + tasklet_schedule(&drv_data->pump_transfers); + + return IRQ_HANDLED; +} + +/* caller already set message->status; dma and pio irqs are blocked */ +static void giveback(struct driver_data *drv_data) +{ + struct spi_transfer* last_transfer; + unsigned long flags; + struct spi_message *msg; + + spin_lock_irqsave(&drv_data->lock, flags); + msg = drv_data->cur_msg; + drv_data->cur_msg = NULL; + drv_data->cur_transfer = NULL; + drv_data->cur_chip = NULL; + queue_work(drv_data->workqueue, &drv_data->pump_messages); + spin_unlock_irqrestore(&drv_data->lock, flags); + + last_transfer = list_entry(msg->transfers.prev, + struct spi_transfer, + transfer_list); + + if (!last_transfer->cs_change) + drv_data->cs_control(drv_data->cs, QSPI_CS_DROP); + + msg->state = NULL; + if (msg->complete) + msg->complete(msg->context); +} + + +static void pump_transfers(unsigned long data) +{ + struct driver_data *drv_data = (struct driver_data *)data; + struct spi_message *message = NULL; + struct spi_transfer *transfer = NULL; + struct spi_transfer *previous = NULL; + struct chip_data *chip = NULL; + unsigned long flags; + + /* Get current state information */ + message = drv_data->cur_msg; + transfer = drv_data->cur_transfer; + chip = drv_data->cur_chip; + + /* Handle for abort */ + if (message->state == ERROR_STATE) { + message->status = -EIO; + giveback(drv_data); + return; + } + + /* Handle end of message */ + if (message->state == DONE_STATE) { + message->status = 0; + giveback(drv_data); + return; + } + + if (message->state == START_STATE) { + qspi_setup_chip(drv_data); + + if (drv_data->cs_control) + drv_data->cs_control(message->spi->chip_select, QSPI_CS_ASSERT); + } + + /* Delay if requested at end of transfer*/ + if (message->state == RUNNING_STATE) { + previous = list_entry(transfer->transfer_list.prev, + struct spi_transfer, + transfer_list); + + if (drv_data->cs_control && transfer->cs_change) + drv_data->cs_control(message->spi->chip_select, QSPI_CS_DROP); + + if (previous->delay_usecs) + udelay(previous->delay_usecs); + + if (drv_data->cs_control && transfer->cs_change) + drv_data->cs_control(message->spi->chip_select, QSPI_CS_ASSERT); + } + + drv_data->flags = 0; + drv_data->tx = (void *)transfer->tx_buf; + drv_data->tx_end = drv_data->tx + transfer->len; + drv_data->rx = transfer->rx_buf; + drv_data->rx_end = drv_data->rx + transfer->len; + drv_data->len = transfer->len; + if (!drv_data->rx) + drv_data->flags |= TRAN_STATE_RX_VOID; + if (!drv_data->tx) + drv_data->flags |= TRAN_STATE_TX_VOID; + drv_data->cs = message->spi->chip_select; + drv_data->cs_change = transfer->cs_change; + drv_data->void_write_data = chip->void_write_data; + + message->state = RUNNING_STATE; + + /* Go baby, go */ + local_irq_save(flags); + write(drv_data); + local_irq_restore(flags); +} + + +static void pump_messages(struct work_struct *work) +{ + struct driver_data *drv_data; + unsigned long flags; + + drv_data = container_of(work, struct driver_data, pump_messages); + + /* Lock queue and check for queue work */ + spin_lock_irqsave(&drv_data->lock, flags); + if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) { + drv_data->busy = 0; + spin_unlock_irqrestore(&drv_data->lock, flags); + return; + } + + /* Make sure we are not already running a message */ + if (drv_data->cur_msg) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return; + } + + /* Extract head of queue */ + drv_data->cur_msg = list_entry(drv_data->queue.next, + struct spi_message, queue); + list_del_init(&drv_data->cur_msg->queue); + + /* Initial message state*/ + drv_data->cur_msg->state = START_STATE; + drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, + struct spi_transfer, + transfer_list); + + /* Setup the SPI Registers using the per chip configuration */ + drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); + + /* Mark as busy and launch transfers */ + tasklet_schedule(&drv_data->pump_transfers); + + drv_data->busy = 1; + spin_unlock_irqrestore(&drv_data->lock, flags); +} + +/****************************************************************************/ + +/* + * SPI master implementation + */ + +static int transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct driver_data *drv_data = spi_master_get_devdata(spi->master); + unsigned long flags; + + spin_lock_irqsave(&drv_data->lock, flags); + + if (drv_data->run == QUEUE_STOPPED) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return -ESHUTDOWN; + } + + msg->actual_length = 0; + msg->status = -EINPROGRESS; + msg->state = START_STATE; + + list_add_tail(&msg->queue, &drv_data->queue); + + if (drv_data->run == QUEUE_RUNNING && !drv_data->busy) + queue_work(drv_data->workqueue, &drv_data->pump_messages); + + spin_unlock_irqrestore(&drv_data->lock, flags); + + return 0; +} + + +static int setup(struct spi_device *spi) +{ + struct coldfire_spi_chip *chip_info; + struct chip_data *chip; +#ifndef SPI_DSPI + u32 baud_divisor = 255; +#endif + + chip_info = (struct coldfire_spi_chip *)spi->controller_data; + + /* Only alloc on first setup */ + chip = spi_get_ctldata(spi); + if (chip == NULL) { + chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL); + if (!chip) + return -ENOMEM; + spi->mode = chip_info->mode; + spi->bits_per_word = chip_info->bits_per_word; + } + +#if defined(SPI_DSPI) + chip->mcr.master = 1; + chip->mcr.cont_scke = 0; + chip->mcr.dconf = 0; + chip->mcr.frz = 0; + chip->mcr.mtfe = 0; + chip->mcr.pcsse = 0; + chip->mcr.rooe = 0; + chip->mcr.pcsis = 0xFF; + chip->mcr.reserved15 = 0; + chip->mcr.mdis = 0; + chip->mcr.dis_tx = 0; + chip->mcr.dis_rxf = 0; + chip->mcr.clr_tx = 1; + chip->mcr.clr_rxf = 1; + chip->mcr.smpl_pt = 0; + chip->mcr.reserved71 = 0; + chip->mcr.halt = 0; + + if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) { + chip->ctar.fmsz = spi->bits_per_word-1; + } else { + printk(KERN_ERR "coldfire-spi: invalid wordsize\n"); + kfree(chip); + return -ENODEV; + } + + if (spi->mode & SPI_CPHA) + chip->ctar.cpha = 1; + else + chip->ctar.cpha = 0; + + if (spi->mode & SPI_CPOL) + chip->ctar.cpol = 1; + else + chip->ctar.cpol = 0; + + if (spi->mode & SPI_LSB_FIRST) + chip->ctar.lsbfe = 1; + else + chip->ctar.lsbfe = 0; + + /* This values are default for audio device */ + chip->ctar.dbr = 0; + chip->ctar.pbr = 2; + chip->ctar.br = 8; + + /* This values are default for audio device */ + chip->ctar.pcssck = 1; + chip->ctar.pasc = 1; + chip->ctar.pdt = 1; + chip->ctar.cssck = 0; + chip->ctar.asc = 1; + chip->ctar.dt = 1; + + chip->void_write_data = chip_info->void_write_data; + +#else + + chip->qwr.csiv = 1; /* Chip selects are active low */ + chip->qmr.master = 1; /* Must set to master mode */ + chip->qmr.dohie = 1; /* Data output high impediance enabled */ + chip->void_write_data = chip_info->void_write_data; + + chip->qdlyr.qcd = chip_info->del_cs_to_clk; + chip->qdlyr.dtl = chip_info->del_after_trans; + + if (spi->max_speed_hz != 0) + baud_divisor = (MCF_CLK/(2*spi->max_speed_hz)); + + if (baud_divisor < 2) + baud_divisor = 2; + + if (baud_divisor > 255) + baud_divisor = 255; + + chip->qmr.baud = baud_divisor; + + /*printk( "SPI: spi->max_speed_hz %d\n", spi->max_speed_hz );*/ + /*printk( "SPI: Baud set to %d\n", chip->qmr.baud );*/ + + if (spi->mode & SPI_CPHA) + chip->qmr.cpha = 1; + + if (spi->mode & SPI_CPOL) + chip->qmr.cpol = 1; + + if (spi->bits_per_word == 16) { + chip->qmr.bits = 0; + } else if ((spi->bits_per_word >= 8) && (spi->bits_per_word <= 15)) { + chip->qmr.bits = spi->bits_per_word; + } else { + printk(KERN_ERR "coldfire-spi: invalid wordsize\n"); + kfree(chip); + return -ENODEV; + } + +#endif + + spi_set_ctldata(spi, chip); + + return 0; +} + +static int init_queue(struct driver_data *drv_data) +{ + INIT_LIST_HEAD(&drv_data->queue); + spin_lock_init(&drv_data->lock); + + drv_data->run = QUEUE_STOPPED; + drv_data->busy = 0; + + tasklet_init(&drv_data->pump_transfers, + pump_transfers, (unsigned long)drv_data); + + INIT_WORK(&drv_data->pump_messages, pump_messages); + + drv_data->workqueue = create_singlethread_workqueue( + drv_data->master->dev.parent->bus_id); + if (drv_data->workqueue == NULL) + return -EBUSY; + + return 0; +} + +static int start_queue(struct driver_data *drv_data) +{ + unsigned long flags; + + spin_lock_irqsave(&drv_data->lock, flags); + + if (drv_data->run == QUEUE_RUNNING || drv_data->busy) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return -EBUSY; + } + + drv_data->run = QUEUE_RUNNING; + drv_data->cur_msg = NULL; + drv_data->cur_transfer = NULL; + drv_data->cur_chip = NULL; + spin_unlock_irqrestore(&drv_data->lock, flags); + + queue_work(drv_data->workqueue, &drv_data->pump_messages); + + return 0; +} + +static int stop_queue(struct driver_data *drv_data) +{ + unsigned long flags; + unsigned limit = 500; + int status = 0; + + spin_lock_irqsave(&drv_data->lock, flags); + + /* This is a bit lame, but is optimized for the common execution path. + * A wait_queue on the drv_data->busy could be used, but then the common + * execution path (pump_messages) would be required to call wake_up or + * friends on every SPI message. Do this instead */ + drv_data->run = QUEUE_STOPPED; + while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { + spin_unlock_irqrestore(&drv_data->lock, flags); + msleep(10); + spin_lock_irqsave(&drv_data->lock, flags); + } + + if (!list_empty(&drv_data->queue) || drv_data->busy) + status = -EBUSY; + + spin_unlock_irqrestore(&drv_data->lock, flags); + + return status; +} + +static int destroy_queue(struct driver_data *drv_data) +{ + int status; + + status = stop_queue(drv_data); + if (status != 0) + return status; + + destroy_workqueue(drv_data->workqueue); + + return 0; +} + + +static void cleanup(struct spi_device *spi) +{ + struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi); + + dev_dbg(&spi->dev, "spi_device %u.%u cleanup\n", + spi->master->bus_num, spi->chip_select); + + kfree(chip); +} + + +/****************************************************************************/ + +/* + * Generic Device driver routines and interface implementation + */ + +static int coldfire_spi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct coldfire_spi_master *platform_info; + struct spi_master *master; + struct driver_data *drv_data = 0; + struct resource *memory_resource; + int irq; + int status = 0; + int i; + + platform_info = (struct coldfire_spi_master *)pdev->dev.platform_data; + + master = spi_alloc_master(dev, sizeof(struct driver_data)); + if (!master) + return -ENOMEM; + + drv_data = spi_master_get_devdata(master); + drv_data->master = master; + + INIT_LIST_HEAD(&drv_data->queue); + spin_lock_init(&drv_data->lock); + + master->bus_num = platform_info->bus_num; + master->num_chipselect = platform_info->num_chipselect; + master->cleanup = cleanup; + master->setup = setup; + master->transfer = transfer; + + drv_data->cs_control = platform_info->cs_control; + if (drv_data->cs_control) + for(i = 0; i < master->num_chipselect; i++) + drv_data->cs_control(i, QSPI_CS_INIT | QSPI_CS_DROP); + + /* Setup register addresses */ + memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spi-module"); + if (!memory_resource) { + dev_dbg(dev, "can not find platform module memory\n"); + goto out_error_master_alloc; + } + +#if defined(SPI_DSPI_EDMA) + drv_data->edma_tx_buf = kmalloc(EDMA_BUFSIZE_KMALLOC, GFP_DMA); + if (!drv_data->edma_tx_buf) { + dev_dbg(dev, "cannot allocate eDMA TX memory\n"); + goto out_error_master_alloc; + } + drv_data->edma_rx_buf = kmalloc(EDMA_BUFSIZE_KMALLOC, GFP_DMA); + if (!drv_data->edma_rx_buf) { + kfree(drv_data->edma_tx_buf); + dev_dbg(dev, "cannot allocate eDMA RX memory\n"); + goto out_error_master_alloc; + } +#endif + +#if defined(SPI_DSPI) + + drv_data->mcr = (void *)(memory_resource->start + 0x00000000); + drv_data->ctar = (void *)(memory_resource->start + 0x0000000C); + drv_data->dspi_sr = (void *)(memory_resource->start + 0x0000002C); + drv_data->dspi_rser = (void *)(memory_resource->start + 0x00000030); + drv_data->dspi_dtfr = (void *)(memory_resource->start + 0x00000034); + drv_data->dspi_drfr = (void *)(memory_resource->start + 0x00000038); + +#else + + drv_data->qmr = (void *)(memory_resource->start + 0x00000000); + drv_data->qdlyr = (void *)(memory_resource->start + 0x00000004); + drv_data->qwr = (void *)(memory_resource->start + 0x00000008); + drv_data->qir = (void *)(memory_resource->start + 0x0000000c); + drv_data->qar = (void *)(memory_resource->start + 0x00000010); + drv_data->qdr = (void *)(memory_resource->start + 0x00000014); + drv_data->qcr = (void *)(memory_resource->start + 0x00000014); + +#endif + + /* Setup register addresses */ + memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spi-par"); + if (!memory_resource) { + dev_dbg(dev, "can not find platform par memory\n"); + goto out_error_master_alloc; + } + + drv_data->par = (void *)memory_resource->start; + + /* Setup register addresses */ + memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spi-int-level"); + if (!memory_resource) { + dev_dbg(dev, "can not find platform par memory\n"); + goto out_error_master_alloc; + } + + drv_data->int_icr = (void *)memory_resource->start; + + /* Setup register addresses */ + memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spi-int-mask"); + if (!memory_resource) { + dev_dbg(dev, "can not find platform par memory\n"); + goto out_error_master_alloc; + } + + drv_data->int_mr = (void *)memory_resource->start; + + if (platform_info->irq_list) { + /* multiple IRQs */ + int *irqlist = platform_info->irq_list; + while ((irq = *irqlist++)) { + int off = *irqlist++; + int lvl = *irqlist++; + int msk = *irqlist++; + status = request_irq(irq, qspi_interrupt, IRQF_DISABLED, + dev->bus_id, drv_data); + if (status < 0) { + dev_err(&pdev->dev, + "unable to attach ColdFire DSPI interrupt\n"); + goto out_error_master_alloc; + } + + if (lvl) + *(drv_data->int_icr + off) = lvl; + + if (msk) + *drv_data->int_mr &= ~msk; + } + } + else { + irq = platform_info->irq_vector; + + status = request_irq(platform_info->irq_vector, qspi_interrupt, + IRQF_DISABLED, dev->bus_id, drv_data); + if (status < 0) { + dev_err(&pdev->dev, "unable to attach ColdFire QSPI interrupt\n"); + goto out_error_master_alloc; + } + + *drv_data->int_icr = platform_info->irq_lp; + *drv_data->int_mr &= ~platform_info->irq_mask; + } + + /* Now that we have all the addresses etc. Let's set it up */ + if (platform_info->par_val) + *drv_data->par = platform_info->par_val; + +#ifdef CONFIG_M5227x + MCF_GPIO_PAR_IRQ = 0x04; /* Mistake in RM documentation */ +#endif + +#ifdef SPI_DSPI + drv_data->dspi_ctas = 0; /* TBD: change later */ +#endif + + /* Initial and start queue */ + status = init_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "problem initializing queue\n"); + goto out_error_irq_alloc; + } + status = start_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "problem starting queue\n"); + goto out_error_irq_alloc; + } + + /* Register with the SPI framework */ + platform_set_drvdata(pdev, drv_data); + status = spi_register_master(master); + if (status != 0) { + dev_err(&pdev->dev, "problem registering spi master\n"); + status = -EINVAL; + goto out_error_queue_alloc; + } + +#if defined(SPI_DSPI_EDMA) + if (mcf_edma_request_channel(DSPI_DMA_TX_TCD, + edma_tx_handler, + NULL, + pdev, + NULL, /* spinlock */ + DRIVER_NAME + )!=0) { + dev_err(&pdev->dev, "problem requesting edma transmit channel\n"); + status = -EINVAL; + goto out_error_queue_alloc; + } + + if (mcf_edma_request_channel(DSPI_DMA_RX_TCD, + edma_rx_handler, + NULL, + pdev, + NULL, /* spinlock */ + DRIVER_NAME + )!=0) { + dev_err(&pdev->dev, "problem requesting edma receive channel\n"); + status = -EINVAL; + goto out_edma_transmit; + } +#endif + + printk(KERN_INFO "SPI: Coldfire master initialized\n" ); + return status; + +#if defined(SPI_DSPI_EDMA) +out_edma_transmit: + mcf_edma_free_channel(DSPI_DMA_TX_TCD, pdev); +#endif + +out_error_queue_alloc: + destroy_queue(drv_data); + +out_error_irq_alloc: + free_irq(irq, drv_data); + +out_error_master_alloc: + spi_master_put(master); + return status; + +} + +static int coldfire_spi_remove(struct platform_device *pdev) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int irq; + int status = 0; + + if (!drv_data) + return 0; + +#if defined(SPI_DSPI_EDMA) + mcf_edma_free_channel(DSPI_DMA_TX_TCD, pdev); + mcf_edma_free_channel(DSPI_DMA_RX_TCD, pdev); +#endif + + /* Remove the queue */ + status = destroy_queue(drv_data); + if (status != 0) + return status; + + /* Release IRQ */ +/* JKM -- check for list and remove list */ + irq = platform_get_irq(pdev, 0); + if (irq >= 0) + free_irq(irq, drv_data); + + /* Disconnect from the SPI framework */ + spi_unregister_master(drv_data->master); + + /* Prevent double remove */ + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static void coldfire_spi_shutdown(struct platform_device *pdev) +{ + int status = 0; + + if ((status = coldfire_spi_remove(pdev)) != 0) + dev_err(&pdev->dev, "shutdown failed with %d\n", status); +} + + +#ifdef CONFIG_PM +static int suspend_devices(struct device *dev, void *pm_message) +{ + pm_message_t *state = pm_message; + + if (dev->power.power_state.event != state->event) { + dev_warn(dev, "pm state does not match request\n"); + return -1; + } + + return 0; +} + +static int coldfire_spi_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int status = 0; + + /* Check all childern for current power state */ + if (device_for_each_child(&pdev->dev, &state, suspend_devices) != 0) { + dev_warn(&pdev->dev, "suspend aborted\n"); + return -1; + } + + status = stop_queue(drv_data); + if (status != 0) + return status; + + return 0; +} + +static int coldfire_spi_resume(struct platform_device *pdev) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int status = 0; + + /* Start the queue running */ + status = start_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "problem starting queue (%d)\n", status); + return status; + } + + return 0; +} +#else +#define coldfire_spi_suspend NULL +#define coldfire_spi_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver driver = { + .driver = { + .name = "spi_coldfire", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + }, + .probe = coldfire_spi_probe, + .remove = __devexit_p(coldfire_spi_remove), + .shutdown = coldfire_spi_shutdown, + .suspend = coldfire_spi_suspend, + .resume = coldfire_spi_resume, +}; + +static int __init coldfire_spi_init(void) +{ + platform_driver_register(&driver); + + return 0; +} +module_init(coldfire_spi_init); + +static void __exit coldfire_spi_exit(void) +{ + platform_driver_unregister(&driver); +} +module_exit(coldfire_spi_exit); --- /dev/null +++ b/drivers/spi/spi-m5445x.c @@ -0,0 +1,156 @@ +/***************************************************************************/ +/* + * linux/arch/m68k/coldfire/spi-m5445x.c + * + * Sub-architcture dependant initialization code for the Freescale + * 5445x SPI module + * + * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com + * Copyright Freescale Semiconductor, Inc 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define SPI_NUM_CHIPSELECTS 0x10 +#define SPI_PAR_VAL (0 | MCF_GPIO_PAR_DSPI_PCS5_PCS5 | MCF_GPIO_PAR_DSPI_PCS2_PCS2 \ + | MCF_GPIO_PAR_DSPI_PCS1_PCS1 | MCF_GPIO_PAR_DSPI_PCS0_PCS0 | MCF_GPIO_PAR_DSPI_SIN_SIN \ + | MCF_GPIO_PAR_DSPI_SOUT_SOUT | MCF_GPIO_PAR_DSPI_SCK_SCK) + +#define MCF5445x_DSPI_IRQ_SOURCE (31) +#define MCF5445x_DSPI_IRQ_VECTOR (64 + MCF5445x_DSPI_IRQ_SOURCE) + +#define MCF5445x_DSPI_PAR (0xFC0A4063) +#define MCF5445x_DSPI_MCR (0xFC05C000) +#define MCF5445x_INTC0_ICR (0xFC048040) +#define MCF5445x_INTC0_IMRL (0xFC04800C) + + +#define M5445x_AUDIO_IRQ_SOURCE 49 +#define M5445x_AUDIO_IRQ_VECTOR (128+M5445x_AUDIO_IRQ_SOURCE) +#define M5445x_AUDIO_IRQ_LEVEL 4 + +void coldfire_qspi_cs_control(u8 cs, u8 command) +{ +} + +#if defined(CONFIG_SPI_COLDFIRE_SSI_AUDIO) +static struct coldfire_spi_chip ssi_audio_chip_info = { + .mode = SPI_MODE_0, + .bits_per_word = 16, + .del_cs_to_clk = 16, + .del_after_trans = 16, + .void_write_data = 0 +}; + +#endif + +static struct spi_board_info spi_board_info[] = { + +#if defined(CONFIG_SPI_COLDFIRE_SSI_AUDIO) + { + .modalias = "ssi_audio", + .max_speed_hz = 300000, + .bus_num = 1, + .chip_select = 5, + .irq = M5445x_AUDIO_IRQ_VECTOR, + .platform_data = NULL, + .controller_data = &ssi_audio_chip_info + } +#endif + +}; + +static struct coldfire_spi_master coldfire_master_info = { + .bus_num = 1, + .num_chipselect = SPI_NUM_CHIPSELECTS, + .irq_source = MCF5445x_DSPI_IRQ_SOURCE, + .irq_vector = MCF5445x_DSPI_IRQ_VECTOR, + .irq_mask = (0x01 << MCF5445x_DSPI_IRQ_SOURCE), + .irq_lp = 0x2, /* Level */ + .par_val = SPI_PAR_VAL, +// .par_val16 = SPI_PAR_VAL, + .cs_control = coldfire_qspi_cs_control, +}; + +static struct resource coldfire_spi_resources[] = { + [0] = { + .name = "qspi-par", + .start = MCF5445x_DSPI_PAR, + .end = MCF5445x_DSPI_PAR, + .flags = IORESOURCE_MEM + }, + + [1] = { + .name = "qspi-module", + .start = MCF5445x_DSPI_MCR, + .end = MCF5445x_DSPI_MCR + 0xB8, + .flags = IORESOURCE_MEM + }, + + [2] = { + .name = "qspi-int-level", + .start = MCF5445x_INTC0_ICR + MCF5445x_DSPI_IRQ_SOURCE, + .end = MCF5445x_INTC0_ICR + MCF5445x_DSPI_IRQ_SOURCE, + .flags = IORESOURCE_MEM + }, + + [3] = { + .name = "qspi-int-mask", + .start = MCF5445x_INTC0_IMRL, + .end = MCF5445x_INTC0_IMRL, + .flags = IORESOURCE_MEM + } +}; + +static struct platform_device coldfire_spi = { + .name = "spi_coldfire", //"coldfire-qspi", + .id = -1, + .resource = coldfire_spi_resources, + .num_resources = ARRAY_SIZE(coldfire_spi_resources), + .dev = { + .platform_data = &coldfire_master_info, + } +}; + +static int __init spi_dev_init(void) +{ + int retval = 0; + + retval = platform_device_register(&coldfire_spi); + + if (retval < 0) { + printk(KERN_ERR "SPI-m5445x: platform_device_register failed with code=%d\n", retval); + goto out; + } + + if (ARRAY_SIZE(spi_board_info)) + retval = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); + + +out: + return retval; +} + +arch_initcall(spi_dev_init); --- /dev/null +++ b/drivers/spi/ssi_audio.c @@ -0,0 +1,921 @@ +/* + * MCF5445x audio driver. + * + * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com + * Copyright Freescale Semiconductor, Inc. 2006, 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef CONFIG_M5445X +#include +#include +#include +#endif + +#define SOUND_DEVICE_NAME "sound" +#define DRIVER_NAME "ssi_audio" + +/* #define AUDIO_DEBUG */ + +#ifdef CONFIG_MMU +#define USE_MMU +#endif + +#define MAX_SPEED_HZ 12000000 + +#define M5445x_AUDIO_IRQ_SOURCE 49 +#define M5445x_AUDIO_IRQ_VECTOR (128+M5445x_AUDIO_IRQ_SOURCE) +#define M5445x_AUDIO_IRQ_LEVEL 5 + +/* TLV320DAC23 audio chip registers */ + +#define CODEC_LEFT_IN_REG (0x00) +#define CODEC_RIGHT_IN_REG (0x01) +#define CODEC_LEFT_HP_VOL_REG (0x02) +#define CODEC_RIGHT_HP_VOL_REG (0x03) +#define CODEC_ANALOG_APATH_REG (0x04) +#define CODEC_DIGITAL_APATH_REG (0x05) +#define CODEC_POWER_DOWN_REG (0x06) +#define CODEC_DIGITAL_IF_FMT_REG (0x07) +#define CODEC_SAMPLE_RATE_REG (0x08) +#define CODEC_DIGITAL_IF_ACT_REG (0x09) +#define CODEC_RESET_REG (0x0f) + +#define CODEC_SAMPLE_8KHZ (0x0C) +#define CODEC_SAMPLE_16KHZ (0x58) +#define CODEC_SAMPLE_22KHZ (0x62) +#define CODEC_SAMPLE_32KHZ (0x18) +#define CODEC_SAMPLE_44KHZ (0x22) +#define CODEC_SAMPLE_48KHZ (0x00) + +/* Audio buffer data size */ +#define BUFSIZE (64*1024) +/* DMA transfer size */ +#define DMASIZE (16*1024) + +/* eDMA channel for SSI channel 0 TX */ +#define DMA_TCD MCF_EDMA_CHAN_TIMER2 +/* eDMA channel for SSI channel 1 TX */ +#define DMA_TCD2 MCF_EDMA_CHAN_TIMER3 + +struct ssi_audio { + struct spi_device *spi; + u32 speed; + u32 stereo; + u32 bits; + u32 format; + u8 isopen; + u8 dmaing; + u8 ssi_enabled; + u8 channel; + spinlock_t lock; + u8* audio_buf; +}; + +static struct ssi_audio* audio_device = NULL; +volatile u32 audio_start; +volatile u32 audio_count; +volatile u32 audio_append; +volatile u32 audio_appstart; +volatile u32 audio_txbusy; + +struct ssi_audio_format { + unsigned int format; + unsigned int bits; +} ssi_audio_formattable[] = { + { AFMT_MU_LAW, 8 }, + { AFMT_A_LAW, 8 }, + { AFMT_IMA_ADPCM, 8 }, + { AFMT_U8, 8 }, + { AFMT_S16_LE, 16 }, + { AFMT_S16_BE, 16 }, + { AFMT_S8, 8 }, + { AFMT_U16_LE, 16 }, + { AFMT_U16_BE, 16 }, +}; + +#define FORMATSIZE (sizeof(ssi_audio_formattable) / sizeof(struct ssi_audio_format)) + +static void ssi_audio_setsamplesize(int val) +{ + int i; + + if (audio_device == NULL) return; + + for (i = 0; (i < FORMATSIZE); i++) { + if (ssi_audio_formattable[i].format == val) { + audio_device->format = ssi_audio_formattable[i].format; + audio_device->bits = ssi_audio_formattable[i].bits; + break; + } + } + +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_setsamplesize %d %d\n", + audio_device->format, audio_device->bits); +#endif +} + +static void ssi_audio_txdrain(void) +{ +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_txdrain()\n"); +#endif + + if (audio_device == NULL) return; + + while (!signal_pending(current)) { + if (audio_txbusy == 0) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } +} + +#ifdef CONFIG_SSIAUDIO_USE_EDMA +/* + * Configure and start DMA engine. + */ +void __inline__ ssi_audio_dmarun(void) +{ + set_edma_params(DMA_TCD, +#ifdef USE_MMU + virt_to_phys(&(audio_device->audio_buf[audio_start])), +#else + (u32)&(audio_device->audio_buf[audio_start]), +#endif + (u32)&MCF_SSI_TX0, + MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, + 8, + 4, + 0, + audio_count/8, + audio_count/8, + 0, + 0, + 0, // major_int + 0 // disable_req + ); + + set_edma_params(DMA_TCD2, +#ifdef USE_MMU + virt_to_phys(&(audio_device->audio_buf[audio_start+4])), +#else + (u32)&(audio_device->audio_buf[audio_start+4]), +#endif + (u32)&MCF_SSI_TX1, + MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, + 8, + 4, + 0, + audio_count/8, + audio_count/8, + 0, + 0, + 1, // major_int + 0 // disable_req + ); + + audio_device->dmaing = 1; + audio_txbusy = 1; + + start_edma_transfer(DMA_TCD); + start_edma_transfer(DMA_TCD2); +} + +/** + * ssi_audio_dmabuf - Start DMA'ing a new buffer of data if any available. + */ +static void ssi_audio_dmabuf(void) +{ +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_dmabuf(): append=%x start=%x\n", + audio_append, audio_appstart); +#endif + + /* If already running then nothing to do... */ + if (audio_device->dmaing) + return; + + /* Set DMA buffer size */ + audio_count = (audio_append >= audio_appstart) ? + (audio_append - audio_appstart) : + (BUFSIZE - audio_appstart); + if (audio_count > DMASIZE) + audio_count = DMASIZE; + + /* Adjust pointers and counters accordingly */ + audio_appstart += audio_count; + if (audio_appstart >= BUFSIZE) + audio_appstart = 0; + + if (audio_count > 0) + ssi_audio_dmarun(); + else { + audio_txbusy = 0; +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":DMA buffer is empty!\n"); +#endif + } +} + +void __inline__ stop_dma(void) +{ + stop_edma_transfer(DMA_TCD); + stop_edma_transfer(DMA_TCD2); +} + +static int ssi_audio_dma_handler_empty(int channel, void *dev_id) +{ + return IRQ_HANDLED; +} + +static int ssi_audio_dma_handler(int channel, void *dev_id) +{ +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_dma_handler(channel=%d)\n", channel); +#endif + + /* Clear DMA interrupt */ + stop_dma(); + + audio_device->dmaing = 0; + + /* Update data pointers and counts */ + audio_start += audio_count; + if (audio_start >= BUFSIZE) + audio_start = 0; + audio_count = 0; + + /* Start new DMA buffer if we can */ + ssi_audio_dmabuf(); + + return IRQ_HANDLED; +} + +static void init_dma(void) +{ + /* SSI DMA Signals mapped to DMA request */ + MCF_CCM_MISCCR &= ~MCF_CCM_MISCCR_TIMDMA; + init_edma(); +} + +#endif /* CONFIG_SSIAUDIO_USE_EDMA */ + +/* Write CODEC register using SPI + * address - CODEC register address + * data - data to be written into register + */ +static int codec_write(u8 addr, u16 data) +{ + u16 spi_word; + + if (audio_device==NULL || audio_device->spi==NULL) + return -ENODEV; + + spi_word = ((addr & 0x7F)<<9)|(data & 0x1FF); + return spi_write(audio_device->spi, (const u8*)&spi_word, + sizeof(spi_word)); +} + +static inline void enable_ssi(void) +{ + if (audio_device==NULL || audio_device->ssi_enabled) return; + audio_device->ssi_enabled = 1; + MCF_SSI_CR |= MCF_SSI_CR_SSI_EN; /* enable SSI module */ + MCF_SSI_CR |= MCF_SSI_CR_TE; /* enable tranmitter */ +} + +static inline void disable_ssi(void) +{ + if (audio_device==NULL || audio_device->ssi_enabled==0) return; + MCF_SSI_CR &= ~MCF_SSI_CR_TE; /* disable transmitter */ + MCF_SSI_CR &= ~MCF_SSI_CR_SSI_EN; /* disable SSI module */ + audio_device->ssi_enabled = 0; +} + +/* Audio CODEC initialization */ +static void adjust_codec_speed(void) { +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":adjust_codec_speed: %d\n", audio_device->speed); +#endif + disable_ssi(); + switch (audio_device->speed) { + case 8000: + MCF_CCM_CDR = MCF_CCM_CDR_SSIDIV(255); + codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_8KHZ); + break; + case 16000: + MCF_CCM_CDR = MCF_CCM_CDR_SSIDIV(129); + codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_16KHZ); + break; + case 22000: + case 22050: + MCF_CCM_CDR = MCF_CCM_CDR_SSIDIV(94); + codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_22KHZ); + break; + case 44000: + case 44100: + MCF_CCM_CDR = MCF_CCM_CDR_SSIDIV(47); + codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_44KHZ); + break; + case 48000: + MCF_CCM_CDR = MCF_CCM_CDR_SSIDIV(42); + codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_48KHZ); + break; + default: + MCF_CCM_CDR = MCF_CCM_CDR_SSIDIV(47); + codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_44KHZ); + } +} + +static void codec_reset(void) +{ + codec_write(CODEC_RESET_REG, 0); /* reset the audio chip */ + udelay(1500); /* wait for reset */ +} + +static void init_audio_codec(void) +{ +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":init_audio_codec()\n"); +#endif + codec_reset(); + + codec_write(CODEC_LEFT_IN_REG, 0x017); + codec_write(CODEC_RIGHT_IN_REG, 0x017); + codec_write(CODEC_POWER_DOWN_REG, 0x000); /* Turn off line input */ + codec_write(CODEC_DIGITAL_IF_FMT_REG, 0x00A); /* I2S slave mode */ + /* codec_write(CODEC_DIGITAL_IF_FMT_REG, 0x042); // I2S master mode */ + codec_write(CODEC_DIGITAL_APATH_REG, 0x007); /* Set A path */ + + /* set sample rate */ + adjust_codec_speed(); + + codec_write(CODEC_LEFT_HP_VOL_REG, 0x075); /* set volume */ + codec_write(CODEC_RIGHT_HP_VOL_REG, 0x075); /* set volume */ + codec_write(CODEC_DIGITAL_IF_ACT_REG, 1); /* Activate digital interface */ + codec_write(CODEC_ANALOG_APATH_REG, 0x0F2); +} + + +static void chip_init(void) +{ +#ifdef CONFIG_SSIAUDIO_USE_EDMA + init_dma(); +#endif + + /* Enable the SSI pins */ + MCF_GPIO_PAR_SSI = (0 + | MCF_GPIO_PAR_SSI_MCLK + | MCF_GPIO_PAR_SSI_STXD(3) + | MCF_GPIO_PAR_SSI_SRXD(3) + | MCF_GPIO_PAR_SSI_FS(3) + | MCF_GPIO_PAR_SSI_BCLK(3) ); +} + +static void init_ssi(void) +{ +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":init_ssi()\n"); +#endif + + /* Dividers are for MCF54445 on 266Mhz, the output is 44.1Khz*/ + /* Enable SSI clock in CCM */ + MCF_CCM_CDR = MCF_CCM_CDR_SSIDIV(47); + + /* Issue a SSI reset */ + MCF_SSI_CR &= ~MCF_SSI_CR_SSI_EN; /* disable SSI module */ + + /* SSI module uses internal CPU clock */ + MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSISRC; + + MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSIPUE; + MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSIPUS_UP; + + MCF_SSI_CR = 0 + | MCF_SSI_CR_CIS + | MCF_SSI_CR_TCH /* Enable two channel mode */ + | MCF_SSI_CR_MCE /* Set clock out on SSI_MCLK pin */ + | MCF_SSI_CR_I2S_MASTER /* Set I2S master mode */ + | MCF_SSI_CR_SYN /* Enable synchronous mode */ + | MCF_SSI_CR_NET + ; + + MCF_SSI_TCR = 0 + | MCF_SSI_TCR_TXDIR /* internally generated bit clock */ + | MCF_SSI_TCR_TFDIR /* internally generated frame sync */ + | MCF_SSI_TCR_TSCKP /* Clock data on falling edge of bit clock */ + | MCF_SSI_TCR_TFSI /* Frame sync active low */ + | MCF_SSI_TCR_TEFS /* TX frame sync 1 bit before data */ + | MCF_SSI_TCR_TFEN0 /* TX FIFO 0 enabled */ + | MCF_SSI_TCR_TFEN1 /* TX FIFO 1 enabled */ + | MCF_SSI_TCR_TXBIT0 + ; + + MCF_SSI_CCR = MCF_SSI_CCR_WL(7) /* 16 bit word length */ + | MCF_SSI_CCR_DC(1) /* Frame rate divider */ + | MCF_SSI_CCR_PM(0) + | MCF_SSI_CCR_DIV2 + ; + + MCF_SSI_FCSR = 0 + | MCF_SSI_FCSR_TFWM0(2) + | MCF_SSI_FCSR_TFWM1(2) + ; + + MCF_SSI_IER = 0 // interrupts +#ifndef CONFIG_SSIAUDIO_USE_EDMA + | MCF_SSI_IER_TIE /* transmit interrupts */ + | MCF_SSI_IER_TFE0 /* transmit FIFO 0 empty */ + | MCF_SSI_IER_TFE1 /* transmit FIFO 1 empty */ +#else + | MCF_SSI_IER_TDMAE /* DMA request enabled */ + | MCF_SSI_IER_TFE0 /* transmit FIFO 0 empty */ + | MCF_SSI_IER_TFE1 /* transmit FIFO 1 empty */ +#endif + ; + +#ifndef CONFIG_SSIAUDIO_USE_EDMA + /* enable IRQ: SSI interrupt */ + MCF_INTC1_ICR(M5445x_AUDIO_IRQ_SOURCE) = M5445x_AUDIO_IRQ_LEVEL; + MCF_INTC1_CIMR = M5445x_AUDIO_IRQ_SOURCE; +#endif +} + +#ifndef CONFIG_SSIAUDIO_USE_EDMA +/* interrupt for SSI */ +static int ssi_audio_isr(int irq, void *dev_id) +{ + unsigned long *bp; + + if (audio_txbusy==0) + return IRQ_HANDLED; + + spin_lock(&(audio_device->lock)); + + if (audio_start == audio_append) { + disable_ssi(); + audio_txbusy = 0; + } else { + if (MCF_SSI_ISR & (MCF_SSI_ISR_TFE0|MCF_SSI_ISR_TFE1)) { + bp = (unsigned long *) &audio_device->audio_buf[audio_start]; + if (audio_device->channel) { + MCF_SSI_TX1 = *bp; + audio_device->channel = 0; + } else { + MCF_SSI_TX0 = *bp; + audio_device->channel = 1; + } + audio_start += 4; + if (audio_start >= BUFSIZE) + audio_start = 0; + } + } + + spin_unlock(&(audio_device->lock)); + + return IRQ_HANDLED; +} +#endif + +/* Set initial driver playback defaults. */ +static void init_driver_variables(void) +{ + audio_device->speed = 44100; + audio_device->format = AFMT_S16_LE; + audio_device->bits = 16; + audio_device->stereo = 1; + audio_device->ssi_enabled = 0; + + audio_start = 0; + audio_count = 0; + audio_append = 0; + audio_appstart = 0; + audio_txbusy = 0; + audio_device->dmaing = 0; +} + +/* open audio device */ +static int ssi_audio_open(struct inode *inode, struct file *filp) +{ +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_open()\n"); +#endif + + if (audio_device==NULL) return (-ENODEV); + + if (audio_device->isopen) + return(-EBUSY); + + spin_lock(&(audio_device->lock)); + + audio_device->isopen = 1; + + init_driver_variables(); + init_ssi(); + init_audio_codec(); + + spin_unlock(&(audio_device->lock)); + + udelay(100); + + return 0; +} + +/* close audio device */ +static int ssi_audio_close(struct inode *inode, struct file *filp) +{ +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_close()\n"); +#endif + + if (audio_device==NULL) return (-ENODEV); + + ssi_audio_txdrain(); + + spin_lock(&(audio_device->lock)); + +#ifdef CONFIG_SSIAUDIO_USE_EDMA + stop_dma(); +#endif + disable_ssi(); + codec_reset(); + init_driver_variables(); + audio_device->isopen = 0; + + spin_unlock(&(audio_device->lock)); + return 0; +} + +/* write to audio device */ +static ssize_t ssi_audio_write(struct file *filp, const char *buf, + size_t count, loff_t *ppos) +{ + unsigned long *dp, *buflp; + unsigned short *bufwp; + unsigned char *bufbp; + unsigned int slen, bufcnt, i, s, e; + +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_write(buf=%x,count=%d)\n", + (int)buf, count); +#endif + + if (audio_device==NULL) + return (-ENODEV); + + if (count <= 0) + return 0; + + spin_lock(&(audio_device->lock)); + + buflp = (unsigned long *) buf; + bufwp = (unsigned short *) buf; + bufbp = (unsigned char *) buf; + + bufcnt = count & ~0x3; + + bufcnt <<= 1; + if (audio_device->stereo == 0) + bufcnt <<= 1; + if (audio_device->bits == 8) + bufcnt <<= 1; + +tryagain: + /* + * Get a snapshot of buffer, so we can figure out how + * much data we can fit in... + */ + s = audio_start; + e = audio_append; + dp = (unsigned long *) &(audio_device->audio_buf[e]); + + slen = ((s > e) ? (s - e) : (BUFSIZE - (e - s))) - 4; + if (slen > bufcnt) + slen = bufcnt; + if ((BUFSIZE - e) < slen) + slen = BUFSIZE - e; + + if (slen == 0) { + if (signal_pending(current)) + return(-ERESTARTSYS); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + goto tryagain; + } + + /* + * For DMA we need to have data as 32 bit + * values (since SSI TX register is 32 bit). + * So, the incoming 16 bit data must be put to buffer as 32 bit values. + * Also, the endianess is converted if needed + */ + if (audio_device->stereo) { + if (audio_device->bits == 16) { + if (audio_device->format==AFMT_S16_LE) { + /*- convert endianess, probably could be done by SSI also */ + for (i = 0; (i < slen); i += 4) { + unsigned short val = le16_to_cpu((*bufwp++)); + *dp++ = val; + } + } else { + for (i = 0; (i < slen); i += 4) { + *dp++ = *bufwp++; + } + } + } else { + for (i = 0; (i < slen); i += 4) { + *dp = (((unsigned long) *bufbp++) << 24); + *dp++ |= (((unsigned long) *bufbp++) << 8); + } + } + } else { + if (audio_device->bits == 16) { + for (i = 0; (i < slen); i += 4) { + *dp++ = (((unsigned long)*bufwp)<<16) | *bufwp; + bufwp++; + } + } else { + for (i = 0; (i < slen); i += 4) { + *dp++ = (((unsigned long) *bufbp) << 24) | + (((unsigned long) *bufbp) << 8); + bufbp++; + } + } + } + + e += slen; + if (e >= BUFSIZE) + e = 0; + audio_append = e; + + /* If not outputing audio, then start now */ + if (audio_txbusy == 0) { + audio_txbusy++; + audio_device->channel = 0; + enable_ssi(); +#ifdef CONFIG_SSIAUDIO_USE_EDMA + ssi_audio_dmabuf(); /* start first DMA transfer */ +#endif + } + + bufcnt -= slen; + + if (bufcnt > 0) + goto tryagain; + + spin_unlock(&(audio_device->lock)); + + return count; +} + +/* ioctl: control the driver */ +static int ssi_audio_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + long val; + int rc = 0; + +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_ioctl(cmd=%x,arg=%x)\n", + (int)cmd, (int)arg); +#endif + + if (audio_device==NULL) + return (-ENODEV); + + switch (cmd) { + + case SNDCTL_DSP_SPEED: + if (access_ok(VERIFY_READ, (void *) arg, sizeof(val))) { + get_user(val, (unsigned long *) arg); +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_ioctl: SNDCTL_DSP_SPEED: %ld\n", val); +#endif + ssi_audio_txdrain(); + audio_device->speed = val; + init_audio_codec(); + } else { + rc = -EINVAL; + } + break; + + case SNDCTL_DSP_SAMPLESIZE: + if (access_ok(VERIFY_READ, (void *) arg, sizeof(val))) { + get_user(val, (unsigned long *) arg); +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME ":ssi_audio_ioctl: SNDCTL_DSP_SAMPLESIZE: %d\n", val); +#endif + ssi_audio_txdrain(); + ssi_audio_setsamplesize(val); + } else { + rc = -EINVAL; + } + break; + + case SNDCTL_DSP_STEREO: + if (access_ok(VERIFY_READ, (void *) arg, sizeof(val))) { + get_user(val, (unsigned long *) arg); + ssi_audio_txdrain(); + audio_device->stereo = val; + } else { + rc = -EINVAL; + } + break; + + case SNDCTL_DSP_GETBLKSIZE: + if (access_ok(VERIFY_WRITE, (void *) arg, sizeof(long))) + put_user(BUFSIZE, (long *) arg); + else + rc = -EINVAL; + break; + + case SNDCTL_DSP_SYNC: + ssi_audio_txdrain(); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +struct file_operations ssi_audio_fops = { + open: ssi_audio_open, /* open */ + release: ssi_audio_close, /* close */ + write: ssi_audio_write, /* write */ + ioctl: ssi_audio_ioctl, /* ioctl */ +}; + +/* initialize audio driver */ +static int __devinit ssi_audio_probe(struct spi_device *spi) +{ + struct ssi_audio *audio; + int err; + +#ifdef AUDIO_DEBUG + printk(DRIVER_NAME": probe\n"); +#endif + + if (!spi->irq) { + dev_dbg(&spi->dev, "no IRQ?\n"); + return -ENODEV; + } + + /* don't exceed max specified sample rate */ + if (spi->max_speed_hz > MAX_SPEED_HZ) { + dev_dbg(&spi->dev, "f(sample) %d KHz?\n", + (spi->max_speed_hz)/1000); + return -EINVAL; + } + + /* register charcter device */ + if (register_chrdev(SOUND_MAJOR, SOUND_DEVICE_NAME, &ssi_audio_fops) < 0) { + printk(KERN_WARNING DRIVER_NAME ": failed to register major %d\n", SOUND_MAJOR); + dev_dbg(&spi->dev, DRIVER_NAME ": failed to register major %d\n", SOUND_MAJOR); + return -ENODEV; + } + + audio = kzalloc(sizeof(struct ssi_audio), GFP_KERNEL); + if (!audio) { + err = -ENOMEM; + goto err_out; + } + + /* DMA buffer must be from GFP_DMA zone, so it will not be cached */ + audio->audio_buf = kmalloc(BUFSIZE, GFP_DMA); + if (audio->audio_buf == NULL) { + dev_dbg(&spi->dev, DRIVER_NAME ": failed to allocate DMA[%d] buffer\n", BUFSIZE); + err = -ENOMEM; + goto err_free_mem; + } + + audio_device = audio; + + dev_set_drvdata(&spi->dev, audio); + spi->dev.power.power_state = PMSG_ON; + + audio->spi = spi; + +#ifndef CONFIG_SSIAUDIO_USE_EDMA + if (request_irq(spi->irq, ssi_audio_isr, IRQF_DISABLED, spi->dev.bus_id, audio)) { + dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); + err = -EBUSY; + goto err_free_mem; + } + +#else + /* request 2 eDMA channels since two channel output mode is used */ + if (request_edma_channel(DMA_TCD, + ssi_audio_dma_handler_empty, + NULL, + audio, + &(audio_device->lock), + DRIVER_NAME)!=0) { + dev_dbg(&spi->dev, "DMA channel %d busy?\n", DMA_TCD); + err = -EBUSY; + goto err_free_mem; + } + if (request_edma_channel(DMA_TCD2, + ssi_audio_dma_handler, + NULL, + audio, + &(audio_device->lock), + DRIVER_NAME)!=0) { + dev_dbg(&spi->dev, "DMA channel %d busy?\n", DMA_TCD2); + err = -EBUSY; + goto err_free_mem; + } + +#endif + chip_init(); + printk(DRIVER_NAME ": Probed successfully\n"); + + return 0; + + err_free_mem: + kfree(audio); + audio_device = NULL; + err_out: + unregister_chrdev(SOUND_MAJOR, SOUND_DEVICE_NAME); + return err; +} + +static int __devexit ssi_audio_remove(struct spi_device *spi) +{ + struct ssi_audio *audio = dev_get_drvdata(&spi->dev); + + ssi_audio_txdrain(); +#ifndef CONFIG_SSIAUDIO_USE_EDMA + free_irq(spi->irq, audio); +#else + free_edma_channel(DMA_TCD, audio); + free_edma_channel(DMA_TCD2, audio); +#endif + kfree(audio->audio_buf); + kfree(audio); + audio_device = NULL; + unregister_chrdev(SOUND_MAJOR, SOUND_DEVICE_NAME); + dev_dbg(&spi->dev, "unregistered audio\n"); + return 0; +} + +static int ssi_audio_suspend(struct spi_device *spi, pm_message_t message) +{ + return 0; +} + +static int ssi_audio_resume(struct spi_device *spi) +{ + return 0; +} + +static struct spi_driver ssi_audio_driver = { + .driver = { + .name = DRIVER_NAME, + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ssi_audio_probe, + .remove = __devexit_p(ssi_audio_remove), + .suspend = ssi_audio_suspend, + .resume = ssi_audio_resume, +}; + +static int __init ssi_audio_init(void) +{ + return spi_register_driver(&ssi_audio_driver); +} +module_init(ssi_audio_init); + +static void __exit ssi_audio_exit(void) +{ + spi_unregister_driver(&ssi_audio_driver); +} +module_exit(ssi_audio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("SSI/I2S Audio Driver"); --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -287,6 +287,9 @@ MODULE_PARM_DESC(host_addr, "Host Ethern #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_MCF5445X +#define DEV_CONFIG_CDC +#endif /*-------------------------------------------------------------------------*/ --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -83,16 +83,6 @@ struct usb_dr_host { u32 endptctrl[6]; /* Endpoint Control Registers */ }; - /* non-EHCI USB system interface registers (Big Endian) */ -struct usb_sys_interface { - u32 snoop1; - u32 snoop2; - u32 age_cnt_thresh; /* Age Count Threshold Register */ - u32 pri_ctrl; /* Priority Control Register */ - u32 si_ctrl; /* System Interface Control Register */ - u8 res[236]; - u32 control; /* General Purpose Control Register */ -}; /* ep0 transfer state */ #define WAIT_FOR_SETUP 0 @@ -101,10 +91,6 @@ struct usb_sys_interface { #define WAIT_FOR_OUT_STATUS 3 #define DATA_STATE_RECV 4 -/* Device Controller Capability Parameter register */ -#define DCCPARAMS_DC 0x00000080 -#define DCCPARAMS_DEN_MASK 0x0000001f - /* Frame Index Register Bit Masks */ #define USB_FRINDEX_MASKS 0x3fff /* USB CMD Register Bit Masks */ @@ -180,172 +166,6 @@ struct usb_sys_interface { /* endpoint list address bit masks */ #define USB_EP_LIST_ADDRESS_MASK 0xfffff800 -/* PORTSCX Register Bit Masks */ -#define PORTSCX_CURRENT_CONNECT_STATUS 0x00000001 -#define PORTSCX_CONNECT_STATUS_CHANGE 0x00000002 -#define PORTSCX_PORT_ENABLE 0x00000004 -#define PORTSCX_PORT_EN_DIS_CHANGE 0x00000008 -#define PORTSCX_OVER_CURRENT_ACT 0x00000010 -#define PORTSCX_OVER_CURRENT_CHG 0x00000020 -#define PORTSCX_PORT_FORCE_RESUME 0x00000040 -#define PORTSCX_PORT_SUSPEND 0x00000080 -#define PORTSCX_PORT_RESET 0x00000100 -#define PORTSCX_LINE_STATUS_BITS 0x00000C00 -#define PORTSCX_PORT_POWER 0x00001000 -#define PORTSCX_PORT_INDICTOR_CTRL 0x0000C000 -#define PORTSCX_PORT_TEST_CTRL 0x000F0000 -#define PORTSCX_WAKE_ON_CONNECT_EN 0x00100000 -#define PORTSCX_WAKE_ON_CONNECT_DIS 0x00200000 -#define PORTSCX_WAKE_ON_OVER_CURRENT 0x00400000 -#define PORTSCX_PHY_LOW_POWER_SPD 0x00800000 -#define PORTSCX_PORT_FORCE_FULL_SPEED 0x01000000 -#define PORTSCX_PORT_SPEED_MASK 0x0C000000 -#define PORTSCX_PORT_WIDTH 0x10000000 -#define PORTSCX_PHY_TYPE_SEL 0xC0000000 - -/* bit 11-10 are line status */ -#define PORTSCX_LINE_STATUS_SE0 0x00000000 -#define PORTSCX_LINE_STATUS_JSTATE 0x00000400 -#define PORTSCX_LINE_STATUS_KSTATE 0x00000800 -#define PORTSCX_LINE_STATUS_UNDEF 0x00000C00 -#define PORTSCX_LINE_STATUS_BIT_POS 10 - -/* bit 15-14 are port indicator control */ -#define PORTSCX_PIC_OFF 0x00000000 -#define PORTSCX_PIC_AMBER 0x00004000 -#define PORTSCX_PIC_GREEN 0x00008000 -#define PORTSCX_PIC_UNDEF 0x0000C000 -#define PORTSCX_PIC_BIT_POS 14 - -/* bit 19-16 are port test control */ -#define PORTSCX_PTC_DISABLE 0x00000000 -#define PORTSCX_PTC_JSTATE 0x00010000 -#define PORTSCX_PTC_KSTATE 0x00020000 -#define PORTSCX_PTC_SEQNAK 0x00030000 -#define PORTSCX_PTC_PACKET 0x00040000 -#define PORTSCX_PTC_FORCE_EN 0x00050000 -#define PORTSCX_PTC_BIT_POS 16 - -/* bit 27-26 are port speed */ -#define PORTSCX_PORT_SPEED_FULL 0x00000000 -#define PORTSCX_PORT_SPEED_LOW 0x04000000 -#define PORTSCX_PORT_SPEED_HIGH 0x08000000 -#define PORTSCX_PORT_SPEED_UNDEF 0x0C000000 -#define PORTSCX_SPEED_BIT_POS 26 - -/* bit 28 is parallel transceiver width for UTMI interface */ -#define PORTSCX_PTW 0x10000000 -#define PORTSCX_PTW_8BIT 0x00000000 -#define PORTSCX_PTW_16BIT 0x10000000 - -/* bit 31-30 are port transceiver select */ -#define PORTSCX_PTS_UTMI 0x00000000 -#define PORTSCX_PTS_ULPI 0x80000000 -#define PORTSCX_PTS_FSLS 0xC0000000 -#define PORTSCX_PTS_BIT_POS 30 - -/* otgsc Register Bit Masks */ -#define OTGSC_CTRL_VUSB_DISCHARGE 0x00000001 -#define OTGSC_CTRL_VUSB_CHARGE 0x00000002 -#define OTGSC_CTRL_OTG_TERM 0x00000008 -#define OTGSC_CTRL_DATA_PULSING 0x00000010 -#define OTGSC_STS_USB_ID 0x00000100 -#define OTGSC_STS_A_VBUS_VALID 0x00000200 -#define OTGSC_STS_A_SESSION_VALID 0x00000400 -#define OTGSC_STS_B_SESSION_VALID 0x00000800 -#define OTGSC_STS_B_SESSION_END 0x00001000 -#define OTGSC_STS_1MS_TOGGLE 0x00002000 -#define OTGSC_STS_DATA_PULSING 0x00004000 -#define OTGSC_INTSTS_USB_ID 0x00010000 -#define OTGSC_INTSTS_A_VBUS_VALID 0x00020000 -#define OTGSC_INTSTS_A_SESSION_VALID 0x00040000 -#define OTGSC_INTSTS_B_SESSION_VALID 0x00080000 -#define OTGSC_INTSTS_B_SESSION_END 0x00100000 -#define OTGSC_INTSTS_1MS 0x00200000 -#define OTGSC_INTSTS_DATA_PULSING 0x00400000 -#define OTGSC_INTR_USB_ID 0x01000000 -#define OTGSC_INTR_A_VBUS_VALID 0x02000000 -#define OTGSC_INTR_A_SESSION_VALID 0x04000000 -#define OTGSC_INTR_B_SESSION_VALID 0x08000000 -#define OTGSC_INTR_B_SESSION_END 0x10000000 -#define OTGSC_INTR_1MS_TIMER 0x20000000 -#define OTGSC_INTR_DATA_PULSING 0x40000000 - -/* USB MODE Register Bit Masks */ -#define USB_MODE_CTRL_MODE_IDLE 0x00000000 -#define USB_MODE_CTRL_MODE_DEVICE 0x00000002 -#define USB_MODE_CTRL_MODE_HOST 0x00000003 -#define USB_MODE_CTRL_MODE_RSV 0x00000001 -#define USB_MODE_SETUP_LOCK_OFF 0x00000008 -#define USB_MODE_STREAM_DISABLE 0x00000010 -/* Endpoint Flush Register */ -#define EPFLUSH_TX_OFFSET 0x00010000 -#define EPFLUSH_RX_OFFSET 0x00000000 - -/* Endpoint Setup Status bit masks */ -#define EP_SETUP_STATUS_MASK 0x0000003F -#define EP_SETUP_STATUS_EP0 0x00000001 - -/* ENDPOINTCTRLx Register Bit Masks */ -#define EPCTRL_TX_ENABLE 0x00800000 -#define EPCTRL_TX_DATA_TOGGLE_RST 0x00400000 /* Not EP0 */ -#define EPCTRL_TX_DATA_TOGGLE_INH 0x00200000 /* Not EP0 */ -#define EPCTRL_TX_TYPE 0x000C0000 -#define EPCTRL_TX_DATA_SOURCE 0x00020000 /* Not EP0 */ -#define EPCTRL_TX_EP_STALL 0x00010000 -#define EPCTRL_RX_ENABLE 0x00000080 -#define EPCTRL_RX_DATA_TOGGLE_RST 0x00000040 /* Not EP0 */ -#define EPCTRL_RX_DATA_TOGGLE_INH 0x00000020 /* Not EP0 */ -#define EPCTRL_RX_TYPE 0x0000000C -#define EPCTRL_RX_DATA_SINK 0x00000002 /* Not EP0 */ -#define EPCTRL_RX_EP_STALL 0x00000001 - -/* bit 19-18 and 3-2 are endpoint type */ -#define EPCTRL_EP_TYPE_CONTROL 0 -#define EPCTRL_EP_TYPE_ISO 1 -#define EPCTRL_EP_TYPE_BULK 2 -#define EPCTRL_EP_TYPE_INTERRUPT 3 -#define EPCTRL_TX_EP_TYPE_SHIFT 18 -#define EPCTRL_RX_EP_TYPE_SHIFT 2 - -/* SNOOPn Register Bit Masks */ -#define SNOOP_ADDRESS_MASK 0xFFFFF000 -#define SNOOP_SIZE_ZERO 0x00 /* snooping disable */ -#define SNOOP_SIZE_4KB 0x0B /* 4KB snoop size */ -#define SNOOP_SIZE_8KB 0x0C -#define SNOOP_SIZE_16KB 0x0D -#define SNOOP_SIZE_32KB 0x0E -#define SNOOP_SIZE_64KB 0x0F -#define SNOOP_SIZE_128KB 0x10 -#define SNOOP_SIZE_256KB 0x11 -#define SNOOP_SIZE_512KB 0x12 -#define SNOOP_SIZE_1MB 0x13 -#define SNOOP_SIZE_2MB 0x14 -#define SNOOP_SIZE_4MB 0x15 -#define SNOOP_SIZE_8MB 0x16 -#define SNOOP_SIZE_16MB 0x17 -#define SNOOP_SIZE_32MB 0x18 -#define SNOOP_SIZE_64MB 0x19 -#define SNOOP_SIZE_128MB 0x1A -#define SNOOP_SIZE_256MB 0x1B -#define SNOOP_SIZE_512MB 0x1C -#define SNOOP_SIZE_1GB 0x1D -#define SNOOP_SIZE_2GB 0x1E /* 2GB snoop size */ - -/* pri_ctrl Register Bit Masks */ -#define PRI_CTRL_PRI_LVL1 0x0000000C -#define PRI_CTRL_PRI_LVL0 0x00000003 - -/* si_ctrl Register Bit Masks */ -#define SI_CTRL_ERR_DISABLE 0x00000010 -#define SI_CTRL_IDRC_DISABLE 0x00000008 -#define SI_CTRL_RD_SAFE_EN 0x00000004 -#define SI_CTRL_RD_PREFETCH_DISABLE 0x00000002 -#define SI_CTRL_RD_PREFEFETCH_VAL 0x00000001 - -/* control Register Bit Masks */ -#define USB_CTRL_IOENB 0x00000004 -#define USB_CTRL_ULPI_INT0EN 0x00000001 /* Endpoint Queue Head data struct * Rem: all the variables of qh are LittleEndian Mode @@ -477,7 +297,10 @@ struct fsl_udc { unsigned int irq; struct usb_ctrlrequest local_setup_buff; - spinlock_t lock; + spinlock_t lock; /* udc lock */ + struct fsl_usb2_platform_data *pdata; + u32 xcvr_type; + struct otg_transceiver *transceiver; unsigned softconnect:1; unsigned vbus_active:1; @@ -514,7 +337,7 @@ struct fsl_udc { #define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \ __FUNCTION__, ## args) #else -#define DBG(fmt, args...) do{}while(0) +#define DBG(fmt, args...) do {} while (0) #endif #if 0 @@ -548,7 +371,7 @@ static void dump_msg(const char *label, #ifdef VERBOSE #define VDBG DBG #else -#define VDBG(stuff...) do{}while(0) +#define VDBG(stuff...) do {} while (0) #endif #define ERR(stuff...) pr_err("udc: " stuff) @@ -573,11 +396,14 @@ static void dump_msg(const char *label, #define ep_maxpacket(EP) ((EP)->ep.maxpacket) #define ep_is_in(EP) ( (ep_index(EP) == 0) ? (EP->udc->ep0_dir == \ USB_DIR_IN ):((EP)->desc->bEndpointAddress \ - & USB_DIR_IN)==USB_DIR_IN) + & USB_DIR_IN) == USB_DIR_IN) #define get_ep_by_pipe(udc, pipe) ((pipe == 1)? &udc->eps[0]: \ &udc->eps[pipe]) #define get_pipe_by_windex(windex) ((windex & USB_ENDPOINT_NUMBER_MASK) \ * 2 + ((windex & USB_DIR_IN) ? 1 : 0)) #define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP)) +/* Bulk only class request */ +#define USB_BULK_RESET_REQUEST 0xff + #endif --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -147,6 +147,11 @@ #define gadget_is_m66592(g) 0 #endif +#ifdef CONFIG_USB_GADGET_MCF5445X +#define gadget_is_mcf5445x(g) !strcmp("fsl-usb2-udc", (g)->name) +#else +#define gadget_is_mcf5445x(g) 0 +#endif // CONFIG_USB_GADGET_SX2 // CONFIG_USB_GADGET_AU1X00 @@ -212,5 +217,7 @@ static inline int usb_gadget_controller_ return 0x20; else if (gadget_is_m66592(gadget)) return 0x21; + else if (gadget_is_mcf5445x(gadget)) + return 0x22; return -ENOENT; } --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -231,6 +231,26 @@ config SUPERH_BUILT_IN_M66592 However, this problem is improved if change a value of NET_IP_ALIGN to 4. +config USB_GADGET_MCF5445X + boolean "MCF5445X USB Device Controller" + depends on M54455 && USB_M5445X_ULPI + select USB_GADGET_DUALSPEED + help + Freescale's MCF5445X processors include + an integrated device controller (as part of the OTG module). + It has four programmable, bidirectional endpoints, + including endpoint 0. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "mcf5445_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_MCF5445X + tristate + depends on USB_GADGET_MCF5445X + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_GOKU boolean "Toshiba TC86C001 'Goku-S'" depends on PCI @@ -285,17 +305,6 @@ config USB_OMAP default USB_GADGET select USB_GADGET_SELECTED -config USB_OTG - boolean "OTG Support" - depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD - help - The most notable feature of USB OTG is support for a - "Dual-Role" device, which can act as either a device - or a host. The initial role choice can be changed - later, when two dual-role devices talk to each other. - - Select this only if your OMAP board has a Mini-AB connector. - config USB_GADGET_S3C2410 boolean "S3C2410 USB Device Controller" depends on ARCH_S3C2410 @@ -369,6 +378,18 @@ config USB_DUMMY_HCD endchoice +config USB_OTG + boolean "OTG Support" + depends on (USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD) || \ + (USB_GADGET_MCF5445X && USB_M5445X_ULPI) + help + The most notable feature of USB OTG is support for a + "Dual-Role" device, which can act as either a device + or a host. The initial role choice can be changed + later, when two dual-role devices talk to each other. + + Select this only if your OMAP board has a Mini-AB connector. + config USB_GADGET_DUALSPEED bool depends on USB_GADGET --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o +obj-$(CONFIG_USB_MCF5445X) += mcf5445x_udc.o # # USB gadget drivers --- /dev/null +++ b/drivers/usb/gadget/mcf5445x_udc.c @@ -0,0 +1,2745 @@ +/* + * Copyright Freescale Semiconductor, Inc. 2006-2007 + * + * Based on mpc_udc.c code + * of Li Yang and Jiang Bo (Freescale Semiconductor, Inc.) + * + * + * 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 + * + *************************************************************************** + * Changes: + * v0.004 30 July 2007 Duck + * mcf5445x port + * v0.003 27 October 2006 Andrey Butok + * Added M5329EVB support (without external transceiver). + * v0.002 29 September 2006 Andrey Butok + * Some little changes. Added OTG support. + * v0.001 12 July 2006 Andrey Butok + * Initial Release - developed on uClinux with 2.6.17.1 kernel. + * Based on mpc_udc.c code + * of Li Yang and Jiang Bo (Freescale Semiconductor, Inc.) + * + */ + +#undef DEBUG +#undef VERBOSE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "fsl_usb2_udc.h" + +#define DRIVER_DESC "Freescale High-Speed USB SoC Device Controller driver" +#define DRIVER_AUTHOR "Freescale Semiconductor Inc." +#define DRIVER_VERSION "30 July 2007" + +#define cpu_to_hc32(x) (x) +#define hc32_to_cpu(x) (x) + +static int udc_suspend(struct fsl_udc *udc); + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +static const char driver_name[] = "fsl-usb2-udc"; +static const char driver_desc[] = DRIVER_DESC; + +volatile static struct fsl_usb_device_regs *dr_regs; +volatile static struct usb_sys_interface *usb_sys_regs; + +/* it is initialized in probe() */ +static struct fsl_udc *udc_controller; + +static const struct usb_endpoint_descriptor +fsl_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD, +}; + +static int fsl_udc_suspend(struct device *dev, pm_message_t state); +static int fsl_udc_resume(struct device *dev); +static void fsl_ep_fifo_flush(struct usb_ep *_ep); + +/******************************************************************** + * Internal Used Function +********************************************************************/ +/*----------------------------------------------------------------- + * done() - retire a request; caller blocked irqs + * @status : request status to be set, only works when + * request is still in progress. + *--------------------------------------------------------------*/ +static void done(struct fsl_ep *ep, struct fsl_req *req, int status) +{ + struct fsl_udc *udc = NULL; + unsigned char stopped = ep->stopped; + + udc = (struct fsl_udc *)ep->udc; + + pr_debug("udc: req=0x%p\n", req); + if (req->head) { + pr_debug("udc: freeing head=0x%p\n", req->head); + dma_pool_free(udc->td_pool, req->head, req->head->td_dma); + } + + /* the req->queue pointer is used by ep_queue() func, in which + * the request will be added into a udc_ep->queue 'd tail + * so here the req will be dropped from the ep->queue + */ + list_del_init(&req->queue); + + /* req.status should be set as -EINPROGRESS in ep_queue() */ + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + pr_debug("udc: req=0x%p mapped=%x\n", req, req->mapped); + + if (req->mapped) { + pr_debug("udc: calling dma_unmap_single(buf,%s) req=0x%p " + "a=0x%x len=%d\n", + ep_is_in(ep) ? "to_dvc" : "from_dvc", + req, req->req.dma, req->req.length); + + dma_unmap_single(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, ep_is_in(ep) ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + pr_debug("udc: req=0x%p set req.dma=0x%x\n", req, req->req.dma); + } else { + if ((req->req.length != 0) + && (req->req.dma != DMA_ADDR_INVALID)) { + pr_debug("udc: calling dma_sync_single_for_cpu(buf,%s) " + "req=0x%p dma=0x%x len=%d\n", + ep_is_in(ep) ? "to_dvc" : "from_dvc", req, + req->req.dma, req->req.length); + + dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + ep_is_in(ep) ? DMA_TO_DEVICE : + DMA_FROM_DEVICE); + } + } + + if (status && (status != -ESHUTDOWN)) { + pr_debug("udc: complete %s req 0c%p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + } + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + + spin_unlock(&ep->udc->lock); + + /* this complete() should a func implemented by gadget layer, + * eg fsg->bulk_in_complete() */ + if (req->req.complete) { + pr_debug("udc: calling gadget's complete() req=0x%p\n", req); + req->req.complete(&ep->ep, &req->req); + pr_debug("udc: back from gadget's complete()\n"); + } + + spin_lock(&ep->udc->lock); + ep->stopped = stopped; +} + +/* + * nuke(): delete all requests related to this ep + * called with spinlock held + *--------------------------------------------------------------*/ +static void nuke(struct fsl_ep *ep, int status) +{ + ep->stopped = 1; + + /* Flush fifo */ + fsl_ep_fifo_flush(&ep->ep); + + /* Whether this eq has request linked */ + while (!list_empty(&ep->queue)) { + struct fsl_req *req = NULL; + + req = list_entry(ep->queue.next, struct fsl_req, queue); + done(ep, req, status); + } +} + +/*------------------------------------------------------------------ + Internal Hardware related function + ------------------------------------------------------------------*/ + +static int dr_controller_setup(struct fsl_udc *udc) +{ + unsigned int tmp; + unsigned int __attribute((unused)) ctrl = 0; + unsigned long timeout; + struct fsl_usb2_platform_data *pdata; + +#define FSL_UDC_RESET_TIMEOUT 1000 + + /* before here, make sure dr_regs has been initialized */ + if (!udc) + return -EINVAL; + pdata = udc->pdata; + + /* Stop and reset the usb controller */ + tmp = fsl_readl(&dr_regs->usbcmd); + tmp &= ~USB_CMD_RUN_STOP; + fsl_writel(tmp, &dr_regs->usbcmd); + + tmp = fsl_readl(&dr_regs->usbcmd); + tmp |= USB_CMD_CTRL_RESET; + fsl_writel(tmp, &dr_regs->usbcmd); + + /* Wait for reset to complete */ + timeout = jiffies + FSL_UDC_RESET_TIMEOUT; + while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) { + if (time_after(jiffies, timeout)) { + ERR("udc reset timeout! \n"); + return -ETIMEDOUT; + } + cpu_relax(); + } + + tmp = fsl_readl(&dr_regs->usbmode); + tmp &= ~0x3; /* clear mode bits */ + tmp |= USB_MODE_CTRL_MODE_DEVICE; + /* Disable Setup Lockout */ + tmp |= USB_MODE_SETUP_LOCK_OFF; + if (pdata->es) + tmp |= USBMODE_ES; + fsl_writel(tmp, &dr_regs->usbmode); + + if (pdata->xcvr_ops && pdata->xcvr_ops->set_device) + pdata->xcvr_ops->set_device(); + + /* Clear the setup status */ + fsl_writel(0, &dr_regs->usbsts); + + tmp = udc->ep_qh_dma; + tmp &= USB_EP_LIST_ADDRESS_MASK; + fsl_writel(tmp, &dr_regs->endpointlistaddr); + + /* + VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x", + (int)udc->ep_qh, (int)tmp, + fsl_readl(&dr_regs->endpointlistaddr)); + */ + + + if (pdata->have_sysif_regs) { + /* Config control enable i/o output, cpu endian register */ + ctrl = __raw_readl(&usb_sys_regs->control); + ctrl |= USB_CTRL_IOENB; + __raw_writel(ctrl, &usb_sys_regs->control); + } + +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + /* Turn on cache snooping hardware, since some PowerPC platforms + * wholly rely on hardware to deal with cache coherent. */ + + if (pdata->have_sysif_regs) { + /* Setup Snooping for all the 4GB space */ + tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */ + __raw_writel(tmp, &usb_sys_regs->snoop1); + tmp |= 0x80000000; /* starts from 0x8000000, size 2G */ + __raw_writel(tmp, &usb_sys_regs->snoop2); + } +#endif + + return 0; +} + +static void pullup_enable(struct fsl_udc *udc) +{ + u32 temp; + + unsigned short ccm = fsl_readw(&MCF_CCM_UOCSR); + ccm |= MCF_CCM_UOCSR_BVLD; + ccm &= ~MCF_CCM_UOCSR_SEND; + fsl_writew(ccm, &MCF_CCM_UOCSR); + + /* Enable DR irq reg */ + temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN + | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN + | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; + + fsl_writel(temp, &dr_regs->usbintr); + + /* Set controller to Run */ + temp = fsl_readl(&dr_regs->usbcmd); + temp |= USB_CMD_RUN_STOP; + fsl_writel(temp, &dr_regs->usbcmd); +} + +static void pullup_disable(struct fsl_udc *udc) +{ + unsigned int tmp; + unsigned short ccm; + + VDBG(); + /* disable all INTRs */ + fsl_writel(0, &dr_regs->usbintr); + + ccm = fsl_readw(&MCF_CCM_UOCSR); + ccm &= ~MCF_CCM_UOCSR_BVLD; + fsl_writew(ccm, &MCF_CCM_UOCSR); + + /* set controller to Stop */ + tmp = fsl_readl(&dr_regs->usbcmd); + tmp &= ~USB_CMD_RUN_STOP; + fsl_writel(tmp, &dr_regs->usbcmd); +} + +static void dr_controller_run(struct fsl_udc *udc) +{ + VDBG(); + pullup_enable(udc); + udc->stopped = 0; +} + +static void dr_controller_stop(struct fsl_udc *udc) +{ + pullup_disable(udc); + udc->stopped = 1; + udc->gadget.b_hnp_enable = 0; + udc->gadget.a_hnp_support = 0; + udc->gadget.a_alt_hnp_support = 0; +} + +void dr_ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type) +{ + unsigned int tmp_epctrl = 0; + + tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (dir) { + if (ep_num) + tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; + tmp_epctrl |= EPCTRL_TX_ENABLE; + tmp_epctrl |= ((unsigned int)(ep_type) + << EPCTRL_TX_EP_TYPE_SHIFT); + } else { + if (ep_num) + tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; + tmp_epctrl |= EPCTRL_RX_ENABLE; + tmp_epctrl |= ((unsigned int)(ep_type) + << EPCTRL_RX_EP_TYPE_SHIFT); + } + + fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]); +} + +static void dr_ep_change_stall(unsigned char ep_num, unsigned char dir, + int value) +{ + u32 tmp_epctrl = 0; + + tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + + if (value) { + /* set the stall bit */ + if (dir) + tmp_epctrl |= EPCTRL_TX_EP_STALL; + else + tmp_epctrl |= EPCTRL_RX_EP_STALL; + } else { + /* clear the stall bit and reset data toggle */ + if (dir) { + tmp_epctrl &= ~EPCTRL_TX_EP_STALL; + tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; + } else { + tmp_epctrl &= ~EPCTRL_RX_EP_STALL; + tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; + } + } + fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]); +} + +/* Get stall status of a specific ep + Return: 0: not stalled; 1:stalled */ +static int dr_ep_get_stall(unsigned char ep_num, unsigned char dir) +{ + u32 epctrl; + + epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (dir) + return (epctrl & EPCTRL_TX_EP_STALL) ? 1 : 0; + else + return (epctrl & EPCTRL_RX_EP_STALL) ? 1 : 0; +} + +/******************************************************************** + Internal Structure Build up functions +********************************************************************/ + +/*------------------------------------------------------------------ +* struct_ep_qh_setup(): set the Endpoint Capabilites field of QH + * @zlt: Zero Length Termination Select (1: disable; 0: enable) + * @mult: Mult field + ------------------------------------------------------------------*/ +static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num, + unsigned char dir, unsigned char ep_type, + unsigned int max_pkt_len, + unsigned int zlt, unsigned char mult) +{ + struct ep_queue_head *p_QH = &udc->ep_qh[2 * ep_num + dir]; + unsigned int tmp = 0; + + /* set the Endpoint Capabilites in QH */ + switch (ep_type) { + case USB_ENDPOINT_XFER_CONTROL: + /* Interrupt On Setup (IOS). for control ep */ + tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) + | EP_QUEUE_HEAD_IOS; + break; + case USB_ENDPOINT_XFER_ISOC: + tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) + | (mult << EP_QUEUE_HEAD_MULT_POS); + break; + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS; + break; + default: + VDBG("error ep type is %d", ep_type); + return; + } + if (zlt) + tmp |= EP_QUEUE_HEAD_ZLT_SEL; + p_QH->max_pkt_length = cpu_to_hc32(tmp); + + return; +} + +/* Setup qh structure and ep register for ep0. */ +static void ep0_setup(struct fsl_udc *udc) +{ + /* the intialization of an ep includes: fields in QH, Regs, + * fsl_ep struct */ + struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, + USB_MAX_CTRL_PAYLOAD, 0, 0); + struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, + USB_MAX_CTRL_PAYLOAD, 0, 0); + dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL); + dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL); + + return; + +} + +/*********************************************************************** + Endpoint Management Functions +***********************************************************************/ + +/*------------------------------------------------------------------------- + * when configurations are set, or when interface settings change + * for example the do_set_interface() in gadget layer, + * the driver will enable or disable the relevant endpoints + * ep0 doesn't use this routine. It is always enabled. +-------------------------------------------------------------------------*/ +static int fsl_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct fsl_udc *udc = NULL; + struct fsl_ep *ep = NULL; + unsigned short max = 0; + unsigned char mult = 0, zlt; + int retval = -EINVAL; + unsigned long flags = 0; + + ep = container_of(_ep, struct fsl_ep, ep); + + /* catch various bogus parameters */ + if (!_ep || !desc || ep->desc + || (desc->bDescriptorType != USB_DT_ENDPOINT)) + return -EINVAL; + + udc = ep->udc; + + if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN)) + return -ESHUTDOWN; + + max = le16_to_cpu(desc->wMaxPacketSize); + + /* Disable automatic zlp generation. Driver is reponsible to indicate + * explicitly through req->req.zero. This is needed to enable multi-td + * request. */ + zlt = 1; + + /* Assume the max packet size from gadget is always correct */ + switch (desc->bmAttributes & 0x03) { + case USB_ENDPOINT_XFER_CONTROL: + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + /* mult = 0. Execute N Transactions as demonstrated by + * the USB variable length packet protocol where N is + * computed using the Maximum Packet Length (dQH) and + * the Total Bytes field (dTD) */ + mult = 0; + break; + case USB_ENDPOINT_XFER_ISOC: + /* Calculate transactions needed for high bandwidth iso */ + mult = (unsigned char)(1 + ((max >> 11) & 0x03)); + max = max & 0x8ff; /* bit 0~10 */ + /* 3 transactions at most */ + if (mult > 3) + goto en_done; + break; + default: + goto en_done; + } + + spin_lock_irqsave(&udc->lock, flags); + ep->ep.maxpacket = max; + ep->desc = desc; + ep->stopped = 0; + + /* Controller related setup */ + /* Init EPx Queue Head (Ep Capabilites field in QH + * according to max, zlt, mult) */ + struct_ep_qh_setup(udc, (unsigned char) ep_index(ep), + (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN) + ? USB_SEND : USB_RECV), + (unsigned char) (desc->bmAttributes + & USB_ENDPOINT_XFERTYPE_MASK), + max, zlt, mult); + + /* Init endpoint ctrl register */ + dr_ep_setup((unsigned char) ep_index(ep), + (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN) + ? USB_SEND : USB_RECV), + (unsigned char) (desc->bmAttributes + & USB_ENDPOINT_XFERTYPE_MASK)); + + spin_unlock_irqrestore(&udc->lock, flags); + retval = 0; + + VDBG("enabled %s (ep%d%s) maxpacket %d", ep->ep.name, + ep->desc->bEndpointAddress & 0x0f, + (desc->bEndpointAddress & USB_DIR_IN) + ? "in" : "out", max); +en_done: + return retval; +} + +/*--------------------------------------------------------------------- + * @ep : the ep being unconfigured. May not be ep0 + * Any pending and uncomplete req will complete with status (-ESHUTDOWN) +*---------------------------------------------------------------------*/ +static int fsl_ep_disable(struct usb_ep *_ep) +{ + struct fsl_udc *udc = NULL; + struct fsl_ep *ep = NULL; + unsigned long flags = 0; + u32 epctrl; + int ep_num; + + ep = container_of(_ep, struct fsl_ep, ep); + if (!_ep || !ep->desc) { + pr_debug("udc: %s not enabled\n", _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + /* disable ep on controller */ + ep_num = ep_index(ep); + epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl &= ~EPCTRL_TX_ENABLE; + else + epctrl &= ~EPCTRL_RX_ENABLE; + fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + + udc = (struct fsl_udc *)ep->udc; + spin_lock_irqsave(&udc->lock, flags); + + /* nuke all pending requests (does flush) */ + nuke(ep, -ESHUTDOWN); + + ep->desc = 0; + ep->stopped = 1; + spin_unlock_irqrestore(&udc->lock, flags); + + pr_debug("udc: disabled %s OK\n", _ep->name); + return 0; +} + +/*--------------------------------------------------------------------- + * allocate a request object used by this endpoint + * the main operation is to insert the req->queue to the eq->queue + * Returns the request, or null if one could not be allocated +*---------------------------------------------------------------------*/ +static struct usb_request * +fsl_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct fsl_req *req = NULL; + + req = kzalloc(sizeof *req, gfp_flags); + if (!req) + return NULL; + + req->req.dma = DMA_ADDR_INVALID; + pr_debug("udc: req=0x%p set req.dma=0x%x\n", req, req->req.dma); + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct fsl_req *req; + + req = container_of(_req, struct fsl_req, req); + pr_debug("udc: req=0x%p\n", req); + + if (_req) + kfree(req); +} + +/*-------------------------------------------------------------------------*/ +static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) +{ + int i = ep_index(ep) * 2 + ep_is_in(ep); + u32 temp, bitmask, tmp_stat; + struct ep_queue_head *dQH = &ep->udc->ep_qh[i]; + + pr_debug("udc: queue req=0x%p to ep index %d\n", req, i); + + bitmask = ep_is_in(ep) + ? (1 << (ep_index(ep) + 16)) + : (1 << (ep_index(ep))); + + /* check if the pipe is empty */ + if (!(list_empty(&ep->queue))) { + /* Add td to the end */ + struct fsl_req *lastreq; + lastreq = list_entry(ep->queue.prev, struct fsl_req, queue); + lastreq->tail->next_td_ptr = + cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK); + /* Read prime bit, if 1 goto done */ + if (fsl_readl(&dr_regs->endpointprime) & bitmask) + goto out; + + do { + /* Set ATDTW bit in USBCMD */ + temp = fsl_readl(&dr_regs->usbcmd); + fsl_writel(temp | USB_CMD_ATDTW, &dr_regs->usbcmd); + + /* Read correct status bit */ + tmp_stat = fsl_readl(&dr_regs->endptstatus) & bitmask; + + } while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_ATDTW)); + + /* Write ATDTW bit to 0 */ + temp = fsl_readl(&dr_regs->usbcmd); + fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd); + + if (tmp_stat) + goto out; + } + + /* Write dQH next pointer and terminate bit to 0 */ + temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; + dQH->next_dtd_ptr = cpu_to_hc32(temp); + + /* Clear active and halt bit */ + temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE + | EP_QUEUE_HEAD_STATUS_HALT)); + dQH->size_ioc_int_sts &= temp; + + /* Prime endpoint by writing 1 to ENDPTPRIME */ + temp = ep_is_in(ep) + ? (1 << (ep_index(ep) + 16)) + : (1 << (ep_index(ep))); + fsl_writel(temp, &dr_regs->endpointprime); +out: + return 0; +} + +/* Fill in the dTD structure + * @req: request that the transfer belongs to + * @length: return actually data length of the dTD + * @dma: return dma address of the dTD + * @is_last: return flag if it is the last dTD of the request + * return: pointer to the built dTD */ +static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length, + dma_addr_t *dma, int *is_last) +{ + u32 swap_temp; + struct ep_td_struct *dtd; + + /* how big will this transfer be? */ + *length = min(req->req.length - req->req.actual, + (unsigned)EP_MAX_LENGTH_TRANSFER); + + dtd = dma_pool_alloc(udc_controller->td_pool, GFP_KERNEL, dma); + if (dtd == NULL) + return dtd; + + dtd->td_dma = *dma; + /* Clear reserved field */ + swap_temp = hc32_to_cpu(dtd->size_ioc_sts); + swap_temp &= ~DTD_RESERVED_FIELDS; + dtd->size_ioc_sts = cpu_to_hc32(swap_temp); + + /* Init all of buffer page pointers */ + swap_temp = (u32) (req->req.dma + req->req.actual); + dtd->buff_ptr0 = cpu_to_hc32(swap_temp); + dtd->buff_ptr1 = cpu_to_hc32(swap_temp + 0x1000); + dtd->buff_ptr2 = cpu_to_hc32(swap_temp + 0x2000); + dtd->buff_ptr3 = cpu_to_hc32(swap_temp + 0x3000); + dtd->buff_ptr4 = cpu_to_hc32(swap_temp + 0x4000); + + req->req.actual += *length; + + /* zlp is needed if req->req.zero is set */ + if (req->req.zero) { + if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) + *is_last = 1; + else + *is_last = 0; + } else if (req->req.length == req->req.actual) + *is_last = 1; + else + *is_last = 0; + + if ((*is_last) == 0) + VDBG("multi-dtd request!\n"); + /* Fill in the transfer size; set active bit */ + swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE); + + /* Enable interrupt for the last dtd of a request */ + if (*is_last && !req->req.no_interrupt) + swap_temp |= DTD_IOC; + + dtd->size_ioc_sts = cpu_to_hc32(swap_temp); + + mb(); + + VDBG("length = %d address= 0x%x", *length, (int)*dma); + + return dtd; +} + +/* Generate dtd chain for a request */ +static int fsl_req_to_dtd(struct fsl_req *req) +{ + unsigned count; + int is_last; + int is_first = 1; + struct ep_td_struct *last_dtd = NULL, *dtd; + dma_addr_t dma; + + do { + dtd = fsl_build_dtd(req, &count, &dma, &is_last); + if (dtd == NULL) + return -ENOMEM; + + if (is_first) { + is_first = 0; + req->head = dtd; + } else { + last_dtd->next_td_ptr = hc32_to_cpu(dma); + last_dtd->next_td_virt = dtd; + } + last_dtd = dtd; + + req->dtd_count++; + } while (!is_last); + + dtd->next_td_ptr = cpu_to_hc32(DTD_NEXT_TERMINATE); + + req->tail = dtd; + + return 0; +} + +/* queues (submits) an I/O request to an endpoint */ +static int +fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep); + struct fsl_req *req = container_of(_req, struct fsl_req, req); + struct fsl_udc *udc; + unsigned long flags; + int is_iso = 0; + + /* catch various bogus parameters */ + if (!_req || !req->req.complete || !req->req.buf + || !list_empty(&req->queue)) { + VDBG("%s, bad params\n", __FUNCTION__); + return -EINVAL; + } + if (!_ep || (!ep->desc && ep_index(ep))) { + VDBG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (req->req.length > ep->ep.maxpacket) + return -EMSGSIZE; + is_iso = 1; + } + + udc = ep->udc; + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + req->ep = ep; + + /* map virtual address to hardware */ + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, + req->req.buf, + req->req.length, ep_is_in(ep) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->mapped = 1; + } else { + dma_sync_single_for_device(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + ep_is_in(ep) + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->mapped = 0; + } + + req->req.status = -EINPROGRESS; + req->req.actual = 0; + req->dtd_count = 0; + + spin_lock_irqsave(&udc->lock, flags); + + /* build dtds and push them to device queue */ + if (!fsl_req_to_dtd(req)) { + fsl_queue_td(ep, req); + } else { + spin_unlock_irqrestore(&udc->lock, flags); + return -ENOMEM; + } + + /* Update ep0 state */ + if ((ep_index(ep) == 0)) + udc->ep0_state = DATA_STATE_XMIT; + + /* irq handler advances the queue */ + if (req != NULL) + list_add_tail(&req->queue, &ep->queue); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/* dequeues (cancels, unlinks) an I/O request from an endpoint */ +static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep); + struct fsl_req *req; + unsigned long flags; + int ep_num, stopped, ret = 0; + u32 epctrl; + + if (!_ep || !_req) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, flags); + stopped = ep->stopped; + + /* Stop the ep before we deal with the queue */ + ep->stopped = 1; + ep_num = ep_index(ep); + epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl &= ~EPCTRL_TX_ENABLE; + else + epctrl &= ~EPCTRL_RX_ENABLE; + fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + ret = -EINVAL; + goto out; + } + + /* The request is in progress, or completed but not dequeued */ + if (ep->queue.next == &req->queue) { + _req->status = -ECONNRESET; + fsl_ep_fifo_flush(_ep); /* flush current transfer */ + + /* The request isn't the last request in this ep queue */ + if (req->queue.next != &ep->queue) { + struct ep_queue_head *qh; + struct fsl_req *next_req; + + qh = ep->qh; + next_req = list_entry(req->queue.next, struct fsl_req, + queue); + + /* Point the QH to the first TD of next request */ + fsl_writel((u32) next_req->head, &qh->curr_dtd_ptr); + } + + /* The request hasn't been processed, patch up the TD chain */ + } else { + struct fsl_req *prev_req; + + prev_req = list_entry(req->queue.prev, struct fsl_req, queue); + fsl_writel(fsl_readl(&req->tail->next_td_ptr), + &prev_req->tail->next_td_ptr); + + } + + done(ep, req, -ECONNRESET); + + /* Enable EP */ +out: epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl |= EPCTRL_TX_ENABLE; + else + epctrl |= EPCTRL_RX_ENABLE; + fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + ep->stopped = stopped; + + spin_unlock_irqrestore(&ep->udc->lock, flags); + return ret; +} + +/*-------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------- + * modify the endpoint halt feature + * @ep: the non-isochronous endpoint being stalled + * @value: 1--set halt 0--clear halt + * Returns zero, or a negative error code. +*----------------------------------------------------------------*/ +static int fsl_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct fsl_ep *ep = NULL; + unsigned long flags = 0; + int status = -EOPNOTSUPP; /* operation not supported */ + unsigned char ep_dir = 0, ep_num = 0; + struct fsl_udc *udc = NULL; + + ep = container_of(_ep, struct fsl_ep, ep); + udc = ep->udc; + if (!_ep || !ep->desc) { + status = -EINVAL; + goto out; + } + + if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + status = -EOPNOTSUPP; + goto out; + } + + /* Attempt to halt IN ep will fail if any transfer requests + * are still queue */ + if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { + status = -EAGAIN; + goto out; + } + + status = 0; + ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV; + ep_num = (unsigned char)(ep_index(ep)); + spin_lock_irqsave(&ep->udc->lock, flags); + dr_ep_change_stall(ep_num, ep_dir, value); + spin_unlock_irqrestore(&ep->udc->lock, flags); + + if (ep_index(ep) == 0) { + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; + } +out: + VDBG(" %s %s halt stat %d", ep->ep.name, + value ? "set" : "clear", status); + + return status; +} + +static void fsl_ep_fifo_flush(struct usb_ep *_ep) +{ + struct fsl_ep *ep; + int ep_num, ep_dir; + u32 bits; + unsigned long timeout; +#define FSL_UDC_FLUSH_TIMEOUT 1000 + + if (!_ep) { + return; + } else { + ep = container_of(_ep, struct fsl_ep, ep); + if (!ep->desc) + return; + } + ep_num = ep_index(ep); + ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV; + + if (ep_num == 0) + bits = (1 << 16) | 1; + else if (ep_dir == USB_SEND) + bits = 1 << (16 + ep_num); + else + bits = 1 << ep_num; + + timeout = jiffies + FSL_UDC_FLUSH_TIMEOUT; + do { + fsl_writel(bits, &dr_regs->endptflush); + + /* Wait until flush complete */ + while (fsl_readl(&dr_regs->endptflush)) { + if (time_after(jiffies, timeout)) { + ERR("ep flush timeout\n"); + return; + } + cpu_relax(); + } + /* See if we need to flush again */ + } while (fsl_readl(&dr_regs->endptstatus) & bits); +} + +static struct usb_ep_ops fsl_ep_ops = { + .enable = fsl_ep_enable, + .disable = fsl_ep_disable, + + .alloc_request = fsl_alloc_request, + .free_request = fsl_free_request, + + .queue = fsl_ep_queue, + .dequeue = fsl_ep_dequeue, + + .set_halt = fsl_ep_set_halt, + .fifo_flush = fsl_ep_fifo_flush, /* flush fifo */ +}; + +/*------------------------------------------------------------------------- + Gadget Driver Layer Operations +-------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------- + * Get the current frame number (from DR frame_index Reg ) + *----------------------------------------------------------------------*/ +static int fsl_get_frame(struct usb_gadget *gadget) +{ + return (int)(fsl_readl(&dr_regs->frindex) & USB_FRINDEX_MASKS); +} + +/*----------------------------------------------------------------------- + * Tries to wake up the host connected to this gadget + -----------------------------------------------------------------------*/ +static int fsl_wakeup(struct usb_gadget *gadget) +{ + struct fsl_udc *udc = container_of(gadget, struct fsl_udc, gadget); + u32 portsc; + + /* Remote wakeup feature not enabled by host */ + if (!udc->remote_wakeup) + return -ENOTSUPP; + + portsc = fsl_readl(&dr_regs->portsc1); + /* not suspended? */ + if (!(portsc & PORTSCX_PORT_SUSPEND)) + return 0; + /* trigger force resume */ + portsc |= PORTSCX_PORT_FORCE_RESUME; + fsl_writel(portsc, &dr_regs->portsc1); + return 0; +} + +static int can_pullup(struct fsl_udc *udc) +{ + return udc->driver && udc->softconnect && udc->vbus_active; +} + +/* + * Notify controller that VBUS is powered, Called by whatever + * detects VBUS sessions + * @param gadger gadger pointer + * @param is_active is active? + * @return Returns zero on success , or a negative error code + */ +static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct fsl_udc *udc; + unsigned long flags; + + udc = container_of(gadget, struct fsl_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); + + pr_debug("udc: VBUS %s\n", is_active ? "on" : "off"); + udc->vbus_active = (is_active != 0); + + if (can_pullup(udc)) { + pullup_enable(udc); + udc_controller->usb_state = USB_STATE_ATTACHED; + } else { + pullup_disable(udc); + udc_controller->usb_state = USB_STATE_NOTATTACHED; + } + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; + + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +/* constrain controller's VBUS power usage + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ +#ifdef CONFIG_USB_OTG + struct fsl_udc *udc; + + udc = container_of(gadget, struct fsl_udc, gadget); + + if (udc->transceiver) + return otg_set_power(udc->transceiver, mA); +#endif + return -ENOTSUPP; +} + +/* + * Change Data+ pullup status + * this func is used by usb_gadget_connect/disconnet + */ +static int fsl_pullup(struct usb_gadget *gadget, int is_on) +{ + struct fsl_udc *udc; + + udc = container_of(gadget, struct fsl_udc, gadget); + udc->softconnect = (is_on != 0); + if (can_pullup(udc)) + fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP), + &dr_regs->usbcmd); + else + fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP), + &dr_regs->usbcmd); + + return 0; +} + +/* defined in usb_gadget.h */ +static struct usb_gadget_ops fsl_gadget_ops = { + .get_frame = fsl_get_frame, + .wakeup = fsl_wakeup, + .vbus_session = fsl_vbus_session, + .vbus_draw = fsl_vbus_draw, + .pullup = fsl_pullup, +}; + +/* Set protocol stall on ep0, protocol stall will automatically be cleared + on new transaction */ +static void ep0stall(struct fsl_udc *udc) +{ + u32 tmp; + + /* must set tx and rx to stall at the same time */ + tmp = fsl_readl(&dr_regs->endptctrl[0]); + tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL; + fsl_writel(tmp, &dr_regs->endptctrl[0]); + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; +} + +/* Prime a status phase for ep0 */ +static int ep0_prime_status(struct fsl_udc *udc, int direction) +{ + struct fsl_req *req = udc->status_req; + struct fsl_ep *ep; + int status = 0; + + if (direction == EP_DIR_IN) + udc->ep0_dir = USB_DIR_IN; + else + udc->ep0_dir = USB_DIR_OUT; + + ep = &udc->eps[0]; + udc->ep0_state = WAIT_FOR_OUT_STATUS; + + req->ep = ep; + req->req.length = 0; + req->req.status = -EINPROGRESS; + req->req.actual = 0; + req->req.complete = NULL; + req->dtd_count = 0; + + if (fsl_req_to_dtd(req) == 0) + status = fsl_queue_td(ep, req); + else + return -ENOMEM; + + if (status) + ERR("Can't queue ep0 status request \n"); + list_add_tail(&req->queue, &ep->queue); + + return status; +} + +static inline int udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe) +{ + struct fsl_ep *ep = get_ep_by_pipe(udc, pipe); + + if (!ep->name) + return 0; + + nuke(ep, -ESHUTDOWN); + + return 0; +} + +/* + * ch9 Set address + */ +static void ch9setaddress(struct fsl_udc *udc, u16 value, u16 index, u16 length) +{ + /* Save the new address to device struct */ + udc->device_address = (u8) value; + /* Update usb state */ + udc->usb_state = USB_STATE_ADDRESS; + /* Status phase */ + if (ep0_prime_status(udc, EP_DIR_IN)) + ep0stall(udc); +} + +/* + * ch9 Get status + */ +static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, + u16 index, u16 length) +{ + u16 tmp = 0; /* Status, cpu endian */ + + struct fsl_req *req; + struct fsl_ep *ep; + int status = 0; + + ep = &udc->eps[0]; + + if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { + /* Get device status */ + tmp = 1 << USB_DEVICE_SELF_POWERED; + tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP; + } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { + /* Get interface status */ + /* We don't have interface information in udc driver */ + tmp = 0; + } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { + /* Get endpoint status */ + struct fsl_ep *target_ep; + + target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index)); + + /* stall if endpoint doesn't exist */ + if (!target_ep->desc) + goto stall; + tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep)) + << USB_ENDPOINT_HALT; + } + + udc->ep0_dir = USB_DIR_IN; + /* Borrow the per device status_req */ + req = udc->status_req; + /* Fill in the reqest structure */ + *((u16 *) req->req.buf) = cpu_to_le16(tmp); + req->ep = ep; + req->req.length = 2; + req->req.status = -EINPROGRESS; + req->req.actual = 0; + req->req.complete = NULL; + req->dtd_count = 0; + + /* prime the data phase */ + if ((fsl_req_to_dtd(req) == 0)) + status = fsl_queue_td(ep, req); + else /* no mem */ + goto stall; + + if (status) { + ERR("Can't respond to getstatus request \n"); + goto stall; + } + list_add_tail(&req->queue, &ep->queue); + udc->ep0_state = DATA_STATE_XMIT; + return; +stall: + ep0stall(udc); +} + +static void ch9setconfig(struct fsl_udc *udc, u16 value, u16 index, + u16 length) +{ + pr_debug("udc: 1 calling gadget driver->setup\n"); + udc->ep0_dir = USB_DIR_IN; + if (udc->driver->setup(&udc->gadget, &udc->local_setup_buff) >= 0) { + /* gadget layer deal with the status phase */ + udc->usb_state = USB_STATE_CONFIGURED; + udc->ep0_state = WAIT_FOR_OUT_STATUS; + pr_debug("udc: ep0_state now WAIT_FOR_OUT_STATUS\n"); + } +} + +static void setup_received_irq(struct fsl_udc *udc, + struct usb_ctrlrequest *setup) +{ + u32 tmp; + u16 ptc = 0; /* port test control */ + int handled = 1; /* set to zero if we do not handle the message, + and should pass it to the gadget driver */ + + /* + * gadget drivers expect the setup pkt to be in wire format, + * so leave it alone and make local copies of stuff we need. + */ + u16 wValue = le16_to_cpu(setup->wValue); + u16 wIndex = le16_to_cpu(setup->wIndex); + u16 wLength = le16_to_cpu(setup->wLength); + + + pr_debug("udc: request=0x%x\n", setup->bRequest); + + udc_reset_ep_queue(udc, 0); + + /* We asume setup only occurs on EP0 */ + if (setup->bRequestType & USB_DIR_IN) + udc->ep0_dir = USB_DIR_IN; + else + udc->ep0_dir = USB_DIR_OUT; + + if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { + /* handle class requests */ + switch (setup->bRequest) { + + case USB_BULK_RESET_REQUEST: + udc->ep0_dir = USB_DIR_IN; + if (udc->driver->setup(&udc->gadget, + &udc->local_setup_buff) >= 0) { + udc->ep0_state = WAIT_FOR_SETUP; + pr_debug("udc: ep0_state now WAIT_FOR_SETUP\n"); + } + break; + + default: + handled = 0; + break; + } + } else if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { + /* handle standard requests */ + switch (setup->bRequest) { + + case USB_REQ_GET_STATUS: + if ((setup-> + bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD)) + != (USB_DIR_IN | USB_TYPE_STANDARD)) + break; + ch9getstatus(udc, setup->bRequestType, wValue, wIndex, + wLength); + break; + + case USB_REQ_SET_ADDRESS: + if (setup->bRequestType != + (USB_DIR_OUT | USB_TYPE_STANDARD | + USB_RECIP_DEVICE)) + break; + ch9setaddress(udc, wValue, wIndex, wLength); + break; + + case USB_REQ_SET_CONFIGURATION: + if (setup->bRequestType != + (USB_DIR_OUT | USB_TYPE_STANDARD | + USB_RECIP_DEVICE)) + break; + /* gadget layer take over the status phase */ + ch9setconfig(udc, wValue, wIndex, wLength); + break; + case USB_REQ_SET_INTERFACE: + if (setup->bRequestType != + (USB_DIR_OUT | USB_TYPE_STANDARD | + USB_RECIP_INTERFACE)) + break; + udc->ep0_dir = USB_DIR_IN; + if (udc->driver->setup(&udc->gadget, + &udc->local_setup_buff) >= 0) + /* gadget layer take over the status phase */ + break; + /* Requests with no data phase */ + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + { /* status transaction */ + int rc = -EOPNOTSUPP; + + if ((setup->bRequestType & USB_TYPE_MASK) != + USB_TYPE_STANDARD) + break; + + /* we only support set/clear feature for + * endpoint */ + if (setup->bRequestType == USB_RECIP_ENDPOINT) { + int dir = (wIndex & 0x0080) ? + EP_DIR_IN : EP_DIR_OUT; + int num = (wIndex & 0x000f); + struct fsl_ep *ep; + + if (wValue != 0 + || wLength != 0 + || (num * 2 + dir) > udc->max_ep) + break; + ep = &udc->eps[num * 2 + dir]; + + if (setup->bRequest == + USB_REQ_SET_FEATURE) { + pr_debug("udc: udc: SET_FEATURE" + " doing set_halt\n"); + rc = fsl_ep_set_halt(&ep-> ep, + 1); + } else { + pr_debug("udc: CLEAR_FEATURE" + " doing clear_halt\n"); + rc = fsl_ep_set_halt(&ep-> ep, + 0); + } + + } else if (setup->bRequestType == + USB_RECIP_DEVICE) { + if (setup->bRequest == + USB_REQ_SET_FEATURE) { + ptc = wIndex >> 8; + rc = 0; + } + if (!udc->gadget.is_otg) + break; + else if (setup->bRequest == + USB_DEVICE_B_HNP_ENABLE) + udc->gadget.b_hnp_enable = 1; + else if (setup->bRequest == + USB_DEVICE_A_HNP_SUPPORT) + udc->gadget.a_hnp_support = 1; + else if (setup->bRequest == + USB_DEVICE_A_ALT_HNP_SUPPORT) + udc->gadget.a_alt_hnp_support = + 1; + rc = 0; + } + if (rc == 0) { + /* send status only if + * fsl_ep_set_halt success */ + if (ep0_prime_status(udc, EP_DIR_IN)) + ep0stall(udc); + } + break; + } + default: + handled = 0; + break; + } + } else { + /* vendor requests */ + handled = 0; + } + + if (!handled) { + if (udc->driver->setup(&udc->gadget, &udc->local_setup_buff) + != 0) { + ep0stall(udc); + } else if (setup->bRequestType & USB_DIR_IN) { + udc->ep0_state = DATA_STATE_XMIT; + pr_debug("udc: ep0_state now DATA_STATE_XMIT\n"); + } else { + udc->ep0_state = DATA_STATE_RECV; + pr_debug("udc: ep0_state now DATA_STATE_RECV\n"); + } + } + + if (ptc) { + tmp =fsl_readl(&dr_regs->portsc1) | ptc << 16; + fsl_writel(tmp, &dr_regs->portsc1); + pr_debug("udc: switch to test mode.\n"); + } +} + +/* Process request for Data or Status phase of ep0 + * prime status phase if needed */ +static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0, + struct fsl_req *req) +{ + if (udc->usb_state == USB_STATE_ADDRESS) { + /* Set the new address */ + u32 new_address = (u32) udc->device_address; + fsl_writel(new_address << USB_DEVICE_ADDRESS_BIT_POS, + &dr_regs->deviceaddr); + } + + done(ep0, req, 0); + + switch (udc->ep0_state) { + case DATA_STATE_XMIT: + /* receive status phase */ + if (ep0_prime_status(udc, EP_DIR_OUT)) + ep0stall(udc); + break; + case DATA_STATE_RECV: + /* send status phase */ + if (ep0_prime_status(udc, EP_DIR_IN)) + ep0stall(udc); + break; + case WAIT_FOR_OUT_STATUS: + udc->ep0_state = WAIT_FOR_SETUP; + break; + case WAIT_FOR_SETUP: + ERR("Unexpect ep0 packets \n"); + break; + default: + ep0stall(udc); + break; + } +} + +/* Tripwire mechanism to ensure a setup packet payload is extracted without + * being corrupted by another incoming setup packet */ +static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr) +{ + u32 temp; + struct ep_queue_head *qh; + struct fsl_usb2_platform_data *pdata = udc->pdata; + + qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT]; + + /* Clear bit in ENDPTSETUPSTAT */ + temp = fsl_readl(&dr_regs->endptsetupstat); + fsl_writel(temp | (1 << ep_num), &dr_regs->endptsetupstat); + + /* while a hazard exists when setup package arrives */ + do { + /* Set Setup Tripwire */ + temp = fsl_readl(&dr_regs->usbcmd); + fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd); + + /* Copy the setup packet to local buffer */ + if (pdata->le_setup_buf) { + u32 *p = (u32 *)buffer_ptr; + u32 *s = (u32 *)qh->setup_buffer; + + /* Convert little endian setup buffer to CPU endian */ + *p++ = le32_to_cpu(*s++); + *p = le32_to_cpu(*s); + } else { + memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8); + } + } while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW)); + + /* Clear Setup Tripwire */ + temp = fsl_readl(&dr_regs->usbcmd); + fsl_writel(temp & ~USB_CMD_SUTW, &dr_regs->usbcmd); +} + +/* process-ep_req(): free the completed Tds for this req */ +static int process_ep_req(struct fsl_udc *udc, int pipe, + struct fsl_req *curr_req) +{ + struct ep_td_struct *curr_td; + int td_complete, actual, remaining_length, j, tmp; + int status = 0; + int errors = 0; + struct ep_queue_head *curr_qh = &udc->ep_qh[pipe]; + int direction = pipe % 2; + + curr_td = curr_req->head; + td_complete = 0; + actual = curr_req->req.length; + + for (j = 0; j < curr_req->dtd_count; j++) { + remaining_length = (hc32_to_cpu(curr_td->size_ioc_sts) + & DTD_PACKET_SIZE) + >> DTD_LENGTH_BIT_POS; + actual -= remaining_length; + + (errors = hc32_to_cpu(curr_td->size_ioc_sts) & DTD_ERROR_MASK); + if (errors) { + if (errors & DTD_STATUS_HALTED) { + ERR("dTD error %08x QH=%d\n", errors, pipe); + /* Clear the errors and Halt condition */ + tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts); + tmp &= ~errors; + curr_qh->size_ioc_int_sts = cpu_to_hc32(tmp); + status = -EPIPE; + /* FIXME: continue with next queued TD? */ + + break; + } + if (errors & DTD_STATUS_DATA_BUFF_ERR) { + VDBG("Transfer overflow"); + status = -EPROTO; + break; + } else if (errors & DTD_STATUS_TRANSACTION_ERR) { + VDBG("ISO error"); + status = -EILSEQ; + break; + } else + ERR("Unknown error has occured (0x%x)!\r\n", + errors); + + } else if (hc32_to_cpu(curr_td->size_ioc_sts) & + DTD_STATUS_ACTIVE) { + VDBG("Request not complete"); + status = REQ_UNCOMPLETE; + return status; + } else if (remaining_length) { + if (direction) { + VDBG("Transmit dTD remaining length not zero"); + status = -EPROTO; + break; + } else { + td_complete++; + break; + } + } else { + td_complete++; + VDBG("dTD transmitted successful "); + } + + if (j != curr_req->dtd_count - 1) + curr_td = curr_td->next_td_virt; + } + + if (status) + return status; + + curr_req->req.actual = actual; + + return 0; +} + +/* Process a DTD completion interrupt */ +static void dtd_complete_irq(struct fsl_udc *udc) +{ + u32 bit_pos; + int i, ep_num, direction, bit_mask, status; + struct fsl_ep *curr_ep; + struct fsl_req *curr_req, *temp_req; + + /* Clear the bits in the register */ + bit_pos = fsl_readl(&dr_regs->endptcomplete); + fsl_writel(bit_pos, &dr_regs->endptcomplete); + + if (!bit_pos) + return; + + for (i = 0; i < udc->max_ep * 2; i++) { + ep_num = i >> 1; + direction = i % 2; + + bit_mask = 1 << (ep_num + 16 * direction); + + if (!(bit_pos & bit_mask)) + continue; + + curr_ep = get_ep_by_pipe(udc, i); + + /* If the ep is configured */ + if (curr_ep->name == NULL) { + WARN("Invalid EP?"); + continue; + } + + /* process the req queue until an uncomplete request */ + list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue, + queue) { + status = process_ep_req(udc, i, curr_req); + + VDBG("status of process_ep_req= %d, ep = %d", + status, ep_num); + if (status == REQ_UNCOMPLETE) + break; + /* write back status to req */ + curr_req->req.status = status; + + if (ep_num == 0) { + ep0_req_complete(udc, curr_ep, curr_req); + break; + } else { + done(curr_ep, curr_req, status); + } + } + } +} + +/* Process a port change interrupt */ +static void port_change_irq(struct fsl_udc *udc) +{ + u32 speed; + + VDBG("portsc=0x%x", fsl_readl(&dr_regs->portsc1) ); + if (udc->bus_reset) + udc->bus_reset = 0; + + /* Bus resetting is finished */ + if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) { + /* Get the speed */ + speed = fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SPEED_MASK; + switch (speed) { + case PORTSCX_PORT_SPEED_HIGH: + udc->gadget.speed = USB_SPEED_HIGH; + break; + case PORTSCX_PORT_SPEED_FULL: + udc->gadget.speed = USB_SPEED_FULL; + break; + case PORTSCX_PORT_SPEED_LOW: + udc->gadget.speed = USB_SPEED_LOW; + break; + default: + udc->gadget.speed = USB_SPEED_UNKNOWN; + break; + } + } + + /* Update USB state */ + if (!udc->resume_state) + udc->usb_state = USB_STATE_DEFAULT; +} + +/* Process suspend interrupt */ +static void suspend_irq(struct fsl_udc *udc) +{ + udc->resume_state = udc->usb_state; + udc->usb_state = USB_STATE_SUSPENDED; + + /* report suspend to the driver, serial.c does not support this */ + if (udc->driver->suspend) + udc->driver->suspend(&udc->gadget); +} + +static void bus_resume(struct fsl_udc *udc) +{ + udc->usb_state = udc->resume_state; + udc->resume_state = 0; + + /* report resume to the driver, serial.c does not support this */ + if (udc->driver->resume) + udc->driver->resume(&udc->gadget); +} + +/* Clear up all ep queues */ +static int reset_queues(struct fsl_udc *udc) +{ + u8 pipe; + + for (pipe = 0; pipe < udc->max_pipes; pipe++) + udc_reset_ep_queue(udc, pipe); + + /* report disconnect; the driver is already quiesced */ + udc->driver->disconnect(&udc->gadget); + + return 0; +} + +/* Process reset interrupt */ +static void reset_irq(struct fsl_udc *udc) +{ + u32 temp; + unsigned long timeout; + + /* Clear the device address */ + temp = fsl_readl(&dr_regs->deviceaddr); + fsl_writel(temp & ~USB_DEVICE_ADDRESS_MASK, &dr_regs->deviceaddr); + + udc->device_address = 0; + + /* Clear usb state */ + udc->resume_state = 0; + udc->ep0_dir = 0; + udc->ep0_state = WAIT_FOR_SETUP; + udc->remote_wakeup = 0; /* default to 0 on reset */ + udc->gadget.b_hnp_enable = 0; + udc->gadget.a_hnp_support = 0; + udc->gadget.a_alt_hnp_support = 0; + + /* Clear all the setup token semaphores */ + temp = fsl_readl(&dr_regs->endptsetupstat); + fsl_writel(temp, &dr_regs->endptsetupstat); + + /* Clear all the endpoint complete status bits */ + temp = fsl_readl(&dr_regs->endptcomplete); + fsl_writel(temp, &dr_regs->endptcomplete); + + timeout = jiffies + 100; + while (fsl_readl(&dr_regs->endpointprime)) { + /* Wait until all endptprime bits cleared */ + if (time_after(jiffies, timeout)) { + ERR("Timeout for reset\n"); + break; + } + cpu_relax(); + } + + /* Write 1s to the flush register */ + fsl_writel(0xffffffff, &dr_regs->endptflush); + + if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) { + VDBG("Bus reset"); + /* Bus is reseting */ + udc->bus_reset = 1; + /* Reset all the queues, include XD, dTD, EP queue + * head and TR Queue */ + reset_queues(udc); + udc->usb_state = USB_STATE_DEFAULT; + } else { + VDBG("Controller reset"); + /* initialize usb hw reg except for regs for EP, not + * touch usbintr reg */ + dr_controller_setup(udc); + + /* Reset all internal used Queues */ + reset_queues(udc); + + ep0_setup(udc); + + /* Enable DR IRQ reg, Set Run bit, change udc state */ + dr_controller_run(udc); + udc->usb_state = USB_STATE_ATTACHED; + } +} + +/* + * USB device controller interrupt handler + */ +static irqreturn_t fsl_udc_irq(int irq, void *_udc) +{ + struct fsl_udc *udc = _udc; + u32 irq_src; + irqreturn_t status = IRQ_NONE; + unsigned long flags; + + /* Disable ISR for OTG host mode */ + if (udc->stopped) + return IRQ_NONE; + spin_lock_irqsave(&udc->lock, flags); + irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr); + /* Clear notification bits */ + fsl_writel(irq_src, &dr_regs->usbsts); + + VDBG("irq_src [0x%8x] portsc=0x%x", irq_src, + fsl_readl(&dr_regs->portsc1)); + + /* Need to resume? */ + if (udc->usb_state == USB_STATE_SUSPENDED) + if ((fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SUSPEND) == 0) + bus_resume(udc); + + /* USB Interrupt */ + if (irq_src & USB_STS_INT) { + VDBG("Packet int"); + /* Setup package, we only support ep0 as control ep */ + if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) { + tripwire_handler(udc, 0, + (u8 *) (&udc->local_setup_buff)); + setup_received_irq(udc, &udc->local_setup_buff); + status = IRQ_HANDLED; + } + + /* completion of dtd */ + if (fsl_readl(&dr_regs->endptcomplete)) { + dtd_complete_irq(udc); + status = IRQ_HANDLED; + } + } + + /* SOF (for ISO transfer) */ + if (irq_src & USB_STS_SOF) { + status = IRQ_HANDLED; + } + + /* Port Change */ + if (irq_src & USB_STS_PORT_CHANGE) { + port_change_irq(udc); + status = IRQ_HANDLED; + } + + /* Reset Received */ + if (irq_src & USB_STS_RESET) { + reset_irq(udc); + status = IRQ_HANDLED; + } + + /* Sleep Enable (Suspend) */ + if (irq_src & USB_STS_SUSPEND) { + suspend_irq(udc); + status = IRQ_HANDLED; + } + + if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) { + VDBG("Error IRQ %x ", irq_src); + } + + spin_unlock_irqrestore(&udc->lock, flags); + return status; +} + +/*----------------------------------------------------------------* + * Hook to gadget drivers + * Called by initialization code of gadget drivers +*----------------------------------------------------------------*/ +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + int retval = -ENODEV; + unsigned long flags = 0; + struct fsl_udc *udc = udc_controller; + + pr_debug("udc: udc=0x%p\n", udc); + + if (!udc) + return -ENODEV; + + if (!driver || (driver->speed != USB_SPEED_FULL + && driver->speed != USB_SPEED_HIGH) + || !driver->bind || !driver->disconnect + || !driver->setup) + return -EINVAL; + + if (udc->driver) + return -EBUSY; + + /* lock is needed but whether should use this lock or another */ + spin_lock_irqsave(&udc->lock, flags); + + driver->driver.bus = 0; + udc->softconnect = 1; + /* hook up the driver */ + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, flags); + + /* bind udc driver to gadget driver */ + retval = driver->bind(&udc->gadget); + if (retval) { + pr_debug("bind to %s --> %d\n", driver->driver.name, retval); + udc->gadget.dev.driver = 0; + udc->driver = 0; + goto out; + } + + /* Enable DR IRQ reg and Set usbcmd reg Run bit */ + if (udc->transceiver) { + /* Suspend the controller until OTG enables it */ + udc_suspend(udc); + pr_debug("udc: suspend udc for OTG auto detect \n"); + + /* Export udc suspend/resume call to OTG */ + udc->gadget.dev.parent->driver->suspend = fsl_udc_suspend; + udc->gadget.dev.parent->driver->resume = fsl_udc_resume; + + retval = otg_set_peripheral(udc->transceiver, &udc->gadget); + if (retval < 0) { + printk(KERN_ERR "can't bind to transceiver\n"); + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = 0; + udc->driver = 0; + return retval; + } + } else { + /* Enable DR IRQ reg and Set usbcmd reg Run bit */ + dr_controller_run(udc); + udc->usb_state = USB_STATE_ATTACHED; + udc->ep0_state = WAIT_FOR_SETUP; + pr_debug("udc: ep0_state now WAIT_FOR_SETUP\n"); + udc->ep0_dir = 0; + } + + printk(KERN_INFO "%s: bind to driver %s \n", udc->gadget.name, + driver->driver.name); + +out: + return retval; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +/* Disconnect from gadget driver */ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct fsl_ep *loop_ep; + unsigned long flags; + + if (!udc_controller) + return -ENODEV; + + if (!driver || driver != udc_controller->driver || !driver->unbind) + return -EINVAL; + +#ifdef CONFIG_USB_OTG + if (udc_controller->transceiver) + (void)otg_set_peripheral(udc_controller->transceiver, 0); +#endif + + /* stop DR, disable intr */ + dr_controller_stop(udc_controller); + + /* in fact, no needed */ + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; + + /* stand operation */ + spin_lock_irqsave(&udc_controller->lock, flags); + udc_controller->gadget.speed = USB_SPEED_UNKNOWN; + nuke(&udc_controller->eps[0], -ESHUTDOWN); + list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list, + ep.ep_list) + nuke(loop_ep, -ESHUTDOWN); + spin_unlock_irqrestore(&udc_controller->lock, flags); + + /* unbind gadget and unhook driver. */ + driver->unbind(&udc_controller->gadget); + udc_controller->gadget.dev.driver = 0; + udc_controller->driver = 0; + + printk(KERN_INFO "unregistered gadget '%s'\n", driver->driver.name); + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +/*------------------------------------------------------------------------- + PROC File System Support +-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +#include + +static const char proc_filename[] = "driver/fsl_usb2_udc"; + +static int fsl_proc_read(char *page, char **start, off_t off, int count, + int *eof, void *_dev) +{ + char *buf = page; + char *next = buf; + unsigned size = count; + unsigned long flags; + int t, i; + u32 tmp_reg; + struct fsl_ep *ep = NULL; + struct fsl_req *req; + + struct fsl_udc *udc = udc_controller; + if (off != 0) + return 0; + + spin_lock_irqsave(&udc->lock, flags); + + /* ------basic driver infomation ---- */ + t = scnprintf(next, size, + DRIVER_DESC "\n" + "%s version: %s\n" + "Gadget driver: %s\n\n", + driver_name, DRIVER_VERSION, + udc->driver ? udc->driver->driver.name : "(none)"); + size -= t; + next += t; + + /* ------ DR Registers ----- */ + tmp_reg = fsl_readl(&dr_regs->usbcmd); + t = scnprintf(next, size, + "USBCMD reg: 0x%08x\n" + "\tSetupTW: %d\n" + "\tRun/Stop: %s\n\n", + tmp_reg, + (tmp_reg & USB_CMD_SUTW) ? 1 : 0, + (tmp_reg & USB_CMD_RUN_STOP) ? "Run" : "Stop"); + size -= t; + next += t; + + tmp_reg = fsl_readl(&dr_regs->usbsts); + t = scnprintf(next, size, + "USB Status Reg: 0x%08x\n" + "\tDr Suspend: %d Reset Received: %d " + "System Error: %s USB Error Interrupt: %s\n\n", + tmp_reg, + (tmp_reg & USB_STS_SUSPEND) ? 1 : 0, + (tmp_reg & USB_STS_RESET) ? 1 : 0, + (tmp_reg & USB_STS_SYS_ERR) ? "Err" : "Normal", + (tmp_reg & USB_STS_ERR) ? "Err detected" : "No err"); + size -= t; + next += t; + + tmp_reg = fsl_readl(&dr_regs->usbintr); + t = scnprintf(next, size, + "USB Interrupt Enable Reg: 0x%08x\n" + "\tSleep Enable: %d SOF Received Enable: %d " + "Reset Enable: %d\n" + "\tSystem Error Enable: %d " + "Port Change Dectected Enable: %d\n" + "\tUSB Error Intr Enable: %d USB Intr Enable: %d\n\n", + tmp_reg, + (tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0, + (tmp_reg & USB_INTR_SOF_EN) ? 1 : 0, + (tmp_reg & USB_INTR_RESET_EN) ? 1 : 0, + (tmp_reg & USB_INTR_SYS_ERR_EN) ? 1 : 0, + (tmp_reg & USB_INTR_PTC_DETECT_EN) ? 1 : 0, + (tmp_reg & USB_INTR_ERR_INT_EN) ? 1 : 0, + (tmp_reg & USB_INTR_INT_EN) ? 1 : 0); + size -= t; + next += t; + + tmp_reg = fsl_readl(&dr_regs->frindex); + t = scnprintf(next, size, + "USB Frame Index Reg: Frame Number is 0x%x\n\n", + (tmp_reg & USB_FRINDEX_MASKS)); + size -= t; + next += t; + + tmp_reg = fsl_readl(&dr_regs->deviceaddr); + t = scnprintf(next, size, + "USB Device Address Reg: Device Addr is 0x%x\n\n", + (tmp_reg & USB_DEVICE_ADDRESS_MASK)); + size -= t; + next += t; + + tmp_reg = fsl_readl(&dr_regs->endpointlistaddr); + t = scnprintf(next, size, + "USB Endpoint List Address Reg:" + "Device Addr is 0x%x\n\n", + (tmp_reg & USB_EP_LIST_ADDRESS_MASK)); + size -= t; + next += t; + + tmp_reg = fsl_readl(&dr_regs->portsc1); + t = scnprintf(next, size, + "USB Port Status&Control Reg:\n" + "\tPort Transceiver Type : %s" "Port Speed: %s \n" + "\tPHY Low Power Suspend: %s" "Port Reset: %s " + "Port Suspend Mode: %s \n" "\tOver-current Change: %s " + "Port Enable/Disable Change: %s\n" + "\tPort Enabled/Disabled: %s" + "Current Connect Status: %s\n\n", ( { + char *s; + switch (tmp_reg & PORTSCX_PTS_FSLS) { + case PORTSCX_PTS_UTMI: + s = "UTMI"; break; + case PORTSCX_PTS_ULPI: + s = "ULPI "; break; + case PORTSCX_PTS_FSLS: + s = "FS/LS Serial"; break; + default: + s = "None"; break; + } + s; } ), ( { + char *s; + switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) { + case PORTSCX_PORT_SPEED_FULL: + s = "Full Speed"; break; + case PORTSCX_PORT_SPEED_LOW: + s = "Low Speed"; break; + case PORTSCX_PORT_SPEED_HIGH: + s = "High Speed"; break; + default: + s = "Undefined"; break; + } + s; + } ), + (tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ? + "Normal PHY mode" : "Low power mode", + (tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" : + "Not in Reset", + (tmp_reg & PORTSCX_PORT_SUSPEND) ? "In " : "Not in", + (tmp_reg & PORTSCX_OVER_CURRENT_CHG) ? "Dected" : + "No", + (tmp_reg & PORTSCX_PORT_EN_DIS_CHANGE) ? "Disable" : + "Not change", + (tmp_reg & PORTSCX_PORT_ENABLE) ? "Enable" : + "Not correct", + (tmp_reg & PORTSCX_CURRENT_CONNECT_STATUS) ? + "Attached" : "Not-Att"); + size -= t; + next += t; + + tmp_reg = fsl_readl(&dr_regs->usbmode); + t = scnprintf(next, size, + "USB Mode Reg:" "Controller Mode is : %s\n\n", ( { + char *s; + switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) { + case USB_MODE_CTRL_MODE_IDLE: + s = "Idle"; break; + case USB_MODE_CTRL_MODE_DEVICE: + s = "Device Controller"; break; + case USB_MODE_CTRL_MODE_HOST: + s = "Host Controller"; break; + default: + s = "None"; break; + } + s; + } )); + size -= t; + next += t; + + tmp_reg = fsl_readl(&dr_regs->endptsetupstat); + t = scnprintf(next, size, + "Endpoint Setup Status Reg:" "SETUP on ep 0x%x\n\n", + (tmp_reg & EP_SETUP_STATUS_MASK)); + size -= t; + next += t; + + for (i = 0; i < udc->max_ep / 2; i++) { + tmp_reg = fsl_readl(&dr_regs->endptctrl[i]); + t = scnprintf(next, size, "EP Ctrl Reg [0x%x]: = [0x%x]\n", + i, tmp_reg); + size -= t; + next += t; + } + tmp_reg = fsl_readl(&dr_regs->endpointprime); + t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n", tmp_reg); + size -= t; + next += t; + +#ifdef HAVE_SYS_REGS + tmp_reg = usb_sys_regs->snoop1; + t = scnprintf(next, size, "\nSnoop1 Reg : = [0x%x]\n\n", tmp_reg); + size -= t; + next += t; + + tmp_reg = usb_sys_regs->control; + t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n", + tmp_reg); + size -= t; + next += t; +#endif + + /* ------fsl_udc, fsl_ep, fsl_request structure information ----- */ + ep = &udc->eps[0]; + t = scnprintf(next, size, "For %s Maxpkt is 0x%x index is 0x%x\n", + ep->ep.name, ep_maxpacket(ep), ep_index(ep)); + size -= t; + next += t; + + if (list_empty(&ep->queue)) { + t = scnprintf(next, size, "its req queue is empty\n\n"); + size -= t; + next += t; + } else { + list_for_each_entry(req, &ep->queue, queue) { + t = scnprintf(next, size, + "req %p actual 0x%x length 0x%x buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); + size -= t; + next += t; + } + } + /* other gadget->eplist ep */ + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) { + t = scnprintf(next, size, + "\nFor %s Maxpkt is 0x%x " + "index is 0x%x\n", + ep->ep.name, ep_maxpacket(ep), + ep_index(ep)); + size -= t; + next += t; + + if (list_empty(&ep->queue)) { + t = scnprintf(next, size, + "its req queue is empty\n\n"); + size -= t; + next += t; + } else { + list_for_each_entry(req, &ep->queue, queue) { + t = scnprintf(next, size, + "req %p actual 0x%x length" + "0x%x buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); + size -= t; + next += t; + } /* end for each_entry of ep req */ + } /* end for else */ + } /* end for if(ep->queue) */ + } /* end (ep->desc) */ + + spin_unlock_irqrestore(&udc->lock, flags); + + *eof = 1; + return count - size; +} + +#define create_proc_file() create_proc_read_entry(proc_filename, \ + 0, NULL, fsl_proc_read, NULL) + +#define remove_proc_file() remove_proc_entry(proc_filename, NULL) + +#else /* !CONFIG_USB_GADGET_DEBUG_FILES */ + +#define create_proc_file() do {} while (0) +#define remove_proc_file() do {} while (0) + +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ + +/*-------------------------------------------------------------------------*/ + +/* Release udc structures */ +static void fsl_udc_release(struct device *dev) +{ + complete(udc_controller->done); + dma_free_coherent(dev, udc_controller->ep_qh_size, + udc_controller->ep_qh, udc_controller->ep_qh_dma); + kfree(udc_controller); +} + +/****************************************************************** + Internal structure setup functions +*******************************************************************/ +/*------------------------------------------------------------------ + * init resource for globle controller + * Return the udc handle on success or NULL on failure + ------------------------------------------------------------------*/ +static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev) +{ + struct fsl_udc *udc; + struct fsl_usb2_platform_data *pdata; + size_t size; + + udc = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); + if (udc == NULL) { + ERR("malloc udc failed\n"); + return NULL; + } + + pdata = pdev->dev.platform_data; + udc->phy_mode = pdata->phy_mode; /* DDD FIXME */ + + /* max_ep_nr is bidirectional ep number, max_ep doubles the number */ + udc->max_ep = pdata->max_ep_nr * 2; + + udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); + if (!udc->eps) { + ERR("malloc fsl_ep failed\n"); + goto cleanup; + } + + /* initialized QHs, take care of alignment */ + size = udc->max_ep * sizeof(struct ep_queue_head); + if (size < QH_ALIGNMENT) + size = QH_ALIGNMENT; + else if ((size % QH_ALIGNMENT) != 0) { + size += QH_ALIGNMENT + 1; + size &= ~(QH_ALIGNMENT - 1); + } + udc->ep_qh = dma_alloc_coherent(&pdev->dev, size, + &udc->ep_qh_dma, GFP_KERNEL); + if (!udc->ep_qh) { + ERR("malloc QHs for udc failed\n"); + kfree(udc->eps); + goto cleanup; + } + + udc->ep_qh_size = size; + + /* Initialize ep0 status request structure */ + udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL), + struct fsl_req, req); + /* allocate a small amount of memory to get valid address */ + udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); + udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf); + + udc->resume_state = USB_STATE_NOTATTACHED; + udc->usb_state = USB_STATE_POWERED; + udc->ep0_dir = 0; + udc->remote_wakeup = 0; /* default to 0 on reset */ + spin_lock_init(&udc->lock); + + return udc; + +cleanup: + kfree(udc); + return NULL; +} + +/*---------------------------------------------------------------- + * Setup the fsl_ep struct for eps + * Link fsl_ep->ep to gadget->ep_list + * ep0out is not used so do nothing here + * ep0in should be taken care + *--------------------------------------------------------------*/ +static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index, + char *name, int link) +{ + struct fsl_ep *ep = &udc->eps[index]; + + ep->udc = udc; + strcpy(ep->name, name); + ep->ep.name = ep->name; + + ep->ep.ops = &fsl_ep_ops; + ep->stopped = 0; + + /* for ep0: maxP defined in desc + * for other eps, maxP is set by epautoconfig() called by gadget layer + */ + ep->ep.maxpacket = (unsigned short) ~0; + + /* the queue lists any req for this ep */ + INIT_LIST_HEAD(&ep->queue); + + /* gagdet.ep_list used for ep_autoconfig so no ep0 */ + if (link) + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + ep->gadget = &udc->gadget; + ep->qh = &udc->ep_qh[index]; + + return 0; +} + +static int board_init(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + + pr_debug("udc: pdev=0x%p pdata=0x%p\n", pdev, pdata); + + /* + * do platform specific init: check the clock, grab/config pins, etc. + */ + if (pdata->platform_init && pdata->platform_init(pdev) != 0) + return -EINVAL; + + return 0; +} + +/* Driver probe functions */ + +static int __init fsl_udc_probe(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_udc *udc; + unsigned int i; + struct otg_transceiver *transceiver = NULL; + int status = -ENODEV; + u32 id; + int irq_number; + u64 rsrc_start, rsrc_len; + int ret = -ENODEV; + + pr_debug("udc: pdev=0x%p pdata=0x%p\n", pdev, pdata); + + if (board_init(pdev) != 0) + return -EINVAL; + + /* Initialize the udc structure including QH member and other member */ + udc = (struct fsl_udc *) struct_udc_setup(pdev); + udc_controller = udc; + + if (!udc) { + ERR("udc is NULL \n"); + return -ENOMEM; + } + dev_set_drvdata(&pdev->dev, udc); + pr_debug("udc_controller=0x%p", udc_controller); + + udc->pdata = pdata; + udc->xcvr_type = pdata->xcvr_type; + +#ifdef CONFIG_USB_OTG + udc->transceiver = otg_get_transceiver(); + pr_debug("udc: otg_get_transceiver returns 0x%p", udc->transceiver); +#endif + + if (pdev->resource[1].flags != IORESOURCE_IRQ) + return -ENODEV; + + rsrc_start = pdev->resource[0].start; + rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; + + pr_debug(" start=0x%ux end=0x%ux\n", + pdev->resource[0].start, pdev->resource[0].end); + pr_debug("rsrc_start=0x%llx rsrc_len=0x%llx\n", rsrc_start, rsrc_len); + + dr_regs = (struct fsl_usb_device_regs *)pdata->regs; + + pr_debug("udc: pdate=0x%p dr_regs=0x%p\n", pdata, dr_regs); + pr_debug("udc: hci_version=0x%x\n", dr_regs->hciversion); + pr_debug("udc: otgsc at 0x%p\n", &dr_regs->otgsc); + + id = fsl_readl(&dr_regs->id); + printk(KERN_INFO "FSL2 USBOTG h/w ID=0x%x revision=0x%x\n", + id & 0x3f, id >> 16); + + /* USB OTG module IRQ */ + irq_number = platform_get_irq(pdev, 0); + if (irq_number > 128) { + status = request_irq(irq_number, fsl_udc_irq, IRQF_SHARED, + driver_name, udc); + if (status) { + ERR("can't get irq %d, err=%d\n", irq_number, status); + goto err2; + } + } else { + status = -ENODEV; + goto err2; + } + + if (!udc->transceiver) { + /* initialize usb hw reg except for regs for EP, + * leave usbintr reg untouched*/ + dr_controller_setup(udc); + } + + /* here comes the stand operations for probe + * set the fsl_udc->gadget.xxx + */ + udc->gadget.ops = &fsl_gadget_ops; + udc->gadget.is_dualspeed = 1; + + /* gadget.ep0 is a pointer */ + udc->gadget.ep0 = &udc->eps[0].ep; + INIT_LIST_HEAD(&udc->gadget.ep_list); + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.name = driver_name; + + /* Setup gadget.dev and register with kernel */ + strcpy(udc->gadget.dev.bus_id, "gadget"); + udc->gadget.dev.release = fsl_udc_release; + udc->gadget.dev.parent = &pdev->dev; + + ret = device_register(&udc->gadget.dev); + if (ret < 0) + goto err3; + + if (udc->transceiver) + udc->gadget.is_otg = 1; + + /* setup QH and epctrl for ep0 */ + ep0_setup(udc); + + /* setup udc->eps[] for ep0 */ + struct_ep_setup(udc_controller, 0, "ep0", 0); + /* for ep0: the desc defined here; + * for other eps, gadget layer called ep_enable with defined desc + */ + udc->eps[0].desc = &fsl_ep0_desc; + udc->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD; + + /* setup the udc->eps[] for non-control endpoints and link + * to gadget.ep_list */ + for (i = 1; i < (int)(udc->max_ep / 2); i++) { + char name[14]; + + sprintf(name, "ep%dout", i); + struct_ep_setup(udc, i * 2, name, 1); + sprintf(name, "ep%din", i); + struct_ep_setup(udc, i * 2 + 1, name, 1); + } + + /* use dma_pool for TD management */ + udc_controller->td_pool = dma_pool_create("udc_td", &pdev->dev, + sizeof(struct ep_td_struct), + DTD_ALIGNMENT, UDC_DMA_BOUNDARY); + if (udc->td_pool == NULL) { + ret = -ENOMEM; + goto err4; + } + + create_proc_file(); + return 0; + +err4: + device_unregister(&udc_controller->gadget.dev); +err3: + free_irq(udc_controller->irq, udc_controller); +err2: + kfree(udc); + if (transceiver) + put_device(transceiver->dev); + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); + return status; + +} + +/* Driver removal functions + * Free resources + * Finish pending transaction + */ +static int __exit fsl_udc_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fsl_udc *udc = (struct fsl_udc *)dev_get_drvdata(dev); + struct fsl_usb2_platform_data *pdata; + int irq_number; + + DECLARE_COMPLETION(done); + + pdata = pdev->dev.platform_data; + + if (!udc) + return -ENODEV; + + udc->done = &done; + + /* DR has been stopped in usb_gadget_unregister_driver() */ + + if (udc->transceiver) { + put_device(udc->transceiver->dev); + udc->transceiver = NULL; + } + + /* remove proc */ + remove_proc_file(); + + /* free irq */ + irq_number = udc->irq; + free_irq(pdev->resource[1].start, udc); + udc->irq = 0; + + /* Free allocated memory */ + kfree(udc->status_req->req.buf); + kfree(udc->status_req); + kfree(udc_controller->eps); + + dma_pool_destroy(udc_controller->td_pool); + /* deinitlaize all ep: strcut */ + /* deinitialize ep0: reg and QH */ + + device_unregister(&udc->gadget.dev); + /* free udc --wait for the release() finished */ + wait_for_completion(&done); + + /* + * do platform specific un-initialization: + * release iomux pins, etc. + */ + if (pdata->platform_uninit) + pdata->platform_uninit(pdev); + + return 0; +} + +static int udc_suspend(struct fsl_udc *udc) +{ + udc->stopped = 1; + return 0; +} + +/* + * Modify Power management attributes + * Used by OTG statemachine to disable gadget temporarily + * Here we stop the DR controller and disable the irq + * @param dev device controller pointer + * @param state current state + * @return The function returns 0 on success or -1 if failed + */ +static int fsl_udc_suspend(struct device *dev, pm_message_t state) +{ + struct fsl_udc *udc = (struct fsl_udc *)dev_get_drvdata(dev); + pr_debug("udc: Suspend. state=%d\n", state.event); + return udc_suspend(udc); +} + +static int udc_resume(struct fsl_udc *udc) +{ + /*Enable DR irq reg and set controller Run */ + if (udc->stopped) { + dr_controller_setup(udc); + dr_controller_run(udc); + } + udc->usb_state = USB_STATE_ATTACHED; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; + return 0; +} + +/* + * Invoked on USB resume. May be called in_interrupt. + * Here we start the DR controller and enable the irq + * @param dev device controller pointer + * @return The function returns 0 on success or -1 if failed + */ +static int fsl_udc_resume(struct device *dev) +{ + struct fsl_udc *udc = (struct fsl_udc *)dev_get_drvdata(dev); + pr_debug("udc: Resume dev=0x%p udc=0x%p\n", dev, udc); + + return udc_resume(udc); +} + +/*------------------------------------------------------------------------- + Register entry point for the peripheral controller driver +--------------------------------------------------------------------------*/ +static struct platform_driver udc_driver = { + .probe = fsl_udc_probe, + .remove = __exit_p(fsl_udc_remove), + .driver = { + .name = (char *)driver_name, + .owner = THIS_MODULE, + }, +}; + +static int __init udc_init(void) +{ + printk(KERN_INFO "%s version %s init \n", driver_desc, DRIVER_VERSION); + return platform_driver_register(&udc_driver); +} + +module_init(udc_init); + +static void __exit udc_exit(void) +{ + platform_driver_unregister(&udc_driver); + printk(KERN_INFO "%s unregistered \n", driver_desc); +} + +module_exit(udc_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); --- /dev/null +++ b/drivers/usb/host/ehci-arc.c @@ -0,0 +1,436 @@ +/* + * drivers/usb/host/ehci-arc.c + * + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* Note: this file is #included by ehci-hcd.c */ + +#include +#include +#include +#include + +#include "ehci-fsl.h" + + +/* FIXME: Power Managment is un-ported so temporarily disable it */ +#undef CONFIG_PM + +/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_hcd_fsl_probe - initialize FSL-based HCDs + * @drvier: Driver to be used for this HCD + * @pdev: USB Host Controller being probed + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller. + * + */ +static int usb_hcd_fsl_probe(const struct hc_driver *driver, + struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct usb_hcd *hcd; + struct resource *res; + int irq; + int retval; + + pr_debug("initializing FSL-SOC USB Controller\n"); + + /* Need platform data for setup */ + if (!pdata) { + dev_err(&pdev->dev, + "No platform data for %s.\n", pdev->dev.bus_id); + return -ENODEV; + } + + retval = fsl_platform_verify(pdev); + if (retval) + return retval; + + /* + * do platform specific init: check the clock, grab/config pins, etc. + */ + if (pdata->platform_init && pdata->platform_init(pdev)) { + retval = -ENODEV; + goto err1; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + pdev->dev.bus_id); + return -ENODEV; + } + irq = res->start; + + fsl_platform_set_vbus_power(pdev, 1); + + hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + retval = -ENOMEM; + goto err1; + } + + if (pdata->regs) { + pr_debug("REGS: using pdata->regs (0x%p)\n", pdata->regs); + hcd->regs = pdata->regs; + hcd->rsrc_start = pdata->r_start; + hcd->rsrc_len = pdata->r_len; + } else { + pr_debug("REGS: NO pdata->regs\n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Found HC with no register addr. " + "Check %s setup!\n", pdev->dev.bus_id); + retval = -ENODEV; + goto err2; + } + hcd->rsrc_start = res->start; + hcd->rsrc_len = res->end - res->start + 1; + + /* + printk("DDD %s(): rsrc_start=0x%llx rsrc_len=0x%llx " + "pdata=0x%p\n", __FUNCTION__, + hcd->rsrc_start, hcd->rsrc_len, pdata); + */ + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + driver->description)) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); + retval = -EBUSY; + goto err2; + } + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + + if (hcd->regs == NULL) { + dev_dbg(&pdev->dev, "error mapping memory\n"); + retval = -EFAULT; + goto err3; + } + } + hcd->power_budget = pdata->power_budget; + + /* DDD + * the following must be done by this point, otherwise the OTG + * host port doesn't make it thru initializtion. + * ehci_halt(), called by ehci_fsl_setup() returns -ETIMEDOUT + */ + fsl_platform_set_host_mode(hcd); + + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (retval != 0) + goto err4; + +#if defined(CONFIG_USB_OTG) + if (pdata->does_otg) { + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + ehci->transceiver = otg_get_transceiver(); + + if (ehci->transceiver) { + retval = otg_set_host(ehci->transceiver, + &ehci_to_hcd(ehci)->self); + if (retval) { + if (ehci->transceiver) + put_device(ehci->transceiver->dev); + goto err3; + } + } else { + printk(KERN_ERR "can't find transceiver\n"); + retval = -ENODEV; + goto err3; + } + } +#endif + + return retval; + +err4: + /* DDD only if we did the iomap() iounmap(hcd->regs); */ +err3: + /* DDD only if we did a request_ + * release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + */ +err2: + usb_put_hcd(hcd); +err1: + dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval); + if (pdata->platform_uninit) + pdata->platform_uninit(pdev); + return retval; +} + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_fsl_probe(). + * + */ +static void usb_hcd_fsl_remove(struct usb_hcd *hcd, + struct platform_device *pdev) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + + /* DDD shouldn't we turn off the power here? */ + fsl_platform_set_vbus_power(pdev, 0); + + usb_remove_hcd(hcd); + + if (ehci->transceiver) { + (void)otg_set_host(ehci->transceiver, 0); + put_device(ehci->transceiver->dev); + } + usb_put_hcd(hcd); + + /* + * do platform specific un-initialization: + * release iomux pins, etc. + */ + if (pdata->platform_uninit) + pdata->platform_uninit(pdev); +} + +/* called after powerup, by probe or system-pm "wakeup" */ +static int ehci_fsl_reinit(struct ehci_hcd *ehci) +{ + fsl_platform_usb_setup(ehci_to_hcd(ehci)); + ehci_port_power(ehci, 0); + + return 0; +} + +/* called during probe() after chip reset completes */ +static int ehci_fsl_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + struct fsl_usb2_platform_data *pdata; + pdata = hcd->self.controller-> platform_data; + + ehci->big_endian_desc = pdata->big_endian_desc; + ehci->big_endian_mmio = pdata->big_endian_mmio; + + /* EHCI registers start at offset 0x100 */ + ehci->caps = hcd->regs + 0x100; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + + pr_debug("%s(): ehci->caps=0x%p ehci->regs=0x%p\n", __FUNCTION__, + ehci->caps, ehci->regs); + + dbg_hcs_params(ehci, "reset"); + dbg_hcc_params(ehci, "reset"); + + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + retval = ehci_halt(ehci); + if (retval) + return retval; + + /* data structure init */ + retval = ehci_init(hcd); + if (retval) + return retval; + + ehci->is_tdi_rh_tt = 1; + + ehci->sbrn = 0x20; + + ehci_reset(ehci); + + retval = ehci_fsl_reinit(ehci); + return retval; +} + +static const struct hc_driver ehci_fsl_hc_driver = { + .description = hcd_name, + .product_desc = "Freescale On-Chip EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = FSL_PLATFORM_HC_FLAGS, + + /* + * basic lifecycle operations + */ + .reset = ehci_fsl_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +}; + +#ifdef CONFIG_USB_OTG +/* + * Holding pen for all the EHCI registers except port_status, + * which is a zero element array and hence takes no space. + * The port_status register is saved in usb_ehci_portsc. + */ +volatile static struct ehci_regs usb_ehci_regs; +static u32 usb_ehci_portsc; + +/* suspend/resume, section 4.3 */ + +/* These routines rely on the bus (pci, platform, etc) + * to handle powerdown and wakeup, and currently also on + * transceivers that don't need any software attention to set up + * the right sort of wakeup. + * + * They're also used for turning on/off the port when doing OTG. + */ +static int ehci_fsl_drv_suspend(struct platform_device *pdev, + pm_message_t message) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + u32 tmp; + + pr_debug("%s pdev=0x%p ehci=0x%p hcd=0x%p\n", + __FUNCTION__, pdev, ehci, hcd); + pr_debug("%s ehci->regs=0x%p hcd->regs=0x%p hcd->state=%d\n", + __FUNCTION__, ehci->regs, hcd->regs, hcd->state); + + hcd->state = HC_STATE_SUSPENDED; + pdev->dev.power.power_state = PMSG_SUSPEND; + + if (hcd->driver->suspend) + return hcd->driver->suspend(hcd, message); + + /* ignore non-host interrupts */ + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + tmp = ehci_readl(ehci, &ehci->regs->command); + tmp &= ~CMD_RUN; + ehci_writel(ehci, tmp, &ehci->regs->command); + + memcpy((void *)&usb_ehci_regs, ehci->regs, sizeof(struct ehci_regs)); + usb_ehci_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]); + + /* clear the W1C bits */ + usb_ehci_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS); + + fsl_platform_set_vbus_power(pdev, 0); + /* clear PP to cut power to the port */ + tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); + tmp &= ~PORT_POWER; + ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); + + return 0; +} + +static int ehci_fsl_drv_resume(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + u32 tmp; + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + + pr_debug("%s pdev=0x%p pdata=0x%p ehci=0x%p hcd=0x%p\n", + __FUNCTION__, pdev, pdata, ehci, hcd); + + pr_debug("%s ehci->regs=0x%p hcd->regs=0x%p\n", + __FUNCTION__, ehci->regs, hcd->regs); + + memcpy(ehci->regs, (void *)&usb_ehci_regs, sizeof(struct ehci_regs)); + + tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0); + ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE); + pr_debug("tmp %08x set usbmode %08x\n", tmp, + ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE)); + + ehci_writel(ehci, usb_ehci_portsc, &ehci->regs->port_status[0]); + pr_debug("set portsc %08x %08x\n", usb_ehci_portsc, + ehci_readl(ehci, &ehci->regs->port_status[0])); + + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + hcd->state = HC_STATE_RUNNING; + pdev->dev.power.power_state = PMSG_ON; + + tmp = ehci_readl(ehci, &ehci->regs->command); + tmp |= CMD_RUN; + ehci_writel(ehci, tmp, &ehci->regs->command); + + fsl_platform_set_vbus_power(pdev, 1); + + usb_hcd_resume_root_hub(hcd); + + return 0; +} +#endif /* CONFIG_USB_OTG */ + +static int ehci_fsl_drv_probe(struct platform_device *pdev) +{ + if (usb_disabled()) + return -ENODEV; + + return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev); +} + +static int ehci_fsl_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_hcd_fsl_remove(hcd, pdev); + + return 0; +} + +MODULE_ALIAS("fsl-ehci"); + +static struct platform_driver ehci_fsl_driver = { + .probe = ehci_fsl_drv_probe, + .remove = ehci_fsl_drv_remove, + .shutdown = usb_hcd_platform_shutdown, +#ifdef CONFIG_USB_OTG + .suspend = ehci_fsl_drv_suspend, + .resume = ehci_fsl_drv_resume, +#endif + .driver = { + .name = "fsl-ehci", + }, +}; --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h @@ -18,6 +18,8 @@ #ifndef _EHCI_FSL_H #define _EHCI_FSL_H +#include + /* offsets for the non-ehci registers in the FSL SOC USB controller */ #define FSL_SOC_USB_ULPIVP 0x170 #define FSL_SOC_USB_PORTSC1 0x184 @@ -34,5 +36,29 @@ #define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */ #define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */ #define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */ -#define SNOOP_SIZE_2GB 0x1e + +#ifdef CONFIG_MPC834x +#include +#endif + +#ifdef CONFIG_ARCH_MX3 +#include +#endif + +#ifdef CONFIG_ARCH_MX27 +#include +#endif + +#ifdef CONFIG_M54455 +#include +#endif + + +static void fsl_platform_set_vbus_power(struct platform_device *pdev, int on) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + + if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power) + pdata->xcvr_ops->set_vbus_power(pdata, on); +} #endif /* _EHCI_FSL_H */ --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -122,6 +122,12 @@ struct ehci_hcd { /* one per controlle u8 sbrn; /* packed release number */ + /* + * OTG controllers and transceivers need software interaction; + * other external transceivers should be software-transparent + */ + struct otg_transceiver *transceiver; + /* irq statistics */ #ifdef EHCI_STATS struct ehci_stats stats; @@ -753,6 +759,22 @@ ehci_port_speed(struct ehci_hcd *ehci, u #define writel_be(val, addr) __raw_writel(val, (__force unsigned *)addr) #endif +#if defined(CONFIG_COLDFIRE) +/* + * Sorry, include/asm-m68k/io.h is messed up. It will give you a + * BE readl or a LE readl depending on whether or not CONFIG_PCI is set. + * how broken is that? Do the right thing here. + */ +#undef readl +#undef writel + +#define readl(addr) in_le32((__force unsigned *)(addr)) +#define writel(val,addr) out_le32((__force unsigned *)(addr),(val)) + +#define readl_be(addr) in_be32((__force unsigned *)(addr)) +#define writel_be(val, addr) out_be32((__force unsigned *)(addr), (val)) +#endif + static inline unsigned int ehci_readl(const struct ehci_hcd *ehci, __u32 __iomem * regs) { --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1043,6 +1043,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ixp4xx_ehci_driver #endif +#ifdef CONFIG_M54455 +#include "ehci-arc.c" +#define PLATFORM_DRIVER ehci_fsl_driver +#endif + #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) #error "missing bus glue for ehci-hcd" --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -40,7 +40,8 @@ static inline void ehci_qtd_init(struct { memset (qtd, 0, sizeof *qtd); qtd->qtd_dma = dma; - qtd->hw_token = cpu_to_le32 (QTD_STS_HALT); + // DDD official code` has: qtd->hw_token = cpu_to_le32 (QTD_STS_HALT); + qtd->hw_token = cpu_to_hc32 (ehci, QTD_STS_HALT); qtd->hw_next = EHCI_LIST_END(ehci); qtd->hw_alt_next = EHCI_LIST_END(ehci); INIT_LIST_HEAD (&qtd->qtd_list); @@ -211,9 +212,11 @@ static int ehci_mem_init (struct ehci_hc } /* Hardware periodic table */ - ehci->periodic = (__le32 *) + // DDD official code has: ehci->periodic = (__le32 *) + ehci->periodic = (__hc32 *) dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller, - ehci->periodic_size * sizeof(__le32), + // DDD official: ehci->periodic_size * sizeof(__le32), + ehci->periodic_size * sizeof(__hc32), &ehci->periodic_dma, 0); if (ehci->periodic == NULL) { goto fail; --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -32,6 +32,7 @@ config USB_EHCI_HCD config USB_EHCI_ROOT_HUB_TT bool "Root Hub Transaction Translators (EXPERIMENTAL)" depends on USB_EHCI_HCD && EXPERIMENTAL + default y if M54455 ---help--- Some EHCI chips have vendor-specific extensions to integrate transaction translators, so that no OHCI or UHCI companion @@ -60,12 +61,12 @@ config USB_EHCI_TT_NEWSCHED config USB_EHCI_BIG_ENDIAN_MMIO bool - depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX) + depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || M54455) default y config USB_EHCI_BIG_ENDIAN_DESC bool - depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX) + depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || M54455) default y config USB_EHCI_FSL @@ -260,3 +261,19 @@ config USB_R8A66597_HCD To compile this driver as a module, choose M here: the module will be called r8a66597-hcd. +choice + prompt "Select transceiver" + depends on M54455 + default USB_M5445X_ULPI + +config USB_M5445X_ULPI + bool "External ULPI" + ---help--- + Enable support for the external HS ULPI transceiver. + +config USB_M5445X_FSLS + bool "On-chip (FL/LS only)" + ---help--- + Enable support for the on-chip FL/LS transceiver. +endchoice + --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -6,7 +6,7 @@ ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif -obj-$(CONFIG_PCI) += pci-quirks.o +#obj-$(CONFIG_PCI) += pci-quirks.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -55,6 +55,7 @@ config USB_ARCH_HAS_EHCI default y if PPC_83xx default y if SOC_AU1200 default y if ARCH_IXP4XX + default y if M54455 default PCI # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -32,3 +32,5 @@ obj-$(CONFIG_USB) += misc/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ + +obj-$(CONFIG_USB_OTG) += otg/ --- /dev/null +++ b/drivers/usb/otg/fsl_otg.c @@ -0,0 +1,1306 @@ +/* + * Copyright (c) Freescale Semiconductor, Inc. 2006-2007 + * + * USB OTG ULPI driver + * + * Based on code for MPC from: + * Leo Li + * Jerry Huang + * + * and M5329 code from + * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com + * Andrey Butok + * + * Initialization based on code from Shlomi Gridish. + * + * 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. + *************************************************************************** + * Changes: + * v0.3 08 August 2007 Duck + * v0.2 20 October 2006 Andrey Butok + * Issues fixing and some changes. + * v0.1 September 2006 Yaroslav Vinogradov + * Initial version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined CONFIG_M54455 +#include +#endif + +#define USE_WORK_QUEUES +#include "fsl_otg.h" + +#define CONFIG_USB_OTG_DEBUG_FILES +#define DRIVER_VERSION "Revision: 1.56" +#define DRIVER_AUTHOR "Freescale Semiconductor Inc." +#define DRIVER_DESC "Freescale USB OTG ULPI Driver" +#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC + +MODULE_DESCRIPTION("Freescale USB OTG Controller Driver"); + +static const char driver_name[] = "fsl-usb2-otg"; + +static spinlock_t usb_dr_regs_lock; + +/*#define HA_DATA_PULSE 1*/ + +volatile static struct fsl_usb_device_regs *usb_dr_regs; +static struct fsl_otg *fsl_otg_dev; +static int srp_wait_done; + +/* Driver specific timers */ +struct fsl_otg_timer *b_data_pulse_tmr, *b_vbus_pulse_tmr, *b_srp_fail_tmr, + *b_srp_wait_tmr, *a_wait_enum_tmr; + +static struct list_head active_timers; + +static struct fsl_otg_config fsl_otg_initdata = { + .otg_port = 1, +}; + +#if 0 +static void dump_state(const char *string, struct otg_fsm *fsm) +{ + printk(KERN_DEBUG "%s\n\tOTG state: %s\n", string, + state_string(fsl_otg_dev->otg.state)); + printk(KERN_DEBUG "\tFSM protocol=%s\n", fsm->protocol ? + (fsm->protocol == PROTO_HOST ? "Host" : "Gadget") + : "None"); + + /* regs */ + printk(KERN_DEBUG "\t OTGSC 0x%08x\n", + fsl_readl(&usb_dr_regs->otgsc)); + printk(KERN_DEBUG "\tPORTSC1 0x%08x\n", + fsl_readl(&usb_dr_regs->portsc1)); + printk(KERN_DEBUG "\tUSBMODE 0x%08x\n", + fsl_readl(&usb_dr_regs->usbmode)); + printk(KERN_DEBUG "\t USBCMD 0x%08x\n", + fsl_readl(&usb_dr_regs->usbcmd)); + printk(KERN_DEBUG "\t USBSTS 0x%08x\n", + fsl_readl(&usb_dr_regs->usbsts)); + + /* ------ State Machine Variables ----- */ + printk(KERN_DEBUG "\ta_bus_req: %d\n", fsm->a_bus_req); + printk(KERN_DEBUG "\tb_bus_req: %d\n", fsm->b_bus_req); + printk(KERN_DEBUG "\ta_bus_resume: %d\n", fsm->a_bus_resume); + printk(KERN_DEBUG "\ta_bus_suspend: %d\n", fsm->a_bus_suspend); + printk(KERN_DEBUG "\ta_conn: %d\n", fsm->a_conn); + printk(KERN_DEBUG "\ta_sess_vld: %d\n", fsm->a_sess_vld); + printk(KERN_DEBUG "\ta_srp_det: %d\n", fsm->a_srp_det); + printk(KERN_DEBUG "\ta_vbus_vld: %d\n", fsm->a_vbus_vld); + printk(KERN_DEBUG "\tb_bus_resume: %d\n", fsm->b_bus_resume); + printk(KERN_DEBUG "\tb_bus_suspend: %d\n", fsm->b_bus_suspend); + printk(KERN_DEBUG "\tb_conn: %d\n", fsm->b_conn); + printk(KERN_DEBUG "\tb_se0_srp: %d\n", fsm->b_se0_srp); + printk(KERN_DEBUG "\tb_sess_end: %d\n", fsm->b_sess_end); + printk(KERN_DEBUG "\tb_sess_vld: %d\n", fsm->b_sess_vld); + printk(KERN_DEBUG "\tid: %d\n", fsm->id); +} +#endif + + +/* Routines to access transceiver ULPI registers */ +u8 view_ulpi(u8 addr) +{ + u32 temp; + + temp = 0x40000000 | (addr << 16); + fsl_writel(temp, &usb_dr_regs->ulpiview); + + udelay(1000); + + /* DDD timeout this loop: */ + do { + temp = fsl_readl(&usb_dr_regs->ulpiview); + } while (temp & 0x40000000); + + return (temp & 0x0000ff00) >> 8; +} + +int write_ulpi(u8 addr, u8 data) +{ + u32 temp; + + temp = 0x60000000 | (addr << 16) | data; + fsl_writel(temp, &usb_dr_regs->ulpiview); + return 0; +} + +/* prototype declaration */ +void fsl_otg_add_timer(void *timer); +void fsl_otg_del_timer(void *timer); + +/* -------------------------------------------------------------*/ +/* Operations that will be called from OTG Finite State Machine */ + +/* Charge vbus for vbus pulsing in SRP */ +void fsl_otg_chrg_vbus(int on) +{ + u32 tmp; + + VDBG(" %d\n", on); + + tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK; + + if (on) { + tmp &= ~OTGSC_CTRL_VBUS_DISCHARGE; + tmp |= OTGSC_CTRL_VBUS_CHARGE; + } else { + tmp &= ~OTGSC_CTRL_VBUS_CHARGE; + } + fsl_writel(tmp, &usb_dr_regs->otgsc); +} + +/* Discharge vbus through a resistor to ground */ +void fsl_otg_dischrg_vbus(int on) +{ + u32 tmp; + + VDBG(" %d\n", on); + + tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK; + + if (on) + tmp |= OTGSC_CTRL_VBUS_DISCHARGE; + else + tmp &= ~OTGSC_CTRL_VBUS_DISCHARGE; + + fsl_writel(tmp, &usb_dr_regs->otgsc); +} + +/* A-device driver vbus, controlled through PP bit in PORTSC */ +void fsl_otg_drv_vbus(int on) +{ + u32 tmp; + + VDBG(" %d\n", on); + + tmp = fsl_readl(&usb_dr_regs->portsc1) & ~PORTSCX_W1C_BITS; + + if (on) + tmp |= PORTSCX_PORT_POWER; + else + tmp &= ~PORTSCX_PORT_POWER; + + fsl_writel(tmp, &usb_dr_regs->portsc1); +} + +/* Pull-up D+, signalling connect by periperal. Also used in + * data-line pulsing in SRP */ +void fsl_otg_loc_conn(int on) +{ + u32 tmp; + + VDBG(" %d\n", on); + + tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK; + + if (on) + tmp |= OTGSC_CTRL_DATA_PULSING; + else + tmp &= ~OTGSC_CTRL_DATA_PULSING; + + fsl_writel(tmp, &usb_dr_regs->otgsc); +} + +/* Generate SOF by host. This is controlled through suspend/resume the + * port. In host mode, controller will automatically send SOF. + * Suspend will block the data on the port. + */ +void fsl_otg_loc_sof(int on) +{ + u32 tmp; + + VDBG(" %d\n", on); + + tmp = fsl_readl(&usb_dr_regs->portsc1) & ~PORTSCX_W1C_BITS; + + if (on) + tmp |= PORTSCX_PORT_FORCE_RESUME; + else + tmp |= PORTSCX_PORT_SUSPEND; + + fsl_writel(tmp, &usb_dr_regs->portsc1); +} + +/* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */ +void fsl_otg_start_pulse(void) +{ + u32 __attribute__ ((unused)) tmp; + + VDBG("\n"); + srp_wait_done = 0; + +#ifdef HA_DATA_PULSE + tmp = fsl_readl(&usb_dr_regs->otgsc) &= ~OTGSC_INTSTS_MASK; + tmp |= OTGSC_HA_DATA_PULSE; + fsl_writel(tmp, &usb_dr_regs->otgsc); +#else + fsl_otg_loc_conn(1); +#endif + + fsl_otg_add_timer(b_data_pulse_tmr); +} + +void fsl_otg_pulse_vbus(void); + +void b_data_pulse_end(unsigned long foo) +{ +#ifdef HA_DATA_PULSE +#else + fsl_otg_loc_conn(0); +#endif + + /* Do VBUS pulse after data pulse */ + fsl_otg_pulse_vbus(); +} + +void fsl_otg_pulse_vbus(void) +{ + srp_wait_done = 0; + fsl_otg_chrg_vbus(1); + /* start the timer to end vbus charge */ + fsl_otg_add_timer(b_vbus_pulse_tmr); +} + +void b_vbus_pulse_end(unsigned long foo) +{ + fsl_otg_chrg_vbus(0); + + /* As USB3300 using the same a_sess_vld and b_sess_vld voltage + * we need to discharge the bus for a while to distinguish + * residual voltage of vbus pulsing and A device pull up */ + fsl_otg_dischrg_vbus(1); + fsl_otg_add_timer(b_srp_wait_tmr); +} + +void b_srp_end(unsigned long foo) +{ + fsl_otg_dischrg_vbus(0); + srp_wait_done = 1; + + if ((fsl_otg_dev->otg.state == OTG_STATE_B_SRP_INIT) && + fsl_otg_dev->fsm.b_sess_vld) + fsl_otg_dev->fsm.b_srp_done = 1; +} + +/* Workaround for a_host suspending too fast. When a_bus_req=0, + * a_host will start by SRP. It needs to set b_hnp_enable before + * actually suspending to start HNP + */ +void a_wait_enum(unsigned long foo) +{ + VDBG("a_wait_enum timeout\n"); + if (!fsl_otg_dev->otg.host->b_hnp_enable) + fsl_otg_add_timer(a_wait_enum_tmr); + else + otg_statemachine(&fsl_otg_dev->fsm); +} + +/* ------------------------------------------------------*/ + +/* The timeout callback function to set time out bit */ +void set_tmout(unsigned long indicator) +{ + *(int *)indicator = 1; +} + +/* Initialize timers */ +void fsl_otg_init_timers(struct otg_fsm *fsm) +{ + /* FSM used timers */ + fsm->a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE, + (unsigned long)&fsm->a_wait_vrise_tmout); + fsm->a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON, + (unsigned long)&fsm->a_wait_bcon_tmout); + fsm->a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS, + (unsigned long)&fsm->a_aidl_bdis_tmout); + fsm->b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST, + (unsigned long)&fsm->b_ase0_brst_tmout); + fsm->b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP, + (unsigned long)&fsm->b_se0_srp); + fsm->b_srp_fail_tmr = otg_timer_initializer(&set_tmout, TB_SRP_FAIL, + (unsigned long)&fsm->b_srp_done); + fsm->a_wait_enum_tmr = otg_timer_initializer(&a_wait_enum, 10, + (unsigned long)&fsm); + + /* device driver used timers */ + b_srp_wait_tmr = otg_timer_initializer(&b_srp_end, TB_SRP_WAIT, 0); + b_data_pulse_tmr = otg_timer_initializer(&b_data_pulse_end, + TB_DATA_PLS, 0); + b_vbus_pulse_tmr = otg_timer_initializer(&b_vbus_pulse_end, + TB_VBUS_PLS, 0); + +} + +/* Add timer to timer list */ +void fsl_otg_add_timer(void *gtimer) +{ + struct fsl_otg_timer *timer = (struct fsl_otg_timer *)gtimer; + struct fsl_otg_timer *tmp_timer; + + /* Check if the timer is already in the active list, + * if so update timer count + */ + list_for_each_entry(tmp_timer, &active_timers, list) + if (tmp_timer == timer) { + timer->count = timer->expires; + return; + } + timer->count = timer->expires; + list_add_tail(&timer->list, &active_timers); +} + +/* Remove timer from the timer list; clear timeout status */ +void fsl_otg_del_timer(void *gtimer) +{ + struct fsl_otg_timer *timer = (struct fsl_otg_timer *)gtimer; + struct fsl_otg_timer *tmp_timer, *del_tmp; + + list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) + if (tmp_timer == timer) + list_del(&timer->list); +} + +/* + * Reduce timer count by 1, and find timeout conditions. + * Called by fsl_otg 1ms timer interrupt + */ +int fsl_otg_tick_timer(void) +{ + struct fsl_otg_timer *tmp_timer, *del_tmp; + int expired = 0; + + list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) { + tmp_timer->count--; + /* check if timer expires */ + if (!tmp_timer->count) { + list_del(&tmp_timer->list); + tmp_timer->function(tmp_timer->data); + expired = 1; + } + } + + return expired; +} + +/* Reset controller, not reset the bus */ +void otg_reset_controller(void) +{ + u32 command; + unsigned long flags; + int timeout; + + VDBG("\n"); + + spin_lock_irqsave(&usb_dr_regs_lock, flags); + + command = fsl_readl(&usb_dr_regs->usbcmd); + command |= USB_CMD_CTRL_RESET; + fsl_writel(command, &usb_dr_regs->usbcmd); + spin_unlock_irqrestore(&usb_dr_regs_lock, flags); + + /* Wait reset completed */ + timeout = 500; + while (fsl_readl(&usb_dr_regs->usbcmd) & USB_CMD_CTRL_RESET) + udelay(1); + if (timeout <= 0) + ERR("%s - USBCMD_RST never clear. Timeout is %d \n", + __FUNCTION__, timeout); +} + +/* Call suspend/resume routines in host driver */ +int fsl_otg_start_host(struct otg_fsm *fsm, int on) +{ + struct otg_transceiver *xceiv = fsm->transceiver; + struct device *dev; + struct fsl_otg *otg_dev = container_of(xceiv, struct fsl_otg, otg); + u32 retval = 0; + + if (!xceiv->host) + return -ENODEV; + + dev = xceiv->host->controller; + + /* + * Update a_vbus_vld state as a_vbus_vld int is disabled + * in device mode + */ + fsm->a_vbus_vld = + !!(fsl_readl(&usb_dr_regs->otgsc) & OTGSC_STS_A_VBUS_VALID); + if (on) { + /* start fsl usb host controller */ + if (otg_dev->host_working) + goto end; + else { + otg_reset_controller(); + VDBG("host on......\n"); + if (dev->driver->resume) { + retval = dev->driver->resume(dev); + if (fsm->id) { + /* default-b */ + fsl_otg_drv_vbus(1); + /* Workaround: b_host can't driver + * vbus, but PP in PORTSC needs to + * be 1 for host to work. + * So we set drv_vbus bit in + * transceiver to 0 thru ULPI. */ + write_ulpi(0x0c, 0x20); + } + } + + otg_dev->host_working = 1; + } + } else { + /* stop fsl usb host controller */ + if (!otg_dev->host_working) + goto end; + else { + VDBG("host off......\n"); + if (dev && dev->driver) { + retval = dev->driver->suspend(dev, PMSG_SUSPEND); + if (fsm->id) + /* default-b */ + fsl_otg_drv_vbus(0); + } + otg_dev->host_working = 0; + } + } +end: + return retval; +} + +/* + * Call suspend and resume function in udc driver + * to stop and start udc driver. + */ +int fsl_otg_start_gadget(struct otg_fsm *fsm, int on) +{ + struct otg_transceiver *xceiv = fsm->transceiver; + struct device *dev; + + VDBG("DDD fsm=%p xceiv=%p\n", fsm, xceiv); + if (!xceiv->gadget || !xceiv->gadget->dev.parent) + return -ENODEV; + + VDBG("DDD xceiv=%p xceiv->gadget=%p parent=%p\n", xceiv, xceiv->gadget, + xceiv->gadget->dev.parent); + + VDBG("gadget %s\n", on ? "on" : "off"); + /* DDD dump_state("starting gadget", fsm); */ + + dev = xceiv->gadget->dev.parent; + + if (on) + dev->driver->resume(dev); + else + dev->driver->suspend(dev, PMSG_SUSPEND); + + return 0; +} + +#if 0 +static void fsl_otg_enable(struct otg_transceiver *otg_p) +{ + struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg); + struct otg_fsm *fsm = &(otg_dev)->fsm; + u32 otg_sc; + + /* DDD VDBG(""); */ + /* enable OTG interrupt */ + otg_sc = fsl_readl(&usb_dr_regs->otgsc); + otg_sc |= OTGSC_INTERRUPT_ENABLE_BITS_MASK; + otg_sc &= ~OTGSC_IE_1ms_TIMER; + otg_sc &= ~OTGSC_CTRL_VBUS_DISCHARGE; + otg_sc |= OTGSC_IE_USB_ID; + fsl_writel(otg_sc, &usb_dr_regs->otgsc); + + fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; + + if (fsm->id) { + otg_p->state = OTG_STATE_UNDEFINED; + } else { + otg_p->state = OTG_STATE_A_IDLE; + } + + otg_p->default_a = (fsm->id == 0); + otg_p->host->is_b_host = fsm->id; + otg_p->gadget->is_a_peripheral = !fsm->id; + + fsm->a_vbus_vld = 1; + + fsm->b_sess_vld = (otg_sc & OTGSC_STS_B_SESSION_VALID) ? 1 : 0; + fsm->a_sess_vld = (otg_sc & OTGSC_STS_A_SESSION_VALID) ? 1 : 0; + fsm->b_sess_end = (otg_sc & OTGSC_STS_B_SESSION_END) ? 1 : 0; +} +#endif + +/* + * Called by initialization code of host driver. Register host controller + * to the OTG. Suspend host for OTG role detection. + */ +static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host) +{ + struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg); + + if (!otg_p || otg_dev != fsl_otg_dev) + return -ENODEV; + + otg_p->host = host; + + otg_dev->fsm.a_bus_drop = 0; + otg_dev->fsm.a_bus_req = 1; + + if (host) { + VDBG("host off......\n"); + + otg_p->host->otg_port = fsl_otg_initdata.otg_port; + otg_p->host->is_b_host = otg_dev->fsm.id; + /* must leave time for khubd to finish its thing + * before yanking the host driver out from under it, + * so suspend the host after a short delay. + */ + otg_dev->host_working = 1; + schedule_delayed_work(&otg_dev->otg_event, 100); + return 0; + } else { /* host driver going away */ + + if (!(le32_to_cpu(otg_dev->dr_mem_map->otgsc) & + OTGSC_STS_USB_ID)) { + /* Mini-A cable connected */ + struct otg_fsm *fsm = &otg_dev->fsm; + + otg_p->state = OTG_STATE_UNDEFINED; + fsm->protocol = PROTO_UNDEF; + } + } + + otg_dev->host_working = 0; + + otg_statemachine(&otg_dev->fsm); + + return 0; +} + +/* Called by initialization code of udc. Register udc to OTG.*/ +static int fsl_otg_set_peripheral(struct otg_transceiver *otg_p, + struct usb_gadget *gadget) +{ + struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg); + + VDBG("\n"); + + if (!otg_p || otg_dev != fsl_otg_dev) + return -ENODEV; + + if (!gadget) { + if (!otg_dev->otg.default_a) + otg_p->gadget->ops->vbus_draw(otg_p->gadget, 0); + usb_gadget_vbus_disconnect(otg_dev->otg.gadget); + otg_dev->otg.gadget = 0; + otg_dev->fsm.b_bus_req = 0; + otg_statemachine(&otg_dev->fsm); + return 0; + } + + otg_p->gadget = gadget; + otg_p->gadget->is_a_peripheral = !otg_dev->fsm.id; + + otg_dev->fsm.b_bus_req = 1; + + /* start the gadget right away if the ID pin says Mini-B */ + DBG("ID pin=%d\n", otg_dev->fsm.id); + if (otg_dev->fsm.id == 1) { + fsl_otg_start_host(&otg_dev->fsm, 0); + fsl_otg_drv_vbus(0); + fsl_otg_start_gadget(&otg_dev->fsm, 1); + } + + return 0; +} + +/* Set OTG port power, only for B-device */ +static int fsl_otg_set_power(struct otg_transceiver *otg_p, unsigned mA) +{ + if (!fsl_otg_dev) + return -ENODEV; + if (otg_p->state == OTG_STATE_B_PERIPHERAL) + printk(KERN_DEBUG "FSL OTG:Draw %d mA\n", mA); + + return 0; +} + +/* Delayed pin detect interrupt processing. + * + * When the Mini-A cable is disconnected from the board, + * the pin-detect interrupt happens before the disconnnect + * interrupts for the connected device(s). In order to + * process the disconnect interrupt(s) prior to switching + * roles, the pin-detect interrupts are delayed, and handled + * by this routine. + */ +static void fsl_otg_event(struct work_struct *work) +{ + struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work); + struct otg_fsm *fsm = &og->fsm; + + VDBG("DDD fsm->id=%d\n", fsm->id); + if (fsm->id) { /* switch to gadget */ + fsl_otg_start_host(fsm, 0); + fsl_otg_drv_vbus(0); + fsl_otg_start_gadget(fsm, 1); + } +} + +/* B-device start SRP */ +static int fsl_otg_start_srp(struct otg_transceiver *otg_p) +{ + struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg); + + if (!otg_p || otg_dev != fsl_otg_dev + || otg_p->state != OTG_STATE_B_IDLE) + return -ENODEV; + + otg_dev->fsm.b_bus_req = 1; + otg_statemachine(&otg_dev->fsm); + + return 0; +} + +/* A_host suspend will call this function to start hnp */ +static int fsl_otg_start_hnp(struct otg_transceiver *otg_p) +{ + struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg); + + if (!otg_p || otg_dev != fsl_otg_dev) + return -ENODEV; + + VDBG("start_hnp.............\n"); + /* clear a_bus_req to enter a_suspend state */ + otg_dev->fsm.a_bus_req = 0; + otg_statemachine(&otg_dev->fsm); + + return 0; +} + +/* + * Interrupt handler. OTG/host/peripheral share the same int line. + * OTG driver clears OTGSC interrupts and leaves USB interrupts + * intact. It needs to have knowledge of some USB interrupts + * such as port change. + */ +irqreturn_t fsl_otg_isr(int irq, void *dev_id) +{ + struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm; + struct otg_transceiver *otg = &((struct fsl_otg *)dev_id)->otg; + u32 otg_int_src, otg_sc; + + otg_sc = fsl_readl(&usb_dr_regs->otgsc); + otg_int_src = otg_sc & OTGSC_INTSTS_MASK & (otg_sc >> 8); + + /* Only clear otg interrupts */ + fsl_writel(otg_sc, &usb_dr_regs->otgsc); + + /*FIXME: ID change not generate when init to 0 */ + fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; + otg->default_a = (fsm->id == 0); + + /* process OTG interrupts */ + if (otg_int_src) { + VDBG("\nOTG irq 0x%08x\n", otg_int_src); + + if (otg_int_src & OTGSC_INTSTS_USB_ID) { + fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; + otg->default_a = (fsm->id == 0); + /* clear conn information */ + if (fsm->id) + fsm->b_conn = 0; + else + fsm->a_conn = 0; + + if (otg->host) + otg->host->is_b_host = fsm->id; + if (otg->gadget) + otg->gadget->is_a_peripheral = !fsm->id; + VDBG("ID int (ID is %d)\n", fsm->id); + + if (fsm->id) { /* switch to gadget */ + schedule_delayed_work(&((struct fsl_otg *) + dev_id)->otg_event, 25); + } else { /* switch to host */ + cancel_delayed_work(& + ((struct fsl_otg *)dev_id)-> + otg_event); + fsl_otg_start_gadget(fsm, 0); + fsl_otg_drv_vbus(1); + fsl_otg_start_host(fsm, 1); + } + + return IRQ_HANDLED; + } + } + + return IRQ_NONE; +} + + +static struct otg_fsm_ops fsl_otg_ops = { + .chrg_vbus = fsl_otg_chrg_vbus, + .drv_vbus = fsl_otg_drv_vbus, + .loc_conn = fsl_otg_loc_conn, + .loc_sof = fsl_otg_loc_sof, + .start_pulse = fsl_otg_start_pulse, + + .add_timer = fsl_otg_add_timer, + .del_timer = fsl_otg_del_timer, + + .start_host = fsl_otg_start_host, + .start_gadget = fsl_otg_start_gadget, +}; + +/* Initialize the global variable fsl_otg_dev and request IRQ for OTG */ +int fsl_otg_cfg(struct platform_device *pdev) +{ + int status; + struct fsl_otg *fsl_otg_tc; + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct resource *res; + + DBG("\n"); + + if (fsl_otg_dev) + return 0; + + /* allocate space to fsl otg device */ + fsl_otg_tc = kzalloc(sizeof(struct fsl_otg), GFP_KERNEL); + if (!fsl_otg_tc) + return -ENODEV; + + if (pdata->regs) { + fsl_otg_tc->dr_mem_map = pdata->regs; + } else { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no register addr.\n"); + return -ENODEV; + } + + /* + printk("DDD %s(): rsrc_start=0x%x rsrc_len=0x%x\n", + __FUNCTION__, res->start, res->end - res->start + 1); + */ + + if (!request_mem_region(res->start, res->end - res->start + 1, + "OTG")) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); + return -EBUSY; + } + fsl_otg_tc->dr_mem_map = ioremap(res->start, + res->end - res->start + 1); + } + DBG("set dr_mem_map to 0x%p\n", fsl_otg_tc->dr_mem_map); + + INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event); + + INIT_LIST_HEAD(&active_timers); + fsl_otg_init_timers(&fsl_otg_tc->fsm); + + /* Set OTG state machine operations */ + fsl_otg_tc->fsm.ops = &fsl_otg_ops; + + /* record initial state of ID pin */ + fsl_otg_tc->fsm.id = (fsl_otg_tc->dr_mem_map->otgsc & OTGSC_STS_USB_ID) + ? 1 : 0; + DBG("initial ID pin=%d\n", fsl_otg_tc->fsm.id); + + /* initialize the otg structure */ + fsl_otg_tc->otg.label = DRIVER_DESC; + fsl_otg_tc->otg.set_host = fsl_otg_set_host; + fsl_otg_tc->otg.set_peripheral = fsl_otg_set_peripheral; + fsl_otg_tc->otg.set_power = fsl_otg_set_power; + fsl_otg_tc->otg.start_hnp = fsl_otg_start_hnp; + fsl_otg_tc->otg.start_srp = fsl_otg_start_srp; + + fsl_otg_dev = fsl_otg_tc; + + /* Store the otg transceiver */ + status = otg_set_transceiver(&fsl_otg_tc->otg); + if (status) { + printk(KERN_WARNING ": unable to register OTG transceiver.\n"); + return status; + } + + return 0; +} + +/* OTG Initialization*/ +int usb_otg_start(struct platform_device *pdev) +{ + struct fsl_otg *p_otg; + struct otg_transceiver *otg_trans = otg_get_transceiver(); + struct otg_fsm *fsm; + int status; + u32 temp; + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + int timeout; + + DBG("\n"); + + p_otg = container_of(otg_trans, struct fsl_otg, otg); + fsm = &p_otg->fsm; + + /* Initialize the state machine structure with default values */ + SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED); + fsm->transceiver = &p_otg->otg; + + usb_dr_regs = p_otg->dr_mem_map; + DBG("set usb_dr_regs to 0x%p\n", usb_dr_regs); + + /* request irq */ + p_otg->irq = platform_get_irq(pdev, 0); + status = request_irq(p_otg->irq, fsl_otg_isr, + IRQF_SHARED, driver_name, p_otg); + if (status) { + dev_dbg(p_otg->otg.dev, "can't get IRQ %d, error %d\n", + p_otg->irq, status); + kfree(p_otg); + return status; + } + + + /* stop the controller */ + temp = fsl_readl(&usb_dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; + fsl_writel(temp, &usb_dr_regs->usbcmd); + + /* reset the controller */ + temp = fsl_readl(&usb_dr_regs->usbcmd); + temp |= USB_CMD_CTRL_RESET; + fsl_writel(temp, &usb_dr_regs->usbcmd); + + /* wait reset completed */ + timeout = 500; + while (timeout-- && + fsl_readl(&usb_dr_regs->usbcmd) & USB_CMD_CTRL_RESET) + udelay(1); + if (timeout <= 0) + ERR("%s - USBCMD_RST never clear. Timeout is %d \n", + __FUNCTION__, timeout); + + /* configure the VBUSHS as IDLE(both host and device) */ + temp = USB_MODE_STREAM_DISABLE | (pdata->es ? USBMODE_ES : 0); + fsl_writel(temp, &usb_dr_regs->usbmode); + + /* configure PHY interface */ + temp = fsl_readl(&usb_dr_regs->portsc1); + temp &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PTW_8BIT); + + /* DDD wrong xcvr setting stuff follows */ + temp |= PORTSCX_PTS_ULPI; + fsl_writel(temp, &usb_dr_regs->portsc1); + + + /* disable all interrupt and clear all OTGSC status */ + temp = fsl_readl(&usb_dr_regs->otgsc); + temp &= ~OTGSC_INTERRUPT_ENABLE_BITS_MASK; + temp |= OTGSC_INTERRUPT_STATUS_BITS_MASK | OTGSC_CTRL_VBUS_DISCHARGE; + fsl_writel(temp, &usb_dr_regs->otgsc); + + fsl_otg_drv_vbus(0); + + /* + * The identification (id) input is FALSE when a Mini-A plug is inserted + * in the devices Mini-AB receptacle. Otherwise, this input is TRUE. + * Also: record initial state of ID pin + */ + if (fsl_readl(&usb_dr_regs->otgsc) & OTGSC_STS_USB_ID) { + p_otg->otg.state = OTG_STATE_UNDEFINED; + p_otg->fsm.id = 1; + } else { + p_otg->otg.state = OTG_STATE_A_IDLE; + p_otg->fsm.id = 0; + } + + DBG("initial ID pin=%d\n", p_otg->fsm.id); + + /* enable OTG ID pin interrupt */ + temp = fsl_readl(&usb_dr_regs->otgsc); + temp |= OTGSC_IE_USB_ID; + temp &= ~(OTGSC_CTRL_VBUS_DISCHARGE | OTGSC_IE_1ms_TIMER); + fsl_writel(temp, &usb_dr_regs->otgsc); + + return 0; +} + +/* Initialize board specific registers,PIB board,clock and pin multiplexing */ +static int board_init(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata; + pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; + + /* + * do platform specific init: check the clock, grab/config pins, etc. + */ + if (pdata->platform_init(pdev) != 0) + return -EINVAL; + + return 0; +} + +/*------------------------------------------------------------------------- + PROC File System Support +-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_OTG_DEBUG_FILES + +#include + +static const char proc_filename[] = "driver/fsl_usb2_otg"; + +static int otg_proc_read(char *page, char **start, off_t off, int count, + int *eof, void *_dev) +{ + struct otg_fsm *fsm = &fsl_otg_dev->fsm; + char *buf = page; + char *next = buf; + unsigned size = count; + unsigned long flags; + int t; + u32 tmp_reg; + + if (off != 0) + return 0; + + spin_lock_irqsave(&fsm->lock, flags); + + /* ------basic driver infomation ---- */ + t = scnprintf(next, size, + DRIVER_DESC "\n" "fsl_usb2_otg version: %s\n\n", + DRIVER_VERSION); + size -= t; + next += t; + + /* ------ Registers ----- */ + /* tmp_reg = le32_to_cpu(usb_dr_regs->otgsc); */ + tmp_reg = fsl_readl(&usb_dr_regs->otgsc); + t = scnprintf(next, size, "OTGSC reg: 0x%08x\n", tmp_reg); + size -= t; + next += t; + + /* tmp_reg = le32_to_cpu(usb_dr_regs->portsc); */ + tmp_reg = fsl_readl(&usb_dr_regs->portsc1); + t = scnprintf(next, size, "PORTSC reg: 0x%08x\n", tmp_reg); + size -= t; + next += t; + + /* tmp_reg = le32_to_cpu(usb_dr_regs->usbmode); */ + tmp_reg = fsl_readl(&usb_dr_regs->usbmode); + t = scnprintf(next, size, "USBMODE reg: 0x%08x\n", tmp_reg); + size -= t; + next += t; + + /* tmp_reg = le32_to_cpu(usb_dr_regs->usbcmd); */ + tmp_reg = fsl_readl(&usb_dr_regs->usbcmd); + t = scnprintf(next, size, "USBCMD reg: 0x%08x\n", tmp_reg); + size -= t; + next += t; + + /* tmp_reg = le32_to_cpu(usb_dr_regs->usbsts); */ + tmp_reg = fsl_readl(&usb_dr_regs->usbsts); + t = scnprintf(next, size, "USBSTS reg: 0x%08x\n", tmp_reg); + size -= t; + next += t; + + /* ------ State ----- */ + t = scnprintf(next, size, "FSM protocol=%d %s\n", fsm->protocol, + fsm->protocol ? + (fsm->protocol == PROTO_HOST ? "Host" : "Gadget") + : "None"); + size -= t; + next += t; + + t = scnprintf(next, size, + "OTG state: %s\n\n", + state_string(fsl_otg_dev->otg.state)); + size -= t; + next += t; + + /* ------ State Machine Variables ----- */ + t = scnprintf(next, size, "a_bus_req: %d\n", fsm->a_bus_req); + size -= t; + next += t; + + t = scnprintf(next, size, "b_bus_req: %d\n", fsm->b_bus_req); + size -= t; + next += t; + + t = scnprintf(next, size, "a_bus_resume: %d\n", fsm->a_bus_resume); + size -= t; + next += t; + + t = scnprintf(next, size, "a_bus_suspend: %d\n", fsm->a_bus_suspend); + size -= t; + next += t; + + t = scnprintf(next, size, "a_conn: %d\n", fsm->a_conn); + size -= t; + next += t; + + t = scnprintf(next, size, "a_sess_vld: %d\n", fsm->a_sess_vld); + size -= t; + next += t; + + t = scnprintf(next, size, "a_srp_det: %d\n", fsm->a_srp_det); + size -= t; + next += t; + + t = scnprintf(next, size, "a_vbus_vld: %d\n", fsm->a_vbus_vld); + size -= t; + next += t; + + t = scnprintf(next, size, "b_bus_resume: %d\n", fsm->b_bus_resume); + size -= t; + next += t; + + t = scnprintf(next, size, "b_bus_suspend: %d\n", fsm->b_bus_suspend); + size -= t; + next += t; + + t = scnprintf(next, size, "b_conn: %d\n", fsm->b_conn); + size -= t; + next += t; + + t = scnprintf(next, size, "b_se0_srp: %d\n", fsm->b_se0_srp); + size -= t; + next += t; + + t = scnprintf(next, size, "b_sess_end: %d\n", fsm->b_sess_end); + size -= t; + next += t; + + t = scnprintf(next, size, "b_sess_vld: %d\n", fsm->b_sess_vld); + size -= t; + next += t; + + t = scnprintf(next, size, "id: %d\n", fsm->id); + size -= t; + next += t; + + spin_unlock_irqrestore(&fsm->lock, flags); + + *eof = 1; + return count - size; +} + +#define create_proc_file() create_proc_read_entry(proc_filename, \ + 0, NULL, otg_proc_read, NULL) + +#define remove_proc_file() remove_proc_entry(proc_filename, NULL) + +#else /* !CONFIG_USB_OTG_DEBUG_FILES */ + +#define create_proc_file() do {} while (0) +#define remove_proc_file() do {} while (0) + +#endif /*CONFIG_USB_OTG_DEBUG_FILES */ + +/*----------------------------------------------------------*/ +/* Char driver interface to control some OTG input */ + +/* + * This function handle some ioctl command,such as get otg + * status and set host suspend + */ +static int fsl_otg_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + u32 retval = 0; + + switch (cmd) { + case GET_OTG_STATUS: + retval = fsl_otg_dev->host_working; + break; + + case SET_A_SUSPEND_REQ: + fsl_otg_dev->fsm.a_suspend_req = arg; + break; + + case SET_A_BUS_DROP: + fsl_otg_dev->fsm.a_bus_drop = arg; + break; + + case SET_A_BUS_REQ: + fsl_otg_dev->fsm.a_bus_req = arg; + break; + + case SET_B_BUS_REQ: + fsl_otg_dev->fsm.b_bus_req = arg; + break; + + default: + break; + } + + otg_statemachine(&fsl_otg_dev->fsm); + + return retval; +} + +static int fsl_otg_open(struct inode *inode, struct file *file) +{ + + return 0; +} + +static int fsl_otg_release(struct inode *inode, struct file *file) +{ + + return 0; +} + +static struct file_operations otg_fops = { + .owner = THIS_MODULE, + .llseek = NULL, + .read = NULL, + .write = NULL, + .ioctl = fsl_otg_ioctl, + .open = fsl_otg_open, + .release = fsl_otg_release, +}; + +static int __init fsl_otg_probe(struct platform_device *pdev) +{ + int status; + struct fsl_usb2_platform_data *pdata; + + DBG("pdev=0x%p\n", pdev); + + if (!pdev) + return -ENODEV; + + if (!pdev->dev.platform_data) + return -ENOMEM; + + pdata = pdev->dev.platform_data; + /* Initialize the clock, multiplexing pin and PHY interface */ + board_init(pdev); + + /* configure the OTG */ + status = fsl_otg_cfg(pdev); + if (status) { + printk(KERN_INFO "Couldn't init OTG module\n"); + return -status; + } + + /* start OTG */ + status = usb_otg_start(pdev); + + if (register_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME, &otg_fops)) { + printk(KERN_WARNING FSL_OTG_NAME + ": unable to register FSL OTG device\n"); + return -EIO; + } + + create_proc_file(); + return status; +} + +static int fsl_otg_remove(struct platform_device *pdev) +{ + u32 ie; + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + unsigned long flags; + + DBG("pdev=0x%p pdata=0x%p\n", pdev, pdata); + + otg_set_transceiver(NULL); + + /* disable and clear OTGSC interrupts */ + spin_lock_irqsave(&usb_dr_regs_lock, flags); + ie = fsl_readl(&usb_dr_regs->otgsc); + ie &= ~OTGSC_INTERRUPT_ENABLE_BITS_MASK; + ie |= OTGSC_INTERRUPT_STATUS_BITS_MASK; + fsl_writel(ie, &usb_dr_regs->otgsc); + spin_unlock_irqrestore(&usb_dr_regs_lock, flags); + + free_irq(fsl_otg_dev->irq, fsl_otg_dev); + + kfree(fsl_otg_dev); + + remove_proc_file(); + + unregister_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME); + + if (pdata->platform_uninit) + pdata->platform_uninit(pdev); + + fsl_otg_dev = NULL; + return 0; +} + +struct platform_driver fsl_otg_driver = { + .probe = fsl_otg_probe, + .remove = fsl_otg_remove, + .driver = { + .name = driver_name, + .owner = THIS_MODULE, + }, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init fsl_usb_otg_init(void) +{ + printk(KERN_INFO DRIVER_DESC " loaded, %s\n", DRIVER_VERSION); + return platform_driver_register(&fsl_otg_driver); +} + +static void __exit fsl_usb_otg_exit(void) +{ + platform_driver_unregister(&fsl_otg_driver); +} + +module_init(fsl_usb_otg_init); +module_exit(fsl_usb_otg_exit); + +MODULE_DESCRIPTION(DRIVER_INFO); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); --- /dev/null +++ b/drivers/usb/otg/fsl_otg.h @@ -0,0 +1,139 @@ +/* + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef FSL_OTG_H +#define FSL_OTG_H +#include +#include "otg_fsm.h" +#include + +#define ERR(format, arg...) \ +printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) + +/* + * A-DEVICE timing constants + */ + +/* Wait for VBUS Rise */ +#define TA_WAIT_VRISE (100) /* a_wait_vrise 100 ms, section: 6.6.5.1 */ + +/* Wait for B-Connect */ +#define TA_WAIT_BCON (10000) /* a_wait_bcon > 1 sec, section: 6.6.5.2 + * This is only used to get out of + * OTG_STATE_A_WAIT_BCON state if there was + * no connection for these many milliseconds + */ + +/* A-Idle to B-Disconnect */ +/* It is necessary for this timer to be more than 750 ms because of a bug in OPT + * test 5.4 in which B OPT disconnects after 750 ms instead of 75ms as stated + * in the test description + */ +#define TA_AIDL_BDIS (5000) /* a_suspend minimum 200 ms, section: 6.6.5.3 */ + +/* B-Idle to A-Disconnect */ +#define TA_BIDL_ADIS (12) /* 3 to 200 ms */ + +/* B-device timing constants */ + +/* Data-Line Pulse Time*/ +#define TB_DATA_PLS (10) /* b_srp_init,continue 5~10ms, section:5.3.3 */ +#define TB_DATA_PLS_MIN (5) /* minimum 5 ms */ +#define TB_DATA_PLS_MAX (10) /* maximum 10 ms */ + +/* SRP Initiate Time */ +#define TB_SRP_INIT (100) /* b_srp_init,maximum 100 ms, section:5.3.8 */ + +/* SRP Fail Time */ +#define TB_SRP_FAIL (7000) /* b_srp_init,Fail time 5~30s, section:6.8.2.2 */ + +/* SRP result wait time */ +#define TB_SRP_WAIT (60) + +/* VBus time */ +#define TB_VBUS_PLS (30) /* time to keep vbus pulsing asserted */ + +/* Discharge time */ +/* This time should be less than 10ms. It varies from system to system. */ +#define TB_VBUS_DSCHRG (8) + +/* A-SE0 to B-Reset */ +#define TB_ASE0_BRST (20) /* b_wait_acon, mini 3.125 ms,section:6.8.2.4 */ + +/* A bus suspend timer before we can switch to b_wait_aconn */ +#define TB_A_SUSPEND (7) +#define TB_BUS_RESUME (12) + +/* SE0 Time Before SRP */ +#define TB_SE0_SRP (2) /* b_idle,minimum 2 ms, section:5.3.2 */ + +#define SET_OTG_STATE(otg_ptr, newstate) ((otg_ptr)->state = newstate) + + +struct fsl_otg_timer { + unsigned long expires; /* Number of count increase to timeout */ + unsigned long count; /* Tick counter */ + void (*function) (unsigned long); /* Timeout function */ + unsigned long data; /* Data passed to function */ + struct list_head list; +}; + +struct fsl_otg_timer inline *otg_timer_initializer + (void (*function) (unsigned long), unsigned long expires, + unsigned long data) { + struct fsl_otg_timer *timer; + timer = kmalloc(sizeof(struct fsl_otg_timer), GFP_KERNEL); + if (timer == NULL) + return NULL; + timer->function = function; + timer->expires = expires; + timer->data = data; + return timer; +} + +struct fsl_otg { + struct otg_transceiver otg; + struct otg_fsm fsm; + struct fsl_usb_device_regs *dr_mem_map; + struct delayed_work otg_event; + + /*used for usb host */ + u8 host_working; + u8 on_off; + + int irq; +}; + +struct fsl_otg_config { + u8 otg_port; +}; + +/*For SRP and HNP handle*/ +#define FSL_OTG_MAJOR 66 +#define FSL_OTG_NAME "fsl-otg" +/*Command to OTG driver(ioctl)*/ +#define OTG_IOCTL_MAGIC FSL_OTG_MAJOR +/*if otg work as host,it should return 1,otherwise it return 0*/ +#define GET_OTG_STATUS _IOR(OTG_IOCTL_MAGIC, 1, int) +#define SET_A_SUSPEND_REQ _IOW(OTG_IOCTL_MAGIC, 2, int) +#define SET_A_BUS_DROP _IOW(OTG_IOCTL_MAGIC, 3, int) +#define SET_A_BUS_REQ _IOW(OTG_IOCTL_MAGIC, 4, int) +#define SET_B_BUS_REQ _IOW(OTG_IOCTL_MAGIC, 5, int) +#define GET_A_SUSPEND_REQ _IOR(OTG_IOCTL_MAGIC, 6, int) +#define GET_A_BUS_DROP _IOR(OTG_IOCTL_MAGIC, 7, int) +#define GET_A_BUS_REQ _IOR(OTG_IOCTL_MAGIC, 8, int) +#define GET_B_BUS_REQ _IOR(OTG_IOCTL_MAGIC, 9, int) + + +/********************************************************************/ +#endif --- /dev/null +++ b/drivers/usb/otg/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for USB OTG controller driver +# +fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o +obj-y += fsl_usb2_otg.o --- /dev/null +++ b/drivers/usb/otg/otg_fsm.c @@ -0,0 +1,381 @@ +/* OTG Finite State Machine from OTG spec + * + * Copyright (C) 2007 Freescale Semiconductor, Inc. + * + * Author: Li Yang + * Jerry Huang + * + * 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 +#include + +#include "otg_fsm.h" + + +/* Defined by device specific driver, for different timer implementation */ +extern void *a_wait_vrise_tmr, *a_wait_bcon_tmr, *a_aidl_bdis_tmr, + *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_fail_tmr, *a_wait_enum_tmr; + +const char *state_string(enum usb_otg_state state) +{ + switch (state) { + case OTG_STATE_A_IDLE: return "a_idle"; + case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise"; + case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon"; + case OTG_STATE_A_HOST: return "a_host"; + case OTG_STATE_A_SUSPEND: return "a_suspend"; + case OTG_STATE_A_PERIPHERAL: return "a_peripheral"; + case OTG_STATE_A_WAIT_VFALL: return "a_wait_vfall"; + case OTG_STATE_A_VBUS_ERR: return "a_vbus_err"; + case OTG_STATE_B_IDLE: return "b_idle"; + case OTG_STATE_B_SRP_INIT: return "b_srp_init"; + case OTG_STATE_B_PERIPHERAL: return "b_peripheral"; + case OTG_STATE_B_WAIT_ACON: return "b_wait_acon"; + case OTG_STATE_B_HOST: return "b_host"; + default: return "UNDEFINED"; + } +} +EXPORT_SYMBOL(state_string); + +/* Change USB protocol when there is a protocol change */ +static int otg_set_protocol(struct otg_fsm *fsm, int protocol) +{ + int ret = 0; + + VDBG("DDD old fsm->protocol= %d; new protocol= %d\n", + fsm->protocol, protocol); + if (fsm->protocol != protocol) { + VDBG("Changing role fsm->protocol= %d; new protocol= %d\n", + fsm->protocol, protocol); + /* stop old protocol */ + if (fsm->protocol == PROTO_HOST) + ret = fsm->ops->start_host(fsm, 0); + else if (fsm->protocol == PROTO_GADGET) + ret = fsm->ops->start_gadget(fsm, 0); + if (ret) + return ret; + + /* start new protocol */ + if (protocol == PROTO_HOST) + ret = fsm->ops->start_host(fsm, 1); + else if (protocol == PROTO_GADGET) + ret = fsm->ops->start_gadget(fsm, 1); + if (ret) + return ret; + + fsm->protocol = protocol; + return 0; + } + + return 0; +} + +static int state_changed; + +/* Called when leaving a state. Do state clean up jobs here */ +static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) +{ + switch (old_state) { + case OTG_STATE_B_IDLE: + otg_del_timer(fsm, fsm->b_se0_srp_tmr); + fsm->b_se0_srp = 0; + break; + case OTG_STATE_B_SRP_INIT: + fsm->b_srp_done = 0; + break; + case OTG_STATE_B_PERIPHERAL: + break; + case OTG_STATE_B_WAIT_ACON: + otg_del_timer(fsm, fsm->b_ase0_brst_tmr); + fsm->b_ase0_brst_tmout = 0; + break; + case OTG_STATE_B_HOST: + break; + case OTG_STATE_A_IDLE: + break; + case OTG_STATE_A_WAIT_VRISE: + otg_del_timer(fsm, fsm->a_wait_vrise_tmr); + fsm->a_wait_vrise_tmout = 0; + break; + case OTG_STATE_A_WAIT_BCON: + otg_del_timer(fsm, fsm->a_wait_bcon_tmr); + fsm->a_wait_bcon_tmout = 0; + break; + case OTG_STATE_A_HOST: + otg_del_timer(fsm, fsm->a_wait_enum_tmr); + break; + case OTG_STATE_A_SUSPEND: + otg_del_timer(fsm, fsm->a_aidl_bdis_tmr); + fsm->a_aidl_bdis_tmout = 0; + fsm->a_suspend_req = 0; + fsm->a_bus_req = 1; /* FIXME */ + break; + case OTG_STATE_A_PERIPHERAL: + break; + case OTG_STATE_A_WAIT_VFALL: + otg_del_timer(fsm, fsm->a_wait_vrise_tmr); + break; + case OTG_STATE_A_VBUS_ERR: + break; + default: + break; + } +} + +/* Called when entering a state */ +static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) +{ + state_changed = 1; + VDBG("State: old=%s new=%s \n", + state_string(fsm->transceiver->state), state_string(new_state)); + + if (fsm->transceiver->state == new_state) + return 0; + + otg_leave_state(fsm, fsm->transceiver->state); + switch (new_state) { + case OTG_STATE_B_IDLE: + otg_drv_vbus(fsm, 0); + otg_chrg_vbus(fsm, 0); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_UNDEF); + otg_add_timer(fsm, fsm->b_se0_srp_tmr); + break; + case OTG_STATE_B_SRP_INIT: + otg_start_pulse(fsm); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_UNDEF); + otg_add_timer(fsm, fsm->b_srp_fail_tmr); + break; + case OTG_STATE_B_PERIPHERAL: + otg_chrg_vbus(fsm, 0); + otg_loc_conn(fsm, 1); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_GADGET); + break; + case OTG_STATE_B_WAIT_ACON: + otg_chrg_vbus(fsm, 0); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_HOST); + otg_add_timer(fsm, fsm->b_ase0_brst_tmr); + fsm->a_bus_suspend = 0; + break; + case OTG_STATE_B_HOST: + otg_chrg_vbus(fsm, 0); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 1); + otg_set_protocol(fsm, PROTO_HOST); + usb_bus_start_enum(fsm->transceiver->host, + fsm->transceiver->host->otg_port); + break; + case OTG_STATE_A_IDLE: + otg_drv_vbus(fsm, 0); + otg_chrg_vbus(fsm, 0); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_HOST); + break; + case OTG_STATE_A_WAIT_VRISE: + otg_drv_vbus(fsm, 1); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_HOST); + otg_add_timer(fsm, fsm->a_wait_vrise_tmr); + break; + case OTG_STATE_A_WAIT_BCON: + otg_drv_vbus(fsm, 1); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_HOST); + otg_add_timer(fsm, fsm->a_wait_bcon_tmr); + break; + case OTG_STATE_A_HOST: + otg_drv_vbus(fsm, 1); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 1); + otg_set_protocol(fsm, PROTO_HOST); + /* + * When HNP is triggered while a_bus_req = 0, a_host will + * suspend too fast to complete a_set_b_hnp_en + */ + if (!fsm->a_bus_req || fsm->a_suspend_req) + otg_add_timer(fsm, fsm->a_wait_enum_tmr); + break; + case OTG_STATE_A_SUSPEND: + otg_drv_vbus(fsm, 1); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_HOST); + otg_add_timer(fsm, fsm->a_aidl_bdis_tmr); + + break; + case OTG_STATE_A_PERIPHERAL: + otg_loc_conn(fsm, 1); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_GADGET); + otg_drv_vbus(fsm, 1); + break; + case OTG_STATE_A_WAIT_VFALL: + otg_drv_vbus(fsm, 0); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_HOST); + break; + case OTG_STATE_A_VBUS_ERR: + otg_drv_vbus(fsm, 0); + otg_loc_conn(fsm, 0); + otg_loc_sof(fsm, 0); + otg_set_protocol(fsm, PROTO_UNDEF); + break; + default: + break; + } + + fsm->transceiver->state = new_state; + return 0; +} + +/* State change judgement */ +int otg_statemachine(struct otg_fsm *fsm) +{ + enum usb_otg_state state; + unsigned long flags; + + spin_lock_irqsave(&fsm->lock, flags); + + state = fsm->transceiver->state; + state_changed = 0; + /* State machine state change judgement */ + + VDBG(" State: %s \n", state_string(state)); + + switch (state) { + case OTG_STATE_UNDEFINED: + if (fsm->id) + otg_set_state(fsm, OTG_STATE_B_IDLE); + else + otg_set_state(fsm, OTG_STATE_A_IDLE); + break; + case OTG_STATE_B_IDLE: + if (!fsm->id) + otg_set_state(fsm, OTG_STATE_A_IDLE); + else if (fsm->b_sess_vld && fsm->transceiver->gadget) + otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); + else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp) + otg_set_state(fsm, OTG_STATE_B_SRP_INIT); + break; + case OTG_STATE_B_SRP_INIT: + if (!fsm->id || fsm->b_srp_done) + otg_set_state(fsm, OTG_STATE_B_IDLE); + break; + case OTG_STATE_B_PERIPHERAL: + if (!fsm->id || !fsm->b_sess_vld) + otg_set_state(fsm, OTG_STATE_B_IDLE); + else if (fsm->b_bus_req && + fsm->transceiver-> + gadget->b_hnp_enable && fsm->a_bus_suspend) + otg_set_state(fsm, OTG_STATE_B_WAIT_ACON); + break; + case OTG_STATE_B_WAIT_ACON: + if (fsm->a_conn) + otg_set_state(fsm, OTG_STATE_B_HOST); + else if (!fsm->id || !fsm->b_sess_vld) + otg_set_state(fsm, OTG_STATE_B_IDLE); + else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) { + fsm->b_ase0_brst_tmout = 0; + otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); + } + break; + case OTG_STATE_B_HOST: + if (!fsm->id || !fsm->b_sess_vld) + otg_set_state(fsm, OTG_STATE_B_IDLE); + else if (!fsm->b_bus_req || !fsm->a_conn) + otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); + break; + case OTG_STATE_A_IDLE: + if (fsm->id) + otg_set_state(fsm, OTG_STATE_B_IDLE); + else if (!fsm->a_bus_drop && (fsm->a_bus_req || fsm->a_srp_det)) + otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE); + break; + case OTG_STATE_A_WAIT_VRISE: + if (fsm->id || fsm->a_bus_drop || fsm->a_vbus_vld || + fsm->a_wait_vrise_tmout) { + otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); + } + break; + case OTG_STATE_A_WAIT_BCON: + if (!fsm->a_vbus_vld) + otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); + else if (fsm->id | fsm->a_bus_drop | fsm->a_wait_bcon_tmout) + otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); + else if (fsm->b_conn) + otg_set_state(fsm, OTG_STATE_A_HOST); + break; + case OTG_STATE_A_HOST: + if ((!fsm->a_bus_req || fsm->a_suspend_req) && + fsm->transceiver->host->b_hnp_enable) + otg_set_state(fsm, OTG_STATE_A_SUSPEND); + else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop) + otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); + else if (!fsm->a_vbus_vld) + otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); + break; + case OTG_STATE_A_SUSPEND: + if (!fsm->b_conn && fsm->transceiver->host->b_hnp_enable) + otg_set_state(fsm, OTG_STATE_A_PERIPHERAL); + else if (!fsm->b_conn && !fsm->transceiver->host->b_hnp_enable) + otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); + else if (fsm->a_bus_req || fsm->b_bus_resume) + otg_set_state(fsm, OTG_STATE_A_HOST); + else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout) + otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); + else if (!fsm->a_vbus_vld) + otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); + break; + case OTG_STATE_A_PERIPHERAL: + if (fsm->id || fsm->a_bus_drop) + otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); + else if (fsm->b_bus_suspend) + otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); + else if (!fsm->a_vbus_vld) + otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); + break; + case OTG_STATE_A_WAIT_VFALL: + if (fsm->id || fsm->a_bus_req || (!fsm->a_sess_vld && + !fsm->b_conn)) + otg_set_state(fsm, OTG_STATE_A_IDLE); + break; + case OTG_STATE_A_VBUS_ERR: + if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err) + otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); + break; + default: + break; + } + spin_unlock_irqrestore(&fsm->lock, flags); + + return state_changed; +} +EXPORT_SYMBOL(otg_statemachine); --- /dev/null +++ b/drivers/usb/otg/otg_fsm.h @@ -0,0 +1,170 @@ +/* Copyright (C) 2006-2007 Freescale Semiconductor, Inc. + * + * 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. + */ + +#ifndef OTG_FSM_H +#define OTG_FSM_H + +#if 0 +#define DEBUG 1 +#define VERBOSE 1 +#endif + +#ifdef DEBUG +#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt , \ + __FUNCTION__, ## args) +#else +#define DBG(fmt, args...) do {} while (0) +#endif + +#ifdef VERBOSE +#define VDBG DBG +#else +#define VDBG(stuff...) do {} while (0) +#endif + +#ifdef VERBOSE +#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__) +#else +#define MPC_LOC do {} while (0) +#endif + +#define PROTO_UNDEF 0 +#define PROTO_HOST 1 +#define PROTO_GADGET 2 + + + + + +/* OTG state machine according to the OTG spec */ +struct otg_fsm { + /* Input */ + int a_bus_resume; + int a_bus_suspend; + int a_conn; + int a_sess_vld; + int a_srp_det; + int a_vbus_vld; + int b_bus_resume; + int b_bus_suspend; + int b_conn; + int b_se0_srp; + int b_sess_end; + int b_sess_vld; + int id; + + /* Internal variables */ + int a_set_b_hnp_en; + int b_srp_done; + int b_hnp_enable; + + /* Timeout indicator for timers */ + int a_wait_vrise_tmout; + int a_wait_bcon_tmout; + int a_aidl_bdis_tmout; + int b_ase0_brst_tmout; + + /* Informative variables */ + int a_bus_drop; + int a_bus_req; + int a_clr_err; + int a_suspend_req; + int b_bus_req; + + /* Output */ + int drv_vbus; + int loc_conn; + int loc_sof; + + struct otg_fsm_ops *ops; + struct otg_transceiver *transceiver; + + void *a_wait_vrise_tmr; + void *a_wait_bcon_tmr; + void *a_aidl_bdis_tmr; + void *b_ase0_brst_tmr; + void *b_se0_srp_tmr; + void *b_srp_fail_tmr; + void *a_wait_enum_tmr; + + /* Current usb protocol used: 0:undefine; 1:host; 2:client */ + int protocol; + spinlock_t lock; /* fsm lock */ +}; + +struct otg_fsm_ops { + void (*chrg_vbus)(int on); + void (*drv_vbus)(int on); + void (*loc_conn)(int on); + void (*loc_sof)(int on); + void (*start_pulse)(void); + void (*add_timer)(void *timer); + void (*del_timer)(void *timer); + int (*start_host)(struct otg_fsm *fsm, int on); + int (*start_gadget)(struct otg_fsm *fsm, int on); +}; + + +static inline void otg_chrg_vbus(struct otg_fsm *fsm, int on) +{ + fsm->ops->chrg_vbus(on); +} + +static inline void otg_drv_vbus(struct otg_fsm *fsm, int on) +{ + if (fsm->drv_vbus != on) { + fsm->drv_vbus = on; + fsm->ops->drv_vbus(on); + } +} + +static inline void otg_loc_conn(struct otg_fsm *fsm, int on) +{ + if (fsm->loc_conn != on) { + fsm->loc_conn = on; + fsm->ops->loc_conn(on); + } +} + +static inline void otg_loc_sof(struct otg_fsm *fsm, int on) +{ + if (fsm->loc_sof != on) { + fsm->loc_sof = on; + fsm->ops->loc_sof(on); + } +} + +static inline void otg_start_pulse(struct otg_fsm *fsm) +{ + fsm->ops->start_pulse(); +} + +static inline void otg_add_timer(struct otg_fsm *fsm, void *timer) +{ + fsm->ops->add_timer(timer); +} + +static inline void otg_del_timer(struct otg_fsm *fsm, void *timer) +{ + fsm->ops->del_timer(timer); +} + +extern int otg_statemachine(struct otg_fsm *fsm); + +extern const char *state_string(enum usb_otg_state state); + +#endif --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -44,12 +44,12 @@ #endif static const u32 cfb_tab8[] = { -#if defined(__BIG_ENDIAN) +#if defined(__BIG_ENDIAN) && !defined(CONFIG_COLDFIRE) 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) +#elif defined(__LITTLE_ENDIAN) || defined(CONFIG_COLDFIRE) 0x00000000,0xff000000,0x00ff0000,0xffff0000, 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, @@ -60,9 +60,9 @@ static const u32 cfb_tab8[] = { }; static const u32 cfb_tab16[] = { -#if defined(__BIG_ENDIAN) +#if defined(__BIG_ENDIAN) && !defined(CONFIG_COLDFIRE) 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) +#elif defined(__LITTLE_ENDIAN) || defined(CONFIG_COLDFIRE) 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff #else #error FIXME: No endianness?? --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -78,7 +78,11 @@ static inline void bit_putcs_aligned(str u32 d_pitch, u32 s_pitch, u32 cellsize, struct fb_image *image, u8 *buf, u8 *dst) { +#ifndef CONFIG_COLDFIRE u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; +#else + u32 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; +#endif u32 idx = vc->vc_font.width >> 3; u8 *src; @@ -111,7 +115,11 @@ static inline void bit_putcs_unaligned(s struct fb_image *image, u8 *buf, u8 *dst) { +#ifndef CONFIG_COLDFIRE u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; +#else + u32 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; +#endif u32 shift_low = 0, mod = vc->vc_font.width % 8; u32 shift_high = 8; u32 idx = vc->vc_font.width >> 3; @@ -238,7 +246,11 @@ static void bit_cursor(struct vc_data *v { struct fb_cursor cursor; struct fbcon_ops *ops = info->fbcon_par; +#ifndef CONFIG_COLDFIRE unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; +#else + unsigned long charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; +#endif int w = (vc->vc_font.width + 7) >> 3, c; int y = real_y(ops->p, vc->vc_y); int attribute, use_sw = (vc->vc_cursor_type & 0x10); --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2679,8 +2679,11 @@ static int fbcon_set_palette(struct vc_d { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; int i, j, k, depth; - u8 val; - +#ifndef CONFIG_COLDFIRE + u8 val; +#else + u32 val; +#endif if (fbcon_is_inactive(vc, info)) return -EINVAL; --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -201,6 +201,16 @@ config FB_TILEBLITTING comment "Frame buffer hardware drivers" depends on FB +config FB_SMI + tristate "SiliconMotion Lynx support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This enables support for the Silicon Motion Lynx family of graphic + chips. It has been tested on ColdFire. + config FB_CIRRUS tristate "Cirrus Logic support" depends on FB && (ZORRO || PCI) --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_FB_DDC) += fb_ddc obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o # Hardware specific drivers go first +obj-$(CONFIG_FB_SMI) += smifb.o obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o --- /dev/null +++ b/drivers/video/smifb.c @@ -0,0 +1,949 @@ +/*************************************************************************** + smifb.c - Silicon Motion, Inc. LynxEM+ frame buffer device + ------------------- + begin : Thu Aug 9 2001 + copyright : (C) 2001 by Szu-Tao Huang + email : johuang@siliconmotion.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "console/fbcon.h" + +/* +#include