diff options
Diffstat (limited to 'target/linux/realtek/files/drivers/char')
4 files changed, 3014 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/char/rtl_gpio.c b/target/linux/realtek/files/drivers/char/rtl_gpio.c new file mode 100644 index 000000000..2269e7ded --- /dev/null +++ b/target/linux/realtek/files/drivers/char/rtl_gpio.c @@ -0,0 +1,1387 @@ +/* + * FILE NAME rtl_gpio.c + * + * BRIEF MODULE DESCRIPTION + * GPIO For Flash Reload Default + * + * Author: jimmylin@realtek.com.tw + * + * Copyright 2005 Realtek Semiconductor Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +//#define CONFIG_USING_JTAG 1 + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/interrupt.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/miscdevice.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/reboot.h> +#include <linux/kmod.h> +#include <linux/proc_fs.h> +//#include "bspchip.h" +#define AUTO_CONFIG + +// 2009-0414 +//#define DET_WPS_SPEC +#ifndef CONFIG_RTK_VOIP_DRIVERS_ATA_DECT //DECT SPI use GPIO E interrupt, need refine code to share irq. +#ifndef CONFIG_SERIAL_SC16IS7X0 //SC16IS7x0 use GPIO E interrupt, too. +#define USE_INTERRUPT_GPIO +#endif +#endif + +#if defined(CONFIG_RTL_8196C) || defined(CONFIG_RTL_8198) +#ifndef CONFIG_RTK_VOIP + #define READ_RF_SWITCH_GPIO +#endif +#endif + +#if defined(CONFIG_RTL_8196C) || defined(CONFIG_RTL_8198) + #include "drivers/net/rtl819x/AsicDriver/rtl865xc_asicregs.h" +/*define the GPIO physical address to customer_gpio.h*/ +#ifdef CONFIG_RTK_VOIP + #if defined (CONFIG_RTK_VOIP_GPIO_8954C_V100) || \ + defined (CONFIG_RTK_VOIP_GPIO_8964C_QA) + + + // GPIO E7 + #define RESET_PIN_IOBASE PEFGH_CNR //RTL_GPIO_PEFGH_CNR + #define RESET_PIN_DIRBASE PEFGH_DIR //RTL_GPIO_PEFGH_DIR + #define RESET_PIN_DATABASE PEFGH_DAT //RTL_GPIO_PEFGH_DATA + #define RESET_PIN_NO 7 //pin number of the EFGH + + // GPIO G0 + #define RESET_LED_IOBASE PEFCH_CNR //RTL_GPIO_PEFGH_CNR + #define RESET_LED_DIRBASE PEFGH_DIR //RTL_GPIO_PEFGH_DIR + #define RESET_LED_DATABASE PEFGH_DAT //RTL_GPIO_PEFGH_DATA + #define RESET_LED_NO 16 //pin number of the EFGH + + // GPIO G1 + #define AUTOCFG_LED_IOBASE PEFGH_CNR //RTL_GPIO_PEFGH_CNR + #define AUTOCFG_LED_DIRBASE PEFGH_DIR //RTL_GPIO_PEFGH_DIR + #define AUTOCFG_LED_DATABASE PEFGH_DAT //RTL_GPIO_PEFGH_DATA + #define AUTOCFG_LED_NO 17 //pin number of the EFGH + + // GPIO E2 + #define AUTOCFG_PIN_IOBASE PEFGH_CNR //RTL_GPIO_PEFGH_CNR + #define AUTOCFG_PIN_DIRBASE PEFGH_DIR //RTL_GPIO_PEFGH_DIR + #define AUTOCFG_PIN_DATABASE PEFGH_DAT //RTL_GPIO_PEFGH_DATA + #define AUTOCFG_PIN_NO 2 //pin number of the EFGH) + + #define AUTOCFG_PIN_IMR PEF_IMR + #define RTL_GPIO_MUX_DATA 0x00004300 //MUX for GPIO + + #elif defined(CONFIG_RTK_VOIP_GPIO_8954C_V200) || \ + defined(CONFIG_RTK_VOIP_GPIO_8954C_V400) + + // GPIO F4 DEFAULT_Button + #define RESET_PIN_IOBASE PEFGH_CNR //RTL_GPIO_PEFGH_CNR + #define RESET_PIN_DIRBASE PEFGH_DIR //RTL_GPIO_PEFGH_DIR + #define RESET_PIN_DATABASE PEFGH_DAT //RTL_GPIO_PEFGH_DATA + #define RESET_PIN_NO 12 //pin number of the EFGH + + // GPIO E7 SYS LED + #define RESET_LED_IOBASE PEFGH_CNR //RTL_GPIO_PEFGH_CNR + #define RESET_LED_DIRBASE PEFGH_DIR //RTL_GPIO_PEFGH_DIR + #define RESET_LED_DATABASE PEFGH_DAT //RTL_GPIO_PEFGH_DATA + #define RESET_LED_NO 7 //number of the EFGH + + // GPIO F0 WPS LED + #define AUTOCFG_LED_IOBASE PEFGH_CNR //RTL_GPIO_PEFGH_CNR + #define AUTOCFG_LED_DIRBASE PEFGH_DIR //RTL_GPIO_PEFGH_DIR + #define AUTOCFG_LED_DATABASE PEFGH_DAT //RTL_GPIO_PEFGH_DATA + #define AUTOCFG_LED_NO 8 //pin number of the EFGH + + // GPIO F3 WPS Button + #define AUTOCFG_PIN_IOBASE PEFGH_CNR //RTL_GPIO_PEFGH_CNR + #define AUTOCFG_PIN_DIRBASE PEFGH_DIR //RTL_GPIO_PEFGH_DIR + #define AUTOCFG_PIN_DATABASE PEFGH_DAT //RTL_GPIO_PEFGH_DATA + #define AUTOCFG_PIN_NO 11 //pin number of the EFGH + #define AUTOCFG_PIN_IMR PEF_IMR + #define RTL_GPIO_MUX_DATA 0x00000300 //MUX for GPIO + #endif + + #define RTL_GPIO_MUX 0xB8000040 + + //#define RTL_GPIO_WIFI_ONOFF 19 + #define AUTOCFG_BTN_PIN AUTOCFG_PIN_NO + #define AUTOCFG_LED_PIN AUTOCFG_LED_NO + #define RESET_LED_PIN RESET_LED_NO + #define RESET_BTN_PIN RESET_PIN_NO + +#else +#if defined(CONFIG_RTL_8196C) + #if defined(CONFIG_RTL_8196CS) + #define PCIE0_BASE 0xb9000000 + #define PCIE_BASE_OFFSET (PCIE0_BASE+0x40) + #define PCIE_PIN_MUX PCIE_BASE_OFFSET + #define RESET_PIN_IOBASE (PCIE_BASE_OFFSET+4) + #define WPS_PIN_IOBASE (PCIE_BASE_OFFSET+4) + #define WPS_LED_IOBASE (PCIE_BASE_OFFSET) + #define PCIE_GPIO_IMR (PCIE_BASE_OFFSET+8) + #define MODE_MARSK 24 + #define MODE_MARSK1 28 + #define DIR_MASK 16 + #define DIR_MASK1 24 + #define IN_MASK 0 + #define OUT_MASK 8 + #define OUT_MASK1 20 + + // GPIO A0 + //#define RESET_PIN_IOBASE RESET_PIN_IOBASE //RTL_GPIO_PABCD_CNR + #define RESET_PIN_DIRBASE RESET_PIN_IOBASE //RTL_GPIO_PABCD_DIR + #define RESET_PIN_DATABASE RESET_PIN_IOBASE //RTL_GPIO_PABCD_DATA + #define RESET_PIN_NO 0 /*number of the ABCD*/ + + // GPIO C2 + #define RESET_LED_IOBASE PABCD_CNR //RTL_GPIO_PABCD_CNR + #define RESET_LED_DIRBASE PABCD_DIR //RTL_GPIO_PABCD_DIR + #define RESET_LED_DATABASE PABCD_DAT //RTL_GPIO_PABCD_DATA + #define RESET_LED_NO 2 /*number of the ABCD*/ + + // GPIO C4 + #define AUTOCFG_LED_IOBASE WPS_LED_IOBASE //RTL_GPIO_PABCD_CNR + #define AUTOCFG_LED_DIRBASE WPS_LED_IOBASE //RTL_GPIO_PABCD_DIR + #define AUTOCFG_LED_DATABASE WPS_LED_IOBASE //RTL_GPIO_PABCD_DATA + #define AUTOCFG_LED_NO 20 /*number of the ABCD*/ + + // GPIO A1 + #define AUTOCFG_PIN_IOBASE WPS_PIN_IOBASE //RTL_GPIO_PABCD_CNR + #define AUTOCFG_PIN_DIRBASE WPS_PIN_IOBASE //RTL_GPIO_PABCD_DIR + #define AUTOCFG_PIN_DATABASE WPS_PIN_IOBASE //RTL_GPIO_PABCD_DATA + #define AUTOCFG_PIN_NO 2 /*number of the ABCD)*/ + #define AUTOCFG_PIN_IMR PCIE_GPIO_IMR + #else + // GPIO A0 + #define RESET_PIN_IOBASE PABCD_CNR //RTL_GPIO_PABCD_CNR + #define RESET_PIN_DIRBASE PABCD_DIR //RTL_GPIO_PABCD_DIR + #define RESET_PIN_DATABASE PABCD_DAT //RTL_GPIO_PABCD_DATA + #define RESET_PIN_NO 0 /*number of the ABCD*/ + + // GPIO C2 + #define RESET_LED_IOBASE PABCD_CNR //RTL_GPIO_PABCD_CNR + #define RESET_LED_DIRBASE PABCD_DIR //RTL_GPIO_PABCD_DIR + #define RESET_LED_DATABASE PABCD_DAT //RTL_GPIO_PABCD_DATA + #define RESET_LED_NO 18 /*number of the ABCD*/ + + // GPIO C4 + #define AUTOCFG_LED_IOBASE PABCD_CNR //RTL_GPIO_PABCD_CNR + #define AUTOCFG_LED_DIRBASE PABCD_DIR //RTL_GPIO_PABCD_DIR + #define AUTOCFG_LED_DATABASE PABCD_DAT //RTL_GPIO_PABCD_DATA + #define AUTOCFG_LED_NO 20 /*number of the ABCD*/ + + // GPIO A1 + #define AUTOCFG_PIN_IOBASE PABCD_CNR //RTL_GPIO_PABCD_CNR + #define AUTOCFG_PIN_DIRBASE PABCD_DIR //RTL_GPIO_PABCD_DIR + #define AUTOCFG_PIN_DATABASE PABCD_DAT //RTL_GPIO_PABCD_DATA + #define AUTOCFG_PIN_NO 1 /*number of the ABCD)*/ + #define AUTOCFG_PIN_IMR PAB_IMR + #endif +#ifdef CONFIG_POCKET_ROUTER_SUPPORT + #define RTL_GPIO_MUX_GPIOA2 (3<<20) + #define RTL_GPIO_MUX_GPIOB3 (3<<2) + #define RTL_GPIO_MUX_GPIOB2 (3<<0) + #define RTL_GPIO_MUX_GPIOC0 (3<<12) + #define RTL_GPIO_MUX_POCKETAP_DATA (RTL_GPIO_MUX_GPIOA2 | RTL_GPIO_MUX_GPIOB3 | RTL_GPIO_MUX_GPIOB2 | RTL_GPIO_MUX_GPIOC0) + + #define RTL_GPIO_CNR_GPIOA2 (1<<2) + #define RTL_GPIO_CNR_GPIOB3 (1<<11) + #define RTL_GPIO_CNR_GPIOB2 (1<<10) + #define RTL_GPIO_CNR_GPIOC0 (1<<16) + #define RTL_GPIO_CNR_POCKETAP_DATA (RTL_GPIO_CNR_GPIOA2 | RTL_GPIO_CNR_GPIOB3 | RTL_GPIO_CNR_GPIOB2 | RTL_GPIO_CNR_GPIOC0) + + #define RTL_GPIO_DIR_GPIOA2 (1<<2) /* &- */ + #define RTL_GPIO_DIR_GPIOB3 (1<<11) /* &- */ + #define RTL_GPIO_DIR_GPIOB2 (1<<10) /* |*/ + #define RTL_GPIO_DIR_GPIOC0 (1<<16) /* &- */ + + #define RTL_GPIO_DAT_GPIOA2 (1<<2) + #define RTL_GPIO_DAT_GPIOB3 (1<<11) + #define RTL_GPIO_DAT_GPIOB2 (1<<10) + #define RTL_GPIO_DAT_GPIOC0 (1<<16) + + static int ap_cli_rou_time_state[2] = {0}; + static char ap_cli_rou_state = 0; + static char ap_cli_rou_idx=0; + static char pocketAP_hw_set_flag='0'; + + static char dc_pwr_plugged_time_state = 0; + static char dc_pwr_plugged_state = 0; + static char dc_pwr_plugged_flag = '0'; + + static int pwr_saving_state=0; + static char pwr_saving_led_toggle = 0; +#endif + + +#elif defined(CONFIG_RTL_8198) + // GPIO H1 + #define RESET_PIN_IOBASE PEFGH_CNR //RTL_GPIO_PABCD_CNR + #define RESET_PIN_DIRBASE PEFGH_DIR //RTL_GPIO_PABCD_DIR + #define RESET_PIN_DATABASE PEFGH_DAT //RTL_GPIO_PABCD_DATA + #define RESET_PIN_NO 25 /*number of the ABCD*/ + + // GPIO H3 + #define RESET_LED_IOBASE PEFGH_CNR //RTL_GPIO_PABCD_CNR + #define RESET_LED_DIRBASE PEFGH_DIR //RTL_GPIO_PABCD_DIR + #define RESET_LED_DATABASE PEFGH_DAT //RTL_GPIO_PABCD_DATA + #define RESET_LED_NO 27 /*number of the ABCD*/ + + // GPIO G4 + #define AUTOCFG_LED_IOBASE PEFGH_CNR //RTL_GPIO_PABCD_CNR + #define AUTOCFG_LED_DIRBASE PEFGH_DIR //RTL_GPIO_PABCD_DIR + #define AUTOCFG_LED_DATABASE PEFGH_DAT //RTL_GPIO_PABCD_DATA + #define AUTOCFG_LED_NO 20 /*number of the ABCD*/ + + // GPIO E1 + #define AUTOCFG_PIN_IOBASE PEFGH_CNR //RTL_GPIO_PABCD_CNR + #define AUTOCFG_PIN_DIRBASE PEFGH_DIR //RTL_GPIO_PABCD_DIR + #define AUTOCFG_PIN_DATABASE PEFGH_DAT //RTL_GPIO_PABCD_DATA + #define AUTOCFG_PIN_NO 1 /*number of the ABCD)*/ + #define AUTOCFG_PIN_IMR PGH_IMR + +#endif + // GPIO C3 + #define WIFI_ONOFF_PIN_IOBASE PABCD_CNR //RTL_GPIO_PABCD_CNR + #define WIFI_ONOFF_PIN_DIRBASE PABCD_DIR //RTL_GPIO_PABCD_DIR + #define WIFI_ONOFF_PIN_DATABASE PABCD_DAT //RTL_GPIO_PABCD_DATA + #define WIFI_ONOFF_PIN_NO 19/*umber of the ABCD)*/ + #define WIFI_ONOFF_PIN_IMR PAB_IMR + +/* + #define RTL_GPIO_MUX 0xB8000030 + #define RTL_GPIO_MUX_DATA 0x0FC00380//for WIFI ON/OFF and GPIO + + + + #define AUTOCFG_BTN_PIN AUTOCFG_PIN_NO // 1 + #define AUTOCFG_LED_PIN AUTOCFG_LED_NO//20 + #define RESET_LED_PIN RESET_LED_NO //18 + #define RESET_BTN_PIN RESET_PIN_NO //0 + #define RTL_GPIO_WIFI_ONOFF WIFI_ONOFF_PIN_NO +*/ + #define RTL_GPIO_MUX 0xB8000040 + #ifdef CONFIG_8198_PORT5_GMII + #define RTL_GPIO_MUX_DATA 0x00340000 + #else + #define RTL_GPIO_MUX_DATA 0x00340C00//for WIFI ON/OFF and GPIO + #endif + #define RTL_GPIO_WIFI_ONOFF 19 + +#if defined(CONFIG_RTL_8196C) + #if defined(CONFIG_RTL_8196CS) + #define AUTOCFG_BTN_PIN 2 + #define AUTOCFG_LED_PIN 1 + #define RESET_LED_PIN 2 + #define RESET_BTN_PIN 0 + #else + #define AUTOCFG_BTN_PIN 3 + #define AUTOCFG_LED_PIN 4 + #define RESET_LED_PIN 6 + #define RESET_BTN_PIN 5 + #endif + +#elif defined(CONFIG_RTL_8198) + #define AUTOCFG_BTN_PIN 24 + #define AUTOCFG_LED_PIN 26 + #define RESET_LED_PIN 27 + #define RESET_BTN_PIN 25 +#endif + +#endif // CONFIG_RTK_VOIP +#endif // CONFIG_RTL_8196C || CONFIG_RTL_8198 + +// 2009-0414 +#ifdef USE_INTERRUPT_GPIO +#ifdef CONFIG_RTK_VOIP + #define GPIO_IRQ_NUM (16+17) // GPIO_EFGH +#else + #define GPIO_IRQ_NUM 1 +#endif +#endif + + #define PROBE_TIME 5 + + +#define PROBE_NULL 0 +#define PROBE_ACTIVE 1 +#define PROBE_RESET 2 +#define PROBE_RELOAD 3 +#define RTL_R32(addr) (*(volatile unsigned long *)(addr)) +#define RTL_W32(addr, l) ((*(volatile unsigned long*)(addr)) = (l)) +#define RTL_R8(addr) (*(volatile unsigned char*)(addr)) +#define RTL_W8(addr, l) ((*(volatile unsigned char*)(addr)) = (l)) + +//#define GPIO_DEBUG +#ifdef GPIO_DEBUG +/* note: prints function name for you */ +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +static struct timer_list probe_timer; +static unsigned int probe_counter; +static unsigned int probe_state; + +static char default_flag='0'; +//Brad add for update flash check 20080711 +int start_count_time=0; +int Reboot_Wait=0; + +static int get_dc_pwr_plugged_state(); + + + +//#ifdef CONFIG_RTL865X_AC + +#ifdef CONFIG_POCKET_ROUTER_SUPPORT +static struct timer_list pocket_ap_timer; +#endif + +#ifdef USE_INTERRUPT_GPIO +static int wps_button_push = 0; + +#endif +#if defined(CONFIG_RTL_8196CS) +void update_pcie_status(void) +{ + unsigned int temp; + temp=RTL_R32(0xb8b00728); + temp=RTL_R32(PCIE_PIN_MUX); + temp=RTL_R32(RESET_PIN_DATABASE); + + + //printk("LINE: %x d:%x * %x****R:%x\n",__LINE__,RTL_R32(0xb8b00728),RTL_R32(PCIE_PIN_MUX),RTL_R32(RESET_PIN_DATABASE)); +} +#endif + +#ifdef AUTO_CONFIG +static unsigned int AutoCfg_LED_Blink; +static unsigned int AutoCfg_LED_Toggle; +static unsigned int AutoCfg_LED_Slow_Blink; +static unsigned int AutoCfg_LED_Slow_Toggle; + +void autoconfig_gpio_init(void) +{ +#if defined(CONFIG_RTL_8196CS) + RTL_W32(AUTOCFG_PIN_IOBASE,(RTL_R32(AUTOCFG_PIN_IOBASE)&(~((1 << AUTOCFG_BTN_PIN)<<MODE_MARSK)))); + RTL_W32(AUTOCFG_LED_IOBASE,(RTL_R32(AUTOCFG_LED_IOBASE)&(~((1 << AUTOCFG_LED_PIN)<<MODE_MARSK1)))); + + // Set GPIOA pin 1 as input pin for auto config button + RTL_W32(AUTOCFG_PIN_DIRBASE, (RTL_R32(AUTOCFG_PIN_DIRBASE) & (~(((1 << AUTOCFG_BTN_PIN))<<DIR_MASK1)))); + + // Set GPIOA ping 3 as output pin for auto config led + RTL_W32(AUTOCFG_LED_DIRBASE, (RTL_R32(AUTOCFG_LED_DIRBASE) | ((1 << AUTOCFG_LED_PIN)<<DIR_MASK1))); + + // turn off auto config led in the beginning + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) | ((1 << AUTOCFG_LED_PIN)<<OUT_MASK1))); + update_pcie_status(); + //printk("LINE: %x d:%x * %x****R:%x\n",__LINE__,RTL_R32(0xb8b00728),RTL_R32(PCIE_PIN_MUX),RTL_R32(RESET_PIN_DATABASE)); +#else + RTL_W32(AUTOCFG_PIN_IOBASE,(RTL_R32(AUTOCFG_PIN_IOBASE)&(~(1 << AUTOCFG_BTN_PIN)))); + RTL_W32(AUTOCFG_LED_IOBASE,(RTL_R32(AUTOCFG_LED_IOBASE)&(~(1 << AUTOCFG_LED_PIN)))); + + // Set GPIOA pin 1 as input pin for auto config button + RTL_W32(AUTOCFG_PIN_DIRBASE, (RTL_R32(AUTOCFG_PIN_DIRBASE) & (~(1 << AUTOCFG_BTN_PIN)))); + + // Set GPIOA ping 3 as output pin for auto config led + RTL_W32(AUTOCFG_LED_DIRBASE, (RTL_R32(AUTOCFG_LED_DIRBASE) | (1 << AUTOCFG_LED_PIN))); + + // turn off auto config led in the beginning + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) | (1 << AUTOCFG_LED_PIN))); +#endif +} +#ifdef CONFIG_RTL_8196C_GW_MP + +void all_led_on(void) +{ + //printk("Into MP GPIO"); + #ifdef CONFIG_RTL_8196C_GW_MP + RTL_W32(0xB8000030, (RTL_R32(0xB8000030) | 0x00F00F80 )); + RTL_W32(PABCD_CNR, (RTL_R32(PABCD_CNR) & (~(1 << PS_LED_GREEN_PIN)))); + RTL_W32(PABCD_CNR, (RTL_R32(PABCD_CNR) & (~(1 << PS_LED_ORANGE_PIN)))); + + RTL_W32(PABCD_DIR, (RTL_R32(PABCD_DIR) | (1 << PS_LED_GREEN_PIN))); + RTL_W32(PABCD_DIR, (RTL_R32(PABCD_DIR) | (1 << PS_LED_ORANGE_PIN))); + + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) | (1 << PS_LED_GREEN_PIN))); + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~(1 << PS_LED_ORANGE_PIN)))); + + /* inet_led init setting */ + RTL_W32(PABCD_CNR, (RTL_R32(PABCD_CNR) & (~(1 << INET_LED_GREEN_PIN)))); + RTL_W32(PABCD_CNR, (RTL_R32(PABCD_CNR) & (~(1 << INET_LED_ORANGE_PIN)))); + + RTL_W32(PABCD_DIR, (RTL_R32(PABCD_DIR) | (1 << INET_LED_GREEN_PIN))); + RTL_W32(PABCD_DIR, (RTL_R32(PABCD_DIR) | (1 << INET_LED_ORANGE_PIN))); + + RTL_W32(AUTOCFG_LED_DIRBASE, (RTL_R32(AUTOCFG_LED_DIRBASE) & (~(1 << AUTOCFG_LED_PIN_MP)))); + + RTL_W32(PABCD_DIR, (RTL_R32(PABCD_DIR) | (1 << AUTOCFG_LED_PIN_MP))); + + //RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~(1 << INET_LED_GREEN_PIN)))); + //RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) | (1 << INET_LED_ORANGE_PIN))); + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~(1 << PS_LED_GREEN_PIN)))); + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~(1 << PS_LED_ORANGE_PIN)))); + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~(1 << INET_LED_GREEN_PIN)))); + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~(1 << INET_LED_ORANGE_PIN)))); + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~(1 << AUTOCFG_LED_PIN_MP)))); + RTL_W32(RESET_LED_DATABASE, (RTL_R32(RESET_LED_DATABASE) & (~(1 << RESET_LED_PIN_MP)))); + #endif + +} +#endif +#if defined(CONFIG_RTL_8196CS) + +void autoconfig_gpio_off(void) +{ + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) | ((1 << AUTOCFG_LED_PIN)<<OUT_MASK1))); + AutoCfg_LED_Blink = 0; + update_pcie_status(); + //printk("LINE: %x d:%x * %x****R:%x\n",__LINE__,RTL_R32(0xb8b00728),RTL_R32(PCIE_PIN_MUX),RTL_R32(RESET_PIN_DATABASE)); +} + + +void autoconfig_gpio_on(void) +{ + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) & (~((1 << AUTOCFG_LED_PIN)<<OUT_MASK1)))); + //printk("LINE: %x d:%x * %x****R:%x\n",__LINE__,RTL_R32(0xb8b00728),RTL_R32(PCIE_PIN_MUX),RTL_R32(RESET_PIN_DATABASE)); + update_pcie_status(); + AutoCfg_LED_Blink = 0; +} + + +void autoconfig_gpio_blink(void) +{ + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) & (~((1 << AUTOCFG_LED_PIN)<<OUT_MASK1)))); + //printk("LINE: %x d:%x * %x****R:%x\n",__LINE__,RTL_R32(0xb8b00728),RTL_R32(PCIE_PIN_MUX),RTL_R32(RESET_PIN_DATABASE)); + update_pcie_status(); + AutoCfg_LED_Blink = 1; + AutoCfg_LED_Toggle = 1; + +} + + + +#else +void autoconfig_gpio_off(void) +{ + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) | (1 << AUTOCFG_LED_PIN))); + AutoCfg_LED_Blink = 0; +} + + +void autoconfig_gpio_on(void) +{ + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) & (~(1 << AUTOCFG_LED_PIN)))); + AutoCfg_LED_Blink = 0; +} + + +void autoconfig_gpio_blink(void) +{ + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) & (~(1 << AUTOCFG_LED_PIN)))); + + AutoCfg_LED_Blink = 1; + AutoCfg_LED_Toggle = 1; + AutoCfg_LED_Slow_Blink = 0; + +} + +void autoconfig_gpio_slow_blink(void) +{ + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) & (~(1 << AUTOCFG_LED_PIN)))); + + AutoCfg_LED_Blink = 1; + AutoCfg_LED_Toggle = 1; + AutoCfg_LED_Slow_Blink = 1; + AutoCfg_LED_Slow_Toggle = 1; + +} + +#endif + + +#endif // AUTO_CONFIG + + + + +static void rtl_gpio_timer(unsigned long data) +{ + unsigned int pressed=1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + struct pid *pid; +#endif +#if defined(CONFIG_RTL_8196CS) + update_pcie_status(); +#endif +#if defined(CONFIG_RTL_8196C) || defined(CONFIG_RTL_8198) + + if ((RTL_R32(RESET_PIN_DATABASE) & (1 << RESET_BTN_PIN))) + +#endif + { + pressed = 0; + + //turn off LED0 + #ifndef CONFIG_RTL_8196C_GW_MP + RTL_W32(RESET_LED_DATABASE, (RTL_R32(RESET_LED_DATABASE) | ((1 << RESET_LED_PIN)))); + #endif + } + else + { + DPRINTK("Key pressed %d!\n", probe_counter+1); + } + + if (RTL_R32(AUTOCFG_PIN_DATABASE) & (1 << AUTOCFG_BTN_PIN)){ + wps_button_push = 0; + }else{ + wps_button_push++; + } + + if (probe_state == PROBE_NULL) + { + if (pressed) + { + probe_state = PROBE_ACTIVE; + probe_counter++; + } + else + probe_counter = 0; + } + else if (probe_state == PROBE_ACTIVE) + { + if (pressed) + { + probe_counter++; + + if ((probe_counter >=2 ) && (probe_counter <=PROBE_TIME)) + { + DPRINTK("2-5 turn on led\n"); + //turn on LED0 + RTL_W32(RESET_LED_DATABASE, (RTL_R32(RESET_LED_DATABASE) & (~(1 << RESET_LED_PIN)))); + } + else if (probe_counter >= PROBE_TIME) + { + // sparkling LED0 + DPRINTK(">5 \n"); + + if (probe_counter & 1) + RTL_W32(RESET_LED_DATABASE, (RTL_R32(RESET_LED_DATABASE) | ((1 << RESET_LED_PIN)))); + else + RTL_W32(RESET_LED_DATABASE, (RTL_R32(RESET_LED_DATABASE) & (~(1 << RESET_LED_PIN)))); + } + } + else + { + #if defined(CONFIG_RTL865X_SC) + if (probe_counter < 5) + #else + if (probe_counter < 2) + #endif + { + probe_state = PROBE_NULL; + probe_counter = 0; + DPRINTK("<2 \n"); + #if defined(CONFIG_RTL865X_SC) + ResetToAutoCfgBtn = 1; + #endif + } + else if (probe_counter >= PROBE_TIME) + { + + + //reload default + default_flag = '1'; + + //kernel_thread(reset_flash_default, (void *)1, SIGCHLD); + return; + + } + else + { + DPRINTK("2-5 reset 1\n"); + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + kill_proc(1,SIGTERM,1); + #else + pid = get_pid(find_vpid(1)); + kill_pid(pid,SIGTERM,1); + #endif + DPRINTK("2-5 reset 2\n"); + //kernel_thread(reset_flash_default, 0, SIGCHLD); + return; + } + } + } + +#ifdef AUTO_CONFIG + if (AutoCfg_LED_Blink==1) + { + if (AutoCfg_LED_Toggle) { +
#if defined(CONFIG_RTL_8196CS) + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) | ((1 << AUTOCFG_LED_PIN)<<OUT_MASK1))); + #else + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) | (1 << AUTOCFG_LED_PIN))); + #endif + } + else { + #if defined(CONFIG_RTL_8196CS) + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) & (~((1 << AUTOCFG_LED_PIN)<<OUT_MASK1)))); + #else + RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) & (~(1 << AUTOCFG_LED_PIN)))); + #endif + + } + + if(AutoCfg_LED_Slow_Blink) + { + if(AutoCfg_LED_Slow_Toggle) + AutoCfg_LED_Toggle = AutoCfg_LED_Toggle; + else + AutoCfg_LED_Toggle = AutoCfg_LED_Toggle? 0 : 1; + + AutoCfg_LED_Slow_Toggle = AutoCfg_LED_Slow_Toggle? 0 : 1; + } + else + AutoCfg_LED_Toggle = AutoCfg_LED_Toggle? 0 : 1; + + } +#endif + + + mod_timer(&probe_timer, jiffies + HZ); + +} + +#ifdef CONFIG_RTL_FLASH_DUAL_IMAGE_ENABLE + +#define SYSTEM_CONTRL_DUMMY_REG 0xb8000068 + +int is_bank2_root() +{ + //boot code will steal System's dummy register bit0 (set to 1 ---> bank2 booting + //for 8198 formal chip + if ((RTL_R32(SYSTEM_CONTRL_DUMMY_REG)) & (0x00000001)) // steal for boot bank idenfy + return 1; + + return 0; +} +static int read_bootbank_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + char flag='1'; + + if (is_bank2_root()) // steal for boot bank idenfy + flag='2'; + + len = sprintf(page, "%c\n", flag); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len > count) len = count; + if (len < 0) len = 0; + return len; +} +#endif + +#ifdef AUTO_CONFIG +#if defined(USE_INTERRUPT_GPIO) +static irqreturn_t gpio_interrupt_isr(int irq, void *dev_instance, struct pt_regs *regs) +{ + wps_button_push = 1; +#ifdef CONFIG_RTK_VOIP + RTL_W32(PEFGH_ISR, RTL_R32(PEFGH_ISR)); +#else + RTL_W32(PABCD_ISR, RTL_R32(PABCD_ISR)); +#endif + return IRQ_HANDLED; +} +#endif + +static int read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + char flag; + +#if defined(USE_INTERRUPT_GPIO) +// 2009-0414 + if (wps_button_push) { + flag = '1'; + //wps_button_push = 0; //mark it for select wlan interface by button pressed time + } + else{ + if (RTL_R32(AUTOCFG_PIN_DATABASE) & (1 << AUTOCFG_BTN_PIN)){ + flag = '0'; + }else{ + //printk("wps button be held \n"); + flag = '1'; + } + + } +// 2009-0414 +#else + + if (RTL_R32(AUTOCFG_PIN_DATABASE) & (1 << AUTOCFG_BTN_PIN)) + flag = '0'; + else { + flag = '1'; + } +#endif // CONFIG_RTL865X_KLD + + len = sprintf(page, "%c\n", flag); + + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len > count) len = count; + if (len < 0) len = 0; + return len; +} + + + +#ifdef CONFIG_RTL_KERNEL_MIPS16_CHAR +__NOMIPS16 +#endif +static int write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char flag[20]; +//Brad add for update flash check 20080711 + + char start_count[10], wait[10]; + + if (count < 2) + return -EFAULT; + + DPRINTK("file: %08x, buffer: %s, count: %lu, data: %08x\n", + (unsigned int)file, buffer, count, (unsigned int)data); + + if (buffer && !copy_from_user(&flag, buffer, 1)) { + if (flag[0] == 'E') { + autoconfig_gpio_init(); + #ifdef CONFIG_RTL865X_CMO + extra_led_gpio_init(); + #endif + } + else if (flag[0] == '0') + autoconfig_gpio_off(); + else if (flag[0] == '1') + autoconfig_gpio_on(); + else if (flag[0] == '2') + autoconfig_gpio_blink(); +#ifndef CONFIG_RTL_8196CS + else if (flag[0] == '3') + autoconfig_gpio_slow_blink(); +#endif + +#ifdef CONFIG_RTL_8196C_GW_MP + else if (flag[0] == '9') // disable system led + { + all_led_on(); + } +#endif + +#ifdef CONFIG_RTL865X_CMO + else if (flag[0] == '3') + wep_wpa_led_on(); + else if (flag[0] == '5') + wep_wpa_led_off(); + else if (flag[0] == '6') + mac_ctl_led_on(); + else if (flag[0] == '7') + mac_ctl_led_off(); + else if (flag[0] == '8') + bridge_repeater_led_on(); + else if (flag[0] == '9') + bridge_repeater_led_off(); + else if (flag[0] == 'A') + system_led_on(); +// else if (flag[0] == 'B') +// system_led_off(); + else if (flag[0] == 'C') + lan_led_on(); + else if (flag[0] == 'D') + lan_led_off(); + else if (flag[0] == 'Z') + printk("gpio test test\n"); +// else if (flag[0] == '9') +// system_led_blink = 2; +#endif + +//Brad add for update flash check 20080711 + + else if (flag[0] == '4'){ + start_count_time= 1; + sscanf(buffer, "%s %s", start_count, wait); + Reboot_Wait = (simple_strtol(wait,NULL,0))*100; + } + + + else + {} + + return count; + } + else + return -EFAULT; +} +#endif // AUTO_CONFIG + +static int default_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%c\n", default_flag); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +#ifdef CONFIG_RTL_KERNEL_MIPS16_CHAR +__NOMIPS16 +#endif +static int default_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + if (count < 2) + return -EFAULT; + if (buffer && !copy_from_user(&default_flag, buffer, 1)) { + return count; + } + return -EFAULT; +} + +#ifdef READ_RF_SWITCH_GPIO +static int rf_switch_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + char flag; + + if (RTL_R32(WIFI_ONOFF_PIN_DATABASE) & (1<<WIFI_ONOFF_PIN_NO)){ + flag = '1'; + }else{ + flag = '0'; + } + len = sprintf(page, "%c\n", flag); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len > count) len = count; + if (len < 0) len = 0; + return len; +} +#endif + +#ifdef CONFIG_POCKET_ROUTER_SUPPORT +static int write_pocketAP_hw_set_flag_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned int reg_cnr, reg_dir; + + if (count != 2) + return -EFAULT; + if (buffer && !copy_from_user(&pocketAP_hw_set_flag, buffer, 1)) { + + } + return -EFAULT; +} + +static int read_pocketAP_hw_set_flag_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%c\n", pocketAP_hw_set_flag); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len > count) len = count; + if (len < 0) len = 0; + +//panic_printk("\r\n __[%s-%u]",__FILE__,__LINE__); + return len; + +} + + + +static int read_ap_client_rou_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + char flag; + int gpioA2_flag,gpioB3_flag; + + + if(ap_cli_rou_state == 2) + { + len = sprintf(page, "%c\n", '2'); // AP + } + else if(ap_cli_rou_state == 1) + { + len = sprintf(page, "%c\n", '1'); // Client + } + else if(ap_cli_rou_state == 3) + { + len = sprintf(page, "%c\n", '3'); // Router + } + else + { + len = sprintf(page, "%c\n", '0'); + } + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len > count) len = count; + if (len < 0) len = 0; + +//panic_printk("\r\n __[%s-%u]",__FILE__,__LINE__); + return len; +} + +static int read_dc_pwr_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + char flag; + int pluged_state=0; +//panic_printk("\r\n 0x%x__[%s-%u]",RTL_R32(RESET_PIN_DATABASE),__FILE__,__LINE__); + + pluged_state = get_dc_pwr_plugged_state(); + if(pluged_state == 1) + { + len = sprintf(page, "%c\n", '1'); + } + else if(pluged_state == 2) + { + len = sprintf(page, "%c\n", '2'); + } + else + { + len = sprintf(page, "%c\n", '0'); + } + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len > count) len = count; + if (len < 0) len = 0; + +//panic_printk("\r\n len=[%u]__[%s-%u]",len,__FILE__,__LINE__); + return len; +} + +static int read_dc_pwr_plugged_flag_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%c\n", dc_pwr_plugged_flag); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len > count) len = count; + if (len < 0) len = 0; + +//panic_printk("\r\n __[%s-%u]",__FILE__,__LINE__); + dc_pwr_plugged_flag = '0'; + return len; + +} +static int read_EnablePHYIf_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + char flag; + +//panic_printk("\r\n 0x%x__[%s-%u]",RTL_R32(RESET_PIN_DATABASE),__FILE__,__LINE__); + + if(RTL_R32(0xBB804114) & (0x01)) + { + flag = '1'; + } + else + { + flag = '0'; + } + + len = sprintf(page, "%c\n", flag); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len > count) len = count; + if (len < 0) len = 0; + +//panic_printk("\r\n len=[%u]__[%s-%u]",len,__FILE__,__LINE__); + return len; +} + +static int get_pocketAP_ap_cli_rou_state() +{ + int gpioA2_flag,gpioB3_flag; + + if(RTL_R32(RESET_PIN_DATABASE) & (RTL_GPIO_DAT_GPIOA2)) + { + gpioA2_flag = 1; + } + else + { + gpioA2_flag = 0; + } + + if(RTL_R32(RESET_PIN_DATABASE) & (RTL_GPIO_DAT_GPIOB3)) + { + gpioB3_flag = 1; + } + else + { + gpioB3_flag = 0; + } + + return ((1<<gpioA2_flag)|gpioB3_flag); +} + +static int get_dc_pwr_plugged_state() +{ + + if(RTL_R32(RESET_PIN_DATABASE) & (RTL_GPIO_DAT_GPIOC0)) + { + return 1; //plugged + } + else + { + return 2; //unplugged + } + +} + +static int check_EnablePHYIf() +{ + if(RTL_R32(0xBB804114) & (0x01)) + { + return 1; + } + else + { + return 0; + } + +} + +static void pocket_ap_timer_func(unsigned long data) +{ +//panic_printk("\r\n __[%s-%u]",__FILE__,__LINE__); + + if(ap_cli_rou_idx >= 1) + ap_cli_rou_idx = 0; + else + ap_cli_rou_idx++; + + ap_cli_rou_time_state[ap_cli_rou_idx]=get_pocketAP_ap_cli_rou_state(); + dc_pwr_plugged_time_state = get_dc_pwr_plugged_state(); + + if(ap_cli_rou_time_state[0] == ap_cli_rou_time_state[1] ) + { + if(ap_cli_rou_state != ap_cli_rou_time_state[0]) + { + ap_cli_rou_state = ap_cli_rou_time_state[0]; + pocketAP_hw_set_flag = '0'; + } + } + + if(dc_pwr_plugged_state == 0) + { + dc_pwr_plugged_state = dc_pwr_plugged_time_state; + } + else if(dc_pwr_plugged_state != dc_pwr_plugged_time_state) + { + dc_pwr_plugged_state = dc_pwr_plugged_time_state; + dc_pwr_plugged_flag = '1'; + } + +//B8b00728 & 0x1F 0x11:L0 0x14:L1 +//panic_printk("\r\n [%d-%d-%d-%d],__[%s-%u]",ap_cli_rou_time_state[0],ap_cli_rou_time_state[1],ap_cli_rou_state,__FILE__,__LINE__); + +//panic_printk("\r\n [0x%x]",RTL_R32(0xB8b00728) & (0x1F)); + pwr_saving_state=(RTL_R32(0xB8b00728) & (0x1F)); +//panic_printk("\r\n pwr_saving_state = [0x%x]",pwr_saving_state); + + if(pwr_saving_state == 0x14) // L1 state, in low speed + { + if (pwr_saving_led_toggle < 2) { + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) | (RTL_GPIO_DAT_GPIOB2))); + pwr_saving_led_toggle++; + } + else if (pwr_saving_led_toggle < 4){ + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~(RTL_GPIO_DAT_GPIOB2)))); + pwr_saving_led_toggle++; + if(pwr_saving_led_toggle == 4) + pwr_saving_led_toggle = 0; + } + else + { + pwr_saving_led_toggle = 0; + } + } + else // L0 state, always on + { + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~(RTL_GPIO_DAT_GPIOB2)))); + } + + + mod_timer(&pocket_ap_timer, jiffies + HZ/2); +} +#endif +int __init rtl_gpio_init(void) +{ + struct proc_dir_entry *res=NULL; + + printk("Realtek GPIO Driver for Flash Reload Default\n"); + + // Set GPIOA pin 10(8181)/0(8186) as input pin for reset button + +#if defined(CONFIG_RTL_8196C) || defined(CONFIG_RTL_8198) +#ifndef CONFIG_USING_JTAG + RTL_W32(RTL_GPIO_MUX, (RTL_R32(RTL_GPIO_MUX) | (RTL_GPIO_MUX_DATA))); +#endif +#if defined(CONFIG_RTL_8198) + RTL_W32(RTL_GPIO_MUX, (RTL_R32(RTL_GPIO_MUX) | 0xf)); +#endif +#if defined(CONFIG_RTL_8196CS) +extern int PCIE_reset_procedure(int PCIE_Port0and1_8196B_208pin, int Use_External_PCIE_CLK, int mdio_reset,unsigned long conf_addr); +#define CLK_MANAGE 0xb8000010 +#define PCI_CONFIG_COMMAND (0xB8B10000+4) +#define PCI_CONFIG_LATENCY (0xB8B10000+0x0c) +#define PCI_CONFIG_BASE0 (0xB8B10000+0x10) +#define PCI_CONFIG_BASE1 (0xB8B10000+0x18) + extern void setBaseAddressRegister(void); + RTL_W32(CLK_MANAGE, (RTL_R32(CLK_MANAGE) | BIT(11))); + mdelay(10); + PCIE_reset_procedure(0, 0, 1, 0xb8b10000); + setBaseAddressRegister(); + { + + int i=0; + *((volatile unsigned long *)PCI_CONFIG_BASE1) = 0x19000000; + //DEBUG_INFO("...config_base1 = 0x%08lx\n", *((volatile unsigned long *)PCI_CONFIG_BASE1)); + for(i=0; i<1000000; i++); + *((volatile unsigned char *)PCI_CONFIG_COMMAND) = 0x07; + //DEBUG_INFO("...command = 0x%08lx\n", *((volatile unsigned long *)PCI_CONFIG_COMMAND)); + for(i=0; i<1000000; i++); + *((volatile unsigned short *)PCI_CONFIG_LATENCY) = 0x2000; + for(i=0; i<1000000; i++); + //DEBUG_INFO("...latency = 0x%08lx\n", *((volatile unsigned long *)PCI_CONFIG_LATENCY)); + } + +#endif +#ifdef CONFIG_POCKET_ROUTER_SUPPORT + +//panic_printk("\r\n 0x%x__[%s-%u]",RTL_R32(RTL_GPIO_MUX),__FILE__,__LINE__); +#ifndef CONFIG_USING_JTAG + RTL_W32(RTL_GPIO_MUX, (RTL_R32(RTL_GPIO_MUX) | (RTL_GPIO_MUX_POCKETAP_DATA))); +#endif +//panic_printk("\r\n 0x%x__[%s-%u]",RTL_R32(RTL_GPIO_MUX),__FILE__,__LINE__); + RTL_W32(PABCD_CNR, (RTL_R32(PABCD_CNR) & (~(RTL_GPIO_CNR_POCKETAP_DATA)))); + + + + + + RTL_W32(PABCD_DIR, (RTL_R32(PABCD_DIR) & (~(RTL_GPIO_DIR_GPIOA2)))); + + RTL_W32(PABCD_DIR, (RTL_R32(PABCD_DIR) & (~(RTL_GPIO_DIR_GPIOB3)))); + + RTL_W32(PABCD_DIR, (RTL_R32(PABCD_DIR) | ((RTL_GPIO_DIR_GPIOB2)))); + + RTL_W32(PABCD_DIR, (RTL_R32(PABCD_DIR) & (~(RTL_GPIO_DIR_GPIOC0)))); + +#endif //end of CONFIG_POCKET_ROUTER_SUPPORT +#if defined(CONFIG_RTL_8196CS) + RTL_W32(PCIE_PIN_MUX,(RTL_R32(PCIE_PIN_MUX)&(~(1<<29)))|(1<<13) ); + RTL_W32(RESET_PIN_IOBASE, (RTL_R32(RESET_PIN_IOBASE) & (~((1 << RESET_BTN_PIN)<<MODE_MARSK)))); + RTL_W32(RESET_PIN_DIRBASE, (RTL_R32(RESET_PIN_DIRBASE) & (~((1 << RESET_BTN_PIN)<<DIR_MASK )))); + +#else + RTL_W32(RESET_PIN_IOBASE, (RTL_R32(RESET_PIN_IOBASE) & (~(1 << RESET_BTN_PIN)))); + RTL_W32(RESET_PIN_DIRBASE, (RTL_R32(RESET_PIN_DIRBASE) & (~(1 << RESET_BTN_PIN)))); +#endif +#if defined(READ_RF_SWITCH_GPIO) + RTL_W32(WIFI_ONOFF_PIN_IOBASE, (RTL_R32(WIFI_ONOFF_PIN_DIRBASE) & ( ~(1<<RTL_GPIO_WIFI_ONOFF)))); + RTL_W32(WIFI_ONOFF_PIN_DIRBASE, (RTL_R32(WIFI_ONOFF_PIN_DIRBASE) & (~(1<<RTL_GPIO_WIFI_ONOFF)))); + RTL_W32(WIFI_ONOFF_PIN_DATABASE, (RTL_R32(WIFI_ONOFF_PIN_DATABASE) & (~(1<<RTL_GPIO_WIFI_ONOFF)))); + +#endif // #if defined(READ_RF_SWITCH_GPIO) +#endif // #if defined(CONFIG_RTL865X) +#if defined(CONFIG_RTL_8196CS) + RTL_W32(RESET_LED_IOBASE, (RTL_R32(RESET_LED_IOBASE) | (((1 << RESET_LED_PIN))))); + RTL_W32(RESET_LED_DIRBASE, (RTL_R32(RESET_LED_DIRBASE) | ((1 << RESET_LED_PIN)))); +#else + // Set GPIOA ping 2 as output pin for reset led + RTL_W32(RESET_LED_DIRBASE, (RTL_R32(RESET_LED_DIRBASE) | ((1 << RESET_LED_PIN)))); +#endif +#ifdef CONFIG_RTL_FLASH_DUAL_IMAGE_ENABLE + res = create_proc_entry("bootbank", 0, NULL); + if (res) { + res->read_proc = read_bootbank_proc; + //res->write_proc = write_bootbank_proc; + } + else { + printk("read bootbank, create proc failed!\n"); + } +#endif +#ifdef AUTO_CONFIG + res = create_proc_entry("gpio", 0, NULL); + if (res) { + res->read_proc = read_proc; + res->write_proc = write_proc; + } + else { + printk("Realtek GPIO Driver, create proc failed!\n"); + } + +// 2009-0414 +#if defined(USE_INTERRUPT_GPIO) +#if defined(CONFIG_RTL_8198) && !defined(CONFIG_RTK_VOIP) + RTL_R32(AUTOCFG_PIN_IMR) |= (0x01 << (AUTOCFG_BTN_PIN-16)*2); // enable interrupt in falling-edge +#else + RTL_R32(AUTOCFG_PIN_IMR) |= (0x01 << AUTOCFG_BTN_PIN*2); // enable interrupt in falling-edge +#endif + if (request_irq(GPIO_IRQ_NUM, gpio_interrupt_isr, IRQF_DISABLED, "rtl_gpio", NULL)) { + //panic_printk("gpio request_irq(%d) error!\n", GPIO_IRQ_NUM); + } +#endif +// 2009-0414 +#endif + + res = create_proc_entry("load_default", 0, NULL); + if (res) { + res->read_proc = default_read_proc; + res->write_proc = default_write_proc; + } + +#ifdef READ_RF_SWITCH_GPIO + res = create_proc_entry("rf_switch", 0, NULL); + if (res) { + res->read_proc = rf_switch_read_proc; + res->write_proc = NULL; + } +#endif + + + +#ifdef CONFIG_POCKET_ROUTER_SUPPORT + + res = create_proc_entry("dc_pwr", 0, NULL); + if (res) + res->read_proc = read_dc_pwr_proc; + else + printk("create read_dc_pwr_proc failed!\n"); + + res = create_proc_entry("dc_pwr_plugged_flag", 0, NULL); + if (res) + { + res->read_proc = read_dc_pwr_plugged_flag_proc; + } + else + printk("create read_pocketAP_hw_set_flag_proc failed!\n"); + + res = create_proc_entry("ap_client_rou", 0, NULL); + if (res) + res->read_proc = read_ap_client_rou_proc; + else + printk("create read_ap_client_rou_proc failed!\n"); + + res = create_proc_entry("pocketAP_hw_set_flag", 0, NULL); + if (res) + { + res->read_proc = read_pocketAP_hw_set_flag_proc; + res->write_proc = write_pocketAP_hw_set_flag_proc; + } + else + printk("create read_pocketAP_hw_set_flag_proc failed!\n"); + + res = create_proc_entry("phyif", 0, NULL); + if (res) + res->read_proc = read_EnablePHYIf_proc; + else + printk("create read_EnablePHYIf_proc failed!\n"); + + init_timer(&pocket_ap_timer); + pocket_ap_timer.data = (unsigned long)NULL; + pocket_ap_timer.function = &pocket_ap_timer_func; + mod_timer(&pocket_ap_timer, jiffies + HZ); +#endif + + init_timer(&probe_timer); + probe_counter = 0; + probe_state = PROBE_NULL; + probe_timer.expires = jiffies + HZ; + probe_timer.data = (unsigned long)NULL; + probe_timer.function = &rtl_gpio_timer; + mod_timer(&probe_timer, jiffies + HZ); + +#ifdef CONFIG_RTL865X_CMO + extra_led_gpio_init(); +#endif + return 0; +} + + +static void __exit rtl_gpio_exit(void) +{ + printk("Unload Realtek GPIO Driver \n"); + del_timer_sync(&probe_timer); +} + + +module_exit(rtl_gpio_exit); +module_init(rtl_gpio_init); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIO driver for Reload default"); diff --git a/target/linux/realtek/files/drivers/char/rtl_mdio/Makefile b/target/linux/realtek/files/drivers/char/rtl_mdio/Makefile new file mode 100644 index 000000000..18b38e500 --- /dev/null +++ b/target/linux/realtek/files/drivers/char/rtl_mdio/Makefile @@ -0,0 +1,2 @@ + +obj-y += rtl_mdio.o diff --git a/target/linux/realtek/files/drivers/char/rtl_mdio/rtl_mdio.c b/target/linux/realtek/files/drivers/char/rtl_mdio/rtl_mdio.c new file mode 100644 index 000000000..85cc3ffda --- /dev/null +++ b/target/linux/realtek/files/drivers/char/rtl_mdio/rtl_mdio.c @@ -0,0 +1,1316 @@ +/* +################################################################################ +# +# RTL8198 MDIO char driver +# +# Copyright(c) 2010 Realtek Semiconductor Corp. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>. +# +# Author: +# Realtek WiFi AP software team <cn_sd8@realtek.com> +# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/ +/*================================================================*/ +/* System Include Files */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <linux/ioport.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/circ_buf.h> +#include <asm/uaccess.h> +#include <linux/timer.h> +#include <linux/proc_fs.h> +#include <linux/interrupt.h> +#include "bspchip.h" + + +/*================================================================*/ +/* Local Include Files */ + +#include "rtl_mdio.h" + +//#define CONFIG_RTL8197B_B_CUT_PATCH +/*================================================================*/ +/* Global Variables */ + +int cpu_suspend_enabled = 0; + + +/*================================================================*/ +/* Local Variables */ +static struct mdio_priv *dev_priv=NULL; + +#ifdef SIMULATION +static unsigned char data_in[256]; +static int data_in_len = 0, data_in_read_idx = 0; + +static unsigned short data_out; +static int data_out_len = 0, msg_is_fetched = 0; +static unsigned long reg_scr =0, reg_isr=0; +#endif + + + + +/*================================================================*/ +#if 0 +int pre_jiffies=1; + +void* MAX_FUNCT; +unsigned int MAX_STACK=8*1024; +unsigned int PRINT_STACK=2428; +unsigned int COPY_STACK=2428; + +unsigned int MAX_FUNCT_call[40]; + +#define PRINT_INTV (1*60*100) +/* print max sp ever 3min */ +//extern volatile int jiffies; + + +void __attribute__((__no_instrument_function__)) +__cyg_profile_func_enter(void *this_func, void *call_site) +{ + unsigned int sp_addr; + unsigned int sp_size; + +#if 0 + if (this_func == rtk_voip_dsp_init) + { + printk("rtk_voip_dsp_init enter\n"); + } +#endif + + __asm__ __volatile__("ori %0, $29, 0": "=r"(sp_addr) ); + + sp_size = sp_addr & 8191; + + if(MAX_STACK > sp_size) + { + MAX_STACK = sp_size; + MAX_FUNCT = this_func; + + if (COPY_STACK > sp_size) { + COPY_STACK = sp_size; + copy_trace(sp_addr); + } + + + } + + if ( ((int)jiffies - pre_jiffies) > PRINT_INTV ) { + + pre_jiffies = jiffies; + printk("MAXSP,%x,%d.", MAX_FUNCT, MAX_STACK); + + if (PRINT_STACK > MAX_STACK) { + int i; + unsigned long flags; + save_flags(flags); cli(); + PRINT_STACK = MAX_STACK; + printk("\nCall Trace:"); + + for (i=0 ; i<40 ; i++) { + if (0==MAX_FUNCT_call[i]) + break; + printk(" [<%08lx>]", MAX_FUNCT_call[i]); + if ( 4==(i%5)) + printk("\n"); + } + restore_flags(flags); + } + MAX_STACK = 8*1024; + } +} + +void __attribute__((__no_instrument_function__)) +__cyg_profile_func_exit(void *this_func, void *call_site) +{ +#if 0 + if (this_func == rtk_voip_dsp_init) + { + printk("rtk_voip_dsp_init exit\n"); + } +#endif +} + +#include <asm-mips/uaccess.h> + +void __attribute__((__no_instrument_function__)) copy_trace(unsigned int *sp) +{ + int i; + //int column = 0; + unsigned int *stack; + unsigned long kernel_start, kernel_end; + + extern char _stext, _etext; + + stack = sp ; + i = 0; + + kernel_start = (unsigned long) &_stext; + kernel_end = (unsigned long) &_etext; + + + //printk("\nCall Trace:"); + + while ((unsigned long) stack & (PAGE_SIZE -1)) { + unsigned long addr; + + if (__get_user(addr, stack++)) { + printk(" (Bad stack address)\n"); + break; + } + + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + + if (addr >= kernel_start && addr < kernel_end) { + + MAX_FUNCT_call[i]=addr; + //printk(" [<%08lx>]", addr); + //if (column++ == 5) { + // printk("\n"); + // column = 0; + //} + if (++i > 40) { + //printk(" ..."); + break; + } + } + + + } + + //if (column != 0) + // printk("\n"); + + for ( ; i<40; i++) + MAX_FUNCT_call[i] = 0; +} +#endif +/*================================================================*/ + + + + +/*================================================================*/ +/* Routine Implementations */ + +#ifdef SIMULATION +static unsigned long register_read_dw(int offset) +{ + unsigned long status = 0; + unsigned short wdata = 0; + + if (offset == REG_ISR) { + status = reg_isr; + + if (data_in_len > data_in_read_idx) + status |= IP_NEWMSG; + + if (msg_is_fetched) { + status |= IP_MSGFETCH; + msg_is_fetched = 0; + } + + return status; + } + else if (offset == REG_RCR) { + ASSERT(data_in_len > data_in_read_idx); + memcpy(&wdata, &data_in[data_in_read_idx], 2); + data_in_read_idx += 2; + status |= wdata; + return status; + } + else if (offset == REG_SYSCR) { + return reg_scr; + } + else { + ASSERT(0); + return status; + } +} + +static void register_write_dw(int offset, unsigned long data) +{ + if (offset == REG_SSR) { + unsigned short wData = (unsigned short)data; + + memcpy(&data_out, &wData, 2); + data_out_len = 2; + } + else if (offset == REG_ISR) { + reg_isr &= ~data ; + } +} +#endif // SIMULATION + +#ifdef KDB_MSG +static void inline debugk_out(unsigned char *label, unsigned char *data, int data_length) +{ + int i,j; + int num_blocks; + int block_remainder; + + num_blocks = data_length >> 4; + block_remainder = data_length & 15; + + if (label) + DEBUGK_OUT("%s\n", label); + + if (data==NULL || data_length==0) + return; + + for (i=0; i<num_blocks; i++) { + printk("\t"); + for (j=0; j<16; j++) + printk("%02x ", data[j + (i<<4)]); + printk("\n"); + } + + if (block_remainder > 0) { + printk("\t"); + for (j=0; j<block_remainder; j++) + printk("%02x ", data[j+(num_blocks<<4)]); + printk("\n"); + } +} +#endif // KDB_MSG + +unsigned long static get_ether_phy_reg(unsigned long phyId, unsigned long regId) +{ + unsigned long status; + + WRITE_MEM32((void *)MDCIOCR, COMMAND_READ | ( phyId << PHYADD_OFFSET ) | ( regId << REGADD_OFFSET )); + + do { status = READ_MEM32( MDCIOSR ); } while ( ( status & MDCIO_STATUS ) != 0 ); + + status &= 0xffff; + return status; +} + +static void set_ether_phy_reg(unsigned long phyId, unsigned long regId, unsigned long wData) +{ + WRITE_MEM32(MDCIOCR, COMMAND_WRITE | ( phyId << PHYADD_OFFSET ) | ( regId << REGADD_OFFSET ) | wData); + + while( ( READ_MEM32( MDCIOSR ) & MDCIO_STATUS ) != 0 ); /* wait until command complete */ +} + +static int is_checksum_ok(unsigned char *data, int len) +{ + int i; + unsigned char sum=0; + + for (i=0; i<len; i++) + sum += data[i]; + + if (sum == 0) + return 1; + else + return 0; +} + +static unsigned char append_checksum(unsigned char *data, int len) +{ + int i; + unsigned char sum=0; + + for (i=0; i<len; i++) + sum += data[i]; + + sum = ~sum + 1; + return sum; +} + +static int indicate_evt(struct mdio_priv *priv, int id, unsigned char *data, int data_len) +{ + int size; + + size = CIRC_SPACE(priv->evt_que_head, priv->evt_que_tail, EV_QUE_MAX); + if (size == 0) { + DEBUGK_ERR("Indication queue full, drop event!\n"); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + if (priv->host_pid != -1) + kill_proc(priv->host_pid, SIGUSR1, 1); +#else + if (priv->host_pid != NULL) + kill_pid(priv->host_pid, SIGUSR1, 1); +#endif + + return 0; + } + + ASSERT(data_len < MDIO_BUFSIZE); + + priv->ind_evt_que[priv->evt_que_head].id = id; + priv->ind_evt_que[priv->evt_que_head].len = data_len; + memcpy(&priv->ind_evt_que[priv->evt_que_head].buf, data, data_len); + priv->evt_que_head = (priv->evt_que_head + 1) & (EV_QUE_MAX - 1); +#if 0 //mark_nfbi , now we use polling instead of singal in HCD +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + if (priv->host_pid != -1) + kill_proc(priv->host_pid, SIGUSR1, 1); +#else + if (priv->host_pid != NULL) + kill_pid(priv->host_pid, SIGUSR1, 1); +#endif +#endif + return 1; +} + +static int retrieve_evt(struct mdio_priv *priv, unsigned char *out) +{ + int len = 0; + + if (CIRC_CNT(priv->evt_que_head, priv->evt_que_tail, EV_QUE_MAX) > 0) { // more than one evt pending + len = EVT_BUF_OFFSET + priv->ind_evt_que[priv->evt_que_tail].len; + memcpy(out, &priv->ind_evt_que[priv->evt_que_tail], len); + priv->evt_que_tail = (priv->evt_que_tail + 1) & (EV_QUE_MAX - 1); + } + return len; +} + +static void process_rx_cmd(struct mdio_priv *priv, unsigned short data) +{ + if (priv->rx_cmd_time && + (priv->rx_cmd_state == STATE_RX_WAIT_LEN || + priv->rx_cmd_state == STATE_RX_WAIT_DATA) && + (priv->cmd_timeout && TIME_DIFF(jiffies, priv->rx_cmd_time) > priv->cmd_timeout)) { + DEBUGK_ERR("Rx cmd timeout [%ld][0x%x], discard pending cmd!\n", TIME_DIFF(jiffies, priv->rx_cmd_time), data); + RESET_RX_STATE; + return; + } + + if ((data & FIRST_CMD_MASK) && (priv->rx_cmd_state != STATE_RX_INIT)) { + DEBUGK_ERR("Rx Sync bit but not in INIT_STATE [%d][0x%x], discard pending cmd!\n", priv->rx_cmd_state, data); + RESET_RX_STATE; + } + + if (priv->rx_cmd_state == STATE_RX_INIT) { + ASSERT(priv->data_in.len == 0); + + if (!(data & FIRST_CMD_MASK)) { + DEBUGK_ERR("Got invalid rx cmd id [0x%x], discard it!\n", data); + goto invalid_cmd; + } + PUT_IN_DATA(data); // cmd id + priv->rx_cmd_state = STATE_RX_WAIT_LEN; + priv->rx_cmd_time = jiffies; + } + else { // STATE_RX_WAIT_LEN or STATE_RX_WAIT_DATA + // check if first cmd byte is '0' + if (data & 0xff00) { + DEBUGK_ERR("1st byte of rx cmd not zero [%x]!\n", data >> 8); + goto invalid_cmd; + } + + if (priv->rx_cmd_state == STATE_RX_WAIT_LEN) { + PUT_IN_DATA(data); + priv->rx_cmd_state = STATE_RX_WAIT_DATA; + priv->rx_cmd_remain_len = (data + 1)*2; // including checksum + priv->rx_cmd_time = jiffies; + } + else { // in STATE_RX_WAIT_DATA + ASSERT (priv->rx_cmd_remain_len > 0); + + PUT_IN_DATA(data); + priv->rx_cmd_remain_len -= 2; + if (priv->rx_cmd_remain_len <= 0) { // rx last bye, calcuate checksum + if (!is_checksum_ok(priv->data_in.buf, priv->data_in.len)) { + DEBUGK_ERR("Rx cmd cheksum error!\n"); + goto invalid_cmd; + } + priv->data_in.len -= 2; // substract checksum length + + indicate_evt(priv, IND_CMD_EV, priv->data_in.buf, priv->data_in.len); + + RESET_RX_STATE; + } + else + priv->rx_cmd_time = jiffies; + } + } + + return; + +invalid_cmd: + RESET_RX_STATE; +} + +static void transmit_msg(struct mdio_priv *priv) +{ + unsigned short data; + + if (priv->data_out.len <= 0 || priv->tx_status_transmitting_len >= priv->data_out.len) + return; + + memcpy(&data, priv->data_out.buf+priv->tx_status_transmitting_len, 2); + register_write_dw(REG_SSR, (unsigned long)data); + + priv->tx_status_transmitting_len += 2; + + if (priv->tx_status_transmitting_len >= priv->data_out.len) + priv->tx_status_state = STATE_TX_INIT; + else + priv->tx_status_state = STATE_TX_IN_PROGRESS; +} + +#ifdef CONFIG_RTK_VOIP_ETHERNET_DSP_IS_DSP + +static irqreturn_t mdio_interrupt(int irq, void *dev_id) +{ + struct mdio_priv *priv = (struct mdio_priv *)dev_id; + + unsigned long status, data; + + while (1) { + status = register_read_dw(REG_ISR); + if (!status) + break; + + register_write_dw(REG_ISR, status); // clear interrupt + + unsigned long st_dsp_id; + extern int Set_Ethernet_DSP_ID(unsigned char dsp_id); + extern unsigned int Get_Ethernet_DSP_ID(void); + printk("in mdio_interrupt, status = 0x%x\n", status); + + if (status & 0x8)//bit3 + { + data = register_read_dw(REG_SYSCR) & 0xF;// use SYSCR bit 0~3 to decide DSP ID for each DSP. up to 16 DSP. + + if((data>=0) && (data<=3)) + { + Set_Ethernet_DSP_ID((unsigned char)data); + //printk("Set DSP ID to %d\n", data); + + // Singal AP process to chage DSP MAC addr + printk("signal to hcd to change MAC Addr\n"); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + if (priv->host_pid != -1) + kill_proc(priv->host_pid, SIGUSR2, 1); +#else + if (priv->host_pid != -1) + kill_pid(priv->host_pid, SIGUSR2, 1); +#endif + } + else + printk("%s: NOT support dsp_id=%d\n", __FUNCTION__, data); + } + else + { + printk("Get unknown mdio interrupt status = 0x%x\n", status); + } + + if (status & IP_NEWMSG) { + data = register_read_dw(REG_RCR); + process_rx_cmd(priv, (unsigned short)data); + } + if (status & IP_MSGFETCH) { + transmit_msg(priv); + } + if (status & (IP_ISOLATION|IP_ETHMAC|IP_WLANMAC|IP_ETHPHY |IP_WLANPHY|IP_SELMIICLK)) { + data = register_read_dw(REG_SYSCR); + data &= (CR_ISOLATION |CR_ETHMAC|CR_WLANMAC|CR_ETHPHY|CR_WLANPHY|CR_SELMIICLK); + indicate_evt(priv, IND_SYSCTL_EV, (unsigned char *)&data, sizeof(data)); + } +#ifdef CONFIG_RTK_VOIP_ETHERNET_DSP_IS_DSP + if (status & ~(IP_MSGFETCH|IP_NEWMSG|IP_ISOLATION|IP_ETHMAC| + IP_WLANMAC|IP_ETHPHY |IP_WLANPHY |IP_SELMIICLK |IP_CUSTOM3)) { +#else + if (status & ~(IP_MSGFETCH|IP_NEWMSG|IP_ISOLATION|IP_ETHMAC| + IP_WLANMAC|IP_ETHPHY |IP_WLANPHY|IP_SELMIICLK)) { +#endif + DEBUGK_ERR("Got satus=0x%x, not supported yet!\n", (unsigned int)status); + } + } + return IRQ_HANDLED; +} + +#else + +//static void mdio_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mdio_interrupt(int irq, void *dev_id) +{ + struct mdio_priv *priv = (struct mdio_priv *)dev_id; + + unsigned long status, data; + + while (1) { + status = register_read_dw(REG_ISR); + if (!status) + break; + + register_write_dw(REG_ISR, status); // clear interrupt + + if (status & IP_NEWMSG) { + data = register_read_dw(REG_RCR); + process_rx_cmd(priv, (unsigned short)data); + } + if (status & IP_MSGFETCH) { + transmit_msg(priv); + } + if (status & (IP_ISOLATION|IP_ETHMAC|IP_WLANMAC|IP_ETHPHY |IP_WLANPHY|IP_SELMIICLK)) { + data = register_read_dw(REG_SYSCR); + data &= (CR_ISOLATION |CR_ETHMAC|CR_WLANMAC|CR_ETHPHY|CR_WLANPHY|CR_SELMIICLK); + indicate_evt(priv, IND_SYSCTL_EV, (unsigned char *)&data, sizeof(data)); + } + if (status & ~(IP_MSGFETCH|IP_NEWMSG|IP_ISOLATION|IP_ETHMAC| + IP_WLANMAC|IP_ETHPHY |IP_WLANPHY|IP_SELMIICLK)) { + DEBUGK_ERR("Got satus=0x%x, not supported yet!\n", (unsigned int)status); + } + } + return IRQ_HANDLED; +} + +#endif + +void toggle_usb_device_insert_bit(void) +{ + unsigned long flags; + + if (dev_priv == NULL) + return; + spin_lock_irqsave(&dev_priv->reglock, flags); + if (REG32(REG_SYSSR) & SR_USBInsertStatus) + REG32(REG_SYSSR) = REG32(REG_SYSSR) & (~SR_USBInsertStatus); + else + REG32(REG_SYSSR) = REG32(REG_SYSSR) | SR_USBInsertStatus; + spin_unlock_irqrestore(&dev_priv->reglock, flags); + //printk("usb device inserted\n"); +} + +void toggle_usb_device_remove_bit(void) +{ + unsigned long flags; + + if (dev_priv == NULL) + return; + spin_lock_irqsave(&dev_priv->reglock, flags); + if (REG32(REG_SYSSR) & SR_USBRemoveStatus) + REG32(REG_SYSSR) = REG32(REG_SYSSR) & (~SR_USBRemoveStatus); + else + REG32(REG_SYSSR) = REG32(REG_SYSSR) | SR_USBRemoveStatus; + spin_unlock_irqrestore(&dev_priv->reglock, flags); + //printk("usb device removed\n"); +} + +void set_wlanlink_bit(int val) +{ + unsigned long flags; + + if (dev_priv == NULL) + return; + spin_lock_irqsave(&dev_priv->reglock, flags); + if (val) + REG32(REG_SYSSR) = REG32(REG_SYSSR) | SR_WLANLink; + else + REG32(REG_SYSSR) = REG32(REG_SYSSR) & (~SR_WLANLink); + spin_unlock_irqrestore(&dev_priv->reglock, flags); +} + +static void mdio_reg_poll_timer(unsigned long task_priv) +{ + unsigned long flags; + unsigned long reg1, reg2; + struct mdio_priv *priv = (struct mdio_priv *)task_priv; + + if (!priv->poll_timer_up) + return; + + if (priv->reg_BMCR_write != REG32(REG_BMCR)) { + //printk("1. priv->reg_BMCR_write=%x\n", priv->reg_BMCR_write); + reg1 = reg2 = REG32(REG_BMCR); + if ((reg1&0x8000) && (priv->reg_BMCR_write&0x8000)) //check "reset" bit + reg1 &= 0x7fff; + if ((reg1&0x0200) && (priv->reg_BMCR_write&0x0200)) //check "restart auto negotiation" bit + reg1 &= 0xfdff; + + if (priv->force_power_down) + reg1 |= 0x0800; //power down + priv->reg_BMCR_write = reg2; + set_ether_phy_reg(ETH_PORT_NUM, 0, reg1); + if (reg1 & 0x1000) { + if ((priv->reg_ANAR_write & 0x0180) == 0x0000) + set_ether_phy_reg(6, 0, 0x120c); + else + set_ether_phy_reg(6, 0, 0x1208); + } +#ifdef CONFIG_RTL8197B_B_CUT_PATCH + else { + if (reg1 & 0x2000) //100M + set_ether_phy_reg(6, 0, 0x120c); + else //10M + set_ether_phy_reg(6, 0, 0x1208); + } +#endif + //printk("2. priv->reg_BMCR_write=%x\n", priv->reg_BMCR_write); + } + + if (priv->reg_BMCR_read != get_ether_phy_reg(ETH_PORT_NUM, 0)) { + //printk("1. priv->reg_BMCR_read=%x\n", priv->reg_BMCR_read); + priv->reg_BMCR_read = get_ether_phy_reg(ETH_PORT_NUM, 0); + if (priv->reg_BMCR_write & 0x0800) //power down + REG32(REG_BMCR) = priv->reg_BMCR_read; + else + REG32(REG_BMCR) = priv->reg_BMCR_read & 0xf7ff; + //printk("2. priv->reg_BMCR_read=%x\n", priv->reg_BMCR_read); + } + + if (priv->reg_BMSR_read != get_ether_phy_reg(ETH_PORT_NUM, 1)) { + reg1 = get_ether_phy_reg(ETH_PORT_NUM, 1); + if ((priv->reg_BMSR_read ^ reg1) & (~BIT(2))) { + //toggle EthPHYStatusChange bit to generate interrupt + spin_lock_irqsave(&priv->reglock, flags); + if (REG32(REG_SYSSR) & SR_EthPHYStatusChange) + REG32(REG_SYSSR) = REG32(REG_SYSSR) & (~SR_EthPHYStatusChange); + else + REG32(REG_SYSSR) = REG32(REG_SYSSR) | SR_EthPHYStatusChange; + spin_unlock_irqrestore(&priv->reglock, flags); + //printk("EthPhy status changed!\n"); + } + + priv->reg_BMSR_read = reg1; + REG32(REG_BMSR) = priv->reg_BMSR_read; + + if (priv->eth_phy_link_status != ((priv->reg_BMSR_read & BIT(2)) ? 1 : 0)) { + priv->eth_phy_link_status = ((priv->reg_BMSR_read & BIT(2)) ? 1 : 0); + spin_lock_irqsave(&priv->reglock, flags); + if (priv->eth_phy_link_status) + REG32(REG_SYSSR) = REG32(REG_SYSSR) | SR_EthLink; + else + REG32(REG_SYSSR) = REG32(REG_SYSSR) & (~SR_EthLink); + spin_unlock_irqrestore(&priv->reglock, flags); + //DEBUGK_OUT("Ether Link changed [%d]!\n", priv->eth_phy_link_status); + //printk("Ether Link changed [%d]!\n", priv->eth_phy_link_status); + } + } + + if (!(priv->reg_BMCR_write&0x8000)) { + if (priv->reg_ANAR_write != REG32(REG_ANAR)) { + //printk("1. priv->reg_ANAR_write=%x\n", priv->reg_ANAR_write); + priv->reg_ANAR_write = REG32(REG_ANAR); + //printk("2. priv->reg_ANAR_write=%x\n", priv->reg_ANAR_write); + set_ether_phy_reg(ETH_PORT_NUM, 4, priv->reg_ANAR_write); + //printk("3. priv->reg_ANAR_write=%x\n", priv->reg_ANAR_write); + if (priv->reg_BMCR_write&0x1000) { + if ((priv->reg_ANAR_write & 0x0180) == 0x0000) + set_ether_phy_reg(6, 0, 0x120c); + else + set_ether_phy_reg(6, 0, 0x1208); + } + } + } + + if (priv->reg_ANAR_read != get_ether_phy_reg(ETH_PORT_NUM, 4)) { + //printk("1. priv->reg_ANAR_read=%x\n", priv->reg_ANAR_read); + priv->reg_ANAR_read = get_ether_phy_reg(ETH_PORT_NUM, 4); + //printk("2. priv->reg_ANAR_read=%x\n", priv->reg_ANAR_read); + REG32(REG_ANAR) = priv->reg_ANAR_read; + } + + if (priv->reg_ANLPAR_read != get_ether_phy_reg(ETH_PORT_NUM, 5)) { + priv->reg_ANLPAR_read = get_ether_phy_reg(ETH_PORT_NUM, 5); + REG32(REG_ANLPAR) = priv->reg_ANLPAR_read; + } + + mod_timer(&priv->reg_poll_timer, jiffies + priv->phy_reg_poll_time); +} + +static int mdio_open(struct inode *inode, struct file *filp) +{ + filp->private_data = dev_priv; + //MOD_INC_USE_COUNT; + return 0; +} + +static int mdio_close(struct inode *inode, struct file *filp) +{ + //MOD_DEC_USE_COUNT; + return 0; +} + +static ssize_t mdio_read (struct file *filp, char *buf, size_t count, loff_t *offset) +{ + struct mdio_priv *priv = (struct mdio_priv *)filp->private_data; + + if (!buf) + return 0; + + count = retrieve_evt(priv, buf); + + return count; +} + +static ssize_t mdio_write (struct file *filp, const char *buf, size_t count, loff_t *offset) +{ + struct mdio_priv *priv = (struct mdio_priv *)filp->private_data; + unsigned short last_word = 0; + + if (!buf) { + DEBUGK_ERR("buf = NULL!\n"); + goto ret; + } + + if (count > MDIO_BUFSIZE) { + DEBUGK_ERR("write length too big!\n"); + count = -EFAULT; + goto ret; + } + + if (priv->tx_status_state != STATE_TX_INIT) { + DEBUGK_ERR("Transmit status, but not in valid state [%d]. Reset state!\n", priv->tx_status_state); + priv->tx_status_state = STATE_TX_INIT; + } + + if (count %2) { + DEBUGK_ERR("Invalid Tx size [%d]!\n", count); + count = -EFAULT; + goto ret; + } + + if (copy_from_user((void *)priv->data_out.buf, buf, count)) { + DEBUGK_ERR("copy_from_user() error!\n"); + count = -EFAULT; + goto ret; + } + +#ifdef KDB_MSG + debugk_out("write data", priv->data_out.buf, count); +#endif + + last_word = (unsigned short) append_checksum(priv->data_out.buf, count); + memcpy(&priv->data_out.buf[count], &last_word, 2); + + priv->data_out.len = count + sizeof(last_word); + priv->tx_status_transmitting_len = 0; + priv->tx_status_state = STATE_TX_INIT; + + transmit_msg(priv); + +ret: + return count; +} + +static void dump_private_data(void) +{ + //int i; + + printk("cmd_timeout=%d\n", dev_priv->cmd_timeout); + printk("poll_timer_up=%d\n", dev_priv->poll_timer_up); + printk("phy_reg_poll_time=%d\n", dev_priv->phy_reg_poll_time); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + printk("host_pid=%d\n", dev_priv->host_pid); +#else + printk("host_pid=0x%p\n", dev_priv->host_pid); +#endif + printk("force_power_down=%d\n", dev_priv->force_power_down); + printk("eth_phy_link_status=%d\n", dev_priv->eth_phy_link_status); + printk("\nreg_BMCR_write=0x%04lx\n", dev_priv->reg_BMCR_write); + printk("reg_BMCR_read=0x%04lx\n", dev_priv->reg_BMCR_read); + printk("reg_BMSR_read=0x%04lx\n", dev_priv->reg_BMSR_read); + printk("reg_ANAR_write=0x%04lx\n", dev_priv->reg_ANAR_write); + printk("reg_ANAR_read=0x%04lx\n", dev_priv->reg_ANAR_read); + printk("reg_ANLPAR_read=0x%04lx\n", dev_priv->reg_ANLPAR_read); + + printk("\nevt_que_head=%d\n", dev_priv->evt_que_head); + printk("evt_que_tail=%d\n", dev_priv->evt_que_tail); + printk("evt_que count=%d\n", CIRC_CNT(dev_priv->evt_que_head, dev_priv->evt_que_tail, EV_QUE_MAX)); + printk("evt_que space=%d\n", CIRC_SPACE(dev_priv->evt_que_head, dev_priv->evt_que_tail, EV_QUE_MAX)); + + printk("\ntx_status_state:"); + switch(dev_priv->tx_status_state) { + case STATE_TX_INIT: + printk("STATE_TX_INIT\n"); + break; + case STATE_TX_IN_PROGRESS: + printk("STATE_TX_IN_PROGRESS\n"); + break; + } + printk("tx_status_transmitting_len=%d\n", dev_priv->tx_status_transmitting_len); + + printk("rx_cmd_state:"); + switch(dev_priv->rx_cmd_state) { + case STATE_RX_INIT: + printk("STATE_RX_INIT\n"); + break; + case STATE_RX_WAIT_LEN: + printk("STATE_RX_WAIT_LEN\n"); + break; + case STATE_RX_WAIT_DATA: + printk("STATE_RX_WAIT_DATA\n"); + break; + case STATE_RX_WAIT_DAEMON: + printk("STATE_RX_WAIT_DAEMON\n"); + break; + } + printk("rx_cmd_remain_len=%d\n", dev_priv->rx_cmd_remain_len); + printk("rx_cmd_time=%lx jiffies=%lx (%d sec)\n", dev_priv->rx_cmd_time, jiffies, (int)(jiffies-dev_priv->rx_cmd_time)/HZ); +} + +void mdio_private_command(int type) +{ + switch(type) { + case 0: //stop reg poll timer + dev_priv->poll_timer_up = 0; + break; + case 1: //start reg poll timer + dev_priv->poll_timer_up = 1; + mod_timer(&dev_priv->reg_poll_timer, jiffies + dev_priv->phy_reg_poll_time); + break; + case 2: //force power down: on + dev_priv->force_power_down = 1; + dev_priv->reg_BMCR_write = 0xf0000; //force poll timer to do power down + break; + case 3: //force power down: off + dev_priv->force_power_down = 0; + dev_priv->reg_BMCR_write = 0xf0000; //force poll timer to do power down + break; + case 4: + dump_private_data(); + break; + case 5: //WLAN link up + set_wlanlink_bit(1); + break; + case 6: //WLAN link down + set_wlanlink_bit(0); + break; + } +} + +static int mdio_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + struct mdio_priv *priv = (struct mdio_priv *)filp->private_data; + int val, retval = 0; + unsigned char bval; + struct mdio_mem32_param mem_param; + struct reg_param regparam; + + /* + * extract the type and number bitfields, and don't decode + * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() + */ + if (_IOC_TYPE(cmd) != MDIO_IOC_MAGIC) return -ENOTTY; + if (_IOC_NR(cmd) > MDIO_IOCTL_MAXNR) return -ENOTTY; + + switch (cmd) { + case MDIO_IOCTL_PRIV_CMD: + retval = get_user(val, (int *)arg); + if (retval == 0) { + mdio_private_command(val); + } + break; + case MDIO_IOCTL_GET_REG: + retval = copy_from_user(®param, (struct reg_param *)arg, sizeof(struct reg_param)); + if (retval == 0) { + //printk("1regparam.addr=%x regparam.val=%x\n", regparam.addr, regparam.val); + regparam.val = get_ether_phy_reg(((regparam.addr>>16)&0xffff), (regparam.addr&0xffff)); + //printk("2regparam.addr=%x regparam.val=%x\n", regparam.addr, regparam.val); + } + retval = copy_to_user((struct reg_param *)arg, ®param, sizeof(struct reg_param)); + break; + case MDIO_IOCTL_SET_REG: + retval = copy_from_user(®param, (struct reg_param *)arg, sizeof(struct reg_param)); + if (retval == 0) { + //printk("regparam.addr=%x regparam.val=%x\n", regparam.addr, regparam.val); + set_ether_phy_reg(((regparam.addr>>16)&0xffff), (regparam.addr&0xffff), regparam.val); + } + break; + case MDIO_IOCTL_SET_HOST_PID: + retval = copy_from_user((void *)&val, (void *)arg, 4); + if (retval == 0) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + priv->host_pid = val; +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) + priv->host_pid = find_pid_ns(val,0); +#else + // TODO : Check in stable 2.6.27 + priv->host_pid = task_pid(find_task_by_vpid(val)); + //priv->host_pid = task_pid(current); +#endif + DEBUGK_OUT("set pid=%d\n", val); + printk("set pid=%d priv->host_pid=%p\n", val, priv->host_pid); + } + spin_lock_irqsave(&priv->reglock, flags); + REG32(REG_SYSSR) = REG32(REG_SYSSR) | SR_AllSoftwareReady; + spin_unlock_irqrestore(&priv->reglock, flags); + break; + case MDIO_IOCTL_SET_CMD_TIMEOUT: + retval = copy_from_user((void *)&bval, (void *)arg, 1); + if (retval == 0) { + priv->cmd_timeout = (int)bval; + DEBUGK_OUT("set cmd_timeout=%d\n", priv->cmd_timeout); + } + break; + case MDIO_IOCTL_SET_PHY_POLL_TIME: + retval = copy_from_user( (void *)&bval, (void *)arg, 1); + if (retval == 0) { + priv->phy_reg_poll_time = (int)bval; + mod_timer(&priv->reg_poll_timer, jiffies + priv->phy_reg_poll_time); + DEBUGK_OUT("set poll_time=%d\n", priv->phy_reg_poll_time); + } + break; + case MDIO_IOCTL_READ_MEM: + retval = copy_from_user( (void *)&mem_param.addr, (void *)arg, 4); + if (retval == 0) { + mem_param.val = READ_MEM32(mem_param.addr); + retval = copy_to_user((void *)arg, (void *)&mem_param.val, 4); + DEBUGK_OUT("read_mem: addr=0x%x, data=0x%x\n", (int)mem_param.addr, (int)mem_param.val); + } + break; + case MDIO_IOCTL_WRITE_MEM: + retval = copy_from_user((void *)&mem_param, (void *)arg, sizeof(mem_param)); + if (retval == 0) { + WRITE_MEM32(mem_param.addr, mem_param.val); + DEBUGK_OUT("write_mem: addr=0x%x, data=0x%x\n", (int)mem_param.addr, (int)mem_param.val); + } + break; + case MDIO_IOCTL_SET_MII_PAUSE: + retval = copy_from_user( (void *)&bval, (void *)arg, 1); + if (retval == 0) { + if (bval == 0) // disable pause + WRITE_MEM32(PCRP0, (~(0x3<<PauseFlowControl))&READ_MEM32(PCRP0)); + else + WRITE_MEM32(PCRP0, (3<<PauseFlowControl)|READ_MEM32(PCRP0)); + DEBUGK_OUT("set mii_pause=%d\n", bval); + } + break; + case MDIO_IOCTL_SET_ETH_PAUSE: + retval = copy_from_user( (void *)&bval, (void *)arg, 1); + if (retval == 0) { + if (bval == 0) // disable pause + WRITE_MEM32(PCRP3, (~(0x3<<PauseFlowControl))&READ_MEM32(PCRP3)); + else + WRITE_MEM32(PCRP3, (3<<PauseFlowControl)|READ_MEM32(PCRP3)); + DEBUGK_OUT("set eth_pause=%d\n", bval); + } + break; + case MDIO_IOCTL_SET_MII_CLK: + retval = copy_from_user( (void *)&val, (void *)arg, 4); + if (retval == 0) { + if (val == 0) { //00: 25MHz at 100M mode + WRITE_MEM32(PCRP0, (~(0x3<<20))&READ_MEM32(PCRP0)); //force 100Mbps for port 0 + WRITE_MEM32(P0GMIICR, (~(1<<22))&READ_MEM32(P0GMIICR)); //Turbo MII off + } + else if (val == 1) { //01: 2.5MHz at 10M mode + WRITE_MEM32(PCRP0, (1<<20)|((~(0x3<<20))&READ_MEM32(PCRP0))); //force 10Mbps for port 0 + WRITE_MEM32(P0GMIICR, (~(1<<22))&READ_MEM32(P0GMIICR)); //Turbo MII off + } + else if (val == 2) { //10: 50MHz at Turbo-MII mode + WRITE_MEM32(PCRP0, (~(0x3<<20))&READ_MEM32(PCRP0)); //force 100Mbps for port 0 + WRITE_MEM32(P0GMIICR, (1<<22)|READ_MEM32(P0GMIICR)); //using Turbo MII + } + //printk("set mii clk=%d\n", val); + } + break; + case MDIO_IOCTL_SET_SUSPEND: + retval = copy_from_user( (void *)&bval, (void *)arg, 1); + if (retval == 0) { + cpu_suspend_enabled = (int) bval; + DEBUGK_OUT("set cpu_suspend=%d\n", bval); + } + break; + case MDIO_IOCTL_READ_SCR: + val = register_read_dw(REG_SYSCR); + retval = copy_to_user((void *)arg, (void *)&val, sizeof(val)); + DEBUGK_OUT("read_src src=0x%x\n", val); + break; +#ifdef CONFIG_RTK_VOIP_ETHERNET_DSP_IS_DSP + case MDIO_IOCTL_READ_DSP_ID: + { + unsigned int id; + extern unsigned int Get_Ethernet_DSP_ID(void); + id = Get_Ethernet_DSP_ID(); + retval = copy_to_user((void *)arg, (void *)&id, sizeof(id)); + printk("Get DSP ID = %d\n", id); + break; + } +#endif +#ifdef JUMP_CMD + case MDIO_IOCTL_JUMP_ADDR: + retval = copy_from_user( (void *)&val, (void *)arg, sizeof(val)); + if (retval == 0) { + extern void setup_reboot_addr(unsigned long addr); + extern int is_fault; + + DEBUGK_OUT("jump to addr=0x%x\n", val); + setup_reboot_addr((unsigned long)val); + is_fault = 1; // cause watchdog reset + } + break; +#endif + default: /* redundant, as cmd was checked against MAXNR */ + DEBUGK_ERR("Invalid ioctl cmd [0x%x]!\n", cmd); + return -ENOTTY; + } + return retval; +} + +#ifdef SIMULATION +static int read_proc(char *buf, char **start, off_t off, + int count, int *eof, void *data) +{ + int size = 0; + + if (data_out_len > 0) { + +fetch_again: + while (data_out_len > 0) { + data_out_len = 0; + size += sprintf(&buf[size], "%04x ", data_out); + } + + msg_is_fetched = 1; + + mdio_interrupt(0, (void *)dev_priv, (struct pt_regs *)NULL); + + if (data_out_len > 0) + goto fetch_again; + + strcat(&buf[size++], "\n"); + } + + return size; +} + +static unsigned short _atoi(char *s, int base) +{ + int k = 0; + + k = 0; + if (base == 10) { + while (*s != '\0' && *s >= '0' && *s <= '9') { + k = 10 * k + (*s - '0'); + s++; + } + } + else { + while (*s != '\0') { + int v; + if ( *s >= '0' && *s <= '9') + v = *s - '0'; + else if ( *s >= 'a' && *s <= 'f') + v = *s - 'a' + 10; + else if ( *s >= 'A' && *s <= 'F') + v = *s - 'A' + 10; + else { + DEBUGK_ERR("error hex format [%x]!\n", *s); + return 0; + } + k = 16 * k + v; + s++; + } + } + return (unsigned short)k; +} + + +static int write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char tmp[100]; + int len=count; + unsigned short in_data; + + if (!memcmp(buffer, "cmd: ", 5)) { + buffer += 5; + len -= 5; + data_in_len = 0; + while (len > 0) { + memcpy(tmp, buffer, 4); + tmp[4] = '\0'; + + in_data = _atoi(tmp, 16); + + memcpy(&data_in[data_in_len], &in_data, 2); + data_in_len += 2; + len -= 5; + buffer += 5; + } + + data_in_read_idx = 0; + mdio_interrupt(0, (void *)dev_priv, (struct pt_regs *)NULL); + } + else if (!memcmp(buffer, "scr: ", 5)) { + buffer += 5; + memcpy(tmp, buffer, 4); + tmp[4] = '\0'; + reg_scr = _atoi(tmp, 16); + } + else if (!memcmp(buffer, "isr: ", 5)) { + buffer += 5; + memcpy(tmp, buffer, 4); + tmp[4] = '\0'; + reg_isr = _atoi(tmp, 16); + + mdio_interrupt(0, (void *)dev_priv, (struct pt_regs *)NULL); + } + else { + printk("Invalid cmd!\n"); + } + + return count; +} +#endif + + +static void __exit mdio_exit(void) +{ + //DEBUGK_OUT("%s: major=%d, minor=%d\n", __FUNCTION__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); + + REG32(REG_IMR) = 0; + + free_irq(BSP_NFBI_IRQ, dev_priv); + + del_timer_sync(&dev_priv->reg_poll_timer); + + kfree(dev_priv); + + dev_priv = NULL; +} + +static struct file_operations mdio_fops = { + read: mdio_read, + write: mdio_write, + ioctl: mdio_ioctl, + open: mdio_open, + release: mdio_close, +}; + +static int __init mdio_init(void) +{ + struct mdio_priv *priv; + + if (register_chrdev(DRIVER_MAJOR, DRIVER_NAME, &mdio_fops)) { + DEBUGK_ERR(KERN_ERR DRIVER_NAME": unable to get major %d\n", DRIVER_MAJOR); + return -EIO; + } + +#ifdef SIMULATION + struct proc_dir_entry *res; + res = create_proc_entry("mdio_flag", 0, NULL); + if (res) { + res->read_proc = read_proc; + res->write_proc = write_proc; + } + else { + DEBUGK_ERR(KERN_ERR DRIVER_NAME": unable to create /proc/mdio_flag\n"); + return -1; + } +#endif + + printk(KERN_INFO DRIVER_NAME" driver "DRIVER_VER" at %x (Interrupt %d)\n", NFBI_BASE, BSP_NFBI_IRQ); + + DEBUGK_OUT("%s: major=%d, minor=%d\n", __FUNCTION__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); + + priv = (struct mdio_priv *)kmalloc(sizeof (struct mdio_priv), GFP_KERNEL); + if(!priv) + return -ENOMEM; + + memset((void *)priv, 0, sizeof (struct mdio_priv)); + priv->reglock = SPIN_LOCK_UNLOCKED; + //if (request_irq(BSP_NFBI_IRQ, mdio_interrupt, SA_INTERRUPT, DRIVER_NAME, (void *)priv)) { + //if (request_irq(BSP_NFBI_IRQ, mdio_interrupt, IRQF_DISABLED, DRIVER_NAME, (void *)priv)) { + if (request_irq(BSP_NFBI_IRQ, mdio_interrupt, 0, DRIVER_NAME, (void *)priv)) { + DEBUGK_ERR(KERN_ERR DRIVER_NAME": IRQ %d is not free.\n", BSP_NFBI_IRQ); + return -1; + } + else + printk("Request BSP_NFBI_IRQ successfully.\n"); + + REG32(REG_IMR) = NEEDED_IRQ_MASK; + +#if 1 + //force the poll time to update the register + priv->reg_BMCR_write = 0xf0000; + priv->reg_BMCR_read = 0xf0000; + priv->reg_BMSR_read = 0xf0000; + priv->reg_ANAR_write = 0xf0000; + priv->reg_ANAR_read = 0xf0000; + priv->reg_ANLPAR_read = 0xf0000; + priv->eth_phy_link_status = -1; +#else + priv->reg_BMCR_write = REG32(REG_BMCR); + set_ether_phy_reg(ETH_PORT_NUM, 0, priv->reg_BMCR_write); + + priv->reg_BMCR_read = get_ether_phy_reg(ETH_PORT_NUM, 0); + REG32(REG_BMCR) = priv->reg_BMCR_read; + + priv->reg_BMSR_read = get_ether_phy_reg(ETH_PORT_NUM, 1); + REG32(REG_BMSR) = priv->reg_BMSR_read; + + priv->reg_ANAR_write = REG32(REG_ANAR); + set_ether_phy_reg(ETH_PORT_NUM, 4, priv->reg_ANAR_write); + //printk("priv->reg_ANAR_write=%x\n", priv->reg_ANAR_write); + + priv->reg_ANAR_read = get_ether_phy_reg(ETH_PORT_NUM, 4); + REG32(REG_ANAR) = priv->reg_ANAR_read; + //printk("priv->reg_ANAR_read=%x\n", priv->reg_ANAR_read); + + priv->reg_ANLPAR_read = get_ether_phy_reg(ETH_PORT_NUM, 5); + REG32(REG_ANLPAR) = priv->reg_ANLPAR_read; + + priv->eth_phy_link_status = ((priv->reg_BMSR_read & BIT(2)) ? 1 : 0); +#endif + + init_timer(&priv->reg_poll_timer); + priv->reg_poll_timer.data = (unsigned long)priv; + priv->reg_poll_timer.function = mdio_reg_poll_timer; + priv->poll_timer_up = 0; + priv->force_power_down = 0; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + priv->host_pid = -1; +#else + priv->host_pid = NULL; +#endif + dev_priv = priv; + + return 0; +} + + +/*================================================================*/ + +module_init(mdio_init); +module_exit(mdio_exit); + +MODULE_DESCRIPTION("Driver for RTL8197B MDC/MDIO"); +MODULE_LICENSE("none-GPL"); +//EXPORT_NO_SYMBOLS; diff --git a/target/linux/realtek/files/drivers/char/rtl_mdio/rtl_mdio.h b/target/linux/realtek/files/drivers/char/rtl_mdio/rtl_mdio.h new file mode 100644 index 000000000..5def6bd34 --- /dev/null +++ b/target/linux/realtek/files/drivers/char/rtl_mdio/rtl_mdio.h @@ -0,0 +1,309 @@ +/* +################################################################################ +# +# RTL8198 MDIO char driver header
+# +# Copyright(c) 2010 Realtek Semiconductor Corp. All rights reserved.
+# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>. +# +# Author: +# Realtek WiFi AP software team <cn_sd8@realtek.com>
+# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/
+/*================================================================*/
+
+#ifndef INCLUDE_RTL_MDIO_H
+#define INCLUDE_RTL_MDIO_H
+
+
+/*================================================================*/
+/* Compiling Flags */
+
+#define KDB_ERR // defined to print out error message
+//#define KDB_MSG // defined to print out debug message
+//#define SIMULATION // defined to do simuation
+#ifndef CONFIG_RTK_VOIP_ETHERNET_DSP_IS_DSP
+#define JUMP_CMD // defined to add jump ioctl cmd, for development purpose
+#endif
+
+
+/*================================================================*/
+/* Constant Definitions */
+
+#define DRIVER_NAME "rtl_mdio"
+#define DRIVER_VER "0.2"
+#define IO_LEN 0x40
+#define DRIVER_MAJOR 14
+#define MDIO_BUFSIZE 516 //2 + 2 + 2*255 + 2
+#define EV_QUE_MAX 16
+//#define BIT(x) (1 << (x))
+
+// RTL8197B IRQ number and Register offset
+#define NFBI_BASE 0xb8019000 // NFBI base address
+#define REG_RCR (0x00+NFBI_BASE) // Receive Command Register
+#define REG_SSR (0x04+NFBI_BASE) // Send Status Register
+#define REG_SYSCR (0x08+NFBI_BASE) // System Control Register
+#define REG_SYSSR (0x0C+NFBI_BASE) // System Status Register
+#define REG_IMR (0x10+NFBI_BASE) // Interrupt Mask Register
+#define REG_ISR (0x14+NFBI_BASE) // Interrupt Status Register
+#define REG_BMCR (0x20+NFBI_BASE) // Basic Mode Control Register
+#define REG_BMSR (0x24+NFBI_BASE) // Basic Mode Status Register
+#define REG_ANAR (0x28+NFBI_BASE) // Auto-Negotiation Advertisement Register
+#define REG_ANLPAR (0x2C+NFBI_BASE) // Auto-Negotiation Link Partner Ability Register
+#define REG_NFBIRR (0x30+NFBI_BASE) // NFBI Reset Control Register
+
+// bitmask definition for ISR
+#define IP_ISOLATION BIT(15) // ISOLATION Interrupt Pending
+#define IP_ETHMAC BIT(14) // Enable/disable Ethernet MAC
+#define IP_WLANMAC BIT(13) // Enable/disable WLAN MAC
+#define IP_ETHPHY BIT(12) // Enable/disable Ethernet PHY
+#define IP_WLANPHY BIT(11) // Enable/disable WLAN PHY
+#define IP_SELMIICLK BIT(10) // Select MII Clock Speed
+#define IP_RSVD9 BIT(9) // Reserved
+#define IP_CUSTOM8 BIT(8) // Customized used 8
+#define IP_CUSTOM7 BIT(7) // Customized used 7
+#define IP_CUSTOM6 BIT(6) // Customized used 6
+#define IP_CUSTOM5 BIT(5) // Customized used 5
+#define IP_CUSTOM4 BIT(4) // Customized used 4
+#define IP_CUSTOM3 BIT(3) // Customized used 3
+#define IP_MSGFETCH BIT(2) // Previous msg has been fetched
+#define IP_NEWMSG BIT(1) // New msg has come
+#define IP_RSVD0 BIT(0) // Reserved
+
+// bitmask definition for SCR
+#define CR_ISOLATION BIT(15) // ISOLATION control bit
+#define CR_ETHMAC BIT(14) // Ethernet MAC control bit
+#define CR_WLANMAC BIT(13) // WLAN MAC control bit
+#define CR_ETHPHY BIT(12) // Ethernet PHY control bi
+#define CR_WLANPHY BIT(11) // WLAN PHY control bit
+#define CR_SELMIICLK (BIT(10)|BIT(9)) // Select MII Clock Speed control bit
+#define CR_CUSTOM8 BIT(8) // Customized used 8
+#define CR_CUSTOM7 BIT(7) // Customized used 7
+#define CR_CUSTOM6 BIT(6) // Customized used 6
+#define CR_CUSTOM5 BIT(5) // Customized used 5
+#define CR_CUSTOM4 BIT(4) // Customized used 4
+#define CR_CUSTOM3 BIT(3) // Customized used 3
+#define CR_CUSTOM2 BIT(2) // Customized used 2
+#define CR_CUSTOM1 BIT(1) // Customized used 1
+#define CR_CUSTOM0 BIT(0) // Customized used 0
+
+// bitmask definition for SYSSR
+#define SR_CheckSumDone BIT(15)
+#define SR_CheckSumOK BIT(14)
+#define SR_WLANLink BIT(13)
+#define SR_EthLink BIT(12)
+#define SR_EthPHYStatusChange BIT(11)
+#define SR_AllSoftwareReady BIT(10)
+#define SR_USBInsertStatus BIT(7)
+#define SR_USBRemoveStatus BIT(6)
+#define SR_BootcodeReady BIT(5)
+
+// rx cmd id bitmask
+#define FIRST_CMD_MASK BIT(15)
+
+// All received interrupt mask
+#ifdef CONFIG_RTK_VOIP_ETHERNET_DSP_IS_DSP
+#define NEEDED_IRQ_MASK (IP_NEWMSG|IP_MSGFETCH|IP_SELMIICLK|IP_WLANPHY| \
+ IP_ETHPHY|IP_WLANMAC|IP_ETHMAC|IP_ISOLATION|IP_CUSTOM3)
+#else
+#define NEEDED_IRQ_MASK (IP_NEWMSG|IP_MSGFETCH|IP_SELMIICLK|IP_WLANPHY| \
+ IP_ETHPHY|IP_WLANMAC|IP_ETHMAC|IP_ISOLATION)
+#endif
+
+/* Ether register base address */
+#define MACCR_BASE 0xbb804000 /* Internal Ether MAC base address */
+#define PCRAM_BASE (MACCR_BASE+0x100) /* Per-port Configuration Register */
+#define PCRP0 (0x004 + PCRAM_BASE) /* Port Configuration Register of Port 0 */
+#define PCRP3 (0x010 + PCRAM_BASE) /* Port Configuration Register of Port 3 */
+#define P0GMIICR (0x04C + PCRAM_BASE) /* Port-0 GMII Configuration Register */
+#define PauseFlowControl 8 /* Bit-shift number of PauseFlowControl */
+
+/* MAC control register field definitions */
+#define MDCIOCR (0x004+MACCR_BASE) /* MDC/MDIO Command */
+#define MDCIOSR (0x008+MACCR_BASE) /* MDC/MDIO Status */
+//#define STATUS (1<<31) /* 0: Process Done, 1: In progress */
+//STATUS has been defined in linux-2.6.30/arch/rlx/include/asm/ptrace.h
+#define MDCIO_STATUS (1<<31) /* 0: Process Done, 1: In progress */
+
+/* MDCIOCR - MDC/MDIO Command */
+#define COMMAND_READ (0<<31) /* 0:Read Access, 1:Write Access */
+#define COMMAND_WRITE (1<<31) /* 0:Read Access, 1:Write Access */
+
+#define PHYADD_OFFSET (24) /* PHY Address, said, PHY ID */
+#define REGADD_OFFSET (16) /* PHY Register */
+
+#define ETH_PORT_NUM (3) /* Port number of built-in Ether phy */
+#define MII_PORT_NUM (0) /* Port number of NFBI MII */
+
+// rx cmd state
+enum {
+ STATE_RX_INIT,
+ STATE_RX_WAIT_LEN,
+ STATE_RX_WAIT_DATA,
+ STATE_RX_WAIT_DAEMON
+};
+
+// tx status state
+enum {
+ STATE_TX_INIT,
+ STATE_TX_IN_PROGRESS
+};
+
+// indication event id
+enum {
+ IND_CMD_EV,
+ IND_SYSCTL_EV
+};
+
+// cmd id of write data
+enum {
+ WRITE_MDIO,
+ SET_CMD_TIMEOUT,
+ SET_PHY_POLL_TIME,
+ SET_HOST_PID,
+};
+
+// cmd id of ioctl
+#define MDIO_IOC_MAGIC 'k'
+
+#define MDIO_IOCTL_SET_HOST_PID _IOW(MDIO_IOC_MAGIC, 0, int)
+#define MDIO_IOCTL_SET_CMD_TIMEOUT _IOW(MDIO_IOC_MAGIC, 1, char)
+#define MDIO_IOCTL_SET_PHY_POLL_TIME _IOW(MDIO_IOC_MAGIC, 2, char)
+#define MDIO_IOCTL_READ_MEM _IOWR(MDIO_IOC_MAGIC, 3, int)
+#define MDIO_IOCTL_WRITE_MEM _IOW(MDIO_IOC_MAGIC, 4, struct mdio_mem32_param)
+#define MDIO_IOCTL_SET_MII_PAUSE _IOW(MDIO_IOC_MAGIC, 5, char)
+#define MDIO_IOCTL_SET_SUSPEND _IOW(MDIO_IOC_MAGIC, 6, char)
+#define MDIO_IOCTL_READ_SCR _IOR(MDIO_IOC_MAGIC, 7, int)
+#define MDIO_IOCTL_JUMP_ADDR _IOW(MDIO_IOC_MAGIC, 8, int)
+#define MDIO_IOCTL_PRIV_CMD _IOW(MDIO_IOC_MAGIC, 9, int)
+#define MDIO_IOCTL_GET_REG _IOWR(MDIO_IOC_MAGIC, 10, struct reg_param)
+#define MDIO_IOCTL_SET_REG _IOW(MDIO_IOC_MAGIC, 11, struct reg_param)
+#define MDIO_IOCTL_SET_MII_CLK _IOW(MDIO_IOC_MAGIC, 12, int)
+#define MDIO_IOCTL_SET_ETH_PAUSE _IOW(MDIO_IOC_MAGIC, 13, char)
+#ifdef CONFIG_RTK_VOIP_ETHERNET_DSP_IS_DSP
+#define MDIO_IOCTL_READ_DSP_ID _IOW(MDIO_IOC_MAGIC, 14, unsigned int)
+#define MDIO_IOCTL_MAXNR 14
+#else
+#define MDIO_IOCTL_MAXNR 13
+#endif
+
+#define TIME_DIFF(a, b) ((a >= b)? (a - b):(0xffffffff - b + a + 1))
+#define EVT_BUF_OFFSET ((int)(long *)&(((struct evt_msg *)0)->buf))
+#ifdef REG32
+ #undef REG32
+#endif
+#define REG32(reg) (*((volatile unsigned long *)(reg)))
+
+#ifdef WRITE_MEM32
+ #undef WRITE_MEM32
+ #undef READ_MEM32
+#endif
+#define WRITE_MEM32(reg,val) REG32(reg)=val
+#define READ_MEM32(reg) REG32(reg)
+
+#ifndef SIMULATION
+#define register_read_dw(offset) (REG32(offset))
+#define register_write_dw(offset, data) (REG32(offset)=data)
+#endif
+
+#define PUT_IN_DATA(data) { \
+ memcpy(&priv->data_in.buf[priv->data_in.len], &data, 2); \
+ priv->data_in.len += 2; \
+}
+
+#define RESET_RX_STATE { \
+ priv->rx_cmd_state = STATE_RX_INIT; \
+ priv->data_in.len = 0; \
+ priv->rx_cmd_time = 0; \
+}
+
+#ifdef KDB_MSG
+ #define DEBUGK_OUT(fmt, args...) printk("%s_%s: "fmt, DRIVER_NAME, __FUNCTION__, ## args)
+
+ #define ASSERT(expr) \
+ if(!(expr)) { \
+ printk( "\033[33;41m%s:%d: assert(%s)\033[m\n", \
+ __FILE__,__LINE__,#expr); \
+ }
+#else
+ #define DEBUGK_OUT(fmt, args...)
+
+ #define ASSERT(expr)
+#endif
+
+#ifdef KDB_ERR
+ #define DEBUGK_ERR(fmt, args...) printk("%s_%s_ERR: "fmt, DRIVER_NAME, __FUNCTION__, ## args)
+#else
+ #define DEBUGK_ERR(fmt, args...)
+#endif
+
+/*================================================================*/
+/* Structure Definition */
+
+struct buf_ar {
+ int len;
+ unsigned char buf[MDIO_BUFSIZE];
+};
+
+struct evt_msg {
+ int id; // event id
+ int len; // length in buf
+ unsigned char buf[MDIO_BUFSIZE];
+};
+
+struct mdio_mem32_param {
+ unsigned long addr;
+ unsigned long val;
+};
+
+struct reg_param {
+ unsigned long addr;
+ unsigned long val;
+};
+
+#ifdef __KERNEL__
+struct mdio_priv {
+ int cmd_timeout; // in 10ms
+ int phy_reg_poll_time; // in 10ms
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+ int host_pid; // pid of host-daemon
+#else
+ struct pid *host_pid;
+#endif
+ int poll_timer_up;
+ int force_power_down;
+ struct timer_list reg_poll_timer;
+ unsigned long reg_BMCR_read, reg_BMCR_write;
+ unsigned long reg_BMSR_read;
+ unsigned long reg_ANAR_read, reg_ANAR_write;
+ unsigned long reg_ANLPAR_read;
+ int eth_phy_link_status;
+ struct file *filp;
+ struct buf_ar data_out;
+ struct buf_ar data_in;
+ int rx_cmd_state;
+ unsigned long rx_cmd_time;
+ int rx_cmd_remain_len;
+ int tx_status_state;
+ int tx_status_transmitting_len;
+ int evt_que_head, evt_que_tail;
+ struct evt_msg ind_evt_que[EV_QUE_MAX];
+ spinlock_t reglock;
+};
+#endif
+
+#endif // INCLUDE_RTL_MDIO_H
|