📄 vsc73xx.c
字号:
/* vsc73xx.c * May 24, 2007 Tag before BSP resturcture */ #ifdef __BDI#include "bdi.h"#else#ifdef __ECOS#if defined(CYGNUM_USE_ENET_VERBOSE)# undef VERBOSE# define VERBOSE CYGNUM_USE_ENET_VERBOSE#else# define VERBOSE 0#endif #define printk DEBUG_PRINTF#define udelay A_UDELAY#else#include <linux/kernel.h>#include <asm/delay.h>#include "ar7100.h"#endif#endif#ifndef VERBOSE#define VERBOSE 0#endif#include "generic_spi.h"#include "vsc73xx.h"#define MODULE_NAME "VSC73XX"/* ************************************************************** */#define VSC73XX_SYSTEM 0x7#define VSC73XX_ICPU_CTRL 0x10#define VSC73XX_ICPU_ADDR 0x11#define VSC73XX_ICPU_SRAM 0x12#define VSC73XX_ICPU_MAILBOX_VAL 0x15#define VSC73XX_ICPU_MAILBOX_SET 0x16#define VSC73XX_ICPU_MAILBOX_CLR 0x17#define VSC73XX_ICPU_CHIPID 0x18#define VSC73XX_ICPU_SIPAD 0x01#define VSC73XX_ICPU_GPIO 0x34#define VSC73XX_ICPU_CLOCK_DELAY 0x05#define VSC73XX_MAC 0x1#define VSC73XX_MAC_CFG 0x0#define VSC73XX_ADVPORTM 0x19#define VSC73XX_RXOCT 0x50#define VSC73XX_TXOCT 0x51#define VSC73XX_C_RX0 0x52#define VSC73XX_C_RX1 0x53#define VSC73XX_C_RX2 0x54#define VSC73XX_C_TX0 0x55#define VSC73XX_C_TX1 0x56#define VSC73XX_C_TX2 0x57#define VSC73XX_C_CFG 0x58#define VSC73XX_MII 0x3#define VSC73XX_MII_STAT 0x0#define VSC73XX_MII_CMD 0x1#define VSC73XX_MII_DATA 0x2static void inlinevsc73xx_force_reset(void){ ar7100_reg_rmw_set(AR7100_RESET, AR7100_RESET_GE1_PHY); udelay(10); ar7100_reg_rmw_clear(AR7100_RESET, AR7100_RESET_GE1_PHY);}#ifdef USE_TEST_CODEvoidvsc73xx_test_reset_line(void){ printk(MODULE_NAME": looping 10 uSec nRESET, 100Usec RESET\n"); generic_spi_init(GENERIC_SPI_VSC73XX_CS); do { vsc73xx_force_reset(); udelay(100); } while (1);}#endifstatic intvsc73xx_check_block_sublock_ok(int block, int sublock) { switch (block) { case 1: switch (sublock) { case 0: case 1: case 2: case 3: case 4: case 6: return (0==0); } break; case 2: case 7: switch (sublock) { case 0: return (0==0); } break; case 3: case 4: case 5: switch (sublock) { case 0: case 1: return (0==0); } break; } return 0;}intvsc73xx_rd(int block, int subblock, int reg, unsigned int *value){ int rc; rc=vsc73xx_check_block_sublock_ok(block, subblock); if (rc<0) { printk(MODULE_NAME": non-supported block/subblock %d %d\n", block, subblock); return -1; } rc=generic_spi_access_enable(GENERIC_SPI_VSC73XX_CS); if (rc<0) { printk(MODULE_NAME": unable to CS %08x \n", GENERIC_SPI_VSC73XX_CS); return -1; } /* Send address */ generic_spi_raw_output_u8((block<<5) | (0/*READ*/<<4) | (subblock<<0)); generic_spi_raw_output_u8(reg); /* Pad based on SiPAD register ( default 2) */ generic_spi_raw_output_u8(0); generic_spi_raw_output_u8(0); /* Clock 32b data into serial shift register */ *value = generic_spi_raw_input_u32(); rc=generic_spi_access_done(); if (rc<0) { printk(MODULE_NAME": unable to deassert CS %08x \n", GENERIC_SPI_VSC73XX_CS); return -1; } return 0;}intvsc73xx_wr(int block, int subblock, int reg, unsigned int value){ int rc; rc=vsc73xx_check_block_sublock_ok(block, subblock); if (rc<0) { printk(MODULE_NAME": non-supported block/subblock %d %d\n", block, subblock); return -1; } rc=generic_spi_access_enable(GENERIC_SPI_VSC73XX_CS); if (rc<0) { printk(MODULE_NAME": unable to CS %08x \n", GENERIC_SPI_VSC73XX_CS); return -1; } /* Address */ generic_spi_raw_output_u8((block<<5) | (1/*WRITE*/<<4) | (subblock<<0) ); generic_spi_raw_output_u8(reg); /* Data */ generic_spi_raw_output_u8((value>>24) & 0xff); generic_spi_raw_output_u8((value>>16) & 0xff); generic_spi_raw_output_u8((value>>8 ) & 0xff); generic_spi_raw_output_u8((value>>0 ) & 0xff); rc=generic_spi_access_done(); if (rc<0) { printk(MODULE_NAME": unable to deassert CS %08x \n", GENERIC_SPI_VSC73XX_CS); return -1; } return 0;}static intvsc73xx_get_and_verify_chipid(void){ int curVal; int chip; int ii=256; do { vsc73xx_rd(VSC73XX_SYSTEM, 0, VSC73XX_ICPU_CHIPID, &curVal); chip = (curVal >> 12) & 0x0ffff; } while ((chip != 0x7385) && (chip != 0x7395) && (chip != 0x7396) && --ii);#ifdef VSC73XX_DEBUG printk(MODULE_NAME": curval = 0x%08x\n", curVal);#endif if (0==ii) { printk(MODULE_NAME": unknown chip: %08x\n", chip); return -1; }#ifdef CONFIG_AR9100 /* * Per Martin Olsen [martino@vitesse.com], * VSC7385YV chips with 0x0 in bits 31:28 of "Block 7 Subblock 0 * Address 0x18" is the first revision and that have a problem * with the reset. This can be the reason why this doesn't work. */ if (!((curVal >> 28) & 0xf)) { printk("\n==================================================\n" "WARNING:\n" "Using revision 0 of chip 0x%x. It might not work!\n" "==================================================\n", chip); }#endif return chip;}static intvsc73xx_reset_and_verify_chipid(void){ vsc73xx_force_reset(); return vsc73xx_get_and_verify_chipid();}#ifdef USE_TEST_CODEvoidvsc73xx_test_reset_and_verify_chipid(void){ printk(MODULE_NAME": looping on reset & verify chipid\n"); generic_spi_init(GENERIC_SPI_VSC73XX_CS); do { vsc73xx_reset_and_verify_chipid(); } while (1);}#endifstatic inline intvsc73xx_mailbox_get(unsigned int *d){ return vsc73xx_rd(VSC73XX_SYSTEM, 0, VSC73XX_ICPU_MAILBOX_VAL, d);}static inline intvsc73xx_mailbox_clr(unsigned int value){ return vsc73xx_wr(VSC73XX_SYSTEM, 0, VSC73XX_ICPU_MAILBOX_CLR, value);}static inline intvsc73xx_mailbox_set(unsigned int value){ return vsc73xx_wr(VSC73XX_SYSTEM, 0, VSC73XX_ICPU_MAILBOX_SET, value);}static inline int vsc73xx_gpio_config_output(int value){ return vsc73xx_wr(VSC73XX_SYSTEM, 0, VSC73XX_ICPU_GPIO, ( value & VSC73XX_GPIO_MASK ) << 4);}static inline intvsc73xx_gpio_output(int value){ unsigned int d; int rc; value &=VSC73XX_GPIO_MASK; /* 1 = high 0=low */ rc=vsc73xx_rd(VSC73XX_SYSTEM, 0, VSC73XX_ICPU_GPIO, &d); if (rc<0) return rc; d &=VSC73XX_GPIO_MASK; d |=value; return vsc73xx_wr(VSC73XX_SYSTEM, 0, VSC73XX_ICPU_GPIO, d);}static inline int vsc73xx_gpio_input(unsigned int *d){ int rc; unsigned int e; rc=vsc73xx_rd(VSC73XX_SYSTEM, 0, VSC73XX_ICPU_GPIO, &e); if (rc<0) return rc; *d = e & VSC73XX_GPIO_MASK; return rc;}#ifdef USE_TEST_CODEvoidvsc73xx_test_gpio(void){ printk(MODULE_NAME": looping on / off vsc73xx GPIO\n"); generic_spi_init(GENERIC_SPI_VSC73XX_CS); vsc73xx_gpio_config_output(VSC73XX_GPIO_2); do { vsc73xx_gpio_output(VSC73XX_GPIO_2); udelay(50); vsc73xx_gpio_output(0); udelay(50); } while (1);}#endifstatic intvsc73xx_get_sVersion_resetNeeded(int *sVersion, int *resetNeeded){ unsigned int d; int rc; rc=vsc73xx_mailbox_get(&d); if (rc<0) return rc; *sVersion = d & 0xffff; *resetNeeded = (d & 0xffff0000) == 0xffff0000; return 0;}static inline int vsc73xx_restart_firmware(void){ int rc; rc = vsc73xx_wr( VSC73XX_SYSTEM, 0, VSC73XX_ICPU_CTRL, (1<<7) | /* SOFT_RST_HOLD = 1 */ (1<<3) | /* BOOT_EN = 1 */ (1<<2) | /* EXT_ACC_EN = 1 */ (0<<0) /* SOFT_RST = 0 */ ); if (rc<0) return rc; rc = vsc73xx_wr( VSC73XX_SYSTEM, 0,VSC73XX_ICPU_ADDR, 0x0000 ); if (rc<0) return rc; udelay(100); rc = vsc73xx_wr( VSC73XX_SYSTEM, 0, VSC73XX_ICPU_CTRL, (1<<8) | /* CLK_DIV = 1 */ (1<<3) | /* BOOT_EN = 1 */ (1<<1) | /* CLK_EN = 1 */ (1<<0) /* SOFT_RST = 1 */ ); return rc;}static intvsc73xx_load_firmware_raw(unsigned char *lutonuAddr, int lutonuSize) { int ii; unsigned char *dp; unsigned int curVal; int diffs; int rc; rc = vsc73xx_wr( VSC73XX_SYSTEM, 0, VSC73XX_ICPU_CTRL, (1<<7) | /* SOFT_RST_HOLD = 1 */ (1<<3) | /* BOOT_EN = 1 */ (1<<2) | /* EXT_ACC_EN = 1 */ (0<<0) /* SOFT_RST = 0 */ ); if (rc<0) return rc; rc = vsc73xx_wr( VSC73XX_SYSTEM, 0,VSC73XX_ICPU_ADDR, 0x0000 ); if (rc<0) return rc; dp = lutonuAddr; for (ii=0; ii<lutonuSize; ii++) { rc = vsc73xx_wr( VSC73XX_SYSTEM, 0, VSC73XX_ICPU_SRAM, *dp++ ); if (rc<0) { printk(MODULE_NAME": could not load microcode %d\n",rc); return rc; } } rc = vsc73xx_wr( VSC73XX_SYSTEM, 0, VSC73XX_ICPU_ADDR, 0x0000 ); if (rc<0) { printk(MODULE_NAME": could not reset microcode %d\n",rc); return rc; } printk(MODULE_NAME": microcode Loaded, verifying...\n"); dp = lutonuAddr; diffs=0; for (ii=0; ii<lutonuSize; ii++) { rc = vsc73xx_rd( VSC73XX_SYSTEM, 0,VSC73XX_ICPU_SRAM, &curVal ); if (rc<0) { printk(MODULE_NAME": could not read microcode %d\n",rc); return rc; } if (curVal > 0xff) { printk(MODULE_NAME": bad val read: %04x : %02x %02x \n", ii, *dp, curVal); return -1; } if ((curVal & 0xff) != *dp) { diffs++; printk(MODULE_NAME": verify error: %04x : %02x %02x \n", ii, *dp, curVal); if (diffs > 4) break; } dp++; } if (diffs) { printk(MODULE_NAME": failed to verify\n"); return -1; } printk(MODULE_NAME": verify OK\n"); rc = vsc73xx_wr( VSC73XX_SYSTEM, 0, VSC73XX_ICPU_CTRL, (1<<8) | /* CLK_DIV = 1 */ (1<<3) | /* BOOT_EN = 1 */ (1<<1) | /* CLK_EN = 1 */ (1<<0) /* SOFT_RST = 1 */ ); return rc;}#define VSC73XX_SFTW_VERSION 0x229#include "g5_Plus1_2_29b_unmanaged_Atheros_v5.c"#include "g5e_Plus1_2_29a_unmanaged_Atheros_v3.c"#include "g5_Plus1_2_29a_unmanaged_Atheros_v5.c"static intvsc73xx_load_firmware(void) { int sVersion; int resetNeeded; int rc; rc = vsc73xx_reset_and_verify_chipid(); if (rc < 0) { printk(MODULE_NAME": could not identify chip, err %d\n", rc); return rc; } printk(MODULE_NAME": found chip id: %04x\n", rc);#if defined(__BDI) && defined(VSC73XX_LOAD_FROM_RAM) rc = vsc73xx_load_firmware_raw(get_scratch_uncached(8192), 8192);#else switch (rc) { case 0x00007385: #ifndef CONFIG_AR9100 rc = vsc73xx_load_firmware_raw(g5_Plus1_2_29b_unmanaged_Atheros_v5, sizeof(g5_Plus1_2_29b_unmanaged_Atheros_v5));#else rc = vsc73xx_load_firmware_raw(g5_Plus1_2_29b_unmanaged_Atheros_v5, sizeof(g5_Plus1_2_29b_unmanaged_Atheros_v5));#endif break; case 0x00007395: /* source from vitesse uses symbol lutonu, later versions use the name of the file. */ rc = vsc73xx_load_firmware_raw(lutonu, /* g5e_Plus1_2_29a_unmanaged_Atheros_v3 */ sizeof(lutonu /* g5e_Plus1_2_29a_unmanaged_Atheros_v3 */)); break; default: printk(MODULE_NAME": microcode not availale for chip id: %08x\n", rc); rc = -1; }#endif if (rc<0) return rc; vsc73xx_get_sVersion_resetNeeded(&sVersion, &resetNeeded); if (resetNeeded) { printk(MODULE_NAME": failed to start\n"); return -1; } if (sVersion < VSC73XX_SFTW_VERSION) { printk(MODULE_NAME": incorrect software version %04x\n", sVersion); return -1; } printk(MODULE_NAME": software version %08x started OK\n",sVersion); return 0;}#ifdef USE_TEST_CODEvoidvsc73xx_test_load_and_reset_firmware(void){ int rc; printk(MODULE_NAME": looping on load firmware / reset firmware\n"); generic_spi_init(GENERIC_SPI_VSC73XX_CS); do { printk(MODULE_NAME": return from load firmware: %d\n", vsc73xx_load_firmware());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -