summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/files/drivers/char
diff options
context:
space:
mode:
authorRoman Yeryomin <roman@advem.lv>2013-02-06 02:59:31 +0200
committerRoman Yeryomin <roman@advem.lv>2013-02-06 02:59:31 +0200
commit691cc9529efe8ea7abaab170c452ae4470bf3ac2 (patch)
tree8d18d131720975fc63c8c2abc7bd933efe503e5f /target/linux/realtek/files/drivers/char
parent62da0fe6152d0025e570ca41a6f9ae68df7da89b (diff)
Rebase files to rsdk 3.2 and refresh patches. Compilable (not by humans).
Signed-off-by: Roman Yeryomin <roman@advem.lv>
Diffstat (limited to 'target/linux/realtek/files/drivers/char')
-rw-r--r--target/linux/realtek/files/drivers/char/rtl_nfbi/Makefile2
-rw-r--r--target/linux/realtek/files/drivers/char/rtl_nfbi/rtl_nfbi.c2354
-rw-r--r--target/linux/realtek/files/drivers/char/rtl_nfbi/rtl_nfbi.h295
3 files changed, 2651 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/char/rtl_nfbi/Makefile b/target/linux/realtek/files/drivers/char/rtl_nfbi/Makefile
new file mode 100644
index 000000000..432fe4728
--- /dev/null
+++ b/target/linux/realtek/files/drivers/char/rtl_nfbi/Makefile
@@ -0,0 +1,2 @@
+
+obj-y += rtl_nfbi.o
diff --git a/target/linux/realtek/files/drivers/char/rtl_nfbi/rtl_nfbi.c b/target/linux/realtek/files/drivers/char/rtl_nfbi/rtl_nfbi.c
new file mode 100644
index 000000000..485edf58b
--- /dev/null
+++ b/target/linux/realtek/files/drivers/char/rtl_nfbi/rtl_nfbi.c
@@ -0,0 +1,2354 @@
+/*
+ * RTL8197B NFBI char driver
+ *
+ * Copyright (C)2008, Realtek Semiconductor Corp. All rights reserved.
+ *
+ */
+/*================================================================*/
+/* 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/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include "rtl_nfbi.h"
+
+#ifdef SIMULATION
+ #include <linux/proc_fs.h>
+#endif
+
+//#ifdef __LINUX_2_6__
+struct module *nfbi_owner;
+//#endif
+
+#ifndef HOST_IS_PANABOARD
+/*================================================================*/
+/* RTL8651C MDC/MDIO Control Register, @Pana_TBD */
+#define SWMACCR_BASE (0xBB804000)
+#define MDCIOCR (0x004+SWMACCR_BASE) /* MDC/MDIO Command Register */
+#define MDCIOSR (0x008+SWMACCR_BASE) /* MDC/MDIO Status Register */
+
+/* GPIO Register Set */
+#define GPIO_BASE (0xB8003500)
+#define PABCDCNR_REG (0x000 + GPIO_BASE) /* Port ABCD control */
+#define PABCDPTYPE_REG (0x004 + GPIO_BASE) /* Port ABCD type */
+#define PABCDDIR_REG (0x008 + GPIO_BASE) /* Port ABCD direction*/
+#define PABCDDAT_REG (0x00C + GPIO_BASE) /* Port ABCD data */
+#define PABCDISR_REG (0x010 + GPIO_BASE) /* Port ABCD interrupt status */
+#define PABIMR_REG (0x014 + GPIO_BASE) /* Port AB interrupt mask */
+#define PCDIMR_REG (0x018 + GPIO_BASE) /* Port CD interrupt mask */
+#define PEFGHCNR_REG (0x01C + GPIO_BASE) /* Port EFGH control */
+#define PEFGHPTYPE_REG (0x020 + GPIO_BASE) /* Port EFGH type */
+#define PEFGHDIR_REG (0x024 + GPIO_BASE) /* Port EFGH direction*/
+#define PEFGHDAT_REG (0x028 + GPIO_BASE) /* Port EFGH data */
+#define PEFGHISR_REG (0x02C + GPIO_BASE) /* Port EFGH interrupt status */
+#define PEFIMR_REG (0x030 + GPIO_BASE) /* Port EF interrupt mask */
+#define PGHIMR_REG (0x034 + GPIO_BASE) /* Port GH interrupt mask */
+
+#define MDIO_TIMEOUT 2000000
+#define DEFAULT_MDIO_PHYAD 16 /* selected by the hardware strapping pin of external Host CPU, @Pana_TBD */
+
+#define REG32(reg) (*((volatile unsigned int *)(reg)))
+
+#ifdef MDCIO_GPIO_SIMULATION
+//RTL8651C - F0: MDC, F1: MDIO
+//RTL8196 - E5: MDC, E6: MDIO
+//RTL8954C V200 EVB - G1: MDC, G0: MDIO, E2: RESET
+//RTL8954C V400 EVB - G1: MDC, F2: MDIO, E2: RESET
+//#define RTL8651C_FAMILY
+#define RTL89xxC_FAMILY
+#endif
+
+#ifdef RTL8651C_FAMILY
+// RTL8651C GPIO B6 is connected with RESETn pin.
+#define Set_NFBI_RESET_L() (REG32(PABCDDAT_REG) = REG32(PABCDDAT_REG) & (~0x4000) )
+#define Set_NFBI_RESET_H() (REG32(PABCDDAT_REG) = REG32(PABCDDAT_REG) | 0x4000)
+#elif defined (RTL89xxC_FAMILY)
+// RTL89xxC GPIO E2 is connected with RESETn pin.
+#define Set_NFBI_RESET_L() (REG32(PEFGHDAT_REG) = REG32(PEFGHDAT_REG) & (~0x4) )
+#define Set_NFBI_RESET_H() (REG32(PEFGHDAT_REG) = REG32(PEFGHDAT_REG) | 0x4)
+
+#endif
+/*================================================================*/
+#else
+/*================================================================*/
+#include "avev3.h"
+extern struct net_device *avev3_dev;
+
+void Set_NFBI_RESET_L(void) /*Reset Start(Assert)*/
+{
+ unsigned long reg;
+
+ AVEV3_REG_READ(reg, _AVEV3_GRR);
+ AVEV3_REG_WRITE( (reg | _AVEV3_GRR_PHYRST), _AVEV3_GRR);
+
+ return;
+}
+
+void Set_NFBI_RESET_H(void) /*Reset End(Negate)*/
+{
+ unsigned long reg;
+
+ AVEV3_REG_READ(reg, _AVEV3_GRR);
+ AVEV3_REG_WRITE( (reg & ~_AVEV3_GRR_PHYRST), _AVEV3_GRR);
+
+ return;
+}
+/*================================================================*/
+#endif /*HOST_IS_PANABOARD*/
+
+/*================================================================*/
+/* Local Variables */
+
+static int io=0xb8019000; //base address of 97B CPU internal register for NFBI
+static int irq = 18;
+static unsigned char mdio_phyaddr;
+static spinlock_t mdio_lock = SPIN_LOCK_UNLOCKED;
+
+#ifdef SIMULATION
+static unsigned char data_in[256];
+static int data_in_len = 0, data_in_read_idx = 0;
+static int msg_is_coming=0;
+
+static unsigned short data_out;
+static int data_out_len = 0, msg_is_fetched = 0;
+
+struct semaphore sim_sem;
+wait_queue_head_t sim_wq, sim_rq;
+#endif
+
+static struct nfbi_dev_priv *dev_priv=NULL;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)
+/* copied from linux kernel 2.6.20 /include/linux/time.h */
+/* Parameters used to convert the timespec values: */
+#define MSEC_PER_SEC 1000L
+
+/* copied from linux kernel 2.6.20 /include/linux/jiffies.h */
+/*
+ * Change timeval to jiffies, trying to avoid the
+ * most obvious overflows..
+ *
+ * And some not so obvious.
+ *
+ * Note that we don't want to return MAX_LONG, because
+ * for various timeout reasons we often end up having
+ * to wait "jiffies+1" in order to guarantee that we wait
+ * at _least_ "jiffies" - so "jiffies+1" had better still
+ * be positive.
+ */
+#define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
+
+/*
+ * Convert jiffies to milliseconds and back.
+ *
+ * Avoid unnecessary multiplications/divisions in the
+ * two most common HZ cases:
+ */
+static inline unsigned int _kc_jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
+ return (MSEC_PER_SEC / HZ) * j;
+#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
+ return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
+#else
+ return (j * MSEC_PER_SEC) / HZ;
+#endif
+}
+
+static inline unsigned long _kc_msecs_to_jiffies(const unsigned int m)
+{
+ if (m > _kc_jiffies_to_msecs(MAX_JIFFY_OFFSET))
+ return MAX_JIFFY_OFFSET;
+#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
+ return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ);
+#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
+ return m * (HZ / MSEC_PER_SEC);
+#else
+ return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC;
+#endif
+}
+#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+/**
+ * msleep_interruptible - sleep waiting for waitqueue interruptions
+ * @msecs: Time in milliseconds to sleep for
+ */
+#define msleep_interruptible _kc_msleep_interruptible
+unsigned long _kc_msleep_interruptible(unsigned int msecs)
+{
+ unsigned long timeout = _kc_msecs_to_jiffies(msecs);
+
+ while (timeout && !signal_pending(current)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ timeout = schedule_timeout(timeout);
+ }
+ return _kc_jiffies_to_msecs(timeout);
+}
+#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+
+
+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;
+}
+
+
+#ifdef SIMULATION
+static unsigned short register_read_dw(unsigned short offset)
+{
+ unsigned short status = 0;
+ unsigned short wdata = 0;
+
+ if (offset == NFBI_REG_ISR) {
+ //down_interruptible(&sim_sem);
+ //if (data_in_len > data_in_read_idx) {
+ if (msg_is_coming) {
+ status |= IP_NEWMSG_COMING;
+ msg_is_coming = 0;
+ }
+
+ if (msg_is_fetched) {
+ status |= IP_PREVMSG_FETCH;
+ msg_is_fetched = 0;
+ }
+ //up(&sim_sem);
+ return status;
+ }
+ else if (offset == NFBI_REG_RSR) {
+ down_interruptible(&sim_sem);
+ ASSERT(data_in_len > data_in_read_idx);
+ memcpy(&wdata, &data_in[data_in_read_idx], 2);
+ data_in_read_idx += 2;
+ up(&sim_sem);
+ wake_up_interruptible(&sim_wq);
+ status |= wdata;
+ return status;
+ }
+ else {
+ ASSERT(0);
+ return status;
+ }
+}
+
+static void register_write_dw(unsigned short offset, unsigned short data)
+{
+ if (offset == NFBI_REG_SCR) {
+ unsigned short wData = data;
+
+ down_interruptible(&sim_sem);
+
+ memcpy(&data_out, &wData, 2);
+ data_out_len = 2;
+
+ up(&sim_sem);
+ }
+
+}
+#endif // SIMULATION
+
+/*----------------------------------------------------------------------------*/
+#ifdef MDCIO_GPIO_SIMULATION
+
+#define DELAY 50
+
+/*
+ * MDC/MDIO API: use two GPIO pin to simulate MDC/MDIO signal
+ *
+ */
+void _smiGpioInit(void)
+{
+ printk("Init GPIO for MDC/MDIO.\n");
+#ifdef RTL8651C_FAMILY //F0: MDC, F1: MDIO
+ //config as GPIO pin
+ REG32(PEFGHCNR_REG) = REG32(PEFGHCNR_REG) & (~0x00000300);
+ printk("0xB800351C=%X\n", REG32(PEFGHCNR_REG));
+ //Disable F0, F0 interrupt
+ REG32(PEFIMR_REG) = REG32(PEFIMR_REG) & (~0x000F0000);
+ printk("0xB8003530=%X\n", REG32(PEFIMR_REG));
+ //set F0, F1 output pin
+ REG32(PEFGHDIR_REG) = REG32(PEFGHDIR_REG) | 0x00000300;
+ printk("0xB8003524=%X\n", REG32(PEFGHDIR_REG));
+#elif defined (RTL89xxC_FAMILY)
+ #ifdef CONFIG_RTK_VOIP_GPIO_8954C_V400 //G1: MDC, F2: MDIO, E2: RESET
+ // PIN Mux select (register PIN_MUX_SEL bit 14, 8, 9)
+ *((volatile unsigned int *)0xB8000040) =
+ *((volatile unsigned int *)0xB8000040) | 0x4300;
+ //config as GPIO pin
+ REG32(PEFGHCNR_REG) = REG32(PEFGHCNR_REG) & (~0x00020400);
+ printk("PEFGHCNR_REG=%X\n", REG32(PEFGHCNR_REG));
+ //Disable G1 interrupt
+ REG32(PGHIMR_REG) = REG32(PGHIMR_REG) & (~0x0000000C);
+ printk("PGHIMR_REG=%X\n", REG32(PGHIMR_REG));
+ //Disable F2 interrupt
+ REG32(PEFIMR_REG) = REG32(PEFIMR_REG) & (~0x00300000);
+ printk("PEFIMR_REG=%X\n", REG32(PEFIMR_REG));
+ //set G0, F2 output pin
+ REG32(PEFGHDIR_REG) = REG32(PEFGHDIR_REG) | 0x00020400;
+ printk("PEFGHDIR_REG=%X\n", REG32(PEFGHDIR_REG));
+ #else //G1: MDC, G0: MDIO, E2: RESET
+ // PIN Mux select (register PIN_MUX_SEL bit 14, 8, 9)
+ *((volatile unsigned int *)0xB8000040) =
+ *((volatile unsigned int *)0xB8000040) | 0x4000 | 0x0300;
+ //config as GPIO pin
+ REG32(PEFGHCNR_REG) = REG32(PEFGHCNR_REG) & (~0x00030000);
+ printk("PEFGHCNR_REG=%X\n", REG32(PEFGHCNR_REG));
+ //Disable G0, G1 interrupt
+ REG32(PGHIMR_REG) = REG32(PGHIMR_REG) & (~0x0000000F);
+ printk("PGHIMR_REG=%X\n", REG32(PGHIMR_REG));
+ //set G0, G1 output pin
+ REG32(PEFGHDIR_REG) = REG32(PEFGHDIR_REG) | 0x00030000;
+ printk("PEFGHDIR_REG=%X\n", REG32(PEFGHDIR_REG));
+ #endif
+#else
+#error "Need implement for _smiGpioInit"
+#endif
+}
+/*
+static void _smiGenReadClk(void)
+{
+ unsigned short i;
+#ifdef RTL8651C_FAMILY
+ REG32(PEFGHDIR_REG) = (REG32(PEFGHDIR_REG)& 0xFFFFFCFF) | 0x00000100; // MDC=OUT, MDIO=IN
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF) | 0x00000100; // MDC=1, MDIO=0
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF); // MDC=0
+#else
+#error "Need implement for _smiGenReadClk"
+#endif
+}
+*/
+static void _smiGenWriteClk(void)
+{
+ unsigned short i;
+#ifdef RTL8651C_FAMILY //F0: MDC, F1: MDIO
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = REG32(PEFGHDAT_REG) & 0xFFFFFCFF;// MDC=0, MDIO=0
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = REG32(PEFGHDAT_REG) | 0x00000100; // MDC=1
+#elif defined (RTL89xxC_FAMILY)
+ #ifdef CONFIG_RTK_VOIP_GPIO_8954C_V400 //G1: MDC, F2: MDIO
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = REG32(PEFGHDAT_REG) & 0xFFFDFBFF;// MDC=0, MDIO=0
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = REG32(PEFGHDAT_REG) | 0x00020000; // MDC=1
+ #else //G1: MDC, G0: MDIO
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = REG32(PEFGHDAT_REG) & 0xFFFCFFFF;// MDC=0, MDIO=0
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = REG32(PEFGHDAT_REG) | 0x00020000; // MDC=1
+ #endif
+#else
+#error "Need implement for _smiGenWriteClk"
+#endif
+}
+
+/* Change clock to 1 */
+static void _smiZBit(void) {
+ unsigned short i;
+#ifdef RTL8651C_FAMILY //F0: MDC, F1: MDIO
+ REG32(PEFGHDIR_REG) = (REG32(PEFGHDIR_REG) & 0xFFFFFCFF) | 0x100;
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF);
+#elif defined (RTL89xxC_FAMILY)
+ #ifdef CONFIG_RTK_VOIP_GPIO_8954C_V400 //G1: MDC, F2: MDIO
+ REG32(PEFGHDIR_REG) = (REG32(PEFGHDIR_REG) & 0xFFFDFBFF) | 0x20000;
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFDFBFF);
+ #else //G1: MDC, G0: MDIO
+ REG32(PEFGHDIR_REG) = (REG32(PEFGHDIR_REG) & 0xFFFCFFFF) | 0x20000;
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFCFFFF);
+ #endif
+#else
+ #ifdef GPIO_E56
+ REG32(PEFGHDIR_REG) = (REG32(PEFGHDIR_REG) & 0xFFFFFF9F) | 0x20;
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFF9F);
+ #elif defined GPIO_D67
+ REG32(GPABCDDIR) = (REG32(GPABCDDIR) & 0x3FFFFFFF) | 0x40000000;// MDIO=IN, MDC=OUT
+ REG32(GPABCDDATA) = (REG32(GPABCDDATA) & 0x3FFFFFFF); // MDIO=0, MDC=0
+ #endif
+#endif
+ for(i=0; i< DELAY; i++);
+}
+
+/* Generate 1 -> 0 transition and sampled at 1 to 0 transition time,
+should not sample at 0->1 transition because some chips stop outputing
+at the last bit at rising edge*/
+
+static void _smiReadBit(unsigned short * pdata) {
+ unsigned short i;
+#ifdef RTL8651C_FAMILY //F0: MDC, F1: MDIO
+ REG32(PEFGHDIR_REG) = (REG32(PEFGHDIR_REG)& 0xFFFFFCFF) | 0x100;
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF) | 0x100;
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF);
+ *pdata = (REG32(PEFGHDAT_REG) & 0x200)?1:0;
+#elif defined (RTL89xxC_FAMILY)
+ #ifdef CONFIG_RTK_VOIP_GPIO_8954C_V400 //G1: MDC, F2: MDIO
+ REG32(PEFGHDIR_REG) = (REG32(PEFGHDIR_REG)& 0xFFFDFBFF) | 0x20000;
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFDFBFF) | 0x20000;
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFDFBFF);
+ *pdata = (REG32(PEFGHDAT_REG) & 0x0400)?1:0; // read F2
+ #else //G1: MDC, G0: MDIO
+ REG32(PEFGHDIR_REG) = (REG32(PEFGHDIR_REG)& 0xFFFCFFFF) | 0x20000;
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFCFFFF) | 0x20000;
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFCFFFF);
+ *pdata = (REG32(PEFGHDAT_REG) & 0x10000)?1:0;
+ #endif
+#else
+ #ifdef GPIO_E56
+ REG32(PEFGHDIR_REG) = (REG32(PEFGHDIR_REG)& 0xFFFFFF9F) | 0x20;
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFF9F) | 0x20;
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFF9F);
+ *pdata = (REG32(PEFGHDAT_REG) & 0x40)?1:0;
+ #elif defined GPIO_D67
+ REG32(GPABCDDIR) = (REG32(GPABCDDIR)& 0x3FFFFFFF) | 0x40000000; // MDIO=IN, MDC=OUT
+ REG32(GPABCDDATA) = (REG32(GPABCDDATA) & 0x3FFFFFFF) | 0x40000000; // MDC=1, MDIO=0
+ for(i=0; i< DELAY; i++);
+ REG32(GPABCDDATA) = (REG32(GPABCDDATA) & 0x3FFFFFFF); // MDC=0
+ *pdata = (REG32(GPABCDDATA) & 0x80000000)?1:0; // Get MDIO value
+ #endif
+#endif
+}
+
+/* Generate 0 -> 1 transition and put data ready during 0 to 1 whole period */
+static void _smiWriteBit(unsigned short data) {
+ unsigned short i;
+#ifdef RTL8651C_FAMILY //F0: MDC, F1: MDIO
+ REG32(PEFGHDIR_REG) = REG32(PEFGHDIR_REG) | 0x300;
+ if(data) {/* Write 1 */
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF) | 0x200;
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF) | 0x300;
+ } else {
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF);
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF) | 0x100;
+ }
+#elif defined (RTL89xxC_FAMILY)
+ #ifdef CONFIG_RTK_VOIP_GPIO_8954C_V400 //G1: MDC, F2: MDIO
+ REG32(PEFGHDIR_REG) = REG32(PEFGHDIR_REG) | 0x00020400;
+ if(data) {/* Write 1 */
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFDFBFF) | 0x00000400;
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFDFBFF) | 0x00020400;
+ } else {
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFDFBFF);
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFDFBFF) | 0x00020000;
+ }
+ #else //G1: MDC, G0: MDIO
+ REG32(PEFGHDIR_REG) = REG32(PEFGHDIR_REG) | 0x30000;
+ if(data) {/* Write 1 */
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFCFFFF) | 0x10000;
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFCFFFF) | 0x30000;
+ } else {
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFCFFFF);
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFCFFFF) | 0x20000;
+ }
+ #endif
+#else
+ #ifdef GPIO_E56
+ REG32(PEFGHDIR_REG) = REG32(PEFGHDIR_REG) | 0x60;
+ if(data) {/* Write 1 */
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF) | 0x40;
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF) | 0x60;
+ } else {
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF);
+ for(i=0; i< DELAY; i++);
+ REG32(PEFGHDAT_REG) = (REG32(PEFGHDAT_REG) & 0xFFFFFCFF) | 0x20;
+ }
+ #elif defined GPIO_D67
+ REG32(GPABCDDIR) = REG32(GPABCDDIR) | 0xC0000000; // set MDIO, MDC to output
+ if(data) {/* Write 1 */
+ REG32(GPABCDDATA) = (REG32(GPABCDDATA) & 0x3FFFFFFF) | 0x80000000; // MDC=0, MDIO=1
+ for(i=0; i< DELAY; i++);
+ REG32(GPABCDDATA) = (REG32(GPABCDDATA) & 0xBFFFFFFF) | 0x40000000; // MDC=1
+ } else {
+ REG32(GPABCDDATA) = (REG32(GPABCDDATA) & 0x3FFFFFFF); // MDC=0, MDIO=0
+ for(i=0; i< DELAY; i++);
+ REG32(GPABCDDATA) = (REG32(GPABCDDATA) & 0xBFFFFFFF) | 0x40000000;// MDC=1
+ }
+ #endif
+#endif
+}
+
+int smiRead(unsigned char phyad, unsigned short regad, unsigned short * data) {
+ int i;
+ unsigned short readBit;
+
+ /* Configure port C pin 1, 0 to be GPIO and disable interrupts of these two pins */
+#ifdef RTL8651C_FAMILY //F0: MDC, F1: MDIO
+// REG32(GPEFGHCNR) = REG32(GPEFGHCNR) & 0xFFFFFCFF;
+// REG32(GPEFIMR) = REG32(GPEFIMR) & 0xFFFFFFF;
+#elif defined (RTL89xxC_FAMILY)
+ #ifdef CONFIG_RTK_VOIP_GPIO_8954C_V400 //G1: MDC, F2: MDIO
+ #else //G1: MDC, G0: MDIO
+ #endif
+#else
+ #ifdef GPIO_E56
+ REG32(GPEFGHCNR) = REG32(GPEFGHCNR) & 0xFFFFFF9F;
+ REG32(GPEFIMR) = REG32(GPEFIMR) & 0xFFFFFFF;
+ #elif defined GPIO_D67
+ //REG32(GPABCDCNR) = REG32(GPABCDCNR) & 0xFFFFFF9F;
+ //REG32(GPCDIMR) = REG32(GPCDIMR) & 0xFFFFFFF;
+ #endif
+#endif
+ /* 32 continuous 1 as preamble*/
+ for(i=0; i<32; i++)
+ _smiWriteBit(1);
+ /* ST: Start of Frame, <01>*/
+ _smiWriteBit(0);
+ _smiWriteBit(1);
+ /* OP: Operation code, read is <10> */
+ _smiWriteBit(1);
+ _smiWriteBit(0);
+ /* PHY Address */
+ for(i=4; i>=0; i--)
+ _smiWriteBit((phyad>>i)&0x1);
+ /* Register Address */
+ for(i=4; i>=0; i--)
+ _smiWriteBit((regad>>i)&0x1);
+ /* TA: Turnaround <z0> */
+ _smiZBit();
+ _smiReadBit(&readBit);
+ /* Data */
+ *data = 0;
+ for(i=15; i>=0; i--) {
+ _smiReadBit(&readBit);
+ *data = (*data<<1) | readBit;
+ }
+ /*add an extra clock cycles for robust reading , ensure partner stop output signal
+ and not affect the next read operation, because TA steal a clock*/
+ _smiWriteBit(1);
+ _smiZBit();
+
+ return 0;
+}
+
+int smiWrite(unsigned char phyad, unsigned short regad, unsigned short data) {
+ int i;
+
+ /* Configure port C pin 1, 0 to be GPIO and disable interrupts of these two pins */
+#ifdef RTL8651C_FAMILY
+// REG32(GPEFGHCNR) = REG32(GPEFGHCNR) & 0xFFFFFCFF;
+// REG32(GPEFIMR) = REG32(GPEFIMR) & 0xFFFFFFF;
+#elif defined (RTL89xxC_FAMILY)
+ #ifdef CONFIG_RTK_VOIP_GPIO_8954C_V400 //G1: MDC, F2: MDIO
+ #else //G1: MDC, G0: MDIO
+ #endif
+#else
+ #ifdef GPIO_E56
+ REG32(GPEFGHCNR) = REG32(GPEFGHCNR) & 0xFFFFFF9F;
+ REG32(GPEFIMR) = REG32(GPEFIMR) & 0xFFFFFFF;
+ #elif defined GPIO_D67
+ //REG32(GPABCDCNR) = REG32(GPABCDCNR) & 0xFFFFFF9F;
+ //REG32(GPCDIMR) = REG32(GPCDIMR) & 0xFFFFFFF;
+ #endif
+#endif
+ /* 32 continuous 1 as preamble*/
+ for(i=0; i<32; i++)
+ _smiWriteBit(1);
+ /* ST: Start of Frame, <01>*/
+ _smiWriteBit(0);
+ _smiWriteBit(1);
+ /* OP: Operation code, write is <01> */
+ _smiWriteBit(0);
+ _smiWriteBit(1);
+ /* PHY Address */
+ for(i=4; i>=0; i--)
+ _smiWriteBit((phyad>>i)&0x1);
+ /* Register Address */
+ for(i=4; i>=0; i--)
+ _smiWriteBit((regad>>i)&0x1);
+ /* TA: Turnaround <10> */
+ _smiWriteBit(1);
+ _smiWriteBit(0);
+ /* Data */
+ for(i=15; i>=0; i--)
+ _smiWriteBit((data>>i)&0x1);
+ _smiGenWriteClk();
+ _smiZBit();
+
+ return 0;
+}
+#endif //MDCIO_GPIO_SIMULATION
+/*----------------------------------------------------------------------------*/
+
+
+//@Pana_TBD
+#ifndef HOST_IS_PANABOARD
+int rtl_mdio_write(unsigned short reg, unsigned short data)
+{
+ unsigned long flags;
+#ifdef MDCIO_GPIO_SIMULATION
+ int ret;
+
+ del_timer(&dev_priv->mdc_timer);
+ spin_lock_irqsave(&mdio_lock, flags);
+ ret = smiWrite(mdio_phyaddr, reg, data);
+ spin_unlock_irqrestore(&mdio_lock, flags);
+ mod_timer(&dev_priv->mdc_timer, jiffies + 1);
+ return ret;
+#else
+ volatile unsigned int val;
+ int timeout = MDIO_TIMEOUT;
+
+ spin_lock_irqsave(&mdio_lock, flags);
+ REG32(MDCIOCR) = 0x80000000 | (mdio_phyaddr<<24) | ((reg&0x1f)<<16) | (data&0xffff);
+ while (--timeout) {
+ val = REG32(MDCIOSR);
+ if ((val&0x80000000) == 0)
+ break;
+ }
+ spin_unlock_irqrestore(&mdio_lock, flags);
+
+ if (timeout==0) {
+ PDEBUG("MDIO Timeout! write data:%x to reg: %x Error!\n",data,reg);
+ return -1;
+ }
+ else
+ return 0;
+#endif
+}
+
+int rtl_mdio_mask_write(unsigned short reg, unsigned short mask, unsigned short data)
+{
+ unsigned long flags;
+#ifdef MDCIO_GPIO_SIMULATION
+ unsigned short regval;
+ int ret;
+
+ del_timer(&dev_priv->mdc_timer);
+ spin_lock_irqsave(&mdio_lock, flags);
+ ret = smiRead(mdio_phyaddr, reg, &regval);
+ if (ret == 0) {
+ data = (regval&(~mask)) | (data&mask);
+ ret = smiWrite(mdio_phyaddr, reg, data);
+ }
+ spin_unlock_irqrestore(&mdio_lock, flags);
+ mod_timer(&dev_priv->mdc_timer, jiffies + 1);
+ return ret;
+#else
+ volatile unsigned int val;
+ unsigned short regval;
+ int timeout = MDIO_TIMEOUT;
+
+ spin_lock_irqsave(&mdio_lock, flags);
+ REG32(MDCIOCR) = 0x7fffffff & ((mdio_phyaddr<<24) | ((reg&0x1f)<<16));
+ while (--timeout) {
+ val = REG32(MDCIOSR);
+ if ((val&0x80000000) == 0)
+ break;
+ }
+
+ if (timeout==0) {
+ PDEBUG("MDIO Timeout! read2 reg: %x Error!\r\n",reg);
+ spin_unlock_irqrestore(&mdio_lock, flags);
+ return -1;
+ }
+ regval = (unsigned short)(val & 0xffff);
+ data = (regval&(~mask)) | (data&mask);
+ REG32(MDCIOCR) = 0x80000000 | (mdio_phyaddr<<24) | ((reg&0x1f)<<16) | (data&0xffff);
+ while (--timeout) {
+ val = REG32(MDCIOSR);
+ if ((val&0x80000000) == 0)
+ break;
+ }
+ spin_unlock_irqrestore(&mdio_lock, flags);
+
+ if (timeout==0) {
+ PDEBUG("MDIO Timeout! write2 data:%x to reg: %x Error!\n",data,reg);
+ return -1;
+ }
+ else
+ return 0;
+#endif
+}
+
+int rtl_mdio_read(unsigned short reg, unsigned short *pdata)
+{
+ unsigned long flags;
+#ifdef MDCIO_GPIO_SIMULATION
+ int ret;
+
+ del_timer(&dev_priv->mdc_timer);
+ spin_lock_irqsave(&mdio_lock, flags);
+ ret = smiRead(mdio_phyaddr, reg, pdata);
+ spin_unlock_irqrestore(&mdio_lock, flags);
+ mod_timer(&dev_priv->mdc_timer, jiffies + 1);
+ return ret;
+#else
+ volatile unsigned int val;
+ int timeout = MDIO_TIMEOUT;
+
+ spin_lock_irqsave(&mdio_lock, flags);
+ REG32(MDCIOCR) = 0x7fffffff & ((mdio_phyaddr<<24) | ((reg&0x1f)<<16));
+ while (--timeout) {
+ val = REG32(MDCIOSR);
+ if ((val&0x80000000) == 0)
+ break;
+ }
+ spin_unlock_irqrestore(&mdio_lock, flags);
+
+ if (timeout==0) {
+ PDEBUG("MDIO Timeout! read reg: %x Error!\r\n",reg);
+ *pdata = 0;
+ return -1;
+ }
+ else {
+ *pdata = val & 0xffff;
+ return 0;
+ }
+#endif
+}
+#else
+int rtl_mdio_write(unsigned short reg, unsigned short data)
+{
+ avev3_mdio_write(avev3_dev, mdio_phyaddr, reg, data);
+ return 0;
+}
+
+int rtl_mdio_mask_write(unsigned short reg, unsigned short mask, unsigned short data)
+{
+ unsigned short regval;
+
+ regval = avev3_mdio_read(avev3_dev, mdio_phyaddr, reg);
+ data = (regval&(~mask)) | (data&mask);
+ avev3_mdio_write(avev3_dev, mdio_phyaddr, reg, data);
+ return 0;
+}
+
+int rtl_mdio_read(unsigned short reg, unsigned short *pdata)
+{
+ *pdata = avev3_mdio_read(avev3_dev, mdio_phyaddr, reg);
+ return 0;
+}
+#endif /*HOST_IS_PANABOARD*/
+
+static void process_rx_msg(struct nfbi_priv *priv, unsigned short data)
+{
+ /*
+ if (priv->rx_status_time &&
+ (priv->state == STATE_RX_WAIT_LEN ||
+ priv->state == STATE_RX_WAIT_DATA) &&
+ TIME_DIFF(jiffies, priv->rx_status_time) > CMD_TIME_OUT) {
+ PDEBUG("Rx status timeout [%ld], discard pending status!\n", TIME_DIFF(jiffies, priv->rx_status_time));
+ RESET_RX_STATE;
+ }
+ */
+ if ((data & FIRST_CMD_MASK) && (priv->state != STATE_RX_INIT)) {
+ PDEBUG("Rx Sync bit but not in INIT_STATE, discard pending status!\n");
+ dev_priv->rx_reset_by_sync_bit_errors++;
+ RESET_RX_STATE;
+ }
+
+ if (priv->state == STATE_RX_INIT) {
+ ASSERT(priv->data_in.len == 0);
+
+ if (!(data & FIRST_CMD_MASK)) {
+ PDEBUG("Not first word [0x%x], discard it!\n", data);
+ dev_priv->rx_not_1st_word_errors++;
+ goto invalid_cmd;
+ }
+ PUT_IN_DATA(data); // cmd id
+ priv->state = STATE_RX_WAIT_LEN;
+ priv->rx_status_time = jiffies;
+ }
+ else { // STATE_RX_WAIT_LEN or STATE_RX_WAIT_DATA
+ // check if first cmd byte is '0'
+ if (data & 0xff00) {
+ PDEBUG("1st byte of rx word not zero [%x]!\n", data >> 8);
+ dev_priv->rx_1st_byte_errors++;
+ goto invalid_cmd;
+ }
+
+ if (priv->state == STATE_RX_WAIT_LEN) {
+ PUT_IN_DATA(data);
+ priv->state = STATE_RX_WAIT_DATA;
+ priv->rx_status_remain_len = (data + 1)*2; // including checksum
+ priv->rx_status_time = jiffies;
+ }
+ else { // in STATE_RX_WAIT_DATA
+ ASSERT (priv->rx_status_remain_len > 0);
+
+ PUT_IN_DATA(data);
+ priv->rx_status_remain_len -= 2;
+ if (priv->rx_status_remain_len <= 0) { // rx last byte, calcuate checksum
+ if (!is_checksum_ok(priv->data_in.buf, priv->data_in.len)) {
+ PDEBUG("Rx frame cheksum error!\n");
+ dev_priv->rx_checksum_errors++;
+ goto invalid_cmd;
+ }
+ //chech if the command field of rx status frame is the same as tx command frame
+ if (priv->data_in.buf[1] != priv->data_out.buf[1]) {
+ PDEBUG("Rx cmd field not match!\n");
+ dev_priv->rx_cmdid_not_match_errors++;
+ goto invalid_cmd;
+ }
+ priv->data_in.len -= 2; // substract checksum length
+ priv->state = STATE_RX_FINISHED;
+ }
+ else
+ priv->rx_status_time = jiffies;
+ }
+ }
+
+ return;
+
+invalid_cmd:
+ RESET_RX_STATE;
+}
+
+static void transmit_msg(struct nfbi_priv *priv)
+{
+ unsigned short data;
+
+ if (priv->data_out.len <= 0 || priv->tx_cmd_transmitting_len >= priv->data_out.len)
+ return;
+#ifndef HOST_IS_PANABOARD
+ memcpy(&data, priv->data_out.buf+priv->tx_cmd_transmitting_len, 2);
+#else
+ data = ( *(priv->data_out.buf+priv->tx_cmd_transmitting_len) << 8 ) |
+ *(priv->data_out.buf+priv->tx_cmd_transmitting_len + 1);
+#endif
+ dev_priv->tx_msg_is_fetched = 0;
+#ifdef SIMULATION
+ register_write_dw(NFBI_REG_SCR, data);
+#else
+ rtl_mdio_write(NFBI_REG_SCR, data);
+#endif
+ dev_priv->tx_words++;
+ priv->tx_cmd_transmitting_len += 2;
+}
+
+static int indicate_evt(struct evt_msg *evt)
+{
+ int size;
+
+ if (dev_priv->hcd_pid == -1)
+ return 0;
+
+ size = CIRC_SPACE(dev_priv->evt_que_head, dev_priv->evt_que_tail, EV_QUE_MAX);
+ if (size == 0) {
+ PDEBUG("Indication queue full, drop event!\n");
+ //send SIGUSR1 signal to notify the host control deamon process
+ //if (dev_priv->hcd_pid != -1)
+ //kill_proc(dev_priv->hcd_pid, SIGUSR1, 1);
+
+ return 0;
+ }
+
+ dev_priv->ind_evt_que[dev_priv->evt_que_head].id = evt->id;
+ dev_priv->ind_evt_que[dev_priv->evt_que_head].status = evt->status;
+ dev_priv->ind_evt_que[dev_priv->evt_que_head].value = evt->value;
+ dev_priv->evt_que_head = (dev_priv->evt_que_head + 1) & (EV_QUE_MAX - 1);
+
+ //send SIGUSR1 signal to notify the host control deamon process
+ //if (dev_priv->hcd_pid != -1)
+ //kill_proc(dev_priv->hcd_pid, SIGUSR1, 1);
+
+ return 1;
+}
+
+//static int retrieve_evt(struct nfbi_priv *priv, struct evt_msg *evt)
+static int retrieve_evt(struct evt_msg *evt)
+{
+ if (CIRC_CNT(dev_priv->evt_que_head, dev_priv->evt_que_tail, EV_QUE_MAX) > 0) { // more than one evt pending
+ evt->id = dev_priv->ind_evt_que[dev_priv->evt_que_tail].id;
+ evt->status = dev_priv->ind_evt_que[dev_priv->evt_que_tail].status;
+ evt->value = dev_priv->ind_evt_que[dev_priv->evt_que_tail].value;
+ dev_priv->evt_que_tail = (dev_priv->evt_que_tail + 1) & (EV_QUE_MAX - 1);
+ }
+ else {
+ evt->id = 0;
+ evt->status = 0;
+ evt->value = 0;
+ }
+ return 0;
+}
+
+static void nfbi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned short status, data, mask;
+ struct evt_msg evt;
+ //struct nfbi_dev_priv *priv = (struct nfbi_dev_priv *)dev_id;
+
+#ifdef HOST_IS_PANABOARD
+ if( mdio_phyaddr == 0xff ){
+ /* Can't found 8197B */
+ return;/* Do noting */
+ }
+#endif /*HOST_IS_PANABOARD*/
+
+ if (!dev_priv->ready) {
+ //==========================================================================
+ // @Pana_TBD
+#ifndef HOST_IS_PANABOARD
+ REG32(PABCDISR_REG) = REG32(PABCDISR_REG) | 0x8000; //write 1 to clear the interrupt at B7 (bit 15)
+#endif
+ //==========================================================================
+ return;
+ }
+
+ //printk("nfbi_interrupt: irq=%d\n", irq);
+#ifdef SIMULATION
+ status = register_read_dw(NFBI_REG_ISR);
+#else
+ rtl_mdio_read(NFBI_REG_ISR, &status);
+ rtl_mdio_read(NFBI_REG_IMR, &mask);
+#endif
+
+ if (!(status&mask)) {
+ //pana suggest us to print this message for debugging
+ printk("Unknown interrupt: status=0x%04x mask=0x%04x\n", status, mask);
+ }
+ status &= mask;
+
+ while (status) {
+ //printk("status=%x mask=%x\n", status, mask);
+ // clear interrupt
+#ifdef SIMULATION
+ register_write_dw(NFBI_REG_ISR, status);
+#else
+ rtl_mdio_write(NFBI_REG_ISR, status);
+#endif
+
+ if (dev_priv->cmd_handshake_polling) {
+ if (status & (IP_PREVMSG_FETCH|IP_NEWMSG_COMING|
+ IP_CHECKSUM_DONE|IP_CHECKSUM_OK|IP_WLANLINK|IP_ETHLINK|
+ IP_ETHPHY_STATUS_CHANGE|IP_ALLSOFTWARE_READY|
+ IP_USBInsertStatus|IP_USBRemoveStatus|
+ IP_BOOTCODE_READY|IP_NEED_BOOTCODE)) {
+ evt.id = 1;
+ evt.status = status & (IP_PREVMSG_FETCH|IP_NEWMSG_COMING|
+ IP_CHECKSUM_DONE|IP_CHECKSUM_OK|IP_WLANLINK|IP_ETHLINK|
+ IP_ETHPHY_STATUS_CHANGE|IP_ALLSOFTWARE_READY|
+ IP_USBInsertStatus|IP_USBRemoveStatus|
+ IP_BOOTCODE_READY|IP_NEED_BOOTCODE);
+ //if (status & IP_NEED_BOOTCODE)
+ // printk("IP_NEED_BOOTCODE\n");
+ rtl_mdio_read(NFBI_REG_SYSSR, &data);
+ evt.value = data;
+ indicate_evt(&evt);
+ }
+ }
+ else {
+ if (status & IP_PREVMSG_FETCH) {
+ dev_priv->tx_msg_is_fetched = 1;
+ wake_up_interruptible(&dev_priv->wq);
+ }
+ if (status & IP_NEWMSG_COMING) {
+ dev_priv->rx_msg_is_coming = 1;
+ wake_up_interruptible(&dev_priv->wq);
+ }
+
+ if (status & (IP_CHECKSUM_DONE|IP_CHECKSUM_OK|IP_WLANLINK|IP_ETHLINK|
+ IP_ETHPHY_STATUS_CHANGE|IP_ALLSOFTWARE_READY|
+ IP_USBInsertStatus|IP_USBRemoveStatus|
+ IP_BOOTCODE_READY|IP_NEED_BOOTCODE)) {
+ evt.id = 1;
+ evt.status = status & (IP_CHECKSUM_DONE|IP_CHECKSUM_OK|IP_WLANLINK|IP_ETHLINK|
+ IP_ETHPHY_STATUS_CHANGE|IP_ALLSOFTWARE_READY|
+ IP_USBInsertStatus|IP_USBRemoveStatus|
+ IP_BOOTCODE_READY|IP_NEED_BOOTCODE);
+ //if (status & IP_NEED_BOOTCODE)
+ // printk("IP_NEED_BOOTCODE\n");
+ rtl_mdio_read(NFBI_REG_SYSSR, &data);
+ evt.value = data;
+ indicate_evt(&evt);
+ }
+ }
+
+ if (status & ~(IP_PREVMSG_FETCH|IP_NEWMSG_COMING|
+ IP_CHECKSUM_DONE|IP_CHECKSUM_OK|IP_WLANLINK|IP_ETHLINK|
+ IP_ETHPHY_STATUS_CHANGE|IP_ALLSOFTWARE_READY|
+ IP_USBInsertStatus|IP_USBRemoveStatus|
+ IP_BOOTCODE_READY|IP_NEED_BOOTCODE)) {
+ PDEBUG("Got satus=0x%x, not supported yet!\n", (unsigned int)status);
+ }
+
+#ifdef SIMULATION
+ status = register_read_dw(NFBI_REG_ISR);
+#else
+ rtl_mdio_read(NFBI_REG_ISR, &status);
+ status &= mask;
+#endif
+ }
+ //==========================================================================
+ // @Pana_TBD
+#ifndef HOST_IS_PANABOARD
+ REG32(PABCDISR_REG) = REG32(PABCDISR_REG) | 0x8000; //write 1 to clear the interrupt at B7 (bit 15)
+#endif
+ //==========================================================================
+}
+
+#ifdef HOST_IS_PANABOARD
+/* Call from AVE network driver interrupt handler */
+//==========================================================================
+void nfbi_interrupt_dummy_avev3(void){
+ nfbi_interrupt(0, (void *)dev_priv, (struct pt_regs *)NULL);
+}
+//==========================================================================
+#endif
+
+static int nfbi_open(struct inode *inode, struct file *filp)
+{
+ struct nfbi_priv *priv;
+
+ //printk("%s: major=%d, minor=%d\n", __FUNCTION__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
+ //printk("filp=%p\n", filp);
+ priv = (struct nfbi_priv *)kmalloc(sizeof(struct nfbi_priv), GFP_KERNEL);
+ if(!priv) {
+ printk(KERN_ERR DRIVER_NAME": unable to kmalloc for nfbi_priv\n");
+ return -ENOMEM;
+ }
+ memset((void *)priv, 0, sizeof (struct nfbi_priv));
+ priv->state = STATE_TX_INIT;
+ priv->retransmit_count = NFBI_RETRANSMIT_COUNT_DEFAULT;
+ priv->response_timeout = NFBI_RESPONSE_TIMEOUT_DEFAULT;
+
+ filp->private_data = priv;
+
+//#ifdef __LINUX_2_6__
+#if 1
+ if(!try_module_get(nfbi_owner)) {
+ printk(KERN_ALERT "Module increasing error!!\n");
+ return -ENODEV;
+ }
+#else
+ MOD_INC_USE_COUNT;
+#endif
+
+ return 0;;
+}
+
+
+static int nfbi_release(struct inode *inode, struct file *filp)
+{
+ //printk("%s: major=%d, minor=%d\n", __FUNCTION__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
+
+ kfree((struct nfbi_priv *)filp->private_data);
+
+//#ifdef __LINUX_2_6__
+#if 1
+ module_put(nfbi_owner);
+#else
+ MOD_DEC_USE_COUNT;
+#endif
+
+ return 0;
+}
+
+static void nfbi_timer_fn(unsigned long arg)
+{
+ wake_up_interruptible(&dev_priv->wq);
+ dev_priv->timer_expired = 1;
+}
+
+#ifdef MDCIO_GPIO_SIMULATION
+static void mdc_timer_fn(unsigned long arg)
+{
+ _smiWriteBit(1); // generate MDC clock
+ mod_timer(&dev_priv->mdc_timer, jiffies + 1);
+}
+#endif
+
+static ssize_t nfbi_read (struct file *filp, char *buf, size_t count, loff_t *offset)
+{
+ struct nfbi_priv *priv = (struct nfbi_priv *)filp->private_data;
+
+ if (!buf)
+ return 0;
+
+ if (priv->state != STATE_RX_FINISHED) {
+ PDEBUG("To read status frame, but not in a valid state!\n");
+ return 0;
+ }
+
+ if (copy_to_user((void *)buf, (void *)priv->data_in.buf, priv->data_in.len)) {
+ PDEBUG("copy_to_user() error!\n");
+ count = -EFAULT;
+ }
+ else
+ count = priv->data_in.len;
+
+ return count;
+}
+
+static ssize_t nfbi_write (struct file *filp, const char *buf, size_t count, loff_t *offset)
+{
+ struct nfbi_priv *priv = (struct nfbi_priv *)filp->private_data;
+ unsigned short last_word = 0;
+ unsigned short data;
+ //unsigned short imr;
+ int retransmit_count;
+ unsigned long curr_time;
+ unsigned short status;
+
+ if (!buf)
+ return 0;
+
+ if (priv->state != STATE_TX_INIT) {
+ //PDEBUG("Transmit status, but not in valid state. Reset state!\n");
+ priv->state = STATE_TX_INIT;
+ }
+
+ if (count > NFBI_BUFSIZE) {
+ PDEBUG("Tx size too big [%d]!\n", count);
+ return 0;
+ }
+ if (count %2) {
+ PDEBUG("Invalid Tx size [%d]!\n", count);
+ return 0;
+ }
+
+ if (copy_from_user((void *)priv->data_out.buf, (void *)buf, count)) {
+ PDEBUG("copy_from_user() error!\n");
+ return -EFAULT;
+ }
+
+ last_word = (unsigned short)append_checksum(priv->data_out.buf, count);
+#ifndef HOST_IS_PANABOARD
+ memcpy(&priv->data_out.buf[count], &last_word, 2);
+#else
+ priv->data_out.buf[count] = (char)( (last_word>>8)&0x00ff );
+ priv->data_out.buf[count+1] = (char)( last_word&0x00ff );
+#endif
+ priv->data_out.len = count + sizeof(last_word);
+
+ if (down_interruptible(&dev_priv->sem))
+ return -ERESTARTSYS;
+
+ if (dev_priv->cmd_handshake_polling) {
+ //disable PREVMSG_FETCH & NEWMSG_COMING
+ rtl_mdio_mask_write(NFBI_REG_IMR, (IM_PREVMSG_FETCH|IM_NEWMSG_COMING), 0x0000);
+ }
+ else{
+ //enable PREVMSG_FETCH & NEWMSG_COMING
+ //rtl_mdio_mask_write(NFBI_REG_IMR, (IM_PREVMSG_FETCH|IM_NEWMSG_COMING), (IM_PREVMSG_FETCH|IM_NEWMSG_COMING));
+ }
+
+ dev_priv->filp = filp;
+ dev_priv->tx_command_frames++;
+ retransmit_count = priv->retransmit_count;
+ //transmit command frame
+retransmit:
+ if (dev_priv->cmd_handshake_polling)
+ rtl_mdio_write(NFBI_REG_ISR, (IP_PREVMSG_FETCH|IP_NEWMSG_COMING));
+
+ priv->tx_cmd_transmitting_len = 0;
+ priv->state = STATE_TX_IN_PROGRESS;
+ transmit_msg(priv);
+ do {
+ if (dev_priv->cmd_handshake_polling) {
+ if (msleep_interruptible(dev_priv->interrupt_timeout*10)) { //in ms
+ priv->state = STATE_TX_INIT;
+ dev_priv->filp = NULL;
+ dev_priv->tx_stop_by_signals++;
+ up(&dev_priv->sem); /* release the lock */
+ return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
+ }
+ rtl_mdio_read(NFBI_REG_ISR, &status);
+ if (!(status & IP_PREVMSG_FETCH)) {
+ priv->state = STATE_TX_INIT;
+ dev_priv->tx_interupt_timeouts++;
+ if (retransmit_count > 0) {
+ retransmit_count--;
+ dev_priv->tx_retransmit_counts++;
+ printk(".\n");
+ goto retransmit;
+ }
+ dev_priv->filp = NULL;
+ up(&dev_priv->sem); // release the lock
+ return -ETIME;
+ }
+ rtl_mdio_write(NFBI_REG_ISR, IP_PREVMSG_FETCH);
+ }
+ else {
+ //PDEBUG("\"%s\"(pid %i) writing: going to sleep\n", current->comm, current->pid);
+ /* register the timer */
+ dev_priv->timer_expired = 0; /* if timer expired, wake up processes in the wait queue */
+ dev_priv->timer.data = 0;
+ dev_priv->timer.function = nfbi_timer_fn;
+ dev_priv->timer.expires = jiffies + dev_priv->interrupt_timeout; /* in jiffies */
+ //curr_time = jiffies;
+ add_timer(&dev_priv->timer);
+ if (wait_event_interruptible(dev_priv->wq, (dev_priv->tx_msg_is_fetched || dev_priv->timer_expired))) {
+ priv->state = STATE_TX_INIT;
+ del_timer(&dev_priv->timer);
+ dev_priv->filp = NULL;
+ dev_priv->tx_stop_by_signals++;
+ //rtl_mdio_read(NFBI_REG_IMR, &imr);
+ //rtl_mdio_write(NFBI_REG_IMR, (imr&0xfff9)); //disable PREVMSG_FETCH & NEWMSG_COMING
+ up(&dev_priv->sem); /* release the lock */
+ return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
+ }
+ if (dev_priv->timer_expired) { //timeout
+ //printk("tx curr_time=%lx jiffies=%lx, %ld ms\n", curr_time, jiffies, (jiffies-curr_time)*1000/HZ);
+ priv->state = STATE_TX_INIT;
+ dev_priv->tx_interupt_timeouts++;
+ if (retransmit_count > 0) {
+ retransmit_count--;
+ dev_priv->tx_retransmit_counts++;
+ printk(".\n");
+ goto retransmit;
+ }
+ dev_priv->filp = NULL;
+ //rtl_mdio_read(NFBI_REG_IMR, &imr);
+ //rtl_mdio_write(NFBI_REG_IMR, (imr&0xfff9)); //disable PREVMSG_FETCH & NEWMSG_COMING
+ up(&dev_priv->sem); // release the lock
+ return -ETIME;
+ }
+ else
+ del_timer(&dev_priv->timer);
+ }
+
+ if (priv->tx_cmd_transmitting_len >= priv->data_out.len)
+ priv->state = STATE_RX_INIT;
+ else {
+ if (dev_priv->tx_cmdword_interval > 0) {
+ if (dev_priv->cmd_handshake_polling) {
+ if(dev_priv->tx_cmdword_interval > dev_priv->interrupt_timeout)
+ mdelay((dev_priv->tx_cmdword_interval-dev_priv->interrupt_timeout)*10);
+ }
+ else {
+ mdelay(dev_priv->tx_cmdword_interval*10);
+ }
+ }
+ transmit_msg(priv);
+ }
+ } while (priv->state != STATE_RX_INIT);
+
+ dev_priv->tx_done_command_frames++;
+
+ //receive status frame
+ RESET_RX_STATE;
+ while (priv->state != STATE_RX_FINISHED) {
+ if (dev_priv->cmd_handshake_polling) {
+ curr_time = jiffies;
+wait_response:
+ if (msleep_interruptible(dev_priv->interrupt_timeout*10)) { //in ms
+ priv->state = STATE_TX_INIT;
+ dev_priv->rx_stop_by_signals++;
+ up(&dev_priv->sem); /* release the lock */
+ return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
+ }
+ rtl_mdio_read(NFBI_REG_ISR, &status);
+ if (!(status & IP_NEWMSG_COMING)) {
+ if (priv->state == STATE_RX_INIT) {
+ if (jiffies < (priv->response_timeout+curr_time))
+ goto wait_response;
+ dev_priv->rx_response_timeouts++;
+ }
+ else
+ dev_priv->rx_interupt_timeouts++;
+ priv->state = STATE_TX_INIT;
+ if (retransmit_count > 0) {
+ retransmit_count--;
+ dev_priv->tx_retransmit_counts++;
+ printk(".\n");
+ goto retransmit;
+ }
+ up(&dev_priv->sem); // release the lock
+ PDEBUG("ETIME=%d\n", ETIME);
+ return -ETIME;
+ }
+ rtl_mdio_write(NFBI_REG_ISR, IP_NEWMSG_COMING);
+ }
+ else {
+ //PDEBUG("\"%s\"(pid %i) reading: going to sleep\n", current->comm, current->pid);
+ /* register the timer */
+ dev_priv->timer_expired = 0; /* if timer expired, wake up processes in the wait queue */
+ dev_priv->timer.data = 0;
+ dev_priv->timer.function = nfbi_timer_fn;
+ if (priv->state == STATE_RX_INIT)
+ dev_priv->timer.expires = jiffies + priv->response_timeout; /* in jiffies */
+ else /* STATE_RX_WAIT_LEN or STATE_RX_WAIT_DATA*/
+ dev_priv->timer.expires = jiffies + dev_priv->interrupt_timeout; /* in jiffies */
+ //curr_time = jiffies;
+ add_timer(&dev_priv->timer);
+ if (wait_event_interruptible(dev_priv->wq, (dev_priv->rx_msg_is_coming || dev_priv->timer_expired))) {
+ priv->state = STATE_TX_INIT;
+ del_timer(&dev_priv->timer);
+ dev_priv->rx_stop_by_signals++;
+ //rtl_mdio_read(NFBI_REG_IMR, &imr);
+ //rtl_mdio_write(NFBI_REG_IMR, (imr&0xfff9)); //disable PREVMSG_FETCH & NEWMSG_COMING
+ up(&dev_priv->sem); /* release the lock */
+ return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
+ }
+
+ if (dev_priv->timer_expired) { //timeout
+ //printk("rx curr_time=%lx jiffies=%lx, %ld ms\n", curr_time, jiffies, (jiffies-curr_time)*1000/HZ);
+ if (priv->state == STATE_RX_INIT)
+ dev_priv->rx_response_timeouts++;
+ else
+ dev_priv->rx_interupt_timeouts++;
+ priv->state = STATE_TX_INIT;
+ if (retransmit_count > 0) {
+ retransmit_count--;
+ dev_priv->tx_retransmit_counts++;
+ printk(".\n");
+ goto retransmit;
+ }
+ //rtl_mdio_read(NFBI_REG_IMR, &imr);
+ //rtl_mdio_write(NFBI_REG_IMR, (imr&0xfff9)); //disable PREVMSG_FETCH & NEWMSG_COMING
+ up(&dev_priv->sem); // release the lock
+ PDEBUG("ETIME=%d\n", ETIME);
+ return -ETIME;
+ }
+ else
+ del_timer(&dev_priv->timer);
+ }
+
+ dev_priv->rx_msg_is_coming = 0;
+#ifdef SIMULATION
+ data = register_read_dw(NFBI_REG_RSR);
+#else
+ rtl_mdio_read(NFBI_REG_RSR, &data);
+#endif
+ dev_priv->rx_words++;
+ //printk("data=%04x\n", data);
+ process_rx_msg(priv, data);
+ }
+ dev_priv->rx_status_frames++;
+ dev_priv->filp = NULL;
+ //rtl_mdio_read(NFBI_REG_IMR, &imr);
+ //rtl_mdio_write(NFBI_REG_IMR, (imr&0xfff9)); //disable PREVMSG_FETCH & NEWMSG_COMING
+
+ if (dev_priv->cmd_handshake_polling)
+ rtl_mdio_write(NFBI_REG_ISR, (IP_PREVMSG_FETCH|IP_NEWMSG_COMING));
+
+ up(&dev_priv->sem);
+
+ return count;
+}
+
+
+#ifdef SIMULATION
+static int read_proc(char *buf, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int size = 0;
+
+ //printk("buf=%p *start=%p count=%d off=%d\n", buf, *start, count, off);
+
+ if (down_interruptible(&sim_sem))
+ return -ERESTARTSYS;
+
+ if ((data_out_len > 0) && (off==0)) {
+
+//fetch_again:
+ //while (data_out_len > 0) {
+ data_out_len = 0;
+ size += sprintf(&buf[size], "%04x ", data_out);
+ //}
+
+ msg_is_fetched = 1;
+ nfbi_interrupt(0, (void *)dev_priv, (struct pt_regs *)NULL);
+
+// if (data_out_len > 0)
+// goto fetch_again;
+
+ strcat(&buf[size++], "\n");
+ }
+
+ up(&sim_sem);
+ *eof = 1;
+ 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 {
+ PDEBUG("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;
+ //int i;
+
+ //printk("file=%p buffer=%p count=%d\n", file, buffer, count);
+ /*
+ printk("buffer=");
+ for(i=0;i<count; i++) {
+ printk("%02x ", buffer[i]);
+ }
+ printk("\n");
+ */
+ //data_in_len = 0;
+
+ while (len > 0) {
+ memcpy(tmp, buffer, 4);
+ tmp[4] = '\0';
+
+ in_data = _atoi(tmp, 16);
+
+ if (down_interruptible(&sim_sem))
+ return -ERESTARTSYS;
+
+ data_in_len = 0;
+ memcpy(&data_in[data_in_len], &in_data, 2);
+ data_in_len = 2;
+ data_in_read_idx = 0;
+ msg_is_coming = 1;
+ nfbi_interrupt(0, (void *)dev_priv, (struct pt_regs *)NULL);
+ up(&sim_sem);
+
+ interruptible_sleep_on(&sim_wq);
+ //if (interruptible_sleep_on(&sim_wq)) {
+ //return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
+ //}
+
+ len -= 5;
+ buffer += 5;
+ }
+
+ return count;
+}
+#endif
+
+#define RTL8198_PATCH1
+#ifdef RTL8198_PATCH1
+static int last_addr;
+#endif
+/*================================================================*/
+/* Description :
+ * char *buf : byte array should be big endian image for RTL8197B
+ */
+int nfbi_mem_write(int addr, int len, char *buf)
+{
+ int ret, i;
+ unsigned short val;
+ char tmp[4];
+
+ if (len > NFBI_MAX_BULK_MEM_SIZE)
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_CMD, 0x0000)) //write mode
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_ADDH, (addr>>16)&0xffff)) //address H
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_ADDL, addr&0xffff)) //address L
+ return -1;
+
+#ifdef RTL8198_PATCH1
+ if ((last_addr&0xfffff000)!= (addr&0xfffff000)) {
+ if (0 != rtl_mdio_write(NFBI_REG_DH, 0x0000)) //data H
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_DL, 0x0000)) //data L
+ return -1;
+#ifdef CHECK_NFBI_BUSY_BIT
+ // check NFBI hardware status
+ do {
+ ret = rtl_mdio_read(NFBI_REG_CMD, &val);
+ if (ret != 0)
+ return -1;
+ } while (val&BM_BUSY); //wait busy bit to zero
+#endif
+ //set address again
+ if (0 != rtl_mdio_write(NFBI_REG_ADDH, (addr>>16)&0xffff)) //address H
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_ADDL, addr&0xffff)) //address L
+ return -1;
+ }
+ last_addr = addr;
+#endif
+
+ if (len >= 4) {
+ for (i=0; i<len; i+=4) {
+#ifndef HOST_IS_PANABOARD
+ if (0 != rtl_mdio_write(NFBI_REG_DH, *(unsigned short *)(buf+i))) //data H
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_DL, *(unsigned short *)(buf+i+2))) //data L
+ return -1;
+#else
+ val = (*(buf+i)<<8)&0xff00;
+ val |= (*(buf+i+1))&0x00ff;
+ if (0 != rtl_mdio_write(NFBI_REG_DH, val)) //data H
+ return -1;
+ val = (*(buf+i+2)<<8)&0xff00;
+ val |= (*(buf+i+3))&0x00ff;
+ if (0 != rtl_mdio_write(NFBI_REG_DL, val)) //data L
+ return -1;
+#endif /*HOST_IS_PANABOARD*/
+#ifdef CHECK_NFBI_BUSY_BIT
+ // check NFBI hardware status
+ do {
+ ret = rtl_mdio_read(NFBI_REG_CMD, &val);
+ if (ret != 0)
+ return -1;
+ } while (val&BM_BUSY); //wait busy bit to zero
+#endif
+ }
+ }
+
+ if ( (len%4) )
+ {
+ memset(tmp, 0, 4);
+ memcpy(tmp, (buf+(len/4)*4),(len%4));
+#ifndef HOST_IS_PANABOARD
+ if (0 != rtl_mdio_write(NFBI_REG_DH, *(unsigned short *)tmp)) //data H
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_DL, *(unsigned short *)(tmp+2))) //data L
+ return -1;
+#else
+ val = (tmp[0]<<8)&0xff00;
+ val |= (tmp[1])&0x00ff;
+ if (0 != rtl_mdio_write(NFBI_REG_DH, val)) //data H
+ return -1;
+ val = (tmp[2]<<8)&0xff00;
+ val |= (tmp[3])&0x00ff;
+ if (0 != rtl_mdio_write(NFBI_REG_DL, val)) //data L
+ return -1;
+#endif /*HOST_IS_PANABOARD*/
+#ifdef CHECK_NFBI_BUSY_BIT
+ // check NFBI hardware status
+ do {
+ ret = rtl_mdio_read(NFBI_REG_CMD, &val);
+ if (ret != 0)
+ return -1;
+ } while (val&BM_BUSY); //wait busy bit to zero
+#endif
+ }
+ return 0;
+}
+
+int nfbi_mem_read(int addr, int len, char *buf)
+{
+ int ret, i;
+ unsigned short val;
+ char tmp[4];
+
+ if (len > NFBI_MAX_BULK_MEM_SIZE)
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_CMD, 0x8000)) //read mode
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_ADDH, (addr>>16)&0xffff)) //address H
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_ADDL, addr&0xffff)) //address L
+ return -1;
+
+#ifdef RTL8198_PATCH1
+ if ((last_addr&0xfffff000)!= (addr&0xfffff000)) {
+ if (0 != rtl_mdio_read(NFBI_REG_DH, (unsigned short *)buf)) //data H
+ return -1;
+ if (0 != rtl_mdio_read(NFBI_REG_DL, (unsigned short *)(buf+2))) //data L
+ return -1;
+#ifdef CHECK_NFBI_BUSY_BIT
+ // check NFBI hardware status
+ do {
+ ret = rtl_mdio_read(NFBI_REG_CMD, &val);
+ if (ret != 0)
+ return -1;
+ } while (val&BM_BUSY); //wait busy bit to zero
+#endif
+ //set address again
+ if (0 != rtl_mdio_write(NFBI_REG_ADDH, (addr>>16)&0xffff)) //address H
+ return -1;
+ if (0 != rtl_mdio_write(NFBI_REG_ADDL, addr&0xffff)) //address L
+ return -1;
+ }
+ last_addr = addr;
+#endif
+
+ if (len >= 4) {
+ for (i=0; i<len; i+=4) {
+#ifndef HOST_IS_PANABOARD
+ if (0 != rtl_mdio_read(NFBI_REG_DH, (unsigned short *)(buf+i))) //data H
+ return -1;
+ if (0 != rtl_mdio_read(NFBI_REG_DL, (unsigned short *)(buf+i+2))) //data L
+ return -1;
+#else
+ if (0 != rtl_mdio_read(NFBI_REG_DH, &val)) //data H
+ return -1;
+ *(buf+i) = (char)( (val>>8)&0x00ff );
+ *(buf+i+1) = (char)( val&0x00ff );
+ if (0 != rtl_mdio_read(NFBI_REG_DL, &val)) //data L
+ return -1;
+ *(buf+i+2) = (char)( (val>>8)&0x00ff );
+ *(buf+i+3) = (char)( val&0x00ff );
+#endif /*HOST_IS_PANABOARD*/
+#ifdef CHECK_NFBI_BUSY_BIT
+ // check NFBI hardware status
+ do {
+ ret = rtl_mdio_read(NFBI_REG_CMD, &val);
+ if (ret != 0)
+ return -1;
+ } while (val&BM_BUSY); //wait busy bit to zero
+#endif
+ }
+ }
+
+ if ( (len%4) )
+ {
+#ifndef HOST_IS_PANABOARD
+ if (0 != rtl_mdio_read(NFBI_REG_DH, (unsigned short *)tmp)) //data H
+ return -1;
+ if (0 != rtl_mdio_read(NFBI_REG_DL, (unsigned short *)(tmp+2))) //data L
+ return -1;
+#else
+ if (0 != rtl_mdio_read(NFBI_REG_DH, &val)) //data H
+ return -1;
+ tmp[0] = (char)( (val>>8)&0x00ff );
+ tmp[1] = (char)( val&0x00ff );
+ if (0 != rtl_mdio_read(NFBI_REG_DL, &val)) //data L
+ return -1;
+ tmp[2] = (char)( (val>>8)&0x00ff );
+ tmp[3] = (char)( val&0x00ff );
+#endif
+#ifdef CHECK_NFBI_BUSY_BIT
+ // check NFBI hardware status
+ do {
+ ret = rtl_mdio_read(NFBI_REG_CMD, &val);
+ if (ret != 0)
+ return -1;
+ } while (val&BM_BUSY); //wait busy bit to zero
+#endif
+ memcpy((buf+(len/4)*4), tmp, (len%4));
+ }
+ return 0;
+}
+
+void nfbi_hw_reset(int type)
+{
+ switch(type) {
+ case 0: //pull low
+ Set_NFBI_RESET_L();
+ break;
+ case 1: //pull high
+ Set_NFBI_RESET_H();
+ break;
+ case 2: //hardware reset
+#ifndef HOST_IS_PANABOARD
+ // In 8198 platform, interrupt will come very soon after pull-low reset pin.
+ // When the interrupt occurs, the hw reset sequence will be interleaved by ISR
+ // and that would cause the reset action unable to compete.
+ // Therefore, it's necessary to disable interrupt before hardware reset.
+ REG32(PABIMR_REG) = REG32(PABIMR_REG) & 0x3fffffff; //set B7 falling interrupt(bit31,30), 0x00 diable, 0x01 falling, 0x02 rasing, 0x03 both
+#endif
+ Set_NFBI_RESET_L();
+ //mdelay(400); //To reset RTL8197B CPU, the RESETn pin must be pull-low at least 350 ms.
+ mdelay(1000);
+ Set_NFBI_RESET_H();
+ mdelay(1000);
+#ifdef HOST_IS_PANABOARD
+ /* Ebina add for Micrel Isolation */
+ avev3_mdio_write(avev3_dev, 0x1, MII_BMCR, 0x3400);
+#endif
+#ifndef HOST_IS_PANABOARD
+ // enable interrupt after hardware reset
+ REG32(PABIMR_REG) = REG32(PABIMR_REG) | (0x01 <<30); //set B7 falling interrupt(bit31,30), 0x00 diable, 0x01 falling, 0x02 rasing, 0x03 both
+#endif
+ break;
+ }
+}
+
+unsigned char nfbi_probephyaddr(void)
+{
+ int i;
+ unsigned int val = 0;
+ int reg = NFBI_REG_PHYID2; //PHYID2
+
+#ifndef HOST_IS_PANABOARD
+#ifdef MDCIO_GPIO_SIMULATION
+ unsigned short regval;
+#else
+ int timeout = MDIO_TIMEOUT;
+#endif
+#endif
+ unsigned char phyaddr;
+
+ for (i=0; i<32; i++) {
+ phyaddr=i;
+
+#ifndef HOST_IS_PANABOARD
+#ifdef MDCIO_GPIO_SIMULATION
+ smiRead(phyaddr, reg, &regval);
+ val = regval;
+#else
+ REG32(MDCIOCR) = 0x7fffffff & ((phyaddr<<24) | ((reg&0x1f)<<16));
+ while (--timeout) {
+ val = REG32(MDCIOSR);
+ if ((val&0x80000000) == 0)
+ break;
+ }
+ if (timeout==0)
+ printk("Timeout! Probe PHY Addr=%x fail!\n",phyaddr);
+#endif
+#else
+ val = avev3_mdio_read(avev3_dev, phyaddr, reg);
+#endif
+ printk("Probe PHY ADDR=0x%x reg3=0x%x\n",phyaddr, val&0xffff);
+ if (((val&0xffff)==NFBI_REG_PHYID2_DEFAULT) ||
+ ((val&0xffff)==NFBI_REG_PHYID2_DEFAULT2)) { //PHY Addr
+ printk("Pass! Probe PHY ADDR = %d\n", phyaddr);
+ dev_priv->ready = 1;
+ return phyaddr;
+ }
+ }
+
+ if(i==32)
+ printk("Error! NFBI maybe not connect!\n");
+
+ dev_priv->ready = 0;
+ return 0xff;
+}
+
+void dump_private_data(void)
+{
+ int i;
+ struct nfbi_priv *priv;
+
+ printk("ready=%d\n", dev_priv->ready);
+ printk("mdio_phyaddr=%d\n", mdio_phyaddr);
+ printk("cmd_handshake_polling=%d\n", dev_priv->cmd_handshake_polling);
+ printk("hcd_pid=%d\n", dev_priv->hcd_pid);
+ printk("evt_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("tx_cmdword_interval:%d (in 10ms)\n", dev_priv->tx_cmdword_interval);
+ printk("tx_msg_is_fetched=%d\n", dev_priv->tx_msg_is_fetched);
+ printk("rx_msg_is_coming=%d\n", dev_priv->rx_msg_is_coming);
+ printk("interrupt_timeout=%d (in 10ms)\n", dev_priv->interrupt_timeout);
+ printk("dev_priv->filp:%p\n", dev_priv->filp);
+
+ if (dev_priv->filp != NULL) {
+ priv = (struct nfbi_priv *)dev_priv->filp->private_data;
+ printk("state:");
+ switch(priv->state) {
+ case STATE_TX_INIT:
+ printk("STATE_TX_INIT\n");
+ break;
+ case STATE_TX_IN_PROGRESS:
+ printk("STATE_TX_IN_PROGRESS\n");
+ break;
+ 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_FINISHED:
+ printk("STATE_RX_FINISHED\n");
+ break;
+ }
+ printk("Tx:\n");
+ printk("data_out:");
+ for(i=0;i<priv->data_out.len;i++) {
+ printk("%02x ", priv->data_out.buf[i]);
+ }
+ printk("\n");
+ printk("tx_cmd_transmitting_len=%d\n", priv->tx_cmd_transmitting_len);
+
+ printk("Rx:\n");
+ printk("data_in:");
+ for(i=0;i<priv->data_in.len;i++) {
+ printk("%02x ", priv->data_in.buf[i]);
+ }
+ printk("\n");
+ printk("rx_status_remain_len=%d\n", priv->rx_status_remain_len);
+ printk("rx_status_time=%lx jiffies=%lx (%d sec)\n", priv->rx_status_time, jiffies, (int)(jiffies-priv->rx_status_time)/HZ);
+ }
+ printk("===============================================\n");
+ printk("Statistics:\n");
+ printk("tx_command_frames=%d\n", dev_priv->tx_command_frames);
+ printk("tx_done_command_frames=%d\n", dev_priv->tx_done_command_frames);
+ printk("tx_retransmit_counts=%d\n", dev_priv->tx_retransmit_counts);
+ printk("tx_words=%d\n", dev_priv->tx_words);
+ printk("tx_interupt_timeouts=%d\n", dev_priv->tx_interupt_timeouts);
+ printk("tx_stop_by_signals=%d\n", dev_priv->tx_stop_by_signals);
+ printk("rx_status_frames=%d\n", dev_priv->rx_status_frames);
+ printk("rx_words=%d\n", dev_priv->rx_words);
+ printk("rx_response_timeouts=%d\n", dev_priv->rx_response_timeouts);
+ printk("rx_interupt_timeouts=%d\n", dev_priv->rx_interupt_timeouts);
+ printk("rx_stop_by_signals=%d\n", dev_priv->rx_stop_by_signals);
+ printk("rx_not_1st_word_errors=%d\n", dev_priv->rx_not_1st_word_errors);
+ printk("rx_1st_byte_errors=%d\n", dev_priv->rx_1st_byte_errors);
+ printk("rx_cmdid_not_match_errors=%d\n", dev_priv->rx_cmdid_not_match_errors);
+ printk("rx_reset_by_sync_bit_errors=%d\n", dev_priv->rx_reset_by_sync_bit_errors);
+ printk("rx_checksum_errors=%d\n", dev_priv->rx_checksum_errors);
+
+#ifdef SIMULATION
+ printk("===============================================\n");
+ printk("msg_is_comming=%d\n", msg_is_coming);
+ printk("data_in_read_idx=%d\n", data_in_read_idx);
+ for(i=0;i<data_in_len;i++) {
+ printk("%02x ", data_in[i]);
+ }
+ printk("\n");
+
+ printk("msg_is_fetched=%d\n", msg_is_fetched);
+ printk("data_out_len=%d\n", data_out_len);
+ printk("data_out=%04x\n", data_out);
+#endif
+}
+
+/*================================================================*/
+
+void nfbi_private_command(int type)
+{
+ switch(type) {
+ case 0: //pull low
+ case 1: //pull high
+ case 2: //hardware reset
+ nfbi_hw_reset(type);
+ break;
+ case 3:
+ nfbi_probephyaddr();
+ break;
+ case 4: //dump private data
+ dump_private_data();
+ break;
+ case 5: //reset event queue
+ dev_priv->evt_que_head = 0;
+ dev_priv->evt_que_tail = 0;
+ break;
+ }
+}
+
+#ifdef CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST
+
+void SetCurrentPhyId(unsigned char dsp_id)
+{
+ if (dsp_id == 0)
+ {
+ mdio_phyaddr = 8;
+ }
+ else if (dsp_id == 1)
+ {
+ mdio_phyaddr = 16;
+ }
+ //printk("Set current phy ID to %d.\n", mdio_phyaddr);
+}
+
+unsigned char GetCurrentPhyId(void)
+{
+ return mdio_phyaddr;
+}
+
+unsigned char CheckDspIfAllSoftwareReady(void)
+{
+ unsigned short val;
+ int retval = 0;
+
+ retval = rtl_mdio_read(0x17 & 0xffff, &val);//SYSSR
+ //printk("val = 0x%x\n", val);
+ //printk("val&0x400 = 0x%x\n", val&0x400);
+
+ if (retval == 0)
+ {
+ if (val & 0x400)
+ return 1; // AllSoftwareReady
+ else
+ return 0; // AllSoftware NOT Ready
+ }
+ return 0;;
+}
+
+unsigned char SetDspIdToDsp(int dsp_id)
+{
+ unsigned short val;
+ int retval = 0;
+
+ retval = rtl_mdio_read(0x18 & 0xffff, &val);//SYSCR
+ if (retval != 0)
+ {
+ printk("SetDspIdToDsp Fail\n");
+ return 0;//Fail
+ }
+
+ val = (val & 0xFFF0) | dsp_id;
+ retval = rtl_mdio_write(0x18 & 0xffff, val&0xffff);
+ if (retval != 0)
+ {
+ printk("SetDspIdToDsp Fail\n");
+ return 0;//Fail
+ }
+
+ printk("SetDspIdToDsp%d \n", dsp_id);
+
+ return 1;
+}
+
+#endif
+
+/*
+ * The ioctl() implementation
+ * Refer to the book "Linux Device Drivers" by Alessandro Rubini and Jonathan Corbet,
+ * published by O'Reilly & Associates.
+ */
+static int nfbi_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ //int err = 0;
+ int retval = 0, tmp;
+ unsigned short val;
+ struct nfbi_bulk_mem_param *pbulkmem;
+ struct nfbi_mem32_param mem32_param;
+ struct evt_msg evt;
+ struct nfbi_priv *priv;
+
+ /*
+ * extract the type and number bitfields, and don't decode
+ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+ */
+ if (_IOC_TYPE(cmd) != NFBI_IOC_MAGIC) return -ENOTTY;
+ if (_IOC_NR(cmd) > NFBI_IOCTL_MAXNR) return -ENOTTY;
+
+ /*
+ * the direction is a bitmask, and VERIFY_WRITE catches R/W
+ * transfers. `Type' is user-oriented, while
+ * access_ok is kernel-oriented, so the concept of "read" and
+ * "write" is reversed
+ */
+ /*
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
+ if (err) return -EFAULT;
+ */
+
+ switch(cmd) {
+ case NFBI_IOCTL_PRIV_CMD:
+ retval = get_user(tmp, (int *)arg);
+ if (retval == 0) {
+ nfbi_private_command(tmp);
+ }
+ break;
+ case NFBI_IOCTL_REGREAD:
+ retval = get_user(tmp, (int *)arg);
+ if (retval == 0) {
+ /* The register address to be read is stored at the high word of tmp. */
+ retval = rtl_mdio_read((tmp >> 16) & 0xffff, &val); //@Pana_TBD
+ if (retval == 0) {
+ /*
+ * stored register address at the high word of tmp and
+ * value at the low word of tmp, and then copy to user space
+ */
+ tmp = (tmp & 0xffff0000) | val;
+ retval = put_user(tmp, (int *)arg);
+ }
+ }
+ break;
+ case NFBI_IOCTL_REGWRITE:
+ retval = get_user(tmp, (int *)arg);
+ if (retval == 0) {
+ /*
+ * The register address is stored at the high word of tmp.
+ * The value to be written is stored at the low word of tmp.
+ */
+ retval = rtl_mdio_write((tmp >> 16) & 0xffff, tmp&0xffff); //@Pana_TBD
+ }
+ break;
+ case NFBI_IOCTL_HCD_PID:
+ if (0 == get_user(tmp, (int *)arg)) {
+ dev_priv->hcd_pid = tmp;
+ //PDEBUG("hcd_pid=%d\n", dev_priv->hcd_pid);
+ }
+ break;
+ case NFBI_IOCTL_GET_EVENT:
+ //retrieve_evt(priv, &evt);
+ retrieve_evt(&evt);
+ retval = copy_to_user((struct evt_msg *)arg, &evt, sizeof(struct evt_msg));
+ break;
+#ifndef HOST_IS_PANABOARD
+ case NFBI_IOCTL_MEM32_WRITE:
+ retval = copy_from_user(&mem32_param, (struct nfbi_mem32_param *)arg, sizeof(struct nfbi_mem32_param));
+ //printk("mem32_param.addr=%x mem32_param.val=%x\n", mem32_param.addr, mem32_param.val);
+ if (retval == 0)
+ retval = nfbi_mem_write(mem32_param.addr, sizeof(int), (char *)&(mem32_param.val));
+ break;
+ case NFBI_IOCTL_MEM32_READ:
+ retval = copy_from_user(&mem32_param, (struct nfbi_mem32_param *)arg, sizeof(struct nfbi_mem32_param));
+ if (retval == 0)
+ retval = nfbi_mem_read(mem32_param.addr, sizeof(int), (char *)&(mem32_param.val));
+ if (retval == 0)
+ retval = copy_to_user((struct nfbi_mem32_param *)arg, &mem32_param, sizeof(struct nfbi_mem32_param));
+ //printk("mem32_param.addr=%x mem32_param.val=%x\n", mem32_param.addr, mem32_param.val);
+ break;
+#else
+ case NFBI_IOCTL_MEM32_WRITE:
+ retval = copy_from_user(&mem32_param, (struct nfbi_mem32_param *)arg, sizeof(struct nfbi_mem32_param));
+ //printk("mem32_param.addr=%x mem32_param.val=%x\n", mem32_param.addr, mem32_param.val);
+ tmp = htonl(mem32_param.val);
+ if (retval == 0)
+ retval = nfbi_mem_write(mem32_param.addr, sizeof(int), (char *)&(tmp));
+ break;
+ case NFBI_IOCTL_MEM32_READ:
+ retval = copy_from_user(&mem32_param, (struct nfbi_mem32_param *)arg, sizeof(struct nfbi_mem32_param));
+ if (retval == 0)
+ retval = nfbi_mem_read(mem32_param.addr, sizeof(int), (char *)&(tmp));
+ mem32_param.val = ntohl (tmp);
+ if (retval == 0)
+ retval = copy_to_user((struct nfbi_mem32_param *)arg, &mem32_param, sizeof(struct nfbi_mem32_param));
+ //printk("mem32_param.addr=%x mem32_param.val=%x\n", mem32_param.addr, mem32_param.val);
+ break;
+#endif/*HOST_IS_PANABOARD*/
+ case NFBI_IOCTL_BULK_MEM_WRITE:
+ pbulkmem = (struct nfbi_bulk_mem_param *)kmalloc(sizeof(struct nfbi_bulk_mem_param), GFP_KERNEL);
+ if(!pbulkmem) {
+ printk(KERN_ERR DRIVER_NAME": unable to kmalloc\n");
+ return -ENOMEM;
+ }
+ retval = copy_from_user(pbulkmem, (struct nfbi_bulk_mem_param *)arg, sizeof(struct nfbi_bulk_mem_param));
+ //printk("pbulkmem->addr=%x pbulkmem->len=%d\n", pbulkmem->addr, pbulkmem->len);
+ if (retval == 0)
+ retval = nfbi_mem_write(pbulkmem->addr, pbulkmem->len, pbulkmem->buf);
+ kfree(pbulkmem);
+ printk(">");
+ break;
+ case NFBI_IOCTL_BULK_MEM_READ:
+ pbulkmem = (struct nfbi_bulk_mem_param *)kmalloc(sizeof(struct nfbi_bulk_mem_param), GFP_KERNEL);
+ if(!pbulkmem) {
+ printk(KERN_ERR DRIVER_NAME": unable to kmalloc\n");
+ return -ENOMEM;
+ }
+ //retval = copy_from_user(pbulkmem, (struct nfbi_bulk_mem_param *)arg, sizeof(struct nfbi_bulk_mem_param));
+ retval = copy_from_user(pbulkmem, (struct nfbi_bulk_mem_param *)arg, 8);
+ if (retval == 0) {
+ //printk("pbulkmem->addr=%x pbulkmem->len=%d\n", pbulkmem->addr, pbulkmem->len);
+ retval = nfbi_mem_read(pbulkmem->addr, pbulkmem->len, pbulkmem->buf);
+ }
+ if (retval == 0)
+ retval = copy_to_user((struct nfbi_bulk_mem_param *)arg, pbulkmem, sizeof(struct nfbi_bulk_mem_param));
+ kfree(pbulkmem);
+ printk("<");
+ break;
+ case NFBI_IOCTL_TX_CMDWORD_INTERVAL:
+ retval = get_user(tmp, (int *)arg);
+ if (retval == 0) {
+ if (tmp & 0x10000)
+ dev_priv->tx_cmdword_interval = tmp & 0xffff; //set
+ else {
+ tmp = dev_priv->tx_cmdword_interval; //get
+ retval = put_user(tmp, (int *)arg);
+ }
+ }
+ break;
+ case NFBI_IOCTL_INTERRUPT_TIMEOUT:
+ retval = get_user(tmp, (int *)arg);
+ if (retval == 0) {
+ if (tmp & 0x10000)
+ dev_priv->interrupt_timeout = tmp & 0xffff; //set
+ else {
+ tmp = dev_priv->interrupt_timeout; //get
+ retval = put_user(tmp, (int *)arg);
+ }
+ }
+ break;
+ case NFBI_IOCTL_RETRANSMIT_COUNT:
+ retval = get_user(tmp, (int *)arg);
+ if (retval == 0) {
+ priv = (struct nfbi_priv *)filp->private_data;
+ priv->retransmit_count = tmp;
+ //PDEBUG("priv->retransmit_count=%d\n", priv->retransmit_count);
+ }
+ break;
+ case NFBI_IOCTL_RESPONSE_TIMEOUT:
+ retval = get_user(tmp, (int *)arg);
+ if (retval == 0) {
+ priv = (struct nfbi_priv *)filp->private_data;
+ priv->response_timeout = tmp;
+ //PDEBUG("priv->response_timeout=%d\n", priv->response_timeout);
+ }
+ break;
+ case NFBI_IOCTL_MDIO_PHYAD:
+ retval = get_user(tmp, (int *)arg);
+ if (retval == 0) {
+ mdio_phyaddr = (unsigned char)tmp;
+ printk("set mdio_phyaddr = %d\n", mdio_phyaddr);
+ if ((mdio_phyaddr==8) || (mdio_phyaddr==16))
+ dev_priv->ready = 1;
+ else
+ dev_priv->ready = 0;
+ //PDEBUG("mdio_phyaddr=%d\n", mdio_phyaddr);
+ }
+ break;
+ case NFBI_IOCTL_CMD_HANDSHAKE_POLLING:
+ retval = get_user(tmp, (int *)arg);
+ if (retval == 0) {
+ if (tmp & 0x10000) {
+ dev_priv->cmd_handshake_polling = tmp & 0xffff; //set
+ if (dev_priv->cmd_handshake_polling) {
+ dev_priv->interrupt_timeout = NFBI_POLLING_INTERVAL_DEFAULT;
+ //disable PREVMSG_FETCH & NEWMSG_COMING
+ rtl_mdio_mask_write(NFBI_REG_IMR, (IM_PREVMSG_FETCH|IM_NEWMSG_COMING), 0x0000);
+ }
+ else {
+ dev_priv->interrupt_timeout = NFBI_INTERRUPT_TIMEOUT_DEFAULT;
+ //enable PREVMSG_FETCH & NEWMSG_COMING
+ rtl_mdio_mask_write(NFBI_REG_IMR, (IM_PREVMSG_FETCH|IM_NEWMSG_COMING), (IM_PREVMSG_FETCH|IM_NEWMSG_COMING));
+ }
+ }
+ else {
+ tmp = dev_priv->cmd_handshake_polling; //get
+ retval = put_user(tmp, (int *)arg);
+ }
+ }
+ break;
+#ifndef HOST_IS_PANABOARD
+ //just for debugging purpose
+ case NFBI_IOCTL_EW:
+ retval = copy_from_user(&mem32_param, (struct nfbi_mem32_param *)arg, sizeof(struct nfbi_mem32_param));
+ //printk("mem32_param.addr=%x mem32_param.val=%x\n", mem32_param.addr, mem32_param.val);
+ if (retval == 0)
+ REG32(mem32_param.addr) = mem32_param.val;
+ break;
+ case NFBI_IOCTL_DW:
+ retval = copy_from_user(&mem32_param, (struct nfbi_mem32_param *)arg, sizeof(struct nfbi_mem32_param));
+ if (retval == 0)
+ mem32_param.val = REG32(mem32_param.addr);
+ if (retval == 0)
+ retval = copy_to_user((struct nfbi_mem32_param *)arg, &mem32_param, sizeof(struct nfbi_mem32_param));
+ //printk("mem32_param.addr=%x mem32_param.val=%x\n", mem32_param.addr, mem32_param.val);
+ break;
+#endif
+ default: /* redundant, as cmd was checked against MAXNR */
+ return -ENOTTY;
+ }
+ return retval;
+}
+
+static struct file_operations nfbi_fops = {
+ owner: THIS_MODULE,
+ read: nfbi_read,
+ write: nfbi_write,
+ ioctl: nfbi_ioctl,
+ open: nfbi_open,
+ release: nfbi_release,
+};
+
+#ifndef HOST_IS_PANABOARD
+static void __exit nfbi_exit(void)
+{
+ free_irq(irq, dev_priv);
+ kfree(dev_priv);
+ dev_priv = NULL;
+}
+#else
+void nfbi_exit(void)
+{
+ //free_irq(irq, dev_priv); /*don't free*/
+ kfree(dev_priv);
+ dev_priv = NULL;
+}
+#endif
+
+#ifndef HOST_IS_PANABOARD
+static int __init nfbi_init(void)
+#else
+int nfbi_init(void)
+#endif
+{
+#ifdef MDCIO_GPIO_SIMULATION
+ _smiGpioInit();
+#endif
+
+ dev_priv = (struct nfbi_dev_priv *)kmalloc(sizeof (struct nfbi_dev_priv), GFP_KERNEL);
+ if(!dev_priv) {
+ printk(KERN_ERR DRIVER_NAME": unable to kmalloc for nfbi_dev_priv\n");
+ return -ENOMEM;
+ }
+ memset((void *)dev_priv, 0, sizeof (struct nfbi_dev_priv));
+ dev_priv->hcd_pid = -1;
+ dev_priv->cmd_handshake_polling = NFBI_CMD_HANDSHAKE_POLLING_DEFAULT;
+ if (dev_priv->cmd_handshake_polling)
+ dev_priv->interrupt_timeout = NFBI_POLLING_INTERVAL_DEFAULT;
+ else
+ dev_priv->interrupt_timeout = NFBI_INTERRUPT_TIMEOUT_DEFAULT;
+ init_waitqueue_head(&(dev_priv->wq));
+ init_timer(&dev_priv->timer);
+ init_MUTEX(&dev_priv->sem);
+
+#ifdef MDCIO_GPIO_SIMULATION
+ init_timer(&dev_priv->mdc_timer);
+ dev_priv->mdc_timer.data = 0;
+ dev_priv->mdc_timer.function = mdc_timer_fn;
+ dev_priv->mdc_timer.expires = jiffies + 1; /* in jiffies */
+ add_timer(&dev_priv->mdc_timer);
+#endif
+
+ if (register_chrdev(DRIVER_MAJOR, DRIVER_NAME, &nfbi_fops)) {
+ printk(KERN_ERR DRIVER_NAME": unable to get major %d\n", DRIVER_MAJOR);
+ kfree(dev_priv);
+ return -EIO;
+ }
+
+ //nfbi_hw_reset(2); //for Pana's Reset-line modification (from pull-up to pull-down)
+
+#ifdef RTL89xxC_FAMILY
+ nfbi_hw_reset(2); //for Pana's Reset-line modification (from pull-up to pull-down)
+#endif
+
+#ifdef SIMULATION
+ init_waitqueue_head(&sim_wq);
+ init_waitqueue_head(&sim_rq);
+ init_MUTEX(&sim_sem);
+
+ struct proc_dir_entry *res;
+ res = create_proc_entry("nfbi_flag", 0, NULL);
+ if (res) {
+ res->read_proc = read_proc;
+ res->write_proc = write_proc;
+ }
+ else {
+ printk(KERN_ERR DRIVER_NAME": unable to create /proc/nfbi_flag\n");
+ return -1;
+ }
+#else
+#ifndef HOST_IS_PANABOARD
+ //register interrupt handler
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
+ if (request_irq(irq, nfbi_interrupt, IRQF_DISABLED, DRIVER_NAME, (void *)dev_priv))
+ {
+ printk(KERN_ERR DRIVER_NAME": IRQ %d is not free.\n", irq);
+ kfree(dev_priv);
+ return -1;
+ }
+#else
+
+ //if (request_irq(irq, nfbi_interrupt, SA_INTERRUPT, DRIVER_NAME, (void *)dev_priv)) {
+ if (request_irq(irq, nfbi_interrupt, 0, DRIVER_NAME, (void *)dev_priv)) {
+ printk(KERN_ERR DRIVER_NAME": IRQ %d is not free.\n", irq);
+ kfree(dev_priv);
+ return -1;
+ }
+#endif
+ printk("NFBI request_irq success!\n");
+
+#ifndef RTL89xxC_FAMILY
+ //================================================================
+ // RTL8651C GPIO B7 is connected with MDIO_INT pin.
+ // configure GPIO pin as input for hardware reset
+ // @Pana_TBD
+ REG32(PABCDCNR_REG) = REG32(PABCDCNR_REG) & (~0x8000); //B7, 0=Configured as GPIO pin
+ REG32(PABCDDIR_REG) = REG32(PABCDDIR_REG) & (~0x8000); //B7, 0=input, 1=output, Configured as input pin
+ REG32(PABIMR_REG) = (0x01 <<30); //set B7 falling interrupt(bit31,30), 0x00 diable, 0x01 falling, 0x02 rasing, 0x03 both
+ REG32(PABCDISR_REG) = REG32(PABCDISR_REG) | 0x8000; //write 1 to clear the interrupt at B7 (bit 15)
+
+ //REG32(IRR2_REG) = (REG32(IRR2_REG) &~(0x0f<<NFBI_IRR_OFFSET)) | (NFBI_IRR_NO<<NFBI_IRR_OFFSET);
+#endif
+#endif
+#endif
+
+ /*================================================================*/
+#ifndef HOST_IS_PANABOARD
+#ifdef RTL8651C_FAMILY
+ // RTL8651C GPIO B6 is connected with RESETn pin.
+ // configure GPIO pin as output for hardware reset
+ // @Pana_TBD
+ REG32(PABCDCNR_REG) = REG32(PABCDCNR_REG) & (~0x4000); //B6, 0=Configured as GPIO pin
+ REG32(PABCDDIR_REG) = REG32(PABCDDIR_REG) | 0x4000; //B6, 0=input, 1=output, Configured as output pin
+#elif defined (RTL89xxC_FAMILY)
+ // RTL89xxC GPIO E2 is connected with RESETn pin.
+ // configure GPIO pin as output for hardware reset
+ REG32(PEFGHCNR_REG) = REG32(PEFGHCNR_REG) & (~0x4); //E2, 0=Configured as GPIO pin
+ REG32(PEFGHDIR_REG) = REG32(PEFGHDIR_REG) | 0x4; //E2, 0=input, 1=output, Configured as output pin
+#endif
+#endif
+
+ // set the pre-selected phy address for MDIO address or probe the correct one
+#if 0
+ mdio_phyaddr = DEFAULT_MDIO_PHYAD;
+ dev_priv->ready = 1;
+#else
+ mdio_phyaddr = nfbi_probephyaddr();
+#endif
+ /*================================================================*/
+ //rtl_mdio_write(NFBI_REG_CMD, 0x0004); //configure interrupt level as high trigger
+ if (dev_priv->cmd_handshake_polling)
+ rtl_mdio_write(NFBI_REG_IMR, 0x0000);
+ else
+ rtl_mdio_write(NFBI_REG_IMR, 0x0006); //PREVMSG_FETCH & NEWMSG_COMING
+
+ printk(KERN_INFO DRIVER_NAME" driver "DRIVER_VER" at %X (Interrupt %d)\n", io, irq);
+ return 0;
+}
+
+#ifndef HOST_IS_PANABOARD
+module_init(nfbi_init);
+module_exit(nfbi_exit);
+
+MODULE_AUTHOR("Michael Lo");
+MODULE_DESCRIPTION("Driver for RTL8197B NFBI");
+MODULE_LICENSE("none-GPL");
+EXPORT_NO_SYMBOLS;
+#endif
+
diff --git a/target/linux/realtek/files/drivers/char/rtl_nfbi/rtl_nfbi.h b/target/linux/realtek/files/drivers/char/rtl_nfbi/rtl_nfbi.h
new file mode 100644
index 000000000..076d8abb4
--- /dev/null
+++ b/target/linux/realtek/files/drivers/char/rtl_nfbi/rtl_nfbi.h
@@ -0,0 +1,295 @@
+#ifndef _RTL_NFBI_H_
+#define _RTL_NFBI_H_
+
+/*================================================================*/
+/* Compiling Flags */
+//#define HOST_IS_PANABOARD
+//#define SIMULATION // defined to do simuation
+#define MDCIO_GPIO_SIMULATION
+#define NFBI_CMD_HANDSHAKE_POLLING_DEFAULT 1 //use polling method for command handshake
+
+/* Constant Definitions */
+#define DRIVER_NAME "rtl_nfbi"
+#define DRIVER_VER "0.2"
+#define IO_LEN 0x40
+#define DRIVER_MAJOR 14
+#define NFBI_BUFSIZE 516 //2 + 2 + 2*255 + 2
+#define EV_QUE_MAX 128
+#if 1
+#define NFBI_POLLING_INTERVAL_DEFAULT 4 //40 ms, in jiffies(10 ms)
+//#define CMD_TIME_OUT 20 // timeout between each cmd word in jiffies
+#define NFBI_INTERRUPT_TIMEOUT_DEFAULT 10 //in jiffies(10 ms)
+#define NFBI_RESPONSE_TIMEOUT_DEFAULT 300 //in jiffies(10 ms)
+#define NFBI_RETRANSMIT_COUNT_DEFAULT 2
+#else
+//#define CMD_TIME_OUT 60000 // timeout between each cmd word in jiffies
+#define NFBI_INTERRUPT_TIMEOUT_DEFAULT 6000
+#define NFBI_RESPONSE_TIMEOUT_DEFAULT 6000
+#define NFBI_RETRANSMIT_COUNT_DEFAULT 0
+#endif
+
+#define BIT(x) (1 << (x))
+
+// RTL8197B NFBI Register offset
+#define NFBI_REG_BMCR 0x00 // Basic Mode Control Register
+#define NFBI_REG_BMSR 0x01 // Basic Mode Status Register
+#define NFBI_REG_PHYID1 0x02 // PHY Identifier Register 1
+#define NFBI_REG_PHYID2 0x03 // PHY Identifier Register 2
+#define NFBI_REG_ANAR 0x04 // Auto-Negotiation Advertisement Register
+#define NFBI_REG_ANLPAR 0x05 // Auto-Negotiation Link Partner Ability Register
+#define NFBI_REG_CMD 0x10 // Command Register
+#define NFBI_REG_ADDH 0x11 // Address High Register
+#define NFBI_REG_ADDL 0x12 // Address Low Register
+#define NFBI_REG_DH 0x13 // Data High Register
+#define NFBI_REG_DL 0x14 // Dta Low Register
+#define NFBI_REG_SCR 0x15 // Send Command Register
+#define NFBI_REG_RSR 0x16 // Receive Status Register
+#define NFBI_REG_SYSSR 0x17 // System Status Register
+#define NFBI_REG_SYSCR 0x18 // System Control Register
+#define NFBI_REG_IMR 0x19 // Interrupt Mask Register
+#define NFBI_REG_ISR 0x1a // Interrupt Status Register
+#define NFBI_REG_DCH 0x1b // DRAM Configuration High Register
+#define NFBI_REG_DCL 0x1c // DRAM Configuration Low Register
+#define NFBI_REG_DTH 0x1d // DRAM Timing High Register
+#define NFBI_REG_DTL 0x1e // DRAM Timing Low Register
+#define NFBI_REG_RR 0x1f // reserved register
+
+// Default value
+#define NFBI_REG_PHYID1_DEFAULT 0x001c // Default value of PHY Identifier Register 1
+#define NFBI_REG_PHYID2_DEFAULT 0xcb61 // Default value of PHY Identifier Register 2
+#define NFBI_REG_PHYID2_DEFAULT2 0xcb81 // Default value of PHY Identifier Register 2
+
+// bitmask definition for CMD (0x10)
+#define BM_CMDTYPE BIT(15) // Command Type
+#define BM_BUSY BIT(14) // Status of NFBI hardware
+#define BM_INTLEVEL BIT(2) // Select interrupt level
+#define BM_SYSTEMRST BIT(1)
+#define BM_START_RUN_BOOTCODE BIT(0)
+
+// bitmask definition for SYSSR (0x17)
+#define BM_CHECKSUM_DONE BIT(15)
+#define BM_CHECKSUM_OK BIT(14)
+#define BM_WLANLINK BIT(13)
+#define BM_ETHLINK BIT(12)
+#define BM_ETHPHY_STATUS_CHANGE BIT(11)
+#define BM_ALLSOFTWARE_READY BIT(10)
+#define BM_USBInsertStatus BIT(7)
+#define BM_USBRemoveStatus BIT(6)
+#define BM_BOOTCODE_READY BIT(5)
+
+// bitmask definition for SYSCR (0x18)
+#define BM_ISOLATION BIT(15) // ISOLATION Interrupt Pending
+#define BM_ETHMAC BIT(14) // Enable/disable Ethernet MAC
+#define BM_WLANMAC BIT(13) // Enable/disable WLAN MAC
+#define BM_ETHPHY BIT(12) // Enable/disable Ethernet PHY
+#define BM_WLANPHY BIT(11) // Enable/disable WLAN PHY
+#define BM_SELMIICLK BIT(10) // Select MII Clock Speed
+#define BM_RSVD9 BIT(9) // Reserved
+#define BM_CUSTOM8 BIT(8) // Customized used 8
+#define BM_CUSTOM7 BIT(7) // Customized used 7
+#define BM_CUSTOM6 BIT(6) // Customized used 6
+#define BM_CUSTOM5 BIT(5) // Customized used 5
+#define BM_CUSTOM4 BIT(4) // Customized used 4
+#define BM_CUSTOM3 BIT(3) // Customized used 3
+#define BM_CUSTOM2 BIT(2) // Previous msg has been fetched
+#define BM_CUSTOM1 BIT(1) // New msg has come
+#define BM_CUSTOM0 BIT(0) // Reserved
+
+// bitmask definition for IMR (0x19)
+#define IM_CHECKSUM_DONE BIT(15)
+#define IM_CHECKSUM_OK BIT(14)
+#define IM_WLANLINK BIT(13)
+#define IM_ETHLINK BIT(12)
+#define IM_ETHPHY_STATUS_CHANGE BIT(11)
+#define IM_ALLSOFTWARE_READY BIT(10)
+#define IM_USBInsertStatus BIT(7)
+#define IM_USBRemoveStatus BIT(6)
+#define IM_BOOTCODE_READY BIT(5)
+#define IM_PREVMSG_FETCH BIT(2)
+#define IM_NEWMSG_COMING BIT(1)
+#define IM_NEED_BOOTCODE BIT(0)
+
+// bitmask definition for ISR (0x1a)
+#define IP_CHECKSUM_DONE BIT(15)
+#define IP_CHECKSUM_OK BIT(14)
+#define IP_WLANLINK BIT(13)
+#define IP_ETHLINK BIT(12)
+#define IP_ETHPHY_STATUS_CHANGE BIT(11)
+#define IP_ALLSOFTWARE_READY BIT(10)
+#define IP_USBInsertStatus BIT(7)
+#define IP_USBRemoveStatus BIT(6)
+#define IP_BOOTCODE_READY BIT(5)
+#define IP_PREVMSG_FETCH BIT(2) // Previous msg has been fetched
+#define IP_NEWMSG_COMING BIT(1) // New msg has coming
+#define IP_NEED_BOOTCODE BIT(0)
+
+/*
+ * Ioctl definitions
+ */
+/* Use 'k' as magic number */
+#define NFBI_IOC_MAGIC 'k' /* @Pana_TBD */
+
+struct nfbi_mem32_param
+{
+ int addr;
+ int val;
+};
+
+#define NFBI_MAX_BULK_MEM_SIZE 512
+struct nfbi_bulk_mem_param
+{
+ int addr;
+ int len;
+ char buf[NFBI_MAX_BULK_MEM_SIZE];
+};
+
+struct evt_msg {
+ int id; // event id
+ int status;
+ int value;
+};
+
+#define NFBI_IOCTL_PRIV_CMD _IOW(NFBI_IOC_MAGIC, 0, int) //private command
+#define NFBI_IOCTL_REGREAD _IOWR(NFBI_IOC_MAGIC, 1, int)
+#define NFBI_IOCTL_REGWRITE _IOW(NFBI_IOC_MAGIC, 2, int)
+#define NFBI_IOCTL_HCD_PID _IOW(NFBI_IOC_MAGIC, 3, int) //set host control deamon PID to driver
+#define NFBI_IOCTL_GET_EVENT _IOR(NFBI_IOC_MAGIC, 4, struct evt_msg)
+#define NFBI_IOCTL_MEM32_WRITE _IOW(NFBI_IOC_MAGIC, 5, struct nfbi_mem32_param)
+#define NFBI_IOCTL_MEM32_READ _IOWR(NFBI_IOC_MAGIC, 6, struct nfbi_mem32_param)
+#define NFBI_IOCTL_BULK_MEM_WRITE _IOW(NFBI_IOC_MAGIC, 7, struct nfbi_bulk_mem_param)
+#define NFBI_IOCTL_BULK_MEM_READ _IOWR(NFBI_IOC_MAGIC, 8, struct nfbi_bulk_mem_param)
+#define NFBI_IOCTL_TX_CMDWORD_INTERVAL _IOWR(NFBI_IOC_MAGIC, 9, int)
+#define NFBI_IOCTL_INTERRUPT_TIMEOUT _IOWR(NFBI_IOC_MAGIC, 10, int)
+#define NFBI_IOCTL_RETRANSMIT_COUNT _IOWR(NFBI_IOC_MAGIC, 11, int)
+#define NFBI_IOCTL_RESPONSE_TIMEOUT _IOWR(NFBI_IOC_MAGIC, 12, int)
+#define NFBI_IOCTL_MDIO_PHYAD _IOWR(NFBI_IOC_MAGIC, 13, int)
+#define NFBI_IOCTL_CMD_HANDSHAKE_POLLING _IOWR(NFBI_IOC_MAGIC, 14, int)
+#define NFBI_IOCTL_EW _IOW(NFBI_IOC_MAGIC, 15, struct nfbi_mem32_param)
+#define NFBI_IOCTL_DW _IOWR(NFBI_IOC_MAGIC, 16, struct nfbi_mem32_param)
+#define NFBI_IOCTL_MAXNR 16
+
+
+//#define DRAM_CONFIG_VAL 0x54480000 //default: 58080000 //32MB DRAM
+#define DRAM_CONFIG_VAL 0x52080000 //default: 58080000 //8MB DRAM
+//#define DRAM_TIMING_VAL 0xffff05c0 //default: FFFF0FC0
+#define DRAM_TIMING_VAL 0x6cea0a80
+#define DRAM_CONFIG_VALH ((DRAM_CONFIG_VAL>>16)&0x0000ffff)
+#define DRAM_CONFIG_VALL (DRAM_CONFIG_VAL&0x0000ffff)
+#define DRAM_TIMING_VALH ((DRAM_TIMING_VAL>>16)&0x0000ffff)
+#define DRAM_TIMING_VALL (DRAM_TIMING_VAL&0x0000ffff)
+
+#define NFBI_BOOTADDR 0x007f0000
+#define NFBI_KERNADDR 0x00700000
+
+#define CHECK_NFBI_BUSY_BIT
+
+#define NFBI_DEBUG
+#undef PDEBUG /* undef it, just in case */
+#ifdef NFBI_DEBUG
+#ifdef __KERNEL__
+ /* This one if debugging is on, and kernel space */
+//#define PDEBUG(fmt, args...) printk( KERN_DEBUG DRIVER_NAME": " fmt, ## args)
+#define PDEBUG(fmt, args...) printk( KERN_ERR DRIVER_NAME": " fmt, ## args)
+#else
+ /* This one for user space */
+//#define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+#define PDEBUG(fmt, args...) printf(fmt, ## args)
+#endif
+#else
+#define PDEBUG(fmt, args...) /* not debugging: nothing */
+#endif
+
+
+// rx cmd id bitmask
+#define FIRST_CMD_MASK BIT(15)
+
+// tx cmd state & rx status state
+enum { STATE_TX_INIT, STATE_TX_IN_PROGRESS, STATE_RX_INIT, STATE_RX_WAIT_LEN, STATE_RX_WAIT_DATA, STATE_RX_FINISHED };
+
+
+#define TIME_DIFF(a, b) ((a >= b)? (a - b):(0xffffffff - b + a + 1))
+
+#ifndef HOST_IS_PANABOARD
+#define PUT_IN_DATA(data) { \
+ memcpy(&priv->data_in.buf[priv->data_in.len], &data, 2); \
+ priv->data_in.len += 2; \
+}
+#else
+#define PUT_IN_DATA(data) { \
+ priv->data_in.buf[priv->data_in.len] = (char)( (data>>8)&0x00ff ); \
+ priv->data_in.buf[priv->data_in.len+1] = (char)( data&0x00ff ); \
+ priv->data_in.len += 2; \
+}
+#endif
+
+#define RESET_RX_STATE { \
+ priv->state = STATE_RX_INIT; \
+ priv->data_in.len = 0; \
+ priv->rx_status_time = 0; \
+}
+
+#define ASSERT(expr) \
+ if(!(expr)) { \
+ printk( "\033[33;41m%s:%d: assert(%s)\033[m\n", \
+ __FILE__,__LINE__,#expr); \
+ }
+
+/*================================================================*/
+/* Structure Definition */
+struct buf_ar {
+ int len;
+ unsigned char buf[NFBI_BUFSIZE];
+};
+
+#ifdef __KERNEL__
+struct nfbi_priv {
+ struct buf_ar data_out;
+ struct buf_ar data_in;
+ int state;
+ unsigned long rx_status_time;
+ int rx_status_remain_len;
+ int tx_cmd_transmitting_len;
+ int retransmit_count;
+ int response_timeout; //in jiffies(10 ms)
+};
+
+struct nfbi_dev_priv {
+ int ready;
+ int hcd_pid;
+ struct file *filp;
+ int tx_cmdword_interval; //in jiffies(10 ms), 0~1000
+ int tx_msg_is_fetched;
+ int rx_msg_is_coming;
+ //statistics
+ int tx_command_frames;
+ int tx_done_command_frames;
+ int tx_retransmit_counts;
+ int tx_words;
+ int tx_interupt_timeouts;
+ int tx_stop_by_signals;
+ int rx_status_frames;
+ int rx_words;
+ int rx_response_timeouts;
+ int rx_interupt_timeouts;
+ int rx_stop_by_signals;
+ int rx_not_1st_word_errors;
+ int rx_1st_byte_errors;
+ int rx_cmdid_not_match_errors;
+ int rx_reset_by_sync_bit_errors;
+ int rx_checksum_errors;
+
+ struct semaphore sem; /* mutual exclusion semaphore */
+ int cmd_handshake_polling;
+ wait_queue_head_t wq; /* wait queue */
+ struct timer_list timer;
+ int timer_expired; /*1-expired*/
+ int interrupt_timeout; //in jiffies(10 ms), 0~1000
+ int evt_que_head, evt_que_tail;
+ struct evt_msg ind_evt_que[EV_QUE_MAX];
+#ifdef MDCIO_GPIO_SIMULATION
+ struct timer_list mdc_timer;
+#endif
+};
+#endif
+
+#endif // _RTL_NFBI_H_