diff --git a/distrib/sets/lists/minix/md.evbarm b/distrib/sets/lists/minix/md.evbarm index 70d70eaa9..bf52cea7c 100644 --- a/distrib/sets/lists/minix/md.evbarm +++ b/distrib/sets/lists/minix/md.evbarm @@ -4,6 +4,7 @@ ./boot/minix/.temp/mod10_vm minix-sys ./boot/minix/.temp/mod11_pfs minix-sys ./boot/minix/.temp/mod12_init minix-sys +./etc/system.conf.d/lan8710a minix-sys ./multiboot/mod07_log minix-sys ./multiboot/mod08_tty minix-sys ./multiboot/mod09_mfs minix-sys @@ -108,6 +109,7 @@ ./usr/sbin/fb minix-sys ./usr/sbin/gpio minix-sys ./usr/sbin/i2c minix-sys +./usr/sbin/lan8710a minix-sys ./usr/sbin/random minix-sys ./usr/sbin/tda19988 minix-sys ./usr/tests/minix-posix/mod minix-sys diff --git a/drivers/Makefile b/drivers/Makefile index 3a5e7c353..105310285 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -23,7 +23,7 @@ SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \ .endif .if ${MACHINE_ARCH} == "earm" -SUBDIR= cat24c256 fb gpio i2c mmc log tda19988 tty random +SUBDIR= cat24c256 fb gpio i2c mmc log tda19988 tty random lan8710a .endif .endif # ${MKIMAGEONLY} != "yes" diff --git a/drivers/lan8710a/Makefile b/drivers/lan8710a/Makefile new file mode 100644 index 000000000..8e5a932cf --- /dev/null +++ b/drivers/lan8710a/Makefile @@ -0,0 +1,16 @@ +# Makefile for the lan8710a ethernet driver. +PROG= lan8710a +SRCS= lan8710a.c + +FILES=$(PROG).conf +FILESNAME=$(PROG) +FILESDIR= /etc/system.conf.d + +DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} +LDADD+= -lnetdriver -lsys -ltimers + +MAN= + +BINDIR?= /usr/sbin + +.include \ No newline at end of file diff --git a/drivers/lan8710a/README.txt b/drivers/lan8710a/README.txt new file mode 100644 index 000000000..6b6e6e990 --- /dev/null +++ b/drivers/lan8710a/README.txt @@ -0,0 +1,41 @@ +-------------------------------------------------------------------------------- +* INFORMATION: * +-------------------------------------------------------------------------------- +README file for the LAN8710A ethernet board driver for BeagleBone Rev. A6a + +created July 2013, JPEmbedded (info@jpembedded.eu) + +-------------------------------------------------------------------------------- +* INSTALLATION: * +-------------------------------------------------------------------------------- +To install LAN8710A for BeagleBone under MINIX you have to edit /etc/inet.conf +by adding line: +eth0 lan8710a 0 { default; }; +and changing: +psip0 { default; }; +to: +psip1; +Restart the system and the driver should work. + +-------------------------------------------------------------------------------- +* TESTS: * +-------------------------------------------------------------------------------- +Driver was tested using various tools, i. e. +* fetch - downloading file from the Internet and also local server. Every file + downloaded well, but speed was about 50-200 kB/s. +* ftp - downloading and uploading 20 MB file completed. +* ping - checking connection between BeagleBone and computer passed using stan - + dard settings, when we set ping requests interval to 200 ms it also + passed. But with 20 ms and 2 ms driver dropped some packets (20 ms - + about 20% loss, 2 ms - 50% loss). +* udpstat, hostaddr, dhcpd, ifconfig, arp gave proper results. +Tests passed, so driver meets the requirements of ethernet driver. + +-------------------------------------------------------------------------------- +* LIMITATION: * +-------------------------------------------------------------------------------- +Download speed: 50-200 kB/s +Low bandwidth is probably caused by memory copy functions. Standard Linux driver +copies packets data directly to destination buffer using DMA. Minix driver needs +to do a safe copy (sys_safecopyfrom and sys_safecopyto) from local buffer to the +system buffer. This operation slows down the whole driver. diff --git a/drivers/lan8710a/lan8710a.c b/drivers/lan8710a/lan8710a.c new file mode 100644 index 000000000..506236f15 --- /dev/null +++ b/drivers/lan8710a/lan8710a.c @@ -0,0 +1,1249 @@ +#include +#include +#include +#include +#include +#include "assert.h" +#include "lan8710a.h" +#include "lan8710a_reg.h" + +/* Local functions */ +#ifdef AM335X +static void lan8710a_readv_s(message *m, int from_int); +static void lan8710a_writev_s(message *m, int from_int); +static void lan8710a_conf(message *m); +static void lan8710a_getstat(message *m); + +static void lan8710a_init(void); +static void lan8710a_enable_interrupt(int interrupt); +static void lan8710a_interrupt(message *m); +static void lan8710a_map_regs(void); +static void lan8710a_stop(void); +static void lan8710a_dma_config_tx(u8_t desc_idx); +static void lan8710a_dma_reset_init(void); +static void lan8710a_init_addr(void); +static void lan8710a_init_desc(void); +static void lan8710a_init_mdio(void); +static int lan8710a_init_hw(void); +static void lan8710a_reset_hw(); + +static void lan8710a_phy_write(u32_t reg, u32_t value); +static u32_t lan8710a_phy_read(u32_t reg); + +static u32_t lan8710a_reg_read(volatile u32_t *reg); +static void lan8710a_reg_write(volatile u32_t *reg, u32_t value); +static void lan8710a_reg_set(volatile u32_t *reg, u32_t value); +static void lan8710a_reg_unset(volatile u32_t *reg, u32_t value); + +static void mess_reply(message *req, message *reply); +static void reply(lan8710a_t *e); + +/* Local variables */ +static lan8710a_t lan8710a_state; + +/* SEF functions and variables. */ +static void sef_local_startup(void); +static int sef_cb_init_fresh(int type, sef_init_info_t *info); +static void sef_cb_signal_handler(int signal); +#endif /* AM335X */ + +/*============================================================================* + * main * + *============================================================================*/ +int +main(int argc, char *argv[]) +{ +#ifdef AM335X + /* Local variables */ + message m; + int r; + int ipc_status; + static int rx_first_enabled = FALSE; + + /* SEF local startup */ + env_setargs(argc, argv); + sef_local_startup(); + + /* Main driver loop */ + for (;;) { + r = netdriver_receive(ANY, &m, &ipc_status); + if (r != OK) { + panic("netdriver_receive failed: %d", r); + } + + if (is_ipc_notify(ipc_status)) { + switch (_ENDPOINT_P(m.m_source)) { + case HARDWARE: + lan8710a_interrupt(&m); + break; + } + } else { + switch (m.m_type) { + case DL_WRITEV_S: + lan8710a_writev_s(&m, FALSE); + break; + case DL_READV_S: + lan8710a_readv_s(&m, FALSE); + break; + case DL_CONF: + lan8710a_conf(&m); + break; + case DL_GETSTAT_S: + lan8710a_getstat(&m); + /* + * Workaround: + * Re-enabling interrupts here is made to avoid + * problem that Rx interrupt came when it can't + * be handled. When this problem occurs next Rx + * interrupts don't appear. + */ + if(rx_first_enabled == FALSE) { + rx_first_enabled = TRUE; + lan8710a_enable_interrupt(RX_INT | + TX_INT); + } + break; + default: + panic("Illegal message: %d", m.m_type); + } + } + } +#endif /* AM335X */ + return EXIT_SUCCESS; +} +#ifdef AM335X +/*============================================================================* + * sef_local_startup * + *============================================================================*/ +static void +sef_local_startup() +{ + /* Register init callbacks. */ + sef_setcb_init_fresh(sef_cb_init_fresh); + sef_setcb_init_lu(sef_cb_init_fresh); + sef_setcb_init_restart(sef_cb_init_fresh); + + /* Register live update callbacks. */ + sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); + sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); + + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + + /* Let SEF perform startup. */ + sef_startup(); +} + +/*============================================================================* + * sef_cb_init_fresh * + *============================================================================*/ +static int +sef_cb_init_fresh(int UNUSED( type), sef_init_info_t *UNUSED( info)) +{ + /* Initialize the ethernet driver. */ + long v = 0; + + /* Clear state. */ + memset(&lan8710a_state, 0, sizeof(lan8710a_state)); + + /* Initialize driver. */ + lan8710a_init(); + + /* Get instance of ethernet device */ + env_parse("instance", "d", 0, &v, 0, 255); + lan8710a_state.instance = (int) v; + + /* Announce we are up! */ + netdriver_announce(); + + return OK; +} + +/*============================================================================* + * sef_cb_signal_handler * + *============================================================================*/ +static void +sef_cb_signal_handler(int signal) +{ + /* Only check for termination signal, ignore anything else. */ + if (signal != SIGTERM) + return; + + lan8710a_stop(); +} + +/*============================================================================* + * lan8710a_enable_interrupt * + *============================================================================*/ +static void +lan8710a_enable_interrupt(interrupt) +u8_t interrupt; +{ + int r; + + if (interrupt & RX_INT) { + if ((r = sys_irqenable(&lan8710a_state.irq_rx_hook)) != OK) { + panic("sys_irqenable failed: %d", r); + } + } + if (interrupt & TX_INT) { + if ((r = sys_irqenable(&lan8710a_state.irq_tx_hook)) != OK) { + panic("sys_irqenable failed: %d", r); + } + } +} +/*============================================================================* + * lan8710a_interrupt * + *============================================================================*/ +static void +lan8710a_interrupt(m) +message *m; +{ + lan8710a_t *e = &lan8710a_state; + u32_t dma_status; + + /* Check the card for interrupt reason(s). */ + u32_t rx_stat = lan8710a_reg_read(CPSW_WR_C0_RX_STAT); + u32_t tx_stat = lan8710a_reg_read(CPSW_WR_C0_TX_STAT); + u32_t cp; + + /* Handle interrupts. */ + if (rx_stat) { + cp = lan8710a_reg_read(CPDMA_STRAM_RX_CP(0)); + + lan8710a_readv_s(&(e->rx_message), TRUE); + + lan8710a_reg_write(CPDMA_STRAM_RX_CP(0), cp); + lan8710a_reg_write(CPDMA_EOI_VECTOR, RX_INT); + } + if (tx_stat) { + cp = lan8710a_reg_read(CPDMA_STRAM_TX_CP(0)); + + /* Disabling channels, where Tx interrupt occurred */ + lan8710a_reg_set(CPDMA_TX_INTMASK_CLEAR, tx_stat); + + lan8710a_writev_s(&(e->tx_message), TRUE); + + lan8710a_reg_write(CPDMA_STRAM_TX_CP(0), cp); + lan8710a_reg_write(CPDMA_EOI_VECTOR, TX_INT); + } + + dma_status = lan8710a_reg_read(CPDMA_STATUS); + + if (dma_status & CPDMA_ERROR) { + LAN8710A_DEBUG_PRINT(("CPDMA error: 0x%X, reset", dma_status)); + lan8710a_dma_reset_init(); + } + + /* Re-enable Rx interrupt. */ + if(m->NOTIFY_ARG & (1 << RX_INT)) + lan8710a_enable_interrupt(RX_INT); + + /* Re-enable Tx interrupt. */ + if(m->NOTIFY_ARG & (1 << TX_INT)) + lan8710a_enable_interrupt(TX_INT); +} + +/*============================================================================* + * lan8710a_conf * + *============================================================================*/ +static void +lan8710a_conf(m) +message *m; +{ + message reply; + + if (!(lan8710a_state.status & LAN8710A_ENABLED) && + !(lan8710a_init_hw())) { + reply.m_type = DL_CONF_REPLY; + reply.DL_STAT = ENXIO; + mess_reply(m, &reply); + return; + } + /* Reply back to INET. */ + reply.m_type = DL_CONF_REPLY; + reply.DL_STAT = OK; + *(ether_addr_t *) reply.DL_HWADDR = lan8710a_state.address; + mess_reply(m, &reply); +} + +/*============================================================================* + * lan8710a_init * + *============================================================================*/ +static void +lan8710a_init(void) +{ + lan8710a_map_regs(); + strlcpy(lan8710a_state.name, "lan8710a#0", LAN8710A_NAME_LEN); + lan8710a_state.name[9] += lan8710a_state.instance; + lan8710a_state.status |= LAN8710A_DETECTED; + + if (!(lan8710a_state.status & LAN8710A_ENABLED) && + !(lan8710a_init_hw())) { + return; + } +} + +/*============================================================================* + * lan8710a_init_addr * + *============================================================================*/ +static void +lan8710a_init_addr(void) +{ + static char eakey[]= LAN8710A_ENVVAR "#_EA"; + static char eafmt[]= "x:x:x:x:x:x"; + int i; + long v; + + /* + * Do we have a user defined ethernet address? + */ + eakey[sizeof(LAN8710A_ENVVAR)-1] = '0' + lan8710a_state.instance; + + for (i= 0; i < 6; i++) { + if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) + break; + else + lan8710a_state.address.ea_addr[i] = v; + } + if (i != 6) { + lan8710a_state.address.ea_addr[0] = + (lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF); + lan8710a_state.address.ea_addr[1] = + ((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF00) >> 8); + lan8710a_state.address.ea_addr[2] = + ((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF0000) >> 16); + lan8710a_state.address.ea_addr[3] = + ((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF000000) >> 24); + lan8710a_state.address.ea_addr[4] = + (lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF); + lan8710a_state.address.ea_addr[5] = + ((lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF00) >> 8); + } +} + +/*============================================================================* + * lan8710a_map_regs * + *============================================================================*/ +static void +lan8710a_map_regs(void) +{ + struct minix_mem_range mr; + mr.mr_base = CM_PER_BASE_ADR; + mr.mr_limit = CM_PER_BASE_ADR + MEMORY_LIMIT; + + if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { + panic("Unable to request permission to map memory"); + } + lan8710a_state.regs_cp_per = + (vir_bytes)vm_map_phys(SELF, (void *)CM_PER_BASE_ADR, 512); + if ((void *)lan8710a_state.regs_cp_per == MAP_FAILED) { + panic("lan8710a_state.regs_cp_per: vm_map_phys failed"); + } + lan8710a_state.regs_cpdma_stram = + (vir_bytes)vm_map_phys(SELF, (void *)CPDMA_STRAM_BASE_ADR, 512); + if ((void *)lan8710a_state.regs_cpdma_stram == MAP_FAILED) { + panic("lan8710a_state.regs_cpdma_stram: vm_map_phys failed"); + } + lan8710a_state.regs_cpsw_cpdma = + (vir_bytes)vm_map_phys(SELF, (void *)CPSW_CPDMA_BASE_ADR, 512); + if ((void *)lan8710a_state.regs_cpsw_cpdma == MAP_FAILED) { + panic("lan8710a_state.regs_cpsw_cpdma: vm_map_phys failed"); + } + lan8710a_state.regs_cpsw_ale = + (vir_bytes)vm_map_phys(SELF, (void *)CPSW_ALE_BASE_ADR, 256); + if ((void *)lan8710a_state.regs_cpsw_ale == MAP_FAILED) { + panic("lan8710a_state.regs_cpsw_ale: vm_map_phys failed"); + } + lan8710a_state.regs_cpsw_sl = + (vir_bytes)vm_map_phys(SELF, (void *)CPSW_SL_BASE_ADR, 512); + if ((void *)lan8710a_state.regs_cpsw_sl == MAP_FAILED) { + panic("lan8710a_state.regs_cpsw_sl: vm_map_phys failed"); + } + lan8710a_state.regs_cpsw_ss = + (vir_bytes)vm_map_phys(SELF, (void *)CPSW_SS_BASE_ADR, 512); + if ((void *)lan8710a_state.regs_cpsw_ss == MAP_FAILED) { + panic("lan8710a_state.regs_cpsw_ss: vm_map_phys failed"); + } + lan8710a_state.regs_cpsw_wr = + (vir_bytes)vm_map_phys(SELF, (void *)CPSW_WR_BASE_ADR, 512); + if ((void *)lan8710a_state.regs_cpsw_wr == MAP_FAILED) { + panic("lan8710a_state.regs_cpsw_wr: vm_map_phys failed"); + } + lan8710a_state.regs_ctrl_mod = + (vir_bytes)vm_map_phys(SELF, (void *)CTRL_MOD_BASE_ADR, 2560); + if ((void *)lan8710a_state.regs_ctrl_mod == MAP_FAILED) { + panic("lan8710a_state.regs_ctrl_mod: vm_map_phys failed"); + } + lan8710a_state.regs_intc = + (vir_bytes)vm_map_phys(SELF, (void *)INTC_BASE_ADR, 512); + if ((void *)lan8710a_state.regs_intc == MAP_FAILED) { + panic("lan8710a_state.regs_intc: vm_map_phys failed"); + } + lan8710a_state.regs_mdio = + (vir_bytes)vm_map_phys(SELF, (void *)MDIO_BASE_ADDR, 512); + if ((void *)lan8710a_state.regs_mdio == MAP_FAILED) { + panic("lan8710a_state.regs_mdio: vm_map_phys failed"); + } + + mr.mr_base = BEGINNING_DESC_MEM; + mr.mr_limit = BEGINNING_DESC_MEM + DESC_MEMORY_LIMIT; + + if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { + panic("Unable to request permission to map memory"); + } + lan8710a_state.rx_desc_phy = BEGINNING_RX_DESC_MEM; + lan8710a_state.tx_desc_phy = BEGINNING_TX_DESC_MEM; + lan8710a_state.rx_desc = (lan8710a_desc_t *)vm_map_phys(SELF, + (void *)lan8710a_state.rx_desc_phy, 1024); + if ((void *)lan8710a_state.rx_desc == MAP_FAILED) { + panic("lan8710a_state.rx_desc: vm_map_phys failed"); + } + lan8710a_state.tx_desc = (lan8710a_desc_t *)vm_map_phys(SELF, + (void *)lan8710a_state.tx_desc_phy, 1024); + if ((void *)lan8710a_state.tx_desc == MAP_FAILED) { + panic("lan8710a_state.tx_desc: vm_map_phys failed"); + } + + mr.mr_base = CPSW_STATS_BASE_ADR; + mr.mr_limit = CPSW_STATS_BASE_ADR + CPSW_STATS_MEM_LIMIT; + + if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { + panic("Unable to request permission to map memory"); + } + lan8710a_state.regs_cpsw_stats = + (vir_bytes)vm_map_phys(SELF, (void *)CPSW_STATS_BASE_ADR, 256); + if ((void *)lan8710a_state.regs_cpsw_stats == MAP_FAILED) { + panic("lan8710a_state.regs_cpsw_stats: vm_map_phys failed"); + } +} + +/*============================================================================* + * lan8710a_getstat * + *============================================================================*/ +static void +lan8710a_getstat(mp) +message *mp; +{ + int r; + eth_stat_t stats; + + stats.ets_recvErr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR) + + lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR) + + lan8710a_reg_read(CPSW_STAT_RX_OVERSIZE); + stats.ets_sendErr = 0; + stats.ets_OVW = 0; + stats.ets_CRCerr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR); + stats.ets_frameAll = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR); + stats.ets_missedP = 0; + stats.ets_packetR = lan8710a_reg_read(CPSW_STAT_RX_GOOD); + stats.ets_packetT = lan8710a_reg_read(CPSW_STAT_TX_GOOD); + stats.ets_collision = lan8710a_reg_read(CPSW_STAT_COLLISIONS); + stats.ets_transAb = 0; + stats.ets_carrSense = lan8710a_reg_read(CPSW_STAT_CARR_SENS_ERR); + stats.ets_fifoUnder = lan8710a_reg_read(CPSW_STAT_TX_UNDERRUN); + stats.ets_fifoOver = lan8710a_reg_read(CPSW_STAT_RX_OVERRUN); + stats.ets_CDheartbeat = 0; + stats.ets_OWC = 0; + + sys_safecopyto(mp->m_source, mp->DL_GRANT, 0, (vir_bytes)&stats, + sizeof(stats)); + mp->m_type = DL_STAT_REPLY; + + if ((r=send(mp->m_source, mp)) != OK) { + panic("lan8710a_getstat: send() failed: %d", r); + } +} + +/*============================================================================* + * lan8710a_stop * + *============================================================================*/ +static void +lan8710a_stop(void) +{ + /* Reset hardware. */ + lan8710a_reset_hw(); + + /* Exit driver. */ + exit(EXIT_SUCCESS); +} + +/*============================================================================* + * lan8710a_dma_config_tx * + *============================================================================*/ +static void +lan8710a_dma_config_tx(desc_idx) +u8_t desc_idx; +{ + phys_bytes phys_addr; + int i; + for (i = 0; i < TX_DMA_CHANNELS; ++i) { + if (!lan8710a_reg_read(CPDMA_STRAM_TX_HDP(i))) break; + } + if (i == TX_DMA_CHANNELS) { + panic("There are no free TX DMA channels."); + } + + /* Enabling only one channel Tx interrupt */ + lan8710a_reg_write(CPDMA_TX_INTMASK_SET, 1 << i); + /* Routing only one channel Tx int to TX_PULSE signal */ + lan8710a_reg_write(CPSW_WR_C0_TX_EN, 1 << i); + + /* Setting HDP */ + phys_addr = lan8710a_state.tx_desc_phy + + (desc_idx * sizeof(lan8710a_desc_t)); + lan8710a_reg_write(CPDMA_STRAM_TX_HDP(i), (u32_t)phys_addr); +} + +/*============================================================================* + * lan8710a_dma_reset_init * + *============================================================================*/ +static void +lan8710a_dma_reset_init(void) +{ + int i; + lan8710a_reg_write(CPDMA_SOFT_RESET, SOFT_RESET); + while ((lan8710a_reg_read(CPDMA_SOFT_RESET) & SOFT_RESET)); + + /* + * Initialize the HDPs (Header Description Pointers) and + * CPs (Completion Pointers) to NULL. + */ + for (i = 0; i < DMA_MAX_CHANNELS; ++i) { + lan8710a_reg_write(CPDMA_STRAM_TX_HDP(i), 0); + lan8710a_reg_write(CPDMA_STRAM_RX_HDP(i), 0); + lan8710a_reg_write(CPDMA_STRAM_TX_CP(i), 0); + lan8710a_reg_write(CPDMA_STRAM_RX_CP(i), 0); + } + + lan8710a_reg_write(CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF); + lan8710a_reg_write(CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF); + + /* Configure the CPDMA controller. */ + lan8710a_reg_set(CPDMA_RX_CONTROL, CPDMA_RX_EN); /* RX Enabled */ + lan8710a_reg_set(CPDMA_TX_CONTROL, CPDMA_TX_EN); /* TX Enabled */ + + /* Enabling first channel Rx interrupt */ + lan8710a_reg_set(CPDMA_RX_INTMASK_SET, CPDMA_FIRST_CHAN_INT); + + /* + * Writing the address of the first buffer descriptor in the queue + * (nonzero value)to the channel’s head descriptor pointer in the + * channel’s Rx DMA state. + */ + lan8710a_reg_write(CPDMA_STRAM_RX_HDP(0), + (u32_t)lan8710a_state.rx_desc_phy); + + lan8710a_state.rx_desc_idx = 0; + lan8710a_state.tx_desc_idx = 0; +} + +/*============================================================================* + * lan8710a_init_desc * + *============================================================================*/ +static void +lan8710a_init_desc(void) +{ + lan8710a_desc_t *p_rx_desc; + lan8710a_desc_t *p_tx_desc; + phys_bytes buf_phys_addr; + u8_t *p_buf; + u8_t i; + + /* Attempt to allocate. */ + if ((lan8710a_state.p_rx_buf = alloc_contig((LAN8710A_NUM_RX_DESC + * LAN8710A_IOBUF_SIZE), AC_ALIGN4K, + &buf_phys_addr)) == NULL) { + panic("failed to allocate RX buffers."); + } + p_buf = lan8710a_state.p_rx_buf; + for (i = 0; i < LAN8710A_NUM_RX_DESC; i++) { + p_rx_desc = &(lan8710a_state.rx_desc[i]); + memset(p_rx_desc, 0x0, sizeof(lan8710a_desc_t)); + p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN; + p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE; + p_rx_desc->buffer_pointer = (u32_t)(buf_phys_addr + + (i * LAN8710A_IOBUF_SIZE)); + + p_rx_desc->next_pointer = + (u32_t)((i == (LAN8710A_NUM_RX_DESC - 1)) ? + (lan8710a_state.rx_desc_phy) : + (lan8710a_state.rx_desc_phy + + ((i + 1) * sizeof(lan8710a_desc_t)))); + } + + /* Attempt to allocate. */ + if ((lan8710a_state.p_tx_buf = alloc_contig((LAN8710A_NUM_TX_DESC + * LAN8710A_IOBUF_SIZE), AC_ALIGN4K, + &buf_phys_addr)) == NULL) { + panic("failed to allocate TX buffers"); + } + p_buf = lan8710a_state.p_tx_buf; + for (i = 0; i < LAN8710A_NUM_TX_DESC; i++) { + p_tx_desc = &(lan8710a_state.tx_desc[i]); + memset(p_tx_desc, 0x0, sizeof(lan8710a_desc_t)); + p_tx_desc->buffer_pointer = (u32_t)(buf_phys_addr + + (i * LAN8710A_IOBUF_SIZE)); + } + lan8710a_state.rx_desc_idx = 0; + lan8710a_state.tx_desc_idx = 0; +} + +/*============================================================================* + * lan8710a_init_hw * + *============================================================================*/ +static int +lan8710a_init_hw(void) +{ + int r, i; + + lan8710a_state.status |= LAN8710A_ENABLED; + + /* + * Set the interrupt handler and policy. Do not automatically + * re-enable interrupts. Return the IRQ line number on interrupts. + */ + lan8710a_state.irq_rx_hook = RX_INT; + if ((r = sys_irqsetpolicy(LAN8710A_RX_INTR, 0, + &lan8710a_state.irq_rx_hook)) != OK) { + panic("sys_irqsetpolicy failed: %d", r); + } + lan8710a_state.irq_tx_hook = TX_INT; + if ((r = sys_irqsetpolicy(LAN8710A_TX_INTR, 0, + &lan8710a_state.irq_tx_hook)) != OK) { + panic("sys_irqsetpolicy failed: %d", r); + } + + /* Reset hardware. */ + lan8710a_reset_hw(); + + /* + * Select the Interface (GMII/RGMII/MII) Mode in the Control Module. + * Port1 GMII/MII Mode, Port2 not used. + */ + lan8710a_reg_write(GMII_SEL, (GMII2_SEL_BIT1 | GMII2_SEL_BIT0)); + + /* + * Configure pads (PIN muxing) as per the Interface Selected using the + * appropriate pin muxing conf_xxx registers in the Control Module. + * + * CONF_MOD_SLEW_CTRL when 0 - Fast Mode, when 1 - Slow Mode + * CONF_MOD_RX_ACTIVE when 0 - Only output, when 1 - Also input + * CONF_MOD_PU_TYPESEL when 0 - Pull-down, when 1 - Pull-up + * CONF_MOD_PUDEN when 0 Pull* enabled, when 1 Pull* disabled + * CONF_MOD_MMODE_MII selects pin to work for MII interface + */ + lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_PU_TYPESEL); + lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_PU_TYPESEL); + lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_PU_TYPESEL); + lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_SLEW_CTRL); + lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_TX_EN, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_PU_TYPESEL); + lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_SLEW_CTRL); + lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_TXD3, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_SLEW_CTRL); + lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_TXD2, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_SLEW_CTRL); + lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_TXD1, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_SLEW_CTRL); + lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_TXD0, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_PU_TYPESEL); + lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_PU_TYPESEL); + lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_PU_TYPESEL); + lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_PU_TYPESEL); + lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MDIO, CONF_MOD_SLEW_CTRL); + lan8710a_reg_set(CONF_MDIO, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MDIO, CONF_MOD_PU_TYPESEL); + lan8710a_reg_unset(CONF_MDIO, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MDIO, CONF_MOD_MMODE_MII); + + lan8710a_reg_unset(CONF_MDC, CONF_MOD_SLEW_CTRL); + lan8710a_reg_unset(CONF_MDC, CONF_MOD_RX_ACTIVE); + lan8710a_reg_set(CONF_MDC, CONF_MOD_PUDEN); + lan8710a_reg_unset(CONF_MDC, CONF_MOD_MMODE_MII); + + /* Apply soft reset to 3PSW Subsytem, CPSW_3G, CPGMAC_SL, and CPDMA. */ + lan8710a_reg_write(CPSW_SS_SOFT_RESET, SOFT_RESET); + lan8710a_reg_write(CPSW_SL_SOFT_RESET(1), SOFT_RESET); + lan8710a_reg_write(CPSW_SL_SOFT_RESET(2), SOFT_RESET); + + /* Wait for software resets completion */ + while ((lan8710a_reg_read(CPSW_SS_SOFT_RESET) & SOFT_RESET) || + (lan8710a_reg_read(CPSW_SL_SOFT_RESET(1)) & SOFT_RESET) || + (lan8710a_reg_read(CPSW_SL_SOFT_RESET(2)) & SOFT_RESET)); + + /* Configure the Statistics Port Enable register. */ + /* Enable port 0 and 1 statistics. */ + lan8710a_reg_write(CPSW_SS_STAT_PORT_EN, (CPSW_P1_STAT_EN | + CPSW_P0_STAT_EN)); + + /* + * Configure the ALE. + * Enabling Ale. + * All packets received on ports 1 are + * sent to the host (only to the host). + */ + lan8710a_reg_write(CPSW_ALE_CONTROL, (CPSW_ALE_ENABLE | + CPSW_ALE_BYPASS)); + /* Port 0 (host) in forwarding mode. */ + lan8710a_reg_write(CPSW_ALE_PORTCTL0, CPSW_ALE_PORT_FWD); + /* Port 1 in forwarding mode. */ + lan8710a_reg_write(CPSW_ALE_PORTCTL1, CPSW_ALE_PORT_FWD); + + /* + * Configure CPSW_SL Register + * Full duplex mode. + */ + lan8710a_reg_write(CPSW_SL_MACCONTROL(1), CPSW_SL_FULLDUPLEX); + + /* Initialize MDIO Protocol */ + lan8710a_init_mdio(); + + /* Getting MAC Address */ + lan8710a_init_addr(); + + /* Initialize descriptors */ + lan8710a_init_desc(); + + /* Reset and initialize CPDMA */ + lan8710a_dma_reset_init(); + + /* + * Configure the Interrupts. + * Routing all channel Rx int to RX_PULSE signal. + */ + lan8710a_reg_set(CPSW_WR_C0_RX_EN, CPSW_FIRST_CHAN_INT); + + /* + * Enabling LAN8710A Auto-negotiation + */ + lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_AUTO_NEG); + + /* Waiting for auto-negotiaion completion. */ + for (i = 0; !(lan8710a_phy_read(LAN8710A_STATUS_REG) & + LAN8710A_AUTO_NEG_COMPL); ++i) { + if (i == 100) { + LAN8710A_DEBUG_PRINT(("Autonegotiation failed")); + break; + } + tickdelay(100); + } + + /* GMII RX and TX release from reset. */ + lan8710a_reg_set(CPSW_SL_MACCONTROL(1), CPSW_SL_GMII_EN); + + return TRUE; +} + +/*============================================================================* + * lan8710a_init_mdio * + *============================================================================*/ +static void +lan8710a_init_mdio(void) +{ + u16_t address = 0; + u32_t r; + + /* Clearing MDIOCONTROL register */ + lan8710a_reg_write(MDIOCONTROL, 0); + /* Configure the PREAMBLE and CLKDIV in the MDIO control register */ + lan8710a_reg_unset(MDIOCONTROL, MDIO_PREAMBLE); /* CLKDIV default */ + /* Enable sending MDIO frame preambles */ + lan8710a_reg_set(MDIOCONTROL, (MDCLK_DIVIDER | MDIO_ENABLE)); + /* Enable the MDIO module by setting the ENABLE bit in MDIOCONTROL */ + + while (!(r = lan8710a_reg_read(MDIOALIVE))); + + /* Get PHY address */ + while (r >>= 1) { + ++address; + } + lan8710a_state.phy_address = address; + + /* Setup appropiate address in MDIOUSERPHYSEL0 */ + lan8710a_reg_set(MDIOUSERPHYSEL0, address); +} + +/*============================================================================* + * lan8710a_writev_s * + *============================================================================*/ +static void +lan8710a_writev_s(mp, from_int) +message *mp; +int from_int; +{ + iovec_s_t iovec[LAN8710A_IOVEC_NR]; + lan8710a_t *e = &lan8710a_state; + lan8710a_desc_t *p_tx_desc; + u8_t *p_buf; + int r, size, buf_data_len, i; + + /* Are we called from the interrupt handler? */ + if (!from_int) { + /* We cannot write twice simultaneously. */ + assert(!(e->status & LAN8710A_WRITING)); + + /* Copy write message. */ + e->tx_message = *mp; + e->client = mp->m_source; + e->status |= LAN8710A_WRITING; + + /* verify vector count */ + assert(mp->DL_COUNT > 0); + assert(mp->DL_COUNT < LAN8710A_IOVEC_NR); + + /* + * Copy the I/O vector table. + */ + if ((r = sys_safecopyfrom(mp->m_source, mp->DL_GRANT, 0, + (vir_bytes) iovec, + mp->DL_COUNT * sizeof(iovec_s_t))) != OK) { + panic("sys_safecopyfrom() failed: %d", r); + } + /* setup descriptors */ + p_tx_desc = &(e->tx_desc[e->tx_desc_idx]); + + /* + * Check if descriptor is available for host + * and drop the packet if not. + */ + if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags) { + panic("No available transmit descriptor."); + } + + /* virtual address of buffer */ + p_buf = e->p_tx_buf + e->tx_desc_idx * LAN8710A_IOBUF_SIZE; + buf_data_len = 0; + for (i = 0; i < mp->DL_COUNT; i++) { + if ((buf_data_len + iovec[i].iov_size) + > LAN8710A_IOBUF_SIZE) { + panic("packet too long"); + } + + /* copy data to buffer */ + size = iovec[i].iov_size + < (LAN8710A_IOBUF_SIZE - buf_data_len) ? + iovec[i].iov_size + : (LAN8710A_IOBUF_SIZE - buf_data_len); + + /* Copy bytes to TX queue buffers. */ + if ((r = sys_safecopyfrom(mp->m_source, + iovec[i].iov_grant, 0, + (vir_bytes) p_buf, size)) != OK) { + panic("sys_safecopyfrom() failed: %d", r); + } + p_buf += size; + buf_data_len += size; + } + + /* set descriptor length */ + p_tx_desc->buffer_length_off = buf_data_len; + /* set flags */ + p_tx_desc->pkt_len_flags = (LAN8710A_DESC_FLAG_OWN | + LAN8710A_DESC_FLAG_SOP | + LAN8710A_DESC_FLAG_EOP | + TX_DESC_TO_PORT1 | + TX_DESC_TO_PORT_EN); + p_tx_desc->pkt_len_flags |= buf_data_len; + + /* setup DMA transfer */ + lan8710a_dma_config_tx(e->tx_desc_idx); + + e->tx_desc_idx++; + if (LAN8710A_NUM_TX_DESC == e->tx_desc_idx) { + e->tx_desc_idx = 0; + } + } else { + e->status |= LAN8710A_TRANSMIT; + } + reply(e); +} + +/*============================================================================* + * lan8710a_readv_s * + *============================================================================*/ +static void +lan8710a_readv_s(mp, from_int) +message *mp; +int from_int; +{ + iovec_s_t iovec[LAN8710A_IOVEC_NR]; + lan8710a_t *e = &lan8710a_state; + lan8710a_desc_t *p_rx_desc; + u32_t flags; + u8_t *p_buf; + u16_t pkt_data_len; + u16_t buf_bytes, buf_len; + int i, r, size; + + /* Are we called from the interrupt handler? */ + if (!from_int) { + e->rx_message = *mp; + e->client = mp->m_source; + e->status |= LAN8710A_READING; + e->rx_size = 0; + + assert(e->rx_message.DL_COUNT > 0); + assert(e->rx_message.DL_COUNT < LAN8710A_IOVEC_NR); + } + if (e->status & LAN8710A_READING) { + /* + * Copy the I/O vector table first. + */ + if ((r = sys_safecopyfrom(e->rx_message.m_source, + e->rx_message.DL_GRANT, 0, (vir_bytes) iovec, + e->rx_message.DL_COUNT * + sizeof(iovec_s_t))) != OK) { + panic("sys_safecopyfrom() failed: %d", r); + } + + /* + * Only handle one packet at a time. + */ + p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); + /* find next OWN descriptor with SOP flag */ + while ((0 == (LAN8710A_DESC_FLAG_SOP & + p_rx_desc->pkt_len_flags)) && + (0 == (LAN8710A_DESC_FLAG_OWN & + p_rx_desc->pkt_len_flags))) { + p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE; + /* set ownership of current descriptor to EMAC */ + p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN; + + e->rx_desc_idx++; + if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx) + e->rx_desc_idx = 0; + p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); + } + if (0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) { + /* SOP was not found */ + reply(e); + return; + } + + /* + * Copy to vector elements. + */ + pkt_data_len = 0; + buf_bytes = 0; + p_buf = e->p_rx_buf + e->rx_desc_idx * LAN8710A_IOBUF_SIZE; + for (i = 0; i < e->rx_message.DL_COUNT; i++) { + buf_len = p_rx_desc->buffer_length_off & 0xFFFF; + if (buf_bytes == buf_len) { + /* Whole buffer move to the next descriptor */ + p_rx_desc->buffer_length_off = + LAN8710A_IOBUF_SIZE; + /* set ownership of current desc to EMAC */ + p_rx_desc->pkt_len_flags = + LAN8710A_DESC_FLAG_OWN; + buf_bytes = 0; + + e->rx_desc_idx++; + if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx) + e->rx_desc_idx = 0; + p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); + p_buf = e->p_rx_buf + (e->rx_desc_idx * + LAN8710A_IOBUF_SIZE) + + (p_rx_desc->buffer_length_off >> 16); + buf_len = p_rx_desc->buffer_length_off & 0xFFFF; + } + size = iovec[i].iov_size < (buf_len - buf_bytes) ? + iovec[i].iov_size : + (buf_len - buf_bytes); + + if ((r = sys_safecopyto(e->rx_message.m_source, + iovec[i].iov_grant, 0, + (vir_bytes) p_buf, + size)) != OK) { + panic("sys_safecopyto() failed: %d", r); + } + p_buf += size; + buf_bytes += size; + pkt_data_len += size; + + /* if EOP flag is set -> stop processing */ + if ((LAN8710A_DESC_FLAG_EOP & p_rx_desc->pkt_len_flags) && + (buf_bytes == buf_len)) { + /* end of packet */ + break; + } + } + do { + /* reset owned descriptors up to EOP flag */ + flags = p_rx_desc->pkt_len_flags; + p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE; + /* set ownership of current descriptor to EMAC */ + p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN; + + e->rx_desc_idx++; + if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx) + e->rx_desc_idx = 0; + + p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); + } + while (0 == (flags & LAN8710A_DESC_FLAG_EOP)); + + /* + * Update state. + */ + e->status |= LAN8710A_RECEIVED; + e->rx_size = pkt_data_len; + + } + reply(e); +} + +/*============================================================================* + * lan8710a_phy_write * + *============================================================================*/ +static void +lan8710a_phy_write(reg, value) +u32_t reg; +u32_t value; +{ + if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) { + /* Clearing MDIOUSERACCESS0 register */ + lan8710a_reg_write(MDIOUSERACCESS0, 0); + /* Setting proper values in MDIOUSERACCESS0 */ + lan8710a_reg_set(MDIOUSERACCESS0, MDIO_WRITE); + lan8710a_reg_set(MDIOUSERACCESS0, reg << MDIO_REGADR); + lan8710a_reg_set(MDIOUSERACCESS0, + lan8710a_state.phy_address << MDIO_PHYADR); + /* Data written only 16 bits. */ + lan8710a_reg_set(MDIOUSERACCESS0, (value & 0xFFFF) << MDIO_DATA); + lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO); + + /* Waiting for writing completion */ + while (lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO); + } +} + +/*============================================================================* + * lan8710a_phy_read * + *============================================================================*/ +static u32_t +lan8710a_phy_read(reg) +u32_t reg; +{ + u32_t value = 0xFFFFFFFF; + + if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) { + /* Clearing MDIOUSERACCESS0 register */ + lan8710a_reg_write(MDIOUSERACCESS0, 0); + /* Setting proper values in MDIOUSERACCESS0 */ + lan8710a_reg_unset(MDIOUSERACCESS0, MDIO_WRITE); + /* Reg number must be 5 bit long */ + lan8710a_reg_set(MDIOUSERACCESS0, (reg & 0x1F) << MDIO_REGADR); + /* Addr must be 5 bit long */ + lan8710a_reg_set(MDIOUSERACCESS0, + (lan8710a_state.phy_address & 0x1F) << MDIO_PHYADR); + lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO); + + /* Waiting for reading completion */ + while ((lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO) + && !(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_ACK)); + + /* Reading data */ + value = lan8710a_reg_read(MDIOUSERACCESS0) & 0xFFFF; + } + return value; +} + +/*============================================================================* + * lan8710a_reset_hw * + *============================================================================*/ +static void +lan8710a_reset_hw() +{ + /* Assert a Device Reset signal. */ + lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_SOFT_RESET); + + /* Waiting for reset completion. */ + while (lan8710a_phy_read(LAN8710A_CTRL_REG) & LAN8710A_SOFT_RESET); +} + +/*============================================================================* + * lan8710a_reg_read * + *============================================================================*/ +static u32_t +lan8710a_reg_read(reg) +volatile u32_t *reg; +{ + u32_t value; + + /* Read from memory mapped register. */ + value = *reg; + + /* Return the result. */ + return value; +} + +/*============================================================================* + * lan8710a_reg_write * + *============================================================================*/ +static void +lan8710a_reg_write(reg, value) +volatile u32_t *reg; +u32_t value; +{ + /* Write to memory mapped register. */ + *reg = value; +} + +/*============================================================================* + * lan8710a_reg_set * + *============================================================================*/ +static void +lan8710a_reg_set(reg, value) +volatile u32_t *reg; +u32_t value; +{ + u32_t data; + + /* First read the current value. */ + data = lan8710a_reg_read(reg); + + /* Set value, and write back. */ + lan8710a_reg_write(reg, data | value); +} + +/*============================================================================* + * lan8710a_reg_unset * + *============================================================================*/ +static void +lan8710a_reg_unset(reg, value) +volatile u32_t *reg; +u32_t value; +{ + u32_t data; + + /* First read the current value. */ + data = lan8710a_reg_read(reg); + + /* Unset value, and write back. */ + lan8710a_reg_write(reg, data & ~value); +} + +/*============================================================================* + * mess_reply * + *============================================================================*/ +static void +mess_reply(req, reply) +message *req;message *reply; +{ + if (send(req->m_source, reply) != OK) { + panic("unable to send reply message"); + } +} + +/*============================================================================* + * reply * + *============================================================================*/ +static void +reply(e) +lan8710a_t *e; +{ + message msg; + int r; + + /* Only reply to client for read/write request. */ + if (!(e->status & LAN8710A_READING || + e->status & LAN8710A_WRITING)) { + return; + } + /* Construct reply message. */ + msg.m_type = DL_TASK_REPLY; + msg.DL_FLAGS = DL_NOFLAGS; + msg.DL_COUNT = 0; + + /* Did we successfully receive packet(s)? */ + if (e->status & LAN8710A_READING && + e->status & LAN8710A_RECEIVED) { + msg.DL_FLAGS |= DL_PACK_RECV; + msg.DL_COUNT = e->rx_size >= ETH_MIN_PACK_SIZE ? + e->rx_size : + ETH_MIN_PACK_SIZE; + + /* Clear flags. */ + e->status &= ~(LAN8710A_READING | LAN8710A_RECEIVED); + } + /* Did we successfully transmit packet(s)? */ + if (e->status & LAN8710A_TRANSMIT && + e->status & LAN8710A_WRITING) { + msg.DL_FLAGS |= DL_PACK_SEND; + + /* Clear flags. */ + e->status &= ~(LAN8710A_WRITING | LAN8710A_TRANSMIT); + } + + /* Acknowledge to INET. */ + if ((r = send(e->client, &msg) != OK)) { + panic("send() failed: %d", r); + } +} +#endif /* AM335X */ diff --git a/drivers/lan8710a/lan8710a.conf b/drivers/lan8710a/lan8710a.conf new file mode 100644 index 000000000..4c37a77d2 --- /dev/null +++ b/drivers/lan8710a/lan8710a.conf @@ -0,0 +1,17 @@ +service lan8710a +{ + type net; + descr "Beaglebone Ethernet Controller LAN8710A"; + system + PRIVCTL # 4 + UMAP # 14 + IRQCTL # 19 + DEVIO # 21 + ; + ipc + tty inet lwip + ; + irq 41 # IRQ 41 allowed + 42 # IRQ 42 allowed + ; +}; diff --git a/drivers/lan8710a/lan8710a.h b/drivers/lan8710a/lan8710a.h new file mode 100644 index 000000000..214df87cc --- /dev/null +++ b/drivers/lan8710a/lan8710a.h @@ -0,0 +1,123 @@ +#ifndef LAN8710A_H_ +#define LAN8710A_H_ + +#include + +#define LAN8710A_DEBUG (1) + +#if LAN8710A_DEBUG == 1 + #define LAN8710A_DEBUG_PRINT(args) \ + do { \ + printf("LAN8710A DEBUG: "); \ + printf args; \ + printf("\n"); \ + } while (0) +#else + #define LAN8710A_DEBUG_PRINT(args) +#endif + +#ifndef ERR + #define ERR (-1) /* general error flag */ +#endif +#ifndef OK + #define OK 0 /* general OK flag */ +#endif + +#define MAP_FAILED ((void *) -1) /* mmap() failed */ + +/* Ethernet driver defines */ +#define LAN8710A_NAME_LEN (11) + +/* Ethernet driver states */ +#define LAN8710A_DETECTED (1 << 0) +#define LAN8710A_ENABLED (1 << 1) +#define LAN8710A_READING (1 << 2) +#define LAN8710A_WRITING (1 << 3) +#define LAN8710A_RECEIVED (1 << 4) +#define LAN8710A_TRANSMIT (1 << 5) + +/* Descriptors flags */ +#define LAN8710A_DESC_FLAG_OWN (1 << 29) /* ownership flag */ +#define LAN8710A_DESC_FLAG_SOP (1 << 31) /* start of packet flag */ +#define LAN8710A_DESC_FLAG_EOP (1 << 30) /* end of packet flag */ + +/* Number of Tx and Rx interrupts */ +#define LAN8710A_RX_INTR (41) +#define LAN8710A_TX_INTR (42) + +/* Values to be written after interrupt handle and interrupt masks*/ +#define RX_INT (1) +#define TX_INT (2) + +/** Numbers of Tx DMA channels */ +#define TX_DMA_CHANNELS (8) + +/** Number of transmit descriptors */ +#define LAN8710A_NUM_TX_DESC (255) + +/** Number of receive descriptors */ +#define LAN8710A_NUM_RX_DESC (255) + +/** Number of I/O vectors to use. */ +#define LAN8710A_IOVEC_NR (16) + +/** Size of each I/O buffer per descriptor. */ +#define LAN8710A_IOBUF_SIZE (1520) + +/** MAC address override variable. */ +#define LAN8710A_ENVVAR "LAN8710AETH" + +/** MAX DMA Channels */ +#define DMA_MAX_CHANNELS (8) + +/* Setting of Tx descriptors */ +#define TX_DESC_TO_PORT1 (1 << 16) +#define TX_DESC_TO_PORT_EN (1 << 20) + +typedef struct lan8710a_desc_t +{ + u32_t next_pointer; + u32_t buffer_pointer; + u32_t buffer_length_off; + u32_t pkt_len_flags; +} lan8710a_desc_t; + +typedef struct lan8710a_t +{ + lan8710a_desc_t *rx_desc; + lan8710a_desc_t *tx_desc; + phys_bytes rx_desc_phy; + phys_bytes tx_desc_phy; + char name[LAN8710A_NAME_LEN]; + int status; + int irq_rx_hook; /* Rx interrupt Request Vector Hook. */ + int irq_tx_hook; /* Tx interrupt Request Vector Hook. */ + int instance; + ether_addr_t address; /* Ethernet MAC address. */ + u8_t *regs; + u32_t phy_address; + u8_t *p_rx_buf; /* pointer to the buffer with receive frames */ + u8_t *p_tx_buf; /* pointer to the buffer with transmit frames */ + + u16_t tx_desc_idx; /* index of the next transmit desciptor */ + u16_t rx_desc_idx; /* index of the next receive desciptor */ + int client; + message tx_message; + message rx_message; + unsigned int rx_size; + + /* register mapping */ + vir_bytes regs_cp_per; + vir_bytes regs_mdio; + vir_bytes regs_cpsw_cpdma; + vir_bytes regs_ctrl_mod; + vir_bytes regs_cpsw_sl; + vir_bytes regs_cpsw_ss; + vir_bytes regs_cpsw_stats; + vir_bytes regs_cpsw_ale; + vir_bytes regs_cpsw_wr; + vir_bytes regs_intc; + vir_bytes regs_cpdma_stram; +} lan8710a_t; + +#endif /* LAN8710A_H_ */ diff --git a/drivers/lan8710a/lan8710a_reg.h b/drivers/lan8710a/lan8710a_reg.h new file mode 100644 index 000000000..68a38bee6 --- /dev/null +++ b/drivers/lan8710a/lan8710a_reg.h @@ -0,0 +1,203 @@ +#ifndef LAN8710A_REG_H_ +#define LAN8710A_REG_H_ + +/* How much memory we should map */ +#define MEMORY_LIMIT (0x5302000) +#define BEGINNING_DESC_MEM (0x4A102000) +#define DESC_MEMORY_LIMIT (0x2000) +#define BEGINNING_RX_DESC_MEM (0x4A102000) +#define BEGINNING_TX_DESC_MEM (0x4A103000) + +/* MDIO Registers */ +#define MDIO_BASE_ADDR (0x4A101000) +#define MDIOVER ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x00)) +#define MDIOCONTROL ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x04)) +#define MDIOALIVE ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x08)) +#define MDIOLINK ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x0C)) +#define MDIOLINKINTRAW ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x10)) +#define MDIOLINKINTMASKED ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x14)) +#define MDIOUSERINTRAW ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x20)) +#define MDIOUSERINTMASKED ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x24)) +#define MDIOUSERINTMASKSET ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x28)) +#define MDIOUSERINTMASKCLR ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x2C)) +#define MDIOUSERACCESS0 ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x80)) +#define MDIOUSERPHYSEL0 ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x84)) +#define MDIOUSERACCESS1 ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x88)) +#define MDIOUSERPHYSEL1 ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x8C)) + +#define MDIO_PREAMBLE (1 << 20) +#define MDCLK_DIVIDER (0x255) +#define MDIO_ENABLE (1 << 30) +#define MDIO_GO (1 << 31) +#define MDIO_WRITE (1 << 30) +#define MDIO_ACK (1 << 29) + +#define MDIO_REGADR (21) +#define MDIO_PHYADR (16) +#define MDIO_DATA (0) + +/* CONTROL MODULE Registers */ +#define CTRL_MOD_BASE_ADR (0x44E10000) +#define CTRL_MAC_ID0_LO ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x630)) +#define CTRL_MAC_ID0_HI ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x634)) +#define GMII_SEL ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x650)) +#define CONF_MII1_COL ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x908)) +#define CONF_MII1_CRS ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x90C)) +#define CONF_MII1_RX_ER ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x910)) +#define CONF_MII1_TX_EN ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x914)) +#define CONF_MII1_RX_DV ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x918)) +#define CONF_MII1_TXD3 ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x91C)) +#define CONF_MII1_TXD2 ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x920)) +#define CONF_MII1_TXD1 ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x924)) +#define CONF_MII1_TXD0 ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x928)) +#define CONF_MII1_TX_CLK ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x92C)) +#define CONF_MII1_RX_CLK ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x930)) +#define CONF_MII1_RXD3 ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x934)) +#define CONF_MII1_RXD2 ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x938)) +#define CONF_MII1_RXD1 ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x93C)) +#define CONF_MII1_RXD0 ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x940)) +#define CONF_MDIO ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x948)) +#define CONF_MDC ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x94C)) + +#define CONF_MOD_SLEW_CTRL (1 << 6) +#define CONF_MOD_RX_ACTIVE (1 << 5) +#define CONF_MOD_PU_TYPESEL (1 << 4) +#define CONF_MOD_PUDEN (1 << 3) +#define CONF_MOD_MMODE_MII (7 << 0) +#define RMII1_IO_CLK_EN (1 << 6) +#define RGMII1_IDMODE (1 << 4) +#define GMII2_SEL_BIT1 (1 << 3) +#define GMII2_SEL_BIT0 (1 << 2) +#define GMII1_SEL_BIT1 (1 << 1) +#define GMII1_SEL_BIT0 (1 << 0) + +/* CLOCK MODULE Registers */ +#define CM_PER_BASE_ADR (0x44E00000) +#define CM_PER_CPSW_CLKSTCTRL ((volatile u32_t *)( lan8710a_state.regs_cp_per + 0x144)) + +#define CM_PER_CPSW_CLKSTCTRL_BIT1 (1 << 1) +#define CM_PER_CPSW_CLKSTCTRL_BIT0 (1 << 0) + +/* CPSW_ALE Registers */ +#define CPSW_ALE_BASE_ADR (0x4A100D00) +#define CPSW_ALE_CONTROL ((volatile u32_t *)( lan8710a_state.regs_cpsw_ale + 0x08)) +#define CPSW_ALE_PORTCTL0 ((volatile u32_t *)( lan8710a_state.regs_cpsw_ale + 0x40)) +#define CPSW_ALE_PORTCTL1 ((volatile u32_t *)( lan8710a_state.regs_cpsw_ale + 0x44)) + +#define CPSW_ALE_ENABLE (1 << 31) +#define CPSW_ALE_BYPASS (1 << 4) +#define CPSW_ALE_PORT_FWD (3 << 0) + +/* CPSW_SL Registers */ +#define CPSW_SL_BASE_ADR (0x4A100D80) +#define CPSW_SL_MACCONTROL(x) ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x04)) +#define CPSW_SL_SOFT_RESET(x) ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x0C)) +#define CPSW_SL_RX_MAXLEN(x) ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x10)) +#define CPSW_SL_BOFFTEST(x) ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x14)) +#define CPSW_SL_EMCONTROL(x) ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x20)) +#define CPSW_SL_RX_PRI_MAP(x) ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x24)) +#define CPSW_SL_TX_GAP(x) ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x28)) + +#define CPSW_SL_GMII_EN (1 << 5) +#define CPSW_SL_FULLDUPLEX (1 << 0) +#define SOFT_RESET (1 << 0) + +/* CPSW_STATS Registers */ +#define CPSW_STATS_BASE_ADR (0x4A100900) +#define CPSW_STATS_MEM_LIMIT (0x90) +#define CPSW_STAT_RX_GOOD ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x00)) +#define CPSW_STAT_RX_CRC_ERR ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x10)) +#define CPSW_STAT_RX_AGNCD_ERR ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x14)) +#define CPSW_STAT_RX_OVERSIZE ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x18)) +#define CPSW_STAT_TX_GOOD ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x34)) +#define CPSW_STAT_COLLISIONS ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x48)) +#define CPSW_STAT_TX_UNDERRUN ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x5C)) +#define CPSW_STAT_CARR_SENS_ERR ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x60)) +#define CPSW_STAT_RX_OVERRUN ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x8C)) + +/* CPSW_CPDMA Registers */ +#define CPSW_CPDMA_BASE_ADR (0x4A100800) +#define CPDMA_SOFT_RESET ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x1C)) +#define CPDMA_TX_CONTROL ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x04)) +#define CPDMA_RX_CONTROL ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x14)) +#define CPDMA_CONTROL ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x20)) +#define CPDMA_STATUS ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x24)) +#define CPDMA_RX_BUFFER_OFFSET ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x28)) +#define CPDMA_EMCONTROL ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x2C)) +#define CPDMA_TX_INTMASK_SET ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x88)) +#define CPDMA_TX_INTMASK_CLEAR ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x8C)) +#define CPDMA_EOI_VECTOR ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x94)) +#define CPDMA_RX_INTMASK_SET ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0xA8)) +#define CPDMA_RX_INTMASK_CLEAR ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0xAC)) + +#define CPDMA_IDLE (1 << 31) +#define CPDMA_TX_RLIM (0xFF << 8) +#define CPDMA_NO_OFFSET (0xFFFF << 0) +#define CPDMA_RX_CEF (1 << 4) +#define CPDMA_CMD_IDLE (1 << 3) +#define RX_OFFLEN_BLOCK (1 << 2) +#define RX_OWNERSHIP (1 << 1) +#define TX_PTYPE (1 << 0) +#define CPDMA_TX_EN (1 << 0) +#define CPDMA_RX_EN (1 << 0) +#define CPDMA_FIRST_CHAN_INT (1 << 0) +#define CPDMA_ALL_CHAN_INT (0xFF << 0) +#define CPDMA_TX_PTYPE (1 << 0) +#define CPDMA_ERROR (0x00F7F700) + +/* CPSW_SS Registers */ +#define CPSW_SS_BASE_ADR (0x4A100000) +#define CPSW_SS_SOFT_RESET ((volatile u32_t *)( lan8710a_state.regs_cpsw_ss + 0x08)) +#define CPSW_SS_STAT_PORT_EN ((volatile u32_t *)( lan8710a_state.regs_cpsw_ss + 0x0C)) +#define CPSW_SS_TX_START_WDS ((volatile u32_t *)( lan8710a_state.regs_cpsw_ss + 0x20)) + +#define CPSW_P2_STAT_EN (1 << 2) +#define CPSW_P1_STAT_EN (1 << 1) +#define CPSW_P0_STAT_EN (1 << 0) + +/* CPSW_WR Registers */ +#define CPSW_WR_BASE_ADR (0x4A101200) +#define CPSW_WR_INT_CONTROL ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x0C)) +#define CPSW_WR_C0_RX_EN ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x14)) +#define CPSW_WR_C1_RX_EN ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x24)) +#define CPSW_WR_C2_RX_EN ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x34)) +#define CPSW_WR_C0_RX_STAT ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x44)) +#define CPSW_WR_C0_TX_EN ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x18)) +#define CPSW_WR_C0_TX_STAT ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x48)) + +#define CPSW_FIRST_CHAN_INT (1 << 0) +#define CPSW_ALL_CHAN_INT (0xFF << 0) + +/* INTERRUPTION CONTROLLER Registers */ +#define INTC_BASE_ADR (0x48200000) +#define INTC_SYSCONFIG ((volatile u32_t *)( lan8710a_state.regs_intc + 0x10)) +#define INTC_IDLE ((volatile u32_t *)( lan8710a_state.regs_intc + 0x50)) +#define INTC_MIR_CLEAR1 ((volatile u32_t *)( lan8710a_state.regs_intc + 0xA8)) +#define INTC_ILR(x) ((volatile u32_t *)( lan8710a_state.regs_intc + 0x100 + 4*(x))) + +#define INTC_AUTOIDLE (1 << 0) +#define INTC_FUNCIDLE (1 << 0) +#define INTC_TURBO (1 << 1) +#define INTC_FIQnIRQ (1 << 0) +#define INTC_RX_MASK (1 << 9) +#define INTC_TX_MASK (1 << 10) + +/* DMA STATERAM Registers */ +#define CPDMA_STRAM_BASE_ADR (0x4A100A00) +#define CPDMA_STRAM_TX_HDP(x) ((volatile u32_t *)( lan8710a_state.regs_cpdma_stram + 4*(x))) +#define CPDMA_STRAM_RX_HDP(x) ((volatile u32_t *)( lan8710a_state.regs_cpdma_stram + 0x20 + 4*(x))) +#define CPDMA_STRAM_TX_CP(x) ((volatile u32_t *)( lan8710a_state.regs_cpdma_stram + 0x40 + 4*(x))) +#define CPDMA_STRAM_RX_CP(x) ((volatile u32_t *)( lan8710a_state.regs_cpdma_stram + 0x60 + 4*(x))) + +#define ALL_BITS (0xFFFFFFFF) + +/* LAN8710A Registers */ +#define PHY_REGISTERS (31) +#define LAN8710A_CTRL_REG (0) +#define LAN8710A_STATUS_REG (1) + +#define LAN8710A_SOFT_RESET (1 << 15) +#define LAN8710A_AUTO_NEG (1 << 12) +#define LAN8710A_AUTO_NEG_COMPL (1 << 5) + +#endif /* LAN8710A_REG_H_ */