diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig --- a/arch/ppc/Kconfig 2004-11-19 12:41:34 +01:00 +++ b/arch/ppc/Kconfig 2004-11-20 23:21:00 +01:00 @@ -623,6 +623,10 @@ config PPC_MPC52xx bool +config PPC_BESTCOMM + bool + depends on PPC_MPC52xx + config 8260 bool "CPM2 Support" if WILLOW depends on 6xx diff -Nru a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile --- a/arch/ppc/syslib/Makefile 2004-11-19 12:41:34 +01:00 +++ b/arch/ppc/syslib/Makefile 2004-11-20 23:21:00 +01:00 @@ -88,3 +88,4 @@ ifeq ($(CONFIG_PPC_MPC52xx),y) obj-$(CONFIG_PCI) += mpc52xx_pci.o endif +obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ diff -Nru a/arch/ppc/syslib/bestcomm/Makefile b/arch/ppc/syslib/bestcomm/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/syslib/bestcomm/Makefile 2004-11-20 23:21:00 +01:00 @@ -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 -Nru a/arch/ppc/syslib/bestcomm/bestcomm.c b/arch/ppc/syslib/bestcomm/bestcomm.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/syslib/bestcomm/bestcomm.c 2004-11-20 23:21:01 +01:00 @@ -0,0 +1,248 @@ +/* + * arch/ppc/syslib/bestcomm/bestcomm.c + * + * Driver for MPC52xx processor BestComm peripheral controller + * + * Author: Dale Farnsworth + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "bestcomm.h" + +static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED; + +/* + * 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. + */ + +struct sdma_tdt *sdma_tdt; + +static u8 *area1_end; +static u8 *area2_begin; + +static void sdma_init(void); + +void *sdma_sram_alloc(int size, int alignment) +{ + u8 *a; + + spin_lock(&sdma_lock); + if (!area1_end) + sdma_init(); + + /* 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 */ + } + 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 void sdma_init(void) +{ + struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA; + int task; + u32 *context; + u32 *var; + u32 *fdt; + struct sdma_tdt *tdt; + + area1_end = (u8 *)MPC52xx_SRAM; + area2_begin = (u8 *)(MPC52xx_SRAM + MPC52xx_SRAM_SIZE); + + memset((void *)MPC52xx_SRAM, 0, MPC52xx_SRAM_SIZE); + + /* allocate space for task descriptors, contexts, and var tables */ + sdma_tdt = sdma_sram_alloc(sizeof(*sdma_tdt) * SDMA_MAX_TASKS, 4); + context = sdma_sram_alloc(SDMA_CONTEXT_SIZE * SDMA_MAX_TASKS, + SDMA_CONTEXT_ALIGN); + var = sdma_sram_alloc(SDMA_VAR_SIZE * SDMA_MAX_TASKS, SDMA_VAR_ALIGN); + fdt = sdma_sram_alloc(SDMA_FDT_SIZE, SDMA_FDT_ALIGN); + memcpy(&fdt[48], fdt_ops, sizeof(fdt_ops)); + + out_be32(&sdma->taskBar, (u32)sdma_tdt); + + tdt = sdma_tdt; + for (task=0; task < SDMA_MAX_TASKS; task++) { + out_be16(&sdma->tcr[task], 0); + out_8(&sdma->ipr[task], 0); + + tdt->context = context; + tdt->var = var; + tdt->fdt = fdt; + var += SDMA_MAX_VAR + SDMA_MAX_INC; + context += SDMA_MAX_CONTEXT; + tdt++; + } + + out_8(&sdma->ipr[SDMA_INITIATOR_ALWAYS], SDMA_IPR_ALWAYS); + + /* Disable COMM Bus Prefetch, apparently it's not reliable yet */ + out_be16(&sdma->PtdCntrl, in_be16(&sdma->PtdCntrl) | 1); +} + +static int new_task_number(void) +{ + struct sdma_tdt *tdt; + int i; + + spin_lock(&sdma_lock); + + if (!sdma_tdt) + sdma_init(); + tdt = sdma_tdt; + + for (i=0; istart == 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; + u32 *inc; + + BUG_ON(head->magic != SDMA_TASK_MAGIC); + + tasknum = new_task_number(); + if (tasknum < 0) + return -ENOMEM; + + desc = (u32 *)(head + 1); + var = desc + head->desc_size; + inc = var + head->var_size; + + tdt = &sdma_tdt[tasknum]; + tdt->start = sdma_sram_alloc(head->desc_size * 4, 4); + if (!tdt->start) + return -ENOMEM; + tdt->stop = tdt->start + head->desc_size - 1; + + memcpy(tdt->start, desc, head->desc_size * sizeof(u32)); + memcpy(tdt->var + head->first_var, var, head->var_size * sizeof(u32)); + memcpy(tdt->var + SDMA_MAX_VAR, inc, 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; icookie = cookie; + } + + s->num_bd = queue_size; + return s; +} + +void sdma_free(struct sdma *s) +{ + if (s->cookie) + kfree(s->cookie); + kfree(s); +} diff -Nru a/arch/ppc/syslib/bestcomm/bestcomm.h b/arch/ppc/syslib/bestcomm/bestcomm.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/syslib/bestcomm/bestcomm.h 2004-11-20 23:21:02 +01:00 @@ -0,0 +1,441 @@ +/* + * arch/ppc/syslib/bestcomm/bestcomm.h + * + * Driver for MPC52xx processor BestComm peripheral controller + * + * Author: Dale Farnsworth + * + * 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. + */ + +#ifndef __BESTCOMM_BESTCOMM_H__ +#define __BESTCOMM_BESTCOMM_H__ + + +#undef SDMA_DEBUG + +/* Buffer Descriptor definitions */ +struct sdma_bd { + u32 status; + void *data; +}; + +struct sdma_bd2 { + u32 status; + void *data1; + void *data2; +}; + +#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 status; + u32 mvtp; + 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_FDT_SIZE SDMA_MAX_FDT * sizeof(u32) +#define SDMA_FDT_ALIGN 0x100 +#define SDMA_BD_ALIGN 0x10 + +#define TASK_ENABLE 0x8000 + +static inline void sdma_enable_task(int task) +{ + struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA; + + out_be16(&sdma->tcr[task], in_be16(&sdma->tcr[task]) | TASK_ENABLE); +} + +static inline void sdma_disable_task(int task) +{ + struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA; + + out_be16(&sdma->tcr[task], in_be16(&sdma->tcr[task]) & ~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) +{ + struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA; + + out_be32(&sdma->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 SDMA_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 SDMA_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_tdt[task].start; +} + +static inline int sdma_task_num_descs(int task) +{ + return sdma_tdt[task].stop - sdma_tdt[task].start + 1; +} + +static inline u32 *sdma_task_var(int task) +{ + return 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) { + struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA; + + u16 *tcr = &sdma->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 SDMA_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 SDMA_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 SDMA_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 SDMA_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 SDMA_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 = (u32 *)&sdma_tdt[task].fdt; + + *fdt = (*fdt & ~0xff) | pragma; +} + +static inline void sdma_set_task_auto_start(int task, int next_task) +{ + struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA; + u16 *tcr = &sdma->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); +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 -Nru a/arch/ppc/syslib/bestcomm/fec.c b/arch/ppc/syslib/bestcomm/fec.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/syslib/bestcomm/fec.c 2004-11-20 23:21:03 +01:00 @@ -0,0 +1,161 @@ +/* + * arch/ppc/syslib/bestcomm/fec.c + * + * Driver for MPC52xx processor BestComm FEC controller + * + * Author: Dale Farnsworth + * + * 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. + */ + +#include +#include +#include +#include + +#include + +#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 mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA; + struct sdma_fec_rx_var *var; + struct sdma_fec_rx_inc *inc; + static int tasknum = -1; + static struct sdma_bd *bd = 0; + + 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); + 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 = MPC52xx_SDMA + + FIELD_OFFSET(mpc52xx_sdma,tcr[tasknum]); + var->fifo = fifo; + var->bd_base = bd; + var->bd_last = &bd[s->num_bd - 1]; + var->bd_start = bd; + 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); + + sdma_set_task_pragma(tasknum, SDMA_FEC_RX_BD_PRAGMA); + sdma_set_task_auto_start(tasknum, tasknum); + + /* clear pending interrupt bits */ + out_be32(&sdma->IntPend, 1<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; inum_bd, + SDMA_BD_ALIGN); + 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 = self_modified_drd(tasknum); + var->fifo = fifo; + var->enable = MPC52xx_SDMA + + FIELD_OFFSET(mpc52xx_sdma,tcr[tasknum]); + var->bd_base = bd; + var->bd_last = &bd[s->num_bd - 1]; + var->bd_start = bd; + + /* 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->IntPend, 1<ipr[SDMA_INITIATOR_FEC_TX], SDMA_IPR_FEC_RX); + + return tasknum; +} diff -Nru a/arch/ppc/syslib/bestcomm/fec.h b/arch/ppc/syslib/bestcomm/fec.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/syslib/bestcomm/fec.h 2004-11-20 23:21:04 +01:00 @@ -0,0 +1,64 @@ +/* + * arch/ppc/syslib/bestcomm/fec.h + * + * Driver for MPC52xx processor BestComm FEC controller + * + * Author: Dale Farnsworth + * + * 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. + */ + +#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; +}; + +/* 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 -Nru a/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c 2004-11-20 23:21:05 +01:00 @@ -0,0 +1,52 @@ +/* + * sdma_fec_rx_task.c + * + * Automatically created by split_dma_image based on dma_image.hex + * on Wed Sep 8 00:37:22 2004 GMT + */ + +#include + +/* + * 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, + 0x0c020409, + 0x00000000, + 0x00000000, + + /* Task descriptors */ + 0x808220da, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc3, idx1 += inc2 */ + 0x10601010, /* DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0 */ + 0xb880025b, /* LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc3, idx3 += inc3 */ + 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) */ + 0xd9190240, /* LCDEXT: idx2 = idx2; idx2 > var9; idx2 += inc0 */ + 0xb8c5e009, /* LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */ + 0x047ecf80, /* DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=3 RS=3 */ + 0x98190024, /* LCD: idx2 = idx0; idx2 once var0; idx2 += inc4 */ + 0x0060c790, /* DRD1A: *idx1 = *idx2; FN=0 init=3 WS=0 RS=0 */ + 0x000001f8, /* NOP */ + + /* VAR[9]-VAR[10] */ + 0x40000000, + 0x7fff7fff, + + /* INC[0]-INC[3] */ + 0x40000000, + 0xe0000000, + 0xa0000008, + 0x20000000, +}; diff -Nru a/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c 2004-11-20 23:21:06 +01:00 @@ -0,0 +1,74 @@ +/* + * sdma_fec_tx_task.c + * + * Automatically created by split_dma_image based on dma_image.hex + * on Wed Sep 8 00:37:22 2004 GMT + */ + +#include + +/* + * 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, + 0x1b06070c, + 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 */ + 0x01ccfc0c, /* DRD2B1: var7 = EU3(); EU3(*idx0,var12) */ + 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 */ + 0xf8810364, /* LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var13; 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 */ + 0x0cccfcce, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var14) */ + 0x991a002c, /* LCD: idx2 = idx2, idx3 = idx4; idx2 once var0; idx2 += inc5, idx3 += inc4 */ + 0x60000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */ + 0x088cfc4f, /* DRD2B1: idx2 = EU3(); EU3(*idx1,var15) */ + 0x9919802c, /* LCD: idx2 = idx2, idx3 = idx3; 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 */ + 0x024cfc4c, /* DRD2B1: var9 = EU3(); EU3(*idx1,var12) */ + 0x60000003, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */ + 0x0cccf247, /* DRD2B1: *idx3 = EU3(); EU3(var9,var7) */ + 0xd9190440, /* LCDEXT: idx2 = idx2; idx2 > var17; idx2 += inc0 */ + 0xb8c86009, /* LCD: idx3 = *(idx1 + var0000001a); ; idx3 += inc1 */ + 0x009ec398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=3 RS=3 */ + 0x99198372, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; 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 */ + 0x0c4cf88d, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var13) */ + 0x000001f8, /* NOP */ + + /* VAR[12]-VAR[17] */ + 0x0c000000, + 0x40000000, + 0x7fff7fff, + 0x43ffffff, + 0x00000000, + 0x40000004, + + /* INC[0]-INC[6] */ + 0x40000000, + 0xe0000000, + 0xe0000000, + 0xa0000008, + 0x20000000, + 0x00000000, + 0x4000ffff, +};