From: Dan Williams <dan.j.williams@intel.com>
To: linux@arm.linux.org.uk, James.Bottomley@steeleye.com
Cc: linux-arm-kernel@lists.arm.linux.org.uk,
linux-scsi@vger.kernel.org, dan.j.williams@intel.com,
greg.b.tucker@intel.com
Subject: [PATCH RFC 1/2] iop13xx: add base support for the imu
Date: Wed, 24 Jan 2007 11:24:16 -0700 [thread overview]
Message-ID: <20070124182416.6029.41466.stgit@dwillia2-linux.ch.intel.com> (raw)
In-Reply-To: <20070124182245.6029.43097.stgit@dwillia2-linux.ch.intel.com>
From: Greg Tucker <greg.b.tucker@intel.com>
The interprocessor messaging unit supports mailbox style communication
between the two Xscale cores on iop342.
Signed-off-by: Greg Tucker <greg.b.tucker@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
arch/arm/mach-iop13xx/Kconfig | 2
arch/arm/mach-iop13xx/Makefile | 1
arch/arm/mach-iop13xx/imu/Kconfig | 19 +
arch/arm/mach-iop13xx/imu/Makefile | 3
arch/arm/mach-iop13xx/imu/common.c | 486 ++++++++++++++++++++++++++++
arch/arm/mach-iop13xx/imu/dev.c | 438 +++++++++++++++++++++++++
arch/arm/mach-iop13xx/imu/imu.c | 151 +++++++++
include/asm-arm/arch-iop13xx/iop13xx-imu.h | 207 ++++++++++++
8 files changed, 1307 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-iop13xx/Kconfig b/arch/arm/mach-iop13xx/Kconfig
index 40c2d68..27c1c2c 100644
--- a/arch/arm/mach-iop13xx/Kconfig
+++ b/arch/arm/mach-iop13xx/Kconfig
@@ -16,5 +16,7 @@ config MACH_IQ81340MC
Say Y here if you want to support running on the Intel IQ81340MC
evaluation kit.
+source "arch/arm/mach-iop13xx/imu/Kconfig"
+
endmenu
endif
diff --git a/arch/arm/mach-iop13xx/Makefile b/arch/arm/mach-iop13xx/Makefile
index 4185e05..7937d73 100644
--- a/arch/arm/mach-iop13xx/Makefile
+++ b/arch/arm/mach-iop13xx/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_ARCH_IOP13XX) += pci.o
obj-$(CONFIG_ARCH_IOP13XX) += io.o
obj-$(CONFIG_MACH_IQ81340SC) += iq81340sc.o
obj-$(CONFIG_MACH_IQ81340MC) += iq81340mc.o
+obj-$(CONFIG_IOP_IMU) += imu/
diff --git a/arch/arm/mach-iop13xx/imu/Kconfig b/arch/arm/mach-iop13xx/imu/Kconfig
new file mode 100644
index 0000000..ee49b37
--- /dev/null
+++ b/arch/arm/mach-iop13xx/imu/Kconfig
@@ -0,0 +1,19 @@
+#
+# IOP13xx IMU Support
+#
+
+menu "IOP13XX IMU Support"
+
+config IOP_IMU
+ tristate "IOP IMU support"
+ depends on EXPERIMENTAL
+ ---help---
+ This includes support functions for the IMU.
+
+config IOP_IMU_DEV
+ tristate "IOP IMU char driver"
+ depends on IOP_IMU
+ ---help---
+ This is a char driver that passes messages throught the IMU.
+
+endmenu
diff --git a/arch/arm/mach-iop13xx/imu/Makefile b/arch/arm/mach-iop13xx/imu/Makefile
new file mode 100644
index 0000000..f89fb53
--- /dev/null
+++ b/arch/arm/mach-iop13xx/imu/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_IOP_IMU) += common.o imu.o
+obj-$(CONFIG_IOP_IMU_DEV) += dev.o
+
diff --git a/arch/arm/mach-iop13xx/imu/common.c b/arch/arm/mach-iop13xx/imu/common.c
new file mode 100644
index 0000000..2d9c311
--- /dev/null
+++ b/arch/arm/mach-iop13xx/imu/common.c
@@ -0,0 +1,486 @@
+/*
+ * arch/arm/mach-iop13xx/imu/iop1340-imu-common.c
+ *
+ * Interface functions for comunication using IMU hardware on the IOP1342
+ *
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Greg Tucker <greg.b.tucker@intel.com>
+ *
+ */
+
+#ifdef linux
+# include <linux/module.h>
+# include <linux/kernel.h>
+# include <asm/arch/iop13xx-imu.h>
+#else
+# include "iop1340-imu-common.h"
+#endif
+
+imu_handler *imu_irq_table[NR_IMU_DOORBELLS + NR_IMU_QUEUE_IRQS];
+struct imu_queue_params imu_queue[NR_IMU_QUEUES];
+
+/**
+ ****************************************************************************
+ * @iop_doorbell_ring
+ * @brief
+ * Ring specified hw doorbell.
+ *
+ * Will cause an interrupt on the other processor if enabled.
+ *
+ * @param IN: int doorbell - doorbell number
+ * @return NONE
+ *****************************************************************************/
+
+/* #define iop_doorbell_ring(doorbell) do {*((volatile int*)IMU_DBAR) = (1<<doorbell);} while(0) */
+
+inline void iop_doorbell_ring(int doorbell)
+{
+ *((volatile int *)IMU_DBAR) = (1 << doorbell);
+}
+
+/**
+ ****************************************************************************
+ * @iop_wait_on_doorbell
+ * @brief
+ * Spin until doorbell asserted.
+ * @param IN: int doorbell - doorbell number
+ * @return NONE
+ *****************************************************************************/
+
+/*#define iop_wait_on_doorbell(doorbell) do {while ( 0 == (*((volatile int*)IMU_DBCR) & (1<<doorbell)) ) ;} while (0) */
+
+inline void iop_wait_on_doorbell(int doorbell)
+{
+ while (0 == (*((volatile int *)IMU_DBCR) & (1 << doorbell))) ;
+}
+
+/**
+ ******************************************************************************
+ * @iop_doorbell_clear_status
+ * @brief
+ * Clear doorbell status bit so future doorbells can interrupt.
+ * @param IN: int doorbell - doorbell number
+ * @return NONE
+ *****************************************************************************/
+
+/* #define iop_doorbell_clear_status(doorbell) do {*((volatile int*)IMU_DBCR) = (1<<doorbell) & ((1<<16)-1);} while(0) */
+
+inline void iop_doorbell_clear_status(int doorbell)
+{
+ *((volatile int *)IMU_DBCR) = (1 << doorbell) & ((1 << 16) - 1);
+}
+
+/**
+ ******************************************************************************
+ * @iop_doorbell_check_status
+ * @brief
+ * Check if doorbell is active.
+ * @param IN: int doorbell - doorbell number
+ * @return
+ * 0: doorbell not active
+ * other: doorbell active
+ *****************************************************************************/
+inline int iop_doorbell_check_status(int doorbell)
+{
+ return *((volatile int *)IMU_DBCR) & (1 << doorbell);
+}
+
+/**
+ ******************************************************************************
+ * @iop_doorbell_enable
+ * @brief
+ * Enable this doorbell to interrupt processor.
+ * @param IN: int doorbell - doorbell number
+ * @return NONE
+ *****************************************************************************/
+void iop_doorbell_enable(int doorbell)
+{
+ *((volatile int *)IMU_DBER) |= (1 << doorbell);
+}
+
+/**
+ ******************************************************************************
+ * @iop_doorbell_disable
+ * @brief
+ * Disable particular doorbell.
+ * @param IN: int doorbell - doorbell number
+ * @return NONE
+ *****************************************************************************/
+void iop_doorbell_disable(int doorbell)
+{
+ *((volatile int *)IMU_DBER) &= ~(1 << doorbell);
+}
+
+/**
+ ******************************************************************************
+ * @iop_doorbell_mask
+ * @brief
+ * Mask/Disable doorbells corresponding to mask.
+ * @param IN: int mask - vector of doorbells to disable
+ * @return NONE
+ *****************************************************************************/
+void iop_doorbell_mask(int mask)
+{
+ *((volatile int *)IMU_DBER) &= ~(mask);
+}
+
+/**
+ ******************************************************************************
+ * @iop_doorbell_unmask
+ * @brief
+ * Unmask/Enable doorbells corresponding to mask.
+ * @param IN: int mask - vector of doorbells to enable
+ * @return NONE
+ *****************************************************************************/
+void iop_doorbell_unmask(int mask)
+{
+ *((volatile int *)IMU_DBER) &= mask;
+}
+
+/**
+ ****************************************************************************
+ * @iop_doorbell_reg_callback
+ * @brief
+ * Register the callback function for a particular doorbell.
+ * @param IN: int doorbell - doorbell number
+ * @param IN: void * callback(void) - pointer to callback function
+ * @return NONE
+ *****************************************************************************/
+int iop_doorbell_reg_callback(int doorbell, void (*callback) (int))
+{
+ if ((doorbell >= 0) && (doorbell <= IMU_DB_RQ3NE)) {
+ imu_irq_table[doorbell] = (imu_handler *) callback;
+ return 0;
+ } else
+ return 1;
+}
+
+/**
+ ******************************************************************************
+ * @iop_mutex_lock
+ * @brief
+ * Block until mutex is granted.
+ *
+ * Checks if current core has been granted access to the hw mutex.
+ * Does not check if it's the current thread that has access or
+ * another thread on the same processor. Only binary mutex is
+ * supported.
+ *
+ * @param IN: mutex - mutex number
+ * @return NONE
+ *****************************************************************************/
+void iop_mutex_lock(int mutex)
+{
+ int trymutex = *IMU_TSR(mutex);
+ int corenum = (1 << CIDR_READ());
+
+ while (trymutex != 0 && trymutex != corenum) {
+ trymutex = *IMU_TSR(mutex);
+ }
+}
+
+/**
+ ****************************************************************************
+ * @iop_mutex_trylock
+ * @brief
+ * Non-blocking attempt to get mutex.
+ *
+ * Checks if current core has been granted access to the hw mutex.
+ * Does not check if it's the current thread that has access or
+ * another thread on the same processor. Only binary mutex is
+ * supported.
+ *
+ * @param IN: int mutex - mutex number
+ * @return
+ * 0: success
+ * 1: other core has lock
+ *****************************************************************************/
+int iop_mutex_trylock(int mutex)
+{
+ int trymutex = *IMU_TSR(mutex);
+ int coreid = CIDR_READ();
+
+ if (trymutex == 0 || (trymutex ^ (1 << coreid)) == 0)
+ return 0;
+ else
+ return 1;
+}
+
+/**
+ ****************************************************************************
+ * @iop_mutex_unlock
+ * @brief
+ * Unlock/free the given mutex.
+ *
+ * Does not first check if the mutex is locked. Assumes that the
+ * calling thread ownes the mutex. Currently only binary mutex is
+ * supported so does not keep a lock count.
+ *
+ * @param IN: int mutex - mutex number
+ * @return NONE
+ *****************************************************************************/
+void iop_mutex_unlock(int mutex)
+{
+ /* assert(iop_mutex_trylock(mutex)); */
+ *IMU_TSR(mutex) = 0x0;
+}
+
+/**
+ ****************************************************************************
+ * @iop_queue_init
+ * @brief
+ * Initialize circular queue.
+ *
+ * Sets up a circular queue with memory for the queue buffers and
+ * callback function for received messages. Caller must first
+ * allocate memory of appropriate size and type for the queue. The
+ * queue is of fixed size (msg_size * num_items) bytes.
+ *
+ * @todo List restrictions on the memory type (dma-able, etc.)
+ *
+ * @param IN: int queueid - queue identifier
+ * @param IN: void * phys_base - physical base pointer to pre-allocated memory
+ * @param IN: void * virt_base - virtual base pointer to pre-allocated memory
+ * @param IN: int msg_size - size of fixed messages in bytes
+ * @param IN: int num_items - max number of items in the queue
+ * @param IN: void * callback(int) - pointer to callback function
+ * @param IN: void * error_callback(int) - pointer to error function
+ * @return 0: success
+ *****************************************************************************/
+int
+iop_queue_init(int queueid, void *phys_base, void *virt_base, int msg_size,
+ int num_items, void (*rcd_callback) (int),
+ void (*error_callback) (int))
+{
+ struct imu_queue *queue_hw = (struct imu_queue *)
+ (IMU_Q0_BASE + (queueid * sizeof(struct imu_queue)));
+
+ if (queueid > 3 || num_items > ((1 << 16) - 1))
+ return 1;
+
+ /* init send queue pointers */
+ queue_hw->sqcr = (1 << 31) /* reset send queue get/put pointers */
+ |num_items; /* set size */
+ queue_hw->rqcr = (1 << 31); /* reset receive queue get/put pointers */
+ queue_hw->sqlbar = (int)phys_base;
+ queue_hw->squbar = 0; /* assuming 32 bit address space */
+
+ imu_queue[queueid].txbase = virt_base;
+ imu_queue[queueid].msg_size = msg_size;
+ imu_queue[queueid].items = num_items;
+ imu_queue[queueid].alloc = queue_hw->sqpg >> 16; /* alloc=get */
+
+ /* Register callback */
+ imu_irq_table[NR_IMU_DOORBELLS - 1 +
+ (IMU_DB_RQ0NE - IMU_DB_QUEUE_IRQ_OFF) + (queueid * 2)] =
+ (imu_handler *) rcd_callback;
+ /* Enable receive interrupt */
+ iop_doorbell_enable(IMU_DB_RQ0NE + (queueid * 2));
+
+ return 0;
+}
+
+/**
+ ****************************************************************************
+ * @iop_queue_allocate
+ * @brief
+ * Return pointer to next free buffer queue.
+ * @param IN: int queueid - queue identifier
+ * @return buffer pointer to fill with message
+ *****************************************************************************/
+void *iop_queue_allocate(int queueid)
+{
+ void *ret = NULL;
+ int alloc, get, items_m1, next_alloc;
+
+ struct imu_queue_params *queue = &imu_queue[queueid];
+ struct imu_queue *queue_hw = (struct imu_queue *)
+ (IMU_Q0_BASE + (queueid * sizeof(struct imu_queue)));
+
+ if (queueid > 3)
+ return NULL;
+
+ /* todo: put mutex around alloc update */
+ alloc = queue->alloc;
+ get = queue_hw->sqpg >> 16;
+ items_m1 = queue->items - 1;
+ next_alloc = (alloc == items_m1) ? 0 : alloc + 1;
+
+ if (next_alloc != get) { /* not full */
+ ret = (void *)(queue->txbase + (queue->msg_size * alloc));
+ queue->alloc = next_alloc;
+ }
+ /* todo: unlock mutex on alloc */
+
+ return ret;
+}
+
+/**
+ ****************************************************************************
+ * @iop_queue_postmsg
+ * @brief
+ * Post (send) all buffers up to message identified by message pointer.
+ * @param IN: int queueid - queue identifier
+ * @param IN: void * msg_adr - pointer to last message to post
+ * @return NONE
+ *****************************************************************************/
+int iop_queue_postmsg(int queueid, void *msg_adr)
+{
+ int offset, items, items_m1, put, alloc, index;
+
+ struct imu_queue_params *queue = &imu_queue[queueid];
+ struct imu_queue *queue_hw = (struct imu_queue *)
+ (IMU_Q0_BASE + (queueid * sizeof(struct imu_queue)));
+
+ offset = (int)(msg_adr - queue->txbase);
+
+ items = queue->items;
+ items_m1 = items - 1;
+
+ /* Check if it is in range for this queue */
+ if (offset < 0 || offset > (queue->msg_size * items))
+ return 1;
+
+ put = queue_hw->sqpg & 0xffff;
+ alloc = queue->alloc;
+ index = offset / queue->msg_size;
+
+ /* todo: Check if allocated? */
+ /* don't post something already posted */
+
+ if (alloc >= put) {
+ if (index < put || index >= alloc)
+ return 1; /* already posted or not allocated */
+ } else {
+ if (index < put && index >= alloc)
+ return 1; /* already posted or not allocated */
+ }
+
+ queue_hw->sqpg = (index == items_m1) ? 0 : index + 1;
+
+ return 0;
+}
+
+/**
+ ****************************************************************************
+ * @iop_queue_rx_not_empty
+ * @brief
+ * Check rx queue for not empty status.
+ * @param IN: int queueid - queue identifier
+ * @return
+ * 0: rx queue empty
+ * other: rx queue not empty
+ *****************************************************************************/
+int iop_queue_rx_not_empty(int queueid)
+{
+ struct imu_queue *queue_hw = (struct imu_queue *)
+ (IMU_Q0_BASE + (queueid * sizeof(struct imu_queue)));
+
+ int rqpg = queue_hw->rqpg;
+ int put = rqpg & 0xffff;
+ int get = rqpg >> 16;
+ return get - put;
+}
+
+/**
+ ****************************************************************************
+ * @iop_queue_tx_not_full
+ * @brief
+ * Check tx queue for full status
+ * @param IN: int queueid - queue identifier
+ * @return
+ * 0: tx queue full
+ * other: rx queue not full
+ *****************************************************************************/
+int iop_queue_tx_not_full(int queueid)
+{
+ struct imu_queue_params *queue = &imu_queue[queueid];
+ struct imu_queue *queue_hw = (struct imu_queue *)
+ (IMU_Q0_BASE + (queueid * sizeof(struct imu_queue)));
+
+ int get = queue_hw->sqpg >> 16;
+ int next_alloc = queue->alloc + 1;
+ next_alloc = (next_alloc == queue->items) ? 0 : next_alloc;
+
+ return next_alloc - get;
+}
+
+/**
+ ****************************************************************************
+ * @iop_queue_getmsg
+ * @brief
+ * Get next available message.
+ *
+ * Get a pointer to the next available message in the recieve queue.
+ * Subsequent calls will return the same value until the message is freed.
+ *
+ * @param IN: int queueid - queue identifier
+ * @return buffer pointer to next available message
+ *****************************************************************************/
+void *iop_queue_getmsg(int queueid)
+{
+
+ struct imu_queue_params *queue = &imu_queue[queueid];
+ struct imu_queue *queue_hw = (struct imu_queue *)
+ (IMU_Q0_BASE + (queueid * sizeof(struct imu_queue)));
+
+ int rqpg = queue_hw->rqpg;
+ void *base = queue->rxbase;
+ int put = rqpg & 0xffff;
+ int get = rqpg >> 16;
+
+ if (!base || put == get)
+ return 0;
+
+ return base + (get * queue->msg_size);
+}
+
+/**
+ ****************************************************************************
+ * @iop_queue_rxfree
+ * @brief
+ * Free a buffer in the receive queue that has already been processed.
+ *
+ * Free the buffer that includes msg_addr. Also frees all prior
+ * messages in the queue.
+ *
+ * @param IN: int queueid - queue identifier
+ * @param IN: void * msg_addr - pointer to data within message to free
+ * @return buffer pointer to next available message
+ *****************************************************************************/
+int iop_queue_rxfree(int queueid, void *msg_adr)
+{
+ int rq_items, offset, index;
+
+ struct imu_queue_params *queue = &imu_queue[queueid];
+ struct imu_queue *queue_hw = (struct imu_queue *)
+ (IMU_Q0_BASE + (queueid * sizeof(struct imu_queue)));
+
+ rq_items = queue_hw->rqcr & 0xffff;
+ offset = (int)(msg_adr - queue->rxbase);
+
+ /* Check if it is in range for this queue */
+ if (offset < 0 || offset > (queue->msg_size * rq_items)) {
+ return 1;
+ }
+
+ index = (offset / queue->msg_size) + 1;
+ index = (index == rq_items) ? 0 : index;
+ queue_hw->rqpg = index << 16; /* update get pointer */
+
+ return 0;
+}
diff --git a/arch/arm/mach-iop13xx/imu/dev.c b/arch/arm/mach-iop13xx/imu/dev.c
new file mode 100644
index 0000000..b73af6b
--- /dev/null
+++ b/arch/arm/mach-iop13xx/imu/dev.c
@@ -0,0 +1,438 @@
+/*
+ * arch/arm/mach-iop13xx/imu/iop1340-imu-dev.c
+ *
+ * Char driver for user-space access to IMU inter-core messaging.
+ *
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Greg Tucker <greg.b.tucker@intel.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/jiffies.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/arch/iop13xx-imu.h>
+
+#define MODULE_VERS "1.0"
+#define MODULE_NAME "IMUdev"
+//#define IMU_MAJOR 245
+#define IMU_MAJOR 0
+#define IMU_MAX_MINORS 4
+#define IMU_FIRST_MINOR 1
+
+#define Q_MSG_SIZE 64
+#define Q_MSG_ITEMS 16
+#define Q_PHYS_BASE (128*1024*1024)
+#define Q_SIZE (Q_MSG_ITEMS*Q_MSG_SIZE)
+#define MSG_HEADER_SIZE 4
+
+#define IMU_WRITE_TIMEOUT 1000
+
+struct imu_dev {
+ struct cdev cdev;
+ wait_queue_head_t rq;
+ wait_queue_head_t wq;
+ size_t rq_leftover;
+ char *rq_leftover_ptr;
+ atomic_t read_available;
+ atomic_t write_available;
+};
+
+static struct imu_dev imu[IMU_MAX_MINORS];
+static int imu_major = IMU_MAJOR;
+
+void queue_rq_callback(int queueid)
+{
+ struct imu_dev *imui = &imu[queueid];
+
+ pr_debug("queue_rq_callback %d\n", queueid);
+ wake_up_interruptible(&imui->rq);
+ iop_doorbell_disable(IMU_DB_RQ0NE + (queueid * 2));
+}
+
+void queue_wq_callback(int queueid)
+{
+ struct imu_dev *imui = &imu[queueid];
+
+ pr_debug("wq callback on not full q=%d\n", queueid);
+ wake_up_interruptible(&imui->wq);
+ iop_doorbell_disable(IMU_DB_SQ0NF + (queueid * 2));
+}
+
+extern struct imu_queue_params imu_queue[];
+
+/*
+ * init_callback only called on the first rx to map the base
+ */
+
+#define has_overlap(a,b,c,d) (((c<=a) && (d>a))||((c<b) && (d>=b))||((c>=a) && (d<=b)))
+
+void init_callback(int queueid)
+{
+ int i, qi_rxitems, err = 0;
+ struct imu_queue_params *qi;
+ struct imu_queue_params *queue = &imu_queue[queueid];
+ struct imu_queue *qi_hw;
+ struct imu_queue *queue_hw = (struct imu_queue *)
+ (IMU_Q0_BASE + (queueid * sizeof(struct imu_queue)));
+
+ int phy_rxbase = queue_hw->rqlbar;
+ int rq_items = queue_hw->rqcr & 0xffff;
+
+ // check if overlap
+
+ for (i = 0; i < 4; i++) {
+ qi = &imu_queue[i];
+ qi_hw = (struct imu_queue *)
+ (IMU_Q0_BASE + (i * sizeof(struct imu_queue)));
+ qi_rxitems = qi_hw->rqcr & 0xffff;
+
+ if (i != queueid && // check overlap with other registered rx
+ qi->rxbase && qi->msg_size &&
+ has_overlap(phy_rxbase,
+ phy_rxbase + (rq_items * qi->msg_size),
+ (int)qi->rxbase,
+ (int)qi->rxbase +
+ (qi_rxitems * qi->msg_size))) {
+ err = 1;
+ }
+
+ if (qi->txbase && qi->msg_size && // check overlap with tx queues
+ has_overlap(phy_rxbase,
+ phy_rxbase + (rq_items * qi->msg_size),
+ (int)qi->txbase,
+ (int)qi->txbase + (qi->items * qi->msg_size))) {
+ err = 1;
+ }
+ }
+
+ if (err) {
+ printk(KERN_WARNING
+ "overlap found in IMU rx queue request 0x%x\n",
+ (int)phy_rxbase);
+ }
+
+ queue->rxbase = ioremap(phy_rxbase, rq_items * Q_MSG_SIZE);
+
+ // switch to regular callback and call
+ iop_doorbell_reg_callback(NR_IMU_DOORBELLS - 1 +
+ (IMU_DB_RQ0NE - IMU_DB_QUEUE_IRQ_OFF) +
+ (queueid * 2), queue_rq_callback);
+
+ printk
+ ("init_callback registerd q=%d rxbase=0x%x rxphy=0x%x size=0x%x\n",
+ queueid, (int)queue->rxbase, phy_rxbase, rq_items * Q_MSG_SIZE);
+ queue_rq_callback(queueid);
+}
+
+void error_callback(int queueid)
+{
+}
+
+static int imu_open(struct inode *inode, struct file *file)
+{
+ struct imu_dev *imui;
+ int queueid = iminor(file->f_dentry->d_inode);
+
+ imui = &imu[queueid];
+
+ switch (file->f_flags & O_ACCMODE) {
+ case O_RDWR:
+ if (!atomic_dec_and_test(&imui->read_available)) {
+ atomic_inc(&imui->read_available);
+ return -EBUSY;
+ }
+ if (!atomic_dec_and_test(&imui->write_available)) {
+ atomic_inc(&imui->write_available);
+ atomic_inc(&imui->read_available);
+ return -EBUSY;
+ }
+ break;
+ case O_WRONLY:
+ if (!atomic_dec_and_test(&imui->write_available)) {
+ atomic_inc(&imui->write_available);
+ return -EBUSY;
+ }
+ break;
+ case O_RDONLY:
+ if (!atomic_dec_and_test(&imui->read_available)) {
+ atomic_inc(&imui->read_available);
+ return -EBUSY;
+ }
+ break;
+
+ }
+ return 0;
+}
+
+static int imu_release(struct inode *inode, struct file *file)
+{
+ struct imu_dev *imui;
+ int queueid = iminor(file->f_dentry->d_inode);
+
+ imui = &imu[queueid];
+
+ switch (file->f_flags & O_ACCMODE) {
+ case O_RDWR:
+ atomic_inc(&imui->read_available); // fall through
+ case O_WRONLY:
+ atomic_inc(&imui->write_available);
+ break;
+ case O_RDONLY:
+ atomic_inc(&imui->read_available);
+ break;
+ }
+ return 0;
+}
+
+static ssize_t
+imu_read(struct file *file, char __user * buf, size_t count, loff_t * f_pos)
+{
+ struct imu_dev *imui;
+ char *dat;
+ int queueid = iminor(file->f_dentry->d_inode);
+
+ imui = &imu[queueid];
+
+ pr_debug("imu_read count=%d ", count);
+
+ while (1) {
+ if (imui->rq_leftover) {
+ pr_debug("%d leftover ", imui->rq_leftover);
+ count = min(count, imui->rq_leftover);
+ if (copy_to_user(buf, imui->rq_leftover_ptr, count))
+ return -EFAULT;
+ imui->rq_leftover -= count;
+ pr_debug(" %d left \n", imui->rq_leftover);
+ if (imui->rq_leftover == 0)
+ iop_queue_rxfree(queueid,
+ imui->rq_leftover_ptr);
+ imui->rq_leftover_ptr += count;
+ return count;
+ }
+
+ while (!iop_queue_rx_not_empty(queueid)) {
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ pr_debug("imu_read: empty going to sleep\n");
+
+ add_wait_queue(&imui->rq, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ iop_doorbell_enable(IMU_DB_RQ0NE + (queueid * 2));
+ schedule_timeout(IMU_WRITE_TIMEOUT);
+
+ remove_wait_queue(&imui->rq, &wait);
+ if (signal_pending(current)) {
+ return -ERESTARTSYS;
+ }
+ }
+
+ // new message
+ dat = iop_queue_getmsg(queueid);
+
+ pr_debug("imu_read: got a new message at 0x%x\n", (int)dat);
+ if (NULL == dat)
+ return -EFAULT;
+
+#if MSG_HEADER_SIZE > 0
+ imui->rq_leftover = *((int *)dat);
+#else
+ imui->rq_leftover = 4;
+#endif
+ if (imui->rq_leftover > Q_MSG_SIZE)
+ imui->rq_leftover = 0;
+
+ imui->rq_leftover_ptr = dat + MSG_HEADER_SIZE;
+
+ pr_debug("imu_read: msg size=%d\n", imui->rq_leftover);
+ if (!imui->rq_leftover)
+ iop_queue_rxfree(queueid, imui->rq_leftover_ptr);
+ }
+
+}
+static ssize_t
+imu_write(struct file *file, const char __user * buf, size_t count,
+ loff_t * f_pos)
+{
+ void *msg;
+ struct imu_dev *imui;
+ int queueid = iminor(file->f_dentry->d_inode);
+
+ imui = &imu[queueid];
+
+ count = min(count, (size_t) (Q_MSG_SIZE - MSG_HEADER_SIZE));
+
+ while (NULL == (msg = iop_queue_allocate(queueid))) {
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ pr_debug("imu_write sleeping\n");
+
+ add_wait_queue(&imui->wq, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ iop_doorbell_enable(IMU_DB_SQ0NF + (queueid * 2));
+ schedule_timeout(IMU_WRITE_TIMEOUT);
+
+ remove_wait_queue(&imui->wq, &wait);
+ if (signal_pending(current)) {
+ return -ERESTARTSYS;
+ }
+
+ }
+
+ if (copy_from_user(msg + MSG_HEADER_SIZE, buf, count))
+ return -EFAULT;
+#if MSG_HEADER_SIZE > 0
+ *((int *)msg) = count;
+#endif
+
+ iop_queue_postmsg(queueid, msg);
+
+ pr_debug("imu_write sent q=%d count=%d msg=0x%x\n", queueid, count,
+ (int)msg);
+ return count;
+}
+
+static unsigned int imu_poll(struct file *file, poll_table * wait)
+{
+ struct imu_dev *imui;
+ unsigned int mask = 0;
+ int queueid = iminor(file->f_dentry->d_inode);
+
+ imui = &imu[queueid];
+ poll_wait(file, &imui->rq, wait);
+ poll_wait(file, &imui->wq, wait);
+
+ if (iop_queue_rx_not_empty(queueid))
+ mask |= POLLIN | POLLRDNORM;
+ if (iop_queue_tx_not_full(queueid))
+ mask |= POLLOUT | POLLWRNORM;
+
+ return mask;
+}
+
+static struct file_operations imu_fops = {
+ .owner = THIS_MODULE,
+ .read = imu_read,
+ .write = imu_write,
+ .poll = imu_poll,
+ .open = imu_open,
+ .release = imu_release,
+};
+
+static int __init imu_dev_init(void)
+{
+ dev_t dev;
+ // struct class_simple *imu_class;
+ int err, i;
+ char *queue_base;
+
+ if (imu_major) {
+ dev = MKDEV(imu_major, 0);
+ err = register_chrdev_region(dev, IMU_MAX_MINORS, "imu");
+ } else {
+ err = alloc_chrdev_region(&dev, IMU_FIRST_MINOR,
+ IMU_MAX_MINORS, "imu");
+ imu_major = MAJOR(dev);
+ }
+ if (err < 0) {
+ printk(KERN_WARNING "imu: can't get major %d\n", imu_major);
+ return err;
+ }
+ //todo: update imu_class = class_simple_create(THIS_MODULE, "imu");
+
+ for (i = IMU_FIRST_MINOR; i < IMU_MAX_MINORS; i++) {
+ cdev_init(&imu[i].cdev, &imu_fops);
+ if (cdev_add(&imu[i].cdev, MKDEV(imu_major, i), 1)) {
+ printk(KERN_WARNING "Error cdev_add imu%i\n", i);
+ continue;
+ }
+
+ imu[i].rq_leftover = 0;
+ atomic_set(&imu[i].read_available, 1);
+ atomic_set(&imu[i].write_available, 1);
+ init_waitqueue_head(&imu[i].rq);
+ init_waitqueue_head(&imu[i].wq);
+ imu_queue[i].rxbase = 0;
+
+ queue_base = ioremap(Q_PHYS_BASE + (i * Q_SIZE), Q_SIZE);
+ // todo: see about changing to one of following
+ // non-shared device tex.cb = 0x010.00
+ // shared device tex.cb = 0x001.01
+
+ err = iop_queue_init(i,
+ (void *)Q_PHYS_BASE + (i * Q_SIZE),
+ queue_base,
+ Q_MSG_SIZE,
+ Q_MSG_ITEMS,
+ init_callback, error_callback);
+ if (err) {
+ printk(KERN_WARNING "could not init imu queue %d\n", i);
+ continue;
+ }
+ iop_doorbell_reg_callback(NR_IMU_DOORBELLS - 1 +
+ (IMU_DB_SQ0NF -
+ IMU_DB_QUEUE_IRQ_OFF) + (i * 2),
+ queue_wq_callback);
+ printk(KERN_INFO
+ "IMU Queue %d initialized major=%d minor=%d base=0x%x\n",
+ i, imu_major, i, (int)queue_base);
+
+ }
+
+ return 0;
+}
+
+static void __exit imu_dev_cleanup(void)
+{
+ int i;
+
+ for (i = IMU_FIRST_MINOR; i < IMU_MAX_MINORS; i++) {
+ cdev_del(&imu[i].cdev);
+ iop_doorbell_disable(IMU_DB_RQ0NE + (i * 2));
+ iop_doorbell_disable(IMU_DB_SQ0NF + (i * 2));
+ iounmap(imu_queue[i].txbase);
+ if (imu_queue[i].rxbase) {
+ iounmap(imu_queue[i].rxbase);
+ imu_queue[i].rxbase = 0;
+ }
+ }
+
+ //todo: update class_simple_device_remove(MKDEV(imu_major, 0));
+ unregister_chrdev_region(MKDEV(imu_major, 0), IMU_MAX_MINORS);
+
+ printk(KERN_INFO "%s driver ver %s removed\n",
+ MODULE_NAME, MODULE_VERS);
+}
+
+module_init(imu_dev_init);
+module_exit(imu_dev_cleanup);
+
+MODULE_AUTHOR("Greg Tucker");
+MODULE_DESCRIPTION("IMU dev interface");
diff --git a/arch/arm/mach-iop13xx/imu/imu.c b/arch/arm/mach-iop13xx/imu/imu.c
new file mode 100644
index 0000000..6626486
--- /dev/null
+++ b/arch/arm/mach-iop13xx/imu/imu.c
@@ -0,0 +1,151 @@
+/*
+ * arch/arm/mach-iop13xx/imu/iop1340-imu.c
+ *
+ * Support for IMU communication for the Intel IOP1340 chipset
+ *
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Greg Tucker <greg.b.tucker@intel.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/reboot.h>
+#include <linux/unistd.h> /* for execve */
+#include <asm/arch/iop13xx-imu.h>
+
+extern imu_handler *imu_irq_table[];
+extern struct imu_queue_params imu_queue[];
+
+static irqreturn_t imu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned int doorbell, queue;
+ unsigned int dbcr = *(volatile int *)IMU_DBCR;
+
+ pr_debug("got imu interrupt. IMU_DBCR=0x%x\n", dbcr);
+
+ do {
+ doorbell = dbcr >> 28;
+ queue = (dbcr >> 24) & 0xf;
+
+ if (doorbell != 0xf && imu_irq_table[doorbell]) {
+ imu_irq_table[doorbell] (doorbell);
+ *(volatile int *)IMU_DBCR = 1 << doorbell; // clear status
+ }
+
+ if (queue != 0xf
+ && imu_irq_table[(NR_IMU_DOORBELLS - 1) + queue])
+ imu_irq_table[(NR_IMU_DOORBELLS - 1) +
+ queue] (queue / 2);
+
+ dbcr = *(volatile int *)IMU_DBCR;
+
+ } while ((dbcr >> 24) != 0xff);
+
+ return IRQ_HANDLED;
+}
+
+static void deferred_reset(void *dummy)
+{
+ static int in_shutdown = 0;
+ static char *envp[] = {
+ "HOME=/", "TERM=linux",
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL
+ };
+ char *argv[] = {
+ "/sbin/shutdown", "-r", "now", NULL
+ };
+
+ // todo: start watchdog timer
+
+ if (!in_shutdown) {
+ in_shutdown = 1;
+ printk(KERN_CRIT "IMU reset: Shutting down the system now.\n");
+ if (0 > execve("/sbin/shutdown", argv, envp))
+ printk("IMU reset: Could not use /sbin/shutdown\n");
+ else
+ return;
+ }
+
+ printk("IMU reset: Starting hard reset\n");
+ //emergency_sync();
+ //kill_proc(1, SIGINT, 1);
+ kernel_restart(NULL);
+}
+
+void restart_callback(int irq)
+{
+ static DECLARE_WORK(reset_work, deferred_reset, NULL);
+
+ printk("\nIMU reset: Got restart doorbell\n");
+ schedule_work(&reset_work);
+ return;
+}
+
+static int __init iop_imu_init(void)
+{
+ int i, err;
+
+ for (i = 0; i < NR_IMU_DOORBELLS + NR_IMU_QUEUE_IRQS; i++)
+ imu_irq_table[i] = 0;
+
+ err = request_irq(IRQ_IOP13XX_IMU, imu_interrupt,
+ SA_INTERRUPT, "imu interrupt", NULL);
+
+ iop_doorbell_reg_callback(IMU_RESET_DOORBELL, restart_callback);
+ iop_doorbell_enable(IMU_RESET_DOORBELL);
+
+ printk(KERN_INFO "IOP 8134x IMU driver\n");
+ return err;
+}
+
+static void __exit iop_imu_exit(void)
+{
+ free_irq(IRQ_IOP13XX_IMU, NULL);
+ return;
+}
+
+EXPORT_SYMBOL(iop_doorbell_ring);
+EXPORT_SYMBOL(iop_wait_on_doorbell);
+EXPORT_SYMBOL(iop_doorbell_clear_status);
+EXPORT_SYMBOL(iop_doorbell_check_status);
+EXPORT_SYMBOL(iop_doorbell_enable);
+EXPORT_SYMBOL(iop_doorbell_disable);
+EXPORT_SYMBOL(iop_doorbell_mask);
+EXPORT_SYMBOL(iop_doorbell_unmask);
+EXPORT_SYMBOL(iop_doorbell_reg_callback);
+EXPORT_SYMBOL(iop_mutex_lock);
+EXPORT_SYMBOL(iop_mutex_trylock);
+EXPORT_SYMBOL(iop_mutex_unlock);
+EXPORT_SYMBOL(iop_queue_init);
+EXPORT_SYMBOL(iop_queue_allocate);
+EXPORT_SYMBOL(iop_queue_postmsg);
+
+EXPORT_SYMBOL(iop_queue_getmsg);
+EXPORT_SYMBOL(iop_queue_rxfree);
+EXPORT_SYMBOL(iop_queue_rx_not_empty);
+EXPORT_SYMBOL(iop_queue_tx_not_full);
+
+EXPORT_SYMBOL(imu_queue);
+
+module_init(iop_imu_init);
+module_exit(iop_imu_exit);
+
+MODULE_AUTHOR("Greg Tucker");
+MODULE_DESCRIPTION("IMU interface");
diff --git a/include/asm-arm/arch-iop13xx/iop13xx-imu.h b/include/asm-arm/arch-iop13xx/iop13xx-imu.h
new file mode 100644
index 0000000..f7ecd6a
--- /dev/null
+++ b/include/asm-arm/arch-iop13xx/iop13xx-imu.h
@@ -0,0 +1,207 @@
+/*
+ * include/asm-arm/arch-iop13xx/iop1340-imu.h
+ *
+ * IMU hardware support on IOP342
+ *
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Greg Tucker <greg.b.tucker@intel.com>
+ *
+ */
+
+#ifndef IOP34X_H
+#define IOP34X_H
+
+#ifndef NULL
+# define NULL (void *) 0
+#endif
+
+typedef int imu_handler(int);
+
+void iop_mutex_lock(int mutex);
+int iop_mutex_trylock(int mutex);
+void iop_mutex_unlock(int mutex);
+
+int iop_queue_init(int queueid, void *phys_base, void *vert_base,
+ int msg_size, int num_items,
+ void (*rcd_callback) (int), void (*error_callback) (int));
+void *iop_queue_allocate(int queueid);
+int iop_queue_postmsg(int queueid, void *msg_adr);
+
+int iop_doorbell_reg_callback(int doorbell, void (*callback) (int));
+void iop_doorbell_clear_status(int doorbell);
+int iop_doorbell_check_status(int doorbell);
+void iop_doorbell_enable(int doorbell);
+void iop_doorbell_disable(int doorbell);
+void iop_doorbell_mask(int doorbell);
+void iop_doorbell_unmask(int doorbell);
+void iop_doorbell_ring(int doorbell);
+inline void iop_wait_on_doorbell(int doorbell);
+
+void *iop_queue_getmsg(int queueid);
+int iop_queue_rxfree(int queueid, void *msg_adr);
+int iop_queue_rx_not_empty(int queueid);
+int iop_queue_tx_not_full(int queueid);
+
+/* Core ID - CIDR */
+
+#define CIDR_READ() \
+ ({unsigned _val_; asm volatile("mrc\tp6, 0, %0, c0, c0, 0" : "=r" (_val_)); _val_;})
+#define COREID0 0
+#define COREID1 1
+
+/* --------------------------------------------------------------------------
+ * IMU/IMM registers
+ */
+
+/* Reset cause status - RCSR */
+
+#define RCSR_READ() \
+ ({unsigned _val_; asm volatile("mrc\tp6, 0, %0, c0, c1, 0" : "=r" (_val_));_val_;})
+#define RCSR_MU_RESET (1<<21)
+#define RCSR_TMPI3_RESET (1<<18)
+#define RCSR_TMPI2_RESET (1<<15)
+#define RCSR_TMPI1_RESET (1<<12)
+#define RCSR_TMPI0_RESET (1<<9)
+#define RCSR_WATCHDOG_RESET (1<<5)
+#define RCSR_TARGETED_RESET (1<<4)
+#define RCSR_ID_RESET_MASK (0xf)
+#define RCSR_SYSTEM_RESET_MASK (RCSR_MU_RESET | RCSR_TARGETED_RESET | RCSR_TMPI3_RESET | \
+ RCSR_TMPI2_RESET | RCSR_TMPI1_RESET | RCSR_TMPI0_RESET | \
+ RCSR_WATCHDOG_RESET | RCSR_TARGETED_RESET)
+
+/* #define is_sys_reset() ((RCSR_READ() & RCSR_SYSTEM_RESET_MASK) == 0) currently not working in simulator */
+#define is_sys_reset() 1
+
+/* Software Interrupt Generation Register - SINTGENR */
+
+#define SINTGENR_READ() \
+ ({ unsigned _val_;asm volatile("mrc\tp6, 0, %0, c1, c1, 0" : "=r" (_val_));_val_;})
+#define SINTGENR_WRITE(val) \
+ ({ asm volatile("mcr\tp6, 0, %0, c1, c1, 0" : : "r" (val)); })
+
+/* Targeted Reset Register - TARRSTR */
+
+# define TARRSTR_WRITE(val) \
+ ({ asm volatile("mcr\tp6, 0, %0, c2, c1, 0" : : "r" (val)); })
+
+#ifdef linux
+# define IMU_BASE IOP13XX_PMMR_VIRT_MEM_BASE
+#else
+# define IMU_BASE 0xffd80000
+#endif
+
+/* IMU doorbell registers */
+
+#define IMU_DBCR (IMU_BASE+0xa00)
+#define IMU_DBER (IMU_BASE+0xa04)
+#define IMU_DBAR (IMU_BASE+0xa10)
+#define IMU_DBEOR (IMU_BASE+0xa14)
+#define NR_IMU_DOORBELLS 14
+
+/* Conventions on doorbell use */
+
+#define IMU_RESET_DOORBELL 3
+
+/* IMU send queue */
+
+#define IMU_Q0_BASE (IMU_BASE+0xa20)
+#define IMU_Q1_BASE (IMU_BASE+0xa40)
+#define IMU_Q2_BASE (IMU_BASE+0xa60)
+#define IMU_Q3_BASE (IMU_BASE+0xa80)
+
+#define IMU_SQPG0 (IMU_Q0_BASE+0x0)
+#define IMU_SQCR0 (IMU_Q0_BASE+0x4)
+#define IMU_SQLBAR0 (IMU_Q0_BASE+0x8)
+#define IMU_SQUBAR0 (IMU_Q0_BASE+0xc)
+#define IMU_RQPG0 (IMU_Q0_BASE+0x10)
+#define IMU_RQCR0 (IMU_Q0_BASE+0x14)
+#define IMU_RQLBAR0 (IMU_Q0_BASE+0x18)
+#define IMU_RQUBAR0 (IMU_Q0_BASE+0x1c)
+
+#define IMU_SQPG1 (IMU_Q1_BASE+0x0)
+#define IMU_SQCR1 (IMU_Q1_BASE+0x4)
+#define IMU_SQLBAR1 (IMU_Q1_BASE+0x8)
+#define IMU_SQUBAR1 (IMU_Q1_BASE+0xc)
+#define IMU_RQPG1 (IMU_Q1_BASE+0x10)
+#define IMU_RQCR1 (IMU_Q1_BASE+0x14)
+#define IMU_RQLBAR1 (IMU_Q1_BASE+0x18)
+#define IMU_RQUBAR1 (IMU_Q1_BASE+0x1c)
+
+#define IMU_SQPG2 (IMU_Q2_BASE+0x0)
+#define IMU_SQCR2 (IMU_Q2_BASE+0x4)
+#define IMU_SQLBAR2 (IMU_Q2_BASE+0x8)
+#define IMU_SQUBAR2 (IMU_Q2_BASE+0xc)
+#define IMU_RQPG2 (IMU_Q2_BASE+0x10)
+#define IMU_RQCR2 (IMU_Q2_BASE+0x14)
+#define IMU_RQLBAR2 (IMU_Q2_BASE+0x18)
+#define IMU_RQUBAR2 (IMU_Q2_BASE+0x1c)
+
+#define IMU_SQPG3 (IMU_Q3_BASE+0x0)
+#define IMU_SQCR3 (IMU_Q3_BASE+0x4)
+#define IMU_SQLBAR3 (IMU_Q3_BASE+0x8)
+#define IMU_SQUBAR3 (IMU_Q3_BASE+0xc)
+#define IMU_RQPG3 (IMU_Q3_BASE+0x10)
+#define IMU_RQCR3 (IMU_Q3_BASE+0x14)
+#define IMU_RQLBAR3 (IMU_Q3_BASE+0x18)
+#define IMU_RQUBAR3 (IMU_Q3_BASE+0x1c)
+#define NR_IMU_QUEUES 3
+
+/* IMU queue interrupts */
+
+#define IMU_DB_SQ0NF 16
+#define IMU_DB_RQ0NE 17
+#define IMU_DB_SQ1NF 18
+#define IMU_DB_RQ1NE 19
+#define IMU_DB_SQ2NF 20
+#define IMU_DB_RQ2NE 21
+#define IMU_DB_SQ3NF 22
+#define IMU_DB_RQ3NE 23
+#define IMU_DB_QUEUE_IRQ_OFF 16
+#define NR_IMU_QUEUE_IRQS 8
+
+#ifndef __ASSEMBLER__
+struct imu_queue {
+ unsigned int sqpg; /* Send queue put/get register */
+ unsigned int sqcr; /* Send queue control register */
+ unsigned int sqlbar; /* Send queue lower base address reg */
+ unsigned int squbar; /* Send queue upper base address reg */
+ unsigned int rqpg; /* Receive queue put/get register */
+ unsigned int rqcr; /* Receive queue control register */
+ unsigned int rqlbar; /* Receive queue lower base address reg */
+ unsigned int rqubar; /* Receive queue upper base address reg */
+};
+
+struct imu_queue_params {
+ void *txbase;
+ void *rxbase;
+ int alloc;
+ int msg_size;
+ int items;
+};
+#endif
+
+/* Test and set semaphore registers */
+
+#define IMU_TSR_BASE (IMU_BASE+0xb00)
+#define IMU_TSR(x) ((volatile char*)(IMU_TSR_BASE+x))
+
+/* Some conventions on the semaphores */
+
+#define HW_MUTEX_FLASH_READ_CORE0 0
+#define HW_MUTEX_FLASH_READ_CORE1 1
+
+#endif /* IOP34X_H */
next prev parent reply other threads:[~2007-01-24 18:24 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-01-24 18:22 [PATCH RFC 0/2] imu-scsi for iop13xx dan.j.williams
2007-01-24 18:24 ` Dan Williams [this message]
2007-01-24 18:24 ` [PATCH RFC 2/2] iop13xx: imu scsi driver Dan Williams
2007-01-25 21:15 ` James Bottomley
2007-01-26 7:03 ` Tucker, Greg B
2007-01-25 21:15 ` [PATCH RFC 0/2] imu-scsi for iop13xx James Bottomley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070124182416.6029.41466.stgit@dwillia2-linux.ch.intel.com \
--to=dan.j.williams@intel.com \
--cc=James.Bottomley@steeleye.com \
--cc=greg.b.tucker@intel.com \
--cc=linux-arm-kernel@lists.arm.linux.org.uk \
--cc=linux-scsi@vger.kernel.org \
--cc=linux@arm.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox