HKC/src/platform_zynq.c
2024-10-22 16:10:27 +09:00

234 lines
6.4 KiB
C

/*
* Copyright (C) 2010 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
/*
* platform_zynq.c
*
* Zynq platform specific functions.
*
* 02/29/2012: UART initialization is removed. Timer initializations are
* removed. All unnecessary include files and hash defines are removed.
* 03/01/2013: Timer initialization is added back. Support for SI #692601 is
* added in the timer callback. The SI #692601 refers to the following issue.
*
* The EmacPs has a HW bug on the Rx path for heavy Rx traffic.
* Under heavy Rx traffic because of the HW bug there are times when the Rx path
* becomes unresponsive. The workaround for it is to check for the Rx path for
* traffic (by reading the stats registers regularly). If the stats register
* does not increment for sometime (proving no Rx traffic), the function resets
* the Rx data path.
*
* </pre>
*/
#ifdef __arm__
#include "platform_config.h"
#ifdef PLATFORM_ZYNQ
#include "xparameters.h"
#include "xparameters_ps.h" /* defines XPAR values */
#include "xil_cache.h"
#include "xscugic.h"
#include "lwip/tcp.h"
#include "xil_printf.h"
#include "netif/xadapter.h"
#include "xscutimer.h"
#include "xtime_l.h"
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define TIMER_DEVICE_ID XPAR_SCUTIMER_DEVICE_ID
#define INTC_BASE_ADDR XPAR_SCUGIC_0_CPU_BASEADDR
#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_0_DIST_BASEADDR
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR
#define RESET_RX_CNTR_LIMIT 400
void tcp_fasttmr(void);
void tcp_slowtmr(void);
static XScuTimer TimerInstance;
#ifndef USE_SOFTETH_ON_ZYNQ
static int ResetRxCntr = 0;
extern struct netif server_netif;
#endif
volatile int TcpFastTmrFlag = 0;
volatile int TcpSlowTmrFlag = 0;
#if LWIP_DHCP==1
volatile int dhcp_timoutcntr = 24;
void dhcp_fine_tmr();
void dhcp_coarse_tmr();
#endif
void
timer_callback(XScuTimer * TimerInstance)
{
/* we need to call tcp_fasttmr & tcp_slowtmr at intervals specified
* by lwIP. It is not important that the timing is absoluetly accurate.
*/
static int odd = 1;
#if LWIP_DHCP==1
static int dhcp_timer = 0;
#endif
TcpFastTmrFlag = 1;
odd = !odd;
#ifndef USE_SOFTETH_ON_ZYNQ
ResetRxCntr++;
#endif
if (odd) {
TcpSlowTmrFlag = 1;
#if LWIP_DHCP==1
dhcp_timer++;
dhcp_timoutcntr--;
dhcp_fine_tmr();
if (dhcp_timer >= 120) {
dhcp_coarse_tmr();
dhcp_timer = 0;
}
#endif
}
/* For providing an SW alternative for the SI #692601. Under heavy
* Rx traffic if at some point the Rx path becomes unresponsive, the
* following API call will ensures a SW reset of the Rx path. The
* API xemacpsif_resetrx_on_no_rxdata is called every 100 milliseconds.
* This ensures that if the above HW bug is hit, in the worst case,
* the Rx path cannot become unresponsive for more than 100
* milliseconds.
*/
#ifndef USE_SOFTETH_ON_ZYNQ
if (ResetRxCntr >= RESET_RX_CNTR_LIMIT) {
xemacpsif_resetrx_on_no_rxdata(&server_netif);
ResetRxCntr = 0;
}
#endif
XScuTimer_ClearInterruptStatus(TimerInstance);
}
void platform_setup_timer(void)
{
int Status = XST_SUCCESS;
XScuTimer_Config *ConfigPtr;
int TimerLoadValue = 0;
ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
Status = XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
xil_printf("In %s: Scutimer Cfg initialization failed...\r\n",
__func__);
return;
}
Status = XScuTimer_SelfTest(&TimerInstance);
if (Status != XST_SUCCESS) {
xil_printf("In %s: Scutimer Self test failed...\r\n",
__func__);
return;
}
XScuTimer_EnableAutoReload(&TimerInstance);
/*
* Set for 250 milli seconds timeout.
*/
TimerLoadValue = XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 8;
XScuTimer_LoadTimer(&TimerInstance, TimerLoadValue);
return;
}
void platform_setup_interrupts(void)
{
Xil_ExceptionInit();
XScuGic_DeviceInitialize(INTC_DEVICE_ID);
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_DeviceInterruptHandler,
(void *)INTC_DEVICE_ID);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
XScuGic_RegisterHandler(INTC_BASE_ADDR, TIMER_IRPT_INTR,
(Xil_ExceptionHandler)timer_callback,
(void *)&TimerInstance);
/*
* Enable the interrupt for scu timer.
*/
XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, TIMER_IRPT_INTR);
return;
}
void platform_enable_interrupts()
{
/*
* Enable non-critical exceptions.
*/
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
XScuTimer_EnableInterrupt(&TimerInstance);
XScuTimer_Start(&TimerInstance);
return;
}
void init_platform()
{
platform_setup_timer();
platform_setup_interrupts();
return;
}
void cleanup_platform()
{
Xil_ICacheDisable();
Xil_DCacheDisable();
return;
}
u64_t get_time_ms()
{
#define COUNTS_PER_MILLI_SECOND (COUNTS_PER_SECOND/1000)
XTime tCur = 0;
XTime_GetTime(&tCur);
return (tCur/COUNTS_PER_MILLI_SECOND);
}
#endif
#endif