/* * linux/arch/arm/mach-dm320/davinci_vlynq_setup.c * * Setup the vlynq on the davinci evm. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Original Version: Eyal Reizer, Texas Instruments Inc * */ #include "davinci_vlynq_setup.h" #include #include "../clock.h" #include #include #ifdef PSP_KERNEL_03 #include #warning "i2c PSP client" #else #warning "i2c client" #include #endif #define PLL1_PLLM __REG(0x01c40910) #define PLL2_PLLM __REG(0x01c40D10) #define PTCMD __REG(0x01C41120) #define PDSTAT __REG(0x01C41200) #define PDCTL1 __REG(0x01C41304) #define EPCPR __REG(0x01C41070) #define PTSTAT __REG(0x01C41128) #define MDSTAT IO_ADDRESS(0x01C41800) #define MDCTL IO_ADDRESS(0x01C41A00) #define VDD3P3V_PWDN __REG(0x01C40048) static char *wlan_reset = "high"; module_param(wlan_reset, charp, 0777); MODULE_PARM_DESC(wlan_reset, "Wlan reset polarity (high/low)"); #ifdef TI_BOARD_SETUP_PSC /*Sascha: Wird bei uns bereits in clocks.c definiert! */ void board_setup_psc(unsigned int domain, unsigned int id, char enable); #endif static unsigned char wlan_reset_val = 0; //extern int davinci_i2c_write(u8 size, u8 * val, u16 client_addr); //extern int davinci_i2c_read(u8 size, u8 * val, u16 client_addr); /********************************************************************/ /* Reset TNETW using the I2C controller */ /* */ /********************************************************************/ int DaVinci_TNETW_Reset(int SetFlag) { u8 val; volatile unsigned int temp; if (SetFlag==IN_RESET) { // printk("--Putting the TNET in Reset--\n"); // val |= ( wlan_reset_val << WLAN_RESET_BIT ); val = wlan_reset_val; } else { // printk("--Taking the TNET out of Reset--\n"); // val |= ( (1-wlan_reset_val) << WLAN_RESET_BIT ); val = 1 - wlan_reset_val; } printk("Write the value %x to the I2C mosulde\n",val); davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, WLAN_RESET, val); #if 0 /* Configure U35 to mux the VLYNQ pins and take the TNET out of reset */ printk("Put the TNET in reset and muxing the VLYNQ pins...\n"); val = 0xfb; // davinci_i2c_write(1, &val, 0x3a); davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, WLAN_RESET, val); /* Delay to make sure GPIOs are stable */ for (temp=0; temp<=20000;temp++); /* Configure U35 to mux the VLYNQ pins and take the TNET out of reset */ printk("Taking the TNET out of reset and muxing the VLYNQ pins...\n"); val = 0xcb; // davinci_i2c_write(1, &val, 0x3a); davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, WLAN_RESET, val); #endif for (temp=0; temp<=20000;temp++); return 0; } /********************************************************************/ /****************V2U to TNETW1130 VLYNQ Setting**********************/ /********************************************************************/ /********************************************************************/ /* arm_1130_vlynq_irq_cfg */ /* */ /********************************************************************/ int arm_1130_vlynq_irq_cfg(void) { IRQ_CONFIG_T *p_irq = &TNETW1x50_irq_config[0]; /* Sets the Polarity of the Hardware IRQ Line */ if(PAL_vlynqSetIrqPol(p_1x50_vlynq, p_irq->irq, pal_vlynq_high_irq_pol)) return(-1); /* Sets the Type of the Hardware IRQ Line */ if(PAL_vlynqSetIrqType(p_1x50_vlynq, p_irq->irq, pal_vlynq_level_irq_type)) return(-1); return(0); } /********************************************************************/ /* arm_1130_vlynq_re_setup */ /* */ /********************************************************************/ int arm_1130_vlynq_re_setup(void) { REGION_CONFIG_T *p_region = &TNETW1x50_region_config[0]; IRQ_CONFIG_T *p_irq = &TNETW1x50_irq_config[0]; vlynq_delay_wait(0xfffff); /* Chack for a link to the remote device */ if(!PAL_vlynqGetLinkStatus(p_1x50_vlynq)) { printk("The Link to peer is down.\n"); return (-1); } printk("Preparing the VLYNQ, now the Link is up. \n"); /* Clears internal interrupt errors */ if(PAL_vlynqIoctl(p_1x50_vlynq, PAL_VLYNQ_IOCTL_MAJOR_VAL(PAL_VLYNQ_IOCTL_CLEAR_INTERN_ERR), 0)) { printk("Failed to clear the internal VLYNQ errors.\n"); return (-1); } /* Setup, now the link is up */ if(PAL_vlynqIoctl(p_1x50_vlynq, PAL_VLYNQ_IOCTL_MAJOR_VAL(PAL_VLYNQ_IOCTL_PREP_LINK_UP), 0)) { printk("Failed to restore the VLYNQ. \n"); return (-1); } while(p_region->id > -1) { /* Maps one Memory Region of the Device */ if(PAL_vlynqMapRegion(p_1x50_vlynq, p_region->remote, p_region->id, p_region->offset, p_region->size, p_vlynq_dev)) { p_region->id = -1; printk("Failed to map the regions.\n"); return (-1); } p_region++; } while(p_irq->hw_intr_line > -1) { /* Maps one IRQ Hardware Line Onto the VLYNQ */ if(PAL_vlynqMapIrq(p_1x50_vlynq, p_irq->hw_intr_line, p_irq->irq, p_vlynq_dev)) { p_irq->hw_intr_line = -1; printk("Failed to map the irq(s).\n"); return(-1); } p_irq++; } /* Sets the polarity and the Type of the Hardware IRQ Line */ if(arm_1130_vlynq_irq_cfg()) { printk("Failed to set irq.\n"); return (-1); } return(0); } /********************************************************************/ /* arm_1130_vlynq_init */ /* */ /********************************************************************/ PAL_Result arm_1130_vlynq_init(void) { REGION_CONFIG_T *p_region = &TNETW1x50_region_config[0]; IRQ_CONFIG_T *p_irq = &TNETW1x50_irq_config[0]; char dev_name[] = "wlan"; int instance = 0; printk("Start the 1350A vlynq initialization\n"); /* Start VLYNQ configuration definition */ vlynq_1x50_config.on_soc = 1; /* VLYNQ on host device (running the code) */ vlynq_1x50_config.base_addr = ARM_VLYNQ_CONTROL_BASE; /* V1 port on V2U */ vlynq_1x50_config.local_clock_dir = pal_vlynq_clk_in; vlynq_1x50_config.local_clock_div = VLYNQ_CLOCK_NO_DIV; vlynq_1x50_config.local_intr_local = True; vlynq_1x50_config.local_intr_vector = 31; vlynq_1x50_config.local_intr_enable = True; vlynq_1x50_config.local_int2cfg = True; vlynq_1x50_config.local_intr_pointer = 0x14; vlynq_1x50_config.local_endianness = pal_vlynq_little_en; vlynq_1x50_config.local_tx_addr = 0; /*ARM_VLYNQ_MEM_MAP_BASE - DaVinci bug !!!!;*/ vlynq_1x50_config.local_rtm_cfg_type = no_rtm_cfg; vlynq_1x50_config.local_rtm_sample_value = 0; /* Do not care as rtm_cfg_type is no_rtm_cfg. */ vlynq_1x50_config.local_tx_fast_path = False; /*TNETW 1x50 */ vlynq_1x50_config.peer_clock_dir = pal_vlynq_clk_out; vlynq_1x50_config.peer_clock_div = VLYNQ_CLOCK_NO_DIV; vlynq_1x50_config.peer_intr_local = False; vlynq_1x50_config.peer_intr_vector = 30; vlynq_1x50_config.peer_intr_enable = True; vlynq_1x50_config.peer_int2cfg = False; vlynq_1x50_config.peer_intr_pointer = 0x14; vlynq_1x50_config.peer_endianness = pal_vlynq_little_en; vlynq_1x50_config.peer_tx_addr = VLYNQ_TNETW1X50_VL0_PORTAL_OFFSET; vlynq_1x50_config.local_rtm_cfg_type = no_rtm_cfg; vlynq_1x50_config.local_rtm_sample_value = 0; /* Do not care as rtm_cfg_type is no_rtm_cfg. */ vlynq_1x50_config.local_tx_fast_path = False; vlynq_1x50_config.init_swap_flag = False; printk("Initializing the 1x50 chip\n"); /* Creates a Device Reference */ p_1x50_vlynq = PAL_vlynqInit(&vlynq_1x50_config); if(!p_1x50_vlynq) { printk("Failed to initialize the vlynq @ 0x%08x.\n", vlynq_1x50_config.base_addr); printk("The error msg: %s.\n", vlynq_1x50_config.error_msg); goto av_vlynq_wlan_init_fail; } /* Save root VLYNQ in global variable for next VLYNQ hop */ p_root_vlynq = p_1x50_vlynq; /* Creates a Device Reference */ p_vlynq_dev = PAL_vlynqDevCreate(p_1x50_vlynq, dev_name, instance, 64, 1); if(!p_vlynq_dev) { printk("Failed to create the %s%d reference for vlynq.\n", dev_name, instance); goto av_vlynq_wlan_dev_fail; } /* Adds the Device Reference into the VLYNQ */ if(PAL_vlynqAddDevice(p_1x50_vlynq, p_vlynq_dev, 1)) { printk("Failed to add %s%d reference into vlynq.\n", dev_name, instance); goto av_vlynq_wlan_add_device_fail; } /* Load the memory regions mapping to the vlynq module registers */ /* Loops until all the regilons are loaded */ while(p_region->id > -1) { /* Maps one Memory Region of the Device */ if(PAL_vlynqMapRegion(p_1x50_vlynq, p_region->remote, p_region->id, p_region->offset, p_region->size, p_vlynq_dev)) { p_region->id = -1; printk("Failed to map regions for %s%d in vlynq.\n", dev_name, instance); goto av_vlynq_wlan_map_region_fail; } p_region++; } /* Load the interrupt mapping to the vlynq module */ while(p_irq->hw_intr_line > (signed char)(-1)) { /* Maps one IRQ Hardware Line Onto the VLYNQ */ if(PAL_vlynqMapIrq(p_1x50_vlynq, p_irq->hw_intr_line, p_irq->irq, p_vlynq_dev)) { p_irq->hw_intr_line = -1; printk("Failed to map interrupts for %s%d in vlynq.\n", dev_name, instance); goto av_vlynq_wlan_map_irq_fail; } p_irq++; } /* Sets the polarity and the Type of the Hardware IRQ Line */ if(arm_1130_vlynq_irq_cfg()) { printk("Failed to set the irq on peer vlynq.\n"); goto av_vlynq_wlan_set_irq_fail; } printk("Success in setting up the 1350 VLYNQ.\n"); reset_flag = 0; return PAL_VLYNQ_OK; /* Error handling code */ av_vlynq_wlan_set_irq_fail: av_vlynq_wlan_map_irq_fail: printk("Unmapping the VLYNQ IRQ(s).\n"); p_irq = &TNETW1x50_irq_config[0]; while(p_irq->hw_intr_line > -1) { PAL_vlynqUnMapIrq(p_1x50_vlynq, p_irq->irq, p_vlynq_dev); p_irq++; } av_vlynq_wlan_map_region_fail: printk("Un mapping the VLYNQ regions.\n"); p_region = &TNETW1x50_region_config[0]; while(p_region->id > -1) { PAL_vlynqUnMapRegion(p_1x50_vlynq, p_region->remote, p_region->id, p_vlynq_dev); p_region++; } PAL_vlynqRemoveDevice(p_1x50_vlynq, p_vlynq_dev); av_vlynq_wlan_add_device_fail: printk("Destroying the VLYNQ device.\n"); PAL_vlynqDevDestroy(p_vlynq_dev); av_vlynq_wlan_dev_fail: printk("Cleaning up.......\n"); if(PAL_vlynqCleanUp(p_1x50_vlynq)) printk("It is not a Clean shut down...\n"); av_vlynq_wlan_init_fail: printk("End.......\n"); return PAL_VLYNQ_INTERNAL_ERROR; } /********************************************************************/ /****************Main vlynq chain initializtion**********************/ /********************************************************************/ void vlynq_dev_init(void) { PAL_Result FunctionResult; /* Start VLYNQ initialization */ PAL_sysVlynqInit(); FunctionResult=arm_1130_vlynq_init(); if (FunctionResult==PAL_VLYNQ_OK) { printk("OK.....\n"); printk("ARM_SDRAM_BASE = %x\n",ARM_SDRAM_BASE); /* Get physical addresses for 1130 */ if(PAL_vlynqGetDevBase(p_1x50_vlynq, VLYNQ_TNETW1X50_MEM_OFFSET, &wlan_mem_addr, p_vlynq_dev)) printk("Not there yet. Still problems.\n"); wlan_mem_addr = wlan_mem_addr + 0x0c000000; //wlan_mem_addr = (unsigned int)ioremap(wlan_mem_addr, VLYNQ_TNETW1X50_MEM_SIZE); printk("the WLAN memory is mapped at address %x \n", wlan_mem_addr); if(PAL_vlynqGetDevBase(p_1x50_vlynq, VLYNQ_TNETW1X50_REG_OFFSET, &wlan_reg_addr, p_vlynq_dev)) printk("Still problematic. \n"); wlan_reg_addr = wlan_reg_addr + 0x0c000000; //wlan_reg_addr = (unsigned int)ioremap(wlan_reg_addr, VLYNQ_TNETW1X50_REG_SIZE); printk("the WLAN registers area is mapped at address %x \n", wlan_reg_addr); } else { printk("\n==>>Function %s: arm_1130_vlynq_init failed with code %d!\n",__FUNCTION__,FunctionResult); } } void DaVinci_evm_vlynq_pins_config( void ) { volatile unsigned int temp; struct clk *clk; static const char __initdata err1[] = KERN_ERR "Error %ld getting vlynq clock?\n"; /*--- static const char __initdata info1[] = ---*/ /*--- KERN_INFO "DaVinci: %d vlynq irqs\n"; ---*/ clk = clk_get(NULL, "VLYNQCLK"); if (IS_ERR(clk)) { printk(err1, PTR_ERR(clk)); return 0; } clk_enable(clk); #if 0 printk("changing GPIO19 direction form: %x \n",*DAVINCI_GPIO_DIR_REG); *DAVINCI_GPIO_DIR_REG &= ~(0x00080000); /* GPIO19 to output mode */ printk("To : %x\n",*DAVINCI_GPIO_DIR_REG); printk("changing GPIO19 output level from: %x \n",*DAVINCI_GPIO_OUT_DATA); *DAVINCI_GPIO_OUT_DATA &= ~(0x00080000); /* Zero on GPIO19 */ printk("To : %x\n",*DAVINCI_GPIO_OUT_DATA); #endif /*--- printk("Lighting some LED's...\n"); ---*/ // val = 0x55; // davinci_i2c_write(1, &val, 0x38); // davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, WLAN_RESET, val); /* Configure PinMux0 to use the vlynq pins and GPIOs 10-21 */ /*--- printk("Muxing the VLYNQ pins using PinMux0...\n"); ---*/ /* Mask bits 0-15 in PinMux0 register */ /*--- *PINMUX0 &= ~0x0000ffff; ---*/ /*--- Program the PinMux0 register ---*/ /*--- *PINMUX0 |= 0x0000d00b; ---*//*d00b*/ /*--- printk("Mux: PinMux0=%x\n",*PINMUX0); ---*/ /* Delay to make sure GPIOs are stable */ for (temp=0; temp<=20000;temp++); /*--- davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, VLYNQ_ON, 0); ---*/ DaVinci_TNETW_Reset(OUT_OF_RESET); DaVinci_TNETW_Reset(IN_RESET); printk("VLYNQ: Version Register=%x\nVLYNQ: Control Register=%x \nVLYNQ: Status Register=%x\n", *VLYNQ_VER, *VLYNQ_CTRL, *VLYNQ_STAT); } #ifdef TI_BOARD_SETUP_PSC void board_setup_psc(unsigned int domain, unsigned int id, char enable) { volatile unsigned int *mdstat = (unsigned int *)((int)MDSTAT + 4 * id); volatile unsigned int *mdctl = (unsigned int *)((int)MDCTL + 4 * id); if (enable) { *mdctl |= 0x00000003; } else { *mdctl &= 0xFFFFFFF2; } if ((PDSTAT & 0x00000001) == 0) { PDCTL1 |= 0x1; PTCMD = (1 << domain); while ((((EPCPR >> domain) & 1) == 0)) ; PDCTL1 |= 0x100; while (!(((PTSTAT >> domain) & 1) == 0)) ; } else { PTCMD = (1 << domain); while (!(((PTSTAT >> domain) & 1) == 0)) ; } if (enable) { while (!((*mdstat & 0x0000001F) == 0x3)) ; } else { while (!((*mdstat & 0x0000001F) == 0x2)) ; } } #endif /********************************************************************/ /* Configure the DM320 on the DaVinci board to activate the VLYNQ */ /********************************************************************/ void Davinci_Vlynq_Hardware_Init( void ) { /* Turn on the VLYNQ PSC */ board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_VLYNQ, 1); /* Turn on the GPIO module */ board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_GPIO, 1); /* We are getting the wlan reset polarity from Bootloader */ if (strcmp(wlan_reset, "low") == 0) { printk("Wlan reset polarity is high (Beta board)\n"); wlan_reset_val = 0; } else { printk("Wlan reset polarity is low (Gamma board)\n"); wlan_reset_val = 1; } /* Configure the DaVinci EVM to use the VLYNQ pins */ DaVinci_evm_vlynq_pins_config(); /* Start the vlynq chain initialization */ vlynq_dev_init(); } EXPORT_SYMBOL(arch_getTnetResources); #if 0 EXPORT_SYMBOL(arch_cacheFlushRange); EXPORT_SYMBOL(arch_cacheInvalidateRange); /*----------------------------------------------------------------------------- Routine Name: arch_cacheFlushRange Routine Description: Clean (write back) the specified virtual address range. Arguments: startAddr - virtual start address size - length in bytes Return Value: None -----------------------------------------------------------------------------*/ void arch_cacheFlushRange(void* startAddr, size_t size) { dmac_flush_range((int)startAddr, (int)startAddr + size); } /*----------------------------------------------------------------------------- Routine Name: arch_cacheInvalidateRange Routine Description: Invalidate (discard) the specified virtual address range. Arguments: startAddr - virtual start address size - length in bytes Return Value: None -----------------------------------------------------------------------------*/ void arch_cacheInvalidateRange(void* startAddr, size_t size) { dmac_inv_range((int)startAddr, (int)startAddr + size); } #endif /*----------------------------------------------------------------------------- Routine Name: arch_getTnetResources( Routine Description: return the memory and register WLAN address.after coonversion of the VLYNQ interface Arguments: tnet_mem_addr - pointer to the virtual WLAN memory start address net_reg_addr - pointer to the virtual WLAN registers start address Return Value: None -----------------------------------------------------------------------------*/ void arch_getTnetResources(unsigned int* tnet_mem_addr, unsigned int* tnet_reg_addr) { *tnet_mem_addr = wlan_mem_addr; /* WLAN memory base */ *tnet_reg_addr = wlan_reg_addr; /* WLAN register area base */ }