From c1e1d638ff5309184f514545cb0bd700088bc732 Mon Sep 17 00:00:00 2001 From: "bernard.xiong" Date: Thu, 19 Nov 2009 07:31:17 +0000 Subject: [PATCH] add dm9000a driver. git-svn-id: https://rt-thread.googlecode.com/svn/trunk@170 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- bsp/stm3210/dm9000a.c | 706 ++++++++++++++++++++++++++++++++++++++++++ bsp/stm3210/dm9000a.h | 148 +++++++++ 2 files changed, 854 insertions(+) create mode 100644 bsp/stm3210/dm9000a.c create mode 100644 bsp/stm3210/dm9000a.h diff --git a/bsp/stm3210/dm9000a.c b/bsp/stm3210/dm9000a.c new file mode 100644 index 0000000000..8b0f07b984 --- /dev/null +++ b/bsp/stm3210/dm9000a.c @@ -0,0 +1,706 @@ +#include +#include "dm9000.h" + +#include +#include "lwipopts.h" +#include "stm32f10x.h" + +// #define DM9000_DEBUG 1 +#if DM9000_DEBUG +#define DM9000_TRACE rt_kprintf +#else +#define DM9000_TRACE(...) +#endif + +/* + * DM9000 interrupt line is connected to PA1 + * 16bit mode + */ + +#define DM9000_PHY 0x40 /* PHY address 0x01 */ + +#define MAX_ADDR_LEN 6 +enum DM9000_PHY_mode +{ + DM9000_10MHD = 0, DM9000_100MHD = 1, + DM9000_10MFD = 4, DM9000_100MFD = 5, + DM9000_AUTO = 8, DM9000_1M_HPNA = 0x10 +}; + +enum DM9000_TYPE +{ + TYPE_DM9000E, + TYPE_DM9000A, + TYPE_DM9000B +}; + +struct rt_dm9000_eth +{ + /* inherit from ethernet device */ + struct eth_device parent; + + enum DM9000_TYPE type; + enum DM9000_PHY_mode mode; + + rt_uint8_t imr_all; + + rt_uint8_t packet_cnt; /* packet I or II */ + rt_uint16_t queue_packet_len; /* queued packet (packet II) */ + + /* interface address info. */ + rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */ +}; +static struct rt_dm9000_eth dm9000_device; +static struct rt_semaphore sem_ack, sem_lock; + +void rt_dm9000_isr(void); + +static void delay_ms(rt_uint32_t ms) +{ + rt_uint32_t len; + for (;ms > 0; ms --) + for (len = 0; len < 100; len++ ); +} + +/* Read a byte from I/O port */ +rt_inline rt_uint8_t dm9000_io_read(rt_uint16_t reg) +{ + DM9000_IO = reg; + return (rt_uint8_t) DM9000_DATA; +} + +/* Write a byte to I/O port */ +rt_inline void dm9000_io_write(rt_uint16_t reg, rt_uint16_t value) +{ + DM9000_IO = reg; + DM9000_DATA = value; +} + +/* Read a word from phyxcer */ +rt_inline rt_uint16_t phy_read(rt_uint16_t reg) +{ + rt_uint16_t val; + + /* Fill the phyxcer register into REG_0C */ + dm9000_io_write(DM9000_EPAR, DM9000_PHY | reg); + dm9000_io_write(DM9000_EPCR, 0xc); /* Issue phyxcer read command */ + + delay_ms(100); /* Wait read complete */ + + dm9000_io_write(DM9000_EPCR, 0x0); /* Clear phyxcer read command */ + val = (dm9000_io_read(DM9000_EPDRH) << 8) | dm9000_io_read(DM9000_EPDRL); + + return val; +} + +/* Write a word to phyxcer */ +rt_inline void phy_write(rt_uint16_t reg, rt_uint16_t value) +{ + /* Fill the phyxcer register into REG_0C */ + dm9000_io_write(DM9000_EPAR, DM9000_PHY | reg); + + /* Fill the written data into REG_0D & REG_0E */ + dm9000_io_write(DM9000_EPDRL, (value & 0xff)); + dm9000_io_write(DM9000_EPDRH, ((value >> 8) & 0xff)); + dm9000_io_write(DM9000_EPCR, 0xa); /* Issue phyxcer write command */ + + delay_ms(500); /* Wait write complete */ + + dm9000_io_write(DM9000_EPCR, 0x0); /* Clear phyxcer write command */ +} + +/* Set PHY operationg mode */ +rt_inline void phy_mode_set(rt_uint32_t media_mode) +{ + rt_uint16_t phy_reg4 = 0x01e1, phy_reg0 = 0x1000; + if (!(media_mode & DM9000_AUTO)) + { + switch (media_mode) + { + case DM9000_10MHD: + phy_reg4 = 0x21; + phy_reg0 = 0x0000; + break; + case DM9000_10MFD: + phy_reg4 = 0x41; + phy_reg0 = 0x1100; + break; + case DM9000_100MHD: + phy_reg4 = 0x81; + phy_reg0 = 0x2000; + break; + case DM9000_100MFD: + phy_reg4 = 0x101; + phy_reg0 = 0x3100; + break; + } + phy_write(4, phy_reg4); /* Set PHY media mode */ + phy_write(0, phy_reg0); /* Tmp */ + } + + dm9000_io_write(DM9000_GPCR, 0x01); /* Let GPIO0 output */ + dm9000_io_write(DM9000_GPR, 0x00); /* Enable PHY */ +} + +/* interrupt service routine */ +void rt_dm9000_isr() +{ + rt_uint16_t int_status; + rt_uint16_t last_io; + + last_io = DM9000_IO; + + /* Disable all interrupts */ + dm9000_io_write(DM9000_IMR, IMR_PAR); + + /* Got DM9000 interrupt status */ + int_status = dm9000_io_read(DM9000_ISR); /* Got ISR */ + dm9000_io_write(DM9000_ISR, int_status); /* Clear ISR status */ + + DM9000_TRACE("dm9000 isr: int status %04x\n", int_status); + + /* receive overflow */ + if (int_status & ISR_ROS) + { + rt_kprintf("overflow\n"); + } + + if (int_status & ISR_ROOS) + { + rt_kprintf("overflow counter overflow\n"); + } + + /* Received the coming packet */ + if (int_status & ISR_PRS) + { + rt_err_t result; + + /* a frame has been received */ + result = eth_device_ready(&(dm9000_device.parent)); + if (result != RT_EOK) rt_kprintf("eth notification failed\n"); + RT_ASSERT(result == RT_EOK); + } + + /* Transmit Interrupt check */ + if (int_status & ISR_PTS) + { + /* transmit done */ + int tx_status = dm9000_io_read(DM9000_NSR); /* Got TX status */ + + if (tx_status & (NSR_TX2END | NSR_TX1END)) + { + dm9000_device.packet_cnt --; + if (dm9000_device.packet_cnt > 0) + { + DM9000_TRACE("dm9000 isr: tx second packet\n"); + + /* transmit packet II */ + /* Set TX length to DM9000 */ + dm9000_io_write(DM9000_TXPLL, dm9000_device.queue_packet_len & 0xff); + dm9000_io_write(DM9000_TXPLH, (dm9000_device.queue_packet_len >> 8) & 0xff); + + /* Issue TX polling command */ + dm9000_io_write(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ + } + + /* One packet sent complete */ + rt_sem_release(&sem_ack); + } + } + + /* Re-enable interrupt mask */ + dm9000_io_write(DM9000_IMR, dm9000_device.imr_all); + + DM9000_IO = last_io; +} + +/* RT-Thread Device Interface */ +/* initialize the interface */ +static rt_err_t rt_dm9000_init(rt_device_t dev) +{ + int i, oft, lnk; + rt_uint32_t value; + + /* RESET device */ + dm9000_io_write(DM9000_NCR, NCR_RST); + delay_ms(1000); /* delay 1ms */ + + /* identfy DM9000 */ + value = dm9000_io_read(DM9000_VIDL); + value |= dm9000_io_read(DM9000_VIDH) << 8; + value |= dm9000_io_read(DM9000_PIDL) << 16; + value |= dm9000_io_read(DM9000_PIDH) << 24; + if (value == DM9000_ID) + { + rt_kprintf("dm9000 id: 0x%x\n", value); + } + else + { + return -RT_ERROR; + } + + /* GPIO0 on pre-activate PHY */ + dm9000_io_write(DM9000_GPR, 0x00); /* REG_1F bit0 activate phyxcer */ + dm9000_io_write(DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ + dm9000_io_write(DM9000_GPR, 0x00); /* Enable PHY */ + + /* Set PHY */ + phy_mode_set(dm9000_device.mode); + + /* Program operating register */ + dm9000_io_write(DM9000_NCR, 0x0); /* only intern phy supported by now */ + dm9000_io_write(DM9000_TCR, 0); /* TX Polling clear */ + dm9000_io_write(DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */ + dm9000_io_write(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8)); /* Flow Control : High/Low Water */ + dm9000_io_write(DM9000_FCR, 0x0); /* SH FIXME: This looks strange! Flow Control */ + dm9000_io_write(DM9000_SMCR, 0); /* Special Mode */ + dm9000_io_write(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); /* clear TX status */ + dm9000_io_write(DM9000_ISR, 0x0f); /* Clear interrupt status */ + dm9000_io_write(DM9000_TCR2, 0x80); /* Switch LED to mode 1 */ + + /* set mac address */ + for (i = 0, oft = 0x10; i < 6; i++, oft++) + dm9000_io_write(oft, dm9000_device.dev_addr[i]); + /* set multicast address */ + for (i = 0, oft = 0x16; i < 8; i++, oft++) + dm9000_io_write(oft, 0xff); + + /* Activate DM9000 */ + dm9000_io_write(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); /* RX enable */ + dm9000_io_write(DM9000_IMR, IMR_PAR); + + if (dm9000_device.mode == DM9000_AUTO) + { + while (!(phy_read(1) & 0x20)) + { + /* autonegation complete bit */ + delay_ms(10); + i++; + if (i == 10000) + { + rt_kprintf("could not establish link\n"); + return 0; + } + } + } + + /* see what we've got */ + lnk = phy_read(17) >> 12; + rt_kprintf("operating at "); + switch (lnk) + { + case 1: + rt_kprintf("10M half duplex "); + break; + case 2: + rt_kprintf("10M full duplex "); + break; + case 4: + rt_kprintf("100M half duplex "); + break; + case 8: + rt_kprintf("100M full duplex "); + break; + default: + rt_kprintf("unknown: %d ", lnk); + break; + } + rt_kprintf("mode\n"); + + dm9000_io_write(DM9000_IMR, dm9000_device.imr_all); /* Enable TX/RX interrupt mask */ + + return RT_EOK; +} + +static rt_err_t rt_dm9000_open(rt_device_t dev, rt_uint16_t oflag) +{ + return RT_EOK; +} + +static rt_err_t rt_dm9000_close(rt_device_t dev) +{ + /* RESET devie */ + phy_write(0, 0x8000); /* PHY RESET */ + dm9000_io_write(DM9000_GPR, 0x01); /* Power-Down PHY */ + dm9000_io_write(DM9000_IMR, 0x80); /* Disable all interrupt */ + dm9000_io_write(DM9000_RCR, 0x00); /* Disable RX */ + + return RT_EOK; +} + +static rt_size_t rt_dm9000_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + +static rt_size_t rt_dm9000_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + +static rt_err_t rt_dm9000_control(rt_device_t dev, rt_uint8_t cmd, void *args) +{ + switch (cmd) + { + case NIOCTL_GADDR: + /* get mac address */ + if (args) rt_memcpy(args, dm9000_device.dev_addr, 6); + else return -RT_ERROR; + break; + + default : + break; + } + + return RT_EOK; +} + +/* ethernet device interface */ +/* transmit packet. */ +rt_err_t rt_dm9000_tx( rt_device_t dev, struct pbuf* p) +{ + struct pbuf* q; + rt_int32_t len; + rt_uint16_t* ptr; + +#if DM9000_DEBUG + rt_uint8_t* dump_ptr; + rt_uint32_t cnt = 0; +#endif + + DM9000_TRACE("dm9000 tx: %d\n", p->tot_len); + + /* lock DM9000 device */ + rt_sem_take(&sem_lock, RT_WAITING_FOREVER); + + /* disable dm9000a interrupt */ + dm9000_io_write(DM9000_IMR, IMR_PAR); + + /* Move data to DM9000 TX RAM */ + DM9000_outb(DM9000_IO_BASE, DM9000_MWCMD); + + for (q = p; q != NULL; q = q->next) + { + len = q->len; + ptr = q->payload; + +#if DM9000_DEBUG + dump_ptr = q->payload; +#endif + + /* use 16bit mode to write data to DM9000 RAM */ + while (len > 0) + { + DM9000_outw(DM9000_DATA_BASE, *ptr); + ptr ++; + len -= 2; + +#ifdef DM9000_DEBUG + DM9000_TRACE("%02x ", *dump_ptr++); + if (++cnt % 16 == 0) DM9000_TRACE("\n"); +#endif + } + } + DM9000_TRACE("\n"); + + if (dm9000_device.packet_cnt == 0) + { + DM9000_TRACE("dm9000 tx: first packet\n"); + + dm9000_device.packet_cnt ++; + /* Set TX length to DM9000 */ + dm9000_io_write(DM9000_TXPLL, p->tot_len & 0xff); + dm9000_io_write(DM9000_TXPLH, (p->tot_len >> 8) & 0xff); + + /* Issue TX polling command */ + dm9000_io_write(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ + } + else + { + DM9000_TRACE("dm9000 tx: second packet\n"); + + dm9000_device.packet_cnt ++; + dm9000_device.queue_packet_len = p->tot_len; + } + + /* enable dm9000a interrupt */ + dm9000_io_write(DM9000_IMR, dm9000_device.imr_all); + + /* unlock DM9000 device */ + rt_sem_release(&sem_lock); + + /* wait ack */ + rt_sem_take(&sem_ack, RT_WAITING_FOREVER); + + DM9000_TRACE("dm9000 tx done\n"); + + return RT_EOK; +} + +/* reception packet. */ +struct pbuf *rt_dm9000_rx(rt_device_t dev) +{ + struct pbuf* p; + rt_uint32_t rxbyte; + +#if DM9000_DEBUG + rt_uint8_t* dump_ptr; + rt_uint32_t cnt = 0; +#endif + + /* init p pointer */ + p = RT_NULL; + + /* lock DM9000 device */ + rt_sem_take(&sem_lock, RT_WAITING_FOREVER); + + /* Check packet ready or not */ + dm9000_io_read(DM9000_MRCMDX); /* Dummy read */ + rxbyte = DM9000_inb(DM9000_DATA_BASE); /* Got most updated data */ + if (rxbyte) + { + rt_uint16_t rx_status, rx_len; + rt_uint16_t* data; + + if (rxbyte > 1) + { + DM9000_TRACE("dm9000 rx: rx error, stop device\n"); + + dm9000_io_write(DM9000_RCR, 0x00); /* Stop Device */ + dm9000_io_write(DM9000_ISR, 0x80); /* Stop INT request */ + } + + /* A packet ready now & Get status/length */ + DM9000_outb(DM9000_IO_BASE, DM9000_MRCMD); + + rx_status = DM9000_inw(DM9000_DATA_BASE); + rx_len = DM9000_inw(DM9000_DATA_BASE); + + DM9000_TRACE("dm9000 rx: status %04x len %d\n", rx_status, rx_len); + + /* allocate buffer */ + p = pbuf_alloc(PBUF_LINK, rx_len, PBUF_RAM); + if (p != RT_NULL) + { + struct pbuf* q; + rt_int32_t len; + + for (q = p; q != RT_NULL; q= q->next) + { + data = (rt_uint16_t*)q->payload; + len = q->len; + +#if DM9000_DEBUG + dump_ptr = q->payload; +#endif + + while (len > 0) + { + *data = DM9000_inw(DM9000_DATA_BASE); + data ++; + len -= 2; + +#if DM9000_DEBUG + DM9000_TRACE("%02x ", *dump_ptr++); + if (++cnt % 16 == 0) DM9000_TRACE("\n"); +#endif + } + } + DM9000_TRACE("\n"); + } + else + { + rt_uint16_t dummy; + + DM9000_TRACE("dm9000 rx: no pbuf\n"); + + /* no pbuf, discard data from DM9000 */ + data = &dummy; + while (rx_len) + { + *data = DM9000_inw(DM9000_DATA_BASE); + rx_len -= 2; + } + } + + if ((rx_status & 0xbf00) || (rx_len < 0x40) + || (rx_len > DM9000_PKT_MAX)) + { + rt_kprintf("rx error: status %04x\n", rx_status); + + if (rx_status & 0x100) + { + rt_kprintf("rx fifo error\n"); + } + if (rx_status & 0x200) + { + rt_kprintf("rx crc error\n"); + } + if (rx_status & 0x8000) + { + rt_kprintf("rx length error\n"); + } + if (rx_len > DM9000_PKT_MAX) + { + rt_kprintf("rx length too big\n"); + + /* RESET device */ + dm9000_io_write(DM9000_NCR, NCR_RST); + rt_thread_delay(1); /* delay 5ms */ + } + + /* it issues an error, release pbuf */ + pbuf_free(p); + p = RT_NULL; + } + } + + /* unlock DM9000 device */ + rt_sem_release(&sem_lock); + + return p; +} + + +static void RCC_Configuration(void) +{ + /* enable gpiob port clock */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); +} + +static void NVIC_Configuration(void) +{ + NVIC_InitTypeDef NVIC_InitStructure; + + /* Configure one bit for preemption priority */ + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); + + /* Enable the EXTI0 Interrupt */ + NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +} + +static void GPIO_Configuration() +{ + GPIO_InitTypeDef GPIO_InitStructure; + EXTI_InitTypeDef EXTI_InitStructure; + + /* configure PA1 as external interrupt */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Connect DM9000 EXTI Line to GPIOA Pin 1 */ + GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1); + + /* Configure DM9000 EXTI Line to generate an interrupt on falling edge */ + EXTI_InitStructure.EXTI_Line = EXTI_Line1; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + /* Clear the Key Button EXTI line pending bit */ + EXTI_ClearITPendingBit(EXTI_Line1); +} + +void rt_hw_dm9000_init() +{ + RCC_Configuration(); + NVIC_Configuration(); + GPIO_Configuration(); + + rt_sem_init(&sem_ack, "tx_ack", 1, RT_IPC_FLAG_FIFO); + rt_sem_init(&sem_lock, "eth_lock", 1, RT_IPC_FLAG_FIFO); + + dm9000_device.type = TYPE_DM9000A; + dm9000_device.mode = DM9000_AUTO; + dm9000_device.packet_cnt = 0; + dm9000_device.queue_packet_len = 0; + + /* + * SRAM Tx/Rx pointer automatically return to start address, + * Packet Transmitted, Packet Received + */ + dm9000_device.imr_all = IMR_PAR | IMR_PTM | IMR_PRM; + + dm9000_device.dev_addr[0] = 0x01; + dm9000_device.dev_addr[1] = 0x60; + dm9000_device.dev_addr[2] = 0x6E; + dm9000_device.dev_addr[3] = 0x11; + dm9000_device.dev_addr[4] = 0x02; + dm9000_device.dev_addr[5] = 0x0F; + + dm9000_device.parent.parent.init = rt_dm9000_init; + dm9000_device.parent.parent.open = rt_dm9000_open; + dm9000_device.parent.parent.close = rt_dm9000_close; + dm9000_device.parent.parent.read = rt_dm9000_read; + dm9000_device.parent.parent.write = rt_dm9000_write; + dm9000_device.parent.parent.control = rt_dm9000_control; + dm9000_device.parent.parent.private = RT_NULL; + + dm9000_device.parent.eth_rx = rt_dm9000_rx; + dm9000_device.parent.eth_tx = rt_dm9000_tx; + + eth_device_init(&(dm9000_device.parent), "e0"); +} + +#ifdef RT_USING_FINSH +#include +void dm9000(void) +{ + rt_kprintf("\n"); + rt_kprintf("NCR (0x00): %02x\n", dm9000_io_read(DM9000_NCR)); + rt_kprintf("NSR (0x01): %02x\n", dm9000_io_read(DM9000_NSR)); + rt_kprintf("TCR (0x02): %02x\n", dm9000_io_read(DM9000_TCR)); + rt_kprintf("TSRI (0x03): %02x\n", dm9000_io_read(DM9000_TSR1)); + rt_kprintf("TSRII (0x04): %02x\n", dm9000_io_read(DM9000_TSR2)); + rt_kprintf("RCR (0x05): %02x\n", dm9000_io_read(DM9000_RCR)); + rt_kprintf("RSR (0x06): %02x\n", dm9000_io_read(DM9000_RSR)); + rt_kprintf("ORCR (0x07): %02x\n", dm9000_io_read(DM9000_ROCR)); + rt_kprintf("CRR (0x2C): %02x\n", dm9000_io_read(DM9000_CHIPR)); + rt_kprintf("CSCR (0x31): %02x\n", dm9000_io_read(DM9000_CSCR)); + rt_kprintf("RCSSR (0x32): %02x\n", dm9000_io_read(DM9000_RCSSR)); + rt_kprintf("ISR (0xFE): %02x\n", dm9000_io_read(DM9000_ISR)); + rt_kprintf("IMR (0xFF): %02x\n", dm9000_io_read(DM9000_IMR)); + rt_kprintf("\n"); +} +FINSH_FUNCTION_EXPORT(dm9000, dm9000 register dump); + +void rx(void) +{ + rt_err_t result; + + dm9000_io_write(DM9000_ISR, ISR_PRS); /* Clear rx status */ + + /* a frame has been received */ + result = eth_device_ready(&(dm9000_device.parent)); + if (result != RT_EOK) rt_kprintf("eth notification failed\n"); + RT_ASSERT(result == RT_EOK); +} +FINSH_FUNCTION_EXPORT(rx, notify packet rx); + +#endif + +void EXTI1_IRQHandler(void) +{ + extern void rt_dm9000_isr(void); + + /* enter interrupt */ + rt_interrupt_enter(); + + rt_dm9000_isr(); + + /* Clear the Key Button EXTI line pending bit */ + EXTI_ClearITPendingBit(EXTI_Line1); + + /* leave interrupt */ + rt_interrupt_leave(); + rt_hw_interrupt_thread_switch(); +} diff --git a/bsp/stm3210/dm9000a.h b/bsp/stm3210/dm9000a.h new file mode 100644 index 0000000000..1b78d156a9 --- /dev/null +++ b/bsp/stm3210/dm9000a.h @@ -0,0 +1,148 @@ +#ifndef __DM9000_H__ +#define __DM9000_H__ + +#define DM9000_IO_BASE 0x6C100000 +#define DM9000_DATA_BASE 0x6C100008 + +#define DM9000_IO (*((volatile rt_uint16_t *) DM9000_IO_BASE)) // CMD = 0 +#define DM9000_DATA (*((volatile rt_uint16_t *) DM9000_DATA_BASE)) // CMD = 1 + +#define DM9000_inb(r) (*(volatile rt_uint8_t *)r) +#define DM9000_outb(r, d) (*(volatile rt_uint8_t *)r = d) +#define DM9000_inw(r) (*(volatile rt_uint16_t *)r) +#define DM9000_outw(r, d) (*(volatile rt_uint16_t *)r = d) + +#define DM9000_ID 0x90000A46 /* DM9000 ID */ +#define DM9000_PKT_MAX 1536 /* Received packet max size */ +#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ + +#define DM9000_NCR 0x00 +#define DM9000_NSR 0x01 +#define DM9000_TCR 0x02 +#define DM9000_TSR1 0x03 +#define DM9000_TSR2 0x04 +#define DM9000_RCR 0x05 +#define DM9000_RSR 0x06 +#define DM9000_ROCR 0x07 +#define DM9000_BPTR 0x08 +#define DM9000_FCTR 0x09 +#define DM9000_FCR 0x0A +#define DM9000_EPCR 0x0B +#define DM9000_EPAR 0x0C +#define DM9000_EPDRL 0x0D +#define DM9000_EPDRH 0x0E +#define DM9000_WCR 0x0F + +#define DM9000_PAR 0x10 +#define DM9000_MAR 0x16 + +#define DM9000_GPCR 0x1e +#define DM9000_GPR 0x1f +#define DM9000_TRPAL 0x22 +#define DM9000_TRPAH 0x23 +#define DM9000_RWPAL 0x24 +#define DM9000_RWPAH 0x25 + +#define DM9000_VIDL 0x28 +#define DM9000_VIDH 0x29 +#define DM9000_PIDL 0x2A +#define DM9000_PIDH 0x2B + +#define DM9000_CHIPR 0x2C +#define DM9000_TCR2 0x2D +#define DM9000_OTCR 0x2E +#define DM9000_SMCR 0x2F + +#define DM9000_ETCR 0x30 /* early transmit control/status register */ +#define DM9000_CSCR 0x31 /* check sum control register */ +#define DM9000_RCSSR 0x32 /* receive check sum status register */ + +#define DM9000_MRCMDX 0xF0 +#define DM9000_MRCMD 0xF2 +#define DM9000_MRRL 0xF4 +#define DM9000_MRRH 0xF5 +#define DM9000_MWCMDX 0xF6 +#define DM9000_MWCMD 0xF8 +#define DM9000_MWRL 0xFA +#define DM9000_MWRH 0xFB +#define DM9000_TXPLL 0xFC +#define DM9000_TXPLH 0xFD +#define DM9000_ISR 0xFE +#define DM9000_IMR 0xFF + +#define CHIPR_DM9000A 0x19 +#define CHIPR_DM9000B 0x1B + +#define NCR_EXT_PHY (1<<7) +#define NCR_WAKEEN (1<<6) +#define NCR_FCOL (1<<4) +#define NCR_FDX (1<<3) +#define NCR_LBK (3<<1) +#define NCR_RST (1<<0) + +#define NSR_SPEED (1<<7) +#define NSR_LINKST (1<<6) +#define NSR_WAKEST (1<<5) +#define NSR_TX2END (1<<3) +#define NSR_TX1END (1<<2) +#define NSR_RXOV (1<<1) + +#define TCR_TJDIS (1<<6) +#define TCR_EXCECM (1<<5) +#define TCR_PAD_DIS2 (1<<4) +#define TCR_CRC_DIS2 (1<<3) +#define TCR_PAD_DIS1 (1<<2) +#define TCR_CRC_DIS1 (1<<1) +#define TCR_TXREQ (1<<0) + +#define TSR_TJTO (1<<7) +#define TSR_LC (1<<6) +#define TSR_NC (1<<5) +#define TSR_LCOL (1<<4) +#define TSR_COL (1<<3) +#define TSR_EC (1<<2) + +#define RCR_WTDIS (1<<6) +#define RCR_DIS_LONG (1<<5) +#define RCR_DIS_CRC (1<<4) +#define RCR_ALL (1<<3) +#define RCR_RUNT (1<<2) +#define RCR_PRMSC (1<<1) +#define RCR_RXEN (1<<0) + +#define RSR_RF (1<<7) +#define RSR_MF (1<<6) +#define RSR_LCS (1<<5) +#define RSR_RWTO (1<<4) +#define RSR_PLE (1<<3) +#define RSR_AE (1<<2) +#define RSR_CE (1<<1) +#define RSR_FOE (1<<0) + +#define FCTR_HWOT(ot) (( ot & 0xf ) << 4 ) +#define FCTR_LWOT(ot) ( ot & 0xf ) + +#define IMR_PAR (1<<7) +#define IMR_ROOM (1<<3) +#define IMR_ROM (1<<2) +#define IMR_PTM (1<<1) +#define IMR_PRM (1<<0) + +#define ISR_ROOS (1<<3) +#define ISR_ROS (1<<2) +#define ISR_PTS (1<<1) +#define ISR_PRS (1<<0) +#define ISR_CLR_STATUS (ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS) + +#define EPCR_REEP (1<<5) +#define EPCR_WEP (1<<4) +#define EPCR_EPOS (1<<3) +#define EPCR_ERPRR (1<<2) +#define EPCR_ERPRW (1<<1) +#define EPCR_ERRE (1<<0) + +#define GPCR_GEP_CNTL (1<<0) + +void rt_hw_dm9000_init(void); + +#endif