#pragma GCC optimize ("O0") | |
#include "Galois_memmap.h" | |
#include "global.h" | |
#include "SysMgr.h" | |
#include "util.h" | |
#include "apb_perf_base.h" | |
#include "apbRegBase.h" | |
#include "lgpl_printf.h" | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
/////////////////////////////////////PINMUX API/////////////////////////////////////////////// | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
//Four pinmux registers, 10 pins per register, 3 bits per pin | |
#define BITS_PER_PIN 3 | |
#define PINMUX_VALUE_MAX ((1 << BITS_PER_PIN) -1) | |
#define PINS_PER_REG 10 | |
#define PINMUX_CTRL_REG_NUM 4 | |
#ifndef I2C_OK | |
#define I2C_OK 0 | |
#endif | |
#ifndef I2C_ERROR | |
#define I2C_ERROR 1 | |
#endif | |
#ifndef I2C_EBADPARAM | |
#define I2C_EBADPARAM 2 | |
#endif | |
#ifndef I2C_EBUSRW | |
#define I2C_EBUSRW 3 | |
#endif | |
#define dbg_printf(...) lgpl_printf(__VA_ARGS__) | |
enum I2C_INSTANCES | |
{ | |
SOC_I2C0, | |
SOC_I2C1, | |
SM_I2C0, | |
SM_I2C1, | |
I2C_MAX | |
}; | |
// I2C standard bus speed | |
enum | |
{ | |
I2C_STANDARD_SPEED_100K = 100, | |
I2C_STANDARD_SPEED_400K = 400, | |
}; | |
// I2C speed mode registers, note our IP doesn't support high speed mode | |
enum | |
{ | |
I2C_STANDARD_SPEED_MODE = 1, // 100K is the default | |
I2C_FAST_SPEED_MODE = 2 // 400K is the default | |
}; | |
// I2C slave address type | |
enum | |
{ | |
I2C_7BIT_SLAVE_ADDR = 0, | |
I2C_10BIT_SLAVE_ADDR = 1 | |
}; | |
enum pinmuxIndexList | |
{ | |
/*00*/ URT0_RXD, | |
/*01*/ URT0_TXD, | |
/*02*/ SPI1_SS0n, | |
/*03*/ SPI1_SS1n, | |
/*04*/ SPI1_SS2n, | |
/*05*/ SPI1_SCLK, | |
/*06*/ SPI1_SDO, | |
/*07*/ SPI1_SDI, | |
/*08*/ USB1_DRV_VBUS, | |
/*09*/ TW1_SCL, | |
/*10*/ TW1_SDA, | |
/*11*/ HDMI_CEC, | |
/*12*/ HDMI_HPD, | |
/*13*/ NAND_IO0, | |
/*14*/ NAND_IO1, | |
/*15*/ NAND_IO2, | |
/*16*/ NAND_IO3, | |
/*17*/ NAND_IO4, | |
/*18*/ NAND_IO5, | |
/*19*/ NAND_IO6, | |
/*20*/ NAND_IO7, | |
/*21*/ NAND_ALE, | |
/*22*/ NAND_CLE, | |
/*23*/ NAND_WEn, | |
/*24*/ NAND_REn, | |
/*25*/ NAND_WPn, | |
/*26*/ NAND_CEn, | |
/*27*/ NAND_RDY, | |
/*28*/ SD0_CLK, | |
/*29*/ SD0_DAT0, | |
/*30*/ SD0_DAT1, | |
/*31*/ SD0_DAT2, | |
/*32*/ SD0_DAT3, | |
/*33*/ SD0_CDn, | |
/*34*/ SD0_CMD, | |
/*35*/ SD0_WP, | |
/*36*/ STS0_CLK, | |
/*37*/ STS0_SOP, | |
/*38*/ STS0_VALD, | |
/*39*/ STS0_SD, | |
/*40*/ SM_TMS, | |
/*41*/ SM_TDI, | |
/*42*/ SM_TDO, | |
/*43*/ PINMUX_INDEX_MAX | |
}; | |
static const char* pinmuxNameList[PINMUX_INDEX_MAX] = | |
{ | |
"URT0_RXD", | |
"URT0_TXD", | |
"SPI1_SS0n", | |
"SPI1_SS1n", | |
"SPI1_SS2n", | |
"SPI1_SCLK", | |
"SPI1_SDO", | |
"SPI1_SDI", | |
"USB1_DRV_VBUS", | |
"TW1_SCL", | |
"TW1_SDA", | |
"HDMI_CEC", | |
"HDMI_HPD", | |
"NAND_IO0", | |
"NAND_IO1", | |
"NAND_IO2", | |
"NAND_IO3", | |
"NAND_IO4", | |
"NAND_IO5", | |
"NAND_IO6", | |
"NAND_IO7", | |
"NAND_ALE", | |
"NAND_CLE", | |
"NAND_WEn", | |
"NAND_REn", | |
"NAND_WPn", | |
"NAND_CEn", | |
"NAND_RDY", | |
"SD0_CLK", | |
"SD0_DAT0", | |
"SD0_DAT1", | |
"SD0_DAT2", | |
"SD0_DAT3", | |
"SD0_CDn", | |
"SD0_CMD", | |
"SD0_WP", | |
"STS0_CLK", | |
"STS0_SOP", | |
"STS0_VALD", | |
"STS0_SD", | |
"SM_TMS", | |
"SM_TDI", | |
"SM_TDO" | |
}; | |
static int diag_i2c_master_set_speed(int master_id, int mode, int speed, int hold_time); | |
static void set_transfer_mode(int master_id, int mode); | |
int pinmux_write(unsigned int index, unsigned int value) | |
{ | |
unsigned int addr, field, pinmux; | |
if(index >= PINMUX_INDEX_MAX) | |
{ | |
dbg_printf("Pinmux Index error ! MAX number is %d",PINMUX_INDEX_MAX); | |
return -1; | |
} | |
if (value > PINMUX_VALUE_MAX) | |
{ | |
dbg_printf("Pinmux value error ! MAX number is %d",PINMUX_VALUE_MAX); | |
return -1; | |
} | |
if ((index == URT0_RXD) || (index == URT0_TXD)) | |
dbg_printf("You are changing the UART pinmux!\n"); | |
if(index < SM_TMS)// SOC pinmux | |
{ | |
addr = MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + ((index / PINS_PER_REG) << 2); | |
field = (index % PINS_PER_REG) * BITS_PER_PIN; | |
} | |
else //SM pinmux | |
{ | |
index -= SM_TMS; | |
addr = SM_SYS_CTRL_REG_BASE + RA_smSysCtl_smPinMuxCntlBus ; | |
field = (index % PINS_PER_REG) * BITS_PER_PIN; | |
} | |
BFM_HOST_Bus_Read32(addr, &pinmux); // read current pinmux | |
pinmux &= ~(0x7 << field); | |
pinmux |= (value << field); | |
BFM_HOST_Bus_Write32(addr, pinmux); | |
return 0; | |
} | |
int pinmux_read(unsigned int index) | |
{ | |
unsigned int addr, field, pinmux; | |
if(index >= PINMUX_INDEX_MAX) | |
{ | |
dbg_printf("Pinmux Index error ! MAX number is %d",PINMUX_INDEX_MAX); | |
return -1; | |
} | |
if(index < SM_TMS)// SOC pinmux | |
{ | |
addr = MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + ((index / PINS_PER_REG) << 2); | |
field = (index % PINS_PER_REG) * BITS_PER_PIN; | |
} | |
else //SM pinmux | |
{ | |
index -= SM_TMS; | |
addr = SM_SYS_CTRL_REG_BASE + RA_smSysCtl_smPinMuxCntlBus ; | |
field = (index % PINS_PER_REG) * BITS_PER_PIN; | |
} | |
BFM_HOST_Bus_Read32(addr, &pinmux); // read current pinmux | |
pinmux = (pinmux >> field) & 0x7; | |
return pinmux; | |
} | |
void pinmux_rdall(void) | |
{ | |
unsigned int data1; | |
for (data1 = 0; data1 < PINMUX_INDEX_MAX; data1++) | |
dbg_printf( "%2d Pin Name: %s\t :: Value = %d\n", data1, pinmuxNameList[data1], pinmux_read(data1)); | |
} | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
/////////////////////////////////////GPIO API///////////////////////////////////////////////// | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
//#define APB_GPIO_VER 0x3230342a | |
#define APB_GPIO_VER 0x3230392a //CD+ Z1 | |
int gpioSet(unsigned int gpio_instance, unsigned int direction, unsigned int state) | |
{ | |
unsigned int read; | |
unsigned int gpio_base; | |
switch (gpio_instance) | |
{ | |
case 0: | |
gpio_base = APB_GPIO0_BASE; | |
break; | |
case 1: | |
gpio_base = APB_GPIO1_BASE; | |
break; | |
case 2: | |
gpio_base = APB_GPIO2_BASE; | |
break; | |
case 3: | |
gpio_base = APB_GPIO3_BASE; | |
break; | |
/* case 4: | |
gpio_base = SM_APB_GPIO0_BASE; | |
break; | |
case 5: | |
gpio_base = SM_APB_GPIO1_BASE; | |
break;*/ | |
default: | |
dbg_printf(" invalid gpio instance\n"); | |
return 1; | |
} | |
// check GPIO ID | |
BFM_HOST_Bus_Read32((gpio_base + 0x6C), &read); | |
if (read != APB_GPIO_VER) | |
{ | |
dbg_printf(" GPIO%d ID = 0x%X incorrect, abort\n", gpio_instance, read); | |
return 1; | |
} | |
//ctrl settings | |
BFM_HOST_Bus_Write32((gpio_base + 0x08), 0x00); // software control | |
//output for all the port D pins | |
BFM_HOST_Bus_Write32((gpio_base + 0x04), direction);// 1 - output, 0 - input | |
BFM_HOST_Bus_Write32((gpio_base + 0x00), state); // set state | |
//BFM_HOST_Bus_Write32((PIN_MUX_REG), pinmux); // restore pinmuxes | |
//BFM_HOST_Bus_Write32((PIN_MUX1_REG), pinmux1); | |
dbg_printf(" APB GPIO%d set to direction = 0x%X, state = 0x%X\n", gpio_instance, direction, state); | |
return 0; | |
} | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
/////////////////////////////////////I2C API/////////////////////////////////////////////// | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
// number of I2C masters in system | |
#define I2C_MASTER_NUM I2C_MAX | |
// I2C master system clock | |
// minimum sysmte clock are required | |
// Standard Mode: 2 MHz | |
// Fast Mode: 10 MHz | |
// High-Speed Mode: 100 MHz | |
//#ifdef BG2_DV_BOARD | |
#define I2C_SYS_CLOCK 150 // 75 MHz, this is the config clock | |
/*#else | |
#define I2C_SYS_CLOCK 10 // 5 MHz | |
#endif*/ | |
#define I2C_SDA_HOLD_TIME 2 // Range: [2, SCL_LCNT -2] | |
// I2C master TX/RX fifo size | |
#define I2C_RX_FIFO_SIZE 64 | |
#define I2C_TX_FIFO_SIZE 64 | |
// register definitions of SPI master | |
#define I2C_REG_CON 0x00 | |
#define I2C_REG_TAR 0x04 | |
#define I2C_REG_SAR 0x08 | |
#define I2C_REG_HS_MADDR 0x0C | |
#define I2C_REG_DATA_CMD 0x10 | |
#define I2C_REG_SS_SCL_HCNT 0x14 | |
#define I2C_REG_SS_SCL_LCNT 0x18 | |
#define I2C_REG_FS_SCL_HCNT 0x1C | |
#define I2C_REG_FS_SCL_LCNT 0x20 | |
#define I2C_REG_HS_SCL_HCNT 0x24 | |
#define I2C_REG_HS_SCL_LCNT 0x28 | |
#define I2C_REG_INTR_STAT 0x2C | |
#define I2C_REG_INTR_MASK 0x30 | |
#define I2C_REG_RINTR_STAT 0x34 | |
#define I2C_REG_RX_TL 0x38 | |
#define I2C_REG_TX_TL 0x3C | |
#define I2C_REG_CLR_INTR 0x40 | |
#define I2C_REG_CLR_RX_UNDER 0x44 | |
#define I2C_REG_CLR_RX_OVER 0x48 | |
#define I2C_REG_CLR_TX_OVER 0x4C | |
#define I2C_REG_CLR_RD_REQ 0x50 | |
#define I2C_REG_CLR_TX_ABRT 0x54 | |
#define I2C_REG_CLR_RX_DONE 0x58 | |
#define I2C_REG_CLR_ACTIVITY 0x5C | |
#define I2C_REG_CLR_STOP_DET 0x60 | |
#define I2C_REG_CLR_START_DET 0x64 | |
#define I2C_REG_CLR_GEN_CALL 0x68 | |
#define I2C_REG_ENABLE 0x6C | |
#define I2C_REG_STATUS 0x70 | |
#define I2C_REG_TXFLR 0x74 | |
#define I2C_REG_RXFLR 0x78 | |
#define I2C_REG_SDA_HOLD 0x7C //for SDA_HOLD | |
#define I2C_REG_TX_ABRT_STAT 0x80 | |
#define I2C_REG_DMA_CR 0x88 | |
#define I2C_REG_DMA_TDLR 0x8C | |
#define I2C_REG_DMA_RDLR 0x90 | |
#define I2C_REG_SDA_SETUP 0x94 //for SDA_SETUP | |
#define I2C_REG_COMP_PARAM 0xF4 | |
#define I2C_REG_COMP_VERSION 0xF8 | |
#define I2C_REG_COMP_TYPE 0xFC // reset value: 0x44570140 | |
// Macros of I2C_REG_CON bit offset | |
#define CON_SLAVE_DISABLE 6 | |
#define CON_RESTART_EN 5 | |
#define CON_10BITADDR 4 | |
#define CON_SPEED 1 | |
#define CON_MASTER_ENABLE 0 | |
// Macros of I2C_REG_TAR bit offset | |
#define TAR_10BITADDR 12 | |
#define TAR_SPECIAL 11 | |
#define TAR_GC_OR_START 10 | |
// Macros of I2C_REG_INTR_* bit definition | |
#define INTR_GEN_CALL 0x800 | |
#define INTR_START_DET 0x400 | |
#define INTR_STOP_DET 0x200 | |
#define INTR_ACTIVITY 0x100 | |
#define INTR_RX_DONE 0x080 | |
#define INTR_TX_ABRT 0x040 | |
#define INTR_RD_REQ 0x020 | |
#define INTR_TX_EMPTY 0x010 | |
#define INTR_TX_OVER 0x008 | |
#define INTR_RX_FULL 0x004 | |
#define INTR_RX_OVER 0x002 | |
#define INTR_RX_UNDER 0x001 | |
// Macros of I2C_REG_ENABLE bit definition | |
#define EN_ENABLE 0x01 | |
// Macros of read-command | |
#define READ_CMD 0x100 | |
// Macros to interrupt mask flag | |
#define MASK 0 | |
#define UNMASK 1 | |
// Macros of read/write I2C master registers | |
#define I2C_RegRead(a, pv) BFM_HOST_Bus_Read32(base_addr+(a), pv) /*(*(volatile int *)(base_addr+(a)))*/ | |
#define I2C_RegWrite(a, v) BFM_HOST_Bus_Write32(base_addr+(a), v) /**(volatile int *)(base_addr+(a)) = (v)*/ | |
// I2C master's transfer buffer, shared by TX and RX | |
static int i2c_master_buffer[I2C_MASTER_NUM][256+4]; | |
// number of command which have been written to TX fifo so far, | |
// this will equal bytes_of_write_cmd + bytes_of_read_cmd at the end of transaction | |
static int bytes_written_to_txfifo[I2C_MASTER_NUM]; | |
// number of bytes read out from RX fifo so far, | |
static int bytes_read_from_rxfifo[I2C_MASTER_NUM]; | |
// number of write-command which need to be written to TX fifo | |
static int bytes_of_write_cmd[I2C_MASTER_NUM]; | |
// number of read-command which need to be written to TX fifo | |
static int bytes_of_read_cmd[I2C_MASTER_NUM]; | |
// variable indicating transaction finishing or not | |
static volatile int transaction_done[I2C_MASTER_NUM]; | |
// I2C master's base-address vector | |
static const unsigned int I2C_MASTER_BASEADDR[I2C_MASTER_NUM] = {APB_I2C0_BASE, APB_I2C1_BASE, SM_APB_I2C0_BASE, SM_APB_I2C1_BASE}; | |
/***************************************************** | |
* set I2C master TX FIFO underflow threshold | |
* thrld: 0 - 255 | |
* | |
*****************************************************/ | |
static void set_txfifo_threshold(int master_id, int thrld) | |
{ | |
unsigned int base_addr; | |
if (thrld<0 || thrld>255) return; | |
base_addr = I2C_MASTER_BASEADDR[master_id]; | |
I2C_RegWrite(I2C_REG_TX_TL, thrld); | |
return; | |
} | |
/***************************************************** | |
* set I2C master RX FIFO overflow threshold | |
* thrld: 1 - 256 | |
* | |
*****************************************************/ | |
static void set_rxfifo_threshold(int master_id, int thrld) | |
{ | |
unsigned int base_addr; | |
if (thrld<1 || thrld>256) return; | |
base_addr = I2C_MASTER_BASEADDR[master_id]; | |
I2C_RegWrite(I2C_REG_RX_TL, thrld-1); | |
return; | |
} | |
/********************************************************* | |
* FUNCTION: init I2C master: set default bus speed | |
* PARAMS: master_id - id of I2C master to init | |
* RETURN: I2C_OK - succeed | |
* I2C_ERROR - invalid parameter | |
********************************************************/ | |
int diag_i2c_master_init(int master_id) | |
{ | |
unsigned int base_addr; | |
int i; | |
if ((master_id < 0) || (master_id > I2C_MASTER_NUM-1)) | |
{ | |
dbg_printf( "I2C wrong master id\n"); | |
return (I2C_ERROR); | |
} | |
base_addr = I2C_MASTER_BASEADDR[master_id]; | |
// disable I2C module first | |
I2C_RegWrite(I2C_REG_ENABLE, ~EN_ENABLE); | |
// set TX/RX fifo default threshold | |
set_txfifo_threshold(master_id, 0); | |
set_rxfifo_threshold(master_id, I2C_RX_FIFO_SIZE/2); | |
// disable all I2C interrupts. | |
I2C_RegWrite(I2C_REG_INTR_MASK, 0); | |
// disable slave mode, enable restart function, enable master mode | |
I2C_RegRead(I2C_REG_CON, &i); | |
i |= (1<<CON_SLAVE_DISABLE)|(1<<CON_RESTART_EN)|(1<<CON_MASTER_ENABLE); | |
I2C_RegWrite(I2C_REG_CON, i); | |
// set default I2C master speed: 100KHz fast-speed mode | |
diag_i2c_master_set_speed(master_id, I2C_STANDARD_SPEED_MODE, I2C_STANDARD_SPEED_100K, I2C_SDA_HOLD_TIME); | |
//diag_i2c_master_set_speed(master_id, I2C_FAST_SPEED_MODE, I2C_STANDARD_SPEED_400K, I2C_SDA_HOLD_TIME); | |
I2C_RegRead(I2C_REG_INTR_MASK, &i); | |
return (I2C_OK); | |
} | |
static int addr_type = I2C_7BIT_SLAVE_ADDR; | |
int diag_i2c_master_set_addr_type(int type) | |
{ | |
addr_type = type; | |
return 0; | |
} | |
/********************************************************************* | |
* FUNCTION: set I2C master bus speed | |
* PARAMS: master_id - id of I2C master to config | |
* mode - STANDARD(1) or FAST(2) | |
* speed - in unit of KHz | |
* RETURN: I2C_OK - succeed | |
* I2C_ERROR - I2C module is enabled or speed not support | |
********************************************************************/ | |
int diag_i2c_master_set_speed(int master_id, int mode, int speed, int hold_time) | |
{ | |
unsigned int base_addr; | |
int i, sda_hold_max; | |
if ((master_id < 0) || (master_id > I2C_MASTER_NUM-1)) | |
{ | |
dbg_printf( "I2C wrong master id\n"); | |
return (I2C_ERROR); | |
} | |
base_addr = I2C_MASTER_BASEADDR[master_id]; | |
// check whether I2C module is disabled | |
I2C_RegRead(I2C_REG_ENABLE, &i); | |
if (i & EN_ENABLE) | |
{ | |
dbg_printf( "I2C is busy\n"); | |
return (I2C_ERROR); | |
} | |
switch (mode) | |
{ | |
case I2C_STANDARD_SPEED_MODE: // standard-speed | |
I2C_RegRead(I2C_REG_CON, &i); | |
i &= ~(3<<CON_SPEED); | |
i |= (1<<CON_SPEED); | |
I2C_RegWrite(I2C_REG_CON, i); /* set master to operate in standard-speed mode */ | |
if(speed==I2C_STANDARD_SPEED_100K) | |
{ | |
//use the default standard 100KHz speed | |
I2C_RegWrite(I2C_REG_SS_SCL_HCNT, 4000*I2C_SYS_CLOCK/1000); /* 4000-ns minimum HIGH-period*/ | |
I2C_RegWrite(I2C_REG_SS_SCL_LCNT, 4700*I2C_SYS_CLOCK/1000); /* 4700-ns minimum LOW-period*/ | |
} | |
else | |
{ | |
// calculate high/low period of SCL in 1/3(high)-2/3(low) criteria. | |
i = 1000000/(speed*3); | |
I2C_RegWrite(I2C_REG_SS_SCL_HCNT, i*I2C_SYS_CLOCK/1000); | |
i <<= 1; | |
I2C_RegWrite(I2C_REG_SS_SCL_LCNT, i*I2C_SYS_CLOCK/1000); | |
} | |
break; | |
case I2C_FAST_SPEED_MODE: // fast-speed | |
I2C_RegRead(I2C_REG_CON, &i); | |
i &= ~(3<<CON_SPEED); | |
i |= (2<<CON_SPEED); | |
I2C_RegWrite(I2C_REG_CON, i); /* set master to operate in fast-speed mode */ | |
if(speed==I2C_STANDARD_SPEED_400K) | |
{ | |
//use the default fast 400KHz speed | |
I2C_RegWrite(I2C_REG_FS_SCL_HCNT, 600*I2C_SYS_CLOCK/1000); /* 600-ns minimum HIGH-period*/ | |
I2C_RegWrite(I2C_REG_FS_SCL_LCNT, 1300*I2C_SYS_CLOCK/1000); /* 1300-ns minimum LOW-period*/ | |
} | |
else | |
{ | |
// calculate high/low period of SCL in 1/3(high)-2/3(low) criteria. | |
i = 1000000/(speed*3); | |
I2C_RegWrite(I2C_REG_FS_SCL_HCNT, i*I2C_SYS_CLOCK/1000); | |
i <<= 1; | |
I2C_RegWrite(I2C_REG_FS_SCL_LCNT, i*I2C_SYS_CLOCK/1000); | |
} | |
break; | |
default: | |
dbg_printf( "I2C unsupported speed mode\n"); | |
return (I2C_ERROR); | |
} | |
/***SDA SETUP/HOLD time tuning***/ | |
I2C_RegWrite(I2C_REG_SDA_HOLD, hold_time); | |
I2C_RegRead(I2C_REG_SDA_HOLD, &i); | |
//set_sda_setup(master_id,value); | |
if(speed==I2C_STANDARD_SPEED_100K) | |
I2C_RegRead(I2C_REG_SS_SCL_LCNT, &sda_hold_max); | |
else if(speed==I2C_STANDARD_SPEED_400K) | |
I2C_RegRead(I2C_REG_FS_SCL_LCNT, &sda_hold_max); | |
if ((i < 2) || (i > sda_hold_max-2)) | |
{ | |
dbg_printf("I2C wrong sda_hold setting.\n"); | |
return (I2C_ERROR); | |
} | |
return (I2C_OK); | |
} | |
/*********************************************************************** | |
* FUNCTION: read bytes from slave device | |
* PARAMS: master_id - id of I2C master to operate | |
* slave_addr - address of slave device | |
* pwbuf - pointer of write buffer | |
* wnum - number of bytes to write | |
* prbuf - pointer of read buffer | |
* rnum - number of bytes to read | |
* RETURN: I2C_OK - succeed | |
* I2C_ERROR - I2C module is enabled, or read failed | |
* NOTE: maximum write bytes is 260, maximum read bytes is 256 in a single | |
* transaction | |
***********************************************************************/ | |
int diag_i2c_master_writeread_bytes(int master_id, int slave_addr, unsigned char *pwbuf, int wnum, unsigned char *prbuf, int rnum) | |
{ | |
unsigned int base_addr; | |
int i, j; | |
int timeout=1000000; | |
if ((master_id < 0) || (master_id > I2C_MASTER_NUM-1)) | |
{ | |
dbg_printf( "I2C wrong master id\n"); | |
return (I2C_ERROR); | |
} | |
if (wnum>260 || rnum>256) | |
{ | |
dbg_printf( "I2C number of bytes too big\n"); | |
return (I2C_ERROR); | |
} | |
if (addr_type!=I2C_7BIT_SLAVE_ADDR && addr_type!=I2C_10BIT_SLAVE_ADDR) | |
{ | |
dbg_printf( "I2C wrong address type\n"); | |
return (I2C_ERROR); | |
} | |
base_addr = I2C_MASTER_BASEADDR[master_id]; | |
// check whether I2C module is disabled | |
I2C_RegRead(I2C_REG_ENABLE, &i); | |
if (i & EN_ENABLE) | |
{ | |
dbg_printf( "I2C is busy\n"); | |
return (I2C_ERROR); | |
} | |
I2C_RegRead(I2C_REG_CON, &i); | |
if (addr_type==I2C_7BIT_SLAVE_ADDR){ // 7-bit slave address | |
// set 7-bit target address, normal transfer mode | |
I2C_RegRead(I2C_REG_TAR, &i); | |
i &= ~((1<<TAR_10BITADDR) | (1<<TAR_SPECIAL) | 0x3ff); | |
i |= slave_addr; | |
I2C_RegWrite(I2C_REG_TAR, i); | |
// for SM_TW1, the dynamic address change is 0, | |
// so we have to set 7-bit address type here | |
I2C_RegRead(I2C_REG_CON, &i); | |
i &= ~(1<<CON_10BITADDR); | |
I2C_RegWrite(I2C_REG_CON, i); | |
} else { // 10-bit slave address | |
// set 10-bit target address, normal transfer mode | |
I2C_RegRead(I2C_REG_TAR, &i); | |
i &= ~((1<<TAR_SPECIAL) | 0x3ff); | |
i |= ((1<<TAR_10BITADDR) | slave_addr); | |
I2C_RegWrite(I2C_REG_TAR, i); | |
// for SM_TW1, the dynamic address change is 0, | |
// so we have to set 7-bit address type here | |
I2C_RegRead(I2C_REG_CON, &i); | |
i |= (1<<CON_10BITADDR); | |
I2C_RegWrite(I2C_REG_CON, i); | |
} | |
// initiate transaction status flag | |
transaction_done[master_id] = 0; | |
// set TX fifo threshold to make sure TXE interrupt will be triggered | |
// as soon as we unmask the TXE interupt, we will start transaction by writing CMD_DATA register then. | |
set_txfifo_threshold(master_id, I2C_TX_FIFO_SIZE/2); | |
// clear TX_ABRT_SOURCE by reading | |
I2C_RegRead(I2C_REG_CLR_INTR, &i); | |
if ((pwbuf && wnum>0) && (prbuf && rnum>0)){ // write & read transaction | |
// set RX fifo threshold | |
if (rnum<=I2C_RX_FIFO_SIZE) | |
set_rxfifo_threshold(master_id, rnum); | |
else | |
set_rxfifo_threshold(master_id, I2C_RX_FIFO_SIZE/2); | |
// initiate number of write and read commands which are going to be written to TX fifo | |
bytes_written_to_txfifo[master_id] = 0; | |
bytes_read_from_rxfifo[master_id] = 0; | |
bytes_of_write_cmd[master_id] = wnum; | |
bytes_of_read_cmd[master_id] = rnum; | |
// write-command need to be copy to buffer first, | |
// read-command don't need because it can be generated dynamically | |
for (i=0; i<wnum; i++) | |
i2c_master_buffer[master_id][i] = (int)pwbuf[i]; | |
// enable I2C master | |
I2C_RegWrite(I2C_REG_ENABLE, EN_ENABLE); | |
// issue write commands to TX fifo | |
for (i=0; i<wnum; i++) | |
{ | |
do{ | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
}while (!(j&0x02)); /* TX fifo is full */ | |
I2C_RegWrite(I2C_REG_DATA_CMD, i2c_master_buffer[master_id][i]); | |
} | |
// issue read commands to TX fifo and receive data from RX fifo | |
i = 0; | |
while (bytes_read_from_rxfifo[master_id]<rnum) | |
{ | |
// if there are received data in RX fifo, read out to buffer | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
if (j&0x08) /* RX fifo is not empty */ | |
I2C_RegRead(I2C_REG_DATA_CMD, &(i2c_master_buffer[master_id][bytes_read_from_rxfifo[master_id]++])); | |
// if TX fifo not full, issue remaining read commands to TX fifo | |
if (i<rnum){ | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
if (j&0x02){ /* TX fifo is not full */ | |
I2C_RegWrite(I2C_REG_DATA_CMD, READ_CMD); | |
i ++; | |
} | |
} | |
if(!(--timeout)) break; | |
} | |
transaction_done[master_id] = 1; | |
} else if (pwbuf && wnum>0) { // write-only transaction | |
// initiate number of write commands which are going to be written to TX fifo | |
bytes_written_to_txfifo[master_id] = 0; | |
bytes_read_from_rxfifo[master_id] = 0; | |
bytes_of_write_cmd[master_id] = wnum; | |
bytes_of_read_cmd[master_id] = 0; | |
// write-command need to be copy to buffer first, | |
for (i=0; i<wnum; i++) | |
i2c_master_buffer[master_id][i] = (int)pwbuf[i]; | |
// enable I2C master | |
I2C_RegWrite(I2C_REG_ENABLE, EN_ENABLE); | |
// issue write commands to TX fifo | |
for (i=0; i<wnum; i++) | |
{ | |
#if 0 //original way to check TX fifo when write | |
if(!(--timeout)) break; | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
while (!(j&0x02)) /* TX fifo is full */ | |
{ | |
if (!(j&0x01)) /* but I2C master is idle */ | |
{ | |
// disable I2C master | |
I2C_RegWrite(I2C_REG_ENABLE, ~EN_ENABLE); | |
/* somehow error happen !!! */ | |
dbg_printf( "I2C write failed\n"); | |
return (I2C_ERROR); | |
} | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
} | |
#else | |
timeout=10000; | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
while (!(j&0x02)) /* TX fifo is full, so wait, but if it take too long, timeout*/ | |
{ | |
if(!(timeout--)) | |
{ | |
// disable I2C master | |
I2C_RegWrite(I2C_REG_ENABLE, ~EN_ENABLE); | |
/* somehow error happen !!! */ | |
dbg_printf( "(%d)I2C write failed\n", __LINE__); | |
return (I2C_ERROR); | |
} | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
} | |
#endif | |
I2C_RegWrite(I2C_REG_DATA_CMD, i2c_master_buffer[master_id][i]); | |
} | |
//add some delay, otherwise, the next error condition will get hit on fast cpu | |
//fifo not empty and master is idle | |
{ | |
volatile int delay=10000; | |
while(delay--); | |
} | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
while (!(j&0x04)){ /* TX fifo is not empty */ | |
if(!(j&0x01)) /* but I2C master is idle */ | |
{ | |
// disable I2C master | |
I2C_RegWrite(I2C_REG_ENABLE, ~EN_ENABLE); | |
/* somehow error happen !!! */ | |
dbg_printf( "(%d)I2C write failed\n", __LINE__); | |
return (I2C_ERROR); | |
} | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
} | |
do{ | |
I2C_RegRead(I2C_REG_STATUS, &i); | |
}while (i&0x01); /* wait until transfer finish */ | |
//for write only transaction, need to check TX_ABRT_SOURCE to know if tx failed | |
I2C_RegRead(I2C_REG_TX_ABRT_STAT, &i); | |
if(i) | |
{ | |
// disable I2C master | |
I2C_RegWrite(I2C_REG_ENABLE, ~EN_ENABLE); | |
/* somehow error happen !!! */ | |
dbg_printf( "I2C tx aborted! I2C_REG_TX_ABRT_STAT = 0x%x\n", i); | |
return (I2C_ERROR); | |
} | |
transaction_done[master_id] = 1; | |
} else if (prbuf && rnum>0) { // read-only transaction | |
// set RX fifo threshold | |
if (rnum<=I2C_RX_FIFO_SIZE) | |
set_rxfifo_threshold(master_id, rnum); | |
else | |
set_rxfifo_threshold(master_id, I2C_RX_FIFO_SIZE/2); | |
// initiate number of read commands which are goding to be written to TX fifo | |
bytes_written_to_txfifo[master_id] = 0; | |
bytes_read_from_rxfifo[master_id] = 0; | |
bytes_of_write_cmd[master_id] = 0; | |
bytes_of_read_cmd[master_id] = rnum; | |
// enable I2C master | |
I2C_RegWrite(I2C_REG_ENABLE, EN_ENABLE); | |
// issue read commands to TX fifo and receive data from RX fifo | |
i = 0; | |
while (bytes_read_from_rxfifo[master_id]<rnum) | |
{ | |
// if there are received data in RX fifo, read out to buffer | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
if (j&0x08) /* RX fifo is not empty */ | |
I2C_RegRead(I2C_REG_DATA_CMD, &(i2c_master_buffer[master_id][bytes_read_from_rxfifo[master_id]++])); | |
// if TX fifo not full, issue remaining read commands to TX fifo | |
if (i<rnum){ | |
I2C_RegRead(I2C_REG_STATUS, &j); | |
if (j&0x02){ /* TX fifo is not full */ | |
I2C_RegWrite(I2C_REG_DATA_CMD, READ_CMD); | |
i ++; | |
} | |
} | |
if(!(--timeout)) break; | |
} | |
transaction_done[master_id] = 1; | |
} | |
// if it is a write only transaction, wait until transfer finish | |
do{ | |
I2C_RegRead(I2C_REG_STATUS, &i); | |
}while (i&0x01); /* wait until transfer finish */ | |
// copy received data from buffer to prbuf if there is | |
if (bytes_of_read_cmd[master_id] > 0){ | |
for (i=0; i<bytes_of_read_cmd[master_id]; i++) | |
prbuf[i] = (unsigned char)i2c_master_buffer[master_id][i]; | |
} | |
// disable I2C master | |
I2C_RegWrite(I2C_REG_ENABLE, ~EN_ENABLE); | |
if(!timeout) | |
{ | |
dbg_printf( "I2C Timed out\n"); | |
return (I2C_ERROR); | |
} | |
return (I2C_OK); | |
} | |
/*********************************************************************** | |
* FUNCTION: checks the 16 bit TX_ABRT_SOURCE register and gives the reason | |
* PARAMS: master_id - id of I2C master to operate | |
* tx_abort_source - pointer to return the value from the TX_ABRT_SOURCE register | |
* RETURN: I2C_OK or I2C_ERROR | |
* | |
***********************************************************************/ | |
const char* g_aApbI2C_AbortSrc[] = | |
{ | |
"(7-bit addressing) address not ACKed by any slave", | |
"(10-bit addressing) 1st address byte not ACKed by any slave", | |
"(10-bit addressing) 2nd address byte not ACKed by any slave", | |
"address ACKed, data not ACKed by slave", | |
"general call not responded by any slave", | |
"general call followed by read command from user", | |
"master in high speed mode and high speed master code ACKed", | |
"master sent a start byte and start byte ACKed", | |
"restart disabled while user trying to use master to send data in high speed mode", | |
"restart disabled while user trying to send a start byte", | |
"restart disabled and master send a read command in 10-bit addressing mode", | |
"user attempted to use disabled master", | |
"lost arbitration", | |
"slave received read command while data exists in Tx FIFO", | |
"slave lost bus while trasmitting data to a remote master", | |
"slave requesting data to Tx and user wrote read command into Tx FIFO" | |
}; | |
int diag_i2c_check_error(int master_id, unsigned int *tx_abort_source) | |
{ | |
unsigned int base_addr; | |
unsigned int read, i; | |
if ((master_id < 0) || (master_id > I2C_MASTER_NUM-1)) | |
{ | |
dbg_printf( "I2C wrong master id\n"); | |
return (I2C_ERROR); | |
} | |
base_addr = I2C_MASTER_BASEADDR[master_id]; | |
I2C_RegRead(I2C_REG_TX_ABRT_STAT, &read);; // check Tx Aborad Source register | |
//dbg_printf( "Tx Abort Source 0x%04X\n", read); | |
*tx_abort_source = read; | |
for (i = 0; i < 16; i++) | |
{ | |
if (read & 1) | |
dbg_printf( "%s\n", g_aApbI2C_AbortSrc[i]); | |
read /= 2; | |
if ((read & 0xFFFF) == 0) | |
break; | |
} | |
return (I2C_OK); | |
} | |
#define I2C_MAX_BUF_SIZE 128 | |
static unsigned char rbuf[I2C_MAX_BUF_SIZE]; | |
//__align(4) static unsigned char wbuf[I2C_MAX_BUF_SIZE]; | |
static const unsigned char* wbuf= (unsigned char*)0xF7A47F00; | |
void diag_i2c_master_read_bytes(unsigned int data1, unsigned int data2, unsigned int data3) | |
{ | |
unsigned int iResult,data4; | |
data2 = 0; // slave address | |
data3 = 1; // number of bytes | |
/* Parse command arguments. */ | |
if (data1 >= I2C_MAX) //GPIO simulated I2C | |
//iResult = diag_i2c_gpio_master_writeread_bytes(data1-I2C_MAX, data2, I2C_7BIT_SLAVE_ADDR, 0, 0, rbuf, data3); | |
dbg_printf("I2C GPIO master is not enabled\n"); | |
else | |
iResult = diag_i2c_master_writeread_bytes(data1, data2, 0, 0, rbuf, data3); | |
if (iResult) | |
{ | |
if (data1 >= I2C_MAX) | |
// iResult |= diag_i2c_gpio_check_error(data1 - I2C_MAX); | |
dbg_printf("I2C GPIO master is not enabled\n"); | |
else | |
{ | |
iResult |= diag_i2c_check_error(data1, &data4); | |
dbg_printf(" error code 0x%08x\n", data4); | |
} | |
dbg_printf(" Failed\n"); | |
} | |
else | |
{ | |
unsigned int i; | |
dbg_printf("Read Data: "); | |
for (i = 0; i < data3; i++) | |
dbg_printf("0x%X ", rbuf[i]); | |
dbg_printf("\n Passed\n"); | |
} | |
} | |
void diag_i2c_master_write_bytes(unsigned int data1, unsigned int data2, unsigned int data3) | |
{ | |
unsigned int iResult,data4; | |
//clear the wbuf first, if number of bytes is | |
//less than the cmd line supplied bytes, the extra bytes will still | |
//be copied int wbuf but not sent to I2C. If number of bytes is | |
//larger than the cmd line supplied bytes, extra zeros will be sent | |
/* memset(wbuf, 0, I2C_MAX_BUF_SIZE); | |
data4 = 0; //counts how many dwords are collected | |
while (1) | |
{ | |
skipSpace( &pCmd ); | |
if ( *pCmd != '\0' ) | |
pCmd = getHexToken( pCmd, (unsigned int *)(wbuf+data4*4)); | |
else | |
break; | |
data4++; | |
}*/ | |
if (data1 >= I2C_MAX) | |
//iResult = diag_i2c_gpio_master_writeread_bytes(data1-I2C_MAX, data2, I2C_7BIT_SLAVE_ADDR, wbuf, data3, 0, 0); | |
dbg_printf("I2C GPIO master is not enabled\n"); | |
else | |
iResult = diag_i2c_master_writeread_bytes(data1, data2, (unsigned char *)wbuf, data3, 0, 0); | |
if (iResult) | |
{ | |
if (data1 >= I2C_MAX) | |
{ | |
//iResult |= diag_i2c_gpio_check_error(data1 - I2C_MAX); | |
dbg_printf("I2C GPIO master is not enabled\n"); | |
} | |
else | |
{ | |
iResult |= diag_i2c_check_error(data1, &data4); | |
dbg_printf(" error code 0x%08x\n", data4); | |
} | |
dbg_printf(" Failed\n"); | |
} | |
else | |
{ | |
unsigned int i; | |
dbg_printf( "Write Data: "); | |
for (i = 0; i < data3; i++) | |
{ | |
dbg_printf( "0x%x ", wbuf[i]); | |
} | |
dbg_printf("\n Passed\n"); | |
} | |
} | |
void diag_i2c_writeread_bytes(unsigned int data1,unsigned int data2,unsigned int data3,unsigned int data4) | |
{ | |
unsigned int iResult,data5 = 0; //counts how many dwords are collected | |
/*while (1) | |
{ | |
skipSpace( &pCmd ); | |
if ( *pCmd != '\0' ) | |
pCmd = getHexToken( pCmd, (unsigned int *)(wbuf+data5*4)); | |
else | |
break; | |
data5++; | |
}*/ | |
if (data1 >= I2C_MAX) | |
//iResult = diag_i2c_gpio_master_writeread_bytes(data1-I2C_MAX, data2, I2C_7BIT_SLAVE_ADDR, wbuf, data3, rbuf, data4); | |
dbg_printf("I2C GPIO master is not enabled\n"); | |
else | |
iResult = diag_i2c_master_writeread_bytes(data1, data2, (unsigned char *)wbuf, data3, rbuf, data4); | |
if (iResult) | |
{ | |
if (data1 >= I2C_MAX) | |
//iResult |= diag_i2c_gpio_check_error(data1 - I2C_MAX); | |
dbg_printf("I2C GPIO master is not enabled\n"); | |
else | |
{ | |
iResult |= diag_i2c_check_error(data1, &data5); | |
dbg_printf(" error code 0x%08x\n", data5); | |
} | |
dbg_printf(" Failed\n"); | |
} | |
else | |
{ | |
unsigned int i; | |
dbg_printf( "Write Data: "); | |
for (i = 0; i < data3; i++) | |
dbg_printf( "0x%X ", wbuf[i]); | |
dbg_printf( "\nRead Data: "); | |
for(i = 0; i < data4; i++) | |
dbg_printf( "0x%X ", rbuf[i]); | |
dbg_printf("\n Passed\n"); | |
} | |
} | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
/////////////////////////////////////SPI API///////////////////////////////////////////////// | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
// polling mode vs. interrupt mode | |
#define POLLING_MODE | |
// number of SPI masters in system | |
//#if defined(BERLIN) | |
#if 1 | |
#define SPI_MASTER_NUM 2 | |
#else | |
#define SPI_MASTER_NUM 3 | |
#endif | |
// SSI system clock | |
// SPI output clock can be calculated as: SPI_SYS_CLOCK/SPI_REG_BAUD | |
//#if defined(BERLIN) | |
#if 1 | |
#if PLATFORM==FPGA | |
#define SPI_SYS_CLOCK 1500 // 1.5MHz | |
#define SPI_SM_CLOCK 9000 // 9MHz | |
#else | |
#define SPI_SYS_CLOCK 75000 // 75MHz, it uses config clock | |
#define SPI_SM_CLOCK 25000 // 25MHz | |
#endif | |
#else | |
#if defined(SOC_ES1) | |
#define SPI_SYS_CLOCK 100000 // 100 MHz | |
#else | |
#define SPI_SYS_CLOCK 5000 // 5MHz | |
#endif | |
#endif | |
// SPI master TX/RX FIFO size | |
#define SPI_TX_FIFO_SIZE 64 | |
#define SPI_RX_FIFO_SIZE 64 | |
// register definitions of SPI master | |
#define SPI_REG_CTRL0 0x00 | |
#define SPI_REG_CTRL1 0x04 | |
#define SPI_REG_SSIENR 0x08 | |
#define SPI_REG_MWCR 0x0C | |
#define SPI_REG_SER 0x10 | |
#define SPI_REG_BAUD 0x14 | |
#define SPI_REG_TXFTLR 0x18 | |
#define SPI_REG_RXFTLR 0x1C | |
#define SPI_REG_TXFLR 0x20 | |
#define SPI_REG_RXFLR 0x24 | |
#define SPI_REG_SR 0x28 | |
#define SPI_REG_IMR 0x2C | |
#define SPI_REG_ISR 0x30 | |
#define SPI_REG_RISR 0x34 | |
#define SPI_REG_TXOICR 0x38 | |
#define SPI_REG_RXOICR 0x3C | |
#define SPI_REG_RXUICR 0x40 | |
#define SPI_REG_MSTICR 0x44 | |
#define SPI_REG_ICR 0x48 | |
#define SPI_REG_DMACR 0x4C | |
#define SPI_REG_DMATDLR 0x50 | |
#define SPI_REG_DMARDLR 0x54 | |
#define SPI_REG_IDR 0x58 | |
#define SPI_REG_DR 0x60 | |
// interrupt masks | |
#define IMR_MASK_RXF 0x10 | |
#define IMR_MASK_RXO 0x08 | |
#define IMR_MASK_RXU 0x04 | |
#define IMR_MASK_TXO 0x02 | |
#define IMR_MASK_TXE 0x01 | |
// interrupt status | |
#define ISR_STAT_RXF 0x10 | |
#define ISR_STAT_RXO 0x08 | |
#define ISR_STAT_RXU 0x04 | |
#define ISR_STAT_TXO 0x02 | |
#define ISR_STAT_TXE 0x01 | |
// error code definitions | |
#define SSI_OK 0 | |
#define SSI_EBADPARAM -1 // bad input parameter | |
#define SSI_EBUSRW -2 // bus read/write error | |
#define SSI_EBUSY -3 // SSI master is busy | |
enum SPI_INSTANCES | |
{ | |
SPI_0, | |
SPI_1, | |
SPI_MAX | |
}; | |
#define IOMAPPER_SPI_MASTER 0 // master id = 0 | |
#define IOMAPPER_SPI_DEVID 0 // CSn=0 | |
#ifndef MAX | |
#define MAX(a,b) (((a)>(b))?(a):(b)) | |
#define MIN(a,b) (((a)>(b))?(b):(a)) | |
#endif | |
// Macros of read/write SPI master registers | |
#define SPI_RegRead(a, pv) BFM_HOST_Bus_Read32(base_addr+(a), pv) /*(*(volatile int *)(base_addr+(a)))*/ | |
#define SPI_RegWrite(a, v) BFM_HOST_Bus_Write32(base_addr+(a), v) /**(volatile int *)(base_addr+(a)) = (v)*/ | |
// SPI master's transfer buffer, shared by TX and RX. | |
// spi_master_buffer[][0] is the number of valid TX/RX frames in buffer | |
int spi_master_buffer[SPI_MASTER_NUM][256+5]; | |
// number of receive frames | |
int spi_master_rx_number[SPI_MASTER_NUM]; | |
// transmit done flag | |
volatile int spi_master_tx_done[SPI_MASTER_NUM]; | |
// receive done flag | |
volatile int spi_master_rx_done[SPI_MASTER_NUM]; | |
// SPI master's base-address vector | |
//#if defined(BERLIN) | |
#if 1 | |
// We actually have only two SPI, but the driver always assume that | |
// SPI_BUS 0 = APB_SSI_INST0 | |
// SPI_BUS 1 = APB_SSI_INST1 | |
// SPI_BUS 2 = APB_SSI_INST2 | |
const unsigned int SPI_MASTER_BASEADDR[SPI_MASTER_NUM] = {APB_SSI_INST1_BASE, APB_SSI_INST2_BASE}; | |
#else | |
const unsigned int SPI_MASTER_BASEADDR[SPI_MASTER_NUM] = {APB_SSI_INST0_BASE, APB_SSI_INST1_BASE, APB_SSI_INST2_BASE}; | |
#endif | |
// Macros for pca995X LED driver | |
/* LED mode registers (read/write) */ | |
#define PCA995X_MODE_REGISTER_1 0x00 | |
#define PCA995X_MODE_REGISTER_2 0x01 | |
#define PCA995X_PWM_BASE_INDEX 0 | |
#define PCA995X_IREFALL_INDEX 1 | |
#define PCA995X_LEDOUT_COUNT_INDEX 2 | |
#define PCA995X_MAX_NUM_LEDS_INDEX 3 | |
#define PCA995X_INFO_LENGTH (PCA995X_MAX_NUM_LEDS_INDEX+1) | |
const unsigned char kLedInfoMap[LED_MODEL_CNT][PCA995X_INFO_LENGTH] = { | |
{0x0A, 0x40, 6, 24}, | |
{0x08, 0x45, 4, 16}, | |
}; | |
/* If auto-increment is enabled, the MSb(bit) needs to be set to 1 in register | |
* address according to datasheet. | |
* In this driver, auto-increment is enabled in pca9956_led_init function. | |
*/ | |
#define PCA995X_AUTO_INCREMENT_ADDRESS_MASK 0x80 | |
/************************************************* | |
* set SSI protocol . | |
* protocol = 0: Motorola SPI | |
* 1: TI SSP | |
* 2: National Semiconductor Microwire | |
* | |
*************************************************/ | |
static void set_ssi_protocol(int master_id, int protocol) | |
{ | |
unsigned int base_addr; | |
int value; | |
if (protocol<0 || protocol>2) return; | |
base_addr = SPI_MASTER_BASEADDR[master_id]; | |
SPI_RegRead(SPI_REG_CTRL0, &value); | |
value &= 0xffcf; | |
value |= (protocol<<4); | |
SPI_RegWrite(SPI_REG_CTRL0, value); | |
return; | |
} | |
/******************************************************************* | |
* FUNCTION: Set SPI master clock mode. | |
* PARAMETERS: master_id - ID of SSI master to config | |
* mode - 0: polarity 0 & phase 0 | |
* 1: polarity 0 & phase 1 | |
* 2: polarity 1 & phase 0 | |
* 3: polarity 1 & phase 1 | |
* RETURN: >=0 - master clock mode | |
* SSI_EBADPARAM - invalid parameters | |
* SSI_EBUSY - master is busy | |
*******************************************************************/ | |
int diag_spi_master_set_clock_mode(int master_id, int mode) | |
{ | |
unsigned int base_addr; | |
int value; | |
if (master_id<0 || master_id>SPI_MASTER_NUM-1) return (SSI_EBADPARAM); | |
if (mode<0 || mode>3) return(SSI_EBADPARAM); | |
base_addr = SPI_MASTER_BASEADDR[master_id]; | |
// check status first | |
SPI_RegRead(SPI_REG_SR, &value); | |
if (value&0x01) return (SSI_EBUSY); | |
// config SPI master clock mode | |
SPI_RegRead(SPI_REG_CTRL0, &value); | |
value &= 0xff3f; | |
value |= (mode<<6); | |
SPI_RegWrite(SPI_REG_CTRL0, value); | |
//return (mode); | |
return (SSI_OK); | |
} | |
/******************************************************************* | |
* FUNCTION: Initialize SSI master. | |
* More than one SSI masters could exist in system. | |
* PARAMETERS: master_id - ID of SSI master to initialize | |
* RETURN: SSI_OK - succeed | |
* SSI_EBADPARAM - invalid parameters | |
*******************************************************************/ | |
int diag_spi_master_init(int master_id) | |
{ | |
unsigned int base_addr; | |
if (master_id<0 || master_id>SPI_MASTER_NUM-1) return (SSI_EBADPARAM); | |
base_addr = SPI_MASTER_BASEADDR[master_id]; | |
// disable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 0); | |
// disable all interrupts | |
SPI_RegWrite(SPI_REG_IMR, 0); | |
// configure SSI as a SPI master device | |
set_ssi_protocol(master_id, 0); // SPI protocol | |
set_transfer_mode(master_id, 0); // duplex transfer mode | |
// global variables for SPI master | |
spi_master_rx_number[master_id] = 0; | |
spi_master_tx_done[master_id] = 0; | |
spi_master_rx_done[master_id] = 0; | |
return (SSI_OK); | |
} | |
/************************************************* | |
* set transfer mode. | |
* mode = 0: full-duplex transfer mode | |
* 1: transmit only | |
* 2: receive only | |
* 3: half-duplex tranfer mode | |
* | |
*************************************************/ | |
void set_transfer_mode(int master_id, int mode) | |
{ | |
unsigned int base_addr; | |
int value; | |
if (mode<0 || mode>3) return; | |
base_addr = SPI_MASTER_BASEADDR[master_id]; | |
SPI_RegRead(SPI_REG_CTRL0, &value); | |
value &= 0xfcff; | |
value |= (mode<<8); | |
SPI_RegWrite(SPI_REG_CTRL0, value); | |
return; | |
} | |
/***************************************************** | |
* select slave device | |
* flag: 1 - select | |
* 0 - de-select | |
*****************************************************/ | |
static void select_slave_device(int master_id, int dev_id, int flag) | |
{ | |
unsigned int base_addr; | |
base_addr = SPI_MASTER_BASEADDR[master_id]; | |
if (flag) | |
SPI_RegWrite(SPI_REG_SER, 1<<dev_id); | |
else | |
SPI_RegWrite(SPI_REG_SER, 0); | |
return; | |
} | |
/******************************************************************* | |
* FUNCTION: Set SPI master speed. | |
* PARAMETERS: master_id - ID of SSI master to config | |
* speed - master speed in unit of KHz | |
* RETURN: >0 - master speed | |
* SSI_EBADPARAM - invalid parameters | |
* SSI_EBUSY - master is busy | |
*******************************************************************/ | |
int diag_spi_master_set_speed(int master_id, unsigned int speed) | |
{ | |
unsigned int base_addr; | |
int value; | |
if (master_id<0 || master_id>SPI_MASTER_NUM-1) return (SSI_EBADPARAM); | |
if (speed<=0) return(SSI_EBADPARAM); | |
base_addr = SPI_MASTER_BASEADDR[master_id]; | |
// check status first | |
SPI_RegRead(SPI_REG_SR, &value); | |
if (value&0x01) return (SSI_EBUSY); | |
//#if defined(BERLIN) | |
#if 1 | |
{ | |
unsigned base_clk; | |
if (base_addr == APB_SSI_INST1_BASE) | |
base_clk = SPI_SYS_CLOCK; | |
else if (base_addr == SM_APB_SPI_BASE) | |
base_clk = SPI_SM_CLOCK; | |
// config SPI master speed | |
if (speed>base_clk) value = 1; | |
else value = (base_clk+speed-1)/speed; | |
SPI_RegWrite(SPI_REG_BAUD, value); | |
//dbg_printf("SPI speed set to %fkHz\n", (float)base_clk/(value&0xfffe)); | |
//return (base_clk/value); | |
return (SSI_OK); | |
} | |
#else | |
// config SPI master speed | |
if (speed>SPI_SYS_CLOCK) value = 1; | |
else value = (SPI_SYS_CLOCK+speed-1)/speed; | |
SPI_RegWrite(SPI_REG_BAUD, value); | |
return (SPI_SYS_CLOCK/value); | |
#endif | |
} | |
/******************************************************************* | |
* FUNCTION: half-duplex read/write frames. | |
* PARAMETERS: master_id - ID of SSI master | |
* pwbuf - pointer to transmit data buffer | |
* wnum - number of frames to transmit | |
* prbuf - pointer to receive data buffer | |
* rnum - number of frames to receive | |
* eeprom - flag when both read and write buffers have data | |
* if 1, SPI is set to eeprom mode, first tx then rx | |
* if 0, SPI tx and rx happens at the same time | |
* RETURN: SSI_OK - transfer succeed | |
* SSI_EBADPARAM - invalid parameters | |
* SSI_EBUSY - master is busy | |
* SSI_EBUSRW - master read/write fail | |
* NOTE: the maximum value of wnum is 256+4, | |
* while the maximum value of rnum is 256 | |
*******************************************************************/ | |
int diag_spi_master_writeread_frames(int master_id, int dev_id, int *pwbuf, int wnum, int *prbuf, int rnum, int eeprom) | |
{ | |
unsigned int base_addr; | |
int value; | |
#ifndef POLLING_MODE // interrupt mode | |
int irqs; | |
#endif | |
int i, j; | |
if (master_id<0 || master_id>SPI_MASTER_NUM-1) return (SSI_EBADPARAM); | |
if (wnum>260 || rnum>256) return (SSI_EBADPARAM); | |
base_addr = SPI_MASTER_BASEADDR[master_id]; | |
// check status first | |
SPI_RegRead(SPI_REG_SR, &value); | |
if (value&0x01) return (SSI_EBUSY); | |
// setup transfer | |
if ((pwbuf && wnum>0) && (prbuf && rnum>0)){ // duplex write, read transfer | |
// set transfer mode to half-duplex | |
if(eeprom) | |
set_transfer_mode(master_id, 3); //eeprom mode | |
else | |
set_transfer_mode(master_id, 0); //full-duplex mode | |
// set number of read frames | |
SPI_RegWrite(SPI_REG_CTRL1, rnum-1); | |
spi_master_rx_number[master_id] = rnum; | |
// set TX fifo threshold | |
if (wnum>SPI_TX_FIFO_SIZE) | |
set_txfifo_threshold(master_id, SPI_TX_FIFO_SIZE/2); | |
else | |
set_txfifo_threshold(master_id, 0); | |
// set RX fifo threshold | |
if (rnum>SPI_RX_FIFO_SIZE) | |
set_rxfifo_threshold(master_id, SPI_RX_FIFO_SIZE/2); | |
else | |
set_rxfifo_threshold(master_id, rnum); | |
// enable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 1); | |
// write TX FIFO | |
for (i=0; i<MIN(wnum,SPI_TX_FIFO_SIZE); i++) | |
SPI_RegWrite(SPI_REG_DR, pwbuf[i]); | |
// write the remaining TX frames into master TX/RX buffer | |
if (wnum>i){ | |
spi_master_buffer[master_id][0] = wnum - i; | |
j = wnum-i; | |
do{ spi_master_buffer[master_id][j--] = pwbuf[i++]; | |
} while (i<wnum); | |
} else spi_master_buffer[master_id][0] = 0; | |
// initiate tx_done and rx_done flags | |
spi_master_tx_done[master_id] = 0; | |
spi_master_rx_done[master_id] = 0; | |
#ifndef POLLING_MODE // interrupt mode | |
// if number of write frames is larger than TX fifo size, | |
// unmask TX empty interrupt | |
irqs = 0; | |
if (wnum>SPI_TX_FIFO_SIZE) | |
irqs |= IMR_MASK_TXE; | |
// if number of read frames is larger than RX fifo size, | |
// unmask RX full interrupt | |
if (rnum>SPI_RX_FIFO_SIZE) | |
irqs |= IMR_MASK_RXF; | |
SPI_RegWrite(SPI_REG_IMR, irqs); | |
#endif | |
// select slave device to start transfer | |
select_slave_device(master_id, dev_id, 1); | |
#ifndef POLLING_MODE // interrupt mode | |
// wait until RX finish | |
if (irqs & IMR_MASK_RXF) { /* RX interrupt wait required */ | |
while (!spi_master_rx_done[master_id]); | |
} else { /* no RX interrupt wait required */ | |
do{ | |
SPI_RegRead(SPI_REG_SR, &i); | |
} while (!(i&0x08)); /* RX fifo is empty */ | |
do { | |
SPI_RegRead(SPI_REG_SR, &i); | |
} while (i&0x01); /* RX transaction is in process */ | |
/* read data from RX fifo */ | |
SPI_RegRead(SPI_REG_RXFLR, &i); | |
for (j=0; j<i; j++) { | |
SPI_RegRead(SPI_REG_DR, &(spi_master_buffer[master_id][j+1])); | |
} | |
spi_master_buffer[master_id][0] = i; | |
} | |
#else // polling mode | |
i = 0; | |
while (i<rnum) { | |
do{ | |
SPI_RegRead(SPI_REG_SR, &j); | |
} while (!(j&0x08)); | |
SPI_RegRead(SPI_REG_SR, &j); | |
if( j&0x10 ) break; | |
SPI_RegRead(SPI_REG_RXFLR, &j); | |
while (j--){ | |
SPI_RegRead(SPI_REG_DR, &(spi_master_buffer[master_id][i+1])); | |
i ++; | |
} | |
} | |
spi_master_buffer[master_id][0] = i; | |
#endif | |
// copy out the received frames in buffer | |
if (spi_master_buffer[master_id][0]!=rnum){ | |
// SPI I/O error!!! | |
// de-select slave device | |
select_slave_device(master_id, dev_id, 0); | |
// disable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 0); | |
return (SSI_EBUSRW); | |
} | |
for (i=0; i<rnum; i++) | |
prbuf[i] = spi_master_buffer[master_id][i+1]; | |
} else if (pwbuf && wnum>0){ // write-only transfer | |
// set transfer mode to transmit-only | |
set_transfer_mode(master_id, 1); | |
// set TX fifo threshold | |
if (wnum>SPI_TX_FIFO_SIZE) | |
set_txfifo_threshold(master_id, SPI_TX_FIFO_SIZE/2); | |
else | |
set_txfifo_threshold(master_id, 0); | |
// enable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 1); | |
// write TX FIFO | |
for (i=0; i<MIN(wnum,SPI_TX_FIFO_SIZE); i++) | |
SPI_RegWrite(SPI_REG_DR, pwbuf[i]); | |
// write the remaining TX frames into master TX/RX buffer | |
if (wnum>i){ | |
spi_master_buffer[master_id][0] = wnum - i; | |
j = wnum-i; | |
do{ spi_master_buffer[master_id][j--] = pwbuf[i++]; | |
} while (i<wnum); | |
} else spi_master_buffer[master_id][0] = 0; | |
// initiate tx_done flags | |
spi_master_tx_done[master_id] = 0; | |
#ifndef POLLING_MODE // interrupt mode | |
// if number of write frames is larger than TX fifo size, | |
// unmask TX empty interrupt | |
irqs = 0; | |
if (wnum>SPI_TX_FIFO_SIZE) | |
irqs |= IMR_MASK_TXE; | |
SPI_RegWrite(SPI_REG_IMR, irqs); | |
#endif | |
// select slave device to start transfer | |
select_slave_device(master_id, dev_id, 1); | |
#ifndef POLLING_MODE // interrupt mode | |
// wait until TX finish | |
if (irqs & IMR_MASK_TXE) { /* TX interrupt wait required */ | |
while (!spi_master_tx_done[master_id]); | |
} else { /* no TX interrupt wait required */ | |
/* wait until TX fifo is empty */ | |
do { | |
SPI_RegRead(SPI_REG_SR, &j); | |
} while (!(j&0x04)); /* TX fifo is not empty */ | |
} | |
// wait until the shift register is flushed | |
do { | |
SPI_RegRead(SPI_REG_SR, &i); | |
} while (i&0x01); | |
#else // polling mode | |
i = spi_master_buffer[master_id][0]; | |
while (i>0) { | |
do { | |
SPI_RegRead(SPI_REG_SR, &j); | |
} while (!(j&0x02)); /* TX fifo is full */ | |
SPI_RegRead(SPI_REG_SR, &j); | |
if( j&0x04 ) break; /* TX fifo is empty */ | |
SPI_RegRead(SPI_REG_TXFLR, &j); | |
j = MIN(SPI_TX_FIFO_SIZE-j, i); | |
while (j-->0) { | |
SPI_RegWrite(SPI_REG_DR, spi_master_buffer[master_id][i--]); | |
} | |
} | |
spi_master_buffer[master_id][0] = i; | |
do { | |
SPI_RegRead(SPI_REG_SR, &j); | |
} while (!(j&0x04)); /* TX fifo is not empty */ | |
do { | |
SPI_RegRead(SPI_REG_SR, &j); | |
} while (j&0x01); /* SSI is transfering */ | |
if (spi_master_buffer[master_id][0]!=0){ | |
// SPI I/O error!!! | |
// de-select slave device | |
select_slave_device(master_id, dev_id, 0); | |
// disable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 0); | |
return (SSI_EBUSRW); | |
} | |
#endif | |
} else if (prbuf && rnum>0){ // read-only transfer | |
// set transfer mode to receive-only | |
set_transfer_mode(master_id, 2); | |
// set number of read frames | |
SPI_RegWrite(SPI_REG_CTRL1, rnum-1); | |
spi_master_rx_number[master_id] = rnum; | |
// set RX fifo threshold | |
if (rnum>SPI_RX_FIFO_SIZE) | |
set_rxfifo_threshold(master_id, SPI_RX_FIFO_SIZE/2); | |
else | |
set_rxfifo_threshold(master_id, rnum); | |
// enable transfer | |
SPI_RegWrite(SPI_REG_SSIENR, 1); | |
// reset RX buffer | |
spi_master_buffer[master_id][0] = 0; | |
// initiate rx_done flags | |
spi_master_rx_done[master_id] = 0; | |
// write TX FIFO to start transfer | |
SPI_RegWrite(SPI_REG_DR, 0); | |
#ifndef POLLING_MODE // interrupt mode | |
// if number of read frames is larger than RX fifo size, | |
// unmask RX full interrupt | |
irqs = 0; | |
if (rnum>SPI_RX_FIFO_SIZE) | |
irqs |= IMR_MASK_RXF; | |
SPI_RegWrite(SPI_REG_IMR, irqs); | |
#endif | |
// select slave device to start transfer | |
select_slave_device(master_id, dev_id, 1); | |
#ifndef POLLING_MODE // interrupt mode | |
// wait until RX finish | |
if (irqs & IMR_MASK_RXF) { /* RX interrupt wait required */ | |
while (!spi_master_rx_done[master_id]); | |
} else { /* no RX interrupt wait required */ | |
do{ | |
SPI_RegRead(SPI_REG_SR, &i); | |
} while (!(i&0x08)); /* RX fifo is empty */ | |
do { | |
SPI_RegRead(SPI_REG_SR, &i); | |
} while (i&0x01); /* RX transaction is in process */ | |
/* read data from RX fifo */ | |
SPI_RegRead(SPI_REG_RXFLR, &i); | |
for (j=0; j<i; j++) { | |
SPI_RegRead(SPI_REG_DR, &(spi_master_buffer[master_id][j+1])); | |
} | |
spi_master_buffer[master_id][0] = i; | |
} | |
#else // polling mode | |
for (i=0; i<rnum; i++) { | |
do { | |
SPI_RegRead(SPI_REG_SR, &j); | |
} while (!(j&0x08)); | |
SPI_RegRead(SPI_REG_SR, &j); | |
if( j&0x10 ) break; | |
SPI_RegRead(SPI_REG_DR, &(spi_master_buffer[master_id][i+1])); | |
} | |
spi_master_buffer[master_id][0] = i; | |
#endif | |
// copy out the received frames in buffer | |
if (spi_master_buffer[master_id][0]!=rnum){ | |
// SPI I/O error!!! | |
// de-select slave device | |
select_slave_device(master_id, dev_id, 0); | |
// disable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 0); | |
return (SSI_EBUSRW); | |
} | |
for (i=0; i<rnum; i++) | |
prbuf[i] = spi_master_buffer[master_id][i+1]; | |
} | |
// de-select slave device | |
select_slave_device(master_id, dev_id, 0); | |
// disable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 0); | |
return (SSI_OK); | |
} | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
/////////////////////////////////////VCORE API///////////////////////////////////////////////// | |
////////////////////////////////////////////////////////////////////////////////////////////// | |
unsigned int diag_spi_ADC_read(unsigned int channel,unsigned int mode, unsigned int master_id) | |
{ | |
unsigned int base_addr; | |
int value; | |
int i, j,rnum=3; | |
unsigned int write_buf[3]= | |
{ | |
0,0,0 | |
}; | |
unsigned int read_buf[3]= | |
{ | |
0,0,0 | |
}; | |
if((channel&0x1)==0) | |
channel>>=1; | |
else | |
channel=(channel>>1)+4; | |
if(mode) | |
write_buf[0]=0x87|((channel&0x7)<<4); | |
else | |
write_buf[0]=0x83|((channel&0x7)<<4); | |
// write_buf[1]=(write_buf[0]&0x1)<<7; | |
// write_buf[0]>>=1; | |
base_addr = SPI_MASTER_BASEADDR[master_id]; | |
//set_ssi_protocol(master_id, 0); | |
// check status first | |
SPI_RegRead(SPI_REG_SR, &value); | |
if (value&0x01) return (SSI_EBUSY); | |
//set_transfer_mode(master_id, 0); //full-duplex mode | |
diag_spi_master_set_clock_mode(master_id,3); | |
// set number of read frames | |
SPI_RegWrite(SPI_REG_CTRL1, rnum-1); | |
spi_master_rx_number[master_id] = rnum; | |
// set TX fifo threshold | |
/* if (wnum>SPI_TX_FIFO_SIZE) | |
set_txfifo_threshold(master_id, SPI_TX_FIFO_SIZE/2); | |
else*/ | |
set_txfifo_threshold(master_id, 0); | |
// set RX fifo threshold | |
if (rnum>SPI_RX_FIFO_SIZE) | |
set_rxfifo_threshold(master_id, SPI_RX_FIFO_SIZE/2); | |
else | |
set_rxfifo_threshold(master_id, rnum); | |
// enable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 1); | |
// write TX FIFO | |
for (i=0; i<3; i++) | |
SPI_RegWrite(SPI_REG_DR, write_buf[i]); | |
// write the remaining TX frames into master TX/RX buffer | |
/* if (wnum>i){ | |
spi_master_buffer[master_id][0] = wnum - i; | |
j = wnum-i; | |
do{ spi_master_buffer[master_id][j--] = pwbuf[i++]; | |
} while (i<wnum); | |
} else*/ | |
spi_master_buffer[master_id][0] = 0; | |
// initiate tx_done and rx_done flags | |
spi_master_tx_done[master_id] = 0; | |
spi_master_rx_done[master_id] = 0; | |
// select slave device to start transfer | |
select_slave_device(master_id, 0, 1);//slave id =0 | |
i = 0; | |
while (i<rnum) { | |
do{ | |
SPI_RegRead(SPI_REG_SR, &j); | |
} while (!(j&0x0A)); | |
//} while (!(j&0x02)); | |
SPI_RegRead(SPI_REG_SR, &j); | |
if( j&0x10 ) break; | |
SPI_RegRead(SPI_REG_RXFLR, &j); | |
while (j--){ | |
SPI_RegRead(SPI_REG_DR, &(spi_master_buffer[master_id][i+1])); | |
i ++; | |
} | |
} | |
spi_master_buffer[master_id][0] = i; | |
// copy out the received frames in buffer | |
if (spi_master_buffer[master_id][0]!=rnum){ | |
// SPI I/O error!!! | |
// de-select slave device | |
select_slave_device(master_id, 0, 0);//slave id =0 | |
// disable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 0); | |
return (SSI_EBUSRW); | |
} | |
for (i=0; i<rnum; i++) | |
read_buf[i] = spi_master_buffer[master_id][i+1]; | |
// de-select slave device | |
select_slave_device(master_id, 2, 0); | |
// disable SPI | |
SPI_RegWrite(SPI_REG_SSIENR, 0); | |
value=((read_buf[1]&0x7F)<<5)|((read_buf[2]&0xF8)>>3); | |
dbg_printf("12 bit ADC read back value is 0x%x (%d) = %f V\n",value,value,(float)value/4095*2.048); | |
gpioSet(5,0x10,0x10); | |
//pinmux_write(1,0,1); | |
diag_spi_master_set_clock_mode(master_id,0); | |
return (value); | |
} | |
int read_adc( int chan_num) | |
{ | |
#if PEK_NOT_DONGLE == 1 | |
int data2; | |
unsigned char wbuf1[2]= | |
{ | |
0x03,0x70 | |
}; | |
unsigned char wbuf2[2]= | |
{ | |
0x01,0x86 | |
}; | |
gpioSet(0, 0, 0); // GPIO 7 -> 0 | |
gpioSet(1,0x200,0x200); // GPIO 41 ->1 | |
//pinmux_write(9,3); | |
// Select MUX to ADC SPI Chip Select | |
//diag_i2c_master_init(0); | |
//diag_i2c_master_writeread_bytes( 0, 0x38, wbuf1, 2, 0, 0); | |
//diag_i2c_master_writeread_bytes( 0, 0x38, wbuf2, 2, 0, 0); | |
// Init SPI and Speed | |
diag_spi_master_init(0); | |
diag_spi_master_set_speed(0,78); | |
data2 = diag_spi_ADC_read(chan_num,1,0); | |
dbg_printf("Read channel #%d : 0x%04x\n", chan_num, data2); | |
//change I2C expander to default | |
//wbuf1[0]=0x03; | |
// wbuf1[1]=0xF8; | |
//wbuf2[0]=0x01; | |
// wbuf2[1]=0x06; | |
//pinmux_write(9,3); | |
// Select MUX to ADC SPI Chip Select | |
//diag_i2c_master_init(0); | |
// diag_i2c_master_writeread_bytes( 0, 0x38, wbuf1, 2, 0, 0); | |
//diag_i2c_master_writeread_bytes( 0, 0x38, wbuf2, 2, 0, 0); | |
// reset_perif(); | |
return data2; | |
#else | |
(void)chan_num; | |
dbg_printf("Only valid on PEK boards\n"); | |
return 0; | |
#endif | |
} | |
void reset_perif(void) | |
{ | |
unsigned int i = 0; | |
BFM_HOST_Bus_Write32(MEMMAP_CHIP_CTRL_REG_BASE+RA_Gbl_ResetTrigger,MSK32Gbl_ResetTrigger_perifSyncReset); | |
for(i = 0; i< 0x1000; i++); | |
BFM_HOST_Bus_Write32(MEMMAP_CHIP_CTRL_REG_BASE+RA_Gbl_ResetTrigger,0); | |
dbg_printf("Perif is reset\n"); | |
} | |
int vcore_set_voltage(int code) | |
{ | |
#if PEK_NOT_DONGLE == 1 | |
unsigned char wbuf1[2]= | |
{ | |
0x03,0x70 | |
}; | |
unsigned char wbuf2[2]= | |
{ | |
0x01, | |
0x0E, | |
}; | |
int spi_wbuf[3]; | |
gpioSet(0,0x80,0x80); // GPIO SET 7 -> 1 | |
gpioSet(1,0x400,0x400); // GPIO SET 42,41 -> (1,0) | |
spi_wbuf[0] = 0xb0; | |
spi_wbuf[1] = (code>>8) & 0x0ff; | |
spi_wbuf[2] = code & 0x0ff; | |
// pinmux_write(9,3); | |
// Select MUX to PMIC SPI Chip Select | |
// diag_i2c_master_init(0); | |
// diag_i2c_master_writeread_bytes( 0, 0x38, wbuf1, 2, 0, 0); | |
// diag_i2c_master_writeread_bytes( 0, 0x38, wbuf2, 2, 0, 0); | |
// pinmux_write(8,0); | |
// pinmux_write(9,1); | |
// pinmux_write(10,0); | |
// pinmux_write(11,0); | |
diag_spi_master_init(0); | |
diag_spi_master_set_speed(0,1000); | |
diag_spi_master_writeread_frames(0,0,spi_wbuf,3,0,0,0); | |
//change I2C expander to default | |
// wbuf1[0]=0x03; | |
//wbuf1[1]=0xF8; | |
//wbuf2[0]=0x01; | |
//wbuf2[1]=0x06; | |
//pinmux_write(9,3); | |
// Select MUX to ADC SPI Chip Select | |
//diag_i2c_master_init(0); | |
//diag_i2c_master_writeread_bytes( 0, 0x38, wbuf1, 2, 0, 0); | |
//diag_i2c_master_writeread_bytes( 0, 0x38, wbuf2, 2, 0, 0); | |
//reset_perif(); | |
return 0; | |
#else | |
(void)code; | |
dbg_printf("Only valid on PEK boards\n"); | |
return 0; | |
#endif | |
} | |
#define DELAY_VCORE 0x45000//400MHz CPU, cache is not enabled | |
int vcore_set(int mv, int step10, int ref1050) | |
{ | |
#if PEK_NOT_DONGLE == 1 | |
int cur_v; | |
int i; | |
int last_step; | |
mv = mv*2; | |
// Pot case | |
// Step are 8 per 10mv | |
// 1115 mv = 0x2E0 | |
step10 = 0x08; | |
ref1050 = 0x2E0; | |
vcore_set_voltage( ref1050 ); | |
for(i=0;i<DELAY_VCORE;i++); | |
cur_v = read_adc(7); | |
dbg_printf("Starting voltage is %d mv\n", cur_v/2); | |
if ((cur_v>(1125*2))||(cur_v<(1105*2))) | |
{ | |
dbg_printf("Out of bound starting voltage!\n"); | |
reset_perif(); | |
return 1; | |
} | |
if (cur_v > mv) // current voltage is higher than target, go down by steps. | |
{ | |
while ((cur_v-mv)>20) | |
{ | |
ref1050 += step10; | |
vcore_set_voltage( ref1050 ); | |
for(i=0;i<DELAY_VCORE;i++); | |
cur_v = read_adc(7); | |
} | |
last_step = ((cur_v-mv)*step10)/20; | |
ref1050 += last_step; | |
vcore_set_voltage( ref1050 ); | |
for(i=0;i<DELAY_VCORE;i++); | |
cur_v = read_adc(7); | |
} | |
else // current voltage is lower than target. go up by steps. | |
{ | |
while ((mv-cur_v)>20) | |
{ | |
ref1050 -= step10; | |
vcore_set_voltage( ref1050 ); | |
for(i=0;i<DELAY_VCORE;i++); | |
cur_v = read_adc(7); | |
} | |
last_step = ((mv-cur_v)*step10)/20; | |
ref1050 -= last_step; | |
vcore_set_voltage( ref1050 ); | |
for(i=0;i<DELAY_VCORE;i++); | |
cur_v = read_adc(7); | |
} | |
dbg_printf("Rough voltage is %d mv\n", cur_v/2); | |
last_step = ((mv-cur_v)*step10)/20; | |
ref1050 -= last_step; | |
vcore_set_voltage( ref1050 ); | |
for(i=0;i<DELAY_VCORE;i++); | |
cur_v = read_adc(7); | |
dbg_printf("Fine voltage is %d mv\n", cur_v/2); | |
if ((cur_v>(mv+10))||(cur_v<(mv-10))) | |
{ | |
dbg_printf("Ending Voltage out of bound!\n"); | |
return 1; | |
} | |
reset_perif(); | |
dbg_printf("\nPerif has been reset.SPI handler is reset\nFor DIAG boot Please use:\n"); | |
dbg_printf(" Turnon DDR power 'gpiowrite 2 0x40 0x40'\n Use 'mempll [frequency]'\nThen 'bootdiag'\n"); | |
return 0; | |
#else | |
(void)ref1050; | |
(void)mv; | |
(void)step10; | |
dbg_printf("Only valid on PEK boards\n"); | |
return 0; | |
#endif | |
} | |
// VIndex: [0-0.90,1-0.925,2-0.95(default),3-0.975,4-1.00,5-1.025,6-1.050, 14-1.25V] | |
int diag_i2c_vcore_control(int master_id, int volt_index) | |
{ | |
#if 1 //PMIC_I2C_INTERFACE | |
static int FPWM_mode = 0; | |
unsigned char buff[2]; | |
unsigned char read = 0xff; | |
unsigned char slaveAddr = 0x19; // PG868 slave address is 0x19 | |
int ret; | |
if(FPWM_mode == 0) | |
{ | |
buff[0] = 0x02; // PG867 buck2 target voltage 2 (active) register | |
diag_i2c_master_init(master_id); | |
diag_i2c_master_set_addr_type(I2C_7BIT_SLAVE_ADDR); | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 1, &read, 1); | |
if (ret != 0) | |
{ | |
dbg_printf(" i2c read fail\n"); | |
return ret; | |
} | |
buff[1] = (read&0xFC)| 0x3; | |
// write | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 2, 0, 0); | |
if (ret != 0) | |
{ | |
dbg_printf(" i2c write fail\n"); | |
return ret; | |
} | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 1, &read, 1); | |
if (ret != 0) | |
{ | |
dbg_printf(" i2c read fail\n"); | |
return ret; | |
} | |
if (buff[1] != read) | |
{ | |
dbg_printf(" PWM mode control fail, read:0x%02x != write:0x%02x\n", read, buff[1]); | |
return 1; | |
} | |
dbg_printf(" PWM mode switch success!\n"); | |
FPWM_mode = 1; | |
} | |
buff[0] = 0x24; // PG868 buck1 target voltage 2 (active) register | |
buff[1] = 0x7 + volt_index; // 0x7 is 0.90v. each step is 0.025 | |
ret = diag_i2c_master_init(master_id); | |
ret = diag_i2c_master_set_addr_type(I2C_7BIT_SLAVE_ADDR); | |
// write | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 2, 0, 0); | |
if (ret != 0) | |
{ | |
dbg_printf( " i2c write fail\n"); | |
return ret; | |
} | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 1, &read, 1); | |
if (ret != 0) | |
{ | |
dbg_printf( " i2c read fail\n"); | |
return ret; | |
} | |
if (buff[1] != read) | |
{ | |
dbg_printf( " i2c vcore control fail, read:0x%02x != write:0x%02x\n", read, buff[1]); | |
return 1; | |
} | |
dbg_printf( " vcore is %04d mv\n", 900 +25*volt_index); | |
return 0; | |
#else | |
return 0; | |
#endif | |
} | |
// VIndex: [0-1.20,1:1.225,2:1.25,3:1.275,4:1.3,5-1.325,6:1.350(default),,, 12:1.5v] | |
int diag_i2c_vddr_control(int master_id, int volt_index) | |
{ | |
#if 1 //PMIC_I2C_INTERFACE | |
static int FPWM_mode = 0; | |
unsigned char buff[2]; | |
unsigned char read = 0xff; | |
unsigned char slaveAddr = 0x19; // PG868 slave address is 0x19 | |
int ret; | |
if(FPWM_mode == 0) | |
{ | |
buff[0] = 0x02; // PG867 buck2 target voltage 2 (active) register | |
diag_i2c_master_init(master_id); | |
diag_i2c_master_set_addr_type(I2C_7BIT_SLAVE_ADDR); | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 1, &read, 1); | |
if (ret != 0) | |
{ | |
dbg_printf(" i2c read fail\n"); | |
return ret; | |
} | |
buff[1] = (read&0xFC)| 0x3; | |
// write | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 2, 0, 0); | |
if (ret != 0) | |
{ | |
dbg_printf(" i2c write fail\n"); | |
return ret; | |
} | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 1, &read, 1); | |
if (ret != 0) | |
{ | |
dbg_printf(" i2c read fail\n"); | |
return ret; | |
} | |
if (buff[1] != read) | |
{ | |
dbg_printf(" PWM mode control fail, read:0x%02x != write:0x%02x\n", read, buff[1]); | |
return 1; | |
} | |
dbg_printf(" PWM mode switch success!\n"); | |
FPWM_mode = 1; | |
} | |
buff[0] = 0x13; // PG867 buck2 target voltage 2 (active) register | |
buff[1] = 0x18 + volt_index; //0x18 is 1.20v. each step is 0.025 | |
diag_i2c_master_init(master_id); | |
diag_i2c_master_set_addr_type(I2C_7BIT_SLAVE_ADDR); | |
// write | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 2, 0, 0); | |
if (ret != 0) | |
{ | |
dbg_printf(" i2c write fail\n"); | |
return ret; | |
} | |
ret = diag_i2c_master_writeread_bytes(master_id, slaveAddr, buff, 1, &read, 1); | |
if (ret != 0) | |
{ | |
dbg_printf(" i2c read fail\n"); | |
return ret; | |
} | |
if (buff[1] != read) | |
{ | |
dbg_printf( " i2c vddr control fail, read:0x%02x != write:0x%02x\n", read, buff[1]); | |
return 1; | |
} | |
dbg_printf( " [I2C control]vddr is %04d mv\n", 1200+25*volt_index); | |
return 0; | |
#else | |
return 0; | |
#endif | |
} | |
static int diag_i2c_check_regulator(int master_id, unsigned char addr, unsigned char command, unsigned char *val) | |
{ | |
unsigned char buff = command; | |
unsigned char read = 0xFF; | |
int ret; | |
ret = diag_i2c_master_init(master_id); | |
if (ret == I2C_ERROR) { | |
dbg_printf(" failed to init master\n"); | |
return ret; | |
} | |
ret = diag_i2c_master_set_addr_type(I2C_7BIT_SLAVE_ADDR); | |
if (ret == I2C_ERROR) { | |
dbg_printf(" failed to set addr type\n"); | |
return ret; | |
} | |
ret = diag_i2c_master_writeread_bytes(master_id, addr, &buff, 1, &read, 1); | |
if (ret == I2C_ERROR) { | |
dbg_printf(" i2c read fail\n"); | |
return ret; | |
} | |
if (val) { | |
*val = read; | |
} | |
return 0; | |
} | |
int sy21202_val = 0; | |
int diag_i2c_check_sy21202(int master_id) | |
{ | |
int ret; | |
unsigned char val = 0xFF; | |
unsigned char voltage; | |
const unsigned char addr = 0x66; | |
const unsigned char command = 0x00; | |
ret = diag_i2c_check_regulator(master_id, addr, command, &val); | |
if (ret != 0) { | |
dbg_printf("diag_i2c_check_sy21202 ret: %d\n", ret); | |
return 1; | |
} | |
dbg_printf("diag_i2c_check_sy21202 val: %d\n", val); | |
sy21202_val = val; | |
// validate BUCK_EN and default MODE | |
if ((val & (1 << 7)) && !(val & (1 << 6))) { | |
// Check voltage is within the expected range | |
// Range from kernel/arch/arm/march-berlin/opp.c | |
// 0x15 -> 1025 mV to 0x23 -> 1200 mV | |
voltage = (val & 0x3F); | |
if (voltage >= 0x15 && voltage <= 0x23) { | |
return 0; | |
} | |
} | |
return 1; | |
} | |
int pg86x_val = 0; | |
int diag_i2c_check_pg86x(int master_id) | |
{ | |
int ret; | |
unsigned char val = 0xFF; | |
const unsigned char addr = 0x19; | |
const unsigned char command = 0x24; | |
ret = diag_i2c_check_regulator(master_id, addr, command, &val); | |
if (ret != 0) { | |
dbg_printf("diag_i2c_check_pg86x ret: %d\n", ret); | |
return 1; | |
} | |
dbg_printf("diag_i2c_check_pg86x val: %d\n", val); | |
pg86x_val = val; | |
// Validate that the voltage is within the expected range | |
// Range from kernel/arch/arm/march-berlin/opp.c | |
// 0x0C -> 1025 mV to 0x13 -> 1200 mV | |
if (pg86x_val >= 0x0C && pg86x_val <= 0x13) { | |
return 0; | |
} | |
return 1; | |
} | |
// Initializes the PCA9956 LED driver at I2C address |slave_addr|. | |
int diag_i2c_led_init(int master_id, unsigned char slave_addr, enum led_chip_model_t model) { | |
unsigned char buff[2]; | |
int ret; | |
diag_i2c_master_init(master_id); | |
diag_i2c_master_set_addr_type(I2C_7BIT_SLAVE_ADDR); | |
/* Initialize NXP LED driver */ | |
/* Set all IREF values */ | |
buff[0] = kLedInfoMap[model][PCA995X_IREFALL_INDEX]; | |
buff[1] = 0xFF; | |
ret = diag_i2c_master_writeread_bytes(master_id, slave_addr, buff, 2, 0, 0); | |
if (ret != 0) { | |
dbg_printf("%s: failed to set all IREF values.\n", __func__); | |
return ret; | |
} | |
/* Set Mode1 register to enable I2C auto-increment for MODE1 to | |
* IREF23 control registers (00h to 39h). | |
*/ | |
buff[0] = PCA995X_MODE_REGISTER_1; | |
buff[1] = 0x40; | |
ret = diag_i2c_master_writeread_bytes(master_id, slave_addr, buff, 2, 0, 0); | |
if (ret != 0) { | |
dbg_printf("%s: failed to set Mode 1 registers.\n", __func__); | |
return ret; | |
} | |
size_t ledout_count = kLedInfoMap[model][PCA995X_LEDOUT_COUNT_INDEX]; | |
unsigned char val[ledout_count + 3]; | |
size_t i; | |
val[0] = PCA995X_MODE_REGISTER_2 | PCA995X_AUTO_INCREMENT_ADDRESS_MASK; | |
val[1] = 0x05; | |
for (i = 2; i < ledout_count+2; ++i) { | |
val[i] = 0xFF; | |
} | |
val[ledout_count+2] = 0x08; | |
ret = diag_i2c_master_writeread_bytes(master_id, slave_addr, val, sizeof(val), | |
0, 0); | |
if (ret < 0) { | |
dbg_printf("%s: failed on initilization LED.", __func__); | |
return ret; | |
} | |
return 0; | |
} | |
// Sets the first |size| LEDs of PCA9956 with address |slave_addr| to |frame|. | |
int diag_i2c_led_set_frame(int master_id, unsigned char slave_addr, | |
unsigned char *frame, size_t size, enum led_chip_model_t model) { | |
int ret; | |
size_t max_num_leds = kLedInfoMap[model][PCA995X_MAX_NUM_LEDS_INDEX]; | |
if (size > max_num_leds) { | |
dbg_printf("%s: Too many LEDs specified: %d", __func__, size); | |
size = max_num_leds; | |
} | |
// Build buffer for writeread_bytes | |
unsigned char val[max_num_leds + 1]; | |
val[0] = kLedInfoMap[model][PCA995X_PWM_BASE_INDEX] | PCA995X_AUTO_INCREMENT_ADDRESS_MASK; | |
size_t i; | |
for (i = 0; i < size; ++i) { | |
val[i + 1] = frame[i]; | |
} | |
for (i = size; i < max_num_leds; ++i) { | |
val[i + 1] = 0; | |
} | |
ret = diag_i2c_master_writeread_bytes(master_id, slave_addr, val, sizeof(val), | |
0, 0); | |
if (ret < 0) { | |
dbg_printf("%s: failed to set LEDs.", __func__); | |
return ret; | |
} | |
return 0; | |
} | |
//////////////////////////////////////////////////////////// | |
/* | |
#define OTP_BindInfo1H (MEMMAP_TSI_REG_BASE + 0x7DC) | |
void parsePVCOMPCmd( unsigned char Index ) | |
{ | |
unsigned int data,Leakage; | |
unsigned int lkdID[9]={196, 248, 296, 348, 396, 448, 496, 548, 596}; | |
unsigned int *ptr = &lkdID; | |
//Chip Leakage INFO | |
BFM_HOST_Bus_Read32(OTP_BindInfo1H, &data); | |
Leakage = ((data>>8)&0xFF) * 4; // 4mv/step in BG2_CD project. | |
dbg_printf(" The Chipset leakage is %d(mA).\n",Leakage); | |
if (Index == 2) | |
{ | |
//diag_i2c_pwm_mode(0,0,1); | |
if (Leakage == 0) | |
{ | |
diag_i2c_vcore_control(0, 8); // 1.1v. | |
dbg_printf(" Warning message: Leakage ID is zero! Set vcore to 1.1v. \n"); | |
} | |
else | |
{ | |
if (0 < Leakage && Leakage <= *ptr) | |
, (0, 10); //1.150v. | |
else if (*ptr < Leakage && Leakage <= *(ptr+1)) | |
diag_i2c_vcore_control(0, 9); // 1.125v. | |
else if (*(ptr+1) < Leakage && Leakage <= *(ptr+2)) | |
diag_i2c_vcore_control(0, 8); // 1.100v. | |
else if (*(ptr+2) < Leakage && Leakage <= *(ptr+3)) | |
diag_i2c_vcore_control(0, 7); // 1.075v. | |
else if (*(ptr+3) < Leakage && Leakage <= *(ptr+4)) | |
diag_i2c_vcore_control(0, 6); // 1.050v. | |
else if (*(ptr+4) < Leakage && Leakage <= *(ptr+5)) | |
diag_i2c_vcore_control(0, 5); // 1.025v. | |
else if (*(ptr+5) < Leakage && Leakage <= *(ptr+6)) | |
diag_i2c_vcore_control(0, 4); // 1.000v. | |
else if (*(ptr+6) < Leakage && Leakage <= *(ptr+7)) | |
diag_i2c_vcore_control(0, 3); // 0.975v. | |
else if (*(ptr+7) < Leakage && Leakage <= *(ptr+8)) | |
diag_i2c_vcore_control(0, 2); // 0.950v. | |
else | |
dbg_printf(" Warning message: Leakage ID is out of range: (0-596mA), Keep harware default vcore.\n"); | |
} | |
} | |
else | |
{ | |
dbg_printf(" PEK boards with PVCOMP table -3%\n"); | |
if (Leakage == 0) | |
{ | |
vcore_set(1100, 0x08, 0x2E0); // 1.1v. | |
dbg_printf(" Warning message: Leakage ID is zero! Set vcore to 1.1v. \n"); | |
} | |
else | |
{ | |
if (0 < Leakage && Leakage <= *ptr) | |
vcore_set(1115, 0x08, 0x2E0); //1.150v. | |
else if (*ptr < Leakage && Leakage <= *(ptr+1)) | |
vcore_set(1091, 0x08, 0x2E0); // 1.125v. | |
else if (*(ptr+1) < Leakage && Leakage <= *(ptr+2)) | |
vcore_set(1067, 0x08, 0x2E0); // 1.100v. | |
else if (*(ptr+2) < Leakage && Leakage <= *(ptr+3)) | |
vcore_set(1042, 0x08, 0x2E0); // 1.075v. | |
else if (*(ptr+3) < Leakage && Leakage <= *(ptr+4)) | |
vcore_set(1018, 0x08, 0x2E0); // 1.050v. | |
else if (*(ptr+4) < Leakage && Leakage <= *(ptr+5)) | |
vcore_set(994, 0x08, 0x2E0); // 1.025v. | |
else if (*(ptr+5) < Leakage && Leakage <= *(ptr+6)) | |
vcore_set(970, 0x08, 0x2E0); // 1.000v. | |
else if (*(ptr+6) < Leakage && Leakage <= *(ptr+7)) | |
vcore_set(945, 0x08, 0x2E0); // 0.975v. | |
else if (*(ptr+7) < Leakage && Leakage <= *(ptr+8)) | |
vcore_set(921, 0x08, 0x2E0); // 0.950v. | |
else | |
dbg_printf(" Warning message: Leakage ID is out of range: (0-596mA), Keep harware default vcore.\n"); | |
} | |
} | |
} | |
*/ | |
#if 0 | |
#define LA_TRIGGER_ENABLE 0 | |
/********************************************************************** | |
* | |
* Filename: memtest.c | |
* | |
* Description: General-purpose memory testing functions. | |
* | |
* Notes: This software can be easily ported to systems with | |
* different data bus widths by redefining 'datum'. | |
* | |
* | |
* Copyright (c) 1998 by Michael Barr. This software is placed into | |
* the public domain and may be used for any purpose. However, this | |
* notice must not be changed or removed and no warranty is either | |
* expressed or implied by its publication or distribution. | |
**********************************************************************/ | |
#define PATTERN_STARTING_VALUE 9 | |
#define PATTERN_INCREMENT 7 | |
#define DRAM_START_ADDR 0 | |
#define AT_SUCCESS 0 | |
#define UINT32 unsigned int | |
#define UINT8 unsigned char | |
/********************************************************************** | |
* | |
* Function: memTestDevice() | |
* | |
* Description: Test the integrity of a physical memory device by | |
* performing an increment/decrement test over the | |
* entire region. In the process every storage bit | |
* in the device is tested as a zero and a one. The | |
* base address and the size of the region are | |
* selected by the caller. | |
* | |
* Notes: | |
* | |
* Returns: NULL if the test succeeds. | |
* | |
* A non-zero result is the first address at which an | |
* incorrect value was read back. By examining the | |
* contents of memory, it may be possible to gather | |
* additional information about the problem. | |
* | |
**********************************************************************/ | |
#if 0 | |
int memTestDevice(volatile datum * baseAddress, unsigned long nBytes) | |
{ | |
unsigned long offset; | |
unsigned long nWords = nBytes / sizeof(datum); | |
datum pattern; | |
datum antipattern; | |
hexout(" : mtd ", (void*) baseAddress, ""); | |
hexout(" - ", (void*) &baseAddress[nWords], "\r"); | |
/* | |
* Fill memory with a known pattern. | |
*/ | |
for (pattern = initial_pattern, offset = 0; | |
offset < nWords; pattern++, offset++) { | |
if (0 == offset % (1024*128)) { | |
hexout(0, (void*) &baseAddress[offset], "\r"); | |
} | |
baseAddress[offset] = pattern; | |
} | |
/* | |
* Check each location and invert it for the second pass. | |
*/ | |
for (pattern = initial_pattern, offset = 0; | |
offset < nWords; pattern++, offset++) { | |
if (0 == offset % (1024*128)) { | |
hexout(0, (void*) &baseAddress[offset], "\r"); | |
} | |
if (baseAddress[offset] != pattern) { | |
failure(">0 ", | |
(void*) &baseAddress[offset], | |
(void*) baseAddress[offset], | |
(void*) pattern); | |
return(1); | |
} | |
antipattern = ~pattern; | |
baseAddress[offset] = antipattern; | |
} | |
/* | |
* Check each location for the inverted pattern and do not zero it, | |
* despite what the previous comment said. | |
*/ | |
for (pattern = initial_pattern, offset = 0; | |
offset < nWords; pattern++, offset++) { | |
if (0 == offset % (1024*128)) { | |
hexout(0, (void*) &baseAddress[offset], "\r"); | |
} | |
antipattern = ~pattern; | |
if (baseAddress[offset] != antipattern) { | |
failure(">1 ", | |
(void *)&baseAddress[offset], | |
(void *) baseAddress[offset], | |
(void *) ~pattern); | |
return(1); | |
} | |
} | |
return(0); | |
} | |
#endif | |
#if LA_TRIGGER_ENABLE | |
#define LA_TRIGGER BFM_HOST_Bus_Write32(0x1800E000, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800E004, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800E008, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800E00c, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800E010, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800E014, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800E018, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800E01c, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800F000, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800F004, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800F008, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800F00c, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800F010, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800F014, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800F018, 0xabcdabcd); \ | |
BFM_HOST_Bus_Write32(0x1800F01c, 0xabcdabcd); | |
#else | |
#define LA_TRIGGER | |
#endif | |
/********************************************************************** | |
* | |
* Function: memTestDataMask() | |
* | |
* Description: Test the data masks by writing a byte pattern and | |
* reading it back. See pages 35-37 of Beth Leonard's | |
* November 2 Limbo notebook for more details. | |
* | |
* Notes: StartAddress must be divisible by 8. | |
* Author: Written by Beth Leonard, November 20, 2000. | |
* | |
* Returns: 0 if the test succeeds. | |
* A non-zero result is the first bit that failed, 1-8. | |
* | |
**********************************************************************/ | |
int memTestDataMask(volatile UINT32 * startAddress, UINT32 totalBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
char pattern[4]; | |
char antipattern[4]; | |
UINT32 i = 0; | |
volatile char * byteAddress = (char *) startAddress; | |
pattern [3] = 0xEE; antipattern[3] = 0x11; | |
pattern [2] = 0xEE; antipattern[2] = 0x11; | |
pattern [1] = 0xAD; antipattern[1] = 0x52; | |
pattern [0] = 0xDE; antipattern[0] = 0x21; | |
//minPrintf("\r\nmemTestDataMask: "); | |
/* Check bottom half for DM stuck at 1 */ | |
for( i=0; i< 4; i++) | |
{ | |
byteAddress[i] = pattern[i]; | |
if(byteAddress[i] != pattern[i]) | |
{ | |
//reportPatternFailure(((UINT32)&startAddress[i]), byteAddress[i], pattern[i], true); | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)byteAddress+((unsigned int)i)), byteAddress[i],pattern[i]); | |
return 1; | |
} | |
byteAddress[i] = antipattern[i]; | |
if(byteAddress[i] != antipattern[i]) | |
{ | |
//reportPatternFailure(((UINT32)&startAddress[i]), byteAddress[i], pattern[i], true); | |
dbg_printf( " Fail_b: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)byteAddress+((unsigned int)i)), byteAddress[i],antipattern[i]); | |
return 1; | |
} | |
} | |
/* Check top half for stuck at 1, bottom half for stuck at 0 */ | |
for(i=0; i<4; i++) | |
{ | |
byteAddress[i+4] = pattern [i]; | |
if( byteAddress[i] != antipattern[i] ) | |
{ | |
//reportPatternFailure(((UINT32)&startAddress[i]), byteAddress[i], antipattern[i], true); | |
dbg_printf( " Fail_c: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)byteAddress+((unsigned int)i)), byteAddress[i],antipattern[i]); | |
return 1; | |
} | |
if( byteAddress[i+4] != pattern[i] ) | |
{ | |
//reportPatternFailure(((UINT32)&startAddress[i+4]), byteAddress[i+4], pattern[i], true); | |
return 1; | |
} | |
byteAddress[i+4] = antipattern[i]; | |
if(byteAddress[i+4] != antipattern[i] ) | |
{ | |
dbg_printf( " Fail_d: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)byteAddress+((unsigned int)i)+4), byteAddress[i+4],antipattern[i]); | |
//reportPatternFailure(((UINT32)&startAddress[i+4]), byteAddress[i+4], antipattern[i], true); | |
return 1; | |
} | |
} | |
/* Check top half for stuck at 0. */ | |
for(i=0; i<4; i++) | |
{ | |
byteAddress[i] = pattern[i]; | |
if(byteAddress[i+4] != antipattern[i]) | |
{ | |
dbg_printf( " Fail_e: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)byteAddress+((unsigned int)i)+4), byteAddress[i+4],antipattern[i]); | |
//reportPatternFailure(((UINT32)&startAddress[i+4]), byteAddress[i+4], antipattern[i], true); | |
return 1; | |
} | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"DataMask"); | |
return AT_SUCCESS; | |
} | |
/********************************************************************** | |
* | |
* Function: memTestDataBus() | |
* | |
* Description: Test the data bus wiring in a memory region by | |
* performing a walking 1's test at a fixed address | |
* within that region. The address (and hence the | |
* memory region) is selected by the caller. | |
* | |
* Notes: | |
* | |
* Returns: 0 if the test succeeds. | |
* A non-zero result is the first pattern that failed. | |
* | |
**********************************************************************/ | |
int memTestDataBus(volatile UINT32 * address, UINT32 totalBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
UINT32 pattern; | |
//minPrintf("\r\nmemTestDataBus: "); | |
/* | |
* Perform a walking 1's test at the given address. | |
*/ | |
for (pattern = 1; pattern != 0; pattern <<= 1) | |
{ | |
/* | |
* Write the test pattern to both halves of the 64 bit word. | |
*/ | |
address[0] = pattern; | |
address[1] = pattern; | |
/* | |
* Read it back (immediately is okay for this test). | |
*/ | |
if (address[0] != pattern) | |
{ | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)address), address[0],pattern); | |
//reportPatternFailure((UINT32)&address[0], address[0], pattern, false); | |
return (1); | |
} | |
if (address[1] != pattern) | |
{ | |
dbg_printf( " Fail_b: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)address+4), address[1],pattern); | |
//reportPatternFailure((UINT32)&address[1], address[1], pattern, false); | |
return (1); | |
} | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"DataBus"); | |
return (AT_SUCCESS); | |
} /* memTestDataBus() */ | |
/********************************************************************** | |
* | |
* Function: memTestAddressBus() | |
* | |
* Description: Test the address bus wiring in a memory region by | |
* performing a walking 1's test on the relevant bits | |
* of the address and checking for aliasing. This test | |
* will find single-bit address failures such as stuck | |
* -high, stuck-low, and shorted pins. The base address | |
* and size of the region are selected by the caller. | |
* | |
* Notes: For best results, the selected base address should | |
* have enough LSB 0's to guarantee single address bit | |
* changes. For example, to test a 64-Kbyte region, | |
* select a base address on a 64-Kbyte boundary. Also, | |
* select the region size as a power-of-two--if at all | |
* possible. | |
* | |
* Returns: NULL if the test succeeds. | |
* A non-zero result is the first address at which an | |
* aliasing problem was uncovered. By examining the | |
* contents of memory, it may be possible to gather | |
* additional information about the problem. | |
* | |
* Refer http://www.netrino.com/Articles/MemoryTesting/index.html | |
* | |
**********************************************************************/ | |
int memTestAddressBus(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
//SW -fixes a bug in the addressMask value | |
// Refer http://www.netrino.com/Articles/MemoryTesting/index.html | |
// Datum size is assumed to be 4 bytes for our case | |
unsigned long addressMask = (nBytes >> 2 ) -1; | |
//SW | |
unsigned long offset; | |
unsigned long testOffset; | |
UINT32 pattern = 0xAAAAAAAA; | |
UINT32 antipattern = 0x55555555; | |
//minPrintf("\r\nmemTestAddressBus: "); | |
/* | |
* Write the default pattern at each of the power-of-two offsets. | |
*/ | |
for (offset = sizeof(UINT32); (offset & addressMask) != 0; offset <<= 1) | |
{ | |
baseAddress[offset] = pattern; | |
} | |
/* | |
* Check for address bits stuck high. | |
*/ | |
testOffset = 0; | |
baseAddress[testOffset] = antipattern; | |
for (offset = sizeof(UINT32); (offset & addressMask) != 0; offset <<= 1) | |
{ | |
if (baseAddress[offset] != pattern) | |
{ | |
/* | |
failure(">0 ", | |
(void*) &baseAddress[offset], | |
(void*) baseAddress[offset], | |
(void*) pattern); | |
*/ | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],pattern); | |
//reportPatternFailure((UINT32)&baseAddress[offset], baseAddress[offset], pattern, false); | |
return 1; | |
} | |
} | |
baseAddress[testOffset] = pattern; | |
/* | |
* Check for address bits stuck low or shorted. | |
*/ | |
for (testOffset = sizeof(UINT32); (testOffset & addressMask) != 0; | |
testOffset <<= 1) | |
{ | |
baseAddress[testOffset] = antipattern; | |
for (offset = sizeof(UINT32); (offset & addressMask) != 0; offset <<= 1) | |
{ | |
if ((baseAddress[offset] != pattern) && (offset != testOffset)) | |
{ | |
/* | |
failure(">0 ", | |
(void*) &baseAddress[offset], | |
(void*) baseAddress[offset], | |
(void*) pattern); | |
*/ | |
dbg_printf( " Fail_b: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],pattern); | |
//reportPatternFailure((UINT32)&baseAddress[offset], baseAddress[offset], pattern, false); | |
return 1; | |
} | |
} | |
baseAddress[testOffset] = pattern; | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"AddressBus"); | |
return (AT_SUCCESS); | |
} /* memTestAddressBus() */ | |
/********************************************************************** | |
* | |
* Function: memTestIncPA() | |
* | |
* Description: Increment Address and Pattern by a word each loop. | |
* | |
**********************************************************************/ | |
int memTestIncPA(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
register UINT32 dataRead; | |
register UINT32 pattern; | |
UINT32 offset; | |
UINT32 nLongWords = (nBytes / 4); | |
//minPrintf("\r\nmemTestIncPA: "); | |
// Fill memory with a known pattern. | |
for(pattern = 1, offset = 0; offset < nLongWords; pattern++, offset+=inc) | |
{ | |
baseAddress[offset] = pattern; | |
} | |
// Check each location | |
for(pattern = 1, offset = 0; offset < nLongWords; pattern++, offset+=inc) | |
{ | |
dataRead = baseAddress[offset]; | |
if(dataRead != pattern) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],pattern); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, pattern, false); | |
return(1); | |
} | |
baseAddress[offset] = ~pattern; | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"IncPA"); | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTestIncBytePA() | |
* | |
* Description: Increment Address and Pattern by a word each loop | |
* All 4 bytes are incremented by one each loop | |
* after a lower byte incs to 0xff, its upper byte will | |
* be increased by 2 | |
* | |
**********************************************************************/ | |
int memTestIncBytePA(volatile UINT32 * baseAddress, UINT32 nBytes, int inc) | |
{ | |
register UINT32 dataRead; | |
register UINT32 pattern; | |
UINT32 offset; | |
UINT32 nLongWords = (nBytes / 4); | |
//minPrintf("\r\nmemTestIncPA: "); | |
// Fill memory with a known pattern. | |
for(pattern = 0x004080c0, offset = 0; offset < nLongWords; pattern+=0x01010101, offset+=inc) | |
{ | |
baseAddress[offset] = pattern; | |
} | |
// Check each location | |
for(pattern = 0x004080c0, offset = 0; offset < nLongWords; pattern+=0x01010101, offset+=inc) | |
{ | |
dataRead = baseAddress[offset]; | |
if(dataRead != pattern) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X, CAS 0X%x \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],pattern, (offset&0x3ff)); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, pattern, false); | |
return(1); | |
} | |
//baseAddress[offset] = ~pattern; | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"IncPA"); | |
return(AT_SUCCESS); | |
} | |
int memTestReadCheck(volatile char * baseAddress, UINT32 nBytes, int inc, int count) | |
{ | |
register char dataRead; | |
register char pattern; | |
UINT32 offset; | |
offset=0; | |
for(;;) | |
{ | |
offset += inc; | |
if(offset>=nBytes) offset=0; | |
dataRead = baseAddress[offset]; | |
} | |
return 0; | |
} | |
//Write one dword and read back | |
int memTestIncByteWriteRead(volatile UINT32 * baseAddress, UINT32 nBytes, int inc) | |
{ | |
register UINT32 dataRead; | |
register UINT32 pattern; | |
UINT32 offset; | |
UINT32 nLongWords = (nBytes / 4); | |
//minPrintf("\r\nmemTestIncPA: "); | |
// Fill memory with a known pattern. | |
for(pattern = 0x004080c0, offset = 0; offset < nLongWords; pattern+=0x01010101, offset+=32) | |
{ | |
baseAddress[offset] = pattern; | |
//if(!(offset % 16)) | |
{ | |
dataRead = baseAddress[offset]; | |
if(dataRead != pattern) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],pattern); | |
return(1); | |
} | |
} | |
} | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTestInvIncPA() | |
* | |
* Description: Increment Address and Pattern by a word each loop. invert | |
* pattern before each read/write. | |
* | |
**********************************************************************/ | |
int memTestInvIncPA(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 pattern, UINT8 inc) | |
{ | |
register UINT32 dataRead; | |
register UINT32 antipattern; | |
UINT32 offset; | |
UINT32 nLongWords = (nBytes / 4); | |
//minPrintf("\r\nmemTestInvIncPA: "); | |
for(pattern = 1, offset = 0; offset < nLongWords; pattern++, offset+=inc) | |
{ | |
baseAddress[offset] = ~pattern; | |
} | |
// Check each location for the inverted pattern and set it to 0xAAAAAAAA | |
for(pattern = 1, offset = 0; offset < nLongWords; pattern++, offset+=inc) | |
{ | |
antipattern = ~pattern; | |
dataRead = baseAddress[offset]; | |
if(dataRead != antipattern) | |
{ | |
/* | |
failure(">0 ", | |
(void*) &baseAddress[offset], | |
(void*) baseAddress[offset], | |
(void*) antipattern); | |
*/ | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), dataRead, antipattern); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, antipattern, false); | |
return(1); | |
} | |
baseAddress[offset] = pattern; | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"InvIncPA"); | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTestGeneric() | |
* | |
* Description: Writes a constant pattern throughout nBytes of memory | |
* beginning at baseAddress. Verifies each memory location. | |
* and then writes ~pattern to that location. | |
* | |
**********************************************************************/ | |
int memTestGeneric(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 pattern, UINT8 inc) | |
{ | |
register UINT32 dataRead; | |
UINT32 offset; | |
UINT32 nLongWords = (nBytes / 4); | |
//minPrintf("\r\nmemTestGeneric: "); | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
baseAddress[offset] = pattern; | |
} | |
// Check each location to see that it is pattern | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
dataRead = baseAddress[offset]; | |
if(dataRead != pattern) | |
{ | |
/* | |
failure(">0 ", | |
(void*) &baseAddress[offset], | |
(void*) baseAddress[offset], | |
(void*) pattern); | |
*/ | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],pattern); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, pattern, false); | |
return(1); | |
} | |
baseAddress[offset] = ~dataRead; | |
} | |
//minPrintf("memTest%08X passed\r\n", pattern); | |
return(AT_SUCCESS); | |
} | |
int memTestWrite16Read(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 pattern, UINT8 inc) | |
{ | |
register UINT32 dataRead; | |
UINT32 offset, i; | |
UINT32 nLongWords = (nBytes / 4); | |
// Check each location to see that it is pattern | |
for(offset = 0; offset < nLongWords; offset+=16) | |
{ | |
dataRead = baseAddress[offset]; | |
if(dataRead != pattern) | |
{ | |
/* | |
failure(">0 ", | |
(void*) &baseAddress[offset], | |
(void*) baseAddress[offset], | |
(void*) pattern); | |
*/ | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],pattern); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, pattern, false); | |
return(1); | |
} | |
} | |
//minPrintf("memTest%08X passed\r\n", pattern); | |
return(AT_SUCCESS); | |
} | |
int memTestWriteRead(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 pattern, UINT8 inc) | |
{ | |
register UINT32 dataRead; | |
UINT32 offset; | |
UINT32 nLongWords = (nBytes / 4); | |
// Check each location to see that it is pattern | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
dataRead = baseAddress[offset]; | |
if(dataRead != pattern) | |
{ | |
/* | |
failure(">0 ", | |
(void*) &baseAddress[offset], | |
(void*) baseAddress[offset], | |
(void*) pattern); | |
*/ | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],pattern); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, pattern, false); | |
return(1); | |
} | |
} | |
//minPrintf("memTest%08X passed\r\n", pattern); | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTestGeneric() | |
* | |
* Description: Writes a constant pattern throughout nBytes of memory | |
* beginning at baseAddress. Verifies each memory location. | |
* and then writes ~pattern to that location. | |
* | |
**********************************************************************/ | |
int memTestReadAll(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 pattern, UINT8 inc) | |
{ | |
register UINT32 dataRead; | |
UINT32 offset,offset2; | |
UINT32 nLongWords = (nBytes / 4); | |
//minPrintf("\r\nmemTestReadAll: "); | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
baseAddress[offset] = ~pattern; | |
} | |
// Check each location to see that it is pattern | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
baseAddress[offset] = pattern; | |
for(offset2 = 0; offset2 < nLongWords; offset2+=inc) | |
{ | |
dataRead = baseAddress[offset2]; | |
if(dataRead != ~pattern) | |
{ | |
if(offset==offset2) | |
{ | |
continue; | |
} | |
/* | |
failure(">0 ", | |
(void*) &baseAddress[offset], | |
(void*) baseAddress[offset], | |
(void*) ~pattern); | |
*/ | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],~pattern); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, pattern, false); | |
return(1); | |
} | |
} | |
baseAddress[offset] = ~pattern; | |
} | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
baseAddress[offset] = pattern; | |
} | |
// Check each location to see that it is pattern | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
baseAddress[offset] = ~pattern; | |
for(offset2 = 0; offset2 < nLongWords; offset2+=inc) | |
{ | |
dataRead = baseAddress[offset2]; | |
if(dataRead != pattern) | |
{ | |
if(offset==offset2) | |
{ | |
continue; | |
} | |
/* | |
failure(">0 ", | |
(void*) &baseAddress[offset], | |
(void*) baseAddress[offset], | |
(void*) pattern); | |
*/ | |
dbg_printf( " Fail_b: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],pattern); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, pattern, false); | |
return(1); | |
} | |
} | |
baseAddress[offset] = pattern; | |
} | |
//minPrintf("memTest%08X passed\r\n", pattern); | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTest257() | |
* | |
* Description: Writes pattern, increments the address, adds PATTERN_INCREMENT | |
* to the pattern and repeats 257 times. This process is then | |
* repeated until the end of memory is reached. | |
* | |
**********************************************************************/ | |
int memTest257(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
UINT32 offset, arrayCounter; | |
unsigned char byteVal; | |
unsigned char *byteAddr = (unsigned char *) baseAddress; | |
unsigned char expectedByte; | |
//minPrintf("\r\nmemTest257: "); | |
for(offset = 0; offset < (nBytes - 257); offset = offset + 257) | |
{ | |
for(arrayCounter = 0; arrayCounter < 257; arrayCounter+=inc) | |
{ | |
byteAddr[offset + arrayCounter] = (unsigned char)(PATTERN_STARTING_VALUE + (PATTERN_INCREMENT * arrayCounter)); | |
} | |
} | |
for(offset = 0; offset < (nBytes - 257); offset = offset + 257) | |
{ | |
for(arrayCounter = 0; arrayCounter < 257; arrayCounter+=inc) | |
{ | |
expectedByte = (unsigned char)(PATTERN_STARTING_VALUE + (PATTERN_INCREMENT * arrayCounter)); | |
byteVal = byteAddr[offset + arrayCounter]; | |
if(byteVal != expectedByte) | |
{ | |
/* | |
failure2(">0 ", | |
(void*) &byteAddr[offset+arrayCounter], | |
(void*) (unsigned int) byteVal, | |
(void*) (unsigned int) expectedByte); | |
*/ | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)byteAddr+((unsigned int)offset+arrayCounter)), byteVal,expectedByte); | |
//reportPatternFailure((UINT32)&baseAddress[offset+arrayCounter], byteVal, (unsigned char)(PATTERN_STARTING_VALUE + (PATTERN_INCREMENT * arrayCounter)), true); | |
return(1); | |
} | |
byteAddr[offset + arrayCounter] = ~byteVal; | |
} | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"257"); | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTestInv257() | |
* | |
* Description: Writes ~pattern, increments the address, adds PATTERN_INCREMENT | |
* to the pattern and repeats 257 times. This process is then | |
* repeated until the end of memory is reached. | |
* | |
**********************************************************************/ | |
int memTestInv257(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
UINT32 offset, arrayCounter; | |
unsigned char byteVal; | |
unsigned char *byteAddr = (unsigned char *) baseAddress; | |
unsigned char expectedByte; | |
//minPrintf("\r\nmemTestInv257: "); | |
for(offset = 0; offset < (nBytes - 257); offset = offset + 257) | |
{ | |
for(arrayCounter = 0; arrayCounter < 257; arrayCounter+=inc) | |
{ | |
byteAddr[offset + arrayCounter] = ~((unsigned char)(PATTERN_STARTING_VALUE + (PATTERN_INCREMENT * arrayCounter))); | |
} | |
} | |
for(offset = 0; offset < (nBytes - 257); offset = offset + 257) | |
{ | |
for(arrayCounter = 0; arrayCounter < 257; arrayCounter+=inc) | |
{ | |
byteVal = byteAddr[offset + arrayCounter]; | |
expectedByte = (unsigned char)(PATTERN_STARTING_VALUE + (PATTERN_INCREMENT * arrayCounter)); | |
expectedByte = ~expectedByte; | |
expectedByte = 0xFF & expectedByte; | |
if(byteVal != expectedByte) | |
{ | |
/* | |
failure2(">0 ", | |
(void*) &byteAddr[offset+arrayCounter], | |
(void*) (unsigned int) byteVal, | |
(void*) (unsigned int) expectedByte); | |
*/ | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)byteAddr+((unsigned int)offset+arrayCounter)), byteVal,expectedByte); | |
//reportPatternFailure((UINT32)&baseAddress[offset+arrayCounter], byteVal, expectedByte, true); | |
return(1); | |
} | |
byteAddr[offset + arrayCounter] = byteVal; | |
} | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"Inv257"); | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTestAllNoise() | |
* | |
* Description: Alternates writing 0x00000000 and 0xFFFFFFFF in order to | |
* generate noise. | |
* | |
**********************************************************************/ | |
int memTestAllNoise(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
register UINT32 dataRead; | |
UINT32 nLongWords = (nBytes / 4); | |
UINT32 offset; | |
UINT32 toggleFlag = 0; | |
//minPrintf("\r\nmemTestAllNoise: "); | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
if(toggleFlag == 0) | |
{ | |
baseAddress[offset] = 0x00000000; | |
toggleFlag = 1; | |
} | |
else if(toggleFlag == 1) | |
{ | |
baseAddress[offset] = 0xFFFFFFFF; | |
toggleFlag = 0; | |
} | |
else | |
{ | |
toggleFlag = 0; | |
} | |
} | |
toggleFlag = 0; | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
dataRead = baseAddress[offset]; | |
if((toggleFlag == 0)&&(dataRead != 0x00000000)) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],0x00000000); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, 0x00000000, false); | |
return(1); | |
} | |
else if((toggleFlag == 1)&&(dataRead != 0xFFFFFFFF)) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_b: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],0xFFFFFFFF); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, 0xFFFFFFFF, false); | |
return(1); | |
} | |
baseAddress[offset] = ~dataRead; | |
if(toggleFlag == 0) | |
toggleFlag = 1; | |
else if(toggleFlag == 1) | |
toggleFlag = 0; | |
else | |
toggleFlag = 0; | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"AllNoise"); | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTestHalfNoise() | |
* | |
* Description: Alternates writing 0xFFFF0000 and 0x0000FFFF in order to | |
* generate noise. | |
* | |
**********************************************************************/ | |
int memTestHalfNoise(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
register UINT32 dataRead; | |
UINT32 offset; | |
UINT32 nLongWords = (nBytes / 4); | |
UINT32 toggleFlag = 0; | |
toggleFlag = 0; | |
//minPrintf("\r\nmemTestHalfNoise: "); | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
if(toggleFlag == 0) | |
{ | |
baseAddress[offset] = 0xFFFF0000; | |
toggleFlag = 1; | |
} | |
else if(toggleFlag == 1) | |
{ | |
baseAddress[offset] = 0x0000FFFF; | |
toggleFlag = 0; | |
} | |
else | |
{ | |
toggleFlag = 0; | |
} | |
} | |
for(offset = 0; offset < nLongWords; offset+=inc) | |
{ | |
dataRead = baseAddress[offset]; | |
if((toggleFlag == 0)&&(dataRead != 0xFFFF0000)) | |
{ | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, 0xFFFF0000, false); | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],0xFFFF0000); | |
return(1); | |
} | |
else if((toggleFlag == 1)&&(dataRead != 0x0000FFFF)) | |
{ | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, 0x0000FFFF, false); | |
LA_TRIGGER | |
dbg_printf( " Fail_b: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],0x0000FFFF); | |
return(1); | |
} | |
baseAddress[offset] = ~dataRead; | |
if(toggleFlag == 0) | |
toggleFlag = 1; | |
else if(toggleFlag == 1) | |
toggleFlag = 0; | |
else | |
toggleFlag = 0; | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"HalfNoise"); | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTestConverge() | |
* | |
* Description: Alternates writing 0xFFFF0000 from baseAddress toward the | |
* end of memory and 0x0000FFFF toward the beginning of memory. | |
* | |
**********************************************************************/ | |
int memTestConverge(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
register UINT32 dataRead, dataRead2; | |
UINT32 offset, offset2; | |
UINT32 nLongWords = (nBytes / 4); | |
//minPrintf("\r\nmemTestConverge: "); | |
for(offset = 0, offset2 = nLongWords - 1; offset < nLongWords/2; offset+=inc, offset2-=inc) | |
{ | |
baseAddress[offset] = 0xFFFF0000; | |
baseAddress[offset2] = 0x0000FFFF; | |
} | |
for(offset = 0, offset2 = nLongWords - 1; offset < nLongWords/2; offset+=inc, offset2-=inc) | |
{ | |
dataRead = baseAddress[offset]; | |
dataRead2 = baseAddress[offset2]; | |
if(dataRead != 0xFFFF0000) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), dataRead,0xFFFF0000); | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, 0xFFFF0000, false); | |
return(1); | |
} | |
baseAddress[offset] = ~dataRead; | |
if(dataRead2 != 0x0000FFFF) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_b: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset2*4)), dataRead2,0x0000FFFF); | |
//reportPatternFailure((UINT32)&baseAddress[offset2], dataRead2, 0x0000FFFF, false); | |
return(1); | |
} | |
baseAddress[offset2] = ~dataRead2; | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"Converge"); | |
return(AT_SUCCESS); | |
} | |
/********************************************************************** | |
* | |
* Function: memTestFourths() | |
* | |
* Description: Divides memory into four equal segments then alternates | |
* between the segments writing 0x0000FFFF, 0xFFFF0000 | |
* 0xAAAA5555, and 0x5555AAAA to each segment respectively. | |
* | |
**********************************************************************/ | |
int memTestFourths(volatile UINT32 * baseAddress, UINT32 nBytes, register UINT32 emptyPatttern, UINT8 inc) | |
{ | |
register UINT32 dataRead, dataRead2, dataRead3, dataRead4; | |
UINT32 offset, offset2, offset3, offset4; | |
UINT32 nLongWords = (nBytes / 4); | |
//minPrintf("\r\nmemTestFourths: "); | |
for(offset = 0, offset2 = nLongWords/4, offset3 = nLongWords/2, offset4 = (3*nLongWords)/4; offset < nLongWords/4; offset+=inc, offset2+=inc, offset3+=inc, offset4+=inc) | |
{ | |
baseAddress[offset] = 0x0000FFFF; | |
baseAddress[offset2] = 0xFFFF0000; | |
baseAddress[offset3] = 0xAAAA5555; | |
baseAddress[offset4] = 0x5555AAAA; | |
} | |
for(offset = 0, offset2 = nLongWords/4, offset3 = nLongWords/2, offset4 = (3*nLongWords)/4; offset < nLongWords/4; offset+=inc, offset2+=inc, offset3+=inc, offset4+=inc) | |
{ | |
dataRead = baseAddress[offset]; | |
dataRead2 = baseAddress[offset2]; | |
dataRead3 = baseAddress[offset3]; | |
dataRead4 = baseAddress[offset4]; | |
if(dataRead != 0x0000FFFF) | |
{ | |
//reportPatternFailure((UINT32)&baseAddress[offset], dataRead, 0x0000FFFF, false); | |
LA_TRIGGER | |
dbg_printf( " Fail_a: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset*4)), baseAddress[offset],0x0000FFFF); | |
return(1); | |
} | |
baseAddress[offset] = ~dataRead; | |
if(dataRead2 != 0xFFFF0000) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_b: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset2*4)), baseAddress[offset2],0xFFFF0000); | |
//reportPatternFailure((UINT32)&baseAddress[offset2], dataRead2, 0xFFFF0000, false); | |
return(1); | |
} | |
baseAddress[offset] = ~dataRead2; | |
if(dataRead3 != 0xAAAA5555) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_c: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset3*4)), baseAddress[offset3],0xAAAA5555); | |
//reportPatternFailure((UINT32)&baseAddress[offset3], dataRead3, 0xAAAA5555, false); | |
return(1); | |
} | |
baseAddress[offset3] = ~dataRead3; | |
if(dataRead4 != 0x5555AAAA) | |
{ | |
LA_TRIGGER | |
dbg_printf( " Fail_d: @ 0x%08X; read 0x%08x expected 0x%08X \n",((unsigned int)baseAddress+((unsigned int)offset4*4)), baseAddress[offset4],0x5555AAAA); | |
//reportPatternFailure((UINT32)&baseAddress[offset4], dataRead4, 0x5555AAAA, false); | |
return(1); | |
} | |
baseAddress[offset4] = ~dataRead4; | |
} | |
//minPrintf(TEXT_HW_MEM_TEST,"Fourths"); | |
return(AT_SUCCESS); | |
} | |
int memtest(unsigned int base, unsigned long len, int en_print) | |
{ | |
UINT32 memTestSize = len; //0x2000000; | |
if (en_print) dbg_printf("memTestIncPA\n"); | |
if(memTestIncPA((volatile void*)base, memTestSize, 0x00000000, 1)) | |
{ | |
dbg_printf("\n===== failed memTestIncPA\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestInvIncPA\n"); | |
if(memTestInvIncPA((volatile void*)base, memTestSize, 0x00000000, 1)) | |
{ | |
dbg_printf("\n===== failed memTestInvIncPA\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestAllNoise\n"); | |
if(memTestAllNoise((volatile void*)base, memTestSize, 0x00000000, 1)) | |
{ | |
dbg_printf("\n===== failed memTestAllNoise\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestHalfNoise\n"); | |
if(memTestHalfNoise((volatile void*)base, memTestSize, 0x00000000, 1)) | |
{ | |
dbg_printf("\n===== failed memTestHalfNoise\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestConverge\n"); | |
if(memTestConverge((volatile void*)base, memTestSize, 0x00000000, 1)) | |
{ | |
dbg_printf("\n===== failed memTestConverge\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestFourths\n"); | |
if(memTestFourths((volatile void*)base, memTestSize, 0x00000000, 1)) | |
{ | |
dbg_printf("\n===== failed memTestFourths\n"); | |
return 1; | |
} | |
// puts("memTestDataMask\n"); | |
// if(memTestDataMask((volatile void*)base, memTestSize, 0x00000000, 1)) | |
// { | |
// puts("\n===== failed memTestDataMask\n"); | |
// *_GPIOD_DATA |= 1<<23; | |
// *_GPIOD_DATA |= 1<<27; | |
// return; | |
// | |
// } | |
// puts("memTestDataBus\n"); | |
// if(memTestDataBus((volatile void*)base, memTestSize, 0x00000000, 1)) | |
// { | |
// puts("\n===== failed memTestDataBus\n"); | |
// *_GPIOD_DATA |= 1<<23; | |
// *_GPIOD_DATA |= 1<<27; | |
// return; | |
// | |
// } | |
// puts("memTestAddressBus\n"); | |
// if(memTestAddressBus((volatile void*)base, memTestSize, 0x00000000, 1)) | |
// { | |
// puts("\n===== failed memTestAddressBus\n"); | |
// *_GPIOD_DATA |= 1<<23; | |
// *_GPIOD_DATA |= 1<<27; | |
// return; | |
// | |
// } | |
if (en_print) dbg_printf("memTestGeneric 0xAAAAAAAA\n"); | |
if(memTestGeneric((volatile void*)base, memTestSize, 0xAAAAAAAA, 1)) | |
{ | |
LA_TRIGGER | |
dbg_printf("\n===== failed 0xAAAAAAAA\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestGeneric 0x55555555\n"); | |
if(memTestGeneric((volatile void*)base, memTestSize, 0x55555555, 1)) | |
{ | |
dbg_printf("\n===== failed 0x55555555\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestGeneric 0xAAAA5555\n"); | |
if(memTestGeneric((volatile void*)base, memTestSize, 0xAAAA5555, 1)) | |
{ | |
dbg_printf("\n===== failed 0xAAAA5555\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestGeneric 0x5555AAAA\n"); | |
if(memTestGeneric((volatile void*)base, memTestSize, 0x5555AAAA, 1)) | |
{ | |
dbg_printf("\n===== failed 0x5555AAAA\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestGeneric 0xFFFFFFFF\n"); | |
if(memTestGeneric((volatile void*)base, memTestSize, 0xFFFFFFFF, 1)) | |
{ | |
dbg_printf("\n===== failed 0xFFFFFFFF\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestGeneric 0x5A5AA5A5\n"); | |
if(memTestGeneric((volatile void*)base, memTestSize, 0x5A5AA5A5, 1)) | |
{ | |
dbg_printf("\n===== failed 0x5A5AA5A5\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestGeneric 0xA5A55A5A\n"); | |
if(memTestGeneric((volatile void*)base, memTestSize, 0xA5A55A5A, 1)) | |
{ | |
dbg_printf("\n===== failed 0xA5A55A5A\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTest257\n"); | |
if(memTest257((volatile void*)base, memTestSize, 0x00000000, 1)) | |
{ | |
dbg_printf("\n===== failed memTest257\n"); | |
return 1; | |
} | |
if (en_print) dbg_printf("memTestInv257\n"); | |
if(memTestInv257((volatile void*)base, memTestSize, 0x00000000, 1)) | |
{ | |
dbg_printf("\n===== failed memTestInv257\n"); | |
return 1; | |
} | |
// puts("memTestDevice\n"); | |
// if(memTestDevice((volatile void*)base, len)>0) | |
// { | |
// puts("\n===== failed memTestDevice\n"); | |
// *_GPIOD_DATA |= 1<<23; | |
// *_GPIOD_DATA |= 1<<27; | |
// return; | |
// | |
// } | |
// puts("memTestGeneric 0xAAAAAAAA\n"); | |
// if(memTestGeneric((volatile void*)base, memTestSize, 0xAAAAAAAA, 1)) | |
// { | |
// puts("\n===== failed 0xAAAAAAAA\n"); | |
// *_GPIOD_DATA |= 1<<23; | |
// *_GPIOD_DATA |= 1<<27; | |
// return; | |
// | |
// } | |
// if (next_ip != initial_pattern) | |
// { | |
// initial_pattern = next_ip; | |
// } | |
// } | |
if (en_print) dbg_printf("\n!!!! memory test passed !!!!\n"); | |
return 0; | |
} | |
void mem_cbyte(unsigned int data1, unsigned int data2, unsigned int data3) | |
{ | |
int i, iResult; | |
if((data2 > 0x20000000) || (data1 > data2)) | |
{ | |
dbg_printf("Wrong address. Pls use [start_addr][end_addr][iteration]\n"); | |
return; | |
} | |
for (i = 0; i < data3; i++) | |
{ | |
if(i == 0) | |
iResult = memtest(data1, data2 - data1, 1); | |
else | |
iResult = memtest(data1, data2 - data1, 0); | |
if (iResult == 1) | |
break; | |
dbg_printf( "."); | |
} | |
} | |
#endif |