blob: 56aac567f54683ca716dd7d6d7705394c43b438b [file] [log] [blame]
/*
* diags/test_pcie.c
*
* Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <types.h>
#include <common.h>
#include <asm/io.h>
#include <mach/comcerto-2000.h>
#include <mach/pcie.h>
#include <mach/serdes.h>
#include <mach/clkcore.h>
#include <mach/gpio.h>
#include <diags.h>
#include "test_pcie.h"
#include "tests.h"
#include "dump.h"
#include "common_func.h"
#include "serdes_common.h"
#include "PCIeMacro.h"
#include "PCIe.c"
#define U8 u8
#define PCI_VENDOR_ID 0x00 /* 16 bits */
#define PCI_DEVICE_ID 0x02 /* 16 bits */
#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
/* DWC PCIEe configuration register offsets on APB */
struct pcie_app_reg app_regs[NUM_PCIE_PORTS] = {
//PCIe0
{ 0x00000000,
0x00000004,
0x00000008,
0x0000000C,
0x00000010,
0x00000014,
0x00000018,
0x00000040,
0x00000044,
0x00000048,
0x00000058,
0x00000080,
0x00000084,
0x000000C0,
0x000000C4,
0x00000100,
0x00000104,
0x00000108,
0x0000010C
},
//PCIe1
{ 0x00000020,
0x00000024,
0x00000028,
0x0000002C,
0x00000030,
0x00000034,
0x00000038,
0x0000004C,
0x00000050,
0x00000054,
0x0000005C,
0x00000088,
0x0000008C,
0x000000C8,
0x000000CC,
0x00000110,
0x00000114,
0x00000118,
0x0000011C
}
};
/* Keeping all DDR area of 256MB accesible for inbound transaction */
#define INBOUND_ADDR_MASK 0xFFFFFFF
#define PCIE_SETUP_iATU_IB_ENTRY( _pp, _view_port, _base, _limit, _ctl1, _ctl2, _target ) \
{\
comcerto_dbi_write_reg(_pp, PCIE_iATU_VIEW_PORT, 4, (u32)(_view_port|iATU_VIEW_PORT_IN_BOUND)); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL2, 4, 0); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_SRC_LOW, 4, (u32)_base); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_SRC_HIGH, 4, 0); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_LIMIT, 4, (u32)_limit); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_TRGT_LOW, 4, (u32)_target); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_TRGT_HIGH, 4, (u32)0); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL1, 4, (u32)_ctl1); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL2, 4, (u32)(_ctl2 |iATU_CTRL2_ID_EN) ); \
}
#define PCIE_SETUP_iATU_OB_ENTRY( _pp, _view_port, _base, _limit, _ctl1, _ctl2, _target ) \
{\
comcerto_dbi_write_reg(_pp, PCIE_iATU_VIEW_PORT, 4, (u32)_view_port); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL2, 4, 0); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_SRC_LOW, 4, (u32)_base); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_SRC_HIGH, 4, (u32)0); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_LIMIT, 4, (u32)_limit); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_TRGT_LOW, 4, (u32)_target); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_TRGT_HIGH, 4, (u32)0); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL1, 4, (u32)_ctl1); \
comcerto_dbi_write_reg(_pp, PCIE_iATU_CTRL2, 4, (u32)(_ctl2 |iATU_CTRL2_ID_EN) ); \
}
//#define MAX_LINK_UP_WAIT_JIFFIES 100
#define MAX_LINK_UP_WAIT_JIFFIES 0xfff
#define PCI_SLOT(d) (((d) >> 3) & 0x1f)
#define PCI_FUNC(d) (((d) >> 8) & 0x7)
static struct pcie_port pcie_port[NUM_PCIE_PORTS];
static int initialized[NUM_PCIE_PORTS] = {0, 0};
/**
* This function checks whether link is up or not.
* Returns true if link is up otherwise returns false.
* @param pp Pointer to PCIe Port control block.
*/
static int comcerto_pcie_link_up( struct pcie_port *pp )
{
unsigned long timeout = MAX_LINK_UP_WAIT_JIFFIES;
do {
if (readl( pp->app_base + pp->app_regs->sts0 ) & STS0_RDLH_LINK_UP) {
printf("PCIe Link up: Ok\n");
return 1;
}
mdelay(1);
} while (timeout--);
printf("PCIe Link up: failed\n");
return 0;
}
/**
* This function is used to read DBI registers.
*/
static void comcerto_dbi_read_reg(struct pcie_port *pp, int where, int size,
u32 *val)
{
u32 address;
address = (u32)pp->base + (where & ~0x3);
*val = readl(address);
if (size == 1)
*val = (*val >> (8 * (where & 3))) & 0xff;
else if (size == 2)
*val = (*val >> (8 * (where & 3))) & 0xffff;
}
/**
* This function is used to write into DBI registers.
*/
static void comcerto_dbi_write_reg(struct pcie_port *pp, int where, int size,
u32 val)
{
u32 address;
int pos, val1, mask = 0;
//printk("%s: start\n", __func__);
address = (u32)pp->base + (where & ~0x3);
pos = (where & 0x3) << 3;
if (size == 4)
val1 = val;
else
{
if (size == 2)
mask = 0xffff;
else if (size == 1)
mask = 0xff;
val1 = readl(address);
val1 = ( val1 & ~( mask << pos ) ) | ( (val & mask) << pos );
}
//printk("%s: address: %08x, val: %08x\n", __func__, address, val1);
writel(val1, address);
//printk("%s: done\n", __func__);
}
static int comcerto_pcie_rd_conf(struct pcie_port *pp, int bus_nr,
u32 devfn, int where, int size, u32 *val)
{
u32 address;
u32 target_address = (u32)(bus_nr << 24) | (PCI_SLOT(devfn) << 19) | (PCI_FUNC(devfn) << 16);
//Initialize iATU
if (bus_nr != pp->root_bus_nr) {
/* Type1 configuration request */
PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_CNF1, (u32)pp->cfg1_base,
((u32)(pp->cfg1_base + (iATU_CFG1_SIZE - 1))),
(AXI_OP_TYPE_CONFIG_RDRW_TYPE1 & iATU_CTRL1_TYPE_MASK),
0, target_address );
address = (u32)pp->cfg1_base |(where & 0xFFFC);
} else {
/* Type0 configuration request */
PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_CNF0, (u32)pp->cfg0_base,
((u32)(pp->cfg0_base + (iATU_CFG0_SIZE - 1))),
(AXI_OP_TYPE_CONFIG_RDRW_TYPE0 & iATU_CTRL1_TYPE_MASK),
0, target_address );
address = (u32)((pp->cfg0_base)|(where & 0xFFFC));
}
//printf("%s: %08x\n", __func__, address);
*val = readl(address);
if (size == 1)
*val = (*val >> (8 * (where & 3))) & 0xff;
else if (size == 2)
*val = (*val >> (8 * (where & 3))) & 0xffff;
return 0;
}
static int pcie_read_conf(struct pcie_port *pp, int bus_nr, u32 devfn, int where, int size, u32 *val)
{
int ret;
/* Make sure that link is up.
* Filter device numbers, unless it's a type1 access
*/
if ( (!pp->link_state)||
((bus_nr == pp->root_bus_nr) && (PCI_SLOT(devfn) > 0)) ) {
*val = 0xffffffff;
return -1;
}
BUG_ON (((where & 0x3) + size) > 4);
ret = comcerto_pcie_rd_conf(pp, bus_nr, devfn, where, size, val);
return ret;
}
static int comcerto_pcie_wr_conf(struct pcie_port *pp, int bus_nr,
u32 devfn, int where, int size, u32 val)
{
int ret = 0;
u32 address;
u32 target_address = (u32)(bus_nr << 24) | (PCI_SLOT(devfn) << 19) | (PCI_FUNC(devfn) << 16);
//Initialize iATU
if (bus_nr != pp->root_bus_nr) {
/* Type1 configuration request */
PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_CNF1, (u32)pp->cfg1_base,
((u32)(pp->cfg1_base + (iATU_CFG1_SIZE - 1))),
(AXI_OP_TYPE_CONFIG_RDRW_TYPE1 & iATU_CTRL1_TYPE_MASK),
0, target_address );
address = (u32)pp->cfg1_base |(where & 0xFFFC);
} else {
/* Type0 configuration request */
PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_CNF0, (u32)pp->cfg0_base,
((u32)(pp->cfg0_base + (iATU_CFG0_SIZE - 1))),
(AXI_OP_TYPE_CONFIG_RDRW_TYPE0 & iATU_CTRL1_TYPE_MASK),
0, target_address );
address = (u32)pp->cfg0_base |(where & 0xFFFC);
}
if (size == 4)
writel(val, address);
else if (size == 2)
writew(val, address + (where & 2));
else if (size == 1)
writeb(val, address + (where & 3));
else
ret = -1;
return ret;
}
static int pcie_write_conf(struct pcie_port *pp, int bus_nr, u32 devfn, int where, int size, u32 val)
{
int ret;
/* Make sure that link is up.
* Filter device numbers, unless it's a type1 access
*/
if ( (!pp->link_state)||
((bus_nr == pp->root_bus_nr) && (PCI_SLOT(devfn) > 0)) ) {
return -1;
}
BUG_ON (((where & 0x3) + size) > 4);
ret = comcerto_pcie_wr_conf(pp, bus_nr, devfn, where, size, val);
return ret;
}
static void __init pcie_port_init_rc(int port)
{
struct pcie_port *pp = &pcie_port[port];
//printf("%s: start \n", __func__);
/* Fixme : Added Venkat */
writel((readl(pp->base + 0x70C) & ~(0x00ffff00))| 0x00F1F100, pp->base + 0x70C);
writel((readl(pp->base + 0x80C) & ~(0xff))|0xF1, pp->base + 0x80C);
/*setup iATU for outbound translation */
PCIE_SETUP_iATU_OB_ENTRY( pp, iATU_ENTRY_MEM, iATU_GET_MEM_BASE(pp->remote_mem_baseaddr),
iATU_MEM_SIZE - 1, 0, 0, pp->remote_mem_baseaddr );
/*setup iATU for inbound translation */
comcerto_dbi_write_reg(pp, PCI_BASE_ADDRESS_0, 4, 0);
PCIE_SETUP_iATU_IB_ENTRY( pp, 0, 0,
INBOUND_ADDR_MASK, 0, (iATU_CTRL2_IB_MEM_BAR_MATCH |
iATU_CTRL2_IB_MATCH_BAR0), COMCERTO_AXI_ACP_BASE );
//FIXME : Bit:27 definition is not clear from document
// This register setting is copied from simulation code.
writel(readl(pp->app_base + pp->app_regs->cfg0) | 0x08007FF0,
pp->app_base + pp->app_regs->cfg0);
//FIXME : Bit:15 definition is not clear from document
// This register setting is copied from simulation code.
writel(readl(pp->app_base + pp->app_regs->cfg4) | 0x00008000,
pp->app_base + pp->app_regs->cfg4);
writel(readl(pp->app_base + pp->app_regs->cfg5) | (CFG5_APP_INIT_RST | CFG5_LTSSM_ENABLE),
pp->app_base + pp->app_regs->cfg5);
//printf("%s: done \n", __func__);
}
static unsigned long pcie_cnf_base_addr[NUM_PCIE_PORTS] =
{ COMCERTO_AXI_PCIe0_CFG_BASE, COMCERTO_AXI_PCIe1_CFG_BASE };
static unsigned long pcie_remote_base_addr[NUM_PCIE_PORTS] =
{ COMCERTO_AXI_PCIe0_SLV_BASE, COMCERTO_AXI_PCIe1_SLV_BASE };
static int comcerto_pcie_init( struct pcie_port *pp, int nr)
{
if (nr >= NUM_PCIE_PORTS) {
printf("%s : Invalid PCIe port number\n", __func__);
return 1;
}
memset(pp, 0, sizeof(struct pcie_port));
pp->app_regs = &app_regs[nr];
pp->root_bus_nr = nr;
pp->base = pcie_cnf_base_addr[nr];
pp->app_base = (unsigned long)COMCERTO_PCIE_SATA_USB_CTRL_BASE;
pp->remote_mem_baseaddr = pcie_remote_base_addr[nr];
pp->cfg0_base = iATU_GET_CFG0_BASE(pp->remote_mem_baseaddr);
pp->cfg1_base = iATU_GET_CFG1_BASE(pp->remote_mem_baseaddr);
if (!nr) {
//writel( readl( AXI_RESET_2 ) | PCIE0_AXI_RST, AXI_RESET_2 );
writel( readl( AXI_RESET_2 ) & ~PCIE0_AXI_RST, AXI_RESET_2 );
//writel( readl( SERDES_RST_CNTRL ) | (SERDES0_RST), SERDES_RST_CNTRL );
writel( readl( SERDES_RST_CNTRL ) & ~(SERDES0_RST), SERDES_RST_CNTRL );
//step-3
/* Put PCIE0 and PCIe1 into reset */
//FIXME : This code is copied from simulation samples,
// Making reset bits to 1 might not be required
// Need to be cleanup after tested.
//writel( readl( PCIe_SATA_RST_CNTRL ) | (PCIE0_PWR_RST|PCIE0_REG_RST), PCIe_SATA_RST_CNTRL );
writel( readl( PCIe_SATA_RST_CNTRL ) & ~(PCIE0_PWR_RST|PCIE0_REG_RST), PCIe_SATA_RST_CNTRL );
/* Configure PCIe0 to Root complex mode */
writel( (readl(pp->app_base + pp->app_regs->cfg0) &
~DWC_CFG0_DEV_TYPE_MASK) | PCIE_PORT_MODE_RC,
pp->app_base + pp->app_regs->cfg0);
/* Enable clocks */
//FIXME : No clock configurtaion register found for SerDes.
// Need to discuss with VLSI team.
//FIXME : By default PCIe is configured in Gen2 mode. Need to
// verify if any setting required to switch to Gen1 mode.
writel( readl( AXI_CLK_CNTRL_2 )| AXI_PCIE0_CLK_EN, AXI_CLK_CNTRL_2);
pp->port_mode = PCIE_PORT_MODE_RC;
}else {
if ( !(readl(COMCERTO_GPIO_SYSTEM_CONFIG) & BOOTSTRAP_SERDES1_CNF_SATA0) ) {
u32 ctrl_reg;
printf("%s: Boot strap configured for PCIe1\n",__func__);
//writel( readl( AXI_RESET_2 ) | PCIE1_AXI_RST, AXI_RESET_2 );
writel( readl( AXI_RESET_2 ) & ~PCIE1_AXI_RST, AXI_RESET_2 );
//writel( readl( SERDES_RST_CNTRL ) | (SERDES1_RST), SERDES_RST_CNTRL );
writel( readl( SERDES_RST_CNTRL ) & ~(SERDES1_RST), SERDES_RST_CNTRL );
//FIXME : This code is copied from simulation samples,
// Making reset bits to 1 might not be required
// Need to be cleanup after tested.
//writel( readl( PCIe_SATA_RST_CNTRL ) | (PCIE1_PWR_RST|PCIE1_REG_RST), PCIe_SATA_RST_CNTRL );
writel( readl( PCIe_SATA_RST_CNTRL ) & ~(PCIE1_PWR_RST|PCIE1_REG_RST), PCIe_SATA_RST_CNTRL );
/* Configure PCIe1 to Root complex mode */
writel( (readl(pp->app_base + pp->app_regs->cfg0) &
~DWC_CFG0_DEV_TYPE_MASK ) | PCIE_PORT_MODE_RC,
pp->app_base + pp->app_regs->cfg0);
pp->port_mode = PCIE_PORT_MODE_RC;
//FIXME: MOULI
//As per VLSI code sequence for Serdes-1
ctrl_reg = COMCERTO_SERDES_DWC_CFG_REG( 1, SD_PHY_CTRL3_REG_OFST );
writel(0xFF3C, ctrl_reg);
ctrl_reg = COMCERTO_SERDES_DWC_CFG_REG( 1, SD_PHY_CTRL2_REG_OFST );
writel(readl(ctrl_reg) & ~0x3, ctrl_reg);
writel( readl( AXI_CLK_CNTRL_2 )| AXI_PCIE1_CLK_EN, AXI_CLK_CNTRL_2);
}
else {
pp->port_mode = PCIE_PORT_MODE_NONE;
return 1;
}
}
//Serdes Initialization.
if( serdes_phy_init(nr, pcie_phy_reg_file,
sizeof(pcie_phy_reg_file) / sizeof(serdes_regs_t),
SD_DEV_TYPE_PCIE) )
{
pp->port_mode = PCIE_PORT_MODE_NONE;
pr_err("%s: Failed to initialize serdes (%d)\n", __func__, nr );
return 1;
}
//Synopsys PCIe core initialization.
pcie_port_init_rc(nr);
pp->link_state = comcerto_pcie_link_up( &pcie_port[nr] );
return 0;
}
int comcerto_pcie_port_test (unsigned int pcie_host_nr)
{
u32 value;
struct pcie_port *pp;
unsigned int addr = PCI_VENDOR_ID;
unsigned int devfn = 0;
if (pcie_host_nr >= NUM_PCIE_PORTS) {
printf("%s : Invalid port number (%d)\n", __func__, pcie_host_nr);
return 1;
}
value = 0xffffffff;
printf("\nPCIe%d Root complex test:\n", pcie_host_nr);
pp = &pcie_port[pcie_host_nr];
if (!initialized[pcie_host_nr])
{
if ( comcerto_pcie_init(pp, pcie_host_nr) ) {
printf("comcerto_pcie_init failed\n");
return 1;
}
initialized[pcie_host_nr] = 1;
}
printf("\n==============PCIE%d TEST RESULT==============\n", pcie_host_nr);
if ( pp->port_mode == PCIE_PORT_MODE_NONE ) {
printf("PCIe%d controller is not enabled.........!!!\n", pcie_host_nr);
return 1;
}
if ( ( pp->port_mode == PCIE_PORT_MODE_RC ) && ( pp->link_state ) )
{
pcie_read_conf(pp, pcie_host_nr, devfn, addr, 0x4, &value);
if(value != 0xffffffff)
{
printf("PCIe Lane %d: Connected Device Vendor_ID: [0x%04X] Device_ID: [0x%04X] .... TEST PASS\n", pcie_host_nr, (value & 0xFFFF), ((value >> 16) & 0xFFFF));
}
else
{
printf("PCIe Lane %d: Vendor and Device Id not found for the device.....TEST FAIL\n", pcie_host_nr);
return 1;
}
}
else
{
printf("PCIe Lane %d: Link Down Or Controller is not Root Complex......... TEST FAIL\n", pcie_host_nr);
return 1;
}
return 0;
}
int comcerto_pcie_rc_test (struct diags_test_param *p)
{
int rc0, rc1;
rc0 = comcerto_pcie_port_test (0);
rc1 = comcerto_pcie_port_test (1);
return rc0 | rc1;
}
int comcerto_pcie_ep_test (struct diags_test_param *p)
{
printf("\n PCIE endpoint diags is not yet supported ....\n");
return 0;
}
#define SERDES_RST_CNTRL 0x904B0004
#define PCIE_SATA_RST_CNTRL 0x904B0008
#define GPIO_BASE 0x90470000
// MDMA stuff
#define MDMA_BASE 0x905E0000
#define S_frame_1 0x40002000 // Source 1 Frame
#define S_data_1 0x40006000 // Source Data1 Buffer
#define D_frame_1 0x20014000 // Destination 1 Frame
// copy to PCIE
#define D_data_1 0xA0000000 // Destination 1 Frame
//#define LOOPBACK_DEST 0X83000000
#define LOOPBACK_DEST 0X70000000
#define MAX_DATA 0X2000 // make it 32K/4
//#define MAX_DATA 0X0400 // make it
// MAX number of DMA TRANSFER ITERNATIONS
#define MAX_DATA_MASK 0x01FFF // number of bits for max data divided by 4
#define RANDOM_DATA_SIZE 1
#define MAX_ITER 100000
#define DEBUG 0
// macro to generate LSFR data
// linear shift feedback register to generate psaudo random numbers to fill initial data
#define LSFR( X ) (X << 1 | (X >> 10 & (((X >> 10) & 1) ^((X >> 3) & 1) ^ ((X >> 0) & 1))))
// random input dwords
//U32 input_dw[3] = {0xab9304c2, 0xf02cb631,0xa2b3c910};
//U32 random_size_cur = 0xab9304c2; //seed for LSFR random
U32 random_size_cur = 0xab930002; //seed for LSFR random
U32 random_min_size = MAX_DATA_MASK;
U32 random_max_size = 0;
U32 p_mode=1; // 1 for random, 2 for counter, 3 for fixed pattern (0xA5A5A5A5)
U32 rd_data, data_pattern = 0xA5A5A5A5;
U32 input_data_counter = 0;
U32 output_data_counter = 0;
U32 total_errors = 0;
U8 gen1_only = 0;
U32 tlp_size_v = 0x2000; // divided by 4
int comcerto_pcie_perf_test (struct diags_test_param *p)
{
int ret = -1;
// Offset Variable
U32 offset = 0x60;
U32 i, j, k,temp, lsfr_data, max_iter_v;
U32 rd_data;
U32 check_bit;
U32 SD0_Ctrl_Reg_offset = 0x34;
U32 SD1_Ctrl_Reg_offset = 0x44;
U32 SD1_Ctrl_Reg_Sel_offset = 0x48;
U32 CMU_Reset_mask = 0x00010000;
U32 Lane_Reset_mask = 0x00000040;
U32 ck_soc_div_mask = 0x00000003;
U8 lanedone = 0;
// ######################################################################################
// Prompt user for Test parameters
// ######################################################################################
printf("########################################\n");
printf("PCIE loopback test, you need to plug external card for this test.\n");
printf("PCIE loopback test, PCIe Gen2/Gen1 support\n");
gen1_only = 0;
//printf("PCIE loopback test, Enter below.\n 1: PCIe Gen1 only support, \n 2: PCIe Gen2/Gen1 support\n");
//scanf("%d", & temp);
//if(temp==1)
// gen1_only = 1;
//else
// gen1_only = 0;
/*
printf("PCIE loopback test, Enter below.\n 1:24Mhz clock, \n2: 48Mhz clock, \n 3: 100MHz clock\n");
scanf("%d", & temp);
if(temp==1)
clock_24Mhz = 1;
else if (temp==2)
clock_48Mhz = 1;
*/
printf("Number of Iterations is 10,000; about two minutes run\n");
max_iter_v = 10000;
//printf("Enter number of Iterations, 10,000 is about two minutes run\n");
//scanf("%d", & temp);
//if (temp > 0){
// max_iter_v = temp;
// printf("Number of iterations is changed to %d\n", max_iter_v);
// }
// else{
// max_iter_v = 10000;
// printf("You entered invalid value, using iterations %d\n", max_iter_v);
// }
printf("###################### Now the test will run ########################################\n");
//#######################################################################################
// reset pcie card
printf("reset mpcie 1\n");
reg_rmw((GPIO_BASE+ 0x0),0x08000000, 0x08000000);
// output enable
reg_rmw((GPIO_BASE+ 0x4),0x08000000, 0x08000000);
nop(400000);
printf("reset mpcie 0\n");
reg_rmw((GPIO_BASE+ 0x0),0x08000000, 0x00000000);
nop(400000);
printf("reset mpcie 1\n");
reg_rmw((GPIO_BASE+ 0x0),0x08000000, 0x08000000);
nop(400000);
// Making PCIE #0 serdes active
reg_rmw(SERDES_RST_CNTRL, 0x00000001, 0x00000000 );
//Making PCIE Controller active
reg_rmw(PCIE_SATA_RST_CNTRL, 0x00000003, 0x00000000 );
//===========================================================
// change below to force Gen1 or Gen2
// turn on support for Gen1 only
if (gen1_only){
printf("Force to Gen1, Writing to link control 2 0x1\n");
reg_rmw(PCIE0_LCNT2_REG, 0x0000000f, 0x1);
reg_rmw(PCIE0_LCAP_REG, 0x0000000f, 0x1);
}
// instruct pcie to switch to gen2 after init
// set bit 17=1 (page 824)
if (gen1_only==0){
reg_rmw(PCIE0_G2CTRL_REG,0x00020000, 0x00020000);
}
//===============================================================
//Configure PCIEO as RC
reg_wr(DWC_CFG_REG0, 0x08007ff4);
reg_wr(DWC_CFG_REG4, 0x00008000);
reg_wr(DWC_CFG_REG5, 0x00000206);
// ####################### init pcie card is moved to inside sbphy_init* in serdes_common.h
// // To take the external card out of reset configure GPIO27 to be an output (to drive 0)
// //Configure GPIO output Enable
// reg_rmw((GPIO_BASE+ 0x0),0x08000000, 0x0);
// // 0x4 is for output enable
// reg_rmw((GPIO_BASE+ 0x4),0x08000000, 0x08000000);
// // Configure GPIO Output register---GPIO_OUT to be 1
// // Making WifiCard reset is Active High to Active WiFiCard
// //reg_rmw((GPIO_BASE+ 0x0),0x08000000, 0x08000000); //dror
//Serdes initilzation happens here
sbphy_init_wait_lane_rdy(true, false, false, 0, 0, false, false, true);
// bhimsens setup hy settings
//reg_wr((SD0_CFG_BASE+ (0x206 << 2)), 0xC4);
//reg_wr((SD0_CFG_BASE+ (0x207 << 2)), 0x34);
//reg_wr((SD0_CFG_BASE+ (0x250 << 2)), 0xF6);
//reg_wr((SD0_CFG_BASE+ (0x251 << 2)), 0x07);
// new settings for tx_lev
//printf("TEST: %D: setting reg 0x207 of SD0 at 0x%X \n", k, (tx_lev_values_rev[k]<<2));
//reg_wr((SD0_CFG_BASE+ (0x207 << 2)), (tx_lev_values_rev[k]<<2) );
// wait for serdes to get ready
// wait_sb_cmu_lane_rdy(0, true, false, true);
//Ack Frequency and L0-L1 ASPM Control Register
// rd_data = reg_rd(PCIE0_AFL0L1_REG);
// printf("A=0x%x d=0x%x \n", PCIE0_AFL0L1_REG, rd_data);
reg_rmw( PCIE0_AFL0L1_REG , 0x00FFFF00 , 0x00F1F100 );
//Gen2 Control Control Register
// rd_data = reg_rd(PCIE0_G2CTRL_REG);
// printf("A=0x%x d=0x%x \n", PCIE0_G2CTRL_REG, rd_data);
reg_rmw( PCIE0_G2CTRL_REG , 0x000000FF , 0x000000F1 );
//Symbol Number Register
//rd_data = reg_rd(PCIE0_SYMNUM_REG);
//printf("Addr = 0x%x rd=0x%x \n", PCIE0_SYMNUM_REG, rd_data);
printf("check link status!\n");
PCIE0_link_up_chk();
printf("Link is UP!!!\n");
//Register Initialization (MEM_SPACE_EN_Enable + BUS_MASTER_EN_Enable + CAP_LIST_Enable)
reg_wr(PCIE0_CMD_REG, 0x00100006);
//printf("ATU programming!\n");
// Outbound Programming to generate Configuration trnasctions
// reg_wr(PCIE0_iATU_VIEW_REG, 0x00000000);
/* Set Region Base and Limit */
//reg_wr(PCIE0_iATU_RLBA_REG, 0xA0000000); //PCIE Base Address
//reg_wr(PCIE0_iATU_RLIA_REG, 0xA00000FF); //PCIE Limit Address
/* Set Target Address to 0x00000000 */
//reg_wr(PCIE0_iATU_RLTA_REG, 0x01000000);
/* Set Control1 Register : Region to be CFG */
//reg_wr(PCIE0_iATU_CTL1_REG, 0x00000004);
/* Enable the Region */
//reg_wr(PCIE0_iATU_CTL2_REG, 0x80000000);
//Reading Device ID and Vendor ID of External WiFI card
//rd_data = reg_rd(0xA0000000);
//printf("Read Device and Vendor ID Reg = 0x%x\n", rd_data);
//Reading Device ID and Vendor ID of External WiFI card
//rd_data = reg_rd(0xA0000004);
//printf("Read Status and Cmd Reg = 0x%x\n", rd_data);
// type 0 config write to enable Bus master enable and Memory Space enable of External WiFI card
//rd_data |= 0x6;
//reg_wr(0xA0000004, rd_data);
//printf("Enable Bus master and Memory Space in Cmd Reg\n");
//rd_data = reg_rd(0xA0000004);
//printf("Read Status and Cmd Reg = 0x%x\n", rd_data);
//Reading the BAR0 External WiFI Card Configuration Space
//rd_data = reg_rd(0xA0000010);
//printf("Read BAR0 = 0x%x\n", rd_data);
//while (1);
//Register Initialization (MEM_SPACE_EN_Enable + BUS_MASTER_EN_Enable + CAP_LIST_Enable)
reg_wr(PCIE0_CMD_REG, 0x00100006);
//Type0 COfig write to write 0xA0000000 Address in BAR0 of External WiFI Card
//reg_wr(0xA0000010 , 0xA0000000);
//Set iATU Registers (Outbound) page 840
/* Set Viewport */
reg_wr(PCIE0_iATU_VIEW_REG, 0x00000001);
/* Set Region Base and Limit */
reg_wr(PCIE0_iATU_RLBA_REG, 0xA0000000); //PCIE Base Address
reg_wr(PCIE0_iATU_RLIA_REG, 0xA000FFFF); //PCIE Limit Address
/* Set Target Address to 0xA0000000 */
reg_wr(PCIE0_iATU_RLTA_REG, 0xA0000000);
/* Set Control1 Register : Region to be MEM */
reg_wr(PCIE0_iATU_CTL1_REG, 0x00000000);
/* Enable the Region */
reg_wr(PCIE0_iATU_CTL2_REG, 0x80000000);
//Set iATU Registers (Inbound)
/* Set Viewport */
reg_wr(PCIE0_iATU_VIEW_REG, 0x80000001);
/* Set Target Address to Empty space in DDR (0x7FFE_0000) */
reg_wr(PCIE0_iATU_RLTA_REG, LOOPBACK_DEST);
/* Set Control1 Register : Region to be MEM */
reg_wr(PCIE0_iATU_CTL1_REG, 0x00000000);
/* Enable the Region */
reg_wr(PCIE0_iATU_CTL2_REG, 0xC0000000);
//reg_wr(PCIE0_iATU_CTL2_REG, 0x00000000);
//Register Initialization (MEM_SPACE_EN_Enable + BUS_MASTER_EN_Enable + CAP_LIST_Enable)
reg_wr(PCIE0_CMD_REG, 0x00100006);
printf("after ATU programming!\n");
/* Write to BAR0 */
reg_wr(PCIE0_BAR0_REG, 0xA0000000);
printf("\n\nLoopback Enabled\n");
// set PCIE in loopback mode
// set bit 2 (page 765)
reg_rmw( PCIE0_PL_REG + 0x10 , 0x00000004 , 0x00000004);
nop(4000000);
// value 0xBABE should be loopbacked and written into DDR LOOPBACK_DEST.
reg_wr(0xA0000000 , 0x0000BABE);
//axi_direct_1w1r();
nop(40000000);
rd_data = reg_rd(LOOPBACK_DEST);
if (rd_data == 0x0000BABE)
printf("PASSED simple write/read!\n");
else
printf("FAILED! rd = 0x%x\n", rd_data);
//while(1);
if (max_iter_v==0)
// not initialized yet
max_iter_v = MAX_ITER;
//printf("MAX DATA = %d\n", tlp_size_v);
printf("Iterations is %d\n", max_iter_v);
//printf("######## Advanced Error Reporting before TEST ##################\n");
//rd_data = reg_rd(0x98000104);
//printf("Uncorrectable Error Status Register (at 0x98000104) = 0x%X\n", rd_data);
//rd_data = reg_rd(0x98000108);
//printf("Uncorrectable Error Mask Register (at 0x98000108) = 0x%X\n", rd_data);
//rd_data = reg_rd(0x9800010C);
//printf("Uncorrectable Error Severity Register (at 0x9800010C) = 0x%X\n", rd_data);
//
//rd_data = reg_rd(0x98000110);
//printf("Correctable Error Status Register (at 0x98000110) = 0x%X\n", rd_data);
//rd_data = reg_rd(0x98000114);
//printf("Correctable Error Mask Register (at 0x98000114) = 0x%X\n", rd_data);
//reg_wr(0x98000118, 0x1E);
//rd_data = reg_rd(0x98000118);
//printf("Enabling ECRC Generation and Check (at 0x98000118) = 0x%X\n", rd_data);
//
//rd_data = reg_rd(0x98000130);
//printf("Root Erro Status Regsiter (at 0x98000130) = 0x%X\n", rd_data);
for (j= 0; j< max_iter_v; j++)
{
//printf("starting iter = %d\n", j);
// MDMA data transfer
// Initialize frame descriptor at address 0x4000_2000
reg_wr((S_frame_1 + 0x0),0x0);
reg_wr((S_frame_1 + 0x4),0x1);
reg_wr((S_frame_1 + 0x8),0x0); //desc_block_size[num_i]<<11 | 1<<9 | block_num[num_i]<<4 | 0<<2 | 1<<1 | 1<<0); // encode mode, read back scratch pad content
reg_wr((S_frame_1 + 0xC),0x0);
// Load Base pointer with Data array address
reg_wr((S_frame_1 + 0x10),S_data_1);
// Load Base pointer with Data array address
if (RANDOM_DATA_SIZE){
tlp_size_v = random_size_cur & MAX_DATA_MASK;
random_size_cur = LSFR ( random_size_cur );
if (tlp_size_v < random_min_size)
random_min_size = tlp_size_v;
if (tlp_size_v > random_max_size)
random_max_size = tlp_size_v;
}else
tlp_size_v = MAX_DATA;
reg_wr((S_frame_1 + 0x14),1<<31 | 0<<17 | 1<<16 | (tlp_size_v*4));
// Initialize Data Buffer location present at 0x0000_4000
//lsfr_data = 0x12345678 + j;
lsfr_data = 0xA55A5A5 + j;
for (i = 0 ; i< tlp_size_v; i++) // divide by 4, since we write 4bytes
{
switch (p_mode){
case 1:
lsfr_data = LSFR( lsfr_data );
break;
case 2:
lsfr_data = input_data_counter++;
break;
default:
lsfr_data = data_pattern;
}
reg_wr((S_data_1 + i*4),lsfr_data);
// clear dest data
reg_wr((LOOPBACK_DEST + i*4),0x12345678);
//if (i==0)
//printf("first data 0x%X\n", lsfr_data);
//reg_wr((S_data_1 + i*4),input_dw[i%3]);
//printf("input 0x%x at %d\n", input_dw[i%3], i*4);
}
// Initialize Destination frame descriptor at address 0x0000_7000
reg_wr((D_frame_1 + 0x0),0x0);
reg_wr((D_frame_1 + 0x4),0x1);
reg_wr((D_frame_1 + 0x8),0x0); //<<11 | 1<<9 | block_num[num_i]<<4 | 0<<2 | 1<<1 | 1<<0);
reg_wr((D_frame_1 + 0xC),0x0);
// Load Base pointer with Data array address
reg_wr((D_frame_1 + 0x10),D_data_1);
//printf("init D frame\n");
// Load Base control with length
reg_wr((D_frame_1 + 0x14),1<<31 | 0<<17 | 1<<16 | (tlp_size_v*4));
// Start programing the DMA at the end enable the DMA
// Enable the Mem to IO MDMA
//reg_wr((MDMA_BASE + 0x0),0x2);
reg_wr((MDMA_BASE + 0x0),0x0);
// Write in to Mem to FLEN register
reg_wr((MDMA_BASE + 0x8),0x50F);
// Write in to Mem to FLEN register
//reg_wr((MDMA_BASE + 0xC),0x4);
// Write in to Mem to IRQ
//reg_wr((MDMA_BASE + 0x10),0x7F);
//rd_data = reg_rd(MDMA_BASE + 0x0);
//printf("read data @ 0x0 = 0x%X\n", rd_data);
// Start programing the DMA at the end enable the DMA
// Enable the Mem to IO MDMA
//reg_wr((MDMA_BASE + 0x80),0x2);
reg_wr((MDMA_BASE + 0x80),0x0);
reg_wr((MDMA_BASE + 0x88),0x50F);
//reg_wr((MDMA_BASE + 0x8C),0x4);
//reg_wr((MDMA_BASE + 0x90),0x7F);
// Initialize the Head Pointer
reg_wr((MDMA_BASE + 0x84),D_frame_1);
//rd_data = reg_rd(MDMA_BASE + 0x84);
//printf("read data @ 0x84 = 0x%X\n", rd_data);
// Initialize the Head Pointer
reg_wr((MDMA_BASE + 0x4),S_frame_1);
//rd_data = reg_rd(MDMA_BASE + 0x4);
//printf("read data @ 0x4 = 0x%X\n", rd_data);
//nop(40000);
//
//rd_data = reg_rd(MDMA_BASE + 0x0);
//printf("read data @ 0x0 = 0x%X\n", rd_data);
//
//rd_data = reg_rd(MDMA_BASE + 0x80);
//printf("read data @ 0x80 = 0x%X\n", rd_data);
// printf("init pointers\n");
// Wait till Data gets transfered from Source to Destination Bufffer pointers
while (! lanedone) {
// wait for number of cycles equal to total size of job
for (i = 0; i<(tlp_size_v*4); i++){
lanedone = 0;
}
//rd_data = reg_rd(MDMA_BASE + 0x0);
//printf("read data @ 0x0 = 0x%X\n", rd_data);
//rd_data = reg_rd(MDMA_BASE + 0x80);
//printf("read data @ 0x80 = 0x%X\n", rd_data);
rd_data = reg_rd(D_frame_1 + 0xC);
if (rd_data >= 0x80000000) // check if bit 31 is set
{
rd_data = reg_rd(D_frame_1 + 0x8);
lanedone = 1;
}
}
lanedone = 0;
nop(40000);
//rd_data = reg_rd(D_data_1 );
//printf("first destination DWORD 0X%X\n",rd_data );
//rd_data = reg_rd(LOOPBACK_DEST );
//printf("first loopback dest DWORD 0X%X\n",rd_data );
//lsfr_data = 0x12345678 + j;
lsfr_data = 0xA55A5A5 + j;
for (i = 0 ; i< tlp_size_v; i++) // divide by 4, since we write 4bytes
{
switch (p_mode){
case 1:
lsfr_data = LSFR( lsfr_data );
break;
case 2:
lsfr_data = output_data_counter++;
break;
default:
lsfr_data = data_pattern;
}
rd_data = reg_rd(LOOPBACK_DEST +i*4);
if (lsfr_data!= rd_data){
if (DEBUG)
printf("FAILED! @ iter = %d, i=%d, rd_data = 0x%X, expected = 0x%X, ADDR = 0x%X, ",j, i, rd_data, lsfr_data, (LOOPBACK_DEST +i*4));
total_errors++;
rd_data = reg_rd(DWC_STS_REG0);
if (DEBUG)
printf("DWC_STS_REG0 = 0x%X\n", rd_data);
}
//else
// if (i%100==0)
// printf("passed @ %d\r", i);
}
// print out percentage
if ( j % (max_iter_v/10) ==0){
printf("Progress! %d%% iter = %d, total_errors = %d\n", ((100*j)/(max_iter_v)), j, total_errors);
//if(total_errors)
// print("Total Errors! %d", total_errors);
}
}
//printf("####### Advanced Error Reporting AFTER TEST ###############\n");
// rd_data = reg_rd(0x98000104);
// printf("Uncorrectable Error Status Register (at 0x98000104) = 0x%X\n", rd_data);
// rd_data = reg_rd(0x98000108);
// printf("Uncorrectable Error Mask Register (at 0x98000108) = 0x%X\n", rd_data);
// rd_data = reg_rd(0x9800010C);
// printf("Uncorrectable Error Severity Register (at 0x9800010C) = 0x%X\n", rd_data);
//
// rd_data = reg_rd(0x98000110);
// printf("Correctable Error Status Register (at 0x98000110) = 0x%X\n", rd_data);
// rd_data = reg_rd(0x98000114);
// printf("Correctable Error Mask Register (at 0x98000114) = 0x%X\n", rd_data);
// reg_wr(0x98000118, 0x1E);
// rd_data = reg_rd(0x98000118);
// printf("Enabling ECRC Generation and Check (at 0x98000118) = 0x%X\n", rd_data);
//
// rd_data = reg_rd(0x98000130);
// printf("Root Erro Status Regsiter (at 0x98000130) = 0x%X\n", rd_data);
if (RANDOM_DATA_SIZE)
printf("DONE! total iter = %d, random size TLP used, max tlp size used = %d, min tlp size used = %d\n", j, random_max_size*4, random_min_size*4);
else
printf("DONE! total iter = %d, each of max size %d\n", j,MAX_DATA);
printf("Total DWORD Errors = %d, \n", total_errors);
if(!total_errors)
ret = 0;
return ret;
}