URL
https://opencores.org/ocsvn/xenie/xenie/trunk
Subversion Repositories xenie
[/] [xenie/] [trunk/] [examples/] [Eth_example/] [mb_fw/] [xenie_eth_test_womtd/] [src/] [main.c] - Rev 13
Compare with Previous | Blame | View Log
/****************************************************************************** ** ** (C) Copyright 2013 DFC Design, s.r.o., Brno, Czech Republic ** Author: Marek Kvas (m.kvas@dspfpga.com) ** **************************************************************************** ** ** This file is part of Xenia Ethernet Example project. ** ** Xenia Ethernet Example project is free software: you can ** redistribute it and/or modify it under the terms of ** the GNU Lesser General Public License as published by the Free ** Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** Xenia Ethernet Example project is distributed in the hope that ** it will be useful, but WITHOUT ANY WARRANTY; without even ** the implied warranty of MERCHANTABILITY or FITNESS FOR A ** PARTICULAR PURPOSE. See the GNU Lesser General Public License ** for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with Xenia Ethernet Example project. If not, ** see <http://www.gnu.org/licenses/>. **************************************************************************** */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <xil_cache.h> #include <sleep.h> #include <xintc.h> #include <xspi.h> #include <xparameters.h> #include "main.h" #include "uprintf.h" #include "build_time.h" #include "mdio.h" #include "gpio.h" #include "spansion_flash.h" #include "timers.h" #include "iic_wrap.h" #include "iic_id_eeprom.h" #include "udpip_rxaui.h" #include "eth_phy.h" #include "fw.h" /* Peripheral IDs, INTC vectors and base addresses */ #define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID #define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID #define TMRCTR_DEVICE_ID XPAR_TMRCTR_0_DEVICE_ID #define TMRCTR_INTERRUPT_ID XPAR_INTC_0_TMRCTR_0_VEC_ID #define IIC_DEVICE_ID XPAR_AXI_IIC_0_DEVICE_ID #define IIC_INTERRUPT_ID XPAR_INTC_0_IIC_0_VEC_ID #define MDIO_BASEADDR XPAR_MDIO_MASTER_TOP_0_BASEADDR /* Address of Marvell PHY on MDIO bus for Xenie board */ #define ETH_PHY_MDIO_ADDR 0 /* Addresses of UID EEPROM on IIC bus for Xenie board */ #define ID_EEPROM_IIC_ADDR 0x50 /* Default timeout of IIC operations in milliseconds*/ #define IIC_DEFAULT_TIMEOUT_MS 20 /* Macros decomposing version numbers */ #define FWREV_TO_MAJOR(A) (((A)>>8) & 0xf) #define FWREV_TO_MINOR(A) (((A)>>4) & 0xf) #define FWREV_TO_Z(A) ((A) & 0xf) #define BITREV_TO_TARGET(A) (((A)>>8) & 0xf) #define BITREV_TO_MAJOR(A) (((A)>>4) & 0xf) #define BITREV_TO_MINOR(A) ((A) & 0xf) /* * Configuration QSPI Flash slave select number * for Xenie board. */ #define SPANSION_FLASH_CS 0 /* * Number of bytes per page in the flash device. */ #define SPANSION_FLASH_PAGE_SIZE 256 /* * Instances to support device drivers */ static XSpi Spi; static XTmrCtr TimerCounterInst; static XIntc InterruptController; static struct iic_wrap_dev iic_wrap_dev; static struct iic_id_eeprom_dev iic_id_eeprom_dev; static struct spansion_flash sf_dev; static struct mdio_struct *mdio_dev_ptr; static struct phy_dev *phy_dev_ptr; /* * Offset in flash where PHY FW header is located */ #define FW_HDR_FLASH_OFFSET 0x00800000u /* System information defaults */ static struct sys_info_s sys_info = { .fwRev = 0x101, .eth_status = {-1, -1}, .uid = {00, 00, 00, 00, 00, 00}, .eth_settings = { .mac = {10, 20, 30, 40, 50, 60}, .ip = 0xc0a80a60, .netmask = 0xffffff00, }, }; /* * Setup how etherned leds should behave. * There are two LEDs on JT7-1104NL magjack that is on Xenie BB. * Green LED is connected between LED0(-) and LED1(+). * Bicolor - two terminal - led is connected between LED2 and LED3. * Green LED will indicate speed with flashing (10G = 4 flashes, * 1G = 3 flashes, ...) * Bicolor LED will indicate activity. * */ void phy_LED_setup(struct mdio_struct *mdio) { /* LED0 drive low */ mdio_write_indirect(mdio, ETH_PHY_MDIO_ADDR, 31, 0xf020, 0x0001); /* LED1 in speed blink mode */ mdio_write_indirect(mdio, ETH_PHY_MDIO_ADDR, 31, 0xf021, 0x00f9); /* LED2 blink on TX or RX activity */ mdio_write_indirect(mdio, ETH_PHY_MDIO_ADDR, 31, 0xf022, 0x0101); /* LED3 solid on RX activity - effectively changes color of * activity LED based on direction*/ mdio_write_indirect(mdio, ETH_PHY_MDIO_ADDR, 31, 0xf023, 0x0011); } /* * Reset PHY by pulling reset signal down. * It must toggle direction to commit reset state change. * Sets clock source to internal and un-reset PHY */ void phy_reset() { /* This should be set correctly by pull-ups */ gpio_set_out(GPIO0_BANK, GPIO0_ETH_PHY_CLK_SEL); /* 1 - on-board; 0 - external*/ gpio_clear_dir(GPIO0_BANK, GPIO0_ETH_PHY_CLK_SEL); /* Pull reset down - assert*/ gpio_set_dir(GPIO0_BANK, GPIO0_ETH_PHY_RESET_N); gpio_clear_out(GPIO0_BANK, GPIO0_ETH_PHY_RESET_N); /* 1 - active; 0 - reset*/ gpio_clear_dir(GPIO0_BANK, GPIO0_ETH_PHY_RESET_N); usleep(100*1000); /* Pull reset up - deassert */ gpio_set_dir(GPIO0_BANK, GPIO0_ETH_PHY_RESET_N); gpio_set_out(GPIO0_BANK, GPIO0_ETH_PHY_RESET_N); /* 1 - active; 0 - reset*/ gpio_clear_dir(GPIO0_BANK, GPIO0_ETH_PHY_RESET_N); } /* * Read bitstream version and build date from * running bitstream. */ void get_bitstream_version(struct bitstreamRev_s *rev) { uint32_t tmp; tmp = gpio_get(VERSION_GPIO_0_BANK); rev->comp_time = tmp & 0xffffff; rev->comp_date = (tmp >> 24) & 0xff; tmp = gpio_get(VERSION_GPIO_1_BANK); rev->comp_date += (tmp & 0xffff) << 8; rev->rev = (tmp >> 16) & 0xffff; } /* * Print bitstream compile time based on * info read using get_bitstream_version */ void print_bitstream_compile_time(struct bitstreamRev_s *rev) { uprintf("20%02x-%02x-%02x %02x:%02x:%02x", (rev->comp_date >> 16) & 0xff, (rev->comp_date >> 8) & 0xff, (rev->comp_date >> 0) & 0xff, (rev->comp_time >> 16) & 0xff, (rev->comp_time >> 8) & 0xff, (rev->comp_time >> 0) & 0xff); } /* Print unique identifier in MAC address format */ void print_UID(u8* uid) { uprintf("%02x-%02x-%02x-%02x-%02x-%02x", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5]); } /* Find string description of given PHY link speed */ char* phy_speed_to_string(uint16_t speed) { switch(speed) { case PHY_ADV_NONE: return("not resolved yet"); break; case PHY_SPEED_10M_HD: return("10 Mbps, half duplex"); break; case PHY_SPEED_10M_FD: return("10 Mbps, full duplex"); break; case PHY_SPEED_100M_HD: return("100 Mbps, half duplex"); break; case PHY_SPEED_100M_FD: return("100 Mbps, full duplex"); break; case PHY_SPEED_1GIG_HD: return("1 Gbps, half duplex"); break; case PHY_SPEED_1GIG_FD: return("1 Gbps, full duplex"); break; case PHY_SPEED_10GIG_FD: return("10 Gbps, full duplex"); break; case PHY_SPEED_2P5GIG_FD: return("2.5 Gbps, full duplex"); break; case PHY_SPEED_5GIG_FD: return("5 Gbps, full duplex"); break; default: return "unknown (error)"; break; } } /* * uprintf back-end function */ extern void outbyte(char c); void uprintf_backend(void *inst, const char *buf, int len) { while (len > 0) { outbyte(*buf++); len--; } } int main() { int res; struct fw_hdr_ext *fw_hdr_ext_ptr; u8 fw_maj, fw_min, fw_inc,fw_test; /* While running from DDR, enable caches */ Xil_ICacheEnable(); Xil_DCacheEnable(); /* * Init uprintf */ uprintf_init(uprintf_backend, NULL); /* Init GPIO based controls */ init_gpio_regs(); get_bitstream_version(&sys_info.bitRev); uprintf("\r\n\r\nXenie Ethernet Test v%d.%d.%d (Microblaze SW)\r\n", FWREV_TO_MAJOR(sys_info.fwRev), FWREV_TO_MINOR(sys_info.fwRev), FWREV_TO_Z(sys_info.fwRev)); uprintf("DFC Design, s.r.o.\r\n"); uprintf("Built: %s, %s\r\n\r\n", build_date, build_time); uprintf("Underlying bitstream:\r\n"); uprintf("Version: %d.%d\r\n", BITREV_TO_MAJOR(sys_info.bitRev.rev), BITREV_TO_MINOR(sys_info.bitRev.rev)); uprintf("Target board: %d \r\n", BITREV_TO_TARGET(sys_info.bitRev.rev)); uprintf("Built: "); print_bitstream_compile_time(&sys_info.bitRev); uprintf("\r\n\r\n"); /* Initialize timers that keep millisecond time */ res = timers_init(&TimerCounterInst, TMRCTR_DEVICE_ID); if(res != XST_SUCCESS) { uprintf("Cannot initialize timers\r\n"); goto failure; } /* Initialize IIC driver wrapper */ res = iic_wrap_init(&iic_wrap_dev, IIC_DEVICE_ID); if(res != XST_SUCCESS) { uprintf("Cannot initialize IIC driver\r\n"); goto failure; } /* * Initialize interrupt controller and * connect handlers of peripherals that require interrupts * (timers and iic). */ res = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); if (res != XST_SUCCESS) { uprintf("Cannot initialize XIntc driver\r\n"); goto failure; } res = XIntc_Connect(&InterruptController, TMRCTR_INTERRUPT_ID, (XInterruptHandler)XTmrCtr_InterruptHandler,(void *)&TimerCounterInst); if (res != XST_SUCCESS) { uprintf("Cannot connect timer handler to interrupt controller\r\n"); goto failure; } res = XIntc_Connect(&InterruptController, IIC_INTERRUPT_ID, (XInterruptHandler)XIic_InterruptHandler,(void *)&iic_wrap_dev.iic); if (res != XST_SUCCESS) { uprintf("Cannot connect IIC handler to interrupt controller\r\n"); goto failure; } /* Start interrupt controller */ res = XIntc_Start(&InterruptController, XIN_REAL_MODE); if (res != XST_SUCCESS) { uprintf("Cannot start XIntc\r\n"); goto failure; } /* Enable interrupts */ XIntc_Enable(&InterruptController, TMRCTR_INTERRUPT_ID); XIntc_Enable(&InterruptController, IIC_INTERRUPT_ID); /* * Initialize the exception table. */ Xil_ExceptionInit(); /* Register the interrupt controller handler with the exception table. */ Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XIntc_InterruptHandler, &InterruptController); /* Enable exceptions */ Xil_ExceptionEnable(); /* Initialize EEPROM containing UID/MAC address*/ res = iic_id_eeprom_init(&iic_id_eeprom_dev, &iic_wrap_dev, ID_EEPROM_IIC_ADDR, IIC_DEFAULT_TIMEOUT_MS); if (res != XST_SUCCESS) { uprintf("Cannot initialize IIC EEPROM with UID/MAC address driver\r\n"); goto failure; } /* Read UID/MAC */ res = iic_id_eeprom_getId(&iic_id_eeprom_dev, sys_info.uid); if (res) { uprintf("Cannot read UID/MAC from eeprom.\r\nDefault MAC will be used: "); } else { uprintf("UID/MAC address read form EEPROM: "); memcpy(sys_info.eth_settings.mac, sys_info.uid, 6); } print_UID(sys_info.eth_settings.mac); uprintf("\r\n\r\n"); /* * Initialize the SPI driver. */ res = XSpi_Initialize(&Spi, SPI_DEVICE_ID); if(res != XST_SUCCESS) { uprintf("Cannot initialize SPI driver\r\n"); goto failure; } /* * Setup SPI driver to work with flash */ res = spansion_flash_init(&sf_dev, &Spi, SPANSION_FLASH_CS); if(res != XST_SUCCESS) { goto failure; } /* * Initialize driver used to read flash in quad mode */ res = spansion_flash_quad_mode(&sf_dev); if(res != XST_SUCCESS) { goto failure; } /* * Initialize MDIO to speed about 12.5 MHz */ mdio_dev_ptr = (struct mdio_struct *)MDIO_BASEADDR; mdio_set_options(mdio_dev_ptr, 3, 1); /* Print version of phy control library that we are about to use */ uprintf("Marvel PHY control library reported this version:\r\n%s\r\n", phy_get_version_string()); /* * Try to init PHY driver and so Marvell API * If call fails we are either after power cycle * or something wrong happened to PHY and its reset is * needed. */ res = phy_init_drv(&phy_dev_ptr, ETH_PHY_MDIO_ADDR, (mdio_read_fcn_type)mdio_read_indirect, (mdio_write_fcn_type)mdio_write_indirect_nonblocking, (mdio_write_burst_fcn_type)mdio_write_indirect_burst, (void *)mdio_dev_ptr); if(res) { uprintf("Initialization of Marvell API driver failed" "- trying again after PHY reset.\r\n"); phy_reset(phy_dev_ptr); usleep(500*1000); /* try again */ res = phy_init_drv(&phy_dev_ptr, ETH_PHY_MDIO_ADDR, (mdio_read_fcn_type)mdio_read_indirect, (mdio_write_fcn_type)mdio_write_indirect_nonblocking, (mdio_write_burst_fcn_type)mdio_write_indirect_burst, (void *)mdio_dev_ptr); if(res) { uprintf("Initialization of Marvell API driver failed.\r\n"); goto failure; } } /* * Check whether PHY is running and what FW revision is being used. * If already running, skip FW upload to save some time during debugging. */ if(phy_get_fw_rev(phy_dev_ptr, &fw_maj, &fw_min, &fw_inc, &fw_test)) { uprintf("Marvell PHY is not running any FW\r\n"); } else { uprintf("Marvell PHY is currently running FW revision: %d.%d.%d.%d\r\n", fw_maj, fw_min, fw_inc, fw_test); } /* When PHY is not running any FW (after reset) it returns all 0 in version*/ if ((fw_maj == 0) & (fw_min == 0) & (fw_inc == 0) & (fw_test == 0)) { uprintf("Looking for FW in flash\r\n"); /* Find and read basic info about FW */ res = fw_find_in_flash(&sf_dev, FW_HDR_FLASH_OFFSET , &fw_hdr_ext_ptr); if (res < 0) { uprintf("FW was not found at offset 0x%08x\r\n", FW_HDR_FLASH_OFFSET); goto failure; } uprintf("FW was found:\r\n"); /* Print FW info */ fw_print_info(fw_hdr_ext_ptr); uprintf("Reading FW from flash to RAM\r\n"); /* Read FW to memory */ res = fw_read_from_flash(&sf_dev, fw_hdr_ext_ptr); if(res < 0) { uprintf("Cannot read FW from flash\r\n"); goto failure; } uprintf("Updating FW in PHY\r\n"); /* Write fw to PHY */ if (phy_update_fw(phy_dev_ptr, fw_hdr_ext_ptr->fw_data_ptr, fw_hdr_ext_ptr->fw_hdr.fw_length)) { uprintf("FW update failed\r\n"); goto failure; } else { /* if the mtdUpdateRamImage() is successful, call the mtdGetFirmwareVersion() to check it running and verify the updated version number */ sleep(1); phy_get_fw_rev(phy_dev_ptr, &fw_maj, &fw_min, &fw_inc, &fw_test); uprintf("FW updated successfully\r\n"); uprintf("Currently running FW revision: %d.%d.%d.%d\r\n", fw_maj, fw_min, fw_inc, fw_test); } } else { uprintf("PHY is already loaded and running don't reload it\r\n"); } /* Configure PHY to RGMII mode compatible with Xilinx RXAUI core */ phy_configure_xilinx_rgmii(phy_dev_ptr); /* Reset Xilinx RXAUI core */ rxaui_core_reset(); /* Change default LED behavior to something meaningful for Xenie baseboard*/ phy_LED_setup(mdio_dev_ptr); /* Enable only full-duplex modes as UDP/IP core doesn't support half-duplex */ phy_enable_speeds(phy_dev_ptr, PHY_SPEED_10M_FD | PHY_SPEED_100M_FD | PHY_SPEED_1GIG_FD | PHY_SPEED_10GIG_FD | PHY_SPEED_2P5GIG_FD | PHY_SPEED_5GIG_FD); /* * Put UDP/IP core to reset (it is by default anyway) * Set network information for UDP/IP core. * Core should be in reset because of CDC is not implemented * for this interface. */ udp_ip_core_reset(1); udpip_core_set_host_info(sys_info.eth_settings.mac, sys_info.eth_settings.ip, sys_info.eth_settings.netmask); uprintf("Initialization successful.\r\n\r\n"); /* * Periodically check Link speed and change it for throttling */ while(1) { uint16_t speed; int link; res = phy_is_baseT_up(phy_dev_ptr, &speed, &link); if(res) { uprintf("Cannot get autonegotioation and link status\r\n"); sys_info.eth_status.link_up = -1; sys_info.eth_status.speed = -1; } else { if(sys_info.eth_status.speed != speed) { udp_ip_core_reset(1); udpip_core_set_speed(speed); uprintf("Current link speed is %s\r\n", phy_speed_to_string(speed)); udp_ip_core_reset(0); } if(sys_info.eth_status.link_up != link) { uprintf("Link is %s\r\n", (link)?"UP":"DOWN"); } sys_info.eth_status.link_up = link; sys_info.eth_status.speed = speed; } usleep(100*1000); } failure: while(1) { uprintf("Initialization failed - restart is needed\r\n"); sleep(1); } }