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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 +#include +#include + +/**** 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; ilocal_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_ */