mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-30 04:05:55 +02:00
ae9c0f20fa
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@1526 3c298f89-4303-0410-b956-a3cf2f4a3e73
2317 lines
84 KiB
Diff
2317 lines
84 KiB
Diff
diff -urN linux.old/drivers/char/avalanche_vlynq/Makefile linux.dev/drivers/char/avalanche_vlynq/Makefile
|
|
--- linux.old/drivers/char/avalanche_vlynq/Makefile 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux.dev/drivers/char/avalanche_vlynq/Makefile 2005-07-22 06:32:53.345189608 +0200
|
|
@@ -0,0 +1,14 @@
|
|
+#
|
|
+# Makefile for the linux kernel.
|
|
+#
|
|
+# Note! Dependencies are done automagically by 'make dep', which also
|
|
+# removes any old dependencies. DON'T put your own dependencies here
|
|
+# unless it's something special (ie not a .c file).
|
|
+#
|
|
+# Note 2! The CFLAGS definitions are now in the main makefile...
|
|
+
|
|
+O_TARGET := avalanche_vlynq.o
|
|
+
|
|
+obj-y += vlynq_drv.o vlynq_hal.o vlynq_board.o
|
|
+
|
|
+include $(TOPDIR)/Rules.make
|
|
diff -urN linux.old/drivers/char/avalanche_vlynq/vlynq_board.c linux.dev/drivers/char/avalanche_vlynq/vlynq_board.c
|
|
--- linux.old/drivers/char/avalanche_vlynq/vlynq_board.c 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux.dev/drivers/char/avalanche_vlynq/vlynq_board.c 2005-07-22 06:34:39.448059520 +0200
|
|
@@ -0,0 +1,182 @@
|
|
+/*
|
|
+ * Jeff Harrell, jharrell@ti.com
|
|
+ * Copyright (C) 2001 Texas Instruments, Inc. All rights reserved.
|
|
+ *
|
|
+ * This program is free software; you can distribute it and/or modify it
|
|
+ * under the terms 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.
|
|
+ *
|
|
+ * Texas Instruments Sangam specific setup.
|
|
+ */
|
|
+#include <linux/config.h>
|
|
+#include <asm/ar7/sangam.h>
|
|
+#include <asm/ar7/avalanche_misc.h>
|
|
+#include <asm/ar7/vlynq.h>
|
|
+
|
|
+#define SYS_VLYNQ_LOCAL_INTERRUPT_VECTOR 30 /* MSB - 1 bit */
|
|
+#define SYS_VLYNQ_REMOTE_INTERRUPT_VECTOR 31 /* MSB bit */
|
|
+#define SYS_VLYNQ_OPTIONS 0x7F; /* all options*/
|
|
+
|
|
+/* These defines are board specific */
|
|
+
|
|
+
|
|
+#define VLYNQ0_REMOTE_WINDOW1_OFFSET (0x0C000000)
|
|
+#define VLYNQ0_REMOTE_WINDOW1_SIZE (0x500)
|
|
+
|
|
+
|
|
+#define VLYNQ1_REMOTE_WINDOW1_OFFSET (0x0C000000)
|
|
+#define VLYNQ1_REMOTE_WINDOW1_SIZE (0x500)
|
|
+
|
|
+
|
|
+extern VLYNQ_DEV vlynqDevice0, vlynqDevice1;
|
|
+int vlynq_init_status[2] = {0, 0};
|
|
+static int reset_hack = 1;
|
|
+
|
|
+void vlynq_ar7wrd_dev_init()
|
|
+{
|
|
+ *(unsigned long*) AVALANCHE_GPIO_ENBL |= (1<<18);
|
|
+ vlynq_delay(20000);
|
|
+ *(unsigned long*) AVALANCHE_GPIO_DIR &= ~(1<<18);
|
|
+ vlynq_delay(20000);
|
|
+ *(unsigned long*) AVALANCHE_GPIO_DATA_OUT&= ~(1<<18);
|
|
+ vlynq_delay(50000);
|
|
+ *(unsigned long*) AVALANCHE_GPIO_DATA_OUT|= (1<<18);
|
|
+ vlynq_delay(50000);
|
|
+
|
|
+ /* Initialize the MIPS host vlynq driver for a given vlynq interface */
|
|
+ vlynqDevice0.dev_idx = 0; /* first vlynq module - this parameter is for reference only */
|
|
+ vlynqDevice0.module_base = AVALANCHE_LOW_VLYNQ_CONTROL_BASE; /* vlynq0 module base address */
|
|
+
|
|
+#if defined(CONFIG_VLYNQ_CLK_LOCAL)
|
|
+ vlynqDevice0.clk_source = VLYNQ_CLK_SOURCE_LOCAL;
|
|
+#else
|
|
+ vlynqDevice0.clk_source = VLYNQ_CLK_SOURCE_REMOTE;
|
|
+#endif
|
|
+ vlynqDevice0.clk_div = 0x01; /* board/hardware specific */
|
|
+ vlynqDevice0.state = VLYNQ_DRV_STATE_UNINIT; /* uninitialized module */
|
|
+
|
|
+ /* Populate vlynqDevice0.local_mem & Vlynq0.remote_mem based on system configuration */
|
|
+ /*Local memory configuration */
|
|
+
|
|
+ /* Demiurg : not good !*/
|
|
+#if 0
|
|
+ vlynqDevice0.local_mem.Txmap= AVALANCHE_LOW_VLYNQ_MEM_MAP_BASE & ~(0xc0000000) ; /* physical address */
|
|
+ vlynqDevice0.remote_mem.RxOffset[0]= VLYNQ0_REMOTE_WINDOW1_OFFSET; /* This is specific to the board on the other end */
|
|
+ vlynqDevice0.remote_mem.RxSize[0]=VLYNQ0_REMOTE_WINDOW1_SIZE;
|
|
+#endif
|
|
+
|
|
+ /* Demiurg : This is how it should be ! */
|
|
+ vlynqDevice0.local_mem.Txmap = PHYSADDR(AVALANCHE_LOW_VLYNQ_MEM_MAP_BASE);
|
|
+#define VLYNQ_ACX111_MEM_OFFSET 0xC0000000 /* Physical address of ACX111 memory */
|
|
+#define VLYNQ_ACX111_MEM_SIZE 0x00040000 /* Total size of the ACX111 memory */
|
|
+#define VLYNQ_ACX111_REG_OFFSET 0xF0000000 /* PHYS_ADDR of ACX111 control registers */
|
|
+#define VLYNQ_ACX111_REG_SIZE 0x00022000 /* Size of ACX111 registers area, MAC+PHY */
|
|
+#define ACX111_VL1_REMOTE_SIZE 0x1000000
|
|
+ vlynqDevice0.remote_mem.RxOffset[0] = VLYNQ_ACX111_MEM_OFFSET;
|
|
+ vlynqDevice0.remote_mem.RxSize[0] = VLYNQ_ACX111_MEM_SIZE ;
|
|
+ vlynqDevice0.remote_mem.RxOffset[1] = VLYNQ_ACX111_REG_OFFSET;
|
|
+ vlynqDevice0.remote_mem.RxSize[1] = VLYNQ_ACX111_REG_SIZE ;
|
|
+ vlynqDevice0.remote_mem.Txmap = 0;
|
|
+ vlynqDevice0.local_mem.RxOffset[0] = AVALANCHE_SDRAM_BASE;
|
|
+ vlynqDevice0.local_mem.RxSize[0] = ACX111_VL1_REMOTE_SIZE;
|
|
+
|
|
+
|
|
+ /* Local interrupt configuration */
|
|
+ vlynqDevice0.local_irq.intLocal = VLYNQ_INT_LOCAL; /* Host handles vlynq interrupts*/
|
|
+ vlynqDevice0.local_irq.intRemote = VLYNQ_INT_ROOT_ISR; /* vlynq root isr used */
|
|
+ vlynqDevice0.local_irq.map_vector = SYS_VLYNQ_LOCAL_INTERRUPT_VECTOR;
|
|
+ vlynqDevice0.local_irq.intr_ptr = 0; /* Since remote interrupts part of vlynq root isr this is unused */
|
|
+
|
|
+ /* Remote interrupt configuration */
|
|
+ vlynqDevice0.remote_irq.intLocal = VLYNQ_INT_REMOTE; /* MIPS handles interrupts */
|
|
+ vlynqDevice0.remote_irq.intRemote = VLYNQ_INT_ROOT_ISR; /* Not significant since MIPS handles interrupts */
|
|
+ vlynqDevice0.remote_irq.map_vector = SYS_VLYNQ_REMOTE_INTERRUPT_VECTOR;
|
|
+ vlynqDevice0. remote_irq.intr_ptr = AVALANCHE_INTC_BASE; /* Not significant since MIPS handles interrupts */
|
|
+
|
|
+ if(reset_hack != 1)
|
|
+ printk("About to re-init the VLYNQ.\n");
|
|
+
|
|
+ if(vlynq_init(&vlynqDevice0,VLYNQ_INIT_PERFORM_ALL)== 0)
|
|
+ {
|
|
+ /* Suraj added the following to keep the 1130 going. */
|
|
+ vlynq_interrupt_vector_set(&vlynqDevice0, 0 /* intr vector line running into 1130 vlynq */,
|
|
+ 0 /* intr mapped onto the interrupt register on remote vlynq and this vlynq */,
|
|
+ VLYNQ_REMOTE_DVC, 0 /* polarity active high */, 0 /* interrupt Level triggered */);
|
|
+
|
|
+ /* System wide interrupt is 80 for 1130, please note. */
|
|
+ vlynq_init_status[0] = 1;
|
|
+ reset_hack = 2;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if(reset_hack == 1)
|
|
+ printk("VLYNQ INIT FAILED: Please try cold reboot. \n");
|
|
+ else
|
|
+ printk("Failed to initialize the VLYNQ interface at insmod.\n");
|
|
+
|
|
+ }
|
|
+}
|
|
+
|
|
+void vlynq_dev_init(void)
|
|
+{
|
|
+ volatile unsigned int *reset_base = (unsigned int *) AVALANCHE_RESET_CONTROL_BASE;
|
|
+
|
|
+ *reset_base &= ~((1 << AVALANCHE_LOW_VLYNQ_RESET_BIT)); /* | (1 << AVALANCHE_HIGH_VLYNQ_RESET_BIT)); */
|
|
+
|
|
+ vlynq_delay(20000);
|
|
+
|
|
+ /* Bring vlynq out of reset if not already done */
|
|
+ *reset_base |= (1 << AVALANCHE_LOW_VLYNQ_RESET_BIT); /* | (1 << AVALANCHE_HIGH_VLYNQ_RESET_BIT); */
|
|
+ vlynq_delay(20000); /* Allowing sufficient time to VLYNQ to settle down.*/
|
|
+
|
|
+ vlynq_ar7wrd_dev_init( );
|
|
+
|
|
+}
|
|
+
|
|
+/* This function is board specific and should be ported for each board. */
|
|
+void remote_vlynq_dev_reset_ctrl(unsigned int module_reset_bit,
|
|
+ AVALANCHE_RESET_CTRL_T reset_ctrl)
|
|
+{
|
|
+ if(module_reset_bit >= 32)
|
|
+ return;
|
|
+
|
|
+ switch(module_reset_bit)
|
|
+ {
|
|
+ case 0:
|
|
+ if(OUT_OF_RESET == reset_ctrl)
|
|
+ {
|
|
+ if(reset_hack) return;
|
|
+
|
|
+ vlynq_delay(20000);
|
|
+ printk("Un-resetting the remote device.\n");
|
|
+ vlynq_dev_init();
|
|
+ printk("Re-initialized the VLYNQ.\n");
|
|
+ reset_hack = 2;
|
|
+ }
|
|
+ else if(IN_RESET == reset_ctrl)
|
|
+ {
|
|
+ *(unsigned long*) AVALANCHE_GPIO_DATA_OUT &= ~(1<<18);
|
|
+
|
|
+ vlynq_delay(20000);
|
|
+ printk("Resetting the remote device.\n");
|
|
+ reset_hack = 0;
|
|
+ }
|
|
+ else
|
|
+ ;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+
|
|
+ }
|
|
+}
|
|
+
|
|
diff -urN linux.old/drivers/char/avalanche_vlynq/vlynq_drv.c linux.dev/drivers/char/avalanche_vlynq/vlynq_drv.c
|
|
--- linux.old/drivers/char/avalanche_vlynq/vlynq_drv.c 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux.dev/drivers/char/avalanche_vlynq/vlynq_drv.c 2005-07-22 06:32:53.345189608 +0200
|
|
@@ -0,0 +1,242 @@
|
|
+/******************************************************************************
|
|
+ * FILE PURPOSE: Vlynq Linux Device Driver Source
|
|
+ ******************************************************************************
|
|
+ * FILE NAME: vlynq_drv.c
|
|
+ *
|
|
+ * DESCRIPTION: Vlynq Linux Device Driver Source
|
|
+ *
|
|
+ * REVISION HISTORY:
|
|
+ *
|
|
+ * Date Description Author
|
|
+ *-----------------------------------------------------------------------------
|
|
+ * 17 July 2003 Initial Creation Anant Gole
|
|
+ * 17 Dec 2003 Updates Sharath Kumar
|
|
+ *
|
|
+ * (C) Copyright 2003, Texas Instruments, Inc
|
|
+ *******************************************************************************/
|
|
+
|
|
+#include <linux/config.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/miscdevice.h>
|
|
+#include <linux/smp_lock.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/proc_fs.h>
|
|
+#include <linux/capability.h>
|
|
+#include <asm/ar7/avalanche_intc.h>
|
|
+#include <asm/ar7/sangam.h>
|
|
+#include <asm/ar7/vlynq.h>
|
|
+
|
|
+
|
|
+#define TI_VLYNQ_VERSION "0.2"
|
|
+
|
|
+/* debug on ? */
|
|
+#define VLYNQ_DEBUG
|
|
+
|
|
+/* Macro for debug and error printf's */
|
|
+#ifdef VLYNQ_DEBUG
|
|
+#define DBGPRINT printk
|
|
+#else
|
|
+#define DBGPRINT(x)
|
|
+#endif
|
|
+
|
|
+#define ERRPRINT printk
|
|
+
|
|
+/* Define the max vlynq ports this driver will support.
|
|
+ Device name strings are statically added here */
|
|
+#define MAX_VLYNQ_PORTS 2
|
|
+
|
|
+
|
|
+/* Type define for VLYNQ private structure */
|
|
+typedef struct vlynqPriv{
|
|
+ int irq;
|
|
+ VLYNQ_DEV *vlynqDevice;
|
|
+}VLYNQ_PRIV;
|
|
+
|
|
+extern int vlynq_init_status[2];
|
|
+
|
|
+/* Extern Global variable for vlynq devices used in initialization of the vlynq device
|
|
+ * These variables need to be populated/initialized by the system as part of initialization
|
|
+ * process. The vlynq enumerator can run at initialization and populate these globals
|
|
+ */
|
|
+
|
|
+VLYNQ_DEV vlynqDevice0;
|
|
+VLYNQ_DEV vlynqDevice1;
|
|
+
|
|
+/* Defining dummy macro AVALANCHE_HIGH_VLYNQ_INT to take
|
|
+ * care of compilation in case of single vlynq device
|
|
+ */
|
|
+
|
|
+#ifndef AVALANCHE_HIGH_VLYNQ_INT
|
|
+#define AVALANCHE_HIGH_VLYNQ_INT 0
|
|
+#endif
|
|
+
|
|
+
|
|
+
|
|
+/* vlynq private object */
|
|
+VLYNQ_PRIV vlynq_priv[CONFIG_AR7_VLYNQ_PORTS] = {
|
|
+ { LNXINTNUM(AVALANCHE_LOW_VLYNQ_INT),&vlynqDevice0},
|
|
+ { LNXINTNUM(AVALANCHE_HIGH_VLYNQ_INT),&vlynqDevice1},
|
|
+};
|
|
+
|
|
+extern void vlynq_dev_init(void);
|
|
+
|
|
+
|
|
+/* =================================== all the operations */
|
|
+
|
|
+static int
|
|
+vlynq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct file_operations vlynq_fops = {
|
|
+ owner: THIS_MODULE,
|
|
+ ioctl: vlynq_ioctl,
|
|
+};
|
|
+
|
|
+/* Vlynq device object */
|
|
+static struct miscdevice vlynq_dev [MAX_VLYNQ_PORTS] = {
|
|
+ { MISC_DYNAMIC_MINOR , "vlynq0", &vlynq_fops },
|
|
+ { MISC_DYNAMIC_MINOR , "vlynq1", &vlynq_fops },
|
|
+};
|
|
+
|
|
+
|
|
+/* Proc read function */
|
|
+static int
|
|
+vlynq_read_link_proc(char *buf, char **start, off_t offset, int count, int *eof, void *unused)
|
|
+{
|
|
+ int instance;
|
|
+ int len = 0;
|
|
+
|
|
+ len += sprintf(buf +len,"VLYNQ Devices : %d\n",CONFIG_AR7_VLYNQ_PORTS);
|
|
+
|
|
+ for(instance =0;instance < CONFIG_AR7_VLYNQ_PORTS;instance++)
|
|
+ {
|
|
+ int link_state;
|
|
+ char *link_msg[] = {" DOWN "," UP "};
|
|
+
|
|
+ if(vlynq_init_status[instance] == 0)
|
|
+ link_state = 0;
|
|
+
|
|
+ else if (vlynq_link_check(vlynq_priv[instance].vlynqDevice))
|
|
+ link_state = 1;
|
|
+
|
|
+ else
|
|
+ link_state = 0;
|
|
+
|
|
+ len += sprintf(buf + len, "VLYNQ %d: Link state: %s\n",instance,link_msg[link_state]);
|
|
+
|
|
+ }
|
|
+ /* Print info about vlynq device 1 */
|
|
+
|
|
+ return len;
|
|
+}
|
|
+
|
|
+
|
|
+/* Proc function to display driver version */
|
|
+static int
|
|
+vlynq_read_ver_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data)
|
|
+{
|
|
+ int instance;
|
|
+ int len=0;
|
|
+
|
|
+ len += sprintf(buf +len,"\nTI Linux VLYNQ Driver Version %s\n",TI_VLYNQ_VERSION);
|
|
+ return len;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+/* Wrapper for vlynq ISR */
|
|
+static void lnx_vlynq_root_isr(int irq, void * arg, struct pt_regs *regs)
|
|
+{
|
|
+ vlynq_root_isr(arg);
|
|
+}
|
|
+
|
|
+/* =================================== init and cleanup */
|
|
+
|
|
+int vlynq_init_module(void)
|
|
+{
|
|
+ int ret;
|
|
+ int unit = 0;
|
|
+ int instance_count = CONFIG_AR7_VLYNQ_PORTS;
|
|
+ volatile int *ptr;
|
|
+
|
|
+ vlynq_dev_init();
|
|
+
|
|
+ DBGPRINT("Vlynq CONFIG_AR7_VLYNQ_PORTS=%d\n", CONFIG_AR7_VLYNQ_PORTS);
|
|
+ /* If num of configured vlynq ports > supported by driver return error */
|
|
+ if (instance_count > MAX_VLYNQ_PORTS)
|
|
+ {
|
|
+ ERRPRINT("ERROR: vlynq_init_module(): Max %d supported\n", MAX_VLYNQ_PORTS);
|
|
+ return (-1);
|
|
+ }
|
|
+
|
|
+ /* register the misc device */
|
|
+ for (unit = 0; unit < CONFIG_AR7_VLYNQ_PORTS; unit++)
|
|
+ {
|
|
+ ret = misc_register(&vlynq_dev[unit]);
|
|
+
|
|
+ if(ret < 0)
|
|
+ {
|
|
+ ERRPRINT("ERROR:Could not register vlynq device:%d\n",unit);
|
|
+ continue;
|
|
+ }
|
|
+ else
|
|
+ DBGPRINT("Vlynq Device %s registered with minor no %d as misc device. Result=%d\n",
|
|
+ vlynq_dev[unit].name, vlynq_dev[unit].minor, ret);
|
|
+#if 0
|
|
+
|
|
+ DBGPRINT("Calling vlynq init\n");
|
|
+
|
|
+ /* Read the global variable for VLYNQ device structure and initialize vlynq driver */
|
|
+ ret = vlynq_init(vlynq_priv[unit].vlynqDevice,VLYNQ_INIT_PERFORM_ALL );
|
|
+#endif
|
|
+
|
|
+ if(vlynq_init_status[unit] == 0)
|
|
+ {
|
|
+ printk("VLYNQ %d : init failed\n",unit);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Check link before proceeding */
|
|
+ if (!vlynq_link_check(vlynq_priv[unit].vlynqDevice))
|
|
+ {
|
|
+ DBGPRINT("\nError: Vlynq link not available.trying once before Exiting");
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ DBGPRINT("Vlynq instance:%d Link UP\n",unit);
|
|
+
|
|
+ /* Install the vlynq local root ISR */
|
|
+ request_irq(vlynq_priv[unit].irq,lnx_vlynq_root_isr,0,vlynq_dev[unit].name,vlynq_priv[unit].vlynqDevice);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Creating proc entry for the devices */
|
|
+ create_proc_read_entry("avalanche/vlynq_link", 0, NULL, vlynq_read_link_proc, NULL);
|
|
+ create_proc_read_entry("avalanche/vlynq_ver", 0, NULL, vlynq_read_ver_proc, NULL);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void vlynq_cleanup_module(void)
|
|
+{
|
|
+ int unit = 0;
|
|
+
|
|
+ for (unit = 0; unit < CONFIG_AR7_VLYNQ_PORTS; unit++)
|
|
+ {
|
|
+ DBGPRINT("vlynq_cleanup_module(): Unregistring misc device %s\n",vlynq_dev[unit].name);
|
|
+ misc_deregister(&vlynq_dev[unit]);
|
|
+ }
|
|
+
|
|
+ remove_proc_entry("avalanche/vlynq_link", NULL);
|
|
+ remove_proc_entry("avalanche/vlynq_ver", NULL);
|
|
+}
|
|
+
|
|
+
|
|
+module_init(vlynq_init_module);
|
|
+module_exit(vlynq_cleanup_module);
|
|
+
|
|
diff -urN linux.old/drivers/char/avalanche_vlynq/vlynq_hal.c linux.dev/drivers/char/avalanche_vlynq/vlynq_hal.c
|
|
--- linux.old/drivers/char/avalanche_vlynq/vlynq_hal.c 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux.dev/drivers/char/avalanche_vlynq/vlynq_hal.c 2005-07-22 06:32:53.359187480 +0200
|
|
@@ -0,0 +1,1214 @@
|
|
+/***************************************************************************
|
|
+**+----------------------------------------------------------------------+**
|
|
+**| **** |**
|
|
+**| **** |**
|
|
+**| ******o*** |**
|
|
+**| ********_///_**** |**
|
|
+**| ***** /_//_/ **** |**
|
|
+**| ** ** (__/ **** |**
|
|
+**| ********* |**
|
|
+**| **** |**
|
|
+**| *** |**
|
|
+**| |**
|
|
+**| Copyright (c) 2003 Texas Instruments Incorporated |**
|
|
+**| ALL RIGHTS RESERVED |**
|
|
+**| |**
|
|
+**| Permission is hereby granted to licensees of Texas Instruments |**
|
|
+**| Incorporated (TI) products to use this computer program for the sole |**
|
|
+**| purpose of implementing a licensee product based on TI products. |**
|
|
+**| No other rights to reproduce, use, or disseminate this computer |**
|
|
+**| program, whether in part or in whole, are granted. |**
|
|
+**| |**
|
|
+**| TI makes no representation or warranties with respect to the |**
|
|
+**| performance of this computer program, and specifically disclaims |**
|
|
+**| any responsibility for any damages, special or consequential, |**
|
|
+**| connected with the use of this program. |**
|
|
+**| |**
|
|
+**+----------------------------------------------------------------------+**
|
|
+***************************************************************************/
|
|
+
|
|
+/***************************************************************************
|
|
+ * ------------------------------------------------------------------------------
|
|
+ * Module : vlynq_hal.c
|
|
+ * Description : This file implements VLYNQ HAL API.
|
|
+ * ------------------------------------------------------------------------------
|
|
+ ***************************************************************************/
|
|
+
|
|
+#include <linux/stddef.h>
|
|
+#include <linux/types.h>
|
|
+#include <asm/ar7/vlynq.h>
|
|
+
|
|
+/**** Local Function prototypes *******/
|
|
+static int vlynqInterruptInit(VLYNQ_DEV *pdev);
|
|
+static void vlynq_configClock(VLYNQ_DEV *pdev);
|
|
+
|
|
+/*** Second argument must be explicitly type casted to
|
|
+ * (VLYNQ_DEV*) inside the following functions */
|
|
+static void vlynq_local_module_isr(void *arg1, void *arg2, void *arg3);
|
|
+static void vlynq_remote_module_isr(void *arg1, void *arg2, void *arg3);
|
|
+
|
|
+
|
|
+volatile int vlynq_delay_value = 0;
|
|
+
|
|
+/* Code adopted from original vlynq driver */
|
|
+void vlynq_delay(unsigned int clktime)
|
|
+{
|
|
+ int i = 0;
|
|
+ volatile int *ptr = &vlynq_delay_value;
|
|
+ *ptr = 0;
|
|
+
|
|
+ /* We are assuming that the each cycle takes about
|
|
+ * 23 assembly instructions. */
|
|
+ for(i = 0; i < (clktime + 23)/23; i++)
|
|
+ {
|
|
+ *ptr = *ptr + 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_configClock()
|
|
+ * Description: Configures clock settings based on input parameters
|
|
+ * Adapted from original vlyna driver from Cable
|
|
+ */
|
|
+static void vlynq_configClock(VLYNQ_DEV * pdev)
|
|
+{
|
|
+ unsigned int tmp;
|
|
+
|
|
+ switch( pdev->clk_source)
|
|
+ {
|
|
+ case VLYNQ_CLK_SOURCE_LOCAL: /* we output the clock, clk_div in range [1..8]. */
|
|
+ tmp = ((pdev->clk_div - 1) << 16) | VLYNQ_CTL_CLKDIR_MASK ;
|
|
+ VLYNQ_CTRL_REG = tmp;
|
|
+ VLYNQ_R_CTRL_REG = 0ul;
|
|
+ break;
|
|
+ case VLYNQ_CLK_SOURCE_REMOTE: /* we need to set the clock pin as input */
|
|
+ VLYNQ_CTRL_REG = 0ul;
|
|
+ tmp = ((pdev->clk_div - 1) << 16) | VLYNQ_CTL_CLKDIR_MASK ;
|
|
+ VLYNQ_R_CTRL_REG = tmp;
|
|
+ break;
|
|
+ default: /* do nothing about the clock, but clear other bits. */
|
|
+ tmp = ~(VLYNQ_CTL_CLKDIR_MASK | VLYNQ_CTL_CLKDIV_MASK);
|
|
+ VLYNQ_CTRL_REG &= tmp;
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+ /* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_link_check()
|
|
+ * Description: This function checks the current VLYNQ for a link.
|
|
+ * An arbitrary amount of time is allowed for the link to come up .
|
|
+ * Returns 0 for "no link / failure " and 1 for "link available".
|
|
+ * -----------------------------------------------------------------------------
|
|
+ */
|
|
+unsigned int vlynq_link_check( VLYNQ_DEV * pdev)
|
|
+{
|
|
+ /*sleep for 64 cycles, allow link to come up*/
|
|
+ vlynq_delay(64);
|
|
+
|
|
+ /* check status register return OK if link is found. */
|
|
+ if (VLYNQ_STATUS_REG & VLYNQ_STS_LINK_MASK)
|
|
+ {
|
|
+ return 1; /* Link Available */
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ return 0; /* Link Failure */
|
|
+ }
|
|
+}
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_init()
|
|
+ * Description: Initialization function accepting paramaters for VLYNQ module
|
|
+ * initialization. The Options bitmap decides what operations are performed
|
|
+ * as a part of initialization. The Input parameters are obtained through the
|
|
+ * sub fields of VLYNQ_DEV structure.
|
|
+ */
|
|
+
|
|
+int vlynq_init(VLYNQ_DEV *pdev, VLYNQ_INIT_OPTIONS options)
|
|
+{
|
|
+ unsigned int map;
|
|
+ unsigned int val=0,cnt,tmp;
|
|
+ unsigned int counter=0;
|
|
+ VLYNQ_INTERRUPT_CNTRL *intSetting=NULL;
|
|
+
|
|
+ /* validate arguments */
|
|
+ if( VLYNQ_OUTRANGE(pdev->clk_source, VLYNQ_CLK_SOURCE_REMOTE, VLYNQ_CLK_SOURCE_NONE) ||
|
|
+ VLYNQ_OUTRANGE(pdev->clk_div, 8, 1) )
|
|
+ {
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+ }
|
|
+
|
|
+ /** perform all sanity checks first **/
|
|
+ if(pdev->state != VLYNQ_DRV_STATE_UNINIT)
|
|
+ return VLYNQ_INVALID_DRV_STATE;
|
|
+
|
|
+ /** Initialize local and remote register set addresses- additional
|
|
+ * provision to access the registers directly if need be */
|
|
+ pdev->local = (VLYNQ_REG_SET*)pdev->module_base;
|
|
+ pdev->remote = (VLYNQ_REG_SET*) (pdev->module_base + VLYNQ_REMOTE_REGS_OFFSET);
|
|
+
|
|
+ /* Detect faulty int configuration that might induce int pkt looping */
|
|
+ if ( (options & VLYNQ_INIT_LOCAL_INTERRUPTS) && (options & VLYNQ_INIT_REMOTE_INTERRUPTS) )
|
|
+ {
|
|
+ /* case when both local and remote are configured */
|
|
+ if((pdev->local_irq.intLocal== VLYNQ_INT_REMOTE ) /* interrupts transfered to remote from local */
|
|
+ && (pdev->remote_irq.intLocal== VLYNQ_INT_REMOTE) /* interrupts transfered from remote to local */
|
|
+ && ((pdev->local_irq.intRemote == VLYNQ_INT_ROOT_ISR) || (pdev->remote_irq.intRemote == VLYNQ_INT_ROOT_ISR)) )
|
|
+ {
|
|
+ return (VLYNQ_INT_CONFIG_ERR);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pdev->state = VLYNQ_DRV_STATE_ININIT;
|
|
+ pdev->intCount = 0;
|
|
+ pdev->isrCount = 0;
|
|
+
|
|
+ /*** Its assumed that the vlynq module has been brought out of reset
|
|
+ * before invocation of vlynq_init. Since, this operation is board specific
|
|
+ * it must be handled outside this generic driver */
|
|
+
|
|
+ /* Assert reset the remote device, call reset_cb,
|
|
+ * reset CB holds Reset according to the device needs. */
|
|
+ VLYNQ_RESETCB(VLYNQ_RESET_ASSERT);
|
|
+
|
|
+ /* Handle VLYNQ clock, HW default (Sense On Reset) is
|
|
+ * usually input for all the devices. */
|
|
+ if (options & VLYNQ_INIT_CONFIG_CLOCK)
|
|
+ {
|
|
+ vlynq_configClock(pdev);
|
|
+ }
|
|
+
|
|
+ /* Call reset_cb again. It will release the remote device
|
|
+ * from reset, and wait for a while. */
|
|
+ VLYNQ_RESETCB(VLYNQ_RESET_DEASSERT);
|
|
+
|
|
+ if(options & VLYNQ_INIT_CHECK_LINK )
|
|
+ {
|
|
+ /* Check for link up during initialization*/
|
|
+ while( counter < 25 )
|
|
+ {
|
|
+ /* loop around giving a chance for link status to settle down */
|
|
+ counter++;
|
|
+ if(vlynq_link_check(pdev))
|
|
+ {
|
|
+ /* Link is up exit loop*/
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ vlynq_delay(4000);
|
|
+ }/*end of while counter loop */
|
|
+
|
|
+ if(!vlynq_link_check(pdev))
|
|
+ {
|
|
+ /* Handle this case as abort */
|
|
+ pdev->state = VLYNQ_DRV_STATE_ERROR;
|
|
+ VLYNQ_RESETCB( VLYNQ_RESET_INITFAIL);
|
|
+ return VLYNQ_LINK_DOWN;
|
|
+ }/* end of if not vlynq_link_check conditional block */
|
|
+
|
|
+ }/*end of if options & VLYNQ_INIT_CHECK_LINK conditional block */
|
|
+
|
|
+
|
|
+ if (options & VLYNQ_INIT_LOCAL_MEM_REGIONS)
|
|
+ {
|
|
+ /* Initialise local memory regions . This initialization lets
|
|
+ * the local host access remote device memory regions*/
|
|
+ int i;
|
|
+
|
|
+ /* configure the VLYNQ portal window to a PHYSICAL
|
|
+ * address of the local CPU */
|
|
+ VLYNQ_ALIGN4(pdev->local_mem.Txmap);
|
|
+ VLYNQ_TXMAP_REG = (pdev->local_mem.Txmap);
|
|
+
|
|
+ /*This code assumes input parameter is itself a physical address */
|
|
+ for(i=0; i < VLYNQ_MAX_MEMORY_REGIONS ; i++)
|
|
+ {
|
|
+ /* Physical address on the remote */
|
|
+ map = i+1;
|
|
+ VLYNQ_R_RXMAP_SIZE_REG(map) = 0;
|
|
+ if( pdev->remote_mem.RxSize[i])
|
|
+ {
|
|
+ VLYNQ_ALIGN4(pdev->remote_mem.RxOffset[i]);
|
|
+ VLYNQ_ALIGN4(pdev->remote_mem.RxSize[i]);
|
|
+ VLYNQ_R_RXMAP_OFFSET_REG(map) = pdev->remote_mem.RxOffset[i];
|
|
+ VLYNQ_R_RXMAP_SIZE_REG(map) = pdev->remote_mem.RxSize[i];
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(options & VLYNQ_INIT_REMOTE_MEM_REGIONS )
|
|
+ {
|
|
+ int i;
|
|
+
|
|
+ /* Initialise remote memory regions. This initialization lets remote
|
|
+ * device access local host memory regions. It configures the VLYNQ portal
|
|
+ * window to a PHYSICAL address of the remote */
|
|
+ VLYNQ_ALIGN4(pdev->remote_mem.Txmap);
|
|
+ VLYNQ_R_TXMAP_REG = pdev->remote_mem.Txmap;
|
|
+
|
|
+ for( i=0; i<VLYNQ_MAX_MEMORY_REGIONS; i++)
|
|
+ {
|
|
+ /* Physical address on the local */
|
|
+ map = i+1;
|
|
+ VLYNQ_RXMAP_SIZE_REG(map) = 0;
|
|
+ if( pdev->local_mem.RxSize[i])
|
|
+ {
|
|
+ VLYNQ_ALIGN4(pdev->local_mem.RxOffset[i]);
|
|
+ VLYNQ_ALIGN4(pdev->local_mem.RxSize[i]);
|
|
+ VLYNQ_RXMAP_OFFSET_REG(map) = (pdev->local_mem.RxOffset[i]);
|
|
+ VLYNQ_RXMAP_SIZE_REG(map) = (pdev->local_mem.RxSize[i]);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Adapted from original vlynq driver from cable - Calculate VLYNQ bus width */
|
|
+ pdev->width = 3 + VLYNQ_STATUS_FLD_WIDTH(VLYNQ_STATUS_REG)
|
|
+ + VLYNQ_STATUS_FLD_WIDTH(VLYNQ_R_STATUS_REG);
|
|
+
|
|
+ /* chance to initialize the device, e.g. to boost VLYNQ
|
|
+ * clock by modifying pdev->clk_div or and verify the width. */
|
|
+ VLYNQ_RESETCB(VLYNQ_RESET_LINKESTABLISH);
|
|
+
|
|
+ /* Handle VLYNQ clock, HW default (Sense On Reset) is
|
|
+ * usually input for all the devices. */
|
|
+ if(options & VLYNQ_INIT_CONFIG_CLOCK )
|
|
+ {
|
|
+ vlynq_configClock(pdev);
|
|
+ }
|
|
+
|
|
+ /* last check for link*/
|
|
+ if(options & VLYNQ_INIT_CHECK_LINK )
|
|
+ {
|
|
+ /* Final Check for link during initialization*/
|
|
+ while( counter < 25 )
|
|
+ {
|
|
+ /* loop around giving a chance for link status to settle down */
|
|
+ counter++;
|
|
+ if(vlynq_link_check(pdev))
|
|
+ {
|
|
+ /* Link is up exit loop*/
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ vlynq_delay(4000);
|
|
+ }/*end of while counter loop */
|
|
+
|
|
+ if(!vlynq_link_check(pdev))
|
|
+ {
|
|
+ /* Handle this case as abort */
|
|
+ pdev->state = VLYNQ_DRV_STATE_ERROR;
|
|
+ VLYNQ_RESETCB( VLYNQ_RESET_INITFAIL);
|
|
+ return VLYNQ_LINK_DOWN;
|
|
+ }/* end of if not vlynq_link_check conditional block */
|
|
+
|
|
+ } /* end of if options & VLYNQ_INIT_CHECK_LINK */
|
|
+
|
|
+ if(options & VLYNQ_INIT_LOCAL_INTERRUPTS )
|
|
+ {
|
|
+ /* Configure local interrupt settings */
|
|
+ intSetting = &(pdev->local_irq);
|
|
+
|
|
+ /* Map local module status interrupts to interrupt vector*/
|
|
+ val = intSetting->map_vector << VLYNQ_CTL_INTVEC_SHIFT ;
|
|
+
|
|
+ /* enable local module status interrupts */
|
|
+ val |= 0x01 << VLYNQ_CTL_INTEN_SHIFT;
|
|
+
|
|
+ if ( intSetting->intLocal == VLYNQ_INT_LOCAL )
|
|
+ {
|
|
+ /*set the intLocal bit*/
|
|
+ val |= 0x01 << VLYNQ_CTL_INTLOCAL_SHIFT;
|
|
+ }
|
|
+
|
|
+ /* Irrespective of whether interrupts are handled locally, program
|
|
+ * int2Cfg. Error checking for accidental loop(when intLocal=0 and int2Cfg=1
|
|
+ * i.e remote packets are set intPending register->which will result in
|
|
+ * same packet being sent out) has been done already
|
|
+ */
|
|
+
|
|
+ if (intSetting->intRemote == VLYNQ_INT_ROOT_ISR)
|
|
+ {
|
|
+ /* Set the int2Cfg register, so that remote interrupt
|
|
+ * packets are written to intPending register */
|
|
+ val |= 0x01 << VLYNQ_CTL_INT2CFG_SHIFT;
|
|
+
|
|
+ /* Set intPtr register to point to intPending register */
|
|
+ VLYNQ_INT_PTR_REG = VLYNQ_INT_PENDING_REG_PTR ;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*set the interrupt pointer register*/
|
|
+ VLYNQ_INT_PTR_REG = intSetting->intr_ptr;
|
|
+ /* Dont bother to modify int2Cfg as it would be zero */
|
|
+ }
|
|
+
|
|
+ /** Clear bits related to INT settings in control register **/
|
|
+ VLYNQ_CTRL_REG = VLYNQ_CTRL_REG & (~VLYNQ_CTL_INTFIELDS_CLEAR_MASK);
|
|
+
|
|
+ /** Or the bits to be set with Control register **/
|
|
+ VLYNQ_CTRL_REG = VLYNQ_CTRL_REG | val;
|
|
+
|
|
+ /* initialise local ICB */
|
|
+ if(vlynqInterruptInit(pdev)==VLYNQ_MEMALLOC_FAIL)
|
|
+ return VLYNQ_MEMALLOC_FAIL;
|
|
+
|
|
+ /* Install handler for local module status interrupts. By default when
|
|
+ * local interrupt setting is initialised, the local module status are
|
|
+ * enabled and handler hooked up */
|
|
+ if(vlynq_install_isr(pdev, intSetting->map_vector, vlynq_local_module_isr,
|
|
+ pdev, NULL, NULL) == VLYNQ_INVALID_ARG)
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+ } /* end of init local interrupts */
|
|
+
|
|
+ if(options & VLYNQ_INIT_REMOTE_INTERRUPTS )
|
|
+ {
|
|
+ /* Configure remote interrupt settings from configuration */
|
|
+ intSetting = &(pdev->remote_irq);
|
|
+
|
|
+ /* Map remote module status interrupts to remote interrupt vector*/
|
|
+ val = intSetting->map_vector << VLYNQ_CTL_INTVEC_SHIFT ;
|
|
+ /* enable remote module status interrupts */
|
|
+ val |= 0x01 << VLYNQ_CTL_INTEN_SHIFT;
|
|
+
|
|
+ if ( intSetting->intLocal == VLYNQ_INT_LOCAL )
|
|
+ {
|
|
+ /*set the intLocal bit*/
|
|
+ val |= 0x01 << VLYNQ_CTL_INTLOCAL_SHIFT;
|
|
+ }
|
|
+
|
|
+ /* Irrespective of whether interrupts are handled locally, program
|
|
+ * int2Cfg. Error checking for accidental loop(when intLocal=0 and int2Cfg=1
|
|
+ * i.e remote packets are set intPending register->which will result in
|
|
+ * same packet being sent out) has been done already
|
|
+ */
|
|
+
|
|
+ if (intSetting->intRemote == VLYNQ_INT_ROOT_ISR)
|
|
+ {
|
|
+ /* Set the int2Cfg register, so that remote interrupt
|
|
+ * packets are written to intPending register */
|
|
+ val |= 0x01 << VLYNQ_CTL_INT2CFG_SHIFT;
|
|
+ /* Set intPtr register to point to intPending register */
|
|
+ VLYNQ_R_INT_PTR_REG = VLYNQ_R_INT_PENDING_REG_PTR ;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*set the interrupt pointer register*/
|
|
+ VLYNQ_R_INT_PTR_REG = intSetting->intr_ptr;
|
|
+ /* Dont bother to modify int2Cfg as it would be zero */
|
|
+ }
|
|
+
|
|
+ if( (intSetting->intLocal == VLYNQ_INT_REMOTE) &&
|
|
+ (options & VLYNQ_INIT_LOCAL_INTERRUPTS) &&
|
|
+ (pdev->local_irq.intRemote == VLYNQ_INT_ROOT_ISR) )
|
|
+ {
|
|
+ /* Install handler for remote module status interrupts. By default when
|
|
+ * remote interrupts are forwarded to local root_isr then remote_module_isr is
|
|
+ * enabled and handler hooked up */
|
|
+ if(vlynq_install_isr(pdev,intSetting->map_vector,vlynq_remote_module_isr,
|
|
+ pdev, NULL, NULL) == VLYNQ_INVALID_ARG)
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+ }
|
|
+
|
|
+
|
|
+ /** Clear bits related to INT settings in control register **/
|
|
+ VLYNQ_R_CTRL_REG = VLYNQ_R_CTRL_REG & (~VLYNQ_CTL_INTFIELDS_CLEAR_MASK);
|
|
+
|
|
+ /** Or the bits to be set with the remote Control register **/
|
|
+ VLYNQ_R_CTRL_REG = VLYNQ_R_CTRL_REG | val;
|
|
+
|
|
+ } /* init remote interrupt settings*/
|
|
+
|
|
+ if(options & VLYNQ_INIT_CLEAR_ERRORS )
|
|
+ {
|
|
+ /* Clear errors during initialization */
|
|
+ tmp = VLYNQ_STATUS_REG & (VLYNQ_STS_RERROR_MASK | VLYNQ_STS_LERROR_MASK);
|
|
+ VLYNQ_STATUS_REG = tmp;
|
|
+ tmp = VLYNQ_R_STATUS_REG & (VLYNQ_STS_RERROR_MASK | VLYNQ_STS_LERROR_MASK);
|
|
+ VLYNQ_R_STATUS_REG = tmp;
|
|
+ }
|
|
+
|
|
+ /* clear int status */
|
|
+ val = VLYNQ_INT_STAT_REG;
|
|
+ VLYNQ_INT_STAT_REG = val;
|
|
+
|
|
+ /* finish initialization */
|
|
+ pdev->state = VLYNQ_DRV_STATE_RUN;
|
|
+ VLYNQ_RESETCB( VLYNQ_RESET_INITOK);
|
|
+ return VLYNQ_SUCCESS;
|
|
+
|
|
+}
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * Function : vlynqInterruptInit()
|
|
+ * Description: This local function is used to set up the ICB table for the
|
|
+ * VLYNQ_STATUS_REG vlynq module. The input parameter "pdev" points the vlynq
|
|
+ * device instance whose ICB is allocated.
|
|
+ * Return : returns VLYNQ_SUCCESS or vlynq error for failure
|
|
+ * -----------------------------------------------------------------------------
|
|
+ */
|
|
+static int vlynqInterruptInit(VLYNQ_DEV *pdev)
|
|
+{
|
|
+ int i, numslots;
|
|
+
|
|
+ /* Memory allocated statically.
|
|
+ * Initialise ICB,free list.Indicate primary slot empty.
|
|
+ * Intialise intVector <==> map_vector translation table*/
|
|
+ for(i=0; i < VLYNQ_NUM_INT_BITS; i++)
|
|
+ {
|
|
+ pdev->pIntrCB[i].isr = NULL;
|
|
+ pdev->pIntrCB[i].next = NULL; /*nothing chained */
|
|
+ pdev->vector_map[i] = -1; /* indicates unmapped */
|
|
+ }
|
|
+
|
|
+ /* In the ICB slots, [VLYNQ_NUM_INT_BITS i.e 32 to ICB array size) are expansion slots
|
|
+ * required only when interrupt chaining/sharing is supported. In case
|
|
+ * of chained interrupts the list starts from primary slot and the
|
|
+ * additional slots are obtained from the common free area */
|
|
+
|
|
+ /* Initialise freelist */
|
|
+
|
|
+ numslots = VLYNQ_NUM_INT_BITS + VLYNQ_IVR_CHAIN_SLOTS;
|
|
+
|
|
+ if (numslots > VLYNQ_NUM_INT_BITS)
|
|
+ {
|
|
+ pdev->freelist = &(pdev->pIntrCB[VLYNQ_NUM_INT_BITS]);
|
|
+
|
|
+ for(i = VLYNQ_NUM_INT_BITS; i < (numslots-1) ; i++)
|
|
+ {
|
|
+ pdev->pIntrCB[i].next = &(pdev->pIntrCB[i+1]);
|
|
+ pdev->pIntrCB[i].isr = NULL;
|
|
+ }
|
|
+ pdev->pIntrCB[i].next=NULL; /* Indicate end of freelist*/
|
|
+ pdev->pIntrCB[i].isr=NULL;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ pdev->freelist = NULL;
|
|
+ }
|
|
+
|
|
+ /** Reset mapping for IV 0-7 **/
|
|
+ VLYNQ_IVR_03TO00_REG = 0;
|
|
+ VLYNQ_IVR_07TO04_REG = 0;
|
|
+
|
|
+ return VLYNQ_SUCCESS;
|
|
+}
|
|
+
|
|
+/** remember that hooking up of root ISR handler with the interrupt controller
|
|
+ * is not done as a part of this driver. Typically, it must be done after
|
|
+ * invoking vlynq_init*/
|
|
+
|
|
+
|
|
+ /* ----------------------------------------------------------------------------
|
|
+ * ISR with the SOC interrupt controller. This ISR typically scans
|
|
+ * the Int PENDING/SET register in the VLYNQ module and calls the
|
|
+ * appropriate ISR associated with the correponding vector number.
|
|
+ * -----------------------------------------------------------------------------
|
|
+ */
|
|
+void vlynq_root_isr(void *arg)
|
|
+{
|
|
+ int source; /* Bit position of pending interrupt, start from 0 */
|
|
+ unsigned int interrupts, clrInterrupts;
|
|
+ VLYNQ_DEV * pdev;
|
|
+ VLYNQ_INTR_CNTRL_ICB *entry;
|
|
+
|
|
+ pdev=(VLYNQ_DEV*)(arg); /*obtain the vlynq device pointer*/
|
|
+
|
|
+ interrupts = VLYNQ_INT_STAT_REG; /* Get the list of pending interrupts */
|
|
+ VLYNQ_INT_STAT_REG = interrupts; /* clear the int CR register */
|
|
+ clrInterrupts = interrupts; /* save them for further analysis */
|
|
+
|
|
+ debugPrint("vlynq_root_isr: dev %u. INTCR = 0x%08lx\n", pdev->dev_idx, clrInterrupts,0,0,0,0);
|
|
+
|
|
+ /* Scan interrupt bits */
|
|
+ source =0;
|
|
+ while( clrInterrupts != 0)
|
|
+ {
|
|
+ /* test if bit is set? */
|
|
+ if( 0x1ul & clrInterrupts)
|
|
+ {
|
|
+ entry = &(pdev->pIntrCB[source]); /* Get the ISR entry */
|
|
+ pdev->intCount++; /* update interrupt count */
|
|
+ if(entry->isr != NULL)
|
|
+ {
|
|
+ do
|
|
+ {
|
|
+ pdev->isrCount++; /* update isr invocation count */
|
|
+ /* Call the user ISR and update the count for ISR */
|
|
+ entry->isrCount++;
|
|
+ entry->isr(entry->arg1, entry->arg2, entry->arg3);
|
|
+ if (entry->next == NULL) break;
|
|
+ entry = entry->next;
|
|
+
|
|
+ } while (entry->isr != NULL);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ debugPrint(" ISR not installed for vlynq vector:%d\n",source,0,0,0,0,0);
|
|
+ }
|
|
+ }
|
|
+ clrInterrupts >>= 1; /* Next source bit */
|
|
+ ++source;
|
|
+ } /* endWhile clrInterrupts != 0 */
|
|
+}
|
|
+
|
|
+
|
|
+ /* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_local__module_isr()
|
|
+ * Description: This ISR is attached to the local VLYNQ interrupt vector
|
|
+ * by the Vlynq Driver when local interrupts are being handled. i.e.
|
|
+ * intLocal=1. This ISR handles local Vlynq module status interrupts only
|
|
+ * AS a part of this ISR, user callback in VLYNQ_DEV structure
|
|
+ * is invoked.
|
|
+ * VLYNQ_DEV is passed as arg1. arg2 and arg3 are unused.
|
|
+ * -----------------------------------------------------------------------------
|
|
+ */
|
|
+static void vlynq_local_module_isr(void *arg1,void *arg2, void *arg3)
|
|
+{
|
|
+ VLYNQ_REPORT_CB func;
|
|
+ unsigned int dwStatRegVal;
|
|
+ VLYNQ_DEV * pdev;
|
|
+
|
|
+ pdev = (VLYNQ_DEV*) arg1;
|
|
+ /* Callback function is read from the device pointer that is passed as an argument */
|
|
+ func = pdev->report_cb;
|
|
+
|
|
+ /* read local status register */
|
|
+ dwStatRegVal = VLYNQ_STATUS_REG;
|
|
+
|
|
+ /* clear pending events */
|
|
+ VLYNQ_STATUS_REG = dwStatRegVal;
|
|
+
|
|
+ /* invoke user callback */
|
|
+ if( func != NULL)
|
|
+ func( pdev, VLYNQ_LOCAL_DVC, dwStatRegVal);
|
|
+
|
|
+}
|
|
+
|
|
+ /* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_remote_module_isr()
|
|
+ * Description: This ISR is attached to the remote VLYNQ interrupt vector
|
|
+ * by the Vlynq Driver when remote interrupts are being handled locally. i.e.
|
|
+ * intLocal=1. This ISR handles local Vlynq module status interrupts only
|
|
+ * AS a part of this ISR, user callback in VLYNQ_DEV structure
|
|
+ * is invoked.
|
|
+ * The parameters irq,regs ar unused.
|
|
+ * -----------------------------------------------------------------------------
|
|
+ */
|
|
+static void vlynq_remote_module_isr(void *arg1,void *arg2, void *arg3)
|
|
+{
|
|
+ VLYNQ_REPORT_CB func;
|
|
+ unsigned int dwStatRegVal;
|
|
+ VLYNQ_DEV * pdev;
|
|
+
|
|
+
|
|
+ pdev = (VLYNQ_DEV*) arg1;
|
|
+
|
|
+ /* Callback function is read from the device pointer that is passed as an argument */
|
|
+ func = pdev->report_cb;
|
|
+
|
|
+ /* read local status register */
|
|
+ dwStatRegVal = VLYNQ_R_STATUS_REG;
|
|
+
|
|
+ /* clear pending events */
|
|
+ VLYNQ_R_STATUS_REG = dwStatRegVal;
|
|
+
|
|
+ /* invoke user callback */
|
|
+ if( func != NULL)
|
|
+ func( pdev, VLYNQ_REMOTE_DVC, dwStatRegVal);
|
|
+
|
|
+}
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_interrupt_get_count()
|
|
+ * Description: This function returns the number of times a particular intr
|
|
+ * has been invoked.
|
|
+ *
|
|
+ * It returns 0, if erroneous map_vector is specified or if the corres isr
|
|
+ * has not been registered with VLYNQ.
|
|
+ */
|
|
+unsigned int vlynq_interrupt_get_count(VLYNQ_DEV *pdev,
|
|
+ unsigned int map_vector)
|
|
+{
|
|
+ VLYNQ_INTR_CNTRL_ICB *entry;
|
|
+ unsigned int count = 0;
|
|
+
|
|
+ if (map_vector > (VLYNQ_NUM_INT_BITS-1))
|
|
+ return count;
|
|
+
|
|
+ entry = &(pdev->pIntrCB[map_vector]);
|
|
+
|
|
+ if (entry)
|
|
+ count = entry->isrCount;
|
|
+
|
|
+ return (count);
|
|
+}
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_install_isr()
|
|
+ * Description: This function installs ISR for Vlynq interrupt vector
|
|
+ * bits(in IntPending register). This function should be used only when
|
|
+ * Vlynq interrupts are being handled locally(remote may be programmed to send
|
|
+ * interrupt packets).Also, the int2cfg should be 1 and the least significant
|
|
+ * 8 bits of the Interrupt Pointer Register must point to Interrupt
|
|
+ * Pending/Set Register).
|
|
+ * If host int2cfg=0 and the Interrupt Pointer register contains
|
|
+ * the address of the interrupt set register in the interrupt controller
|
|
+ * module of the local device , then the ISR for the remote interrupt must be
|
|
+ * directly registered with the Interrupt controller and must not use this API
|
|
+ * Note: this function simply installs the ISR in ICB It doesnt modify
|
|
+ * any register settings
|
|
+ */
|
|
+int
|
|
+vlynq_install_isr(VLYNQ_DEV *pdev,
|
|
+ unsigned int map_vector,
|
|
+ VLYNQ_INTR_CNTRL_ISR isr,
|
|
+ void *arg1, void *arg2, void *arg3)
|
|
+{
|
|
+ VLYNQ_INTR_CNTRL_ICB *entry;
|
|
+
|
|
+ if ( (map_vector > (VLYNQ_NUM_INT_BITS-1)) || (isr == NULL) )
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+
|
|
+ entry = &(pdev->pIntrCB[map_vector]);
|
|
+
|
|
+ if(entry->isr == NULL)
|
|
+ {
|
|
+ entry->isr = isr;
|
|
+ entry->arg1 = arg1;
|
|
+ entry->arg2 = arg2;
|
|
+ entry->arg3 = arg3;
|
|
+ entry->next = NULL;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /** No more empty slots,return error */
|
|
+ if(pdev->freelist == NULL)
|
|
+ return VLYNQ_MEMALLOC_FAIL;
|
|
+
|
|
+ while(entry->next != NULL)
|
|
+ {
|
|
+ entry = entry->next;
|
|
+ }
|
|
+
|
|
+ /* Append new node to the chain */
|
|
+ entry->next = pdev->freelist;
|
|
+ /* Remove the appended node from freelist */
|
|
+ pdev->freelist = pdev->freelist->next;
|
|
+ entry= entry->next;
|
|
+
|
|
+ /*** Set the ICB fields ***/
|
|
+ entry->isr = isr;
|
|
+ entry->arg1 = arg1;
|
|
+ entry->arg2 = arg2;
|
|
+ entry->arg3 = arg3;
|
|
+ entry->next = NULL;
|
|
+ }
|
|
+
|
|
+ return VLYNQ_SUCCESS;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_uninstall_isr
|
|
+ * Description: This function is used to uninstall a previously
|
|
+ * registered ISR. In case of shared/chained interrupts, the
|
|
+ * void * arg parameter must uniquely identify the ISR to be
|
|
+ * uninstalled.
|
|
+ * Note: this function simply uninstalls the ISR in ICB
|
|
+ * It doesnt modify any register settings
|
|
+ */
|
|
+int
|
|
+vlynq_uninstall_isr(VLYNQ_DEV *pdev,
|
|
+ unsigned int map_vector,
|
|
+ void *arg1, void *arg2, void *arg3)
|
|
+{
|
|
+ VLYNQ_INTR_CNTRL_ICB *entry,*temp;
|
|
+
|
|
+ if (map_vector > (VLYNQ_NUM_INT_BITS-1))
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+
|
|
+ entry = &(pdev->pIntrCB[map_vector]);
|
|
+
|
|
+ if(entry->isr == NULL )
|
|
+ return VLYNQ_ISR_NON_EXISTENT;
|
|
+
|
|
+ if ( (entry->arg1 == arg1) && (entry->arg2 == arg2) && (entry->arg3 == arg3) )
|
|
+ {
|
|
+ if(entry->next == NULL)
|
|
+ {
|
|
+ entry->isr=NULL;
|
|
+ return VLYNQ_SUCCESS;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ temp = entry->next;
|
|
+ /* Copy next node in the chain to prim.slot */
|
|
+ entry->isr = temp->isr;
|
|
+ entry->arg1 = temp->arg1;
|
|
+ entry->arg2 = temp->arg2;
|
|
+ entry->arg3 = temp->arg3;
|
|
+ entry->next = temp->next;
|
|
+ /* Free the just copied node */
|
|
+ temp->isr = NULL;
|
|
+ temp->arg1 = NULL;
|
|
+ temp->arg2 = NULL;
|
|
+ temp->arg3 = NULL;
|
|
+ temp->next = pdev->freelist;
|
|
+ pdev->freelist = temp;
|
|
+ return VLYNQ_SUCCESS;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ temp = entry;
|
|
+ while ( (entry = temp->next) != NULL)
|
|
+ {
|
|
+ if ( (entry->arg1 == arg1) && (entry->arg2 == arg2) && (entry->arg3 == arg3) )
|
|
+ {
|
|
+ /* remove node from chain */
|
|
+ temp->next = entry->next;
|
|
+ /* Add the removed node to freelist */
|
|
+ entry->isr = NULL;
|
|
+ entry->arg1 = NULL;
|
|
+ entry->arg2 = NULL;
|
|
+ entry->arg3 = NULL;
|
|
+ entry->next = pdev->freelist;
|
|
+ entry->isrCount = 0;
|
|
+ pdev->freelist = entry;
|
|
+ return VLYNQ_SUCCESS;
|
|
+ }
|
|
+ temp = entry;
|
|
+ }
|
|
+
|
|
+ return VLYNQ_ISR_NON_EXISTENT;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * function : vlynq_interrupt_vector_set()
|
|
+ * description:configures interrupt vector mapping,interrupt type
|
|
+ * polarity -all in one go.
|
|
+ */
|
|
+int
|
|
+vlynq_interrupt_vector_set(VLYNQ_DEV *pdev, /* vlynq device */
|
|
+ unsigned int int_vector, /* int vector on vlynq device */
|
|
+ unsigned int map_vector, /* bit for this interrupt */
|
|
+ VLYNQ_DEV_TYPE dev_type, /* local or remote device */
|
|
+ VLYNQ_INTR_POLARITY pol, /* polarity of interrupt */
|
|
+ VLYNQ_INTR_TYPE type) /* pulsed/level interrupt */
|
|
+{
|
|
+ volatile unsigned int * vecreg;
|
|
+ unsigned int val=0;
|
|
+ unsigned int bytemask=0XFF;
|
|
+
|
|
+ /* use the lower 8 bits of val to set the value , shift it to
|
|
+ * appropriate byte position in the ivr and write it to the
|
|
+ * corresponding register */
|
|
+
|
|
+ /* validate the number of interrupts supported */
|
|
+ if (int_vector >= VLYNQ_IVR_MAXIVR)
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+
|
|
+ if(map_vector > (VLYNQ_NUM_INT_BITS - 1) )
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+
|
|
+ if (dev_type == VLYNQ_LOCAL_DVC)
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+
|
|
+ /* Update the intVector<==> bit position translation table */
|
|
+ pdev->vector_map[map_vector] = int_vector;
|
|
+
|
|
+ /* val has been initialised to zero. we only have to turn on appropriate bits*/
|
|
+ if(type == VLYNQ_INTR_PULSED)
|
|
+ val |= VLYNQ_IVR_INTTYPE_MASK;
|
|
+
|
|
+ if(pol == VLYNQ_INTR_ACTIVE_LOW)
|
|
+ val |= VLYNQ_IVR_INTPOL_MASK;
|
|
+
|
|
+ val |= map_vector;
|
|
+
|
|
+ /** clear the correct byte position and then or val **/
|
|
+ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
|
|
+
|
|
+ /** write to correct byte position in vecreg*/
|
|
+ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
|
|
+
|
|
+ /* Setting a interrupt vector, leaves the interrupt disabled
|
|
+ * which must be enabled subsequently */
|
|
+
|
|
+ return VLYNQ_SUCCESS;
|
|
+}
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_interrupt_vector_cntl()
|
|
+ * Description:enables/disable interrupt
|
|
+ */
|
|
+int vlynq_interrupt_vector_cntl( VLYNQ_DEV *pdev,
|
|
+ unsigned int int_vector,
|
|
+ VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int enable)
|
|
+{
|
|
+ volatile unsigned int *vecReg;
|
|
+ unsigned int val=0;
|
|
+ unsigned int intenMask=0x80;
|
|
+
|
|
+ /* validate the number of interrupts supported */
|
|
+ if (int_vector >= VLYNQ_IVR_MAXIVR)
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+
|
|
+ if (dev_type == VLYNQ_LOCAL_DVC)
|
|
+ {
|
|
+ vecReg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vecReg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+
|
|
+ /** Clear the correct byte position and then or val **/
|
|
+ *vecReg = (*vecReg) & ( ~(intenMask << ( (int_vector %4)*8) ) );
|
|
+
|
|
+ if(enable)
|
|
+ {
|
|
+ val |= VLYNQ_IVR_INTEN_MASK;
|
|
+ /** Write to correct byte position in vecReg*/
|
|
+ *vecReg = (*vecReg) | (val << ( (int_vector % 4)*8) ) ;
|
|
+ }
|
|
+
|
|
+ return VLYNQ_SUCCESS;
|
|
+
|
|
+}/* end of function vlynq_interrupt_vector_cntl */
|
|
+
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * Function : vlynq_interrupt_vector_map()
|
|
+ * Description:Configures interrupt vector mapping alone
|
|
+ */
|
|
+int
|
|
+vlynq_interrupt_vector_map( VLYNQ_DEV *pdev,
|
|
+ VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int int_vector,
|
|
+ unsigned int map_vector)
|
|
+{
|
|
+ volatile unsigned int * vecreg;
|
|
+ unsigned int val=0;
|
|
+ unsigned int bytemask=0x1f; /* mask to turn off bits corresponding to int vector */
|
|
+
|
|
+ /* use the lower 8 bits of val to set the value , shift it to
|
|
+ * appropriate byte position in the ivr and write it to the
|
|
+ * corresponding register */
|
|
+
|
|
+ /* validate the number of interrupts supported */
|
|
+ if (int_vector >= VLYNQ_IVR_MAXIVR)
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+
|
|
+ if(map_vector > (VLYNQ_NUM_INT_BITS - 1) )
|
|
+ return VLYNQ_INVALID_ARG;
|
|
+
|
|
+ if (dev_type == VLYNQ_LOCAL_DVC)
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+
|
|
+ /* Update the intVector<==> bit position translation table */
|
|
+ pdev->vector_map[map_vector] = int_vector;
|
|
+
|
|
+ /** val has been initialised to zero. we only have to turn on
|
|
+ * appropriate bits*/
|
|
+ val |= map_vector;
|
|
+
|
|
+ /** clear the correct byte position and then or val **/
|
|
+ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
|
|
+
|
|
+ /** write to correct byte position in vecreg*/
|
|
+ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
|
|
+
|
|
+ return VLYNQ_SUCCESS;
|
|
+}
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * function : vlynq_interrupt_set_polarity()
|
|
+ * description:configures interrupt polarity .
|
|
+ */
|
|
+int
|
|
+vlynq_interrupt_set_polarity( VLYNQ_DEV *pdev ,
|
|
+ VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int map_vector,
|
|
+ VLYNQ_INTR_POLARITY pol)
|
|
+{
|
|
+ volatile unsigned int * vecreg;
|
|
+ int int_vector;
|
|
+ unsigned int val=0;
|
|
+ unsigned int bytemask=0x20; /** mask to turn off bits corresponding to int polarity */
|
|
+
|
|
+ /* get the int_vector from map_vector */
|
|
+ int_vector = pdev->vector_map[map_vector];
|
|
+
|
|
+ if(int_vector == -1)
|
|
+ return VLYNQ_INTVEC_MAP_NOT_FOUND;
|
|
+
|
|
+ /* use the lower 8 bits of val to set the value , shift it to
|
|
+ * appropriate byte position in the ivr and write it to the
|
|
+ * corresponding register */
|
|
+
|
|
+ if (dev_type == VLYNQ_LOCAL_DVC)
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+
|
|
+ /* val has been initialised to zero. we only have to turn on
|
|
+ * appropriate bits, if need be*/
|
|
+
|
|
+ /** clear the correct byte position and then or val **/
|
|
+ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
|
|
+
|
|
+ if( pol == VLYNQ_INTR_ACTIVE_LOW)
|
|
+ {
|
|
+ val |= VLYNQ_IVR_INTPOL_MASK;
|
|
+ /** write to correct byte position in vecreg*/
|
|
+ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
|
|
+ }
|
|
+
|
|
+ return VLYNQ_SUCCESS;
|
|
+}
|
|
+
|
|
+int vlynq_interrupt_get_polarity( VLYNQ_DEV *pdev ,
|
|
+ VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int map_vector)
|
|
+{
|
|
+ volatile unsigned int * vecreg;
|
|
+ int int_vector;
|
|
+ unsigned int val=0;
|
|
+
|
|
+ /* get the int_vector from map_vector */
|
|
+ int_vector = pdev->vector_map[map_vector];
|
|
+
|
|
+ if (map_vector > (VLYNQ_NUM_INT_BITS-1))
|
|
+ return(-1);
|
|
+
|
|
+ if(int_vector == -1)
|
|
+ return VLYNQ_INTVEC_MAP_NOT_FOUND;
|
|
+
|
|
+ /* use the lower 8 bits of val to set the value , shift it to
|
|
+ * appropriate byte position in the ivr and write it to the
|
|
+ * corresponding register */
|
|
+
|
|
+ if (dev_type == VLYNQ_LOCAL_DVC)
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+
|
|
+ /** read the information into val **/
|
|
+ val = (*vecreg) & ((VLYNQ_IVR_INTPOL_MASK << ( (int_vector %4)*8) ) );
|
|
+
|
|
+ return (val ? (VLYNQ_INTR_ACTIVE_LOW) : (VLYNQ_INTR_ACTIVE_HIGH));
|
|
+}
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * function : vlynq_interrupt_set_type()
|
|
+ * description:configures interrupt type .
|
|
+ */
|
|
+int vlynq_interrupt_set_type( VLYNQ_DEV *pdev,
|
|
+ VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int map_vector,
|
|
+ VLYNQ_INTR_TYPE type)
|
|
+{
|
|
+ volatile unsigned int * vecreg;
|
|
+ unsigned int val=0;
|
|
+ int int_vector;
|
|
+
|
|
+ /** mask to turn off bits corresponding to interrupt type */
|
|
+ unsigned int bytemask=0x40;
|
|
+
|
|
+ /* get the int_vector from map_vector */
|
|
+ int_vector = pdev->vector_map[map_vector];
|
|
+ if(int_vector == -1)
|
|
+ return VLYNQ_INTVEC_MAP_NOT_FOUND;
|
|
+
|
|
+ /* use the lower 8 bits of val to set the value , shift it to
|
|
+ * appropriate byte position in the ivr and write it to the
|
|
+ * corresponding register */
|
|
+ if (dev_type == VLYNQ_LOCAL_DVC)
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+
|
|
+ /** val has been initialised to zero. we only have to turn on
|
|
+ * appropriate bits if need be*/
|
|
+
|
|
+ /** clear the correct byte position and then or val **/
|
|
+ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
|
|
+
|
|
+ if( type == VLYNQ_INTR_PULSED)
|
|
+ {
|
|
+ val |= VLYNQ_IVR_INTTYPE_MASK;
|
|
+ /** write to correct byte position in vecreg*/
|
|
+ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
|
|
+ }
|
|
+
|
|
+ return VLYNQ_SUCCESS;
|
|
+}
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * function : vlynq_interrupt_get_type()
|
|
+ * description:returns interrupt type .
|
|
+ */
|
|
+int vlynq_interrupt_get_type( VLYNQ_DEV *pdev, VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int map_vector)
|
|
+{
|
|
+ volatile unsigned int * vecreg;
|
|
+ unsigned int val=0;
|
|
+ int int_vector;
|
|
+
|
|
+ if (map_vector > (VLYNQ_NUM_INT_BITS-1))
|
|
+ return(-1);
|
|
+
|
|
+ /* get the int_vector from map_vector */
|
|
+ int_vector = pdev->vector_map[map_vector];
|
|
+ if(int_vector == -1)
|
|
+ return VLYNQ_INTVEC_MAP_NOT_FOUND;
|
|
+
|
|
+ /* use the lower 8 bits of val to set the value , shift it to
|
|
+ * appropriate byte position in the ivr and write it to the
|
|
+ * corresponding register */
|
|
+ if (dev_type == VLYNQ_LOCAL_DVC)
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+
|
|
+ /** Read the correct bit position into val **/
|
|
+ val = (*vecreg) & ((VLYNQ_IVR_INTTYPE_MASK << ( (int_vector %4)*8) ) );
|
|
+
|
|
+ return (val ? (VLYNQ_INTR_PULSED) : (VLYNQ_INTR_LEVEL));
|
|
+}
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * function : vlynq_interrupt_enable()
|
|
+ * description:Enable interrupt by writing to IVR register.
|
|
+ */
|
|
+int vlynq_interrupt_enable( VLYNQ_DEV *pdev,
|
|
+ VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int map_vector)
|
|
+{
|
|
+ volatile unsigned int * vecreg;
|
|
+ unsigned int val=0;
|
|
+ int int_vector;
|
|
+
|
|
+ /** mask to turn off bits corresponding to interrupt enable */
|
|
+ unsigned int bytemask=0x80;
|
|
+
|
|
+ /* get the int_vector from map_vector */
|
|
+ int_vector = pdev->vector_map[map_vector];
|
|
+ if(int_vector == -1)
|
|
+ return VLYNQ_INTVEC_MAP_NOT_FOUND;
|
|
+
|
|
+ /* use the lower 8 bits of val to set the value , shift it to
|
|
+ * appropriate byte position in the ivr and write it to the
|
|
+ * corresponding register */
|
|
+
|
|
+ if (dev_type == VLYNQ_LOCAL_DVC)
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+
|
|
+ /** val has been initialised to zero. we only have to turn on
|
|
+ * bit corresponding to interrupt enable*/
|
|
+ val |= VLYNQ_IVR_INTEN_MASK;
|
|
+
|
|
+ /** clear the correct byte position and then or val **/
|
|
+ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
|
|
+
|
|
+ /** write to correct byte position in vecreg*/
|
|
+ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
|
|
+
|
|
+ return VLYNQ_SUCCESS;
|
|
+}
|
|
+
|
|
+
|
|
+/* ----------------------------------------------------------------------------
|
|
+ * function : vlynq_interrupt_disable()
|
|
+ * description:Disable interrupt by writing to IVR register.
|
|
+ */
|
|
+int
|
|
+vlynq_interrupt_disable( VLYNQ_DEV *pdev,
|
|
+ VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int map_vector)
|
|
+{
|
|
+ volatile unsigned int * vecreg;
|
|
+ int int_vector;
|
|
+
|
|
+ /** mask to turn off bits corresponding to interrupt enable */
|
|
+ unsigned int bytemask=0x80;
|
|
+
|
|
+ /* get the int_vector from map_vector */
|
|
+ int_vector = pdev->vector_map[map_vector];
|
|
+ if(int_vector == -1)
|
|
+ return VLYNQ_INTVEC_MAP_NOT_FOUND;
|
|
+
|
|
+ /* use the lower 8 bits of val to set the value , shift it to
|
|
+ * appropriate byte position in the ivr and write it to the
|
|
+ * corresponding register */
|
|
+ if (dev_type == VLYNQ_LOCAL_DVC)
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
|
|
+ }
|
|
+
|
|
+ /* We disable the interrupt by simply turning off the bit
|
|
+ * corresponding to Interrupt enable.
|
|
+ * Clear the interrupt enable bit in the correct byte position **/
|
|
+ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
|
|
+
|
|
+ /* Dont have to set any bit positions */
|
|
+
|
|
+ return VLYNQ_SUCCESS;
|
|
+
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+
|
|
diff -urN linux.old/drivers/char/Config.in linux.dev/drivers/char/Config.in
|
|
--- linux.old/drivers/char/Config.in 2005-07-22 06:47:42.777975272 +0200
|
|
+++ linux.dev/drivers/char/Config.in 2005-07-22 06:48:54.359093288 +0200
|
|
@@ -192,6 +192,13 @@
|
|
tristate 'Total Impact briQ front panel driver' CONFIG_BRIQ_PANEL
|
|
fi
|
|
|
|
+if [ "$CONFIG_AR7" = "y" ]; then
|
|
+ bool 'VLYNQ support for the TI SOC' CONFIG_AR7_VLYNQ
|
|
+ dep_bool 'VLYNQ clock source Internal' CONFIG_VLYNQ_CLK_LOCAL $CONFIG_AR7_VLYNQ
|
|
+
|
|
+ define_int CONFIG_AR7_VLYNQ_PORTS 2
|
|
+fi
|
|
+
|
|
source drivers/i2c/Config.in
|
|
|
|
mainmenu_option next_comment
|
|
diff -urN linux.old/drivers/char/Makefile linux.dev/drivers/char/Makefile
|
|
--- linux.old/drivers/char/Makefile 2005-07-22 06:47:35.151134728 +0200
|
|
+++ linux.dev/drivers/char/Makefile 2005-07-22 06:32:53.360187328 +0200
|
|
@@ -191,6 +191,13 @@
|
|
endif
|
|
|
|
#
|
|
+# Texas Intruments VLYNQ driver
|
|
+#
|
|
+
|
|
+subdir-$(CONFIG_AR7_VLYNQ) += avalanche_vlynq
|
|
+obj-$(CONFIG_AR7_VLYNQ) += avalanche_vlynq/avalanche_vlynq.o
|
|
+
|
|
+#
|
|
# Texas Intruments LED driver
|
|
#
|
|
obj-$(CONFIG_AR7_LED) += avalanche_led/avalanche_led.o
|
|
diff -urN linux.old/include/asm-mips/ar7/vlynq.h linux.dev/include/asm-mips/ar7/vlynq.h
|
|
--- linux.old/include/asm-mips/ar7/vlynq.h 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux.dev/include/asm-mips/ar7/vlynq.h 2005-07-22 06:32:53.361187176 +0200
|
|
@@ -0,0 +1,610 @@
|
|
+/***************************************************************************
|
|
+**+----------------------------------------------------------------------+**
|
|
+**| **** |**
|
|
+**| **** |**
|
|
+**| ******o*** |**
|
|
+**| ********_///_**** |**
|
|
+**| ***** /_//_/ **** |**
|
|
+**| ** ** (__/ **** |**
|
|
+**| ********* |**
|
|
+**| **** |**
|
|
+**| *** |**
|
|
+**| |**
|
|
+**| Copyright (c) 2003 Texas Instruments Incorporated |**
|
|
+**| ALL RIGHTS RESERVED |**
|
|
+**| |**
|
|
+**| Permission is hereby granted to licensees of Texas Instruments |**
|
|
+**| Incorporated (TI) products to use this computer program for the sole |**
|
|
+**| purpose of implementing a licensee product based on TI products. |**
|
|
+**| No other rights to reproduce, use, or disseminate this computer |**
|
|
+**| program, whether in part or in whole, are granted. |**
|
|
+**| |**
|
|
+**| TI makes no representation or warranties with respect to the |**
|
|
+**| performance of this computer program, and specifically disclaims |**
|
|
+**| any responsibility for any damages, special or consequential, |**
|
|
+**| connected with the use of this program. |**
|
|
+**| |**
|
|
+**+----------------------------------------------------------------------+**
|
|
+***************************************************************************/
|
|
+
|
|
+/*********************************************************************************
|
|
+ * ------------------------------------------------------------------------------
|
|
+ * Module : vlynq_hal.h
|
|
+ * Description :
|
|
+ * This header file provides the set of functions exported by the
|
|
+ * VLYNQ HAL. This file is included from the SOC specific VLYNQ driver wrapper.
|
|
+ * ------------------------------------------------------------------------------
|
|
+ *********************************************************************************/
|
|
+
|
|
+#ifndef _VLYNQ_HAL_H_
|
|
+#define _VLYNQ_HAL_H_
|
|
+
|
|
+/* Enable/Disable debug feature */
|
|
+#undef VLYNQ_DEBUG
|
|
+
|
|
+#ifdef VLYNQ_DEBUG /* This needs to be OS abstracted - for testing use vxworks/linux calls */
|
|
+#define debugPrint(format,args...)
|
|
+#else
|
|
+#define debugPrint(format,args...)
|
|
+#endif
|
|
+
|
|
+ /* number of VLYNQ memory regions supported */
|
|
+#define VLYNQ_MAX_MEMORY_REGIONS 0x04
|
|
+
|
|
+ /* Max.number of external interrupt inputs supported by VLYNQ module */
|
|
+#define VLYNQ_IVR_MAXIVR 0x08
|
|
+
|
|
+#define VLYNQ_CLK_DIV_MAX 0x08
|
|
+#define VLYNQ_CLK_DIV_MIN 0x01
|
|
+
|
|
+
|
|
+/*** the total number of entries allocated for ICB would be
|
|
+ * 32(for 32 bits in IntPending register) + VLYNQ_IVR_CHAIN_SLOTS*/
|
|
+#define VLYNQ_IVR_CHAIN_SLOTS 10
|
|
+
|
|
+
|
|
+/* Error defines */
|
|
+#define VLYNQ_SUCCESS 0
|
|
+
|
|
+#define VLYNQ_ERRCODE_BASE 0 /* Chosen by system */
|
|
+#define VLYNQ_INVALID_ARG -(VLYNQ_ERRCODE_BASE+1)
|
|
+#define VLYNQ_INVALID_DRV_STATE -(VLYNQ_ERRCODE_BASE+2)
|
|
+#define VLYNQ_INT_CONFIG_ERR -(VLYNQ_ERRCODE_BASE+3)
|
|
+#define VLYNQ_LINK_DOWN -(VLYNQ_ERRCODE_BASE+4)
|
|
+#define VLYNQ_MEMALLOC_FAIL -(VLYNQ_ERRCODE_BASE+5)
|
|
+#define VLYNQ_ISR_NON_EXISTENT -(VLYNQ_ERRCODE_BASE+6)
|
|
+#define VLYNQ_INTVEC_MAP_NOT_FOUND -(VLYNQ_ERRCODE_BASE+7)
|
|
+
|
|
+/* Vlynq Defines and Macros */
|
|
+
|
|
+#define VLYNQ_NUM_INT_BITS 32 /* 32 bit interrupt staus register */
|
|
+
|
|
+/* Base address of module */
|
|
+#define VLYNQ_BASE (pdev->module_base)
|
|
+
|
|
+#define VLYNQ_REMOTE_REGS_OFFSET 0x0080
|
|
+
|
|
+#define VLYNQ_REV_OFFSET 0x0000
|
|
+#define VLYNQ_CTRL_OFFSET 0x0004
|
|
+#define VLYNQ_STATUS_OFFSET 0x0008
|
|
+#define VLYNQ_INT_STAT_OFFSET 0x0010
|
|
+#define VLYNQ_INT_PEND_OFFSET 0x0014
|
|
+#define VLYNQ_INT_PTR_OFFSET 0x0018
|
|
+#define VLYNQ_TXMAP_OFFSET 0x001c
|
|
+
|
|
+#define VLYNQ_RX0MAP_SIZE_REG_OFFSET 0x0020
|
|
+#define VLYNQ_RX0MAP_OFFSET_REG_OFFSET 0x0024
|
|
+
|
|
+#define VLYNQ_CHIP_VER_OFFSET 0x0040
|
|
+#define VLYNQ_IVR_REGS_OFFSET 0x0060
|
|
+
|
|
+#define VLYNQ_INT_PENDING_REG_PTR 0x14
|
|
+#define VLYNQ_R_INT_PENDING_REG_PTR VLYNQ_REMOTE_REGS_OFFSET + 0x14
|
|
+
|
|
+#define VLYNQ_REV_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_REV_OFFSET))
|
|
+#define VLYNQ_CTRL_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_CTRL_OFFSET))
|
|
+#define VLYNQ_STATUS_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_STATUS_OFFSET))
|
|
+#define VLYNQ_INT_STAT_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_INT_STAT_OFFSET))
|
|
+#define VLYNQ_INT_PEND_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_INT_PEND_OFFSET))
|
|
+#define VLYNQ_INT_PTR_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_INT_PTR_OFFSET))
|
|
+#define VLYNQ_TXMAP_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_TXMAP_OFFSET))
|
|
+
|
|
+/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
|
|
+#define VLYNQ_RXMAP_SIZE_REG(map) \
|
|
+ *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_RX0MAP_SIZE_REG_OFFSET+( (map-1)<<3)))
|
|
+
|
|
+/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
|
|
+#define VLYNQ_RXMAP_OFFSET_REG(map) \
|
|
+ *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_RX0MAP_OFFSET_REG_OFFSET+( (map-1)<<3)))
|
|
+
|
|
+#define VLYNQ_CHIP_VER_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_CHIP_VER_OFFSET))
|
|
+
|
|
+/* 0 =< ivr <= 31; currently ivr < VLYNQ_IVR_MAXIVR=8) */
|
|
+#define VLYNQ_IVR_OFFSET(ivr) \
|
|
+ (VLYNQ_BASE + VLYNQ_IVR_REGS_OFFSET +((((unsigned)(ivr)) & 31) & ~3) )
|
|
+
|
|
+#define VLYNQ_IVR_03TO00_REG *((volatile unsigned int*) (VLYNQ_IVR_OFFSET(0)) )
|
|
+#define VLYNQ_IVR_07TO04_REG *((volatile unsigned int*) (VLYNQ_IVR_OFFSET(4)) )
|
|
+/*** Can be extended for 11TO08...31TO28 when all 31 are supported**/
|
|
+
|
|
+#define VLYNQ_IVR_INTEN(ivr) (((unsigned int)(0x80)) << ((((unsigned)(ivr)) % 4) * 8))
|
|
+#define VLYNQ_IVR_INTTYPE(ivr) (((unsigned int)(0x40)) << ((((unsigned)(ivr)) % 4) * 8))
|
|
+#define VLYNQ_IVR_INTPOL(ivr) (((unsigned int)(0x20)) << ((((unsigned)(ivr)) % 4) * 8))
|
|
+#define VLYNQ_IVR_INTVEC(ivr) (((unsigned int)(0x1F)) << ((((unsigned)(ivr)) % 4) * 8))
|
|
+#define VLYNQ_IVR_INTALL(ivr) (((unsigned int)(0xFF)) << ((((unsigned)(ivr)) % 4) * 8))
|
|
+
|
|
+
|
|
+
|
|
+/*********************************
|
|
+ * Remote VLYNQ register set *
|
|
+ *********************************/
|
|
+
|
|
+#define VLYNQ_R_REV_OFFSET 0x0080
|
|
+#define VLYNQ_R_CTRL_OFFSET 0x0084
|
|
+#define VLYNQ_R_STATUS_OFFSET 0x0088
|
|
+#define VLYNQ_R_INT_STAT_OFFSET 0x0090
|
|
+#define VLYNQ_R_INT_PEND_OFFSET 0x0094
|
|
+#define VLYNQ_R_INT_PTR_OFFSET 0x0098
|
|
+#define VLYNQ_R_TXMAP_OFFSET 0x009c
|
|
+
|
|
+#define VLYNQ_R_RX0MAP_SIZE_REG_OFFSET 0x00A0
|
|
+#define VLYNQ_R_RX0MAP_OFFSET_REG_OFFSET 0x00A4
|
|
+
|
|
+#define VLYNQ_R_CHIP_VER_OFFSET 0x00C0
|
|
+#define VLYNQ_R_IVR_REGS_OFFSET 0x00E0
|
|
+
|
|
+#define VLYNQ_R_REV_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_REV_OFFSET))
|
|
+#define VLYNQ_R_CTRL_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_CTRL_OFFSET))
|
|
+#define VLYNQ_R_STATUS_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_STATUS_OFFSET))
|
|
+#define VLYNQ_R_INT_STAT_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_INT_STAT_OFFSET))
|
|
+#define VLYNQ_R_INT_PEND_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_INT_PEND_OFFSET))
|
|
+#define VLYNQ_R_INT_PTR_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_INT_PTR_OFFSET))
|
|
+#define VLYNQ_R_TXMAP_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_TXMAP_OFFSET))
|
|
+
|
|
+/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
|
|
+#define VLYNQ_R_RXMAP_SIZE_REG(map) \
|
|
+ *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_RX0MAP_SIZE_REG_OFFSET + ((map-1)<<3)))
|
|
+
|
|
+/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
|
|
+#define VLYNQ_R_RXMAP_OFFSET_REG(map) \
|
|
+ *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_RX0MAP_OFFSET_REG_OFFSET + ((map-1)<<3)))
|
|
+
|
|
+#define VLYNQ_R_CHIP_VER_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_CHIP_VER_OFFSET)
|
|
+
|
|
+#define VLYNQ_R_IVR_OFFSET(ivr) \
|
|
+ (VLYNQ_BASE + VLYNQ_R_IVR_REGS_OFFSET +((((unsigned)(ivr)) & 31) & ~3))
|
|
+
|
|
+
|
|
+/*** Can be extended for 11TO08...31TO28 when all 31 are supported**/
|
|
+#define VLYNQ_R_IVR_03TO00_REG *((volatile unsigned int*) (VLYNQ_R_IVR_OFFSET(0)) )
|
|
+#define VLYNQ_R_IVR_07TO04_REG *((volatile unsigned int*) (VLYNQ_R_IVR_OFFSET(4)) )
|
|
+
|
|
+
|
|
+/****End of remote register set definition******/
|
|
+
|
|
+
|
|
+/*** Masks for individual register fields ***/
|
|
+
|
|
+#define VLYNQ_MODULE_ID_MASK 0xffff0000
|
|
+#define VLYNQ_MAJOR_REV_MASK 0x0000ff00
|
|
+#define VLYNQ_MINOR_REV_MASK 0x000000ff
|
|
+
|
|
+
|
|
+#define VLYNQ_CTL_ILOOP_MASK 0x00000002
|
|
+#define VLYNQ_CTL_INT2CFG_MASK 0x00000080
|
|
+#define VLYNQ_CTL_INTVEC_MASK 0x00001f00
|
|
+#define VLYNQ_CTL_INTEN_MASK 0x00002000
|
|
+#define VLYNQ_CTL_INTLOCAL_MASK 0x00004000
|
|
+#define VLYNQ_CTL_CLKDIR_MASK 0x00008000
|
|
+#define VLYNQ_CTL_CLKDIV_MASK 0x00070000
|
|
+#define VLYNQ_CTL_MODE_MASK 0x00e00000
|
|
+
|
|
+
|
|
+#define VLYNQ_STS_LINK_MASK 0x00000001 /* Link is active */
|
|
+#define VLYNQ_STS_MPEND_MASK 0x00000002 /* Pending master requests */
|
|
+#define VLYNQ_STS_SPEND_MASK 0x00000004 /* Pending slave requests */
|
|
+#define VLYNQ_STS_NFEMPTY0_MASK 0x00000008 /* Master data FIFO not empty */
|
|
+#define VLYNQ_STS_NFEMPTY1_MASK 0x00000010 /* Master command FIFO not empty */
|
|
+#define VLYNQ_STS_NFEMPTY2_MASK 0x00000020 /* Slave data FIFO not empty */
|
|
+#define VLYNQ_STS_NFEMPTY3_MASK 0x00000040 /* Slave command FIFO not empty */
|
|
+#define VLYNQ_STS_LERROR_MASK 0x00000080 /* Local error, w/c */
|
|
+#define VLYNQ_STS_RERROR_MASK 0x00000100 /* remote error w/c */
|
|
+#define VLYNQ_STS_OFLOW_MASK 0x00000200
|
|
+#define VLYNQ_STS_IFLOW_MASK 0x00000400
|
|
+#define VLYNQ_STS_MODESUP_MASK 0x00E00000 /* Highest mode supported */
|
|
+#define VLYNQ_STS_SWIDTH_MASK 0x07000000 /* Used for reading the width of VLYNQ bus */
|
|
+#define VLYNQ_STS_DEBUG_MASK 0xE0000000
|
|
+
|
|
+#define VLYNQ_CTL_INTVEC_SHIFT 0x08
|
|
+#define VLYNQ_CTL_INTEN_SHIFT 0x0D
|
|
+#define VLYNQ_CTL_INT2CFG_SHIFT 0x07
|
|
+#define VLYNQ_CTL_INTLOCAL_SHIFT 0x0E
|
|
+
|
|
+#define VLYNQ_CTL_INTFIELDS_CLEAR_MASK 0x7F80
|
|
+
|
|
+#define VLYNQ_CHIPVER_DEVREV_MASK 0xffff0000
|
|
+#define VLYNQ_CHIPVER_DEVID_MASK 0x0000ffff
|
|
+
|
|
+#define VLYNQ_IVR_INTEN_MASK 0x80
|
|
+#define VLYNQ_IVR_INTTYPE_MASK 0x40
|
|
+#define VLYNQ_IVR_INTPOL_MASK 0x20
|
|
+
|
|
+
|
|
+/**** Helper macros ****/
|
|
+
|
|
+#define VLYNQ_RESETCB(arg) \
|
|
+ if( pdev->reset_cb != NULL) \
|
|
+ { \
|
|
+ (pdev->reset_cb)(pdev, (arg)); \
|
|
+ }
|
|
+
|
|
+#define VLYNQ_STATUS_FLD_WIDTH(sts) (((sts) & VLYNQ_STS_SWIDTH_MASK) >> 24 )
|
|
+#define VLYNQ_CTL_INTVEC(x) (((x) & 31) << 8 )
|
|
+
|
|
+#define VLYNQ_INRANGE(x,hi,lo) (((x) <= (hi)) && ((x) >= (lo)))
|
|
+#define VLYNQ_OUTRANGE(x,hi,lo) (((x) > (hi)) || ((x) < (lo)))
|
|
+
|
|
+#define VLYNQ_ALIGN4(x) (x)=(x)&(~3)
|
|
+
|
|
+
|
|
+/*************************************
|
|
+ * Enums *
|
|
+ *************************************/
|
|
+
|
|
+/* Initialization options define what operations are
|
|
+ * undertaken during vlynq module initialization */
|
|
+typedef enum
|
|
+{
|
|
+ /* Init host local memory regions.This allows
|
|
+ * local host access remote memory regions */
|
|
+ VLYNQ_INIT_LOCAL_MEM_REGIONS = 0x01,
|
|
+ /* Init host remote memory regions.This allows
|
|
+ * remote device access local memory regions */
|
|
+ VLYNQ_INIT_REMOTE_MEM_REGIONS =0x02,
|
|
+ /* Init local interrupt config*/
|
|
+ VLYNQ_INIT_LOCAL_INTERRUPTS =0x04,
|
|
+ /* Init remote interrupt config*/
|
|
+ VLYNQ_INIT_REMOTE_INTERRUPTS =0x08,
|
|
+ /* Check link during initialization*/
|
|
+ VLYNQ_INIT_CHECK_LINK =0x10,
|
|
+ /* configure clock during init */
|
|
+ VLYNQ_INIT_CONFIG_CLOCK =0x20,
|
|
+ /* Clear errors during init */
|
|
+ VLYNQ_INIT_CLEAR_ERRORS =0x40,
|
|
+ /* All options */
|
|
+ VLYNQ_INIT_PERFORM_ALL =0x7F
|
|
+}VLYNQ_INIT_OPTIONS;
|
|
+
|
|
+
|
|
+/* VLYNQ_DEV_TYPE identifies local or remote device */
|
|
+typedef enum
|
|
+{
|
|
+ VLYNQ_LOCAL_DVC = 0, /* vlynq local device (SOC's vlynq module) */
|
|
+ VLYNQ_REMOTE_DVC = 1 /* vlynq remote device (remote vlynq module) */
|
|
+}VLYNQ_DEV_TYPE;
|
|
+
|
|
+
|
|
+/* VLYNQ_CLK_SOURCE identifies the vlynq module clock source */
|
|
+typedef enum
|
|
+{
|
|
+ VLYNQ_CLK_SOURCE_NONE = 0, /* do not initialize clock generator*/
|
|
+ VLYNQ_CLK_SOURCE_LOCAL = 1, /* clock is generated by local machine */
|
|
+ VLYNQ_CLK_SOURCE_REMOTE = 2 /* clock is generated by remote machine */
|
|
+}VLYNQ_CLK_SOURCE;
|
|
+
|
|
+
|
|
+/* VLYNQ_DRV_STATE indicates the current driver state */
|
|
+typedef enum
|
|
+{
|
|
+ VLYNQ_DRV_STATE_UNINIT = 0, /* driver is uninitialized */
|
|
+ VLYNQ_DRV_STATE_ININIT = 1, /* VLYNQ is being initialized */
|
|
+ VLYNQ_DRV_STATE_RUN = 2, /* VLYNQ is running properly */
|
|
+ VLYNQ_DRV_STATE_HOLD = 3, /* driver stopped temporarily */
|
|
+ VLYNQ_DRV_STATE_ERROR = 4 /* driver stopped on unrecoverable error */
|
|
+}VLYNQ_DRV_STATE;
|
|
+
|
|
+
|
|
+/* VLYNQ_BUS_WIDTH identifies the vlynq module bus width */
|
|
+typedef enum
|
|
+{
|
|
+ VLYNQ_BUS_WIDTH_3 = 3,
|
|
+ VLYNQ_BUS_WIDTH_5 = 5,
|
|
+ VLYNQ_BUS_WIDTH_7 = 7,
|
|
+ VLYNQ_BUS_WIDTH_9 = 9
|
|
+}VLYNQ_BUS_WIDTH;
|
|
+
|
|
+
|
|
+/* VLYNQ_LOCAL_INT_CONFIG indicates whether the local vlynq
|
|
+ * interrupts are processed by the host or passed on to the
|
|
+ * remote device.
|
|
+ */
|
|
+typedef enum
|
|
+{
|
|
+ VLYNQ_INT_REMOTE = 0, /* Interrupt packets sent to remote, intlocal=0 */
|
|
+ VLYNQ_INT_LOCAL = 1 /* Interrupts are handled locally, intlocal=1 */
|
|
+}VLYNQ_LOCAL_INT_CONFIG;
|
|
+
|
|
+
|
|
+/* VLYNQ_REMOTE_INT_CONFIG indicates whether the remote
|
|
+ * interrupts are to be handled by the SOC system ISR
|
|
+ * or via the vlynq root ISR
|
|
+ */
|
|
+typedef enum
|
|
+{
|
|
+ VLYNQ_INT_ROOT_ISR = 0, /* remote ints handled via vlynq root ISR */
|
|
+ VLYNQ_INT_SYSTEM_ISR = 1 /* remote ints handled via system ISR */
|
|
+}VLYNQ_REMOTE_INT_CONFIG;
|
|
+
|
|
+
|
|
+/* VLYNQ_INTR_POLARITY - vlynq interrupt polarity setting */
|
|
+typedef enum
|
|
+{
|
|
+ VLYNQ_INTR_ACTIVE_HIGH = 0,
|
|
+ VLYNQ_INTR_ACTIVE_LOW = 1
|
|
+}VLYNQ_INTR_POLARITY;
|
|
+
|
|
+
|
|
+/* VLYNQ_INTR_TYPE - vlynq interrupt type */
|
|
+typedef enum
|
|
+{
|
|
+ VLYNQ_INTR_LEVEL = 0,
|
|
+ VLYNQ_INTR_PULSED = 1
|
|
+}VLYNQ_INTR_TYPE;
|
|
+
|
|
+
|
|
+/* VLYNQ_RESET_MODE - vlynq reset mode */
|
|
+typedef enum
|
|
+{
|
|
+ VLYNQ_RESET_ASSERT, /* hold device in reset state */
|
|
+ VLYNQ_RESET_DEASSERT, /* release device from reset state */
|
|
+ VLYNQ_RESET_INITFAIL, /* handle the device in case driver initialization fails */
|
|
+ VLYNQ_RESET_LINKESTABLISH, /* handle the device in case driver established link */
|
|
+ VLYNQ_RESET_INITFAIL2, /* Driver initialization failed but VLYNQ link exist. */
|
|
+ VLYNQ_RESET_INITOK /* Driver initialization finished OK. */
|
|
+}VLYNQ_RESET_MODE;
|
|
+
|
|
+
|
|
+
|
|
+/*************************************
|
|
+ * Typedefs *
|
|
+ *************************************/
|
|
+
|
|
+struct VLYNQ_DEV_t; /*forward declaration*/
|
|
+
|
|
+/*--------Function Pointers defintions -----------*/
|
|
+
|
|
+/* prototype for interrupt handler definition */
|
|
+typedef void (*VLYNQ_INTR_CNTRL_ISR)(void *arg1,void *arg2,void *arg3);
|
|
+
|
|
+typedef void
|
|
+(*VLYNQ_RESET_REMOTE)(struct VLYNQ_DEV_t *pDev, VLYNQ_RESET_MODE mode);
|
|
+
|
|
+typedef void
|
|
+(*VLYNQ_REPORT_CB)( struct VLYNQ_DEV_t *pDev, /* This VLYNQ */
|
|
+ VLYNQ_DEV_TYPE aSrcDvc, /* Event Cause -local/remote? */
|
|
+ unsigned int dwStatRegVal); /* Value of the relevant status register */
|
|
+
|
|
+
|
|
+/*-------Structure Definitions------------*/
|
|
+
|
|
+typedef struct VLYNQ_MEMORY_MAP_t
|
|
+{
|
|
+ unsigned int Txmap;
|
|
+ unsigned int RxOffset[VLYNQ_MAX_MEMORY_REGIONS];
|
|
+ unsigned int RxSize[VLYNQ_MAX_MEMORY_REGIONS];
|
|
+}VLYNQ_MEMORY_MAP;
|
|
+
|
|
+
|
|
+/**VLYNQ_INTERRUPT_CNTRL - defines the vlynq module interrupt
|
|
+ * settings in vlynq Control register */
|
|
+typedef struct VLYNQ_INTERRUPT_CNTRL_t
|
|
+{
|
|
+ /* vlynq interrupts handled by host or remote - maps to
|
|
+ * intLocal bit in vlynq control register */
|
|
+ VLYNQ_LOCAL_INT_CONFIG intLocal;
|
|
+
|
|
+ /* remote interrupts handled by vlynq isr or host system
|
|
+ * interrupt controller - maps to the int2Cfg in vlynq
|
|
+ * control register */
|
|
+ VLYNQ_REMOTE_INT_CONFIG intRemote;
|
|
+
|
|
+ /* bit in pending/set register used for module interrupts*/
|
|
+ unsigned int map_vector;
|
|
+
|
|
+ /* used only if remote interrupts are to be handled by system ISR*/
|
|
+ unsigned int intr_ptr;
|
|
+
|
|
+}VLYNQ_INTERRUPT_CNTRL;
|
|
+
|
|
+
|
|
+/* VLYNQ_INTR_CNTRL_ICB - defines the Interrupt control block which hold
|
|
+ * the interrupt dispatch table. The vlynq_root_isr() indexes into this
|
|
+ * table to identify the ISR to be invoked
|
|
+ */
|
|
+typedef struct VLYNQ_INTR_CNTRL_ICB_t
|
|
+{
|
|
+ VLYNQ_INTR_CNTRL_ISR isr; /* Clear errors during initialization */
|
|
+ void *arg1 ; /* Arg 1 for the ISR */
|
|
+ void *arg2 ; /* Arg 2 for the ISR */
|
|
+ void *arg3 ; /* Arg 3 for the ISR */
|
|
+ unsigned int isrCount; /* number of ISR invocations so far */
|
|
+ struct VLYNQ_INTR_CNTRL_ICB_t *next;
|
|
+}VLYNQ_INTR_CNTRL_ICB;
|
|
+
|
|
+/* overlay of vlynq register set */
|
|
+typedef struct VLYNQ_REG_SET_t
|
|
+{
|
|
+ unsigned int revision; /*offset : 0x00 */
|
|
+ unsigned int control; /* 0x04*/
|
|
+ unsigned int status; /* 0x08*/
|
|
+ unsigned int pad1; /* 0x0c*/
|
|
+ unsigned int intStatus; /*0x10*/
|
|
+ unsigned int intPending; /*0x14*/
|
|
+ unsigned int intPtr; /*0x18*/
|
|
+ unsigned int txMap; /*0x1C*/
|
|
+ unsigned int rxSize1; /*0x20*/
|
|
+ unsigned int rxOffset1; /*0x24*/
|
|
+ unsigned int rxSize2; /*0x28*/
|
|
+ unsigned int rxOffset2; /*0x2C*/
|
|
+ unsigned int rxSize3; /*0x30*/
|
|
+ unsigned int rxOffset3; /*0x34*/
|
|
+ unsigned int rxSize4; /*0x38*/
|
|
+ unsigned int rxOffset4; /*0x3C*/
|
|
+ unsigned int chipVersion; /*0x40*/
|
|
+ unsigned int pad2[8];
|
|
+ unsigned int ivr30; /*0x60*/
|
|
+ unsigned int ivr74; /*0x64*/
|
|
+ unsigned int pad3[7];
|
|
+}VLYNQ_REG_SET;
|
|
+
|
|
+
|
|
+typedef struct VLYNQ_DEV_t
|
|
+{
|
|
+ /** module index:1,2,3... used for debugging purposes */
|
|
+ unsigned int dev_idx;
|
|
+
|
|
+ /*VLYNQ module base address */
|
|
+ unsigned int module_base;
|
|
+
|
|
+ /* clock source selection */
|
|
+ VLYNQ_CLK_SOURCE clk_source;
|
|
+
|
|
+ /* Clock Divider.Val=1 to 8. VLYNQ_clk = VBUSCLK/clk_div */
|
|
+ unsigned int clk_div;
|
|
+
|
|
+ /* State of the VLYNQ driver, set to VLYNQ_DRV_STATE_UNINIT, when initializing */
|
|
+ VLYNQ_DRV_STATE state;
|
|
+
|
|
+ /* Valid VLYNQ bus width, filled by driver */
|
|
+ VLYNQ_BUS_WIDTH width;
|
|
+
|
|
+ /* local memory mapping */
|
|
+ VLYNQ_MEMORY_MAP local_mem;
|
|
+
|
|
+ /* remote memory mapping */
|
|
+ VLYNQ_MEMORY_MAP remote_mem;
|
|
+
|
|
+ /* Local module interrupt params */
|
|
+ VLYNQ_INTERRUPT_CNTRL local_irq;
|
|
+
|
|
+ /* remote module interrupt params */
|
|
+ VLYNQ_INTERRUPT_CNTRL remote_irq;
|
|
+
|
|
+ /*** ICB related fields **/
|
|
+
|
|
+ /* Sizeof of ICB = VLYNQ_NUM_INT_BITS(for 32 bits in IntPending) +
|
|
+ * expansion slots for shared interrupts*/
|
|
+ VLYNQ_INTR_CNTRL_ICB pIntrCB[VLYNQ_NUM_INT_BITS + VLYNQ_IVR_CHAIN_SLOTS];
|
|
+ VLYNQ_INTR_CNTRL_ICB *freelist;
|
|
+
|
|
+ /* table holding mapping between intVector and the bit position the interrupt
|
|
+ * is mapped to(mapVector)*/
|
|
+ char vector_map[32];
|
|
+
|
|
+ /* user callback for vlynq events, NULL if unused */
|
|
+ VLYNQ_REPORT_CB report_cb;
|
|
+
|
|
+ /* user callback for resetting/realeasing remote device */
|
|
+ VLYNQ_RESET_REMOTE reset_cb;
|
|
+
|
|
+ /*** Handles provided for direct access to register set if need be
|
|
+ * Must be intialized to point to appropriate address during
|
|
+ * vlynq_init */
|
|
+ volatile VLYNQ_REG_SET * local;
|
|
+ volatile VLYNQ_REG_SET * remote;
|
|
+
|
|
+ unsigned int intCount; /* number of interrupts generated so far */
|
|
+ unsigned int isrCount; /* number of ISR invocations so far */
|
|
+}VLYNQ_DEV;
|
|
+
|
|
+
|
|
+typedef struct VLYNQ_ISR_ARGS_t
|
|
+{
|
|
+ int irq;
|
|
+ void * arg;
|
|
+ void * regset;
|
|
+}VLYNQ_ISR_ARGS;
|
|
+
|
|
+
|
|
+/****************************************
|
|
+ * Function Prototypes *
|
|
+ * API exported by generic vlynq driver *
|
|
+ ****************************************/
|
|
+/* Initialization function */
|
|
+int vlynq_init( VLYNQ_DEV *pdev, VLYNQ_INIT_OPTIONS options);
|
|
+
|
|
+/* Check vlynq link */
|
|
+unsigned int vlynq_link_check( VLYNQ_DEV * pdev);
|
|
+
|
|
+/* Set interrupt vector in local or remote device */
|
|
+int vlynq_interrupt_vector_set( VLYNQ_DEV *pdev,
|
|
+ unsigned int int_vector,
|
|
+ unsigned int map_vector,
|
|
+ VLYNQ_DEV_TYPE dev,
|
|
+ VLYNQ_INTR_POLARITY pol,
|
|
+ VLYNQ_INTR_TYPE type);
|
|
+
|
|
+
|
|
+int vlynq_interrupt_vector_cntl( VLYNQ_DEV *pdev,
|
|
+ unsigned int int_vector,
|
|
+ VLYNQ_DEV_TYPE dev,
|
|
+ unsigned int enable);
|
|
+
|
|
+unsigned int vlynq_interrupt_get_count( VLYNQ_DEV *pdev,
|
|
+ unsigned int map_vector);
|
|
+
|
|
+int vlynq_install_isr( VLYNQ_DEV *pdev,
|
|
+ unsigned int map_vector,
|
|
+ VLYNQ_INTR_CNTRL_ISR isr,
|
|
+ void *arg1, void *arg2, void *arg3);
|
|
+
|
|
+int vlynq_uninstall_isr( VLYNQ_DEV *pdev,
|
|
+ unsigned int map_vector,
|
|
+ void *arg1, void *arg2, void *arg3);
|
|
+
|
|
+
|
|
+void vlynq_root_isr(void *arg);
|
|
+
|
|
+void vlynq_delay(unsigned int clktime);
|
|
+
|
|
+/* The following functions, provide better granularity in setting
|
|
+ * interrupt parameters. (for better support of linux INT Controller)
|
|
+ * Note: The interrupt source is identified by "map_vector"- the bit
|
|
+ * position in interrupt status register*/
|
|
+
|
|
+int vlynq_interrupt_vector_map(VLYNQ_DEV * pdev,
|
|
+ VLYNQ_DEV_TYPE dev,
|
|
+ unsigned int int_vector,
|
|
+ unsigned int map_vector);
|
|
+
|
|
+int vlynq_interrupt_set_polarity(VLYNQ_DEV * pdev,
|
|
+ VLYNQ_DEV_TYPE dev,
|
|
+ unsigned int map_vector,
|
|
+ VLYNQ_INTR_POLARITY pol);
|
|
+
|
|
+int vlynq_interrupt_get_polarity( VLYNQ_DEV *pdev ,
|
|
+ VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int map_vector);
|
|
+
|
|
+int vlynq_interrupt_set_type(VLYNQ_DEV * pdev,
|
|
+ VLYNQ_DEV_TYPE dev,
|
|
+ unsigned int map_vector,
|
|
+ VLYNQ_INTR_TYPE type);
|
|
+
|
|
+int vlynq_interrupt_get_type( VLYNQ_DEV *pdev,
|
|
+ VLYNQ_DEV_TYPE dev_type,
|
|
+ unsigned int map_vector);
|
|
+
|
|
+int vlynq_interrupt_enable(VLYNQ_DEV* pdev,
|
|
+ VLYNQ_DEV_TYPE dev,
|
|
+ unsigned int map_vector);
|
|
+
|
|
+int vlynq_interrupt_disable(VLYNQ_DEV * pdev,
|
|
+ VLYNQ_DEV_TYPE dev,
|
|
+ unsigned int map_vector);
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+#endif /* _VLYNQ_HAL_H_ */
|