linux/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff

1899 lines
48 KiB
Diff
Raw Blame History

From 6a9d4efc825b36726e94ecfe9e642cc923cb6d78 Mon Sep 17 00:00:00 2001
From: Nicolas DET <nd@bplan-gmbh.de>
Date: Fri, 24 Nov 2006 13:33:48 +0100
Subject: [PATCH] Add Efika platform
Signed-off-by: Nicolas DET <nd@bplan-gmbh.de>
---
arch/powerpc/Kconfig | 8 +
arch/powerpc/boot/Makefile | 1 +
arch/powerpc/platforms/Makefile | 1 +
arch/powerpc/platforms/efika/Makefile | 1 +
arch/powerpc/platforms/efika/bestcomm.h | 488 +++++++++++++
arch/powerpc/platforms/efika/efika.h | 19 +
arch/powerpc/platforms/efika/mpc52xx_bestcomm.c | 715 ++++++++++++++++++++
.../platforms/efika/mpc52xx_bestcomm_helper.c | 299 ++++++++
arch/powerpc/platforms/efika/pci.c | 119 ++++
arch/powerpc/platforms/efika/setup.c | 150 ++++
10 files changed, 1801 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 0673dbe..32a128d 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -386,6 +386,14 @@ config PPC_CHRP
select PPC_UDBG_16550
default y
+config PPC_EFIKA
+ bool "bPlan Efika 5k2. MPC5200B based computer"
+ depends on PPC_MULTIPLATFORM && PPC32
+ select PPC_RTAS
+ select RTAS_PROC
+ select PPC_MPC52xx
+ default y
+
config PPC_PMAC
bool "Apple PowerMac based machines"
depends on PPC_MULTIPLATFORM
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 4b2be61..7b8ce5e 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -155,6 +155,7 @@ image-$(CONFIG_PPC_PSERIES) += zImage.p
image-$(CONFIG_PPC_MAPLE) += zImage.pseries
image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
image-$(CONFIG_PPC_CHRP) += zImage.chrp
+image-$(CONFIG_PPC_EFIKA) += zImage.chrp
image-$(CONFIG_PPC_PMAC) += zImage.pmac
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index e58fa95..8294fe4 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_PPC_PMAC) += powermac/
endif
endif
obj-$(CONFIG_PPC_CHRP) += chrp/
+obj-$(CONFIG_PPC_EFIKA) += efika/
obj-$(CONFIG_4xx) += 4xx/
obj-$(CONFIG_PPC_83xx) += 83xx/
obj-$(CONFIG_PPC_85xx) += 85xx/
diff --git a/arch/powerpc/platforms/efika/Makefile b/arch/powerpc/platforms/efika/Makefile
new file mode 100644
index 0000000..5aefd3d
--- /dev/null
+++ b/arch/powerpc/platforms/efika/Makefile
@@ -0,0 +1 @@
+obj-y += setup.o pci.o mpc52xx_bestcomm.o mpc52xx_bestcomm_helper.o
diff --git a/arch/powerpc/platforms/efika/bestcomm.h b/arch/powerpc/platforms/efika/bestcomm.h
new file mode 100644
index 0000000..9555c1b
--- /dev/null
+++ b/arch/powerpc/platforms/efika/bestcomm.h
@@ -0,0 +1,488 @@
+/*
+ * include/asm-powerpc/Bestcomm.h
+ *
+ * Driver for MPC52xx processor BestComm peripheral controller
+ * Using bplan GmbH OpenFirmware
+ *
+ * 2006 (c) bplan GmbH 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__
+
+
+/**************/
+/**************/
+/**************/
+
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+
+#include <linux/types.h>
+
+/**************/
+/**************/
+/**************/
+
+#define BESTCOMM_MAX_VAR 24
+#define BESTCOMM_MAX_INC 8
+#define BESTCOMM_MAX_TASKS 16
+
+/**************/
+/**************/
+/**************/
+
+/* Task Descriptor Table Entry */
+/* copied from bestcomm.h, can be found in the public freescale doc */
+
+/* pragma pack required ? */
+struct bestcomm_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;
+};
+
+struct bestcomm_taskhandle
+{
+ int taskid;
+ int irq;
+
+ struct bestcomm_tdt __iomem * bestcomm_tdt;
+
+ u32 __iomem *bestcomm_taskcode;
+ u32 __iomem *bestcomm_vartable;
+
+ union {
+ struct sdma_bd *bd;
+ struct sdma_bd2 *bd2;
+ };
+
+ void **cookie;
+ u16 index;
+ u16 outdex;
+ u16 num_bd;
+ u32 flags;
+};
+
+
+/**************/
+struct bestcomm_mainhandle
+{
+ struct device_node *buildin_ofwnode;
+ struct device_node *sram_ofwnode;
+ struct device_node *bestcomm_ofwnode;
+
+ int bestcomm_irq;
+
+ unsigned long sdma_io_basebus;
+ struct mpc52xx_sdma __iomem* sdma_io_basevirt;
+ size_t sdma_io_size;
+
+ struct bestcomm_tdt __iomem *sdma_tdtentry;
+
+ unsigned long sram_basebus;
+ void __iomem* sram_basevirt;
+ size_t sram_size;
+ size_t sram_available;
+
+ struct bestcomm_taskhandle taskhandle_table[BESTCOMM_MAX_TASKS];
+};
+
+
+
+/**************/
+/**************/
+/**************/
+int
+bestcomm_init_once(void);
+
+struct device_node *
+bestcomm_find_hw(char *name);
+
+int
+bestcomm_hwiscapable(void);
+
+u32
+bestcomm_getreg(char *name, int *size);
+
+int
+bestcomm_getintrvector(char *name);
+
+/**************/
+struct bestcomm_taskhandle *
+bestcomm_taskallocate(int bestcomm_tasknum, int queue_size);
+
+void
+bestcomm_taskfree(struct bestcomm_taskhandle *mytaskhandle);
+
+int
+bestcomm_taskclear_irq(struct bestcomm_taskhandle *mytaskhandle);
+
+int
+bestcomm_taskenable(struct bestcomm_taskhandle *mytaskhandle);
+
+int
+bestcomm_taskdisable(struct bestcomm_taskhandle *mytaskhandle);
+
+int
+bestcomm_taskget_irq(struct bestcomm_taskhandle *mytaskhandle);
+
+u32 __iomem*
+bestcomm_taskget_code(struct bestcomm_taskhandle *mytaskhandle);
+
+u32 __iomem*
+bestcomm_taskget_vartable(struct bestcomm_taskhandle *mytaskhandle);
+
+u32 __iomem*
+bestcomm_taskget_inctable(struct bestcomm_taskhandle *mytaskhandle);
+
+u16 __iomem*
+bestcomm_taskget_tcr(struct bestcomm_taskhandle *mytaskhandle);
+
+void __iomem *
+bestcomm_phys_to_virt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr);
+
+unsigned long
+bestcomm_virt_to_phys(struct bestcomm_mainhandle *mymainhandle, void *virtaddr);
+
+void __iomem*
+bestcomm_sram_alloc(struct bestcomm_taskhandle *mytaskhandle, int len, unsigned long *busaddr);
+
+void
+bestcomm_sram_free(struct bestcomm_taskhandle *mytaskhandle, void *ptr, int len);
+
+/**************/
+/*
+ * The original Linux API has been here partially copied or wrapped
+ * this way, it's quiet easy to reuse exising code
+*/
+/* Buffer Descriptor definitions */
+struct sdma_bd {
+ u32 status;
+ void *data;
+};
+
+struct sdma_bd2 {
+ u32 status;
+ void *data1;
+ void *data2;
+};
+
+#define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f)))
+
+#define SDMA_FLAGS_NONE 0x0000
+#define SDMA_FLAGS_ENABLE_TASK 0x0001
+#define SDMA_FLAGS_BD2 0x0002
+#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)
+
+#define SDMA_LEN_BITS 26
+#define SDMA_LEN_MASK ((1 << SDMA_LEN_BITS) - 1)
+
+#define SDMA_BD_ALIGN 0x10
+
+/**************/
+/**************/
+/**************/
+struct sdma { struct bestcomm_taskhandle taskhandle; };
+
+/**************/
+/**************/
+/**************/
+unsigned long
+sdma_sram_pa(void __iomem *virt);
+
+void __iomem *
+sdma_sram_va(unsigned long pa);
+
+unsigned long sdma_io_pa
+(void __iomem *virt);
+
+void __iomem *
+sdma_io_va(unsigned long pa);
+
+/**************/
+struct sdma *
+sdma_fex_tx_preinit(int bdnum);
+
+struct sdma *
+sdma_fex_rx_preinit(int bdnum);
+
+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);
+
+struct sdma *
+sdma_ata_preinit(int maxbuffers);
+
+int
+sdma_ata_init(struct bestcomm_taskhandle *mytaskhandle, int maxbufsize);
+
+struct sdma_ata_var {
+ 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; /* size of receive buffer */
+};
+
+/**************/
+/* ata task incs that need to be set before enabling the task */
+struct sdma_ata_inc {
+ u16 pad0;
+ s16 incr_bytes;
+ u16 pad1;
+ s16 incr_dst;
+ u16 pad2;
+ s16 incr_src;
+};
+
+/* 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;
+};
+/**************/
+void *
+sdma_sram_alloc(int size, int alignment, u32 *dma_handle);
+
+static inline struct sdma *
+sdma_alloc(int request_queue_size)
+{ return NULL; };
+
+static inline void
+sdma_free(struct sdma *s)
+{ bestcomm_taskfree( (struct bestcomm_taskhandle *)s); }
+
+static inline int
+sdma_irq(struct sdma *s)
+{ return bestcomm_taskget_irq(&s->taskhandle); }
+
+static inline void
+sdma_enable(struct sdma *s)
+{ bestcomm_taskenable(&s->taskhandle); }
+
+static inline void
+sdma_disable(struct sdma *s)
+{ bestcomm_taskdisable(&s->taskhandle); }
+
+static inline int
+sdma_queue_empty(struct sdma *s_)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+ return s->index == s->outdex;
+}
+
+static inline void
+sdma_clear_irq(struct sdma *s)
+{ bestcomm_taskclear_irq( &s->taskhandle); }
+
+static inline int
+sdma_next_index(struct sdma *s_)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+ return ((s->index + 1) == s->num_bd) ? 0 : s->index + 1;
+}
+
+static inline int
+sdma_next_outdex(struct sdma *s_)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+ return ((s->outdex + 1) == s->num_bd) ? 0 : s->outdex + 1;
+}
+
+static inline int
+sdma_queue_full(struct sdma *s_)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+ return s->outdex == sdma_next_index(s_);
+}
+
+static inline int
+sdma_buffer_done(struct sdma *s_)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+
+ if (sdma_queue_empty(s_))
+ return 0;
+
+ rmb();
+ return (s->bd[s->outdex].status & SDMA_BD_READY) == 0;
+}
+
+static inline int
+sdma_buffer_done_fixed(struct sdma *s_)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+ rmb();
+ return (s->bd[s->outdex].status & SDMA_BD_READY) == 0;
+}
+
+static inline int
+sdma_buffer2_done(struct sdma *s_)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+
+ if (sdma_queue_empty(s_))
+ return 0;
+
+ rmb();
+ return (s->bd2[s->outdex].status & SDMA_BD_READY) == 0;
+}
+
+static inline void
+sdma_submit_buffer(struct sdma *s_, void *cookie, void *data, int length)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+
+ s->cookie[s->index] = cookie;
+ s->bd[s->index].data = data;
+ wmb();
+ s->bd[s->index].status = SDMA_BD_READY | length;
+ s->index = sdma_next_index(s_);
+ if (s->flags & SDMA_FLAGS_ENABLE_TASK)
+ bestcomm_taskenable(s);
+}
+
+/*
+ * 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)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+
+ s->cookie[s->index] = cookie;
+ s->bd[s->index].data = data;
+ wmb();
+ s->bd[s->index].status = SDMA_FEC_TX_BD_TFD_INIT | length;
+ s->index = sdma_next_index(s_);
+ bestcomm_taskenable(s);
+}
+
+static inline void *
+sdma_retrieve_buffer(struct sdma *s_, int *length)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+ void *cookie = s->cookie[s->outdex];
+
+ if (length) {
+ rmb();
+ *length = s->bd[s->outdex].status & SDMA_LEN_MASK;
+ }
+ s->outdex = sdma_next_outdex(s_);
+ return cookie;
+}
+
+static inline void
+sdma_reset_buffers(struct sdma *s_)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+
+ while (!sdma_queue_empty(s_)) {
+ s->bd[s->outdex].status = 0;
+ wmb();
+ s->bd[s->outdex].data = 0;
+ sdma_retrieve_buffer(s_, NULL);
+ }
+ s->index = s->outdex = 0;
+}
+
+static inline void
+sdma_submit_buffer2(struct sdma *s_, void *cookie,
+ void *data1, void *data2, int length)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+
+ s->cookie[s->index] = cookie;
+ s->bd2[s->index].data1 = data1;
+ s->bd2[s->index].data2 = data2;
+ wmb();
+ s->bd2[s->index].status = SDMA_BD_READY | length;
+ s->index = sdma_next_index(s_);
+ if (s->flags & SDMA_FLAGS_ENABLE_TASK)
+ bestcomm_taskenable(s);
+}
+
+static inline void *
+sdma_retrieve_buffer2(struct sdma *s_, int *length)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+ void *cookie = s->cookie[s->outdex];
+
+ if (length) {
+ rmb();
+ *length = s->bd2[s->outdex].status & SDMA_LEN_MASK;
+ }
+
+ s->outdex = sdma_next_outdex(s_);
+ return cookie;
+}
+
+static inline void
+sdma_reset_buffers2(struct sdma *s_)
+{
+ struct bestcomm_taskhandle *s = &s_->taskhandle;
+ while (!sdma_queue_empty(s_)) {
+ s->bd2[s->outdex].status = 0;
+ s->bd2[s->outdex].data1 = 0;
+ s->bd2[s->outdex].data2 = 0;
+ wmb();
+ sdma_retrieve_buffer2(s_, NULL);
+ }
+
+ s->index = s->outdex = 0;
+}
+
+#endif
+
diff --git a/arch/powerpc/platforms/efika/efika.h b/arch/powerpc/platforms/efika/efika.h
new file mode 100644
index 0000000..2f060fd
--- /dev/null
+++ b/arch/powerpc/platforms/efika/efika.h
@@ -0,0 +1,19 @@
+/*
+ * Efika 5K2 platform setup - Header file
+ *
+ * Copyright (C) 2006 bplan GmbH
+ *
+ * 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 __ARCH_POWERPC_EFIKA__
+#define __ARCH_POWERPC_EFIKA__
+
+#define EFIKA_PLATFORM_NAME "Efika"
+
+extern void __init efika_pcisetup(void);
+
+#endif
diff --git a/arch/powerpc/platforms/efika/mpc52xx_bestcomm.c b/arch/powerpc/platforms/efika/mpc52xx_bestcomm.c
new file mode 100644
index 0000000..c573aed
--- /dev/null
+++ b/arch/powerpc/platforms/efika/mpc52xx_bestcomm.c
@@ -0,0 +1,715 @@
+/*
+ * arch/powerpc/platforms/mpc52xx_bestcomm.c
+ *
+ * Driver for MPC52xx processor BestComm peripheral controller
+ * Using bplan GmbH OpenFirmware
+ *
+ * 2006 (c) bplan GmbH 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.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/prom.h>
+
+#include "bestcomm.h"
+
+/**************/
+/**************/
+/**************/
+
+struct bestcomm_mainhandle bestcomm_mainhandle;
+
+static int opencnt = 0;
+static struct bestcomm_taskhandle *mysdma_alloc(struct bestcomm_taskhandle *mytaskhandle, int queue_size);
+
+/**************/
+/**************/
+/**************/
+
+typedef u32 Cell;
+
+/*
+ * Virtutal <-> Bus address translator
+ * everything is static inlien here
+*/
+
+/**************/
+static void __iomem *
+sram_bustovirt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr)
+{
+ void __iomem *virtaddr;
+ long offset;
+
+ offset = busaddr - mymainhandle->sram_basebus;
+
+ if (offset < 0)
+ return NULL;
+
+ if (offset > mymainhandle->sram_size)
+ return NULL;
+
+ virtaddr = (void __iomem *) ( (u8 *)mymainhandle->sram_basevirt + offset);
+
+ return virtaddr;
+}
+
+static unsigned long
+sram_virttobus(struct bestcomm_mainhandle *mymainhandle, void *virtaddr)
+{
+ unsigned long busaddr;
+ long offset;
+
+ offset = (u8 *) virtaddr - (u8 *) mymainhandle->sram_basevirt;
+
+ if (offset < 0)
+ return 0;
+
+ if (offset > mymainhandle->sram_size)
+ return 0;
+
+ busaddr = mymainhandle->sram_basebus + offset;
+
+ return busaddr;
+}
+
+static void __iomem *
+io_bustovirt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr)
+{
+ void __iomem *virtaddr;
+ long offset;
+
+ offset = busaddr - mymainhandle->sdma_io_basebus;
+
+ if (offset < 0)
+ return NULL;
+
+ if (offset > mymainhandle->sdma_io_size)
+ return NULL;
+
+ virtaddr = (void __iomem *) ( (u8 *)mymainhandle->sdma_io_basevirt + offset);
+
+ return virtaddr;
+}
+
+static unsigned long
+io_virttobus(struct bestcomm_mainhandle *mymainhandle, void *virtaddr)
+{
+ unsigned long busaddr;
+ long offset;
+
+ offset = (u8 *) virtaddr - (u8 *) mymainhandle->sdma_io_basevirt;
+
+ if (offset < 0)
+ return 0;
+
+ if (offset > mymainhandle->sdma_io_size)
+ return 0;
+
+ busaddr = mymainhandle->sdma_io_basebus + offset;
+
+ return busaddr;
+}
+
+/**************/
+static u8 *area1_end;
+static u8 *area2_begin;
+static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED;
+
+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;
+}
+
+void __iomem*
+bestcomm_sram_alloc(struct bestcomm_taskhandle *mytaskhandle, int len, unsigned long *busaddr)
+{
+ void *virtaddr;
+ u32 lbusaddr=0;
+
+ virtaddr = sdma_sram_alloc(len, 32, &lbusaddr);
+ *busaddr = (unsigned long) lbusaddr;
+
+ return virtaddr;
+}
+
+/**************/
+void
+bestcomm_sram_free(struct bestcomm_taskhandle *mytaskhandle, void *ptr, int len)
+{
+}
+
+/**************/
+static int probemisc(struct bestcomm_mainhandle *mymainhandle)
+{
+ int interrupt;
+ interrupt = 0xc0;
+ mymainhandle->bestcomm_irq = interrupt;
+ return 0;
+}
+
+/**************/
+static int
+probeavailable_sram(struct bestcomm_mainhandle *mymainhandle)
+{
+ struct device_node *sram_ofwnode;
+ Cell *oneptr;
+ int proplen;
+ int nac;
+ int nsc;
+ int onepair_size;
+ int paircount;
+ int i;
+
+ int pair_size;
+ unsigned long pair_addr;
+
+ int biggestpair_size=0;
+ unsigned long biggestpair_addr=0;
+
+ pr_debug("\n");
+
+ sram_ofwnode = mymainhandle->sram_ofwnode;
+ nac = prom_n_addr_cells(sram_ofwnode);
+ nsc = prom_n_size_cells(sram_ofwnode);
+ onepair_size = nac + nsc;
+
+ oneptr = (Cell *) get_property(sram_ofwnode, "available", &proplen);
+ if (!oneptr)
+ return -1;
+
+ paircount = proplen / (sizeof(Cell) * onepair_size);
+
+ for(i=0; i < paircount; i++)
+ {
+ pair_addr = (unsigned long) oneptr[i * onepair_size];
+ pair_size = (int) oneptr[i * onepair_size + nac];
+
+ mymainhandle->sram_available += pair_size;
+
+ pr_debug("SRAM free at 0x%8.8lx, size=%d\n", pair_addr, pair_size);
+
+ if (pair_size>biggestpair_size) {
+ biggestpair_size = pair_size;
+ biggestpair_addr = pair_addr;
+ }
+ }
+
+ area1_end = sram_bustovirt(mymainhandle, biggestpair_addr);
+ area2_begin = sram_bustovirt(mymainhandle, biggestpair_addr + biggestpair_size);
+
+ pr_debug("SRAM area %p -> %p\n", area1_end, area2_begin);
+
+ return 0;
+}
+
+/**************/
+static int
+mapsram(struct bestcomm_mainhandle *mymainhandle)
+{
+ unsigned long sram_offset;
+ int sram_size;
+ void *__iomem sram_virtmem;
+
+ sram_size = mymainhandle->sram_size;
+ sram_offset = mymainhandle->sram_basebus;
+
+ sram_virtmem = ioremap_nocache(sram_offset, sram_size);
+ if (!sram_virtmem)
+ return -1;
+
+ mymainhandle->sram_basevirt = sram_virtmem;
+
+ pr_debug("SRAM mapped at %p\n", sram_virtmem);
+
+ return 0;
+}
+
+/**************/
+static int
+probesram(struct bestcomm_mainhandle *mymainhandle)
+{
+ struct device_node *onenode;
+ Cell *oneptr;
+ int proplen;
+ int nac;
+ int nsc;
+
+ unsigned long sram_offset;
+ int sram_size;
+
+ pr_debug("\n");
+
+ onenode = of_find_compatible_node(NULL, "memory", "mpc5200-sram");
+ if (!onenode)
+ return -1;
+
+ nac = prom_n_addr_cells(onenode);
+ nsc = prom_n_size_cells(onenode);
+
+ pr_debug("nac=%d, nsc=%d\n", nac, nsc);
+
+ oneptr = (Cell *) get_property(onenode, "reg", &proplen);
+ if (!oneptr)
+ return -1;
+
+ if (proplen < 2)
+ return -1;
+
+ sram_offset = (unsigned long) oneptr[0];
+ sram_size = (int) oneptr[nac];
+
+ pr_debug("oneptr=%p. %lx %d\n", oneptr, sram_offset , sram_size);
+
+ mymainhandle->sram_size = sram_size;
+ mymainhandle->sram_basebus = sram_offset;
+ mymainhandle->sram_ofwnode = onenode;
+
+ return 0;
+}
+
+/**************/
+static int
+probetasktable(struct bestcomm_mainhandle *mymainhandle)
+{
+ struct device_node *onenode;
+ Cell *oneptr;
+ int proplen;
+ int nac;
+ unsigned long tdt_busaddr;
+ long tdt_offset;
+ int tdt_size;
+
+ pr_debug("\n");
+
+ onenode = mymainhandle->bestcomm_ofwnode;
+ oneptr = (Cell *) get_property(onenode, "bestcomm_tasktable", &proplen);
+ if (!oneptr)
+ return -1;
+
+ if (proplen < 2)
+ return -1;
+
+ nac = prom_n_addr_cells(onenode);
+
+ tdt_busaddr = (unsigned long) oneptr[0];
+ tdt_size = (int) oneptr[nac];
+
+ tdt_offset = tdt_busaddr - mymainhandle->sram_basebus;
+
+ pr_debug("tdt_busaddr=%8.8lx, tdt_size=%d, tdt_offset=%ld<6C>\n", tdt_busaddr, tdt_size, tdt_offset);
+
+ if (tdt_offset < 0)
+ return -1;
+
+ if (tdt_offset > mymainhandle->sram_size)
+ return -1;
+
+ mymainhandle->sdma_tdtentry = (struct bestcomm_tdt __iomem *) ( (u8 *)mymainhandle->sram_basevirt + tdt_offset);
+
+ pr_debug("SDMA_TDTEntry =%p\n", mymainhandle->sdma_tdtentry);
+
+ return 0;
+}
+
+/**************/
+static int
+probeio(struct bestcomm_mainhandle *mymainhandle)
+{
+ struct device_node *onenode;
+ Cell *oneptr;
+ int proplen;
+ int nac;
+ int nsc;
+
+ unsigned long io_busaddr;
+ int io_size;
+
+ pr_debug("\n");
+
+ onenode = of_find_compatible_node(NULL, "dma-controller", "mpc5200-bestcomm");
+ if (!onenode)
+ return -1;
+
+ nac = prom_n_addr_cells(onenode);
+ nsc = prom_n_size_cells(onenode);
+
+ pr_debug("nac=%d, nsc=%d\n", nac, nsc);
+
+ oneptr = (Cell *) get_property(onenode, "reg", &proplen);
+ if (!oneptr)
+ return -1;
+
+ if (proplen < 2)
+ return -1;
+
+ io_busaddr = (unsigned long) oneptr[0];
+ io_size = (int) oneptr[nac];
+
+ pr_debug("oneptr=%p. %lx %d\n", oneptr, io_busaddr , io_size);
+ mymainhandle->sdma_io_size = io_size;
+ mymainhandle->sdma_io_basebus = io_busaddr;
+ mymainhandle->bestcomm_ofwnode = onenode;
+
+ return 0;
+}
+
+/**************/
+static int
+mapio(struct bestcomm_mainhandle *mymainhandle)
+{
+ unsigned long io_busaddr;
+ void __iomem *io_virtaddr;
+ int io_size;
+
+ io_busaddr = mymainhandle->sdma_io_basebus;
+ io_size = mymainhandle->sdma_io_size;
+
+ io_virtaddr = ioremap_nocache(io_busaddr, io_size);
+ if (!io_virtaddr)
+ goto fail;
+
+ mymainhandle->sdma_io_basevirt = io_virtaddr;
+
+ pr_debug("Bestcomm mapped at %p\n", io_virtaddr );
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+/**************/
+static int
+do_bestcomminit(struct bestcomm_mainhandle *mymainhandle)
+{
+ int ret;
+
+ ret = probeio(mymainhandle);
+ if (ret<0)
+ goto fail;
+
+ ret = mapio(mymainhandle);
+ if (ret<0)
+ goto fail;
+
+ ret = probesram(mymainhandle);
+ if (ret<0)
+ goto fail;
+
+ ret = mapsram(mymainhandle);
+ if (ret<0)
+ goto fail;
+
+ ret = probeavailable_sram(mymainhandle);
+ if (ret<0)
+ goto fail;
+
+ ret = probetasktable(mymainhandle);
+ if (ret<0)
+ goto fail;
+
+ ret = probemisc(mymainhandle);
+ if (ret<0)
+ goto fail;
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/**************/
+int
+bestcomm_hwiscapable(void)
+{
+ return bestcomm_mainhandle.buildin_ofwnode != NULL;
+}
+
+/**************/
+/*
+ * Entry, should be called when the CPU is running
+ * on an OFW machine.
+ * We will silently and properly failed if no compatible
+ * hardware (MPC5200, MPC5200b yet)
+*/
+int
+bestcomm_init_once(void)
+{
+ int ret;
+
+ pr_debug("opencnt %d\n", opencnt);
+
+ /* Already inited ? */
+ if (opencnt>0)
+ return 0;
+
+ memset(&bestcomm_mainhandle, 0x00, sizeof(bestcomm_mainhandle) );
+
+ ret = do_bestcomminit(&bestcomm_mainhandle);
+ if (ret<0)
+ return -1;
+
+ opencnt++;
+
+ printk(KERN_INFO "MPC52xx/OpenFirmware: %d kB of free SRAM\n", bestcomm_mainhandle.sram_available );
+
+ return 0;
+}
+
+/**************/
+/**************/
+/**************/
+void
+bestcomm_taskfree(struct bestcomm_taskhandle *mytaskhandle)
+{
+ if (mytaskhandle)
+ {
+ kfree(mytaskhandle->cookie);
+ mytaskhandle->cookie = NULL;
+ }
+}
+
+struct bestcomm_taskhandle *
+bestcomm_taskallocate(int bestcomm_tasknum, int queue_size)
+{
+ struct bestcomm_taskhandle *mytaskhandle;
+ struct bestcomm_tdt __iomem *bestcomm_tdt;
+
+ if (bestcomm_tasknum<0)
+ return NULL;
+
+ if (bestcomm_tasknum>=BESTCOMM_MAX_TASKS)
+ return NULL;
+
+ mytaskhandle = &bestcomm_mainhandle.taskhandle_table[bestcomm_tasknum];
+
+ pr_debug("bestcomm_tasknum %d\n", bestcomm_tasknum);
+
+ bestcomm_tdt = &bestcomm_mainhandle.sdma_tdtentry[bestcomm_tasknum];
+
+ mytaskhandle->taskid = bestcomm_tasknum;
+ mytaskhandle->bestcomm_taskcode = sram_bustovirt(&bestcomm_mainhandle, bestcomm_tdt->start);
+ mytaskhandle->bestcomm_vartable = sram_bustovirt(&bestcomm_mainhandle, bestcomm_tdt->var);
+ mytaskhandle->irq = bestcomm_mainhandle.bestcomm_irq + bestcomm_tasknum;
+
+ pr_debug("irq=%d\n", mytaskhandle->irq );
+
+ mytaskhandle = mysdma_alloc(mytaskhandle, queue_size);
+
+ return mytaskhandle;
+}
+
+/**************/
+int
+bestcomm_taskenable(struct bestcomm_taskhandle *mytaskhandle)
+{
+ int task;
+ u16 reg;
+
+ task = mytaskhandle->taskid;
+
+ reg = in_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task]);
+ out_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task], reg | 0x8000);
+
+ return task;
+}
+
+/**************/
+int
+bestcomm_taskdisable(struct bestcomm_taskhandle *mytaskhandle)
+{
+ int task;
+ u16 reg;
+
+ task = mytaskhandle->taskid;
+
+ reg = in_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task]);
+ out_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task], reg & ~0x8000);
+
+ return task;
+}
+
+/**************/
+int
+bestcomm_taskclear_irq(struct bestcomm_taskhandle *mytaskhandle)
+{
+ int tasknum = mytaskhandle->taskid;
+ out_be32(&bestcomm_mainhandle.sdma_io_basevirt->IntPend, 1 << tasknum);
+ return tasknum;
+}
+
+/**************/
+/**************/
+/**************/
+
+
+/**************/
+void __iomem *
+bestcomm_phys_to_virt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr)
+{
+ return sram_bustovirt(mymainhandle, busaddr);
+}
+
+unsigned long
+bestcomm_virt_to_phys(struct bestcomm_mainhandle *mymainhandle, void __iomem* virtaddr)
+{
+ return sram_virttobus(mymainhandle, virtaddr);
+}
+
+/**************/
+/**************/
+/**************/
+
+/*
+ * friendly helper func
+*/
+
+int
+bestcomm_taskget_irq(struct bestcomm_taskhandle *mytaskhandle)
+{
+ return mytaskhandle->irq;
+}
+
+u32 __iomem*
+bestcomm_taskget_code(struct bestcomm_taskhandle *mytaskhandle)
+{
+ return mytaskhandle->bestcomm_taskcode;
+}
+
+u32 __iomem*
+bestcomm_taskget_vartable(struct bestcomm_taskhandle *mytaskhandle)
+{
+ return mytaskhandle->bestcomm_vartable;
+}
+
+u32 __iomem*
+bestcomm_taskget_inctable(struct bestcomm_taskhandle *mytaskhandle)
+{
+ return mytaskhandle->bestcomm_vartable + BESTCOMM_MAX_VAR;
+}
+
+u16 __iomem*
+bestcomm_taskget_tcr(struct bestcomm_taskhandle *mytaskhandle)
+{
+ return &bestcomm_mainhandle.sdma_io_basevirt->tcr[mytaskhandle->taskid];
+}
+
+
+/**************/
+/**************/
+/**************/
+/*
+ * Stuff copied and a little bit modified from the original Linux code
+ * indeed, I think it makes sense to reuse code which works. Moreover,
+ * it's then easier to reuse existing driver with SDMA task which are
+ * not in the OFW
+*/
+
+/**************/
+unsigned long
+sdma_sram_pa(void __iomem *virt)
+{
+ return sram_virttobus(&bestcomm_mainhandle, virt);
+}
+
+void __iomem *
+sdma_sram_va(unsigned long pa)
+{
+ return sram_bustovirt(&bestcomm_mainhandle, pa);
+}
+
+unsigned long
+sdma_io_pa(void __iomem *virt)
+{
+ return io_virttobus(&bestcomm_mainhandle, virt);
+}
+
+void __iomem *
+sdma_io_va(unsigned long pa)
+{
+ return io_bustovirt(&bestcomm_mainhandle, pa);
+}
+
+/**************/
+/*
+ * Here, I just alloc and setup the buffer management stuff
+ * for this task
+*/
+static struct bestcomm_taskhandle *
+mysdma_alloc(struct bestcomm_taskhandle *mytaskhandle, int queue_size)
+{
+ void **cookie;
+
+ if (!mytaskhandle)
+ return NULL;
+
+ if (queue_size)
+ {
+ cookie = kmalloc(sizeof(*cookie) * queue_size, GFP_KERNEL);
+ if (!cookie) {
+ return NULL;
+ }
+
+ mytaskhandle->cookie = cookie;
+ }
+
+ mytaskhandle->num_bd = queue_size;
+ return mytaskhandle;
+}
+
+/**************/
+/*
+ * Export symbol for modules
+*/
+
+EXPORT_SYMBOL(bestcomm_init_once);
+EXPORT_SYMBOL(bestcomm_hwiscapable);
+EXPORT_SYMBOL(bestcomm_taskallocate);
+EXPORT_SYMBOL(bestcomm_taskfree);
+EXPORT_SYMBOL(bestcomm_taskclear_irq);
+EXPORT_SYMBOL(bestcomm_taskenable);
+EXPORT_SYMBOL(bestcomm_taskdisable);
+EXPORT_SYMBOL(bestcomm_taskget_irq);
+EXPORT_SYMBOL(bestcomm_taskget_code);
+EXPORT_SYMBOL(bestcomm_taskget_vartable);
+EXPORT_SYMBOL(bestcomm_taskget_inctable);
+EXPORT_SYMBOL(bestcomm_taskget_tcr);
+EXPORT_SYMBOL(bestcomm_phys_to_virt);
+EXPORT_SYMBOL(bestcomm_virt_to_phys);
+EXPORT_SYMBOL(bestcomm_sram_alloc);
+EXPORT_SYMBOL(bestcomm_sram_free);
diff --git a/arch/powerpc/platforms/efika/mpc52xx_bestcomm_helper.c b/arch/powerpc/platforms/efika/mpc52xx_bestcomm_helper.c
new file mode 100644
index 0000000..0eef3be
--- /dev/null
+++ b/arch/powerpc/platforms/efika/mpc52xx_bestcomm_helper.c
@@ -0,0 +1,299 @@
+/*
+ * arch/powerpc/platforms/mpc52xx_bestcomm_helper.c
+ *
+ * This piece of code help the driver using the Bestcomm DMA
+ * for example, it find and setup the bestcomm dma tasks.
+ * Notice that the prototypes are all gather in Bestcomm.h
+ *
+ * 2006 (c) bplan GmbH 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.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+
+#include "bestcomm.h"
+
+
+/**************/
+/**************/
+/**************/
+extern struct bestcomm_mainhandle bestcomm_mainhandle;
+
+static int irqhack(int irq)
+{
+ struct irq_host *mpc52xx_irqhost;
+ struct device_node *pic_dev;
+
+ pic_dev = of_find_compatible_node(NULL, "interrupt-controller", "mpc5200-pic");
+
+ if (pic_dev == NULL)
+ return -1;
+
+ mpc52xx_irqhost = irq_find_host(pic_dev);
+ if (mpc52xx_irqhost == NULL)
+ return -1;
+
+ pr_debug("%s: irq=0x%x\n", __func__, irq);
+ return irq_create_mapping(mpc52xx_irqhost, irq);
+}
+
+
+/**************/
+/**************/
+/**************/
+static struct sdma *
+sdma_task_preinit(char * devicetype, char * devicecomp, char* taskname, int bdnum)
+{
+ struct sdma *sdma;
+ struct device_node *onenode;
+ struct device_node *parentnode;
+ uint32_t *oneptr;
+ int tasknum;
+ int irq;
+
+ pr_debug("%s:\n", __FUNCTION__);
+
+ if (!devicecomp)
+ return NULL;
+
+ if (!taskname)
+ return NULL;
+
+ if ( bestcomm_init_once() != 0)
+ return NULL;
+
+ pr_debug("devicecomp=%s, taskname=%s, type=%s\n", devicecomp, taskname, devicetype);
+
+ onenode = of_find_compatible_node(NULL, devicetype, devicecomp);
+ if (!onenode)
+ return NULL;
+
+ pr_debug("node=%p\n", onenode);
+
+ parentnode = onenode;
+ onenode = NULL;
+ while( (onenode = of_get_next_child(parentnode, onenode) ) )
+ {
+ pr_debug("node=%p, name=%s\n", onenode, onenode->name);
+ if ( strcmp(onenode->name, taskname) == 0)
+ break;
+ }
+
+ pr_debug("node=%p\n", onenode);
+
+ if (!onenode)
+ return NULL;
+
+ oneptr = (uint32_t*) get_property(onenode, "taskid", NULL);
+ if (!oneptr)
+ return NULL;
+
+ tasknum = (int) * oneptr;
+
+ pr_debug("tasknum=%d, bdnum=%d\n", tasknum, bdnum);
+
+ sdma = (struct sdma *) bestcomm_taskallocate(tasknum, bdnum);
+ if (!sdma)
+ return NULL;
+
+ irq = irq_of_parse_and_map(onenode, 0);
+ irqhack(irq);
+
+ return sdma;
+}
+
+
+/**************/
+/**************/
+/**************/
+/*
+ * FEC driver helper
+*/
+
+struct sdma *
+sdma_fex_tx_preinit(int bdnum)
+{
+ pr_debug("\n");
+ return sdma_task_preinit("network", "mpc5200-ethernet", "bestcomm-txtask", bdnum);
+}
+
+int
+sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo)
+{
+ struct bestcomm_taskhandle *mytaskhandle = (struct bestcomm_taskhandle *) s;
+ struct sdma_fec_tx_var *var;
+ struct sdma_fec_tx_inc *inc;
+
+ int tasknum = -1;
+ struct sdma_bd *bd = 0;
+ u32 bd_pa;
+
+ if (!bd)
+ bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * mytaskhandle->num_bd, SDMA_BD_ALIGN, &bd_pa);
+ if (!bd)
+ return -ENOMEM;
+
+ bestcomm_taskdisable(mytaskhandle);
+
+ tasknum = mytaskhandle->taskid;
+
+ mytaskhandle->bd = bd;
+ mytaskhandle->flags = SDMA_FLAGS_ENABLE_TASK;
+ mytaskhandle->index = 0;
+ mytaskhandle->outdex = 0;
+ memset(bd, 0, sizeof(*bd) * mytaskhandle->num_bd);
+
+ var = (struct sdma_fec_tx_var *) bestcomm_taskget_vartable(mytaskhandle);
+ var->DRD = sdma_sram_pa( bestcomm_taskget_code(mytaskhandle) + 31);
+ var->fifo = fifo;
+ var->enable = sdma_io_pa(&bestcomm_mainhandle.sdma_io_basevirt->tcr[tasknum]);
+ var->bd_base = bd_pa;
+ var->bd_last = bd_pa + (mytaskhandle->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 *)bestcomm_taskget_inctable(mytaskhandle);
+ inc->incr_bytes = -(s16)sizeof(u32);
+ inc->incr_src = sizeof(u32);
+ inc->incr_src_ma = sizeof(u8);
+
+ pr_debug("tasknum=%d, bdnum=%d\n", tasknum, mytaskhandle->num_bd);
+
+ mb();
+
+ return tasknum;
+}
+
+struct sdma *sdma_fex_rx_preinit(int bdnum)
+{
+ pr_debug("%s:\n", __FUNCTION__);
+ return sdma_task_preinit("network", "mpc5200-ethernet", "bestcomm-rxtask", bdnum);
+}
+
+
+int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize)
+{
+ int tasknum;
+ struct sdma_fec_rx_var *var;
+ struct sdma_fec_rx_inc *inc;
+ struct bestcomm_taskhandle *mytaskhandle = (struct bestcomm_taskhandle *) s;
+
+ struct sdma_bd *bd = 0;
+ u32 bd_pa;
+
+ if (!bd)
+ bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * mytaskhandle->num_bd, SDMA_BD_ALIGN, &bd_pa);
+
+ if (!bd)
+ return -ENOMEM;
+
+ bestcomm_taskdisable(mytaskhandle);
+
+ tasknum = mytaskhandle->taskid;
+
+ mytaskhandle->bd = bd;
+ mytaskhandle->flags = SDMA_FLAGS_NONE;
+ mytaskhandle->index = 0;
+ mytaskhandle->outdex = 0;
+ memset(bd, 0, sizeof(*bd) * mytaskhandle->num_bd);
+
+ var = (struct sdma_fec_rx_var *) bestcomm_taskget_vartable(mytaskhandle);
+
+ var->enable = sdma_io_pa(&bestcomm_mainhandle.sdma_io_basevirt->tcr[tasknum]);
+ var->fifo = fifo;
+ var->bd_base = bd_pa;
+ var->bd_last = bd_pa + (mytaskhandle->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 *) bestcomm_taskget_inctable(mytaskhandle);
+ inc->incr_bytes = -(s16)sizeof(u32);
+ inc->incr_dst = sizeof(u32);
+ inc->incr_dst_ma = sizeof(u8);
+
+ pr_debug("tasknum=%d, bdnum=%d\n", tasknum, mytaskhandle->num_bd);
+
+ mb();
+
+ return tasknum;
+}
+
+/**************/
+/**************/
+/**************/
+int sdma_ata_init(struct bestcomm_taskhandle *mytaskhandle, int maxbufsize)
+{
+ struct sdma_ata_var *var;
+ struct sdma_bd2 *bd2 = 0;
+ u32 bd_pa;
+ int tasknum = -1;
+
+ pr_debug("MyTaskHandle=%pn max buf=%d\n", mytaskhandle, maxbufsize);
+
+ if (!bd2)
+ bd2 = (struct sdma_bd2 *)sdma_sram_alloc(sizeof(*bd2) * mytaskhandle->num_bd, SDMA_BD_ALIGN, &bd_pa);
+
+ if (!bd2)
+ return -ENOMEM;
+
+ bestcomm_taskdisable(mytaskhandle);
+
+ tasknum = mytaskhandle->taskid;
+
+ mytaskhandle->flags = SDMA_FLAGS_BD2;
+ mytaskhandle->bd2 = bd2;
+ mytaskhandle->index = 0;
+ mytaskhandle->outdex = 0;
+ memset(bd2, 0, sizeof(*bd2) * mytaskhandle->num_bd);
+
+ var = (struct sdma_ata_var *)bestcomm_taskget_vartable(mytaskhandle);
+ var->enable = sdma_io_pa(&bestcomm_mainhandle.sdma_io_basevirt->tcr[tasknum]);
+ var->bd_base = bd_pa;
+ var->bd_last = bd_pa + (mytaskhandle->num_bd - 1)*sizeof(struct sdma_bd2);
+ var->bd_start = bd_pa;
+ var->buffer_size = maxbufsize;
+
+ mb();
+
+ return 0;
+}
+
+/**************/
+
+struct sdma *sdma_ata_preinit(int maxbuffers)
+{
+ pr_debug("%s:\n", __FUNCTION__);
+ return sdma_task_preinit("ata", "mpc5200-ata", "bestcomm-task", maxbuffers);
+}
+
+
+/**************/
+/*
+ * Export symbol for modules
+*/
+
+EXPORT_SYMBOL(sdma_sram_pa);
+EXPORT_SYMBOL(sdma_sram_va);
+EXPORT_SYMBOL(sdma_io_pa);
+EXPORT_SYMBOL(sdma_io_va);
+
+EXPORT_SYMBOL(sdma_fex_tx_preinit);
+EXPORT_SYMBOL(sdma_fex_rx_preinit);
+EXPORT_SYMBOL(sdma_fec_rx_init);
+EXPORT_SYMBOL(sdma_fec_tx_init);
+
+EXPORT_SYMBOL(sdma_ata_preinit);
+EXPORT_SYMBOL(sdma_ata_init);
diff --git a/arch/powerpc/platforms/efika/pci.c b/arch/powerpc/platforms/efika/pci.c
new file mode 100644
index 0000000..62e05b2
--- /dev/null
+++ b/arch/powerpc/platforms/efika/pci.c
@@ -0,0 +1,119 @@
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/sections.h>
+#include <asm/pci-bridge.h>
+#include <asm/rtas.h>
+
+#include "efika.h"
+
+#ifdef CONFIG_PCI
+/*
+ * Access functions for PCI config space using RTAS calls.
+ */
+static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 * val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
+ | (((bus->number - hose->first_busno) & 0xff) << 16)
+ | (hose->index << 24);
+ int ret = -1;
+ int rval;
+
+ rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len);
+ *val = ret;
+ return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int rtas_write_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
+ | (((bus->number - hose->first_busno) & 0xff) << 16)
+ | (hose->index << 24);
+ int rval;
+
+ rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
+ addr, len, val);
+ return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops rtas_pci_ops = {
+ rtas_read_config,
+ rtas_write_config
+};
+
+void __init efika_pcisetup(void)
+{
+ const int *bus_range;
+ int len;
+ struct pci_controller *hose;
+ struct device_node *root;
+ struct device_node *pcictrl;
+
+ root = of_find_node_by_path("/");
+ if (root == NULL) {
+ printk(KERN_WARNING EFIKA_PLATFORM_NAME
+ ": Unable to find the root node\n");
+ return;
+ }
+
+ for (pcictrl = NULL;;) {
+ pcictrl = of_get_next_child(root, pcictrl);
+ if ((pcictrl == NULL) || (strcmp(pcictrl->name, "pci") == 0))
+ break;
+ }
+
+ of_node_put(root);
+
+ if (pcictrl == NULL) {
+ printk(KERN_WARNING EFIKA_PLATFORM_NAME
+ ": Unable to find the PCI bridge node\n");
+ return;
+ }
+
+ bus_range = get_property(pcictrl, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING EFIKA_PLATFORM_NAME
+ ": Can't get bus-range for %s\n", pcictrl->full_name);
+ return;
+ }
+
+ if (bus_range[1] == bus_range[0])
+ printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d",
+ bus_range[0]);
+ else
+ printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d",
+ bus_range[0], bus_range[1]);
+ printk(" controlled by %s\n", pcictrl->full_name);
+ printk("\n");
+
+ hose = pcibios_alloc_controller();
+ if (!hose) {
+ printk(KERN_WARNING EFIKA_PLATFORM_NAME
+ ": Can't allocate PCI controller structure for %s\n",
+ pcictrl->full_name);
+ return;
+ }
+
+ hose->arch_data = of_node_get(pcictrl);
+ hose->first_busno = bus_range[0];
+ hose->last_busno = bus_range[1];
+ hose->ops = &rtas_pci_ops;
+
+ pci_process_bridge_OF_ranges(hose, pcictrl, 0);
+}
+
+#else
+void __init efika_pcisetup(void)
+{}
+#endif
diff --git a/arch/powerpc/platforms/efika/setup.c b/arch/powerpc/platforms/efika/setup.c
new file mode 100644
index 0000000..110c980
--- /dev/null
+++ b/arch/powerpc/platforms/efika/setup.c
@@ -0,0 +1,150 @@
+/*
+ *
+ * Efika 5K2 platform setup
+ * Some code really inspired from the lite5200b platform.
+ *
+ * Copyright (C) 2006 bplan GmbH
+ *
+ * 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 <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/utsrelease.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/rtas.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include <asm/mpc52xx.h>
+
+#include "efika.h"
+
+static void efika_show_cpuinfo(struct seq_file *m)
+{
+ struct device_node *root;
+ const char *revision = NULL;
+ const char *codegendescription = NULL;
+ const char *codegenvendor = NULL;
+
+ root = of_find_node_by_path("/");
+ if (root) {
+ revision = get_property(root, "revision", NULL);
+ codegendescription =
+ get_property(root, "CODEGEN,description", NULL);
+ codegenvendor = get_property(root, "CODEGEN,vendor", NULL);
+
+ of_node_put(root);
+ }
+
+ if (codegendescription)
+ seq_printf(m, "machine\t\t: %s\n", codegendescription);
+ else
+ seq_printf(m, "machine\t\t: Efika\n");
+
+ if (revision)
+ seq_printf(m, "revision\t: %s\n", revision);
+
+ if (codegenvendor)
+ seq_printf(m, "vendor\t\t: %s\n", codegenvendor);
+
+ of_node_put(root);
+}
+
+static void __init efika_setup_arch(void)
+{
+ rtas_initialize();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ initrd_below_start_ok = 1;
+
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+ ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */
+
+ efika_pcisetup();
+
+ if (ppc_md.progress)
+ ppc_md.progress("Linux/PPC " UTS_RELEASE " runnung on Efika ;-)\n", 0x0);
+}
+
+static void __init efika_init(void)
+{
+ struct device_node *np;
+ struct device_node *cnp = NULL;
+ const u32 *base;
+
+ /* Find every child of the SOC node and add it to of_platform */
+ np = of_find_node_by_name(NULL, "builtin");
+ if (np) {
+ char name[BUS_ID_SIZE];
+ while ((cnp = of_get_next_child(np, cnp))) {
+ strcpy(name, cnp->name);
+
+ base = get_property(cnp, "reg", NULL);
+ if (base == NULL)
+ continue;
+
+ snprintf(name+strlen(name), BUS_ID_SIZE, "@%x", *base);
+ of_platform_device_create(cnp, name, NULL);
+
+ printk(KERN_INFO EFIKA_PLATFORM_NAME" : Added %s (type '%s' at '%s') to the known devices\n", name, cnp->type, cnp->full_name);
+ }
+ }
+
+ if (ppc_md.progress)
+ ppc_md.progress(" Have fun with your Efika! ", 0x7777);
+}
+
+static int __init efika_probe(void)
+{
+ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ "model", NULL);
+
+ if (model == NULL)
+ return 0;
+ if (strcmp(model, "EFIKA5K2"))
+ return 0;
+
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ return 1;
+}
+
+define_machine(efika)
+{
+ .name = EFIKA_PLATFORM_NAME,
+ .probe = efika_probe,
+ .setup_arch = efika_setup_arch,
+ .init = efika_init,
+ .show_cpuinfo = efika_show_cpuinfo,
+ .init_IRQ = mpc52xx_init_irq,
+ .get_irq = mpc52xx_get_irq,
+ .restart = rtas_restart,
+ .power_off = rtas_power_off,
+ .halt = rtas_halt,
+ .set_rtc_time = rtas_set_rtc_time,
+ .get_rtc_time = rtas_get_rtc_time,
+ .progress = rtas_progress,
+ .get_boot_time = rtas_get_boot_time,
+ .calibrate_decr = generic_calibrate_decr,
+ .phys_mem_access_prot = pci_phys_mem_access_prot,
+};
--
1.4.3.2