diff options
Diffstat (limited to 'packages/linux/linux-efika-2.6.20/0019-MPC5200-Bestcomm-platform-driver.txt')
-rw-r--r-- | packages/linux/linux-efika-2.6.20/0019-MPC5200-Bestcomm-platform-driver.txt | 1439 |
1 files changed, 1439 insertions, 0 deletions
diff --git a/packages/linux/linux-efika-2.6.20/0019-MPC5200-Bestcomm-platform-driver.txt b/packages/linux/linux-efika-2.6.20/0019-MPC5200-Bestcomm-platform-driver.txt new file mode 100644 index 0000000000..74bfbf9b39 --- /dev/null +++ b/packages/linux/linux-efika-2.6.20/0019-MPC5200-Bestcomm-platform-driver.txt @@ -0,0 +1,1439 @@ +From d9e27abf78b3bd714eb9c37c529d0bff7c5403d9 Mon Sep 17 00:00:00 2001 +From: Andrey Volkov <avolkov@varma-el.com> +Date: Fri, 18 Aug 2006 10:01:38 -0600 +Subject: [PATCH] [PATCH 01/02] MPC5200 Bestcomm platform driver + +This is first part of "platformizied" bestcomm/fec drivers. + +Signed-Off-By: Andrey Volkov <avolkov at varma-el.com> +--- + arch/ppc/Kconfig | 5 + + arch/ppc/syslib/Makefile | 1 + + arch/ppc/syslib/bestcomm/Makefile | 2 + + arch/ppc/syslib/bestcomm/bestcomm.c | 408 +++++++++++++++++++++++ + arch/ppc/syslib/bestcomm/bestcomm.h | 473 +++++++++++++++++++++++++++ + arch/ppc/syslib/bestcomm/fec.c | 174 ++++++++++ + arch/ppc/syslib/bestcomm/fec.h | 71 ++++ + arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c | 71 ++++ + arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c | 84 +++++ + arch/ppc/syslib/mpc52xx_devices.c | 22 ++ + arch/ppc/syslib/mpc52xx_sys.c | 4 +- + include/asm-ppc/mpc52xx.h | 2 + + 12 files changed, 1315 insertions(+), 2 deletions(-) + +diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig +index 8eb82ef..d8a561e 100644 +--- a/arch/ppc/Kconfig ++++ b/arch/ppc/Kconfig +@@ -775,6 +775,11 @@ config EMBEDDEDBOOT + config PPC_MPC52xx + bool + ++config PPC_BESTCOMM ++ bool ++ depends on PPC_MPC52xx ++ default y ++ + config 8260 + bool "CPM2 Support" if WILLOW + depends on 6xx +diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile +index dca23f2..ab015df 100644 +--- a/arch/ppc/syslib/Makefile ++++ b/arch/ppc/syslib/Makefile +@@ -106,3 +106,4 @@ obj-$(CONFIG_PCI) += mpc52xx_pci.o + endif + + obj-$(CONFIG_PPC_I8259) += i8259.o ++obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ +diff --git a/arch/ppc/syslib/bestcomm/Makefile b/arch/ppc/syslib/bestcomm/Makefile +new file mode 100644 +index 0000000..02cc99a +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_PPC_BESTCOMM) += bestcomm.o ++obj-$(CONFIG_FEC_MPC52xx) += sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o +diff --git a/arch/ppc/syslib/bestcomm/bestcomm.c b/arch/ppc/syslib/bestcomm/bestcomm.c +new file mode 100644 +index 0000000..ef45e02 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/bestcomm.c +@@ -0,0 +1,408 @@ ++/* ++ * arch/ppc/syslib/bestcomm/bestcomm.c ++ * ++ * Driver for MPC52xx processor BestComm peripheral controller ++ * ++ * Author: Dale Farnsworth <dfarnsworth@mvista.com> ++ * ++ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under ++ * the terms of the GNU General Public License version 2. This program ++ * is licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov <avolkov@varma-el.com>, Varma Electronics Oy ++ */ ++ ++#include <linux/config.h> ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/string.h> ++#include <linux/device.h> ++ ++#include <asm/bug.h> ++#include <asm/io.h> ++#include <asm/mpc52xx.h> ++ ++#include "bestcomm.h" ++ ++#define DRIVER_NAME "mpc52xx-sdma" ++ ++struct sdma_io sdma; ++ ++static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED; ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++void sdma_dump(void) ++{ ++ int i; ++ printk("** SDMA registers: pa = %08x, va = %08x\n", sdma.base_reg_addr, sdma.io); ++ printk("** taskBar = %08x\n", sdma.io->taskBar); ++ printk("** currentPointer = %08x\n", sdma.io->currentPointer); ++ printk("** endPointer = %08x\n", sdma.io->endPointer); ++ printk("** variablePointer = %08x\n", sdma.io->variablePointer); ++ ++ printk("** IntVect1 = %08x\n", sdma.io->IntVect1); ++ printk("** IntVect2 = %08x\n", sdma.io->IntVect2); ++ printk("** PtdCntrl = %08x\n", sdma.io->PtdCntrl); ++ ++ printk("** IntPend = %08x\n", sdma.io->IntPend); ++ printk("** IntMask = %08x\n", sdma.io->IntMask); ++ ++ printk("** TCR dump:"); ++ ++ for (i=0;i<16;i++) { ++ if(i%8 == 0) ++ printk("\n** %02X:",i); ++ printk(" %04X",sdma.io->tcr[i]); ++ } ++ printk("\n** IPR dump:"); ++ for (i=0;i<32;i++) { ++ if(i%16 == 0) ++ printk("\n** %02X:",i); ++ printk(" %02X",sdma.io->ipr[i]); ++ } ++ printk("\n** cReqSelect = %08x\n", sdma.io->cReqSelect); ++ printk("** task_size0 = %08x\n", sdma.io->task_size0); ++ printk("** task_size1 = %08x\n", sdma.io->task_size1); ++ printk("** MDEDebug = %08x\n", sdma.io->MDEDebug); ++ printk("** ADSDebug = %08x\n", sdma.io->ADSDebug); ++ printk("** Value1 = %08x\n", sdma.io->Value1); ++ printk("** Value2 = %08x\n", sdma.io->Value2); ++ printk("** Control = %08x\n", sdma.io->Control); ++ printk("** Status = %08x\n", sdma.io->Status); ++ printk("** PTDDebug = %08x\n", sdma.io->PTDDebug); ++} ++#endif ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++#define SDMA_DUMP_REGS() sdma_dump() ++#else ++#define SDMA_DUMP_REGS() ++#endif ++ ++/* ++ * Use a very simple SRAM allocator. ++ * There is no mechanism for freeing space. ++ * In an attempt to minimize internal fragmentation, the SRAM is ++ * divided into two areas. ++ * ++ * Area 1 is at the beginning of SRAM ++ * and is used for allocations requiring alignments of 16 bytes or less. ++ * Successive allocations return higher addresses. ++ * ++ * Area 2 is at the end of SRAM and is used for the remaining allocations. ++ * Successive allocations return lower addresses. ++ * ++ * I've considered adding routines to support the freeing of SRAM allocations, ++ * but the SRAM is so small (16K) that fragmentation can quickly cause the ++ * SRAM to be unusable. If you can come up with a slick way to free SRAM ++ * memory without the fragmentation problem, please do so. ++ */ ++ ++static u8 *area1_end; ++static u8 *area2_begin; ++ ++void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle) ++{ ++ u8 *a; ++ ++ spin_lock(&sdma_lock); ++ ++ /* alignment must be a power of 2 */ ++ BUG_ON(alignment & (alignment - 1)); ++ ++ if (alignment < 16) { ++ a = (u8 *)(((u32)area1_end + (alignment-1)) & ~(alignment-1)); ++ if (a + size <= area2_begin) ++ area1_end = a + size; ++ else ++ a = 0; /* out of memory */ ++ } else { ++ a = (u8 *)(((u32)area2_begin - size) & ~(alignment - 1)); ++ if (a >= area1_end) ++ area2_begin = a; ++ else ++ a = 0; /* out of memory */ ++ } ++ if(a && dma_handle) ++ *dma_handle = sdma_sram_pa(a); ++ spin_unlock(&sdma_lock); ++ return (void *)a; ++} ++ ++/* this will need to be updated if Freescale changes their task code FDT */ ++static u32 fdt_ops[] = { ++ 0xa0045670, /* FDT[48] */ ++ 0x80045670, /* FDT[49] */ ++ 0x21800000, /* FDT[50] */ ++ 0x21e00000, /* FDT[51] */ ++ 0x21500000, /* FDT[52] */ ++ 0x21400000, /* FDT[53] */ ++ 0x21500000, /* FDT[54] */ ++ 0x20400000, /* FDT[55] */ ++ 0x20500000, /* FDT[56] */ ++ 0x20800000, /* FDT[57] */ ++ 0x20a00000, /* FDT[58] */ ++ 0xc0170000, /* FDT[59] */ ++ 0xc0145670, /* FDT[60] */ ++ 0xc0345670, /* FDT[61] */ ++ 0xa0076540, /* FDT[62] */ ++ 0xa0000760, /* FDT[63] */ ++}; ++ ++static int new_task_number(void) ++{ ++ struct sdma_tdt *tdt; ++ int i; ++ ++ spin_lock(&sdma_lock); ++ ++ tdt = sdma.tdt; ++ for (i=0; i<SDMA_MAX_TASKS; i++, tdt++) ++ if (tdt->start == 0) ++ break; ++ if (i == SDMA_MAX_TASKS) ++ i = -1; ++ ++ spin_unlock(&sdma_lock); ++ ++ return i; ++} ++ ++int sdma_load_task(u32 *task_image) ++{ ++ struct sdma_task_header *head = (struct sdma_task_header *)task_image; ++ struct sdma_tdt *tdt; ++ int tasknum; ++ u32 *desc; ++ u32 *var_src, *var_dst; ++ u32 *inc_src; ++ void *start; ++ ++ BUG_ON(head->magic != SDMA_TASK_MAGIC); ++ ++ tasknum = new_task_number(); ++ if (tasknum < 0) ++ return -ENOMEM; ++ ++ desc = (u32 *)(head + 1); ++ var_src = desc + head->desc_size; ++ inc_src = var_src + head->var_size; ++ ++ tdt = &sdma.tdt[tasknum]; ++ ++ start = sdma_sram_alloc(head->desc_size * sizeof(u32), 4, &tdt->start); ++ if (!start) ++ return -ENOMEM; ++ tdt->stop = tdt->start + (head->desc_size - 1)*sizeof(u32); ++ var_dst = sdma_sram_va(tdt->var); ++ ++ memcpy(start, desc, head->desc_size * sizeof(u32)); ++ memcpy(&var_dst[head->first_var], var_src, head->var_size * sizeof(u32)); ++ memcpy(&var_dst[SDMA_MAX_VAR], inc_src, head->inc_size * sizeof(u32)); ++ ++ return tasknum; ++} ++ ++void sdma_set_initiator(int task, int initiator) ++{ ++ int i; ++ int num_descs; ++ u32 *desc; ++ int next_drd_has_initiator; ++ ++ sdma_set_tcr_initiator(task, initiator); ++ ++ desc = sdma_task_desc(task); ++ next_drd_has_initiator = 1; ++ num_descs = sdma_task_num_descs(task); ++ ++ for (i=0; i<num_descs; i++, desc++) { ++ if (!sdma_desc_is_drd(*desc)) ++ continue; ++ if (next_drd_has_initiator) ++ if (sdma_desc_initiator(*desc) != SDMA_INITIATOR_ALWAYS) ++ sdma_set_desc_initiator(desc, initiator); ++ next_drd_has_initiator = !sdma_drd_is_extended(*desc); ++ } ++} ++ ++struct sdma *sdma_alloc(int queue_size) ++{ ++ struct sdma *s = kmalloc(sizeof(*s), GFP_KERNEL); ++ void **cookie; ++ ++ if (!s) ++ return NULL; ++ ++ memset(s, 0, sizeof(*s)); ++ ++ if (queue_size) { ++ cookie = kmalloc(sizeof(*cookie) * queue_size, GFP_KERNEL); ++ if (!cookie) { ++ kfree(s); ++ return NULL; ++ } ++ s->cookie = cookie; ++ } ++ ++ s->num_bd = queue_size; ++ return s; ++} ++ ++void sdma_free(struct sdma *s) ++{ ++ if (s->cookie) ++ kfree(s->cookie); ++ kfree(s); ++} ++ ++static int __devinit mpc52xx_sdma_probe(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ int task; ++ u32 *context; ++ u32 *fdt; ++ struct sdma_tdt *tdt; ++ struct resource *mem_io, *mem_sram; ++ u32 tdt_pa, var_pa, context_pa, fdt_pa; ++ int ret = -ENODEV; ++ ++ mem_io = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ mem_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!mem_io || !mem_sram) ++ goto out; ++ ++ if (!request_mem_region(mem_io->start, mem_io->end - mem_io->start + 1, DRIVER_NAME)) { ++ printk(KERN_ERR DRIVER_NAME " - resource unavailable\n"); ++ goto out; ++ } ++ sdma.base_reg_addr = mem_io->start; ++ ++ sdma.io = ioremap_nocache(mem_io->start, sizeof(struct mpc52xx_sdma)); ++ ++ if (!sdma.io ) { ++ printk(KERN_ERR DRIVER_NAME " - failed to map sdma regs\n"); ++ ret = -ENOMEM; ++ goto map_io_error; ++ } ++ ++ SDMA_DUMP_REGS(); ++ ++ sdma.sram_size = mem_sram->end - mem_sram->start + 1; ++ if (!request_mem_region(mem_sram->start, sdma.sram_size, DRIVER_NAME)) { ++ printk(KERN_ERR DRIVER_NAME " - resource unavailable\n"); ++ goto req_sram_error; ++ } ++ ++ sdma.base_sram_addr = mem_sram->start; ++ sdma.sram = ioremap_nocache(mem_sram->start, sdma.sram_size); ++ if (!sdma.sram ) { ++ printk(KERN_ERR DRIVER_NAME " - failed to map sdma sram\n"); ++ ret = -ENOMEM; ++ goto map_sram_error; ++ } ++ ++ area1_end = sdma.sram; ++ area2_begin = area1_end + sdma.sram_size; ++ ++ memset(area1_end, 0, sdma.sram_size); ++ ++ /* allocate space for task descriptors, contexts, and var tables */ ++ sdma.tdt = sdma_sram_alloc(sizeof(struct sdma_tdt) * SDMA_MAX_TASKS, 4, &tdt_pa); ++ ++ context = sdma_sram_alloc(SDMA_CONTEXT_SIZE * SDMA_MAX_TASKS, ++ SDMA_CONTEXT_ALIGN, &context_pa); ++ sdma.var = sdma_sram_alloc( (SDMA_VAR_SIZE + SDMA_INC_SIZE) * SDMA_MAX_TASKS, ++ SDMA_VAR_ALIGN, &var_pa); ++ fdt = sdma_sram_alloc(SDMA_FDT_SIZE, SDMA_FDT_ALIGN, &fdt_pa); ++ memcpy(&fdt[48], fdt_ops, sizeof(fdt_ops)); ++ ++ out_be32(&sdma.io->taskBar, tdt_pa); ++ ++ tdt = sdma.tdt; ++ for (task=0; task < SDMA_MAX_TASKS; task++) { ++ out_be16(&sdma.io->tcr[task], 0); ++ out_8(&sdma.io->ipr[task], 0); ++ ++ tdt->context = context_pa; ++ tdt->var = var_pa; ++ tdt->fdt = fdt_pa; ++ var_pa += (SDMA_MAX_VAR + SDMA_MAX_INC)*sizeof(u32); ++ context_pa += SDMA_MAX_CONTEXT*sizeof(u32); ++ tdt++; ++ } ++ ++ out_8(&sdma.io->ipr[SDMA_INITIATOR_ALWAYS], SDMA_IPR_ALWAYS); ++ ++ /* Disable COMM Bus Prefetch, apparently it's not reliable yet */ ++ out_be16(&sdma.io->PtdCntrl, in_be16(&sdma.io->PtdCntrl) | 1); ++ ++ printk(KERN_INFO "MPC52xx BestComm inited\n"); ++ ++ return 0; ++ ++map_sram_error: ++ release_mem_region(mem_sram->start, sdma.sram_size); ++req_sram_error: ++ iounmap(sdma.io); ++map_io_error: ++ release_mem_region(mem_io->start, mem_io->end - mem_io->start + 1); ++out: ++ printk(KERN_ERR "DMA: MPC52xx BestComm init FAILED !!!\n"); ++ return ret; ++} ++ ++ ++static struct device_driver mpc52xx_sdma_driver = { ++ .owner = THIS_MODULE, ++ .name = DRIVER_NAME, ++ .bus = &platform_bus_type, ++ .probe = mpc52xx_sdma_probe, ++/* .remove = mpc52xx_sdma_remove, TODO */ ++#ifdef CONFIG_PM ++/* .suspend = mpc52xx_sdma_suspend, TODO */ ++/* .resume = mpc52xx_sdma_resume, TODO */ ++#endif ++}; ++ ++static int __init ++mpc52xx_sdma_init(void) ++{ ++ printk(KERN_INFO "DMA: MPC52xx BestComm driver\n"); ++ return driver_register(&mpc52xx_sdma_driver); ++} ++ ++#ifdef MODULE ++static void __exit ++mpc52xx_sdma_exit(void) ++{ ++ driver_unregister(&mpc52xx_sdma_driver); ++} ++#endif ++ ++#ifndef MODULE ++ subsys_initcall(mpc52xx_sdma_init); ++#else ++ module_init(mpc52xx_sdma_init); ++ module_exit(mpc52xx_sdma_exit); ++#endif ++ ++ ++MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA"); ++MODULE_LICENSE("GPL"); ++ ++EXPORT_SYMBOL(sdma_sram_alloc); ++EXPORT_SYMBOL(sdma_load_task); ++EXPORT_SYMBOL(sdma_set_initiator); ++EXPORT_SYMBOL(sdma_free); ++EXPORT_SYMBOL(sdma); ++ ++ +diff --git a/arch/ppc/syslib/bestcomm/bestcomm.h b/arch/ppc/syslib/bestcomm/bestcomm.h +new file mode 100644 +index 0000000..14bf397 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/bestcomm.h +@@ -0,0 +1,473 @@ ++/* ++ * arch/ppc/syslib/bestcomm/bestcomm.h ++ * ++ * Driver for MPC52xx processor BestComm peripheral controller ++ * ++ * Author: Dale Farnsworth <dfarnsworth@mvista.com> ++ * ++ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under ++ * the terms of the GNU General Public License version 2. This program ++ * is licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov <avolkov@varma-el.com>, Varma Electronics Oy ++ */ ++ ++#ifndef __BESTCOMM_BESTCOMM_H__ ++#define __BESTCOMM_BESTCOMM_H__ ++ ++/* Buffer Descriptor definitions */ ++struct sdma_bd { ++ u32 status; ++ void *data; ++}; ++ ++struct sdma_bd2 { ++ u32 status; ++ void *data1; ++ void *data2; ++}; ++ ++struct sdma_io { ++ unsigned long base_reg_addr; ++ struct mpc52xx_sdma __iomem *io; ++ unsigned long base_sram_addr; ++ void __iomem *sram; ++ size_t sram_size; ++ ++ struct sdma_tdt __iomem *tdt; ++ u32 __iomem *var; ++}; ++extern struct sdma_io sdma; ++ ++#define sdma_sram_pa(virt) (((unsigned long)(((void __iomem *)(virt))-sdma.sram))+sdma.base_sram_addr) ++#define sdma_sram_va(pa) ((void __iomem *)((((unsigned long)(pa))-sdma.base_sram_addr)+((unsigned long)sdma.sram))) ++ ++#define sdma_io_pa(virt) (((unsigned long)(((void __iomem *)(virt))-((void __iomem *)sdma.io)))+sdma.base_reg_addr) ++#define sdma_io_va(pa) ((void __iomem *)((((unsigned long)(pa))-sdma.base_reg_addr)+((unsigned long)sdma.io))) ++ ++#define SDMA_LEN_BITS 26 ++#define SDMA_LEN_MASK ((1 << SDMA_LEN_BITS) - 1) ++ ++#define SDMA_BD_READY 0x40000000UL ++ ++#define SDMA_FEC_TX_BD_TFD 0x08000000UL /* transmit frame done */ ++#define SDMA_FEC_TX_BD_INT 0x04000000UL /* Interrupt */ ++#define SDMA_FEC_TX_BD_TFD_INIT (SDMA_BD_READY | SDMA_FEC_TX_BD_TFD | \ ++ SDMA_FEC_TX_BD_INT) ++ ++struct sdma { ++ union { ++ struct sdma_bd *bd; ++ struct sdma_bd2 *bd2; ++ }; ++ void **cookie; ++ u16 index; ++ u16 outdex; ++ u16 num_bd; ++ s16 tasknum; ++ u32 flags; ++}; ++ ++#define SDMA_FLAGS_NONE 0x0000 ++#define SDMA_FLAGS_ENABLE_TASK 0x0001 ++#define SDMA_FLAGS_BD2 0x0002 ++ ++/* Task Descriptor Table Entry */ ++struct sdma_tdt { ++ u32 start; ++ u32 stop; ++ u32 var; ++ u32 fdt; ++ u32 exec_status; /* used internally by SmartComm engine */ ++ u32 mvtp; /* used internally by SmartComm engine */ ++ u32 context; ++ u32 litbase; ++}; ++ ++//extern struct sdma_tdt *sdma_tdt; ++ ++#define SDMA_MAX_TASKS 16 ++#define SDMA_MAX_VAR 24 ++#define SDMA_MAX_INC 8 ++#define SDMA_MAX_FDT 64 ++#define SDMA_MAX_CONTEXT 20 ++#define SDMA_CONTEXT_SIZE SDMA_MAX_CONTEXT * sizeof(u32) ++#define SDMA_CONTEXT_ALIGN 0x100 ++#define SDMA_VAR_SIZE SDMA_MAX_VAR * sizeof(u32) ++#define SDMA_VAR_ALIGN 0x80 ++#define SDMA_INC_SIZE SDMA_MAX_INC * sizeof(u32) ++#define SDMA_FDT_SIZE SDMA_MAX_FDT * sizeof(u32) ++#define SDMA_FDT_ALIGN 0x100 ++#define SDMA_BD_ALIGN 0x10 ++ ++#define TASK_ENABLE 0x8000 ++ ++#ifndef DPRINK ++ #ifdef CONFIG_BESTCOMM_DEBUG ++ #define DPRINTK(a,b...) printk(KERN_DEBUG "sdma: %s: " a, __FUNCTION__ , ## b) ++ #else ++ #define DPRINTK(a,b...) ++ #endif ++#endif ++ ++static inline void sdma_enable_task(int task) ++{ ++ DPRINTK("***DMA enable task (%d): tdt = %08x\n",task, sdma.tdt); ++ DPRINTK("***tdt->start = %08x\n",sdma.tdt[task].start); ++ DPRINTK("***tdt->stop = %08x\n",sdma.tdt[task].stop); ++ DPRINTK("***tdt->var = %08x\n",sdma.tdt[task].var); ++ DPRINTK("***tdt->fdt = %08x\n",sdma.tdt[task].fdt); ++ DPRINTK("***tdt->status = %08x\n",sdma.tdt[task].exec_status); ++ DPRINTK("***tdt->mvtp = %08x\n",sdma.tdt[task].mvtp); ++ DPRINTK("***tdt->context = %08x\n",sdma.tdt[task].context); ++ DPRINTK("***tdt->litbase = %08x\n",sdma.tdt[task].litbase); ++ DPRINTK("***--------------\n"); ++ ++ u16 reg = in_be16(&sdma.io->tcr[task]); ++ DPRINTK("***enable task: &sdma.io->tcr=%08x, reg = %04x\n", &sdma.io->tcr, reg); ++ out_be16(&sdma.io->tcr[task], reg | TASK_ENABLE); ++} ++ ++static inline void sdma_disable_task(int task) ++{ ++ u16 reg = in_be16(&sdma.io->tcr[task]); ++ DPRINTK("***disable task(%d): reg = %04x\n", task, reg); ++ out_be16(&sdma.io->tcr[task], reg & ~TASK_ENABLE); ++} ++ ++static inline int sdma_irq(struct sdma *s) ++{ ++ return MPC52xx_SDMA_IRQ_BASE + s->tasknum; ++} ++ ++static inline void sdma_enable(struct sdma *s) ++{ ++ sdma_enable_task(s->tasknum); ++} ++ ++static inline void sdma_disable(struct sdma *s) ++{ ++ sdma_disable_task(s->tasknum); ++} ++ ++static inline int sdma_queue_empty(struct sdma *s) ++{ ++ return s->index == s->outdex; ++} ++ ++static inline void sdma_clear_irq(struct sdma *s) ++{ ++ out_be32(&sdma.io->IntPend, 1 << s->tasknum); ++} ++ ++static inline int sdma_next_index(struct sdma *s) ++{ ++ return ((s->index + 1) == s->num_bd) ? 0 : s->index + 1; ++} ++ ++static inline int sdma_next_outdex(struct sdma *s) ++{ ++ return ((s->outdex + 1) == s->num_bd) ? 0 : s->outdex + 1; ++} ++ ++static inline int sdma_queue_full(struct sdma *s) ++{ ++ return s->outdex == sdma_next_index(s); ++} ++ ++static inline int sdma_buffer_done(struct sdma *s) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ if (sdma_queue_empty(s)) ++ return 0; ++ return (s->bd[s->outdex].status & SDMA_BD_READY) == 0; ++} ++ ++static inline int sdma_buffer2_done(struct sdma *s) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(!(s->flags & SDMA_FLAGS_BD2)); ++#endif ++ if (sdma_queue_empty(s)) ++ return 0; ++ ++ return (s->bd2[s->outdex].status & SDMA_BD_READY) == 0; ++} ++ ++static inline u32 *sdma_task_desc(int task) ++{ ++ return sdma_sram_va(sdma.tdt[task].start); ++} ++ ++static inline u32 sdma_task_num_descs(int task) ++{ ++ return (sdma.tdt[task].stop - sdma.tdt[task].start)/sizeof(u32) + 1; ++} ++ ++static inline u32 *sdma_task_var(int task) ++{ ++ return sdma_sram_va(sdma.tdt[task].var); ++} ++ ++static inline u32 *sdma_task_inc(int task) ++{ ++ return &sdma_task_var(task)[SDMA_MAX_VAR]; ++} ++ ++static inline void sdma_set_tcr_initiator(int task, int initiator) { ++ u16 *tcr = &sdma.io->tcr[task]; ++ out_be16(tcr, (in_be16(tcr) & ~0x1f00) | (initiator << 8)); ++} ++ ++#define SDMA_DRD_INITIATOR_SHIFT 21 ++ ++static inline int sdma_desc_initiator(u32 desc) ++{ ++ return (desc >> SDMA_DRD_INITIATOR_SHIFT) & 0x1f; ++} ++ ++static inline void sdma_set_desc_initiator(u32 *desc, int initiator) ++{ ++ *desc = (*desc & ~(0x1f << SDMA_DRD_INITIATOR_SHIFT)) | ++ ((initiator << SDMA_DRD_INITIATOR_SHIFT) & 0x1f); ++} ++ ++static inline void sdma_submit_buffer(struct sdma *s, void *cookie, void *data, ++ int length) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ s->cookie[s->index] = cookie; ++ s->bd[s->index].data = data; ++ s->bd[s->index].status = SDMA_BD_READY | length; ++ s->index = sdma_next_index(s); ++ if (s->flags & SDMA_FLAGS_ENABLE_TASK) ++ sdma_enable_task(s->tasknum); ++} ++ ++/* ++ * Special submit_buffer function to submit last buffer of a frame to ++ * the FEC tx task. tfd means "transmit frame done". ++ */ ++static inline void sdma_fec_tfd_submit_buffer(struct sdma *s, void *cookie, ++ void *data, int length) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ s->cookie[s->index] = cookie; ++ s->bd[s->index].data = data; ++ s->bd[s->index].status = SDMA_FEC_TX_BD_TFD_INIT | length; ++ s->index = sdma_next_index(s); ++ sdma_enable_task(s->tasknum); ++} ++ ++static inline void *sdma_retrieve_buffer(struct sdma *s, int *length) ++{ ++ void *cookie = s->cookie[s->outdex]; ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ if (length) ++ *length = s->bd[s->outdex].status & SDMA_LEN_MASK; ++ s->outdex = sdma_next_outdex(s); ++ return cookie; ++} ++ ++static inline void sdma_submit_buffer2(struct sdma *s, void *cookie, ++ void *data1, void *data2, int length) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(!(s->flags & SDMA_FLAGS_BD2)); ++#endif ++ s->cookie[s->index] = cookie; ++ s->bd2[s->index].data1 = data1; ++ s->bd2[s->index].data2 = data2; ++ s->bd2[s->index].status = SDMA_BD_READY | length; ++ s->index = sdma_next_index(s); ++ if (s->flags & SDMA_FLAGS_ENABLE_TASK) ++ sdma_enable_task(s->tasknum); ++} ++ ++static inline void *sdma_retrieve_buffer2(struct sdma *s, int *length) ++{ ++ void *cookie = s->cookie[s->outdex]; ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(!(s->flags & SDMA_FLAGS_BD2)); ++#endif ++ if (length) ++ *length = s->bd2[s->outdex].status & SDMA_LEN_MASK; ++ s->outdex = sdma_next_outdex(s); ++ return cookie; ++} ++ ++#define SDMA_TASK_MAGIC 0x4243544B /* 'BCTK' */ ++ ++/* the size fields are given in number of 32-bit words */ ++struct sdma_task_header { ++ u32 magic; ++ u8 desc_size; ++ u8 var_size; ++ u8 inc_size; ++ u8 first_var; ++ u8 reserved[8]; ++}; ++ ++#define SDMA_DESC_NOP 0x000001f8 ++#define SDMA_LCD_MASK 0x80000000 ++#define SDMA_DRD_EXTENDED 0x40000000 ++ ++#define sdma_drd_is_extended(desc) ((desc) & SDMA_DRD_EXTENDED) ++ ++static inline int sdma_desc_is_drd(u32 desc) { ++ return !(desc & SDMA_LCD_MASK) && desc != SDMA_DESC_NOP; ++}; ++ ++#define SDMA_PRAGMA_BIT_RSV 7 /* reserved pragma bit */ ++#define SDMA_PRAGMA_BIT_PRECISE_INC 6 /* increment 0=when possible, */ ++ /* 1=iter end */ ++#define SDMA_PRAGMA_BIT_RST_ERROR_NO 5 /* don't reset errors on */ ++ /* task enable */ ++#define SDMA_PRAGMA_BIT_PACK 4 /* pack data enable */ ++#define SDMA_PRAGMA_BIT_INTEGER 3 /* data alignment */ ++ /* 0=frac(msb), 1=int(lsb) */ ++#define SDMA_PRAGMA_BIT_SPECREAD 2 /* XLB speculative read */ ++#define SDMA_PRAGMA_BIT_CW 1 /* write line buffer enable */ ++#define SDMA_PRAGMA_BIT_RL 0 /* read line buffer enable */ ++ ++#define SDMA_STD_PRAGMA ((0 << SDMA_PRAGMA_BIT_RSV) | \ ++ (0 << SDMA_PRAGMA_BIT_PRECISE_INC) | \ ++ (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO) | \ ++ (0 << SDMA_PRAGMA_BIT_PACK) | \ ++ (0 << SDMA_PRAGMA_BIT_INTEGER) | \ ++ (1 << SDMA_PRAGMA_BIT_SPECREAD) | \ ++ (1 << SDMA_PRAGMA_BIT_CW) | \ ++ (1 << SDMA_PRAGMA_BIT_RL)) ++ ++#define SDMA_PCI_PRAGMA ((0 << SDMA_PRAGMA_BIT_RSV) | \ ++ (0 << SDMA_PRAGMA_BIT_PRECISE_INC) | \ ++ (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO) | \ ++ (0 << SDMA_PRAGMA_BIT_PACK) | \ ++ (1 << SDMA_PRAGMA_BIT_INTEGER) | \ ++ (1 << SDMA_PRAGMA_BIT_SPECREAD) | \ ++ (1 << SDMA_PRAGMA_BIT_CW) | \ ++ (1 << SDMA_PRAGMA_BIT_RL)) ++ ++#define SDMA_ATA_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_CRC16_DP_0_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_CRC16_DP_1_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_FEC_RX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_FEC_TX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_0_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_1_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_2_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_3_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_BD_0_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_BD_1_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_RX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_TX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_LPC_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_PCI_RX_PRAGMA SDMA_PCI_PRAGMA ++#define SDMA_PCI_TX_PRAGMA SDMA_PCI_PRAGMA ++ ++static inline void sdma_set_task_pragma(int task, int pragma) ++{ ++ u32 *fdt = &sdma.tdt[task].fdt; ++ *fdt = (*fdt & ~0xff) | pragma; ++} ++ ++static inline void sdma_set_task_auto_start(int task, int next_task) ++{ ++ u16 *tcr = &sdma.io->tcr[task]; ++ out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task); ++} ++ ++#define SDMA_INITIATOR_ALWAYS 0 ++#define SDMA_INITIATOR_SCTMR_0 1 ++#define SDMA_INITIATOR_SCTMR_1 2 ++#define SDMA_INITIATOR_FEC_RX 3 ++#define SDMA_INITIATOR_FEC_TX 4 ++#define SDMA_INITIATOR_ATA_RX 5 ++#define SDMA_INITIATOR_ATA_TX 6 ++#define SDMA_INITIATOR_SCPCI_RX 7 ++#define SDMA_INITIATOR_SCPCI_TX 8 ++#define SDMA_INITIATOR_PSC3_RX 9 ++#define SDMA_INITIATOR_PSC3_TX 10 ++#define SDMA_INITIATOR_PSC2_RX 11 ++#define SDMA_INITIATOR_PSC2_TX 12 ++#define SDMA_INITIATOR_PSC1_RX 13 ++#define SDMA_INITIATOR_PSC1_TX 14 ++#define SDMA_INITIATOR_SCTMR_2 15 ++#define SDMA_INITIATOR_SCLPC 16 ++#define SDMA_INITIATOR_PSC5_RX 17 ++#define SDMA_INITIATOR_PSC5_TX 18 ++#define SDMA_INITIATOR_PSC4_RX 19 ++#define SDMA_INITIATOR_PSC4_TX 20 ++#define SDMA_INITIATOR_I2C2_RX 21 ++#define SDMA_INITIATOR_I2C2_TX 22 ++#define SDMA_INITIATOR_I2C1_RX 23 ++#define SDMA_INITIATOR_I2C1_TX 24 ++#define SDMA_INITIATOR_PSC6_RX 25 ++#define SDMA_INITIATOR_PSC6_TX 26 ++#define SDMA_INITIATOR_IRDA_RX 25 ++#define SDMA_INITIATOR_IRDA_TX 26 ++#define SDMA_INITIATOR_SCTMR_3 27 ++#define SDMA_INITIATOR_SCTMR_4 28 ++#define SDMA_INITIATOR_SCTMR_5 29 ++#define SDMA_INITIATOR_SCTMR_6 30 ++#define SDMA_INITIATOR_SCTMR_7 31 ++ ++#define SDMA_IPR_ALWAYS 7 ++#define SDMA_IPR_SCTMR_0 2 ++#define SDMA_IPR_SCTMR_1 2 ++#define SDMA_IPR_FEC_RX 6 ++#define SDMA_IPR_FEC_TX 5 ++#define SDMA_IPR_ATA_RX 4 ++#define SDMA_IPR_ATA_TX 3 ++#define SDMA_IPR_SCPCI_RX 2 ++#define SDMA_IPR_SCPCI_TX 2 ++#define SDMA_IPR_PSC3_RX 2 ++#define SDMA_IPR_PSC3_TX 2 ++#define SDMA_IPR_PSC2_RX 2 ++#define SDMA_IPR_PSC2_TX 2 ++#define SDMA_IPR_PSC1_RX 2 ++#define SDMA_IPR_PSC1_TX 2 ++#define SDMA_IPR_SCTMR_2 2 ++#define SDMA_IPR_SCLPC 2 ++#define SDMA_IPR_PSC5_RX 2 ++#define SDMA_IPR_PSC5_TX 2 ++#define SDMA_IPR_PSC4_RX 2 ++#define SDMA_IPR_PSC4_TX 2 ++#define SDMA_IPR_I2C2_RX 2 ++#define SDMA_IPR_I2C2_TX 2 ++#define SDMA_IPR_I2C1_RX 2 ++#define SDMA_IPR_I2C1_TX 2 ++#define SDMA_IPR_PSC6_RX 2 ++#define SDMA_IPR_PSC6_TX 2 ++#define SDMA_IPR_IRDA_RX 2 ++#define SDMA_IPR_IRDA_TX 2 ++#define SDMA_IPR_SCTMR_3 2 ++#define SDMA_IPR_SCTMR_4 2 ++#define SDMA_IPR_SCTMR_5 2 ++#define SDMA_IPR_SCTMR_6 2 ++#define SDMA_IPR_SCTMR_7 2 ++ ++extern struct sdma *sdma_alloc(int request_queue_size); ++extern void sdma_free(struct sdma *sdma_struct); ++extern int sdma_load_task(u32 *task_image); ++extern void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle); ++extern void sdma_init_bd(struct sdma *s); ++extern void sdma_init_bd2(struct sdma *s); ++ ++#define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f))) ++ ++#endif /* __BESTCOMM_BESTCOMM_H__ */ +diff --git a/arch/ppc/syslib/bestcomm/fec.c b/arch/ppc/syslib/bestcomm/fec.c +new file mode 100644 +index 0000000..8756856 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/fec.c +@@ -0,0 +1,174 @@ ++/* ++ * arch/ppc/syslib/bestcomm/fec.c ++ * ++ * Driver for MPC52xx processor BestComm FEC controller ++ * ++ * Author: Dale Farnsworth <dfarnsworth@mvista.com> ++ * ++ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under ++ * the terms of the GNU General Public License version 2. This program ++ * is licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov <avolkov@varma-el.com>, Varma Electronics Oy ++ */ ++ ++#include <linux/config.h> ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/types.h> ++#include <asm/errno.h> ++#include <asm/io.h> ++ ++#include <asm/mpc52xx.h> ++ ++#include "bestcomm.h" ++#include "fec.h" ++ ++/* ++ * Initialize FEC receive task. ++ * Returns task number of FEC receive task. ++ * Returns -1 on failure ++ */ ++int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize) ++{ ++ struct sdma_fec_rx_var *var; ++ struct sdma_fec_rx_inc *inc; ++ ++ static int tasknum = -1; ++ static struct sdma_bd *bd = 0; ++ static u32 bd_pa; ++ ++ if (tasknum < 0) { ++ tasknum = sdma_load_task(sdma_fec_rx_task); ++ if (tasknum < 0) ++ return tasknum; ++ } ++ ++ if (!bd) ++ bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd, ++ SDMA_BD_ALIGN, &bd_pa); ++ if (!bd) ++ return -ENOMEM; ++ ++ sdma_disable_task(tasknum); ++ ++ s->tasknum = tasknum; ++ s->bd = bd; ++ s->flags = SDMA_FLAGS_NONE; ++ s->index = 0; ++ s->outdex = 0; ++ memset(bd, 0, sizeof(*bd) * s->num_bd); ++ ++ var = (struct sdma_fec_rx_var *)sdma_task_var(tasknum); ++ var->enable = sdma_io_pa(&sdma.io->tcr[tasknum]); ++ var->fifo = fifo; ++ var->bd_base = bd_pa; ++ var->bd_last = bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd); ++ var->bd_start = bd_pa; ++ var->buffer_size = maxbufsize; ++ ++ /* These are constants, they should have been in the image file */ ++ inc = (struct sdma_fec_rx_inc *)sdma_task_inc(tasknum); ++ inc->incr_bytes = -(s16)sizeof(u32); ++ inc->incr_dst = sizeof(u32); ++ inc->incr_dst_ma = sizeof(u8); ++ ++ sdma_set_task_pragma(tasknum, SDMA_FEC_RX_BD_PRAGMA); ++ sdma_set_task_auto_start(tasknum, tasknum); ++ ++ /* clear pending interrupt bits */ ++ out_be32(&sdma.io->IntPend, 1<<tasknum); ++ ++ out_8(&sdma.io->ipr[SDMA_INITIATOR_FEC_RX], SDMA_IPR_FEC_RX); ++ ++ return tasknum; ++} ++ ++/* ++ * Return 2nd to last DRD ++ * This is an ugly hack, but at least it's only done once at initialization ++ */ ++static u32 *self_modified_drd(int tasknum) ++{ ++ u32 *desc; ++ int num_descs; ++ int drd_count; ++ int i; ++ ++ num_descs = sdma_task_num_descs(tasknum); ++ desc = sdma_task_desc(tasknum) + num_descs - 1; ++ drd_count = 0; ++ for (i=0; i<num_descs; i++, desc--) ++ if (sdma_desc_is_drd(*desc) && ++drd_count == 3) ++ break; ++ return desc; ++} ++ ++/* ++ * Initialize FEC transmit task. ++ * Returns task number of FEC transmit task. ++ * Returns -1 on failure ++ */ ++int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo) ++{ ++ struct sdma_fec_tx_var *var; ++ struct sdma_fec_tx_inc *inc; ++ ++ static int tasknum = -1; ++ static struct sdma_bd *bd = 0; ++ static u32 bd_pa; ++ ++ if (tasknum < 0) { ++ tasknum = sdma_load_task(sdma_fec_tx_task); ++ if (tasknum < 0) ++ return tasknum; ++ } ++ ++ if (!bd) ++ bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd, ++ SDMA_BD_ALIGN, &bd_pa); ++ if (!bd) ++ return -ENOMEM; ++ ++ sdma_disable_task(tasknum); ++ ++ s->tasknum = tasknum; ++ s->bd = bd; ++ s->flags = SDMA_FLAGS_ENABLE_TASK; ++ s->index = 0; ++ s->outdex = 0; ++ memset(bd, 0, sizeof(*bd) * s->num_bd); ++ ++ var = (struct sdma_fec_tx_var *)sdma_task_var(tasknum); ++ var->DRD = sdma_sram_pa(self_modified_drd(tasknum)); ++ var->fifo = fifo; ++ var->enable = sdma_io_pa(&sdma.io->tcr[tasknum]); ++ var->bd_base = bd_pa; ++ var->bd_last = bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd); ++ var->bd_start = bd_pa; ++ ++ /* These are constants, they should have been in the image file */ ++ inc = (struct sdma_fec_tx_inc *)sdma_task_inc(tasknum); ++ inc->incr_bytes = -(s16)sizeof(u32); ++ inc->incr_src = sizeof(u32); ++ inc->incr_src_ma = sizeof(u8); ++ ++ sdma_set_task_pragma(tasknum, SDMA_FEC_TX_BD_PRAGMA); ++ sdma_set_task_auto_start(tasknum, tasknum); ++ ++ /* clear pending interrupt bits */ ++ out_be32(&sdma.io->IntPend, 1<<tasknum); ++ ++ out_8(&sdma.io->ipr[SDMA_INITIATOR_FEC_TX], SDMA_IPR_FEC_TX); ++ ++ return tasknum; ++} ++ ++EXPORT_SYMBOL(sdma_fec_rx_init); ++EXPORT_SYMBOL(sdma_fec_tx_init); +diff --git a/arch/ppc/syslib/bestcomm/fec.h b/arch/ppc/syslib/bestcomm/fec.h +new file mode 100644 +index 0000000..e3abc0f +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/fec.h +@@ -0,0 +1,71 @@ ++/* ++ * arch/ppc/syslib/bestcomm/fec.h ++ * ++ * Driver for MPC52xx processor BestComm FEC controller ++ * ++ * Author: Dale Farnsworth <dfarnsworth@mvista.com> ++ * ++ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under ++ * the terms of the GNU General Public License version 2. This program ++ * is licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov <avolkov@varma-el.com>, Varma Electronics Oy ++ */ ++ ++#ifndef __BESTCOMM_FEC_H__ ++#define __BESTCOMM_FEC_H__ ++ ++ ++/* rx task vars that need to be set before enabling the task */ ++struct sdma_fec_rx_var { ++ u32 enable; /* (u16*) address of task's control register */ ++ u32 fifo; /* (u32*) address of fec's fifo */ ++ u32 bd_base; /* (struct sdma_bd*) beginning of ring buffer */ ++ u32 bd_last; /* (struct sdma_bd*) end of ring buffer */ ++ u32 bd_start; /* (struct sdma_bd*) current bd */ ++ u32 buffer_size; /* size of receive buffer */ ++}; ++ ++/* rx task incs that need to be set before enabling the task */ ++struct sdma_fec_rx_inc { ++ u16 pad0; ++ s16 incr_bytes; ++ u16 pad1; ++ s16 incr_dst; ++ u16 pad2; ++ s16 incr_dst_ma; ++}; ++ ++/* tx task vars that need to be set before enabling the task */ ++struct sdma_fec_tx_var { ++ u32 DRD; /* (u32*) address of self-modified DRD */ ++ u32 fifo; /* (u32*) address of fec's fifo */ ++ u32 enable; /* (u16*) address of task's control register */ ++ u32 bd_base; /* (struct sdma_bd*) beginning of ring buffer */ ++ u32 bd_last; /* (struct sdma_bd*) end of ring buffer */ ++ u32 bd_start; /* (struct sdma_bd*) current bd */ ++ u32 buffer_size; /* set by uCode for each packet */ ++}; ++ ++/* tx task incs that need to be set before enabling the task */ ++struct sdma_fec_tx_inc { ++ u16 pad0; ++ s16 incr_bytes; ++ u16 pad1; ++ s16 incr_src; ++ u16 pad2; ++ s16 incr_src_ma; ++}; ++ ++extern int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize); ++extern int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo); ++ ++extern u32 sdma_fec_rx_task[]; ++extern u32 sdma_fec_tx_task[]; ++ ++ ++#endif /* __BESTCOMM_FEC_H__ */ +diff --git a/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c +new file mode 100644 +index 0000000..511b036 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c +@@ -0,0 +1,71 @@ ++/* ++ * sdma_fec_rx_task.c ++ * ++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex ++ * on Tue Mar 22 11:19:38 2005 GMT ++ */ ++ ++#include <linux/types.h> ++ ++/* ++ * The header consists of the following fields: ++ * uint32_t magic; ++ * uint8_t desc_size; ++ * uint8_t var_size; ++ * uint8_t inc_size; ++ * uint8_t first_var; ++ * uint8_t reserved[8]; ++ * ++ * The size fields contain the number of 32-bit words. ++*/ ++ ++uint32_t sdma_fec_rx_task[] = { ++ /* header */ ++ 0x4243544b, ++ 0x18060709, ++ 0x00000000, ++ 0x00000000, ++ ++ /* Task descriptors */ ++ 0x808220e3, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */ ++ 0x10601010, /* DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0 */ ++ 0xb8800264, /* LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc4, idx3 += inc4 */ ++ 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ ++ 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ ++ 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0xb8c58029, /* LCD: idx3 = *(idx1 + var00000015); idx3 once var0; idx3 += inc5 */ ++ 0x60000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */ ++ 0x088cf8cc, /* DRD2B1: idx2 = EU3(); EU3(idx3,var12) */ ++ 0x991982f2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var11; idx2 += inc6, idx3 += inc2 */ ++ 0x006acf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=1 RS=1 */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x034cfc4e, /* DRD2B1: var13 = EU3(); EU3(*idx1,var14) */ ++ 0x00008868, /* DRD1A: idx2 = var13; FN=0 init=0 WS=0 RS=0 */ ++ 0x99198341, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; idx2 += inc0, idx3 += inc1 */ ++ 0x007ecf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=3 RS=3 */ ++ 0x99198272, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc6, idx3 += inc2 */ ++ 0x046acf80, /* DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=1 RS=1 */ ++ 0x9819002d, /* LCD: idx2 = idx0; idx2 once var0; idx2 += inc5 */ ++ 0x0060c790, /* DRD1A: *idx1 = *idx2; FN=0 init=3 WS=0 RS=0 */ ++ 0x000001f8, /* NOP */ ++ ++ /* VAR[9]-VAR[14] */ ++ 0x40000000, ++ 0x7fff7fff, ++ 0x00000000, ++ 0x00000003, ++ 0x40000008, ++ 0x43ffffff, ++ ++ /* INC[0]-INC[6] */ ++ 0x40000000, ++ 0xe0000000, ++ 0xe0000000, ++ 0xa0000008, ++ 0x20000000, ++ 0x00000000, ++ 0x4000ffff, ++}; +diff --git a/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c +new file mode 100644 +index 0000000..d8d7fd3 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c +@@ -0,0 +1,84 @@ ++/* ++ * sdma_fec_tx_task.c ++ * ++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex ++ * on Tue Mar 22 11:19:29 2005 GMT ++ */ ++ ++#include <linux/types.h> ++ ++/* ++ * The header consists of the following fields: ++ * uint32_t magic; ++ * uint8_t desc_size; ++ * uint8_t var_size; ++ * uint8_t inc_size; ++ * uint8_t first_var; ++ * uint8_t reserved[8]; ++ * ++ * The size fields contain the number of 32-bit words. ++*/ ++ ++uint32_t sdma_fec_tx_task[] = { ++ /* header */ ++ 0x4243544b, ++ 0x2407070d, ++ 0x00000000, ++ 0x00000000, ++ ++ /* Task descriptors */ ++ 0x8018001b, /* LCD: idx0 = var0; idx0 <= var0; idx0 += inc3 */ ++ 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ ++ 0x01ccfc0d, /* DRD2B1: var7 = EU3(); EU3(*idx0,var13) */ ++ 0x8082a123, /* LCD: idx0 = var1, idx1 = var5; idx1 <= var4; idx0 += inc4, idx1 += inc3 */ ++ 0x10801418, /* DRD1A: var5 = var3; FN=0 MORE init=4 WS=0 RS=0 */ ++ 0xf88103a4, /* LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var14; idx2 += inc4, idx3 += inc4 */ ++ 0x801a6024, /* LCD: idx4 = var0; ; idx4 += inc4 */ ++ 0x10001708, /* DRD1A: var5 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ ++ 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ ++ 0x0cccfccf, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var15) */ ++ 0x991a002c, /* LCD: idx2 = idx2, idx3 = idx4; idx2 once var0; idx2 += inc5, idx3 += inc4 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x024cfc4d, /* DRD2B1: var9 = EU3(); EU3(*idx1,var13) */ ++ 0x60000003, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */ ++ 0x0cccf247, /* DRD2B1: *idx3 = EU3(); EU3(var9,var7) */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0xb8c80029, /* LCD: idx3 = *(idx1 + var0000001a); idx3 once var0; idx3 += inc5 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x088cf8d1, /* DRD2B1: idx2 = EU3(); EU3(idx3,var17) */ ++ 0x00002f10, /* DRD1A: var11 = idx2; FN=0 init=0 WS=0 RS=0 */ ++ 0x99198432, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var16; idx2 += inc6, idx3 += inc2 */ ++ 0x008ac398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=1 RS=1 */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x048cfc53, /* DRD2B1: var18 = EU3(); EU3(*idx1,var19) */ ++ 0x60000008, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=8 EXT init=0 WS=0 RS=0 */ ++ 0x088cf48b, /* DRD2B1: idx2 = EU3(); EU3(var18,var11) */ ++ 0x99198481, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var18; idx2 += inc0, idx3 += inc1 */ ++ 0x009ec398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=3 RS=3 */ ++ 0x991983b2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var14; idx2 += inc6, idx3 += inc2 */ ++ 0x088ac398, /* DRD1A: *idx0 = *idx3; FN=0 TFD init=4 WS=1 RS=1 */ ++ 0x9919002d, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc5 */ ++ 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ ++ 0x0c4cf88e, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var14) */ ++ 0x000001f8, /* NOP */ ++ ++ /* VAR[13]-VAR[19] */ ++ 0x0c000000, ++ 0x40000000, ++ 0x7fff7fff, ++ 0x00000000, ++ 0x00000003, ++ 0x40000004, ++ 0x43ffffff, ++ ++ /* INC[0]-INC[6] */ ++ 0x40000000, ++ 0xe0000000, ++ 0xe0000000, ++ 0xa0000008, ++ 0x20000000, ++ 0x00000000, ++ 0x4000ffff, ++}; +diff --git a/arch/ppc/syslib/mpc52xx_devices.c b/arch/ppc/syslib/mpc52xx_devices.c +index 7487539..abe6161 100644 +--- a/arch/ppc/syslib/mpc52xx_devices.c ++++ b/arch/ppc/syslib/mpc52xx_devices.c +@@ -33,6 +33,28 @@ static struct fsl_i2c_platform_data mpc52xx_fsl_i2c_pdata = { + possibly using IORESOURCE_DMA. But that's when BestComm is ready ... */ + + struct platform_device ppc_sys_platform_devices[] = { ++ [MPC52xx_SDMA] = { ++ .name = "mpc52xx-sdma", ++ .id = -1, ++ .num_resources = 3, ++ .resource = (struct resource[]) { ++ { ++ .start = 0x1200, ++ .end = 0x12ff, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = 0x8000, ++ .end = 0xbfff, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = MPC52xx_SDMA_IRQ, ++ .end = MPC52xx_SDMA_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++ }, ++ }, + [MPC52xx_MSCAN1] = { + .name = "mpc52xx-mscan", + .id = 0, +diff --git a/arch/ppc/syslib/mpc52xx_sys.c b/arch/ppc/syslib/mpc52xx_sys.c +index b4e6f97..a74b19c 100644 +--- a/arch/ppc/syslib/mpc52xx_sys.c ++++ b/arch/ppc/syslib/mpc52xx_sys.c +@@ -19,10 +19,10 @@ struct ppc_sys_spec ppc_sys_specs[] = { + .ppc_sys_name = "5200", + .mask = 0xffff0000, + .value = 0x80110000, +- .num_devices = 15, ++ .num_devices = MPC52xx_NUM_DEVICES, + .device_list = (enum ppc_sys_devices[]) + { +- MPC52xx_MSCAN1, MPC52xx_MSCAN2, MPC52xx_SPI, ++ MPC52xx_SDMA, MPC52xx_MSCAN1, MPC52xx_MSCAN2, MPC52xx_SPI, + MPC52xx_USB, MPC52xx_BDLC, MPC52xx_PSC1, MPC52xx_PSC2, + MPC52xx_PSC3, MPC52xx_PSC4, MPC52xx_PSC5, MPC52xx_PSC6, + MPC52xx_FEC, MPC52xx_ATA, MPC52xx_I2C1, MPC52xx_I2C2, +diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h +index d9d21aa..4856b74 100644 +--- a/include/asm-ppc/mpc52xx.h ++++ b/include/asm-ppc/mpc52xx.h +@@ -34,6 +34,8 @@ struct pt_regs; + /* ======================================================================== */ + + enum ppc_sys_devices { ++ MPC52xx_SDMA, /* Must be first device to probe, ++ else FEC/ATA will failed */ + MPC52xx_MSCAN1, + MPC52xx_MSCAN2, + MPC52xx_SPI, +-- +1.4.4.2 + |