OpenCores
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);
	}
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.