diff options
author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2005-07-21 20:40:56 +0000 |
---|---|---|
committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2005-07-21 20:40:56 +0000 |
commit | fa0a8c02e1c26cdde57258b9faf144daba02c4d7 (patch) | |
tree | a93d0b31dd73e5c41c152d6f750d9100aa0401ac /openwrt/target/linux/linux-2.4/patches | |
parent | c3b6255ca50a112efdabab8021b158315788cc5f (diff) |
add vlynq support
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@1525 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'openwrt/target/linux/linux-2.4/patches')
-rw-r--r-- | openwrt/target/linux/linux-2.4/patches/ar7/005-vlynq.patch | 2332 |
1 files changed, 2332 insertions, 0 deletions
diff --git a/openwrt/target/linux/linux-2.4/patches/ar7/005-vlynq.patch b/openwrt/target/linux/linux-2.4/patches/ar7/005-vlynq.patch new file mode 100644 index 000000000..eee70c076 --- /dev/null +++ b/openwrt/target/linux/linux-2.4/patches/ar7/005-vlynq.patch @@ -0,0 +1,2332 @@ +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-10 20:50:43.556826000 +0200 ++++ linux.dev/drivers/char/Config.in 2005-07-22 06:32:53.359187480 +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-10 20:50:43.556826000 +0200 ++++ linux.dev/drivers/char/Makefile 2005-07-22 06:32:53.360187328 +0200 +@@ -191,16 +191,23 @@ + endif + + # ++# Texas Intruments VLYNQ driver ++# ++ ++subdir-$(CONFIG_AR7_VLYNQ) += avalanche_vlynq ++obj-$(CONFIG_AR7_VLYNQ) += avalanche_vlynq/avalanche_vlynq.o ++ ++# + # Texas Intruments LED driver + # +-ifeq ($(CONFIG_MIPS_AVALANCHE_LED),y) +-obj-$(CONFIG_MIPS_AVALANCHE_LED) += avalanche_led/avalanche_led.o +-subdir-$(CONFIG_MIPS_AVALANCHE_LED) += avalanche_led ++ifeq ($(CONFIG_AR7_LED),y) ++obj-$(CONFIG_AR7_LED) += avalanche_led/avalanche_led.o ++subdir-$(CONFIG_AR7_LED) += avalanche_led + endif + +-ifeq ($(CONFIG_MIPS_AVALANCHE_LED),m) +-obj-$(CONFIG_MIPS_AVALANCHE_LED) += avalanche_led/avalanche_led.o +-subdir-$(CONFIG_MIPS_AVALANCHE_LED) += avalanche_led ++ifeq ($(CONFIG_AR7_LED),m) ++obj-$(CONFIG_AR7_LED) += avalanche_led/avalanche_led.o ++subdir-$(CONFIG_AR7_LED) += avalanche_led + endif + + obj-$(CONFIG_HIL) += hp_keyb.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_ */ |